summaryrefslogtreecommitdiffstats
path: root/storage/connect
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:07:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:07:14 +0000
commita175314c3e5827eb193872241446f2f8f5c9d33c (patch)
treecd3d60ca99ae00829c52a6ca79150a5b6e62528b /storage/connect
parentInitial commit. (diff)
downloadmariadb-10.5-a175314c3e5827eb193872241446f2f8f5c9d33c.tar.xz
mariadb-10.5-a175314c3e5827eb193872241446f2f8f5c9d33c.zip
Adding upstream version 1:10.5.12.upstream/1%10.5.12upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'storage/connect')
-rw-r--r--storage/connect/.gitignore264
-rw-r--r--storage/connect/ApacheInterface.java61
-rw-r--r--storage/connect/CMakeLists.txt458
-rw-r--r--storage/connect/Client.java200
-rw-r--r--storage/connect/Client2.java130
-rw-r--r--storage/connect/Client3.java154
-rw-r--r--storage/connect/JdbcInterface.java834
-rw-r--r--storage/connect/MariadbInterface.java69
-rw-r--r--storage/connect/Mongo2Interface.java531
-rw-r--r--storage/connect/Mongo3Interface.java618
-rw-r--r--storage/connect/MysqlInterface.java69
-rw-r--r--storage/connect/OracleInterface.java69
-rw-r--r--storage/connect/PostgresqlInterface.java70
-rw-r--r--storage/connect/TestInsert2.java131
-rw-r--r--storage/connect/TestInsert3.java131
-rw-r--r--storage/connect/array.cpp1151
-rw-r--r--storage/connect/array.h131
-rw-r--r--storage/connect/blkfil.cpp1075
-rw-r--r--storage/connect/blkfil.h295
-rw-r--r--storage/connect/block.h61
-rw-r--r--storage/connect/bson.cpp1795
-rw-r--r--storage/connect/bson.h207
-rw-r--r--storage/connect/bsonudf.cpp6221
-rw-r--r--storage/connect/bsonudf.h410
-rw-r--r--storage/connect/catalog.h105
-rw-r--r--storage/connect/checklvl.h51
-rw-r--r--storage/connect/cmgfam.cpp315
-rw-r--r--storage/connect/cmgfam.h68
-rw-r--r--storage/connect/cmgoconn.cpp1120
-rw-r--r--storage/connect/cmgoconn.h121
-rw-r--r--storage/connect/colblk.cpp414
-rw-r--r--storage/connect/colblk.h232
-rw-r--r--storage/connect/connect.cc965
-rw-r--r--storage/connect/connect.h80
-rw-r--r--storage/connect/csort.cpp966
-rw-r--r--storage/connect/csort.h104
-rw-r--r--storage/connect/domdoc.cpp756
-rw-r--r--storage/connect/domdoc.h146
-rw-r--r--storage/connect/encas.h320
-rw-r--r--storage/connect/engmsg.h326
-rw-r--r--storage/connect/enids.h46
-rw-r--r--storage/connect/filamap.cpp788
-rw-r--r--storage/connect/filamap.h120
-rw-r--r--storage/connect/filamdbf.cpp1202
-rw-r--r--storage/connect/filamdbf.h108
-rw-r--r--storage/connect/filamfix.cpp1540
-rw-r--r--storage/connect/filamfix.h93
-rw-r--r--storage/connect/filamgz.cpp1427
-rw-r--r--storage/connect/filamgz.h170
-rw-r--r--storage/connect/filamtxt.cpp2119
-rw-r--r--storage/connect/filamtxt.h254
-rw-r--r--storage/connect/filamvct.cpp4313
-rw-r--r--storage/connect/filamvct.h252
-rw-r--r--storage/connect/filamzip.cpp1454
-rw-r--r--storage/connect/filamzip.h232
-rw-r--r--storage/connect/filter.cpp1753
-rw-r--r--storage/connect/filter.h178
-rw-r--r--storage/connect/fmdlex.c1540
-rw-r--r--storage/connect/frcas.h320
-rw-r--r--storage/connect/frids.h46
-rw-r--r--storage/connect/frmsg.h320
-rw-r--r--storage/connect/frmsg1.h1013
-rw-r--r--storage/connect/frmsg2.h1013
-rw-r--r--storage/connect/global.h230
-rw-r--r--storage/connect/ha_connect.cc7535
-rw-r--r--storage/connect/ha_connect.h557
-rw-r--r--storage/connect/inihandl.cpp1405
-rw-r--r--storage/connect/inihandl.h55
-rw-r--r--storage/connect/ioapi.c248
-rw-r--r--storage/connect/ioapi.h209
-rw-r--r--storage/connect/javaconn.cpp613
-rw-r--r--storage/connect/javaconn.h130
-rw-r--r--storage/connect/jdbccat.h35
-rw-r--r--storage/connect/jdbconn.cpp1686
-rw-r--r--storage/connect/jdbconn.h92
-rw-r--r--storage/connect/jmgfam.cpp390
-rw-r--r--storage/connect/jmgfam.h82
-rw-r--r--storage/connect/jmgoconn.cpp883
-rw-r--r--storage/connect/jmgoconn.h116
-rw-r--r--storage/connect/json.cpp2060
-rw-r--r--storage/connect/json.h364
-rw-r--r--storage/connect/jsonudf.cpp6646
-rw-r--r--storage/connect/jsonudf.h411
-rw-r--r--storage/connect/libdoc.cpp1288
-rw-r--r--storage/connect/libdoc.h6
-rw-r--r--storage/connect/macutil.cpp318
-rw-r--r--storage/connect/macutil.h36
-rw-r--r--storage/connect/maputil.cpp200
-rw-r--r--storage/connect/maputil.h21
-rw-r--r--storage/connect/messages.h13
-rw-r--r--storage/connect/mini-global.h33
-rw-r--r--storage/connect/mongo.cpp451
-rw-r--r--storage/connect/mongo.h91
-rw-r--r--storage/connect/msgid.h326
-rw-r--r--storage/connect/mycat.cc583
-rw-r--r--storage/connect/mycat.h119
-rw-r--r--storage/connect/myconn.cpp1092
-rw-r--r--storage/connect/myconn.h105
-rw-r--r--storage/connect/mysql-test/connect/disabled.def27
-rw-r--r--storage/connect/mysql-test/connect/my.cnf17
-rw-r--r--storage/connect/mysql-test/connect/r/alter.result274
-rw-r--r--storage/connect/mysql-test/connect/r/alter_engine.result11
-rw-r--r--storage/connect/mysql-test/connect/r/alter_xml.result84
-rw-r--r--storage/connect/mysql-test/connect/r/alter_xml2.result86
-rw-r--r--storage/connect/mysql-test/connect/r/bin.result99
-rw-r--r--storage/connect/mysql-test/connect/r/bson.result517
-rw-r--r--storage/connect/mysql-test/connect/r/bson_java_2.result385
-rw-r--r--storage/connect/mysql-test/connect/r/bson_java_3.result385
-rw-r--r--storage/connect/mysql-test/connect/r/bson_mongo_c.result385
-rw-r--r--storage/connect/mysql-test/connect/r/bson_udf.result685
-rw-r--r--storage/connect/mysql-test/connect/r/csv.result221
-rw-r--r--storage/connect/mysql-test/connect/r/datest.result59
-rw-r--r--storage/connect/mysql-test/connect/r/dbf.result649
-rw-r--r--storage/connect/mysql-test/connect/r/dir.result32
-rw-r--r--storage/connect/mysql-test/connect/r/drop-open-error.result15
-rw-r--r--storage/connect/mysql-test/connect/r/endian.result105
-rw-r--r--storage/connect/mysql-test/connect/r/fix.result131
-rw-r--r--storage/connect/mysql-test/connect/r/fmt.result68
-rw-r--r--storage/connect/mysql-test/connect/r/general.result18
-rw-r--r--storage/connect/mysql-test/connect/r/grant.result604
-rw-r--r--storage/connect/mysql-test/connect/r/grant2.result770
-rw-r--r--storage/connect/mysql-test/connect/r/grant3.result5
-rw-r--r--storage/connect/mysql-test/connect/r/index.result141
-rw-r--r--storage/connect/mysql-test/connect/r/infoschema-9739.result8
-rw-r--r--storage/connect/mysql-test/connect/r/infoschema2-9739.result10
-rw-r--r--storage/connect/mysql-test/connect/r/ini.result279
-rw-r--r--storage/connect/mysql-test/connect/r/ini_grant.result89
-rw-r--r--storage/connect/mysql-test/connect/r/jdbc.result284
-rw-r--r--storage/connect/mysql-test/connect/r/jdbc_new.result234
-rw-r--r--storage/connect/mysql-test/connect/r/jdbc_oracle.result76
-rw-r--r--storage/connect/mysql-test/connect/r/jdbc_postgresql.result74
-rw-r--r--storage/connect/mysql-test/connect/r/json.result517
-rw-r--r--storage/connect/mysql-test/connect/r/json_java_2.result385
-rw-r--r--storage/connect/mysql-test/connect/r/json_java_3.result385
-rw-r--r--storage/connect/mysql-test/connect/r/json_mongo_c.result385
-rw-r--r--storage/connect/mysql-test/connect/r/json_udf.result651
-rw-r--r--storage/connect/mysql-test/connect/r/json_udf_bin.result587
-rw-r--r--storage/connect/mysql-test/connect/r/mongo_c.result381
-rw-r--r--storage/connect/mysql-test/connect/r/mongo_java_2.result381
-rw-r--r--storage/connect/mysql-test/connect/r/mongo_java_3.result381
-rw-r--r--storage/connect/mysql-test/connect/r/mrr.result117
-rw-r--r--storage/connect/mysql-test/connect/r/mul.result57
-rw-r--r--storage/connect/mysql-test/connect/r/mul_new.result136
-rw-r--r--storage/connect/mysql-test/connect/r/mysql.result296
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_discovery.result45
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_exec.result76
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_grant.result73
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_index.result436
-rw-r--r--storage/connect/mysql-test/connect/r/mysql_new.result237
-rw-r--r--storage/connect/mysql-test/connect/r/null.result134
-rw-r--r--storage/connect/mysql-test/connect/r/occur.result255
-rw-r--r--storage/connect/mysql-test/connect/r/odbc.result47
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_firebird.result110
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_oracle.result237
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_postgresql.result296
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_sqlite3.result2463
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result86
-rw-r--r--storage/connect/mysql-test/connect/r/odbc_xls.result26
-rw-r--r--storage/connect/mysql-test/connect/r/part_file.result343
-rw-r--r--storage/connect/mysql-test/connect/r/part_table.result222
-rw-r--r--storage/connect/mysql-test/connect/r/pivot.result251
-rw-r--r--storage/connect/mysql-test/connect/r/rest.result19
-rw-r--r--storage/connect/mysql-test/connect/r/secure_file_priv.result8
-rw-r--r--storage/connect/mysql-test/connect/r/tbl.result143
-rw-r--r--storage/connect/mysql-test/connect/r/tbl_thread.result165
-rw-r--r--storage/connect/mysql-test/connect/r/temporary.result6
-rw-r--r--storage/connect/mysql-test/connect/r/type_inet6.result15
-rw-r--r--storage/connect/mysql-test/connect/r/unsigned.result61
-rw-r--r--storage/connect/mysql-test/connect/r/upd.result1629
-rw-r--r--storage/connect/mysql-test/connect/r/updelx.result2570
-rw-r--r--storage/connect/mysql-test/connect/r/updelx2.result133
-rw-r--r--storage/connect/mysql-test/connect/r/vcol.result29
-rw-r--r--storage/connect/mysql-test/connect/r/vec.result138
-rw-r--r--storage/connect/mysql-test/connect/r/xcol.result117
-rw-r--r--storage/connect/mysql-test/connect/r/xml.result392
-rw-r--r--storage/connect/mysql-test/connect/r/xml2.result400
-rw-r--r--storage/connect/mysql-test/connect/r/xml2_grant.result107
-rw-r--r--storage/connect/mysql-test/connect/r/xml2_html.result32
-rw-r--r--storage/connect/mysql-test/connect/r/xml2_mdev5261.result25
-rw-r--r--storage/connect/mysql-test/connect/r/xml2_mult.result104
-rw-r--r--storage/connect/mysql-test/connect/r/xml2_zip.result98
-rw-r--r--storage/connect/mysql-test/connect/r/xml_grant.result105
-rw-r--r--storage/connect/mysql-test/connect/r/xml_html.result30
-rw-r--r--storage/connect/mysql-test/connect/r/xml_mdev5261.result23
-rw-r--r--storage/connect/mysql-test/connect/r/xml_mult.result102
-rw-r--r--storage/connect/mysql-test/connect/r/xml_zip.result96
-rw-r--r--storage/connect/mysql-test/connect/r/zip.result240
-rw-r--r--storage/connect/mysql-test/connect/std_data/JavaWrappers.jarbin0 -> 19192 bytes
-rw-r--r--storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jarbin0 -> 6021947 bytes
-rw-r--r--storage/connect/mysql-test/connect/std_data/Mongo2.jarbin0 -> 624130 bytes
-rw-r--r--storage/connect/mysql-test/connect/std_data/Mongo3.jarbin0 -> 1706057 bytes
-rw-r--r--storage/connect/mysql-test/connect/std_data/Testbal.datbin0 -> 78 bytes
-rw-r--r--storage/connect/mysql-test/connect/std_data/beers.xml16
-rw-r--r--storage/connect/mysql-test/connect/std_data/bib0.json2
-rw-r--r--storage/connect/mysql-test/connect/std_data/biblio.json43
-rw-r--r--storage/connect/mysql-test/connect/std_data/bios.json273
-rw-r--r--storage/connect/mysql-test/connect/std_data/bookstore.xml31
-rw-r--r--storage/connect/mysql-test/connect/std_data/boys.txt6
-rw-r--r--storage/connect/mysql-test/connect/std_data/boyswin.txt6
-rw-r--r--storage/connect/mysql-test/connect/std_data/cities.json29353
-rw-r--r--storage/connect/mysql-test/connect/std_data/coffee.htm24
-rw-r--r--storage/connect/mysql-test/connect/std_data/contact.ini23
-rw-r--r--storage/connect/mysql-test/connect/std_data/contacts.xlsbin0 -> 9216 bytes
-rw-r--r--storage/connect/mysql-test/connect/std_data/cp1251.xml2
-rw-r--r--storage/connect/mysql-test/connect/std_data/dept.dat4
-rw-r--r--storage/connect/mysql-test/connect/std_data/emp.txt4545
-rw-r--r--storage/connect/mysql-test/connect/std_data/employee.dat27
-rw-r--r--storage/connect/mysql-test/connect/std_data/expense.json158
-rw-r--r--storage/connect/mysql-test/connect/std_data/expenses.txt24
-rw-r--r--storage/connect/mysql-test/connect/std_data/funny.txt3
-rw-r--r--storage/connect/mysql-test/connect/std_data/funny2.txt3
-rw-r--r--storage/connect/mysql-test/connect/std_data/girls.txt5
-rw-r--r--storage/connect/mysql-test/connect/std_data/gloss.json22
-rw-r--r--storage/connect/mysql-test/connect/std_data/latin1.xml2
-rw-r--r--storage/connect/mysql-test/connect/std_data/mdev9949.frmbin0 -> 35031 bytes
-rw-r--r--storage/connect/mysql-test/connect/std_data/mulexp3.json52
-rw-r--r--storage/connect/mysql-test/connect/std_data/mulexp4.json52
-rw-r--r--storage/connect/mysql-test/connect/std_data/mulexp5.json52
-rw-r--r--storage/connect/mysql-test/connect/std_data/nocs.xml2
-rw-r--r--storage/connect/mysql-test/connect/std_data/people.csv3
-rw-r--r--storage/connect/mysql-test/connect/std_data/sexe.csv3
-rw-r--r--storage/connect/mysql-test/connect/std_data/sitmat.csv7
-rw-r--r--storage/connect/mysql-test/connect/std_data/test.sqlite3bin0 -> 445440 bytes
-rw-r--r--storage/connect/mysql-test/connect/std_data/xsample.xml35
-rw-r--r--storage/connect/mysql-test/connect/std_data/xsample2.xml47
-rw-r--r--storage/connect/mysql-test/connect/suite.opt1
-rw-r--r--storage/connect/mysql-test/connect/suite.pm16
-rw-r--r--storage/connect/mysql-test/connect/t/alter.test139
-rw-r--r--storage/connect/mysql-test/connect/t/alter_engine.test11
-rw-r--r--storage/connect/mysql-test/connect/t/alter_xml.test29
-rw-r--r--storage/connect/mysql-test/connect/t/alter_xml2.test29
-rw-r--r--storage/connect/mysql-test/connect/t/bin.test77
-rw-r--r--storage/connect/mysql-test/connect/t/bson.test294
-rw-r--r--storage/connect/mysql-test/connect/t/bson_java_2.test14
-rw-r--r--storage/connect/mysql-test/connect/t/bson_java_3.test14
-rw-r--r--storage/connect/mysql-test/connect/t/bson_mongo_c.test10
-rw-r--r--storage/connect/mysql-test/connect/t/bson_udf.inc72
-rw-r--r--storage/connect/mysql-test/connect/t/bson_udf.test282
-rw-r--r--storage/connect/mysql-test/connect/t/bson_udf2.inc63
-rw-r--r--storage/connect/mysql-test/connect/t/csv.test185
-rw-r--r--storage/connect/mysql-test/connect/t/datest.test28
-rw-r--r--storage/connect/mysql-test/connect/t/dbf.test511
-rw-r--r--storage/connect/mysql-test/connect/t/dir.test53
-rw-r--r--storage/connect/mysql-test/connect/t/drop-open-error.opt1
-rw-r--r--storage/connect/mysql-test/connect/t/drop-open-error.test29
-rw-r--r--storage/connect/mysql-test/connect/t/endian.test88
-rw-r--r--storage/connect/mysql-test/connect/t/fix.test108
-rw-r--r--storage/connect/mysql-test/connect/t/fmt.test85
-rw-r--r--storage/connect/mysql-test/connect/t/general.test16
-rw-r--r--storage/connect/mysql-test/connect/t/grant.inc86
-rw-r--r--storage/connect/mysql-test/connect/t/grant.test96
-rw-r--r--storage/connect/mysql-test/connect/t/grant2.test869
-rw-r--r--storage/connect/mysql-test/connect/t/grant3.test11
-rw-r--r--storage/connect/mysql-test/connect/t/have_libxml2.inc17
-rw-r--r--storage/connect/mysql-test/connect/t/have_odbc.inc9
-rw-r--r--storage/connect/mysql-test/connect/t/have_odbc_oracle.inc15
-rw-r--r--storage/connect/mysql-test/connect/t/have_odbc_postgresql.inc15
-rw-r--r--storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc15
-rw-r--r--storage/connect/mysql-test/connect/t/have_zip.inc19
-rw-r--r--storage/connect/mysql-test/connect/t/index.test86
-rw-r--r--storage/connect/mysql-test/connect/t/infoschema-9739.test9
-rw-r--r--storage/connect/mysql-test/connect/t/infoschema2-9739.test9
-rw-r--r--storage/connect/mysql-test/connect/t/ini.test156
-rw-r--r--storage/connect/mysql-test/connect/t/ini_grant.test81
-rw-r--r--storage/connect/mysql-test/connect/t/jdbc.test150
-rw-r--r--storage/connect/mysql-test/connect/t/jdbc_new.test187
-rw-r--r--storage/connect/mysql-test/connect/t/jdbc_oracle.test56
-rw-r--r--storage/connect/mysql-test/connect/t/jdbc_postgresql.test64
-rw-r--r--storage/connect/mysql-test/connect/t/jdbconn.inc33
-rw-r--r--storage/connect/mysql-test/connect/t/jdbconn_cleanup.inc8
-rw-r--r--storage/connect/mysql-test/connect/t/json.test294
-rw-r--r--storage/connect/mysql-test/connect/t/json_java_2.test14
-rw-r--r--storage/connect/mysql-test/connect/t/json_java_3.test14
-rw-r--r--storage/connect/mysql-test/connect/t/json_mongo_c.test10
-rw-r--r--storage/connect/mysql-test/connect/t/json_udf.inc60
-rw-r--r--storage/connect/mysql-test/connect/t/json_udf.test268
-rw-r--r--storage/connect/mysql-test/connect/t/json_udf2.inc51
-rw-r--r--storage/connect/mysql-test/connect/t/json_udf_bin.test213
-rw-r--r--storage/connect/mysql-test/connect/t/mongo.inc3
-rw-r--r--storage/connect/mysql-test/connect/t/mongo_c.test9
-rw-r--r--storage/connect/mysql-test/connect/t/mongo_java_2.test12
-rw-r--r--storage/connect/mysql-test/connect/t/mongo_java_3.test12
-rw-r--r--storage/connect/mysql-test/connect/t/mongo_test.inc216
-rw-r--r--storage/connect/mysql-test/connect/t/mrr.test66
-rw-r--r--storage/connect/mysql-test/connect/t/mul.test43
-rw-r--r--storage/connect/mysql-test/connect/t/mul_new.test67
-rw-r--r--storage/connect/mysql-test/connect/t/myconn.inc27
-rw-r--r--storage/connect/mysql-test/connect/t/myconn_cleanup.inc9
-rw-r--r--storage/connect/mysql-test/connect/t/mysql.test472
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_discovery.test33
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_exec.test45
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_grant.test80
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_index.test145
-rw-r--r--storage/connect/mysql-test/connect/t/mysql_new.test325
-rw-r--r--storage/connect/mysql-test/connect/t/null.test87
-rw-r--r--storage/connect/mysql-test/connect/t/occur.test61
-rw-r--r--storage/connect/mysql-test/connect/t/odbc.test25
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_firebird.test35
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_oracle.sql16
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_oracle.test230
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_postgresql.sql27
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_postgresql.test207
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_sqlite3.test90
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test91
-rw-r--r--storage/connect/mysql-test/connect/t/odbc_xls.test39
-rw-r--r--storage/connect/mysql-test/connect/t/part_file.test166
-rw-r--r--storage/connect/mysql-test/connect/t/part_table.test107
-rw-r--r--storage/connect/mysql-test/connect/t/pivot.test163
-rw-r--r--storage/connect/mysql-test/connect/t/rest.inc17
-rw-r--r--storage/connect/mysql-test/connect/t/rest.test17
-rw-r--r--storage/connect/mysql-test/connect/t/secure_file_priv-master.opt1
-rw-r--r--storage/connect/mysql-test/connect/t/secure_file_priv.test13
-rw-r--r--storage/connect/mysql-test/connect/t/tbl.test53
-rw-r--r--storage/connect/mysql-test/connect/t/tbl_thread.test112
-rw-r--r--storage/connect/mysql-test/connect/t/temporary.test13
-rw-r--r--storage/connect/mysql-test/connect/t/type_inet6.test10
-rw-r--r--storage/connect/mysql-test/connect/t/unsigned.test35
-rw-r--r--storage/connect/mysql-test/connect/t/upd.test157
-rw-r--r--storage/connect/mysql-test/connect/t/updelx.inc25
-rw-r--r--storage/connect/mysql-test/connect/t/updelx.test96
-rw-r--r--storage/connect/mysql-test/connect/t/updelx2.test22
-rw-r--r--storage/connect/mysql-test/connect/t/vcol.test31
-rw-r--r--storage/connect/mysql-test/connect/t/vec.test80
-rw-r--r--storage/connect/mysql-test/connect/t/windows.inc5
-rw-r--r--storage/connect/mysql-test/connect/t/xcol.test41
-rw-r--r--storage/connect/mysql-test/connect/t/xml.test321
-rw-r--r--storage/connect/mysql-test/connect/t/xml2.test320
-rw-r--r--storage/connect/mysql-test/connect/t/xml2_grant.test8
-rw-r--r--storage/connect/mysql-test/connect/t/xml2_html.test39
-rw-r--r--storage/connect/mysql-test/connect/t/xml2_mdev5261.test27
-rw-r--r--storage/connect/mysql-test/connect/t/xml2_mult.test64
-rw-r--r--storage/connect/mysql-test/connect/t/xml2_zip.test41
-rw-r--r--storage/connect/mysql-test/connect/t/xml_grant.test8
-rw-r--r--storage/connect/mysql-test/connect/t/xml_html.test39
-rw-r--r--storage/connect/mysql-test/connect/t/xml_mdev5261.test27
-rw-r--r--storage/connect/mysql-test/connect/t/xml_mult.test64
-rw-r--r--storage/connect/mysql-test/connect/t/xml_zip.test41
-rw-r--r--storage/connect/mysql-test/connect/t/zip.test136
-rw-r--r--storage/connect/myutil.cpp318
-rw-r--r--storage/connect/myutil.h14
-rw-r--r--storage/connect/noconst.c38
-rw-r--r--storage/connect/odbccat.h25
-rw-r--r--storage/connect/odbconn.cpp2639
-rw-r--r--storage/connect/odbconn.h202
-rw-r--r--storage/connect/os.h70
-rw-r--r--storage/connect/osutil.c179
-rw-r--r--storage/connect/osutil.h58
-rw-r--r--storage/connect/plgcnx.h67
-rw-r--r--storage/connect/plgdbsem.h651
-rw-r--r--storage/connect/plgdbutl.cpp1614
-rw-r--r--storage/connect/plgodbc.h230
-rw-r--r--storage/connect/plgxml.cpp185
-rw-r--r--storage/connect/plgxml.h194
-rw-r--r--storage/connect/plugutil.cpp637
-rw-r--r--storage/connect/preparse.h34
-rw-r--r--storage/connect/rcmsg.c69
-rw-r--r--storage/connect/rcmsg.h15
-rw-r--r--storage/connect/reldef.cpp949
-rw-r--r--storage/connect/reldef.h251
-rw-r--r--storage/connect/resource.h46
-rw-r--r--storage/connect/rest.def4
-rw-r--r--storage/connect/restget.cpp90
-rw-r--r--storage/connect/tabbson.cpp2627
-rw-r--r--storage/connect/tabbson.h342
-rw-r--r--storage/connect/tabcmg.cpp506
-rw-r--r--storage/connect/tabcmg.h133
-rw-r--r--storage/connect/tabcol.cpp169
-rw-r--r--storage/connect/tabcol.h109
-rw-r--r--storage/connect/tabdos.cpp2921
-rw-r--r--storage/connect/tabdos.h269
-rw-r--r--storage/connect/tabext.cpp720
-rw-r--r--storage/connect/tabext.h204
-rw-r--r--storage/connect/tabfix.cpp681
-rw-r--r--storage/connect/tabfix.h117
-rw-r--r--storage/connect/tabfmt.cpp1573
-rw-r--r--storage/connect/tabfmt.h191
-rw-r--r--storage/connect/tabjdbc.cpp1328
-rw-r--r--storage/connect/tabjdbc.h236
-rw-r--r--storage/connect/tabjmg.cpp632
-rw-r--r--storage/connect/tabjmg.h147
-rw-r--r--storage/connect/tabjson.cpp2707
-rw-r--r--storage/connect/tabjson.h323
-rw-r--r--storage/connect/table.cpp805
-rw-r--r--storage/connect/tabmac.cpp458
-rw-r--r--storage/connect/tabmac.h108
-rw-r--r--storage/connect/tabmul.cpp1623
-rw-r--r--storage/connect/tabmul.h248
-rw-r--r--storage/connect/tabmysql.cpp1761
-rw-r--r--storage/connect/tabmysql.h252
-rw-r--r--storage/connect/taboccur.cpp589
-rw-r--r--storage/connect/taboccur.h142
-rw-r--r--storage/connect/tabodbc.cpp1411
-rw-r--r--storage/connect/tabodbc.h264
-rw-r--r--storage/connect/tabpivot.cpp912
-rw-r--r--storage/connect/tabpivot.h200
-rw-r--r--storage/connect/tabrest.cpp359
-rw-r--r--storage/connect/tabrest.h50
-rw-r--r--storage/connect/tabsys.cpp884
-rw-r--r--storage/connect/tabsys.h182
-rw-r--r--storage/connect/tabtbl.cpp876
-rw-r--r--storage/connect/tabtbl.h168
-rw-r--r--storage/connect/tabutil.cpp804
-rw-r--r--storage/connect/tabutil.h155
-rw-r--r--storage/connect/tabvct.cpp588
-rw-r--r--storage/connect/tabvct.h124
-rw-r--r--storage/connect/tabvir.cpp305
-rw-r--r--storage/connect/tabvir.h110
-rw-r--r--storage/connect/tabwmi.cpp851
-rw-r--r--storage/connect/tabwmi.h151
-rw-r--r--storage/connect/tabxcl.cpp298
-rw-r--r--storage/connect/tabxcl.h104
-rw-r--r--storage/connect/tabxml.cpp2291
-rw-r--r--storage/connect/tabxml.h273
-rw-r--r--storage/connect/tabzip.cpp251
-rw-r--r--storage/connect/tabzip.h102
-rw-r--r--storage/connect/unzip.c2125
-rw-r--r--storage/connect/unzip.h437
-rw-r--r--storage/connect/user_connect.cc192
-rw-r--r--storage/connect/user_connect.h73
-rw-r--r--storage/connect/valblk.cpp1417
-rw-r--r--storage/connect/valblk.h363
-rw-r--r--storage/connect/value.cpp2891
-rw-r--r--storage/connect/value.h451
-rw-r--r--storage/connect/xindex.cpp3298
-rw-r--r--storage/connect/xindex.h509
-rw-r--r--storage/connect/xobject.cpp441
-rw-r--r--storage/connect/xobject.h165
-rw-r--r--storage/connect/xtable.h275
-rw-r--r--storage/connect/zip.c2007
-rw-r--r--storage/connect/zip.h362
430 files changed, 195449 insertions, 0 deletions
diff --git a/storage/connect/.gitignore b/storage/connect/.gitignore
new file mode 100644
index 00000000..e2fa07ee
--- /dev/null
+++ b/storage/connect/.gitignore
@@ -0,0 +1,264 @@
+# Edited by Olivier Bertrand
+*-t
+*.a
+*.ctest
+*.o
+*.reject
+*.so
+*.so.*
+*.spec
+*~
+*.bak
+*.log
+*.cmake
+*.tgz
+*.msg
+.*.swp
+*.ninja
+.ninja_*
+.gdb_history
+
+CMakeFiles/
+connect.dir/
+connect.dir-Copie/
+Debug/
+MinSizeRel/
+Release/
+RelWithDebInfo/
+
+# C and C++
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.ko
+*.obj
+*.elf
+*.exp
+*.manifest
+*.dep
+*.idb
+*.res
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Static libraries
+*.lib
+*.a
+*.la
+*.lai
+*.lo
+
+# Compiled Dynamic libraries
+*.so
+*.so.*
+*.dylib
+*.dll
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+*.ncb
+*.sln
+
+*.vcproj
+*.vcproj.*
+*.vcproj.*.*
+*.vcproj.*.*.*
+*.vcxproj
+*.vcxproj.*
+*.vcxproj.*.*
+*.vcxproj.*.*.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+
+# Roslyn cache directories
+*.ide/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+#NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding addin-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# If using the old MSBuild-Integrated Package Restore, uncomment this:
+#!**/packages/repositories.config
+
+# Windows Azure Build Output
+csx/
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+# sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
diff --git a/storage/connect/ApacheInterface.java b/storage/connect/ApacheInterface.java
new file mode 100644
index 00000000..47b46dc0
--- /dev/null
+++ b/storage/connect/ApacheInterface.java
@@ -0,0 +1,61 @@
+package wrappers;
+
+import java.sql.*;
+import java.util.Hashtable;
+import org.apache.commons.dbcp2.BasicDataSource;
+
+public class ApacheInterface extends JdbcInterface {
+ static Hashtable<String,BasicDataSource> pool = new Hashtable<String, BasicDataSource>();
+
+ public ApacheInterface() {
+ this(true);
+ } // end of default constructor
+
+ public ApacheInterface(boolean b) {
+ super(b);
+ } // end of constructor
+
+ @Override
+ public int JdbcConnect(String[] parms, int fsize, boolean scrollable) {
+ int rc = 0;
+ String url = parms[1];
+ BasicDataSource ds = null;
+
+ if (DEBUG)
+ System.out.println("Connecting to Apache data source");
+
+ try {
+ CheckURL(url, null);
+
+ if ((ds = pool.get(url)) == null) {
+ ds = new BasicDataSource();
+ ds.setDriverClassName(parms[0]);
+ ds.setUrl(url);
+ ds.setUsername(parms[2]);
+ ds.setPassword(parms[3]);
+ pool.put(url, ds);
+ } // endif ds
+
+ // if (parms.length > 4 && parms[4] != null)
+ // ds.setConnectionProperties(parms[4]);
+
+ // Get a connection from the data source
+ conn = ds.getConnection();
+
+ // Get the data base meta data object
+ dbmd = conn.getMetaData();
+
+ // Get a statement from the connection
+ stmt = GetStmt(fsize, scrollable);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ rc = -2;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ rc = -3;
+ } // end try/catch
+
+ return rc;
+ } // end of JdbcConnect
+
+} // end of class ApacheInterface
diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt
new file mode 100644
index 00000000..456a7b62
--- /dev/null
+++ b/storage/connect/CMakeLists.txt
@@ -0,0 +1,458 @@
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+IF(WITHOUT_DYNAMIC_PLUGINS OR WITH_NONE OR ("${PLUGIN_CONNECT}" STREQUAL "NO"))
+ RETURN()
+ENDIF()
+
+SET(CONNECT_PLUGIN_STATIC "connect")
+SET(CONNECT_PLUGIN_DYNAMIC "connect")
+
+SET(CONNECT_SOURCES
+ha_connect.cc connect.cc user_connect.cc mycat.cc
+fmdlex.c osutil.c rcmsg.c rcmsg.h
+array.cpp blkfil.cpp colblk.cpp csort.cpp
+filamap.cpp filamdbf.cpp filamfix.cpp filamgz.cpp filamtxt.cpp filter.cpp
+json.cpp jsonudf.cpp maputil.cpp myconn.cpp myutil.cpp plgdbutl.cpp plugutil.cpp
+reldef.cpp tabcol.cpp tabdos.cpp tabext.cpp tabfix.cpp tabfmt.cpp tabjson.cpp
+table.cpp tabmul.cpp tabmysql.cpp taboccur.cpp tabpivot.cpp tabsys.cpp tabtbl.cpp
+tabutil.cpp tabvir.cpp tabxcl.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp
+
+array.h blkfil.h block.h catalog.h checklvl.h colblk.h connect.h csort.h
+engmsg.h filamap.h filamdbf.h filamfix.h filamgz.h filamtxt.h
+filter.h global.h ha_connect.h inihandl.h json.h jsonudf.h maputil.h msgid.h
+mycat.h myconn.h myutil.h os.h osutil.h plgcnx.h plgdbsem.h preparse.h reldef.h
+resource.h tabcol.h tabdos.h tabext.h tabfix.h tabfmt.h tabjson.h tabmul.h
+tabmysql.h taboccur.h tabpivot.h tabsys.h tabtbl.h tabutil.h tabvir.h tabxcl.h
+user_connect.h valblk.h value.h xindex.h xobject.h xtable.h)
+
+#
+# Definitions that are shared for all OSes
+#
+add_definitions( -DMARIADB -DFORCE_INIT_OF_VARS -Dconnect_EXPORTS)
+add_definitions( -DHUGE_SUPPORT -DGZ_SUPPORT )
+
+macro(DISABLE_WARNING W)
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-error=${W}")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-${W}" DEBUG)
+endmacro()
+
+#
+# OS specific C flags, definitions and source files.
+#
+IF(UNIX)
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wall -Wmissing-declarations")
+ if(NOT WITH_WARNINGS)
+ DISABLE_WARNING("unused-function")
+ DISABLE_WARNING("unused-variable")
+ DISABLE_WARNING("unused-value")
+ DISABLE_WARNING("parentheses")
+ DISABLE_WARNING("strict-aliasing")
+ DISABLE_WARNING("misleading-indentation")
+ DISABLE_WARNING("format-truncation")
+ DISABLE_WARNING("implicit-fallthrough")
+ DISABLE_WARNING("type-limits")
+ endif(NOT WITH_WARNINGS)
+
+ add_definitions( -DUNIX -DLINUX -DUBUNTU )
+
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -fexceptions -fPIC ")
+ get_property(inc_dirs DIRECTORY PROPERTY INCLUDE_DIRECTORIES)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} inihandl.cpp)
+ SET(IPHLPAPI_LIBRARY "")
+ELSE(NOT UNIX)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES}
+ tabwmi.cpp tabwmi.h tabmac.cpp tabmac.h macutil.cpp macutil.h)
+ # Add exception handling to the CONNECT project)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
+ SET(IPHLPAPI_LIBRARY iphlpapi.lib)
+ IF(MSVC AND (CMAKE_CXX_COMPILER_ID MATCHES Clang))
+ # Connect does not work with clang-cl
+ RETURN()
+ ENDIF()
+ENDIF(UNIX)
+
+
+#
+# BSON: the new handling of JSON data included temporarily for testing
+#
+
+OPTION(CONNECT_WITH_BSON "Compile CONNECT storage engine with BSON support" ON)
+
+IF(CONNECT_WITH_BSON)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES}
+ bson.cpp bsonudf.cpp tabbson.cpp bson.h bsonudf.h tabbson.h)
+ add_definitions(-DBSON_SUPPORT)
+ENDIF(CONNECT_WITH_BSON)
+
+
+#
+# VCT: the VEC format might be not supported in future versions
+#
+
+OPTION(CONNECT_WITH_VCT "Compile CONNECT storage engine with VCT support" ON)
+
+IF(CONNECT_WITH_VCT)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} filamvct.cpp tabvct.cpp filamvct.h tabvct.h)
+ add_definitions(-DVCT_SUPPORT)
+ENDIF(CONNECT_WITH_VCT)
+ADD_FEATURE_INFO(CONNECT_VCT CONNECT_WITH_VCT "Support for VCT in the CONNECT storage engine")
+
+
+#
+# XML
+#
+
+OPTION(CONNECT_WITH_LIBXML2 "Compile CONNECT storage engine with LIBXML2 support" ON)
+
+IF(CONNECT_WITH_LIBXML2)
+ IF(WIN32)
+ #
+ # NOTE: when switching to static linking of libxml2
+ # make sure to define LIBXML_STATIC.
+ #
+ # Adding some typical places to search in
+ SET(PC_LIBXML_INCLUDE_DIRS
+ C:/libxml2/include
+ C:/libxml/include
+ D:/libxml/include)
+ SET(PC_LIBXML_LIBRARY_DIRS
+ C:/libxml2/lib
+ C:/libxml/lib
+ D:/libxml/lib)
+ ENDIF(WIN32)
+ FIND_PACKAGE(LibXml2)
+ SET_PACKAGE_PROPERTIES(LibXml2 PROPERTIES TYPE OPTIONAL)
+ IF (LIBXML2_FOUND)
+ INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
+ SET(XML_LIBRARY ${LIBXML2_LIBRARIES})
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} libdoc.cpp libdoc.h)
+ add_definitions(-DLIBXML2_SUPPORT)
+ ENDIF(LIBXML2_FOUND)
+ENDIF(CONNECT_WITH_LIBXML2)
+ADD_FEATURE_INFO(CONNECT_LIBXML2 CONNECT_WITH_LIBXML2
+ "Support for LIBXML2 in the CONNECT storage engine")
+
+
+IF(WIN32)
+ OPTION(CONNECT_WITH_MSXML "Compile CONNECT storage engine with MSXML support" ON)
+ IF(CONNECT_WITH_MSXML)
+ add_definitions(-DMSX6 -DDOMDOC_SUPPORT)
+ SET(MSXML_FOUND 1)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} domdoc.cpp domdoc.h)
+ ENDIF(CONNECT_WITH_MSXML)
+ ADD_FEATURE_INFO(CONNECT_MSXML CONNECT_WITH_MSXML
+ "Support for MSXML in the CONNECT storage engine")
+ENDIF(WIN32)
+
+IF(LIBXML2_FOUND OR MSXML_FOUND)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES}
+ tabxml.cpp tabxml.h plgxml.cpp plgxml.h)
+ENDIF()
+
+#
+# MySQL is now included unconditionnally
+#
+
+IF(NOT UNIX)
+ #
+ # TODO: remove this
+ # change to use "#include "../../include/mysql.h" in the sources.
+ INCLUDE_DIRECTORIES("../../include/mysql")
+ENDIF(NOT UNIX)
+
+
+#
+# ODBC
+#
+
+OPTION(CONNECT_WITH_ODBC "Compile CONNECT storage engine with ODBC support" ON)
+
+IF(CONNECT_WITH_ODBC)
+ if(UNIX)
+ # Note, we currently detect unixODBC only on Linux.
+ # TODO: detect iODBC as well. Simply adding "iodbc" into NAMES in
+ # find_library does not work on machines with both unixODBC and iODBC
+ # installed, because it finds headers from unixODBC while libraries
+ # from iODBC. We could search for 'isql.h' instead of 'sql.h' so
+ # the library 'libodbc' gets compiled with 'isql.h' and
+ # the library 'libiodbc' gets compiled with 'sql'h.
+ # This will also need changes in the sources (e.g. #include <isql.h>).
+
+ find_file(ODBC_INCLUDES sql.h
+ PATHS
+ /usr/include
+ /usr/include/odbc
+ /usr/local/include
+ /usr/local/include/odbc
+ /usr/local/odbc/include
+ #"C:/Program Files/ODBC/include"
+ #"C:/Program Files/Microsoft SDKs/Windows/v7.0A/include"
+ #"C:/Program Files/Microsoft SDKs/Windows/v6.0a/include"
+ #"C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/include"
+ DOC "Specify the path to sql.h."
+ )
+
+ find_library(ODBC_LIBRARY
+ NAMES odbc odbcinst odbc32
+ PATHS
+ /usr/lib
+ /usr/lib/odbc
+ /usr/local/lib
+ /usr/local/lib/odbc
+ /usr/local/odbc/lib
+ #"C:/Program Files/ODBC/lib"
+ #"C:/ODBC/lib/debug"
+ #"C:/Program Files/Microsoft SDKs/Windows/v7.0A/Lib"
+ #"C:/Program Files/Microsoft SDKs/Windows/v6.0A/Lib"
+ #"C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/Lib"
+ DOC "Specify the ODBC driver manager library here."
+ )
+
+ mark_as_advanced(ODBC_LIBRARY ODBC_INCLUDES)
+
+ IF(ODBC_INCLUDES AND ODBC_LIBRARY)
+ get_filename_component(ODBC_INCLUDE_DIR "${ODBC_INCLUDES}" PATH)
+ set(CMAKE_REQUIRED_LIBRARIES ${ODBC_LIBRARY})
+ set(CMAKE_REQUIRED_INCLUDES ${ODBC_INCLUDE_DIR})
+ CHECK_CXX_SOURCE_COMPILES(
+"
+#include <stdio.h>
+#include <sql.h>
+#include <sqlext.h>
+typedef long BOOL; /* this fails with iODBC */
+int main() {
+ SQLULEN rowofs= 0; /* this fails on older unixODBC */
+ SQLExtendedFetch(NULL, 0, 0, &rowofs, NULL);
+ return 0;
+}
+" ODBC_OK)
+ ENDIF()
+
+ IF(ODBC_OK)
+ INCLUDE_DIRECTORIES(${ODBC_INCLUDE_DIR})
+ add_definitions(-DODBC_SUPPORT)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} tabodbc.cpp odbconn.cpp)
+ ELSE()
+ SET(ODBC_LIBRARY "")
+ ENDIF()
+ ELSE(NOT UNIX)
+ add_definitions(-DODBC_SUPPORT)
+ SET(ODBC_LIBRARY odbc32.lib odbccp32.lib)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES}
+ tabodbc.cpp tabodbc.h odbccat.h odbconn.cpp odbconn.h)
+ ENDIF(UNIX)
+ENDIF(CONNECT_WITH_ODBC)
+ADD_FEATURE_INFO(CONNECT_ODBC ODBC_LIBRARY "Support for ODBC in the CONNECT storage engine")
+
+#
+# JDBC with MongoDB Java Driver included but disabled if without MONGO
+#
+OPTION(CONNECT_WITH_MONGO "Compile CONNECT storage engine with MONGO support" ON)
+OPTION(CONNECT_WITH_JDBC "Compile CONNECT storage engine with JDBC support" ON)
+
+IF(CONNECT_WITH_JDBC)
+ FIND_PACKAGE(Java 1.6)
+ SET_PACKAGE_PROPERTIES(Java PROPERTIES TYPE OPTIONAL)
+ FIND_PACKAGE(JNI)
+ SET_PACKAGE_PROPERTIES(JNI PROPERTIES TYPE OPTIONAL)
+ IF (JAVA_FOUND AND JNI_FOUND)
+ INCLUDE(UseJava)
+ INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH})
+ INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH2})
+ # SET(JDBC_LIBRARY ${JAVA_JVM_LIBRARY}) will be dynamically linked
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES}
+ javaconn.cpp jdbconn.cpp tabjdbc.cpp
+ jmgfam.cpp jmgoconn.cpp mongo.cpp tabjmg.cpp
+ jdbccat.h javaconn.h jdbconn.h tabjdbc.h
+ jmgfam.h jmgoconn.h mongo.h tabjmg.h
+ JdbcInterface.java ApacheInterface.java MariadbInterface.java
+ MysqlInterface.java OracleInterface.java PostgresqlInterface.java
+ Mongo2Interface.java Mongo3Interface.java
+ mysql-test/connect/std_data/JavaWrappers.jar)
+ add_definitions(-DJAVA_SUPPORT)
+ ADD_FEATURE_INFO(CONNECT_JDBC "ON" "Support for JDBC in the CONNECT storage engine")
+ IF(CONNECT_WITH_MONGO)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES}
+ mysql-test/connect/std_data/Mongo2.jar
+ mysql-test/connect/std_data/Mongo3.jar)
+ add_definitions(-DMONGO_SUPPORT)
+ ENDIF()
+ ELSE()
+ SET(JDBC_LIBRARY "")
+ ADD_FEATURE_INFO(CONNECT_JDBC "OFF" "Support for JDBC in the CONNECT storage engine")
+ ENDIF()
+ELSE(CONNECT_WITH_JDBC)
+ ADD_FEATURE_INFO(CONNECT_JDBC "OFF" "Support for JDBC in the CONNECT storage engine")
+ENDIF(CONNECT_WITH_JDBC)
+
+#
+# ZIP
+#
+
+OPTION(CONNECT_WITH_ZIP "Compile CONNECT storage engine with ZIP support" ON)
+
+IF(CONNECT_WITH_ZIP)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} filamzip.cpp tabzip.cpp unzip.c ioapi.c zip.c
+ filamzip.h tabzip.h ioapi.h unzip.h zip.h)
+ add_definitions(-DZIP_SUPPORT -DNOCRYPT)
+ENDIF(CONNECT_WITH_ZIP)
+ADD_FEATURE_INFO(CONNECT_ZIP CONNECT_WITH_ZIP "Support for ZIP in the CONNECT storage engine")
+
+#
+# MONGO C Driver
+#
+
+IF(CONNECT_WITH_MONGO)
+ IF(WIN32)
+ # Adding some typical places to search in
+ SET(PC_MONGO_INCLUDE_DIRS
+ C:/mongo-c-driver/include
+ D:/mongo-c-driver/include)
+ SET(PC_MONGO_LIBRARY_DIRS
+ C:/mongo-c-driver/lib
+ D:/mongo-c-driver/lib)
+ ENDIF(WIN32)
+ FIND_PACKAGE(libmongoc-1.0 1.7 QUIET)
+ SET_PACKAGE_PROPERTIES(libmongoc PROPERTIES TYPE OPTIONAL)
+ IF (libmongoc-1.0_FOUND)
+ INCLUDE_DIRECTORIES(${MONGOC_INCLUDE_DIRS})
+ SET(MONGOC_LIBRARY ${MONGOC_LIBRARIES})
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES}
+ cmgoconn.cpp cmgfam.cpp tabcmg.cpp
+ cmgoconn.h cmgfam.h tabcmg.h)
+ add_definitions(-DCMGO_SUPPORT)
+ ADD_FEATURE_INFO(CONNECT_MONGODB "ON" "Support for MongoDB in the CONNECT storage engine")
+ IF (NOT JAVA_FOUND AND JNI_FOUND)
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} mongo.cpp mongo.h)
+ add_definitions(-DMONGO_SUPPORT)
+ ENDIF (NOT JAVA_FOUND AND JNI_FOUND)
+ ELSE(libmongoc-1.0_FOUND)
+ ADD_FEATURE_INFO(CONNECT_MONGODB "OFF" "Support for MongoDB in the CONNECT storage engine")
+ ENDIF(libmongoc-1.0_FOUND)
+ELSE(CONNECT_WITH_MONGO)
+ ADD_FEATURE_INFO(CONNECT_MONGODB "OFF" "Support for MongoDB in the CONNECT storage engine")
+ENDIF(CONNECT_WITH_MONGO)
+
+#
+# REST
+#
+
+OPTION(CONNECT_WITH_REST "Compile CONNECT storage engine with REST support" ON)
+
+IF(CONNECT_WITH_REST)
+# MESSAGE(STATUS "=====> REST support is ON")
+ SET(CONNECT_SOURCES ${CONNECT_SOURCES} tabrest.cpp tabrest.h)
+ add_definitions(-DREST_SUPPORT)
+# FIND_PACKAGE(cpprestsdk QUIET)
+# IF (cpprestsdk_FOUND)
+# IF(UNIX)
+## INCLUDE_DIRECTORIES(${CPPRESTSDK_INCLUDE_DIR})
+## If needed edit next line to set the path to libcpprest.so
+# SET(REST_LIBRARY -lcpprest)
+# MESSAGE (STATUS ${REST_LIBRARY})
+# ELSE(NOT UNIX)
+## Next line sets debug compile mode matching cpprest_2_10d.dll
+## when it was binary installed (can be change later in Visual Studio)
+## Comment it out if not needed depending on your cpprestsdk installation.
+# SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
+# ENDIF(UNIX)
+## IF(REST_LIBRARY) why this? how about Windows
+# SET(CONNECT_SOURCES ${CONNECT_SOURCES} restget.cpp)
+# add_definitions(-DREST_SOURCE)
+## ENDIF()
+##ELSE(NOT cpprestsdk_FOUND)
+## MESSAGE(STATUS "=====> cpprestsdk package not found")
+# ENDIF (cpprestsdk_FOUND)
+ENDIF(CONNECT_WITH_REST)
+ADD_FEATURE_INFO(CONNECT_REST CONNECT_WITH_REST "Support for REST API in the CONNECT storage engine")
+
+#
+# XMAP
+#
+
+OPTION(CONNECT_WITH_XMAP "Compile CONNECT storage engine with index file mapping support" ON)
+
+IF(CONNECT_WITH_XMAP)
+ add_definitions(-DXMAP)
+ENDIF(CONNECT_WITH_XMAP)
+ADD_FEATURE_INFO(CONNECT_XMAP CONNECT_WITH_XMAP "Support for index file mapping in the CONNECT storage engine")
+
+#
+# Plugin definition
+#
+
+MYSQL_ADD_PLUGIN(connect ${CONNECT_SOURCES}
+ STORAGE_ENGINE
+ COMPONENT connect-engine
+ RECOMPILE_FOR_EMBEDDED
+ LINK_LIBRARIES ${ZLIB_LIBRARY} ${XML_LIBRARY} ${ICONV_LIBRARY}
+ ${ODBC_LIBRARY} ${JDBC_LIBRARY} ${MONGOC_LIBRARY} ${IPHLPAPI_LIBRARY} ${REST_LIBRARY})
+
+IF(NOT TARGET connect)
+ RETURN()
+ENDIF()
+
+IF(MSVC AND (CMAKE_CXX_FLAGS MATCHES "/MP"))
+ # domdoc.cpp uses compiler directive #import which is not compatible
+ # with the /MP option, resulting in compiler error C2813.
+ # Remove /MP for this file.
+ SET(src_list ${CONNECT_SOURCES})
+ LIST(FIND src_list domdoc.cpp idx)
+ IF(idx GREATER -1)
+ STRING(REPLACE "/MP" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ LIST(REMOVE_AT src_list ${idx})
+ SET_SOURCE_FILES_PROPERTIES(${src_list} PROPERTIES COMPILE_FLAGS "/MP")
+ ENDIF()
+ENDIF()
+
+IF(WIN32)
+ IF (libmongoc-1.0_FOUND)
+ SET_TARGET_PROPERTIES(connect PROPERTIES LINK_FLAGS
+ "/DELAYLOAD:libbson-1.0.dll /DELAYLOAD:libmongoc-1.0.dll")
+ ENDIF(libmongoc-1.0_FOUND)
+
+# Install some extra files that belong to connect engine
+
+ INSTALL(FILES "$<TARGET_FILE_DIR:connect>/ha_connect.lib"
+ DESTINATION ${INSTALL_PLUGINDIR} COMPONENT connect-engine)
+ENDIF(WIN32)
+
+IF(MSVC)
+ # Temporarily disable "conversion from size_t .."
+ IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4267")
+ ENDIF()
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4996")
+ string(REPLACE "/permissive-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ENDIF()
+
+IF(CONNECT_WITH_JDBC AND JAVA_FOUND AND JNI_FOUND)
+ # TODO: Find how to compile and install the java wrapper classes
+ # Find required libraries and include directories
+ SET (JAVA_SOURCES JdbcInterface.java)
+ add_jar(JdbcInterface ${JAVA_SOURCES})
+ INSTALL(FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/mysql-test/connect/std_data/JavaWrappers.jar
+ ${CMAKE_CURRENT_BINARY_DIR}/JdbcInterface.jar
+ DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT connect-engine)
+ IF(CONNECT_WITH_MONGO)
+ INSTALL(FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/mysql-test/connect/std_data/Mongo2.jar
+ ${CMAKE_CURRENT_SOURCE_DIR}/mysql-test/connect/std_data/Mongo3.jar
+ DESTINATION ${INSTALL_MYSQLSHAREDIR} COMPONENT connect-engine)
+ ENDIF()
+ENDIF()
diff --git a/storage/connect/Client.java b/storage/connect/Client.java
new file mode 100644
index 00000000..afa54fa4
--- /dev/null
+++ b/storage/connect/Client.java
@@ -0,0 +1,200 @@
+
+package wrappers;
+
+import java.io.BufferedReader;
+import java.io.Console;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+
+public class Client {
+ static boolean DEBUG = true;
+ static final Console c = System.console();
+ static JdbcInterface jdi = null;
+
+ public static void main(String[] args) {
+ int rc, n, ncol, i = 0, fsize = 0;
+ boolean scrollable = false;
+ String s;
+ String[] parms = new String[4];
+
+ if (args.length > 0)
+ try {
+ i = Integer.parseInt(args[i]);
+ } catch (NumberFormatException e) {
+ i = 0;
+ } // end try/catch
+
+ switch (i) {
+ case 1:
+ jdi = new ApacheInterface(DEBUG);
+ break;
+ case 2:
+ jdi = new MysqlInterface(DEBUG);
+ break;
+ case 3:
+ jdi = new MariadbInterface(DEBUG);
+ break;
+ case 4:
+ jdi = new OracleInterface(DEBUG);
+ break;
+ case 5:
+ jdi = new PostgresqlInterface(DEBUG);
+ break;
+ default:
+ jdi = new JdbcInterface(DEBUG);
+ } // endswitch i
+
+ parms[0] = getLine("Driver: ", false);
+ parms[1] = getLine("URL: ", false);
+ parms[2] = getLine("User: ", false);
+ parms[3] = getLine("Password: ", true);
+ s = getLine("Fsize: ", false);
+ fsize = (s != null) ? Integer.parseInt(s) : 0;
+ s = getLine("Scrollable: ", false);
+ scrollable = (s != null) ? s.toLowerCase().charAt(0) != 'n' : false;
+
+ rc = jdi.JdbcConnect(parms, fsize, scrollable);
+
+ if (rc == 0) {
+ String query;
+ System.out.println("Successfully connected to " + parms[1]);
+
+ s = jdi.GetQuoteString();
+ System.out.println("Qstr = '" + s + "'");
+
+ while ((query = getLine("Query: ", false)) != null) {
+ n = jdi.Execute(query);
+ System.out.println("Returned n = " + n);
+
+ if ((ncol = jdi.GetResult()) > 0)
+ PrintResult(ncol);
+ else
+ System.out.println("Affected rows = " + n);
+
+ } // endwhile
+
+ rc = jdi.JdbcDisconnect();
+ System.out.println("Disconnect returned " + rc);
+ } else
+ System.out.println(jdi.GetErrmsg() + " rc=" + rc);
+
+ } // end of main
+
+ private static void PrintResult(int ncol) {
+ // Get result set meta data
+ int i;
+ Date date = new Date(0);
+ Time time = new Time(0);
+ Timestamp tsp = new Timestamp(0);
+ String columnName;
+ Object job;
+
+ // Get the column names; column indices start from 1
+ for (i = 1; i <= ncol; i++) {
+ columnName = jdi.ColumnName(i);
+
+ if (columnName == null)
+ return;
+
+ // Get the name of the column's table name
+ //String tableName = rsmd.getTableName(i);
+
+ if (i > 1)
+ System.out.print("\t");
+
+ System.out.print(columnName);
+ } // endfor i
+
+ System.out.println();
+
+ // Loop through the result set
+ while (jdi.ReadNext() > 0) {
+ for (i = 1; i <= ncol; i++) {
+ if (i > 1)
+ System.out.print("\t");
+
+ if (DEBUG)
+ System.out.print("(" + jdi.ColumnType(i, null) + ")");
+
+ switch (jdi.ColumnType(i, null)) {
+ case java.sql.Types.VARCHAR:
+ case java.sql.Types.LONGVARCHAR:
+ case java.sql.Types.CHAR:
+ case 1111:
+ System.out.print(jdi.StringField(i, null));
+ break;
+ case java.sql.Types.INTEGER:
+ System.out.print(jdi.IntField(i, null));
+ break;
+ case java.sql.Types.BIGINT:
+ System.out.print(jdi.BigintField(i, null));
+ break;
+ case java.sql.Types.TIME:
+ time.setTime((long)jdi.TimeField(i, null) * 1000);
+ System.out.print(time);
+ break;
+ case java.sql.Types.DATE:
+ date.setTime((long)jdi.DateField(i, null) * 1000);
+ System.out.print(date);
+ break;
+ case java.sql.Types.TIMESTAMP:
+ tsp.setTime((long)jdi.TimestampField(i, null) * 1000);
+ System.out.print(tsp);
+ break;
+ case java.sql.Types.SMALLINT:
+ System.out.print(jdi.IntField(i, null));
+ break;
+ case java.sql.Types.DOUBLE:
+ case java.sql.Types.REAL:
+ case java.sql.Types.FLOAT:
+ case java.sql.Types.DECIMAL:
+ System.out.print(jdi.DoubleField(i, null));
+ break;
+ case java.sql.Types.BOOLEAN:
+ System.out.print(jdi.BooleanField(i, null));
+ default:
+ job = jdi.ObjectField(i, null);
+ System.out.print(job.toString());
+ break;
+ } // endswitch Type
+
+ } // endfor i
+
+ System.out.println();
+ } // end while rs
+
+ } // end of PrintResult
+
+ // ==================================================================
+ private static String getLine(String p, boolean b) {
+ String response;
+
+ if (c != null) {
+ // Standard console mode
+ if (b) {
+ response = new String(c.readPassword(p));
+ } else
+ response = c.readLine(p);
+
+ } else {
+ // For instance when testing from Eclipse
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+
+ System.out.print(p);
+
+ try {
+ // Cannot suppress echo for password entry
+ response = in.readLine();
+ } catch (IOException e) {
+ response = "";
+ } // end of try/catch
+
+ } // endif c
+
+ return (response.isEmpty()) ? null : response;
+ } // end of getLine
+
+} // end of class Client
diff --git a/storage/connect/Client2.java b/storage/connect/Client2.java
new file mode 100644
index 00000000..6dbf4188
--- /dev/null
+++ b/storage/connect/Client2.java
@@ -0,0 +1,130 @@
+package wrappers;
+
+import java.io.BufferedReader;
+import java.io.Console;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Set;
+
+public class Client2 {
+ static boolean DEBUG = true;
+ static final Console c = System.console();
+ static Mongo2Interface jdi = null;
+
+ public static void main(String[] args) {
+ int rc, m, i = 0;
+ boolean brc;
+ Set<String> columns;
+ String[] parms = new String[4];
+
+ jdi = new Mongo2Interface(DEBUG);
+
+ parms[0] = getLine("URI: ", false);
+ parms[1] = getLine("DB: ", false);
+ parms[2] = null;
+ parms[3] = null;
+
+ if (parms[0] == null)
+ parms[0] = "mongodb://localhost:27017";
+
+ if (parms[1] == null)
+ parms[1] = "test";
+
+ rc = jdi.MongoConnect(parms);
+
+ if (rc == 0) {
+ String name, pipeline, query, fields;
+ System.out.println("Successfully connected to " + parms[1]);
+
+ while ((name = getLine("Collection: ", false)) != null) {
+ if (jdi.GetCollection(name))
+ System.out.println("GetCollection failed");
+ else
+ System.out.println("Collection size: " + jdi.GetCollSize());
+
+ pipeline = getLine("Pipeline: ", false);
+
+ if (pipeline == null) {
+ query = getLine("Filter: ", false);
+ fields = getLine("Proj: ", false);
+ brc = jdi.FindColl(query, fields);
+ } else
+ brc = jdi.AggregateColl(pipeline);
+
+ System.out.println("Returned brc = " + brc);
+
+ if (!brc) {
+ for (i = 0; i < 10; i++) {
+ m = jdi.ReadNext();
+
+ if (m > 0) {
+ columns = jdi.GetColumns();
+
+ for (String col : columns)
+ System.out.println(col + "=" + jdi.GetField(col));
+
+ if (pipeline == null) {
+ if (name.equalsIgnoreCase("gtst"))
+ System.out.println("gtst=" + jdi.GetField("*"));
+
+ if (name.equalsIgnoreCase("inventory")) {
+ System.out.println("warehouse=" + jdi.GetField("instock.0.warehouse"));
+ System.out.println("quantity=" + jdi.GetField("instock.1.qty"));
+ } // endif inventory
+
+ if (name.equalsIgnoreCase("restaurants")) {
+ System.out.println("score=" + jdi.GetField("grades.0.score"));
+ System.out.println("date=" + jdi.GetField("grades.0.date"));
+ } // endif restaurants
+
+ } // endif pipeline
+
+ } else if (m < 0) {
+ System.out.println("ReadNext: " + jdi.GetErrmsg());
+ break;
+ } else
+ break;
+
+ } // endfor i
+
+ } // endif brc
+
+ } // endwhile name
+
+ rc = jdi.MongoDisconnect();
+ System.out.println("Disconnect returned " + rc);
+ } else
+ System.out.println(jdi.GetErrmsg() + " rc=" + rc);
+
+ } // end of main
+
+ // ==================================================================
+ private static String getLine(String p, boolean b) {
+ String response;
+
+ if (c != null) {
+ // Standard console mode
+ if (b) {
+ response = new String(c.readPassword(p));
+ } else
+ response = c.readLine(p);
+
+ } else {
+ // For instance when testing from Eclipse
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+
+ System.out.print(p);
+
+ try {
+ // Cannot suppress echo for password entry
+ response = in.readLine();
+ } catch (IOException e) {
+ response = "";
+ } // end of try/catch
+
+ } // endif c
+
+ return (response.isEmpty()) ? null : response;
+ } // end of getLine
+
+} // end of class Client
diff --git a/storage/connect/Client3.java b/storage/connect/Client3.java
new file mode 100644
index 00000000..0d3914cd
--- /dev/null
+++ b/storage/connect/Client3.java
@@ -0,0 +1,154 @@
+package wrappers;
+
+import java.io.BufferedReader;
+import java.io.Console;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Set;
+
+public class Client3 {
+ static boolean DEBUG = true;
+ static final Console c = System.console();
+ static Mongo3Interface jdi = null;
+
+ public static void main(String[] args) {
+ int rc, level = 0;
+ boolean brc, desc = false;
+ Set<String> columns;
+ String[] parms = new String[4];
+
+ jdi = new Mongo3Interface(DEBUG);
+
+ parms[0] = getLine("URI: ", false);
+ parms[1] = getLine("Database: ", false);
+ parms[2] = null;
+ parms[3] = null;
+
+ if (parms[0] == null)
+ parms[0] = "mongodb://localhost:27017";
+
+ if (parms[1] == null)
+ parms[1] = "test";
+
+ rc = jdi.MongoConnect(parms);
+
+ if (rc == 0) {
+ String name, pipeline, query, fields;
+ System.out.println("Successfully connected to " + parms[0]);
+
+ while ((name = getLine("Collection: ", false)) != null) {
+ if (jdi.GetCollection(name))
+ System.out.println("GetCollection failed");
+ else
+ System.out.println("Collection size: " + jdi.GetCollSize());
+
+ pipeline = getLine("Pipeline: ", false);
+
+ if (pipeline == null || (desc = pipeline.equals("*"))) {
+ query = getLine("Filter: ", false);
+ fields = getLine("Proj: ", false);
+
+ if (desc)
+ level = Integer.parseInt(getLine("Level: ", false));
+
+ brc = jdi.FindColl(query, fields);
+ } else
+ brc = jdi.AggregateColl(pipeline);
+
+ System.out.println("Returned brc = " + brc);
+
+ if (!brc && !desc) {
+ for (int i = 0; jdi.ReadNext() > 0 && i < 10; i++) {
+ columns = jdi.GetColumns();
+
+ for (String col : columns)
+ System.out.println(col + "=" + jdi.GetField(col));
+
+ if (name.equalsIgnoreCase("gtst"))
+ System.out.println("gtst=" + jdi.GetField("*"));
+
+ if (name.equalsIgnoreCase("inventory")) {
+ System.out.println("warehouse=" + jdi.GetField("instock.0.warehouse"));
+ System.out.println("quantity=" + jdi.GetField("instock.1.qty"));
+ } // endif inventory
+
+ if (name.equalsIgnoreCase("restaurants")) {
+ System.out.println("score=" + jdi.GetField("grades.0.score"));
+ System.out.println("date=" + jdi.GetField("grades.0.date"));
+ } // endif inventory
+
+ } // endfor i
+
+ } else if (desc) {
+ int ncol;
+
+ for (int i = 0; (ncol = jdi.ReadNext()) > 0 && i < 2; i++) {
+ if (discovery(null, "", ncol, level))
+ break;
+
+ System.out.println("--------------");
+ } // endfor i
+
+ } // endif desc
+
+ } // endwhile query
+
+ rc = jdi.MongoDisconnect();
+ System.out.println("Disconnect returned " + rc);
+ } else
+ System.out.println(jdi.GetErrmsg() + " rc=" + rc);
+
+ } // end of main
+
+ private static boolean discovery(Object obj, String name, int ncol, int level) {
+ int[] val = new int[5];
+ Object ret = null;
+ String bvn = null;
+
+ for (int k = 0; k < ncol; k++) {
+ ret = jdi.ColumnDesc(obj, k, val, level);
+ bvn = jdi.ColDescName();
+
+ if (ret != null)
+ discovery(ret, name.concat(bvn).concat("."), val[4], level - 1);
+ else if (val[0] > 0)
+ System.out.println(
+ name + bvn + ": type=" + val[0] + " length=" + val[1] + " prec=" + val[2] + " nullable=" + val[3]);
+ else if (val[0] < 0)
+ System.out.println(jdi.GetErrmsg());
+
+ } // endfor k
+
+ return false;
+ } // end of discovery
+
+ // ==================================================================
+ private static String getLine(String p, boolean b) {
+ String response;
+
+ if (c != null) {
+ // Standard console mode
+ if (b) {
+ response = new String(c.readPassword(p));
+ } else
+ response = c.readLine(p);
+
+ } else {
+ // For instance when testing from Eclipse
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+
+ System.out.print(p);
+
+ try {
+ // Cannot suppress echo for password entry
+ response = in.readLine();
+ } catch (IOException e) {
+ response = "";
+ } // end of try/catch
+
+ } // endif c
+
+ return (response.isEmpty()) ? null : response;
+ } // end of getLine
+
+} // end of class Client
diff --git a/storage/connect/JdbcInterface.java b/storage/connect/JdbcInterface.java
new file mode 100644
index 00000000..72ee4ab0
--- /dev/null
+++ b/storage/connect/JdbcInterface.java
@@ -0,0 +1,834 @@
+package wrappers;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.Date;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+public class JdbcInterface {
+ // This is used by DS classes
+ static Hashtable<String,DataSource> dst = null;
+
+ boolean DEBUG = false;
+ boolean CatisSchema = false;
+ String Errmsg = "No error";
+ Connection conn = null;
+ DatabaseMetaData dbmd = null;
+ Statement stmt = null;
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ ResultSetMetaData rsmd = null;
+
+ // === Constructors/finalize =========================================
+ public JdbcInterface() {
+ this(false);
+ } // end of default constructor
+
+ public JdbcInterface(boolean b) {
+ DEBUG = b;
+ } // end of constructor
+
+ protected void SetErrmsg(Exception e) {
+ if (DEBUG)
+ System.out.println(e.getMessage());
+
+ Errmsg = e.toString();
+ } // end of SetErrmsg
+
+ public String GetErrmsg() {
+ String err = Errmsg;
+
+ Errmsg = "No error";
+ return err;
+ } // end of GetErrmsg
+
+ protected void CheckURL(String url, String vendor) throws Exception {
+ if (url == null)
+ throw new Exception("URL cannot be null");
+
+ String[] tk = url.split(":", 3);
+
+ if (!tk[0].equals("jdbc") || tk[1] == null)
+ throw new Exception("Invalid URL");
+
+ if (vendor != null && !tk[1].equals(vendor))
+ throw new Exception("Wrong URL for this wrapper");
+
+ // Some drivers use Catalog as Schema
+ CatisSchema = tk[1].equals("mysql") || tk[1].equals("mariadb");
+ } // end of CatalogIsSchema
+
+ public int JdbcConnect(String[] parms, int fsize, boolean scrollable) {
+ int rc = 0;
+
+ if (DEBUG)
+ System.out.println("In JdbcInterface: driver=" + parms[0]);
+
+ try {
+ if (DEBUG)
+ System.out.println("In try block");
+
+ if (parms[0] != null && !parms[0].isEmpty()) {
+ if (DEBUG)
+ System.out.println("Loading class" + parms[0]);
+
+ Class.forName(parms[0]); //loads the driver
+ } // endif driver
+
+ if (DEBUG)
+ System.out.println("URL=" + parms[1]);
+
+ CheckURL(parms[1], null);
+
+ // This is required for drivers using context class loaders
+ Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+
+ if (parms[2] != null && !parms[2].isEmpty()) {
+ if (DEBUG)
+ System.out.println("user=" + parms[2] + " pwd=" + parms[3]);
+
+ conn = DriverManager.getConnection(parms[1], parms[2], parms[3]);
+ } else
+ conn = DriverManager.getConnection(parms[1]);
+
+ if (DEBUG)
+ System.out.println("Connection " + conn.toString() + " established");
+
+ // Get the data base meta data object
+ dbmd = conn.getMetaData();
+
+ // Get a statement from the connection
+ stmt = GetStmt(fsize, scrollable);
+ } catch(ClassNotFoundException e) {
+ SetErrmsg(e);
+ rc = -1;
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ rc = -2;
+ } catch( Exception e ) {
+ SetErrmsg(e);
+ rc = -3;
+ } // end try/catch
+
+ return rc;
+ } // end of JdbcConnect
+
+ protected Statement GetStmt(int fsize, boolean scrollable) throws SQLException, Exception {
+ Statement stmt = null;
+
+ if (scrollable)
+ stmt = conn.createStatement(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE, java.sql.ResultSet.CONCUR_READ_ONLY);
+ else
+ stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY);
+
+ if (DEBUG)
+ System.out.println("Statement type = " + stmt.getResultSetType()
+ + " concurrency = " + stmt.getResultSetConcurrency());
+
+ if (DEBUG) // Get the fetch size of a statement
+ System.out.println("Default fetch size = " + stmt.getFetchSize());
+
+ if (fsize != 0) {
+ // Set the fetch size
+ stmt.setFetchSize(fsize);
+
+ if (DEBUG)
+ System.out.println("New fetch size = " + stmt.getFetchSize());
+
+ } // endif fsize
+
+ return stmt;
+ } // end of GetStmt
+
+
+ public int CreatePrepStmt(String sql) {
+ int rc = 0;
+
+ try {
+ pstmt = conn.prepareStatement(sql);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ rc = -1;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ rc = -2;
+ } // end try/catch
+
+ return rc;
+ } // end of CreatePrepStmt
+
+ public void SetStringParm(int i, String s) {
+ try {
+ pstmt.setString(i, s);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ } // end try/catch
+
+ } // end of SetStringParm
+
+ public void SetIntParm(int i, int n) {
+ try {
+ pstmt.setInt(i, n);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ } // end try/catch
+
+ } // end of SetIntParm
+
+ public void SetShortParm(int i, short n) {
+ try {
+ pstmt.setShort(i, n);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ } // end try/catch
+
+ } // end of SetShortParm
+
+ public void SetBigintParm(int i, long n) {
+ try {
+ pstmt.setLong(i, n);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ } // end try/catch
+
+ } // end of SetBigintParm
+
+ public void SetFloatParm(int i, float f) {
+ try {
+ pstmt.setFloat(i, f);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ } // end try/catch
+
+ } // end of SetFloatParm
+
+ public void SetDoubleParm(int i, double d) {
+ try {
+ pstmt.setDouble(i, d);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ } // end try/catch
+
+ } // end of SetDoubleParm
+
+ public void SetTimestampParm(int i, Timestamp t) {
+ try {
+ pstmt.setTimestamp(i, t);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ } // end try/catch
+
+ } // end of SetTimestampParm
+
+ public void SetUuidParm(int i, String s) {
+ try {
+ UUID uuid;
+
+ if (s == null)
+ uuid = null;
+ else if (s.isEmpty())
+ uuid = UUID.randomUUID();
+ else
+ uuid = UUID.fromString(s);
+
+ pstmt.setObject(i, uuid);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ } // end try/catch
+
+ } // end of SetUuidParm
+
+ public int SetNullParm(int i, int typ) {
+ int rc = 0;
+
+ try {
+ pstmt.setNull(i, typ);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ rc = -1;
+ } // end try/catch
+
+ return rc;
+ } // end of SetNullParm
+
+ public int ExecutePrep() {
+ int n = -3;
+
+ if (pstmt != null) try {
+ n = pstmt.executeUpdate();
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ n = -1;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ n = -2;
+ } //end try/catch
+
+ return n;
+ } // end of ExecutePrep
+
+ public boolean ClosePrepStmt() {
+ boolean b = false;
+
+ if (pstmt != null) try {
+ pstmt.close();
+ pstmt = null;
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ b = true;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ b = true;
+ } // end try/catch
+
+ return b;
+ } // end of ClosePrepStmt
+
+ public int JdbcDisconnect() {
+ int rc = 0;
+
+ // Cancel pending statement
+ if (stmt != null)
+ try {
+ if (DEBUG)
+ System.out.println("Cancelling statement");
+
+ stmt.cancel();
+ } catch(SQLException se) {
+ SetErrmsg(se);
+ rc += 1;
+ } // nothing more we can do
+
+ // Close the statement and the connection
+ if (rs != null)
+ try {
+ if (DEBUG)
+ System.out.println("Closing result set");
+
+ rs.close();
+ } catch(SQLException se) {
+ SetErrmsg(se);
+ rc = 2;
+ } // nothing more we can do
+
+ if (stmt != null)
+ try {
+ if (DEBUG)
+ System.out.println("Closing statement");
+
+ stmt.close();
+ } catch(SQLException se) {
+ SetErrmsg(se);
+ rc += 4;
+ } // nothing more we can do
+
+ ClosePrepStmt();
+
+ if (conn != null)
+ try {
+ if (DEBUG)
+ System.out.println("Closing connection");
+
+ conn.close();
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ rc += 8;
+ } //end try/catch
+
+ if (DEBUG)
+ System.out.println("All closed");
+
+ return rc;
+ } // end of JdbcDisconnect
+
+ public int GetMaxValue(int n) {
+ int m = 0;
+
+ try {
+ switch (n) {
+ case 1: // Max columns in table
+ m = dbmd.getMaxColumnsInTable();
+ break;
+ case 2: // Max catalog name length
+ m = dbmd.getMaxCatalogNameLength();
+ break;
+ case 3: // Max schema name length
+ m = dbmd.getMaxSchemaNameLength();
+ break;
+ case 4: // Max table name length
+ m = dbmd.getMaxTableNameLength();
+ break;
+ case 5: // Max column name length
+ m = dbmd.getMaxColumnNameLength();
+ break;
+ } // endswitch n
+
+ } catch(Exception e) {
+ SetErrmsg(e);
+ m = -1;
+ } // end try/catch
+
+ return m;
+ } // end of GetMaxValue
+
+ public String GetQuoteString() {
+ String qs = null;
+
+ try {
+ qs = dbmd.getIdentifierQuoteString();
+ } catch(SQLException se) {
+ SetErrmsg(se);
+ } // end try/catch
+
+ return qs;
+ } // end of GetQuoteString
+
+ public int GetColumns(String[] parms) {
+ int ncol = -1;
+
+ try {
+ if (rs != null) rs.close();
+
+ if (CatisSchema)
+ rs = dbmd.getColumns(parms[1], null, parms[2], parms[3]);
+ else
+ rs = dbmd.getColumns(parms[0], parms[1], parms[2], parms[3]);
+
+ if (rs != null) {
+ rsmd = rs.getMetaData();
+ ncol = rsmd.getColumnCount();
+ } // endif rs
+
+ } catch(SQLException se) {
+ SetErrmsg(se);
+ } // end try/catch
+
+ return ncol;
+ } // end of GetColumns
+
+ public int GetTables(String[] parms) {
+ int ncol = -1;
+ String[] typ = null;
+
+ if (parms[3] != null) {
+ typ = new String[1];
+ typ[0] = parms[3];
+ } // endif parms
+
+ try {
+ if (rs != null) rs.close();
+
+ if (CatisSchema)
+ rs = dbmd.getTables(parms[1], null, parms[2], typ);
+ else
+ rs = dbmd.getTables(parms[0], parms[1], parms[2], typ);
+
+ if (rs != null) {
+ rsmd = rs.getMetaData();
+ ncol = rsmd.getColumnCount();
+ } // endif rs
+
+ } catch(SQLException se) {
+ SetErrmsg(se);
+ } // end try/catch
+
+ return ncol;
+ } // end of GetColumns
+
+ public int Execute(String query) {
+ int n = 0;
+
+ if (DEBUG)
+ System.out.println("Executing '" + query + "'");
+
+ try {
+ boolean b = stmt.execute(query);
+
+ if (b == false) {
+ n = stmt.getUpdateCount();
+ if (rs != null) rs.close();
+ } // endif b
+
+ if (DEBUG)
+ System.out.println("Query '" + query + "' executed: n = " + n);
+
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ n = -1;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ n = -2;
+ } //end try/catch
+
+ return n;
+ } // end of Execute
+
+ public int GetResult() {
+ int ncol = 0;
+
+ try {
+ rs = stmt.getResultSet();
+
+ if (rs != null) {
+ rsmd = rs.getMetaData();
+ ncol = rsmd.getColumnCount();
+
+ if (DEBUG)
+ System.out.println("Result set has " + rsmd.getColumnCount() + " column(s)");
+
+ } // endif rs
+
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ ncol = -1;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ ncol = -2;
+ } //end try/catch
+
+ return ncol;
+ } // end of GetResult
+
+ public int ExecuteQuery(String query) {
+ int ncol = 0;
+
+ if (DEBUG)
+ System.out.println("Executing query '" + query + "'");
+
+ try {
+ if (rs != null)
+ rs.close();
+ rs = stmt.executeQuery(query);
+ rsmd = rs.getMetaData();
+ ncol = rsmd.getColumnCount();
+
+ if (DEBUG) {
+ System.out.println("Query '" + query + "' executed successfully");
+ System.out.println("Result set has " + rsmd.getColumnCount() + " column(s)");
+ } // endif DEBUG
+
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ ncol = -1;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ ncol = -2;
+ } //end try/catch
+
+ return ncol;
+ } // end of ExecuteQuery
+
+ public int ExecuteUpdate(String query) {
+ int n = 0;
+
+ if (DEBUG)
+ System.out.println("Executing update query '" + query + "'");
+
+ try {
+ n = stmt.executeUpdate(query);
+
+ if (DEBUG)
+ System.out.println("Update Query '" + query + "' executed: n = " + n);
+
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ n = -1;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ n = -2;
+ } //end try/catch
+
+ return n;
+ } // end of ExecuteUpdate
+
+ public int ReadNext() {
+ if (rs != null) {
+ try {
+ return rs.next() ? 1 : 0;
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ return -1;
+ } //end try/catch
+
+ } else
+ return 0;
+
+ } // end of ReadNext
+
+ public boolean Fetch(int row) {
+ if (rs != null) {
+ try {
+ return rs.absolute(row);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ return false;
+ } //end try/catch
+
+ } else
+ return false;
+
+ } // end of Fetch
+
+ public String ColumnName(int n) {
+ if (rsmd == null) {
+ System.out.println("No result metadata");
+ } else try {
+ return rsmd.getColumnLabel(n);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return null;
+ } // end of ColumnName
+
+ public int ColumnType(int n, String name) {
+ if (rsmd == null) {
+ System.out.println("No result metadata");
+ } else try {
+ if (n == 0)
+ n = rs.findColumn(name);
+
+ return rsmd.getColumnType(n);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return 666; // Not a type
+ } // end of ColumnType
+
+ public String ColumnDesc(int n, int[] val) {
+ if (rsmd == null) {
+ System.out.println("No result metadata");
+ return null;
+ } else try {
+ val[0] = rsmd.getColumnType(n);
+ val[1] = rsmd.getPrecision(n);
+ val[2] = rsmd.getScale(n);
+ val[3] = rsmd.isNullable(n);
+ return rsmd.getColumnLabel(n);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return null;
+ } // end of ColumnDesc
+
+ public String StringField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ return (n > 0) ? rs.getString(n) : rs.getString(name);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return null;
+ } // end of StringField
+
+ public int IntField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ return (n > 0) ? rs.getInt(n) : rs.getInt(name);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return 0;
+ } // end of IntField
+
+ public long BigintField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ BigDecimal bigDecimal = (n > 0) ? rs.getBigDecimal(n) : rs.getBigDecimal(name);
+ return bigDecimal != null ? bigDecimal.longValue() : 0;
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return 0;
+ } // end of BiginttField
+
+ public double DoubleField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ return (n > 0) ? rs.getDouble(n) : rs.getDouble(name);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return 0.;
+ } // end of DoubleField
+
+ public float FloatField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ return (n > 0) ? rs.getFloat(n) : rs.getFloat(name);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return 0;
+ } // end of FloatField
+
+ public boolean BooleanField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ return (n > 0) ? rs.getBoolean(n) : rs.getBoolean(name);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return false;
+ } // end of BooleanField
+
+ public int DateField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ Date d = (n > 0) ? rs.getDate(n) : rs.getDate(name);
+ return (d != null) ? (int)(d.getTime() / 1000) : 0;
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return 0;
+ } // end of DateField
+
+ public int TimeField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ Time t = (n > 0) ? rs.getTime(n) : rs.getTime(name);
+ return (t != null) ? (int)(t.getTime() / 1000) : 0;
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return 0;
+ } // end of TimeField
+
+ public int TimestampField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ Timestamp ts = (n > 0) ? rs.getTimestamp(n) : rs.getTimestamp(name);
+ return (ts != null) ? (int)(ts.getTime() / 1000) : 0;
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return 0;
+ } // end of TimestampField
+
+ public Object ObjectField(int n, String name) {
+ if (rs == null) {
+ System.out.println("No result set");
+ } else try {
+ return (n > 0) ? rs.getObject(n) : rs.getObject(name);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } //end try/catch
+
+ return null;
+ } // end of ObjectField
+
+ public String UuidField(int n, String name) {
+ Object job;
+
+ if (rs == null) {
+ System.out.println("No result set");
+ } else
+ try {
+ job = (n > 0) ? rs.getObject(n) : rs.getObject(name);
+ return job.toString();
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ } // end try/catch
+
+ return null;
+ } // end of UuidField
+
+ public int GetDrivers(String[] s, int mxs) {
+ int n = 0;
+ List<Driver> drivers = Collections.list(DriverManager.getDrivers());
+ int size = Math.min(mxs, drivers.size());
+
+ for (int i = 0; i < size; i++) {
+ Driver driver = (Driver)drivers.get(i);
+
+ // Get name of driver
+ s[n++] = driver.getClass().getName();
+
+ // Get version info
+ s[n++] = driver.getMajorVersion() + "." + driver.getMinorVersion();
+ s[n++] = driver.jdbcCompliant() ? "Yes" : "No";
+ s[n++] = driver.toString();
+ } // endfor i
+
+ return size;
+ } // end of GetDrivers
+
+ /**
+ * Adds the specified path to the java library path
+ * from Fahd Shariff blog
+ *
+ * @param pathToAdd the path to add
+ static public int addLibraryPath(String pathToAdd) {
+ System.out.println("jpath = " + pathToAdd);
+
+ try {
+ Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
+ usrPathsField.setAccessible(true);
+
+ //get array of paths
+ String[] paths = (String[])usrPathsField.get(null);
+
+ //check if the path to add is already present
+ for (String path : paths) {
+ System.out.println("path = " + path);
+
+ if (path.equals(pathToAdd))
+ return -5;
+
+ } // endfor path
+
+ //add the new path
+ String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
+ newPaths[paths.length] = pathToAdd;
+ usrPathsField.set(null, newPaths);
+ System.setProperty("java.library.path",
+ System.getProperty("java.library.path") + File.pathSeparator + pathToAdd);
+ Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
+ fieldSysPath.setAccessible(true);
+ fieldSysPath.set(null, null);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ return -1;
+ } // end try/catch
+
+ return 0;
+ } // end of addLibraryPath
+ */
+
+} // end of class JdbcInterface
+
diff --git a/storage/connect/MariadbInterface.java b/storage/connect/MariadbInterface.java
new file mode 100644
index 00000000..26ff7a82
--- /dev/null
+++ b/storage/connect/MariadbInterface.java
@@ -0,0 +1,69 @@
+package wrappers;
+
+import java.sql.*;
+import java.util.Hashtable;
+
+import javax.sql.DataSource;
+import org.mariadb.jdbc.MariaDbDataSource;
+
+public class MariadbInterface extends JdbcInterface {
+ public MariadbInterface() {
+ this(true);
+ } // end of default constructor
+
+ public MariadbInterface(boolean b) {
+ super(b);
+
+ if (dst == null)
+ dst = new Hashtable<String, DataSource>();
+
+ } // end of default constructor
+
+ @Override
+ public int JdbcConnect(String[] parms, int fsize, boolean scrollable) {
+ int rc = 0;
+ String url = parms[1];
+ DataSource ds = null;
+ MariaDbDataSource ads = null;
+
+ if (DEBUG)
+ System.out.println("Connecting to MariaDB data source");
+
+ try {
+ CheckURL(url, "mariadb");
+
+ if ((ds = dst.get(url)) == null) {
+ ads = new MariaDbDataSource();
+ ads.setUrl(url);
+
+ if (parms[2] != null)
+ ads.setUser(parms[2]);
+
+ if (parms[3] != null)
+ ads.setPassword(parms[3]);
+
+ ds = ads;
+
+ dst.put(url, ds);
+ } // endif ds
+
+ // Get a connection from the data source
+ conn = ds.getConnection();
+
+ // Get the data base meta data object
+ dbmd = conn.getMetaData();
+
+ // Get a statement from the connection
+ stmt = GetStmt(fsize, scrollable);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ rc = -2;
+ } catch( Exception e ) {
+ SetErrmsg(e);
+ rc = -3;
+ } // end try/catch
+
+ return rc;
+ } // end of JdbcConnect
+
+}
diff --git a/storage/connect/Mongo2Interface.java b/storage/connect/Mongo2Interface.java
new file mode 100644
index 00000000..5d27fe46
--- /dev/null
+++ b/storage/connect/Mongo2Interface.java
@@ -0,0 +1,531 @@
+package wrappers;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import com.mongodb.AggregationOptions;
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.Cursor;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientURI;
+import com.mongodb.MongoException;
+import com.mongodb.WriteConcernException;
+import com.mongodb.WriteResult;
+import com.mongodb.util.JSON;
+
+public class Mongo2Interface {
+ boolean DEBUG = false;
+ String Errmsg = "No error";
+ String ovalName = null;
+ Set<String> Colnames = null;
+ Cursor cursor = null;
+ MongoClient client = null;
+ DB db = null;
+ DBCollection coll = null;
+ BasicDBObject doc = null;
+ BasicDBObject dbq = null;
+ BasicDBObject dbf = null;
+ List<DBObject> pip = null;
+ AggregationOptions aop = null;
+
+ // === Constructors/finalize =========================================
+ public Mongo2Interface() {
+ this(false);
+ } // end of default constructor
+
+ public Mongo2Interface(boolean b) {
+ DEBUG = b;
+ } // end of constructor
+
+ protected void SetErrmsg(String str) {
+ if (DEBUG)
+ System.out.println(str);
+
+ Errmsg = str;
+ } // end of SetErrmsg
+
+ protected void SetErrmsg(Exception e) {
+ if (DEBUG)
+ System.out.println(e.getMessage());
+
+ Errmsg = e.toString();
+ } // end of SetErrmsg
+
+ public String GetErrmsg() {
+ String err = Errmsg;
+
+ Errmsg = "No error";
+ return err;
+ } // end of GetErrmsg
+
+ public int MongoConnect(String[] parms) {
+ int rc = 0;
+
+ if (DEBUG)
+ System.out.println("Mongo2: URI=" + parms[0] + " DB=" + parms[1]);
+
+ try {
+ MongoClientURI uri = new MongoClientURI(parms[0]);
+
+ client = new MongoClient(uri);
+
+ if (DEBUG)
+ System.out.println("Connection " + client.toString() + " established");
+
+ // Now connect to your databases
+ db = client.getDB(parms[1]);
+
+ if (parms[2] != null && !parms[2].isEmpty()) {
+ if (DEBUG)
+ System.out.println("user=" + parms[2] + " pwd=" + parms[3]);
+
+ @SuppressWarnings("deprecation")
+ boolean auth = db.authenticate(parms[2], parms[3].toCharArray());
+
+ if (DEBUG)
+ System.out.println("Authentication: " + auth);
+
+ } // endif user
+
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ rc = -1;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ rc = -3;
+ } // end try/catch
+
+ return rc;
+ } // end of MongoConnect
+
+ public int MongoDisconnect() {
+ int rc = 0;
+
+ try {
+ if (cursor != null) {
+ if (DEBUG)
+ System.out.println("Closing cursor");
+
+ cursor.close();
+ cursor = null;
+ } // endif client
+
+ if (client != null) {
+ if (DEBUG)
+ System.out.println("Closing connection");
+
+ client.close();
+ client = null;
+ } // endif client
+
+ } catch (MongoException se) {
+ SetErrmsg(se);
+ rc += 8;
+ } // end try/catch
+
+ return rc;
+ } // end of MongoDisconnect
+
+ public boolean GetCollection(String name) {
+ if (DEBUG)
+ System.out.println("GetCollection: name=" + name);
+
+ try {
+ coll = db.getCollection(name);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of GetCollection
+
+ public long GetCollSize() {
+ return (coll != null) ? coll.count() : 0;
+ } // end of GetCollSize
+
+ public boolean FindColl(String query, String fields) {
+ if (DEBUG)
+ System.out.println("FindColl: query=" + query + " fields=" + fields);
+
+ try {
+ if (query != null || fields != null) {
+ dbq = (BasicDBObject) JSON.parse((query != null) ? query : "{}");
+
+ if (fields != null) {
+ dbf = (BasicDBObject) JSON.parse(fields);
+ cursor = coll.find(dbq, dbf);
+ } else
+ cursor = coll.find(dbq);
+
+ } else
+ cursor = coll.find();
+
+ } catch (Exception e) {
+ SetErrmsg(e);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of FindColl
+
+ @SuppressWarnings("unchecked")
+ public boolean AggregateColl(String pipeline) {
+ if (DEBUG)
+ System.out.println("AggregateColl: pipeline=" + pipeline);
+
+ try {
+ DBObject pipe = (DBObject) JSON.parse(pipeline);
+
+ pip = (List<DBObject>) pipe.get("pipeline");
+ aop = AggregationOptions.builder().batchSize(0).allowDiskUse(true)
+ .outputMode(AggregationOptions.OutputMode.CURSOR).build();
+ cursor = coll.aggregate(pip, aop);
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of AggregateColl
+
+ public boolean Rewind() {
+ if (cursor != null)
+ cursor.close();
+
+ if (pip == null) {
+ if (dbf != null)
+ cursor = coll.find(dbq, dbf);
+ else if (dbq != null)
+ cursor = coll.find(dbq);
+ else
+ cursor = coll.find();
+
+ } else
+ cursor = coll.aggregate(pip, aop);
+
+ return (cursor == null);
+ } // end of Rewind
+
+ public int ReadNext() {
+ try {
+ if (cursor.hasNext()) {
+ doc = (BasicDBObject) cursor.next();
+
+ if (DEBUG)
+ System.out.println("Class doc = " + doc.getClass());
+
+ Colnames = doc.keySet();
+ return Colnames.size();
+ } else
+ return 0;
+
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return -1;
+ } // end try/catch
+
+ } // end of ReadNext
+
+ public boolean Fetch(int row) {
+ if (cursor.hasNext()) {
+ doc = (BasicDBObject) cursor.next();
+ Colnames = doc.keySet();
+ return true;
+ } else
+ return false;
+
+ } // end of Fetch
+
+ public String GetDoc() {
+ return (doc != null) ? doc.toString() : null;
+ } // end of GetDoc
+
+ public Set<String> GetColumns() {
+ if (doc != null)
+ return doc.keySet();
+ else
+ return null;
+
+ } // end of GetColumns
+
+ public Object ColumnDesc(Object obj, int n, int[] val, int lvl) {
+ Object ret = null;
+ Object oval = ((obj != null) ? obj : doc);
+ BasicDBObject dob = (oval instanceof BasicDBObject) ? (BasicDBObject) oval : null;
+ BasicDBList ary = (oval instanceof BasicDBList) ? (BasicDBList) oval : null;
+
+ try {
+ if (ary != null) {
+ oval = ary.get(n);
+ ovalName = Integer.toString(n);
+ } else if (dob != null) {
+ // String[] k = dob.keySet().toArray(new String[0]);
+ Object[] k = dob.keySet().toArray();
+ oval = dob.get(k[n]);
+ ovalName = (String) k[n];
+ } else
+ ovalName = "x" + Integer.toString(n);
+
+ if (DEBUG)
+ System.out.println("Class of " + ovalName + " = " + oval.getClass());
+
+ val[0] = 0; // ColumnType
+ val[1] = 0; // Precision
+ val[2] = 0; // Scale
+ val[3] = 0; // Nullable
+ val[4] = 0; // ncol
+
+ if (oval == null) {
+ val[3] = 1;
+ } else if (oval instanceof String) {
+ val[0] = 1;
+ val[1] = ((String) oval).length();
+ } else if (oval instanceof org.bson.types.ObjectId) {
+ val[0] = 1;
+ val[1] = ((org.bson.types.ObjectId) oval).toString().length();
+ } else if (oval instanceof Integer) {
+ val[0] = 7;
+ val[1] = Integer.toString(((Integer) oval).intValue()).length();
+ } else if (oval instanceof Long) {
+ val[0] = 5;
+ val[1] = Long.toString(((Long) oval).longValue()).length();
+ } else if (oval instanceof Date) {
+ Long TS = (((Date) oval).getTime() / 1000);
+ val[0] = 8;
+ val[1] = TS.toString().length();
+ } else if (oval instanceof Double) {
+ String d = Double.toString(((Double) oval).doubleValue());
+ int i = d.indexOf('.') + 1;
+
+ val[0] = 2;
+ val[1] = d.length();
+ val[2] = (i > 0) ? val[1] - i : 0;
+ } else if (oval instanceof Boolean) {
+ val[0] = 4;
+ val[1] = 1;
+ } else if (oval instanceof BasicDBObject) {
+ if (lvl > 0) {
+ ret = oval;
+ val[0] = 1;
+ val[4] = ((BasicDBObject) oval).size();
+ } else if (lvl == 0) {
+ val[0] = 1;
+ val[1] = oval.toString().length();
+ } // endif lvl
+
+ } else if (oval instanceof BasicDBList) {
+ if (lvl > 0) {
+ ret = oval;
+ val[0] = 2;
+ val[4] = ((BasicDBList) oval).size();
+ } else if (lvl == 0) {
+ val[0] = 1;
+ val[1] = oval.toString().length();
+ } // endif lvl
+
+ } else {
+ SetErrmsg("Type " + " of " + ovalName + " not supported");
+ val[0] = -1;
+ } // endif's
+
+ return ret;
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ } // end try/catch
+
+ val[0] = -1;
+ return null;
+ } // end of ColumnDesc
+
+ public String ColDescName() {
+ return ovalName;
+ } // end of ColDescName
+
+ protected Object GetFieldObject(String path) {
+ Object o = null;
+ BasicDBObject dob = null;
+ BasicDBList lst = null;
+ String[] names = null;
+
+ if (path == null || path.equals("") || path.equals("*"))
+ return doc;
+ else if (doc instanceof BasicDBObject)
+ dob = doc;
+ // else if (o instanceof BasicDBList)
+ // lst = (BasicDBList) doc;
+ else
+ return doc;
+
+ try {
+ names = path.split("\\.");
+
+ for (String name : names) {
+ if (lst != null) {
+ o = lst.get(Integer.parseInt(name));
+ } else
+ o = dob.get(name);
+
+ if (o == null)
+ break;
+
+ if (DEBUG)
+ System.out.println("Class o = " + o.getClass());
+
+ if (o instanceof BasicDBObject) {
+ dob = (BasicDBObject) o;
+ lst = null;
+ } else if (o instanceof BasicDBList) {
+ lst = (BasicDBList) o;
+ } else
+ break;
+
+ } // endfor name
+
+ } catch (IndexOutOfBoundsException x) {
+ o = null;
+ } catch (MongoException se) {
+ SetErrmsg(se);
+ o = null;
+ } // end try/catch
+
+ return o;
+ } // end of GetFieldObject
+
+ public String GetField(String path) {
+ Object o = GetFieldObject(path);
+
+ if (o != null) {
+ if (o instanceof Date) {
+ Long TS = (((Date) o).getTime() / 1000);
+ return TS.toString();
+ } else if (o instanceof Boolean)
+ return (Boolean) o ? "1" : "0";
+
+ return o.toString();
+ } else
+ return null;
+
+ } // end of GetField
+
+ public Object MakeBson(String s, int json) {
+ if (json == 1 || json == 2) {
+ return com.mongodb.util.JSON.parse(s);
+ } else
+ return null;
+
+ } // end of MakeBson
+
+ public Object MakeDocument() {
+ return new BasicDBObject();
+ } // end of MakeDocument
+
+ public boolean DocAdd(Object bdc, String key, Object val, int json) {
+ try {
+ if (json != 0 && val instanceof String)
+ ((BasicDBObject) bdc).append(key, JSON.parse((String) val));
+ else
+ ((BasicDBObject) bdc).append(key, val);
+
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of DocAdd
+
+ public Object MakeArray() {
+ return new BasicDBList();
+ } // end of MakeArray
+
+ public boolean ArrayAdd(Object bar, int n, Object val, int json) {
+ try {
+ if (json != 0 && val instanceof String)
+ ((BasicDBList) bar).put(n, JSON.parse((String) val));
+ else
+ ((BasicDBList) bar).put(n, val);
+
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return true;
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of ArrayAdd
+
+ public boolean CollInsert(Object dob) {
+ try {
+ coll.insert((BasicDBObject) dob);
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return true;
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of CollInsert
+
+ public long CollUpdate(Object upd) {
+ long n = -1;
+
+ if (DEBUG)
+ System.out.println("upd: " + upd.toString());
+
+ try {
+ DBObject qry = new BasicDBObject("_id", doc.get("_id"));
+
+ WriteResult res = coll.update(qry, (DBObject) upd);
+
+ if (DEBUG)
+ System.out.println("CollUpdate: " + res.toString());
+
+ n = res.getN();
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ } // end try/catch
+
+ return n;
+ } // end of CollUpdate
+
+ public long CollDelete(boolean all) {
+ long n = -1;
+
+ try {
+ WriteResult res;
+ BasicDBObject qry = new BasicDBObject();
+
+ if (!all)
+ qry.append("_id", doc.get("_id"));
+
+ res = coll.remove(qry);
+
+ if (DEBUG)
+ System.out.println("CollDelete: " + res.toString());
+
+ n = res.getN();
+ } catch (WriteConcernException wx) {
+ SetErrmsg(wx);
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ } catch (UnsupportedOperationException ux) {
+ SetErrmsg(ux);
+ n = 0;
+ } // end try/catch
+
+ return n;
+ } // end of CollDelete
+
+} // end of class MongoInterface
diff --git a/storage/connect/Mongo3Interface.java b/storage/connect/Mongo3Interface.java
new file mode 100644
index 00000000..73175e13
--- /dev/null
+++ b/storage/connect/Mongo3Interface.java
@@ -0,0 +1,618 @@
+package wrappers;
+
+//import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.bson.BsonArray;
+import org.bson.BsonBoolean;
+import org.bson.BsonDateTime;
+//import org.bson.BsonDecimal128;
+import org.bson.BsonDocument;
+import org.bson.BsonDouble;
+import org.bson.BsonInt32;
+import org.bson.BsonInt64;
+import org.bson.BsonNull;
+import org.bson.BsonString;
+import org.bson.BsonValue;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+//import org.bson.types.Decimal128;
+
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientURI;
+import com.mongodb.MongoException;
+import com.mongodb.client.AggregateIterable;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoCursor;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.model.Filters;
+import com.mongodb.client.result.DeleteResult;
+import com.mongodb.client.result.UpdateResult;
+
+public class Mongo3Interface {
+ boolean DEBUG = false;
+ String Errmsg = "No error";
+ String bvalName = null;
+ Set<String> Colnames = null;
+ MongoClient client = null;
+ MongoDatabase db = null;
+ MongoCollection<BsonDocument> coll = null;
+ FindIterable<BsonDocument> finditer = null;
+ AggregateIterable<BsonDocument> aggiter = null;
+ MongoCursor<BsonDocument> cursor = null;
+ BsonDocument doc = null;
+ BsonDocument util = null;
+ BsonNull bsonull = new BsonNull();
+
+ // === Constructors/finalize =========================================
+ public Mongo3Interface() {
+ this(false);
+ } // end of default constructor
+
+ public Mongo3Interface(boolean b) {
+ DEBUG = b;
+ } // end of constructor
+
+ protected void SetErrmsg(String str) {
+ if (DEBUG)
+ System.out.println(str);
+
+ Errmsg = str;
+ } // end of SetErrmsg
+
+ protected void SetErrmsg(Exception e) {
+ if (DEBUG)
+ System.out.println(e.getMessage());
+
+ Errmsg = e.toString();
+ } // end of SetErrmsg
+
+ public String GetErrmsg() {
+ String err = Errmsg;
+
+ Errmsg = "No error";
+ return err;
+ } // end of GetErrmsg
+
+ public int MongoConnect(String[] parms) {
+ int rc = 0;
+
+ if (DEBUG)
+ System.out.println("Mongo3: URI=" + parms[0] + " DB=" + parms[1]);
+
+ try {
+ MongoClientURI uri = new MongoClientURI(parms[0]);
+
+ client = new MongoClient(uri);
+
+ if (DEBUG)
+ System.out.println("Connection " + client.toString() + " established");
+
+ // Now connect to your databases
+ db = client.getDatabase(parms[1]);
+
+ // if (parms[2] != null && !parms[2].isEmpty()) {
+ // if (DEBUG)
+ // System.out.println("user=" + parms[2] + " pwd=" + parms[3]);
+
+ // @SuppressWarnings("deprecation")
+ // boolean auth = db.authenticate(parms[2], parms[3].toCharArray());
+
+ // if (DEBUG)
+ // System.out.println("Authentication: " + auth);
+
+ // } // endif user
+
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ rc = -1;
+ } catch (Exception e) {
+ SetErrmsg(e);
+ rc = -3;
+ } // end try/catch
+
+ return rc;
+ } // end of MongoConnect
+
+ public int MongoDisconnect() {
+ int rc = 0;
+
+ try {
+ if (cursor != null) {
+ if (DEBUG)
+ System.out.println("Closing cursor");
+
+ cursor.close();
+ cursor = null;
+ } // endif client
+
+ if (client != null) {
+ if (DEBUG)
+ System.out.println("Closing connection");
+
+ client.close();
+ client = null;
+ } // endif client
+
+ } catch (MongoException se) {
+ SetErrmsg(se);
+ rc += 8;
+ } // end try/catch
+
+ return rc;
+ } // end of MongoDisconnect
+
+ public boolean GetCollection(String name) {
+ if (DEBUG)
+ System.out.println("GetCollection: name=" + name);
+
+ try {
+ coll = db.getCollection(name).withDocumentClass(BsonDocument.class);
+ } catch (Exception e) {
+ SetErrmsg(e);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of GetCollection
+
+ public long GetCollSize() {
+ return (coll != null) ? coll.count() : 0;
+ } // end of GetCollSize
+
+ public boolean FindColl(String query, String fields) {
+ if (DEBUG)
+ System.out.println("FindColl: query=" + query + " fields=" + fields);
+
+ try {
+ if (query != null) {
+ Bson dbq = Document.parse(query);
+ finditer = coll.find(dbq);
+ } else
+ finditer = coll.find();
+
+ if (fields != null) {
+ Bson dbf = BsonDocument.parse(fields);
+ finditer = finditer.projection(dbf);
+ } // endif fields
+
+ cursor = finditer.iterator();
+ } catch (Exception e) {
+ SetErrmsg(e);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of FindColl
+
+ @SuppressWarnings("unchecked")
+ public boolean AggregateColl(String pipeline) {
+ if (DEBUG)
+ System.out.println("AggregateColl: pipeline=" + pipeline);
+
+ try {
+ Document pipe = Document.parse(pipeline);
+ ArrayList<?> pip = (ArrayList<?>) pipe.get("pipeline");
+
+ aggiter = coll.aggregate((List<? extends Bson>) pip);
+ cursor = aggiter.iterator();
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of AggregateColl
+
+ public boolean Rewind() {
+ if (cursor != null)
+ cursor.close();
+
+ if (finditer != null)
+ cursor = finditer.iterator();
+ else if (aggiter != null)
+ cursor = aggiter.iterator();
+
+ return (cursor == null);
+ } // end of Rewind
+
+ public int ReadNext() {
+ try {
+ if (cursor.hasNext()) {
+ doc = cursor.next();
+
+ if (DEBUG)
+ System.out.println("Class doc = " + doc.getClass());
+
+ Colnames = doc.keySet();
+ return Colnames.size();
+ } else
+ return 0;
+
+ } catch (MongoException mx) {
+ SetErrmsg(mx);
+ } // end try/catch
+
+ return -1;
+ } // end of ReadNext
+
+ public boolean Fetch(int row) {
+ if (cursor.hasNext()) {
+ doc = cursor.next();
+ Colnames = doc.keySet();
+ return true;
+ } else
+ return false;
+
+ } // end of Fetch
+
+ public String GetDoc() {
+ return (doc != null) ? doc.toJson() : null;
+ } // end of GetDoc
+
+ public Set<String> GetColumns() {
+ if (doc != null)
+ return doc.keySet();
+ else
+ return null;
+
+ } // end of GetColumns
+
+ public String ColumnName(int n) {
+ if (n < Colnames.size())
+ return (String) Colnames.toArray()[n];
+ else
+ return null;
+
+ } // end of ColumnName
+
+ public int ColumnType(int n, String name) {
+ // if (rsmd == null) {
+ // System.out.println("No result metadata");
+ // } else try {
+ // if (n == 0)
+ // n = rs.findColumn(name);
+
+ // return rsmd.getColumnType(n);
+ // } catch (SQLException se) {
+ // SetErrmsg(se);
+ // } //end try/catch
+
+ return 666; // Not a type
+ } // end of ColumnType
+
+ public Object ColumnDesc(Object obj, int n, int[] val, int lvl) {
+ Object ret = null;
+ BsonValue bval = (BsonValue) ((obj != null) ? obj : doc);
+ BsonDocument dob = (bval instanceof BsonDocument) ? (BsonDocument) bval : null;
+ BsonArray ary = (bval instanceof BsonArray) ? (BsonArray) bval : null;
+
+ try {
+ if (ary != null) {
+ bval = ary.get(n);
+ bvalName = Integer.toString(n);
+ } else if (dob != null) {
+ // String[] k = dob.keySet().toArray(new String[0]);
+ Object[] k = dob.keySet().toArray();
+ bval = dob.get(k[n]);
+ bvalName = (String) k[n];
+ } else
+ bvalName = "x" + Integer.toString(n);
+
+ val[0] = 0; // ColumnType
+ val[1] = 0; // Precision
+ val[2] = 0; // Scale
+ val[3] = 0; // Nullable
+ val[4] = 0; // ncol
+
+ if (bval.isString()) {
+ val[0] = 1;
+ val[1] = bval.asString().getValue().length();
+ } else if (bval.isInt32()) {
+ val[0] = 7;
+ val[1] = Integer.toString(bval.asInt32().getValue()).length();
+ } else if (bval.isInt64()) {
+ val[0] = 5;
+ val[1] = Long.toString(bval.asInt64().getValue()).length();
+ } else if (bval.isObjectId()) {
+ val[0] = 1;
+ val[1] = bval.asObjectId().getValue().toString().length();
+ } else if (bval.isDateTime()) {
+ Long TS = (bval.asDateTime().getValue() / 1000);
+ val[0] = 8;
+ val[1] = TS.toString().length();
+ } else if (bval.isDouble()) {
+ String d = Double.toString(bval.asDouble().getValue());
+ int i = d.indexOf('.') + 1;
+
+ val[0] = 2;
+ val[1] = d.length();
+ val[2] = (i > 0) ? val[1] - i : 0;
+ } else if (bval.isBoolean()) {
+ val[0] = 4;
+ val[1] = 1;
+ } else if (bval.isDocument()) {
+ if (lvl > 0) {
+ ret = bval;
+ val[0] = 1;
+ val[4] = bval.asDocument().keySet().size();
+ } else if (lvl == 0) {
+ val[0] = 1;
+ val[1] = bval.asDocument().toJson().length();
+ } // endif lvl
+
+ } else if (bval.isArray()) {
+ if (lvl > 0) {
+ ret = bval;
+ val[0] = 2;
+ val[4] = bval.asArray().size();
+ } else if (lvl == 0) {
+ val[0] = 1;
+ util = new BsonDocument("arr", bval.asArray());
+ String s = util.toJson();
+ int i1 = s.indexOf('[');
+ int i2 = s.lastIndexOf(']');
+ val[1] = i2 - i1 + 1;
+ } // endif lvl
+
+ } else if (bval.isDecimal128()) {
+ val[0] = 9;
+ val[1] = bval.asDecimal128().toString().length();
+ } else if (bval.isNull()) {
+ val[0] = 0;
+ val[3] = 1;
+ } else {
+ SetErrmsg("Type " + bval.getBsonType() + " of " + bvalName + " not supported");
+ val[0] = -1;
+ } // endif's
+
+ return ret;
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ } // end try/catch
+
+ val[0] = -1;
+ return null;
+ } // end of ColumnDesc
+
+ public String ColDescName() {
+ return bvalName;
+ } // end of ColDescName
+
+ protected BsonValue GetFieldObject(String path) {
+ BsonValue o = doc;
+ BsonDocument dob = null;
+ BsonArray ary = null;
+ String[] names = null;
+
+ if (path == null || path.equals("") || path.equals("*"))
+ return doc;
+ else if (o instanceof BsonDocument)
+ dob = doc;
+ else if (o instanceof BsonArray)
+ ary = (BsonArray) o;
+ else
+ return doc;
+
+ try {
+ names = path.split("\\.");
+
+ for (String name : names) {
+ if (ary != null) {
+ o = ary.get(Integer.parseInt(name));
+ } else
+ o = dob.get(name);
+
+ if (o == null)
+ break;
+
+ if (DEBUG)
+ System.out.println("Class o = " + o.getClass());
+
+ if (o instanceof BsonDocument) {
+ dob = (BsonDocument) o;
+ ary = null;
+ } else if (o instanceof BsonArray) {
+ ary = (BsonArray) o;
+ } else
+ break;
+
+ } // endfor name
+
+ } catch (IndexOutOfBoundsException x) {
+ o = null;
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ o = null;
+ } // end try/catch
+
+ return o;
+ } // end of GetFieldObject
+
+ public String GetField(String path) {
+ BsonValue o = GetFieldObject(path);
+
+ if (o != null) {
+ if (o.isString()) {
+ return o.asString().getValue();
+ } else if (o.isInt32()) {
+ return Integer.toString(o.asInt32().getValue());
+ } else if (o.isInt64()) {
+ return Long.toString(o.asInt64().getValue());
+ } else if (o.isObjectId()) {
+ return o.asObjectId().getValue().toString();
+ } else if (o.isDateTime()) {
+ Integer TS = (int) (o.asDateTime().getValue() / 1000);
+ return TS.toString();
+ } else if (o.isDouble()) {
+ return Double.toString(o.asDouble().getValue());
+ } else if (o.isBoolean()) {
+ return o.asBoolean().getValue() ? "1" : "0";
+ } else if (o.isDocument()) {
+ return o.asDocument().toJson();
+ } else if (o.isArray()) {
+ util = new BsonDocument("arr", o.asArray());
+ String s = util.toJson();
+ int i1 = s.indexOf('[');
+ int i2 = s.lastIndexOf(']');
+ return s.substring(i1, i2 + 1);
+ } else if (o.isDecimal128()) {
+ return o.asDecimal128().toString();
+ } else if (o.isNull()) {
+ return null;
+ } else
+ return o.toString();
+
+ } else
+ return null;
+
+ } // end of GetField
+
+ public Object MakeBson(String s, int json) {
+ BsonValue bval;
+
+ if (json == 1)
+ bval = BsonDocument.parse(s);
+ else if (json == 2)
+ bval = BsonArray.parse(s);
+ else
+ bval = null;
+
+ return bval;
+ } // end of MakeBson
+
+ protected BsonValue ObjToBson(Object val, int json) {
+ BsonValue bval = null;
+
+ if (val == null)
+ bval = bsonull;
+ else if (val.getClass() == String.class) {
+ if (json == 1)
+ bval = BsonDocument.parse((String) val);
+ else if (json == 2)
+ bval = BsonArray.parse((String) val);
+ else
+ bval = new BsonString((String) val);
+
+ } else if (val.getClass() == Integer.class)
+ bval = new BsonInt32((int) val);
+ else if (val.getClass() == Double.class)
+ bval = new BsonDouble((double) val);
+ else if (val.getClass() == BigInteger.class)
+ bval = new BsonInt64((long) val);
+ else if (val.getClass() == Boolean.class)
+ bval = new BsonBoolean((Boolean) val);
+ else if (val.getClass() == Date.class)
+ bval = new BsonDateTime(((Date) val).getTime() * 1000);
+ else if (val.getClass() == BsonDocument.class)
+ bval = (BsonDocument) val;
+ else if (val.getClass() == BsonArray.class)
+ bval = (BsonArray) val;
+ // else if (val.getClass() == BigDecimal.class)
+ // bval = new BsonDecimal128((BigDecimal) val);
+
+ return bval;
+ } // end of ObjToBson
+
+ public Object MakeDocument() {
+ return new BsonDocument();
+ } // end of MakeDocument
+
+ public boolean DocAdd(Object bdc, String key, Object val, int json) {
+ try {
+ ((BsonDocument) bdc).append(key, ObjToBson(val, json));
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of DocAdd
+
+ public Object MakeArray() {
+ return new BsonArray();
+ } // end of MakeArray
+
+ public boolean ArrayAdd(Object bar, int n, Object val, int json) {
+ try {
+ for (int i = ((BsonArray) bar).size(); i < n; i++)
+ ((BsonArray) bar).add(bsonull);
+
+ ((BsonArray) bar).add(ObjToBson(val, json));
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return true;
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of ArrayAdd
+
+ public boolean CollInsert(Object dob) {
+ try {
+ coll.insertOne((BsonDocument) dob);
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ return true;
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of CollInsert
+
+ public long CollUpdate(Object upd) {
+ long n = -1;
+
+ if (DEBUG)
+ System.out.println("upd: " + upd.toString());
+
+ try {
+ UpdateResult res = coll.updateOne(Filters.eq("_id", doc.get("_id")), (Bson) upd);
+
+ if (DEBUG)
+ System.out.println("CollUpdate: " + res.toString());
+
+ n = res.getModifiedCount();
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ } // end try/catch
+
+ return n;
+ } // end of CollUpdate
+
+ public long CollDelete(boolean all) {
+ long n = -1;
+
+ try {
+ DeleteResult res;
+
+ if (all)
+ res = coll.deleteMany(new Document());
+ else
+ res = coll.deleteOne(Filters.eq("_id", doc.get("_id")));
+
+ if (DEBUG)
+ System.out.println("CollDelete: " + res.toString());
+
+ n = res.getDeletedCount();
+ } catch (MongoException me) {
+ SetErrmsg(me);
+ } catch (Exception ex) {
+ SetErrmsg(ex);
+ } // end try/catch
+
+ return n;
+ } // end of CollDelete
+
+} // end of class Mongo3Interface
diff --git a/storage/connect/MysqlInterface.java b/storage/connect/MysqlInterface.java
new file mode 100644
index 00000000..a13020e3
--- /dev/null
+++ b/storage/connect/MysqlInterface.java
@@ -0,0 +1,69 @@
+package wrappers;
+
+import java.sql.*;
+import java.util.Hashtable;
+
+import javax.sql.DataSource;
+import com.mysql.cj.jdbc.MysqlDataSource;
+
+public class MysqlInterface extends JdbcInterface {
+ public MysqlInterface() {
+ this(true);
+ } // end of default constructor
+
+ public MysqlInterface(boolean b) {
+ super(b);
+
+ if (dst == null)
+ dst = new Hashtable<String, DataSource>();
+
+ } // end of default constructor
+
+ @Override
+ public int JdbcConnect(String[] parms, int fsize, boolean scrollable) {
+ int rc = 0;
+ String url = parms[1];
+ DataSource ds = null;
+ MysqlDataSource mds = null;
+
+ if (DEBUG)
+ System.out.println("Connecting to MySQL data source");
+
+ try {
+ CheckURL(url, "mysql");
+
+ if ((ds = dst.get(url)) == null) {
+ mds = new MysqlDataSource();
+ mds.setUrl(url);
+
+ if (parms[2] != null)
+ mds.setUser(parms[2]);
+
+ if (parms[3] != null)
+ mds.setPassword(parms[3]);
+
+ ds = mds;
+
+ dst.put(url, ds);
+ } // endif ds
+
+ // Get a connection from the data source
+ conn = ds.getConnection();
+
+ // Get the data base meta data object
+ dbmd = conn.getMetaData();
+
+ // Get a statement from the connection
+ stmt = GetStmt(fsize, scrollable);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ rc = -2;
+ } catch( Exception e ) {
+ SetErrmsg(e);
+ rc = -3;
+ } // end try/catch
+
+ return rc;
+ } // end of JdbcConnect
+
+} // end of class MysqlInterface
diff --git a/storage/connect/OracleInterface.java b/storage/connect/OracleInterface.java
new file mode 100644
index 00000000..0bfdd20e
--- /dev/null
+++ b/storage/connect/OracleInterface.java
@@ -0,0 +1,69 @@
+package wrappers;
+
+import java.sql.*;
+import java.util.Hashtable;
+
+import javax.sql.DataSource;
+import oracle.jdbc.pool.OracleDataSource;
+
+public class OracleInterface extends JdbcInterface {
+ public OracleInterface() {
+ this(true);
+ } // end of OracleInterface constructor
+
+ public OracleInterface(boolean b) {
+ super(b);
+
+ if (dst == null)
+ dst = new Hashtable<String, DataSource>();
+
+ } // end of OracleInterface constructor
+
+ @Override
+ public int JdbcConnect(String[] parms, int fsize, boolean scrollable) {
+ int rc = 0;
+ String url = parms[1];
+ DataSource ds = null;
+ OracleDataSource ods = null;
+
+ if (DEBUG)
+ System.out.println("Connecting to Oracle data source");
+
+ try {
+ CheckURL(url, "oracle");
+
+ if ((ds = dst.get(url)) == null) {
+ ods = new OracleDataSource();
+ ods.setURL(url);
+
+ if (parms[2] != null)
+ ods.setUser(parms[2]);
+
+ if (parms[3] != null)
+ ods.setPassword(parms[3]);
+
+ ds = ods;
+
+ dst.put(url, ds);
+ } // endif ds
+
+ // Get a connection from the data source
+ conn = ds.getConnection();
+
+ // Get the data base meta data object
+ dbmd = conn.getMetaData();
+
+ // Get a statement from the connection
+ stmt = GetStmt(fsize, scrollable);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ rc = -2;
+ } catch( Exception e ) {
+ SetErrmsg(e);
+ rc = -3;
+ } // end try/catch
+
+ return rc;
+ } // end of JdbcConnect
+
+} // end of class OracleInterface
diff --git a/storage/connect/PostgresqlInterface.java b/storage/connect/PostgresqlInterface.java
new file mode 100644
index 00000000..9f611eeb
--- /dev/null
+++ b/storage/connect/PostgresqlInterface.java
@@ -0,0 +1,70 @@
+package wrappers;
+
+import java.sql.SQLException;
+import java.util.Hashtable;
+
+import javax.sql.DataSource;
+
+import org.postgresql.jdbc2.optional.PoolingDataSource;
+
+public class PostgresqlInterface extends JdbcInterface {
+ public PostgresqlInterface() {
+ this(true);
+ } // end of constructor
+
+ public PostgresqlInterface(boolean b) {
+ super(b);
+
+ if (dst == null)
+ dst = new Hashtable<String, DataSource>();
+
+ } // end of constructor
+
+ @Override
+ public int JdbcConnect(String[] parms, int fsize, boolean scrollable) {
+ int rc = 0;
+ String url = parms[1];
+ DataSource ds = null;
+ PoolingDataSource pds = null;
+
+ if (DEBUG)
+ System.out.println("Connecting to Postgresql data source");
+
+ try {
+ CheckURL(url, "postgresql");
+
+ if ((ds = dst.get(url)) == null) {
+ pds = new PoolingDataSource();
+ pds.setUrl(url);
+
+ if (parms[2] != null)
+ pds.setUser(parms[2]);
+
+ if (parms[3] != null)
+ pds.setPassword(parms[3]);
+
+ ds = pds;
+
+ dst.put(url, ds);
+ } // endif ds
+
+ // Get a connection from the data source
+ conn = ds.getConnection();
+
+ // Get the data base meta data object
+ dbmd = conn.getMetaData();
+
+ // Get a statement from the connection
+ stmt = GetStmt(fsize, scrollable);
+ } catch (SQLException se) {
+ SetErrmsg(se);
+ rc = -2;
+ } catch( Exception e ) {
+ SetErrmsg(e);
+ rc = -3;
+ } // end try/catch
+
+ return rc;
+ } // end of JdbcConnect
+
+} // end of class PostgresqlInterface
diff --git a/storage/connect/TestInsert2.java b/storage/connect/TestInsert2.java
new file mode 100644
index 00000000..e1a7cb4f
--- /dev/null
+++ b/storage/connect/TestInsert2.java
@@ -0,0 +1,131 @@
+package wrappers;
+
+import java.io.BufferedReader;
+import java.io.Console;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Date;
+
+public class TestInsert2 {
+ static boolean DEBUG = true;
+ static final Console c = System.console();
+ static Mongo2Interface jdi = null;
+
+ public static void main(String[] args) {
+ int rc;
+ String[] parms = new String[4];
+
+ jdi = new Mongo2Interface(DEBUG);
+
+ parms[0] = getLine("URI: ", false);
+ parms[1] = getLine("Database: ", false);
+ parms[2] = null;
+ parms[3] = null;
+
+ if (parms[0] == null)
+ parms[0] = "mongodb://localhost:27017";
+
+ if (parms[1] == null)
+ parms[1] = "test";
+
+ rc = jdi.MongoConnect(parms);
+
+ if (rc == 0) {
+ Object bdoc = jdi.MakeDocument();
+
+ if (jdi.DocAdd(bdoc, "_id", (Object) 1, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Name", (Object) "Smith", 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Age", (Object) 39, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Pi", (Object) 3.14, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Phone", (Object) "{\"ext\":[4,5,7]}", 1))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Scores", (Object) "[24,2,13]", 2))
+ System.out.println(jdi.GetErrmsg());
+
+ Object bar = jdi.MakeArray();
+
+ for (int i = 1; i < 3; i++)
+ if (jdi.ArrayAdd(bar, i, (Object) (Math.random() * 10.0), 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Prices", bar, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ Object dat = new Date();
+
+ if (jdi.DocAdd(bdoc, "Date", dat, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ System.out.println(bdoc);
+
+ // Try to update
+ if (!jdi.GetCollection("updtest") && !jdi.FindColl(null, null)) {
+ if (jdi.CollDelete(true) < 0)
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.CollInsert(bdoc))
+ System.out.println(jdi.GetErrmsg());
+
+ Object updlist = jdi.MakeDocument();
+
+ if (jdi.DocAdd(updlist, "Age", (Object) 45, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ Object upd = jdi.MakeDocument();
+
+ if (jdi.DocAdd(upd, "$set", updlist, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.ReadNext() > 0 && jdi.CollUpdate(upd) < 0)
+ System.out.println(jdi.GetErrmsg());
+
+ if (!jdi.Rewind() && jdi.ReadNext() > 0)
+ System.out.println(jdi.GetDoc());
+ else
+ System.out.println("Failed Rewind");
+
+ } // endif n
+
+ } // endif rc
+
+ } // end of main
+
+ // ==================================================================
+ private static String getLine(String p, boolean b) {
+ String response;
+
+ if (c != null) {
+ // Standard console mode
+ if (b) {
+ response = new String(c.readPassword(p));
+ } else
+ response = c.readLine(p);
+
+ } else {
+ // For instance when testing from Eclipse
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+
+ System.out.print(p);
+
+ try {
+ // Cannot suppress echo for password entry
+ response = in.readLine();
+ } catch (IOException e) {
+ response = "";
+ } // end of try/catch
+
+ } // endif c
+
+ return (response.isEmpty()) ? null : response;
+ } // end of getLine
+
+}
diff --git a/storage/connect/TestInsert3.java b/storage/connect/TestInsert3.java
new file mode 100644
index 00000000..a56a361e
--- /dev/null
+++ b/storage/connect/TestInsert3.java
@@ -0,0 +1,131 @@
+package wrappers;
+
+import java.io.BufferedReader;
+import java.io.Console;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Date;
+
+public class TestInsert3 {
+ static boolean DEBUG = true;
+ static final Console c = System.console();
+ static Mongo3Interface jdi = null;
+
+ public static void main(String[] args) {
+ int rc;
+ String[] parms = new String[4];
+
+ jdi = new Mongo3Interface(DEBUG);
+
+ parms[0] = getLine("URI: ", false);
+ parms[1] = getLine("Database: ", false);
+ parms[2] = null;
+ parms[3] = null;
+
+ if (parms[0] == null)
+ parms[0] = "mongodb://localhost:27017";
+
+ if (parms[1] == null)
+ parms[1] = "test";
+
+ rc = jdi.MongoConnect(parms);
+
+ if (rc == 0) {
+ Object bdoc = jdi.MakeDocument();
+
+ if (jdi.DocAdd(bdoc, "_id", (Object) 1, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Name", (Object) "Smith", 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Age", (Object) 39, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Pi", (Object) 3.14, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Phone", (Object) "{\"ext\":[4,5,7]}", 1))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Scores", (Object) "[24,2,13]", 2))
+ System.out.println(jdi.GetErrmsg());
+
+ Object bar = jdi.MakeArray();
+
+ for (int i = 0; i < 2; i++)
+ if (jdi.ArrayAdd(bar, i, (Object) (Math.random() * 10.0), 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.DocAdd(bdoc, "Prices", bar, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ Object dat = new Date();
+
+ if (jdi.DocAdd(bdoc, "Date", dat, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ System.out.println(bdoc);
+
+ // Try to update
+ if (!jdi.GetCollection("updtest") && !jdi.FindColl(null, null)) {
+ if (jdi.CollDelete(true) < 0)
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.CollInsert(bdoc))
+ System.out.println(jdi.GetErrmsg());
+
+ Object updlist = jdi.MakeDocument();
+
+ if (jdi.DocAdd(updlist, "Age", (Object) 40, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ Object upd = jdi.MakeDocument();
+
+ if (jdi.DocAdd(upd, "$set", updlist, 0))
+ System.out.println(jdi.GetErrmsg());
+
+ if (jdi.ReadNext() > 0 && jdi.CollUpdate(upd) < 0)
+ System.out.println(jdi.GetErrmsg());
+
+ if (!jdi.Rewind() && jdi.ReadNext() > 0)
+ System.out.println(jdi.GetDoc());
+ else
+ System.out.println("Failed Rewind");
+
+ } // endif n
+
+ } // endif rc
+
+ } // end of main
+
+ // ==================================================================
+ private static String getLine(String p, boolean b) {
+ String response;
+
+ if (c != null) {
+ // Standard console mode
+ if (b) {
+ response = new String(c.readPassword(p));
+ } else
+ response = c.readLine(p);
+
+ } else {
+ // For instance when testing from Eclipse
+ BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+
+ System.out.print(p);
+
+ try {
+ // Cannot suppress echo for password entry
+ response = in.readLine();
+ } catch (IOException e) {
+ response = "";
+ } // end of try/catch
+
+ } // endif c
+
+ return (response.isEmpty()) ? null : response;
+ } // end of getLine
+
+}
diff --git a/storage/connect/array.cpp b/storage/connect/array.cpp
new file mode 100644
index 00000000..6d105c12
--- /dev/null
+++ b/storage/connect/array.cpp
@@ -0,0 +1,1151 @@
+/************* Array C++ Functions Source Code File (.CPP) *************/
+/* Name: ARRAY.CPP Version 2.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2019 */
+/* */
+/* This file contains the XOBJECT derived class ARRAY functions. */
+/* ARRAY is used for elaborate type of processing, such as sorting */
+/* and dichotomic search (Find). This new version does not use sub */
+/* classes anymore for the different types but relies entirely on the */
+/* functionalities provided by the VALUE and VALBLK classes. */
+/* Currently the only supported types are STRING, SHORT, int, DATE, */
+/* TOKEN, DOUBLE, and Compressed Strings. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#include "sql_class.h"
+//#include "sql_time.h"
+
+#if defined(_WIN32)
+//#include <windows.h>
+#else // !_WIN32
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h> // for uintprt_h
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* xobject.h is header containing XOBJECT derived classes declares. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "array.h"
+//#include "select.h"
+//#include "query.h"
+//#include "token.h"
+
+/***********************************************************************/
+/* Macro definitions. */
+/***********************************************************************/
+#if defined(_DEBUG)
+#define ASSERT(B) assert(B);
+#else
+#define ASSERT(B)
+#endif
+
+/***********************************************************************/
+/* DB static external variables. */
+/***********************************************************************/
+extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
+
+/***********************************************************************/
+/* External functions. */
+/***********************************************************************/
+BYTE OpBmp(PGLOBAL g, OPVAL opc);
+void EncodeValue(int *lp, char *strp, int n);
+PARRAY MakeValueArray(PGLOBAL g, PPARM pp); // avoid gcc warning
+
+/***********************************************************************/
+/* MakeValueArray: Makes a value array from a value list. */
+/***********************************************************************/
+PARRAY MakeValueArray(PGLOBAL g, PPARM pp)
+{
+ int n, valtyp = 0;
+ size_t len = 0;
+ PARRAY par;
+ PPARM parmp;
+
+ if (!pp)
+ return NULL;
+
+ /*********************************************************************/
+ /* New version with values coming in a list. */
+ /*********************************************************************/
+ if ((valtyp = pp->Type) != TYPE_STRING)
+ len = 1;
+
+ xtrc(1, "valtyp=%d len=%d\n", valtyp, len);
+
+ /*********************************************************************/
+ /* Firstly check the list and count the number of values in it. */
+ /*********************************************************************/
+ for (n = 0, parmp = pp; parmp; n++, parmp = parmp->Next)
+ if (parmp->Type != valtyp) {
+ sprintf(g->Message, MSG(BAD_PARAM_TYPE), "MakeValueArray", parmp->Type);
+ return NULL;
+ } else if (valtyp == TYPE_STRING)
+ len = MY_MAX(len, strlen((char*)parmp->Value));
+
+ /*********************************************************************/
+ /* Make an array object with one block of the proper size. */
+ /*********************************************************************/
+ par = new(g) ARRAY(g, valtyp, n, (int)len);
+
+ if (par->GetResultType() == TYPE_ERROR)
+ return NULL; // Memory allocation error in ARRAY
+
+ /*********************************************************************/
+ /* All is right now, fill the array block. */
+ /*********************************************************************/
+ for (parmp = pp; parmp; parmp = parmp->Next)
+ switch (valtyp) {
+ case TYPE_STRING:
+ par->AddValue(g, (PSZ)parmp->Value);
+ break;
+ case TYPE_SHORT:
+ par->AddValue(g, *(short*)parmp->Value);
+ break;
+ case TYPE_INT:
+ par->AddValue(g, *(int*)parmp->Value);
+ break;
+ case TYPE_DOUBLE:
+ par->AddValue(g, *(double*)parmp->Value);
+ break;
+ case TYPE_PCHAR:
+ par->AddValue(g, parmp->Value);
+ break;
+ case TYPE_VOID:
+ // Integer stored inside pp->Value
+ par->AddValue(g, parmp->Intval);
+ break;
+ } // endswitch valtyp
+
+ /*********************************************************************/
+ /* Send back resulting array. */
+ /*********************************************************************/
+ return par;
+} // end of MakeValueArray
+
+/* -------------------------- Class ARRAY ---------------------------- */
+
+/***********************************************************************/
+/* ARRAY public constructor. */
+/***********************************************************************/
+ARRAY::ARRAY(PGLOBAL g, int type, int size, int length, int prec)
+ : CSORT(false)
+ {
+ Nval = 0;
+ Ndif = 0;
+ Bot = 0;
+ Top = 0;
+ Size = size;
+ Type = type;
+ Xsize = -1;
+ Len = 1;
+ X = 0;
+ Inf = 0;
+ Sup = 0;
+
+ switch (type) {
+ case TYPE_STRING:
+ Len = length;
+ /* fall through */
+ case TYPE_SHORT:
+ case TYPE_INT:
+ case TYPE_DOUBLE:
+ case TYPE_PCHAR:
+ Type = type;
+ break;
+ case TYPE_VOID:
+ Type = TYPE_INT;
+ break;
+#if 0
+ case TYPE_TOKEN:
+ break;
+ case TYPE_LIST:
+ Len = 0;
+ prec = length;
+ break;
+#endif // 0
+ default: // This is illegal an causes an ill formed array building
+ sprintf(g->Message, MSG(BAD_ARRAY_TYPE), type);
+ Type = TYPE_ERROR;
+ return;
+ } // endswitch type
+
+ Valblk = new(g) MBVALS;
+
+ if (!(Vblp = Valblk->Allocate(g, Type, Len, prec, Size)))
+ Type = TYPE_ERROR;
+ else if (!Valblk->GetMemp() && Type != TYPE_LIST)
+ // The error message was built by PlgDBalloc
+ Type = TYPE_ERROR;
+ else if (type != TYPE_PCHAR)
+ Value = AllocateValue(g, type, Len, prec);
+
+ Constant = true;
+ } // end of ARRAY constructor
+
+#if 0
+/***********************************************************************/
+/* ARRAY public constructor from a QUERY. */
+/***********************************************************************/
+ARRAY::ARRAY(PGLOBAL g, PQUERY qryp) : CSORT(false)
+ {
+ Type = qryp->GetColType(0);
+ Nval = qryp->GetNblin();
+ Ndif = 0;
+ Bot = 0;
+ Top = 0;
+ Size = Nval;
+ Xsize = -1;
+ Len = qryp->GetColLength(0);
+ X = Inf = Sup = 0;
+ Correlated = false;
+
+ switch (Type) {
+ case TYPE_STRING:
+ case TYPE_SHORT:
+ case TYPE_INT:
+ case TYPE_DATE:
+ case TYPE_DOUBLE:
+// case TYPE_TOKEN:
+// case TYPE_LIST:
+// Valblk = qryp->GetCol(0)->Result;
+// Vblp = qryp->GetColBlk(0);
+// Value = qryp->GetColValue(0);
+// break;
+ default: // This is illegal an causes an ill formed array building
+ sprintf(g->Message, MSG(BAD_ARRAY_TYPE), Type);
+ Type = TYPE_ERROR;
+ } // endswitch type
+
+ if (!Valblk || (!Valblk->GetMemp() && Type != TYPE_LIST))
+ // The error message was built by ???
+ Type = TYPE_ERROR;
+
+ Constant = true;
+ } // end of ARRAY constructor
+
+/***********************************************************************/
+/* ARRAY constructor from a TYPE_LIST subarray. */
+/***********************************************************************/
+ARRAY::ARRAY(PGLOBAL g, PARRAY par, int k) : CSORT(false)
+ {
+ int prec;
+ LSTBLK *lp;
+
+ if (par->Type != TYPE_LIST) {
+ Type = TYPE_ERROR;
+ return;
+ } // endif Type
+
+ lp = (LSTBLK*)par->Vblp;
+
+ Nval = par->Nval;
+ Ndif = 0;
+ Bot = 0;
+ Top = 0;
+ Size = par->Size;
+ Xsize = -1;
+
+ Valblk = lp->Mbvk[k];
+ Vblp = Valblk->Vblk;
+ Type = Vblp->GetType();
+ Len = (Type == TYPE_STRING) ? Vblp->GetVlen() : 0;
+ prec = (Type == TYPE_FLOAT) ? 2 : 0;
+ Value = AllocateValue(g, Type, Len, prec, NULL);
+ Constant = true;
+ } // end of ARRAY constructor
+
+/***********************************************************************/
+/* Empty: reset the array for a new use (correlated queries). */
+/* Note: this is temporary as correlated queries will not use arrays */
+/* anymore with future optimized algorithms. */
+/***********************************************************************/
+void ARRAY::Empty(void)
+ {
+ assert(Correlated);
+ Nval = Ndif = 0;
+ Bot = Top = X = Inf = Sup = 0;
+ } // end of Empty
+#endif // 0
+
+/***********************************************************************/
+/* Add a string element to an array. */
+/***********************************************************************/
+bool ARRAY::AddValue(PGLOBAL g, PSZ strp)
+{
+ if (Type != TYPE_STRING) {
+ sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "CHAR");
+ return true;
+ } // endif Type
+
+ xtrc(1, " adding string(%d): '%s'\n", Nval, strp);
+ Vblp->SetValue(strp, Nval++);
+ return false;
+} // end of AddValue
+
+/***********************************************************************/
+/* Add a char pointer element to an array. */
+/***********************************************************************/
+bool ARRAY::AddValue(PGLOBAL g, void *p)
+{
+ if (Type != TYPE_PCHAR) {
+ sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "PCHAR");
+ return true;
+ } // endif Type
+
+ xtrc(1, " adding pointer(%d): %p\n", Nval, p);
+ Vblp->SetValue((PSZ)p, Nval++);
+ return false;
+} // end of AddValue
+
+/***********************************************************************/
+/* Add a short integer element to an array. */
+/***********************************************************************/
+bool ARRAY::AddValue(PGLOBAL g, short n)
+{
+ if (Type != TYPE_SHORT) {
+ sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "SHORT");
+ return true;
+ } // endif Type
+
+ xtrc(1, " adding SHORT(%d): %hd\n", Nval, n);
+ Vblp->SetValue(n, Nval++);
+ return false;
+} // end of AddValue
+
+/***********************************************************************/
+/* Add an integer element to an array. */
+/***********************************************************************/
+bool ARRAY::AddValue(PGLOBAL g, int n)
+{
+ if (Type != TYPE_INT) {
+ sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "INTEGER");
+ return true;
+ } // endif Type
+
+ xtrc(1, " adding int(%d): %d\n", Nval, n);
+ Vblp->SetValue(n, Nval++);
+ return false;
+} // end of AddValue
+
+/***********************************************************************/
+/* Add a double float element to an array. */
+/***********************************************************************/
+bool ARRAY::AddValue(PGLOBAL g, double d)
+{
+ if (Type != TYPE_DOUBLE) {
+ sprintf(g->Message, MSG(ADD_BAD_TYPE), GetTypeName(Type), "DOUBLE");
+ return true;
+ } // endif Type
+
+ xtrc(1, " adding float(%d): %lf\n", Nval, d);
+ Value->SetValue(d);
+ Vblp->SetValue(Value, Nval++);
+ return false;
+} // end of AddValue
+
+/***********************************************************************/
+/* Add the value of a XOBJECT block to an array. */
+/***********************************************************************/
+bool ARRAY::AddValue(PGLOBAL g, PXOB xp)
+{
+ if (Type != xp->GetResultType()) {
+ sprintf(g->Message, MSG(ADD_BAD_TYPE),
+ GetTypeName(xp->GetResultType()), GetTypeName(Type));
+ return true;
+ } // endif Type
+
+ xtrc(1, " adding (%d) from xp=%p\n", Nval, xp);
+ Vblp->SetValue(xp->GetValue(), Nval++);
+ return false;
+} // end of AddValue
+
+/***********************************************************************/
+/* Add a value to an array. */
+/***********************************************************************/
+bool ARRAY::AddValue(PGLOBAL g, PVAL vp)
+{
+ if (Type != vp->GetType()) {
+ sprintf(g->Message, MSG(ADD_BAD_TYPE),
+ GetTypeName(vp->GetType()), GetTypeName(Type));
+ return true;
+ } // endif Type
+
+ xtrc(1, " adding (%d) from vp=%p\n", Nval, vp);
+ Vblp->SetValue(vp, Nval++);
+ return false;
+} // end of AddValue
+
+/***********************************************************************/
+/* Retrieve the nth value of the array. */
+/***********************************************************************/
+void ARRAY::GetNthValue(PVAL valp, int n)
+ {
+ valp->SetValue_pvblk(Vblp, n);
+ } // end of GetNthValue
+
+#if 0
+/***********************************************************************/
+/* Retrieve the nth subvalue of a list array. */
+/***********************************************************************/
+bool ARRAY::GetSubValue(PGLOBAL g, PVAL valp, int *kp)
+ {
+ PVBLK vblp;
+
+ if (Type != TYPE_LIST) {
+ sprintf(g->Message, MSG(NO_SUB_VAL), Type);
+ return true;
+ } // endif Type
+
+ vblp = ((LSTBLK*)Vblp)->Mbvk[kp[0]]->Vblk;
+ valp->SetValue_pvblk(vblp, kp[1]);
+ return false;
+ } // end of GetSubValue
+#endif // 0
+
+/***********************************************************************/
+/* Return the nth value of an integer array. */
+/***********************************************************************/
+int ARRAY::GetIntValue(int n)
+ {
+ assert (Type == TYPE_INT);
+ return Vblp->GetIntValue(n);
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* Return the nth value of a STRING array. */
+/***********************************************************************/
+char *ARRAY::GetStringValue(int n)
+ {
+ assert (Type == TYPE_STRING || Type == TYPE_PCHAR);
+ return Vblp->GetCharValue(n);
+ } // end of GetStringValue
+
+/***********************************************************************/
+/* Find whether a value is in an array. */
+/* Provide a conversion limited to the Value limitation. */
+/***********************************************************************/
+bool ARRAY::Find(PVAL valp)
+ {
+ int n;
+ PVAL vp;
+
+ if (Type != valp->GetType()) {
+ Value->SetValue_pval(valp);
+ vp = Value;
+ } else
+ vp = valp;
+
+ Inf = Bot, Sup = Top;
+
+ while (Sup - Inf > 1) {
+ X = (Inf + Sup) >> 1;
+ n = Vblp->CompVal(vp, X);
+
+ if (n < 0)
+ Sup = X;
+ else if (n > 0)
+ Inf = X;
+ else
+ return true;
+
+ } // endwhile
+
+ return false;
+ } // end of Find
+
+/***********************************************************************/
+/* ARRAY: Compare routine for a list of values. */
+/***********************************************************************/
+BYTE ARRAY::Vcompare(PVAL vp, int n)
+ {
+ Value->SetValue_pvblk(Vblp, n);
+ return vp->TestValue(Value);
+ } // end of Vcompare
+
+/***********************************************************************/
+/* Test a filter condition on an array depending on operator and mod. */
+/* Modificator values are 1: ANY (or SOME) and 2: ALL. */
+/***********************************************************************/
+bool ARRAY::FilTest(PGLOBAL g, PVAL valp, OPVAL opc, int opm)
+ {
+ int i;
+ PVAL vp;
+ BYTE bt = OpBmp(g, opc);
+ int top = Nval - 1;
+
+ if (top < 0) // Array is empty
+ // Return true for ALL because it means that there are no item that
+ // does not verify the condition, which is true indeed.
+ // Return false for ANY because true means that there is at least
+ // one item that verifies the condition, which is false.
+ return opm == 2;
+
+ if (valp) {
+ if (Type != valp->GetType()) {
+ Value->SetValue_pval(valp);
+ vp = Value;
+ } else
+ vp = valp;
+
+ } else if (opc != OP_EXIST) {
+ sprintf(g->Message, MSG(MISSING_ARG), opc);
+ throw (int)TYPE_ARRAY;
+ } else // OP_EXIST
+ return Nval > 0;
+
+ if (opc == OP_IN || (opc == OP_EQ && opm == 1))
+ return Find(vp);
+ else if (opc == OP_NE && opm == 2)
+ return !Find(vp);
+ else if (opc == OP_EQ && opm == 2)
+ return (Ndif == 1) ? !(Vcompare(vp, 0) & bt) : false;
+ else if (opc == OP_NE && opm == 1)
+ return (Ndif == 1) ? !(Vcompare(vp, 0) & bt) : true;
+
+ if (Type != TYPE_LIST) {
+ if (opc == OP_GT || opc == OP_GE)
+ return !(Vcompare(vp, (opm == 1) ? 0 : top) & bt);
+ else
+ return !(Vcompare(vp, (opm == 2) ? 0 : top) & bt);
+
+ } // endif Type
+
+ // Case of TYPE_LIST
+ if (opm == 2) {
+ for (i = 0; i < Nval; i++)
+ if (Vcompare(vp, i) & bt)
+ return false;
+
+ return true;
+ } else { // opm == 1
+ for (i = 0; i < Nval; i++)
+ if (!(Vcompare(vp, i) & bt))
+ return true;
+
+ return false;
+ } // endif opm
+
+ } // end of FilTest
+
+/***********************************************************************/
+/* Test whether this array can be converted to TYPE_SHORT. */
+/* Must be called after the array is sorted. */
+/***********************************************************************/
+bool ARRAY::CanBeShort(void)
+ {
+ int* To_Val = (int*)Valblk->GetMemp();
+
+ if (Type != TYPE_INT || !Ndif)
+ return false;
+
+ // Because the array is sorted, this is true if all the array
+ // int values are in the range of SHORT values
+ return (To_Val[0] >= -32768 && To_Val[Nval-1] < 32768);
+ } // end of CanBeShort
+
+/***********************************************************************/
+/* Convert an array to new numeric type k. */
+/* Note: conversion is always made in ascending order from STRING to */
+/* short to int to double so no precision is lost in the conversion. */
+/* One exception is converting from int to short compatible arrays. */
+/***********************************************************************/
+int ARRAY::Convert(PGLOBAL g, int k, PVAL vp)
+ {
+ int i, prec = 0;
+ bool b = false;
+ PMBV ovblk = Valblk;
+ PVBLK ovblp = Vblp;
+
+ Type = k; // k is the new type
+ Valblk = new(g) MBVALS;
+
+ switch (Type) {
+ case TYPE_DOUBLE:
+ prec = 2;
+ /* fall through */
+ case TYPE_SHORT:
+ case TYPE_INT:
+ case TYPE_DATE:
+ Len = 1;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_CONV_TYPE), Type);
+ return TYPE_ERROR;
+ } // endswitch k
+
+ Size = Nval;
+ Nval = 0;
+ Vblp = Valblk->Allocate(g, Type, Len, prec, Size);
+
+ if (!Valblk->GetMemp())
+ // The error message was built by PlgDBalloc
+ return TYPE_ERROR;
+ else
+ Value = AllocateValue(g, Type, Len, prec);
+
+ /*********************************************************************/
+ /* Converting STRING to DATE can be done according to date format. */
+ /*********************************************************************/
+ if (Type == TYPE_DATE && ovblp->GetType() == TYPE_STRING && vp)
+ {
+ if (((DTVAL*)Value)->SetFormat(g, vp))
+ return TYPE_ERROR;
+ else
+ b = true; // Sort the new array on date internal values
+ }
+
+ /*********************************************************************/
+ /* Do the actual conversion. */
+ /*********************************************************************/
+ for (i = 0; i < Size; i++) {
+ Value->SetValue_pvblk(ovblp, i);
+
+ if (AddValue(g, Value))
+ return TYPE_ERROR;
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* For sorted arrays, get the initial find values. */
+ /*********************************************************************/
+ if (b)
+ Sort(g);
+
+ ovblk->Free();
+ return Type;
+ } // end of Convert
+
+/***********************************************************************/
+/* ARRAY Save: save value at i (used while rordering). */
+/***********************************************************************/
+void ARRAY::Save(int i)
+ {
+ Value->SetValue_pvblk(Vblp, i);
+ } // end of Save
+
+/***********************************************************************/
+/* ARRAY Restore: restore value to j (used while rordering). */
+/***********************************************************************/
+void ARRAY::Restore(int j)
+ {
+ Vblp->SetValue(Value, j);
+ } // end of Restore
+
+/***********************************************************************/
+/* ARRAY Move: move value from k to j (used while rordering). */
+/***********************************************************************/
+void ARRAY::Move(int j, int k)
+ {
+ Vblp->Move(k, j); // VALBLK does the opposite !!!
+ } // end of Move
+
+/***********************************************************************/
+/* ARRAY: Compare routine for one LIST value (ascending only). */
+/***********************************************************************/
+int ARRAY::Qcompare(int *i1, int *i2)
+ {
+ return Vblp->CompVal(*i1, *i2);
+ } // end of Qcompare
+
+/***********************************************************************/
+/* Mainly meant to set the character arrays case sensitiveness. */
+/***********************************************************************/
+void ARRAY::SetPrecision(PGLOBAL g, int p)
+ {
+ if (Vblp == NULL) {
+ strcpy(g->Message, MSG(PREC_VBLP_NULL));
+ throw (int)TYPE_ARRAY;
+ } // endif Vblp
+
+ bool was = Vblp->IsCi();
+
+ if (was && !p) {
+ strcpy(g->Message, MSG(BAD_SET_CASE));
+ throw (int)TYPE_ARRAY;
+ } // endif Vblp
+
+ if (was || !p)
+ return;
+ else
+ Vblp->SetPrec(p);
+
+ if (!was && Type == TYPE_STRING)
+ // Must be resorted to eliminate duplicate strings
+ if (Sort(g))
+ throw (int)TYPE_ARRAY;
+
+ } // end of SetPrecision
+
+/***********************************************************************/
+/* Sort and eliminate distinct values from an array. */
+/* Note: this is done by making a sorted index on distinct values. */
+/* Returns false if Ok or true in case of error. */
+/***********************************************************************/
+bool ARRAY::Sort(PGLOBAL g)
+ {
+ int i, j, k;
+
+ // This is to avoid multiply allocating for correlated subqueries
+ if (Nval > Xsize) {
+ if (Xsize >= 0) {
+ // Was already allocated
+ PlgDBfree(Index);
+ PlgDBfree(Offset);
+ } // endif Xsize
+
+ // Prepare non conservative sort with offet values
+ Index.Size = Nval * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Index))
+ goto error;
+
+ Offset.Size = (Nval + 1) * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Offset))
+ goto error;
+
+ Xsize = Nval;
+ } // endif Nval
+
+ // Call the sort program, it returns the number of distinct values
+ Ndif = Qsort(g, Nval);
+
+ if (Ndif < 0)
+ goto error;
+
+ // Use the sort index to reorder the data in storage so it will
+ // be physically sorted and Index can be removed.
+ for (i = 0; i < Nval; i++) {
+ if (Pex[i] == i || Pex[i] == Nval)
+ // Already placed or already moved
+ continue;
+
+ Save(i);
+
+ for (j = i;; j = k) {
+ k = Pex[j];
+ Pex[j] = Nval; // Mark position as set
+
+ if (k == i) {
+ Restore(j);
+ break; // end of loop
+ } else
+ Move(j, k);
+
+ } // endfor j
+
+ } // endfor i
+
+ // Reduce the size of the To_Val array if Ndif < Nval
+ if (Ndif < Nval) {
+ for (i = 1; i < Ndif; i++)
+ if (i != Pof[i])
+ break;
+
+ for (; i < Ndif; i++)
+ Move(i, Pof[i]);
+
+ Nval = Ndif;
+ } // endif ndif
+
+//if (!Correlated) {
+ if (Size > Nval) {
+ Size = Nval;
+ Valblk->ReAllocate(g, Size);
+ } // endif Size
+
+ // Index and Offset are not used anymore
+ PlgDBfree(Index);
+ PlgDBfree(Offset);
+ Xsize = -1;
+// } // endif Correlated
+
+ Bot = -1; // For non optimized search
+ Top = Ndif; // Find searches the whole array.
+ return false;
+
+ error:
+ Nval = Ndif = 0;
+ Valblk->Free();
+ PlgDBfree(Index);
+ PlgDBfree(Offset);
+ return true;
+ } // end of Sort
+
+/***********************************************************************/
+/* Sort and return the sort index. */
+/* Note: This is meant if the array contains unique values. */
+/* Returns Index.Memp if Ok or NULL in case of error. */
+/***********************************************************************/
+void *ARRAY::GetSortIndex(PGLOBAL g)
+ {
+ // Prepare non conservative sort with offet values
+ Index.Size = Nval * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Index))
+ goto error;
+
+ Offset.Size = (Nval + 1) * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Offset))
+ goto error;
+
+ // Call the sort program, it returns the number of distinct values
+ Ndif = Qsort(g, Nval);
+
+ if (Ndif < 0)
+ goto error;
+
+ if (Ndif < Nval)
+ goto error;
+
+ PlgDBfree(Offset);
+ return Index.Memp;
+
+ error:
+ Nval = Ndif = 0;
+ Valblk->Free();
+ PlgDBfree(Index);
+ PlgDBfree(Offset);
+ return NULL;
+ } // end of GetSortIndex
+
+/***********************************************************************/
+/* Block filter testing for IN operator on Column/Array operands. */
+/* Here we call Find that returns true if the value is in the array */
+/* with X equal to the index of the found value in the array, or */
+/* false if the value is not in the array with Inf and Sup being the */
+/* indexes of the array values that are immediately below and over */
+/* the not found value. This enables to restrict the array to the */
+/* values that are between the min and max block values and to return */
+/* the indication of whether the Find will be always true, always not */
+/* true or other. */
+/***********************************************************************/
+int ARRAY::BlockTest(PGLOBAL, int opc, int opm,
+ void *minp, void *maxp, bool s)
+ {
+ bool bin, bax, pin, pax, veq, all = (opm == 2);
+
+ if (Ndif == 0) // Array is empty
+ // Return true for ALL because it means that there are no item that
+ // does not verify the condition, which is true indeed.
+ // Return false for ANY because true means that there is at least
+ // one item that verifies the condition, which is false.
+ return (all) ? 2 : -2;
+ else if (opc == OP_EQ && all && Ndif > 1)
+ return -2;
+ else if (opc == OP_NE && !all && Ndif > 1)
+ return 2;
+// else if (Ndif == 1)
+// all = false;
+
+ // veq is true when all values in the block are equal
+ switch (Type) {
+ case TYPE_STRING: veq = (Vblp->IsCi())
+ ? !stricmp((char*)minp, (char*)maxp)
+ : !strcmp((char*)minp, (char*)maxp); break;
+ case TYPE_SHORT: veq = *(short*)minp == *(short*)maxp; break;
+ case TYPE_INT: veq = *(int*)minp == *(int*)maxp; break;
+ case TYPE_DOUBLE: veq = *(double*)minp == *(double*)maxp; break;
+ default: veq = false; // Error ?
+ } // endswitch type
+
+ if (!s)
+ Bot = -1;
+
+ Top = Ndif; // Reset Top at top of list
+ Value->SetBinValue(maxp);
+ Top = (bax = Find(Value)) ? X + 1 : Sup;
+
+ if (bax) {
+ if (opc == OP_EQ)
+ return (veq) ? 1 : 0;
+ else if (opc == OP_NE)
+ return (veq) ? -1 : 0;
+
+ if (X == 0) switch (opc) {
+ // Max value is equal to min list value
+ case OP_LE: return 1; break;
+ case OP_LT: return (veq) ? -1 : 0; break;
+ case OP_GE: return (veq) ? 1 : 0; break;
+ case OP_GT: return -1; break;
+ } // endswitch opc
+
+ pax = (opc == OP_GE) ? (X < Ndif - 1) : true;
+ } else if (Inf == Bot) {
+ // Max value is smaller than min list value
+ return (opc == OP_LT || opc == OP_LE || opc == OP_NE) ? 1 : -1;
+ } else
+ pax = (Sup < Ndif); // True if max value is inside the list value
+
+ if (!veq) {
+ Value->SetBinValue(minp);
+ bin = Find(Value);
+ } else
+ bin = bax;
+
+ Bot = (bin) ? X - 1 : Inf;
+
+ if (bin) {
+ if (opc == OP_EQ || opc == OP_NE)
+ return 0;
+
+ if (X == Ndif - 1) switch (opc) {
+ case OP_GE: return (s) ? 2 : 1; break;
+ case OP_GT: return (veq) ? -1 : 0; break;
+ case OP_LE: return (veq) ? 1 : 0; break;
+ case OP_LT: return (s) ? -2 : -1; break;
+ } // endswitch opc
+
+ pin = (opc == OP_LE) ? (X > 0) : true;
+ } else if (Sup == Ndif) {
+ // Min value is greater than max list value
+ if (opc == OP_GT || opc == OP_GE || opc == OP_NE)
+ return (s) ? 2 : 1;
+ else
+ return (s) ? -2 : -1;
+
+ } else
+ pin = (Inf >= 0); // True if min value is inside the list value
+
+ if (Top - Bot <= 1) {
+ // No list item between min and max value
+#if defined(_DEBUG)
+ assert (!bin && !bax);
+#endif
+ switch (opc) {
+ case OP_EQ: return -1; break;
+ case OP_NE: return 1; break;
+ default: return (all) ? -1 : 1; break;
+ } // endswitch opc
+
+ } // endif
+
+#if defined(_DEBUG)
+ assert (Ndif > 1); // if Ndif = 1 we should have returned already
+#endif
+
+ // At this point, if there are no logical errors in the algorithm,
+ // the only possible overlaps between the array and the block are:
+ // Array: +-------+ +-------+ +-------+ +-----+
+ // Block: +-----+ +---+ +------+ +--------+
+ // true: pax pin pax pin
+ if (all) switch (opc) {
+ case OP_GT:
+ case OP_GE: return (pax) ? -1 : 0; break;
+ case OP_LT:
+ case OP_LE: return (pin) ? -1 : 0; break;
+ } // endswitch opc
+
+ return 0;
+ } // end of BlockTest
+
+/***********************************************************************/
+/* MakeArrayList: Makes a value list from an SQL IN array (in work). */
+/***********************************************************************/
+PSZ ARRAY::MakeArrayList(PGLOBAL g)
+{
+ char *p, *tp;
+ int i;
+ size_t z, len = 2;
+
+ if (Type == TYPE_LIST)
+ return (PSZ)("(?" "?" "?)"); // To be implemented
+
+ z = MY_MAX(24, GetTypeSize(Type, Len) + 4);
+ tp = (char*)PlugSubAlloc(g, NULL, z);
+
+ for (i = 0; i < Nval; i++) {
+ Value->SetValue_pvblk(Vblp, i);
+ Value->Prints(g, tp, z);
+ len += strlen(tp);
+ } // enfor i
+
+ xtrc(1, "Arraylist: len=%d\n", len);
+ p = (char *)PlugSubAlloc(g, NULL, len);
+ strcpy(p, "(");
+
+ for (i = 0; i < Nval;) {
+ Value->SetValue_pvblk(Vblp, i);
+ Value->Prints(g, tp, z);
+ strcat(p, tp);
+ strcat(p, (++i == Nval) ? ")" : ",");
+ } // enfor i
+
+ xtrc(1, "Arraylist: newlen=%d\n", strlen(p));
+ return p;
+} // end of MakeArrayList
+
+/***********************************************************************/
+/* Make file output of ARRAY contents. */
+/***********************************************************************/
+void ARRAY::Printf(PGLOBAL g, FILE *f, uint n)
+{
+ char m[64];
+ int lim = MY_MIN(Nval,10);
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+ fprintf(f, "%sARRAY: type=%d\n", m, Type);
+ memset(m, ' ', n + 2); // Make margin string
+ m[n] = '\0';
+
+ if (Type != TYPE_LIST) {
+ fprintf(f, "%sblock=%p numval=%d\n", m, Valblk->GetMemp(), Nval);
+
+ if (Vblp)
+ for (int i = 0; i < lim; i++) {
+ Value->SetValue_pvblk(Vblp, i);
+ Value->Printf(g, f, n+4);
+ } // endfor i
+
+ } else
+ fprintf(f, "%sVALLST: numval=%d\n", m, Nval);
+
+} // end of Printf
+
+/***********************************************************************/
+/* Make string output of ARRAY contents. */
+/***********************************************************************/
+void ARRAY::Prints(PGLOBAL, char *ps, uint z)
+{
+ if (z < 16)
+ return;
+
+ sprintf(ps, "ARRAY: type=%d\n", Type);
+ // More to be implemented later
+} // end of Prints
+
+/* -------------------------- Class MULAR ---------------------------- */
+
+/***********************************************************************/
+/* MULAR public constructor. */
+/***********************************************************************/
+MULAR::MULAR(PGLOBAL g, int n) : CSORT(false)
+ {
+ Narray = n;
+ Pars = (PARRAY*)PlugSubAlloc(g, NULL, n * sizeof(PARRAY));
+ } // end of MULAR constructor
+
+/***********************************************************************/
+/* MULAR: Compare routine multiple arrays. */
+/***********************************************************************/
+int MULAR::Qcompare(int *i1, int *i2)
+ {
+ int i, n = 0;
+
+ for (i = 0; i < Narray; i++)
+ if ((n = Pars[i]->Qcompare(i1, i2)))
+ break;
+
+ return n;
+ } // end of Qcompare
+
+/***********************************************************************/
+/* Sort and eliminate distinct values from multiple arrays. */
+/* Note: this is done by making a sorted index on distinct values. */
+/* Returns false if Ok or true in case of error. */
+/***********************************************************************/
+bool MULAR::Sort(PGLOBAL g)
+ {
+ int i, j, k, n, nval, ndif;
+
+ // All arrays must have the same number of values
+ nval = Pars[0]->Nval;
+
+ for (n = 1; n < Narray; n++)
+ if (Pars[n]->Nval != nval) {
+ strcpy(g->Message, MSG(BAD_ARRAY_VAL));
+ return true;
+ } // endif nval
+
+ // Prepare non conservative sort with offet values
+ Index.Size = nval * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Index))
+ goto error;
+
+ Offset.Size = (nval + 1) * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Offset))
+ goto error;
+
+ // Call the sort program, it returns the number of distinct values
+ ndif = Qsort(g, nval);
+
+ if (ndif < 0)
+ goto error;
+
+ // Use the sort index to reorder the data in storage so it will
+ // be physically sorted and Index can be removed.
+ for (i = 0; i < nval; i++) {
+ if (Pex[i] == i || Pex[i] == nval)
+ // Already placed or already moved
+ continue;
+
+ for (n = 0; n < Narray; n++)
+ Pars[n]->Save(i);
+
+ for (j = i;; j = k) {
+ k = Pex[j];
+ Pex[j] = nval; // Mark position as set
+
+ if (k == i) {
+ for (n = 0; n < Narray; n++)
+ Pars[n]->Restore(j);
+
+ break; // end of loop
+ } else
+ for (n = 0; n < Narray; n++)
+ Pars[n]->Move(j, k);
+
+ } // endfor j
+
+ } // endfor i
+
+ // Reduce the size of the To_Val array if ndif < nval
+ if (ndif < nval) {
+ for (i = 1; i < ndif; i++)
+ if (i != Pof[i])
+ break;
+
+ for (; i < ndif; i++)
+ for (n = 0; n < Narray; n++)
+ Pars[n]->Move(i, Pof[i]);
+
+ for (n = 0; n < Narray; n++) {
+ Pars[n]->Nval = ndif;
+ Pars[n]->Size = ndif;
+ Pars[n]->Valblk->ReAllocate(g, ndif);
+ } // endfor n
+
+ } // endif ndif
+
+ // Index and Offset are not used anymore
+ PlgDBfree(Index);
+ PlgDBfree(Offset);
+
+ for (n = 0; n < Narray; n++) {
+ Pars[n]->Bot = -1; // For non optimized search
+ Pars[n]->Top = ndif; // Find searches the whole array.
+ } // endfor n
+
+ return false;
+
+ error:
+ PlgDBfree(Index);
+ PlgDBfree(Offset);
+ return true;
+ } // end of Sort
diff --git a/storage/connect/array.h b/storage/connect/array.h
new file mode 100644
index 00000000..bd38344d
--- /dev/null
+++ b/storage/connect/array.h
@@ -0,0 +1,131 @@
+/**************** Array H Declares Source Code File (.H) ***************/
+/* Name: ARRAY.H Version 3.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2017 */
+/* */
+/* This file contains the ARRAY and VALBASE derived classes declares. */
+/***********************************************************************/
+#ifndef __ARRAY_H
+#define __ARRAY_H
+
+
+/***********************************************************************/
+/* Include required application header files */
+/***********************************************************************/
+#include "xobject.h"
+#include "valblk.h"
+#include "csort.h"
+
+typedef class ARRAY *PARRAY;
+
+/***********************************************************************/
+/* Definition of class ARRAY with all its method functions. */
+/* Note: This is not a general array class that could be defined as */
+/* a template class, but rather a specific object containing a list */
+/* of values to be processed by the filter IN operator. */
+/* In addition it must act as a metaclass by being able to give back */
+/* the type of values it contains. */
+/* It must also be able to convert itself from some type to another. */
+/***********************************************************************/
+class DllExport ARRAY : public XOBJECT, public CSORT { // Array descblock
+ friend class MULAR;
+//friend class VALLST;
+//friend class SFROW;
+ public:
+ // Constructors
+ ARRAY(PGLOBAL g, int type, int size, int len = 1, int prec = 0);
+//ARRAY(PGLOBAL g, PQUERY qryp);
+//ARRAY(PGLOBAL g, PARRAY par, int k);
+
+ // Implementation
+ virtual int GetType(void) {return TYPE_ARRAY;}
+ virtual int GetResultType(void) {return Type;}
+ virtual int GetLength(void) {return Len;}
+ virtual int GetLengthEx(void) {return Len;}
+ virtual int GetScale() {return 0;}
+ int GetNval(void) {return Nval;}
+ int GetSize(void) {return Size;}
+// PVAL GetValp(void) {return Valp;}
+ void SetType(int atype) {Type = atype;}
+// void SetCorrel(bool b) {Correlated = b;}
+
+ // Methods
+ using XOBJECT::GetIntValue;
+ virtual void Reset(void) {Bot = -1;}
+ virtual int Qcompare(int *, int *);
+ virtual bool Compare(PXOB) {assert(false); return false;}
+ virtual bool SetFormat(PGLOBAL, FORMAT&) {assert(false); return false;}
+//virtual int CheckSpcCol(PTDB, int) {return 0;}
+ virtual void Printf(PGLOBAL g, FILE *f, uint n);
+ virtual void Prints(PGLOBAL g, char *ps, uint z);
+// void Empty(void);
+ void SetPrecision(PGLOBAL g, int p);
+ bool AddValue(PGLOBAL g, PSZ sp);
+ bool AddValue(PGLOBAL g, void *p);
+ bool AddValue(PGLOBAL g, short n);
+ bool AddValue(PGLOBAL g, int n);
+ bool AddValue(PGLOBAL g, double f);
+ bool AddValue(PGLOBAL g, PXOB xp);
+ bool AddValue(PGLOBAL g, PVAL vp);
+ void GetNthValue(PVAL valp, int n);
+ int GetIntValue(int n);
+ char *GetStringValue(int n);
+ BYTE Vcompare(PVAL vp, int n);
+ void Save(int);
+ void Restore(int);
+ void Move(int, int);
+ bool Sort(PGLOBAL g);
+ void *GetSortIndex(PGLOBAL g);
+ bool Find(PVAL valp);
+ bool FilTest(PGLOBAL g, PVAL valp, OPVAL opc, int opm);
+ int Convert(PGLOBAL g, int k, PVAL vp = NULL);
+ int BlockTest(PGLOBAL g, int opc, int opm,
+ void *minp, void *maxp, bool s);
+ PSZ MakeArrayList(PGLOBAL g);
+ bool CanBeShort(void);
+ bool GetSubValue(PGLOBAL g, PVAL valp, int *kp);
+
+ protected:
+ // Members
+ PMBV Valblk; // To the MBVALS class
+ PVBLK Vblp; // To Valblock of the data array
+//PVAL Valp; // The value used for Save and Restore is Value
+ int Size; // Size of value array
+ int Nval; // Total number of items in array
+ int Ndif; // Total number of distinct items in array
+ int Xsize; // Size of Index (used for correlated arrays)
+ int Type; // Type of individual values in the array
+ int Len; // Length of character string
+ int Bot; // Bottom of research index
+ int Top; // Top of research index
+ int X, Inf, Sup; // Used for block optimization
+//bool Correlated; // -----------> Temporary
+ }; // end of class ARRAY
+
+/***********************************************************************/
+/* Definition of class MULAR with all its method functions. */
+/* This class is used when constructing the arrays of constants used */
+/* for indexing. Its only purpose is to provide a way to sort, reduce */
+/* and reorder the arrays of multicolumn indexes as one block. Indeed */
+/* sorting the arrays independantly would break the correspondance of */
+/* column values. */
+/***********************************************************************/
+class MULAR : public CSORT, public BLOCK { // No need to be an XOBJECT
+ public:
+ // Constructor
+ MULAR(PGLOBAL g, int n);
+
+ // Implementation
+ void SetPars(PARRAY par, int i) {Pars[i] = par;}
+
+ // Methods
+ virtual int Qcompare(int *i1, int *i2); // Sort compare routine
+ bool Sort(PGLOBAL g);
+
+ protected:
+ // Members
+ int Narray; // The number of sub-arrays
+ PARRAY *Pars; // To the block of real arrays
+ }; // end of class ARRAY
+
+#endif // __ARRAY_H
diff --git a/storage/connect/blkfil.cpp b/storage/connect/blkfil.cpp
new file mode 100644
index 00000000..93ae5a5e
--- /dev/null
+++ b/storage/connect/blkfil.cpp
@@ -0,0 +1,1075 @@
+/************* BlkFil C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: BLKFIL */
+/* ------------- */
+/* Version 2.6 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2004-2017 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program is the implementation of block indexing classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#include "sql_class.h"
+//#include "sql_time.h"
+
+#if defined(_WIN32)
+//#include <windows.h>
+#else // !_WIN32
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h" // global declarations
+#include "plgdbsem.h" // DB application declarations
+#include "xindex.h" // Key Index class declarations
+#include "filamtxt.h" // File access method dcls
+#include "tabdos.h" // TDBDOS and DOSCOL class dcls
+#include "array.h" // ARRAY classes dcls
+#include "blkfil.h" // Block Filter classes dcls
+
+/* ------------------------ Class BLOCKFILTER ------------------------ */
+
+/***********************************************************************/
+/* BLOCKFILTER constructor. */
+/***********************************************************************/
+BLOCKFILTER::BLOCKFILTER(PTDBDOS tdbp, int op)
+ {
+ Tdbp = tdbp;
+ Correl = FALSE;
+ Opc = op;
+ Opm = 0;
+ Result = 0;
+ } // end of BLOCKFILTER constructor
+
+/***********************************************************************/
+/* Make file output of BLOCKFILTER contents. */
+/***********************************************************************/
+void BLOCKFILTER::Printf(PGLOBAL, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+
+ fprintf(f, "%sBLOCKFILTER: at %p opc=%d opm=%d result=%d\n",
+ m, this, Opc, Opm, Result);
+ } // end of Printf
+
+/***********************************************************************/
+/* Make string output of BLOCKFILTER contents. */
+/***********************************************************************/
+void BLOCKFILTER::Prints(PGLOBAL, char *ps, uint z)
+ {
+ strncat(ps, "BlockFilter(s)", z);
+ } // end of Prints
+
+
+/* ---------------------- Class BLKFILLOG ---------------------------- */
+
+/***********************************************************************/
+/* BLKFILLOG constructor. */
+/***********************************************************************/
+BLKFILLOG::BLKFILLOG(PTDBDOS tdbp, int op, PBF *bfp, int n)
+ : BLOCKFILTER(tdbp, op)
+ {
+ N = n;
+ Fil = bfp;
+
+ for (int i = 0; i < N; i++)
+ if (Fil[i])
+ Correl |= Fil[i]->Correl;
+
+ } // end of BLKFILLOG constructor
+
+/***********************************************************************/
+/* Reset: this function is used only to check the existence of a */
+/* BLKFILIN block and have it reset its Bot value for sorted columns. */
+/***********************************************************************/
+void BLKFILLOG::Reset(PGLOBAL g)
+ {
+ for (int i = 0; i < N; i++)
+ if (Fil[i])
+ Fil[i]->Reset(g);
+
+ } // end of Reset
+
+/***********************************************************************/
+/* This function is used for block filter evaluation. We use here a */
+/* fuzzy logic between the values returned by evaluation blocks: */
+/* -2: the condition will be always false for the rest of the file. */
+/* -1: the condition will be false for the whole group. */
+/* 0: the condition may be true for some of the group values. */
+/* 1: the condition will be true for the whole group. */
+/* 2: the condition will be always true for the rest of the file. */
+/***********************************************************************/
+int BLKFILLOG::BlockEval(PGLOBAL g)
+ {
+ int i, rc;
+
+ for (i = 0; i < N; i++) {
+ // 0: Means some block filter value may be True
+ rc = (Fil[i]) ? Fil[i]->BlockEval(g) : 0;
+
+ if (!i)
+ Result = (Opc == OP_NOT) ? -rc : rc;
+ else switch (Opc) {
+ case OP_AND:
+ Result = MY_MIN(Result, rc);
+ break;
+ case OP_OR:
+ Result = MY_MAX(Result, rc);
+ break;
+ default:
+ // Should never happen
+ Result = 0;
+ return Result;
+ } // endswitch Opc
+
+ } // endfor i
+
+ return Result;
+ } // end of BlockEval
+
+/* ---------------------- Class BLKFILARI----------------------------- */
+
+/***********************************************************************/
+/* BLKFILARI constructor. */
+/***********************************************************************/
+BLKFILARI::BLKFILARI(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
+ : BLOCKFILTER(tdbp, op)
+ {
+ Colp = (PDOSCOL)xp[0];
+
+ if (xp[1]->GetType() == TYPE_COLBLK) {
+ Cpx = (PCOL)xp[1]; // Subquery pseudo constant column
+ Correl = TRUE;
+ } else
+ Cpx = NULL;
+
+ Sorted = Colp->IsSorted() > 0;
+
+ // Don't remember why this was changed. Anyway it is no good for
+ // correlated subqueries because the Value must reflect changes
+ if (Cpx)
+ Valp = xp[1]->GetValue();
+ else
+ Valp = AllocateValue(g, xp[1]->GetValue());
+
+ } // end of BLKFILARI constructor
+
+/***********************************************************************/
+/* Reset: re-eval the constant value in the case of pseudo constant */
+/* column use in a correlated subquery. */
+/***********************************************************************/
+void BLKFILARI::Reset(PGLOBAL g)
+ {
+ if (Cpx) {
+ Cpx->Reset();
+ Cpx->Eval(g);
+ MakeValueBitmap(); // Does nothing for class BLKFILARI
+ } // endif Cpx
+
+ } // end of Reset
+
+/***********************************************************************/
+/* Evaluate block filter for arithmetic operators. */
+/***********************************************************************/
+int BLKFILARI::BlockEval(PGLOBAL)
+ {
+ int mincmp, maxcmp, n;
+
+#if defined(_DEBUG)
+ assert (Colp->IsClustered());
+#endif
+
+ n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
+ mincmp = Colp->GetMin()->CompVal(Valp, n);
+ maxcmp = Colp->GetMax()->CompVal(Valp, n);
+
+ switch (Opc) {
+ case OP_EQ:
+ case OP_NE:
+ if (mincmp < 0) // Means minval > Val
+ Result = (Sorted) ? -2 : -1;
+ else if (maxcmp > 0) // Means maxval < Val
+ Result = -1;
+ else if (!mincmp && !maxcmp) // minval = maxval = val
+ Result = 1;
+ else
+ Result = 0;
+
+ break;
+ case OP_GT:
+ case OP_LE:
+ if (mincmp < 0) // minval > Val
+ Result = (Sorted) ? 2 : 1;
+ else if (maxcmp < 0) // maxval > Val
+ Result = 0;
+ else // maxval <= Val
+ Result = -1;
+
+ break;
+ case OP_GE:
+ case OP_LT:
+ if (mincmp <= 0) // minval >= Val
+ Result = (Sorted) ? 2 : 1;
+ else if (maxcmp <= 0) // Maxval >= Val
+ Result = 0;
+ else // Maxval < Val
+ Result = -1;
+
+ break;
+ } // endswitch Opc
+
+ switch (Opc) {
+ case OP_NE:
+ case OP_LE:
+ case OP_LT:
+ Result = -Result;
+ break;
+ } // endswitch Opc
+
+ if (trace(1))
+ htrc("BlockEval: op=%d n=%d rc=%d\n", Opc, n, Result);
+
+ return Result;
+ } // end of BlockEval
+
+/* ---------------------- Class BLKFILAR2----------------------------- */
+
+/***********************************************************************/
+/* BLKFILAR2 constructor. */
+/***********************************************************************/
+BLKFILAR2::BLKFILAR2(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
+ : BLKFILARI(g, tdbp, op, xp)
+ {
+ MakeValueBitmap();
+ } // end of BLKFILAR2 constructor
+
+/***********************************************************************/
+/* MakeValueBitmap: Set the constant value bit map. It can be void */
+/* if the constant value is not in the column distinct values list. */
+/***********************************************************************/
+void BLKFILAR2::MakeValueBitmap(void)
+ {
+ int i; // ndv = Colp->GetNdv();
+ bool found = FALSE;
+ PVBLK dval = Colp->GetDval();
+
+ assert(dval);
+
+ /*********************************************************************/
+ /* Here we cannot use Find because we must get the index */
+ /* of where to put the value if it is not found in the array. */
+ /* This is needed by operators other than OP_EQ or OP_NE. */
+ /*********************************************************************/
+ found = dval->Locate(Valp, i);
+
+ /*********************************************************************/
+ /* Set the constant value bitmap. The bitmaps are really matching */
+ /* the OP_EQ, OP_LE, and OP_LT operator but are also used for the */
+ /* other operators for which the Result will be inverted. */
+ /* The reason the bitmaps are not directly complemented for them is */
+ /* to be able to test easily the cases of sorted columns with Bxp, */
+ /* and the case of a void bitmap, which happens if the constant */
+ /* value is not in the column distinct values list. */
+ /*********************************************************************/
+ if (found) {
+ Bmp = 1 << i; // Bit of the found value
+ Bxp = Bmp - 1; // All smaller values
+
+ if (Opc != OP_LT && Opc != OP_GE)
+ Bxp |= Bmp; // Found value must be included
+
+ } else {
+ Bmp = 0;
+ Bxp = (1 << i) - 1;
+ } // endif found
+
+ if (!(Opc == OP_EQ || Opc == OP_NE))
+ Bmp = Bxp;
+
+ } // end of MakeValueBitmap
+
+/***********************************************************************/
+/* Evaluate XDB2 block filter for arithmetic operators. */
+/***********************************************************************/
+int BLKFILAR2::BlockEval(PGLOBAL)
+ {
+#if defined(_DEBUG)
+ assert (Colp->IsClustered());
+#endif
+
+ int n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
+ uint bkmp = *(uint*)Colp->GetBmap()->GetValPtr(n);
+ uint bres = Bmp & bkmp;
+
+ // Set result as if Opc were OP_EQ, OP_LT, or OP_LE
+ if (!bres) {
+ if (!Bmp)
+ Result = -2; // No good block in the table file
+ else if (!Sorted)
+ Result = -1; // No good values in this block
+ else // Sorted column, test for no more good blocks in file
+ Result = (Bxp & bkmp) ? -1 : -2;
+
+ } else
+ // Test whether all block values are good or only some ones
+ Result = (bres == bkmp) ? 1 : 0;
+
+ // For OP_NE, OP_GE, and OP_GT the result must be inverted.
+ switch (Opc) {
+ case OP_NE:
+ case OP_GE:
+ case OP_GT:
+ Result = -Result;
+ break;
+ } // endswitch Opc
+
+ if (trace(1))
+ htrc("BlockEval2: op=%d n=%d rc=%d\n", Opc, n, Result);
+
+ return Result;
+ } // end of BlockEval
+
+/* ---------------------- Class BLKFILMR2----------------------------- */
+
+/***********************************************************************/
+/* BLKFILMR2 constructor. */
+/***********************************************************************/
+BLKFILMR2::BLKFILMR2(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp)
+ : BLKFILARI(g, tdbp, op, xp)
+ {
+ Nbm = Colp->GetNbm();
+ Bmp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
+ Bxp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
+ MakeValueBitmap();
+ } // end of BLKFILMR2 constructor
+
+/***********************************************************************/
+/* MakeValueBitmap: Set the constant value bit map. It can be void */
+/* if the constant value is not in the column distinct values list. */
+/***********************************************************************/
+void BLKFILMR2::MakeValueBitmap(void)
+ {
+ int i; // ndv = Colp->GetNdv();
+ bool found = FALSE, noteq = !(Opc == OP_EQ || Opc == OP_NE);
+ PVBLK dval = Colp->GetDval();
+
+ assert(dval);
+
+ for (i = 0; i < Nbm; i++)
+ Bmp[i] = Bxp[i] = 0;
+
+ /*********************************************************************/
+ /* Here we cannot use Find because we must get the index */
+ /* of where to put the value if it is not found in the array. */
+ /* This is needed by operators other than OP_EQ or OP_NE. */
+ /*********************************************************************/
+ found = dval->Locate(Valp, i);
+
+ /*********************************************************************/
+ /* For bitmaps larger than a ULONG, we must know where Bmp and Bxp */
+ /* are positioned in the ULONG bit map block array. */
+ /*********************************************************************/
+ N = i / MAXBMP;
+ i %= MAXBMP;
+
+ /*********************************************************************/
+ /* Set the constant value bitmaps. The bitmaps are really matching */
+ /* the OP_EQ, OP_LE, and OP_LT operator but are also used for the */
+ /* other operators for which the Result will be inverted. */
+ /* The reason the bitmaps are not directly complemented for them is */
+ /* to be able to easily test the cases of sorted columns with Bxp, */
+ /* and the case of a void bitmap, which happens if the constant */
+ /* value is not in the column distinct values list. */
+ /*********************************************************************/
+ if (found) {
+ Bmp[N] = 1 << i;
+ Bxp[N] = Bmp[N] - 1;
+
+ if (Opc != OP_LT && Opc != OP_GE)
+ Bxp[N] |= Bmp[N]; // Found value must be included
+
+ } else
+ Bxp[N] = (1 << i) - 1;
+
+ if (noteq)
+ Bmp[N] = Bxp[N];
+
+ Void = !Bmp[N]; // There are no good values in the file
+
+ for (i = 0; i < N; i++) {
+ Bxp[i] = ~0;
+
+ if (noteq)
+ Bmp[i] = Bxp[i];
+
+ Void = Void && !Bmp[i];
+ } // endfor i
+
+ if (!Bmp[N] && !Bxp[N])
+ N--;
+
+ } // end of MakeValueBitmap
+
+/***********************************************************************/
+/* Evaluate XDB2 block filter for arithmetic operators. */
+/***********************************************************************/
+int BLKFILMR2::BlockEval(PGLOBAL)
+ {
+#if defined(_DEBUG)
+ assert (Colp->IsClustered());
+#endif
+
+ int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
+ bool fnd = FALSE, all = TRUE, gt = TRUE;
+ uint bres;
+ uint *bkmp = (uint*)Colp->GetBmap()->GetValPtr(n * Nbm);
+
+ // Set result as if Opc were OP_EQ, OP_LT, or OP_LE
+ for (i = 0; i < Nbm; i++)
+ if (i <= N) {
+ if ((bres = Bmp[i] & bkmp[i]))
+ fnd = TRUE; // Some good value(s) found in the block
+
+ if (bres != bkmp[i])
+ all = FALSE; // Not all block values are good
+
+ if (Bxp[i] & bkmp[i])
+ gt = FALSE; // Not all block values are > good value(s)
+
+ } else if (bkmp[i]) {
+ all = FALSE;
+ break;
+ } // endif's
+
+ if (!fnd) {
+ if (Void || (gt && Sorted))
+ Result = -2; // No (more) good block in file
+ else
+ Result = -1; // No good values in this block
+
+ } else
+ Result = (all) ? 1 : 0; // All block values are good
+
+ // For OP_NE, OP_GE, and OP_GT the result must be inverted.
+ switch (Opc) {
+ case OP_NE:
+ case OP_GE:
+ case OP_GT:
+ Result = -Result;
+ break;
+ } // endswitch Opc
+
+ if (trace(1))
+ htrc("BlockEval2: op=%d n=%d rc=%d\n", Opc, n, Result);
+
+ return Result;
+ } // end of BlockEval
+
+/***********************************************************************/
+/* BLKSPCARI constructor. */
+/***********************************************************************/
+BLKSPCARI::BLKSPCARI(PTDBDOS tdbp, int op, PXOB *xp, int bsize)
+ : BLOCKFILTER(tdbp, op)
+ {
+ if (xp[1]->GetType() == TYPE_COLBLK) {
+ Cpx = (PCOL)xp[1]; // Subquery pseudo constant column
+ Correl = TRUE;
+ } else
+ Cpx = NULL;
+
+ Valp = xp[1]->GetValue();
+ Val = (int)xp[1]->GetValue()->GetIntValue();
+ Bsize = bsize;
+ } // end of BLKFILARI constructor
+
+/***********************************************************************/
+/* Reset: re-eval the constant value in the case of pseudo constant */
+/* column use in a correlated subquery. */
+/***********************************************************************/
+void BLKSPCARI::Reset(PGLOBAL g)
+ {
+ if (Cpx) {
+ Cpx->Reset();
+ Cpx->Eval(g);
+ Val = (int)Valp->GetIntValue();
+ } // endif Cpx
+
+ } // end of Reset
+
+/***********************************************************************/
+/* Evaluate block filter for arithmetic operators (ROWID) */
+/***********************************************************************/
+int BLKSPCARI::BlockEval(PGLOBAL)
+ {
+ int mincmp, maxcmp, n, m;
+
+ n = Tdbp->GetCurBlk();
+ m = n * Bsize + 1; // Minimum Rowid value for this block
+ mincmp = (Val > m) ? 1 : (Val < m) ? (-1) : 0;
+ m = (n + 1) * Bsize; // Maximum Rowid value for this block
+ maxcmp = (Val > m) ? 1 : (Val < m) ? (-1) : 0;
+
+ switch (Opc) {
+ case OP_EQ:
+ case OP_NE:
+ if (mincmp < 0) // Means minval > Val
+ Result = -2; // Always sorted
+ else if (maxcmp > 0) // Means maxval < Val
+ Result = -1;
+ else if (!mincmp && !maxcmp) // minval = maxval = val
+ Result = 1;
+ else
+ Result = 0;
+
+ break;
+ case OP_GT:
+ case OP_LE:
+ if (mincmp < 0) // minval > Val
+ Result = 2; // Always sorted
+ else if (maxcmp < 0) // maxval > Val
+ Result = 0;
+ else // maxval <= Val
+ Result = -1;
+
+ break;
+ case OP_GE:
+ case OP_LT:
+ if (mincmp <= 0) // minval >= Val
+ Result = 2; // Always sorted
+ else if (maxcmp <= 0) // Maxval >= Val
+ Result = 0;
+ else // Maxval < Val
+ Result = -1;
+
+ break;
+ } // endswitch Opc
+
+ switch (Opc) {
+ case OP_NE:
+ case OP_LE:
+ case OP_LT:
+ Result = -Result;
+ break;
+ } // endswitch Opc
+
+ if (trace(1))
+ htrc("BlockEval: op=%d n=%d rc=%d\n", Opc, n, Result);
+
+ return Result;
+ } // end of BlockEval
+
+/* ------------------------ Class BLKFILIN --------------------------- */
+
+/***********************************************************************/
+/* BLKFILIN constructor. */
+/***********************************************************************/
+BLKFILIN::BLKFILIN(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
+ : BLOCKFILTER(tdbp, op)
+ {
+ if (op == OP_IN) {
+ Opc = OP_EQ;
+ Opm = 1;
+ } else {
+ Opc = op;
+ Opm = opm;
+ } // endif op
+
+ Colp = (PDOSCOL)xp[0];
+ Arap = (PARRAY)xp[1];
+ Type = Arap->GetResultType();
+
+ if (Colp->GetResultType() != Type) {
+ sprintf(g->Message, "BLKFILIN: %s", MSG(VALTYPE_NOMATCH));
+ throw g->Message;
+ } else if (Colp->GetValue()->IsCi())
+ Arap->SetPrecision(g, 1); // Case insensitive
+
+ Sorted = Colp->IsSorted() > 0;
+ } // end of BLKFILIN constructor
+
+/***********************************************************************/
+/* Reset: have the sorted array reset its Bot value to -1 (bottom). */
+/***********************************************************************/
+void BLKFILIN::Reset(PGLOBAL)
+ {
+ Arap->Reset();
+// MakeValueBitmap(); // Does nothing for class BLKFILIN
+ } // end of Reset
+
+/***********************************************************************/
+/* Evaluate block filter for a IN operator on a constant array. */
+/* Note: here we need to use the GetValPtrEx function to get a zero */
+/* ended string in case of string argument. This is because the ARRAY */
+/* can have a different width than the char column. */
+/***********************************************************************/
+int BLKFILIN::BlockEval(PGLOBAL g)
+ {
+ int n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
+ void *minp = Colp->GetMin()->GetValPtrEx(n);
+ void *maxp = Colp->GetMax()->GetValPtrEx(n);
+
+ Result = Arap->BlockTest(g, Opc, Opm, minp, maxp, Sorted);
+ return Result;
+ } // end of BlockEval
+
+/* ------------------------ Class BLKFILIN2 -------------------------- */
+
+/***********************************************************************/
+/* BLKFILIN2 constructor. */
+/* New version that takes care of all operators and modificators. */
+/* It is also ready to handle the case of correlated sub-selects. */
+/***********************************************************************/
+BLKFILIN2::BLKFILIN2(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
+ : BLKFILIN(g, tdbp, op, opm, xp)
+ {
+ Nbm = Colp->GetNbm();
+ Valp = AllocateValue(g, Colp->GetValue());
+ Invert = (Opc == OP_NE || Opc == OP_GE || Opc ==OP_GT);
+ Bmp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
+ Bxp = (uint*)PlugSubAlloc(g, NULL, Nbm * sizeof(uint));
+ MakeValueBitmap();
+ } // end of BLKFILIN2 constructor
+
+/***********************************************************************/
+/* MakeValueBitmap: Set the constant values bit map. It can be void */
+/* if the constant values are not in the column distinct values list. */
+/* The bitmaps are prepared for the EQ, LE, and LT operators and */
+/* takes care of the ALL and ANY modificators. If the operators are */
+/* NE, GE, or GT the modificator is inverted and the result will be. */
+/***********************************************************************/
+void BLKFILIN2::MakeValueBitmap(void)
+ {
+ int i, k, n, ndv = Colp->GetNdv();
+ bool found, noteq = !(Opc == OP_EQ || Opc == OP_NE);
+ bool all = (!Invert) ? (Opm == 2) : (Opm != 2);
+ uint btp;
+ PVBLK dval = Colp->GetDval();
+
+ N = -1;
+
+ // Take care of special cases
+ if (!(n = Arap->GetNval())) {
+ // Return TRUE for ALL because it means that there are no item that
+ // does not verify the condition, which is true indeed.
+ // Return FALSE for ANY because TRUE means that there is at least
+ // one item that verifies the condition, which is false.
+ Result = (Opm == 2) ? 2 : -2;
+ return;
+ } else if (!noteq && all && n > 1) {
+ // An item cannot be equal to all different values
+ // or an item is always unequal to any different values
+ Result = (Opc == OP_EQ) ? -2 : 2;
+ return;
+ } // endif's
+
+ for (i = 0; i < Nbm; i++)
+ Bmp[i] = Bxp[i] = 0;
+
+ for (k = 0; k < n; k++) {
+ Arap->GetNthValue(Valp, k);
+ found = dval->Locate(Valp, i);
+ N = i / MAXBMP;
+ btp = 1 << (i % MAXBMP);
+
+ if (found)
+ Bmp[N] |= btp;
+
+ // For LT and LE if ALL the condition applies to the smallest item
+ // if ANY it applies to the largest item. In the case of EQ we come
+ // here only if ANY or if n == 1, so it does applies to the largest.
+ if ((!k && all) || (k == n - 1 && !all)) {
+ Bxp[N] = btp - 1;
+
+ if (found && Opc != OP_LT && Opc != OP_GE)
+ Bxp[N] |= btp; // Found value must be included
+
+ } // endif k, opm
+
+ } // endfor k
+
+ if (noteq)
+ Bmp[N] = Bxp[N];
+
+ Void = !Bmp[N]; // There are no good values in the file
+
+ for (i = 0; i < N; i++) {
+ Bxp[i] = ~0;
+
+ if (noteq) {
+ Bmp[i] = Bxp[i];
+ Void = FALSE;
+ } // endif noteq
+
+ } // endfor i
+
+ if (!Bmp[N] && !Bxp[N]) {
+ if (--N < 0)
+ // All array values are smaller than block values
+ Result = (Invert) ? 2 : -2;
+
+ } else if (N == Nbm - 1 && (signed)Bmp[N] == (1 << (ndv % MAXBMP)) - 1) {
+ // Condition will be always TRUE or FALSE for the whole file
+ Result = (Invert) ? -2 : 2;
+ N = -1;
+ } // endif's
+
+ } // end of MakeValueBitmap
+
+/***********************************************************************/
+/* Evaluate block filter for set operators on a constant array. */
+/* Note: here we need to use the GetValPtrEx function to get a zero */
+/* ended string in case of string argument. This is because the ARRAY */
+/* can have a different width than the char column. */
+/***********************************************************************/
+int BLKFILIN2::BlockEval(PGLOBAL)
+ {
+ if (N < 0)
+ return Result; // Was set in MakeValueBitmap
+
+ int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
+ bool fnd = FALSE, all = TRUE, gt = TRUE;
+ uint bres;
+ uint *bkmp = (uint*)Colp->GetBmap()->GetValPtr(n * Nbm);
+
+ // Set result as if Opc were OP_EQ, OP_LT, or OP_LE
+ // The difference between ALL or ANY was handled in MakeValueBitmap
+ for (i = 0; i < Nbm; i++)
+ if (i <= N) {
+ if ((bres = Bmp[i] & bkmp[i]))
+ fnd = TRUE;
+
+ if (bres != bkmp[i])
+ all = FALSE;
+
+ if (Bxp[i] & bkmp[i])
+ gt = FALSE;
+
+ } else if (bkmp[i]) {
+ all = FALSE;
+ break;
+ } // endif's
+
+ if (!fnd) {
+ if (Void || (Sorted && gt))
+ Result = -2; // No more good block in file
+ else
+ Result = -1; // No good values in this block
+
+ } else if (all)
+ Result = 1; // All block values are good
+ else
+ Result = 0; // Block contains some good values
+
+ // For OP_NE, OP_GE, and OP_GT the result must be inverted.
+ switch (Opc) {
+ case OP_NE:
+ case OP_GE:
+ case OP_GT:
+ Result = -Result;
+ break;
+ } // endswitch Opc
+
+ return Result;
+ } // end of BlockEval
+
+#if 0
+/***********************************************************************/
+/* BLKFILIN2 constructor. */
+/***********************************************************************/
+BLKFILIN2::BLKFILIN2(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp)
+ : BLKFILIN(g, tdbp, op, opm, xp)
+ {
+ // Currently, bitmap matching is only implemented for the IN operator
+ if (!(Bitmap = (op == OP_IN || (op == OP_EQ && opm != 2)))) {
+ Nbm = Colp->GetNbm();
+ N = 0;
+ return; // Revert to standard minmax method
+ } // endif minmax
+
+ int i, n;
+ ULONG btp;
+ PVAL valp = AllocateValue(g, Colp->GetValue());
+ PVBLK dval = Colp->GetDval();
+
+ Nbm = Colp->GetNbm();
+ N = -1;
+ Bmp = (PULONG)PlugSubAlloc(g, NULL, Nbm * sizeof(ULONG));
+ Bxp = (PULONG)PlugSubAlloc(g, NULL, Nbm * sizeof(ULONG));
+
+ for (i = 0; i < Nbm; i++)
+ Bmp[i] = Bxp[i] = 0;
+
+ for (n = 0; n < Arap->GetNval(); n++) {
+ Arap->GetNthValue(valp, n);
+
+ if ((i = dval->Find(valp)) >= 0)
+ Bmp[i / MAXBMP] |= 1 << (i % MAXBMP);
+
+ } // endfor n
+
+ for (i = Nbm - 1; i >= 0; i--)
+ if (Bmp[i]) {
+ for (btp = Bmp[i]; btp; btp >>= 1)
+ Bxp[i] |= btp;
+
+ for (N = i--; i >= 0; i--)
+ Bxp[i] = ~0;
+
+ break;
+ } // endif Bmp
+
+ } // end of BLKFILIN2 constructor
+
+/***********************************************************************/
+/* Evaluate block filter for a IN operator on a constant array. */
+/* Note: here we need to use the GetValPtrEx function to get a zero */
+/* ended string in case of string argument. This is because the ARRAY */
+/* can have a different width than the char column. */
+/***********************************************************************/
+int BLKFILIN2::BlockEval(PGLOBAL g)
+ {
+ if (N < 0)
+ return -2; // IN list contains no good values
+
+ int i, n = ((PTDBDOS)Colp->GetTo_Tdb())->GetCurBlk();
+ bool fnd = FALSE, all = TRUE, gt = TRUE;
+ ULONG bres;
+ PULONG bkmp = (PULONG)Colp->GetBmap()->GetValPtr(n * Nbm);
+
+ if (Bitmap) {
+ // For IN operator use the bitmap method
+ for (i = 0; i < Nbm; i++)
+ if (i <= N) {
+ if ((bres = Bmp[i] & bkmp[i]))
+ fnd = TRUE;
+
+ if (bres != bkmp[i])
+ all = FALSE;
+
+ if (Bxp[i] & bkmp[i])
+ gt = FALSE;
+
+ } else if (bkmp[i]) {
+ all = FALSE;
+ break;
+ } // endif's
+
+ if (!fnd) {
+ if (Sorted && gt)
+ Result = -2; // No more good block in file
+ else
+ Result = -1; // No good values in this block
+
+ } else if (all)
+ Result = 1; // All block values are good
+ else
+ Result = 0; // Block contains some good values
+
+ } else {
+ // For other than IN operators, revert to standard minmax method
+ int n = 0, ndv = Colp->GetNdv();
+ void *minp = NULL;
+ void *maxp = NULL;
+ ULONG btp;
+ PVBLK dval = Colp->GetDval();
+
+ for (i = 0; i < Nbm; i++)
+ for (btp = 1; btp && n < ndv; btp <<= 1, n++)
+ if (btp & bkmp[i]) {
+ if (!minp)
+ minp = dval->GetValPtrEx(n);
+
+ maxp = dval->GetValPtrEx(n);
+ } // endif btp
+
+ Result = Arap->BlockTest(g, Opc, Opm, minp, maxp, Colp->IsSorted());
+ } // endif Bitmap
+
+ return Result;
+ } // end of BlockEval
+#endif // 0
+
+/* ------------------------ Class BLKSPCIN --------------------------- */
+
+/***********************************************************************/
+/* BLKSPCIN constructor. */
+/***********************************************************************/
+BLKSPCIN::BLKSPCIN(PGLOBAL, PTDBDOS tdbp, int op, int opm,
+ PXOB *xp, int bsize)
+ : BLOCKFILTER(tdbp, op)
+ {
+ if (op == OP_IN) {
+ Opc = OP_EQ;
+ Opm = 1;
+ } else
+ Opm = opm;
+
+ Arap = (PARRAY)xp[1];
+#if defined(_DEBUG)
+ assert (Opm);
+ assert (Arap->GetResultType() == TYPE_INT);
+#endif
+ Bsize = bsize;
+ } // end of BLKSPCIN constructor
+
+/***********************************************************************/
+/* Reset: have the sorted array reset its Bot value to -1 (bottom). */
+/***********************************************************************/
+void BLKSPCIN::Reset(PGLOBAL)
+ {
+ Arap->Reset();
+ } // end of Reset
+
+/***********************************************************************/
+/* Evaluate block filter for a IN operator on a constant array. */
+/***********************************************************************/
+int BLKSPCIN::BlockEval(PGLOBAL g)
+ {
+ int n = Tdbp->GetCurBlk();
+ int minrow = n * Bsize + 1; // Minimum Rowid value for this block
+ int maxrow = (n + 1) * Bsize; // Maximum Rowid value for this block
+
+ Result = Arap->BlockTest(g, Opc, Opm, &minrow, &maxrow, TRUE);
+ return Result;
+ } // end of BlockEval
+
+/* ------------------------------------------------------------------- */
+
+#if 0
+/***********************************************************************/
+/* Implementation of the BLOCKINDEX class. */
+/***********************************************************************/
+BLOCKINDEX::BLOCKINDEX(PBX nx, PDOSCOL cp, PKXBASE kp)
+ {
+ Next = nx;
+ Tdbp = (cp) ? (PTDBDOS)cp->GetTo_Tdb() : NULL;
+ Colp = cp;
+ Kxp = kp;
+ Type = (cp) ? cp->GetResultType() : TYPE_ERROR;
+ Sorted = (cp) ? cp->IsSorted() > 0 : FALSE;
+ Result = 0;
+ } // end of BLOCKINDEX constructor
+
+/***********************************************************************/
+/* Reset Bot and Top values of optimized Kindex blocks. */
+/***********************************************************************/
+void BLOCKINDEX::Reset(void)
+ {
+ if (Next)
+ Next->Reset();
+
+ Kxp->Reset();
+ } // end of Reset
+
+/***********************************************************************/
+/* Evaluate block indexing test. */
+/***********************************************************************/
+int BLOCKINDEX::BlockEval(PGLOBAL g)
+ {
+#if defined(_DEBUG)
+ assert (Tdbp && Colp);
+#endif
+ int n = Tdbp->GetCurBlk();
+ void *minp = Colp->GetMin()->GetValPtr(n);
+ void *maxp = Colp->GetMax()->GetValPtr(n);
+
+ Result = Kxp->BlockTest(g, minp, maxp, Type, Sorted);
+ return Result;
+ } // end of BlockEval
+
+/***********************************************************************/
+/* Make file output of BLOCKINDEX contents. */
+/***********************************************************************/
+void BLOCKINDEX::Printf(PGLOBAL g, FILE *f, UINT n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+
+ fprintf(f, "%sBLOCKINDEX: at %p next=%p col=%s kxp=%p result=%d\n",
+ m, this, Next, (Colp) ? Colp->GetName() : "Rowid", Kxp, Result);
+
+ if (Next)
+ Next->Printf(g, f, n);
+
+ } // end of Printf
+
+/***********************************************************************/
+/* Make string output of BLOCKINDEX contents. */
+/***********************************************************************/
+void BLOCKINDEX::Prints(PGLOBAL g, char *ps, UINT z)
+ {
+ strncat(ps, "BlockIndex(es)", z);
+ } // end of Prints
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the BLOCKINDX2 class. */
+/***********************************************************************/
+BLOCKINDX2::BLOCKINDX2(PBX nx, PDOSCOL cp, PKXBASE kp)
+ : BLOCKINDEX(nx, cp, kp)
+ {
+ Nbm = Colp->GetNbm();
+ Dval = Colp->GetDval();
+ Bmap = Colp->GetBmap();
+#if defined(_DEBUG)
+ assert(Dval && Bmap);
+#endif
+ } // end of BLOCKINDX2 constructor
+
+/***********************************************************************/
+/* Evaluate block indexing test. */
+/***********************************************************************/
+int BLOCKINDX2::BlockEval(PGLOBAL g)
+ {
+ int n = Tdbp->GetCurBlk();
+ PUINT bmp = (PUINT)Bmap->GetValPtr(n * Nbm);
+
+ Result = Kxp->BlockTst2(g, Dval, bmp, Nbm, Type, Sorted);
+ return Result;
+ } // end of BlockEval
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the BLKSPCINDX class. */
+/***********************************************************************/
+BLKSPCINDX::BLKSPCINDX(PBX nx, PTDBDOS tp, PKXBASE kp, int bsize)
+ : BLOCKINDEX(nx, NULL, kp)
+ {
+ Tdbp = tp;
+ Bsize = bsize;
+ Type = TYPE_INT;
+ Sorted = TRUE;
+ } // end of BLKSPCINDX constructor
+
+/***********************************************************************/
+/* Evaluate block indexing test. */
+/***********************************************************************/
+int BLKSPCINDX::BlockEval(PGLOBAL g)
+ {
+ int n = Tdbp->GetCurBlk();
+ int minrow = n * Bsize + 1; // Minimum Rowid value for this block
+ int maxrow = (n + 1) * Bsize; // Maximum Rowid value for this block
+
+ Result = Kxp->BlockTest(g, &minrow, &maxrow, TYPE_INT, TRUE);
+ return Result;
+ } // end of BlockEval
+#endif // 0
diff --git a/storage/connect/blkfil.h b/storage/connect/blkfil.h
new file mode 100644
index 00000000..61b02c53
--- /dev/null
+++ b/storage/connect/blkfil.h
@@ -0,0 +1,295 @@
+/*************** BlkFil H Declares Source Code File (.H) ***************/
+/* Name: BLKFIL.H Version 2.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2004-2010 */
+/* */
+/* This file contains the block optimization related classes declares */
+/***********************************************************************/
+#ifndef __BLKFIL__
+#define __BLKFIL__
+
+typedef class BLOCKFILTER *PBF;
+typedef class BLOCKINDEX *PBX;
+
+/***********************************************************************/
+/* Definition of class BLOCKFILTER. */
+/***********************************************************************/
+class DllExport BLOCKFILTER : public BLOCK { /* Block Filter */
+ friend class BLKFILLOG;
+ public:
+ // Constructors
+ BLOCKFILTER(PTDBDOS tdbp, int op);
+
+ // Implementation
+ int GetResult(void) {return Result;}
+ bool Correlated(void) {return Correl;}
+
+ // Methods
+ virtual void Reset(PGLOBAL) = 0;
+ virtual int BlockEval(PGLOBAL) = 0;
+ virtual void Printf(PGLOBAL g, FILE *f, uint n);
+ virtual void Prints(PGLOBAL g, char *ps, uint z);
+
+ protected:
+ BLOCKFILTER(void) {} // Standard constructor not to be used
+
+ // Members
+ PTDBDOS Tdbp; // Owner TDB
+ bool Correl; // TRUE for correlated subqueries
+ int Opc; // Comparison operator
+ int Opm; // Operator modificator
+ int Result; // Result from evaluation
+ }; // end of class BLOCKFILTER
+
+/***********************************************************************/
+/* Definition of class BLKFILLOG (with Op=OP_AND,OP_OR, or OP_NOT) */
+/***********************************************************************/
+class DllExport BLKFILLOG : public BLOCKFILTER { /* Logical Op Block Filter */
+ public:
+ // Constructors
+ BLKFILLOG(PTDBDOS tdbp, int op, PBF *bfp, int n);
+
+ // Methods
+ virtual void Reset(PGLOBAL g);
+ virtual int BlockEval(PGLOBAL g);
+
+ protected:
+ BLKFILLOG(void) {} // Standard constructor not to be used
+
+ // Members
+ PBF *Fil; // Points to Block filter args
+ int N;
+ }; // end of class BLKFILLOG
+
+/***********************************************************************/
+/* Definition of class BLKFILARI (with Op=OP_EQ,NE,GT,GE,LT, or LE) */
+/***********************************************************************/
+class DllExport BLKFILARI : public BLOCKFILTER { /* Arithm. Op Block Filter */
+ public:
+ // Constructors
+ BLKFILARI(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp);
+
+ // Methods
+ virtual void Reset(PGLOBAL g);
+ virtual int BlockEval(PGLOBAL g);
+ virtual void MakeValueBitmap(void) {}
+
+ protected:
+ BLKFILARI(void) {} // Standard constructor not to be used
+
+ // Members
+ PDOSCOL Colp; // Points to column argument
+ PCOL Cpx; // Point to subquery "constant" column
+ PVAL Valp; // Points to constant argument Value
+ bool Sorted; // True if the column is sorted
+ }; // end of class BLKFILARI
+
+/***********************************************************************/
+/* Definition of class BLKFILAR2 (with Op=OP_EQ,NE,GT,GE,LT, or LE) */
+/***********************************************************************/
+class DllExport BLKFILAR2 : public BLKFILARI { /* Arithm. Op Block Filter */
+ public:
+ // Constructors
+ BLKFILAR2(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp);
+
+ // Methods
+ virtual int BlockEval(PGLOBAL g);
+ virtual void MakeValueBitmap(void);
+
+ protected:
+ BLKFILAR2(void) {} // Standard constructor not to be used
+
+ // Members
+ uint Bmp; // The value bitmap used to test blocks
+ uint Bxp; // Bitmap used when Opc = OP_EQ
+ }; // end of class BLKFILAR2
+
+/***********************************************************************/
+/* Definition of class BLKFILAR2 (with Op=OP_EQ,NE,GT,GE,LT, or LE) */
+/* To be used when the bitmap is an array of ULONG bitmaps; */
+/***********************************************************************/
+class DllExport BLKFILMR2 : public BLKFILARI { /* Arithm. Op Block Filter */
+ public:
+ // Constructors
+ BLKFILMR2(PGLOBAL g, PTDBDOS tdbp, int op, PXOB *xp);
+
+ // Methods
+ virtual int BlockEval(PGLOBAL g);
+ virtual void MakeValueBitmap(void);
+
+ protected:
+ BLKFILMR2(void) {} // Standard constructor not to be used
+
+ // Members
+ int Nbm; // The number of ULONG bitmaps
+ int N; // The position of the leftmost ULONG
+ bool Void; // True if all file blocks can be skipped
+ uint *Bmp; // The values bitmaps used to test blocks
+ uint *Bxp; // Bit of values <= max value
+ }; // end of class BLKFILMR2
+
+/***********************************************************************/
+/* Definition of class BLKSPCARI (with Op=OP_EQ,NE,GT,GE,LT, or LE) */
+/***********************************************************************/
+class DllExport BLKSPCARI : public BLOCKFILTER { /* Arithm. Op Block Filter */
+ public:
+ // Constructors
+ BLKSPCARI(PTDBDOS tdbp, int op, PXOB *xp, int bsize);
+
+ // Methods
+ virtual void Reset(PGLOBAL g);
+ virtual int BlockEval(PGLOBAL g);
+
+ protected:
+ BLKSPCARI(void) {} // Standard constructor not to be used
+
+ // Members
+ PCOL Cpx; // Point to subquery "constant" column
+ PVAL Valp; // Points to constant argument Value
+ int Val; // Constant argument Value
+ int Bsize; // Table block size
+ }; // end of class BLKSPCARI
+
+/***********************************************************************/
+/* Definition of class BLKFILIN (with Op=OP_IN) */
+/***********************************************************************/
+class DllExport BLKFILIN : public BLOCKFILTER { // With array arguments.
+ public:
+ // Constructors
+ BLKFILIN(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp);
+
+ // Methods
+ virtual void Reset(PGLOBAL g);
+ virtual int BlockEval(PGLOBAL g);
+ virtual void MakeValueBitmap(void) {}
+
+ protected:
+ // Member
+ PDOSCOL Colp; // Points to column argument
+ PARRAY Arap; // Points to array argument
+ bool Sorted; // True if the column is sorted
+ int Type; // Type of array elements
+ }; // end of class BLKFILIN
+
+/***********************************************************************/
+/* Definition of class BLKFILIN2 (with Op=OP_IN) */
+/***********************************************************************/
+class DllExport BLKFILIN2 : public BLKFILIN { // With array arguments.
+ public:
+ // Constructors
+ BLKFILIN2(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp);
+
+ // Methods
+//virtual void Reset(PGLOBAL g);
+ virtual int BlockEval(PGLOBAL g);
+ virtual void MakeValueBitmap(void);
+
+ protected:
+ // Member
+ int Nbm; // The number of ULONG bitmaps
+ int N; // The position of the leftmost ULONG
+//bool Bitmap; // True for IN operator (temporary)
+ bool Void; // True if all file blocks can be skipped
+ bool Invert; // True when Result must be inverted
+ uint *Bmp; // The values bitmaps used to test blocks
+ uint *Bxp; // Bit of values <= max value
+ PVAL Valp; // Used while building the bitmaps
+ }; // end of class BLKFILIN2
+
+/***********************************************************************/
+/* Definition of class BLKSPCIN (with Op=OP_IN) Special column */
+/***********************************************************************/
+class DllExport BLKSPCIN : public BLOCKFILTER { // With array arguments.
+ public:
+ // Constructors
+ BLKSPCIN(PGLOBAL g, PTDBDOS tdbp, int op, int opm, PXOB *xp, int bsize);
+
+ // Methods
+ virtual void Reset(PGLOBAL g);
+ virtual int BlockEval(PGLOBAL g);
+
+ protected:
+ // Member
+ PARRAY Arap; // Points to array argument
+ int Bsize; // Table block size
+ }; // end of class BLKSPCIN
+
+// ---------------- Class used in block indexing testing ----------------
+
+#if 0
+/***********************************************************************/
+/* Definition of class BLOCKINDEX. */
+/* Used to test the indexing to joined tables when the foreign key is */
+/* a clustered or sorted column. If the table is joined to several */
+/* tables, blocks will be chained together. */
+/***********************************************************************/
+class DllExport BLOCKINDEX : public BLOCK { /* Indexing Test Block */
+ public:
+ // Constructors
+ BLOCKINDEX(PBX nx, PDOSCOL cp, PKXBASE kp);
+
+ // Implementation
+ PBX GetNext(void) {return Next;}
+
+ // Methods
+ void Reset(void);
+ virtual int BlockEval(PGLOBAL);
+ virtual void Printf(PGLOBAL g, FILE *f, UINT n);
+ virtual void Prints(PGLOBAL g, char *ps, UINT z);
+
+ protected:
+ BLOCKINDEX(void) {} // Standard constructor not to be used
+
+ // Members
+ PBX Next; // To next Index Block
+ PTDBDOS Tdbp; // To table description block
+ PDOSCOL Colp; // Clustered foreign key
+ PKXBASE Kxp; // To Kindex of joined table
+ bool Sorted; // TRUE if column is sorted
+ int Type; // Col/Index type
+ int Result; // Result from evaluation
+ }; // end of class BLOCKINDEX
+
+/***********************************************************************/
+/* Definition of class BLOCKINDX2. (XDB2) */
+/***********************************************************************/
+class DllExport BLOCKINDX2 : public BLOCKINDEX { /* Indexing Test Block */
+ public:
+ // Constructors
+ BLOCKINDX2(PBX nx, PDOSCOL cp, PKXBASE kp);
+
+ // Methods
+ virtual int BlockEval(PGLOBAL);
+
+ protected:
+ BLOCKINDX2(void) {} // Standard constructor not to be used
+
+ // Members
+ int Nbm; // The number of ULONG bitmaps
+ PVBLK Dval; // Array of column distinct values
+ PVBLK Bmap; // Array of block bitmap values
+ }; // end of class BLOCKINDX2
+
+/***********************************************************************/
+/* Definition of class BLKSPCINDX. */
+/* Used to test the indexing to joined tables when the foreign key is */
+/* the ROWID special column. If the table is joined to several */
+/* tables, blocks will be chained together. */
+/***********************************************************************/
+class DllExport BLKSPCINDX : public BLOCKINDEX { /* Indexing Test Block */
+ public:
+ // Constructors
+ BLKSPCINDX(PBX nx, PTDBDOS tp, PKXBASE kp, int bsize);
+
+ // Methods
+ virtual int BlockEval(PGLOBAL);
+
+ protected:
+ BLKSPCINDX(void) {} // Standard constructor not to be used
+
+ // Members
+ int Bsize; // Table block size
+ }; // end of class BLOCKINDEX
+#endif // 0
+
+#endif // __BLKFIL__
diff --git a/storage/connect/block.h b/storage/connect/block.h
new file mode 100644
index 00000000..e8871277
--- /dev/null
+++ b/storage/connect/block.h
@@ -0,0 +1,61 @@
+/**************** Block H Declares Source Code File (.H) ***************/
+/* Name: BLOCK.H Version 2.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998 - 2020 */
+/* */
+/* This file contains the BLOCK pure virtual class definition. */
+/*---------------------------------------------------------------------*/
+/* Note: one of the main purpose of this base class is to take care */
+/* of the very specific way Connect handles memory allocation. */
+/* Instead of allocating small chunks of storage via new or malloc */
+/* Connect works in its private memory pool in which it does the sub- */
+/* allocation using the function PlugSubAlloc. These are never freed */
+/* separately but when a transaction is terminated, the entire pool */
+/* is set to empty, resulting in a very fast and efficient allocate */
+/* process, no garbage collection problem, and an automatic recovery */
+/* procedure (via throw) when the memory is exhausted. */
+/* For this to work new must be given two parameters, first the */
+/* global pointer of the Plug application, and an optional pointer to */
+/* the memory pool to use, defaulting to NULL meaning using the Plug */
+/* standard default memory pool, example: */
+/* tabp = new(g) XTAB("EMPLOYEE"); */
+/* allocates a XTAB class object in the standard Plug memory pool. */
+/***********************************************************************/
+#if !defined(BLOCK_DEFINED)
+#define BLOCK_DEFINED
+
+#if defined(_WIN32) && !defined(NOEX)
+#define DllExport __declspec( dllexport )
+#else // !_WIN32
+#define DllExport
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Definition of class BLOCK with its method function new. */
+/***********************************************************************/
+typedef class BLOCK *PBLOCK;
+
+class DllExport BLOCK {
+ public:
+ void *operator new(size_t size, PGLOBAL g, void *mp = NULL) {
+ xtrc(256, "New BLOCK: size=%d g=%p p=%p\n", size, g, mp);
+ return PlugSubAlloc(g, mp, size);
+ } // end of new
+
+ void* operator new(size_t size, long long mp) {
+ xtrc(256, "Realloc at: mp=%lld\n", mp);
+ return (void*)mp;
+ } // end of new
+
+ virtual void Printf(PGLOBAL, FILE *, uint) {} // Produce file desc
+ virtual void Prints(PGLOBAL, char *, uint) {} // Produce string desc
+
+ // Avoid gcc errors by defining matching dummy delete operators
+ void operator delete(void*, PGLOBAL, void *) {}
+ void operator delete(void*, long long) {}
+ void operator delete(void*) {}
+
+ virtual ~BLOCK() {}
+}; // end of class BLOCK
+
+#endif // !BLOCK_DEFINED
diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp
new file mode 100644
index 00000000..fa9cd5f1
--- /dev/null
+++ b/storage/connect/bson.cpp
@@ -0,0 +1,1795 @@
+/*************** bson CPP Declares Source Code File (.H) ***************/
+/* Name: bson.cpp Version 1.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2020 */
+/* */
+/* This file contains the BJSON classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* bson.h is header containing the BSON classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "bson.h"
+
+/***********************************************************************/
+/* Check macro. */
+/***********************************************************************/
+#if defined(_DEBUG)
+#define CheckType(X,Y) if (!X || X ->Type != Y) throw MSG(VALTYPE_NOMATCH);
+#else
+#define CheckType(X,Y)
+#endif
+
+#if defined(_WIN32)
+#define EL "\r\n"
+#else
+#define EL "\n"
+#undef SE_CATCH // Does not work for Linux
+#endif
+
+int GetJsonDefPrec(void);
+
+#if defined(SE_CATCH)
+/**************************************************************************/
+/* This is the support of catching C interrupts to prevent crashes. */
+/**************************************************************************/
+#include <eh.h>
+
+class SE_Exception {
+public:
+ SE_Exception(unsigned int n, PEXCEPTION_RECORD p) : nSE(n), eRec(p) {}
+ ~SE_Exception() {}
+
+ unsigned int nSE;
+ PEXCEPTION_RECORD eRec;
+}; // end of class SE_Exception
+
+void trans_func(unsigned int u, _EXCEPTION_POINTERS* pExp) {
+ throw SE_Exception(u, pExp->ExceptionRecord);
+} // end of trans_func
+
+char* GetExceptionDesc(PGLOBAL g, unsigned int e);
+#endif // SE_CATCH
+
+/* --------------------------- Class BDOC ---------------------------- */
+
+/***********************************************************************/
+/* BDOC constructor. */
+/***********************************************************************/
+BDOC::BDOC(PGLOBAL G) : BJSON(G, NULL)
+{
+ jp = NULL;
+ s = NULL;
+ len = 0;
+ pretty = 3;
+ pty[0] = pty[1] = pty[2] = true;
+ comma = false;
+} // end of BDOC constructor
+
+/***********************************************************************/
+/* Parse a json string. */
+/* Note: when pretty is not known, the caller set pretty to 3. */
+/***********************************************************************/
+PBVAL BDOC::ParseJson(PGLOBAL g, char* js, size_t lng)
+{
+ size_t i;
+ bool b = false;
+ PBVAL bvp = NULL;
+
+ s = js;
+ len = lng;
+ xtrc(1, "BDOC::ParseJson: s=%.10s len=%zd\n", s, len);
+
+ if (!s || !len) {
+ strcpy(g->Message, "Void JSON object");
+ return NULL;
+ } // endif s
+
+ // Trying to guess the pretty format
+ if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
+ pty[0] = false;
+
+ try {
+ bvp = NewVal();
+ bvp->Type = TYPE_UNKNOWN;
+
+ for (i = 0; i < len; i++)
+ switch (s[i]) {
+ case '[':
+ if (bvp->Type != TYPE_UNKNOWN)
+ bvp->To_Val = ParseAsArray(i);
+ else
+ bvp->To_Val = ParseArray(++i);
+
+ bvp->Type = TYPE_JAR;
+ break;
+ case '{':
+ if (bvp->Type != TYPE_UNKNOWN) {
+ bvp->To_Val = ParseAsArray(i);
+ bvp->Type = TYPE_JAR;
+ } else {
+ bvp->To_Val = ParseObject(++i);
+ bvp->Type = TYPE_JOB;
+ } // endif Type
+
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ case ',':
+ if (bvp->Type != TYPE_UNKNOWN && (pretty == 1 || pretty == 3)) {
+ comma = true;
+ pty[0] = pty[2] = false;
+ break;
+ } // endif pretty
+
+ sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
+ throw 3;
+ case '(':
+ b = true;
+ break;
+ case ')':
+ if (b) {
+ b = false;
+ break;
+ } // endif b
+ /* fall through */
+ default:
+ if (bvp->Type != TYPE_UNKNOWN) {
+ bvp->To_Val = ParseAsArray(i);
+ bvp->Type = TYPE_JAR;
+ } else if ((bvp->To_Val = MOF(ParseValue(i, NewVal()))))
+ bvp->Type = TYPE_JVAL;
+ else
+ throw 4;
+
+ break;
+ }; // endswitch s[i]
+
+ if (bvp->Type == TYPE_UNKNOWN)
+ sprintf(g->Message, "Invalid Json string '%.*s'", MY_MIN((int)len, 50), s);
+ else if (pretty == 3) {
+ for (i = 0; i < 3; i++)
+ if (pty[i]) {
+ pretty = i;
+ break;
+ } // endif pty
+
+ } // endif ptyp
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, G->Message);
+ GetMsg(g);
+ bvp = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ bvp = NULL;
+ } // end catch
+
+ return bvp;
+} // end of ParseJson
+
+/***********************************************************************/
+/* Parse several items as being in an array. */
+/***********************************************************************/
+OFFSET BDOC::ParseAsArray(size_t& i) {
+ if (pty[0] && (!pretty || pretty > 2)) {
+ OFFSET jsp;
+
+ if ((jsp = ParseArray((i = 0))) && pretty == 3)
+ pretty = (pty[0]) ? 0 : 3;
+
+ return jsp;
+ } else
+ strcpy(G->Message, "More than one item in file");
+
+ return 0;
+} // end of ParseAsArray
+
+/***********************************************************************/
+/* Parse a JSON Array. */
+/***********************************************************************/
+OFFSET BDOC::ParseArray(size_t& i)
+{
+ int level = 0;
+ bool b = (!i);
+ PBVAL vlp, firstvlp, lastvlp;
+
+ vlp = firstvlp = lastvlp = NULL;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case ',':
+ if (level < 2) {
+ sprintf(G->Message, "Unexpected ',' near %.*s", (int) ARGS);
+ throw 1;
+ } else
+ level = 1;
+
+ break;
+ case ']':
+ if (level == 1) {
+ sprintf(G->Message, "Unexpected ',]' near %.*s", (int) ARGS);
+ throw 1;
+ } // endif level
+
+ return MOF(firstvlp);
+ case '\n':
+ if (!b)
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ if (level == 2) {
+ sprintf(G->Message, "Unexpected value near %.*s", (int) ARGS);
+ throw 1;
+ } else if (lastvlp) {
+ vlp = ParseValue(i, NewVal());
+ lastvlp->Next = MOF(vlp);
+ lastvlp = vlp;
+ } else
+ firstvlp = lastvlp = ParseValue(i, NewVal());
+
+ level = (b) ? 1 : 2;
+ break;
+ }; // endswitch s[i]
+
+ if (b) {
+ // Case of Pretty == 0
+ return MOF(firstvlp);
+ } // endif b
+
+ throw ("Unexpected EOF in array");
+} // end of ParseArray
+
+/***********************************************************************/
+/* Parse a JSON Object. */
+/***********************************************************************/
+OFFSET BDOC::ParseObject(size_t& i)
+{
+ OFFSET key;
+ int level = 0;
+ PBPR bpp, firstbpp, lastbpp;
+
+ bpp = firstbpp = lastbpp = NULL;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '"':
+ if (level < 2) {
+ key = ParseString(++i);
+ bpp = NewPair(key);
+
+ if (lastbpp) {
+ lastbpp->Vlp.Next = MOF(bpp);
+ lastbpp = bpp;
+ } else
+ firstbpp = lastbpp = bpp;
+
+ level = 2;
+ } else {
+ sprintf(G->Message, "misplaced string near %.*s", (int) ARGS);
+ throw 2;
+ } // endif level
+
+ break;
+ case ':':
+ if (level == 2) {
+ ParseValue(++i, GetVlp(lastbpp));
+ level = 3;
+ } else {
+ sprintf(G->Message, "Unexpected ':' near %.*s", (int) ARGS);
+ throw 2;
+ } // endif level
+
+ break;
+ case ',':
+ if (level < 3) {
+ sprintf(G->Message, "Unexpected ',' near %.*s", (int) ARGS);
+ throw 2;
+ } else
+ level = 1;
+
+ break;
+ case '}':
+ if (!(level == 0 || level == 3)) {
+ sprintf(G->Message, "Unexpected '}' near %.*s", (int) ARGS);
+ throw 2;
+ } // endif level
+
+ return MOF(firstbpp);
+ case '\n':
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ sprintf(G->Message, "Unexpected character '%c' near %.*s",
+ s[i], (int) ARGS);
+ throw 2;
+ }; // endswitch s[i]
+
+ strcpy(G->Message, "Unexpected EOF in Object");
+ throw 2;
+} // end of ParseObject
+
+/***********************************************************************/
+/* Parse a JSON Value. */
+/***********************************************************************/
+PBVAL BDOC::ParseValue(size_t& i, PBVAL bvp)
+{
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '\n':
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ goto suite;
+ } // endswitch
+
+suite:
+ switch (s[i]) {
+ case '[':
+ bvp->To_Val = ParseArray(++i);
+ bvp->Type = TYPE_JAR;
+ break;
+ case '{':
+ bvp->To_Val = ParseObject(++i);
+ bvp->Type = TYPE_JOB;
+ break;
+ case '"':
+ bvp->To_Val = ParseString(++i);
+ bvp->Type = TYPE_STRG;
+ break;
+ case 't':
+ if (!strncmp(s + i, "true", 4)) {
+ bvp->B = true;
+ bvp->Type = TYPE_BOOL;
+ i += 3;
+ } else
+ goto err;
+
+ break;
+ case 'f':
+ if (!strncmp(s + i, "false", 5)) {
+ bvp->B = false;
+ bvp->Type = TYPE_BOOL;
+ i += 4;
+ } else
+ goto err;
+
+ break;
+ case 'n':
+ if (!strncmp(s + i, "null", 4)) {
+ bvp->Type = TYPE_NULL;
+ i += 3;
+ } else
+ goto err;
+
+ break;
+ case '-':
+ default:
+ if (s[i] == '-' || isdigit(s[i]))
+ ParseNumeric(i, bvp);
+ else
+ goto err;
+
+ }; // endswitch s[i]
+
+ return bvp;
+
+err:
+ sprintf(G->Message, "Unexpected character '%c' near %.*s", s[i], (int) ARGS);
+ throw 3;
+} // end of ParseValue
+
+/***********************************************************************/
+/* Unescape and parse a JSON string. */
+/***********************************************************************/
+OFFSET BDOC::ParseString(size_t& i)
+{
+ uchar* p;
+ int n = 0;
+
+ // Be sure of memory availability
+ if (((size_t)len + 1 - i) > ((PPOOLHEADER)G->Sarea)->FreeBlk)
+ throw("ParseString: Out of memory");
+
+ // The size to allocate is not known yet
+ p = (uchar*)BsonSubAlloc(0);
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '"':
+ p[n++] = 0;
+ BsonSubAlloc(n);
+ return MOF(p);
+ case '\\':
+ if (++i < len) {
+ if (s[i] == 'u') {
+ if (len - i > 5) {
+ // if (charset == utf8) {
+ char xs[5];
+ uint hex;
+
+ xs[0] = s[++i];
+ xs[1] = s[++i];
+ xs[2] = s[++i];
+ xs[3] = s[++i];
+ xs[4] = 0;
+ hex = strtoul(xs, NULL, 16);
+
+ if (hex < 0x80) {
+ p[n] = (uchar)hex;
+ } else if (hex < 0x800) {
+ p[n++] = (uchar)(0xC0 | (hex >> 6));
+ p[n] = (uchar)(0x80 | (hex & 0x3F));
+ } else if (hex < 0x10000) {
+ p[n++] = (uchar)(0xE0 | (hex >> 12));
+ p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
+ p[n] = (uchar)(0x80 | (hex & 0x3f));
+ } else
+ p[n] = '?';
+
+#if 0
+ } else {
+ char xs[3];
+ UINT hex;
+
+ i += 2;
+ xs[0] = s[++i];
+ xs[1] = s[++i];
+ xs[2] = 0;
+ hex = strtoul(xs, NULL, 16);
+ p[n] = (char)hex;
+ } // endif charset
+#endif // 0
+ } else
+ goto err;
+
+ } else switch (s[i]) {
+ case 't': p[n] = '\t'; break;
+ case 'n': p[n] = '\n'; break;
+ case 'r': p[n] = '\r'; break;
+ case 'b': p[n] = '\b'; break;
+ case 'f': p[n] = '\f'; break;
+ default: p[n] = s[i]; break;
+ } // endswitch
+
+ n++;
+ } else
+ goto err;
+
+ break;
+ default:
+ p[n++] = s[i];
+ break;
+}; // endswitch s[i]
+
+err:
+throw("Unexpected EOF in String");
+} // end of ParseString
+
+/***********************************************************************/
+/* Parse a JSON numeric value. */
+/***********************************************************************/
+void BDOC::ParseNumeric(size_t& i, PBVAL vlp)
+{
+ char buf[50];
+ int n = 0;
+ short nd = 0;
+ bool has_dot = false;
+ bool has_e = false;
+ bool found_digit = false;
+
+ for (; i < len; i++) {
+ switch (s[i]) {
+ case '.':
+ if (!found_digit || has_dot || has_e)
+ goto err;
+
+ has_dot = true;
+ break;
+ case 'e':
+ case 'E':
+ if (!found_digit || has_e)
+ goto err;
+
+ has_e = true;
+ found_digit = false;
+ break;
+ case '+':
+ if (!has_e)
+ goto err;
+
+ // fall through
+ case '-':
+ if (found_digit)
+ goto err;
+
+ break;
+ default:
+ if (isdigit(s[i])) {
+ if (has_dot && !has_e)
+ nd++; // Number of decimals
+
+ found_digit = true;
+ } else
+ goto fin;
+
+ }; // endswitch s[i]
+
+ buf[n++] = s[i];
+ } // endfor i
+
+fin:
+ if (found_digit) {
+ buf[n] = 0;
+
+ if (has_dot || has_e) {
+ double dv = atof(buf);
+
+ if (nd >= 6 || dv > FLT_MAX || dv < FLT_MIN) {
+ double* dvp = (double*)PlugSubAlloc(G, NULL, sizeof(double));
+
+ *dvp = dv;
+ vlp->To_Val = MOF(dvp);
+ vlp->Type = TYPE_DBL;
+ } else {
+ vlp->F = (float)dv;
+ vlp->Type = TYPE_FLOAT;
+ } // endif nd
+
+ vlp->Nd = MY_MIN(nd, 16);
+ } else {
+ longlong iv = strtoll(buf, NULL, 10);
+
+ if (iv > INT_MAX32 || iv < INT_MIN32) {
+ longlong *llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong));
+
+ *llp = iv;
+ vlp->To_Val = MOF(llp);
+ vlp->Type = TYPE_BINT;
+ } else {
+ vlp->N = (int)iv;
+ vlp->Type = TYPE_INTG;
+ } // endif iv
+
+ } // endif has
+
+ i--; // Unstack following character
+ return;
+ } else
+ throw("No digit found");
+
+err:
+ throw("Unexpected EOF in number");
+} // end of ParseNumeric
+
+/***********************************************************************/
+/* Serialize a BJSON document tree: */
+/***********************************************************************/
+PSZ BDOC::Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty)
+{
+ PSZ str = NULL;
+ bool b = false, err = true;
+ FILE* fs = NULL;
+
+ G->Message[0] = 0;
+
+ try {
+ if (!bvp) {
+ strcpy(g->Message, "Null json tree");
+ throw 1;
+ } else if (!fn) {
+ // Serialize to a string
+ jp = new(g) JOUTSTR(g);
+ b = pretty == 1;
+ } else {
+ if (!(fs = fopen(fn, "wb"))) {
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "w", (int)errno, fn);
+ strcat(strcat(g->Message, ": "), strerror(errno));
+ throw 2;
+ } else if (pretty >= 2) {
+ // Serialize to a pretty file
+ jp = new(g)JOUTPRT(g, fs);
+ } else {
+ // Serialize to a flat file
+ b = true;
+ jp = new(g)JOUTFILE(g, fs, pretty);
+ } // endif's
+
+ } // endif's
+
+ switch (bvp->Type) {
+ case TYPE_JAR:
+ err = SerializeArray(bvp->To_Val, b);
+ break;
+ case TYPE_JOB:
+ err = ((b && jp->Prty()) && jp->WriteChr('\t'));
+ err |= SerializeObject(bvp->To_Val);
+ break;
+ case TYPE_JVAL:
+ err = SerializeValue(MVP(bvp->To_Val));
+ break;
+ default:
+ err = SerializeValue(bvp, true);
+ } // endswitch Type
+
+ if (fs) {
+ fputs(EL, fs);
+ fclose(fs);
+ str = (err) ? NULL : strcpy(g->Message, "Ok");
+ } else if (!err) {
+ str = ((JOUTSTR*)jp)->Strp;
+ jp->WriteChr('\0');
+ PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
+ } else if (G->Message[0])
+ strcpy(g->Message, "Error in Serialize");
+ else
+ GetMsg(g);
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, G->Message);
+ GetMsg(g);
+ str = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ str = NULL;
+ } // end catch
+
+ return str;
+} // end of Serialize
+
+
+/***********************************************************************/
+/* Serialize a JSON Array. */
+/***********************************************************************/
+bool BDOC::SerializeArray(OFFSET arp, bool b)
+{
+ bool first = true;
+ PBVAL vp = MVP(arp);
+
+ if (b) {
+ if (jp->Prty()) {
+ if (jp->WriteChr('['))
+ return true;
+ else if (jp->Prty() == 1 && (jp->WriteStr(EL) || jp->WriteChr('\t')))
+ return true;
+
+ } // endif Prty
+
+ } else if (jp->WriteChr('['))
+ return true;
+
+ for (; vp; vp = MVP(vp->Next)) {
+ if (first)
+ first = false;
+ else if ((!b || jp->Prty()) && jp->WriteChr(','))
+ return true;
+ else if (b) {
+ if (jp->Prty() < 2 && jp->WriteStr(EL))
+ return true;
+ else if (jp->Prty() == 1 && jp->WriteChr('\t'))
+ return true;
+
+ } // endif b
+
+ if (SerializeValue(vp))
+ return true;
+
+ } // endfor vp
+
+ if (b && jp->Prty() == 1 && jp->WriteStr(EL))
+ return true;
+
+ return ((!b || jp->Prty()) && jp->WriteChr(']'));
+} // end of SerializeArray
+
+/***********************************************************************/
+/* Serialize a JSON Object. */
+/***********************************************************************/
+bool BDOC::SerializeObject(OFFSET obp)
+{
+ bool first = true;
+ PBPR prp = MPP(obp);
+
+ if (jp->WriteChr('{'))
+ return true;
+
+ for (; prp; prp = GetNext(prp)) {
+ if (first)
+ first = false;
+ else if (jp->WriteChr(','))
+ return true;
+
+ if (jp->WriteChr('"') ||
+ jp->WriteStr(MZP(prp->Key)) ||
+ jp->WriteChr('"') ||
+ jp->WriteChr(':') ||
+ SerializeValue(GetVlp(prp)))
+ return true;
+
+ } // endfor i
+
+ return jp->WriteChr('}');
+} // end of SerializeObject
+
+/***********************************************************************/
+/* Serialize a JSON Value. */
+/***********************************************************************/
+bool BDOC::SerializeValue(PBVAL jvp, bool b)
+{
+ char buf[64];
+
+ if (jvp) switch (jvp->Type) {
+ case TYPE_JAR:
+ return SerializeArray(jvp->To_Val, false);
+ case TYPE_JOB:
+ return SerializeObject(jvp->To_Val);
+ case TYPE_BOOL:
+ return jp->WriteStr(jvp->B ? "true" : "false");
+ case TYPE_STRG:
+ case TYPE_DTM:
+ if (b) {
+ return jp->WriteStr(MZP(jvp->To_Val));
+ } else
+ return jp->Escape(MZP(jvp->To_Val));
+
+ case TYPE_INTG:
+ sprintf(buf, "%d", jvp->N);
+ return jp->WriteStr(buf);
+ case TYPE_BINT:
+ sprintf(buf, "%lld", *(longlong*)MakePtr(Base, jvp->To_Val));
+ return jp->WriteStr(buf);
+ case TYPE_FLOAT:
+ sprintf(buf, "%.*f", jvp->Nd, jvp->F);
+ return jp->WriteStr(buf);
+ case TYPE_DBL:
+ sprintf(buf, "%.*lf", jvp->Nd, *(double*)MakePtr(Base, jvp->To_Val));
+ return jp->WriteStr(buf);
+ case TYPE_NULL:
+ return jp->WriteStr("null");
+ case TYPE_JVAL:
+ return SerializeValue(MVP(jvp->To_Val));
+ default:
+ return jp->WriteStr("???"); // TODO
+ } // endswitch Type
+
+ return jp->WriteStr("null");
+} // end of SerializeValue
+
+/* --------------------------- Class BJSON --------------------------- */
+
+/***********************************************************************/
+/* Program for sub-allocating Bjson structures. */
+/***********************************************************************/
+void* BJSON::BsonSubAlloc(size_t size)
+{
+ PPOOLHEADER pph; /* Points on area header. */
+ void* memp = G->Sarea;
+
+ size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */
+ pph = (PPOOLHEADER)memp;
+
+ xtrc(16, "SubAlloc in %p size=%zd used=%zd free=%zd\n",
+ memp, size, pph->To_Free, pph->FreeBlk);
+
+ if (size > pph->FreeBlk) { /* Not enough memory left in pool */
+ sprintf(G->Message,
+ "Not enough memory for request of %zd (used=%zd free=%zd)",
+ size, pph->To_Free, pph->FreeBlk);
+ xtrc(1, "BsonSubAlloc: %s\n", G->Message);
+
+ if (Throw)
+ throw(1234);
+ else
+ return NULL;
+
+ } /* endif size OS32 code */
+
+ // Do the suballocation the simplest way
+ memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
+ pph->To_Free += size; /* New offset of pool free block */
+ pph->FreeBlk -= size; /* New size of pool free block */
+ xtrc(16, "Done memp=%p used=%zd free=%zd\n",
+ memp, pph->To_Free, pph->FreeBlk);
+ return memp;
+} // end of BsonSubAlloc
+
+/*********************************************************************************/
+/* Program for SubSet re-initialization of the memory pool. */
+/*********************************************************************************/
+PSZ BJSON::NewStr(PSZ str)
+{
+ if (str) {
+ PSZ sm = (PSZ)BsonSubAlloc(strlen(str) + 1);
+
+ strcpy(sm, str);
+ return sm;
+ } else
+ return NULL;
+
+} // end of NewStr
+
+/*********************************************************************************/
+/* Program for SubSet re-initialization of the memory pool. */
+/*********************************************************************************/
+void BJSON::SubSet(bool b)
+{
+ PPOOLHEADER pph = (PPOOLHEADER)G->Sarea;
+
+ pph->To_Free = (G->Saved_Size) ? G->Saved_Size : sizeof(POOLHEADER);
+ pph->FreeBlk = G->Sarea_Size - pph->To_Free;
+
+ if (b)
+ G->Saved_Size = 0;
+
+} // end of SubSet
+
+/*********************************************************************************/
+/* Set the beginning of suballocations. */
+/*********************************************************************************/
+void BJSON::MemSet(size_t size)
+{
+ PPOOLHEADER pph = (PPOOLHEADER)G->Sarea;
+
+ pph->To_Free = size + sizeof(POOLHEADER);
+ pph->FreeBlk = G->Sarea_Size - pph->To_Free;
+} // end of MemSet
+
+ /* ------------------------ Bobject functions ------------------------ */
+
+/***********************************************************************/
+/* Set a pair vlp to some PVAL values. */
+/***********************************************************************/
+void BJSON::SetPairValue(PBPR brp, PBVAL bvp)
+{
+ if (bvp) {
+ brp->Vlp.To_Val = bvp->To_Val;
+ brp->Vlp.Nd = bvp->Nd;
+ brp->Vlp.Type = bvp->Type;
+ } else {
+ brp->Vlp.To_Val = 0;
+ brp->Vlp.Nd = 0;
+ brp->Vlp.Type = TYPE_NULL;
+ } // endif bvp
+
+} // end of SetPairValue
+
+ /***********************************************************************/
+/* Sub-allocate and initialize a BPAIR. */
+/***********************************************************************/
+PBPR BJSON::NewPair(OFFSET key, int type)
+{
+ PBPR bpp = (PBPR)BsonSubAlloc(sizeof(BPAIR));
+
+ bpp->Key = key;
+ bpp->Vlp.Type = type;
+ bpp->Vlp.To_Val = 0;
+ bpp->Vlp.Nd = 0;
+ bpp->Vlp.Next = 0;
+ return bpp;
+} // end of SubAllocPair
+
+/***********************************************************************/
+/* Return the number of pairs in this object. */
+/***********************************************************************/
+int BJSON::GetObjectSize(PBVAL bop, bool b)
+{
+ CheckType(bop, TYPE_JOB);
+ int n = 0;
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ // If b return only non null pairs
+ if (!b || (brp->Vlp.To_Val && brp->Vlp.Type != TYPE_NULL))
+ n++;
+
+ return n;
+} // end of GetObjectSize
+
+/***********************************************************************/
+/* Add a new pair to an Object and return it. */
+/***********************************************************************/
+PBVAL BJSON::AddPair(PBVAL bop, PSZ key, int type)
+{
+ CheckType(bop, TYPE_JOB);
+ PBPR brp;
+ OFFSET nrp = NewPair(key, type);
+
+ if (bop->To_Val) {
+ for (brp = GetObject(bop); brp->Vlp.Next; brp = GetNext(brp));
+
+ brp->Vlp.Next = nrp;
+ } else
+ bop->To_Val = nrp;
+
+ bop->Nd++;
+ return GetVlp(MPP(nrp));
+} // end of AddPair
+
+/***********************************************************************/
+/* Return all object keys as an array. */
+/***********************************************************************/
+PBVAL BJSON::GetKeyList(PBVAL bop)
+{
+ CheckType(bop, TYPE_JOB);
+ PBVAL arp = NewVal(TYPE_JAR);
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ AddArrayValue(arp, MOF(SubAllocVal(brp->Key, TYPE_STRG)));
+
+ return arp;
+} // end of GetKeyList
+
+/***********************************************************************/
+/* Return all object values as an array. */
+/***********************************************************************/
+PBVAL BJSON::GetObjectValList(PBVAL bop)
+{
+ CheckType(bop, TYPE_JOB);
+ PBVAL arp = NewVal(TYPE_JAR);
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ AddArrayValue(arp, DupVal(GetVlp(brp)));
+
+ return arp;
+} // end of GetObjectValList
+
+/***********************************************************************/
+/* Get the value corresponding to the given key. */
+/***********************************************************************/
+PBVAL BJSON::GetKeyValue(PBVAL bop, PSZ key)
+{
+ CheckType(bop, TYPE_JOB);
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ if (!strcmp(GetKey(brp), key))
+ return GetVlp(brp);
+
+ return NULL;
+} // end of GetKeyValue;
+
+/***********************************************************************/
+/* Return the text corresponding to all keys (XML like). */
+/***********************************************************************/
+PSZ BJSON::GetObjectText(PGLOBAL g, PBVAL bop, PSTRG text)
+{
+ CheckType(bop, TYPE_JOB);
+ PBPR brp = GetObject(bop);
+
+ if (brp) {
+ bool b;
+
+ if (!text) {
+ text = new(g) STRING(g, 256);
+ b = true;
+ } else {
+ if (text->GetLastChar() != ' ')
+ text->Append(' ');
+
+ b = false;
+ } // endif text
+
+ if (b && !brp->Vlp.Next && !strcmp(MZP(brp->Key), "$date")) {
+ int i;
+ PSZ s;
+
+ GetValueText(g, GetVlp(brp), text);
+ s = text->GetStr();
+ i = (s[1] == '-' ? 2 : 1);
+
+ if (IsNum(s + i)) {
+ // Date is in milliseconds
+ int j = text->GetLength();
+
+ if (j >= 4 + i) {
+ s[j - 3] = 0; // Change it to seconds
+ text->SetLength((uint)strlen(s));
+ } else
+ text->Set(" 0");
+
+ } // endif text
+
+ } else for (; brp; brp = GetNext(brp)) {
+ GetValueText(g, GetVlp(brp), text);
+
+ if (brp->Vlp.Next)
+ text->Append(' ');
+
+ } // endfor brp
+
+ if (b) {
+ text->Trim();
+ return text->GetStr();
+ } // endif b
+
+ } // endif bop
+
+ return NULL;
+} // end of GetObjectText;
+
+/***********************************************************************/
+/* Set or add a value corresponding to the given key. */
+/***********************************************************************/
+void BJSON::SetKeyValue(PBVAL bop, OFFSET bvp, PSZ key)
+{
+ CheckType(bop, TYPE_JOB);
+ PBPR brp, prp = NULL;
+
+ if (bop->To_Val) {
+ for (brp = GetObject(bop); brp; brp = GetNext(brp))
+ if (!strcmp(GetKey(brp), key))
+ break;
+ else
+ prp = brp;
+
+ if (!brp)
+ brp = MPP(prp->Vlp.Next = NewPair(key));
+
+ } else
+ brp = MPP(bop->To_Val = NewPair(key));
+
+ SetPairValue(brp, MVP(bvp));
+ bop->Nd++;
+} // end of SetKeyValue
+
+/***********************************************************************/
+/* Merge two objects. */
+/***********************************************************************/
+PBVAL BJSON::MergeObject(PBVAL bop1, PBVAL bop2)
+{
+ CheckType(bop1, TYPE_JOB);
+ CheckType(bop2, TYPE_JOB);
+
+ if (bop1->To_Val)
+ for (PBPR brp = GetObject(bop2); brp; brp = GetNext(brp))
+ SetKeyValue(bop1, GetVlp(brp), GetKey(brp));
+
+ else {
+ bop1->To_Val = bop2->To_Val;
+ bop1->Nd = bop2->Nd;
+ } // endelse To_Val
+
+ return bop1;
+} // end of MergeObject;
+
+/***********************************************************************/
+/* Delete a value corresponding to the given key. */
+/***********************************************************************/
+bool BJSON::DeleteKey(PBVAL bop, PCSZ key)
+{
+ CheckType(bop, TYPE_JOB);
+ PBPR brp, pbrp = NULL;
+
+ for (brp = GetObject(bop); brp; brp = GetNext(brp))
+ if (!strcmp(MZP(brp->Key), key)) {
+ if (pbrp) {
+ pbrp->Vlp.Next = brp->Vlp.Next;
+ } else
+ bop->To_Val = brp->Vlp.Next;
+
+ bop->Nd--;
+ return true;;
+ } else
+ pbrp = brp;
+
+ return false;
+} // end of DeleteKey
+
+/***********************************************************************/
+/* True if void or if all members are nulls. */
+/***********************************************************************/
+bool BJSON::IsObjectNull(PBVAL bop)
+{
+ CheckType(bop, TYPE_JOB);
+
+ for (PBPR brp = GetObject(bop); brp; brp = GetNext(brp))
+ if (brp->Vlp.To_Val && brp->Vlp.Type != TYPE_NULL)
+ return false;
+
+ return true;
+} // end of IsObjectNull
+
+/* ------------------------- Barray functions ------------------------ */
+
+/***********************************************************************/
+/* Return the number of values in this object. */
+/***********************************************************************/
+int BJSON::GetArraySize(PBVAL bap, bool b)
+{
+ CheckType(bap, TYPE_JAR);
+ int n = 0;
+
+ for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp))
+ // If b, return only non null values
+ if (!b || bvp->Type != TYPE_NULL)
+ n++;
+
+ return n;
+} // end of GetArraySize
+
+/***********************************************************************/
+/* Get the Nth value of an Array. */
+/***********************************************************************/
+PBVAL BJSON::GetArrayValue(PBVAL bap, int n)
+{
+ CheckType(bap, TYPE_JAR);
+ int i = 0;
+
+ if (n < 0)
+ n += GetArraySize(bap);
+
+ for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
+ if (i == n)
+ return bvp;
+
+ return NULL;
+} // end of GetArrayValue
+
+/***********************************************************************/
+/* Add a Value to the Array Value list. */
+/***********************************************************************/
+void BJSON::AddArrayValue(PBVAL bap, OFFSET nbv, int* x)
+{
+ CheckType(bap, TYPE_JAR);
+ int i = 0;
+ PBVAL bvp, lbp = NULL;
+
+ if (!nbv)
+ nbv = MOF(NewVal());
+
+ for (bvp = GetArray(bap); bvp; bvp = GetNext(bvp), i++)
+ if (x && i == *x)
+ break;
+ else
+ lbp = bvp;
+
+ if (lbp) {
+ MVP(nbv)->Next = lbp->Next;
+ lbp->Next = nbv;
+ } else {
+ MVP(nbv)->Next = bap->To_Val;
+ bap->To_Val = nbv;
+ } // endif lbp
+
+ bap->Nd++;
+} // end of AddArrayValue
+
+/***********************************************************************/
+/* Merge two arrays. */
+/***********************************************************************/
+void BJSON::MergeArray(PBVAL bap1, PBVAL bap2)
+{
+ CheckType(bap1, TYPE_JAR);
+ CheckType(bap2, TYPE_JAR);
+
+ if (bap1->To_Val) {
+ for (PBVAL bvp = GetArray(bap2); bvp; bvp = GetNext(bvp))
+ AddArrayValue(bap1, MOF(DupVal(bvp)));
+
+ } else {
+ bap1->To_Val = bap2->To_Val;
+ bap1->Nd = bap2->Nd;
+ } // endif To_Val
+
+} // end of MergeArray
+
+/***********************************************************************/
+/* Set the nth Value of the Array Value list or add it. */
+/***********************************************************************/
+void BJSON::SetArrayValue(PBVAL bap, PBVAL nvp, int n)
+{
+ CheckType(bap, TYPE_JAR);
+ int i = 0;
+ PBVAL bvp = NULL;
+
+ for (bvp = GetArray(bap); i < n; i++, bvp = bvp ? GetNext(bvp) : NULL)
+ if (!bvp)
+ AddArrayValue(bap, NewVal());
+
+ if (!bvp)
+ AddArrayValue(bap, MOF(nvp));
+ else
+ SetValueVal(bvp, nvp);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* Return the text corresponding to all values. */
+/***********************************************************************/
+PSZ BJSON::GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text)
+{
+ CheckType(bap, TYPE_JAR);
+
+ if (bap->To_Val) {
+ bool b;
+
+ if (!text) {
+ text = new(g) STRING(g, 256);
+ b = true;
+ } else {
+ if (text->GetLastChar() != ' ')
+ text->Append(" (");
+ else
+ text->Append('(');
+
+ b = false;
+ } // endif text
+
+ for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp)) {
+ GetValueText(g, bvp, text);
+
+ if (bvp->Next)
+ text->Append(", ");
+ else if (!b)
+ text->Append(')');
+
+ } // endfor bvp
+
+ if (b) {
+ text->Trim();
+ return text->GetStr();
+ } // endif b
+
+ } // endif To_Val
+
+ return NULL;
+} // end of GetText;
+
+/***********************************************************************/
+/* Delete a Value from the Arrays Value list. */
+/***********************************************************************/
+bool BJSON::DeleteValue(PBVAL bap, int n)
+{
+ CheckType(bap, TYPE_JAR);
+ int i = 0;
+ PBVAL bvp, pvp = NULL;
+
+ for (bvp = GetArray(bap); bvp; i++, bvp = GetNext(bvp))
+ if (i == n) {
+ if (pvp)
+ pvp->Next = bvp->Next;
+ else
+ bap->To_Val = bvp->Next;
+
+ bap->Nd--;
+ return true;;
+ } else
+ pvp = bvp;
+
+ return false;
+} // end of DeleteValue
+
+/***********************************************************************/
+/* True if void or if all members are nulls. */
+/***********************************************************************/
+bool BJSON::IsArrayNull(PBVAL bap)
+{
+ CheckType(bap, TYPE_JAR);
+
+ for (PBVAL bvp = GetArray(bap); bvp; bvp = GetNext(bvp))
+ if (bvp->Type != TYPE_NULL)
+ return false;
+
+ return true;
+} // end of IsNull
+
+/* ------------------------- Bvalue functions ------------------------ */
+
+/***********************************************************************/
+/* Sub-allocate and clear a BVAL. */
+/***********************************************************************/
+PBVAL BJSON::NewVal(int type)
+{
+ PBVAL bvp = (PBVAL)BsonSubAlloc(sizeof(BVAL));
+
+ bvp->To_Val = 0;
+ bvp->Nd = 0;
+ bvp->Type = type;
+ bvp->Next = 0;
+ return bvp;
+} // end of SubAllocVal
+
+/***********************************************************************/
+/* Sub-allocate and initialize a BVAL as type. */
+/***********************************************************************/
+PBVAL BJSON::SubAllocVal(OFFSET toval, int type, short nd)
+{
+ PBVAL bvp = NewVal(type);
+
+ bvp->To_Val = toval;
+ bvp->Nd = nd;
+ return bvp;
+} // end of SubAllocVal
+
+/***********************************************************************/
+/* Sub-allocate and initialize a BVAL as string. */
+/***********************************************************************/
+PBVAL BJSON::SubAllocStr(OFFSET toval, short nd)
+{
+ PBVAL bvp = NewVal(TYPE_STRG);
+
+ bvp->To_Val = toval;
+ bvp->Nd = nd;
+ return bvp;
+} // end of SubAllocStr
+
+/***********************************************************************/
+/* Allocate a BVALUE with a given string or numeric value. */
+/***********************************************************************/
+PBVAL BJSON::NewVal(PVAL valp)
+{
+ PBVAL vlp = NewVal();
+
+ SetValue(vlp, valp);
+ return vlp;
+} // end of SubAllocVal
+
+/***********************************************************************/
+/* Sub-allocate and initialize a BVAL from another BVAL. */
+/***********************************************************************/
+PBVAL BJSON::DupVal(PBVAL bvlp)
+{
+ if (bvlp) {
+ PBVAL bvp = NewVal();
+
+ *bvp = *bvlp;
+ bvp->Next = 0;
+ return bvp;
+ } else
+ return NULL;
+
+} // end of DupVal
+
+/***********************************************************************/
+/* Return the size of value's value. */
+/***********************************************************************/
+int BJSON::GetSize(PBVAL vlp, bool b)
+{
+ switch (vlp->Type) {
+ case TYPE_JAR:
+ return GetArraySize(vlp);
+ case TYPE_JOB:
+ return GetObjectSize(vlp);
+ default:
+ return 1;
+ } // enswitch Type
+
+} // end of GetSize
+
+PBVAL BJSON::GetBson(PBVAL bvp)
+{
+ PBVAL bp = NULL;
+
+ switch (bvp->Type) {
+ case TYPE_JAR:
+ bp = MVP(bvp->To_Val);
+ break;
+ case TYPE_JOB:
+ bp = GetVlp(MPP(bvp->To_Val));
+ break;
+ default:
+ bp = bvp;
+ break;
+ } // endswitch Type
+
+ return bp;
+} // end of GetBson
+
+/***********************************************************************/
+/* Return the Value's as a Value struct. */
+/***********************************************************************/
+PVAL BJSON::GetValue(PGLOBAL g, PBVAL vp)
+{
+ double d;
+ PVAL valp;
+ PBVAL vlp = vp->Type == TYPE_JVAL ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_STRG:
+ case TYPE_DBL:
+ case TYPE_BINT:
+ valp = AllocateValue(g, MP(vlp->To_Val), vlp->Type, vlp->Nd);
+ break;
+ case TYPE_INTG:
+ case TYPE_BOOL:
+ valp = AllocateValue(g, vlp, vlp->Type);
+ break;
+ case TYPE_FLOAT:
+ d = (double)vlp->F;
+ valp = AllocateValue(g, &d, TYPE_DOUBLE, vlp->Nd);
+ break;
+ default:
+ valp = NULL;
+ break;
+ } // endswitch Type
+
+ return valp;
+} // end of GetValue
+
+/***********************************************************************/
+/* Return the Value's Integer value. */
+/***********************************************************************/
+int BJSON::GetInteger(PBVAL vp) {
+ int n;
+ PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_INTG:
+ n = vlp->N;
+ break;
+ case TYPE_FLOAT:
+ n = (int)vlp->F;
+ break;
+ case TYPE_DTM:
+ case TYPE_STRG:
+ n = atoi(MZP(vlp->To_Val));
+ break;
+ case TYPE_BOOL:
+ n = (vlp->B) ? 1 : 0;
+ break;
+ case TYPE_BINT:
+ n = (int)*(longlong*)MP(vlp->To_Val);
+ break;
+ case TYPE_DBL:
+ n = (int)*(double*)MP(vlp->To_Val);
+ break;
+ default:
+ n = 0;
+ } // endswitch Type
+
+ return n;
+} // end of GetInteger
+
+/***********************************************************************/
+/* Return the Value's Big integer value. */
+/***********************************************************************/
+longlong BJSON::GetBigint(PBVAL vp) {
+ longlong lln;
+ PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_BINT:
+ lln = *(longlong*)MP(vlp->To_Val);
+ break;
+ case TYPE_INTG:
+ lln = (longlong)vlp->N;
+ break;
+ case TYPE_FLOAT:
+ lln = (longlong)vlp->F;
+ break;
+ case TYPE_DBL:
+ lln = (longlong)*(double*)MP(vlp->To_Val);
+ break;
+ case TYPE_DTM:
+ case TYPE_STRG:
+ lln = atoll(MZP(vlp->To_Val));
+ break;
+ case TYPE_BOOL:
+ lln = (vlp->B) ? 1 : 0;
+ break;
+ default:
+ lln = 0;
+ } // endswitch Type
+
+ return lln;
+} // end of GetBigint
+
+/***********************************************************************/
+/* Return the Value's Double value. */
+/***********************************************************************/
+double BJSON::GetDouble(PBVAL vp)
+{
+ double d;
+ PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_DBL:
+ d = *(double*)MP(vlp->To_Val);
+ break;
+ case TYPE_BINT:
+ d = (double)*(longlong*)MP(vlp->To_Val);
+ break;
+ case TYPE_INTG:
+ d = (double)vlp->N;
+ break;
+ case TYPE_FLOAT:
+ d = (double)vlp->F;
+ break;
+ case TYPE_DTM:
+ case TYPE_STRG:
+ d = atof(MZP(vlp->To_Val));
+ break;
+ case TYPE_BOOL:
+ d = (vlp->B) ? 1.0 : 0.0;
+ break;
+ default:
+ d = 0.0;
+ } // endswitch Type
+
+ return d;
+} // end of GetDouble
+
+/***********************************************************************/
+/* Return the Value's String value. */
+/***********************************************************************/
+PSZ BJSON::GetString(PBVAL vp, char* buff)
+{
+ char buf[32];
+ char* p = (buff) ? buff : buf;
+ PBVAL vlp = (vp->Type == TYPE_JVAL) ? MVP(vp->To_Val) : vp;
+
+ switch (vlp->Type) {
+ case TYPE_DTM:
+ case TYPE_STRG:
+ p = MZP(vlp->To_Val);
+ break;
+ case TYPE_INTG:
+ sprintf(p, "%d", vlp->N);
+ break;
+ case TYPE_FLOAT:
+ sprintf(p, "%.*f", vlp->Nd, vlp->F);
+ break;
+ case TYPE_BINT:
+ sprintf(p, "%lld", *(longlong*)MP(vlp->To_Val));
+ break;
+ case TYPE_DBL:
+ sprintf(p, "%.*lf", vlp->Nd, *(double*)MP(vlp->To_Val));
+ break;
+ case TYPE_BOOL:
+ p = (PSZ)((vlp->B) ? "true" : "false");
+ break;
+ case TYPE_NULL:
+ p = (PSZ)"null";
+ break;
+ default:
+ p = NULL;
+ } // endswitch Type
+
+ return (p == buf) ? (PSZ)PlugDup(G, buf) : p;
+} // end of GetString
+
+/***********************************************************************/
+/* Return the Value's String value. */
+/***********************************************************************/
+PSZ BJSON::GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text)
+{
+ if (vlp->Type == TYPE_JOB)
+ return GetObjectText(g, vlp, text);
+ else if (vlp->Type == TYPE_JAR)
+ return GetArrayText(g, vlp, text);
+
+ char buff[32];
+ PSZ s = (vlp->Type == TYPE_NULL) ? NULL : GetString(vlp, buff);
+
+ if (s)
+ text->Append(s);
+ else if (GetJsonNull())
+ text->Append(GetJsonNull());
+
+ return NULL;
+} // end of GetText
+
+void BJSON::SetValueObj(PBVAL vlp, PBVAL bop)
+{
+ CheckType(bop, TYPE_JOB);
+ vlp->To_Val = bop->To_Val;
+ vlp->Nd = bop->Nd;
+ vlp->Type = TYPE_JOB;
+} // end of SetValueObj;
+
+void BJSON::SetValueArr(PBVAL vlp, PBVAL bap)
+{
+ CheckType(bap, TYPE_JAR);
+ vlp->To_Val = bap->To_Val;
+ vlp->Nd = bap->Nd;
+ vlp->Type = TYPE_JAR;
+} // end of SetValue;
+
+void BJSON::SetValueVal(PBVAL vlp, PBVAL vp)
+{
+ vlp->To_Val = vp->To_Val;
+ vlp->Nd = vp->Nd;
+ vlp->Type = vp->Type;
+} // end of SetValue;
+
+PBVAL BJSON::SetValue(PBVAL vlp, PVAL valp)
+{
+ if (!vlp)
+ vlp = NewVal();
+
+ if (!valp || valp->IsNull()) {
+ vlp->Type = TYPE_NULL;
+ } else switch (valp->GetType()) {
+ case TYPE_DATE:
+ if (((DTVAL*)valp)->IsFormatted())
+ vlp->To_Val = DupStr(valp->GetCharValue());
+ else {
+ char buf[32];
+
+ vlp->To_Val = DupStr(valp->GetCharString(buf));
+ } // endif Formatted
+
+ vlp->Type = TYPE_DTM;
+ break;
+ case TYPE_STRING:
+ vlp->To_Val = DupStr(valp->GetCharValue());
+ vlp->Type = TYPE_STRG;
+ break;
+ case TYPE_DOUBLE:
+ case TYPE_DECIM:
+ { double d = valp->GetFloatValue();
+ int nd = (IsTypeNum(valp->GetType())) ? valp->GetValPrec() : 0;
+
+ if (nd > 0 && nd <= 6 && d >= FLT_MIN && d <= FLT_MAX) {
+ vlp->F = (float)valp->GetFloatValue();
+ vlp->Type = TYPE_FLOAT;
+ } else {
+ double* dp = (double*)BsonSubAlloc(sizeof(double));
+
+ *dp = d;
+ vlp->To_Val = MOF(dp);
+ vlp->Type = TYPE_DBL;
+ } // endif Nd
+
+ vlp->Nd = MY_MIN(nd, 16);
+ } break;
+ case TYPE_TINY:
+ vlp->B = valp->GetTinyValue() != 0;
+ vlp->Type = TYPE_BOOL;
+ break;
+ case TYPE_INT:
+ vlp->N = valp->GetIntValue();
+ vlp->Type = TYPE_INTG;
+ break;
+ case TYPE_BIGINT:
+ if (valp->GetBigintValue() >= INT_MIN32 &&
+ valp->GetBigintValue() <= INT_MAX32) {
+ vlp->N = valp->GetIntValue();
+ vlp->Type = TYPE_INTG;
+ } else {
+ longlong* llp = (longlong*)BsonSubAlloc(sizeof(longlong));
+
+ *llp = valp->GetBigintValue();
+ vlp->To_Val = MOF(llp);
+ vlp->Type = TYPE_BINT;
+ } // endif BigintValue
+
+ break;
+ default:
+ sprintf(G->Message, "Unsupported typ %d\n", valp->GetType());
+ throw(777);
+ } // endswitch Type
+
+ return vlp;
+} // end of SetValue
+
+/***********************************************************************/
+/* Set the Value's value as the given integer. */
+/***********************************************************************/
+void BJSON::SetInteger(PBVAL vlp, int n)
+{
+ vlp->N = n;
+ vlp->Type = TYPE_INTG;
+} // end of SetInteger
+
+/***********************************************************************/
+/* Set the Value's Boolean value as a tiny integer. */
+/***********************************************************************/
+void BJSON::SetBool(PBVAL vlp, bool b)
+{
+ vlp->B = b;
+ vlp->Type = TYPE_BOOL;
+} // end of SetTiny
+
+/***********************************************************************/
+/* Set the Value's value as the given big integer. */
+/***********************************************************************/
+void BJSON::SetBigint(PBVAL vlp, longlong ll)
+{
+ if (ll >= INT_MIN32 && ll <= INT_MAX32) {
+ vlp->N = (int)ll;
+ vlp->Type = TYPE_INTG;
+ } else {
+ longlong* llp = (longlong*)PlugSubAlloc(G, NULL, sizeof(longlong));
+
+ *llp = ll;
+ vlp->To_Val = MOF(llp);
+ vlp->Type = TYPE_BINT;
+ } // endif ll
+
+} // end of SetBigint
+
+/***********************************************************************/
+/* Set the Value's value as the given DOUBLE. */
+/***********************************************************************/
+void BJSON::SetFloat(PBVAL vlp, double d, int prec)
+{
+ int nd = MY_MIN((prec < 0) ? GetJsonDefPrec() : prec, 16);
+
+ if (nd < 6 && d >= FLT_MIN && d <= FLT_MAX) {
+ vlp->F = (float)d;
+ vlp->Type = TYPE_FLOAT;
+ } else {
+ double* dp = (double*)BsonSubAlloc(sizeof(double));
+
+ *dp = d;
+ vlp->To_Val = MOF(dp);
+ vlp->Type = TYPE_DBL;
+ } // endif nd
+
+ vlp->Nd = nd;
+} // end of SetFloat
+
+/***********************************************************************/
+/* Set the Value's value as the given DOUBLE representation. */
+/***********************************************************************/
+void BJSON::SetFloat(PBVAL vlp, PSZ s)
+{
+ char *p = strchr(s, '.');
+ int nd = 0;
+ double d = atof(s);
+
+ if (p) {
+ for (++p; isdigit(*p); nd++, p++);
+ for (--p; *p == '0'; nd--, p--);
+ } // endif p
+
+ SetFloat(vlp, d, nd);
+} // end of SetFloat
+
+ /***********************************************************************/
+/* Set the Value's value as the given string. */
+/***********************************************************************/
+void BJSON::SetString(PBVAL vlp, PSZ s, int ci)
+{
+ vlp->To_Val = MOF(s);
+ vlp->Nd = ci;
+ vlp->Type = TYPE_STRG;
+} // end of SetString
+
+/***********************************************************************/
+/* True when its JSON or normal value is null. */
+/***********************************************************************/
+bool BJSON::IsValueNull(PBVAL vlp)
+{
+ bool b;
+
+ switch (vlp->Type) {
+ case TYPE_NULL:
+ b = true;
+ break;
+ case TYPE_JOB:
+ b = IsObjectNull(vlp);
+ break;
+ case TYPE_JAR:
+ b = IsArrayNull(vlp);
+ break;
+ default:
+ b = false;
+ } // endswitch Type
+
+ return b;
+ } // end of IsNull
diff --git a/storage/connect/bson.h b/storage/connect/bson.h
new file mode 100644
index 00000000..acc36e8e
--- /dev/null
+++ b/storage/connect/bson.h
@@ -0,0 +1,207 @@
+/**************** bson H Declares Source Code File (.H) ****************/
+/* Name: bson.h Version 1.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2020 */
+/* */
+/* This file contains the BSON classe declares. */
+/***********************************************************************/
+#pragma once
+#include <mysql_com.h>
+#include "json.h"
+#include "xobject.h"
+
+#if defined(_DEBUG)
+#define X assert(false);
+#else
+#define X
+#endif
+
+#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
+
+class BDOC;
+class BOUT;
+class BJSON;
+
+typedef class BDOC* PBDOC;
+typedef class BJSON* PBJSON;
+typedef uint OFFSET;
+
+/***********************************************************************/
+/* Structure BVAL. Binary representation of a JVALUE. */
+/***********************************************************************/
+typedef struct _jvalue {
+ union {
+ OFFSET To_Val; // Offset to a value
+ int N; // An integer value
+ float F; // A float value
+ bool B; // A boolean value True or false (0)
+ };
+ short Nd; // Number of decimals
+ short Type; // The value type
+ OFFSET Next; // Offset to the next value in array
+} BVAL, *PBVAL; // end of struct BVALUE
+
+/***********************************************************************/
+/* Structure BPAIR. The pairs of a json Object. */
+/***********************************************************************/
+typedef struct _jpair {
+ OFFSET Key; // Offset to this pair key name
+ BVAL Vlp; // The value of the pair
+} BPAIR, *PBPR; // end of struct BPAIR
+
+char* NextChr(PSZ s, char sep);
+char* GetJsonNull(void);
+const char* GetFmt(int type, bool un);
+
+DllExport bool IsNum(PSZ s);
+
+/***********************************************************************/
+/* Class BJSON. The class handling all BJSON operations. */
+/***********************************************************************/
+class BJSON : public BLOCK {
+public:
+ // Constructor
+ BJSON(PGLOBAL g, PBVAL vp = NULL)
+ { G = g, Base = G->Sarea; Bvp = vp; Throw = true; }
+
+ // Utility functions
+ inline OFFSET MOF(void *p) {return MakeOff(Base, p);}
+ inline void *MP(OFFSET o) {return MakePtr(Base, o);}
+ inline PBPR MPP(OFFSET o) {return (PBPR)MakePtr(Base, o);}
+ inline PBVAL MVP(OFFSET o) {return (PBVAL)MakePtr(Base, o);}
+ inline PSZ MZP(OFFSET o) {return (PSZ)MakePtr(Base, o);}
+ inline longlong LLN(OFFSET o) {return *(longlong*)MakePtr(Base, o);}
+ inline double DBL(OFFSET o) {return *(double*)MakePtr(Base, o);}
+
+ void Reset(void) {Base = G->Sarea;}
+ void* GetBase(void) { return Base; }
+ void SubSet(bool b = false);
+ void MemSave(void) {G->Saved_Size = ((PPOOLHEADER)G->Sarea)->To_Free;}
+ void MemSet(size_t size);
+ void GetMsg(PGLOBAL g) { if (g != G) strcpy(g->Message, G->Message); }
+
+ // SubAlloc functions
+ void* BsonSubAlloc(size_t size);
+ PBPR NewPair(OFFSET key, int type = TYPE_NULL);
+ OFFSET NewPair(PSZ key, int type = TYPE_NULL)
+ {return MOF(NewPair(DupStr(key), type));}
+ PBVAL NewVal(int type = TYPE_NULL);
+ PBVAL NewVal(PVAL valp);
+ PBVAL SubAllocVal(OFFSET toval, int type = TYPE_NULL, short nd = 0);
+ PBVAL SubAllocVal(PBVAL toval, int type = TYPE_NULL, short nd = 0)
+ {return SubAllocVal(MOF(toval), type, nd);}
+ PBVAL SubAllocStr(OFFSET str, short nd = 0);
+ PBVAL SubAllocStr(PSZ str, short nd = 0)
+ {return SubAllocStr(DupStr(str), nd);}
+ PBVAL DupVal(PBVAL bvp);
+ OFFSET DupStr(PSZ str) { return MOF(NewStr(str)); }
+ PSZ NewStr(PSZ str);
+
+ // Array functions
+ inline PBVAL GetArray(PBVAL vlp) {return MVP(vlp->To_Val);}
+ int GetArraySize(PBVAL bap, bool b = false);
+ PBVAL GetArrayValue(PBVAL bap, int i);
+ PSZ GetArrayText(PGLOBAL g, PBVAL bap, PSTRG text);
+ void MergeArray(PBVAL bap1,PBVAL bap2);
+ bool DeleteValue(PBVAL bap, int n);
+ void AddArrayValue(PBVAL bap, OFFSET nvp = 0, int* x = NULL);
+ inline void AddArrayValue(PBVAL bap, PBVAL nvp = NULL, int* x = NULL)
+ {AddArrayValue(bap, MOF(nvp), x);}
+ void SetArrayValue(PBVAL bap, PBVAL nvp, int n);
+ bool IsArrayNull(PBVAL bap);
+
+ // Object functions
+ inline PBPR GetObject(PBVAL bop) {return MPP(bop->To_Val);}
+ inline PBPR GetNext(PBPR brp) { return MPP(brp->Vlp.Next); }
+ void SetPairValue(PBPR brp, PBVAL bvp);
+ int GetObjectSize(PBVAL bop, bool b = false);
+ PSZ GetObjectText(PGLOBAL g, PBVAL bop, PSTRG text);
+ PBVAL MergeObject(PBVAL bop1, PBVAL bop2);
+ PBVAL AddPair(PBVAL bop, PSZ key, int type = TYPE_NULL);
+ PSZ GetKey(PBPR prp) {return prp ? MZP(prp->Key) : NULL;}
+ PBVAL GetTo_Val(PBPR prp) {return prp ? MVP(prp->Vlp.To_Val) : NULL;}
+ PBVAL GetVlp(PBPR prp) {return prp ? (PBVAL)&prp->Vlp : NULL;}
+ PBVAL GetKeyValue(PBVAL bop, PSZ key);
+ PBVAL GetKeyList(PBVAL bop);
+ PBVAL GetObjectValList(PBVAL bop);
+ void SetKeyValue(PBVAL bop, OFFSET bvp, PSZ key);
+ inline void SetKeyValue(PBVAL bop, PBVAL vlp, PSZ key)
+ {SetKeyValue(bop, MOF(vlp), key);}
+ bool DeleteKey(PBVAL bop, PCSZ k);
+ bool IsObjectNull(PBVAL bop);
+
+ // Value functions
+ int GetSize(PBVAL vlp, bool b = false);
+ PBVAL GetNext(PBVAL vlp) {return MVP(vlp->Next);}
+ //PJSON GetJsp(void) { return (DataType == TYPE_JSON ? Jsp : NULL); }
+ PSZ GetValueText(PGLOBAL g, PBVAL vlp, PSTRG text);
+ PBVAL GetBson(PBVAL bvp);
+ PSZ GetString(PBVAL vp, char* buff = NULL);
+ int GetInteger(PBVAL vp);
+ long long GetBigint(PBVAL vp);
+ double GetDouble(PBVAL vp);
+ PVAL GetValue(PGLOBAL g, PBVAL vp);
+ void SetValueObj(PBVAL vlp, PBVAL bop);
+ void SetValueArr(PBVAL vlp, PBVAL bap);
+ void SetValueVal(PBVAL vlp, PBVAL vp);
+ PBVAL SetValue(PBVAL vlp, PVAL valp);
+ void SetString(PBVAL vlp, PSZ s, int ci = 0);
+ void SetInteger(PBVAL vlp, int n);
+ void SetBigint(PBVAL vlp, longlong ll);
+ void SetFloat(PBVAL vlp, double f, int nd = -1);
+ void SetFloat(PBVAL vlp, PSZ s);
+ void SetBool(PBVAL vlp, bool b);
+ void Clear(PBVAL vlp) { vlp->N = 0; vlp->Nd = 0; vlp->Next = 0; }
+ bool IsValueNull(PBVAL vlp);
+ bool IsJson(PBVAL vlp) {return vlp ? vlp->Type == TYPE_JAR ||
+ vlp->Type == TYPE_JOB ||
+ vlp->Type == TYPE_JVAL : false;}
+
+ // Members
+ PGLOBAL G;
+ PBVAL Bvp;
+ void *Base;
+ bool Throw;
+
+protected:
+ // Default constructor not to be used
+ BJSON(void) {}
+}; // end of class BJSON
+
+/***********************************************************************/
+/* Class JDOC. The class for parsing and serializing json documents. */
+/***********************************************************************/
+class BDOC : public BJSON {
+public:
+ BDOC(PGLOBAL G);
+
+ bool GetComma(void) { return comma; }
+ int GetPretty(void) { return pretty; }
+ void SetPretty(int pty) { pretty = pty; }
+
+ // Methods
+ PBVAL ParseJson(PGLOBAL g, char* s, size_t n);
+ PSZ Serialize(PGLOBAL g, PBVAL bvp, char* fn, int pretty);
+
+protected:
+ OFFSET ParseArray(size_t& i);
+ OFFSET ParseObject(size_t& i);
+ PBVAL ParseValue(size_t& i, PBVAL bvp);
+ OFFSET ParseString(size_t& i);
+ void ParseNumeric(size_t& i, PBVAL bvp);
+ OFFSET ParseAsArray(size_t& i);
+ bool SerializeArray(OFFSET arp, bool b);
+ bool SerializeObject(OFFSET obp);
+ bool SerializeValue(PBVAL vp, bool b = false);
+
+ // Members used when parsing and serializing
+ JOUT* jp; // Used with serialize
+ char* s; // The Json string to parse
+ size_t len; // The Json string length
+ int pretty; // The pretty style of the file to parse
+ bool pty[3]; // Used to guess what pretty is
+ bool comma; // True if Pretty = 1
+
+ // Default constructor not to be used
+ BDOC(void) {}
+}; // end of class BDOC
diff --git a/storage/connect/bsonudf.cpp b/storage/connect/bsonudf.cpp
new file mode 100644
index 00000000..7022600e
--- /dev/null
+++ b/storage/connect/bsonudf.cpp
@@ -0,0 +1,6221 @@
+/****************** bsonudf C++ Program Source Code File (.CPP) ******************/
+/* PROGRAM NAME: bsonudf Version 1.0 */
+/* (C) Copyright to the author Olivier BERTRAND 2020 - 2021 */
+/* This program are the BSON User Defined Functions. */
+/*********************************************************************************/
+
+/*********************************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/*********************************************************************************/
+#include <my_global.h>
+#include <mysqld.h>
+#include <mysql.h>
+#include <sql_error.h>
+#include <stdio.h>
+
+#include "bsonudf.h"
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#define _O_RDONLY O_RDONLY
+#endif
+
+#define MEMFIX 4096
+#if defined(connect_EXPORTS)
+#define PUSH_WARNING(M) push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0, M)
+#else
+#define PUSH_WARNING(M) htrc(M)
+#endif
+#define M 6
+
+int JsonDefPrec = -1;
+int GetDefaultPrec(void);
+int IsArgJson(UDF_ARGS* args, uint i);
+void SetChanged(PBSON bsp);
+int GetJsonDefPrec(void);
+
+static PBSON BbinAlloc(PGLOBAL g, ulong len, PBVAL jsp);
+
+/* --------------------------------- JSON UDF ---------------------------------- */
+
+/*********************************************************************************/
+/* Replaces GetJsonGrpSize not usable when CONNECT is not installed. */
+/*********************************************************************************/
+int GetJsonDefPrec(void) {
+ return (JsonDefPrec < 0) ? GetDefaultPrec() : JsonDefPrec;
+} /* end of GetJsonDefPrec */
+
+/*********************************************************************************/
+/* Program for saving the status of the memory pools. */
+/*********************************************************************************/
+inline void JsonMemSave(PGLOBAL g) {
+ g->Saved_Size = ((PPOOLHEADER)g->Sarea)->To_Free;
+} /* end of JsonMemSave */
+
+/*********************************************************************************/
+/* Program for freeing the memory pools. */
+/*********************************************************************************/
+inline void JsonFreeMem(PGLOBAL g) {
+ g->Activityp = NULL;
+ g = PlugExit(g);
+} /* end of JsonFreeMem */
+
+/*********************************************************************************/
+/* Allocate and initialize a BSON structure. */
+/*********************************************************************************/
+static PBSON BbinAlloc(PGLOBAL g, ulong len, PBVAL jsp)
+{
+ PBSON bsp = (PBSON)PlgDBSubAlloc(g, NULL, sizeof(BSON));
+
+ if (bsp) {
+ strcpy(bsp->Msg, "Binary Json");
+ bsp->Msg[BMX] = 0;
+ bsp->Filename = NULL;
+ bsp->G = g;
+ bsp->Pretty = 2;
+ bsp->Reslen = len;
+ bsp->Changed = false;
+ bsp->Top = bsp->Jsp = (PJSON)jsp;
+ bsp->Bsp = NULL;
+ } else
+ PUSH_WARNING(g->Message);
+
+ return bsp;
+} /* end of BbinAlloc */
+
+/* --------------------------- New Testing BJSON Stuff --------------------------*/
+
+/*********************************************************************************/
+/* SubAlloc a new BJNX class with protection against memory exhaustion. */
+/*********************************************************************************/
+#ifdef NOT_USED
+static PBJNX BjnxNew(PGLOBAL g, PBVAL vlp, int type, int len)
+{
+ PBJNX bjnx;
+
+ try {
+ bjnx = new(g) BJNX(g, vlp, type, len);
+ } catch (...) {
+ if (trace(1023))
+ htrc("%s\n", g->Message);
+
+ PUSH_WARNING(g->Message);
+ bjnx = NULL;
+ } // end try/catch
+
+ return bjnx;
+} /* end of BjnxNew */
+#endif
+/* ----------------------------------- BSNX ------------------------------------ */
+
+/*********************************************************************************/
+/* BSNX public constructor. */
+/*********************************************************************************/
+BJNX::BJNX(PGLOBAL g) : BDOC(g)
+{
+ Row = NULL;
+ Bvalp = NULL;
+ Jpnp = NULL;
+ Jp = NULL;
+ Nodes = NULL;
+ Value = NULL;
+ //MulVal = NULL;
+ Jpath = NULL;
+ Buf_Type = TYPE_STRING;
+ Long = len;
+ Prec = 0;
+ Nod = 0;
+ Xnod = -1;
+ K = 0;
+ I = -1;
+ Imax = 9;
+ B = 0;
+ Xpd = false;
+ Parsed = false;
+ Found = false;
+ Wr = false;
+ Jb = false;
+ Changed = false;
+ Throw = false;
+} // end of BJNX constructor
+
+/*********************************************************************************/
+/* BSNX public constructor. */
+/*********************************************************************************/
+BJNX::BJNX(PGLOBAL g, PBVAL row, int type, int len, int prec, my_bool wr) : BDOC(g)
+{
+ Row = row;
+ Bvalp = NULL;
+ Jpnp = NULL;
+ Jp = NULL;
+ Nodes = NULL;
+ Value = AllocateValue(g, type, len, prec);
+ //MulVal = NULL;
+ Jpath = NULL;
+ Buf_Type = type;
+ Long = len;
+ Prec = prec;
+ Nod = 0;
+ Xnod = -1;
+ K = 0;
+ I = -1;
+ Imax = 9;
+ B = 0;
+ Xpd = false;
+ Parsed = false;
+ Found = false;
+ Wr = wr;
+ Jb = false;
+ Changed = false;
+ Throw = false;
+} // end of BJNX constructor
+
+/*********************************************************************************/
+/* SetJpath: set and parse the json path. */
+/*********************************************************************************/
+my_bool BJNX::SetJpath(PGLOBAL g, char* path, my_bool jb)
+{
+ // Check Value was allocated
+ if (Value)
+ Value->SetNullable(true);
+
+ Jpath = path;
+
+ // Parse the json path
+ Parsed = false;
+ Nod = 0;
+ Jb = jb;
+ return ParseJpath(g);
+} // end of SetJpath
+
+/*********************************************************************************/
+/* Analyse array processing options. */
+/*********************************************************************************/
+my_bool BJNX::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm)
+{
+ int n = (int)strlen(p);
+ my_bool dg = true, b = false;
+ PJNODE jnp = &Nodes[i];
+
+ if (*p) {
+ if (p[n - 1] == ']') {
+ p[--n] = 0;
+ } else if (!IsNum(p)) {
+ // Wrong array specification
+ sprintf(g->Message, "Invalid array specification %s", p);
+ return true;
+ } // endif p
+
+ } else
+ b = true;
+
+ // To check whether a numeric Rank was specified
+ dg = IsNum(p);
+
+ if (!n) {
+ // Default specifications
+ if (jnp->Op != OP_EXP) {
+ if (Wr) {
+ // Force append
+ jnp->Rank = INT_MAX32;
+ jnp->Op = OP_LE;
+ } else if (Jb) {
+ // Return a Json item
+ jnp->Op = OP_XX;
+ } else if (b) {
+ // Return 1st value (B is the index base)
+ jnp->Rank = B;
+ jnp->Op = OP_LE;
+ } else if (!Value->IsTypeNum()) {
+ jnp->CncVal = AllocateValue(g, PlugDup(g, ", "), TYPE_STRING);
+ jnp->Op = OP_CNC;
+ } else
+ jnp->Op = OP_ADD;
+
+ } // endif OP
+
+ } else if (dg) {
+ // Return nth value
+ jnp->Rank = atoi(p) - B;
+ jnp->Op = OP_EQ;
+ } else if (Wr) {
+ sprintf(g->Message, "Invalid specification %s in a write path", p);
+ return true;
+ } else if (n == 1) {
+ // Set the Op value;
+ switch (*p) {
+ case '+': jnp->Op = OP_ADD; break;
+ case 'x': jnp->Op = OP_MULT; break;
+ case '>': jnp->Op = OP_MAX; break;
+ case '<': jnp->Op = OP_MIN; break;
+ case '!': jnp->Op = OP_SEP; break; // Average
+ case '#': jnp->Op = OP_NUM; break;
+ case '*': jnp->Op = OP_EXP; break;
+ default:
+ sprintf(g->Message, "Invalid function specification %c", *p);
+ return true;
+ } // endswitch *p
+
+ } else if (*p == '"' && p[n - 1] == '"') {
+ // This is a concat specification
+ jnp->Op = OP_CNC;
+
+ if (n > 2) {
+ // Set concat intermediate string
+ p[n - 1] = 0;
+
+ if (trace(1))
+ htrc("Concat string=%s\n", p + 1);
+
+ jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
+ } // endif n
+
+ } else {
+ strcpy(g->Message, "Wrong array specification");
+ return true;
+ } // endif's
+
+ return false;
+} // end of SetArrayOptions
+
+/*********************************************************************************/
+/* Parse the eventual passed Jpath information. */
+/* This information can be specified in the Fieldfmt column option when */
+/* creating the table. It permits to indicate the position of the node */
+/* corresponding to that column. */
+/*********************************************************************************/
+my_bool BJNX::ParseJpath(PGLOBAL g)
+{
+ char* p, * p1 = NULL, * p2 = NULL, * pbuf = NULL;
+ int i;
+ my_bool a;
+
+ if (Parsed)
+ return false; // Already done
+ else if (!Jpath)
+ // Jpath = Name;
+ return true;
+
+ if (trace(1))
+ htrc("ParseJpath %s\n", SVP(Jpath));
+
+ if (!(pbuf = PlgDBDup(g, Jpath)))
+ return true;
+
+ if (*pbuf == '$') pbuf++;
+ if (*pbuf == '.') pbuf++;
+ if (*pbuf == '[') p1 = pbuf++;
+
+ // Estimate the required number of nodes
+ for (i = 0, p = pbuf; (p = NextChr(p, '.')); i++, p++)
+ Nod++; // One path node found
+
+ if (!(Nodes = (PJNODE)PlgDBSubAlloc(g, NULL, (++Nod) * sizeof(JNODE))))
+ return true;
+
+ memset(Nodes, 0, (Nod) * sizeof(JNODE));
+
+ // Analyze the Jpath for this column
+ for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
+ a = (p1 != NULL);
+ p1 = strchr(p, '[');
+ p2 = strchr(p, '.');
+
+ if (!p2)
+ p2 = p1;
+ else if (p1) {
+ if (p1 < p2)
+ p2 = p1;
+ else if (p1 == p2 + 1)
+ *p2++ = 0; // Old syntax .[
+ else
+ p1 = NULL;
+
+ } // endif p1
+
+ if (p2)
+ *p2++ = 0;
+
+ // Jpath must be explicit
+ if (a || *p == 0 || *p == '[' || IsNum(p)) {
+ // Analyse intermediate array processing
+ if (SetArrayOptions(g, p, i, Nodes[i - 1].Key))
+ return true;
+
+ } else if (*p == '*') {
+ if (Wr) {
+ sprintf(g->Message, "Invalid specification %c in a write path", *p);
+ return true;
+ } else // Return JSON
+ Nodes[i].Op = OP_XX;
+
+ } else {
+ Nodes[i].Key = p;
+ Nodes[i].Op = OP_EXIST;
+ } // endif's
+
+ } // endfor i, p
+
+ Nod = i;
+//MulVal = AllocateValue(g, Value);
+
+ if (trace(1))
+ for (i = 0; i < Nod; i++)
+ htrc("Node(%d) Key=%s Op=%d Rank=%d\n",
+ i, SVP(Nodes[i].Key), Nodes[i].Op, Nodes[i].Rank);
+
+ Parsed = true;
+ return false;
+} // end of ParseJpath
+
+/*********************************************************************************/
+/* Make a valid key from the passed argument. */
+/*********************************************************************************/
+PSZ BJNX::MakeKey(UDF_ARGS *args, int i)
+{
+ if (args->arg_count > (unsigned)i) {
+ int j = 0, n = args->attribute_lengths[i];
+ my_bool b; // true if attribute is zero terminated
+ PSZ p;
+ PCSZ s = args->attributes[i];
+
+ if (s && *s && (n || *s == '\'')) {
+ if ((b = (!n || !s[n])))
+ n = strlen(s);
+
+ if (IsArgJson(args, i))
+ j = (int)(strchr(s, '_') - s + 1);
+
+ if (j && n > j) {
+ s += j;
+ n -= j;
+ } else if (*s == '\'' && s[n-1] == '\'') {
+ s++;
+ n -= 2;
+ b = false;
+ } // endif *s
+
+ if (n < 1)
+ return NewStr((PSZ)"Key");
+
+ if (!b) {
+ p = (PSZ)BsonSubAlloc(n + 1);
+ memcpy(p, s, n);
+ p[n] = 0;
+ return p;
+ } // endif b
+
+ } // endif s
+
+ return NewStr((PSZ)s);
+ } // endif count
+
+ return NewStr((PSZ)"Key");
+} // end of MakeKey
+
+/*********************************************************************************/
+/* MakeJson: Make the Json tree to serialize. */
+/*********************************************************************************/
+PBVAL BJNX::MakeJson(PGLOBAL g, PBVAL bvp, int n)
+{
+ PBVAL vlp, jvp = bvp;
+
+ Jb = false;
+
+ if (n < Nod -1) {
+ if (bvp->Type == TYPE_JAR) {
+ int ars = GetArraySize(bvp);
+ PJNODE jnp = &Nodes[n];
+
+ jvp = NewVal(TYPE_JAR);
+ jnp->Op = OP_EQ;
+
+ for (int i = 0; i < ars; i++) {
+ jnp->Rank = i;
+ vlp = GetRowValue(g, bvp, n);
+ AddArrayValue(jvp, DupVal(vlp));
+ } // endfor i
+
+ jnp->Op = OP_XX;
+ jnp->Rank = 0;
+ } else if(bvp->Type == TYPE_JOB) {
+ jvp = NewVal(TYPE_JOB);
+
+ for (PBPR prp = GetObject(bvp); prp; prp = GetNext(prp)) {
+ vlp = GetRowValue(g, GetVlp(prp), n + 1);
+ SetKeyValue(jvp, vlp, MZP(prp->Key));
+ } // endfor prp
+
+ } // endif Type
+
+ } // endif n
+
+ Jb = true;
+ return jvp;
+} // end of MakeJson
+
+/*********************************************************************************/
+/* SetValue: Set a value from a BVALUE contains. */
+/*********************************************************************************/
+void BJNX::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp)
+{
+ if (vlp) {
+ vp->SetNull(false);
+
+ if (Jb) {
+ vp->SetValue_psz(Serialize(g, vlp, NULL, 0));
+ Jb = false;
+ } else switch (vlp->Type) {
+ case TYPE_DTM:
+ case TYPE_STRG:
+ vp->SetValue_psz(GetString(vlp));
+ break;
+ case TYPE_INTG:
+ vp->SetValue(GetInteger(vlp));
+ break;
+ case TYPE_BINT:
+ vp->SetValue(GetBigint(vlp));
+ break;
+ case TYPE_DBL:
+ case TYPE_FLOAT:
+ if (vp->IsTypeNum())
+ vp->SetValue(GetDouble(vlp));
+ else // Get the proper number of decimals
+ vp->SetValue_psz(GetString(vlp));
+
+ break;
+ case TYPE_BOOL:
+ if (vp->IsTypeNum())
+ vp->SetValue(GetInteger(vlp) ? 1 : 0);
+ else
+ vp->SetValue_psz(GetString(vlp));
+
+ break;
+ case TYPE_JAR:
+ vp->SetValue_psz(GetArrayText(g, vlp, NULL));
+ break;
+ case TYPE_JOB:
+ vp->SetValue_psz(GetObjectText(g, vlp, NULL));
+ break;
+ case TYPE_NULL:
+ vp->SetNull(true);
+ /* fall through */
+ default:
+ vp->Reset();
+ } // endswitch Type
+
+ } else {
+ vp->SetNull(true);
+ vp->Reset();
+ } // endif val
+
+} // end of SetJsonValue
+
+/*********************************************************************************/
+/* GetJson: */
+/*********************************************************************************/
+PBVAL BJNX::GetJson(PGLOBAL g)
+{
+ return GetRowValue(g, Row, 0);
+} // end of GetJson
+
+/*********************************************************************************/
+/* ReadValue: */
+/*********************************************************************************/
+void BJNX::ReadValue(PGLOBAL g)
+{
+ Value->SetValue_pval(GetColumnValue(g, Row, 0));
+} // end of ReadValue
+
+/*********************************************************************************/
+/* GetColumnValue: */
+/*********************************************************************************/
+PVAL BJNX::GetColumnValue(PGLOBAL g, PBVAL row, int i)
+{
+ PBVAL vlp = GetRowValue(g, row, i);
+
+ SetJsonValue(g, Value, vlp);
+ return Value;
+} // end of GetColumnValue
+
+/*********************************************************************************/
+/* GetRowValue: */
+/*********************************************************************************/
+PBVAL BJNX::GetRowValue(PGLOBAL g, PBVAL row, int i)
+{
+ PBVAL bap;
+ PBVAL vlp = NULL;
+
+ for (; i < Nod && row; i++) {
+ if (Nodes[i].Op == OP_NUM) {
+ Value->SetValue(row->Type == TYPE_JAR ? GetArraySize(row) : 1);
+ vlp = NewVal(Value);
+ return vlp;
+ } else if (Nodes[i].Op == OP_XX) {
+ return MakeJson(g, row, i);
+ } else if (Nodes[i].Op == OP_EXP) {
+ PUSH_WARNING("Expand not supported by this function");
+ return NULL;
+ } else switch (row->Type) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key) {
+ // Expected Array was not there
+ if (Nodes[i].Op == OP_LE) {
+ if (i < Nod - 1)
+ continue;
+ else
+ vlp = row; // DupVal(g, row) ???
+
+ } else {
+ strcpy(g->Message, "Unexpected object");
+ vlp = NULL;
+ } //endif Op
+
+ } else
+ vlp = GetKeyValue(row, Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ bap = row;
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
+ vlp = GetArrayValue(bap, Nodes[i].Rank);
+ else if (Nodes[i].Op == OP_EXP)
+ return (PBVAL)ExpandArray(g, bap, i);
+ else
+ return NewVal(CalculateArray(g, bap, i));
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ vlp = GetArrayValue(bap, 0);
+ i--;
+ } // endif's
+
+ break;
+ case TYPE_JVAL:
+ vlp = row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->Type);
+ vlp = NULL;
+ } // endswitch Type
+
+ row = vlp;
+ } // endfor i
+
+ return vlp;
+} // end of GetRowValue
+
+/*********************************************************************************/
+/* ExpandArray: */
+/*********************************************************************************/
+PVAL BJNX::ExpandArray(PGLOBAL g, PBVAL arp, int n)
+{
+ strcpy(g->Message, "Expand cannot be done by this function");
+ return NULL;
+} // end of ExpandArray
+
+/*********************************************************************************/
+/* Get the value used for calculating the array. */
+/*********************************************************************************/
+PVAL BJNX::GetCalcValue(PGLOBAL g, PBVAL bap, int n)
+{
+ // For calculated arrays, a local Value must be used
+ int lng = 0;
+ short type = 0, prec = 0;
+ bool b = n < Nod - 1;
+ PVAL valp;
+ PBVAL vlp, vp;
+ OPVAL op = Nodes[n].Op;
+
+ switch (op) {
+ case OP_NUM:
+ type = TYPE_INT;
+ break;
+ case OP_ADD:
+ case OP_MULT:
+ if (!IsTypeNum(Buf_Type)) {
+ type = TYPE_INT;
+ prec = 0;
+
+ for (vlp = GetArray(bap); vlp; vlp = GetNext(vlp)) {
+ vp = (b && IsJson(vlp)) ? GetRowValue(g, vlp, n + 1) : vlp;
+
+ switch (vp->Type) {
+ case TYPE_BINT:
+ if (type == TYPE_INT)
+ type = TYPE_BIGINT;
+
+ break;
+ case TYPE_DBL:
+ case TYPE_FLOAT:
+ type = TYPE_DOUBLE;
+ prec = MY_MAX(prec, vp->Nd);
+ break;
+ default:
+ break;
+ } // endswitch Type
+
+ } // endfor vlp
+
+ } else {
+ type = Buf_Type;
+ prec = GetPrecision();
+ } // endif Buf_Type
+
+ break;
+ case OP_SEP:
+ if (IsTypeChar(Buf_Type)) {
+ type = TYPE_DOUBLE;
+ prec = 2;
+ } else {
+ type = Buf_Type;
+ prec = GetPrecision();
+ } // endif Buf_Type
+
+ break;
+ case OP_MIN:
+ case OP_MAX:
+ type = Buf_Type;
+ lng = Long;
+ prec = GetPrecision();
+ break;
+ case OP_CNC:
+ type = TYPE_STRING;
+
+ if (IsTypeChar(Buf_Type)) {
+ lng = (Long) ? Long : 512;
+ prec = GetPrecision();
+ } else
+ lng = 512;
+
+ break;
+ default:
+ break;
+ } // endswitch Op
+
+ return valp = AllocateValue(g, type, lng, prec);
+} // end of GetCalcValue
+
+/*********************************************************************************/
+/* CalculateArray */
+/*********************************************************************************/
+PVAL BJNX::CalculateArray(PGLOBAL g, PBVAL bap, int n)
+{
+ int i, ars = GetArraySize(bap), nv = 0;
+ bool err;
+ OPVAL op = Nodes[n].Op;
+ PVAL val[2], vp = GetCalcValue(g, bap, n);
+ PVAL mulval = AllocateValue(g, vp);
+ PBVAL bvrp, bvp;
+ BVAL bval;
+
+ vp->Reset();
+ xtrc(1, "CalculateArray size=%d op=%d\n", ars, op);
+
+ try {
+ for (i = 0; i < ars; i++) {
+ bvrp = GetArrayValue(bap, i);
+ xtrc(1, "i=%d nv=%d\n", i, nv);
+
+ if (!IsValueNull(bvrp) || (op == OP_CNC && GetJsonNull())) {
+ if (IsValueNull(bvrp)) {
+ SetString(bvrp, NewStr(GetJsonNull()), 0);
+ bvp = bvrp;
+ } else if (n < Nod - 1 && IsJson(bvrp)) {
+ SetValue(&bval, GetColumnValue(g, bvrp, n + 1));
+ bvp = &bval;
+ } else
+ bvp = bvrp;
+
+ if (trace(1))
+ htrc("bvp=%s null=%d\n",
+ GetString(bvp), IsValueNull(bvp) ? 1 : 0);
+
+ if (!nv++) {
+ SetJsonValue(g, vp, bvp);
+ continue;
+ } else
+ SetJsonValue(g, mulval, bvp);
+
+ if (!mulval->IsNull()) {
+ switch (op) {
+ case OP_CNC:
+ if (Nodes[n].CncVal) {
+ val[0] = Nodes[n].CncVal;
+ err = vp->Compute(g, val, 1, op);
+ } // endif CncVal
+
+ val[0] = mulval;
+ err = vp->Compute(g, val, 1, op);
+ break;
+ // case OP_NUM:
+ case OP_SEP:
+ val[0] = vp;
+ val[1] = mulval;
+ err = vp->Compute(g, val, 2, OP_ADD);
+ break;
+ default:
+ val[0] = vp;
+ val[1] = mulval;
+ err = vp->Compute(g, val, 2, op);
+ } // endswitch Op
+
+ if (err)
+ vp->Reset();
+
+ if (trace(1)) {
+ char buf(32);
+
+ htrc("vp='%s' err=%d\n",
+ vp->GetCharString(&buf), err ? 1 : 0);
+ } // endif trace
+
+ } // endif Zero
+
+ } // endif jvrp
+
+ } // endfor i
+
+ if (op == OP_SEP) {
+ // Calculate average
+ mulval->SetValue(nv);
+ val[0] = vp;
+ val[1] = mulval;
+
+ if (vp->Compute(g, val, 2, OP_DIV))
+ vp->Reset();
+
+ } // endif Op
+
+ } catch (int n) {
+ xtrc(1, "Exception %d: %s\n", n, g->Message);
+ PUSH_WARNING(g->Message);
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+ return vp;
+} // end of CalculateArray
+
+/***********************************************************************/
+/* GetRow: Set the complete path of the object to be set. */
+/***********************************************************************/
+PBVAL BJNX::GetRow(PGLOBAL g)
+{
+ PBVAL val = NULL;
+ PBVAL arp;
+ PBVAL nwr, row = Row;
+
+ for (int i = 0; i < Nod - 1 && row; i++) {
+ if (Nodes[i].Op == OP_XX)
+ break;
+ else if (Nodes[i].Op == OP_EXP) {
+ PUSH_WARNING("Expand not supported by this function");
+ return NULL;
+ } else switch (row->Type) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key)
+ // Expected Array was not there, wrap the value
+ continue;
+
+ val = GetKeyValue(row, Nodes[i].Key);
+ break;
+ case TYPE_JAR:
+ arp = row;
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EQ)
+ val = GetArrayValue(arp, Nodes[i].Rank);
+ else
+ val = GetArrayValue(arp, Nodes[i].Rx);
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ val = GetArrayValue(arp, 0);
+ i--;
+ } // endif Nodes
+
+ break;
+ case TYPE_JVAL:
+ val = MVP(row->To_Val);
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->Type);
+ val = NULL;
+ } // endswitch Type
+
+ if (val) {
+ row = val;
+ } else {
+ // Construct missing objects
+ for (i++; row && i < Nod; i++) {
+ if (Nodes[i].Op == OP_XX)
+ break;
+
+ // Construct new row
+ nwr = NewVal();
+
+ if (row->Type == TYPE_JOB) {
+ SetKeyValue(row, MOF(nwr), Nodes[i - 1].Key);
+ } else if (row->Type == TYPE_JAR) {
+ AddArrayValue(row, MOF(nwr));
+ } else {
+ strcpy(g->Message, "Wrong type when writing new row");
+ nwr = NULL;
+ } // endif's
+
+ row = nwr;
+ } // endfor i
+
+ break;
+ } // endelse
+
+ } // endfor i
+
+ return row;
+} // end of GetRow
+
+/***********************************************************************/
+/* WriteValue: */
+/***********************************************************************/
+my_bool BJNX::WriteValue(PGLOBAL g, PBVAL jvalp)
+{
+ PBVAL objp = NULL;
+ PBVAL arp = NULL;
+ PBVAL jvp = NULL;
+ PBVAL row = GetRow(g);
+
+ if (!row)
+ return true;
+
+ switch (row->Type) {
+ case TYPE_JOB: objp = row; break;
+ case TYPE_JAR: arp = row; break;
+ case TYPE_JVAL: jvp = MVP(row->To_Val); break;
+ default:
+ strcpy(g->Message, "Invalid target type");
+ return true;
+ } // endswitch Type
+
+ if (arp) {
+ if (!Nodes[Nod - 1].Key) {
+ if (Nodes[Nod - 1].Op == OP_EQ)
+ SetArrayValue(arp, jvalp, Nodes[Nod - 1].Rank);
+ else
+ AddArrayValue(arp, MOF(jvalp));
+
+ } // endif Key
+
+ } else if (objp) {
+ if (Nodes[Nod - 1].Key)
+ SetKeyValue(objp, MOF(jvalp), Nodes[Nod - 1].Key);
+
+ } else if (jvp)
+ SetValueVal(jvp, jvalp);
+
+ return false;
+} // end of WriteValue
+
+/*********************************************************************************/
+/* GetRowValue: */
+/*********************************************************************************/
+my_bool BJNX::DeleteItem(PGLOBAL g, PBVAL row)
+{
+ int n = -1;
+ my_bool b = false;
+ bool loop;
+ PBVAL vlp, pvp, rwp;
+
+ do {
+ loop = false;
+ vlp = NULL;
+ pvp = rwp = row;
+
+ for (int i = 0; i < Nod && rwp; i++) {
+ if (Nodes[i].Op == OP_XX)
+ break;
+ else switch (rwp->Type) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key) {
+ vlp = NULL;
+ } else
+ vlp = GetKeyValue(rwp, Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EXP) {
+ if (loop) {
+ PUSH_WARNING("Only one expand can be handled");
+ return b;
+ } // endif loop
+
+ n++;
+ } else
+ n = Nodes[i].Rank;
+
+ vlp = GetArrayValue(rwp, n);
+
+ if (GetNext(vlp) && Nodes[i].Op == OP_EXP)
+ loop = true;
+
+ } else
+ vlp = NULL;
+
+ break;
+ case TYPE_JVAL:
+ vlp = rwp;
+ break;
+ default:
+ vlp = NULL;
+ } // endswitch Type
+
+ pvp = rwp;
+ rwp = vlp;
+ vlp = NULL;
+ } // endfor i
+
+ if (rwp) {
+ if (Nodes[Nod - 1].Op == OP_XX) {
+ if (!IsJson(rwp))
+ rwp->Type = TYPE_NULL;
+
+ rwp->To_Val = 0;
+ } else switch (pvp->Type) {
+ case TYPE_JOB:
+ b = DeleteKey(pvp, Nodes[Nod - 1].Key);
+ break;
+ case TYPE_JAR:
+ if (Nodes[Nod - 1].Op == OP_EXP) {
+ pvp->To_Val = 0;
+ loop = false;
+ } else
+ b = DeleteValue(pvp, n);
+
+ break;
+ default:
+ break;
+ } // endswitch Type
+
+ } // endif rwp
+
+ } while (loop);
+
+ return b;
+} // end of DeleteItem
+
+/*********************************************************************************/
+/* CheckPath: Checks whether the path exists in the document. */
+/*********************************************************************************/
+my_bool BJNX::CheckPath(PGLOBAL g)
+{
+ PBVAL val = NULL;
+ PBVAL row = Row;
+
+ for (int i = 0; i < Nod && row; i++) {
+ val = NULL;
+
+ if (Nodes[i].Op == OP_NUM || Nodes[i].Op == OP_XX) {
+ } else switch (row->Type) {
+ case TYPE_JOB:
+ if (Nodes[i].Key)
+ val = GetKeyValue(row, Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ if (!Nodes[i].Key)
+ if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
+ val = GetArrayValue(row, Nodes[i].Rank);
+
+ break;
+ case TYPE_JVAL:
+ val = row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->Type);
+ } // endswitch Type
+
+ if (i < Nod-1)
+ if (!(row = (IsJson(val)) ? val : NULL))
+ val = NULL;
+
+ } // endfor i
+
+ return (val != NULL);
+} // end of CheckPath
+
+/*********************************************************************************/
+/* Check if a path was specified and set jvp according to it. */
+/*********************************************************************************/
+my_bool BJNX::CheckPath(PGLOBAL g, UDF_ARGS *args, PBVAL jsp, PBVAL& jvp, int n)
+{
+ for (uint i = n; i < args->arg_count; i++)
+ if (args->arg_type[i] == STRING_RESULT && args->args[i]) {
+ // A path to a subset of the json tree is given
+ char *path = MakePSZ(g, args, i);
+
+ if (path) {
+ Row = jsp;
+
+ if (SetJpath(g, path))
+ return true;
+
+ if (!(jvp = GetJson(g))) {
+ sprintf(g->Message, "No sub-item at '%s'", path);
+ return true;
+ } else
+ return false;
+
+ } else {
+ strcpy(g->Message, "Path argument is null");
+ return true;
+ } // endif path
+
+ } // endif type
+
+ jvp = jsp;
+ return false;
+} // end of CheckPath
+
+/*********************************************************************************/
+/* Locate a value in a JSON tree: */
+/*********************************************************************************/
+PSZ BJNX::Locate(PGLOBAL g, PBVAL jsp, PBVAL jvp, int k)
+{
+ PSZ str = NULL;
+ my_bool err = true;
+
+ g->Message[0] = 0;
+
+ if (!jsp) {
+ strcpy(g->Message, "Null json tree");
+ return NULL;
+ } // endif jsp
+
+ try {
+ // Write to the path string
+ Jp = new(g) JOUTSTR(g);
+ Jp->WriteChr('$');
+ Bvalp = jvp;
+ K = k;
+
+ switch (jsp->Type) {
+ case TYPE_JAR:
+ err = LocateArray(g, jsp);
+ break;
+ case TYPE_JOB:
+ err = LocateObject(g, jsp);
+ break;
+ case TYPE_JVAL:
+ err = LocateValue(g, MVP(jsp->To_Val));
+ break;
+ default:
+ err = true;
+ } // endswitch Type
+
+ if (err) {
+ if (!g->Message[0])
+ strcpy(g->Message, "Invalid json tree");
+
+ } else if (Found) {
+ Jp->WriteChr('\0');
+ PlugSubAlloc(g, NULL, Jp->N);
+ str = Jp->Strp;
+ } // endif's
+
+ } catch (int n) {
+ xtrc(1, "Exception %d: %s\n", n, g->Message);
+ PUSH_WARNING(g->Message);
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+ return str;
+} // end of Locate
+
+/*********************************************************************************/
+/* Locate in a JSON Array. */
+/*********************************************************************************/
+my_bool BJNX::LocateArray(PGLOBAL g, PBVAL jarp)
+{
+ char s[16];
+ int n = GetArraySize(jarp);
+ size_t m = Jp->N;
+
+ for (int i = 0; i < n && !Found; i++) {
+ Jp->N = m;
+ sprintf(s, "[%d]", i + B);
+
+ if (Jp->WriteStr(s))
+ return true;
+
+ if (LocateValue(g, GetArrayValue(jarp, i)))
+ return true;
+
+ } // endfor i
+
+ return false;
+} // end of LocateArray
+
+/*********************************************************************************/
+/* Locate in a JSON Object. */
+/*********************************************************************************/
+my_bool BJNX::LocateObject(PGLOBAL g, PBVAL jobp)
+{
+ size_t m;
+
+ if (Jp->WriteChr('.'))
+ return true;
+
+ m = Jp->N;
+
+ for (PBPR pair = GetObject(jobp); pair && !Found; pair = GetNext(pair)) {
+ Jp->N = m;
+
+ if (Jp->WriteStr(MZP(pair->Key)))
+ return true;
+
+ if (LocateValue(g, GetVlp(pair)))
+ return true;
+
+ } // endfor i
+
+ return false;
+} // end of LocateObject
+
+/*********************************************************************************/
+/* Locate a JSON Value. */
+/*********************************************************************************/
+my_bool BJNX::LocateValue(PGLOBAL g, PBVAL jvp)
+{
+ if (CompareTree(g, Bvalp, jvp))
+ Found = (--K == 0);
+ else if (jvp->Type == TYPE_JAR)
+ return LocateArray(g, jvp);
+ else if (jvp->Type == TYPE_JOB)
+ return LocateObject(g, jvp);
+
+ return false;
+} // end of LocateValue
+
+/*********************************************************************************/
+/* Locate all occurrences of a value in a JSON tree: */
+/*********************************************************************************/
+PSZ BJNX::LocateAll(PGLOBAL g, PBVAL jsp, PBVAL bvp, int mx)
+{
+ PSZ str = NULL;
+ my_bool err = true;
+ PJPN jnp;
+
+ if (!jsp) {
+ strcpy(g->Message, "Null json tree");
+ return NULL;
+ } // endif jsp
+
+ try {
+ jnp = (PJPN)PlugSubAlloc(g, NULL, sizeof(JPN) * mx);
+ memset(jnp, 0, sizeof(JPN) * mx);
+ g->Message[0] = 0;
+
+ // Write to the path string
+ Jp = new(g)JOUTSTR(g);
+ Bvalp = bvp;
+ Imax = mx - 1;
+ Jpnp = jnp;
+ Jp->WriteChr('[');
+
+ switch (jsp->Type) {
+ case TYPE_JAR:
+ err = LocateArrayAll(g, jsp);
+ break;
+ case TYPE_JOB:
+ err = LocateObjectAll(g, jsp);
+ break;
+ case TYPE_JVAL:
+ err = LocateValueAll(g, MVP(jsp->To_Val));
+ break;
+ default:
+ err = LocateValueAll(g, jsp);
+ } // endswitch Type
+
+ if (!err) {
+ if (Jp->N > 1)
+ Jp->N--;
+
+ Jp->WriteChr(']');
+ Jp->WriteChr('\0');
+ PlugSubAlloc(g, NULL, Jp->N);
+ str = Jp->Strp;
+ } else if (!g->Message[0])
+ strcpy(g->Message, "Invalid json tree");
+
+ } catch (int n) {
+ xtrc(1, "Exception %d: %s\n", n, g->Message);
+ PUSH_WARNING(g->Message);
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+ return str;
+} // end of LocateAll
+
+/*********************************************************************************/
+/* Locate in a JSON Array. */
+/*********************************************************************************/
+my_bool BJNX::LocateArrayAll(PGLOBAL g, PBVAL jarp)
+{
+ int i = 0;
+
+ if (I < Imax) {
+ Jpnp[++I].Type = TYPE_JAR;
+
+ for (PBVAL vp = GetArray(jarp); vp; vp = GetNext(vp)) {
+ Jpnp[I].N = i;
+
+ if (LocateValueAll(g, GetArrayValue(jarp, i)))
+ return true;
+
+ i++;
+ } // endfor i
+
+ I--;
+ } // endif I
+
+ return false;
+} // end of LocateArrayAll
+
+/*********************************************************************************/
+/* Locate in a JSON Object. */
+/*********************************************************************************/
+my_bool BJNX::LocateObjectAll(PGLOBAL g, PBVAL jobp)
+{
+ if (I < Imax) {
+ Jpnp[++I].Type = TYPE_JOB;
+
+ for (PBPR pair = GetObject(jobp); pair; pair = GetNext(pair)) {
+ Jpnp[I].Key = MZP(pair->Key);
+
+ if (LocateValueAll(g, GetVlp(pair)))
+ return true;
+
+ } // endfor i
+
+ I--;
+ } // endif I
+
+ return false;
+} // end of LocateObjectAll
+
+/*********************************************************************************/
+/* Locate a JSON Value. */
+/*********************************************************************************/
+my_bool BJNX::LocateValueAll(PGLOBAL g, PBVAL jvp)
+{
+ if (CompareTree(g, Bvalp, jvp))
+ return AddPath();
+ else if (jvp->Type == TYPE_JAR)
+ return LocateArrayAll(g, jvp);
+ else if (jvp->Type == TYPE_JOB)
+ return LocateObjectAll(g, jvp);
+
+ return false;
+} // end of LocateValueAll
+
+/*********************************************************************************/
+/* Compare two JSON trees. */
+/*********************************************************************************/
+my_bool BJNX::CompareTree(PGLOBAL g, PBVAL jp1, PBVAL jp2)
+{
+ if (!jp1 || !jp2 || jp1->Type != jp2->Type || GetSize(jp1) != GetSize(jp2))
+ return false;
+
+ my_bool found = true;
+
+ if (jp1->Type == TYPE_JAR) {
+ for (int i = 0; found && i < GetArraySize(jp1); i++)
+ found = (CompareValues(g, GetArrayValue(jp1, i), GetArrayValue(jp2, i)));
+
+ } else if (jp1->Type == TYPE_JOB) {
+ PBPR p1 = GetObject(jp1), p2 = GetObject(jp2);
+
+ // Keys can be differently ordered
+ for (; found && p1 && p2; p1 = GetNext(p1))
+ found = CompareValues(g, GetVlp(p1), GetKeyValue(jp2, GetKey(p1)));
+
+ } else if (jp1->Type == TYPE_JVAL) {
+ found = CompareTree(g, MVP(jp1->To_Val), (MVP(jp2->To_Val)));
+ } else
+ found = CompareValues(g, jp1, jp2);
+
+ return found;
+} // end of CompareTree
+
+/*********************************************************************************/
+/* Compare two VAL values and return true if they are equal. */
+/*********************************************************************************/
+my_bool BJNX::CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2)
+{
+ my_bool b = false;
+
+ if (v1 && v2)
+ switch (v1->Type) {
+ case TYPE_JAR:
+ case TYPE_JOB:
+ if (v2->Type == v1->Type)
+ b = CompareTree(g, v1, v2);
+
+ break;
+ case TYPE_STRG:
+ if (v2->Type == TYPE_STRG) {
+ if (v1->Nd || v2->Nd) // Case insensitive
+ b = (!stricmp(MZP(v1->To_Val), MZP(v2->To_Val)));
+ else
+ b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
+
+ } // endif Type
+
+ break;
+ case TYPE_DTM:
+ if (v2->Type == TYPE_DTM)
+ b = (!strcmp(MZP(v1->To_Val), MZP(v2->To_Val)));
+
+ break;
+ case TYPE_INTG:
+ if (v2->Type == TYPE_INTG)
+ b = (v1->N == v2->N);
+ else if (v2->Type == TYPE_BINT)
+ b = ((longlong)v1->N == LLN(v2->To_Val));
+
+ break;
+ case TYPE_BINT:
+ if (v2->Type == TYPE_INTG)
+ b = (LLN(v1->To_Val) == (longlong)v2->N);
+ else if (v2->Type == TYPE_BINT)
+ b = (LLN(v1->To_Val) == LLN(v2->To_Val));
+
+ break;
+ case TYPE_FLOAT:
+ if (v2->Type == TYPE_FLOAT)
+ b = (v1->F == v2->F);
+ else if (v2->Type == TYPE_DBL)
+ b = ((double)v1->F == DBL(v2->To_Val));
+
+ break;
+ case TYPE_DBL:
+ if (v2->Type == TYPE_DBL)
+ b = (DBL(v1->To_Val) == DBL(v2->To_Val));
+ else if (v2->Type == TYPE_FLOAT)
+ b = (DBL(v1->To_Val) == (double)v2->F);
+
+ break;
+ case TYPE_BOOL:
+ if (v2->Type == TYPE_BOOL)
+ b = (v1->B == v2->B);
+
+ break;
+ case TYPE_NULL:
+ b = (v2->Type == TYPE_NULL);
+ break;
+ default:
+ break;
+ } // endswitch Type
+
+ else
+ b = (!v1 && !v2);
+
+ return b;
+} // end of CompareValues
+
+/*********************************************************************************/
+/* Add the found path to the list. */
+/*********************************************************************************/
+my_bool BJNX::AddPath(void)
+{
+ char s[16];
+
+ if (Jp->WriteStr("\"$"))
+ return true;
+
+ for (int i = 0; i <= I; i++) {
+ if (Jpnp[i].Type == TYPE_JAR) {
+ sprintf(s, "[%d]", Jpnp[i].N + B);
+
+ if (Jp->WriteStr(s))
+ return true;
+
+ } else {
+ if (Jp->WriteChr('.'))
+ return true;
+
+ if (Jp->WriteStr(Jpnp[i].Key))
+ return true;
+
+ } // endif's
+
+ } // endfor i
+
+ if (Jp->WriteStr("\","))
+ return true;
+
+ return false;
+} // end of AddPath
+
+/*********************************************************************************/
+/* Make a JSON value from the passed argument. */
+/*********************************************************************************/
+PBVAL BJNX::MakeValue(UDF_ARGS *args, uint i, bool b, PBVAL *top)
+{
+ char *sap = (args->arg_count > i) ? args->args[i] : NULL;
+ int n, len;
+ int ci;
+ long long bigint;
+ PGLOBAL& g = G;
+ PBVAL jvp = NewVal();
+
+ if (top)
+ *top = NULL;
+
+ if (sap) switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ if ((len = args->lengths[i])) {
+ if ((n = IsArgJson(args, i)) < 3)
+ sap = MakePSZ(g, args, i);
+
+ if (n) {
+ if (n == 3) {
+ PBSON bsp = (PBSON)sap;
+
+ if (i == 0) {
+ if (top)
+ *top = (PBVAL)bsp->Top;
+
+ jvp = (PBVAL)bsp->Jsp;
+ G = bsp->G;
+ Base = G->Sarea;
+ } else {
+ BJNX bnx(bsp->G);
+
+ jvp = MoveJson(&bnx, (PBVAL)bsp->Jsp);
+ } // endelse i
+
+ } else {
+ if (n == 2) {
+ if (!(sap = GetJsonFile(g, sap))) {
+ PUSH_WARNING(g->Message);
+ return jvp;
+ } // endif sap
+
+ len = strlen(sap);
+ } // endif n
+
+ if (!(jvp = ParseJson(g, sap, strlen(sap))))
+ PUSH_WARNING(g->Message);
+ else if (top)
+ *top = jvp;
+
+ } // endif's n
+
+ } else {
+ PBVAL bp = NULL;
+
+ if (b) {
+ if (strchr("[{ \t\r\n", *sap)) {
+ // Check whether this string is a valid json string
+ JsonMemSave(g);
+
+ if (!(bp = ParseJson(g, sap, strlen(sap))))
+ JsonSubSet(g); // Recover suballocated memory
+
+ g->Saved_Size = 0;
+ } else {
+ // Perhaps a file name
+ char* s = GetJsonFile(g, sap);
+
+ if (s)
+ bp = ParseJson(g, s, strlen(s));
+
+ } // endif's
+
+ } // endif b
+
+ if (!bp) {
+ ci = (strnicmp(args->attributes[i], "ci", 2)) ? 0 : 1;
+ SetString(jvp, sap, ci);
+ } else {
+ if (top)
+ *top = bp;
+
+ jvp = bp;
+ } // endif bp
+
+ } // endif n
+
+ } // endif len
+
+ break;
+ case INT_RESULT:
+ bigint = *(long long*)sap;
+
+ if ((bigint == 0LL && !strcmp(args->attributes[i], "FALSE")) ||
+ (bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
+ SetBool(jvp, (char)bigint);
+ else
+ SetBigint(jvp, bigint);
+
+ break;
+ case REAL_RESULT:
+ SetFloat(jvp, *(double*)sap);
+ break;
+ case DECIMAL_RESULT:
+ SetFloat(jvp, MakePSZ(g, args, i));
+ break;
+ case TIME_RESULT:
+ case ROW_RESULT:
+ default:
+ break;
+ } // endswitch arg_type
+
+ return jvp;
+} // end of MakeValue
+
+/*********************************************************************************/
+/* Try making a JSON value of the passed type from the passed argument. */
+/*********************************************************************************/
+PBVAL BJNX::MakeTypedValue(PGLOBAL g, UDF_ARGS *args, uint i, JTYP type, PBVAL *top)
+{
+ char *sap;
+ PBVAL jsp;
+ PBVAL jvp = MakeValue(args, i, false, top);
+
+ //if (type == TYPE_JSON) {
+ // if (jvp->GetValType() >= TYPE_JSON)
+ // return jvp;
+
+ //} else if (jvp->GetValType() == type)
+ // return jvp;
+
+ if (jvp->Type == TYPE_STRG) {
+ sap = GetString(jvp);
+
+ if ((jsp = ParseJson(g, sap, strlen(sap)))) {
+ if ((type == TYPE_JSON && jsp->Type != TYPE_JVAL) || jsp->Type == type) {
+ if (top)
+ *top = jvp;
+
+ SetValueVal(jvp, jsp);
+ } // endif Type
+
+ } // endif jsp
+
+ } // endif Type
+
+ return jvp;
+} // end of MakeTypedValue
+
+/*********************************************************************************/
+/* Parse a json file. */
+/*********************************************************************************/
+PBVAL BJNX::ParseJsonFile(PGLOBAL g, char *fn, int& pty, size_t& len)
+{
+ char *memory;
+ HANDLE hFile;
+ MEMMAP mm;
+ PBVAL jsp;
+
+ // Create the mapping file object
+ hFile = CreateFileMap(g, fn, &mm, MODE_READ, false);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+
+ if (!(*g->Message))
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int)rc, fn);
+
+ return NULL;
+ } // endif hFile
+
+ // Get the file size
+ len = (size_t)mm.lenL;
+
+ if (mm.lenH)
+ len += mm.lenH;
+
+ memory = (char *)mm.memory;
+
+ if (!len) { // Empty or deleted file
+ CloseFileHandle(hFile);
+ return NULL;
+ } // endif len
+
+ if (!memory) {
+ CloseFileHandle(hFile);
+ sprintf(g->Message, MSG(MAP_VIEW_ERROR), fn, GetLastError());
+ return NULL;
+ } // endif Memory
+
+ CloseFileHandle(hFile); // Not used anymore
+
+ // Parse the json file and allocate its tree structure
+ g->Message[0] = 0;
+ jsp = ParseJson(g, memory, len);
+ pty = pretty;
+ CloseMemMap(memory, len);
+ return jsp;
+} // end of ParseJsonFile
+
+/*********************************************************************************/
+/* Make the result according to the first argument type. */
+/*********************************************************************************/
+char *BJNX::MakeResult(UDF_ARGS *args, PBVAL top, uint n)
+{
+ char *str = NULL;
+ PGLOBAL& g = G;
+
+ if (IsArgJson(args, 0) == 2) {
+ // Make the change in the json file
+ PSZ fn = MakePSZ(g, args, 0);
+
+ if (Changed) {
+ int pretty = 2;
+
+ for (uint i = n; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT) {
+ pretty = (int)*(longlong*)args->args[i];
+ break;
+ } // endif type
+
+ if (!Serialize(g, top, fn, pretty))
+ PUSH_WARNING(g->Message);
+
+ Changed = false;
+ } // endif Changed
+
+ str = fn;
+ } else if (IsArgJson(args, 0) == 3) {
+ PBSON bsp = (PBSON)args->args[0];
+
+ if (bsp->Filename) {
+ if (Changed) {
+ // Make the change in the json file
+ if (!Serialize(g, (PBVAL)top, bsp->Filename, bsp->Pretty))
+ PUSH_WARNING(g->Message);
+
+ Changed = false;
+ } // endif Changed
+
+ str = bsp->Filename;
+ } else if (!(str = Serialize(g, (PBVAL)top, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ } else if (!(str = Serialize(g, top, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ return str;
+} // end of MakeResult
+
+/*********************************************************************************/
+/* Make the binary result according to the first argument type. */
+/*********************************************************************************/
+PBSON BJNX::MakeBinResult(UDF_ARGS *args, PBVAL top, ulong len, int n)
+{
+ char* filename = NULL;
+ int pretty = 2;
+ PBSON bnp = NULL;
+
+ if (IsArgJson(args, 0) == 3) {
+ bnp = (PBSON)args->args[0];
+
+ if (bnp->Top != (PJSON)top)
+ bnp->Top = bnp->Jsp = (PJSON)top;
+
+ return bnp;
+ } // endif 3
+
+ if (IsArgJson(args, 0) == 2) {
+ for (uint i = n; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT) {
+ pretty = (int)*(longlong*)args->args[i];
+ break;
+ } // endif type
+
+ filename = (char*)args->args[0];
+ } // endif 2
+
+ if ((bnp = BbinAlloc(G, len, top))) {
+ bnp->Filename = filename;
+ bnp->Pretty = pretty;
+ strcpy(bnp->Msg, "Json Binary item");
+ } //endif bnp
+
+ return bnp;
+} // end of MakeBinResult
+
+/***********************************************************************/
+/* Move a Json val block from one area to the current area. */
+/***********************************************************************/
+PBVAL BJNX::MoveVal(PBVAL vlp)
+{
+ PBVAL nvp = NewVal(vlp->Type);
+
+ nvp->Nd = vlp->Nd;
+ return nvp;
+} // end of MovedVal
+
+/***********************************************************************/
+/* Move a Json tree from one area to current area. */
+/***********************************************************************/
+PBVAL BJNX::MoveJson(PBJNX bxp, PBVAL jvp)
+{
+ PBVAL res = NULL;
+
+ if (jvp)
+ switch (jvp->Type) {
+ case TYPE_JAR:
+ res = MoveArray(bxp, jvp);
+ break;
+ case TYPE_JOB:
+ res = MoveObject(bxp, jvp);
+ break;
+ default:
+ res = MoveValue(bxp, jvp);
+ break;
+ } // endswitch Type
+
+ return res;
+} // end of MoveJson
+
+/***********************************************************************/
+/* Move an array. */
+/***********************************************************************/
+PBVAL BJNX::MoveArray(PBJNX bxp, PBVAL jap)
+{
+ PBVAL vlp, vmp, jvp = NULL, jarp = MoveVal(jap);
+
+ for (vlp = bxp->GetArray(jap); vlp; vlp = bxp->GetNext(vlp)) {
+ vmp = MoveJson(bxp, vlp);
+
+ if (jvp)
+ jvp->Next = MOF(vmp);
+ else
+ jarp->To_Val = MOF(vmp);
+
+ jvp = vmp;
+ } // endfor vlp
+
+ return jarp;
+} // end of MoveArray
+
+/***********************************************************************/
+/* Replace all object pointers by offsets. */
+/***********************************************************************/
+PBVAL BJNX::MoveObject(PBJNX bxp, PBVAL jop)
+{
+ PBPR mpp, prp, ppp = NULL;
+ PBVAL vmp, jobp = MoveVal(jop);
+
+ for (prp = bxp->GetObject(jop); prp; prp = bxp->GetNext(prp)) {
+ vmp = MoveJson(bxp, GetVlp(prp));
+ mpp = NewPair(DupStr(bxp->MZP(prp->Key)));
+ SetPairValue(mpp, vmp);
+
+ if (ppp)
+ ppp->Vlp.Next = MOF(mpp);
+ else
+ jobp->To_Val = MOF(mpp);
+
+ ppp = mpp;
+ } // endfor vlp
+
+ return jobp;
+} // end of MoffObject
+
+/***********************************************************************/
+/* Move a non json value. */
+/***********************************************************************/
+PBVAL BJNX::MoveValue(PBJNX bxp, PBVAL jvp)
+{
+ double *dp;
+ PBVAL nvp = MoveVal(jvp);
+
+ switch (jvp->Type) {
+ case TYPE_STRG:
+ case TYPE_DTM:
+ nvp->To_Val = DupStr(bxp->MZP(jvp->To_Val));
+ break;
+ case TYPE_DBL:
+ dp = (double*)BsonSubAlloc(sizeof(double));
+ *dp = bxp->DBL(jvp->To_Val);
+ nvp->To_Val = MOF(dp);
+ break;
+ case TYPE_JVAL:
+ nvp->To_Val = MOF(MoveJson(bxp, bxp->MVP(jvp->To_Val)));
+ break;
+ default:
+ nvp->To_Val = jvp->To_Val;
+ break;
+ } // endswith Type
+
+ return nvp;
+} // end of MoveValue
+
+/* -----------------------------Utility functions ------------------------------ */
+
+/*********************************************************************************/
+/* Returns a pointer to the first integer argument found from the nth argument. */
+/*********************************************************************************/
+static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n)
+{
+ int *x = NULL;
+
+ for (uint i = n; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT) {
+ if (args->args[i]) {
+ if ((x = (int*)PlgDBSubAlloc(g, NULL, sizeof(int))))
+ *x = (int)*(longlong*)args->args[i];
+ else
+ PUSH_WARNING(g->Message);
+
+ } // endif args
+
+ n = i + 1;
+ break;
+ } // endif arg_type
+
+ return x;
+} // end of GetIntArgPtr
+
+/*********************************************************************************/
+/* Returns not 0 if the argument is a JSON item or file name. */
+/*********************************************************************************/
+int IsArgJson(UDF_ARGS *args, uint i)
+{
+ const char *pat = args->attributes[i];
+ int n = 0;
+
+ if (*pat == '@') {
+ pat++;
+
+ if (*pat == '\'' || *pat == '"')
+ pat++;
+
+ } // endif pat
+
+ if (i >= args->arg_count || args->arg_type[i] != STRING_RESULT) {
+ } else if (!strnicmp(pat, "Bson_", 5) || !strnicmp(pat, "Json_", 5)) {
+ if (!args->args[i] || strchr("[{ \t\r\n", *args->args[i]))
+ n = 1; // arg should be is a json item
+// else
+// n = 2; // A file name may have been returned
+
+ } else if (!strnicmp(pat, "Bbin_", 5)) {
+ if (args->lengths[i] == sizeof(BSON))
+ n = 3; // arg is a binary json item
+// else
+// n = 2; // A file name may have been returned
+
+ } else if (!strnicmp(pat, "Bfile_", 6) || !strnicmp(pat, "Jfile_", 6)) {
+ n = 2; // arg is a json file name
+#if 0
+ } else if (args->lengths[i]) {
+ PGLOBAL g = PlugInit(NULL, (size_t)args->lengths[i] * M + 1024);
+ char *sap = MakePSZ(g, args, i);
+
+ if (ParseJson(g, sap, strlen(sap)))
+ n = 4;
+
+ JsonFreeMem(g);
+#endif // 0
+ } // endif's
+
+ return n;
+} // end of IsArgJson
+
+/*********************************************************************************/
+/* GetFileLength: returns file size in number of bytes. */
+/*********************************************************************************/
+static long GetFileLength(char *fn)
+{
+ int h;
+ long len;
+
+ h= open(fn, _O_RDONLY);
+
+ if (h != -1) {
+ if ((len = _filelength(h)) < 0)
+ len = 0;
+
+ close(h);
+ } else
+ len = 0;
+
+ return len;
+} // end of GetFileLength
+
+/* ------------------------- Now the new Bin UDF's ----------------------------- */
+
+/*********************************************************************************/
+/* Make a Json value containing the parameter. */
+/*********************************************************************************/
+my_bool bsonvalue_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count > 1) {
+ strcpy(message, "Cannot accept more than 1 argument");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of bsonvalue_init
+
+char* bsonvalue(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char*, char*)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, 1, false)) {
+ BJNX bnx(g);
+ PBVAL bvp = bnx.MakeValue(args, 0, true);
+
+ if (!(str = bnx.Serialize(g, bvp, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ } else
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of bsonValue
+
+void bsonvalue_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bsonvalue_deinit
+
+/*********************************************************************************/
+/* Make a Json array containing all the parameters. */
+/* Note: jvp must be set before arp because it can be a binary argument. */
+/*********************************************************************************/
+my_bool bson_make_array_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, false, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of bson_make_array_init
+
+char* bson_make_array(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char*, char*)
+{
+ char* str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false)) {
+ BJNX bnx(g);
+ PBVAL jvp = bnx.MakeValue(args, 0);
+ PBVAL arp = bnx.NewVal(TYPE_JAR);
+
+ for (uint i = 0; i < args->arg_count;) {
+ bnx.AddArrayValue(arp, jvp);
+ jvp = bnx.MakeValue(args, ++i);
+ } // endfor i
+
+ if (!(str = bnx.Serialize(g, arp, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ } else
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of bson_make_array
+
+void bson_make_array_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_make_array_deinit
+
+/*********************************************************************************/
+/* Add one or several values to a Bson array. */
+/*********************************************************************************/
+my_bool bson_array_add_values_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ //} else if (!IsArgJson(args, 0, true)) {
+ // strcpy(message, "First argument must be a valid json string or item");
+ // return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of bson_array_add_values_init
+
+char* bson_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char*) {
+ char* str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, true)) {
+ BJNX bnx(g);
+ PBVAL arp = bnx.MakeValue(args, 0, true);
+
+ if (arp->Type != TYPE_JAR) {
+ PUSH_WARNING("First argument is not an array");
+ goto fin;
+ } // endif arp
+
+ for (uint i = 1; i < args->arg_count; i++)
+ bnx.AddArrayValue(arp, bnx.MakeValue(args, i));
+
+ bnx.SetChanged(true);
+ str = bnx.MakeResult(args, arp, INT_MAX);
+ } // endif CheckMemory
+
+ if (!str) {
+ PUSH_WARNING(g->Message);
+ str = args->args[0];
+ } // endif str
+
+ // Keep result of constant function
+ g->Xchk = (g->N) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ fin:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_array_add_values
+
+void bson_array_add_values_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_array_add_values_deinit
+
+/*********************************************************************************/
+/* Add one value to a Json array. */
+/*********************************************************************************/
+my_bool bson_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ //} else if (!IsArgJson(args, 0, true)) {
+ // strcpy(message, "First argument is not a valid Json item");
+ // return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of bson_array_add_init
+
+char *bson_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 2, false, false, true)) {
+ int *x;
+ uint n = 2;
+ BJNX bnx(g, NULL, TYPE_STRING);
+ PBVAL jsp, top;
+ PBVAL arp, jvp = bnx.MakeValue(args, 0, true, &top);
+
+ jsp = jvp;
+ x = GetIntArgPtr(g, args, n);
+
+ if (bnx.CheckPath(g, args, jsp, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp) {
+ if (jvp->Type != TYPE_JAR) {
+ if ((arp = bnx.NewVal(TYPE_JAR))) {
+ bnx.AddArrayValue(arp, jvp);
+
+ if (!top)
+ top = arp;
+
+ } // endif arp
+
+ } else
+ arp = jvp;
+
+ if (arp) {
+ bnx.AddArrayValue(arp, bnx.MakeValue(args, 1), x);
+ bnx.SetChanged(true);
+ str = bnx.MakeResult(args, top, n);
+ } else
+ PUSH_WARNING(g->Message);
+
+ } else {
+ PUSH_WARNING("Target is not an array");
+ // if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+fin:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ *error = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_array_add
+
+void bson_array_add_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_array_add_deinit
+
+/*********************************************************************************/
+/* Delete a value from a Json array. */
+/*********************************************************************************/
+my_bool bson_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of bson_array_delete_init
+
+char *bson_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ int *x;
+ uint n = 1;
+ BJNX bnx(g, NULL, TYPE_STRING);
+ PBVAL arp, top;
+ PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
+
+ if (!(x = GetIntArgPtr(g, args, n)))
+ PUSH_WARNING("Missing or null array index");
+ else if (bnx.CheckPath(g, args, jvp, arp, 1))
+ PUSH_WARNING(g->Message);
+ else if (arp && arp->Type == TYPE_JAR) {
+ bnx.DeleteValue(arp, *x);
+ bnx.SetChanged(true);
+ str = bnx.MakeResult(args, top, n);
+ } else {
+ PUSH_WARNING("First argument target is not an array");
+ // if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+fin:
+ if (!str) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_array_delete
+
+void bson_array_delete_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_array_delete_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all the parameters. */
+/*********************************************************************************/
+my_bool bson_make_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of bson_make_object_init
+
+char *bson_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, false, true)) {
+ BJNX bnx(g);
+ PBVAL objp;
+
+ if ((objp = bnx.NewVal(TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i++)
+ bnx.SetKeyValue(objp, bnx.MakeValue(args, i), bnx.MakeKey(args, i));
+
+ str = bnx.Serialize(g, objp, NULL, 0);
+ } // endif objp
+
+ } // endif CheckMemory
+
+ if (!str)
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of bson_make_object
+
+void bson_make_object_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_make_object_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all not null parameters. */
+/*********************************************************************************/
+my_bool bson_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args,
+ char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of bson_object_nonull_init
+
+char *bson_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
+ BJNX bnx(g);
+ PBVAL jvp, objp;
+
+ if ((objp = bnx.NewVal(TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i++)
+ if (!bnx.IsValueNull(jvp = bnx.MakeValue(args, i)))
+ bnx.SetKeyValue(objp, jvp, bnx.MakeKey(args, i));
+
+ str = bnx.Serialize(g, objp, NULL, 0);
+ } // endif objp
+
+ } // endif CheckMemory
+
+ if (!str)
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of bson_object_nonull
+
+void bson_object_nonull_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_object_nonull_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all the key/value parameters. */
+/*********************************************************************************/
+my_bool bson_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count % 2) {
+ strcpy(message, "This function must have an even number of arguments");
+ return true;
+ } // endif arg_count
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of bson_object_key_init
+
+char *bson_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
+ BJNX bnx(g);
+ PBVAL objp;
+
+ if ((objp = bnx.NewVal(TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i += 2)
+ bnx.SetKeyValue(objp, bnx.MakeValue(args, i + 1), MakePSZ(g, args, i));
+
+ str = bnx.Serialize(g, objp, NULL, 0);
+ } // endif objp
+
+ } // endif CheckMemory
+
+ if (!str)
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of bson_object_key
+
+void bson_object_key_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_object_key_deinit
+
+/*********************************************************************************/
+/* Add or replace a value in a Json Object. */
+/*********************************************************************************/
+my_bool bson_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else if (!IsArgJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of bson_object_add_init
+
+char *bson_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PSZ key;
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 2, false, true, true)) {
+ BJNX bnx(g, NULL, TYPE_STRING);
+ PBVAL jvp, objp;
+ PBVAL jsp, top;
+
+ jsp = bnx.MakeValue(args, 0, true, &top);
+
+ if (bnx.CheckPath(g, args, jsp, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->Type == TYPE_JOB) {
+ objp = jvp;
+ jvp = bnx.MakeValue(args, 1);
+ key = bnx.MakeKey(args, 1);
+ bnx.SetKeyValue(objp, jvp, key);
+ bnx.SetChanged(true);
+ str = bnx.MakeResult(args, top);
+ } else {
+ PUSH_WARNING("First argument target is not an object");
+ // if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+fin:
+ if (!str) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_object_add
+
+void bson_object_add_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_object_add_deinit
+
+/*********************************************************************************/
+/* Delete a value from a Json object. */
+/*********************************************************************************/
+my_bool bson_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have 2 or 3 arguments");
+ return true;
+ } else if (!IsArgJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument must be a key string");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of bson_object_delete_init
+
+char *bson_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 1, false, true, true)) {
+ bool chg;
+ BJNX bnx(g, NULL, TYPE_STRG);
+ PSZ key;
+ PBVAL jsp, objp, top;
+ PBVAL jvp = bnx.MakeValue(args, 0, false, &top);
+
+ jsp = jvp;
+
+ if (bnx.CheckPath(g, args, jsp, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->Type == TYPE_JOB) {
+ key = bnx.MakeKey(args, 1);
+ objp = jvp;
+ chg = bnx.DeleteKey(objp, key);
+ bnx.SetChanged(chg);
+ str = bnx.MakeResult(args, top);
+ } else {
+ PUSH_WARNING("First argument target is not an object");
+ // if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+fin:
+ if (!str) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_object_delete
+
+void bson_object_delete_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_object_delete_deinit
+
+/*********************************************************************************/
+/* Returns an array of the Json object keys. */
+/*********************************************************************************/
+my_bool bson_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function must have 1 argument");
+ return true;
+ } else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "Argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bson_object_list_init
+
+char *bson_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->N) {
+ if (!CheckMemory(g, initid, args, 1, true, true)) {
+ BJNX bnx(g);
+ PBVAL jarp;
+ PBVAL jsp = bnx.MakeValue(args, 0, true);
+
+ if (jsp->Type == TYPE_JOB) {
+ jarp = bnx.GetKeyList(jsp);
+
+ if (!(str = bnx.Serialize(g, jarp, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ } else {
+ PUSH_WARNING("First argument is not an object");
+ if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ g->Xchk = str;
+ g->N = 1; // str can be NULL
+ } // endif const_item
+
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_object_list
+
+void bson_object_list_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_object_list_deinit
+
+/*********************************************************************************/
+/* Returns an array of the Json object values. */
+/*********************************************************************************/
+my_bool bson_object_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function must have 1 argument");
+ return true;
+ } else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "Argument must be a json object");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bson_object_values_init
+
+char *bson_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->N) {
+ if (!CheckMemory(g, initid, args, 1, true, true)) {
+ BJNX bnx(g);
+ char *p;
+ PBVAL jsp, jarp;
+ PBVAL jvp = bnx.MakeValue(args, 0);
+
+ if ((p = bnx.GetString(jvp))) {
+ if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ return NULL;
+ } // endif jsp
+
+ } else
+ jsp = jvp;
+
+ if (jsp->Type == TYPE_JOB) {
+ jarp = bnx.GetObjectValList(jsp);
+
+ if (!(str = bnx.Serialize(g, jarp, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ } else {
+ PUSH_WARNING("First argument is not an object");
+ if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ g->Xchk = str;
+ g->N = 1; // str can be NULL
+ } // endif const_item
+
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_object_values
+
+void bson_object_values_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_object_values_deinit
+
+/*********************************************************************************/
+/* Set the value of JsonGrpSize. */
+/*********************************************************************************/
+my_bool bsonset_def_prec_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) {
+ strcpy(message, "This function must have 1 integer argument");
+ return true;
+ } else
+ return false;
+
+} // end of bsonset_def_prec_init
+
+long long bsonset_def_prec(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
+{
+ long long n = *(long long*)args->args[0];
+
+ JsonDefPrec = (int)n;
+ return (long long)GetJsonDefPrec();
+} // end of bsonset_def_prec
+
+/*********************************************************************************/
+/* Get the value of JsonGrpSize. */
+/*********************************************************************************/
+my_bool bsonget_def_prec_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 0) {
+ strcpy(message, "This function must have no arguments");
+ return true;
+ } else
+ return false;
+
+} // end of bsonget_def_prec_init
+
+long long bsonget_def_prec(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
+{
+ return (long long)GetJsonDefPrec();
+} // end of bsonget_def_prec
+
+/*********************************************************************************/
+/* Set the value of JsonGrpSize. */
+/*********************************************************************************/
+my_bool bsonset_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) {
+ strcpy(message, "This function must have 1 integer argument");
+ return true;
+ } else
+ return false;
+
+} // end of bsonset_grp_size_init
+
+long long bsonset_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
+{
+ long long n = *(long long*)args->args[0];
+
+ JsonGrpSize = (uint)n;
+ return (long long)GetJsonGroupSize();
+} // end of bsonset_grp_size
+
+/*********************************************************************************/
+/* Get the value of JsonGrpSize. */
+/*********************************************************************************/
+my_bool bsonget_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 0) {
+ strcpy(message, "This function must have no arguments");
+ return true;
+ } else
+ return false;
+
+} // end of bsonget_grp_size_init
+
+long long bsonget_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
+{
+ return (long long)GetJsonGroupSize();
+} // end of bsonget_grp_size
+
+/*********************************************************************************/
+/* Make a Json array from values coming from rows. */
+/*********************************************************************************/
+my_bool bson_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, n = GetJsonGroupSize();
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function can only accept 1 argument");
+ return true;
+ } else if (IsArgJson(args, 0) == 3) {
+ strcpy(message, "This function does not support Jbin arguments");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ reslen *= n;
+ memlen += ((memlen - MEMFIX) * (n - 1));
+
+ if (JsonInit(initid, args, message, false, reslen, memlen))
+ return true;
+
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ (void) new(g) BJNX(g);
+
+ JsonMemSave(g);
+ return false;
+} // end of bson_array_grp_init
+
+void bson_array_grp_clear(UDF_INIT *initid, char*, char*)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
+
+ JsonSubSet(g);
+ g->Activityp = (PACTIVITY)bxp->NewVal(TYPE_JAR);
+ g->N = GetJsonGroupSize();
+} // end of bson_array_grp_clear
+
+void bson_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
+ PBVAL arp = (PBVAL)g->Activityp;
+
+ if (arp && g->N-- > 0)
+ bxp->AddArrayValue(arp, bxp->MakeValue(args, 0));
+
+} // end of bson_array_grp_add
+
+char *bson_array_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
+ PBVAL arp = (PBVAL)g->Activityp;
+
+ if (g->N < 0)
+ PUSH_WARNING("Result truncated to json_grp_size values");
+
+ if (!arp || !(str = bxp->Serialize(g, arp, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ *res_length = strlen(str);
+ return str;
+} // end of bson_array_grp
+
+void bson_array_grp_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_array_grp_deinit
+
+/*********************************************************************************/
+/* Make a Json object from values coming from rows. */
+/*********************************************************************************/
+my_bool bson_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, n = GetJsonGroupSize();
+
+ if (args->arg_count != 2) {
+ strcpy(message, "This function requires 2 arguments (key, value)");
+ return true;
+ } else if (IsArgJson(args, 0) == 3) {
+ strcpy(message, "This function does not support Jbin arguments");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen);
+
+ reslen *= n;
+ memlen += ((memlen - MEMFIX) * (n - 1));
+
+ if (JsonInit(initid, args, message, false, reslen, memlen))
+ return true;
+
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ (void) new(g) BJNX(g);
+
+ JsonMemSave(g);
+ return false;
+} // end of bson_object_grp_init
+
+void bson_object_grp_clear(UDF_INIT *initid, char*, char*)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
+
+ JsonSubSet(g);
+ g->Activityp = (PACTIVITY)bxp->NewVal(TYPE_JOB);
+ g->N = GetJsonGroupSize();
+} // end of bson_object_grp_clear
+
+void bson_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
+ PBVAL bop = (PBVAL)g->Activityp;
+
+ if (g->N-- > 0)
+ bxp->SetKeyValue(bop, bxp->MakeValue(args, 1), MakePSZ(g, args, 0));
+
+} // end of bson_object_grp_add
+
+char *bson_object_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBJNX bxp = (PBJNX)((char*)g->Sarea + sizeof(POOLHEADER));
+ PBVAL bop = (PBVAL)g->Activityp;
+
+ if (g->N < 0)
+ PUSH_WARNING("Result truncated to json_grp_size values");
+
+ if (!bop || !(str = bxp->Serialize(g, bop, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ *res_length = strlen(str);
+ return str;
+} // end of bson_object_grp
+
+void bson_object_grp_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_object_grp_deinit
+
+/*********************************************************************************/
+/* Test BJSON parse and serialize. */
+/*********************************************************************************/
+my_bool bson_test_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen, more = 1000;
+
+ if (args->arg_count == 0) {
+ strcpy(message, "At least 1 argument required (json)");
+ return true;
+ } else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of bson_test_init
+
+char* bson_test(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char* error) {
+ char* str = NULL, * fn = NULL;
+ int pretty = 1;
+ PBVAL bvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ str = (char*)g->Activityp;
+ goto err;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ try {
+ BJNX bnx(g);
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
+ PUSH_WARNING("CheckMemory error");
+ *error = 1;
+ goto err;
+ } else // Sarea may have been reallocated
+ bnx.Reset();
+
+ bvp = bnx.MakeValue(args, 0, true);
+
+ if (bvp->Type == TYPE_NULL) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif bvp
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = bvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ bvp = (PBVAL)g->Xchk;
+
+ for (uint i = 1; i < args->arg_count; i++)
+ if (args->arg_type[i] == STRING_RESULT)
+ fn = args->args[i];
+ else if (args->arg_type[i] == INT_RESULT)
+ pretty = (int)*(longlong*)args->args[i];
+
+ // Serialize the parse tree
+ str = bnx.Serialize(g, bvp, fn, pretty);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+ } catch (int n) {
+ xtrc(1, "json_test_bson: error %d: %s\n", n, g->Message);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ str = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ str = NULL;
+ } // end catch
+
+err:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_test
+
+void bson_test_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_test_deinit
+
+/*********************************************************************************/
+/* Locate a value in a Json tree. */
+/*********************************************************************************/
+my_bool bsonlocate_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen, more = 1000;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third argument is not an integer (rank)");
+ return true;
+ } // endifs args
+
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ if (IsArgJson(args, 0) == 3)
+ more = 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of bsonlocate_init
+
+char* bsonlocate(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char* error) {
+ char *path = NULL;
+ int k;
+ PBVAL bvp, bvp2;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (g->Activityp) {
+ path = (char*)g->Activityp;
+ *res_length = strlen(path);
+ return path;
+ } else {
+ *res_length = 0;
+ *is_null = 1;
+ return NULL;
+ } // endif Activityp
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ try {
+ BJNX bnx(g);
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
+ PUSH_WARNING("CheckMemory error");
+ *error = 1;
+ goto err;
+ } else {
+ bnx.Reset(); // Sarea may have been re-allocated
+ bvp = bnx.MakeValue(args, 0, true);
+
+ if (!bvp) {
+ bnx.GetMsg(g);
+ PUSH_WARNING(g->Message);
+ goto err;
+ } else if (bvp->Type == TYPE_NULL) {
+ PUSH_WARNING("First argument is not a valid JSON item");
+ goto err;
+ } // endif bvp
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = bvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } // endif CheckMemory
+
+ } else
+ bvp = (PBVAL)g->Xchk;
+
+ // The item to locate
+ bvp2 = bnx.MakeValue(args, 1, true);
+
+ if (bvp2->Type == TYPE_NULL) {
+ PUSH_WARNING("Invalid second argument");
+ goto err;
+ } // endif bvp
+
+ k = (args->arg_count > 2) ? (int)*(long long*)args->args[2] : 1;
+
+// bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
+ path = bnx.Locate(g, bvp, bvp2, k);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)path;
+
+ } catch (int n) {
+ xtrc(1, "Exception %d: %s\n", n, g->Message);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } // end catch
+
+err:
+ if (!path) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(path);
+
+ return path;
+} // end of bsonlocate
+
+void bsonlocate_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bsonlocate_deinit
+
+/*********************************************************************************/
+/* Locate all occurences of a value in a Json tree. */
+/*********************************************************************************/
+my_bool bson_locate_all_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen, more = 1000;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third argument is not an integer (Depth)");
+ return true;
+ } // endifs
+
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ if (IsArgJson(args, 0) == 3)
+ more = 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of bson_locate_all_init
+
+char* bson_locate_all(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char* error) {
+ char* path = NULL;
+ int mx = 10;
+ PBVAL bvp, bvp2;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (g->Activityp) {
+ path = (char*)g->Activityp;
+ *res_length = strlen(path);
+ return path;
+ } else {
+ *error = 1;
+ *res_length = 0;
+ *is_null = 1;
+ return NULL;
+ } // endif Activityp
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ try {
+ BJNX bnx(g);
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ *error = 1;
+ goto err;
+ } else
+ bnx.Reset();
+
+ bvp = bnx.MakeValue(args, 0, true);
+
+ if (bvp->Type == TYPE_NULL) {
+ PUSH_WARNING("First argument is not a valid JSON item");
+ goto err;
+ } // endif bvp
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = bvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ bvp = (PBVAL)g->Xchk;
+
+ // The item to locate
+ bvp2 = bnx.MakeValue(args, 1, true);
+
+ if (bvp2->Type == TYPE_NULL) {
+ PUSH_WARNING("Invalid second argument");
+ goto err;
+ } // endif bvp
+
+ if (args->arg_count > 2)
+ mx = (int)*(long long*)args->args[2];
+
+// bnxp = new(g) BJNX(g, bvp, TYPE_STRING);
+ path = bnx.LocateAll(g, bvp, bvp2, mx);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)path;
+
+ } catch (int n) {
+ xtrc(1, "Exception %d: %s\n", n, g->Message);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } // end catch
+
+err:
+ if (!path) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(path);
+
+ return path;
+} // end of bson_locate_all
+
+void bson_locate_all_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_locate_all_deinit
+
+/*********************************************************************************/
+/* Check whether the document contains a value or item. */
+/*********************************************************************************/
+my_bool bson_contains_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 1024;
+ int n = IsArgJson(args, 0);
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third argument is not an integer (index)");
+ return true;
+ } else if (args->arg_count > 3) {
+ if (args->arg_type[3] == INT_RESULT && args->args[3])
+ more += (unsigned long)*(long long*)args->args[3];
+ else
+ strcpy(message, "Fourth argument is not an integer (memory)");
+
+ } // endif's
+
+ CalcLen(args, false, reslen, memlen);
+ //memlen += more;
+
+ // TODO: calculate this
+ more += (IsArgJson(args, 0) != 3 ? 1000 : 0);
+
+ return JsonInit(initid, args, message, false, reslen, memlen, more);
+} // end of bson contains_init
+
+long long bson_contains(UDF_INIT *initid, UDF_ARGS *args, char *, char *error)
+{
+ char isn, res[256];
+ unsigned long reslen;
+
+ isn = 0;
+ bsonlocate(initid, args, res, &reslen, &isn, error);
+ return (isn) ? 0LL : 1LL;
+} // end of bson_contains
+
+void bson_contains_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_contains_deinit
+
+/*********************************************************************************/
+/* Check whether the document contains a path. */
+/*********************************************************************************/
+my_bool bsoncontains_path_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 1024;
+ int n = IsArgJson(args, 0);
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a string (path)");
+ return true;
+ } else if (args->arg_count > 2) {
+ if (args->arg_type[2] == INT_RESULT && args->args[2])
+ more += (unsigned long)*(long long*)args->args[2];
+ else
+ strcpy(message, "Third argument is not an integer (memory)");
+
+ } // endif's
+
+ CalcLen(args, false, reslen, memlen);
+ //memlen += more;
+
+ // TODO: calculate this
+ more += (IsArgJson(args, 0) != 3 ? 1000 : 0);
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of bsoncontains_path_init
+
+long long bsoncontains_path(UDF_INIT *initid, UDF_ARGS *args, char *, char *error)
+{
+ char *p, *path;
+ long long n;
+ PBVAL jsp;
+ PBVAL jvp;
+ PBJNX bxp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (!g->Activityp) {
+ return 0LL;
+ } else
+ return *(long long*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto err;
+ } else {
+ BJNX bnx(g);
+
+ jvp = bnx.MakeValue(args, 0);
+
+ if ((p = bnx.GetString(jvp))) {
+ if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif jsp
+
+ } else
+ jsp = jvp;
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } // endelse CheckMemory
+
+ } else
+ jsp = (PBVAL)g->Xchk;
+
+ bxp = new(g) BJNX(g, jsp, TYPE_BIGINT);
+ path = MakePSZ(g, args, 1);
+
+ if (bxp->SetJpath(g, path)) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif SetJpath
+
+ n = (bxp->CheckPath(g)) ? 1LL : 0LL;
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
+
+ if (np) {
+ *np = n;
+ g->Activityp = (PACTIVITY)np;
+ } else
+ PUSH_WARNING(g->Message);
+
+ } // endif const_item
+
+ return n;
+
+err:
+ if (g->Mrr) *error = 1;
+ return 0LL;
+} // end of bsoncontains_path
+
+void bsoncontains_path_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bsoncontains_path_deinit
+
+/*********************************************************************************/
+/* Merge two arrays or objects. */
+/*********************************************************************************/
+my_bool bson_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else for (int i = 0; i < 2; i++)
+ if (!IsArgJson(args, i) && args->arg_type[i] != STRING_RESULT) {
+ sprintf(message, "Argument %d must be a json item", i);
+ return true;
+ } // endif type
+
+ CalcLen(args, false, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of bson_item_merge_init
+
+char *bson_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 2, false, false, true)) {
+ JTYP type;
+ BJNX bnx(g);
+ PBVAL jvp, top = NULL;
+ PBVAL jsp[2] = {NULL, NULL};
+
+ for (int i = 0; i < 2; i++) {
+ jvp = bnx.MakeValue(args, i, true);
+
+ if (i) {
+ if (jvp->Type != type) {
+ PUSH_WARNING("Argument types mismatch");
+ goto fin;
+ } // endif type
+
+ } else {
+ type = (JTYP)jvp->Type;
+
+ if (type != TYPE_JAR && type != TYPE_JOB) {
+ PUSH_WARNING("First argument is not an array or object");
+ goto fin;
+ } else
+ top = jvp;
+
+ } // endif i
+
+ jsp[i] = jvp;
+ } // endfor i
+
+ if (type == TYPE_JAR)
+ bnx.MergeArray(jsp[0], jsp[1]);
+ else
+ bnx.MergeObject(jsp[0], jsp[1]);
+
+ bnx.SetChanged(true);
+ str = bnx.MakeResult(args, top);
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged first argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+fin:
+ if (!str) {
+ *res_length = 0;
+ *error = 1;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_item_merge
+
+void bson_item_merge_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_item_merge_deinit
+
+/*********************************************************************************/
+/* Get a Json item from a Json document. */
+/*********************************************************************************/
+my_bool bson_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more;
+ int n = IsArgJson(args, 0);
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a string (jpath)");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ if (n == 2 && args->args[0]) {
+ char fn[_MAX_PATH];
+ long fl;
+
+ memcpy(fn, args->args[0], args->lengths[0]);
+ fn[args->lengths[0]] = 0;
+ fl = GetFileLength(fn);
+ more = fl * 3;
+ } else if (n != 3) {
+ more = args->lengths[0] * 3;
+ } else
+ more = 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of bson_get_item_init
+
+char *bson_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *path, *str = NULL;
+ PBVAL jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ BJNX bnx(g, NULL, TYPE_STRING, initid->max_length);
+
+ if (g->N) {
+ str = (char*)g->Activityp;
+ goto fin;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto fin;
+ } else {
+ bnx.Reset();
+ jvp = bnx.MakeValue(args, 0, true);
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } // endelse CheckMemory
+
+ } else
+ jvp = (PBVAL)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+
+ if (bnx.SetJpath(g, path, true)) {
+ goto fin;
+ } else
+ jvp = bnx.GetRowValue(g, jvp, 0);
+
+ if (!bnx.IsJson(jvp)) {
+ strcpy(g->Message, "Not a Json item");
+ } else
+ str = bnx.Serialize(g, jvp, NULL, 0);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+fin:
+ if (!str) {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_get_item
+
+void bson_get_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_get_item_deinit
+
+/*********************************************************************************/
+/* Get a string value from a Json item. */
+/*********************************************************************************/
+my_bool bsonget_string_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 1024;
+ int n = IsArgJson(args, 0);
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a string (jpath)");
+ return true;
+ } else if (args->arg_count > 2) {
+ if (args->arg_type[2] == INT_RESULT && args->args[2])
+ more += (unsigned long)*(long long*)args->args[2];
+ else
+ strcpy(message, "Third argument is not an integer (memory)");
+
+ } // endif's
+
+ CalcLen(args, false, reslen, memlen);
+ //memlen += more;
+
+ if (n == 2 && args->args[0]) {
+ char fn[_MAX_PATH];
+ long fl;
+
+ memcpy(fn, args->args[0], args->lengths[0]);
+ fn[args->lengths[0]] = 0;
+ fl = GetFileLength(fn);
+ more += fl * 3;
+ } else if (n != 3)
+ more += args->lengths[0] * 3;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of bsonget_string_init
+
+char *bsonget_string(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *p, *path, *str = NULL;
+ PBVAL jsp, jvp;
+ PBJNX bxp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ str = (char*)g->Activityp;
+ goto err;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ try {
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto err;
+ } else {
+ BJNX bnx(g);
+
+ jvp = bnx.MakeValue(args, 0);
+
+ if ((p = bnx.GetString(jvp))) {
+ if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif jsp
+
+ } else
+ jsp = jvp;
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } // endelse CheckMemory
+
+ } else
+ jsp = (PBVAL)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+ bxp = new(g) BJNX(g, jsp, TYPE_STRING, initid->max_length);
+
+ if (bxp->SetJpath(g, path)) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } else
+ bxp->ReadValue(g);
+
+ if (!bxp->GetValue()->IsNull())
+ str = bxp->GetValue()->GetCharValue();
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ } // end catch
+
+err:
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bsonget_string
+
+void bsonget_string_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bsonget_string_deinit
+
+/*********************************************************************************/
+/* Get an integer value from a Json item. */
+/*********************************************************************************/
+my_bool bsonget_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more;
+
+ if (args->arg_count != 2) {
+ strcpy(message, "This function must have 2 arguments");
+ return true;
+ } else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a (jpath) string");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ more = (IsArgJson(args, 0) != 3) ? 1000 : 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of bsonget_int_init
+
+long long bsonget_int(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error)
+{
+ char *p, *path;
+ long long n;
+ PBVAL jsp, jvp;
+ PBJNX bxp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (!g->Activityp) {
+ *is_null = 1;
+ return 0LL;
+ } else
+ return *(long long*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ if (g->Mrr) *error = 1;
+ *is_null = 1;
+ return 0LL;
+ } else {
+ BJNX bnx(g);
+
+ jvp = bnx.MakeValue(args, 0);
+
+ if ((p = bnx.GetString(jvp))) {
+ if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ if (g->Mrr) *error = 1;
+ *is_null = 1;
+ return 0;
+ } // endif jsp
+
+ } else
+ jsp = jvp;
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } // endelse CheckMemory
+
+ } else
+ jsp = (PBVAL)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+ bxp = new(g) BJNX(g, jsp, TYPE_BIGINT);
+
+ if (bxp->SetJpath(g, path)) {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return 0;
+ } else
+ bxp->ReadValue(g);
+
+ if (bxp->GetValue()->IsNull()) {
+ *is_null = 1;
+ return 0;
+ } // endif IsNull
+
+ n = bxp->GetValue()->GetBigintValue();
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
+
+ if (np) {
+ *np = n;
+ g->Activityp = (PACTIVITY)np;
+ } else
+ PUSH_WARNING(g->Message);
+
+ } // endif const_item
+
+ return n;
+} // end of bsonget_int
+
+void bsonget_int_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bsonget_int_deinit
+
+/*********************************************************************************/
+/* Get a double value from a Json item. */
+/*********************************************************************************/
+my_bool bsonget_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a (jpath) string");
+ return true;
+ } else if (args->arg_count > 2) {
+ if (args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third argument is not an integer (decimals)");
+ return true;
+ } else
+ initid->decimals = (uint)*(longlong*)args->args[2];
+
+ } else
+ initid->decimals = 15;
+
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ more = (IsArgJson(args, 0) != 3) ? 1000 : 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of bsonget_real_init
+
+double bsonget_real(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error)
+{
+ char *p, *path;
+ double d;
+ PBVAL jsp, jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ BJNX bnx(g);
+
+ if (g->N) {
+ if (!g->Activityp) {
+ *is_null = 1;
+ return 0.0;
+ } else
+ return *(double*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ if (g->Mrr) *error = 1;
+ *is_null = 1;
+ return 0.0;
+ } else {
+ bnx.Reset();
+ jvp = bnx.MakeValue(args, 0);
+
+ if ((p = bnx.GetString(jvp))) {
+ if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return 0.0;
+ } // endif jsp
+
+ } else
+ jsp = jvp;
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+ } // endelse CheckMemory
+
+ } else
+ jsp = (PBVAL)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+//bxp = new(g) BJNX(g, jsp, TYPE_DOUBLE, 32, jsp->Nd);
+
+ if (bnx.SetJpath(g, path)) {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return 0.0;
+ } else
+ jvp = bnx.GetRowValue(g, jsp, 0);
+
+ if (!jvp || bnx.IsValueNull(jvp)) {
+ *is_null = 1;
+ return 0.0;
+ } else if (args->arg_count == 2) {
+ d = atof(bnx.GetString(jvp));
+ } else
+ d = bnx.GetDouble(jvp);
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ double *dp;
+
+ if ((dp = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
+ *dp = d;
+ g->Activityp = (PACTIVITY)dp;
+ } else {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return 0.0;
+ } // endif dp
+
+ } // endif const_item
+
+ return d;
+} // end of jsonget_real
+
+void bsonget_real_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bsonget_real_deinit
+
+/*********************************************************************************/
+/* Delete items from a Json document. */
+/*********************************************************************************/
+my_bool bson_delete_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ if (IsArgJson(args, 0) != 3) {
+ strcpy(message, "This function must have at least 2 arguments or one binary");
+ return true;
+ } // endif args
+
+ } // endif count
+
+ CalcLen(args, false, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // Is this a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of bson_delete_item_init
+
+char *bson_delete_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *path, *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ BJNX bnx(g, NULL, TYPE_STRING);
+ PBVAL top, jar = NULL;
+ PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
+
+ if (args->arg_count == 1) {
+ // This should be coming from bbin_locate_all
+ jar = jvp; // This is the array of paths
+ jvp = top; // And this is the document
+ } else if(!bnx.IsJson(jvp)) {
+ PUSH_WARNING("First argument is not a JSON document");
+ goto fin;
+ } else if (args->arg_count == 2) {
+ // Check whether this is an array of paths
+ jar = bnx.MakeValue(args, 1, true);
+
+ if (jar && jar->Type != TYPE_JAR)
+ jar = NULL;
+
+ } // endif arg_count
+
+ if (jar) {
+ // Do the deletion in reverse order
+ for(int i = bnx.GetArraySize(jar) - 1; i >= 0; i--) {
+ path = bnx.GetString(bnx.GetArrayValue(jar, i));
+
+ if (bnx.SetJpath(g, path, false)) {
+ PUSH_WARNING(g->Message);
+ continue;
+ } // endif SetJpath
+
+ bnx.SetChanged(bnx.DeleteItem(g, jvp));
+ } // endfor i
+
+ } else for (uint i = 1; i < args->arg_count; i++) {
+ path = MakePSZ(g, args, i);
+
+ if (bnx.SetJpath(g, path, false)) {
+ PUSH_WARNING(g->Message);
+ continue;
+ } // endif SetJpath
+
+ bnx.SetChanged(bnx.DeleteItem(g, jvp));
+ } // endfor i
+
+ str = bnx.MakeResult(args, top, INT_MAX);
+ } // endif CheckMemory
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+fin:
+ if (!str) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_delete_item
+
+void bson_delete_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_delete_item_deinit
+
+/*********************************************************************************/
+/* This function is used by the json_set/insert/update_item functions. */
+/*********************************************************************************/
+static char *bson_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *path, *str = NULL;
+ int w;
+ my_bool b = true;
+ PBJNX bxp;
+ PBVAL jsp, jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Alchecked) {
+ str = (char*)g->Activityp;
+ goto fin;
+ } else if (g->N)
+ g->Alchecked = 1;
+
+ if (!strcmp(result, "$set"))
+ w = 0;
+ else if (!strcmp(result, "$insert"))
+ w = 1;
+ else if (!strcmp(result, "$update"))
+ w = 2;
+ else {
+ PUSH_WARNING("Logical error, please contact CONNECT developer");
+ goto fin;
+ } // endelse
+
+ try {
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true, false, true)) {
+ PUSH_WARNING("CheckMemory error");
+ throw 1;
+ } else {
+ BJNX bnx(g);
+
+ jsp = bnx.MakeValue(args, 0, true);
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } // endif CheckMemory
+
+ } else
+ jsp = (PBVAL)g->Xchk;
+
+ bxp = new(g)BJNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
+
+ for (uint i = 1; i + 1 < args->arg_count; i += 2) {
+ jvp = bxp->MakeValue(args, i);
+ path = MakePSZ(g, args, i + 1);
+
+ if (bxp->SetJpath(g, path, false)) {
+ PUSH_WARNING(g->Message);
+ continue;
+ } // endif SetJpath
+
+ if (w) {
+ bxp->ReadValue(g);
+ b = bxp->GetValue()->IsNull();
+ b = (w == 1) ? b : !b;
+ } // endif w
+
+ if (b && bxp->WriteValue(g, jvp)) {
+ PUSH_WARNING(g->Message);
+ continue;
+ } // endif SetJpath
+
+ bxp->SetChanged(true);
+ } // endfor i
+
+ // In case of error or file, return unchanged argument
+ if (!(str = bxp->MakeResult(args, jsp, INT_MAX32)))
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ } // end catch
+
+fin:
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_handle_item
+
+/*********************************************************************************/
+/* Set Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool bson_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 0;
+ int n = IsArgJson(args, 0);
+
+ if (!(args->arg_count % 2)) {
+ strcpy(message, "This function must have an odd number of arguments");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ if (n == 2 && args->args[0]) {
+ char fn[_MAX_PATH];
+ long fl;
+
+ memcpy(fn, args->args[0], args->lengths[0]);
+ fn[args->lengths[0]] = 0;
+ fl = GetFileLength(fn);
+ more += fl * 3;
+ } else if (n != 3)
+ more += args->lengths[0] * 3;
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen, more)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ g->Alchecked = 0;
+ return false;
+ } else
+ return true;
+
+} // end of bson_set_item_init
+
+char *bson_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$set");
+ return bson_handle_item(initid, args, result, res_length, is_null, p);
+} // end of bson_set_item
+
+void bson_set_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_set_item_deinit
+
+/*********************************************************************************/
+/* Insert Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool bson_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_set_item_init(initid, args, message);
+} // end of bson_insert_item_init
+
+char *bson_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$insert");
+ return bson_handle_item(initid, args, result, res_length, is_null, p);
+} // end of bson_insert_item
+
+void bson_insert_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_insert_item_deinit
+
+/*********************************************************************************/
+/* Update Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool bson_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_set_item_init(initid, args, message);
+} // end of bson_update_item_init
+
+char *bson_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$update");
+ return bson_handle_item(initid, args, result, res_length, is_null, p);
+} // end of bson_update_item
+
+void bson_update_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_update_item_deinit
+
+/*********************************************************************************/
+/* Returns a json file as a json string. */
+/*********************************************************************************/
+my_bool bson_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, fl, more = 1024;
+
+ if (args->arg_count < 1 || args->arg_count > 4) {
+ strcpy(message, "This function only accepts 1 to 4 arguments");
+ return true;
+ } else if (args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a string (file name)");
+ return true;
+ } // endif's args[0]
+
+ for (unsigned int i = 1; i < args->arg_count; i++) {
+ if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) {
+ sprintf(message, "Argument %d is not an integer or a string (pretty or path)", i);
+ return true;
+ } // endif arg_type
+
+ // Take care of eventual memory argument
+ if (args->arg_type[i] == INT_RESULT && args->args[i])
+ more += (ulong)*(longlong*)args->args[i];
+
+ } // endfor i
+
+ initid->maybe_null = 1;
+ CalcLen(args, false, reslen, memlen);
+
+ if (args->args[0])
+ fl = GetFileLength(args->args[0]);
+ else
+ fl = 100; // What can be done here?
+
+ reslen += fl;
+
+ if (initid->const_item)
+ more += fl;
+
+ if (args->arg_count > 1)
+ more += fl * M;
+
+ memlen += more;
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bson_file_init
+
+char *bson_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *fn, *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ str = (char*)g->Xchk;
+ goto fin;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ fn = MakePSZ(g, args, 0);
+
+ if (args->arg_count > 1) {
+ int pretty = 3, pty = 3;
+ size_t len;
+ PBVAL jsp, jvp = NULL;
+ BJNX bnx(g);
+
+ for (unsigned int i = 1; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
+ pretty = (int) * (longlong*)args->args[i];
+ break;
+ } // endif type
+
+ // Parse the json file and allocate its tree structure
+ if (!(jsp = bnx.ParseJsonFile(g, fn, pty, len))) {
+ PUSH_WARNING(g->Message);
+ goto fin;
+ } // endif jsp
+
+ if (pty == 3)
+ PUSH_WARNING("File pretty format cannot be determined");
+ else if (pretty != 3 && pty != pretty)
+ PUSH_WARNING("File pretty format doesn't match the specified pretty value");
+ else if (pretty == 3)
+ pretty = pty;
+
+ // Check whether a path was specified
+ if (bnx.CheckPath(g, args, jsp, jvp, 1)) {
+ PUSH_WARNING(g->Message);
+ goto fin;
+ } else if (jvp)
+ jsp = jvp;
+
+ if (!(str = bnx.Serialize(g, jsp, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ } else
+ if (!(str = GetJsonFile(g, fn)))
+ PUSH_WARNING(g->Message);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = str;
+
+fin:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bson_file
+
+void bson_file_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_file_deinit
+
+/*********************************************************************************/
+/* Make a json file from a json item. */
+/*********************************************************************************/
+my_bool bfile_make_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 1 || args->arg_count > 3) {
+ strcpy(message, "Wrong number of arguments");
+ return true;
+ } else if (!IsArgJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } // endif
+
+ CalcLen(args, false, reslen, memlen);
+ memlen = memlen + 5000; // To take care of not pretty files
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bfile_make_init
+
+char *bfile_make(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *p, *str = NULL, *fn = NULL;
+ int n, pretty = 2;
+ PBVAL jsp, jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ BJNX bnx(g);
+
+ if (g->N) {
+ str = (char*)g->Activityp;
+ goto fin;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if ((n = IsArgJson(args, 0)) == 3) {
+ // Get default file name and pretty
+ PBSON bsp = (PBSON)args->args[0];
+
+ fn = bsp->Filename;
+ pretty = bsp->Pretty;
+ } else if ((n = IsArgJson(args, 0)) == 2)
+ fn = args->args[0];
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto fin;
+ } else
+ bnx.Reset();
+
+ jvp = bnx.MakeValue(args, 0);
+
+ if (!n && (p = bnx.GetString(jvp))) {
+ if (!strchr("[{ \t\r\n", *p)) {
+ // Is this a file name?
+ if (!(p = GetJsonFile(g, p))) {
+ PUSH_WARNING(g->Message);
+ goto fin;
+ } else
+ fn = bnx.GetString(jvp);
+
+ } // endif p
+
+ if (!(jsp = bnx.ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ goto fin;
+ } // endif jsp
+
+ bnx.SetValueVal(jvp, jsp);
+ } // endif p
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jvp = (PBVAL)g->Xchk;
+
+ for (uint i = 1; i < args->arg_count; i++)
+ switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ fn = MakePSZ(g, args, i);
+ break;
+ case INT_RESULT:
+ pretty = (int)*(longlong*)args->args[i];
+ break;
+ default:
+ PUSH_WARNING("Unexpected argument type in bfile_make");
+ } // endswitch arg_type
+
+ if (fn) {
+ if (!bnx.Serialize(g, jvp, fn, pretty))
+ PUSH_WARNING(g->Message);
+ } else
+ PUSH_WARNING("Missing file name");
+
+ str = fn;
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+fin:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of bfile_make
+
+void bfile_make_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bfile_make_deinit
+
+/*********************************************************************************/
+/* Convert a prettiest Json file to Pretty=0. */
+/*********************************************************************************/
+my_bool bfile_convert_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 3) {
+ strcpy(message, "This function must have 3 arguments");
+ return true;
+ } else if (args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third Argument must be an integer (LRECL)");
+ return true;
+ } else for (int i = 0; i < 2; i++)
+ if (args->arg_type[i] != STRING_RESULT) {
+ sprintf(message, "Arguments %d must be a string (file name)", i+1);
+ return true;
+ } // endif args
+
+ CalcLen(args, false, reslen, memlen);
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bfile_convert_init
+
+char *bfile_convert(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long *res_length, char *is_null, char *error) {
+ char *str, *fn, *ofn;
+ int lrecl = (int)*(longlong*)args->args[2];
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ fn = MakePSZ(g, args, 0);
+ ofn = MakePSZ(g, args, 1);
+
+ if (!g->Xchk) {
+ JUP* jup = new(g) JUP(g);
+
+ str = jup->UnprettyJsonFile(g, fn, ofn, lrecl);
+ g->Xchk = str;
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ PUSH_WARNING(g->Message[0] != '\0' ? g->Message : "Unexpected error");
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else {
+ strcpy(result, str);
+ *res_length = strlen(str);
+ } // endif str
+
+ return str;
+} // end of bfile_convert
+
+void bfile_convert_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bfile_convert_deinit
+
+/*********************************************************************************/
+/* Convert a pretty=0 Json file to binary BJSON. */
+/*********************************************************************************/
+my_bool bfile_bjson_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 2 && args->arg_count != 3) {
+ strcpy(message, "This function must have 2 or 3 arguments");
+ return true;
+ } else if (args->arg_count == 3 && args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third Argument must be an integer (LRECL)");
+ return true;
+ } else for (int i = 0; i < 2; i++)
+ if (args->arg_type[i] != STRING_RESULT) {
+ sprintf(message, "Arguments %d must be a string (file name)", i + 1);
+ return true;
+ } // endif args
+
+ CalcLen(args, false, reslen, memlen);
+ memlen = memlen * M;
+ memlen += (args->arg_count == 3) ? (ulong)*(longlong*)args->args[2] : 1024;
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of bfile_bjson_init
+
+char *bfile_bjson(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char*, char *error) {
+ char *buf, *str = NULL, fn[_MAX_PATH], ofn[_MAX_PATH];
+ bool loop;
+ ssize_t len, newloc;
+ size_t lrecl, binszp;
+ PBVAL jsp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ BDOC doc(g);
+
+ strcpy(fn, MakePSZ(g, args, 0));
+ strcpy(ofn, MakePSZ(g, args, 1));
+
+ if (args->arg_count == 3)
+ lrecl = (size_t)*(longlong*)args->args[2];
+ else
+ lrecl = 1024;
+
+ if (!g->Xchk) {
+ int msgid = MSGID_OPEN_MODE_STRERROR;
+ FILE *fout = NULL;
+ FILE *fin;
+
+ if (!(fin = global_fopen(g, msgid, fn, "rt")))
+ str = strcpy(result, g->Message);
+ else if (!(fout = global_fopen(g, msgid, ofn, "wb")))
+ str = strcpy(result, g->Message);
+ else if ((buf = (char*)malloc(lrecl))) {
+ try {
+ do {
+ loop = false;
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+
+ if (!fgets(buf, lrecl, fin)) {
+ if (!feof(fin)) {
+ sprintf(g->Message, "Error %d reading %zd bytes from %s",
+ errno, lrecl, fn);
+ str = strcpy(result, g->Message);
+ } else
+ str = strcpy(result, ofn);
+
+ } else if ((len = strlen(buf))) {
+ if ((jsp = doc.ParseJson(g, buf, len))) {
+ newloc = (size_t)PlugSubAlloc(g, NULL, 0);
+ binszp = newloc - (size_t)jsp;
+
+ if (fwrite(&binszp, sizeof(binszp), 1, fout) != 1) {
+ sprintf(g->Message, "Error %d writing %zd bytes to %s",
+ errno, sizeof(binszp), ofn);
+ str = strcpy(result, g->Message);
+ } else if (fwrite(jsp, binszp, 1, fout) != 1) {
+ sprintf(g->Message, "Error %d writing %zd bytes to %s",
+ errno, binszp, ofn);
+ str = strcpy(result, g->Message);
+ } else
+ loop = true;
+
+ } else {
+ str = strcpy(result, g->Message);
+ } // endif jsp
+
+ } else
+ loop = true;
+
+ } while (loop);
+
+ } catch (int) {
+ str = strcpy(result, g->Message);
+ } catch (const char* msg) {
+ str = strcpy(result, msg);
+ } // end catch
+
+ free(buf);
+ } else
+ str = strcpy(result, "Buffer malloc failed");
+
+ if (fin) fclose(fin);
+ if (fout) fclose(fout);
+ g->Xchk = str;
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ if (g->Message[0] != '\0')
+ str = strcpy(result, g->Message);
+ else
+ str = strcpy(result, "Unexpected error");
+
+ } // endif str
+
+ *res_length = strlen(str);
+ return str;
+} // end of bfile_bjson
+
+void bfile_bjson_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bfile_bjson_deinit
+
+/*********************************************************************************/
+/* Serialize a Json document. . */
+/*********************************************************************************/
+my_bool bson_serialize_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->args[0] && IsArgJson(args, 0) != 3) {
+ strcpy(message, "Argument must be a Jbin tree");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of bson_serialize_init
+
+char *bson_serialize(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *error)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (IsArgJson(args, 0) == 3) {
+ PBSON bsp = (PBSON)args->args[0];
+ BJNX bnx(bsp->G);
+ PBVAL bvp = (args->arg_count == 1) ? (PBVAL)bsp->Jsp : (PBVAL)bsp->Top;
+
+// if (!(str = bnx.Serialize(g, bvp, bsp->Filename, bsp->Pretty)))
+ if (!(str = bnx.Serialize(g, bvp, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else {
+ // *error = 1;
+ str = strcpy(result, "Argument is not a Jbin tree");
+ } // endif
+
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of bson_serialize
+
+void bson_serialize_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bson_serialize_deinit
+
+/*********************************************************************************/
+/* Make and return a binary Json array containing all the parameters. */
+/* Note: jvp must be set before arp because it can be a binary argument. */
+/*********************************************************************************/
+my_bool bbin_make_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, false, reslen, memlen);
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bbin_make_array_init
+
+char *bbin_make_array(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = NULL;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false)) {
+ BJNX bnx(g);
+ PBVAL jvp = bnx.MakeValue(args, 0);
+ PBVAL arp = bnx.NewVal(TYPE_JAR);
+
+ for (uint i = 0; i < args->arg_count;) {
+ bnx.AddArrayValue(arp, jvp);
+ jvp = bnx.MakeValue(args, ++i);
+ } // endfor i
+
+ if ((bsp = BbinAlloc(bnx.G, initid->max_length, arp))) {
+ strcat(bsp->Msg, " array");
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ } // endif CheckMemory
+
+ } else
+ bsp = (PBSON)g->Xchk;
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_make_array
+
+void bbin_make_array_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_make_array_deinit
+
+/*********************************************************************************/
+/* Add one value to a Json array. */
+/*********************************************************************************/
+my_bool bbin_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsArgJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of bbin_array_add_init
+
+char *bbin_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = NULL;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ bsp = (PBSON)g->Xchk;
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } else if (!CheckMemory(g, initid, args, 2, false, false, true)) {
+ uint n = 2;
+ int* x = GetIntArgPtr(g, args, n);
+ BJNX bnx(g, NULL, TYPE_STRING);
+ PBVAL top, jarp = NULL, jvp = NULL;
+ PBVAL jsp = bnx.MakeValue(args, 0, true, &top);
+
+ if (bnx.CheckPath(g, args, jsp, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->Type != TYPE_JAR) {
+ if ((jarp = bnx.NewVal(TYPE_JAR))) {
+ bnx.AddArrayValue(jarp, jvp);
+
+ if (!top)
+ top = jarp;
+
+ } // endif jarp
+
+ } else
+ jarp = jvp;
+
+ if (jarp) {
+ bnx.AddArrayValue(jarp, bnx.MakeValue(args, 1), x);
+ bnx.SetChanged(true);
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ } else
+ PUSH_WARNING(g->Message);
+
+ } // endif CheckMemory
+
+ if (!bsp) {
+ *res_length = 0;
+ *is_null = 1;
+ *error = 1;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_array_add
+
+void bbin_array_add_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_array_add_deinit
+
+/*********************************************************************************/
+/* Add one or several values to a Bson array. */
+/*********************************************************************************/
+my_bool bbin_array_add_values_init(UDF_INIT* initid, UDF_ARGS* args, char* message)
+{
+ return bson_array_add_values_init(initid, args, message);
+} // end of bbin_array_add_values_init
+
+char* bbin_array_add_values(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char* error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = NULL;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, true)) {
+ uint i = 0;
+ BJNX bnx(g);
+ PBVAL arp, top;
+ PBVAL bvp = bnx.MakeValue(args, 0, true, &top);
+
+ if (bvp->Type == TYPE_JAR) {
+ arp = bvp;
+ i = 1;
+ } else // First argument is not an array
+ arp = bnx.NewVal(TYPE_JAR);
+
+ for (; i < args->arg_count; i++)
+ bnx.AddArrayValue(arp, bnx.MakeValue(args, i));
+
+ bnx.SetChanged(true);
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+ } // endif CheckMemory
+
+ // Keep result of constant function
+ g->Xchk = (g->N) ? bsp : NULL;
+ } else
+ bsp = (PBSON)g->Xchk;
+
+ if (!bsp) {
+ *res_length = 0;
+ *is_null = 1;
+ *error = 1;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_array_add_values
+
+void bbin_array_add_values_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_array_add_values_deinit
+
+/*********************************************************************************/
+/* Make a Json array from values coming from rows. */
+/*********************************************************************************/
+my_bool bbin_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_array_grp_init(initid, args, message);
+} // end of bbin_array_grp_init
+
+void bbin_array_grp_clear(UDF_INIT *initid, char *a, char *b)
+{
+ bson_array_grp_clear(initid, a, b);
+} // end of bbin_array_grp_clear
+
+void bbin_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, char *a, char *b)
+{
+ bson_array_grp_add(initid, args, a, b);
+} // end of bbin_array_grp_add
+
+char *bbin_array_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PBSON bsp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBVAL arp = (PBVAL)g->Activityp;
+
+ if (g->N < 0)
+ PUSH_WARNING("Result truncated to json_grp_size values");
+
+ if (arp)
+ if ((bsp = BbinAlloc(g, initid->max_length, arp)))
+ strcat(bsp->Msg, " array");
+
+ if (!bsp) {
+ *res_length = 0;
+ *is_null = 1;
+ *error = 1;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_array_grp
+
+void bbin_array_grp_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_array_grp_deinit
+
+/*********************************************************************************/
+/* Make a Json object from values coming from rows. */
+/*********************************************************************************/
+my_bool bbin_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_object_grp_init(initid, args, message);
+} // end of bbin_object_grp_init
+
+void bbin_object_grp_clear(UDF_INIT *initid, char *a, char *b)
+{
+ bson_object_grp_clear(initid, a, b);
+} // end of bbin_object_grp_clear
+
+void bbin_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, char *a, char *b)
+{
+ bson_object_grp_add(initid, args, a, b);
+} // end of bbin_object_grp_add
+
+char *bbin_object_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PBSON bsp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBVAL bop = (PBVAL)g->Activityp;
+
+ if (g->N < 0)
+ PUSH_WARNING("Result truncated to json_grp_size values");
+
+ if (bop)
+ if ((bsp = BbinAlloc(g, initid->max_length, bop)))
+ strcat(bsp->Msg, " object");
+
+ if (!bsp) {
+ *res_length = 0;
+ *is_null = 1;
+ *error = 1;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_object_grp
+
+void bbin_object_grp_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_object_grp_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all the parameters. */
+/*********************************************************************************/
+my_bool bbin_make_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of bbin_make_object_init
+
+char *bbin_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp) {
+ if (!CheckMemory(g, initid, args, args->arg_count, true)) {
+ BJNX bnx(g);
+ PBVAL objp;
+
+ if ((objp = bnx.NewVal(TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i++)
+ bnx.SetKeyValue(objp, bnx.MakeValue(args, i), bnx.MakeKey(args, i));
+
+ if ((bsp = BbinAlloc(bnx.G, initid->max_length, objp))) {
+ strcat(bsp->Msg, " object");
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ } // endif objp
+
+ } // endif CheckMemory
+
+ } // endif Xchk
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_make_object
+
+void bbin_make_object_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_make_object_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all not null parameters. */
+/*********************************************************************************/
+my_bool bbin_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bbin_object_nonull_init
+
+char *bbin_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
+ BJNX bnx(g);
+ PBVAL jvp, objp;
+
+ if ((objp = bnx.NewVal(TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i++)
+ if (!bnx.IsValueNull(jvp = bnx.MakeValue(args, i)))
+ bnx.SetKeyValue(objp, jvp, bnx.MakeKey(args, i));
+
+ if ((bsp = BbinAlloc(bnx.G, initid->max_length, objp))) {
+ strcat(bsp->Msg, " object");
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ } // endif objp
+
+ } // endif CheckMemory
+
+ } // endif Xchk
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_object_nonull
+
+void bbin_object_nonull_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_object_nonull_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all the key/value parameters. */
+/*********************************************************************************/
+my_bool bbin_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count % 2) {
+ strcpy(message, "This function must have an even number of arguments");
+ return true;
+ } // endif arg_count
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bbin_object_key_init
+
+char *bbin_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
+ BJNX bnx(g);
+ PBVAL objp;
+
+ if ((objp = bnx.NewVal(TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i += 2)
+ bnx.SetKeyValue(objp, bnx.MakeValue(args, i + 1), MakePSZ(g, args, i));
+
+ if ((bsp = BbinAlloc(bnx.G, initid->max_length, objp))) {
+ strcat(bsp->Msg, " object");
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ } // endif objp
+
+ } // endif CheckMemory
+
+ } // endif Xchk
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_object_key
+
+void bbin_object_key_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_object_key_deinit
+
+/*********************************************************************************/
+/* Add or replace a value in a Json Object. */
+/*********************************************************************************/
+my_bool bbin_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else if (!IsArgJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen, true);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bbin_object_add_init
+
+char *bbin_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = NULL;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ bsp = (PBSON)g->Xchk;
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } else if (!CheckMemory(g, initid, args, 2, false, true, true)) {
+ PSZ key;
+ BJNX bnx(g, NULL, TYPE_STRING);
+ PBVAL top;
+ PBVAL jobp = bnx.MakeValue(args, 0, true, &top);
+ PBVAL jvp = jobp;
+
+ if (bnx.CheckPath(g, args, jvp, jobp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jobp && jobp->Type == TYPE_JOB) {
+ jvp = bnx.MakeValue(args, 1);
+ key = bnx.MakeKey(args, 1);
+ bnx.SetKeyValue(jobp, jvp, key);
+ bnx.SetChanged(true);
+ } else {
+ PUSH_WARNING("First argument target is not an object");
+ // if (g->Mrr) *error = 1; (only if no path)
+ } // endif jobp
+
+ // In case of error unchanged argument will be returned
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ } // endif CheckMemory
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_object_add
+
+void bbin_object_add_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_object_add_deinit
+
+/*********************************************************************************/
+/* Delete a value from a Json array. */
+/*********************************************************************************/
+my_bool bbin_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_array_delete_init(initid, args, message);
+} // end of bbin_array_delete_init
+
+char *bbin_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = NULL;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ bsp = (PBSON)g->Xchk;
+ } else if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ int* x;
+ uint n = 1;
+ BJNX bnx(g);
+ PBVAL arp, top;
+ PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
+
+ if (!(x = GetIntArgPtr(g, args, n)))
+ PUSH_WARNING("Missing or null array index");
+ else if (bnx.CheckPath(g, args, jvp, arp, 1))
+ PUSH_WARNING(g->Message);
+ else if (arp && arp->Type == TYPE_JAR) {
+ bnx.SetChanged(bnx.DeleteValue(arp, *x));
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+ } else {
+ PUSH_WARNING("First argument target is not an array");
+ // if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ } // endif CheckMemory
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_array_delete
+
+void bbin_array_delete_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_array_delete_deinit
+
+/*********************************************************************************/
+/* Delete a value from a Json object. */
+/*********************************************************************************/
+my_bool bbin_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have 2 or 3 arguments");
+ return true;
+ } else if (!IsArgJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument must be a key string");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen, true);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of bbin_object_delete_init
+
+char *bbin_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = NULL;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ bsp = (PBSON)g->Xchk;
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } else if (!CheckMemory(g, initid, args, 1, false, true, true)) {
+ PCSZ key;
+ BJNX bnx(g, NULL, TYPE_STRING);
+ PBVAL top;
+ PBVAL jobp = bnx.MakeValue(args, 0, true, &top);
+
+ if (bnx.CheckPath(g, args, top, jobp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jobp && jobp->Type == TYPE_JOB) {
+ key = bnx.MakeKey(args, 1);
+ bnx.SetChanged(bnx.DeleteKey(jobp, key));
+ } else {
+ PUSH_WARNING("First argument target is not an object");
+ // if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ // In case of error unchanged argument will be returned
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ } // endif CheckMemory
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_object_delete
+
+void bbin_object_delete_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_object_delete_deinit
+
+/*********************************************************************************/
+/* Returns an array of the Json object keys. */
+/*********************************************************************************/
+my_bool bbin_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_object_list_init(initid, args, message);
+} // end of bbin_object_list_init
+
+char *bbin_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp) {
+ if (!CheckMemory(g, initid, args, 1, true, true)) {
+ BJNX bnx(g);
+ PBVAL top, jarp = NULL;
+ PBVAL jsp = bnx.MakeValue(args, 0, true, &top);
+
+ if (jsp->Type == TYPE_JOB) {
+ jarp = bnx.GetKeyList(jsp);
+ } else {
+ PUSH_WARNING("First argument is not an object");
+ if (g->Mrr) *error = 1;
+ } // endif jsp type
+
+ // In case of error unchanged argument will be returned
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+ bsp->Jsp = (PJSON)jarp;
+
+ } // endif CheckMemory
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_object_list
+
+void bbin_object_list_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_object_list_deinit
+
+/*********************************************************************************/
+/* Returns an array of the Json object values. */
+/*********************************************************************************/
+my_bool bbin_object_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_object_values_init(initid, args, message);
+} // end of bbin_object_values_init
+
+char *bbin_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp) {
+ if (!CheckMemory(g, initid, args, 1, true, true)) {
+ BJNX bnx(g);
+ PBVAL top, jarp = NULL;
+ PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
+
+ if (jvp->Type == TYPE_JOB) {
+ jarp = bnx.GetObjectValList(jvp);
+ } else {
+ PUSH_WARNING("First argument is not an object");
+ if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ // In case of error unchanged argument will be returned
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+ bsp->Jsp = (PJSON)jarp;
+
+ } // endif CheckMemory
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ g->Xchk = bsp;
+ } // endif const_item
+
+ } // endif bsp
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_object_values
+
+void bbin_object_values_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_object_values_deinit
+
+/*********************************************************************************/
+/* Get a Json item from a Json document. */
+/*********************************************************************************/
+my_bool bbin_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_get_item_init(initid, args, message);
+} // end of bbin_get_item_init
+
+char *bbin_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PBSON bsp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ bsp = (PBSON)g->Xchk;
+ } else if (!CheckMemory(g, initid, args, 1, true, true)) {
+ // char *path = MakePSZ(g, args, 1);
+ BJNX bnx(g, NULL, TYPE_STRING, initid->max_length);
+ PBVAL top, jvp = NULL;
+ PBVAL jsp = bnx.MakeValue(args, 0, true, &top);
+
+ if (bnx.CheckPath(g, args, jsp, jvp, 1))
+ PUSH_WARNING(g->Message);
+ else if (jvp) {
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+ bsp->Jsp = (PJSON)jvp;
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ } // endif jvp
+
+ } else
+ PUSH_WARNING("CheckMemory error");
+
+ if (!bsp) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_get_item
+
+void bbin_get_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_get_item_deinit
+
+/*********************************************************************************/
+/* Merge two arrays or objects. */
+/*********************************************************************************/
+my_bool bbin_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_item_merge_init(initid, args, message);
+} // end of bbin_item_merge_init
+
+char *bbin_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PBSON bsp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ bsp = (PBSON)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 2, false, false, true)) {
+ JTYP type;
+ BJNX bnx(g);
+ PBVAL jvp, top = NULL;
+ PBVAL jsp[2] = {NULL, NULL};
+
+ for (int i = 0; i < 2; i++) {
+ if (i) {
+ jvp = bnx.MakeValue(args, i, true);
+
+ if (jvp->Type != type) {
+ PUSH_WARNING("Argument types mismatch");
+ goto fin;
+ } // endif type
+
+ } else {
+ jvp = bnx.MakeValue(args, i, true, &top);
+ type = (JTYP)jvp->Type;
+
+ if (type != TYPE_JAR && type != TYPE_JOB) {
+ PUSH_WARNING("First argument is not an array or object");
+ goto fin;
+ } // endif type
+
+ } // endif i
+
+ jsp[i] = jvp;
+ } // endfor i
+
+ if (type == TYPE_JAR)
+ bnx.MergeArray(jsp[0], jsp[1]);
+ else
+ bnx.MergeObject(jsp[0], jsp[1]);
+
+ bnx.SetChanged(true);
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+ } // endif CheckMemory
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+fin:
+ if (!bsp) {
+ *res_length = 0;
+ *error = 1;
+ *is_null = 1;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_item_merge
+
+void bbin_item_merge_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_item_merge_deinit
+
+/*********************************************************************************/
+/* This function is used by the jbin_set/insert/update_item functions. */
+/*********************************************************************************/
+static char *bbin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *path;
+ int w;
+ my_bool b = true;
+ PBJNX bxp;
+ PBVAL jsp, jvp, top;
+ PBSON bsp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Alchecked) {
+ bsp = (PBSON)g->Activityp;
+ goto fin;
+ } else if (g->N)
+ g->Alchecked = 1;
+
+ if (!strcmp(result, "$set"))
+ w = 0;
+ else if (!strcmp(result, "$insert"))
+ w = 1;
+ else if (!strcmp(result, "$update"))
+ w = 2;
+ else {
+ PUSH_WARNING("Logical error, please contact CONNECT developer");
+ goto fin;
+ } // endelse
+
+ try {
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true, false, true)) {
+ throw 1;
+ } else {
+ BJNX bnx(g);
+
+ jsp = bnx.MakeValue(args, 0, true, &top);
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ g->More = (size_t)top;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } // endif CheckMemory
+
+ } else {
+ jsp = (PBVAL)g->Xchk;
+ top = (PBVAL)g->More;
+ } // endif Xchk
+
+ bxp = new(g)BJNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
+
+ for (uint i = 1; i + 1 < args->arg_count; i += 2) {
+ jvp = bxp->MakeValue(args, i);
+ path = MakePSZ(g, args, i + 1);
+
+ if (bxp->SetJpath(g, path, false))
+ throw 2;
+
+ if (w) {
+ bxp->ReadValue(g);
+ b = bxp->GetValue()->IsNull();
+ b = (w == 1) ? b : !b;
+ } // endif w
+
+ if (b && bxp->WriteValue(g, jvp))
+ throw 3;
+
+ bxp->SetChanged(true);
+ } // endfor i
+
+ if (!(bsp = bxp->MakeBinResult(args, top, initid->max_length)))
+ throw 4;
+
+ if (g->N)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)bsp;
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ } // end catch
+
+fin:
+ if (!bsp) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_handle_item
+
+/*********************************************************************************/
+/* Set Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool bbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_set_item_init(initid, args, message);
+} // end of bbin_set_item_init
+
+char *bbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$set");
+ return bbin_handle_item(initid, args, result, res_length, is_null, p);
+} // end of bbin_set_item
+
+void bbin_set_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_set_item_deinit
+
+/*********************************************************************************/
+/* Insert Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool bbin_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_set_item_init(initid, args, message);
+} // end of bbin_insert_item_init
+
+char *bbin_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$insert");
+ return bbin_handle_item(initid, args, result, res_length, is_null, p);
+} // end of bbin_insert_item
+
+void bbin_insert_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_insert_item_deinit
+
+/*********************************************************************************/
+/* Update Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool bbin_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_set_item_init(initid, args, message);
+} // end of bbin_update_item_init
+
+char *bbin_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$update");
+ return bbin_handle_item(initid, args, result, res_length, is_null, p);
+} // end of bbin_update_item
+
+void bbin_update_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_update_item_deinit
+
+/*********************************************************************************/
+/* Delete items from a Json document. */
+/*********************************************************************************/
+my_bool bbin_delete_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_delete_item_init(initid, args, message);
+} // end of bbin_delete_item_init
+
+char *bbin_delete_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *path;
+ PBSON bsp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ bsp = (PBSON)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ BJNX bnx(g, NULL, TYPE_STRING);
+ PBVAL top, jar = NULL;
+ PBVAL jvp = bnx.MakeValue(args, 0, true, &top);
+
+ if (args->arg_count == 1) {
+ // This should be coming from bbin_locate_all
+ jar = jvp; // This is the array of paths
+ jvp = top; // And this is the document
+ } else if(!bnx.IsJson(jvp)) {
+ PUSH_WARNING("First argument is not a JSON document");
+ goto fin;
+ } else if (args->arg_count == 2) {
+ // Check whether this is an array of paths
+ jar = bnx.MakeValue(args, 1, true);
+
+ if (jar && jar->Type != TYPE_JAR)
+ jar = NULL;
+
+ } // endif arg_count
+
+ if (jar) {
+ // Do the deletion in reverse order
+ for(int i = bnx.GetArraySize(jar) - 1; i >= 0; i--) {
+ path = bnx.GetString(bnx.GetArrayValue(jar, i));
+
+ if (bnx.SetJpath(g, path, false)) {
+ PUSH_WARNING(g->Message);
+ continue;
+ } // endif SetJpath
+
+ bnx.SetChanged(bnx.DeleteItem(g, jvp));
+ } // endfor i
+
+ } else for (uint i = 1; i < args->arg_count; i++) {
+ path = MakePSZ(g, args, i);
+
+ if (bnx.SetJpath(g, path, false)) {
+ PUSH_WARNING(g->Message);
+ continue;
+ } // endif SetJpath
+
+ bnx.SetChanged(bnx.DeleteItem(g, jvp));
+ } // endfor i
+
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+
+ if (args->arg_count == 1)
+ // Here Jsp was not a sub-item of top
+ bsp->Jsp = (PJSON)top;
+
+ } // endif CheckMemory
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+fin:
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_delete_item
+
+void bbin_delete_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_delete_item_deinit
+
+/*********************************************************************************/
+/* Returns a json file as a json binary tree. */
+/*********************************************************************************/
+my_bool bbin_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return bson_file_init(initid, args, message);
+} // end of bbin_file_init
+
+char *bbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *fn;
+ int pretty = 3;
+ size_t len = 0;
+ PBVAL jsp, jvp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ BJNX bnx(g);
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (bsp)
+ goto fin;
+
+ fn = MakePSZ(g, args, 0);
+
+ for (unsigned int i = 1; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
+ pretty = (int) * (longlong*)args->args[i];
+ break;
+ } // endif type
+
+ // Parse the json file and allocate its tree structure
+ if (!(jsp = bnx.ParseJsonFile(g, fn, pretty, len))) {
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ goto fin;
+ } // endif jsp
+
+// if (pretty == 3)
+// PUSH_WARNING("File pretty format cannot be determined");
+// else if (pretty == 3)
+// pretty = pty;
+
+ if ((bsp = BbinAlloc(bnx.G, len, jsp))) {
+ strcat(bsp->Msg, " file");
+ bsp->Filename = fn;
+ bsp->Pretty = pretty;
+ } else {
+ *error = 1;
+ goto fin;
+ } // endif bsp
+
+ // Check whether a path was specified
+ if (bnx.CheckPath(g, args, jsp, jvp, 1)) {
+ PUSH_WARNING(g->Message);
+ bsp = NULL;
+ goto fin;
+ } else if (jvp)
+ bsp->Jsp = (PJSON)jvp;
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+fin:
+ if (!bsp) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_file
+
+void bbin_file_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_file_deinit
+
+/*********************************************************************************/
+/* Locate all occurences of a value in a Json tree. */
+/*********************************************************************************/
+my_bool bbin_locate_all_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ return bson_locate_all_init(initid, args, message);
+} // end of bbin_locate_all_init
+
+char* bbin_locate_all(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long* res_length, char* is_null, char* error) {
+ char *path = NULL;
+ int mx = 10;
+ PBVAL bvp, bvp2;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = NULL;
+
+ if (g->N) {
+ if (g->Activityp) {
+ bsp = (PBSON)g->Activityp;
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } else {
+ *error = 1;
+ *res_length = 0;
+ *is_null = 1;
+ return NULL;
+ } // endif Activityp
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ try {
+ PBVAL top = NULL;
+ BJNX bnx(g);
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ *error = 1;
+ goto err;
+ } else
+ bnx.Reset();
+
+ bvp = bnx.MakeValue(args, 0, true, &top);
+
+ if (bvp->Type == TYPE_NULL) {
+ PUSH_WARNING("First argument is not a valid JSON item");
+ goto err;
+ } // endif bvp
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = bvp;
+ g->More = (size_t)top;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else {
+ bvp = (PBVAL)g->Xchk;
+ top = (PBVAL)g->More;
+ } // endif Xchk
+
+ // The item to locate
+ bvp2 = bnx.MakeValue(args, 1, true);
+
+ if (bvp2->Type == TYPE_NULL) {
+ PUSH_WARNING("Invalid second argument");
+ goto err;
+ } // endif bvp2
+
+ if (args->arg_count > 2)
+ mx = (int)*(long long*)args->args[2];
+
+ if ((path = bnx.LocateAll(g, bvp, bvp2, mx))) {
+ bsp = bnx.MakeBinResult(args, top, initid->max_length);
+ bsp->Jsp = (PJSON)bnx.ParseJson(g, path, strlen(path));
+ } // endif path
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)bsp;
+
+ } catch (int n) {
+ xtrc(1, "Exception %d: %s\n", n, g->Message);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } // end catch
+
+err:
+ if (!bsp) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bbin_locate_all
+
+void bbin_locate_all_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of bbin_locate_all_deinit
+
+
diff --git a/storage/connect/bsonudf.h b/storage/connect/bsonudf.h
new file mode 100644
index 00000000..0fe37156
--- /dev/null
+++ b/storage/connect/bsonudf.h
@@ -0,0 +1,410 @@
+/******************** tabjson H Declares Source Code File (.H) *******************/
+/* Name: bsonudf.h Version 1.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2020 - 2021 */
+/* */
+/* This file contains the BSON UDF function and class declares. */
+/*********************************************************************************/
+#pragma once
+#include "jsonudf.h"
+#include "bson.h"
+
+#if 0
+#define UDF_EXEC_ARGS \
+ UDF_INIT*, UDF_ARGS*, char*, unsigned long*, char*, char*
+
+// BSON size should be equal on Linux and Windows
+#define BMX 255
+typedef struct BSON* PBSON;
+
+/***********************************************************************/
+/* Structure used to return binary json to Json UDF functions. */
+/***********************************************************************/
+struct BSON {
+ char Msg[BMX + 1];
+ char *Filename;
+ PGLOBAL G;
+ int Pretty;
+ ulong Reslen;
+ my_bool Changed;
+ PJSON Top;
+ PJSON Jsp;
+ PBSON Bsp;
+}; // end of struct BSON
+
+PBSON JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp);
+
+/*********************************************************************************/
+/* The JSON tree node. Can be an Object or an Array. */
+/*********************************************************************************/
+typedef struct _jnode {
+ PSZ Key; // The key used for object
+ OPVAL Op; // Operator used for this node
+ PVAL CncVal; // To cont value used for OP_CNC
+ int Rank; // The rank in array
+ int Rx; // Read row number
+ int Nx; // Next to read row number
+} JNODE, *PJNODE;
+
+/*********************************************************************************/
+/* The JSON utility functions. */
+/*********************************************************************************/
+bool IsNum(PSZ s);
+char *NextChr(PSZ s, char sep);
+char *GetJsonNull(void);
+uint GetJsonGrpSize(void);
+my_bool JsonSubSet(PGLOBAL g, my_bool b = false);
+my_bool CalcLen(UDF_ARGS* args, my_bool obj, unsigned long& reslen,
+ unsigned long& memlen, my_bool mod = false);
+my_bool JsonInit(UDF_INIT* initid, UDF_ARGS* args, char* message, my_bool mbn,
+ unsigned long reslen, unsigned long memlen,
+ unsigned long more = 0);
+my_bool CheckMemory(PGLOBAL g, UDF_INIT* initid, UDF_ARGS* args, uint n,
+ my_bool m, my_bool obj = false, my_bool mod = false);
+PSZ MakePSZ(PGLOBAL g, UDF_ARGS* args, int i);
+int IsArgJson(UDF_ARGS* args, uint i);
+char *GetJsonFile(PGLOBAL g, char* fn);
+
+/*********************************************************************************/
+/* Structure JPN. Used to make the locate path. */
+/*********************************************************************************/
+typedef struct _jpn {
+ int Type;
+ PCSZ Key;
+ int N;
+} JPN, *PJPN;
+
+#endif // 0
+
+/* --------------------------- New Testing BJSON Stuff --------------------------*/
+extern uint JsonGrpSize;
+uint GetJsonGroupSize(void);
+
+
+typedef class BJNX* PBJNX;
+
+/*********************************************************************************/
+/* Class BJNX: BJSON access methods. */
+/*********************************************************************************/
+class BJNX : public BDOC {
+public:
+ // Constructors
+ BJNX(PGLOBAL g);
+ BJNX(PGLOBAL g, PBVAL row, int type, int len = 64, int prec = 0, my_bool wr = false);
+
+ // Implementation
+ int GetPrecision(void) { return Prec; }
+ PVAL GetValue(void) { return Value; }
+ void SetRow(PBVAL vp) { Row = vp; }
+ void SetChanged(my_bool b) { Changed = b; }
+
+ // Methods
+ my_bool SetJpath(PGLOBAL g, char* path, my_bool jb = false);
+ my_bool ParseJpath(PGLOBAL g);
+ void ReadValue(PGLOBAL g);
+ PBVAL GetRowValue(PGLOBAL g, PBVAL row, int i);
+ PBVAL GetJson(PGLOBAL g);
+ my_bool CheckPath(PGLOBAL g);
+ my_bool CheckPath(PGLOBAL g, UDF_ARGS* args, PBVAL jsp, PBVAL& jvp, int n);
+ my_bool WriteValue(PGLOBAL g, PBVAL jvalp);
+ my_bool DeleteItem(PGLOBAL g, PBVAL vlp);
+ char *Locate(PGLOBAL g, PBVAL jsp, PBVAL jvp, int k = 1);
+ char *LocateAll(PGLOBAL g, PBVAL jsp, PBVAL jvp, int mx = 10);
+ PSZ MakeKey(UDF_ARGS* args, int i);
+ PBVAL MakeValue(UDF_ARGS* args, uint i, bool b = false, PBVAL* top = NULL);
+ PBVAL MakeTypedValue(PGLOBAL g, UDF_ARGS* args, uint i,
+ JTYP type, PBVAL* top = NULL);
+ PBVAL ParseJsonFile(PGLOBAL g, char* fn, int& pty, size_t& len);
+ char *MakeResult(UDF_ARGS* args, PBVAL top, uint n = 2);
+ PBSON MakeBinResult(UDF_ARGS* args, PBVAL top, ulong len, int n = 2);
+
+protected:
+ my_bool SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm);
+ PVAL GetColumnValue(PGLOBAL g, PBVAL row, int i);
+ PVAL ExpandArray(PGLOBAL g, PBVAL arp, int n);
+ PVAL CalculateArray(PGLOBAL g, PBVAL arp, int n);
+ PVAL GetCalcValue(PGLOBAL g, PBVAL bap, int n);
+ PBVAL MakeJson(PGLOBAL g, PBVAL bvp, int n);
+ void SetJsonValue(PGLOBAL g, PVAL vp, PBVAL vlp);
+ PBVAL GetRow(PGLOBAL g);
+ PBVAL MoveVal(PBVAL vlp);
+ PBVAL MoveJson(PBJNX bxp, PBVAL jvp);
+ PBVAL MoveArray(PBJNX bxp, PBVAL jvp);
+ PBVAL MoveObject(PBJNX bxp, PBVAL jvp);
+ PBVAL MoveValue(PBJNX bxp, PBVAL jvp);
+ my_bool CompareValues(PGLOBAL g, PBVAL v1, PBVAL v2);
+ my_bool LocateArray(PGLOBAL g, PBVAL jarp);
+ my_bool LocateObject(PGLOBAL g, PBVAL jobp);
+ my_bool LocateValue(PGLOBAL g, PBVAL jvp);
+ my_bool LocateArrayAll(PGLOBAL g, PBVAL jarp);
+ my_bool LocateObjectAll(PGLOBAL g, PBVAL jobp);
+ my_bool LocateValueAll(PGLOBAL g, PBVAL jvp);
+ my_bool CompareTree(PGLOBAL g, PBVAL jp1, PBVAL jp2);
+ my_bool AddPath(void);
+
+ // Default constructor not to be used
+ BJNX(void) {}
+
+ // Members
+ PBVAL Row;
+ PBVAL Bvalp;
+ PJPN Jpnp;
+ JOUTSTR *Jp;
+ JNODE *Nodes; // The intermediate objects
+ PVAL Value;
+ //PVAL MulVal; // To value used by multiple column
+ char *Jpath; // The json path
+ int Buf_Type;
+ int Long;
+ int Prec;
+ int Nod; // The number of intermediate objects
+ int Xnod; // Index of multiple values
+ int K; // Kth item to locate
+ int I; // Index of JPN
+ int Imax; // Max number of JPN's
+ int B; // Index base
+ my_bool Xpd; // True for expandable column
+ my_bool Parsed; // True when parsed
+ my_bool Found; // Item found by locate
+ my_bool Wr; // Write mode
+ my_bool Jb; // Must return json item
+ my_bool Changed; // True when contains was modified
+}; // end of class BJNX
+
+extern "C" {
+ DllExport my_bool bson_test_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_test(UDF_EXEC_ARGS);
+ DllExport void bson_test_deinit(UDF_INIT*);
+
+ DllExport my_bool bsonvalue_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bsonvalue(UDF_EXEC_ARGS);
+ DllExport void bsonvalue_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_make_array_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_make_array(UDF_EXEC_ARGS);
+ DllExport void bson_make_array_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_array_add_values_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_array_add_values(UDF_EXEC_ARGS);
+ DllExport void bson_array_add_values_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_array_add_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_array_add(UDF_EXEC_ARGS);
+ DllExport void bson_array_add_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_array_delete_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_array_delete(UDF_EXEC_ARGS);
+ DllExport void bson_array_delete_deinit(UDF_INIT*);
+
+ DllExport my_bool bsonlocate_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bsonlocate(UDF_EXEC_ARGS);
+ DllExport void bsonlocate_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_locate_all_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_locate_all(UDF_EXEC_ARGS);
+ DllExport void bson_locate_all_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_contains_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long bson_contains(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void bson_contains_deinit(UDF_INIT*);
+
+ DllExport my_bool bsoncontains_path_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long bsoncontains_path(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void bsoncontains_path_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_make_object_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_make_object(UDF_EXEC_ARGS);
+ DllExport void bson_make_object_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_object_nonull_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_object_nonull(UDF_EXEC_ARGS);
+ DllExport void bson_object_nonull_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_object_key_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_object_key(UDF_EXEC_ARGS);
+ DllExport void bson_object_key_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_object_add_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_object_add(UDF_EXEC_ARGS);
+ DllExport void bson_object_add_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_object_delete_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_object_delete(UDF_EXEC_ARGS);
+ DllExport void bson_object_delete_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_object_list_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_object_list(UDF_EXEC_ARGS);
+ DllExport void bson_object_list_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_object_values_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_object_values(UDF_EXEC_ARGS);
+ DllExport void bson_object_values_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_item_merge_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_item_merge(UDF_EXEC_ARGS);
+ DllExport void bson_item_merge_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_get_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bson_get_item(UDF_EXEC_ARGS);
+ DllExport void bson_get_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bsonget_string_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bsonget_string(UDF_EXEC_ARGS);
+ DllExport void bsonget_string_deinit(UDF_INIT*);
+
+ DllExport my_bool bsonget_int_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long bsonget_int(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void bsonget_int_deinit(UDF_INIT*);
+
+ DllExport my_bool bsonget_real_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport double bsonget_real(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void bsonget_real_deinit(UDF_INIT*);
+
+ DllExport my_bool bsonset_def_prec_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long bsonset_def_prec(UDF_INIT*, UDF_ARGS*, char*, char*);
+
+ DllExport my_bool bsonget_def_prec_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long bsonget_def_prec(UDF_INIT*, UDF_ARGS*, char*, char*);
+
+ DllExport my_bool bsonset_grp_size_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long bsonset_grp_size(UDF_INIT*, UDF_ARGS*, char*, char*);
+
+ DllExport my_bool bsonget_grp_size_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long bsonget_grp_size(UDF_INIT*, UDF_ARGS*, char*, char*);
+
+ DllExport my_bool bson_array_grp_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport void bson_array_grp_clear(UDF_INIT *, char *, char *);
+ DllExport void bson_array_grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
+ DllExport char *bson_array_grp(UDF_EXEC_ARGS);
+ DllExport void bson_array_grp_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_object_grp_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport void bson_object_grp_clear(UDF_INIT *, char *, char *);
+ DllExport void bson_object_grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
+ DllExport char *bson_object_grp(UDF_EXEC_ARGS);
+ DllExport void bson_object_grp_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_delete_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bson_delete_item(UDF_EXEC_ARGS);
+ DllExport void bson_delete_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_set_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bson_set_item(UDF_EXEC_ARGS);
+ DllExport void bson_set_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_insert_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bson_insert_item(UDF_EXEC_ARGS);
+ DllExport void bson_insert_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_update_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bson_update_item(UDF_EXEC_ARGS);
+ DllExport void bson_update_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_file_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bson_file(UDF_EXEC_ARGS);
+ DllExport void bson_file_deinit(UDF_INIT*);
+
+ DllExport my_bool bfile_make_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bfile_make(UDF_EXEC_ARGS);
+ DllExport void bfile_make_deinit(UDF_INIT*);
+
+ DllExport my_bool bfile_convert_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bfile_convert(UDF_EXEC_ARGS);
+ DllExport void bfile_convert_deinit(UDF_INIT*);
+
+ DllExport my_bool bfile_bjson_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bfile_bjson(UDF_EXEC_ARGS);
+ DllExport void bfile_bjson_deinit(UDF_INIT*);
+
+ DllExport my_bool bson_serialize_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bson_serialize(UDF_EXEC_ARGS);
+ DllExport void bson_serialize_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_make_array_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_make_array(UDF_EXEC_ARGS);
+ DllExport void bbin_make_array_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_array_add_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_array_add(UDF_EXEC_ARGS);
+ DllExport void bbin_array_add_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_array_add_values_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_array_add_values(UDF_EXEC_ARGS);
+ DllExport void bbin_array_add_values_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_array_delete_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_array_delete(UDF_EXEC_ARGS);
+ DllExport void bbin_array_delete_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_array_grp_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport void bbin_array_grp_clear(UDF_INIT *, char *, char *);
+ DllExport void bbin_array_grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
+ DllExport char *bbin_array_grp(UDF_EXEC_ARGS);
+ DllExport void bbin_array_grp_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_object_grp_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport void bbin_object_grp_clear(UDF_INIT *, char *, char *);
+ DllExport void bbin_object_grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
+ DllExport char *bbin_object_grp(UDF_EXEC_ARGS);
+ DllExport void bbin_object_grp_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_make_object_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_make_object(UDF_EXEC_ARGS);
+ DllExport void bbin_make_object_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_object_nonull_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_object_nonull(UDF_EXEC_ARGS);
+ DllExport void bbin_object_nonull_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_object_key_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_object_key(UDF_EXEC_ARGS);
+ DllExport void bbin_object_key_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_object_add_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_object_add(UDF_EXEC_ARGS);
+ DllExport void bbin_object_add_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_object_delete_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_object_delete(UDF_EXEC_ARGS);
+ DllExport void bbin_object_delete_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_object_list_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_object_list(UDF_EXEC_ARGS);
+ DllExport void bbin_object_list_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_object_values_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_object_values(UDF_EXEC_ARGS);
+ DllExport void bbin_object_values_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_get_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_get_item(UDF_EXEC_ARGS);
+ DllExport void bbin_get_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_item_merge_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_item_merge(UDF_EXEC_ARGS);
+ DllExport void bbin_item_merge_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_set_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_set_item(UDF_EXEC_ARGS);
+ DllExport void bbin_set_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_insert_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_insert_item(UDF_EXEC_ARGS);
+ DllExport void bbin_insert_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_update_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_update_item(UDF_EXEC_ARGS);
+ DllExport void bbin_update_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_delete_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_delete_item(UDF_EXEC_ARGS);
+ DllExport void bbin_delete_item_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_locate_all_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* bbin_locate_all(UDF_EXEC_ARGS);
+ DllExport void bbin_locate_all_deinit(UDF_INIT*);
+
+ DllExport my_bool bbin_file_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *bbin_file(UDF_EXEC_ARGS);
+ DllExport void bbin_file_deinit(UDF_INIT*);
+} // extern "C"
diff --git a/storage/connect/catalog.h b/storage/connect/catalog.h
new file mode 100644
index 00000000..48347d75
--- /dev/null
+++ b/storage/connect/catalog.h
@@ -0,0 +1,105 @@
+/*************** Catalog H Declares Source Code File (.H) **************/
+/* Name: CATALOG.H Version 3.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2000-2015 */
+/* */
+/* This file contains the CATALOG PlugDB classes definitions. */
+/***********************************************************************/
+#ifndef __CATALOG__H
+#define __CATALOG__H
+
+#include "block.h"
+
+/***********************************************************************/
+/* Defines the length of a buffer to contain entire table section. */
+/***********************************************************************/
+#define PLG_MAX_PATH 144 /* Must be the same across systems */
+#define PLG_BUFF_LEN 100 /* Number of lines in binary file buffer */
+
+
+//typedef class INDEXDEF *PIXDEF;
+
+/***********************************************************************/
+/* Defines the structure used to enumerate tables or views. */
+/***********************************************************************/
+typedef struct _curtab {
+ PRELDEF CurTdb;
+ char *Curp;
+ char *Tabpat;
+ bool Ispat;
+ bool NoView;
+ int Nt;
+ char *Type[16];
+ } CURTAB, *PCURTAB;
+
+/***********************************************************************/
+/* Defines the structure used to get column catalog info. */
+/***********************************************************************/
+typedef struct _colinfo {
+ PCSZ Name;
+ int Type;
+ int Offset;
+ int Length;
+ int Key;
+ int Precision;
+ int Scale;
+ int Opt;
+ int Freq;
+ PCSZ Remark;
+ PCSZ Datefmt;
+ PCSZ Fieldfmt;
+ ushort Flags; // Used by MariaDB CONNECT handlers
+ } COLINFO, *PCOLINFO;
+
+/***********************************************************************/
+/* CATALOG: base class for catalog classes. */
+/***********************************************************************/
+class DllExport CATALOG {
+ friend class RELDEF;
+ friend class TABDEF;
+ friend class DIRDEF;
+ friend class OEMDEF;
+ public:
+ CATALOG(void); // Constructor
+ virtual ~CATALOG() { } // Make -Wdelete-non-virtual-dtor happy
+
+ // Implementation
+ int GetCblen(void) {return Cblen;}
+ bool GetDefHuge(void) {return DefHuge;}
+ void SetDefHuge(bool b) {DefHuge = b;}
+ char *GetCbuf(void) {return Cbuf;}
+
+ // Methods
+ virtual void Reset(void) {}
+ virtual bool CheckName(PGLOBAL, char*) {return true;}
+ virtual bool ClearName(PGLOBAL, PSZ) {return true;}
+ virtual PRELDEF MakeOneTableDesc(PGLOBAL, LPCSTR, LPCSTR) {return NULL;}
+ virtual PRELDEF GetTableDescEx(PGLOBAL, PTABLE) {return NULL;}
+ //virtual PRELDEF GetTableDesc(PGLOBAL, LPCSTR, LPCSTR,
+ // PRELDEF* = NULL) {return NULL;}
+ virtual PRELDEF GetFirstTable(PGLOBAL) {return NULL;}
+ virtual PRELDEF GetNextTable(PGLOBAL) {return NULL;}
+ virtual bool TestCond(PGLOBAL, const char*, const char*) {return true;}
+ virtual bool DropTable(PGLOBAL, PSZ, bool) {return true;}
+ virtual PTDB GetTable(PGLOBAL, PTABLE,
+ MODE = MODE_READ, LPCSTR = NULL) {return NULL;}
+ virtual void TableNames(PGLOBAL, char*, int, int[]) {}
+ virtual void ColumnNames(PGLOBAL, char*, char*, int, int[]) {}
+ virtual void ColumnDefs(PGLOBAL, char*, char*, int, int[]) {}
+ virtual void *DecodeValues(PGLOBAL, char*, char*, char*,
+ int, int[]) {return NULL;}
+ virtual int ColumnType(PGLOBAL, char*, char*) {return 0;}
+ virtual void ClearDB(PGLOBAL) {}
+
+ protected:
+ virtual bool ClearSection(PGLOBAL, const char*, const char*) {return true;}
+ //virtual PRELDEF MakeTableDesc(PGLOBAL, LPCSTR, LPCSTR) {return NULL;}
+
+ // Members
+ char *Cbuf; /* Buffer used for col section */
+ int Cblen; /* Length of suballoc. buffer */
+ CURTAB Ctb; /* Used to enumerate tables */
+ bool DefHuge; /* true: tables default to huge */
+ }; // end of class CATALOG
+
+#endif // __CATALOG__H
diff --git a/storage/connect/checklvl.h b/storage/connect/checklvl.h
new file mode 100644
index 00000000..9029e616
--- /dev/null
+++ b/storage/connect/checklvl.h
@@ -0,0 +1,51 @@
+/************** PlgDBSem H Declares Source Code File (.H) **************/
+/* Name: CHKLVL.H Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2009 */
+/* */
+/* This file contains the definition of the checking level constants. */
+/***********************************************************************/
+
+#if !defined(_CHKLVL_DEFINED_)
+#define _CHKLVL_DEFINED_
+/***********************************************************************/
+/* Following definitions are used to indicate the level of checking. */
+/***********************************************************************/
+enum CHKLVL {CHK_NO = 0x00, /* No checking */
+ CHK_TYPE = 0x01, /* Check types for Insert/Update */
+ CHK_UPDATE = 0x02, /* Two pass checking of Update */
+ CHK_DELETE = 0x04, /* Indexed checking of Delete */
+ CHK_JOIN = 0x08, /* Check types joining tables */
+ CHK_OPT = 0x10, /* Automatic optimize on changes */
+ CHK_MANY = 0x20, /* Check many-to-many joins */
+ CHK_ALL = 0x3F, /* All of the above */
+ CHK_STD = 0x1E, /* Standard level of checking */
+ CHK_MAXRES = 0x40, /* Prevent Maxres recalculation */
+ CHK_ONLY = 0x100}; /* Just check, no action (NIY) */
+
+/***********************************************************************/
+/* Following definitions are used to indicate the execution mode. */
+/***********************************************************************/
+enum XMOD {XMOD_EXECUTE = 0, /* DOS execution mode */
+ XMOD_PREPARE = 1, /* Prepare mode */
+ XMOD_TEST = 2, /* Test mode */
+ XMOD_CONVERT = 3}; /* HQL conversion mode */
+
+/***********************************************************************/
+/* Following definitions indicate the use of a temporay file. */
+/***********************************************************************/
+enum USETEMP {TMP_NO = 0, /* Never */
+ TMP_AUTO = 1, /* Best choice */
+ TMP_YES = 2, /* Always */
+ TMP_FORCE = 3, /* Forced for MAP tables */
+ TMP_TEST = 4}; /* Testing value */
+
+/***********************************************************************/
+/* Following definitions indicate conversion of TEXT columns. */
+/***********************************************************************/
+enum TYPCONV {TPC_NO = 0, /* Never */
+ TPC_YES = 1, /* Always */
+ TPC_FORCE = 2, /* Also convert BLOBs */
+ TPC_SKIP = 3}; /* Skip TEXT columns */
+
+#endif // _CHKLVL_DEFINED_
diff --git a/storage/connect/cmgfam.cpp b/storage/connect/cmgfam.cpp
new file mode 100644
index 00000000..a3afc154
--- /dev/null
+++ b/storage/connect/cmgfam.cpp
@@ -0,0 +1,315 @@
+/************** CMGFAM C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: cmgfam.cpp */
+/* ------------- */
+/* Version 1.5 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 20017 - 2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the MongoDB access method classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* filamtxt.h is header containing the file AM classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "reldef.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#if defined(BSON_SUPPORT)
+#include "tabbson.h"
+#else
+#include "tabjson.h"
+#endif // BSON_SUPPORT
+#include "cmgfam.h"
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#include "osutil.h"
+#endif
+
+/* --------------------------- Class CMGFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+CMGFAM::CMGFAM(PJDEF tdp) : DOSFAM((PDOSDEF)NULL)
+{
+ Cmgp = NULL;
+ Pcg.Tdbp = NULL;
+
+ if (tdp) {
+ Pcg.Uristr = tdp->Uri;
+ Pcg.Db_name = tdp->Schema;
+ Pcg.Coll_name = tdp->Collname;
+ Pcg.Options = tdp->Options;
+ Pcg.Filter = tdp->Filter;
+ Pcg.Line = NULL;
+ Pcg.Pipe = tdp->Pipe && tdp->Options != NULL;
+ Lrecl = tdp->Lrecl + tdp->Ending;
+ } else {
+ Pcg.Uristr = NULL;
+ Pcg.Db_name = NULL;
+ Pcg.Coll_name = NULL;
+ Pcg.Options = NULL;
+ Pcg.Filter = NULL;
+ Pcg.Line = NULL;
+ Pcg.Pipe = false;
+ Lrecl = 0;
+ } // endif tdp
+
+ To_Fbt = NULL;
+ Mode = MODE_ANY;
+ Done = false;
+} // end of CMGFAM standard constructor
+
+#if defined(BSON_SUPPORT)
+ /***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+CMGFAM::CMGFAM(PBDEF tdp) : DOSFAM((PDOSDEF)NULL)
+{
+ Cmgp = NULL;
+ Pcg.Tdbp = NULL;
+
+ if (tdp) {
+ Pcg.Uristr = tdp->Uri;
+ Pcg.Db_name = tdp->Schema;
+ Pcg.Coll_name = tdp->Collname;
+ Pcg.Options = tdp->Options;
+ Pcg.Filter = tdp->Filter;
+ Pcg.Line = NULL;
+ Pcg.Pipe = tdp->Pipe && tdp->Options != NULL;
+ Lrecl = tdp->Lrecl + tdp->Ending;
+ } else {
+ Pcg.Uristr = NULL;
+ Pcg.Db_name = NULL;
+ Pcg.Coll_name = NULL;
+ Pcg.Options = NULL;
+ Pcg.Filter = NULL;
+ Pcg.Line = NULL;
+ Pcg.Pipe = false;
+ Lrecl = 0;
+ } // endif tdp
+
+ To_Fbt = NULL;
+ Mode = MODE_ANY;
+ Done = false;
+} // end of CMGFAM standard constructor
+#endif // BSON_SUPPORT
+
+CMGFAM::CMGFAM(PCMGFAM tdfp) : DOSFAM(tdfp)
+{
+ Cmgp = tdfp->Cmgp;
+ Pcg = tdfp->Pcg;
+ To_Fbt = tdfp->To_Fbt;
+ Mode = tdfp->Mode;
+ Done = tdfp->Done;
+} // end of CMGFAM copy constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void CMGFAM::Reset(void)
+{
+ TXTFAM::Reset();
+ Fpos = Tpos = Spos = 0;
+} // end of Reset
+
+/***********************************************************************/
+/* MGO GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int CMGFAM::GetFileLength(PGLOBAL g)
+{
+ return 0;
+} // end of GetFileLength
+
+/***********************************************************************/
+/* Cardinality: returns the number of documents in the collection. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int CMGFAM::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 1;
+
+ return (!Init(g)) ? Cmgp->CollSize(g) : 0;
+} // end of Cardinality
+
+/***********************************************************************/
+/* Note: This function is not really implemented yet. */
+/***********************************************************************/
+int CMGFAM::MaxBlkSize(PGLOBAL, int s)
+{
+ return s;
+} // end of MaxBlkSize
+
+/***********************************************************************/
+/* Init: initialize MongoDB processing. */
+/***********************************************************************/
+bool CMGFAM::Init(PGLOBAL g)
+{
+ if (Done)
+ return false;
+
+ /*********************************************************************/
+ /* Open an C connection for this table. */
+ /*********************************************************************/
+ if (!Cmgp) {
+ Pcg.Tdbp = Tdbp;
+ Cmgp = new(g) CMgoConn(g, &Pcg);
+ } else if (Cmgp->IsConnected())
+ Cmgp->Close();
+
+ if (Cmgp->Connect(g))
+ return true;
+
+ Done = true;
+ return false;
+} // end of Init
+
+/***********************************************************************/
+/* OpenTableFile: Open a MongoDB table. */
+/***********************************************************************/
+bool CMGFAM::OpenTableFile(PGLOBAL g)
+{
+ Mode = Tdbp->GetMode();
+
+ if (Pcg.Pipe && Mode != MODE_READ) {
+ strcpy(g->Message, "Pipeline tables are read only");
+ return true;
+ } // endif Pipe
+
+ if (Init(g))
+ return true;
+
+ if (Mode == MODE_DELETE && !Tdbp->GetNext())
+ // Delete all documents
+ return Cmgp->DocDelete(g);
+ else if (Mode == MODE_INSERT)
+ Cmgp->MakeColumnGroups(g);
+
+ return false;
+} // end of OpenTableFile
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int CMGFAM::GetRowID(void)
+{
+ return Rows;
+} // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int CMGFAM::GetPos(void)
+{
+ return Fpos;
+} // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: return the position of next record. */
+/***********************************************************************/
+int CMGFAM::GetNextPos(void)
+{
+ return Fpos; // TODO
+} // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool CMGFAM::SetPos(PGLOBAL g, int pos)
+{
+ Fpos = pos;
+ Placed = true;
+ return false;
+} // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/***********************************************************************/
+bool CMGFAM::RecordPos(PGLOBAL g)
+{
+ strcpy(g->Message, "CMGFAM::RecordPos NIY");
+ return true;
+} // end of RecordPos
+
+/***********************************************************************/
+/* Initialize Fpos and the current position for indexed DELETE. */
+/***********************************************************************/
+int CMGFAM::InitDelete(PGLOBAL g, int fpos, int spos)
+{
+ strcpy(g->Message, "CMGFAM::InitDelete NIY");
+ return RC_FX;
+} // end of InitDelete
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int CMGFAM::SkipRecord(PGLOBAL g, bool header)
+{
+ return RC_OK; // Dummy
+} // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Get next document from a collection. */
+/***********************************************************************/
+int CMGFAM::ReadBuffer(PGLOBAL g)
+{
+ int rc = Cmgp->ReadNext(g);
+
+ if (rc != RC_OK)
+ return rc;
+
+ strncpy(Tdbp->GetLine(), Cmgp->GetDocument(g), Lrecl);
+ return RC_OK;
+} // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for MGO access method. */
+/***********************************************************************/
+int CMGFAM::WriteBuffer(PGLOBAL g)
+{
+ Pcg.Line = Tdbp->GetLine();
+ return Cmgp->Write(g);
+} // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for MGO and BLK access methods. */
+/***********************************************************************/
+int CMGFAM::DeleteRecords(PGLOBAL g, int irc)
+{
+ return (irc == RC_OK) ? WriteBuffer(g) : RC_OK;
+} // end of DeleteRecords
+
+/***********************************************************************/
+/* Table file close routine for MGO access method. */
+/***********************************************************************/
+void CMGFAM::CloseTableFile(PGLOBAL g, bool)
+{
+ Cmgp->Close();
+ Done = false;
+} // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for MGO access method. */
+/***********************************************************************/
+void CMGFAM::Rewind(void)
+{
+ Cmgp->Rewind();
+} // end of Rewind
+
diff --git a/storage/connect/cmgfam.h b/storage/connect/cmgfam.h
new file mode 100644
index 00000000..9c5f91f0
--- /dev/null
+++ b/storage/connect/cmgfam.h
@@ -0,0 +1,68 @@
+/*************** CMGFam H Declares Source Code File (.H) ***************/
+/* Name: cmgfam.h Version 1.6 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2020 */
+/* */
+/* This file contains the MongoDB access method classes declares. */
+/***********************************************************************/
+#include "cmgoconn.h"
+
+typedef class TXTFAM *PTXF;
+typedef class CMGFAM *PCMGFAM;
+typedef class MGODEF *PMGODEF;
+typedef class TDBCMG *PTDBCMG;
+
+/***********************************************************************/
+/* This is the MongoDB Access Method class declaration. */
+/***********************************************************************/
+class DllExport CMGFAM : public DOSFAM {
+ friend void mongo_init(bool);
+public:
+ // Constructor
+ CMGFAM(PJDEF tdp);
+#if defined(BSON_SUPPORT)
+ CMGFAM(PBDEF tdp);
+#endif // BSON_SUPPORT
+ CMGFAM(PCMGFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) { return TYPE_AM_MGO; }
+ virtual bool GetUseTemp(void) { return false; }
+ virtual int GetPos(void);
+ virtual int GetNextPos(void);
+ void SetTdbp(PTDBDOS tdbp) { Tdbp = tdbp; }
+ virtual PTXF Duplicate(PGLOBAL g) { return (PTXF)new(g) CMGFAM(this); }
+ void SetLrecl(int lrecl) { Lrecl = lrecl; }
+
+ // Methods
+ virtual void Reset(void);
+ virtual int GetFileLength(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int MaxBlkSize(PGLOBAL g, int s);
+ virtual bool AllocateBuffer(PGLOBAL g) { return false; }
+ virtual int GetRowID(void);
+ virtual bool RecordPos(PGLOBAL g);
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int SkipRecord(PGLOBAL g, bool header);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+protected:
+ virtual bool OpenTempFile(PGLOBAL g) { return false; }
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b) { return false; }
+ virtual int RenameTempFile(PGLOBAL g) { return RC_OK; }
+ virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+ bool Init(PGLOBAL g);
+
+ // Members
+ CMgoConn *Cmgp; // Points to a C Mongo connection class
+ CMGOPARM Pcg; // Parms passed to Cmgp
+ PFBLOCK To_Fbt; // Pointer to temp file block
+ MODE Mode;
+ bool Done; // Init done
+}; // end of class CMGFAM
+
diff --git a/storage/connect/cmgoconn.cpp b/storage/connect/cmgoconn.cpp
new file mode 100644
index 00000000..f3fc30fa
--- /dev/null
+++ b/storage/connect/cmgoconn.cpp
@@ -0,0 +1,1120 @@
+/************ CMgoConn C++ Functions Source Code File (.CPP) ***********/
+/* Name: CMgoConn.CPP Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
+/* */
+/* This file contains the MongoDB C connection classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Required objects includes. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "colblk.h"
+#include "xobject.h"
+#include "xtable.h"
+#include "filter.h"
+#include "cmgoconn.h"
+
+bool CMgoConn::IsInit = false;
+
+bool IsArray(PSZ s);
+bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s);
+int GetDefaultPrec(void);
+
+/* --------------------------- Class INCOL --------------------------- */
+
+/***********************************************************************/
+/* Add a column in the column list. */
+/***********************************************************************/
+void INCOL::AddCol(PGLOBAL g, PCOL colp, char *jp)
+{
+ char *p;
+ PKC kp, kcp;
+
+ if ((p = strchr(jp, '.'))) {
+ PINCOL icp;
+
+ *p++ = 0;
+
+ for (kp = Klist; kp; kp = kp->Next)
+ if (kp->Incolp && !strcmp(jp, kp->Key))
+ break;
+
+ if (!kp) {
+ icp = new(g) INCOL();
+ kcp = (PKC)PlugSubAlloc(g, NULL, sizeof(KEYCOL));
+ kcp->Next = NULL;
+ kcp->Incolp = icp;
+ kcp->Colp = NULL;
+ kcp->Key = PlugDup(g, jp);
+ kcp->Array = IsArray(p);
+
+ if (Klist) {
+ for (kp = Klist; kp->Next; kp = kp->Next);
+
+ kp->Next = kcp;
+ } else
+ Klist = kcp;
+
+ } else
+ icp = kp->Incolp;
+
+ *(p - 1) = '.';
+ icp->AddCol(g, colp, p);
+ } else {
+ kcp = (PKC)PlugSubAlloc(g, NULL, sizeof(KEYCOL));
+
+ kcp->Next = NULL;
+ kcp->Incolp = NULL;
+ kcp->Colp = colp;
+ kcp->Key = jp;
+ kcp->Array = IsArray(jp);
+
+ if (Klist) {
+ for (kp = Klist; kp->Next; kp = kp->Next);
+
+ kp->Next = kcp;
+ } else
+ Klist = kcp;
+
+ } // endif jp
+
+} // end of AddCol
+
+/***********************************************************************/
+/* Clear. */
+/***********************************************************************/
+void INCOL::Init(void)
+{
+ bson_init(Child);
+
+ for (PKC kp = Klist; kp; kp = kp->Next)
+ if (kp->Incolp)
+ kp->Incolp->Init();
+
+} // end of init
+
+/***********************************************************************/
+/* Destroy. */
+/***********************************************************************/
+void INCOL::Destroy(void)
+{
+ bson_destroy(Child);
+
+ for (PKC kp = Klist; kp; kp = kp->Next)
+ if (kp->Incolp)
+ kp->Incolp->Destroy();
+
+} // end of Destroy
+
+/* -------------------------- Class CMgoConn ------------------------- */
+
+/***********************************************************************/
+/* Implementation of the CMgoConn class. */
+/***********************************************************************/
+CMgoConn::CMgoConn(PGLOBAL g, PCPARM pcg)
+{
+ Pcg = pcg;
+ Uri = NULL;
+//Pool = NULL;
+ Client = NULL;
+ Database = NULL;
+ Collection = NULL;
+ Cursor = NULL;
+ Document = NULL;
+ Query = NULL;
+ Opts = NULL;
+ Fpc = NULL;
+ fp = NULL;
+ m_Connected = false;
+} // end of CMgoConn standard constructor
+
+/***********************************************************************/
+/* Required to initialize libmongoc's internals. */
+/***********************************************************************/
+void CMgoConn::mongo_init(bool init)
+{
+ if (init)
+ mongoc_init();
+ else if (IsInit)
+ mongoc_cleanup();
+
+ IsInit = init;
+} // end of mongo_init
+
+/***********************************************************************/
+/* Connect to the MongoDB server and get the collection. */
+/***********************************************************************/
+bool CMgoConn::Connect(PGLOBAL g)
+{
+ if (!Pcg->Db_name || !Pcg->Coll_name) {
+ // This would crash in mongoc_client_get_collection
+ strcpy(g->Message, "Missing DB or collection name");
+ return true;
+ } // endif name
+
+ if (!IsInit)
+#if defined(_WIN32)
+ __try {
+ mongo_init(true);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ strcpy(g->Message, "Cannot load MongoDB C driver");
+ return true;
+ } // end try/except
+#else // !_WIN32
+ mongo_init(true);
+#endif // !_WIN32
+
+ Uri = mongoc_uri_new_with_error(Pcg->Uristr, &Error);
+
+ if (!Uri) {
+ sprintf(g->Message, "Failed to parse URI: \"%s\" Msg: %s",
+ Pcg->Uristr, Error.message);
+ return true;
+ } // endif Uri
+
+#if 0
+ // Create a new client pool instance
+ Pool = mongoc_client_pool_new(Uri);
+ mongoc_client_pool_set_error_api(Pool, 2);
+
+ // Register the application name so we can track it in the profile logs
+ // on the server. This can also be done from the URI.
+ mongoc_client_pool_set_appname(Pool, "Connect");
+
+ // Create a new client instance
+ Client = mongoc_client_pool_pop(Pool);
+#else
+ // Create a new client instance
+ Client = mongoc_client_new_from_uri (Uri);
+
+ if (!Client) {
+ sprintf(g->Message, "Failed to get Client");
+ return true;
+ } // endif Client
+
+ // Register the application name so we can track it in the profile logs
+ // on the server. This can also be done from the URI (see other examples).
+ mongoc_client_set_appname (Client, "Connect");
+
+ // Get a handle on the database
+ // Database = mongoc_client_get_database (Client, Pcg->Db_name);
+#endif // 0
+
+ // Get a handle on the collection
+ Collection = mongoc_client_get_collection(Client, Pcg->Db_name, Pcg->Coll_name);
+
+ if (!Collection) {
+ sprintf(g->Message, "Failed to get Collection %s.%s",
+ Pcg->Db_name, Pcg->Coll_name);
+ return true;
+ } // endif Collection
+
+ /*********************************************************************/
+ /* Link a Fblock. This make possible to automatically close it */
+ /* in case of error (throw). */
+ /*********************************************************************/
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ fp->Type = TYPE_FB_MONGO;
+ fp->Fname = NULL;
+ fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = fp;
+ fp->Count = 1;
+ fp->Length = 0;
+ fp->Memory = NULL;
+ fp->Mode = MODE_ANY;
+ fp->File = this;
+ fp->Handle = 0;
+
+ m_Connected = true;
+ return false;
+} // end of Connect
+
+/***********************************************************************/
+/* CollSize: returns the number of documents in the collection. */
+/***********************************************************************/
+int CMgoConn::CollSize(PGLOBAL g)
+{
+ int cnt;
+ bson_t* query;
+ const char* jf = NULL;
+
+ if (Pcg->Pipe)
+ return 10;
+ else if (Pcg->Filter)
+ jf = Pcg->Filter;
+
+ if (jf) {
+ query = bson_new_from_json((const uint8_t*)jf, -1, &Error);
+
+ if (!query) {
+ htrc("Wrong filter: %s", Error.message);
+ return 10;
+ } // endif Query
+
+ } else
+ query = bson_new();
+
+#if defined(DEVELOPMENT)
+ if (jf)
+ cnt = (int)mongoc_collection_count_documents(Collection,
+ query, NULL, NULL, NULL, &Error);
+ else
+ cnt = (int)mongoc_collection_estimated_document_count(
+ Collection, NULL, NULL, NULL, &Error);
+#else
+ cnt = (int)mongoc_collection_count(Collection,
+ MONGOC_QUERY_NONE, query, 0, 0, NULL, &Error);
+#endif
+
+ if (cnt < 0) {
+ htrc("Collection count: %s", Error.message);
+ cnt = 2;
+ } // endif Cardinal
+
+ bson_destroy(query);
+ return cnt;
+} // end of CollSize
+
+/***********************************************************************/
+/* Project: make the projection avoid path collision. */
+/***********************************************************************/
+void CMgoConn::Project(PGLOBAL g, PSTRG s)
+{
+ bool m, b = false;
+ size_t n;
+ PSZ path;
+ PCOL cp;
+ PTDB tp = Pcg->Tdbp;
+ PTHP hp, php = NULL, * nphp = &php;
+
+ for (cp = tp->GetColumns(); cp; cp = cp->GetNext()) {
+ path = cp->GetJpath(g, true);
+
+ // Resolve path collision
+ for (hp = php; hp; hp = hp->Next) {
+ if (strlen(path) < strlen(hp->Path)) {
+ n = strlen(path);
+ m = true;
+ } else {
+ n = strlen(hp->Path);
+ m = false;
+ } // endif path
+
+ if (!strncmp(path, hp->Path, n))
+ break;
+
+ } // endfor hp
+
+ if (!hp) {
+ // New path
+ hp = (PTHP)PlugSubAlloc(g, NULL, sizeof(PTH));
+ hp->Path = path;
+ hp->Name = cp->GetName();
+ hp->Next = NULL;
+ *nphp = hp;
+ nphp = &hp->Next;
+ } else if (m) // Smaller path must replace longer one
+ hp->Path = path;
+
+ } // endfor cp
+
+ for (hp = php; hp; hp = hp->Next) {
+ if (b)
+ s->Append(",\"");
+ else
+ b = true;
+
+ if (*hp->Path == '{') {
+ // This is a Mongo defined column
+ s->Append(hp->Name);
+ s->Append("\":");
+ s->Append(hp->Path);
+ } else {
+ s->Append(hp->Path);
+ s->Append("\":1");
+ } // endif Path
+
+ } // endfor hp
+
+} // end of Project
+
+/***********************************************************************/
+/* MakeCursor: make the cursor used to retrieve documents. */
+/***********************************************************************/
+bool CMgoConn::MakeCursor(PGLOBAL g)
+{
+ const char *p;
+ bool id, all = false;
+ PCSZ options = Pcg->Options;
+ PTDB tp = Pcg->Tdbp;
+ PCOL cp;
+ PSTRG s = NULL;
+ PFIL filp = tp->GetFilter();
+
+ id = (tp->GetMode() == MODE_UPDATE || tp->GetMode() == MODE_DELETE);
+
+ if (options && !stricmp(options, "all")) {
+ options = NULL;
+ all = true;
+ } else for (cp = tp->GetColumns(); cp && !all; cp = cp->GetNext())
+ if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && !options)
+ all = true;
+ else if (!id)
+ id = !strcmp(cp->GetFmt() ? cp->GetFmt() : cp->GetName(), "_id");
+
+ if (Pcg->Pipe) {
+ if (trace(1))
+ htrc("Pipeline: %s\n", options);
+
+ p = strrchr(options, ']');
+
+ if (!p) {
+ strcpy(g->Message, "Missing ] in pipeline");
+ return true;
+ } else
+ *(char*)p = 0;
+
+ s = new(g) STRING(g, 1023, (PSZ)options);
+
+ if (filp) {
+ s->Append(",{\"$match\":");
+
+ if (MakeSelector(g, filp, s)) {
+ strcpy(g->Message, "Failed making selector");
+ return true;
+ } else
+ s->Append('}');
+
+ tp->SetFilter(NULL); // Not needed anymore
+ } // endif To_Filter
+
+ if (tp->GetColumns() && !strstr(s->GetStr(), "$project")) {
+ // Project list
+ s->Append(",{\"$project\":{\"");
+
+ if (!id)
+ s->Append("_id\":0,\"");
+
+ Project(g, s);
+ s->Append("}}");
+ } // endif all
+
+ s->Append("]}");
+ s->Resize(s->GetLength() + 1);
+ *(char*)p = ']'; // Restore Colist for discovery
+ p = s->GetStr();
+
+ if (trace(33))
+ htrc("New Pipeline: %s\n", p);
+
+ Query = bson_new_from_json((const uint8_t *)p, -1, &Error);
+
+ if (!Query) {
+ sprintf(g->Message, "Wrong pipeline: %s", Error.message);
+ return true;
+ } // endif Query
+
+ Cursor = mongoc_collection_aggregate(Collection, MONGOC_QUERY_NONE,
+ Query, NULL, NULL);
+
+ if (mongoc_cursor_error(Cursor, &Error)) {
+ sprintf(g->Message, "Mongo aggregate Failure: %s", Error.message);
+ return true;
+ } // endif error
+
+ } else {
+ if (Pcg->Filter || filp) {
+ if (trace(1)) {
+ if (Pcg->Filter)
+ htrc("Filter: %s\n", Pcg->Filter);
+
+ if (filp) {
+ char buf[512];
+
+ filp->Prints(g, buf, 511);
+ htrc("To_Filter: %s\n", buf);
+ } // endif To_Filter
+
+ } // endif trace
+
+ s = new(g) STRING(g, 1023, (PSZ)Pcg->Filter);
+
+ if (filp) {
+ if (Pcg->Filter)
+ s->Append(',');
+
+ if (MakeSelector(g, filp, s)) {
+ strcpy(g->Message, "Failed making selector");
+ return true;
+ } // endif Selector
+
+ tp->SetFilter(NULL); // Not needed anymore
+ } // endif To_Filter
+
+ if (trace(33))
+ htrc("selector: %s\n", s->GetStr());
+
+ s->Resize(s->GetLength() + 1);
+ Query = bson_new_from_json((const uint8_t *)s->GetStr(), -1, &Error);
+
+ if (!Query) {
+ sprintf(g->Message, "Wrong filter: %s", Error.message);
+ return true;
+ } // endif Query
+
+ } else
+ Query = bson_new();
+
+ if (!all) {
+ if (options && *options) {
+ if (trace(1))
+ htrc("options=%s\n", options);
+
+ p = options;
+ } else if (tp->GetColumns()) {
+ // Projection list
+ if (s)
+ s->Set("{\"projection\":{\"");
+ else
+ s = new(g) STRING(g, 511, "{\"projection\":{\"");
+
+ if (!id)
+ s->Append("_id\":0,\"");
+
+ Project(g, s);
+ s->Append("}}");
+ s->Resize(s->GetLength() + 1);
+ p = s->GetStr();
+ } else {
+ // count(*) ?
+ p = "{\"projection\":{\"_id\":1}}";
+ } // endif Options
+
+ Opts = bson_new_from_json((const uint8_t *)p, -1, &Error);
+
+ if (!Opts) {
+ sprintf(g->Message, "Wrong options: %s", Error.message);
+ return true;
+ } // endif Opts
+
+ } // endif all
+
+ Cursor = mongoc_collection_find_with_opts(Collection, Query, Opts, NULL);
+ } // endif Pipe
+
+ return false;
+} // end of MakeCursor
+
+/***********************************************************************/
+/* Fetch next document. */
+/***********************************************************************/
+int CMgoConn::ReadNext(PGLOBAL g)
+{
+ int rc = RC_OK;
+
+ if (!Cursor && MakeCursor(g)) {
+ rc = RC_FX;
+ } else if (mongoc_cursor_next(Cursor, &Document)) {
+ if (trace(512)) {
+ bson_iter_t iter;
+ ShowDocument(&iter, Document, "");
+ } else if (trace(1))
+ htrc("%s\n", GetDocument(g));
+
+ } else if (mongoc_cursor_error(Cursor, &Error)) {
+ sprintf(g->Message, "Mongo Cursor Failure: %s", Error.message);
+ rc = RC_FX;
+ } else
+ rc = RC_EF;
+
+ return rc;
+} // end of Fetch
+
+/***********************************************************************/
+/* Get the Json string of the current document. */
+/***********************************************************************/
+PSZ CMgoConn::GetDocument(PGLOBAL g)
+{
+ char *str = bson_as_json(Document, NULL);
+ PSZ doc = PlugDup(g, str);
+
+ bson_free(str);
+ return doc;
+} // end of GetDocument
+
+/***********************************************************************/
+/* Use to trace restaurants document contains. */
+/***********************************************************************/
+void CMgoConn::ShowDocument(bson_iter_t *iter, const bson_t *doc, const char *k)
+{
+ if (!doc || bson_iter_init(iter, doc)) {
+ const char *key;
+
+ while (bson_iter_next(iter)) {
+ key = bson_iter_key(iter);
+ htrc("Found element key: \"%s\"\n", key);
+
+ switch (bson_iter_type(iter)) {
+ case BSON_TYPE_UTF8:
+ htrc("%s.%s=\"%s\"\n", k, key, bson_iter_utf8(iter, NULL));
+ break;
+ case BSON_TYPE_INT32:
+ htrc("%s.%s=%d\n", k, key, bson_iter_int32(iter));
+ break;
+ case BSON_TYPE_INT64:
+ htrc("%s.%s=%lld\n", k, key, bson_iter_int64(iter));
+ break;
+ case BSON_TYPE_DOUBLE:
+ htrc("%s.%s=%g\n", k, key, bson_iter_double(iter));
+ break;
+ case BSON_TYPE_DATE_TIME:
+ htrc("%s.%s=date(%lld)\n", k, key, bson_iter_date_time(iter));
+ break;
+ case BSON_TYPE_OID: {
+ char str[25];
+
+ bson_oid_to_string(bson_iter_oid(iter), str);
+ htrc("%s.%s=%s\n", k, key, str);
+ } break;
+ case BSON_TYPE_DECIMAL128: {
+ char str[BSON_DECIMAL128_STRING];
+ bson_decimal128_t dec;
+
+ bson_iter_decimal128(iter, &dec);
+ bson_decimal128_to_string(&dec, str);
+ htrc("%s.%s=%s\n", k, key, str);
+ } break;
+ case BSON_TYPE_DOCUMENT: {
+ bson_iter_t child;
+
+ if (bson_iter_recurse(iter, &child))
+ ShowDocument(&child, NULL, key);
+
+ } break;
+ case BSON_TYPE_ARRAY: {
+ bson_t* arr;
+ bson_iter_t itar;
+ const uint8_t* data = NULL;
+ uint32_t len = 0;
+
+ bson_iter_array(iter, &len, &data);
+ arr = bson_new_from_data(data, len);
+ ShowDocument(&itar, arr, key);
+ } break;
+ } // endswitch iter
+
+ } // endwhile bson_iter_next
+
+ } // endif bson_iter_init
+
+} // end of ShowDocument
+
+/***********************************************************************/
+/* Group columns for inserting or updating. */
+/***********************************************************************/
+void CMgoConn::MakeColumnGroups(PGLOBAL g)
+{
+ Fpc = new(g) INCOL();
+
+ for (PCOL colp = Pcg->Tdbp->GetColumns(); colp; colp = colp->GetNext())
+ if (!colp->IsSpecial())
+ Fpc->AddCol(g, colp, colp->GetJpath(g, false));
+
+} // end of MakeColumnGroups
+
+/***********************************************************************/
+/* DocWrite. */
+/***********************************************************************/
+bool CMgoConn::DocWrite(PGLOBAL g, PINCOL icp)
+{
+ for (PKC kp = icp->Klist; kp; kp = kp->Next)
+ if (kp->Incolp) {
+ bool isdoc = !kp->Array;
+
+ if (isdoc)
+ BSON_APPEND_DOCUMENT_BEGIN(icp->Child, kp->Key, kp->Incolp->Child);
+ else
+ BSON_APPEND_ARRAY_BEGIN(icp->Child, kp->Key, kp->Incolp->Child);
+
+ if (DocWrite(g, kp->Incolp))
+ return true;
+
+ if (isdoc)
+ bson_append_document_end(icp->Child, kp->Incolp->Child);
+ else
+ bson_append_array_end(icp->Child, kp->Incolp->Child);
+
+ } else if (AddValue(g, kp->Colp, icp->Child, kp->Key, false))
+ return true;
+
+ return false;
+} // end of DocWrite
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for CMGO access method. */
+/***********************************************************************/
+int CMgoConn::Write(PGLOBAL g)
+{
+ int rc = RC_OK;
+ PTDB tp = Pcg->Tdbp;
+
+ if (tp->GetMode() == MODE_INSERT) {
+ if (!Pcg->Line) {
+ Fpc->Init();
+
+ if (DocWrite(g, Fpc))
+ return RC_FX;
+
+ if (trace(2)) {
+ char* str = bson_as_json(Fpc->Child, NULL);
+ htrc("Inserting: %s\n", str);
+ bson_free(str);
+ } // endif trace
+
+ if (!mongoc_collection_insert(Collection, MONGOC_INSERT_NONE,
+ Fpc->Child, NULL, &Error)) {
+ sprintf(g->Message, "Mongo insert: %s", Error.message);
+ rc = RC_FX;
+ } // endif insert
+
+ } else {
+ const uint8_t* val = (const uint8_t*)Pcg->Line;
+ bson_t* doc = bson_new_from_json(val, -1, &Error);
+
+ if (doc && trace(2)) {
+ char* str = bson_as_json(doc, NULL);
+ htrc("Inserting: %s\n", str);
+ bson_free(str);
+ } // endif trace
+
+ if (!doc) {
+ sprintf(g->Message, "bson_new_from_json: %s", Error.message);
+ rc = RC_FX;
+ } else if (!mongoc_collection_insert(Collection,
+ MONGOC_INSERT_NONE, doc, NULL, &Error)) {
+ sprintf(g->Message, "Mongo insert: %s", Error.message);
+ bson_destroy(doc);
+ rc = RC_FX;
+ } // endif insert
+
+ } // endif Line
+
+ } else {
+ bool b = false;
+ bson_iter_t iter;
+ bson_t *query = bson_new();
+
+ bson_iter_init(&iter, Document);
+
+ if (bson_iter_find(&iter, "_id"))
+ switch (bson_iter_type(&iter)) {
+ case BSON_TYPE_OID:
+ b = BSON_APPEND_OID(query, "_id", bson_iter_oid(&iter));
+ break;
+ case BSON_TYPE_UTF8:
+ b = BSON_APPEND_UTF8(query, "_id", bson_iter_utf8(&iter, NULL));
+ break;
+ case BSON_TYPE_INT32:
+ b = BSON_APPEND_INT32(query, "_id", bson_iter_int32(&iter));
+ break;
+ case BSON_TYPE_INT64:
+ b = BSON_APPEND_INT64(query, "_id", bson_iter_int64(&iter));
+ break;
+ case BSON_TYPE_DOUBLE:
+ b = BSON_APPEND_DOUBLE(query, "_id", bson_iter_double(&iter));
+ break;
+ default:
+ break;
+ } // endswitch iter
+
+ if (b) {
+ if (trace(2)) {
+ char *str = bson_as_json(query, NULL);
+ htrc("update query: %s\n", str);
+ bson_free(str);
+ } // endif trace
+
+ if (tp->GetMode() == MODE_UPDATE) {
+ bson_t child;
+ bson_t *update = bson_new();
+
+ BSON_APPEND_DOCUMENT_BEGIN(update, "$set", &child);
+
+ for (PCOL colp = tp->GetSetCols(); colp; colp = colp->GetNext())
+ if (AddValue(g, colp, &child, colp->GetJpath(g, false), true))
+ rc = RC_FX;
+
+ bson_append_document_end(update, &child);
+
+ if (rc == RC_OK)
+ if (!mongoc_collection_update(Collection, MONGOC_UPDATE_NONE,
+ query, update, NULL, &Error)) {
+ sprintf(g->Message, "Mongo update: %s", Error.message);
+ rc = RC_FX;
+ } // endif update
+
+ bson_destroy(update);
+ } else if (!mongoc_collection_remove(Collection,
+ MONGOC_REMOVE_SINGLE_REMOVE, query, NULL, &Error)) {
+ sprintf(g->Message, "Mongo delete: %s", Error.message);
+ rc = RC_FX;
+ } // endif remove
+
+ } else {
+ strcpy(g->Message, "Mongo update: cannot find _id");
+ rc = RC_FX;
+ } // endif b
+
+ bson_destroy(query);
+ } // endif Mode
+
+ return rc;
+} // end of Write
+
+/***********************************************************************/
+/* Remove all documents from the collection. */
+/***********************************************************************/
+bool CMgoConn::DocDelete(PGLOBAL g)
+{
+ Query = bson_new();
+
+ if (!mongoc_collection_remove(Collection, MONGOC_REMOVE_NONE,
+ Query, NULL, &Error)) {
+ sprintf(g->Message, "Mongo remove all: %s", Error.message);
+ return true;
+ } // endif remove
+
+ return false;
+} // end of DocDelete
+
+/***********************************************************************/
+/* Rewind the collection. */
+/***********************************************************************/
+void CMgoConn::Rewind(void)
+{
+ mongoc_cursor_t *cursor = mongoc_cursor_clone(Cursor);
+
+ mongoc_cursor_destroy(Cursor);
+ Cursor = cursor;
+} // end of Rewind
+
+/***********************************************************************/
+/* Table close routine for MONGO tables. */
+/***********************************************************************/
+void CMgoConn::Close(void)
+{
+ if (Query) bson_destroy(Query);
+ if (Opts) bson_destroy(Opts);
+ if (Cursor) mongoc_cursor_destroy(Cursor);
+ if (Collection) mongoc_collection_destroy(Collection);
+//if (Client) mongoc_client_pool_push(Pool, Client);
+//if (Pool) mongoc_client_pool_destroy(Pool);
+ if (Client) mongoc_client_destroy(Client);
+ if (Uri) mongoc_uri_destroy(Uri);
+ if (Fpc) Fpc->Destroy();
+ if (fp) fp->Count = 0;
+} // end of Close
+
+/***********************************************************************/
+/* Mini: used to suppress blanks to json strings. */
+/***********************************************************************/
+char *CMgoConn::Mini(PGLOBAL g, PCOL colp, const bson_t *bson, bool b)
+{
+ char *s, *str = NULL;
+ char *Mbuf = (char*)PlugSubAlloc(g, NULL, (size_t)colp->GetLength() + 1);
+ int i, j = 0, k = 0, n = 0, m = GetDefaultPrec();
+ bool ok = true, dbl = false;
+ double d;
+ size_t len;
+
+ if (b)
+ s = str = bson_array_as_json(bson, &len);
+ else
+ s = str = bson_as_json(bson, &len);
+
+ if (len > (size_t)colp->GetLength()) {
+ sprintf(g->Message, "Value too long for column %s", colp->GetName());
+ bson_free(str);
+ throw (int)TYPE_AM_MGO;
+ } // endif len
+
+ for (i = 0; i < colp->GetLength() && s[i]; i++) {
+ switch (s[i]) {
+ case ' ':
+ if (ok) continue;
+ break;
+ case '"':
+ ok = !ok;
+ break;
+ case '.':
+ if (j) dbl = true;
+ break;
+ default:
+ if (ok) {
+ if (isdigit(s[i])) {
+ if (!j) j = k;
+ if (dbl) n++;
+ } else if (dbl && n > m) {
+ Mbuf[k] = 0;
+ d = atof(Mbuf + j);
+ n = sprintf(Mbuf + j, "%.*f", m, d);
+ k = j + n;
+ j = n = 0;
+ } else if (j)
+ j = n = 0;
+
+ } // endif ok
+
+ break;
+ } // endswitch s[i]
+
+ Mbuf[k++] = s[i];
+ } // endfor i
+
+ bson_free(str);
+
+ Mbuf[k] = 0;
+ return Mbuf;
+} // end of Mini
+
+/***********************************************************************/
+/* Retrieve the column value from the document. */
+/***********************************************************************/
+void CMgoConn::GetColumnValue(PGLOBAL g, PCOL colp)
+{
+ char *jpath = colp->GetJpath(g, false);
+ bool b = false;
+ PVAL value = colp->GetValue();
+ bson_iter_t Iter; // Used to retrieve column value
+ bson_iter_t Desc; // Descendant iter
+
+ if (*jpath == '{')
+ jpath = colp->GetName(); // This is a Mongo defined column
+
+ if (!*jpath || !strcmp(jpath, "*")) {
+ value->SetValue_psz(Mini(g, colp, Document, false));
+ } else if (bson_iter_init(&Iter, Document) &&
+ bson_iter_find_descendant(&Iter, jpath, &Desc)) {
+ switch (bson_iter_type(&Desc)) {
+ case BSON_TYPE_UTF8:
+ value->SetValue_psz((PSZ)bson_iter_utf8(&Desc, NULL));
+ break;
+ case BSON_TYPE_INT32:
+ value->SetValue(bson_iter_int32(&Desc));
+ break;
+ case BSON_TYPE_INT64:
+ value->SetValue(bson_iter_int64(&Desc));
+ break;
+ case BSON_TYPE_DOUBLE:
+ value->SetValue(bson_iter_double(&Desc));
+ break;
+ case BSON_TYPE_DATE_TIME:
+ value->SetValue(bson_iter_date_time(&Desc) / 1000);
+ break;
+ case BSON_TYPE_BOOL:
+ b = bson_iter_bool(&Desc);
+
+ if (value->IsTypeNum())
+ value->SetValue(b ? 1 : 0);
+ else
+ value->SetValue_psz(b ? "true" : "false");
+
+ break;
+ case BSON_TYPE_OID: {
+ char str[25];
+
+ bson_oid_to_string(bson_iter_oid(&Desc), str);
+ value->SetValue_psz(str);
+ } break;
+ case BSON_TYPE_ARRAY:
+ b = true;
+ // passthru
+ case BSON_TYPE_DOCUMENT:
+ { // All this because MongoDB can return the wrong type
+ int i = 0;
+ const uint8_t *data = NULL;
+ uint32_t len = 0;
+
+ for (; i < 2; i++) {
+ if (b) // Try array first
+ bson_iter_array(&Desc, &len, &data);
+ else
+ bson_iter_document(&Desc, &len, &data);
+
+ if (!data) {
+ len = 0;
+ b = !b;
+ } else
+ break;
+
+ } // endfor i
+
+ if (data) {
+ bson_t *doc = bson_new_from_data(data, len);
+
+ value->SetValue_psz(Mini(g, colp, doc, b));
+ bson_destroy(doc);
+ } else {
+ // ... or we can also come here in case of NULL!
+ value->Reset();
+ value->SetNull(true);
+ } // endif data
+
+ } break;
+ case BSON_TYPE_NULL:
+ // Apparently this does not work...
+ value->Reset();
+ value->SetNull(true);
+ break;
+ case BSON_TYPE_DECIMAL128: {
+ char str[BSON_DECIMAL128_STRING];
+ bson_decimal128_t dec;
+
+ bson_iter_decimal128(&Desc, &dec);
+ bson_decimal128_to_string(&dec, str);
+ value->SetValue_psz(str);
+// bson_free(str);
+ } break;
+ default:
+ value->Reset();
+ break;
+ } // endswitch Desc
+
+ } else {
+ // Field does not exist
+ value->Reset();
+ value->SetNull(true);
+ } // endif Iter
+
+} // end of GetColumnValue
+
+/***********************************************************************/
+/* AddValue: Add column value to the document to insert or update. */
+/***********************************************************************/
+bool CMgoConn::AddValue(PGLOBAL g, PCOL colp, bson_t *doc, char *key, bool upd)
+{
+ bool rc = false;
+ PVAL value = colp->GetValue();
+
+ if (value->IsNull()) {
+// if (upd)
+ rc = BSON_APPEND_NULL(doc, key);
+// else
+// return false;
+
+ } else switch (colp->GetResultType()) {
+ case TYPE_STRING:
+ if (colp->Stringify()) {
+ const uint8_t *val = (const uint8_t*)value->GetCharValue();
+ bson_t *bsn = bson_new_from_json(val, -1, &Error);
+
+ if (!bsn) {
+ sprintf (g->Message, "AddValue: %s", Error.message);
+ return true;
+ } else if (*key) {
+ if (*val == '[')
+ rc = BSON_APPEND_ARRAY(doc, key, bsn);
+ else
+ rc = BSON_APPEND_DOCUMENT(doc, key, bsn);
+
+ } else {
+ bson_copy_to (bsn, doc);
+ rc = true;
+ } // endif's
+
+ bson_free(bsn);
+ } else
+ rc = BSON_APPEND_UTF8(doc, key, value->GetCharValue());
+
+ break;
+ case TYPE_INT:
+ case TYPE_SHORT:
+ rc = BSON_APPEND_INT32(doc, key, value->GetIntValue());
+ break;
+ case TYPE_TINY:
+ rc = BSON_APPEND_BOOL(doc, key, value->GetIntValue());
+ break;
+ case TYPE_BIGINT:
+ rc = BSON_APPEND_INT64(doc, key, value->GetBigintValue());
+ break;
+ case TYPE_DOUBLE:
+ rc = BSON_APPEND_DOUBLE(doc, key, value->GetFloatValue());
+ break;
+ case TYPE_DECIM:
+ {bson_decimal128_t dec;
+
+ if (bson_decimal128_from_string(value->GetCharValue(), &dec))
+ rc = BSON_APPEND_DECIMAL128(doc, key, &dec);
+
+ } break;
+ case TYPE_DATE:
+ rc = BSON_APPEND_DATE_TIME(doc, key, value->GetBigintValue() * 1000);
+ break;
+ default:
+ sprintf(g->Message, "Type %d not supported yet", colp->GetResultType());
+ return true;
+ } // endswitch Buf_Type
+
+ if (!rc) {
+ strcpy(g->Message, "Adding value failed");
+ return true;
+ } else
+ return false;
+
+} // end of AddValue
+
+#if 0
+void *CMgoConn::mgo_alloc(size_t n)
+{
+ char *mst = (char*)PlgDBSubAlloc(G, NULL, n + sizeof(size_t));
+
+ if (mst) {
+ *(size_t*)mst = n;
+ return mst + sizeof(size_t);
+ } // endif mst
+
+ return NULL;
+} // end of mgo_alloc
+
+void *CMgoConn::mgo_calloc(size_t n, size_t sz)
+{
+ void *m = mgo_alloc(n * sz);
+
+ if (m)
+ memset(m, 0, n * sz);
+
+ return m;
+} // end of mgo_calloc
+
+void *CMgoConn::mgo_realloc(void *m, size_t n)
+{
+ if (!m)
+ return n ? mgo_alloc(n) : NULL;
+
+ size_t *osz = (size_t*)((char*)m - sizeof(size_t));
+
+ if (n > *osz) {
+ void *nwm = mgo_alloc(n);
+
+ if (nwm)
+ memcpy(nwm, m, *osz);
+
+ return nwm;
+ } else {
+ *osz = n;
+ return m;
+ } // endif n
+
+} // end of mgo_realloc
+#endif // 0
+
diff --git a/storage/connect/cmgoconn.h b/storage/connect/cmgoconn.h
new file mode 100644
index 00000000..f37a96cb
--- /dev/null
+++ b/storage/connect/cmgoconn.h
@@ -0,0 +1,121 @@
+/***********************************************************************/
+/* CMgoConn.h : header file for the MongoDB connection classes. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include MongoDB library header files. */
+/***********************************************************************/
+#include <bson.h>
+#include <bcon.h>
+#include <mongoc.h>
+
+// C connection to a MongoDB data source
+class TDBCMG;
+class MGOCOL;
+
+/***********************************************************************/
+/* Include MongoDB library header files. */
+/***********************************************************************/
+typedef class INCOL *PINCOL;
+typedef class MGODEF *PMGODEF;
+typedef class TDBCMG *PTDBCMG;
+typedef class MGOCOL *PMGOCOL;
+
+typedef struct mongo_parms {
+ PTDB Tdbp;
+ PCSZ Uristr; // Driver URI
+ PCSZ Db_name;
+ PCSZ Coll_name;
+ PCSZ Options;
+ PCSZ Filter;
+ PCSZ Line;
+ bool Pipe;
+} CMGOPARM, *PCPARM;
+
+typedef struct KEYCOL {
+ KEYCOL *Next;
+ PINCOL Incolp;
+ PCOL Colp;
+ char *Key;
+ bool Array;
+} *PKC;
+
+typedef struct _path_list *PTHP;
+
+typedef struct _path_list {
+ PSZ Path;
+ PSZ Name;
+ PTHP Next;
+} PTH;
+
+/***********************************************************************/
+/* Used when inserting values in a MongoDB collection. */
+/***********************************************************************/
+class INCOL : public BLOCK {
+public:
+ // Constructor
+ INCOL(void) { Child = bson_new(); Klist = NULL; }
+
+ // Methods
+ void AddCol(PGLOBAL g, PCOL colp, char *jp);
+ void Init(void);
+ void Destroy(void);
+
+ //Members
+ bson_t *Child;
+ PKC Klist;
+}; // end of INCOL;
+
+/***********************************************************************/
+/* CMgoConn class. */
+/***********************************************************************/
+class CMgoConn : public BLOCK {
+ friend class TDBCMG;
+ friend class CMGDISC;
+public:
+ // Constructor
+ CMgoConn(PGLOBAL g, PCPARM pcg);
+
+ //static void *mgo_alloc(size_t n);
+ //static void *mgo_calloc(size_t n, size_t sz);
+ //static void *mgo_realloc(void *m, size_t n);
+ //static void mgo_free(void *) {}
+
+ // Implementation
+ bool IsConnected(void) { return m_Connected; }
+ bool Connect(PGLOBAL g);
+ int CollSize(PGLOBAL g);
+ void CMgoConn::Project(PGLOBAL g, PSTRG s);
+ bool MakeCursor(PGLOBAL g);
+ int ReadNext(PGLOBAL g);
+ PSZ GetDocument(PGLOBAL g);
+ void ShowDocument(bson_iter_t *iter, const bson_t *doc, const char *k);
+ void MakeColumnGroups(PGLOBAL g);
+ bool DocWrite(PGLOBAL g, PINCOL icp);
+ int Write(PGLOBAL g);
+ bool DocDelete(PGLOBAL g);
+ void Rewind(void);
+ void Close(void);
+ PSZ Mini(PGLOBAL g, PCOL colp, const bson_t *bson, bool b);
+ void GetColumnValue(PGLOBAL g, PCOL colp);
+ bool AddValue(PGLOBAL g, PCOL colp, bson_t *doc, char *key, bool upd);
+ static void mongo_init(bool init);
+
+protected:
+ // Members
+ PCPARM Pcg;
+ mongoc_uri_t *Uri;
+//mongoc_client_pool_t *Pool; // Thread safe client pool
+ mongoc_client_t *Client; // The MongoDB client
+ mongoc_database_t *Database; // The MongoDB database
+ mongoc_collection_t *Collection; // The MongoDB collection
+ mongoc_cursor_t *Cursor;
+ const bson_t *Document;
+ bson_t *Query; // MongoDB cursor filter
+ bson_t *Opts; // MongoDB cursor options
+ bson_error_t Error;
+ PINCOL Fpc; // To insert INCOL classes
+ PFBLOCK fp;
+ bool m_Connected;
+ static bool IsInit;
+}; // end of class CMgoConn
diff --git a/storage/connect/colblk.cpp b/storage/connect/colblk.cpp
new file mode 100644
index 00000000..d5316859
--- /dev/null
+++ b/storage/connect/colblk.cpp
@@ -0,0 +1,414 @@
+/************* Colblk C++ Functions Source Code File (.CPP) ************/
+/* Name: COLBLK.CPP Version 2.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2017 */
+/* */
+/* This file contains the COLBLK class functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "tabcol.h"
+#include "colblk.h"
+#include "xindex.h"
+#include "xtable.h"
+
+/***********************************************************************/
+/* COLBLK protected constructor. */
+/***********************************************************************/
+COLBLK::COLBLK(PCOLDEF cdp, PTDB tdbp, int i)
+ {
+ Next = NULL;
+ Index = i;
+//Number = 0;
+ ColUse = 0;
+
+ if ((Cdp = cdp)) {
+ Name = cdp->Name;
+ Format = cdp->F;
+ Opt = cdp->Opt;
+ Long = cdp->Long;
+ Precision = cdp->Precision;
+ Freq = cdp->Freq;
+ Buf_Type = cdp->Buf_Type;
+ ColUse |= cdp->Flags; // Used by CONNECT
+ Nullable = !!(cdp->Flags & U_NULLS);
+ Unsigned = !!(cdp->Flags & U_UNSIGNED);
+ } else {
+ Name = NULL;
+ memset(&Format, 0, sizeof(FORMAT));
+ Opt = 0;
+ Long = 0;
+ Precision = 0;
+ Freq = 0;
+ Buf_Type = TYPE_ERROR;
+ Nullable = false;
+ Unsigned = false;
+ } // endif cdp
+
+ To_Tdb = tdbp;
+ Status = BUF_NO;
+//Value = NULL; done in XOBJECT constructor
+ To_Kcol = NULL;
+ } // end of COLBLK constructor
+
+/***********************************************************************/
+/* COLBLK constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+COLBLK::COLBLK(PCOL col1, PTDB tdbp)
+ {
+ PCOL colp;
+
+ // Copy the old column block to the new one
+ *this = *col1;
+ Next = NULL;
+//To_Orig = col1;
+ To_Tdb = tdbp;
+
+ if (trace(2))
+ htrc(" copying COLBLK %s from %p to %p\n", Name, col1, this);
+
+ if (tdbp) {
+ // Attach the new column to the table block
+ if (!tdbp->GetColumns()) {
+ tdbp->SetColumns(this);
+ } else {
+ for (colp = tdbp->GetColumns(); colp->Next; colp = colp->Next) ;
+ colp->Next = this;
+ } // endelse
+ }
+
+ } // end of COLBLK copy constructor
+
+/***********************************************************************/
+/* Reset the column descriptor to non evaluated yet. */
+/***********************************************************************/
+void COLBLK::Reset(void)
+ {
+ Status &= ~BUF_READ;
+ } // end of Reset
+
+/***********************************************************************/
+/* Compare: compares itself to an (expression) object and returns */
+/* true if it is equivalent. */
+/***********************************************************************/
+bool COLBLK::Compare(PXOB xp)
+ {
+ return (this == xp);
+ } // end of Compare
+
+/***********************************************************************/
+/* SetFormat: function used to set SELECT output format. */
+/***********************************************************************/
+bool COLBLK::SetFormat(PGLOBAL, FORMAT& fmt)
+ {
+ fmt = Format;
+
+ if (trace(2))
+ htrc("COLBLK: %p format=%c(%d,%d)\n",
+ this, *fmt.Type, fmt.Length, fmt.Prec);
+
+ return false;
+ } // end of SetFormat
+
+/***********************************************************************/
+/* Eval: get the column value from the last read record or from a */
+/* matching Index column if there is one. */
+/***********************************************************************/
+bool COLBLK::Eval(PGLOBAL g)
+ {
+ if (trace(2))
+ htrc("Col Eval: %s status=%.4X\n", Name, Status);
+
+ if (!GetStatus(BUF_READ)) {
+// if (To_Tdb->IsNull())
+// Value->Reset();
+ if (To_Kcol)
+ To_Kcol->FillValue(Value);
+ else
+ ReadColumn(g);
+
+ AddStatus(BUF_READ);
+ } // endif
+
+ return false;
+ } // end of Eval
+
+/***********************************************************************/
+/* InitValue: prepare a column block for read operation. */
+/* Now we use Format.Length for the len parameter to avoid strings */
+/* to be truncated when converting from string to coded string. */
+/* Added in version 1.5 is the arguments GetScale() and Domain */
+/* in calling AllocateValue. Domain is used for TYPE_DATE only. */
+/***********************************************************************/
+bool COLBLK::InitValue(PGLOBAL g)
+ {
+ if (Value)
+ return false; // Already done
+
+ // Allocate a Value object
+ if (!(Value = AllocateValue(g, Buf_Type, Precision,
+ GetScale(), Unsigned, GetDomain())))
+ return true;
+
+ AddStatus(BUF_READY);
+ Value->SetNullable(Nullable);
+
+ if (trace(2))
+ htrc(" colp=%p type=%d value=%p coluse=%.4X status=%.4X\n",
+ this, Buf_Type, Value, ColUse, Status);
+
+ return false;
+ } // end of InitValue
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool COLBLK::SetBuffer(PGLOBAL g, PVAL, bool, bool)
+ {
+ sprintf(g->Message, MSG(UNDEFINED_AM), "SetBuffer");
+ return true;
+ } // end of SetBuffer
+
+/***********************************************************************/
+/* GetLength: returns an evaluation of the column string length. */
+/***********************************************************************/
+int COLBLK::GetLengthEx(void)
+ {
+ return Long;
+ } // end of GetLengthEx
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the last line */
+/* read from the corresponding table, extract from it the field */
+/* corresponding to this column and convert it to buffer type. */
+/***********************************************************************/
+void COLBLK::ReadColumn(PGLOBAL g)
+{
+ sprintf(g->Message, MSG(UNDEFINED_AM), "ReadColumn");
+ throw (int)TYPE_COLBLK;
+} // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last line */
+/* read from the corresponding table, and rewrite the field */
+/* corresponding to this column from the column buffer and type. */
+/***********************************************************************/
+void COLBLK::WriteColumn(PGLOBAL g)
+{
+ sprintf(g->Message, MSG(UNDEFINED_AM), "WriteColumn");
+ throw (int)TYPE_COLBLK;
+} // end of WriteColumn
+
+/***********************************************************************/
+/* Make file output of a column descriptor block. */
+/***********************************************************************/
+void COLBLK::Printf(PGLOBAL, FILE *f, uint n)
+ {
+ char m[64];
+ int i;
+ PCOL colp;
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+
+ for (colp = To_Tdb->GetColumns(), i = 1; colp; colp = colp->Next, i++)
+ if (colp == this)
+ break;
+
+ fprintf(f, "%sR%dC%d type=%d F=%.2s(%d,%d)", m, To_Tdb->GetTdb_No(),
+ i, GetAmType(), Format.Type, Format.Length, Format.Prec);
+ fprintf(f,
+ " coluse=%04X status=%04X buftyp=%d value=%p name=%s\n",
+ ColUse, Status, Buf_Type, Value, Name);
+ } // end of Printf
+
+/***********************************************************************/
+/* Make string output of a column descriptor block. */
+/***********************************************************************/
+void COLBLK::Prints(PGLOBAL, char *ps, uint)
+ {
+ sprintf(ps, "R%d.%s", To_Tdb->GetTdb_No(), Name);
+ } // end of Prints
+
+
+/***********************************************************************/
+/* SPCBLK constructor. */
+/***********************************************************************/
+SPCBLK::SPCBLK(PCOLUMN cp)
+ : COLBLK((PCOLDEF)NULL, cp->GetTo_Table()->GetTo_Tdb(), 0)
+ {
+ Name = (char*)cp->GetName();
+ Precision = Long = 0;
+ Buf_Type = TYPE_ERROR;
+ } // end of SPCBLK constructor
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last line */
+/* read from the corresponding table, and rewrite the field */
+/* corresponding to this column from the column buffer and type. */
+/***********************************************************************/
+void SPCBLK::WriteColumn(PGLOBAL g)
+{
+ sprintf(g->Message, MSG(SPCOL_READONLY), Name);
+ throw (int)TYPE_COLBLK;
+} // end of WriteColumn
+
+/***********************************************************************/
+/* RIDBLK constructor for the ROWID special column. */
+/***********************************************************************/
+RIDBLK::RIDBLK(PCOLUMN cp, bool rnm) : SPCBLK(cp)
+ {
+ Precision = Long = 10;
+ Buf_Type = TYPE_INT;
+ Rnm = rnm;
+ *Format.Type = 'N';
+ Format.Length = 10;
+ } // end of RIDBLK constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to return the ordinal */
+/* number of the current row in the table (if Rnm is true) or in the */
+/* current file (if Rnm is false) the same except for multiple tables.*/
+/***********************************************************************/
+void RIDBLK::ReadColumn(PGLOBAL g)
+ {
+ Value->SetValue(To_Tdb->RowNumber(g, Rnm));
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* FIDBLK constructor for the FILEID special column. */
+/***********************************************************************/
+FIDBLK::FIDBLK(PCOLUMN cp, OPVAL op) : SPCBLK(cp), Op(op)
+ {
+//Is_Key = 2; for when the MUL table indexed reading will be implemented.
+ Precision = Long = _MAX_PATH;
+ Buf_Type = TYPE_STRING;
+ *Format.Type = 'C';
+ Format.Length = Long;
+#if defined(_WIN32)
+ Format.Prec = 1; // Case insensitive
+#endif // _WIN32
+ Constant = (!To_Tdb->GetDef()->GetMultiple() &&
+ To_Tdb->GetAmType() != TYPE_AM_PLG &&
+ To_Tdb->GetAmType() != TYPE_AM_PLM);
+ Fn = NULL;
+ } // end of FIDBLK constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to return the current */
+/* file ID of the table (can change for Multiple tables). */
+/***********************************************************************/
+void FIDBLK::ReadColumn(PGLOBAL g)
+ {
+ if (Fn != To_Tdb->GetFile(g)) {
+ char filename[_MAX_PATH];
+
+ Fn = To_Tdb->GetFile(g);
+ PlugSetPath(filename, Fn, To_Tdb->GetPath());
+
+ if (Op != OP_XX) {
+ char buff[_MAX_PATH];
+
+ Value->SetValue_psz(ExtractFromPath(g, buff, filename, Op));
+ } else
+ Value->SetValue_psz(filename);
+
+ } // endif Fn
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* TIDBLK constructor for the TABID special column. */
+/***********************************************************************/
+TIDBLK::TIDBLK(PCOLUMN cp) : SPCBLK(cp)
+ {
+//Is_Key = 2; for when the MUL table indexed reading will be implemented.
+ Precision = Long = 64;
+ Buf_Type = TYPE_STRING;
+ *Format.Type = 'C';
+ Format.Length = Long;
+ Format.Prec = 1; // Case insensitive
+ Constant = (To_Tdb->GetAmType() != TYPE_AM_TBL);
+ Tname = NULL;
+ } // end of TIDBLK constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to return the table ID. */
+/***********************************************************************/
+void TIDBLK::ReadColumn(PGLOBAL)
+ {
+ if (Tname == NULL) {
+ Tname = (char*)To_Tdb->GetName();
+ Value->SetValue_psz(Tname);
+ } // endif Tname
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* PRTBLK constructor for the PARTID special column. */
+/***********************************************************************/
+PRTBLK::PRTBLK(PCOLUMN cp) : SPCBLK(cp)
+ {
+//Is_Key = 2; for when the MUL table indexed reading will be implemented.
+ Precision = Long = 64;
+ Buf_Type = TYPE_STRING;
+ *Format.Type = 'C';
+ Format.Length = Long;
+ Format.Prec = 1; // Case insensitive
+ Constant = true; // TODO: check whether this is true indeed
+ Pname = NULL;
+ } // end of PRTBLK constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to return the partition ID. */
+/***********************************************************************/
+void PRTBLK::ReadColumn(PGLOBAL g)
+ {
+ if (Pname == NULL) {
+ const char *p;
+
+ Pname = To_Tdb->GetDef()->GetStringCatInfo(g, "partname", "?");
+ p = strrchr(Pname, '#');
+ Value->SetValue_psz((p) ? p + 1 : Pname);
+ } // endif Pname
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* SIDBLK constructor for the SERVID special column. */
+/***********************************************************************/
+SIDBLK::SIDBLK(PCOLUMN cp) : SPCBLK(cp)
+ {
+//Is_Key = 2; for when the MUL table indexed reading will be implemented.
+ Precision = Long = 64;
+ Buf_Type = TYPE_STRING;
+ *Format.Type = 'C';
+ Format.Length = Long;
+ Format.Prec = 1; // Case insensitive
+ Constant = (To_Tdb->GetAmType() != TYPE_AM_TBL);
+ Sname = NULL;
+ } // end of TIDBLK constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to return the server ID. */
+/***********************************************************************/
+void SIDBLK::ReadColumn(PGLOBAL)
+ {
+//if (Sname == NULL) {
+ Sname = To_Tdb->GetServer();
+ Value->SetValue_psz(Sname);
+// } // endif Sname
+
+ } // end of ReadColumn
diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h
new file mode 100644
index 00000000..7f1af8b8
--- /dev/null
+++ b/storage/connect/colblk.h
@@ -0,0 +1,232 @@
+/*************** Colblk H Declares Source Code File (.H) ***************/
+/* Name: COLBLK.H Version 1.7 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2015 */
+/* */
+/* This file contains the COLBLK and derived classes declares. */
+/***********************************************************************/
+#ifndef __COLBLK__H
+#define __COLBLK__H
+
+/***********************************************************************/
+/* Include required application header files */
+/***********************************************************************/
+#include "xobject.h"
+#include "reldef.h"
+
+/***********************************************************************/
+/* Class COLBLK: Base class for table column descriptors. */
+/***********************************************************************/
+class DllExport COLBLK : public XOBJECT {
+ friend class TDBPIVOT;
+ protected:
+ // Default constructors used by derived classes
+ COLBLK(PCOLDEF cdp = NULL, PTDB tdbp = NULL, int i = 0);
+ COLBLK(PCOL colp, PTDB tdbp = NULL); // Used in copy process
+ COLBLK(int) {} // Used when changing a column class in TDBXML
+
+ public:
+ // Implementation
+ virtual int GetType(void) {return TYPE_COLBLK;}
+ virtual int GetResultType(void) {return Buf_Type;}
+ virtual int GetScale(void) {return Format.Prec;}
+ virtual int GetPrecision(void) {return Precision;}
+ virtual int GetLength(void) {return Long;}
+ virtual int GetLengthEx(void);
+ virtual int GetAmType() {return TYPE_AM_ERROR;}
+ virtual void SetOk(void) {Status |= BUF_EMPTY;}
+ virtual PTDB GetTo_Tdb(void) {return To_Tdb;}
+ virtual int GetClustered(void) {return 0;}
+ virtual int IsClustered(void) {return FALSE;}
+ virtual bool Stringify(void) {return FALSE;}
+ virtual PSZ GetJpath(PGLOBAL g, bool proj) {return NULL;}
+ PCOL GetNext(void) {return Next;}
+ PSZ GetName(void) {return Name;}
+ int GetIndex(void) {return Index;}
+ ushort GetColUse(void) {return ColUse;}
+ int GetOpt(void) {return Opt;}
+ ushort GetColUse(ushort u) {return (ColUse & u);}
+ ushort GetStatus(void) {return Status;}
+ ushort GetStatus(ushort u) {return (Status & u);}
+ void SetColUse(ushort u) {ColUse = u;}
+ void SetStatus(ushort u) {Status = u;}
+ void AddColUse(ushort u) {ColUse |= u;}
+ void AddStatus(ushort u) {Status |= u;}
+ void SetNext(PCOL cp) {Next = cp;}
+ PXCOL GetKcol(void) {return To_Kcol;}
+ void SetKcol(PXCOL kcp) {To_Kcol = kcp;}
+ PCOLDEF GetCdp(void) {return Cdp;}
+ PSZ GetDomain(void) {return (Cdp) ? Cdp->Decode : NULL;}
+ PSZ GetDesc(void) {return (Cdp) ? Cdp->Desc : NULL;}
+ PSZ GetFmt(void) {return (Cdp) ? Cdp->Fmt : NULL;}
+ bool IsUnsigned(void) {return Unsigned;}
+ bool IsVirtual(void) {return Cdp->IsVirtual();}
+ bool IsNullable(void) {return Nullable;}
+ void SetNullable(bool b) {Nullable = b;}
+ void SetName(PSZ name_var) { Name= name_var; }
+ // Methods
+ virtual void Reset(void);
+ virtual bool Compare(PXOB xp);
+ virtual bool SetFormat(PGLOBAL, FORMAT&);
+ virtual bool IsSpecial(void) {return false;}
+ virtual bool Eval(PGLOBAL g);
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void SetTo_Val(PVAL) {}
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ virtual void Printf(PGLOBAL g, FILE *, uint);
+ virtual void Prints(PGLOBAL g, char *, uint);
+ virtual bool VarSize(void) {return false;}
+ bool InitValue(PGLOBAL g);
+
+ protected:
+ // Members
+ PCOL Next; // Next column in table
+ PSZ Name; // Column name
+ PCOLDEF Cdp; // To column definition block
+ PTDB To_Tdb; // Points to Table Descriptor Block
+ PXCOL To_Kcol; // Points to Xindex matching column
+ bool Nullable; // True if nullable
+ bool Unsigned; // True if unsigned
+ int Index; // Column number in table
+ int Opt; // Cluster/sort information
+ int Buf_Type; // Data type
+ int Long; // Internal length in table
+ int Precision; // Column length (as for ODBC)
+ int Freq; // Evaluated ceiling of distinct values
+ FORMAT Format; // Output format
+ ushort ColUse; // Column usage
+ ushort Status; // Column read status
+ }; // end of class COLBLK
+
+/***********************************************************************/
+/* Class SPCBLK: Base class for special column descriptors. */
+/***********************************************************************/
+class DllExport SPCBLK : public COLBLK {
+ public:
+ // Constructor
+ SPCBLK(PCOLUMN cp);
+
+ // Implementation
+ virtual int GetAmType(void) = 0;
+ virtual bool GetRnm(void) {return false;}
+
+ // Methods
+ virtual bool IsSpecial(void) {return true;}
+ virtual void ReadColumn(PGLOBAL g) = 0;
+ virtual void WriteColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ SPCBLK(void) : COLBLK(1) {}
+ }; // end of class SPCBLK
+
+/***********************************************************************/
+/* Class RIDBLK: ROWID special column descriptor. */
+/***********************************************************************/
+class DllExport RIDBLK : public SPCBLK {
+ public:
+ // Constructor
+ RIDBLK(PCOLUMN cp, bool rnm);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_ROWID;}
+ virtual bool GetRnm(void) {return Rnm;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ bool Rnm; // False for RowID, True for RowNum
+ }; // end of class RIDBLK
+
+/***********************************************************************/
+/* Class FIDBLK: FILEID special column descriptor. */
+/***********************************************************************/
+class DllExport FIDBLK : public SPCBLK {
+ public:
+ // Constructor
+ FIDBLK(PCOLUMN cp, OPVAL op);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_FILID;}
+
+ // Methods
+ virtual void Reset(void) {} // This is a pseudo constant column
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ PCSZ Fn; // The current To_File of the table
+ OPVAL Op; // The file part operator
+ }; // end of class FIDBLK
+
+/***********************************************************************/
+/* Class TIDBLK: TABID special column descriptor. */
+/***********************************************************************/
+class DllExport TIDBLK : public SPCBLK {
+ public:
+ // Constructor
+ TIDBLK(PCOLUMN cp);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_TABID;}
+
+ // Methods
+ virtual void Reset(void) {} // This is a pseudo constant column
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ TIDBLK(void) {}
+
+ // Members
+ PCSZ Tname; // The current table name
+ }; // end of class TIDBLK
+
+/***********************************************************************/
+/* Class PRTBLK: PARTID special column descriptor. */
+/***********************************************************************/
+class DllExport PRTBLK : public SPCBLK {
+ public:
+ // Constructor
+ PRTBLK(PCOLUMN cp);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_PRTID;}
+
+ // Methods
+ virtual void Reset(void) {} // This is a pseudo constant column
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ PRTBLK(void) {}
+
+ // Members
+ PCSZ Pname; // The current partition name
+ }; // end of class PRTBLK
+
+/***********************************************************************/
+/* Class SIDBLK: SERVID special column descriptor. */
+/***********************************************************************/
+class DllExport SIDBLK : public SPCBLK {
+ public:
+ // Constructor
+ SIDBLK(PCOLUMN cp);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_SRVID;}
+
+ // Methods
+ virtual void Reset(void) {} // This is a pseudo constant column
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ SIDBLK(void) {}
+
+ // Members
+ PCSZ Sname; // The current server name
+ }; // end of class SIDBLK
+
+#endif // __COLBLK__H
diff --git a/storage/connect/connect.cc b/storage/connect/connect.cc
new file mode 100644
index 00000000..ee62e0cd
--- /dev/null
+++ b/storage/connect/connect.cc
@@ -0,0 +1,965 @@
+/* Copyright (C) Olivier Bertrand 2004 - 2017
+ Copyright (C) MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/***********************************************************************/
+/* Author Olivier BERTRAND bertrandop@gmail.com 2004-2019 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the CONNECT general purpose semantic routines. */
+/***********************************************************************/
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+/***********************************************************************/
+/* Include application header files */
+/* */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/***********************************************************************/
+#define DONT_DEFINE_VOID
+#include <my_global.h>
+#include "handler.h"
+#undef OFFSET
+
+#include "global.h"
+#include "plgdbsem.h"
+#include "xobject.h"
+#include "connect.h"
+#include "tabcol.h"
+#include "catalog.h"
+#include "ha_connect.h"
+
+#define my_strupr(p) my_caseup_str(default_charset_info, (p));
+#define my_strlwr(p) my_casedn_str(default_charset_info, (p));
+#define my_stricmp(a, b) my_strcasecmp(default_charset_info, (a), (b))
+
+/***********************************************************************/
+/* Routines called internally by semantic routines. */
+/***********************************************************************/
+void CntEndDB(PGLOBAL);
+RCODE EvalColumns(PGLOBAL g, PTDB tdbp, bool reset, bool mrr= false);
+
+/***********************************************************************/
+/* MySQL routines called externally by semantic routines. */
+/***********************************************************************/
+int rename_file_ext(const char *from, const char *to,const char *ext);
+
+/***********************************************************************/
+/* CntExit: CONNECT termination routine. */
+/***********************************************************************/
+PGLOBAL CntExit(PGLOBAL g)
+ {
+ if (g) {
+ CntEndDB(g);
+
+ if (g->Activityp) {
+ delete g->Activityp;
+ g->Activityp = NULL;
+ } // endif Activityp
+
+ g= PlugExit(g);
+ } // endif g
+
+ return g;
+ } // end of CntExit
+
+/***********************************************************************/
+/* CntEndDB: DB termination semantic routine. */
+/***********************************************************************/
+void CntEndDB(PGLOBAL g)
+{
+ PDBUSER dbuserp= PlgGetUser(g);
+
+ if (dbuserp) {
+ if (dbuserp->Catalog)
+ delete dbuserp->Catalog;
+
+ free(dbuserp);
+
+ if (trace(1))
+ htrc("CntEndDB: Freeing Dup\n");
+
+ g->Activityp->Aptr = NULL;
+ } // endif dbuserp
+
+} // end of CntEndDB
+
+/***********************************************************************/
+/* CntCheckDB: Initialize a DB application session. */
+/* Note: because MySQL does not call a storage handler when a user */
+/* executes a use db command, a check must be done before an SQL */
+/* command is executed to check whether we are still working on the */
+/* current database, and if not to load the newly used database. */
+/***********************************************************************/
+bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname)
+ {
+ bool rc= false;
+ PDBUSER dbuserp= PlgGetUser(g);
+
+ if (trace(1)) {
+ printf("CntCheckDB: dbuserp=%p\n", dbuserp);
+ } // endif trace
+
+ if (!dbuserp || !handler)
+ return true;
+
+ if (trace(1))
+ printf("cat=%p oldhandler=%p newhandler=%p\n", dbuserp->Catalog,
+ (dbuserp->Catalog) ? ((MYCAT*)dbuserp->Catalog)->GetHandler() : NULL,
+ handler);
+
+ // Set the database path for this table
+ if (handler->SetDataPath(g, pathname))
+ return true;
+
+ if (dbuserp->Catalog) {
+ return false; // Nothing else to do
+ } // endif Catalog
+
+ // Copy new database name in dbuser block
+ strncpy(dbuserp->Name, "???", sizeof(dbuserp->Name) - 1);
+
+ dbuserp->Vtdbno= 0; // Init of TDB numbers
+
+ /*********************************************************************/
+ /* Now allocate and initialize the Database Catalog. */
+ /*********************************************************************/
+ dbuserp->Step= MSG(READY);
+
+ if (!(dbuserp->Catalog= new MYCAT(handler)))
+ return true;
+
+ /*********************************************************************/
+ /* All is correct. */
+ /*********************************************************************/
+ sprintf(g->Message, MSG(DATABASE_LOADED), "???");
+
+ if (trace(1))
+ printf("msg=%s\n", g->Message);
+
+ return rc;
+ } // end of CntCheckDB
+
+/***********************************************************************/
+/* CntInfo: Get table info. */
+/* Returns valid: true if this is a table info. */
+/***********************************************************************/
+bool CntInfo(PGLOBAL g, PTDB tp, PXF info)
+{
+ if (tp) {
+ bool b = (tp->GetFtype() == RECFM_NAF);
+ PTDBDOS tdbp = b ? NULL : (PTDBDOS)tp;
+
+ info->data_file_length = (b) ? 0 : (ulonglong)tdbp->GetFileLength(g);
+
+ if (b || info->data_file_length)
+ info->records= (unsigned)tp->Cardinality(g);
+// info->records= (unsigned)tp->GetMaxSize(g);
+ else
+ info->records= 0;
+
+// info->mean_rec_length= tdbp->GetLrecl();
+ info->mean_rec_length= 0;
+ info->data_file_name= (b) ? NULL : (char*)tdbp->GetFile(g);
+ return true;
+ } else {
+ info->data_file_length= 0;
+ info->records= 0;
+ info->mean_rec_length= 0;
+ info->data_file_name= NULL;
+ return false;
+ } // endif tdbp
+
+} // end of CntInfo
+
+/***********************************************************************/
+/* GetTDB: Get the table description block of a CONNECT table. */
+/***********************************************************************/
+PTDB CntGetTDB(PGLOBAL g, LPCSTR name, MODE mode, PHC h)
+{
+ PTDB tdbp = NULL;
+ PTABLE tabp;
+ PDBUSER dup = PlgGetUser(g);
+ volatile PCATLG cat = (dup) ? dup->Catalog : NULL; // Safe over throw
+
+ if (trace(1))
+ printf("CntGetTDB: name=%s mode=%d cat=%p\n", name, mode, cat);
+
+ if (!cat)
+ return NULL;
+
+ try {
+ // Get table object from the catalog
+ tabp = new(g) XTAB(name);
+
+ if (trace(1))
+ printf("CntGetTDB: tabp=%p\n", tabp);
+
+ // Perhaps this should be made thread safe
+ ((MYCAT*)cat)->SetHandler(h);
+
+ if (!(tdbp = cat->GetTable(g, tabp, mode)))
+ printf("CntGetTDB: %s\n", g->Message);
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+ if (trace(1))
+ printf("Returning tdbp=%p mode=%d\n", tdbp, mode);
+
+ return tdbp;
+} // end of CntGetTDB
+
+/***********************************************************************/
+/* OPENTAB: Open a Table. */
+/***********************************************************************/
+bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE mode, char *c1, char *c2,
+ bool del, PHC)
+ {
+ char *p;
+ int i, n;
+ bool rcop= true;
+ PCOL colp;
+//PCOLUMN cp;
+ PDBUSER dup= PlgGetUser(g);
+
+ if (trace(1))
+ printf("CntOpenTable: tdbp=%p mode=%d\n", tdbp, mode);
+
+ if (!tdbp) {
+ strcpy(g->Message, "Null tdbp");
+ printf("CntOpenTable: %s\n", g->Message);
+ return true;
+ } // endif tdbp
+
+ try {
+ if (!c1) {
+// if (mode == MODE_INSERT) or CHECK TABLE
+ // Allocate all column blocks for that table
+ tdbp->ColDB(g, NULL, 0);
+
+ } else for (p = c1; *p; p += n) {
+ // Allocate only used column blocks
+ if (trace(1))
+ printf("Allocating column %s\n", p);
+
+ g->Message[0] = 0; // To check whether ColDB made an error message
+ colp = tdbp->ColDB(g, p, 0);
+
+ if (!colp && !(mode == MODE_INSERT && tdbp->IsSpecial(p))) {
+ if (g->Message[0] == 0)
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), p, tdbp->GetName());
+
+ throw 1;
+ } // endif colp
+
+ n = strlen(p) + 1;
+ } // endfor p
+
+ for (i = 0, colp = tdbp->GetColumns(); colp; i++, colp = colp->GetNext()) {
+ if (colp->InitValue(g))
+ throw 2;
+
+ if (mode == MODE_INSERT)
+ // Allow type conversion
+ if (colp->SetBuffer(g, colp->GetValue(), true, false))
+ throw 3;
+
+ colp->AddColUse(U_P); // For PLG tables
+ } // endfor colp
+
+ /*******************************************************************/
+ /* In Update mode, the updated column blocks must be distinct from */
+ /* the read column blocks. So make a copy of the TDB and allocate */
+ /* its column blocks in mode write (required by XML tables). */
+ /*******************************************************************/
+ if (mode == MODE_UPDATE) {
+ PTDB utp;
+
+ if (!(utp = tdbp->Duplicate(g))) {
+ sprintf(g->Message, MSG(INV_UPDT_TABLE), tdbp->GetName());
+ throw 4;
+ } // endif tp
+
+ if (!c2)
+ // Allocate all column blocks for that table
+ utp->ColDB(g, NULL, 0);
+ else for (p = c2; *p; p += n) {
+ // Allocate only used column blocks
+ colp = utp->ColDB(g, p, 0);
+ n = strlen(p) + 1;
+ } // endfor p
+
+ for (i = 0, colp = utp->GetColumns(); colp; i++, colp = colp->GetNext()) {
+ if (colp->InitValue(g))
+ throw 5;
+
+ if (colp->SetBuffer(g, colp->GetValue(), true, false))
+ throw 6;
+
+ } // endfor colp
+
+ // Attach the updated columns list to the main table
+ tdbp->SetSetCols(utp->GetColumns());
+ } else if (tdbp && mode == MODE_INSERT)
+ tdbp->SetSetCols(tdbp->GetColumns());
+
+ // Now do open the physical table
+ if (trace(1))
+ printf("Opening table %s in mode %d tdbp=%p\n",
+ tdbp->GetName(), mode, tdbp);
+
+ //tdbp->SetMode(mode);
+
+ if (del/* && (tdbp->GetFtype() != RECFM_NAF*/) {
+ // To avoid erasing the table when doing a partial delete
+ // make a fake Next
+// PDOSDEF ddp= new(g) DOSDEF;
+// PTDB tp= new(g) TDBDOS(ddp, NULL);
+ tdbp->SetNext((PTDB)1);
+ dup->Check &= ~CHK_DELETE;
+ } // endif del
+
+
+ if (trace(1))
+ printf("About to open the table: tdbp=%p\n", tdbp);
+
+ if (mode != MODE_ANY && mode != MODE_ALTER) {
+ if (tdbp->OpenDB(g)) {
+ printf("%s\n", g->Message);
+ throw 7;
+ } else
+ tdbp->SetNext(NULL);
+
+ } // endif mode
+
+ rcop = false;
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+ return rcop;
+ } // end of CntOpenTable
+
+/***********************************************************************/
+/* Rewind a table by reopening it. */
+/***********************************************************************/
+bool CntRewindTable(PGLOBAL g, PTDB tdbp)
+{
+ if (!tdbp)
+ return true;
+
+ tdbp->OpenDB(g);
+ return false;
+} // end of CntRewindTable
+
+/***********************************************************************/
+/* Evaluate all columns after a record is read. */
+/***********************************************************************/
+RCODE EvalColumns(PGLOBAL g, PTDB tdbp, bool reset, bool mrr)
+{
+ RCODE rc= RC_OK;
+ PCOL colp;
+
+ try {
+ for (colp = tdbp->GetColumns(); rc == RC_OK && colp;
+ colp = colp->GetNext()) {
+ xtrc(2, "Going to read column %s of table %s\n",
+ colp->GetName(), tdbp->GetName());
+
+ if (reset)
+ colp->Reset();
+
+ // Virtual columns are computed by MariaDB
+ if (!colp->GetColUse(U_VIRTUAL) && (!mrr || colp->GetKcol()))
+ if (colp->Eval(g))
+ rc = RC_FX;
+
+ } // endfor colp
+
+ } catch (int n) {
+ if (trace(1))
+ printf("Error %d reading columns: %s\n", n, g->Message);
+
+ rc = RC_FX;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc = RC_NF;
+ } // end catch
+
+ return rc;
+} // end of EvalColumns
+
+/***********************************************************************/
+/* ReadNext: Read next record sequentially. */
+/***********************************************************************/
+RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
+{
+ RCODE rc;
+
+ if (!tdbp)
+ return RC_FX;
+ else if (tdbp->GetKindex()) {
+ // Reading sequencially an indexed table. This happens after the
+ // handler function records_in_range was called and MySQL decides
+ // to quit using the index (!!!) Drop the index.
+// for (PCOL colp= tdbp->GetColumns(); colp; colp= colp->GetNext())
+// colp->SetKcol(NULL);
+
+ ((PTDBASE)tdbp)->ResetKindex(g, NULL);
+ } // endif index
+
+ try {
+ // Do it now to avoid double eval when filtering
+ for (PCOL colp = tdbp->GetColumns(); colp; colp = colp->GetNext())
+ colp->Reset();
+
+ do {
+ if ((rc = (RCODE)tdbp->ReadDB(g)) == RC_OK)
+ if (!ApplyFilter(g, tdbp->GetFilter()))
+ rc = RC_NF;
+
+ } while (rc == RC_NF);
+
+ if (rc == RC_OK)
+ rc = EvalColumns(g, tdbp, false);
+
+ } catch (int) {
+ rc = RC_FX;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc = RC_FX;
+ } // end catch
+
+ return rc;
+} // end of CntReadNext
+
+/***********************************************************************/
+/* WriteRow: Insert a new row into a table. */
+/***********************************************************************/
+RCODE CntWriteRow(PGLOBAL g, PTDB tdbp)
+{
+ RCODE rc;
+ PCOL colp;
+ //PTDBASE tp= (PTDBASE)tdbp;
+
+ if (!tdbp)
+ return RC_FX;
+
+ try {
+ // Store column values in table write buffer(s)
+ for (colp = tdbp->GetSetCols(); colp; colp = colp->GetNext())
+ if (!colp->GetColUse(U_VIRTUAL))
+ colp->WriteColumn(g);
+
+ if (tdbp->IsIndexed())
+ // Index values must be sorted before updating
+ rc = (RCODE)((PTDBDOS)tdbp)->GetTxfp()->StoreValues(g, true);
+ else
+ // Return result code from write operation
+ rc = (RCODE)tdbp->WriteDB(g);
+
+ } catch (int n) {
+ printf("Exception %d: %s\n", n, g->Message);
+ rc = RC_FX;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc = RC_FX;
+ } // end catch
+
+ return rc;
+} // end of CntWriteRow
+
+/***********************************************************************/
+/* UpdateRow: Update a row into a table. */
+/***********************************************************************/
+RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp)
+ {
+ if (!tdbp || tdbp->GetMode() != MODE_UPDATE)
+ return RC_FX;
+
+ // Return result code from write operation
+ return CntWriteRow(g, tdbp);
+ } // end of CntUpdateRow
+
+/***********************************************************************/
+/* DeleteRow: Delete a row from a table. */
+/***********************************************************************/
+RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all)
+ {
+ RCODE rc;
+//PTDBASE tp= (PTDBASE)tdbp;
+
+ if (!tdbp || tdbp->GetMode() != MODE_DELETE)
+ return RC_FX;
+ else if (tdbp->IsReadOnly())
+ return RC_NF;
+
+ if (all) {
+ if (tdbp->GetDef()->Indexable())
+ ((PTDBDOS)tdbp)->Cardinal= 0;
+
+ // Note: if all, this call will be done when closing the table
+ rc= (RCODE)tdbp->DeleteDB(g, RC_FX);
+//} else if (tdbp->GetKindex() && !((PTDBASE)tdbp)->GetKindex()->IsSorted() &&
+// ((PTDBASE)tdbp)->Txfp->GetAmType() != TYPE_AM_DBF) {
+ } else if(tdbp->IsIndexed()) {
+ // Index values must be sorted before updating
+ rc= (RCODE)((PTDBDOS)tdbp)->GetTxfp()->StoreValues(g, false);
+ } else // Return result code from delete operation
+ rc= (RCODE)tdbp->DeleteDB(g, RC_OK);
+
+ return rc;
+ } // end of CntDeleteRow
+
+/***********************************************************************/
+/* CLOSETAB: Close a table. */
+/***********************************************************************/
+int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort)
+{
+ int rc = RC_OK;
+ //TDBASE *tbxp= (PTDBASE)tdbp;
+
+ if (!tdbp)
+ return rc; // Nothing to do
+ else if (tdbp->GetUse() != USE_OPEN) {
+ if (tdbp->GetAmType() == TYPE_AM_XML)
+ tdbp->CloseDB(g); // Opened by GetMaxSize
+
+ return rc;
+ } // endif !USE_OPEN
+
+ if (trace(1))
+ printf("CntCloseTable: tdbp=%p mode=%d nox=%d abort=%d\n",
+ tdbp, tdbp->GetMode(), nox, abort);
+
+ if (tdbp->GetMode() == MODE_DELETE && tdbp->GetUse() == USE_OPEN) {
+ if (tdbp->IsIndexed())
+ rc = ((PTDBDOS)tdbp)->GetTxfp()->DeleteSortedRows(g);
+
+ if (!rc)
+ rc = tdbp->DeleteDB(g, RC_EF); // Specific A.M. delete routine
+
+ } else if (tdbp->GetMode() == MODE_UPDATE && tdbp->IsIndexed())
+ rc = ((PTDBDOS)tdbp)->GetTxfp()->UpdateSortedRows(g);
+
+ switch (rc) {
+ case RC_FX:
+ abort = true;
+ break;
+ case RC_INFO:
+ PushWarning(g, tdbp);
+ break;
+ } // endswitch rc
+
+ try {
+ // This will close the table file(s) and also finalize write
+ // operations such as Insert, Update, or Delete.
+ tdbp->SetAbort(abort);
+ tdbp->CloseDB(g);
+ tdbp->SetAbort(false);
+
+ if (trace(2))
+ printf("Table %s closed\n", tdbp->GetName());
+
+ if (!nox && tdbp->GetMode() != MODE_READ && tdbp->GetMode() != MODE_ANY) {
+ if (trace(2))
+ printf("About to reset opt\n");
+
+ if (!tdbp->IsRemote()) {
+ // Make all the eventual indexes
+ PTDBASE tbxp = (PTDBASE)tdbp;
+ tbxp->ResetKindex(g, NULL);
+ tbxp->SetKey_Col(NULL);
+ rc = tbxp->ResetTableOpt(g, true, tbxp->GetDef()->Indexable() == 1);
+ } // endif remote
+
+ } // endif nox
+
+ } catch (int) {
+ rc = RC_FX;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc = RC_FX;
+ } // end catch
+
+ if (trace(2))
+ htrc("Done rc=%d\n", rc);
+
+ return (rc == RC_OK || rc == RC_INFO) ? 0 : rc;
+} // end of CntCloseTable
+
+/***********************************************************************/
+/* Load and initialize the use of an index. */
+/* This is the condition(s) for doing indexing. */
+/* Note: FIX table are not reset here to Nrec= 1. */
+/***********************************************************************/
+int CntIndexInit(PGLOBAL g, PTDB ptdb, int id, bool sorted)
+ {
+ PIXDEF xdp;
+ PTDBDOS tdbp;
+ DOSDEF *dfp;
+
+ if (!ptdb)
+ return -1;
+ else if (!ptdb->GetDef()->Indexable()) {
+ sprintf(g->Message, MSG(TABLE_NO_INDEX), ptdb->GetName());
+ return 0;
+ } else if (ptdb->GetDef()->Indexable() == 3) {
+ return 1;
+ } else
+ tdbp= (PTDBDOS)ptdb;
+
+ dfp= (DOSDEF*)tdbp->GetDef();
+
+//if (!(k= colp->GetKey()))
+// if (colp->GetOpt() >= 2) {
+// strcpy(g->Message, "Not a valid indexed column");
+// return -1;
+// } else
+ // This is a pseudo indexed sorted block optimized column
+// return 0;
+
+ if (tdbp->GetKindex())
+ {
+ if (((XXBASE*)tdbp->GetKindex())->GetID() == id) {
+ tdbp->GetKindex()->Reset(); // Same index
+ return (tdbp->GetKindex()->IsMul()) ? 2 : 1;
+ } else {
+ tdbp->GetKindex()->Close();
+ tdbp->SetKindex(NULL);
+ } // endif colp
+ }
+
+ for (xdp= dfp->GetIndx(); xdp; xdp= xdp->GetNext())
+ if (xdp->GetID() == id)
+ break;
+
+ if (!xdp) {
+ sprintf(g->Message, "Wrong index ID %d", id);
+ return 0;
+ } // endif xdp
+
+#if 0
+ if (xdp->IsDynamic()) {
+ // This is a dynamically created index (KINDEX)
+ // It should not be created now, if called by index range
+ tdbp->SetXdp(xdp);
+ return (xdp->IsUnique()) ? 1 : 2;
+ } // endif dynamic
+#endif // 0
+
+ // Static indexes must be initialized now for records_in_range
+ if (tdbp->InitialyzeIndex(g, xdp, sorted))
+ return 0;
+
+ return (tdbp->GetKindex()->IsMul()) ? 2 : 1;
+ } // end of CntIndexInit
+
+#if defined(WORDS_BIGENDIAN)
+/***********************************************************************/
+/* Swap bytes of the key that are written in little endian order. */
+/***********************************************************************/
+static void SetSwapValue(PVAL valp, char *kp)
+{
+ if (valp->IsTypeNum() && valp->GetType() != TYPE_DECIM) {
+ uchar buf[8];
+ int i, k= valp->GetClen();
+
+ for (i = 0; k > 0;)
+ buf[i++]= kp[--k];
+
+
+
+ valp->SetBinValue((void*)buf);
+ } else
+ valp->SetBinValue((void*)kp);
+
+} // end of SetSwapValue
+#endif // WORDS_BIGENDIAN
+
+/***********************************************************************/
+/* IndexRead: fetch a record having the index value. */
+/***********************************************************************/
+RCODE CntIndexRead(PGLOBAL g, PTDB ptdb, OPVAL op,
+ const key_range *kr, bool mrr)
+ {
+ int n, x;
+ RCODE rc;
+ XXBASE *xbp;
+ PTDBDOS tdbp;
+
+ if (!ptdb)
+ return RC_FX;
+ else
+ x= ptdb->GetDef()->Indexable();
+
+ if (!x) {
+ sprintf(g->Message, MSG(TABLE_NO_INDEX), ptdb->GetName());
+ return RC_FX;
+ } else if (x == 2) {
+ // Remote index. Only used in read mode
+ if ((ptdb->GetMode() == MODE_READ || ptdb->GetMode() == MODE_READX)
+ && op != OP_SAME && ptdb->ReadKey(g, op, kr))
+ return RC_FX;
+
+ goto rnd;
+ } else if (x == 3) {
+ if (kr)
+ ((PTDBASE)ptdb)->SetRecpos(g, *(int*)kr->key);
+
+ if (op == OP_SAME)
+ return RC_NF;
+
+ goto rnd;
+ } else
+ tdbp= (PTDBDOS)ptdb;
+
+ // Set reference values and index operator
+ if (!tdbp->GetLink() || !tdbp->GetKindex()) {
+// if (!tdbp->To_Xdp) {
+ sprintf(g->Message, "Index not initialized for table %s", tdbp->GetName());
+ return RC_FX;
+#if 0
+ } // endif !To_Xdp
+ // Now it's time to make the dynamic index
+ if (tdbp->InitialyzeIndex(g, NULL, false)) {
+ sprintf(g->Message, "Fail to make dynamic index %s",
+ tdbp->To_Xdp->GetName());
+ return RC_FX;
+ } // endif MakeDynamicIndex
+#endif // 0
+ } // endif !To_Kindex
+
+ xbp= (XXBASE*)tdbp->GetKindex();
+
+ if (kr) {
+ char *kp= (char*)kr->key;
+ int len= kr->length;
+ short lg;
+ bool rcb;
+ PVAL valp;
+ PCOL colp;
+
+ for (n= 0; n < tdbp->GetKnum(); n++) {
+ colp= (PCOL)tdbp->Key(n);
+
+ if (colp->GetColUse(U_NULLS))
+ kp++; // Skip null byte
+
+ valp= tdbp->Link(n)->GetValue();
+
+ if (!valp->IsTypeNum()) {
+ if (colp->GetColUse(U_VAR)) {
+#if defined(WORDS_BIGENDIAN)
+ ((char*)&lg)[0]= ((char*)kp)[1];
+ ((char*)&lg)[1]= ((char*)kp)[0];
+#else // !WORDS_BIGENDIAN
+ lg= *(short*)kp;
+#endif //!WORDS_BIGENDIAN
+ kp+= sizeof(short);
+ rcb= valp->SetValue_char(kp, (int)lg);
+ } else
+ rcb= valp->SetValue_char(kp, valp->GetClen());
+
+ if (rcb) {
+ if (tdbp->RowNumber(g))
+ sprintf(g->Message, "Out of range value for column %s at row %d",
+ colp->GetName(), tdbp->RowNumber(g));
+ else
+ sprintf(g->Message, "Out of range value for column %s",
+ colp->GetName());
+
+ PushWarning(g, tdbp);
+ } // endif b
+
+ } else
+#if defined(WORDS_BIGENDIAN)
+ SetSwapValue(valp, kp);
+#else // !WORDS_BIGENDIAN
+ valp->SetBinValue((void*)kp);
+#endif //!WORDS_BIGENDIAN
+
+ kp+= valp->GetClen();
+
+ if (len == kp - (char*)kr->key) {
+ n++;
+ break;
+ } else if (len < kp - (char*)kr->key) {
+ strcpy(g->Message, "Key buffer is too small");
+ return RC_FX;
+ } // endif len
+
+ } // endfor n
+
+ xbp->SetNval(n);
+ } // endif key
+
+ xbp->SetOp(op);
+ xbp->SetNth(0);
+
+ rnd:
+ if ((rc= (RCODE)ptdb->ReadDB(g)) == RC_OK)
+ rc= EvalColumns(g, ptdb, true, mrr);
+
+ return rc;
+ } // end of CntIndexRead
+
+/***********************************************************************/
+/* Return the number of rows matching given values. */
+/***********************************************************************/
+int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len,
+ bool *incl, key_part_map *kmap)
+ {
+ const uchar *p, *kp;
+ int i, n, x, k[2];
+ short lg;
+ bool b, rcb;
+ PVAL valp;
+ PCOL colp;
+ PTDBDOS tdbp;
+ XXBASE *xbp;
+
+ if (!ptdb)
+ return -1;
+
+ x= ptdb->GetDef()->Indexable();
+
+ if (!x) {
+ sprintf(g->Message, MSG(TABLE_NO_INDEX), ptdb->GetName());
+ DBUG_PRINT("Range", ("%s", g->Message));
+ return -1;
+ } else if (x == 2) {
+ // Remote index
+ return 2;
+ } else if (x == 3) {
+ // Virtual index
+ for (i= 0; i < 2; i++)
+ if (key[i])
+ k[i] = *(int*)key[i] + (incl[i] ? 0 : 1 - 2 * i);
+ else
+ k[i] = (i) ? ptdb->Cardinality(g) : 1;
+
+ return k[1] - k[0] + 1;
+ } else
+ tdbp= (PTDBDOS)ptdb;
+
+ if (!tdbp->GetKindex() || !tdbp->GetLink()) {
+ if (!tdbp->GetXdp()) {
+ sprintf(g->Message, "Index not initialized for table %s", tdbp->GetName());
+ DBUG_PRINT("Range", ("%s", g->Message));
+ return -1;
+ } else // Dynamic index
+ return tdbp->GetXdp()->GetMaxSame(); // TODO a better estimate
+
+ } else
+ xbp= (XXBASE*)tdbp->GetKindex();
+
+ for (b= false, i= 0; i < 2; i++) {
+ p= kp= key[i];
+
+ if (kp) {
+ for (n= 0; n < tdbp->GetKnum(); n++) {
+ if (kmap[i] & (key_part_map)(1 << n)) {
+ if (b == true)
+ // Cannot do indexing with missing intermediate key
+ return -1;
+
+ colp= (PCOL)tdbp->Key(n);
+
+ if (colp->GetColUse(U_NULLS))
+ p++; // Skip null byte ???
+
+ valp= tdbp->Link(n)->GetValue();
+
+ if (!valp->IsTypeNum()) {
+ if (colp->GetColUse(U_VAR)) {
+#if defined(WORDS_BIGENDIAN)
+ ((char*)&lg)[0]= ((char*)p)[1];
+ ((char*)&lg)[1]= ((char*)p)[0];
+#else // !WORDS_BIGENDIAN
+ lg= *(short*)p;
+#endif //!WORDS_BIGENDIAN
+ p+= sizeof(short);
+ rcb= valp->SetValue_char((char*)p, (int)lg);
+ } else
+ rcb= valp->SetValue_char((char*)p, valp->GetClen());
+
+ if (rcb) {
+ if (tdbp->RowNumber(g))
+ sprintf(g->Message,
+ "Out of range value for column %s at row %d",
+ colp->GetName(), tdbp->RowNumber(g));
+ else
+ sprintf(g->Message, "Out of range value for column %s",
+ colp->GetName());
+
+ PushWarning(g, tdbp);
+ } // endif b
+
+ } else
+#if defined(WORDS_BIGENDIAN)
+ SetSwapValue(valp, (char*)p);
+#else // !WORDS_BIGENDIAN
+ valp->SetBinValue((void*)p);
+#endif // !WORDS_BIGENDIAN
+
+ if (trace(1)) {
+ char bf[32];
+ printf("i=%d n=%d key=%s\n", i, n, valp->GetCharString(bf));
+ } // endif trace
+
+ p+= valp->GetClen();
+
+ if (len[i] == (unsigned)(p - kp)) {
+ n++;
+ break;
+ } else if (len[i] < (unsigned)(p - kp)) {
+ strcpy(g->Message, "Key buffer is too small");
+ return -1;
+ } // endif len
+
+ } else
+ b= true;
+
+ } // endfor n
+
+ xbp->SetNval(n);
+
+ if (trace(1))
+ printf("xbp=%p Nval=%d i=%d incl=%d\n", xbp, n, i, incl[i]);
+
+ k[i]= xbp->Range(g, i + 1, incl[i]);
+ } else
+ k[i]= (i) ? xbp->GetNum_K() : 0;
+
+ } // endfor i
+
+ if (trace(1))
+ printf("k1=%d k0=%d\n", k[1], k[0]);
+
+ return k[1] - k[0];
+ } // end of CntIndexRange
diff --git a/storage/connect/connect.h b/storage/connect/connect.h
new file mode 100644
index 00000000..d1fc2ea5
--- /dev/null
+++ b/storage/connect/connect.h
@@ -0,0 +1,80 @@
+/* Copyright (C) MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**************** Cnt H Declares Source Code File (.H) *****************/
+/* Name: CONNECT.H Version 2.4 */
+/* Author Olivier BERTRAND bertrandop@gmail.com */
+/* This file contains the some based classes declares. */
+/***********************************************************************/
+#include "filamtxt.h"
+#include "tabdos.h"
+
+//typedef struct _tabdesc *PTABD; // For friend setting
+typedef struct _xinfo *PXF;
+typedef struct _create_xinfo *PCXF;
+typedef class ha_connect *PHC;
+typedef class TDBDOX *PTDBDOX;
+
+/****************************************************************************/
+/* CONNECT functions called externally. */
+/****************************************************************************/
+bool CntCheckDB(PGLOBAL g, PHC handler, const char *pathname);
+PTDB CntGetTDB(PGLOBAL g, const char *name, MODE xmod, PHC);
+bool CntOpenTable(PGLOBAL g, PTDB tdbp, MODE, char *, char *, bool, PHC);
+bool CntRewindTable(PGLOBAL g, PTDB tdbp);
+int CntCloseTable(PGLOBAL g, PTDB tdbp, bool nox, bool abort);
+int CntIndexInit(PGLOBAL g, PTDB tdbp, int id, bool sorted);
+RCODE CntReadNext(PGLOBAL g, PTDB tdbp);
+RCODE CntIndexRead(PGLOBAL g, PTDB, OPVAL op, const key_range *kr, bool mrr);
+RCODE CntWriteRow(PGLOBAL g, PTDB tdbp);
+RCODE CntUpdateRow(PGLOBAL g, PTDB tdbp);
+RCODE CntDeleteRow(PGLOBAL g, PTDB tdbp, bool all);
+bool CntInfo(PGLOBAL g, PTDB tdbp, PXF info);
+int CntIndexRange(PGLOBAL g, PTDB ptdb, const uchar* *key, uint *len,
+ bool *incl, key_part_map *kmap);
+PGLOBAL CntExit(PGLOBAL g);
+
+#if 0
+/***********************************************************************/
+/* Definition of classes XKPDEF, DOXDEF, TDBDOX */
+/* These classes purpose is chiefly to access protected items! */
+/***********************************************************************/
+class DOXDEF: public DOSDEF {
+ friend int CntIndexInit(PGLOBAL, PTDB, int, bool);
+ }; // end of class DOXDEF
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method base class declaration. */
+/***********************************************************************/
+class TDBDOX: public TDBDOS {
+ friend int MakeIndex(PGLOBAL, PTDB, PIXDEF);
+ friend int CntCloseTable(PGLOBAL, PTDB, bool, bool);
+ friend int CntIndexInit(PGLOBAL, PTDB, int, bool);
+ friend RCODE CntIndexRead(PGLOBAL, PTDB, OPVAL, const key_range*, bool);
+ friend RCODE CntDeleteRow(PGLOBAL, PTDB, bool);
+ friend int CntIndexRange(PGLOBAL, PTDB, const uchar**, uint*,
+ bool*, key_part_map*);
+ friend class ha_connect;
+ TDBDOX() : TDBDOS((PGLOBAL)0, (PTDBDOS)0) {} /* Never called */
+}; // end of class TDBDOX
+
+class XKPDEF: public KPARTDEF {
+ friend class TDBDOX;
+ friend class ha_connect;
+ friend int CntIndexInit(PGLOBAL, PTDB, int, bool);
+ public:
+ XKPDEF(const char *name, int n) : KPARTDEF((PSZ)name, n) {}
+ }; // end of class XKPDEF
+#endif // 0
diff --git a/storage/connect/csort.cpp b/storage/connect/csort.cpp
new file mode 100644
index 00000000..1e4ba674
--- /dev/null
+++ b/storage/connect/csort.cpp
@@ -0,0 +1,966 @@
+/*************** CSort C Program Source Code File (.CPP) ***************/
+/* PROGRAM NAME: CSORT */
+/* ------------- */
+/* Version 2.2 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier Bertrand 1995-2016 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program is the C++ sorting routines that use qsort/insert */
+/* algorithm and produces an offset/break table while sorting. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* csort.cpp - Source code */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* OS2DEF.LIB - OS2 libray definition subset. */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* Microsoft C++ Compiler */
+/* or GNU Compiler/Linker */
+/* or BORLAND 4.5 C++ compiler */
+/* */
+/* NOTE */
+/* ---- */
+/* These functions are not 64-bits ready. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+
+/***********************************************************************/
+/* Include application header files */
+/***********************************************************************/
+#include <stdlib.h> /* C standard library */
+#include <string.h> /* String manipulation declares */
+#include <stdio.h> /* Required for sprintf declare */
+#if defined(_DEBUG)
+#include <assert.h> /* Assertion routine declares */
+#endif
+
+/***********************************************************************/
+/* Include CSort class header file */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h" /* For MBLOCK type definition */
+#include "csort.h" /* CSort class definition */
+#include "osutil.h"
+
+#if !defined(BIGSORT)
+#define BIGSORT 200000
+#endif // !BIGSORT
+
+/***********************************************************************/
+/* DB static external variables. */
+/***********************************************************************/
+extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
+
+/***********************************************************************/
+/* Initialize the CSORT static members. */
+/***********************************************************************/
+int CSORT::Limit = 0;
+double CSORT::Lg2 = log(2.0);
+size_t CSORT::Cpn[1000] = {0}; /* Precalculated cmpnum values */
+
+/***********************************************************************/
+/* CSORT constructor. */
+/***********************************************************************/
+CSORT::CSORT(bool cns, int th, int mth)
+ : Pex((int*&)Index.Memp), Pof((int*&)Offset.Memp)
+ {
+ G = NULL;
+ Dup =NULL;
+ Cons = cns;
+ Thresh = th;
+ Mthresh = mth;
+ Nitem = 0;
+ Index = Nmblk;
+ Offset = Nmblk;
+ Swix = NULL;
+ Savmax = 0;
+ Savcur = 0;
+ Savstep = NULL;
+ } // end of CSORT constructor
+
+/***********************************************************************/
+/* CSORT intialization. */
+/***********************************************************************/
+int CSORT::Qsort(PGLOBAL g, int nb)
+ {
+ int rc;
+
+#if defined(_DEBUG)
+ assert(Index.Size >= nb * sizeof(int));
+#endif
+
+ if (nb > BIGSORT) {
+ G = g;
+ Dup = (PDBUSER)g->Activityp->Aptr;
+
+ if (Dup->Proginfo) {
+ Savstep = Dup->Step;
+ Savmax = Dup->ProgMax;
+ Savcur = Dup->ProgCur;
+
+ // Evaluate the number of comparisons that we will do
+ Dup->ProgMax = Cmpnum(nb);
+ Dup->ProgCur = 0;
+ Dup->Step = (char*)PlugSubAlloc(g, NULL, 32);
+ sprintf((char*)Dup->Step, MSG(SORTING_VAL), nb);
+ } else
+ Dup = NULL;
+
+ } else
+ Dup = NULL;
+
+ Nitem = nb;
+
+ for (int n = 0; n < Nitem; n++)
+ Pex[n] = n;
+
+ rc = (Cons) ? Qsortc() : Qsortx();
+
+ if (Dup) {
+ // Restore any change in progress info settings
+// printf("Progcur=%u\n", Dup->ProgCur);
+
+ Dup->Step = Savstep;
+ Dup->ProgMax = Savmax;
+ Dup->ProgCur = Savcur;
+ } // endif Subcor
+
+ return rc;
+ } // end of QSort
+
+#if defined(DEBTRACE)
+/***********************************************************************/
+/* Debug routine to be used by sort for specific data (dummy as now) */
+/***********************************************************************/
+void CSORT::DebugSort(int ph, int n, int *base, int *mid, int *tmp)
+ {
+ htrc("phase=%d n=%d base=%p mid=%p tmp=%p\n",
+ ph, n, base, mid, tmp);
+ } // end of DebugSort
+#endif
+
+/***********************************************************************/
+/* Qsortx: Version adapted from qsortx.c by O.Bertrand */
+/* This version is specialy adapted for Index sorting, meaning that */
+/* the data is not moved, but the Index only is sorted. */
+/* Index array elements are any 4-byte word (a pointer or a int int */
+/* array index), they are not interpreted except by the user provided */
+/* comparison routine which must works accordingly. */
+/* In addition, this program takes care of data in which there is a */
+/* high rate of repetitions. */
+/* CAUTION: the sort algorithm used here is not conservative. Equal */
+/* values will be internally stored in unpredictable order. */
+/* The THRESHold below is the insertion sort threshold, and also the */
+/* threshold for continuing que quicksort partitioning. */
+/* The MTHREShold is where we stop finding a better median. */
+/* These two quantities should be adjusted dynamically depending upon */
+/* the repetition rate of the data. */
+/* Algorithm used: */
+/* First, set up some global parameters for Qstx to share. Then, */
+/* quicksort with Qstx(), and then a cleanup insertion sort ourselves. */
+/* Sound simple? It's not... */
+/***********************************************************************/
+int CSORT::Qsortx(void)
+ {
+ int c;
+ int lo, hi, min;
+ int i, j, rc = 0;
+ // To do: rc should be checked for being used uninitialized
+ int *top;
+#ifdef DEBTRACE
+ int ncp;
+
+ num_comp = 0;
+#endif
+
+ /*********************************************************************/
+ /* Prepare the Offset array that will be updated during sorts. */
+ /*********************************************************************/
+ if (Pof)
+ for (Pof[Nitem] = Nitem, j = 0; j < Nitem; j++)
+ Pof[j] = 0;
+ else
+ j = Nitem + 1;
+
+ /*********************************************************************/
+ /* Sort on one or zero element is obvious. */
+ /*********************************************************************/
+ if (Nitem <= 1)
+ return Nitem;
+
+ /*********************************************************************/
+ /* Thresh seems to be good as (10 * n / rep). But for testing we */
+ /* set it directly as one parameter of the Xset function call. */
+ /* Note: this should be final as the rep parameter is no more used. */
+ /*********************************************************************/
+ top = Pex + Nitem;
+
+#ifdef DEBTRACE
+ htrc("Qsortx: nitem=%d thresh=%d mthresh=%d\n",
+ Nitem, Thresh, Mthresh);
+#endif
+
+ /*********************************************************************/
+ /* If applicable, do a rough preliminary quick sort. */
+ /*********************************************************************/
+ if (Nitem >= Thresh)
+ Qstx(Pex, top);
+
+#ifdef DEBTRACE
+ htrc(" after quick sort num_comp=%d\n", num_comp);
+ ncp = num_comp;
+ num_comp = 0;
+#ifdef DEBUG2
+ DebugSort((Pof) ? 1 : 4, Nitem, Pex, NULL, NULL);
+#endif
+#endif
+
+ if (Thresh > 2) {
+ if (Pof)
+ /*****************************************************************/
+ /* The preliminary search for the smallest element has been */
+ /* removed so with no sentinel in place, we must check for x */
+ /* going below the Pof pointer. For each remaining element */
+ /* group from [1] to [n-1], set hi to the index of the element */
+ /* AFTER which this one goes. Then, do the standard insertion */
+ /* sort shift on an integer at a time basis for each equal */
+ /* element group in the frob. */
+ /*****************************************************************/
+ for (min = hi = 0; min < Nitem; min = hi) {
+ if (Pof[hi]) {
+ hi += Pof[hi];
+ continue;
+ } // endif Pof
+
+ Pof[min] = 1;
+
+#ifdef DEBUG2
+ htrc("insert from min=%d\n", min);
+#endif
+
+ for (lo = hi; !Pof[++hi]; lo = hi) {
+ while (lo >= min && (rc = Qcompare(Pex + lo, Pex + hi)) > 0)
+ if (Pof[lo] > 0)
+ lo -= Pof[lo];
+ else
+ return -2;
+
+ if (++lo != hi) {
+ c = Pex[hi];
+
+ for (i = j = hi; i > 0; i = j)
+ if (Pof[i - 1] <= 0)
+ return -3;
+ else if ((j -= Pof[i - 1]) >= lo) {
+ Pex[i] = Pex[j];
+ Pof[j + 1] = Pof[i] = Pof[j];
+ } else
+ break;
+
+ Pex[i] = c;
+ } // endif lo
+
+ if (rc)
+ Pof[lo] = 1;
+ else {
+ i = lo - Pof[lo - 1];
+ Pof[lo] = ++Pof[i];
+ } // endelse
+
+#ifdef DEBUG2
+ htrc("rc=%d lo=%d hi=%d trx=%d\n", rc, lo, hi, Pof[lo]);
+#endif
+
+ } // endfor hi
+
+ } // endfor min
+
+ else
+ /*****************************************************************/
+ /* Call conservative insertion sort not using/setting offset. */
+ /*****************************************************************/
+ Istc(Pex, Pex + MY_MIN(Nitem, Thresh), top);
+
+ } // endif Thresh
+
+#ifdef DEBTRACE
+ htrc(" after insert sort num_comp=%d\n", num_comp);
+ num_comp += ncp;
+#endif
+
+ if (Pof)
+ /*******************************************************************/
+ /* Reduce the Offset array. */
+ /*******************************************************************/
+ for (i = j = 0; i <= Nitem; j++, i += c) {
+#ifdef DEBUG2
+ htrc(" trxp(%d)=%d trxp(%d)=%d c=%d\n",
+ i, Pof[i], j, Pof[j], c);
+#endif
+ if ((c = Pof[i]))
+ Pof[j] = i;
+ else
+ return -4;
+
+ } // endfor i
+
+ return (j - 1);
+ } // end of Qsortx
+
+/***********************************************************************/
+/* Qstx: Do a quicksort on index elements (just one int int). */
+/* First, find the median element, and put that one in the first place */
+/* as the discriminator. (This "median" is just the median of the */
+/* first, last and middle elements). (Using this median instead of */
+/* the first element is a big win). Then, the usual partitioning/ */
+/* swapping, followed by moving the discriminator into the right place.*/
+/* Element equal to the discriminator are placed against it, so the */
+/* mid (discriminator) block grows when equal elements exist. This is */
+/* a huge win in case of repartitions with few different elements. */
+/* The mid block being at its final position, its first and last */
+/* elements are marked in the offset list (used to make break list). */
+/* Then, figure out the sizes of the two partitions, do the smaller */
+/* one recursively and the larger one via a repeat of this code. */
+/* Stopping when there are less than THRESH elements in a partition */
+/* and cleaning up with an insertion sort (in our caller) is a huge */
+/* win(?). All data swaps are done in-line, which is space-losing but */
+/* time-saving. (And there are only three places where this is done). */
+/***********************************************************************/
+void CSORT::Qstx(int *base, int *max)
+ {
+ int *i, *j, *jj, *mid, *him, c;
+ int *tmp;
+ int lo, hi, rc;
+ size_t zlo, zhi, cnm;
+
+ zlo = zhi = cnm = 0; // Avoid warning message
+
+ lo = (int)(max - base); // Number of elements as longs
+
+ if (Dup)
+ cnm = Cmpnum(lo);
+
+ do {
+ /*******************************************************************/
+ /* At the top here, lo is the number of integers of elements in */
+ /* the current partition. (Which should be max - base). */
+ /* Find the median of the first, last, and middle element and make */
+ /* that the middle element. Set j to largest of first and middle. */
+ /* If max is larger than that guy, then it's that guy, else */
+ /* compare max with loser of first and take larger. Things are */
+ /* set up to prefer the middle, then the first in case of ties. */
+ /* In addition, hi and rc are set to comparison results. So if hi */
+ /* is null, the two high values are equal and if rc is null, the */
+ /* two low values are equal. This was used to set which test will */
+ /* be made by LE and which one by LT (does not apply anymore). */
+ /*******************************************************************/
+ him = mid = i = base + (lo >> 1);
+ hi = rc = 0;
+
+#ifdef DEBTRACE
+ tmp = max - 1;
+ htrc("--> block base=%d size=%d\n", base - Pex, lo);
+ DebugSort(2, 0, base, mid, tmp);
+#endif
+
+ if (lo >= Mthresh) {
+ rc = Qcompare((jj = base), i);
+ j = (rc > 0) ? jj : i;
+ hi = Qcompare(j, (tmp = max - 1));
+
+ if (hi > 0 && rc) {
+ j = (j == jj) ? i : jj; // switch to first loser
+
+ if ((rc = Qcompare(j, tmp)) < 0)
+ j = tmp;
+
+ } // endif
+
+ if (j != i) {
+ c = *i;
+ *i = *j;
+ *j = c;
+ } // endif j
+
+ } else if (lo == 2) {
+ /*****************************************************************/
+ /* Small group. Do special quicker processing. */
+ /*****************************************************************/
+ if ((rc = Qcompare(base, (him = base + 1))) > 0)
+ c = *base, *base = *him, *him = c;
+
+ if (Pof)
+ Pof[base - Pex] = Pof[him - Pex] = (rc) ? 1 : 2;
+
+ break;
+ } // endif lo
+
+#ifdef DEBTRACE
+ DebugSort(3, hi, NULL, mid, &rc);
+#endif
+
+ /*******************************************************************/
+ /* Semi-standard quicksort partitioning/swapping. Added here is */
+ /* a test on equality. All values equal to the mid element are */
+ /* placed under or over it. Mid block can be also moved when it */
+ /* is necessary because the other partition is full. At the end */
+ /* of the for loop the mid block is definitely positionned. */
+ /*******************************************************************/
+ for (i = base, j = max - 1; ;) {
+ CONT:
+ while (i < mid)
+ if ((rc = Qcompare(i, mid)) < 0)
+ i++;
+ else if (!rc) {
+ c = *i;
+ *i = *(--mid);
+ *mid = c;
+ } else
+ break;
+
+ while (j > him)
+ if ((rc = Qcompare(him, j)) < 0)
+ j--;
+ else if (!rc) {
+ c = *j;
+ *j = *(++him);
+ *him = c;
+ } else if (i == mid) { // Triple move:
+ c = *j; // j goes under mid block
+ *j = *(++him); // val over mid block -> j
+ *him = *mid++; // and mid block goes one
+ *i++ = c; // position higher.
+ } else { // i <-> j
+ c = *i;
+ *i++ = *j;
+ *j-- = c;
+ goto CONT;
+ } // endif's
+
+ if (i == mid)
+ break;
+ else { // Triple move:
+ c = *i; // i goes over mid block
+ *i = *(--mid); // val under mid block -> i
+ *mid = *him--; // and mid block goes one
+ *j-- = c; // position lower.
+ } // endelse
+
+ } // endfor i
+
+ /*******************************************************************/
+ /* The mid block being placed at its final position we can now set */
+ /* the offset array values indicating break point and block size. */
+ /*******************************************************************/
+ j = mid;
+ i = him + 1;
+
+ if (Pof)
+ Pof[him - Pex] = Pof[mid - Pex] = (int)(i - j);
+
+ /*******************************************************************/
+ /* Look at sizes of the two partitions, do the smaller one first */
+ /* by recursion, then do the larger one by making sure lo is its */
+ /* size, base and max are update correctly, and branching back. */
+ /* But only repeat (recursively or by branching) if the partition */
+ /* is of at least size THRESH. */
+ /*******************************************************************/
+ lo = (int)(j - base);
+ hi = (int)(max - i);
+
+ if (Dup) { // Update progress information
+ zlo = Cmpnum(lo);
+ zhi = Cmpnum(hi);
+ Dup->ProgCur += cnm - (zlo + zhi);
+ } // endif Dup
+
+#ifdef DEBTRACE
+ htrc(" done lo=%d sep=%d hi=%d\n", lo, i - j, hi);
+#endif
+
+ if (lo <= hi) {
+ if (lo >= Thresh)
+ Qstx(base, j);
+ else if (lo == 1 && Pof)
+ Pof[base - Pex] = 1;
+
+ base = i;
+ lo = hi;
+ cnm = zhi;
+ } else {
+ if (hi >= Thresh)
+ Qstx(i, max);
+ else if (hi == 1 && Pof)
+ Pof[i - Pex] = 1;
+
+ max = j;
+ cnm = zlo;
+ } // endif
+
+ if (lo == 1 && Pof)
+ Pof[base - Pex] = 1;
+
+ } while (lo >= Thresh); // enddo
+
+ } // end of Qstx
+
+/***********************************************************************/
+/* Qsortc.c: Version adapted from qsort.c by O.Bertrand */
+/* This version is specialy adapted for Index sorting, meaning that */
+/* the data is not moved, but the Index only is sorted. */
+/* Index array elements are any 4-byte word (a pointer or a int int */
+/* array index), they are not interpreted except by the user provided */
+/* comparison routine which must works accordingly. */
+/* In addition, this program takes care of data in which there is a */
+/* high rate of repetitions. */
+/* NOTE: the sort algorithm used here is conservative. Equal and */
+/* greater than values are internally stored in additional work area. */
+/* The THRESHold below is the insertion sort threshold, and also the */
+/* threshold for continuing que quicksort partitioning. */
+/* The MTHREShold is where we stop finding a better median. */
+/* These two quantities should be adjusted dynamically depending upon */
+/* the repetition rate of the data. */
+/* Algorithm used: */
+/* First, set up some global parameters for Qstc to share. Then, */
+/* quicksort with Qstc(), and then a cleanup insertion sort ourselves.*/
+/* Sound simple? It's not... */
+/***********************************************************************/
+int CSORT::Qsortc(void)
+ {
+ int c;
+ int lo, hi, min;
+ int i, j, k, m, rc = 0;
+ // To do: rc should be checked for being used uninitialized
+ int *max;
+#ifdef DEBTRACE
+ int ncp;
+
+ num_comp = 0;
+#endif
+
+ /*********************************************************************/
+ /* Prepare the Offset array that will be updated during sorts. */
+ /*********************************************************************/
+ if (Pof)
+ for (Pof[Nitem] = Nitem, j = 0; j < Nitem; j++)
+ Pof[j] = 0;
+ else
+ j = Nitem + 1;
+
+ /*********************************************************************/
+ /* Sort on one or zero element is obvious. */
+ /*********************************************************************/
+ if (Nitem <= 1)
+ return Nitem;
+
+ /*********************************************************************/
+ /* Thresh seems to be good as (10 * n / rep). But for testing we */
+ /* set it directly as one parameter of the Xset function call. */
+ /* Note: this should be final as the rep parameter is no more used. */
+ /*********************************************************************/
+ max = Pex + Nitem;
+
+#ifdef DEBTRACE
+ htrc("Qsortc: nitem=%d thresh=%d mthresh=%d\n",
+ Nitem, Thresh, Mthresh);
+#endif
+
+ /*********************************************************************/
+ /* If applicable, do a rough preliminary conservative quick sort. */
+ /*********************************************************************/
+ if (Nitem >= Thresh) {
+ if (!(Swix = (int *)malloc(Nitem * sizeof(int))))
+ return -1;
+
+ Qstc(Pex, max);
+
+ free(Swix);
+ Swix = NULL;
+ } // endif n
+
+#ifdef DEBTRACE
+ htrc(" after quick sort num_comp=%d\n", num_comp);
+ ncp = num_comp;
+ num_comp = 0;
+#ifdef DEBUG2
+ DebugSort((Pof) ? 1 : 4, Nitem, Pex, NULL, NULL);
+#endif
+#endif
+
+ if (Thresh > 2) {
+ if (Pof)
+ /*****************************************************************/
+ /* The preliminary search for the smallest element has been */
+ /* removed so with no sentinel in place, we must check for x */
+ /* going below the Pof pointer. For each remaining element */
+ /* group from [1] to [n-1], set hi to the index of the element */
+ /* AFTER which this one goes. Then, do the standard insertion */
+ /* sort shift on an integer at a time basis for each equal */
+ /* element group in the frob. */
+ /*****************************************************************/
+ for (min = hi = 0; min < Nitem; min = hi) {
+ if (Pof[hi]) {
+ hi += Pof[hi];
+ continue;
+ } // endif
+
+ Pof[min] = 1;
+
+#ifdef DEBUG2
+ htrc("insert from min=%d\n", min);
+#endif
+
+ for (lo = hi; !Pof[++hi]; lo = hi) {
+ while (lo >= min && (rc = Qcompare(Pex + lo, Pex + hi)) > 0)
+ if (Pof[lo] > 0)
+ lo -= Pof[lo];
+ else
+ return -2;
+
+ if (++lo != hi) {
+ c = Pex[hi];
+
+ for (i = j = hi; i > 0; i = j)
+ if (Pof[i - 1] <= 0)
+ return -3;
+ else if ((j -= Pof[i - 1]) >= lo) {
+ for (k = m = i; --m >= j; k--) // Move intermediate
+ Pex[k] = Pex[m]; // for conservation.
+
+ Pof[j + 1] = Pof[i] = Pof[j];
+ } else
+ break;
+
+ Pex[i] = c;
+ } // endif
+
+ if (rc)
+ Pof[lo] = 1;
+ else {
+ i = lo - Pof[lo - 1];
+ Pof[lo] = ++Pof[i];
+ } // endelse
+
+#ifdef DEBUG2
+ htrc("rc=%d lo=%d hi=%d ofx=%d\n", rc, lo, hi, Pof[lo]);
+#endif
+
+ } // endfor hi
+
+ } // endfor min
+
+ else
+ /*****************************************************************/
+ /* Call conservative insertion sort not using/setting offset. */
+ /*****************************************************************/
+ Istc(Pex, Pex + MY_MIN(Nitem, Thresh), max);
+
+ } // endif Thresh
+
+#ifdef DEBTRACE
+ htrc(" after insert sort num_comp=%d\n", num_comp);
+ num_comp += ncp;
+#endif
+
+ if (Pof)
+ /*******************************************************************/
+ /* Reduce the Offset array. */
+ /*******************************************************************/
+ for (i = j = 0; i <= Nitem; j++, i += c) {
+#ifdef DEBUG2
+ htrc(" Pof(%d)=%d Pof(%d)=%d c=%d\n",
+ i, Pof[i], j, Pof[j], c);
+#endif
+ if ((c = Pof[i]))
+ Pof[j] = i;
+ else
+ return -4;
+
+ } // endfor i
+
+ return (j - 1);
+ } // end of Qsortc
+
+/***********************************************************************/
+/* Qstc: Do a quicksort on index elements (just one int int). */
+/* First, find the median element, and set it as the discriminator. */
+/* (This "median" is just the median of the first, last and middle */
+/* elements). (Using this median instead of the first element is a */
+/* big win). Then, the special partitioning/swapping, where elements */
+/* smaller than the discriminator are placed in the sorted block, */
+/* elements equal to the discriminator are placed backward from the */
+/* top of the work area and elements greater than *j (discriminator) */
+/* are placed in the work area from its bottom. Then the elements in */
+/* the work area are placed back in the sort area in natural order, */
+/* making the sort conservative. Non equal blocks shrink faster when */
+/* equal elements exist. This is a huge win in case of repartitions */
+/* with few different elements. The mid block being at its final */
+/* position, its first and last elements are marked in the offset */
+/* list (used to make break list). Then, figure out the sizes of the */
+/* two partitions, do the smaller one recursively and the larger one */
+/* via a repeat of this code. Stopping when there are less than */
+/* THRESH elements in a partition and cleaning up with an insertion */
+/* sort (in our caller) is a huge win (yet to be proved?). */
+/***********************************************************************/
+void CSORT::Qstc(int *base, int *max)
+ {
+ int *i, *j, *jj, *lt, *eq, *gt, *mid;
+ int c = 0, lo, hi, rc;
+ size_t zlo, zhi, cnm;
+
+ zlo = zhi = cnm = 0; // Avoid warning message
+
+ lo = (int)(max - base); // Number of elements as longs
+
+ if (Dup)
+ cnm = Cmpnum(lo);
+
+ do {
+ /*******************************************************************/
+ /* At the top here, lo is the number of integers of elements in */
+ /* the current partition. (Which should be max - base). Find the */
+ /* median of the first, last, and middle element and make that */
+ /* the compare element. Set jj to smallest of middle and last. */
+ /* If base is smaller or equal than that guy, then it's that guy, */
+ /* else compare base with loser of first and take smaller. Things */
+ /* are set up to prefer the top, then the middle in case of ties. */
+ /*******************************************************************/
+ i = base + (lo >> 1);
+ jj = mid = max - 1;
+
+#ifdef DEBTRACE
+ htrc("--> block base=%d size=%d\n", base - Pex, lo);
+ DebugSort(2, 0, base, i, mid);
+#endif
+
+ if (lo >= Mthresh) {
+ jj = ((rc = Qcompare(i, mid)) < 0) ? i : mid;
+
+ if (rc && Qcompare(base, jj) > 0) {
+ jj = (jj == mid) ? i : mid; // switch to first loser
+
+ if (Qcompare(base, jj) < 0)
+ jj = base;
+
+ } // endif
+
+ if (jj != mid) {
+ /***************************************************************/
+ /* The compare element must be at the top of the block so it */
+ /* cannot be overwritten while making the partitioning. So */
+ /* save the last block value which will be compared later. */
+ /***************************************************************/
+ c = *mid;
+ *mid = *jj;
+ } // endif
+
+ } else if (lo == 2) {
+ /*****************************************************************/
+ /* Small group. Do special quicker processing. */
+ /*****************************************************************/
+ if ((rc = Qcompare(base, (i = base + 1))) > 0) {
+ c = *base;
+ *base = *i;
+ *i = c;
+ } // endif rc
+
+ if (Pof)
+ Pof[base - Pex] = Pof[i - Pex] = (rc) ? 1 : 2;
+
+ break;
+ } // endif lo
+
+#ifdef DEBTRACE
+ DebugSort(3, lo, NULL, jj, &rc);
+#endif
+
+ /*******************************************************************/
+ /* Non-standard quicksort partitioning using additional storage */
+ /* to store values less than, equal or greater than the middle */
+ /* element. This uses more memory but provides conservation of */
+ /* the equal elements order. */
+ /*******************************************************************/
+ lt = base;
+ eq = Swix + lo;
+ gt = Swix;
+
+ if (jj == mid) {
+ /*****************************************************************/
+ /* Compare element was last. No problem. */
+ /*****************************************************************/
+ for (i = base; i < max; i++)
+ if ((rc = Qcompare(i, mid)) < 0)
+ *lt++ = *i;
+ else if (rc > 0)
+ *gt++ = *i;
+ else
+ *--eq = *i;
+
+ } else {
+ /*****************************************************************/
+ /* Compare element was not last and was copied to top of block. */
+ /*****************************************************************/
+ for (i = base; i < mid; i++)
+ if ((rc = Qcompare(i, mid)) < 0)
+ *lt++ = *i;
+ else if (rc > 0)
+ *gt++ = *i;
+ else
+ *--eq = *i;
+
+ /*****************************************************************/
+ /* Restore saved last value and do the comparison from there. */
+ /*****************************************************************/
+ *--i = c;
+
+ if ((rc = Qcompare(i, mid)) < 0)
+ *lt++ = *i;
+ else if (rc > 0)
+ *gt++ = *i;
+ else
+ *--eq = *i;
+
+ } // endif
+
+ /*******************************************************************/
+ /* Now copy the equal and greater values back in the main array in */
+ /* the same order they have been placed in the work area. */
+ /*******************************************************************/
+ for (j = Swix + lo, i = lt; j > eq; )
+ *i++ = *--j;
+
+ for (j = Swix, jj = i; j < gt; )
+ *i++ = *j++;
+
+ /*******************************************************************/
+ /* The mid block being placed at its final position we can now set */
+ /* the offset array values indicating break point and block size. */
+ /*******************************************************************/
+ if (Pof)
+ Pof[lt - Pex] = Pof[(jj - 1) - Pex] = (int)(jj - lt);
+
+ /*******************************************************************/
+ /* Look at sizes of the two partitions, do the smaller one first */
+ /* by recursion, then do the larger one by making sure lo is its */
+ /* size, base and max are update correctly, and branching back. */
+ /* But only repeat (recursively or by branching) if the partition */
+ /* is of at least size THRESH. */
+ /*******************************************************************/
+ lo = (int)(lt - base);
+ hi = (int)(gt - Swix);
+
+ if (Dup) { // Update progress information
+ zlo = Cmpnum(lo);
+ zhi = Cmpnum(hi);
+ Dup->ProgCur += cnm - (zlo + zhi);
+ } // endif Dup
+
+#ifdef DEBTRACE
+ htrc(" done lo=%d hi=%d\n",
+ lo, /*Swix + lt - base - eq,*/ hi);
+#endif
+
+ if (lo <= hi) {
+ if (lo >= Thresh)
+ Qstc(base, lt);
+ else if (lo == 1 && Pof)
+ Pof[base - Pex] = 1;
+
+ base = jj;
+ lo = hi;
+ cnm = zhi;
+ } else {
+ if (hi >= Thresh)
+ Qstc(jj, max);
+ else if (hi == 1 && Pof)
+ Pof[jj - Pex] = 1;
+
+ max = lt;
+ cnm = zlo;
+ } // endif
+
+ if (lo == 1 && Pof)
+ Pof[base - Pex] = 1;
+
+ } while (lo >= Thresh); // enddo
+
+ } // end of Qstc
+
+/***********************************************************************/
+/* Conservative insertion sort not using/setting offset array. */
+/***********************************************************************/
+void CSORT::Istc(int *base, int *hi, int *max)
+ {
+ int c = 0;
+ int *lo;
+ int *i, *j;
+
+ /*********************************************************************/
+ /* First put smallest element, which must be in the first THRESH, */
+ /* in the first position as a sentinel. This is done just by */
+ /* searching the 1st THRESH elements (or the 1st n if n < THRESH) */
+ /* finding the min, and shifting it into the first position. */
+ /*********************************************************************/
+ for (j = lo = base; ++lo < hi; )
+ if (Qcompare(j, lo) > 0)
+ j = lo;
+
+ if (j != base) { // shift j into place
+ c = *j;
+
+ for (i = j; --j >= base; i = j)
+ *i = *j;
+
+ *base = c;
+ } // endif j
+
+#ifdef DEBTRACE
+ htrc("sentinel %d in place, base=%p hi=%p max=%p\n",
+ c, base, hi, max);
+#endif
+
+ /*********************************************************************/
+ /* With our sentinel in place, we now run the following hyper- */
+ /* fast insertion sort. For each remaining element, lo, from [1] */
+ /* to [n-1], set hi to the index of the element AFTER which this */
+ /* one goes. Then, do the standard insertion sort shift for each */
+ /* element in the frob. */
+ /*********************************************************************/
+ for (lo = base; (hi = ++lo) < max;) {
+ while (Qcompare(--hi, lo) > 0) ;
+
+#ifdef DEBUG2
+ htrc("after while: hi(%p)=%d lo(%p)=%d\n",
+ hi, *hi, lo, *lo);
+#endif
+
+ if (++hi != lo) {
+ c = *lo;
+
+ for (i = j = lo; --j >= hi; i = j)
+ *i = *j;
+
+ *i = c;
+ } // endif hi
+
+ } // endfor lo
+
+ } // end of Istc
+
+/* -------------------------- End of CSort --------------------------- */
diff --git a/storage/connect/csort.h b/storage/connect/csort.h
new file mode 100644
index 00000000..6e700059
--- /dev/null
+++ b/storage/connect/csort.h
@@ -0,0 +1,104 @@
+/*************** Csort H Declares Source Code File (.H) ****************/
+/* Name: CSORT.H Version 1.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2000-2012 */
+/* */
+/* This file contains the CSORT class declares (not 64-bits ready) */
+/* */
+/* Note on use of this class: This class is meant to be used as a */
+/* base class by the calling class. This is because the comparison */
+/* routine must belong to both CSORT and the calling class. */
+/* This avoids to pass explicitly to it the calling "this" pointer. */
+/***********************************************************************/
+#if !defined(CSORT_DEFINED)
+#define CSORT_DEFINED
+
+#include <math.h> /* Required for log function */
+#undef DOMAIN // Was defined in math.h
+
+/***********************************************************************/
+/* Constant and external definitions. */
+/***********************************************************************/
+#define THRESH 4 /* Threshold for insertion (was 4) */
+#define MTHRESH 6 /* Threshold for median */
+
+//extern FILE *debug; /* Debug file */
+
+typedef int* const CPINT;
+
+/***********************************************************************/
+/* This is the CSORT base class declaration. */
+/***********************************************************************/
+class DllExport CSORT {
+ public:
+ // Constructor
+ CSORT(bool cns, int th = THRESH, int mth = MTHRESH);
+ virtual ~CSORT() {}
+ protected:
+ // Implementation
+ /*********************************************************************/
+ /* qsortx/qstx are NOT conservative but use less storage space. */
+ /* qsortc/qstc ARE conservative but use more storage space. */
+ /*********************************************************************/
+ int Qsortx(void); /* Index quick/insert sort */
+ void Qstx(int *base, int *max); /* Preliminary quick sort */
+ int Qsortc(void); /* Conservative q/ins sort */
+ void Qstc(int *base, int *max); /* Preliminary quick sort */
+ void Istc(int *base, int *hi, int *max); /* Insertion sort routine */
+
+ public:
+ // Methods
+ int Qsort(PGLOBAL g, int n); /* Sort calling routine */
+//virtual void Printf(PGLOBAL g, FILE *f, uint n);
+//virtual void Prints(PGLOBAL g, char *ps, uint z);
+#ifdef DEBTRACE
+ int GetNcmp(void) {return num_comp;}
+#endif
+
+ protected:
+ // Overridable
+ virtual int Qcompare(int *, int *) = 0; /* Item compare routine */
+#ifdef DEBTRACE
+ virtual void DebugSort(int ph, int n, int *base, int *mid, int *tmp);
+#endif
+
+ public:
+ // Utility
+ static void SetCmpNum(void)
+ {for (int i = 1; i < 1000; i++) Cpn[i] = Cmpnum(i); Limit = 1000;}
+ protected:
+ static size_t Cmpnum(int n)
+#if defined(AIX)
+ {return (n < Limit) ? Cpn[n]
+ : (size_t)round(1.0 + (double)n * (log2((double)n) - 1.0));}
+#else // !AIX
+ {return (n < Limit) ? Cpn[n]
+ : (size_t)(1.5 + (double)n * (log((double)n)/Lg2 - 1.0));}
+#endif // !AIX
+
+
+ // Members
+ static int Limit; /* Size of precalculated array */
+ static size_t Cpn[1000]; /* Precalculated cmpnum values */
+ static double Lg2; /* Precalculated log(2) value */
+ PGLOBAL G;
+ PDBUSER Dup; /* Used for progress info */
+ bool Cons; /* true for conservative sort */
+ int Thresh; /* Threshold for using qsort */
+ int Mthresh; /* Threshold for median find */
+ int Nitem; /* Number of items to sort */
+ MBLOCK Index; /* Index allocation block */
+ MBLOCK Offset; /* Offset allocation block */
+ CPINT &Pex; /* Reference to sort index */
+ CPINT &Pof; /* Reference to offset array */
+ int *Swix; /* Pointer on EQ/GT work area */
+ int Savmax; /* Saved ProgMax value */
+ int Savcur; /* Saved ProgCur value */
+ LPCSTR Savstep; /* Saved progress step */
+#ifdef DEBTRACE
+ int num_comp; /* Number of quick sort calls */
+#endif
+ }; // end of class CSORT
+
+#endif // CSORT_DEFINED
+
diff --git a/storage/connect/domdoc.cpp b/storage/connect/domdoc.cpp
new file mode 100644
index 00000000..482f0b34
--- /dev/null
+++ b/storage/connect/domdoc.cpp
@@ -0,0 +1,756 @@
+/******************************************************************/
+/* Implementation of XML document processing using MS DOM */
+/* Author: Olivier Bertrand 2007 - 2013 */
+/******************************************************************/
+#include "my_global.h"
+#include <stdio.h>
+#if defined(_WIN32)
+//#include <windows.h>
+#if defined(MSX2)
+#import "msxml2.dll" //Does not exist on Vista
+#elif defined(MSX3)
+#import "msxml3.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
+#elif defined(MSX4)
+#import "msxml4.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
+#elif defined(MSX6)
+#pragma warning(suppress : 4192)
+#import "msxml6.dll" //Causes error C2872: DOMNodeType: ambiguous symbol ??
+#else // MSX4
+#error MSX? is not defined
+#endif // MSX
+using namespace MSXML2;
+#else
+#error This is a Windows implementation only
+#endif
+
+#define NODE_TYPE_LIST
+
+#include "global.h"
+#include "plgdbsem.h"
+#include "xobject.h"
+#include "domdoc.h"
+
+inline bool TestHr(PGLOBAL g, HRESULT hr)
+ {
+ if FAILED(hr) {
+ sprintf(g->Message, "%s, hr=%d", MSG(COM_ERROR), hr);
+ return true;
+ } else
+ return false;
+
+ } // end of TestHr
+
+/******************************************************************/
+/* Return a DOMDOC as a XMLDOC. */
+/******************************************************************/
+PXDOC GetDomDoc(PGLOBAL g, char *nsl, char *nsdf,
+ char *enc, PFBLOCK fp)
+ {
+ return (PXDOC) new(g) DOMDOC(nsl, nsdf, enc, fp);
+ } // end of GetDomDoc
+
+/***********************************************************************/
+/* Close a loaded DOM XML file. */
+/***********************************************************************/
+void CloseXMLFile(PGLOBAL g, PFBLOCK fp, bool all)
+ {
+ PXBLOCK xp = (PXBLOCK)fp;
+
+ if (xp && xp->Count > 1 && !all) {
+ xp->Count--;
+ } else if (xp && xp->Count > 0) {
+ try {
+ if (xp->Docp)
+ xp->Docp->Release();
+
+ } catch(_com_error e) {
+ char *p = _com_util::ConvertBSTRToString(e.Description());
+ sprintf(g->Message, "%s %s", MSG(COM_ERROR), p);
+ delete[] p;
+ } catch(...) {}
+
+ CoUninitialize();
+ xp->Count = 0;
+ } // endif
+
+ } // end of CloseXMLFile
+
+/* ------------------------ class DOMDOC ------------------------ */
+
+/******************************************************************/
+/* DOMDOC constructor. */
+/******************************************************************/
+DOMDOC::DOMDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp)
+ : XMLDOCUMENT(nsl, nsdf, enc)
+ {
+ assert (!fp || fp->Type == TYPE_FB_XML);
+ Docp = (fp) ? ((PXBLOCK)fp)->Docp : (MSXML2::IXMLDOMDocumentPtr)NULL;
+ Nlist = NULL;
+ Hr = 0;
+ } // end of DOMDOC constructor
+
+/******************************************************************/
+/* Initialize XML parser and check library compatibility. */
+/******************************************************************/
+bool DOMDOC::Initialize(PGLOBAL g, PCSZ entry, bool zipped)
+{
+ if (zipped && InitZip(g, entry))
+ return true;
+
+ if (TestHr(g, CoInitialize(NULL)))
+ return true;
+
+ if (TestHr(g, Docp.CreateInstance("msxml2.domdocument")))
+ return true;
+
+ return MakeNSlist(g);
+} // end of Initialize
+
+/******************************************************************/
+/* Parse the XML file and construct node tree in memory. */
+/******************************************************************/
+bool DOMDOC::ParseFile(PGLOBAL g, char *fn)
+{
+ bool b;
+
+ Docp->async = false;
+
+ if (zip) {
+ // Parse an in memory document
+ char *xdoc = GetMemDoc(g, fn);
+
+ // This is not equivalent to load for UTF8 characters
+ // It is why get node content is not the same
+ b = (xdoc) ? (bool)Docp->loadXML((_bstr_t)xdoc) : false;
+ } else
+ // Load the document
+ b = (bool)Docp->load((_bstr_t)fn);
+
+ if (!b)
+ return true;
+
+ return false;
+} // end of ParseFile
+
+/******************************************************************/
+/* Create or reuse an Xblock for this document. */
+/******************************************************************/
+PFBLOCK DOMDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
+ {
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+ PXBLOCK xp = (PXBLOCK)PlugSubAlloc(g, NULL, sizeof(XBLOCK));
+
+ memset(xp, 0, sizeof(XBLOCK));
+ xp->Next = (PXBLOCK)dup->Openlist;
+ dup->Openlist = (PFBLOCK)xp;
+ xp->Type = TYPE_FB_XML;
+ xp->Fname = (LPCSTR)PlugSubAlloc(g, NULL, strlen(fn) + 1);
+ strcpy((char*)xp->Fname, fn);
+ xp->Count = 1;
+ xp->Length = (m == MODE_READ) ? 1 : 0;
+ xp->Docp = Docp;
+ xp->Retcode = rc;
+
+ // Return xp as a fp
+ return (PFBLOCK)xp;
+ } // end of LinkXblock
+
+/******************************************************************/
+/* Create the XML node. */
+/******************************************************************/
+bool DOMDOC::NewDoc(PGLOBAL g, PCSZ ver)
+ {
+ char buf[64];
+ MSXML2::IXMLDOMProcessingInstructionPtr pip;
+
+ sprintf(buf, "version=\"%s\" encoding=\"%s\"", ver, Encoding);
+ pip = Docp->createProcessingInstruction("xml", buf);
+ return(TestHr(g, Docp->appendChild(pip)));
+ } // end of NewDoc
+
+/******************************************************************/
+/* Add a comment to the document node. */
+/******************************************************************/
+void DOMDOC::AddComment(PGLOBAL g, char *com)
+ {
+ TestHr(g, Docp->appendChild(Docp->createComment(com)));
+ } // end of AddComment
+
+/******************************************************************/
+/* Return the node class of the root of the document. */
+/******************************************************************/
+PXNODE DOMDOC::GetRoot(PGLOBAL g)
+ {
+ MSXML2::IXMLDOMElementPtr root = Docp->documentElement;
+
+ if (root == NULL)
+ return NULL;
+
+ return new(g) DOMNODE(this, root);
+ } // end of GetRoot
+
+/******************************************************************/
+/* Create a new root element and return its class node. */
+/******************************************************************/
+PXNODE DOMDOC::NewRoot(PGLOBAL g, char *name)
+ {
+ MSXML2::IXMLDOMElementPtr ep = Docp->createElement(name);
+
+ if (ep == NULL || TestHr(g, Docp->appendChild(ep)))
+ return NULL;
+
+ return new(g) DOMNODE(this, ep);
+ } // end of NewRoot
+
+/******************************************************************/
+/* Return a void DOMNODE node class. */
+/******************************************************************/
+PXNODE DOMDOC::NewPnode(PGLOBAL g, char *name)
+ {
+ MSXML2::IXMLDOMElementPtr root = NULL;
+
+ if (name)
+ if ((root = Docp->createElement(name)) == NULL)
+ return NULL;
+
+ return new(g) DOMNODE(this, root);
+ } // end of NewPnode
+
+/******************************************************************/
+/* Return a void DOMATTR node class. */
+/******************************************************************/
+PXATTR DOMDOC::NewPattr(PGLOBAL g)
+ {
+ return new(g) DOMATTR(this, NULL);
+ } // end of NewPattr
+
+/******************************************************************/
+/* Return a void DOMATTR node class. */
+/******************************************************************/
+PXLIST DOMDOC::NewPlist(PGLOBAL g)
+ {
+ return new(g) DOMNODELIST(this, NULL);
+ } // end of NewPlist
+
+/******************************************************************/
+/* Dump the node tree to a new XML file. */
+/******************************************************************/
+int DOMDOC::DumpDoc(PGLOBAL g, char *ofn)
+ {
+ int rc = 0;
+
+ try {
+ Docp->save(ofn);
+ } catch(_com_error e) {
+ sprintf(g->Message, "%s: %s", MSG(COM_ERROR),
+ _com_util::ConvertBSTRToString(e.Description()));
+ rc = -1;
+ } catch(...) {}
+
+ return rc;
+ } // end of Dump
+
+/******************************************************************/
+/* Free the document, cleanup the XML library, and */
+/* debug memory for regression tests. */
+/******************************************************************/
+void DOMDOC::CloseDoc(PGLOBAL g, PFBLOCK xp)
+ {
+ CloseXMLFile(g, xp, false);
+ CloseZip();
+ } // end of Close
+
+/* ----------------------- class DOMNODE ------------------------ */
+
+/******************************************************************/
+/* DOMNODE constructor. */
+/******************************************************************/
+DOMNODE::DOMNODE(PXDOC dp, MSXML2::IXMLDOMNodePtr np) : XMLNODE(dp)
+ {
+ Docp = ((PDOMDOC)dp)->Docp;
+ Nodep = np;
+ Ws = NULL;
+ Len = 0;
+ Zip = (bool)dp->zip;
+ } // end of DOMNODE constructor
+
+/******************************************************************/
+/* Return the node name. */
+/******************************************************************/
+char *DOMNODE::GetName(PGLOBAL g)
+ {
+ if (!WideCharToMultiByte(CP_ACP, 0, Nodep->nodeName, -1,
+ Name, sizeof(Name), NULL, NULL)) {
+ strcpy(g->Message, MSG(NAME_CONV_ERR));
+ return NULL;
+ } // endif
+
+ return Name;
+ } // end of GetName
+
+/******************************************************************/
+/* Return the node class of next sibling of the node. */
+/******************************************************************/
+PXNODE DOMNODE::GetNext(PGLOBAL g)
+ {
+ if (Nodep->nextSibling == NULL)
+ Next = NULL;
+ else // if (!Next)
+ Next = new(g) DOMNODE(Doc, Nodep->nextSibling);
+
+ return Next;
+ } // end of GetNext
+
+/******************************************************************/
+/* Return the node class of first children of the node. */
+/******************************************************************/
+PXNODE DOMNODE::GetChild(PGLOBAL g)
+ {
+ if (Nodep->firstChild == NULL)
+ Children = NULL;
+ else // if (!Children)
+ Children = new(g) DOMNODE(Doc, Nodep->firstChild);
+
+ return Children;
+ } // end of GetChild
+
+/******************************************************************/
+/* Return the content of a node and subnodes. */
+/******************************************************************/
+RCODE DOMNODE::GetContent(PGLOBAL g, char *buf, int len)
+ {
+ RCODE rc = RC_OK;
+
+ // Nodep can be null for a missing HTML table column
+ if (Nodep) {
+ if (Zip) {
+ strcpy(buf, Nodep->text);
+ } else if (!WideCharToMultiByte(CP_UTF8, 0, Nodep->text, -1,
+ buf, len, NULL, NULL)) {
+ DWORD lsr = GetLastError();
+
+ switch (lsr) {
+ case 0:
+ case ERROR_INSUFFICIENT_BUFFER: // 122L
+ sprintf(g->Message, "Truncated %s content", GetName(g));
+ rc = RC_INFO;
+ break;
+ case ERROR_NO_UNICODE_TRANSLATION: // 1113L
+ sprintf(g->Message, "Invalid character(s) in %s content",
+ GetName(g));
+ rc = RC_INFO;
+ break;
+ default:
+ sprintf(g->Message, "System error getting %s content",
+ GetName(g));
+ rc = RC_FX;
+ break;
+ } // endswitch
+
+ } // endif
+
+ } else
+ *buf = '\0';
+
+ return rc;
+ } // end of GetContent
+
+/******************************************************************/
+/* Set the text content of an attribute. */
+/******************************************************************/
+bool DOMNODE::SetContent(PGLOBAL g, char *txtp, int len)
+ {
+ bool rc;
+ BSTR val;
+
+ if (len > Len || !Ws) {
+ Ws = (WCHAR*)PlugSubAlloc(g, NULL, (len + 1) * 2);
+ Len = len;
+ } // endif len
+
+ if (!MultiByteToWideChar(CP_UTF8, 0, txtp, strlen(txtp) + 1,
+ Ws, Len + 1)) {
+ sprintf(g->Message, MSG(WS_CONV_ERR), txtp);
+ return true;
+ } // endif
+
+ val = SysAllocString(Ws);
+ rc = TestHr(g, Nodep->put_text(val));
+ SysFreeString(val);
+ return rc;
+ } // end of SetContent
+
+/******************************************************************/
+/* Return a clone of this node. */
+/******************************************************************/
+PXNODE DOMNODE::Clone(PGLOBAL g, PXNODE np)
+ {
+ if (np) {
+ ((PDOMNODE)np)->Nodep = Nodep;
+ return np;
+ } else
+ return new(g) DOMNODE(Doc, Nodep);
+
+ } // end of Clone
+
+/******************************************************************/
+/* Return the list of all or matching children that are elements.*/
+/******************************************************************/
+PXLIST DOMNODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp)
+ {
+ MSXML2::IXMLDOMNodeListPtr dnlp;
+
+ if (xp) {
+ if (Nodep->nodeType == MSXML2::NODE_ELEMENT) {
+ MSXML2::IXMLDOMElementPtr ep = Nodep;
+ dnlp = ep->getElementsByTagName(xp);
+ } else
+ return NULL;
+
+ } else
+ dnlp = Nodep->childNodes;
+
+ if (lp) {
+ ((PDOMLIST)lp)->Listp = dnlp;
+ return lp;
+ } else
+ return new(g) DOMNODELIST(Doc, dnlp);
+
+ } // end of GetChildElements
+
+/******************************************************************/
+/* Return the list of nodes verifying the passed Xapth. */
+/******************************************************************/
+PXLIST DOMNODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp)
+ {
+ MSXML2::IXMLDOMNodeListPtr dnlp = Nodep->selectNodes(xp);
+
+ if (lp) {
+ ((PDOMLIST)lp)->Listp = dnlp;
+ return lp;
+ } else
+ return new(g) DOMNODELIST(Doc, dnlp);
+
+ } // end of SelectNodes
+
+/******************************************************************/
+/* Return the first node verifying the passed Xapth. */
+/******************************************************************/
+PXNODE DOMNODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np)
+ {
+ try {
+ MSXML2::IXMLDOMNodePtr dnp = Nodep->selectSingleNode(xp);
+
+ if (dnp) {
+ if (np) {
+ ((PDOMNODE)np)->Nodep = dnp;
+ return np;
+ } else
+ return new(g) DOMNODE(Doc, dnp);
+
+ } // endif dnp
+
+ } catch(_com_error e) {
+ sprintf(g->Message, "%s: %s", MSG(COM_ERROR),
+ _com_util::ConvertBSTRToString(e.Description()));
+ } catch(...) {}
+
+ return NULL;
+ } // end of SelectSingleNode
+
+/******************************************************************/
+/* Return the node attribute with the specified name. */
+/******************************************************************/
+PXATTR DOMNODE::GetAttribute(PGLOBAL g, char *name, PXATTR ap)
+ {
+ MSXML2::IXMLDOMElementPtr ep;
+ MSXML2::IXMLDOMNamedNodeMapPtr nmp;
+ MSXML2::IXMLDOMAttributePtr atp;
+
+ if (name) {
+ ep = Nodep;
+ atp = ep->getAttributeNode(name);
+ nmp = NULL;
+ } else {
+ nmp = Nodep->Getattributes();
+ atp = nmp->Getitem(0);
+ } // endif name
+
+ if (atp) {
+ if (ap) {
+ ((PDOMATTR)ap)->Atrp = atp;
+ ((PDOMATTR)ap)->Nmp = nmp;
+ ((PDOMATTR)ap)->K = 0;
+ return ap;
+ } else
+ return new(g) DOMATTR(Doc, atp, nmp);
+
+ } else
+ return NULL;
+
+ } // end of GetAttribute
+
+/******************************************************************/
+/* Add a new element child node to this node and return it. */
+/******************************************************************/
+PXNODE DOMNODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np)
+ {
+ const char *p, *pn;
+// char *p, *pn, *epf, *pf = NULL;
+ MSXML2::IXMLDOMNodePtr ep;
+// _bstr_t uri((wchar_t*)NULL);
+
+#if 0
+ // Is a prefix specified ?
+ if ((p = strchr(name, ':'))) {
+ pf = BufAlloc(g, name, p - name);
+
+ // Is it the pseudo default prefix
+ if (Doc->DefNs && !strcmp(pf, Doc->DefNs)) {
+ name = p + 1; // Suppress it from name
+ pf = NULL; // No real prefix
+ } // endif DefNs
+
+ } // endif p
+
+ // Look for matching namespace URI in context
+ for (ep = Nodep; ep; ep = ep->parentNode) {
+ epf = (_bstr_t)ep->prefix;
+
+ if ((!pf && !epf) || (pf && epf && !strcmp(pf, epf))) {
+ uri = Nodep->namespaceURI;
+ break;
+ } // endif
+
+ } // endfor ep
+
+ if ((wchar_t*)uri == NULL) {
+ if (!pf)
+ pf = Doc->DefNs;
+
+ // Look for the namespace URI corresponding to this node
+ if (pf)
+ for (PNS nsp = Doc->Namespaces; nsp; nsp = nsp->Next)
+ if (!strcmp(pf, nsp->Prefix)) {
+ uri = nsp->Uri;
+ break;
+ } // endfor nsp
+
+ } // endif pns
+#endif // 0
+
+ // If name has the format m[n] only m is taken as node name
+ if ((p = strchr(name, '[')))
+ pn = BufAlloc(g, name, (int)(p - name));
+ else
+ pn = name;
+
+ // Construct the element node with eventual namespace
+// ep = Docp->createNode(_variant_t("Element"), pn, uri);
+ ep = Docp->createElement(pn);
+
+ _bstr_t pfx = ep->prefix;
+ _bstr_t uri = ep->namespaceURI;
+
+ if (ep == NULL || TestHr(g, Nodep->appendChild(ep)))
+ return NULL;
+
+ if (np)
+ ((PDOMNODE)np)->Nodep = ep;
+ else
+ np = new(g) DOMNODE(Doc, ep);
+
+ return NewChild(np);
+ } // end of AddChildNode
+
+/******************************************************************/
+/* Add a new property to this node and return it. */
+/******************************************************************/
+PXATTR DOMNODE::AddProperty(PGLOBAL g, char *name, PXATTR ap)
+ {
+ MSXML2::IXMLDOMAttributePtr atp = Docp->createAttribute(name);
+
+ if (atp) {
+ MSXML2::IXMLDOMElementPtr ep = Nodep;
+ ep->setAttributeNode(atp);
+
+ if (ap) {
+ ((PDOMATTR)ap)->Atrp = atp;
+ return ap;
+ } else
+ return new(g) DOMATTR(Doc, atp);
+
+ } else
+ return NULL;
+
+ } // end of AddProperty
+
+/******************************************************************/
+/* Add a new text node to this node. */
+/******************************************************************/
+void DOMNODE::AddText(PGLOBAL g, PCSZ txtp)
+ {
+ MSXML2::IXMLDOMTextPtr tp= Docp->createTextNode((_bstr_t)txtp);
+
+ if (tp != NULL)
+ TestHr(g, Nodep->appendChild(tp));
+
+ } // end of AddText
+
+/******************************************************************/
+/* Remove a child node from this node. */
+/******************************************************************/
+void DOMNODE::DeleteChild(PGLOBAL g, PXNODE dnp)
+ {
+ TestHr(g, Nodep->removeChild(((PDOMNODE)dnp)->Nodep));
+// ((PDOMNODE)dnp)->Nodep->Release(); bad idea, causes a crash
+ Delete(dnp);
+ } // end of DeleteChild
+
+/* --------------------- class DOMNODELIST ---------------------- */
+
+/******************************************************************/
+/* DOMNODELIST constructor. */
+/******************************************************************/
+DOMNODELIST::DOMNODELIST(PXDOC dp, MSXML2::IXMLDOMNodeListPtr lp)
+ : XMLNODELIST(dp)
+ {
+ Listp = lp;
+ } // end of DOMNODELIST constructor
+
+/******************************************************************/
+/* Return the nth element of the list. */
+/******************************************************************/
+PXNODE DOMNODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
+ {
+ if (Listp == NULL || Listp->length <= n)
+ return NULL;
+
+ if (np) {
+ ((PDOMNODE)np)->Nodep = Listp->item[n];
+ return np;
+ } else
+ return new(g) DOMNODE(Doc, Listp->item[n]);
+
+ } // end of GetItem
+
+/******************************************************************/
+/* Reset the pointer on the deleted item. */
+/******************************************************************/
+bool DOMNODELIST::DropItem(PGLOBAL g, int n)
+{
+ if (Listp == NULL || Listp->length < n)
+ return true;
+
+//Listp->item[n] = NULL; La propriété n'a pas de méthode 'set'
+ return false;
+} // end of DeleteItem
+
+/* ----------------------- class DOMATTR ------------------------ */
+
+/******************************************************************/
+/* DOMATTR constructor. */
+/******************************************************************/
+DOMATTR::DOMATTR(PXDOC dp, MSXML2::IXMLDOMAttributePtr ap,
+ MSXML2::IXMLDOMNamedNodeMapPtr nmp)
+ : XMLATTRIBUTE(dp)
+ {
+ Atrp = ap;
+ Nmp = nmp;
+ Ws = NULL;
+ Len = 0;
+ K = 0;
+ } // end of DOMATTR constructor
+
+/******************************************************************/
+/* Return the attribute name. */
+/******************************************************************/
+char *DOMATTR::GetName(PGLOBAL g)
+ {
+ if (!WideCharToMultiByte(CP_ACP, 0, Atrp->nodeName, -1,
+ Name, sizeof(Name), NULL, NULL)) {
+ strcpy(g->Message, MSG(NAME_CONV_ERR));
+ return NULL;
+ } // endif
+
+ return Name;
+ } // end of GetName
+
+/******************************************************************/
+/* Return the next attribute node. */
+/* This funtion is implemented as needed by XMLColumns. */
+/******************************************************************/
+PXATTR DOMATTR::GetNext(PGLOBAL g)
+ {
+ if (!Nmp)
+ return NULL;
+
+ if (++K >= Nmp->Getlength()) {
+ Nmp->reset();
+ Nmp = NULL;
+ K = 0;
+ return NULL;
+ } // endif K
+
+ Atrp = Nmp->Getitem(K);
+ return this;
+ } // end of GetNext
+
+/******************************************************************/
+/* Return the content of a node and subnodes. */
+/******************************************************************/
+RCODE DOMATTR::GetText(PGLOBAL g, char *buf, int len)
+ {
+ RCODE rc = RC_OK;
+
+ if (!WideCharToMultiByte(CP_UTF8, 0, Atrp->text, -1,
+ buf, len, NULL, NULL)) {
+ DWORD lsr = GetLastError();
+
+ switch (lsr) {
+ case 0:
+ case ERROR_INSUFFICIENT_BUFFER: // 122L
+ sprintf(g->Message, "Truncated %s content", GetName(g));
+ rc = RC_INFO;
+ break;
+ case ERROR_NO_UNICODE_TRANSLATION: // 1113L
+ sprintf(g->Message, "Invalid character(s) in %s content",
+ GetName(g));
+ rc = RC_INFO;
+ break;
+ default:
+ sprintf(g->Message, "System error getting %s content",
+ GetName(g));
+ rc = RC_FX;
+ break;
+ } // endswitch
+
+ } // endif
+
+ return rc;
+ } // end of GetText
+
+/******************************************************************/
+/* Set the text content of an attribute. */
+/******************************************************************/
+bool DOMATTR::SetText(PGLOBAL g, char *txtp, int len)
+ {
+ bool rc;
+ BSTR val;
+
+ if (len > Len || !Ws) {
+ Ws = (WCHAR*)PlugSubAlloc(g, NULL, (len + 1) * 2);
+ Len = len;
+ } // endif len
+
+ if (!MultiByteToWideChar(CP_UTF8, 0, txtp, strlen(txtp) + 1,
+ Ws, Len + 1)) {
+ sprintf(g->Message, MSG(WS_CONV_ERR), txtp);
+ return true;
+ } // endif
+
+ val = SysAllocString(Ws);
+ rc = TestHr(g, Atrp->put_text(val));
+ SysFreeString(val);
+ return rc;
+ } // end of SetText
diff --git a/storage/connect/domdoc.h b/storage/connect/domdoc.h
new file mode 100644
index 00000000..dd893609
--- /dev/null
+++ b/storage/connect/domdoc.h
@@ -0,0 +1,146 @@
+/******************************************************************/
+/* Declaration of XML document processing using MS DOM */
+/* Author: Olivier Bertrand 2007 - 2012 */
+/******************************************************************/
+#include "plgxml.h"
+
+typedef class DOMDOC *PDOMDOC;
+typedef class DOMNODE *PDOMNODE;
+typedef class DOMATTR *PDOMATTR;
+typedef class DOMNODELIST *PDOMLIST;
+
+/******************************************************************/
+/* XML block. Must have the same layout than FBLOCK up to Type. */
+/******************************************************************/
+typedef struct _xblock { /* Loaded XML file block */
+ struct _xblock *Next;
+ LPCSTR Fname; /* Point on file name */
+ size_t Length; /* Used to tell if read mode */
+ short Count; /* Nb of times file is used */
+ short Type; /* TYPE_FB_XML */
+ int Retcode; /* Return code from Load */
+ MSXML2::IXMLDOMDocumentPtr Docp;/* Document interface pointer */
+ } XBLOCK, *PXBLOCK;
+
+/******************************************************************/
+/* Declaration of DOM document. */
+/******************************************************************/
+class DOMDOC : public XMLDOCUMENT {
+ friend class DOMNODE;
+ public:
+ // Constructor
+ DOMDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp);
+
+ // Properties
+ virtual short GetDocType(void) {return TYPE_FB_XML;}
+ virtual void *GetDocPtr(void) {return Docp;}
+ virtual void SetNofree(bool b) {} // Only libxml2
+
+ // Methods
+ virtual bool Initialize(PGLOBAL g, PCSZ entry, bool zipped);
+ virtual bool ParseFile(PGLOBAL g, char *fn);
+ virtual bool NewDoc(PGLOBAL g, PCSZ ver);
+ virtual void AddComment(PGLOBAL g, char *com);
+ virtual PXNODE GetRoot(PGLOBAL g);
+ virtual PXNODE NewRoot(PGLOBAL g, char *name);
+ virtual PXNODE NewPnode(PGLOBAL g, char *name);
+ virtual PXATTR NewPattr(PGLOBAL g);
+ virtual PXLIST NewPlist(PGLOBAL g);
+ virtual int DumpDoc(PGLOBAL g, char *ofn);
+ virtual void CloseDoc(PGLOBAL g, PFBLOCK xp);
+ virtual PFBLOCK LinkXblock(PGLOBAL g, MODE m, int rc, char *fn);
+
+ protected:
+ // Members
+ MSXML2::IXMLDOMDocumentPtr Docp;
+ MSXML2::IXMLDOMNodeListPtr Nlist;
+ HRESULT Hr;
+}; // end of class DOMDOC
+
+/******************************************************************/
+/* Declaration of DOM XML node. */
+/******************************************************************/
+class DOMNODE : public XMLNODE {
+ friend class DOMDOC;
+ friend class DOMNODELIST;
+ public:
+ // Properties
+ virtual char *GetName(PGLOBAL g);
+ virtual int GetType(void) {return Nodep->nodeType;}
+ virtual PXNODE GetNext(PGLOBAL g);
+ virtual PXNODE GetChild(PGLOBAL g);
+
+ // Methods
+ virtual RCODE GetContent(PGLOBAL g, char *buf, int len);
+ virtual bool SetContent(PGLOBAL g, char *txtp, int len);
+ virtual PXNODE Clone(PGLOBAL g, PXNODE np);
+ virtual PXLIST GetChildElements(PGLOBAL g, char *xp, PXLIST lp);
+ virtual PXLIST SelectNodes(PGLOBAL g, char *xp, PXLIST lp);
+ virtual PXNODE SelectSingleNode(PGLOBAL g, char *xp, PXNODE np);
+ virtual PXATTR GetAttribute(PGLOBAL g, char *name, PXATTR ap);
+ virtual PXNODE AddChildNode(PGLOBAL g, PCSZ name, PXNODE np);
+ virtual PXATTR AddProperty(PGLOBAL g, char *name, PXATTR ap);
+ virtual void AddText(PGLOBAL g, PCSZ txtp);
+ virtual void DeleteChild(PGLOBAL g, PXNODE dnp);
+
+ protected:
+ // Constructor
+ DOMNODE(PXDOC dp, MSXML2::IXMLDOMNodePtr np);
+
+ // Members
+ MSXML2::IXMLDOMDocumentPtr Docp;
+ MSXML2::IXMLDOMNodePtr Nodep;
+ char Name[64];
+ WCHAR *Ws;
+ int Len;
+ bool Zip;
+}; // end of class DOMNODE
+
+/******************************************************************/
+/* Declaration of DOM XML node list. */
+/******************************************************************/
+class DOMNODELIST : public XMLNODELIST {
+ friend class DOMDOC;
+ friend class DOMNODE;
+ public:
+ // Methods
+ virtual int GetLength(void) {return Listp->length;}
+ virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np);
+ virtual bool DropItem(PGLOBAL g, int n);
+
+ protected:
+ // Constructor
+ DOMNODELIST(PXDOC dp, MSXML2::IXMLDOMNodeListPtr lp);
+
+ // Members
+ MSXML2::IXMLDOMNodeListPtr Listp;
+}; // end of class DOMNODELIST
+
+/******************************************************************/
+/* Declaration of DOM XML attribute. */
+/******************************************************************/
+class DOMATTR : public XMLATTRIBUTE {
+ friend class DOMDOC;
+ friend class DOMNODE;
+ public:
+ // Properties
+ virtual char *GetName(PGLOBAL g);
+ virtual PXATTR GetNext(PGLOBAL);
+
+ // Methods
+ virtual RCODE GetText(PGLOBAL g, char *bufp, int len);
+ virtual bool SetText(PGLOBAL g, char *txtp, int len);
+
+ protected:
+ // Constructor
+ DOMATTR(PXDOC dp, MSXML2::IXMLDOMAttributePtr ap,
+ MSXML2::IXMLDOMNamedNodeMapPtr nmp = NULL);
+
+ // Members
+ MSXML2::IXMLDOMAttributePtr Atrp;
+ MSXML2::IXMLDOMNamedNodeMapPtr Nmp;
+ char Name[64];
+ WCHAR *Ws;
+ int Len;
+ long K;
+}; // end of class DOMATTR
diff --git a/storage/connect/encas.h b/storage/connect/encas.h
new file mode 100644
index 00000000..37e97f21
--- /dev/null
+++ b/storage/connect/encas.h
@@ -0,0 +1,320 @@
+ case MSG_ACCESS_VIOLATN: p = "Access violation"; break;
+ case MSG_ADD_BAD_TYPE: p = "Array add value type mismatch (%s -> %s)"; break;
+ case MSG_ALLOC_ERROR: p = "Error allocating %s"; break;
+ case MSG_ANSWER_TYPE: p = "Answer of type"; break;
+ case MSG_API_CONF_ERROR: p = "SQL Error: API_CONFORMANCE"; break;
+ case MSG_APPL_NOT_INIT: p = "Application not initialized"; break;
+ case MSG_ARRAY_BNDS_EXCD: p = "Array bounds exceeded"; break;
+ case MSG_BAD_ARRAY_OPER: p = "Arrays must be used with the IN operator"; break;
+ case MSG_BAD_ARRAY_TYPE: p = "Illegal array type %d"; break;
+ case MSG_BAD_ARRAY_VAL: p = "Arrays must have the same number of values"; break;
+ case MSG_BAD_BIN_FMT: p = "Invalid format %c for the %s BIN column"; break;
+ case MSG_BAD_BLK_ESTIM: p = "Number of blocks exceeds estimate"; break;
+ case MSG_BAD_BLK_SIZE: p = "No match in block %d size"; break;
+ case MSG_BAD_BYTE_NUM: p = "bad number of bytes written"; break;
+ case MSG_BAD_BYTE_READ: p = "bad number of bytes read"; break;
+ case MSG_BAD_COL_TYPE: p = "Invalid type %s for column %s"; break;
+ case MSG_BAD_COL_XPATH: p = "Invalid Xpath in column %s for HTML table %s"; break;
+ case MSG_BAD_CONST_TYPE: p = "Bad constant type=%d"; break;
+ case MSG_BAD_CONV_TYPE: p = "Invalid convert type %d"; break;
+ case MSG_BAD_DATETIME: p = "Invalid datetime value"; break;
+ case MSG_BAD_DBF_FILE: p = "DBF file %s is corrupted"; break;
+ case MSG_BAD_DBF_REC: p = "DBF file %s corrupted at record %d"; break;
+ case MSG_BAD_DBF_TYPE: p = "Unsupported DBF type %c for column %s"; break;
+ case MSG_BAD_DIRECTORY: p = "Bad directory %s: %s"; break;
+ case MSG_BAD_FIELD_RANK: p = "Invalid field rank %d for column %s"; break;
+ case MSG_BAD_FIELD_TYPE: p = "Bad type field %s"; break;
+ case MSG_BAD_FILE_HANDLE: p = "Invalid File Handle: %s"; break;
+ case MSG_BAD_FILTER: p = "Bad filter: Opc=%d B_T=%d %d Type=%d %d"; break;
+ case MSG_BAD_FILTER_CONV: p = "Bad filter conversion, B_T=%d,%d"; break;
+ case MSG_BAD_FILTER_OP: p = "Invalid filter operator %d"; break;
+ case MSG_BAD_FLD_FORMAT: p = "Bad format for field %d of %s"; break;
+ case MSG_BAD_FLD_LENGTH: p = "Field %s too long (%s --> %d) line %d of %s"; break;
+ case MSG_BAD_FREQ_SET: p = "Bad frequency setting for column %s"; break;
+ case MSG_BAD_FUNC_MODE: p = "%s: invalid mode %d"; break;
+ case MSG_BAD_HANDLE_VAL: p = "Invalid handle value"; break;
+ case MSG_BAD_HEADER: p = "File %s: Header corrupted"; break;
+ case MSG_BAD_HEAD_END: p = "Can't read end of header"; break;
+ case MSG_BAD_INDEX_FILE: p = "Wrong index file %s"; break;
+ case MSG_BAD_LINEFLD_FMT: p = "Bad format line %d field %d of %s"; break;
+ case MSG_BAD_LINE_LEN: p = "Line length not equal to Lrecl"; break;
+ case MSG_BAD_LRECL: p = "Table/File lrecl mismatch (%d,%hd)"; break;
+ case MSG_BAD_NODE_TYPE: p = "Bad type %d for table node"; break;
+ case MSG_BAD_OFFSET_VAL: p = "Invalid null offset value for a CSV table"; break;
+ case MSG_BAD_OPEN_MODE: p = "Invalid open mode %d"; break;
+ case MSG_BAD_PARAM_TYPE: p = "%.8s: Bad parameter type=%d"; break;
+ case MSG_BAD_PARM_COUNT: p = "Parameter count mismatch"; break;
+ case MSG_BAD_QUOTE_FIELD: p = "Missing ending quote in %s field %d line %d"; break;
+ case MSG_BAD_READ_NUMBER: p = "Wrong number %d of values read from %s"; break;
+ case MSG_BAD_RECFM: p = "Invalid recfm type %d for DOSCOL"; break;
+ case MSG_BAD_RECFM_VAL: p = "Bad Recfm value %d"; break;
+ case MSG_BAD_SET_CASE: p = "Cannot set sensitive an insensitive array"; break;
+ case MSG_BAD_SET_STRING: p = "Invalid SetValue from string"; break;
+ case MSG_BAD_SPECIAL_COL: p = "Bad special column %s"; break;
+ case MSG_BAD_SPEC_COLUMN: p = "Special column invalid for this table type"; break;
+ case MSG_BAD_TABLE_TYPE: p = "Bad type %s for table %s"; break;
+ case MSG_BAD_TYPE_LIKE: p = "Bad operand(%d) type=%d for LIKE"; break;
+ case MSG_BAD_VALBLK_INDX: p = "Out of range valblock index value"; break;
+ case MSG_BAD_VALBLK_TYPE: p = "Invalid value block type %d"; break;
+ case MSG_BAD_VALNODE: p = "Bad type %d for column %s value node"; break;
+ case MSG_BAD_VALUE_TYPE: p = "Invalid value type %d"; break;
+ case MSG_BAD_VAL_UPDATE: p = "Don't know which %s value to update"; break;
+ case MSG_BAS_NS_LIST: p = "Invalid namespaces list format"; break;
+ case MSG_BIN_F_TOO_LONG: p = "Value too long for field %s (%d --> %d)"; break;
+ case MSG_BIN_MODE_FAIL: p = "Set binary mode failed: %s"; break;
+ case MSG_BLKTYPLEN_MISM: p = "Non matching block types/lengths in SetValue"; break;
+ case MSG_BLK_IS_NULL: p = "Blk is NULL"; break;
+ case MSG_BREAKPOINT: p = "Breakpoint"; break;
+ case MSG_BUILD_INDEX: p = "Building index %s on %s"; break;
+ case MSG_CANNOT_OPEN: p = "Cannot open %s"; break;
+ case MSG_CHSIZE_ERROR: p = "chsize error: %s"; break;
+ case MSG_COL_ALLOC_ERR: p = "Cannot allocate column node"; break;
+ case MSG_COL_ISNOT_TABLE: p = "Column %s is not in table %s"; break;
+ case MSG_COL_NOT_SORTED: p = "Column %s of table %s is not sorted"; break;
+ case MSG_COL_NUM_MISM: p = "Number of columns mismatch"; break;
+ case MSG_COM_ERROR: p = "Com error"; break;
+ case MSG_CONCAT_SUBNODE: p = "Cannot concatenate sub-nodes"; break;
+ case MSG_CONNECT_CANCEL: p = "Connection cancelled by user"; break;
+ case MSG_CONTROL_C_EXIT: p = "Control C exit"; break;
+ case MSG_DATABASE_LOADED: p = "Database %s loaded"; break;
+ case MSG_DATA_MISALIGN: p = "Datatype misalignment"; break;
+ case MSG_DBASE_FILE: p = "dBASE dbf file: "; break;
+ case MSG_DEF_ALLOC_ERROR: p = "Error allocating %s DEF class"; break;
+ case MSG_DEL_FILE_ERR: p = "Error deleting %s"; break;
+ case MSG_DEL_READ_ERROR: p = "Delete: read error req=%d len=%d"; break;
+ case MSG_DEL_WRITE_ERROR: p = "Delete: write error: %s"; break;
+ case MSG_DEPREC_FLAG: p = "Deprecated option Flag, use Coltype"; break;
+ case MSG_DLL_LOAD_ERROR: p = "Error %d loading module %s"; break;
+ case MSG_DOM_NOT_SUPP: p = "MS-DOM not supported by this version"; break;
+ case MSG_DVAL_NOTIN_LIST: p = "Value %s not found in distinct values list of column %s"; break;
+ case MSG_EMPTY_DOC: p = "Empty document"; break;
+ case MSG_EMPTY_FILE: p = "%s empty file %s: "; break;
+ case MSG_EOF_AFTER_LINE: p = "EOF after line %d"; break;
+ case MSG_EOF_INDEX_FILE: p = "EOF while reading index file"; break;
+ case MSG_ERROR_IN_LSK: p = "Error %d in lseek64"; break;
+ case MSG_ERROR_IN_SFP: p = "Error %d in SetFilePointer"; break;
+ case MSG_ERR_READING_REC: p = "Error reading record %d of %s"; break;
+ case MSG_FAIL_ADD_NODE: p = "Failed to add %s table node"; break;
+ case MSG_FETCH_NO_RES: p = "Fetch: No Result Set"; break;
+ case MSG_FIELD_TOO_LONG: p = "Value too long for field %d line %d"; break;
+ case MSG_FILELEN_ERROR: p = "Error in %s for %s"; break;
+ case MSG_FILE_IS_EMPTY: p = "File %s is empty"; break;
+ case MSG_FILE_MAP_ERR: p = "File mapping error"; break;
+ case MSG_FILE_MAP_ERROR: p = "CreateFileMapping %s error rc=%d"; break;
+ case MSG_FILE_OPEN_YET: p = "File %s already open"; break;
+ case MSG_FILE_UNFOUND: p = "File %s not found"; break;
+ case MSG_FLD_TOO_LNG_FOR: p = "Field %d too long for %s line %d of %s"; break;
+ case MSG_FLT_BAD_RESULT: p = "Float inexact result"; break;
+ case MSG_FLT_DENORMAL_OP: p = "Float denormal operand"; break;
+ case MSG_FLT_INVALID_OP: p = "Float invalid operation"; break;
+ case MSG_FLT_OVERFLOW: p = "Float overflow"; break;
+ case MSG_FLT_STACK_CHECK: p = "Float stack check"; break;
+ case MSG_FLT_UNDERFLOW: p = "Float underflow"; break;
+ case MSG_FLT_ZERO_DIVIDE: p = "Float divide by zero"; break;
+ case MSG_FMT_WRITE_NIY: p = "Writing %s files is not implemented yet"; break;
+ case MSG_FOXPRO_FILE: p = "FoxPro file: "; break;
+ case MSG_FPUTS_ERROR: p = "fputs error: %s"; break;
+ case MSG_FSEEK_ERROR: p = "fseek error: %s"; break;
+ case MSG_FSETPOS_ERROR: p = "fseek error for i=%d"; break;
+ case MSG_FTELL_ERROR: p = "ftell error for recd=%d: %s"; break;
+ case MSG_FUNCTION_ERROR: p = "%s error: %d"; break;
+ case MSG_FUNC_ERRNO: p = "Error %d in %s"; break;
+ case MSG_FUNC_ERROR: p = "Error in %s"; break;
+ case MSG_FUNC_ERR_S: p = "%s error: %s"; break;
+ case MSG_FWRITE_ERROR: p = "fwrite error: %s"; break;
+ case MSG_GET_DIST_VALS: p = "Retrieving distinct values from "; break;
+ case MSG_GET_FUNC_ERR: p = "Error getting function %s: %s"; break;
+ case MSG_GLOBAL_ERROR: p = "Cannot allocate Global (size=%d)\n"; break;
+ case MSG_GUARD_PAGE: p = "Guard page violation"; break;
+ case MSG_GZOPEN_ERROR: p = "gzopen %s error %d on %s"; break;
+ case MSG_ILLEGAL_INSTR: p = "Illegal instruction"; break;
+ case MSG_ILL_FILTER_CONV: p = "Filtering implies an illegal conversion"; break;
+ case MSG_INDEX_NOT_UNIQ: p = "Index is not unique"; break;
+ case MSG_INDEX_YET_ON: p = "Index %s already exists on %s"; break;
+ case MSG_INDX_COL_NOTIN: p = "Index column %s is not in table %s"; break;
+ case MSG_INDX_EXIST_YET: p = "Index entry already exists"; break;
+ case MSG_INIT_FAILED: p = "Failed to initialize %s processing"; break;
+ case MSG_INT_COL_ERROR: p = "Internal error for index column %s"; break;
+ case MSG_INT_OVERFLOW: p = "Integer overflow"; break;
+ case MSG_INT_ZERO_DIVIDE: p = "Integer divide by zero"; break;
+ case MSG_INVALID_DISP: p = "Invalid disposition"; break;
+ case MSG_INVALID_FTYPE: p = "SBV: invalid Ftype %d"; break;
+ case MSG_INVALID_HANDLE: p = "Invalid handle"; break;
+ case MSG_INVALID_OPER: p = "Invalid operator %d for %s"; break;
+ case MSG_INV_COLUMN_TYPE: p = "Invalid type %d for column %s"; break;
+ case MSG_INV_COL_TYPE: p = "Invalid column type %s"; break;
+ case MSG_INV_DEF_READ: p = "Invalid deferred Read rc=%d"; break;
+ case MSG_INV_DIRCOL_OFST: p = "Invalid DIRCOL offset %d"; break;
+ case MSG_INV_MAP_POS: p = "Invalid map position"; break;
+ case MSG_INV_RAND_ACC: p = "Invalid random access to non optimized table"; break;
+ case MSG_INV_REC_POS: p = "Invalid record position"; break;
+ case MSG_INV_RESULT_TYPE: p = "Invalid result type %s"; break;
+ case MSG_INV_UPDT_TABLE: p = "Table %s invalid for update"; break;
+ case MSG_IN_WITHOUT_SUB: p = "IN or EXISTS without array or subquery"; break;
+ case MSG_KEY_ALLOC_ERR: p = "Error allocating Key offset block"; break;
+ case MSG_KEY_ALLOC_ERROR: p = "Memory allocation error, Klen=%d n=%d"; break;
+ case MSG_LINE_TOO_LONG: p = "New line is too long"; break;
+ case MSG_LIST: p = "--List--"; break;
+ case MSG_LOADING_FAILED: p = "Loading of %s failed"; break;
+ case MSG_LRECL_TOO_SMALL: p = "Lrecl too small (headlen = %d)"; break;
+ case MSG_MAKE_EMPTY_FILE: p = "Making empty file %s: %s"; break;
+ case MSG_MAKING: p = "Making"; break;
+ case MSG_MALLOC_ERROR: p = "Memory allocation failed: %s returned Null"; break;
+ case MSG_MAP_VIEW_ERROR: p = "MapViewOfFile %s error rc=%d"; break;
+ case MSG_MAXSIZE_ERROR: p = "Cannot calculate max size on open table"; break;
+ case MSG_MEM_ALLOC_ERR: p = "Memory allocation error, %s size=%d"; break;
+ case MSG_MEM_ALLOC_ERROR: p = "Memory allocation error"; break;
+ case MSG_MISPLACED_QUOTE: p = "Misplaced quote in line %d"; break;
+ case MSG_MISSING_ARG: p = "Missing argument for operator %d"; break;
+ case MSG_MISSING_FIELD: p = "Missing field %d in %s line %d"; break;
+ case MSG_MISSING_FNAME: p = "Missing file name"; break;
+ case MSG_MISSING_NODE: p = "Missing %s node in %s"; break;
+ case MSG_MISSING_ROWNODE: p = "Can't find RowNode for row %d"; break;
+ case MSG_MIS_TAG_LIST: p = "Missing column tag list"; break;
+ case MSG_MUL_MAKECOL_ERR: p = "Tabmul MakeCol logical error"; break;
+ case MSG_NAME_CONV_ERR: p = "Error converting node name"; break;
+ case MSG_NEW_DOC_FAILED: p = "Cannot create new document"; break;
+ case MSG_NEW_RETURN_NULL: p = "New returned Null in PlugEvalLike"; break;
+ case MSG_NEXT_FILE_ERROR: p = "Couldn't find next file. rc=%d"; break;
+ case MSG_NONCONT_EXCEPT: p = "Noncontinuable exception"; break;
+ case MSG_NOP_ZLIB_INDEX: p = "Cannot do indexing on non optimized zlib table"; break;
+ case MSG_NOT_A_DBF_FILE: p = "Not a dBASE dbf file "; break;
+ case MSG_NOT_FIXED_LEN: p = "File %s is not fixed length, len=%d lrecl=%d"; break;
+ case MSG_NO_0DH_HEAD: p = "No 0Dh at end of header (dbc=%d)"; break;
+ case MSG_NO_ACTIVE_DB: p = "No active database"; break;
+ case MSG_NO_CHAR_FROM: p = "Cannot return char value from type %d"; break;
+ case MSG_NO_DATE_FMT: p = "No date format for valblock of type %d"; break;
+ case MSG_NO_DEF_FNCCOL: p = "Cannot find default function column"; break;
+ case MSG_NO_DEF_PIVOTCOL: p = "Cannot find default pivot column"; break;
+ case MSG_NO_DIR_INDX_RD: p = "No direct access of %s tables"; break;
+ case MSG_NO_FEAT_SUPPORT: p = "No %s support in this version"; break;
+ case MSG_NO_FLD_FORMAT: p = "Missing format for field %d of %s"; break;
+ case MSG_NO_FORMAT_COL: p = "Cannot format the type COLUMN"; break;
+ case MSG_NO_FORMAT_TYPE: p = "Cannot set format from type %d"; break;
+ case MSG_NO_INDEX_READ: p = "No indexed read for multiple tables"; break;
+ case MSG_NO_KEY_COL: p = "No key columns found"; break;
+ case MSG_NO_KEY_UPDATE: p = "Cannot update key names"; break;
+ case MSG_NO_MAP_INSERT: p = "MAP incompatible with Insert"; break;
+ case MSG_NO_MATCHING_COL: p = "No matching column %s in %s"; break;
+ case MSG_NO_MATCH_COL: p = "Cannot find matching column"; break;
+ case MSG_NO_MEMORY: p = "No memory"; break;
+ case MSG_NO_MODE_PADDED: p = "Mode not supported for padded files"; break;
+ case MSG_NO_MUL_VCT: p = "VCT tables cannot be multiple"; break;
+ case MSG_NO_ODBC_DELETE: p = "Delete should not be called for ODBC tables"; break;
+ case MSG_NO_ODBC_DIRECT: p = "Direct access of ODBC tables not implemented yet"; break;
+ case MSG_NO_ODBC_MUL: p = "Multiple(2) not supported for ODBC tables"; break;
+ case MSG_NO_ODBC_SPECOL: p = "No ODBC special columns"; break;
+ case MSG_NO_PART_DEL: p = "No partial delete of %s files"; break;
+ case MSG_NO_PART_MAP: p = "Partial mapping not implemented for this OS"; break;
+ case MSG_NO_PAR_BLK_INS: p = "Cannot insert partial block yet"; break;
+ case MSG_NO_PIV_DIR_ACC: p = "No direct access to PIVOT tables"; break;
+ case MSG_NO_READ_32: p = "Can't read 32 bytes"; break;
+ case MSG_NO_RECOV_SPACE: p = "Cannot recover space in index file"; break;
+ case MSG_NO_ROWID_FOR_AM: p = "Can't get RowID in direct access for tables of type %s"; break;
+ case MSG_NO_ROW_NODE: p = "Row node name is not defined"; break;
+ case MSG_NO_SECTION_NAME: p = "Missing section name"; break;
+ case MSG_NO_SEC_UPDATE: p = "Cannot update section names"; break;
+ case MSG_NO_SETPOS_YET: p = "%s SetPos not implemented yet"; break;
+ case MSG_NO_SPEC_COL: p = "No MySQL special columns"; break;
+ case MSG_NO_SUB_VAL: p = "No sub value for array of type %d"; break;
+ case MSG_NO_TABCOL_DATA: p = "No data found for table %s column %s"; break;
+ case MSG_NO_TABLE_DEL: p = "Delete not enabled for %s tables "; break;
+ case MSG_NO_TAB_DATA: p = "No data found for table %s"; break;
+ case MSG_NO_VCT_DELETE: p = "Partial delete not yet implemented for VCT files"; break;
+ case MSG_NO_ZIP_DELETE: p = "Delete Zip files not implemented yet"; break;
+ case MSG_OPENING: p = "Opening"; break;
+ case MSG_OPEN_EMPTY_FILE: p = "Opening empty file %s: %s"; break;
+ case MSG_OPEN_ERROR: p = "Open error %d in mode %d on %s: "; break;
+ case MSG_OPEN_ERROR_IS: p = "Open error on %s: %s"; break;
+ case MSG_OPEN_MODE_ERROR: p = "Open(%s) error %d on %s"; break;
+ case MSG_OPEN_STRERROR: p = "open error: %s"; break;
+ case MSG_OPTBLK_RD_ERR: p = "Error reading opt block values: %s"; break;
+ case MSG_OPTBLK_WR_ERR: p = "Error writing opt block values: %s"; break;
+ case MSG_OPTIMIZING: p = "Optimizing "; break;
+ case MSG_OPT_BMAP_RD_ERR: p = "Error reading opt bitmaps: %s"; break;
+ case MSG_OPT_BMAP_WR_ERR: p = "Error writing opt bitmaps: %s"; break;
+ case MSG_OPT_CANCELLED: p = "Optimize cancelled by User"; break;
+ case MSG_OPT_DVAL_RD_ERR: p = "Error reading distinct values: %s"; break;
+ case MSG_OPT_DVAL_WR_ERR: p = "Error writing distinct values: %s"; break;
+ case MSG_OPT_HEAD_RD_ERR: p = "Error reading opt file header: %s"; break;
+ case MSG_OPT_HEAD_WR_ERR: p = "Error writing opt file header: %s"; break;
+ case MSG_OPT_LOGIC_ERR: p = "Logical error in SetBitmap, i=%d"; break;
+ case MSG_OPT_MAX_RD_ERR: p = "Error reading opt max values: %s"; break;
+ case MSG_OPT_MAX_WR_ERR: p = "Error writing opt max values: %s"; break;
+ case MSG_OPT_MIN_RD_ERR: p = "Error reading opt min values: %s"; break;
+ case MSG_OPT_MIN_WR_ERR: p = "Error writing opt min values: %s"; break;
+ case MSG_OPT_NOT_MATCH: p = "Non-matching opt file %s"; break;
+ case MSG_PAGE_ERROR: p = "In page error"; break;
+ case MSG_PARM_CNT_MISS: p = "Parameter count mismatch"; break;
+ case MSG_PREC_VBLP_NULL: p = "ARRAY SetPrecision: Vblp is NULL"; break;
+ case MSG_PRIV_INSTR: p = "Privileged instruction"; break;
+ case MSG_PROCADD_ERROR: p = "Error %d getting address of %s"; break;
+ case MSG_QUERY_CANCELLED: p = "Query Cancelled by User"; break;
+ case MSG_RANGE_NO_JOIN: p = "Range is not meant for join index"; break;
+ case MSG_RC_READING: p = "rc=%d reading table %s"; break;
+ case MSG_READY: p = "Ready"; break;
+ case MSG_READ_ERROR: p = "Error reading %s: %s"; break;
+ case MSG_READ_ONLY: p = "Cannot modify this read/only protected table"; break;
+ case MSG_READ_SEEK_ERROR: p = "Read seek error: %s"; break;
+ case MSG_REGISTER_ERR: p = "Unable to register NS with prefix='%s' and href='%s'"; break;
+ case MSG_REMOVE_ERROR: p = "Error removing %s: %s"; break;
+ case MSG_RENAME_ERROR: p = "Error renaming %s to %s: %s"; break;
+ case MSG_ROWID_NOT_IMPL: p = "RowNumber not implemented for tables of type %s"; break;
+ case MSG_SEC_KEY_FIRST: p = "Section and key names must come first on Insert"; break;
+ case MSG_SEC_NAME_FIRST: p = "Section name must come first on Insert"; break;
+ case MSG_SEP_IN_FIELD: p = "Field %d contains the separator character"; break;
+ case MSG_SEQUENCE_ERROR: p = "Sequence error on statement allocation"; break;
+ case MSG_SETEOF_ERROR: p = "Error %d in SetEndOfFile"; break;
+ case MSG_SETRECPOS_NIY: p = "SetRecpos not implemented for this table type"; break;
+ case MSG_SET_STR_TRUNC: p = "SetValue: String would be truncated"; break;
+ case MSG_SFP_ERROR: p = "SetFilePointer error: %s"; break;
+ case MSG_SHARED_LIB_ERR: p = "Error loading shared library %s: %s"; break;
+ case MSG_SINGLE_STEP: p = "Single step"; break;
+ case MSG_SORTING_VAL: p = "Sorting %d values"; break;
+ case MSG_SPCOL_READONLY: p = "Special column %s is Read Only"; break;
+ case MSG_SQL_CONF_ERROR: p = "SQL Error: SQL_CONFORMANCE"; break;
+ case MSG_SRCH_CLOSE_ERR: p = "Couldn't close search handle"; break;
+ case MSG_SRC_TABLE_UNDEF: p = "Source table is not defined"; break;
+ case MSG_STACK_OVERFLOW: p = "Stack overflow"; break;
+ case MSG_TABDIR_READONLY: p = "DIR tables are read/only"; break;
+ case MSG_TABLE_NOT_OPT: p = "Not an optimizable table"; break;
+ case MSG_TABLE_NO_INDEX: p = "Table %s is not indexable"; break;
+ case MSG_TABLE_READ_ONLY: p = "%s tables are read only "; break;
+ case MSG_TABMUL_READONLY: p = "Multiple tables are read/only"; break;
+ case MSG_TOO_MANY_FIELDS: p = "Too many fields line %d of %s"; break;
+ case MSG_TOO_MANY_JUMPS: p = "Too many jump levels"; break;
+ case MSG_TOO_MANY_KEYS: p = "Too many keys (%d)"; break;
+ case MSG_TO_BLK_IS_NULL: p = "To Blk is NULL"; break;
+ case MSG_TRUNCATE_ERROR: p = "truncate error: %s"; break;
+ case MSG_TRUNC_BY_ESTIM: p = "truncated by Estimate"; break;
+ case MSG_TYPE_MISMATCH: p = "Key and source are not of the same type"; break;
+ case MSG_TYPE_VALUE_ERR: p = "Column %s type(%s)/value(%s) mismatch"; break;
+ case MSG_UNBALANCE_QUOTE: p = "Unbalanced quote in line %d"; break;
+ case MSG_UNDEFINED_AM: p = "COLBLK %s: undefined Access Method"; break;
+ case MSG_UNKNOWN_EXCPT: p = "Unknown exception"; break;
+ case MSG_UNMATCH_FIL_ARG: p = "Unmatched filter argument"; break;
+ case MSG_UPDATE_ERROR: p = "Error updating %s"; break;
+ case MSG_UPD_ZIP_NOT_IMP: p = "Updating ZDOS tables not implemented yet"; break;
+ case MSG_VALSTR_TOO_LONG: p = "Value %s too long for string of length %d"; break;
+ case MSG_VALTYPE_NOMATCH: p = "Non matching Value types"; break;
+ case MSG_VALUE_ERROR: p = "Column %s: value is null"; break;
+ case MSG_VALUE_TOO_BIG: p = "Value %lld too big for column %s"; break;
+ case MSG_VALUE_TOO_LONG: p = "Value %s too long for column %s of length %d"; break;
+ case MSG_VAL_ALLOC_ERR: p = "Cannot allocate value node"; break;
+ case MSG_VIR_NO_DELETE: p = "Delete not allowed for %s tables"; break;
+ case MSG_VIR_READ_ONLY: p = "Virtual %s tables are read only"; break;
+ case MSG_VOID_FIRST_ARG: p = "First argument should not be void"; break;
+ case MSG_WORK_AREA: p = "Work area: %s"; break;
+ case MSG_WRITE_SEEK_ERR: p = "Write seek error: %s"; break;
+ case MSG_WRITE_STRERROR: p = "Error writing %s: %s"; break;
+ case MSG_WRITING: p = "Writing"; break;
+ case MSG_WRITING_ERROR: p = "Error writing to %s: %s"; break;
+ case MSG_WS_CONV_ERR: p = "Error converting %s to WS"; break;
+ case MSG_XCOL_MISMATCH: p = "Column %s mismatch in index"; break;
+ case MSG_XFILE_READERR: p = "Error %d reading index file"; break;
+ case MSG_XFILE_WRITERR: p = "Error writing index file: %s"; break;
+ case MSG_XMLTAB_INIT_ERR: p = "Error initializing XML table"; break;
+ case MSG_XML_INIT_ERROR: p = "Error initializing new XML file"; break;
+ case MSG_XPATH_CNTX_ERR: p = "Unable to create new XPath context"; break;
+ case MSG_XPATH_EVAL_ERR: p = "Unable to evaluate xpath location '%s'"; break;
+ case MSG_XPATH_NOT_SUPP: p = "Unsupported Xpath for column %s"; break;
diff --git a/storage/connect/engmsg.h b/storage/connect/engmsg.h
new file mode 100644
index 00000000..c0725110
--- /dev/null
+++ b/storage/connect/engmsg.h
@@ -0,0 +1,326 @@
+/* Copyright (C) MariaDB Corporation Ab */
+#define MSG_ACCESS_VIOLATN "Access violation"
+#define MSG_ADD_BAD_TYPE "Array add value type mismatch (%s -> %s)"
+#define MSG_ALLOC_ERROR "Error allocating %s"
+#define MSG_ANSWER_TYPE "Answer of type"
+#define MSG_API_CONF_ERROR "SQL Error: API_CONFORMANCE"
+#define MSG_APPL_NOT_INIT "Application not initialized"
+#define MSG_ARRAY_BNDS_EXCD "Array bounds exceeded"
+#define MSG_BAD_ARRAY_OPER "Arrays must be used with the IN operator"
+#define MSG_BAD_ARRAY_TYPE "Illegal array type %d"
+#define MSG_BAD_ARRAY_VAL "Arrays must have the same number of values"
+#define MSG_BAD_BIN_FMT "Invalid format %c for the %s BIN column"
+#define MSG_BAD_BLK_ESTIM "Number of blocks exceeds estimate"
+#define MSG_BAD_BLK_SIZE "No match in block %d size"
+#define MSG_BAD_BYTE_NUM "bad number of bytes written"
+#define MSG_BAD_BYTE_READ "bad number of bytes read"
+#define MSG_BAD_COL_TYPE "Invalid type %s for column %s"
+#define MSG_BAD_COL_XPATH "Invalid Xpath in column %s for HTML table %s"
+#define MSG_BAD_CONST_TYPE "Bad constant type=%d"
+#define MSG_BAD_CONV_TYPE "Invalid convert type %d"
+#define MSG_BAD_DATETIME "Invalid datetime value"
+#define MSG_BAD_DBF_FILE "DBF file %s is corrupted"
+#define MSG_BAD_DBF_REC "DBF file %s corrupted at record %d"
+#define MSG_BAD_DBF_TYPE "Unsupported DBF type %c for column %s"
+#define MSG_BAD_DIRECTORY "Bad directory %s: %s"
+#define MSG_BAD_FIELD_RANK "Invalid field rank %d for column %s"
+#define MSG_BAD_FIELD_TYPE "Bad type field %s"
+#define MSG_BAD_FILE_HANDLE "Invalid File Handle: %s"
+#define MSG_BAD_FILTER "Bad filter: Opc=%d B_T=%d %d Type=%d %d"
+#define MSG_BAD_FILTER_CONV "Bad filter conversion, B_T=%d,%d"
+#define MSG_BAD_FILTER_OP "Invalid filter operator %d"
+#define MSG_BAD_FLD_FORMAT "Bad format for field %d of %s"
+#define MSG_BAD_FLD_LENGTH "Field %s too long (%s --> %d) line %d of %s"
+#define MSG_BAD_FREQ_SET "Bad frequency setting for column %s"
+#define MSG_BAD_FUNC_MODE "%s: invalid mode %d"
+#define MSG_BAD_HANDLE_VAL "Invalid handle value"
+#define MSG_BAD_HEADER "File %s: Header corrupted"
+#define MSG_BAD_HEAD_END "Can't read end of header"
+#define MSG_BAD_INDEX_FILE "Wrong index file %s"
+#define MSG_BAD_LINEFLD_FMT "Bad format line %d field %d of %s"
+#define MSG_BAD_LINE_LEN "Line length not equal to Lrecl"
+#define MSG_BAD_LRECL "Table/File lrecl mismatch (%d,%hd)"
+#define MSG_BAD_NODE_TYPE "Bad type %d for table node"
+#define MSG_BAD_OFFSET_VAL "Invalid null offset value for a CSV table"
+#define MSG_BAD_OPEN_MODE "Invalid open mode %d"
+#define MSG_BAD_PARAM_TYPE "%.8s: Bad parameter type=%d"
+#define MSG_BAD_PARM_COUNT "Parameter count mismatch"
+#define MSG_BAD_QUOTE_FIELD "Missing ending quote in %s field %d line %d"
+#define MSG_BAD_READ_NUMBER "Wrong number %d of values read from %s"
+#define MSG_BAD_RECFM "Invalid recfm type %d for DOSCOL"
+#define MSG_BAD_RECFM_VAL "Bad Recfm value %d"
+#define MSG_BAD_SET_CASE "Cannot set sensitive an insensitive array"
+#define MSG_BAD_SET_STRING "Invalid SetValue from string"
+#define MSG_BAD_SPECIAL_COL "Bad special column %s"
+#define MSG_BAD_SPEC_COLUMN "Special column invalid for this table type"
+#define MSG_BAD_TABLE_TYPE "Bad type %s for table %s"
+#define MSG_BAD_TYPE_LIKE "Bad operand(%d) type=%d for LIKE"
+#define MSG_BAD_VALBLK_INDX "Out of range valblock index value"
+#define MSG_BAD_VALBLK_TYPE "Invalid value block type %d"
+#define MSG_BAD_VALNODE "Bad type %d for column %s value node"
+#define MSG_BAD_VALUE_TYPE "Invalid value type %d"
+#define MSG_BAD_VAL_UPDATE "Don't know which %s value to update"
+#define MSG_BAS_NS_LIST "Invalid namespaces list format"
+#define MSG_BIN_F_TOO_LONG "Value too long for field %s (%d --> %d)"
+#define MSG_BIN_MODE_FAIL "Set binary mode failed: %s"
+#define MSG_BLKTYPLEN_MISM "Non matching block types/lengths in SetValue"
+#define MSG_BLK_IS_NULL "Blk is NULL"
+#define MSG_BREAKPOINT "Breakpoint"
+#define MSG_BUILD_INDEX "Building index %s on %s"
+#define MSG_CANNOT_OPEN "Cannot open %s"
+#define MSG_CHSIZE_ERROR "chsize error: %s"
+#define MSG_COL_ALLOC_ERR "Cannot allocate column node"
+#define MSG_COL_ISNOT_TABLE "Column %s is not in table %s"
+#define MSG_COL_NOT_SORTED "Column %s of table %s is not sorted"
+#define MSG_COL_NUM_MISM "Number of columns mismatch"
+#define MSG_COM_ERROR "Com error"
+#define MSG_CONCAT_SUBNODE "Cannot concatenate sub-nodes"
+#define MSG_CONNECT_CANCEL "Connection cancelled by user"
+#define MSG_CONTROL_C_EXIT "Control C exit"
+#define MSG_DATABASE_LOADED "Database %s loaded"
+#define MSG_DATA_MISALIGN "Datatype misalignment"
+#define MSG_DBASE_FILE "dBASE dbf file: "
+#define MSG_DEF_ALLOC_ERROR "Error allocating %s DEF class"
+#define MSG_DEL_FILE_ERR "Error deleting %s"
+#define MSG_DEL_READ_ERROR "Delete: read error req=%d len=%d"
+#define MSG_DEL_WRITE_ERROR "Delete: write error: %s"
+#define MSG_DEPREC_FLAG "Deprecated option Flag, use Coltype"
+#define MSG_DLL_LOAD_ERROR "Error %d loading module %s"
+#define MSG_DOM_NOT_SUPP "MS-DOM not supported by this version"
+#define MSG_DVAL_NOTIN_LIST "Value %s not found in distinct values list of column %s"
+#define MSG_EMPTY_DOC "Empty document"
+#define MSG_EMPTY_FILE "%s empty file %s: "
+#define MSG_EOF_AFTER_LINE "EOF after line %d"
+#define MSG_EOF_INDEX_FILE "EOF while reading index file"
+#define MSG_ERROR_IN_LSK "Error %d in lseek64"
+#define MSG_ERROR_IN_SFP "Error %d in SetFilePointer"
+#define MSG_ERR_READING_REC "Error reading record %d of %s"
+#define MSG_FAIL_ADD_NODE "Failed to add %s table node"
+#define MSG_FETCH_NO_RES "Fetch: No Result Set"
+#define MSG_FIELD_TOO_LONG "Value too long for field %d line %d"
+#define MSG_FILELEN_ERROR "Error in %s for %s"
+#define MSG_FILE_IS_EMPTY "File %s is empty"
+#define MSG_FILE_MAP_ERR "File mapping error"
+#define MSG_FILE_MAP_ERROR "CreateFileMapping %s error rc=%d"
+#define MSG_FILE_OPEN_YET "File %s already open"
+#define MSG_FILE_UNFOUND "File %s not found"
+#define MSG_FIX_OVFLW_ADD "Fixed Overflow on add"
+#define MSG_FIX_OVFLW_TIMES "Fixed Overflow on times"
+#define MSG_FIX_UNFLW_ADD "Fixed Underflow on add"
+#define MSG_FIX_UNFLW_TIMES "Fixed Underflow on times"
+#define MSG_FLD_TOO_LNG_FOR "Field %d too long for %s line %d of %s"
+#define MSG_FLT_BAD_RESULT "Float inexact result"
+#define MSG_FLT_DENORMAL_OP "Float denormal operand"
+#define MSG_FLT_INVALID_OP "Float invalid operation"
+#define MSG_FLT_OVERFLOW "Float overflow"
+#define MSG_FLT_STACK_CHECK "Float stack check"
+#define MSG_FLT_UNDERFLOW "Float underflow"
+#define MSG_FLT_ZERO_DIVIDE "Float divide by zero"
+#define MSG_FMT_WRITE_NIY "Writing %s files is not implemented yet"
+#define MSG_FOXPRO_FILE "FoxPro file: "
+#define MSG_FPUTS_ERROR "fputs error: %s"
+#define MSG_FSEEK_ERROR "fseek error: %s"
+#define MSG_FSETPOS_ERROR "fseek error for i=%d"
+#define MSG_FTELL_ERROR "ftell error for recd=%d: %s"
+#define MSG_FUNCTION_ERROR "%s error: %d"
+#define MSG_FUNC_ERRNO "Error %d in %s"
+#define MSG_FUNC_ERROR "Error in %s"
+#define MSG_FUNC_ERR_S "%s error: %s"
+#define MSG_FWRITE_ERROR "fwrite error: %s"
+#define MSG_GET_DIST_VALS "Retrieving distinct values from "
+#define MSG_GET_FUNC_ERR "Error getting function %s: %s"
+#define MSG_GLOBAL_ERROR "Cannot allocate Global (size=%d)\n"
+#define MSG_GUARD_PAGE "Guard page violation"
+#define MSG_GZOPEN_ERROR "gzopen %s error %d on %s"
+#define MSG_ILLEGAL_INSTR "Illegal instruction"
+#define MSG_ILL_FILTER_CONV "Filtering implies an illegal conversion"
+#define MSG_INDEX_NOT_UNIQ "Index is not unique"
+#define MSG_INDEX_YET_ON "Index %s already exists on %s"
+#define MSG_INDX_COL_NOTIN "Index column %s is not in table %s"
+#define MSG_INDX_EXIST_YET "Index entry already exists"
+#define MSG_INIT_FAILED "Failed to initialize %s processing"
+#define MSG_INT_COL_ERROR "Internal error for index column %s"
+#define MSG_INT_OVERFLOW "Integer overflow"
+#define MSG_INT_ZERO_DIVIDE "Integer divide by zero"
+#define MSG_INVALID_DISP "Invalid disposition"
+#define MSG_INVALID_FTYPE "SBV: invalid Ftype %d"
+#define MSG_INVALID_HANDLE "Invalid handle"
+#define MSG_INVALID_OPER "Invalid operator %d for %s"
+#define MSG_INV_COLUMN_TYPE "Invalid type %d for column %s"
+#define MSG_INV_COL_TYPE "Invalid column type %s"
+#define MSG_INV_DEF_READ "Invalid deferred Read rc=%d"
+#define MSG_INV_DIRCOL_OFST "Invalid DIRCOL offset %d"
+#define MSG_INV_MAP_POS "Invalid map position"
+#define MSG_INV_RAND_ACC "Invalid random access to non optimized table"
+#define MSG_INV_REC_POS "Invalid record position"
+#define MSG_INV_RESULT_TYPE "Invalid result type %s"
+#define MSG_INV_UPDT_TABLE "Table %s invalid for update"
+#define MSG_IN_WITHOUT_SUB "IN or EXISTS without array or subquery"
+#define MSG_KEY_ALLOC_ERR "Error allocating Key offset block"
+#define MSG_KEY_ALLOC_ERROR "Memory allocation error, Klen=%d n=%d"
+#define MSG_LINE_TOO_LONG "New line is too long"
+#define MSG_LIST "--List--"
+#define MSG_LOADING_FAILED "Loading of %s failed"
+#define MSG_LRECL_TOO_SMALL "Lrecl too small (headlen = %d)"
+#define MSG_MAKE_EMPTY_FILE "Making empty file %s: %s"
+#define MSG_MAKING "Making"
+#define MSG_MALLOC_ERROR "Memory allocation failed: %s returned Null"
+#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s error rc=%d"
+#define MSG_MAXSIZE_ERROR "Cannot calculate max size on open table"
+#define MSG_MEM_ALLOC_ERR "Memory allocation error, %s size=%d"
+#define MSG_MEM_ALLOC_ERROR "Memory allocation error"
+#define MSG_MISPLACED_QUOTE "Misplaced quote in line %d"
+#define MSG_MISSING_ARG "Missing argument for operator %d"
+#define MSG_MISSING_FIELD "Missing field %d in %s line %d"
+#define MSG_MISSING_FNAME "Missing file name"
+#define MSG_MISSING_NODE "Missing %s node in %s"
+#define MSG_MISSING_ROWNODE "Can't find RowNode for row %d"
+#define MSG_MIS_TAG_LIST "Missing column tag list"
+#define MSG_MUL_MAKECOL_ERR "Tabmul MakeCol logical error"
+#define MSG_NAME_CONV_ERR "Error converting node name"
+#define MSG_NEW_DOC_FAILED "Cannot create new document"
+#define MSG_NEW_RETURN_NULL "New returned Null in PlugEvalLike"
+#define MSG_NEXT_FILE_ERROR "Couldn't find next file. rc=%d"
+#define MSG_NONCONT_EXCEPT "Noncontinuable exception"
+#define MSG_NOP_ZLIB_INDEX "Cannot do indexing on non optimized zlib table"
+#define MSG_NOT_A_DBF_FILE "Not a dBASE dbf file "
+#define MSG_NOT_FIXED_LEN "File %s is not fixed length, len=%d lrecl=%d"
+#define MSG_NO_0DH_HEAD "No 0Dh at end of header (dbc=%d)"
+#define MSG_NO_ACTIVE_DB "No active database"
+#define MSG_NO_CHAR_FROM "Cannot return char value from type %d"
+#define MSG_NO_DATE_FMT "No date format for valblock of type %d"
+#define MSG_NO_DEF_FNCCOL "Cannot find default function column"
+#define MSG_NO_DEF_PIVOTCOL "Cannot find default pivot column"
+#define MSG_NO_DIR_INDX_RD "No direct access of %s tables"
+#define MSG_NO_FEAT_SUPPORT "No %s support in this version"
+#define MSG_NO_FLD_FORMAT "Missing format for field %d of %s"
+#define MSG_NO_FORMAT_COL "Cannot format the type COLUMN"
+#define MSG_NO_FORMAT_TYPE "Cannot set format from type %d"
+#define MSG_NO_INDEX_READ "No indexed read for multiple tables"
+#define MSG_NO_KEY_COL "No key columns found"
+#define MSG_NO_KEY_UPDATE "Cannot update key names"
+#define MSG_NO_MAP_INSERT "MAP incompatible with Insert"
+#define MSG_NO_MATCHING_COL "No matching column %s in %s"
+#define MSG_NO_MATCH_COL "Cannot find matching column"
+#define MSG_NO_MEMORY "No memory"
+#define MSG_NO_MODE_PADDED "Mode not supported for padded files"
+#define MSG_NO_MUL_VCT "VCT tables cannot be multiple"
+#define MSG_NO_ODBC_DELETE "Delete should not be called for ODBC tables"
+#define MSG_NO_ODBC_DIRECT "Direct access of ODBC tables not implemented yet"
+#define MSG_NO_ODBC_MUL "Multiple(2) not supported for ODBC tables"
+#define MSG_NO_ODBC_SPECOL "No ODBC special columns"
+#define MSG_NO_PART_DEL "No partial delete of %s files"
+#define MSG_NO_PART_MAP "Partial mapping not implemented for this OS"
+#define MSG_NO_PAR_BLK_INS "Cannot insert partial block yet"
+#define MSG_NO_PIV_DIR_ACC "No direct access to PIVOT tables"
+#define MSG_NO_READ_32 "Can't read 32 bytes"
+#define MSG_NO_RECOV_SPACE "Cannot recover space in index file"
+#define MSG_NO_ROWID_FOR_AM "Can't get RowID in direct access for tables of type %s"
+#define MSG_NO_ROW_NODE "Row node name is not defined"
+#define MSG_NO_SECTION_NAME "Missing section name"
+#define MSG_NO_SEC_UPDATE "Cannot update section names"
+#define MSG_NO_SETPOS_YET "%s SetPos not implemented yet"
+#define MSG_NO_SPEC_COL "No MySQL special columns"
+#define MSG_NO_SUB_VAL "No sub value for array of type %d"
+#define MSG_NO_TABCOL_DATA "No data found for table %s column %s"
+#define MSG_NO_TABLE_DEL "Delete not enabled for %s tables "
+#define MSG_NO_TAB_DATA "No data found for table %s"
+#define MSG_NO_VCT_DELETE "Partial delete not yet implemented for VCT files"
+#define MSG_NO_ZIP_DELETE "Delete Zip files not implemented yet"
+#define MSG_OPENING "Opening"
+#define MSG_OPEN_EMPTY_FILE "Opening empty file %s: %s"
+#define MSG_OPEN_ERROR "Open error %d in mode %d on %s: "
+#define MSG_OPEN_ERROR_IS "Open error on %s: %s"
+#define MSG_OPEN_MODE_ERROR "Open(%s) error %d on %s"
+#define MSG_OPEN_STRERROR "open error: %s"
+#define MSG_OPTBLK_RD_ERR "Error reading opt block values: %s"
+#define MSG_OPTBLK_WR_ERR "Error writing opt block values: %s"
+#define MSG_OPTIMIZING "Optimizing "
+#define MSG_OPT_BMAP_RD_ERR "Error reading opt bitmaps: %s"
+#define MSG_OPT_BMAP_WR_ERR "Error writing opt bitmaps: %s"
+#define MSG_OPT_CANCELLED "Optimize cancelled by User"
+#define MSG_OPT_DVAL_RD_ERR "Error reading distinct values: %s"
+#define MSG_OPT_DVAL_WR_ERR "Error writing distinct values: %s"
+#define MSG_OPT_HEAD_RD_ERR "Error reading opt file header: %s"
+#define MSG_OPT_HEAD_WR_ERR "Error writing opt file header: %s"
+#define MSG_OPT_LOGIC_ERR "Logical error in SetBitmap, i=%d"
+#define MSG_OPT_MAX_RD_ERR "Error reading opt max values: %s"
+#define MSG_OPT_MAX_WR_ERR "Error writing opt max values: %s"
+#define MSG_OPT_MIN_RD_ERR "Error reading opt min values: %s"
+#define MSG_OPT_MIN_WR_ERR "Error writing opt min values: %s"
+#define MSG_OPT_NOT_MATCH "Non-matching opt file %s"
+#define MSG_PAGE_ERROR "In page error"
+#define MSG_PARM_CNT_MISS "Parameter count mismatch"
+#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp is NULL"
+#define MSG_PRIV_INSTR "Privileged instruction"
+#define MSG_PROCADD_ERROR "Error %d getting address of %s"
+#define MSG_QUERY_CANCELLED "Query Cancelled by User"
+#define MSG_RANGE_NO_JOIN "Range is not meant for join index"
+#define MSG_RC_READING "rc=%d reading table %s"
+#define MSG_READY "Ready"
+#define MSG_READ_ERROR "Error reading %s: %s"
+#define MSG_READ_ONLY "Cannot modify this read/only protected table"
+#define MSG_READ_SEEK_ERROR "Read seek error: %s"
+#define MSG_REGISTER_ERR "Unable to register NS with prefix='%s' and href='%s'"
+#define MSG_REMOVE_ERROR "Error removing %s: %s"
+#define MSG_RENAME_ERROR "Error renaming %s to %s: %s"
+#define MSG_ROWID_NOT_IMPL "RowNumber not implemented for tables of type %s"
+#define MSG_SEC_KEY_FIRST "Section and key names must come first on Insert"
+#define MSG_SEC_NAME_FIRST "Section name must come first on Insert"
+#define MSG_SEP_IN_FIELD "Field %d contains the separator character"
+#define MSG_SEQUENCE_ERROR "Sequence error on statement allocation"
+#define MSG_SETEOF_ERROR "Error %d in SetEndOfFile"
+#define MSG_SETRECPOS_NIY "SetRecpos not implemented for this table type"
+#define MSG_SET_STR_TRUNC "SetValue: String would be truncated"
+#define MSG_SFP_ERROR "SetFilePointer error: %s"
+#define MSG_SHARED_LIB_ERR "Error loading shared library %s: %s"
+#define MSG_SINGLE_STEP "Single step"
+#define MSG_SORTING_VAL "Sorting %d values"
+#define MSG_SPCOL_READONLY "Special column %s is Read Only"
+#define MSG_SQL_CONF_ERROR "SQL Error: SQL_CONFORMANCE"
+#define MSG_SRCH_CLOSE_ERR "Couldn't close search handle"
+#define MSG_SRC_TABLE_UNDEF "Source table is not defined"
+#define MSG_STACK_OVERFLOW "Stack overflow"
+#define MSG_TABDIR_READONLY "DIR tables are read/only"
+#define MSG_TABLE_NOT_OPT "Not an optimizable table"
+#define MSG_TABLE_NO_INDEX "Table %s is not indexable"
+#define MSG_TABLE_READ_ONLY "%s tables are read only "
+#define MSG_TABMUL_READONLY "Multiple tables are read/only"
+#define MSG_TOO_MANY_FIELDS "Too many fields line %d of %s"
+#define MSG_TOO_MANY_JUMPS "Too many jump levels"
+#define MSG_TOO_MANY_KEYS "Too many keys (%d)"
+#define MSG_TO_BLK_IS_NULL "To Blk is NULL"
+#define MSG_TRUNCATE_ERROR "truncate error: %s"
+#define MSG_TRUNC_BY_ESTIM "truncated by Estimate"
+#define MSG_TYPE_MISMATCH "Key and source are not of the same type"
+#define MSG_TYPE_VALUE_ERR "Column %s type(%s)/value(%s) mismatch"
+#define MSG_UNBALANCE_QUOTE "Unbalanced quote in line %d"
+#define MSG_UNDEFINED_AM "COLBLK %s: undefined Access Method"
+#define MSG_UNKNOWN_EXCPT "Unknown exception"
+#define MSG_UNMATCH_FIL_ARG "Unmatched filter argument"
+#define MSG_UPDATE_ERROR "Error updating %s"
+#define MSG_UPD_ZIP_NOT_IMP "Updating ZDOS tables not implemented yet"
+#define MSG_VALSTR_TOO_LONG "Value %s too long for string of length %d"
+#define MSG_VALTYPE_NOMATCH "Non matching Value types"
+#define MSG_VALUE_ERROR "Column %s: value is null"
+#define MSG_VALUE_TOO_BIG "Value %lld too big for column %s"
+#define MSG_VALUE_TOO_LONG "Value %s too long for column %s of length %d"
+#define MSG_VAL_ALLOC_ERR "Cannot allocate value node"
+#define MSG_VIR_NO_DELETE "Delete not allowed for %s tables"
+#define MSG_VIR_READ_ONLY "Virtual %s tables are read only"
+#define MSG_VOID_FIRST_ARG "First argument should not be void"
+#define MSG_WORK_AREA "Work area: %s"
+#define MSG_WRITE_SEEK_ERR "Write seek error: %s"
+#define MSG_WRITE_STRERROR "Error writing %s: %s"
+#define MSG_WRITING "Writing"
+#define MSG_WRITING_ERROR "Error writing to %s: %s"
+#define MSG_WS_CONV_ERR "Error converting %s to WS"
+#define MSG_XCOL_MISMATCH "Column %s mismatch in index"
+#define MSG_XFILE_READERR "Error %d reading index file"
+#define MSG_XFILE_WRITERR "Error writing index file: %s"
+#define MSG_XMLTAB_INIT_ERR "Error initializing XML table"
+#define MSG_XML_INIT_ERROR "Error initializing new XML file"
+#define MSG_XPATH_CNTX_ERR "Unable to create new XPath context"
+#define MSG_XPATH_EVAL_ERR "Unable to evaluate xpath location '%s'"
+#define MSG_XPATH_NOT_SUPP "Unsupported Xpath for column %s"
+#define MSG_ZERO_DIVIDE "Zero divide in expression"
diff --git a/storage/connect/enids.h b/storage/connect/enids.h
new file mode 100644
index 00000000..d171955b
--- /dev/null
+++ b/storage/connect/enids.h
@@ -0,0 +1,46 @@
+ case IDS_TABLES: p = "Table Headers"; break;
+ case IDS_TAB_01: p = "Table_Cat"; break;
+ case IDS_TAB_02: p = "Table_Schema"; break;
+ case IDS_TAB_03: p = "Table_Name"; break;
+ case IDS_TAB_04: p = "Table_Type"; break;
+ case IDS_TAB_05: p = "Remark"; break;
+ case IDS_COLUMNS: p = "Column Headers"; break;
+ case IDS_COL_01: p = "Table_Cat"; break;
+ case IDS_COL_02: p = "Table_Schema"; break;
+ case IDS_COL_03: p = "Table_Name"; break;
+ case IDS_COL_04: p = "Column_Name"; break;
+ case IDS_COL_05: p = "Data_Type"; break;
+ case IDS_COL_06: p = "Type_Name"; break;
+ case IDS_COL_07: p = "Column_Size"; break;
+ case IDS_COL_08: p = "Buffer_Length"; break;
+ case IDS_COL_09: p = "Decimal_Digits"; break;
+ case IDS_COL_10: p = "Radix"; break;
+ case IDS_COL_11: p = "Nullable"; break;
+ case IDS_COL_12: p = "Remarks"; break;
+ case IDS_PKEY: p = "Key Headers"; break;
+ case IDS_PKY_01: p = "Table_Catalog"; break;
+ case IDS_PKY_02: p = "Table_Schema"; break;
+ case IDS_PKY_03: p = "Table_Name"; break;
+ case IDS_PKY_04: p = "Column_Name"; break;
+ case IDS_PKY_05: p = "Key_Seq"; break;
+ case IDS_PKY_06: p = "Pk_Name"; break;
+ case IDS_STAT: p = "Stat Headers"; break;
+ case IDS_STA_01: p = "Table_Catalog"; break;
+ case IDS_STA_02: p = "Table_Schema"; break;
+ case IDS_STA_03: p = "Table_Name"; break;
+ case IDS_STA_04: p = "Non_Unique"; break;
+ case IDS_STA_05: p = "Index_Qualifier"; break;
+ case IDS_STA_06: p = "Index_Name"; break;
+ case IDS_STA_07: p = "Type"; break;
+ case IDS_STA_08: p = "Seq_in_Index"; break;
+ case IDS_STA_09: p = "Column_Name"; break;
+ case IDS_STA_10: p = "Collation"; break;
+ case IDS_STA_11: p = "Cardinality"; break;
+ case IDS_STA_12: p = "Pages"; break;
+ case IDS_STA_13: p = "Filter_Condition"; break;
+ case IDS_DRIVER: p = "Driver Headers"; break;
+ case IDS_DRV_01: p = "Description"; break;
+ case IDS_DRV_02: p = "Attributes"; break;
+ case IDS_DSRC: p = "DataSrc Headers"; break;
+ case IDS_DSC_01: p = "Name"; break;
+ case IDS_DSC_02: p = "Description"; break;
diff --git a/storage/connect/filamap.cpp b/storage/connect/filamap.cpp
new file mode 100644
index 00000000..4930e394
--- /dev/null
+++ b/storage/connect/filamap.cpp
@@ -0,0 +1,788 @@
+/*********** File AM Map C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMAP */
+/* ------------- */
+/* Version 1.6 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the MAP file access method classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* filamtxt.h is header containing the file AM classes declarations. */
+/* Note: these files are included inside the include files below. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "osutil.h"
+#include "maputil.h"
+#include "filamap.h"
+#include "tabdos.h"
+#include "tabfmt.h"
+
+/* --------------------------- Class MAPFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+MAPFAM::MAPFAM(PDOSDEF tdp) : TXTFAM(tdp)
+ {
+ Memory = NULL;
+ Mempos = NULL;
+ Tpos = NULL;
+ Fpos = NULL;
+ Spos = NULL;
+ Top = NULL;
+ } // end of MAPFAM standard constructor
+
+MAPFAM::MAPFAM(PMAPFAM tmfp) : TXTFAM(tmfp)
+ {
+ Memory = tmfp->Memory;
+ Mempos = tmfp->Mempos;
+ Fpos = tmfp->Fpos;
+ Spos = tmfp->Spos;
+ Tpos = tmfp->Tpos;
+ Top = tmfp->Top;
+ } // end of MAPFAM copy constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void MAPFAM::Reset(void)
+ {
+ TXTFAM::Reset();
+ Fpos = Tpos = Spos = NULL;
+ } // end of Reset
+
+/***********************************************************************/
+/* MAP GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int MAPFAM::GetFileLength(PGLOBAL g)
+ {
+ int len;
+
+ len = (To_Fb && To_Fb->Count) ? To_Fb->Length : TXTFAM::GetFileLength(g);
+
+ if (trace(1))
+ htrc("Mapped file length=%d\n", len);
+
+ return len;
+ } // end of GetFileLength
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file as a mapped file. */
+/***********************************************************************/
+bool MAPFAM::OpenTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ size_t len;
+ MODE mode = Tdbp->GetMode();
+ PFBLOCK fp;
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+#if defined(_DEBUG)
+ // Insert mode is no more handled using file mapping
+ assert(mode != MODE_INSERT);
+#endif // _DEBUG
+
+ /*********************************************************************/
+ /* We used the file name relative to recorded datapath. */
+ /*********************************************************************/
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ /*********************************************************************/
+ /* Under Win32 the whole file will be mapped so we can use it as */
+ /* if it were entirely read into virtual memory. */
+ /* Firstly we check whether this file have been already mapped. */
+ /*********************************************************************/
+ if (mode == MODE_READ) {
+ for (fp = dbuserp->Openlist; fp; fp = fp->Next)
+ if (fp->Type == TYPE_FB_MAP && !stricmp(fp->Fname, filename)
+ && fp->Count && fp->Mode == mode)
+ break;
+
+ if (trace(1))
+ htrc("Mapping file, fp=%p\n", fp);
+
+ } else
+ fp = NULL;
+
+ if (fp) {
+ /*******************************************************************/
+ /* File already mapped. Just increment use count and get pointer. */
+ /*******************************************************************/
+ fp->Count++;
+ Memory = fp->Memory;
+ len = fp->Length;
+ } else {
+ /*******************************************************************/
+ /* If required, delete the whole file if no filtering is implied. */
+ /*******************************************************************/
+ bool del;
+ HANDLE hFile;
+ MEMMAP mm;
+
+ del = mode == MODE_DELETE && !Tdbp->GetNext();
+
+ if (del)
+ DelRows = Cardinality(g);
+
+ /*******************************************************************/
+ /* Create the mapping file object. */
+ /*******************************************************************/
+ hFile = CreateFileMap(g, filename, &mm, mode, del);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+
+ if (!(*g->Message))
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "map", (int) rc, filename);
+
+ if (trace(1))
+ htrc("CreateFileMap: %s\n", g->Message);
+
+ return (mode == MODE_READ && rc == ENOENT)
+ ? false : true;
+// ? PushWarning(g, Tdbp) : true; --> assert fails into MariaDB
+ } // endif hFile
+
+ /*******************************************************************/
+ /* Get the file size. */
+ /*******************************************************************/
+ len = (size_t)mm.lenL;
+
+ if (mm.lenH)
+ len += ((size_t)mm.lenH * 0x000000001LL);
+
+ Memory = (char *)mm.memory;
+
+ if (!len) { // Empty or deleted file
+ CloseFileHandle(hFile);
+ Tdbp->ResetSize();
+ return false;
+ } // endif len
+
+ if (!Memory) {
+ CloseFileHandle(hFile);
+ sprintf(g->Message, MSG(MAP_VIEW_ERROR),
+ filename, GetLastError());
+ return true;
+ } // endif Memory
+
+#if defined(_WIN32)
+ if (mode != MODE_DELETE) {
+#else // !_WIN32
+ if (mode == MODE_READ) {
+#endif // !_WIN32
+ CloseFileHandle(hFile); // Not used anymore
+ hFile = INVALID_HANDLE_VALUE; // For Fblock
+ } // endif Mode
+
+ /*******************************************************************/
+ /* Link a Fblock. This make possible to reuse already opened maps */
+ /* and also to automatically unmap them in case of error g->jump. */
+ /* Note: block can already exist for previously closed file. */
+ /*******************************************************************/
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ fp->Type = TYPE_FB_MAP;
+ fp->Fname = PlugDup(g, filename);
+ fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = fp;
+ fp->Count = 1;
+ fp->Length = len;
+ fp->Memory = Memory;
+ fp->Mode = mode;
+ fp->File = NULL;
+ fp->Handle = hFile; // Used for Delete
+ } // endif fp
+
+ To_Fb = fp; // Useful when closing
+
+ /*********************************************************************/
+ /* The pseudo "buffer" is here the entire file mapping view. */
+ /*********************************************************************/
+ Fpos = Mempos = Memory;
+ Top = Memory + len;
+
+ if (trace(1))
+ htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n",
+ fp, fp->Count, Memory, len, Top);
+
+ return AllocateBuffer(g); // Useful for DBF files
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int MAPFAM::GetRowID(void)
+ {
+ return Rows;
+ } // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int MAPFAM::GetPos(void)
+ {
+ return (int)(Fpos - Memory);
+ } // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: return the position of next record. */
+/***********************************************************************/
+int MAPFAM::GetNextPos(void)
+ {
+ return (int)(Mempos - Memory);
+ } // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool MAPFAM::SetPos(PGLOBAL g, int pos)
+ {
+ Fpos = Mempos = Memory + pos;
+
+ if (Mempos >= Top || Mempos < Memory) {
+ strcpy(g->Message, MSG(INV_MAP_POS));
+ return true;
+ } // endif Mempos
+
+ Placed = true;
+ return false;
+ } // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/***********************************************************************/
+bool MAPFAM::RecordPos(PGLOBAL)
+ {
+ Fpos = Mempos;
+ return false;
+ } // end of RecordPos
+
+/***********************************************************************/
+/* Initialize Fpos and Mempos for indexed DELETE. */
+/***********************************************************************/
+int MAPFAM::InitDelete(PGLOBAL, int fpos, int spos)
+ {
+ Fpos = Memory + (ptrdiff_t)fpos;
+ Mempos = Memory + (ptrdiff_t)spos;
+ return RC_OK;
+ } // end of InitDelete
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int MAPFAM::SkipRecord(PGLOBAL g, bool header)
+ {
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ // Skip this record
+ while (*Mempos++ != '\n') // What about Unix ???
+ if (Mempos == Top)
+ return RC_EF;
+
+ // Update progress information
+ dup->ProgCur = GetPos();
+
+ if (header)
+ Fpos = Tpos = Spos = Mempos; // For Delete
+
+ return RC_OK;
+ } // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a mapped text file. */
+/***********************************************************************/
+int MAPFAM::ReadBuffer(PGLOBAL g)
+ {
+ int rc, len, n = 1;
+
+ // Are we at the end of the memory
+ if (Mempos >= Top) {
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+ else if (Tdbp->GetAmType() == TYPE_AM_CSV && ((PTDBCSV)Tdbp)->Header)
+ if ((rc = SkipRecord(g, true)) != RC_OK)
+ return rc;
+
+ } // endif Mempos
+
+
+ if (!Placed) {
+ /*******************************************************************/
+ /* Record file position in case of UPDATE or DELETE. */
+ /*******************************************************************/
+ next:
+ Fpos = Mempos;
+ CurBlk = (int)Rows++;
+
+ /*******************************************************************/
+ /* Check whether optimization on ROWID */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ /* falls through */
+ case RC_NF:
+ // Skip this record
+ if ((rc = SkipRecord(g, false)) != RC_OK)
+ return rc;
+
+ goto next;
+ } // endswitch rc
+
+ } else
+ Placed = false;
+
+ // Immediately calculate next position (Used by DeleteDB)
+ while (*Mempos++ != '\n') // What about Unix ???
+ if (Mempos == Top) {
+ n = 0;
+ break;
+ } // endif Mempos
+
+ // Set caller line buffer
+ len = (int)(Mempos - Fpos) - n;
+
+ // Don't rely on ENDING setting
+ if (len > 0 && *(Mempos - 2) == '\r')
+ len--; // Line ends by CRLF
+
+ memcpy(Tdbp->GetLine(), Fpos, len);
+ Tdbp->GetLine()[len] = '\0';
+ return RC_OK;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for MAP access method. */
+/***********************************************************************/
+int MAPFAM::WriteBuffer(PGLOBAL g __attribute__((unused)))
+ {
+#if defined(_DEBUG)
+ // Insert mode is no more handled using file mapping
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ strcpy(g->Message, MSG(NO_MAP_INSERT));
+ return RC_FX;
+ } // endif
+#endif // _DEBUG
+
+ /*********************************************************************/
+ /* Copy the updated record back into the memory mapped file. */
+ /*********************************************************************/
+ memcpy(Fpos, Tdbp->GetLine(), strlen(Tdbp->GetLine()));
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for MAP (and FIX?) access methods. */
+/* Lines between deleted lines are moved in the mapfile view. */
+/***********************************************************************/
+int MAPFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ int n;
+
+ if (trace(1))
+ htrc("MAP DeleteDB: irc=%d mempos=%p tobuf=%p Tpos=%p Spos=%p\n",
+ irc, Mempos, To_Buf, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the top of map position. */
+ /*******************************************************************/
+ Fpos = Top;
+
+ if (trace(1))
+ htrc("Fpos placed at file top=%p\n", Fpos);
+
+ } // endif irc
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete. Move of eventual preceding lines is */
+ /* not required here, just setting of future Spos and Tpos. */
+ /*******************************************************************/
+ Tpos = Spos = Fpos;
+ } else if ((n = (int)(Fpos - Spos)) > 0) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ memmove(Tpos, Spos, n);
+ Tpos += n;
+
+ if (trace(1))
+ htrc("move %d bytes\n", n);
+
+ } // endif n
+
+ if (irc == RC_OK) {
+ Spos = Mempos; // New start position
+
+ if (trace(1))
+ htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos);
+
+ } else if (To_Fb) { // Can be NULL for deleted files
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /* We must firstly Unmap the view and use the saved file handle */
+ /* to put an EOF at the end of the copied part of the file. */
+ /*******************************************************************/
+ PFBLOCK fp = To_Fb;
+
+ CloseMemMap(fp->Memory, (size_t)fp->Length);
+ fp->Count = 0; // Avoid doing it twice
+
+ if (!Abort) {
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+ n = (int)(Tpos - Memory);
+
+#if defined(_WIN32)
+ DWORD drc = SetFilePointer(fp->Handle, n, NULL, FILE_BEGIN);
+
+ if (drc == 0xFFFFFFFF) {
+ sprintf(g->Message, MSG(FUNCTION_ERROR),
+ "SetFilePointer", GetLastError());
+ CloseHandle(fp->Handle);
+ return RC_FX;
+ } // endif
+
+ if (trace(1))
+ htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc);
+
+ if (!SetEndOfFile(fp->Handle)) {
+ sprintf(g->Message, MSG(FUNCTION_ERROR),
+ "SetEndOfFile", GetLastError());
+ CloseHandle(fp->Handle);
+ return RC_FX;
+ } // endif
+
+#else // UNIX
+ if (ftruncate(fp->Handle, (off_t)n)) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(fp->Handle);
+ return RC_FX;
+ } // endif
+
+#endif // UNIX
+ } // endif Abort
+
+#if defined(_WIN32)
+ CloseHandle(fp->Handle);
+#else // UNIX
+ close(fp->Handle);
+#endif // UNIX
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Table file close routine for MAP access method. */
+/***********************************************************************/
+void MAPFAM::CloseTableFile(PGLOBAL g, bool)
+ {
+ PlugCloseFile(g, To_Fb);
+//To_Fb = NULL; // To get correct file size in Cardinality
+
+ if (trace(1))
+ htrc("MAP Close: closing %s count=%d\n",
+ To_File, (To_Fb) ? To_Fb->Count : 0);
+
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for MAP access method. */
+/***********************************************************************/
+void MAPFAM::Rewind(void)
+ {
+ Mempos = Memory;
+ } // end of Rewind
+
+/* --------------------------- Class MBKFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+MBKFAM::MBKFAM(PDOSDEF tdp) : MAPFAM(tdp)
+ {
+ Blocked = true;
+ Block = tdp->GetBlock();
+ Last = tdp->GetLast();
+ Nrec = tdp->GetElemt();
+ BlkPos = tdp->GetTo_Pos();
+ CurNum = Nrec;
+ } // end of MBKFAM standard constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void MBKFAM::Reset(void)
+ {
+ MAPFAM::Reset();
+ CurNum = Nrec; // To start by a new block
+ } // end of Reset
+
+/***********************************************************************/
+/* Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int MBKFAM::Cardinality(PGLOBAL g)
+ {
+ return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int MBKFAM::SkipRecord(PGLOBAL, bool)
+ {
+ return RC_OK;
+ } // end of SkipRecord
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int MBKFAM::GetRowID(void)
+ {
+ return CurNum + Nrec * CurBlk + 1;
+ } // end of GetRowID
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a mapped Fix file. */
+/***********************************************************************/
+int MBKFAM::ReadBuffer(PGLOBAL g)
+ {
+ int rc, len;
+
+ /*********************************************************************/
+ /* Sequential block reading when Placed is not true. */
+ /*********************************************************************/
+ if (Placed) {
+ Placed = false;
+ } else if (Mempos >= Top) { // Are we at the end of the memory
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ } else if (++CurNum < Nrec) {
+ Fpos = Mempos;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ next:
+ if (++CurBlk >= Block)
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ /*******************************************************************/
+ /* Before reading a new block, check whether block optimization */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ break;
+ case RC_NF:
+ goto next;
+ } // endswitch rc
+
+ Fpos = Mempos = Memory + BlkPos[CurBlk];
+ } // endif's
+
+ // Immediately calculate next position (Used by DeleteDB)
+ while (*Mempos++ != '\n') // What about Unix ???
+ if (Mempos == Top)
+ break;
+
+ // Set caller line buffer
+ len = (int)(Mempos - Fpos) - Ending;
+ memcpy(Tdbp->GetLine(), Fpos, len);
+ Tdbp->GetLine()[len] = '\0';
+ return RC_OK;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Rewind routine for FIX MAP access method. */
+/***********************************************************************/
+void MBKFAM::Rewind(void)
+ {
+ Mempos = Memory + Headlen;
+ CurBlk = -1;
+ CurNum = Nrec;
+ } // end of Rewind
+
+/* --------------------------- Class MPXFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+MPXFAM::MPXFAM(PDOSDEF tdp) : MBKFAM(tdp)
+ {
+ Blksize = tdp->GetBlksize();
+ Padded = tdp->GetPadded();
+
+ if (Padded && Blksize)
+ Nrec = Blksize / Lrecl;
+ else {
+ Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN;
+ Blksize = Nrec * Lrecl;
+ Padded = false;
+ } // endelse
+
+ CurNum = Nrec;
+ } // end of MPXFAM standard constructor
+
+#if 0 // MBKFAM routine is correct
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int MPXFAM::GetRowID(void)
+ {
+ return (Mempos - Memory - Headlen) / Lrecl;
+ } // end of GetRowID
+#endif
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int MPXFAM::GetPos(void)
+ {
+ return (CurNum + Nrec * CurBlk); // Computed file index
+ } // end of GetPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool MPXFAM::SetPos(PGLOBAL g, int pos)
+ {
+ if (pos < 0) {
+ strcpy(g->Message, MSG(INV_REC_POS));
+ return true;
+ } // endif recpos
+
+ CurBlk = pos / Nrec;
+ CurNum = pos % Nrec;
+ Fpos = Mempos = Memory + Headlen + pos * Lrecl;
+
+ // Indicate the table position was externally set
+ Placed = true;
+ return false;
+ } // end of SetPos
+
+/***********************************************************************/
+/* Initialize CurBlk, CurNum, Mempos and Fpos for indexed DELETE. */
+/***********************************************************************/
+int MPXFAM::InitDelete(PGLOBAL, int fpos, int)
+ {
+ Fpos = Memory + Headlen + (ptrdiff_t)fpos * Lrecl;
+ Mempos = Fpos + Lrecl;
+ return RC_OK;
+ } // end of InitDelete
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a mapped Fix file. */
+/***********************************************************************/
+int MPXFAM::ReadBuffer(PGLOBAL g)
+ {
+ int rc;
+
+ /*********************************************************************/
+ /* Sequential block reading when Placed is not true. */
+ /*********************************************************************/
+ if (Placed) {
+ Placed = false;
+ } else if (Mempos >= Top) { // Are we at the end of the memory
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ } else if (++CurNum < Nrec) {
+ Fpos = Mempos;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ next:
+ if (++CurBlk >= Block)
+ return GetNext(g);
+
+ /*******************************************************************/
+ /* Before reading a new block, check whether block optimization */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ if ((rc = GetNext(g)) != RC_OK)
+ return rc;
+
+ break;
+ case RC_NF:
+ goto next;
+ } // endswitch rc
+
+ Fpos = Mempos = Headlen + Memory + CurBlk * Blksize;
+ } // endif's
+
+ Tdbp->SetLine(Mempos);
+
+ // Immediately calculate next position (Used by DeleteDB)
+ Mempos += Lrecl;
+ return RC_OK;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for MAP access method. */
+/***********************************************************************/
+int MPXFAM::WriteBuffer(PGLOBAL g __attribute__((unused)))
+ {
+#if defined(_DEBUG)
+ // Insert mode is no more handled using file mapping
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ strcpy(g->Message, MSG(NO_MAP_INSERT));
+ return RC_FX;
+ } // endif
+#endif // _DEBUG
+
+ // In Update mode, file was modified in memory
+ return RC_OK;
+ } // end of WriteBuffer
+
diff --git a/storage/connect/filamap.h b/storage/connect/filamap.h
new file mode 100644
index 00000000..774eb8b9
--- /dev/null
+++ b/storage/connect/filamap.h
@@ -0,0 +1,120 @@
+/*************** FilAMap H Declares Source Code File (.H) **************/
+/* Name: FILAMAP.H Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */
+/* */
+/* This file contains the MAP file access method classes declares. */
+/***********************************************************************/
+#ifndef __FILAMAP_H
+#define __FILAMAP_H
+
+#include "block.h"
+#include "filamtxt.h"
+
+typedef class MAPFAM *PMAPFAM;
+
+/***********************************************************************/
+/* This is the variable file access method using file mapping. */
+/***********************************************************************/
+class DllExport MAPFAM : public TXTFAM {
+ friend class TDBJSON;
+ public:
+ // Constructor
+ MAPFAM(PDOSDEF tdp);
+ MAPFAM(PMAPFAM tmfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_MAP;}
+ virtual int GetPos(void);
+ virtual int GetNextPos(void);
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) MAPFAM(this);}
+
+ // Methods
+ virtual void Reset(void);
+ virtual int GetFileLength(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;}
+ virtual int MaxBlkSize(PGLOBAL g, int s) {return s;}
+ virtual int GetRowID(void);
+ virtual bool RecordPos(PGLOBAL g);
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int SkipRecord(PGLOBAL g, bool header);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual bool DeferReading(void) {return false;}
+ virtual int GetNext(PGLOBAL g) {return RC_EF;}
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ protected:
+ virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+
+ // Members
+ char *Memory; // Pointer on file mapping view.
+ char *Mempos; // Position of next data to read
+ char *Fpos; // Position of last read record
+ char *Tpos; // Target Position for delete move
+ char *Spos; // Start position for delete move
+ char *Top; // Mark end of file mapping view
+ }; // end of class MAPFAM
+
+/***********************************************************************/
+/* This is the blocked file access method using file mapping. */
+/***********************************************************************/
+class DllExport MBKFAM : public MAPFAM {
+ public:
+ // Constructor
+ MBKFAM(PDOSDEF tdp);
+ MBKFAM(PMAPFAM tmfp) : MAPFAM(tmfp) {}
+
+ // Implementation
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) MBKFAM(this);}
+
+ // Methods
+ virtual void Reset(void);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int MaxBlkSize(PGLOBAL g, int s)
+ {return TXTFAM::MaxBlkSize(g, s);}
+ virtual int GetRowID(void);
+ virtual int SkipRecord(PGLOBAL g, bool header);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual void Rewind(void);
+
+ protected:
+ // No additional members
+ }; // end of class MBKFAM
+
+/***********************************************************************/
+/* This is the fixed file access method using file mapping. */
+/***********************************************************************/
+class DllExport MPXFAM : public MBKFAM {
+ public:
+ // Constructor
+ MPXFAM(PDOSDEF tdp);
+ MPXFAM(PMAPFAM tmfp) : MBKFAM(tmfp) {}
+
+ // Implementation
+ virtual int GetPos(void);
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) MPXFAM(this);}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g) {return TXTFAM::Cardinality(g);}
+ virtual int MaxBlkSize(PGLOBAL g, int s)
+ {return TXTFAM::MaxBlkSize(g, s);}
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int GetNextPos(void) {return GetPos() + 1;}
+ virtual bool DeferReading(void) {return false;}
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+
+ protected:
+ virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+
+ // No additional members
+ }; // end of class MPXFAM
+
+#endif // __FILAMAP_H
diff --git a/storage/connect/filamdbf.cpp b/storage/connect/filamdbf.cpp
new file mode 100644
index 00000000..3d1718b9
--- /dev/null
+++ b/storage/connect/filamdbf.cpp
@@ -0,0 +1,1202 @@
+/*********** File AM Dbf C++ Program Source Code File (.CPP) ****************/
+/* PROGRAM NAME: FILAMDBF */
+/* ------------- */
+/* Version 1.8 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2017 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the DBF file access method classes. */
+/* */
+/* ACKNOWLEDGEMENT: */
+/* ---------------- */
+/* Somerset Data Systems, Inc. (908) 766-5845 */
+/* Version 1.2 April 6, 1991 */
+/* Programmer: Jay Parsons */
+/****************************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+//#include <errno.h>
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#else // !UNIX
+//#include <io.h>
+#endif // !UNIX
+//#include <fcntl.h>
+#endif // !_WIN32
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tabdos.h is header containing the TABDOS class declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "filamdbf.h"
+#include "filamzip.h"
+#include "tabdos.h"
+#include "valblk.h"
+#define NO_FUNC
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+
+/****************************************************************************/
+/* Definitions. */
+/****************************************************************************/
+#define HEADLEN 32 /* sizeof ( mainhead or thisfield ) */
+//efine MEMOLEN 10 /* length of memo field in .dbf */
+#define DBFTYPE 3 /* value of bits 0 and 1 if .dbf */
+#define EOH 0x0D /* end-of-header marker in .dbf file */
+
+/****************************************************************************/
+/* First 32 bytes of a .dbf file. */
+/* Note: some reserved fields are used here to store info (Fields) */
+/****************************************************************************/
+typedef struct _dbfheader {
+//uchar Dbf :2; /* both 1 for dBASE III or IV .dbf */
+//uchar :1;
+//uchar Db4dbt:1; /* 1 if a dBASE IV-type .dbt exists */
+//uchar Dbfox :4; /* FoxPro if equal to 3 */
+ uchar Version; /* Version information flags */
+ char Filedate[3]; /* date, YYMMDD, binary. YY=year-1900 */
+ private:
+ /* The following four members are stored in little-endian format on disk */
+ char m_RecordsBuf[4]; /* records in the file */
+ char m_HeadlenBuf[2]; /* bytes in the header */
+ char m_ReclenBuf[2]; /* bytes in a record */
+ char m_FieldsBuf[2]; /* Reserved but used to store fields */
+ public:
+ char Incompleteflag; /* 01 if incomplete, else 00 */
+ char Encryptflag; /* 01 if encrypted, else 00 */
+ char Reserved2[12]; /* for LAN use */
+ char Mdxflag; /* 01 if production .mdx, else 00 */
+ char Language; /* Codepage */
+ char Reserved3[2];
+
+ uint Records(void) const {return uint4korr(m_RecordsBuf);}
+ ushort Headlen(void) const {return uint2korr(m_HeadlenBuf);}
+ ushort Reclen(void) const {return uint2korr(m_ReclenBuf);}
+ ushort Fields(void) const {return uint2korr(m_FieldsBuf);}
+
+ void SetHeadlen(ushort num) {int2store(m_HeadlenBuf, num);}
+ void SetReclen(ushort num) {int2store(m_ReclenBuf, num);}
+ void SetFields(ushort num) {int2store(m_FieldsBuf, num);}
+ } DBFHEADER;
+
+/****************************************************************************/
+/* Column field descriptor of a .dbf file. */
+/****************************************************************************/
+typedef struct _descriptor {
+ char Name[11]; /* field name, in capitals, null filled*/
+ char Type; /* field type, C, D, F, L, M or N */
+ uint Offset; /* used in memvars, not in files. */
+ uchar Length; /* field length */
+ uchar Decimals; /* number of decimal places */
+ short Reserved4;
+ char Workarea; /* ??? */
+ char Reserved5[2];
+ char Setfield; /* ??? */
+ char Reserved6[7];
+ char Mdxfield; /* 01 if tag field in production .mdx */
+ } DESCRIPTOR;
+
+/****************************************************************************/
+/* dbfhead: Routine to analyze a .dbf header. */
+/* Parameters: */
+/* PGLOBAL g -- pointer to the Plug Global structure */
+/* FILE *file -- pointer to file to analyze */
+/* PSZ fn -- pathname of the file to analyze */
+/* DBFHEADER *buf -- pointer to _dbfheader structure */
+/* Returns: */
+/* RC_OK, RC_NF, RC_INFO, or RC_FX if error. */
+/* Side effects: */
+/* Moves file pointer to byte 32; fills buffer at buf with */
+/* first 32 bytes of file. */
+/****************************************************************************/
+static int dbfhead(PGLOBAL g, FILE *file, PCSZ fn, DBFHEADER *buf)
+ {
+ char endmark[2];
+ int dbc = 2, rc = RC_OK;
+
+ *g->Message = '\0';
+
+ // Read the first 32 bytes into buffer
+ if (fread(buf, HEADLEN, 1, file) != 1) {
+ strcpy(g->Message, MSG(NO_READ_32));
+ return RC_NF;
+ } // endif fread
+
+ // Check first byte to be sure of .dbf type
+ if ((buf->Version & 0x03) != DBFTYPE) {
+ strcpy(g->Message, MSG(NOT_A_DBF_FILE));
+ rc = RC_INFO;
+
+ if ((buf->Version & 0x30) == 0x30) {
+ strcpy(g->Message, MSG(FOXPRO_FILE));
+ dbc = 264; // FoxPro database container
+ } // endif Version
+
+ } else
+ strcpy(g->Message, MSG(DBASE_FILE));
+
+ // Check last byte(s) of header
+ if (fseek(file, buf->Headlen() - dbc, SEEK_SET) != 0) {
+ sprintf(g->Message, MSG(BAD_HEADER), fn);
+ return RC_FX;
+ } // endif fseek
+
+ if (fread(&endmark, 2, 1, file) != 1) {
+ strcpy(g->Message, MSG(BAD_HEAD_END));
+ return RC_FX;
+ } // endif fread
+
+ // Some files have just 1D others have 1D00 following fields
+ if (endmark[0] != EOH && endmark[1] != EOH) {
+ sprintf(g->Message, MSG(NO_0DH_HEAD), dbc);
+
+ if (rc == RC_OK)
+ return RC_FX;
+
+ } // endif endmark
+
+ // Calculate here the number of fields while we have the dbc info
+ buf->SetFields((buf->Headlen() - dbc - 1) / 32);
+ fseek(file, HEADLEN, SEEK_SET);
+ return rc;
+ } // end of dbfhead
+
+/****************************************************************************/
+/* dbfields: Analyze a DBF header and set the table fields number. */
+/* Parameters: */
+/* PGLOBAL g -- pointer to the CONNECT Global structure */
+/* DBFHEADER *hdrp -- pointer to _dbfheader structure */
+/* Returns: */
+/* RC_OK, RC_INFO, or RC_FX if error. */
+/****************************************************************************/
+static int dbfields(PGLOBAL g, DBFHEADER* hdrp)
+{
+ char* endmark;
+ int dbc = 2, rc = RC_OK;
+
+ *g->Message = '\0';
+
+ // Check first byte to be sure of .dbf type
+ if ((hdrp->Version & 0x03) != DBFTYPE) {
+ strcpy(g->Message, MSG(NOT_A_DBF_FILE));
+ rc = RC_INFO;
+
+ if ((hdrp->Version & 0x30) == 0x30) {
+ strcpy(g->Message, MSG(FOXPRO_FILE));
+ dbc = 264; // FoxPro database container
+ } // endif Version
+
+ } else
+ strcpy(g->Message, MSG(DBASE_FILE));
+
+ // Check last byte(s) of header
+ endmark = (char*)hdrp + hdrp->Headlen() - dbc;
+
+ // Some headers just have 1D others have 1D00 following fields
+ if (endmark[0] != EOH && endmark[1] != EOH) {
+ sprintf(g->Message, MSG(NO_0DH_HEAD), dbc);
+
+ if (rc == RC_OK)
+ return RC_FX;
+
+ } // endif endmark
+
+ // Calculate here the number of fields while we have the dbc info
+ hdrp->SetFields((hdrp->Headlen() - dbc - 1) / 32);
+ return rc;
+} // end of dbfields
+
+/* -------------------------- Function DBFColumns ------------------------- */
+
+/****************************************************************************/
+/* DBFColumns: constructs the result blocks containing the description */
+/* of all the columns of a DBF file that will be retrieved by #GetData. */
+/****************************************************************************/
+PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, PTOS topt, bool info)
+ {
+ int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
+ TYPE_INT, TYPE_INT, TYPE_SHORT};
+ XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME,
+ FLD_PREC, FLD_LENGTH, FLD_SCALE};
+ unsigned int length[] = {11, 6, 8, 10, 10, 6};
+ char buf[2], filename[_MAX_PATH];
+ int ncol = sizeof(buftyp) / sizeof(int);
+ int rc, type, len, field, fields;
+ bool bad, mul;
+ PCSZ target, pwd;
+ DBFHEADER mainhead, *hp;
+ DESCRIPTOR thisfield, *tfp;
+ FILE *infile = NULL;
+ UNZIPUTL *zutp = NULL;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ if (trace(1))
+ htrc("DBFColumns: File %s\n", SVP(fn));
+
+ if (!info) {
+ if (!fn) {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return NULL;
+ } // endif fn
+
+ /************************************************************************/
+ /* Open the input file. */
+ /************************************************************************/
+ PlugSetPath(filename, fn, dp);
+
+ if (topt->zipped) {
+ target = GetStringTableOption(g, topt, "Entry", NULL);
+ mul = (target && *target) ? strchr(target, '*') || strchr(target, '?')
+ : false;
+ mul = GetBooleanTableOption(g, topt, "Mulentries", mul);
+
+ if (mul) {
+ strcpy(g->Message, "Cannot find column definition for multiple entries");
+ return NULL;
+ } // endif Multiple
+
+ pwd = GetStringTableOption(g, topt, "Password", NULL);
+ zutp = new(g) UNZIPUTL(target, pwd, mul);
+
+ if (!zutp->OpenTable(g, MODE_READ, filename))
+ hp = (DBFHEADER*)zutp->memory;
+ else
+ return NULL;
+
+ /**********************************************************************/
+ /* Set the table fields number. */
+ /**********************************************************************/
+ if ((rc = dbfields(g, hp)) == RC_FX) {
+ zutp->close();
+ return NULL;
+ } // endif dbfields
+
+ tfp = (DESCRIPTOR*)hp;
+ } else {
+ if (!(infile = global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb")))
+ return NULL;
+ else
+ hp = &mainhead;
+
+ /**********************************************************************/
+ /* Get the first 32 bytes of the header. */
+ /**********************************************************************/
+ if ((rc = dbfhead(g, infile, filename, hp)) == RC_FX) {
+ fclose(infile);
+ return NULL;
+ } // endif dbfhead
+
+ tfp = &thisfield;
+ } // endif zipped
+
+ /************************************************************************/
+ /* Get the number of the table fields. */
+ /************************************************************************/
+ fields = hp->Fields();
+ } else
+ fields = 0;
+
+ qrp = PlgAllocResult(g, ncol, fields, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, true, false);
+
+ if (info || !qrp) {
+ if (infile)
+ fclose(infile);
+ else if (zutp)
+ zutp->close();
+
+ return qrp;
+ } // endif info
+
+ if (trace(1)) {
+ htrc("Structure of %s\n", filename);
+ htrc("headlen=%hd reclen=%hd degree=%d\n",
+ hp->Headlen(), hp->Reclen(), fields);
+ htrc("flags(iem)=%d,%d,%d cp=%d\n", hp->Incompleteflag,
+ hp->Encryptflag, hp->Mdxflag, hp->Language);
+ htrc("%hd records, last changed %02d/%02d/%d\n",
+ hp->Records(), hp->Filedate[1], hp->Filedate[2],
+ hp->Filedate[0] + ((hp->Filedate[0] <= 30) ? 2000 : 1900));
+ htrc("Field Type Offset Len Dec Set Mdx\n");
+ } // endif trace
+
+ buf[1] = '\0';
+
+ /**************************************************************************/
+ /* Do it field by field. We are at byte 32 of file. */
+ /**************************************************************************/
+ for (field = 0; field < fields; field++) {
+ bad = FALSE;
+
+ if (topt->zipped) {
+ tfp = (DESCRIPTOR*)((char*)tfp + HEADLEN);
+ } else if (fread(tfp, HEADLEN, 1, infile) != 1) {
+ sprintf(g->Message, MSG(ERR_READING_REC), field+1, fn);
+ goto err;
+ } // endif fread
+
+ len = tfp->Length;
+
+ if (trace(1))
+ htrc("%-11s %c %6ld %3d %2d %3d %3d\n",
+ tfp->Name, tfp->Type, tfp->Offset, len,
+ tfp->Decimals, tfp->Setfield, tfp->Mdxfield);
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ switch (tfp->Type) {
+ case 'C': // Characters
+ case 'L': // Logical 'T' or 'F' or space
+ type = TYPE_STRING;
+ break;
+ case 'M': // Memo a .DBT block number
+ case 'B': // Binary a .DBT block number
+ case 'G': // Ole a .DBT block number
+ type = TYPE_STRING;
+ break;
+ //case 'I': // Long
+ //case '+': // Autoincrement
+ // type = TYPE_INT;
+ // break;
+ case 'N':
+ type = (tfp->Decimals) ? TYPE_DOUBLE
+ : (len > 10) ? TYPE_BIGINT : TYPE_INT;
+ break;
+ case 'F': // Float
+ //case 'O': // Double
+ type = TYPE_DOUBLE;
+ break;
+ case 'D':
+ type = TYPE_DATE; // Is this correct ???
+ break;
+ default:
+ if (!info) {
+ sprintf(g->Message, MSG(BAD_DBF_TYPE), tfp->Type
+ , tfp->Name);
+ goto err;
+ } // endif info
+
+ type = TYPE_ERROR;
+ bad = TRUE;
+ } // endswitch Type
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(tfp->Name, field);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue((int)type, field);
+ crp = crp->Next; // Type Name
+
+ if (bad) {
+ buf[0] = tfp->Type;
+ crp->Kdata->SetValue(buf, field);
+ } else
+ crp->Kdata->SetValue(GetTypeName(type), field);
+
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue((int)tfp->Length, field);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue((int)tfp->Length, field);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue((int)tfp->Decimals, field);
+ } // endfor field
+
+ qrp->Nblin = field;
+
+ if (infile)
+ fclose(infile);
+ else if (zutp)
+ zutp->close();
+
+#if 0
+ if (info) {
+ /************************************************************************/
+ /* Prepare return message for dbfinfo command. */
+ /************************************************************************/
+ char buf[64];
+
+ sprintf(buf,
+ "Ver=%02x ncol=%hu nlin=%u lrecl=%hu headlen=%hu date=%02d/%02d/%02d",
+ hp->Version, fields, hp->Records, hp->Reclen,
+ hp->Headlen, hp->Filedate[0], hp->Filedate[1],
+ hp->Filedate[2]);
+
+ strcat(g->Message, buf);
+ } // endif info
+#endif // 0
+
+ /**************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /**************************************************************************/
+ return qrp;
+
+err:
+ if (infile)
+ fclose(infile);
+ else if (zutp)
+ zutp->close();
+
+ return NULL;
+ } // end of DBFColumns
+
+/* ---------------------------- Class DBFBASE ----------------------------- */
+
+/****************************************************************************/
+/* Constructors. */
+/****************************************************************************/
+DBFBASE::DBFBASE(PDOSDEF tdp)
+ {
+ Records = 0;
+ Nerr = 0;
+ Maxerr = tdp->Maxerr;
+ Accept = tdp->Accept;
+ ReadMode = tdp->ReadMode;
+ } // end of DBFBASE standard constructor
+
+DBFBASE::DBFBASE(DBFBASE *txfp)
+ {
+ Records = txfp->Records;
+ Nerr = txfp->Nerr;
+ Maxerr = txfp->Maxerr;
+ Accept = txfp->Accept;
+ ReadMode = txfp->ReadMode;
+ } // end of DBFBASE copy constructor
+
+/****************************************************************************/
+/* ScanHeader: scan the DBF file header for number of records, record size,*/
+/* and header length. Set Records, check that Reclen is equal to lrecl and */
+/* return the header length or 0 in case of error. */
+/****************************************************************************/
+int DBFBASE::ScanHeader(PGLOBAL g, PCSZ fn, int lrecl, int *rln, PCSZ defpath)
+ {
+ int rc;
+ char filename[_MAX_PATH];
+ DBFHEADER header;
+ FILE *infile;
+
+ /************************************************************************/
+ /* Open the input file. */
+ /************************************************************************/
+ PlugSetPath(filename, fn, defpath);
+
+ if (!(infile= global_fopen(g, MSGID_CANNOT_OPEN, filename, "rb")))
+ return 0; // Assume file does not exist
+
+ /************************************************************************/
+ /* Get the first 32 bytes of the header. */
+ /************************************************************************/
+ rc = dbfhead(g, infile, filename, &header);
+ fclose(infile);
+
+ if (rc == RC_NF) {
+ Records = 0;
+ return 0;
+ } else if (rc == RC_FX)
+ return -1;
+
+ *rln = (int)header.Reclen();
+ Records = (int)header.Records();
+ return (int)header.Headlen();
+ } // end of ScanHeader
+
+/* ---------------------------- Class DBFFAM ------------------------------ */
+
+/****************************************************************************/
+/* Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/****************************************************************************/
+int DBFFAM::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return 1;
+
+ if (!Headlen) {
+ int rln = 0; // Record length in the file header
+
+ Headlen = ScanHeader(g, To_File, Lrecl, &rln, Tdbp->GetPath());
+
+ if (Headlen < 0)
+ return -1; // Error in ScanHeader
+
+ if (rln && Lrecl != rln) {
+ // This happens always on some Linux platforms
+ sprintf(g->Message, MSG(BAD_LRECL), Lrecl, (ushort)rln);
+
+ if (Accept) {
+ Lrecl = rln;
+ Blksize = Nrec * rln;
+ PushWarning(g, Tdbp);
+ } else
+ return -1;
+
+ } // endif rln
+
+ } // endif Headlen
+
+ // Set number of blocks for later use
+ Block = (Records > 0) ? (Records + Nrec - 1) / Nrec : 0;
+ return Records;
+ } // end of Cardinality
+
+#if 0 // Not compatible with ROWID block optimization
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int DBFFAM::GetRowID(void)
+ {
+ return Rows;
+ } // end of GetRowID
+#endif
+
+/***********************************************************************/
+/* OpenTableFile: Open a DBF table file using C standard I/Os. */
+/* Binary mode cannot be used on Insert because of EOF (CTRL+Z) char. */
+/***********************************************************************/
+bool DBFFAM::OpenTableFile(PGLOBAL g)
+ {
+ char opmode[4], filename[_MAX_PATH];
+//int ftype = Tdbp->GetFtype();
+ MODE mode = Tdbp->GetMode();
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "rb");
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = -1; // Means all lines deleted
+// DelRows = Cardinality(g); no good because of soft deleted lines
+
+ // This will erase the entire file
+ strcpy(opmode, "w");
+ Tdbp->ResetSize();
+ Records = 0;
+ break;
+ } // endif
+
+ // Selective delete
+ /* fall through */
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ strcpy(opmode, (UseTemp) ? "rb" : "r+b");
+ break;
+ case MODE_INSERT:
+ // Must be in text mode to remove an eventual EOF character
+ strcpy(opmode, "a+");
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ // Now open the file stream
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!(Stream = PlugOpenFile(g, filename, opmode))) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return (mode == MODE_READ && errno == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif Stream
+
+ if (trace(1))
+ htrc("File %s is open in mode %s\n", filename, opmode);
+
+ To_Fb = dbuserp->Openlist; // Keep track of File block
+
+ /*********************************************************************/
+ /* Allocate the line buffer. For mode Delete a bigger buffer has to */
+ /* be allocated because is it also used to move lines into the file.*/
+ /*********************************************************************/
+ return AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/****************************************************************************/
+/* Allocate the block buffer for the table. */
+/****************************************************************************/
+bool DBFFAM::AllocateBuffer(PGLOBAL g)
+ {
+ char c;
+ int rc;
+ MODE mode = Tdbp->GetMode();
+
+ Buflen = Blksize;
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (mode == MODE_INSERT) {
+#if defined(_WIN32)
+ /************************************************************************/
+ /* Now we can revert to binary mode in particular because the eventual */
+ /* writing of a new header must be done in binary mode to avoid */
+ /* translating 0A bytes (LF) into 0D0A (CRLF) by Windows in text mode. */
+ /************************************************************************/
+ if (_setmode(_fileno(Stream), _O_BINARY) == -1) {
+ sprintf(g->Message, MSG(BIN_MODE_FAIL), strerror(errno));
+ return true;
+ } // endif setmode
+#endif // _WIN32
+
+ /************************************************************************/
+ /* If this is a new file, the header must be generated. */
+ /************************************************************************/
+ int len = GetFileLength(g);
+
+ if (!len) {
+ // Make the header for this DBF table file
+ struct tm *datm;
+ int hlen, n = 0;
+ ushort reclen = 1;
+ time_t t;
+ DBFHEADER *header;
+ DESCRIPTOR *descp;
+ PCOLDEF cdp;
+ PDOSDEF tdp = (PDOSDEF)Tdbp->GetDef();
+
+ // Count the number of columns
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!(cdp->Flags & U_SPECIAL)) {
+ reclen += cdp->GetLong();
+ n++;
+ } // endif Flags
+
+ if (Lrecl != reclen) {
+ sprintf(g->Message, MSG(BAD_LRECL), Lrecl, reclen);
+
+ if (Accept) {
+ Lrecl = reclen;
+ Blksize = Nrec * Lrecl;
+ PushWarning(g, Tdbp);
+ } else
+ return true;
+
+ } // endif Lrecl
+
+ hlen = HEADLEN * (n + 1) + 2;
+ header = (DBFHEADER*)PlugSubAlloc(g, NULL, hlen);
+ memset(header, 0, hlen);
+ header->Version = DBFTYPE;
+ t = time(NULL) - (time_t)DTVAL::GetShift();
+ datm = gmtime(&t);
+ header->Filedate[0] = datm->tm_year - 100;
+ header->Filedate[1] = datm->tm_mon + 1;
+ header->Filedate[2] = datm->tm_mday;
+ header->SetHeadlen((ushort)hlen);
+ header->SetReclen(reclen);
+ descp = (DESCRIPTOR*)header;
+
+ // Currently only standard Xbase types are supported
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!(cdp->Flags & U_SPECIAL)) {
+ descp++;
+
+ switch ((c = *GetFormatType(cdp->GetType()))) {
+ case 'S': // Short integer
+ case 'L': // Large (big) integer
+ case 'T': // Tiny integer
+ c = 'N'; // Numeric
+ /* fall through */
+ case 'N': // Numeric (integer)
+ case 'F': // Float (double)
+ descp->Decimals = (uchar)cdp->F.Prec;
+ case 'C': // Char
+ case 'D': // Date
+ break;
+ default: // Should never happen
+ sprintf(g->Message, MSG(BAD_DBF_TYPE),
+ c, cdp->GetName());
+ return true;
+ } // endswitch c
+
+ strncpy(descp->Name, cdp->GetName(), 11);
+ descp->Type = c;
+ descp->Length = (uchar)cdp->GetLong();
+ } // endif Flags
+
+ *(char*)(++descp) = EOH;
+
+ // Now write the header
+ if (fwrite(header, 1, hlen, Stream) != (unsigned)hlen) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ return true;
+ } // endif fwrite
+
+ Records = 0;
+ Headlen = hlen;
+ } else if (len < 0)
+ return true; // Error in GetFileLength
+
+ /************************************************************************/
+ /* For Insert the buffer must be prepared. */
+ /************************************************************************/
+ memset(To_Buf, ' ', Buflen);
+ Rbuf = Nrec; // To be used by WriteDB
+ } else if (UseTemp) {
+ // Allocate a separate buffer so block reading can be kept
+ Dbflen = Nrec;
+ DelBuf = PlugSubAlloc(g, NULL, Blksize);
+ } // endif's
+
+ if (!Headlen) {
+ /************************************************************************/
+ /* Here is a good place to process the DBF file header */
+ /************************************************************************/
+ DBFHEADER header;
+
+ if ((rc = dbfhead(g, Stream, Tdbp->GetFile(g), &header)) == RC_OK) {
+ if (Lrecl != (int)header.Reclen()) {
+ sprintf(g->Message, MSG(BAD_LRECL), Lrecl, header.Reclen());
+
+ if (Accept) {
+ Lrecl = header.Reclen();
+ Blksize = Nrec * Lrecl;
+ PushWarning(g, Tdbp);
+ } else
+ return true;
+
+ } // endif Lrecl
+
+ Records = (int)header.Records();
+ Headlen = (int)header.Headlen();
+ } else if (rc == RC_NF) {
+ Records = 0;
+ Headlen = 0;
+ } else // RC_FX
+ return true; // Error in dbfhead
+
+ } // endif Headlen
+
+ /**************************************************************************/
+ /* Position the file at the begining of the data. */
+ /**************************************************************************/
+ if (Tdbp->GetMode() == MODE_INSERT)
+ rc = fseek(Stream, 0, SEEK_END);
+ else
+ rc = fseek(Stream, Headlen, SEEK_SET);
+
+ if (rc) {
+ sprintf(g->Message, MSG(BAD_DBF_FILE), Tdbp->GetFile(g));
+ return true;
+ } // endif fseek
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Reset buffer access according to indexing and to mode. */
+/* >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
+/***********************************************************************/
+void DBFFAM::ResetBuffer(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* If access is random, performances can be much better when the */
+ /* reads are done on only one row, except for small tables that can */
+ /* be entirely read in one block. */
+ /*********************************************************************/
+ if (Tdbp->GetKindex() && ReadBlks != 1) {
+ Nrec = 1; // Better for random access
+ Rbuf = 0;
+ Blksize = Lrecl;
+ OldBlk = -2; // Has no meaning anymore
+ Block = Tdbp->Cardinality(g); // Blocks are one line now
+ } // endif Mode
+
+ } // end of ResetBuffer
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a DBF file. */
+/***********************************************************************/
+int DBFFAM::ReadBuffer(PGLOBAL g)
+ {
+ if (!Placed && !Closing && GetRowID() == Records)
+ return RC_EF;
+
+ int rc = FIXFAM::ReadBuffer(g);
+
+ if (rc != RC_OK || Closing)
+ return rc;
+
+ switch (*Tdbp->GetLine()) {
+ case '*':
+ if (!ReadMode)
+ rc = RC_NF; // Deleted line
+ else
+ Rows++;
+
+ break;
+ case ' ':
+ if (ReadMode < 2)
+ Rows++; // Non deleted line
+ else
+ rc = RC_NF;
+
+ break;
+ default:
+ if (++Nerr >= Maxerr && !Accept) {
+ sprintf(g->Message, MSG(BAD_DBF_REC), Tdbp->GetFile(g), GetRowID());
+ rc = RC_FX;
+ } else
+ rc = (Accept) ? RC_OK : RC_NF;
+
+ } // endswitch To_Buf
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Copy the header into the temporary file. */
+/***********************************************************************/
+bool DBFFAM::CopyHeader(PGLOBAL g)
+ {
+ bool rc = true;
+
+ if (Headlen) {
+ void *hdr = PlugSubAlloc(g, NULL, Headlen);
+ size_t n, hlen = (size_t)Headlen;
+ int pos = ftell(Stream);
+
+ if (fseek(Stream, 0, SEEK_SET))
+ strcpy(g->Message, "Seek error in CopyHeader");
+ else if ((n = fread(hdr, 1, hlen, Stream)) != hlen)
+ sprintf(g->Message, MSG(BAD_READ_NUMBER), (int) n, To_File);
+ else if ((n = fwrite(hdr, 1, hlen, T_Stream)) != hlen)
+ sprintf(g->Message, MSG(WRITE_STRERROR), To_Fbt->Fname
+ , strerror(errno));
+ else if (fseek(Stream, pos, SEEK_SET))
+ strcpy(g->Message, "Seek error in CopyHeader");
+ else
+ rc = false;
+
+ } else
+ rc = false;
+
+ return rc;
+ } // end of CopyHeader
+
+#if 0 // Not useful when UseTemp is false.
+/***********************************************************************/
+/* Mark the line to delete with '*' (soft delete). */
+/* NOTE: this is not ready for UseTemp. */
+/***********************************************************************/
+int DBFFAM::InitDelete(PGLOBAL g, int fpos, int spos)
+ {
+ int rc = RC_FX;
+ size_t lrecl = (size_t)Lrecl;
+
+ if (Nrec != 1)
+ strcpy(g->Message, "Cannot delete in block mode");
+ else if (fseek(Stream, Headlen + fpos * Lrecl, SEEK_SET))
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ else if (fread(To_Buf, 1, lrecl, Stream) != lrecl)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+ else
+ *To_Buf = '*';
+
+ if (fseek(Stream, Headlen + fpos * Lrecl, SEEK_SET))
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ else if (fwrite(To_Buf, 1, lrecl, Stream) != lrecl)
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ else
+ rc = RC_NF; // Ok, Nothing else to do
+
+ return rc;
+ } // end of InitDelete
+#endif // 0
+
+/***********************************************************************/
+/* Data Base delete line routine for DBF access methods. */
+/* Deleted lines are just flagged in the first buffer character. */
+/***********************************************************************/
+int DBFFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ if (irc == RC_OK) {
+ // T_Stream is the temporary stream or the table file stream itself
+ if (!T_Stream)
+ {
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ if (CopyHeader(g)) // For DBF tables
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+ }
+ *Tdbp->GetLine() = '*';
+ Modif++; // Modified line in Delete mode
+ } // endif irc
+
+ return RC_OK;
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Rewind routine for DBF access method. */
+/***********************************************************************/
+void DBFFAM::Rewind(void)
+ {
+ BLKFAM::Rewind();
+ Nerr = 0;
+ } // end of Rewind
+
+/***********************************************************************/
+/* Table file close routine for DBF access method. */
+/***********************************************************************/
+void DBFFAM::CloseTableFile(PGLOBAL g, bool abort)
+ {
+ int rc = RC_OK, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ Abort = abort;
+
+ // Closing is True if last Write was in error
+ if (mode == MODE_INSERT && CurNum && !Closing) {
+ // Some more inserted lines remain to be written
+ Rbuf = CurNum--;
+// Closing = true;
+ wrc = WriteBuffer(g);
+ } else if (mode == MODE_UPDATE || mode == MODE_DELETE) {
+ if (Modif && !Closing) {
+ // Last updated block remains to be written
+ Closing = true;
+ wrc = WriteModifiedBlock(g);
+ } // endif Modif
+
+ if (UseTemp && T_Stream && wrc == RC_OK) {
+ if (!Abort) {
+ // Copy any remaining lines
+ bool b;
+
+ Fpos = Tdbp->Cardinality(g);
+ Abort = MoveIntermediateLines(g, &b) != RC_OK;
+ } // endif Abort
+
+ // Delete the old file and rename the new temp file.
+ RenameTempFile(g);
+ goto fin;
+ } // endif UseTemp
+
+ } // endif's mode
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ int n = ftell(Stream) - Headlen;
+
+ rc = PlugCloseFile(g, To_Fb);
+
+ if (n >= 0 && !(n % Lrecl)) {
+ n /= Lrecl; // New number of lines
+
+ if (n > Records) {
+ // Update the number of rows in the file header
+ char filename[_MAX_PATH];
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+ if ((Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r+b")))
+ {
+ char nRecords[4];
+ int4store(nRecords, n);
+
+ fseek(Stream, 4, SEEK_SET); // Get header.Records position
+ fwrite(nRecords, sizeof(nRecords), 1, Stream);
+ fclose(Stream);
+ Stream= NULL;
+ Records= n; // Update Records value
+ }
+ } // endif n
+
+ } // endif n
+
+ } else // Finally close the file
+ rc = PlugCloseFile(g, To_Fb);
+
+ fin:
+ if (trace(1))
+ htrc("DBF CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
+ To_File, mode, wrc, rc);
+
+ Stream = NULL; // So we can know whether table is open
+ } // end of CloseTableFile
+
+/* ---------------------------- Class DBMFAM ------------------------------ */
+
+/****************************************************************************/
+/* Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/****************************************************************************/
+int DBMFAM::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return 1;
+
+ if (!Headlen) {
+ int rln = 0; // Record length in the file header
+
+ Headlen = ScanHeader(g, To_File, Lrecl, &rln, Tdbp->GetPath());
+
+ if (Headlen < 0)
+ return -1; // Error in ScanHeader
+
+ if (rln && Lrecl != rln) {
+ // This happens always on some Linux platforms
+ sprintf(g->Message, MSG(BAD_LRECL), Lrecl, (ushort)rln);
+
+ if (Accept) {
+ Lrecl = rln;
+ Blksize = Nrec * Lrecl;
+ PushWarning(g, Tdbp);
+ } else
+ return -1;
+
+ } // endif rln
+
+ } // endif Headlen
+
+ // Set number of blocks for later use
+ Block = (Records > 0) ? (Records + Nrec - 1) / Nrec : 0;
+ return Records;
+ } // end of Cardinality
+
+#if 0 // Not compatible with ROWID block optimization
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int DBMFAM::GetRowID(void)
+ {
+ return Rows;
+ } // end of GetRowID
+#endif
+
+/***********************************************************************/
+/* Just check that on all deletion the unknown deleted line number is */
+/* sent back because Cardinality doesn't count soft deleted lines. */
+/***********************************************************************/
+int DBMFAM::GetDelRows(void)
+ {
+ if (Tdbp->GetMode() == MODE_DELETE && !Tdbp->GetNext())
+ return -1; // Means all lines deleted
+ else
+ return DelRows;
+
+ } // end of GetDelRows
+
+/****************************************************************************/
+/* Allocate the block buffer for the table. */
+/****************************************************************************/
+bool DBMFAM::AllocateBuffer(PGLOBAL g)
+ {
+ if (!Headlen) {
+ /************************************************************************/
+ /* Here is a good place to process the DBF file header */
+ /************************************************************************/
+ DBFHEADER *hp = (DBFHEADER*)Memory;
+
+ if (Lrecl != (int)hp->Reclen()) {
+ sprintf(g->Message, MSG(BAD_LRECL), Lrecl, hp->Reclen());
+
+ if (Accept) {
+ Lrecl = hp->Reclen();
+ Blksize = Nrec * Lrecl;
+ PushWarning(g, Tdbp);
+ } else
+ return true;
+
+ } // endif Lrecl
+
+ Records = (int)hp->Records();
+ Headlen = (int)hp->Headlen();
+ } // endif Headlen
+
+ /**************************************************************************/
+ /* Position the file at the begining of the data. */
+ /**************************************************************************/
+ Fpos = Mempos = Memory + Headlen;
+ Top--; // Because of EOF marker
+ return false;
+ } // end of AllocateBuffer
+
+/****************************************************************************/
+/* ReadBuffer: Read one line for a FIX file. */
+/****************************************************************************/
+int DBMFAM::ReadBuffer(PGLOBAL g)
+ {
+// if (!Placed && GetRowID() == Records)
+// return RC_EF;
+
+ int rc = MPXFAM::ReadBuffer(g);
+
+ if (rc != RC_OK)
+ return rc;
+
+ switch (*Fpos) {
+ case '*':
+ if (!ReadMode)
+ rc = RC_NF; // Deleted line
+ else
+ Rows++;
+
+ break;
+ case ' ':
+ if (ReadMode < 2)
+ Rows++; // Non deleted line
+ else
+ rc = RC_NF;
+
+ break;
+ default:
+ if (++Nerr >= Maxerr && !Accept) {
+ sprintf(g->Message, MSG(BAD_DBF_REC), Tdbp->GetFile(g), GetRowID());
+ rc = RC_FX;
+ } else
+ rc = (Accept) ? RC_OK : RC_NF;
+ } // endswitch To_Buf
+
+ return rc;
+ } // end of ReadBuffer
+
+/****************************************************************************/
+/* Data Base delete line routine for DBF access methods. */
+/* Deleted lines are just flagged in the first buffer character. */
+/****************************************************************************/
+int DBMFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ if (irc == RC_OK)
+ *Fpos = '*';
+
+ return RC_OK;
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Rewind routine for DBF access method. */
+/***********************************************************************/
+void DBMFAM::Rewind(void)
+ {
+ MBKFAM::Rewind();
+ Nerr = 0;
+ } // end of Rewind
+
+/* --------------------------------- EOF ---------------------------------- */
diff --git a/storage/connect/filamdbf.h b/storage/connect/filamdbf.h
new file mode 100644
index 00000000..dfe5cb5c
--- /dev/null
+++ b/storage/connect/filamdbf.h
@@ -0,0 +1,108 @@
+/***************** FilAmDbf H Declares Source Code File (.H) ****************/
+/* Name: filamdbf.h Version 1.4 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */
+/* */
+/* This file contains the DBF file access method classes declares. */
+/****************************************************************************/
+
+#ifndef __FILAMDBF_H
+#define __FILAMDBF_H
+
+#include "filamfix.h"
+#include "filamap.h"
+
+typedef class DBFBASE *PDBF;
+typedef class DBFFAM *PDBFFAM;
+typedef class DBMFAM *PDBMFAM;
+
+/****************************************************************************/
+/* Functions used externally. */
+/****************************************************************************/
+PQRYRES DBFColumns(PGLOBAL g, PCSZ dp, PCSZ fn, PTOS tiop, bool info);
+
+/****************************************************************************/
+/* This is the base class for dBASE file access methods. */
+/****************************************************************************/
+class DllExport DBFBASE {
+ public:
+ // Constructors
+ DBFBASE(PDOSDEF tdp);
+ DBFBASE(PDBF txfp);
+
+ // Implementation
+ int ScanHeader(PGLOBAL g, PCSZ fname, int lrecl, int *rlen, PCSZ defpath);
+
+ protected:
+ // Default constructor, not to be used
+ DBFBASE(void) {}
+
+ // Members
+ int Records; /* records in the file */
+ bool Accept; /* true if bad lines are accepted */
+ int Nerr; /* Number of bad records */
+ int Maxerr; /* Maximum number of bad records */
+ int ReadMode; /* 1: ALL 2: DEL 0: NOT DEL */
+ }; // end of class DBFBASE
+
+/****************************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for DBase files. */
+/****************************************************************************/
+class DllExport DBFFAM : public FIXFAM, public DBFBASE {
+ public:
+ // Constructors
+ DBFFAM(PDOSDEF tdp) : FIXFAM(tdp), DBFBASE(tdp) {}
+ DBFFAM(PDBFFAM txfp) : FIXFAM(txfp), DBFBASE((PDBF)txfp) {}
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_DBF;}
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) DBFFAM(this);}
+
+ // Methods
+ virtual int GetNerr(void) {return Nerr;}
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual void ResetBuffer(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ protected:
+ virtual bool CopyHeader(PGLOBAL g);
+//virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+
+ // Members
+ }; // end of class DBFFAM
+
+/****************************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for DBase files */
+/* using file mapping to access the file. */
+/****************************************************************************/
+class DllExport DBMFAM : public MPXFAM, public DBFBASE {
+ public:
+ // Constructors
+ DBMFAM(PDOSDEF tdp) : MPXFAM(tdp), DBFBASE(tdp) {}
+ DBMFAM(PDBMFAM txfp) : MPXFAM(txfp), DBFBASE((PDBF)txfp) {}
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_DBF;}
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) DBMFAM(this);}
+ virtual int GetDelRows(void);
+
+ // Methods
+ virtual int GetNerr(void) {return Nerr;}
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void Rewind(void);
+
+ protected:
+ // Members
+ }; // end of class DBFFAM
+
+#endif // __FILAMDBF_H
diff --git a/storage/connect/filamfix.cpp b/storage/connect/filamfix.cpp
new file mode 100644
index 00000000..46f3ea01
--- /dev/null
+++ b/storage/connect/filamfix.cpp
@@ -0,0 +1,1540 @@
+/*********** File AM Fix C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMFIX */
+/* ------------- */
+/* Version 1.6 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2015 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the FIX/BIN file access method classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#include <errno.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* filamfix.h is header containing the file AM classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "filamfix.h"
+#include "tabdos.h"
+#include "tabfix.h"
+#include "osutil.h"
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+#endif
+
+extern int num_read, num_there, num_eq[2]; // Statistics
+
+/* --------------------------- Class FIXFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+FIXFAM::FIXFAM(PDOSDEF tdp) : BLKFAM(tdp)
+ {
+ Blksize = tdp->GetBlksize();
+ Padded = tdp->GetPadded();
+
+ if (Padded && Blksize)
+ Nrec = Blksize / Lrecl;
+ else {
+ Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN;
+ Blksize = Nrec * Lrecl;
+ Padded = false;
+ } // endelse
+
+ } // end of FIXFAM standard constructor
+
+FIXFAM::FIXFAM(PFIXFAM txfp) : BLKFAM(txfp)
+ {
+ } // end of FIXFAM copy constructor
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool FIXFAM::SetPos(PGLOBAL g, int pos)
+ {
+ if (pos < 0) {
+ strcpy(g->Message, MSG(INV_REC_POS));
+ return true;
+ } // endif recpos
+
+ CurBlk = pos / Nrec;
+ CurNum = pos % Nrec;
+#if defined(_DEBUG)
+ num_eq[(CurBlk == OldBlk) ? 1 : 0]++;
+#endif
+
+ // Indicate the table position was externally set
+ Placed = true;
+ return false;
+ } // end of SetPos
+
+/***********************************************************************/
+/* Initialize CurBlk and CurNum for indexed DELETE. */
+/***********************************************************************/
+int FIXFAM::InitDelete(PGLOBAL, int fpos, int)
+ {
+ CurBlk = fpos / Nrec;
+ CurNum = fpos % Nrec;
+ return RC_OK;
+ } // end of InitDelete
+
+/***********************************************************************/
+/* Allocate the block buffer for the table. */
+/***********************************************************************/
+bool FIXFAM::AllocateBuffer(PGLOBAL g)
+ {
+ Buflen = Blksize;
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (UseTemp || Tdbp->GetMode() == MODE_DELETE) {
+ if (Padded) {
+ strcpy(g->Message, MSG(NO_MODE_PADDED));
+ return true;
+ } // endif Padded
+
+ // Allocate a separate buffer so block reading can be kept
+ Dbflen = Nrec;
+ DelBuf = PlugSubAlloc(g, NULL, Blksize);
+ } else if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* For Insert the buffer must be prepared. */
+ /*******************************************************************/
+ if (Tdbp->GetFtype() == RECFM_BIN) {
+ // The buffer must be prepared depending on column types
+ int n = 0;
+ bool b = false;
+ PBINCOL colp;
+
+ // Prepare the first line of the buffer
+ memset(To_Buf, 0, Buflen);
+
+#if 0
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext()) {
+ if (!IsTypeNum(cdp->GetType())) {
+ memset(To_Buf + cdp->GetOffset(), ' ', cdp->GetClen());
+ b = true;
+ } // endif not num
+
+ n = MY_MAX(n, cdp->GetOffset() + cdp->GetClen());
+ } // endfor cdp
+#endif // 0
+
+ for (colp = (PBINCOL)Tdbp->GetColumns(); colp;
+ colp = (PBINCOL)colp->GetNext())
+ if (!colp->IsSpecial()) {
+ if (!IsTypeNum(colp->GetResultType())) {
+ memset(To_Buf + colp->GetDeplac(), ' ', colp->GetLength());
+ b = true;
+ } // endif not num
+
+ n = MY_MAX(n, colp->GetDeplac() + colp->GetFileSize());
+ } // endif !special
+
+ // We do this for binary table because the lrecl can have been
+ // specified with additional space to include line ending.
+ if (n < Lrecl && Ending) {
+ To_Buf[Lrecl - 1] = '\n';
+
+ if (n < Lrecl - 1 && Ending == 2)
+ To_Buf[Lrecl - 2] = '\r';
+
+ } // endif n
+
+ if (b)
+ // Now repeat this for the whole buffer
+ for (int len = Lrecl; len <= Buflen - Lrecl; len += Lrecl)
+ memcpy(To_Buf + len, To_Buf, Lrecl);
+
+ } else {
+ memset(To_Buf, ' ', Buflen);
+
+ if (!Padded)
+ // The file is physically a text file.
+ for (int len = Lrecl; len <= Buflen; len += Lrecl) {
+ if (Ending == 2)
+ To_Buf[len - 2] = '\r';
+
+ To_Buf[len - 1] = '\n';
+ } // endfor len
+
+ } // endif Ftype
+
+ Rbuf = Nrec; // To be used by WriteDB
+ } // endif Insert
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Reset buffer access according to indexing and to mode. */
+/* >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
+/***********************************************************************/
+void FIXFAM::ResetBuffer(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* If access is random, performances can be much better when the */
+ /* reads are done on only one row, except for small tables that can */
+ /* be entirely read in one block. */
+ /*********************************************************************/
+ if (Tdbp->GetKindex() && ReadBlks != 1 && !Padded) {
+ Nrec = 1; // Better for random access
+ Rbuf = 0;
+ Blksize = Lrecl;
+ OldBlk = -2; // Has no meaning anymore
+ Block = Tdbp->Cardinality(g); // Blocks are one line now
+ } // endif Mode
+
+ } // end of ResetBuffer
+
+/***********************************************************************/
+/* WriteModifiedBlock: Used when updating. */
+/***********************************************************************/
+int FIXFAM::WriteModifiedBlock(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* The old block was modified in Update mode. */
+ /* In Update mode we simply rewrite the old block on itself. */
+ /*********************************************************************/
+ int rc = RC_OK;
+ bool moved = false;
+
+ // Using temp copy any intermediate lines.
+ if (UseTemp && MoveIntermediateLines(g, &moved))
+ rc = RC_FX;
+
+ // Fpos is last position, Headlen is DBF file header length
+ else if (!moved && fseek(Stream, Headlen + Fpos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ rc = RC_FX;
+ } else if (fwrite(To_Buf, Lrecl, Rbuf, T_Stream) != (size_t)Rbuf) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ rc = RC_FX;
+ } else
+ Spos = Fpos + Nrec; // + Rbuf ???
+
+ if (Closing || rc != RC_OK) { // Error or called from CloseDB
+ Closing = true; // To tell CloseDB about error
+ return rc;
+ } // endif Closing
+
+ // NOTE: Next line was added to avoid a very strange fread bug.
+ // When the fseek is not executed (even the file has the good
+ // pointer position) the next read can happen anywhere in the file.
+ OldBlk = -2; // This will force fseek to be executed
+ Modif = 0;
+ return rc;
+ } // end of WriteModifiedBlock
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a FIX file. */
+/***********************************************************************/
+int FIXFAM::ReadBuffer(PGLOBAL g)
+ {
+ int n, rc = RC_OK;
+
+ /*********************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*********************************************************************/
+ if (Placed) {
+ Tdbp->SetLine(To_Buf + CurNum * Lrecl);
+ Placed = false;
+ } else if (++CurNum < Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK;
+ } else if (Rbuf < Nrec && CurBlk != -1) {
+ return RC_EF;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+ next:
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ /*******************************************************************/
+ /* Before reading a new block, check whether block indexing */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ goto next;
+ } // endswitch rc
+ } // endif's
+
+ if (OldBlk == CurBlk) {
+ IsRead = true; // Was read indeed
+ return RC_OK; // Block is already there
+ } // endif OldBlk
+
+ // Write modified block in mode UPDATE
+ if (Modif && (rc = WriteModifiedBlock(g)) != RC_OK)
+ return rc;
+
+ // This could be done only for new block. However note that FPOS
+ // is used as block position when updating and as line position
+ // when deleting so this has to be carefully checked.
+ Fpos = CurBlk * Nrec; // Fpos is new line position
+
+ // fseek is required only in non sequential reading
+ if (CurBlk != OldBlk + 1)
+ // Note: Headlen is for DBF tables
+ if (fseek(Stream, Headlen + Fpos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
+ return RC_FX;
+ } // endif fseek
+
+ if (trace(2))
+ htrc("File position is now %d\n", ftell(Stream));
+
+ if (Padded)
+ n = fread(To_Buf, (size_t)Blksize, 1, Stream);
+ else
+ n = fread(To_Buf, (size_t)Lrecl, (size_t)Nrec, Stream);
+
+ if (n) {
+ rc = RC_OK;
+ Rbuf = (Padded) ? n * Nrec : n;
+ ReadBlks++;
+ num_read++;
+ } else if (feof(Stream)) {
+ rc = RC_EF;
+ } else {
+#if defined(_WIN32)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#endif
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return RC_FX;
+ } // endelse
+
+ OldBlk = CurBlk; // Last block actually read
+ IsRead = true; // Is read indeed
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for FIX access method. */
+/* Updates are written into the (Temp) file in ReadBuffer. */
+/***********************************************************************/
+int FIXFAM::WriteBuffer(PGLOBAL g)
+ {
+ if (trace(2))
+ htrc("FIX WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n",
+ Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum);
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode, blocs are added sequentialy to the file end. */
+ /*******************************************************************/
+ if (++CurNum != Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK; // We write only full blocks
+ } // endif CurNum
+
+ if (trace(2))
+ htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf);
+
+ // Now start the writing process.
+ if (fwrite(To_Buf, Lrecl, Rbuf, Stream) != (size_t)Rbuf) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ Closing = true; // To tell CloseDB about a Write error
+ return RC_FX;
+ } // endif size
+
+ CurBlk++;
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+ if (trace(2))
+ htrc("write done\n");
+
+ } else { // Mode == MODE_UPDATE
+ // T_Stream is the temporary stream or the table file stream itself
+ if (!T_Stream) {
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+ else if (CopyHeader(g)) // For DBF tables
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+
+ } // endif T_Stream
+
+ if (Nrec > 1)
+ Modif++; // Modified line in blocked mode
+ else if (WriteModifiedBlock(g)) // Indexed update
+ return RC_FX;
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for FIXFAM access method. */
+/***********************************************************************/
+int FIXFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool moved;
+
+ /*********************************************************************/
+ /* There is an alternative here: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /* This will be experimented. */
+ /*********************************************************************/
+ if (trace(2))
+ htrc("DOS DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = Tdbp->Cardinality(g);
+
+ if (trace(2))
+ htrc("Fpos placed at file end=%d\n", Fpos);
+
+ } else // Fpos is the deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete. */
+ /*******************************************************************/
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open temporary file, lines before this will be moved. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block moving. */
+ /*****************************************************************/
+ T_Stream = Stream;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+ /*******************************************************************/
+ /* Reposition the file pointer and set Spos. */
+ /*******************************************************************/
+ Spos = Fpos + 1; // New start position is on next line
+
+ if (moved) {
+ if (fseek(Stream, Spos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif fseek
+
+ OldBlk = -2; // To force fseek to be executed on next block
+ } // endif moved
+
+ if (trace(2))
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Ok, now delete old file and rename new temp file. */
+ /*****************************************************************/
+ if (RenameTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the file and reopen it with the */
+ /* open function (_fopen for MS ??) this is still to be checked */
+ /* for compatibility with Text files and other OS's. */
+ /*****************************************************************/
+ char filename[_MAX_PATH];
+ int h;
+
+ /*rc= */PlugCloseFile(g, To_Fb);
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+#if defined(UNIX)
+ if (ftruncate(h, (off_t)(Tpos * Lrecl))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (chsize(h, Tpos * Lrecl)) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+ if (trace(2))
+ htrc("done, h=%d irc=%d\n", h, irc);
+
+ } // endif UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/* This works only for file open in binary mode. */
+/***********************************************************************/
+bool FIXFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int n;
+ size_t req, len;
+
+ for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!UseTemp || !*b)
+ if (fseek(Stream, Headlen + Spos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ req = (size_t)MY_MIN(n, Dbflen);
+ len = fread(DelBuf, Lrecl, req, Stream);
+
+ if (trace(2))
+ htrc("after read req=%d len=%d\n", req, len);
+
+ if (len != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), (int) req, (int) len);
+ return true;
+ } // endif len
+
+ if (!UseTemp) // Delete mode, cannot be a DBF file
+ if (fseek(T_Stream, Tpos * Lrecl, SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(DelBuf, Lrecl, req, T_Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ if (trace(2))
+ htrc("after write pos=%d\n", ftell(Stream));
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (trace(2))
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ *b = true;
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediate Lines
+
+/***********************************************************************/
+/* Table file close routine for FIX access method. */
+/***********************************************************************/
+void FIXFAM::CloseTableFile(PGLOBAL g, bool abort)
+ {
+ int rc = RC_OK, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ Abort = abort;
+
+ // Closing is True if last Write was in error
+ if (mode == MODE_INSERT && CurNum && !Closing) {
+ // Some more inserted lines remain to be written
+ Rbuf = CurNum--;
+ wrc = WriteBuffer(g);
+ } else if (mode == MODE_UPDATE) {
+ if (Modif && !Closing) {
+ // Last updated block remains to be written
+ Closing = true; // ???
+ wrc = WriteModifiedBlock(g);
+ } // endif Modif
+
+ if (UseTemp && T_Stream && wrc == RC_OK) {
+ if (!Abort) {
+ // Copy any remaining lines
+ bool b;
+
+ Fpos = Tdbp->Cardinality(g);
+ Abort = MoveIntermediateLines(g, &b) != RC_OK;
+ } // endif Abort
+
+ // Delete the old file and rename the new temp file.
+ RenameTempFile(g);
+ goto fin;
+ } // endif UseTemp
+
+ } // endif's mode
+
+ // Finally close the file
+ rc = PlugCloseFile(g, To_Fb);
+
+ fin:
+ if (trace(1))
+ htrc("FIX CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
+ To_File, mode, wrc, rc);
+
+ Stream = NULL; // So we can know whether table is open
+ } // end of CloseTableFile
+
+/* ------------------------- Class BGXFAM ---------------------------- */
+
+/***********************************************************************/
+/* Implementation of the BGXFAM class. */
+/* This is the FAM class for FIX tables of more than 2 gigabytes. */
+/***********************************************************************/
+BGXFAM::BGXFAM(PDOSDEF tdp) : FIXFAM(tdp)
+ {
+ Hfile = INVALID_HANDLE_VALUE;
+ Tfile = INVALID_HANDLE_VALUE;
+ } // end of BGXFAM constructor
+
+BGXFAM::BGXFAM(PBGXFAM txfp) : FIXFAM(txfp)
+ {
+ Hfile = txfp->Hfile;
+ Tfile = txfp->Tfile;
+ } // end of BGXFAM copy constructor
+
+/***********************************************************************/
+/* Set current position in a big file. */
+/***********************************************************************/
+bool BGXFAM::BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, int org)
+ {
+#if defined(_WIN32)
+ char buf[256];
+ DWORD drc;
+ LARGE_INTEGER of;
+
+ of.QuadPart = pos;
+ of.LowPart = SetFilePointer(h, of.LowPart, &of.HighPart, org);
+
+ if (of.LowPart == INVALID_SET_FILE_POINTER &&
+ (drc = GetLastError()) != NO_ERROR) {
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(SFP_ERROR), buf);
+ return true;
+ } // endif
+#else // !_WIN32
+ if (lseek64(h, pos, org) < 0) {
+// sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
+ sprintf(g->Message, "lseek64: %s", strerror(errno));
+ printf("%s\n", g->Message);
+ return true;
+ } // endif
+#endif // !_WIN32
+
+ return false;
+ } // end of BigSeek
+
+/***********************************************************************/
+/* Read from a big file. */
+/***********************************************************************/
+int BGXFAM::BigRead(PGLOBAL g __attribute__((unused)),
+ HANDLE h, void *inbuf, int req)
+ {
+ int rc;
+
+#if defined(_WIN32)
+ DWORD nbr, drc, len = (DWORD)req;
+ bool brc = ReadFile(h, inbuf, len, &nbr, NULL);
+
+ if (trace(2))
+ htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr);
+
+ if (!brc) {
+ char buf[256]; // , *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ drc = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(READ_ERROR), To_File, buf);
+
+ if (trace(2))
+ htrc("BIGREAD: %s\n", g->Message);
+
+ rc = -1;
+ } else
+ rc = (int)nbr;
+#else // !_WIN32
+ size_t len = (size_t)req;
+ ssize_t nbr = read(h, inbuf, len);
+
+ rc = (int)nbr;
+#endif // !_WIN32
+
+ return rc;
+ } // end of BigRead
+
+/***********************************************************************/
+/* Write into a big file. */
+/***********************************************************************/
+bool BGXFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req)
+ {
+ bool rc = false;
+
+#if defined(_WIN32)
+ DWORD nbw, drc, len = (DWORD)req;
+ bool brc = WriteFile(h, inbuf, len, &nbw, NULL);
+
+ if (trace(2))
+ htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw);
+
+ if (!brc || nbw != len) {
+ char buf[256];
+ PCSZ fn = (h == Hfile) ? To_File : "Tempfile";
+
+ if (brc)
+ strcpy(buf, MSG(BAD_BYTE_NUM));
+ else {
+ drc = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ } // endelse brc
+
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, buf);
+
+ if (trace(2))
+ htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
+ nbw, len, drc, g->Message);
+
+ rc = true;
+ } // endif brc || nbw
+#else // !_WIN32
+ size_t len = (size_t)req;
+ ssize_t nbw = write(h, inbuf, len);
+
+ if (nbw != (ssize_t)len) {
+ const char *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
+
+ if (trace(2))
+ htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
+ nbw, len, errno, g->Message);
+
+ rc = true;
+ } // endif nbr
+#endif // !_WIN32
+
+ return rc;
+ } // end of BigWrite
+
+#if 0
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void BGXFAM::Reset(void)
+ {
+ FIXFAM::Reset();
+ Xpos = 0;
+ } // end of Reset
+#endif // 0
+
+/***********************************************************************/
+/* OpenTableFile: opens a huge file using Windows/Unix API's. */
+/***********************************************************************/
+bool BGXFAM::OpenTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ if ((To_Fb && To_Fb->Count) || Hfile != INVALID_HANDLE_VALUE) {
+ sprintf(g->Message, MSG(FILE_OPEN_YET), To_File);
+ return true;
+ } // endif
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (trace(1))
+ htrc("OpenTableFile: filename=%s mode=%d\n", filename, mode);
+
+#if defined(_WIN32)
+ DWORD rc, access, creation, share = 0;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ access = GENERIC_READ;
+ share = FILE_SHARE_READ;
+ creation = OPEN_EXISTING;
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted rows
+ DelRows = Cardinality(g);
+
+ // This will delete the whole file and provoque ReadDB to
+ // return immediately.
+ access = GENERIC_READ | GENERIC_WRITE;
+ creation = TRUNCATE_EXISTING;
+ Tdbp->ResetSize();
+ Headlen = 0;
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ case MODE_UPDATE:
+ if ((UseTemp = Tdbp->IsUsingTemp(g)))
+ access = GENERIC_READ;
+ else
+ access = GENERIC_READ | GENERIC_WRITE;
+
+ creation = OPEN_EXISTING;
+ break;
+ case MODE_INSERT:
+ access = GENERIC_WRITE;
+ creation = OPEN_ALWAYS;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch
+
+ Hfile = CreateFile(filename, access, share, NULL, creation,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+ } else
+ rc = 0;
+
+ if (trace(2))
+ htrc(" rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n",
+ rc, access, share, creation, Hfile, filename);
+
+ if (mode == MODE_INSERT)
+ /*******************************************************************/
+ /* In Insert mode we must position the cursor at end of file. */
+ /*******************************************************************/
+ if (BigSeek(g, Hfile, (BIGINT)0, FILE_END))
+ return true;
+
+#else // UNIX
+ int rc = 0;
+ int oflag = O_LARGEFILE; // Enable file size > 2G
+ mode_t tmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ oflag |= O_RDONLY;
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // This will delete the whole file and provoque ReadDB to
+ // return immediately.
+ oflag |= (O_RDWR | O_TRUNC);
+ Tdbp->ResetSize();
+ break;
+ } // endif
+
+ // Selective delete
+ /* fall through */
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ oflag |= (UseTemp) ? O_RDONLY : O_RDWR;
+ break;
+ case MODE_INSERT:
+ oflag |= (O_WRONLY | O_CREAT | O_APPEND);
+ // tmode = S_IREAD | S_IWRITE;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch
+
+ Hfile= global_open(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, oflag, tmode);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = errno;
+ } else
+ rc = 0;
+
+ if (trace(2))
+ htrc(" rc=%d oflag=%p tmode=%p handle=%p fn=%s\n",
+ rc, oflag, tmode, Hfile, filename);
+
+#endif // UNIX
+
+ if (!rc) {
+ if (!To_Fb) {
+ To_Fb = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ To_Fb->Fname = To_File;
+ To_Fb->Type = TYPE_FB_HANDLE;
+ To_Fb->Memory = NULL;
+ To_Fb->Length = 0;
+ To_Fb->Mode = mode;
+ To_Fb->File = NULL;
+ To_Fb->Next = dbuserp->Openlist;
+ dbuserp->Openlist = To_Fb;
+ } // endif To_Fb
+
+ To_Fb->Count = 1;
+ To_Fb->Mode = mode;
+ To_Fb->Handle = Hfile;
+
+ /*******************************************************************/
+ /* Allocate the block buffer. */
+ /*******************************************************************/
+ return AllocateBuffer(g);
+ } else
+ return (mode == MODE_READ && rc == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* BIGFIX Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int BGXFAM::Cardinality(PGLOBAL g)
+ {
+ if (g) {
+ char filename[_MAX_PATH];
+ int card = -1;
+ BIGINT fsize;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+#if defined(_WIN32) // OB
+ LARGE_INTEGER len;
+ DWORD rc = 0;
+
+ len.QuadPart = -1;
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ HANDLE h = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (h == INVALID_HANDLE_VALUE)
+ if ((rc = GetLastError()) != ERROR_FILE_NOT_FOUND) {
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, 10, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+ return -1;
+ } else
+ return 0; // File does not exist
+
+ // Get the size of the file (can be greater than 4 GB)
+ len.LowPart = GetFileSize(h, (LPDWORD)&len.HighPart);
+ CloseHandle(h);
+ } else
+ len.LowPart = GetFileSize(Hfile, (LPDWORD)&len.HighPart);
+
+ if (len.LowPart == 0xFFFFFFFF && (rc = GetLastError()) != NO_ERROR) {
+ sprintf(g->Message, MSG(FILELEN_ERROR), "GetFileSize", filename);
+ return -2;
+ } else
+ fsize = len.QuadPart;
+
+#else // UNIX
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ int h = open64(filename, O_RDONLY, 0);
+
+ if (trace(1))
+ htrc(" h=%d\n", h);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ if (trace(1))
+ htrc(" errno=%d ENOENT=%d\n", errno, ENOENT);
+
+ if (errno != ENOENT) {
+ sprintf(g->Message, MSG(OPEN_ERROR_IS),
+ filename, strerror(errno));
+ return -1;
+ } else
+ return 0; // File does not exist
+
+ } // endif h
+
+ // Get the size of the file (can be greater than 4 GB)
+ fsize = lseek64(h, 0, SEEK_END);
+ close(h);
+ } else {
+ BIGINT curpos = lseek64(Hfile, 0, SEEK_CUR);
+
+ fsize = lseek64(Hfile, 0, SEEK_END);
+ lseek64(Hfile, curpos, SEEK_SET);
+ } // endif Hfile
+
+ if (fsize < 0) {
+ sprintf(g->Message, MSG(FILELEN_ERROR), "lseek64", filename);
+ return -2;
+ } // endif fsize
+
+#endif // UNIX
+
+ // Check the real size of the file
+ if (Padded && Blksize) {
+ if (fsize % (BIGINT)Blksize) {
+ sprintf(g->Message, MSG(NOT_FIXED_LEN),
+ filename, (int)fsize, Lrecl);
+ return -3;
+ } else
+ card = (int)(fsize / (BIGINT)Blksize) * Nrec;
+
+ } else if (fsize % (BIGINT)Lrecl) {
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), filename, (int)fsize, Lrecl);
+ return -3;
+ } else
+ card = (int)(fsize / (BIGINT)Lrecl); // Fixed length file
+
+ if (trace(1))
+ htrc(" Computed max_K=%d fsize=%lf lrecl=%d\n",
+ card, (double)fsize, Lrecl);
+
+ // Set number of blocks for later use
+ Block = (card + Nrec - 1) / Nrec;
+ return card;
+ } else
+ return -1;
+
+ } // end of Cardinality
+
+/***********************************************************************/
+/* WriteModifiedBlock: Used when updating. */
+/***********************************************************************/
+int BGXFAM::WriteModifiedBlock(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* The old block was modified in Update mode. */
+ /* In Update mode we simply rewrite the old block on itself. */
+ /*********************************************************************/
+ int rc = RC_OK;
+ bool moved = false;
+
+ if (UseTemp) // Copy any intermediate lines.
+ if (MoveIntermediateLines(g, &moved))
+ rc = RC_FX;
+
+ if (rc == RC_OK) {
+ // Set file position to OldBlk position (Fpos)
+ if (!moved && BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl))
+ rc = RC_FX;
+ else if (BigWrite(g, Tfile, To_Buf, Lrecl * Rbuf))
+ rc = RC_FX;
+
+ Spos = Fpos + Nrec; // + Rbuf ???
+ } // endif rc
+
+ if (Closing || rc != RC_OK) // Error or called from CloseDB
+ return rc;
+
+ // NOTE: Next line was added to avoid a very strange fread bug.
+ // When the fseek is not executed (even the file has the good
+ // pointer position) the next read can happen anywhere in the file.
+ OldBlk = CurBlk; // This will force fseek to be executed
+ Modif = 0;
+ return rc;
+ } // end of WriteModifiedBlock
+
+/***********************************************************************/
+/* ReadBuffer: Read Nrec lines for a big fixed/binary file. */
+/***********************************************************************/
+int BGXFAM::ReadBuffer(PGLOBAL g)
+ {
+ int nbr, rc = RC_OK;
+
+ /*********************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*********************************************************************/
+ if (Placed) {
+ Tdbp->SetLine(To_Buf + CurNum * Lrecl);
+ Placed = false;
+ } else if (++CurNum < Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK;
+ } else if (Rbuf < Nrec && CurBlk != -1) {
+ return RC_EF;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+ next:
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ /*******************************************************************/
+ /* Before reading a new block, check whether block optimization */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ goto next;
+ } // endswitch rc
+
+ } // endif's
+
+ if (OldBlk == CurBlk) {
+ IsRead = true; // Was read indeed
+ return RC_OK; // Block is already there
+ } // endif OldBlk
+
+ // Write modified block in mode UPDATE
+ if (Modif && (rc = WriteModifiedBlock(g)) != RC_OK)
+ return rc;
+
+ Fpos = CurBlk * Nrec;
+
+ // Setting file pointer is required only in non sequential reading
+ if (CurBlk != OldBlk + 1)
+ if (BigSeek(g, Hfile, (BIGINT)Fpos * (BIGINT)Lrecl))
+ return RC_FX;
+
+ if (trace(2))
+ htrc("File position is now %d\n", Fpos);
+
+ nbr = BigRead(g, Hfile, To_Buf, (Padded) ? Blksize : Lrecl * Nrec);
+
+ if (nbr > 0) {
+ Rbuf = (Padded) ? Nrec : nbr / Lrecl;
+ rc = RC_OK;
+ ReadBlks++;
+ num_read++;
+ } else
+ rc = (nbr == 0) ? RC_EF : RC_FX;
+
+ OldBlk = CurBlk; // Last block actually read
+ IsRead = true; // Is read indeed
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for BGXFAM access method. */
+/* Updates are written into the (Temp) file in ReadBuffer. */
+/***********************************************************************/
+int BGXFAM::WriteBuffer(PGLOBAL g)
+ {
+ if (trace(2))
+ htrc("BIG WriteDB: Mode=%d buf=%p line=%p Nrec=%d Rbuf=%d CurNum=%d\n",
+ Tdbp->GetMode(), To_Buf, Tdbp->GetLine(), Nrec, Rbuf, CurNum);
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode, blocks are added sequentialy to the file end. */
+ /*******************************************************************/
+ if (++CurNum != Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK; // We write only full blocks
+ } // endif CurNum
+
+ if (trace(2))
+ htrc(" First line is '%.*s'\n", Lrecl - 2, To_Buf);
+
+ // Now start the writing process.
+ if (BigWrite(g, Hfile, To_Buf, Lrecl * Rbuf))
+ return RC_FX;
+
+ CurBlk++;
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+ if (trace(2))
+ htrc("write done\n");
+
+ } else { // Mode == MODE_UPDATE
+ // Tfile is the temporary file or the table file handle itself
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ Tfile = Hfile;
+
+ } // endif Tfile
+
+ if (Nrec > 1)
+ Modif++; // Modified line in blocked mode
+ else if (WriteModifiedBlock(g)) // Indexed update
+ return RC_FX;
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for BGXFAM access method. */
+/***********************************************************************/
+int BGXFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool moved;
+
+ /*********************************************************************/
+ /* There is an alternative here: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /* This will be experimented. */
+ /*********************************************************************/
+ if (trace(2))
+ htrc("BGX DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = Tdbp->Cardinality(g);
+
+ if (trace(2))
+ htrc("Fpos placed at file end=%d\n", Fpos);
+
+ } else // Fpos is the deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete. Move of eventual preceding lines is */
+ /* not required here if a temporary file is not used, just the */
+ /* setting of future Spos and Tpos. */
+ /*******************************************************************/
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ Tfile = Hfile;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+ if (trace(1))
+ assert(Spos == Fpos);
+
+ Spos++; // New start position is on next line
+
+ if (moved) {
+ if (BigSeek(g, Hfile, (BIGINT)Spos * (BIGINT)Lrecl))
+ return RC_FX;
+
+ OldBlk = -2; // To force fseek to be executed on next block
+ } // endif moved
+
+ if (trace(2))
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } else if (irc != RC_OK) {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Ok, now delete old file and rename new temp file. */
+ /*****************************************************************/
+ if (RenameTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+#if defined(_WIN32)
+ if (BigSeek(g, Hfile, (BIGINT)Tpos * (BIGINT)Lrecl))
+ return RC_FX;
+
+ if (!SetEndOfFile(Hfile)) {
+ DWORD drc = GetLastError();
+
+ sprintf(g->Message, MSG(SETEOF_ERROR), drc);
+ return RC_FX;
+ } // endif error
+#else // !_WIN32
+ if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+#endif // !_WIN32
+
+ } // endif UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open a temporary file used while updating or deleting. */
+/***********************************************************************/
+bool BGXFAM::OpenTempFile(PGLOBAL g)
+ {
+ char *tempname;
+ PDBUSER dup = PlgGetUser(g);
+
+ /*********************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*********************************************************************/
+ tempname = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ PlugSetPath(tempname, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(tempname, tempname), ".t");
+ remove(tempname); // Be sure it does not exist yet
+
+#if defined(_WIN32)
+ Tfile = CreateFile(tempname, GENERIC_WRITE, 0, NULL,
+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)tempname, _MAX_PATH, NULL);
+ strcat(g->Message, tempname);
+ return true;
+ } // endif Tfile
+#else // UNIX
+ Tfile = open64(tempname, O_WRONLY | O_TRUNC, S_IWRITE);
+
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ int rc = errno;
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
+ strcat(g->Message, strerror(errno));
+ return true;
+ } //endif Tfile
+#endif // UNIX
+
+ To_Fbt = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ To_Fbt->Fname = tempname;
+ To_Fbt->Type = TYPE_FB_HANDLE;
+ To_Fbt->Memory = NULL;
+ To_Fbt->Length = 0;
+ To_Fbt->File = NULL;
+ To_Fbt->Next = dup->Openlist;
+ To_Fbt->Count = 1;
+ To_Fbt->Mode = MODE_INSERT;
+ To_Fbt->Handle = Tfile;
+ dup->Openlist = To_Fbt;
+ return false;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool BGXFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int n, req, nbr;
+
+ for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!UseTemp || !*b)
+ if (BigSeek(g, Hfile, (BIGINT)Spos * (BIGINT)Lrecl))
+ return true;
+
+ req = MY_MIN(n, Dbflen) * Lrecl;
+
+ if ((nbr = BigRead(g, Hfile, DelBuf, req)) != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), req, nbr);
+ return true;
+ } // endif nbr
+
+ if (!UseTemp)
+ if (BigSeek(g, Tfile, (BIGINT)Tpos * (BIGINT)Lrecl))
+ return true;
+
+ if (BigWrite(g, Tfile, DelBuf, req))
+ return true;
+
+ req /= Lrecl;
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (trace(2))
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ *b = true;
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediateLines
+
+/***********************************************************************/
+/* Data Base close routine for BIGFIX access method. */
+/***********************************************************************/
+void BGXFAM::CloseTableFile(PGLOBAL g, bool abort)
+ {
+ int rc = RC_OK, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ Abort = abort;
+
+ // Closing is True if last Write was in error
+ if (mode == MODE_INSERT && CurNum && !Closing) {
+ // Some more inserted lines remain to be written
+ Rbuf = CurNum--;
+ wrc = WriteBuffer(g);
+ } else if (mode == MODE_UPDATE) {
+ if (Modif && !Closing) {
+ // Last updated block remains to be written
+ Closing = true;
+ wrc = WriteModifiedBlock(g);
+ } // endif Modif
+
+ if (UseTemp && Tfile && wrc == RC_OK) {
+ if (!Abort) {
+ // Copy any remaining lines
+ bool b;
+
+ Fpos = Tdbp->Cardinality(g);
+ Abort = MoveIntermediateLines(g, &b) != RC_OK;
+ } // endif Abort
+
+ // Delete the old file and rename the new temp file.
+ RenameTempFile(g);
+ goto fin;
+ } // endif UseTemp
+
+ } // endif's mode
+
+ // Finally close the file
+ rc = PlugCloseFile(g, To_Fb);
+
+ fin:
+ if (trace(1))
+ htrc("BGX CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
+ To_File, mode, wrc, rc);
+
+ Hfile = INVALID_HANDLE_VALUE; // So we can know whether table is open
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for huge FIX access method. */
+/* Note: commenting out OldBlk = -1 has two advantages: */
+/* 1 - It forces fseek on first block, thus suppressing the need to */
+/* rewind the file, anyway unuseful when second pass if indexed. */
+/* 2 - It permit to avoid re-reading small tables having only 1 block.*/
+/* (even very unlikely for huge files!) */
+/***********************************************************************/
+void BGXFAM::Rewind(void)
+ {
+#if 0 // This is probably unuseful because file is accessed directly
+#if defined(_WIN32) //OB
+ SetFilePointer(Hfile, 0, NULL, FILE_BEGIN);
+#else // UNIX
+ lseek64(Hfile, 0, SEEK_SET);
+#endif // UNIX
+#endif // 0
+ CurBlk = -1;
+ CurNum = Rbuf;
+//OldBlk = -1;
+//Rbuf = 0; commented out in case we reuse last read block
+ Fpos = 0;
+ } // end of Rewind
diff --git a/storage/connect/filamfix.h b/storage/connect/filamfix.h
new file mode 100644
index 00000000..a99a36af
--- /dev/null
+++ b/storage/connect/filamfix.h
@@ -0,0 +1,93 @@
+/************** FilAMFix H Declares Source Code File (.H) **************/
+/* Name: FILAMFIX.H Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005 - 2014 */
+/* */
+/* This file contains the FIX file access method classes declares. */
+/***********************************************************************/
+
+#ifndef __FILAMFIX_H
+#define __FILAMFIX_H
+
+#include "filamtxt.h"
+
+typedef class FIXFAM *PFIXFAM;
+typedef class BGXFAM *PBGXFAM;
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for standard */
+/* files with fixed record format (FIX, BIN) */
+/***********************************************************************/
+class DllExport FIXFAM : public BLKFAM {
+ public:
+ // Constructor
+ FIXFAM(PDOSDEF tdp);
+ FIXFAM(PFIXFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_FIX;}
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) FIXFAM(this);}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g) {return TXTFAM::Cardinality(g);}
+ virtual int MaxBlkSize(PGLOBAL g, int s)
+ {return TXTFAM::MaxBlkSize(g, s);}
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int GetNextPos(void) {return Fpos + 1;}
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual void ResetBuffer(PGLOBAL g);
+ virtual int WriteModifiedBlock(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+
+ protected:
+ virtual bool CopyHeader(PGLOBAL g) {return false;}
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b);
+ virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+
+ // No additional members
+ }; // end of class FIXFAM
+
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* that are standard files with columns starting at fixed offset */
+/* This class is for fixed formatted files of more than 2 gigabytes. */
+/***********************************************************************/
+class BGXFAM : public FIXFAM {
+ public:
+ // Constructor
+ BGXFAM(PDOSDEF tdp);
+ BGXFAM(PBGXFAM txfp);
+
+ // Implementation
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) BGXFAM(this);}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int WriteModifiedBlock(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ protected:
+ virtual bool OpenTempFile(PGLOBAL g);
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
+ int BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req);
+ bool BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req);
+ bool BigSeek(PGLOBAL g, HANDLE h, BIGINT pos
+ , int org = FILE_BEGIN);
+
+ // Members
+ HANDLE Hfile; // Handle(descriptor) to big file
+ HANDLE Tfile; // Handle(descriptor) to big temp file
+ }; // end of class BGXFAM
+
+#endif // __FILAMFIX_H
diff --git a/storage/connect/filamgz.cpp b/storage/connect/filamgz.cpp
new file mode 100644
index 00000000..634599ec
--- /dev/null
+++ b/storage/connect/filamgz.cpp
@@ -0,0 +1,1427 @@
+/************ File AM GZ C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMGZ */
+/* ------------- */
+/* Version 1.5 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2016 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the ZLIB compressed files classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <errno.h>
+#else // !UNIX
+#include <io.h>
+#endif
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tabdos.h is header containing the TABDOS class declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+//#include "catalog.h"
+//#include "reldef.h"
+//#include "xobject.h"
+//#include "kindex.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#if defined(UNIX)
+#include "osutil.h"
+#endif
+
+/***********************************************************************/
+/* This define prepares ZLIB function declarations. */
+/***********************************************************************/
+//#define ZLIB_DLL
+
+#include "filamgz.h"
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+extern int num_read, num_there, num_eq[]; // Statistics
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the GZFAM class. */
+/***********************************************************************/
+GZFAM::GZFAM(PGZFAM txfp) : TXTFAM(txfp)
+ {
+ Zfile = txfp->Zfile;
+ Zpos = txfp->Zpos;
+ } // end of GZFAM copy constructor
+
+/***********************************************************************/
+/* Zerror: Error function for gz calls. */
+/* gzerror returns the error message for the last error which occurred*/
+/* on the given compressed file. errnum is set to zlib error number. */
+/* If an error occurred in the file system and not in the compression */
+/* library, errnum is set to Z_ERRNO and the application may consult */
+/* errno to get the exact error code. */
+/***********************************************************************/
+int GZFAM::Zerror(PGLOBAL g)
+ {
+ int errnum;
+
+ strcpy(g->Message, gzerror(Zfile, &errnum));
+
+ if (errnum == Z_ERRNO)
+#if defined(_WIN32)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(NULL));
+#else // !_WIN32
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#endif // !_WIN32
+
+ return (errnum == Z_STREAM_END) ? RC_EF : RC_FX;
+ } // end of Zerror
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void GZFAM::Reset(void)
+ {
+ TXTFAM::Reset();
+//gzrewind(Zfile); // Useful ?????
+ Zpos = 0;
+ } // end of Reset
+
+/***********************************************************************/
+/* GZ GetFileLength: returns an estimate of what would be the */
+/* uncompressed file size in number of bytes. */
+/***********************************************************************/
+int GZFAM::GetFileLength(PGLOBAL g)
+ {
+ int len = TXTFAM::GetFileLength(g);
+
+ if (len > 0)
+ // Estimate size reduction to a max of 6
+ len *= 6;
+
+ return len;
+ } // end of GetFileLength
+
+/***********************************************************************/
+/* GZ Access Method opening routine. */
+/***********************************************************************/
+bool GZFAM::OpenTableFile(PGLOBAL g)
+ {
+ char opmode[4], filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "r");
+ break;
+ case MODE_UPDATE:
+ /*****************************************************************/
+ /* Updating GZ files not implemented yet. */
+ /*****************************************************************/
+ strcpy(g->Message, MSG(UPD_ZIP_NOT_IMP));
+ return true;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ // This will erase the entire file
+ strcpy(opmode, "w");
+// Block = 0; // For ZBKFAM
+// Last = Nrec; // For ZBKFAM
+ Tdbp->ResetSize();
+ } else {
+ sprintf(g->Message, MSG(NO_PART_DEL), "GZ");
+ return true;
+ } // endif filter
+
+ break;
+ case MODE_INSERT:
+ strcpy(opmode, "a+");
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ /*********************************************************************/
+ /* Open according to logical input/output mode required. */
+ /* Use specific zlib functions. */
+ /* Treat files as binary. */
+ /*********************************************************************/
+ strcat(opmode, "b");
+ Zfile = gzopen(PlugSetPath(filename, To_File, Tdbp->GetPath()), opmode);
+
+ if (Zfile == NULL) {
+ sprintf(g->Message, MSG(GZOPEN_ERROR),
+ opmode, (int)errno, filename);
+ strcat(strcat(g->Message, ": "), strerror(errno));
+ return (mode == MODE_READ && errno == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif Zfile
+
+ /*********************************************************************/
+ /* Something to be done here. >>>>>>>> NOT DONE <<<<<<<< */
+ /*********************************************************************/
+//To_Fb = dbuserp->Openlist; // Keep track of File block
+
+ /*********************************************************************/
+ /* Allocate the line buffer. */
+ /*********************************************************************/
+ return AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Allocate the line buffer. For mode Delete a bigger buffer has to */
+/* be allocated because is it also used to move lines into the file. */
+/***********************************************************************/
+bool GZFAM::AllocateBuffer(PGLOBAL g)
+ {
+ MODE mode = Tdbp->GetMode();
+
+ Buflen = Lrecl + 2; // Lrecl does not include CRLF
+//Buflen *= ((Mode == MODE_DELETE) ? DOS_BUFF_LEN : 1); NIY
+
+ if (trace(1))
+ htrc("SubAllocating a buffer of %d bytes\n", Buflen);
+
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* For Insert buffer must be prepared. */
+ /*******************************************************************/
+ memset(To_Buf, ' ', Buflen);
+ To_Buf[Buflen - 2] = '\n';
+ To_Buf[Buflen - 1] = '\0';
+ } // endif Insert
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int GZFAM::GetRowID(void)
+ {
+ return Rows;
+ } // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int GZFAM::GetPos(void)
+ {
+ return (int)Zpos;
+ } // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: return the position of next record. */
+/***********************************************************************/
+int GZFAM::GetNextPos(void)
+ {
+ return gztell(Zfile);
+ } // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool GZFAM::SetPos(PGLOBAL g, int pos __attribute__((unused)))
+ {
+ sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ");
+ return true;
+#if 0
+ Fpos = pos;
+
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
+ return true;
+ } // endif
+
+ Placed = true;
+ return false;
+#endif // 0
+ } // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/***********************************************************************/
+bool GZFAM::RecordPos(PGLOBAL)
+ {
+ Zpos = gztell(Zfile);
+ return false;
+ } // end of RecordPos
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int GZFAM::SkipRecord(PGLOBAL g, bool header)
+ {
+ // Skip this record
+ if (gzeof(Zfile))
+ return RC_EF;
+ else if (gzgets(Zfile, To_Buf, Buflen) == Z_NULL)
+ return Zerror(g);
+
+ if (header)
+ RecordPos(g);
+
+ return RC_OK;
+ } // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Read one line from a compressed text file. */
+/***********************************************************************/
+int GZFAM::ReadBuffer(PGLOBAL g)
+ {
+ char *p;
+ int rc;
+
+ if (!Zfile)
+ return RC_EF;
+
+ if (!Placed) {
+ /*******************************************************************/
+ /* Record file position in case of UPDATE or DELETE. */
+ /*******************************************************************/
+ next:
+ if (RecordPos(g))
+ return RC_FX;
+
+ CurBlk = Rows++; // Update RowID
+
+ /*******************************************************************/
+ /* Check whether optimization on ROWID */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ // Skip this record
+ if ((rc = SkipRecord(g, FALSE)) != RC_OK)
+ return rc;
+
+ goto next;
+ } // endswitch rc
+
+ } else
+ Placed = false;
+
+ if (gzeof(Zfile)) {
+ rc = RC_EF;
+ } else if (gzgets(Zfile, To_Buf, Buflen) != Z_NULL) {
+ p = To_Buf + strlen(To_Buf) - 1;
+
+ if (*p == '\n')
+ *p = '\0'; // Eliminate ending new-line character
+
+ if (*(--p) == '\r')
+ *p = '\0'; // Eliminate eventuel carriage return
+
+ strcpy(Tdbp->GetLine(), To_Buf);
+ IsRead = true;
+ rc = RC_OK;
+ num_read++;
+ } else
+ rc = Zerror(g);
+
+ if (trace(2))
+ htrc(" Read: '%s' rc=%d\n", To_Buf, rc);
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for ZDOS access method. */
+/* Update is not possible without using a temporary file (NIY). */
+/***********************************************************************/
+int GZFAM::WriteBuffer(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Prepare the write buffer. */
+ /*********************************************************************/
+ strcat(strcpy(To_Buf, Tdbp->GetLine()), CrLf);
+
+ /*********************************************************************/
+ /* Now start the writing process. */
+ /*********************************************************************/
+ if (gzputs(Zfile, To_Buf) < 0)
+ return Zerror(g);
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for ZDOS access method. (NIY) */
+/***********************************************************************/
+int GZFAM::DeleteRecords(PGLOBAL g, int)
+ {
+ strcpy(g->Message, MSG(NO_ZIP_DELETE));
+ return RC_FX;
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Data Base close routine for DOS access method. */
+/***********************************************************************/
+void GZFAM::CloseTableFile(PGLOBAL, bool)
+ {
+ int rc = gzclose(Zfile);
+
+ if (trace(1))
+ htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc);
+
+ Zfile = NULL; // So we can know whether table is open
+//To_Fb->Count = 0; // Avoid double closing by PlugCloseAll
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for GZ access method. */
+/***********************************************************************/
+void GZFAM::Rewind(void)
+ {
+ gzrewind(Zfile);
+ } // end of Rewind
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+ZBKFAM::ZBKFAM(PDOSDEF tdp) : GZFAM(tdp)
+ {
+ Blocked = true;
+ Block = tdp->GetBlock();
+ Last = tdp->GetLast();
+ Nrec = tdp->GetElemt();
+ CurLine = NULL;
+ NxtLine = NULL;
+ Closing = false;
+ BlkPos = tdp->GetTo_Pos();
+ } // end of ZBKFAM standard constructor
+
+ZBKFAM::ZBKFAM(PZBKFAM txfp) : GZFAM(txfp)
+ {
+ CurLine = txfp->CurLine;
+ NxtLine = txfp->NxtLine;
+ Closing = txfp->Closing;
+ } // end of ZBKFAM copy constructor
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/***********************************************************************/
+int ZBKFAM::MaxBlkSize(PGLOBAL g, int)
+ {
+ int rc = RC_OK, savcur = CurBlk;
+ int size;
+
+ // Roughly estimate the table size as the sum of blocks
+ // that can contain good rows
+ for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++)
+ if ((rc = Tdbp->TestBlock(g)) == RC_OK)
+ size += (CurBlk == Block - 1) ? Last : Nrec;
+ else if (rc == RC_EF)
+ break;
+
+ CurBlk = savcur;
+ return size;
+ } // end of MaxBlkSize
+
+/***********************************************************************/
+/* ZBK Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int ZBKFAM::Cardinality(PGLOBAL g)
+ {
+ return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Allocate the line buffer. For mode Delete a bigger buffer has to */
+/* be allocated because is it also used to move lines into the file. */
+/***********************************************************************/
+bool ZBKFAM::AllocateBuffer(PGLOBAL g)
+ {
+ Buflen = Nrec * (Lrecl + 2);
+ CurLine = To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ // Set values so Block and Last can be recalculated
+ if (Last == Nrec) {
+ CurBlk = Block;
+ Rbuf = Nrec; // To be used by WriteDB
+ } else {
+ // The last block must be completed
+ CurBlk = Block - 1;
+ Rbuf = Nrec - Last; // To be used by WriteDB
+ } // endif Last
+
+ } // endif Insert
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int ZBKFAM::GetRowID(void)
+ {
+ return CurNum + Nrec * CurBlk + 1;
+ } // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int ZBKFAM::GetPos(void)
+ {
+ return CurNum + Nrec * CurBlk; // Computed file index
+ } // end of GetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/* Not used yet for fixed tables. */
+/***********************************************************************/
+bool ZBKFAM::RecordPos(PGLOBAL /*g*/)
+ {
+//strcpy(g->Message, "RecordPos not implemented for gz blocked tables");
+//return true;
+ return RC_OK;
+ } // end of RecordPos
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int ZBKFAM::SkipRecord(PGLOBAL /*g*/, bool)
+ {
+//strcpy(g->Message, "SkipRecord not implemented for gz blocked tables");
+//return RC_FX;
+ return RC_OK;
+ } // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Read one line from a compressed text file. */
+/***********************************************************************/
+int ZBKFAM::ReadBuffer(PGLOBAL g)
+ {
+ int n, skip, rc = RC_OK;
+
+ /*********************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*********************************************************************/
+ if (++CurNum < Rbuf) {
+ CurLine = NxtLine;
+
+ // Get the position of the next line in the buffer
+ while (*NxtLine++ != '\n') ;
+
+ // Set caller line buffer
+ n = (int)(NxtLine - CurLine - Ending);
+ memcpy(Tdbp->GetLine(), CurLine, n);
+ Tdbp->GetLine()[n] = '\0';
+ return RC_OK;
+ } else if (Rbuf < Nrec && CurBlk != -1)
+ return RC_EF;
+
+ /*********************************************************************/
+ /* New block. */
+ /*********************************************************************/
+ CurNum = 0;
+ skip = 0;
+
+ next:
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ /*********************************************************************/
+ /* Before using the new block, check whether block optimization */
+ /* can be done, as well as for join as for local filtering. */
+ /*********************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ skip++;
+ goto next;
+ } // endswitch rc
+
+ if (skip)
+ // Skip blocks rejected by block optimization
+ for (int i = CurBlk - skip; i < CurBlk; i++) {
+ BlkLen = BlkPos[i + 1] - BlkPos[i];
+
+ if (gzseek(Zfile, (z_off_t)BlkLen, SEEK_CUR) < 0)
+ return Zerror(g);
+
+ } // endfor i
+
+ BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk];
+
+ if (!(n = gzread(Zfile, To_Buf, BlkLen))) {
+ rc = RC_EF;
+ } else if (n > 0) {
+ // Get the position of the current line
+ CurLine = To_Buf;
+
+ // Now get the position of the next line
+ for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
+
+ // Set caller line buffer
+ n = (int)(NxtLine - CurLine - Ending);
+ memcpy(Tdbp->GetLine(), CurLine, n);
+ Tdbp->GetLine()[n] = '\0';
+ Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
+ IsRead = true;
+ rc = RC_OK;
+ num_read++;
+ } else
+ rc = Zerror(g);
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for ZDOS access method. */
+/* Update is not possible without using a temporary file (NIY). */
+/***********************************************************************/
+int ZBKFAM::WriteBuffer(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Prepare the write buffer. */
+ /*********************************************************************/
+ if (!Closing)
+ strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
+
+ /*********************************************************************/
+ /* In Insert mode, blocs are added sequentialy to the file end. */
+ /* Note: Update mode is not handled for gz files. */
+ /*********************************************************************/
+ if (++CurNum == Rbuf) {
+ /*******************************************************************/
+ /* New block, start the writing process. */
+ /*******************************************************************/
+ BlkLen = CurLine + strlen(CurLine) - To_Buf;
+
+ if (gzwrite(Zfile, To_Buf, BlkLen) != BlkLen ||
+ gzflush(Zfile, Z_FULL_FLUSH)) {
+ Closing = true;
+ return Zerror(g);
+ } // endif gzwrite
+
+ Rbuf = Nrec;
+ CurBlk++;
+ CurNum = 0;
+ CurLine = To_Buf;
+ } else
+ CurLine += strlen(CurLine);
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for ZBK access method. */
+/* Implemented only for total deletion of the table, which is done */
+/* by opening the file in mode "wb". */
+/***********************************************************************/
+int ZBKFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ if (irc == RC_EF) {
+ (void) Tdbp->GetName(); // XXX Should be removed ?
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ defp->SetBlock(0);
+ defp->SetLast(Nrec);
+
+ if (!defp->SetIntCatInfo("Blocks", 0) ||
+ !defp->SetIntCatInfo("Last", 0)) {
+ sprintf(g->Message, MSG(UPDATE_ERROR), "Header");
+ return RC_FX;
+ } else
+ return RC_OK;
+
+ } else
+ return irc;
+
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Data Base close routine for ZBK access method. */
+/***********************************************************************/
+void ZBKFAM::CloseTableFile(PGLOBAL g, bool)
+ {
+ int rc = RC_OK;
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ (void) Tdbp->GetName(); // XXX Should be removed?
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ if (CurNum && !Closing) {
+ // Some more inserted lines remain to be written
+ Last = (Nrec - Rbuf) + CurNum;
+ Block = CurBlk + 1;
+ Rbuf = CurNum--;
+ Closing = true;
+ rc = WriteBuffer(g);
+ } else if (Rbuf == Nrec) {
+ Last = Nrec;
+ Block = CurBlk;
+ } // endif CurNum
+
+ if (rc != RC_FX) {
+ defp->SetBlock(Block);
+ defp->SetLast(Last);
+ defp->SetIntCatInfo("Blocks", Block);
+ defp->SetIntCatInfo("Last", Last);
+ } // endif
+
+ gzclose(Zfile);
+ } else if (Tdbp->GetMode() == MODE_DELETE) {
+ rc = DeleteRecords(g, RC_EF);
+ gzclose(Zfile);
+ } else
+ rc = gzclose(Zfile);
+
+ if (trace(1))
+ htrc("GZ CloseDB: closing %s rc=%d\n", To_File, rc);
+
+ Zfile = NULL; // So we can know whether table is open
+//To_Fb->Count = 0; // Avoid double closing by PlugCloseAll
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for ZBK access method. */
+/***********************************************************************/
+void ZBKFAM::Rewind(void)
+ {
+ gzrewind(Zfile);
+ CurBlk = -1;
+ CurNum = Rbuf;
+ } // end of Rewind
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+GZXFAM::GZXFAM(PDOSDEF tdp) : ZBKFAM(tdp)
+ {
+//Block = tdp->GetBlock();
+//Last = tdp->GetLast();
+ Nrec = (tdp->GetElemt()) ? tdp->GetElemt() : DOS_BUFF_LEN;
+ Blksize = Nrec * Lrecl;
+ } // end of GZXFAM standard constructor
+
+/***********************************************************************/
+/* ZIX Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int GZXFAM::Cardinality(PGLOBAL g)
+ {
+ if (Last)
+ return (g) ? (int)((Block - 1) * Nrec + Last) : 1;
+ else // Last and Block not defined, cannot do it yet
+ return 0;
+
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Allocate the line buffer. For mode Delete a bigger buffer has to */
+/* be allocated because is it also used to move lines into the file. */
+/***********************************************************************/
+bool GZXFAM::AllocateBuffer(PGLOBAL g)
+ {
+ Buflen = Blksize;
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* For Insert the buffer must be prepared. */
+ /*******************************************************************/
+ memset(To_Buf, ' ', Buflen);
+
+ if (Tdbp->GetFtype() < 2)
+ // if not binary, the file is physically a text file
+ for (int len = Lrecl; len <= Buflen; len += Lrecl) {
+#if defined(_WIN32)
+ To_Buf[len - 2] = '\r';
+#endif // _WIN32
+ To_Buf[len - 1] = '\n';
+ } // endfor len
+
+ // Set values so Block and Last can be recalculated
+ if (Last == Nrec) {
+ CurBlk = Block;
+ Rbuf = Nrec; // To be used by WriteDB
+ } else {
+ // The last block must be completed
+ CurBlk = Block - 1;
+ Rbuf = Nrec - Last; // To be used by WriteDB
+ } // endif Last
+
+ } // endif Insert
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* ReadBuffer: Read one line from a compressed text file. */
+/***********************************************************************/
+int GZXFAM::ReadBuffer(PGLOBAL g)
+ {
+ int n, rc = RC_OK;
+
+ /*********************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*********************************************************************/
+ if (++CurNum < Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK;
+ } else if (Rbuf < Nrec && CurBlk != -1)
+ return RC_EF;
+
+ /*********************************************************************/
+ /* New block. */
+ /*********************************************************************/
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+
+ int skip = 0;
+
+ next:
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ /*********************************************************************/
+ /* Before using the new block, check whether block optimization */
+ /* can be done, as well as for join as for local filtering. */
+ /*********************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ skip++;
+ goto next;
+ } // endswitch rc
+
+ if (skip)
+ // Skip blocks rejected by block optimization
+ for (int i = 0; i < skip; i++) {
+ if (gzseek(Zfile, (z_off_t)Buflen, SEEK_CUR) < 0)
+ return Zerror(g);
+
+ } // endfor i
+
+ if (!(n = gzread(Zfile, To_Buf, Buflen))) {
+ rc = RC_EF;
+ } else if (n > 0) {
+ Rbuf = n / Lrecl;
+ IsRead = true;
+ rc = RC_OK;
+ num_read++;
+ } else
+ rc = Zerror(g);
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for ZDOS access method. */
+/* Update is not possible without using a temporary file (NIY). */
+/***********************************************************************/
+int GZXFAM::WriteBuffer(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* In Insert mode, blocs are added sequentialy to the file end. */
+ /* Note: Update mode is not handled for gz files. */
+ /*********************************************************************/
+ if (++CurNum == Rbuf) {
+ /*******************************************************************/
+ /* New block, start the writing process. */
+ /*******************************************************************/
+ BlkLen = Rbuf * Lrecl;
+
+ if (gzwrite(Zfile, To_Buf, BlkLen) != BlkLen ||
+ gzflush(Zfile, Z_FULL_FLUSH)) {
+ Closing = true;
+ return Zerror(g);
+ } // endif gzwrite
+
+ Rbuf = Nrec;
+ CurBlk++;
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+ } else
+ Tdbp->IncLine(Lrecl); // Used by FIXCOL functions
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/* --------------------------- Class ZLBFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+ZLBFAM::ZLBFAM(PDOSDEF tdp) : BLKFAM(tdp)
+ {
+ Zstream = NULL;
+ Zbuffer = NULL;
+ Zlenp = NULL;
+ Optimized = tdp->IsOptimized();
+ } // end of ZLBFAM standard constructor
+
+ZLBFAM::ZLBFAM(PZLBFAM txfp) : BLKFAM(txfp)
+ {
+ Zstream = txfp->Zstream;
+ Zbuffer = txfp->Zbuffer;
+ Zlenp = txfp->Zlenp;
+ Optimized = txfp->Optimized;
+ } // end of ZLBFAM (dummy?) copy constructor
+
+/***********************************************************************/
+/* ZLB GetFileLength: returns an estimate of what would be the */
+/* uncompressed file size in number of bytes. */
+/***********************************************************************/
+int ZLBFAM::GetFileLength(PGLOBAL g)
+ {
+ int len = (Optimized) ? BlkPos[Block] : BLKFAM::GetFileLength(g);
+
+ if (len > 0)
+ // Estimate size reduction to a max of 5
+ len *= 5;
+
+ return len;
+ } // end of GetFileLength
+
+/***********************************************************************/
+/* Allocate the line buffer. For mode Delete a bigger buffer has to */
+/* be allocated because is it also used to move lines into the file. */
+/***********************************************************************/
+bool ZLBFAM::AllocateBuffer(PGLOBAL g)
+ {
+ PCSZ msg;
+ int n, zrc;
+
+#if 0
+ if (!Optimized && Tdbp->NeedIndexing(g)) {
+ strcpy(g->Message, MSG(NOP_ZLIB_INDEX));
+ return TRUE;
+ } // endif indexing
+#endif // 0
+
+#if defined(NOLIB)
+ if (!zlib && LoadZlib()) {
+ sprintf(g->Message, MSG(DLL_LOAD_ERROR), GetLastError(), "zlib.dll");
+ return TRUE;
+ } // endif zlib
+#endif
+
+ BLKFAM::AllocateBuffer(g);
+//Buflen = Nrec * (Lrecl + 2);
+//Rbuf = Nrec;
+
+ // Allocate the compressed buffer
+ n = Buflen + 16; // ?????????????????????????????????
+ Zlenp = (int*)PlugSubAlloc(g, NULL, n);
+ Zbuffer = (Byte*)(Zlenp + 1);
+
+ // Allocate and initialize the Z stream
+ Zstream = (z_streamp)PlugSubAlloc(g, NULL, sizeof(z_stream));
+ Zstream->zalloc = (alloc_func)0;
+ Zstream->zfree = (free_func)0;
+ Zstream->opaque = (voidpf)0;
+ Zstream->next_in = NULL;
+ Zstream->avail_in = 0;
+
+ if (Tdbp->GetMode() == MODE_READ) {
+ msg = "inflateInit";
+ zrc = inflateInit(Zstream);
+ } else {
+ msg = "deflateInit";
+ zrc = deflateInit(Zstream, Z_DEFAULT_COMPRESSION);
+ } // endif Mode
+
+ if (zrc != Z_OK) {
+ if (Zstream->msg)
+ sprintf(g->Message, "%s error: %s", msg, Zstream->msg);
+ else
+ sprintf(g->Message, "%s error: %d", msg, zrc);
+
+ return TRUE;
+ } // endif zrc
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ // Write the file header block
+ if (Last == Nrec) {
+ CurBlk = Block;
+ CurNum = 0;
+
+ if (!GetFileLength(g)) {
+ // Write the zlib header as an extra block
+ strcpy(To_Buf, "PlugDB");
+ BlkLen = strlen("PlugDB") + 1;
+
+ if (WriteCompressedBuffer(g))
+ return TRUE;
+
+ } // endif void file
+
+ } else {
+ // In mode insert, if Last != Nrec, last block must be updated
+ CurBlk = Block - 1;
+ CurNum = Last;
+
+ strcpy(g->Message, MSG(NO_PAR_BLK_INS));
+ return TRUE;
+ } // endif Last
+
+ } else { // MODE_READ
+ // First thing to do is to read the header block
+ void *rdbuf;
+
+ if (Optimized) {
+ BlkLen = BlkPos[0];
+ rdbuf = Zlenp;
+ } else {
+ // Get the stored length from the file itself
+ if (fread(Zlenp, sizeof(int), 1, Stream) != 1)
+ return FALSE; // Empty file
+
+ BlkLen = *Zlenp;
+ rdbuf = Zbuffer;
+ } // endif Optimized
+
+ switch (ReadCompressedBuffer(g, rdbuf)) {
+ case RC_EF:
+ return FALSE;
+ case RC_FX:
+#if defined(UNIX)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#endif
+ /* falls through */
+ case RC_NF:
+ return TRUE;
+ } // endswitch
+
+ // Some old tables can have PlugDB in their header
+ if (strcmp(To_Buf, "PlugDB")) {
+ sprintf(g->Message, MSG(BAD_HEADER), Tdbp->GetFile(g));
+ return TRUE;
+ } // endif strcmp
+
+ } // endif Mode
+
+ return FALSE;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int ZLBFAM::GetPos(void)
+ {
+ return (Optimized) ? (CurNum + Nrec * CurBlk) : Fpos;
+ } // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: should not be called for this class. */
+/***********************************************************************/
+int ZLBFAM::GetNextPos(void)
+ {
+ if (Optimized) {
+ assert(FALSE);
+ return 0;
+ } else
+ return ftell(Stream);
+
+ } // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool ZLBFAM::SetPos(PGLOBAL g, int pos __attribute__((unused)))
+ {
+ sprintf(g->Message, MSG(NO_SETPOS_YET), "GZ");
+ return true;
+#if 0 // All this must be checked
+ if (pos < 0) {
+ strcpy(g->Message, MSG(INV_REC_POS));
+ return true;
+ } // endif recpos
+
+ CurBlk = pos / Nrec;
+ CurNum = pos % Nrec;
+#if defined(_DEBUG)
+ num_eq[(CurBlk == OldBlk) ? 1 : 0]++;
+#endif
+
+ // Indicate the table position was externally set
+ Placed = true;
+ return false;
+#endif // 0
+ } // end of SetPos
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a text file. */
+/***********************************************************************/
+int ZLBFAM::ReadBuffer(PGLOBAL g)
+ {
+ size_t n;
+ void *rdbuf;
+
+ /*********************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*********************************************************************/
+ if (Placed) {
+ Placed = FALSE;
+ } else if (++CurNum < Rbuf) {
+ CurLine = NxtLine;
+
+ // Get the position of the next line in the buffer
+ if (Tdbp->GetFtype() == RECFM_VAR)
+ while (*NxtLine++ != '\n') ;
+ else
+ NxtLine += Lrecl;
+
+ // Set caller line buffer
+ n = NxtLine - CurLine - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending);
+ memcpy(Tdbp->GetLine(), CurLine, n);
+ Tdbp->GetLine()[n] = '\0';
+ return RC_OK;
+ } else if (Rbuf < Nrec && CurBlk != -1) {
+ CurNum--; // To have a correct Last value when optimizing
+ return RC_EF;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ next:
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ /*******************************************************************/
+ /* Before reading a new block, check whether block optimization */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ if (Optimized) switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ goto next;
+ } // endswitch rc
+
+ } // endif's
+
+ if (OldBlk == CurBlk)
+ goto ok; // Block is already there
+
+ if (Optimized) {
+ // Store the position of next block
+ Fpos = BlkPos[CurBlk];
+
+ // fseek is required only in non sequential reading
+ if (CurBlk != OldBlk + 1)
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
+ return RC_FX;
+ } // endif fseek
+
+ // Calculate the length of block to read
+ BlkLen = BlkPos[CurBlk + 1] - Fpos;
+ rdbuf = Zlenp;
+ } else { // !Optimized
+ if (CurBlk != OldBlk + 1) {
+ strcpy(g->Message, MSG(INV_RAND_ACC));
+ return RC_FX;
+ } else
+ Fpos = ftell(Stream); // Used when optimizing
+
+ // Get the stored length from the file itself
+ if (fread(Zlenp, sizeof(int), 1, Stream) != 1) {
+ if (feof(Stream))
+ return RC_EF;
+
+ goto err;
+ } // endif fread
+
+ BlkLen = *Zlenp;
+ rdbuf = Zbuffer;
+ } // endif Optimized
+
+ // Read the next block
+ switch (ReadCompressedBuffer(g, rdbuf)) {
+ case RC_FX: goto err;
+ case RC_NF: return RC_FX;
+ case RC_EF: return RC_EF;
+ default: Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
+ } // endswitch ReadCompressedBuffer
+
+ ok:
+ if (Tdbp->GetFtype() == RECFM_VAR) {
+ int i;
+
+ // Get the position of the current line
+ for (i = 0, CurLine = To_Buf; i < CurNum; i++)
+ while (*CurLine++ != '\n') ; // What about Unix ???
+
+ // Now get the position of the next line
+ for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
+
+ // Set caller line buffer
+ n = NxtLine - CurLine - Ending;
+ } else {
+ CurLine = To_Buf + CurNum * Lrecl;
+ NxtLine = CurLine + Lrecl;
+ n = Lrecl - ((Tdbp->GetFtype() == RECFM_BIN) ? 0 : Ending);
+ } // endif Ftype
+
+ memcpy(Tdbp->GetLine(), CurLine, n);
+ Tdbp->GetLine()[n] = '\0';
+
+ OldBlk = CurBlk; // Last block actually read
+ IsRead = TRUE; // Is read indeed
+ return RC_OK;
+
+ err:
+#if defined(UNIX)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#endif
+ return RC_FX;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Read and decompress a block from the stream. */
+/***********************************************************************/
+int ZLBFAM::ReadCompressedBuffer(PGLOBAL g, void *rdbuf)
+ {
+ if (fread(rdbuf, 1, (size_t)BlkLen, Stream) == (unsigned)BlkLen) {
+ int zrc;
+
+ num_read++;
+
+ if (Optimized && BlkLen != signed(*Zlenp + sizeof(int))) {
+ sprintf(g->Message, MSG(BAD_BLK_SIZE), CurBlk + 1);
+ return RC_NF;
+ } // endif BlkLen
+
+ // HERE WE MUST INFLATE THE BLOCK
+ Zstream->next_in = Zbuffer;
+ Zstream->avail_in = (uInt)(*Zlenp);
+ Zstream->next_out = (Byte*)To_Buf;
+ Zstream->avail_out = Buflen;
+ zrc = inflate(Zstream, Z_SYNC_FLUSH);
+
+ if (zrc != Z_OK) {
+ if (Zstream->msg)
+ sprintf(g->Message, MSG(FUNC_ERR_S), "inflate", Zstream->msg);
+ else
+ sprintf(g->Message, MSG(FUNCTION_ERROR), "inflate", (int)zrc);
+
+ return RC_NF;
+ } // endif zrc
+
+ } else if (feof(Stream)) {
+ return RC_EF;
+ } else
+ return RC_FX;
+
+ return RC_OK;
+ } // end of ReadCompressedBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for DOS access method. */
+/* Update is directly written back into the file, */
+/* with this (fast) method, record size cannot change. */
+/***********************************************************************/
+int ZLBFAM::WriteBuffer(PGLOBAL g)
+ {
+ assert (Tdbp->GetMode() == MODE_INSERT);
+
+ /*********************************************************************/
+ /* Prepare the write buffer. */
+ /*********************************************************************/
+ if (!Closing) {
+ if (Tdbp->GetFtype() == RECFM_BIN)
+ memcpy(CurLine, Tdbp->GetLine(), Lrecl);
+ else
+ strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
+
+#if defined(_DEBUG)
+ if (Tdbp->GetFtype() == RECFM_FIX &&
+ (signed)strlen(CurLine) != Lrecl + (signed)strlen(CrLf)) {
+ strcpy(g->Message, MSG(BAD_LINE_LEN));
+ Closing = TRUE;
+ return RC_FX;
+ } // endif Lrecl
+#endif // _DEBUG
+ } // endif Closing
+
+ /*********************************************************************/
+ /* In Insert mode, blocs are added sequentialy to the file end. */
+ /*********************************************************************/
+ if (++CurNum != Rbuf) {
+ if (Tdbp->GetFtype() == RECFM_VAR)
+ CurLine += strlen(CurLine);
+ else
+ CurLine += Lrecl;
+
+ return RC_OK; // We write only full blocks
+ } // endif CurNum
+
+ // HERE WE MUST DEFLATE THE BLOCK
+ if (Tdbp->GetFtype() == RECFM_VAR)
+ NxtLine = CurLine + strlen(CurLine);
+ else
+ NxtLine = CurLine + Lrecl;
+
+ BlkLen = (int)(NxtLine - To_Buf);
+
+ if (WriteCompressedBuffer(g)) {
+ Closing = TRUE; // To tell CloseDB about a Write error
+ return RC_FX;
+ } // endif WriteCompressedBuffer
+
+ CurBlk++;
+ CurNum = 0;
+ CurLine = To_Buf;
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Compress the buffer and write the deflated output to stream. */
+/***********************************************************************/
+bool ZLBFAM::WriteCompressedBuffer(PGLOBAL g)
+ {
+ int zrc;
+
+ Zstream->next_in = (Byte*)To_Buf;
+ Zstream->avail_in = (uInt)BlkLen;
+ Zstream->next_out = Zbuffer;
+ Zstream->avail_out = Buflen + 16;
+ Zstream->total_out = 0;
+ zrc = deflate(Zstream, Z_FULL_FLUSH);
+
+ if (zrc != Z_OK) {
+ if (Zstream->msg)
+ sprintf(g->Message, MSG(FUNC_ERR_S), "deflate", Zstream->msg);
+ else
+ sprintf(g->Message, MSG(FUNCTION_ERROR), "deflate", (int)zrc);
+
+ return TRUE;
+ } else
+ *Zlenp = Zstream->total_out;
+
+ // Now start the writing process.
+ BlkLen = *Zlenp + sizeof(int);
+
+ if (fwrite(Zlenp, 1, BlkLen, Stream) != (size_t)BlkLen) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ return TRUE;
+ } // endif size
+
+ return FALSE;
+ } // end of WriteCompressedBuffer
+
+/***********************************************************************/
+/* Table file close routine for DOS access method. */
+/***********************************************************************/
+void ZLBFAM::CloseTableFile(PGLOBAL g, bool)
+ {
+ int rc = RC_OK;
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ (void) Tdbp->GetName(); // XXX Should be removed?
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ // Closing is True if last Write was in error
+ if (CurNum && !Closing) {
+ // Some more inserted lines remain to be written
+ Last = (Nrec - Rbuf) + CurNum;
+ Block = CurBlk + 1;
+ Rbuf = CurNum--;
+ Closing = TRUE;
+ rc = WriteBuffer(g);
+ } else if (Rbuf == Nrec) {
+ Last = Nrec;
+ Block = CurBlk;
+ } // endif CurNum
+
+ if (rc != RC_FX) {
+ defp->SetBlock(Block);
+ defp->SetLast(Last);
+ defp->SetIntCatInfo("Blocks", Block);
+ defp->SetIntCatInfo("Last", Last);
+ } // endif
+
+ fclose(Stream);
+ } else
+ rc = fclose(Stream);
+
+ if (trace(1))
+ htrc("ZLB CloseTableFile: closing %s mode=%d rc=%d\n",
+ To_File, Tdbp->GetMode(), rc);
+
+ Stream = NULL; // So we can know whether table is open
+ To_Fb->Count = 0; // Avoid double closing by PlugCloseAll
+
+ if (Tdbp->GetMode() == MODE_READ)
+ rc = inflateEnd(Zstream);
+ else
+ rc = deflateEnd(Zstream);
+
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for ZLIB access method. */
+/***********************************************************************/
+void ZLBFAM::Rewind(void)
+ {
+ // We must be positioned after the header block
+ if (CurBlk >= 0) { // Nothing to do if no block read yet
+ if (!Optimized) { // If optimized, fseek will be done in ReadBuffer
+ size_t st;
+
+ rewind(Stream);
+
+ if (!(st = fread(Zlenp, sizeof(int), 1, Stream)) && trace(1))
+ htrc("fread error %d in Rewind", errno);
+
+ fseek(Stream, *Zlenp + sizeof(int), SEEK_SET);
+ OldBlk = -1;
+ } // endif Optimized
+
+ CurBlk = -1;
+ CurNum = Rbuf;
+ } // endif CurBlk
+
+//OldBlk = -1;
+//Rbuf = 0; commented out in case we reuse last read block
+ } // end of Rewind
+
+/* ------------------------ End of GzFam ---------------------------- */
diff --git a/storage/connect/filamgz.h b/storage/connect/filamgz.h
new file mode 100644
index 00000000..7a00c0d4
--- /dev/null
+++ b/storage/connect/filamgz.h
@@ -0,0 +1,170 @@
+/*************** FilAmGz H Declares Source Code File (.H) **************/
+/* Name: FILAMGZ.H Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2016 */
+/* */
+/* This file contains the GZIP access method classes declares. */
+/***********************************************************************/
+#ifndef __FILAMGZ_H
+#define __FILAMGZ_H
+
+#include "zlib.h"
+
+typedef class GZFAM *PGZFAM;
+typedef class ZBKFAM *PZBKFAM;
+typedef class GZXFAM *PZIXFAM;
+typedef class ZLBFAM *PZLBFAM;
+
+/***********************************************************************/
+/* This is the access method class declaration for not optimized */
+/* variable record length files compressed using the gzip library */
+/* functions. File is accessed record by record (row). */
+/***********************************************************************/
+class DllExport GZFAM : public TXTFAM {
+// friend class DOSCOL;
+ public:
+ // Constructor
+ GZFAM(PDOSDEF tdp) : TXTFAM(tdp) {Zfile = NULL; Zpos = 0;}
+ GZFAM(PGZFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_GZ;}
+ virtual int GetPos(void);
+ virtual int GetNextPos(void);
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) GZFAM(this);}
+
+ // Methods
+ virtual void Reset(void);
+ virtual int GetFileLength(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g) {return (g) ? -1 : 0;}
+ virtual int MaxBlkSize(PGLOBAL g, int s) {return s;}
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual int GetRowID(void);
+ virtual bool RecordPos(PGLOBAL g);
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int SkipRecord(PGLOBAL g, bool header);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ protected:
+ int Zerror(PGLOBAL g); // GZ error function
+
+ // Members
+ gzFile Zfile; // Points to GZ file structure
+ z_off_t Zpos; // Uncompressed file position
+ }; // end of class GZFAM
+
+/***********************************************************************/
+/* This is the access method class declaration for optimized variable */
+/* record length files compressed using the gzip library functions. */
+/* The File is accessed by block (requires an opt file). */
+/***********************************************************************/
+class DllExport ZBKFAM : public GZFAM {
+ public:
+ // Constructor
+ ZBKFAM(PDOSDEF tdp);
+ ZBKFAM(PZBKFAM txfp);
+
+ // Implementation
+ virtual int GetPos(void);
+ virtual int GetNextPos(void) {return 0;}
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) ZBKFAM(this);}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g);
+ virtual int MaxBlkSize(PGLOBAL g, int s);
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual int GetRowID(void);
+ virtual bool RecordPos(PGLOBAL g);
+ virtual int SkipRecord(PGLOBAL g, bool header);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ protected:
+ // Members
+ char *CurLine; // Position of current line in buffer
+ char *NxtLine; // Position of Next line in buffer
+ bool Closing; // True when closing on Insert
+ }; // end of class ZBKFAM
+
+/***********************************************************************/
+/* This is the access method class declaration for fixed record */
+/* length files compressed using the gzip library functions. */
+/* The file is always accessed by block. */
+/***********************************************************************/
+class DllExport GZXFAM : public ZBKFAM {
+ public:
+ // Constructor
+ GZXFAM(PDOSDEF tdp);
+ GZXFAM(PZIXFAM txfp) : ZBKFAM(txfp) {}
+
+ // Implementation
+ virtual int GetNextPos(void) {return 0;}
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) GZXFAM(this);}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+
+ protected:
+ // No additional Members
+ }; // end of class GZXFAM
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for PlugDB */
+/* fixed/variable files compressed using the zlib library functions. */
+/* Physically these are written and read using the same technique */
+/* than blocked variable files, only the contain of each block is */
+/* compressed using the deflate zlib function. The purpose of this */
+/* specific format is to have a fast mechanism for direct access of */
+/* records so blocked optimization is fast and direct access (joins) */
+/* is allowed. Note that the block length is written ahead of each */
+/* block to enable reading when optimization file is not available. */
+/***********************************************************************/
+class DllExport ZLBFAM : public BLKFAM {
+ public:
+ // Constructor
+ ZLBFAM(PDOSDEF tdp);
+ ZLBFAM(PZLBFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_ZLIB;}
+ virtual int GetPos(void);
+ virtual int GetNextPos(void);
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) ZLBFAM(this);}
+ inline void SetOptimized(bool b) {Optimized = b;}
+
+ // Methods
+ virtual int GetFileLength(PGLOBAL g);
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ protected:
+ bool WriteCompressedBuffer(PGLOBAL g);
+ int ReadCompressedBuffer(PGLOBAL g, void *rdbuf);
+
+ // Members
+ z_streamp Zstream; // Compression/decompression stream
+ Byte *Zbuffer; // Compressed block buffer
+ int *Zlenp; // Pointer to block length
+ bool Optimized; // true when opt file is available
+ }; // end of class ZLBFAM
+
+#endif // __FILAMGZ_H
diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp
new file mode 100644
index 00000000..393ca360
--- /dev/null
+++ b/storage/connect/filamtxt.cpp
@@ -0,0 +1,2119 @@
+/*********** File AM Txt C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMTXT */
+/* ------------- */
+/* Version 1.8 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the Text file access method classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#include <errno.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX) || defined(UNIV_LINUX)
+#include <errno.h>
+#include <unistd.h>
+//#if !defined(sun) // Sun has the ftruncate fnc.
+//#define USETEMP // Force copy mode for DELETE
+//#endif // !sun
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* filamtxt.h is header containing the file AM classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#include "tabjson.h"
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#include "osutil.h"
+#define _fileno fileno
+#define _O_RDONLY O_RDONLY
+#endif
+
+extern int num_read, num_there, num_eq[2]; // Statistics
+
+/***********************************************************************/
+/* Routine called externally by TXTFAM SortedRows functions. */
+/***********************************************************************/
+PARRAY MakeValueArray(PGLOBAL g, PPARM pp);
+
+/* --------------------------- Class TXTFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+TXTFAM::TXTFAM(PDOSDEF tdp)
+ {
+ Tdbp = NULL;
+ To_Fb = NULL;
+
+ if (tdp) {
+ To_File = tdp->Fn;
+ Lrecl = tdp->Lrecl;
+ Eof = tdp->Eof;
+ Ending = tdp->Ending;
+ } else {
+ To_File = NULL;
+ Lrecl = 0;
+ Eof = false;
+#if defined(_WIN32)
+ Ending = 2;
+#else
+ Ending = 1;
+#endif
+ } // endif tdp
+
+ Placed = false;
+ IsRead = true;
+ Blocked = false;
+ To_Buf = NULL;
+ DelBuf = NULL;
+ BlkPos = NULL;
+ To_Pos = NULL;
+ To_Sos = NULL;
+ To_Upd = NULL;
+ Posar = NULL;
+ Sosar = NULL;
+ Updar = NULL;
+ BlkLen = 0;
+ Buflen = 0;
+ Dbflen = 0;
+ Rows = 0;
+ DelRows = 0;
+ Headlen = 0;
+ Block = 0;
+ Last = 0;
+ Nrec = 1;
+ OldBlk = -1;
+ CurBlk = -1;
+ ReadBlks = 0;
+ CurNum = 0;
+ Rbuf = 0;
+ Modif = 0;
+ Blksize = 0;
+ Fpos = Spos = Tpos = 0;
+ Padded = false;
+ Abort = false;
+ CrLf = (char*)(Ending == 1 ? "\n" : "\r\n");
+ } // end of TXTFAM standard constructor
+
+TXTFAM::TXTFAM(PTXF txfp)
+ {
+ Tdbp = txfp->Tdbp;
+ To_Fb = txfp->To_Fb;
+ To_File = txfp->To_File;
+ Lrecl = txfp->Lrecl;
+ Placed = txfp->Placed;
+ IsRead = txfp->IsRead;
+ Blocked = txfp->Blocked;
+ To_Buf = txfp->To_Buf;
+ DelBuf = txfp->DelBuf;
+ BlkPos = txfp->BlkPos;
+ To_Pos = txfp->To_Pos;
+ To_Sos = txfp->To_Sos;
+ To_Upd = txfp->To_Upd;
+ Posar = txfp->Posar;
+ Sosar = txfp->Sosar;
+ Updar = txfp->Updar;
+ BlkLen = txfp->BlkLen;
+ Buflen = txfp->Buflen;
+ Dbflen = txfp->Dbflen;
+ Rows = txfp->Rows;
+ DelRows = txfp->DelRows;
+ Headlen = txfp->Headlen;
+ Block = txfp->Block;
+ Last = txfp->Last;
+ Nrec = txfp->Nrec;
+ OldBlk = txfp->OldBlk;
+ CurBlk = txfp->CurBlk;
+ ReadBlks = txfp->ReadBlks;
+ CurNum = txfp->CurNum;
+ Rbuf = txfp->Rbuf;
+ Modif = txfp->Modif;
+ Blksize = txfp->Blksize;
+ Fpos = txfp->Fpos;
+ Spos = txfp->Spos;
+ Tpos = txfp->Tpos;
+ Padded = txfp->Padded;
+ Eof = txfp->Eof;
+ Ending = txfp->Ending;
+ Abort = txfp->Abort;
+ CrLf = txfp->CrLf;
+ } // end of TXTFAM copy constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void TXTFAM::Reset(void)
+ {
+ Rows = 0;
+ DelRows = 0;
+ OldBlk = -1;
+ CurBlk = -1;
+ ReadBlks = 0;
+ CurNum = 0;
+ Rbuf = 0;
+ Modif = 0;
+ Placed = false;
+ } // end of Reset
+
+/***********************************************************************/
+/* TXT GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int TXTFAM::GetFileLength(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int h;
+ int len;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+ h= global_open(g, MSGID_OPEN_MODE_STRERROR, filename, _O_RDONLY);
+
+ if (trace(1))
+ htrc("GetFileLength: fn=%s h=%d\n", filename, h);
+
+ if (h == -1) {
+ if (errno != ENOENT) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ len = -1;
+ } else {
+ len = 0; // File does not exist yet
+ g->Message[0]= '\0';
+ } // endif errno
+
+ } else {
+ if ((len = _filelength(h)) < 0)
+ sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", filename);
+
+ if (Eof && len)
+ len--; // Do not count the EOF character
+
+ close(h);
+ } // endif h
+
+ return len;
+ } // end of GetFileLength
+
+/***********************************************************************/
+/* Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/* Note: This function is meant only for fixed length files but is */
+/* placed here to be available to FIXFAM and MPXFAM classes. */
+/***********************************************************************/
+int TXTFAM::Cardinality(PGLOBAL g)
+ {
+ if (g) {
+ int card = -1;
+ int len = GetFileLength(g);
+
+ if (len >= 0) {
+ if (Padded && Blksize) {
+ if (!(len % Blksize))
+ card = (len / Blksize) * Nrec;
+ else
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, Lrecl);
+
+ } else {
+ if (!(len % Lrecl))
+ card = len / (int)Lrecl; // Fixed length file
+ else
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, Lrecl);
+
+ } // endif Padded
+
+ if (trace(1))
+ htrc(" Computed max_K=%d Filen=%d lrecl=%d\n",
+ card, len, Lrecl);
+
+ } else
+ card = 0;
+
+ // Set number of blocks for later use
+ Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0;
+ return card;
+ } else
+ return 1;
+
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/* Note: This function is meant only for fixed length files but is */
+/* placed here to be available to FIXFAM and MPXFAM classes. */
+/***********************************************************************/
+int TXTFAM::MaxBlkSize(PGLOBAL g, int s)
+ {
+ int rc = RC_OK, savcur = CurBlk, blm1 = Block - 1;
+ int size, last = s - blm1 * Nrec;
+
+ // Roughly estimate the table size as the sum of blocks
+ // that can contain good rows
+ for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++)
+ if ((rc = Tdbp->TestBlock(g)) == RC_OK)
+ size += (CurBlk == blm1) ? last : Nrec;
+ else if (rc == RC_EF)
+ break;
+
+ CurBlk = savcur;
+ return size;
+ } // end of MaxBlkSize
+
+/***********************************************************************/
+/* AddListValue: Used when doing indexed update or delete. */
+/***********************************************************************/
+bool TXTFAM::AddListValue(PGLOBAL g, int type, void *val, PPARM *top)
+ {
+ PPARM pp = (PPARM)PlugSubAlloc(g, NULL, sizeof(PARM));
+
+ switch (type) {
+// case TYPE_INT:
+// pp->Value = PlugSubAlloc(g, NULL, sizeof(int));
+// *((int*)pp->Value) = *((int*)val);
+// break;
+ case TYPE_VOID:
+ pp->Intval = *(int*)val;
+ break;
+// case TYPE_STRING:
+// pp->Value = PlugDup(g, (char*)val);
+// break;
+ case TYPE_PCHAR:
+ pp->Value = val;
+ break;
+ default:
+ return true;
+ } // endswitch type
+
+ pp->Type = type;
+ pp->Domain = 0;
+ pp->Next = *top;
+ *top = pp;
+ return false;
+ } // end of AddListValue
+
+/***********************************************************************/
+/* Store needed values for indexed UPDATE or DELETE. */
+/***********************************************************************/
+int TXTFAM::StoreValues(PGLOBAL g, bool upd)
+{
+ int pos = GetPos();
+ bool rc = AddListValue(g, TYPE_VOID, &pos, &To_Pos);
+
+ if (!rc) {
+ pos = GetNextPos();
+ rc = AddListValue(g, TYPE_VOID, &pos, &To_Sos);
+ } // endif rc
+
+ if (upd && !rc) {
+ char *buf;
+
+ if (Tdbp->PrepareWriting(g))
+ return RC_FX;
+
+ buf = PlugDup(g, Tdbp->GetLine());
+ rc = AddListValue(g, TYPE_PCHAR, buf, &To_Upd);
+ } // endif upd
+
+ return rc ? RC_FX : RC_OK;
+} // end of StoreValues
+
+/***********************************************************************/
+/* UpdateSortedRows. When updating using indexing, the issue is that */
+/* record are not necessarily updated in sequential order. */
+/* Moving intermediate lines cannot be done while making them because */
+/* this can cause extra wrong records to be included in the new file. */
+/* What we do here is to reorder the updated records and do all the */
+/* updates ordered by record position. */
+/***********************************************************************/
+int TXTFAM::UpdateSortedRows(PGLOBAL g)
+ {
+ int *ix, i;
+
+ /*********************************************************************/
+ /* Get the stored update values and sort them. */
+ /*********************************************************************/
+ if (!(Posar = MakeValueArray(g, To_Pos))) {
+// strcpy(g->Message, "Position array is null");
+// return RC_INFO;
+ return RC_OK; // Nothing to do
+ } else if (!(Sosar = MakeValueArray(g, To_Sos))) {
+ strcpy(g->Message, "Start position array is null");
+ goto err;
+ } else if (!(Updar = MakeValueArray(g, To_Upd))) {
+ strcpy(g->Message, "Updated line array is null");
+ goto err;
+ } else if (!(ix = (int*)Posar->GetSortIndex(g))) {
+ strcpy(g->Message, "Error getting array sort index");
+ goto err;
+ } // endif's
+
+ Rewind();
+
+ for (i = 0; i < Posar->GetNval(); i++) {
+ SetPos(g, Sosar->GetIntValue(ix[i]));
+ Fpos = Posar->GetIntValue(ix[i]);
+ strcpy(Tdbp->To_Line, Updar->GetStringValue(ix[i]));
+
+ // Now write the updated line.
+ if (WriteBuffer(g))
+ goto err;
+
+ } // endfor i
+
+ return RC_OK;
+
+err:
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return RC_FX;
+ } // end of UpdateSortedRows
+
+/***********************************************************************/
+/* DeleteSortedRows. When deleting using indexing, the issue is that */
+/* record are not necessarily deleted in sequential order. Moving */
+/* intermediate lines cannot be done while deleing them because */
+/* this can cause extra wrong records to be included in the new file. */
+/* What we do here is to reorder the deleted record and delete from */
+/* the file from the ordered deleted records. */
+/***********************************************************************/
+int TXTFAM::DeleteSortedRows(PGLOBAL g)
+ {
+ int *ix, i, irc;
+
+ /*********************************************************************/
+ /* Get the stored delete values and sort them. */
+ /*********************************************************************/
+ if (!(Posar = MakeValueArray(g, To_Pos))) {
+// strcpy(g->Message, "Position array is null");
+// return RC_INFO;
+ return RC_OK; // Nothing to do
+ } else if (!(Sosar = MakeValueArray(g, To_Sos))) {
+ strcpy(g->Message, "Start position array is null");
+ goto err;
+ } else if (!(ix = (int*)Posar->GetSortIndex(g))) {
+ strcpy(g->Message, "Error getting array sort index");
+ goto err;
+ } // endif's
+
+ Tpos = Spos = 0;
+
+ for (i = 0; i < Posar->GetNval(); i++) {
+ if ((irc = InitDelete(g, Posar->GetIntValue(ix[i]),
+ Sosar->GetIntValue(ix[i]))) == RC_FX)
+ goto err;
+
+ // Now delete the sorted rows
+ if (DeleteRecords(g, irc))
+ goto err;
+
+ } // endfor i
+
+ return RC_OK;
+
+err:
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return RC_FX;
+ } // end of DeleteSortedRows
+
+/***********************************************************************/
+/* The purpose of this function is to deal with access methods that */
+/* are not coherent regarding the use of SetPos and GetPos. */
+/***********************************************************************/
+int TXTFAM::InitDelete(PGLOBAL g, int, int)
+ {
+ strcpy(g->Message, "InitDelete should not be used by this table type");
+ return RC_FX;
+ } // end of InitDelete
+
+/* --------------------------- Class DOSFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+DOSFAM::DOSFAM(PDOSDEF tdp) : TXTFAM(tdp)
+ {
+ To_Fbt = NULL;
+ Stream = NULL;
+ T_Stream = NULL;
+ UseTemp = false;
+ Bin = false;
+ } // end of DOSFAM standard constructor
+
+DOSFAM::DOSFAM(PDOSFAM tdfp) : TXTFAM(tdfp)
+ {
+ To_Fbt = tdfp->To_Fbt;
+ Stream = tdfp->Stream;
+ T_Stream = tdfp->T_Stream;
+ UseTemp = tdfp->UseTemp;
+ Bin = tdfp->Bin;
+ } // end of DOSFAM copy constructor
+
+DOSFAM::DOSFAM(PBLKFAM tdfp, PDOSDEF tdp) : TXTFAM(tdp)
+ {
+ Tdbp = tdfp->Tdbp;
+ To_Fb = tdfp->To_Fb;
+ To_Fbt = tdfp->To_Fbt;
+ Stream = tdfp->Stream;
+ T_Stream = tdfp->T_Stream;
+ UseTemp = tdfp->UseTemp;
+ Bin = tdfp->Bin;
+ } // end of DOSFAM constructor from BLKFAM
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void DOSFAM::Reset(void)
+ {
+ TXTFAM::Reset();
+ Bin = false;
+ Fpos = Tpos = Spos = 0;
+ } // end of Reset
+
+/***********************************************************************/
+/* DOS GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int DOSFAM::GetFileLength(PGLOBAL g)
+ {
+ int len;
+
+ if (!Stream)
+ len = TXTFAM::GetFileLength(g);
+ else
+ if ((len = _filelength(_fileno(Stream))) < 0)
+ sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", To_File);
+
+ if (trace(1))
+ htrc("File length=%d\n", len);
+
+ return len;
+ } // end of GetFileLength
+
+/***********************************************************************/
+/* Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int DOSFAM::Cardinality(PGLOBAL g)
+ {
+ return (g) ? -1 : 0;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/* Note: This function is not really implemented yet. */
+/***********************************************************************/
+int DOSFAM::MaxBlkSize(PGLOBAL, int s)
+ {
+ return s;
+ } // end of MaxBlkSize
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file using C standard I/Os. */
+/***********************************************************************/
+bool DOSFAM::OpenTableFile(PGLOBAL g)
+ {
+ char opmode[4], filename[_MAX_PATH];
+//int ftype = Tdbp->GetFtype();
+ MODE mode = Tdbp->Mode;
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ // This is required when using Unix files under Windows and vice versa
+//Bin = (Blocked || Ending != CRLF);
+ Bin = true; // To avoid ftell problems
+
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "r");
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->Next) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ if (Blocked) {
+ // Cardinality must return 0
+ Block = 0;
+ Last = Nrec;
+ } // endif blocked
+
+ // This will erase the entire file
+ strcpy(opmode, "w");
+ Tdbp->ResetSize();
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ Bin = true;
+ /* fall through */
+ case MODE_UPDATE:
+ if ((UseTemp = Tdbp->IsUsingTemp(g))) {
+ strcpy(opmode, "r");
+ Bin = true;
+ } else
+ strcpy(opmode, "r+");
+
+ break;
+ case MODE_INSERT:
+ strcpy(opmode, "a+");
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ // For blocked I/O or for moving lines, open the table in binary
+ strcat(opmode, (Bin) ? "b" : "t");
+
+ // Now open the file stream
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!(Stream = PlugOpenFile(g, filename, opmode))) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return (mode == MODE_READ && errno == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif Stream
+
+ if (trace(1))
+ htrc("File %s open Stream=%p mode=%s\n", filename, Stream, opmode);
+
+ To_Fb = dbuserp->Openlist; // Keep track of File block
+
+ /*********************************************************************/
+ /* Allocate the line buffer. For mode Delete a bigger buffer has to */
+ /* be allocated because is it also used to move lines into the file.*/
+ /*********************************************************************/
+ return AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Allocate the line buffer. For mode Delete a bigger buffer has to */
+/* be allocated because is it also used to move lines into the file. */
+/***********************************************************************/
+bool DOSFAM::AllocateBuffer(PGLOBAL g)
+ {
+ MODE mode = Tdbp->Mode;
+
+ // Lrecl does not include line ending
+ Buflen = Lrecl + Ending + ((Bin) ? 1 : 0) + 1; // Sergei
+
+ if (trace(1))
+ htrc("SubAllocating a buffer of %d bytes\n", Buflen);
+
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (UseTemp || mode == MODE_DELETE) {
+ // Have a big buffer to move lines
+ Dbflen = Buflen * DOS_BUFF_LEN;
+ DelBuf = PlugSubAlloc(g, NULL, Dbflen);
+ } else if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* Prepare the buffer so eventual gaps are filled with blanks. */
+ /*******************************************************************/
+ memset(To_Buf, ' ', Buflen);
+ To_Buf[Buflen - 2] = '\n';
+ To_Buf[Buflen - 1] = '\0';
+ } // endif's mode
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int DOSFAM::GetRowID(void)
+ {
+ return Rows;
+ } // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int DOSFAM::GetPos(void)
+ {
+ return Fpos;
+ } // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: return the position of next record. */
+/***********************************************************************/
+int DOSFAM::GetNextPos(void)
+ {
+ return ftell(Stream);
+ } // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool DOSFAM::SetPos(PGLOBAL g, int pos)
+ {
+ Fpos = pos;
+
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
+ return true;
+ } // endif
+
+ Placed = true;
+ return false;
+ } // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/***********************************************************************/
+bool DOSFAM::RecordPos(PGLOBAL g)
+ {
+ if ((Fpos = ftell(Stream)) < 0) {
+ sprintf(g->Message, MSG(FTELL_ERROR), 0, strerror(errno));
+// strcat(g->Message, " (possible wrong ENDING option value)");
+ return true;
+ } // endif Fpos
+
+ return false;
+ } // end of RecordPos
+
+/***********************************************************************/
+/* Initialize Fpos and the current position for indexed DELETE. */
+/***********************************************************************/
+int DOSFAM::InitDelete(PGLOBAL g, int fpos, int spos)
+ {
+ Fpos = fpos;
+
+ if (fseek(Stream, spos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
+ return RC_FX;
+ } // endif
+
+ return RC_OK;
+ } // end of InitDelete
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int DOSFAM::SkipRecord(PGLOBAL g, bool header)
+ {
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ // Skip this record
+ if (!fgets(To_Buf, Buflen, Stream)) {
+ if (feof(Stream))
+ return RC_EF;
+
+#if defined(_WIN32)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0));
+#endif
+ return RC_FX;
+ } // endif fgets
+
+ // Update progress information
+ dup->ProgCur = GetPos();
+
+ if (header) {
+ // For Delete
+ Fpos = ftell(Stream);
+
+ if (!UseTemp)
+ Tpos = Spos = Fpos; // No need to move header
+
+ } // endif header
+
+#if defined(THREAD)
+ return RC_NF; // To have progress info
+#else
+ return RC_OK; // To loop locally
+#endif
+ } // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a text file. */
+/***********************************************************************/
+int DOSFAM::ReadBuffer(PGLOBAL g)
+ {
+ char *p;
+ int rc;
+
+ if (!Stream)
+ return RC_EF;
+
+ if (trace(2))
+ htrc("ReadBuffer: Tdbp=%p To_Line=%p Placed=%d\n",
+ Tdbp, Tdbp->To_Line, Placed);
+
+ if (!Placed) {
+ /*******************************************************************/
+ /* Record file position in case of UPDATE or DELETE. */
+ /*******************************************************************/
+ next:
+ if (RecordPos(g))
+ return RC_FX;
+
+ CurBlk = (int)Rows++;
+
+ if (trace(2))
+ htrc("ReadBuffer: CurBlk=%d\n", CurBlk);
+
+ /********************************************************************/
+ /* Check whether optimization on ROWID */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ // Skip this record
+ if ((rc = SkipRecord(g, FALSE)) != RC_OK)
+ return rc;
+
+ goto next;
+ } // endswitch rc
+
+ } else
+ Placed = false;
+
+ if (trace(2))
+ htrc(" About to read: stream=%p To_Buf=%p Buflen=%d Fpos=%d\n",
+ Stream, To_Buf, Buflen, Fpos);
+
+ if (fgets(To_Buf, Buflen, Stream)) {
+ p = To_Buf + strlen(To_Buf) - 1;
+
+ if (trace(2))
+ htrc(" Read: To_Buf=%p p=%c\n", To_Buf, p);
+
+#if defined(_WIN32)
+ if (Bin) {
+ // Data file is read in binary so CRLF remains
+#else
+ if (true) {
+ // Data files can be imported from Windows (having CRLF)
+#endif
+ if (*p == '\n' || *p == '\r') {
+ // is this enough for Unix ???
+ *p = '\0'; // Eliminate ending CR or LF character
+
+ if (p > To_Buf) {
+ // is this enough for Unix ???
+ p--;
+
+ if (*p == '\n' || *p == '\r')
+ *p = '\0'; // Eliminate ending CR or LF character
+
+ } // endif To_Buf
+
+ } // endif p
+
+ } else if (*p == '\n')
+ *p = '\0'; // Eliminate ending new-line character
+
+ if (trace(2))
+ htrc(" To_Buf='%s'\n", To_Buf);
+
+ strcpy(Tdbp->To_Line, To_Buf);
+ num_read++;
+ rc = RC_OK;
+ } else if (feof(Stream)) {
+ rc = RC_EF;
+ } else {
+#if defined(_WIN32)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0));
+#endif
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ rc = RC_FX;
+ } // endif's fgets
+
+ if (trace(2))
+ htrc("ReadBuffer: rc=%d\n", rc);
+
+ IsRead = true;
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for DOS access method. */
+/***********************************************************************/
+int DOSFAM::WriteBuffer(PGLOBAL g)
+ {
+ int curpos = 0;
+ bool moved = true;
+
+ // T_Stream is the temporary stream or the table file stream itself
+ if (!T_Stream) {
+ if (UseTemp && Tdbp->Mode == MODE_UPDATE) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+
+ } // endif T_Stream
+
+ if (Tdbp->Mode == MODE_UPDATE) {
+ /*******************************************************************/
+ /* Here we simply rewrite a record on itself. There are two cases */
+ /* were another method should be used, a/ when Update apply to */
+ /* the whole file, b/ when updating the last field of a variable */
+ /* length file. The method could be to rewrite a new file, then */
+ /* to erase the old one and rename the new updated file. */
+ /*******************************************************************/
+ curpos = ftell(Stream);
+
+ if (trace(1))
+ htrc("Last : %d cur: %d\n", Fpos, curpos);
+
+ if (UseTemp) {
+ /*****************************************************************/
+ /* We are using a temporary file. */
+ /* Before writing the updated record, we must eventually copy */
+ /* all the intermediate records that have not been updated. */
+ /*****************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ Spos = curpos; // New start position
+ } else
+ // Update is directly written back into the file,
+ // with this (fast) method, record size cannot change.
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif
+
+ } // endif mode
+
+ /*********************************************************************/
+ /* Prepare the write the updated line. */
+ /*********************************************************************/
+ strcat(strcpy(To_Buf, Tdbp->To_Line), (Bin) ? CrLf : "\n");
+
+ /*********************************************************************/
+ /* Now start the writing process. */
+ /*********************************************************************/
+ if ((fputs(To_Buf, T_Stream)) == EOF) {
+ sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif EOF
+
+ if (Tdbp->Mode == MODE_UPDATE && moved)
+ if (fseek(Stream, curpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+
+ if (trace(1))
+ htrc("write done\n");
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for DOS and BLK access methods. */
+/***********************************************************************/
+int DOSFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool moved;
+ int curpos = ftell(Stream);
+
+ /*********************************************************************/
+ /* There is an alternative here: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /* This will be experimented. */
+ /*********************************************************************/
+ if (trace(1))
+ htrc(
+ "DOS DeleteDB: rc=%d UseTemp=%d curpos=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, curpos, Fpos, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ fseek(Stream, 0, SEEK_END);
+ Fpos = ftell(Stream);
+
+ if (trace(1))
+ htrc("Fpos placed at file end=%d\n", Fpos);
+
+ } // endif irc
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete, Open temporary file. */
+ /*******************************************************************/
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ T_Stream = Stream;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+ /*******************************************************************/
+ /* Reposition the file pointer and set Spos. */
+ /*******************************************************************/
+ if (!UseTemp || moved)
+ if (fseek(Stream, curpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif
+
+ Spos = GetNextPos(); // New start position
+
+ if (trace(1))
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /* The UseTemp case is treated in CloseTableFile. */
+ /*******************************************************************/
+ if (!UseTemp & !Abort) {
+ /*****************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the file and reopen it with the */
+ /* open function (_fopen for MS ??) this is still to be checked */
+ /* for compatibility with Text files and other OS's. */
+ /*****************************************************************/
+ char filename[_MAX_PATH];
+ int h; // File handle, return code
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+ /*rc=*/ PlugCloseFile(g, To_Fb);
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+#if defined(_WIN32)
+ if (chsize(h, Tpos)) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (ftruncate(h, (off_t)Tpos)) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+ if (trace(1))
+ htrc("done, h=%d irc=%d\n", h, irc);
+
+ } // endif !UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open a temporary file used while updating or deleting. */
+/***********************************************************************/
+bool DOSFAM::OpenTempFile(PGLOBAL g)
+ {
+ char tempname[_MAX_PATH];
+ bool rc = false;
+
+ /*********************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*********************************************************************/
+ PlugSetPath(tempname, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(tempname, tempname), ".t");
+
+ if (!(T_Stream = PlugOpenFile(g, tempname, "wb"))) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ rc = true;
+ } else
+ To_Fbt = PlgGetUser(g)->Openlist;
+
+ return rc;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/* This works only for file open in binary mode. */
+/***********************************************************************/
+bool DOSFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int n;
+ size_t req, len;
+
+ for (*b = false, n = Fpos - Spos; n > 0; n -= req) {
+ if (!UseTemp || !*b)
+ if (fseek(Stream, Spos, SEEK_SET)) {
+ sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ req = (size_t)MY_MIN(n, Dbflen);
+ len = fread(DelBuf, 1, req, Stream);
+
+ if (trace(1))
+ htrc("after read req=%d len=%d\n", req, len);
+
+ if (len != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), (int) req, (int) len);
+ return true;
+ } // endif len
+
+ if (!UseTemp)
+ if (fseek(T_Stream, Tpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(DelBuf, 1, req, T_Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ if (trace(1))
+ htrc("after write pos=%d\n", ftell(Stream));
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (trace(1))
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ *b = true;
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediate Lines
+
+/***********************************************************************/
+/* Delete the old file and rename the new temp file. */
+/* If aborting just delete the new temp file. */
+/* If indexed, make the temp file from the arrays. */
+/***********************************************************************/
+int DOSFAM::RenameTempFile(PGLOBAL g)
+ {
+ char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH];
+ int rc = RC_OK;
+
+ if (To_Fbt)
+ tempname = (char*)To_Fbt->Fname;
+ else
+ return RC_INFO; // Nothing to do ???
+
+ // This loop is necessary because, in case of join,
+ // To_File can have been open several times.
+ for (PFBLOCK fb = PlgGetUser(g)->Openlist; fb; fb = fb->Next)
+ if (fb == To_Fb || (fb == To_Fbt))
+ rc = PlugCloseFile(g, fb);
+
+ if (!Abort) {
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(filetemp, filename), ".ttt");
+ remove(filetemp); // May still be there from previous error
+
+ if (rename(filename, filetemp)) { // Save file for security
+ snprintf(g->Message, MAX_STR, MSG(RENAME_ERROR),
+ filename, filetemp, strerror(errno));
+ throw 51;
+ } else if (rename(tempname, filename)) {
+ snprintf(g->Message, MAX_STR, MSG(RENAME_ERROR),
+ tempname, filename, strerror(errno));
+ rc = rename(filetemp, filename); // Restore saved file
+ throw 52;
+ } else if (remove(filetemp)) {
+ sprintf(g->Message, MSG(REMOVE_ERROR),
+ filetemp, strerror(errno));
+ rc = RC_INFO; // Acceptable
+ } // endif's
+
+ } else
+ remove(tempname);
+
+ return rc;
+ } // end of RenameTempFile
+
+/***********************************************************************/
+/* Table file close routine for DOS access method. */
+/***********************************************************************/
+void DOSFAM::CloseTableFile(PGLOBAL g, bool abort)
+ {
+ int rc;
+
+ Abort = abort;
+
+ if (UseTemp && T_Stream) {
+ if (Tdbp->Mode == MODE_UPDATE && !Abort) {
+ // Copy eventually remaining lines
+ bool b;
+
+ fseek(Stream, 0, SEEK_END);
+ Fpos = ftell(Stream);
+ Abort = MoveIntermediateLines(g, &b) != RC_OK;
+ } // endif Abort
+
+ // Delete the old file and rename the new temp file.
+ rc = RenameTempFile(g); // Also close all files
+ } else {
+ rc = PlugCloseFile(g, To_Fb);
+
+ if (trace(1))
+ htrc("DOS Close: closing %s rc=%d\n", To_File, rc);
+
+ } // endif UseTemp
+
+ Stream = NULL; // So we can know whether table is open
+ T_Stream = NULL;
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for DOS access method. */
+/***********************************************************************/
+void DOSFAM::Rewind(void)
+ {
+ if (Stream) // Can be NULL when making index on void table
+ rewind(Stream);
+
+ Rows = 0;
+ OldBlk = CurBlk = -1;
+ } // end of Rewind
+
+/* --------------------------- Class BLKFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+BLKFAM::BLKFAM(PDOSDEF tdp) : DOSFAM(tdp)
+ {
+ Blocked = true;
+ Block = tdp->GetBlock();
+ Last = tdp->GetLast();
+ Nrec = tdp->GetElemt();
+ Closing = false;
+ BlkPos = tdp->GetTo_Pos();
+ CurLine = NULL;
+ NxtLine = NULL;
+ OutBuf = NULL;
+ } // end of BLKFAM standard constructor
+
+BLKFAM::BLKFAM(PBLKFAM txfp) : DOSFAM(txfp)
+ {
+ Closing = txfp->Closing;
+ CurLine = txfp->CurLine;
+ NxtLine = txfp->NxtLine;
+ OutBuf = txfp->OutBuf;
+ } // end of BLKFAM copy constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void BLKFAM::Reset(void)
+ {
+ DOSFAM::Reset();
+ Closing = false;
+ } // end of Reset
+
+/***********************************************************************/
+/* Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int BLKFAM::Cardinality(PGLOBAL g)
+ {
+ return (g) ? ((Block > 0) ? (int)((Block - 1) * Nrec + Last) : 0) : 1;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/***********************************************************************/
+int BLKFAM::MaxBlkSize(PGLOBAL g, int)
+ {
+ int rc = RC_OK, savcur = CurBlk;
+ int size;
+
+ // Roughly estimate the table size as the sum of blocks
+ // that can contain good rows
+ for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++)
+ if ((rc = Tdbp->TestBlock(g)) == RC_OK)
+ size += (CurBlk == Block - 1) ? Last : Nrec;
+ else if (rc == RC_EF)
+ break;
+
+ CurBlk = savcur;
+ return size;
+ } // end of MaxBlkSize
+
+/***********************************************************************/
+/* Allocate the line buffer. For mode Delete or when a temp file is */
+/* used another big buffer has to be allocated because is it used */
+/* to move or update the lines into the (temp) file. */
+/***********************************************************************/
+bool BLKFAM::AllocateBuffer(PGLOBAL g)
+ {
+ int len;
+ MODE mode = Tdbp->GetMode();
+
+ // For variable length files, Lrecl does not include CRLF
+ len = Lrecl + ((Tdbp->GetFtype()) ? 0 : Ending);
+ Buflen = len * Nrec;
+ CurLine = To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+
+ if (UseTemp || mode == MODE_DELETE) {
+ if (mode == MODE_UPDATE)
+ OutBuf = (char*)PlugSubAlloc(g, NULL, len + 1);
+
+ Dbflen = Buflen;
+ DelBuf = PlugSubAlloc(g, NULL, Dbflen);
+ } else if (mode == MODE_INSERT)
+ Rbuf = Nrec; // To be used by WriteDB
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int BLKFAM::GetRowID(void)
+ {
+ return CurNum + Nrec * CurBlk + 1;
+ } // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int BLKFAM::GetPos(void)
+ {
+ return (CurNum + Nrec * CurBlk); // Computed file index
+ } // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: called by DeleteRecords. */
+/***********************************************************************/
+int BLKFAM::GetNextPos(void)
+ {
+ return (int)(Fpos + NxtLine - CurLine);
+ } // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool BLKFAM::SetPos(PGLOBAL g, int)
+ {
+ strcpy(g->Message, "Blocked variable tables cannot be used indexed");
+ return true;
+ } // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/* Not used yet for blocked tables. */
+/***********************************************************************/
+bool BLKFAM::RecordPos(PGLOBAL)
+ {
+ Fpos = (CurNum + Nrec * CurBlk); // Computed file index
+ return false;
+ } // end of RecordPos
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int BLKFAM::SkipRecord(PGLOBAL, bool header)
+ {
+ if (header) {
+ // For Delete
+ Fpos = BlkPos[0]; // First block starts after the header
+
+ if (!UseTemp)
+ Tpos = Spos = Fpos; // No need to move header
+
+ } // endif header
+
+ OldBlk = -2; // To force fseek on first block
+ return RC_OK;
+ } // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a text file. */
+/***********************************************************************/
+int BLKFAM::ReadBuffer(PGLOBAL g)
+ {
+ int i, rc = RC_OK;
+ size_t n;
+
+ /*********************************************************************/
+ /* Sequential reading when Placed is not true. */
+ /*********************************************************************/
+ if (Placed) {
+ Placed = false;
+ } else if (++CurNum < Rbuf) {
+ CurLine = NxtLine;
+
+ // Get the position of the next line in the buffer
+ while (*NxtLine++ != '\n') ;
+
+ // Set caller line buffer
+ n = NxtLine - CurLine - Ending;
+ memcpy(Tdbp->GetLine(), CurLine, n);
+ Tdbp->GetLine()[n] = '\0';
+ goto fin;
+ } else if (Rbuf < Nrec && CurBlk != -1) {
+ return RC_EF;
+ } else {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ next:
+ if (++CurBlk >= Block)
+ return RC_EF;
+
+ /*******************************************************************/
+ /* Before reading a new block, check whether block optimization */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ goto next;
+ } // endswitch rc
+
+ } // endif's
+
+ if (OldBlk == CurBlk)
+ goto ok; // Block is already there
+
+ // fseek is required only in non sequential reading
+ if (CurBlk != OldBlk + 1)
+ if (fseek(Stream, BlkPos[CurBlk], SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), BlkPos[CurBlk]);
+ return RC_FX;
+ } // endif fseek
+
+ // Calculate the length of block to read
+ BlkLen = BlkPos[CurBlk + 1] - BlkPos[CurBlk];
+
+ if (trace(1))
+ htrc("File position is now %d\n", ftell(Stream));
+
+ // Read the entire next block
+ n = fread(To_Buf, 1, (size_t)BlkLen, Stream);
+
+ if ((size_t) n == (size_t) BlkLen) {
+// ReadBlks++;
+ num_read++;
+ Rbuf = (CurBlk == Block - 1) ? Last : Nrec;
+
+ ok:
+ rc = RC_OK;
+
+ // Get the position of the current line
+ for (i = 0, CurLine = To_Buf; i < CurNum; i++)
+ while (*CurLine++ != '\n') ; // What about Unix ???
+
+ // Now get the position of the next line
+ for (NxtLine = CurLine; *NxtLine++ != '\n';) ;
+
+ // Set caller line buffer
+ n = NxtLine - CurLine - Ending;
+ memcpy(Tdbp->GetLine(), CurLine, n);
+ Tdbp->GetLine()[n] = '\0';
+ } else if (feof(Stream)) {
+ rc = RC_EF;
+ } else {
+#if defined(_WIN32)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(errno));
+#endif
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return RC_FX;
+ } // endelse
+
+ OldBlk = CurBlk; // Last block actually read
+ IsRead = true; // Is read indeed
+
+ fin:
+ // Store the current record file position for Delete and Update
+ Fpos = (int)(BlkPos[CurBlk] + CurLine - To_Buf);
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for the blocked DOS access method. */
+/* Update is directly written back into the file, */
+/* with this (fast) method, record size cannot change. */
+/***********************************************************************/
+int BLKFAM::WriteBuffer(PGLOBAL g)
+ {
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode, blocks are added sequentially to the file end. */
+ /*******************************************************************/
+ if (!Closing) { // Add line to the write buffer
+ strcat(strcpy(CurLine, Tdbp->GetLine()), CrLf);
+
+ if (++CurNum != Rbuf) {
+ CurLine += strlen(CurLine);
+ return RC_OK; // We write only full blocks
+ } // endif CurNum
+
+ } // endif Closing
+
+ // Now start the writing process.
+ NxtLine = CurLine + strlen(CurLine);
+ BlkLen = (int)(NxtLine - To_Buf);
+
+ if (fwrite(To_Buf, 1, BlkLen, Stream) != (size_t)BlkLen) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ Closing = true; // To tell CloseDB about a Write error
+ return RC_FX;
+ } // endif size
+
+ CurBlk++;
+ CurNum = 0;
+ CurLine = To_Buf;
+ } else {
+ /*******************************************************************/
+ /* Mode == MODE_UPDATE. */
+ /*******************************************************************/
+ const char *crlf;
+ size_t len;
+ int curpos = ftell(Stream);
+ bool moved = true;
+
+ // T_Stream is the temporary stream or the table file stream itself
+ if (!T_Stream)
+ {
+ if (UseTemp /*&& Tdbp->GetMode() == MODE_UPDATE*/) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+ }
+ if (UseTemp) {
+ /*****************************************************************/
+ /* We are using a temporary file. Before writing the updated */
+ /* record, we must eventually copy all the intermediate records */
+ /* that have not been updated. */
+ /*****************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ Spos = GetNextPos(); // New start position
+
+ // Prepare the output buffer
+#if defined(_WIN32)
+ crlf = "\r\n";
+#else
+ crlf = "\n";
+#endif // _WIN32
+ strcat(strcpy(OutBuf, Tdbp->GetLine()), crlf);
+ len = strlen(OutBuf);
+ } else {
+ if (fseek(Stream, Fpos, SEEK_SET)) { // Fpos is last position
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif fseek
+
+ // Replace the line inside read buffer (length has not changed)
+ memcpy(CurLine, Tdbp->GetLine(), strlen(Tdbp->GetLine()));
+ OutBuf = CurLine;
+ len = (size_t)(NxtLine - CurLine);
+ } // endif UseTemp
+
+ if (fwrite(OutBuf, 1, len, T_Stream) != (size_t)len) {
+ sprintf(g->Message, MSG(FWRITE_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif fwrite
+
+ if (moved)
+ if (fseek(Stream, curpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Table file close routine for DOS access method. */
+/***********************************************************************/
+void BLKFAM::CloseTableFile(PGLOBAL g, bool abort)
+ {
+ int rc, wrc = RC_OK;
+
+ Abort = abort;
+
+ if (UseTemp && T_Stream) {
+ if (Tdbp->GetMode() == MODE_UPDATE && !Abort) {
+ // Copy eventually remaining lines
+ bool b;
+
+ fseek(Stream, 0, SEEK_END);
+ Fpos = ftell(Stream);
+ Abort = MoveIntermediateLines(g, &b) != RC_OK;
+ } // endif Abort
+
+ // Delete the old file and rename the new temp file.
+ rc = RenameTempFile(g); // Also close all files
+ } else {
+ // Closing is True if last Write was in error
+ if (Tdbp->GetMode() == MODE_INSERT && CurNum && !Closing) {
+ // Some more inserted lines remain to be written
+ Rbuf = CurNum--;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else if (Modif && !Closing) {
+ // Last updated block remains to be written
+ Closing = true;
+ wrc = ReadBuffer(g);
+ } // endif's
+
+ rc = PlugCloseFile(g, To_Fb);
+
+ if (trace(1))
+ htrc("BLK CloseTableFile: closing %s mode=%d wrc=%d rc=%d\n",
+ To_File, Tdbp->GetMode(), wrc, rc);
+
+ } // endif UseTemp
+
+ Stream = NULL; // So we can know whether table is open
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for DOS access method. */
+/* Note: commenting out OldBlk = -1 has two advantages: */
+/* 1 - It forces fseek on first block, thus suppressing the need to */
+/* rewind the file, anyway unuseful when second pass if indexed. */
+/* 2 - It permit to avoid re-reading small tables having only 1 block.*/
+/***********************************************************************/
+void BLKFAM::Rewind(void)
+ {
+//rewind(Stream); will be placed by fseek
+ CurBlk = -1;
+ CurNum = Rbuf;
+//OldBlk = -1; commented out in case we reuse last read block
+//Rbuf = 0; commented out in case we reuse last read block
+ } // end of Rewind
+
+/* --------------------------- Class BINFAM -------------------------- */
+
+#if 0
+/***********************************************************************/
+/* BIN GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int BINFAM::GetFileLength(PGLOBAL g)
+{
+ int len;
+
+ if (!Stream)
+ len = TXTFAM::GetFileLength(g);
+ else
+ if ((len = _filelength(_fileno(Stream))) < 0)
+ sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", To_File);
+
+ xtrc(1, "File length=%d\n", len);
+ return len;
+} // end of GetFileLength
+
+/***********************************************************************/
+/* Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int BINFAM::Cardinality(PGLOBAL g)
+{
+ return (g) ? -1 : 0;
+} // end of Cardinality
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file using C standard I/Os. */
+/***********************************************************************/
+bool BINFAM::OpenTableFile(PGLOBAL g) {
+ char opmode[4], filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "rb");
+ break;
+ case MODE_WRITE:
+ strcpy(opmode, "wb");
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ // Now open the file stream
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!(Stream = PlugOpenFile(g, filename, opmode))) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return (mode == MODE_READ && errno == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif Stream
+
+ if (trace(1))
+ htrc("File %s open Stream=%p mode=%s\n", filename, Stream, opmode);
+
+ To_Fb = dbuserp->Openlist; // Keep track of File block
+
+ /*********************************************************************/
+ /* Allocate the line buffer. */
+ /*********************************************************************/
+ return AllocateBuffer(g);
+} // end of OpenTableFile
+#endif // 0
+
+/***********************************************************************/
+/* Allocate the line buffer. For mode Delete a bigger buffer has to */
+/* be allocated because is it also used to move lines into the file. */
+/***********************************************************************/
+bool BINFAM::AllocateBuffer(PGLOBAL g)
+{
+ MODE mode = Tdbp->GetMode();
+
+ // Lrecl is Ok
+ Buflen = Lrecl;
+
+ // Buffer will be allocated separately
+ if (mode == MODE_ANY) {
+ xtrc(1, "SubAllocating a buffer of %d bytes\n", Buflen);
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+ } else if (UseTemp || mode == MODE_DELETE) {
+ // Have a big buffer to move lines
+ Dbflen = Buflen * DOS_BUFF_LEN;
+ DelBuf = PlugSubAlloc(g, NULL, Dbflen);
+ } // endif mode
+
+ return false;
+#if 0
+ MODE mode = Tdbp->GetMode();
+
+ // Lrecl is Ok
+ Dbflen = Buflen = Lrecl;
+
+ if (trace(1))
+ htrc("SubAllocating a buffer of %d bytes\n", Buflen);
+
+ DelBuf = To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+ return false;
+#endif // 0
+} // end of AllocateBuffer
+
+#if 0
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int BINFAM::GetRowID(void) {
+ return Rows;
+} // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int BINFAM::GetPos(void) {
+ return Fpos;
+} // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: return the position of next record. */
+/***********************************************************************/
+int BINFAM::GetNextPos(void) {
+ return ftell(Stream);
+} // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool BINFAM::SetPos(PGLOBAL g, int pos) {
+ Fpos = pos;
+
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), Fpos);
+ return true;
+ } // endif
+
+ Placed = true;
+ return false;
+} // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/***********************************************************************/
+bool BINFAM::RecordPos(PGLOBAL g) {
+ if ((Fpos = ftell(Stream)) < 0) {
+ sprintf(g->Message, MSG(FTELL_ERROR), 0, strerror(errno));
+ // strcat(g->Message, " (possible wrong ENDING option value)");
+ return true;
+ } // endif Fpos
+
+ return false;
+} // end of RecordPos
+#endif // 0
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a text file. */
+/***********************************************************************/
+int BINFAM::ReadBuffer(PGLOBAL g)
+{
+ int rc;
+
+ if (!Stream)
+ return RC_EF;
+
+ xtrc(2, "ReadBuffer: Tdbp=%p To_Line=%p Placed=%d\n",
+ Tdbp, Tdbp->GetLine(), Placed);
+
+ if (!Placed) {
+ /*******************************************************************/
+ /* Record file position in case of UPDATE or DELETE. */
+ /*******************************************************************/
+ if (RecordPos(g))
+ return RC_FX;
+
+ CurBlk = (int)Rows++;
+ xtrc(2, "ReadBuffer: CurBlk=%d\n", CurBlk);
+ } else
+ Placed = false;
+
+ xtrc(2, " About to read: bstream=%p To_Buf=%p Buflen=%d Fpos=%d\n",
+ Stream, To_Buf, Buflen, Fpos);
+
+ // Read the prefix giving the row length
+ if (!fread(&Recsize, sizeof(size_t), 1, Stream)) {
+ if (!feof(Stream)) {
+ strcpy(g->Message, "Error reading line prefix\n");
+ return RC_FX;
+ } else
+ return RC_EF;
+
+ } else if (Recsize > (unsigned)Buflen) {
+ sprintf(g->Message, "Record too big (Recsize=%zd Buflen=%d)\n", Recsize, Buflen);
+ return RC_FX;
+ } // endif Recsize
+
+ if (fread(To_Buf, Recsize, 1, Stream)) {
+ xtrc(2, " Read: To_Buf=%p Recsize=%zd\n", To_Buf, Recsize);
+ num_read++;
+ rc = RC_OK;
+ } else if (feof(Stream)) {
+ rc = RC_EF;
+ } else {
+#if defined(_WIN32)
+ sprintf(g->Message, MSG(READ_ERROR), To_File, _strerror(NULL));
+#else
+ sprintf(g->Message, MSG(READ_ERROR), To_File, strerror(0));
+#endif
+ xtrc(2, "%s\n", g->Message);
+ rc = RC_FX;
+ } // endif's fread
+
+ xtrc(2, "ReadBuffer: rc=%d\n", rc);
+ IsRead = true;
+ return rc;
+} // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for BIN access method. */
+/***********************************************************************/
+int BINFAM::WriteBuffer(PGLOBAL g)
+{
+ int curpos = 0;
+ bool moved = true;
+
+ // T_Stream is the temporary stream or the table file stream itself
+ if (!T_Stream) {
+ if (UseTemp && Tdbp->GetMode() == MODE_UPDATE) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+
+ } // endif T_Stream
+
+ if (Tdbp->GetMode() == MODE_UPDATE) {
+ /*******************************************************************/
+ /* Here we simply rewrite a record on itself. There are two cases */
+ /* were another method should be used, a/ when Update apply to */
+ /* the whole file, b/ when updating the last field of a variable */
+ /* length file. The method could be to rewrite a new file, then */
+ /* to erase the old one and rename the new updated file. */
+ /*******************************************************************/
+ curpos = ftell(Stream);
+
+ if (trace(1))
+ htrc("Last : %d cur: %d\n", Fpos, curpos);
+
+ if (UseTemp) {
+ /*****************************************************************/
+ /* We are using a temporary file. */
+ /* Before writing the updated record, we must eventually copy */
+ /* all the intermediate records that have not been updated. */
+ /*****************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ Spos = curpos; // New start position
+ } else
+ // Update is directly written back into the file,
+ // with this (fast) method, record size cannot change.
+ if (fseek(Stream, Fpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif
+
+ } // endif mode
+
+ /*********************************************************************/
+ /* Prepare writing the line. */
+ /*********************************************************************/
+//memcpy(To_Buf, Tdbp->GetLine(), Recsize);
+
+ /*********************************************************************/
+ /* Now start the writing process. */
+ /*********************************************************************/
+ if (fwrite(&Recsize, sizeof(size_t), 1, T_Stream) != 1) {
+ sprintf(g->Message, "Error %d writing prefix to %s",
+ errno, To_File);
+ return RC_FX;
+ } else if (fwrite(To_Buf, Recsize, 1, T_Stream) != 1) {
+ sprintf(g->Message, "Error %d writing %zd bytes to %s",
+ errno, Recsize, To_File);
+ return RC_FX;
+ } // endif fwrite
+
+ if (Tdbp->GetMode() == MODE_UPDATE && moved)
+ if (fseek(Stream, curpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+
+ xtrc(1, "Binary write done\n");
+ return RC_OK;
+} // end of WriteBuffer
+
+#if 0
+/***********************************************************************/
+/* Data Base delete line routine for DOS and BLK access methods. */
+/***********************************************************************/
+int DOSFAM::DeleteRecords(PGLOBAL g, int irc)
+{
+ bool moved;
+ int curpos = ftell(Stream);
+
+ /*********************************************************************/
+ /* There is an alternative here: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /* This will be experimented. */
+ /*********************************************************************/
+ if (trace(1))
+ htrc(
+ "DOS DeleteDB: rc=%d UseTemp=%d curpos=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, curpos, Fpos, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ fseek(Stream, 0, SEEK_END);
+ Fpos = ftell(Stream);
+
+ if (trace(1))
+ htrc("Fpos placed at file end=%d\n", Fpos);
+
+ } // endif irc
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete, Open temporary file. */
+ /*******************************************************************/
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ T_Stream = Stream;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &moved))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+ /*******************************************************************/
+ /* Reposition the file pointer and set Spos. */
+ /*******************************************************************/
+ if (!UseTemp || moved)
+ if (fseek(Stream, curpos, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSETPOS_ERROR), 0);
+ return RC_FX;
+ } // endif
+
+ Spos = GetNextPos(); // New start position
+
+ if (trace(1))
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /* The UseTemp case is treated in CloseTableFile. */
+ /*******************************************************************/
+ if (!UseTemp & !Abort) {
+ /*****************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the file and reopen it with the */
+ /* open function (_fopen for MS ??) this is still to be checked */
+ /* for compatibility with Text files and other OS's. */
+ /*****************************************************************/
+ char filename[_MAX_PATH];
+ int h; // File handle, return code
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+ /*rc=*/ PlugCloseFile(g, To_Fb);
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+#if defined(_WIN32)
+ if (chsize(h, Tpos)) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (ftruncate(h, (off_t)Tpos)) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+ if (trace(1))
+ htrc("done, h=%d irc=%d\n", h, irc);
+
+ } // endif !UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+} // end of DeleteRecords
+
+/***********************************************************************/
+/* Table file close routine for DOS access method. */
+/***********************************************************************/
+void BINFAM::CloseTableFile(PGLOBAL g, bool abort)
+{
+ int rc;
+
+ Abort = abort;
+ rc = PlugCloseFile(g, To_Fb);
+ xtrc(1, "BIN Close: closing %s rc=%d\n", To_File, rc);
+ Stream = NULL; // So we can know whether table is open
+} // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for BIN access method. */
+/***********************************************************************/
+void BINFAM::Rewind(void)
+{
+ if (Stream) // Can be NULL when making index on void table
+ rewind(Stream);
+
+ Rows = 0;
+ OldBlk = CurBlk = -1;
+} // end of Rewind
+#endif // 0
diff --git a/storage/connect/filamtxt.h b/storage/connect/filamtxt.h
new file mode 100644
index 00000000..353e06ad
--- /dev/null
+++ b/storage/connect/filamtxt.h
@@ -0,0 +1,254 @@
+/************** FilAMTxt H Declares Source Code File (.H) **************/
+/* Name: FILAMTXT.H Version 1.4 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2020 */
+/* */
+/* This file contains the file access method classes declares. */
+/***********************************************************************/
+
+#ifndef __FILAMTXT_H
+#define __FILAMTXT_H
+
+#include "block.h"
+#include "array.h"
+
+typedef class TXTFAM *PTXF;
+typedef class DOSFAM *PDOSFAM;
+typedef class BLKFAM *PBLKFAM;
+typedef class BINFAM *PBINFAM;
+typedef class DOSDEF *PDOSDEF;
+typedef class TDBDOS *PTDBDOS;
+
+/***********************************************************************/
+/* This is the base class for all file access method classes. */
+/***********************************************************************/
+class DllExport TXTFAM : public BLOCK {
+ friend class TDBDOS;
+ friend class TDBCSV;
+ friend class TDBFIX;
+ friend class TDBVCT;
+ friend class TDBJSON;
+ friend class DOSCOL;
+ friend class BINCOL;
+ friend class VCTCOL;
+ public:
+ // Constructor
+ TXTFAM(PDOSDEF tdp);
+ TXTFAM(PTXF txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) = 0;
+ virtual int GetPos(void) = 0;
+ virtual int GetNextPos(void) = 0;
+ virtual PTXF Duplicate(PGLOBAL g) = 0;
+ virtual bool GetUseTemp(void) {return false;}
+ virtual int GetDelRows(void) {return DelRows;}
+ PFBLOCK GetTo_Fb(void) {return To_Fb;}
+ int GetCurBlk(void) {return CurBlk;}
+ void SetTdbp(PTDBDOS tdbp) {Tdbp = tdbp;}
+ int GetBlock(void) {return Block;}
+ void SetBlkPos(int *bkp) {BlkPos = bkp;}
+ void SetNrec(int n) {Nrec = n;}
+ char *GetBuf(void) {return To_Buf;}
+ int GetRows(void) {return Rows;}
+ bool IsBlocked(void) {return Blocked;}
+
+ // Methods
+ virtual void Reset(void);
+ virtual int GetFileLength(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int MaxBlkSize(PGLOBAL g, int s);
+ virtual bool AllocateBuffer(PGLOBAL) {return false;}
+ virtual void ResetBuffer(PGLOBAL) {}
+ virtual int GetNerr(void) {return 0;}
+ virtual int GetRowID(void) = 0;
+ virtual bool RecordPos(PGLOBAL g) = 0;
+ virtual bool SetPos(PGLOBAL g, int recpos) = 0;
+ virtual int SkipRecord(PGLOBAL g, bool header) = 0;
+ virtual bool OpenTableFile(PGLOBAL g) = 0;
+ virtual bool DeferReading(void) {IsRead = false; return true;}
+ virtual int ReadBuffer(PGLOBAL g) = 0;
+ virtual int WriteBuffer(PGLOBAL g) = 0;
+ virtual int DeleteRecords(PGLOBAL g, int irc) = 0;
+ virtual void CloseTableFile(PGLOBAL g, bool abort) = 0;
+ virtual void Rewind(void) = 0;
+ virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+ bool AddListValue(PGLOBAL g, int type, void *val, PPARM *top);
+ int StoreValues(PGLOBAL g, bool upd);
+ int UpdateSortedRows(PGLOBAL g);
+ int DeleteSortedRows(PGLOBAL g);
+
+ protected:
+ // Members
+ PTDBDOS Tdbp; // To table class
+ PCSZ To_File; // Points to table file name
+ PFBLOCK To_Fb; // Pointer to file block
+ PPARM To_Pos; // Pointer to position list
+ PPARM To_Sos; // Pointer to start position list
+ PPARM To_Upd; // Pointer to udated line list
+ PARRAY Posar; // Pointer to position array
+ PARRAY Sosar; // Pointer to start position array
+ PARRAY Updar; // Pointer to udated lines array
+ bool Placed; // true if Recpos was externally set
+ bool IsRead; // false for deferred reading
+ bool Blocked; // true if using blocked I/O
+ char *To_Buf; // Points to I/O buffer
+ void *DelBuf; // Buffer used to move lines in Delete
+ int *BlkPos; // To array of block positions
+ int BlkLen; // Current block length
+ int Buflen; // Buffer length
+ int Dbflen; // Delete buffer length
+ int Rows; // Number of rows read so far
+ int DelRows; // Number of deleted rows
+ int Headlen; // Number of bytes in header
+ int Lrecl; // Logical Record Length
+ int Block; // Number of blocks in table
+ int Last; // Number of elements of last block
+ int Nrec; // Number of records in buffer
+ int OldBlk; // Index of last read block
+ int CurBlk; // Index of current block
+ int CurNum; // Current buffer line number
+ int ReadBlks; // Number of blocks read (selected)
+ int Rbuf; // Number of lines read in buffer
+ int Modif; // Number of modified lines in block
+ int Blksize; // Size of padded blocks
+ int Ending; // Length of line end
+ int Fpos; // Position of last read record
+ int Spos; // Start position for update/delete move
+ int Tpos; // Target Position for delete move
+ bool Padded; // true if fixed size blocks are padded
+ bool Eof; // true if an EOF (0xA) character exists
+ bool Abort; // To abort on error
+ char *CrLf; // End of line character(s)
+ }; // end of class TXTFAM
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for standard */
+/* text files with variable record format (DOS, CSV, FMT) */
+/***********************************************************************/
+class DllExport DOSFAM : public TXTFAM {
+ public:
+ // Constructor
+ DOSFAM(PDOSDEF tdp);
+ DOSFAM(PDOSFAM txfp);
+ DOSFAM(PBLKFAM tdfp, PDOSDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_DOS;}
+ virtual bool GetUseTemp(void) {return UseTemp;}
+ virtual int GetPos(void);
+ virtual int GetNextPos(void);
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) DOSFAM(this);}
+
+ // Methods
+ virtual void Reset(void);
+ virtual int GetFileLength(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int MaxBlkSize(PGLOBAL g, int s);
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual int GetRowID(void);
+ virtual bool RecordPos(PGLOBAL g);
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int SkipRecord(PGLOBAL g, bool header);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ protected:
+ virtual bool OpenTempFile(PGLOBAL g);
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b);
+ virtual int RenameTempFile(PGLOBAL g);
+ virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+
+ // Members
+ FILE *Stream; // Points to Dos file structure
+ FILE *T_Stream; // Points to temporary file structure
+ PFBLOCK To_Fbt; // Pointer to temp file block
+ bool UseTemp; // True to use a temporary file in Upd/Del
+ bool Bin; // True to force binary mode
+ }; // end of class DOSFAM
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for standard */
+/* text files with variable record format (DOS, CSV, FMT) */
+/***********************************************************************/
+class DllExport BLKFAM : public DOSFAM {
+ public:
+ // Constructor
+ BLKFAM(PDOSDEF tdp);
+ BLKFAM(PBLKFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_BLK;}
+ virtual int GetPos(void);
+ virtual int GetNextPos(void);
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) BLKFAM(this);}
+
+ // Methods
+ virtual void Reset(void);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int MaxBlkSize(PGLOBAL g, int s);
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual int GetRowID(void);
+ virtual bool RecordPos(PGLOBAL g);
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int SkipRecord(PGLOBAL g, bool header);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ protected:
+ // Members
+ char *CurLine; // Position of current line in buffer
+ char *NxtLine; // Position of Next line in buffer
+ char *OutBuf; // Buffer to write in temporary file
+ bool Closing; // True when closing on Update
+ }; // end of class BLKFAM
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for binary */
+/* files with variable record format (BJSON) */
+/***********************************************************************/
+class DllExport BINFAM : public DOSFAM {
+public:
+ // Constructor
+ BINFAM(PDOSDEF tdp) : DOSFAM(tdp) {Recsize = 0;}
+ BINFAM(PBINFAM txfp) : DOSFAM(txfp) {Recsize = txfp->Recsize;}
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_BIN;}
+//virtual int GetPos(void);
+//virtual int GetNextPos(void);
+ virtual PTXF Duplicate(PGLOBAL g) { return (PTXF)new(g) BINFAM(this); }
+
+ // Methods
+//virtual void Reset(void) {TXTFAM::Reset();}
+//virtual int GetFileLength(PGLOBAL g);
+//virtual int Cardinality(PGLOBAL g);
+ virtual int MaxBlkSize(PGLOBAL g, int s) {return s;}
+ virtual bool AllocateBuffer(PGLOBAL g);
+//virtual int GetRowID(void);
+//virtual bool RecordPos(PGLOBAL g);
+//virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int SkipRecord(PGLOBAL g, bool header) {return RC_OK;}
+//virtual bool OpenTableFile(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+//virtual int DeleteRecords(PGLOBAL g, int irc);
+//virtual void CloseTableFile(PGLOBAL g, bool abort);
+//virtual void Rewind(void);
+
+//protected:
+//virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+
+ // Members
+ size_t Recsize; // Length of last read or next written record
+}; // end of class BINFAM
+
+#endif // __FILAMTXT_H
diff --git a/storage/connect/filamvct.cpp b/storage/connect/filamvct.cpp
new file mode 100644
index 00000000..2cd80f5d
--- /dev/null
+++ b/storage/connect/filamvct.cpp
@@ -0,0 +1,4313 @@
+/*********** File AM Vct C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMVCT */
+/* ------------- */
+/* Version 2.6 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the VCT file access method classes. */
+/* Added in version 2: */
+/* - Split Vec format. */
+/* - Partial delete. */
+/* - Use of tempfile for update. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLAND__
+//#include <windows.h>
+#include <sys/stat.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#define NO_ERROR 0
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tabdos.h is header containing the TABDOS class declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "osutil.h" // Unuseful for WINDOWS
+#include "plgdbsem.h"
+#include "valblk.h"
+#include "filamfix.h"
+#include "tabdos.h"
+#include "tabvct.h"
+#include "maputil.h"
+#include "filamvct.h"
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+extern int num_read, num_there; // Statistics
+static int num_write;
+
+/***********************************************************************/
+/* Header containing block info for not split VEC tables. */
+/* Block and last values can be calculated from NumRec and Nrec. */
+/* This is better than directly storing Block and Last because it */
+/* make possible to use the same file with tables having a different */
+/* block size value (Element -> Nrec) */
+/* Note: can be in a separate file if header=1 or a true header (2) */
+/***********************************************************************/
+typedef struct _vecheader {
+//int Block; /* The number of used blocks */
+//int Last; /* The number of used records in last block */
+ int MaxRec; /* Max number of records (True vector format)*/
+ int NumRec; /* Number of valid records in the table */
+ } VECHEADER;
+
+/***********************************************************************/
+/* Char VCT column blocks are right filled with blanks (blank = true) */
+/* Conversion of block values allowed conditionally for insert only. */
+/***********************************************************************/
+PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
+ bool check = true, bool blank = true, bool un = false);
+
+/* -------------------------- Class VCTFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the VCTFAM class. */
+/***********************************************************************/
+VCTFAM::VCTFAM(PVCTDEF tdp) : FIXFAM((PDOSDEF)tdp)
+ {
+ Last = tdp->GetLast();
+ MaxBlk = (tdp->GetEstimate() > 0) ?
+ ((tdp->GetEstimate() - 1) / Nrec + 1) : 0;
+ NewBlock = NULL;
+ AddBlock = false;
+ Split = false;
+
+ if ((Header = (MaxBlk) ? tdp->Header : 0))
+ Block = Last = -1;
+
+ Bsize = Nrec;
+ CurNum = Nrec - 1;
+ Colfn = NULL;
+ Tempat = NULL;
+ Clens = NULL;
+ Deplac = NULL;
+ Isnum = NULL;
+ Ncol = 0;
+ } // end of VCTFAM standard constructor
+
+VCTFAM::VCTFAM(PVCTFAM txfp) : FIXFAM(txfp)
+ {
+ MaxBlk = txfp->MaxBlk;
+ NewBlock = NULL;
+ AddBlock = false;
+ Split = txfp->Split;
+ Header = txfp->Header;
+ Bsize = txfp->Bsize;
+ Colfn = txfp->Colfn;
+ Tempat = txfp->Tempat;
+ Clens = txfp->Clens;
+ Deplac = txfp->Deplac;
+ Isnum = txfp->Isnum;
+ Ncol = txfp->Ncol;
+ } // end of VCTFAM copy constructor
+
+/***********************************************************************/
+/* VCT GetFileLength: returns file size in number of bytes. */
+/* This function is here to be accessible by VECFAM and VMPFAM. */
+/***********************************************************************/
+int VCTFAM::GetFileLength(PGLOBAL g)
+ {
+ if (Split) {
+ // Get the total file length
+ char filename[_MAX_PATH];
+ PCSZ savfile = To_File;
+ int i, len = 0;
+
+ // Initialize the array of file structures
+ if (!Colfn) {
+ // Prepare the column file name pattern and set Ncol
+ Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ Ncol = ((PVCTDEF)Tdbp->GetDef())->MakeFnPattern(Colfn);
+ } // endif Colfn
+
+ To_File = filename;
+
+ for (i = 0; i < Ncol; i++) {
+ sprintf(filename, Colfn, i+1);
+ len += TXTFAM::GetFileLength(g);
+ } // endfor i
+
+ To_File = savfile;
+ return len;
+ } else
+ return TXTFAM::GetFileLength(g);
+
+ } // end of GetFileLength
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void VCTFAM::Reset(void)
+ {
+ FIXFAM::Reset();
+ NewBlock = NULL;
+ AddBlock = false;
+ CurNum = Nrec - 1;
+ } // end of Reset
+
+/***********************************************************************/
+/* Get the Headlen, Block and Last info from the file header. */
+/***********************************************************************/
+int VCTFAM::GetBlockInfo(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int h, k, n;
+ VECHEADER vh;
+
+ if (Header < 1 || Header > 3 || !MaxBlk) {
+ sprintf(g->Message, "Invalid header value %d", Header);
+ return -1;
+ } else
+ n = (Header == 1) ? (int)sizeof(VECHEADER) : 0;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (Header == 2)
+ strcat(PlugRemoveType(filename, filename), ".blk");
+
+ if ((h = global_open(g, MSGID_CANNOT_OPEN, filename, O_RDONLY)) == -1
+ || !_filelength(h)) {
+ // Consider this is a void table
+ Last = Nrec;
+ Block = 0;
+
+ if (h != -1)
+ close(h);
+
+ return n;
+ } else if (Header == 3)
+ k = lseek(h, -(int)sizeof(VECHEADER), SEEK_END);
+
+ if ((k = read(h, &vh, sizeof(vh))) != sizeof(vh)) {
+ sprintf(g->Message, "Error reading header file %s", filename);
+ n = -1;
+ } else if (MaxBlk * Nrec != vh.MaxRec) {
+ sprintf(g->Message, "MaxRec=%d doesn't match MaxBlk=%d Nrec=%d",
+ vh.MaxRec, MaxBlk, Nrec);
+ n = -1;
+ } else {
+ Block = (vh.NumRec > 0) ? (vh.NumRec + Nrec - 1) / Nrec : 0;
+ Last = (vh.NumRec + Nrec - 1) % Nrec + 1;
+ } // endif s
+
+ close(h);
+ return n;
+ } // end of GetBlockInfo
+
+/***********************************************************************/
+/* Get the Headlen, Block and Last info from the file header. */
+/***********************************************************************/
+bool VCTFAM::SetBlockInfo(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool rc = false;
+ size_t n;
+ VECHEADER vh;
+ FILE *s;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (Header != 2) {
+ if (Stream) {
+ s = Stream;
+
+ if (Header == 1)
+ /*k =*/ fseek(s, 0, SEEK_SET);
+
+ } else
+ s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "r+b");
+
+ } else { // Header == 2
+ strcat(PlugRemoveType(filename, filename), ".blk");
+ s= global_fopen(g, MSGID_CANNOT_OPEN, filename, "wb");
+ } // endif Header
+
+ if (!s) {
+ sprintf(g->Message, "Error opening header file %s", filename);
+ return true;
+ } else if (Header == 3)
+ /*k =*/ fseek(s, -(int)sizeof(VECHEADER), SEEK_END);
+
+ vh.MaxRec = MaxBlk * Bsize;
+ vh.NumRec = (Block - 1) * Nrec + Last;
+
+ if ((n = fwrite(&vh, sizeof(vh), 1, s)) != 1) {
+ sprintf(g->Message, "Error writing header file %s", filename);
+ rc = true;
+ } // endif fread
+
+ if (Header == 2 || !Stream)
+ fclose(s);
+
+ return rc;
+ } // end of SetBlockInfo
+
+/***********************************************************************/
+/* Use BlockTest to reduce the table estimated size. */
+/***********************************************************************/
+int VCTFAM::MaxBlkSize(PGLOBAL g, int)
+ {
+ int rc = RC_OK, savcur = CurBlk;
+ int size;
+
+ // Roughly estimate the table size as the sum of blocks
+ // that can contain good rows
+ for (size = 0, CurBlk = 0; CurBlk < Block; CurBlk++)
+ if ((rc = Tdbp->TestBlock(g)) == RC_OK)
+ size += (CurBlk == Block - 1) ? Last : Nrec;
+ else if (rc == RC_EF)
+ break;
+
+ CurBlk = savcur;
+ return size;
+ } // end of MaxBlkSize
+
+/***********************************************************************/
+/* VCT Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int VCTFAM::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return 1;
+
+ if (Block < 0)
+ {
+ if (Split) {
+ // Separate column files and no pre setting of Block and Last
+ // This allows to see a table modified externally, but Block
+ // and Last must be set from the file cardinality.
+ // Only happens when called by sub classes.
+ char filename[_MAX_PATH];
+ PCSZ savfn = To_File;
+ int len, clen, card = -1;
+ PCOLDEF cdp = Tdbp->GetDef()->GetCols();
+
+ if (!Colfn) {
+ // Prepare the column file name pattern
+ Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
+ } // endif Colfn
+
+ // Use the first column file to calculate the cardinality
+ clen = cdp->GetClen();
+ sprintf(filename, Colfn, 1);
+ To_File = filename;
+ len = TXTFAM::GetFileLength(g);
+ To_File = savfn;
+
+ if (len >= 0) {
+ if (!(len % clen))
+ card = len / clen; // Fixed length file
+ else
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), To_File, len, clen);
+
+ if (trace(1))
+ htrc(" Computed max_K=%d Filen=%d Clen=%d\n", card, len, clen);
+
+ } else
+ card = 0;
+
+ // Set number of blocks for later use
+ Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0;
+ Last = (card + Nrec - 1) % Nrec + 1;
+ return card;
+ } else {
+ // Vector table having Block and Last info in a Header (file)
+ if ((Headlen = GetBlockInfo(g)) < 0)
+ return -1; // Error
+
+ } // endif split
+ }
+ return (Block) ? ((Block - 1) * Nrec + Last) : 0;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int VCTFAM::GetRowID(void)
+ {
+ return 1 + ((CurBlk < Block) ? CurNum + Nrec * CurBlk
+ : (Block - 1) * Nrec + Last);
+ } // end of GetRowID
+
+/***********************************************************************/
+/* VCT Create an empty file for Vector formatted tables. */
+/***********************************************************************/
+bool VCTFAM::MakeEmptyFile(PGLOBAL g, PCSZ fn)
+ {
+ // Vector formatted file: this will create an empty file of the
+ // required length if it does not exists yet.
+ char filename[_MAX_PATH], c = 0;
+ int h, n;
+
+ PlugSetPath(filename, fn, Tdbp->GetPath());
+#if defined(_WIN32)
+ h= global_open(g, MSGID_OPEN_EMPTY_FILE, filename, _O_CREAT | _O_WRONLY, S_IREAD | S_IWRITE);
+#else // !_WIN32
+ h= global_open(g, MSGID_OPEN_EMPTY_FILE, filename, O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
+#endif // !_WIN32
+
+ if (h == -1)
+ return true;
+
+ n = (Header == 1 || Header == 3) ? sizeof(VECHEADER) : 0;
+
+ if (lseek(h, n + MaxBlk * Nrec * Lrecl - 1, SEEK_SET) < 0)
+ goto err;
+
+ // This actually fills the empty file
+ if (write(h, &c, 1) < 0)
+ goto err;
+
+ close(h);
+ return false;
+
+ err:
+ sprintf(g->Message, MSG(MAKE_EMPTY_FILE), To_File, strerror(errno));
+ close(h);
+ return true;
+ } // end of MakeEmptyFile
+
+/***********************************************************************/
+/* VCT Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool VCTFAM::OpenTableFile(PGLOBAL g)
+ {
+ char opmode[4], filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ /*********************************************************************/
+ /* Update block info if necessary. */
+ /*********************************************************************/
+ if (Block < 0)
+ if ((Headlen = GetBlockInfo(g)) < 0)
+ return true;
+
+ /*********************************************************************/
+ /* Open according to input/output mode required. */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "rb");
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ // This will delete the whole file
+ strcpy(opmode, "wb");
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ /* fall through */
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ strcpy(opmode, (UseTemp) ? "rb" : "r+b");
+ break;
+ case MODE_INSERT:
+ if (MaxBlk) {
+ if (!Block)
+ if (MakeEmptyFile(g, To_File))
+ return true;
+
+ strcpy(opmode, "r+b"); // Required to update empty blocks
+ } else if (!Block || Last == Nrec)
+ strcpy(opmode, "ab");
+ else
+ strcpy(opmode, "r+b"); // Required to update the last block
+
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ /*********************************************************************/
+ /* Use conventionnal input/output functions. */
+ /*********************************************************************/
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!(Stream = PlugOpenFile(g, filename, opmode))) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return (mode == MODE_READ && errno == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif Stream
+
+ if (trace(1))
+ htrc("File %s is open in mode %s\n", filename, opmode);
+
+ To_Fb = dbuserp->Openlist; // Keep track of File block
+
+ if (!strcmp(opmode, "wb"))
+ // This will stop the process by
+ // causing GetProgMax to return 0.
+ return ResetTableSize(g, 0, Nrec);
+
+ num_read = num_there = num_write = 0;
+
+ // Allocate the table and column block buffer
+ return AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/***********************************************************************/
+bool VCTFAM::AllocateBuffer(PGLOBAL g)
+ {
+ MODE mode = Tdbp->GetMode();
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+ PCOLDEF cdp;
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ if (mode == MODE_INSERT) {
+ bool chk = PlgGetUser(g)->Check & CHK_TYPE;
+
+ NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
+
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ memset(NewBlock + Nrec * cdp->GetPoff(),
+ (IsTypeNum(cdp->GetType()) ? 0 : ' '),
+ Nrec * cdp->GetClen());
+
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->Blk = AllocValBlock(g, NewBlock + Nrec * cp->Deplac,
+ cp->Buf_Type, Nrec, cp->Format.Length,
+ cp->Format.Prec, chk, true,
+ cp->IsUnsigned());
+
+ return InitInsert(g); // Initialize inserting
+ } else {
+ if (UseTemp || mode == MODE_DELETE) {
+ // Allocate all that is needed to move lines
+ int i = 0, n = (MaxBlk) ? MaxBlk : 1;
+
+ if (!Ncol)
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ Ncol++;
+
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+ Deplac = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+ Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
+
+ for (cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext()) {
+ Clens[i] = cdp->GetClen();
+ Deplac[i] = Headlen + cdp->GetPoff() * n * Nrec;
+ Isnum[i] = IsTypeNum(cdp->GetType());
+ Buflen = MY_MAX(Buflen, cdp->GetClen());
+ } // endfor cdp
+
+ if (!UseTemp || MaxBlk) {
+ Buflen *= Nrec;
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+ } else
+ NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
+
+ } // endif mode
+
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) // Not a pseudo column
+ cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec,
+ true, true, cp->IsUnsigned());
+
+ } //endif mode
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Do initial action when inserting. */
+/***********************************************************************/
+bool VCTFAM::InitInsert(PGLOBAL g)
+{
+ bool rc = false;
+
+ // We come here in MODE_INSERT only
+ if (Last == Nrec) {
+ CurBlk = Block;
+ CurNum = 0;
+ AddBlock = !MaxBlk;
+ } else {
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ // The starting point must be at the end of file as for append.
+ CurBlk = Block - 1;
+ CurNum = Last;
+
+ try {
+ // Last block must be updated by new values
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->ReadBlock(g);
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ rc = true;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc = true;
+ } // end catch
+
+ } // endif Last
+
+ if (!rc)
+ // We are not currently using a temporary file for Insert
+ T_Stream = Stream;
+
+ return rc;
+ } // end of InitInsert
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a VCT file. */
+/***********************************************************************/
+int VCTFAM::ReadBuffer(PGLOBAL g)
+ {
+ int rc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ if (Placed)
+ Placed = false;
+ else if ((++CurNum) >= ((CurBlk < Block - 1) ? Nrec : Last)) {
+ /*******************************************************************/
+ /* New block. */
+ /*******************************************************************/
+ CurNum = 0;
+
+ next:
+ if (++CurBlk == Block)
+ return RC_EF; // End of file
+
+ /*******************************************************************/
+ /* Before reading a new block, check whether block optimizing */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ goto next;
+ } // endswitch rc
+
+ num_there++;
+ } // endif CurNum
+
+ if (OldBlk != CurBlk) {
+ if (mode == MODE_UPDATE) {
+ /*****************************************************************/
+ /* Flush the eventually modified column buffers in old blocks */
+ /* and read the blocks to modify attached to Set columns. */
+ /*****************************************************************/
+ if (MoveLines(g)) // For VECFAM
+ return RC_FX;
+
+ for (PVCTCOL colp = (PVCTCOL)Tdbp->GetSetCols();
+ colp; colp = (PVCTCOL)colp->Next) {
+ colp->WriteBlock(g);
+ colp->ReadBlock(g);
+ } // endfor colp
+
+ } // endif mode
+
+ OldBlk = CurBlk; // Last block actually read
+ } // endif oldblk
+
+ if (trace(1))
+ htrc(" Read: CurNum=%d CurBlk=%d rc=%d\n", CurNum, CurBlk, RC_OK);
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Data Base write routine for VCT access method. */
+/***********************************************************************/
+int VCTFAM::WriteBuffer(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("VCT WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
+ Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
+
+ if (Tdbp->GetMode() == MODE_UPDATE) {
+ // Mode Update is done in ReadDB, we just initialize it here
+ if (!T_Stream) {
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ // Most of the time, not all table columns are updated.
+ // This why we must completely pre-fill the temporary file.
+ Fpos = (MaxBlk) ? (Block - 1) * Nrec + Last
+ : Block * Nrec; // To write last lock
+
+ if (MoveIntermediateLines(g))
+ return RC_FX;
+
+ } else
+ T_Stream = Stream;
+
+ } // endif T_Stream
+
+ } else {
+ // Mode Insert
+ if (MaxBlk && CurBlk == MaxBlk) {
+ strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
+ return RC_EF; // Too many lines for vector formatted table
+ } // endif MaxBlk
+
+ if (Closing || ++CurNum == Nrec) {
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ if (!AddBlock) {
+ // Write back the updated last block values
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->WriteBlock(g);
+
+ if (!Closing && !MaxBlk) {
+ // For VCT tables, future blocks must be added
+ char filename[_MAX_PATH];
+
+ // Close the file and reopen it in mode Insert
+ fclose(Stream);
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!(Stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "ab"))) {
+ Closing = true; // Tell CloseDB of error
+ return RC_FX;
+ } // endif Stream
+
+ AddBlock = true;
+ } // endif Closing
+
+ } else {
+ // Here we must add a new block to the file
+ if (Closing)
+ // Reset the overwritten columns for last block extra records
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ memset(NewBlock + Nrec * cp->Deplac + Last * cp->Clen,
+ (cp->Buf_Type == TYPE_STRING) ? ' ' : '\0',
+ (Nrec - Last) * cp->Clen);
+
+ if ((size_t)Nrec !=
+ fwrite(NewBlock, (size_t)Lrecl, (size_t)Nrec, Stream)) {
+ sprintf(g->Message, MSG(WRITE_STRERROR), To_File, strerror(errno));
+ return RC_FX;
+ } // endif
+
+ } // endif AddBlock
+
+ if (!Closing) {
+ CurBlk++;
+ CurNum = 0;
+ } // endif Closing
+
+ } // endif Closing || CurNum
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for VCT access method. */
+/* Note: lines are moved directly in the files (ooops...) */
+/* Using temp file depends on the Check setting, false by default. */
+/***********************************************************************/
+int VCTFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool eof = false;
+
+ if (trace(1))
+ htrc("VCT DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = (Block - 1) * Nrec + Last;
+
+ if (trace(1))
+ htrc("Fpos placed at file end=%d\n", Fpos);
+
+ eof = UseTemp && !MaxBlk;
+ } else // Fpos is the Deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* First line to delete. Move of eventual preceding lines is */
+ /* not required here, just the setting of future Spos and Tpos. */
+ /*****************************************************************/
+ T_Stream = Stream;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &eof))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+ /*******************************************************************/
+ /* Reposition the file pointer and set Spos. */
+ /*******************************************************************/
+#ifdef _DEBUG
+ assert(Spos == Fpos);
+#endif
+ Spos++; // New start position is on next line
+
+ if (trace(1))
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /* Update the Block and Last values. */
+ /*******************************************************************/
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ if (!UseTemp) { // The UseTemp case is treated in CloseTableFile
+ if (!MaxBlk) {
+ /***************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the file and reopen it with the */
+ /* open function (_fopen for MS ??) this is still to be */
+ /* checked for compatibility with Text files and other OS's. */
+ /***************************************************************/
+ char filename[_MAX_PATH];
+ int h;
+
+ /*rc =*/ CleanUnusedSpace(g); // Clean last block
+ /*rc =*/ PlugCloseFile(g, To_Fb);
+ Stream = NULL; // For SetBlockInfo
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /***************************************************************/
+ /* Remove extra blocks. */
+ /***************************************************************/
+#if defined(UNIX)
+ if (ftruncate(h, (off_t)(Headlen + Block * Blksize))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (chsize(h, Headlen + Block * Blksize)) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+ if (trace(1))
+ htrc("done, h=%d irc=%d\n", h, irc);
+
+ } else
+ // Clean the unused space in the file, this is required when
+ // inserting again with a partial column list.
+ if (CleanUnusedSpace(g))
+ return RC_FX;
+
+ if (ResetTableSize(g, Block, Last))
+ return RC_FX;
+
+ } // endif UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open a temporary file used while updating or deleting. */
+/***********************************************************************/
+bool VCTFAM::OpenTempFile(PGLOBAL g)
+ {
+ PCSZ opmode;
+ char tempname[_MAX_PATH];
+ bool rc = false;
+
+ /*********************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*********************************************************************/
+ PlugSetPath(tempname, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(tempname, tempname), ".t");
+
+ if (MaxBlk) {
+ if (MakeEmptyFile(g, tempname))
+ return true;
+
+ opmode = "r+b";
+ } else
+ opmode = "wb";
+
+ if (!(T_Stream = PlugOpenFile(g, tempname, opmode))) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ rc = true;
+ } else
+ To_Fbt = PlgGetUser(g)->Openlist;
+
+ return rc;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool VCTFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int i, dep, off;
+ int n;
+ bool eof = (b) ? *b : false;
+ size_t req, len;
+
+ for (n = Fpos - Spos; n > 0 || eof; n -= req) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!MaxBlk)
+ req = (size_t)MY_MIN(n, Nrec - MY_MAX(Spos % Nrec, Tpos % Nrec));
+ else
+ req = (size_t)MY_MIN(n, Nrec);
+
+ if (req) for (i = 0; i < Ncol; i++) {
+ if (MaxBlk) {
+ dep = Deplac[i];
+ off = Spos * Clens[i];
+ } else {
+ if (UseTemp)
+ To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
+
+ dep = Deplac[i] + (Spos / Nrec) * Blksize;
+ off = (Spos % Nrec) * Clens[i];
+ } // endif MaxBlk
+
+ if (fseek(Stream, dep + off, SEEK_SET)) {
+ sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ len = fread(To_Buf, Clens[i], req, Stream);
+
+ if (trace(1))
+ htrc("after read req=%d len=%d\n", req, len);
+
+ if (len != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), (int) req, (int) len);
+ return true;
+ } // endif len
+
+ if (!UseTemp || MaxBlk) {
+ if (MaxBlk) {
+ dep = Deplac[i];
+ off = Tpos * Clens[i];
+ } else {
+ dep = Deplac[i] + (Tpos / Nrec) * Blksize;
+ off = (Tpos % Nrec) * Clens[i];
+ } // endif MaxBlk
+
+ if (fseek(T_Stream, dep + off, SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(To_Buf, Clens[i], req, T_Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ } // endif UseTemp
+
+ if (trace(1))
+ htrc("after write pos=%d\n", ftell(Stream));
+
+ } // endfor i
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (UseTemp && !MaxBlk && (Tpos % Nrec == 0 || (eof && Spos == Fpos))) {
+ // Write the full or last block to the temporary file
+ if ((dep = Nrec - (Tpos % Nrec)) < Nrec)
+ // Clean the last block in case of future insert,
+ // must be done here because T_Stream was open in write only.
+ for (i = 0; i < Ncol; i++) {
+ To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
+ memset(To_Buf, (Isnum[i]) ? 0 : ' ', dep * Clens[i]);
+ } // endfor i
+
+ // Write a new block in the temporary file
+ len = (size_t)Blksize;
+
+ if (fwrite(NewBlock, 1, len, T_Stream) != len) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ if (Spos == Fpos)
+ eof = false;
+
+ } // endif UseTemp
+
+ if (trace(1))
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediateLines
+
+/***********************************************************************/
+/* Clean deleted space in a VCT or Vec table file. */
+/***********************************************************************/
+bool VCTFAM::CleanUnusedSpace(PGLOBAL g)
+ {
+ int i, dep;
+ int n;
+ size_t req, len;
+
+ if (!MaxBlk) {
+ /*******************************************************************/
+ /* Clean last block of the VCT table file. */
+ /*******************************************************************/
+ assert(!UseTemp);
+
+ if (!(n = Nrec - Last))
+ return false;
+
+ dep = (Block - 1) * Blksize;
+ req = (size_t)n;
+
+ for (i = 0; i < Ncol; i++) {
+ memset(To_Buf, (Isnum[i]) ? 0 : ' ', n * Clens[i]);
+
+ if (fseek(Stream, dep + Deplac[i] + Last * Clens[i], SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(To_Buf, Clens[i], req, Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ } // endfor i
+
+ } else for (n = Fpos - Tpos; n > 0; n -= req) {
+ /*******************************************************************/
+ /* Fill VEC file remaining lines with 0's. */
+ /* Note: this seems to work even column blocks have been made */
+ /* with Blanks = true. Perhaps should it be set to false for VEC. */
+ /*******************************************************************/
+ req = (size_t)MY_MIN(n, Nrec);
+ memset(To_Buf, 0, Buflen);
+
+ for (i = 0; i < Ncol; i++) {
+ if (fseek(T_Stream, Deplac[i] + Tpos * Clens[i], SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(To_Buf, Clens[i], req, T_Stream)) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ } // endfor i
+
+ Tpos += (int)req;
+ } // endfor n
+
+ return false;
+ } // end of CleanUnusedSpace
+
+/***********************************************************************/
+/* Data Base close routine for VCT access method. */
+/***********************************************************************/
+void VCTFAM::CloseTableFile(PGLOBAL g, bool abort)
+ {
+ int rc = 0, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ Abort = abort;
+
+ if (mode == MODE_INSERT) {
+ if (Closing)
+ wrc = RC_FX; // Last write was in error
+ else
+ if (CurNum) {
+ // Some more inserted lines remain to be written
+ Last = CurNum;
+ Block = CurBlk + 1;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else {
+ Last = Nrec;
+ Block = CurBlk;
+ wrc = RC_OK;
+ } // endif CurNum
+
+ if (wrc != RC_FX) {
+ rc = ResetTableSize(g, Block, Last);
+ } else if (AddBlock) {
+ // Last block was not written
+ rc = ResetTableSize(g, CurBlk, Nrec);
+ throw 44;
+ } // endif
+
+ } else if (mode == MODE_UPDATE) {
+ // Write back to file any pending modifications
+ for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols;
+ colp; colp = (PVCTCOL)colp->Next)
+ colp->WriteBlock(g);
+
+ if (UseTemp && T_Stream) {
+ rc = RenameTempFile(g);
+
+ if (Header) {
+ // Header must be set because it was not set in temp file
+ Stream = T_Stream = NULL; // For SetBlockInfo
+ rc = SetBlockInfo(g);
+ } // endif Header
+
+ } // endif UseTemp
+
+ } else if (mode == MODE_DELETE && UseTemp && T_Stream) {
+ if (MaxBlk)
+ rc = CleanUnusedSpace(g);
+
+ if ((rc = RenameTempFile(g)) != RC_FX) {
+ Stream = T_Stream = NULL; // For SetBlockInfo
+ rc = ResetTableSize(g, Block, Last);
+ } // endif rc
+
+ } // endif's mode
+
+ if (!(UseTemp && T_Stream))
+ rc = PlugCloseFile(g, To_Fb);
+
+ if (trace(1))
+ htrc("VCT CloseTableFile: closing %s wrc=%d rc=%d\n",
+ To_File, wrc, rc);
+
+ Stream = NULL;
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* Data Base close routine for VCT access method. */
+/***********************************************************************/
+bool VCTFAM::ResetTableSize(PGLOBAL g, int block, int last)
+ {
+ bool rc = false;
+
+ // Set Block and Last values for TDBVCT::MakeBlockValues
+ Block = block;
+ Last = last;
+
+ if (!Split) {
+ if (!Header) {
+ // Update catalog values for Block and Last
+ PVCTDEF defp = (PVCTDEF)Tdbp->GetDef();
+
+ defp->SetBlock(Block);
+ defp->SetLast(Last);
+
+ if (!defp->SetIntCatInfo("Blocks", Block) ||
+ !defp->SetIntCatInfo("Last", Last)) {
+ sprintf(g->Message, MSG(UPDATE_ERROR), "Header");
+ rc = true;
+ } // endif
+
+ } else
+ rc = SetBlockInfo(g);
+
+ } // endif Split
+
+ Tdbp->ResetSize();
+ return rc;
+ } // end of ResetTableSize
+
+/***********************************************************************/
+/* Rewind routine for VCT access method. */
+/***********************************************************************/
+void VCTFAM::Rewind(void)
+ {
+ // In mode update we need to read Set Column blocks
+ if (Tdbp->GetMode() == MODE_UPDATE)
+ OldBlk = -1;
+
+ // Initialize so block optimization is called for 1st block
+ CurBlk = -1;
+ CurNum = Nrec - 1;
+//rewind(Stream); will be placed by fseek
+ } // end of Rewind
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+bool VCTFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int len;
+ size_t n;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to read. */
+ /*********************************************************************/
+ if (MaxBlk) // True vector format
+ len = Headlen + Nrec * (colp->Deplac * MaxBlk + colp->Clen * CurBlk);
+ else // Blocked vector format
+ len = Nrec * (colp->Deplac + Lrecl * CurBlk);
+
+ if (trace(1))
+ htrc("len=%d Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d maxblk=%d\n",
+ len, Nrec, colp->Deplac, Lrecl, CurBlk, MaxBlk);
+
+ if (fseek(Stream, len, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ n = fread(colp->Blk->GetValPointer(), (size_t)colp->Clen,
+ (size_t)Nrec, Stream);
+
+ if (n != (size_t)Nrec) {
+ if (errno == NO_ERROR)
+ sprintf(g->Message, MSG(BAD_READ_NUMBER), (int) n, To_File);
+ else
+ sprintf(g->Message, MSG(READ_ERROR),
+ To_File, strerror(errno));
+
+ if (trace(1))
+ htrc(" Read error: %s\n", g->Message);
+
+ return true;
+ } // endif
+
+ if (trace(1))
+ num_read++;
+
+ return false;
+ } // end of ReadBlock
+
+/***********************************************************************/
+/* WriteBlock: Write back current column values for one block. */
+/* Note: the test of Status is meant to prevent physical writing of */
+/* the block during the checking loop in mode Update. It is set to */
+/* BUF_EMPTY when reopening the table between the two loops. */
+/***********************************************************************/
+bool VCTFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int len;
+ size_t n;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to write. */
+ /*********************************************************************/
+ if (MaxBlk) // File has Vector format
+ len = Headlen
+ + Nrec * (colp->Deplac * MaxBlk + colp->Clen * colp->ColBlk);
+ else // Old VCT format
+ len = Nrec * (colp->Deplac + Lrecl * colp->ColBlk);
+
+ if (trace(1))
+ htrc("modif=%d len=%d Nrec=%d Deplac=%d Lrecl=%d colblk=%d\n",
+ Modif, len, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
+
+ if (fseek(T_Stream, len, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ // Here Nrec was changed to CurNum in mode Insert,
+ // this is the true number of records to write,
+ // this also avoid writing garbage in the file for true vector tables.
+ n = (Tdbp->GetMode() == MODE_INSERT) ? CurNum : Nrec;
+
+ if (n != fwrite(colp->Blk->GetValPointer(),
+ (size_t)colp->Clen, n, T_Stream)) {
+ sprintf(g->Message, MSG(WRITE_STRERROR),
+ (UseTemp) ? To_Fbt->Fname : To_File, strerror(errno));
+
+ if (trace(1))
+ htrc("Write error: %s\n", strerror(errno));
+
+ return true;
+ } // endif
+
+#if defined(UNIX)
+ fflush(T_Stream); //NGC
+#endif
+
+#ifdef _DEBUG
+ num_write++;
+#endif
+
+ return false;
+ } // end of WriteBlock
+
+/* -------------------------- Class VCMFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the VCMFAM class. */
+/***********************************************************************/
+VCMFAM::VCMFAM(PVCTDEF tdp) : VCTFAM((PVCTDEF)tdp)
+ {
+ Memory = NULL;
+ Memcol = NULL;
+ } // end of VCMFAM standard constructor
+
+VCMFAM::VCMFAM(PVCMFAM txfp) : VCTFAM(txfp)
+ {
+ Memory = txfp->Memory;
+ Memcol = txfp->Memcol;
+ } // end of VCMFAM copy constructor
+
+/***********************************************************************/
+/* Mapped VCT Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool VCMFAM::OpenTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ size_t len;
+ MODE mode = Tdbp->GetMode();
+ PFBLOCK fp = NULL;
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ /*********************************************************************/
+ /* Update block info if necessary. */
+ /*********************************************************************/
+ if (Block < 0)
+ if ((Headlen = GetBlockInfo(g)) < 0)
+ return true;
+
+ /*********************************************************************/
+ /* We used the file name relative to recorded datapath. */
+ /*********************************************************************/
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ /*********************************************************************/
+ /* The whole file will be mapped so we can use it as if it were */
+ /* entirely read into virtual memory. */
+ /* Firstly we check whether this file have been already mapped. */
+ /*********************************************************************/
+ if (mode == MODE_READ) {
+ for (fp = dbuserp->Openlist; fp; fp = fp->Next)
+ if (fp->Type == TYPE_FB_MAP && !stricmp(fp->Fname, filename)
+ && fp->Count && fp->Mode == mode)
+ break;
+
+ if (trace(1))
+ htrc("Mapping VCM file, fp=%p cnt=%d\n", fp, fp->Count);
+
+ } else
+ fp = NULL;
+
+ if (fp) {
+ /*******************************************************************/
+ /* File already mapped. Just increment use count and get pointer. */
+ /*******************************************************************/
+ fp->Count++;
+ Memory = fp->Memory;
+ len = fp->Length;
+ } else {
+ /*******************************************************************/
+ /* If required, delete the whole file if no filtering is implied. */
+ /*******************************************************************/
+ bool del;
+ HANDLE hFile;
+ MEMMAP mm;
+ MODE mapmode = mode;
+
+ if (mode == MODE_INSERT) {
+ if (MaxBlk) {
+ if (!Block)
+ if (MakeEmptyFile(g, To_File))
+ return true;
+
+ // Inserting will be like updating the file
+ mapmode = MODE_UPDATE;
+ } else {
+ strcpy(g->Message, "MAP Insert is for VEC Estimate tables only");
+ return true;
+ } // endif MaxBlk
+
+ } // endif mode
+
+ del = mode == MODE_DELETE && !Tdbp->GetNext();
+
+ if (del) {
+ DelRows = Cardinality(g);
+
+ // This will stop the process by causing GetProgMax to return 0.
+// ResetTableSize(g, 0, Nrec); must be done later
+ } // endif del
+
+ /*******************************************************************/
+ /* Create the mapping file object. */
+ /*******************************************************************/
+ hFile = CreateFileMap(g, filename, &mm, mapmode, del);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+
+ if (!(*g->Message))
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "map", (int) rc, filename);
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return (mode == MODE_READ && rc == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif hFile
+
+ /*******************************************************************/
+ /* Get the file size. */
+ /*******************************************************************/
+ len = (size_t)mm.lenL;
+
+ if (mm.lenH)
+ len += ((size_t)mm.lenH * 0x000000001LL);
+
+ Memory = (char *)mm.memory;
+
+ if (!len) { // Empty or deleted file
+ CloseFileHandle(hFile);
+ bool rc = ResetTableSize(g, 0, Nrec);
+ return (mapmode == MODE_UPDATE) ? true : rc;
+ } // endif len
+
+ if (!Memory) {
+ CloseFileHandle(hFile);
+ sprintf(g->Message, MSG(MAP_VIEW_ERROR),
+ filename, GetLastError());
+ return true;
+ } // endif Memory
+
+ if (mode != MODE_DELETE) {
+ CloseFileHandle(hFile); // Not used anymore
+ hFile = INVALID_HANDLE_VALUE; // For Fblock
+ } // endif Mode
+
+ /*******************************************************************/
+ /* Link a Fblock. This make possible to reuse already opened maps */
+ /* and also to automatically unmap them in case of error g->jump. */
+ /* Note: block can already exist for previously closed file. */
+ /*******************************************************************/
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ fp->Type = TYPE_FB_MAP;
+ fp->Fname = PlugDup(g, filename);
+ fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = fp;
+ fp->Count = 1;
+ fp->Length = len;
+ fp->Memory = Memory;
+ fp->Mode = mode;
+ fp->File = NULL;
+ fp->Handle = hFile; // Used for Delete
+ } // endif fp
+
+ To_Fb = fp; // Useful when closing
+
+ if (trace(1))
+ htrc("fp=%p count=%d MapView=%p len=%d Top=%p\n",
+ fp, fp->Count, Memory, len);
+
+ return AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/* Give a dummy value (1) to prevent allocating the value block. */
+/* It will be set pointing into the memory map of the file. */
+/* Note: Memcol must be set for all columns because it can be used */
+/* for set columns in Update. Clens values are used only in Delete. */
+/***********************************************************************/
+bool VCMFAM::AllocateBuffer(PGLOBAL g)
+ {
+ int m, i = 0;
+ bool b = Tdbp->GetMode() == MODE_DELETE;
+ PVCTCOL cp;
+ PCOLDEF cdp;
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ // Calculate the number of columns
+ if (!Ncol)
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ Ncol++;
+
+ // To store the start position of each column
+ Memcol = (char**)PlugSubAlloc(g, NULL, Ncol * sizeof(char*));
+ m = (MaxBlk) ? MaxBlk : 1;
+
+ // We will need all column sizes and type for Delete
+ if (b) {
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+ Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
+ } // endif b
+
+ for (cdp = defp->GetCols(); i < Ncol; i++, cdp = cdp->GetNext()) {
+ if (b) {
+ Clens[i] = cdp->GetClen();
+ Isnum[i] = IsTypeNum(cdp->GetType());
+ } // endif b
+
+ Memcol[i] = Memory + Headlen + cdp->GetPoff() * m * Nrec;
+ } // endfor cdp
+
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) { // Not a pseudo column
+ cp->Blk = AllocValBlock(g, (void*)1, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec,
+ true, true, cp->IsUnsigned());
+ cp->AddStatus(BUF_MAPPED);
+ } // endif IsSpecial
+
+ if (Tdbp->GetMode() == MODE_INSERT)
+ return InitInsert(g);
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Do initial action when inserting. */
+/***********************************************************************/
+bool VCMFAM::InitInsert(PGLOBAL g)
+{
+ bool rc = false;
+ volatile PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ // We come here in MODE_INSERT only
+ if (Last == Nrec) {
+ CurBlk = Block;
+ CurNum = 0;
+ AddBlock = !MaxBlk;
+ } else {
+ // The starting point must be at the end of file as for append.
+ CurBlk = Block - 1;
+ CurNum = Last;
+ } // endif Last
+
+ try {
+ // Initialize the column block pointer
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->ReadBlock(g);
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ rc = true;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc = true;
+ } // end catch
+
+ return rc;
+} // end of InitInsert
+
+/***********************************************************************/
+/* Data Base write routine for VMP access method. */
+/***********************************************************************/
+int VCMFAM::WriteBuffer(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("VCM WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
+ Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
+
+ // Mode Update being done in ReadDB we process here Insert mode only.
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ if (CurBlk == MaxBlk) {
+ strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
+ return RC_EF; // Too many lines for vector formatted table
+ } // endif MaxBlk
+
+ if (Closing || ++CurNum == Nrec) {
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ // Write back the updated last block values
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->WriteBlock(g);
+
+ if (!Closing) {
+ CurBlk++;
+ CurNum = 0;
+
+ // Re-initialize the column block pointer
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ cp->ReadBlock(g);
+
+ } // endif Closing
+
+ } // endif Closing || CurNum
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for VMP access method. */
+/* Lines between deleted lines are moved in the mapfile view. */
+/***********************************************************************/
+int VCMFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ if (trace(1))
+ htrc("VCM DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n",
+ irc, To_Buf, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the top of map position. */
+ /*******************************************************************/
+ Fpos = (Block - 1) * Nrec + Last;
+
+ if (trace(1))
+ htrc("Fpos placed at file top=%p\n", Fpos);
+
+ } else // Fpos is the Deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete. Move of eventual preceding lines is */
+ /* not required here, just setting of future Spos and Tpos. */
+ /*******************************************************************/
+ Tpos = Spos = Fpos;
+ } else
+ (void)MoveIntermediateLines(g);
+
+ if (irc == RC_OK) {
+ Spos = Fpos + 1; // New start position
+
+ if (trace(1))
+ htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ int i, m, n;
+
+ /*******************************************************************/
+ /* Reset the Block and Last values for TDBVCT::MakeBlockValues. */
+ /*******************************************************************/
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ if (!MaxBlk) {
+ PFBLOCK fp = To_Fb;
+
+ // Clean the unused part of the last block
+ m = (Block - 1) * Blksize;
+ n = Nrec - Last;
+
+ for (i = 0; i < Ncol; i++)
+ memset(Memcol[i] + m + Last * Clens[i],
+ (Isnum[i]) ? 0 : ' ', n * Clens[i]);
+
+ // We must Unmap the view and use the saved file handle
+ // to put an EOF at the end of the last block of the file.
+ CloseMemMap(fp->Memory, (size_t)fp->Length);
+ fp->Count = 0; // Avoid doing it twice
+
+ // Remove extra blocks
+ n = Block * Blksize;
+
+#if defined(_WIN32)
+ DWORD drc = SetFilePointer(fp->Handle, n, NULL, FILE_BEGIN);
+
+ if (drc == 0xFFFFFFFF) {
+ sprintf(g->Message, MSG(FUNCTION_ERROR),
+ "SetFilePointer", GetLastError());
+ CloseHandle(fp->Handle);
+ return RC_FX;
+ } // endif
+
+ if (trace(1))
+ htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc);
+
+ if (!SetEndOfFile(fp->Handle)) {
+ sprintf(g->Message, MSG(FUNCTION_ERROR),
+ "SetEndOfFile", GetLastError());
+ CloseHandle(fp->Handle);
+ return RC_FX;
+ } // endif
+
+ CloseHandle(fp->Handle);
+#else // UNIX
+ if (ftruncate(fp->Handle, (off_t)n)) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(fp->Handle);
+ return RC_FX;
+ } // endif
+
+ close(fp->Handle);
+#endif // UNIX
+ } else
+ // True vector table, Table file size does not change.
+ // Just clean the unused part of the file.
+ for (n = Fpos - Tpos, i = 0; i < Ncol; i++)
+ memset(Memcol[i] + Tpos * Clens[i], 0, n * Clens[i]);
+
+ // Reset Last and Block values in the catalog
+ PlugCloseFile(g, To_Fb); // in case of Header
+ ResetTableSize(g, Block, Last);
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool VCMFAM::MoveIntermediateLines(PGLOBAL, bool *)
+ {
+ int i, m, n;
+
+ if ((n = Fpos - Spos) > 0) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!MaxBlk) {
+ // Old VCT format, moving must respect block limits
+ char *ps, *pt;
+ int req, soff, toff;
+
+ for (; n > 0; n -= req) {
+ soff = Spos % Nrec;
+ toff = Tpos % Nrec;
+ req = (size_t)MY_MIN(n, Nrec - MY_MAX(soff, toff));
+
+ for (i = 0; i < Ncol; i++) {
+ ps = Memcol[i] + (Spos / Nrec) * Blksize + soff * Clens[i];
+ pt = Memcol[i] + (Tpos / Nrec) * Blksize + toff * Clens[i];
+ memmove(pt, ps, req * Clens[i]);
+ } // endfor i
+
+ Tpos += req;
+ Spos += req;
+ } // endfor n
+
+ } else {
+ // True vector format, all is simple...
+ for (i = 0; i < Ncol; i++) {
+ m = Clens[i];
+ memmove(Memcol[i] + Tpos * m, Memcol[i] + Spos * m, n * m);
+ } // endfor i
+
+ Tpos += n;
+ } // endif MaxBlk
+
+ if (trace(1))
+ htrc("move %d bytes\n", n);
+
+ } // endif n
+
+ return false;
+ } // end of MoveIntermediate Lines
+
+/***********************************************************************/
+/* Data Base close routine for VMP access method. */
+/***********************************************************************/
+void VCMFAM::CloseTableFile(PGLOBAL g, bool)
+ {
+ int wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ if (mode == MODE_INSERT) {
+ if (!Closing) {
+ if (CurNum) {
+ // Some more inserted lines remain to be written
+ Last = CurNum;
+ Block = CurBlk + 1;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else {
+ Last = Nrec;
+ Block = CurBlk;
+ wrc = RC_OK;
+ } // endif CurNum
+
+ } else
+ wrc = RC_FX; // Last write was in error
+
+ PlugCloseFile(g, To_Fb);
+
+ if (wrc != RC_FX)
+ /*rc =*/ ResetTableSize(g, Block, Last);
+
+ } else if (mode != MODE_DELETE || Abort)
+ PlugCloseFile(g, To_Fb);
+
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+bool VCMFAM::ReadBlock(PGLOBAL, PVCTCOL colp)
+ {
+ char *mempos;
+ int i = colp->Index - 1;
+ int n = Nrec * ((MaxBlk || Split) ? colp->Clen : Lrecl);
+
+ /*********************************************************************/
+ /* Calculate the start position of the column block to read. */
+ /*********************************************************************/
+ mempos = Memcol[i] + n * CurBlk;
+
+ if (trace(1))
+ htrc("mempos=%p i=%d Nrec=%d Clen=%d CurBlk=%d\n",
+ mempos, i, Nrec, colp->Clen, CurBlk);
+
+ if (colp->GetStatus(BUF_MAPPED))
+ colp->Blk->SetValPointer(mempos);
+
+ if (trace(1))
+ num_read++;
+
+ return false;
+ } // end of ReadBlock
+
+/***********************************************************************/
+/* WriteBlock: Write back current column values for one block. */
+/* Note: there is nothing to do because we are working directly into */
+/* the mapped file, except when checking for Update but in this case */
+/* we do not want to write back the modifications either. */
+/***********************************************************************/
+bool VCMFAM::WriteBlock(PGLOBAL, PVCTCOL colp __attribute__((unused)))
+ {
+#if defined(_DEBUG)
+ char *mempos;
+ int i = colp->Index - 1;
+ int n = Nrec * colp->Clen;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to write. */
+ /*********************************************************************/
+ mempos = Memcol[i] + n * CurBlk;
+
+ if (trace(1))
+ htrc("modif=%d mempos=%p i=%d Nrec=%d Clen=%d colblk=%d\n",
+ Modif, mempos, i, Nrec, colp->Clen, colp->ColBlk);
+
+#endif // _DEBUG
+
+ return false;
+ } // end of WriteBlock
+
+/* -------------------------- Class VECFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the VECFAM class. */
+/***********************************************************************/
+VECFAM::VECFAM(PVCTDEF tdp) : VCTFAM((PVCTDEF)tdp)
+ {
+ Streams = NULL;
+ To_Fbs = NULL;
+ To_Bufs = NULL;
+ Split = true;
+ Block = Last = -1;
+ InitUpdate = false;
+ } // end of VECFAM standard constructor
+
+VECFAM::VECFAM(PVECFAM txfp) : VCTFAM(txfp)
+ {
+ Streams = txfp->Streams;
+ To_Fbs = txfp->To_Fbs;
+ Clens = txfp->Clens;
+ To_Bufs = txfp->To_Bufs;
+ InitUpdate = txfp->InitUpdate;
+ } // end of VECFAM copy constructor
+
+/***********************************************************************/
+/* VEC Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool VECFAM::OpenTableFile(PGLOBAL g)
+ {
+ char opmode[4];
+ int i;
+ bool b= false;
+ PCOLDEF cdp;
+ PVCTCOL cp;
+ MODE mode = Tdbp->GetMode();
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ /*********************************************************************/
+ /* Call Cardinality to set Block and Last values in case it was not */
+ /* already called (this happens indeed in test xmode) */
+ /*********************************************************************/
+ Cardinality(g);
+
+ /*********************************************************************/
+ /* Open according to input/output mode required. */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ strcpy(opmode, "rb");
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ // This will delete the whole file
+ strcpy(opmode, "wb");
+
+ // This will stop the process by causing GetProgMax to return 0.
+ ResetTableSize(g, 0, Nrec);
+ break;
+ } // endif filter
+
+ // Selective delete, pass thru
+ /* fall through */
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ strcpy(opmode, (UseTemp) ? "rb": "r+b");
+ break;
+ case MODE_INSERT:
+ strcpy(opmode, "ab");
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch Mode
+
+ /*********************************************************************/
+ /* Initialize the array of file structures. */
+ /*********************************************************************/
+ if (!Colfn) {
+ // Prepare the column file name pattern and set Ncol
+ Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
+ } // endif Colfn
+
+ Streams = (FILE* *)PlugSubAlloc(g, NULL, Ncol * sizeof(FILE*));
+ To_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
+
+ for (i = 0; i < Ncol; i++) {
+ Streams[i] = NULL;
+ To_Fbs[i] = NULL;
+ } // endif i
+
+ /*********************************************************************/
+ /* Open the files corresponding to columns used in the query. */
+ /*********************************************************************/
+ if (mode == MODE_INSERT || mode == MODE_DELETE) {
+ // All columns must be written or deleted
+ for (i = 0, cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext())
+ if (OpenColumnFile(g, opmode, i))
+ return true;
+
+ // Check for void table or missing columns
+ for (b = !Streams[0], i = 1; i < Ncol; i++)
+ if (b != !Streams[i])
+ return true;
+
+ } else {
+ /*******************************************************************/
+ /* Open the files corresponding to updated columns of the query. */
+ /*******************************************************************/
+ for (cp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols; cp;
+ cp = (PVCTCOL)cp->Next)
+ if (OpenColumnFile(g, opmode, cp->Index - 1))
+ return true;
+
+ // Open in read only mode the used columns not already open
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial() && !Streams[cp->Index - 1])
+ if (OpenColumnFile(g, "rb", cp->Index - 1))
+ return true;
+
+ // Check for void table or missing columns
+ for (i = 0, cp = (PVCTCOL)Tdbp->GetColumns(); cp;
+ cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) {
+ if (!i++)
+ b = !Streams[cp->Index - 1];
+ else if (b != !Streams[cp->Index - 1])
+ return true;
+
+ } // endif Special
+
+ } // endif mode
+
+ /*********************************************************************/
+ /* Allocate the table and column block buffer. */
+ /*********************************************************************/
+ return (b) ? false : AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Open the file corresponding to one column. */
+/***********************************************************************/
+bool VECFAM::OpenColumnFile(PGLOBAL g, PCSZ opmode, int i)
+ {
+ char filename[_MAX_PATH];
+ PDBUSER dup = PlgGetUser(g);
+
+ sprintf(filename, Colfn, i+1);
+
+ if (!(Streams[i] = PlugOpenFile(g, filename, opmode))) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return (Tdbp->GetMode() == MODE_READ && errno == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif Streams
+
+ if (trace(1))
+ htrc("File %s is open in mode %s\n", filename, opmode);
+
+ To_Fbs[i] = dup->Openlist; // Keep track of File blocks
+ return false;
+ } // end of OpenColumnFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/***********************************************************************/
+bool VECFAM::AllocateBuffer(PGLOBAL g)
+ {
+ int i;
+ PVCTCOL cp;
+ PCOLDEF cdp;
+ PTDBVCT tdbp = (PTDBVCT)Tdbp;
+ MODE mode = tdbp->GetMode();
+ PDOSDEF defp = (PDOSDEF)tdbp->GetDef();
+
+ if (mode != MODE_READ) {
+ // Allocate what is needed by all modes except Read
+ T_Streams = (FILE* *)PlugSubAlloc(g, NULL, Ncol * sizeof(FILE*));
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+
+ // Give default values
+ for (i = 0; i < Ncol; i++) {
+ T_Streams[i] = Streams[i];
+ Clens[i] = 0;
+ } // endfor i
+
+ } // endif mode
+
+ if (mode == MODE_INSERT) {
+ bool chk = PlgGetUser(g)->Check & CHK_TYPE;
+
+ To_Bufs = (void**)PlugSubAlloc(g, NULL, Ncol * sizeof(void*));
+ cdp = defp->GetCols();
+
+ for (i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext()) {
+ Clens[i] = cdp->GetClen();
+ To_Bufs[i] = PlugSubAlloc(g, NULL, Nrec * Clens[i]);
+
+ if (cdp->GetType() == TYPE_STRING)
+ memset(To_Bufs[i], ' ', Nrec * Clens[i]);
+ else
+ memset(To_Bufs[i], 0, Nrec * Clens[i]);
+
+ } // endfor cdp
+
+ for (cp = (PVCTCOL)tdbp->Columns; cp; cp = (PVCTCOL)cp->Next)
+ cp->Blk = AllocValBlock(g, To_Bufs[cp->Index - 1],
+ cp->Buf_Type, Nrec, cp->Format.Length,
+ cp->Format.Prec, chk, true, cp->IsUnsigned());
+
+ return InitInsert(g);
+ } else {
+ if (UseTemp || mode == MODE_DELETE) {
+ // Allocate all that is needed to move lines and make Temp
+ if (UseTemp) {
+ Tempat = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ strcpy(Tempat, Colfn);
+ PlugSetPath(Tempat, Tempat, Tdbp->GetPath());
+ strcat(PlugRemoveType(Tempat, Tempat), ".t");
+ T_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
+ } // endif UseTemp
+
+ if (UseTemp)
+ for (i = 0; i < Ncol; i++) {
+ T_Streams[i] = (mode == MODE_UPDATE) ? (FILE*)1 : NULL;
+ T_Fbs[i] = NULL;
+ } // endfor i
+
+ if (mode == MODE_DELETE) { // All columns are moved
+ cdp = defp->GetCols();
+
+ for (i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext()) {
+ Clens[i] = cdp->GetClen();
+ Buflen = MY_MAX(Buflen, cdp->GetClen());
+ } // endfor cdp
+
+ } else { // Mode Update, only some columns are updated
+ for (cp = (PVCTCOL)tdbp->To_SetCols; cp; cp = (PVCTCOL)cp->Next) {
+ i = cp->Index -1;
+
+ if (UseTemp)
+ T_Streams[i] = NULL; // Mark the streams to open
+
+ Clens[i] = cp->Clen;
+ Buflen = MY_MAX(Buflen, cp->Clen);
+ } // endfor cp
+
+ InitUpdate = true; // To be initialized
+ } // endif mode
+
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen * Nrec);
+ } // endif mode
+
+ // Finally allocate column buffers for all modes
+ for (cp = (PVCTCOL)tdbp->Columns; cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) // Not a pseudo column
+ cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec,
+ true, true, cp->IsUnsigned());
+
+ } // endif mode
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Do initial action when inserting. */
+/***********************************************************************/
+bool VECFAM::InitInsert(PGLOBAL)
+ {
+ // We come here in MODE_INSERT only
+ CurBlk = 0;
+ CurNum = 0;
+ AddBlock = true;
+ return false;
+ } // end of InitInsert
+
+/***********************************************************************/
+/* Reset buffer access according to indexing and to mode. */
+/* >>>>>>>>>>>>>> TO BE RE-VISITED AND CHECKED <<<<<<<<<<<<<<<<<<<<<< */
+/***********************************************************************/
+void VECFAM::ResetBuffer(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* If access is random, performances can be much better when the */
+ /* reads are done on only one row, except for small tables that can */
+ /* be entirely read in one block. If the index is just used as a */
+ /* bitmap filter, as for Update or Delete, reading will be */
+ /* sequential and we better keep block reading. */
+ /*********************************************************************/
+ if (Tdbp->GetKindex() && Block > 1 && Tdbp->GetMode() == MODE_READ) {
+ Nrec = 1; // Better for random access
+ Rbuf = 0;
+ OldBlk = -2; // Has no meaning anymore
+ Block = Tdbp->Cardinality(g); // Blocks are one line now
+ Last = 1; // Probably unuseful
+ } // endif Mode
+
+ } // end of ResetBuffer
+
+/***********************************************************************/
+/* Data Base write routine for VCT access method. */
+/***********************************************************************/
+int VECFAM::WriteBuffer(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("VCT WriteBuffer: R%d Mode=%d CurNum=%d CurBlk=%d\n",
+ Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
+
+ if (Tdbp->GetMode() == MODE_INSERT) {
+ if (Closing || ++CurNum == Nrec) {
+ // Here we must add a new blocks to the files
+ int i;
+ size_t n = (size_t)CurNum;
+
+ for (i = 0; i < Ncol; i++)
+ if (n != fwrite(To_Bufs[i], (size_t)Clens[i], n, Streams[i])) {
+ sprintf(g->Message, MSG(WRITE_STRERROR), To_File, strerror(errno));
+ return RC_FX;
+ } // endif
+
+ if (!Closing) {
+ CurBlk++;
+ CurNum = 0;
+ } // endif Closing
+
+ } // endif Closing || CurNum
+
+ } else // Mode Update
+ // Writing updates being done in ReadDB we do initialization only.
+ if (InitUpdate) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ InitUpdate = false; // Done
+ } // endif InitUpdate
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for split vertical access methods. */
+/* Note: lines are moved directly in the files (ooops...) */
+/* Using temp file depends on the Check setting, false by default. */
+/***********************************************************************/
+int VECFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ if (trace(1))
+ htrc("VEC DeleteDB: rc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = Cardinality(g);
+
+ if (trace(1))
+ htrc("Fpos placed at file end=%d\n", Fpos);
+
+ } else // Fpos is the Deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ // First line to delete
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open the temporary files, Spos is at the beginning of file. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else
+ /*****************************************************************/
+ /* Move of eventual preceding lines is not required here. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ Spos = Tpos = Fpos;
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+#ifdef _DEBUG
+ assert(Spos == Fpos);
+#endif
+ Spos++; // New start position is on next line
+
+ if (trace(1))
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ if (!UseTemp) {
+ /*****************************************************************/
+ /* Because the chsize functionality is only accessible with a */
+ /* system call we must close the files and reopen them with the */
+ /* open function (_fopen for MS??) this is still to be checked */
+ /* for compatibility with other OS's. */
+ /*****************************************************************/
+ char filename[_MAX_PATH];
+ int h; // File handle, return code
+
+ for (int i = 0; i < Ncol; i++) {
+ sprintf(filename, Colfn, i + 1);
+ /*rc =*/ PlugCloseFile(g, To_Fbs[i]);
+
+ if ((h= global_open(g, MSGID_OPEN_STRERROR, filename, O_WRONLY)) <= 0)
+ return RC_FX;
+
+ /***************************************************************/
+ /* Remove extra records. */
+ /***************************************************************/
+#if defined(UNIX)
+ if (ftruncate(h, (off_t)(Tpos * Clens[i]))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#else
+ if (chsize(h, Tpos * Clens[i])) {
+ sprintf(g->Message, MSG(CHSIZE_ERROR), strerror(errno));
+ close(h);
+ return RC_FX;
+ } // endif
+#endif
+
+ close(h);
+
+ if (trace(1))
+ htrc("done, h=%d irc=%d\n", h, irc);
+
+ } // endfor i
+
+ } else // UseTemp
+ // Ok, now delete old files and rename new temp files
+ if (RenameTempFile(g) == RC_FX)
+ return RC_FX;
+
+ // Reset these values for TDBVCT::MakeBlockValues
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ if (ResetTableSize(g, Block, Last))
+ return RC_FX;
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open temporary files used while updating or deleting. */
+/* Note: the files not updated have been given a T_Stream value of 1. */
+/***********************************************************************/
+bool VECFAM::OpenTempFile(PGLOBAL g)
+ {
+ char tempname[_MAX_PATH];
+
+ for (int i = 0; i < Ncol; i++)
+ if (!T_Streams[i]) {
+ /*****************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*****************************************************************/
+ sprintf(tempname, Tempat, i+1);
+
+ if (!(T_Streams[i] = PlugOpenFile(g, tempname, "wb"))) {
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return true;
+ } else
+ T_Fbs[i] = PlgGetUser(g)->Openlist;
+
+ } else // This is a column that is not updated
+ T_Streams[i] = NULL; // For RenameTempFile
+
+ return false;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate updated lines before writing blocks. */
+/***********************************************************************/
+bool VECFAM::MoveLines(PGLOBAL g)
+ {
+ if (UseTemp && !InitUpdate) { // Don't do it in check pass
+ Fpos = OldBlk * Nrec;
+
+ if (MoveIntermediateLines(g)) {
+ Closing = true; // ???
+ return true;
+ } // endif UseTemp
+
+// Spos = Fpos + Nrec;
+ } // endif UseTemp
+ return false;
+
+ } // end of MoveLines
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool VECFAM::MoveIntermediateLines(PGLOBAL g, bool *)
+ {
+ int i, n;
+ bool b = false;
+ size_t req, len;
+
+ for (n = Fpos - Spos; n > 0; n -= Nrec) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ req = (size_t)MY_MIN(n, Nrec);
+
+ for (i = 0; i < Ncol; i++) {
+ if (!T_Streams[i])
+ continue; // Non updated column
+
+ if (!UseTemp || !b)
+ if (fseek(Streams[i], Spos * Clens[i], SEEK_SET)) {
+ sprintf(g->Message, MSG(READ_SEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ len = fread(To_Buf, Clens[i], req, Streams[i]);
+
+ if (trace(1))
+ htrc("after read req=%d len=%d\n", req, len);
+
+ if (len != req) {
+ sprintf(g->Message, MSG(DEL_READ_ERROR), (int) req, (int) len);
+ return true;
+ } // endif len
+
+ if (!UseTemp)
+ if (fseek(T_Streams[i], Tpos * Clens[i], SEEK_SET)) {
+ sprintf(g->Message, MSG(WRITE_SEEK_ERR), strerror(errno));
+ return true;
+ } // endif
+
+ if ((len = fwrite(To_Buf, Clens[i], req, T_Streams[i])) != req) {
+ sprintf(g->Message, MSG(DEL_WRITE_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ if (trace(1))
+ htrc("after write pos=%d\n", ftell(Streams[i]));
+
+ } // endfor i
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (trace(1))
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ b = true;
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediate Lines
+
+/***********************************************************************/
+/* Delete the old files and rename the new temporary files. */
+/***********************************************************************/
+int VECFAM::RenameTempFile(PGLOBAL g)
+ {
+ char *tempname, filetemp[_MAX_PATH], filename[_MAX_PATH];
+ int rc = RC_OK;
+
+ // Close all files.
+ // This loop is necessary because, in case of join,
+ // the table files can have been open several times.
+ for (PFBLOCK fb = PlgGetUser(g)->Openlist; fb; fb = fb->Next)
+ rc = PlugCloseFile(g, fb);
+
+ for (int i = 0; i < Ncol && rc == RC_OK; i++) {
+ if (!T_Fbs[i])
+ continue;
+
+ tempname = (char*)T_Fbs[i]->Fname;
+
+ if (!Abort) {
+ sprintf(filename, Colfn, i+1);
+ PlugSetPath(filename, filename, Tdbp->GetPath());
+ strcat(PlugRemoveType(filetemp, filename), ".ttt");
+ remove(filetemp); // May still be there from previous error
+
+ if (rename(filename, filetemp)) { // Save file for security
+ snprintf(g->Message, MAX_STR, MSG(RENAME_ERROR),
+ filename, filetemp, strerror(errno));
+ rc = RC_FX;
+ } else if (rename(tempname, filename)) {
+ snprintf(g->Message, MAX_STR, MSG(RENAME_ERROR),
+ tempname, filename, strerror(errno));
+ rc = rename(filetemp, filename); // Restore saved file
+ rc = RC_FX;
+ } else if (remove(filetemp)) {
+ sprintf(g->Message, MSG(REMOVE_ERROR),
+ filetemp, strerror(errno));
+ rc = RC_INFO; // Acceptable
+ } // endif's
+
+ } else
+ remove(tempname);
+
+ } // endfor i
+
+ return rc;
+ } // end of RenameTempFile
+
+/***********************************************************************/
+/* Data Base close routine for VEC access method. */
+/***********************************************************************/
+void VECFAM::CloseTableFile(PGLOBAL g, bool abort)
+ {
+ int rc = 0, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ Abort = abort;
+
+ if (mode == MODE_INSERT) {
+ if (Closing)
+ wrc = RC_FX; // Last write was in error
+ else
+ if (CurNum) {
+ // Some more inserted lines remain to be written
+ Last += (CurBlk * Nrec + CurNum -1);
+ Block += (Last / Nrec);
+ Last = Last % Nrec + 1;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else {
+ Block += CurBlk;
+ wrc = RC_OK;
+ } // endif CurNum
+
+ if (wrc != RC_FX)
+ rc = ResetTableSize(g, Block, Last);
+ else
+ throw 44;
+
+ } else if (mode == MODE_UPDATE) {
+ if (UseTemp && !InitUpdate && !Abort) {
+ // Write any intermediate lines to temp file
+ Fpos = OldBlk * Nrec;
+ Abort = MoveIntermediateLines(g) != RC_OK;
+// Spos = Fpos + Nrec;
+ } // endif UseTemp
+
+ // Write back to file any pending modifications
+ if (wrc == RC_OK)
+ for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols;
+ colp; colp = (PVCTCOL)colp->Next)
+ colp->WriteBlock(g);
+
+ if (wrc == RC_OK && UseTemp && !InitUpdate && !Abort) {
+ // Write any intermediate lines to temp file
+ Fpos = (Block - 1) * Nrec + Last;
+ Abort = MoveIntermediateLines(g) != RC_OK;
+ } // endif UseTemp
+
+ } // endif's mode
+
+ if (UseTemp && !InitUpdate) {
+ // If they are errors, leave files unchanged
+ rc = RenameTempFile(g);
+
+ } else if (Streams)
+ for (int i = 0; i < Ncol; i++)
+ if (Streams[i]) {
+ rc = PlugCloseFile(g, To_Fbs[i]);
+ Streams[i] = NULL;
+ To_Fbs[i] = NULL;
+ } // endif Streams
+
+ if (trace(1))
+ htrc("VCT CloseTableFile: closing %s wrc=%d rc=%d\n", To_File, wrc, rc);
+
+ } // end of CloseTableFile
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+bool VECFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int i, len;
+ size_t n;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to read. */
+ /*********************************************************************/
+ len = Nrec * colp->Clen * CurBlk;
+ i = colp->Index - 1;
+
+ if (trace(1))
+ htrc("len=%d i=%d Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d\n",
+ len, i, Nrec, colp->Deplac, Lrecl, CurBlk);
+
+ if (fseek(Streams[i], len, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ n = fread(colp->Blk->GetValPointer(), (size_t)colp->Clen,
+ (size_t)Nrec, Streams[i]);
+
+ if (n != (size_t)Nrec && (CurBlk+1 != Block || n != (size_t)Last)) {
+ char fn[_MAX_PATH];
+
+ sprintf(fn, Colfn, colp->Index);
+#if defined(_WIN32)
+ if (feof(Streams[i]))
+#else // !_WIN32
+ if (errno == NO_ERROR)
+#endif // !_WIN32
+ sprintf(g->Message, MSG(BAD_READ_NUMBER), (int) n, fn);
+ else
+ sprintf(g->Message, MSG(READ_ERROR),
+ fn, strerror(errno));
+
+ if (trace(1))
+ htrc(" Read error: %s\n", g->Message);
+
+ return true;
+ } // endif
+
+ if (trace(1))
+ num_read++;
+
+ return false;
+ } // end of ReadBlock
+
+/***********************************************************************/
+/* WriteBlock: Write back current column values for one block. */
+/* Note: the test of Status is meant to prevent physical writing of */
+/* the block during the checking loop in mode Update. It is set to */
+/* BUF_EMPTY when reopening the table between the two loops. */
+/***********************************************************************/
+bool VECFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int i, len;
+ size_t n;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to write. */
+ /*********************************************************************/
+ len = Nrec * colp->Clen * colp->ColBlk;
+ i = colp->Index - 1;
+
+ if (trace(1))
+ htrc("modif=%d len=%d i=%d Nrec=%d Deplac=%d Lrecl=%d colblk=%d\n",
+ Modif, len, i, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
+
+ if (Tdbp->GetMode() == MODE_UPDATE && !UseTemp)
+ if (fseek(T_Streams[i], len, SEEK_SET)) {
+ sprintf(g->Message, MSG(FSEEK_ERROR), strerror(errno));
+ return true;
+ } // endif
+
+ // Here Nrec was changed to CurNum in mode Insert,
+ // this is the true number of records to write,
+ // this also avoid writing garbage in the file for true vector tables.
+ n = (Tdbp->GetMode() == MODE_INSERT) ? CurNum
+ : (colp->ColBlk == Block - 1) ? Last : Nrec;
+
+ if (n != fwrite(colp->Blk->GetValPointer(),
+ (size_t)colp->Clen, n, T_Streams[i])) {
+ char fn[_MAX_PATH];
+
+ sprintf(fn, (UseTemp) ? Tempat : Colfn, colp->Index);
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
+
+ if (trace(1))
+ htrc("Write error: %s\n", strerror(errno));
+
+ return true;
+ } else
+ Spos = Fpos + n;
+
+#if defined(UNIX)
+ fflush(Streams[i]); //NGC
+#endif
+ return false;
+ } // end of WriteBlock
+
+/* -------------------------- Class VMPFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the VMPFAM class. */
+/***********************************************************************/
+VMPFAM::VMPFAM(PVCTDEF tdp) : VCMFAM((PVCTDEF)tdp)
+ {
+ To_Fbs = NULL;
+ Split = true;
+ Block = Last = -1;
+ } // end of VMPFAM standard constructor
+
+VMPFAM::VMPFAM(PVMPFAM txfp) : VCMFAM(txfp)
+ {
+ To_Fbs = txfp->To_Fbs;
+ } // end of VMPFAM copy constructor
+
+/***********************************************************************/
+/* VCT Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool VMPFAM::OpenTableFile(PGLOBAL g)
+ {
+ int i;
+ bool b = false;
+ MODE mode = Tdbp->GetMode();
+ PCOLDEF cdp;
+ PVCTCOL cp;
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+
+ if (mode == MODE_DELETE && !Tdbp->GetNext()) {
+ DelRows = Cardinality(g);
+
+ // This will stop the process by causing GetProgMax to return 0.
+ ResetTableSize(g, 0, Nrec);
+ } else
+ Cardinality(g); // See comment in VECFAM::OpenTbleFile
+
+
+ /*********************************************************************/
+ /* Prepare the filename pattern for column files and set Ncol. */
+ /*********************************************************************/
+ if (!Colfn) {
+ // Prepare the column file name pattern
+ Colfn = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ Ncol = ((VCTDEF*)Tdbp->GetDef())->MakeFnPattern(Colfn);
+ } // endif Colfn
+
+ /*********************************************************************/
+ /* Initialize the array of file structures. */
+ /*********************************************************************/
+ Memcol = (char* *)PlugSubAlloc(g, NULL, Ncol * sizeof(char *));
+ To_Fbs = (PFBLOCK *)PlugSubAlloc(g, NULL, Ncol * sizeof(PFBLOCK));
+
+ for (i = 0; i < Ncol; i++) {
+ Memcol[i] = NULL;
+ To_Fbs[i] = NULL;
+ } // endif i
+
+ /*********************************************************************/
+ /* Open the files corresponding to columns used in the query. */
+ /*********************************************************************/
+ if (mode == MODE_DELETE) {
+ // All columns are used in Delete mode
+ for (i = 0, cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext())
+ if (MapColumnFile(g, mode, i))
+ return true;
+
+ } else {
+ /*******************************************************************/
+ /* Open the files corresponding to updated columns of the query. */
+ /*******************************************************************/
+ for (cp = (PVCTCOL)((PTDBVCT)Tdbp)->To_SetCols; cp;
+ cp = (PVCTCOL)cp->Next)
+ if (MapColumnFile(g, MODE_UPDATE, cp->Index - 1))
+ return true;
+
+ /*******************************************************************/
+ /* Open other non already open used columns (except pseudos) */
+ /*******************************************************************/
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial() && !Memcol[cp->Index - 1])
+ if (MapColumnFile(g, MODE_READ, cp->Index - 1))
+ return true;
+
+ // Check for void table or missing columns
+ for (i = 0, cp = (PVCTCOL)Tdbp->GetColumns(); cp;
+ cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) {
+ if (!i++)
+ b = !Memcol[cp->Index - 1];
+ else if (b != !Memcol[cp->Index - 1])
+ return true;
+
+ } // endif Special
+
+ } // endif mode
+
+ /*********************************************************************/
+ /* Allocate the table and column block buffer. */
+ /*********************************************************************/
+ return (b) ? false : AllocateBuffer(g);
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Open the file corresponding to one column. */
+/***********************************************************************/
+bool VMPFAM::MapColumnFile(PGLOBAL g, MODE mode, int i)
+ {
+ char filename[_MAX_PATH];
+ size_t len;
+ HANDLE hFile;
+ MEMMAP mm;
+ PFBLOCK fp;
+ PDBUSER dup = PlgGetUser(g);
+
+ sprintf(filename, Colfn, i+1);
+
+ /*********************************************************************/
+ /* The whole file will be mapped so we can use it as */
+ /* if it were entirely read into virtual memory. */
+ /* Firstly we check whether this file have been already mapped. */
+ /*********************************************************************/
+ if (mode == MODE_READ) {
+ for (fp = dup->Openlist; fp; fp = fp->Next)
+ if (fp->Type == TYPE_FB_MAP && !stricmp(fp->Fname, filename)
+ && fp->Count && fp->Mode == mode)
+ break;
+
+ if (trace(1))
+ htrc("Mapping file, fp=%p\n", fp);
+
+ } else
+ fp = NULL;
+
+ if (fp) {
+ /*******************************************************************/
+ /* File already mapped. Just increment use count and get pointer. */
+ /*******************************************************************/
+ fp->Count++;
+ Memcol[i] = fp->Memory;
+ len = fp->Length;
+ } else {
+ /*******************************************************************/
+ /* Create the mapping file object. */
+ /*******************************************************************/
+ hFile = CreateFileMap(g, filename, &mm, mode, DelRows);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+
+ if (!(*g->Message))
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "map", (int) rc, filename);
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return (mode == MODE_READ && rc == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+ } // endif hFile
+
+ /*****************************************************************/
+ /* Get the file size (assuming file is smaller than 4 GB) */
+ /*****************************************************************/
+ len = (size_t)mm.lenL;
+
+ if (mm.lenH)
+ len += ((size_t)mm.lenH * 0x000000001LL);
+
+ Memcol[i] = (char *)mm.memory;
+
+ if (!len) { // Empty or deleted file
+ CloseFileHandle(hFile);
+ ResetTableSize(g, 0, Nrec);
+ return false;
+ } // endif len
+
+ if (!Memcol[i]) {
+ CloseFileHandle(hFile);
+ sprintf(g->Message, MSG(MAP_VIEW_ERROR),
+ filename, GetLastError());
+ return true;
+ } // endif Memory
+
+ if (mode != MODE_DELETE) {
+ CloseFileHandle(hFile); // Not used anymore
+ hFile = INVALID_HANDLE_VALUE; // For Fblock
+ } // endif Mode
+
+ /*******************************************************************/
+ /* Link a Fblock. This make possible to reuse already opened maps */
+ /* and also to automatically unmap them in case of error g->jump. */
+ /* Note: block can already exist for previously closed file. */
+ /*******************************************************************/
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ fp->Type = TYPE_FB_MAP;
+ fp->Fname = PlugDup(g, filename);
+ fp->Next = dup->Openlist;
+ dup->Openlist = fp;
+ fp->Count = 1;
+ fp->Length = len;
+ fp->Memory = Memcol[i];
+ fp->Mode = mode;
+ fp->File = NULL;
+ fp->Handle = hFile; // Used for Delete
+ } // endif fp
+
+ To_Fbs[i] = fp; // Useful when closing
+
+ if (trace(1))
+ htrc("fp=%p count=%d MapView=%p len=%d\n",
+ fp, fp->Count, Memcol[i], len);
+
+ return false;
+ } // end of MapColumnFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/* Give a dummy value (1) to prevent allocating the value block. */
+/* It will be set pointing into the memory map of the file. */
+/***********************************************************************/
+bool VMPFAM::AllocateBuffer(PGLOBAL g)
+ {
+ PVCTCOL cp;
+
+ if (Tdbp->GetMode() == MODE_DELETE) {
+ PCOLDEF cdp = Tdbp->GetDef()->GetCols();
+
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+
+ for (int i = 0; cdp && i < Ncol; i++, cdp = cdp->GetNext())
+ Clens[i] = cdp->GetClen();
+
+ } // endif mode
+
+ for (cp = (PVCTCOL)Tdbp->GetColumns(); cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) { // Not a pseudo column
+ cp->Blk = AllocValBlock(g, (void*)1, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec,
+ true, true, cp->IsUnsigned());
+ cp->AddStatus(BUF_MAPPED);
+ } // endif IsSpecial
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for VMP access method. */
+/* Lines between deleted lines are moved in the mapfile view. */
+/***********************************************************************/
+int VMPFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ int i;
+ int m, n;
+
+ if (trace(1))
+ htrc("VMP DeleteDB: irc=%d tobuf=%p Tpos=%p Spos=%p\n",
+ irc, To_Buf, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the top of map position. */
+ /*******************************************************************/
+ Fpos = (Block - 1) * Nrec + Last;
+
+ if (trace(1))
+ htrc("Fpos placed at file top=%p\n", Fpos);
+
+ } else // Fpos is the Deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ /*******************************************************************/
+ /* First line to delete. Move of eventual preceding lines is */
+ /* not required here, just setting of future Spos and Tpos. */
+ /*******************************************************************/
+ Tpos = Fpos; // Spos is set below
+ } else if ((n = Fpos - Spos) > 0) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ for (i = 0; i < Ncol; i++) {
+ m = Clens[i];
+ memmove(Memcol[i] + Tpos * m, Memcol[i] + Spos * m, m * n);
+ } // endif i
+
+ Tpos += n;
+
+ if (trace(1))
+ htrc("move %d bytes\n", n);
+
+ } // endif n
+
+ if (irc == RC_OK) {
+ Spos = Fpos + 1; // New start position
+
+ if (trace(1))
+ htrc("after: Tpos=%p Spos=%p\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /* We must firstly Unmap the view and use the saved file handle */
+ /* to put an EOF at the end of the copied part of the file. */
+ /*******************************************************************/
+ PFBLOCK fp;
+
+ /*******************************************************************/
+ /* Reset the Block and Last values for TDBVCT::MakeBlockValues. */
+ /*******************************************************************/
+// Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+// Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ for (i = 0; i < Ncol; i++) {
+ fp = To_Fbs[i];
+ CloseMemMap(fp->Memory, (size_t)fp->Length);
+ fp->Count = 0; // Avoid doing it twice
+
+ /*****************************************************************/
+ /* Remove extra records. */
+ /*****************************************************************/
+ n = Tpos * Clens[i];
+
+#if defined(_WIN32)
+ DWORD drc = SetFilePointer(fp->Handle, n, NULL, FILE_BEGIN);
+
+ if (drc == 0xFFFFFFFF) {
+ sprintf(g->Message, MSG(FUNCTION_ERROR),
+ "SetFilePointer", GetLastError());
+ CloseHandle(fp->Handle);
+ return RC_FX;
+ } // endif
+
+ if (trace(1))
+ htrc("done, Tpos=%p newsize=%d drc=%d\n", Tpos, n, drc);
+
+ if (!SetEndOfFile(fp->Handle)) {
+ sprintf(g->Message, MSG(FUNCTION_ERROR),
+ "SetEndOfFile", GetLastError());
+ CloseHandle(fp->Handle);
+ return RC_FX;
+ } // endif
+
+ CloseHandle(fp->Handle);
+#else // UNIX
+ if (ftruncate(fp->Handle, (off_t)n)) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ close(fp->Handle);
+ return RC_FX;
+ } // endif
+
+ close(fp->Handle);
+#endif // UNIX
+ } // endfor i
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Data Base close routine for VMP access method. */
+/***********************************************************************/
+void VMPFAM::CloseTableFile(PGLOBAL g, bool)
+ {
+ if (Tdbp->GetMode() == MODE_DELETE) {
+ // Set Block and Nrec values for TDBVCT::MakeBlockValues
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+ ResetTableSize(g, Block, Last);
+ } else if (Tdbp->GetMode() == MODE_INSERT)
+ assert(false);
+
+ for (int i = 0; i < Ncol; i++)
+ PlugCloseFile(g, To_Fbs[i]);
+
+ } // end of CloseTableFile
+
+/* -------------------------- Class BGVFAM --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the BGVFAM class. */
+/***********************************************************************/
+// Constructors
+BGVFAM::BGVFAM(PVCTDEF tdp) : VCTFAM(tdp)
+ {
+ Hfile = INVALID_HANDLE_VALUE;
+ Tfile = INVALID_HANDLE_VALUE;
+ BigDep = NULL;
+ } // end of BGVFAM constructor
+
+BGVFAM::BGVFAM(PBGVFAM txfp) : VCTFAM(txfp)
+ {
+ Hfile = txfp->Hfile;
+ Tfile = txfp->Tfile;
+ BigDep= txfp->BigDep;
+ } // end of BGVFAM copy constructor
+
+/***********************************************************************/
+/* Set current position in a big file. */
+/***********************************************************************/
+bool BGVFAM::BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, bool b)
+ {
+#if defined(_WIN32)
+ char buf[256];
+ DWORD drc, m = (b) ? FILE_END : FILE_BEGIN;
+ LARGE_INTEGER of;
+
+ of.QuadPart = pos;
+ of.LowPart = SetFilePointer(h, of.LowPart, &of.HighPart, m);
+
+ if (of.LowPart == INVALID_SET_FILE_POINTER &&
+ (drc = GetLastError()) != NO_ERROR) {
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(SFP_ERROR), buf);
+ return true;
+ } // endif
+#else // !_WIN32
+ if (lseek64(h, pos, (b) ? SEEK_END : SEEK_SET) < 0) {
+ sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
+ return true;
+ } // endif
+#endif // !_WIN32
+
+ return false;
+ } // end of BigSeek
+
+/***********************************************************************/
+/* Read from a big file. */
+/***********************************************************************/
+bool BGVFAM::BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req)
+ {
+ bool rc = false;
+
+#if defined(_WIN32)
+ DWORD nbr, drc, len = (DWORD)req;
+ bool brc = ReadFile(h, inbuf, len, &nbr, NULL);
+
+ if (trace(1))
+ htrc("after read req=%d brc=%d nbr=%d\n", req, brc, nbr);
+
+ if (!brc || nbr != len) {
+ char buf[256]; // , *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ if (brc)
+ strcpy(buf, MSG(BAD_BYTE_READ));
+ else {
+ drc = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ } // endelse brc
+
+ sprintf(g->Message, MSG(READ_ERROR), To_File, buf);
+
+ if (trace(1))
+ htrc("BIGREAD: %s\n", g->Message);
+
+ rc = true;
+ } // endif brc || nbr
+#else // !_WIN32
+ size_t len = (size_t)req;
+ ssize_t nbr = read(h, inbuf, len);
+
+ if (nbr != (ssize_t)len) {
+ const char *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ sprintf(g->Message, MSG(READ_ERROR), fn, strerror(errno));
+
+ if (trace(1))
+ htrc("BIGREAD: nbr=%d len=%d errno=%d %s\n",
+ nbr, len, errno, g->Message);
+
+ rc = true;
+ } // endif nbr
+#endif // !_WIN32
+
+ return rc;
+ } // end of BigRead
+
+/***********************************************************************/
+/* Write into a big file. */
+/***********************************************************************/
+bool BGVFAM::BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req)
+ {
+ bool rc = false;
+
+#if defined(_WIN32)
+ DWORD nbw, drc, len = (DWORD)req;
+ bool brc = WriteFile(h, inbuf, len, &nbw, NULL);
+
+ if (trace(1))
+ htrc("after write req=%d brc=%d nbw=%d\n", req, brc, nbw);
+
+ if (!brc || nbw != len) {
+ char buf[256];
+ PCSZ fn = (h == Hfile) ? To_File : "Tempfile";
+
+ if (brc)
+ strcpy(buf, MSG(BAD_BYTE_NUM));
+ else {
+ drc = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ } // endelse brc
+
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, buf);
+
+ if (trace(1))
+ htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
+ nbw, len, drc, g->Message);
+
+ rc = true;
+ } // endif brc || nbw
+#else // !_WIN32
+ size_t len = (size_t)req;
+ ssize_t nbw = write(h, inbuf, len);
+
+ if (nbw != (ssize_t)len) {
+ const char *fn = (h == Hfile) ? To_File : "Tempfile";
+
+ sprintf(g->Message, MSG(WRITE_STRERROR), fn, strerror(errno));
+
+ if (trace(1))
+ htrc("BIGWRITE: nbw=%d len=%d errno=%d %s\n",
+ nbw, len, errno, g->Message);
+
+ rc = true;
+ } // endif nbr
+#endif // !_WIN32
+
+ return rc;
+ } // end of BigWrite
+
+/***********************************************************************/
+/* Get the Headlen, Block and Last info from the file header. */
+/***********************************************************************/
+int BGVFAM::GetBlockInfo(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int n;
+ VECHEADER vh;
+ HANDLE h;
+
+ if (Header < 1 || Header > 3 || !MaxBlk) {
+ sprintf(g->Message, "Invalid header value %d", Header);
+ return -1;
+ } else
+ n = (Header == 1) ? (int)sizeof(VECHEADER) : 0;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (Header == 2)
+ strcat(PlugRemoveType(filename, filename), ".blk");
+
+#if defined(_WIN32)
+ LARGE_INTEGER len;
+
+ h = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (h != INVALID_HANDLE_VALUE) {
+ // Get the size of the file (can be greater than 4 GB)
+ len.LowPart = GetFileSize(h, (LPDWORD)&len.HighPart);
+ } // endif h
+
+ if (h == INVALID_HANDLE_VALUE || !len.QuadPart) {
+#else // !_WIN32
+ h = open64(filename, O_RDONLY, 0);
+
+ if (h == INVALID_HANDLE_VALUE || !_filelength(h)) {
+#endif // !_WIN32
+ // Consider this is a void table
+ if (trace(1))
+ htrc("Void table h=%d\n", h);
+
+ Last = Nrec;
+ Block = 0;
+
+ if (h != INVALID_HANDLE_VALUE)
+ CloseFileHandle(h);
+
+ return n;
+ } else if (Header == 3)
+ /*b = */ BigSeek(g, h, -(BIGINT)sizeof(vh), true);
+
+ if (BigRead(g, h, &vh, sizeof(vh))) {
+ sprintf(g->Message, "Error reading header file %s", filename);
+ n = -1;
+ } else if (MaxBlk * Nrec != vh.MaxRec) {
+ sprintf(g->Message, "MaxRec=%d doesn't match MaxBlk=%d Nrec=%d",
+ vh.MaxRec, MaxBlk, Nrec);
+ n = -1;
+ } else {
+ Block = (vh.NumRec > 0) ? (vh.NumRec + Nrec - 1) / Nrec : 0;
+ Last = (vh.NumRec + Nrec - 1) % Nrec + 1;
+
+ if (trace(1))
+ htrc("Block=%d Last=%d\n", Block, Last);
+
+ } // endif's
+
+ CloseFileHandle(h);
+ return n;
+ } // end of GetBlockInfo
+
+/***********************************************************************/
+/* Set the MaxRec and NumRec info in the file header. */
+/***********************************************************************/
+bool BGVFAM::SetBlockInfo(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool b = false, rc = false;
+ VECHEADER vh;
+ HANDLE h = INVALID_HANDLE_VALUE;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (Header != 2) {
+ if (Hfile != INVALID_HANDLE_VALUE) {
+ h = Hfile;
+
+ if (Header == 1)
+ /*bk =*/ BigSeek(g, h, (BIGINT)0);
+
+ } else
+ b = true;
+
+ } else // Header == 2
+ strcat(PlugRemoveType(filename, filename), ".blk");
+
+ if (h == INVALID_HANDLE_VALUE) {
+#if defined(_WIN32)
+ DWORD creation = (b) ? OPEN_EXISTING : TRUNCATE_EXISTING;
+
+ h = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0,
+ NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
+
+#else // !_WIN32
+ int oflag = (b) ? O_RDWR : O_RDWR | O_TRUNC;
+
+ h = open64(filename, oflag, 0);
+#endif // !_WIN32
+
+ if (h == INVALID_HANDLE_VALUE) {
+ sprintf(g->Message, "Error opening header file %s", filename);
+ return true;
+ } // endif h
+
+ } // endif h
+
+ if (Header == 3)
+ /*bk =*/ BigSeek(g, h, -(BIGINT)sizeof(vh), true);
+
+ vh.MaxRec = MaxBlk * Bsize;
+ vh.NumRec = (Block - 1) * Nrec + Last;
+
+ if (BigWrite(g, h, &vh, sizeof(vh))) {
+ sprintf(g->Message, "Error writing header file %s", filename);
+ rc = true;
+ } // endif fread
+
+ if (Header == 2 || Hfile == INVALID_HANDLE_VALUE)
+ CloseFileHandle(h);
+
+ return rc;
+ } // end of SetBlockInfo
+
+/***********************************************************************/
+/* VEC Create an empty file for new Vector formatted tables. */
+/***********************************************************************/
+bool BGVFAM::MakeEmptyFile(PGLOBAL g, PCSZ fn)
+ {
+ // Vector formatted file this will create an empty file of the
+ // required length if it does not exists yet.
+ char filename[_MAX_PATH], c = 0;
+ int n = (Header == 1 || Header == 3) ? sizeof(VECHEADER) : 0;
+
+ PlugSetPath(filename, fn, Tdbp->GetPath());
+
+#if defined(_WIN32)
+ PCSZ p;
+ DWORD rc;
+ bool brc;
+ LARGE_INTEGER of;
+ HANDLE h;
+
+ h = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ p = MSG(OPENING);
+ goto err;
+ } // endif h
+
+ of.QuadPart = (BIGINT)n + (BIGINT)MaxBlk * (BIGINT)Blksize - (BIGINT)1;
+
+ if (trace(1))
+ htrc("MEF: of=%lld n=%d maxblk=%d blksize=%d\n",
+ of.QuadPart, n, MaxBlk, Blksize);
+
+ of.LowPart = SetFilePointer(h, of.LowPart,
+ &of.HighPart, FILE_BEGIN);
+
+ if (of.LowPart == INVALID_SET_FILE_POINTER &&
+ GetLastError() != NO_ERROR) {
+ p = MSG(MAKING);
+ goto err;
+ } // endif
+
+ brc = WriteFile(h, &c, 1, &rc, NULL);
+
+ if (!brc || rc != 1) {
+ p = MSG(WRITING);
+ goto err;
+ } // endif
+
+ CloseHandle(h);
+ return false;
+
+ err:
+ rc = GetLastError();
+ sprintf(g->Message, MSG(EMPTY_FILE), p, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+
+ if (h != INVALID_HANDLE_VALUE)
+ CloseHandle(h);
+
+ return true;
+#else // !_WIN32
+ int h;
+ BIGINT pos;
+
+ h= open64(filename, O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
+
+ if (h == -1)
+ return true;
+
+ pos = (BIGINT)n + (BIGINT)MaxBlk * (BIGINT)Blksize - (BIGINT)1;
+
+ if (trace(1))
+ htrc("MEF: pos=%lld n=%d maxblk=%d blksize=%d\n",
+ pos, n, MaxBlk, Blksize);
+
+ if (lseek64(h, pos, SEEK_SET) < 0)
+ goto err;
+
+ // This actually fills the empty file
+ if (write(h, &c, 1) < 0)
+ goto err;
+
+ close(h);
+ return false;
+
+ err:
+ sprintf(g->Message, MSG(MAKE_EMPTY_FILE), To_File, strerror(errno));
+ close(h);
+ return true;
+#endif // !_WIN32
+ } // end of MakeEmptyFile
+
+/***********************************************************************/
+/* Vopen function: opens a file using Windows or Unix API's. */
+/***********************************************************************/
+bool BGVFAM::OpenTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool del = false;
+ MODE mode = Tdbp->GetMode();
+ PDBUSER dbuserp = PlgGetUser(g);
+
+ if ((To_Fb && To_Fb->Count) || Hfile != INVALID_HANDLE_VALUE) {
+ sprintf(g->Message, MSG(FILE_OPEN_YET), To_File);
+ return true;
+ } // endif
+
+ /*********************************************************************/
+ /* Update block info if necessary. */
+ /*********************************************************************/
+ if (Block < 0)
+ if ((Headlen = GetBlockInfo(g)) < 0)
+ return true;
+
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (trace(1))
+ htrc("OpenTableFile: filename=%s mode=%d Last=%d\n",
+ filename, mode, Last);
+
+#if defined(_WIN32)
+ DWORD access, creation, share = 0, rc = 0;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ access = GENERIC_READ;
+ share = FILE_SHARE_READ;
+ creation = OPEN_EXISTING;
+ break;
+ case MODE_INSERT:
+ if (MaxBlk) {
+ if (!Block)
+ if (MakeEmptyFile(g, To_File))
+ return true;
+
+ // Required to update empty blocks
+ access = GENERIC_READ | GENERIC_WRITE;
+ } else if (Last == Nrec)
+ access = GENERIC_WRITE;
+ else
+ // Required to update the last block
+ access = GENERIC_READ | GENERIC_WRITE;
+
+ creation = OPEN_ALWAYS;
+ break;
+ case MODE_DELETE:
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+
+ // This will stop the process by
+ // causing GetProgMax to return 0.
+// ResetTableSize(g, 0, Nrec); must be done later
+ del = true;
+
+ // This will delete the whole file
+ access = GENERIC_READ | GENERIC_WRITE;
+ creation = TRUNCATE_EXISTING;
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ case MODE_UPDATE:
+ if ((UseTemp = Tdbp->IsUsingTemp(g)))
+ access = GENERIC_READ;
+ else
+ access = GENERIC_READ | GENERIC_WRITE;
+
+ creation = OPEN_EXISTING;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch
+
+ /*********************************************************************/
+ /* Use specific Windows API functions. */
+ /*********************************************************************/
+ Hfile = CreateFile(filename, access, share, NULL, creation,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+ } // endif Hfile
+
+ if (trace(1))
+ htrc(" rc=%d access=%p share=%p creation=%d handle=%p fn=%s\n",
+ rc, access, share, creation, Hfile, filename);
+
+ if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode we must position the cursor at end of file. */
+ /*******************************************************************/
+ LARGE_INTEGER of;
+
+ of.QuadPart = (BIGINT)0;
+ of.LowPart = SetFilePointer(Hfile, of.LowPart,
+ &of.HighPart, FILE_END);
+
+ if (of.LowPart == INVALID_SET_FILE_POINTER &&
+ (rc = GetLastError()) != NO_ERROR) {
+ sprintf(g->Message, MSG(ERROR_IN_SFP), rc);
+ CloseHandle(Hfile);
+ Hfile = INVALID_HANDLE_VALUE;
+ } // endif
+
+ } // endif Mode
+
+#else // UNIX
+ /*********************************************************************/
+ /* The open() function has a transitional interface for 64-bit */
+ /* file offsets. Note that using open64() is equivalent to using */
+ /* open() with O_LARGEFILE set in oflag (see Xopen in tabfix.cpp). */
+ /*********************************************************************/
+ int rc = 0;
+ int oflag;
+ mode_t pmd = 0;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ oflag = O_RDONLY;
+ break;
+ case MODE_INSERT:
+ if (MaxBlk) {
+ if (!Block)
+ if (MakeEmptyFile(g, To_File))
+ return true;
+
+ // Required to update empty blocks
+ oflag = O_RDWR;
+ } else if (Last == Nrec)
+ oflag = O_WRONLY | O_CREAT | O_APPEND;
+ else
+ // Required to update the last block
+ oflag = O_RDWR | O_CREAT | O_APPEND;
+
+ pmd = S_IREAD | S_IWRITE;
+ break;
+ case MODE_DELETE:
+ // This is temporary until a partial delete is implemented
+ if (!Tdbp->GetNext()) {
+ // Store the number of deleted lines
+ DelRows = Cardinality(g);
+ del = true;
+
+ // This will delete the whole file and provoque ReadDB to
+ // return immediately.
+ oflag = O_RDWR | O_TRUNC;
+ strcpy(g->Message, MSG(NO_VCT_DELETE));
+ break;
+ } // endif
+
+ // Selective delete, pass thru
+ /* fall through */
+ case MODE_UPDATE:
+ UseTemp = Tdbp->IsUsingTemp(g);
+ oflag = (UseTemp) ? O_RDONLY : O_RDWR;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_OPEN_MODE), mode);
+ return true;
+ } // endswitch
+
+ Hfile = open64(filename, oflag, pmd); // Enable file size > 2G
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = errno;
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
+ strcat(g->Message, strerror(errno));
+ } // endif Hfile
+
+ if (trace(1))
+ htrc(" rc=%d oflag=%p mode=%p handle=%d fn=%s\n",
+ rc, oflag, mode, Hfile, filename);
+#endif // UNIX
+
+ if (!rc) {
+ if (!To_Fb) {
+ To_Fb = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ To_Fb->Fname = To_File;
+ To_Fb->Type = TYPE_FB_HANDLE;
+ To_Fb->Memory = NULL;
+ To_Fb->Length = 0;
+ To_Fb->File = NULL;
+ To_Fb->Next = dbuserp->Openlist;
+ dbuserp->Openlist = To_Fb;
+ } // endif To_Fb
+
+ To_Fb->Count = 1;
+ To_Fb->Mode = mode;
+ To_Fb->Handle = Hfile;
+
+ if (trace(1))
+ htrc("File %s is open in mode %d\n", filename, mode);
+
+ if (del)
+ // This will stop the process by
+ // causing GetProgMax to return 0.
+ return ResetTableSize(g, 0, Nrec);
+
+ /*********************************************************************/
+ /* Allocate the table and column block buffers. */
+ /*********************************************************************/
+ return AllocateBuffer(g);
+ } else
+ return (mode == MODE_READ && rc == ENOENT)
+ ? PushWarning(g, Tdbp) : true;
+
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* Allocate the block buffers for columns used in the query. */
+/***********************************************************************/
+bool BGVFAM::AllocateBuffer(PGLOBAL g)
+ {
+ MODE mode = Tdbp->GetMode();
+ PDOSDEF defp = (PDOSDEF)Tdbp->GetDef();
+ PCOLDEF cdp;
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ if (mode == MODE_INSERT) {
+ if (!NewBlock) {
+ // Not reopening after inserting the last block
+ bool chk = PlgGetUser(g)->Check & CHK_TYPE;
+
+ NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
+
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ memset(NewBlock + Nrec * cdp->GetPoff(),
+ (IsTypeNum(cdp->GetType()) ? 0 : ' '),
+ Nrec * cdp->GetClen());
+
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->Blk = AllocValBlock(g, NewBlock + Nrec * cp->Deplac,
+ cp->Buf_Type, Nrec, cp->Format.Length,
+ cp->Format.Prec, chk, true, cp->IsUnsigned());
+
+ InitInsert(g); // Initialize inserting
+
+ // Currently we don't use a temporary file for inserting
+ Tfile = Hfile;
+ } // endif NewBlock
+
+ } else {
+ if (UseTemp || mode == MODE_DELETE) {
+ // Allocate all that is needed to move lines
+ int i = 0;
+
+ if (!Ncol)
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ Ncol++;
+
+ if (MaxBlk)
+ BigDep = (BIGINT*)PlugSubAlloc(g, NULL, Ncol * sizeof(BIGINT));
+ else
+ Deplac = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+
+ Clens = (int*)PlugSubAlloc(g, NULL, Ncol * sizeof(int));
+ Isnum = (bool*)PlugSubAlloc(g, NULL, Ncol * sizeof(bool));
+
+ for (cdp = defp->GetCols(); cdp; i++, cdp = cdp->GetNext()) {
+ if (MaxBlk)
+ BigDep[i] = (BIGINT)Headlen
+ + (BIGINT)(cdp->GetPoff() * Nrec) * (BIGINT)MaxBlk;
+ else
+ Deplac[i] = cdp->GetPoff() * Nrec;
+
+ Clens[i] = cdp->GetClen();
+ Isnum[i] = IsTypeNum(cdp->GetType());
+ Buflen = MY_MAX(Buflen, cdp->GetClen());
+ } // endfor cdp
+
+ if (!UseTemp || MaxBlk) {
+ Buflen *= Nrec;
+ To_Buf = (char*)PlugSubAlloc(g, NULL, Buflen);
+ } else
+ NewBlock = (char*)PlugSubAlloc(g, NULL, Blksize);
+
+ } // endif mode
+
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ if (!cp->IsSpecial()) // Not a pseudo column
+ cp->Blk = AllocValBlock(g, NULL, cp->Buf_Type, Nrec,
+ cp->Format.Length, cp->Format.Prec,
+ true, true, cp->IsUnsigned());
+
+ } //endif mode
+
+ return false;
+ } // end of AllocateBuffer
+
+/***********************************************************************/
+/* Data Base write routine for huge VCT access method. */
+/***********************************************************************/
+int BGVFAM::WriteBuffer(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("BGV WriteDB: R%d Mode=%d CurNum=%d CurBlk=%d\n",
+ Tdbp->GetTdb_No(), Tdbp->GetMode(), CurNum, CurBlk);
+
+ if (Tdbp->GetMode() == MODE_UPDATE) {
+ // Mode Update is done in ReadDB, we just initialize it here
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ if (UseTemp) {
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ // Most of the time, not all table columns are updated.
+ // This why we must completely pre-fill the temporary file.
+ Fpos = (MaxBlk) ? (Block - 1) * Nrec + Last
+ : Block * Nrec; // To write last lock
+
+ if (MoveIntermediateLines(g))
+ return RC_FX;
+
+ } else
+ Tfile = Hfile;
+
+ } // endif Tfile
+
+ } else {
+ // Mode Insert
+ if (MaxBlk && CurBlk == MaxBlk) {
+ strcpy(g->Message, MSG(TRUNC_BY_ESTIM));
+ return RC_EF; // Too many lines for a Vector formatted table
+ } // endif MaxBlk
+
+ if (Closing || ++CurNum == Nrec) {
+ PVCTCOL cp = (PVCTCOL)Tdbp->GetColumns();
+
+ if (!AddBlock) {
+ // Write back the updated last block values
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ cp->WriteBlock(g);
+
+ if (!Closing && !MaxBlk) {
+ // Close the VCT file and reopen it in mode Insert
+//#if defined(_WIN32) //OB
+// CloseHandle(Hfile);
+//#else // UNIX
+// close(Hfile);
+//#endif // UNIX
+ CloseFileHandle(Hfile);
+ Hfile = INVALID_HANDLE_VALUE;
+ To_Fb->Count = 0;
+ Last = Nrec; // Tested in OpenTableFile
+
+ if (OpenTableFile(g)) {
+ Closing = true; // Tell CloseDB of error
+ return RC_FX;
+ } // endif Vopen
+
+ AddBlock = true;
+ } // endif Closing
+
+ } else {
+ // Here we must add a new block to the VCT file
+ if (Closing)
+ // Reset the overwritten columns for last block extra records
+ for (; cp; cp = (PVCTCOL)cp->Next)
+ memset(NewBlock + Nrec * cp->Deplac + Last * cp->Clen,
+ (cp->Buf_Type == TYPE_STRING) ? ' ' : '\0',
+ (Nrec - Last) * cp->Clen);
+
+ if (BigWrite(g, Hfile, NewBlock, Blksize))
+ return RC_FX;
+
+ } // endif AddBlock
+
+ if (!Closing) {
+ CurBlk++;
+ CurNum = 0;
+ } // endif Closing
+
+ } // endif
+
+ } // endif Mode
+
+ return RC_OK;
+ } // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for BGVFAM access method. */
+/***********************************************************************/
+int BGVFAM::DeleteRecords(PGLOBAL g, int irc)
+ {
+ bool eof = false;
+
+ /*********************************************************************/
+ /* There is an alternative here depending on UseTemp: */
+ /* 1 - use a temporary file in which are copied all not deleted */
+ /* lines, at the end the original file will be deleted and */
+ /* the temporary file renamed to the original file name. */
+ /* 2 - directly move the not deleted lines inside the original */
+ /* file, and at the end erase all trailing records. */
+ /*********************************************************************/
+ if (trace(1))
+ htrc("BGV DeleteDB: irc=%d UseTemp=%d Fpos=%d Tpos=%d Spos=%d\n",
+ irc, UseTemp, Fpos, Tpos, Spos);
+
+ if (irc != RC_OK) {
+ /*******************************************************************/
+ /* EOF: position Fpos at the end-of-file position. */
+ /*******************************************************************/
+ Fpos = (Block - 1) * Nrec + Last;
+
+ if (trace(1))
+ htrc("Fpos placed at file end=%d\n", Fpos);
+
+ eof = UseTemp && !MaxBlk;
+ } else // Fpos is the deleted line position
+ Fpos = CurBlk * Nrec + CurNum;
+
+ if (Tpos == Spos) {
+ if (UseTemp) {
+ /*****************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*****************************************************************/
+ if (OpenTempFile(g))
+ return RC_FX;
+
+ } else {
+ /*****************************************************************/
+ /* Move of eventual preceding lines is not required here. */
+ /* Set the target file as being the source file itself. */
+ /* Set the future Tpos, and give Spos a value to block copying. */
+ /*****************************************************************/
+ Tfile = Hfile;
+ Spos = Tpos = Fpos;
+ } // endif UseTemp
+
+ } // endif Tpos == Spos
+
+ /*********************************************************************/
+ /* Move any intermediate lines. */
+ /*********************************************************************/
+ if (MoveIntermediateLines(g, &eof))
+ return RC_FX;
+
+ if (irc == RC_OK) {
+#ifdef _DEBUG
+ assert(Spos == Fpos);
+#endif
+ Spos++; // New start position is on next line
+
+ if (trace(1))
+ htrc("after: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } else {
+ /*******************************************************************/
+ /* Last call after EOF has been reached. */
+ /*******************************************************************/
+ Block = (Tpos > 0) ? (Tpos + Nrec - 1) / Nrec : 0;
+ Last = (Tpos + Nrec - 1) % Nrec + 1;
+
+ if (!UseTemp) { // The UseTemp case is treated in CloseTableFile
+ if (!MaxBlk) {
+ if (Last < Nrec) // Clean last block
+ if (CleanUnusedSpace(g))
+ return RC_FX;
+
+ /***************************************************************/
+ /* Remove extra records. */
+ /***************************************************************/
+#if defined(_WIN32)
+ BIGINT pos = (BIGINT)Block * (BIGINT)Blksize;
+
+ if (BigSeek(g, Hfile, pos))
+ return RC_FX;
+
+ if (!SetEndOfFile(Hfile)) {
+ DWORD drc = GetLastError();
+
+ sprintf(g->Message, MSG(SETEOF_ERROR), drc);
+ return RC_FX;
+ } // endif error
+#else // !_WIN32
+ if (ftruncate64(Hfile, (BIGINT)(Tpos * Lrecl))) {
+ sprintf(g->Message, MSG(TRUNCATE_ERROR), strerror(errno));
+ return RC_FX;
+ } // endif
+#endif // !_WIN32
+ } else // MaxBlk
+ // Clean the unused space in the file, this is required when
+ // inserting again with a partial column list.
+ if (CleanUnusedSpace(g))
+ return RC_FX;
+
+ if (ResetTableSize(g, Block, Last))
+ return RC_FX;
+
+ } // endif UseTemp
+
+ } // endif irc
+
+ return RC_OK; // All is correct
+ } // end of DeleteRecords
+
+/***********************************************************************/
+/* Open a temporary file used while updating or deleting. */
+/***********************************************************************/
+bool BGVFAM::OpenTempFile(PGLOBAL g)
+ {
+ char *tempname;
+ PDBUSER dup = PlgGetUser(g);
+
+ /*********************************************************************/
+ /* Open the temporary file, Spos is at the beginning of file. */
+ /*********************************************************************/
+ tempname = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+ PlugSetPath(tempname, To_File, Tdbp->GetPath());
+ strcat(PlugRemoveType(tempname, tempname), ".t");
+
+ if (!MaxBlk)
+ remove(tempname); // Be sure it does not exist yet
+ else if (MakeEmptyFile(g, tempname))
+ return true;
+
+#if defined(_WIN32)
+ DWORD access = (MaxBlk) ? OPEN_EXISTING : CREATE_NEW;
+
+ Tfile = CreateFile(tempname, GENERIC_WRITE, 0, NULL,
+ access, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_DELETE, tempname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)tempname, _MAX_PATH, NULL);
+ strcat(g->Message, tempname);
+ return true;
+ } // endif Tfile
+#else // UNIX
+ int oflag = (MaxBlk) ? O_WRONLY : O_WRONLY | O_TRUNC;
+
+ Tfile = open64(tempname, oflag, S_IWRITE);
+
+ if (Tfile == INVALID_HANDLE_VALUE) {
+ int rc = errno;
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, MODE_INSERT, tempname);
+ strcat(g->Message, strerror(errno));
+ return true;
+ } //endif Tfile
+#endif // UNIX
+
+ To_Fbt = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ To_Fbt->Fname = tempname;
+ To_Fbt->Type = TYPE_FB_HANDLE;
+ To_Fbt->Memory = NULL;
+ To_Fbt->Length = 0;
+ To_Fbt->File = NULL;
+ To_Fbt->Next = dup->Openlist;
+ To_Fbt->Count = 1;
+ To_Fbt->Mode = MODE_INSERT;
+ To_Fbt->Handle = Tfile;
+ dup->Openlist = To_Fbt;
+ return false;
+ } // end of OpenTempFile
+
+/***********************************************************************/
+/* Move intermediate deleted or updated lines. */
+/***********************************************************************/
+bool BGVFAM::MoveIntermediateLines(PGLOBAL g, bool *b)
+ {
+ int i, n, req, dep;
+ bool eof = (b) ? *b : false;
+ BIGINT pos;
+
+ for (n = Fpos - Spos; n > 0 || eof; n -= req) {
+ /*******************************************************************/
+ /* Non consecutive line to delete. Move intermediate lines. */
+ /*******************************************************************/
+ if (!MaxBlk)
+ req = (DWORD)MY_MIN(n, Nrec - MY_MAX(Spos % Nrec, Tpos % Nrec));
+ else
+ req = (DWORD)MY_MIN(n, Nrec);
+
+ if (req) for (i = 0; i < Ncol; i++) {
+ if (!MaxBlk) {
+ if (UseTemp)
+ To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
+
+ pos = (BIGINT)Deplac[i] + (BIGINT)((Spos % Nrec) * Clens[i])
+ + (BIGINT)(Spos / Nrec) * (BIGINT)Blksize;
+ } else
+ pos = BigDep[i] + (BIGINT)Spos * (BIGINT)Clens[i];
+
+ if (BigSeek(g, Hfile, pos))
+ return true;
+
+ if (BigRead(g, Hfile, To_Buf, req * Clens[i]))
+ return true;
+
+ if (!UseTemp || MaxBlk) {
+ if (!MaxBlk)
+ pos = (BIGINT)Deplac[i] + (BIGINT)((Tpos % Nrec) * Clens[i])
+ + (BIGINT)(Tpos / Nrec) * (BIGINT)Blksize;
+ else
+ pos = BigDep[i] + (BIGINT)Tpos * (BIGINT)Clens[i];
+
+ if (BigSeek(g, Tfile, pos))
+ return true;
+
+ if (BigWrite(g, Tfile, To_Buf, req * Clens[i]))
+ return true;
+
+ } // endif UseTemp
+
+ } // endfor i
+
+ Tpos += (int)req;
+ Spos += (int)req;
+
+ if (UseTemp && !MaxBlk && (!(Tpos % Nrec) || (eof && Spos == Fpos))) {
+ // Write the full or last block to the temporary file
+ if ((dep = Nrec - (Tpos % Nrec)) < Nrec)
+ // Clean the last block in case of future insert, must be
+ // done here because Tfile was open in write only.
+ for (i = 0; i < Ncol; i++) {
+ To_Buf = NewBlock + Deplac[i] + (Tpos % Nrec) * Clens[i];
+ memset(To_Buf, (Isnum[i]) ? 0 : ' ', dep * Clens[i]);
+ } // endfor i
+
+ if (BigWrite(g, Tfile, NewBlock, Blksize))
+ return true;
+
+ if (Spos == Fpos)
+ eof = false;
+
+ } // endif Usetemp...
+
+ if (trace(1))
+ htrc("loop: Tpos=%d Spos=%d\n", Tpos, Spos);
+
+ } // endfor n
+
+ return false;
+ } // end of MoveIntermediateLines
+
+/***********************************************************************/
+/* Clean deleted space in a huge VCT or Vec table file. */
+/***********************************************************************/
+bool BGVFAM::CleanUnusedSpace(PGLOBAL g)
+ {
+ int i;
+ int n;
+ BIGINT pos, dep;
+
+ if (!MaxBlk) {
+ /*******************************************************************/
+ /* Clean last block of the VCT table file. */
+ /*******************************************************************/
+ assert(!UseTemp); // This case is handled in MoveIntermediateLines
+
+ if (!(n = Nrec - Last))
+ return false;
+
+ dep = (BIGINT)((Block - 1) * Blksize);
+
+ for (i = 0; i < Ncol; i++) {
+ memset(To_Buf, (Isnum[i]) ? 0 : ' ', n * Clens[i]);
+ pos = dep + (BIGINT)(Deplac[i] + Last * Clens[i]);
+
+ if (BigSeek(g, Hfile, pos))
+ return true;
+
+ if (BigWrite(g, Hfile, To_Buf, n * Clens[i]))
+ return true;
+
+ } // endfor i
+
+ } else {
+ int req;
+
+ if (To_Buf)
+ memset(To_Buf, 0, Buflen);
+
+ for (n = Fpos - Tpos; n > 0; n -= req) {
+ /*****************************************************************/
+ /* Fill VEC file remaining lines with 0's. */
+ /* This seems to work even column blocks have been made with */
+ /* Blanks = true. Perhaps should it be set to false for VEC. */
+ /*****************************************************************/
+ req = MY_MIN(n, Nrec);
+
+ for (i = 0; i < Ncol; i++) {
+ pos = BigDep[i] + (BIGINT)Tpos * (BIGINT)Clens[i];
+
+ if (BigSeek(g, Tfile, pos))
+ return true;
+
+ if (BigWrite(g, Tfile, To_Buf, req * Clens[i]))
+ return true;
+
+ } // endfor i
+
+ Tpos += req;
+ } // endfor n
+
+ } // endif MaxBlk
+
+ return false;
+ } // end of CleanUnusedSpace
+
+/***********************************************************************/
+/* Data Base close routine for huge VEC access method. */
+/***********************************************************************/
+void BGVFAM::CloseTableFile(PGLOBAL g, bool abort)
+ {
+ int rc = 0, wrc = RC_OK;
+ MODE mode = Tdbp->GetMode();
+
+ Abort = abort;
+
+ if (mode == MODE_INSERT) {
+ if (Closing)
+ wrc = RC_FX; // Last write was in error
+ else
+ if (CurNum) {
+ // Some more inserted lines remain to be written
+ Last = CurNum;
+ Block = CurBlk + 1;
+ Closing = true;
+ wrc = WriteBuffer(g);
+ } else {
+ Last = Nrec;
+ Block = CurBlk;
+ wrc = RC_OK;
+ } // endif CurNum
+
+ if (wrc != RC_FX) {
+ rc = ResetTableSize(g, Block, Last);
+ } else if (AddBlock) {
+ // Last block was not written
+ rc = ResetTableSize(g, CurBlk, Nrec);
+ throw 44;
+ } // endif
+
+ } else if (mode == MODE_UPDATE) {
+ // Write back to file any pending modifications
+ for (PVCTCOL colp = (PVCTCOL)((PTDBVCT)Tdbp)->GetSetCols();
+ colp; colp = (PVCTCOL)colp->Next)
+ colp->WriteBlock(g);
+
+ if (UseTemp && Tfile) {
+ rc = RenameTempFile(g);
+ Hfile = Tfile = INVALID_HANDLE_VALUE;
+
+ if (Header)
+ // Header must be set because it was not set in temp file
+ rc = SetBlockInfo(g);
+
+ } // endif UseTemp
+
+ } else if (mode == MODE_DELETE && UseTemp && Tfile) {
+ if (MaxBlk)
+ rc = CleanUnusedSpace(g);
+
+ if ((rc = RenameTempFile(g)) != RC_FX) {
+ Hfile = Tfile = INVALID_HANDLE_VALUE; // For SetBlockInfo
+ rc = ResetTableSize(g, Block, Last);
+ } // endif rc
+
+ } // endif's mode
+
+ if (Hfile != INVALID_HANDLE_VALUE)
+ rc = PlugCloseFile(g, To_Fb);
+
+ if (trace(1))
+ htrc("BGV CloseTableFile: closing %s wrc=%d rc=%d\n",
+ To_File, wrc, rc);
+
+ Hfile = INVALID_HANDLE_VALUE;
+ } // end of CloseDB
+
+/***********************************************************************/
+/* Rewind routine for huge VCT access method. */
+/***********************************************************************/
+void BGVFAM::Rewind(void)
+ {
+ // In mode update we need to read Set Column blocks
+ if (Tdbp->GetMode() == MODE_UPDATE)
+ OldBlk = -1;
+
+ // Initialize so block optimization is called for 1st block
+ CurBlk = -1;
+ CurNum = Nrec - 1;
+
+#if 0 // This is probably unuseful as the file is directly accessed
+#if defined(_WIN32) //OB
+ SetFilePointer(Hfile, 0, NULL, FILE_BEGIN);
+#else // UNIX
+ lseek64(Hfile, 0, SEEK_SET);
+#endif // UNIX
+#endif // 0
+ } // end of Rewind
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+bool BGVFAM::ReadBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ BIGINT pos;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to read. */
+ /*********************************************************************/
+ if (MaxBlk) // File has Vector format
+ pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac * (BIGINT)MaxBlk
+ + (BIGINT)colp->Clen * (BIGINT)CurBlk) + (BIGINT)Headlen;
+ else // Old VCT format
+ pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac
+ + (BIGINT)Lrecl * (BIGINT)CurBlk);
+
+ if (trace(1))
+ htrc("RB: offset=%lld Nrec=%d Deplac=%d Lrecl=%d CurBlk=%d MaxBlk=%d\n",
+ pos, Nrec, colp->Deplac, Lrecl, CurBlk, MaxBlk);
+
+ if (BigSeek(g, Hfile, pos))
+ return true;
+
+ if (BigRead(g, Hfile, colp->Blk->GetValPointer(), colp->Clen * Nrec))
+ return true;
+
+ if (trace(1))
+ num_read++;
+
+ return false;
+ } // end of ReadBlock
+
+/***********************************************************************/
+/* WriteBlock: Write back current column values for one block. */
+/* Note: the test of Status is meant to prevent physical writing of */
+/* the block during the checking loop in mode Update. It is set to */
+/* BUF_EMPTY when reopening the table between the two loops. */
+/***********************************************************************/
+bool BGVFAM::WriteBlock(PGLOBAL g, PVCTCOL colp)
+ {
+ int len;
+ BIGINT pos;
+
+ /*********************************************************************/
+ /* Calculate the offset and size of the block to write. */
+ /*********************************************************************/
+ if (MaxBlk) // File has Vector format
+ pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac * (BIGINT)MaxBlk
+ + (BIGINT)colp->Clen * (BIGINT)colp->ColBlk) + (BIGINT)Headlen;
+ else // Old VCT format
+ pos = (BIGINT)Nrec * ((BIGINT)colp->Deplac
+ + (BIGINT)Lrecl * (BIGINT)colp->ColBlk);
+
+ if (trace(1))
+ htrc("WB: offset=%lld Nrec=%d Deplac=%d Lrecl=%d ColBlk=%d\n",
+ pos, Nrec, colp->Deplac, Lrecl, colp->ColBlk);
+
+ if (BigSeek(g, Tfile, pos))
+ return true;
+
+//len = colp->Clen * Nrec; see comment in VCTFAM
+ len = colp->Clen * ((Tdbp->GetMode() == MODE_INSERT) ? CurNum : Nrec);
+
+ if (BigWrite(g, Tfile, colp->Blk->GetValPointer(), len))
+ return true;
+
+ return false;
+ } // end of WriteBlock
+
+/* ----------------------- End of FilAMVct --------------------------- */
diff --git a/storage/connect/filamvct.h b/storage/connect/filamvct.h
new file mode 100644
index 00000000..85982403
--- /dev/null
+++ b/storage/connect/filamvct.h
@@ -0,0 +1,252 @@
+/************** FilAMVct H Declares Source Code File (.H) **************/
+/* Name: FILAMVCT.H Version 1.5 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2012 */
+/* */
+/* This file contains the VCT file access method classes declares. */
+/***********************************************************************/
+#ifndef __FILAMVCT__
+#define __FILAMVCT__
+
+#include "filamfix.h"
+
+typedef class VCTFAM *PVCTFAM;
+typedef class VCTCOL *PVCTCOL;
+typedef class VCMFAM *PVCMFAM;
+typedef class VECFAM *PVECFAM;
+typedef class VMPFAM *PVMPFAM;
+typedef class BGVFAM *PBGVFAM;
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* in vector format. If MaxBlk=0, each block containing "Elements" */
+/* records, values of each columns are consecutively stored (vector). */
+/* Otherwise, data is arranged by column in the file and MaxBlk is */
+/* used to set the maximum number of blocks. This leave some white */
+/* space allowing to insert new values up to this maximum size. */
+/***********************************************************************/
+class DllExport VCTFAM : public FIXFAM {
+ friend class TDBVCT;
+ friend class VCTCOL;
+ public:
+ // Constructor
+ VCTFAM(PVCTDEF tdp);
+ VCTFAM(PVCTFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_VCT;}
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) VCTFAM(this);}
+ virtual int GetFileLength(PGLOBAL g);
+
+ // Methods
+ virtual void Reset(void);
+ virtual int MaxBlkSize(PGLOBAL g, int s);
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual bool InitInsert(PGLOBAL g);
+ virtual void ResetBuffer(PGLOBAL g) {}
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetRowID(void);
+
+ // Database routines
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ // Specific functions
+ virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
+ virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
+
+ protected:
+ virtual bool MakeEmptyFile(PGLOBAL g, PCSZ fn);
+ virtual bool OpenTempFile(PGLOBAL g);
+ virtual bool MoveLines(PGLOBAL g) {return false;}
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
+ virtual bool CleanUnusedSpace(PGLOBAL g);
+ virtual int GetBlockInfo(PGLOBAL g);
+ virtual bool SetBlockInfo(PGLOBAL g);
+ bool ResetTableSize(PGLOBAL g, int block, int last);
+
+ // Members
+ char *NewBlock; // To block written on Insert
+ char *Colfn; // Pattern for column file names (VEC)
+ char *Tempat; // Pattern for temp file names (VEC)
+ int *Clens; // Pointer to col size array
+ int *Deplac; // Pointer to col start position array
+ bool *Isnum; // Pointer to buffer type isnum result
+ bool AddBlock; // True when adding new blocks on Insert
+ bool Split; // true: split column file vector format
+ int Header; // 0: no, 1: separate, 2: in data file
+ int MaxBlk; // Max number of blocks (True vector format)
+ int Bsize; // Because Nrec can be modified
+ int Ncol; // The number of columns;
+ }; // end of class VCTFAM
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* in vector format accessed using file mapping. */
+/***********************************************************************/
+class DllExport VCMFAM : public VCTFAM {
+ friend class TDBVCT;
+ friend class VCTCOL;
+ public:
+ // Constructor
+ VCMFAM(PVCTDEF tdp);
+ VCMFAM(PVCMFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_VMP;}
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) VCMFAM(this);}
+
+ // Methods
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual bool InitInsert(PGLOBAL g);
+
+ // Database routines
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+
+ protected:
+ // Specific functions
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
+ virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
+ virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
+
+ // Members
+ char* Memory; // Pointer on file mapping view.
+ char* *Memcol; // Pointer on column start.
+ }; // end of class VCMFAM
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* in full vertical format. Each column is contained in a separate */
+/* file whose name is the table name followed by the column number. */
+/***********************************************************************/
+class DllExport VECFAM : public VCTFAM {
+ friend class TDBVCT;
+ friend class VCTCOL;
+ public:
+ // Constructor
+ VECFAM(PVCTDEF tdp);
+ VECFAM(PVECFAM txfp);
+
+ // Implementation
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) VECFAM(this);}
+
+ // Methods
+ virtual bool AllocateBuffer(PGLOBAL g);
+ virtual bool InitInsert(PGLOBAL g);
+ virtual void ResetBuffer(PGLOBAL g);
+
+ // Database routines
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+
+ // Specific functions
+ virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
+ virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
+
+ protected:
+ virtual bool OpenTempFile(PGLOBAL g);
+ virtual bool MoveLines(PGLOBAL g);
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
+ virtual int RenameTempFile(PGLOBAL g);
+ bool OpenColumnFile(PGLOBAL g, PCSZ opmode, int i);
+
+ // Members
+ FILE* *Streams; // Points to Dos file structure array
+ FILE* *T_Streams; // Points to temp file structure array
+ PFBLOCK *To_Fbs; // Pointer to file block array
+ PFBLOCK *T_Fbs; // Pointer to temp file block array
+ void* *To_Bufs; // Pointer to col val block array
+ bool InitUpdate; // Used to initialize updating
+ }; // end of class VECFAM
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* in full vertical format accessed using file mapping. */
+/***********************************************************************/
+class DllExport VMPFAM : public VCMFAM {
+ friend class TDBVCT;
+ friend class VCTCOL;
+ public:
+ // Constructor
+ VMPFAM(PVCTDEF tdp);
+ VMPFAM(PVMPFAM txfp);
+
+ // Implementation
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) VMPFAM(this);}
+
+ // Methods
+ virtual bool AllocateBuffer(PGLOBAL g);
+
+ // Database routines
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+
+ protected:
+ bool MapColumnFile(PGLOBAL g, MODE mode, int i);
+
+ // Members
+ PFBLOCK *To_Fbs; // Pointer to file block array
+ }; // end of class VMPFAM
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* in (possibly blocked) vector format that can be larger than 2GB. */
+/***********************************************************************/
+class BGVFAM : public VCTFAM {
+ friend class VCTCOL;
+ public:
+ // Constructors
+ BGVFAM(PVCTDEF tdp);
+ BGVFAM(PBGVFAM txfp);
+
+ // Implementation
+ virtual PTXF Duplicate(PGLOBAL g)
+ {return (PTXF)new(g) BGVFAM(this);}
+
+ // Methods
+ virtual bool AllocateBuffer(PGLOBAL g);
+
+ // Database routines
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+ // Specific functions
+ virtual bool ReadBlock(PGLOBAL g, PVCTCOL colp);
+ virtual bool WriteBlock(PGLOBAL g, PVCTCOL colp);
+
+ protected:
+ bool BigSeek(PGLOBAL g, HANDLE h, BIGINT pos, bool b = false);
+ bool BigRead(PGLOBAL g, HANDLE h, void *inbuf, int req);
+ bool BigWrite(PGLOBAL g, HANDLE h, void *inbuf, int req);
+ virtual bool MakeEmptyFile(PGLOBAL g, PCSZ fn);
+ virtual bool OpenTempFile(PGLOBAL g);
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b = NULL);
+ virtual bool CleanUnusedSpace(PGLOBAL g);
+ virtual bool SetBlockInfo(PGLOBAL g);
+ virtual int GetBlockInfo(PGLOBAL g);
+
+ // Members
+ HANDLE Hfile; // Handle to big file
+ HANDLE Tfile; // Handle to temporary file
+ BIGINT *BigDep; // Pointer to col start position array
+ }; // end of class BGVFAM
+
+#endif // __FILAMVCT__
+
diff --git a/storage/connect/filamzip.cpp b/storage/connect/filamzip.cpp
new file mode 100644
index 00000000..77a97b95
--- /dev/null
+++ b/storage/connect/filamzip.cpp
@@ -0,0 +1,1454 @@
+/*********** File AM Zip C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: FILAMZIP */
+/* ------------- */
+/* Version 1.4 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2016-2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the ZIP file access method classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if !defined(_WIN32)
+#if defined(UNIX)
+#include <fnmatch.h>
+#include <errno.h>
+#include <dirent.h>
+#include <unistd.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !_WIN32
+#include <time.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "osutil.h"
+#include "filamtxt.h"
+#include "tabfmt.h"
+//#include "tabzip.h"
+#include "filamzip.h"
+
+#define WRITEBUFFERSIZE (16384)
+
+/****************************************************************************/
+/* Definitions used for DBF tables. */
+/****************************************************************************/
+#define HEADLEN 32 /* sizeof ( mainhead or thisfield ) */
+//efine MEMOLEN 10 /* length of memo field in .dbf */
+#define DBFTYPE 3 /* value of bits 0 and 1 if .dbf */
+#define EOH 0x0D /* end-of-header marker in .dbf file */
+
+/****************************************************************************/
+/* First 32 bytes of a DBF table. */
+/* Note: some reserved fields are used here to store info (Fields) */
+/****************************************************************************/
+typedef struct _dbfheader {
+ uchar Version; /* Version information flags */
+ char Filedate[3]; /* date, YYMMDD, binary. YY=year-1900 */
+private:
+ /* The following four members are stored in little-endian format on disk */
+ char m_RecordsBuf[4]; /* records in the file */
+ char m_HeadlenBuf[2]; /* bytes in the header */
+ char m_ReclenBuf[2]; /* bytes in a record */
+ char m_FieldsBuf[2]; /* Reserved but used to store fields */
+public:
+ char Incompleteflag; /* 01 if incomplete, else 00 */
+ char Encryptflag; /* 01 if encrypted, else 00 */
+ char Reserved2[12]; /* for LAN use */
+ char Mdxflag; /* 01 if production .mdx, else 00 */
+ char Language; /* Codepage */
+ char Reserved3[2];
+
+ uint Records(void) const { return uint4korr(m_RecordsBuf); }
+ ushort Headlen(void) const { return uint2korr(m_HeadlenBuf); }
+ ushort Reclen(void) const { return uint2korr(m_ReclenBuf); }
+ ushort Fields(void) const { return uint2korr(m_FieldsBuf); }
+
+ void SetHeadlen(ushort num) { int2store(m_HeadlenBuf, num); }
+ void SetReclen(ushort num) { int2store(m_ReclenBuf, num); }
+ void SetFields(ushort num) { int2store(m_FieldsBuf, num); }
+} DBFHEADER;
+
+/****************************************************************************/
+/* Column field descriptor of a .dbf file. */
+/****************************************************************************/
+typedef struct _descriptor {
+ char Name[11]; /* field name, in capitals, null filled*/
+ char Type; /* field type, C, D, F, L, M or N */
+ uint Offset; /* used in memvars, not in files. */
+ uchar Length; /* field length */
+ uchar Decimals; /* number of decimal places */
+ short Reserved4;
+ char Workarea; /* ??? */
+ char Reserved5[2];
+ char Setfield; /* ??? */
+ char Reserved6[7];
+ char Mdxfield; /* 01 if tag field in production .mdx */
+} DESCRIPTOR;
+
+bool ZipLoadFile(PGLOBAL g, PCSZ zfn, PCSZ fn, PCSZ entry, bool append, bool mul);
+
+/***********************************************************************/
+/* Compress a file in zip when creating a table. */
+/***********************************************************************/
+static bool ZipFile(PGLOBAL g, ZIPUTIL *zutp, PCSZ fn, PCSZ entry, char *buf)
+{
+ int rc = RC_OK, size_read, size_buf = WRITEBUFFERSIZE;
+ FILE *fin;
+
+ if (zutp->addEntry(g, entry))
+ return true;
+ else if (!(fin = fopen(fn, "rb"))) {
+ sprintf(g->Message, "error in opening %s for reading", fn);
+ return true;
+ } // endif fin
+
+ do {
+ size_read = (int)fread(buf, 1, size_buf, fin);
+
+ if (size_read < size_buf && feof(fin) == 0) {
+ sprintf(g->Message, "error in reading %s", fn);
+ rc = RC_FX;
+ } // endif size_read
+
+ if (size_read > 0) {
+ rc = zutp->writeEntry(g, buf, size_read);
+
+ if (rc == RC_FX)
+ sprintf(g->Message, "error in writing %s in the zipfile", fn);
+
+ } // endif size_read
+
+ } while (rc == RC_OK && size_read > 0);
+
+ fclose(fin);
+ zutp->closeEntry();
+ return rc != RC_OK;
+} // end of ZipFile
+
+/***********************************************************************/
+/* Find and Compress several files in zip when creating a table. */
+/***********************************************************************/
+static bool ZipFiles(PGLOBAL g, ZIPUTIL *zutp, PCSZ pat, char *buf)
+{
+ char filename[_MAX_PATH];
+
+ /*********************************************************************/
+ /* pat is a multiple file name with wildcard characters */
+ /*********************************************************************/
+ strcpy(filename, pat);
+
+#if defined(_WIN32)
+ int rc;
+ char drive[_MAX_DRIVE], direc[_MAX_DIR];
+ WIN32_FIND_DATA FileData;
+ HANDLE hSearch;
+
+ _splitpath(filename, drive, direc, NULL, NULL);
+
+ // Start searching files in the target directory.
+ hSearch = FindFirstFile(filename, &FileData);
+
+ if (hSearch == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+
+ if (rc != ERROR_FILE_NOT_FOUND) {
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), 0, (LPTSTR)&filename, sizeof(filename), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
+ return true;
+ } else {
+ strcpy(g->Message, "Cannot find any file to load");
+ return true;
+ } // endif rc
+
+ } // endif hSearch
+
+ while (true) {
+ if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ strcat(strcat(strcpy(filename, drive), direc), FileData.cFileName);
+
+ if (ZipFile(g, zutp, filename, FileData.cFileName, buf)) {
+ FindClose(hSearch);
+ return true;
+ } // endif ZipFile
+
+ } // endif dwFileAttributes
+
+ if (!FindNextFile(hSearch, &FileData)) {
+ rc = GetLastError();
+
+ if (rc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
+ FindClose(hSearch);
+ return true;
+ } // endif rc
+
+ break;
+ } // endif FindNextFile
+
+ } // endwhile n
+
+ // Close the search handle.
+ if (!FindClose(hSearch)) {
+ strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
+ return true;
+ } // endif FindClose
+
+#else // !_WIN32
+ struct stat fileinfo;
+ char fn[FN_REFLEN], direc[FN_REFLEN], pattern[FN_HEADLEN], ftype[FN_EXTLEN];
+ DIR *dir;
+ struct dirent *entry;
+
+ _splitpath(filename, NULL, direc, pattern, ftype);
+ strcat(pattern, ftype);
+
+ // Start searching files in the target directory.
+ if (!(dir = opendir(direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), direc, strerror(errno));
+ return true;
+ } // endif dir
+
+ while ((entry = readdir(dir))) {
+ strcat(strcpy(fn, direc), entry->d_name);
+
+ if (lstat(fn, &fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", fn, strerror(errno));
+ return true;
+ } else if (!S_ISREG(fileinfo.st_mode))
+ continue; // Not a regular file (should test for links)
+
+ /*******************************************************************/
+ /* Test whether the file name matches the table name filter. */
+ /*******************************************************************/
+ if (fnmatch(pattern, entry->d_name, 0))
+ continue; // Not a match
+
+ strcat(strcpy(filename, direc), entry->d_name);
+
+ if (ZipFile(g, zutp, filename, entry->d_name, buf)) {
+ closedir(dir);
+ return true;
+ } // endif ZipFile
+
+ } // endwhile readdir
+
+ // Close the dir handle.
+ closedir(dir);
+#endif // !_WIN32
+
+ return false;
+} // end of ZipFiles
+
+/***********************************************************************/
+/* Load and Compress a file in zip when creating a table. */
+/***********************************************************************/
+bool ZipLoadFile(PGLOBAL g, PCSZ zfn, PCSZ fn, PCSZ entry, bool append, bool mul)
+{
+ char *buf;
+ bool err;
+ ZIPUTIL *zutp = new(g) ZIPUTIL(NULL);
+
+ if (zutp->open(g, zfn, append))
+ return true;
+
+ buf = (char*)PlugSubAlloc(g, NULL, WRITEBUFFERSIZE);
+
+ if (!mul) {
+ PCSZ entp;
+
+ if (!entry) { // entry defaults to the file name
+ char* p = strrchr((char*)fn, '/');
+#if defined(_WIN32)
+ if (!p) p = strrchr((char*)fn, '\\');
+#endif // _WIN32
+ entp = (p) ? p + 1 : entry;
+ } else
+ entp = entry;
+
+ err = ZipFile(g, zutp, fn, entp, buf);
+ } else
+ err = ZipFiles(g, zutp, fn, buf);
+
+ zutp->close();
+ return err;
+} // end of ZipLoadFile
+
+/* -------------------------- class ZIPUTIL -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+ZIPUTIL::ZIPUTIL(PCSZ tgt)
+{
+ zipfile = NULL;
+ target = tgt;
+ pwd = NULL;
+ fp = NULL;
+ entryopen = false;
+} // end of ZIPUTIL standard constructor
+
+#if 0
+ZIPUTIL::ZIPUTIL(ZIPUTIL *zutp)
+{
+ zipfile = zutp->zipfile;
+ target = zutp->target;
+ pwd = zutp->pwd;
+ fp = zutp->fp;
+ entryopen = zutp->entryopen;
+} // end of UNZIPUTL copy constructor
+#endif // 0
+
+/***********************************************************************/
+/* Fill the zip time structure */
+/* param: tmZip time structure to be filled */
+/***********************************************************************/
+void ZIPUTIL::getTime(tm_zip& tmZip)
+{
+ time_t rawtime;
+ time(&rawtime);
+ struct tm *timeinfo = localtime(&rawtime);
+ tmZip.tm_sec = timeinfo->tm_sec;
+ tmZip.tm_min = timeinfo->tm_min;
+ tmZip.tm_hour = timeinfo->tm_hour;
+ tmZip.tm_mday = timeinfo->tm_mday;
+ tmZip.tm_mon = timeinfo->tm_mon;
+ tmZip.tm_year = timeinfo->tm_year;
+} // end of getTime
+
+/***********************************************************************/
+/* open a zip file for deflate. */
+/* param: filename path and the filename of the zip file to open. */
+/* append: set true to append the zip file */
+/* return: true if open, false otherwise. */
+/***********************************************************************/
+bool ZIPUTIL::open(PGLOBAL g, PCSZ filename, bool append)
+{
+ if (!zipfile && !(zipfile = zipOpen64(filename,
+ append ? APPEND_STATUS_ADDINZIP
+ : APPEND_STATUS_CREATE)))
+ sprintf(g->Message, "Zipfile open error on %s", filename);
+
+ return (zipfile == NULL);
+} // end of open
+
+/***********************************************************************/
+/* Close the zip file. */
+/***********************************************************************/
+void ZIPUTIL::close()
+{
+ if (zipfile) {
+ closeEntry();
+ zipClose(zipfile, 0);
+ zipfile = NULL;
+ } // endif zipfile
+
+ if (fp)
+ fp->Count = 0;
+
+} // end of close
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */
+/***********************************************************************/
+bool ZIPUTIL::OpenTable(PGLOBAL g, MODE mode, PCSZ fn, bool append)
+{
+ /*********************************************************************/
+ /* The file will be compressed. */
+ /*********************************************************************/
+ if (mode == MODE_INSERT) {
+ bool b = open(g, fn, append);
+
+ if (!b) {
+ if (addEntry(g, target))
+ return true;
+
+ /*****************************************************************/
+ /* Link a Fblock. This make possible to automatically close it */
+ /* in case of error g->jump. */
+ /*****************************************************************/
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ fp->Type = TYPE_FB_ZIP;
+ fp->Fname = PlugDup(g, fn);
+ fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = fp;
+ fp->Count = 1;
+ fp->Length = 0;
+ fp->Memory = NULL;
+ fp->Mode = mode;
+ fp->File = this;
+ fp->Handle = 0;
+ } else
+ return true;
+
+ } else {
+ strcpy(g->Message, "Only INSERT mode supported for ZIPPING files");
+ return true;
+ } // endif mode
+
+ return false;
+} // end of OpenTableFile
+
+/***********************************************************************/
+/* Add target in zip file. */
+/***********************************************************************/
+bool ZIPUTIL::addEntry(PGLOBAL g, PCSZ entry)
+{
+ //?? we dont need the stinking time
+ zip_fileinfo zi = { {0, 0, 0, 0, 0, 0}, 0, 0, 0 };
+
+ getTime(zi.tmz_date);
+ target = entry;
+
+ int err = zipOpenNewFileInZip(zipfile, target, &zi,
+ NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
+
+ return !(entryopen = (err == ZIP_OK));
+} // end of addEntry
+
+/***********************************************************************/
+/* writeEntry: Deflate the buffer to the zip file. */
+/***********************************************************************/
+int ZIPUTIL::writeEntry(PGLOBAL g, char *buf, int len)
+{
+ if (zipWriteInFileInZip(zipfile, buf, len) < 0) {
+ sprintf(g->Message, "Error writing %s in the zipfile", target);
+ return RC_FX;
+ } // endif zipWriteInFileInZip
+
+ return RC_OK;
+} // end of writeEntry
+
+/***********************************************************************/
+/* Close the zip file. */
+/***********************************************************************/
+void ZIPUTIL::closeEntry()
+{
+ if (entryopen) {
+ zipCloseFileInZip(zipfile);
+ entryopen = false;
+ } // endif entryopen
+
+} // end of closeEntry
+
+/* ------------------------- class UNZIPUTL -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+UNZIPUTL::UNZIPUTL(PCSZ tgt, PCSZ pw, bool mul)
+{
+ zipfile = NULL;
+ target = tgt;
+ pwd = pw;
+ fp = NULL;
+ memory = NULL;
+ size = 0;
+ entryopen = false;
+ multiple = mul;
+ memset(fn, 0, sizeof(fn));
+
+ // Init the case mapping table.
+#if defined(_WIN32)
+ for (int i = 0; i < 256; ++i) mapCaseTable[i] = toupper(i);
+#else
+ for (int i = 0; i < 256; ++i) mapCaseTable[i] = i;
+#endif
+} // end of UNZIPUTL standard constructor
+
+UNZIPUTL::UNZIPUTL(PDOSDEF tdp)
+{
+ zipfile = NULL;
+ target = tdp->GetEntry();
+ pwd = tdp->Pwd;
+ fp = NULL;
+ memory = NULL;
+ size = 0;
+ entryopen = false;
+ multiple = tdp->GetMul();
+ memset(fn, 0, sizeof(fn));
+
+ // Init the case mapping table.
+#if defined(_WIN32)
+ for (int i = 0; i < 256; ++i) mapCaseTable[i] = toupper(i);
+#else
+ for (int i = 0; i < 256; ++i) mapCaseTable[i] = i;
+#endif
+} // end of UNZIPUTL standard constructor
+
+#if 0
+UNZIPUTL::UNZIPUTL(PZIPUTIL zutp)
+{
+ zipfile = zutp->zipfile;
+ target = zutp->target;
+ fp = zutp->fp;
+ finfo = zutp->finfo;
+ entryopen = zutp->entryopen;
+ multiple = zutp->multiple;
+ for (int i = 0; i < 256; ++i) mapCaseTable[i] = zutp->mapCaseTable[i];
+} // end of UNZIPUTL copy constructor
+#endif // 0
+
+/***********************************************************************/
+/* This code is the copyright property of Alessandro Felice Cantatore. */
+/* http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html */
+/***********************************************************************/
+bool UNZIPUTL::WildMatch(PCSZ pat, PCSZ str) {
+ PCSZ s, p;
+ bool star = FALSE;
+
+loopStart:
+ for (s = str, p = pat; *s; ++s, ++p) {
+ switch (*p) {
+ case '?':
+ if (*s == '.') goto starCheck;
+ break;
+ case '*':
+ star = TRUE;
+ str = s, pat = p;
+ if (!*++pat) return TRUE;
+ goto loopStart;
+ default:
+ if (mapCaseTable[(uint)*s] != mapCaseTable[(uint)*p])
+ goto starCheck;
+ break;
+ } /* endswitch */
+ } /* endfor */
+ if (*p == '*') ++p;
+ return (!*p);
+
+starCheck:
+ if (!star) return FALSE;
+ str++;
+ goto loopStart;
+} // end of WildMatch
+
+/***********************************************************************/
+/* open a zip file. */
+/* param: filename path and the filename of the zip file to open. */
+/* return: true if open, false otherwise. */
+/***********************************************************************/
+bool UNZIPUTL::open(PGLOBAL g, PCSZ filename)
+{
+ if (!zipfile && !(zipfile = unzOpen64(filename)))
+ sprintf(g->Message, "Zipfile open error on %s", filename);
+
+ return (zipfile == NULL);
+} // end of open
+
+/***********************************************************************/
+/* Close the zip file. */
+/***********************************************************************/
+void UNZIPUTL::close()
+{
+ if (zipfile) {
+ closeEntry();
+ unzClose(zipfile);
+ zipfile = NULL;
+ } // endif zipfile
+
+ if (fp)
+ fp->Count = 0;
+
+} // end of close
+
+/***********************************************************************/
+/* Find next entry matching target pattern. */
+/***********************************************************************/
+int UNZIPUTL::findEntry(PGLOBAL g, bool next)
+{
+ int rc;
+
+ do {
+ if (next) {
+ rc = unzGoToNextFile(zipfile);
+
+ if (rc == UNZ_END_OF_LIST_OF_FILE)
+ return RC_EF;
+ else if (rc != UNZ_OK) {
+ sprintf(g->Message, "unzGoToNextFile rc = %d", rc);
+ return RC_FX;
+ } // endif rc
+
+ } // endif next
+
+ if (target && *target) {
+ rc = unzGetCurrentFileInfo(zipfile, NULL, fn, sizeof(fn),
+ NULL, 0, NULL, 0);
+ if (rc == UNZ_OK) {
+ if (WildMatch(target, fn))
+ return RC_OK;
+
+ } else {
+ sprintf(g->Message, "GetCurrentFileInfo rc = %d", rc);
+ return RC_FX;
+ } // endif rc
+
+ } else
+ return RC_OK;
+
+ next = true;
+ } while (true);
+
+ strcpy(g->Message, "FindNext logical error");
+ return RC_FX;
+} // end of FindEntry
+
+
+/***********************************************************************/
+/* Get the next used entry. */
+/***********************************************************************/
+int UNZIPUTL::nextEntry(PGLOBAL g)
+{
+ if (multiple) {
+ int rc;
+
+ closeEntry();
+
+ if ((rc = findEntry(g, true)) != RC_OK)
+ return rc;
+
+ if (openEntry(g))
+ return RC_FX;
+
+ return RC_OK;
+ } else
+ return RC_EF;
+
+} // end of nextEntry
+
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */
+/***********************************************************************/
+bool UNZIPUTL::OpenTable(PGLOBAL g, MODE mode, PCSZ fn)
+{
+ /*********************************************************************/
+ /* The file will be decompressed into virtual memory. */
+ /*********************************************************************/
+ if (mode == MODE_READ || mode == MODE_ANY) {
+ bool b = open(g, fn);
+
+ if (!b) {
+ int rc;
+
+ if (target && *target) {
+ if (!multiple) {
+ rc = unzLocateFile(zipfile, target, 0);
+
+ if (rc == UNZ_END_OF_LIST_OF_FILE) {
+ sprintf(g->Message, "Target file %s not in %s", target, fn);
+ return true;
+ } else if (rc != UNZ_OK) {
+ sprintf(g->Message, "unzLocateFile rc=%d", rc);
+ return true;
+ } // endif's rc
+
+ } else {
+ if ((rc = findEntry(g, false)) == RC_FX)
+ return true;
+ else if (rc == RC_EF) {
+ sprintf(g->Message, "No match of %s in %s", target, fn);
+ return true;
+ } // endif rc
+
+ } // endif multiple
+
+ } // endif target
+
+ if (openEntry(g))
+ return true;
+
+ if (size > 0) {
+ /*******************************************************************/
+ /* Link a Fblock. This make possible to automatically close it */
+ /* in case of error g->jump. */
+ /*******************************************************************/
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ fp->Type = TYPE_FB_ZIP;
+ fp->Fname = PlugDup(g, fn);
+ fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = fp;
+ fp->Count = 1;
+ fp->Length = size;
+ fp->Memory = memory;
+ fp->Mode = mode;
+ fp->File = this;
+ fp->Handle = 0;
+ } // endif fp
+
+ } else
+ return true;
+
+ } else {
+ strcpy(g->Message, "Only READ mode supported for ZIPPED tables");
+ return true;
+ } // endif mode
+
+ return false;
+} // end of OpenTableFile
+
+/***********************************************************************/
+/* Insert only if the entry does not exist. */
+/***********************************************************************/
+bool UNZIPUTL::IsInsertOk(PGLOBAL g, PCSZ fn)
+{
+ bool ok = true, b = open(g, fn);
+
+ if (!b) {
+ if (!target || *target == 0) {
+ unz_global_info64 ginfo;
+ int err = unzGetGlobalInfo64(zipfile, &ginfo);
+
+ ok = !(err == UNZ_OK && ginfo.number_entry > 0);
+ } else // Check if the target exist
+ ok = (unzLocateFile(zipfile, target, 0) != UNZ_OK);
+
+ unzClose(zipfile);
+ } // endif b
+
+ return ok;
+} // end of IsInsertOk
+
+/***********************************************************************/
+/* Open target in zip file. */
+/***********************************************************************/
+bool UNZIPUTL::openEntry(PGLOBAL g)
+{
+ int rc;
+
+ rc = unzGetCurrentFileInfo(zipfile, &finfo, fn, sizeof(fn),
+ NULL, 0, NULL, 0);
+
+ if (rc != UNZ_OK) {
+ sprintf(g->Message, "unzGetCurrentFileInfo64 rc=%d", rc);
+ return true;
+ } else if ((rc = unzOpenCurrentFilePassword(zipfile, pwd)) != UNZ_OK) {
+ sprintf(g->Message, "unzOpen fn=%s rc=%d", fn, rc);
+ return true;
+ } // endif rc
+
+ size = finfo.uncompressed_size;
+
+ try {
+ memory = new char[size + 1];
+ } catch (...) {
+ strcpy(g->Message, "Out of memory");
+ return true;
+ } // end try/catch
+
+ if ((rc = unzReadCurrentFile(zipfile, memory, size)) < 0) {
+ sprintf(g->Message, "unzReadCurrentFile rc = %d", rc);
+ unzCloseCurrentFile(zipfile);
+ delete[] memory;
+ memory = NULL;
+ entryopen = false;
+ } else {
+ memory[size] = 0; // Required by some table types (XML)
+ entryopen = true;
+ } // endif rc
+
+ if (trace(1))
+ htrc("Opening entry%s %s\n", fn, (entryopen) ? "oked" : "failed");
+
+ return !entryopen;
+} // end of openEntry
+
+/***********************************************************************/
+/* Close the zip file. */
+/***********************************************************************/
+void UNZIPUTL::closeEntry()
+{
+ if (entryopen) {
+ unzCloseCurrentFile(zipfile);
+ entryopen = false;
+ } // endif entryopen
+
+ if (memory) {
+ delete[] memory;
+ memory = NULL;
+ } // endif memory
+
+} // end of closeEntry
+
+/* -------------------------- class UNZFAM --------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+UNZFAM::UNZFAM(PDOSDEF tdp) : MAPFAM(tdp)
+{
+ zutp = NULL;
+ tdfp = tdp;
+ //target = tdp->GetEntry();
+ //mul = tdp->GetMul();
+} // end of UNZFAM standard constructor
+
+UNZFAM::UNZFAM(PUNZFAM txfp) : MAPFAM(txfp)
+{
+ zutp = txfp->zutp;
+ tdfp = txfp->tdfp;
+ //target = txfp->target;
+ //mul = txfp->mul;
+} // end of UNZFAM copy constructor
+
+/***********************************************************************/
+/* ZIP GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int UNZFAM::GetFileLength(PGLOBAL g)
+{
+ int len = (zutp && zutp->entryopen) ? (int)(Top - Memory)
+ : TXTFAM::GetFileLength(g) * 3;
+
+ if (trace(1))
+ htrc("Zipped file length=%d\n", len);
+
+ return len;
+} // end of GetFileLength
+
+/***********************************************************************/
+/* ZIP Cardinality: return the number of rows if possible. */
+/***********************************************************************/
+int UNZFAM::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 1;
+
+ int card = -1;
+ int len = GetFileLength(g);
+
+ if (len) {
+ // Estimated ???
+ card = (len / (int)Lrecl) * 2;
+ card = card ? card : 10; // Lrecl can be too big
+ } else
+ card = 0;
+
+ return card;
+} // end of Cardinality
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */
+/***********************************************************************/
+bool UNZFAM::OpenTableFile(PGLOBAL g)
+{
+ char filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+
+ /*********************************************************************/
+ /* Allocate the ZIP utility class. */
+ /*********************************************************************/
+ zutp = new(g) UNZIPUTL(tdfp);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!zutp->OpenTable(g, mode, filename)) {
+ // The pseudo "buffer" is here the entire real buffer
+ Fpos = Mempos = Memory = zutp->memory;
+ Top = Memory + zutp->size;
+ To_Fb = zutp->fp; // Useful when closing
+ } else
+ return true;
+
+ return false;
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* GetNext: go to next entry. */
+/***********************************************************************/
+int UNZFAM::GetNext(PGLOBAL g)
+{
+ int rc = zutp->nextEntry(g);
+
+ if (rc != RC_OK)
+ return rc;
+
+ Mempos = Memory = zutp->memory;
+ Top = Memory + zutp->size;
+ return RC_OK;
+} // end of GetNext
+
+#if 0
+/***********************************************************************/
+/* ReadBuffer: Read one line for a ZIP file. */
+/***********************************************************************/
+int UNZFAM::ReadBuffer(PGLOBAL g)
+{
+ int rc, len;
+
+ // Are we at the end of the memory
+ if (Mempos >= Top) {
+ if ((rc = zutp->nextEntry(g)) != RC_OK)
+ return rc;
+
+ Mempos = Memory = zutp->memory;
+ Top = Memory + zutp->size;
+ } // endif Mempos
+
+#if 0
+ if (!Placed) {
+ /*******************************************************************/
+ /* Record file position in case of UPDATE or DELETE. */
+ /*******************************************************************/
+ int rc;
+
+ next:
+ Fpos = Mempos;
+ CurBlk = (int)Rows++;
+
+ /*******************************************************************/
+ /* Check whether optimization on ROWID */
+ /* can be done, as well as for join as for local filtering. */
+ /*******************************************************************/
+ switch (Tdbp->TestBlock(g)) {
+ case RC_EF:
+ return RC_EF;
+ case RC_NF:
+ // Skip this record
+ if ((rc = SkipRecord(g, false)) != RC_OK)
+ return rc;
+
+ goto next;
+ } // endswitch rc
+
+ } else
+ Placed = false;
+#else
+ // Perhaps unuseful
+ Fpos = Mempos;
+ CurBlk = (int)Rows++;
+ Placed = false;
+#endif
+
+ // Immediately calculate next position (Used by DeleteDB)
+ while (*Mempos++ != '\n'); // What about Unix ???
+
+ // Set caller line buffer
+ len = (Mempos - Fpos) - 1;
+
+ // Don't rely on ENDING setting
+ if (len > 0 && *(Mempos - 2) == '\r')
+ len--; // Line ends by CRLF
+
+ memcpy(Tdbp->GetLine(), Fpos, len);
+ Tdbp->GetLine()[len] = '\0';
+ return RC_OK;
+} // end of ReadBuffer
+
+/***********************************************************************/
+/* Table file close routine for MAP access method. */
+/***********************************************************************/
+void UNZFAM::CloseTableFile(PGLOBAL g, bool)
+{
+ close();
+} // end of CloseTableFile
+#endif // 0
+
+/* -------------------------- class UZXFAM --------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+UZXFAM::UZXFAM(PDOSDEF tdp) : MPXFAM(tdp)
+{
+ zutp = NULL;
+ tdfp = tdp;
+ //target = tdp->GetEntry();
+ //mul = tdp->GetMul();
+ //Lrecl = tdp->GetLrecl();
+} // end of UZXFAM standard constructor
+
+UZXFAM::UZXFAM(PUZXFAM txfp) : MPXFAM(txfp)
+{
+ zutp = txfp->zutp;
+ tdfp = txfp->tdfp;
+ //target = txfp->target;
+ //mul = txfp->mul;
+ //Lrecl = txfp->Lrecl;
+} // end of UZXFAM copy constructor
+
+/***********************************************************************/
+/* ZIP GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int UZXFAM::GetFileLength(PGLOBAL g)
+{
+ int len;
+
+ if (!zutp && OpenTableFile(g))
+ return 0;
+
+ if (zutp->entryopen)
+ len = zutp->size;
+ else
+ len = 0;
+
+ return len;
+} // end of GetFileLength
+
+/***********************************************************************/
+/* ZIP Cardinality: return the number of rows if possible. */
+/***********************************************************************/
+int UZXFAM::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 1;
+
+ int card = -1;
+ int len = GetFileLength(g);
+
+ if (!(len % Lrecl))
+ card = len / (int)Lrecl; // Fixed length file
+ else
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), zutp->fn, len, Lrecl);
+
+ // Set number of blocks for later use
+ Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0;
+ return card;
+} // end of Cardinality
+
+/***********************************************************************/
+/* OpenTableFile: Open a FIX/UNIX table file from a ZIP file. */
+/***********************************************************************/
+bool UZXFAM::OpenTableFile(PGLOBAL g)
+{
+ // May have been already opened in GetFileLength
+ if (!zutp || !zutp->zipfile) {
+ char filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+
+ /*********************************************************************/
+ /* Allocate the ZIP utility class. */
+ /*********************************************************************/
+ if (!zutp)
+ zutp = new(g)UNZIPUTL(tdfp);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!zutp->OpenTable(g, mode, filename)) {
+ // The pseudo "buffer" is here the entire real buffer
+ Memory = zutp->memory;
+ Fpos = Mempos = Memory + Headlen;
+ Top = Memory + zutp->size;
+ To_Fb = zutp->fp; // Useful when closing
+ } else
+ return true;
+
+ } else
+ Reset();
+
+ return false;
+} // end of OpenTableFile
+
+/***********************************************************************/
+/* GetNext: go to next entry. */
+/***********************************************************************/
+int UZXFAM::GetNext(PGLOBAL g)
+{
+ int rc = zutp->nextEntry(g);
+
+ if (rc != RC_OK)
+ return rc;
+
+ int len = zutp->size;
+
+ if (len % Lrecl) {
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), zutp->fn, len, Lrecl);
+ return RC_FX;
+ } // endif size
+
+ Memory = zutp->memory;
+ Top = Memory + len;
+ Rewind();
+ return RC_OK;
+} // end of GetNext
+
+/* -------------------------- class UZDFAM --------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+UZDFAM::UZDFAM(PDOSDEF tdp) : DBMFAM(tdp)
+{
+ zutp = NULL;
+ tdfp = tdp;
+ //target = tdp->GetEntry();
+ //mul = tdp->GetMul();
+ //Lrecl = tdp->GetLrecl();
+} // end of UZXFAM standard constructor
+
+UZDFAM::UZDFAM(PUZDFAM txfp) : DBMFAM(txfp)
+{
+ zutp = txfp->zutp;
+ tdfp = txfp->tdfp;
+ //target = txfp->target;
+ //mul = txfp->mul;
+ //Lrecl = txfp->Lrecl;
+} // end of UZXFAM copy constructor
+
+#if 0
+/****************************************************************************/
+/* dbfhead: Routine to analyze a DBF header. */
+/* Parameters: */
+/* PGLOBAL g -- pointer to the CONNECT Global structure */
+/* DBFHEADER *hdrp -- pointer to _dbfheader structure */
+/* Returns: */
+/* RC_OK, RC_NF, RC_INFO, or RC_FX if error. */
+/* Side effects: */
+/* Set the fields number in the header. */
+/****************************************************************************/
+int UZDFAM::dbfhead(PGLOBAL g, void* buf)
+{
+ char *endmark;
+ int dbc = 2, rc = RC_OK;
+ DBFHEADER* hdrp = (DBFHEADER*)buf;
+
+ *g->Message = '\0';
+
+ // Check first byte to be sure of .dbf type
+ if ((hdrp->Version & 0x03) != DBFTYPE) {
+ strcpy(g->Message, MSG(NOT_A_DBF_FILE));
+ rc = RC_INFO;
+
+ if ((hdrp->Version & 0x30) == 0x30) {
+ strcpy(g->Message, MSG(FOXPRO_FILE));
+ dbc = 264; // FoxPro database container
+ } // endif Version
+
+ } else
+ strcpy(g->Message, MSG(DBASE_FILE));
+
+ // Check last byte(s) of header
+ endmark = (char*)hdrp + hdrp->Headlen() - dbc;
+
+ // Some headers just have 1D others have 1D00 following fields
+ if (endmark[0] != EOH && endmark[1] != EOH) {
+ sprintf(g->Message, MSG(NO_0DH_HEAD), dbc);
+
+ if (rc == RC_OK)
+ return RC_FX;
+
+ } // endif endmark
+
+ // Calculate here the number of fields while we have the dbc info
+ hdrp->SetFields((hdrp->Headlen() - dbc - 1) / 32);
+ return rc;
+} // end of dbfhead
+
+/****************************************************************************/
+/* ScanHeader: scan the DBF file header for number of records, record size,*/
+/* and header length. Set Records, check that Reclen is equal to lrecl and */
+/* return the header length or 0 in case of error. */
+/****************************************************************************/
+int UZDFAM::ScanHeader(PGLOBAL g, int* rln)
+{
+ int rc;
+ DBFHEADER header;
+
+ /************************************************************************/
+ /* Get the first 32 bytes of the header. */
+ /************************************************************************/
+ rc = dbfhead(g, &header);
+
+ if (rc == RC_FX)
+ return -1;
+
+ *rln = (int)header.Reclen();
+ Records = (int)header.Records();
+ return (int)header.Headlen();
+} // end of ScanHeader
+#endif // 0
+
+/***********************************************************************/
+/* ZIP GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int UZDFAM::GetFileLength(PGLOBAL g)
+{
+ int len;
+
+ if (!zutp && OpenTableFile(g))
+ return 0;
+
+ if (zutp->entryopen)
+ len = zutp->size;
+ else
+ len = 0;
+
+ return len;
+} // end of GetFileLength
+
+/***********************************************************************/
+/* ZIP Cardinality: return the number of rows if possible. */
+/***********************************************************************/
+int UZDFAM::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 1;
+
+ int card = -1;
+
+ card = Records;
+
+ // Set number of blocks for later use
+ Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0;
+ return card;
+} // end of Cardinality
+
+/***********************************************************************/
+/* OpenTableFile: Open a DBF table file from a ZIP file. */
+/***********************************************************************/
+bool UZDFAM::OpenTableFile(PGLOBAL g)
+{
+ // May have been already opened in GetFileLength
+ if (!zutp || !zutp->zipfile) {
+ char filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+
+ /*********************************************************************/
+ /* Allocate the ZIP utility class. */
+ /*********************************************************************/
+ if (!zutp)
+ zutp = new(g)UNZIPUTL(tdfp);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!zutp->OpenTable(g, mode, filename)) {
+ // The pseudo "buffer" is here the entire real buffer
+ Memory = zutp->memory;
+ Top = Memory + zutp->size;
+ To_Fb = zutp->fp; // Useful when closing
+ return AllocateBuffer(g);
+ } else
+ return true;
+
+ } else
+ Reset();
+
+ return false;
+} // end of OpenTableFile
+
+/***********************************************************************/
+/* GetNext: go to next entry. */
+/***********************************************************************/
+int UZDFAM::GetNext(PGLOBAL g)
+{
+ int rc = zutp->nextEntry(g);
+
+ if (rc != RC_OK)
+ return rc;
+
+ int len = zutp->size;
+
+#if 0
+ if (len % Lrecl) {
+ sprintf(g->Message, MSG(NOT_FIXED_LEN), zutp->fn, len, Lrecl);
+ return RC_FX;
+ } // endif size
+#endif // 0
+
+ Memory = zutp->memory;
+ Top = Memory + len;
+ Rewind();
+ return RC_OK;
+} // end of GetNext
+
+/* -------------------------- class ZIPFAM --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+ZIPFAM::ZIPFAM(PDOSDEF tdp) : DOSFAM(tdp)
+{
+ zutp = NULL;
+ target = tdp->GetEntry();
+ append = tdp->GetAppend();
+} // end of ZIPFAM standard constructor
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */
+/***********************************************************************/
+bool ZIPFAM::OpenTableFile(PGLOBAL g)
+{
+ char filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+ int len = TXTFAM::GetFileLength(g);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (len < 0)
+ return true;
+ else if (!append && len > 0) {
+ strcpy(g->Message, "No insert into existing zip file");
+ return true;
+ } else if (append && len > 0) {
+ UNZIPUTL *zutp = new(g) UNZIPUTL(target, NULL, false);
+
+ if (!zutp->IsInsertOk(g, filename)) {
+ strcpy(g->Message, "No insert into existing entry");
+ return true;
+ } // endif Ok
+
+ } // endif's
+
+ /*********************************************************************/
+ /* Allocate the ZIP utility class. */
+ /*********************************************************************/
+ zutp = new(g) ZIPUTIL(target);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!zutp->OpenTable(g, mode, filename, append)) {
+ To_Fb = zutp->fp; // Useful when closing
+ } else
+ return true;
+
+ return AllocateBuffer(g);
+} // end of OpenTableFile
+
+/***********************************************************************/
+/* ReadBuffer: Read one line for a ZIP file. */
+/***********************************************************************/
+int ZIPFAM::ReadBuffer(PGLOBAL g)
+{
+ strcpy(g->Message, "ReadBuffer should not been called when zipping");
+ return RC_FX;
+} // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: Deflate the buffer to the zip file. */
+/***********************************************************************/
+int ZIPFAM::WriteBuffer(PGLOBAL g)
+{
+ int len;
+
+ // Prepare to write the new line
+ strcat(strcpy(To_Buf, Tdbp->GetLine()), (Bin) ? CrLf : "\n");
+ len = (int)(strchr(To_Buf, '\n') - To_Buf + 1);
+ return zutp->writeEntry(g, To_Buf, len);
+} // end of WriteBuffer
+
+/***********************************************************************/
+/* Table file close routine for ZIP access method. */
+/***********************************************************************/
+void ZIPFAM::CloseTableFile(PGLOBAL g, bool)
+{
+ To_Fb->Count = 0;
+ zutp->close();
+} // end of CloseTableFile
+
+/* -------------------------- class ZPXFAM --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+ZPXFAM::ZPXFAM(PDOSDEF tdp) : FIXFAM(tdp)
+{
+ zutp = NULL;
+ target = tdp->GetEntry();
+ append = tdp->GetAppend();
+ //Lrecl = tdp->GetLrecl();
+} // end of ZPXFAM standard constructor
+
+/***********************************************************************/
+/* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */
+/***********************************************************************/
+bool ZPXFAM::OpenTableFile(PGLOBAL g)
+{
+ char filename[_MAX_PATH];
+ MODE mode = Tdbp->GetMode();
+ int len = TXTFAM::GetFileLength(g);
+
+ if (len < 0)
+ return true;
+ else if (!append && len > 0) {
+ strcpy(g->Message, "No insert into existing zip file");
+ return true;
+ } else if (append && len > 0) {
+ UNZIPUTL *zutp = new(g) UNZIPUTL(target, NULL, false);
+
+ if (!zutp->IsInsertOk(g, filename)) {
+ strcpy(g->Message, "No insert into existing entry");
+ return true;
+ } // endif Ok
+
+ } // endif's
+
+ /*********************************************************************/
+ /* Allocate the ZIP utility class. */
+ /*********************************************************************/
+ zutp = new(g) ZIPUTIL(target);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, To_File, Tdbp->GetPath());
+
+ if (!zutp->OpenTable(g, mode, filename, append)) {
+ To_Fb = zutp->fp; // Useful when closing
+ } else
+ return true;
+
+ return AllocateBuffer(g);
+} // end of OpenTableFile
+
+/***********************************************************************/
+/* WriteBuffer: Deflate the buffer to the zip file. */
+/***********************************************************************/
+int ZPXFAM::WriteBuffer(PGLOBAL g)
+{
+ /*********************************************************************/
+ /* In Insert mode, we write only full blocks. */
+ /*********************************************************************/
+ if (++CurNum != Rbuf) {
+ Tdbp->IncLine(Lrecl); // Used by DOSCOL functions
+ return RC_OK;
+ } // endif CurNum
+
+ // Now start the compress process.
+ if (zutp->writeEntry(g, To_Buf, Lrecl * Rbuf) != RC_OK) {
+ Closing = true;
+ return RC_FX;
+ } // endif writeEntry
+
+ CurBlk++;
+ CurNum = 0;
+ Tdbp->SetLine(To_Buf);
+ return RC_OK;
+} // end of WriteBuffer
+
+/***********************************************************************/
+/* Table file close routine for ZIP access method. */
+/***********************************************************************/
+void ZPXFAM::CloseTableFile(PGLOBAL g, bool)
+{
+ if (CurNum && !Closing) {
+ // Some more inserted lines remain to be written
+ Rbuf = CurNum--;
+ WriteBuffer(g);
+ } // endif Curnum
+
+ To_Fb->Count = 0;
+ zutp->close();
+} // end of CloseTableFile
diff --git a/storage/connect/filamzip.h b/storage/connect/filamzip.h
new file mode 100644
index 00000000..7ff1fb0a
--- /dev/null
+++ b/storage/connect/filamzip.h
@@ -0,0 +1,232 @@
+/************** filamzip H Declares Source Code File (.H) **************/
+/* Name: filamzip.h Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2016-2020 */
+/* */
+/* This file contains the ZIP file access method classes declares. */
+/***********************************************************************/
+#ifndef __FILAMZIP_H
+#define __FILAMZIP_H
+
+#include "block.h"
+#include "filamap.h"
+#include "filamfix.h"
+#include "filamdbf.h"
+#include "zip.h"
+#include "unzip.h"
+
+#define DLLEXPORT extern "C"
+
+typedef class UNZFAM *PUNZFAM;
+typedef class UZXFAM *PUZXFAM;
+typedef class UZDFAM* PUZDFAM;
+typedef class ZIPFAM *PZIPFAM;
+typedef class ZPXFAM *PZPXFAM;
+
+/***********************************************************************/
+/* This is the ZIP utility fonctions class. */
+/***********************************************************************/
+class DllExport ZIPUTIL : public BLOCK {
+ public:
+ // Constructor
+ ZIPUTIL(PCSZ tgt);
+ //ZIPUTIL(ZIPUTIL *zutp);
+
+ // Methods
+ bool OpenTable(PGLOBAL g, MODE mode, PCSZ fn, bool append);
+ bool open(PGLOBAL g, PCSZ fn, bool append);
+ bool addEntry(PGLOBAL g, PCSZ entry);
+ void close(void);
+ void closeEntry(void);
+ int writeEntry(PGLOBAL g, char *buf, int len);
+ void getTime(tm_zip& tmZip);
+
+ // Members
+ zipFile zipfile; // The ZIP container file
+ PCSZ target; // The target file name
+ PCSZ pwd; // The ZIP file password
+ PFBLOCK fp;
+ bool entryopen; // True when open current entry
+}; // end of ZIPUTIL
+
+/***********************************************************************/
+/* This is the unZIP utility fonctions class. */
+/***********************************************************************/
+class DllExport UNZIPUTL : public BLOCK {
+ public:
+ // Constructor
+ UNZIPUTL(PCSZ tgt, PCSZ pw, bool mul);
+ UNZIPUTL(PDOSDEF tdp);
+
+ // Implementation
+//PTXF Duplicate(PGLOBAL g) { return (PTXF) new(g)UNZFAM(this); }
+
+ // Methods
+ bool OpenTable(PGLOBAL g, MODE mode, PCSZ fn);
+ bool open(PGLOBAL g, PCSZ fn);
+ bool openEntry(PGLOBAL g);
+ void close(void);
+ void closeEntry(void);
+ bool WildMatch(PCSZ pat, PCSZ str);
+ int findEntry(PGLOBAL g, bool next);
+ int nextEntry(PGLOBAL g);
+ bool IsInsertOk(PGLOBAL g, PCSZ fn);
+
+ // Members
+ unzFile zipfile; // The ZIP container file
+ PCSZ target; // The target file name
+ PCSZ pwd; // The ZIP file password
+ unz_file_info finfo; // The current file info
+ PFBLOCK fp;
+ char *memory;
+ uint size;
+ int multiple; // Multiple targets
+ bool entryopen; // True when open current entry
+ char fn[FILENAME_MAX]; // The current entry file name
+ char mapCaseTable[256];
+}; // end of UNZIPUTL
+
+/***********************************************************************/
+/* This is the unzip file access method. */
+/***********************************************************************/
+class DllExport UNZFAM : public MAPFAM {
+//friend class UZXFAM;
+ public:
+ // Constructors
+ UNZFAM(PDOSDEF tdp);
+ UNZFAM(PUNZFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_ZIP;}
+ virtual PTXF Duplicate(PGLOBAL g) {return (PTXF) new(g) UNZFAM(this);}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetFileLength(PGLOBAL g);
+ //virtual int MaxBlkSize(PGLOBAL g, int s) {return s;}
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual bool DeferReading(void) { return false; }
+ virtual int GetNext(PGLOBAL g);
+ //virtual int ReadBuffer(PGLOBAL g);
+ //virtual int WriteBuffer(PGLOBAL g);
+ //virtual int DeleteRecords(PGLOBAL g, int irc);
+ //virtual void CloseTableFile(PGLOBAL g, bool abort);
+
+ protected:
+ // Members
+ UNZIPUTL *zutp;
+ PDOSDEF tdfp;
+}; // end of UNZFAM
+
+/***********************************************************************/
+/* This is the fixed unzip file access method. */
+/***********************************************************************/
+class DllExport UZXFAM : public MPXFAM {
+//friend class UNZFAM;
+ public:
+ // Constructors
+ UZXFAM(PDOSDEF tdp);
+ UZXFAM(PUZXFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) { return TYPE_AM_ZIP; }
+ virtual PTXF Duplicate(PGLOBAL g) { return (PTXF) new(g)UZXFAM(this); }
+
+ // Methods
+ virtual int GetFileLength(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int GetNext(PGLOBAL g);
+ //virtual int ReadBuffer(PGLOBAL g);
+
+ protected:
+ // Members
+ UNZIPUTL *zutp;
+ PDOSDEF tdfp;
+}; // end of UZXFAM
+
+/***********************************************************************/
+/* This is the fixed unzip file access method. */
+/***********************************************************************/
+class DllExport UZDFAM : public DBMFAM {
+ //friend class UNZFAM;
+public:
+ // Constructors
+ UZDFAM(PDOSDEF tdp);
+ UZDFAM(PUZDFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) { return TYPE_AM_ZIP; }
+ virtual PTXF Duplicate(PGLOBAL g) { return (PTXF) new(g)UZDFAM(this); }
+
+ // Methods
+ virtual int GetFileLength(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int GetNext(PGLOBAL g);
+ //virtual int ReadBuffer(PGLOBAL g);
+
+protected:
+ int dbfhead(PGLOBAL g, void* buf);
+ int ScanHeader(PGLOBAL g, int* rln);
+
+ // Members
+ UNZIPUTL* zutp;
+ PDOSDEF tdfp;
+}; // end of UZDFAM
+
+/***********************************************************************/
+/* This is the zip file access method. */
+/***********************************************************************/
+class DllExport ZIPFAM : public DOSFAM {
+ public:
+ // Constructors
+ ZIPFAM(PDOSDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_ZIP;}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g) {return 0;}
+ virtual int GetFileLength(PGLOBAL g) {return g ? 0 : 1;}
+ //virtual int MaxBlkSize(PGLOBAL g, int s) {return s;}
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ //virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+
+ protected:
+ // Members
+ ZIPUTIL *zutp;
+ PCSZ target;
+ bool append;
+//bool replace;
+}; // end of ZIPFAM
+
+/***********************************************************************/
+/* This is the fixed zip file access method. */
+/***********************************************************************/
+class DllExport ZPXFAM : public FIXFAM {
+ public:
+ // Constructors
+ ZPXFAM(PDOSDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_ZIP;}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g) {return 0;}
+ virtual int GetFileLength(PGLOBAL g) {return g ? 0 : 1;}
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+
+ protected:
+ // Members
+ ZIPUTIL *zutp;
+ PCSZ target;
+ bool append;
+}; // end of ZPXFAM
+
+#endif // __FILAMZIP_H
diff --git a/storage/connect/filter.cpp b/storage/connect/filter.cpp
new file mode 100644
index 00000000..9d8518ec
--- /dev/null
+++ b/storage/connect/filter.cpp
@@ -0,0 +1,1753 @@
+/***************** Filter C++ Class Filter Code (.CPP) *****************/
+/* Name: FILTER.CPP Version 4.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2017 */
+/* */
+/* This file contains the class FILTER function code. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+//#include "sql_class.h"
+//#include "sql_time.h"
+
+#if defined(_WIN32)
+//#include <windows.h>
+#else // !_WIN32
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif // !_WIN32
+
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* xobject.h is header containing the XOBJECT derived classes dcls. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "tabcol.h"
+#include "xtable.h"
+#include "array.h"
+#include "filter.h"
+#include "xindex.h"
+
+/***********************************************************************/
+/* Utility routines. */
+/***********************************************************************/
+void PlugConvertConstant(PGLOBAL, void* &, short&);
+//void *PlugCopyDB(PTABS, void*, INT);
+void NewPointer(PTABS, void*, void*);
+void AddPointer(PTABS, void*);
+
+static PPARM MakeParm(PGLOBAL g, PXOB xp)
+ {
+ PPARM pp = (PPARM)PlugSubAlloc(g, NULL, sizeof(PARM));
+ pp->Type = TYPE_XOBJECT;
+ pp->Value = xp;
+ pp->Domain = 0;
+ pp->Next = NULL;
+ return pp;
+ } // end of MakeParm
+
+/***********************************************************************/
+/* Routines called internally/externally by FILTER functions. */
+/***********************************************************************/
+bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
+//bool ReadSubQuery(PGLOBAL, PSUBQ);
+//PSUBQ OpenSubQuery(PGLOBAL, PSQL);
+//void PlugCloseDB(PGLOBAL, PSQL);
+BYTE OpBmp(PGLOBAL g, OPVAL opc);
+PARRAY MakeValueArray(PGLOBAL g, PPARM pp);
+
+/***********************************************************************/
+/* Returns the bitmap representing the conditions that must not be */
+/* met when returning from TestValue for a given operator. */
+/* Bit one is EQ, bit 2 is LT, and bit 3 is GT. */
+/***********************************************************************/
+BYTE OpBmp(PGLOBAL g, OPVAL opc)
+ {
+ BYTE bt;
+
+ switch (opc) {
+ case OP_IN:
+ case OP_EQ: bt = 0x06; break;
+ case OP_NE: bt = 0x01; break;
+ case OP_GT: bt = 0x03; break;
+ case OP_GE: bt = 0x02; break;
+ case OP_LT: bt = 0x05; break;
+ case OP_LE: bt = 0x04; break;
+ case OP_EXIST: bt = 0x00; break;
+ default:
+ sprintf(g->Message, MSG(BAD_FILTER_OP), opc);
+ throw (int)TYPE_FILTER;
+ } // endswitch opc
+
+ return bt;
+ } // end of OpBmp
+
+/***********************************************************************/
+/* Routines called externally by CondFilter. */
+/***********************************************************************/
+PFIL MakeFilter(PGLOBAL g, PFIL fp1, OPVAL vop, PFIL fp2)
+ {
+ PFIL filp = new(g) FILTER(g, vop);
+
+ filp->Arg(0) = fp1;
+ filp->Arg(1) = (fp2) ? fp2 : pXVOID;
+
+ if (filp->Convert(g, false))
+ return NULL;
+
+ return filp;
+ } // end of MakeFilter
+
+PFIL MakeFilter(PGLOBAL g, PCOL *colp, POPER pop, PPARM pfirst, bool neg)
+{
+ PPARM parmp, pp[2];
+ PFIL fp1, fp2, filp = NULL;
+
+ if (pop->Val == OP_IN) {
+ PARRAY par = MakeValueArray(g, pfirst);
+
+ if (par) {
+ pp[0] = MakeParm(g, colp[0]);
+ pp[1] = MakeParm(g, par);
+ fp1 = new(g) FILTER(g, pop, pp);
+
+ if (fp1->Convert(g, false))
+ return NULL;
+
+ filp = (neg) ? MakeFilter(g, fp1, OP_NOT, NULL) : fp1;
+ } // endif par
+
+ } else if (pop->Val == OP_XX) { // BETWEEN
+ if (pfirst && pfirst->Next) {
+ pp[0] = MakeParm(g, colp[0]);
+ pp[1] = pfirst;
+ fp1 = new(g) FILTER(g, neg ? OP_LT : OP_GE, pp);
+
+ if (fp1->Convert(g, false))
+ return NULL;
+
+ pp[1] = pfirst->Next;
+ fp2 = new(g) FILTER(g, neg ? OP_GT : OP_LE, pp);
+
+ if (fp2->Convert(g, false))
+ return NULL;
+
+ filp = MakeFilter(g, fp1, neg ? OP_OR : OP_AND, fp2);
+ } // endif parmp
+
+ } else {
+ parmp = pfirst;
+
+ for (int i = 0; i < 2; i++)
+ if (colp[i]) {
+ pp[i] = MakeParm(g, colp[i]);
+ } else {
+ if (!parmp || parmp->Domain != i)
+ return NULL; // Logical error, should never happen
+
+ pp[i] = parmp;
+ parmp = parmp->Next;
+ } // endif colp
+
+ filp = new(g) FILTER(g, pop, pp);
+
+ if (filp->Convert(g, false))
+ return NULL;
+
+ } // endif's Val
+
+ return filp;
+} // end of MakeFilter
+
+/* --------------------------- Class FILTER -------------------------- */
+
+/***********************************************************************/
+/* FILTER public constructors. */
+/***********************************************************************/
+FILTER::FILTER(PGLOBAL g, POPER pop, PPARM *tp)
+ {
+ Constr(g, pop->Val, pop->Mod, tp);
+ } // end of FILTER constructor
+
+FILTER::FILTER(PGLOBAL g, OPVAL opc, PPARM *tp)
+ {
+ Constr(g, opc, 0, tp);
+ } // end of FILTER constructor
+
+void FILTER::Constr(PGLOBAL g, OPVAL opc, int opm, PPARM *tp)
+ {
+ Next = NULL;
+ Opc = opc;
+ Opm = opm;
+ Bt = 0x00;
+
+ for (int i = 0; i < 2; i++) {
+ Test[i].B_T = TYPE_VOID;
+
+ if (tp && tp[i]) {
+ PlugConvertConstant(g, tp[i]->Value, tp[i]->Type);
+#if defined(_DEBUG)
+ assert(tp[i]->Type == TYPE_XOBJECT);
+#endif
+ Arg(i) = (PXOB)tp[i]->Value;
+ } else
+ Arg(i) = pXVOID;
+
+ Val(i) = NULL;
+ Test[i].Conv = FALSE;
+ } // endfor i
+
+ } // end of Constr
+
+/***********************************************************************/
+/* FILTER copy constructor. */
+/***********************************************************************/
+FILTER::FILTER(PFIL fil1)
+ {
+ Next = NULL;
+ Opc = fil1->Opc;
+ Opm = fil1->Opm;
+ Test[0] = fil1->Test[0];
+ Test[1] = fil1->Test[1];
+ } // end of FILTER copy constructor
+
+#if 0
+/***********************************************************************/
+/* Linearize: Does the linearization of the filter tree: */
+/* Independent filters (not implied in OR/NOT) will be separated */
+/* from others and filtering operations will be automated by */
+/* making a list of filter operations in polish operation style. */
+/* Returned value points to the first filter of the list, which ends */
+/* with the filter that was pointed by the first call argument, */
+/* except for separators, in which case a loop is needed to find it. */
+/* Note: a loop is used now in all cases (was not for OP_NOT) to be */
+/* able to handle the case of filters whose arguments are already */
+/* linearized, as it is done in LNA semantic routines. Indeed for */
+/* already linearized chains, the first filter is never an OP_AND, */
+/* OP_OR or OP_NOT filter, so this function just returns 'this'. */
+/***********************************************************************/
+PFIL FILTER::Linearize(bool nosep)
+ {
+ int i;
+ PFIL lfp[2], ffp[2] = {NULL,NULL};
+
+ switch (Opc) {
+ case OP_NOT:
+ if (GetArgType(0) == TYPE_FILTER) {
+ lfp[0] = (PFIL)Arg(0);
+ ffp[0] = lfp[0]->Linearize(TRUE);
+ } /* endif */
+
+ if (!ffp[0])
+ return NULL;
+
+ while (lfp[0]->Next) // See Note above
+ lfp[0] = lfp[0]->Next;
+
+ Arg(0) = lfp[0];
+ lfp[0]->Next = this;
+ break;
+ case OP_OR:
+ nosep = TRUE;
+ case OP_AND:
+ for (i = 0; i < 2; i++) {
+ if (GetArgType(i) == TYPE_FILTER) {
+ lfp[i] = (PFIL)Arg(i);
+ ffp[i] = lfp[i]->Linearize(nosep);
+ } /* endif */
+
+ if (!ffp[i])
+ return NULL;
+
+ while (lfp[i]->Next)
+ lfp[i] = lfp[i]->Next;
+
+ Arg(i) = lfp[i];
+ } /* endfor i */
+
+ if (nosep) {
+ lfp[0]->Next = ffp[1];
+ lfp[1]->Next = this;
+ } else {
+ lfp[0]->Next = this;
+ Opc = OP_SEP;
+ Arg(1) = pXVOID;
+ Next = ffp[1];
+ } /* endif */
+
+ break;
+ default:
+ ffp[0] = this;
+ } /* endswitch */
+
+ return (ffp[0]);
+ } // end of Linearize
+
+/***********************************************************************/
+/* Link the fil2 filter chain to the fil1(this) filter chain. */
+/***********************************************************************/
+PFIL FILTER::Link(PGLOBAL g, PFIL fil2)
+ {
+ PFIL fil1;
+
+ if (trace(1))
+ htrc("Linking filter %p with op=%d... to filter %p with op=%d\n",
+ this, Opc, fil2, (fil2) ? fil2->Opc : 0);
+
+ for (fil1 = this; fil1->Next; fil1 = fil1->Next) ;
+
+ if (fil1->Opc == OP_SEP)
+ fil1->Next = fil2; // Separator already exists
+ else {
+ // Create a filter separator and insert it between the chains
+ PFIL filp = new(g) FILTER(g, OP_SEP);
+
+ filp->Arg(0) = fil1;
+ filp->Next = fil2;
+ fil1->Next = filp;
+ } // endelse
+
+ return (this);
+ } // end of Link
+
+/***********************************************************************/
+/* Remove eventual last separator from a filter chain. */
+/***********************************************************************/
+PFIL FILTER::RemoveLastSep(void)
+ {
+ PFIL filp, gfp = NULL;
+
+ // Find last filter block (filp) and previous one (gfp).
+ for (filp = this; filp->Next; filp = filp->Next)
+ gfp = filp;
+
+ // If last filter is a separator, remove it
+ if (filp->Opc == OP_SEP)
+ if (gfp)
+ gfp->Next = NULL;
+ else
+ return NULL; // chain is now empty
+
+ return this;
+ } // end of RemoveLastSep
+
+/***********************************************************************/
+/* CheckColumn: Checks references to Columns in the filter and change */
+/* them into references to Col Blocks. */
+/* Returns the number of column references or -1 in case of column */
+/* not found and -2 in case of unrecoverable error. */
+/* WHERE filters are called with *aggreg == AGG_NO. */
+/* HAVING filters are called with *aggreg == AGG_ANY. */
+/***********************************************************************/
+int FILTER::CheckColumn(PGLOBAL g, PSQL sqlp, PXOB &p, int &ag)
+ {
+ char errmsg[MAX_STR] = "";
+ int agg, k, n = 0;
+
+ if (trace(1))
+ htrc("FILTER CheckColumn: sqlp=%p ag=%d\n", sqlp, ag);
+
+ switch (Opc) {
+ case OP_SEP:
+ case OP_AND:
+ case OP_OR:
+ case OP_NOT:
+ return 0; // This because we are called for a linearized filter
+ default:
+ break;
+ } // endswitch Opc
+
+ // Check all arguments even in case of error for when we are called
+ // from CheckHaving, where references to an alias raise an error but
+ // we must have all other arguments to be set.
+ for (int i = 0; i < 2; i++) {
+ if (GetArgType(i) == TYPE_FILTER) // Should never happen in
+ return 0; // current implementation
+
+ agg = ag;
+
+ if ((k = Arg(i)->CheckColumn(g, sqlp, Arg(i), agg)) < -1) {
+ return k;
+ } else if (k < 0) {
+ if (!*errmsg) // Keep first error message
+ strcpy(errmsg, g->Message);
+
+ } else
+ n += k;
+
+ } // endfor i
+
+ if (*errmsg) {
+ strcpy(g->Message, errmsg);
+ return -1;
+ } else
+ return n;
+
+ } // end of CheckColumn
+
+/***********************************************************************/
+/* RefNum: Find the number of references correlated sub-queries make */
+/* to the columns of the outer query (pointed by sqlp). */
+/***********************************************************************/
+int FILTER::RefNum(PSQL sqlp)
+ {
+ int n = 0;
+
+ for (int i = 0; i < 2; i++)
+ n += Arg(i)->RefNum(sqlp);
+
+ return n;
+ } // end of RefNum
+
+/***********************************************************************/
+/* CheckSubQuery: see SUBQUERY::CheckSubQuery for comment. */
+/***********************************************************************/
+PXOB FILTER::CheckSubQuery(PGLOBAL g, PSQL sqlp)
+ {
+ switch (Opc) {
+ case OP_SEP:
+ case OP_AND:
+ case OP_OR:
+ case OP_NOT:
+ break;
+ default:
+ for (int i = 0; i < 2; i++)
+ if (!(Arg(i) = (PXOB)Arg(i)->CheckSubQuery(g, sqlp)))
+ return NULL;
+
+ break;
+ } // endswitch Opc
+
+ return this;
+ } // end of CheckSubQuery
+
+/***********************************************************************/
+/* SortJoin: function that places ahead of the list the 'good' groups */
+/* for join filtering. These are groups with only one filter that */
+/* specify equality between two different table columns, at least */
+/* one is a table key column. Doing so the join filter will be in */
+/* general compatible with linearization of the joined table tree. */
+/* This function has been added a further sorting on column indexing. */
+/***********************************************************************/
+PFIL FILTER::SortJoin(PGLOBAL g)
+ {
+ int k;
+ PCOL cp1, cp2;
+ PTDBASE tp1, tp2;
+ PFIL fp, filp, gfp, filstart = this, filjoin = NULL, lfp = NULL;
+ bool join = TRUE, key = TRUE;
+
+ // This routine requires that the chain ends with a separator
+ // So check for it and eventually add one if necessary
+ for (filp = this; filp->Next; filp = filp->Next) ;
+
+ if (filp->Opc != OP_SEP)
+ filp->Next = new(g) FILTER(g, OP_SEP);
+
+ again:
+ for (k = (key) ? 0 : MAX_MULT_KEY; k <= MAX_MULT_KEY; k++)
+ for (gfp = NULL, fp = filp = filstart; filp; filp = filp->Next)
+ switch (filp->Opc) {
+ case OP_SEP:
+ if (join) {
+ // Put this filter group into the join filter group list.
+ if (!lfp)
+ filjoin = fp;
+ else
+ lfp->Next = fp;
+
+ if (!gfp)
+ filstart = filp->Next;
+ else
+ gfp->Next = filp->Next;
+
+ lfp = filp; // last block of join filter list
+ } else
+ gfp = filp; // last block of bad filter list
+
+ join = TRUE;
+ fp = filp->Next;
+ break;
+ case OP_LOJ:
+ case OP_ROJ:
+ case OP_DTJ:
+ join &= TRUE;
+ break;
+ case OP_EQ:
+ if (join && k > 0 // So specific join operators come first
+ && filp->GetArgType(0) == TYPE_COLBLK
+ && filp->GetArgType(1) == TYPE_COLBLK) {
+ cp1 = (PCOL)filp->Arg(0);
+ cp2 = (PCOL)filp->Arg(1);
+ tp1 = (PTDBASE)cp1->GetTo_Tdb();
+ tp2 = (PTDBASE)cp2->GetTo_Tdb();
+
+ if (tp1->GetTdb_No() != tp2->GetTdb_No()) {
+ if (key)
+ join &= (cp1->GetKey() == k || cp2->GetKey() == k);
+ else
+ join &= (tp1->GetColIndex(cp1) || tp2->GetColIndex(cp2));
+
+ } else
+ join = FALSE;
+
+ } else
+ join = FALSE;
+
+ break;
+ default:
+ join = FALSE;
+ } // endswitch filp->Opc
+
+ if (key) {
+ key = FALSE;
+ goto again;
+ } // endif key
+
+ if (filjoin) {
+ lfp->Next = filstart;
+ filstart = filjoin;
+ } // endif filjoin
+
+ // Removing last separator is perhaps unuseful, but it was so
+ return filstart->RemoveLastSep();
+ } // end of SortJoin
+
+/***********************************************************************/
+/* Check that this filter is a good join filter. */
+/* If so the opj block will be set accordingly. */
+/* opj points to the join block, fprec to the filter block to which */
+/* the rest of the chain must be linked in case of success. */
+/* teq, tek and tk2 indicates the severity of the tests: */
+/* tk2 == TRUE means both columns must be primary keys. */
+/* tc2 == TRUE means both args must be columns (not expression). */
+/* tek == TRUE means at least one column must be a primary key. */
+/* teq == TRUE means the filter operator must be OP_EQ. */
+/* tix == TRUE means at least one column must be a simple index key. */
+/* thx == TRUE means at least one column must be a leading index key. */
+/***********************************************************************/
+bool FILTER::FindJoinFilter(POPJOIN opj, PFIL fprec, bool teq, bool tek,
+ bool tk2, bool tc2, bool tix, bool thx)
+ {
+ if (trace(1))
+ htrc("FindJoinFilter: opj=%p fprec=%p tests=(%d,%d,%d,%d)\n",
+ opj, fprec, teq, tek, tk2, tc2);
+
+ // Firstly check that this filter is an independent filter
+ // meaning that it is the only one in its own group.
+ if (Next && Next->Opc != OP_SEP)
+ return (Opc < 0);
+
+ // Keep only equi-joins and specific joins (Outer and Distinct)
+ // Normally specific join operators comme first because they have
+ // been placed first by SortJoin.
+ if (teq && Opc > OP_EQ)
+ return FALSE;
+
+ // We have a candidate for join filter, now check that it
+ // fulfil the requirement about its operands, to point to
+ // columns of respectively the two TDB's of that join.
+ int col1 = 0, col2 = 0;
+ bool key = tk2;
+ bool idx = FALSE, ihx = FALSE;
+ PIXDEF pdx;
+
+ for (int i = 0; i < 2; i++)
+ if (GetArgType(i) == TYPE_COLBLK) {
+ PCOL colp = (PCOL)Arg(i);
+
+ if (tk2)
+ key &= (colp->IsKey());
+ else
+ key |= (colp->IsKey());
+
+ pdx = ((PTDBASE)colp->GetTo_Tdb())->GetColIndex(colp);
+ idx |= (pdx && pdx->GetNparts() == 1);
+ ihx |= (pdx != NULL);
+
+ if (colp->VerifyColumn(opj->GetTbx1()))
+ col1 = i + 1;
+ else if (colp->VerifyColumn(opj->GetTbx2()))
+ col2 = i + 1;
+
+ } else if (!tc2 && GetArgType(i) != TYPE_CONST) {
+ PXOB xp = Arg(i);
+
+ if (xp->VerifyColumn(opj->GetTbx1()))
+ col1 = i + 1;
+ else if (xp->VerifyColumn(opj->GetTbx2()))
+ col2 = i + 1;
+
+ } else
+ return (Opc < 0);
+
+ if (col1 == 0 || col2 == 0)
+ return (Opc < 0);
+
+ if (((tek && !key) || (tix && !idx) || (thx && !ihx)) && Opc != OP_DTJ)
+ return FALSE;
+
+ // This is the join filter, set the join block.
+ if (col1 == 1) {
+ opj->SetCol1(Arg(0));
+ opj->SetCol2(Arg(1));
+ } else {
+ opj->SetCol1(Arg(1));
+ opj->SetCol2(Arg(0));
+
+ switch (Opc) {
+// case OP_GT: Opc = OP_LT; break;
+// case OP_LT: Opc = OP_GT; break;
+// case OP_GE: Opc = OP_LE; break;
+// case OP_LE: Opc = OP_GE; break;
+ case OP_LOJ:
+ case OP_ROJ:
+ case OP_DTJ:
+ // For expended join operators, the filter must indicate
+ // the way the join should be done, and not the order of
+ // appearance of tables in the table list (which is kept
+ // because tables are sorted in AddTdb). Therefore the
+ // join is inversed, not the filter.
+ opj->InverseJoin();
+ default: break;
+ } // endswitch Opc
+
+ } // endif col1
+
+ if (Opc < 0) {
+ // For join operators, special processing is needed
+ int knum = 0;
+ PFIL fp;
+
+ switch (Opc) {
+ case OP_LOJ:
+ opj->SetJtype(JT_LEFT);
+ knum = opj->GetCol2()->GetKey();
+ break;
+ case OP_ROJ:
+ opj->SetJtype(JT_RIGHT);
+ knum = opj->GetCol1()->GetKey();
+ break;
+ case OP_DTJ:
+ for (knum = 1, fp = this->Next; fp; fp = fp->Next)
+ if (fp->Opc == OP_DTJ)
+ knum++;
+ else if (fp->Opc != OP_SEP)
+ break;
+
+ opj->SetJtype(JT_DISTINCT);
+ opj->GetCol2()->SetKey(knum);
+ break;
+ default:
+ break;
+ } // endswitch Opc
+
+ if (knum > 1) {
+ // Lets take care of a multiple key join
+ // We do a minimum of checking here as it will done later
+ int k = 1;
+ OPVAL op;
+ BYTE tmp[sizeof(Test[0])];
+
+ for (fp = this->Next; k < knum && fp; fp = fp->Next) {
+ switch (op = fp->Opc) {
+ case OP_SEP:
+ continue;
+ case OP_LOJ:
+ if (Opc == OP_ROJ) {
+ op = Opc;
+ memcpy(tmp, &fp->Test[0], sizeof(Test[0]));
+ fp->Test[0] = fp->Test[1];
+ memcpy(&fp->Test[1], tmp, sizeof(Test[0]));
+ } // endif Opc
+
+ k++;
+ break;
+ case OP_ROJ:
+ if (Opc == OP_LOJ) {
+ op = Opc;
+ memcpy(tmp, &fp->Test[0], sizeof(Test[0]));
+ fp->Test[0] = fp->Test[1];
+ memcpy(&fp->Test[1], tmp, sizeof(Test[0]));
+ } // endif Opc
+
+ k++;
+ break;
+ case OP_DTJ:
+ if (op == Opc && fp->GetArgType(1) == TYPE_COLBLK)
+ ((PCOL)fp->Arg(1))->SetKey(knum);
+
+ k++;
+ break;
+ default:
+ break;
+ } // endswitch op
+
+ if (op != Opc)
+ return TRUE;
+
+ fp->Opc = OP_EQ;
+ } // endfor fp
+
+ } // endif k
+
+ Opc = OP_EQ;
+ } // endif Opc
+
+ // Set the join filter operator
+ opj->SetOpc(Opc);
+
+ // Now mark the columns involved in the join filter because
+ // this information will be used by the linearize program.
+ // Note: this should be replaced in the future by something
+ // enabling to mark tables as Parent or Child.
+ opj->GetCol1()->MarkCol(U_J_EXT);
+ opj->GetCol2()->MarkCol(U_J_EXT);
+
+ // Remove the filter from the filter chain. If the filter is
+ // not last in the chain, also remove the SEP filter after it.
+ if (Next) // Next->Opc == OP_SEP
+ Next = Next->Next;
+
+ if (!fprec)
+ opj->SetFilter(Next);
+ else
+ fprec->Next = Next;
+
+ return FALSE;
+ } // end of FindJoinFilter
+
+/***********************************************************************/
+/* CheckHaving: check and process a filter of an HAVING clause. */
+/* Check references to Columns and Functions in the filter. */
+/* All these references can correspond to items existing in the */
+/* SELECT list, else if it is a function, allocate a SELECT block */
+/* to be added to the To_Sel list (non projected blocks). */
+/***********************************************************************/
+bool FILTER::CheckHaving(PGLOBAL g, PSQL sqlp)
+ {
+ int agg = AGG_ANY;
+ PXOB xp;
+
+//sqlp->SetOk(TRUE); // Ok to look into outer queries for filters
+
+ switch (Opc) {
+ case OP_SEP:
+ case OP_AND:
+ case OP_OR:
+ case OP_NOT:
+ return FALSE;
+ default:
+ if (CheckColumn(g, sqlp, xp, agg) < -1)
+ return TRUE; // Unrecovable error
+
+ break;
+ } // endswitch Opc
+
+ sqlp->SetOk(TRUE); // Ok to look into outer queries for filters
+
+ for (int i = 0; i < 2; i++)
+ if (!(xp = Arg(i)->SetSelect(g, sqlp, TRUE)))
+ return TRUE;
+ else if (xp != Arg(i)) {
+ Arg(i) = xp;
+ Val(i) = Arg(i)->GetValue();
+ } // endif
+
+ sqlp->SetOk(FALSE);
+ return FALSE;
+ } // end of CheckHaving
+
+/***********************************************************************/
+/* Used while building a table index. This function split the filter */
+/* attached to the tdbp table into the local and not local part. */
+/* The local filter is used to restrict the size of the index and the */
+/* not local part remains to be executed later. This has been added */
+/* recently and not only to improve the performance but chiefly to */
+/* avoid loosing rows when processing distinct joins. */
+/* Returns: */
+/* 0: the whole filter is local (both arguments are) */
+/* 1: the whole filter is not local */
+/* 2: the filter was split in local (attached to fp[0]) and */
+/* not local (attached to fp[1]). */
+/***********************************************************************/
+int FILTER::SplitFilter(PFIL *fp)
+ {
+ int i, rc[2];
+
+ if (Opc == OP_AND) {
+ for (i = 0; i < 2; i++)
+ rc[i] = ((PFIL)Arg(i))->SplitFilter(fp);
+
+ // Filter first argument should never be split because of the
+ // algorithm used to de-linearize the filter.
+ assert(rc[0] != 2);
+
+ if (rc[0] != rc[1]) {
+ // Splitting to be done
+ if (rc[1] == 2) {
+ // 2nd argument already split, add 1st to the proper filter
+ assert(fp[*rc]);
+ Arg(1) = fp[*rc];
+ Val(1) = fp[*rc]->GetValue();
+ fp[*rc] = this;
+ } else for (i = 0; i < 2; i++) {
+ // Split the filter arguments
+ assert(!fp[rc[i]]);
+ fp[rc[i]] = (PFIL)Arg(i);
+ } // endfor i
+
+ *rc = 2;
+ } // endif rc
+
+ } else
+ *rc = (CheckLocal(NULL)) ? 0 : 1;
+
+ return *rc;
+ } // end of SplitFilter
+
+/***********************************************************************/
+/* This function is called when making a Kindex after the filter was */
+/* split in local and nolocal part in the case of many to many joins. */
+/* Indeed the whole filter must be reconstructed to take care of next */
+/* same values when doing the explosive join. In addition, the link */
+/* must be done respecting the way filters are de-linearized, no AND */
+/* filter in the first argument of an AND filter, because this is */
+/* expected to be true if SplitFilter is used again on this filter. */
+/***********************************************************************/
+PFIL FILTER::LinkFilter(PGLOBAL g, PFIL fp2)
+ {
+ PFIL fp1, filp, filand = NULL;
+
+ assert(fp2); // Test must be made by caller
+
+ // Find where the new AND filter must be attached
+ for (fp1 = this; fp1->Opc == OP_AND; fp1 = (PFIL)fp1->Arg(1))
+ filand = fp1;
+
+ filp = new(g) FILTER(g, OP_AND);
+ filp->Arg(0) = fp1;
+ filp->Val(0) = fp1->GetValue();
+ filp->Test[0].B_T = TYPE_INT;
+ filp->Test[0].Conv = FALSE;
+ filp->Arg(1) = fp2;
+ filp->Val(1) = fp2->GetValue();
+ filp->Test[1].B_T = TYPE_INT;
+ filp->Test[1].Conv = FALSE;
+ filp->Value = AllocateValue(g, TYPE_INT);
+
+ if (filand) {
+ // filp must be inserted here
+ filand->Arg(1) = filp;
+ filand->Val(1) = filp->GetValue();
+ filp = this;
+ } // endif filand
+
+ return filp;
+ } // end of LinkFilter
+
+/***********************************************************************/
+/* Checks whether filter contains reference to a previous table that */
+/* is not logically joined to the currently opened table, or whether */
+/* it is a Sub-Select filter. In any case, local is set to FALSE. */
+/* Note: This function is now applied to de-linearized filters. */
+/***********************************************************************/
+bool FILTER::CheckLocal(PTDB tdbp)
+ {
+ bool local = TRUE;
+
+ if (trace(1)) {
+ if (tdbp)
+ htrc("CheckLocal: filp=%p R%d\n", this, tdbp->GetTdb_No());
+ else
+ htrc("CheckLocal: filp=%p\n", this);
+ } // endif trace
+
+ for (int i = 0; local && i < 2; i++)
+ local = Arg(i)->CheckLocal(tdbp);
+
+ if (trace(1))
+ htrc("FCL: returning %d\n", local);
+
+ return (local);
+ } // end of CheckLocal
+
+/***********************************************************************/
+/* This routine is used to split the filter attached to the tdbp */
+/* table into the local and not local part where "local" means that */
+/* it applies "locally" to the FILEID special column with crit = 2 */
+/* and to the SERVID and/or TABID special columns with crit = 3. */
+/* Returns: */
+/* 0: the whole filter is local (both arguments are) */
+/* 1: the whole filter is not local */
+/* 2: the filter was split in local (attached to fp[0]) and */
+/* not local (attached to fp[1]). */
+/* Note: "Locally" means that the "local" filter can be evaluated */
+/* before opening the table. This implies that the special column be */
+/* compared only with constants and that this filter not to be or'ed */
+/* with a non "local" filter. */
+/***********************************************************************/
+int FILTER::SplitFilter(PFIL *fp, PTDB tp, int crit)
+ {
+ int i, rc[2];
+
+ if (Opc == OP_AND) {
+ for (i = 0; i < 2; i++)
+ rc[i] = ((PFIL)Arg(i))->SplitFilter(fp, tp, crit);
+
+ // Filter first argument should never be split because of the
+ // algorithm used to de-linearize the filter.
+ assert(rc[0] != 2);
+
+ if (rc[0] != rc[1]) {
+ // Splitting to be done
+ if (rc[1] == 2) {
+ // 2nd argument already split, add 1st to the proper filter
+ assert(fp[*rc]);
+ Arg(1) = fp[*rc];
+ Val(1) = fp[*rc]->GetValue();
+ fp[*rc] = this;
+ } else for (i = 0; i < 2; i++) {
+ // Split the filter arguments
+ assert(!fp[rc[i]]);
+ fp[rc[i]] = (PFIL)Arg(i);
+ } // endfor i
+
+ *rc = 2;
+ } // endif rc
+
+ } else
+ *rc = (CheckSpcCol(tp, crit) == 1) ? 0 : 1;
+
+ return *rc;
+ } // end of SplitFilter
+
+/***********************************************************************/
+/* Checks whether filter contains only references to FILEID, SERVID, */
+/* or TABID with constants or pseudo constants. */
+/***********************************************************************/
+int FILTER::CheckSpcCol(PTDB tdbp, int n)
+ {
+ int n1 = Arg(0)->CheckSpcCol(tdbp, n);
+ int n2 = Arg(1)->CheckSpcCol(tdbp, n);
+
+ return max(n1, n2);
+ } // end of CheckSpcCol
+#endif // 0
+
+/***********************************************************************/
+/* Reset the filter arguments to non evaluated yet. */
+/***********************************************************************/
+void FILTER::Reset(void)
+ {
+ for (int i = 0; i < 2; i++)
+ Arg(i)->Reset();
+
+ } // end of Reset
+
+/***********************************************************************/
+/* Init: called when reinitializing a query (Correlated subqueries) */
+/***********************************************************************/
+bool FILTER::Init(PGLOBAL g)
+ {
+ for (int i = 0; i < 2; i++)
+ Arg(i)->Init(g);
+
+ return FALSE;
+ } // end of Init
+
+/***********************************************************************/
+/* Convert: does all filter setting and conversions. */
+/* (having = TRUE for Having Clauses, FALSE for Where Clauses) */
+/* Note: hierarchy of types is implied by the ConvertType */
+/* function, currently FLOAT, int, STRING and TOKEN. */
+/* Returns FALSE if successful or TRUE in case of error. */
+/* Note on result type for filters: */
+/* Currently the result type is of TYPE_INT (should be TYPE_BOOL). */
+/* This avoids to introduce a new type and perhaps will permit */
+/* conversions. However the boolean operators will result in a */
+/* boolean int result, meaning that result shall be only 0 or 1 . */
+/***********************************************************************/
+bool FILTER::Convert(PGLOBAL g, bool having)
+ {
+ int i, comtype = TYPE_ERROR;
+
+ if (trace(1))
+ htrc("converting(?) %s %p opc=%d\n",
+ (having) ? "having" : "filter", this, Opc);
+
+ for (i = 0; i < 2; i++) {
+ switch (GetArgType(i)) {
+ case TYPE_COLBLK:
+ if (((PCOL)Arg(i))->InitValue(g))
+ return TRUE;
+
+ break;
+ case TYPE_ARRAY:
+ if ((Opc != OP_IN && !Opm) || i == 0) {
+ strcpy(g->Message, MSG(BAD_ARRAY_OPER));
+ return TRUE;
+ } // endif
+
+ if (((PARRAY)Arg(i))->Sort(g)) // Sort the array
+ return TRUE; // Error
+
+ break;
+ case TYPE_VOID:
+ if (i == 1) {
+ Val(0) = Arg(0)->GetValue();
+ goto TEST; // Filter has only one argument
+ } // endif i
+
+ strcpy(g->Message, MSG(VOID_FIRST_ARG));
+ return TRUE;
+ } // endswitch
+
+ if (trace(1))
+ htrc("Filter(%d): Arg type=%d\n", i, GetArgType(i));
+
+ // Set default values
+ Test[i].B_T = Arg(i)->GetResultType();
+ Test[i].Conv = FALSE;
+
+ // Special case of the LIKE operator.
+ if (Opc == OP_LIKE) {
+ if (!IsTypeChar((int)Test[i].B_T)) {
+ sprintf(g->Message, MSG(BAD_TYPE_LIKE), i, Test[i].B_T);
+ return TRUE;
+ } // endif
+
+ comtype = TYPE_STRING;
+ } else {
+ // Set the common type for both (eventually converted) arguments
+ int argtyp = Test[i].B_T;
+
+ if (GetArgType(i) == TYPE_CONST && argtyp == TYPE_INT) {
+ // If possible, downcast the type to smaller types to avoid
+ // convertion as much as possible.
+ int n = Arg(i)->GetValue()->GetIntValue();
+
+ if (n >= INT_MIN8 && n <= INT_MAX8)
+ argtyp = TYPE_TINY;
+ else if (n >= INT_MIN16 && n <= INT_MAX16)
+ argtyp = TYPE_SHORT;
+
+ } else if (GetArgType(i) == TYPE_ARRAY) {
+ // If possible, downcast int arrays target type to TYPE_SHORT
+ // to take care of filters written like shortcol in (34,35,36).
+ if (((PARRAY)Arg(i))->CanBeShort())
+ argtyp = TYPE_SHORT;
+
+ } // endif TYPE_CONST
+
+ comtype = ConvertType(comtype, argtyp, CNV_ANY);
+ } // endif Opc
+
+ if (comtype == TYPE_ERROR) {
+ strcpy(g->Message, MSG(ILL_FILTER_CONV));
+ return TRUE;
+ } // endif
+
+ if (trace(1))
+ htrc(" comtype=%d, B_T(%d)=%d Val(%d)=%p\n",
+ comtype, i, Test[i].B_T, i, Val(i));
+
+ } // endfor i
+
+ // Set or allocate the filter argument values and buffers
+ for (i = 0; i < 2; i++) {
+ if (trace(1))
+ htrc(" conv type %d ? i=%d B_T=%d comtype=%d\n",
+ GetArgType(i), i, Test[i].B_T, comtype);
+
+ if (Test[i].B_T == comtype) {
+ // No conversion, set Value to argument Value
+ Val(i) = Arg(i)->GetValue();
+#if defined(_DEBUG)
+ assert (Val(i) && Val(i)->GetType() == Test[i].B_T);
+#endif
+ } else {
+ // Conversion between filter arguments to be done.
+ // Note that the argument must be converted, not only the
+ // buffer and buffer type, so GetArgType() returns the new type.
+ switch (GetArgType(i)) {
+ case TYPE_CONST:
+ if (comtype == TYPE_DATE && Test[i].B_T == TYPE_STRING) {
+ // Convert according to the format of the other argument
+ Val(i) = AllocateValue(g, comtype, Arg(i)->GetLength());
+
+ if (((DTVAL*)Val(i))->SetFormat(g, Val(1-i)))
+ return TRUE;
+
+ Val(i)->SetValue_psz(Arg(i)->GetValue()->GetCharValue());
+ } else {
+ ((PCONST)Arg(i))->Convert(g, comtype);
+ Val(i) = Arg(i)->GetValue();
+ } // endif comtype
+
+ break;
+ case TYPE_ARRAY:
+ // Conversion PSZ or int array to int or double FLOAT.
+ if (((PARRAY)Arg(i))->Convert(g, comtype, Val(i-1)) == TYPE_ERROR)
+ return TRUE;
+
+ break;
+ case TYPE_FILTER:
+ strcpy(g->Message, MSG(UNMATCH_FIL_ARG));
+ return TRUE;
+ default:
+ // Conversion from Column, Select/Func, Expr, Scalfnc...
+ // The argument requires conversion during Eval
+ // A separate Value block must be allocated.
+ // Note: the test on comtype is to prevent unnecessary
+ // domain initialization and get the correct length in
+ // case of Token -> numeric conversion.
+ Val(i) = AllocateValue(g, comtype, (comtype == TYPE_STRING)
+ ? Arg(i)->GetLengthEx() : Arg(i)->GetLength());
+
+ if (comtype == TYPE_DATE && Test[i].B_T == TYPE_STRING)
+ // Convert according to the format of the other argument
+ if (((DTVAL*)Val(i))->SetFormat(g, Val(1 - i)))
+ return TRUE;
+
+ Test[i].Conv = TRUE;
+ break;
+ } // endswitch GetType
+
+ Test[i].B_T = comtype;
+ } // endif comtype
+
+ } // endfor i
+
+ // Last check to be sure all is correct.
+ if (Test[0].B_T != Test[1].B_T) {
+ sprintf(g->Message, MSG(BAD_FILTER_CONV), Test[0].B_T, Test[1].B_T);
+ return TRUE;
+//} else if (Test[0].B_T == TYPE_LIST &&
+// ((LSTVAL*)Val(0))->GetN() != ((LSTVAL*)Val(1))->GetN()) {
+// sprintf(g->Message, MSG(ROW_ARGNB_ERR),
+// ((LSTVAL*)Val(0))->GetN(), ((LSTVAL*)Val(1))->GetN());
+// return TRUE;
+ } // endif's B_T
+
+
+ TEST: // Test for possible Eval optimization
+
+ if (trace(1))
+ htrc("Filp %p op=%d argtypes=(%d,%d)\n",
+ this, Opc, GetArgType(0), GetArgType(1));
+
+ // Check whether we have a "simple" filter and in that case
+ // change its class so an optimized Eval function will be used
+ if (!Test[0].Conv && !Test[1].Conv) {
+ if (Opm) switch (Opc) {
+ case OP_EQ:
+ case OP_NE:
+ case OP_GT:
+ case OP_GE:
+ case OP_LT:
+ case OP_LE:
+ if (GetArgType(1) != TYPE_ARRAY)
+ break; // On subquery, do standard processing
+
+ // Change the FILTER class to FILTERIN
+ new(this) FILTERIN;
+ break;
+ default:
+ break;
+ } // endswitch Opc
+
+ else switch (Opc) {
+#if 0
+ case OP_EQ: new(this) FILTEREQ; break;
+ case OP_NE: new(this) FILTERNE; break;
+ case OP_GT: new(this) FILTERGT; break;
+ case OP_GE: new(this) FILTERGE; break;
+ case OP_LT: new(this) FILTERLT; break;
+ case OP_LE: new(this) FILTERLE; break;
+#endif // 0
+ case OP_EQ:
+ case OP_NE:
+ case OP_GT:
+ case OP_GE:
+ case OP_LT:
+ case OP_LE: new(this) FILTERCMP(g); break;
+ case OP_AND: new(this) FILTERAND; break;
+ case OP_OR: new(this) FILTEROR; break;
+ case OP_NOT: new(this) FILTERNOT; break;
+ case OP_EXIST:
+ if (GetArgType(1) == TYPE_VOID) {
+ // For EXISTS it is the first argument that should be null
+ Arg(1) = Arg(0);
+ Arg(0) = pXVOID;
+ } // endif void
+
+ // fall through
+ case OP_IN:
+ // For IN operator do optimize if operand is an array
+ if (GetArgType(1) != TYPE_ARRAY)
+ break; // IN on subquery, do standard processing
+
+ // Change the FILTER class to FILTERIN
+ new(this) FILTERIN;
+ break;
+ default:
+ break;
+ } // endswitch Opc
+
+ } // endif Conv
+
+ // The result value (should be TYPE_BOOL ???)
+ Value = AllocateValue(g, TYPE_INT);
+ return FALSE;
+ } // end of Convert
+
+/***********************************************************************/
+/* Eval: Compute filter result value. */
+/* New algorithm: evaluation is now done from the root for each group */
+/* so Eval is now a recursive process for FILTER operands. */
+/***********************************************************************/
+bool FILTER::Eval(PGLOBAL g)
+ {
+ int i; // n = 0;
+//PSUBQ subp = NULL;
+ PARRAY ap = NULL;
+
+ (void) PlgGetUser(g);
+
+ if (Opc <= OP_XX)
+ {
+ for (i = 0; i < 2; i++)
+ {
+ // Evaluate the object and eventually convert it.
+ if (Arg(i)->Eval(g))
+ return TRUE;
+ else if (Test[i].Conv)
+ Val(i)->SetValue_pval(Arg(i)->GetValue());
+ }
+ }
+
+ if (trace(1))
+ htrc(" Filter: op=%d type=%d %d B_T=%d %d val=%p %p\n",
+ Opc, GetArgType(0), GetArgType(1), Test[0].B_T, Test[1].B_T,
+ Val(0), Val(1));
+
+ // Main switch on filtering according to operator type.
+ switch (Opc) {
+ case OP_EQ:
+ case OP_NE:
+ case OP_GT:
+ case OP_GE:
+ case OP_LT:
+ case OP_LE:
+ if (!Opm) {
+ // Comparison boolean operators.
+#if defined(_DEBUG)
+ if (Val(0)->GetType() != Val(1)->GetType())
+ goto FilterError;
+#endif
+ // Compare the two arguments
+ // New algorithm to take care of TYPE_LIST
+ Bt = OpBmp(g, Opc);
+ Value->SetValue_bool(!(Val(0)->TestValue(Val(1)) & Bt));
+ break;
+ } // endif Opm
+
+ // For modified operators, pass thru
+ /* fall through */
+ case OP_IN:
+ case OP_EXIST:
+ // For IN operations, special processing is done here
+ switch (GetArgType(1)) {
+ case TYPE_ARRAY:
+ ap = (PARRAY)Arg(1);
+ break;
+ default:
+ strcpy(g->Message, MSG(IN_WITHOUT_SUB));
+ goto FilterError;
+ } // endswitch Type
+
+ if (trace(1)) {
+ htrc(" IN filtering: ap=%p\n", ap);
+
+ if (ap)
+ htrc(" Array: type=%d size=%d other_type=%d\n",
+ ap->GetType(), ap->GetSize(), Test[0].B_T);
+
+ } // endif trace
+
+ /*****************************************************************/
+ /* Implementation note: The Find function is now able to do a */
+ /* conversion but limited to SHORT, int, and FLOAT arrays. */
+ /*****************************************************************/
+// Value->SetValue_bool(ap->Find(g, Val(0)));
+
+ if (ap)
+ Value->SetValue_bool(ap->FilTest(g, Val(0), Opc, Opm));
+
+ break;
+
+ case OP_LIKE:
+#if defined(_DEBUG)
+ if (!IsTypeChar((int)Test[0].B_T) || !IsTypeChar((int)Test[1].B_T))
+ goto FilterError;
+#endif
+ if (Arg(0)->Eval(g))
+ return TRUE;
+
+ Value->SetValue_bool(PlugEvalLike(g, Val(0)->GetCharValue(),
+ Val(1)->GetCharValue(),
+ Val(0)->IsCi()));
+ break;
+
+ case OP_AND:
+#if defined(_DEBUG)
+ if (Test[0].B_T != TYPE_INT || Test[1].B_T != TYPE_INT)
+ goto FilterError;
+#endif
+
+ if (Arg(0)->Eval(g))
+ return TRUE;
+
+ Value->SetValue(Val(0)->GetIntValue());
+
+ if (!Value->GetIntValue())
+ return FALSE; // No need to evaluate 2nd argument
+
+ if (Arg(1)->Eval(g))
+ return TRUE;
+
+ Value->SetValue(Val(1)->GetIntValue());
+ break;
+
+ case OP_OR:
+#if defined(_DEBUG)
+ if (Test[0].B_T != TYPE_INT || Test[1].B_T != TYPE_INT)
+ goto FilterError;
+#endif
+
+ if (Arg(0)->Eval(g))
+ return TRUE;
+
+ Value->SetValue(Val(0)->GetIntValue());
+
+ if (Value->GetIntValue())
+ return FALSE; // No need to evaluate 2nd argument
+
+ if (Arg(1)->Eval(g))
+ return TRUE;
+
+ Value->SetValue(Val(1)->GetIntValue());
+ break;
+
+ case OP_NOT:
+#if defined(_DEBUG)
+ if (Test[0].B_T != TYPE_INT) // Should be type bool ???
+ goto FilterError;
+#endif
+
+ if (Arg(0)->Eval(g))
+ return TRUE;
+
+ Value->SetValue_bool(!Val(0)->GetIntValue());
+ break;
+
+ case OP_SEP: // No more used while evaluating
+ default:
+ goto FilterError;
+ } // endswitch Opc
+
+ if (trace(1))
+ htrc("Eval: filter %p Opc=%d result=%d\n",
+ this, Opc, Value->GetIntValue());
+
+ return FALSE;
+
+ FilterError:
+ sprintf(g->Message, MSG(BAD_FILTER),
+ Opc, Test[0].B_T, Test[1].B_T, GetArgType(0), GetArgType(1));
+ return TRUE;
+ } // end of Eval
+
+#if 0
+/***********************************************************************/
+/* Called by PlugCopyDB to make a copy of a (linearized) filter chain.*/
+/***********************************************************************/
+PFIL FILTER::Copy(PTABS t)
+ {
+ int i;
+ PFIL fil1, fil2, newfilchain = NULL, fprec = NULL;
+
+ for (fil1 = this; fil1; fil1 = fil1->Next) {
+ fil2 = new(t->G) FILTER(fil1);
+
+ if (!fprec)
+ newfilchain = fil2;
+ else
+ fprec->Next = fil2;
+
+ NewPointer(t, fil1, fil2);
+
+ for (i = 0; i < 2; i++)
+ if (fil1->GetArgType(i) == TYPE_COLBLK ||
+ fil1->GetArgType(i) == TYPE_FILTER)
+ AddPointer(t, &fil2->Arg(i));
+
+ fprec = fil2;
+ } /* endfor fil1 */
+
+ return newfilchain;
+ } // end of Copy
+#endif // 0
+
+/*********************************************************************/
+/* Make file output of FILTER contents. */
+/*********************************************************************/
+void FILTER::Printf(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+
+ bool lin = (Next != NULL); // lin == TRUE if linearized
+
+ for (PFIL fp = this; fp; fp = fp->Next) {
+ fprintf(f, "%sFILTER: at %p opc=%d lin=%d result=%d\n",
+ m, fp, fp->Opc, lin,
+ (Value) ? Value->GetIntValue() : 0);
+
+ for (int i = 0; i < 2; i++) {
+ fprintf(f, "%s Arg(%d) type=%d value=%p B_T=%d val=%p\n",
+ m, i, fp->GetArgType(i), fp->Arg(i),
+ fp->Test[i].B_T, fp->Val(i));
+
+ if (lin && fp->GetArgType(i) == TYPE_FILTER)
+ fprintf(f, "%s Filter at %p\n", m, fp->Arg(i));
+ else
+ fp->Arg(i)->Printf(g, f, n + 2);
+
+ } // endfor i
+
+ } // endfor fp
+
+ } // end of Printf
+
+/***********************************************************************/
+/* Make string output of TABLE contents (z should be checked). */
+/***********************************************************************/
+void FILTER::Prints(PGLOBAL g, char *ps, uint z)
+ {
+ #define FLEN 100
+
+ typedef struct _bc {
+ struct _bc *Next;
+ char Cold[FLEN+1];
+ } BC, *PBC;
+
+ char *p;
+ int n;
+ PFIL fp;
+ PBC bxp, bcp = NULL;
+
+ *ps = '\0';
+
+ for (fp = this; fp && z > 0; fp = fp->Next) {
+ if (fp->Opc < OP_CNC || fp->Opc == OP_IN || fp->Opc == OP_NULL
+ || fp->Opc == OP_LIKE || fp->Opc == OP_EXIST) {
+ if (!(bxp = new BC)) {
+ strncat(ps, "Filter(s)", z);
+ return;
+ } /* endif */
+
+ bxp->Next = bcp;
+ bcp = bxp;
+ p = bcp->Cold;
+ n = FLEN;
+ fp->Arg(0)->Prints(g, p, n);
+ n = FLEN - strlen(p);
+
+ switch (fp->Opc) {
+ case OP_EQ:
+ strncat(bcp->Cold, "=", n);
+ break;
+ case OP_NE:
+ strncat(bcp->Cold, "!=", n);
+ break;
+ case OP_GT:
+ strncat(bcp->Cold, ">", n);
+ break;
+ case OP_GE:
+ strncat(bcp->Cold, ">=", n);
+ break;
+ case OP_LT:
+ strncat(bcp->Cold, "<", n);
+ break;
+ case OP_LE:
+ strncat(bcp->Cold, "<=", n);
+ break;
+ case OP_IN:
+ strncat(bcp->Cold, " in ", n);
+ break;
+ case OP_NULL:
+ strncat(bcp->Cold, " is null", n);
+ break;
+ case OP_LIKE:
+ strncat(bcp->Cold, " like ", n);
+ break;
+ case OP_EXIST:
+ strncat(bcp->Cold, " exists ", n);
+ break;
+ case OP_AND:
+ strncat(bcp->Cold, " and ", n);
+ break;
+ case OP_OR:
+ strncat(bcp->Cold, " or ", n);
+ break;
+ default:
+ strncat(bcp->Cold, "?", n);
+ } // endswitch Opc
+
+ n = FLEN - strlen(p);
+ p += strlen(p);
+ fp->Arg(1)->Prints(g, p, n);
+ } else
+ if (!bcp) {
+ strncat(ps, "???", z);
+ z -= 3;
+ } else
+ switch (fp->Opc) {
+ case OP_SEP: // Filter list separator
+ strncat(ps, bcp->Cold, z);
+ z -= strlen(bcp->Cold);
+ strncat(ps, ";", z--);
+ bxp = bcp->Next;
+ delete bcp;
+ bcp = bxp;
+ break;
+ case OP_NOT: // Filter NOT operator
+ for (n = MY_MIN((int)strlen(bcp->Cold), FLEN-3); n >= 0; n--)
+ bcp->Cold[n+2] = bcp->Cold[n];
+ bcp->Cold[0] = '^';
+ bcp->Cold[1] = '(';
+ strcat(bcp->Cold, ")");
+ break;
+ default:
+ for (n = MY_MIN((int)strlen(bcp->Cold), FLEN-4); n >= 0; n--)
+ bcp->Cold[n+3] = bcp->Cold[n];
+ bcp->Cold[0] = ')';
+ switch (fp->Opc) {
+ case OP_AND: bcp->Cold[1] = '&'; break;
+ case OP_OR: bcp->Cold[1] = '|'; break;
+ default: bcp->Cold[1] = '?';
+ } // endswitch
+ bcp->Cold[2] = '(';
+ strcat(bcp->Cold, ")");
+ bxp = bcp->Next;
+ for (n = MY_MIN((int)strlen(bxp->Cold), FLEN-1); n >= 0; n--)
+ bxp->Cold[n+1] = bxp->Cold[n];
+ bxp->Cold[0] = '(';
+ strncat(bxp->Cold, bcp->Cold, FLEN-strlen(bxp->Cold));
+ delete bcp;
+ bcp = bxp;
+ } // endswitch
+
+ } // endfor fp
+
+ n = 0;
+
+ if (!bcp)
+ strncat(ps, "Null-Filter", z);
+ else do {
+ if (z > 0) {
+ if (n++ > 0) {
+ strncat(ps, "*?*", z);
+ z = MY_MAX(0, (int)z-3);
+ } // endif
+ strncat(ps, bcp->Cold, z);
+ z -= strlen(bcp->Cold);
+ } // endif
+
+ bxp = bcp->Next;
+ delete bcp;
+ bcp = bxp;
+ } while (bcp); // enddo
+
+ } // end of Prints
+
+
+/* -------------------- Derived Classes Functions -------------------- */
+
+/***********************************************************************/
+/* FILTERCMP constructor. */
+/***********************************************************************/
+FILTERCMP::FILTERCMP(PGLOBAL g)
+ {
+ Bt = OpBmp(g, Opc);
+ } // end of FILTERCMP constructor
+
+/***********************************************************************/
+/* Eval: Compute result value for comparison operators. */
+/***********************************************************************/
+bool FILTERCMP::Eval(PGLOBAL g)
+ {
+ if (Arg(0)->Eval(g) || Arg(1)->Eval(g))
+ return TRUE;
+
+ Value->SetValue_bool(!(Val(0)->TestValue(Val(1)) & Bt));
+ return FALSE;
+ } // end of Eval
+
+/***********************************************************************/
+/* Eval: Compute result value for AND filters. */
+/***********************************************************************/
+bool FILTERAND::Eval(PGLOBAL g)
+ {
+ if (Arg(0)->Eval(g))
+ return TRUE;
+
+ Value->SetValue(Val(0)->GetIntValue());
+
+ if (!Value->GetIntValue())
+ return FALSE; // No need to evaluate 2nd argument
+
+ if (Arg(1)->Eval(g))
+ return TRUE;
+
+ Value->SetValue(Val(1)->GetIntValue());
+ return FALSE;
+ } // end of Eval
+
+/***********************************************************************/
+/* Eval: Compute result value for OR filters. */
+/***********************************************************************/
+bool FILTEROR::Eval(PGLOBAL g)
+ {
+ if (Arg(0)->Eval(g))
+ return TRUE;
+
+ Value->SetValue(Val(0)->GetIntValue());
+
+ if (Value->GetIntValue())
+ return FALSE; // No need to evaluate 2nd argument
+
+ if (Arg(1)->Eval(g))
+ return TRUE;
+
+ Value->SetValue(Val(1)->GetIntValue());
+ return FALSE;
+ } // end of Eval
+
+/***********************************************************************/
+/* Eval: Compute result value for NOT filters. */
+/***********************************************************************/
+bool FILTERNOT::Eval(PGLOBAL g)
+ {
+ if (Arg(0)->Eval(g))
+ return TRUE;
+
+ Value->SetValue_bool(!Val(0)->GetIntValue());
+ return FALSE;
+ } // end of Eval
+
+/***********************************************************************/
+/* Eval: Compute result value for IN filters. */
+/***********************************************************************/
+bool FILTERIN::Eval(PGLOBAL g)
+ {
+ if (Arg(0)->Eval(g))
+ return TRUE;
+
+ Value->SetValue_bool(((PARRAY)Arg(1))->FilTest(g, Val(0), Opc, Opm));
+ return FALSE;
+ } // end of Eval
+
+/***********************************************************************/
+/* FILTERTRUE does nothing and returns TRUE. */
+/***********************************************************************/
+void FILTERTRUE::Reset(void)
+ {
+ } // end of Reset
+
+bool FILTERTRUE::Eval(PGLOBAL)
+ {
+ return FALSE;
+ } // end of Eval
+
+/* ------------------------- Friend Functions ------------------------ */
+
+#if 0
+/***********************************************************************/
+/* Prepare: prepare a filter for execution. This implies two things: */
+/* 1) de-linearize the filter to be able to evaluate it recursively. */
+/* This permit to conditionally evaluate only the first argument */
+/* of OP_OR and OP_AND filters without having to pass by an */
+/* intermediate Apply function (as this has a performance cost). */
+/* 2) do all the necessary conversion for all filter block arguments. */
+/***********************************************************************/
+PFIL PrepareFilter(PGLOBAL g, PFIL fp, bool having)
+ {
+ PFIL filp = NULL;
+
+ if (trace(1))
+ htrc("PrepareFilter: fp=%p having=%d\n", fp, having);
+
+ while (fp) {
+ if (fp->Opc == OP_SEP)
+ // If separator is not last transform it into an AND filter
+ if (fp->Next) {
+ filp = PrepareFilter(g, fp->Next, having);
+ fp->Arg(1) = filp;
+ fp->Opc = OP_AND;
+ fp->Next = NULL; // This will end the loop
+ } else
+ break; // Remove eventual ending separator(s)
+
+// if (fp->Convert(g, having))
+// throw (int)TYPE_FILTER;
+
+ filp = fp;
+ fp = fp->Next;
+ filp->Next = NULL;
+ } // endwhile
+
+ if (trace(1))
+ htrc(" returning filp=%p\n", filp);
+
+ return filp;
+ } // end of PrepareFilter
+#endif // 0
+
+/***********************************************************************/
+/* ApplyFilter: Apply filtering for a table (where or having clause). */
+/* New algorithm: evaluate from the root a de-linearized filter so */
+/* AND/OR clauses can be optimized throughout the whole tree. */
+/***********************************************************************/
+DllExport bool ApplyFilter(PGLOBAL g, PFIL filp)
+ {
+ if (!filp)
+ return TRUE;
+
+ // Must be done for null tables
+ filp->Reset();
+
+//if (tdbp && tdbp->IsNull())
+// return TRUE;
+
+ if (filp->Eval(g))
+ throw (int)TYPE_FILTER;
+
+ if (trace(2))
+ htrc("PlugFilter filp=%p result=%d\n",
+ filp, filp->GetResult());
+
+ return filp->GetResult();
+ } // end of ApplyFilter
diff --git a/storage/connect/filter.h b/storage/connect/filter.h
new file mode 100644
index 00000000..12ac3a16
--- /dev/null
+++ b/storage/connect/filter.h
@@ -0,0 +1,178 @@
+/*************** Filter H Declares Source Code File (.H) ***************/
+/* Name: FILTER.H Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2010-2017 */
+/* */
+/* This file contains the FILTER and derived classes declares. */
+/***********************************************************************/
+#ifndef __FILTER__
+#define __FILTER__
+
+/***********************************************************************/
+/* Include required application header files */
+/***********************************************************************/
+#include "xobject.h"
+
+/***********************************************************************/
+/* Utilities for WHERE condition building. */
+/***********************************************************************/
+PFIL MakeFilter(PGLOBAL g, PFIL filp, OPVAL vop, PFIL fp);
+PFIL MakeFilter(PGLOBAL g, PCOL *colp, POPER pop, PPARM pfirst, bool neg);
+
+/***********************************************************************/
+/* Definition of class FILTER with all its method functions. */
+/* Note: Most virtual implementation functions are not in use yet */
+/* but could be in future system evolution. */
+/***********************************************************************/
+class DllExport FILTER : public XOBJECT { /* Filter description block */
+//friend PFIL PrepareFilter(PGLOBAL, PFIL, bool);
+ friend DllExport bool ApplyFilter(PGLOBAL, PFIL);
+ public:
+ // Constructors
+ FILTER(PGLOBAL g, POPER pop, PPARM *tp = NULL);
+ FILTER(PGLOBAL g, OPVAL opc, PPARM *tp = NULL);
+ FILTER(PFIL fil1);
+
+ // Implementation
+ virtual int GetType(void) {return TYPE_FILTER;}
+ virtual int GetResultType(void) {return TYPE_INT;}
+ virtual int GetLength(void) {return 1;}
+ virtual int GetLengthEx(void) {assert(FALSE); return 0;}
+ virtual int GetScale() {return 0;};
+ PFIL GetNext(void) {return Next;}
+ OPVAL GetOpc(void) {return Opc;}
+ int GetOpm(void) {return Opm;}
+ int GetArgType(int i) {return Arg(i)->GetType();}
+ bool GetResult(void) {return Value->GetIntValue() != 0;}
+ PXOB &Arg(int i) {return Test[i].Arg;}
+ PVAL &Val(int i) {return Test[i].Value;}
+ bool &Conv(int i) {return Test[i].Conv;}
+ void SetNext(PFIL filp) {Next = filp;}
+
+ // Methods
+ virtual void Reset(void);
+ virtual bool Compare(PXOB) {return FALSE;} // Not used yet
+ virtual bool Init(PGLOBAL);
+ virtual bool Eval(PGLOBAL);
+ virtual bool SetFormat(PGLOBAL, FORMAT&) {return TRUE;} // NUY
+//virtual int CheckColumn(PGLOBAL g, PSQL sqlp, PXOB &xp, int &ag);
+//virtual int RefNum(PSQL);
+//virtual PXOB SetSelect(PGLOBAL, PSQL, bool) {return NULL;} // NUY
+//virtual PXOB CheckSubQuery(PGLOBAL, PSQL);
+//virtual bool CheckLocal(PTDB);
+//virtual int CheckSpcCol(PTDB tdbp, int n);
+ virtual void Printf(PGLOBAL g, FILE *f, uint n);
+ virtual void Prints(PGLOBAL g, char *ps, uint z);
+// PFIL Linearize(bool nosep);
+// PFIL Link(PGLOBAL g, PFIL fil2);
+// PFIL RemoveLastSep(void);
+// PFIL SortJoin(PGLOBAL g);
+// bool FindJoinFilter(POPJOIN opj, PFIL fprec, bool teq,
+// bool tek, bool tk2, bool tc2, bool tix, bool thx);
+// bool CheckHaving(PGLOBAL g, PSQL sqlp);
+ bool Convert(PGLOBAL g, bool having);
+// int SplitFilter(PFIL *fp);
+// int SplitFilter(PFIL *fp, PTDB tp, int n);
+// PFIL LinkFilter(PGLOBAL g, PFIL fp2);
+// PFIL Copy(PTABS t);
+
+ protected:
+ FILTER(void) {} // Standard constructor not to be used
+ void Constr(PGLOBAL g, OPVAL opc, int opm, PPARM *tp);
+
+ // Members
+ PFIL Next; // Used for linearization
+ OPVAL Opc; // Comparison operator
+ int Opm; // Modificator
+ BYTE Bt; // Operator bitmap
+ struct {
+ int B_T; // Buffer type
+ PXOB Arg; // Points to argument
+ PVAL Value; // Points to argument value
+ bool Conv; // TRUE if argument must be converted
+ } Test[2];
+ }; // end of class FILTER
+
+/***********************************************************************/
+/* Derived class FILTERX: used to replace a filter by a derived class */
+/* using an Eval method optimizing the filtering evaluation. */
+/* Note: this works only if the members of the derived class are the */
+/* same than the ones of the original class (NO added members). */
+/***********************************************************************/
+class FILTERX : public FILTER {
+ public:
+ // Methods
+ virtual bool Eval(PGLOBAL) = 0; // just to prevent direct FILTERX use
+
+ // Fake operator new used to change a filter into a derived filter
+ void * operator new(size_t, PFIL filp) {return filp;}
+#if defined(_WIN32)
+ // Avoid warning C4291 by defining a matching dummy delete operator
+ void operator delete(void *, PFIL) {}
+#else
+ void operator delete(void *) {}
+#endif
+ }; // end of class FILTERX
+
+/***********************************************************************/
+/* Derived class FILTEREQ: OP_EQ, no conversion and Xobject args. */
+/***********************************************************************/
+class FILTERCMP : public FILTERX {
+ public:
+ // Constructor
+ FILTERCMP(PGLOBAL g);
+
+ // Methods
+ virtual bool Eval(PGLOBAL);
+ }; // end of class FILTEREQ
+
+/***********************************************************************/
+/* Derived class FILTERAND: OP_AND, no conversion and Xobject args. */
+/***********************************************************************/
+class FILTERAND : public FILTERX {
+ public:
+ // Methods
+ virtual bool Eval(PGLOBAL);
+ }; // end of class FILTERAND
+
+/***********************************************************************/
+/* Derived class FILTEROR: OP_OR, no conversion and Xobject args. */
+/***********************************************************************/
+class FILTEROR : public FILTERX {
+ public:
+ // Methods
+ virtual bool Eval(PGLOBAL);
+ }; // end of class FILTEROR
+
+/***********************************************************************/
+/* Derived class FILTERNOT: OP_NOT, no conversion and Xobject args. */
+/***********************************************************************/
+class FILTERNOT : public FILTERX {
+ public:
+ // Methods
+ virtual bool Eval(PGLOBAL);
+ }; // end of class FILTERNOT
+
+/***********************************************************************/
+/* Derived class FILTERIN: OP_IN, no conversion and Array 2nd arg. */
+/***********************************************************************/
+class FILTERIN : public FILTERX {
+ public:
+ // Methods
+ virtual bool Eval(PGLOBAL);
+ }; // end of class FILTERIN
+
+/***********************************************************************/
+/* Derived class FILTERTRUE: Always returns TRUE. */
+/***********************************************************************/
+class FILTERTRUE : public FILTERX {
+ public:
+ // Constructor
+ FILTERTRUE(PVAL valp) {Value = valp; Value->SetValue_bool(TRUE);}
+
+ // Methods
+ virtual void Reset(void);
+ virtual bool Eval(PGLOBAL);
+ }; // end of class FILTERTRUE
+
+#endif // __FILTER__
diff --git a/storage/connect/fmdlex.c b/storage/connect/fmdlex.c
new file mode 100644
index 00000000..1bca2d4e
--- /dev/null
+++ b/storage/connect/fmdlex.c
@@ -0,0 +1,1540 @@
+#include <setjmp.h>
+
+#define yyFlexLexer fmdfFlexLexer
+#define yy_create_buffer fmdf_create_buffer
+#define yy_delete_buffer fmdf_delete_buffer
+#define yy_flex_debug fmdf_flex_debug
+#define yy_init_buffer fmdf_init_buffer
+#define yy_load_buffer_state fmdf_load_buffer_state
+#define yy_switch_to_buffer fmdf_switch_to_buffer
+#define yyin fmdfin
+#define yyleng fmdfleng
+#define yylex fmdflex
+#define yyout fmdfout
+#define yyrestart fmdfrestart
+#define yytext fmdftext
+#define yywrap fmdfwrap
+
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/daffy/u0/vern/flex/flex-2.4.7/RCS/flex.skl,v 1.2 94/08/03 11:13:24 vern Exp $
+ */
+
+#define FLEX_SCANNER
+#ifdef _WIN32
+#define __STDC__ 1
+#define isatty _isatty
+#endif
+#include <stdio.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#ifdef __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+
+#ifdef __TURBOC__
+#define YY_USE_CONST
+#endif
+
+
+#ifndef YY_USE_CONST
+#ifndef const
+#define const
+#endif
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.
+ */
+#define YY_START ((yy_start - 1) / 2)
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". Now included
+ * only for backward compatibility with previous versions of flex.
+ */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern int yywrap YY_PROTO(( void ));
+#ifdef __cplusplus
+ }
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+void yyrestart YY_PROTO(( FILE *input_file ));
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+
+#ifdef NOT_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#endif
+
+static void *yy_flex_alloc YY_PROTO(( unsigned int ));
+static void *yy_flex_realloc YY_PROTO(( void *, unsigned int ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define INITIAL 0
+#define txt 1
+#define sqt 2
+#define dqt 3
+typedef unsigned char YY_CHAR;
+typedef int yy_state_type;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+extern char *yytext;
+#define yytext_ptr yytext
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, const char *, int ));
+#endif
+
+#ifdef NOT_USED
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( const char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int)(yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_END_OF_BUFFER 17
+static const short int yy_accept[45] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 17, 15,
+ 16, 14, 1, 13, 2, 3, 8, 7, 6, 9,
+ 10, 11, 12, 15, 16, 5, 15, 16, 4, 1,
+ 8, 8, 7, 7, 6, 9, 10, 11, 12, 0,
+ 5, 0, 4, 0
+ } ;
+
+static const int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 1, 1, 1, 1, 5, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 6, 1, 1,
+ 1, 1, 1, 1, 1, 1, 7, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 8, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 9, 1, 1, 1, 1, 10, 1,
+ 1, 1, 1, 1, 11, 12, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const int yy_meta[13] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1
+ } ;
+
+static const short int yy_base[52] =
+ { 0,
+ 49, 48, 0, 0, 10, 13, 16, 18, 50, 53,
+ 53, 53, 47, 53, 53, 53, 42, 40, 38, 36,
+ 34, 32, 30, 36, 35, 53, 35, 34, 53, 35,
+ 53, 30, 53, 28, 26, 24, 22, 20, 18, 24,
+ 53, 24, 53, 53, 26, 25, 24, 23, 22, 16,
+ 13
+ } ;
+
+static const short int yy_def[52] =
+ { 0,
+ 45, 45, 44, 3, 46, 46, 47, 47, 44, 44,
+ 44, 44, 44, 44, 44, 44, 48, 49, 44, 44,
+ 44, 44, 44, 50, 50, 44, 51, 51, 44, 44,
+ 44, 48, 44, 49, 44, 44, 44, 44, 44, 50,
+ 44, 51, 44, 0, 44, 44, 44, 44, 44, 44,
+ 44
+ } ;
+
+static const short int yy_nxt[66] =
+ { 0,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 25, 42, 26, 25, 40, 26, 28, 29,
+ 28, 29, 33, 31, 27, 24, 10, 43, 41, 39,
+ 38, 37, 36, 35, 34, 32, 30, 43, 43, 41,
+ 41, 39, 38, 37, 36, 35, 34, 32, 30, 44,
+ 11, 11, 9, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44
+ } ;
+
+static const short int yy_chk[66] =
+ { 0,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 5, 51, 5, 6, 50, 6, 7, 7,
+ 8, 8, 49, 48, 47, 46, 45, 42, 40, 39,
+ 38, 37, 36, 35, 34, 32, 30, 28, 27, 25,
+ 24, 23, 22, 21, 20, 19, 18, 17, 13, 9,
+ 2, 1, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+char *yytext;
+#if defined(UNIX)
+#define _fileno fileno
+#define istty _istty
+#else
+#include <stdlib.h>
+#include <io.h>
+#endif /* UNIX */
+#include <string.h>
+#include "preparse.h"
+
+#ifndef fileno
+#define fileno _fileno
+#endif
+#undef YY_DECL
+#define YY_DECL int yylex YY_PROTO((PDTP ppp))
+#define YYSTATE ((yy_start-1)/2)
+#undef YY_INPUT
+#define YY_INPUT(buf,n,m) \
+ {n=((int) m< (int) strlen(pp->Curp))? (int) m: (int) strlen(pp->Curp);strncpy(buf,pp->Curp,n);pp->Curp+=n;}
+#if defined(UNIX)
+#undef yywrap
+#define yywrap ddwrap
+#endif /* UNIX */
+int yywrap(void);
+
+static PDTP pp;
+static void MakeParm(int n);
+static void MakeMMDD(int n);
+static void MakeAMPM(int n);
+static void MakeIn(const char *);
+static void MakeOut(const char *);
+static void Quotin(const char *);
+static void Quotout(const char *);
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = getc( yyin ); \
+ result = c == (int) EOF ? 0 : 1; \
+ buf[0] = (char) c; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+static jmp_buf env;
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+ if (setjmp(env))
+ return -1;
+
+ /*************************************************************************/
+ /* Flex parser to analyze date format and produce input and/or output */
+ /* formats. Non quoted blanks are significant (put in the output format) */
+ /* unless the Flag is not null, then there are ignored for output fmt. */
+ /*************************************************************************/
+ BEGIN txt;
+ pp = ppp;
+ pp->Num = 0;
+ if (pp->InFmt) {*pp->InFmt = '\0'; pp->InFmt[pp->Outsize -1] = '\0'; }
+ if (pp->OutFmt) {*pp->OutFmt = '\0'; pp->OutFmt[pp->Outsize -1] = '\0'; }
+ pp->Curp = (char*) pp->Format;
+ yy_init = 1; /* This is a new input */
+
+
+ if ( yy_init )
+ {
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( yy_current_buffer )
+ yy_init_buffer( yy_current_buffer, yyin );
+ else
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+
+ yy_init = 0;
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 45 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 53 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_USER_ACTION
+{MakeIn(" "); if (!pp->Flag) MakeOut(" ");}
+ YY_BREAK
+case 2:
+YY_USER_ACTION
+{BEGIN dqt;}
+ YY_BREAK
+case 3:
+YY_USER_ACTION
+{BEGIN sqt;}
+ YY_BREAK
+case 4:
+YY_USER_ACTION
+{Quotin(yytext); Quotout(yytext);
+#ifdef DEBUG
+ fprintf(stderr, "In double quote yytext=>>%s<<\n", yytext);
+#endif
+ BEGIN txt;}
+ YY_BREAK
+case 5:
+YY_USER_ACTION
+{Quotin(yytext); Quotout(yytext);
+#ifdef DEBUG
+ fprintf(stderr, "In simple quote yytext=>>%s<<\n", yytext);
+#endif
+ BEGIN txt;}
+ YY_BREAK
+case 6:
+YY_USER_ACTION
+MakeParm(0);
+ YY_BREAK
+case 7:
+YY_USER_ACTION
+MakeMMDD(1);
+ YY_BREAK
+case 8:
+YY_USER_ACTION
+MakeMMDD(2);
+ YY_BREAK
+case 9:
+YY_USER_ACTION
+MakeParm(3);
+ YY_BREAK
+case 10:
+YY_USER_ACTION
+MakeParm(4);
+ YY_BREAK
+case 11:
+YY_USER_ACTION
+MakeParm(5);
+ YY_BREAK
+case 12:
+YY_USER_ACTION
+MakeAMPM(6);
+ YY_BREAK
+case 13:
+YY_USER_ACTION
+
+ YY_BREAK
+case 14:
+YY_USER_ACTION
+{MakeIn(yytext); MakeOut(yytext);
+#ifdef DEBUG
+ fprintf(stderr, "No quote char=>>%s<<\n", yytext);
+#endif
+ }
+ YY_BREAK
+case 15:
+YY_USER_ACTION
+{pp->Flag = -1; yyterminate();}
+ YY_BREAK
+case 16:
+YY_USER_ACTION
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(txt):
+case YY_STATE_EOF(sqt):
+case YY_STATE_EOF(dqt):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int)(yy_cp - yytext_ptr - 1);
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr - 1; /* copy prev. char, too */
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a singled characater, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int)(yy_c_buf_p - yytext_ptr);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset = (int)(yy_c_buf_p - b->yy_ch_buf);
+
+ b->yy_buf_size *= 2;
+ b->yy_ch_buf = (char *)
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size );
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move - YY_MORE_ADJ == 1 )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ /* yytext begins at the second character in yy_ch_buf; the first
+ * character is the one which preceded it before reading in the latest
+ * buffer; it needs to be kept around in case it's a newline, so
+ * yy_get_previous_state() will have with '^' rules active.
+ */
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[1];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 45 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 45 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 44);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += dest - source;
+ yy_bp += dest - source;
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ if ( yy_cp > yy_bp && yy_cp[-1] == '\n' )
+ yy_cp[-2] = '\n';
+
+ *--yy_cp = (char) c;
+
+
+ /* Note: the formal parameter *must* be called "yy_bp" for this
+ * macro to now work correctly.
+ */
+ YY_DO_BEFORE_ACTION; /* set up yytext again */
+ }
+
+
+#ifdef NOT_USED
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ yytext_ptr = yy_c_buf_p;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ {
+ yy_c_buf_p =
+ yytext_ptr + YY_MORE_ADJ;
+ return EOF;
+ }
+
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+ break;
+
+ case EOB_ACT_LAST_MATCH:
+#ifdef __cplusplus
+ YY_FATAL_ERROR(
+ "unexpected last match in yyinput()" );
+#else
+ YY_FATAL_ERROR(
+ "unexpected last match in input()" );
+#endif
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ return c;
+ }
+#endif /* NOT_USED */
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ yy_flex_free( (void *) b->yy_ch_buf );
+ yy_flex_free( (void *) b );
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+ {
+ b->yy_input_file = file;
+
+ /* We put in the '\n' and start reading from [1] so that an
+ * initial match-at-newline will be true.
+ */
+
+ b->yy_ch_buf[0] = '\n';
+ b->yy_n_chars = 1;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[2] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[1];
+
+ b->yy_is_interactive = file ? isatty( fileno(file) ) : 0;
+
+ b->yy_fill_buffer = 1;
+
+ b->yy_buffer_status = YY_BUFFER_NEW;
+ }
+
+
+#ifdef NOT_USED
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ int new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+
+
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif /* NOT_USED */
+
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( const char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ longjmp(env, 1 );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n - YY_MORE_ADJ; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, const char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+const char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( unsigned int size )
+#else
+static void *yy_flex_alloc( size )
+unsigned int size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, unsigned int size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+unsigned int size;
+#endif
+ {
+ return (void *) realloc( ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+
+void MakeMMDD(int n)
+ {
+ int m = strlen(yytext) - 1;
+ char c = yytext[m];
+
+ if ((c == 'M' && n == 1) || (c == 'D' && n == 2)) {
+ m++;
+ c = 0;
+ } /* endif c */
+
+#ifdef DEBUG
+ fprintf(stderr, "MM: n=%d num=%d InFmt=%s OutFmt=%s;\n",
+ n, pp->Num, pp->InFmt, pp->OutFmt);
+#endif
+ pp->Index[pp->Num++] = (m < 3) ? n : (-n);
+
+ switch (m) {
+ case 1:
+ MakeIn("%2d");
+ MakeOut((n == 1) ? "%#m" : "%#d");
+ break;
+ case 2:
+ MakeIn("%2d");
+ MakeOut((n == 1) ? "%m" : "%d");
+ break;
+ case 3:
+ MakeIn("%3s");
+ MakeOut((n == 1) ? "%b" : "%a");
+ break;
+ default:
+ if (c && c != ' ') {
+ char fm[] = "%[^x]";
+ fm[3] = c;
+ MakeIn(fm);
+ } else
+ MakeIn("%s");
+
+ MakeOut((n == 1) ? "%B" : "%A");
+ } /* endswitch m */
+
+ if (c)
+ unput(c);
+
+ } /* end of MakeMMDD */
+
+void MakeParm(int n)
+ {
+ int m = strlen(yytext);
+
+#ifdef DEBUG
+ fprintf(stderr, "MP: n=%d num=%d InFmt=%s OutFmt=%s;\n",
+ n, pp->Num, pp->InFmt, pp->OutFmt);
+#endif
+ pp->Index[pp->Num++] = n;
+
+ switch (m) {
+ case 1:
+ MakeIn("%2d");
+ MakeOut((n == 0) ? "%#y" : (n == 3) ? "%#H"
+ : (n == 4) ? "%#M" : "%#S");
+ break;
+ case 2:
+ MakeIn("%2d");
+ MakeOut((n == 0) ? "%y" : (n == 3) ? "%H"
+ : (n == 4) ? "%M" : "%S");
+ break;
+ default:
+ MakeIn("%4d");
+ MakeOut("%Y");
+ } /* endswitch m */
+
+ } /* end of MakeParm */
+
+void MakeAMPM(int n)
+ {
+ char buf[8];
+ int m = strlen(yytext);
+
+#ifdef DEBUG
+ fprintf(stderr, "AM: n=%d num=%d InFmt=%s OutFmt=%s;\n",
+ n, pp->Num, pp->InFmt, pp->OutFmt);
+#endif
+ pp->Index[pp->Num++] = -n;
+ sprintf(buf, "%%%ds", m);
+ MakeIn(buf);
+
+ if (pp->OutFmt) {
+ char *p;
+
+ if ((p = strstr(pp->OutFmt, "%H")))
+ *(p + 1) = 'I'; // 12-hour format
+ else if ((p = strstr(pp->OutFmt, "%#H")))
+ *(p + 2) = 'I'; // 12-hour format
+
+ MakeOut("%p");
+ } /* endif Flag */
+
+ } /* end of MakeAMPM */
+
+void MakeIn(const char *text)
+ {
+ if (!pp->InFmt)
+ return;
+
+ strncat(pp->InFmt, text, (pp->Outsize - 1) - strlen(pp->InFmt));
+ } /* end of MakeIn */
+
+void MakeOut(const char *text)
+ {
+ if (!pp->OutFmt) return;
+
+ strncat(pp->OutFmt, text, (pp->Outsize - 1) - strlen(pp->OutFmt));
+ } /* end of MakeOut */
+
+void Quotin(const char *text)
+ {
+ if (!pp->InFmt)
+ return;
+
+ MakeIn(text);
+ pp->InFmt[strlen(pp->InFmt)-1] = '\0';
+ } /* end of Quotin */
+
+void Quotout(const char *text)
+ {
+ if (!pp->OutFmt)
+ return;
+
+ MakeOut(text);
+ pp->OutFmt[strlen(pp->OutFmt)-1] = '\0';
+ } /* end of Quotout */
+
+int yywrap(void)
+ {
+ /* Avoid memory leak */
+ if (yy_current_buffer)
+ yy_delete_buffer(yy_current_buffer);
+
+ return 1;
+ } /* end of yywrap */
+
diff --git a/storage/connect/frcas.h b/storage/connect/frcas.h
new file mode 100644
index 00000000..e9401d47
--- /dev/null
+++ b/storage/connect/frcas.h
@@ -0,0 +1,320 @@
+ case MSG_ACCESS_VIOLATN: p = "Violation accès mémoire"; break;
+ case MSG_ADD_BAD_TYPE: p = "Ajout d'une valeur de type %s non conforme dans un tableau %s"; break;
+ case MSG_ALLOC_ERROR: p = "Erreur d'allocation de %s"; break;
+ case MSG_ANSWER_TYPE: p = "Réponse de type"; break;
+ case MSG_API_CONF_ERROR: p = "Erreur SQL: API_CONFORMANCE"; break;
+ case MSG_APPL_NOT_INIT: p = "Application non initialisée"; break;
+ case MSG_ARRAY_BNDS_EXCD: p = "Hors limite de tableau"; break;
+ case MSG_BAD_ARRAY_OPER: p = "Les tableaux doivent utiliser l'opérateur IN"; break;
+ case MSG_BAD_ARRAY_TYPE: p = "Type=%d invalide pour un tableau"; break;
+ case MSG_BAD_ARRAY_VAL: p = "Les tableaux doivent avoir le même nombre de valeurs"; break;
+ case MSG_BAD_BIN_FMT: p = "Format invalide %c pour la colonne BIN %s"; break;
+ case MSG_BAD_BLK_ESTIM: p = "Nombre de blocs supérieur à l'estimation"; break;
+ case MSG_BAD_BLK_SIZE: p = "Taille du bloc %d non conforme"; break;
+ case MSG_BAD_BYTE_NUM: p = "Le nombre d'octets écrits est faux"; break;
+ case MSG_BAD_BYTE_READ: p = "Le nombre d'octets lus est faux"; break;
+ case MSG_BAD_COL_TYPE: p = "Type invalide %s pour la colonne %s"; break;
+ case MSG_BAD_COL_XPATH: p = "Xpath invalide colonne %s de la table HTML %s"; break;
+ case MSG_BAD_CONST_TYPE: p = "Type=%d invalide pour une constante"; break;
+ case MSG_BAD_CONV_TYPE: p = "Convertion de type invalide %d"; break;
+ case MSG_BAD_DATETIME: p = "Valeur date/temps invalide"; break;
+ case MSG_BAD_DBF_FILE: p = "Le fichier DBF %s est altéré"; break;
+ case MSG_BAD_DBF_REC: p = "Fichier DBF %s altéré enregistrement %d"; break;
+ case MSG_BAD_DBF_TYPE: p = "Type DBF %c non supporté colonne %s"; break;
+ case MSG_BAD_DIRECTORY: p = "Répertoire invalide %s: %s"; break;
+ case MSG_BAD_FIELD_RANK: p = "Rang %d invalide pour la colonne %s"; break;
+ case MSG_BAD_FIELD_TYPE: p = "Mauvais type de champ %s"; break;
+ case MSG_BAD_FILE_HANDLE: p = "Handle de fichier invalide: %s"; break;
+ case MSG_BAD_FILTER: p = "Mauvais filtre: Opc=%d B_T=%d %d Type=%d %d"; break;
+ case MSG_BAD_FILTER_CONV: p = "Conversion filtre incorrecte, B_T=%d,%d"; break;
+ case MSG_BAD_FILTER_OP: p = "Opérateur de filtre invalide %d"; break;
+ case MSG_BAD_FLD_FORMAT: p = "Format invalide pour le champs %d de %s"; break;
+ case MSG_BAD_FLD_LENGTH: p = "Champs %s trop long (%s --> %d) ligne %d de %s"; break;
+ case MSG_BAD_FREQ_SET: p = "Spécification erronnée de Freq pour la colonne %s"; break;
+ case MSG_BAD_FUNC_MODE: p = "%s: mode invalide %d"; break;
+ case MSG_BAD_HANDLE_VAL: p = "Valeur Handle invalide"; break;
+ case MSG_BAD_HEADER: p = "Fichier %s: bloc en-tête altéré"; break;
+ case MSG_BAD_HEAD_END: p = "Lecture fin d'en-tête impossible"; break;
+ case MSG_BAD_INDEX_FILE: p = "Fichier index %s corrompu"; break;
+ case MSG_BAD_LINEFLD_FMT: p = "Format invalide ligne %d champs %d de %s"; break;
+ case MSG_BAD_LINE_LEN: p = "Longueur ligne non égale à Lrecl"; break;
+ case MSG_BAD_LRECL: p = "Disparité lrecl table/fichier (%d,%hd)"; break;
+ case MSG_BAD_NODE_TYPE: p = "Type noeud erroné pour la table"; break;
+ case MSG_BAD_OFFSET_VAL: p = "Nul offset invalide pour une table CSV"; break;
+ case MSG_BAD_OPEN_MODE: p = "Mode d'ouverture invalide %d"; break;
+ case MSG_BAD_PARAM_TYPE: p = "%.8s: Paramètre de type=%d invalide"; break;
+ case MSG_BAD_PARM_COUNT: p = "Nombre de paramètres incohérent"; break;
+ case MSG_BAD_QUOTE_FIELD: p = "Quote manquante dans %s champs %d ligne %d"; break;
+ case MSG_BAD_READ_NUMBER: p = "Mauvais nombre %d de valeurs lues dans %s"; break;
+ case MSG_BAD_RECFM: p = "Recfm type %d invalide pour DOSCOL"; break;
+ case MSG_BAD_RECFM_VAL: p = "Valeur invalide %d de Recfm"; break;
+ case MSG_BAD_SET_CASE: p = "La casse d'un tableau ne peut pas passer de non respect à respecter"; break;
+ case MSG_BAD_SET_STRING: p = "SetValue: appel invalide pour STRING"; break;
+ case MSG_BAD_SPECIAL_COL: p = "Colonne spéciale invalide %s"; break;
+ case MSG_BAD_SPEC_COLUMN: p = "Colonne spéciale invalide pour ce type de table"; break;
+ case MSG_BAD_TABLE_TYPE: p = "Type invalide %s pour la table %s"; break;
+ case MSG_BAD_TYPE_LIKE: p = "Type(%d)= %d invalide pour LIKE"; break;
+ case MSG_BAD_VALBLK_INDX: p = "Valeur hors limites de l'index du bloc de valeurs"; break;
+ case MSG_BAD_VALBLK_TYPE: p = "Type=%d invalide pour un bloc de valeurs"; break;
+ case MSG_BAD_VALNODE: p = "Type %d invalide pour le noeud valeur colonne %s"; break;
+ case MSG_BAD_VALUE_TYPE: p = "Type de valeur invalide %d"; break;
+ case MSG_BAD_VAL_UPDATE: p = "Impossible de déterminer quelle valeur %s doit être mise à jour"; break;
+ case MSG_BAS_NS_LIST: p = "Format invalide de la liste des espace-noms"; break;
+ case MSG_BIN_F_TOO_LONG: p = "Valeur trop longue pour le champ %s (%d --> %d)"; break;
+ case MSG_BIN_MODE_FAIL: p = "Echec mode binaire: %s"; break;
+ case MSG_BLKTYPLEN_MISM: p = "Disparité types/longueurs de bloc dans SetValue"; break;
+ case MSG_BLK_IS_NULL: p = "Blk est nul"; break;
+ case MSG_BREAKPOINT: p = "Point de contrôle"; break;
+ case MSG_BUILD_INDEX: p = "Construction index %s sur %s"; break;
+ case MSG_CANNOT_OPEN: p = "Ouverture impossible de %s"; break;
+ case MSG_CHSIZE_ERROR: p = "Erreur dans chsize: %s"; break;
+ case MSG_COL_ALLOC_ERR: p = "Allocation impossible du noeud colonne"; break;
+ case MSG_COL_ISNOT_TABLE: p = "La colonne %s n'est pas dans la table %s"; break;
+ case MSG_COL_NOT_SORTED: p = "La colonne %s de la table %s n'est pas triée"; break;
+ case MSG_COL_NUM_MISM: p = "Disparité du nombre de colonnes"; break;
+ case MSG_COM_ERROR: p = "Erreur Com"; break;
+ case MSG_CONCAT_SUBNODE: p = "Concaténation de sous-noeuds impossible"; break;
+ case MSG_CONNECT_CANCEL: p = "Connection interrompue par l'utilisateur"; break;
+ case MSG_CONTROL_C_EXIT: p = "Exit par Ctrl-C"; break;
+ case MSG_DATABASE_LOADED: p = "Base de données %s chargée"; break;
+ case MSG_DATA_MISALIGN: p = "Mauvais alignement pour ce type de données"; break;
+ case MSG_DBASE_FILE: p = "Fichier dBASE dbf: "; break;
+ case MSG_DEF_ALLOC_ERROR: p = "Erreur d'allocation de la classe DEF %s"; break;
+ case MSG_DEL_FILE_ERR: p = "Erreur à l'effacement de %s"; break;
+ case MSG_DEL_READ_ERROR: p = "Delete: erreur en lecture req=%d len=%d"; break;
+ case MSG_DEL_WRITE_ERROR: p = "Delete: erreur en écriture: %s"; break;
+ case MSG_DEPREC_FLAG: p = "Option Flag périmée, utiliser Coltype"; break;
+ case MSG_DLL_LOAD_ERROR: p = "Erreur %d au chargement du module %s"; break;
+ case MSG_DOM_NOT_SUPP: p = "MS-DOM non supporté par cette version"; break;
+ case MSG_DVAL_NOTIN_LIST: p = "Valeur %s non trouvée dans la liste des valeurs distinctes de la colonne %s"; break;
+ case MSG_EMPTY_DOC: p = "Document vide"; break;
+ case MSG_EMPTY_FILE: p = "%s du fichier vide %s: "; break;
+ case MSG_EOF_AFTER_LINE: p = "Fin de fichier après la ligne %d"; break;
+ case MSG_EOF_INDEX_FILE: p = "EOF lisant le fichier index"; break;
+ case MSG_ERROR_IN_LSK: p = "Erreur %d dans lseek64"; break;
+ case MSG_ERROR_IN_SFP: p = "Erreur %d dans SetFilePointer"; break;
+ case MSG_ERR_READING_REC: p = "Erreur lisant l'enregistrement %d de %s"; break;
+ case MSG_FAIL_ADD_NODE: p = "L'ajout du noeud %s dans la table a échoué"; break;
+ case MSG_FETCH_NO_RES: p = "Fetch: Pas de Résultats"; break;
+ case MSG_FIELD_TOO_LONG: p = "Valeur trop longue pour le champs %d ligne %d"; break;
+ case MSG_FILELEN_ERROR: p = "Erreur dans %s pour %s"; break;
+ case MSG_FILE_IS_EMPTY: p = "Le fichier %s est vide"; break;
+ case MSG_FILE_MAP_ERR: p = "Erreur de File mapping"; break;
+ case MSG_FILE_MAP_ERROR: p = "CreateFileMapping %s erreur rc=%d"; break;
+ case MSG_FILE_OPEN_YET: p = "Fichier %s déjà ouvert"; break;
+ case MSG_FILE_UNFOUND: p = "Fichier %s non trouvé"; break;
+ case MSG_FLD_TOO_LNG_FOR: p = "Champs %d trop long pour %s ligne %d de %s"; break;
+ case MSG_FLT_BAD_RESULT: p = "Virgule flottante: résultat inexacte"; break;
+ case MSG_FLT_DENORMAL_OP: p = "Opérande virgule flottante non normalisé"; break;
+ case MSG_FLT_INVALID_OP: p = "Opération virgule flottante invalide"; break;
+ case MSG_FLT_OVERFLOW: p = "Dépassement de capacité virgule flottante"; break;
+ case MSG_FLT_STACK_CHECK: p = "Virgule flottante: Erreur de la pile"; break;
+ case MSG_FLT_UNDERFLOW: p = "Sous-dépassement de capacité virgule flottante"; break;
+ case MSG_FLT_ZERO_DIVIDE: p = "Virgule flottante: division par zéro"; break;
+ case MSG_FMT_WRITE_NIY: p = "L'écriture des fichiers %s n'est pas encore implémentée"; break;
+ case MSG_FOXPRO_FILE: p = "Fichier FoxPro: "; break;
+ case MSG_FPUTS_ERROR: p = "Erreur dans fputs: %s"; break;
+ case MSG_FSEEK_ERROR: p = "Erreur dans fseek: %s"; break;
+ case MSG_FSETPOS_ERROR: p = "Erreur dans fseek pour i=%d"; break;
+ case MSG_FTELL_ERROR: p = "Erreur dans ftell enregistrement=%d: %s"; break;
+ case MSG_FUNCTION_ERROR: p = "Erreur dans %s: %d"; break;
+ case MSG_FUNC_ERRNO: p = "Erreur %d dans %s"; break;
+ case MSG_FUNC_ERROR: p = "Erreur dans %s"; break;
+ case MSG_FUNC_ERR_S: p = "Erreur dans %s: %s"; break;
+ case MSG_FWRITE_ERROR: p = "Erreur dans fwrite: %s"; break;
+ case MSG_GET_DIST_VALS: p = "Récupération des valeurs distinctes de "; break;
+ case MSG_GET_FUNC_ERR: p = "Erreur en recherche de la fonction %s: %s"; break;
+ case MSG_GLOBAL_ERROR: p = "Erreur d'allocation de Global (taille=%d)\n"; break;
+ case MSG_GUARD_PAGE: p = "Violation de page de garde"; break;
+ case MSG_GZOPEN_ERROR: p = "gzopen %s: erreur %d sur %s"; break;
+ case MSG_ILLEGAL_INSTR: p = "Instruction illégale"; break;
+ case MSG_ILL_FILTER_CONV: p = "Conversion implicite illégale dans un filtre"; break;
+ case MSG_INDEX_NOT_UNIQ: p = "L'index n'est pas Unique"; break;
+ case MSG_INDEX_YET_ON: p = "L'index %s existe déjà sur %s"; break;
+ case MSG_INDX_COL_NOTIN: p = "La colonne index %s n'existe pas dans la table %s"; break;
+ case MSG_INDX_EXIST_YET: p = "L'entrée index existe déjà"; break;
+ case MSG_INIT_FAILED: p = "L'initialisation de %s a échoué"; break;
+ case MSG_INT_COL_ERROR: p = "Erreur interne sur la colonne index %s"; break;
+ case MSG_INT_OVERFLOW: p = "Dépassement de capacité sur entier"; break;
+ case MSG_INT_ZERO_DIVIDE: p = "Division entière par zéro"; break;
+ case MSG_INVALID_DISP: p = "Disposition invalide"; break;
+ case MSG_INVALID_FTYPE: p = "SBV: Ftype %d invalide"; break;
+ case MSG_INVALID_HANDLE: p = "Poignée invalide"; break;
+ case MSG_INVALID_OPER: p = "Opérateur invalide %d pour %s"; break;
+ case MSG_INV_COLUMN_TYPE: p = "Type %d Invalide pour la colonne %s"; break;
+ case MSG_INV_COL_TYPE: p = "Type de colonne %s invalide"; break;
+ case MSG_INV_DEF_READ: p = "Lecture différée invalide rc=%d"; break;
+ case MSG_INV_DIRCOL_OFST: p = "Offset invalide pour une colonne DIR"; break;
+ case MSG_INV_MAP_POS: p = "Position mémoire invalide"; break;
+ case MSG_INV_RAND_ACC: p = "L'accès aléatoire d'une table non optimisée est impossible"; break;
+ case MSG_INV_REC_POS: p = "Position d'enregistrement invalide"; break;
+ case MSG_INV_RESULT_TYPE: p = "Type de résultat invalide %s"; break;
+ case MSG_INV_UPDT_TABLE: p = "Table %s invalide pour Update"; break;
+ case MSG_IN_WITHOUT_SUB: p = "IN ou EXISTS sans tableau ou subquery"; break;
+ case MSG_KEY_ALLOC_ERR: p = "Erreur d'allocation d'un bloc offset clé"; break;
+ case MSG_KEY_ALLOC_ERROR: p = "Erreur d'allocation mémoire, Klen=%d n=%d"; break;
+ case MSG_LINE_TOO_LONG: p = "La nouvelle ligne est trop longue"; break;
+ case MSG_LIST: p = "--Liste--"; break;
+ case MSG_LOADING_FAILED: p = "Le chargement de %s a échoué"; break;
+ case MSG_LRECL_TOO_SMALL: p = "Lrecl trop petit (longueur en-tête = %d)"; break;
+ case MSG_MAKE_EMPTY_FILE: p = "Génération du fichier vide %s: %s"; break;
+ case MSG_MAKING: p = "Génération"; break;
+ case MSG_MALLOC_ERROR: p = "Allocation mémoire impossible par %s"; break;
+ case MSG_MAP_VIEW_ERROR: p = "MapViewOfFile %s erreur rc=%d"; break;
+ case MSG_MAXSIZE_ERROR: p = "Maxsize incalculable sur table ouverte"; break;
+ case MSG_MEM_ALLOC_ERR: p = "Erreur d'allocation mémoire, taille %s = %d"; break;
+ case MSG_MEM_ALLOC_ERROR: p = "Erreur d'allocation mémoire"; break;
+ case MSG_MISPLACED_QUOTE: p = "Appostrophe mal placée ligne %d"; break;
+ case MSG_MISSING_ARG: p = "Argument manquant pour l'opérateur %d"; break;
+ case MSG_MISSING_FIELD: p = "Champs %d manquant dans %s ligne %d"; break;
+ case MSG_MISSING_FNAME: p = "Nom du fichier manquant"; break;
+ case MSG_MISSING_NODE: p = "Noeud %s manquant dans %s"; break;
+ case MSG_MISSING_ROWNODE: p = "Impossible de trouver le noeud de la ligne %d"; break;
+ case MSG_MIS_TAG_LIST: p = "Liste des balises colonne manquante"; break;
+ case MSG_MUL_MAKECOL_ERR: p = "Erreur logique dans TABMUL::MakeCol"; break;
+ case MSG_NAME_CONV_ERR: p = "Erreur de convertion du nom de noeud"; break;
+ case MSG_NEW_DOC_FAILED: p = "Impossible de créer le nouveau document"; break;
+ case MSG_NEW_RETURN_NULL: p = "NULL renvoyé par New dans PlugEvalLike"; break;
+ case MSG_NEXT_FILE_ERROR: p = "Erreur en recherche du fichier suivant. rc=%s"; break;
+ case MSG_NONCONT_EXCEPT: p = "Exception non-continuable"; break;
+ case MSG_NOP_ZLIB_INDEX: p = "L'indexage d'une table zlib non optimisée est impossible"; break;
+ case MSG_NOT_A_DBF_FILE: p = "Le fichier n'a pas le format dBASE dbf "; break;
+ case MSG_NOT_FIXED_LEN: p = "Fichier %s non fixe, len=%d lrecl=%d"; break;
+ case MSG_NO_0DH_HEAD: p = "0DH manquant en fin d'en-tête (dbc=%d)"; break;
+ case MSG_NO_ACTIVE_DB: p = "Pas de base de données active"; break;
+ case MSG_NO_CHAR_FROM: p = "Conversion de type %d en caractères impossible"; break;
+ case MSG_NO_DATE_FMT: p = "Pas de format date pour le valblock de type %d"; break;
+ case MSG_NO_DEF_FNCCOL: p = "Colonne fonction par défaut introuvable"; break;
+ case MSG_NO_DEF_PIVOTCOL: p = "Colonne pivot par défaut introuvable"; break;
+ case MSG_NO_DIR_INDX_RD: p = "Pas d'accès directe des tables %s"; break;
+ case MSG_NO_FEAT_SUPPORT: p = "%s non supporté dans cette version"; break;
+ case MSG_NO_FLD_FORMAT: p = "Format absent pour le champs %d de %s"; break;
+ case MSG_NO_FORMAT_COL: p = "Type COLUMN informattable"; break;
+ case MSG_NO_FORMAT_TYPE: p = "Le format ne peut pas être défini à partir du type %d"; break;
+ case MSG_NO_INDEX_READ: p = "Pas d'accès directe des tables multiples"; break;
+ case MSG_NO_KEY_COL: p = "Pas de colonne clé trouvée"; break;
+ case MSG_NO_KEY_UPDATE: p = "Le nom des clés ne peut pas être modifié"; break;
+ case MSG_NO_MAP_INSERT: p = "MAP incompatible avec Insert"; break;
+ case MSG_NO_MATCHING_COL: p = "Pas de colonne correspondant à %s dans %s"; break;
+ case MSG_NO_MATCH_COL: p = "Colonne correspondante introuvable"; break;
+ case MSG_NO_MEMORY: p = "Mémoire pleine"; break;
+ case MSG_NO_MODE_PADDED: p = "Mode non supporté pour les fichiers 'padded'"; break;
+ case MSG_NO_MUL_VCT: p = "Les tables VCT ne peuvent pas être multiples"; break;
+ case MSG_NO_ODBC_DELETE: p = "Delete ne devrait pas être appelé pour les tables ODBC"; break;
+ case MSG_NO_ODBC_DIRECT: p = "Accès directe des tables ODBC non encore implémenté"; break;
+ case MSG_NO_ODBC_MUL: p = "Multiple(2) non supporté pour les tables ODBC"; break;
+ case MSG_NO_ODBC_SPECOL: p = "Pas de colonne spéciale ODBC"; break;
+ case MSG_NO_PART_DEL: p = "Delete partiel des fichier %s impossible"; break;
+ case MSG_NO_PART_MAP: p = "Mapping partiel non implémenté pour cet OS"; break;
+ case MSG_NO_PAR_BLK_INS: p = "Insertion de bloc partiel impossible"; break;
+ case MSG_NO_PIV_DIR_ACC: p = "Pas d'accès directe aux tables PIVOT"; break;
+ case MSG_NO_READ_32: p = "Lecture de 32 octets impossible"; break;
+ case MSG_NO_RECOV_SPACE: p = "Espace non recouvrable dans le fichier index"; break;
+ case MSG_NO_ROWID_FOR_AM: p = "Accès direct impossible de ROWID pour les tables de type %s"; break;
+ case MSG_NO_ROW_NODE: p = "Le nom du Rownode n'est pas défini"; break;
+ case MSG_NO_SECTION_NAME: p = "Nom de section manquant"; break;
+ case MSG_NO_SEC_UPDATE: p = "Les noms de section ne peuvent pas être modifiés"; break;
+ case MSG_NO_SETPOS_YET: p = "SetPos pas encore implémenté pour les fichier %s"; break;
+ case MSG_NO_SPEC_COL: p = "Pas de colonne spéciales MYSQL"; break;
+ case MSG_NO_SUB_VAL: p = "Pas de sous-value d'un tableau de type %d"; break;
+ case MSG_NO_TABCOL_DATA: p = "Pas de données pour la table %s colonne %s"; break;
+ case MSG_NO_TABLE_DEL: p = "Delete non autorisé pour les tables %s "; break;
+ case MSG_NO_TAB_DATA: p = "Pas de données pour la table %s"; break;
+ case MSG_NO_VCT_DELETE: p = "Délétion Partielle non implémentée pour les fichiers VCT"; break;
+ case MSG_NO_ZIP_DELETE: p = "Delete sur fichier Zip non encore implementé"; break;
+ case MSG_OPENING: p = "Ouverture"; break;
+ case MSG_OPEN_EMPTY_FILE: p = "Ouverture du fichier vide %s: %s"; break;
+ case MSG_OPEN_ERROR: p = "Erreur d'ouverture %d en mode %d sur %s: "; break;
+ case MSG_OPEN_ERROR_IS: p = "Erreur à l'ouverture de %s: %s"; break;
+ case MSG_OPEN_MODE_ERROR: p = "Erreur d'ouverture(%s) %d sur %s"; break;
+ case MSG_OPEN_STRERROR: p = "Erreur à l'ouverture: %s"; break;
+ case MSG_OPTBLK_RD_ERR: p = "Erreur à la lecture d'un bloc optimisation: %s"; break;
+ case MSG_OPTBLK_WR_ERR: p = "Erreur à l'écriture d'un bloc optimisation: %s"; break;
+ case MSG_OPTIMIZING: p = "Optimisation de "; break;
+ case MSG_OPT_BMAP_RD_ERR: p = "Erreur en lecture des bitmaps d'optimisation: %s"; break;
+ case MSG_OPT_BMAP_WR_ERR: p = "Erreur en écriture des bitmaps d'optimisation: %s"; break;
+ case MSG_OPT_CANCELLED: p = "Optimisation interrompue par l'utilisateur"; break;
+ case MSG_OPT_DVAL_RD_ERR: p = "Erreur en lecture des valeurs distinctes: %s"; break;
+ case MSG_OPT_DVAL_WR_ERR: p = "Erreur en écriture des valeurs distinctes: %s"; break;
+ case MSG_OPT_HEAD_RD_ERR: p = "Erreur en lecture de l'entête du fichier opt: %s"; break;
+ case MSG_OPT_HEAD_WR_ERR: p = "Erreur en écriture de l'entête du fichier opt: %s"; break;
+ case MSG_OPT_LOGIC_ERR: p = "Erreur logique dans SetBitmap, i=%d"; break;
+ case MSG_OPT_MAX_RD_ERR: p = "Erreur en lecture des valeurs maxi: %s"; break;
+ case MSG_OPT_MAX_WR_ERR: p = "Erreur en écriture des valeurs maxi: %s"; break;
+ case MSG_OPT_MIN_RD_ERR: p = "Erreur en lecture des valeurs mini: %s"; break;
+ case MSG_OPT_MIN_WR_ERR: p = "Erreur en écriture des valeurs mini: %s"; break;
+ case MSG_OPT_NOT_MATCH: p = "Le fichier opt %s n'est pas à jour"; break;
+ case MSG_PAGE_ERROR: p = "Erreur de pagination"; break;
+ case MSG_PARM_CNT_MISS: p = "Disparité du nombre de Paramètres"; break;
+ case MSG_PREC_VBLP_NULL: p = "ARRAY SetPrecision: Vblp est NULL"; break;
+ case MSG_PRIV_INSTR: p = "Instruction privilégiée"; break;
+ case MSG_PROCADD_ERROR: p = "Erreur %d sur l'adresse de %s"; break;
+ case MSG_QUERY_CANCELLED: p = "Requête interrompue par l'utilisateur"; break;
+ case MSG_RANGE_NO_JOIN: p = "Range non compatible avec les index de jointure"; break;
+ case MSG_RC_READING: p = "rc=%d en lecture de la table %s"; break;
+ case MSG_READY: p = "Prêt"; break;
+ case MSG_READ_ERROR: p = "Erreur en lecture sur %s: %s"; break;
+ case MSG_READ_ONLY: p = "Cette table protégée en lecture seule ne peut être modifiée"; break;
+ case MSG_READ_SEEK_ERROR: p = "Erreur de recherche en lecture: %s"; break;
+ case MSG_REGISTER_ERR: p = "Enregistrement NS impossible, préfix='%s' et href='%s'"; break;
+ case MSG_REMOVE_ERROR: p = "Erreur en supprimant %s: %s"; break;
+ case MSG_RENAME_ERROR: p = "Erreur renommant %s en %s: %s"; break;
+ case MSG_ROWID_NOT_IMPL: p = "RowNumber non implémenté pour les tables de type %s"; break;
+ case MSG_SEC_KEY_FIRST: p = "Les sections et clés doivent être insérées en premier"; break;
+ case MSG_SEC_NAME_FIRST: p = "Le nom de section doit être en tête de liste en insertion"; break;
+ case MSG_SEP_IN_FIELD: p = "Le champ %d contient le caractère séparateur"; break;
+ case MSG_SEQUENCE_ERROR: p = "HSTMT: Allocation hors séquence"; break;
+ case MSG_SETEOF_ERROR: p = "Erreur %d dans SetEndOfFile"; break;
+ case MSG_SETRECPOS_NIY: p = "SetRecpos non implémenté pour ce type de table"; break;
+ case MSG_SET_STR_TRUNC: p = "SetValue: Chaîne de caractères tronquée"; break;
+ case MSG_SFP_ERROR: p = "Erreur sur SetFilePointer: %s"; break;
+ case MSG_SHARED_LIB_ERR: p = "Erreur au chargement de la librairie partagée %s: %s"; break;
+ case MSG_SINGLE_STEP: p = "Pas à pas"; break;
+ case MSG_SORTING_VAL: p = "Tri de %d valeurs"; break;
+ case MSG_SPCOL_READONLY: p = "La colonne spéciale %s est en lecture seulement"; break;
+ case MSG_SQL_CONF_ERROR: p = "Erreur SQL: SQL_CONFORMANCE"; break;
+ case MSG_SRCH_CLOSE_ERR: p = "Erreur à la fermeture de l'Handle de recherche"; break;
+ case MSG_SRC_TABLE_UNDEF: p = "La table source n'est pas définie"; break;
+ case MSG_STACK_OVERFLOW: p = "Dépassement de capacité de la pile"; break;
+ case MSG_TABDIR_READONLY: p = "Les tables DIR sont en lecture seulement"; break;
+ case MSG_TABLE_NOT_OPT: p = "Table non optimisable"; break;
+ case MSG_TABLE_NO_INDEX: p = "La table %s n'est pas indexable"; break;
+ case MSG_TABLE_READ_ONLY: p = "Les tables %s sont en lecture seulement "; break;
+ case MSG_TABMUL_READONLY: p = "Les tables multiples sont en lecture seulement"; break;
+ case MSG_TOO_MANY_FIELDS: p = "Trop de champs ligne %d de %s"; break;
+ case MSG_TOO_MANY_JUMPS: p = "Trop de niveaux de saut"; break;
+ case MSG_TOO_MANY_KEYS: p = "Trop de clés (%d)"; break;
+ case MSG_TO_BLK_IS_NULL: p = "To Blk est nul"; break;
+ case MSG_TRUNCATE_ERROR: p = "Erreur en troncation: %s"; break;
+ case MSG_TRUNC_BY_ESTIM: p = "Tronqué par l'option Estimate"; break;
+ case MSG_TYPE_MISMATCH: p = "Clé et source ne sont pas du même type"; break;
+ case MSG_TYPE_VALUE_ERR: p = "Colonne %s: disparité type(%s)/valeur(%s)"; break;
+ case MSG_UNBALANCE_QUOTE: p = "Appostrophe en trop ligne %d"; break;
+ case MSG_UNDEFINED_AM: p = "COLBLK %s: méthode d'accès indéfinie"; break;
+ case MSG_UNKNOWN_EXCPT: p = "Exception non répertoriée"; break;
+ case MSG_UNMATCH_FIL_ARG: p = "Argument de filtre dépareillé"; break;
+ case MSG_UPDATE_ERROR: p = "Erreur en Update sur %s"; break;
+ case MSG_UPD_ZIP_NOT_IMP: p = "Mise à jour des tables ZDOS non encore implementé"; break;
+ case MSG_VALSTR_TOO_LONG: p = "Valeur %s trop longue pour une chaîne de longueur %d"; break;
+ case MSG_VALTYPE_NOMATCH: p = "Disparité types de valeur"; break;
+ case MSG_VALUE_ERROR: p = "Colonne %s: bloc valeur nul"; break;
+ case MSG_VALUE_TOO_BIG: p = "Valeur %lld trop grande pour la colonne %s"; break;
+ case MSG_VALUE_TOO_LONG: p = "Valeur %s trop longue pour la colonne %s de longueur %d"; break;
+ case MSG_VAL_ALLOC_ERR: p = "Allocation impossible du noeud valeur"; break;
+ case MSG_VIR_NO_DELETE: p = "Delete impossible sur les tables %s"; break;
+ case MSG_VIR_READ_ONLY: p = "Les tables virtuelles %s sont en lecture seulement"; break;
+ case MSG_VOID_FIRST_ARG: p = "Le premier argument ne doit pas être vide"; break;
+ case MSG_WORK_AREA: p = "Espace de travail: %s"; break;
+ case MSG_WRITE_SEEK_ERR: p = "Erreur de recherche en écriture: %s"; break;
+ case MSG_WRITE_STRERROR: p = "Erreur en écriture sur %s: %s"; break;
+ case MSG_WRITING: p = "Ecriture"; break;
+ case MSG_WRITING_ERROR: p = "Erreur à l'écriture de %s: %s"; break;
+ case MSG_WS_CONV_ERR: p = "Erreur de convertion de %s en WS"; break;
+ case MSG_XCOL_MISMATCH: p = "La colonne %s ne correspond pas à l'index"; break;
+ case MSG_XFILE_READERR: p = "Erreur %d en lisant le fichier index"; break;
+ case MSG_XFILE_WRITERR: p = "Erreur en écrivant le fichier index: %s"; break;
+ case MSG_XMLTAB_INIT_ERR: p = "Erreur d'initialisation de la table XML"; break;
+ case MSG_XML_INIT_ERROR: p = "Erreur d'initialisation du nouveau fichier XML"; break;
+ case MSG_XPATH_CNTX_ERR: p = "Le nouveau contexte XPath ne peut être créé"; break;
+ case MSG_XPATH_EVAL_ERR: p = "Impossible d'évaluer l'emplacement xpath '%s'"; break;
+ case MSG_XPATH_NOT_SUPP: p = "Xpath non supporté colonne %s"; break;
diff --git a/storage/connect/frids.h b/storage/connect/frids.h
new file mode 100644
index 00000000..561dbb68
--- /dev/null
+++ b/storage/connect/frids.h
@@ -0,0 +1,46 @@
+ case IDS_TABLES: p = "Table Entêtes"; break;
+ case IDS_TAB_01: p = "Catalogue"; break;
+ case IDS_TAB_02: p = "Schéma"; break;
+ case IDS_TAB_03: p = "Nom"; break;
+ case IDS_TAB_04: p = "Type"; break;
+ case IDS_TAB_05: p = "Remarque"; break;
+ case IDS_COLUMNS: p = "Colonne Entêtes"; break;
+ case IDS_COL_01: p = "Cat_Table"; break;
+ case IDS_COL_02: p = "Schem_Table"; break;
+ case IDS_COL_03: p = "Nom_Table"; break;
+ case IDS_COL_04: p = "Nom_Colonne"; break;
+ case IDS_COL_05: p = "Type_Données"; break;
+ case IDS_COL_06: p = "Nom_Type"; break;
+ case IDS_COL_07: p = "Précision"; break;
+ case IDS_COL_08: p = "Longueur"; break;
+ case IDS_COL_09: p = "Echelle"; break;
+ case IDS_COL_10: p = "Base"; break;
+ case IDS_COL_11: p = "Nullifiable"; break;
+ case IDS_COL_12: p = "Remarques"; break;
+ case IDS_PKEY: p = "Clé Entêtes"; break;
+ case IDS_PKY_01: p = "Cat_Table"; break;
+ case IDS_PKY_02: p = "Schem_Table"; break;
+ case IDS_PKY_03: p = "Nom_Table"; break;
+ case IDS_PKY_04: p = "Nom_Colonne"; break;
+ case IDS_PKY_05: p = "Numéro_Clé"; break;
+ case IDS_PKY_06: p = "Nom_Clé"; break;
+ case IDS_STAT: p = "Stat Entêtes"; break;
+ case IDS_STA_01: p = "Table_Catalog"; break;
+ case IDS_STA_02: p = "Table_Schema"; break;
+ case IDS_STA_03: p = "Table_Name"; break;
+ case IDS_STA_04: p = "Non_Unique"; break;
+ case IDS_STA_05: p = "Index_Qualifier"; break;
+ case IDS_STA_06: p = "Index_Name"; break;
+ case IDS_STA_07: p = "Type"; break;
+ case IDS_STA_08: p = "Seq_in_Index"; break;
+ case IDS_STA_09: p = "Column_Name"; break;
+ case IDS_STA_10: p = "Collation"; break;
+ case IDS_STA_11: p = "Cardinality"; break;
+ case IDS_STA_12: p = "Pages"; break;
+ case IDS_STA_13: p = "Filter_Condition"; break;
+ case IDS_DRIVER: p = "Driver Entêtes"; break;
+ case IDS_DRV_01: p = "Description"; break;
+ case IDS_DRV_02: p = "Attributs"; break;
+ case IDS_DSRC: p = "DataSrc Entêtes"; break;
+ case IDS_DSC_01: p = "Nom"; break;
+ case IDS_DSC_02: p = "Description"; break;
diff --git a/storage/connect/frmsg.h b/storage/connect/frmsg.h
new file mode 100644
index 00000000..d58779b9
--- /dev/null
+++ b/storage/connect/frmsg.h
@@ -0,0 +1,320 @@
+#define MSG_ACCESS_VIOLATN "Violation accès mémoire"
+#define MSG_ADD_BAD_TYPE "Ajout d'une valeur de type %s non conforme dans un tableau %s"
+#define MSG_ALLOC_ERROR "Erreur d'allocation de %s"
+#define MSG_ANSWER_TYPE "Réponse de type"
+#define MSG_API_CONF_ERROR "Erreur SQL: API_CONFORMANCE"
+#define MSG_APPL_NOT_INIT "Application non initialisée"
+#define MSG_ARRAY_BNDS_EXCD "Hors limite de tableau"
+#define MSG_BAD_ARRAY_OPER "Les tableaux doivent utiliser l'opérateur IN"
+#define MSG_BAD_ARRAY_TYPE "Type=%d invalide pour un tableau"
+#define MSG_BAD_ARRAY_VAL "Les tableaux doivent avoir le même nombre de valeurs"
+#define MSG_BAD_BIN_FMT "Format invalide %c pour la colonne BIN %s"
+#define MSG_BAD_BLK_ESTIM "Nombre de blocs supérieur à l'estimation"
+#define MSG_BAD_BLK_SIZE "Taille du bloc %d non conforme"
+#define MSG_BAD_BYTE_NUM "Le nombre d'octets écrits est faux"
+#define MSG_BAD_BYTE_READ "Le nombre d'octets lus est faux"
+#define MSG_BAD_COL_TYPE "Type invalide %s pour la colonne %s"
+#define MSG_BAD_COL_XPATH "Xpath invalide colonne %s de la table HTML %s"
+#define MSG_BAD_CONST_TYPE "Type=%d invalide pour une constante"
+#define MSG_BAD_CONV_TYPE "Convertion de type invalide %d"
+#define MSG_BAD_DATETIME "Valeur date/temps invalide"
+#define MSG_BAD_DBF_FILE "Le fichier DBF %s est altéré"
+#define MSG_BAD_DBF_REC "Fichier DBF %s altéré enregistrement %d"
+#define MSG_BAD_DBF_TYPE "Type DBF %c non supporté colonne %s"
+#define MSG_BAD_DIRECTORY "Répertoire invalide %s: %s"
+#define MSG_BAD_FIELD_RANK "Rang %d invalide pour la colonne %s"
+#define MSG_BAD_FIELD_TYPE "Mauvais type de champ %s"
+#define MSG_BAD_FILE_HANDLE "Handle de fichier invalide: %s"
+#define MSG_BAD_FILTER "Mauvais filtre: Opc=%d B_T=%d %d Type=%d %d"
+#define MSG_BAD_FILTER_CONV "Conversion filtre incorrecte, B_T=%d,%d"
+#define MSG_BAD_FILTER_OP "Opérateur de filtre invalide %d"
+#define MSG_BAD_FLD_FORMAT "Format invalide pour le champs %d de %s"
+#define MSG_BAD_FLD_LENGTH "Champs %s trop long (%s --> %d) ligne %d de %s"
+#define MSG_BAD_FREQ_SET "Spécification erronnée de Freq pour la colonne %s"
+#define MSG_BAD_FUNC_MODE "%s: mode invalide %d"
+#define MSG_BAD_HANDLE_VAL "Valeur Handle invalide"
+#define MSG_BAD_HEADER "Fichier %s: bloc en-tête altéré"
+#define MSG_BAD_HEAD_END "Lecture fin d'en-tête impossible"
+#define MSG_BAD_INDEX_FILE "Fichier index %s corrompu"
+#define MSG_BAD_LINEFLD_FMT "Format invalide ligne %d champs %d de %s"
+#define MSG_BAD_LINE_LEN "Longueur ligne non égale à Lrecl"
+#define MSG_BAD_LRECL "Disparité lrecl table/fichier (%d,%hd)"
+#define MSG_BAD_NODE_TYPE "Type noeud erroné pour la table"
+#define MSG_BAD_OFFSET_VAL "Nul offset invalide pour une table CSV"
+#define MSG_BAD_OPEN_MODE "Mode d'ouverture invalide %d"
+#define MSG_BAD_PARAM_TYPE "%.8s: Paramètre de type=%d invalide"
+#define MSG_BAD_PARM_COUNT "Nombre de paramètres incohérent"
+#define MSG_BAD_QUOTE_FIELD "Quote manquante dans %s champs %d ligne %d"
+#define MSG_BAD_READ_NUMBER "Mauvais nombre %d de valeurs lues dans %s"
+#define MSG_BAD_RECFM "Recfm type %d invalide pour DOSCOL"
+#define MSG_BAD_RECFM_VAL "Valeur invalide %d de Recfm"
+#define MSG_BAD_SET_CASE "La casse d'un tableau ne peut pas passer de non respect à respecter"
+#define MSG_BAD_SET_STRING "SetValue: appel invalide pour STRING"
+#define MSG_BAD_SPECIAL_COL "Colonne spéciale invalide %s"
+#define MSG_BAD_SPEC_COLUMN "Colonne spéciale invalide pour ce type de table"
+#define MSG_BAD_TABLE_TYPE "Type invalide %s pour la table %s"
+#define MSG_BAD_TYPE_LIKE "Type(%d)= %d invalide pour LIKE"
+#define MSG_BAD_VALBLK_INDX "Valeur hors limites de l'index du bloc de valeurs"
+#define MSG_BAD_VALBLK_TYPE "Type=%d invalide pour un bloc de valeurs"
+#define MSG_BAD_VALNODE "Type %d invalide pour le noeud valeur colonne %s"
+#define MSG_BAD_VALUE_TYPE "Type de valeur invalide %d"
+#define MSG_BAD_VAL_UPDATE "Impossible de déterminer quelle valeur %s doit être mise à jour"
+#define MSG_BAS_NS_LIST "Format invalide de la liste des espace-noms"
+#define MSG_BIN_F_TOO_LONG "Valeur trop longue pour le champ %s (%d --> %d)"
+#define MSG_BIN_MODE_FAIL "Echec mode binaire: %s"
+#define MSG_BLKTYPLEN_MISM "Disparité types/longueurs de bloc dans SetValue"
+#define MSG_BLK_IS_NULL "Blk est nul"
+#define MSG_BREAKPOINT "Point de contrôle"
+#define MSG_BUILD_INDEX "Construction index %s sur %s"
+#define MSG_CANNOT_OPEN "Ouverture impossible de %s"
+#define MSG_CHSIZE_ERROR "Erreur dans chsize: %s"
+#define MSG_COL_ALLOC_ERR "Allocation impossible du noeud colonne"
+#define MSG_COL_ISNOT_TABLE "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NOT_SORTED "La colonne %s de la table %s n'est pas triée"
+#define MSG_COL_NUM_MISM "Disparité du nombre de colonnes"
+#define MSG_COM_ERROR "Erreur Com"
+#define MSG_CONCAT_SUBNODE "Concaténation de sous-noeuds impossible"
+#define MSG_CONNECT_CANCEL "Connection interrompue par l'utilisateur"
+#define MSG_CONTROL_C_EXIT "Exit par Ctrl-C"
+#define MSG_DATABASE_LOADED "Base de données %s chargée"
+#define MSG_DATA_MISALIGN "Mauvais alignement pour ce type de données"
+#define MSG_DBASE_FILE "Fichier dBASE dbf: "
+#define MSG_DEF_ALLOC_ERROR "Erreur d'allocation de la classe DEF %s"
+#define MSG_DEL_FILE_ERR "Erreur à l'effacement de %s"
+#define MSG_DEL_READ_ERROR "Delete: erreur en lecture req=%d len=%d"
+#define MSG_DEL_WRITE_ERROR "Delete: erreur en écriture: %s"
+#define MSG_DEPREC_FLAG "Option Flag périmée, utiliser Coltype"
+#define MSG_DLL_LOAD_ERROR "Erreur %d au chargement du module %s"
+#define MSG_DOM_NOT_SUPP "MS-DOM non supporté par cette version"
+#define MSG_DVAL_NOTIN_LIST "Valeur %s non trouvée dans la liste des valeurs distinctes de la colonne %s"
+#define MSG_EMPTY_DOC "Document vide"
+#define MSG_EMPTY_FILE "%s du fichier vide %s: "
+#define MSG_EOF_AFTER_LINE "Fin de fichier après la ligne %d"
+#define MSG_EOF_INDEX_FILE "EOF lisant le fichier index"
+#define MSG_ERROR_IN_LSK "Erreur %d dans lseek64"
+#define MSG_ERROR_IN_SFP "Erreur %d dans SetFilePointer"
+#define MSG_ERR_READING_REC "Erreur lisant l'enregistrement %d de %s"
+#define MSG_FAIL_ADD_NODE "L'ajout du noeud %s dans la table a échoué"
+#define MSG_FETCH_NO_RES "Fetch: Pas de Résultats"
+#define MSG_FIELD_TOO_LONG "Valeur trop longue pour le champs %d ligne %d"
+#define MSG_FILELEN_ERROR "Erreur dans %s pour %s"
+#define MSG_FILE_IS_EMPTY "Le fichier %s est vide"
+#define MSG_FILE_MAP_ERR "Erreur de File mapping"
+#define MSG_FILE_MAP_ERROR "CreateFileMapping %s erreur rc=%d"
+#define MSG_FILE_OPEN_YET "Fichier %s déjà ouvert"
+#define MSG_FILE_UNFOUND "Fichier %s non trouvé"
+#define MSG_FLD_TOO_LNG_FOR "Champs %d trop long pour %s ligne %d de %s"
+#define MSG_FLT_BAD_RESULT "Virgule flottante: résultat inexacte"
+#define MSG_FLT_DENORMAL_OP "Opérande virgule flottante non normalisé"
+#define MSG_FLT_INVALID_OP "Opération virgule flottante invalide"
+#define MSG_FLT_OVERFLOW "Dépassement de capacité virgule flottante"
+#define MSG_FLT_STACK_CHECK "Virgule flottante: Erreur de la pile"
+#define MSG_FLT_UNDERFLOW "Sous-dépassement de capacité virgule flottante"
+#define MSG_FLT_ZERO_DIVIDE "Virgule flottante: division par zéro"
+#define MSG_FMT_WRITE_NIY "L'écriture des fichiers %s n'est pas encore implémentée"
+#define MSG_FOXPRO_FILE "Fichier FoxPro: "
+#define MSG_FPUTS_ERROR "Erreur dans fputs: %s"
+#define MSG_FSEEK_ERROR "Erreur dans fseek: %s"
+#define MSG_FSETPOS_ERROR "Erreur dans fseek pour i=%d"
+#define MSG_FTELL_ERROR "Erreur dans ftell enregistrement=%d: %s"
+#define MSG_FUNCTION_ERROR "Erreur dans %s: %d"
+#define MSG_FUNC_ERRNO "Erreur %d dans %s"
+#define MSG_FUNC_ERROR "Erreur dans %s"
+#define MSG_FUNC_ERR_S "Erreur dans %s: %s"
+#define MSG_FWRITE_ERROR "Erreur dans fwrite: %s"
+#define MSG_GET_DIST_VALS "Récupération des valeurs distinctes de "
+#define MSG_GET_FUNC_ERR "Erreur en recherche de la fonction %s: %s"
+#define MSG_GLOBAL_ERROR "Erreur d'allocation de Global (taille=%d)\n"
+#define MSG_GUARD_PAGE "Violation de page de garde"
+#define MSG_GZOPEN_ERROR "gzopen %s: erreur %d sur %s"
+#define MSG_ILLEGAL_INSTR "Instruction illégale"
+#define MSG_ILL_FILTER_CONV "Conversion implicite illégale dans un filtre"
+#define MSG_INDEX_NOT_UNIQ "L'index n'est pas Unique"
+#define MSG_INDEX_YET_ON "L'index %s existe déjà sur %s"
+#define MSG_INDX_COL_NOTIN "La colonne index %s n'existe pas dans la table %s"
+#define MSG_INDX_EXIST_YET "L'entrée index existe déjà"
+#define MSG_INIT_FAILED "L'initialisation de %s a échoué"
+#define MSG_INT_COL_ERROR "Erreur interne sur la colonne index %s"
+#define MSG_INT_OVERFLOW "Dépassement de capacité sur entier"
+#define MSG_INT_ZERO_DIVIDE "Division entière par zéro"
+#define MSG_INVALID_DISP "Disposition invalide"
+#define MSG_INVALID_FTYPE "SBV: Ftype %d invalide"
+#define MSG_INVALID_HANDLE "Poignée invalide"
+#define MSG_INVALID_OPER "Opérateur invalide %d pour %s"
+#define MSG_INV_COLUMN_TYPE "Type %d Invalide pour la colonne %s"
+#define MSG_INV_COL_TYPE "Type de colonne %s invalide"
+#define MSG_INV_DEF_READ "Lecture différée invalide rc=%d"
+#define MSG_INV_DIRCOL_OFST "Offset invalide pour une colonne DIR"
+#define MSG_INV_MAP_POS "Position mémoire invalide"
+#define MSG_INV_RAND_ACC "L'accès aléatoire d'une table non optimisée est impossible"
+#define MSG_INV_REC_POS "Position d'enregistrement invalide"
+#define MSG_INV_RESULT_TYPE "Type de résultat invalide %s"
+#define MSG_INV_UPDT_TABLE "Table %s invalide pour Update"
+#define MSG_IN_WITHOUT_SUB "IN ou EXISTS sans tableau ou subquery"
+#define MSG_KEY_ALLOC_ERR "Erreur d'allocation d'un bloc offset clé"
+#define MSG_KEY_ALLOC_ERROR "Erreur d'allocation mémoire, Klen=%d n=%d"
+#define MSG_LINE_TOO_LONG "La nouvelle ligne est trop longue"
+#define MSG_LIST "--Liste--"
+#define MSG_LOADING_FAILED "Le chargement de %s a échoué"
+#define MSG_LRECL_TOO_SMALL "Lrecl trop petit (longueur en-tête = %d)"
+#define MSG_MAKE_EMPTY_FILE "Génération du fichier vide %s: %s"
+#define MSG_MAKING "Génération"
+#define MSG_MALLOC_ERROR "Allocation mémoire impossible par %s"
+#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s erreur rc=%d"
+#define MSG_MAXSIZE_ERROR "Maxsize incalculable sur table ouverte"
+#define MSG_MEM_ALLOC_ERR "Erreur d'allocation mémoire, taille %s = %d"
+#define MSG_MEM_ALLOC_ERROR "Erreur d'allocation mémoire"
+#define MSG_MISPLACED_QUOTE "Appostrophe mal placée ligne %d"
+#define MSG_MISSING_ARG "Argument manquant pour l'opérateur %d"
+#define MSG_MISSING_FIELD "Champs %d manquant dans %s ligne %d"
+#define MSG_MISSING_FNAME "Nom du fichier manquant"
+#define MSG_MISSING_NODE "Noeud %s manquant dans %s"
+#define MSG_MISSING_ROWNODE "Impossible de trouver le noeud de la ligne %d"
+#define MSG_MIS_TAG_LIST "Liste des balises colonne manquante"
+#define MSG_MUL_MAKECOL_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_NAME_CONV_ERR "Erreur de convertion du nom de noeud"
+#define MSG_NEW_DOC_FAILED "Impossible de créer le nouveau document"
+#define MSG_NEW_RETURN_NULL "NULL renvoyé par New dans PlugEvalLike"
+#define MSG_NEXT_FILE_ERROR "Erreur en recherche du fichier suivant. rc=%s"
+#define MSG_NONCONT_EXCEPT "Exception non-continuable"
+#define MSG_NOP_ZLIB_INDEX "L'indexage d'une table zlib non optimisée est impossible"
+#define MSG_NOT_A_DBF_FILE "Le fichier n'a pas le format dBASE dbf "
+#define MSG_NOT_FIXED_LEN "Fichier %s non fixe, len=%d lrecl=%d"
+#define MSG_NO_0DH_HEAD "0DH manquant en fin d'en-tête (dbc=%d)"
+#define MSG_NO_ACTIVE_DB "Pas de base de données active"
+#define MSG_NO_CHAR_FROM "Conversion de type %d en caractères impossible"
+#define MSG_NO_DATE_FMT "Pas de format date pour le valblock de type %d"
+#define MSG_NO_DEF_FNCCOL "Colonne fonction par défaut introuvable"
+#define MSG_NO_DEF_PIVOTCOL "Colonne pivot par défaut introuvable"
+#define MSG_NO_DIR_INDX_RD "Pas d'accès directe des tables %s"
+#define MSG_NO_FEAT_SUPPORT "%s non supporté dans cette version"
+#define MSG_NO_FLD_FORMAT "Format absent pour le champs %d de %s"
+#define MSG_NO_FORMAT_COL "Type COLUMN informattable"
+#define MSG_NO_FORMAT_TYPE "Le format ne peut pas être défini à partir du type %d"
+#define MSG_NO_INDEX_READ "Pas d'accès directe des tables multiples"
+#define MSG_NO_KEY_COL "Pas de colonne clé trouvée"
+#define MSG_NO_KEY_UPDATE "Le nom des clés ne peut pas être modifié"
+#define MSG_NO_MAP_INSERT "MAP incompatible avec Insert"
+#define MSG_NO_MATCHING_COL "Pas de colonne correspondant à %s dans %s"
+#define MSG_NO_MATCH_COL "Colonne correspondante introuvable"
+#define MSG_NO_MEMORY "Mémoire pleine"
+#define MSG_NO_MODE_PADDED "Mode non supporté pour les fichiers 'padded'"
+#define MSG_NO_MUL_VCT "Les tables VCT ne peuvent pas être multiples"
+#define MSG_NO_ODBC_DELETE "Delete ne devrait pas être appelé pour les tables ODBC"
+#define MSG_NO_ODBC_DIRECT "Accès directe des tables ODBC non encore implémenté"
+#define MSG_NO_ODBC_MUL "Multiple(2) non supporté pour les tables ODBC"
+#define MSG_NO_ODBC_SPECOL "Pas de colonne spéciale ODBC"
+#define MSG_NO_PART_DEL "Delete partiel des fichier %s impossible"
+#define MSG_NO_PART_MAP "Mapping partiel non implémenté pour cet OS"
+#define MSG_NO_PAR_BLK_INS "Insertion de bloc partiel impossible"
+#define MSG_NO_PIV_DIR_ACC "Pas d'accès directe aux tables PIVOT"
+#define MSG_NO_READ_32 "Lecture de 32 octets impossible"
+#define MSG_NO_RECOV_SPACE "Espace non recouvrable dans le fichier index"
+#define MSG_NO_ROWID_FOR_AM "Accès direct impossible de ROWID pour les tables de type %s"
+#define MSG_NO_ROW_NODE "Le nom du Rownode n'est pas défini"
+#define MSG_NO_SECTION_NAME "Nom de section manquant"
+#define MSG_NO_SEC_UPDATE "Les noms de section ne peuvent pas être modifiés"
+#define MSG_NO_SETPOS_YET "SetPos pas encore implémenté pour les fichier %s"
+#define MSG_NO_SPEC_COL "Pas de colonne spéciales MYSQL"
+#define MSG_NO_SUB_VAL "Pas de sous-value d'un tableau de type %d"
+#define MSG_NO_TABCOL_DATA "Pas de données pour la table %s colonne %s"
+#define MSG_NO_TABLE_DEL "Delete non autorisé pour les tables %s "
+#define MSG_NO_TAB_DATA "Pas de données pour la table %s"
+#define MSG_NO_VCT_DELETE "Délétion Partielle non implémentée pour les fichiers VCT"
+#define MSG_NO_ZIP_DELETE "Delete sur fichier Zip non encore implementé"
+#define MSG_OPENING "Ouverture"
+#define MSG_OPEN_EMPTY_FILE "Ouverture du fichier vide %s: %s"
+#define MSG_OPEN_ERROR "Erreur d'ouverture %d en mode %d sur %s: "
+#define MSG_OPEN_ERROR_IS "Erreur à l'ouverture de %s: %s"
+#define MSG_OPEN_MODE_ERROR "Erreur d'ouverture(%s) %d sur %s"
+#define MSG_OPEN_STRERROR "Erreur à l'ouverture: %s"
+#define MSG_OPTBLK_RD_ERR "Erreur à la lecture d'un bloc optimisation: %s"
+#define MSG_OPTBLK_WR_ERR "Erreur à l'écriture d'un bloc optimisation: %s"
+#define MSG_OPTIMIZING "Optimisation de "
+#define MSG_OPT_BMAP_RD_ERR "Erreur en lecture des bitmaps d'optimisation: %s"
+#define MSG_OPT_BMAP_WR_ERR "Erreur en écriture des bitmaps d'optimisation: %s"
+#define MSG_OPT_CANCELLED "Optimisation interrompue par l'utilisateur"
+#define MSG_OPT_DVAL_RD_ERR "Erreur en lecture des valeurs distinctes: %s"
+#define MSG_OPT_DVAL_WR_ERR "Erreur en écriture des valeurs distinctes: %s"
+#define MSG_OPT_HEAD_RD_ERR "Erreur en lecture de l'entête du fichier opt: %s"
+#define MSG_OPT_HEAD_WR_ERR "Erreur en écriture de l'entête du fichier opt: %s"
+#define MSG_OPT_LOGIC_ERR "Erreur logique dans SetBitmap, i=%d"
+#define MSG_OPT_MAX_RD_ERR "Erreur en lecture des valeurs maxi: %s"
+#define MSG_OPT_MAX_WR_ERR "Erreur en écriture des valeurs maxi: %s"
+#define MSG_OPT_MIN_RD_ERR "Erreur en lecture des valeurs mini: %s"
+#define MSG_OPT_MIN_WR_ERR "Erreur en écriture des valeurs mini: %s"
+#define MSG_OPT_NOT_MATCH "Le fichier opt %s n'est pas à jour"
+#define MSG_PAGE_ERROR "Erreur de pagination"
+#define MSG_PARM_CNT_MISS "Disparité du nombre de Paramètres"
+#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp est NULL"
+#define MSG_PRIV_INSTR "Instruction privilégiée"
+#define MSG_PROCADD_ERROR "Erreur %d sur l'adresse de %s"
+#define MSG_QUERY_CANCELLED "Requête interrompue par l'utilisateur"
+#define MSG_RANGE_NO_JOIN "Range non compatible avec les index de jointure"
+#define MSG_RC_READING "rc=%d en lecture de la table %s"
+#define MSG_READY "Prêt"
+#define MSG_READ_ERROR "Erreur en lecture sur %s: %s"
+#define MSG_READ_ONLY "Cette table protégée en lecture seule ne peut être modifiée"
+#define MSG_READ_SEEK_ERROR "Erreur de recherche en lecture: %s"
+#define MSG_REGISTER_ERR "Enregistrement NS impossible, préfix='%s' et href='%s'"
+#define MSG_REMOVE_ERROR "Erreur en supprimant %s: %s"
+#define MSG_RENAME_ERROR "Erreur renommant %s en %s: %s"
+#define MSG_ROWID_NOT_IMPL "RowNumber non implémenté pour les tables de type %s"
+#define MSG_SEC_KEY_FIRST "Les sections et clés doivent être insérées en premier"
+#define MSG_SEC_NAME_FIRST "Le nom de section doit être en tête de liste en insertion"
+#define MSG_SEP_IN_FIELD "Le champ %d contient le caractère séparateur"
+#define MSG_SEQUENCE_ERROR "HSTMT: Allocation hors séquence"
+#define MSG_SETEOF_ERROR "Erreur %d dans SetEndOfFile"
+#define MSG_SETRECPOS_NIY "SetRecpos non implémenté pour ce type de table"
+#define MSG_SET_STR_TRUNC "SetValue: Chaîne de caractères tronquée"
+#define MSG_SFP_ERROR "Erreur sur SetFilePointer: %s"
+#define MSG_SHARED_LIB_ERR "Erreur au chargement de la librairie partagée %s: %s"
+#define MSG_SINGLE_STEP "Pas à pas"
+#define MSG_SORTING_VAL "Tri de %d valeurs"
+#define MSG_SPCOL_READONLY "La colonne spéciale %s est en lecture seulement"
+#define MSG_SQL_CONF_ERROR "Erreur SQL: SQL_CONFORMANCE"
+#define MSG_SRCH_CLOSE_ERR "Erreur à la fermeture de l'Handle de recherche"
+#define MSG_SRC_TABLE_UNDEF "La table source n'est pas définie"
+#define MSG_STACK_OVERFLOW "Dépassement de capacité de la pile"
+#define MSG_TABDIR_READONLY "Les tables DIR sont en lecture seulement"
+#define MSG_TABLE_NOT_OPT "Table non optimisable"
+#define MSG_TABLE_NO_INDEX "La table %s n'est pas indexable"
+#define MSG_TABLE_READ_ONLY "Les tables %s sont en lecture seulement "
+#define MSG_TABMUL_READONLY "Les tables multiples sont en lecture seulement"
+#define MSG_TOO_MANY_FIELDS "Trop de champs ligne %d de %s"
+#define MSG_TOO_MANY_JUMPS "Trop de niveaux de saut"
+#define MSG_TOO_MANY_KEYS "Trop de clés (%d)"
+#define MSG_TO_BLK_IS_NULL "To Blk est nul"
+#define MSG_TRUNCATE_ERROR "Erreur en troncation: %s"
+#define MSG_TRUNC_BY_ESTIM "Tronqué par l'option Estimate"
+#define MSG_TYPE_MISMATCH "Clé et source ne sont pas du même type"
+#define MSG_TYPE_VALUE_ERR "Colonne %s: disparité type(%s)/valeur(%s)"
+#define MSG_UNBALANCE_QUOTE "Appostrophe en trop ligne %d"
+#define MSG_UNDEFINED_AM "COLBLK %s: méthode d'accès indéfinie"
+#define MSG_UNKNOWN_EXCPT "Exception non répertoriée"
+#define MSG_UNMATCH_FIL_ARG "Argument de filtre dépareillé"
+#define MSG_UPDATE_ERROR "Erreur en Update sur %s"
+#define MSG_UPD_ZIP_NOT_IMP "Mise à jour des tables ZDOS non encore implementé"
+#define MSG_VALSTR_TOO_LONG "Valeur %s trop longue pour une chaîne de longueur %d"
+#define MSG_VALTYPE_NOMATCH "Disparité types de valeur"
+#define MSG_VALUE_ERROR "Colonne %s: bloc valeur nul"
+#define MSG_VALUE_TOO_BIG "Valeur %lld trop grande pour la colonne %s"
+#define MSG_VALUE_TOO_LONG "Valeur %s trop longue pour la colonne %s de longueur %d"
+#define MSG_VAL_ALLOC_ERR "Allocation impossible du noeud valeur"
+#define MSG_VIR_NO_DELETE "Delete impossible sur les tables %s"
+#define MSG_VIR_READ_ONLY "Les tables virtuelles %s sont en lecture seulement"
+#define MSG_VOID_FIRST_ARG "Le premier argument ne doit pas être vide"
+#define MSG_WORK_AREA "Espace de travail: %s"
+#define MSG_WRITE_SEEK_ERR "Erreur de recherche en écriture: %s"
+#define MSG_WRITE_STRERROR "Erreur en écriture sur %s: %s"
+#define MSG_WRITING "Ecriture"
+#define MSG_WRITING_ERROR "Erreur à l'écriture de %s: %s"
+#define MSG_WS_CONV_ERR "Erreur de convertion de %s en WS"
+#define MSG_XCOL_MISMATCH "La colonne %s ne correspond pas à l'index"
+#define MSG_XFILE_READERR "Erreur %d en lisant le fichier index"
+#define MSG_XFILE_WRITERR "Erreur en écrivant le fichier index: %s"
+#define MSG_XMLTAB_INIT_ERR "Erreur d'initialisation de la table XML"
+#define MSG_XML_INIT_ERROR "Erreur d'initialisation du nouveau fichier XML"
+#define MSG_XPATH_CNTX_ERR "Le nouveau contexte XPath ne peut être créé"
+#define MSG_XPATH_EVAL_ERR "Impossible d'évaluer l'emplacement xpath '%s'"
+#define MSG_XPATH_NOT_SUPP "Xpath non supporté colonne %s"
diff --git a/storage/connect/frmsg1.h b/storage/connect/frmsg1.h
new file mode 100644
index 00000000..e88440a3
--- /dev/null
+++ b/storage/connect/frmsg1.h
@@ -0,0 +1,1013 @@
+#define MSG_ACCESS_VIOLATN "Violation accès mémoire"
+#define MSG_ACT_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Activity"
+#define MSG_ADDVAL_ERROR "Erreur %d dans AddValue"
+#define MSG_ADD_BAD_TYPE "Ajout d'une valeur de type %s non conforme dans un tableau %s"
+#define MSG_ADD_NULL_DOM "Ajout de la chaîne %s à un domaine nul"
+#define MSG_ADPOS_IN_DICTP "ADPOS au travail dans User_Dictp"
+#define MSG_AFTER " après: "
+#define MSG_ALG_CHOICE_AUTO "Le choix du meilleur algorithme est automatique"
+#define MSG_ALG_CHOICE_BAD "Choix d'algorithme invalide, remis à AUTO"
+#define MSG_ALG_CHOICE_QRY "Utilise l'algorithme 'Query'"
+#define MSG_ALG_CURLY_BRK "Le choix de l'algorithme dépend des accolades externes"
+#define MSG_ALLOC_ERROR "Erreur d'allocation de %s"
+#define MSG_ALL_DELETED "Toutes les lignes enlevées en %.2lf sec"
+#define MSG_ALTER_DB_ERR "Impossible de déterminer la base de données à modifier"
+#define MSG_AMBIG_COL_QUAL "Qualificateur ambigu %s pour la colonne %s"
+#define MSG_AMBIG_CORREL "Select %s.* corrélation ambigue"
+#define MSG_AMBIG_SPEC_COL "Colonne spéciale ambiguë %s"
+#define MSG_ANSWER_TYPE "Réponse de type"
+#define MSG_API_CONF_ERROR "Erreur SQL: API_CONFORMANCE"
+#define MSG_APPL_ACCESSIBLE "Application %s accessible"
+#define MSG_APPL_ACTIVE "Application %s encore active"
+#define MSG_APPL_BAD_SAVE "Application %s partiellement sauvegardée"
+#define MSG_APPL_CREATED "Application %s crée"
+#define MSG_APPL_IS_ACTIVE "Application déjà active"
+#define MSG_APPL_NOT_INIT "Application non initialisée"
+#define MSG_APPL_NOT_LOADED "Application non chargée"
+#define MSG_APPL_QUIT "Fin de l'application %s"
+#define MSG_APPL_SAVED "Application %s sauvegardée"
+#define MSG_APP_STILL_ACTIV "Application du langage %s encore active (non libérable)"
+#define MSG_AREAFILE_NOTFND "Fichier Area introuvable"
+#define MSG_ARGS_SYNTAX_ERR "?SetArgs erreur de syntaxe: %s inattendu après %s"
+#define MSG_ARG_ALREADY_SET "Argument %d déjà alloué"
+#define MSG_ARG_NOT_AN_ATTR "L'argument n'est pas un attribut (type %d erroné)"
+#define MSG_ARG_OUT_CONTEXT "Argument de type @ utilisé hors contexte"
+#define MSG_ARG_OUT_RANGE "Argument de phrase valant %d hors limite"
+#define MSG_ARG_PTR_NOSEM "Argument valant %d pointe sur un noeud sans Sem"
+#define MSG_ARG_PTR_NOSEMS "Argument valant %d pointe sur un noeud sans sémantique"
+#define MSG_ARG_REF_LOOP "?Bouclage entre références croisées des arguments"
+#define MSG_ARG_TWO_CONST "Le 2ème argument de %s doit être constant"
+#define MSG_ARRAY_ALLOC_ERR "Erreur d'allocation mémoire dans ARRAY"
+#define MSG_ARRAY_BNDS_EXCD "Hors limite de tableau"
+#define MSG_ARRAY_ERROR "Erreur de fonctionnement k=%d n=%d"
+#define MSG_ATTRIBUTE_ERROR "Erreur règle %u attribut %s: "
+#define MSG_ATT_NOT_CASE "Mauvaise valeur %d pour attribut (pas une CaseValue)"
+#define MSG_ATT_POSCODE_BIG "Code attribut %d trop grand (max=%d)"
+#define MSG_AVGLEN_ERROR "avglen doit être entre %d et %d"
+#define MSG_BAD_AGGREG_FUNC "Fonction aggrégée %d non supportée"
+#define MSG_BAD_ARGTYPES "Argument de type invalide pour %s"
+#define MSG_BAD_ARGUMENTS "Argument not attachés pour %s"
+#define MSG_BAD_ARG_NUM "Nombre d'arguments invalide %d"
+#define MSG_BAD_ARG_TYPE "Type d'argument %d invalide"
+#define MSG_BAD_ARRAY_OPER "Les tableaux doivent utiliser l'opérateur IN"
+#define MSG_BAD_ARRAY_TYPE "Type=%d invalide pour un tableau"
+#define MSG_BAD_ARRAY_VAL "Les tableaux doivent avoir le même nombre de valeurs"
+#define MSG_BAD_BIN_FMT "Format invalide %c pour la colonne BIN %s"
+#define MSG_BAD_BLK_ESTIM "Nombre de blocs supérieur à l'estimation"
+#define MSG_BAD_BLK_SIZE "Taille du bloc %d non conforme"
+#define MSG_BAD_BYTE_NUM "Le nombre d'octets écrits est faux"
+#define MSG_BAD_BYTE_READ "Le nombre d'octets lus est faux"
+#define MSG_BAD_CARDINALITY "Appel invalide de Cardinality pour une table multiple"
+#define MSG_BAD_CASE_SPEC "Min/Maj: spécification %c incorrecte, recommencez: "
+#define MSG_BAD_CHAR_SPEC "Spécification '%s' invalide pour caractère"
+#define MSG_BAD_CHECK_TYPE "Sous-type %d invalide pour CheckColumn"
+#define MSG_BAD_CHECK_VAL "Valeur pour Check invalide '%s'"
+#define MSG_BAD_COLCRT_ARG "COLCRT: Arg invalide (type=%hd, domain=%hd)"
+#define MSG_BAD_COLDEF_TYPE "Coldefs: type illégal %d"
+#define MSG_BAD_COLIST_ITEM "Elément invalide dans une Colist"
+#define MSG_BAD_COLIST_TYPE "Mauvais type=%d pour une Colist"
+#define MSG_BAD_COLSIZE "Colsize %d trop petit pour cette base de données"
+#define MSG_BAD_COL_ENTRY "Entrée invalide pour la colonne %s"
+#define MSG_BAD_COL_FORMAT "Type de formattage %d invalide pour une colonne"
+#define MSG_BAD_COL_IN_FILT "Colonne incorrecte dans un filtre"
+#define MSG_BAD_COL_QUALIF "Qualificateur invalide %s pour la colonne %s"
+#define MSG_BAD_COL_TYPE "Type invalide %s pour la colonne %s"
+#define MSG_BAD_COL_XPATH "Xpath invalide colonne %s de la table HTML %s"
+#define MSG_BAD_COMPARE_OP "Opérateur de comparaison %d invalide"
+#define MSG_BAD_CONST_TYPE "Type=%d invalide pour une constante"
+#define MSG_BAD_CONV_TYPE "Convertion de type invalide %d"
+#define MSG_BAD_CORREL "Select %s.* corrélation absente"
+#define MSG_BAD_DATETIME "Valeur date/temps invalide"
+#define MSG_BAD_DATE_OPER "Opérateur de date inattendu %d"
+#define MSG_BAD_DBF_FILE "Le fichier DBF %s est altéré"
+#define MSG_BAD_DBF_REC "Fichier DBF %s altéré enregistrement %d"
+#define MSG_BAD_DBF_TYPE "Type DBF %c non supporté"
+#define MSG_BAD_DEF_ARG "Argument invalide pour INDEXDEF (type=%hd, domain=%hd)"
+#define MSG_BAD_DEF_READ "EOF inattendue en lecture différée"
+#define MSG_BAD_DEF_TYPE "Type de colonne invalide"
+#define MSG_BAD_DIRECTORY "Répertoire invalide %s: %s"
+#define MSG_BAD_DIST_JN_FIL "Filtre de jointure distincte invalide"
+#define MSG_BAD_DIST_JOIN "Spécification invalide de jointure distincte"
+#define MSG_BAD_DOM_COL_DEF "Définition de colonnes invalide pour un domaine"
+#define MSG_BAD_DOM_VALUE "La valeur %d n'appartient pas au domaine"
+#define MSG_BAD_EDIT_INIT "Coparm: édition %s initialisée improprement"
+#define MSG_BAD_EVAL_TYPE "Fonction scalaire de type=%d invalide"
+#define MSG_BAD_EXEC_MODE "Mode d'exécution invalide '%s'"
+#define MSG_BAD_EXP_ARGTYPE "Argument de type %d invalide pour une expression"
+#define MSG_BAD_EXP_OPER "Opérateur=%d invalide pour expression"
+#define MSG_BAD_FETCH_RC "Code retour inattendu de Fetch %d"
+#define MSG_BAD_FIELD_FMT "Format de champ invalide %c pour %s"
+#define MSG_BAD_FIELD_RANK "Rang %d invalide pour la colonne %s"
+#define MSG_BAD_FIELD_TYPE "Mauvais type de champ %s"
+#define MSG_BAD_FILE_HANDLE "Handle de fichier invalide: %s"
+#define MSG_BAD_FILE_LIST "La section liste de fichiers est erronée"
+#define MSG_BAD_FILTER "Mauvais filtre: Opc=%d B_T=%d %d Type=%d %d"
+#define MSG_BAD_FILTER_CONV "Conversion filtre incorrecte, B_T=%d,%d"
+#define MSG_BAD_FILTER_LINK "Opérateur de chaînage illégal %d"
+#define MSG_BAD_FILTER_OP "Opérateur de filtre invalide %d"
+#define MSG_BAD_FILTEST_OP "Opérateur invalide %d %d pour FilTest"
+#define MSG_BAD_FLD_FORMAT "Format invalide pour le champs %d de %s"
+#define MSG_BAD_FLD_LENGTH "Champs %s trop long (%s --> %d) ligne %d de %s"
+#define MSG_BAD_FLOAT_CONV "Convertion invalide d'un tableau flottant"
+#define MSG_BAD_FPARM_NEXT "Coparm: FPARM avec Next non nul"
+#define MSG_BAD_FREQ_SET "Spécification erronnée de Freq pour la colonne %s"
+#define MSG_BAD_FUNC_ARG "Funcarg de type %d non implémenté"
+#define MSG_BAD_FUNC_ARGTYP "Mauvais type d'argument=%d pour une fonction"
+#define MSG_BAD_FUNC_MODE "%s: mode invalide %d"
+#define MSG_BAD_GENRE "Genre est invalide"
+#define MSG_BAD_GETVIEW_RET "GetView: type de retour %d invalide"
+#define MSG_BAD_HANDLE_VAL "Valeur Handle invalide"
+#define MSG_BAD_HAV_FILTER "Filtre Having sur une requête non groupée"
+#define MSG_BAD_HAV_FILTYPE "Filtre invalide pour clause Having"
+#define MSG_BAD_HEADER "Fichier %s: bloc en-tête altéré"
+#define MSG_BAD_HEADER_VAL "Valeur invalide pour Header"
+#define MSG_BAD_HEAD_END "Lecture fin d'en-tête impossible"
+#define MSG_BAD_INDEX_COL "Colonne %s invalide pour index %s"
+#define MSG_BAD_INDEX_DEF "Définition invalide pour index %s"
+#define MSG_BAD_INDEX_FILE "Fichier index %s corrompu"
+#define MSG_BAD_INDEX_PART "Définition colonne invalide pour index %s"
+#define MSG_BAD_INPUT "Entrée incorrecte"
+#define MSG_BAD_IN_ARGTYPE "Argument de type invalide pour l'opérateur IN"
+#define MSG_BAD_IN_ENDING "Erreur: fin de chaîne IN invalide"
+#define MSG_BAD_IN_STRING "La chaîne IN commence ou finie par des caractères invalides %c ... %c"
+#define MSG_BAD_JCOL_TYPE "Erreur logique JCT: disparité des types colonnes"
+#define MSG_BAD_JOIN_EXP "Expression invalide pour une jointure"
+#define MSG_BAD_JOIN_FILTER "Filtre de jointure invalide"
+#define MSG_BAD_JOIN_OP "Opérateur de joint invalide %d"
+#define MSG_BAD_LANG_SIZE "Le fichier langage a une mauvaise taille %d"
+#define MSG_BAD_LINEFLD_FMT "Format invalide ligne %d champs %d de %s"
+#define MSG_BAD_LINE_LEN "Longueur ligne non égale à Lrecl"
+#define MSG_BAD_LIST_TYPE "Type de liste invalide %d"
+#define MSG_BAD_LOCALE "Locale invalide %s"
+#define MSG_BAD_LOCDFON_ARG "Mauvais paramètre pour LOCDFON"
+#define MSG_BAD_LOCNODE_USE "Usage inattendu de LOCNODE"
+#define MSG_BAD_LRECL "Disparité lrecl table/fichier (%d,%hd)"
+#define MSG_BAD_MAX_HAVING "MAXTMP trop petit pour Having"
+#define MSG_BAD_MAX_NREC "MaxRec=%d ne correspond pas à MaxBlk=%d Nrec=%d"
+#define MSG_BAD_MAX_PARAM "Mauvais paramètres pour spécifier une valeur maximum"
+#define MSG_BAD_MAX_SETTING "Mauvaise valeur '%c' pour max"
+#define MSG_BAD_MERGE_TYPE "Le type %d ne pas être intercallé"
+#define MSG_BAD_NODE_TYPE "Type noeud erroné pour la table"
+#define MSG_BAD_OFFSET_VAL "Nul offset invalide pour une table CSV"
+#define MSG_BAD_OPEN_MODE "Mode d'ouverture invalide %d"
+#define MSG_BAD_OPERATOR "Opérateur invalide %s"
+#define MSG_BAD_ORDER_MODE "Mode de tri %c invalide"
+#define MSG_BAD_ORDER_TYPE "Tri sur objet de type=%d invalide"
+#define MSG_BAD_OUTER_JOIN "Jointure externe invalide sur table enfant"
+#define MSG_BAD_PAD_ARGTYP "Argument de type invalide pour Pad ou Justify"
+#define MSG_BAD_PARAMETERS "%.8s: Mauvais paramètres"
+#define MSG_BAD_PARAM_TYPE "%.8s: Paramètre de type=%d invalide"
+#define MSG_BAD_PARM_COUNT "Nombre de paramètres incohérent"
+#define MSG_BAD_PHASE_NUM "Numéro de phrase %d hors limite"
+#define MSG_BAD_PHRASE_NB "numéro de phrase hors limite %d rc=%d\n"
+#define MSG_BAD_POS_CODE "POS_code invalide %d"
+#define MSG_BAD_POS_TYPE "Type de POS_code invalide %d"
+#define MSG_BAD_PROJNUM "Mauvais projnum %d pour la colonne %s"
+#define MSG_BAD_QUERY_OPEN "Mode invalide %d pour l'ouverture d'une requête"
+#define MSG_BAD_QUERY_TYPE "Type de requête %d invalide pour %s"
+#define MSG_BAD_QUOTE_FIELD "Quote manquante dans %s champs %d ligne %d"
+#define MSG_BAD_READ_NUMBER "Mauvais nombre %d de valeurs lues dans %s"
+#define MSG_BAD_RECFM "Recfm type %d invalide pour DOSCOL"
+#define MSG_BAD_RECFM_VAL "Valeur invalide %d de Recfm"
+#define MSG_BAD_RESULT_TYPE "Mauvais type de résultat %d pour %s"
+#define MSG_BAD_RETURN_TYPE "Type de retour %d incorrect"
+#define MSG_BAD_ROW_VALIST "Liste de valeurs invalide pour ROW"
+#define MSG_BAD_ROW_VALNB "Nombre de valeurs inégal dans la liste"
+#define MSG_BAD_SCF_ARGTYPE "Argument %d de type=%s invalide pour %s"
+#define MSG_BAD_SEM_DOMAIN "Domain .%d invalide"
+#define MSG_BAD_SETTINGS "Certaines spécifications sont incompatibles avec le type de la table"
+#define MSG_BAD_SET_CASE "La casse d'un tableau ne peut pas passer de non respect à respecter"
+#define MSG_BAD_SET_STRING "SetValue: appel invalide pour STRING"
+#define MSG_BAD_SET_TYPE "Set type %hd invalide"
+#define MSG_BAD_SPECIAL_CMD "Commande spéciale invalide"
+#define MSG_BAD_SPECIAL_COL "Colonne spéciale invalide %s"
+#define MSG_BAD_SPEC_COLUMN "Colonne spéciale invalide pour ce type de table"
+#define MSG_BAD_SQL_PARAM "Paramètre SQL invalide pour FindColblk"
+#define MSG_BAD_SUBLST_TYPE "Coparm: type %d de sous-liste invalide"
+#define MSG_BAD_SUBSEL_IN_X "Sub-select invalide pour une expression"
+#define MSG_BAD_SUBSEL_TYPE "Type %d invalide retourné de Sub-Select"
+#define MSG_BAD_SUB_RESULT "Résultat indéfini de fonction Sub-Select"
+#define MSG_BAD_SUB_SELECT "Sub-select invalide comme argument de fonction"
+#define MSG_BAD_TABLE_LINE "Ligne '%s' illégale ou tronquée dans la section Tables"
+#define MSG_BAD_TABLE_LIST "Table %s absente de la liste des tables"
+#define MSG_BAD_TABLE_TYPE "Type invalide %s pour la table %s"
+#define MSG_BAD_TEST_TYPE "BlockTest sur tableau: types dépareillés %s %s"
+#define MSG_BAD_TRIM_ARGTYP "Argument de type invalide pour Trim"
+#define MSG_BAD_TYPE_FOR_IN "Types d'argument incompatibles pour la fonction IN"
+#define MSG_BAD_TYPE_FOR_S "Type incorrecte %d pour %s(%d)"
+#define MSG_BAD_TYPE_LIKE "Type(%d)= %d invalide pour LIKE"
+#define MSG_BAD_UPD_COR "Le qualificateur %s de la colonne %s ne se refère pas à la table mise à jour %s"
+#define MSG_BAD_USERBLK_LEN "Mauvaise longueur à l'écriture du bloc utilisateur"
+#define MSG_BAD_USETEMP "Usetemp invalide '%s'"
+#define MSG_BAD_USETEMP_VAL "Valeur pour Usetemp invalide %d"
+#define MSG_BAD_VALBLK_INDX "Valeur hors limites de l'index du bloc de valeurs"
+#define MSG_BAD_VALBLK_TYPE "Type=%d invalide pour un bloc de valeurs"
+#define MSG_BAD_VALNODE "Type %d invalide pour le noeud valeur colonne %s"
+#define MSG_BAD_VALUE_TYPE "Type de valeur invalide %d"
+#define MSG_BAD_VAL_UPDATE "Impossible de déterminer quelle valeur %s doit être mise à jour"
+#define MSG_BAD_VIEW_OPEN "Mode invalide %d pour l'ouverture d'une View"
+#define MSG_BAD_XMODE_VAL "Mode d'exécution %d invalide"
+#define MSG_BAD_XOBJ_TYPE "Mauvais type de Xobject %d"
+#define MSG_BAS_NS_LIST "Format invalide de la liste des espace-noms"
+#define MSG_BIN_F_TOO_LONG "Valeur trop longue pour le champ %s (%d --> %d)"
+#define MSG_BIN_MODE_FAIL "Echec mode binaire: %s"
+#define MSG_BLKTYPLEN_MISM "Disparité types/longueurs de bloc dans SetValue"
+#define MSG_BLK_IS_NULL "Blk est nul"
+#define MSG_BLOCK_NO_MATCH "Bloc non correspondant"
+#define MSG_BREAKPOINT "Point de contrôle"
+#define MSG_BUFF_TOO_SMALL "GetColData: Buffer trop petit"
+#define MSG_BUFSIZE_ERROR "Erreur en recherchant la taille du buffer"
+#define MSG_BUILDING_GROUPS "Formation des groupes"
+#define MSG_BUILD_DIST_GRPS "Formation des groupes distinctes"
+#define MSG_BUILD_INDEX "Construction index %s sur %s"
+#define MSG_BXP_NULL "Bxp nul dans PUTFON"
+#define MSG_CANNOT_OPEN "Ouverture impossible de %s"
+#define MSG_CD_ONE_STEP "Count Distinct doit être exécuté en une seule étape"
+#define MSG_CD_ORDER_ERROR "Erreur de tri dans Count Distinct"
+#define MSG_CHECKING_ROWS "Test des lignes à mettre à jour"
+#define MSG_CHECK_LEVEL "Niveau de vérification fixé à %u"
+#define MSG_CHSIZE_ERROR "Erreur dans chsize: %s"
+#define MSG_CLN_NOT_IN_JOIN "La colonne C%d n'est pas dans le join"
+#define MSG_CNTDIS_COL_LOST "Colonne du Count Distinct perdue"
+#define MSG_COLIST_BAD_TYPE "Type=%d invalide pour Colist"
+#define MSG_COLNAM_TOO_LONG "Nom de colonne trop long"
+#define MSG_COLSEC_TOO_BIG "Section colonne trop grande, table %s (%d)"
+#define MSG_COLS_REDUCED " (réduit par Maxcol)"
+#define MSG_COLUMN_ERROR "Erreur de colonne"
+#define MSG_COLUMN_MISMATCH "Colonne %s dépareillée"
+#define MSG_COLUMN_NOT_KEY "La colonne jointe R%d.%s n'est pas une clé"
+#define MSG_COL_ALLOC_ERR "Allocation impossible du noeud colonne"
+#define MSG_COL_ALLOC_ERROR "Erreur d'allocation mémoire pour la colonne %d"
+#define MSG_COL_HAS_NO_DEF "La colonne %s n'est pas définie"
+#define MSG_COL_INVAL_TABLE "La colonne %s.%s n'existe pas dans la table %s alias %s"
+#define MSG_COL_ISNOT_TABLE "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NB_MISM "Le nombre de colonnes ne correspond pas"
+#define MSG_COL_NOTIN_GRPBY "La colonne %s n'est pas dans la liste de Group By"
+#define MSG_COL_NOTIN_TABLE "La colonne %s n'est dans aucune table"
+#define MSG_COL_NOTIN_UPDT "%s n'appartient pas à la table mise à jour %s"
+#define MSG_COL_NOT_CODED "La colonne %s n'est pas codifiée"
+#define MSG_COL_NOT_EXIST "La colonne %s n'existe pas dans %s"
+#define MSG_COL_NOT_FOUND "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NOT_IN_DB "La colonne %s de la table %s n'est pas dans la base de données"
+#define MSG_COL_NOT_IN_JOIN "La colonne %s n'est pas dans le join"
+#define MSG_COL_NOT_SORTED "La colonne %s de la table %s n'est pas triée"
+#define MSG_COL_NUM_MISM "Disparité du nombre de colonnes"
+#define MSG_COL_USED_TWICE "Colonne %s utilisée deux fois ???"
+#define MSG_COMPUTE_ERROR "Erreur dans Compute, op=%d"
+#define MSG_COMPUTE_NIY "Compute non implémenté pour TOKEN"
+#define MSG_COMPUTING "Calculs en cours"
+#define MSG_COMPUTING_DIST "Comptage des valeurs distinctes"
+#define MSG_COMPUTING_FUNC "Calcul de(s) fonction(s)"
+#define MSG_COM_ERROR "Erreur Com"
+#define MSG_CONCAT_SUBNODE "Concaténation de sous-noeuds impossible"
+#define MSG_CONNECTED "Connecté"
+#define MSG_CONNECT_CANCEL "Connection interrompue par l'utilisateur"
+#define MSG_CONNECT_ERROR "Erreur %d se connectant à %s"
+#define MSG_CONN_CLOSED "%s(%d) fermée"
+#define MSG_CONN_CREATED "Connexion %s crée"
+#define MSG_CONN_DROPPED "Connexion %s supprimée"
+#define MSG_CONN_OPEN "%s(%d) ouverte (%s)"
+#define MSG_CONN_SUC_OPEN "%s(%d) ouverte avec succès"
+#define MSG_CONTROL_C_EXIT "Exit par Ctrl-C"
+#define MSG_COPY_BAD_PHASE "Copie de liste invalide en phase %d"
+#define MSG_COPY_INV_TYPE "Coparm: type non supporté %d"
+#define MSG_CORREL_NO_QRY "Les sous-requêtes corrélées ne peuvent pas être de type QRY"
+#define MSG_CREATED_PLUGDB " Créé par PlugDB %s "
+#define MSG_CURSOR_SET "Curseur remis à %d"
+#define MSG_DATABASE_ACTIVE "Base de données %s activée"
+#define MSG_DATABASE_LOADED "Base de données %s chargée"
+#define MSG_DATA_IS_NULL "ExecSpecialCmd: data est NULL"
+#define MSG_DATA_MISALIGN "Mauvais alignement pour ce type de données"
+#define MSG_DBASE_FILE "Fichier dBASE dbf: "
+#define MSG_DB_ALREADY_DEF "Base de données %s déjà définie"
+#define MSG_DB_ALTERED "Base de données modifiée"
+#define MSG_DB_CREATED "Base de données %s créée"
+#define MSG_DB_NOT_SPEC "Base de données non spécifiée"
+#define MSG_DB_REMOVED "Base de données %s retirée de la liste"
+#define MSG_DB_SORT_ERROR "Erreur de tri DB"
+#define MSG_DB_STOPPED "Arrêt de la base de données %s"
+#define MSG_DEBUG_NOT_ACTIV "Mode Debug inactif"
+#define MSG_DEBUG_SET_INV "Invalide pour Debug: %c"
+#define MSG_DEF_ALLOC_ERROR "Erreur d'allocation de la classe DEF %s"
+#define MSG_DELETING_ROWS "Suppression des lignes"
+#define MSG_DEL_FILE_ERR "Erreur à l'effacement de %s"
+#define MSG_DEL_READ_ERROR "Delete: erreur en lecture req=%d len=%d"
+#define MSG_DEL_WRITE_ERROR "Delete: erreur en écriture: %s"
+#define MSG_DEPREC_FLAG "Option Flag périmée, utiliser Coltype"
+#define MSG_DICTIONARY "Dictionnaire "
+#define MSG_DIRECT_VARTOK "Accès direct aux règles du Variable Token non implémenté"
+#define MSG_DISCONNECTED "Déconnecté"
+#define MSG_DISTINCT_ERROR "Plus d'un élément fonctionel DISTINCT"
+#define MSG_DISTINCT_ROWS "Sélection des lignes distinctes"
+#define MSG_DISTINCT_VALUES "Extraction des valeurs distinctes"
+#define MSG_DIS_NOHEAD_JOIN "Jointure distincte sur une table non en tête"
+#define MSG_DLL_LOAD_ERROR "Erreur %d au chargement du module %s"
+#define MSG_DOMAIN_EMPTY "Le domaine %s est vide"
+#define MSG_DOMAIN_ERROR "Colonne %s: disparité domaine(%s)/valeur(%s)"
+#define MSG_DOMAIN_FULL "Le domaine %s est plein (max=%d)"
+#define MSG_DOM_FILE_ERROR "Fichier domain %s introuvable"
+#define MSG_DOM_NOT_SUPP "MS-DOM non supporté par cette version"
+#define MSG_DOM_OPEN_ERROR "Erreur d'ouverture du domaine: %s"
+#define MSG_DOM_READ_ERROR "Erreur %d en lecture de domaine: %s"
+#define MSG_DOM_READ_ONLY "La table domaine %s est en lecture seulement"
+#define MSG_DOM_WRITE_ERROR "Erreur %d en écriture de domaine: %s"
+#define MSG_DONE "Effectué, rc=%d"
+#define MSG_DOSALMEM_NOMEM "Erreur d'allocation, pas assez de mémoire"
+#define MSG_DROP_DB_ERR "Echec du Drop sur le base de données %s"
+#define MSG_DSORT_LOG_ERROR "Kindex: Erreur logique de tri distincte"
+#define MSG_DUMMY_NO_COLS "Les tables DUMMY ne peuvent pas avoir de colonne"
+#define MSG_DUPLICAT_COUNT "Count sur plus d'une colonne"
+#define MSG_DUP_COL_NAME "La colonne %s existe en double"
+#define MSG_DUP_PROJNUM "Non unique projnum %d pour la colonne %s"
+#define MSG_DVAL_NOTIN_LIST "Valeur %s non trouvée dans la liste des valeurs distinctes de la colonne %s"
+#define MSG_EMPTY_DOC "Document vide"
+#define MSG_EMPTY_FILE "%s du fichier vide %s: "
+#define MSG_ENDSTR_MISMATCH "Fins de chaîne et de noeud ne correspondent pas"
+#define MSG_END_OF_DELETE "%d ligne(s) enlevée(s) en %.2lf sec"
+#define MSG_END_OF_INSERT "%d ligne(s) insérée(s) en %.2lf sec"
+#define MSG_END_OF_QUERY "%d ligne(s) extraite(s) en %.2lf sec"
+#define MSG_END_OF_UPDATE "%d ligne(s) modifiée(s) en %.2lf sec"
+#define MSG_EOF_AFTER_LINE "Fin de fichier après la ligne %d"
+#define MSG_EOF_INDEX_FILE "EOF lisant le fichier index"
+#define MSG_ERASED " et effacée"
+#define MSG_ERASE_FAILED " (échec de l'effacement)"
+#define MSG_ERROR "Erreur"
+#define MSG_ERROR_IN_LSK "Erreur %d dans lseek64"
+#define MSG_ERROR_IN_SFP "Erreur %d dans SetFilePointer"
+#define MSG_ERROR_NO_PARM "Paramètre absent (valide seulement pour %.8s.1 et %.8s.5)"
+#define MSG_ERROR_OPENING "Erreur à l'ouverture de : "
+#define MSG_ERR_NUM_GT_MAX "Erreur: Numval (%d) plus grand que Maxnum (%d)"
+#define MSG_ERR_READING_REC "Erreur lisant l'enregistrement %d de %s"
+#define MSG_ERR_RET_RULE "Retour erreur, règle=%u"
+#define MSG_ERR_RET_TYPE "Retour erreur, type=%d"
+#define MSG_EVAL_EXPIRED "Cette version d'évaluation est expirée"
+#define MSG_EVAL_ONLY "L'utilisation de cette Dll est pour évaluation seulement"
+#define MSG_EXECUTING "Exécution"
+#define MSG_EXECUTION_ERROR "Erreur d'exécution"
+#define MSG_EXEC_MODE_IS "Le mode d'exécution est %s"
+#define MSG_EXEC_MODE_RESET ". Mode remis à Execute"
+#define MSG_EXEC_MODE_SET "Mode d'exécution fixé à %s"
+#define MSG_EXIT_EVAL_ERR "Erreur pendant l'évaluation de Exit"
+#define MSG_EXIT_FROM_LANG "Fin du langage %s version %d.%d"
+#define MSG_FAIL_ADD_NODE "L'ajout du noeud %s dans la table a échoué"
+#define MSG_FETCHING_DATA "Recherche des données"
+#define MSG_FETCHING_ROWS "Recherche des lignes"
+#define MSG_FETCH_NO_RES "Fetch: Pas de Résultats"
+#define MSG_FIELD_TOO_LONG "Valeur trop longue pour le champs %d ligne %d"
+#define MSG_FILELEN_ERROR "Erreur dans %s pour %s"
+#define MSG_FILE_CLOSE_ERR "Erreur %d à la fermeture du fichier"
+#define MSG_FILE_IS_EMPTY "Le fichier %s est vide"
+#define MSG_FILE_MAP_ERR "Erreur de File mapping"
+#define MSG_FILE_MAP_ERROR "CreateFileMapping %s erreur rc=%d"
+#define MSG_FILE_NOT_FOUND "Fichier %s introuvable"
+#define MSG_FILE_OPEN_YET "Fichier %s déjà ouvert"
+#define MSG_FILE_UNFOUND "Fichier %s non trouvé"
+#define MSG_FILGRP_NO_TABLE "Table %d manquante pour groupe filtre"
+#define MSG_FILTER_ATTACH "Filtre passé à Attach"
+#define MSG_FILTER_NO_TABLE "Filtre: première table manquante"
+#define MSG_FIND_BAD_TYPE "Recherche dans un tableau: type non conforme %s %s"
+#define MSG_FIX_OVFLW_ADD "Dépassement de capacité en addition"
+#define MSG_FIX_OVFLW_TIMES "Dépassement de capacité en mutiplication"
+#define MSG_FIX_UNFLW_ADD "Sous dépassement de capacité en addition"
+#define MSG_FIX_UNFLW_TIMES "Sous dépassement de capacité en multiplication"
+#define MSG_FLD_TOO_LNG_FOR "Champs %d trop long pour %s ligne %d de %s"
+#define MSG_FLTST_NO_CORREL "FilTest ne devrait être appelé que pour les sous-requêtes corrélées"
+#define MSG_FLT_BAD_RESULT "Virgule flottante: résultat inexacte"
+#define MSG_FLT_DENORMAL_OP "Opérande virgule flottante non normalisé"
+#define MSG_FLT_INVALID_OP "Opération virgule flottante invalide"
+#define MSG_FLT_OVERFLOW "Dépassement de capacité virgule flottante"
+#define MSG_FLT_STACK_CHECK "Virgule flottante: Erreur de la pile"
+#define MSG_FLT_UNDERFLOW "Sous-dépassement de capacité virgule flottante"
+#define MSG_FLT_ZERO_DIVIDE "Virgule flottante: division par zéro"
+#define MSG_FMT_WRITE_NIY "L'écriture des fichiers %s n'est pas encore implémentée"
+#define MSG_FNC_NOTIN_SLIST "Fonction de tri absente de la liste de sélection"
+#define MSG_FORMAT_ERROR "Erreur de formattage"
+#define MSG_FOXPRO_FILE "Fichier FoxPro: "
+#define MSG_FPUTS_ERROR "Erreur dans fputs: %s"
+#define MSG_FSBPARP_NULL "PUTFON: fsbparp est nul"
+#define MSG_FSEEK_ERROR "Erreur dans fseek: %s"
+#define MSG_FSETPOS_ERROR "Erreur dans fseek pour i=%d"
+#define MSG_FTELL_ERROR "Erreur dans ftell enregistrement=%d: %s"
+#define MSG_FUNCTION_ERROR "Erreur dans %s: %d"
+#define MSG_FUNC_ERRNO "Erreur %d dans %s"
+#define MSG_FUNC_ERROR "Erreur dans %s"
+#define MSG_FUNC_ERR_S "Erreur dans %s: %s"
+#define MSG_FUNC_REF_DEL "Référence à une fonction définie (règle %d) qui a été supprimée"
+#define MSG_FWRITE_ERROR "Erreur dans fwrite: %s"
+#define MSG_GETCWD_ERR_NO "?getcwd %s errno=%d"
+#define MSG_GETFILESIZE_ERR "Erreur %d dans GetFileSize"
+#define MSG_GET_DIST_VALS "Récupération des valeurs distinctes de "
+#define MSG_GET_ERROR "Erreur dans %s (colonne %d)"
+#define MSG_GET_FUNC_ERR "Erreur en recherche de la fonction %s: %s"
+#define MSG_GET_NAME_ERR "Erreur en retrouvant le nom d'une table SYS"
+#define MSG_GLOBAL_ERROR "Erreur d'allocation de Global (taille=%d)\n"
+#define MSG_GRAM_ALLOC_ERR "Erreur d'allocation dans Grammar Up"
+#define MSG_GRAM_MISMATCH "Avertissement: version de GRAMMAR perimée (sauvé sous GRAMMAR v%u)"
+#define MSG_GRAM_SUBSET_ERR "Erreur d'initialisation du dictionnaire de la grammaire"
+#define MSG_GRBY_TAB_NOTIMP "Group by avec tables jointes non implémenté"
+#define MSG_GROUPBY_NOT_ALL "Group By doit inclure toutes les sélections non-fonctionnelles"
+#define MSG_GROUP_ON_FUNC "Group by invalide sur colonne fonctionnelle"
+#define MSG_GRP_COL_MISM "Disparité colonne des groupes"
+#define MSG_GRP_LIST_MISMAT "Le groupement ne couvre pas la liste de sélection"
+#define MSG_GUARD_PAGE "Violation de page de garde"
+#define MSG_GZOPEN_ERROR "gzopen %s: erreur %d sur %s"
+#define MSG_GZPUTS_ERROR "Erreur dans gzputs: %s"
+#define MSG_HANDLE_IS_NULL "%s est NULL: erreur code: %d"
+#define MSG_HARRY_COMP_NIY "Compute non implémenté pour les chaînes codées"
+#define MSG_HAVING_FILTER "Traitement du Filtre Having"
+#define MSG_HBUF_TOO_SMALL "Buffer(%d) trop petit pour entête(%d)"
+#define MSG_HEAD_OPEN_ERROR "Erreur à l'ouverture du fichier header"
+#define MSG_HEAD_READ_ERROR "Erreur en lecture du fichier header %s"
+#define MSG_HEAD_WRITE_ERR "Erreur en écriture du fichier header"
+#define MSG_HI_OFFSET_ERR "Offset supérieur non nul"
+#define MSG_HUGE_DEFAULT "Huge est %d par défault"
+#define MSG_HUGE_WARNING_1 "Mémoire Huge non compatible 16-bit pour %d\n"
+#define MSG_HUGE_WARNING_2 "Résultats imprévisibles possibles\n"
+#define MSG_IDLE "Au repos"
+#define MSG_ILLEGAL_INSTR "Instruction illégale"
+#define MSG_ILL_FILTER_CONV "Conversion implicite illégale dans un filtre"
+#define MSG_INDEX_CREATED "Index %s créé sur %s"
+#define MSG_INDEX_DEF_ERR "Erreur sauvegardant l'index définition pour %s"
+#define MSG_INDEX_DROPPED "Index %s supprimé de %s"
+#define MSG_INDEX_INIT_ERR "Echec de l'initialisation de l'index %s"
+#define MSG_INDEX_NOT_DEF "Index %s non défini"
+#define MSG_INDEX_NOT_UNIQ "L'index n'est pas Unique"
+#define MSG_INDEX_ONE_SAVE "Les index sont sauvegardés dans un fichier unique"
+#define MSG_INDEX_SEP_SAVE "Les index sont sauvegardés dans des fichiers séparés"
+#define MSG_INDEX_YET_ON "L'index %s existe déjà sur %s"
+#define MSG_INDX_ALL_DROP "Tous les index de %s supprimés"
+#define MSG_INDX_COL_NOTIN "La colonne index %s n'existe pas dans la table %s"
+#define MSG_INDX_EXIST_YET "L'entrée index existe déjà"
+#define MSG_INIT_ERROR "Erreur à l'initialisation de %s"
+#define MSG_INIT_FAILED "L'initialisation de %s a échoué"
+#define MSG_INPUT "Entrée: "
+#define MSG_INPUT_KEYBD_YET "L'entrée est déjà au clavier"
+#define MSG_INSERTING "Insertion: "
+#define MSG_INSERT_ERROR "Insert erreur: usage multiple du fichier %s"
+#define MSG_INSERT_MISMATCH "Les listes colonne et valeur ne correspondent pas"
+#define MSG_INTERNAL "interne"
+#define MSG_INT_COL_ERROR "Erreur interne sur la colonne index %s"
+#define MSG_INT_OVERFLOW "Dépassement de capacité sur entier"
+#define MSG_INT_ZERO_DIVIDE "Division entière par zéro"
+#define MSG_INVALID_BIP "Bip invalide .%d"
+#define MSG_INVALID_DISP "Disposition invalide"
+#define MSG_INVALID_FTYPE "SBV: Ftype %d invalide"
+#define MSG_INVALID_HANDLE "Poignée invalide"
+#define MSG_INVALID_OPER "Opérateur invalide %d pour %s"
+#define MSG_INVALID_OPTION "Option invalide %s"
+#define MSG_INV_COLUMN_TYPE "Type %d Invalide pour la colonne %s"
+#define MSG_INV_COL_DATATYP "Type de données %d invalide pour la colonne %d"
+#define MSG_INV_COL_NUM "Colonne invalide %d"
+#define MSG_INV_COL_TYPE "Type de colonne %s invalide"
+#define MSG_INV_CONC_BIP "Bip invalide (seuls valides: %.8s.0 .1 and .5)"
+#define MSG_INV_DATA_PATH "Chemin vers les données invalide"
+#define MSG_INV_DEF_READ "Lecture différée invalide rc=%d"
+#define MSG_INV_DIRCOL_OFST "Offset invalide pour une colonne DIR"
+#define MSG_INV_DOMAIN_TYPE "Type invalide %d"
+#define MSG_INV_FILTER "Filtre résiduel dans %s"
+#define MSG_INV_FNC_BUFTYPE "FNC: Type %d de l'argument invalide pour %s"
+#define MSG_INV_INFO_TYPE "Type d'info catalog invalide %d"
+#define MSG_INV_INIPATH "Inipath invalide "
+#define MSG_INV_MAP_POS "Position mémoire invalide"
+#define MSG_INV_OPERATOR "opérateur invalide %d\n"
+#define MSG_INV_PARAMETER "Paramètre invalide %s"
+#define MSG_INV_PARM_TYPE "Type de paramètre invalide"
+#define MSG_INV_QUALIFIER "Qalificateur '%s' invalide"
+#define MSG_INV_QUERY_TYPE "Type de requête %d invalide"
+#define MSG_INV_RAND_ACC "L'accès aléatoire d'une table non optimisée est impossible"
+#define MSG_INV_REC_POS "Position d'enregistrement invalide"
+#define MSG_INV_RESULT_TYPE "Type de résultat invalide %s"
+#define MSG_INV_SET_SUBTYPE "Type de formattage %d invalide"
+#define MSG_INV_SPECIAL_CMD "%s: Commande spéciale invalide"
+#define MSG_INV_SUBTYPE "Sous type invalide %s"
+#define MSG_INV_TOK_DOMAIN "Le domaine %s n'existe pas"
+#define MSG_INV_TOPSEM_CMD "Commande TopSem invalide %c"
+#define MSG_INV_TRANSF_USE "Usage invalide en règle transformationnelle"
+#define MSG_INV_TYPE_SPEC "Spécification de type invalide (%.8s.%d)"
+#define MSG_INV_UPDT_TABLE "Table %s invalide pour Update"
+#define MSG_INV_VALUE_LIST "Liste de valeurs invalide pour Insert"
+#define MSG_INV_WHERE_JOIN "Clause Where invalide dans une requête de jointure"
+#define MSG_INV_WORK_PATH "Chemin de travail invalide"
+#define MSG_IN_ARGTYPE_MISM "Arguments de types incompatibles pour une expression IN"
+#define MSG_IN_USE " et en activité"
+#define MSG_IN_WITHOUT_SUB "IN ou EXISTS sans tableau ou subquery"
+#define MSG_IS_NOT_CONN "%s n'est pas une connexion définie"
+#define MSG_JCT_MISS_COLS "Colonnes manquantes pour une table JCT"
+#define MSG_JCT_MISS_TABLE "Table jointe manquante pour JCT"
+#define MSG_JCT_NO_FILTER "Filtrage impossible des tables virtuelles JCT"
+#define MSG_JCT_NO_KEY "Erreur logique JCT: clé manquante"
+#define MSG_JOIN_KEY_NO_COL "La clé de jointure n'est pas une colonne"
+#define MSG_KEY_ALLOC_ERR "Erreur d'allocation d'un bloc offset clé"
+#define MSG_KEY_ALLOC_ERROR "Erreur d'allocation mémoire, Klen=%d n=%d"
+#define MSG_LANGUAGE_QUIT "%s libéré"
+#define MSG_LANG_ACTIVE "Langage %s actif"
+#define MSG_LANG_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Lang"
+#define MSG_LANG_ALREADY_UP "Langage déjà en édition"
+#define MSG_LANG_BAD_SAVE "Langage %s peut-être incorrectement sauvegardé"
+#define MSG_LANG_NOT_FREED "Langage %s non libérable (pas dans la chaîne principale)"
+#define MSG_LANG_SAVED "Langage %s sauvegardé"
+#define MSG_LANG_WR_LEN_ERR "Erreur de longueur à l'écriture du bloc Lang"
+#define MSG_LDF_ALLOC_ERROR "Erreur d'allocation d'un LdfBlock"
+#define MSG_LDF_RN_MISMATCH "LDF: décalage des numéros de règle"
+#define MSG_LDF_WLEN_ERROR "Erreur de longueur en écrivant LdfData"
+#define MSG_LDF_W_LEN_ERROR "Erreur de longueur pour LdfData en écriture"
+#define MSG_LIC_NO_MYSQL "Votre licence actuelle ne permet pas l'utilisation du type MYSQL"
+#define MSG_LINEAR_ERROR "Erreur de linéarisation"
+#define MSG_LINE_LENGTH "Largeur d'impression fixée à %d"
+#define MSG_LINE_MAXLIN "Nombre de lignes de travail plafonné à %d"
+#define MSG_LINE_MAXRES "Nombre de lignes de résultat plafonné à %d"
+#define MSG_LINE_MAXTMP "Nombre de lignes intermédiaires plafonné à %d"
+#define MSG_LINE_TOO_LONG "La nouvelle ligne est trop longue"
+#define MSG_LINJOINDB_ERROR "Erreur système: appel incorrecte à LinJoinDB"
+#define MSG_LIST "--Liste--"
+#define MSG_LNG_NOT_IN_LIST "Le langage %s n'est pas dans la liste"
+#define MSG_LOADING_DB "Chargement description de la BD"
+#define MSG_LOADING_FAILED "Le chargement de %s a échoué"
+#define MSG_LOAD_CDLL_ERROR "Erreur au chargement de ConnDll: rc=%d"
+#define MSG_LOCSTRG_TOO_BIG "LOCSTRG: n trop grand ? (%d)\n"
+#define MSG_LOGICAL_ERROR "%s: Erreur logique"
+#define MSG_LRECL_TOO_SMALL "Lrecl trop petit (longueur en-tête = %d)"
+#define MSG_MAC_NO_DELETE "Pas de suppression de lignes pour les tables MAC"
+#define MSG_MAC_NO_INDEX "Pas d'accès direct aux tables MAC"
+#define MSG_MAC_READ_ONLY "Les tables MAC sont en lecture seulement"
+#define MSG_MAC_WIN_ONLY "Les tables MAC sont seulement sous Windows"
+#define MSG_MAKE_EMPTY_FILE "Génération du fichier vide %s: %s"
+#define MSG_MAKING "Génération"
+#define MSG_MAKING_DISTINCT "Regroupement des valeures distinctes"
+#define MSG_MALLOC_ERROR "Allocation mémoire impossible par %s"
+#define MSG_MALLOC_NULL "malloc retourne Null"
+#define MSG_MAP_NO_MORE "Le type %s n'est plus supporté"
+#define MSG_MAP_OBJ_ERR "Erreur %d à la fermeture du map objet"
+#define MSG_MAP_VEC_ONLY "MAP Insert permis seulement pour les tables VEC Estimate"
+#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s erreur rc=%d"
+#define MSG_MAXSIZE_ERROR "Maxsize incalculable sur table ouverte"
+#define MSG_MAXTMP_TRUNCATE "Résultats intermédiaires tronqués par maxtmp=%d"
+#define MSG_MAX_BITMAP "Taille maxi des bitmaps d'optimisation fixée à %d"
+#define MSG_MEMSIZE_TOO_BIG "Erreur: memsize (%d) trop grand pour Length (%d)"
+#define MSG_MEM_ALLOC_ERR "Erreur d'allocation mémoire, taille %s = %d"
+#define MSG_MEM_ALLOC_ERROR "Erreur d'allocation mémoire"
+#define MSG_MEM_ALLOC_YET "Mémoire déjà allouée"
+#define MSG_METAFILE_NOTFND "Fichier Meta introuvable"
+#define MSG_MISPLACED_QUOTE "Appostrophe mal placée ligne %d"
+#define MSG_MISSING "Manquant: Value=%p Argval=%p Builtin=%d"
+#define MSG_MISSING_ARG "Argument manquant pour l'opérateur %d"
+#define MSG_MISSING_COL_DEF "Définition des colonnes manquante"
+#define MSG_MISSING_CONNECT "Connection #1 manquante"
+#define MSG_MISSING_EOL "Fin de ligne manquante dans %s"
+#define MSG_MISSING_FIELD "Champs %d manquant dans %s ligne %d"
+#define MSG_MISSING_FNAME "Nom du fichier manquant"
+#define MSG_MISSING_NODE "Noeud %s manquant dans %s"
+#define MSG_MISSING_POS "POS code manquant"
+#define MSG_MISSING_ROWNODE "Impossible de trouver le noeud de la ligne %d"
+#define MSG_MISSING_SERV_DB "Indication serveur et/ou base de données manquante"
+#define MSG_MISS_LEAD_COL "Colonne majeure %s manquante"
+#define MSG_MISS_NAME_LRECL "Nom du fichier et/ou LRECL manquant"
+#define MSG_MISS_TABLE_LIST "Liste des tables manquante"
+#define MSG_MISS_VCT_ELMT "Taille de bloc vectoriel manquante (Elements)"
+#define MSG_MIS_TAG_LIST "Liste des balises colonne manquante"
+#define MSG_MKEMPTY_NIY "MakeEmptyFile: pas encore implementé pour Huge et Unix"
+#define MSG_MOVE_INV_TYPE "MOVPARM: paramètre de type invalide %d"
+#define MSG_MULT_DISTINCT "Distinct utilisé plus d'une fois"
+#define MSG_MULT_KEY_ERROR "Erreur sur clé multiple k=%d n=%d"
+#define MSG_MUL_MAKECOL_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_MYSQL_CNC_OFF "La connexion à MySQL est fermée"
+#define MSG_MYSQL_CNC_ON "La connexion à MySQL est établie"
+#define MSG_MYSQL_NOT_SUP "Pas de support de MySQL dans cette version"
+#define MSG_MY_CNC_ALREADY "La connexion à MySQL est déjà active"
+#define MSG_NAME_CONV_ERR "Erreur de convertion du nom de noeud"
+#define MSG_NAME_IS_USED "Le nom %s est déjà utilisé"
+#define MSG_NCOL_GT_MAXCOL "Trop de colonnes (%d > %d max)"
+#define MSG_NEW_CHAR_NULL "new char(%d) retourne Null"
+#define MSG_NEW_DOC_FAILED "Impossible de créer le nouveau document"
+#define MSG_NEW_RETURN_NULL "NULL renvoyé par New dans PlugEvalLike"
+#define MSG_NEW_TABLE_ERR "La nouvelle table %s ne peut pas être chargée"
+#define MSG_NEXT_FILE_ERROR "Erreur en recherche du fichier suivant. rc=%s"
+#define MSG_NODEF_FROM_VIEW "Pas de définition de table depuis une view"
+#define MSG_NODE_FOR_CHAR "Noeud %s trouvé au lieu d'un caractère"
+#define MSG_NODE_SUBSET_ERR "Erreur d'initialisation de la zone Noeud %d"
+#define MSG_NONCONT_EXCEPT "Exception non-continuable"
+#define MSG_NON_DUP_HAVING "Clause Having dans une requête non fonctionelle"
+#define MSG_NON_EVAL_SEM "Sem non évaluée: p_no=%d"
+#define MSG_NOP_ZLIB_INDEX "L'indexage d'une table zlib non optimisée est impossible"
+#define MSG_NOT_A_DBF_FILE "Le fichier n'a pas le format dBASE dbf "
+#define MSG_NOT_ENOUGH_COLS "Pas assez de colonnes dans %s"
+#define MSG_NOT_ENOUGH_MEM "Mémoire insuffisante pour cette opération"
+#define MSG_NOT_FIXED_LEN "Fichier %s non fixe, len=%d lrecl=%d"
+#define MSG_NOT_IMPLEMENTED "Non implementé: %.8s"
+#define MSG_NOT_IMPL_JOIN "Pas implémenté pour les jointures"
+#define MSG_NOT_IMPL_SET "Pas implémenté pour les opérateurs d'ensembles"
+#define MSG_NOT_IMPL_YET "Pas encore implementé"
+#define MSG_NOT_LINEARIZED "Arborescence des tables non linéarisée"
+#define MSG_NOT_MODIFIABLE " (non modifiable)"
+#define MSG_NO_0DH_HEAD "0DH manquant en fin d'en-tête (dbc=%d)"
+#define MSG_NO_ACTIVE_APPL "Pas d'application active"
+#define MSG_NO_ACTIVE_DB "Pas de base de données active"
+#define MSG_NO_ACTIVE_UDIC "Pas de dictionaire utilisateur actif"
+#define MSG_NO_AGGR_FUNC "Fonction aggrégée %d illégale à cet endroit"
+#define MSG_NO_AREA_FILE "Fichier Area introuvable"
+#define MSG_NO_AVAIL_RESULT "Pas de résultat disponible"
+#define MSG_NO_BIG_DELETE "Délétion Partielle non implémentée pour les fichiers HUGE"
+#define MSG_NO_CHAR_FROM "Conversion de type %d en caractères impossible"
+#define MSG_NO_CLUSTER_COL "Pas de colonne optimisable"
+#define MSG_NO_COL_ADDING "Ajouter des colonnes dans une définition existante est impossible"
+#define MSG_NO_COL_DEF_AS "La définitions des colonnes est incompatible avec AS Select"
+#define MSG_NO_COL_FOUND "La section colonne %s est vide"
+#define MSG_NO_COL_IN_TABLE "La colonne %d n'est pas dans la table %s"
+#define MSG_NO_COL_SECTION "Section colonne manquante pour la table %s"
+#define MSG_NO_CONNECT_ADDR "Adresse de connection non spécifiée"
+#define MSG_NO_CONST_FILTER "Filtres constants non implementés"
+#define MSG_NO_CURLY_BRKT "Pas d'accolade de fermeture"
+#define MSG_NO_DATABASE "Base de données %s introuvable"
+#define MSG_NO_DATE_FMT "Pas de format date pour le valblock de type %d"
+#define MSG_NO_DBF_INSERT "Insert pas encore implémenté pour les fichier DBF"
+#define MSG_NO_DEF_FNCCOL "Colonne fonction par défaut introuvable"
+#define MSG_NO_DEF_PIVOTCOL "Colonne pivot par défaut introuvable"
+#define MSG_NO_DIR_INDX_RD "Pas d'accès directe des tables %s"
+#define MSG_NO_DMY_DIR_ACC "Pas d'accès direct aux tables virtuelles DUMMY"
+#define MSG_NO_DOM_DELETE "Délétion Partielle non implémentée pour les domaines"
+#define MSG_NO_DOM_MATCH "Chaîne %.8s... non touvée dans le domaine %s"
+#define MSG_NO_EDITED_LANG "Coparm: Pas de langage en édition"
+#define MSG_NO_EXP_LINK "Liaison par expression invalide pour une table JCT"
+#define MSG_NO_EXT_FILTER "Le filtrage ne peut se référer à une autre table"
+#define MSG_NO_EXT_UPDATE "Pas de mise à jour en référence à une autre table"
+#define MSG_NO_FEAT_SUPPORT "%s non supporté dans cette version"
+#define MSG_NO_FILE_LIST "La table %s n'a pas de liste de fichiers"
+#define MSG_NO_FLD_FORMAT "Format absent pour le champs %d de %s"
+#define MSG_NO_FORMAT_COL "Type COLUMN informattable"
+#define MSG_NO_FORMAT_TYPE "Le format ne peut pas être défini à partir du type %d"
+#define MSG_NO_FULL_JOIN "Jointures autorisées seulement à égalité sur clé(s)"
+#define MSG_NO_FUL_OUT_JOIN "Jointures externes complètes non supportées"
+#define MSG_NO_FUNC_ORDER "Tri non supporté sur élément fonctionnel"
+#define MSG_NO_HEAD_JOIN "Jointure sur une table non en tête"
+#define MSG_NO_HQL_CONV "Conversion en HQL non disponible"
+#define MSG_NO_INDEX "La table %s n'a pas d'index"
+#define MSG_NO_INDEX_GBX "Pas ou mauvais index pour SQLGBX"
+#define MSG_NO_INDEX_IN "Pas d'index dans %s"
+#define MSG_NO_INDEX_READ "Pas d'accès directe des tables multiples"
+#define MSG_NO_INIT_LANG "Pas de langage initial"
+#define MSG_NO_JOIN_TO_EXP "Jointure vers une expression impossible"
+#define MSG_NO_JOIN_UPDEL "Pas de jointure avec Update/Delete"
+#define MSG_NO_KEY_COL "Pas de colonne clé trouvée"
+#define MSG_NO_KEY_UPDATE "Le nom des clés ne peut pas être modifié"
+#define MSG_NO_LANGUAGE "Pas de langage opérationnel\n"
+#define MSG_NO_LANG_TO_QUIT "Pas de langage à quitter"
+#define MSG_NO_LISTVAL_HERE "LSTBLK: Liste de valeurs utilisée hors contexte"
+#define MSG_NO_MAP_INSERT "MAP incompatible avec Insert"
+#define MSG_NO_MATCHING_COL "Pas de colonne correspondant à %s dans %s"
+#define MSG_NO_MATCH_COL "Colonne correspondante introuvable"
+#define MSG_NO_MEMORY "Mémoire pleine"
+#define MSG_NO_MEM_CORR_SUB "Subquery corrélée en mémoire non encore implémentée"
+#define MSG_NO_MODE_PADDED "Mode non supporté pour les fichiers 'padded'"
+#define MSG_NO_MORE_COL "La colonne %s n'est plus dans la table pivot"
+#define MSG_NO_MORE_LANG "Plus de langage, exit de %s\n"
+#define MSG_NO_MORE_VAR "Les fichiers VAR ne sont plus supportés"
+#define MSG_NO_MULCOL_JOIN "Jointure vers un index multi-colonne pas encore possible"
+#define MSG_NO_MULT_HAVING "Clauses Having multiples non implémentées"
+#define MSG_NO_MUL_DIR_ACC "Accès direct des tables multiples pas encore implémenté"
+#define MSG_NO_MUL_VCT "Les tables VCT ne peuvent pas être multiples"
+#define MSG_NO_MYSQL_CONN "Aucune connexion MySQL ouverte"
+#define MSG_NO_MYSQL_DELETE "Pas de Delete pour les tables MySQL"
+#define MSG_NO_NBCOL "Pas de NBcol"
+#define MSG_NO_NBLIN "Pas de NBlin, MaxSize ou Continued"
+#define MSG_NO_NBLIN_CONT "Fetch: Pas de NBlin ou Continued"
+#define MSG_NO_NULL_CONST "Les constantes <null> ne sont pas prises en charge"
+#define MSG_NO_ODBC_COL "Colonnes ODBC automatiques non supportées par cette version"
+#define MSG_NO_ODBC_DELETE "Delete ne devrait pas être appelé pour les tables ODBC"
+#define MSG_NO_ODBC_DIRECT "Accès directe des tables ODBC non encore implémenté"
+#define MSG_NO_ODBC_MUL "Multiple(2) non supporté pour les tables ODBC"
+#define MSG_NO_ODBC_SPECOL "Pas de colonne spéciale ODBC"
+#define MSG_NO_OPT_COLUMN "Pas optimisable ou pas de colonne optimisées"
+#define MSG_NO_OP_MODIF "Les modificateurs ne s'appliquent pas à %s"
+#define MSG_NO_PARAMETER "Pas de paramètre"
+#define MSG_NO_PART_DEL "Delete partiel des fichier %s impossible"
+#define MSG_NO_PART_MAP "Mapping partiel non implémenté pour cet OS"
+#define MSG_NO_PAR_BLK_INS "Insertion de bloc partiel impossible"
+#define MSG_NO_PIV_DIR_ACC "Pas d'accès directe aux tables PIVOT"
+#define MSG_NO_POS_ADDED "Pos_code non ajouté"
+#define MSG_NO_PROMPTING "Relance impossible pour les tables distribuées"
+#define MSG_NO_QRY_DELETE "Delete n'est pas utilisable pour les views QRY"
+#define MSG_NO_QUERY_ARRAY "Tableaux avec QUERY non encore implémentés"
+#define MSG_NO_RCUR_DSK_YET "Usage recursif de DISK non encore implementé"
+#define MSG_NO_READ_32 "Lecture de 32 octets impossible"
+#define MSG_NO_RECOV_SPACE "Espace non recouvrable dans le fichier index"
+#define MSG_NO_REF_DELETE "Pas de suppression en référence à une autre table"
+#define MSG_NO_REF_UPDATE "Pas de mise à jour en référence à une autre table"
+#define MSG_NO_REMOTE_FNC "Certaines fonctions ne peuvent pas être exécutées à distance"
+#define MSG_NO_ROWID_FOR_AM "Accès direct impossible de ROWID pour les tables de type %s"
+#define MSG_NO_ROW_NODE "Le nom du Rownode n'est pas défini"
+#define MSG_NO_SECTION_NAME "Nom de section manquant"
+#define MSG_NO_SEC_UPDATE "Les noms de section ne peuvent pas être modifiés"
+#define MSG_NO_SELECTED_DB "Aucune base de données sélectée"
+#define MSG_NO_SELF_PIVOT "Une table ne peut se pivoter elle-même !"
+#define MSG_NO_SERVER_FOUND "Serveur introuvable"
+#define MSG_NO_SETPOS_YET "SetPos pas encore implémenté pour les fichier %s"
+#define MSG_NO_SFEXIT_UNIX "Fonction %s non disponible sur Unix"
+#define MSG_NO_SOURCE " (pas de source)"
+#define MSG_NO_SPEC_COL "Pas de colonne spéciales MYSQL"
+#define MSG_NO_SQL_DELETE "Delete n'est pas utilisable actuellement pour les views SQL"
+#define MSG_NO_SUB_VAL "Pas de sous-value d'un tableau de type %d"
+#define MSG_NO_SUCH_INDEX "La table %s n'a pas l'index %s"
+#define MSG_NO_SUCH_SERVER "Serveur %s introuvable"
+#define MSG_NO_SUCH_TABLE "Table %s pas dans la base de données"
+#define MSG_NO_TABCOL_DATA "Pas de données pour la table %s colonne %s"
+#define MSG_NO_TABLE_COL "Aucune colonne trouvée pour %s"
+#define MSG_NO_TABLE_DEL "Delete non autorisé pour les tables %s "
+#define MSG_NO_TABLE_DESC "Pas de bloc descriptif de table"
+#define MSG_NO_TABLE_INDEX "La table %s n'a pas d'index"
+#define MSG_NO_TABLE_LIST "Pas de liste de tables"
+#define MSG_NO_TAB_DATA "Pas de données pour la table %s"
+#define MSG_NO_TERM_IN_TOK "Les non-terminaux ne sont pas utilisables dans les règles de Token"
+#define MSG_NO_TOKEN_DB "DB introuvable pour la colonne TOKEN %s"
+#define MSG_NO_UNIX_CATINFO "Pas d'info catalogue sous Unix"
+#define MSG_NO_UPDEL_JOIN "Pas de jointure de tables ODBC pour Update/Delete"
+#define MSG_NO_VCT_DELETE "Délétion Partielle non implémentée pour les fichiers VCT"
+#define MSG_NO_VIEW_COLDEF "Colonne définition impossible pour les views"
+#define MSG_NO_VIEW_SORT "La View fonctionnelle %s ne peut pas être triée ou jointe"
+#define MSG_NO_ZIP_DELETE "Delete sur fichier Zip non encore implementé"
+#define MSG_NO_ZIP_DIR_ACC "Accès directe des tables ZDOS non encore implementé"
+#define MSG_NULL_COL_VALUE "La colonne n'a pas de valeur"
+#define MSG_NULL_ENTRY "InitLang, entrée nulle %d %s"
+#define MSG_NULL_QUERY "Requête vide"
+#define MSG_NUMVAL_NOMATCH "Disparité de Numval pour %s"
+#define MSG_N_FULL_PARSES "%d significations"
+#define MSG_ODBC_READ_ONLY "ODBC est actuellement en lecture seulement"
+#define MSG_OFFSET_NOT_SUPP "Offset non supporté pour ce type de sous requête"
+#define MSG_ONE_LANG_YET "Un langage est déjà en édition"
+#define MSG_ONE_PARAM_ONLY "Un seul paramètre autorisé"
+#define MSG_ONLY_LOG10_IMPL "Seul Log10 est implementé"
+#define MSG_ON_LANGUAGE "Langage %.8s version %d niveau %d éditable"
+#define MSG_OPENING "Ouverture"
+#define MSG_OPENING_QUERY "Ouverture de la requête"
+#define MSG_OPEN_EMPTY_FILE "Ouverture du fichier vide %s: %s"
+#define MSG_OPEN_ERROR "Erreur d'ouverture %d en mode %d sur %s: "
+#define MSG_OPEN_ERROR_IS "Erreur à l'ouverture de %s: %s"
+#define MSG_OPEN_ERROR_ON "Erreur d'ouverture sur %s"
+#define MSG_OPEN_MODE_ERROR "Erreur d'ouverture(%s) %d sur %s"
+#define MSG_OPEN_SORT_ERROR "Erreur logique de tri dans QUERY Open"
+#define MSG_OPEN_STRERROR "Erreur à l'ouverture: %s"
+#define MSG_OPEN_W_ERROR "Erreur à l'ouverture de %s en écriture"
+#define MSG_OPTBLK_RD_ERR "Erreur à la lecture d'un bloc optimisation: %s"
+#define MSG_OPTBLK_WR_ERR "Erreur à l'écriture d'un bloc optimisation: %s"
+#define MSG_OPTIMIZING "Optimisation de "
+#define MSG_OPT_BMAP_RD_ERR "Erreur en lecture des bitmaps d'optimisation: %s"
+#define MSG_OPT_BMAP_WR_ERR "Erreur en écriture des bitmaps d'optimisation: %s"
+#define MSG_OPT_CANCELLED "Optimisation interrompue par l'utilisateur"
+#define MSG_OPT_DVAL_RD_ERR "Erreur en lecture des valeurs distinctes: %s"
+#define MSG_OPT_DVAL_WR_ERR "Erreur en écriture des valeurs distinctes: %s"
+#define MSG_OPT_HEAD_RD_ERR "Erreur en lecture de l'entête du fichier opt: %s"
+#define MSG_OPT_HEAD_WR_ERR "Erreur en écriture de l'entête du fichier opt: %s"
+#define MSG_OPT_INIT "Optimisation initialisée"
+#define MSG_OPT_LOGIC_ERR "Erreur logique dans SetBitmap, i=%d"
+#define MSG_OPT_MAX_RD_ERR "Erreur en lecture des valeurs maxi: %s"
+#define MSG_OPT_MAX_WR_ERR "Erreur en écriture des valeurs maxi: %s"
+#define MSG_OPT_MIN_RD_ERR "Erreur en lecture des valeurs mini: %s"
+#define MSG_OPT_MIN_WR_ERR "Erreur en écriture des valeurs mini: %s"
+#define MSG_OPT_NOT_MATCH "Le fichier opt %s n'est pas à jour"
+#define MSG_OP_RES_TOO_LONG "Résultat trop long pour l'opérateur=%d"
+#define MSG_ORDER_OUT_RANGE "Tri: Order %d hors limite"
+#define MSG_ORDER_TWICE "Un même élément est trié deux fois"
+#define MSG_PAGE_ERROR "Erreur de pagination"
+#define MSG_PARM_CNT_MISS "Disparité du nombre de Paramètres"
+#define MSG_PARSE_NULL_SEM "Sémantique nulle"
+#define MSG_PARSING_QUERY "Analyse de la requête"
+#define MSG_PIX_ERROR "Pix %s erreur règle no=%u\n"
+#define MSG_PIX_TEST_ERROR "Règle=%u: pix-TEST pas dans le premier noeud\n"
+#define MSG_PLG_READ_ONLY "PLG est actuellement en lecture seulement"
+#define MSG_PLM_NULL_SFP "TABPLM ReadDB: Sfp est NULL"
+#define MSG_PLUG_NOT_INIT "Plug n'est pas initialisé\n"
+#define MSG_PLUG_NOT_RUN "Plug n'est pas en marche"
+#define MSG_PNODE_RULE "(Noeud %d règle %d) "
+#define MSG_POS_TOO_LONG "%s trop long (>%d)"
+#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp est NULL"
+#define MSG_PRIV_INSTR "Instruction privilégiée"
+#define MSG_PROCADD_ERROR "Erreur %d sur l'adresse de %s"
+#define MSG_PROCESS_SUBQRY "Sub-Query en cours de traitement"
+#define MSG_PROC_WOULD_LOOP "Bouclage du traitement (maxres=%d maxlin=%d)"
+#define MSG_PROGRESS_INFO "Informations sur le traitement en cours"
+#define MSG_PROMPT_CANCEL "Relance annulée"
+#define MSG_PROMPT_NIY "Prompt non implémenté pour cette configuration"
+#define MSG_PTR_NOT_FOUND "Pointeur introuvable Num=%d ti1=%d"
+#define MSG_PXDEF_IS_NULL "Pxdef est NULL"
+#define MSG_QRY_READ_ONLY "Les views QRY sont en lecture seulement"
+#define MSG_QUERY_CANCELLED "Requête interrompue par l'utilisateur"
+#define MSG_QUERY_NOT_EXEC "Requête non exécutée"
+#define MSG_QUERY_SAVED "Requête %s sauvegardée"
+#define MSG_QUOTE_IN_QUOTE "Appostrophe dans un champ entre appostrophe ligne %d"
+#define MSG_RANGE_NIY "Range pas encore implémenté pour %s"
+#define MSG_RANGE_NO_JOIN "Range non compatible avec les index de jointure"
+#define MSG_RC_READING "rc=%d en lecture de la table %s"
+#define MSG_READB_BAD_INIT "%s ReadDB appelé avec Init=0"
+#define MSG_READCOL_ERROR "SQLCOL: erreur dans ReadColumn"
+#define MSG_READING "Lecture"
+#define MSG_READING_FROM "Lecture de %s"
+#define MSG_READING_RECORD "Erreur en lecture de l'enregistrement %d de %s"
+#define MSG_READY "Prêt"
+#define MSG_READ_ERROR "Erreur en lecture sur %s: %s"
+#define MSG_READ_ERROR_RC "Erreur en lecture, rc=%d"
+#define MSG_READ_MEM_ERROR "Lecture mémoire %d: taille=%d"
+#define MSG_READ_ONLY "Cette table protégée en lecture seule ne peut être modifiée"
+#define MSG_READ_SEEK_ERROR "Erreur de recherche en lecture: %s"
+#define MSG_READ_SEG_ERROR "Lecture segment %d: taille=%d"
+#define MSG_RECEIVED "Reçu %c\n"
+#define MSG_RECORD_ERROR "Erreur à la lecture de l'enregistrement %d de %s"
+#define MSG_RECORD_NO_SEP "Enregistrement sans séparateur"
+#define MSG_REC_SKIPPED " (%d lignes erronnées sautées par l'option MaxErr)"
+#define MSG_REDUCE_INDEX "Réduction de l'index"
+#define MSG_REGISTER_ERR "Enregistrement NS impossible, préfix='%s' et href='%s'"
+#define MSG_REMOTE_CONN_ERR "La connection éloignée a échoué"
+#define MSG_REMOVE_ERROR "Erreur en supprimant %s: %s"
+#define MSG_REMOVE_NOT_IMPL "Remove non implémenté pour TDB non Table"
+#define MSG_RENAME_ERROR "Erreur renommant %s en %s: %s"
+#define MSG_RENUM_RULES "Renumérotez les règles et réentrez ADD (règle sauvegardée dans la zone tampon)"
+#define MSG_REORDER_INDEX "Reclassement de l'index"
+#define MSG_REQU_ARG_NUM "La fonction %s doit avoir %d arguments"
+#define MSG_RESET_TO "%s remis à %d"
+#define MSG_RES_NOT_UNIQUE "Le résultat n'est pas unique"
+#define MSG_RET_FROM_LANG "Retour au language %s version %d.%d du language %s version %d.%d"
+#define MSG_ROWID_NOT_IMPL "RowNumber non implémenté pour les tables de type %s"
+#define MSG_ROWS_SELECTED "%d lignes sélectionnées en %.2lf sec"
+#define MSG_ROWS_TRUNCATED " (tronqué par MAXRES, LIMIT, FREQ ou AreaSize)"
+#define MSG_ROW_ARGNB_ERR "ROW: disparité du nombre d'arguments (%d,%d)"
+#define MSG_RPC_SERVER_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_RSC_ALLOC_ERROR "Erreur d'allocation mémoire dans Rescol %s"
+#define MSG_RULE_ENTERED "Règle %d entrée"
+#define MSG_RULE_SUBSET_ERR "Erreur d'initialisation de la zone Règles"
+#define MSG_SAVING_INDEX "Sauvegarde du fichier index"
+#define MSG_SCAN_NOT_IMP "Scan non implémenté"
+#define MSG_SEC_KEY_FIRST "Les sections et clés doivent être insérées en premier"
+#define MSG_SEC_NAME_FIRST "Le nom de section doit être en tête de liste en insertion"
+#define MSG_SEC_NOT_FOUND "Section %s absente de %s"
+#define MSG_SEEK_ERROR "Seek erreur dans CopyHeader"
+#define MSG_SEMANTIC_TREE "Arbre sémantique"
+#define MSG_SEM_BAD_REF "Sem @%d référence un argument de type non 0 ou 1"
+#define MSG_SEM_UNKNOWN "inconnue, rc=%d"
+#define MSG_SEP_IN_FIELD "Le champ %d contient le caractère séparateur"
+#define MSG_SEQUENCE_ERROR "HSTMT: Allocation hors séquence"
+#define MSG_SETEOF_ERROR "Erreur %d dans SetEndOfFile"
+#define MSG_SETRECPOS_NIY "SetRecpos non implémenté pour ce type de table"
+#define MSG_SET_LOCALE "Locale fixée à %s"
+#define MSG_SET_NULL_DOM "Valeur %d donnée à un domaine nul"
+#define MSG_SET_OP_NOT_IMPL "Opérateurs ensemblistes non implementés"
+#define MSG_SET_STR_TRUNC "SetValue: Chaîne de caractères tronquée"
+#define MSG_SEVERAL_TREES "Jointure non spécifiée pour certaines tables"
+#define MSG_SFP_ERROR "Erreur sur SetFilePointer: %s"
+#define MSG_SFUNC_NOT_IMPL "Fonction scalaire %s non implémentée"
+#define MSG_SHARED_LIB_ERR "Erreur au chargement de la librairie partagée %s: %s"
+#define MSG_SINGLE_STEP "Pas à pas"
+#define MSG_SLEEP "J'ai dormi %d milliseconds"
+#define MSG_SMART_SORTING "Récupération des lignes triées (passage %d de %d)"
+#define MSG_SMART_SORT_ERR "Erreur logique 1 dans Smart Sort"
+#define MSG_SORTING "Tri en cours"
+#define MSG_SORTING_INDEX "Tri de l'index"
+#define MSG_SORTING_VAL "Tri de %d valeurs"
+#define MSG_SORT_JOIN_INDEX "Tri de l'index de jointure"
+#define MSG_SPCOL_READONLY "La colonne spéciale %s est en lecture seulement"
+#define MSG_SPEC_CMD_SEP "Les commandes spéciales doivent être exécutées séparément"
+#define MSG_SQL_BAD_TYPE "RephraseSQL: type %d non supporté"
+#define MSG_SQL_BLOCK_MISM "CheckColumn: bloc SQL courant non correspondant"
+#define MSG_SQL_CONF_ERROR "Erreur SQL: SQL_CONFORMANCE"
+#define MSG_SQL_READ_ONLY "Les views SQL sont actuellement en lecture seulement"
+#define MSG_SRCH_CLOSE_ERR "Erreur à la fermeture de l'Handle de recherche"
+#define MSG_SRC_TABLE_UNDEF "La table source n'est pas définie"
+#define MSG_STACK_ERROR "Erreur sur la pile, i=%d\n"
+#define MSG_STACK_OVERFLOW "Parser: Débordement de la pile\n"
+#define MSG_STRG_NOT_FOUND "Chaîne introuvable"
+#define MSG_STRING_INV_LIST "Liste invalide pour SemString"
+#define MSG_STRING_TOO_BIG "Chaîne trop grande pour le domaine %s"
+#define MSG_SUBALLOC_ERROR "Pas assez de mémoire en zone %p pour allouer %d (utilisé=%d libre=%d)"
+#define MSG_SUBAL_HUGE_ERR "Pas assez de mémoire en zone huge %p pour allouer %d"
+#define MSG_SUBARG_NOSEM "Argument @ ou sous-phrase de niveau %d pointe sur un noeud sans Sem"
+#define MSG_SUBARG_OUTRANGE "Argument @ ou sous-phrase de niveau %d hors limite"
+#define MSG_SUBQRY_ONEITEM "Une Sub-Query ne doit avoir qu'une sélection"
+#define MSG_SUBSET_ERROR "SubSet erreur dans LoadDB"
+#define MSG_SUB_OPEN_YET "Subquery déjà ouverte"
+#define MSG_SUB_RES_TOO_LNG "Résultat trop long pour SUBSTR"
+#define MSG_SYNTAX_ERROR "Erreur de syntaxe"
+#define MSG_SYSTEM_ERROR "Erreur système %d"
+#define MSG_S_ACCESS_DENIED "%s: accès non autorisé"
+#define MSG_S_ERROR "%s erreur"
+#define MSG_S_ERROR_NUM "%s: erreur=%d"
+#define MSG_S_INTRUPT_ERROR "%s: erreur interruption"
+#define MSG_S_INVALID_PARM "%s: paramètre invalide"
+#define MSG_S_INV_ADDRESS "%s: adresse invalide"
+#define MSG_S_UNKNOWN_ERROR "%s: erreur de code %u inconnu"
+#define MSG_TABDIR_READONLY "Les tables DIR sont en lecture seulement"
+#define MSG_TABLE_ALREADY "La table %s existe déjà"
+#define MSG_TABLE_ALTERED "Table %s %s altérée"
+#define MSG_TABLE_CREATED "%s table %s créée"
+#define MSG_TABLE_DROPPED "Table %s supprimée"
+#define MSG_TABLE_MULT_JOIN "Utilisation multiple de la table %s pour jointure"
+#define MSG_TABLE_NOT_IN_DB "La table %s n'existe pas dans %s"
+#define MSG_TABLE_NOT_OPT "Table non optimisable"
+#define MSG_TABLE_NO_INDEX "La table %s n'est pas indexable"
+#define MSG_TABLE_NO_OPT "La table %s n'existe pas ou de type non optimisable"
+#define MSG_TABLE_READ_ONLY "Les tables %s sont en lecture seulement "
+#define MSG_TABMUL_READONLY "Les tables multiples sont en lecture seulement"
+#define MSG_TAB_NOT_LOADED " (certaines tables n'ont put être chargées)"
+#define MSG_TAB_NOT_SPEC "Table non specifiée"
+#define MSG_TB_VW_NOTIN_DB "Table ou view %s pas dans la base de données"
+#define MSG_TDB_NXT_NOT_NUL "Tdb.Next non NULL"
+#define MSG_TDB_USE_ERROR "Erreur, Tdbp->Use=%d"
+#define MSG_TOO_MANY_COLS "Trop de colonnes"
+#define MSG_TOO_MANY_COLTAB "Trop de colonnes dans %s (%d)"
+#define MSG_TOO_MANY_FIELDS "Trop de champs ligne %d de %s"
+#define MSG_TOO_MANY_JUMPS "Trop de niveaux de saut"
+#define MSG_TOO_MANY_KEYS "Trop de clés (%d)"
+#define MSG_TOO_MANY_POS "Trop de pos_codes"
+#define MSG_TOO_MANY_TABLES "Trop de tables (%d)"
+#define MSG_TOPSEM_ERROR "Erreur inconnue dans TopSem"
+#define MSG_TO_BLK_IS_NULL "To Blk est nul"
+#define MSG_TO_FTR_NOT_NULL "Set.To_Ftr n'est pas nul"
+#define MSG_TO_PIX_NOT_NULL "Set.To_Pix n'est pas nul"
+#define MSG_TO_SEM_NOT_NULL "Set.To_Sem n'est pas nul"
+#define MSG_TRUNCATE_ERROR "Erreur en troncation: %s"
+#define MSG_TRUNC_BY_ESTIM "Tronqué par l'option Estimate"
+#define MSG_TYPES_ERROR "Erreur sur Types(%d)"
+#define MSG_TYPE_CONV_ERROR "Type non convertible dans une expression"
+#define MSG_TYPE_DEF_MISM "Disparité entre type et définition"
+#define MSG_TYPE_MISMATCH "Clé et source ne sont pas du même type"
+#define MSG_TYPE_RECFM_MISM "Disparité entre Type et Recfm"
+#define MSG_TYPE_TO_VERIFY "Type à vérifier: %d"
+#define MSG_TYPE_VALUE_ERR "Colonne %s: disparité type(%s)/valeur(%s)"
+#define MSG_UNBALANCE_QUOTE "Appostrophe en trop ligne %d"
+#define MSG_UNDEFINED_AM "COLBLK %s: méthode d'accès indéfinie"
+#define MSG_UNDEFINED_PATH "Chemin d'accès indéfini pour Plgcnx.ini"
+#define MSG_UNDEF_COL_COUNT "Count sur colonne non définie"
+#define MSG_UNKNOWN_DOMAIN "Domaine inconnu %s"
+#define MSG_UNKNOWN_ERROR "Erreur inconnue"
+#define MSG_UNKNOWN_EXCPT "Exception non répertoriée"
+#define MSG_UNKNOWN_NAME "Nom inconnu: %.8s"
+#define MSG_UNKNOWN_PATH "Chemin d'accès inconnu pour Plgcnx.ini"
+#define MSG_UNKNOWN_POS "Nom pos_code inconnu: %s"
+#define MSG_UNKNOWN_SEM "Sem %.8s inconnue, rc=%d"
+#define MSG_UNKNOWN_SYNONYM "Synonyme inconnu"
+#define MSG_UNKNW_QRY_TYPE "ReadDB: type de requête inconnu"
+#define MSG_UNKN_ERR_CODE "Erreur de code %d inconnu"
+#define MSG_UNLOADABLE " inchargeable: "
+#define MSG_UNLOADABLE_PRM "%s inchargeable: %s"
+#define MSG_UNMATCH_FIL_ARG "Argument de filtre dépareillé"
+#define MSG_UNQ_COL_SEV_TAB "La colonne %s non qualifiée est dans plusieurs tables"
+#define MSG_UNRESOLVED_ARG "?Argument manquant: %s non résolu en %d ligne %d"
+#define MSG_UPDATE_ERROR "Erreur en Update sur %s"
+#define MSG_UPDATING_ROWS "Mise à jour des lignes"
+#define MSG_UPD_ZIP_NOT_IMP "Mise à jour des tables ZDOS non encore implementé"
+#define MSG_UP_LANGUAGE "Bloc langage %.8s version %d niveau %d chargé"
+#define MSG_USED_FREE_MEM "Sarea: utilisé %d, libre %d"
+#define MSG_USETEMP_IS "Usetemp est : %s"
+#define MSG_USETEMP_RESET ". Usetemp remis à Auto"
+#define MSG_USETEMP_SET "Usetemp fixé à %s"
+#define MSG_USE_NO_MATCH "Use non correspondant : Use=%d, ti2=%d, ti3=%d"
+#define MSG_USING_INDEX " (Indexé par"
+#define MSG_VALIST_MISMATCH "Disparité des listes de valeurs"
+#define MSG_VALSTR_TOO_LONG "Valeur %s trop longue pour une chaîne de longueur %d"
+#define MSG_VALTYPE_NOMATCH "Disparité types de valeur"
+#define MSG_VALUE_ERROR "Colonne %s: bloc valeur nul"
+#define MSG_VALUE_NOT_ALLOC "Valeur non allouée pour la colonne R%d %s"
+#define MSG_VALUE_TOO_BIG "Valeur %lld trop grande pour la colonne %s"
+#define MSG_VALUE_TOO_LONG "Valeur %s trop longue pour la colonne %s de longueur %d"
+#define MSG_VAL_ALLOC_ERR "Allocation impossible du noeud valeur"
+#define MSG_VAL_TOO_LONG "Valeur %s trop longue pour le champ %s"
+#define MSG_VIEW_ALREADY "La VIEW %s existe déjà"
+#define MSG_VIEW_CREATED "%s view %s créée"
+#define MSG_VIEW_DROPPED "View %s supprimée"
+#define MSG_VIEW_NOT_IN_DB "%s n'est pas une View de %s"
+#define MSG_VIR_NO_DELETE "Delete impossible sur les tables %s"
+#define MSG_VIR_READ_ONLY "Les tables virtuelles %s sont en lecture seulement"
+#define MSG_VM_LANG "Langage au format VM, non supporté"
+#define MSG_VOID_FIRST_ARG "Le premier argument ne doit pas être vide"
+#define MSG_VOID_IN_STRING "Erreur: chaîne IN vide"
+#define MSG_VOID_ORDER_LIST "Liste de tri vide, erreur système ?"
+#define MSG_VOID_POS_DICT "Dictionnaire interne du langage vide"
+#define MSG_VOID_QUERY "Requête vide %s"
+#define MSG_WORK_AREA "Espace de travail: %s"
+#define MSG_WORK_TOO_SMALL "Zone de travail trop petite, accroître AreaSize"
+#define MSG_WRITE_ERROR "Erreur à l'écriture de %s"
+#define MSG_WRITE_SEEK_ERR "Erreur de recherche en écriture: %s"
+#define MSG_WRITE_STRERROR "Erreur en écriture sur %s: %s"
+#define MSG_WRITING "Ecriture"
+#define MSG_WRITING_ERROR "Erreur à l'écriture de %s: %s"
+#define MSG_WRITING_QUERY "Erreur à l'écriture de la requête: "
+#define MSG_WRONG_ARG_NUM "La fonction %s ne prend pas %d arguments"
+#define MSG_WRONG_COL_NUM "Numéro de colonne %d trop grand pour %s"
+#define MSG_WRONG_DB_LIST "Liste des bases de données incorrecte ou vide"
+#define MSG_WRONG_FUNCTION "Mauvaise fonction %d"
+#define MSG_WRONG_OP_PARM "Mauvais opérateur ou paramètres pour %s"
+#define MSG_WRONG_PARMS "Mauvais paramètres pour %s"
+#define MSG_WRONG_PASSWORD "Mot de passe illégal pour %s"
+#define MSG_WRONG_TYPE "type non supporté"
+#define MSG_WRONG_USERFILE "La Userfile a une mauvaise taille %d"
+#define MSG_WS_CONV_ERR "Erreur de convertion de %s en WS"
+#define MSG_XCOL_MISMATCH "La colonne %s ne correspond pas à l'index"
+#define MSG_XDB_DEL_ERROR "Erreur en supprimant des entrées du fichier XDB"
+#define MSG_XFILE_READERR "Erreur %d en lisant le fichier index"
+#define MSG_XFILE_TOO_SMALL "Le fichier index est plus petit que la taille de l'index"
+#define MSG_XFILE_WRITERR "Erreur en écrivant le fichier index: %s"
+#define MSG_XMLTAB_INIT_ERR "Erreur d'initialisation de la table XML"
+#define MSG_XML_INIT_ERROR "Erreur d'initialisation du nouveau fichier XML"
+#define MSG_XPATH_CNTX_ERR "Le nouveau contexte XPath ne peut être créé"
+#define MSG_XPATH_EVAL_ERR "Impossible d'évaluer l'emplacement xpath '%s'"
+#define MSG_XPATH_NOT_SUPP "Xpath non supporté colonne %s"
+#define MSG_X_ARG_ADDED "%d arguments ajoutés"
+#define MSG_X_ARG_SET "%d arguments ont été initialisés"
+#define MSG_X_ON_TAB " %s sur %s("
+#define MSG_ZERO_DIVIDE "Division par zéro dans une expression"
diff --git a/storage/connect/frmsg2.h b/storage/connect/frmsg2.h
new file mode 100644
index 00000000..487db339
--- /dev/null
+++ b/storage/connect/frmsg2.h
@@ -0,0 +1,1013 @@
+#define MSG_ACCESS_VIOLATN "Violation accŠs m‚moire"
+#define MSG_ACT_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Activity"
+#define MSG_ADDVAL_ERROR "Erreur %d dans AddValue"
+#define MSG_ADD_BAD_TYPE "Ajout d'une valeur de type %s non conforme dans un tableau %s"
+#define MSG_ADD_NULL_DOM "Ajout de la chaŒne %s … un domaine nul"
+#define MSG_ADPOS_IN_DICTP "ADPOS au travail dans User_Dictp"
+#define MSG_AFTER " aprŠs: "
+#define MSG_ALG_CHOICE_AUTO "Le choix du meilleur algorithme est automatique"
+#define MSG_ALG_CHOICE_BAD "Choix d'algorithme invalide, remis … AUTO"
+#define MSG_ALG_CHOICE_QRY "Utilise l'algorithme 'Query'"
+#define MSG_ALG_CURLY_BRK "Le choix de l'algorithme d‚pend des accolades externes"
+#define MSG_ALLOC_ERROR "Erreur d'allocation de %s"
+#define MSG_ALL_DELETED "Toutes les lignes enlev‚es en %.2lf sec"
+#define MSG_ALTER_DB_ERR "Impossible de d‚terminer la base de donn‚es … modifier"
+#define MSG_AMBIG_COL_QUAL "Qualificateur ambigu %s pour la colonne %s"
+#define MSG_AMBIG_CORREL "Select %s.* corr‚lation ambigue"
+#define MSG_AMBIG_SPEC_COL "Colonne sp‚ciale ambigue %s"
+#define MSG_ANSWER_TYPE "R‚ponse de type"
+#define MSG_API_CONF_ERROR "Erreur SQL: API_CONFORMANCE"
+#define MSG_APPL_ACCESSIBLE "Application %s accessible"
+#define MSG_APPL_ACTIVE "Application %s encore active"
+#define MSG_APPL_BAD_SAVE "Application %s partiellement sauvegard‚e"
+#define MSG_APPL_CREATED "Application %s cr‚‚"
+#define MSG_APPL_IS_ACTIVE "Application d‚j… active"
+#define MSG_APPL_NOT_INIT "Application non initialis‚e"
+#define MSG_APPL_NOT_LOADED "Application non charg‚e"
+#define MSG_APPL_QUIT "Fin de l'application %s"
+#define MSG_APPL_SAVED "Application %s sauvegard‚e"
+#define MSG_APP_STILL_ACTIV "Application du langage %s encore active (non lib‚rable)"
+#define MSG_AREAFILE_NOTFND "Fichier Area introuvable"
+#define MSG_ARGS_SYNTAX_ERR "?SetArgs erreur de syntaxe: %s inattendu aprŠs %s"
+#define MSG_ARG_ALREADY_SET "Argument %d d‚j… allou‚"
+#define MSG_ARG_NOT_AN_ATTR "L'argument n'est pas un attribut (type %d erron‚)"
+#define MSG_ARG_OUT_CONTEXT "Argument de type @ utilis‚ hors contexte"
+#define MSG_ARG_OUT_RANGE "Argument de phrase valant %d hors limite"
+#define MSG_ARG_PTR_NOSEM "Argument valant %d pointe sur un noeud sans Sem"
+#define MSG_ARG_PTR_NOSEMS "Argument valant %d pointe sur un noeud sans s‚mantique"
+#define MSG_ARG_REF_LOOP "?Bouclage entre r‚f‚rences crois‚es des arguments"
+#define MSG_ARG_TWO_CONST "Le 2Šme argument de %s doit ˆtre constant"
+#define MSG_ARRAY_ALLOC_ERR "Erreur d'allocation m‚moire dans ARRAY"
+#define MSG_ARRAY_BNDS_EXCD "Hors limite de tableau"
+#define MSG_ARRAY_ERROR "Erreur de fonctionnement k=%d n=%d"
+#define MSG_ATTRIBUTE_ERROR "Erreur rŠgle %u attribut %s: "
+#define MSG_ATT_NOT_CASE "Mauvaise valeur %d pour attribut (pas une CaseValue)"
+#define MSG_ATT_POSCODE_BIG "Code attribut %d trop grand (max=%d)"
+#define MSG_AVGLEN_ERROR "avglen doit ˆtre entre %d et %d"
+#define MSG_BAD_AGGREG_FUNC "Fonction aggr‚g‚e %d non support‚e"
+#define MSG_BAD_ARGTYPES "Argument de type invalide pour %s"
+#define MSG_BAD_ARGUMENTS "Argument non attach‚s pour %s"
+#define MSG_BAD_ARG_NUM "Nombre d'arguments invalide %d"
+#define MSG_BAD_ARG_TYPE "Type d'argument %d invalide"
+#define MSG_BAD_ARRAY_OPER "Les tableaux doivent utiliser l'op‚rateur IN"
+#define MSG_BAD_ARRAY_TYPE "Type=%d invalide pour un tableau"
+#define MSG_BAD_ARRAY_VAL "Les tableaux doivent avoir le mˆme nombre de valeurs"
+#define MSG_BAD_BIN_FMT "Format invalide %c pour la colonne BIN %s"
+#define MSG_BAD_BLK_ESTIM "Nombre de blocs sup‚rieur … l'estimation"
+#define MSG_BAD_BLK_SIZE "Taille du bloc %d non conforme"
+#define MSG_BAD_BYTE_NUM "Le nombre d'octets ‚crits est faux"
+#define MSG_BAD_BYTE_READ "Le nombre d'octets lus est faux"
+#define MSG_BAD_CARDINALITY "Appel invalide de Cardinality pour une table multiple"
+#define MSG_BAD_CASE_SPEC "Min/Maj: sp‚cification %c incorrecte, recommencez: "
+#define MSG_BAD_CHAR_SPEC "Sp‚cification '%s' invalide pour caractŠre"
+#define MSG_BAD_CHECK_TYPE "Sous-type %d invalide pour CheckColumn"
+#define MSG_BAD_CHECK_VAL "Valeur pour Check invalide '%s'"
+#define MSG_BAD_COLCRT_ARG "COLCRT: Arg invalide (type=%hd, domain=%hd)"
+#define MSG_BAD_COLDEF_TYPE "Coldefs: type ill‚gal %d"
+#define MSG_BAD_COLIST_ITEM "El‚ment invalide dans une Colist"
+#define MSG_BAD_COLIST_TYPE "Mauvais type=%d pour une Colist"
+#define MSG_BAD_COLSIZE "Colsize %d trop petit pour cette base de donn‚es"
+#define MSG_BAD_COL_ENTRY "Entr‚e invalide pour la colonne %s"
+#define MSG_BAD_COL_FORMAT "Type de formattage %d invalide pour une colonne"
+#define MSG_BAD_COL_IN_FILT "Colonne incorrecte dans un filtre"
+#define MSG_BAD_COL_QUALIF "Qualificateur invalide %s pour la colonne %s"
+#define MSG_BAD_COL_TYPE "Type invalide %s pour la colonne %s"
+#define MSG_BAD_COL_XPATH "Xpath invalide colonne %s de la table HTML %s"
+#define MSG_BAD_COMPARE_OP "Op‚rateur de comparaison %d invalide"
+#define MSG_BAD_CONST_TYPE "Type=%d invalide pour une constante"
+#define MSG_BAD_CONV_TYPE "Convertion de type invalide %d"
+#define MSG_BAD_CORREL "Select %s.* corr‚lation absente"
+#define MSG_BAD_DATETIME "Valeur date/temps invalide"
+#define MSG_BAD_DATE_OPER "Op‚rateur de date inattendu %d"
+#define MSG_BAD_DBF_FILE "Le fichier DBF %s est alt‚r‚"
+#define MSG_BAD_DBF_REC "Fichier DBF %s alt‚r‚ enregistrement %d"
+#define MSG_BAD_DBF_TYPE "Type DBF %c non support‚"
+#define MSG_BAD_DEF_ARG "Argument invalide pour INDEXDEF (type=%hd, domain=%hd)"
+#define MSG_BAD_DEF_READ "EOF inattendue en lecture diff‚r‚e"
+#define MSG_BAD_DEF_TYPE "Type de colonne invalide"
+#define MSG_BAD_DIRECTORY "R‚pertoire invalide %s: %s"
+#define MSG_BAD_DIST_JN_FIL "Filtre de jointure distincte invalide"
+#define MSG_BAD_DIST_JOIN "Sp‚cification invalide de jointure distincte"
+#define MSG_BAD_DOM_COL_DEF "D‚finition de colonnes invalide pour un domaine"
+#define MSG_BAD_DOM_VALUE "La valeur %d n'appartient pas au domaine"
+#define MSG_BAD_EDIT_INIT "Coparm: ‚dition %s initialis‚e improprement"
+#define MSG_BAD_EVAL_TYPE "Fonction scalaire de type=%d invalide"
+#define MSG_BAD_EXEC_MODE "Mode d'ex‚cution invalide '%s'"
+#define MSG_BAD_EXP_ARGTYPE "Argument de type %d invalide pour une expression"
+#define MSG_BAD_EXP_OPER "Op‚rateur=%d invalide pour expression"
+#define MSG_BAD_FETCH_RC "Code retour inattendu de Fetch %d"
+#define MSG_BAD_FIELD_FMT "Format de champ invalide %c pour %s"
+#define MSG_BAD_FIELD_RANK "Rang %d invalide pour la colonne %s"
+#define MSG_BAD_FIELD_TYPE "Mauvais type de champ %s"
+#define MSG_BAD_FILE_HANDLE "Handle de fichier invalide: %s"
+#define MSG_BAD_FILE_LIST "La section liste de fichiers est erron‚e"
+#define MSG_BAD_FILTER "Mauvais filtre: Opc=%d B_T=%d %d Type=%d %d"
+#define MSG_BAD_FILTER_CONV "Conversion filtre incorrecte, B_T=%d,%d"
+#define MSG_BAD_FILTER_LINK "Op‚rateur de chaŒnage ill‚gal %d"
+#define MSG_BAD_FILTER_OP "Op‚rateur de filtre invalide %d"
+#define MSG_BAD_FILTEST_OP "Op‚rateur invalide %d %d pour FilTest"
+#define MSG_BAD_FLD_FORMAT "Format invalide pour le champs %d de %s"
+#define MSG_BAD_FLD_LENGTH "Champs %s trop long (%s --> %d) ligne %d de %s"
+#define MSG_BAD_FLOAT_CONV "Convertion invalide d'un tableau flottant"
+#define MSG_BAD_FPARM_NEXT "Coparm: FPARM avec Next non nul"
+#define MSG_BAD_FREQ_SET "Sp‚cification erronn‚e de Freq pour la colonne %s"
+#define MSG_BAD_FUNC_ARG "Funcarg de type %d non impl‚ment‚"
+#define MSG_BAD_FUNC_ARGTYP "Mauvais type d'argument=%d pour une fonction"
+#define MSG_BAD_FUNC_MODE "%s: mode invalide %d"
+#define MSG_BAD_GENRE "Genre est invalide"
+#define MSG_BAD_GETVIEW_RET "GetView: type de retour %d invalide"
+#define MSG_BAD_HANDLE_VAL "Valeur Handle invalide"
+#define MSG_BAD_HAV_FILTER "Filtre Having sur une requˆte non group‚e"
+#define MSG_BAD_HAV_FILTYPE "Filtre invalide pour clause Having"
+#define MSG_BAD_HEADER "Fichier %s: bloc en-tˆte alt‚r‚"
+#define MSG_BAD_HEADER_VAL "Valeur invalide pour Header"
+#define MSG_BAD_HEAD_END "Lecture fin d'en-tˆte impossible"
+#define MSG_BAD_INDEX_COL "Colonne %s invalide pour index %s"
+#define MSG_BAD_INDEX_DEF "D‚finition invalide pour index %s"
+#define MSG_BAD_INDEX_FILE "Fichier index %s corrompu"
+#define MSG_BAD_INDEX_PART "D‚finition colonne invalide pour index %s"
+#define MSG_BAD_INPUT "Entr‚e incorrecte"
+#define MSG_BAD_IN_ARGTYPE "Argument de type invalide pour l'op‚rateur IN"
+#define MSG_BAD_IN_ENDING "Erreur: fin de chaŒne IN invalide"
+#define MSG_BAD_IN_STRING "La chaŒne IN commence ou finie par des caractŠres invalides %c ... %c"
+#define MSG_BAD_JCOL_TYPE "Erreur logique JCT: disparit‚ des types colonnes"
+#define MSG_BAD_JOIN_EXP "Expression invalide pour une jointure"
+#define MSG_BAD_JOIN_FILTER "Filtre de jointure invalide"
+#define MSG_BAD_JOIN_OP "Op‚rateur de joint invalide %d"
+#define MSG_BAD_LANG_SIZE "Le fichier langage a une mauvaise taille %d"
+#define MSG_BAD_LINEFLD_FMT "Format invalide ligne %d champs %d de %s"
+#define MSG_BAD_LINE_LEN "Longueur ligne non ‚gale … Lrecl"
+#define MSG_BAD_LIST_TYPE "Type de liste invalide %d"
+#define MSG_BAD_LOCALE "Locale invalide %s"
+#define MSG_BAD_LOCDFON_ARG "Mauvais paramŠtre pour LOCDFON"
+#define MSG_BAD_LOCNODE_USE "Usage inattendu de LOCNODE"
+#define MSG_BAD_LRECL "Disparit‚ lrecl table/fichier (%d,%hd)"
+#define MSG_BAD_MAX_HAVING "MAXTMP trop petit pour Having"
+#define MSG_BAD_MAX_NREC "MaxRec=%d ne correspond pas … MaxBlk=%d Nrec=%d"
+#define MSG_BAD_MAX_PARAM "Mauvais paramŠtres pour sp‚cifier une valeur maximum"
+#define MSG_BAD_MAX_SETTING "Mauvaise valeur '%c' pour max"
+#define MSG_BAD_MERGE_TYPE "Le type %d ne pas ˆtre intercall‚"
+#define MSG_BAD_NODE_TYPE "Type noeud erron‚ pour la table"
+#define MSG_BAD_OFFSET_VAL "Nul offset invalide pour une table CSV"
+#define MSG_BAD_OPEN_MODE "Mode d'ouverture invalide %d"
+#define MSG_BAD_OPERATOR "Op‚rateur invalide %s"
+#define MSG_BAD_ORDER_MODE "Mode de tri %c invalide"
+#define MSG_BAD_ORDER_TYPE "Tri sur objet de type=%d invalide"
+#define MSG_BAD_OUTER_JOIN "Jointure externe invalide sur table enfant"
+#define MSG_BAD_PAD_ARGTYP "Argument de type invalide pour Pad ou Justify"
+#define MSG_BAD_PARAMETERS "%.8s: Mauvais paramŠtres"
+#define MSG_BAD_PARAM_TYPE "%.8s: ParamŠtre de type=%d invalide"
+#define MSG_BAD_PARM_COUNT "Nombre de paramŠtres incoh‚rent"
+#define MSG_BAD_PHASE_NUM "Num‚ro de phrase %d hors limite"
+#define MSG_BAD_PHRASE_NB "num‚ro de phrase hors limite %d rc=%d\n"
+#define MSG_BAD_POS_CODE "POS_code invalide %d"
+#define MSG_BAD_POS_TYPE "Type de POS_code invalide %d"
+#define MSG_BAD_PROJNUM "Mauvais projnum %d pour la colonne %s"
+#define MSG_BAD_QUERY_OPEN "Mode invalide %d pour l'ouverture d'une requˆte"
+#define MSG_BAD_QUERY_TYPE "Type de requˆte %d invalide pour %s"
+#define MSG_BAD_QUOTE_FIELD "Quote manquante dans %s champs %d ligne %d"
+#define MSG_BAD_READ_NUMBER "Mauvais nombre %d de valeurs lues dans %s"
+#define MSG_BAD_RECFM "Recfm type %d invalide pour DOSCOL"
+#define MSG_BAD_RECFM_VAL "Valeur invalide %d de Recfm"
+#define MSG_BAD_RESULT_TYPE "Mauvais type de r‚sultat %d pour %s"
+#define MSG_BAD_RETURN_TYPE "Type de retour %d incorrect"
+#define MSG_BAD_ROW_VALIST "Liste de valeurs invalide pour ROW"
+#define MSG_BAD_ROW_VALNB "Nombre de valeurs in‚gal dans la liste"
+#define MSG_BAD_SCF_ARGTYPE "Argument %d de type=%s invalide pour %s"
+#define MSG_BAD_SEM_DOMAIN "Domain .%d invalide"
+#define MSG_BAD_SETTINGS "Certaines sp‚cifications sont incompatibles avec le type de la table"
+#define MSG_BAD_SET_CASE "La casse d'un tableau ne peut pas passer de non respect … respecter"
+#define MSG_BAD_SET_STRING "SetValue: appel invalide pour STRING"
+#define MSG_BAD_SET_TYPE "Set type %hd invalide"
+#define MSG_BAD_SPECIAL_CMD "Commande sp‚ciale invalide"
+#define MSG_BAD_SPECIAL_COL "Colonne sp‚ciale invalide %s"
+#define MSG_BAD_SPEC_COLUMN "Colonne sp‚ciale invalide pour ce type de table"
+#define MSG_BAD_SQL_PARAM "ParamŠtre SQL invalide pour FindColblk"
+#define MSG_BAD_SUBLST_TYPE "Coparm: type %d de sous-liste invalide"
+#define MSG_BAD_SUBSEL_IN_X "Sub-select invalide pour une expression"
+#define MSG_BAD_SUBSEL_TYPE "Type %d invalide retourn‚ de Sub-Select"
+#define MSG_BAD_SUB_RESULT "R‚sultat ind‚fini de fonction Sub-Select"
+#define MSG_BAD_SUB_SELECT "Sub-select invalide comme argument de fonction"
+#define MSG_BAD_TABLE_LINE "Ligne '%s' ill‚gale ou tronqu‚e dans la section Tables"
+#define MSG_BAD_TABLE_LIST "Table %s absente de la liste des tables"
+#define MSG_BAD_TABLE_TYPE "Type invalide %s pour la table %s"
+#define MSG_BAD_TEST_TYPE "BlockTest sur tableau: types d‚pareill‚s %s %s"
+#define MSG_BAD_TRIM_ARGTYP "Argument de type invalide pour Trim"
+#define MSG_BAD_TYPE_FOR_IN "Types d'argument incompatibles pour la fonction IN"
+#define MSG_BAD_TYPE_FOR_S "Type incorrecte %d pour %s(%d)"
+#define MSG_BAD_TYPE_LIKE "Type(%d)= %d invalide pour LIKE"
+#define MSG_BAD_UPD_COR "Le qualificateur %s de la colonne %s ne se refŠre pas … la table mise … jour %s"
+#define MSG_BAD_USERBLK_LEN "Mauvaise longueur … l'‚criture du bloc utilisateur"
+#define MSG_BAD_USETEMP "Usetemp invalide '%s'"
+#define MSG_BAD_USETEMP_VAL "Valeur pour Usetemp invalide %d"
+#define MSG_BAD_VALBLK_INDX "Valeur hors limites de l'index du bloc de valeurs"
+#define MSG_BAD_VALBLK_TYPE "Type=%d invalide pour un bloc de valeurs"
+#define MSG_BAD_VALNODE "Type %d invalide pour le noeud valeur colonne %s"
+#define MSG_BAD_VALUE_TYPE "Type de valeur invalide %d"
+#define MSG_BAD_VAL_UPDATE "Impossible de d‚terminer quelle valeur %s doit ˆtre mise … jour"
+#define MSG_BAD_VIEW_OPEN "Mode invalide %d pour l'ouverture d'une View"
+#define MSG_BAD_XMODE_VAL "Mode d'ex‚cution %d invalide"
+#define MSG_BAD_XOBJ_TYPE "Mauvais type de Xobject %d"
+#define MSG_BAS_NS_LIST "Format invalide de la liste des espace-noms"
+#define MSG_BIN_F_TOO_LONG "Valeur trop longue pour le champ %s (%d --> %d)"
+#define MSG_BIN_MODE_FAIL "Echec mode binaire: %s"
+#define MSG_BLKTYPLEN_MISM "Disparit‚ types/longueurs de bloc dans SetValue"
+#define MSG_BLK_IS_NULL "Blk est nul"
+#define MSG_BLOCK_NO_MATCH "Bloc non correspondant"
+#define MSG_BREAKPOINT "Point de controle"
+#define MSG_BUFF_TOO_SMALL "GetColData: Buffer trop petit"
+#define MSG_BUFSIZE_ERROR "Erreur en recherchant la taille du buffer"
+#define MSG_BUILDING_GROUPS "Formation des groupes"
+#define MSG_BUILD_DIST_GRPS "Formation des groupes distinctes"
+#define MSG_BUILD_INDEX "Construction index %s sur %s"
+#define MSG_BXP_NULL "Bxp nul dans PUTFON"
+#define MSG_CANNOT_OPEN "Ouverture impossible de %s"
+#define MSG_CD_ONE_STEP "Count Distinct doit ˆtre ex‚cut‚ en une seule ‚tape"
+#define MSG_CD_ORDER_ERROR "Erreur de tri dans Count Distinct"
+#define MSG_CHECKING_ROWS "Test des lignes … mettre … jour"
+#define MSG_CHECK_LEVEL "Niveau de v‚rification fix‚ … %u"
+#define MSG_CHSIZE_ERROR "Erreur dans chsize: %s"
+#define MSG_CLN_NOT_IN_JOIN "La colonne C%d n'est pas dans le join"
+#define MSG_CNTDIS_COL_LOST "Colonne du Count Distinct perdue"
+#define MSG_COLIST_BAD_TYPE "Type=%d invalide pour Colist"
+#define MSG_COLNAM_TOO_LONG "Nom de colonne trop long"
+#define MSG_COLSEC_TOO_BIG "Section colonne trop grande, table %s (%d)"
+#define MSG_COLS_REDUCED " (r‚duit par Maxcol)"
+#define MSG_COLUMN_ERROR "Erreur de colonne"
+#define MSG_COLUMN_MISMATCH "Colonne %s d‚pareill‚e"
+#define MSG_COLUMN_NOT_KEY "La colonne jointe R%d.%s n'est pas une cl‚"
+#define MSG_COL_ALLOC_ERR "Allocation impossible du noeud colonne"
+#define MSG_COL_ALLOC_ERROR "Erreur d'allocation m‚moire pour la colonne %d"
+#define MSG_COL_HAS_NO_DEF "La colonne %s n'est pas d‚finie"
+#define MSG_COL_INVAL_TABLE "La colonne %s.%s n'existe pas dans la table %s alias %s"
+#define MSG_COL_ISNOT_TABLE "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NB_MISM "Le nombre de colonnes ne correspond pas"
+#define MSG_COL_NOTIN_GRPBY "La colonne %s n'est pas dans la liste de Group By"
+#define MSG_COL_NOTIN_TABLE "La colonne %s n'est dans aucune table"
+#define MSG_COL_NOTIN_UPDT "%s n'appartient pas … la table mise … jour %s"
+#define MSG_COL_NOT_CODED "La colonne %s n'est pas codifi‚e"
+#define MSG_COL_NOT_EXIST "La colonne %s n'existe pas dans %s"
+#define MSG_COL_NOT_FOUND "La colonne %s n'est pas dans la table %s"
+#define MSG_COL_NOT_IN_DB "La colonne %s de la table %s n'est pas dans la base de donn‚es"
+#define MSG_COL_NOT_IN_JOIN "La colonne %s n'est pas dans le join"
+#define MSG_COL_NOT_SORTED "La colonne %s de la table %s n'est pas tri‚e"
+#define MSG_COL_NUM_MISM "Disparit‚ du nombre de colonnes"
+#define MSG_COL_USED_TWICE "Colonne %s utilis‚e deux fois ???"
+#define MSG_COMPUTE_ERROR "Erreur dans Compute, op=%d"
+#define MSG_COMPUTE_NIY "Compute non impl‚ment‚ pour TOKEN"
+#define MSG_COMPUTING "Calculs en cours"
+#define MSG_COMPUTING_DIST "Comptage des valeurs distinctes"
+#define MSG_COMPUTING_FUNC "Calcul de(s) fonction(s)"
+#define MSG_COM_ERROR "Erreur Com"
+#define MSG_CONCAT_SUBNODE "Concat‚nation de sous-noeuds impossible"
+#define MSG_CONNECTED "Connect‚e"
+#define MSG_CONNECT_CANCEL "Connection interrompue par l'utilisateur"
+#define MSG_CONNECT_ERROR "Erreur %d se connectant à %s"
+#define MSG_CONN_CLOSED "%s(%d) ferm‚e"
+#define MSG_CONN_CREATED "Connexion %s cr‚e"
+#define MSG_CONN_DROPPED "Connexion %s supprim‚e"
+#define MSG_CONN_OPEN "%s(%d) ouverte (%s)"
+#define MSG_CONN_SUC_OPEN "%s(%d) ouverte avec succŠs"
+#define MSG_CONTROL_C_EXIT "Exit par Ctrl-C"
+#define MSG_COPY_BAD_PHASE "Copie de liste invalide en phase %d"
+#define MSG_COPY_INV_TYPE "Coparm: type non support‚ %d"
+#define MSG_CORREL_NO_QRY "Les sous-requˆtes corr‚l‚es ne peuvent pas ˆtre de type QRY"
+#define MSG_CREATED_PLUGDB " Cr‚‚ par PlugDB %s "
+#define MSG_CURSOR_SET "Curseur remis … %d"
+#define MSG_DATABASE_ACTIVE "Base de donn‚es %s activ‚e"
+#define MSG_DATABASE_LOADED "Base de donn‚es %s charg‚e"
+#define MSG_DATA_IS_NULL "ExecSpecialCmd: data est NULL"
+#define MSG_DATA_MISALIGN "Mauvais alignement pour ce type de donn‚es"
+#define MSG_DBASE_FILE "Fichier dBASE dbf: "
+#define MSG_DB_ALREADY_DEF "Base de donn‚es %s d‚j… d‚finie"
+#define MSG_DB_ALTERED "Base de donn‚es modifi‚e"
+#define MSG_DB_CREATED "Base de donn‚es %s cr‚‚e"
+#define MSG_DB_NOT_SPEC "Base de donn‚es non sp‚cifi‚e"
+#define MSG_DB_REMOVED "Base de donn‚es %s retir‚e de la liste"
+#define MSG_DB_SORT_ERROR "Erreur de tri DB"
+#define MSG_DB_STOPPED "Arrˆt de la base de donn‚es %s"
+#define MSG_DEBUG_NOT_ACTIV "Mode Debug inactif"
+#define MSG_DEBUG_SET_INV "Invalide pour Debug: %c"
+#define MSG_DEF_ALLOC_ERROR "Erreur d'allocation de la classe DEF %s"
+#define MSG_DELETING_ROWS "Suppression des lignes"
+#define MSG_DEL_FILE_ERR "Erreur … l'effacement de %s"
+#define MSG_DEL_READ_ERROR "Delete: erreur en lecture req=%d len=%d"
+#define MSG_DEL_WRITE_ERROR "Delete: erreur en ‚criture: %s"
+#define MSG_DEPREC_FLAG "Option Flag p‚rim‚e, utiliser Coltype"
+#define MSG_DICTIONARY "Dictionnaire "
+#define MSG_DIRECT_VARTOK "AccŠs direct aux rŠgles du Variable Token non impl‚ment‚"
+#define MSG_DISCONNECTED "D‚connect‚"
+#define MSG_DISTINCT_ERROR "Plus d'un ‚l‚ment fonctionel DISTINCT"
+#define MSG_DISTINCT_ROWS "S‚lection des lignes distinctes"
+#define MSG_DISTINCT_VALUES "Extraction des valeurs distinctes"
+#define MSG_DIS_NOHEAD_JOIN "Jointure distincte sur une table non en tˆte"
+#define MSG_DLL_LOAD_ERROR "Erreur %d au chargement du module %s"
+#define MSG_DOMAIN_EMPTY "Le domaine %s est vide"
+#define MSG_DOMAIN_ERROR "Colonne %s: disparit‚ domaine(%s)/valeur(%s)"
+#define MSG_DOMAIN_FULL "Le domaine %s est plein (max=%d)"
+#define MSG_DOM_FILE_ERROR "Fichier domain %s introuvable"
+#define MSG_DOM_NOT_SUPP "MS-DOM non support‚ par cette version"
+#define MSG_DOM_OPEN_ERROR "Erreur d'ouverture du domaine: %s"
+#define MSG_DOM_READ_ERROR "Erreur %d en lecture de domaine: %s"
+#define MSG_DOM_READ_ONLY "La table domaine %s est en lecture seulement"
+#define MSG_DOM_WRITE_ERROR "Erreur %d en ‚criture de domaine: %s"
+#define MSG_DONE "Effectu‚, rc=%d"
+#define MSG_DOSALMEM_NOMEM "Erreur d'allocation, pas assez de m‚moire"
+#define MSG_DROP_DB_ERR "Echec du Drop sur le base de donn‚es %s"
+#define MSG_DSORT_LOG_ERROR "Kindex: Erreur logique de tri distincte"
+#define MSG_DUMMY_NO_COLS "Les tables DUMMY ne peuvent pas avoir de colonne"
+#define MSG_DUPLICAT_COUNT "Count sur plus d'une colonne"
+#define MSG_DUP_COL_NAME "La colonne %s existe en double"
+#define MSG_DUP_PROJNUM "Non unique projnum %d pour la colonne %s"
+#define MSG_DVAL_NOTIN_LIST "Valeur %s non trouv‚e dans la liste des valeurs distinctes de la colonne %s"
+#define MSG_EMPTY_DOC "Document vide"
+#define MSG_EMPTY_FILE "%s du fichier vide %s: "
+#define MSG_ENDSTR_MISMATCH "Fins de chaŒne et de noeud ne correspondent pas"
+#define MSG_END_OF_DELETE "%d ligne(s) enlev‚e(s) en %.2lf sec"
+#define MSG_END_OF_INSERT "%d ligne(s) ins‚r‚e(s) en %.2lf sec"
+#define MSG_END_OF_QUERY "%d ligne(s) extraite(s) en %.2lf sec"
+#define MSG_END_OF_UPDATE "%d ligne(s) modifi‚e(s) en %.2lf sec"
+#define MSG_EOF_AFTER_LINE "Fin de fichier aprŠs la ligne %d"
+#define MSG_EOF_INDEX_FILE "EOF lisant le fichier index"
+#define MSG_ERASED " et effac‚e"
+#define MSG_ERASE_FAILED " (‚chec de l'effacement)"
+#define MSG_ERROR "Erreur"
+#define MSG_ERROR_IN_LSK "Erreur %d dans lseek64"
+#define MSG_ERROR_IN_SFP "Erreur %d dans SetFilePointer"
+#define MSG_ERROR_NO_PARM "ParamŠtre absent (valide seulement pour %.8s.1 et %.8s.5)"
+#define MSG_ERROR_OPENING "Erreur … l'ouverture de : "
+#define MSG_ERR_NUM_GT_MAX "Erreur: Numval (%d) plus grand que Maxnum (%d)"
+#define MSG_ERR_READING_REC "Erreur lisant l'enregistrement %d de %s"
+#define MSG_ERR_RET_RULE "Retour erreur, rŠgle=%u"
+#define MSG_ERR_RET_TYPE "Retour erreur, type=%d"
+#define MSG_EVAL_EXPIRED "Cette version d'évaluation est expir‚e"
+#define MSG_EVAL_ONLY "L'utilisation de cette Dll est pour ‚valuation seulement"
+#define MSG_EXECUTING "Ex‚cution"
+#define MSG_EXECUTION_ERROR "Erreur d'ex‚cution"
+#define MSG_EXEC_MODE_IS "Le mode d'ex‚cution est %s"
+#define MSG_EXEC_MODE_RESET ". Mode remis … Execute"
+#define MSG_EXEC_MODE_SET "Mode d'ex‚cution fix‚ … %s"
+#define MSG_EXIT_EVAL_ERR "Erreur pendant l'‚valuation de Exit"
+#define MSG_EXIT_FROM_LANG "Fin du langage %s version %d.%d"
+#define MSG_FAIL_ADD_NODE "L'ajout du noeud %s dans la table a ‚chou‚"
+#define MSG_FETCHING_DATA "Recherche des donn‚es"
+#define MSG_FETCHING_ROWS "Recherche des lignes"
+#define MSG_FETCH_NO_RES "Fetch: Pas de R‚sultats"
+#define MSG_FIELD_TOO_LONG "Valeur trop longue pour le champs %d ligne %d"
+#define MSG_FILELEN_ERROR "Erreur dans %s pour %s"
+#define MSG_FILE_CLOSE_ERR "Erreur %d … la fermeture du fichier"
+#define MSG_FILE_IS_EMPTY "Le fichier %s est vide"
+#define MSG_FILE_MAP_ERR "Erreur de File mapping"
+#define MSG_FILE_MAP_ERROR "CreateFileMapping %s erreur rc=%d"
+#define MSG_FILE_NOT_FOUND "Fichier %s introuvable"
+#define MSG_FILE_OPEN_YET "Fichier %s d‚j… ouvert"
+#define MSG_FILE_UNFOUND "Fichier %s non trouv‚"
+#define MSG_FILGRP_NO_TABLE "Table %d manquante pour groupe filtre"
+#define MSG_FILTER_ATTACH "Filtre pass‚ … Attach"
+#define MSG_FILTER_NO_TABLE "Filtre: premiŠre table manquante"
+#define MSG_FIND_BAD_TYPE "Recherche dans un tableau: type non conforme %s %s"
+#define MSG_FIX_OVFLW_ADD "D‚passement de capacit‚ en addition"
+#define MSG_FIX_OVFLW_TIMES "D‚passement de capacit‚ en mutiplication"
+#define MSG_FIX_UNFLW_ADD "Sous d‚passement de capacit‚ en addition"
+#define MSG_FIX_UNFLW_TIMES "Sous d‚passement de capacit‚ en multiplication"
+#define MSG_FLD_TOO_LNG_FOR "Champs %d trop long pour %s ligne %d de %s"
+#define MSG_FLTST_NO_CORREL "FilTest ne devrait ˆtre appel‚ que pour les sous-requˆtes corr‚l‚es"
+#define MSG_FLT_BAD_RESULT "Virgule flottante: r‚sultat inexacte"
+#define MSG_FLT_DENORMAL_OP "Op‚rande virgule flottante non normalis‚"
+#define MSG_FLT_INVALID_OP "Op‚ration virgule flottante invalide"
+#define MSG_FLT_OVERFLOW "D‚passement de capacit‚ virgule flottante"
+#define MSG_FLT_STACK_CHECK "Virgule flottante: Erreur de la pile"
+#define MSG_FLT_UNDERFLOW "Sous-d‚passement de capacit‚ virgule flottante"
+#define MSG_FLT_ZERO_DIVIDE "Virgule flottante: division par z‚ro"
+#define MSG_FMT_WRITE_NIY "L'‚criture des fichiers %s n'est pas encore impl‚ment‚e"
+#define MSG_FNC_NOTIN_SLIST "Fonction de tri absente de la liste de s‚lection"
+#define MSG_FORMAT_ERROR "Erreur de formattage"
+#define MSG_FOXPRO_FILE "Fichier FoxPro: "
+#define MSG_FPUTS_ERROR "Erreur dans fputs: %s"
+#define MSG_FSBPARP_NULL "PUTFON: fsbparp est nul"
+#define MSG_FSEEK_ERROR "Erreur dans fseek: %s"
+#define MSG_FSETPOS_ERROR "Erreur dans fseek pour i=%d"
+#define MSG_FTELL_ERROR "Erreur dans ftell enregistrement=%d: %s"
+#define MSG_FUNCTION_ERROR "Erreur dans %s: %d"
+#define MSG_FUNC_ERRNO "Erreur %d dans %s"
+#define MSG_FUNC_ERROR "Erreur dans %s"
+#define MSG_FUNC_ERR_S "Erreur dans %s: %s"
+#define MSG_FUNC_REF_DEL "R‚f‚rence … une fonction d‚finie (rŠgle %d) qui a ‚t‚ supprim‚e"
+#define MSG_FWRITE_ERROR "Erreur dans fwrite: %s"
+#define MSG_GETCWD_ERR_NO "?getcwd %s errno=%d"
+#define MSG_GETFILESIZE_ERR "Erreur %d dans GetFileSize"
+#define MSG_GET_DIST_VALS "R‚cup‚ration des valeurs distinctes de "
+#define MSG_GET_ERROR "Erreur dans %s (colonne %d)"
+#define MSG_GET_FUNC_ERR "Erreur en recherche de la fonction %s: %s"
+#define MSG_GET_NAME_ERR "Erreur en retrouvant le nom d'une table SYS"
+#define MSG_GLOBAL_ERROR "Erreur d'allocation de Global (taille=%d)\n"
+#define MSG_GRAM_ALLOC_ERR "Erreur d'allocation dans Grammar Up"
+#define MSG_GRAM_MISMATCH "Avertissement: version de GRAMMAR p‚rim‚e (sauv‚ sous GRAMMAR v%u)"
+#define MSG_GRAM_SUBSET_ERR "Erreur d'initialisation du dictionnaire de la grammaire"
+#define MSG_GRBY_TAB_NOTIMP "Group by avec tables jointes non impl‚ment‚"
+#define MSG_GROUPBY_NOT_ALL "Group By doit inclure toutes les s‚lections non-fonctionnelles"
+#define MSG_GROUP_ON_FUNC "Group by invalide sur colonne fonctionnelle"
+#define MSG_GRP_COL_MISM "Disparit‚ colonne des groupes"
+#define MSG_GRP_LIST_MISMAT "Le groupement ne couvre pas la liste de s‚lection"
+#define MSG_GUARD_PAGE "Violation de page de garde"
+#define MSG_GZOPEN_ERROR "gzopen %s: erreur %d sur %s"
+#define MSG_GZPUTS_ERROR "Erreur dans gzputs: %s"
+#define MSG_HANDLE_IS_NULL "%s est NULL: erreur code: %d"
+#define MSG_HARRY_COMP_NIY "Compute non impl‚ment‚ pour les chaŒnes cod‚es"
+#define MSG_HAVING_FILTER "Traitement du Filtre Having"
+#define MSG_HBUF_TOO_SMALL "Buffer(%d) trop petit pour entˆte(%d)"
+#define MSG_HEAD_OPEN_ERROR "Erreur … l'ouverture du fichier header"
+#define MSG_HEAD_READ_ERROR "Erreur en lecture du fichier header %s"
+#define MSG_HEAD_WRITE_ERR "Erreur en ‚criture du fichier header"
+#define MSG_HI_OFFSET_ERR "Offset sup‚rieur non nul"
+#define MSG_HUGE_DEFAULT "Huge est %d par d‚fault"
+#define MSG_HUGE_WARNING_1 "M‚moire Huge non compatible 16-bit pour %d\n"
+#define MSG_HUGE_WARNING_2 "R‚sultats impr‚visibles possibles\n"
+#define MSG_IDLE "Au repos"
+#define MSG_ILLEGAL_INSTR "Instruction ill‚gale"
+#define MSG_ILL_FILTER_CONV "Conversion implicite ill‚gale dans un filtre"
+#define MSG_INDEX_CREATED "Index %s cr‚‚ sur %s"
+#define MSG_INDEX_DEF_ERR "Erreur sauvegardant l'index d‚finition pour %s"
+#define MSG_INDEX_DROPPED "Index %s supprim‚ de %s"
+#define MSG_INDEX_INIT_ERR "Echec de l'initialisation de l'index %s"
+#define MSG_INDEX_NOT_DEF "Index %s non d‚fini"
+#define MSG_INDEX_NOT_UNIQ "L'index n'est pas Unique"
+#define MSG_INDEX_ONE_SAVE "Les index sont sauvegard‚s dans un fichier unique"
+#define MSG_INDEX_SEP_SAVE "Les index sont sauvegard‚s dans des fichiers s‚par‚s"
+#define MSG_INDEX_YET_ON "L'index %s existe d‚j… sur %s"
+#define MSG_INDX_ALL_DROP "Tous les index de %s supprim‚s"
+#define MSG_INDX_COL_NOTIN "La colonne index %s n'existe pas dans la table %s"
+#define MSG_INDX_EXIST_YET "L'entr‚e index existe d‚j…"
+#define MSG_INIT_ERROR "Erreur à l'initialisation de %s"
+#define MSG_INIT_FAILED "L'initialisation de %s a ‚chou‚"
+#define MSG_INPUT "Entr‚e: "
+#define MSG_INPUT_KEYBD_YET "L'entr‚e est d‚j… au clavier"
+#define MSG_INSERTING "Insertion: "
+#define MSG_INSERT_ERROR "Insert erreur: usage multiple du fichier %s"
+#define MSG_INSERT_MISMATCH "Les listes colonne et valeur ne correspondent pas"
+#define MSG_INTERNAL "interne"
+#define MSG_INT_COL_ERROR "Erreur interne sur la colonne index %s"
+#define MSG_INT_OVERFLOW "D‚passement de capacit‚ sur entier"
+#define MSG_INT_ZERO_DIVIDE "Division entiŠre par z‚ro"
+#define MSG_INVALID_BIP "Bip invalide .%d"
+#define MSG_INVALID_DISP "Disposition invalide"
+#define MSG_INVALID_FTYPE "SBV: Ftype %d invalide"
+#define MSG_INVALID_HANDLE "Poign‚e invalide"
+#define MSG_INVALID_OPER "Op‚rateur invalide %d pour %s"
+#define MSG_INVALID_OPTION "Option invalide %s"
+#define MSG_INV_COLUMN_TYPE "Type %d Invalide pour la colonne %s"
+#define MSG_INV_COL_DATATYP "Type de donn‚es %d invalide pour la colonne %d"
+#define MSG_INV_COL_NUM "Colonne invalide %d"
+#define MSG_INV_COL_TYPE "Type de colonne %s invalide"
+#define MSG_INV_CONC_BIP "Bip invalide (seuls valides: %.8s.0 .1 and .5)"
+#define MSG_INV_DATA_PATH "Chemin vers les donn‚es invalide"
+#define MSG_INV_DEF_READ "Lecture diff‚r‚e invalide rc=%d"
+#define MSG_INV_DIRCOL_OFST "Offset invalide pour une colonne DIR"
+#define MSG_INV_DOMAIN_TYPE "Type invalide %d"
+#define MSG_INV_FILTER "Filtre r‚siduel dans %s"
+#define MSG_INV_FNC_BUFTYPE "FNC: Type %d de l'argument invalide pour %s"
+#define MSG_INV_INFO_TYPE "Type d'info catalog invalide %d"
+#define MSG_INV_INIPATH "Inipath invalide "
+#define MSG_INV_MAP_POS "Position m‚moire invalide"
+#define MSG_INV_OPERATOR "op‚rateur invalide %d\n"
+#define MSG_INV_PARAMETER "ParamŠtre invalide %s"
+#define MSG_INV_PARM_TYPE "Type de paramŠtre invalide"
+#define MSG_INV_QUALIFIER "Qalificateur '%s' invalide"
+#define MSG_INV_QUERY_TYPE "Type de requˆte %d invalide"
+#define MSG_INV_RAND_ACC "L'accŠs al‚atoire d'une table non optimis‚e est impossible"
+#define MSG_INV_REC_POS "Position d'enregistrement invalide"
+#define MSG_INV_RESULT_TYPE "Type de r‚sultat invalide %s"
+#define MSG_INV_SET_SUBTYPE "Type de formattage %d invalide"
+#define MSG_INV_SPECIAL_CMD "%s: Commande sp‚ciale invalide"
+#define MSG_INV_SUBTYPE "Sous type invalide %s"
+#define MSG_INV_TOK_DOMAIN "Le domaine %s n'existe pas"
+#define MSG_INV_TOPSEM_CMD "Commande TopSem invalide %c"
+#define MSG_INV_TRANSF_USE "Usage invalide en rŠgle transformationnelle"
+#define MSG_INV_TYPE_SPEC "Sp‚cification de type invalide (%.8s.%d)"
+#define MSG_INV_UPDT_TABLE "Table %s invalide pour Update"
+#define MSG_INV_VALUE_LIST "Liste de valeurs invalide pour Insert"
+#define MSG_INV_WHERE_JOIN "Clause Where invalide dans une requˆte de jointure"
+#define MSG_INV_WORK_PATH "Chemin de travail invalide"
+#define MSG_IN_ARGTYPE_MISM "Arguments de types incompatibles pour une expression IN"
+#define MSG_IN_USE " et en activit‚"
+#define MSG_IN_WITHOUT_SUB "IN ou EXISTS sans tableau ou subquery"
+#define MSG_IS_NOT_CONN "%s n'est pas une connexion d‚finie"
+#define MSG_JCT_MISS_COLS "Colonnes manquantes pour une table JCT"
+#define MSG_JCT_MISS_TABLE "Table jointe manquante pour JCT"
+#define MSG_JCT_NO_FILTER "Filtrage impossible des tables virtuelles JCT"
+#define MSG_JCT_NO_KEY "Erreur logique JCT: cl‚ manquante"
+#define MSG_JOIN_KEY_NO_COL "La cl‚ de jointure n'est pas une colonne"
+#define MSG_KEY_ALLOC_ERR "Erreur d'allocation d'un bloc offset cl‚"
+#define MSG_KEY_ALLOC_ERROR "Erreur d'allocation m‚moire, Klen=%d n=%d"
+#define MSG_LANGUAGE_QUIT "%s lib‚r‚"
+#define MSG_LANG_ACTIVE "Langage %s actif"
+#define MSG_LANG_ALLOC_FAIL "PlugInitLang: Erreur d'allocation du bloc Lang"
+#define MSG_LANG_ALREADY_UP "Langage d‚j… en ‚dition"
+#define MSG_LANG_BAD_SAVE "Langage %s peut-ˆtre incorrectement sauvegard‚"
+#define MSG_LANG_NOT_FREED "Langage %s non lib‚rable (pas dans la chaŒne principale)"
+#define MSG_LANG_SAVED "Langage %s sauvegard‚"
+#define MSG_LANG_WR_LEN_ERR "Erreur de longueur … l'‚criture du bloc Lang"
+#define MSG_LDF_ALLOC_ERROR "Erreur d'allocation d'un LdfBlock"
+#define MSG_LDF_RN_MISMATCH "LDF: d‚calage des num‚ros de rŠgle"
+#define MSG_LDF_WLEN_ERROR "Erreur de longueur en ‚crivant LdfData"
+#define MSG_LDF_W_LEN_ERROR "Erreur de longueur pour LdfData en ‚criture"
+#define MSG_LIC_NO_MYSQL "Votre licence actuelle ne permet pas l'utilisation du type MYSQL"
+#define MSG_LINEAR_ERROR "Erreur de lin‚arisation"
+#define MSG_LINE_LENGTH "Largeur d'impression fix‚e … %d"
+#define MSG_LINE_MAXLIN "Nombre de lignes de travail plafonn‚ … %d"
+#define MSG_LINE_MAXRES "Nombre de lignes de r‚sultat plafonn‚ … %d"
+#define MSG_LINE_MAXTMP "Nombre de lignes interm‚diaires plafonn‚ … %d"
+#define MSG_LINE_TOO_LONG "La nouvelle ligne est trop longue"
+#define MSG_LINJOINDB_ERROR "Erreur systŠme: appel incorrecte … LinJoinDB"
+#define MSG_LIST "--Liste--"
+#define MSG_LNG_NOT_IN_LIST "Le langage %s n'est pas dans la liste"
+#define MSG_LOADING_DB "Chargement description de la BD"
+#define MSG_LOADING_FAILED "Le chargement de %s a ‚chou‚"
+#define MSG_LOAD_CDLL_ERROR "Erreur au chargement de ConnDll: rc=%d"
+#define MSG_LOCSTRG_TOO_BIG "LOCSTRG: n trop grand ? (%d)\n"
+#define MSG_LOGICAL_ERROR "%s: Erreur logique"
+#define MSG_LRECL_TOO_SMALL "Lrecl trop petit (longueur en-tˆte = %d)"
+#define MSG_MAC_NO_DELETE "Pas de suppression de lignes pour les tables MAC"
+#define MSG_MAC_NO_INDEX "Pas d'accŠs direct aux tables MAC"
+#define MSG_MAC_READ_ONLY "Les tables MAC sont en lecture seulement"
+#define MSG_MAC_WIN_ONLY "Les tables MAC sont seulement sous Windows"
+#define MSG_MAKE_EMPTY_FILE "G‚n‚ration du fichier vide %s: %s"
+#define MSG_MAKING "G‚n‚ration"
+#define MSG_MAKING_DISTINCT "Regroupement des valeures distinctes"
+#define MSG_MALLOC_ERROR "Allocation m‚moire impossible par %s"
+#define MSG_MALLOC_NULL "malloc retourne Null"
+#define MSG_MAP_NO_MORE "Le type %s n'est plus support‚"
+#define MSG_MAP_OBJ_ERR "Erreur %d … la fermeture du map objet"
+#define MSG_MAP_VEC_ONLY "MAP Insert permis seulement pour les tables VEC Estimate"
+#define MSG_MAP_VIEW_ERROR "MapViewOfFile %s erreur rc=%d"
+#define MSG_MAXSIZE_ERROR "Maxsize incalculable sur table ouverte"
+#define MSG_MAXTMP_TRUNCATE "R‚sultats interm‚diaires tronqu‚s par maxtmp=%d"
+#define MSG_MAX_BITMAP "Taille maxi des bitmaps d'optimisation fix‚e … %d"
+#define MSG_MEMSIZE_TOO_BIG "Erreur: memsize (%d) trop grand pour Length (%d)"
+#define MSG_MEM_ALLOC_ERR "Erreur d'allocation m‚moire, taille %s = %d"
+#define MSG_MEM_ALLOC_ERROR "Erreur d'allocation m‚moire"
+#define MSG_MEM_ALLOC_YET "M‚moire d‚j… allou‚e"
+#define MSG_METAFILE_NOTFND "Fichier Meta introuvable"
+#define MSG_MISPLACED_QUOTE "Appostrophe mal plac‚e ligne %d"
+#define MSG_MISSING "Manquant: Value=%p Argval=%p Builtin=%d"
+#define MSG_MISSING_ARG "Argument manquant pour l'op‚rateur %d"
+#define MSG_MISSING_COL_DEF "D‚finition des colonnes manquante"
+#define MSG_MISSING_CONNECT "Connection #1 manquante"
+#define MSG_MISSING_EOL "Fin de ligne manquante dans %s"
+#define MSG_MISSING_FIELD "Champs %d manquant dans %s ligne %d"
+#define MSG_MISSING_FNAME "Nom du fichier manquant"
+#define MSG_MISSING_NODE "Noeud %s manquant dans %s"
+#define MSG_MISSING_POS "POS code manquant"
+#define MSG_MISSING_ROWNODE "Impossible de trouver le noeud de la ligne %d"
+#define MSG_MISSING_SERV_DB "Indication serveur et/ou base de donn‚es manquante"
+#define MSG_MISS_LEAD_COL "Colonne majeure %s manquante"
+#define MSG_MISS_NAME_LRECL "Nom du fichier et/ou LRECL manquant"
+#define MSG_MISS_TABLE_LIST "Liste des tables manquante"
+#define MSG_MISS_VCT_ELMT "Taille de bloc vectoriel manquante (Elements)"
+#define MSG_MIS_TAG_LIST "Liste des balises colonne manquante"
+#define MSG_MKEMPTY_NIY "MakeEmptyFile: pas encore implement‚ pour Huge et Unix"
+#define MSG_MOVE_INV_TYPE "MOVPARM: paramŠtre de type invalide %d"
+#define MSG_MULT_DISTINCT "Distinct utilis‚ plus d'une fois"
+#define MSG_MULT_KEY_ERROR "Erreur sur cl‚ multiple k=%d n=%d"
+#define MSG_MUL_MAKECOL_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_MYSQL_CNC_OFF "La connexion … MySQL est ferm‚e"
+#define MSG_MYSQL_CNC_ON "La connexion … MySQL est ‚tablie"
+#define MSG_MYSQL_NOT_SUP "Pas de support de MySQL dans cette version"
+#define MSG_MY_CNC_ALREADY "La connexion … MySQL est d‚j… active"
+#define MSG_NAME_CONV_ERR "Erreur de convertion du nom de noeud"
+#define MSG_NAME_IS_USED "Le nom %s est d‚j… utilis‚"
+#define MSG_NCOL_GT_MAXCOL "Trop de colonnes (%d > %d max)"
+#define MSG_NEW_CHAR_NULL "new char(%d) retourne Null"
+#define MSG_NEW_DOC_FAILED "Impossible de cr‚er le nouveau document"
+#define MSG_NEW_RETURN_NULL "NULL renvoy‚ par New dans PlugEvalLike"
+#define MSG_NEW_TABLE_ERR "La nouvelle table %s ne peut pas ˆtre charg‚e"
+#define MSG_NEXT_FILE_ERROR "Erreur en recherche du fichier suivant. rc=%s"
+#define MSG_NODEF_FROM_VIEW "Pas de d‚finition de table depuis une view"
+#define MSG_NODE_FOR_CHAR "Noeud %s trouve au lieu d'un caractŠre"
+#define MSG_NODE_SUBSET_ERR "Erreur d'initialisation de la zone Noeud %d"
+#define MSG_NONCONT_EXCEPT "Exception non-continuable"
+#define MSG_NON_DUP_HAVING "Clause Having dans une requˆte non fonctionelle"
+#define MSG_NON_EVAL_SEM "Sem non ‚valu‚e: p_no=%d"
+#define MSG_NOP_ZLIB_INDEX "L'indexage d'une table zlib non optimis‚e est impossible"
+#define MSG_NOT_A_DBF_FILE "Le fichier n'a pas le format dBASE dbf "
+#define MSG_NOT_ENOUGH_COLS "Pas assez de colonnes dans %s"
+#define MSG_NOT_ENOUGH_MEM "M‚moire insuffisante pour cette op‚ration"
+#define MSG_NOT_FIXED_LEN "Fichier %s non fixe, len=%d lrecl=%d"
+#define MSG_NOT_IMPLEMENTED "Non implement‚: %.8s"
+#define MSG_NOT_IMPL_JOIN "Pas impl‚ment‚ pour les jointures"
+#define MSG_NOT_IMPL_SET "Pas impl‚ment‚ pour les op‚rateurs d'ensembles"
+#define MSG_NOT_IMPL_YET "Pas encore implement‚"
+#define MSG_NOT_LINEARIZED "Arborescence des tables non lin‚aris‚e"
+#define MSG_NOT_MODIFIABLE " (non modifiable)"
+#define MSG_NO_0DH_HEAD "0DH manquant en fin d'en-tˆte (dbc=%d)"
+#define MSG_NO_ACTIVE_APPL "Pas d'application active"
+#define MSG_NO_ACTIVE_DB "Pas de base de donn‚es active"
+#define MSG_NO_ACTIVE_UDIC "Pas de dictionaire utilisateur actif"
+#define MSG_NO_AGGR_FUNC "Fonction aggr‚g‚e %d ill‚gale … cet endroit"
+#define MSG_NO_AREA_FILE "Fichier Area introuvable"
+#define MSG_NO_AVAIL_RESULT "Pas de r‚sultat disponible"
+#define MSG_NO_BIG_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les fichiers HUGE"
+#define MSG_NO_CHAR_FROM "Conversion de type %d en caractŠres impossible"
+#define MSG_NO_CLUSTER_COL "Pas de colonne optimisable"
+#define MSG_NO_COL_ADDING "Ajouter des colonnes dans une d‚finition existante est impossible"
+#define MSG_NO_COL_DEF_AS "La d‚finitions des colonnes est incompatible avec AS Select"
+#define MSG_NO_COL_FOUND "La section colonne %s est vide"
+#define MSG_NO_COL_IN_TABLE "La colonne %d n'est pas dans la table %s"
+#define MSG_NO_COL_SECTION "Section colonne manquante pour la table %s"
+#define MSG_NO_CONNECT_ADDR "Adresse de connection non sp‚cifi‚e"
+#define MSG_NO_CONST_FILTER "Filtres constants non implement‚s"
+#define MSG_NO_CURLY_BRKT "Pas d'accolade de fermeture"
+#define MSG_NO_DATABASE "Base de donn‚es %s introuvable"
+#define MSG_NO_DATE_FMT "Pas de format date pour le valblock de type %d"
+#define MSG_NO_DBF_INSERT "Insert pas encore impl‚ment‚ pour les fichier DBF"
+#define MSG_NO_DEF_FNCCOL "Colonne fonction par d‚faut introuvable"
+#define MSG_NO_DEF_PIVOTCOL "Colonne pivot par d‚faut introuvable"
+#define MSG_NO_DIR_INDX_RD "Pas d'accŠs directe des tables %s"
+#define MSG_NO_DMY_DIR_ACC "Pas d'accŠs direct aux tables virtuelles DUMMY"
+#define MSG_NO_DOM_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les domaines"
+#define MSG_NO_DOM_MATCH "ChaŒne %.8s... non touv‚e dans le domaine %s"
+#define MSG_NO_EDITED_LANG "Coparm: Pas de langage en ‚dition"
+#define MSG_NO_EXP_LINK "Liaison par expression invalide pour une table JCT"
+#define MSG_NO_EXT_FILTER "Le filtrage ne peut se r‚f‚rer … une autre table"
+#define MSG_NO_EXT_UPDATE "Pas de mise … jour en r‚f‚rence … une autre table"
+#define MSG_NO_FEAT_SUPPORT "%s non support‚ dans cette version"
+#define MSG_NO_FILE_LIST "La table %s n'a pas de liste de fichiers"
+#define MSG_NO_FLD_FORMAT "Format absent pour le champs %d de %s"
+#define MSG_NO_FORMAT_COL "Type COLUMN informattable"
+#define MSG_NO_FORMAT_TYPE "Le format ne peut pas ˆtre d‚fini … partir du type %d"
+#define MSG_NO_FULL_JOIN "Jointures autoris‚es seulement … ‚galit‚ sur cl‚(s)"
+#define MSG_NO_FUL_OUT_JOIN "Jointures externes complŠtes non support‚es"
+#define MSG_NO_FUNC_ORDER "Tri non support‚ sur ‚l‚ment fonctionnel"
+#define MSG_NO_HEAD_JOIN "Jointure sur une table non en tˆte"
+#define MSG_NO_HQL_CONV "Conversion en HQL non disponible"
+#define MSG_NO_INDEX "La table %s n'a pas d'index"
+#define MSG_NO_INDEX_GBX "Pas ou mauvais index pour SQLGBX"
+#define MSG_NO_INDEX_IN "Pas d'index dans %s"
+#define MSG_NO_INDEX_READ "Pas d'accŠs directe des tables multiples"
+#define MSG_NO_INIT_LANG "Pas de langage initial"
+#define MSG_NO_JOIN_TO_EXP "Jointure vers une expression impossible"
+#define MSG_NO_JOIN_UPDEL "Pas de jointure avec Update/Delete"
+#define MSG_NO_KEY_COL "Pas de colonne cl‚ trouv‚e"
+#define MSG_NO_KEY_UPDATE "Le nom des cl‚s ne peut pas ˆtre modifi‚"
+#define MSG_NO_LANGUAGE "Pas de langage op‚rationnel\n"
+#define MSG_NO_LANG_TO_QUIT "Pas de langage … quitter"
+#define MSG_NO_LISTVAL_HERE "LSTBLK: Liste de valeurs utilis‚e hors contexte"
+#define MSG_NO_MAP_INSERT "MAP incompatible avec Insert"
+#define MSG_NO_MATCHING_COL "Pas de colonne correspondant … %s dans %s"
+#define MSG_NO_MATCH_COL "Colonne correspondante introuvable"
+#define MSG_NO_MEMORY "M‚moire pleine"
+#define MSG_NO_MEM_CORR_SUB "Subquery corr‚l‚e en m‚moire non encore impl‚ment‚e"
+#define MSG_NO_MODE_PADDED "Mode non support‚ pour les fichiers 'padded'"
+#define MSG_NO_MORE_COL "La colonne %s n'est plus dans la table pivot"
+#define MSG_NO_MORE_LANG "Plus de langage, exit de %s\n"
+#define MSG_NO_MORE_VAR "Les fichiers VAR ne sont plus support‚s"
+#define MSG_NO_MULCOL_JOIN "Jointure vers un index multi-colonne pas encore possible"
+#define MSG_NO_MULT_HAVING "Clauses Having multiples non impl‚ment‚es"
+#define MSG_NO_MUL_DIR_ACC "AccŠs direct des tables multiples pas encore impl‚ment‚"
+#define MSG_NO_MUL_VCT "Les tables VCT ne peuvent pas ˆtre multiples"
+#define MSG_NO_MYSQL_CONN "Aucune connexion MySQL ouverte"
+#define MSG_NO_MYSQL_DELETE "Pas de Delete pour les tables MySQL"
+#define MSG_NO_NBCOL "Pas de NBcol"
+#define MSG_NO_NBLIN "Pas de NBlin, MaxSize ou Continued"
+#define MSG_NO_NBLIN_CONT "Fetch: Pas de NBlin ou Continued"
+#define MSG_NO_NULL_CONST "Les constantes <null> ne sont pas prises en charge"
+#define MSG_NO_ODBC_COL "Colonnes ODBC automatiques non support‚es par cette version"
+#define MSG_NO_ODBC_DELETE "Delete ne devrait pas ˆtre appel‚ pour les tables ODBC"
+#define MSG_NO_ODBC_DIRECT "AccŠs directe des tables ODBC non encore impl‚ment‚"
+#define MSG_NO_ODBC_MUL "Multiple(2) non support‚ pour les tables ODBC"
+#define MSG_NO_ODBC_SPECOL "Pas de colonne sp‚ciale ODBC"
+#define MSG_NO_OPT_COLUMN "Pas optimisable ou pas de colonne optimis‚es"
+#define MSG_NO_OP_MODIF "Les modificateurs ne s'appliquent pas … %s"
+#define MSG_NO_PARAMETER "Pas de paramŠtre"
+#define MSG_NO_PART_DEL "Delete partiel des fichier %s impossible"
+#define MSG_NO_PART_MAP "Mapping partiel non impl‚ment‚ pour cet OS"
+#define MSG_NO_PAR_BLK_INS "Insertion de bloc partiel impossible"
+#define MSG_NO_PIV_DIR_ACC "Pas d'accŠs directe aux tables PIVOT"
+#define MSG_NO_POS_ADDED "Pos_code non ajout‚"
+#define MSG_NO_PROMPTING "Relance impossible pour les tables distribu‚es"
+#define MSG_NO_QRY_DELETE "Delete n'est pas utilisable pour les views QRY"
+#define MSG_NO_QUERY_ARRAY "Tableaux avec QUERY non encore impl‚ment‚s"
+#define MSG_NO_RCUR_DSK_YET "Usage r‚cursif de DISK non encore implement‚"
+#define MSG_NO_READ_32 "Lecture de 32 octets impossible"
+#define MSG_NO_RECOV_SPACE "Espace non recouvrable dans le fichier index"
+#define MSG_NO_REF_DELETE "Pas de suppression en r‚f‚rence … une autre table"
+#define MSG_NO_REF_UPDATE "Pas de mise … jour en r‚f‚rence … une autre table"
+#define MSG_NO_REMOTE_FNC "Certaines fonctions ne peuvent pas ˆtre ex‚cut‚es … distance"
+#define MSG_NO_ROWID_FOR_AM "AccŠs direct impossible de ROWID pour les tables de type %s"
+#define MSG_NO_ROW_NODE "Le nom du Rownode n'est pas d‚fini"
+#define MSG_NO_SECTION_NAME "Nom de section manquant"
+#define MSG_NO_SEC_UPDATE "Les noms de section ne peuvent pas ˆtre modifi‚s"
+#define MSG_NO_SELECTED_DB "Aucune base de donn‚es s‚lect‚e"
+#define MSG_NO_SELF_PIVOT "Une table ne peut se pivoter elle-mˆme !"
+#define MSG_NO_SERVER_FOUND "Serveur introuvable"
+#define MSG_NO_SETPOS_YET "SetPos pas encore impl‚ment‚ pour les fichier %s"
+#define MSG_NO_SFEXIT_UNIX "Fonction %s non disponible sur Unix"
+#define MSG_NO_SOURCE " (pas de source)"
+#define MSG_NO_SPEC_COL "Pas de colonne sp‚ciales MYSQL"
+#define MSG_NO_SQL_DELETE "Delete n'est pas utilisable actuellement pour les views SQL"
+#define MSG_NO_SUB_VAL "Pas de sous-value d'un tableau de type %d"
+#define MSG_NO_SUCH_INDEX "La table %s n'a pas l'index %s"
+#define MSG_NO_SUCH_SERVER "Serveur %s introuvable"
+#define MSG_NO_SUCH_TABLE "Table %s pas dans la base de donn‚es"
+#define MSG_NO_TABCOL_DATA "Pas de donn‚es pour la table %s colonne %s"
+#define MSG_NO_TABLE_COL "Aucune colonne trouv‚e pour %s"
+#define MSG_NO_TABLE_DEL "Delete non autoris‚ pour les tables %s "
+#define MSG_NO_TABLE_DESC "Pas de bloc descriptif de table"
+#define MSG_NO_TABLE_INDEX "La table %s n'a pas d'index"
+#define MSG_NO_TABLE_LIST "Pas de liste de tables"
+#define MSG_NO_TAB_DATA "Pas de donn‚es pour la table %s"
+#define MSG_NO_TERM_IN_TOK "Les non-terminaux ne sont pas utilisables dans les rŠgles de Token"
+#define MSG_NO_TOKEN_DB "DB introuvable pour la colonne TOKEN %s"
+#define MSG_NO_UNIX_CATINFO "Pas d'info catalogue sous Unix"
+#define MSG_NO_UPDEL_JOIN "Pas de jointure de tables ODBC pour Update/Delete"
+#define MSG_NO_VCT_DELETE "D‚l‚tion Partielle non impl‚ment‚e pour les fichiers VCT"
+#define MSG_NO_VIEW_COLDEF "Colonne d‚finition impossible pour les views"
+#define MSG_NO_VIEW_SORT "La View fonctionnelle %s ne peut pas ˆtre tri‚e ou jointe"
+#define MSG_NO_ZIP_DELETE "Delete sur fichier Zip non encore implement‚"
+#define MSG_NO_ZIP_DIR_ACC "AccŠs directe des tables ZDOS non encore implement‚"
+#define MSG_NULL_COL_VALUE "La colonne n'a pas de valeur"
+#define MSG_NULL_ENTRY "InitLang, entr‚e nulle %d %s"
+#define MSG_NULL_QUERY "Requˆte vide"
+#define MSG_NUMVAL_NOMATCH "Disparit‚ de Numval pour %s"
+#define MSG_N_FULL_PARSES "%d significations"
+#define MSG_ODBC_READ_ONLY "ODBC est actuellement en lecture seulement"
+#define MSG_OFFSET_NOT_SUPP "Offset non support‚ pour ce type de sous requˆte"
+#define MSG_ONE_LANG_YET "Un langage est d‚j… en ‚dition"
+#define MSG_ONE_PARAM_ONLY "Un seul paramŠtre autoris‚"
+#define MSG_ONLY_LOG10_IMPL "Seul Log10 est implement‚"
+#define MSG_ON_LANGUAGE "Langage %.8s version %d niveau %d ‚ditable"
+#define MSG_OPENING "Ouverture"
+#define MSG_OPENING_QUERY "Ouverture de la requˆte"
+#define MSG_OPEN_EMPTY_FILE "Ouverture du fichier vide %s: %s"
+#define MSG_OPEN_ERROR "Erreur d'ouverture %d en mode %d sur %s: "
+#define MSG_OPEN_ERROR_IS "Erreur … l'ouverture de %s: %s"
+#define MSG_OPEN_ERROR_ON "Erreur d'ouverture sur %s"
+#define MSG_OPEN_MODE_ERROR "Erreur d'ouverture(%s) %d sur %s"
+#define MSG_OPEN_SORT_ERROR "Erreur logique de tri dans QUERY Open"
+#define MSG_OPEN_STRERROR "Erreur … l'ouverture: %s"
+#define MSG_OPEN_W_ERROR "Erreur … l'ouverture de %s en ‚criture"
+#define MSG_OPTBLK_RD_ERR "Erreur … la lecture d'un bloc optimisation: %s"
+#define MSG_OPTBLK_WR_ERR "Erreur … l'‚criture d'un bloc optimisation: %s"
+#define MSG_OPTIMIZING "Optimisation de "
+#define MSG_OPT_BMAP_RD_ERR "Erreur en lecture des bitmaps d'optimisation: %s"
+#define MSG_OPT_BMAP_WR_ERR "Erreur en ‚criture des bitmaps d'optimisation: %s"
+#define MSG_OPT_CANCELLED "Optimisation interrompue par l'utilisateur"
+#define MSG_OPT_DVAL_RD_ERR "Erreur en lecture des valeurs distinctes: %s"
+#define MSG_OPT_DVAL_WR_ERR "Erreur en ‚criture des valeurs distinctes: %s"
+#define MSG_OPT_HEAD_RD_ERR "Erreur en lecture de l'entˆte du fichier opt: %s"
+#define MSG_OPT_HEAD_WR_ERR "Erreur en ‚criture de l'entˆte du fichier opt: %s"
+#define MSG_OPT_INIT "Optimisation initialis‚e"
+#define MSG_OPT_LOGIC_ERR "Erreur logique dans SetBitmap, i=%d"
+#define MSG_OPT_MAX_RD_ERR "Erreur en lecture des valeurs maxi: %s"
+#define MSG_OPT_MAX_WR_ERR "Erreur en ‚criture des valeurs maxi: %s"
+#define MSG_OPT_MIN_RD_ERR "Erreur en lecture des valeurs mini: %s"
+#define MSG_OPT_MIN_WR_ERR "Erreur en ‚criture des valeurs mini: %s"
+#define MSG_OPT_NOT_MATCH "Le fichier opt %s n'est pas … jour"
+#define MSG_OP_RES_TOO_LONG "R‚sultat trop long pour l'op‚rateur=%d"
+#define MSG_ORDER_OUT_RANGE "Tri: Order %d hors limite"
+#define MSG_ORDER_TWICE "Un mˆme ‚l‚ment est tri‚ deux fois"
+#define MSG_PAGE_ERROR "Erreur de pagination"
+#define MSG_PARM_CNT_MISS "Disparit‚ du nombre de ParamŠtres"
+#define MSG_PARSE_NULL_SEM "S‚mantique nulle"
+#define MSG_PARSING_QUERY "Analyse de la requˆte"
+#define MSG_PIX_ERROR "Pix %s erreur rŠgle no=%u\n"
+#define MSG_PIX_TEST_ERROR "RŠgle=%u: pix-TEST pas dans le premier noeud\n"
+#define MSG_PLG_READ_ONLY "PLG est actuellement en lecture seulement"
+#define MSG_PLM_NULL_SFP "TABPLM ReadDB: Sfp est NULL"
+#define MSG_PLUG_NOT_INIT "Plug n'est pas initialis‚\n"
+#define MSG_PLUG_NOT_RUN "Plug n'est pas en marche"
+#define MSG_PNODE_RULE "(Noeud %d rŠgle %d) "
+#define MSG_POS_TOO_LONG "%s trop long (>%d)"
+#define MSG_PREC_VBLP_NULL "ARRAY SetPrecision: Vblp est NULL"
+#define MSG_PRIV_INSTR "Instruction privil‚gi‚e"
+#define MSG_PROCADD_ERROR "Erreur %d sur l'adresse de %s"
+#define MSG_PROCESS_SUBQRY "Sub-Query en cours de traitement"
+#define MSG_PROC_WOULD_LOOP "Bouclage du traitement (maxres=%d maxlin=%d)"
+#define MSG_PROGRESS_INFO "Informations sur le traitement en cours"
+#define MSG_PROMPT_CANCEL "Relance annul‚e"
+#define MSG_PROMPT_NIY "Prompt non impl‚ment‚ pour cette configuration"
+#define MSG_PTR_NOT_FOUND "Pointeur introuvable Num=%d ti1=%d"
+#define MSG_PXDEF_IS_NULL "Pxdef est NULL"
+#define MSG_QRY_READ_ONLY "Les views QRY sont en lecture seulement"
+#define MSG_QUERY_CANCELLED "Requˆte interrompue par l'utilisateur"
+#define MSG_QUERY_NOT_EXEC "Requˆte non ex‚cut‚e"
+#define MSG_QUERY_SAVED "Requˆte %s sauvegard‚e"
+#define MSG_QUOTE_IN_QUOTE "Appostrophe dans un champ entre appostrophe ligne %d"
+#define MSG_RANGE_NIY "Range pas encore impl‚ment‚ pour %s"
+#define MSG_RANGE_NO_JOIN "Range non compatible avec les index de jointure"
+#define MSG_RC_READING "rc=%d en lecture de la table %s"
+#define MSG_READB_BAD_INIT "%s ReadDB appel‚ avec Init=0"
+#define MSG_READCOL_ERROR "SQLCOL: erreur dans ReadColumn"
+#define MSG_READING "Lecture"
+#define MSG_READING_FROM "Lecture de %s"
+#define MSG_READING_RECORD "Erreur en lecture de l'enregistrement %d de %s"
+#define MSG_READY "Prˆt"
+#define MSG_READ_ERROR "Erreur en lecture sur %s: %s"
+#define MSG_READ_ERROR_RC "Erreur en lecture, rc=%d"
+#define MSG_READ_MEM_ERROR "Lecture m‚moire %d: taille=%d"
+#define MSG_READ_ONLY "Cette table prot‚g‚e en lecture seule ne peut ˆtre modifi‚e"
+#define MSG_READ_SEEK_ERROR "Erreur de recherche en lecture: %s"
+#define MSG_READ_SEG_ERROR "Lecture segment %d: taille=%d"
+#define MSG_RECEIVED "Re‡u %c\n"
+#define MSG_RECORD_ERROR "Erreur … la lecture de l'enregistrement %d de %s"
+#define MSG_RECORD_NO_SEP "Enregistrement sans s‚parateur"
+#define MSG_REC_SKIPPED " (%d lignes erronn‚es saut‚es par l'option MaxErr)"
+#define MSG_REDUCE_INDEX "Réduction de l'index"
+#define MSG_REGISTER_ERR "Enregistrement NS impossible, pr‚fix='%s' et href='%s'"
+#define MSG_REMOTE_CONN_ERR "La connection ‚loign‚e a ‚chou‚"
+#define MSG_REMOVE_ERROR "Erreur en supprimant %s: %s"
+#define MSG_REMOVE_NOT_IMPL "Remove non impl‚ment‚ pour TDB non Table"
+#define MSG_RENAME_ERROR "Erreur renommant %s en %s: %s"
+#define MSG_RENUM_RULES "Renum‚rotez les rŠgles et r‚entrez ADD (rŠgle sauvegard‚e dans la zone tampon)"
+#define MSG_REORDER_INDEX "Reclassement de l'index"
+#define MSG_REQU_ARG_NUM "La fonction %s doit avoir %d arguments"
+#define MSG_RESET_TO "%s remis … %d"
+#define MSG_RES_NOT_UNIQUE "Le r‚sultat n'est pas unique"
+#define MSG_RET_FROM_LANG "Retour au language %s version %d.%d du language %s version %d.%d"
+#define MSG_ROWID_NOT_IMPL "RowNumber non impl‚ment‚ pour les tables de type %s"
+#define MSG_ROWS_SELECTED "%d lignes s‚lectionn‚es en %.2lf sec"
+#define MSG_ROWS_TRUNCATED " (tronqu‚ par MAXRES, LIMIT, FREQ ou AreaSize)"
+#define MSG_ROW_ARGNB_ERR "ROW: disparit‚ du nombre d'arguments (%d,%d)"
+#define MSG_RPC_SERVER_ERR "Erreur logique dans TABMUL::MakeCol"
+#define MSG_RSC_ALLOC_ERROR "Erreur d'allocation m‚moire dans Rescol %s"
+#define MSG_RULE_ENTERED "RŠgle %d entr‚e"
+#define MSG_RULE_SUBSET_ERR "Erreur d'initialisation de la zone RŠgles"
+#define MSG_SAVING_INDEX "Sauvegarde du fichier index"
+#define MSG_SCAN_NOT_IMP "Scan non impl‚ment‚"
+#define MSG_SEC_KEY_FIRST "Les sections et cl‚s doivent ˆtre ins‚r‚es en premier"
+#define MSG_SEC_NAME_FIRST "Le nom de section doit ˆtre en tˆte de liste en insertion"
+#define MSG_SEC_NOT_FOUND "Section %s absente de %s"
+#define MSG_SEEK_ERROR "Seek erreur dans CopyHeader"
+#define MSG_SEMANTIC_TREE "Arbre s‚mantique"
+#define MSG_SEM_BAD_REF "Sem @%d r‚f‚rence un argument de type non 0 ou 1"
+#define MSG_SEM_UNKNOWN "inconnue, rc=%d"
+#define MSG_SEP_IN_FIELD "Le champ %d contient le caractŠre s‚parateur"
+#define MSG_SEQUENCE_ERROR "HSTMT: Allocation hors s‚quence"
+#define MSG_SETEOF_ERROR "Erreur %d dans SetEndOfFile"
+#define MSG_SETRECPOS_NIY "SetRecpos non impl‚ment‚ pour ce type de table"
+#define MSG_SET_LOCALE "Locale fix‚e … %s"
+#define MSG_SET_NULL_DOM "Valeur %d donn‚e … un domaine nul"
+#define MSG_SET_OP_NOT_IMPL "Op‚rateurs ensemblistes non impl‚ment‚s"
+#define MSG_SET_STR_TRUNC "SetValue: ChaŒne de caractŠres tronqu‚e"
+#define MSG_SEVERAL_TREES "Jointure non sp‚cifi‚e pour certaines tables"
+#define MSG_SFP_ERROR "Erreur sur SetFilePointer: %s"
+#define MSG_SFUNC_NOT_IMPL "Fonction scalaire %s non impl‚ment‚e"
+#define MSG_SHARED_LIB_ERR "Erreur au chargement de la librairie partag‚e %s: %s"
+#define MSG_SINGLE_STEP "Pas … pas"
+#define MSG_SLEEP "J'ai dormi %d milliseconds"
+#define MSG_SMART_SORTING "R‚cup‚ration des lignes tri‚es (passage %d de %d)"
+#define MSG_SMART_SORT_ERR "Erreur logique 1 dans Smart Sort"
+#define MSG_SORTING "Tri en cours"
+#define MSG_SORTING_INDEX "Tri de l'index"
+#define MSG_SORTING_VAL "Tri de %d valeurs"
+#define MSG_SORT_JOIN_INDEX "Tri de l'index de jointure"
+#define MSG_SPCOL_READONLY "La colonne sp‚ciale %s est en lecture seulement"
+#define MSG_SPEC_CMD_SEP "Les commandes sp‚ciales doivent ˆtre ex‚cut‚es s‚par‚ment"
+#define MSG_SQL_BAD_TYPE "RephraseSQL: type %d non support‚"
+#define MSG_SQL_BLOCK_MISM "CheckColumn: bloc SQL courant non correspondant"
+#define MSG_SQL_CONF_ERROR "Erreur SQL: SQL_CONFORMANCE"
+#define MSG_SQL_READ_ONLY "Les views SQL sont actuellement en lecture seulement"
+#define MSG_SRCH_CLOSE_ERR "Erreur … la fermeture de l'Handle de recherche"
+#define MSG_SRC_TABLE_UNDEF "La table source n'est pas d‚finie"
+#define MSG_STACK_ERROR "Erreur sur la pile, i=%d\n"
+#define MSG_STACK_OVERFLOW "Parser: D‚bordement de la pile\n"
+#define MSG_STRG_NOT_FOUND "ChaŒne introuvable"
+#define MSG_STRING_INV_LIST "Liste invalide pour SemString"
+#define MSG_STRING_TOO_BIG "ChaŒne trop grande pour le domaine %s"
+#define MSG_SUBALLOC_ERROR "Pas assez de m‚moire en zone %p pour allouer %d (utilis‚=%d libre=%d)"
+#define MSG_SUBAL_HUGE_ERR "Pas assez de m‚moire en zone huge %p pour allouer %d"
+#define MSG_SUBARG_NOSEM "Argument @ ou sous-phrase de niveau %d pointe sur un noeud sans Sem"
+#define MSG_SUBARG_OUTRANGE "Argument @ ou sous-phrase de niveau %d hors limite"
+#define MSG_SUBQRY_ONEITEM "Une Sub-Query ne doit avoir qu'une s‚lection"
+#define MSG_SUBSET_ERROR "SubSet erreur dans LoadDB"
+#define MSG_SUB_OPEN_YET "Subquery d‚j… ouverte"
+#define MSG_SUB_RES_TOO_LNG "R‚sultat trop long pour SUBSTR"
+#define MSG_SYNTAX_ERROR "Erreur de syntaxe"
+#define MSG_SYSTEM_ERROR "Erreur systŠme %d"
+#define MSG_S_ACCESS_DENIED "%s: accŠs non autoris‚"
+#define MSG_S_ERROR "%s erreur"
+#define MSG_S_ERROR_NUM "%s: erreur=%d"
+#define MSG_S_INTRUPT_ERROR "%s: erreur interruption"
+#define MSG_S_INVALID_PARM "%s: paramŠtre invalide"
+#define MSG_S_INV_ADDRESS "%s: adresse invalide"
+#define MSG_S_UNKNOWN_ERROR "%s: erreur de code %u inconnu"
+#define MSG_TABDIR_READONLY "Les tables DIR sont en lecture seulement"
+#define MSG_TABLE_ALREADY "La table %s existe d‚j…"
+#define MSG_TABLE_ALTERED "Table %s %s alt‚r‚e"
+#define MSG_TABLE_CREATED "%s table %s cr‚‚e"
+#define MSG_TABLE_DROPPED "Table %s supprim‚e"
+#define MSG_TABLE_MULT_JOIN "Utilisation multiple de la table %s pour jointure"
+#define MSG_TABLE_NOT_IN_DB "La table %s n'existe pas dans %s"
+#define MSG_TABLE_NOT_OPT "Table non optimisable"
+#define MSG_TABLE_NO_INDEX "La table %s n'est pas indexable"
+#define MSG_TABLE_NO_OPT "La table %s n'existe pas ou de type non optimisable"
+#define MSG_TABLE_READ_ONLY "Les tables %s sont en lecture seulement "
+#define MSG_TABMUL_READONLY "Les tables multiples sont en lecture seulement"
+#define MSG_TAB_NOT_LOADED " (certaines tables n'ont put ˆtre charg‚es)"
+#define MSG_TAB_NOT_SPEC "Table non specifi‚e"
+#define MSG_TB_VW_NOTIN_DB "Table ou view %s pas dans la base de donn‚es"
+#define MSG_TDB_NXT_NOT_NUL "Tdb.Next non NULL"
+#define MSG_TDB_USE_ERROR "Erreur, Tdbp->Use=%d"
+#define MSG_TOO_MANY_COLS "Trop de colonnes"
+#define MSG_TOO_MANY_COLTAB "Trop de colonnes dans %s (%d)"
+#define MSG_TOO_MANY_FIELDS "Trop de champs ligne %d de %s"
+#define MSG_TOO_MANY_JUMPS "Trop de niveaux de saut"
+#define MSG_TOO_MANY_KEYS "Trop de cl‚s (%d)"
+#define MSG_TOO_MANY_POS "Trop de pos_codes"
+#define MSG_TOO_MANY_TABLES "Trop de tables (%d)"
+#define MSG_TOPSEM_ERROR "Erreur inconnue dans TopSem"
+#define MSG_TO_BLK_IS_NULL "To Blk est nul"
+#define MSG_TO_FTR_NOT_NULL "Set.To_Ftr n'est pas nul"
+#define MSG_TO_PIX_NOT_NULL "Set.To_Pix n'est pas nul"
+#define MSG_TO_SEM_NOT_NULL "Set.To_Sem n'est pas nul"
+#define MSG_TRUNCATE_ERROR "Erreur en troncation: %s"
+#define MSG_TRUNC_BY_ESTIM "Tronqu‚ par l'option Estimate"
+#define MSG_TYPES_ERROR "Erreur sur Types(%d)"
+#define MSG_TYPE_CONV_ERROR "Type non convertible dans une expression"
+#define MSG_TYPE_DEF_MISM "Disparit‚ entre type et d‚finition"
+#define MSG_TYPE_MISMATCH "Cl‚ et source ne sont pas du mˆme type"
+#define MSG_TYPE_RECFM_MISM "Disparit‚ entre Type et Recfm"
+#define MSG_TYPE_TO_VERIFY "Type … v‚rifier: %d"
+#define MSG_TYPE_VALUE_ERR "Colonne %s: disparit‚ type(%s)/valeur(%s)"
+#define MSG_UNBALANCE_QUOTE "Appostrophe en trop ligne %d"
+#define MSG_UNDEFINED_AM "COLBLK %s: m‚thode d'accŠs ind‚finie"
+#define MSG_UNDEFINED_PATH "Chemin d'accŠs ind‚fini pour Plgcnx.ini"
+#define MSG_UNDEF_COL_COUNT "Count sur colonne non d‚finie"
+#define MSG_UNKNOWN_DOMAIN "Domaine inconnu %s"
+#define MSG_UNKNOWN_ERROR "Erreur inconnue"
+#define MSG_UNKNOWN_EXCPT "Exception non r‚pertori‚e"
+#define MSG_UNKNOWN_NAME "Nom inconnu: %.8s"
+#define MSG_UNKNOWN_PATH "Chemin d'accŠs inconnu pour Plgcnx.ini"
+#define MSG_UNKNOWN_POS "Nom pos_code inconnu: %s"
+#define MSG_UNKNOWN_SEM "Sem %.8s inconnue, rc=%d"
+#define MSG_UNKNOWN_SYNONYM "Synonyme inconnu"
+#define MSG_UNKNW_QRY_TYPE "ReadDB: type de requˆte inconnu"
+#define MSG_UNKN_ERR_CODE "Erreur de code %d inconnu"
+#define MSG_UNLOADABLE " inchargeable: "
+#define MSG_UNLOADABLE_PRM "%s inchargeable: %s"
+#define MSG_UNMATCH_FIL_ARG "Argument de filtre d‚pareill‚"
+#define MSG_UNQ_COL_SEV_TAB "La colonne %s non qualifi‚e est dans plusieurs tables"
+#define MSG_UNRESOLVED_ARG "?Argument manquant: %s non r‚solu en %d ligne %d"
+#define MSG_UPDATE_ERROR "Erreur en Update sur %s"
+#define MSG_UPDATING_ROWS "Mise … jour des lignes"
+#define MSG_UPD_ZIP_NOT_IMP "Mise … jour des tables ZDOS non encore implement‚"
+#define MSG_UP_LANGUAGE "Bloc langage %.8s version %d niveau %d charg‚"
+#define MSG_USED_FREE_MEM "Sarea: utilis‚ %d, libre %d"
+#define MSG_USETEMP_IS "Usetemp est : %s"
+#define MSG_USETEMP_RESET ". Usetemp remis … Auto"
+#define MSG_USETEMP_SET "Usetemp fix‚ … %s"
+#define MSG_USE_NO_MATCH "Use non correspondant : Use=%d, ti2=%d, ti3=%d"
+#define MSG_USING_INDEX " (Index‚ par"
+#define MSG_VALIST_MISMATCH "Disparit‚ des listes de valeurs"
+#define MSG_VALSTR_TOO_LONG "Valeur %s trop longue pour une chaŒne de longueur %d"
+#define MSG_VALTYPE_NOMATCH "Disparit‚ types de valeur"
+#define MSG_VALUE_ERROR "Colonne %s: bloc valeur nul"
+#define MSG_VALUE_NOT_ALLOC "Valeur non allou‚e pour la colonne R%d %s"
+#define MSG_VALUE_TOO_BIG "Valeur %lld trop grande pour la colonne %s"
+#define MSG_VALUE_TOO_LONG "Valeur %s trop longue pour la colonne %s de longueur %d"
+#define MSG_VAL_ALLOC_ERR "Allocation impossible du noeud valeur"
+#define MSG_VAL_TOO_LONG "Valeur %s trop longue pour le champ %s"
+#define MSG_VIEW_ALREADY "La VIEW %s existe d‚j…"
+#define MSG_VIEW_CREATED "%s view %s cr‚‚e"
+#define MSG_VIEW_DROPPED "View %s supprim‚e"
+#define MSG_VIEW_NOT_IN_DB "%s n'est pas une View de %s"
+#define MSG_VIR_NO_DELETE "Delete impossible sur les tables %s"
+#define MSG_VIR_READ_ONLY "Les tables virtuelles %s sont en lecture seulement"
+#define MSG_VM_LANG "Langage au format VM, non support‚"
+#define MSG_VOID_FIRST_ARG "Le premier argument ne doit pas ˆtre vide"
+#define MSG_VOID_IN_STRING "Erreur: chaŒne IN vide"
+#define MSG_VOID_ORDER_LIST "Liste de tri vide, erreur systŠme ?"
+#define MSG_VOID_POS_DICT "Dictionnaire interne du langage vide"
+#define MSG_VOID_QUERY "Requˆte vide %s"
+#define MSG_WORK_AREA "Espace de travail: %s"
+#define MSG_WORK_TOO_SMALL "Zone de travail trop petite, accroŒtre AreaSize"
+#define MSG_WRITE_ERROR "Erreur … l'‚criture de %s"
+#define MSG_WRITE_SEEK_ERR "Erreur de recherche en ‚criture: %s"
+#define MSG_WRITE_STRERROR "Erreur en ‚criture sur %s: %s"
+#define MSG_WRITING "Ecriture"
+#define MSG_WRITING_ERROR "Erreur … l'‚criture de %s: %s"
+#define MSG_WRITING_QUERY "Erreur … l'‚criture de la requˆte: "
+#define MSG_WRONG_ARG_NUM "La fonction %s ne prend pas %d arguments"
+#define MSG_WRONG_COL_NUM "Num‚ro de colonne %d trop grand pour %s"
+#define MSG_WRONG_DB_LIST "Liste des bases de donn‚es incorrecte ou vide"
+#define MSG_WRONG_FUNCTION "Mauvaise fonction %d"
+#define MSG_WRONG_OP_PARM "Mauvais op‚rateur ou paramŠtres pour %s"
+#define MSG_WRONG_PARMS "Mauvais paramŠtres pour %s"
+#define MSG_WRONG_PASSWORD "Mot de passe ill‚gal pour %s"
+#define MSG_WRONG_TYPE "type non support‚"
+#define MSG_WRONG_USERFILE "La Userfile a une mauvaise taille %d"
+#define MSG_WS_CONV_ERR "Erreur de convertion de %s en WS"
+#define MSG_XCOL_MISMATCH "La colonne %s ne correspond pas … l'index"
+#define MSG_XDB_DEL_ERROR "Erreur en supprimant des entr‚es du fichier XDB"
+#define MSG_XFILE_READERR "Erreur %d en lisant le fichier index"
+#define MSG_XFILE_TOO_SMALL "Le fichier index est plus petit que la taille de l'index"
+#define MSG_XFILE_WRITERR "Erreur en ‚crivant le fichier index: %s"
+#define MSG_XMLTAB_INIT_ERR "Erreur d'initialisation de la table XML"
+#define MSG_XML_INIT_ERROR "Erreur d'initialisation du nouveau fichier XML"
+#define MSG_XPATH_CNTX_ERR "Le nouveau contexte XPath ne peut ˆtre cr‚‚"
+#define MSG_XPATH_EVAL_ERR "Impossible d'‚valuer l'emplacement xpath '%s'"
+#define MSG_XPATH_NOT_SUPP "Xpath non support‚ colonne %s"
+#define MSG_X_ARG_ADDED "%d arguments ajout‚s"
+#define MSG_X_ARG_SET "%d arguments ont ‚t‚ initialis‚s"
+#define MSG_X_ON_TAB " %s sur %s("
+#define MSG_ZERO_DIVIDE "Division par z‚ro dans une expression"
diff --git a/storage/connect/global.h b/storage/connect/global.h
new file mode 100644
index 00000000..eb3d4106
--- /dev/null
+++ b/storage/connect/global.h
@@ -0,0 +1,230 @@
+/***********************************************************************/
+/* GLOBAL.H: Declaration file used by all CONNECT implementations. */
+/* (C) Copyright MariaDB Corporation Ab */
+/* Author Olivier Bertrand 1993-2020 */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Included C-definition files common to all Plug routines */
+/***********************************************************************/
+#include <string.h> /* String manipulation declares */
+#include <stdlib.h> /* C standard library */
+#include <ctype.h> /* C language specific types */
+#include <stdio.h> /* FOPEN_MAX declaration */
+#include <time.h> /* time_t type declaration */
+#include <setjmp.h> /* Long jump declarations */
+
+#if defined(_WIN32) && !defined(NOEX)
+#define DllExport __declspec( dllexport )
+#else // !_WIN32
+#define DllExport
+#endif // !_WIN32
+
+#if defined(DOMDOC_SUPPORT) || defined(LIBXML2_SUPPORT)
+#define XML_SUPPORT 1
+#endif
+
+#if defined(XMSG)
+//#error Option XMSG is not yet fully implemented
+// Definition used to read messages from message file.
+#include "msgid.h"
+#define MSG(I) PlugReadMessage(NULL, MSG_##I, #I)
+#define STEP(I) PlugReadMessage(g, MSG_##I, #I)
+#elif defined(NEWMSG)
+//#error Option NEWMSG is not yet fully implemented
+// Definition used to get messages from resource.
+#include "msgid.h"
+#define MSG(I) PlugGetMessage(NULL, MSG_##I)
+#define STEP(I) PlugGetMessage(g, MSG_##I)
+#else // !XMSG and !NEWMSG
+// Definition used to replace messages ID's by their definition.
+#include "messages.h"
+#define MSG(I) MSG_##I
+#define STEP(I) MSG_##I
+#endif // !XMSG and !NEWMSG
+
+#if defined(_WIN32)
+#define CRLF 2
+#else // !_WIN32
+#define CRLF 1
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Define access to the thread based trace value. */
+/***********************************************************************/
+#define trace(T) (bool)(GetTraceValue() & (uint)T)
+
+/***********************************************************************/
+/* Miscellaneous Constants */
+/***********************************************************************/
+#define NO_IVAL -95684275 /* Used by GetIntegerOption */
+#define MAX_JUMP 24 /* Maximum jump level number */
+#define MAX_STR 4160 /* Maximum message length */
+
+#define TYPE_VOID -1
+#define TYPE_ERROR 0
+#define TYPE_STRING 1
+#define TYPE_DOUBLE 2
+#define TYPE_SHORT 3
+#define TYPE_TINY 4
+#define TYPE_BIGINT 5
+#define TYPE_LIST 6
+#define TYPE_INT 7
+#define TYPE_DATE 8
+#define TYPE_DECIM 9
+#define TYPE_BIN 10
+#define TYPE_PCHAR 11
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/***********************************************************************/
+/* Static variables */
+/***********************************************************************/
+
+/***********************************************************************/
+/* File-Selection Indicators */
+/***********************************************************************/
+#define PAT_LOG "log"
+
+#if defined(UNIX) || defined(LINUX) || defined(UNIV_LINUX)
+ // printf does not accept null pointer for %s target
+ #define SVP(S) ((S) ? S : "<null>")
+#else
+ // printf accepts null pointer for %s target
+ #define SVP(S) S
+#endif
+
+#if defined(STORAGE)
+ FILE *debug;
+#else
+ extern FILE *debug;
+#endif
+
+
+/***********************************************************************/
+/* General purpose type definitions. */
+/***********************************************************************/
+#include "os.h"
+
+typedef struct {
+ ushort Length;
+ char String[2];
+ } VARSTR;
+
+#if !defined(PGLOBAL_DEFINED)
+typedef struct _global *PGLOBAL;
+#define PGLOBAL_DEFINED
+#endif
+typedef struct _globplg *PGS;
+typedef struct _activity *PACTIVITY;
+typedef struct _parm *PPARM;
+typedef char NAME[9];
+
+/***********************************************************************/
+/* Segment Sub-Allocation block structure declares. */
+/* Next block is an implementation dependent segment suballoc save */
+/* structure used to keep the suballocation system offsets and to */
+/* restore them if needed. This scheme implies that no SubFree be used */
+/***********************************************************************/
+typedef struct { /* Plug Area SubAlloc header */
+ size_t To_Free; /* Offset of next free block */
+ size_t FreeBlk; /* Size of remaining free memory */
+ } POOLHEADER, *PPOOLHEADER;
+
+/***********************************************************************/
+/* Language block. Containing all global information for the language */
+/* this block is saved and retrieved with the language. Information */
+/* in this block can be set and modified under Grammar editing. */
+/***********************************************************************/
+#if defined(BIT64)
+typedef int TIME_T; /* Lang block size must not change */
+#else // BIT32
+typedef time_t TIME_T; /* time_t */
+#endif // BIT32
+
+typedef struct {
+ uint Memsize;
+ uint Size;
+ } AREADEF;
+
+typedef struct Lang_block {
+ NAME LangName; /* Language name */
+ NAME Application; /* Application name */
+ } LANG, *PLANG;
+
+/***********************************************************************/
+/* Application block. It contains all global information for the */
+/* current parse and execution using the corresponding language. */
+/* This block is dynamically allocated and set at language init. */
+/***********************************************************************/
+typedef struct _activity { /* Describes activity and language */
+ void *Aptr; /* Points to user work area(s) */
+ NAME Ap_Name; /* Current application name */
+ } ACTIVITY;
+
+/*---------------- UNIT ?????????? VERSION ? ----------------------*/
+typedef struct _parm {
+ union {
+ void *Value;
+ int Intval;
+ }; // end union
+ short Type, Domain;
+ PPARM Next;
+ } PARM;
+
+/***********************************************************************/
+/* Global Structure Block. This block contains, or points to, all */
+/* information used by CONNECT tables. Passed as an argument */
+/* to any routine allows it to have access to the entire information */
+/* currently available for the whole set of loaded languages. */
+/***********************************************************************/
+typedef struct _global { /* Global structure */
+ void *Sarea; /* Points to work area */
+ size_t Sarea_Size; /* Work area size */
+ PACTIVITY Activityp;
+ char Message[MAX_STR]; /* Message (result, error, trace) */
+ size_t More; /* Used by jsonudf */
+ size_t Saved_Size; /* Saved work area to_free */
+ bool Createas; /* To pass multi to ext tables */
+ void *Xchk; /* indexes in create/alter */
+ short Alchecked; /* Checked for ALTER */
+ short Mrr; /* True when doing mrr */
+ int N; /* Utility */
+ int jump_level;
+ jmp_buf jumper[MAX_JUMP + 2];
+ } GLOBAL;
+
+/***********************************************************************/
+/* Exported routine declarations. */
+/***********************************************************************/
+#if defined(XMSG)
+DllExport char *PlugReadMessage(PGLOBAL, int, char *);
+#elif defined(NEWMSG)
+DllExport char *PlugGetMessage(PGLOBAL, int);
+#endif // XMSG || NEWMSG
+#if defined(_WIN32)
+DllExport short GetLineLength(PGLOBAL); // Console line length
+#endif // _WIN32
+DllExport PGLOBAL PlugInit(LPCSTR, size_t); // Plug global initialization
+DllExport PGLOBAL PlugExit(PGLOBAL); // Plug global termination
+DllExport LPSTR PlugRemoveType(LPSTR, LPCSTR);
+DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR prefix, LPCSTR name, LPCSTR dir);
+DllExport BOOL PlugIsAbsolutePath(LPCSTR path);
+DllExport bool AllocSarea(PGLOBAL, size_t);
+DllExport void FreeSarea(PGLOBAL);
+DllExport BOOL PlugSubSet(void *, size_t);
+DllExport void *PlugSubAlloc(PGLOBAL, void *, size_t);
+DllExport char *PlugDup(PGLOBAL g, const char *str);
+DllExport void htrc(char const *fmt, ...);
+DllExport void xtrc(uint, char const* fmt, ...);
+DllExport uint GetTraceValue(void);
+DllExport void* MakePtr(void* memp, size_t offset);
+DllExport size_t MakeOff(void* memp, void* ptr);
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+/*-------------------------- End of Global.H --------------------------*/
diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc
new file mode 100644
index 00000000..e95e91e1
--- /dev/null
+++ b/storage/connect/ha_connect.cc
@@ -0,0 +1,7535 @@
+/* Copyright (C) MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file ha_connect.cc
+
+ @brief
+ The ha_connect engine is a stubbed storage engine that enables to create tables
+ based on external data. Principally they are based on plain files of many
+ different types, but also on collections of such files, collection of tables,
+ local or remote MySQL/MariaDB tables retrieved via MySQL API,
+ ODBC/JDBC tables retrieving data from other DBMS having an ODBC/JDBC server,
+ and even virtual tables.
+
+ @details
+ ha_connect will let you create/open/delete tables, the created table can be
+ done specifying an already existing file, the drop table command will just
+ suppress the table definition but not the eventual data file.
+ Indexes are not supported for all table types but data can be inserted,
+ updated or deleted.
+
+ You can enable the CONNECT storage engine in your build by doing the
+ following during your build process:<br> ./configure
+ --with-connect-storage-engine
+
+ You can install the CONNECT handler as all other storage handlers.
+
+ Once this is done, MySQL will let you create tables with:<br>
+ CREATE TABLE <table name> (...) ENGINE=CONNECT;
+
+ The example storage engine does not use table locks. It
+ implements an example "SHARE" that is inserted into a hash by table
+ name. This is not used yet.
+
+ Please read the object definition in ha_connect.h before reading the rest
+ of this file.
+
+ @note
+ This MariaDB CONNECT handler is currently an adaptation of the XDB handler
+ that was written for MySQL version 4.1.2-alpha. Its overall design should
+ be enhanced in the future to meet MariaDB requirements.
+
+ @note
+ It was written also from the Brian's ha_example handler and contains parts
+ of it that are there, such as table and system variables.
+
+ @note
+ When you create an CONNECT table, the MySQL Server creates a table .frm
+ (format) file in the database directory, using the table name as the file
+ name as is customary with MySQL.
+ For file based tables, if a file name is not specified, this is an inward
+ table. An empty file is made in the current data directory that you can
+ populate later like for other engine tables. This file modified on ALTER
+ and is deleted when dropping the table.
+ If a file name is specified, this in an outward table. The specified file
+ will be used as representing the table data and will not be modified or
+ deleted on command such as ALTER or DROP.
+ To get an idea of what occurs, here is an example select that would do
+ a scan of an entire table:
+
+ @code
+ ha-connect::open
+ ha_connect::store_lock
+ ha_connect::external_lock
+ ha_connect::info
+ ha_connect::rnd_init
+ ha_connect::extra
+ ENUM HA_EXTRA_CACHE Cache record in HA_rrnd()
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::rnd_next
+ ha_connect::extra
+ ENUM HA_EXTRA_NO_CACHE End caching of records (def)
+ ha_connect::external_lock
+ ha_connect::extra
+ ENUM HA_EXTRA_RESET Reset database to after open
+ @endcode
+
+ Here you see that the connect storage engine has 9 rows called before
+ rnd_next signals that it has reached the end of its data. Calls to
+ ha_connect::extra() are hints as to what will be occuring to the request.
+
+ Author Olivier Bertrand
+ */
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#define MYSQL_SERVER 1
+#define DONT_DEFINE_VOID
+#include <my_global.h>
+#include "sql_parse.h"
+#include "sql_base.h"
+#include "sql_partition.h"
+#undef OFFSET
+
+#define NOPARSE
+#define NJDBC
+#if defined(UNIX)
+#include "osutil.h"
+#endif // UNIX
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabext.h"
+#if defined(ODBC_SUPPORT)
+#include "odbccat.h"
+#endif // ODBC_SUPPORT
+#if defined(JAVA_SUPPORT)
+#include "tabjdbc.h"
+#include "jdbconn.h"
+#endif // JAVA_SUPPORT
+#if defined(CMGO_SUPPORT)
+#include "cmgoconn.h"
+#endif // CMGO_SUPPORT
+#include "tabmysql.h"
+#include "filamdbf.h"
+#include "tabxcl.h"
+#include "tabfmt.h"
+//#include "reldef.h"
+#include "tabcol.h"
+#include "xindex.h"
+#if defined(_WIN32)
+#include <io.h>
+#include "tabwmi.h"
+#endif // _WIN32
+#include "connect.h"
+#include "user_connect.h"
+#include "ha_connect.h"
+#include "myutil.h"
+#include "preparse.h"
+#include "inihandl.h"
+#if defined(LIBXML2_SUPPORT)
+#include "libdoc.h"
+#endif // LIBXML2_SUPPORT
+#include "taboccur.h"
+#include "tabpivot.h"
+#include "tabfix.h"
+
+#define my_strupr(p) my_caseup_str(default_charset_info, (p));
+#define my_strlwr(p) my_casedn_str(default_charset_info, (p));
+#define my_stricmp(a,b) my_strcasecmp(default_charset_info, (a), (b))
+
+
+/***********************************************************************/
+/* Initialize the ha_connect static members. */
+/***********************************************************************/
+#define SZCONV 1024 // Default converted text size
+#define SZWORK 67108864 // Default work area size 64M
+#define SZWMIN 4194304 // Minimum work area size 4M
+#define JSONMAX 50 // JSON Default max grp size
+
+extern "C" {
+ char version[]= "Version 1.07.0002 March 22, 2021";
+#if defined(_WIN32)
+ char compver[]= "Version 1.07.0002 " __DATE__ " " __TIME__;
+ static char slash= '\\';
+#else // !_WIN32
+ static char slash= '/';
+#endif // !_WIN32
+} // extern "C"
+
+#if MYSQL_VERSION_ID > 100200
+#define stored_in_db stored_in_db()
+#endif // MYSQL_VERSION_ID
+
+#if defined(XMAP)
+ my_bool xmap= false;
+#endif // XMAP
+
+ulong ha_connect::num= 0;
+
+#if defined(XMSG)
+extern "C" {
+ char *msg_path;
+} // extern "C"
+#endif // XMSG
+
+#if defined(JAVA_SUPPORT)
+ char *JvmPath;
+ char *ClassPath;
+#endif // JAVA_SUPPORT
+
+pthread_mutex_t parmut;
+pthread_mutex_t usrmut;
+pthread_mutex_t tblmut;
+
+#if defined(DEVELOPMENT)
+char *GetUserVariable(PGLOBAL g, const uchar *varname);
+
+char *GetUserVariable(PGLOBAL g, const uchar *varname)
+{
+ char buf[1024];
+ bool b;
+ THD *thd= current_thd;
+ CHARSET_INFO *cs= system_charset_info;
+ String *str= NULL, tmp(buf, sizeof(buf), cs);
+ HASH uvars= thd->user_vars;
+ user_var_entry *uvar= (user_var_entry*)my_hash_search(&uvars, varname, 0);
+
+ if (uvar)
+ str= uvar->val_str(&b, &tmp, NOT_FIXED_DEC);
+
+ return str ? PlugDup(g, str->ptr()) : NULL;
+}; // end of GetUserVariable
+#endif // DEVELOPMENT
+
+/***********************************************************************/
+/* Utility functions. */
+/***********************************************************************/
+PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
+PQRYRES VirColumns(PGLOBAL g, bool info);
+PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info);
+#ifdef BSON_SUPPORT
+PQRYRES BSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info);
+#endif // BSON_SUPPORT
+PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info);
+#if defined(REST_SUPPORT)
+PQRYRES RESTColumns(PGLOBAL g, PTOS topt, char *tab, char *db, bool info);
+#endif // REST_SUPPORT
+#if defined(JAVA_SUPPORT)
+PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ url, PTOS topt, bool info);
+#endif // JAVA_SUPPORT
+int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v);
+void PushWarning(PGLOBAL g, THD *thd, int level);
+bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, PCSZ host, PCSZ db,
+ PCSZ tab, PCSZ src, int port);
+#if defined(ZIP_SUPPORT)
+bool ZipLoadFile(PGLOBAL, PCSZ, PCSZ, PCSZ, bool, bool);
+#endif // ZIP_SUPPORT
+bool ExactInfo(void);
+#if defined(CMGO_SUPPORT)
+//void mongo_init(bool);
+#endif // CMGO_SUPPORT
+USETEMP UseTemp(void);
+int GetConvSize(void);
+TYPCONV GetTypeConv(void);
+int GetDefaultDepth(void);
+int GetDefaultPrec(void);
+bool JsonAllPath(void);
+char *GetJsonNull(void);
+uint GetJsonGrpSize(void);
+char *GetJavaWrapper(void);
+#if defined(BSON_SUPPORT)
+bool Force_Bson(void);
+#endif // BSON_SUPPORT
+size_t GetWorkSize(void);
+void SetWorkSize(size_t);
+extern "C" const char *msglang(void);
+
+static void PopUser(PCONNECT xp);
+static PCONNECT GetUser(THD *thd, PCONNECT xp);
+static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp);
+
+static handler *connect_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root);
+
+static bool checkPrivileges(THD* thd, TABTYPE type, PTOS options,
+ const char* db, TABLE* table = NULL,
+ bool quick = false);
+
+static int connect_assisted_discovery(handlerton *hton, THD* thd,
+ TABLE_SHARE *table_s,
+ HA_CREATE_INFO *info);
+
+/****************************************************************************/
+/* Return str as a zero terminated string. */
+/****************************************************************************/
+static char *strz(PGLOBAL g, LEX_CSTRING &ls)
+{
+ char* str= NULL;
+
+ if (ls.str) {
+ str= (char*)PlugSubAlloc(g, NULL, ls.length + 1);
+ memcpy(str, ls.str, ls.length);
+ str[ls.length] = 0;
+ } // endif str
+
+ return str;
+} // end of strz
+
+/***********************************************************************/
+/* CONNECT session variables definitions. */
+/***********************************************************************/
+// Tracing: 0 no, 1 yes, 2 more, 4 index... 511 all
+const char *xtrace_names[] =
+{
+ "YES", "MORE", "INDEX", "MEMORY", "SUBALLOC",
+ "QUERY", "STMT", "HANDLER", "BLOCK", "MONGO", NullS
+};
+
+TYPELIB xtrace_typelib =
+{
+ array_elements(xtrace_names) - 1, "xtrace_typelib",
+ xtrace_names, NULL
+};
+
+static MYSQL_THDVAR_SET(
+ xtrace, // name
+ PLUGIN_VAR_RQCMDARG, // opt
+ "Trace values.", // comment
+ NULL, // check
+ NULL, // update function
+ 0, // def (NO)
+ &xtrace_typelib); // typelib
+
+// Getting exact info values
+static MYSQL_THDVAR_BOOL(exact_info, PLUGIN_VAR_RQCMDARG,
+ "Getting exact info values",
+ NULL, NULL, 0);
+
+// Enabling cond_push
+static MYSQL_THDVAR_BOOL(cond_push, PLUGIN_VAR_RQCMDARG,
+ "Enabling cond_push",
+ NULL, NULL, 1); // YES by default
+
+/**
+ Temporary file usage:
+ no: Not using temporary file
+ auto: Using temporary file when needed
+ yes: Allways using temporary file
+ force: Force using temporary file (no MAP)
+ test: Reserved
+*/
+const char *usetemp_names[]=
+{
+ "NO", "AUTO", "YES", "FORCE", "TEST", NullS
+};
+
+TYPELIB usetemp_typelib=
+{
+ array_elements(usetemp_names) - 1, "usetemp_typelib",
+ usetemp_names, NULL
+};
+
+static MYSQL_THDVAR_ENUM(
+ use_tempfile, // name
+ PLUGIN_VAR_RQCMDARG, // opt
+ "Temporary file use.", // comment
+ NULL, // check
+ NULL, // update function
+ 1, // def (AUTO)
+ &usetemp_typelib); // typelib
+
+#ifdef _WIN64
+// Size used for g->Sarea_Size
+static MYSQL_THDVAR_ULONGLONG(work_size,
+ PLUGIN_VAR_RQCMDARG,
+ "Size of the CONNECT work area.",
+ NULL, NULL, SZWORK, SZWMIN, ULONGLONG_MAX, 1);
+#else
+// Size used for g->Sarea_Size
+static MYSQL_THDVAR_ULONG(work_size,
+ PLUGIN_VAR_RQCMDARG,
+ "Size of the CONNECT work area.",
+ NULL, NULL, SZWORK, SZWMIN, ULONG_MAX, 1);
+#endif
+
+// Size used when converting TEXT columns to VARCHAR
+static MYSQL_THDVAR_INT(conv_size,
+ PLUGIN_VAR_RQCMDARG, // opt
+ "Size used when converting TEXT columns.",
+ NULL, NULL, SZCONV, 0, 65500, 1);
+
+/**
+ Type conversion:
+ no: Unsupported types -> TYPE_ERROR
+ yes: TEXT -> VARCHAR
+ force: Do it also for ODBC BINARY and BLOBs
+ skip: skip unsupported type columns in Discovery
+*/
+const char *xconv_names[]=
+{
+ "NO", "YES", "FORCE", "SKIP", NullS
+};
+
+TYPELIB xconv_typelib=
+{
+ array_elements(xconv_names) - 1, "xconv_typelib",
+ xconv_names, NULL
+};
+
+static MYSQL_THDVAR_ENUM(
+ type_conv, // name
+ PLUGIN_VAR_RQCMDARG, // opt
+ "Unsupported types conversion.", // comment
+ NULL, // check
+ NULL, // update function
+ 1, // def (yes)
+ &xconv_typelib); // typelib
+
+// Adding JPATH to all Json table columns
+static MYSQL_THDVAR_BOOL(json_all_path, PLUGIN_VAR_RQCMDARG,
+ "Adding JPATH to all Json table columns",
+ NULL, NULL, 1); // YES by default
+
+// Null representation for JSON values
+static MYSQL_THDVAR_STR(json_null,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Representation of Json null values",
+ // check_json_null, update_json_null,
+ NULL, NULL, "<null>");
+
+// Default Json, XML or Mongo depth
+static MYSQL_THDVAR_INT(default_depth,
+ PLUGIN_VAR_RQCMDARG,
+ "Default depth used by Json, XML and Mongo discovery",
+ NULL, NULL, 5, -1, 16, 1); // Defaults to 5
+
+// Default precision for doubles
+static MYSQL_THDVAR_INT(default_prec,
+ PLUGIN_VAR_RQCMDARG,
+ "Default precision used for doubles",
+ NULL, NULL, 6, 0, 16, 1); // Defaults to 6
+
+// Estimate max number of rows for JSON aggregate functions
+static MYSQL_THDVAR_UINT(json_grp_size,
+ PLUGIN_VAR_RQCMDARG, // opt
+ "max number of rows for JSON aggregate functions.",
+ NULL, NULL, JSONMAX, 1, INT_MAX, 1);
+
+#if defined(JAVA_SUPPORT)
+// Default java wrapper to use with JDBC tables
+static MYSQL_THDVAR_STR(java_wrapper,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Java wrapper class name",
+ // check_java_wrapper, update_java_wrapper,
+ NULL, NULL, "wrappers/JdbcInterface");
+#endif // JAVA_SUPPORT
+
+// This is apparently not acceptable for a plugin so it is undocumented
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+// Enabling MONGO table type
+#if defined(MONGO_SUPPORT) || (MYSQL_VERSION_ID > 100200)
+static MYSQL_THDVAR_BOOL(enable_mongo, PLUGIN_VAR_RQCMDARG,
+ "Enabling the MongoDB access", NULL, NULL, 1);
+#else // !version 2,3
+static MYSQL_THDVAR_BOOL(enable_mongo, PLUGIN_VAR_RQCMDARG,
+ "Enabling the MongoDB access", NULL, NULL, 0);
+#endif // !version 2,3
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
+
+#if defined(BSON_SUPPORT)
+// Force using BSON for JSON tables
+static MYSQL_THDVAR_BOOL(force_bson, PLUGIN_VAR_RQCMDARG,
+ "Force using BSON for JSON tables",
+ NULL, NULL, 0); // NO by default
+#endif // BSON_SUPPORT
+
+#if defined(XMSG) || defined(NEWMSG)
+const char *language_names[]=
+{
+ "default", "english", "french", NullS
+};
+
+TYPELIB language_typelib=
+{
+ array_elements(language_names) - 1, "language_typelib",
+ language_names, NULL
+};
+
+static MYSQL_THDVAR_ENUM(
+ msg_lang, // name
+ PLUGIN_VAR_RQCMDARG, // opt
+ "Message language", // comment
+ NULL, // check
+ NULL, // update
+ 1, // def (ENGLISH)
+ &language_typelib); // typelib
+#endif // XMSG || NEWMSG
+
+/***********************************************************************/
+/* The CONNECT handlerton object. */
+/***********************************************************************/
+handlerton *connect_hton= NULL;
+
+/***********************************************************************/
+/* Function to export session variable values to other source files. */
+/***********************************************************************/
+uint GetTraceValue(void)
+ {return (uint)(connect_hton ? THDVAR(current_thd, xtrace) : 0);}
+bool ExactInfo(void) {return THDVAR(current_thd, exact_info);}
+static bool CondPushEnabled(void) {return THDVAR(current_thd, cond_push);}
+bool JsonAllPath(void) {return THDVAR(current_thd, json_all_path);}
+USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);}
+int GetConvSize(void) {return THDVAR(current_thd, conv_size);}
+TYPCONV GetTypeConv(void) {return (TYPCONV)THDVAR(current_thd, type_conv);}
+char *GetJsonNull(void)
+ {return connect_hton ? THDVAR(current_thd, json_null) : NULL;}
+int GetDefaultDepth(void) {return THDVAR(current_thd, default_depth);}
+int GetDefaultPrec(void) {return THDVAR(current_thd, default_prec);}
+uint GetJsonGrpSize(void)
+ {return connect_hton ? THDVAR(current_thd, json_grp_size) : 50;}
+size_t GetWorkSize(void) {return (size_t)THDVAR(current_thd, work_size);}
+void SetWorkSize(size_t)
+{
+ // Changing the session variable value seems to be impossible here
+ // and should be done in a check function
+ push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0,
+ "Work size too big, try setting a smaller value");
+} // end of SetWorkSize
+
+#if defined(JAVA_SUPPORT)
+char *GetJavaWrapper(void)
+{return connect_hton ? THDVAR(current_thd, java_wrapper)
+ : (char*)"wrappers/JdbcInterface";}
+#endif // JAVA_SUPPORT
+
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+bool MongoEnabled(void) {return THDVAR(current_thd, enable_mongo);}
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
+
+#if defined(BSON_SUPPORT)
+bool Force_Bson(void) {return THDVAR(current_thd, force_bson);}
+#endif // BSON_SUPPORT)
+
+#if defined(XMSG) || defined(NEWMSG)
+extern "C" const char *msglang(void)
+ {return language_names[THDVAR(current_thd, msg_lang)];}
+#else // !XMSG && !NEWMSG
+extern "C" const char *msglang(void)
+{
+#if defined(FRENCH)
+ return "french";
+#else // DEFAULT
+ return "english";
+#endif // DEFAULT
+} // end of msglang
+#endif // !XMSG && !NEWMSG
+
+#if 0
+/***********************************************************************/
+/* Global variables update functions. */
+/***********************************************************************/
+static void update_connect_zconv(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ zconv= *(int *)var_ptr= *(int *)save;
+} // end of update_connect_zconv
+
+static void update_connect_xconv(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ xconv= (int)(*(ulong *)var_ptr= *(ulong *)save);
+} // end of update_connect_xconv
+
+#if defined(XMAP)
+static void update_connect_xmap(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ xmap= (my_bool)(*(my_bool *)var_ptr= *(my_bool *)save);
+} // end of update_connect_xmap
+#endif // XMAP
+#endif // 0
+
+#if 0 // (was XMSG) Unuseful because not called for default value
+static void update_msg_path(MYSQL_THD thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ char *value= *(char**)save;
+ char *old= *(char**)var_ptr;
+
+ if (value)
+ *(char**)var_ptr= my_strdup(value, MYF(0));
+ else
+ *(char**)var_ptr= 0;
+
+ my_free(old);
+} // end of update_msg_path
+
+static int check_msg_path (MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *save, struct st_mysql_value *value)
+{
+ const char *path;
+ char buff[512];
+ int len= sizeof(buff);
+
+ path= value->val_str(value, buff, &len);
+
+ if (path && *path != '*') {
+ /* Save a pointer to the name in the
+ 'file_format_name_map' constant array. */
+ *(char**)save= my_strdup(path, MYF(0));
+ return(0);
+ } else {
+ push_warning_printf(thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_ARGUMENTS,
+ "CONNECT: invalid message path");
+ } // endif path
+
+ *(char**)save= NULL;
+ return(1);
+} // end of check_msg_path
+#endif // 0
+
+/**
+ CREATE TABLE option list (table options)
+
+ These can be specified in the CREATE TABLE:
+ CREATE TABLE ( ... ) {...here...}
+*/
+ha_create_table_option connect_table_option_list[]=
+{
+ HA_TOPTION_STRING("TABLE_TYPE", type),
+ HA_TOPTION_STRING("FILE_NAME", filename),
+ HA_TOPTION_STRING("XFILE_NAME", optname),
+//HA_TOPTION_STRING("CONNECT_STRING", connect),
+ HA_TOPTION_STRING("TABNAME", tabname),
+ HA_TOPTION_STRING("TABLE_LIST", tablist),
+ HA_TOPTION_STRING("DBNAME", dbname),
+ HA_TOPTION_STRING("SEP_CHAR", separator),
+ HA_TOPTION_STRING("QCHAR", qchar),
+ HA_TOPTION_STRING("MODULE", module),
+ HA_TOPTION_STRING("SUBTYPE", subtype),
+ HA_TOPTION_STRING("CATFUNC", catfunc),
+ HA_TOPTION_STRING("SRCDEF", srcdef),
+ HA_TOPTION_STRING("COLIST", colist),
+ HA_TOPTION_STRING("FILTER", filter),
+ HA_TOPTION_STRING("OPTION_LIST", oplist),
+ HA_TOPTION_STRING("DATA_CHARSET", data_charset),
+ HA_TOPTION_STRING("HTTP", http),
+ HA_TOPTION_STRING("URI", uri),
+ HA_TOPTION_NUMBER("LRECL", lrecl, 0, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("BLOCK_SIZE", elements, 0, 0, INT_MAX32, 1),
+//HA_TOPTION_NUMBER("ESTIMATE", estimate, 0, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("MULTIPLE", multiple, 0, 0, 3, 1),
+ HA_TOPTION_NUMBER("HEADER", header, 0, 0, 3, 1),
+ HA_TOPTION_NUMBER("QUOTED", quoted, (ulonglong) -1, 0, 3, 1),
+ HA_TOPTION_NUMBER("ENDING", ending, (ulonglong) -1, 0, INT_MAX32, 1),
+ HA_TOPTION_NUMBER("COMPRESS", compressed, 0, 0, 2, 1),
+ HA_TOPTION_BOOL("MAPPED", mapped, 0),
+ HA_TOPTION_BOOL("HUGE", huge, 0),
+ HA_TOPTION_BOOL("SPLIT", split, 0),
+ HA_TOPTION_BOOL("READONLY", readonly, 0),
+ HA_TOPTION_BOOL("SEPINDEX", sepindex, 0),
+ HA_TOPTION_BOOL("ZIPPED", zipped, 0),
+ HA_TOPTION_END
+};
+
+
+/**
+ CREATE TABLE option list (field options)
+
+ These can be specified in the CREATE TABLE per field:
+ CREATE TABLE ( field ... {...here...}, ... )
+*/
+ha_create_table_option connect_field_option_list[]=
+{
+ HA_FOPTION_NUMBER("FLAG", offset, (ulonglong) -1, 0, INT_MAX32, 1),
+ HA_FOPTION_NUMBER("MAX_DIST", freq, 0, 0, INT_MAX32, 1), // BLK_INDX
+ HA_FOPTION_NUMBER("FIELD_LENGTH", fldlen, 0, 0, INT_MAX32, 1),
+ HA_FOPTION_STRING("DATE_FORMAT", dateformat),
+ HA_FOPTION_STRING("FIELD_FORMAT", fieldformat),
+ HA_FOPTION_STRING("JPATH", jsonpath),
+ HA_FOPTION_STRING("XPATH", xmlpath),
+ HA_FOPTION_STRING("SPECIAL", special),
+ HA_FOPTION_ENUM("DISTRIB", opt, "scattered,clustered,sorted", 0),
+ HA_FOPTION_END
+};
+
+/*
+ CREATE TABLE option list (index options)
+
+ These can be specified in the CREATE TABLE per index:
+ CREATE TABLE ( field ..., .., INDEX .... *here*, ... )
+*/
+ha_create_table_option connect_index_option_list[]=
+{
+ HA_IOPTION_BOOL("DYNAM", dynamic, 0),
+ HA_IOPTION_BOOL("MAPPED", mapped, 0),
+ HA_IOPTION_END
+};
+
+/***********************************************************************/
+/* Push G->Message as a MySQL warning. */
+/***********************************************************************/
+bool PushWarning(PGLOBAL g, PTDB tdbp, int level)
+{
+ PHC phc;
+ THD *thd;
+ MYCAT *cat= (MYCAT*)tdbp->GetDef()->GetCat();
+
+ if (!cat || !(phc= cat->GetHandler()) || !phc->GetTable() ||
+ !(thd= (phc->GetTable())->in_use))
+ return true;
+
+ PushWarning(g, thd, level);
+ return false;
+} // end of PushWarning
+
+void PushWarning(PGLOBAL g, THD *thd, int level)
+ {
+ if (thd) {
+ Sql_condition::enum_warning_level wlvl;
+
+ wlvl= (Sql_condition::enum_warning_level)level;
+ push_warning(thd, wlvl, 0, g->Message);
+ } else
+ htrc("%s\n", g->Message);
+
+ } // end of PushWarning
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key con_key_mutex_CONNECT_SHARE_mutex;
+
+static PSI_mutex_info all_connect_mutexes[]=
+{
+ { &con_key_mutex_CONNECT_SHARE_mutex, "CONNECT_SHARE::mutex", 0}
+};
+
+static void init_connect_psi_keys()
+{
+ const char* category= "connect";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_connect_mutexes);
+ PSI_server->register_mutex(category, all_connect_mutexes, count);
+}
+#else
+static void init_connect_psi_keys() {}
+#endif
+
+
+DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir)
+{
+ const char *res= PlugSetPath(to, mysql_data_home, name, dir);
+ return res;
+}
+
+
+/**
+ @brief
+ If frm_error() is called then we will use this to determine
+ the file extensions that exist for the storage engine. This is also
+ used by the default rename_table and delete_table method in
+ handler.cc.
+
+ For engines that have two file name extensions (separate meta/index file
+ and data file), the order of elements is relevant. First element of engine
+ file name extensions array should be meta/index file extension. Second
+ element - data file extension. This order is assumed by
+ prepare_for_repair() when REPAIR TABLE ... USE_FRM is issued.
+
+ @see
+ rename_table method in handler.cc and
+ delete_table method in handler.cc
+*/
+static const char *ha_connect_exts[]= {
+ ".dos", ".fix", ".csv", ".bin", ".fmt", ".dbf", ".xml", ".json", ".ini",
+ ".vec", ".dnx", ".fnx", ".bnx", ".vnx", ".dbx", ".dop", ".fop", ".bop",
+ ".vop", NULL};
+
+/**
+ @brief
+ Plugin initialization
+*/
+static int connect_init_func(void *p)
+{
+ DBUG_ENTER("connect_init_func");
+
+// added from Sergei mail
+#if 0 // (defined(LINUX))
+ Dl_info dl_info;
+ if (dladdr(&connect_hton, &dl_info))
+ {
+ if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0)
+ {
+ sql_print_information("CONNECT: dlopen() failed, OEM table type is not supported");
+ sql_print_information("CONNECT: %s", dlerror());
+ }
+ }
+ else
+ {
+ sql_print_information("CONNECT: dladdr() failed, OEM table type is not supported");
+ sql_print_information("CONNECT: %s", dlerror());
+ }
+#endif // 0 (LINUX)
+
+#if defined(_WIN32)
+ sql_print_information("CONNECT: %s", compver);
+#else // !_WIN32
+ sql_print_information("CONNECT: %s", version);
+#endif // !_WIN32
+ pthread_mutex_init(&parmut, NULL);
+ pthread_mutex_init(&usrmut, NULL);
+ pthread_mutex_init(&tblmut, NULL);
+
+#if defined(LIBXML2_SUPPORT)
+ XmlInitParserLib();
+#endif // LIBXML2_SUPPORT
+
+#if 0 //defined(CMGO_SUPPORT)
+ mongo_init(true);
+#endif // CMGO_SUPPORT
+
+ init_connect_psi_keys();
+
+ connect_hton= (handlerton *)p;
+ connect_hton->create= connect_create_handler;
+ connect_hton->flags= HTON_TEMPORARY_NOT_SUPPORTED;
+ connect_hton->table_options= connect_table_option_list;
+ connect_hton->field_options= connect_field_option_list;
+ connect_hton->index_options= connect_index_option_list;
+ connect_hton->tablefile_extensions= ha_connect_exts;
+ connect_hton->discover_table_structure= connect_assisted_discovery;
+
+ if (trace(128))
+ sql_print_information("connect_init: hton=%p", p);
+
+ DTVAL::SetTimeShift(); // Initialize time zone shift once for all
+ BINCOL::SetEndian(); // Initialize host endian setting
+#if defined(JAVA_SUPPORT)
+ JAVAConn::SetJVM();
+#endif // JAVA_SUPPORT
+ DBUG_RETURN(0);
+} // end of connect_init_func
+
+
+/**
+ @brief
+ Plugin clean up
+*/
+int connect_done_func(void *)
+{
+ int error= 0;
+ PCONNECT pc, pn;
+ DBUG_ENTER("connect_done_func");
+
+#ifdef LIBXML2_SUPPORT
+ XmlCleanupParserLib();
+#endif // LIBXML2_SUPPORT
+
+#if defined(CMGO_SUPPORT)
+ CMgoConn::mongo_init(false);
+#endif // CMGO_SUPPORT
+
+#ifdef JAVA_SUPPORT
+ JAVAConn::ResetJVM();
+#endif // JAVA_SUPPORT
+
+#if !defined(_WIN32)
+ PROFILE_End();
+#endif // !_WIN32
+
+ pthread_mutex_lock(&usrmut);
+ for (pc= user_connect::to_users; pc; pc= pn) {
+ if (pc->g)
+ PlugCleanup(pc->g, true);
+
+ pn= pc->next;
+ delete pc;
+ } // endfor pc
+
+ pthread_mutex_unlock(&usrmut);
+
+ pthread_mutex_destroy(&usrmut);
+ pthread_mutex_destroy(&parmut);
+ pthread_mutex_destroy(&tblmut);
+ connect_hton= NULL;
+ DBUG_RETURN(error);
+} // end of connect_done_func
+
+
+/**
+ @brief
+ Example of simple lock controls. The "share" it creates is a
+ structure we will pass to each CONNECT handler. Do you have to have
+ one of these? Well, you have pieces that are used for locking, and
+ they are needed to function.
+*/
+
+CONNECT_SHARE *ha_connect::get_share()
+{
+ CONNECT_SHARE *tmp_share;
+
+ lock_shared_ha_data();
+
+ if (!(tmp_share= static_cast<CONNECT_SHARE*>(get_ha_share_ptr()))) {
+ tmp_share= new CONNECT_SHARE;
+ if (!tmp_share)
+ goto err;
+ mysql_mutex_init(con_key_mutex_CONNECT_SHARE_mutex,
+ &tmp_share->mutex, MY_MUTEX_INIT_FAST);
+ set_ha_share_ptr(static_cast<Handler_share*>(tmp_share));
+ } // endif tmp_share
+
+ err:
+ unlock_shared_ha_data();
+ return tmp_share;
+} // end of get_share
+
+
+static handler* connect_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
+{
+ handler *h= new (mem_root) ha_connect(hton, table);
+
+ if (trace(128))
+ htrc("New CONNECT %p, table: %.*s\n", h,
+ table ? table->table_name.length : 6,
+ table ? table->table_name.str : "<null>");
+
+ return h;
+} // end of connect_create_handler
+
+/****************************************************************************/
+/* ha_connect constructor. */
+/****************************************************************************/
+ha_connect::ha_connect(handlerton *hton, TABLE_SHARE *table_arg)
+ :handler(hton, table_arg)
+{
+ hnum= ++num;
+ xp= (table) ? GetUser(ha_thd(), NULL) : NULL;
+ if (xp)
+ xp->SetHandler(this);
+#if defined(_WIN32)
+ datapath= ".\\";
+#else // !_WIN32
+ datapath= "./";
+#endif // !_WIN32
+ tdbp= NULL;
+ sdvalin1= sdvalin2= sdvalin3= sdvalin4= NULL;
+ sdvalout= NULL;
+ xmod= MODE_ANY;
+ istable= false;
+ memset(partname, 0, sizeof(partname));
+ bzero((char*) &xinfo, sizeof(XINFO));
+ valid_info= false;
+ valid_query_id= 0;
+ creat_query_id= (table && table->in_use) ? table->in_use->query_id : 0;
+ stop= false;
+ alter= false;
+ mrr= false;
+ nox= true;
+ abort= false;
+ indexing= -1;
+ locked= 0;
+ part_id= NULL;
+ data_file_name= NULL;
+ index_file_name= NULL;
+ enable_activate_all_index= 0;
+ int_table_flags= (HA_NO_TRANSACTIONS | HA_NO_PREFIX_CHAR_KEYS);
+ ref_length= sizeof(int);
+ share= NULL;
+ tshp= NULL;
+} // end of ha_connect constructor
+
+
+/****************************************************************************/
+/* ha_connect destructor. */
+/****************************************************************************/
+ha_connect::~ha_connect(void)
+{
+ if (trace(128))
+ htrc("Delete CONNECT %p, table: %.*s, xp=%p count=%d\n", this,
+ table ? table->s->table_name.length : 6,
+ table ? table->s->table_name.str : "<null>",
+ xp, xp ? xp->count : 0);
+
+ PopUser(xp);
+} // end of ha_connect destructor
+
+
+/****************************************************************************/
+/* Check whether this user can be removed. */
+/****************************************************************************/
+static void PopUser(PCONNECT xp)
+{
+ if (xp) {
+ pthread_mutex_lock(&usrmut);
+ xp->count--;
+
+ if (!xp->count) {
+ PCONNECT p;
+
+ for (p= user_connect::to_users; p; p= p->next)
+ if (p == xp)
+ break;
+
+ if (p) {
+ if (p->next)
+ p->next->previous= p->previous;
+
+ if (p->previous)
+ p->previous->next= p->next;
+ else
+ user_connect::to_users= p->next;
+
+ } // endif p
+
+ PlugCleanup(xp->g, true);
+ delete xp;
+ } // endif count
+
+ pthread_mutex_unlock(&usrmut);
+ } // endif xp
+
+} // end of PopUser
+
+
+/****************************************************************************/
+/* Get a pointer to the user of this handler. */
+/****************************************************************************/
+static PCONNECT GetUser(THD *thd, PCONNECT xp)
+{
+ if (!thd)
+ return NULL;
+
+ if (xp) {
+ if (thd == xp->thdp)
+ return xp;
+
+ PopUser(xp); // Avoid memory leak
+ } // endif xp
+
+ pthread_mutex_lock(&usrmut);
+
+ for (xp= user_connect::to_users; xp; xp= xp->next)
+ if (thd == xp->thdp)
+ break;
+
+ if (xp)
+ xp->count++;
+
+ pthread_mutex_unlock(&usrmut);
+
+ if (!xp) {
+ xp= new user_connect(thd);
+
+ if (xp->user_init()) {
+ delete xp;
+ xp= NULL;
+ } // endif user_init
+
+ } // endif xp
+
+ //} else
+ // xp->count++;
+
+ return xp;
+} // end of GetUser
+
+/****************************************************************************/
+/* Get the global pointer of the user of this handler. */
+/****************************************************************************/
+static PGLOBAL GetPlug(THD *thd, PCONNECT& lxp)
+{
+ lxp= GetUser(thd, lxp);
+ return (lxp) ? lxp->g : NULL;
+} // end of GetPlug
+
+/****************************************************************************/
+/* Get the implied table type. */
+/****************************************************************************/
+TABTYPE ha_connect::GetRealType(PTOS pos)
+{
+ TABTYPE type= TAB_UNDEF;
+
+ if (pos || (pos= GetTableOptionStruct())) {
+ type= GetTypeID(pos->type);
+
+ if (type == TAB_UNDEF && !pos->http)
+ type= pos->srcdef ? TAB_MYSQL : pos->tabname ? TAB_PRX : TAB_DOS;
+#if defined(REST_SUPPORT)
+ else if (pos->http)
+ switch (type) {
+ case TAB_JSON:
+ case TAB_XML:
+ case TAB_CSV:
+ case TAB_UNDEF:
+ type = TAB_REST;
+ break;
+ case TAB_REST:
+ type = TAB_NIY;
+ break;
+ default:
+ break;
+ } // endswitch type
+#endif // REST_SUPPORT
+
+ } // endif pos
+
+ return type;
+} // end of GetRealType
+
+/** @brief
+ The name of the index type that will be used for display.
+ Don't implement this method unless you really have indexes.
+ */
+const char *ha_connect::index_type(uint inx)
+{
+ switch (GetIndexType(GetRealType())) {
+ case 1:
+ if (table_share)
+ return (GetIndexOption(&table_share->key_info[inx], "Dynamic"))
+ ? "KINDEX" : "XINDEX";
+ else
+ return "XINDEX";
+
+ case 2: return "REMOTE";
+ case 3: return "VIRTUAL";
+ } // endswitch
+
+ return "Unknown";
+} // end of index_type
+
+/** @brief
+ This is a bitmap of flags that indicates how the storage engine
+ implements indexes. The current index flags are documented in
+ handler.h. If you do not implement indexes, just return zero here.
+
+ @details
+ part is the key part to check. First key part is 0.
+ If all_parts is set, MySQL wants to know the flags for the combined
+ index, up to and including 'part'.
+*/
+//ong ha_connect::index_flags(uint inx, uint part, bool all_parts) const
+ulong ha_connect::index_flags(uint, uint, bool) const
+{
+ ulong flags= HA_READ_NEXT | HA_READ_RANGE |
+ HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR;
+ ha_connect *hp= (ha_connect*)this;
+ PTOS pos= hp->GetTableOptionStruct();
+
+ if (pos) {
+ TABTYPE type= hp->GetRealType(pos);
+
+ switch (GetIndexType(type)) {
+ case 1: flags|= (HA_READ_ORDER | HA_READ_PREV); break;
+ case 2: flags|= HA_READ_AFTER_KEY; break;
+ } // endswitch
+
+ } // endif pos
+
+ return flags;
+} // end of index_flags
+
+/** @brief
+ This is a list of flags that indicate what functionality the storage
+ engine implements. The current table flags are documented in handler.h
+*/
+ulonglong ha_connect::table_flags() const
+{
+ ulonglong flags= HA_CAN_VIRTUAL_COLUMNS | HA_REC_NOT_IN_SEQ |
+ HA_NO_AUTO_INCREMENT | HA_NO_PREFIX_CHAR_KEYS |
+ HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
+ HA_PARTIAL_COLUMN_READ | HA_FILE_BASED |
+// HA_NULL_IN_KEY | not implemented yet
+// HA_FAST_KEY_READ | causes error when sorting (???)
+ HA_NO_TRANSACTIONS | HA_DUPLICATE_KEY_NOT_IN_ORDER |
+ HA_NO_BLOBS | HA_MUST_USE_TABLE_CONDITION_PUSHDOWN |
+ HA_REUSES_FILE_NAMES;
+ ha_connect *hp= (ha_connect*)this;
+ PTOS pos= hp->GetTableOptionStruct();
+
+ if (pos) {
+ TABTYPE type= hp->GetRealType(pos);
+
+ if (IsFileType(type))
+ flags|= HA_FILE_BASED;
+
+ if (IsExactType(type))
+ flags|= (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT);
+
+ // No data change on ALTER for outward tables
+ if (!IsFileType(type) || hp->FileExists(pos->filename, true))
+ flags|= HA_NO_COPY_ON_ALTER;
+
+ } // endif pos
+
+ return flags;
+} // end of table_flags
+
+/****************************************************************************/
+/* Return the value of an option specified in an option list. */
+/****************************************************************************/
+PCSZ GetListOption(PGLOBAL g, PCSZ opname, PCSZ oplist, PCSZ def)
+{
+ if (!oplist)
+ return (char*)def;
+
+ char key[16], val[256];
+ char *pv, *pn, *pk= (char*)oplist;
+ PCSZ opval= def;
+ int n;
+
+ while (*pk == ' ')
+ pk++;
+
+ for (; pk; pk= pn) {
+ pn= strchr(pk, ',');
+ pv= strchr(pk, '=');
+
+ if (pv && (!pn || pv < pn)) {
+ n= MY_MIN(static_cast<size_t>(pv - pk), sizeof(key) - 1);
+ memcpy(key, pk, n);
+
+ while (n && key[n - 1] == ' ')
+ n--;
+
+ key[n]= 0;
+
+ while (*(++pv) == ' ');
+
+ n= MY_MIN((pn ? pn - pv : strlen(pv)), sizeof(val) - 1);
+ memcpy(val, pv, n);
+
+ while (n && val[n - 1] == ' ')
+ n--;
+
+ val[n]= 0;
+ } else {
+ n= MY_MIN((pn ? pn - pk : strlen(pk)), sizeof(key) - 1);
+ memcpy(key, pk, n);
+
+ while (n && key[n - 1] == ' ')
+ n--;
+
+ key[n]= 0;
+ val[0]= 0;
+ } // endif pv
+
+ if (!stricmp(opname, key)) {
+ opval= PlugDup(g, val);
+ break;
+ } else if (!pn)
+ break;
+
+ while (*(++pn) == ' ');
+ } // endfor pk
+
+ return opval;
+} // end of GetListOption
+
+/****************************************************************************/
+/* Return the value of a string option or NULL if not specified. */
+/****************************************************************************/
+PCSZ GetStringTableOption(PGLOBAL g, PTOS options, PCSZ opname, PCSZ sdef)
+{
+ PCSZ opval= NULL;
+
+ if (!options)
+ return sdef;
+ else if (!stricmp(opname, "Type"))
+ opval= options->type;
+ else if (!stricmp(opname, "Filename"))
+ opval= options->filename;
+ else if (!stricmp(opname, "Optname"))
+ opval= options->optname;
+ else if (!stricmp(opname, "Tabname"))
+ opval= options->tabname;
+ else if (!stricmp(opname, "Tablist"))
+ opval= options->tablist;
+ else if (!stricmp(opname, "Database") ||
+ !stricmp(opname, "DBname"))
+ opval= options->dbname;
+ else if (!stricmp(opname, "Separator"))
+ opval= options->separator;
+ else if (!stricmp(opname, "Qchar"))
+ opval= options->qchar;
+ else if (!stricmp(opname, "Module"))
+ opval= options->module;
+ else if (!stricmp(opname, "Subtype"))
+ opval= options->subtype;
+ else if (!stricmp(opname, "Catfunc"))
+ opval= options->catfunc;
+ else if (!stricmp(opname, "Srcdef"))
+ opval= options->srcdef;
+ else if (!stricmp(opname, "Colist"))
+ opval= options->colist;
+ else if (!stricmp(opname, "Filter"))
+ opval= options->filter;
+ else if (!stricmp(opname, "Data_charset"))
+ opval= options->data_charset;
+ else if (!stricmp(opname, "Http") || !stricmp(opname, "URL"))
+ opval= options->http;
+ else if (!stricmp(opname, "Uri"))
+ opval= options->uri;
+
+ if (!opval && options->oplist)
+ opval= GetListOption(g, opname, options->oplist);
+
+ return opval ? (char*)opval : sdef;
+} // end of GetStringTableOption
+
+/****************************************************************************/
+/* Return the value of a Boolean option or bdef if not specified. */
+/****************************************************************************/
+bool GetBooleanTableOption(PGLOBAL g, PTOS options, PCSZ opname, bool bdef)
+{
+ bool opval= bdef;
+ PCSZ pv;
+
+ if (!options)
+ return bdef;
+ else if (!stricmp(opname, "Mapped"))
+ opval= options->mapped;
+ else if (!stricmp(opname, "Huge"))
+ opval= options->huge;
+ else if (!stricmp(opname, "Split"))
+ opval= options->split;
+ else if (!stricmp(opname, "Readonly"))
+ opval= options->readonly;
+ else if (!stricmp(opname, "SepIndex"))
+ opval= options->sepindex;
+ else if (!stricmp(opname, "Header"))
+ opval= (options->header != 0); // Is Boolean for some table types
+ else if (!stricmp(opname, "Zipped"))
+ opval= options->zipped;
+ else if (options->oplist)
+ if ((pv= GetListOption(g, opname, options->oplist)))
+ opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0);
+
+ return opval;
+} // end of GetBooleanTableOption
+
+/****************************************************************************/
+/* Return the value of an integer option or NO_IVAL if not specified. */
+/****************************************************************************/
+int GetIntegerTableOption(PGLOBAL g, PTOS options, PCSZ opname, int idef)
+{
+ ulonglong opval= (ulonglong) NO_IVAL;
+
+ if (!options)
+ return idef;
+ else if (!stricmp(opname, "Lrecl"))
+ opval= options->lrecl;
+ else if (!stricmp(opname, "Elements"))
+ opval= options->elements;
+ else if (!stricmp(opname, "Multiple"))
+ opval= options->multiple;
+ else if (!stricmp(opname, "Header"))
+ opval= options->header;
+ else if (!stricmp(opname, "Quoted"))
+ opval= options->quoted;
+ else if (!stricmp(opname, "Ending"))
+ opval= options->ending;
+ else if (!stricmp(opname, "Compressed"))
+ opval= (options->compressed);
+
+ if ((ulonglong) opval == (ulonglong)NO_IVAL) {
+ PCSZ pv;
+
+ if ((pv = GetListOption(g, opname, options->oplist))) {
+ // opval = CharToNumber((char*)pv, strlen(pv), ULONGLONG_MAX, false);
+ return atoi(pv);
+ } else
+ return idef;
+
+ } // endif opval
+
+ return (int)opval;
+} // end of GetIntegerTableOption
+
+/****************************************************************************/
+/* Return the table option structure. */
+/****************************************************************************/
+PTOS ha_connect::GetTableOptionStruct(TABLE_SHARE *s)
+{
+ TABLE_SHARE *tsp= (tshp) ? tshp : (s) ? s : table_share;
+
+ return (tsp && (!tsp->db_plugin ||
+ !stricmp(plugin_name(tsp->db_plugin)->str, "connect") ||
+ !stricmp(plugin_name(tsp->db_plugin)->str, "partition")))
+ ? tsp->option_struct : NULL;
+} // end of GetTableOptionStruct
+
+/****************************************************************************/
+/* Return the string eventually formatted with partition name. */
+/****************************************************************************/
+char *ha_connect::GetRealString(PCSZ s)
+{
+ char *sv;
+
+ if (IsPartitioned() && s && *partname) {
+ sv= (char*)PlugSubAlloc(xp->g, NULL, 0);
+ sprintf(sv, s, partname);
+ PlugSubAlloc(xp->g, NULL, strlen(sv) + 1);
+ } else
+ sv= (char*)s;
+
+ return sv;
+} // end of GetRealString
+
+/****************************************************************************/
+/* Return the value of a string option or sdef if not specified. */
+/****************************************************************************/
+PCSZ ha_connect::GetStringOption(PCSZ opname, PCSZ sdef)
+{
+ PCSZ opval= NULL;
+ PTOS options= GetTableOptionStruct();
+
+ if (!stricmp(opname, "Connect")) {
+ LEX_CSTRING cnc= (tshp) ? tshp->connect_string
+ : table->s->connect_string;
+
+ if (cnc.length)
+ opval= strz(xp->g, cnc);
+ else
+ opval= GetListOption(xp->g, opname, options->oplist);
+
+ } else if (!stricmp(opname, "Query_String")) {
+// This escapes everything and returns a wrong query
+// opval= thd_query_string(table->in_use)->str;
+ opval= (PCSZ)PlugSubAlloc(xp->g, NULL,
+ thd_query_string(table->in_use)->length + 1);
+ strcpy((char*)opval, thd_query_string(table->in_use)->str);
+// sprintf((char*)opval, "%s", thd_query_string(table->in_use)->str);
+ } else if (!stricmp(opname, "Partname"))
+ opval= partname;
+ else if (!stricmp(opname, "Table_charset")) {
+ const CHARSET_INFO *chif= (tshp) ? tshp->table_charset
+ : table->s->table_charset;
+
+ if (chif)
+ opval= (char*)chif->csname;
+
+ } else
+ opval= GetStringTableOption(xp->g, options, opname, NULL);
+
+ if (opval && (!stricmp(opname, "connect")
+ || !stricmp(opname, "tabname")
+ || !stricmp(opname, "filename")
+ || !stricmp(opname, "optname")
+ || !stricmp(opname, "entry")))
+ opval= GetRealString(opval);
+
+ if (!opval) {
+ if (sdef && !strcmp(sdef, "*")) {
+ // Return the handler default value
+ if (!stricmp(opname, "Dbname") || !stricmp(opname, "Database"))
+ opval= (char*)GetDBName(NULL); // Current database
+ else if (!stricmp(opname, "Type")) // Default type
+ opval= (!options) ? NULL :
+ (options->srcdef) ? (char*)"MYSQL" :
+ (options->tabname) ? (char*)"PROXY" : (char*)"DOS";
+ else if (!stricmp(opname, "User")) // Connected user
+ opval= (char *) "root";
+ else if (!stricmp(opname, "Host")) // Connected user host
+ opval= (char *) "localhost";
+ else
+ opval= sdef; // Caller default
+
+ } else
+ opval= sdef; // Caller default
+
+ } // endif !opval
+
+ return opval;
+} // end of GetStringOption
+
+/****************************************************************************/
+/* Return the value of a Boolean option or bdef if not specified. */
+/****************************************************************************/
+bool ha_connect::GetBooleanOption(PCSZ opname, bool bdef)
+{
+ bool opval;
+ PTOS options= GetTableOptionStruct();
+
+ if (!stricmp(opname, "View"))
+ opval= (tshp) ? tshp->is_view : table_share->is_view;
+ else
+ opval= GetBooleanTableOption(xp->g, options, opname, bdef);
+
+ return opval;
+} // end of GetBooleanOption
+
+/****************************************************************************/
+/* Set the value of the opname option (does not work for oplist options) */
+/* Currently used only to set the Sepindex value. */
+/****************************************************************************/
+bool ha_connect::SetBooleanOption(PCSZ opname, bool b)
+{
+ PTOS options= GetTableOptionStruct();
+
+ if (!options)
+ return true;
+
+ if (!stricmp(opname, "SepIndex"))
+ options->sepindex= b;
+ else
+ return true;
+
+ return false;
+} // end of SetBooleanOption
+
+/****************************************************************************/
+/* Return the value of an integer option or NO_IVAL if not specified. */
+/****************************************************************************/
+int ha_connect::GetIntegerOption(PCSZ opname)
+{
+ int opval;
+ PTOS options= GetTableOptionStruct();
+ TABLE_SHARE *tsp= (tshp) ? tshp : table_share;
+
+ if (!stricmp(opname, "Avglen"))
+ opval= (int)tsp->avg_row_length;
+ else if (!stricmp(opname, "Estimate"))
+ opval= (int)tsp->max_rows;
+ else
+ opval= GetIntegerTableOption(xp->g, options, opname, NO_IVAL);
+
+ return opval;
+} // end of GetIntegerOption
+
+/****************************************************************************/
+/* Set the value of the opname option (does not work for oplist options) */
+/* Currently used only to set the Lrecl value. */
+/****************************************************************************/
+bool ha_connect::SetIntegerOption(PCSZ opname, int n)
+{
+ PTOS options= GetTableOptionStruct();
+
+ if (!options)
+ return true;
+
+ if (!stricmp(opname, "Lrecl"))
+ options->lrecl= n;
+ else if (!stricmp(opname, "Elements"))
+ options->elements= n;
+//else if (!stricmp(opname, "Estimate"))
+// options->estimate= n;
+ else if (!stricmp(opname, "Multiple"))
+ options->multiple= n;
+ else if (!stricmp(opname, "Header"))
+ options->header= n;
+ else if (!stricmp(opname, "Quoted"))
+ options->quoted= n;
+ else if (!stricmp(opname, "Ending"))
+ options->ending= n;
+ else if (!stricmp(opname, "Compressed"))
+ options->compressed= n;
+ else
+ return true;
+//else if (options->oplist)
+// SetListOption(opname, options->oplist, n);
+
+ return false;
+} // end of SetIntegerOption
+
+/****************************************************************************/
+/* Return a field option structure. */
+/****************************************************************************/
+PFOS ha_connect::GetFieldOptionStruct(Field *fdp)
+{
+ return fdp->option_struct;
+} // end of GetFildOptionStruct
+
+/****************************************************************************/
+/* Returns the column description structure used to make the column. */
+/****************************************************************************/
+void *ha_connect::GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf)
+{
+ const char *cp;
+ char *chset, v= 0;
+ ha_field_option_struct *fop;
+ Field* fp;
+ Field* *fldp;
+
+ // Double test to be on the safe side
+ if (!table)
+ return NULL;
+
+ // Find the column to describe
+ if (field) {
+ fldp= (Field**)field;
+ fldp++;
+ } else
+ fldp= (tshp) ? tshp->field : table->field;
+
+ if (!fldp || !(fp= *fldp))
+ return NULL;
+
+ // Get the CONNECT field options structure
+ fop= GetFieldOptionStruct(fp);
+ pcf->Flags= 0;
+
+ // Now get column information
+ pcf->Name= (char*)fp->field_name.str;
+ chset = (char*)fp->charset()->name;
+
+ if (fop && fop->special) {
+ pcf->Fieldfmt= (char*)fop->special;
+ pcf->Flags= U_SPECIAL;
+ return fldp;
+ } // endif special
+
+ pcf->Scale= 0;
+ pcf->Opt= (fop) ? (int)fop->opt : 0;
+
+ if (fp->field_length >= 0) {
+ pcf->Length= fp->field_length;
+
+ // length is bytes for Connect, not characters
+ if (!strnicmp(chset, "utf8", 4))
+ pcf->Length /= 3;
+
+ } else
+ pcf->Length= 256; // BLOB?
+
+ pcf->Precision= pcf->Length;
+
+ if (fop) {
+ pcf->Offset= (int)fop->offset;
+ pcf->Freq= (int)fop->freq;
+ pcf->Datefmt= (char*)fop->dateformat;
+ pcf->Fieldfmt= fop->fieldformat ? (char*)fop->fieldformat
+ : fop->jsonpath ? (char*)fop->jsonpath : (char*)fop->xmlpath;
+ } else {
+ pcf->Offset= -1;
+ pcf->Freq= 0;
+ pcf->Datefmt= NULL;
+ pcf->Fieldfmt= NULL;
+ } // endif fop
+
+ if (!strcmp(chset, "binary"))
+ v = 'B'; // Binary string
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ pcf->Flags |= U_VAR;
+ // fall through
+ default:
+ pcf->Type= MYSQLtoPLG(fp->type(), &v);
+ break;
+ } // endswitch SQL type
+
+ switch (pcf->Type) {
+ case TYPE_STRING:
+ case TYPE_BIN:
+ // Do something for case
+ cp= chset;
+
+ // Find if collation name ends by _ci
+ if (!strcmp(cp + strlen(cp) - 3, "_ci")) {
+ pcf->Scale= 1; // Case insensitive
+ pcf->Opt= 0; // Prevent index opt until it is safe
+ } // endif ci
+
+ break;
+ case TYPE_DOUBLE:
+ pcf->Scale= MY_MAX(MY_MIN(fp->decimals(), ((unsigned)pcf->Length - 2)), 0);
+ break;
+ case TYPE_DECIM:
+ pcf->Precision= ((Field_new_decimal*)fp)->precision;
+ pcf->Length= pcf->Precision;
+ pcf->Scale= fp->decimals();
+ break;
+ case TYPE_DATE:
+ // Field_length is only used for DATE columns
+ if (fop && fop->fldlen)
+ pcf->Length= (int)fop->fldlen;
+ else {
+ int len;
+
+ if (pcf->Datefmt) {
+ // Find the (max) length produced by the date format
+ char buf[256];
+ PGLOBAL g= GetPlug(table->in_use, xp);
+ PDTP pdtp= MakeDateFormat(g, pcf->Datefmt, false, true, 0);
+ struct tm datm;
+ bzero(&datm, sizeof(datm));
+ datm.tm_mday= 12;
+ datm.tm_mon= 11;
+ datm.tm_year= 112;
+ mktime(&datm); // set other fields get proper day name
+ len= strftime(buf, 256, pdtp->OutFmt, &datm);
+ } else
+ len= 0;
+
+ // 11 is for signed numeric representation of the date
+ pcf->Length= (len) ? len : 11;
+ } // endelse
+
+ // For Value setting
+ pcf->Precision= MY_MAX(pcf->Precision, pcf->Length);
+ break;
+ default:
+ break;
+ } // endswitch type
+
+ if (fp->flags & UNSIGNED_FLAG)
+ pcf->Flags |= U_UNSIGNED;
+
+ if (fp->flags & ZEROFILL_FLAG)
+ pcf->Flags |= U_ZEROFILL;
+
+ // This is used to skip null bit
+ if (fp->real_maybe_null())
+ pcf->Flags |= U_NULLS;
+
+ // Mark virtual columns as such
+ if (fp->vcol_info && !fp->stored_in_db)
+ pcf->Flags |= U_VIRTUAL;
+
+ pcf->Key= 0; // Not used when called from MySQL
+
+ // Get the comment if any
+ if (fp->comment.str && fp->comment.length)
+ pcf->Remark= strz(g, fp->comment);
+ else
+ pcf->Remark= NULL;
+
+ return fldp;
+} // end of GetColumnOption
+
+/****************************************************************************/
+/* Return an index option structure. */
+/****************************************************************************/
+PXOS ha_connect::GetIndexOptionStruct(KEY *kp)
+{
+ return kp->option_struct;
+} // end of GetIndexOptionStruct
+
+/****************************************************************************/
+/* Return a Boolean index option or false if not specified. */
+/****************************************************************************/
+bool ha_connect::GetIndexOption(KEY *kp, PCSZ opname)
+{
+ bool opval= false;
+ PXOS options= GetIndexOptionStruct(kp);
+
+ if (options) {
+ if (!stricmp(opname, "Dynamic"))
+ opval= options->dynamic;
+ else if (!stricmp(opname, "Mapped"))
+ opval= options->mapped;
+
+ } else if (kp->comment.str && kp->comment.length) {
+ PCSZ pv, oplist= strz(xp->g, kp->comment);
+
+ if ((pv= GetListOption(xp->g, opname, oplist)))
+ opval= (!*pv || *pv == 'y' || *pv == 'Y' || atoi(pv) != 0);
+
+ } // endif comment
+
+ return opval;
+} // end of GetIndexOption
+
+/****************************************************************************/
+/* Returns the index description structure used to make the index. */
+/****************************************************************************/
+bool ha_connect::IsUnique(uint n)
+{
+ return (table->key_info[n].flags & HA_NOSAME) != 0;
+} // end of IsUnique
+
+/****************************************************************************/
+/* Returns the index description structure used to make the index. */
+/****************************************************************************/
+PIXDEF ha_connect::GetIndexInfo(TABLE_SHARE *s)
+{
+ char *name, *pn;
+ bool unique;
+ PIXDEF xdp, pxd=NULL, toidx= NULL;
+ PKPDEF kpp, pkp;
+ KEY kp;
+ PGLOBAL& g= xp->g;
+
+ if (!s)
+ s= table->s;
+
+ for (int n= 0; (unsigned)n < s->keynames.count; n++) {
+ if (trace(1))
+ htrc("Getting created index %d info\n", n + 1);
+
+ // Find the index to describe
+ kp= s->key_info[n];
+
+ // Now get index information
+ pn= (char*)s->keynames.type_names[n];
+ name= PlugDup(g, pn);
+ unique= (kp.flags & 1) != 0;
+ pkp= NULL;
+
+ // Allocate the index description block
+ xdp= new(g) INDEXDEF(name, unique, n);
+
+ // Get the the key parts info
+ for (int k= 0; (unsigned)k < kp.user_defined_key_parts; k++) {
+ pn= (char*)kp.key_part[k].field->field_name.str;
+ name= PlugDup(g, pn);
+
+ // Allocate the key part description block
+ kpp= new(g) KPARTDEF(name, k + 1);
+ kpp->SetKlen(kp.key_part[k].length);
+
+#if 0 // NIY
+ // Index on auto increment column can be an XXROW index
+ if (kp.key_part[k].field->flags & AUTO_INCREMENT_FLAG &&
+ kp.uder_defined_key_parts == 1) {
+ char *type= GetStringOption("Type", "DOS");
+ TABTYPE typ= GetTypeID(type);
+
+ xdp->SetAuto(IsTypeFixed(typ));
+ } // endif AUTO_INCREMENT
+#endif // 0
+
+ if (pkp)
+ pkp->SetNext(kpp);
+ else
+ xdp->SetToKeyParts(kpp);
+
+ pkp= kpp;
+ } // endfor k
+
+ xdp->SetNParts(kp.user_defined_key_parts);
+ xdp->Dynamic= GetIndexOption(&kp, "Dynamic");
+ xdp->Mapped= GetIndexOption(&kp, "Mapped");
+
+ if (pxd)
+ pxd->SetNext(xdp);
+ else
+ toidx= xdp;
+
+ pxd= xdp;
+ } // endfor n
+
+ return toidx;
+} // end of GetIndexInfo
+
+/****************************************************************************/
+/* Returns the index description structure used to make the index. */
+/****************************************************************************/
+bool ha_connect::CheckVirtualIndex(TABLE_SHARE *s)
+{
+
+ char *rid;
+ KEY kp;
+ Field *fp;
+ PGLOBAL& g= xp->g;
+
+ if (!s)
+ s= table->s;
+
+ for (int n= 0; (unsigned)n < s->keynames.count; n++) {
+ kp= s->key_info[n];
+
+ // Now get index information
+
+ // Get the the key parts info
+ for (int k= 0; (unsigned)k < kp.user_defined_key_parts; k++) {
+ fp= kp.key_part[k].field;
+ rid= (fp->option_struct) ? fp->option_struct->special : NULL;
+
+ if (!rid || (stricmp(rid, "ROWID") && stricmp(rid, "ROWNUM"))) {
+ strcpy(g->Message, "Invalid virtual index");
+ return true;
+ } // endif rowid
+
+ } // endfor k
+
+ } // endfor n
+
+ return false;
+} // end of CheckVirtualIndex
+
+bool ha_connect::IsPartitioned(void)
+{
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ if (tshp)
+ return tshp->partition_info_str_len > 0;
+ else if (table && table->part_info)
+ return true;
+ else
+#endif
+ return false;
+
+} // end of IsPartitioned
+
+PCSZ ha_connect::GetDBName(PCSZ name)
+{
+ return (name) ? name : table->s->db.str;
+} // end of GetDBName
+
+const char *ha_connect::GetTableName(void)
+{
+ const char *path= tshp ? tshp->path.str : table_share->path.str;
+ const char *name= strrchr(path, slash);
+ return name ? name + 1 : path;
+} // end of GetTableName
+
+char *ha_connect::GetPartName(void)
+{
+ return (IsPartitioned()) ? partname : (char*)GetTableName();
+} // end of GetTableName
+
+#if 0
+/****************************************************************************/
+/* Returns the column real or special name length of a field. */
+/****************************************************************************/
+int ha_connect::GetColNameLen(Field *fp)
+{
+ int n;
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ // Now get the column name length
+ if (fop && fop->special)
+ n= strlen(fop->special) + 1;
+ else
+ n= fp->field_name.length;
+
+ return n;
+} // end of GetColNameLen
+
+/****************************************************************************/
+/* Returns the column real or special name of a field. */
+/****************************************************************************/
+char *ha_connect::GetColName(Field *fp)
+{
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ return (fop && fop->special) ? fop->special : (char*)fp->field_name.str;
+} // end of GetColName
+
+/****************************************************************************/
+/* Adds the column real or special name of a field to a string. */
+/****************************************************************************/
+void ha_connect::AddColName(char *cp, Field *fp)
+{
+ PFOS fop= GetFieldOptionStruct(fp);
+
+ // Now add the column name
+ if (fop && fop->special)
+ // The prefix * mark the column as "special"
+ strcat(strcpy(cp, "*"), strupr(fop->special));
+ else
+ strcpy(cp, fp->field_name.str);
+
+} // end of AddColName
+#endif // 0
+
+/***********************************************************************/
+/* This function sets the current database path. */
+/***********************************************************************/
+bool ha_connect::SetDataPath(PGLOBAL g, PCSZ path)
+{
+ return (!(datapath= SetPath(g, path)));
+} // end of SetDataPath
+
+/****************************************************************************/
+/* Get the table description block of a CONNECT table. */
+/****************************************************************************/
+PTDB ha_connect::GetTDB(PGLOBAL g)
+{
+ const char *table_name;
+ PTDB tp;
+
+ // Double test to be on the safe side
+ if (!g || !table)
+ return NULL;
+
+ table_name= GetTableName();
+
+ if (!xp->CheckQuery(valid_query_id) && tdbp
+ && !stricmp(tdbp->GetName(), table_name)
+ && (tdbp->GetMode() == xmod
+ || (tdbp->GetMode() == MODE_READ && xmod == MODE_READX)
+ || tdbp->GetAmType() == TYPE_AM_XML)) {
+ tp= tdbp;
+ tp->SetMode(xmod);
+ } else if ((tp= CntGetTDB(g, table_name, xmod, this))) {
+ valid_query_id= xp->last_query_id;
+// tp->SetMode(xmod);
+ } else
+ htrc("GetTDB: %s\n", g->Message);
+
+ return tp;
+} // end of GetTDB
+
+/****************************************************************************/
+/* Open a CONNECT table, restricting column list if cols is true. */
+/****************************************************************************/
+int ha_connect::OpenTable(PGLOBAL g, bool del)
+{
+ bool rc= false;
+ char *c1= NULL, *c2=NULL;
+
+ // Double test to be on the safe side
+ if (!g || !table) {
+ htrc("OpenTable logical error; g=%p table=%p\n", g, table);
+ return HA_ERR_INITIALIZATION;
+ } // endif g
+
+ if (!(tdbp= GetTDB(g)))
+ return RC_FX;
+ else if (tdbp->IsReadOnly())
+ switch (xmod) {
+ case MODE_WRITE:
+ case MODE_INSERT:
+ case MODE_UPDATE:
+ case MODE_DELETE:
+ strcpy(g->Message, MSG(READ_ONLY));
+ return HA_ERR_TABLE_READONLY;
+ default:
+ break;
+ } // endswitch xmode
+
+ // g->More is 1 when executing commands from triggers
+ if (!g->More && (xmod != MODE_INSERT
+ || tdbp->GetAmType() == TYPE_AM_MYSQL
+ || tdbp->GetAmType() == TYPE_AM_ODBC
+ || tdbp->GetAmType() == TYPE_AM_JDBC)) {
+ // Get the list of used fields (columns)
+ char *p;
+ unsigned int k1, k2, n1, n2;
+ Field* *field;
+ Field* fp;
+ MY_BITMAP *map= (xmod == MODE_INSERT) ? table->write_set : table->read_set;
+ MY_BITMAP *ump= (xmod == MODE_UPDATE) ? table->write_set : NULL;
+
+ k1= k2= 0;
+ n1= n2= 1; // 1 is space for final null character
+
+ for (field= table->field; (fp= *field); field++) {
+ if (bitmap_is_set(map, fp->field_index)) {
+ n1+= (fp->field_name.length + 1);
+ k1++;
+ } // endif
+
+ if (ump && bitmap_is_set(ump, fp->field_index)) {
+ n2+= (fp->field_name.length + 1);
+ k2++;
+ } // endif
+
+ } // endfor field
+
+ if (k1) {
+ p= c1= (char*)PlugSubAlloc(g, NULL, n1);
+
+ for (field= table->field; (fp= *field); field++)
+ if (bitmap_is_set(map, fp->field_index)) {
+ strcpy(p, fp->field_name.str);
+ p+= (fp->field_name.length + 1);
+ } // endif used field
+
+ *p= '\0'; // mark end of list
+ } // endif k1
+
+ if (k2) {
+ p= c2= (char*)PlugSubAlloc(g, NULL, n2);
+
+ for (field= table->field; (fp= *field); field++)
+ if (bitmap_is_set(ump, fp->field_index)) {
+ strcpy(p, fp->field_name.str);
+
+ if (part_id && bitmap_is_set(part_id, fp->field_index)) {
+ // Trying to update a column used for partitioning
+ // This cannot be currently done because it may require
+ // a row to be moved in another partition.
+ sprintf(g->Message,
+ "Cannot update column %s because it is used for partitioning",
+ p);
+ return HA_ERR_INTERNAL_ERROR;
+ } // endif part_id
+
+ p+= (strlen(p) + 1);
+ } // endif used field
+
+ *p= '\0'; // mark end of list
+ } // endif k2
+
+ } // endif xmod
+
+ // Open the table
+ if (!(rc= CntOpenTable(g, tdbp, xmod, c1, c2, del, this))) {
+ istable= true;
+// strmake(tname, table_name, sizeof(tname)-1);
+
+#ifdef NOT_USED_VARIABLE
+ // We may be in a create index query
+ if (xmod == MODE_ANY && *tdbp->GetName() != '#') {
+ // The current indexes
+ PIXDEF oldpix= GetIndexInfo();
+ } // endif xmod
+#endif
+
+ } else
+ htrc("OpenTable: %s\n", g->Message);
+
+ if (rc) {
+ tdbp= NULL;
+ valid_info= false;
+ } // endif rc
+
+ return (rc) ? HA_ERR_INITIALIZATION : 0;
+} // end of OpenTable
+
+
+/****************************************************************************/
+/* CheckColumnList: check that all bitmap columns do exist. */
+/****************************************************************************/
+bool ha_connect::CheckColumnList(PGLOBAL g)
+{
+ // Check the list of used fields (columns)
+ bool brc= false;
+ PCOL colp;
+ Field* *field;
+ Field* fp;
+ MY_BITMAP *map= table->read_set;
+
+ try {
+ for (field= table->field; (fp= *field); field++)
+ if (bitmap_is_set(map, fp->field_index)) {
+ if (!(colp= tdbp->ColDB(g, (PSZ)fp->field_name.str, 0))) {
+ sprintf(g->Message, "Column %s not found in %s",
+ fp->field_name.str, tdbp->GetName());
+ throw 1;
+ } // endif colp
+
+ if ((brc= colp->InitValue(g)))
+ throw 2;
+
+ colp->AddColUse(U_P); // For PLG tables
+ } // endif
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ brc= true;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ brc= true;
+ } // end catch
+
+ return brc;
+} // end of CheckColumnList
+
+
+/****************************************************************************/
+/* IsOpened: returns true if the table is already opened. */
+/****************************************************************************/
+bool ha_connect::IsOpened(void)
+{
+ return (!xp->CheckQuery(valid_query_id) && tdbp
+ && tdbp->GetUse() == USE_OPEN);
+} // end of IsOpened
+
+
+/****************************************************************************/
+/* Close a CONNECT table. */
+/****************************************************************************/
+int ha_connect::CloseTable(PGLOBAL g)
+{
+ int rc= CntCloseTable(g, tdbp, nox, abort);
+ tdbp= NULL;
+ sdvalin1= sdvalin2= sdvalin3= sdvalin4= NULL;
+ sdvalout=NULL;
+ valid_info= false;
+ indexing= -1;
+ nox= true;
+ abort= false;
+ return rc;
+} // end of CloseTable
+
+
+/***********************************************************************/
+/* Make a pseudo record from current row values. Specific to MySQL. */
+/***********************************************************************/
+int ha_connect::MakeRecord(char *buf)
+{
+ PCSZ fmt;
+ char *p, val[32];
+ int rc= 0;
+ Field* *field;
+ Field *fp;
+ CHARSET_INFO *charset= tdbp->data_charset();
+//MY_BITMAP readmap;
+ MY_BITMAP *map;
+ PVAL value;
+ PCOL colp= NULL;
+ DBUG_ENTER("ha_connect::MakeRecord");
+
+ if (trace(2))
+ htrc("Maps: read=%08X write=%08X defr=%08X defw=%08X\n",
+ *table->read_set->bitmap, *table->write_set->bitmap,
+ *table->def_read_set.bitmap, *table->def_write_set.bitmap);
+
+ // Avoid asserts in field::store() for columns that are not updated
+ MY_BITMAP *org_bitmap= dbug_tmp_use_all_columns(table, &table->write_set);
+
+ // This is for variable_length rows
+ memset(buf, 0, table->s->null_bytes);
+
+ // When sorting read_set selects all columns, so we use def_read_set
+ map= (MY_BITMAP *)&table->def_read_set;
+
+ // Make the pseudo record from field values
+ for (field= table->field; *field && !rc; field++) {
+ fp= *field;
+
+ if (fp->vcol_info && !fp->stored_in_db)
+ continue; // This is a virtual column
+
+ if (bitmap_is_set(map, fp->field_index) || alter) {
+ // This is a used field, fill the buffer with value
+ for (colp= tdbp->GetColumns(); colp; colp= colp->GetNext())
+ if ((!mrr || colp->GetKcol()) &&
+ !stricmp(colp->GetName(), fp->field_name.str))
+ break;
+
+ if (!colp) {
+ if (mrr)
+ continue;
+
+ htrc("Column %s not found\n", fp->field_name.str);
+ dbug_tmp_restore_column_map(&table->write_set, org_bitmap);
+ DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
+ } // endif colp
+
+ value= colp->GetValue();
+ p= NULL;
+
+ // All this was better optimized
+ if (!value->IsNull()) {
+ switch (value->GetType()) {
+ case TYPE_DATE:
+ if (!sdvalout)
+ sdvalout= AllocateValue(xp->g, TYPE_STRING, 20);
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_DATE:
+ fmt= "%Y-%m-%d";
+ break;
+ case MYSQL_TYPE_TIME:
+ fmt= "%H:%M:%S";
+ break;
+ case MYSQL_TYPE_YEAR:
+ fmt= "%Y";
+ break;
+ default:
+ fmt= "%Y-%m-%d %H:%M:%S";
+ break;
+ } // endswitch type
+
+ // Get date in the format required by MySQL fields
+ value->FormatValue(sdvalout, fmt);
+ p= sdvalout->GetCharValue();
+ rc= fp->store(p, strlen(p), charset, CHECK_FIELD_WARN);
+ break;
+ case TYPE_STRING:
+ case TYPE_DECIM:
+ p= value->GetCharString(val);
+ charset= tdbp->data_charset();
+ rc= fp->store_text(p, strlen(p), charset, CHECK_FIELD_WARN);
+ break;
+ case TYPE_BIN:
+ p= value->GetCharValue();
+ charset= &my_charset_bin;
+ rc= fp->store(p, value->GetSize(), charset, CHECK_FIELD_WARN);
+ break;
+ case TYPE_DOUBLE:
+ rc= fp->store(value->GetFloatValue());
+ break;
+ default:
+ rc= fp->store(value->GetBigintValue(), value->IsUnsigned());
+ break;
+ } // endswitch Type
+
+ // Store functions returns 1 on overflow and -1 on fatal error
+ if (rc > 0) {
+ char buf[256];
+ THD *thd= ha_thd();
+
+ sprintf(buf, "Out of range value %.140s for column '%s' at row %ld",
+ value->GetCharString(val),
+ fp->field_name.str,
+ thd->get_stmt_da()->current_row_for_warning());
+
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, buf);
+ DBUG_PRINT("MakeRecord", ("%s", buf));
+ rc= 0;
+ } else if (rc < 0)
+ rc= HA_ERR_WRONG_IN_RECORD;
+
+ fp->set_notnull();
+ } else
+ fp->set_null();
+
+ } // endif bitmap
+
+ } // endfor field
+
+ // This is sometimes required for partition tables because the buf
+ // can be different from the table->record[0] buffer
+ if (buf != (char*)table->record[0])
+ memcpy(buf, table->record[0], table->s->stored_rec_length);
+
+ // This is copied from ha_tina and is necessary to avoid asserts
+ dbug_tmp_restore_column_map(&table->write_set, org_bitmap);
+ DBUG_RETURN(rc);
+} // end of MakeRecord
+
+
+/***********************************************************************/
+/* Set row values from a MySQL pseudo record. Specific to MySQL. */
+/***********************************************************************/
+int ha_connect::ScanRecord(PGLOBAL g, const uchar *)
+{
+ char attr_buffer[1024];
+ char data_buffer[1024];
+ PCSZ fmt;
+ int rc= 0;
+ PCOL colp;
+ PVAL value, sdvalin;
+ Field *fp;
+//PTDBASE tp= (PTDBASE)tdbp;
+ String attribute(attr_buffer, sizeof(attr_buffer),
+ table->s->table_charset);
+ MY_BITMAP *bmap= dbug_tmp_use_all_columns(table, &table->read_set);
+ const CHARSET_INFO *charset= tdbp->data_charset();
+ String data_charset_value(data_buffer, sizeof(data_buffer), charset);
+
+ // Scan the pseudo record for field values and set column values
+ for (Field **field=table->field ; *field ; field++) {
+ fp= *field;
+
+ if ((fp->vcol_info && !fp->stored_in_db) ||
+ fp->option_struct->special)
+ continue; // Is a virtual column possible here ???
+
+ if ((xmod == MODE_INSERT && tdbp->GetAmType() != TYPE_AM_MYSQL
+ && tdbp->GetAmType() != TYPE_AM_ODBC
+ && tdbp->GetAmType() != TYPE_AM_JDBC) ||
+ bitmap_is_set(table->write_set, fp->field_index)) {
+ for (colp= tdbp->GetSetCols(); colp; colp= colp->GetNext())
+ if (!stricmp(colp->GetName(), fp->field_name.str))
+ break;
+
+ if (!colp) {
+ htrc("Column %s not found\n", fp->field_name.str);
+ rc= HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ } else
+ value= colp->GetValue();
+
+ // This is a used field, fill the value from the row buffer
+ // All this could be better optimized
+ if (fp->is_null()) {
+ if (colp->IsNullable())
+ value->SetNull(true);
+
+ value->Reset();
+ } else switch (value->GetType()) {
+ case TYPE_DOUBLE:
+ value->SetValue(fp->val_real());
+ break;
+ case TYPE_DATE:
+ // Get date in the format produced by MySQL fields
+ switch (fp->type()) {
+ case MYSQL_TYPE_DATE:
+ if (!sdvalin2) {
+ sdvalin2= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
+ fmt= "YYYY-MM-DD";
+ ((DTVAL*)sdvalin2)->SetFormat(g, fmt, strlen(fmt));
+ } // endif sdvalin1
+
+ sdvalin= sdvalin2;
+ break;
+ case MYSQL_TYPE_TIME:
+ if (!sdvalin3) {
+ sdvalin3= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
+ fmt= "hh:mm:ss";
+ ((DTVAL*)sdvalin3)->SetFormat(g, fmt, strlen(fmt));
+ } // endif sdvalin1
+
+ sdvalin= sdvalin3;
+ break;
+ case MYSQL_TYPE_YEAR:
+ if (!sdvalin4) {
+ sdvalin4= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
+ fmt= "YYYY";
+ ((DTVAL*)sdvalin4)->SetFormat(g, fmt, strlen(fmt));
+ } // endif sdvalin1
+
+ sdvalin= sdvalin4;
+ break;
+ default:
+ if (!sdvalin1) {
+ sdvalin1= (DTVAL*)AllocateValue(xp->g, TYPE_DATE, 19);
+ fmt= "YYYY-MM-DD hh:mm:ss";
+ ((DTVAL*)sdvalin1)->SetFormat(g, fmt, strlen(fmt));
+ } // endif sdvalin1
+
+ sdvalin= sdvalin1;
+ } // endswitch type
+
+ sdvalin->SetNullable(colp->IsNullable());
+ fp->val_str(&attribute);
+ sdvalin->SetValue_psz(attribute.c_ptr_safe());
+ value->SetValue_pval(sdvalin);
+ break;
+ default:
+ fp->val_str(&attribute);
+
+ if (charset != &my_charset_bin) {
+ // Convert from SQL field charset to DATA_CHARSET
+ uint cnv_errors;
+
+ data_charset_value.copy(attribute.ptr(), attribute.length(),
+ attribute.charset(), charset, &cnv_errors);
+ value->SetValue_psz(data_charset_value.c_ptr_safe());
+ } else
+ value->SetValue_psz(attribute.c_ptr_safe());
+
+ break;
+ } // endswitch Type
+
+#ifdef NEWCHANGE
+ } else if (xmod == MODE_UPDATE) {
+ PCOL cp;
+
+ for (cp= tdbp->GetColumns(); cp; cp= cp->GetNext())
+ if (!stricmp(colp->GetName(), cp->GetName()))
+ break;
+
+ if (!cp) {
+ rc= HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ } // endif cp
+
+ value->SetValue_pval(cp->GetValue());
+ } else // mode Insert
+ value->Reset();
+#else
+ } // endif bitmap_is_set
+#endif
+
+ } // endfor field
+
+ err:
+ dbug_tmp_restore_column_map(&table->read_set, bmap);
+ return rc;
+} // end of ScanRecord
+
+
+/***********************************************************************/
+/* Check change in index column. Specific to MySQL. */
+/* Should be elaborated to check for real changes. */
+/***********************************************************************/
+int ha_connect::CheckRecord(PGLOBAL g, const uchar *, const uchar *newbuf)
+{
+ return ScanRecord(g, newbuf);
+} // end of dummy CheckRecord
+
+
+/***********************************************************************/
+/* Return true if this field is used in current indexing. */
+/***********************************************************************/
+bool ha_connect::IsIndexed(Field *fp)
+{
+ if (active_index < MAX_KEY) {
+ KEY_PART_INFO *kpart;
+ KEY *kfp= &table->key_info[active_index];
+ uint rem= kfp->user_defined_key_parts;
+
+ for (kpart= kfp->key_part; rem; rem--, kpart++)
+ if (kpart->field == fp)
+ return true;
+
+ } // endif active_index
+
+ return false;
+} // end of IsIndexed
+
+
+/***********************************************************************/
+/* Return the where clause for remote indexed read. */
+/***********************************************************************/
+bool ha_connect::MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL vop, char q,
+ const key_range *kr)
+{
+ const uchar *ptr;
+//uint i, rem, len, klen, stlen;
+ uint i, rem, len, stlen;
+ bool nq, both, oom;
+ OPVAL op;
+ Field *fp;
+ const key_range *ranges[2];
+ MY_BITMAP *old_map;
+ KEY *kfp;
+ KEY_PART_INFO *kpart;
+
+ if (active_index == MAX_KEY)
+ return false;
+
+ ranges[0]= kr;
+ ranges[1]= (end_range && !eq_range) ? &save_end_range : NULL;
+
+ if (!ranges[0] && !ranges[1]) {
+ strcpy(g->Message, "MakeKeyWhere: No key");
+ return true;
+ } else
+ both= ranges[0] && ranges[1];
+
+ kfp= &table->key_info[active_index];
+ old_map= dbug_tmp_use_all_columns(table, &table->write_set);
+
+ for (i= 0; i <= 1; i++) {
+ if (ranges[i] == NULL)
+ continue;
+
+ if (both && i > 0)
+ qry->Append(") AND (");
+ else
+ qry->Append(" WHERE (");
+
+// klen= len= ranges[i]->length;
+ len= ranges[i]->length;
+ rem= kfp->user_defined_key_parts;
+ ptr= ranges[i]->key;
+
+ for (kpart= kfp->key_part; rem; rem--, kpart++) {
+ fp= kpart->field;
+ stlen= kpart->store_length;
+ nq= fp->str_needs_quotes();
+
+ if (kpart != kfp->key_part)
+ qry->Append(" AND ");
+
+ if (q) {
+ qry->Append(q);
+ qry->Append((PSZ)fp->field_name.str);
+ qry->Append(q);
+ } else
+ qry->Append((PSZ)fp->field_name.str);
+
+ switch (ranges[i]->flag) {
+ case HA_READ_KEY_EXACT:
+// op= (stlen >= len || !nq || fp->result_type() != STRING_RESULT)
+// ? OP_EQ : OP_LIKE;
+ op= OP_EQ;
+ break;
+ case HA_READ_AFTER_KEY:
+ op= (stlen >= len || i > 0) ? (i > 0 ? OP_LE : OP_GT) : OP_GE;
+ break;
+ case HA_READ_KEY_OR_NEXT:
+ op= OP_GE;
+ break;
+ case HA_READ_BEFORE_KEY:
+ op= (stlen >= len) ? OP_LT : OP_LE;
+ break;
+ case HA_READ_KEY_OR_PREV:
+ op= OP_LE;
+ break;
+ default:
+ sprintf(g->Message, "cannot handle flag %d", ranges[i]->flag);
+ goto err;
+ } // endswitch flag
+
+ qry->Append((PSZ)GetValStr(op, false));
+
+ if (nq)
+ qry->Append('\'');
+
+ if (kpart->key_part_flag & HA_VAR_LENGTH_PART) {
+ String varchar;
+ uint var_length= uint2korr(ptr);
+
+ varchar.set_quick((char*)ptr + HA_KEY_BLOB_LENGTH,
+ var_length, &my_charset_bin);
+ qry->Append(varchar.ptr(), varchar.length(), nq);
+ } else {
+ char strbuff[MAX_FIELD_WIDTH];
+ String str(strbuff, sizeof(strbuff), kpart->field->charset()), *res;
+
+ res= fp->val_str(&str, ptr);
+ qry->Append(res->ptr(), res->length(), nq);
+ } // endif flag
+
+ if (nq)
+ qry->Append('\'');
+
+ if (stlen >= len)
+ break;
+
+ len-= stlen;
+
+ /* For nullable columns, null-byte is already skipped before, that is
+ ptr was incremented by 1. Since store_length still counts null-byte,
+ we need to subtract 1 from store_length. */
+ ptr+= stlen - MY_TEST(kpart->null_bit);
+ } // endfor kpart
+
+ } // endfor i
+
+ qry->Append(')');
+
+ if ((oom= qry->IsTruncated()))
+ strcpy(g->Message, "Out of memory");
+
+ dbug_tmp_restore_column_map(&table->write_set, old_map);
+ return oom;
+
+err:
+ dbug_tmp_restore_column_map(&table->write_set, old_map);
+ return true;
+} // end of MakeKeyWhere
+
+
+/***********************************************************************/
+/* Return the string representing an operator. */
+/***********************************************************************/
+const char *ha_connect::GetValStr(OPVAL vop, bool neg)
+{
+ const char *val;
+
+ switch (vop) {
+ case OP_EQ:
+ val= "= ";
+ break;
+ case OP_NE:
+ val= " <> ";
+ break;
+ case OP_GT:
+ val= " > ";
+ break;
+ case OP_GE:
+ val= " >= ";
+ break;
+ case OP_LT:
+ val= " < ";
+ break;
+ case OP_LE:
+ val= " <= ";
+ break;
+ case OP_IN:
+ val= (neg) ? " NOT IN (" : " IN (";
+ break;
+ case OP_NULL:
+ val= (neg) ? " IS NOT NULL" : " IS NULL";
+ break;
+ case OP_LIKE:
+ val= (neg) ? " NOT LIKE " : " LIKE ";
+ break;
+ case OP_XX:
+ val= (neg) ? " NOT BETWEEN " : " BETWEEN ";
+ break;
+ case OP_EXIST:
+ val= (neg) ? " NOT EXISTS " : " EXISTS ";
+ break;
+ case OP_AND:
+ val= " AND ";
+ break;
+ case OP_OR:
+ val= " OR ";
+ break;
+ case OP_NOT:
+ val= " NOT ";
+ break;
+ case OP_CNC:
+ val= " || ";
+ break;
+ case OP_ADD:
+ val= " + ";
+ break;
+ case OP_SUB:
+ val= " - ";
+ break;
+ case OP_MULT:
+ val= " * ";
+ break;
+ case OP_DIV:
+ val= " / ";
+ break;
+ default:
+ val= " ? ";
+ break;
+ } /* endswitch */
+
+ return val;
+} // end of GetValStr
+
+#if 0
+/***********************************************************************/
+/* Check the WHERE condition and return a CONNECT filter. */
+/***********************************************************************/
+PFIL ha_connect::CheckFilter(PGLOBAL g)
+{
+ return CondFilter(g, (Item *)pushed_cond);
+} // end of CheckFilter
+#endif // 0
+
+/***********************************************************************/
+/* Check the WHERE condition and return a CONNECT filter. */
+/***********************************************************************/
+PFIL ha_connect::CondFilter(PGLOBAL g, Item *cond)
+{
+ unsigned int i;
+ bool ismul= false;
+ OPVAL vop= OP_XX;
+ PFIL filp= NULL;
+
+ if (!cond)
+ return NULL;
+
+ if (trace(1))
+ htrc("Cond type=%d\n", cond->type());
+
+ if (cond->type() == COND::COND_ITEM) {
+ PFIL fp;
+ Item_cond *cond_item= (Item_cond *)cond;
+
+ if (trace(1))
+ htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(),
+ cond_item->func_name());
+
+ switch (cond_item->functype()) {
+ case Item_func::COND_AND_FUNC: vop= OP_AND; break;
+ case Item_func::COND_OR_FUNC: vop= OP_OR; break;
+ default: return NULL;
+ } // endswitch functype
+
+ List<Item>* arglist= cond_item->argument_list();
+ List_iterator<Item> li(*arglist);
+ Item *subitem;
+
+ for (i= 0; i < arglist->elements; i++)
+ if ((subitem= li++)) {
+ if (!(fp= CondFilter(g, subitem))) {
+ if (vop == OP_OR)
+ return NULL;
+ } else
+ filp= (filp) ? MakeFilter(g, filp, vop, fp) : fp;
+
+ } else
+ return NULL;
+
+ } else if (cond->type() == COND::FUNC_ITEM) {
+ unsigned int i;
+ bool iscol, neg= FALSE;
+ PCOL colp[2]= {NULL,NULL};
+ PPARM pfirst= NULL, pprec= NULL;
+ POPER pop;
+ Item_func *condf= (Item_func *)cond;
+ Item* *args= condf->arguments();
+
+ if (trace(1))
+ htrc("Func type=%d argnum=%d\n", condf->functype(),
+ condf->argument_count());
+
+ switch (condf->functype()) {
+ case Item_func::EQUAL_FUNC:
+ case Item_func::EQ_FUNC: vop= OP_EQ; break;
+ case Item_func::NE_FUNC: vop= OP_NE; break;
+ case Item_func::LT_FUNC: vop= OP_LT; break;
+ case Item_func::LE_FUNC: vop= OP_LE; break;
+ case Item_func::GE_FUNC: vop= OP_GE; break;
+ case Item_func::GT_FUNC: vop= OP_GT; break;
+ case Item_func::IN_FUNC: vop= OP_IN; /* fall through */
+ case Item_func::BETWEEN:
+ ismul= true;
+ neg= ((Item_func_opt_neg *)condf)->negated;
+ break;
+ default: return NULL;
+ } // endswitch functype
+
+ pop= (POPER)PlugSubAlloc(g, NULL, sizeof(OPER));
+ pop->Name= NULL;
+ pop->Val=vop;
+ pop->Mod= 0;
+
+ if (condf->argument_count() < 2)
+ return NULL;
+
+ for (i= 0; i < condf->argument_count(); i++) {
+ if (trace(1))
+ htrc("Argtype(%d)=%d\n", i, args[i]->type());
+
+ if (i >= 2 && !ismul) {
+ if (trace(1))
+ htrc("Unexpected arg for vop=%d\n", vop);
+
+ continue;
+ } // endif i
+
+ if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
+ Item_field *pField= (Item_field *)args[i];
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (i && ismul)
+ return NULL;
+
+ if (pField->field->table != table ||
+ !(colp[i]= tdbp->ColDB(g, (PSZ)pField->field->field_name.str, 0)))
+ return NULL; // Column does not belong to this table
+
+ // These types are not yet implemented (buggy)
+ switch (pField->field->type()) {
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_NEWDATE:
+ return NULL;
+ default:
+ break;
+ } // endswitch type
+
+ if (trace(1)) {
+ htrc("Field index=%d\n", pField->field->field_index);
+ htrc("Field name=%s\n", pField->field->field_name.str);
+ } // endif trace
+
+ } else {
+ char buff[256];
+ String *res, tmp(buff, sizeof(buff), &my_charset_bin);
+ PPARM pp= (PPARM)PlugSubAlloc(g, NULL, sizeof(PARM));
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (!i && (ismul))
+ return NULL;
+
+ switch (args[i]->real_type()) {
+ case COND::CONST_ITEM:
+ {
+ Item *pval= (Item *)args[i];
+ switch (args[i]->cmp_type()) {
+ case STRING_RESULT:
+ res= pval->val_str(&tmp);
+ pp->Value= PlugSubAllocStr(g, NULL, res->ptr(), res->length());
+ pp->Type= (pp->Value) ? TYPE_STRING : TYPE_ERROR;
+ break;
+ case INT_RESULT:
+ pp->Type= TYPE_INT;
+ pp->Value= PlugSubAlloc(g, NULL, sizeof(int));
+ *((int*)pp->Value)= (int)pval->val_int();
+ break;
+ case TIME_RESULT:
+ pp->Type= TYPE_DATE;
+ pp->Value= PlugSubAlloc(g, NULL, sizeof(int));
+ *((int*)pp->Value)= (int) Temporal_hybrid(pval).to_longlong();
+ break;
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ pp->Type= TYPE_DOUBLE;
+ pp->Value= PlugSubAlloc(g, NULL, sizeof(double));
+ *((double*)pp->Value)= pval->val_real();
+ break;
+ case ROW_RESULT:
+ DBUG_ASSERT(0);
+ return NULL;
+ }
+ }
+ break;
+ case COND::CACHE_ITEM: // Possible ???
+ case COND::NULL_ITEM: // TODO: handle this
+ default:
+ return NULL;
+ } // endswitch type
+
+ if (trace(1))
+ htrc("Value type=%hd\n", pp->Type);
+
+ // Append the value to the argument list
+ if (pprec)
+ pprec->Next= pp;
+ else
+ pfirst= pp;
+
+ pp->Domain= i;
+ pp->Next= NULL;
+ pprec= pp;
+ } // endif type
+
+ } // endfor i
+
+ filp= MakeFilter(g, colp, pop, pfirst, neg);
+ } else {
+ if (trace(1))
+ htrc("Unsupported condition\n");
+
+ return NULL;
+ } // endif's type
+
+ return filp;
+} // end of CondFilter
+
+/***********************************************************************/
+/* Check the WHERE condition and return a MYSQL/ODBC/JDBC/WQL filter. */
+/***********************************************************************/
+PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, const Item *cond)
+{
+ AMT tty= filp->Type;
+ char *body= filp->Body;
+ char *havg= filp->Having;
+ unsigned int i;
+ bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
+ bool nonul= ((tty == TYPE_AM_ODBC || tty == TYPE_AM_JDBC) &&
+ (tdbp->GetMode() == MODE_INSERT || tdbp->GetMode() == MODE_DELETE));
+ OPVAL vop= OP_XX;
+
+ if (!cond)
+ return NULL;
+
+ if (trace(1))
+ htrc("Cond type=%d\n", cond->type());
+
+ if (cond->type() == COND::COND_ITEM) {
+ char *pb0, *pb1, *pb2, *ph0= 0, *ph1= 0, *ph2= 0;
+ bool bb= false, bh= false;
+ Item_cond *cond_item= (Item_cond *)cond;
+
+ if (x)
+ return NULL;
+ else
+ pb0= pb1= pb2= ph0= ph1= ph2= NULL;
+
+ if (trace(1))
+ htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(),
+ cond_item->func_name());
+
+ switch (cond_item->functype()) {
+ case Item_func::COND_AND_FUNC: vop= OP_AND; break;
+ case Item_func::COND_OR_FUNC: vop= OP_OR; break;
+ default: return NULL;
+ } // endswitch functype
+
+ List<Item>* arglist= cond_item->argument_list();
+ List_iterator<Item> li(*arglist);
+ const Item *subitem;
+
+ pb0= pb1= body + strlen(body);
+ strcpy(pb0, "(");
+ pb2= pb1 + 1;
+
+ if (havg) {
+ ph0= ph1= havg + strlen(havg);
+ strcpy(ph0, "(");
+ ph2= ph1 + 1;
+ } // endif havg
+
+ for (i= 0; i < arglist->elements; i++)
+ if ((subitem= li++)) {
+ if (!CheckCond(g, filp, subitem)) {
+ if (vop == OP_OR || nonul)
+ return NULL;
+ else {
+ *pb2= 0;
+ if (havg) *ph2= 0;
+ } // endelse
+
+ } else {
+ if (filp->Bd) {
+ pb1= pb2 + strlen(pb2);
+ strcpy(pb1, GetValStr(vop, false));
+ pb2= pb1 + strlen(pb1);
+ } // endif Bd
+
+ if (filp->Hv) {
+ ph1= ph2 + strlen(ph2);
+ strcpy(ph1, GetValStr(vop, false));
+ ph2= ph1 + strlen(ph1);
+ } // endif Hv
+
+ } // endif CheckCond
+
+ bb |= filp->Bd;
+ bh |= filp->Hv;
+ filp->Bd= filp->Hv= false;
+ } else
+ return NULL;
+
+ if (bb) {
+ strcpy(pb1, ")");
+ filp->Bd= bb;
+ } else
+ *pb0= 0;
+
+ if (havg) {
+ if (bb && bh && vop == OP_OR) {
+ // Cannot or'ed a where clause with a having clause
+ bb= bh= 0;
+ *pb0= 0;
+ *ph0= 0;
+ } else if (bh) {
+ strcpy(ph1, ")");
+ filp->Hv= bh;
+ } else
+ *ph0= 0;
+
+ } // endif havg
+
+ if (!bb && !bh)
+ return NULL;
+
+ } else if (cond->type() == COND::FUNC_ITEM) {
+ unsigned int i;
+ bool iscol, ishav= false, neg= false;
+ Item_func *condf= (Item_func *)cond;
+ Item* *args= condf->arguments();
+
+ filp->Bd= filp->Hv= false;
+
+ if (trace(1))
+ htrc("Func type=%d argnum=%d\n", condf->functype(),
+ condf->argument_count());
+
+ switch (condf->functype()) {
+ case Item_func::EQUAL_FUNC:
+ case Item_func::EQ_FUNC: vop= OP_EQ; break;
+ case Item_func::NE_FUNC: vop= OP_NE; break;
+ case Item_func::LT_FUNC: vop= OP_LT; break;
+ case Item_func::LE_FUNC: vop= OP_LE; break;
+ case Item_func::GE_FUNC: vop= OP_GE; break;
+ case Item_func::GT_FUNC: vop= OP_GT; break;
+#if MYSQL_VERSION_ID > 100200
+ case Item_func::LIKE_FUNC:
+ vop = OP_LIKE;
+ neg= ((Item_func_like*)condf)->negated;
+ break;
+#endif // VERSION_ID > 100200
+ case Item_func::ISNOTNULL_FUNC:
+ neg= true;
+ // fall through
+ case Item_func::ISNULL_FUNC: vop= OP_NULL; break;
+ case Item_func::IN_FUNC: vop= OP_IN; /* fall through */
+ case Item_func::BETWEEN:
+ ismul= true;
+ neg= ((Item_func_opt_neg *)condf)->negated;
+ break;
+ default: return NULL;
+ } // endswitch functype
+
+ if (condf->argument_count() < 2)
+ return NULL;
+ else if (ismul && tty == TYPE_AM_WMI)
+ return NULL; // Not supported by WQL
+
+ if (x && (neg || !(vop == OP_EQ || vop == OP_IN || vop == OP_NULL)))
+ return NULL;
+
+ for (i= 0; i < condf->argument_count(); i++) {
+ if (trace(1))
+ htrc("Argtype(%d)=%d\n", i, args[i]->type());
+
+ if (i >= 2 && !ismul) {
+ if (trace(1))
+ htrc("Unexpected arg for vop=%d\n", vop);
+
+ continue;
+ } // endif i
+
+ if ((iscol= args[i]->type() == COND::FIELD_ITEM)) {
+ const char *fnm;
+ ha_field_option_struct *fop;
+ Item_field *pField= (Item_field *)args[i];
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (i && (x || ismul))
+ return NULL; // IN and BETWEEN clauses should be col VOP list
+ else if (pField->field->table != table)
+ return NULL; // Field does not belong to this table
+ else if (tty != TYPE_AM_WMI && IsIndexed(pField->field))
+ return NULL; // Will be handled by ReadKey
+ else
+ fop= GetFieldOptionStruct(pField->field);
+
+ if (fop && fop->special) {
+ if (tty == TYPE_AM_TBL && !stricmp(fop->special, "TABID"))
+ fnm= "TABID";
+ else if (tty == TYPE_AM_PLG)
+ fnm= fop->special;
+ else
+ return NULL;
+
+ } else if (tty == TYPE_AM_TBL) {
+ return NULL;
+ } else {
+ bool h;
+
+ fnm= filp->Chk(pField->field->field_name.str, &h);
+
+ if (h && i && !ishav)
+ return NULL; // Having should be col VOP arg
+ else
+ ishav= h;
+
+ } // endif's
+
+ if (trace(1)) {
+ htrc("Field index=%d\n", pField->field->field_index);
+ htrc("Field name=%s\n", pField->field->field_name.str);
+ htrc("Field type=%d\n", pField->field->type());
+ htrc("Field_type=%d\n", args[i]->field_type());
+ } // endif trace
+
+ strcat((ishav ? havg : body), fnm);
+ } else if (args[i]->type() == COND::FUNC_ITEM) {
+ if (tty == TYPE_AM_MYSQL) {
+ if (!CheckCond(g, filp, args[i]))
+ return NULL;
+
+ } else
+ return NULL;
+
+ } else {
+ char buff[256];
+ String *res, tmp(buff, sizeof(buff), &my_charset_bin);
+ Item *pval= (Item *)args[i];
+ Item::Type type= args[i]->real_type();
+
+ switch (type) {
+ case COND::CONST_ITEM:
+ case COND::NULL_ITEM:
+ case COND::CACHE_ITEM:
+ break;
+ default:
+ return NULL;
+ } // endswitch type
+
+ if ((res= pval->val_str(&tmp)) == NULL)
+ return NULL; // To be clarified
+
+ if (trace(1))
+ htrc("Value=%.*s\n", res->length(), res->ptr());
+
+ // IN and BETWEEN clauses should be col VOP list
+ if (!i && (x || ismul))
+ return NULL;
+
+ if (!x) {
+ const char *p;
+ char *s= (ishav) ? havg : body;
+ uint j, k, n;
+
+ // Append the value to the filter
+ switch (args[i]->field_type()) {
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ if (tty == TYPE_AM_ODBC) {
+ strcat(s, "{ts '");
+ strncat(s, res->ptr(), res->length());
+
+ if (res->length() < 19)
+ strcat(s, &"1970-01-01 00:00:00"[res->length()]);
+
+ strcat(s, "'}");
+ break;
+ } // endif ODBC
+ // fall through
+ case MYSQL_TYPE_DATE:
+ if (tty == TYPE_AM_ODBC) {
+ strcat(s, "{d '");
+ strcat(strncat(s, res->ptr(), res->length()), "'}");
+ break;
+ } // endif ODBC
+ // fall through
+
+ case MYSQL_TYPE_TIME:
+ if (tty == TYPE_AM_ODBC) {
+ strcat(s, "{t '");
+ strcat(strncat(s, res->ptr(), res->length()), "'}");
+ break;
+ } // endif ODBC
+ // fall through
+
+ case MYSQL_TYPE_VARCHAR:
+ if (tty == TYPE_AM_ODBC && i) {
+ switch (args[0]->field_type()) {
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ strcat(s, "{ts '");
+ strncat(s, res->ptr(), res->length());
+
+ if (res->length() < 19)
+ strcat(s, &"1970-01-01 00:00:00"[res->length()]);
+
+ strcat(s, "'}");
+ break;
+ case MYSQL_TYPE_DATE:
+ strcat(s, "{d '");
+ strncat(s, res->ptr(), res->length());
+ strcat(s, "'}");
+ break;
+ case MYSQL_TYPE_TIME:
+ strcat(s, "{t '");
+ strncat(s, res->ptr(), res->length());
+ strcat(s, "'}");
+ break;
+ default:
+ j= strlen(s);
+ s[j++]= '\'';
+ p= res->ptr();
+ n= res->length();
+
+ for (k= 0; k < n; k++) {
+ if (p[k] == '\'')
+ s[j++]= '\'';
+
+ s[j++]= p[k];
+ } // endfor k
+
+ s[j++]= '\'';
+ s[j]= 0;
+ } // endswitch field type
+
+ } else {
+ j= strlen(s);
+ s[j++]= '\'';
+ p= res->ptr();
+ n= res->length();
+
+ for (k= 0; k < n; k++) {
+ if (p[k] == '\'')
+ s[j++]= '\'';
+
+ s[j++]= p[k];
+ } // endfor k
+
+ s[j++]= '\'';
+ s[j]= 0;
+ } // endif tty
+
+ break;
+ default:
+ strncat(s, res->ptr(), res->length());
+ } // endswitch field type
+
+ } else {
+ if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) {
+ // Add the command to the list
+ PCMD *ncp, cmdp= new(g) CMD(g, (char*)res->c_ptr());
+
+ for (ncp= &filp->Cmds; *ncp; ncp= &(*ncp)->Next) ;
+
+ *ncp= cmdp;
+ } else
+ return NULL;
+
+ } // endif x
+
+ } // endif's Type
+
+ if (!x) {
+ char *s= (ishav) ? havg : body;
+
+ if (!i)
+ strcat(s, GetValStr(vop, neg));
+ else if (vop == OP_XX && i == 1)
+ strcat(s, " AND ");
+ else if (vop == OP_IN)
+ strcat(s, (i == condf->argument_count() - 1) ? ")" : ",");
+
+ } // endif x
+
+ } // endfor i
+
+ if (x)
+ filp->Op= vop;
+ else if (ishav)
+ filp->Hv= true;
+ else
+ filp->Bd= true;
+
+ } else {
+ if (trace(1))
+ htrc("Unsupported condition\n");
+
+ return NULL;
+ } // endif's type
+
+ return filp;
+} // end of CheckCond
+
+
+ /**
+ Push condition down to the table handler.
+
+ @param cond Condition to be pushed. The condition tree must not be
+ modified by the caller.
+
+ @return
+ The 'remainder' condition that caller must use to filter out records.
+ NULL means the handler will not return rows that do not match the
+ passed condition.
+
+ @note
+ CONNECT handles the filtering only for table types that construct
+ an SQL or WQL query, but still leaves it to MySQL because only some
+ parts of the filter may be relevant.
+ The first suballocate finds the position where the string will be
+ constructed in the sarea. The second one does make the suballocation
+ with the proper length.
+ */
+const COND *ha_connect::cond_push(const COND *cond)
+{
+ DBUG_ENTER("ha_connect::cond_push");
+
+ if (tdbp && CondPushEnabled()) {
+ PGLOBAL& g= xp->g;
+ AMT tty= tdbp->GetAmType();
+ bool x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
+ bool b= (tty == TYPE_AM_WMI || tty == TYPE_AM_ODBC ||
+ tty == TYPE_AM_TBL || tty == TYPE_AM_MYSQL ||
+ tty == TYPE_AM_PLG || tty == TYPE_AM_JDBC || x);
+
+ // This should never happen but is done to avoid crashing
+ try {
+ if (b) {
+ PCFIL filp;
+ int rc;
+
+ if ((filp= tdbp->GetCondFil()) && tdbp->GetCond() == cond &&
+ filp->Idx == active_index && filp->Type == tty)
+ goto fin;
+
+ filp= new(g) CONDFIL(active_index, tty);
+ rc= filp->Init(g, this);
+
+ if (rc == RC_INFO) {
+ filp->Having= (char*)PlugSubAlloc(g, NULL, 256);
+ *filp->Having= 0;
+ } else if (rc == RC_FX)
+ goto fin;
+
+ filp->Body= (char*)PlugSubAlloc(g, NULL, (x) ? 128 : 0);
+ *filp->Body= 0;
+
+ if (CheckCond(g, filp, cond)) {
+ if (filp->Having && strlen(filp->Having) > 255)
+ goto fin; // Memory collapse
+
+ if (trace(1))
+ htrc("cond_push: %s\n", filp->Body);
+
+ tdbp->SetCond(cond);
+
+ if (!x)
+ PlugSubAlloc(g, NULL, strlen(filp->Body) + 1);
+ else
+ cond= NULL; // Does this work?
+
+ tdbp->SetCondFil(filp);
+ } else if (x && cond)
+ tdbp->SetCondFil(filp); // Wrong filter
+
+ } else if (tdbp->CanBeFiltered()) {
+ if (!tdbp->GetCond() || tdbp->GetCond() != cond) {
+ tdbp->SetFilter(CondFilter(g, (Item *)cond));
+
+ if (tdbp->GetFilter())
+ tdbp->SetCond(cond);
+
+ } // endif cond
+
+ } // endif tty
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+ fin:;
+ } // endif tdbp
+
+ // Let MySQL do the filtering
+ DBUG_RETURN(cond);
+} // end of cond_push
+
+/**
+ Number of rows in table. It will only be called if
+ (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
+*/
+ha_rows ha_connect::records()
+{
+ if (!valid_info)
+ info(HA_STATUS_VARIABLE);
+
+ if (tdbp)
+ return stats.records;
+ else
+ return HA_POS_ERROR;
+
+} // end of records
+
+
+int ha_connect::check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ int rc= HA_ADMIN_OK;
+ PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) :
+ (xp) ? xp->g : NULL);
+ DBUG_ENTER("ha_connect::check");
+
+ if (!g || !table || xmod != MODE_READ)
+ DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR);
+
+ // Do not close the table if it was opened yet (possible?)
+ if (IsOpened()) {
+ if (IsPartitioned() && CheckColumnList(g)) // map can have been changed
+ rc= HA_ADMIN_CORRUPT;
+ else if (tdbp->OpenDB(g)) // Rewind table
+ rc= HA_ADMIN_CORRUPT;
+
+ } else if (xp->CheckQuery(valid_query_id)) {
+ tdbp= NULL; // Not valid anymore
+
+ if (OpenTable(g, false))
+ rc= HA_ADMIN_CORRUPT;
+
+ } else // possible?
+ DBUG_RETURN(HA_ADMIN_INTERNAL_ERROR);
+
+ if (rc == HA_ADMIN_OK) {
+ TABTYPE type= GetTypeID(GetStringOption("Type", "*"));
+
+ if (IsFileType(type)) {
+ if (check_opt->flags & T_MEDIUM) {
+ // TO DO
+ do {
+ if ((rc= CntReadNext(g, tdbp)) == RC_FX)
+ break;
+
+ } while (rc != RC_EF);
+
+ rc= (rc == RC_EF) ? HA_ADMIN_OK : HA_ADMIN_CORRUPT;
+ } else if (check_opt->flags & T_EXTEND) {
+ // TO DO
+ } // endif's flags
+
+ } // endif file type
+
+ } else
+ PushWarning(g, thd, 1);
+
+ DBUG_RETURN(rc);
+} // end of check
+
+
+/**
+ Return an error message specific to this handler.
+
+ @param error error code previously returned by handler
+ @param buf pointer to String where to add error message
+
+ @return
+ Returns true if this is a temporary error
+*/
+bool ha_connect::get_error_message(int error, String* buf)
+{
+ DBUG_ENTER("ha_connect::get_error_message");
+
+ if (xp && xp->g) {
+ PGLOBAL g= xp->g;
+
+ if (trace(1))
+ htrc("GEM(%d): %s\n", error, g->Message);
+
+ buf->append(ErrConvString(g->Message, strlen(g->Message),
+ &my_charset_latin1).ptr());
+ } else
+ buf->append("Cannot retrieve error message");
+
+ DBUG_RETURN(false);
+} // end of get_error_message
+
+/**
+ Convert a filename partition name to system
+*/
+static char *decode(PGLOBAL g, const char *pn)
+ {
+ char *buf= (char*)PlugSubAlloc(g, NULL, strlen(pn) + 1);
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, strlen(pn) + 1,
+ system_charset_info,
+ pn, strlen(pn),
+ &my_charset_filename,
+ &dummy_errors);
+ buf[len]= '\0';
+ return buf;
+ } // end of decode
+
+/**
+ @brief
+ Used for opening tables. The name will be the name of the file.
+
+ @details
+ A table is opened when it needs to be opened; e.g. when a request comes in
+ for a SELECT on the table (tables are not open and closed for each request,
+ they are cached).
+
+ Called from handler.cc by handler::ha_open(). The server opens all tables by
+ calling ha_open() which then calls the handler specific open().
+
+ @note
+ For CONNECT no open can be done here because field information is not yet
+ updated. >>>>> TO BE CHECKED <<<<<
+ (Thread information could be get by using 'ha_thd')
+
+ @see
+ handler::ha_open() in handler.cc
+*/
+int ha_connect::open(const char *name, int mode, uint test_if_locked)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::open");
+
+ if (trace(1))
+ htrc("open: name=%s mode=%d test=%u\n", name, mode, test_if_locked);
+
+ if (!(share= get_share()))
+ DBUG_RETURN(1);
+
+ thr_lock_data_init(&share->lock,&lock,NULL);
+
+ // Try to get the user if possible
+ xp= GetUser(ha_thd(), xp);
+ PGLOBAL g= (xp) ? xp->g : NULL;
+
+ // Try to set the database environment
+ if (g) {
+ rc= (CntCheckDB(g, this, name)) ? (-2) : 0;
+
+ if (g->Mrr) {
+ // This should only happen for the mrr secondary handler
+ mrr= true;
+ g->Mrr= false;
+ } else
+ mrr= false;
+
+#if defined(WITH_PARTITION_STORAGE_ENGINE)
+ if (table->part_info) {
+ if (GetStringOption("Filename") || GetStringOption("Tabname")
+ || GetStringOption("Connect")) {
+ strncpy(partname, decode(g, strrchr(name, '#') + 1), sizeof(partname) - 1);
+// strcpy(partname, table->part_info->curr_part_elem->partition_name);
+// part_id= &table->part_info->full_part_field_set;
+ } else // Inward table
+ strncpy(partname, strrchr(name, slash) + 1, sizeof(partname) - 1);
+
+ part_id= &table->part_info->full_part_field_set; // Temporary
+ } // endif part_info
+#endif // WITH_PARTITION_STORAGE_ENGINE
+ } else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ DBUG_RETURN(rc);
+} // end of open
+
+/**
+ @brief
+ Make the indexes for this table
+*/
+int ha_connect::optimize(THD* thd, HA_CHECK_OPT*)
+{
+ int rc= 0;
+ PGLOBAL& g= xp->g;
+ PDBUSER dup= PlgGetUser(g);
+
+ try {
+ // Ignore error on the opt file
+ dup->Check &= ~CHK_OPT;
+ tdbp= GetTDB(g);
+ dup->Check |= CHK_OPT;
+
+ if (tdbp && !tdbp->IsRemote()) {
+ bool dop= IsTypeIndexable(GetRealType(NULL));
+ bool dox= (tdbp->GetDef()->Indexable() == 1);
+
+ if ((rc= ((PTDBASE)tdbp)->ResetTableOpt(g, dop, dox))) {
+ if (rc == RC_INFO) {
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ rc= 0;
+ } else
+ rc= HA_ERR_CRASHED_ON_USAGE; // Table must be repaired
+
+ } // endif rc
+
+ } else if (!tdbp)
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // end catch
+
+ if (rc)
+ my_message(ER_WARN_DATA_OUT_OF_RANGE, g->Message, MYF(0));
+
+ return rc;
+} // end of optimize
+
+/**
+ @brief
+ Closes a table.
+
+ @details
+ Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is
+ only used to close up temporary tables or during the process where a
+ temporary table is converted over to being a myisam table.
+
+ For sql_base.cc look at close_data_tables().
+
+ @see
+ sql_base.cc, sql_select.cc and table.cc
+*/
+int ha_connect::close(void)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::close");
+
+ // If this is called by a later query, the table may have
+ // been already closed and the tdbp is not valid anymore.
+ if (tdbp && xp->last_query_id == valid_query_id)
+ rc= CloseTable(xp->g);
+
+ DBUG_RETURN(rc);
+} // end of close
+
+
+/**
+ @brief
+ write_row() inserts a row. No extra() hint is given currently if a bulk load
+ is happening. buf() is a byte array of data. You can use the field
+ information to extract the data from the native byte array type.
+
+ @details
+ Example of this would be:
+ @code
+ for (Field **field=table->field ; *field ; field++)
+ {
+ ...
+ }
+ @endcode
+
+ See ha_tina.cc for an example of extracting all of the data as strings.
+ ha_berekly.cc has an example of how to store it intact by "packing" it
+ for ha_berkeley's own native storage type.
+
+ See the note for update_row() on auto_increments and timestamps. This
+ case also applies to write_row().
+
+ Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
+ sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
+
+ @see
+ item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
+ sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc
+*/
+int ha_connect::write_row(const uchar *buf)
+{
+ int rc= 0;
+ PGLOBAL& g= xp->g;
+ DBUG_ENTER("ha_connect::write_row");
+
+ // This is not tested yet
+ if (xmod == MODE_ALTER) {
+ if (IsPartitioned() && GetStringOption("Filename", NULL))
+ // Why does this happen now that check_if_supported_inplace_alter is called?
+ DBUG_RETURN(0); // Alter table on an outward partition table
+
+ xmod= MODE_INSERT;
+ } else if (xmod == MODE_ANY)
+ DBUG_RETURN(0); // Probably never met
+
+ // Open the table if it was not opened yet (locked)
+ if (!IsOpened() || xmod != tdbp->GetMode()) {
+ if (IsOpened())
+ CloseTable(g);
+
+ if ((rc= OpenTable(g)))
+ DBUG_RETURN(rc);
+
+ } // endif isopened
+
+#if 0 // AUTO_INCREMENT NIY
+ if (table->next_number_field && buf == table->record[0]) {
+ int error;
+
+ if ((error= update_auto_increment()))
+ return error;
+
+ } // endif nex_number_field
+#endif // 0
+
+ // Set column values from the passed pseudo record
+ if ((rc= ScanRecord(g, buf)))
+ DBUG_RETURN(rc);
+
+ // Return result code from write operation
+ if (CntWriteRow(g, tdbp)) {
+ DBUG_PRINT("write_row", ("%s", g->Message));
+ htrc("write_row: %s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else // Table is modified
+ nox= false; // Indexes to be remade
+
+ DBUG_RETURN(rc);
+} // end of write_row
+
+
+/**
+ @brief
+ Yes, update_row() does what you expect, it updates a row. old_data will have
+ the previous row record in it, while new_data will have the newest data in it.
+ Keep in mind that the server can do updates based on ordering if an ORDER BY
+ clause was used. Consecutive ordering is not guaranteed.
+
+ @details
+ Currently new_data will not have an updated auto_increament record, or
+ and updated timestamp field. You can do these for example by doing:
+ @code
+ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
+ table->timestamp_field->set_time();
+ if (table->next_number_field && record == table->record[0])
+ update_auto_increment();
+ @endcode
+
+ Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
+
+ @see
+ sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc
+*/
+int ha_connect::update_row(const uchar *old_data, const uchar *new_data)
+{
+ int rc= 0;
+ PGLOBAL& g= xp->g;
+ DBUG_ENTER("ha_connect::update_row");
+
+ if (trace(2))
+ htrc("update_row: old=%s new=%s\n", old_data, new_data);
+
+ // Check values for possible change in indexed column
+ if ((rc= CheckRecord(g, old_data, new_data)))
+ DBUG_RETURN(rc);
+
+ if (CntUpdateRow(g, tdbp)) {
+ DBUG_PRINT("update_row", ("%s", g->Message));
+ htrc("update_row CONNECT: %s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ nox= false; // Table is modified
+
+ DBUG_RETURN(rc);
+} // end of update_row
+
+
+/**
+ @brief
+ This will delete a row. buf will contain a copy of the row to be deleted.
+ The server will call this right after the current row has been called (from
+ either a previous rnd_nexT() or index call).
+
+ @details
+ If you keep a pointer to the last row or can access a primary key it will
+ make doing the deletion quite a bit easier. Keep in mind that the server does
+ not guarantee consecutive deletions. ORDER BY clauses can be used.
+
+ Called in sql_acl.cc and sql_udf.cc to manage internal table
+ information. Called in sql_delete.cc, sql_insert.cc, and
+ sql_select.cc. In sql_select it is used for removing duplicates
+ while in insert it is used for REPLACE calls.
+
+ @see
+ sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc
+*/
+int ha_connect::delete_row(const uchar *)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::delete_row");
+
+ if (CntDeleteRow(xp->g, tdbp, false)) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ htrc("delete_row CONNECT: %s\n", xp->g->Message);
+ } else
+ nox= false; // To remake indexes
+
+ DBUG_RETURN(rc);
+} // end of delete_row
+
+
+/****************************************************************************/
+/* We seem to come here at the begining of an index use. */
+/****************************************************************************/
+int ha_connect::index_init(uint idx, bool sorted)
+{
+ int rc;
+ PGLOBAL& g= xp->g;
+ DBUG_ENTER("index_init");
+
+ if (trace(1))
+ htrc("index_init: this=%p idx=%u sorted=%d\n", this, idx, sorted);
+
+ if (GetIndexType(GetRealType()) == 2) {
+ if (xmod == MODE_READ)
+ // This is a remote index
+ xmod= MODE_READX;
+
+ if (!(rc= rnd_init(0))) {
+// if (xmod == MODE_READX) {
+ active_index= idx;
+ indexing= IsUnique(idx) ? 1 : 2;
+// } else {
+// active_index= MAX_KEY;
+// indexing= 0;
+// } // endif xmod
+
+ } //endif rc
+
+ DBUG_RETURN(rc);
+ } // endif index type
+
+ if ((rc= rnd_init(0)))
+ DBUG_RETURN(rc);
+
+ if (locked == 2) {
+ // Indexes are not updated in lock write mode
+ active_index= MAX_KEY;
+ indexing= 0;
+ DBUG_RETURN(0);
+ } // endif locked
+
+ indexing= CntIndexInit(g, tdbp, (signed)idx, sorted);
+
+ if (indexing <= 0) {
+ DBUG_PRINT("index_init", ("%s", g->Message));
+ htrc("index_init CONNECT: %s\n", g->Message);
+ active_index= MAX_KEY;
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else if (tdbp->GetKindex()) {
+ if (((PTDBDOS)tdbp)->GetKindex()->GetNum_K()) {
+ if (tdbp->GetFtype() != RECFM_NAF)
+ ((PTDBDOS)tdbp)->GetTxfp()->ResetBuffer(g);
+
+ active_index= idx;
+// } else { // Void table
+// active_index= MAX_KEY;
+// indexing= 0;
+ } // endif Num
+
+ rc= 0;
+ } // endif indexing
+
+ if (trace(1))
+ htrc("index_init: rc=%d indexing=%d active_index=%d\n",
+ rc, indexing, active_index);
+
+ DBUG_RETURN(rc);
+} // end of index_init
+
+/****************************************************************************/
+/* We seem to come here at the end of an index use. */
+/****************************************************************************/
+int ha_connect::index_end()
+{
+ DBUG_ENTER("index_end");
+ active_index= MAX_KEY;
+ ds_mrr.dsmrr_close();
+ DBUG_RETURN(rnd_end());
+} // end of index_end
+
+
+/****************************************************************************/
+/* This is internally called by all indexed reading functions. */
+/****************************************************************************/
+int ha_connect::ReadIndexed(uchar *buf, OPVAL op, const key_range *kr)
+{
+ int rc;
+
+//statistic_increment(ha_read_key_count, &LOCK_status);
+
+ switch (CntIndexRead(xp->g, tdbp, op, kr, mrr)) {
+ case RC_OK:
+ xp->fnd++;
+ rc= MakeRecord((char*)buf);
+ break;
+ case RC_EF: // End of file
+ rc= HA_ERR_END_OF_FILE;
+ break;
+ case RC_NF: // Not found
+ xp->nfd++;
+ rc= (op == OP_SAME) ? HA_ERR_END_OF_FILE : HA_ERR_KEY_NOT_FOUND;
+ break;
+ default: // Read error
+ DBUG_PRINT("ReadIndexed", ("%s", xp->g->Message));
+ htrc("ReadIndexed: %s\n", xp->g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ break;
+ } // endswitch RC
+
+ if (trace(2))
+ htrc("ReadIndexed: op=%d rc=%d\n", op, rc);
+
+ table->status= (rc == RC_OK) ? 0 : STATUS_NOT_FOUND;
+ return rc;
+} // end of ReadIndexed
+
+
+#ifdef NOT_USED
+/**
+ @brief
+ Positions an index cursor to the index specified in the handle. Fetches the
+ row if available. If the key value is null, begin at the first key of the
+ index.
+*/
+int ha_connect::index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map __attribute__((unused)),
+ enum ha_rkey_function find_flag
+ __attribute__((unused)))
+{
+ DBUG_ENTER("ha_connect::index_read");
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+#endif // NOT_USED
+
+
+/****************************************************************************/
+/* This is called by handler::index_read_map. */
+/****************************************************************************/
+int ha_connect::index_read(uchar * buf, const uchar * key, uint key_len,
+ enum ha_rkey_function find_flag)
+{
+ int rc;
+ OPVAL op= OP_XX;
+ DBUG_ENTER("ha_connect::index_read");
+
+ switch(find_flag) {
+ case HA_READ_KEY_EXACT: op= OP_EQ; break;
+ case HA_READ_AFTER_KEY: op= OP_GT; break;
+ case HA_READ_KEY_OR_NEXT: op= OP_GE; break;
+ default: DBUG_RETURN(-1); break;
+ } // endswitch find_flag
+
+ if (trace(2))
+ htrc("%p index_read: op=%d\n", this, op);
+
+ if (indexing > 0) {
+ start_key.key= key;
+ start_key.length= key_len;
+ start_key.flag= find_flag;
+ start_key.keypart_map= 0;
+
+ rc= ReadIndexed(buf, op, &start_key);
+
+ if (rc == HA_ERR_INTERNAL_ERROR) {
+ nox= true; // To block making indexes
+ abort= true; // Don't rename temp file
+ } // endif rc
+
+ } else
+ rc= HA_ERR_INTERNAL_ERROR; // HA_ERR_KEY_NOT_FOUND ?
+
+ DBUG_RETURN(rc);
+} // end of index_read
+
+
+/**
+ @brief
+ Used to read forward through the index.
+*/
+int ha_connect::index_next(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_next");
+ //statistic_increment(ha_read_next_count, &LOCK_status);
+
+ if (indexing > 0)
+ rc= ReadIndexed(buf, OP_NEXT);
+ else if (!indexing)
+ rc= rnd_next(buf);
+ else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ DBUG_RETURN(rc);
+} // end of index_next
+
+
+/**
+ @brief
+ Used to read backwards through the index.
+*/
+int ha_connect::index_prev(uchar *buf)
+{
+ DBUG_ENTER("ha_connect::index_prev");
+ int rc;
+
+ if (indexing > 0) {
+ rc= ReadIndexed(buf, OP_PREV);
+ } else
+ rc= HA_ERR_WRONG_COMMAND;
+
+ DBUG_RETURN(rc);
+} // end of index_prev
+
+
+/**
+ @brief
+ index_first() asks for the first key in the index.
+
+ @details
+ Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
+
+ @see
+ opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
+*/
+int ha_connect::index_first(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_first");
+
+ if (indexing > 0)
+ rc= ReadIndexed(buf, OP_FIRST);
+ else if (indexing < 0)
+ rc= HA_ERR_INTERNAL_ERROR;
+ else if (CntRewindTable(xp->g, tdbp)) {
+ table->status= STATUS_NOT_FOUND;
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ rc= rnd_next(buf);
+
+ DBUG_RETURN(rc);
+} // end of index_first
+
+
+/**
+ @brief
+ index_last() asks for the last key in the index.
+
+ @details
+ Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc.
+
+ @see
+ opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc
+*/
+int ha_connect::index_last(uchar *buf)
+{
+ DBUG_ENTER("ha_connect::index_last");
+ int rc;
+
+ if (indexing <= 0) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ rc= ReadIndexed(buf, OP_LAST);
+
+ DBUG_RETURN(rc);
+}
+
+
+/****************************************************************************/
+/* This is called to get more rows having the same index value. */
+/****************************************************************************/
+//t ha_connect::index_next_same(uchar *buf, const uchar *key, uint keylen)
+int ha_connect::index_next_same(uchar *buf, const uchar *, uint)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::index_next_same");
+//statistic_increment(ha_read_next_count, &LOCK_status);
+
+ if (!indexing)
+ rc= rnd_next(buf);
+ else if (indexing > 0)
+ rc= ReadIndexed(buf, OP_SAME);
+ else
+ rc= HA_ERR_INTERNAL_ERROR;
+
+ DBUG_RETURN(rc);
+} // end of index_next_same
+
+
+/**
+ @brief
+ rnd_init() is called when the system wants the storage engine to do a table
+ scan. See the example in the introduction at the top of this file to see when
+ rnd_init() is called.
+
+ @details
+ Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
+ and sql_update.cc.
+
+ @note
+ We always call open and extern_lock/start_stmt before comming here.
+
+ @see
+ filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
+*/
+int ha_connect::rnd_init(bool scan)
+{
+ PGLOBAL g= ((table && table->in_use) ? GetPlug(table->in_use, xp) :
+ (xp) ? xp->g : NULL);
+ DBUG_ENTER("ha_connect::rnd_init");
+
+ // This is not tested yet
+ if (xmod == MODE_ALTER) {
+ xmod= MODE_READ;
+ alter= 1;
+ } // endif xmod
+
+ if (trace(1))
+ htrc("rnd_init: this=%p scan=%d xmod=%d alter=%d\n",
+ this, scan, xmod, alter);
+
+ if (!g || !table || xmod == MODE_INSERT)
+ DBUG_RETURN(HA_ERR_INITIALIZATION);
+
+ // Do not close the table if it was opened yet (locked?)
+ if (IsOpened()) {
+ if (IsPartitioned() && xmod != MODE_INSERT)
+ if (CheckColumnList(g)) // map can have been changed
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
+ if (tdbp->OpenDB(g)) // Rewind table
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ else
+ DBUG_RETURN(0);
+
+ } else if (xp->CheckQuery(valid_query_id))
+ tdbp= NULL; // Not valid anymore
+
+ // When updating, to avoid skipped update, force the table
+ // handler to retrieve write-only fields to be able to compare
+ // records and detect data change.
+ if (xmod == MODE_UPDATE)
+ bitmap_union(table->read_set, table->write_set);
+
+ if (OpenTable(g, xmod == MODE_DELETE))
+ DBUG_RETURN(HA_ERR_INITIALIZATION);
+
+ xp->nrd= xp->fnd= xp->nfd= 0;
+ xp->tb1= my_interval_timer();
+ DBUG_RETURN(0);
+} // end of rnd_init
+
+/**
+ @brief
+ Not described.
+
+ @note
+ The previous version said:
+ Stop scanning of table. Note that this may be called several times during
+ execution of a sub select.
+ =====> This has been moved to external lock to avoid closing subselect tables.
+*/
+int ha_connect::rnd_end()
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::rnd_end");
+
+ // If this is called by a later query, the table may have
+ // been already closed and the tdbp is not valid anymore.
+// if (tdbp && xp->last_query_id == valid_query_id)
+// rc= CloseTable(xp->g);
+
+ ds_mrr.dsmrr_close();
+ DBUG_RETURN(rc);
+} // end of rnd_end
+
+
+/**
+ @brief
+ This is called for each row of the table scan. When you run out of records
+ you should return HA_ERR_END_OF_FILE. Fill buff up with the row information.
+ The Field structure for the table is the key to getting data into buf
+ in a manner that will allow the server to understand it.
+
+ @details
+ Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc,
+ and sql_update.cc.
+
+ @see
+ filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and sql_update.cc
+*/
+int ha_connect::rnd_next(uchar *buf)
+{
+ int rc;
+ DBUG_ENTER("ha_connect::rnd_next");
+//statistic_increment(ha_read_rnd_next_count, &LOCK_status);
+
+ if (tdbp->GetMode() == MODE_ANY) {
+ // We will stop on next read
+ if (!stop) {
+ stop= true;
+ DBUG_RETURN(RC_OK);
+ } else
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ } // endif Mode
+
+ switch (CntReadNext(xp->g, tdbp)) {
+ case RC_OK:
+ rc= MakeRecord((char*)buf);
+ break;
+ case RC_EF: // End of file
+ rc= HA_ERR_END_OF_FILE;
+ break;
+ case RC_NF: // Not found
+ rc= HA_ERR_RECORD_DELETED;
+ break;
+ default: // Read error
+ htrc("rnd_next CONNECT: %s\n", xp->g->Message);
+ rc= (records()) ? HA_ERR_INTERNAL_ERROR : HA_ERR_END_OF_FILE;
+ break;
+ } // endswitch RC
+
+ if (trace(2) && (rc || !(xp->nrd++ % 16384))) {
+ ulonglong tb2= my_interval_timer();
+ double elapsed= (double) (tb2 - xp->tb1) / 1000000000ULL;
+ DBUG_PRINT("rnd_next", ("rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n",
+ rc, (uint)xp->nrd, (uint)xp->fnd,
+ (uint)xp->nfd, elapsed));
+ htrc("rnd_next: rc=%d nrd=%u fnd=%u nfd=%u sec=%.3lf\n",
+ rc, (uint)xp->nrd, (uint)xp->fnd,
+ (uint)xp->nfd, elapsed);
+ xp->tb1= tb2;
+ xp->fnd= xp->nfd= 0;
+ } // endif nrd
+
+ table->status= (!rc) ? 0 : STATUS_NOT_FOUND;
+ DBUG_RETURN(rc);
+} // end of rnd_next
+
+
+/**
+ @brief
+ position() is called after each call to rnd_next() if the data needs
+ to be ordered. You can do something like the following to store
+ the position:
+ @code
+ my_store_ptr(ref, ref_length, current_position);
+ @endcode
+
+ @details
+ The server uses ref to store data. ref_length in the above case is
+ the size needed to store current_position. ref is just a byte array
+ that the server will maintain. If you are using offsets to mark rows, then
+ current_position should be the offset. If it is a primary key like in
+ BDB, then it needs to be a primary key.
+
+ Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc.
+
+ @see
+ filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc
+*/
+void ha_connect::position(const uchar *)
+{
+ DBUG_ENTER("ha_connect::position");
+ my_store_ptr(ref, ref_length, (my_off_t)tdbp->GetRecpos());
+
+ if (trace(2))
+ htrc("position: pos=%d\n", tdbp->GetRecpos());
+
+ DBUG_VOID_RETURN;
+} // end of position
+
+
+/**
+ @brief
+ This is like rnd_next, but you are given a position to use
+ to determine the row. The position will be of the type that you stored in
+ ref. You can use my_get_ptr(pos,ref_length) to retrieve whatever key
+ or position you saved when position() was called.
+
+ @details
+ Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and sql_update.cc.
+
+ @note
+ Is this really useful? It was never called even when sorting.
+
+ @see
+ filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc
+*/
+int ha_connect::rnd_pos(uchar *buf, uchar *pos)
+{
+ int rc;
+//PTDBASE tp= (PTDBASE)tdbp;
+ DBUG_ENTER("ha_connect::rnd_pos");
+
+ if (!tdbp->SetRecpos(xp->g, (int)my_get_ptr(pos, ref_length))) {
+ if (trace(1))
+ htrc("rnd_pos: %d\n", tdbp->GetRecpos());
+
+ tdbp->SetFilter(NULL);
+ rc= rnd_next(buf);
+ } else {
+ PGLOBAL g= GetPlug((table) ? table->in_use : NULL, xp);
+// strcpy(g->Message, "Not supported by this table type");
+ my_message(ER_ILLEGAL_HA, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // endif SetRecpos
+
+ DBUG_RETURN(rc);
+} // end of rnd_pos
+
+
+/**
+ @brief
+ ::info() is used to return information to the optimizer. See my_base.h for
+ the complete description.
+
+ @details
+ Currently this table handler doesn't implement most of the fields really needed.
+ SHOW also makes use of this data.
+
+ You will probably want to have the following in your code:
+ @code
+ if (records < 2)
+ records= 2;
+ @endcode
+ The reason is that the server will optimize for cases of only a single
+ record. If, in a table scan, you don't know the number of records, it
+ will probably be better to set records to two so you can return as many
+ records as you need. Along with records, a few more variables you may wish
+ to set are:
+ records
+ deleted
+ data_file_length
+ index_file_length
+ delete_length
+ check_time
+ Take a look at the public variables in handler.h for more information.
+
+ Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc,
+ sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc,
+ sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc,
+ sql_table.cc, sql_union.cc, and sql_update.cc.
+
+ @see
+ filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, sql_delete.cc,
+ sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, sql_select.cc,
+ sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_show.cc, sql_table.cc,
+ sql_union.cc and sql_update.cc
+*/
+int ha_connect::info(uint flag)
+{
+ bool pure= false;
+ PGLOBAL g= GetPlug((table) ? table->in_use : NULL, xp);
+
+ DBUG_ENTER("ha_connect::info");
+
+ if (!g) {
+ my_message(ER_UNKNOWN_ERROR, "Cannot get g pointer", MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif g
+
+ if (trace(1))
+ htrc("%p In info: flag=%u valid_info=%d\n", this, flag, valid_info);
+
+ // tdbp must be available to get updated info
+ if (xp->CheckQuery(valid_query_id) || !tdbp) {
+
+ if (xmod == MODE_ANY || xmod == MODE_ALTER) {
+ // Pure info, not a query
+ pure= true;
+ xp->CheckCleanup(xmod == MODE_ANY && valid_query_id == 0);
+ } // endif xmod
+
+ // This is necessary for getting file length
+ if (table) {
+ if (SetDataPath(g, table->s->db.str)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif SetDataPath
+
+ } else
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR); // Should never happen
+
+ if (!(tdbp= GetTDB(g))) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif tdbp
+
+ valid_info= false;
+ } // endif tdbp
+
+ if (!valid_info) {
+ valid_info= CntInfo(g, tdbp, &xinfo);
+
+ if (((signed)xinfo.records) < 0)
+ DBUG_RETURN(HA_ERR_INITIALIZATION); // Error in Cardinality
+
+ } // endif valid_info
+
+ if (flag & HA_STATUS_VARIABLE) {
+ stats.records= xinfo.records;
+ stats.deleted= 0;
+ stats.data_file_length= xinfo.data_file_length;
+ stats.index_file_length= 0;
+ stats.delete_length= 0;
+ stats.check_time= 0;
+ stats.mean_rec_length= xinfo.mean_rec_length;
+ } // endif HA_STATUS_VARIABLE
+
+ if (flag & HA_STATUS_CONST) {
+ // This is imported from the previous handler and must be reconsidered
+ stats.max_data_file_length= 4294967295LL;
+ stats.max_index_file_length= 4398046510080LL;
+ stats.create_time= 0;
+ data_file_name= xinfo.data_file_name;
+ index_file_name= NULL;
+// sortkey= (uint) - 1; // Table is not sorted
+ ref_length= sizeof(int); // Pointer size to row
+ table->s->db_options_in_use= 03;
+ stats.block_size= 1024;
+ table->s->keys_in_use.set_prefix(table->s->keys);
+ table->s->keys_for_keyread= table->s->keys_in_use;
+// table->s->keys_for_keyread.subtract(table->s->read_only_keys);
+ table->s->db_record_offset= 0;
+ } // endif HA_STATUS_CONST
+
+ if (flag & HA_STATUS_ERRKEY) {
+ errkey= 0;
+ } // endif HA_STATUS_ERRKEY
+
+ if (flag & HA_STATUS_TIME)
+ stats.update_time= 0;
+
+ if (flag & HA_STATUS_AUTO)
+ stats.auto_increment_value= 1;
+
+ if (tdbp && pure)
+ CloseTable(g); // Not used anymore
+
+ DBUG_RETURN(0);
+} // end of info
+
+
+/**
+ @brief
+ extra() is called whenever the server wishes to send a hint to
+ the storage engine. The myisam engine implements the most hints.
+ ha_innodb.cc has the most exhaustive list of these hints.
+
+ @note
+ This is not yet implemented for CONNECT.
+
+ @see
+ ha_innodb.cc
+*/
+int ha_connect::extra(enum ha_extra_function /*operation*/)
+{
+ DBUG_ENTER("ha_connect::extra");
+ DBUG_RETURN(0);
+} // end of extra
+
+
+/**
+ @brief
+ Used to delete all rows in a table, including cases of truncate and cases where
+ the optimizer realizes that all rows will be removed as a result of an SQL statement.
+
+ @details
+ Called from item_sum.cc by Item_func_group_concat::clear(),
+ Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
+ Called from sql_delete.cc by mysql_delete().
+ Called from sql_select.cc by JOIN::reinit().
+ Called from sql_union.cc by st_select_lex_unit::exec().
+
+ @see
+ Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and
+ Item_func_group_concat::clear() in item_sum.cc;
+ mysql_delete() in sql_delete.cc;
+ JOIN::reinit() in sql_select.cc and
+ st_select_lex_unit::exec() in sql_union.cc.
+*/
+int ha_connect::delete_all_rows()
+{
+ int rc= 0;
+ PGLOBAL g= xp->g;
+ DBUG_ENTER("ha_connect::delete_all_rows");
+
+ if (tdbp && tdbp->GetUse() == USE_OPEN &&
+ tdbp->GetAmType() != TYPE_AM_XML &&
+ tdbp->GetFtype() != RECFM_NAF)
+ // Close and reopen the table so it will be deleted
+ rc= CloseTable(g);
+
+ if (!(rc= OpenTable(g))) {
+ if (CntDeleteRow(g, tdbp, true)) {
+ htrc("%s\n", g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ nox= false;
+
+ } // endif rc
+
+ DBUG_RETURN(rc);
+} // end of delete_all_rows
+
+
+static bool checkPrivileges(THD *thd, TABTYPE type, PTOS options,
+ const char *db, TABLE *table, bool quick)
+{
+ switch (type) {
+ case TAB_UNDEF:
+// case TAB_CATLG:
+ case TAB_PLG:
+ case TAB_JCT:
+ case TAB_DMY:
+ case TAB_NIY:
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Unsupported table type %s", MYF(0), options->type);
+ return true;
+
+ case TAB_DOS:
+ case TAB_FIX:
+ case TAB_BIN:
+ case TAB_CSV:
+ case TAB_FMT:
+ case TAB_DBF:
+ case TAB_XML:
+ case TAB_INI:
+ case TAB_VEC:
+ case TAB_REST:
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+#endif // BSON_SUPPORT
+ if (options->filename && *options->filename) {
+ if (!quick) {
+ char path[FN_REFLEN], dbpath[FN_REFLEN];
+
+ strcpy(dbpath, mysql_real_data_home);
+
+ if (db)
+#if defined(_WIN32)
+ strcat(strcat(dbpath, db), "\\");
+#else // !_WIN32
+ strcat(strcat(dbpath, db), "/");
+#endif // !_WIN32
+
+ (void)fn_format(path, options->filename, dbpath, "",
+ MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
+
+ if (!is_secure_file_path(path)) {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv");
+ return true;
+ } // endif path
+
+ } // endif !quick
+
+ } else
+ return false;
+
+ // Fall through
+ case TAB_MYSQL:
+ case TAB_DIR:
+ case TAB_ZIP:
+ case TAB_OEM:
+ if (table && table->pos_in_table_list) { // if SELECT
+#if MYSQL_VERSION_ID > 100200
+ Switch_to_definer_security_ctx backup_ctx(thd, table->pos_in_table_list);
+#endif // VERSION_ID > 100200
+ return check_global_access(thd, FILE_ACL);
+ } else
+ return check_global_access(thd, FILE_ACL);
+ case TAB_ODBC:
+ case TAB_JDBC:
+ case TAB_MONGO:
+ case TAB_MAC:
+ case TAB_WMI:
+ return false;
+ case TAB_TBL:
+ case TAB_XCL:
+ case TAB_PRX:
+ case TAB_OCCUR:
+ case TAB_PIVOT:
+ case TAB_VIR:
+ default:
+ // This is temporary until a solution is found
+ return false;
+ } // endswitch type
+
+ my_printf_error(ER_UNKNOWN_ERROR, "check_privileges failed", MYF(0));
+ return true;
+} // end of checkPrivileges
+
+// Check whether the user has required (file) privileges
+bool ha_connect::check_privileges(THD *thd, PTOS options, const char *dbn,
+ bool quick)
+{
+ const char *db= (dbn && *dbn) ? dbn : NULL;
+ TABTYPE type=GetRealType(options);
+
+ return checkPrivileges(thd, type, options, db, table, quick);
+} // end of check_privileges
+
+// Check that two indexes are equivalent
+bool ha_connect::IsSameIndex(PIXDEF xp1, PIXDEF xp2)
+{
+ bool b= true;
+ PKPDEF kp1, kp2;
+
+ if (stricmp(xp1->Name, xp2->Name))
+ b= false;
+ else if (xp1->Nparts != xp2->Nparts ||
+ xp1->MaxSame != xp2->MaxSame ||
+ xp1->Unique != xp2->Unique)
+ b= false;
+ else for (kp1= xp1->ToKeyParts, kp2= xp2->ToKeyParts;
+ b && (kp1 || kp2);
+ kp1= kp1->Next, kp2= kp2->Next)
+ if (!kp1 || !kp2)
+ b= false;
+ else if (stricmp(kp1->Name, kp2->Name))
+ b= false;
+ else if (kp1->Klen != kp2->Klen)
+ b= false;
+
+ return b;
+} // end of IsSameIndex
+
+MODE ha_connect::CheckMode(PGLOBAL g, THD *thd,
+ MODE newmode, bool *chk, bool *cras)
+{
+#if defined(DEVELOPMENT)
+ if (true) {
+#else
+ if (trace(65)) {
+#endif
+ LEX_STRING *query_string= thd_query_string(thd);
+ htrc("%p check_mode: cmdtype=%d\n", this, thd_sql_command(thd));
+ htrc("Cmd=%.*s\n", (int) query_string->length, query_string->str);
+ } // endif trace
+
+ // Next code is temporarily replaced until sql_command is set
+ stop= false;
+
+ if (newmode == MODE_WRITE) {
+ switch (thd_sql_command(thd)) {
+ case SQLCOM_LOCK_TABLES:
+ locked= 2; // fall through
+ case SQLCOM_CREATE_TABLE:
+ case SQLCOM_INSERT:
+ case SQLCOM_LOAD:
+ case SQLCOM_INSERT_SELECT:
+ newmode= MODE_INSERT;
+ break;
+// case SQLCOM_REPLACE:
+// case SQLCOM_REPLACE_SELECT:
+// newmode= MODE_UPDATE; // To be checked
+// break;
+ case SQLCOM_DELETE_MULTI:
+ *cras= true;
+ // fall through
+ case SQLCOM_DELETE:
+ case SQLCOM_TRUNCATE:
+ newmode= MODE_DELETE;
+ break;
+ case SQLCOM_UPDATE_MULTI:
+ *cras= true;
+ // fall through
+ case SQLCOM_UPDATE:
+ newmode= MODE_UPDATE;
+ break;
+ case SQLCOM_SELECT:
+ case SQLCOM_OPTIMIZE:
+ newmode= MODE_READ;
+ break;
+ case SQLCOM_FLUSH:
+ locked= 0;
+ // fall through
+ case SQLCOM_DROP_TABLE:
+ case SQLCOM_RENAME_TABLE:
+ newmode= MODE_ANY;
+ break;
+ case SQLCOM_CREATE_VIEW:
+ case SQLCOM_DROP_VIEW:
+ newmode= MODE_ANY;
+ break;
+ case SQLCOM_ALTER_TABLE:
+ newmode= MODE_ALTER;
+ break;
+ case SQLCOM_DROP_INDEX:
+ case SQLCOM_CREATE_INDEX:
+// if (!IsPartitioned()) {
+ newmode= MODE_ANY;
+ break;
+// } // endif partitioned
+ case SQLCOM_REPAIR: // TODO implement it
+ newmode= MODE_UPDATE;
+ break;
+ default:
+ htrc("Unsupported sql_command=%d\n", thd_sql_command(thd));
+ strcpy(g->Message, "CONNECT Unsupported command");
+ my_message(ER_NOT_ALLOWED_COMMAND, g->Message, MYF(0));
+ newmode= MODE_ERROR;
+ break;
+ } // endswitch newmode
+
+ } else if (newmode == MODE_READ) {
+ switch (thd_sql_command(thd)) {
+ case SQLCOM_CREATE_TABLE:
+ *chk= true;
+ break;
+ case SQLCOM_UPDATE_MULTI:
+ case SQLCOM_DELETE_MULTI:
+ *cras= true;
+ case SQLCOM_INSERT:
+ case SQLCOM_LOAD:
+ case SQLCOM_INSERT_SELECT:
+// case SQLCOM_REPLACE:
+// case SQLCOM_REPLACE_SELECT:
+ case SQLCOM_DELETE:
+ case SQLCOM_TRUNCATE:
+ case SQLCOM_UPDATE:
+ case SQLCOM_SELECT:
+ case SQLCOM_OPTIMIZE:
+ case SQLCOM_SET_OPTION:
+ break;
+ case SQLCOM_LOCK_TABLES:
+ locked= 1;
+ break;
+ case SQLCOM_DROP_TABLE:
+ case SQLCOM_RENAME_TABLE:
+ newmode= MODE_ANY;
+ break;
+ case SQLCOM_CREATE_VIEW:
+ case SQLCOM_DROP_VIEW:
+ case SQLCOM_CREATE_TRIGGER:
+ case SQLCOM_DROP_TRIGGER:
+ newmode= MODE_ANY;
+ break;
+ case SQLCOM_ALTER_TABLE:
+ *chk= true;
+ newmode= MODE_ALTER;
+ break;
+ case SQLCOM_DROP_INDEX:
+ case SQLCOM_CREATE_INDEX:
+// if (!IsPartitioned()) {
+ *chk= true;
+ newmode= MODE_ANY;
+ break;
+// } // endif partitioned
+
+ case SQLCOM_CHECK: // TODO implement it
+ case SQLCOM_ANALYZE: // TODO implement it
+ case SQLCOM_END: // Met in procedures: IF(EXISTS(SELECT...
+ newmode= MODE_READ;
+ break;
+ default:
+ htrc("Unsupported sql_command=%d\n", thd_sql_command(thd));
+ strcpy(g->Message, "CONNECT Unsupported command");
+ my_message(ER_NOT_ALLOWED_COMMAND, g->Message, MYF(0));
+ newmode= MODE_ERROR;
+ break;
+ } // endswitch newmode
+
+ } // endif's newmode
+
+ if (trace(1))
+ htrc("New mode=%d\n", newmode);
+
+ return newmode;
+} // end of check_mode
+
+int ha_connect::start_stmt(THD *thd, thr_lock_type lock_type)
+{
+ int rc= 0;
+ bool chk=false, cras= false;
+ MODE newmode;
+ PGLOBAL g= GetPlug(thd, xp);
+ DBUG_ENTER("ha_connect::start_stmt");
+
+ if (check_privileges(thd, GetTableOptionStruct(), table->s->db.str, true))
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
+ // Action will depend on lock_type
+ switch (lock_type) {
+ case TL_WRITE_ALLOW_WRITE:
+ case TL_WRITE_CONCURRENT_INSERT:
+ case TL_WRITE_DELAYED:
+ case TL_WRITE_DEFAULT:
+ case TL_WRITE_LOW_PRIORITY:
+ case TL_WRITE:
+ case TL_WRITE_ONLY:
+ newmode= MODE_WRITE;
+ break;
+ case TL_READ:
+ case TL_READ_WITH_SHARED_LOCKS:
+ case TL_READ_HIGH_PRIORITY:
+ case TL_READ_NO_INSERT:
+ case TL_READ_DEFAULT:
+ newmode= MODE_READ;
+ break;
+ case TL_UNLOCK:
+ default:
+ newmode= MODE_ANY;
+ break;
+ } // endswitch mode
+
+ if (newmode == MODE_ANY) {
+ if (CloseTable(g)) {
+ // Make error a warning to avoid crash
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ rc= 0;
+ } // endif Close
+
+ locked= 0;
+ xmod= MODE_ANY; // For info commands
+ DBUG_RETURN(rc);
+ } // endif MODE_ANY
+
+ newmode= CheckMode(g, thd, newmode, &chk, &cras);
+
+ if (newmode == MODE_ERROR)
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
+ DBUG_RETURN(check_stmt(g, newmode, cras));
+} // end of start_stmt
+
+/**
+ @brief
+ This create a lock on the table. If you are implementing a storage engine
+ that can handle transacations look at ha_berkely.cc to see how you will
+ want to go about doing this. Otherwise you should consider calling flock()
+ here. Hint: Read the section "locking functions for mysql" in lock.cc to understand
+ this.
+
+ @details
+ Called from lock.cc by lock_external() and unlock_external(). Also called
+ from sql_table.cc by copy_data_between_tables().
+
+ @note
+ Following what we did in the MySQL XDB handler, we use this call to actually
+ physically open the table. This could be reconsider when finalizing this handler
+ design, which means we have a better understanding of what MariaDB does.
+
+ @see
+ lock.cc by lock_external() and unlock_external() in lock.cc;
+ the section "locking functions for mysql" in lock.cc;
+ copy_data_between_tables() in sql_table.cc.
+
+*/
+int ha_connect::external_lock(THD *thd, int lock_type)
+{
+ int rc= 0;
+ bool xcheck=false, cras= false;
+ MODE newmode;
+ PTOS options= GetTableOptionStruct();
+ PGLOBAL g= GetPlug(thd, xp);
+ DBUG_ENTER("ha_connect::external_lock");
+
+ DBUG_ASSERT(thd == current_thd);
+
+ if (trace(1))
+ htrc("external_lock: this=%p thd=%p xp=%p g=%p lock_type=%d\n",
+ this, thd, xp, g, lock_type);
+
+ if (!g)
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
+ // Action will depend on lock_type
+ switch (lock_type) {
+ case F_WRLCK:
+ newmode= MODE_WRITE;
+ break;
+ case F_RDLCK:
+ newmode= MODE_READ;
+ break;
+ case F_UNLCK:
+ default:
+ newmode= MODE_ANY;
+ break;
+ } // endswitch mode
+
+ if (newmode == MODE_ANY) {
+ int sqlcom= thd_sql_command(thd);
+
+ // This is unlocking, do it by closing the table
+ if (xp->CheckQueryID() && sqlcom != SQLCOM_UNLOCK_TABLES
+ && sqlcom != SQLCOM_LOCK_TABLES
+ && sqlcom != SQLCOM_FLUSH
+ && sqlcom != SQLCOM_BEGIN
+ && sqlcom != SQLCOM_DROP_TABLE) {
+ sprintf(g->Message, "external_lock: unexpected command %d", sqlcom);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ DBUG_RETURN(0);
+ } else if (g->Xchk) {
+ if (!tdbp) {
+ if (!(tdbp= GetTDB(g))) {
+// DBUG_RETURN(HA_ERR_INTERNAL_ERROR); causes assert error
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ DBUG_RETURN(0);
+ } else if (!tdbp->GetDef()->Indexable()) {
+ sprintf(g->Message, "external_lock: Table %s is not indexable", tdbp->GetName());
+// DBUG_RETURN(HA_ERR_INTERNAL_ERROR); causes assert error
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ DBUG_RETURN(0);
+ } else if (tdbp->GetDef()->Indexable() == 1) {
+ bool oldsep= ((PCHK)g->Xchk)->oldsep;
+ bool newsep= ((PCHK)g->Xchk)->newsep;
+ PTDBDOS tdp= (PTDBDOS)tdbp;
+
+ PDOSDEF ddp= (PDOSDEF)tdp->GetDef();
+ PIXDEF xp, xp1, xp2, drp=NULL, adp= NULL;
+ PIXDEF oldpix= ((PCHK)g->Xchk)->oldpix;
+ PIXDEF newpix= ((PCHK)g->Xchk)->newpix;
+ PIXDEF *xlst, *xprc;
+
+ ddp->SetIndx(oldpix);
+
+ if (oldsep != newsep) {
+ // All indexes have to be remade
+ ddp->DeleteIndexFile(g, NULL);
+ oldpix= NULL;
+ ddp->SetIndx(NULL);
+ SetBooleanOption("Sepindex", newsep);
+ } else if (newsep) {
+ // Make the list of dropped indexes
+ xlst= &drp; xprc= &oldpix;
+
+ for (xp2= oldpix; xp2; xp2= xp) {
+ for (xp1= newpix; xp1; xp1= xp1->Next)
+ if (IsSameIndex(xp1, xp2))
+ break; // Index not to drop
+
+ xp= xp2->GetNext();
+
+ if (!xp1) {
+ *xlst= xp2;
+ *xprc= xp;
+ *(xlst= &xp2->Next)= NULL;
+ } else
+ xprc= &xp2->Next;
+
+ } // endfor xp2
+
+ if (drp) {
+ // Here we erase the index files
+ ddp->DeleteIndexFile(g, drp);
+ } // endif xp1
+
+ } else if (oldpix) {
+ // TODO: optimize the case of just adding new indexes
+ if (!newpix)
+ ddp->DeleteIndexFile(g, NULL);
+
+ oldpix= NULL; // To remake all indexes
+ ddp->SetIndx(NULL);
+ } // endif sepindex
+
+ // Make the list of new created indexes
+ xlst= &adp; xprc= &newpix;
+
+ for (xp1= newpix; xp1; xp1= xp) {
+ for (xp2= oldpix; xp2; xp2= xp2->Next)
+ if (IsSameIndex(xp1, xp2))
+ break; // Index already made
+
+ xp= xp1->Next;
+
+ if (!xp2) {
+ *xlst= xp1;
+ *xprc= xp;
+ *(xlst= &xp1->Next)= NULL;
+ } else
+ xprc= &xp1->Next;
+
+ } // endfor xp1
+
+ if (adp)
+ // Here we do make the new indexes
+ if (tdp->MakeIndex(g, adp, true) == RC_FX) {
+ // Make it a warning to avoid crash
+ //push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ // 0, g->Message);
+ //rc= 0;
+ my_message(ER_TOO_MANY_KEYS, g->Message, MYF(0));
+ rc= HA_ERR_INDEX_CORRUPT;
+ } // endif MakeIndex
+
+ } else if (tdbp->GetDef()->Indexable() == 3) {
+ if (CheckVirtualIndex(NULL)) {
+ // Make it a warning to avoid crash
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ 0, g->Message);
+ rc= 0;
+ } // endif Check
+
+ } // endif indexable
+
+ } // endif Tdbp
+
+ } // endelse Xchk
+
+ if (CloseTable(g)) {
+ // This is an error while builing index
+ // Make it a warning to avoid crash
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ rc= 0;
+ } // endif Close
+
+ locked= 0;
+ xmod= MODE_ANY; // For info commands
+ DBUG_RETURN(rc);
+ } else if (check_privileges(thd, options, table->s->db.str)) {
+ strcpy(g->Message, "This operation requires the FILE privilege");
+ htrc("%s\n", g->Message);
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif check_privileges
+
+
+ DBUG_ASSERT(table && table->s);
+
+ // Table mode depends on the query type
+ newmode= CheckMode(g, thd, newmode, &xcheck, &cras);
+
+ if (newmode == MODE_ERROR)
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
+ DBUG_RETURN(check_stmt(g, newmode, cras));
+} // end of external_lock
+
+
+int ha_connect::check_stmt(PGLOBAL g, MODE newmode, bool cras)
+{
+ int rc= 0;
+ DBUG_ENTER("ha_connect::check_stmt");
+
+ // If this is the start of a new query, cleanup the previous one
+ if (xp->CheckCleanup()) {
+ tdbp= NULL;
+ valid_info= false;
+ } // endif CheckCleanup
+
+ if (cras)
+ g->Createas= true; // To tell external tables of a multi-table command
+
+ if (trace(1))
+ htrc("Calling CntCheckDB db=%s cras=%d\n", GetDBName(NULL), cras);
+
+ // Set or reset the good database environment
+ if (CntCheckDB(g, this, GetDBName(NULL))) {
+ htrc("%p check_stmt: %s\n", this, g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ // This can NOT be called without open called first, but
+ // the table can have been closed since then
+ } else if (!tdbp || xp->CheckQuery(valid_query_id) || xmod != newmode) {
+ if (tdbp) {
+ // If this is called by a later query, the table may have
+ // been already closed and the tdbp is not valid anymore.
+ if (xp->last_query_id == valid_query_id)
+ rc= CloseTable(g);
+ else
+ tdbp= NULL;
+
+ } // endif tdbp
+
+ xmod= newmode;
+
+ // Delay open until used fields are known
+ } // endif tdbp
+
+ if (trace(1))
+ htrc("check_stmt: rc=%d\n", rc);
+
+ DBUG_RETURN(rc);
+} // end of check_stmt
+
+
+/**
+ @brief
+ The idea with handler::store_lock() is: The statement decides which locks
+ should be needed for the table. For updates/deletes/inserts we get WRITE
+ locks, for SELECT... we get read locks.
+
+ @details
+ Before adding the lock into the table lock handler (see thr_lock.c),
+ mysqld calls store lock with the requested locks. Store lock can now
+ modify a write lock to a read lock (or some other lock), ignore the
+ lock (if we don't want to use MySQL table locks at all), or add locks
+ for many tables (like we do when we are using a MERGE handler).
+
+ Berkeley DB, for example, changes all WRITE locks to TL_WRITE_ALLOW_WRITE
+ (which signals that we are doing WRITES, but are still allowing other
+ readers and writers).
+
+ When releasing locks, store_lock() is also called. In this case one
+ usually doesn't have to do anything.
+
+ In some exceptional cases MySQL may send a request for a TL_IGNORE;
+ This means that we are requesting the same lock as last time and this
+ should also be ignored. (This may happen when someone does a flush
+ table when we have opened a part of the tables, in which case mysqld
+ closes and reopens the tables and tries to get the same locks at last
+ time). In the future we will probably try to remove this.
+
+ Called from lock.cc by get_lock_data().
+
+ @note
+ In this method one should NEVER rely on table->in_use, it may, in fact,
+ refer to a different thread! (this happens if get_lock_data() is called
+ from mysql_lock_abort_for_thread() function)
+
+ @see
+ get_lock_data() in lock.cc
+*/
+THR_LOCK_DATA **ha_connect::store_lock(THD *,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
+ lock.type=lock_type;
+ *to++= &lock;
+ return to;
+}
+
+
+/**
+ Searches for a pointer to the last occurrence of the
+ character c in the string src.
+ Returns true on failure, false on success.
+*/
+static bool
+strnrchr(LEX_CSTRING *ls, const char *src, size_t length, int c)
+{
+ const char *srcend, *s;
+ for (s= srcend= src + length; s > src; s--)
+ {
+ if (s[-1] == c)
+ {
+ ls->str= s;
+ ls->length= srcend - s;
+ return false;
+ }
+ }
+ return true;
+}
+
+
+/**
+ Split filename into database and table name.
+*/
+static bool
+filename_to_dbname_and_tablename(const char *filename,
+ char *database, size_t database_size,
+ char *table, size_t table_size)
+{
+ LEX_CSTRING d, t;
+ size_t length= strlen(filename);
+
+ /* Find filename - the rightmost directory part */
+ if (strnrchr(&t, filename, length, slash) || t.length + 1 > table_size)
+ return true;
+ memcpy(table, t.str, t.length);
+ table[t.length]= '\0';
+ if (!(length-= t.length))
+ return true;
+
+ length--; /* Skip slash */
+
+ /* Find database name - the second rightmost directory part */
+ if (strnrchr(&d, filename, length, slash) || d.length + 1 > database_size)
+ return true;
+ memcpy(database, d.str, d.length);
+ database[d.length]= '\0';
+ return false;
+} // end of filename_to_dbname_and_tablename
+
+/**
+ @brief
+ Used to delete or rename a table. By the time delete_table() has been
+ called all opened references to this table will have been closed
+ (and your globally shared references released) ===> too bad!!!
+ The variable name will just be the name of the table.
+ You will need to remove or rename any files you have created at
+ this point.
+
+ @details
+ If you do not implement this, the default delete_table() is called from
+ handler.cc and it will delete all files with the file extensions returned
+ by bas_ext().
+
+ Called from handler.cc by delete_table and ha_create_table(). Only used
+ during create if the table_flag HA_DROP_BEFORE_CREATE was specified for
+ the storage engine.
+
+ @see
+ delete_table and ha_create_table() in handler.cc
+*/
+int ha_connect::delete_or_rename_table(const char *name, const char *to)
+{
+ DBUG_ENTER("ha_connect::delete_or_rename_table");
+ char db[128], tabname[128];
+ int rc= 0;
+ bool ok= false;
+ THD *thd= current_thd;
+ int sqlcom= thd_sql_command(thd);
+
+ if (trace(1)) {
+ if (to)
+ htrc("rename_table: this=%p thd=%p sqlcom=%d from=%s to=%s\n",
+ this, thd, sqlcom, name, to);
+ else
+ htrc("delete_table: this=%p thd=%p sqlcom=%d name=%s\n",
+ this, thd, sqlcom, name);
+
+ } // endif trace
+
+ if (to && (filename_to_dbname_and_tablename(to, db, sizeof(db),
+ tabname, sizeof(tabname))
+ || (*tabname == '#' && sqlcom == SQLCOM_CREATE_INDEX)))
+ DBUG_RETURN(0);
+
+ if (filename_to_dbname_and_tablename(name, db, sizeof(db),
+ tabname, sizeof(tabname))
+ || (*tabname == '#' && sqlcom == SQLCOM_CREATE_INDEX))
+ DBUG_RETURN(0);
+
+ // If a temporary file exists, all the tests below were passed
+ // successfully when making it, so they are not needed anymore
+ // in particular because they sometimes cause DBUG_ASSERT crash.
+ // Also, for partitioned tables, no test can be done because when
+ // this function is called, the .par file is already deleted and
+ // this causes the open_table_def function to fail.
+ // Not having any other clues (table and table_share are NULL)
+ // the only mean we have to test for partitioning is this:
+ if (*tabname != '#' && !strstr(tabname, "#P#")) {
+ // We have to retrieve the information about this table options.
+ ha_table_option_struct *pos;
+ char key[MAX_DBKEY_LENGTH];
+ uint key_length;
+ TABLE_SHARE *share;
+
+// if ((p= strstr(tabname, "#P#"))) won't work, see above
+// *p= 0; // Get the main the table name
+
+ key_length= tdc_create_key(key, db, tabname);
+
+ // share contains the option struct that we need
+ if (!(share= alloc_table_share(db, tabname, key, key_length)))
+ DBUG_RETURN(rc);
+
+ // Get the share info from the .frm file
+ Dummy_error_handler error_handler;
+ thd->push_internal_handler(&error_handler);
+ bool got_error= open_table_def(thd, share);
+ thd->pop_internal_handler();
+ if (!got_error && share->db_type() != connect_hton)
+ {
+ /* The .frm file is not for the connect engine. Something is wrong! */
+ got_error= 1;
+ rc= HA_ERR_INTERNAL_ERROR;
+ my_error(HA_ERR_INTERNAL_ERROR, MYF(0),
+ "TABLE_SHARE is not for the CONNECT engine");
+ }
+ if (!got_error) {
+ // Now we can work
+ if ((pos= share->option_struct)) {
+ if (check_privileges(thd, pos, db))
+ rc= HA_ERR_INTERNAL_ERROR; // ???
+ else
+ if (IsFileType(GetRealType(pos)) && !pos->filename)
+ ok= true;
+
+ } // endif pos
+
+ } // endif open_table_def
+ else
+ rc= ENOENT;
+ free_table_share(share);
+ } else // Temporary file
+ ok= true;
+
+ if (ok) {
+ // Let the base handler do the job
+ if (to)
+ rc= handler::rename_table(name, to);
+ else if ((rc= handler::delete_table(name)) == ENOENT)
+ rc= 0; // No files is not an error for CONNECT
+
+ } // endif ok
+
+ DBUG_RETURN(rc);
+} // end of delete_or_rename_table
+
+int ha_connect::delete_table(const char *name)
+{
+ return delete_or_rename_table(name, NULL);
+} // end of delete_table
+
+int ha_connect::rename_table(const char *from, const char *to)
+{
+ return delete_or_rename_table(from, to);
+} // end of rename_table
+
+/**
+ @brief
+ Given a starting key and an ending key, estimate the number of rows that
+ will exist between the two keys.
+
+ @details
+ end_key may be empty, in which case determine if start_key matches any rows.
+
+ Called from opt_range.cc by check_quick_keys().
+
+ @see
+ check_quick_keys() in opt_range.cc
+*/
+ha_rows ha_connect::records_in_range(uint inx,
+ const key_range *min_key,
+ const key_range *max_key,
+ page_range *pages)
+
+{
+ ha_rows rows;
+ DBUG_ENTER("ha_connect::records_in_range");
+
+ if (indexing < 0 || inx != active_index)
+ if (index_init(inx, false))
+ DBUG_RETURN(HA_POS_ERROR);
+
+ if (trace(1))
+ htrc("records_in_range: inx=%d indexing=%d\n", inx, indexing);
+
+ if (indexing > 0) {
+ int nval;
+ uint len[2];
+ const uchar *key[2];
+ bool incl[2];
+ key_part_map kmap[2];
+
+ key[0]= (min_key) ? min_key->key : NULL;
+ key[1]= (max_key) ? max_key->key : NULL;
+ len[0]= (min_key) ? min_key->length : 0;
+ len[1]= (max_key) ? max_key->length : 0;
+ incl[0]= (min_key) ? (min_key->flag == HA_READ_KEY_EXACT) : false;
+ incl[1]= (max_key) ? (max_key->flag == HA_READ_AFTER_KEY) : false;
+ kmap[0]= (min_key) ? min_key->keypart_map : 0;
+ kmap[1]= (max_key) ? max_key->keypart_map : 0;
+
+ if ((nval= CntIndexRange(xp->g, tdbp, key, len, incl, kmap)) < 0)
+ rows= HA_POS_ERROR;
+ else
+ rows= (ha_rows)nval;
+
+ } else if (indexing == 0)
+ rows= 100000000; // Don't use missing index
+ else
+ rows= HA_POS_ERROR;
+
+ if (trace(1))
+ htrc("records_in_range: rows=%llu\n", rows);
+
+ DBUG_RETURN(rows);
+} // end of records_in_range
+
+// Used to check whether a MYSQL table is created on itself
+bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, PCSZ host,
+ PCSZ db, PCSZ tab, PCSZ src, int port)
+{
+ if (src)
+ return false;
+ else if (host && stricmp(host, "localhost") && strcmp(host, "127.0.0.1"))
+ return false;
+ else if (db && stricmp(db, s->db.str))
+ return false;
+ else if (tab && stricmp(tab, s->table_name.str))
+ return false;
+ else if (port && port != (signed)GetDefaultPort())
+ return false;
+
+ strcpy(g->Message, "This MySQL table is defined on itself");
+ return true;
+} // end of CheckSelf
+
+/**
+ Convert an ISO-8859-1 column name to UTF-8
+*/
+static char *encode(PGLOBAL g, const char *cnm)
+ {
+ char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) * 3);
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, strlen(cnm) * 3,
+ &my_charset_utf8mb3_general_ci,
+ cnm, strlen(cnm),
+ &my_charset_latin1,
+ &dummy_errors);
+ buf[len]= '\0';
+ return buf;
+ } // end of encode
+
+/**
+ Store field definition for create.
+
+ @return
+ Return 0 if ok
+*/
+static bool add_field(String* sql, TABTYPE ttp, const char* field_name, int typ,
+ int len, int dec, char* key, uint tm, const char* rem,
+ char* dft, char* xtra, char* fmt, int flag, bool dbf, char v)
+{
+ char var = (len > 255) ? 'V' : v;
+ bool q, error = false;
+ const char* type = PLGtoMYSQLtype(typ, dbf, var);
+
+ error |= sql->append('`');
+ error |= sql->append(field_name);
+ error |= sql->append("` ");
+ error |= sql->append(type);
+
+ if (typ == TYPE_STRING ||
+ (len && typ != TYPE_DATE && (typ != TYPE_DOUBLE || dec >= 0))) {
+ error |= sql->append('(');
+ error |= sql->append_ulonglong(len);
+
+ if (typ == TYPE_DOUBLE) {
+ error |= sql->append(',');
+ // dec must be < len and < 31
+ error |= sql->append_ulonglong(MY_MIN(dec, (MY_MIN(len, 31) - 1)));
+ } else if (dec > 0 && !strcmp(type, "DECIMAL")) {
+ error |= sql->append(',');
+ // dec must be < len
+ error |= sql->append_ulonglong(MY_MIN(dec, len - 1));
+ } // endif dec
+
+ error |= sql->append(')');
+ } // endif len
+
+ if (v == 'U')
+ error |= sql->append(" UNSIGNED");
+ else if (v == 'Z')
+ error |= sql->append(" ZEROFILL");
+
+ if (key && *key) {
+ error |= sql->append(" ");
+ error |= sql->append(key);
+ } // endif key
+
+ if (tm)
+ error |= sql->append(STRING_WITH_LEN(" NOT NULL"), system_charset_info);
+
+ if (dft && *dft) {
+ error |= sql->append(" DEFAULT ");
+
+ if (typ == TYPE_DATE)
+ q = (strspn(dft, "0123456789 -:/") == strlen(dft));
+ else
+ q = !IsTypeNum(typ);
+
+ if (q) {
+ error |= sql->append("'");
+ error |= sql->append_for_single_quote(dft, strlen(dft));
+ error |= sql->append("'");
+ } else
+ error |= sql->append(dft);
+
+ } // endif dft
+
+ if (xtra && *xtra) {
+ error |= sql->append(" ");
+ error |= sql->append(xtra);
+ } // endif rem
+
+ if (rem && *rem) {
+ error |= sql->append(" COMMENT '");
+ error |= sql->append_for_single_quote(rem, strlen(rem));
+ error |= sql->append("'");
+ } // endif rem
+
+ if (fmt && *fmt) {
+ switch (ttp) {
+ case TAB_MONGO:
+ case TAB_BSON:
+ case TAB_JSON: error |= sql->append(" JPATH='"); break;
+ case TAB_XML: error |= sql->append(" XPATH='"); break;
+ default: error |= sql->append(" FIELD_FORMAT='");
+ } // endswitch ttp
+
+ error |= sql->append_for_single_quote(fmt, strlen(fmt));
+ error |= sql->append("'");
+ } // endif flag
+
+ if (flag) {
+ error |= sql->append(" FLAG=");
+ error |= sql->append_ulonglong(flag);
+ } // endif flag
+
+ error |= sql->append(',');
+ return error;
+} // end of add_field
+
+/**
+ Initialise the table share with the new columns.
+
+ @return
+ Return 0 if ok
+*/
+static int init_table_share(THD* thd,
+ TABLE_SHARE *table_s,
+ HA_CREATE_INFO *create_info,
+ String *sql)
+{
+ bool oom= false;
+ PTOS topt= table_s->option_struct;
+
+ sql->length(sql->length()-1); // remove the trailing comma
+ sql->append(')');
+
+ for (ha_create_table_option *opt= connect_table_option_list;
+ opt->name; opt++) {
+ ulonglong vull;
+ const char *vstr;
+
+ switch (opt->type) {
+ case HA_OPTION_TYPE_ULL:
+ vull= *(ulonglong*)(((char*)topt) + opt->offset);
+
+ if (vull != opt->def_value) {
+ oom|= sql->append(' ');
+ oom|= sql->append(opt->name);
+ oom|= sql->append('=');
+ oom|= sql->append_ulonglong(vull);
+ } // endif vull
+
+ break;
+ case HA_OPTION_TYPE_STRING:
+ vstr= *(char**)(((char*)topt) + opt->offset);
+
+ if (vstr) {
+ oom|= sql->append(' ');
+ oom|= sql->append(opt->name);
+ oom|= sql->append("='");
+ oom|= sql->append_for_single_quote(vstr, strlen(vstr));
+ oom|= sql->append('\'');
+ } // endif vstr
+
+ break;
+ case HA_OPTION_TYPE_BOOL:
+ vull= *(bool*)(((char*)topt) + opt->offset);
+
+ if (vull != opt->def_value) {
+ oom|= sql->append(' ');
+ oom|= sql->append(opt->name);
+ oom|= sql->append('=');
+ oom|= sql->append(vull ? "YES" : "NO");
+ } // endif vull
+
+ break;
+ default: // no enums here, good :)
+ break;
+ } // endswitch type
+
+ if (oom)
+ return HA_ERR_OUT_OF_MEM;
+
+ } // endfor opt
+
+ if (create_info->connect_string.length) {
+ oom|= sql->append(' ');
+ oom|= sql->append("CONNECTION='");
+ oom|= sql->append_for_single_quote(create_info->connect_string.str,
+ create_info->connect_string.length);
+ oom|= sql->append('\'');
+
+ if (oom)
+ return HA_ERR_OUT_OF_MEM;
+
+ } // endif string
+
+ if (create_info->default_table_charset) {
+ oom|= sql->append(' ');
+ oom|= sql->append("CHARSET=");
+ oom|= sql->append(create_info->default_table_charset->csname);
+
+ if (oom)
+ return HA_ERR_OUT_OF_MEM;
+
+ } // endif charset
+
+ if (trace(1))
+ htrc("s_init: %.*s\n", sql->length(), sql->ptr());
+
+ return table_s->init_from_sql_statement_string(thd, true,
+ sql->ptr(), sql->length());
+} // end of init_table_share
+
+/**
+ @brief
+ connect_assisted_discovery() is called when creating a table with no columns.
+
+ @details
+ When assisted discovery is used the .frm file have not already been
+ created. You can overwrite some definitions at this point but the
+ main purpose of it is to define the columns for some table types.
+
+ @note
+ this function is no more called in case of CREATE .. SELECT
+*/
+static int connect_assisted_discovery(handlerton *, THD* thd,
+ TABLE_SHARE *table_s,
+ HA_CREATE_INFO *create_info)
+{
+ char v=0;
+ PCSZ fncn= "?";
+ PCSZ user, fn, db, host, pwd, sep, tbl, src;
+ PCSZ col, ocl, rnk, pic, fcl, skc, zfn;
+ char *tab, *dsn, *shm, *dpath, *url;
+#if defined(_WIN32)
+ PCSZ nsp= NULL, cls= NULL;
+#endif // _WIN32
+//int hdr, mxe;
+ int port= 0, mxr __attribute__((unused)) = 0, rc= 0, mul= 0;
+//PCSZ tabtyp= NULL;
+#if defined(ODBC_SUPPORT)
+ POPARM sop= NULL;
+ PCSZ ucnc= NULL;
+ bool cnc= false;
+ int cto= -1, qto= -1;
+#endif // ODBC_SUPPORT
+#if defined(JAVA_SUPPORT)
+ PJPARM sjp= NULL;
+ PCSZ driver= NULL;
+#endif // JAVA_SUPPORT
+ uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
+ bool bif, ok= false, dbf= false;
+ TABTYPE ttp= TAB_UNDEF, ttr=TAB_UNDEF;
+ PQRYRES qrp= NULL;
+ PCOLRES crp;
+ PCONNECT xp= NULL;
+ PGLOBAL g= GetPlug(thd, xp);
+
+ if (!g)
+ return HA_ERR_INTERNAL_ERROR;
+
+ PTOS topt= table_s->option_struct;
+ char buf[1024];
+ String sql(buf, sizeof(buf), system_charset_info);
+
+ sql.copy(STRING_WITH_LEN("CREATE TABLE whatever ("), system_charset_info);
+ user= host= pwd= tbl= src= col= ocl= pic= fcl= skc= rnk= zfn= NULL;
+ dsn= url= NULL;
+
+ // Get the useful create options
+ ttp= GetTypeID(topt->type);
+ fn= topt->filename;
+ tab= (char*)topt->tabname;
+ src= topt->srcdef;
+ db= topt->dbname;
+ fncn= topt->catfunc;
+ fnc= GetFuncID(fncn);
+ sep= topt->separator;
+ mul= (int)topt->multiple;
+ tbl= topt->tablist;
+ col= topt->colist;
+
+ if (topt->oplist) {
+ host= GetListOption(g, "host", topt->oplist, "localhost");
+ user= GetListOption(g, "user", topt->oplist,
+ ((ttp == TAB_ODBC || ttp == TAB_JDBC) ? NULL : "root"));
+ // Default value db can come from the DBNAME=xxx option.
+ db= GetListOption(g, "database", topt->oplist, db);
+ col= GetListOption(g, "colist", topt->oplist, col);
+ ocl= GetListOption(g, "occurcol", topt->oplist, NULL);
+ pic= GetListOption(g, "pivotcol", topt->oplist, NULL);
+ fcl= GetListOption(g, "fnccol", topt->oplist, NULL);
+ skc= GetListOption(g, "skipcol", topt->oplist, NULL);
+ rnk= GetListOption(g, "rankcol", topt->oplist, NULL);
+ pwd= GetListOption(g, "password", topt->oplist);
+#if defined(_WIN32)
+ nsp= GetListOption(g, "namespace", topt->oplist);
+ cls= GetListOption(g, "class", topt->oplist);
+#endif // _WIN32
+ port= atoi(GetListOption(g, "port", topt->oplist, "0"));
+#if defined(ODBC_SUPPORT)
+// tabtyp= GetListOption(g, "Tabtype", topt->oplist, NULL);
+ mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0"));
+ cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1"));
+ qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1"));
+
+ if ((ucnc= GetListOption(g, "UseDSN", topt->oplist)))
+ cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0);
+#endif
+#if defined(JAVA_SUPPORT)
+ driver= GetListOption(g, "Driver", topt->oplist, NULL);
+#endif // JAVA_SUPPORT
+#if defined(PROMPT_OK)
+ cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0"));
+#endif // PROMPT_OK
+#if defined(ZIP_SUPPORT)
+ zfn= GetListOption(g, "Zipfile", topt->oplist, NULL);
+#endif // ZIP_SUPPORT
+ } else {
+ host= "localhost";
+ user= ((ttp == TAB_ODBC || ttp == TAB_JDBC) ? NULL : "root");
+ } // endif option_list
+
+ if (!(shm= (char*)db))
+ db= table_s->db.str; // Default value
+
+ try {
+ // Check table type
+ if (ttp == TAB_UNDEF && !topt->http) {
+ topt->type= (src) ? "MYSQL" : (tab) ? "PROXY" : "DOS";
+ ttp= GetTypeID(topt->type);
+ sprintf(g->Message, "No table_type. Was set to %s", topt->type);
+ push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, 0, g->Message);
+ } else if (ttp == TAB_NIY) {
+ sprintf(g->Message, "Unsupported table type %s", topt->type);
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+#if defined(REST_SUPPORT)
+ } else if (topt->http) {
+ if (ttp == TAB_UNDEF) {
+ ttr= TAB_JSON;
+ strcpy(g->Message, "No table_type. Was set to JSON");
+ push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, 0, g->Message);
+ } else
+ ttr= ttp;
+
+ switch (ttr) {
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+#endif // BSON_SUPPORT
+ case TAB_XML:
+ case TAB_CSV:
+ ttp = TAB_REST;
+ break;
+ default:
+ break;
+ } // endswitch type
+#endif // REST_SUPPORT
+ } // endif ttp
+
+ if (fn && *fn)
+ switch (ttp) {
+ case TAB_FMT:
+ case TAB_DBF:
+ case TAB_XML:
+ case TAB_INI:
+ case TAB_VEC:
+ case TAB_REST:
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+#endif // BSON_SUPPORT
+ if (checkPrivileges(thd, ttp, topt, db)) {
+ strcpy(g->Message, "This operation requires the FILE privilege");
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif check_privileges
+
+ break;
+ default:
+ break;
+ } // endswitch ttp
+
+ if (!tab) {
+ if (ttp == TAB_TBL) {
+ // Make tab the first table of the list
+ char *p;
+
+ if (!tbl) {
+ strcpy(g->Message, "Missing table list");
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif tbl
+
+ tab= PlugDup(g, tbl);
+
+ if ((p= strchr(tab, ',')))
+ *p= 0;
+
+ if ((p= strchr(tab, '.'))) {
+ *p= 0;
+ db= tab;
+ tab= p + 1;
+ } // endif p
+
+ } else if (ttp != TAB_ODBC || !(fnc & (FNC_TABLE | FNC_COL)))
+ tab= (char*)table_s->table_name.str; // Default value
+
+ } // endif tab
+
+ switch (ttp) {
+#if defined(ODBC_SUPPORT)
+ case TAB_ODBC:
+ dsn= strz(g, create_info->connect_string);
+
+ if (fnc & (FNC_DSN | FNC_DRIVER)) {
+ ok= true;
+#if defined(PROMPT_OK)
+ } else if (!stricmp(thd->main_security_ctx.host, "localhost")
+ && cop == 1) {
+ if ((dsn= ODBCCheckConnection(g, dsn, cop)) != NULL) {
+ thd->make_lex_string(&create_info->connect_string, dsn, strlen(dsn));
+ ok= true;
+ } // endif dsn
+#endif // PROMPT_OK
+
+ } else if (!dsn) {
+ sprintf(g->Message, "Missing %s connection string", topt->type);
+ } else {
+ // Store ODBC additional parameters
+ sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
+ sop->User= (char*)user;
+ sop->Pwd= (char*)pwd;
+ sop->Cto= cto;
+ sop->Qto= qto;
+ sop->UseCnc= cnc;
+ ok= true;
+ } // endif's
+
+ supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
+ break;
+#endif // ODBC_SUPPORT
+#if defined(JAVA_SUPPORT)
+ case TAB_JDBC:
+ if (fnc & FNC_DRIVER) {
+ ok= true;
+ } else if (!(url= strz(g, create_info->connect_string))) {
+ strcpy(g->Message, "Missing URL");
+ } else {
+ // Store JDBC additional parameters
+ int rc;
+ PJDBCDEF jdef= new(g) JDBCDEF();
+
+ jdef->SetName(create_info->alias.str);
+ sjp = (PJPARM)PlugSubAlloc(g, NULL, sizeof(JDBCPARM));
+ sjp->Driver = driver;
+ // sjp->Properties = prop;
+ sjp->Fsize = 0;
+ sjp->Scrollable = false;
+
+ if ((rc = jdef->ParseURL(g, url, false)) == RC_OK) {
+ sjp->Url = url;
+ sjp->User = (char*)user;
+ sjp->Pwd = (char*)pwd;
+ ok = true;
+ } else if (rc == RC_NF) {
+ if (jdef->GetTabname())
+ tab= (char*)jdef->GetTabname();
+
+ ok= jdef->SetParms(sjp);
+ } // endif rc
+
+ } // endif's
+
+ supfnc |= (FNC_DRIVER | FNC_TABLE);
+ break;
+#endif // JAVA_SUPPORT
+ case TAB_DBF:
+ dbf= true;
+ // fall through
+ case TAB_CSV:
+ if (!fn && fnc != FNC_NO)
+ sprintf(g->Message, "Missing %s file name", topt->type);
+ else if (sep && strlen(sep) > 1)
+ sprintf(g->Message, "Invalid separator %s", sep);
+ else
+ ok= true;
+
+ break;
+ case TAB_MYSQL:
+ ok= true;
+
+ if (create_info->connect_string.str &&
+ create_info->connect_string.length) {
+ PMYDEF mydef= new(g) MYSQLDEF();
+
+ dsn= strz(g, create_info->connect_string);
+ mydef->SetName(create_info->alias.str);
+
+ if (!mydef->ParseURL(g, dsn, false)) {
+ if (mydef->GetHostname())
+ host= mydef->GetHostname();
+
+ if (mydef->GetUsername())
+ user= mydef->GetUsername();
+
+ if (mydef->GetPassword())
+ pwd= mydef->GetPassword();
+
+ if (mydef->GetTabschema())
+ db= mydef->GetTabschema();
+
+ if (mydef->GetTabname())
+ tab= (char*)mydef->GetTabname();
+
+ if (mydef->GetPortnumber())
+ port= mydef->GetPortnumber();
+
+ } else
+ ok= false;
+
+ } else if (!user)
+ user= "root";
+
+ if (ok && CheckSelf(g, table_s, host, db, tab, src, port))
+ ok= false;
+
+ break;
+#if defined(_WIN32)
+ case TAB_WMI:
+ ok= true;
+ break;
+#endif // _WIN32
+ case TAB_PIVOT:
+ supfnc= FNC_NO;
+ // fall through
+ case TAB_PRX:
+ case TAB_TBL:
+ case TAB_XCL:
+ case TAB_OCCUR:
+ if (!src && !stricmp(tab, create_info->alias.str) &&
+ (!db || !stricmp(db, table_s->db.str)))
+ sprintf(g->Message, "A %s table cannot refer to itself", topt->type);
+ else
+ ok= true;
+
+ break;
+ case TAB_OEM:
+ if (topt->module && topt->subtype)
+ ok= true;
+ else
+ strcpy(g->Message, "Missing OEM module or subtype");
+
+ break;
+#if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT)
+ case TAB_XML:
+#endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+#endif // BSON_SUPPORT
+ dsn= strz(g, create_info->connect_string);
+
+ if (!fn && !zfn && !mul && !dsn)
+ sprintf(g->Message, "Missing %s file name", topt->type);
+ else if (dsn && !topt->tabname)
+ topt->tabname= tab;
+
+ ok= true;
+ break;
+#if defined(JAVA_SUPPORT)
+ case TAB_MONGO:
+ if (!topt->tabname)
+ topt->tabname= tab;
+
+ ok= true;
+ break;
+#endif // JAVA_SUPPORT
+#if defined(REST_SUPPORT)
+ case TAB_REST:
+ if (!topt->http)
+ strcpy(g->Message, "Missing REST HTTP option");
+ else
+ ok = true;
+
+ break;
+#endif // REST_SUPPORT
+ case TAB_VIR:
+ ok= true;
+ break;
+ default:
+ sprintf(g->Message, "Cannot get column info for table type %s", topt->type);
+ break;
+ } // endif ttp
+
+ // Check for supported catalog function
+ if (ok && !(supfnc & fnc)) {
+ sprintf(g->Message, "Unsupported catalog function %s for table type %s",
+ fncn, topt->type);
+ ok= false;
+ } // endif supfnc
+
+ if (src && fnc != FNC_NO) {
+ strcpy(g->Message, "Cannot make catalog table from srcdef");
+ ok= false;
+ } // endif src
+
+ if (ok) {
+ const char *cnm, *rem;
+ char *dft, *xtra, *key, *fmt;
+ int i, len, prec, dec, typ, flg;
+
+ if (!(dpath= SetPath(g, table_s->db.str))) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif dpath
+
+ if (src && ttp != TAB_PIVOT && ttp != TAB_ODBC && ttp != TAB_JDBC) {
+ qrp= SrcColumns(g, host, db, user, pwd, src, port);
+
+ if (qrp && ttp == TAB_OCCUR)
+ if (OcrSrcCols(g, qrp, col, ocl, rnk)) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif OcrSrcCols
+
+ } else switch (ttp) {
+ case TAB_DBF:
+ qrp= DBFColumns(g, dpath, fn, topt, fnc == FNC_COL);
+ break;
+#if defined(ODBC_SUPPORT)
+ case TAB_ODBC:
+ switch (fnc) {
+ case FNC_NO:
+ case FNC_COL:
+ if (src) {
+ qrp= ODBCSrcCols(g, dsn, (char*)src, sop);
+ src= NULL; // for next tests
+ } else
+ qrp= ODBCColumns(g, dsn, shm, tab, NULL,
+ mxr, fnc == FNC_COL, sop);
+
+ break;
+ case FNC_TABLE:
+ qrp= ODBCTables(g, dsn, shm, tab, NULL, mxr, true, sop);
+ break;
+ case FNC_DSN:
+ qrp= ODBCDataSources(g, mxr, true);
+ break;
+ case FNC_DRIVER:
+ qrp= ODBCDrivers(g, mxr, true);
+ break;
+ default:
+ sprintf(g->Message, "invalid catfunc %s", fncn);
+ break;
+ } // endswitch info
+
+ break;
+#endif // ODBC_SUPPORT
+#if defined(JAVA_SUPPORT)
+ case TAB_JDBC:
+ switch (fnc) {
+ case FNC_NO:
+ case FNC_COL:
+ if (src) {
+ qrp= JDBCSrcCols(g, (char*)src, sjp);
+ src= NULL; // for next tests
+ } else
+ qrp= JDBCColumns(g, shm, tab, NULL, mxr, fnc == FNC_COL, sjp);
+
+ break;
+ case FNC_TABLE:
+// qrp= JDBCTables(g, shm, tab, tabtyp, mxr, true, sjp);
+ qrp= JDBCTables(g, shm, tab, NULL, mxr, true, sjp);
+ break;
+#if 0
+ case FNC_DSN:
+ qrp= JDBCDataSources(g, mxr, true);
+ break;
+#endif // 0
+ case FNC_DRIVER:
+ qrp= JDBCDrivers(g, mxr, true);
+ break;
+ default:
+ sprintf(g->Message, "invalid catfunc %s", fncn);
+ break;
+ } // endswitch info
+
+ break;
+#endif // JAVA_SUPPORT
+ case TAB_MYSQL:
+ qrp= MyColumns(g, thd, host, db, user, pwd, tab,
+ NULL, port, fnc == FNC_COL);
+ break;
+ case TAB_CSV:
+ qrp= CSVColumns(g, dpath, topt, fnc == FNC_COL);
+ break;
+#if defined(_WIN32)
+ case TAB_WMI:
+ qrp= WMIColumns(g, nsp, cls, fnc == FNC_COL);
+ break;
+#endif // _WIN32
+ case TAB_PRX:
+ case TAB_TBL:
+ case TAB_XCL:
+ case TAB_OCCUR:
+ bif= fnc == FNC_COL;
+ qrp= TabColumns(g, thd, db, tab, bif);
+
+ if (!qrp && bif && fnc != FNC_COL) // tab is a view
+ qrp= MyColumns(g, thd, host, db, user, pwd, tab, NULL, port, false);
+
+ if (qrp && ttp == TAB_OCCUR && fnc != FNC_COL)
+ if (OcrColumns(g, qrp, col, ocl, rnk)) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif OcrColumns
+
+ break;
+ case TAB_PIVOT:
+ qrp= PivotColumns(g, tab, src, pic, fcl, skc, host, db, user, pwd, port);
+ break;
+ case TAB_VIR:
+ qrp= VirColumns(g, fnc == FNC_COL);
+ break;
+ case TAB_JSON:
+#if !defined(FORCE_BSON)
+ qrp= JSONColumns(g, db, dsn, topt, fnc == FNC_COL);
+ break;
+#endif // !FORCE_BSON
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+ qrp= BSONColumns(g, db, dsn, topt, fnc == FNC_COL);
+ break;
+#endif // BSON_SUPPORT
+#if defined(JAVA_SUPPORT)
+ case TAB_MONGO:
+ url= strz(g, create_info->connect_string);
+ qrp= MGOColumns(g, db, url, topt, fnc == FNC_COL);
+ break;
+#endif // JAVA_SUPPORT
+#if defined(LIBXML2_SUPPORT) || defined(DOMDOC_SUPPORT)
+ case TAB_XML:
+ qrp= XMLColumns(g, (char*)db, tab, topt, fnc == FNC_COL);
+ break;
+#endif // LIBXML2_SUPPORT || DOMDOC_SUPPORT
+#if defined(REST_SUPPORT)
+ case TAB_REST:
+ qrp = RESTColumns(g, topt, tab, (char *)db, fnc == FNC_COL);
+ break;
+#endif // REST_SUPPORT
+ case TAB_OEM:
+ qrp= OEMColumns(g, topt, tab, (char*)db, fnc == FNC_COL);
+ break;
+ default:
+ strcpy(g->Message, "System error during assisted discovery");
+ break;
+ } // endswitch ttp
+
+ if (!qrp) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif !qrp
+
+ if (fnc != FNC_NO || src || ttp == TAB_PIVOT) {
+ // Catalog like table
+ for (crp= qrp->Colresp; !rc && crp; crp= crp->Next) {
+ cnm= (ttp == TAB_PIVOT) ? crp->Name : encode(g, crp->Name);
+ typ= crp->Type;
+ len= crp->Length;
+ dec= crp->Prec;
+ flg= crp->Flag;
+ v= (crp->Kdata->IsUnsigned()) ? 'U' : crp->Var;
+ tm= (crp->Kdata->IsNullable()) ? 0 : NOT_NULL_FLAG;
+
+ if (!len && typ == TYPE_STRING)
+ len= 256; // STRBLK's have 0 length
+
+ // Now add the field
+ if (add_field(&sql, ttp, cnm, typ, len, dec, NULL, tm,
+ NULL, NULL, NULL, NULL, flg, dbf, v))
+ rc= HA_ERR_OUT_OF_MEM;
+ } // endfor crp
+
+ } else {
+ char *schem __attribute__((unused)) = NULL;
+ char *tn= NULL;
+
+ // Not a catalog table
+ if (!qrp->Nblin) {
+ if (tab)
+ sprintf(g->Message, "Cannot get columns from %s", tab);
+ else
+ strcpy(g->Message, "Fail to retrieve columns");
+
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif !nblin
+
+ // Restore language type
+ if (ttp == TAB_REST)
+ ttp = ttr;
+
+ for (i= 0; !rc && i < qrp->Nblin; i++) {
+ typ= len= prec= dec= flg= 0;
+ tm= NOT_NULL_FLAG;
+ cnm= (char*)"noname";
+ dft= xtra= key= fmt= tn= NULL;
+ v= ' ';
+ rem= NULL;
+
+ for (crp= qrp->Colresp; crp; crp= crp->Next)
+ switch (crp->Fld) {
+ case FLD_NAME:
+ if (ttp == TAB_PRX ||
+ (ttp == TAB_CSV && topt->data_charset &&
+ (!stricmp(topt->data_charset, "UTF8") ||
+ !stricmp(topt->data_charset, "UTF-8"))))
+ cnm= crp->Kdata->GetCharValue(i);
+ else
+ cnm= encode(g, crp->Kdata->GetCharValue(i));
+
+ break;
+ case FLD_TYPE:
+ typ= crp->Kdata->GetIntValue(i);
+ v= (crp->Nulls) ? crp->Nulls[i] : 0;
+ break;
+ case FLD_TYPENAME:
+ tn= crp->Kdata->GetCharValue(i);
+ break;
+ case FLD_PREC:
+ // PREC must be always before LENGTH
+ len= prec= crp->Kdata->GetIntValue(i);
+ break;
+ case FLD_LENGTH:
+ len= crp->Kdata->GetIntValue(i);
+ break;
+ case FLD_SCALE:
+ dec= (!crp->Kdata->IsNull(i)) ? crp->Kdata->GetIntValue(i) : -1;
+ break;
+ case FLD_NULL:
+ if (crp->Kdata->GetIntValue(i))
+ tm= 0; // Nullable
+
+ break;
+ case FLD_FLAG:
+ flg = crp->Kdata->GetIntValue(i);
+ break;
+ case FLD_FORMAT:
+ fmt= (crp->Kdata) ? crp->Kdata->GetCharValue(i) : NULL;
+ break;
+ case FLD_REM:
+ rem= crp->Kdata->GetCharValue(i);
+ break;
+ // case FLD_CHARSET:
+ // No good because remote table is already translated
+ // if (*(csn= crp->Kdata->GetCharValue(i)))
+ // cs= get_charset_by_name(csn, 0);
+
+ // break;
+ case FLD_DEFAULT:
+ dft= crp->Kdata->GetCharValue(i);
+ break;
+ case FLD_EXTRA:
+ xtra= crp->Kdata->GetCharValue(i);
+
+ // Auto_increment is not supported yet
+ if (!stricmp(xtra, "AUTO_INCREMENT"))
+ xtra= NULL;
+
+ break;
+ case FLD_KEY:
+ if (ttp == TAB_VIR)
+ key= crp->Kdata->GetCharValue(i);
+
+ break;
+ case FLD_SCHEM:
+#if defined(ODBC_SUPPORT) || defined(JAVA_SUPPORT)
+ if ((ttp == TAB_ODBC || ttp == TAB_JDBC) && crp->Kdata) {
+ if (schem && stricmp(schem, crp->Kdata->GetCharValue(i))) {
+ sprintf(g->Message,
+ "Several %s tables found, specify DBNAME", tab);
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } else if (!schem)
+ schem= crp->Kdata->GetCharValue(i);
+
+ } // endif ttp
+#endif // ODBC_SUPPORT || JAVA_SUPPORT
+ default:
+ break; // Ignore
+ } // endswitch Fld
+
+#if defined(ODBC_SUPPORT)
+ if (ttp == TAB_ODBC) {
+ int plgtyp;
+ bool w= false; // Wide character type
+
+ // typ must be PLG type, not SQL type
+ if (!(plgtyp= TranslateSQLType(typ, dec, prec, v, w))) {
+ if (GetTypeConv() == TPC_SKIP) {
+ // Skip this column
+ sprintf(g->Message, "Column %s skipped (unsupported type %d)",
+ cnm, typ);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ continue;
+ } else {
+ sprintf(g->Message, "Unsupported SQL type %d", typ);
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif type_conv
+
+ } else
+ typ= plgtyp;
+
+ switch (typ) {
+ case TYPE_STRING:
+ if (w) {
+ sprintf(g->Message, "Column %s is wide characters", cnm);
+ push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, 0, g->Message);
+ } // endif w
+
+ break;
+ case TYPE_DOUBLE:
+ // Some data sources do not count dec in length (prec)
+ prec += (dec + 2); // To be safe
+ break;
+ case TYPE_DECIM:
+ prec= len;
+ break;
+ default:
+ dec= 0;
+ } // endswitch typ
+
+ } else
+#endif // ODBC_SUPPORT
+#if defined(JAVA_SUPPORT)
+ if (ttp == TAB_JDBC) {
+ int plgtyp;
+
+ // typ must be PLG type, not SQL type
+ if (!(plgtyp= TranslateJDBCType(typ, tn, dec, prec, v))) {
+ if (GetTypeConv() == TPC_SKIP) {
+ // Skip this column
+ sprintf(g->Message, "Column %s skipped (unsupported type %d)",
+ cnm, typ);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ continue;
+ } else {
+ sprintf(g->Message, "Unsupported SQL type %d", typ);
+ rc= HA_ERR_INTERNAL_ERROR;
+ goto err;
+ } // endif type_conv
+
+ } else
+ typ= plgtyp;
+
+ switch (typ) {
+ case TYPE_DOUBLE:
+ case TYPE_DECIM:
+ // Some data sources do not count dec in length (prec)
+ prec += (dec + 2); // To be safe
+ break;
+ default:
+ dec= 0;
+ } // endswitch typ
+
+ } else
+#endif // ODBC_SUPPORT
+ // Make the arguments as required by add_fields
+ if (typ == TYPE_DOUBLE)
+ prec= len;
+
+ if (typ == TYPE_DATE)
+ prec= 0;
+
+ // Now add the field
+ if (add_field(&sql, ttp, cnm, typ, prec, dec, key, tm, rem, dft, xtra,
+ fmt, flg, dbf, v))
+ rc= HA_ERR_OUT_OF_MEM;
+ } // endfor i
+
+ } // endif fnc
+
+ if (!rc)
+ rc= init_table_share(thd, table_s, create_info, &sql);
+
+ //g->jump_level--;
+ //PopUser(xp);
+ //return rc;
+ } else {
+ rc= HA_ERR_UNSUPPORTED;
+ } // endif ok
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc= HA_ERR_INTERNAL_ERROR;
+ } // end catch
+
+ err:
+ if (rc)
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+
+ PopUser(xp);
+ return rc;
+} // end of connect_assisted_discovery
+
+/**
+ Get the database name from a qualified table name.
+*/
+char *ha_connect::GetDBfromName(const char *name)
+{
+ char *db, dbname[128], tbname[128];
+
+ if (filename_to_dbname_and_tablename(name, dbname, sizeof(dbname),
+ tbname, sizeof(tbname)))
+ *dbname= 0;
+
+ if (*dbname) {
+ assert(xp && xp->g);
+ db= (char*)PlugSubAlloc(xp->g, NULL, strlen(dbname + 1));
+ strcpy(db, dbname);
+ } else
+ db= NULL;
+
+ return db;
+} // end of GetDBfromName
+
+
+/**
+ @brief
+ create() is called to create a database. The variable name will have the name
+ of the table.
+
+ @details
+ When create() is called you do not need to worry about
+ opening the table. Also, the .frm file will have already been
+ created so adjusting create_info is not necessary. You can overwrite
+ the .frm file at this point if you wish to change the table
+ definition, but there are no methods currently provided for doing
+ so.
+
+ Called from handle.cc by ha_create_table().
+
+ @note
+ Currently we do some checking on the create definitions and stop
+ creating if an error is found. We wish we could change the table
+ definition such as providing a default table type. However, as said
+ above, there are no method to do so.
+
+ @see
+ ha_create_table() in handle.cc
+*/
+
+int ha_connect::create(const char *name, TABLE *table_arg,
+ HA_CREATE_INFO *create_info)
+{
+ int rc= RC_OK;
+ bool dbf, inward;
+ Field* *field;
+ Field *fp;
+ TABTYPE type;
+ TABLE *st= table; // Probably unuseful
+ THD *thd= ha_thd();
+ LEX_CSTRING cnc = table_arg->s->connect_string;
+#if defined(WITH_PARTITION_STORAGE_ENGINE)
+ partition_info *part_info= table_arg->part_info;
+#else // !WITH_PARTITION_STORAGE_ENGINE
+#define part_info 0
+#endif // !WITH_PARTITION_STORAGE_ENGINE
+ xp= GetUser(thd, xp);
+ PGLOBAL g= xp->g;
+
+ DBUG_ENTER("ha_connect::create");
+ /*
+ This assignment fixes test failures if some
+ "ALTER TABLE t1 ADD KEY(a)" query exits on ER_ACCESS_DENIED_ERROR
+ (e.g. on missing FILE_ACL). All following "CREATE TABLE" failed with
+ "ERROR 1105: CONNECT index modification should be in-place"
+ TODO: check with Olivier.
+ */
+ g->Xchk= NULL;
+ int sqlcom= thd_sql_command(table_arg->in_use);
+ PTOS options= GetTableOptionStruct(table_arg->s);
+
+ table= table_arg; // Used by called functions
+
+ if (trace(1))
+ htrc("create: this=%p thd=%p xp=%p g=%p sqlcom=%d name=%s\n",
+ this, thd, xp, g, sqlcom, GetTableName());
+
+ // CONNECT engine specific table options:
+ DBUG_ASSERT(options);
+ type= GetTypeID(options->type);
+
+ // Check table type
+ if (type == TAB_UNDEF) {
+ options->type= (options->srcdef) ? "MYSQL" :
+#if defined(REST_SUPPORT)
+ (options->http) ? "JSON" :
+#endif // REST_SUPPORT
+ (options->tabname) ? "PROXY" : "DOS";
+ type= GetTypeID(options->type);
+ sprintf(g->Message, "No table_type. Will be set to %s", options->type);
+
+ if (sqlcom == SQLCOM_CREATE_TABLE)
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+
+ } else if (type == TAB_NIY) {
+ sprintf(g->Message, "Unsupported table type %s", options->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif ttp
+
+ if (check_privileges(thd, options, GetDBfromName(name)))
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+
+ inward= IsFileType(type) && !options->filename &&
+ ((type != TAB_JSON && type != TAB_BSON) || !cnc.length);
+
+ if (options->data_charset) {
+ const CHARSET_INFO *data_charset;
+
+ if (!(data_charset= get_charset_by_csname(options->data_charset,
+ MY_CS_PRIMARY, MYF(0)))) {
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), options->data_charset);
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif charset
+
+ if (type == TAB_XML && data_charset != &my_charset_utf8mb3_general_ci) {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "DATA_CHARSET='%s' is not supported for TABLE_TYPE=XML",
+ MYF(0), options->data_charset);
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif utf8
+
+ } // endif charset
+
+ if (!g) {
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } else
+ dbf= (GetTypeID(options->type) == TAB_DBF && !options->catfunc);
+
+ // Can be null in ALTER TABLE
+ if (create_info->alias.str)
+ // Check whether a table is defined on itself
+ switch (type) {
+ case TAB_PRX:
+ case TAB_XCL:
+ case TAB_PIVOT:
+ case TAB_OCCUR:
+ if (options->srcdef) {
+ strcpy(g->Message, "Cannot check looping reference");
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ } else if (options->tabname) {
+ if (!stricmp(options->tabname, create_info->alias.str) &&
+ (!options->dbname ||
+ !stricmp(options->dbname, table_arg->s->db.str))) {
+ sprintf(g->Message, "A %s table cannot refer to itself",
+ options->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif tab
+
+ } else {
+ strcpy(g->Message, "Missing object table name or definition");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif tabname
+
+ // fall through
+ case TAB_MYSQL:
+ if (!part_info)
+ {const char *src= options->srcdef;
+ PCSZ host, db, tab= options->tabname;
+ int port;
+
+ host= GetListOption(g, "host", options->oplist, NULL);
+ db= GetStringOption("database", NULL);
+ port= atoi(GetListOption(g, "port", options->oplist, "0"));
+
+ if (create_info->connect_string.str &&
+ create_info->connect_string.length) {
+ char *dsn= strz(g, create_info->connect_string);
+ PMYDEF mydef= new(g) MYSQLDEF();
+
+ mydef->SetName(create_info->alias.str);
+
+ if (!mydef->ParseURL(g, dsn, false)) {
+ if (mydef->GetHostname())
+ host= mydef->GetHostname();
+
+ if (mydef->GetTabschema())
+ db= mydef->GetTabschema();
+
+ if (mydef->GetTabname())
+ tab= mydef->GetTabname();
+
+ if (mydef->GetPortnumber())
+ port= mydef->GetPortnumber();
+
+ } else {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif ParseURL
+
+ } // endif connect_string
+
+ if (CheckSelf(g, table_arg->s, host, db, tab, src, port)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif CheckSelf
+
+ } break;
+ default: /* do nothing */;
+ break;
+ } // endswitch ttp
+
+ if (type == TAB_XML) {
+ bool dom; // True: MS-DOM, False libxml2
+ PCSZ xsup= GetListOption(g, "Xmlsup", options->oplist, "*");
+
+ // Note that if no support is specified, the default is MS-DOM
+ // on Windows and libxml2 otherwise
+ switch (toupper(*xsup)) {
+ case '*':
+#if defined(_WIN32)
+ dom= true;
+#else // !_WIN32
+ dom= false;
+#endif // !_WIN32
+ break;
+ case 'M':
+ case 'D':
+ dom= true;
+ break;
+ default:
+ dom= false;
+ break;
+ } // endswitch xsup
+
+#if !defined(DOMDOC_SUPPORT)
+ if (dom) {
+ strcpy(g->Message, "MS-DOM not supported by this version");
+ xsup= NULL;
+ } // endif DomDoc
+#endif // !DOMDOC_SUPPORT
+
+#if !defined(LIBXML2_SUPPORT)
+ if (!dom) {
+ strcpy(g->Message, "libxml2 not supported by this version");
+ xsup= NULL;
+ } // endif Libxml2
+#endif // !LIBXML2_SUPPORT
+
+ if (!xsup) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif xsup
+
+ } // endif type
+
+ if (type == TAB_JSON) {
+ int pretty= atoi(GetListOption(g, "Pretty", options->oplist, "2"));
+
+ if (!options->lrecl && pretty != 2) {
+ sprintf(g->Message, "LRECL must be specified for pretty=%d", pretty);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif lrecl
+
+ } // endif type JSON
+
+ if (type == TAB_CSV) {
+ const char *sep= options->separator;
+
+ if (sep && strlen(sep) > 1) {
+ sprintf(g->Message, "Invalid separator %s", sep);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif sep
+
+ } // endif type CSV
+
+ // Check column types
+ for (field= table_arg->field; *field; field++) {
+ fp= *field;
+
+ if (fp->vcol_info && !fp->stored_in_db)
+ continue; // This is a virtual column
+
+ if (fp->flags & AUTO_INCREMENT_FLAG) {
+ strcpy(g->Message, "Auto_increment is not supported yet");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif flags
+
+ if (fp->flags & (BLOB_FLAG | ENUM_FLAG | SET_FLAG)) {
+ sprintf(g->Message, "Unsupported type for column %s",
+ fp->field_name.str);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif flags
+
+ if (type == TAB_VIR)
+ if (!fp->option_struct || !fp->option_struct->special) {
+ strcpy(g->Message, "Virtual tables accept only special or virtual columns");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif special
+
+ switch (fp->type()) {
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_INT24:
+ break; // Ok
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+#if 0
+ if (!fp->field_length) {
+ sprintf(g->Message, "Unsupported 0 length for column %s",
+ fp->field_name.str);
+ rc= HA_ERR_INTERNAL_ERROR;
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Unsupported 0 length for column %s",
+ MYF(0), fp->field_name.str);
+ DBUG_RETURN(rc);
+ } // endif fp
+#endif // 0
+ break; // To be checked
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ default:
+// fprintf(stderr, "Unsupported type column %s\n", fp->field_name.str);
+ sprintf(g->Message, "Unsupported type for column %s",
+ fp->field_name.str);
+ rc= HA_ERR_INTERNAL_ERROR;
+ my_printf_error(ER_UNKNOWN_ERROR, "Unsupported type for column %s",
+ MYF(0), fp->field_name.str);
+ DBUG_RETURN(rc);
+ break;
+ } // endswitch type
+
+ if ((fp)->real_maybe_null() && !IsTypeNullable(type)) {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Table type %s does not support nullable columns",
+ MYF(0), options->type);
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ } // endif !nullable
+
+ if (dbf) {
+ bool b= false;
+
+ if ((b= fp->field_name.length > 10))
+ sprintf(g->Message, "DBF: Column name '%s' is too long (max=10)",
+ fp->field_name.str);
+ else if ((b= fp->field_length > 255))
+ sprintf(g->Message, "DBF: Column length too big for '%s' (max=255)",
+ fp->field_name.str);
+
+ if (b) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ DBUG_RETURN(rc);
+ } // endif b
+
+ } // endif dbf
+
+ } // endfor field
+
+ if ((sqlcom == SQLCOM_CREATE_TABLE || *GetTableName() == '#') && inward) {
+ // The file name is not specified, create a default file in
+ // the database directory named table_name.table_type.
+ // (temporarily not done for XML because a void file causes
+ // the XML parsers to report an error on the first Insert)
+ char buf[_MAX_PATH], fn[_MAX_PATH], dbpath[_MAX_PATH], lwt[12];
+ int h;
+
+ // Check for incompatible options
+ if (options->sepindex) {
+ my_message(ER_UNKNOWN_ERROR,
+ "SEPINDEX is incompatible with unspecified file name", MYF(0));
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ } else if (GetTypeID(options->type) == TAB_VEC) {
+ if (!table->s->max_rows || options->split) {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "%s tables whose file name is unspecified cannot be split",
+ MYF(0), options->type);
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ } else if (options->header == 2) {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "header=2 is not allowed for %s tables whose file name is unspecified",
+ MYF(0), options->type);
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ } // endif's
+
+ } else if (options->zipped) {
+ my_message(ER_UNKNOWN_ERROR,
+ "ZIPPED is incompatible with unspecified file name", MYF(0));
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ } // endif's options
+
+ // Fold type to lower case
+ for (int i= 0; i < 12; i++)
+ if (!options->type[i]) {
+ lwt[i]= 0;
+ break;
+ } else
+ lwt[i]= tolower(options->type[i]);
+
+ if (part_info) {
+ char *p;
+
+ strcpy(dbpath, name);
+ p= strrchr(dbpath, slash);
+ strncpy(partname, ++p, sizeof(partname) - 1);
+ strcat(strcat(strcpy(buf, p), "."), lwt);
+ *p= 0;
+ } else {
+ strcat(strcat(strcpy(buf, GetTableName()), "."), lwt);
+ sprintf(g->Message, "No file name. Table will use %s", buf);
+
+ if (sqlcom == SQLCOM_CREATE_TABLE)
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+
+ strcat(strcat(strcpy(dbpath, "./"), table->s->db.str), "/");
+ } // endif part_info
+
+ PlugSetPath(fn, buf, dbpath);
+
+ if ((h= ::open(fn, O_CREAT | O_EXCL, 0666)) == -1) {
+ if (errno == EEXIST)
+ sprintf(g->Message, "Default file %s already exists", fn);
+ else
+ sprintf(g->Message, "Error %d creating file %s", errno, fn);
+
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ } else
+ ::close(h);
+
+ if ((type == TAB_FMT || options->readonly) && sqlcom == SQLCOM_CREATE_TABLE)
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0,
+ "Congratulation, you just created a read-only void table!");
+
+ } // endif sqlcom
+
+ if (trace(1))
+ htrc("xchk=%p createas=%d\n", g->Xchk, g->Createas);
+
+ if (options->zipped) {
+#if defined(ZIP_SUPPORT)
+ // Check whether the zip entry must be made from a file
+ PCSZ fn= GetListOption(g, "Load", options->oplist, NULL);
+
+ if (fn) {
+ char zbuf[_MAX_PATH], buf[_MAX_PATH], dbpath[_MAX_PATH];
+ PCSZ entry= GetListOption(g, "Entry", options->oplist, NULL);
+ PCSZ a= GetListOption(g, "Append", options->oplist, "NO");
+ bool append= *a == '1' || *a == 'Y' || *a == 'y' || !stricmp(a, "ON");
+ PCSZ m= GetListOption(g, "Mulentries", options->oplist, "NO");
+ bool mul= *m == '1' || *m == 'Y' || *m == 'y' || !stricmp(m, "ON");
+
+ strcat(strcat(strcpy(dbpath, "./"), table->s->db.str), "/");
+ PlugSetPath(zbuf, options->filename, dbpath);
+ PlugSetPath(buf, fn, dbpath);
+
+ if (ZipLoadFile(g, zbuf, buf, entry, append, mul)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif LoadFile
+
+ } // endif fn
+#else // !ZIP_SUPPORT
+ my_message(ER_UNKNOWN_ERROR, "Option ZIP not supported", MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+#endif // !ZIP_SUPPORT
+ } // endif zipped
+
+ // To check whether indexes have to be made or remade
+ if (!g->Xchk) {
+ PIXDEF xdp;
+
+ // We should be in CREATE TABLE, ALTER_TABLE or CREATE INDEX
+ if (!(sqlcom == SQLCOM_CREATE_TABLE || sqlcom == SQLCOM_ALTER_TABLE ||
+ sqlcom == SQLCOM_CREATE_INDEX || sqlcom == SQLCOM_DROP_INDEX))
+// (sqlcom == SQLCOM_CREATE_INDEX && part_info) ||
+// (sqlcom == SQLCOM_DROP_INDEX && part_info)))
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0,
+ "Unexpected command in create, please contact CONNECT team");
+
+ if (part_info && !inward)
+ strncpy(partname, decode(g, strrchr(name, '#') + 1), sizeof(partname) - 1);
+// strcpy(partname, part_info->curr_part_elem->partition_name);
+
+ if (g->Alchecked == 0 &&
+ (!IsFileType(type) || FileExists(options->filename, false))) {
+ if (part_info) {
+ sprintf(g->Message, "Data repartition in %s is unchecked", partname);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ } else if (sqlcom == SQLCOM_ALTER_TABLE) {
+ // This is an ALTER to CONNECT from another engine.
+ // It cannot be accepted because the table data would be modified
+ // except when the target file does not exist.
+ strcpy(g->Message, "Operation denied. Table data would be modified.");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
+ } // endif part_info
+
+ } // endif outward
+
+ // Get the index definitions
+ if ((xdp= GetIndexInfo()) || sqlcom == SQLCOM_DROP_INDEX) {
+ if (options->multiple) {
+ strcpy(g->Message, "Multiple tables are not indexable");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_UNSUPPORTED;
+ } else if (options->compressed) {
+ strcpy(g->Message, "Compressed tables are not indexable");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_UNSUPPORTED;
+ } else if (GetIndexType(type) == 1) {
+ PDBUSER dup= PlgGetUser(g);
+ PCATLG cat= (dup) ? dup->Catalog : NULL;
+
+ if (SetDataPath(g, table_arg->s->db.str)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else if (cat) {
+ if (part_info)
+ strncpy(partname,
+ decode(g, strrchr(name, (inward ? slash : '#')) + 1),
+ sizeof(partname) - 1);
+
+ if ((rc= optimize(table->in_use, NULL))) {
+ htrc("Create rc=%d %s\n", rc, g->Message);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_INTERNAL_ERROR;
+ } else
+ CloseTable(g);
+
+ } // endif cat
+
+ } else if (GetIndexType(type) == 3) {
+ if (CheckVirtualIndex(table_arg->s)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_UNSUPPORTED;
+ } // endif Check
+
+ } else if (!GetIndexType(type)) {
+ sprintf(g->Message, "Table type %s is not indexable", options->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ rc= HA_ERR_UNSUPPORTED;
+ } // endif index type
+
+ } // endif xdp
+
+ } else {
+ // This should not happen anymore with indexing new way
+ my_message(ER_UNKNOWN_ERROR,
+ "CONNECT index modification should be in-place", MYF(0));
+ DBUG_RETURN(HA_ERR_UNSUPPORTED);
+ } // endif Xchk
+
+ table= st;
+ DBUG_RETURN(rc);
+} // end of create
+
+/**
+ Used to check whether a file based outward table can be populated by
+ an ALTER TABLE command. The conditions are:
+ - file does not exist or is void
+ - user has file privilege
+*/
+bool ha_connect::FileExists(const char *fn, bool bf)
+{
+ if (!fn || !*fn)
+ return false;
+ else if (IsPartitioned() && bf)
+ return true;
+
+ if (table) {
+ const char *s;
+ char tfn[_MAX_PATH], filename[_MAX_PATH], path[_MAX_PATH];
+ bool b= false;
+ int n;
+ struct stat info;
+
+#if defined(_WIN32)
+ s= "\\";
+#else // !_WIN32
+ s= "/";
+#endif // !_WIN32
+ if (IsPartitioned()) {
+ sprintf(tfn, fn, GetPartName());
+
+ // This is to avoid an initialization error raised by the
+ // test on check_table_flags made in ha_partition::open
+ // that can fail if some partition files are empty.
+ b= true;
+ } else
+ strcpy(tfn, fn);
+
+ strcat(strcat(strcat(strcpy(path, "."), s), table->s->db.str), s);
+ PlugSetPath(filename, tfn, path);
+ n= stat(filename, &info);
+
+ if (n < 0) {
+ if (errno != ENOENT) {
+ char buf[_MAX_PATH + 20];
+
+ sprintf(buf, "Error %d for file %s", errno, filename);
+ push_warning(table->in_use, Sql_condition::WARN_LEVEL_WARN, 0, buf);
+ return true;
+ } else
+ return false;
+
+ } else
+ return (info.st_size || b) ? true : false;
+
+ } // endif table
+
+ return true;
+} // end of FileExists
+
+// Called by SameString and NoFieldOptionChange
+bool ha_connect::CheckString(PCSZ str1, PCSZ str2)
+{
+ bool b1= (!str1 || !*str1), b2= (!str2 || !*str2);
+
+ if (b1 && b2)
+ return true;
+ else if ((b1 && !b2) || (!b1 && b2) || stricmp(str1, str2))
+ return false;
+
+ return true;
+} // end of CheckString
+
+/**
+ check whether a string option have changed
+ */
+bool ha_connect::SameString(TABLE *tab, PCSZ opn)
+{
+ PCSZ str1, str2;
+
+ tshp= tab->s; // The altered table
+ str1= GetStringOption(opn);
+ tshp= NULL;
+ str2= GetStringOption(opn);
+ return CheckString(str1, str2);
+} // end of SameString
+
+/**
+ check whether a Boolean option have changed
+ */
+bool ha_connect::SameBool(TABLE *tab, PCSZ opn)
+{
+ bool b1, b2;
+
+ tshp= tab->s; // The altered table
+ b1= GetBooleanOption(opn, false);
+ tshp= NULL;
+ b2= GetBooleanOption(opn, false);
+ return (b1 == b2);
+} // end of SameBool
+
+/**
+ check whether an integer option have changed
+ */
+bool ha_connect::SameInt(TABLE *tab, PCSZ opn)
+{
+ int i1, i2;
+
+ tshp= tab->s; // The altered table
+ i1= GetIntegerOption(opn);
+ tshp= NULL;
+ i2= GetIntegerOption(opn);
+
+ if (!stricmp(opn, "lrecl"))
+ return (i1 == i2 || !i1 || !i2);
+ else if (!stricmp(opn, "ending"))
+ return (i1 == i2 || i1 <= 0 || i2 <= 0);
+ else
+ return (i1 == i2);
+
+} // end of SameInt
+
+/**
+ check whether a field option have changed
+ */
+bool ha_connect::NoFieldOptionChange(TABLE *tab)
+{
+ bool rc= true;
+ ha_field_option_struct *fop1, *fop2;
+ Field* *fld1= table->s->field;
+ Field* *fld2= tab->s->field;
+
+ for (; rc && *fld1 && *fld2; fld1++, fld2++) {
+ fop1= (*fld1)->option_struct;
+ fop2= (*fld2)->option_struct;
+
+ rc= (fop1->offset == fop2->offset &&
+ fop1->fldlen == fop2->fldlen &&
+ CheckString(fop1->dateformat, fop2->dateformat) &&
+ CheckString(fop1->fieldformat, fop2->fieldformat) &&
+ CheckString(fop1->special, fop2->special));
+ } // endfor fld
+
+ return rc;
+} // end of NoFieldOptionChange
+
+ /**
+ Check if a storage engine supports a particular alter table in-place
+
+ @param altered_table TABLE object for new version of table.
+ @param ha_alter_info Structure describing changes to be done
+ by ALTER TABLE and holding data used
+ during in-place alter.
+
+ @retval HA_ALTER_ERROR Unexpected error.
+ @retval HA_ALTER_INPLACE_NOT_SUPPORTED Not supported, must use copy.
+ @retval HA_ALTER_INPLACE_EXCLUSIVE_LOCK Supported, but requires X lock.
+ @retval HA_ALTER_INPLACE_COPY_LOCK
+ Supported, but requires SNW lock
+ during main phase. Prepare phase
+ requires X lock.
+ @retval HA_ALTER_INPLACE_SHARED_LOCK Supported, but requires SNW lock.
+ @retval HA_ALTER_INPLACE_COPY_NO_LOCK
+ Supported, concurrent reads/writes
+ allowed. However, prepare phase
+ requires X lock.
+ @retval HA_ALTER_INPLACE_NO_LOCK Supported, concurrent
+ reads/writes allowed.
+
+ @note The default implementation uses the old in-place ALTER API
+ to determine if the storage engine supports in-place ALTER or not.
+
+ @note Called without holding thr_lock.c lock.
+ */
+enum_alter_inplace_result
+ha_connect::check_if_supported_inplace_alter(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ DBUG_ENTER("check_if_supported_alter");
+
+ bool idx= false, outward= false;
+ THD *thd= ha_thd();
+ int sqlcom= thd_sql_command(thd);
+ TABTYPE newtyp, type= TAB_UNDEF;
+ HA_CREATE_INFO *create_info= ha_alter_info->create_info;
+ PTOS newopt, oldopt;
+ xp= GetUser(thd, xp);
+ PGLOBAL g= xp->g;
+
+ if (!g || !table) {
+ my_message(ER_UNKNOWN_ERROR, "Cannot check ALTER operations", MYF(0));
+ DBUG_RETURN(HA_ALTER_ERROR);
+ } // endif Xchk
+
+ newopt= altered_table->s->option_struct;
+ oldopt= table->s->option_struct;
+
+ // If this is the start of a new query, cleanup the previous one
+ if (xp->CheckCleanup()) {
+ tdbp= NULL;
+ valid_info= false;
+ } // endif CheckCleanup
+
+ g->Alchecked= 1; // Tested in create
+ g->Xchk= NULL;
+ type= GetRealType(oldopt);
+ newtyp= GetRealType(newopt);
+
+ // No copy algorithm for outward tables
+ outward= (!IsFileType(type) || (oldopt->filename && *oldopt->filename));
+
+ // Index operations
+ alter_table_operations index_operations=
+ ALTER_ADD_INDEX |
+ ALTER_DROP_INDEX |
+ ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX |
+ ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX |
+ ALTER_ADD_UNIQUE_INDEX |
+ ALTER_DROP_UNIQUE_INDEX |
+ ALTER_ADD_PK_INDEX |
+ ALTER_DROP_PK_INDEX;
+
+ alter_table_operations inplace_offline_operations=
+ ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE |
+ ALTER_COLUMN_NAME |
+ ALTER_COLUMN_DEFAULT |
+ ALTER_CHANGE_CREATE_OPTION |
+ ALTER_RENAME |
+ ALTER_PARTITIONED | index_operations;
+
+ if (ha_alter_info->handler_flags & index_operations ||
+ !SameString(altered_table, "optname") ||
+ !SameBool(altered_table, "sepindex")) {
+ if (newopt->multiple) {
+ strcpy(g->Message, "Multiple tables are not indexable");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ALTER_ERROR);
+ } else if (newopt->compressed) {
+ strcpy(g->Message, "Compressed tables are not indexable");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ALTER_ERROR);
+ } else if (GetIndexType(type) == 1) {
+ g->Xchk= new(g) XCHK;
+ PCHK xcp= (PCHK)g->Xchk;
+
+ xcp->oldpix= GetIndexInfo(table->s);
+ xcp->newpix= GetIndexInfo(altered_table->s);
+ xcp->oldsep= GetBooleanOption("sepindex", false);
+ xcp->oldsep= xcp->SetName(g, GetStringOption("optname"));
+ tshp= altered_table->s;
+ xcp->newsep= GetBooleanOption("sepindex", false);
+ xcp->newsep= xcp->SetName(g, GetStringOption("optname"));
+ tshp= NULL;
+
+ if (trace(1) && g->Xchk)
+ htrc(
+ "oldsep=%d newsep=%d oldopn=%s newopn=%s oldpix=%p newpix=%p\n",
+ xcp->oldsep, xcp->newsep,
+ SVP(xcp->oldopn), SVP(xcp->newopn),
+ xcp->oldpix, xcp->newpix);
+
+ if (sqlcom == SQLCOM_ALTER_TABLE)
+ idx= true;
+ else
+ DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
+
+ } else if (GetIndexType(type) == 3) {
+ if (CheckVirtualIndex(altered_table->s)) {
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ALTER_ERROR);
+ } // endif Check
+
+ } else if (!GetIndexType(type)) {
+ sprintf(g->Message, "Table type %s is not indexable", oldopt->type);
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ALTER_ERROR);
+ } // endif index type
+
+ } // endif index operation
+
+ if (!SameString(altered_table, "filename")) {
+ if (!outward) {
+ // Conversion to outward table is only allowed for file based
+ // tables whose file does not exist.
+ tshp= altered_table->s;
+ PCSZ fn= GetStringOption("filename");
+ tshp= NULL;
+
+ if (FileExists(fn, false)) {
+ strcpy(g->Message, "Operation denied. Table data would be lost.");
+ my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
+ DBUG_RETURN(HA_ALTER_ERROR);
+ } else
+ goto fin;
+
+ } else
+ goto fin;
+
+ } // endif filename
+
+ /* Is there at least one operation that requires copy algorithm? */
+ if (ha_alter_info->handler_flags & ~inplace_offline_operations)
+ goto fin;
+
+ /*
+ ALTER TABLE tbl_name CONVERT TO CHARACTER SET .. and
+ ALTER TABLE table_name DEFAULT CHARSET= .. most likely
+ change column charsets and so not supported in-place through
+ old API.
+
+ Changing of PACK_KEYS, MAX_ROWS and ROW_FORMAT options were
+ not supported as in-place operations in old API either.
+ */
+ if (create_info->used_fields & (HA_CREATE_USED_CHARSET |
+ HA_CREATE_USED_DEFAULT_CHARSET |
+ HA_CREATE_USED_PACK_KEYS |
+ HA_CREATE_USED_MAX_ROWS) ||
+ (table->s->row_type != create_info->row_type))
+ goto fin;
+
+#if 0
+ uint table_changes= (ha_alter_info->handler_flags &
+ ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE) ?
+ IS_EQUAL_PACK_LENGTH : IS_EQUAL_YES;
+
+ if (table->file->check_if_incompatible_data(create_info, table_changes)
+ == COMPATIBLE_DATA_YES)
+ DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
+#endif // 0
+
+ // This was in check_if_incompatible_data
+ if (NoFieldOptionChange(altered_table) &&
+ type == newtyp &&
+ SameInt(altered_table, "lrecl") &&
+ SameInt(altered_table, "elements") &&
+ SameInt(altered_table, "header") &&
+ SameInt(altered_table, "quoted") &&
+ SameInt(altered_table, "ending") &&
+ SameInt(altered_table, "compressed"))
+ DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
+
+fin:
+ if (idx) {
+ // Indexing is only supported inplace
+ my_message(ER_ALTER_OPERATION_NOT_SUPPORTED,
+ "Alter operations not supported together by CONNECT", MYF(0));
+ DBUG_RETURN(HA_ALTER_ERROR);
+ } else if (outward) {
+ if (IsFileType(type))
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0,
+ "This is an outward table, table data were not modified.");
+
+ DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
+ } else
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+
+} // end of check_if_supported_inplace_alter
+
+
+/**
+ check_if_incompatible_data() called if ALTER TABLE can't detect otherwise
+ if new and old definition are compatible
+
+ @details If there are no other explicit signs like changed number of
+ fields this function will be called by compare_tables()
+ (sql/sql_tables.cc) to decide should we rewrite whole table or only .frm
+ file.
+
+ @note: This function is no more called by check_if_supported_inplace_alter
+*/
+
+bool ha_connect::check_if_incompatible_data(HA_CREATE_INFO *, uint)
+{
+ DBUG_ENTER("ha_connect::check_if_incompatible_data");
+ // TO DO: really implement and check it.
+ push_warning(ha_thd(), Sql_condition::WARN_LEVEL_WARN, 0,
+ "Unexpected call to check_if_incompatible_data.");
+ DBUG_RETURN(COMPATIBLE_DATA_NO);
+} // end of check_if_incompatible_data
+
+/****************************************************************************
+ * CONNECT MRR implementation: use DS-MRR
+ This is just copied from myisam
+ ***************************************************************************/
+
+int ha_connect::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buf)
+{
+ return ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf);
+} // end of multi_range_read_init
+
+int ha_connect::multi_range_read_next(range_id_t *range_info)
+{
+ return ds_mrr.dsmrr_next(range_info);
+} // end of multi_range_read_next
+
+ha_rows ha_connect::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint *bufsz,
+ uint *flags, Cost_estimate *cost)
+{
+ /*
+ This call is here because there is no location where this->table would
+ already be known.
+ TODO: consider moving it into some per-query initialization call.
+ */
+ ds_mrr.init(this, table);
+
+ // MMR is implemented for "local" file based tables only
+ if (!IsFileType(GetRealType(GetTableOptionStruct())))
+ *flags|= HA_MRR_USE_DEFAULT_IMPL;
+
+ ha_rows rows= ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges,
+ bufsz, flags, cost);
+ xp->g->Mrr= !(*flags & HA_MRR_USE_DEFAULT_IMPL);
+ return rows;
+} // end of multi_range_read_info_const
+
+ha_rows ha_connect::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+ uint key_parts, uint *bufsz,
+ uint *flags, Cost_estimate *cost)
+{
+ ds_mrr.init(this, table);
+
+ // MMR is implemented for "local" file based tables only
+ if (!IsFileType(GetRealType(GetTableOptionStruct())))
+ *flags|= HA_MRR_USE_DEFAULT_IMPL;
+
+ ha_rows rows= ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz,
+ flags, cost);
+ xp->g->Mrr= !(*flags & HA_MRR_USE_DEFAULT_IMPL);
+ return rows;
+} // end of multi_range_read_info
+
+
+int ha_connect::multi_range_read_explain_info(uint mrr_mode, char *str,
+ size_t size)
+{
+ return ds_mrr.dsmrr_explain_info(mrr_mode, str, size);
+} // end of multi_range_read_explain_info
+
+/* CONNECT MRR implementation ends */
+
+#if 0
+// Does this make sens for CONNECT?
+Item *ha_connect::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
+{
+ pushed_idx_cond_keyno= keyno_arg;
+ pushed_idx_cond= idx_cond_arg;
+ in_range_check_pushed_down= TRUE;
+ if (active_index == pushed_idx_cond_keyno)
+ mi_set_index_cond_func(file, handler_index_cond_check, this);
+ return NULL;
+}
+#endif // 0
+
+
+struct st_mysql_storage_engine connect_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+/***********************************************************************/
+/* CONNECT global variables definitions. */
+/***********************************************************************/
+#if defined(XMAP)
+// Using file mapping for indexes if true
+static MYSQL_SYSVAR_BOOL(indx_map, xmap, PLUGIN_VAR_RQCMDARG,
+ "Using file mapping for indexes", NULL, NULL, 0);
+#endif // XMAP
+
+#if defined(XMSG)
+static MYSQL_SYSVAR_STR(errmsg_dir_path, msg_path,
+// PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Path to the directory where are the message files",
+// check_msg_path, update_msg_path,
+ NULL, NULL,
+ "../../../../storage/connect/"); // for testing
+#endif // XMSG
+
+#if defined(JAVA_SUPPORT)
+static MYSQL_SYSVAR_STR(jvm_path, JvmPath,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Path to the directory where is the JVM lib",
+ // check_jvm_path, update_jvm_path,
+ NULL, NULL, NULL);
+
+static MYSQL_SYSVAR_STR(class_path, ClassPath,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Java class path",
+ // check_class_path, update_class_path,
+ NULL, NULL, NULL);
+#endif // JAVA_SUPPORT
+
+
+static struct st_mysql_sys_var* connect_system_variables[]= {
+ MYSQL_SYSVAR(xtrace),
+ MYSQL_SYSVAR(conv_size),
+ MYSQL_SYSVAR(type_conv),
+#if defined(XMAP)
+ MYSQL_SYSVAR(indx_map),
+#endif // XMAP
+ MYSQL_SYSVAR(work_size),
+ MYSQL_SYSVAR(use_tempfile),
+ MYSQL_SYSVAR(exact_info),
+#if defined(XMSG) || defined(NEWMSG)
+ MYSQL_SYSVAR(msg_lang),
+#endif // XMSG || NEWMSG
+#if defined(XMSG)
+ MYSQL_SYSVAR(errmsg_dir_path),
+#endif // XMSG
+ MYSQL_SYSVAR(json_null),
+ MYSQL_SYSVAR(json_all_path),
+ MYSQL_SYSVAR(default_depth),
+ MYSQL_SYSVAR(default_prec),
+ MYSQL_SYSVAR(json_grp_size),
+#if defined(JAVA_SUPPORT)
+ MYSQL_SYSVAR(jvm_path),
+ MYSQL_SYSVAR(class_path),
+ MYSQL_SYSVAR(java_wrapper),
+#endif // JAVA_SUPPORT
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+ MYSQL_SYSVAR(enable_mongo),
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
+ MYSQL_SYSVAR(cond_push),
+#if defined(BSON_SUPPORT)
+ MYSQL_SYSVAR(force_bson),
+#endif // BSON_SUPPORT
+ NULL
+};
+
+maria_declare_plugin(connect)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &connect_storage_engine,
+ "CONNECT",
+ "Olivier Bertrand",
+ "Management of External Data (SQL/NOSQL/MED), including Rest query results",
+ PLUGIN_LICENSE_GPL,
+ connect_init_func, /* Plugin Init */
+ connect_done_func, /* Plugin Deinit */
+ 0x0107, /* version number (1.07) */
+ NULL, /* status variables */
+ connect_system_variables, /* system variables */
+ "1.07.0003", /* string version */
+ MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
+}
+maria_declare_plugin_end;
diff --git a/storage/connect/ha_connect.h b/storage/connect/ha_connect.h
new file mode 100644
index 00000000..d1aca22b
--- /dev/null
+++ b/storage/connect/ha_connect.h
@@ -0,0 +1,557 @@
+/* Copyright (C) MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/** @file ha_connect.h
+ Author Olivier Bertrand
+
+ @brief
+ The ha_connect engine is a prototype storage engine to access external data.
+
+ @see
+ /sql/handler.h and /storage/connect/ha_connect.cc
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+/****************************************************************************/
+/* mycat.h contains the TOS, PTOS, ha_table_option_struct declarations. */
+/****************************************************************************/
+#include "mycat.h"
+
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+bool MongoEnabled(void);
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
+
+/****************************************************************************/
+/* Structures used to pass info between CONNECT and ha_connect. */
+/****************************************************************************/
+typedef struct _create_xinfo {
+ char *Type; /* Retrieved from table comment */
+ char *Filename; /* Set if not standard */
+ char *IndexFN; /* Set if not standard */
+ ulonglong Maxrows; /* Estimated max nb of rows */
+ ulong Lrecl; /* Set if not default */
+ ulong Elements; /* Number of lines in blocks */
+ bool Fixed; /* False for DOS type */
+ void *Pcf; /* To list of columns */
+ void *Pxdf; /* To list of indexes */
+} CRXINFO, *PCXF;
+
+typedef struct _xinfo {
+ ulonglong data_file_length; /* Length of data file */
+ ha_rows records; /* Records in table */
+ ulong mean_rec_length; /* Physical record length */
+ char *data_file_name; /* Physical file name */
+} XINFO, *PXF;
+
+class XCHK : public BLOCK {
+public:
+ XCHK(void) {oldsep= newsep= false;
+ oldopn= newopn= NULL;
+ oldpix= newpix= NULL;}
+
+ inline char *SetName(PGLOBAL g, PCSZ name) {return PlugDup(g, name);}
+
+ bool oldsep; // Sepindex before create/alter
+ bool newsep; // Sepindex after create/alter
+ char *oldopn; // Optname before create/alter
+ char *newopn; // Optname after create/alter
+ PIXDEF oldpix; // The indexes before create/alter
+ PIXDEF newpix; // The indexes after create/alter
+}; // end of class XCHK
+
+typedef class XCHK *PCHK;
+typedef class user_connect *PCONNECT;
+typedef struct ha_field_option_struct FOS, *PFOS;
+typedef struct ha_index_option_struct XOS, *PXOS;
+
+extern handlerton *connect_hton;
+
+/**
+ structure for CREATE TABLE options (table options)
+
+ These can be specified in the CREATE TABLE:
+ CREATE TABLE ( ... ) {...here...}
+
+ ------ Was moved to mycat.h ------
+ */
+
+/**
+ structure for CREATE TABLE options (field options)
+
+ These can be specified in the CREATE TABLE per field:
+ CREATE TABLE ( field ... {...here...}, ... )
+*/
+struct ha_field_option_struct
+{
+ ulonglong offset;
+ ulonglong freq;
+ ulonglong fldlen;
+ uint opt;
+ const char *dateformat;
+ const char *fieldformat;
+ const char* jsonpath;
+ const char* xmlpath;
+ char *special;
+};
+
+/*
+ index options can be declared similarly
+ using the ha_index_option_struct structure.
+
+ Their values can be specified in the CREATE TABLE per index:
+ CREATE TABLE ( field ..., .., INDEX .... *here*, ... )
+*/
+struct ha_index_option_struct
+{
+ bool dynamic;
+ bool mapped;
+};
+
+/** @brief
+ CONNECT_SHARE is a structure that will be shared among all open handlers.
+ This example implements the minimum of what you will probably need.
+*/
+class CONNECT_SHARE : public Handler_share {
+public:
+ mysql_mutex_t mutex;
+ THR_LOCK lock;
+ CONNECT_SHARE()
+ {
+ thr_lock_init(&lock);
+ }
+ ~CONNECT_SHARE()
+ {
+ thr_lock_delete(&lock);
+ mysql_mutex_destroy(&mutex);
+ }
+};
+
+typedef class ha_connect *PHC;
+
+/** @brief
+ Class definition for the storage engine
+*/
+class ha_connect final : public handler
+{
+ THR_LOCK_DATA lock; ///< MySQL lock
+ CONNECT_SHARE *share; ///< Shared lock info
+ CONNECT_SHARE *get_share();
+
+protected:
+ char *PlugSubAllocStr(PGLOBAL g, void *memp, const char *str, size_t length)
+ {
+ char *ptr= (char*)PlgDBSubAlloc(g, memp, length + 1);
+
+ if (ptr) {
+ memcpy(ptr, str, length);
+ ptr[length]= '\0';
+ } // endif ptr
+
+ return ptr;
+ } // end of PlugSubAllocStr
+
+public:
+ ha_connect(handlerton *hton, TABLE_SHARE *table_arg);
+ ~ha_connect();
+
+ // CONNECT Implementation
+//static bool connect_init(void);
+//static bool connect_end(void);
+ TABTYPE GetRealType(PTOS pos= NULL);
+ char *GetRealString(PCSZ s);
+ PCSZ GetStringOption(PCSZ opname, PCSZ sdef= NULL);
+ PTOS GetTableOptionStruct(TABLE_SHARE *s= NULL);
+ bool GetBooleanOption(PCSZ opname, bool bdef);
+ bool SetBooleanOption(PCSZ opname, bool b);
+ int GetIntegerOption(PCSZ opname);
+ bool GetIndexOption(KEY *kp, PCSZ opname);
+ bool CheckString(PCSZ str1, PCSZ str2);
+ bool SameString(TABLE *tab, PCSZ opn);
+ bool SetIntegerOption(PCSZ opname, int n);
+ bool SameInt(TABLE *tab, PCSZ opn);
+ bool SameBool(TABLE *tab, PCSZ opn);
+ bool FileExists(const char *fn, bool bf);
+ bool NoFieldOptionChange(TABLE *tab);
+ PFOS GetFieldOptionStruct(Field *fp);
+ void *GetColumnOption(PGLOBAL g, void *field, PCOLINFO pcf);
+ PXOS GetIndexOptionStruct(KEY *kp);
+ PIXDEF GetIndexInfo(TABLE_SHARE *s= NULL);
+ bool CheckVirtualIndex(TABLE_SHARE *s);
+ PCSZ GetDBName(PCSZ name);
+ PCSZ GetTableName(void);
+ char *GetPartName(void);
+//int GetColNameLen(Field *fp);
+//char *GetColName(Field *fp);
+//void AddColName(char *cp, Field *fp);
+ TABLE *GetTable(void) {return table;}
+ bool IsSameIndex(PIXDEF xp1, PIXDEF xp2);
+ bool IsPartitioned(void);
+ bool IsUnique(uint n);
+ PCSZ GetDataPath(void) {return datapath;}
+
+ bool SetDataPath(PGLOBAL g, PCSZ path);
+ PTDB GetTDB(PGLOBAL g);
+ int OpenTable(PGLOBAL g, bool del= false);
+ bool CheckColumnList(PGLOBAL g);
+ bool IsOpened(void);
+ int CloseTable(PGLOBAL g);
+ int MakeRecord(char *buf);
+ int ScanRecord(PGLOBAL g, const uchar *buf);
+ int CheckRecord(PGLOBAL g, const uchar *oldbuf, const uchar *newbuf);
+ int ReadIndexed(uchar *buf, OPVAL op, const key_range *kr= NULL);
+ bool IsIndexed(Field *fp);
+ bool MakeKeyWhere(PGLOBAL g, PSTRG qry, OPVAL op, char q,
+ const key_range *kr);
+//inline char *Strz(LEX_STRING &ls);
+ key_range start_key;
+
+
+ /** @brief
+ The name that will be used for display purposes.
+ */
+ const char *table_type() const {return "CONNECT";}
+
+ /** @brief
+ The name of the index type that will be used for display.
+ Don't implement this method unless you really have indexes.
+ */
+ const char *index_type(uint inx);
+
+ /** @brief
+ The file extensions.
+ */
+//const char **bas_ext() const;
+
+ /**
+ Check if a storage engine supports a particular alter table in-place
+ @note Called without holding thr_lock.c lock.
+ */
+ virtual enum_alter_inplace_result
+ check_if_supported_inplace_alter(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+
+ /** @brief
+ This is a list of flags that indicate what functionality the storage engine
+ implements. The current table flags are documented in handler.h
+ */
+ ulonglong table_flags() const;
+
+ /** @brief
+ This is a bitmap of flags that indicates how the storage engine
+ implements indexes. The current index flags are documented in
+ handler.h. If you do not implement indexes, just return zero here.
+
+ @details
+ part is the key part to check. First key part is 0.
+ If all_parts is set, MySQL wants to know the flags for the combined
+ index, up to and including 'part'.
+ */
+ ulong index_flags(uint inx, uint part, bool all_parts) const;
+
+ /** @brief
+ unireg.cc will call max_supported_record_length(), max_supported_keys(),
+ max_supported_key_parts(), uint max_supported_key_length()
+ to make sure that the storage engine can handle the data it is about to
+ send. Return *real* limits of your storage engine here; MySQL will do
+ min(your_limits, MySQL_limits) automatically.
+ */
+ uint max_supported_record_length() const { return HA_MAX_REC_LENGTH; }
+
+ /** @brief
+ unireg.cc will call this to make sure that the storage engine can handle
+ the data it is about to send. Return *real* limits of your storage engine
+ here; MySQL will do min(your_limits, MySQL_limits) automatically.
+
+ @details
+ There is no need to implement ..._key_... methods if your engine doesn't
+ support indexes.
+ */
+ uint max_supported_keys() const { return 10; }
+
+ /** @brief
+ unireg.cc will call this to make sure that the storage engine can handle
+ the data it is about to send. Return *real* limits of your storage engine
+ here; MySQL will do min(your_limits, MySQL_limits) automatically.
+
+ @details
+ There is no need to implement ..._key_... methods if your engine doesn't
+ support indexes.
+ */
+ uint max_supported_key_parts() const { return 10; }
+
+ /** @brief
+ unireg.cc will call this to make sure that the storage engine can handle
+ the data it is about to send. Return *real* limits of your storage engine
+ here; MySQL will do min(your_limits, MySQL_limits) automatically.
+
+ @details
+ There is no need to implement ..._key_... methods if your engine doesn't
+ support indexes.
+ */
+ uint max_supported_key_length() const { return 255; }
+
+ /** @brief
+ Called in test_quick_select to determine if indexes should be used.
+ */
+ virtual double scan_time() { return (double) (stats.records+stats.deleted) / 20.0+10; }
+
+ /** @brief
+ This method will never be called if you do not implement indexes.
+ */
+ virtual double read_time(uint, uint, ha_rows rows)
+ { return (double) rows / 20.0+1; }
+
+ /*
+ Everything below are methods that we implement in ha_connect.cc.
+
+ Most of these methods are not obligatory, skip them and
+ MySQL will treat them as not implemented
+ */
+ virtual bool get_error_message(int error, String *buf);
+
+ /**
+ Push condition down to the table handler.
+
+ @param cond Condition to be pushed. The condition tree must not be
+ modified by the by the caller.
+
+ @return
+ The 'remainder' condition that caller must use to filter out records.
+ NULL means the handler will not return rows that do not match the
+ passed condition.
+
+ @note
+ The pushed conditions form a stack (from which one can remove the
+ last pushed condition using cond_pop).
+ The table handler filters out rows using (pushed_cond1 AND pushed_cond2
+ AND ... AND pushed_condN)
+ or less restrictive condition, depending on handler's capabilities.
+
+ handler->ha_reset() call empties the condition stack.
+ Calls to rnd_init/rnd_end, index_init/index_end etc do not affect the
+ condition stack.
+ */
+virtual const COND *cond_push(const COND *cond);
+PCFIL CheckCond(PGLOBAL g, PCFIL filp, const Item *cond);
+const char *GetValStr(OPVAL vop, bool neg);
+PFIL CondFilter(PGLOBAL g, Item *cond);
+//PFIL CheckFilter(PGLOBAL g);
+
+/** admin commands - called from mysql_admin_table */
+virtual int check(THD* thd, HA_CHECK_OPT* check_opt);
+
+ /**
+ Number of rows in table. It will only be called if
+ (table_flags() & (HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT)) != 0
+ */
+ virtual ha_rows records();
+
+ /**
+ Type of table for caching query
+ CONNECT should not use caching because its tables are external
+ data prone to me modified out of MariaDB
+ */
+ virtual uint8 table_cache_type(void)
+ {
+#if defined(MEMORY_TRACE)
+ // Temporary until bug MDEV-4771 is fixed
+ return HA_CACHE_TBL_NONTRANSACT;
+#else
+ return HA_CACHE_TBL_NOCACHE;
+#endif
+ }
+
+ /** @brief
+ We implement this in ha_connect.cc; it's a required method.
+ */
+ int open(const char *name, int mode, uint test_if_locked); // required
+
+ /** @brief
+ We implement this in ha_connect.cc; it's a required method.
+ */
+ int close(void); // required
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int write_row(const uchar *buf);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int update_row(const uchar *old_data, const uchar *new_data);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int delete_row(const uchar *buf);
+
+ // Added to the connect handler
+ int index_init(uint idx, bool sorted);
+ int index_end();
+ int index_read(uchar * buf, const uchar * key, uint key_len,
+ enum ha_rkey_function find_flag);
+ int index_next_same(uchar *buf, const uchar *key, uint keylen);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+//int index_read_map(uchar *buf, const uchar *key,
+// key_part_map keypart_map, enum ha_rkey_function find_flag);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int index_next(uchar *buf);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+int index_prev(uchar *buf);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int index_first(uchar *buf);
+
+ /** @brief
+ We implement this in ha_connect.cc. It's not an obligatory method;
+ skip it and and MySQL will treat it as not implemented.
+ */
+ int index_last(uchar *buf);
+
+ /* Index condition pushdown implementation */
+//Item *idx_cond_push(uint keyno, Item* idx_cond);
+
+ /** @brief
+ Unlike index_init(), rnd_init() can be called two consecutive times
+ without rnd_end() in between (it only makes sense if scan=1). In this
+ case, the second call should prepare for the new table scan (e.g if
+ rnd_init() allocates the cursor, the second call should position the
+ cursor to the start of the table; no need to deallocate and allocate
+ it again. This is a required method.
+ */
+ int rnd_init(bool scan); //required
+ int rnd_end();
+ int rnd_next(uchar *buf); ///< required
+ int rnd_pos(uchar *buf, uchar *pos); ///< required
+ void position(const uchar *record); ///< required
+ int info(uint); ///< required
+ int extra(enum ha_extra_function operation);
+ int start_stmt(THD *thd, thr_lock_type lock_type);
+ int external_lock(THD *thd, int lock_type); ///< required
+ int delete_all_rows(void);
+ ha_rows records_in_range(uint inx, const key_range *start_key,
+ const key_range *end_key, page_range *pages);
+ /**
+ These methods can be overridden, but their default implementation
+ provide useful functionality.
+ */
+ int rename_table(const char *from, const char *to);
+ /**
+ Delete a table in the engine. Called for base as well as temporary
+ tables.
+ */
+ int delete_table(const char *name);
+ /**
+ Called by delete_table and rename_table
+ */
+ int delete_or_rename_table(const char *from, const char *to);
+ int create(const char *name, TABLE *form,
+ HA_CREATE_INFO *create_info); ///< required
+ bool check_if_incompatible_data(HA_CREATE_INFO *info,
+ uint table_changes);
+
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type); ///< required
+ int optimize(THD* thd, HA_CHECK_OPT* check_opt);
+
+ /**
+ * Multi Range Read interface
+ */
+ int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode, HANDLER_BUFFER *buf);
+ int multi_range_read_next(range_id_t *range_info);
+ ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint *bufsz,
+ uint *flags, Cost_estimate *cost);
+ ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+ uint key_parts, uint *bufsz,
+ uint *flags, Cost_estimate *cost);
+ int multi_range_read_explain_info(uint mrr_mode, char *str, size_t size);
+
+ int reset(void) {ds_mrr.dsmrr_close(); return 0;}
+
+ /* Index condition pushdown implementation */
+// Item *idx_cond_push(uint keyno, Item* idx_cond);
+private:
+ DsMrr_impl ds_mrr;
+
+protected:
+ bool check_privileges(THD *thd, PTOS options, const char *dbn, bool quick=false);
+ MODE CheckMode(PGLOBAL g, THD *thd, MODE newmode, bool *chk, bool *cras);
+ int check_stmt(PGLOBAL g, MODE newmode, bool cras);
+ char *GetDBfromName(const char *name);
+
+ // Members
+ static ulong num; // Tracable handler number
+ PCONNECT xp; // To user_connect associated class
+ ulong hnum; // The number of this handler
+ query_id_t valid_query_id; // The one when tdbp was allocated
+ query_id_t creat_query_id; // The one when handler was allocated
+ PCSZ datapath; // Is the Path of DB data directory
+ PTDB tdbp; // To table class object
+ PVAL sdvalin1; // Used to convert date values
+ PVAL sdvalin2; // Used to convert date values
+ PVAL sdvalin3; // Used to convert date values
+ PVAL sdvalin4; // Used to convert date values
+ PVAL sdvalout; // Used to convert date values
+ bool istable; // True for table handler
+ char partname[65]; // The partition name
+ MODE xmod; // Table mode
+ XINFO xinfo; // The table info structure
+ bool valid_info; // True if xinfo is valid
+ bool stop; // Used when creating index
+ bool alter; // True when converting to other engine
+ bool mrr; // True when getting index positions
+ bool nox; // True when index should not be made
+ bool abort; // True after error in UPDATE/DELETE
+ int indexing; // Type of indexing for CONNECT
+ int locked; // Table lock
+ MY_BITMAP *part_id; // Columns used for partition func
+ THR_LOCK_DATA lock_data;
+
+public:
+ TABLE_SHARE *tshp; // Used by called tables
+ char *data_file_name;
+ char *index_file_name;
+ uint int_table_flags; // Inherited from MyISAM
+ bool enable_activate_all_index; // Inherited from MyISAM
+}; // end of ha_connect class definition
+
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+bool MongoEnabled(void);
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
diff --git a/storage/connect/inihandl.cpp b/storage/connect/inihandl.cpp
new file mode 100644
index 00000000..c39c94fb
--- /dev/null
+++ b/storage/connect/inihandl.cpp
@@ -0,0 +1,1405 @@
+/*
+ * Profile functions
+ *
+ * Copyright 1993 Miguel de Icaza
+ * Copyright 1996 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+ */
+#include "my_global.h"
+
+#include <ctype.h>
+//#include <errno.h>
+#include <fcntl.h>
+//#include <io.h> commented this line out to compile for solaris
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+//#include <sys/types.h>
+//#include <memory.h>
+#include "osutil.h"
+#include "global.h"
+#include "inihandl.h"
+
+// The types and variables used locally
+//typedef int bool;
+typedef unsigned int uint;
+//#define SVP(S) ((S) ? S : "<null>")
+#define _strlwr(P) strlwr(P) //OB: changed this line
+#define MAX_PATHNAME_LEN 256
+#define N_CACHED_PROFILES 10
+#ifndef WIN32
+#define stricmp strcasecmp
+#define _strnicmp strncasecmp
+#endif // !WIN32
+#define EnterCriticalSection(x)
+#define LeaveCriticalSection(x)
+
+#if defined(TEST_MODULE)
+// Stand alone test program
+#include <stdarg.h>
+ int trace = 0;
+void htrc(char const *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end (ap);
+} /* end of htrc */
+#else // !TEST_MODULE
+// Normal included functions
+//extern int trace;
+//void htrc(char const *fmt, ...);
+#endif // !TEST MODULE
+
+
+typedef struct tagPROFILEKEY {
+ char *value;
+ struct tagPROFILEKEY *next;
+ char name[1];
+ } PROFILEKEY;
+
+typedef struct tagPROFILESECTION {
+ struct tagPROFILEKEY *key;
+ struct tagPROFILESECTION *next;
+ char name[1];
+ } PROFILESECTION;
+
+typedef struct {
+ BOOL changed;
+ PROFILESECTION *section;
+//char *dos_name;
+//char *unix_name;
+ char *filename;
+ time_t mtime;
+ } PROFILE;
+
+#define memfree(P) if (P) free(P)
+
+/* Cached profile files */
+static PROFILE *MRUProfile[N_CACHED_PROFILES] = {NULL};
+
+#define CurProfile (MRUProfile[0])
+
+/* wine.ini config file registry root */
+//static HKEY wine_profile_key;
+
+#define PROFILE_MAX_LINE_LEN 1024
+
+/* Wine profile name in $HOME directory; must begin with slash */
+//static const char PROFILE_WineIniName[] = "/.winerc";
+
+/* Wine profile: the profile file being used */
+//static char PROFILE_WineIniUsed[MAX_PATHNAME_LEN] = "";
+
+/* Check for comments in profile */
+#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
+
+//static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 };
+
+//static CRITICAL_SECTION PROFILE_CritSect = CRITICAL_SECTION_INIT("PROFILE_CritSect");
+
+BOOL WritePrivateProfileString(LPCSTR section, LPCSTR entry,
+ LPCSTR string, LPCSTR filename);
+
+/***********************************************************************
+ * PROFILE_CopyEntry
+ *
+ * Copy the content of an entry into a buffer, removing quotes,
+ * and possibly translating environment variables.
+ ***********************************************************************/
+static void PROFILE_CopyEntry( char *buffer, const char *value, uint len,
+ int handle_env )
+{
+ const char *p;
+ char quote = '\0';
+
+ if (!buffer)
+ return;
+
+ if ((*value == '\'') || (*value == '\"'))
+ if (value[1] && (value[strlen(value)-1] == *value))
+ quote = *value++;
+
+ if (!handle_env) {
+ strncpy(buffer, value, len);
+
+ if (quote && (len >= strlen(value)))
+ buffer[strlen(buffer)-1] = '\0';
+
+ return;
+ } // endif handle
+
+ for (p = value; (*p && (len > 1)); *buffer++ = *p++, len--) {
+ if ((*p == '$') && (p[1] == '{')) {
+ char env_val[1024];
+ const char *env_p;
+ const char *p2 = strchr(p, '}');
+
+ if (!p2)
+ continue; /* ignore it */
+
+ strncpy(env_val, p + 2, MY_MIN((int) sizeof(env_val), (int)(p2-p)-1));
+
+ if ((env_p = getenv(env_val)) != NULL) {
+ int buffer_len;
+
+ strncpy( buffer, env_p, len );
+ buffer_len = strlen( buffer );
+ buffer += buffer_len;
+ len -= buffer_len;
+ } // endif env_p
+
+ p = p2 + 1;
+ } // endif p
+
+ } // endfor p
+
+ if (quote && (len > 1))
+ buffer--;
+
+ *buffer = '\0';
+} // end of PROFILE_CopyEntry
+
+
+/***********************************************************************
+ * PROFILE_Save
+ *
+ * Save a profile tree to a file.
+ ***********************************************************************/
+static void PROFILE_Save( FILE *file, PROFILESECTION *section )
+{
+ PROFILEKEY *key;
+ int secno;
+
+ for (secno= 0; section; section= section->next) {
+ if (section->name[0]) {
+ fprintf(file, "%s[%s]\n", secno ? "\n" : "", SVP(section->name));
+ secno++;
+ }
+
+ for (key = section->key; key; key = key->next)
+ if (key->name[0]) {
+ fprintf(file, "%s", SVP(key->name));
+
+ if (key->value)
+ fprintf(file, "=%s", SVP(key->value));
+
+ fprintf(file, "\n");
+ } // endif key->name
+
+ } // endfor section
+
+} // end of PROFILE_Save
+
+
+/***********************************************************************
+ * PROFILE_Free
+ *
+ * Free a profile tree.
+ ***********************************************************************/
+static void PROFILE_Free( PROFILESECTION *section )
+{
+ PROFILESECTION *next_section;
+ PROFILEKEY *key, *next_key;
+
+ for (; section; section = next_section) {
+ for (key = section->key; key; key = next_key) {
+ next_key = key->next;
+ memfree(key->value);
+ free(key);
+ } // endfor key
+
+ next_section = section->next;
+ free(section);
+ } // endfor section
+
+} // end of PROFILE_Free
+
+static int PROFILE_isspace(char c)
+{
+ /* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
+ if (isspace(c) || c=='\r' || c==0x1a)
+ return 1;
+
+ return 0;
+} // end of PROFILE_isspace
+
+
+/***********************************************************************
+ * PROFILE_Load
+ *
+ * Load a profile tree from a file.
+ ***********************************************************************/
+static PROFILESECTION *PROFILE_Load( FILE *file )
+{
+ char buffer[PROFILE_MAX_LINE_LEN];
+ char *p, *p2;
+ int line = 0;
+ PROFILESECTION *section, *first_section;
+ PROFILESECTION* *next_section;
+ PROFILEKEY *key, *prev_key, **next_key;
+
+ first_section = (PROFILESECTION*)malloc(sizeof(*section));
+
+ if (first_section == NULL)
+ return NULL;
+
+ first_section->name[0] = 0;
+ first_section->key = NULL;
+ first_section->next = NULL;
+ next_section = &first_section->next;
+ next_key = &first_section->key;
+ prev_key = NULL;
+
+ while (fgets(buffer, PROFILE_MAX_LINE_LEN, file)) {
+ line++;
+ p = buffer;
+
+ while (*p && PROFILE_isspace(*p))
+ p++;
+
+ if (*p == '[') { /* section start */
+ if (!(p2 = strrchr( p, ']'))) {
+ fprintf(stderr, "Invalid section header at line %d: '%s'\n",
+ line, p);
+ } else {
+ *p2 = '\0';
+ p++;
+
+ if (!(section = (PROFILESECTION*)malloc(sizeof(*section) + strlen(p))))
+ break;
+
+ strcpy(section->name, p);
+ section->key = NULL;
+ section->next = NULL;
+ *next_section = section;
+ next_section = &section->next;
+ next_key = &section->key;
+ prev_key = NULL;
+
+ if (trace(2))
+ htrc("New section: '%s'\n",section->name);
+
+ continue;
+ } // endif p2
+
+ } // endif p
+
+ p2 = p + strlen(p) - 1;
+
+ while ((p2 > p) && ((*p2 == '\n') || PROFILE_isspace(*p2)))
+ *p2-- = '\0';
+
+ if ((p2 = strchr(p, '=')) != NULL) {
+ char *p3 = p2 - 1;
+
+ while ((p3 > p) && PROFILE_isspace(*p3))
+ *p3-- = '\0';
+
+ *p2++ = '\0';
+
+ while (*p2 && PROFILE_isspace(*p2))
+ p2++;
+
+ } // endif p2
+
+ if (*p || !prev_key || *prev_key->name) {
+ if (!(key = (PROFILEKEY*)malloc(sizeof(*key) + strlen(p))))
+ break;
+
+ strcpy(key->name, p);
+
+ if (p2) {
+ key->value = (char*)malloc(strlen(p2)+1);
+ strcpy(key->value, p2);
+ } else
+ key->value = NULL;
+
+ key->next = NULL;
+ *next_key = key;
+ next_key = &key->next;
+ prev_key = key;
+
+ if (trace(2))
+ htrc("New key: name='%s', value='%s'\n",
+ key->name,key->value?key->value:"(none)");
+
+ } // endif p || prev_key
+
+ } // endif *p
+
+ return first_section;
+} // end of PROFILE_Load
+
+/***********************************************************************
+ * PROFILE_FlushFile
+ *
+ * Flush the current profile to disk if changed.
+ ***********************************************************************/
+static BOOL PROFILE_FlushFile(void)
+{
+//char *p, buffer[MAX_PATHNAME_LEN];
+//const char *unix_name;
+ FILE *file = NULL;
+ struct stat buf;
+
+ if (trace(2))
+ htrc("PROFILE_FlushFile: CurProfile=%p\n", CurProfile);
+
+ if (!CurProfile) {
+ fprintf(stderr, "No current profile!\n");
+ return FALSE;
+ } // endif !CurProfile
+
+ if (!CurProfile->changed || !CurProfile->filename)
+ return TRUE;
+
+#if 0
+ if (!(file = fopen(unix_name, "w"))) {
+ /* Try to create it in $HOME/.wine */
+ /* FIXME: this will need a more general solution */
+ //strcpy( buffer, get_config_dir() );
+ //p = buffer + strlen(buffer);
+ //*p++ = '/';
+ char *p1 = strrchr(CurProfile->filename, '\\');
+
+ p = buffer; // OB: To be elaborate
+
+ if (p1)
+ p1++;
+ else
+ p1 = CurProfile->dos_name;
+
+ strcpy(p, p1);
+ _strlwr(p);
+ file = fopen(buffer, "w");
+ unix_name = buffer;
+ } // endif !unix_name
+#endif // 0
+
+ if (!(file = fopen(CurProfile->filename, "w"))) {
+ fprintf(stderr, "could not save profile file %s\n", CurProfile->filename);
+ return FALSE;
+ } // endif !file
+
+ if (trace(2))
+ htrc("Saving '%s'\n", CurProfile->filename);
+
+ PROFILE_Save(file, CurProfile->section);
+ fclose(file);
+ CurProfile->changed = FALSE;
+
+ if (!stat(CurProfile->filename, &buf))
+ CurProfile->mtime = buf.st_mtime;
+
+ return TRUE;
+} // end of PROFILE_FlushFile
+
+
+/***********************************************************************
+ * PROFILE_ReleaseFile
+ *
+ * Flush the current profile to disk and remove it from the cache.
+ ***********************************************************************/
+static void PROFILE_ReleaseFile(void)
+{
+ PROFILE_FlushFile();
+ PROFILE_Free(CurProfile->section);
+//memfree(CurProfile->dos_name);
+//memfree(CurProfile->unix_name);
+ memfree(CurProfile->filename);
+ CurProfile->changed = FALSE;
+ CurProfile->section = NULL;
+//CurProfile->dos_name = NULL;
+//CurProfile->unix_name = NULL;
+ CurProfile->filename = NULL;
+ CurProfile->mtime = 0;
+} // end of PROFILE_ReleaseFile
+
+
+/***********************************************************************
+ * PROFILE_Open
+ *
+ * Open a profile file, checking the cached file first.
+ ***********************************************************************/
+static BOOL PROFILE_Open(LPCSTR filename)
+{
+//char buffer[MAX_PATHNAME_LEN];
+//char *p;
+ FILE *file = NULL;
+ int i, j;
+ struct stat buf;
+ PROFILE *tempProfile;
+
+ if (trace(2))
+ htrc("PROFILE_Open: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
+
+ /* First time around */
+ if (!CurProfile)
+ for (i = 0; i < N_CACHED_PROFILES; i++) {
+ MRUProfile[i] = (PROFILE*)malloc(sizeof(PROFILE));
+
+ if (MRUProfile[i] == NULL)
+ break;
+
+ MRUProfile[i]->changed=FALSE;
+ MRUProfile[i]->section=NULL;
+// MRUProfile[i]->dos_name=NULL;
+// MRUProfile[i]->unix_name=NULL;
+ MRUProfile[i]->filename=NULL;
+ MRUProfile[i]->mtime=0;
+ } // endfor i
+
+ /* Check for a match */
+ for (i = 0; i < N_CACHED_PROFILES; i++) {
+ if (trace(2))
+ htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
+
+ if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) {
+ if (i) {
+ PROFILE_FlushFile();
+ tempProfile = MRUProfile[i];
+
+ for (j = i; j > 0; j--)
+ MRUProfile[j] = MRUProfile[j-1];
+
+ CurProfile=tempProfile;
+ } // endif i
+
+ if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime) {
+ if (trace(2))
+ htrc("(%s): already opened (mru=%d)\n", filename, i);
+
+ } else {
+ if (trace(2))
+ htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i);
+
+ } // endif stat
+
+ return TRUE;
+ } // endif filename
+
+ } // endfor i
+
+ /* Flush the old current profile */
+ PROFILE_FlushFile();
+
+ /* Make the oldest profile the current one only in order to get rid of it */
+ if (i == N_CACHED_PROFILES) {
+ tempProfile = MRUProfile[N_CACHED_PROFILES-1];
+
+ for(i = N_CACHED_PROFILES-1; i > 0; i--)
+ MRUProfile[i] = MRUProfile[i-1];
+
+ CurProfile = tempProfile;
+ } // endif i
+
+ if (CurProfile->filename)
+ PROFILE_ReleaseFile();
+
+ /* OK, now that CurProfile is definitely free we assign it our new file */
+// newdos_name = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.short_name)+1 );
+// strcpy( newdos_name, full_name.short_name );
+
+// newdos_name = malloc(strlen(filename)+1);
+// strcpy(newdos_name, filename);
+
+// CurProfile->dos_name = newdos_name;
+ CurProfile->filename = (char*)malloc(strlen(filename) + 1);
+ strcpy(CurProfile->filename, filename);
+
+ /* Try to open the profile file, first in $HOME/.wine */
+
+ /* FIXME: this will need a more general solution */
+// strcpy( buffer, get_config_dir() );
+// p = buffer + strlen(buffer);
+// *p++ = '/';
+// strcpy( p, strrchr( newdos_name, '\\' ) + 1 );
+// p = buffer;
+// strcpy(p, filename);
+// _strlwr(p);
+
+ if (trace(2))
+ htrc("Opening %s\n", filename);
+
+ if ((file = fopen(filename, "r"))) {
+ if (trace(2))
+ htrc("(%s): found it\n", filename);
+
+// CurProfile->unix_name = malloc(strlen(buffer)+1);
+// strcpy(CurProfile->unix_name, buffer);
+ } /* endif file */
+
+ if (file) {
+ CurProfile->section = PROFILE_Load(file);
+ fclose(file);
+
+ if (!stat(CurProfile->filename, &buf))
+ CurProfile->mtime = buf.st_mtime;
+
+ } else {
+ /* Does not exist yet, we will create it in PROFILE_FlushFile */
+ fprintf(stderr, "profile file %s not found\n", filename);
+ } /* endif file */
+
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * PROFILE_Close
+ *
+ * Flush the named profile to disk and remove it from the cache.
+ ***********************************************************************/
+void PROFILE_Close(LPCSTR filename)
+{
+ int i;
+ BOOL close = FALSE;
+ struct stat buf;
+ PROFILE *tempProfile;
+
+ if (trace(2))
+ htrc("PROFILE_Close: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
+
+ /* Check for a match */
+ for (i = 0; i < N_CACHED_PROFILES; i++) {
+ if (trace(2))
+ htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
+
+ if (MRUProfile[i]->filename && !strcmp(filename, MRUProfile[i]->filename)) {
+ if (i) {
+ /* Make the profile to close current */
+ tempProfile = MRUProfile[i];
+ MRUProfile[i] = MRUProfile[0];
+ MRUProfile[0] = tempProfile;
+ CurProfile=tempProfile;
+ } // endif i
+
+ if (trace(2)) {
+ if (!stat(CurProfile->filename, &buf) && CurProfile->mtime == buf.st_mtime)
+ htrc("(%s): already opened (mru=%d)\n", filename, i);
+ else
+ htrc("(%s): already opened, needs refreshing (mru=%d)\n", filename, i);
+
+ } // endif trace
+
+ close = TRUE;
+ break;
+ } // endif filename
+
+ } // endfor i
+
+ if (close)
+ PROFILE_ReleaseFile();
+
+} // end of PROFILE_Close
+
+
+/***********************************************************************
+ * PROFILE_End
+ *
+ * Terminate and release the cache.
+ ***********************************************************************/
+void PROFILE_End(void)
+{
+ int i;
+
+ if (trace(3))
+ htrc("PROFILE_End: CurProfile=%p N=%d\n", CurProfile, N_CACHED_PROFILES);
+
+ if (!CurProfile) // Sergey Vojtovich
+ return;
+
+ /* Close all opened files and free the cache structure */
+ for (i = 0; i < N_CACHED_PROFILES; i++) {
+ if (trace(3))
+ htrc("MRU=%s i=%d\n", SVP(MRUProfile[i]->filename), i);
+
+// CurProfile = MRUProfile[i]; Sergey Vojtovich
+// PROFILE_ReleaseFile(); see MDEV-9997
+ free(MRUProfile[i]);
+ } // endfor i
+
+} // end of PROFILE_End
+
+
+/***********************************************************************
+ * PROFILE_DeleteSection
+ *
+ * Delete a section from a profile tree.
+ ***********************************************************************/
+static BOOL PROFILE_DeleteSection(PROFILESECTION* *section, LPCSTR name)
+{
+ while (*section) {
+ if ((*section)->name[0] && !stricmp((*section)->name, name)) {
+ PROFILESECTION *to_del = *section;
+
+ *section = to_del->next;
+ to_del->next = NULL;
+ PROFILE_Free(to_del);
+ return TRUE;
+ } // endif section
+
+ section = &(*section)->next;
+ } // endwhile section
+
+ return FALSE;
+} // end of PROFILE_DeleteSection
+
+
+/***********************************************************************
+ * PROFILE_DeleteKey
+ *
+ * Delete a key from a profile tree.
+ ***********************************************************************/
+static BOOL PROFILE_DeleteKey(PROFILESECTION* *section,
+ LPCSTR section_name, LPCSTR key_name)
+{
+ while (*section) {
+ if ((*section)->name[0] && !stricmp((*section)->name, section_name)) {
+ PROFILEKEY* *key = &(*section)->key;
+
+ while (*key) {
+ if (!stricmp((*key)->name, key_name)) {
+ PROFILEKEY *to_del = *key;
+
+ *key = to_del->next;
+ memfree(to_del->value);
+ free(to_del);
+ return TRUE;
+ } // endif name
+
+ key = &(*key)->next;
+ } // endwhile *key
+
+ } // endif section->name
+
+ section = &(*section)->next;
+ } // endwhile *section
+
+ return FALSE;
+} // end of PROFILE_DeleteKey
+
+
+/***********************************************************************
+ * PROFILE_DeleteAllKeys
+ *
+ * Delete all keys from a profile tree.
+ ***********************************************************************/
+static void PROFILE_DeleteAllKeys(LPCSTR section_name)
+{
+ PROFILESECTION* *section= &CurProfile->section;
+
+ while (*section) {
+ if ((*section)->name[0] && !stricmp((*section)->name, section_name)) {
+ PROFILEKEY* *key = &(*section)->key;
+
+ while (*key) {
+ PROFILEKEY *to_del = *key;
+
+ *key = to_del->next;
+ memfree(to_del->value);
+ free(to_del);
+ CurProfile->changed = TRUE;
+ } // endwhile *key
+
+ } // endif section->name
+
+ section = &(*section)->next;
+ } // endwhile *section
+
+} // end of PROFILE_DeleteAllKeys
+
+
+/***********************************************************************
+ * PROFILE_Find
+ *
+ * Find a key in a profile tree, optionally creating it.
+ ***********************************************************************/
+static PROFILEKEY *PROFILE_Find(PROFILESECTION* *section,
+ const char *section_name,
+ const char *key_name,
+ BOOL create, BOOL create_always)
+{
+ const char *p;
+ int seclen, keylen;
+
+ while (PROFILE_isspace(*section_name))
+ section_name++;
+
+ p = section_name + strlen(section_name) - 1;
+
+ while ((p > section_name) && PROFILE_isspace(*p))
+ p--;
+
+ seclen = p - section_name + 1;
+
+ while (PROFILE_isspace(*key_name))
+ key_name++;
+
+ p = key_name + strlen(key_name) - 1;
+
+ while ((p > key_name) && PROFILE_isspace(*p))
+ p--;
+
+ keylen = p - key_name + 1;
+
+ while (*section) {
+ if (((*section)->name[0])
+ && (!(_strnicmp((*section)->name, section_name, seclen )))
+ && (((*section)->name)[seclen] == '\0')) {
+ PROFILEKEY* *key = &(*section)->key;
+
+ while (*key) {
+ /* If create_always is FALSE then we check if the keyname already exists.
+ * Otherwise we add it regardless of its existence, to allow
+ * keys to be added more then once in some cases.
+ */
+ if (!create_always) {
+ if ((!(_strnicmp( (*key)->name, key_name, keylen )))
+ && (((*key)->name)[keylen] == '\0'))
+ return *key;
+
+ } // endif !create_always
+
+ key = &(*key)->next;
+ } // endwhile *key
+
+ if (!create)
+ return NULL;
+
+ if (!(*key = (PROFILEKEY*)malloc(sizeof(PROFILEKEY) + strlen(key_name))))
+ return NULL;
+
+ strcpy((*key)->name, key_name);
+ (*key)->value = NULL;
+ (*key)->next = NULL;
+ return *key;
+ } // endifsection->name
+
+ section = &(*section)->next;
+ } // endwhile *section
+
+ if (!create)
+ return NULL;
+
+ *section = (PROFILESECTION*)malloc(sizeof(PROFILESECTION) + strlen(section_name));
+
+ if (*section == NULL)
+ return NULL;
+
+ strcpy((*section)->name, section_name);
+ (*section)->next = NULL;
+
+ if (!((*section)->key = (tagPROFILEKEY*)malloc(sizeof(PROFILEKEY) + strlen(key_name)))) {
+ free(*section);
+ return NULL;
+ } // endif malloc
+
+ strcpy((*section)->key->name, key_name);
+ (*section)->key->value = NULL;
+ (*section)->key->next = NULL;
+ return (*section)->key;
+} // end of PROFILE_Find
+
+
+/***********************************************************************
+ * PROFILE_GetSection
+ *
+ * Returns all keys of a section.
+ * If return_values is TRUE, also include the corresponding values.
+ ***********************************************************************/
+static int PROFILE_GetSection(PROFILESECTION *section, LPCSTR section_name,
+ LPSTR buffer, uint len,
+ BOOL handle_env, BOOL return_values)
+{
+ PROFILEKEY *key;
+
+ if(!buffer)
+ return 0;
+
+ while (section) {
+ if (section->name[0] && !stricmp(section->name, section_name)) {
+ uint oldlen = len;
+
+ for (key = section->key; key; key = key->next) {
+ if (len <= 2)
+ break;
+
+ if (!*key->name)
+ continue; /* Skip empty lines */
+
+ if (IS_ENTRY_COMMENT(key->name))
+ continue; /* Skip comments */
+
+ PROFILE_CopyEntry(buffer, key->name, len - 1, handle_env);
+ len -= strlen(buffer) + 1;
+ buffer += strlen(buffer) + 1;
+
+ if (len < 2)
+ break;
+
+ if (return_values && key->value) {
+ buffer[-1] = '=';
+ PROFILE_CopyEntry(buffer, key->value, len - 1, handle_env);
+ len -= strlen(buffer) + 1;
+ buffer += strlen(buffer) + 1;
+ } // endif return_values
+
+ } // endfor key
+
+ *buffer = '\0';
+
+ if (len <= 1) {
+ /*If either lpszSection or lpszKey is NULL and the supplied
+ destination buffer is too small to hold all the strings,
+ the last string is truncated and followed by two null characters.
+ In this case, the return value is equal to cchReturnBuffer
+ minus two. */
+ buffer[-1] = '\0';
+ return oldlen - 2;
+ } // endif len
+
+ return oldlen - len;
+ } // endif section->name
+
+ section = section->next;
+ } // endwhile section
+
+ buffer[0] = buffer[1] = '\0';
+ return 0;
+} // end of PROFILE_GetSection
+
+
+/* See GetPrivateProfileSectionNamesA for documentation */
+static int PROFILE_GetSectionNames(LPSTR buffer, uint len)
+{
+ LPSTR buf;
+ uint f,l;
+ PROFILESECTION *section;
+
+ if (trace(2))
+ htrc("GetSectionNames: buffer=%p len=%u\n", buffer, len);
+
+ if (!buffer || !len)
+ return 0;
+
+ if (len == 1) {
+ *buffer='\0';
+ return 0;
+ } // endif len
+
+ f = len - 1;
+ buf = buffer;
+ section = CurProfile->section;
+
+ if (trace(2))
+ htrc("GetSectionNames: section=%p\n", section);
+
+ while (section != NULL) {
+ if (trace(2))
+ htrc("section=%s\n", section->name);
+
+ if (section->name[0]) {
+ l = strlen(section->name) + 1;
+
+ if (trace(2))
+ htrc("l=%u f=%u\n", l, f);
+
+ if (l > f) {
+ if (f > 0) {
+ strncpy(buf, section->name, f-1);
+ buf += f-1;
+ *buf++='\0';
+ } // endif f
+
+ *buf = '\0';
+ return len - 2;
+ } // endif l
+
+ strcpy(buf, section->name);
+ buf += l;
+ f -= l;
+ } // endif section->name
+
+ section = section->next;
+ } // endwhile section
+
+ *buf='\0';
+ return buf-buffer;
+} // end of PROFILE_GetSectionNames
+
+
+/***********************************************************************
+ * PROFILE_GetString
+ *
+ * Get a profile string.
+ *
+ * Tests with GetPrivateProfileString16, W95a,
+ * with filled buffer ("****...") and section "set1" and key_name "1" valid:
+ * section key_name def_val res buffer
+ * "set1" "1" "x" 43 [data]
+ * "set1" "1 " "x" 43 [data] (!)
+ * "set1" " 1 "' "x" 43 [data] (!)
+ * "set1" "" "x" 1 "x"
+ * "set1" "" "x " 1 "x" (!)
+ * "set1" "" " x " 3 " x" (!)
+ * "set1" NULL "x" 6 "1\02\03\0\0"
+ * "set1" "" "x" 1 "x"
+ * NULL "1" "x" 0 "" (!)
+ * "" "1" "x" 1 "x"
+ * NULL NULL "" 0 ""
+ *
+ *************************************************************************/
+static int PROFILE_GetString(LPCSTR section, LPCSTR key_name,
+ LPCSTR def_val, LPSTR buffer, uint len)
+{
+ PROFILEKEY *key = NULL;
+
+ if(!buffer)
+ return 0;
+
+ if (!def_val)
+ def_val = "";
+
+ if (key_name && key_name[0]) {
+ key = PROFILE_Find(&CurProfile->section, section, key_name, FALSE, FALSE);
+ PROFILE_CopyEntry(buffer, (key && key->value) ? key->value : def_val, len, FALSE);
+
+ if (trace(2))
+ htrc("('%s','%s','%s'): returning '%s'\n",
+ section, key_name, def_val, buffer );
+
+ return strlen(buffer);
+ } // endif key_name
+
+ if (key_name && !(key_name[0]))
+ /* Win95 returns 0 on keyname "". Tested with Likse32 bon 000227 */
+ return 0;
+
+ if (section && section[0])
+ return PROFILE_GetSection(CurProfile->section, section, buffer, len,
+ FALSE, FALSE);
+ buffer[0] = '\0';
+ return 0;
+} // end of PROFILE_GetString
+
+
+/***********************************************************************
+ * PROFILE_SetString
+ *
+ * Set a profile string.
+ ***********************************************************************/
+static BOOL PROFILE_SetString(LPCSTR section_name, LPCSTR key_name,
+ LPCSTR value, BOOL create_always)
+{
+ if (!key_name) { /* Delete a whole section */
+ if (trace(2))
+ htrc("Deleting('%s')\n", section_name);
+
+ CurProfile->changed |= PROFILE_DeleteSection(&CurProfile->section,
+ section_name);
+ return TRUE; /* Even if PROFILE_DeleteSection() has failed,
+ this is not an error on application's level.*/
+ } else if (!value) { /* Delete a key */
+ if (trace(2))
+ htrc("Deleting('%s','%s')\n", section_name, key_name);
+
+ CurProfile->changed |= PROFILE_DeleteKey(&CurProfile->section,
+ section_name, key_name);
+ return TRUE; /* same error handling as above */
+ } else { /* Set the key value */
+ PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name,
+ key_name, TRUE, create_always);
+ if (trace(2))
+ htrc("Setting('%s','%s','%s')\n", section_name, key_name, value);
+
+ if (!key)
+ return FALSE;
+
+ if (key->value) {
+ /* strip the leading spaces. We can safely strip \n\r and
+ * friends too, they should not happen here anyway. */
+ while (PROFILE_isspace(*value))
+ value++;
+
+ if (!strcmp(key->value, value)) {
+ if (trace(2))
+ htrc(" no change needed\n" );
+
+ return TRUE; /* No change needed */
+ } // endif value
+
+ if (trace(2))
+ htrc(" replacing '%s'\n", key->value);
+
+ free(key->value);
+ } else if (trace(2))
+ htrc(" creating key\n" );
+
+ key->value = (char*)malloc(strlen(value) + 1);
+ strcpy(key->value, value);
+ CurProfile->changed = TRUE;
+ } // endelse
+
+ return TRUE;
+} // end of PROFILE_SetString
+
+
+/***********************************************************************
+ * PROFILE_GetStringItem
+ *
+ * Convenience function that turns a string 'xxx, yyy, zzz' into
+ * the 'xxx\0 yyy, zzz' and returns a pointer to the 'yyy, zzz'.
+ ***********************************************************************/
+#if 0
+char *PROFILE_GetStringItem(char* start)
+{
+ char *lpchX, *lpch;
+
+ for (lpchX = start, lpch = NULL; *lpchX != '\0'; lpchX++) {
+ if (*lpchX == ',') {
+ if (lpch)
+ *lpch = '\0';
+ else
+ *lpchX = '\0';
+
+ while(*(++lpchX))
+ if (!PROFILE_isspace(*lpchX))
+ return lpchX;
+
+ } else if (PROFILE_isspace(*lpchX) && !lpch) {
+ lpch = lpchX;
+ } else
+ lpch = NULL;
+
+ } // endfor lpchX
+
+ if (lpch)
+ *lpch = '\0';
+
+ return NULL;
+} // end of PROFILE_GetStringItem
+#endif
+
+/**********************************************************************
+ * if allow_section_name_copy is TRUE, allow the copying :
+ * - of Section names if 'section' is NULL
+ * - of Keys in a Section if 'entry' is NULL
+ * (see MSDN doc for GetPrivateProfileString)
+ **********************************************************************/
+static int PROFILE_GetPrivateProfileString(LPCSTR section, LPCSTR entry,
+ LPCSTR def_val, LPSTR buffer,
+ uint len, LPCSTR filename,
+ BOOL allow_section_name_copy)
+{
+ int ret;
+ LPSTR pDefVal = NULL;
+
+ if (!filename)
+ filename = "win.ini";
+
+ /* strip any trailing ' ' of def_val. */
+ if (def_val) {
+ LPSTR p = (LPSTR)&def_val[strlen(def_val)]; // even "" works !
+
+ while (p > def_val)
+ if ((*(--p)) != ' ')
+ break;
+
+ if (*p == ' ') { /* ouch, contained trailing ' ' */
+ int len = p - (LPSTR)def_val;
+
+ pDefVal = (LPSTR)malloc(len + 1);
+ strncpy(pDefVal, def_val, len);
+ pDefVal[len] = '\0';
+ } // endif *p
+
+ } // endif def_val
+
+ if (!pDefVal)
+ pDefVal = (LPSTR)def_val;
+
+ EnterCriticalSection(&PROFILE_CritSect);
+
+ if (PROFILE_Open(filename)) {
+ if ((allow_section_name_copy) && (section == NULL))
+ ret = PROFILE_GetSectionNames(buffer, len);
+ else
+ /* PROFILE_GetString already handles the 'entry == NULL' case */
+ ret = PROFILE_GetString(section, entry, pDefVal, buffer, len);
+
+ } else {
+ strncpy(buffer, pDefVal, len);
+ ret = strlen(buffer);
+ } // endif Open
+
+ LeaveCriticalSection(&PROFILE_CritSect);
+
+ if (pDefVal != def_val) /* allocated */
+ memfree(pDefVal);
+
+ return ret;
+} // end of PROFILE_GetPrivateProfileString
+
+/********************** API functions **********************************/
+
+/***********************************************************************
+ * GetPrivateProfileStringA (KERNEL32.@)
+ ***********************************************************************/
+int GetPrivateProfileString(LPCSTR section, LPCSTR entry, LPCSTR def_val,
+ LPSTR buffer, DWORD len, LPCSTR filename)
+{
+ return PROFILE_GetPrivateProfileString(section, entry, def_val,
+ buffer, len, filename, TRUE);
+} // end of GetPrivateProfileString
+
+
+/***********************************************************************
+ * GetPrivateProfileIntA (KERNEL32.@)
+ ***********************************************************************/
+uint GetPrivateProfileInt(LPCSTR section, LPCSTR entry,
+ int def_val, LPCSTR filename)
+{
+ char buffer[20];
+ int result;
+
+ if (!PROFILE_GetPrivateProfileString(section, entry, "", buffer,
+ sizeof(buffer), filename, FALSE))
+ return def_val;
+
+ /* FIXME: if entry can be found but it's empty, then Win16 is
+ * supposed to return 0 instead of def_val ! Difficult/problematic
+ * to implement (every other failure also returns zero buffer),
+ * thus wait until testing framework avail for making sure nothing
+ * else gets broken that way. */
+ if (!buffer[0])
+ return (uint)def_val;
+
+ /* Don't use strtol() here !
+ * (returns LONG_MAX/MIN on overflow instead of "proper" overflow)
+ YES, scan for unsigned format ! (otherwise compatibility error) */
+ if (!sscanf(buffer, "%u", &result))
+ return 0;
+
+ return (uint)result;
+} // end of GetPrivateProfileInt
+
+
+/***********************************************************************
+ * GetPrivateProfileSectionA (KERNEL32.@)
+ ***********************************************************************/
+int GetPrivateProfileSection(LPCSTR section, LPSTR buffer,
+ DWORD len, LPCSTR filename)
+{
+ int ret = 0;
+
+ EnterCriticalSection( &PROFILE_CritSect );
+
+ if (PROFILE_Open(filename))
+ ret = PROFILE_GetSection(CurProfile->section, section, buffer, len,
+ FALSE, TRUE);
+
+ LeaveCriticalSection( &PROFILE_CritSect );
+ return ret;
+} // end of GetPrivateProfileSection
+
+
+/***********************************************************************
+ * WritePrivateProfileStringA (KERNEL32.@)
+ ***********************************************************************/
+BOOL WritePrivateProfileString(LPCSTR section, LPCSTR entry,
+ LPCSTR string, LPCSTR filename)
+{
+ BOOL ret = FALSE;
+
+ EnterCriticalSection( &PROFILE_CritSect );
+
+ if (PROFILE_Open(filename)) {
+ if (!section && !entry && !string) /* documented "file flush" case */
+ PROFILE_ReleaseFile(); /* always return FALSE in this case */
+ else {
+ if (!section) {
+ //FIXME("(NULL?,%s,%s,%s)? \n",entry,string,filename);
+ } else {
+ ret = PROFILE_SetString(section, entry, string, FALSE);
+
+ if (ret)
+ ret = PROFILE_FlushFile();
+
+ } // endif section
+
+ } // endif section || entry|| string
+
+ } // endif Open
+
+ LeaveCriticalSection( &PROFILE_CritSect );
+ return ret;
+} // end of WritePrivateProfileString
+
+
+/***********************************************************************
+ * WritePrivateProfileSectionA (KERNEL32.@)
+ ***********************************************************************/
+BOOL WritePrivateProfileSection(LPCSTR section,
+ LPCSTR string, LPCSTR filename )
+{
+ BOOL ret = FALSE;
+ LPSTR p ;
+
+ EnterCriticalSection(&PROFILE_CritSect);
+
+ if (PROFILE_Open(filename)) {
+ if (!section && !string)
+ PROFILE_ReleaseFile(); /* always return FALSE in this case */
+ else if (!string) { /* delete the named section*/
+ ret = PROFILE_SetString(section, NULL, NULL, FALSE);
+
+ if (ret)
+ ret = PROFILE_FlushFile();
+ } else {
+ PROFILE_DeleteAllKeys(section);
+ ret = TRUE;
+
+ while (*string) {
+ LPSTR buf = (LPSTR)malloc(strlen(string) + 1);
+ strcpy(buf, string);
+
+ if ((p = strchr(buf, '='))) {
+ *p='\0';
+ ret = PROFILE_SetString(section, buf, p+1, TRUE);
+ } // endif p
+
+ free(buf);
+ string += strlen(string) + 1;
+
+ if (ret)
+ ret = PROFILE_FlushFile();
+
+ } // endwhile *string
+
+ } // endelse
+
+ } // endif Open
+
+ LeaveCriticalSection(&PROFILE_CritSect);
+ return ret;
+} // end of WritePrivateProfileSection
+
+
+/***********************************************************************
+ * GetPrivateProfileSectionNamesA (KERNEL32.@)
+ *
+ * Returns the section names contained in the specified file.
+ * FIXME: Where do we find this file when the path is relative?
+ * The section names are returned as a list of strings with an extra
+ * '\0' to mark the end of the list. Except for that the behavior
+ * depends on the Windows version.
+ *
+ * Win95:
+ * - if the buffer is 0 or 1 character long then it is as if it was of
+ * infinite length.
+ * - otherwise, if the buffer is to small only the section names that fit
+ * are returned.
+ * - note that this means if the buffer was to small to return even just
+ * the first section name then a single '\0' will be returned.
+ * - the return value is the number of characters written in the buffer,
+ * except if the buffer was too smal in which case len-2 is returned
+ *
+ * Win2000:
+ * - if the buffer is 0, 1 or 2 characters long then it is filled with
+ * '\0' and the return value is 0
+ * - otherwise if the buffer is too small then the first section name that
+ * does not fit is truncated so that the string list can be terminated
+ * correctly (double '\0')
+ * - the return value is the number of characters written in the buffer
+ * except for the trailing '\0'. If the buffer is too small, then the
+ * return value is len-2
+ * - Win2000 has a bug that triggers when the section names and the
+ * trailing '\0' fit exactly in the buffer. In that case the trailing
+ * '\0' is missing.
+ *
+ * Wine implements the observed Win2000 behavior (except for the bug).
+ *
+ * Note that when the buffer is big enough then the return value may be any
+ * value between 1 and len-1 (or len in Win95), including len-2.
+ */
+#ifdef TEST_MODULE
+static DWORD
+GetPrivateProfileSectionNames(LPSTR buffer, DWORD size, LPCSTR filename)
+{
+ DWORD ret = 0;
+
+ if (trace(2))
+ htrc("GPPSN: filename=%s\n", filename);
+
+ EnterCriticalSection(&PROFILE_CritSect);
+
+ if (PROFILE_Open(filename))
+ ret = PROFILE_GetSectionNames(buffer, size);
+
+ LeaveCriticalSection(&PROFILE_CritSect);
+ return ret;
+} // end of GetPrivateProfileSectionNames
+
+
+/************************************************************************
+ * Program to test the above
+ ************************************************************************/
+int main(int argc, char**argv) {
+ char buff[128];
+ char *p, *inifile = "D:\\Plug\\Data\\contact.ini";
+ DWORD n;
+
+ n = GetPrivateProfileSectionNames(buff, 128, inifile);
+ printf("Sections: n=%d\n", n);
+
+ for (p = buff; *p; p += (strlen(p) + 1))
+ printf("section=[%s]\n", p);
+
+ GetPrivateProfileString("BER", "name", "?", buff, 128, inifile);
+ printf("[BER](name) = %s\n", buff);
+
+ WritePrivateProfileString("FOO", "city", NULL, inifile);
+ GetPrivateProfileString("FOO", "city", "?", buff, 128, inifile);
+ printf("[FOO](city) = %s\n", buff);
+
+ printf("FOO city: ");
+ fgets(buff, sizeof(buff), stdin);
+ if (buff[strlen(buff) - 1] == '\n')
+ buff[strlen(buff) - 1] = '\0';
+ WritePrivateProfileString("FOO", "city", buff, inifile);
+ GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile);
+ printf("After write, [FOO](City) = %s\n", buff);
+
+ printf("New city: ");
+ fgets(buff, sizeof(buff), stdin);
+ if (buff[strlen(buff) - 1] == '\n')
+ buff[strlen(buff) - 1] = '\0';
+ WritePrivateProfileString("FOO", "city", buff, inifile);
+ GetPrivateProfileString("FOO", "city", "???", buff, 128, inifile);
+ printf("After update, [FOO](City) = %s\n", buff);
+
+ printf("FOO name: ");
+ fgets(buff, sizeof(buff), stdin);
+ if (buff[strlen(buff) - 1] == '\n')
+ buff[strlen(buff) - 1] = '\0';
+ WritePrivateProfileString("FOO", "name", buff, inifile);
+ GetPrivateProfileString("FOO", "name", "X", buff, 128, inifile);
+ printf("[FOO](name) = %s\n", buff);
+} // end of main
+#endif // TEST_MODULE
diff --git a/storage/connect/inihandl.h b/storage/connect/inihandl.h
new file mode 100644
index 00000000..f0b7c9af
--- /dev/null
+++ b/storage/connect/inihandl.h
@@ -0,0 +1,55 @@
+#ifndef __INIHANDL_H__
+#define __INIHANDL_H__
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void PROFILE_Close(LPCSTR filename);
+void PROFILE_End(void);
+
+int GetPrivateProfileString(
+ LPCTSTR lpAppName, // section name
+ LPCTSTR lpKeyName, // key name
+ LPCTSTR lpDefault, // default string
+ LPTSTR lpReturnedString, // destination buffer
+ DWORD nSize, // size of destination buffer
+ LPCTSTR lpFileName // initialization file name
+ );
+
+uint GetPrivateProfileInt(
+ LPCTSTR lpAppName, // section name
+ LPCTSTR lpKeyName, // key name
+ INT nDefault, // return value if key name not found
+ LPCTSTR lpFileName // initialization file name
+ );
+
+BOOL WritePrivateProfileString(
+ LPCTSTR lpAppName, // section name
+ LPCTSTR lpKeyName, // key name
+ LPCTSTR lpString, // string to add
+ LPCTSTR lpFileName // initialization file
+ );
+
+int GetPrivateProfileSection(
+ LPCTSTR lpAppName, // section name
+ LPTSTR lpReturnedString, // return buffer
+ DWORD nSize, // size of return buffer
+ LPCTSTR lpFileName // initialization file name
+ );
+
+BOOL WritePrivateProfileSection(
+ LPCTSTR lpAppName, // section name
+ LPCTSTR lpString, // data
+ LPCTSTR lpFileName // file name
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* defined(UNIX) */
+
+#endif /* __INIHANDL_H__ */
diff --git a/storage/connect/ioapi.c b/storage/connect/ioapi.c
new file mode 100644
index 00000000..a49da91f
--- /dev/null
+++ b/storage/connect/ioapi.c
@@ -0,0 +1,248 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+*/
+
+#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
+ #define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#if defined(__APPLE__) || defined(IOAPI_NO_64)
+// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
+#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
+#define FTELLO_FUNC(stream) ftello(stream)
+#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
+#else
+#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
+#define FTELLO_FUNC(stream) ftello64(stream)
+#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
+#endif
+
+
+#include "ioapi.h"
+#include "my_attribute.h"
+
+voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
+{
+ if (pfilefunc->zfile_func64.zopen64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
+ else
+ {
+ return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
+ }
+}
+
+long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+ else
+ {
+ uLong offsetTruncated = (uLong)offset;
+ if (offsetTruncated != offset)
+ return -1;
+ else
+ return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
+ }
+}
+
+ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
+ else
+ {
+ uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
+ if ((tell_uLong) == MAXU32)
+ return (ZPOS64_T)-1;
+ else
+ return tell_uLong;
+ }
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
+{
+ p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+ p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+ p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+ p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+ p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+ p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+ p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+ p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
+
+
+
+static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
+static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
+static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
+static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
+static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
+
+static voidpf ZCALLBACK fopen_file_func (voidpf opaque __attribute__((unused)), const char* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = fopen(filename, mode_fopen);
+ return file;
+}
+
+static voidpf ZCALLBACK fopen64_file_func (voidpf opaque __attribute__((unused)), const void* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = FOPEN_FUNC((const char*)filename, mode_fopen);
+ return file;
+}
+
+
+static uLong ZCALLBACK fread_file_func (voidpf opaque __attribute__((unused)), voidpf stream, void* buf, uLong size)
+{
+ uLong ret;
+ ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+static uLong ZCALLBACK fwrite_file_func (voidpf opaque __attribute__((unused)), voidpf stream, const void* buf, uLong size)
+{
+ uLong ret;
+ ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+static long ZCALLBACK ftell_file_func (voidpf opaque __attribute__((unused)), voidpf stream)
+{
+ long ret;
+ ret = ftell((FILE *)stream);
+ return ret;
+}
+
+
+static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque __attribute__((unused)), voidpf stream)
+{
+ ZPOS64_T ret;
+ ret = FTELLO_FUNC((FILE *)stream);
+ return ret;
+}
+
+static long ZCALLBACK fseek_file_func (voidpf opaque __attribute__((unused)), voidpf stream, uLong offset, int origin)
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+ if (fseek((FILE *)stream, offset, fseek_origin) != 0)
+ ret = -1;
+ return ret;
+}
+
+static long ZCALLBACK fseek64_file_func (voidpf opaque __attribute__((unused)), voidpf stream, ZPOS64_T offset, int origin)
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+
+ if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int ZCALLBACK fclose_file_func (voidpf opaque __attribute__((unused)), voidpf stream)
+{
+ int ret;
+ ret = fclose((FILE *)stream);
+ return ret;
+}
+
+static int ZCALLBACK ferror_file_func (voidpf opaque __attribute__((unused)), voidpf stream)
+{
+ int ret;
+ ret = ferror((FILE *)stream);
+ return ret;
+}
+
+void fill_fopen_filefunc (pzlib_filefunc_def)
+ zlib_filefunc_def* pzlib_filefunc_def;
+{
+ pzlib_filefunc_def->zopen_file = fopen_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell_file = ftell_file_func;
+ pzlib_filefunc_def->zseek_file = fseek_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = fopen64_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell64_file = ftell64_file_func;
+ pzlib_filefunc_def->zseek64_file = fseek64_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
diff --git a/storage/connect/ioapi.h b/storage/connect/ioapi.h
new file mode 100644
index 00000000..e2148c56
--- /dev/null
+++ b/storage/connect/ioapi.h
@@ -0,0 +1,209 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ Changes
+
+ Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
+ Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
+ More if/def section may be needed to support other platforms
+ Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
+ (but you should use iowin32.c for windows instead)
+
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
+
+ // Linux needs this to support file operation on files larger then 4+GB
+ // But might need better if/def to select just the platforms that needs them.
+
+ #ifndef __USE_FILE_OFFSET64
+ #define __USE_FILE_OFFSET64
+ #endif
+ #ifndef __USE_LARGEFILE64
+ #define __USE_LARGEFILE64
+ #endif
+ #ifndef _LARGEFILE64_SOURCE
+ #define _LARGEFILE64_SOURCE
+ #endif
+ #ifndef _FILE_OFFSET_BIT
+ #define _FILE_OFFSET_BIT 64
+ #endif
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#define fopen64 fopen
+#define ftello64 ftell
+#define fseeko64 fseek
+#else
+#ifdef __FreeBSD__
+#define fopen64 fopen
+#define ftello64 ftello
+#define fseeko64 fseeko
+#endif
+#ifdef _MSC_VER
+ #define fopen64 fopen
+ #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+ #define ftello64 _ftelli64
+ #define fseeko64 _fseeki64
+ #else // old MSC
+ #define ftello64 ftell
+ #define fseeko64 fseek
+ #endif
+#endif
+#endif
+
+/*
+#ifndef ZPOS64_T
+ #ifdef _WIN32
+ #define ZPOS64_T fpos_t
+ #else
+ #include <stdint.h>
+ #define ZPOS64_T uint64_t
+ #endif
+#endif
+*/
+
+#ifdef HAVE_MINIZIP64_CONF_H
+#include "mz64conf.h"
+#endif
+
+/* a type chosen by DEFINE */
+#ifdef HAVE_64BIT_INT_CUSTOM
+typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
+#else
+#ifdef HAS_STDINT_H
+#include "stdint.h"
+typedef uint64_t ZPOS64_T;
+#else
+
+/* Maximum unsigned 32-bit value used as placeholder for zip64 */
+#define MAXU32 0xffffffff
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ZPOS64_T;
+#else
+typedef unsigned long long int ZPOS64_T;
+#endif
+#endif
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ (1)
+#define ZLIB_FILEFUNC_MODE_WRITE (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE (8)
+
+
+#ifndef ZCALLBACK
+ #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+ #define ZCALLBACK CALLBACK
+ #else
+ #define ZCALLBACK
+ #endif
+#endif
+
+#ifndef OF
+#define OF(args) args
+#endif
+
+typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
+typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+ open_file_func zopen_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell_file_func ztell_file;
+ seek_file_func zseek_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc_def;
+
+typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode));
+
+typedef struct zlib_filefunc64_def_s
+{
+ open64_file_func zopen64_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell64_file_func ztell64_file;
+ seek64_file_func zseek64_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc64_def;
+
+void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+ zlib_filefunc64_def zfile_func64;
+ open_file_func zopen32_file;
+ tell_file_func ztell32_file;
+ seek_file_func zseek32_file;
+} zlib_filefunc64_32_def;
+
+
+#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
+//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
+#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
+long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
+ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
+
+#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/storage/connect/javaconn.cpp b/storage/connect/javaconn.cpp
new file mode 100644
index 00000000..de37d5b6
--- /dev/null
+++ b/storage/connect/javaconn.cpp
@@ -0,0 +1,613 @@
+/************ Javaconn C++ Functions Source Code File (.CPP) ***********/
+/* Name: JAVAConn.CPP Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
+/* */
+/* This file contains the JAVA connection classes functions. */
+/***********************************************************************/
+
+#if defined(_WIN32)
+// This is needed for RegGetValue
+#define _WINVER 0x0601
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0601
+#endif // _WIN32
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+//#include <m_string.h>
+#if defined(_WIN32)
+#include <direct.h> // for getcwd
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+#else // !_WIN32
+#if defined(UNIX)
+#include <errno.h>
+#else // !UNIX
+#endif // !UNIX
+#include <stdio.h>
+#include <stdlib.h> // for getenv
+#define NODW
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Required objects includes. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "colblk.h"
+#include "xobject.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "javaconn.h"
+#include "resource.h"
+#include "valblk.h"
+#include "osutil.h"
+
+#if defined(_WIN32)
+extern "C" HINSTANCE s_hModule; // Saved module handle
+#endif // _WIN32
+#define nullptr 0
+
+//TYPCONV GetTypeConv();
+//int GetConvSize();
+extern char *JvmPath; // The connect_jvm_path global variable value
+extern char *ClassPath; // The connect_class_path global variable value
+
+char *GetPluginDir(void);
+char *GetMessageDir(void);
+char *GetJavaWrapper(void); // The connect_java_wrapper variable value
+extern MYSQL_PLUGIN_IMPORT char lc_messages_dir[FN_REFLEN];
+
+/***********************************************************************/
+/* Static JAVAConn objects. */
+/***********************************************************************/
+void *JAVAConn::LibJvm = NULL;
+CRTJVM JAVAConn::CreateJavaVM = NULL;
+GETJVM JAVAConn::GetCreatedJavaVMs = NULL;
+#if defined(_DEBUG)
+GETDEF JAVAConn::GetDefaultJavaVMInitArgs = NULL;
+#endif // _DEBUG
+
+/***********************************************************************/
+/* Some macro's (should be defined elsewhere to be more accessible) */
+/***********************************************************************/
+#if defined(_DEBUG)
+#define ASSERT(f) assert(f)
+#define DEBUG_ONLY(f) (f)
+#else // !_DEBUG
+#define ASSERT(f) ((void)0)
+#define DEBUG_ONLY(f) ((void)0)
+#endif // !_DEBUG
+
+/***********************************************************************/
+/* JAVAConn construction/destruction. */
+/***********************************************************************/
+JAVAConn::JAVAConn(PGLOBAL g, PCSZ wrapper)
+{
+ m_G = g;
+ jvm = nullptr; // Pointer to the JVM (Java Virtual Machine)
+ env = nullptr; // Pointer to native interface
+ jdi = nullptr; // Pointer to the java wrapper class
+ job = nullptr; // The java wrapper class object
+ errid = nullptr;
+ DiscFunc = "Disconnect";
+ Msg = NULL;
+ m_Wrap = (wrapper) ? wrapper : GetJavaWrapper();
+
+ if (!strchr(m_Wrap, '/')) {
+ // Add the wrapper package name
+ char *wn = (char*)PlugSubAlloc(g, NULL, strlen(m_Wrap) + 10);
+ m_Wrap = strcat(strcpy(wn, "wrappers/"), m_Wrap);
+ } // endif m_Wrap
+
+ fp = NULL;
+ m_Opened = false;
+ m_Connected = false;
+ m_Rows = 0;
+//*m_ErrMsg = '\0';
+} // end of JAVAConn
+
+//JAVAConn::~JAVAConn()
+// {
+//if (Connected())
+// EndCom();
+
+// } // end of ~JAVAConn
+char *JAVAConn::GetUTFString(jstring s)
+{
+ char *str;
+ const char *utf = env->GetStringUTFChars(s, nullptr);
+
+ str = PlugDup(m_G, utf);
+ env->ReleaseStringUTFChars(s, utf);
+ env->DeleteLocalRef(s);
+ return str;
+} // end of GetUTFString
+
+/***********************************************************************/
+/* Screen for errors. */
+/***********************************************************************/
+bool JAVAConn::Check(jint rc)
+{
+ jstring s;
+
+ if (env->ExceptionCheck()) {
+ jthrowable exc = env->ExceptionOccurred();
+ jmethodID tid = env->GetMethodID(env->FindClass("java/lang/Object"),
+ "toString", "()Ljava/lang/String;");
+
+ if (exc != nullptr && tid != nullptr) {
+ s = (jstring)env->CallObjectMethod(exc, tid);
+ Msg = GetUTFString(s);
+ } else
+ Msg = "Exception occurred";
+
+ env->ExceptionClear();
+ } else if (rc < 0) {
+ s = (jstring)env->CallObjectMethod(job, errid);
+ Msg = GetUTFString(s);
+ } else
+ Msg = NULL;
+
+ return (Msg != NULL);
+} // end of Check
+
+/***********************************************************************/
+/* Get MethodID if not exists yet. */
+/***********************************************************************/
+bool JAVAConn::gmID(PGLOBAL g, jmethodID& mid, const char *name, const char *sig)
+{
+ if (mid == nullptr) {
+ mid = env->GetMethodID(jdi, name, sig);
+
+ if (Check()) {
+ strcpy(g->Message, Msg);
+ return true;
+ } else
+ return false;
+
+ } else
+ return false;
+
+} // end of gmID
+
+#if 0
+/***********************************************************************/
+/* Utility routine. */
+/***********************************************************************/
+int JAVAConn::GetMaxValue(int n)
+{
+ jint m;
+ jmethodID maxid = nullptr;
+
+ if (gmID(m_G, maxid, "GetMaxValue", "(I)I"))
+ return -1;
+
+ // call method
+ if (Check(m = env->CallIntMethod(job, maxid, n)))
+ htrc("GetMaxValue: %s", Msg);
+
+ return (int)m;
+} // end of GetMaxValue
+#endif // 0
+
+/***********************************************************************/
+/* Reset the JVM library. */
+/***********************************************************************/
+void JAVAConn::ResetJVM(void)
+{
+ if (LibJvm) {
+#if defined(_WIN32)
+ FreeLibrary((HMODULE)LibJvm);
+#else // !_WIN32
+ dlclose(LibJvm);
+#endif // !_WIN32
+ LibJvm = NULL;
+ CreateJavaVM = NULL;
+ GetCreatedJavaVMs = NULL;
+#if defined(_DEBUG)
+ GetDefaultJavaVMInitArgs = NULL;
+#endif // _DEBUG
+ } // endif LibJvm
+
+} // end of ResetJVM
+
+/***********************************************************************/
+/* Dynamically link the JVM library. */
+/* The purpose of this function is to allow using the CONNECT plugin */
+/* for other table types when the Java JDK is not installed. */
+/***********************************************************************/
+bool JAVAConn::GetJVM(PGLOBAL g)
+{
+ int ntry;
+
+ if (!LibJvm) {
+ char soname[512];
+
+#if defined(_WIN32)
+ for (ntry = 0; !LibJvm && ntry < 3; ntry++) {
+ if (!ntry && JvmPath) {
+ strcat(strcpy(soname, JvmPath), "\\jvm.dll");
+ ntry = 3; // No other try
+ } else if (ntry < 2 && getenv("JAVA_HOME")) {
+ strcpy(soname, getenv("JAVA_HOME"));
+
+ if (ntry == 1)
+ strcat(soname, "\\jre");
+
+ strcat(soname, "\\bin\\client\\jvm.dll");
+ } else {
+ // Try to find it through the registry
+ char version[16];
+ char javaKey[64] = "SOFTWARE\\JavaSoft\\Java Runtime Environment";
+ LONG rc;
+ DWORD BufferSize = 16;
+
+ strcpy(soname, "jvm.dll"); // In case it fails
+
+ if ((rc = RegGetValue(HKEY_LOCAL_MACHINE, javaKey, "CurrentVersion",
+ RRF_RT_ANY, NULL, (PVOID)&version, &BufferSize)) == ERROR_SUCCESS) {
+ strcat(strcat(javaKey, "\\"), version);
+ BufferSize = sizeof(soname);
+
+ if ((rc = RegGetValue(HKEY_LOCAL_MACHINE, javaKey, "RuntimeLib",
+ RRF_RT_ANY, NULL, (PVOID)&soname, &BufferSize)) != ERROR_SUCCESS)
+ printf("RegGetValue: rc=%ld\n", rc);
+
+ } // endif rc
+
+ ntry = 3; // Try this only once
+ } // endelse
+
+ // Load the desired shared library
+ LibJvm = LoadLibrary(soname);
+ } // endfor ntry
+
+ // Get the needed entries
+ if (!LibJvm) {
+ char buf[256];
+ DWORD rc = GetLastError();
+
+ sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, soname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ strcat(strcat(g->Message, ": "), buf);
+ } else if (!(CreateJavaVM = (CRTJVM)GetProcAddress((HINSTANCE)LibJvm,
+ "JNI_CreateJavaVM"))) {
+ sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), "JNI_CreateJavaVM");
+ FreeLibrary((HMODULE)LibJvm);
+ LibJvm = NULL;
+ } else if (!(GetCreatedJavaVMs = (GETJVM)GetProcAddress((HINSTANCE)LibJvm,
+ "JNI_GetCreatedJavaVMs"))) {
+ sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), "JNI_GetCreatedJavaVMs");
+ FreeLibrary((HMODULE)LibJvm);
+ LibJvm = NULL;
+#if defined(_DEBUG)
+ } else if (!(GetDefaultJavaVMInitArgs = (GETDEF)GetProcAddress((HINSTANCE)LibJvm,
+ "JNI_GetDefaultJavaVMInitArgs"))) {
+ sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(),
+ "JNI_GetDefaultJavaVMInitArgs");
+ FreeLibrary((HMODULE)LibJvm);
+ LibJvm = NULL;
+#endif // _DEBUG
+ } // endif LibJvm
+#else // !_WIN32
+ const char *error = NULL;
+
+ for (ntry = 0; !LibJvm && ntry < 2; ntry++) {
+ if (!ntry && JvmPath) {
+ strcat(strcpy(soname, JvmPath), "/libjvm.so");
+ ntry = 2;
+ } else if (!ntry && getenv("JAVA_HOME")) {
+ // TODO: Replace i386 by a better guess
+ strcat(strcpy(soname, getenv("JAVA_HOME")), "/jre/lib/i386/client/libjvm.so");
+ } else { // Will need LD_LIBRARY_PATH to be set
+ strcpy(soname, "libjvm.so");
+ ntry = 2;
+ } // endelse
+
+ LibJvm = dlopen(soname, RTLD_LAZY);
+ } // endfor ntry
+
+ // Load the desired shared library
+ if (!LibJvm) {
+ error = dlerror();
+ sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error));
+ } else if (!(CreateJavaVM = (CRTJVM)dlsym(LibJvm, "JNI_CreateJavaVM"))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_CreateJavaVM", SVP(error));
+ dlclose(LibJvm);
+ LibJvm = NULL;
+ } else if (!(GetCreatedJavaVMs = (GETJVM)dlsym(LibJvm, "JNI_GetCreatedJavaVMs"))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_GetCreatedJavaVMs", SVP(error));
+ dlclose(LibJvm);
+ LibJvm = NULL;
+#if defined(_DEBUG)
+ } else if (!(GetDefaultJavaVMInitArgs = (GETDEF)dlsym(LibJvm,
+ "JNI_GetDefaultJavaVMInitArgs"))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(GET_FUNC_ERR), "JNI_GetDefaultJavaVMInitArgs", SVP(error));
+ dlclose(LibJvm);
+ LibJvm = NULL;
+#endif // _DEBUG
+ } // endif LibJvm
+#endif // !_WIN32
+
+ } // endif LibJvm
+
+ return LibJvm == NULL;
+} // end of GetJVM
+
+/***********************************************************************/
+/* Open: connect to a data source. */
+/***********************************************************************/
+bool JAVAConn::Open(PGLOBAL g)
+{
+ bool brc = true;
+ jboolean jt = (trace(1));
+
+ // Link or check whether jvm library was linked
+ if (GetJVM(g))
+ return true;
+
+ // Firstly check whether the jvm was already created
+ JavaVM* jvms[1];
+ jsize jsz;
+ jint rc = GetCreatedJavaVMs(jvms, 1, &jsz);
+
+ if (rc == JNI_OK && jsz == 1) {
+ // jvm already existing
+ jvm = jvms[0];
+ rc = jvm->AttachCurrentThread((void**)&env, nullptr);
+
+ if (rc != JNI_OK) {
+ strcpy(g->Message, "Cannot attach jvm to the current thread");
+ return true;
+ } // endif rc
+
+ } else {
+ /*******************************************************************/
+ /* Create a new jvm */
+ /*******************************************************************/
+ PSTRG jpop = new(g)STRING(g, 512, "-Djava.class.path=.");
+ char *cp = NULL;
+ char sep;
+
+#if defined(_WIN32)
+ sep = ';';
+#define N 1
+ //#define N 2
+ //#define N 3
+#else
+ sep = ':';
+#define N 1
+#endif
+
+ // Add wrappers jar files
+ AddJars(jpop, sep);
+
+ //================== prepare loading of Java VM ============================
+ JavaVMInitArgs vm_args; // Initialization arguments
+ JavaVMOption* options = new JavaVMOption[N]; // JVM invocation options
+
+ // where to find java .class
+ if (ClassPath && *ClassPath) {
+ jpop->Append(sep);
+ jpop->Append(ClassPath);
+ } // endif ClassPath
+
+ // All wrappers are pre-compiled in JavaWrappers.jar in the share dir
+ jpop->Append(sep);
+ jpop->Append(GetMessageDir());
+ jpop->Append("JavaWrappers.jar");
+
+#if defined(MONGO_SUPPORT)
+ jpop->Append(sep);
+ jpop->Append(GetMessageDir());
+ jpop->Append("Mongo3.jar");
+ jpop->Append(sep);
+ jpop->Append(GetMessageDir());
+ jpop->Append("Mongo2.jar");
+#endif // MONGO_SUPPORT
+
+ if ((cp = getenv("CLASSPATH"))) {
+ jpop->Append(sep);
+ jpop->Append(cp);
+ } // endif cp
+
+ if (trace(1)) {
+ htrc("ClassPath=%s\n", ClassPath ? ClassPath : "null");
+ htrc("CLASSPATH=%s\n", cp ? cp : "null");
+ htrc("%s\n", jpop->GetStr());
+ } // endif trace
+
+ options[0].optionString = jpop->GetStr();
+#if N == 2
+ options[1].optionString = "-Xcheck:jni";
+#endif
+#if N == 3
+ options[1].optionString = "-Xms256M";
+ options[2].optionString = "-Xmx512M";
+#endif
+#if defined(_DEBUG)
+ vm_args.version = JNI_VERSION_1_2; // minimum Java version
+ rc = GetDefaultJavaVMInitArgs(&vm_args);
+#else
+ vm_args.version = JNI_VERSION_1_6; // minimum Java version
+#endif // _DEBUG
+ vm_args.nOptions = N; // number of options
+ vm_args.options = options;
+ vm_args.ignoreUnrecognized = false; // invalid options make the JVM init fail
+
+ //=============== load and initialize Java VM and JNI interface =============
+ rc = CreateJavaVM(&jvm, (void**)&env, &vm_args); // YES !!
+ delete[] options; // we then no longer need the initialisation options.
+
+ switch (rc) {
+ case JNI_OK:
+ strcpy(g->Message, "VM successfully created");
+ brc = false;
+ break;
+ case JNI_ERR:
+ strcpy(g->Message, "Initialising JVM failed: unknown error");
+ break;
+ case JNI_EDETACHED:
+ strcpy(g->Message, "Thread detached from the VM");
+ break;
+ case JNI_EVERSION:
+ strcpy(g->Message, "JNI version error");
+ break;
+ case JNI_ENOMEM:
+ strcpy(g->Message, "Not enough memory");
+ break;
+ case JNI_EEXIST:
+ strcpy(g->Message, "VM already created");
+ break;
+ case JNI_EINVAL:
+ strcpy(g->Message, "Invalid arguments");
+ break;
+ default:
+ sprintf(g->Message, "Unknown return code %d", (int)rc);
+ break;
+ } // endswitch rc
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ if (brc)
+ return true;
+
+ //=============== Display JVM version ===============
+ jint ver = env->GetVersion();
+ printf("JVM Version %d.%d\n", ((ver >> 16) & 0x0f), (ver & 0x0f));
+ } // endif rc
+
+ // try to find the java wrapper class
+ jdi = env->FindClass(m_Wrap);
+
+ if (jdi == nullptr) {
+ sprintf(g->Message, "ERROR: class %s not found!", m_Wrap);
+ return true;
+ } // endif jdi
+
+#if 0 // Suppressed because it does not make any usable change
+ if (b && jpath && *jpath) {
+ // Try to add that path the the jvm class path
+ jmethodID alp = env->GetStaticMethodID(jdi, "addLibraryPath",
+ "(Ljava/lang/String;)I");
+
+ if (alp == nullptr) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ } else {
+ char *msg;
+ jstring path = env->NewStringUTF(jpath);
+ rc = env->CallStaticIntMethod(jdi, alp, path);
+
+ if ((msg = Check(rc))) {
+ strcpy(g->Message, msg);
+ env->DeleteLocalRef(path);
+ return RC_FX;
+ } else switch (rc) {
+ case JNI_OK:
+ printf("jpath added\n");
+ break;
+ case JNI_EEXIST:
+ printf("jpath already exist\n");
+ break;
+ case JNI_ERR:
+ default:
+ strcpy(g->Message, "Error adding jpath");
+ env->DeleteLocalRef(path);
+ return RC_FX;
+ } // endswitch rc
+
+ env->DeleteLocalRef(path);
+ } // endif alp
+
+ } // endif jpath
+#endif // 0
+
+ // if class found, continue
+ jmethodID ctor = env->GetMethodID(jdi, "<init>", "(Z)V");
+
+ if (ctor == nullptr) {
+ sprintf(g->Message, "ERROR: %s constructor not found!", m_Wrap);
+ return true;
+ } else
+ job = env->NewObject(jdi, ctor, jt);
+
+ if (job == nullptr) {
+ sprintf(g->Message, "%s class object not constructed!", m_Wrap);
+ return true;
+ } // endif job
+
+ // If the object is successfully constructed,
+ // we can then search for the method we want to call,
+ // and invoke it for the object:
+ errid = env->GetMethodID(jdi, "GetErrmsg", "()Ljava/lang/String;");
+
+ if (env->ExceptionCheck()) {
+ strcpy(g->Message, "ERROR: method GetErrmsg() not found!");
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ return true;
+ } // endif Check
+
+ /*********************************************************************/
+ /* Link a Fblock. This make possible to automatically close it */
+ /* in case of error (throw). */
+ /*********************************************************************/
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ fp->Type = TYPE_FB_JAVA;
+ fp->Fname = NULL;
+ fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = fp;
+ fp->Count = 1;
+ fp->Length = 0;
+ fp->Memory = NULL;
+ fp->Mode = MODE_ANY;
+ fp->File = this;
+ fp->Handle = 0;
+
+ m_Opened = true;
+ return false;
+} // end of Open
+
+/***********************************************************************/
+/* Disconnect connection */
+/***********************************************************************/
+void JAVAConn::Close()
+{
+ jint rc;
+
+ if (m_Connected) {
+ jmethodID did = nullptr;
+
+ // Could have been detached in case of join
+ rc = jvm->AttachCurrentThread((void**)&env, nullptr);
+
+ if (gmID(m_G, did, DiscFunc, "()I"))
+ printf("%s\n", Msg);
+ else if (Check(env->CallIntMethod(job, did)))
+ printf("%s: %s\n", DiscFunc, Msg);
+
+ m_Connected = false;
+ } // endif m_Connected
+
+ if ((rc = jvm->DetachCurrentThread()) != JNI_OK)
+ printf("DetachCurrentThread: rc=%d\n", (int)rc);
+
+ if (fp)
+ fp->Count = 0;
+
+ m_Opened = false;
+} // end of Close
diff --git a/storage/connect/javaconn.h b/storage/connect/javaconn.h
new file mode 100644
index 00000000..963b8c1a
--- /dev/null
+++ b/storage/connect/javaconn.h
@@ -0,0 +1,130 @@
+/***********************************************************************/
+/* JavaConn.h : header file for the Java connection classes. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Included C-definition files required by the interface. */
+/***********************************************************************/
+#include "block.h"
+#include "jdbccat.h"
+
+/***********************************************************************/
+/* Java native interface. */
+/***********************************************************************/
+#include <jni.h>
+
+/***********************************************************************/
+/* Constants and defines. */
+/***********************************************************************/
+// Miscellaneous sizing info
+#define MAX_NUM_OF_MSG 10 // Max number of error messages
+//efine MAX_CURRENCY 30 // Max size of Currency($) string
+#define MAX_TNAME_LEN 32 // Max size of table names
+//efine MAX_FNAME_LEN 256 // Max size of field names
+//efine MAX_STRING_INFO 256 // Max size of string from SQLGetInfo
+//efine MAX_DNAME_LEN 256 // Max size of Recordset names
+//efine MAX_CONNECT_LEN 512 // Max size of Connect string
+//efine MAX_CURSOR_NAME 18 // Max size of a cursor name
+//efine DEFAULT_FIELD_TYPE 0 // TYPE_NULL
+
+#if !defined(_WIN32)
+typedef unsigned char *PUCHAR;
+#endif // !_WIN32
+
+enum JCATINFO {
+ JCAT_TAB = 1, // JDBC Tables
+ JCAT_COL = 2, // JDBC Columns
+ JCAT_KEY = 3, // JDBC PrimaryKeys
+};
+
+/***********************************************************************/
+/* This structure is used to control the catalog functions. */
+/***********************************************************************/
+typedef struct tagJCATPARM {
+ JCATINFO Id; // Id to indicate function
+ PQRYRES Qrp; // Result set pointer
+ PCSZ DB; // Database (Schema)
+ PCSZ Tab; // Table name or pattern
+ PCSZ Pat; // Table type or column pattern
+} JCATPARM;
+
+typedef jint(JNICALL *CRTJVM) (JavaVM **, void **, void *);
+typedef jint(JNICALL *GETJVM) (JavaVM **, jsize, jsize *);
+#if defined(_DEBUG)
+typedef jint(JNICALL *GETDEF) (void *);
+#endif // _DEBUG
+
+//class JAVAConn;
+
+/***********************************************************************/
+/* JAVAConn class. */
+/***********************************************************************/
+class DllExport JAVAConn : public BLOCK {
+ friend class TDBJMG;
+ friend class JMGDISC;
+private:
+ JAVAConn(); // Standard (unused) constructor
+
+public:
+ // Constructor
+ JAVAConn(PGLOBAL g, PCSZ wrapper);
+
+ // Set static variables
+ static void SetJVM(void) {
+ LibJvm = NULL;
+ CreateJavaVM = NULL;
+ GetCreatedJavaVMs = NULL;
+#if defined(_DEBUG)
+ GetDefaultJavaVMInitArgs = NULL;
+#endif // _DEBUG
+ } // end of SetJVM
+
+ static void ResetJVM(void);
+ static bool GetJVM(PGLOBAL g);
+
+ // Implementation
+public:
+ //virtual ~JAVAConn();
+ bool IsOpen(void) { return m_Opened; }
+ bool IsConnected(void) { return m_Connected; }
+
+ // Java operations
+protected:
+ char *GetUTFString(jstring s);
+ bool gmID(PGLOBAL g, jmethodID& mid, const char *name, const char *sig);
+ bool Check(jint rc = 0);
+
+public:
+ virtual void AddJars(PSTRG jpop, char sep) = 0;
+ virtual bool Connect(PJPARM sop) = 0;
+ virtual bool Open(PGLOBAL g);
+ virtual bool MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options,
+ PCSZ filter, bool pipe) = 0;
+ virtual void Close(void);
+
+protected:
+ // Members
+#if defined(_WIN32)
+ static HANDLE LibJvm; // Handle to the jvm DLL
+#else // !_WIN32
+ static void *LibJvm; // Handle for the jvm shared library
+#endif // !_WIN32
+ static CRTJVM CreateJavaVM;
+ static GETJVM GetCreatedJavaVMs;
+#if defined(_DEBUG)
+ static GETDEF GetDefaultJavaVMInitArgs;
+#endif // _DEBUG
+ PGLOBAL m_G;
+ JavaVM *jvm; // Pointer to the JVM (Java Virtual Machine)
+ JNIEnv *env; // Pointer to native interface
+ jclass jdi; // Pointer to the java wrapper class
+ jobject job; // The java wrapper class object
+ jmethodID errid; // The GetErrmsg method ID
+ PFBLOCK fp;
+ bool m_Opened;
+ bool m_Connected;
+ PCSZ DiscFunc;
+ PCSZ Msg;
+ PCSZ m_Wrap;
+ int m_Rows;
+}; // end of JAVAConn class definition
diff --git a/storage/connect/jdbccat.h b/storage/connect/jdbccat.h
new file mode 100644
index 00000000..d137164b
--- /dev/null
+++ b/storage/connect/jdbccat.h
@@ -0,0 +1,35 @@
+#ifndef __JDBCCAT_H
+#define __JDBCCAT_H
+
+// Timeout and net wait defaults
+#define DEFAULT_LOGIN_TIMEOUT -1 // means do not set
+#define DEFAULT_QUERY_TIMEOUT -1 // means do not set
+
+typedef struct jdbc_parms {
+ int CheckSize(int rows);
+ PCSZ Driver; // JDBC driver
+ PCSZ Url; // Driver URL
+ PCSZ User; // User connect info
+ PCSZ Pwd; // Password connect info
+//int Cto; // Connect timeout
+//int Qto; // Query timeout
+ int Version; // Driver version
+ int Fsize; // Fetch size
+ bool Scrollable; // Scrollable cursor
+} JDBCPARM, *PJPARM;
+
+/***********************************************************************/
+/* JDBC catalog function prototypes. */
+/***********************************************************************/
+#if defined(PROMPT_OK)
+char *JDBCCheckConnection(PGLOBAL g, PCSZ dsn, int cop);
+#endif // PROMPT_OK
+//PQRYRES JDBCDataSources(PGLOBAL g, int maxres, bool info);
+PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table,
+ PCSZ colpat, int maxres, bool info, PJPARM sop);
+PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sop);
+PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat,
+ PCSZ tabtyp, int maxres, bool info, PJPARM sop);
+PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info);
+
+#endif // __JDBCCAT_H
diff --git a/storage/connect/jdbconn.cpp b/storage/connect/jdbconn.cpp
new file mode 100644
index 00000000..1035c2b8
--- /dev/null
+++ b/storage/connect/jdbconn.cpp
@@ -0,0 +1,1686 @@
+/************ Jdbconn C++ Functions Source Code File (.CPP) ************/
+/* Name: JDBCONN.CPP Version 1.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2016-2018 */
+/* */
+/* This file contains the JDBC connection classes functions. */
+/***********************************************************************/
+
+#if defined(_WIN32)
+// This is needed for RegGetValue
+#define _WINVER 0x0601
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0601
+#endif // _WIN32
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+#include <m_string.h>
+#if defined(_WIN32)
+//nclude <io.h>
+//nclude <fcntl.h>
+#include <direct.h> // for getcwd
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <errno.h>
+#else // !UNIX
+//nclude <io.h>
+#endif // !UNIX
+#include <stdio.h>
+#include <stdlib.h> // for getenv
+//nclude <fcntl.h>
+#define NODW
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Required objects includes. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xobject.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "tabjdbc.h"
+//#include "jdbconn.h"
+#include "resource.h"
+#include "valblk.h"
+#include "osutil.h"
+
+
+//#if defined(_WIN32)
+//extern "C" HINSTANCE s_hModule; // Saved module handle
+//#endif // _WIN32
+#define nullptr 0
+
+TYPCONV GetTypeConv();
+int GetConvSize();
+//extern char *JvmPath; // The connect_jvm_path global variable value
+//extern char *ClassPath; // The connect_class_path global variable value
+
+//char *GetJavaWrapper(void); // The connect_java_wrapper variable value
+
+/***********************************************************************/
+/* Some macro's (should be defined elsewhere to be more accessible) */
+/***********************************************************************/
+//#if defined(_DEBUG)
+//#define ASSERT(f) assert(f)
+//#define DEBUG_ONLY(f) (f)
+//#else // !_DEBUG
+//#define ASSERT(f) ((void)0)
+//#define DEBUG_ONLY(f) ((void)0)
+//#endif // !_DEBUG
+
+// To avoid gcc warning
+int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v);
+
+/***********************************************************************/
+/* GetJDBCType: returns the SQL_TYPE corresponding to a PLG type. */
+/***********************************************************************/
+static short GetJDBCType(int type)
+{
+ short tp = 0; // NULL
+
+ switch (type) {
+ case TYPE_STRING: tp = 12; break; // VARCHAR
+ case TYPE_SHORT: tp = 5; break; // SMALLINT
+ case TYPE_INT: tp = 4; break; // INTEGER
+ case TYPE_DATE: tp = 93; break; // DATE
+//case TYPE_TIME: tp = 92; break; // TIME
+//case TYPE_TIMESTAMP: tp = 93; break; // TIMESTAMP
+ case TYPE_BIGINT: tp = -5; break; // BIGINT
+ case TYPE_DOUBLE: tp = 8; break; // DOUBLE
+ case TYPE_TINY: tp = -6; break; // TINYINT
+ case TYPE_DECIM: tp = 3; break; // DECIMAL
+ } // endswitch type
+
+ return tp;
+} // end of GetJDBCType
+
+/***********************************************************************/
+/* TranslateJDBCType: translate a JDBC Type to a PLG type. */
+/***********************************************************************/
+int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v)
+{
+ int type;
+
+ switch (stp) {
+ case -1: // LONGVARCHAR, TEXT
+ case -16: // LONGNVARCHAR, NTEXT (unicode)
+ if (GetTypeConv() != TPC_YES)
+ return TYPE_ERROR;
+ else
+ len = MY_MIN(abs(len), GetConvSize());
+
+ // Pass through
+ case 12: // VARCHAR
+ if (tn && !stricmp(tn, "TEXT"))
+ // Postgresql returns 12 for TEXT
+ if (GetTypeConv() == TPC_NO)
+ return TYPE_ERROR;
+
+ // Postgresql can return this
+ if (len == 0x7FFFFFFF)
+ len = GetConvSize();
+
+ // Pass through
+ case -9: // NVARCHAR (unicode)
+ // Postgresql can return this when size is unknown
+ if (len == 0x7FFFFFFF)
+ len = GetConvSize();
+
+ v = 'V';
+ // Pass through
+ case 1: // CHAR
+ case -15: // NCHAR (unicode)
+ case -8: // ROWID
+ type = TYPE_STRING;
+ break;
+ case 2: // NUMERIC
+ case 3: // DECIMAL
+ case -3: // VARBINARY
+ type = TYPE_DECIM;
+ break;
+ case 4: // INTEGER
+ type = TYPE_INT;
+ break;
+ case 5: // SMALLINT
+ type = TYPE_SHORT;
+ break;
+ case -6: // TINYINT
+ case -7: // BIT
+ case 16: // BOOLEAN
+ type = TYPE_TINY;
+ break;
+ case 6: // FLOAT
+ case 7: // REAL
+ case 8: // DOUBLE
+ type = TYPE_DOUBLE;
+ break;
+ case 93: // TIMESTAMP, DATETIME
+ type = TYPE_DATE;
+ len = 19 + ((prec) ? (prec+1) : 0);
+ v = (tn && toupper(tn[0]) == 'T') ? 'S' : 'E';
+ break;
+ case 91: // DATE, YEAR
+ type = TYPE_DATE;
+
+ if (!tn || toupper(tn[0]) != 'Y') {
+ len = 10;
+ v = 'D';
+ } else {
+ len = 4;
+ v = 'Y';
+ } // endif len
+
+ break;
+ case 92: // TIME
+ type = TYPE_DATE;
+ len = 8 + ((prec) ? (prec + 1) : 0);
+ v = 'T';
+ break;
+ case -5: // BIGINT
+ type = TYPE_BIGINT;
+ break;
+ case 1111: // UNKNOWN or UUID
+ if (!tn || !stricmp(tn, "UUID")) {
+ type = TYPE_STRING;
+ len = 36;
+ break;
+ } // endif tn
+
+ // Pass through
+ case 0: // NULL
+ case -2: // BINARY
+ case -4: // LONGVARBINARY
+ case 70: // DATALINK
+ case 2000: // JAVA_OBJECT
+ case 2001: // DISTINCT
+ case 2002: // STRUCT
+ case 2003: // ARRAY
+ case 2004: // BLOB
+ case 2005: // CLOB
+ case 2006: // REF
+ case 2009: // SQLXML
+ case 2011: // NCLOB
+ default:
+ type = TYPE_ERROR;
+ len = 0;
+ } // endswitch type
+
+ return type;
+} // end of TranslateJDBCType
+
+ /***********************************************************************/
+ /* A helper class to split an optionally qualified table name into */
+ /* components. */
+ /* These formats are understood: */
+ /* "CatalogName.SchemaName.TableName" */
+ /* "SchemaName.TableName" */
+ /* "TableName" */
+ /***********************************************************************/
+class SQLQualifiedName {
+ static const uint max_parts = 3; // Catalog.Schema.Table
+ MYSQL_LEX_STRING m_part[max_parts];
+ char m_buf[512];
+
+ void lex_string_set(MYSQL_LEX_STRING *S, char *str, size_t length)
+ {
+ S->str = str;
+ S->length = length;
+ } // end of lex_string_set
+
+ void lex_string_shorten_down(MYSQL_LEX_STRING *S, size_t offs)
+ {
+ DBUG_ASSERT(offs <= S->length);
+ S->str += offs;
+ S->length -= offs;
+ } // end of lex_string_shorten_down
+
+ /*********************************************************************/
+ /* Find the rightmost '.' delimiter and return the length */
+ /* of the qualifier, including the rightmost '.' delimier. */
+ /* For example, for the string {"a.b.c",5} it will return 4, */
+ /* which is the length of the qualifier "a.b." */
+ /*********************************************************************/
+ size_t lex_string_find_qualifier(MYSQL_LEX_STRING *S)
+ {
+ size_t i;
+ for (i = S->length; i > 0; i--)
+ {
+ if (S->str[i - 1] == '.')
+ {
+ S->str[i - 1] = '\0';
+ return i;
+ }
+ }
+ return 0;
+ } // end of lex_string_find_qualifier
+
+public:
+ /*********************************************************************/
+ /* Initialize to the given optionally qualified name. */
+ /* NULL pointer in "name" is supported. */
+ /* name qualifier has precedence over schema. */
+ /*********************************************************************/
+ SQLQualifiedName(JCATPARM *cap)
+ {
+ const char *name = (const char *)cap->Tab;
+ char *db = (char *)cap->DB;
+ size_t len, i;
+
+ // Initialize the parts
+ for (i = 0; i < max_parts; i++)
+ lex_string_set(&m_part[i], NULL, 0);
+
+ if (name) {
+ // Initialize the first (rightmost) part
+ lex_string_set(&m_part[0], m_buf,
+ strmake(m_buf, name, sizeof(m_buf) - 1) - m_buf);
+
+ // Initialize the other parts, if exist.
+ for (i = 1; i < max_parts; i++) {
+ if (!(len = lex_string_find_qualifier(&m_part[i - 1])))
+ break;
+
+ lex_string_set(&m_part[i], m_part[i - 1].str, len - 1);
+ lex_string_shorten_down(&m_part[i - 1], len);
+ } // endfor i
+
+ } // endif name
+
+ // If it was not specified, set schema as the passed db name
+ if (db && !m_part[1].length)
+ lex_string_set(&m_part[1], db, strlen(db));
+
+ } // end of SQLQualifiedName
+
+ char *ptr(uint i)
+ {
+ DBUG_ASSERT(i < max_parts);
+ return (char *)(m_part[i].length ? m_part[i].str : NULL);
+ } // end of ptr
+
+ size_t length(uint i)
+ {
+ DBUG_ASSERT(i < max_parts);
+ return m_part[i].length;
+ } // end of length
+
+}; // end of class SQLQualifiedName
+
+/***********************************************************************/
+/* Allocate the structure used to refer to the result set. */
+/***********************************************************************/
+static JCATPARM *AllocCatInfo(PGLOBAL g, JCATINFO fid, PCSZ db,
+ PCSZ tab, PQRYRES qrp)
+{
+ JCATPARM *cap;
+
+ if ((cap = (JCATPARM *)PlgDBSubAlloc(g, NULL, sizeof(JCATPARM)))) {
+ memset(cap, 0, sizeof(JCATPARM));
+ cap->Id = fid;
+ cap->Qrp = qrp;
+ cap->DB = db;
+ cap->Tab = tab;
+ } // endif cap
+
+ return cap;
+} // end of AllocCatInfo
+
+/***********************************************************************/
+/* JDBCColumns: constructs the result blocks containing all columns */
+/* of a JDBC table that will be retrieved by GetData commands. */
+/***********************************************************************/
+PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat,
+ int maxres, bool info, PJPARM sjp)
+{
+ int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
+ TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT,
+ TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
+ XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_TABNAME, FLD_NAME,
+ FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH,
+ FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM};
+ unsigned int length[] = {0, 0, 0, 0, 6, 0, 10, 10, 6, 6, 6, 0};
+ bool b[] = {true, true, false, false, false, false, false, false, true, true, false, true};
+ int i, n, ncol = 12;
+ PCOLRES crp;
+ PQRYRES qrp;
+ JCATPARM *cap;
+ JDBConn *jcp = NULL;
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ if (!info) {
+ jcp = new(g)JDBConn(g, NULL);
+
+ if (jcp->Connect(sjp)) // openReadOnly + noJDBCdialog
+ return NULL;
+
+ if (table && !strchr(table, '%')) {
+ // We fix a MySQL limit because some data sources return 32767
+ n = jcp->GetMaxValue(1); // MAX_COLUMNS_IN_TABLE)
+ maxres = (n > 0) ? MY_MIN(n, 4096) : 4096;
+ } else if (!maxres)
+ maxres = 20000;
+
+ // n = jcp->GetMaxValue(2); MAX_CATALOG_NAME_LEN
+ // length[0] = (n) ? (n + 1) : 0;
+ // n = jcp->GetMaxValue(3); MAX_SCHEMA_NAME_LEN
+ // length[1] = (n) ? (n + 1) : 0;
+ // n = jcp->GetMaxValue(4); MAX_TABLE_NAME_LEN
+ // length[2] = (n) ? (n + 1) : 0;
+ n = jcp->GetMaxValue(5); // MAX_COLUMN_NAME_LEN
+ length[3] = (n > 0) ? (n + 1) : 128;
+ } else { // Info table
+ maxres = 0;
+ length[0] = 128;
+ length[1] = 128;
+ length[2] = 128;
+ length[3] = 128;
+ length[5] = 30;
+ length[11] = 255;
+ } // endif jcp
+
+ if (trace(1))
+ htrc("JDBCColumns: max=%d len=%d,%d,%d,%d\n",
+ maxres, length[0], length[1], length[2], length[3]);
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS,
+ buftyp, fldtyp, length, false, true);
+
+ for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
+ if (b[i])
+ crp->Kdata->SetNullable(true);
+
+ if (info || !qrp) // Info table
+ return qrp;
+
+ if (trace(1))
+ htrc("Getting col results ncol=%d\n", qrp->Nbcol);
+
+ if (!(cap = AllocCatInfo(g, JCAT_COL, db, table, qrp)))
+ return NULL;
+
+ // Colpat cannot be null or empty for some drivers
+ cap->Pat = (colpat && *colpat) ? colpat : PlugDup(g, "%");
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = jcp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+ // ResetNullValues(cap);
+
+ if (trace(1))
+ htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
+
+ } else
+ qrp = NULL;
+
+ /* Cleanup */
+ jcp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+} // end of JDBCColumns
+
+/**************************************************************************/
+/* JDBCSrcCols: constructs the result blocks containing the */
+/* description of all the columns of a Srcdef option. */
+/**************************************************************************/
+PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sjp)
+{
+ char *sqry;
+ PQRYRES qrp;
+ JDBConn *jcp = new(g)JDBConn(g, NULL);
+
+ if (jcp->Connect(sjp))
+ return NULL;
+
+ if (strstr(src, "%s")) {
+ // Place holder for an eventual where clause
+ sqry = (char*)PlugSubAlloc(g, NULL, strlen(src) + 2);
+ sprintf(sqry, src, "1=1"); // dummy where clause
+ } else
+ sqry = (char*)src;
+
+ qrp = jcp->GetMetaData(g, sqry);
+ jcp->Close();
+ return qrp;
+} // end of JDBCSrcCols
+
+/**************************************************************************/
+/* JDBCTables: constructs the result blocks containing all tables in */
+/* an JDBC database that will be retrieved by GetData commands. */
+/**************************************************************************/
+PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp,
+ int maxres, bool info, PJPARM sjp)
+{
+ int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
+ TYPE_STRING, TYPE_STRING};
+ XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_NAME, FLD_TYPE, FLD_REM};
+ unsigned int length[] = {0, 0, 0, 16, 0};
+ bool b[] = {true, true, false, false, true};
+ int i, n, ncol = 5;
+ PCOLRES crp;
+ PQRYRES qrp;
+ JCATPARM *cap;
+ JDBConn *jcp = NULL;
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ if (!info) {
+ /**********************************************************************/
+ /* Open the connection with the JDBC data source. */
+ /**********************************************************************/
+ jcp = new(g)JDBConn(g, NULL);
+
+ if (jcp->Connect(sjp))
+ return NULL;
+
+ if (!maxres)
+ maxres = 10000; // This is completely arbitrary
+
+ n = jcp->GetMaxValue(2); // Max catalog name length
+
+// if (n < 0)
+// return NULL;
+
+ length[0] = (n > 0) ? (n + 1) : 0;
+ n = jcp->GetMaxValue(3); // Max schema name length
+ length[1] = (n > 0) ? (n + 1) : 0;
+ n = jcp->GetMaxValue(4); // Max table name length
+ length[2] = (n > 0) ? (n + 1) : 128;
+ } else {
+ maxres = 0;
+ length[0] = 128;
+ length[1] = 128;
+ length[2] = 128;
+ length[4] = 255;
+ } // endif info
+
+ if (trace(1))
+ htrc("JDBCTables: max=%d len=%d,%d\n", maxres, length[0], length[1]);
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES, buftyp,
+ fldtyp, length, false, true);
+
+ for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
+ if (b[i])
+ crp->Kdata->SetNullable(true);
+
+ if (info || !qrp)
+ return qrp;
+
+ // Tabpat cannot be null or empty for some drivers
+ if (!(cap = AllocCatInfo(g, JCAT_TAB, db,
+ (tabpat && *tabpat) ? tabpat : PlugDup(g, "%"), qrp)))
+ return NULL;
+
+ cap->Pat = tabtyp;
+
+ if (trace(1))
+ htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol);
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = jcp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+ // ResetNullValues(cap);
+
+ if (trace(1))
+ htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
+
+ } else
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Close any local connection. */
+ /************************************************************************/
+ jcp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+} // end of JDBCTables
+
+/*************************************************************************/
+/* JDBCDrivers: constructs the result blocks containing all JDBC */
+/* drivers available on the local host. */
+/* Called with info=true to have result column names. */
+/*************************************************************************/
+PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info)
+{
+ int buftyp[] ={TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING};
+ XFLD fldtyp[] ={FLD_NAME, FLD_EXTRA, FLD_DEFAULT, FLD_REM };
+ unsigned int length[] ={ 128, 32, 4, 256 };
+ bool b[] ={ false, false, false, true };
+ int i, ncol = 4;
+ PCOLRES crp;
+ PQRYRES qrp;
+ JDBConn *jcp = NULL;
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ if (!info) {
+ jcp = new(g) JDBConn(g, NULL);
+
+ if (jcp->Open(g) != RC_OK)
+ return NULL;
+
+ if (!maxres)
+ maxres = 256; // Estimated max number of drivers
+
+ } else
+ maxres = 0;
+
+ if (trace(1))
+ htrc("JDBCDrivers: max=%d len=%d\n", maxres, length[0]);
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, 0, buftyp, fldtyp, length, false, true);
+
+ for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next) {
+ if (b[i])
+ crp->Kdata->SetNullable(true);
+
+ switch (i) {
+ case 0: crp->Name = "Name"; break;
+ case 1: crp->Name = "Version"; break;
+ case 2: crp->Name = "Compliant"; break;
+ case 3: crp->Name = "Description"; break;
+ } // endswitch
+
+ } // endfor i
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if (!info && qrp && jcp->GetDrivers(qrp))
+ qrp = NULL;
+
+ if (!info)
+ jcp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+} // end of JDBCDrivers
+
+/***********************************************************************/
+/* JDBConn construction/destruction. */
+/***********************************************************************/
+JDBConn::JDBConn(PGLOBAL g, PCSZ wrapper) : JAVAConn(g, wrapper)
+{
+ xqid = xuid = xid = grs = readid = fetchid = typid = errid = nullptr;
+ prepid = xpid = pcid = nullptr;
+ chrfldid = intfldid = dblfldid = fltfldid = bigfldid = nullptr;
+ objfldid = datfldid = timfldid = tspfldid = uidfldid = nullptr;
+ DiscFunc = "JdbcDisconnect";
+ m_Ncol = 0;
+ m_Aff = 0;
+ //m_Rows = 0;
+ m_Fetch = 0;
+ m_RowsetSize = 0;
+ m_Updatable = true;
+ m_Transact = false;
+ m_Scrollable = false;
+ m_Full = false;
+ m_Opened = false;
+ m_IDQuoteChar[0] = '"';
+ m_IDQuoteChar[1] = 0;
+} // end of JDBConn
+
+/***********************************************************************/
+/* Search for UUID columns. */
+/***********************************************************************/
+bool JDBConn::SetUUID(PGLOBAL g, PTDBJDBC tjp)
+{
+ int ncol, ctyp;
+ bool brc = true;
+ PCSZ fnc = "GetColumns";
+ PCOL colp;
+ JCATPARM *cap;
+ //jint jtyp;
+ jboolean rc = false;
+ jobjectArray parms;
+ jmethodID catid = nullptr;
+
+ if (gmID(g, catid, fnc, "([Ljava/lang/String;)I"))
+ return true;
+ else if (gmID(g, intfldid, "IntField", "(ILjava/lang/String;)I"))
+ return true;
+ else if (gmID(g, readid, "ReadNext", "()I"))
+ return true;
+
+ cap = AllocCatInfo(g, JCAT_COL, tjp->Schema, tjp->TableName, NULL);
+ SQLQualifiedName name(cap);
+
+ // Build the java string array
+ parms = env->NewObjectArray(4, env->FindClass("java/lang/String"), NULL);
+ env->SetObjectArrayElement(parms, 0, env->NewStringUTF(name.ptr(2)));
+ env->SetObjectArrayElement(parms, 1, env->NewStringUTF(name.ptr(1)));
+ env->SetObjectArrayElement(parms, 2, env->NewStringUTF(name.ptr(0)));
+
+ for (colp = tjp->GetColumns(); colp; colp = colp->GetNext()) {
+ env->SetObjectArrayElement(parms, 3, env->NewStringUTF(colp->GetName()));
+ ncol = env->CallIntMethod(job, catid, parms);
+
+ if (Check(ncol)) {
+ sprintf(g->Message, "%s: %s", fnc, Msg);
+ goto err;
+ } // endif Check
+
+ rc = env->CallBooleanMethod(job, readid);
+
+ if (Check(rc)) {
+ sprintf(g->Message, "ReadNext: %s", Msg);
+ goto err;
+ } else if (rc == 0) {
+ sprintf(g->Message, "table %s does not exist", tjp->TableName);
+ goto err;
+ } // endif rc
+
+ // Should return 666 is case of error (not done yet)
+ ctyp = (int)env->CallIntMethod(job, intfldid, 5, nullptr);
+
+ //if (Check((ctyp == 666) ? -1 : 1)) {
+ // sprintf(g->Message, "Getting ctyp: %s", Msg);
+ // goto err;
+ //} // endif ctyp
+
+ if (ctyp == 1111)
+ ((PJDBCCOL)colp)->uuid = true;
+
+ } // endfor colp
+
+ // All is Ok
+ brc = false;
+
+ err:
+ // Not used anymore
+ env->DeleteLocalRef(parms);
+ return brc;
+} // end of SetUUID
+
+/***********************************************************************/
+/* Utility routine. */
+/***********************************************************************/
+int JDBConn::GetMaxValue(int n)
+{
+ jint m;
+ jmethodID maxid = nullptr;
+
+ if (gmID(m_G, maxid, "GetMaxValue", "(I)I"))
+ return -1;
+
+ // call method
+ if (Check(m = env->CallIntMethod(job, maxid, n)))
+ htrc("GetMaxValue: %s", Msg);
+
+ return (int)m;
+} // end of GetMaxValue
+
+/***********************************************************************/
+/* AddJars: add some jar file to the Class path. */
+/***********************************************************************/
+void JDBConn::AddJars(PSTRG jpop, char sep)
+{
+#if defined(DEVELOPMENT)
+ jpop->Append(
+ ";C:/Jconnectors/postgresql-9.4.1208.jar"
+ ";C:/Oracle/ojdbc7.jar"
+ ";C:/Apache/commons-dbcp2-2.1.1/commons-dbcp2-2.1.1.jar"
+ ";C:/Apache/commons-pool2-2.4.2/commons-pool2-2.4.2.jar"
+ ";C:/Apache/commons-logging-1.2/commons-logging-1.2.jar"
+ ";C:/Jconnectors/mysql-connector-java-6.0.2-bin.jar"
+ ";C:/Jconnectors/mariadb-java-client-2.0.1.jar"
+ ";C:/Jconnectors/sqljdbc42.jar");
+#endif // DEVELOPMENT
+} // end of AddJars
+
+/***********************************************************************/
+/* Connect: connect to a data source. */
+/***********************************************************************/
+bool JDBConn::Connect(PJPARM sop)
+{
+ int irc = RC_FX;
+ bool err = false;
+ jint rc;
+ PGLOBAL& g = m_G;
+
+ /*******************************************************************/
+ /* Create or attach a JVM. */
+ /*******************************************************************/
+ if (Open(g))
+ return true;
+
+ if (!sop) // DRIVER catalog table
+ return false;
+
+ jmethodID cid = nullptr;
+
+ if (gmID(g, cid, "JdbcConnect", "([Ljava/lang/String;IZ)I"))
+ return true;
+
+ // Build the java string array
+ jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4
+ env->FindClass("java/lang/String"), NULL); // Strings
+
+ m_Scrollable = sop->Scrollable;
+ m_RowsetSize = sop->Fsize;
+ //m_LoginTimeout = sop->Cto;
+ //m_QueryTimeout = sop->Qto;
+ //m_UseCnc = sop->UseCnc;
+
+ // change some elements
+ if (sop->Driver)
+ env->SetObjectArrayElement(parms, 0, env->NewStringUTF(sop->Driver));
+
+ if (sop->Url)
+ env->SetObjectArrayElement(parms, 1, env->NewStringUTF(sop->Url));
+
+ if (sop->User)
+ env->SetObjectArrayElement(parms, 2, env->NewStringUTF(sop->User));
+
+ if (sop->Pwd)
+ env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd));
+
+ // call method
+ rc = env->CallIntMethod(job, cid, parms, m_RowsetSize, m_Scrollable);
+ err = Check(rc);
+ env->DeleteLocalRef(parms); // Not used anymore
+
+ if (err) {
+ sprintf(g->Message, "Connecting: %s rc=%d", Msg, (int)rc);
+ return true;
+ } // endif Msg
+
+ jmethodID qcid = nullptr;
+
+ if (!gmID(g, qcid, "GetQuoteString", "()Ljava/lang/String;")) {
+ jstring s = (jstring)env->CallObjectMethod(job, qcid);
+
+ if (s != nullptr) {
+ char *qch = GetUTFString(s);
+ m_IDQuoteChar[0] = *qch;
+ } else {
+ s = (jstring)env->CallObjectMethod(job, errid);
+ Msg = GetUTFString(s);
+ } // endif s
+
+ } // endif qcid
+
+ if (gmID(g, typid, "ColumnType", "(ILjava/lang/String;)I"))
+ return true;
+ else
+ m_Connected = true;
+
+ return false;
+} // end of Connect
+
+
+/***********************************************************************/
+/* Execute an SQL command. */
+/***********************************************************************/
+int JDBConn::ExecuteCommand(PCSZ sql)
+{
+ int rc;
+ jint n;
+ jstring qry;
+ PGLOBAL& g = m_G;
+
+ // Get the methods used to execute a query and get the result
+ if (gmID(g, xid, "Execute", "(Ljava/lang/String;)I") ||
+ gmID(g, grs, "GetResult", "()I"))
+ return RC_FX;
+
+ qry = env->NewStringUTF(sql);
+ n = env->CallIntMethod(job, xid, qry);
+ env->DeleteLocalRef(qry);
+
+ if (Check(n)) {
+ sprintf(g->Message, "Execute: %s", Msg);
+ return RC_FX;
+ } // endif n
+
+ m_Ncol = env->CallIntMethod(job, grs);
+
+ if (Check(m_Ncol)) {
+ sprintf(g->Message, "GetResult: %s", Msg);
+ rc = RC_FX;
+ } else if (m_Ncol) {
+ strcpy(g->Message, "Result set column number");
+ rc = RC_OK; // A result set was returned
+ } else {
+ m_Aff = (int)n; // Affected rows
+ strcpy(g->Message, "Affected rows");
+ rc = RC_NF;
+ } // endif ncol
+
+ return rc;
+} // end of ExecuteCommand
+
+/***********************************************************************/
+/* Fetch next row. */
+/***********************************************************************/
+int JDBConn::Fetch(int pos)
+{
+ jint rc = JNI_ERR;
+ PGLOBAL& g = m_G;
+
+ if (m_Full) // Result set has one row
+ return 1;
+
+ if (pos) {
+ if (!m_Scrollable) {
+ strcpy(g->Message, "Cannot fetch(pos) if FORWARD ONLY");
+ return rc;
+ } else if (gmID(m_G, fetchid, "Fetch", "(I)Z"))
+ return rc;
+
+ if (env->CallBooleanMethod(job, fetchid, pos))
+ rc = m_Rows;
+
+ } else {
+ if (gmID(g, readid, "ReadNext", "()I"))
+ return rc;
+
+ rc = env->CallBooleanMethod(job, readid);
+
+ if (!Check(rc)) {
+ if (rc == 0)
+ m_Full = (m_Fetch == 1);
+ else
+ m_Fetch++;
+
+ m_Rows += (int)rc;
+ } else
+ sprintf(g->Message, "Fetch: %s", Msg);
+
+ } // endif pos
+
+ return (int)rc;
+} // end of Fetch
+
+/***********************************************************************/
+/* Restart from beginning of result set */
+/***********************************************************************/
+int JDBConn::Rewind(PCSZ sql)
+{
+ int rbuf = -1;
+
+ if (m_Full)
+ rbuf = m_Rows; // No need to "rewind"
+ else if (m_Scrollable) {
+ if (gmID(m_G, fetchid, "Fetch", "(I)Z"))
+ return -1;
+
+ (void) env->CallBooleanMethod(job, fetchid, 0);
+
+ rbuf = m_Rows;
+ } else if (ExecuteCommand(sql) != RC_FX)
+ rbuf = 0;
+
+ return rbuf;
+} // end of Rewind
+
+/***********************************************************************/
+/* Retrieve and set the column value from the result set. */
+/***********************************************************************/
+void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val)
+{
+ const char *field;
+ PGLOBAL& g = m_G;
+ jint ctyp;
+ jstring cn, jn = nullptr;
+ jobject jb = nullptr;
+
+ if (rank == 0)
+ if (!name || (jn = env->NewStringUTF(name)) == nullptr) {
+ sprintf(g->Message, "Fail to allocate jstring %s", SVP(name));
+ throw (int)TYPE_AM_JDBC;
+ } // endif name
+
+ // Returns 666 is case of error
+ ctyp = env->CallIntMethod(job, typid, rank, jn);
+
+ if (Check((ctyp == 666) ? -1 : 1)) {
+ sprintf(g->Message, "Getting ctyp: %s", Msg);
+ throw (int)TYPE_AM_JDBC;
+ } // endif Check
+
+ if (val->GetNullable())
+ if (!gmID(g, objfldid, "ObjectField", "(ILjava/lang/String;)Ljava/lang/Object;")) {
+ jb = env->CallObjectMethod(job, objfldid, (jint)rank, jn);
+
+ if (Check(0)) {
+ sprintf(g->Message, "Getting jp: %s", Msg);
+ throw (int)TYPE_AM_JDBC;
+ } // endif Check
+
+ if (jb == nullptr) {
+ val->Reset();
+ val->SetNull(true);
+ goto chk;
+ } // endif job
+
+ } // endif objfldid
+
+ switch (ctyp) {
+ case 12: // VARCHAR
+ case -9: // NVARCHAR
+ case -1: // LONGVARCHAR, TEXT
+ case 1: // CHAR
+ case -15: // NCHAR
+ case -16: // LONGNVARCHAR, NTEXT
+ case 3: // DECIMAL
+ case -8: // ROWID
+ if (jb && ctyp != 3)
+ cn = (jstring)jb;
+ else if (!gmID(g, chrfldid, "StringField", "(ILjava/lang/String;)Ljava/lang/String;"))
+ cn = (jstring)env->CallObjectMethod(job, chrfldid, (jint)rank, jn);
+ else
+ cn = nullptr;
+
+ if (cn) {
+ field = GetUTFString(cn);
+ val->SetValue_psz((PSZ)field);
+ } else
+ val->Reset();
+
+ break;
+ case 4: // INTEGER
+ case 5: // SMALLINT
+ case -6: // TINYINT
+ case 16: // BOOLEAN
+ case -7: // BIT
+ if (!gmID(g, intfldid, "IntField", "(ILjava/lang/String;)I"))
+ val->SetValue((int)env->CallIntMethod(job, intfldid, rank, jn));
+ else
+ val->Reset();
+
+ break;
+ case 8: // DOUBLE
+ case 2: // NUMERIC
+//case 3: // DECIMAL
+ if (!gmID(g, dblfldid, "DoubleField", "(ILjava/lang/String;)D"))
+ val->SetValue((double)env->CallDoubleMethod(job, dblfldid, rank, jn));
+ else
+ val->Reset();
+
+ break;
+ case 7: // REAL
+ case 6: // FLOAT
+ if (!gmID(g, fltfldid, "FloatField", "(ILjava/lang/String;)F"))
+ val->SetValue((float)env->CallFloatMethod(job, fltfldid, rank, jn));
+ else
+ val->Reset();
+
+ break;
+ case 91: // DATE
+ if (!gmID(g, datfldid, "DateField", "(ILjava/lang/String;)I")) {
+ val->SetValue((int)env->CallIntMethod(job, datfldid, (jint)rank, jn));
+ } else
+ val->Reset();
+
+ break;
+ case 92: // TIME
+ if (!gmID(g, timfldid, "TimeField", "(ILjava/lang/String;)I")) {
+ val->SetValue((int)env->CallIntMethod(job, timfldid, (jint)rank, jn));
+ } else
+ val->Reset();
+
+ break;
+ case 93: // TIMESTAMP
+ if (!gmID(g, tspfldid, "TimestampField", "(ILjava/lang/String;)I")) {
+ val->SetValue((int)env->CallIntMethod(job, tspfldid, (jint)rank, jn));
+ } else
+ val->Reset();
+
+ break;
+ case -5: // BIGINT
+ if (!gmID(g, bigfldid, "BigintField", "(ILjava/lang/String;)J"))
+ val->SetValue((long long)env->CallLongMethod(job, bigfldid, (jint)rank, jn));
+ else
+ val->Reset();
+
+ break;
+ /* case java.sql.Types.SMALLINT:
+ System.out.print(jdi.IntField(i));
+ break;
+ case java.sql.Types.BOOLEAN:
+ System.out.print(jdi.BooleanField(i)); */
+ case 1111: // UUID
+ if (!gmID(g, uidfldid, "UuidField", "(ILjava/lang/String;)Ljava/lang/String;"))
+ cn = (jstring)env->CallObjectMethod(job, uidfldid, (jint)rank, jn);
+ else
+ cn = nullptr;
+
+ if (cn) {
+ val->SetValue_psz((PSZ)GetUTFString(cn));
+ } else
+ val->Reset();
+
+ break;
+ case 0: // NULL
+ val->SetNull(true);
+ // passthru
+ default:
+ val->Reset();
+ } // endswitch Type
+
+ chk:
+ if (Check()) {
+ if (rank == 0)
+ env->DeleteLocalRef(jn);
+
+ sprintf(g->Message, "SetColumnValue: %s rank=%d ctyp=%d", Msg, rank, (int)ctyp);
+ throw (int)TYPE_AM_JDBC;
+ } // endif Check
+
+ if (rank == 0)
+ env->DeleteLocalRef(jn);
+
+} // end of SetColumnValue
+
+/***********************************************************************/
+/* Prepare an SQL statement for insert. */
+/***********************************************************************/
+bool JDBConn::PrepareSQL(PCSZ sql)
+{
+ bool b = true;
+ PGLOBAL& g = m_G;
+
+ if (!gmID(g, prepid, "CreatePrepStmt", "(Ljava/lang/String;)I")) {
+ // Create the prepared statement
+ jstring qry = env->NewStringUTF(sql);
+
+ if (Check(env->CallBooleanMethod(job, prepid, qry)))
+ sprintf(g->Message, "CreatePrepStmt: %s", Msg);
+ else
+ b = false;
+
+ env->DeleteLocalRef(qry);
+ } // endif prepid
+
+ return b;
+} // end of PrepareSQL
+
+/***********************************************************************/
+/* Execute an SQL query that returns a result set. */
+/***********************************************************************/
+int JDBConn::ExecuteQuery(PCSZ sql)
+{
+ int rc = RC_FX;
+ jint ncol;
+ jstring qry;
+ PGLOBAL& g = m_G;
+
+ // Get the methods used to execute a query and get the result
+ if (!gmID(g, xqid, "ExecuteQuery", "(Ljava/lang/String;)I")) {
+ qry = env->NewStringUTF(sql);
+ ncol = env->CallIntMethod(job, xqid, qry);
+
+ if (!Check(ncol)) {
+ m_Ncol = (int)ncol;
+ m_Aff = 0; // Affected rows
+ rc = RC_OK;
+ } else
+ sprintf(g->Message, "ExecuteQuery: %s", Msg);
+
+ env->DeleteLocalRef(qry);
+ } // endif xqid
+
+ return rc;
+} // end of ExecuteQuery
+
+/***********************************************************************/
+/* Execute an SQL query and get the affected rows. */
+/***********************************************************************/
+int JDBConn::ExecuteUpdate(PCSZ sql)
+{
+ int rc = RC_FX;
+ jint n;
+ jstring qry;
+ PGLOBAL& g = m_G;
+
+ // Get the methods used to execute a query and get the affected rows
+ if (!gmID(g, xuid, "ExecuteUpdate", "(Ljava/lang/String;)I")) {
+ qry = env->NewStringUTF(sql);
+ n = env->CallIntMethod(job, xuid, qry);
+
+ if (!Check(n)) {
+ m_Ncol = 0;
+ m_Aff = (int)n; // Affected rows
+ rc = RC_OK;
+ } else
+ sprintf(g->Message, "ExecuteUpdate: %s n=%d", Msg, n);
+
+ env->DeleteLocalRef(qry);
+ } // endif xuid
+
+ return rc;
+} // end of ExecuteUpdate
+
+/***********************************************************************/
+/* Get the number of lines of the result set. */
+/***********************************************************************/
+int JDBConn::GetResultSize(PCSZ sql, PCOL colp)
+{
+ int rc;
+
+ if ((rc = ExecuteQuery(sql)) != RC_OK)
+ return -1;
+
+ if ((rc = Fetch()) > 0) {
+ try {
+ SetColumnValue(1, NULL, colp->GetValue());
+ } catch (...) {
+ return -4;
+ } // end catch
+
+ } else
+ return -2;
+
+ if ((rc = Fetch()) != 0)
+ return -3;
+
+ m_Full = false;
+ return colp->GetIntValue();
+} // end of GetResultSize
+
+/***********************************************************************/
+/* Execute a prepared statement. */
+/***********************************************************************/
+int JDBConn::ExecuteSQL(void)
+{
+ int rc = RC_FX;
+ PGLOBAL& g = m_G;
+
+ // Get the methods used to execute a prepared statement
+ if (!gmID(g, xpid, "ExecutePrep", "()I")) {
+ jint n = env->CallIntMethod(job, xpid);
+
+ if (n == -3)
+ strcpy(g->Message, "SQL statement is not prepared");
+ else if (Check(n))
+ sprintf(g->Message, "ExecutePrep: %s", Msg);
+ else {
+ m_Aff = (int)n;
+ rc = RC_OK;
+ } // endswitch n
+
+ } // endif xpid
+
+ return rc;
+} // end of ExecuteSQL
+
+/***********************************************************************/
+/* Set a parameter for inserting. */
+/***********************************************************************/
+bool JDBConn::SetParam(JDBCCOL *colp)
+{
+ PGLOBAL& g = m_G;
+ bool rc = false;
+ PVAL val = colp->GetValue();
+ jint n, jrc = 0, i = (jint)colp->GetRank();
+ jshort s;
+ jlong lg;
+//jfloat f;
+ jdouble d;
+ jclass dat;
+ jobject datobj;
+ jstring jst = nullptr;
+ jmethodID dtc, setid = nullptr;
+
+ if (val->GetNullable() && val->IsNull()) {
+ if (gmID(g, setid, "SetNullParm", "(II)I"))
+ return true;
+
+ jrc = env->CallIntMethod(job, setid, i,
+ (colp->uuid ? 1111 : (jint)GetJDBCType(val->GetType())));
+ } else if (colp->uuid) {
+ if (gmID(g, setid, "SetUuidParm", "(ILjava/lang/String;)V"))
+ return true;
+
+ jst = env->NewStringUTF(val->GetCharValue());
+ env->CallVoidMethod(job, setid, i, jst);
+ } else switch (val->GetType()) {
+ case TYPE_STRING:
+ if (gmID(g, setid, "SetStringParm", "(ILjava/lang/String;)V"))
+ return true;
+
+ jst = env->NewStringUTF(val->GetCharValue());
+ env->CallVoidMethod(job, setid, i, jst);
+ break;
+ case TYPE_INT:
+ if (gmID(g, setid, "SetIntParm", "(II)V"))
+ return true;
+
+ n = (jint)val->GetIntValue();
+ env->CallVoidMethod(job, setid, i, n);
+ break;
+ case TYPE_TINY:
+ case TYPE_SHORT:
+ if (gmID(g, setid, "SetShortParm", "(IS)V"))
+ return true;
+
+ s = (jshort)val->GetShortValue();
+ env->CallVoidMethod(job, setid, i, s);
+ break;
+ case TYPE_BIGINT:
+ if (gmID(g, setid, "SetBigintParm", "(IJ)V"))
+ return true;
+
+ lg = (jlong)val->GetBigintValue();
+ env->CallVoidMethod(job, setid, i, lg);
+ break;
+ case TYPE_DOUBLE:
+ case TYPE_DECIM:
+ if (gmID(g, setid, "SetDoubleParm", "(ID)V"))
+ return true;
+
+ d = (jdouble)val->GetFloatValue();
+ env->CallVoidMethod(job, setid, i, d);
+ break;
+ case TYPE_DATE:
+ if ((dat = env->FindClass("java/sql/Timestamp")) == nullptr) {
+ strcpy(g->Message, "Cannot find Timestamp class");
+ return true;
+ } else if (!(dtc = env->GetMethodID(dat, "<init>", "(J)V"))) {
+ strcpy(g->Message, "Cannot find Timestamp class constructor");
+ return true;
+ } // endif's
+
+ lg = (jlong)val->GetBigintValue() * 1000;
+
+ if ((datobj = env->NewObject(dat, dtc, lg)) == nullptr) {
+ strcpy(g->Message, "Cannot make Timestamp object");
+ return true;
+ } else if (gmID(g, setid, "SetTimestampParm", "(ILjava/sql/Timestamp;)V"))
+ return true;
+
+ env->CallVoidMethod(job, setid, i, datobj);
+ break;
+ default:
+ sprintf(g->Message, "Parm type %d not supported", val->GetType());
+ return true;
+ } // endswitch Type
+
+ if (Check(jrc)) {
+ sprintf(g->Message, "SetParam: col=%s msg=%s", colp->GetName(), Msg);
+ rc = true;
+ } // endif msg
+
+ if (jst)
+ env->DeleteLocalRef(jst);
+
+ return rc;
+ } // end of SetParam
+
+ /***********************************************************************/
+ /* Get the list of Drivers and set it in qrp. */
+ /***********************************************************************/
+ bool JDBConn::GetDrivers(PQRYRES qrp)
+ {
+ PSZ sval;
+ int i, n, size;
+ PCOLRES crp;
+ jstring js;
+ jmethodID gdid = nullptr;
+
+ if (gmID(m_G, gdid, "GetDrivers", "([Ljava/lang/String;I)I"))
+ return true;
+
+ // Build the java string array
+ jobjectArray s = env->NewObjectArray(4 * qrp->Maxres,
+ env->FindClass("java/lang/String"), NULL);
+
+ size = env->CallIntMethod(job, gdid, s, qrp->Maxres);
+
+ for (i = 0, n = 0; i < size; i++) {
+ crp = qrp->Colresp;
+ js = (jstring)env->GetObjectArrayElement(s, n++);
+ sval = GetUTFString(js);
+ crp->Kdata->SetValue(sval, i);
+ crp = crp->Next;
+ js = (jstring)env->GetObjectArrayElement(s, n++);
+ sval = GetUTFString(js);
+ crp->Kdata->SetValue(sval, i);
+ crp = crp->Next;
+ js = (jstring)env->GetObjectArrayElement(s, n++);
+ sval = GetUTFString(js);
+ crp->Kdata->SetValue(sval, i);
+ crp = crp->Next;
+ js = (jstring)env->GetObjectArrayElement(s, n++);
+ sval = GetUTFString(js);
+ crp->Kdata->SetValue(sval, i);
+ } // endfor i
+
+ // Not used anymore
+ env->DeleteLocalRef(s);
+
+ qrp->Nblin = size;
+ return false;
+ } // end of GetDrivers
+
+ /**************************************************************************/
+ /* GetMetaData: constructs the result blocks containing the */
+ /* description of all the columns of an SQL command. */
+ /**************************************************************************/
+ PQRYRES JDBConn::GetMetaData(PGLOBAL g, PCSZ src)
+ {
+ static int buftyp[] = {TYPE_STRING, TYPE_INT, TYPE_INT,
+ TYPE_INT, TYPE_INT};
+ static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_PREC,
+ FLD_SCALE, FLD_NULL };
+ static unsigned int length[] = {0, 6, 10, 6, 6};
+ const char *name;
+ int len, qcol = 5;
+ PQRYRES qrp = NULL;
+ PCOLRES crp;
+ ushort i;
+ jint *n = nullptr;
+ jstring label;
+ jmethodID colid = nullptr;
+ int rc = ExecuteCommand(src);
+
+ if (rc == RC_NF) {
+ strcpy(g->Message, "Srcdef is not returning a result set");
+ return NULL;
+ } else if ((rc) == RC_FX) {
+ return NULL;
+ } else if (m_Ncol == 0) {
+ strcpy(g->Message, "Invalid Srcdef");
+ return NULL;
+ } // endif's
+
+ if (gmID(g, colid, "ColumnDesc", "(I[I)Ljava/lang/String;"))
+ return NULL;
+
+ // Get max column name length
+ len = GetMaxValue(5);
+ length[0] = (len > 0) ? len + 1 : 128;
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ if (!(qrp = PlgAllocResult(g, qcol, m_Ncol, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, true)))
+ return NULL;
+
+ // Some columns must be renamed
+ for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
+ switch (++i) {
+ case 3: crp->Name = "Precision"; break;
+ case 4: crp->Name = "Scale"; break;
+ case 5: crp->Name = "Nullable"; break;
+ } // endswitch i
+
+ // Build the java int array
+ jintArray val = env->NewIntArray(4);
+
+ if (val == nullptr) {
+ strcpy(m_G->Message, "Cannot allocate jint array");
+ return NULL;
+ } // endif colid
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ for (i = 0; i < m_Ncol; i++) {
+ if (!(label = (jstring)env->CallObjectMethod(job, colid, i + 1, val))) {
+ if (Check())
+ sprintf(g->Message, "ColumnDesc: %s", Msg);
+ else
+ strcpy(g->Message, "No result metadata");
+
+ env->ReleaseIntArrayElements(val, n, 0);
+ return NULL;
+ } // endif label
+
+ name = GetUTFString(label);
+ crp = qrp->Colresp; // Column_Name
+ crp->Kdata->SetValue((char*)name, i);
+ n = env->GetIntArrayElements(val, 0);
+ crp = crp->Next; // Data_Type
+ crp->Kdata->SetValue((int)n[0], i);
+ crp = crp->Next; // Precision (length)
+ crp->Kdata->SetValue((int)n[1], i);
+ crp = crp->Next; // Scale
+ crp->Kdata->SetValue((int)n[2], i);
+ crp = crp->Next; // Nullable
+ crp->Kdata->SetValue((int)n[3], i);
+ qrp->Nblin++;
+ } // endfor i
+
+ /* Cleanup */
+ env->ReleaseIntArrayElements(val, n, 0);
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of GetMetaData
+
+ /***********************************************************************/
+ /* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */
+ /***********************************************************************/
+ int JDBConn::GetCatInfo(JCATPARM *cap)
+ {
+ PGLOBAL& g = m_G;
+// void *buffer;
+ int i, ncol;
+ PCSZ fnc = "Unknown";
+ uint n;
+ short len, tp;
+ PQRYRES qrp = cap->Qrp;
+ PCOLRES crp;
+ jboolean rc = false;
+// HSTMT hstmt = NULL;
+// SQLLEN *vl, *vlen = NULL;
+ PVAL *pval = NULL;
+ char* *pbuf = NULL;
+ jobjectArray parms;
+ jmethodID catid = nullptr;
+
+ if (qrp->Maxres <= 0)
+ return 0; // 0-sized result"
+
+ SQLQualifiedName name(cap);
+
+ // Build the java string array
+ parms = env->NewObjectArray(4, env->FindClass("java/lang/String"), NULL);
+ env->SetObjectArrayElement(parms, 0, env->NewStringUTF(name.ptr(2)));
+ env->SetObjectArrayElement(parms, 1, env->NewStringUTF(name.ptr(1)));
+ env->SetObjectArrayElement(parms, 2, env->NewStringUTF(name.ptr(0)));
+ env->SetObjectArrayElement(parms, 3, env->NewStringUTF((const char*)cap->Pat));
+
+ // Now do call the proper JDBC API
+ switch (cap->Id) {
+ case JCAT_COL:
+ fnc = "GetColumns";
+ break;
+ case JCAT_TAB:
+ fnc = "GetTables";
+ break;
+#if 0
+ case JCAT_KEY:
+ fnc = "SQLPrimaryKeys";
+ rc = SQLPrimaryKeys(hstmt, name.ptr(2), name.length(2),
+ name.ptr(1), name.length(1),
+ name.ptr(0), name.length(0));
+ break;
+#endif // 0
+ default:
+ sprintf(g->Message, "Invalid SQL function id");
+ return -1;
+ } // endswitch infotype
+
+ if (gmID(g, catid, fnc, "([Ljava/lang/String;)I"))
+ return -1;
+
+ // call method
+ ncol = env->CallIntMethod(job, catid, parms);
+
+ if (Check(ncol)) {
+ sprintf(g->Message, "%s: %s", fnc, Msg);
+ env->DeleteLocalRef(parms);
+ return -1;
+ } // endif Check
+
+ // Not used anymore
+ env->DeleteLocalRef(parms);
+
+ if (trace(1))
+ htrc("Method %s returned %d columns\n", fnc, ncol);
+
+ // n because we no more ignore the first column
+ if ((n = qrp->Nbcol) > (uint)ncol) {
+ strcpy(g->Message, MSG(COL_NUM_MISM));
+ return -1;
+ } // endif n
+
+ // Unconditional to handle STRBLK's
+ pval = (PVAL *)PlugSubAlloc(g, NULL, n * sizeof(PVAL));
+// vlen = (SQLLEN *)PlugSubAlloc(g, NULL, n * sizeof(SQLLEN));
+ pbuf = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
+
+ // Prepare retrieving column values
+ for (n = 0, crp = qrp->Colresp; crp; crp = crp->Next) {
+ if (!(tp = GetJDBCType(crp->Type))) {
+ sprintf(g->Message, MSG(INV_COLUMN_TYPE), crp->Type, crp->Name);
+ return -1;
+ } // endif tp
+
+ if (!(len = GetTypeSize(crp->Type, crp->Length))) {
+ len = 255; // for STRBLK's
+ ((STRBLK*)crp->Kdata)->SetSorted(true);
+ } // endif len
+
+ pval[n] = AllocateValue(g, crp->Type, len);
+ pval[n]->SetNullable(true);
+
+ if (crp->Type == TYPE_STRING) {
+ pbuf[n] = (char*)PlugSubAlloc(g, NULL, len);
+// buffer = pbuf[n];
+ } // endif Type
+// } else
+// buffer = pval[n]->GetTo_Val();
+
+ n++;
+ } // endfor n
+
+ // Now fetch the result
+ for (i = 0; i < qrp->Maxres; i++) {
+ if (Check(rc = Fetch(0))) {
+ sprintf(g->Message, "Fetch: %s", Msg);
+ return -1;
+ } if (rc == 0) {
+ if (trace(1))
+ htrc("End of fetches i=%d\n", i);
+
+ break;
+ } // endif rc
+
+ for (n = 0, crp = qrp->Colresp; crp; n++, crp = crp->Next) {
+ SetColumnValue(n + 1, nullptr, pval[n]);
+ crp->Kdata->SetValue(pval[n], i);
+ } // endfor n
+
+ } // endfor i
+
+ if (rc > 0)
+ qrp->Truncated = true;
+
+ return i;
+ } // end of GetCatInfo
+
+ /***********************************************************************/
+ /* Allocate a CONNECT result structure from the JDBC result. */
+ /***********************************************************************/
+ PQRYRES JDBConn::AllocateResult(PGLOBAL g, PTDB tdbp)
+ {
+ bool uns;
+ PCOL colp;
+ PCOLRES *pcrp, crp;
+ PQRYRES qrp;
+
+ if (!m_Rows) {
+ strcpy(g->Message, "Void result");
+ return NULL;
+ } // endif m_Rows
+
+ /*********************************************************************/
+ /* Allocate the result storage for future retrieval. */
+ /*********************************************************************/
+ qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
+ pcrp = &qrp->Colresp;
+ qrp->Continued = FALSE;
+ qrp->Truncated = FALSE;
+ qrp->Info = FALSE;
+ qrp->Suball = TRUE;
+ qrp->BadLines = 0;
+ qrp->Maxsize = m_Rows;
+ qrp->Maxres = m_Rows;
+ qrp->Nbcol = 0;
+ qrp->Nblin = 0;
+ qrp->Cursor = 0;
+
+ for (colp = tdbp->GetColumns(); colp; colp = colp->GetNext())
+ if (!colp->IsSpecial()) {
+ *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
+ crp = *pcrp;
+ pcrp = &crp->Next;
+ memset(crp, 0, sizeof(COLRES));
+ crp->Ncol = ++qrp->Nbcol;
+ crp->Name = colp->GetName();
+ crp->Type = colp->GetResultType();
+ crp->Prec = colp->GetScale();
+ crp->Length = colp->GetLength();
+ crp->Clen = colp->GetValue()->GetClen();
+ uns = colp->IsUnsigned();
+
+ if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
+ crp->Clen, 0, FALSE, TRUE, uns))) {
+ sprintf(g->Message, MSG(INV_RESULT_TYPE),
+ GetFormatType(crp->Type));
+ return NULL;
+ } // endif Kdata
+
+ if (!colp->IsNullable())
+ crp->Nulls = NULL;
+ else {
+ crp->Nulls = (char*)PlugSubAlloc(g, NULL, m_Rows);
+ memset(crp->Nulls, ' ', m_Rows);
+ } // endelse Nullable
+
+ ((EXTCOL*)colp)->SetCrp(crp);
+ } // endif colp
+
+ *pcrp = NULL;
+ return qrp;
+ } // end of AllocateResult
diff --git a/storage/connect/jdbconn.h b/storage/connect/jdbconn.h
new file mode 100644
index 00000000..0c36ccca
--- /dev/null
+++ b/storage/connect/jdbconn.h
@@ -0,0 +1,92 @@
+/***********************************************************************/
+/* JDBConn.h : header file for the JDBC connection classes. */
+/***********************************************************************/
+#include "javaconn.h"
+
+// JDBC connection to a data source
+class TDBJDBC;
+class JDBCCOL;
+class JDBConn;
+class TDBXJDC;
+
+/***********************************************************************/
+/* JDBConn class. */
+/***********************************************************************/
+class JDBConn : public JAVAConn {
+ friend class TDBJDBC;
+ friend class TDBXJDC;
+//friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
+private:
+ JDBConn(); // Standard (unused) constructor
+
+public:
+ // Constructor
+ JDBConn(PGLOBAL g, PCSZ wrapper);
+
+ virtual void AddJars(PSTRG jpop, char sep);
+ PQRYRES AllocateResult(PGLOBAL g, PTDB tdbp);
+
+ // Attributes
+public:
+ char *GetQuoteChar(void) { return m_IDQuoteChar; }
+ bool SetUUID(PGLOBAL g, PTDBJDBC tjp);
+ virtual int GetMaxValue(int infotype);
+
+public:
+ // Operations
+ virtual bool Connect(PJPARM sop);
+ virtual bool MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options,
+ PCSZ filter, bool pipe) {return true;}
+ virtual int GetResultSize(PCSZ sql, PCOL colp);
+ virtual int ExecuteCommand(PCSZ sql);
+ virtual int ExecuteQuery(PCSZ sql);
+ virtual int ExecuteUpdate(PCSZ sql);
+ virtual int Fetch(int pos = 0);
+ virtual void SetColumnValue(int rank, PSZ name, PVAL val);
+
+ // Jdbc operations
+ bool PrepareSQL(PCSZ sql);
+ int ExecuteSQL(void); // Prepared statement
+ bool SetParam(JDBCCOL *colp);
+ int GetCatInfo(JCATPARM *cap);
+ bool GetDrivers(PQRYRES qrp);
+ PQRYRES GetMetaData(PGLOBAL g, PCSZ src);
+ int Rewind(PCSZ sql);
+
+ // Implementation
+public:
+ //virtual ~JDBConn();
+
+protected:
+ // Members
+ jmethodID xqid; // The ExecuteQuery method ID
+ jmethodID xuid; // The ExecuteUpdate method ID
+ jmethodID xid; // The Execute method ID
+ jmethodID grs; // The GetResult method ID
+ jmethodID readid; // The ReadNext method ID
+ jmethodID fetchid; // The Fetch method ID
+ jmethodID typid; // The ColumnType method ID
+ jmethodID prepid; // The CreatePrepStmt method ID
+ jmethodID xpid; // The ExecutePrep method ID
+ jmethodID pcid; // The ClosePrepStmt method ID
+ jmethodID objfldid; // The ObjectField method ID
+ jmethodID chrfldid; // The StringField method ID
+ jmethodID intfldid; // The IntField method ID
+ jmethodID dblfldid; // The DoubleField method ID
+ jmethodID fltfldid; // The FloatField method ID
+ jmethodID datfldid; // The DateField method ID
+ jmethodID timfldid; // The TimeField method ID
+ jmethodID tspfldid; // The TimestampField method ID
+ jmethodID bigfldid; // The BigintField method ID
+ jmethodID uidfldid; // The UuidField method ID
+ char m_IDQuoteChar[2];
+ PCSZ m_Pwd;
+ int m_Ncol;
+ int m_Aff;
+ int m_Fetch;
+ int m_RowsetSize;
+ jboolean m_Updatable;
+ jboolean m_Transact;
+ jboolean m_Scrollable;
+ bool m_Full;
+}; // end of JDBConn class definition
diff --git a/storage/connect/jmgfam.cpp b/storage/connect/jmgfam.cpp
new file mode 100644
index 00000000..670781da
--- /dev/null
+++ b/storage/connect/jmgfam.cpp
@@ -0,0 +1,390 @@
+/************ JMONGO FAM C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: jmgfam.cpp */
+/* ------------- */
+/* Version 1.2 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 20017 - 2021 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the Java MongoDB access method classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+//#include <io.h>
+//#include <fcntl.h>
+//#include <errno.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX) || defined(UNIV_LINUX)
+//#include <errno.h>
+#include <unistd.h>
+//#if !defined(sun) // Sun has the ftruncate fnc.
+//#define USETEMP // Force copy mode for DELETE
+//#endif // !sun
+#else // !UNIX
+//#include <io.h>
+#endif // !UNIX
+//#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* filamtxt.h is header containing the file AM classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "reldef.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#if defined(BSON_SUPPORT)
+#include "tabbson.h"
+#else
+#include "tabjson.h"
+#endif // BSON_SUPPORT
+#include "jmgfam.h"
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#include "osutil.h"
+//#define _fileno fileno
+//#define _O_RDONLY O_RDONLY
+#endif
+
+/* --------------------------- Class JMGFAM -------------------------- */
+
+/***********************************************************************/
+/* Constructors. */
+/***********************************************************************/
+JMGFAM::JMGFAM(PJDEF tdp) : DOSFAM((PDOSDEF)NULL)
+{
+ Jcp = NULL;
+ //Client = NULL;
+ //Database = NULL;
+ //Collection = NULL;
+ //Cursor = NULL;
+ //Query = NULL;
+ //Opts = NULL;
+ Ops.Driver = tdp->Schema;
+ Ops.Url = tdp->Uri;
+ Ops.User = NULL;
+ Ops.Pwd = NULL;
+ Ops.Scrollable = false;
+ Ops.Fsize = 0;
+ Ops.Version = tdp->Version;
+ To_Fbt = NULL;
+ Mode = MODE_ANY;
+ Uristr = tdp->Uri;
+ Db_name = tdp->Schema;
+ Coll_name = tdp->Collname;
+ Options = tdp->Options;
+ Filter = tdp->Filter;
+ Wrapname = tdp->Wrapname;
+ Done = false;
+ Pipe = tdp->Pipe;
+ Version = tdp->Version;
+ Lrecl = tdp->Lrecl + tdp->Ending;
+ Curpos = 0;
+} // end of JMGFAM Json standard constructor
+
+#if defined(BSON_SUPPORT)
+JMGFAM::JMGFAM(PBDEF tdp) : DOSFAM((PDOSDEF)NULL)
+{
+ Jcp = NULL;
+ Ops.Driver = tdp->Schema;
+ Ops.Url = tdp->Uri;
+ Ops.User = NULL;
+ Ops.Pwd = NULL;
+ Ops.Scrollable = false;
+ Ops.Fsize = 0;
+ Ops.Version = tdp->Version;
+ To_Fbt = NULL;
+ Mode = MODE_ANY;
+ Uristr = tdp->Uri;
+ Db_name = tdp->Schema;
+ Coll_name = tdp->Collname;
+ Options = tdp->Options;
+ Filter = tdp->Filter;
+ Wrapname = tdp->Wrapname;
+ Done = false;
+ Pipe = tdp->Pipe;
+ Version = tdp->Version;
+ Lrecl = tdp->Lrecl + tdp->Ending;
+ Curpos = 0;
+} // end of JMGFAM Bson standard constructor
+#endif // BSON_SUPPORT
+
+JMGFAM::JMGFAM(PJMGFAM tdfp) : DOSFAM(tdfp)
+{
+ Jcp = tdfp->Jcp;
+ //Client = tdfp->Client;
+ //Database = NULL;
+ //Collection = tdfp->Collection;
+ //Cursor = tdfp->Cursor;
+ //Query = tdfp->Query;
+ //Opts = tdfp->Opts;
+ Ops = tdfp->Ops;
+ To_Fbt = tdfp->To_Fbt;
+ Mode = tdfp->Mode;
+ Uristr = tdfp->Uristr;
+ Db_name = tdfp->Db_name;
+ Coll_name = tdfp->Coll_name;
+ Options = tdfp->Options;
+ Filter = NULL;
+ Wrapname = tdfp->Wrapname;
+ Done = tdfp->Done;
+ Pipe = tdfp->Pipe;
+ Version = tdfp->Version;
+ Curpos = tdfp->Curpos;
+} // end of JMGFAM copy constructor
+
+/***********************************************************************/
+/* Reset: reset position values at the beginning of file. */
+/***********************************************************************/
+void JMGFAM::Reset(void)
+{
+ TXTFAM::Reset();
+ Fpos = Tpos = Spos = 0;
+} // end of Reset
+
+/***********************************************************************/
+/* MGO GetFileLength: returns file size in number of bytes. */
+/***********************************************************************/
+int JMGFAM::GetFileLength(PGLOBAL g)
+{
+ return 0;
+} // end of GetFileLength
+
+/***********************************************************************/
+/* Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int JMGFAM::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 1;
+
+ return (!Init(g)) ? Jcp->CollSize(g) : 0;
+} // end of Cardinality
+
+/***********************************************************************/
+/* Note: This function is not really implemented yet. */
+/***********************************************************************/
+int JMGFAM::MaxBlkSize(PGLOBAL, int s)
+{
+ return s;
+} // end of MaxBlkSize
+
+/***********************************************************************/
+/* Init: initialize MongoDB processing. */
+/***********************************************************************/
+bool JMGFAM::Init(PGLOBAL g)
+{
+ if (Done)
+ return false;
+
+ /*********************************************************************/
+ /* Open an JDBC connection for this table. */
+ /* Note: this may not be the proper way to do. Perhaps it is better */
+ /* to test whether a connection is already open for this datasource */
+ /* and if so to allocate just a new result set. But this only for */
+ /* drivers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Jcp)
+ Jcp = new(g) JMgoConn(g, Coll_name, Wrapname);
+ else if (Jcp->IsOpen())
+ Jcp->Close();
+
+ if (Jcp->Connect(&Ops))
+ return true;
+
+ Done = true;
+ return false;
+} // end of Init
+
+/***********************************************************************/
+/* OpenTableFile: Open a MongoDB table. */
+/***********************************************************************/
+bool JMGFAM::OpenTableFile(PGLOBAL g)
+{
+ Mode = Tdbp->GetMode();
+
+ if (Pipe && Mode != MODE_READ) {
+ strcpy(g->Message, "Pipeline tables are read only");
+ return true;
+ } // endif Pipe
+
+ if (Init(g))
+ return true;
+
+ if (Jcp->GetMethodId(g, Mode))
+ return true;
+
+ if (Mode == MODE_DELETE && !Tdbp->GetNext()) {
+ // Delete all documents
+ if (!Jcp->MakeCursor(g, Tdbp, "all", Filter, false))
+ if (Jcp->DocDelete(g, true) == RC_OK)
+ return false;
+
+ return true;
+ } // endif Mode
+
+//if (Mode == MODE_INSERT)
+// Jcp->MakeColumnGroups(g, Tdbp);
+
+ if (Mode != MODE_UPDATE)
+ return Jcp->MakeCursor(g, Tdbp, Options, Filter, Pipe);
+
+ return false;
+ } // end of OpenTableFile
+
+/***********************************************************************/
+/* GetRowID: return the RowID of last read record. */
+/***********************************************************************/
+int JMGFAM::GetRowID(void)
+{
+ return Rows;
+} // end of GetRowID
+
+/***********************************************************************/
+/* GetPos: return the position of last read record. */
+/***********************************************************************/
+int JMGFAM::GetPos(void)
+{
+ return Fpos;
+} // end of GetPos
+
+/***********************************************************************/
+/* GetNextPos: return the position of next record. */
+/***********************************************************************/
+int JMGFAM::GetNextPos(void)
+{
+ return Fpos; // TODO
+} // end of GetNextPos
+
+/***********************************************************************/
+/* SetPos: Replace the table at the specified position. */
+/***********************************************************************/
+bool JMGFAM::SetPos(PGLOBAL g, int pos)
+{
+ Fpos = pos;
+ Placed = true;
+ return false;
+} // end of SetPos
+
+/***********************************************************************/
+/* Record file position in case of UPDATE or DELETE. */
+/***********************************************************************/
+bool JMGFAM::RecordPos(PGLOBAL g)
+{
+ strcpy(g->Message, "JMGFAM::RecordPos NIY");
+ return true;
+} // end of RecordPos
+
+/***********************************************************************/
+/* Initialize Fpos and the current position for indexed DELETE. */
+/***********************************************************************/
+int JMGFAM::InitDelete(PGLOBAL g, int fpos, int spos)
+{
+ strcpy(g->Message, "JMGFAM::InitDelete NIY");
+ return RC_FX;
+} // end of InitDelete
+
+/***********************************************************************/
+/* Skip one record in file. */
+/***********************************************************************/
+int JMGFAM::SkipRecord(PGLOBAL g, bool header)
+{
+ return RC_OK; // Dummy
+} // end of SkipRecord
+
+/***********************************************************************/
+/* ReadBuffer: Get next document from a collection. */
+/***********************************************************************/
+int JMGFAM::ReadBuffer(PGLOBAL g)
+{
+ int rc = RC_FX;
+
+ if (!Curpos && Mode == MODE_UPDATE)
+ if (Jcp->MakeCursor(g, Tdbp, Options, Filter, Pipe))
+ return RC_FX;
+
+ if (++CurNum >= Rbuf) {
+ Rbuf = Jcp->Fetch();
+ Curpos++;
+ CurNum = 0;
+ } // endif CurNum
+
+ if (Rbuf > 0) {
+ PSZ str = Jcp->GetDocument();
+
+ if (str) {
+ if (trace(1))
+ htrc("%s\n", str);
+
+ strncpy(Tdbp->GetLine(), str, Lrecl);
+ rc = RC_OK;
+ } else
+ strcpy(g->Message, "Null document");
+
+ } else if (!Rbuf)
+ rc = RC_EF;
+
+ return rc;
+} // end of ReadBuffer
+
+/***********************************************************************/
+/* WriteBuffer: File write routine for JMG access method. */
+/***********************************************************************/
+int JMGFAM::WriteBuffer(PGLOBAL g)
+{
+ int rc = RC_OK;
+
+ if (Mode == MODE_INSERT) {
+ rc = Jcp->DocWrite(g, Tdbp->GetLine());
+ } else if (Mode == MODE_DELETE) {
+ rc = Jcp->DocDelete(g, false);
+ } else if (Mode == MODE_UPDATE) {
+ rc = Jcp->DocUpdate(g, Tdbp);
+ } // endif Mode
+
+ return rc;
+} // end of WriteBuffer
+
+/***********************************************************************/
+/* Data Base delete line routine for MGO and BLK access methods. */
+/***********************************************************************/
+int JMGFAM::DeleteRecords(PGLOBAL g, int irc)
+{
+ return (irc == RC_OK) ? WriteBuffer(g) : RC_OK;
+} // end of DeleteRecords
+
+/***********************************************************************/
+/* Table file close routine for MGO access method. */
+/***********************************************************************/
+void JMGFAM::CloseTableFile(PGLOBAL g, bool)
+{
+ Jcp->Close();
+ Done = false;
+} // end of CloseTableFile
+
+/***********************************************************************/
+/* Rewind routine for MGO access method. */
+/***********************************************************************/
+void JMGFAM::Rewind(void)
+{
+ Jcp->Rewind();
+} // end of Rewind
+
diff --git a/storage/connect/jmgfam.h b/storage/connect/jmgfam.h
new file mode 100644
index 00000000..c5d9d1f5
--- /dev/null
+++ b/storage/connect/jmgfam.h
@@ -0,0 +1,82 @@
+/************** MongoFam H Declares Source Code File (.H) **************/
+/* Name: jmgfam.h Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2020 */
+/* */
+/* This file contains the JAVA MongoDB access method classes declares */
+/***********************************************************************/
+#pragma once
+
+/***********************************************************************/
+/* Include MongoDB library header files. */
+/***********************************************************************/
+#include "block.h"
+//#include "mongo.h"
+#include "jmgoconn.h"
+
+typedef class JMGFAM *PJMGFAM;
+typedef class MGODEF *PMGODEF;
+
+/***********************************************************************/
+/* This is the Java MongoDB Access Method class declaration. */
+/***********************************************************************/
+class DllExport JMGFAM : public DOSFAM {
+ friend void mongo_init(bool);
+public:
+ // Constructor
+ JMGFAM(PJDEF tdp);
+#if defined(BSON_SUPPORT)
+ JMGFAM(PBDEF tdp);
+#endif // BSON_SUPPORT
+ JMGFAM(PJMGFAM txfp);
+
+ // Implementation
+ virtual AMT GetAmType(void) { return TYPE_AM_MGO; }
+ virtual bool GetUseTemp(void) { return false; }
+ virtual int GetPos(void);
+ virtual int GetNextPos(void);
+ virtual PTXF Duplicate(PGLOBAL g) { return (PTXF)new(g) JMGFAM(this); }
+ void SetLrecl(int lrecl) { Lrecl = lrecl; }
+
+ // Methods
+ virtual void Reset(void);
+ virtual int GetFileLength(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int MaxBlkSize(PGLOBAL g, int s);
+ virtual bool AllocateBuffer(PGLOBAL g) { return false; }
+ virtual int GetRowID(void);
+ virtual bool RecordPos(PGLOBAL g);
+ virtual bool SetPos(PGLOBAL g, int recpos);
+ virtual int SkipRecord(PGLOBAL g, bool header);
+ virtual bool OpenTableFile(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g);
+ virtual int WriteBuffer(PGLOBAL g);
+ virtual int DeleteRecords(PGLOBAL g, int irc);
+ virtual void CloseTableFile(PGLOBAL g, bool abort);
+ virtual void Rewind(void);
+
+protected:
+ virtual bool OpenTempFile(PGLOBAL g) { return false; }
+ virtual bool MoveIntermediateLines(PGLOBAL g, bool *b) { return false; }
+ virtual int RenameTempFile(PGLOBAL g) { return RC_OK; }
+ virtual int InitDelete(PGLOBAL g, int fpos, int spos);
+ bool Init(PGLOBAL g);
+//bool MakeCursor(PGLOBAL g);
+
+ // Members
+ JMgoConn *Jcp; // Points to a Mongo connection class
+ JDBCPARM Ops; // Additional parameters
+ PFBLOCK To_Fbt; // Pointer to temp file block
+ MODE Mode;
+ PCSZ Uristr;
+ PCSZ Db_name;
+ PCSZ Coll_name;
+ PCSZ Options;
+ PCSZ Filter;
+ PSZ Wrapname;
+ bool Done; // Init done
+ bool Pipe;
+ int Version;
+ int Curpos; // Cursor position of last fetch
+}; // end of class JMGFAM
+
diff --git a/storage/connect/jmgoconn.cpp b/storage/connect/jmgoconn.cpp
new file mode 100644
index 00000000..a4091e88
--- /dev/null
+++ b/storage/connect/jmgoconn.cpp
@@ -0,0 +1,883 @@
+/************ JMgoConn C++ Functions Source Code File (.CPP) ***********/
+/* Name: JMgoConn.CPP Version 1.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
+/* */
+/* This file contains the MongoDB Java connection classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Required objects includes. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "colblk.h"
+#include "xobject.h"
+#include "xtable.h"
+#include "filter.h"
+#include "jmgoconn.h"
+
+#define nullptr 0
+
+bool IsArray(PSZ s);
+bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s);
+
+/* --------------------------- Class JNCOL --------------------------- */
+
+/***********************************************************************/
+/* Add a column in the column list. */
+/***********************************************************************/
+void JNCOL::AddCol(PGLOBAL g, PCOL colp, PSZ jp)
+{
+ char *p;
+ PJKC kp, kcp;
+
+ if ((p = strchr(jp, '.'))) {
+ PJNCOL icp;
+
+ *p++ = 0;
+
+ for (kp = Klist; kp; kp = kp->Next)
+ if (kp->Jncolp && ((kp->Key && !strcmp(jp, kp->Key))
+ || (!kp->Key && IsArray(jp) && kp->N == atoi(jp))))
+ break;
+
+ if (!kp) {
+ icp = new(g) JNCOL();
+ kcp = (PJKC)PlugSubAlloc(g, NULL, sizeof(JKCOL));
+ kcp->Next = NULL;
+ kcp->Jncolp = icp;
+ kcp->Colp = NULL;
+ kcp->Array = IsArray(jp);
+
+ if (kcp->Array) {
+ kcp->Key = NULL;
+ kcp->N = atoi(jp);
+ } else {
+ kcp->Key = PlugDup(g, jp);
+ kcp->N = 0;
+ } // endif Array
+
+ if (Klist) {
+ for (kp = Klist; kp->Next; kp = kp->Next);
+
+ kp->Next = kcp;
+ } else
+ Klist = kcp;
+
+ } else
+ icp = kp->Jncolp;
+
+ *(p - 1) = '.';
+ icp->AddCol(g, colp, p);
+ } else {
+ kcp = (PJKC)PlugSubAlloc(g, NULL, sizeof(JKCOL));
+ kcp->Next = NULL;
+ kcp->Jncolp = NULL;
+ kcp->Colp = colp;
+ kcp->Array = IsArray(jp);
+
+ if (kcp->Array) {
+ kcp->Key = NULL;
+ kcp->N = atoi(jp);
+ } else {
+ kcp->Key = jp;
+ kcp->N = 0;
+ } // endif Array
+
+ if (Klist) {
+ for (kp = Klist; kp->Next; kp = kp->Next);
+
+ kp->Next = kcp;
+ } else
+ Klist = kcp;
+
+ } // endif jp
+
+} // end of AddCol
+
+/***********************************************************************/
+/* JMgoConn construction/destruction. */
+/***********************************************************************/
+JMgoConn::JMgoConn(PGLOBAL g, PCSZ collname, PCSZ wrapper)
+ : JAVAConn(g, wrapper)
+{
+ CollName = collname;
+ readid = fetchid = getdocid = objfldid = fcollid = acollid =
+ mkdocid = docaddid = mkarid = araddid = insertid = updateid =
+ deleteid = gcollid = countid = rewindid = mkbsonid = nullptr;
+ DiscFunc = "MongoDisconnect";
+ Fpc = NULL;
+ m_Fetch = 0;
+ m_Ncol = 0;
+ m_Version = 0;
+} // end of JMgoConn
+
+/***********************************************************************/
+/* AddJars: add some jar file to the Class path. */
+/***********************************************************************/
+void JMgoConn::AddJars(PSTRG jpop, char sep)
+{
+#if defined(DEVELOPMENT)
+ if (m_Version == 2) {
+ jpop->Append(sep);
+// jpop->Append("C:/Eclipse/workspace/MongoWrap2/bin");
+// jpop->Append(sep);
+ jpop->Append("C:/mongo-java-driver/mongo-java-driver-2.13.3.jar");
+ } else {
+ jpop->Append(sep);
+// jpop->Append("C:/Eclipse/workspace/MongoWrap3/bin");
+// jpop->Append(sep);
+// jpop->Append("C:/Program Files/MariaDB 10.1/lib/plugin/JavaWrappers.jar");
+// jpop->Append(sep);
+ jpop->Append("C:/mongo-java-driver/mongo-java-driver-3.4.2.jar");
+ } // endif m_Version
+#endif // DEVELOPMENT
+} // end of AddJars
+
+/***********************************************************************/
+/* Connect: connect to a data source. */
+/***********************************************************************/
+bool JMgoConn::Connect(PJPARM sop)
+{
+ bool err = false;
+ jint rc;
+ jboolean brc;
+ jstring cln;
+ PGLOBAL& g = m_G;
+
+ m_Version = sop->Version;
+
+ /*******************************************************************/
+ /* Create or attach a JVM. */
+ /*******************************************************************/
+ if (Open(g))
+ return true;
+
+ /*******************************************************************/
+ /* Connect to MongoDB. */
+ /*******************************************************************/
+ jmethodID cid = nullptr;
+
+ if (gmID(g, cid, "MongoConnect", "([Ljava/lang/String;)I"))
+ return true;
+
+ // Build the java string array
+ jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4
+ env->FindClass("java/lang/String"), NULL); // Strings
+
+ //m_Scrollable = sop->Scrollable;
+ //m_RowsetSize = sop->Fsize;
+
+ // change some elements
+ if (sop->Driver)
+ env->SetObjectArrayElement(parms, 0, env->NewStringUTF(sop->Url));
+
+ if (sop->Url)
+ env->SetObjectArrayElement(parms, 1, env->NewStringUTF(sop->Driver));
+
+ if (sop->User)
+ env->SetObjectArrayElement(parms, 2, env->NewStringUTF(sop->User));
+
+ if (sop->Pwd)
+ env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd));
+
+ // call method
+ rc = env->CallIntMethod(job, cid, parms);
+ err = Check(rc);
+ env->DeleteLocalRef(parms); // Not used anymore
+
+ if (err) {
+ sprintf(g->Message, "Connecting: %s rc=%d", Msg, (int)rc);
+ return true;
+ } // endif Msg
+
+ /*********************************************************************/
+ /* Get the collection. */
+ /*********************************************************************/
+ if (gmID(g, gcollid, "GetCollection", "(Ljava/lang/String;)Z"))
+ return true;
+
+ cln = env->NewStringUTF(CollName);
+ brc = env->CallBooleanMethod(job, gcollid, cln);
+ env->DeleteLocalRef(cln);
+
+ if (Check(brc ? -1 : 0)) {
+ sprintf(g->Message, "GetCollection: %s", Msg);
+ return true;
+ } // endif Msg
+
+ m_Connected = true;
+ return false;
+} // end of Connect
+
+/***********************************************************************/
+/* CollSize: returns the number of documents in the collection. */
+/***********************************************************************/
+int JMgoConn::CollSize(PGLOBAL g)
+{
+ if (!gmID(g, countid, "GetCollSize", "()J")) {
+ jlong card = env->CallLongMethod(job, countid);
+
+ return (int)card;
+ } else
+ return 2; // Make MariaDB happy
+
+} // end of CollSize
+
+/***********************************************************************/
+/* OpenDB: Data Base open routine for MONGO access method. */
+/***********************************************************************/
+bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options,
+ PCSZ filter, bool pipe)
+{
+ const char *p;
+ bool id, b = false, all = false;
+ uint len;
+ PCOL cp;
+ PSZ jp;
+ PCSZ op = NULL, sf = NULL, Options = options;
+ PSTRG s = NULL;
+ PFIL filp = tdbp->GetFilter();
+
+ if (Options && !stricmp(Options, "all")) {
+ Options = NULL;
+ all = true;
+ } else
+ id = (tdbp->GetMode() == MODE_UPDATE || tdbp->GetMode() == MODE_DELETE);
+
+ for (cp = tdbp->GetColumns(); cp && !all; cp = cp->GetNext())
+ if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && (!Options || pipe))
+ all = true;
+ else if (!id)
+ id = !strcmp(cp->GetJpath(g, false), "_id");
+
+ if (pipe && Options) {
+ if (trace(1))
+ htrc("Pipeline: %s\n", Options);
+
+ p = strrchr(Options, ']');
+
+ if (!p) {
+ strcpy(g->Message, "Missing ] in pipeline");
+ return true;
+ } else
+ *(char*)p = 0;
+
+ s = new(g) STRING(g, 1023, (PSZ)Options);
+
+ if (filp) {
+ s->Append(",{\"$match\":");
+
+ if (MakeSelector(g, filp, s)) {
+ strcpy(g->Message, "Failed making selector");
+ return true;
+ } else
+ s->Append('}');
+
+ tdbp->SetFilter(NULL); // Not needed anymore
+ } // endif To_Filter
+
+ if (!all && tdbp->GetColumns()) {
+ // Project list
+ len = s->GetLength();
+ s->Append(",{\"$project\":{\"");
+
+ if (!id)
+ s->Append("_id\":0,\"");
+
+ for (PCOL cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) {
+ if (b)
+ s->Append(",\"");
+ else
+ b = true;
+
+ if ((jp = cp->GetJpath(g, true)))
+ s->Append(jp);
+ else {
+ s->Truncate(len);
+ goto nop;
+ } // endif Jpath
+
+ s->Append("\":1");
+ } // endfor cp
+
+ s->Append("}}");
+ } // endif all
+
+ nop:
+ s->Append("]}");
+ s->Resize(s->GetLength() + 1);
+ *(char*)p = ']'; // Restore Colist for discovery
+ p = s->GetStr();
+
+ if (trace(33))
+ htrc("New Pipeline: %s\n", p);
+
+ return AggregateCollection(p);
+ } else {
+ if (filter || filp) {
+ if (trace(1)) {
+ if (filter)
+ htrc("Filter: %s\n", filter);
+
+ if (filp) {
+ char buf[512];
+
+ filp->Prints(g, buf, 511);
+ htrc("To_Filter: %s\n", buf);
+ } // endif To_Filter
+
+ } // endif trace
+
+ s = new(g) STRING(g, 1023, (PSZ)filter);
+ len = s->GetLength();
+
+ if (filp) {
+ if (filter)
+ s->Append(',');
+
+ if (MakeSelector(g, filp, s)) {
+ strcpy(g->Message, "Failed making selector");
+ return true;
+ } // endif Selector
+
+ tdbp->SetFilter(NULL); // Not needed anymore
+ } // endif To_Filter
+
+ if (trace(33))
+ htrc("selector: %s\n", s->GetStr());
+
+ s->Resize(s->GetLength() + 1);
+ sf = PlugDup(g, s->GetStr());
+ } // endif Filter
+
+ if (!all) {
+ if (Options && *Options) {
+ if (trace(1))
+ htrc("options=%s\n", Options);
+
+ op = Options;
+ } else if (tdbp->GetColumns()) {
+ // Projection list
+ if (s)
+ s->Set("{\"");
+ else
+ s = new(g) STRING(g, 511, "{\"");
+
+ if (!id)
+ s->Append("_id\":0,\"");
+
+ for (PCOL cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) {
+ if (b)
+ s->Append(",\"");
+ else
+ b = true;
+
+ if ((jp = cp->GetJpath(g, true)))
+ s->Append(jp);
+ else {
+ // Can this happen?
+ htrc("Fail getting projection path of %s\n", cp->GetName());
+ goto nope;
+ } // endif Jpath
+
+ s->Append("\":1");
+ } // endfor cp
+
+ s->Append("}");
+ s->Resize(s->GetLength() + 1);
+ op = s->GetStr();
+ } else {
+ // count(*) ?
+ op = "{\"_id\":1}";
+ } // endif Options
+
+ } // endif all
+
+ nope:
+ return FindCollection(sf, op);
+ } // endif Pipe
+
+} // end of MakeCursor
+
+/***********************************************************************/
+/* Find a collection and make cursor. */
+/***********************************************************************/
+bool JMgoConn::FindCollection(PCSZ query, PCSZ proj)
+{
+ bool rc = true;
+ jboolean brc;
+ jstring qry = nullptr, prj = nullptr;
+ PGLOBAL& g = m_G;
+
+ // Get the methods used to execute a query and get the result
+ if (!gmID(g, fcollid, "FindColl", "(Ljava/lang/String;Ljava/lang/String;)Z")) {
+ if (query)
+ qry = env->NewStringUTF(query);
+
+ if (proj)
+ prj = env->NewStringUTF(proj);
+
+ brc = env->CallBooleanMethod(job, fcollid, qry, prj);
+
+ if (!Check(brc ? -1 : 0)) {
+ rc = false;
+ } else
+ sprintf(g->Message, "FindColl: %s", Msg);
+
+ if (query)
+ env->DeleteLocalRef(qry);
+
+ if (proj)
+ env->DeleteLocalRef(prj);
+
+ } // endif xqid
+
+ return rc;
+} // end of FindCollection
+
+/***********************************************************************/
+/* Find a collection and make cursor. */
+/***********************************************************************/
+bool JMgoConn::AggregateCollection(PCSZ pipeline)
+{
+ bool rc = true;
+ jboolean brc;
+ jstring pip = nullptr;
+ PGLOBAL& g = m_G;
+
+ // Get the methods used to execute a query and get the result
+ if (!gmID(g, acollid, "AggregateColl", "(Ljava/lang/String;)Z")) {
+ pip = env->NewStringUTF(pipeline);
+
+ brc = env->CallBooleanMethod(job, acollid, pip);
+
+ if (!Check(brc ? -1 : 0)) {
+ rc = false;
+ } else
+ sprintf(g->Message, "AggregateColl: %s", Msg);
+
+ env->DeleteLocalRef(pip);
+ } // endif acollid
+
+ return rc;
+} // end of AggregateCollection
+
+/***********************************************************************/
+/* Fetch next row. */
+/***********************************************************************/
+int JMgoConn::Fetch(int pos)
+{
+ jint rc = JNI_ERR;
+ PGLOBAL& g = m_G;
+
+ //if (m_Full) // Result set has one row
+ // return 1;
+
+ //if (pos) {
+ // if (!m_Scrollable) {
+ // strcpy(g->Message, "Cannot fetch(pos) if FORWARD ONLY");
+ // return rc;
+ // } else if (gmID(m_G, fetchid, "Fetch", "(I)Z"))
+ // return rc;
+
+ // if (env->CallBooleanMethod(job, fetchid, pos))
+ // rc = m_Rows;
+
+ //} else {
+ if (gmID(g, readid, "ReadNext", "()I"))
+ return (int)rc;
+
+ rc = env->CallIntMethod(job, readid);
+
+ if (!Check(rc)) {
+ //if (rc == 0)
+ // m_Full = (m_Fetch == 1);
+ //else
+ // m_Fetch++;
+
+ m_Ncol = (int)rc;
+ rc = MY_MIN(rc, 1);
+ m_Rows += rc;
+ } else
+ sprintf(g->Message, "Fetch: %s", Msg);
+
+ //} // endif pos
+
+ return rc;
+} // end of Fetch
+
+/***********************************************************************/
+/* Get the Json string of the current document. */
+/***********************************************************************/
+PSZ JMgoConn::GetDocument(void)
+{
+ PGLOBAL& g = m_G;
+ PSZ doc = NULL;
+ jstring jdc;
+
+ if (!gmID(g, getdocid, "GetDoc", "()Ljava/lang/String;")) {
+ jdc = (jstring)env->CallObjectMethod(job, getdocid);
+
+ if (jdc)
+ doc = (PSZ)GetUTFString(jdc);
+
+ } // endif getdocid
+
+ return doc;
+ } // end of GetDocument
+
+/***********************************************************************/
+/* Group columns for inserting or updating. */
+/***********************************************************************/
+void JMgoConn::MakeColumnGroups(PGLOBAL g, PTDB tdbp)
+{
+ Fpc = new(g) JNCOL();
+
+ for (PCOL colp = tdbp->GetColumns(); colp; colp = colp->GetNext())
+ if (!colp->IsSpecial())
+ Fpc->AddCol(g, colp, colp->GetJpath(g, false));
+
+} // end of MakeColumnGroups
+
+/***********************************************************************/
+/* Get additional method ID. */
+/***********************************************************************/
+bool JMgoConn::GetMethodId(PGLOBAL g, MODE mode)
+{
+ if (mode == MODE_UPDATE) {
+ if (gmID(g, mkdocid, "MakeDocument", "()Ljava/lang/Object;"))
+ return true;
+
+ if (gmID(g, docaddid, "DocAdd",
+ "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;I)Z"))
+ return true;
+
+ if (gmID(g, updateid, "CollUpdate", "(Ljava/lang/Object;)J"))
+ return true;
+
+ } else if (mode == MODE_INSERT) {
+ if (gmID(g, mkdocid, "MakeDocument", "()Ljava/lang/Object;"))
+ return true;
+
+ if (gmID(g, mkbsonid, "MakeBson",
+ "(Ljava/lang/String;I)Ljava/lang/Object;"))
+ return true;
+
+ if (gmID(g, docaddid, "DocAdd",
+ "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;I)Z"))
+ return true;
+
+ if (gmID(g, mkarid, "MakeArray", "()Ljava/lang/Object;"))
+ return true;
+
+ if (gmID(g, araddid, "ArrayAdd",
+ "(Ljava/lang/Object;ILjava/lang/Object;I)Z"))
+ return true;
+
+ if (gmID(g, insertid, "CollInsert", "(Ljava/lang/Object;)Z"))
+ return true;
+
+ } else if (mode == MODE_DELETE)
+ if (gmID(g, deleteid, "CollDelete", "(Z)J"))
+ return true;
+
+ return gmID(g, rewindid, "Rewind", "()Z");
+} // end of GetMethodId
+
+/***********************************************************************/
+/* MakeObject. */
+/***********************************************************************/
+jobject JMgoConn::MakeObject(PGLOBAL g, PCOL colp, bool&error )
+{
+ jclass cls;
+ jmethodID cns = nullptr; // Constructor
+ jobject val = nullptr;
+ PVAL valp = colp->GetValue();
+
+ error = false;
+
+ if (valp->IsNull())
+ return NULL;
+
+ try {
+ switch (valp->GetType()) {
+ case TYPE_STRING:
+ val = env->NewStringUTF(valp->GetCharValue());
+ break;
+ case TYPE_INT:
+ case TYPE_SHORT:
+ cls = env->FindClass("java/lang/Integer");
+ cns = env->GetMethodID(cls, "<init>", "(I)V");
+ val = env->NewObject(cls, cns, valp->GetIntValue());
+ break;
+ case TYPE_TINY:
+ cls = env->FindClass("java/lang/Boolean");
+ cns = env->GetMethodID(cls, "<init>", "(Z)V");
+ val = env->NewObject(cls, cns, (valp->GetIntValue() != 0));
+ break;
+ case TYPE_BIGINT:
+ cls = env->FindClass("java/lang/Long");
+ cns = env->GetMethodID(cls, "<init>", "(J)V");
+ val = env->NewObject(cls, cns, valp->GetBigintValue());
+ break;
+ case TYPE_DOUBLE:
+ cls = env->FindClass("java/lang/Double");
+ cns = env->GetMethodID(cls, "<init>", "(D)V");
+ val = env->NewObject(cls, cns, valp->GetFloatValue());
+ break;
+ default:
+ sprintf(g->Message, "Cannot make object from %d type", valp->GetType());
+ error = true;
+ break;
+ } // endswitch Type
+
+ } catch (...) {
+ sprintf(g->Message, "Cannot make object from %s value", colp->GetName());
+ error = true;
+ } // end try/catch
+
+ return val;
+} // end of MakeObject
+
+/***********************************************************************/
+/* Stringify. */
+/***********************************************************************/
+bool JMgoConn::Stringify(PCOL colp)
+{
+ bool b = false;
+
+ if (colp)
+ b = (colp->Stringify() && colp->GetResultType() == TYPE_STRING);
+
+ return b;
+} // end of Stringify
+
+/***********************************************************************/
+/* MakeDoc. */
+/***********************************************************************/
+jobject JMgoConn::MakeDoc(PGLOBAL g, PJNCOL jcp)
+{
+ int j;
+ bool b, error = false;
+ jobject parent, child, val;
+ jstring jkey;
+ PJKC kp = jcp->Klist;
+
+ if (kp->Array)
+ parent = env->CallObjectMethod(job, mkarid);
+ else
+ parent = env->CallObjectMethod(job, mkdocid);
+
+ for (j = 0; kp; j = 0, kp = kp->Next) {
+ if (Stringify(kp->Colp)) {
+ switch (*kp->Colp->GetCharValue()) {
+ case '{': j = 1; break;
+ case '[': j = 2; break;
+ default: break;
+ } // endswitch
+
+ b = (!kp->Key || !*kp->Key || *kp->Key == '*');
+ } else
+ b = false;
+
+ if (kp->Jncolp) {
+ if (!(child = MakeDoc(g, kp->Jncolp)))
+ return NULL;
+
+ if (!kp->Array) {
+ jkey = env->NewStringUTF(kp->Key);
+
+ if (env->CallBooleanMethod(job, docaddid, parent, jkey, child, j))
+ return NULL;
+
+ env->DeleteLocalRef(jkey);
+ } else
+ if (env->CallBooleanMethod(job, araddid, parent, kp->N, child, j))
+ return NULL;
+
+ env->DeleteLocalRef(child);
+ } else {
+ if (!(val = MakeObject(g, kp->Colp, error))) {
+ if (error)
+ return NULL;
+
+ } else if (!kp->Array) {
+ if (!b) {
+ jkey = env->NewStringUTF(kp->Key);
+
+ if (env->CallBooleanMethod(job, docaddid, parent, jkey, val, j))
+ return NULL;
+
+ env->DeleteLocalRef(jkey);
+ } else {
+ env->DeleteLocalRef(parent);
+ parent = env->CallObjectMethod(job, mkbsonid, val, j);
+ } // endif b
+
+ } else if (env->CallBooleanMethod(job, araddid, parent, kp->N, val, j)) {
+ if (Check(-1))
+ sprintf(g->Message, "ArrayAdd: %s", Msg);
+ else
+ sprintf(g->Message, "ArrayAdd: unknown error");
+
+ return NULL;
+ } // endif ArrayAdd
+
+ env->DeleteLocalRef(val);
+ } // endif Jncolp
+
+ } // endfor kp
+
+ return parent;
+} // end of MakeDoc
+
+/***********************************************************************/
+/* Insert a new document in the collation. */
+/***********************************************************************/
+int JMgoConn::DocWrite(PGLOBAL g, PCSZ line)
+{
+ int rc = RC_OK;
+ jobject doc = nullptr;
+
+ if (line) {
+ int j;
+ jobject val = env->NewStringUTF(line);
+
+ switch (*line) {
+ case '{': j = 1; break;
+ case '[': j = 2; break;
+ default: j = 0; break;
+ } // endswitch line
+
+ doc = env->CallObjectMethod(job, mkbsonid, val, j);
+ env->DeleteLocalRef(val);
+ } else if (Fpc)
+ doc = MakeDoc(g, Fpc);
+
+ if (!doc)
+ return RC_FX;
+
+ if (env->CallBooleanMethod(job, insertid, doc)) {
+ if (Check(-1))
+ sprintf(g->Message, "CollInsert: %s", Msg);
+ else
+ sprintf(g->Message, "CollInsert: unknown error");
+
+ rc = RC_FX;
+ } // endif Insert
+
+ env->DeleteLocalRef(doc);
+ return rc;
+} // end of DocWrite
+
+/***********************************************************************/
+/* Update the current document from the collection. */
+/***********************************************************************/
+int JMgoConn::DocUpdate(PGLOBAL g, PTDB tdbp)
+{
+ int j = 0, rc = RC_OK;
+ bool error;
+ PCOL colp;
+ jstring jkey;
+ jobject val, upd, updlist = env->CallObjectMethod(job, mkdocid);
+
+ // Make the list of changes to do
+ for (colp = tdbp->GetSetCols(); colp; colp = colp->GetNext()) {
+ jkey = env->NewStringUTF(colp->GetJpath(g, false));
+ val = MakeObject(g, colp, error);
+
+ if (error)
+ return RC_FX;
+ else if (Stringify(colp))
+ switch (*colp->GetCharValue()) {
+ case '{': j = 1; break;
+ case '[': j = 2; break;
+ default: break;
+ } // endswitch
+
+ if (env->CallBooleanMethod(job, docaddid, updlist, jkey, val, j))
+ return RC_OK;
+
+ env->DeleteLocalRef(jkey);
+ } // endfor colp
+
+ // Make the update parameter
+ upd = env->CallObjectMethod(job, mkdocid);
+ jkey = env->NewStringUTF("$set");
+
+ if (env->CallBooleanMethod(job, docaddid, upd, jkey, updlist, 0))
+ return RC_OK;
+
+ env->DeleteLocalRef(jkey);
+
+ jlong ar = env->CallLongMethod(job, updateid, upd);
+
+ if (trace(1))
+ htrc("DocUpdate: ar = %ld\n", ar);
+
+ if (Check((int)ar)) {
+ sprintf(g->Message, "CollUpdate: %s", Msg);
+ rc = RC_FX;
+ } // endif ar
+
+ return rc;
+} // end of DocUpdate
+
+/***********************************************************************/
+/* Remove all or only the current document from the collection. */
+/***********************************************************************/
+int JMgoConn::DocDelete(PGLOBAL g, bool all)
+{
+ int rc = RC_OK;
+ jlong ar = env->CallLongMethod(job, deleteid, all);
+
+ if (trace(1))
+ htrc("DocDelete: ar = %ld\n", ar);
+
+ if (Check((int)ar)) {
+ sprintf(g->Message, "CollDelete: %s", Msg);
+ rc = RC_FX;
+ } // endif ar
+
+ return rc;
+} // end of DocDelete
+
+/***********************************************************************/
+/* Rewind the collection. */
+/***********************************************************************/
+bool JMgoConn::Rewind(void)
+{
+ return env->CallBooleanMethod(job, rewindid);
+} // end of Rewind
+
+/***********************************************************************/
+/* Retrieve the column string value from the document. */
+/***********************************************************************/
+PSZ JMgoConn::GetColumnValue(PSZ path)
+{
+ PGLOBAL& g = m_G;
+ PSZ fld = NULL;
+ jstring fn, jn = nullptr;
+
+ if (!path || (jn = env->NewStringUTF(path)) == nullptr) {
+ sprintf(g->Message, "Fail to allocate jstring %s", SVP(path));
+ throw (int)TYPE_AM_MGO;
+ } // endif name
+
+ if (!gmID(g, objfldid, "GetField", "(Ljava/lang/String;)Ljava/lang/String;")) {
+ fn = (jstring)env->CallObjectMethod(job, objfldid, jn);
+
+ if (fn)
+ fld = (PSZ)GetUTFString(fn);
+
+ } // endif objfldid
+
+ return fld;
+} // end of GetColumnValue
diff --git a/storage/connect/jmgoconn.h b/storage/connect/jmgoconn.h
new file mode 100644
index 00000000..9fed1907
--- /dev/null
+++ b/storage/connect/jmgoconn.h
@@ -0,0 +1,116 @@
+/***********************************************************************/
+/* JMgoConn.h : header file for the MongoDB connection classes. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Java interface. */
+/***********************************************************************/
+#include "javaconn.h"
+
+// Java connection to a MongoDB data source
+class TDBJMG;
+class JMGCOL;
+
+/***********************************************************************/
+/* Include MongoDB library header files. */
+/***********************************************************************/
+typedef class JNCOL *PJNCOL;
+typedef class MGODEF *PMGODEF;
+typedef class TDBJMG *PTDBJMG;
+typedef class JMGCOL *PJMGCOL;
+
+typedef struct JKCOL {
+ JKCOL *Next;
+ PJNCOL Jncolp;
+ PCOL Colp;
+ char *Key;
+ int N;
+ bool Array;
+} *PJKC;
+
+/***********************************************************************/
+/* Used when inserting values in a MongoDB collection. */
+/***********************************************************************/
+class JNCOL : public BLOCK {
+public:
+ // Constructor
+//JNCOL(bool ar) { Klist = NULL; Array = ar; }
+ JNCOL(void) { Klist = NULL; }
+
+ // Methods
+ void AddCol(PGLOBAL g, PCOL colp, PSZ jp);
+
+ //Members
+ PJKC Klist;
+}; // end of JNCOL;
+
+/***********************************************************************/
+/* JMgoConn class. */
+/***********************************************************************/
+class JMgoConn : public JAVAConn {
+ friend class TDBJMG;
+ friend class JMGDISC;
+ //friend class TDBXJDC;
+ //friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
+private:
+ JMgoConn(); // Standard (unused) constructor
+
+public:
+ // Constructor
+ JMgoConn(PGLOBAL g, PCSZ collname, PCSZ wrapper);
+
+ // Implementation
+public:
+ virtual void AddJars(PSTRG jpop, char sep);
+ virtual bool Connect(PJPARM sop);
+ virtual bool MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, PCSZ filter, bool pipe);
+// PQRYRES AllocateResult(PGLOBAL g, TDBEXT *tdbp, int n);
+
+ // Attributes
+public:
+// virtual int GetMaxValue(int infotype);
+
+public:
+ // Operations
+ virtual int Fetch(int pos = 0);
+ virtual PSZ GetColumnValue(PSZ name);
+
+ int CollSize(PGLOBAL g);
+ bool FindCollection(PCSZ query, PCSZ proj);
+ bool AggregateCollection(PCSZ pipeline);
+ void MakeColumnGroups(PGLOBAL g, PTDB tdbp);
+ bool GetMethodId(PGLOBAL g, MODE mode);
+ jobject MakeObject(PGLOBAL g, PCOL colp, bool& error);
+ jobject MakeDoc(PGLOBAL g, PJNCOL jcp);
+ int DocWrite(PGLOBAL g, PCSZ line);
+ int DocUpdate(PGLOBAL g, PTDB tdbp);
+ int DocDelete(PGLOBAL g, bool all);
+ bool Rewind(void);
+ PSZ GetDocument(void);
+ bool Stringify(PCOL colp);
+
+protected:
+ // Members
+ PCSZ CollName; // The collation name
+ jmethodID gcollid; // The GetCollection method ID
+ jmethodID countid; // The GetCollSize method ID
+ jmethodID fcollid; // The FindColl method ID
+ jmethodID acollid; // The AggregateColl method ID
+ jmethodID readid; // The ReadNext method ID
+ jmethodID fetchid; // The Fetch method ID
+ jmethodID rewindid; // The Rewind method ID
+ jmethodID getdocid; // The GetDoc method ID
+ jmethodID objfldid; // The ObjectField method ID
+ jmethodID mkdocid; // The MakeDocument method ID
+ jmethodID mkbsonid; // The MakeBson method ID
+ jmethodID docaddid; // The DocAdd method ID
+ jmethodID mkarid; // The MakeArray method ID
+ jmethodID araddid; // The ArrayAdd method ID
+ jmethodID insertid; // The CollInsert method ID
+ jmethodID updateid; // The CollUpdate method ID
+ jmethodID deleteid; // The CollDelete method ID
+ PJNCOL Fpc; // To JNCOL classes
+ int m_Fetch;
+ int m_Ncol;
+ int m_Version; // Java driver version (2 or 3)
+}; // end of JMgoConn class definition
diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp
new file mode 100644
index 00000000..b9f94923
--- /dev/null
+++ b/storage/connect/json.cpp
@@ -0,0 +1,2060 @@
+/*************** json CPP Declares Source Code File (.H) ***************/
+/* Name: json.cpp Version 1.6 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */
+/* */
+/* This file contains the JSON classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* xjson.h is header containing the JSON classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "json.h"
+
+#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
+
+#if defined(_WIN32)
+#define EL "\r\n"
+#else
+#define EL "\n"
+#undef SE_CATCH // Does not work for Linux
+#endif
+
+#if defined(SE_CATCH)
+/**************************************************************************/
+/* This is the support of catching C interrupts to prevent crashes. */
+/**************************************************************************/
+#include <eh.h>
+
+class SE_Exception {
+public:
+ SE_Exception(unsigned int n, PEXCEPTION_RECORD p) : nSE(n), eRec(p) {}
+ ~SE_Exception() {}
+
+ unsigned int nSE;
+ PEXCEPTION_RECORD eRec;
+}; // end of class SE_Exception
+
+void trans_func(unsigned int u, _EXCEPTION_POINTERS* pExp)
+{
+ throw SE_Exception(u, pExp->ExceptionRecord);
+} // end of trans_func
+
+char *GetExceptionDesc(PGLOBAL g, unsigned int e);
+#endif // SE_CATCH
+
+char *GetJsonNull(void);
+int GetDefaultPrec(void);
+int PrepareColist(char*);
+
+/***********************************************************************/
+/* IsNum: check whether this string is all digits. */
+/***********************************************************************/
+bool IsNum(PSZ s)
+{
+ char* p = s;
+
+ if (*p == '-')
+ p++;
+
+ if (*p == ']')
+ return false;
+ else for (; *p; p++)
+ if (*p == ']')
+ break;
+ else if (!isdigit(*p))
+ return false;
+
+ return true;
+} // end of IsNum
+
+/***********************************************************************/
+/* IsArray: check whether this is a Mongo array path. */
+/***********************************************************************/
+bool IsArray(PSZ s)
+{
+ char* p = s;
+
+ if (!p || !*p)
+ return false;
+ else for (; *p; p++)
+ if (*p == '.')
+ break;
+ else if (!isdigit(*p))
+ return false;
+
+ return true;
+} // end of IsArray
+
+/***********************************************************************/
+/* NextChr: return the first found '[' or Sep pointer. */
+/***********************************************************************/
+char* NextChr(PSZ s, char sep)
+{
+ char* p1 = strchr(s, '[');
+ char* p2 = strchr(s, sep);
+
+ if (!p2)
+ return p1;
+ else if (p1)
+ return MY_MIN(p1, p2);
+
+ return p2;
+} // end of NextChr
+
+/***********************************************************************/
+/* Stringified: check that this column is in the stringified list. */
+/***********************************************************************/
+bool Stringified(PCSZ strfy, char *colname)
+{
+ if (strfy) {
+ char *p, colist[512];
+ int n;
+
+ strncpy(colist, strfy, sizeof(colist) - 1);
+ n = PrepareColist(colist);
+
+ for (p = colist; n && p; p += (strlen(p) + 1), n--)
+ if (!stricmp(p, colname))
+ return true;
+
+ } // endif strfy
+
+ return false;
+} // end of Stringified
+
+#if 0
+/***********************************************************************/
+/* Allocate a VAL structure, make sure common field and Nd are zeroed. */
+/***********************************************************************/
+PVL AllocVal(PGLOBAL g, JTYP type)
+{
+ PVL vlp = (PVL)PlugSubAlloc(g, NULL, sizeof(VAL));
+
+ vlp->LLn = 0;
+ vlp->Nd = 0;
+ vlp->Type = type;
+ return vlp;
+} // end of AllocVal
+#endif // 0
+
+/***********************************************************************/
+/* Parse a json string. */
+/* Note: when pretty is not known, the caller set pretty to 3. */
+/***********************************************************************/
+PJSON ParseJson(PGLOBAL g, char* s, size_t len, int* ptyp, bool* comma)
+{
+ int i, pretty = (ptyp) ? *ptyp : 3;
+ bool b = false, pty[3] = { true,true,true };
+ PJSON jsp = NULL;
+ PJDOC jdp = NULL;
+
+ if (trace(1))
+ htrc("ParseJson: s=%.10s len=%zd\n", s, len);
+
+ if (!s || !len) {
+ strcpy(g->Message, "Void JSON object");
+ return NULL;
+ } else if (comma)
+ *comma = false;
+
+ // Trying to guess the pretty format
+ if (s[0] == '[' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
+ pty[0] = false;
+
+ try {
+ jdp = new(g) JDOC;
+ jdp->s = s;
+ jdp->len = len;
+ jdp->pty = pty;
+
+ for (i = 0; i < jdp->len; i++)
+ switch (s[i]) {
+ case '[':
+ if (jsp)
+ jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
+ else
+ jsp = jdp->ParseArray(g, ++i);
+
+ break;
+ case '{':
+ if (jsp)
+ jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
+ else if (!(jsp = jdp->ParseObject(g, ++i)))
+ throw 2;
+
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ case ',':
+ if (jsp && (pretty == 1 || pretty == 3)) {
+ if (comma)
+ *comma = true;
+
+ pty[0] = pty[2] = false;
+ break;
+ } // endif pretty
+
+ sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
+ throw 3;
+ case '(':
+ b = true;
+ break;
+ case ')':
+ if (b) {
+ b = false;
+ break;
+ } // endif b
+ /* falls through */
+ default:
+ if (jsp)
+ jsp = jdp->ParseAsArray(g, i, pretty, ptyp);
+ else if (!(jsp = jdp->ParseValue(g, i)))
+ throw 4;
+
+ break;
+ }; // endswitch s[i]
+
+ if (!jsp)
+ sprintf(g->Message, "Invalid Json string '%.*s'", MY_MIN((int)len, 50), s);
+ else if (ptyp && pretty == 3) {
+ *ptyp = 3; // Not recognized pretty
+
+ for (i = 0; i < 3; i++)
+ if (pty[i]) {
+ *ptyp = i;
+ break;
+ } // endif pty
+
+ } // endif ptyp
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ jsp = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ jsp = NULL;
+ } // end catch
+
+ return jsp;
+} // end of ParseJson
+
+/***********************************************************************/
+/* Serialize a JSON document tree: */
+/***********************************************************************/
+PSZ Serialize(PGLOBAL g, PJSON jsp, char* fn, int pretty) {
+ PSZ str = NULL;
+ bool b = false, err = true;
+ JOUT* jp;
+ FILE* fs = NULL;
+ PJDOC jdp = NULL;
+
+ g->Message[0] = 0;
+
+ try {
+ jdp = new(g) JDOC; // MUST BE ALLOCATED BEFORE jp !!!!!
+ jdp->dfp = GetDefaultPrec();
+
+ if (!jsp) {
+ strcpy(g->Message, "Null json tree");
+ throw 1;
+ } else if (!fn) {
+ // Serialize to a string
+ jp = new(g) JOUTSTR(g);
+ b = pretty == 1;
+ } else {
+ if (!(fs = fopen(fn, "wb"))) {
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "w", (int)errno, fn);
+ strcat(strcat(g->Message, ": "), strerror(errno));
+ throw 2;
+ } else if (pretty >= 2) {
+ // Serialize to a pretty file
+ jp = new(g)JOUTPRT(g, fs);
+ } else {
+ // Serialize to a flat file
+ b = true;
+ jp = new(g)JOUTFILE(g, fs, pretty);
+ } // endif's
+
+ } // endif's
+
+ jdp->SetJp(jp);
+
+ switch (jsp->GetType()) {
+ case TYPE_JAR:
+ err = jdp->SerializeArray((PJAR)jsp, b);
+ break;
+ case TYPE_JOB:
+ err = ((b && jp->Prty()) && jp->WriteChr('\t'));
+ err |= jdp->SerializeObject((PJOB)jsp);
+ break;
+ case TYPE_JVAL:
+ err = jdp->SerializeValue((PJVAL)jsp);
+ break;
+ default:
+ strcpy(g->Message, "Invalid json tree");
+ } // endswitch Type
+
+ if (fs) {
+ fputs(EL, fs);
+ fclose(fs);
+ str = (err) ? NULL : strcpy(g->Message, "Ok");
+ } else if (!err) {
+ str = ((JOUTSTR*)jp)->Strp;
+ jp->WriteChr('\0');
+ PlugSubAlloc(g, NULL, ((JOUTSTR*)jp)->N);
+ } else {
+ if (!g->Message[0])
+ strcpy(g->Message, "Error in Serialize");
+
+ } // endif's
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ str = NULL;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ str = NULL;
+ } // end catch
+
+ return str;
+} // end of Serialize
+
+
+/* -------------------------- Class JOUTSTR -------------------------- */
+
+/***********************************************************************/
+/* JOUTSTR constructor. */
+/***********************************************************************/
+JOUTSTR::JOUTSTR(PGLOBAL g) : JOUT(g) {
+ PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
+
+ N = 0;
+ Max = pph->FreeBlk;
+ Max = (Max > 32) ? Max - 32 : Max;
+ Strp = (char*)PlugSubAlloc(g, NULL, 0); // Size not know yet
+} // end of JOUTSTR constructor
+
+/***********************************************************************/
+/* Concatenate a string to the Serialize string. */
+/***********************************************************************/
+bool JOUTSTR::WriteStr(const char* s) {
+ if (s) {
+ size_t len = strlen(s);
+
+ if (N + len > Max)
+ return true;
+
+ memcpy(Strp + N, s, len);
+ N += len;
+ return false;
+ } else
+ return true;
+
+} // end of WriteStr
+
+/***********************************************************************/
+/* Concatenate a character to the Serialize string. */
+/***********************************************************************/
+bool JOUTSTR::WriteChr(const char c) {
+ if (N + 1 > Max)
+ return true;
+
+ Strp[N++] = c;
+ return false;
+} // end of WriteChr
+
+/***********************************************************************/
+/* Escape and Concatenate a string to the Serialize string. */
+/***********************************************************************/
+bool JOUTSTR::Escape(const char* s)
+{
+ if (s) {
+ WriteChr('"');
+
+ for (unsigned int i = 0; s[i]; i++)
+ switch (s[i]) {
+ case '"':
+ case '\\':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\b':
+ case '\f': WriteChr('\\');
+ // fall through
+ default:
+ WriteChr(s[i]);
+ break;
+ } // endswitch s[i]
+
+ WriteChr('"');
+ } else
+ WriteStr("null");
+
+ return false;
+} // end of Escape
+
+/* ------------------------- Class JOUTFILE -------------------------- */
+
+/***********************************************************************/
+/* Write a string to the Serialize file. */
+/***********************************************************************/
+bool JOUTFILE::WriteStr(const char* s)
+{
+ // This is temporary
+ fputs(s, Stream);
+ return false;
+} // end of WriteStr
+
+/***********************************************************************/
+/* Write a character to the Serialize file. */
+/***********************************************************************/
+bool JOUTFILE::WriteChr(const char c)
+{
+ // This is temporary
+ fputc(c, Stream);
+ return false;
+} // end of WriteChr
+
+/***********************************************************************/
+/* Escape and Concatenate a string to the Serialize string. */
+/***********************************************************************/
+bool JOUTFILE::Escape(const char* s)
+{
+ // This is temporary
+ if (s) {
+ fputc('"', Stream);
+
+ for (unsigned int i = 0; s[i]; i++)
+ switch (s[i]) {
+ case '"': fputs("\\\"", Stream); break;
+ case '\\': fputs("\\\\", Stream); break;
+ case '\t': fputs("\\t", Stream); break;
+ case '\n': fputs("\\n", Stream); break;
+ case '\r': fputs("\\r", Stream); break;
+ case '\b': fputs("\\b", Stream); break;
+ case '\f': fputs("\\f", Stream); break;
+ default:
+ fputc(s[i], Stream);
+ break;
+ } // endswitch s[i]
+
+ fputc('"', Stream);
+ } else
+ fputs("null", Stream);
+
+ return false;
+} // end of Escape
+
+/* ------------------------- Class JOUTPRT --------------------------- */
+
+/***********************************************************************/
+/* Write a string to the Serialize pretty file. */
+/***********************************************************************/
+bool JOUTPRT::WriteStr(const char* s)
+{
+ // This is temporary
+ if (B) {
+ fputs(EL, Stream);
+ M--;
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+
+ B = false;
+ } // endif B
+
+ fputs(s, Stream);
+ return false;
+} // end of WriteStr
+
+/***********************************************************************/
+/* Write a character to the Serialize pretty file. */
+/***********************************************************************/
+bool JOUTPRT::WriteChr(const char c)
+{
+ switch (c) {
+ case ':':
+ fputs(": ", Stream);
+ break;
+ case '{':
+ case '[':
+#if 0
+ if (M)
+ fputs(EL, Stream);
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+#endif // 0
+
+ fputc(c, Stream);
+ fputs(EL, Stream);
+ M++;
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+
+ break;
+ case '}':
+ case ']':
+ M--;
+ fputs(EL, Stream);
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+
+ fputc(c, Stream);
+ B = true;
+ break;
+ case ',':
+ fputc(c, Stream);
+ fputs(EL, Stream);
+
+ for (int i = 0; i < M; i++)
+ fputc('\t', Stream);
+
+ B = false;
+ break;
+ default:
+ fputc(c, Stream);
+ } // endswitch c
+
+ return false;
+} // end of WriteChr
+
+/* --------------------------- Class JDOC ---------------------------- */
+
+/***********************************************************************/
+/* Parse several items as being in an array. */
+/***********************************************************************/
+PJAR JDOC::ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp)
+{
+ if (pty[0] && (!pretty || pretty > 2)) {
+ PJAR jsp;
+
+ if ((jsp = ParseArray(g, (i = 0))) && ptyp && pretty == 3)
+ *ptyp = (pty[0]) ? 0 : 3;
+
+ return jsp;
+ } else
+ strcpy(g->Message, "More than one item in file");
+
+ return NULL;
+} // end of ParseAsArray
+
+/***********************************************************************/
+/* Parse a JSON Array. */
+/***********************************************************************/
+PJAR JDOC::ParseArray(PGLOBAL g, int& i)
+{
+ int level = 0;
+ bool b = (!i);
+ PJAR jarp = new(g) JARRAY;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case ',':
+ if (level < 2) {
+ sprintf(g->Message, "Unexpected ',' near %.*s",ARGS);
+ throw 1;
+ } else
+ level = 1;
+
+ break;
+ case ']':
+ if (level == 1) {
+ sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS);
+ throw 1;
+ } // endif level
+
+ jarp->InitArray(g);
+ return jarp;
+ case '\n':
+ if (!b)
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ if (level == 2) {
+ sprintf(g->Message, "Unexpected value near %.*s", ARGS);
+ throw 1;
+ } else
+ jarp->AddArrayValue(g, ParseValue(g, i));
+
+ level = (b) ? 1 : 2;
+ break;
+ }; // endswitch s[i]
+
+ if (b) {
+ // Case of Pretty == 0
+ jarp->InitArray(g);
+ return jarp;
+ } // endif b
+
+ throw ("Unexpected EOF in array");
+} // end of ParseArray
+
+/***********************************************************************/
+/* Parse a JSON Object. */
+/***********************************************************************/
+PJOB JDOC::ParseObject(PGLOBAL g, int& i)
+{
+ PSZ key;
+ int level = -1;
+ PJOB jobp = new(g) JOBJECT;
+ PJPR jpp = NULL;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '"':
+ if (level < 2) {
+ key = ParseString(g, ++i);
+ jpp = jobp->AddPair(g, key);
+ level = 1;
+ } else {
+ sprintf(g->Message, "misplaced string near %.*s", ARGS);
+ throw 2;
+ } // endif level
+
+ break;
+ case ':':
+ if (level == 1) {
+ jpp->Val = ParseValue(g, ++i);
+ level = 2;
+ } else {
+ sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
+ throw 2;
+ } // endif level
+
+ break;
+ case ',':
+ if (level < 2) {
+ sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
+ throw 2;
+ } else
+ level = 0;
+
+ break;
+ case '}':
+ if (level == 0 || level == 1) {
+ sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
+ throw 2;
+ } // endif level
+
+ return jobp;
+ case '\n':
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ sprintf(g->Message, "Unexpected character '%c' near %.*s",
+ s[i], ARGS);
+ throw 2;
+ }; // endswitch s[i]
+
+ strcpy(g->Message, "Unexpected EOF in Object");
+ throw 2;
+} // end of ParseObject
+
+/***********************************************************************/
+/* Parse a JSON Value. */
+/***********************************************************************/
+PJVAL JDOC::ParseValue(PGLOBAL g, int& i)
+{
+ PJVAL jvp = new(g) JVALUE;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '\n':
+ pty[0] = pty[1] = false;
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ goto suite;
+ } // endswitch
+
+ suite:
+ switch (s[i]) {
+ case '[':
+ jvp->Jsp = ParseArray(g, ++i);
+ jvp->DataType = TYPE_JSON;
+ break;
+ case '{':
+ jvp->Jsp = ParseObject(g, ++i);
+ jvp->DataType = TYPE_JSON;
+ break;
+ case '"':
+// jvp->Val = AllocVal(g, TYPE_STRG);
+ jvp->Strp = ParseString(g, ++i);
+ jvp->DataType = TYPE_STRG;
+ break;
+ case 't':
+ if (!strncmp(s + i, "true", 4)) {
+// jvp->Val = AllocVal(g, TYPE_BOOL);
+ jvp->B = true;
+ jvp->DataType = TYPE_BOOL;
+ i += 3;
+ } else
+ goto err;
+
+ break;
+ case 'f':
+ if (!strncmp(s + i, "false", 5)) {
+// jvp->Val = AllocVal(g, TYPE_BOOL);
+ jvp->B = false;
+ jvp->DataType = TYPE_BOOL;
+ i += 4;
+ } else
+ goto err;
+
+ break;
+ case 'n':
+ if (!strncmp(s + i, "null", 4)) {
+ jvp->DataType = TYPE_NULL;
+ i += 3;
+ } else
+ goto err;
+
+ break;
+ case '-':
+ default:
+ if (s[i] == '-' || isdigit(s[i]))
+ ParseNumeric(g, i, jvp);
+ else
+ goto err;
+
+ }; // endswitch s[i]
+
+ return jvp;
+
+err:
+ sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS);
+ throw 3;
+} // end of ParseValue
+
+/***********************************************************************/
+/* Unescape and parse a JSON string. */
+/***********************************************************************/
+char *JDOC::ParseString(PGLOBAL g, int& i)
+{
+ uchar *p;
+ int n = 0;
+
+ // Be sure of memory availability
+ if (((size_t)len + 1 - i) > ((PPOOLHEADER)g->Sarea)->FreeBlk)
+ throw("ParseString: Out of memory");
+
+ // The size to allocate is not known yet
+ p = (uchar*)PlugSubAlloc(g, NULL, 0);
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '"':
+ p[n++] = 0;
+ PlugSubAlloc(g, NULL, n);
+ return (char*)p;
+ case '\\':
+ if (++i < len) {
+ if (s[i] == 'u') {
+ if (len - i > 5) {
+// if (charset == utf8) {
+ char xs[5];
+ uint hex;
+
+ xs[0] = s[++i];
+ xs[1] = s[++i];
+ xs[2] = s[++i];
+ xs[3] = s[++i];
+ xs[4] = 0;
+ hex = strtoul(xs, NULL, 16);
+
+ if (hex < 0x80) {
+ p[n] = (uchar)hex;
+ } else if (hex < 0x800) {
+ p[n++] = (uchar)(0xC0 | (hex >> 6));
+ p[n] = (uchar)(0x80 | (hex & 0x3F));
+ } else if (hex < 0x10000) {
+ p[n++] = (uchar)(0xE0 | (hex >> 12));
+ p[n++] = (uchar)(0x80 | ((hex >> 6) & 0x3f));
+ p[n] = (uchar)(0x80 | (hex & 0x3f));
+ } else
+ p[n] = '?';
+
+#if 0
+ } else {
+ char xs[3];
+ UINT hex;
+
+ i += 2;
+ xs[0] = s[++i];
+ xs[1] = s[++i];
+ xs[2] = 0;
+ hex = strtoul(xs, NULL, 16);
+ p[n] = (char)hex;
+ } // endif charset
+#endif // 0
+ } else
+ goto err;
+
+ } else switch(s[i]) {
+ case 't': p[n] = '\t'; break;
+ case 'n': p[n] = '\n'; break;
+ case 'r': p[n] = '\r'; break;
+ case 'b': p[n] = '\b'; break;
+ case 'f': p[n] = '\f'; break;
+ default: p[n] = s[i]; break;
+ } // endswitch
+
+ n++;
+ } else
+ goto err;
+
+ break;
+ default:
+ p[n++] = s[i];
+ break;
+ }; // endswitch s[i]
+
+ err:
+ throw("Unexpected EOF in String");
+} // end of ParseString
+
+/***********************************************************************/
+/* Parse a JSON numeric value. */
+/***********************************************************************/
+void JDOC::ParseNumeric(PGLOBAL g, int& i, PJVAL vlp)
+{
+ char buf[50];
+ int n = 0;
+ short nd = 0;
+ bool has_dot = false;
+ bool has_e = false;
+ bool found_digit = false;
+//PVL vlp = NULL;
+
+ for (; i < len; i++) {
+ switch (s[i]) {
+ case '.':
+ if (!found_digit || has_dot || has_e)
+ goto err;
+
+ has_dot = true;
+ break;
+ case 'e':
+ case 'E':
+ if (!found_digit || has_e)
+ goto err;
+
+ has_e = true;
+ found_digit = false;
+ break;
+ case '+':
+ if (!has_e)
+ goto err;
+
+ // fall through
+ case '-':
+ if (found_digit)
+ goto err;
+
+ break;
+ default:
+ if (isdigit(s[i])) {
+ if (has_dot && !has_e)
+ nd++; // Number of decimals
+
+ found_digit = true;
+ } else
+ goto fin;
+
+ }; // endswitch s[i]
+
+ buf[n++] = s[i];
+ } // endfor i
+
+ fin:
+ if (found_digit) {
+ buf[n] = 0;
+
+ if (has_dot || has_e) {
+ double dv = strtod(buf, NULL);
+
+// vlp = AllocVal(g, TYPE_DBL);
+ vlp->F = dv;
+ vlp->Nd = nd;
+ vlp->DataType = TYPE_DBL;
+ } else {
+ long long iv = strtoll(buf, NULL, 10);
+
+ if (iv > INT_MAX32 || iv < INT_MIN32) {
+// vlp = AllocVal(g, TYPE_BINT);
+ vlp->LLn = iv;
+ vlp->DataType = TYPE_BINT;
+ } else {
+// vlp = AllocVal(g, TYPE_INTG);
+ vlp->N = (int)iv;
+ vlp->DataType = TYPE_INTG;
+ } // endif iv
+
+ } // endif has
+
+ i--; // Unstack following character
+ return;
+ } else
+ throw("No digit found");
+
+ err:
+ throw("Unexpected EOF in number");
+} // end of ParseNumeric
+
+/***********************************************************************/
+/* Serialize a JSON Array. */
+/***********************************************************************/
+bool JDOC::SerializeArray(PJAR jarp, bool b)
+{
+ bool first = true;
+
+ if (b) {
+ if (js->Prty()) {
+ if (js->WriteChr('['))
+ return true;
+ else if (js->Prty() == 1 && (js->WriteStr(EL) || js->WriteChr('\t')))
+ return true;
+
+ } // endif Prty
+
+ } else if (js->WriteChr('['))
+ return true;
+
+ for (int i = 0; i < jarp->size(); i++) {
+ if (first)
+ first = false;
+ else if ((!b || js->Prty()) && js->WriteChr(','))
+ return true;
+ else if (b) {
+ if (js->Prty() < 2 && js->WriteStr(EL))
+ return true;
+ else if (js->Prty() == 1 && js->WriteChr('\t'))
+ return true;
+
+ } // endif b
+
+ if (SerializeValue(jarp->GetArrayValue(i)))
+ return true;
+
+ } // endfor i
+
+ if (b && js->Prty() == 1 && js->WriteStr(EL))
+ return true;
+
+ return ((!b || js->Prty()) && js->WriteChr(']'));
+} // end of SerializeArray
+
+/***********************************************************************/
+/* Serialize a JSON Object. */
+/***********************************************************************/
+bool JDOC::SerializeObject(PJOB jobp)
+{
+ bool first = true;
+
+ if (js->WriteChr('{'))
+ return true;
+
+ for (PJPR pair = jobp->GetFirst(); pair; pair = pair->Next) {
+ if (first)
+ first = false;
+ else if (js->WriteChr(','))
+ return true;
+
+ if (js->WriteChr('"') ||
+ js->WriteStr(pair->Key) ||
+ js->WriteChr('"') ||
+ js->WriteChr(':') ||
+ SerializeValue(pair->Val))
+ return true;
+
+ } // endfor i
+
+ return js->WriteChr('}');
+} // end of SerializeObject
+
+/***********************************************************************/
+/* Serialize a JSON Value. */
+/***********************************************************************/
+bool JDOC::SerializeValue(PJVAL jvp)
+{
+ char buf[64];
+ PJAR jap;
+ PJOB jop;
+ //PVL vlp;
+
+ if ((jap = jvp->GetArray()))
+ return SerializeArray(jap, false);
+ else if ((jop = jvp->GetObject()))
+ return SerializeObject(jop);
+//else if (!(vlp = jvp->Val))
+// return js->WriteStr("null");
+ else switch (jvp->DataType) {
+ case TYPE_BOOL:
+ return js->WriteStr(jvp->B ? "true" : "false");
+ case TYPE_STRG:
+ case TYPE_DTM:
+ return js->Escape(jvp->Strp);
+ case TYPE_INTG:
+ sprintf(buf, "%d", jvp->N);
+ return js->WriteStr(buf);
+ case TYPE_BINT:
+ sprintf(buf, "%lld", jvp->LLn);
+ return js->WriteStr(buf);
+ case TYPE_DBL: // dfp to limit to the default number of decimals
+ sprintf(buf, "%.*f", MY_MIN(jvp->Nd, dfp), jvp->F);
+ return js->WriteStr(buf);
+ case TYPE_NULL:
+ return js->WriteStr("null");
+ default:
+ return js->WriteStr("???"); // TODO
+ } // endswitch Type
+
+ strcpy(js->g->Message, "Unrecognized value");
+ return true;
+} // end of SerializeValue
+
+/* -------------------------- Class JOBJECT -------------------------- */
+
+/***********************************************************************/
+/* Return the number of pairs in this object. */
+/***********************************************************************/
+int JOBJECT::GetSize(bool b) {
+ int n = 0;
+
+ for (PJPR jpp = First; jpp; jpp = jpp->Next)
+ // If b return only non null pairs
+ if (!b || jpp->Val && !jpp->Val->IsNull())
+ n++;
+
+ return n;
+} // end of GetSize
+
+/***********************************************************************/
+/* Add a new pair to an Object. */
+/***********************************************************************/
+PJPR JOBJECT::AddPair(PGLOBAL g, PCSZ key)
+{
+ PJPR jpp = (PJPR)PlugSubAlloc(g, NULL, sizeof(JPAIR));
+
+ jpp->Key = key;
+ jpp->Next = NULL;
+ jpp->Val = NULL;
+
+ if (Last)
+ Last->Next = jpp;
+ else
+ First = jpp;
+
+ Last = jpp;
+ return jpp;
+} // end of AddPair
+
+/***********************************************************************/
+/* Return all keys as an array. */
+/***********************************************************************/
+PJAR JOBJECT::GetKeyList(PGLOBAL g)
+{
+ PJAR jarp = new(g) JARRAY();
+
+ for (PJPR jpp = First; jpp; jpp = jpp->Next)
+ jarp->AddArrayValue(g, new(g) JVALUE(g, jpp->Key));
+
+ jarp->InitArray(g);
+ return jarp;
+} // end of GetKeyList
+
+/***********************************************************************/
+/* Return all values as an array. */
+/***********************************************************************/
+PJAR JOBJECT::GetValList(PGLOBAL g)
+{
+ PJAR jarp = new(g) JARRAY();
+
+ for (PJPR jpp = First; jpp; jpp = jpp->Next)
+ jarp->AddArrayValue(g, jpp->Val);
+
+ jarp->InitArray(g);
+ return jarp;
+} // end of GetValList
+
+/***********************************************************************/
+/* Get the value corresponding to the given key. */
+/***********************************************************************/
+PJVAL JOBJECT::GetKeyValue(const char* key)
+{
+ for (PJPR jp = First; jp; jp = jp->Next)
+ if (!strcmp(jp->Key, key))
+ return jp->Val;
+
+ return NULL;
+} // end of GetValue;
+
+/***********************************************************************/
+/* Return the text corresponding to all keys (XML like). */
+/***********************************************************************/
+PSZ JOBJECT::GetText(PGLOBAL g, PSTRG text)
+{
+ if (First) {
+ bool b;
+
+ if (!text) {
+ text = new(g) STRING(g, 256);
+ b = true;
+ } else {
+ if (text->GetLastChar() != ' ')
+ text->Append(' ');
+
+ b = false;
+ } // endif text
+
+ if (b && !First->Next && !strcmp(First->Key, "$date")) {
+ int i;
+ PSZ s;
+
+ First->Val->GetText(g, text);
+ s = text->GetStr();
+ i = (s[1] == '-' ? 2 : 1);
+
+ if (IsNum(s + i)) {
+ // Date is in milliseconds
+ int j = text->GetLength();
+
+ if (j >= 4 + i) {
+ s[j - 3] = 0; // Change it to seconds
+ text->SetLength((uint)strlen(s));
+ } else
+ text->Set(" 0");
+
+ } // endif text
+
+ } else for (PJPR jp = First; jp; jp = jp->Next) {
+ jp->Val->GetText(g, text);
+
+ if (jp->Next)
+ text->Append(' ');
+
+ } // endfor jp
+
+ if (b) {
+ text->Trim();
+ return text->GetStr();
+ } // endif b
+
+ } // endif First
+
+ return NULL;
+} // end of GetText;
+
+/***********************************************************************/
+/* Merge two objects. */
+/***********************************************************************/
+bool JOBJECT::Merge(PGLOBAL g, PJSON jsp)
+{
+ if (jsp->GetType() != TYPE_JOB) {
+ strcpy(g->Message, "Second argument is not an object");
+ return true;
+ } // endif Type
+
+ PJOB jobp = (PJOB)jsp;
+
+ for (PJPR jpp = jobp->First; jpp; jpp = jpp->Next)
+ SetKeyValue(g, jpp->Val, jpp->Key);
+
+ return false;
+} // end of Marge;
+
+/***********************************************************************/
+/* Set or add a value corresponding to the given key. */
+/***********************************************************************/
+void JOBJECT::SetKeyValue(PGLOBAL g, PJVAL jvp, PCSZ key)
+{
+ PJPR jp;
+
+ for (jp = First; jp; jp = jp->Next)
+ if (!strcmp(jp->Key, key)) {
+ jp->Val = jvp;
+ break;
+ } // endif key
+
+ if (!jp) {
+ jp = AddPair(g, key);
+ jp->Val = jvp;
+ } // endif jp
+
+} // end of SetValue
+
+/***********************************************************************/
+/* Delete a value corresponding to the given key. */
+/***********************************************************************/
+void JOBJECT::DeleteKey(PCSZ key)
+{
+ PJPR jp, *pjp = &First;
+
+ for (jp = First; jp; jp = jp->Next)
+ if (!strcmp(jp->Key, key)) {
+ *pjp = jp->Next;
+ break;
+ } else
+ pjp = &jp->Next;
+
+} // end of DeleteKey
+
+/***********************************************************************/
+/* True if void or if all members are nulls. */
+/***********************************************************************/
+bool JOBJECT::IsNull(void)
+{
+ for (PJPR jp = First; jp; jp = jp->Next)
+ if (!jp->Val->IsNull())
+ return false;
+
+ return true;
+} // end of IsNull
+
+/* -------------------------- Class JARRAY --------------------------- */
+
+/***********************************************************************/
+/* JARRAY constructor. */
+/***********************************************************************/
+JARRAY::JARRAY(void) : JSON()
+{
+ Type = TYPE_JAR;
+ Size = 0;
+ Alloc = 0;
+ First = Last = NULL;
+ Mvals = NULL;
+} // end of JARRAY constructor
+
+/***********************************************************************/
+/* Return the number of values in this object. */
+/***********************************************************************/
+int JARRAY::GetSize(bool b)
+{
+ if (b) {
+ // Return only non null values
+ int n = 0;
+
+ for (PJVAL jvp = First; jvp; jvp = jvp->Next)
+ if (!jvp->IsNull())
+ n++;
+
+ return n;
+ } else
+ return Size;
+
+} // end of GetSize
+
+/***********************************************************************/
+/* Make the array of values from the values list. */
+/***********************************************************************/
+void JARRAY::InitArray(PGLOBAL g)
+{
+ int i;
+ PJVAL jvp, *pjvp = &First;
+
+ for (Size = 0, jvp = First; jvp; jvp = jvp->Next)
+ if (!jvp->Del)
+ Size++;
+
+ if (Size > Alloc) {
+ // No need to realloc after deleting values
+ Mvals = (PJVAL*)PlugSubAlloc(g, NULL, Size * sizeof(PJVAL));
+ Alloc = Size;
+ } // endif Size
+
+ for (i = 0, jvp = First; jvp; jvp = jvp->Next)
+ if (!jvp->Del) {
+ Mvals[i++] = jvp;
+ pjvp = &jvp->Next;
+ Last = jvp;
+ } else
+ *pjvp = jvp->Next;
+
+} // end of InitArray
+
+/***********************************************************************/
+/* Get the Nth value of an Array. */
+/***********************************************************************/
+PJVAL JARRAY::GetArrayValue(int i)
+{
+ if (Mvals && i >= 0 && i < Size)
+ return Mvals[i];
+ else if (Mvals && i < 0 && i >= -Size)
+ return Mvals[Size + i];
+ else
+ return NULL;
+} // end of GetValue
+
+/***********************************************************************/
+/* Add a Value to the Array Value list. */
+/***********************************************************************/
+PJVAL JARRAY::AddArrayValue(PGLOBAL g, PJVAL jvp, int *x)
+{
+ if (!jvp)
+ jvp = new(g) JVALUE;
+
+ if (x) {
+ int i = 0, n = *x;
+ PJVAL jp, *jpp = &First;
+
+ for (jp = First; jp && i < n; i++, jp = *(jpp = &jp->Next));
+
+ (*jpp) = jvp;
+
+ if (!(jvp->Next = jp))
+ Last = jvp;
+
+ } else {
+ if (!First)
+ First = jvp;
+ else if (Last == First)
+ First->Next = Last = jvp;
+ else
+ Last->Next = jvp;
+
+ Last = jvp;
+ Last->Next = NULL;
+ } // endif x
+
+ return jvp;
+} // end of AddValue
+
+/***********************************************************************/
+/* Merge two arrays. */
+/***********************************************************************/
+bool JARRAY::Merge(PGLOBAL g, PJSON jsp)
+{
+ if (jsp->GetType() != TYPE_JAR) {
+ strcpy(g->Message, "Second argument is not an array");
+ return true;
+ } // endif Type
+
+ PJAR arp = (PJAR)jsp;
+
+ for (int i = 0; i < arp->size(); i++)
+ AddArrayValue(g, arp->GetArrayValue(i));
+
+ InitArray(g);
+ return false;
+} // end of Merge
+
+/***********************************************************************/
+/* Set the nth Value of the Array Value list or add it. */
+/***********************************************************************/
+void JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n)
+{
+ int i = 0;
+ PJVAL jp, *jpp = &First;
+
+ for (jp = First; i < n; i++, jp = *(jpp = &jp->Next))
+ if (!jp)
+ *jpp = jp = new(g) JVALUE;
+
+ *jpp = jvp;
+ jvp->Next = (jp ? jp->Next : NULL);
+} // end of SetValue
+
+/***********************************************************************/
+/* Return the text corresponding to all values. */
+/***********************************************************************/
+PSZ JARRAY::GetText(PGLOBAL g, PSTRG text)
+{
+ if (First) {
+ bool b;
+ PJVAL jp;
+
+ if (!text) {
+ text = new(g) STRING(g, 256);
+ b = true;
+ } else {
+ if (text->GetLastChar() != ' ')
+ text->Append(" (");
+ else
+ text->Append('(');
+
+ b = false;
+ }
+
+ for (jp = First; jp; jp = jp->Next) {
+ jp->GetText(g, text);
+
+ if (jp->Next)
+ text->Append(", ");
+ else if (!b)
+ text->Append(')');
+
+ } // endfor jp
+
+ if (b) {
+ text->Trim();
+ return text->GetStr();
+ } // endif b
+
+ } // endif First
+
+ return NULL;
+} // end of GetText;
+
+/***********************************************************************/
+/* Delete a Value from the Arrays Value list. */
+/***********************************************************************/
+bool JARRAY::DeleteValue(int n)
+{
+ PJVAL jvp = GetArrayValue(n);
+
+ if (jvp) {
+ jvp->Del = true;
+ return false;
+ } else
+ return true;
+
+} // end of DeleteValue
+
+/***********************************************************************/
+/* True if void or if all members are nulls. */
+/***********************************************************************/
+bool JARRAY::IsNull(void)
+{
+ for (int i = 0; i < Size; i++)
+ if (!Mvals[i]->IsNull())
+ return false;
+
+ return true;
+} // end of IsNull
+
+/* -------------------------- Class JVALUE- -------------------------- */
+
+/***********************************************************************/
+/* Constructor for a JVALUE. */
+/***********************************************************************/
+JVALUE::JVALUE(PJSON jsp) : JSON()
+{
+ if (jsp && jsp->GetType() == TYPE_JVAL) {
+ PJVAL jvp = (PJVAL)jsp;
+
+// Val = ((PJVAL)jsp)->GetVal();
+ if (jvp->DataType == TYPE_JSON) {
+ Jsp = jvp->GetJsp();
+ DataType = TYPE_JSON;
+ Nd = 0;
+ } else {
+ LLn = jvp->LLn; // Must be LLn on 32 bit machines
+ Nd = jvp->Nd;
+ DataType = jvp->DataType;
+ } // endelse Jsp
+
+ } else {
+ Jsp = jsp;
+// Val = NULL;
+ DataType = Jsp ? TYPE_JSON : TYPE_NULL;
+ Nd = 0;
+ } // endif Type
+
+ Next = NULL;
+ Del = false;
+ Type = TYPE_JVAL;
+} // end of JVALUE constructor
+
+#if 0
+/***********************************************************************/
+/* Constructor for a JVALUE with a given string or numeric value. */
+/***********************************************************************/
+JVALUE::JVALUE(PGLOBAL g, PVL vlp) : JSON()
+{
+ Jsp = NULL;
+ Val = vlp;
+ Next = NULL;
+ Del = false;
+ Type = TYPE_JVAL;
+} // end of JVALUE constructor
+#endif // 0
+
+/***********************************************************************/
+/* Constructor for a JVALUE with a given string or numeric value. */
+/***********************************************************************/
+JVALUE::JVALUE(PGLOBAL g, PVAL valp) : JSON() {
+ Jsp = NULL;
+//Val = NULL;
+ SetValue(g, valp);
+ Next = NULL;
+ Del = false;
+ Type = TYPE_JVAL;
+} // end of JVALUE constructor
+
+/***********************************************************************/
+/* Constructor for a given string. */
+/***********************************************************************/
+JVALUE::JVALUE(PGLOBAL g, PCSZ strp) : JSON()
+{
+ Jsp = NULL;
+//Val = AllocVal(g, TYPE_STRG);
+ Strp = (char*)strp;
+ DataType = TYPE_STRG;
+ Nd = 0;
+ Next = NULL;
+ Del = false;
+ Type = TYPE_JVAL;
+} // end of JVALUE constructor
+
+/***********************************************************************/
+/* Set or reset all Jvalue members. */
+/***********************************************************************/
+void JVALUE::Clear(void)
+{
+ Jsp = NULL;
+ Next = NULL;
+ Type = TYPE_JVAL;
+ Del = false;
+ Nd = 0;
+ DataType = TYPE_NULL;
+} // end of Clear
+
+/***********************************************************************/
+/* Returns the type of the Value's value. */
+/***********************************************************************/
+JTYP JVALUE::GetValType(void)
+{
+ if (DataType == TYPE_JSON)
+ return Jsp->GetType();
+//else if (Val)
+// return Val->Type;
+ else
+ return DataType;
+
+} // end of GetValType
+
+/***********************************************************************/
+/* Return the Value's Object value. */
+/***********************************************************************/
+PJOB JVALUE::GetObject(void)
+{
+ if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JOB)
+ return (PJOB)Jsp;
+
+ return NULL;
+} // end of GetObject
+
+/***********************************************************************/
+/* Return the Value's Array value. */
+/***********************************************************************/
+PJAR JVALUE::GetArray(void)
+{
+ if (DataType == TYPE_JSON && Jsp->GetType() == TYPE_JAR)
+ return (PJAR)Jsp;
+
+ return NULL;
+} // end of GetArray
+
+/***********************************************************************/
+/* Return the Value's as a Value class. */
+/***********************************************************************/
+PVAL JVALUE::GetValue(PGLOBAL g)
+{
+ PVAL valp = NULL;
+
+ if (DataType != TYPE_JSON)
+ if (DataType == TYPE_STRG)
+ valp = AllocateValue(g, Strp, DataType, Nd);
+ else
+ valp = AllocateValue(g, &LLn, DataType, Nd);
+
+ return valp;
+} // end of GetValue
+
+/***********************************************************************/
+/* Return the Value's Integer value. */
+/***********************************************************************/
+int JVALUE::GetInteger(void) {
+ int n;
+
+ switch (DataType) {
+ case TYPE_INTG: n = N; break;
+ case TYPE_DBL: n = (int)F; break;
+ case TYPE_DTM:
+ case TYPE_STRG: n = atoi(Strp); break;
+ case TYPE_BOOL: n = (B) ? 1 : 0; break;
+ case TYPE_BINT: n = (int)LLn; break;
+ default:
+ n = 0;
+ } // endswitch Type
+
+ return n;
+} // end of GetInteger
+
+/***********************************************************************/
+/* Return the Value's Big integer value. */
+/***********************************************************************/
+long long JVALUE::GetBigint(void)
+{
+ long long lln;
+
+ switch (DataType) {
+ case TYPE_BINT: lln = LLn; break;
+ case TYPE_INTG: lln = (long long)N; break;
+ case TYPE_DBL: lln = (long long)F; break;
+ case TYPE_DTM:
+ case TYPE_STRG: lln = atoll(Strp); break;
+ case TYPE_BOOL: lln = (B) ? 1 : 0; break;
+ default:
+ lln = 0;
+ } // endswitch Type
+
+ return lln;
+} // end of GetBigint
+
+/***********************************************************************/
+/* Return the Value's Double value. */
+/***********************************************************************/
+double JVALUE::GetFloat(void)
+{
+ double d;
+
+ switch (DataType) {
+ case TYPE_DBL: d = F; break;
+ case TYPE_BINT: d = (double)LLn; break;
+ case TYPE_INTG: d = (double)N; break;
+ case TYPE_DTM:
+ case TYPE_STRG: d = atof(Strp); break;
+ case TYPE_BOOL: d = (B) ? 1.0 : 0.0; break;
+ default:
+ d = 0.0;
+ } // endswitch Type
+
+ return d;
+} // end of GetFloat
+
+/***********************************************************************/
+/* Return the Value's String value. */
+/***********************************************************************/
+PSZ JVALUE::GetString(PGLOBAL g, char *buff)
+{
+ char buf[32];
+ char *p = (buff) ? buff : buf;
+
+ switch (DataType) {
+ case TYPE_DTM:
+ case TYPE_STRG:
+ p = Strp;
+ break;
+ case TYPE_INTG:
+ sprintf(p, "%d", N);
+ break;
+ case TYPE_BINT:
+ sprintf(p, "%lld", LLn);
+ break;
+ case TYPE_DBL:
+ sprintf(p, "%.*lf", Nd, F);
+ break;
+ case TYPE_BOOL:
+ p = (char*)((B) ? "true" : "false");
+ break;
+ case TYPE_NULL:
+ p = (char*)"null";
+ break;
+ default:
+ p = NULL;
+ } // endswitch Type
+
+
+ return (p == buf) ? (char*)PlugDup(g, buf) : p;
+} // end of GetString
+
+/***********************************************************************/
+/* Return the Value's String value. */
+/***********************************************************************/
+PSZ JVALUE::GetText(PGLOBAL g, PSTRG text)
+{
+ if (DataType == TYPE_JSON)
+ return Jsp->GetText(g, text);
+
+ char buff[32];
+ PSZ s = (DataType == TYPE_NULL) ? NULL : GetString(g, buff);
+
+ if (s)
+ text->Append(s);
+ else if (GetJsonNull())
+ text->Append(GetJsonNull());
+
+ return NULL;
+} // end of GetText
+
+void JVALUE::SetValue(PJSON jsp)
+{
+ if (DataType == TYPE_JSON && jsp->GetType() == TYPE_JVAL) {
+ Jsp = jsp->GetJsp();
+ Nd = ((PJVAL)jsp)->Nd;
+ DataType = ((PJVAL)jsp)->DataType;
+ // Val = ((PJVAL)jsp)->GetVal();
+ } else {
+ Jsp = jsp;
+ DataType = TYPE_JSON;
+ } // endif Type
+
+} // end of SetValue;
+
+void JVALUE::SetValue(PGLOBAL g, PVAL valp)
+{
+//if (!Val)
+// Val = AllocVal(g, TYPE_VAL);
+
+ if (!valp || valp->IsNull()) {
+ DataType = TYPE_NULL;
+ } else switch (valp->GetType()) {
+ case TYPE_DATE:
+ if (((DTVAL*)valp)->IsFormatted())
+ Strp = PlugDup(g, valp->GetCharValue());
+ else {
+ char buf[32];
+
+ Strp = PlugDup(g, valp->GetCharString(buf));
+ } // endif Formatted
+
+ DataType = TYPE_DTM;
+ break;
+ case TYPE_STRING:
+ Strp = PlugDup(g, valp->GetCharValue());
+ DataType = TYPE_STRG;
+ break;
+ case TYPE_DOUBLE:
+ case TYPE_DECIM:
+ F = valp->GetFloatValue();
+
+ if (IsTypeNum(valp->GetType()))
+ Nd = valp->GetValPrec();
+
+ DataType = TYPE_DBL;
+ break;
+ case TYPE_TINY:
+ B = valp->GetTinyValue() != 0;
+ DataType = TYPE_BOOL;
+ case TYPE_INT:
+ N = valp->GetIntValue();
+ DataType = TYPE_INTG;
+ break;
+ case TYPE_BIGINT:
+ LLn = valp->GetBigintValue();
+ DataType = TYPE_BINT;
+ break;
+ default:
+ sprintf(g->Message, "Unsupported typ %d\n", valp->GetType());
+ throw(777);
+ } // endswitch Type
+
+} // end of SetValue
+
+/***********************************************************************/
+/* Set the Value's value as the given integer. */
+/***********************************************************************/
+void JVALUE::SetInteger(PGLOBAL g, int n)
+{
+ N = n;
+ DataType = TYPE_INTG;
+} // end of SetInteger
+
+/***********************************************************************/
+/* Set the Value's Boolean value as a tiny integer. */
+/***********************************************************************/
+void JVALUE::SetBool(PGLOBAL g, bool b)
+{
+ B = b;
+ DataType = TYPE_BOOL;
+} // end of SetTiny
+
+/***********************************************************************/
+/* Set the Value's value as the given big integer. */
+/***********************************************************************/
+void JVALUE::SetBigint(PGLOBAL g, long long ll)
+{
+ LLn = ll;
+ DataType = TYPE_BINT;
+} // end of SetBigint
+
+/***********************************************************************/
+/* Set the Value's value as the given DOUBLE. */
+/***********************************************************************/
+void JVALUE::SetFloat(PGLOBAL g, double f)
+{
+ F = f;
+ Nd = GetDefaultPrec();
+ DataType = TYPE_DBL;
+} // end of SetFloat
+
+/***********************************************************************/
+/* Set the Value's value as the given string. */
+/***********************************************************************/
+void JVALUE::SetString(PGLOBAL g, PSZ s, int ci)
+{
+ Strp = s;
+ Nd = ci;
+ DataType = TYPE_STRG;
+} // end of SetString
+
+/***********************************************************************/
+/* True when its JSON or normal value is null. */
+/***********************************************************************/
+bool JVALUE::IsNull(void)
+{
+ return (DataType == TYPE_JSON) ? Jsp->IsNull() : DataType == TYPE_NULL;
+} // end of IsNull
+
+
+/* ---------------------------- Class SWAP --------------------------- */
+
+/***********************************************************************/
+/* Replace all pointers by offsets or the opposite. */
+/***********************************************************************/
+void SWAP::SwapJson(PJSON jsp, bool move)
+{
+ if (move)
+ MoffJson(jsp);
+ else
+ MptrJson((PJSON)MakeOff(Base, jsp));
+
+ return;
+} // end of SwapJson
+
+/***********************************************************************/
+/* Replace all pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffJson(PJSON jsp) {
+ size_t res = 0;
+
+ if (jsp)
+ switch (jsp->Type) {
+ case TYPE_JAR:
+ res = MoffArray((PJAR)jsp);
+ break;
+ case TYPE_JOB:
+ res = MoffObject((PJOB)jsp);
+ break;
+ case TYPE_JVAL:
+ res = MoffJValue((PJVAL)jsp);
+ break;
+ default:
+ throw "Invalid json tree";
+ } // endswitch Type
+
+ return res;
+} // end of MoffJson
+
+/***********************************************************************/
+/* Replace all array pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffArray(PJAR jarp)
+{
+ if (jarp->First) {
+ for (int i = 0; i < jarp->Size; i++)
+ jarp->Mvals[i] = (PJVAL)MakeOff(Base, jarp->Mvals[i]);
+
+ jarp->Mvals = (PJVAL*)MakeOff(Base, jarp->Mvals);
+ jarp->First = (PJVAL)MoffJValue(jarp->First);
+ jarp->Last = (PJVAL)MakeOff(Base, jarp->Last);
+ } // endif First
+
+ return MakeOff(Base, jarp);
+} // end of MoffArray
+
+/***********************************************************************/
+/* Replace all object pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffObject(PJOB jobp) {
+ if (jobp->First) {
+ jobp->First = (PJPR)MoffPair(jobp->First);
+ jobp->Last = (PJPR)MakeOff(Base, jobp->Last);
+ } // endif First
+
+ return MakeOff(Base, jobp);
+} // end of MoffObject
+
+/***********************************************************************/
+/* Replace all pair pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffPair(PJPR jpp) {
+ jpp->Key = (PCSZ)MakeOff(Base, (void*)jpp->Key);
+
+ if (jpp->Val)
+ jpp->Val = (PJVAL)MoffJValue(jpp->Val);
+
+ if (jpp->Next)
+ jpp->Next = (PJPR)MoffPair(jpp->Next);
+
+ return MakeOff(Base, jpp);
+} // end of MoffPair
+
+/***********************************************************************/
+/* Replace all jason value pointers by offsets. */
+/***********************************************************************/
+size_t SWAP::MoffJValue(PJVAL jvp) {
+ if (!jvp->Del) {
+ if (jvp->DataType == TYPE_JSON)
+ jvp->Jsp = (PJSON)MoffJson(jvp->Jsp);
+ else if (jvp->DataType == TYPE_STRG)
+ jvp->Strp = (PSZ)MakeOff(Base, (jvp->Strp));
+
+// if (jvp->Val)
+// jvp->Val = (PVL)MoffVal(jvp->Val);
+
+ } // endif Del
+
+ if (jvp->Next)
+ jvp->Next = (PJVAL)MoffJValue(jvp->Next);
+
+ return MakeOff(Base, jvp);
+} // end of MoffJValue
+
+#if 0
+/***********************************************************************/
+/* Replace string pointers by offset. */
+/***********************************************************************/
+size_t SWAP::MoffVal(PVL vlp) {
+ if (vlp->Type == TYPE_STRG)
+ vlp->Strp = (PSZ)MakeOff(Base, (vlp->Strp));
+
+ return MakeOff(Base, vlp);
+} // end of MoffVal
+#endif // 0
+
+/***********************************************************************/
+/* Replace all offsets by pointers. */
+/***********************************************************************/
+PJSON SWAP::MptrJson(PJSON ojp) { // ojp is an offset
+ PJSON jsp = (PJSON)MakePtr(Base, (size_t)ojp);
+
+ if (ojp)
+ switch (jsp->Type) {
+ case TYPE_JAR:
+ jsp = MptrArray((PJAR)ojp);
+ break;
+ case TYPE_JOB:
+ jsp = MptrObject((PJOB)ojp);
+ break;
+ case TYPE_JVAL:
+ jsp = MptrJValue((PJVAL)ojp);
+ break;
+ default:
+ throw "Invalid json tree";
+ } // endswitch Type
+
+ return jsp;
+} // end of MptrJson
+
+/***********************************************************************/
+/* Replace all array offsets by pointers. */
+/***********************************************************************/
+PJAR SWAP::MptrArray(PJAR ojar) {
+ PJAR jarp = (PJAR)MakePtr(Base, (size_t)ojar);
+
+ jarp = (PJAR)new((long long)jarp) JARRAY(0);
+
+ if (jarp->First) {
+ jarp->Mvals = (PJVAL*)MakePtr(Base, (size_t)jarp->Mvals);
+
+ for (int i = 0; i < jarp->Size; i++)
+ jarp->Mvals[i] = (PJVAL)MakePtr(Base, (size_t)jarp->Mvals[i]);
+
+ jarp->First = (PJVAL)MptrJValue(jarp->First);
+ jarp->Last = (PJVAL)MakePtr(Base, (size_t)jarp->Last);
+ } // endif First
+
+ return jarp;
+} // end of MptrArray
+
+/***********************************************************************/
+/* Replace all object offsets by pointers. */
+/***********************************************************************/
+PJOB SWAP::MptrObject(PJOB ojob) {
+ PJOB jobp = (PJOB)MakePtr(Base, (size_t)ojob);
+
+ jobp = (PJOB)new((long long)jobp) JOBJECT(0);
+
+ if (jobp->First) {
+ jobp->First = (PJPR)MptrPair(jobp->First);
+ jobp->Last = (PJPR)MakePtr(Base, (size_t)jobp->Last);
+ } // endif First
+
+ return jobp;
+} // end of MptrObject
+
+/***********************************************************************/
+/* Replace all pair offsets by pointers. */
+/***********************************************************************/
+PJPR SWAP::MptrPair(PJPR ojp) {
+ PJPR jpp = (PJPR)MakePtr(Base, (size_t)ojp);
+
+ jpp->Key = (PCSZ)MakePtr(Base, (size_t)jpp->Key);
+
+ if (jpp->Val)
+ jpp->Val = (PJVAL)MptrJValue(jpp->Val);
+
+ if (jpp->Next)
+ jpp->Next = (PJPR)MptrPair(jpp->Next);
+
+ return jpp;
+} // end of MptrPair
+
+/***********************************************************************/
+/* Replace all value offsets by pointers. */
+/***********************************************************************/
+PJVAL SWAP::MptrJValue(PJVAL ojv) {
+ PJVAL jvp = (PJVAL)MakePtr(Base, (size_t)ojv);
+
+ jvp = (PJVAL)new((long long)jvp) JVALUE(0);
+
+ if (!jvp->Del) {
+ if (jvp->DataType == TYPE_JSON)
+ jvp->Jsp = (PJSON)MptrJson(jvp->Jsp);
+ else if (jvp->DataType == TYPE_STRG)
+ jvp->Strp = (PSZ)MakePtr(Base, (size_t)jvp->Strp);
+
+// if (jvp->Val)
+// jvp->Val = (PVL)MptrVal(jvp->Val);
+
+ } // endif Del
+
+ if (jvp->Next)
+ jvp->Next = (PJVAL)MptrJValue(jvp->Next);
+
+ return jvp;
+} // end of MptrJValue
+
+#if 0
+/***********************************************************************/
+/* Replace string offsets by a pointer. */
+/***********************************************************************/
+PVL SWAP::MptrVal(PVL ovl) {
+ PVL vlp = (PVL)MakePtr(Base, (size_t)ovl);
+
+ if (vlp->Type == TYPE_STRG)
+ vlp->Strp = (PSZ)MakePtr(Base, (size_t)vlp->Strp);
+
+ return vlp;
+} // end of MptrValue
+#endif // 0
diff --git a/storage/connect/json.h b/storage/connect/json.h
new file mode 100644
index 00000000..53fc5f65
--- /dev/null
+++ b/storage/connect/json.h
@@ -0,0 +1,364 @@
+/**************** json H Declares Source Code File (.H) ****************/
+/* Name: json.h Version 1.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2014 - 2020 */
+/* */
+/* This file contains the JSON classes declares. */
+/***********************************************************************/
+#pragma once
+#include <mysql_com.h>
+#include "value.h"
+#include "xobject.h"
+
+#if defined(_DEBUG)
+#define X assert(false);
+#else
+#define X
+#endif
+
+enum JTYP {
+ TYPE_NULL = TYPE_VOID,
+ TYPE_STRG = TYPE_STRING,
+ TYPE_DBL = TYPE_DOUBLE,
+ TYPE_BOOL = TYPE_TINY,
+ TYPE_BINT = TYPE_BIGINT,
+ TYPE_INTG = TYPE_INT,
+ TYPE_DTM = TYPE_DATE,
+ TYPE_FLOAT,
+ TYPE_JAR,
+ TYPE_JOB,
+ TYPE_JVAL,
+ TYPE_JSON,
+ TYPE_DEL,
+ TYPE_UNKNOWN
+};
+
+class JDOC;
+class JOUT;
+class JSON;
+class JVALUE;
+class JOBJECT;
+class JARRAY;
+
+typedef class JDOC *PJDOC;
+typedef class JSON *PJSON;
+typedef class JVALUE *PJVAL;
+typedef class JOBJECT *PJOB;
+typedef class JARRAY *PJAR;
+
+typedef struct JPAIR *PJPR;
+//typedef struct VAL *PVL;
+
+/***********************************************************************/
+/* Structure JPAIR. The pairs of a json Object. */
+/***********************************************************************/
+struct JPAIR {
+ PCSZ Key; // This pair key name
+ PJVAL Val; // To the value of the pair
+ PJPR Next; // To the next pair
+}; // end of struct JPAIR
+
+//PVL AllocVal(PGLOBAL g, JTYP type);
+char *NextChr(PSZ s, char sep);
+char *GetJsonNull(void);
+const char* GetFmt(int type, bool un);
+
+PJSON ParseJson(PGLOBAL g, char* s, size_t n, int* prty = NULL, bool* b = NULL);
+PSZ Serialize(PGLOBAL g, PJSON jsp, char *fn, int pretty);
+DllExport bool IsNum(PSZ s);
+bool IsArray(PSZ s);
+bool Stringified(PCSZ strfy, char *colname);
+
+/***********************************************************************/
+/* Class JDOC. The class for parsing and serializing json documents. */
+/***********************************************************************/
+class JDOC: public BLOCK {
+ friend PJSON ParseJson(PGLOBAL, char*, size_t, int*, bool*);
+ friend PSZ Serialize(PGLOBAL, PJSON, char*, int);
+public:
+ JDOC(void) : js(NULL), s(NULL), len(0), dfp(0), pty(NULL) {}
+
+ void SetJp(JOUT* jp) { js = jp; }
+
+ protected:
+ PJAR ParseArray(PGLOBAL g, int& i);
+ PJOB ParseObject(PGLOBAL g, int& i);
+ PJVAL ParseValue(PGLOBAL g, int& i);
+ char *ParseString(PGLOBAL g, int& i);
+ void ParseNumeric(PGLOBAL g, int& i, PJVAL jvp);
+ PJAR ParseAsArray(PGLOBAL g, int& i, int pretty, int *ptyp);
+ bool SerializeArray(PJAR jarp, bool b);
+ bool SerializeObject(PJOB jobp);
+ bool SerializeValue(PJVAL jvp);
+
+ // Members used when parsing and serializing
+ private:
+ JOUT* js;
+ char *s;
+ int len, dfp;
+ bool *pty;
+}; // end of class JDOC
+
+/***********************************************************************/
+/* Class JSON. The base class for all other json classes. */
+/***********************************************************************/
+class JSON : public BLOCK {
+public:
+ // Constructor
+ JSON(void) { Type = TYPE_JSON; }
+ JSON(int) {}
+
+ // Implementation
+ inline JTYP GetType(void) { return Type; }
+
+ // Methods
+ virtual int size(void) { return 1; }
+ virtual void Clear(void) { X }
+ virtual PJOB GetObject(void) { return NULL; }
+ virtual PJAR GetArray(void) { return NULL; }
+ virtual PJVAL GetArrayValue(int i) { X return NULL; }
+ virtual int GetSize(bool b) { X return 0; }
+ virtual PJSON GetJsp(void) { X return NULL; }
+ virtual PJPR GetFirst(void) { X return NULL; }
+ virtual PSZ GetText(PGLOBAL g, PSTRG text) { X return NULL; }
+ virtual bool Merge(PGLOBAL g, PJSON jsp) { X return true; }
+ virtual void SetValue(PJSON jsp) { X }
+ virtual bool DeleteValue(int i) { X return true; }
+ virtual bool IsNull(void) { X return true; }
+
+ // Members
+ JTYP Type;
+}; // end of class JSON
+
+/***********************************************************************/
+/* Class JOBJECT: contains a list of value pairs. */
+/***********************************************************************/
+class JOBJECT : public JSON {
+ friend class JDOC;
+ friend class JSNX;
+ friend class SWAP;
+public:
+ JOBJECT(void) : JSON() { Type = TYPE_JOB; First = Last = NULL; }
+ JOBJECT(int i) : JSON(i) {}
+
+ // Methods
+ virtual void Clear(void) {First = Last = NULL;}
+//virtual JTYP GetValType(void) {return TYPE_JOB;}
+ virtual PJPR GetFirst(void) {return First;}
+ virtual int GetSize(bool b);
+ virtual PJOB GetObject(void) {return this;}
+ virtual PSZ GetText(PGLOBAL g, PSTRG text);
+ virtual bool Merge(PGLOBAL g, PJSON jsp);
+ virtual bool IsNull(void);
+
+ // Specific
+ PJPR AddPair(PGLOBAL g, PCSZ key);
+ PJVAL GetKeyValue(const char* key);
+ PJAR GetKeyList(PGLOBAL g);
+ PJAR GetValList(PGLOBAL g);
+ void SetKeyValue(PGLOBAL g, PJVAL jvp, PCSZ key);
+ void DeleteKey(PCSZ k);
+
+ protected:
+ PJPR First;
+ PJPR Last;
+}; // end of class JOBJECT
+
+/***********************************************************************/
+/* Class JARRAY. */
+/***********************************************************************/
+class JARRAY : public JSON {
+ friend class SWAP;
+ public:
+ JARRAY(void);
+ JARRAY(int i) : JSON(i) {}
+
+ // Methods
+ virtual void Clear(void) {First = Last = NULL; Size = 0;}
+ virtual int size(void) { return Size; }
+ virtual PJAR GetArray(void) {return this;}
+ virtual int GetSize(bool b);
+ virtual PJVAL GetArrayValue(int i);
+ virtual PSZ GetText(PGLOBAL g, PSTRG text);
+ virtual bool Merge(PGLOBAL g, PJSON jsp);
+ virtual bool DeleteValue(int n);
+ virtual bool IsNull(void);
+
+ // Specific
+ PJVAL AddArrayValue(PGLOBAL g, PJVAL jvp = NULL, int* x = NULL);
+ void SetArrayValue(PGLOBAL g, PJVAL jvp, int i);
+ void InitArray(PGLOBAL g);
+
+ protected:
+ // Members
+ int Size; // The number of items in the array
+ int Alloc; // The Mvals allocated size
+ PJVAL First; // Used when constructing
+ PJVAL Last; // Last constructed value
+ PJVAL *Mvals; // Allocated when finished
+}; // end of class JARRAY
+
+/***********************************************************************/
+/* Class JVALUE. */
+/***********************************************************************/
+class JVALUE : public JSON {
+ friend class JARRAY;
+ friend class JSNX;
+ friend class JSONDISC;
+ friend class JSONCOL;
+ friend class JSON;
+ friend class JDOC;
+ friend class SWAP;
+public:
+ JVALUE(void) : JSON() { Type = TYPE_JVAL; Clear(); }
+ JVALUE(PJSON jsp);
+//JVALUE(PGLOBAL g, PVL vlp);
+ JVALUE(PGLOBAL g, PVAL valp);
+ JVALUE(PGLOBAL g, PCSZ strp);
+ JVALUE(int i) : JSON(i) {}
+
+ //using JSON::GetVal;
+ //using JSON::SetVal;
+
+ // Methods
+ virtual void Clear(void);
+//virtual JTYP GetType(void) {return TYPE_JVAL;}
+ virtual JTYP GetValType(void);
+ virtual PJOB GetObject(void);
+ virtual PJAR GetArray(void);
+ virtual PJSON GetJsp(void) {return (DataType == TYPE_JSON ? Jsp : NULL);}
+ virtual PSZ GetText(PGLOBAL g, PSTRG text);
+ virtual bool IsNull(void);
+
+ // Specific
+ //inline PVL GetVal(void) { return Val; }
+ //inline void SetVal(PVL vlp) { Val = vlp; }
+ inline PJSON GetJson(void) { return (DataType == TYPE_JSON ? Jsp : this); }
+ PSZ GetString(PGLOBAL g, char* buff = NULL);
+ int GetInteger(void);
+ long long GetBigint(void);
+ double GetFloat(void);
+ PVAL GetValue(PGLOBAL g);
+ void SetValue(PJSON jsp);
+ void SetValue(PGLOBAL g, PVAL valp);
+ void SetString(PGLOBAL g, PSZ s, int ci = 0);
+ void SetInteger(PGLOBAL g, int n);
+ void SetBigint(PGLOBAL g, longlong ll);
+ void SetFloat(PGLOBAL g, double f);
+ void SetBool(PGLOBAL g, bool b);
+
+ protected:
+ union {
+ PJSON Jsp; // To the json value
+ char *Strp; // Ptr to a string
+ int N; // An integer value
+ long long LLn; // A big integer value
+ double F; // A (double) float value
+ bool B; // True or false
+ };
+//PVL Val; // To the string or numeric value
+ PJVAL Next; // Next value in array
+ JTYP DataType; // The data value type
+ int Nd; // Decimal number
+ bool Del; // True when deleted
+}; // end of class JVALUE
+
+
+/***********************************************************************/
+/* Class JOUT. Used by Serialize. */
+/***********************************************************************/
+class JOUT : public BLOCK {
+public:
+ JOUT(PGLOBAL gp) : BLOCK() { g = gp; Pretty = 3; }
+
+ virtual bool WriteStr(const char* s) = 0;
+ virtual bool WriteChr(const char c) = 0;
+ virtual bool Escape(const char* s) = 0;
+ int Prty(void) { return Pretty; }
+
+ // Member
+ PGLOBAL g;
+ int Pretty;
+}; // end of class JOUT
+
+/***********************************************************************/
+/* Class JOUTSTR. Used to Serialize to a string. */
+/***********************************************************************/
+class JOUTSTR : public JOUT {
+public:
+ JOUTSTR(PGLOBAL g);
+
+ virtual bool WriteStr(const char* s);
+ virtual bool WriteChr(const char c);
+ virtual bool Escape(const char* s);
+
+ // Member
+ char* Strp; // The serialized string
+ size_t N; // Position of next char
+ size_t Max; // String max size
+}; // end of class JOUTSTR
+
+/***********************************************************************/
+/* Class JOUTFILE. Used to Serialize to a file. */
+/***********************************************************************/
+class JOUTFILE : public JOUT {
+public:
+ JOUTFILE(PGLOBAL g, FILE* str, int pty) : JOUT(g) { Stream = str; Pretty = pty; }
+
+ virtual bool WriteStr(const char* s);
+ virtual bool WriteChr(const char c);
+ virtual bool Escape(const char* s);
+
+ // Member
+ FILE* Stream;
+}; // end of class JOUTFILE
+
+/***********************************************************************/
+/* Class JOUTPRT. Used to Serialize to a pretty file. */
+/***********************************************************************/
+class JOUTPRT : public JOUTFILE {
+public:
+ JOUTPRT(PGLOBAL g, FILE* str) : JOUTFILE(g, str, 2) { M = 0; B = false; }
+
+ virtual bool WriteStr(const char* s);
+ virtual bool WriteChr(const char c);
+
+ // Member
+ int M;
+ bool B;
+}; // end of class JOUTPRT
+
+
+/***********************************************************************/
+/* Class SWAP. Used to make or unmake a JSON tree movable. */
+/* This is done by making all pointers to offsets. */
+/***********************************************************************/
+class SWAP : public BLOCK {
+public:
+ // Constructor
+ SWAP(PGLOBAL g, PJSON jsp)
+ {
+ G = g, Base = (char*)jsp - 8;
+ }
+
+ // Methods
+ void SwapJson(PJSON jsp, bool move);
+
+protected:
+ size_t MoffJson(PJSON jnp);
+ size_t MoffArray(PJAR jarp);
+ size_t MoffObject(PJOB jobp);
+ size_t MoffJValue(PJVAL jvp);
+ size_t MoffPair(PJPR jpp);
+//size_t MoffVal(PVL vlp);
+ PJSON MptrJson(PJSON jnp);
+ PJAR MptrArray(PJAR jarp);
+ PJOB MptrObject(PJOB jobp);
+ PJVAL MptrJValue(PJVAL jvp);
+ PJPR MptrPair(PJPR jpp);
+//PVL MptrVal(PVL vlp);
+
+ // Member
+ PGLOBAL G;
+ void *Base;
+}; // end of class SWAP
diff --git a/storage/connect/jsonudf.cpp b/storage/connect/jsonudf.cpp
new file mode 100644
index 00000000..8185be66
--- /dev/null
+++ b/storage/connect/jsonudf.cpp
@@ -0,0 +1,6646 @@
+/****************** jsonudf C++ Program Source Code File (.CPP) ******************/
+/* PROGRAM NAME: jsonudf Version 1.8 */
+/* (C) Copyright to the author Olivier BERTRAND 2015-2019 */
+/* This program are the JSON User Defined Functions . */
+/*********************************************************************************/
+
+/*********************************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/*********************************************************************************/
+#include <my_global.h>
+#include <mysqld.h>
+#include <mysql.h>
+#include <sql_error.h>
+#include <stdio.h>
+
+#include "jsonudf.h"
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#define _O_RDONLY O_RDONLY
+#endif
+
+#define MEMFIX 4096
+#if defined(connect_EXPORTS)
+#define PUSH_WARNING(M) push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0, M)
+#else
+#define PUSH_WARNING(M) htrc(M)
+#endif
+#define M 9
+
+static char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error);
+static char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error);
+static PJSON JsonNew(PGLOBAL g, JTYP type);
+static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp = NULL);
+static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len = 64);
+uint GetJsonGroupSize(void);
+static void SetChanged(PBSON bsp);
+
+uint JsonGrpSize = 10;
+
+/*********************************************************************************/
+/* SubAlloc a new JSNX class with protection against memory exhaustion. */
+/*********************************************************************************/
+static PJSNX JsnxNew(PGLOBAL g, PJSON jsp, int type, int len)
+{
+ PJSNX jsx;
+
+ try {
+ jsx = new(g) JSNX(g, jsp, type, len);
+ } catch (...) {
+ if (trace(1023))
+ htrc("%s\n", g->Message);
+
+ PUSH_WARNING(g->Message);
+ jsx = NULL;
+ } // end try/catch
+
+ return jsx;
+} /* end of JsnxNew */
+
+/* ----------------------------------- JSNX ------------------------------------ */
+
+/*********************************************************************************/
+/* JSNX public constructor. */
+/*********************************************************************************/
+JSNX::JSNX(PGLOBAL g, PJSON row, int type, int len, int prec, my_bool wr)
+{
+ Row = row;
+ Jvalp = NULL;
+ Jpnp = NULL;
+ Jp = NULL;
+ Nodes = NULL;
+ Value = AllocateValue(g, type, len, prec);
+ //MulVal = NULL;
+ Jpath = NULL;
+ Buf_Type = type;
+ Long = len;
+ Prec = prec;
+ Nod = 0;
+ Xnod = -1;
+ K = 0;
+ I = -1;
+ Imax = 9;
+ B = 0;
+ Xpd = false;
+ Parsed = false;
+ Found = false;
+ Wr = wr;
+ Jb = false;
+} // end of JSNX constructor
+
+/*********************************************************************************/
+/* SetJpath: set and parse the json path. */
+/*********************************************************************************/
+my_bool JSNX::SetJpath(PGLOBAL g, char *path, my_bool jb)
+{
+ // Check Value was allocated
+ if (!Value)
+ return true;
+
+ Value->SetNullable(true);
+ Jpath = path;
+
+ // Parse the json path
+ Parsed = false;
+ Nod = 0;
+ Jb = jb;
+ return ParseJpath(g);
+} // end of SetJpath
+
+/*********************************************************************************/
+/* Analyse array processing options. */
+/*********************************************************************************/
+my_bool JSNX::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
+{
+ int n = (int)strlen(p);
+ my_bool dg = true, b = false;
+ PJNODE jnp = &Nodes[i];
+
+ if (*p) {
+ if (p[n - 1] == ']') {
+ p[--n] = 0;
+ } else if (!IsNum(p)) {
+ // Wrong array specification
+ sprintf(g->Message, "Invalid array specification %s", p);
+ return true;
+ } // endif p
+
+ } else
+ b = true;
+
+ // To check whether a numeric Rank was specified
+ dg = IsNum(p);
+
+ if (!n) {
+ // Default specifications
+ if (jnp->Op != OP_EXP) {
+ if (Wr) {
+ // Force append
+ jnp->Rank = INT_MAX32;
+ jnp->Op = OP_LE;
+ } else if (Jb) {
+ // Return a Json item
+ jnp->Op = OP_XX;
+ } else if (b) {
+ // Return 1st value (B is the index base)
+ jnp->Rank = B;
+ jnp->Op = OP_LE;
+ } else if (!Value->IsTypeNum()) {
+ jnp->CncVal = AllocateValue(g, PlugDup(g, ", "), TYPE_STRING);
+ jnp->Op = OP_CNC;
+ } else
+ jnp->Op = OP_ADD;
+
+ } // endif OP
+
+ } else if (dg) {
+ // Return nth value
+ jnp->Rank = atoi(p) - B;
+ jnp->Op = OP_EQ;
+ } else if (Wr) {
+ sprintf(g->Message, "Invalid specification %s in a write path", p);
+ return true;
+ } else if (n == 1) {
+ // Set the Op value;
+ switch (*p) {
+ case '+': jnp->Op = OP_ADD; break;
+ case 'x': jnp->Op = OP_MULT; break;
+ case '>': jnp->Op = OP_MAX; break;
+ case '<': jnp->Op = OP_MIN; break;
+ case '!': jnp->Op = OP_SEP; break; // Average
+ case '#': jnp->Op = OP_NUM; break;
+ case '*': // Expand this array
+ strcpy(g->Message, "Expand not supported by this function");
+ return true;
+ default:
+ sprintf(g->Message, "Invalid function specification %c", *p);
+ return true;
+ } // endswitch *p
+
+ } else if (*p == '"' && p[n - 1] == '"') {
+ // This is a concat specification
+ jnp->Op = OP_CNC;
+
+ if (n > 2) {
+ // Set concat intermediate string
+ p[n - 1] = 0;
+
+ if (trace(1))
+ htrc("Concat string=%s\n", p + 1);
+
+ jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
+ } // endif n
+
+ } else {
+ strcpy(g->Message, "Wrong array specification");
+ return true;
+ } // endif's
+
+ return false;
+} // end of SetArrayOptions
+
+/*********************************************************************************/
+/* Parse the eventual passed Jpath information. */
+/* This information can be specified in the Fieldfmt column option when */
+/* creating the table. It permits to indicate the position of the node */
+/* corresponding to that column. */
+/*********************************************************************************/
+my_bool JSNX::ParseJpath(PGLOBAL g)
+{
+ char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL;
+ int i;
+ my_bool a;
+
+ if (Parsed)
+ return false; // Already done
+ else if (!Jpath)
+ // Jpath = Name;
+ return true;
+
+ if (trace(1))
+ htrc("ParseJpath %s\n", SVP(Jpath));
+
+ if (!(pbuf = PlgDBDup(g, Jpath)))
+ return true;
+
+ if (*pbuf == '$') pbuf++;
+ if (*pbuf == '.') pbuf++;
+ if (*pbuf == '[') p1 = pbuf++;
+
+ // Estimate the required number of nodes
+ for (i = 0, p = pbuf; (p = NextChr(p, '.')); i++, p++)
+ Nod++; // One path node found
+
+ if (!(Nodes = (PJNODE)PlgDBSubAlloc(g, NULL, (++Nod) * sizeof(JNODE))))
+ return true;
+
+ memset(Nodes, 0, (Nod)* sizeof(JNODE));
+
+ // Analyze the Jpath for this column
+ for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
+ a = (p1 != NULL);
+ p1 = strchr(p, '[');
+ p2 = strchr(p, '.');
+
+ if (!p2)
+ p2 = p1;
+ else if (p1) {
+ if (p1 < p2)
+ p2 = p1;
+ else if (p1 == p2 + 1)
+ *p2++ = 0; // Old syntax .[
+ else
+ p1 = NULL;
+
+ } // endif p1
+
+ if (p2)
+ *p2++ = 0;
+
+ // Jpath must be explicit
+ if (a || *p == 0 || *p == '[' || IsNum(p)) {
+ // Analyse intermediate array processing
+ if (SetArrayOptions(g, p, i, Nodes[i-1].Key))
+ return true;
+
+ } else if (*p == '*') {
+ if (Wr) {
+ sprintf(g->Message, "Invalid specification %c in a write path", *p);
+ return true;
+ } else // Return JSON
+ Nodes[i].Op = OP_XX;
+
+ } else {
+ Nodes[i].Key = p;
+ Nodes[i].Op = OP_EXIST;
+ } // endif's
+
+ } // endfor i, p
+
+ Nod = i;
+ //MulVal = AllocateValue(g, Value);
+
+ if (trace(1))
+ for (i = 0; i < Nod; i++)
+ htrc("Node(%d) Key=%s Op=%d Rank=%d\n",
+ i, SVP(Nodes[i].Key), Nodes[i].Op, Nodes[i].Rank);
+
+ Parsed = true;
+ return false;
+} // end of ParseJpath
+
+/*********************************************************************************/
+/* SetValue: Set a value from a JVALUE contains. */
+/*********************************************************************************/
+void JSNX::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val)
+{
+ if (val) {
+ vp->SetNull(false);
+
+ if (Jb) {
+ vp->SetValue_psz(Serialize(g, val->GetJsp(), NULL, 0));
+ Jb = false;
+ } else switch (val->GetValType()) {
+ case TYPE_DTM:
+ case TYPE_STRG:
+ vp->SetValue_psz(val->GetString(g));
+ break;
+ case TYPE_INTG:
+ vp->SetValue(val->GetInteger());
+ break;
+ case TYPE_BINT:
+ vp->SetValue(val->GetBigint());
+ break;
+ case TYPE_DBL:
+ if (vp->IsTypeNum())
+ vp->SetValue(val->GetFloat());
+ else // Get the proper number of decimals
+ vp->SetValue_psz(val->GetString(g));
+
+ break;
+ case TYPE_BOOL:
+ if (vp->IsTypeNum())
+ vp->SetValue(val->GetInteger() ? 1 : 0);
+ else
+ vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
+
+ break;
+ case TYPE_JAR:
+ vp->SetValue_psz(val->GetArray()->GetText(g, NULL));
+ break;
+ case TYPE_JOB:
+ vp->SetValue_psz(val->GetObject()->GetText(g, NULL));
+ break;
+ case TYPE_NULL:
+ vp->SetNull(true);
+ /* falls through */
+ default:
+ vp->Reset();
+ } // endswitch Type
+
+ } else {
+ vp->SetNull(true);
+ vp->Reset();
+ } // endif val
+
+} // end of SetJsonValue
+
+/*********************************************************************************/
+/* MakeJson: Serialize the json item and set value to it. */
+/*********************************************************************************/
+PJVAL JSNX::MakeJson(PGLOBAL g, PJSON jsp, int n)
+{
+ Jb = false;
+
+ if (Value->IsTypeNum()) {
+ strcpy(g->Message, "Cannot make Json for a numeric value");
+ return NULL;
+ } else if (jsp->GetType() != TYPE_JAR && jsp->GetType() != TYPE_JOB) {
+ strcpy(g->Message, "Target is not an array or object");
+ return NULL;
+ } else if (n < Nod -1) {
+ if (jsp->GetType() == TYPE_JAR) {
+ int ars = jsp->GetSize(false);
+ PJNODE jnp = &Nodes[n];
+ PJAR jarp = new(g) JARRAY;
+
+ jnp->Op = OP_EQ;
+
+ for (jnp->Rank = 0; jnp->Rank < ars; jnp->Rank++)
+ jarp->AddArrayValue(g, GetRowValue(g, jsp, n));
+
+ jarp->InitArray(g);
+ jnp->Op = OP_XX;
+ jnp->Rank = 0;
+ jsp = jarp;
+ } else if(jsp->GetType() == TYPE_JOB) {
+ PJSON jp;
+ PJOB jobp = new(g) JOBJECT;
+
+ for (PJPR prp = ((PJOB)jsp)->GetFirst(); prp; prp = prp->Next) {
+ jp = (prp->Val->DataType == TYPE_JSON) ? prp->Val->Jsp : prp->Val;
+ jobp->SetKeyValue(g, GetRowValue(g, jp, n + 1), prp->Key);
+ } // endfor prp
+
+ jsp = jobp;
+ } // endif Type
+
+ } // endif
+
+ Jb = true;
+ return new(g) JVALUE(jsp);
+} // end of MakeJson
+
+/*********************************************************************************/
+/* GetJson: */
+/*********************************************************************************/
+PJVAL JSNX::GetJson(PGLOBAL g)
+{
+ return GetRowValue(g, Row, 0);
+} // end of GetJson
+
+/*********************************************************************************/
+/* ReadValue: */
+/*********************************************************************************/
+void JSNX::ReadValue(PGLOBAL g)
+{
+ Value->SetValue_pval(GetColumnValue(g, Row, 0));
+} // end of ReadValue
+
+/*********************************************************************************/
+/* GetColumnValue: */
+/*********************************************************************************/
+PVAL JSNX::GetColumnValue(PGLOBAL g, PJSON row, int i)
+{
+ PJVAL val = NULL;
+
+ val = GetRowValue(g, row, i);
+ SetJsonValue(g, Value, val);
+ return Value;
+} // end of GetColumnValue
+
+/*********************************************************************************/
+/* GetRowValue: */
+/*********************************************************************************/
+PJVAL JSNX::GetRowValue(PGLOBAL g, PJSON row, int i, my_bool b)
+{
+ PJAR arp;
+ PJVAL val = NULL;
+
+ for (; i < Nod && row; i++) {
+ if (Nodes[i].Op == OP_NUM) {
+ Value->SetValue(row->GetType() == TYPE_JAR ? ((PJAR)row)->size() : 1);
+ val = new(g) JVALUE(g, Value);
+ return val;
+ } else if (Nodes[i].Op == OP_XX) {
+ return MakeJson(g, row, i);
+ } else switch (row->GetType()) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key) {
+ // Expected Array was not there
+ if (Nodes[i].Op == OP_LE) {
+ if (i < Nod-1)
+ continue;
+ else
+ val = new(g)JVALUE(row);
+
+ } else {
+ strcpy(g->Message, "Unexpected object");
+ val = NULL;
+ } //endif Op
+
+ } else
+ val = ((PJOB)row)->GetKeyValue(Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ arp = (PJAR)row;
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
+ val = arp->GetArrayValue(Nodes[i].Rank);
+ else if (Nodes[i].Op == OP_EXP)
+ return (PJVAL)ExpandArray(g, arp, i);
+ else
+ return new(g) JVALUE(g, CalculateArray(g, arp, i));
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ val = arp->GetArrayValue(0);
+ i--;
+ } // endif's
+
+ break;
+ case TYPE_JVAL:
+ val = (PJVAL)row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+ val = NULL;
+ } // endswitch Type
+
+ if (i < Nod-1)
+ if (!(row = (val) ? val->GetJsp() : NULL))
+ val = NULL;
+// row = (val) ? val->GetJson() : NULL;
+
+ } // endfor i
+
+ // SetJsonValue(g, Value, val);
+ return val;
+} // end of GetRowValue
+
+/*********************************************************************************/
+/* ExpandArray: */
+/*********************************************************************************/
+PVAL JSNX::ExpandArray(PGLOBAL g, PJAR arp, int n)
+{
+ strcpy(g->Message, "Expand cannot be done by this function");
+ return NULL;
+} // end of ExpandArray
+
+/*********************************************************************************/
+/* Get the value used for calculating the array. */
+/*********************************************************************************/
+PVAL JSNX::GetCalcValue(PGLOBAL g, PJAR jap, int n)
+{
+ // For calculated arrays, a local Value must be used
+ int lng = 0;
+ short type= 0, prec= 0;
+ bool b = n < Nod - 1;
+ PVAL valp;
+ PJVAL vlp, vp;
+ OPVAL op = Nodes[n].Op;
+
+ switch (op) {
+ case OP_NUM:
+ type = TYPE_INT;
+ break;
+ case OP_ADD:
+ case OP_MULT:
+ if (!IsTypeNum(Buf_Type)) {
+ type = TYPE_INT;
+ prec = 0;
+
+ for (vlp = jap->GetArrayValue(0); vlp; vlp = vlp->Next) {
+ vp = (b && vlp->GetJsp()) ? GetRowValue(g, vlp, n + 1) : vlp;
+
+ switch (vp->DataType) {
+ case TYPE_BINT:
+ if (type == TYPE_INT)
+ type = TYPE_BIGINT;
+
+ break;
+ case TYPE_DBL:
+ case TYPE_FLOAT:
+ type = TYPE_DOUBLE;
+ prec = MY_MAX(prec, vp->Nd);
+ break;
+ default:
+ break;
+ } // endswitch Type
+
+ } // endfor vlp
+
+ } else {
+ type = Buf_Type;
+ prec = GetPrecision();
+ } // endif Buf_Type
+
+ break;
+ case OP_SEP:
+ if (IsTypeChar(Buf_Type)) {
+ type = TYPE_DOUBLE;
+ prec = 2;
+ } else {
+ type = Buf_Type;
+ prec = GetPrecision();
+ } // endif Buf_Type
+
+ break;
+ case OP_MIN:
+ case OP_MAX:
+ type = Buf_Type;
+ lng = Long;
+ prec = GetPrecision();
+ break;
+ case OP_CNC:
+ type = TYPE_STRING;
+
+ if (IsTypeChar(Buf_Type)) {
+ lng = (Long) ? Long : 512;
+ prec = GetPrecision();
+ } else
+ lng = 512;
+
+ break;
+ default:
+ break;
+ } // endswitch Op
+
+ return valp = AllocateValue(g, type, lng, prec);
+} // end of GetCalcValue
+
+/*********************************************************************************/
+/* CalculateArray: */
+/*********************************************************************************/
+PVAL JSNX::CalculateArray(PGLOBAL g, PJAR arp, int n)
+{
+ int i, ars = arp->size(), nv = 0;
+ bool err;
+ OPVAL op = Nodes[n].Op;
+ PVAL val[2], vp = GetCalcValue(g, arp, n);
+ PVAL mulval = AllocateValue(g, vp);
+ PJVAL jvrp, jvp;
+ JVALUE jval;
+
+ vp->Reset();
+
+ if (trace(1))
+ htrc("CalculateArray size=%d op=%d\n", ars, op);
+
+ for (i = 0; i < ars; i++) {
+ jvrp = arp->GetArrayValue(i);
+
+ if (trace(1))
+ htrc("i=%d nv=%d\n", i, nv);
+
+ if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) {
+ if (jvrp->IsNull()) {
+ jvrp->SetString(g, GetJsonNull(), 0);
+ jvp = jvrp;
+ } else if (n < Nod - 1 && jvrp->GetJson()) {
+ jval.SetValue(g, GetColumnValue(g, jvrp->GetJson(), n + 1));
+ jvp = &jval;
+ } else
+ jvp = jvrp;
+
+ if (trace(1))
+ htrc("jvp=%s null=%d\n",
+ jvp->GetString(g), jvp->IsNull() ? 1 : 0);
+
+ if (!nv++) {
+ SetJsonValue(g, vp, jvp);
+ continue;
+ } else
+ SetJsonValue(g, mulval, jvp);
+
+ if (!mulval->IsNull()) {
+ switch (op) {
+ case OP_CNC:
+ if (Nodes[n].CncVal) {
+ val[0] = Nodes[n].CncVal;
+ err = vp->Compute(g, val, 1, op);
+ } // endif CncVal
+
+ val[0] = mulval;
+ err = vp->Compute(g, val, 1, op);
+ break;
+// case OP_NUM:
+ case OP_SEP:
+ val[0] = vp;
+ val[1] = mulval;
+ err = vp->Compute(g, val, 2, OP_ADD);
+ break;
+ default:
+ val[0] = vp;
+ val[1] = mulval;
+ err = vp->Compute(g, val, 2, op);
+ } // endswitch Op
+
+ if (err)
+ vp->Reset();
+
+ if (trace(1)) {
+ char buf(32);
+
+ htrc("vp='%s' err=%d\n",
+ vp->GetCharString(&buf), err ? 1 : 0);
+ } // endif trace
+
+ } // endif Zero
+
+ } // endif jvrp
+
+ } // endfor i
+
+ if (op == OP_SEP) {
+ // Calculate average
+ mulval->SetValue(nv);
+ val[0] = vp;
+ val[1] = mulval;
+
+ if (vp->Compute(g, val, 2, OP_DIV))
+ vp->Reset();
+
+ } // endif Op
+
+ return vp;
+} // end of CalculateArray
+
+/*********************************************************************************/
+/* CheckPath: Checks whether the path exists in the document. */
+/*********************************************************************************/
+my_bool JSNX::CheckPath(PGLOBAL g)
+{
+ PJVAL val= NULL;
+ PJSON row = Row;
+
+ for (int i = 0; i < Nod && row; i++) {
+ val = NULL;
+
+ if (Nodes[i].Op == OP_NUM || Nodes[i].Op == OP_XX) {
+ } else switch (row->GetType()) {
+ case TYPE_JOB:
+ if (Nodes[i].Key)
+ val = ((PJOB)row)->GetKeyValue(Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ if (!Nodes[i].Key)
+ if (Nodes[i].Op == OP_EQ || Nodes[i].Op == OP_LE)
+ val = ((PJAR)row)->GetArrayValue(Nodes[i].Rank);
+
+ break;
+ case TYPE_JVAL:
+ val = (PJVAL)row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+ } // endswitch Type
+
+ if (i < Nod-1)
+ if (!(row = (val) ? val->GetJsp() : NULL))
+ val = NULL;
+
+ } // endfor i
+
+ return (val != NULL);
+} // end of CheckPath
+
+/***********************************************************************/
+/* GetRow: Set the complete path of the object to be set. */
+/***********************************************************************/
+PJSON JSNX::GetRow(PGLOBAL g)
+{
+ PJVAL val = NULL;
+ PJAR arp;
+ PJSON nwr, row = Row;
+
+ for (int i = 0; i < Nod - 1 && row; i++) {
+ if (Nodes[i].Op == OP_XX)
+ break;
+ else switch (row->GetType()) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key)
+ // Expected Array was not there, wrap the value
+ continue;
+
+ val = ((PJOB)row)->GetKeyValue(Nodes[i].Key);
+ break;
+ case TYPE_JAR:
+ arp = (PJAR)row;
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EQ)
+ val = arp->GetArrayValue(Nodes[i].Rank);
+ else
+ val = arp->GetArrayValue(Nodes[i].Rx);
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ val = arp->GetArrayValue(0);
+ i--;
+ } // endif Nodes
+
+ break;
+ case TYPE_JVAL:
+ val = (PJVAL)row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+ val = NULL;
+ } // endswitch Type
+
+ if (val) {
+ row = val->GetJson();
+ } else {
+ // Construct missing objects
+ for (i++; row && i < Nod; i++) {
+ if (Nodes[i].Op == OP_XX)
+ break;
+ else if (!Nodes[i].Key)
+ // Construct intermediate array
+ nwr = new(g)JARRAY;
+ else
+ nwr = new(g)JOBJECT;
+
+ if (row->GetType() == TYPE_JOB) {
+ ((PJOB)row)->SetKeyValue(g, new(g)JVALUE(nwr), Nodes[i-1].Key);
+ } else if (row->GetType() == TYPE_JAR) {
+ ((PJAR)row)->AddArrayValue(g, new(g)JVALUE(nwr));
+ ((PJAR)row)->InitArray(g);
+ } else {
+ strcpy(g->Message, "Wrong type when writing new row");
+ nwr = NULL;
+ } // endif's
+
+ row = nwr;
+ } // endfor i
+
+ break;
+ } // endelse
+
+ } // endfor i
+
+ return row;
+} // end of GetRow
+
+/***********************************************************************/
+/* WriteValue: */
+/***********************************************************************/
+my_bool JSNX::WriteValue(PGLOBAL g, PJVAL jvalp)
+{
+ PJOB objp = NULL;
+ PJAR arp = NULL;
+ PJVAL jvp = NULL;
+ PJSON row = GetRow(g);
+
+ if (!row)
+ return true;
+
+ switch (row->GetType()) {
+ case TYPE_JOB: objp = (PJOB)row; break;
+ case TYPE_JAR: arp = (PJAR)row; break;
+ case TYPE_JVAL: jvp = (PJVAL)row; break;
+ default:
+ strcpy(g->Message, "Invalid target type");
+ return true;
+ } // endswitch Type
+
+ if (arp) {
+ if (!Nodes[Nod-1].Key) {
+ if (Nodes[Nod-1].Op == OP_EQ)
+ arp->SetArrayValue(g, jvalp, Nodes[Nod-1].Rank);
+ else
+ arp->AddArrayValue(g, jvalp);
+
+ arp->InitArray(g);
+ } // endif Key
+
+ } else if (objp) {
+ if (Nodes[Nod-1].Key)
+ objp->SetKeyValue(g, jvalp, Nodes[Nod-1].Key);
+
+ } else if (jvp)
+ jvp->SetValue(jvalp);
+
+ return false;
+} // end of WriteValue
+
+/*********************************************************************************/
+/* Locate a value in a JSON tree: */
+/*********************************************************************************/
+PSZ JSNX::Locate(PGLOBAL g, PJSON jsp, PJVAL jvp, int k)
+{
+ PSZ str = NULL;
+ my_bool err = true;
+
+ g->Message[0] = 0;
+
+ if (!jsp) {
+ strcpy(g->Message, "Null json tree");
+ return NULL;
+ } // endif jsp
+
+ try {
+ // Write to the path string
+ Jp = new(g) JOUTSTR(g);
+ Jp->WriteChr('$');
+ Jvalp = jvp;
+ K = k;
+
+ switch (jsp->GetType()) {
+ case TYPE_JAR:
+ err = LocateArray(g, (PJAR)jsp);
+ break;
+ case TYPE_JOB:
+ err = LocateObject(g, (PJOB)jsp);
+ break;
+ case TYPE_JVAL:
+ err = LocateValue(g, (PJVAL)jsp);
+ break;
+ default:
+ err = true;
+ } // endswitch Type
+
+ if (err) {
+ if (!g->Message[0])
+ strcpy(g->Message, "Invalid json tree");
+
+ } else if (Found) {
+ Jp->WriteChr('\0');
+ PlugSubAlloc(g, NULL, Jp->N);
+ str = Jp->Strp;
+ } // endif's
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+ return str;
+} // end of Locate
+
+/*********************************************************************************/
+/* Locate in a JSON Array. */
+/*********************************************************************************/
+my_bool JSNX::LocateArray(PGLOBAL g, PJAR jarp)
+{
+ char s[16];
+ size_t m = Jp->N;
+
+ for (int i = 0; i < jarp->size() && !Found; i++) {
+ Jp->N = m;
+ sprintf(s, "[%d]", i + B);
+
+ if (Jp->WriteStr(s))
+ return true;
+
+ if (LocateValue(g, jarp->GetArrayValue(i)))
+ return true;
+
+ } // endfor i
+
+ return false;
+} // end of LocateArray
+
+/*********************************************************************************/
+/* Locate in a JSON Object. */
+/*********************************************************************************/
+my_bool JSNX::LocateObject(PGLOBAL g, PJOB jobp)
+{
+ size_t m;
+
+ if (Jp->WriteChr('.'))
+ return true;
+
+ m = Jp->N;
+
+ for (PJPR pair = jobp->First; pair && !Found; pair = pair->Next) {
+ Jp->N = m;
+
+ if (Jp->WriteStr(pair->Key))
+ return true;
+
+ if (LocateValue(g, pair->Val))
+ return true;
+
+ } // endfor i
+
+ return false;
+} // end of LocateObject
+
+/*********************************************************************************/
+/* Locate a JSON Value. */
+/*********************************************************************************/
+my_bool JSNX::LocateValue(PGLOBAL g, PJVAL jvp)
+{
+ if (CompareTree(g, Jvalp, jvp))
+ Found = (--K == 0);
+ else if (jvp->GetArray())
+ return LocateArray(g, jvp->GetArray());
+ else if (jvp->GetObject())
+ return LocateObject(g, jvp->GetObject());
+
+ return false;
+} // end of LocateValue
+
+/*********************************************************************************/
+/* Locate all occurrences of a value in a JSON tree: */
+/*********************************************************************************/
+PSZ JSNX::LocateAll(PGLOBAL g, PJSON jsp, PJVAL jvp, int mx)
+{
+ PSZ str = NULL;
+ my_bool err = true;
+ PJPN jnp;
+
+ if (!jsp) {
+ strcpy(g->Message, "Null json tree");
+ return NULL;
+ } // endif jsp
+
+ try {
+ jnp = (PJPN)PlugSubAlloc(g, NULL, sizeof(JPN) * mx);
+ memset(jnp, 0, sizeof(JPN) * mx);
+ g->Message[0] = 0;
+
+ // Write to the path string
+ Jp = new(g)JOUTSTR(g);
+ Jvalp = jvp;
+ Imax = mx - 1;
+ Jpnp = jnp;
+ Jp->WriteChr('[');
+
+ switch (jsp->GetType()) {
+ case TYPE_JAR:
+ err = LocateArrayAll(g, (PJAR)jsp);
+ break;
+ case TYPE_JOB:
+ err = LocateObjectAll(g, (PJOB)jsp);
+ break;
+ case TYPE_JVAL:
+ err = LocateValueAll(g, (PJVAL)jsp);
+ break;
+ default:
+ err = true;
+ } // endswitch Type
+
+ if (!err) {
+ if (Jp->N > 1)
+ Jp->N--;
+
+ Jp->WriteChr(']');
+ Jp->WriteChr('\0');
+ PlugSubAlloc(g, NULL, Jp->N);
+ str = Jp->Strp;
+ } else if (!g->Message[0])
+ strcpy(g->Message, "Invalid json tree");
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+ return str;
+} // end of LocateAll
+
+/*********************************************************************************/
+/* Locate in a JSON Array. */
+/*********************************************************************************/
+my_bool JSNX::LocateArrayAll(PGLOBAL g, PJAR jarp)
+{
+ if (I < Imax) {
+ Jpnp[++I].Type = TYPE_JAR;
+
+ for (int i = 0; i < jarp->size(); i++) {
+ Jpnp[I].N = i;
+
+ if (LocateValueAll(g, jarp->GetArrayValue(i)))
+ return true;
+
+ } // endfor i
+
+ I--;
+ } // endif I
+
+ return false;
+} // end of LocateArrayAll
+
+/*********************************************************************************/
+/* Locate in a JSON Object. */
+/*********************************************************************************/
+my_bool JSNX::LocateObjectAll(PGLOBAL g, PJOB jobp)
+{
+ if (I < Imax) {
+ Jpnp[++I].Type = TYPE_JOB;
+
+ for (PJPR pair = jobp->First; pair; pair = pair->Next) {
+ Jpnp[I].Key = pair->Key;
+
+ if (LocateValueAll(g, pair->Val))
+ return true;
+
+ } // endfor i
+
+ I--;
+ } // endif I
+
+ return false;
+} // end of LocateObjectAll
+
+/*********************************************************************************/
+/* Locate a JSON Value. */
+/*********************************************************************************/
+my_bool JSNX::LocateValueAll(PGLOBAL g, PJVAL jvp)
+{
+ if (CompareTree(g, Jvalp, jvp))
+ return AddPath();
+ else if (jvp->GetArray())
+ return LocateArrayAll(g, jvp->GetArray());
+ else if (jvp->GetObject())
+ return LocateObjectAll(g, jvp->GetObject());
+
+ return false;
+} // end of LocateValueAll
+
+/*********************************************************************************/
+/* Compare two JSON trees. */
+/*********************************************************************************/
+my_bool JSNX::CompareTree(PGLOBAL g, PJSON jp1, PJSON jp2)
+{
+ if (!jp1 || !jp2 || jp1->GetType() != jp2->GetType()
+ || jp1->size() != jp2->size())
+ return false;
+
+ my_bool found = true;
+
+ if (jp1->GetType() == TYPE_JVAL) {
+// PVL v1 = ((PJVAL)jp1)->GetVal(), v2 = ((PJVAL)jp2)->GetVal();
+
+ if (((PJVAL)jp1)->DataType == TYPE_JSON && ((PJVAL)jp2)->DataType == TYPE_JSON)
+ found = CompareTree(g, jp1->GetJsp(), jp2->GetJsp());
+ else
+ found = CompareValues(((PJVAL)jp1), ((PJVAL)jp2));
+
+ } else if (jp1->GetType() == TYPE_JAR) {
+ for (int i = 0; found && i < jp1->size(); i++)
+ found = (CompareTree(g, jp1->GetArrayValue(i), jp2->GetArrayValue(i)));
+
+ } else if (jp1->GetType() == TYPE_JOB) {
+ PJPR p1 = jp1->GetFirst(), p2 = jp2->GetFirst();
+
+ for (; found && p1 && p2; p1 = p1->Next, p2 = p2->Next)
+ found = CompareTree(g, p1->Val, p2->Val);
+
+ } else
+ found = false;
+
+ return found;
+} // end of CompareTree
+
+/*********************************************************************************/
+/* Compare two VAL values and return true if they are equal. */
+/*********************************************************************************/
+my_bool JSNX::CompareValues(PJVAL v1, PJVAL v2)
+{
+ my_bool b = false;
+
+ switch (v1->DataType) {
+ case TYPE_STRG:
+ if (v2->DataType == TYPE_STRG) {
+ if (v1->Nd || v2->Nd) // Case insensitive
+ b = (!stricmp(v1->Strp, v2->Strp));
+ else
+ b = (!strcmp(v1->Strp, v2->Strp));
+
+ } // endif Type
+
+ break;
+ case TYPE_DTM:
+ if (v2->DataType == TYPE_DTM)
+ b = (!strcmp(v1->Strp, v2->Strp));
+
+ break;
+ case TYPE_INTG:
+ if (v2->DataType == TYPE_INTG)
+ b = (v1->N == v2->N);
+ else if (v2->DataType == TYPE_BINT)
+ b = (v1->N == v2->LLn);
+
+ break;
+ case TYPE_BINT:
+ if (v2->DataType == TYPE_INTG)
+ b = (v1->LLn == v2->N);
+ else if (v2->DataType == TYPE_BINT)
+ b = (v1->LLn == v2->LLn);
+
+ break;
+ case TYPE_DBL:
+ if (v2->DataType == TYPE_DBL)
+ b = (v1->F == v2->F);
+
+ break;
+ case TYPE_BOOL:
+ if (v2->DataType == TYPE_BOOL)
+ b = (v1->B == v2->B);
+
+ break;
+ case TYPE_NULL:
+ if (v2->DataType == TYPE_NULL)
+ b = true;
+
+ break;
+ default:
+ break;
+ } // endswitch Type
+
+ return b;
+} // end of CompareValues
+
+/*********************************************************************************/
+/* Add the found path to the list. */
+/*********************************************************************************/
+my_bool JSNX::AddPath(void) {
+ char s[16];
+
+ if (Jp->WriteStr("\"$"))
+ return true;
+
+ for (int i = 0; i <= I; i++) {
+ if (Jpnp[i].Type == TYPE_JAR) {
+ sprintf(s, "[%d]", Jpnp[i].N + B);
+
+ if (Jp->WriteStr(s))
+ return true;
+
+ } else {
+ if (Jp->WriteChr('.'))
+ return true;
+
+ if (Jp->WriteStr(Jpnp[i].Key))
+ return true;
+
+ } // endif's
+
+ } // endfor i
+
+ if (Jp->WriteStr("\","))
+ return true;
+
+ return false;
+} // end of AddPath
+
+/* --------------------------------- JSON UDF ---------------------------------- */
+
+/*********************************************************************************/
+/* Allocate and initialize a BSON structure. */
+/*********************************************************************************/
+PBSON JbinAlloc(PGLOBAL g, UDF_ARGS *args, ulong len, PJSON jsp)
+{
+ PBSON bsp = (PBSON)PlgDBSubAlloc(g, NULL, sizeof(BSON));
+
+ if (bsp) {
+ strcpy(bsp->Msg, "Binary Json");
+ bsp->Msg[BMX] = 0;
+ bsp->Filename = NULL;
+ bsp->G = g;
+ bsp->Pretty = 2;
+ bsp->Reslen = len;
+ bsp->Changed = false;
+ bsp->Top = bsp->Jsp = jsp;
+ bsp->Bsp = (args && IsJson(args, 0) == 3) ? (PBSON)args->args[0] : NULL;
+ } else
+ PUSH_WARNING(g->Message);
+
+ return bsp;
+} /* end of JbinAlloc */
+
+/*********************************************************************************/
+/* Set the BSON chain as changed. */
+/*********************************************************************************/
+static void SetChanged(PBSON bsp)
+{
+ if (bsp->Bsp)
+ SetChanged(bsp->Bsp);
+
+ bsp->Changed = true;
+} /* end of SetChanged */
+
+/*********************************************************************************/
+/* Replaces GetJsonGrpSize not usable when CONNECT is not installed. */
+/*********************************************************************************/
+uint GetJsonGroupSize(void)
+{
+ return (JsonGrpSize) ? JsonGrpSize : GetJsonGrpSize();
+} // end of GetJsonGroupSize
+
+/*********************************************************************************/
+/* Program for SubSet re-initialization of the memory pool. */
+/*********************************************************************************/
+my_bool JsonSubSet(PGLOBAL g, my_bool b)
+{
+ PPOOLHEADER pph = (PPOOLHEADER)g->Sarea;
+
+ pph->To_Free = (g->Saved_Size) ? g->Saved_Size : sizeof(POOLHEADER);
+ pph->FreeBlk = g->Sarea_Size - pph->To_Free;
+
+ if (b)
+ g->Saved_Size = 0;
+
+ return FALSE;
+} /* end of JsonSubSet */
+
+/*********************************************************************************/
+/* Program for saving the status of the memory pools. */
+/*********************************************************************************/
+inline void JsonMemSave(PGLOBAL g)
+{
+ g->Saved_Size = ((PPOOLHEADER)g->Sarea)->To_Free;
+} /* end of JsonMemSave */
+
+/*********************************************************************************/
+/* Program for freeing the memory pools. */
+/*********************************************************************************/
+inline void JsonFreeMem(PGLOBAL g)
+{
+ g->Activityp = NULL;
+ g = PlugExit(g);
+} /* end of JsonFreeMem */
+
+/*********************************************************************************/
+/* SubAlloc a new JSON item with protection against memory exhaustion. */
+/*********************************************************************************/
+static PJSON JsonNew(PGLOBAL g, JTYP type)
+{
+ PJSON jsp = NULL;
+
+ try {
+ switch (type) {
+ case TYPE_JAR:
+ jsp = new(g) JARRAY;
+ break;
+ case TYPE_JOB:
+ jsp = new(g) JOBJECT;
+ break;
+ default:
+ break;
+ } // endswitch type
+
+ } catch (...) {
+ if (trace(1023))
+ htrc("%s\n", g->Message);
+
+ PUSH_WARNING(g->Message);
+ } // end try/catch
+
+ return jsp;
+} /* end of JsonNew */
+
+/*********************************************************************************/
+/* SubAlloc a new JValue with protection against memory exhaustion. */
+/*********************************************************************************/
+static PJVAL JvalNew(PGLOBAL g, JTYP type, void *vp)
+{
+ PJVAL jvp = NULL;
+
+ try {
+ if (!vp)
+ jvp = new (g) JVALUE;
+ else switch (type) {
+ case TYPE_JSON:
+ case TYPE_JVAL:
+ case TYPE_JAR:
+ case TYPE_JOB:
+ jvp = new(g) JVALUE((PJSON)vp);
+ break;
+// case TYPE_VAL:
+// jvp = new(g) JVALUE(g, (PVAL)vp);
+// break;
+ case TYPE_DTM:
+ case TYPE_STRG:
+ jvp = new(g) JVALUE(g, (PCSZ)vp);
+ break;
+ default:
+ break;
+ } // endswitch type
+
+ } catch (...) {
+ if (trace(1023))
+ htrc("%s\n", g->Message);
+
+ PUSH_WARNING(g->Message);
+ } // end try/catch
+
+ return jvp;
+} /* end of JvalNew */
+
+/*********************************************************************************/
+/* Allocate and initialise the memory area. */
+/*********************************************************************************/
+my_bool JsonInit(UDF_INIT *initid, UDF_ARGS *args, char *message, my_bool mbn,
+ unsigned long reslen, unsigned long memlen, unsigned long more)
+{
+ PGLOBAL g = PlugInit(NULL, (size_t)memlen + more + 500); // +500 to avoid CheckMem
+
+ if (!g) {
+ strcpy(message, "Allocation error");
+ return true;
+ } else if (g->Sarea_Size == 0) {
+ strcpy(message, g->Message);
+ g = PlugExit(g);
+ return true;
+ } // endif g
+
+ g->Mrr = (args->arg_count && args->args[0]) ? 1 : 0;
+ g->More = more;
+ initid->maybe_null = mbn;
+ initid->max_length = reslen;
+ initid->ptr = (char*)g;
+ return false;
+} // end of JsonInit
+
+/*********************************************************************************/
+/* Check if a path was specified and set jvp according to it. */
+/*********************************************************************************/
+static my_bool CheckPath(PGLOBAL g, UDF_ARGS *args, PJSON jsp, PJVAL& jvp, int n)
+{
+ for (uint i = n; i < args->arg_count; i++)
+ if (args->arg_type[i] == STRING_RESULT && args->args[i]) {
+ // A path to a subset of the json tree is given
+ char *path = MakePSZ(g, args, i);
+
+ if (path) {
+ PJSNX jsx = new(g)JSNX(g, jsp, TYPE_STRING);
+
+ if (jsx->SetJpath(g, path))
+ return true;
+
+ if (!(jvp = jsx->GetJson(g))) {
+ sprintf(g->Message, "No sub-item at '%s'", path);
+ return true;
+ } // endif jvp
+
+ } else {
+ strcpy(g->Message, "Path argument is null");
+ return true;
+ } // endif path
+
+ break;
+ } // endif type
+
+ return false;
+} // end of CheckPath
+
+/*********************************************************************************/
+/* Make the result according to the first argument type. */
+/*********************************************************************************/
+static char *MakeResult(PGLOBAL g, UDF_ARGS *args, PJSON top, uint n = 2)
+{
+ char *str;
+
+ if (IsJson(args, 0) == 2) {
+ // Make the change in the json file
+ int pretty = 2;
+
+ for (uint i = n; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT) {
+ pretty = (int)*(longlong*)args->args[i];
+ break;
+ } // endif type
+
+ if (!Serialize(g, top, MakePSZ(g, args, 0), pretty))
+ PUSH_WARNING(g->Message);
+
+ str = NULL;
+ } else if (IsJson(args, 0) == 3) {
+ PBSON bsp = (PBSON)args->args[0];
+
+ if (bsp->Filename) {
+ // Make the change in the json file
+ if (!Serialize(g, top, bsp->Filename, bsp->Pretty))
+ PUSH_WARNING(g->Message);
+
+ str = bsp->Filename;
+ } else if (!(str = Serialize(g, top, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ SetChanged(bsp);
+ } else if (!(str = Serialize(g, top, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ return str;
+} // end of MakeResult
+
+/*********************************************************************************/
+/* Make the binary result according to the first argument type. */
+/*********************************************************************************/
+static PBSON MakeBinResult(PGLOBAL g, UDF_ARGS *args, PJSON top, ulong len, int n = 2)
+{
+ PBSON bsnp = JbinAlloc(g, args, len, top);
+
+ if (!bsnp)
+ return NULL;
+
+ if (IsJson(args, 0) == 2) {
+ int pretty = 0;
+
+ for (uint i = n; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT) {
+ pretty = (int)*(longlong*)args->args[i];
+ break;
+ } // endif type
+
+ bsnp->Pretty = pretty;
+
+ if ((bsnp->Filename = (char*)args->args[0])) {
+ bsnp->Filename = MakePSZ(g, args, 0);
+ strncpy(bsnp->Msg, bsnp->Filename, BMX);
+ } else
+ strncpy(bsnp->Msg, "null filename", BMX);
+
+ } else if (IsJson(args, 0) == 3) {
+ PBSON bsp = (PBSON)args->args[0];
+
+ if (bsp->Filename) {
+ bsnp->Filename = bsp->Filename;
+ strncpy(bsnp->Msg, bsp->Filename, BMX);
+ bsnp->Pretty = bsp->Pretty;
+ } else
+ strcpy(bsnp->Msg, "Json Binary item");
+
+ } else
+ strcpy(bsnp->Msg, "Json Binary item");
+
+ return bsnp;
+} // end of MakeBinResult
+
+/*********************************************************************************/
+/* Returns a pointer to the first integer argument found from the nth argument. */
+/*********************************************************************************/
+static int *GetIntArgPtr(PGLOBAL g, UDF_ARGS *args, uint& n)
+{
+ int *x = NULL;
+
+ for (uint i = n; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT) {
+ if (args->args[i]) {
+ if ((x = (int*)PlgDBSubAlloc(g, NULL, sizeof(int))))
+ *x = (int)*(longlong*)args->args[i];
+ else
+ PUSH_WARNING(g->Message);
+
+ } // endif args
+
+ n = i + 1;
+ break;
+ } // endif arg_type
+
+ return x;
+} // end of GetIntArgPtr
+
+/*********************************************************************************/
+/* Returns not 0 if the argument is a JSON item or file name. */
+/*********************************************************************************/
+int IsJson(UDF_ARGS *args, uint i, bool b)
+{
+ const char *pat = args->attributes[i];
+ int n = 0;
+
+ if (*pat == '@') {
+ pat++;
+
+ if (*pat == '\'' || *pat == '"')
+ pat++;
+
+ } // endif pat
+
+ if (i >= args->arg_count || args->arg_type[i] != STRING_RESULT) {
+ } else if (!strnicmp(pat, "Json_", 5)) {
+ if (!args->args[i] || strchr("[{ \t\r\n", *args->args[i]))
+ n = 1; // arg should be is a json item
+ else
+ n = 2; // A file name may have been returned
+
+ } else if (!strnicmp(pat, "Jbin_", 5)) {
+ if (args->lengths[i] == sizeof(BSON))
+ n = 3; // arg is a binary json item
+ else
+ n = 2; // A file name may have been returned
+
+ } else if (!strnicmp(pat, "Jfile_", 6)) {
+ n = 2; // arg is a json file name
+ } else if (b) {
+ char *sap;
+ PGLOBAL g = PlugInit(NULL, (size_t)args->lengths[i] * M + 1024);
+
+// JsonSubSet(g);
+ sap = MakePSZ(g, args, i);
+
+ if (ParseJson(g, sap, strlen(sap)))
+ n = 4;
+
+ JsonFreeMem(g);
+ } // endif's
+
+ return n;
+} // end of IsJson
+
+/*********************************************************************************/
+/* GetMemPtr: returns the memory pointer used by this argument. */
+/*********************************************************************************/
+static PGLOBAL GetMemPtr(PGLOBAL g, UDF_ARGS *args, uint i)
+{
+ return (IsJson(args, i) == 3) ? ((PBSON)args->args[i])->G : g;
+} // end of GetMemPtr
+
+/*********************************************************************************/
+/* GetFileLength: returns file size in number of bytes. */
+/*********************************************************************************/
+static long GetFileLength(char *fn)
+{
+ int h;
+ long len;
+
+ h= open(fn, _O_RDONLY);
+
+ if (h != -1) {
+ if ((len = _filelength(h)) < 0)
+ len = 0;
+
+ close(h);
+ } else
+ len = 0;
+
+ return len;
+} // end of GetFileLength
+
+/*********************************************************************************/
+/* Calculate the reslen and memlen needed by a function. */
+/*********************************************************************************/
+my_bool CalcLen(UDF_ARGS *args, my_bool obj, unsigned long& reslen,
+ unsigned long& memlen, my_bool mod)
+{
+ char fn[_MAX_PATH];
+ unsigned long i, k, m, n;
+ long fl = 0, j = -1;
+
+ reslen = args->arg_count + 2;
+
+ // Calculate the result max length
+ for (i = 0; i < args->arg_count; i++) {
+ n = IsJson(args, i);
+
+ if (obj) {
+ if (!(k = args->attribute_lengths[i]))
+ k = strlen(args->attributes[i]);
+
+ reslen += (k + 3); // For quotes and :
+ } // endif obj
+
+ switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ if (n == 2 && args->args[i]) {
+ if (!mod) {
+ m = MY_MIN(args->lengths[i], sizeof(fn) - 1);
+ memcpy(fn, args->args[i], m);
+ fn[m] = 0;
+ j = i;
+ fl = GetFileLength(fn);
+ reslen += fl;
+ } else
+ reslen += args->lengths[i];
+
+ } else if (n == 3 && args->args[i])
+ reslen += ((PBSON)args->args[i])->Reslen;
+ else if (n == 1)
+ reslen += args->lengths[i];
+ else
+ reslen += (args->lengths[i] + 1) * 2; // Pessimistic !
+
+ break;
+ case INT_RESULT:
+ reslen += 20;
+ break;
+ case REAL_RESULT:
+ reslen += 31;
+ break;
+ case DECIMAL_RESULT:
+ reslen += (args->lengths[i] + 7); // 6 decimals
+ break;
+ case TIME_RESULT:
+ case ROW_RESULT:
+ default:
+ // What should we do here ?
+ break;
+ } // endswitch arg_type
+
+ } // endfor i
+
+ // Calculate the amount of memory needed
+ memlen = MEMFIX + sizeof(JOUTSTR) + reslen;
+
+ for (i = 0; i < args->arg_count; i++) {
+ n = IsJson(args, i);
+ memlen += (args->lengths[i] + sizeof(JVALUE));
+
+ if (obj) {
+ if (!(k = args->attribute_lengths[i]))
+ k = strlen(args->attributes[i]);
+
+ memlen += (k + sizeof(JOBJECT) + sizeof(JPAIR));
+ } else
+ memlen += sizeof(JARRAY);
+
+ switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ if (n == 2 && args->args[i]) {
+ if ((signed)i != j) {
+ m = MY_MIN(args->lengths[i], sizeof(fn) - 1);
+ memcpy(fn, args->args[i], m);
+ fn[m] = 0;
+ j = -1;
+ fl = GetFileLength(fn);
+ } // endif i
+
+ memlen += fl * M;
+ } else if (n == 1) {
+ if (i == 0)
+ memlen += sizeof(BSON); // For Jbin functions
+
+ memlen += args->lengths[i] * M; // Estimate parse memory
+ } else if (n == 3)
+ memlen += sizeof(JVALUE);
+
+ memlen += sizeof(TYPVAL<PSZ>);
+ break;
+ case INT_RESULT:
+ memlen += sizeof(TYPVAL<int>);
+ break;
+ case REAL_RESULT:
+ case DECIMAL_RESULT:
+ memlen += sizeof(TYPVAL<double>);
+ break;
+ case TIME_RESULT:
+ case ROW_RESULT:
+ default:
+ // What should we do here ?
+ break;
+ } // endswitch arg_type
+
+ } // endfor i
+
+ return false;
+} // end of CalcLen
+
+/*********************************************************************************/
+/* Check if the calculated memory is enough. */
+/*********************************************************************************/
+my_bool CheckMemory(PGLOBAL g, UDF_INIT *initid, UDF_ARGS *args, uint n,
+ my_bool m, my_bool obj, my_bool mod)
+{
+ unsigned long rl, ml;
+ my_bool b = false;
+
+ n = MY_MIN(n, args->arg_count);
+
+ for (uint i = 0; i < n; i++)
+ if (IsJson(args, i) == 2 ||
+ (b = (m && !i && args->arg_type[0] == STRING_RESULT && !IsJson(args, 0)))) {
+ if (CalcLen(args, obj, rl, ml, mod))
+ return true;
+ else if (b) {
+ ulong len;
+ char *p = args->args[0];
+
+ // Is this a file name?
+ if (p && !strchr("[{ \t\r\n", *p) && (len = GetFileLength(p)))
+ ml += len * (M + 1);
+ else
+ ml += args->lengths[0] * M;
+
+ } // endif b
+
+ ml += g->More;
+
+ if (ml > g->Sarea_Size) {
+ FreeSarea(g);
+
+ if (AllocSarea(g, ml)) {
+ char errmsg[MAX_STR];
+
+ snprintf(errmsg, sizeof(errmsg) - 1, MSG(WORK_AREA), g->Message);
+ strcpy(g->Message, errmsg);
+ return true;
+ } // endif SareaAlloc
+
+ g->Saved_Size = 0;
+ g->Xchk = NULL;
+ initid->max_length = rl;
+ } // endif Size
+
+ break;
+ } // endif IsJson
+
+ JsonSubSet(g);
+ return false;
+} // end of CheckMemory
+
+/*********************************************************************************/
+/* Make a zero terminated string from the passed argument. */
+/*********************************************************************************/
+PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i)
+{
+ if (args->arg_count > (unsigned)i && args->args[i]) {
+ int n = args->lengths[i];
+ PSZ s = (PSZ)PlgDBSubAlloc(g, NULL, n + 1);
+
+ if (s) {
+ memcpy(s, args->args[i], n);
+ s[n] = 0;
+ } else
+ PUSH_WARNING(g->Message);
+
+ return s;
+ } else
+ return NULL;
+
+} // end of MakePSZ
+
+/*********************************************************************************/
+/* Make a valid key from the passed argument. */
+/*********************************************************************************/
+static PCSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
+{
+ if (args->arg_count > (unsigned)i) {
+ int j = 0, n = args->attribute_lengths[i];
+ my_bool b; // true if attribute is zero terminated
+ PSZ p;
+ PCSZ s = args->attributes[i];
+
+ if (s && *s && (n || *s == '\'')) {
+ if ((b = (!n || !s[n])))
+ n = strlen(s);
+
+ if (IsJson(args, i))
+ j = (int)(strchr(s, '_') - s + 1);
+
+ if (j && n > j) {
+ s += j;
+ n -= j;
+ } else if (*s == '\'' && s[n-1] == '\'') {
+ s++;
+ n -= 2;
+ b = false;
+ } // endif *s
+
+ if (n < 1)
+ return (PCSZ) "Key";
+
+ if (!b) {
+ if ((p = (PSZ)PlgDBSubAlloc(g, NULL, n + 1))) {
+ memcpy(p, s, n);
+ p[n] = 0;
+ } else
+ PUSH_WARNING(g->Message);
+
+ s = p;
+ } // endif b
+
+ } // endif s
+
+ return (char*) s;
+ } // endif count
+
+ return (PCSZ) "Key";
+} // end of MakeKey
+
+/*********************************************************************************/
+/* Parse a json file. */
+/*********************************************************************************/
+static PJSON ParseJsonFile(PGLOBAL g, char *fn, int *pretty, size_t& len)
+{
+ char *memory;
+ HANDLE hFile;
+ MEMMAP mm;
+ PJSON jsp;
+
+ /*******************************************************************************/
+ /* Create the mapping file object. */
+ /*******************************************************************************/
+ hFile = CreateFileMap(g, fn, &mm, MODE_READ, false);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+
+ if (!(*g->Message))
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int)rc, fn);
+
+ return NULL;
+ } // endif hFile
+
+ /*******************************************************************************/
+ /* Get the file size. */
+ /*******************************************************************************/
+ len = (size_t)mm.lenL;
+
+ if (mm.lenH)
+ len += ((size_t)mm.lenH * 0x000000001LL);
+
+ memory = (char *)mm.memory;
+
+ if (!len) { // Empty or deleted file
+ CloseFileHandle(hFile);
+ return NULL;
+ } // endif len
+
+ if (!memory) {
+ CloseFileHandle(hFile);
+ sprintf(g->Message, MSG(MAP_VIEW_ERROR), fn, GetLastError());
+ return NULL;
+ } // endif Memory
+
+ CloseFileHandle(hFile); // Not used anymore
+
+ /*********************************************************************************/
+ /* Parse the json file and allocate its tree structure. */
+ /*********************************************************************************/
+ g->Message[0] = 0;
+ jsp = ParseJson(g, memory, len, pretty);
+ CloseMemMap(memory, len);
+ return jsp;
+} // end of ParseJsonFile
+
+/*********************************************************************************/
+/* Return a json file contains. */
+/*********************************************************************************/
+char *GetJsonFile(PGLOBAL g, char *fn)
+{
+ char *str;
+ int h, n, len;
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+ h= open(fn, O_RDONLY);
+#else
+ h= open(fn, _O_RDONLY, _O_TEXT);
+#endif
+
+ if (h == -1) {
+ sprintf(g->Message, "Error %d opening %-.1024s", errno, fn);
+ return NULL;
+ } // endif h
+
+ if ((len = _filelength(h)) < 0) {
+ sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", fn);
+ close(h);
+ return NULL;
+ } // endif len
+
+ if ((str = (char*)PlgDBSubAlloc(g, NULL, len + 1))) {
+ if ((n = read(h, str, len)) < 0) {
+ sprintf(g->Message, "Error %d reading %d bytes from %-.1024s", errno, len, fn);
+ return NULL;
+ } // endif n
+
+ str[n] = 0;
+ close(h);
+ } // endif str
+
+ return str;
+} // end of GetJsonFile
+
+/*********************************************************************************/
+/* Make a JSON value from the passed argument. */
+/*********************************************************************************/
+static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, uint i, PJSON *top = NULL)
+{
+ char *sap = (args->arg_count > i) ? args->args[i] : NULL;
+ int n, len;
+ int ci;
+ long long bigint;
+ PJSON jsp;
+ PJVAL jvp = new(g) JVALUE;
+
+ if (top)
+ *top = NULL;
+
+ if (sap) switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ if ((len = args->lengths[i])) {
+ if ((n = IsJson(args, i)) < 3)
+ sap = MakePSZ(g, args, i);
+
+ if (n) {
+ if (n == 3) {
+ if (top)
+ *top = ((PBSON)sap)->Top;
+
+ jsp = ((PBSON)sap)->Jsp;
+ } else {
+ if (n == 2) {
+ if (!(sap = GetJsonFile(g, sap))) {
+ PUSH_WARNING(g->Message);
+ return jvp;
+ } // endif sap
+
+ len = strlen(sap);
+ } // endif n
+
+ if (!(jsp = ParseJson(g, sap, strlen(sap))))
+ PUSH_WARNING(g->Message);
+ else if (top)
+ *top = jsp;
+
+ } // endif's n
+
+ if (jsp && jsp->GetType() == TYPE_JVAL)
+ jvp = (PJVAL)jsp;
+ else
+ jvp->SetValue(jsp);
+
+ } else {
+ ci = (strnicmp(args->attributes[i], "ci", 2)) ? 0 : 1;
+ jvp->SetString(g, sap, ci);
+ } // endif n
+
+ } // endif len
+
+ break;
+ case INT_RESULT:
+ bigint = *(long long*)sap;
+
+ if ((bigint == 0LL && !strcmp(args->attributes[i], "FALSE")) ||
+ (bigint == 1LL && !strcmp(args->attributes[i], "TRUE")))
+ jvp->SetBool(g, (char)bigint);
+ else
+ jvp->SetBigint(g, bigint);
+
+ break;
+ case REAL_RESULT:
+ jvp->SetFloat(g, *(double*)sap);
+ break;
+ case DECIMAL_RESULT:
+ jvp->SetFloat(g, atof(MakePSZ(g, args, i)));
+ break;
+ case TIME_RESULT:
+ case ROW_RESULT:
+ default:
+ break;
+ } // endswitch arg_type
+
+ return jvp;
+} // end of MakeValue
+
+/*********************************************************************************/
+/* Try making a JSON value of the passed type from the passed argument. */
+/*********************************************************************************/
+static PJVAL MakeTypedValue(PGLOBAL g, UDF_ARGS *args, uint i,
+ JTYP type, PJSON *top = NULL)
+{
+ char *sap;
+ PJSON jsp;
+ PJVAL jvp = MakeValue(g, args, i, top);
+
+ //if (type == TYPE_JSON) {
+ // if (jvp->GetValType() >= TYPE_JSON)
+ // return jvp;
+
+ //} else if (jvp->GetValType() == type)
+ // return jvp;
+
+ if (jvp->GetValType() == TYPE_STRG) {
+ sap = jvp->GetString(g);
+
+ if ((jsp = ParseJson(g, sap, strlen(sap)))) {
+ if ((type == TYPE_JSON && jsp->GetType() != TYPE_JVAL) || jsp->GetType() == type) {
+ if (top)
+ *top = jsp;
+
+ jvp->SetValue(jsp);
+ } // endif Type
+
+ } // endif jsp
+
+ } // endif Type
+
+ return jvp;
+} // end of MakeTypedValue
+
+/* ------------------------------ The JSON UDF's ------------------------------- */
+
+/*********************************************************************************/
+/* Make a Json value containing the parameter. */
+/*********************************************************************************/
+my_bool jsonvalue_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count > 1) {
+ strcpy(message, "Cannot accept more than 1 argument");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of jsonvalue_init
+
+char *jsonvalue(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, 1, false)) {
+ PJVAL jvp = MakeValue(g, args, 0);
+
+ if (!(str = Serialize(g, jvp, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ } else
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of JsonValue
+
+void jsonvalue_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonvalue_deinit
+
+/*********************************************************************************/
+/* Make a Json array containing all the parameters. */
+/*********************************************************************************/
+my_bool json_make_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, false, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of json_make_array_init
+
+char *json_make_array(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false)) {
+ PJAR arp = new(g)JARRAY;
+
+ for (uint i = 0; i < args->arg_count; i++)
+ arp->AddArrayValue(g, MakeValue(g, args, i));
+
+ arp->InitArray(g);
+
+ if (!(str = Serialize(g, arp, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ } else
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of json_make_array
+
+void json_make_array_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_make_array_deinit
+
+/*********************************************************************************/
+/* Add one or several values to a Json array. */
+/*********************************************************************************/
+my_bool json_array_add_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ //} else if (!IsJson(args, 0, true)) {
+ // strcpy(message, "First argument must be a valid json string or item");
+ // return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of json_array_add_values_init
+
+char *json_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, true)) {
+ PJSON top;
+ PJAR arp;
+ PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JAR, &top);
+
+ if (jvp->GetValType() != TYPE_JAR) {
+ arp = new(g)JARRAY;
+ arp->AddArrayValue(g, jvp);
+ top = arp;
+ } else
+ arp = jvp->GetArray();
+
+ for (uint i = 1; i < args->arg_count; i++)
+ arp->AddArrayValue(g, MakeValue(g, args, i));
+
+ arp->InitArray(g);
+ str = MakeResult(g, args, top, args->arg_count);
+ } // endif CheckMemory
+
+ if (!str) {
+ PUSH_WARNING(g->Message);
+ str = args->args[0];
+ } // endif str
+
+ // Keep result of constant function
+ g->Xchk = (g->N) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_array_add_values
+
+void json_array_add_values_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_array_add_values_deinit
+
+/*********************************************************************************/
+/* Add one value to a Json array. */
+/*********************************************************************************/
+my_bool json_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ //} else if (!IsJson(args, 0, true)) {
+ // strcpy(message, "First argument is not a valid Json item");
+ // return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of json_array_add_init
+
+char *json_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 2, false, false, true)) {
+ int *x;
+ uint n = 2;
+ PJSON jsp, top;
+ PJVAL jvp;
+ PJAR arp;
+
+ jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
+ jsp = jvp->GetJson();
+ x = GetIntArgPtr(g, args, n);
+
+ if (CheckPath(g, args, jsp, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp) {
+ PGLOBAL gb = GetMemPtr(g, args, 0);
+
+ if (jvp->GetValType() != TYPE_JAR) {
+ if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
+ arp->AddArrayValue(gb, JvalNew(gb, TYPE_JVAL, jvp));
+ jvp->SetValue(arp);
+
+ if (!top)
+ top = arp;
+
+ } // endif arp
+
+ } else
+ arp = jvp->GetArray();
+
+ if (arp) {
+ arp->AddArrayValue(gb, MakeValue(gb, args, 1), x);
+ arp->InitArray(gb);
+ str = MakeResult(g, args, top, n);
+ } else
+ PUSH_WARNING(gb->Message);
+
+ } else {
+ PUSH_WARNING("Target is not an array");
+ // if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+ fin:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ *error = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_array_add
+
+void json_array_add_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_array_add_deinit
+
+/*********************************************************************************/
+/* Delete a value from a Json array. */
+/*********************************************************************************/
+my_bool json_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of json_array_delete_init
+
+char *json_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ int *x;
+ uint n = 1;
+ PJSON top;
+ PJAR arp;
+ PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
+
+ if (!(x = GetIntArgPtr(g, args, n)))
+ PUSH_WARNING("Missing or null array index");
+ else if (CheckPath(g, args, jvp->GetJson(), jvp, 1))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->GetValType() == TYPE_JAR) {
+ arp = jvp->GetArray();
+ arp->DeleteValue(*x);
+ arp->InitArray(GetMemPtr(g, args, 0));
+ str = MakeResult(g, args, top, n);
+ } else {
+ PUSH_WARNING("First argument target is not an array");
+// if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+ fin:
+ if (!str) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_array_delete
+
+void json_array_delete_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_array_delete_deinit
+
+/*********************************************************************************/
+/* Sum big integer values from a Json array. */
+/*********************************************************************************/
+my_bool jsonsum_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more;
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function must have 1 argument");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ more = (IsJson(args, 0) != 3) ? 1000 : 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of jsonsum_int_init
+
+long long jsonsum_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
+{
+ long long n = 0LL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (!g->Activityp) {
+ *is_null = 1;
+ return 0LL;
+ } else
+ return *(long long*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ PJVAL jvp = MakeValue(g, args, 0);
+
+ if (jvp && jvp->GetValType() == TYPE_JAR) {
+ PJAR arp = jvp->GetArray();
+
+ for (int i = 0; i < arp->size(); i++)
+ n += arp->GetArrayValue(i)->GetBigint();
+
+ } else {
+ PUSH_WARNING("First argument target is not an array");
+ } // endif jvp
+
+ } else {
+ *error = 1;
+ n = -1LL;
+ } // end of CheckMemory
+
+ if (g->N) {
+ // Keep result of constant function
+ long long *np;
+
+ if ((np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long)))) {
+ *np = n;
+ g->Activityp = (PACTIVITY)np;
+ } else
+ PUSH_WARNING(g->Message);
+
+ } // endif const_item
+
+ return n;
+} // end of jsonsum_int
+
+void jsonsum_int_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonsum_int_deinit
+
+/*********************************************************************************/
+/* Sum big integer values from a Json array. */
+/*********************************************************************************/
+my_bool jsonsum_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more;
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function must have 1 argument");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ more = (IsJson(args, 0) != 3) ? 1000 : 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of jsonsum_real_init
+
+double jsonsum_real(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
+{
+ double n = 0.0;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (!g->Activityp) {
+ *is_null = 1;
+ return 0.0;
+ } else
+ return *(double*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ PJVAL jvp = MakeValue(g, args, 0);
+
+ if (jvp && jvp->GetValType() == TYPE_JAR) {
+ PJAR arp = jvp->GetArray();
+
+ for (int i = 0; i < arp->size(); i++)
+ n += arp->GetArrayValue(i)->GetFloat();
+
+ } else {
+ PUSH_WARNING("First argument target is not an array");
+ } // endif jvp
+
+ } else {
+ *error = 1;
+ n = -1.0;
+ } // endif CheckMemory
+
+ if (g->N) {
+ // Keep result of constant function
+ double *np;
+
+ if ((np = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
+ *np = n;
+ g->Activityp = (PACTIVITY)np;
+ } else {
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ n = -1.0;
+ } // endif np
+
+ } // endif const_item
+
+ return n;
+} // end of jsonsum_real
+
+void jsonsum_real_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonsum_real_deinit
+
+/*********************************************************************************/
+/* Returns the average of big integer values from a Json array. */
+/*********************************************************************************/
+my_bool jsonavg_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return jsonsum_real_init(initid, args, message);
+} // end of jsonavg_real_init
+
+double jsonavg_real(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
+{
+ double n = 0.0;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (!g->Activityp) {
+ *is_null = 1;
+ return 0.0;
+ } else
+ return *(double*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ PJVAL jvp = MakeValue(g, args, 0);
+
+ if (jvp && jvp->GetValType() == TYPE_JAR) {
+ PJAR arp = jvp->GetArray();
+
+ if (arp->size()) {
+ for (int i = 0; i < arp->size(); i++)
+ n += arp->GetArrayValue(i)->GetFloat();
+
+ n /= arp->size();
+ } // endif size
+
+ } else {
+ PUSH_WARNING("First argument target is not an array");
+ } // endif jvp
+
+ } else {
+ *error = 1;
+ n = -1.0;
+ } // endif CheckMemory
+
+ if (g->N) {
+ // Keep result of constant function
+ double *np;
+
+ if ((np = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
+ *np = n;
+ g->Activityp = (PACTIVITY)np;
+ } else {
+ *error = 1;
+ n = -1.0;
+ } // endif np
+
+ } // endif const_item
+
+ return n;
+} // end of jsonavg_real
+
+void jsonavg_real_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonavg_real_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all the parameters. */
+/*********************************************************************************/
+my_bool json_make_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of json_make_object_init
+
+char *json_make_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, false, true)) {
+ PJOB objp;
+
+ if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i++)
+ objp->SetKeyValue(g, MakeValue(g, args, i), MakeKey(g, args, i));
+
+ str = Serialize(g, objp, NULL, 0);
+ } // endif objp
+
+ } // endif CheckMemory
+
+ if (!str)
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of json_make_object
+
+void json_make_object_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_make_object_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all not null parameters. */
+/*********************************************************************************/
+my_bool json_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args,
+ char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of json_object_nonull_init
+
+char *json_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
+ PJVAL jvp;
+ PJOB objp;
+
+ if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i++)
+ if (!(jvp = MakeValue(g, args, i))->IsNull())
+ objp->SetKeyValue(g, jvp, MakeKey(g, args, i));
+
+ str = Serialize(g, objp, NULL, 0);
+ } // endif objp
+
+ } // endif CheckMemory
+
+ if (!str)
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of json_object_nonull
+
+void json_object_nonull_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_object_nonull_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all the key/value parameters. */
+/*********************************************************************************/
+my_bool json_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count % 2) {
+ strcpy(message, "This function must have an even number of arguments");
+ return true;
+ } // endif arg_count
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of json_object_key_init
+
+char *json_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
+ PJOB objp;
+
+ if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i += 2)
+ objp->SetKeyValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i));
+
+ str = Serialize(g, objp, NULL, 0);
+ } // endif objp
+
+ } // endif CheckMemory
+
+ if (!str)
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of json_object_key
+
+void json_object_key_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_object_key_deinit
+
+/*********************************************************************************/
+/* Add or replace a value in a Json Object. */
+/*********************************************************************************/
+my_bool json_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else if (!IsJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of json_object_add_init
+
+char *json_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PCSZ key;
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 2, false, true, true)) {
+ PJOB jobp;
+ PJVAL jvp;
+ PJSON jsp, top;
+ PGLOBAL gb = GetMemPtr(g, args, 0);
+
+ jvp = MakeValue(g, args, 0, &top);
+ jsp = jvp->GetJson();
+
+ if (CheckPath(g, args, jsp, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->GetValType() == TYPE_JOB) {
+ jobp = jvp->GetObject();
+ jvp = MakeValue(gb, args, 1);
+ key = MakeKey(gb, args, 1);
+ jobp->SetKeyValue(gb, jvp, key);
+ str = MakeResult(g, args, top);
+ } else {
+ PUSH_WARNING("First argument target is not an object");
+// if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+ fin:
+ if (!str) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_object_add
+
+void json_object_add_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_object_add_deinit
+
+/*********************************************************************************/
+/* Delete a value from a Json object. */
+/*********************************************************************************/
+my_bool json_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have 2 or 3 arguments");
+ return true;
+ } else if (!IsJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument must be a key string");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of json_object_delete_init
+
+char *json_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 1, false, true, true)) {
+ PCSZ key;
+ PJOB jobp;
+ PJSON jsp, top;
+ PJVAL jvp = MakeValue(g, args, 0, &top);
+
+ jsp = jvp->GetJson();
+
+ if (CheckPath(g, args, jsp, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->GetValType() == TYPE_JOB) {
+ key = MakeKey(GetMemPtr(g, args, 0), args, 1);
+ jobp = jvp->GetObject();
+ jobp->DeleteKey(key);
+ str = MakeResult(g, args, top);
+ } else {
+ PUSH_WARNING("First argument target is not an object");
+// if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+ fin:
+ if (!str) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_object_delete
+
+void json_object_delete_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_object_delete_deinit
+
+/*********************************************************************************/
+/* Returns an array of the Json object keys. */
+/*********************************************************************************/
+my_bool json_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function must have 1 argument");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "Argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of json_object_list_init
+
+char *json_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->N) {
+ if (!CheckMemory(g, initid, args, 1, true, true)) {
+ char *p;
+ PJSON jsp;
+ PJVAL jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ return NULL;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (jsp->GetType() == TYPE_JOB) {
+ PJAR jarp = ((PJOB)jsp)->GetKeyList(g);
+
+ if (!(str = Serialize(g, jarp, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ } else {
+ PUSH_WARNING("First argument is not an object");
+ if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ g->Xchk = str;
+ g->N = 1; // str can be NULL
+ } // endif const_item
+
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_object_list
+
+void json_object_list_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_object_list_deinit
+
+/*********************************************************************************/
+/* Returns an array of the Json object values. */
+/*********************************************************************************/
+my_bool json_object_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function must have 1 argument");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "Argument must be a json object");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of json_object_list_init
+
+char *json_object_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->N) {
+ if (!CheckMemory(g, initid, args, 1, true, true)) {
+ char *p;
+ PJSON jsp;
+ PJVAL jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ return NULL;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (jsp->GetType() == TYPE_JOB) {
+ PJAR jarp = ((PJOB)jsp)->GetValList(g);
+
+ if (!(str = Serialize(g, jarp, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ } else {
+ PUSH_WARNING("First argument is not an object");
+ if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ g->Xchk = str;
+ g->N = 1; // str can be NULL
+ } // endif const_item
+
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_object_values
+
+void json_object_values_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_object_values_deinit
+
+/*********************************************************************************/
+/* Set the value of JsonGrpSize. */
+/*********************************************************************************/
+my_bool jsonset_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1 || args->arg_type[0] != INT_RESULT) {
+ strcpy(message, "This function must have 1 integer argument");
+ return true;
+ } else
+ return false;
+
+} // end of jsonset_grp_size_init
+
+long long jsonset_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
+{
+ long long n = *(long long*)args->args[0];
+
+ JsonGrpSize = (uint)n;
+ return (long long)GetJsonGroupSize();
+} // end of jsonset_grp_size
+
+/*********************************************************************************/
+/* Get the value of JsonGrpSize. */
+/*********************************************************************************/
+my_bool jsonget_grp_size_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 0) {
+ strcpy(message, "This function must have no arguments");
+ return true;
+ } else
+ return false;
+
+} // end of jsonget_grp_size_init
+
+long long jsonget_grp_size(UDF_INIT *initid, UDF_ARGS *args, char *, char *)
+{
+ return (long long)GetJsonGroupSize();
+} // end of jsonget_grp_size
+
+/*********************************************************************************/
+/* Make a Json array from values coming from rows. */
+/*********************************************************************************/
+my_bool json_array_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, n = GetJsonGroupSize();
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function can only accept 1 argument");
+ return true;
+ } else if (IsJson(args, 0) == 3) {
+ strcpy(message, "This function does not support Jbin arguments");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ reslen *= n;
+ memlen += ((memlen - MEMFIX) * (n - 1));
+
+ if (JsonInit(initid, args, message, false, reslen, memlen))
+ return true;
+
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JAR);
+ g->N = (int)n;
+ return false;
+} // end of json_array_grp_init
+
+void json_array_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PJAR arp = (PJAR)g->Activityp;
+
+ if (arp && g->N-- > 0)
+ arp->AddArrayValue(g, MakeValue(g, args, 0));
+
+} // end of json_array_grp_add
+
+char *json_array_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PJAR arp = (PJAR)g->Activityp;
+
+ if (g->N < 0)
+ PUSH_WARNING("Result truncated to json_grp_size values");
+
+ if (arp) {
+ arp->InitArray(g);
+ str = Serialize(g, arp, NULL, 0);
+ } else
+ str = NULL;
+
+ if (!str)
+ str = strcpy(result, g->Message);
+
+ *res_length = strlen(str);
+ return str;
+} // end of json_array_grp
+
+void json_array_grp_clear(UDF_INIT *initid, char*, char*)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JAR);
+ g->N = GetJsonGroupSize();
+} // end of json_array_grp_clear
+
+void json_array_grp_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_array_grp_deinit
+
+/*********************************************************************************/
+/* Make a Json object from values coming from rows. */
+/*********************************************************************************/
+my_bool json_object_grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, n = GetJsonGroupSize();
+
+ if (args->arg_count != 2) {
+ strcpy(message, "This function requires 2 arguments (key, value)");
+ return true;
+ } else if (IsJson(args, 0) == 3) {
+ strcpy(message, "This function does not support Jbin arguments");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen);
+
+ reslen *= n;
+ memlen += ((memlen - MEMFIX) * (n - 1));
+
+ if (JsonInit(initid, args, message, false, reslen, memlen))
+ return true;
+
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JOB);
+ g->N = (int)n;
+ return false;
+} // end of json_object_grp_init
+
+void json_object_grp_add(UDF_INIT *initid, UDF_ARGS *args, char*, char*)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PJOB objp = (PJOB)g->Activityp;
+
+ if (g->N-- > 0)
+ objp->SetKeyValue(g, MakeValue(g, args, 1), MakePSZ(g, args, 0));
+
+} // end of json_object_grp_add
+
+char *json_object_grp(UDF_INIT *initid, UDF_ARGS *, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PJOB objp = (PJOB)g->Activityp;
+
+ if (g->N < 0)
+ PUSH_WARNING("Result truncated to json_grp_size values");
+
+ if (!objp || !(str = Serialize(g, objp, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ *res_length = strlen(str);
+ return str;
+} // end of json_object_grp
+
+void json_object_grp_clear(UDF_INIT *initid, char*, char*)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ g->Activityp = (PACTIVITY)JsonNew(g, TYPE_JOB);
+ g->N = GetJsonGroupSize();
+} // end of json_object_grp_clear
+
+void json_object_grp_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_object_grp_deinit
+
+/*********************************************************************************/
+/* Merge two arrays or objects. */
+/*********************************************************************************/
+my_bool json_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else if (!IsJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (!IsJson(args, 1)) {
+ strcpy(message, "Second argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ return false;
+ } else
+ return true;
+
+} // end of json_item_merge_init
+
+char *json_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->Xchk) {
+ // This constant function was recalled
+ str = (char*)g->Xchk;
+ goto fin;
+ } // endif Xchk
+
+ if (!CheckMemory(g, initid, args, 2, false, false, true)) {
+ PJSON top = NULL;
+ PJVAL jvp;
+ PJSON jsp[2] = {NULL, NULL};
+
+ for (int i = 0; i < 2; i++) {
+ jvp = MakeValue(g, args, i);
+ if (!i) top = jvp->GetJson();
+
+ if (jvp->GetValType() != TYPE_JAR && jvp->GetValType() != TYPE_JOB) {
+ sprintf(g->Message, "Argument %d is not an array or object", i);
+ PUSH_WARNING(g->Message);
+ } else
+ jsp[i] = jvp->GetJsp();
+
+ } // endfor i
+
+ if (jsp[0]) {
+ if (jsp[0]->Merge(GetMemPtr(g, args, 0), jsp[1]))
+ PUSH_WARNING(GetMemPtr(g, args, 0)->Message);
+ else
+ str = MakeResult(g, args, top);
+
+ } // endif jsp
+
+ } // endif CheckMemory
+
+ // In case of error or file, return unchanged argument
+ if (!str)
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Xchk = str;
+
+ fin:
+ if (!str) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_item_merge
+
+void json_item_merge_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_item_merge_deinit
+
+/*********************************************************************************/
+/* Get a Json item from a Json document. */
+/*********************************************************************************/
+my_bool json_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more;
+ int n = IsJson(args, 0);
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a string (jpath)");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ if (n == 2 && args->args[0]) {
+ char fn[_MAX_PATH];
+ long fl;
+
+ memcpy(fn, args->args[0], args->lengths[0]);
+ fn[args->lengths[0]] = 0;
+ fl = GetFileLength(fn);
+ more = fl * 3;
+ } else if (n != 3) {
+ more = args->lengths[0] * 3;
+ } else
+ more = 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of json_get_item_init
+
+char *json_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *path, *str = NULL;
+ PJSON jsp;
+ PJVAL jvp;
+ PJSNX jsx;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ str = (char*)g->Activityp;
+ goto fin;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto fin;
+ } // endif CheckMemory
+
+ jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+ jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
+
+ if (!jsx || jsx->SetJpath(g, path, true)) {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return NULL;
+ } // endif SetJpath
+
+ jsx->ReadValue(g);
+
+ if (!jsx->GetValue()->IsNull())
+ str = jsx->GetValue()->GetCharValue();
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+ fin:
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_get_item
+
+void json_get_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_get_item_deinit
+
+/*********************************************************************************/
+/* Get a string value from a Json item. */
+/*********************************************************************************/
+my_bool jsonget_string_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 1024;
+ int n = IsJson(args, 0);
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a string (jpath)");
+ return true;
+ } else if (args->arg_count > 2) {
+ if (args->arg_type[2] == INT_RESULT && args->args[2])
+ more += (unsigned long)*(long long*)args->args[2];
+ else
+ strcpy(message, "Third argument is not an integer (memory)");
+
+ } // endif's
+
+ CalcLen(args, false, reslen, memlen);
+//memlen += more;
+
+ if (n == 2 && args->args[0]) {
+ char fn[_MAX_PATH];
+ long fl;
+
+ memcpy(fn, args->args[0], args->lengths[0]);
+ fn[args->lengths[0]] = 0;
+ fl = GetFileLength(fn);
+ more += fl * 3;
+ } else if (n != 3)
+ more += args->lengths[0] * 3;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of jsonget_string_init
+
+char *jsonget_string(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *p, *path, *str = NULL;
+ PJSON jsp;
+ PJSNX jsx;
+ PJVAL jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ str = (char*)g->Activityp;
+ goto err;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ try {
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto err;
+ } else
+ jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+ jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
+
+ if (!jsx || jsx->SetJpath(g, path)) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif SetJpath
+
+ jsx->ReadValue(g);
+
+ if (!jsx->GetValue()->IsNull())
+ str = jsx->GetValue()->GetCharValue();
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %-.256s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ } // end catch
+
+ err:
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of jsonget_string
+
+void jsonget_string_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonget_string_deinit
+
+/*********************************************************************************/
+/* Get an integer value from a Json item. */
+/*********************************************************************************/
+my_bool jsonget_int_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more;
+
+ if (args->arg_count != 2) {
+ strcpy(message, "This function must have 2 arguments");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a (jpath) string");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ more = (IsJson(args, 0) != 3) ? 1000 : 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of jsonget_int_init
+
+long long jsonget_int(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error)
+{
+ char *p, *path;
+ long long n;
+ PJSON jsp;
+ PJSNX jsx;
+ PJVAL jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (!g->Activityp) {
+ *is_null = 1;
+ return 0LL;
+ } else
+ return *(long long*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ if (g->Mrr) *error = 1;
+ *is_null = 1;
+ return 0LL;
+ } else
+ jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ if (g->Mrr) *error = 1;
+ *is_null = 1;
+ return 0;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+ jsx = JsnxNew(g, jsp, TYPE_BIGINT);
+
+ if (!jsx || jsx->SetJpath(g, path)) {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return 0;
+ } // endif SetJpath
+
+ jsx->ReadValue(g);
+
+ if (jsx->GetValue()->IsNull()) {
+ *is_null = 1;
+ return 0;
+ } // endif IsNull
+
+ n = jsx->GetValue()->GetBigintValue();
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
+
+ if (np) {
+ *np = n;
+ g->Activityp = (PACTIVITY)np;
+ } else
+ PUSH_WARNING(g->Message);
+
+ } // endif const_item
+
+ return n;
+} // end of jsonget_int
+
+void jsonget_int_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonget_int_deinit
+
+/*********************************************************************************/
+/* Get a double value from a Json item. */
+/*********************************************************************************/
+my_bool jsonget_real_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a (jpath) string");
+ return true;
+ } else if (args->arg_count > 2) {
+ if (args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third argument is not an integer (decimals)");
+ return true;
+ } else
+ initid->decimals = (uint)*(longlong*)args->args[2];
+
+ } else
+ initid->decimals = 15;
+
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ more = (IsJson(args, 0) != 3) ? 1000 : 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of jsonget_real_init
+
+double jsonget_real(UDF_INIT *initid, UDF_ARGS *args,
+ char *is_null, char *error)
+{
+ char *p, *path;
+ double d;
+ PJSON jsp;
+ PJSNX jsx;
+ PJVAL jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (!g->Activityp) {
+ *is_null = 1;
+ return 0.0;
+ } else
+ return *(double*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ if (g->Mrr) *error = 1;
+ *is_null = 1;
+ return 0.0;
+ } else
+ jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return 0.0;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+ jsx = JsnxNew(g, jsp, TYPE_DOUBLE);
+
+ if (!jsx || jsx->SetJpath(g, path)) {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return 0.0;
+ } // endif SetJpath
+
+ jsx->ReadValue(g);
+
+ if (jsx->GetValue()->IsNull()) {
+ *is_null = 1;
+ return 0.0;
+ } // endif IsNull
+
+ d = jsx->GetValue()->GetFloatValue();
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ double *dp;
+
+ if ((dp = (double*)PlgDBSubAlloc(g, NULL, sizeof(double)))) {
+ *dp = d;
+ g->Activityp = (PACTIVITY)dp;
+ } else {
+ PUSH_WARNING(g->Message);
+ *is_null = 1;
+ return 0.0;
+ } // endif dp
+
+ } // endif const_item
+
+ return d;
+} // end of jsonget_real
+
+void jsonget_real_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonget_real_deinit
+
+/*********************************************************************************/
+/* Locate a value in a Json tree. */
+/*********************************************************************************/
+my_bool jsonlocate_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 1000;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third argument is not an integer (rank)");
+ return true;
+ } else if (args->arg_count > 3)
+ {
+ if (args->arg_type[3] != INT_RESULT) {
+ strcpy(message, "Fourth argument is not an integer (memory)");
+ return true;
+ } else
+ more += (ulong)*(longlong*)args->args[2];
+ }
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ if (IsJson(args, 0) == 3)
+ more = 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of jsonlocate_init
+
+char *jsonlocate(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *path = NULL;
+ int k;
+ PJVAL jvp, jvp2;
+ PJSON jsp;
+ PJSNX jsx;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (g->Activityp) {
+ path = (char*)g->Activityp;
+ *res_length = strlen(path);
+ return path;
+ } else {
+ *res_length = 0;
+ *is_null = 1;
+ return NULL;
+ } // endif Activityp
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ try {
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, !g->Xchk)) {
+ PUSH_WARNING("CheckMemory error");
+ *error = 1;
+ goto err;
+ } else
+ jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
+
+ //if ((p = jvp->GetString(g))) {
+ // if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ // PUSH_WARNING(g->Message);
+ // goto err;
+ // } // endif jsp
+ //} else
+ // jsp = jvp->GetJson();
+
+ if (!(jsp = jvp->GetJson())) {
+ PUSH_WARNING("First argument is not a valid JSON item");
+ goto err;
+ } // endif jsp
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ // The item to locate
+ jvp2 = MakeValue(g, args, 1);
+
+ k = (args->arg_count > 2) ? (int)*(long long*)args->args[2] : 1;
+
+ jsx = new(g) JSNX(g, jsp, TYPE_STRING);
+ path = jsx->Locate(g, jsp, jvp2, k);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)path;
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %-.256s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } // end catch
+
+ err:
+ if (!path) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(path);
+
+ return path;
+} // end of jsonlocate
+
+void jsonlocate_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsonlocate_deinit
+
+/*********************************************************************************/
+/* Locate all occurences of a value in a Json tree. */
+/*********************************************************************************/
+my_bool json_locate_all_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 1000;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third argument is not an integer (Depth)");
+ return true;
+ } else if (args->arg_count > 3)
+ {
+ if (args->arg_type[3] != INT_RESULT) {
+ strcpy(message, "Fourth argument is not an integer (memory)");
+ return true;
+ } else
+ more += (ulong)*(longlong*)args->args[2];
+ }
+ CalcLen(args, false, reslen, memlen);
+
+ // TODO: calculate this
+ if (IsJson(args, 0) == 3)
+ more = 0;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of json_locate_all_init
+
+char *json_locate_all(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *p, *path = NULL;
+ int mx = 10;
+ PJVAL jvp, jvp2;
+ PJSON jsp;
+ PJSNX jsx;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (g->Activityp) {
+ path = (char*)g->Activityp;
+ *res_length = strlen(path);
+ return path;
+ } else {
+ *error = 1;
+ *res_length = 0;
+ *is_null = 1;
+ return NULL;
+ } // endif Activityp
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ try {
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ *error = 1;
+ goto err;
+ } else
+ jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ // The item to locate
+ jvp2 = MakeValue(g, args, 1);
+
+ if (args->arg_count > 2)
+ mx = (int)*(long long*)args->args[2];
+
+ jsx = new(g) JSNX(g, jsp, TYPE_STRING);
+ path = jsx->LocateAll(g, jsp, jvp2, mx);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)path;
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %-.256s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ path = NULL;
+ } // end catch
+
+ err:
+ if (!path) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(path);
+
+ return path;
+} // end of json_locate_all
+
+void json_locate_all_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_locate_all_deinit
+
+/*********************************************************************************/
+/* Check whether the document contains a value or item. */
+/*********************************************************************************/
+my_bool jsoncontains_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 1024;
+ int n = IsJson(args, 0);
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_count > 2 && args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third argument is not an integer (index)");
+ return true;
+ } else if (args->arg_count > 3) {
+ if (args->arg_type[3] == INT_RESULT && args->args[3])
+ more += (unsigned long)*(long long*)args->args[3];
+ else
+ strcpy(message, "Fourth argument is not an integer (memory)");
+
+ } // endif's
+
+ CalcLen(args, false, reslen, memlen);
+//memlen += more;
+
+ // TODO: calculate this
+ more += (IsJson(args, 0) != 3 ? 1000 : 0);
+
+ return JsonInit(initid, args, message, false, reslen, memlen, more);
+} // end of jsoncontains_init
+
+long long jsoncontains(UDF_INIT *initid, UDF_ARGS *args, char *, char *error)
+{
+ char isn, res[256];
+ unsigned long reslen;
+
+ isn = 0;
+ jsonlocate(initid, args, res, &reslen, &isn, error);
+ return (isn) ? 0LL : 1LL;
+} // end of jsoncontains
+
+void jsoncontains_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsoncontains_deinit
+
+/*********************************************************************************/
+/* Check whether the document contains a path. */
+/*********************************************************************************/
+my_bool jsoncontains_path_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 1024;
+ int n = IsJson(args, 0);
+
+ if (args->arg_count < 2) {
+ strcpy(message, "At least 2 arguments required");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a string (path)");
+ return true;
+ } else if (args->arg_count > 2) {
+ if (args->arg_type[2] == INT_RESULT && args->args[2])
+ more += (unsigned long)*(long long*)args->args[2];
+ else
+ strcpy(message, "Third argument is not an integer (memory)");
+
+ } // endif's
+
+ CalcLen(args, false, reslen, memlen);
+//memlen += more;
+
+ // TODO: calculate this
+ more += (IsJson(args, 0) != 3 ? 1000 : 0);
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of jsoncontains_path_init
+
+long long jsoncontains_path(UDF_INIT *initid, UDF_ARGS *args, char *, char *error)
+{
+ char *p, *path;
+ long long n;
+ PJSON jsp;
+ PJSNX jsx;
+ PJVAL jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ if (!g->Activityp) {
+ return 0LL;
+ } else
+ return *(long long*)g->Activityp;
+
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto err;
+ } else
+ jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+ jsx = JsnxNew(g, jsp, TYPE_BIGINT);
+
+ if (!jsx || jsx->SetJpath(g, path)) {
+ PUSH_WARNING(g->Message);
+ goto err;
+ } // endif SetJpath
+
+ n = (jsx->CheckPath(g)) ? 1LL : 0LL;
+
+ if (initid->const_item) {
+ // Keep result of constant function
+ long long *np = (long long*)PlgDBSubAlloc(g, NULL, sizeof(long long));
+
+ if (np) {
+ *np = n;
+ g->Activityp = (PACTIVITY)np;
+ } else
+ PUSH_WARNING(g->Message);
+
+ } // endif const_item
+
+ return n;
+
+ err:
+ if (g->Mrr) *error = 1;
+ return 0LL;
+} // end of jsoncontains_path
+
+void jsoncontains_path_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jsoncontains_path_deinit
+
+/*********************************************************************************/
+/* This function is used by the json_set/insert/update_item functions. */
+/*********************************************************************************/
+char *handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *p, *path, *str = NULL;
+ int w;
+ my_bool b = true;
+ PJSON jsp;
+ PJSNX jsx;
+ PJVAL jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PGLOBAL gb = GetMemPtr(g, args, 0);
+
+ if (g->Alchecked) {
+ str = (char*)g->Activityp;
+ goto fin;
+ } else if (g->N)
+ g->Alchecked = 1;
+
+ if (!strcmp(result, "$set"))
+ w = 0;
+ else if (!strcmp(result, "$insert"))
+ w = 1;
+ else if (!strcmp(result, "$update"))
+ w = 2;
+ else {
+ PUSH_WARNING("Logical error, please contact CONNECT developer");
+ goto fin;
+ } // endelse
+
+ try {
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true, false, true)) {
+ PUSH_WARNING("CheckMemory error");
+ throw 1;
+ } else
+ jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ throw 2;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ jsx = new(g)JSNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
+
+ for (uint i = 1; i + 1 < args->arg_count; i += 2) {
+ jvp = MakeValue(gb, args, i);
+ path = MakePSZ(g, args, i + 1);
+
+ if (jsx->SetJpath(g, path, false)) {
+ PUSH_WARNING(g->Message);
+ continue;
+ } // endif SetJpath
+
+ if (w) {
+ jsx->ReadValue(g);
+ b = jsx->GetValue()->IsNull();
+ b = (w == 1) ? b : !b;
+ } // endif w
+
+ if (b && jsx->WriteValue(gb, jvp))
+ PUSH_WARNING(g->Message);
+
+ } // endfor i
+
+ // In case of error or file, return unchanged argument
+ if (!(str = MakeResult(g, args, jsp, INT_MAX32)))
+ str = MakePSZ(g, args, 0);
+
+ if (g->N)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %-.256s\n", n, g->Message);
+
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ } // end catch
+
+fin:
+ if (!str) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of handle_item
+
+/*********************************************************************************/
+/* Set Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool json_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 0;
+ int n = IsJson(args, 0);
+
+ if (!(args->arg_count % 2)) {
+ strcpy(message, "This function must have an odd number of arguments");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ if (n == 2 && args->args[0]) {
+ char fn[_MAX_PATH];
+ long fl;
+
+ memcpy(fn, args->args[0], args->lengths[0]);
+ fn[args->lengths[0]] = 0;
+ fl = GetFileLength(fn);
+ more += fl * 3;
+ } else if (n != 3)
+ more += args->lengths[0] * 3;
+
+ if (!JsonInit(initid, args, message, true, reslen, memlen, more)) {
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ // This is a constant function
+ g->N = (initid->const_item) ? 1 : 0;
+
+ // This is to avoid double execution when using prepared statements
+ if (IsJson(args, 0) > 1)
+ initid->const_item = 0;
+
+ g->Alchecked = 0;
+ return false;
+ } else
+ return true;
+
+} // end of json_set_item_init
+
+char *json_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$set");
+ return handle_item(initid, args, result, res_length, is_null, p);
+} // end of json_set_item
+
+void json_set_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_set_item_deinit
+
+/*********************************************************************************/
+/* Insert Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool json_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return json_set_item_init(initid, args, message);
+} // end of json_insert_item_init
+
+char *json_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$insert");
+ return handle_item(initid, args, result, res_length, is_null, p);
+} // end of json_insert_item
+
+void json_insert_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_insert_item_deinit
+
+/*********************************************************************************/
+/* Update Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool json_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return json_set_item_init(initid, args, message);
+} // end of json_update_item_init
+
+char *json_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$update");
+ return handle_item(initid, args, result, res_length, is_null, p);
+} // end of json_update_item
+
+void json_update_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_update_item_deinit
+
+/*********************************************************************************/
+/* Returns a json file as a json string. */
+/*********************************************************************************/
+my_bool json_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, fl, more = 1024;
+
+ if (args->arg_count < 1 || args->arg_count > 4) {
+ strcpy(message, "This function only accepts 1 to 4 arguments");
+ return true;
+ } else if (args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a string (file name)");
+ return true;
+ } // endif's args[0]
+
+ for (unsigned int i = 1; i < args->arg_count; i++) {
+ if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) {
+ sprintf(message, "Argument %d is not an integer or a string (pretty or path)", i);
+ return true;
+ } // endif arg_type
+
+ // Take care of eventual memory argument
+ if (args->arg_type[i] == INT_RESULT && args->args[i])
+ more += (ulong)*(longlong*)args->args[i];
+
+ } // endfor i
+
+ initid->maybe_null = 1;
+ CalcLen(args, false, reslen, memlen);
+
+ if (args->args[0])
+ fl = GetFileLength(args->args[0]);
+ else
+ fl = 100; // What can be done here?
+
+ reslen += fl;
+
+ if (initid->const_item)
+ more += fl;
+
+ if (args->arg_count > 1)
+ more += fl * M;
+
+ memlen += more;
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of json_file_init
+
+char *json_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *str, *fn;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ str = (char*)g->Xchk;
+ goto fin;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ fn = MakePSZ(g, args, 0);
+
+ if (args->arg_count > 1) {
+ int pretty = 3, pty = 3;
+ size_t len;
+ PJSON jsp;
+ PJVAL jvp = NULL;
+
+ for (unsigned int i = 1; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
+ pretty = (int) * (longlong*)args->args[i];
+ break;
+ } // endif type
+
+ /*******************************************************************************/
+ /* Parse the json file and allocate its tree structure. */
+ /*******************************************************************************/
+ if (!(jsp = ParseJsonFile(g, fn, &pty, len))) {
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ goto fin;
+ } // endif jsp
+
+ if (pty == 3)
+ PUSH_WARNING("File pretty format cannot be determined");
+ else if (pretty != 3 && pty != pretty)
+ PUSH_WARNING("File pretty format doesn't match the specified pretty value");
+ else if (pretty == 3)
+ pretty = pty;
+
+ // Check whether a path was specified
+ if (CheckPath(g, args, jsp, jvp, 1)) {
+ PUSH_WARNING(g->Message);
+ str = NULL;
+ goto fin;
+ } else if (jvp)
+ jsp = jvp->GetJson();
+
+ if (!(str = Serialize(g, jsp, NULL, 0)))
+ PUSH_WARNING(g->Message);
+
+ } else
+ if (!(str = GetJsonFile(g, fn)))
+ PUSH_WARNING(g->Message);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = str;
+
+ fin:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of json_file
+
+void json_file_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_file_deinit
+
+/*********************************************************************************/
+/* Make a json file from a json item. */
+/*********************************************************************************/
+my_bool jfile_make_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 1 || args->arg_count > 3) {
+ strcpy(message, "Wrong number of arguments");
+ return true;
+ } else if (!IsJson(args, 0) && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } // endif
+
+ CalcLen(args, false, reslen, memlen);
+ memlen = memlen + 5000; // To take care of not pretty files
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of jfile_make_init
+
+char *jfile_make(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *p, *str = NULL, *fn = NULL;
+ int n, pretty = 2;
+ PJSON jsp;
+ PJVAL jvp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ str = (char*)g->Activityp;
+ goto fin;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if ((n = IsJson(args, 0)) == 3) {
+ // Get default file name and pretty
+ PBSON bsp = (PBSON)args->args[0];
+
+ fn = bsp->Filename;
+ pretty = bsp->Pretty;
+ } else if (n == 2)
+ fn = args->args[0];
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto fin;
+ } else
+ jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!strchr("[{ \t\r\n", *p)) {
+ // Is this a file name?
+ if (!(p = GetJsonFile(g, p))) {
+ PUSH_WARNING(g->Message);
+ goto fin;
+ } else
+ fn = jvp->GetString(g);
+
+ } // endif p
+
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ goto fin;
+ } // endif jsp
+
+ jvp->SetValue(jsp);
+ } // endif p
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jvp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jvp = (PJVAL)g->Xchk;
+
+ for (uint i = 1; i < args->arg_count; i++)
+ switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ fn = MakePSZ(g, args, i);
+ break;
+ case INT_RESULT:
+ pretty = (int)*(longlong*)args->args[i];
+ break;
+ default:
+ PUSH_WARNING("Unexpected argument type in jfile_make");
+ } // endswitch arg_type
+
+ if (fn) {
+ if (!Serialize(g, jvp->GetJson(), fn, pretty))
+ PUSH_WARNING(g->Message);
+ } else
+ PUSH_WARNING("Missing file name");
+
+ str= fn;
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)str;
+
+ fin:
+ if (!str) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of jfile_make
+
+void jfile_make_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jfile_make_deinit
+
+/*********************************************************************************/
+/* Make and return a binary Json array containing all the parameters. */
+/*********************************************************************************/
+my_bool jbin_array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, false, reslen, memlen);
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of jbin_array_init
+
+char *jbin_array(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp || bsp->Changed) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false)) {
+ PJAR arp;
+
+ if ((arp = (PJAR)JsonNew(g, TYPE_JAR)) &&
+ (bsp = JbinAlloc(g, args, initid->max_length, arp))) {
+ strcat(bsp->Msg, " array");
+
+ for (uint i = 0; i < args->arg_count; i++)
+ arp->AddArrayValue(g, MakeValue(g, args, i));
+
+ arp->InitArray(g);
+ } // endif arp && bsp
+
+ } else
+ bsp = NULL;
+
+ if (!bsp && (bsp = JbinAlloc(g, args, initid->max_length, NULL)))
+ strncpy(bsp->Msg, g->Message, BMX);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_array
+
+void jbin_array_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_array_deinit
+
+/*********************************************************************************/
+/* Add one or several values to a Json array. */
+/*********************************************************************************/
+my_bool jbin_array_add_values_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of jbin_array_add_values_init
+
+char *jbin_array_add_values(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp || bsp->Changed) {
+ if (!CheckMemory(g, initid, args, args->arg_count, true)) {
+ PJSON top;
+ PJAR arp;
+ PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JAR, &top);
+ PGLOBAL gb = GetMemPtr(g, args, 0);
+
+ if (jvp->GetValType() != TYPE_JAR) {
+ if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
+ arp->AddArrayValue(gb, jvp);
+ top = arp;
+ } // endif arp
+
+ } else
+ arp = jvp->GetArray();
+
+ for (uint i = 1; i < args->arg_count; i++)
+ arp->AddArrayValue(gb, MakeValue(gb, args, i));
+
+ arp->InitArray(gb);
+
+ if ((bsp = JbinAlloc(g, args, initid->max_length, top))) {
+ strcat(bsp->Msg, " array");
+ bsp->Jsp = arp;
+ } // endif bsp
+
+ } else
+ if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
+ strncpy(bsp->Msg, g->Message, BMX);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_array_add_values
+
+void jbin_array_add_values_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_array_add_values_deinit
+
+/*********************************************************************************/
+/* Add one value to a Json array. */
+/*********************************************************************************/
+my_bool jbin_array_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ //} else if (!IsJson(args, 0)) {
+ // strcpy(message, "First argument must be a json item");
+ // return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of jbin_array_add_init
+
+char *jbin_array_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ int n = 2;
+ PJSON top = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (bsp && !bsp->Changed) {
+ // This constant function was recalled
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } // endif bsp
+
+ if (!CheckMemory(g, initid, args, 2, false, false, true)) {
+ int *x = NULL;
+ uint n = 2;
+// PJSON jsp;
+ PJVAL jvp;
+ PJAR arp;
+
+ jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
+ // jsp = jvp->GetJson();
+ x = GetIntArgPtr(g, args, n);
+
+ if (CheckPath(g, args, top, jvp, n))
+ PUSH_WARNING(g->Message);
+ else if (jvp) {
+ PGLOBAL gb = GetMemPtr(g, args, 0);
+
+ if (jvp->GetValType() != TYPE_JAR) {
+ if ((arp = (PJAR)JsonNew(gb, TYPE_JAR))) {
+ arp->AddArrayValue(gb, (PJVAL)JvalNew(gb, TYPE_JVAL, jvp));
+ jvp->SetValue(arp);
+
+ if (!top)
+ top = arp;
+
+ } // endif arp
+
+ } else
+ arp = jvp->GetArray();
+
+ arp->AddArrayValue(gb, MakeValue(gb, args, 1), x);
+ arp->InitArray(gb);
+ } else {
+ PUSH_WARNING("First argument target is not an array");
+// if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error unchanged argument will be returned
+ bsp = MakeBinResult(g, args, top, initid->max_length, n);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_array_add
+
+void jbin_array_add_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_array_add_deinit
+
+/*********************************************************************************/
+/* Delete a value from a Json array. */
+/*********************************************************************************/
+my_bool jbin_array_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+ } // end of jbin_array_delete_init
+
+char *jbin_array_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PJSON top = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (bsp && !bsp->Changed) {
+ // This constant function was recalled
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } // endif bsp
+
+ if (!CheckMemory(g, initid, args, 1, false, false, true)) {
+ int *x;
+ uint n = 1;
+ PJAR arp;
+ PJVAL jvp = MakeTypedValue(g, args, 0, TYPE_JSON, &top);
+
+ if (CheckPath(g, args, top, jvp, 1))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->GetValType() == TYPE_JAR) {
+ if ((x = GetIntArgPtr(g, args, n))) {
+ arp = jvp->GetArray();
+ arp->DeleteValue(*x);
+ arp->InitArray(GetMemPtr(g, args, 0));
+ } else
+ PUSH_WARNING("Missing or null array index");
+
+ } else {
+ PUSH_WARNING("First argument target is not an array");
+// if (g->Mrr) *error = 1;
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error unchanged argument will be returned
+ bsp = MakeBinResult(g, args, top, initid->max_length);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_array_delete
+
+void jbin_array_delete_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_array_delete_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all the parameters. */
+/*********************************************************************************/
+my_bool jbin_object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of jbin_object_init
+
+char *jbin_object(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp || bsp->Changed) {
+ if (!CheckMemory(g, initid, args, args->arg_count, true)) {
+ PJOB objp;
+
+ if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i++)
+ objp->SetKeyValue(g, MakeValue(g, args, i), MakeKey(g, args, i));
+
+
+ if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
+ strcat(bsp->Msg, " object");
+
+ } else
+ bsp = NULL;
+
+ } else
+ if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
+ strncpy(bsp->Msg, g->Message, BMX);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_object
+
+void jbin_object_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_object_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all not null parameters. */
+/*********************************************************************************/
+my_bool jbin_object_nonull_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of jbin_object_nonull_init
+
+char *jbin_object_nonull(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp || bsp->Changed) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
+ PJVAL jvp;
+ PJOB objp;
+
+ if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i++)
+ if (!(jvp = MakeValue(g, args, i))->IsNull())
+ objp->SetKeyValue(g, jvp, MakeKey(g, args, i));
+
+ if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
+ strcat(bsp->Msg, " object");
+
+ } else
+ bsp = NULL;
+
+ } else
+ if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
+ strncpy(bsp->Msg, g->Message, BMX);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_object_nonull
+
+void jbin_object_nonull_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_object_nonull_deinit
+
+/*********************************************************************************/
+/* Make a Json Object containing all the key/value parameters. */
+/*********************************************************************************/
+my_bool jbin_object_key_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count % 2) {
+ strcpy(message, "This function must have an even number of arguments");
+ return true;
+ } // endif arg_count
+
+ CalcLen(args, true, reslen, memlen);
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of jbin_object_key_init
+
+char *jbin_object_key(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp || bsp->Changed) {
+ if (!CheckMemory(g, initid, args, args->arg_count, false, true)) {
+ PJOB objp;
+
+ if ((objp = (PJOB)JsonNew(g, TYPE_JOB))) {
+ for (uint i = 0; i < args->arg_count; i += 2)
+ objp->SetKeyValue(g, MakeValue(g, args, i + 1), MakePSZ(g, args, i));
+
+ if ((bsp = JbinAlloc(g, args, initid->max_length, objp)))
+ strcat(bsp->Msg, " object");
+
+ } else
+ bsp = NULL;
+
+ } else
+ if ((bsp = JbinAlloc(g, args, initid->max_length, NULL)))
+ strncpy(bsp->Msg, g->Message, BMX);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_object_key
+
+void jbin_object_key_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_object_key_deinit
+
+/*********************************************************************************/
+/* Add or replace a value in a Json Object. */
+/*********************************************************************************/
+my_bool jbin_object_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else if (!IsJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen, true);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+ } // end of jbin_object_add_init
+
+char *jbin_object_add(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PJSON top = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (bsp && !bsp->Changed) {
+ // This constant function was recalled
+ bsp = (PBSON)g->Xchk;
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } // endif bsp
+
+ if (!CheckMemory(g, initid, args, 2, false, true, true)) {
+ PCSZ key;
+ PJOB jobp;
+ PJVAL jvp = MakeValue(g, args, 0, &top);
+ PJSON jsp = jvp->GetJson();
+
+ if (CheckPath(g, args, jsp, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->GetValType() == TYPE_JOB) {
+ PGLOBAL gb = GetMemPtr(g, args, 0);
+
+ jobp = jvp->GetObject();
+ jvp = MakeValue(gb, args, 1);
+ key = MakeKey(gb, args, 1);
+ jobp->SetKeyValue(gb, jvp, key);
+ } else {
+ PUSH_WARNING("First argument target is not an object");
+// if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error unchanged argument will be returned
+ bsp = MakeBinResult(g, args, top, initid->max_length);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_object_add
+
+void jbin_object_add_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_object_add_deinit
+
+/*********************************************************************************/
+/* Delete a value from a Json object. */
+/*********************************************************************************/
+my_bool jbin_object_delete_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have 2 or 3 arguments");
+ return true;
+ } else if (!IsJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument must be a key string");
+ return true;
+ } else
+ CalcLen(args, true, reslen, memlen, true);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+ } // end of jbin_object_delete_init
+
+char *jbin_object_delete(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PJSON top = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (bsp && !bsp->Changed) {
+ // This constant function was recalled
+ bsp = (PBSON)g->Xchk;
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } // endif bsp
+
+ if (!CheckMemory(g, initid, args, 1, false, true, true)) {
+ PCSZ key;
+ PJOB jobp;
+ PJVAL jvp = MakeValue(g, args, 0, &top);
+ (void) jvp->GetJson(); // XXX Should be removed?
+
+ if (CheckPath(g, args, top, jvp, 2))
+ PUSH_WARNING(g->Message);
+ else if (jvp && jvp->GetValType() == TYPE_JOB) {
+ key = MakeKey(g, args, 1);
+ jobp = jvp->GetObject();
+ jobp->DeleteKey(key);
+ } else {
+ PUSH_WARNING("First argument target is not an object");
+// if (g->Mrr) *error = 1; (only if no path)
+ } // endif jvp
+
+ } // endif CheckMemory
+
+ // In case of error unchanged argument will be returned
+ bsp = MakeBinResult(g, args, top, initid->max_length);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_object_delete
+
+void jbin_object_delete_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_object_delete_deinit
+
+/*********************************************************************************/
+/* Returns an array of the Json object keys. */
+/*********************************************************************************/
+my_bool jbin_object_list_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return json_object_list_init(initid, args, message);
+} // end of jbin_object_list_init
+
+char *jbin_object_list(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PJAR jarp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (!bsp || bsp->Changed) {
+ if (!CheckMemory(g, initid, args, 1, true, true)) {
+ char *p;
+ PJSON jsp;
+ PJVAL jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ return NULL;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (jsp->GetType() == TYPE_JOB) {
+ jarp = ((PJOB)jsp)->GetKeyList(g);
+ } else {
+ PUSH_WARNING("First argument is not an object");
+ if (g->Mrr) *error = 1;
+ } // endif jsp type
+
+ } // endif CheckMemory
+
+ if ((bsp = JbinAlloc(g, args, initid->max_length, jarp)))
+ strcat(bsp->Msg, " array");
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? bsp : NULL;
+ } // endif bsp
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_object_list
+
+void jbin_object_list_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_object_list_deinit
+
+/*********************************************************************************/
+/* Get a Json item from a Json document. */
+/*********************************************************************************/
+my_bool jbin_get_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return json_get_item_init(initid, args, message);
+} // end of jbin_get_item_init
+
+char *jbin_get_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *path;
+ PJSON jsp;
+ PJSNX jsx;
+ PJVAL jvp;
+ PBSON bsp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (g->N) {
+ bsp = (PBSON)g->Activityp;
+ goto fin;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto fin;
+ } // endif CheckMemory
+
+ jvp = MakeTypedValue(g, args, 0, TYPE_JSON);
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ path = MakePSZ(g, args, 1);
+ jsx = JsnxNew(g, jsp, TYPE_STRING, initid->max_length);
+
+ if (!jsx || jsx->SetJpath(g, path, false)) {
+ PUSH_WARNING(g->Message);
+ goto fin;
+ } // endif SetJpath
+
+ // Get the json tree
+ if ((jvp = jsx->GetRowValue(g, jsp, 0, false))) {
+ jsp = (jvp->GetJsp()) ? jvp->GetJsp() : JvalNew(g, TYPE_JVAL, jvp->GetValue(g));
+
+ if ((bsp = JbinAlloc(g, args, initid->max_length, jsp)))
+ strcat(bsp->Msg, " item");
+ else
+ *error = 1;
+
+ } // endif jvp
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)bsp;
+
+ fin:
+ if (!bsp) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_get_item
+
+void jbin_get_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_get_item_deinit
+
+/*********************************************************************************/
+/* Merge two arrays or objects. */
+/*********************************************************************************/
+my_bool jbin_item_merge_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count < 2) {
+ strcpy(message, "This function must have at least 2 arguments");
+ return true;
+ } else if (!IsJson(args, 0)) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else if (!IsJson(args, 1)) {
+ strcpy(message, "Second argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ return JsonInit(initid, args, message, true, reslen, memlen);
+ } // end of jbin_item_merge_init
+
+char *jbin_item_merge(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ PJSON top = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (bsp && !bsp->Changed) {
+ // This constant function was recalled
+ *res_length = sizeof(BSON);
+ return (char*)bsp;
+ } // endif bsp
+
+ if (!CheckMemory(g, initid, args, 2, false, false, true)) {
+ PJVAL jvp;
+ PJSON jsp[2] = {NULL, NULL};
+ PGLOBAL gb = GetMemPtr(g, args, 0);
+
+ for (int i = 0; i < 2; i++) {
+ jvp = MakeValue(g, args, i);
+ if (!i) top = jvp->GetJson();
+
+ if (jvp->GetValType() != TYPE_JAR && jvp->GetValType() != TYPE_JOB) {
+ sprintf(g->Message, "Argument %d is not an array or object", i);
+ PUSH_WARNING(g->Message);
+ } else
+ jsp[i] = jvp->GetJsp();
+
+ } // endfor i
+
+ if (jsp[0] && jsp[0]->Merge(gb, jsp[1]))
+ PUSH_WARNING(gb->Message);
+
+ } // endif CheckMemory
+
+ // In case of error unchanged first argument will be returned
+ bsp = MakeBinResult(g, args, top, initid->max_length);
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ if (!bsp) {
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_item_merge
+
+void jbin_item_merge_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_item_merge_deinit
+
+/*********************************************************************************/
+/* This function is used by the jbin_set/insert/update functions. */
+/*********************************************************************************/
+char *bin_handle_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *p, *path;
+ int w;
+ my_bool b = true;
+ PJSON jsp;
+ PJSNX jsx;
+ PJVAL jvp = NULL;
+ PBSON bsp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PGLOBAL gb = GetMemPtr(g, args, 0);
+
+ if (g->N) {
+ bsp = (PBSON)g->Activityp;
+ goto fin;
+ } else if (initid->const_item)
+ g->N = 1;
+
+ if (!strcmp(result, "$set"))
+ w = 0;
+ else if (!strcmp(result, "$insert"))
+ w = 1;
+ else if (!strcmp(result, "$update"))
+ w = 2;
+ else {
+ PUSH_WARNING("Logical error, please contact CONNECT developer");
+ goto fin;
+ } // endelse
+
+ if (!g->Xchk) {
+ if (CheckMemory(g, initid, args, 1, true, false, true)) {
+ PUSH_WARNING("CheckMemory error");
+ goto fin;
+ } else
+ jvp = MakeValue(g, args, 0);
+
+ if ((p = jvp->GetString(g))) {
+ if (!(jsp = ParseJson(g, p, strlen(p)))) {
+ PUSH_WARNING(g->Message);
+ goto fin;
+ } // endif jsp
+
+ } else
+ jsp = jvp->GetJson();
+
+ if (g->Mrr) { // First argument is a constant
+ g->Xchk = jsp;
+ JsonMemSave(g);
+ } // endif Mrr
+
+ } else
+ jsp = (PJSON)g->Xchk;
+
+ jsx = new(g)JSNX(g, jsp, TYPE_STRING, initid->max_length, 0, true);
+
+ for (uint i = 1; i+1 < args->arg_count; i += 2) {
+ jvp = MakeValue(gb, args, i);
+ path = MakePSZ(g, args, i+1);
+
+ if (jsx->SetJpath(g, path, false)) {
+ PUSH_WARNING(g->Message);
+ continue;
+ } // endif SetJpath
+
+ if (w) {
+ jsx->ReadValue(g);
+ b = jsx->GetValue()->IsNull();
+ b = (w == 1) ? b : !b;
+ } // endif w
+
+ if (b && jsx->WriteValue(gb, jvp))
+ PUSH_WARNING(g->Message);
+
+ } // endfor i
+
+ if (!(bsp = MakeBinResult(g, args, jsp, initid->max_length, INT_MAX32)))
+ *error = 1;
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Activityp = (PACTIVITY)bsp;
+
+fin:
+ if (!bsp) {
+ *is_null = 1;
+ *res_length = 0;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of bin_handle_item
+
+/*********************************************************************************/
+/* Set Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool jbin_set_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, more = 0;
+ int n = IsJson(args, 0);
+
+ if (!(args->arg_count % 2)) {
+ strcpy(message, "This function must have an odd number of arguments");
+ return true;
+ } else if (!n && args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be a json item");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ if (n == 2 && args->args[0]) {
+ char fn[_MAX_PATH];
+ long fl;
+
+ memcpy(fn, args->args[0], args->lengths[0]);
+ fn[args->lengths[0]] = 0;
+ fl = GetFileLength(fn);
+ more = fl * 3;
+ } else if (n != 3)
+ more = args->lengths[0] * 3;
+
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+ } // end of jbin_set_item_init
+
+char *jbin_set_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$set");
+ return bin_handle_item(initid, args, result, res_length, is_null, p);
+} // end of jbin_set_item
+
+void jbin_set_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_set_item_deinit
+
+/*********************************************************************************/
+/* Insert Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool jbin_insert_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return json_set_item_init(initid, args, message);
+} // end of jbin_insert_item_init
+
+char *jbin_insert_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$insert");
+ return bin_handle_item(initid, args, result, res_length, is_null, p);
+} // end of jbin_insert_item
+
+void jbin_insert_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_insert_item_deinit
+
+/*********************************************************************************/
+/* Update Json items of a Json document according to path. */
+/*********************************************************************************/
+my_bool jbin_update_item_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ return json_set_item_init(initid, args, message);
+} // end of jbin_update_item_init
+
+char *jbin_update_item(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *p)
+{
+ strcpy(result, "$update");
+ return bin_handle_item(initid, args, result, res_length, is_null, p);
+} // end of jbin_update_item
+
+void jbin_update_item_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_update_item_deinit
+
+/*********************************************************************************/
+/* Returns a json file as a json item. */
+/*********************************************************************************/
+my_bool jbin_file_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen, fl, more = 1024;
+
+ if (args->arg_count < 1 || args->arg_count > 4) {
+ strcpy(message, "This function only accepts 1 to 4 arguments");
+ return true;
+ } else if (args->arg_type[0] != STRING_RESULT || !args->args[0]) {
+ strcpy(message, "First argument must be a constant string (file name)");
+ return true;
+ } // endifs
+
+ for (unsigned int i = 1; i < args->arg_count; i++) {
+ if (!(args->arg_type[i] == INT_RESULT || args->arg_type[i] == STRING_RESULT)) {
+ sprintf(message, "Argument %d is not an integer or a string (pretty or path)", i);
+ return true;
+ } // endif arg_type
+
+ // Take care of eventual memory argument
+ if (args->arg_type[i] == INT_RESULT && args->args[i])
+ more += (ulong) * (longlong*)args->args[i];
+
+ } // endfor i
+
+ initid->maybe_null = 1;
+ CalcLen(args, false, reslen, memlen);
+ fl = GetFileLength(args->args[0]);
+ reslen += fl;
+ more += fl * M;
+//memlen += more;
+ return JsonInit(initid, args, message, true, reslen, memlen, more);
+} // end of jbin_file_init
+
+char *jbin_file(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *error)
+{
+ char *fn;
+ int pretty = 3, pty = 3;
+ size_t len = 0;
+ PJSON jsp;
+ PJVAL jvp = NULL;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ PBSON bsp = (PBSON)g->Xchk;
+
+ if (bsp && !bsp->Changed)
+ goto fin;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ g->Xchk = NULL;
+ fn = MakePSZ(g, args, 0);
+
+ for (unsigned int i = 1; i < args->arg_count; i++)
+ if (args->arg_type[i] == INT_RESULT && *(longlong*)args->args[i] < 4) {
+ pretty = (int) * (longlong*)args->args[i];
+ break;
+ } // endif type
+
+ /*********************************************************************************/
+ /* Parse the json file and allocate its tree structure. */
+ /*********************************************************************************/
+ if (!(jsp = ParseJsonFile(g, fn, &pty, len))) {
+ PUSH_WARNING(g->Message);
+ *error = 1;
+ goto fin;
+ } // endif jsp
+
+ if (pty == 3)
+ PUSH_WARNING("File pretty format cannot be determined");
+ else if (pretty != 3 && pty != pretty)
+ PUSH_WARNING("File pretty format doesn't match the specified pretty value");
+ else if (pretty == 3)
+ pretty = pty;
+
+ if ((bsp = JbinAlloc(g, args, len, jsp))) {
+ strcat(bsp->Msg, " file");
+ bsp->Filename = fn;
+ bsp->Pretty = pretty;
+ } else {
+ *error = 1;
+ goto fin;
+ } // endif bsp
+
+ // Check whether a path was specified
+ if (CheckPath(g, args, jsp, jvp, 1)) {
+ PUSH_WARNING(g->Message);
+ bsp = NULL;
+ goto fin;
+ } else if (jvp)
+ bsp->Jsp = jvp->GetJsp();
+
+ if (initid->const_item)
+ // Keep result of constant function
+ g->Xchk = bsp;
+
+ fin:
+ if (!bsp) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = sizeof(BSON);
+
+ return (char*)bsp;
+} // end of jbin_file
+
+void jbin_file_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jbin_file_deinit
+
+/*********************************************************************************/
+/* Serialize a Json document. . */
+/*********************************************************************************/
+my_bool json_serialize_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 1) {
+ strcpy(message, "This function must have 1 argument");
+ return true;
+ } else if (args->args[0] && IsJson(args, 0) != 3) {
+ strcpy(message, "Argument must be a Jbin tree");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen);
+
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of json_serialize_init
+
+char *json_serialize(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *error)
+{
+ char *str;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ if (!g->Xchk) {
+ if (IsJson(args, 0) == 3) {
+ PBSON bsp = (PBSON)args->args[0];
+
+ JsonSubSet(g);
+
+ if (!(str = Serialize(g, bsp->Jsp, NULL, 0)))
+ str = strcpy(result, g->Message);
+
+ // Keep result of constant function
+ g->Xchk = (initid->const_item) ? str : NULL;
+ } else {
+ // *error = 1;
+ str = strcpy(result, "Argument is not a Jbin tree");
+ } // endif
+
+ } else
+ str = (char*)g->Xchk;
+
+ *res_length = strlen(str);
+ return str;
+} // end of json_serialize
+
+void json_serialize_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of json_serialize_deinit
+
+/*********************************************************************************/
+/* Convert a prettiest Json file to Pretty=0. */
+/*********************************************************************************/
+my_bool jfile_convert_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 3) {
+ strcpy(message, "This function must have 3 arguments");
+ return true;
+ } else if (args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third Argument must be an integer (LRECL)");
+ return true;
+ } else for (int i = 0; i < 2; i++)
+ if (args->arg_type[i] != STRING_RESULT) {
+ sprintf(message, "Arguments %d must be a string (file name)", i+1);
+ return true;
+ } // endif args
+
+ CalcLen(args, false, reslen, memlen);
+ return JsonInit(initid, args, message, true, reslen, memlen);
+} // end of jfile_convert_init
+
+char *jfile_convert(UDF_INIT* initid, UDF_ARGS* args, char* result,
+ unsigned long *res_length, char *is_null, char *error) {
+ char *str, *fn, *ofn;
+ int lrecl = (int)*(longlong*)args->args[2];
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ fn = MakePSZ(g, args, 0);
+ ofn = MakePSZ(g, args, 1);
+
+ if (!g->Xchk) {
+ JUP* jup = new(g) JUP(g);
+
+ str = jup->UnprettyJsonFile(g, fn, ofn, lrecl);
+ g->Xchk = str;
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ PUSH_WARNING(g->Message[0] != '\0' ? g->Message : "Unexpected error");
+ *is_null = 1;
+ *error = 1;
+ *res_length = 0;
+ } else {
+ strcpy(result, str);
+ *res_length = strlen(str);
+ } // endif str
+
+ return str;
+} // end of jfile_convert
+
+void jfile_convert_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jfile_convert_deinit
+
+/*********************************************************************************/
+/* Convert a prettiest Json file to Pretty=0. */
+/*********************************************************************************/
+my_bool jfile_bjson_init(UDF_INIT* initid, UDF_ARGS* args, char* message) {
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 2 && args->arg_count != 3) {
+ strcpy(message, "This function must have 2 or 3 arguments");
+ return true;
+ } else if (args->arg_count == 3 && args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "Third Argument must be an integer (LRECL)");
+ return true;
+ } else for (int i = 0; i < 2; i++)
+ if (args->arg_type[i] != STRING_RESULT) {
+ sprintf(message, "Arguments %d must be a string (file name)", i + 1);
+ return true;
+ } // endif args
+
+ CalcLen(args, false, reslen, memlen);
+ memlen = memlen * M;
+ memlen += (args->arg_count == 3) ? (ulong)*(longlong*)args->args[2] : 1024;
+ return JsonInit(initid, args, message, false, reslen, memlen);
+} // end of jfile_bjson_init
+
+char *jfile_bjson(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char*, char *error) {
+ char *fn, *ofn, *buf, *str = NULL;
+ bool loop;
+ ssize_t len, newloc;
+ size_t lrecl, *binszp;
+ PJSON jsp;
+ SWAP *swp;
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ fn = MakePSZ(g, args, 0);
+ ofn = MakePSZ(g, args, 1);
+
+ if (args->arg_count == 3)
+ lrecl = (size_t)*(longlong*)args->args[2];
+ else
+ lrecl = 1024;
+
+ if (!g->Xchk) {
+ int msgid = MSGID_OPEN_MODE_STRERROR;
+ FILE *fout = NULL;
+ FILE *fin;
+
+ if (!(fin = global_fopen(g, msgid, fn, "rt")))
+ str = strcpy(result, g->Message);
+ else if (!(fout = global_fopen(g, msgid, ofn, "wb")))
+ str = strcpy(result, g->Message);
+ else if ((buf = (char*)PlgDBSubAlloc(g, NULL, lrecl)) &&
+ (binszp = (size_t*)PlgDBSubAlloc(g, NULL, sizeof(size_t)))) {
+ JsonMemSave(g);
+
+ try {
+ do {
+ loop = false;
+ JsonSubSet(g);
+
+ if (!fgets(buf, lrecl, fin)) {
+ if (!feof(fin)) {
+ sprintf(g->Message, "Error %d reading %zd bytes from %s", errno, lrecl, fn);
+ str = strcpy(result, g->Message);
+ } else
+ str = strcpy(result, ofn);
+
+ } else if ((len = strlen(buf))) {
+ if ((jsp = ParseJson(g, buf, len))) {
+ newloc = (size_t)PlugSubAlloc(g, NULL, 0);
+ *binszp = newloc - (size_t)jsp;
+
+ swp = new(g) SWAP(g, jsp);
+ swp->SwapJson(jsp, true);
+
+ if (fwrite(binszp, sizeof(binszp), 1, fout) != 1) {
+ sprintf(g->Message, "Error %d writing %zd bytes to %s",
+ errno, sizeof(binszp), ofn);
+ str = strcpy(result, g->Message);
+ } else if (fwrite(jsp, *binszp, 1, fout) != 1) {
+ sprintf(g->Message, "Error %d writing %zd bytes to %s",
+ errno, *binszp, ofn);
+ str = strcpy(result, g->Message);
+ } else
+ loop = true;
+
+ } else {
+ str = strcpy(result, g->Message);
+ } // endif jsp
+
+ } else
+ loop = true;
+
+ } while (loop);
+
+ } catch (int) {
+ str = strcpy(result, g->Message);
+ } catch (const char* msg) {
+ str = strcpy(result, msg);
+ } // end catch
+
+ } else
+ str = strcpy(result, g->Message);
+
+ if (fin) fclose(fin);
+ if (fout) fclose(fout);
+ g->Xchk = str;
+ } else
+ str = (char*)g->Xchk;
+
+ if (!str) {
+ if (g->Message[0] != '\0')
+ str = strcpy(result, g->Message);
+ else
+ str = strcpy(result, "Unexpected error");
+
+ } // endif str
+
+ *res_length = strlen(str);
+ return str;
+} // end of jfile_bjson
+
+void jfile_bjson_deinit(UDF_INIT* initid) {
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of jfile_bjson_deinit
+
+/* --------------------------------- Class JUP --------------------------------- */
+
+#define ARGS MY_MIN(24,(int)len-i),s+MY_MAX(i-3,0)
+
+/*********************************************************************************/
+/* JUP public constructor. */
+/*********************************************************************************/
+JUP::JUP(PGLOBAL g) {
+ fs = NULL;
+ s = buff = NULL;
+ len = 0;
+ k = recl = 0;
+ i = 0;
+} // end of JUP constructor
+
+/*********************************************************************************/
+/* Copy a json file to another with pretty = 0. */
+/*********************************************************************************/
+char* JUP::UnprettyJsonFile(PGLOBAL g, char *fn, char *outfn, int lrecl) {
+ char *ret = NULL;
+ HANDLE hFile;
+ MEMMAP mm;
+
+ /*******************************************************************************/
+ /* Create the mapping file object. */
+ /*******************************************************************************/
+ hFile = CreateFileMap(g, fn, &mm, MODE_READ, false);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DWORD rc = GetLastError();
+
+ if (!(*g->Message))
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR), "map", (int)rc, fn);
+
+ return NULL;
+ } // endif hFile
+
+ /*******************************************************************************/
+ /* Get the file size (assuming file is smaller than 4 GB) */
+ /*******************************************************************************/
+ if (!mm.lenL && !mm.lenH) { // Empty or deleted file
+ CloseFileHandle(hFile);
+ return NULL;
+ } else {
+ len = (size_t)mm.lenL;
+
+ if (mm.lenH)
+ len += ((size_t)mm.lenH * 0x000000001LL);
+
+ } // endif size
+
+ if (!mm.memory) {
+ CloseFileHandle(hFile);
+ sprintf(g->Message, MSG(MAP_VIEW_ERROR), fn, GetLastError());
+ return NULL;
+ } else
+ s = (char*)mm.memory;
+
+ CloseFileHandle(hFile); // Not used anymore
+
+ /*********************************************************************************/
+ /* Parse the json file and allocate its tree structure. */
+ /*********************************************************************************/
+ if (!(fs = fopen(outfn, "wb"))) {
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "w", (int)errno, outfn);
+ strcat(strcat(g->Message, ": "), strerror(errno));
+ CloseMemMap(mm.memory, len);
+ return NULL;
+ } // endif fs
+
+ g->Message[0] = 0;
+
+ if (!unPretty(g, lrecl))
+ ret = outfn;
+
+ CloseMemMap(mm.memory, len);
+ fclose(fs);
+ return ret;
+} // end of UnprettyJsonFile
+
+/***********************************************************************/
+/* Translate a json file to pretty = 0. */
+/***********************************************************************/
+bool JUP::unPretty(PGLOBAL g, int lrecl) {
+ bool go, next, rc = false;
+
+ if (trace(1))
+ htrc("UnPretty: s=%.10s len=%zd lrecl=%d\n", s, len, lrecl);
+
+ if (!s || !len) {
+ strcpy(g->Message, "Void JSON file");
+ return true;
+ } else if (*s != '[') {
+ // strcpy(g->Message, "JSON file is not an array");
+ s = strchr(s, '[');
+ // return true;
+ } // endif s
+
+ i = 1;
+ go = next = true;
+
+ try {
+ // Allocate the record
+ buff = (char*)PlugSubAlloc(g, NULL, (size_t)lrecl + 3);
+ recl = lrecl;
+
+ do {
+ for (k = 0; go && i < len; i++)
+ switch (s[i]) {
+ case '{':
+ buff[k++] = s[i++];
+ CopyObject(g);
+ break;
+ case '[':
+ throw "JSON file is not an array of objects";
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ case ',':
+ go = false;
+ break;
+ case ']':
+ go = next = false;
+ break;
+ default:
+ sprintf(g->Message, "Unexpected '%c' near %.*s", s[i], ARGS);
+ throw 4;
+ break;
+ }; // endswitch s[i]
+
+ // Write the record
+#ifdef __win_
+ buff[k++] = '\r';
+#endif
+ buff[k++] = '\n';
+ buff[k] = 0;
+
+ if ((fputs(buff, fs)) == EOF) {
+ sprintf(g->Message, MSG(FPUTS_ERROR), strerror(errno));
+ throw 5;
+ } // endif EOF
+
+ go = true;
+ } while (next);
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ rc = true;
+ } catch (const char* msg) {
+ strcpy(g->Message, msg);
+ rc = true;
+ } // end catch
+
+ return rc;
+} // end of unPretty
+
+/***********************************************************************/
+/* Copy a JSON Object. */
+/***********************************************************************/
+void JUP::CopyObject(PGLOBAL g) {
+ int level = 0;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '"':
+ AddBuff(s[i++]);
+
+ if (level < 2) {
+ CopyString(g);
+ level = 1;
+ } else {
+ sprintf(g->Message, "misplaced string near %.*s", ARGS);
+ throw 3;
+ } // endif level
+
+ break;
+ case ':':
+ AddBuff(s[i++]);
+
+ if (level == 1) {
+ CopyValue(g);
+ level = 2;
+ } else {
+ sprintf(g->Message, "Unexpected ':' near %.*s", ARGS);
+ throw 3;
+ } // endif level
+
+ break;
+ case ',':
+ AddBuff(s[i]);
+
+ if (level < 2) {
+ sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
+ throw 3;
+ } else
+ level = 0;
+
+ break;
+ case '}':
+ AddBuff(s[i]);
+
+ if (level == 1) {
+ sprintf(g->Message, "Unexpected '}' near %.*s", ARGS);
+ throw 3;
+ } // endif level
+
+ return;
+ case '\n':
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS);
+ throw 3;
+ }; // endswitch s[i]
+
+ throw "Unexpected EOF in Object";
+} // end of CopyObject
+
+/***********************************************************************/
+/* Copy a JSON Array. */
+/***********************************************************************/
+void JUP::CopyArray(PGLOBAL g) {
+ int level = 0;
+
+ for (; i < len; i++)
+ switch (s[i]) {
+ case ',':
+ if (level < 2) {
+ sprintf(g->Message, "Unexpected ',' near %.*s", ARGS);
+ throw 2;
+ } else
+ level = 1;
+
+ AddBuff(s[i]);
+ break;
+ case ']':
+ if (level == 1) {
+ sprintf(g->Message, "Unexpected ',]' near %.*s", ARGS);
+ throw 2;
+ } // endif level
+
+ AddBuff(s[i]);
+ return;
+ case '\n':
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ if (level == 2) {
+ sprintf(g->Message, "Unexpected value near %.*s", ARGS);
+ throw 2;
+ } // endif level
+
+ CopyValue(g);
+ level = 2;
+ break;
+ }; // endswitch s[i]
+
+ throw "Unexpected EOF in array";
+} // end of CopyArray
+
+/***********************************************************************/
+/* Copy a JSON Value. */
+/***********************************************************************/
+void JUP::CopyValue(PGLOBAL g) {
+ for (; i < len; i++)
+ switch (s[i]) {
+ case '\n':
+ case '\r':
+ case ' ':
+ case '\t':
+ break;
+ default:
+ goto suite;
+ } // endswitch
+
+suite:
+ switch (s[i]) {
+ case '[':
+ AddBuff(s[i++]);
+ CopyArray(g);
+ break;
+ case '{':
+ AddBuff(s[i++]);
+ CopyObject(g);
+ break;
+ case '"':
+ AddBuff(s[i++]);
+ CopyString(g);
+ break;
+ case 't':
+ if (!strncmp(s + i, "true", 4)) {
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i]);
+ } else
+ goto err;
+
+ break;
+ case 'f':
+ if (!strncmp(s + i, "false", 5)) {
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i]);
+ } else
+ goto err;
+
+ break;
+ case 'n':
+ if (!strncmp(s + i, "null", 4)) {
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i++]);
+ AddBuff(s[i]);
+ } else
+ goto err;
+
+ break;
+ default:
+ if (s[i] == '-' || isdigit(s[i]))
+ CopyNumeric(g);
+ else
+ goto err;
+
+ }; // endswitch s[i]
+
+ return;
+
+err:
+ sprintf(g->Message, "Unexpected character '%c' near %.*s", s[i], ARGS);
+ throw 1;
+} // end of CopyValue
+
+/***********************************************************************/
+/* Unescape and parse a JSON string. */
+/***********************************************************************/
+void JUP::CopyString(PGLOBAL g) {
+ for (; i < len; i++) {
+ AddBuff(s[i]);
+
+ switch (s[i]) {
+ case '"':
+ return;
+ case '\\':
+ AddBuff(s[++i]);
+ break;
+ default:
+ break;
+ }; // endswitch s[i]
+
+ } // endfor i
+
+ throw "Unexpected EOF in String";
+} // end of CopyString
+
+/***********************************************************************/
+/* Copy a JSON numeric value. */
+/***********************************************************************/
+void JUP::CopyNumeric(PGLOBAL g) {
+ bool has_dot = false;
+ bool has_e = false;
+ bool found_digit = false;
+
+ for (; i < len; i++) {
+ switch (s[i]) {
+ case '.':
+ if (!found_digit || has_dot || has_e)
+ goto err;
+
+ has_dot = true;
+ break;
+ case 'e':
+ case 'E':
+ if (!found_digit || has_e)
+ goto err;
+
+ has_e = true;
+ found_digit = false;
+ break;
+ case '+':
+ if (!has_e)
+ goto err;
+
+ // fall through
+ case '-':
+ if (found_digit)
+ goto err;
+
+ break;
+ default:
+ if (isdigit(s[i])) {
+ found_digit = true;
+ } else
+ goto fin;
+
+ }; // endswitch s[i]
+
+ AddBuff(s[i]);
+ } // endfor i
+
+fin:
+ if (!found_digit)
+ throw "No digit found";
+ else
+ i--;
+
+ return;
+
+err:
+ throw "Unexpected EOF in number";
+} // end of CopyNumeric
+
+/*********************************************************************************/
+/* Utility function returning an environment variable value. */
+/*********************************************************************************/
+my_bool envar_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1) {
+ strcpy(message, "Unique argument must be an environment variable name");
+ return true;
+ } else {
+ initid->maybe_null = true;
+ return false;
+ } // endif count
+
+} // end of envar_init
+
+char *envar(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *str, name[256];
+ int n = MY_MIN(args->lengths[0], sizeof(name) - 1);
+
+ memcpy(name, args->args[0], n);
+ name[n] = 0;
+
+ if (!(str = getenv(name))) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of envar
+
+#if defined(DEVELOPMENT)
+extern char *GetUserVariable(PGLOBAL g, const uchar *varname);
+
+/*********************************************************************************/
+/* Utility function returning a user variable value. */
+/*********************************************************************************/
+my_bool uvar_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ unsigned long reslen, memlen;
+
+ if (args->arg_count != 1) {
+ strcpy(message, "Unique argument must be a user variable name");
+ return true;
+ } else
+ CalcLen(args, false, reslen, memlen, true);
+
+ initid->maybe_null = true;
+ return JsonInit(initid, args, message, true, reslen, memlen, 2048);
+} // end of uvar_init
+
+char *uvar(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *is_null, char *)
+{
+ char *str, varname[256];
+ PGLOBAL g = (PGLOBAL)initid->ptr;
+ int n = MY_MIN(args->lengths[0], sizeof(varname) - 1);
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ memcpy(varname, args->args[0], n);
+ varname[n] = 0;
+
+ if (!(str = GetUserVariable(g, (const uchar*)&varname))) {
+ *res_length = 0;
+ *is_null = 1;
+ } else
+ *res_length = strlen(str);
+
+ return str;
+} // end of uvar
+
+void uvar_deinit(UDF_INIT* initid)
+{
+ JsonFreeMem((PGLOBAL)initid->ptr);
+} // end of uvar_deinit
+#endif // DEVELOPMENT
+
+/*********************************************************************************/
+/* Returns the distinct number of B occurences in A. */
+/*********************************************************************************/
+my_bool countin_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 2) {
+ strcpy(message, "This function must have 2 arguments");
+ return true;
+ } else if (args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "First argument must be string");
+ return true;
+ } else if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message, "Second argument is not a string");
+ return true;
+ } // endif args
+
+ return false;
+} // end of countin_init
+
+long long countin(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *)
+{
+ PSZ str1, str2;
+ char *s;
+ long long n = 0;
+ size_t lg;
+
+ lg = (size_t)args->lengths[0];
+ s = str1 = (PSZ)malloc(lg + 1);
+ memcpy(str1, args->args[0], lg);
+ str1[lg] = 0;
+
+ lg = (size_t)args->lengths[1];
+ str2 = (PSZ)malloc(lg + 1);
+ memcpy(str2, args->args[1], lg);
+ str2[lg] = 0;
+
+ while ((s = strstr(s, str2))) {
+ n++;
+ s += lg;
+ } // endwhile
+
+ free(str1);
+ free(str2);
+ return n;
+} // end of countin
diff --git a/storage/connect/jsonudf.h b/storage/connect/jsonudf.h
new file mode 100644
index 00000000..ada0dbcd
--- /dev/null
+++ b/storage/connect/jsonudf.h
@@ -0,0 +1,411 @@
+/******************** tabjson H Declares Source Code File (.H) *******************/
+/* Name: jsonudf.h Version 1.4 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2015-2020 */
+/* */
+/* This file contains the JSON UDF function and class declares. */
+/*********************************************************************************/
+#pragma once
+#include "global.h"
+#include "plgdbsem.h"
+#include "block.h"
+#include "osutil.h"
+#include "maputil.h"
+#include "json.h"
+
+#define UDF_EXEC_ARGS \
+ UDF_INIT*, UDF_ARGS*, char*, unsigned long*, char*, char*
+
+// BSON size should be equal on Linux and Windows
+#define BMX 255
+typedef struct BSON* PBSON;
+
+/***********************************************************************/
+/* Structure used to return binary json to Json UDF functions. */
+/***********************************************************************/
+struct BSON {
+ char Msg[BMX + 1];
+ char *Filename;
+ PGLOBAL G;
+ int Pretty;
+ ulong Reslen;
+ my_bool Changed;
+ PJSON Top;
+ PJSON Jsp;
+ PBSON Bsp;
+}; // end of struct BSON
+
+PBSON JbinAlloc(PGLOBAL g, UDF_ARGS* args, ulong len, PJSON jsp);
+
+/*********************************************************************************/
+/* The JSON tree node. Can be an Object or an Array. */
+/*********************************************************************************/
+typedef struct _jnode {
+ PSZ Key; // The key used for object
+ OPVAL Op; // Operator used for this node
+ PVAL CncVal; // To cont value used for OP_CNC
+ int Rank; // The rank in array
+ int Rx; // Read row number
+ int Nx; // Next to read row number
+} JNODE, *PJNODE;
+
+typedef class JSNX *PJSNX;
+
+/*********************************************************************************/
+/* The JSON utility functions. */
+/*********************************************************************************/
+bool IsNum(PSZ s);
+char *NextChr(PSZ s, char sep);
+char *GetJsonNull(void);
+uint GetJsonGrpSize(void);
+my_bool JsonSubSet(PGLOBAL g, my_bool b = false);
+my_bool CalcLen(UDF_ARGS* args, my_bool obj, unsigned long& reslen,
+ unsigned long& memlen, my_bool mod = false);
+my_bool JsonInit(UDF_INIT* initid, UDF_ARGS* args, char* message, my_bool mbn,
+ unsigned long reslen, unsigned long memlen,
+ unsigned long more = 0);
+my_bool CheckMemory(PGLOBAL g, UDF_INIT* initid, UDF_ARGS* args, uint n,
+ my_bool m, my_bool obj = false, my_bool mod = false);
+PSZ MakePSZ(PGLOBAL g, UDF_ARGS* args, int i);
+int IsJson(UDF_ARGS* args, uint i, bool b = false);
+char *GetJsonFile(PGLOBAL g, char* fn);
+
+/*********************************************************************************/
+/* The JSON UDF functions. */
+/*********************************************************************************/
+extern "C" {
+ DllExport my_bool jsonvalue_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jsonvalue(UDF_EXEC_ARGS);
+ DllExport void jsonvalue_deinit(UDF_INIT*);
+
+ DllExport my_bool json_make_array_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_make_array(UDF_EXEC_ARGS);
+ DllExport void json_make_array_deinit(UDF_INIT*);
+
+ DllExport my_bool json_array_add_values_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_array_add_values(UDF_EXEC_ARGS);
+ DllExport void json_array_add_values_deinit(UDF_INIT*);
+
+ DllExport my_bool json_array_add_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_array_add(UDF_EXEC_ARGS);
+ DllExport void json_array_add_deinit(UDF_INIT*);
+
+ DllExport my_bool json_array_delete_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_array_delete(UDF_EXEC_ARGS);
+ DllExport void json_array_delete_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonsum_int_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long jsonsum_int(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void jsonsum_int_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonsum_real_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport double jsonsum_real(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void jsonsum_real_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonavg_real_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport double jsonavg_real(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void jsonavg_real_deinit(UDF_INIT*);
+
+ DllExport my_bool json_make_object_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_make_object(UDF_EXEC_ARGS);
+ DllExport void json_make_object_deinit(UDF_INIT*);
+
+ DllExport my_bool json_object_nonull_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_object_nonull(UDF_EXEC_ARGS);
+ DllExport void json_object_nonull_deinit(UDF_INIT*);
+
+ DllExport my_bool json_object_key_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_object_key(UDF_EXEC_ARGS);
+ DllExport void json_object_key_deinit(UDF_INIT*);
+
+ DllExport my_bool json_object_add_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_object_add(UDF_EXEC_ARGS);
+ DllExport void json_object_add_deinit(UDF_INIT*);
+
+ DllExport my_bool json_object_delete_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_object_delete(UDF_EXEC_ARGS);
+ DllExport void json_object_delete_deinit(UDF_INIT*);
+
+ DllExport my_bool json_object_list_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_object_list(UDF_EXEC_ARGS);
+ DllExport void json_object_list_deinit(UDF_INIT*);
+
+ DllExport my_bool json_object_values_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_object_values(UDF_EXEC_ARGS);
+ DllExport void json_object_values_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonset_grp_size_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long jsonset_grp_size(UDF_INIT*, UDF_ARGS*, char*, char*);
+
+ DllExport my_bool jsonget_grp_size_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long jsonget_grp_size(UDF_INIT*, UDF_ARGS*, char*, char*);
+
+ DllExport my_bool json_array_grp_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport void json_array_grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
+ DllExport char *json_array_grp(UDF_EXEC_ARGS);
+ DllExport void json_array_grp_clear(UDF_INIT *, char *, char *);
+ DllExport void json_array_grp_deinit(UDF_INIT*);
+
+ DllExport my_bool json_object_grp_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport void json_object_grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
+ DllExport char *json_object_grp(UDF_EXEC_ARGS);
+ DllExport void json_object_grp_clear(UDF_INIT *, char *, char *);
+ DllExport void json_object_grp_deinit(UDF_INIT*);
+
+ DllExport my_bool json_item_merge_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_item_merge(UDF_EXEC_ARGS);
+ DllExport void json_item_merge_deinit(UDF_INIT*);
+
+ DllExport my_bool json_get_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_get_item(UDF_EXEC_ARGS);
+ DllExport void json_get_item_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonget_string_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jsonget_string(UDF_EXEC_ARGS);
+ DllExport void jsonget_string_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonget_int_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long jsonget_int(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void jsonget_int_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonget_real_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport double jsonget_real(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void jsonget_real_deinit(UDF_INIT*);
+
+ DllExport my_bool jsoncontains_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long jsoncontains(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void jsoncontains_deinit(UDF_INIT*);
+
+ DllExport my_bool jsonlocate_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jsonlocate(UDF_EXEC_ARGS);
+ DllExport void jsonlocate_deinit(UDF_INIT*);
+
+ DllExport my_bool json_locate_all_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_locate_all(UDF_EXEC_ARGS);
+ DllExport void json_locate_all_deinit(UDF_INIT*);
+
+ DllExport my_bool jsoncontains_path_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long jsoncontains_path(UDF_INIT*, UDF_ARGS*, char*, char*);
+ DllExport void jsoncontains_path_deinit(UDF_INIT*);
+
+ DllExport my_bool json_set_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_set_item(UDF_EXEC_ARGS);
+ DllExport void json_set_item_deinit(UDF_INIT*);
+
+ DllExport my_bool json_insert_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_insert_item(UDF_EXEC_ARGS);
+ DllExport void json_insert_item_deinit(UDF_INIT*);
+
+ DllExport my_bool json_update_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_update_item(UDF_EXEC_ARGS);
+ DllExport void json_update_item_deinit(UDF_INIT*);
+
+ DllExport my_bool json_file_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_file(UDF_EXEC_ARGS);
+ DllExport void json_file_deinit(UDF_INIT*);
+
+ DllExport my_bool jfile_make_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jfile_make(UDF_EXEC_ARGS);
+ DllExport void jfile_make_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_array_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_array(UDF_EXEC_ARGS);
+ DllExport void jbin_array_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_array_add_values_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_array_add_values(UDF_EXEC_ARGS);
+ DllExport void jbin_array_add_values_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_array_add_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_array_add(UDF_EXEC_ARGS);
+ DllExport void jbin_array_add_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_array_delete_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_array_delete(UDF_EXEC_ARGS);
+ DllExport void jbin_array_delete_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_object_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_object(UDF_EXEC_ARGS);
+ DllExport void jbin_object_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_object_nonull_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_object_nonull(UDF_EXEC_ARGS);
+ DllExport void jbin_object_nonull_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_object_key_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_object_key(UDF_EXEC_ARGS);
+ DllExport void jbin_object_key_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_object_add_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_object_add(UDF_EXEC_ARGS);
+ DllExport void jbin_object_add_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_object_delete_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_object_delete(UDF_EXEC_ARGS);
+ DllExport void jbin_object_delete_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_object_list_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_object_list(UDF_EXEC_ARGS);
+ DllExport void jbin_object_list_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_get_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_get_item(UDF_EXEC_ARGS);
+ DllExport void jbin_get_item_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_item_merge_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_item_merge(UDF_EXEC_ARGS);
+ DllExport void jbin_item_merge_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_set_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_set_item(UDF_EXEC_ARGS);
+ DllExport void jbin_set_item_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_insert_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_insert_item(UDF_EXEC_ARGS);
+ DllExport void jbin_insert_item_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_update_item_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_update_item(UDF_EXEC_ARGS);
+ DllExport void jbin_update_item_deinit(UDF_INIT*);
+
+ DllExport my_bool jbin_file_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *jbin_file(UDF_EXEC_ARGS);
+ DllExport void jbin_file_deinit(UDF_INIT*);
+
+ DllExport my_bool json_serialize_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *json_serialize(UDF_EXEC_ARGS);
+ DllExport void json_serialize_deinit(UDF_INIT*);
+
+ DllExport my_bool jfile_convert_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* jfile_convert(UDF_EXEC_ARGS);
+ DllExport void jfile_convert_deinit(UDF_INIT*);
+
+ DllExport my_bool jfile_bjson_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char* jfile_bjson(UDF_EXEC_ARGS);
+ DllExport void jfile_bjson_deinit(UDF_INIT*);
+
+ DllExport my_bool envar_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *envar(UDF_EXEC_ARGS);
+
+#if defined(DEVELOPMENT)
+ DllExport my_bool uvar_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *uvar(UDF_EXEC_ARGS);
+#endif // DEVELOPMENT
+
+ DllExport my_bool countin_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport long long countin(UDF_INIT*, UDF_ARGS*, char*, char*);
+} // extern "C"
+
+
+/*********************************************************************************/
+/* Structure JPN. Used to make the locate path. */
+/*********************************************************************************/
+typedef struct _jpn {
+ int Type;
+ PCSZ Key;
+ int N;
+} JPN, *PJPN;
+
+/*********************************************************************************/
+/* Class JSNX: JSON access method. */
+/*********************************************************************************/
+class JSNX : public BLOCK {
+public:
+ // Constructors
+ JSNX(PGLOBAL g, PJSON row, int type, int len = 64, int prec = 0, my_bool wr = false);
+
+ // Implementation
+ int GetPrecision(void) {return Prec;}
+ PVAL GetValue(void) {return Value;}
+
+ // Methods
+ my_bool SetJpath(PGLOBAL g, char *path, my_bool jb = false);
+ my_bool ParseJpath(PGLOBAL g);
+ void ReadValue(PGLOBAL g);
+ PJVAL GetRowValue(PGLOBAL g, PJSON row, int i, my_bool b = true);
+ PJVAL GetJson(PGLOBAL g);
+ my_bool CheckPath(PGLOBAL g);
+ my_bool WriteValue(PGLOBAL g, PJVAL jvalp);
+ char *Locate(PGLOBAL g, PJSON jsp, PJVAL jvp, int k = 1);
+ char *LocateAll(PGLOBAL g, PJSON jsp, PJVAL jvp, int mx = 10);
+
+protected:
+ my_bool SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm);
+ PVAL GetColumnValue(PGLOBAL g, PJSON row, int i);
+ PVAL ExpandArray(PGLOBAL g, PJAR arp, int n);
+ PVAL GetCalcValue(PGLOBAL g, PJAR bap, int n);
+ PVAL CalculateArray(PGLOBAL g, PJAR arp, int n);
+ PJVAL MakeJson(PGLOBAL g, PJSON jsp, int i);
+ void SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val);
+ PJSON GetRow(PGLOBAL g);
+ my_bool CompareValues(PJVAL v1, PJVAL v2);
+ my_bool LocateArray(PGLOBAL g, PJAR jarp);
+ my_bool LocateObject(PGLOBAL g, PJOB jobp);
+ my_bool LocateValue(PGLOBAL g, PJVAL jvp);
+ my_bool LocateArrayAll(PGLOBAL g, PJAR jarp);
+ my_bool LocateObjectAll(PGLOBAL g, PJOB jobp);
+ my_bool LocateValueAll(PGLOBAL g, PJVAL jvp);
+ my_bool CompareTree(PGLOBAL g, PJSON jp1, PJSON jp2);
+ my_bool AddPath(void);
+
+ // Default constructor not to be used
+ JSNX(void) {}
+
+ // Members
+ PJSON Row;
+ PJVAL Jvalp;
+ PJPN Jpnp;
+ JOUTSTR *Jp;
+ JNODE *Nodes; // The intermediate objects
+ PVAL Value;
+ //PVAL MulVal; // To value used by multiple column
+ char *Jpath; // The json path
+ int Buf_Type;
+ int Long;
+ int Prec;
+ int Nod; // The number of intermediate objects
+ int Xnod; // Index of multiple values
+ int K; // Kth item to locate
+ int I; // Index of JPN
+ int Imax; // Max number of JPN's
+ int B; // Index base
+ my_bool Xpd; // True for expandable column
+ my_bool Parsed; // True when parsed
+ my_bool Found; // Item found by locate
+ my_bool Wr; // Write mode
+ my_bool Jb; // Must return json item
+}; // end of class JSNX
+
+/*********************************************************************************/
+/* Class JUP: used by jfile_convert to make a json file pretty = 0. */
+/*********************************************************************************/
+class JUP : public BLOCK {
+public:
+ // Constructor
+ JUP(PGLOBAL g);
+
+ // Implementation
+ void AddBuff(char c) {
+ if (k < recl)
+ buff[k++] = c;
+ else
+ throw "Record size is too small";
+ } // end of AddBuff
+
+ // Methods
+ char *UnprettyJsonFile(PGLOBAL g, char* fn, char* outfn, int lrecl);
+ bool unPretty(PGLOBAL g, int lrecl);
+ void CopyObject(PGLOBAL g);
+ void CopyArray(PGLOBAL g);
+ void CopyValue(PGLOBAL g);
+ void CopyString(PGLOBAL g);
+ void CopyNumeric(PGLOBAL g);
+
+ // Members
+ FILE *fs;
+ char *s;
+ char *buff;
+ size_t len;
+ uint i;
+ int k, recl;
+}; // end of class JUP
diff --git a/storage/connect/libdoc.cpp b/storage/connect/libdoc.cpp
new file mode 100644
index 00000000..3b2696b0
--- /dev/null
+++ b/storage/connect/libdoc.cpp
@@ -0,0 +1,1288 @@
+/******************************************************************/
+/* Implementation of XML document processing using libxml2 */
+/* Author: Olivier Bertrand 2007-2016 */
+/******************************************************************/
+#include "my_global.h"
+#include <string.h>
+#include <stdio.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/catalog.h>
+#include <libxml/xmlschemastypes.h>
+#include <libxml/relaxng.h>
+
+#if !defined(LIBXML_TREE_ENABLED) || !defined(LIBXML_OUTPUT_ENABLED)
+#error "tree support not compiled in"
+#endif
+
+#if !defined(LIBXML_XPATH_ENABLED) || !defined(LIBXML_SAX1_ENABLED)
+#error "XPath not supported"
+#endif
+
+#include "global.h"
+#include "plgdbsem.h"
+#include "xobject.h"
+#include "libdoc.h"
+
+#include "sql_string.h"
+
+/******************************************************************/
+/* Declaration of XML document processing using libxml2 */
+/* Author: Olivier Bertrand 2007-2012 */
+/******************************************************************/
+#include "plgxml.h"
+
+typedef class LIBXMLDOC *PXDOC2;
+typedef class XML2NODE *PNODE2;
+typedef class XML2ATTR *PATTR2;
+typedef class XML2NODELIST *PLIST2;
+
+/******************************************************************/
+/* XML2 block. Must have the same layout than FBLOCK up to Type. */
+/******************************************************************/
+typedef struct _x2block { /* Loaded XML file block */
+ struct _x2block *Next;
+ LPCSTR Fname; /* Point on file name */
+ size_t Length; /* Used to tell if read mode */
+ short Count; /* Nb of times file is used */
+ short Type; /* TYPE_FB_XML */
+ int Retcode; /* Return code from Load */
+ xmlDocPtr Docp; /* Document interface pointer */
+ } X2BLOCK, *PX2BLOCK;
+
+/******************************************************************/
+/* Declaration of libxml2 document. */
+/******************************************************************/
+class LIBXMLDOC : public XMLDOCUMENT {
+ friend class XML2NODE;
+ friend class XML2ATTR;
+ public:
+ // Constructor
+ LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp);
+
+ // Properties
+ virtual short GetDocType(void) {return TYPE_FB_XML2;}
+ virtual void *GetDocPtr(void) {return Docp;}
+ virtual void SetNofree(bool b) {Nofreelist = b;}
+
+ // Methods
+ virtual bool Initialize(PGLOBAL g, PCSZ entry, bool zipped);
+ virtual bool ParseFile(PGLOBAL g, char *fn);
+ virtual bool NewDoc(PGLOBAL g, PCSZ ver);
+ virtual void AddComment(PGLOBAL g, char *com);
+ virtual PXNODE GetRoot(PGLOBAL g);
+ virtual PXNODE NewRoot(PGLOBAL g, char *name);
+ virtual PXNODE NewPnode(PGLOBAL g, char *name);
+ virtual PXATTR NewPattr(PGLOBAL g);
+ virtual PXLIST NewPlist(PGLOBAL g);
+ virtual int DumpDoc(PGLOBAL g, char *ofn);
+ virtual void CloseDoc(PGLOBAL g, PFBLOCK xp);
+ virtual PFBLOCK LinkXblock(PGLOBAL g, MODE m, int rc, char *fn);
+
+ protected:
+// bool CheckDocument(FILE *of, xmlNodePtr np);
+ xmlNodeSetPtr GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp);
+ int Decode(xmlChar *cnt, char *buf, int n);
+ xmlChar *Encode(PGLOBAL g, char *txt);
+
+ // Members
+ xmlDocPtr Docp;
+ xmlNodeSetPtr Nlist;
+ xmlXPathContextPtr Ctxp;
+ xmlXPathObjectPtr Xop;
+ xmlXPathObjectPtr NlXop;
+ xmlErrorPtr Xerr;
+ char *Buf; // Temporary
+ bool Nofreelist;
+}; // end of class LIBXMLDOC
+
+/******************************************************************/
+/* Declaration of libxml2 node. */
+/******************************************************************/
+class XML2NODE : public XMLNODE {
+ friend class LIBXMLDOC;
+ friend class XML2NODELIST;
+ public:
+ // Properties
+ virtual char *GetName(PGLOBAL g) {return (char*)Nodep->name;}
+ virtual int GetType(void);
+ virtual PXNODE GetNext(PGLOBAL g);
+ virtual PXNODE GetChild(PGLOBAL g);
+
+ // Methods
+ virtual RCODE GetContent(PGLOBAL g, char *buf, int len);
+ virtual bool SetContent(PGLOBAL g, char *txtp, int len);
+ virtual PXNODE Clone(PGLOBAL g, PXNODE np);
+ virtual PXLIST GetChildElements(PGLOBAL g, char *xp, PXLIST lp);
+ virtual PXLIST SelectNodes(PGLOBAL g, char *xp, PXLIST lp);
+ virtual PXNODE SelectSingleNode(PGLOBAL g, char *xp, PXNODE np);
+ virtual PXATTR GetAttribute(PGLOBAL g, char *name, PXATTR ap);
+ virtual PXNODE AddChildNode(PGLOBAL g, PCSZ name, PXNODE np);
+ virtual PXATTR AddProperty(PGLOBAL g, char *name, PXATTR ap);
+ virtual void AddText(PGLOBAL g, PCSZ txtp);
+ virtual void DeleteChild(PGLOBAL g, PXNODE dnp);
+
+ protected:
+ // Constructor
+ XML2NODE(PXDOC dp, xmlNodePtr np);
+
+ // Members
+ xmlDocPtr Docp;
+ xmlChar *Content;
+ xmlNodePtr Nodep;
+}; // end of class XML2NODE
+
+/******************************************************************/
+/* Declaration of libxml2 node list. */
+/******************************************************************/
+class XML2NODELIST : public XMLNODELIST {
+ friend class LIBXMLDOC;
+ friend class XML2NODE;
+ public:
+ // Methods
+ virtual int GetLength(void);
+ virtual PXNODE GetItem(PGLOBAL g, int n, PXNODE np);
+ virtual bool DropItem(PGLOBAL g, int n);
+
+ protected:
+ // Constructor
+ XML2NODELIST(PXDOC dp, xmlNodeSetPtr lp);
+
+ // Members
+ xmlNodeSetPtr Listp;
+}; // end of class XML2NODELIST
+
+/******************************************************************/
+/* Declaration of libxml2 attribute. */
+/******************************************************************/
+class XML2ATTR : public XMLATTRIBUTE {
+ friend class LIBXMLDOC;
+ friend class XML2NODE;
+ public:
+ // Properties
+ virtual char *GetName(PGLOBAL g) {return (char*)Atrp->name;}
+ virtual PXATTR GetNext(PGLOBAL g);
+
+ // Methods
+ virtual RCODE GetText(PGLOBAL g, char *bufp, int len);
+ virtual bool SetText(PGLOBAL g, char *txtp, int len);
+
+ protected:
+ // Constructor
+ XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np);
+
+ // Members
+ xmlAttrPtr Atrp;
+ xmlNodePtr Parent;
+}; // end of class XML2ATTR
+
+
+
+extern "C" {
+extern char version[];
+} // "C"
+
+#if defined(MEMORY_TRACE)
+static int m = 0;
+static char s[500];
+/**************************************************************************/
+/* Tracing output function. */
+/**************************************************************************/
+void xtrc(char const *fmt, ...)
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ ;
+//vfprintf(stderr, fmt, ap);
+ vsprintf(s, fmt, ap);
+ if (s[strlen(s)-1] == '\n')
+ s[strlen(s)-1] = 0;
+ va_end (ap);
+ } // end of htrc
+
+static xmlFreeFunc Free;
+static xmlMallocFunc Malloc;
+static xmlMallocFunc MallocA;
+static xmlReallocFunc Realloc;
+static xmlStrdupFunc Strdup;
+
+void xmlMyFree(void *mem)
+{
+ if (trace(1)) {
+ htrc("%.4d Freeing at %p %-.256s\n", ++m, mem, s);
+ *s = 0;
+ } // endif trace
+ Free(mem);
+} // end of xmlMyFree
+
+void *xmlMyMalloc(size_t size)
+{
+ void *p = Malloc(size);
+ if (trace(1)) {
+ htrc("%.4d Allocating %.5d at %p %-.256s\n", ++m, size, p, s);
+ *s = 0;
+ } // endif trace
+ return p;
+} // end of xmlMyMalloc
+
+void *xmlMyMallocAtomic(size_t size)
+{
+ void *p = MallocA(size);
+ if (trace(1)) {
+ htrc("%.4d Atom alloc %.5d at %p %-.256s\n", ++m, size, p, s);
+ *s = 0;
+ } // endif trace
+ return p;
+} // end of xmlMyMallocAtomic
+
+void *xmlMyRealloc(void *mem, size_t size)
+{
+ void *p = Realloc(mem, size);
+ if (trace(1)) {
+ htrc("%.4d ReAlloc %.5d to %p from %p %-.256s\n", ++m, size, p, mem, s);
+ *s = 0;
+ } // endif trace
+ return p;
+} // end of xmlMyRealloc
+
+char *xmlMyStrdup(const char *str)
+{
+ char *p = Strdup(str);
+ if (trace(1)) {
+ htrc("%.4d Duplicating to %p from %p %-.256s %-.256s\n", ++m, p, str, str, s);
+ *s = 0;
+ } // endif trace
+ return p;
+} // end of xmlMyStrdup
+#define htrc xtrc
+#endif // MEMORY_TRACE
+
+/******************************************************************/
+/* Return a LIBXMLDOC as a XMLDOC. */
+/******************************************************************/
+PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf,
+ char *enc, PFBLOCK fp)
+ {
+ return (PXDOC) new(g) LIBXMLDOC(nsl, nsdf, enc, fp);
+ } // end of GetLibxmlDoc
+
+/******************************************************************/
+/* XML library initialization function. */
+/******************************************************************/
+void XmlInitParserLib(void)
+ {
+#if defined(MEMORY_TRACE)
+int rc = xmlGcMemGet(&Free, &Malloc, &MallocA, &Realloc, &Strdup);
+
+if (!rc)
+ rc = xmlGcMemSetup(xmlMyFree,
+ xmlMyMalloc,
+ xmlMyMallocAtomic,
+ xmlMyRealloc,
+ xmlMyStrdup);
+
+#endif // MEMORY_TRACE
+ xmlInitParser();
+ } // end of XmlInitParserLib
+
+/******************************************************************/
+/* XML library cleanup function. */
+/******************************************************************/
+/*
+ This is a copy of xmlCleanupParser() from the libxml2 sources
+ with xmlResetLastError() commented.
+
+ xmlResetLastError() called from the original xmlCleanupParser() causes
+ valgrind to report memory leaks. This happens because
+ ha_initialize_handlerton() is called from the main thread in mysqld.cc,
+ while ha_finalize_handlerton() is called from a non-main thread.
+ libxml2 gets confused because of xmlInitParser() and xmlCleanupParser()
+ being called from the different threads.
+
+ Perhaps the code in mysqld.cc should eventually be modified
+ to shutdown plugins from the main thread.
+*/
+static void
+xmlCleanupParser_replacement(void)
+ {
+ xmlCleanupCharEncodingHandlers();
+#ifdef LIBXML_CATALOG_ENABLED
+ xmlCatalogCleanup();
+#endif
+ xmlDictCleanup();
+ xmlCleanupInputCallbacks();
+#ifdef LIBXML_OUTPUT_ENABLED
+ xmlCleanupOutputCallbacks();
+#endif
+#ifdef LIBXML_SCHEMAS_ENABLED
+ xmlSchemaCleanupTypes();
+ xmlRelaxNGCleanupTypes();
+#endif
+ //xmlResetLastError();
+ xmlCleanupGlobals();
+ xmlCleanupThreads(); /* must be last if called not from the main thread */
+ xmlCleanupMemory();
+ }
+
+
+void XmlCleanupParserLib(void)
+ {
+ xmlCleanupParser_replacement();
+ } // end of XmlCleanupParserLib
+
+/******************************************************************/
+/* Close a loaded libxml2 XML file. */
+/******************************************************************/
+void CloseXML2File(PGLOBAL g, PFBLOCK fp, bool all)
+ {
+ PX2BLOCK xp = (PX2BLOCK)fp;
+
+ if (trace(1))
+ htrc("CloseXML2File: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0);
+
+ if (xp && xp->Count > 1 && !all) {
+ xp->Count--;
+ } else if (xp && xp->Count > 0) {
+ xmlFreeDoc(xp->Docp);
+ xp->Count = 0;
+ } // endif
+
+ } // end of CloseXML2File
+
+/* ---------------------- class LIBXMLDOC ----------------------- */
+
+/******************************************************************/
+/* LIBXMLDOC constructor. */
+/******************************************************************/
+LIBXMLDOC::LIBXMLDOC(char *nsl, char *nsdf, char *enc, PFBLOCK fp)
+ : XMLDOCUMENT(nsl, nsdf, enc)
+ {
+ assert (!fp || fp->Type == TYPE_FB_XML2);
+ Docp = (fp) ? ((PX2BLOCK)fp)->Docp : NULL;
+ Nlist = NULL;
+ Ctxp = NULL;
+ Xop = NULL;
+ NlXop = NULL;
+ Xerr = NULL;
+ Buf = NULL;
+ Nofreelist = false;
+ } // end of LIBXMLDOC constructor
+
+/******************************************************************/
+/* Initialize XML parser and check library compatibility. */
+/******************************************************************/
+bool LIBXMLDOC::Initialize(PGLOBAL g, PCSZ entry, bool zipped)
+{
+ if (zipped && InitZip(g, entry))
+ return true;
+
+ xmlKeepBlanksDefault(1);
+ return MakeNSlist(g);
+} // end of Initialize
+
+/******************************************************************/
+/* Parse the XML file and construct node tree in memory. */
+/******************************************************************/
+bool LIBXMLDOC::ParseFile(PGLOBAL g, char *fn)
+ {
+ if (trace(1))
+ htrc("ParseFile\n");
+
+ if (zip) {
+ // Parse an in memory document
+ char *xdoc = GetMemDoc(g, fn);
+
+ Docp = (xdoc) ? xmlParseDoc((const xmlChar *)xdoc) : NULL;
+ } else
+ Docp = xmlParseFile(fn);
+
+ if (Docp) {
+ if (Docp->encoding)
+ Encoding = (char*)Docp->encoding;
+
+ return false;
+ } else if ((Xerr = xmlGetLastError()))
+ xmlResetError(Xerr);
+
+ return true;
+ } // end of ParseFile
+
+/******************************************************************/
+/* Create or reuse an Xblock for this document. */
+/******************************************************************/
+PFBLOCK LIBXMLDOC::LinkXblock(PGLOBAL g, MODE m, int rc, char *fn)
+ {
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+ PX2BLOCK xp = (PX2BLOCK)PlugSubAlloc(g, NULL, sizeof(X2BLOCK));
+
+ memset(xp, 0, sizeof(X2BLOCK));
+ xp->Next = (PX2BLOCK)dup->Openlist;
+ dup->Openlist = (PFBLOCK)xp;
+ xp->Type = TYPE_FB_XML2;
+ xp->Fname = (LPCSTR)PlugDup(g, fn);
+ xp->Count = 1;
+ xp->Length = (m == MODE_READ) ? 1 : 0;
+ xp->Retcode = rc;
+ xp->Docp = Docp;
+
+ // Return xp as a fp
+ return (PFBLOCK)xp;
+ } // end of LinkXblock
+
+/******************************************************************/
+/* Construct and add the XML processing instruction node. */
+/******************************************************************/
+bool LIBXMLDOC::NewDoc(PGLOBAL g, PCSZ ver)
+ {
+ if (trace(1))
+ htrc("NewDoc\n");
+
+ return ((Docp = xmlNewDoc(BAD_CAST ver)) == NULL);
+ } // end of NewDoc
+
+/******************************************************************/
+/* Add a new comment node to the document. */
+/******************************************************************/
+void LIBXMLDOC::AddComment(PGLOBAL g, char *txtp)
+ {
+ if (trace(1))
+ htrc("AddComment: %-.256s\n", txtp);
+
+ xmlNodePtr cp = xmlNewDocComment(Docp, BAD_CAST txtp);
+ xmlAddChild((xmlNodePtr)Docp, cp);
+ } // end of AddText
+
+/******************************************************************/
+/* Return the node class of the root of the document. */
+/******************************************************************/
+PXNODE LIBXMLDOC::GetRoot(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("GetRoot\n");
+
+ xmlNodePtr root = xmlDocGetRootElement(Docp);
+
+ if (!root)
+ return NULL;
+
+ return new(g) XML2NODE(this, root);
+ } // end of GetRoot
+
+/******************************************************************/
+/* Create a new root element and return its class node. */
+/******************************************************************/
+PXNODE LIBXMLDOC::NewRoot(PGLOBAL g, char *name)
+ {
+ if (trace(1))
+ htrc("NewRoot: %-.256s\n", name);
+
+ xmlNodePtr root = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL);
+
+ if (root) {
+ xmlDocSetRootElement(Docp, root);
+ return new(g) XML2NODE(this, root);
+ } else
+ return NULL;
+
+ } // end of NewRoot
+
+/******************************************************************/
+/* Return a void XML2NODE node class. */
+/******************************************************************/
+PXNODE LIBXMLDOC::NewPnode(PGLOBAL g, char *name)
+ {
+ if (trace(1))
+ htrc("NewNode: %-.256s\n", name);
+
+ xmlNodePtr nop;
+
+ if (name) {
+ nop = xmlNewDocNode(Docp, NULL, BAD_CAST name, NULL);
+
+ if (nop == NULL)
+ return NULL;
+
+ } else
+ nop = NULL;
+
+ return new(g) XML2NODE(this, nop);
+ } // end of NewPnode
+
+/******************************************************************/
+/* Return a void XML2ATTR node class. */
+/******************************************************************/
+PXATTR LIBXMLDOC::NewPattr(PGLOBAL g)
+ {
+ return new(g) XML2ATTR(this, NULL, NULL);
+ } // end of NewPattr
+
+/******************************************************************/
+/* Return a void XML2ATTR node class. */
+/******************************************************************/
+PXLIST LIBXMLDOC::NewPlist(PGLOBAL g)
+ {
+ return new(g) XML2NODELIST(this, NULL);
+ } // end of NewPlist
+
+/******************************************************************/
+/* Dump the node tree to a new XML file. */
+/******************************************************************/
+int LIBXMLDOC::DumpDoc(PGLOBAL g, char *ofn)
+ {
+ int rc = 0;
+ FILE *of;
+
+ if (trace(1))
+ htrc("DumpDoc: %-.256s\n", ofn);
+
+ if (!(of= global_fopen(g, MSGID_CANNOT_OPEN, ofn, "w")))
+ return -1;
+
+#if 1
+ // This function does not crash (
+ if (xmlSaveFormatFileEnc((const char *)ofn, Docp, Encoding, 0) < 0) {
+ xmlErrorPtr err = xmlGetLastError();
+ strcpy(g->Message, (err) ? err->message : "Error saving XML doc");
+ xmlResetError(Xerr);
+ rc = -1;
+ } // endif Save
+// rc = xmlDocDump(of, Docp);
+#else // 0
+ // Until this function is fixed, do the job ourself
+ xmlNodePtr Rootp;
+
+ // Save the modified document
+ fprintf(of, "<?xml version=\"1.0\" encoding=\"%-.256s\"?>\n", Encoding);
+ fprintf(of, "<!-- Created by CONNECT %-.256s -->\n", version);
+
+ if (!(Rootp = xmlDocGetRootElement(Docp)))
+ return 1;
+
+ Buf = (char*)PlugSubAlloc(g, NULL, 1024);
+ rc = iconv_close(Cd2);
+ Cd2 = iconv_open(Encoding, "UTF-8");
+ rc = CheckDocument(of, Rootp);
+#endif // 0
+
+ fclose(of);
+ return rc;
+ } // end of Dump
+
+/******************************************************************/
+/* Free the document, cleanup the XML library, and */
+/* debug memory for regression tests. */
+/******************************************************************/
+void LIBXMLDOC::CloseDoc(PGLOBAL g, PFBLOCK xp)
+ {
+ if (trace(1))
+ htrc("CloseDoc: xp=%p count=%d\n", xp, (xp) ? xp->Count : 0);
+
+//if (xp && xp->Count == 1) {
+ if (xp) {
+ if (Nlist) {
+ xmlXPathFreeNodeSet(Nlist);
+
+ if ((Xerr = xmlGetLastError()))
+ xmlResetError(Xerr);
+
+ Nlist = NULL;
+ } // endif Nlist
+
+ if (Xop) {
+ xmlXPathFreeObject(Xop);
+
+ if ((Xerr = xmlGetLastError()))
+ xmlResetError(Xerr);
+
+ Xop = NULL;
+ } // endif Xop
+
+ if (NlXop) {
+ xmlXPathFreeObject(NlXop);
+
+ if ((Xerr = xmlGetLastError()))
+ xmlResetError(Xerr);
+
+ NlXop = NULL;
+ } // endif NlXop
+
+ if (Ctxp) {
+ xmlXPathFreeContext(Ctxp);
+
+ if ((Xerr = xmlGetLastError()))
+ xmlResetError(Xerr);
+
+ Ctxp = NULL;
+ } // endif Ctxp
+
+ } // endif xp
+
+ CloseXML2File(g, xp, false);
+ CloseZip();
+ } // end of Close
+
+/******************************************************************/
+/* Evaluate the passed Xpath from the passed context node. */
+/******************************************************************/
+xmlNodeSetPtr LIBXMLDOC::GetNodeList(PGLOBAL g, xmlNodePtr np, char *xp)
+ {
+ xmlNodeSetPtr nl;
+
+ if (trace(1))
+ htrc("GetNodeList: %-.256s np=%p\n", xp, np);
+
+ if (!Ctxp) {
+ // Init Xpath
+ if (trace(1))
+ htrc("Calling xmlPathInit\n");
+
+ xmlXPathInit();
+
+ if (trace(1))
+ htrc("Calling xmlXPathNewContext Docp=%p\n", Docp);
+
+ // Create xpath evaluation context
+ if (!(Ctxp = xmlXPathNewContext(Docp))) {
+ strcpy(g->Message, MSG(XPATH_CNTX_ERR));
+
+ if (trace(1))
+ htrc("Context error: %-.256s\n", g->Message);
+
+ return NULL;
+ } // endif xpathCtx
+
+ // Register namespaces from list (if any)
+ for (PNS nsp = Namespaces; nsp; nsp = nsp->Next) {
+ if (trace(1))
+ htrc("Calling xmlXPathRegisterNs Prefix=%-.256s Uri=%-.512s\n",
+ nsp->Prefix, nsp->Uri);
+
+ if (xmlXPathRegisterNs(Ctxp, BAD_CAST nsp->Prefix,
+ BAD_CAST nsp->Uri)) {
+ sprintf(g->Message, MSG(REGISTER_ERR), nsp->Prefix, nsp->Uri);
+
+ if (trace(1))
+ htrc("Ns error: %-.256s\n", g->Message);
+
+ return NULL;
+ } // endif Registering
+
+ } // endfor nsp
+
+ } // endif Ctxp
+
+ if (Xop) {
+ if (trace(1))
+ htrc("Calling xmlXPathFreeNodeSetList Xop=%p NOFREE=%d\n",
+ Xop, Nofreelist);
+
+ if (Nofreelist) {
+ // Making Nlist that must not be freed yet
+// xmlXPathFreeNodeSetList(Xop); // Caused memory leak
+ assert(!NlXop);
+ NlXop = Xop; // Freed on closing
+ Nofreelist = false;
+ } else
+ xmlXPathFreeObject(Xop); // Caused node not found
+
+ if ((Xerr = xmlGetLastError())) {
+ strcpy(g->Message, Xerr->message);
+ xmlResetError(Xerr);
+ return NULL;
+ } // endif Xerr
+
+ } // endif Xop
+
+ // Set the context to the calling node
+ Ctxp->node = np;
+
+ if (trace(1))
+ htrc("Calling xmlXPathEval %-.256s Ctxp=%p\n", xp, Ctxp);
+
+ // Evaluate table xpath
+ if (!(Xop = xmlXPathEval(BAD_CAST xp, Ctxp))) {
+ sprintf(g->Message, MSG(XPATH_EVAL_ERR), xp);
+
+ if (trace(1))
+ htrc("Path error: %-.256s\n", g->Message);
+
+ return NULL;
+ } else
+ nl = Xop->nodesetval;
+
+ if (trace(1))
+ htrc("GetNodeList nl=%p n=%p\n", nl, (nl) ? nl->nodeNr : 0);
+
+ return nl;
+ } // end of GetNodeList
+
+#if 0 // Not used anymore
+/******************************************************************/
+/* CheckDocument: check if the document is ok to dump. */
+/* Currently this does the dumping of the document. */
+/******************************************************************/
+bool LIBXMLDOC::CheckDocument(FILE *of, xmlNodePtr np)
+ {
+ int n;
+ bool b;
+
+ if (!np)
+ return true;
+
+ if (np->type == XML_ELEMENT_NODE) {
+ n = fprintf(of, "<%s", np->name);
+ b = CheckDocument(of, (xmlNodePtr)np->properties);
+
+ if (np->children)
+ n = fprintf(of, ">");
+ else
+ n = fprintf(of, "/>");
+
+ } else if (np->type == XML_ATTRIBUTE_NODE)
+ n = fprintf(of, " %s=\"", np->name);
+ else if (np->type == XML_TEXT_NODE)
+ n = fprintf(of, "%s", Encode(NULL, (char*)np->content));
+ else if (np->type == XML_COMMENT_NODE)
+ n = fprintf(of, "%s", Encode(NULL, (char*)np->content));
+
+ b = CheckDocument(of, np->children);
+
+ if (np->type == XML_ATTRIBUTE_NODE)
+ n = fprintf(of, "\"");
+ else if (!b && np->type == XML_ELEMENT_NODE)
+ n = fprintf(of, "</%s>", np->name);
+
+ b = CheckDocument(of, np->next);
+ return false;
+ } // end of CheckDocument
+
+/******************************************************************/
+/* Convert node or attribute content to latin characters. */
+/******************************************************************/
+int LIBXMLDOC::Decode(xmlChar *cnt, char *buf, int n)
+ {
+ const char *txt = (const char *)cnt;
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, n, &my_charset_utf8mb3_general_ci, txt,
+ strlen(txt), &my_charset_utf8mb3_general_ci,
+ &dummy_errors);
+ buf[len]= '\0';
+ return 0;
+ } // end of Decode
+
+/******************************************************************/
+/* Convert node or attribute content to latin characters. */
+/******************************************************************/
+xmlChar *LIBXMLDOC::Encode(PGLOBAL g, char *txt)
+ {
+ const CHARSET_INFO *ics= &my_charset_utf8mb3_general_ci;
+ const CHARSET_INFO *ocs= &my_charset_utf8mb3_general_ci;
+ size_t i = strlen(txt);
+ size_t o = i * ocs->mbmaxlen / ics->mbmaxlen + 1;
+ char *buf;
+ if (g) {
+ buf = (char*)PlugSubAlloc(g, NULL, o);
+ } else {
+ o = 1024;
+ buf = Buf;
+ } // endif g
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, o, ocs,
+ txt, i, ics,
+ &dummy_errors);
+ buf[len]= '\0';
+ return BAD_CAST buf;
+ } // end of Encode
+#endif // 0
+
+/* ---------------------- class XML2NODE ------------------------ */
+
+/******************************************************************/
+/* XML2NODE constructor. */
+/******************************************************************/
+XML2NODE::XML2NODE(PXDOC dp, xmlNodePtr np) : XMLNODE(dp)
+ {
+ Docp = ((PXDOC2)dp)->Docp;
+ Content = NULL;
+ Nodep = np;
+ } // end of XML2NODE constructor
+
+int XML2NODE::GetType(void)
+ {
+ if (trace(1))
+ htrc("GetType type=%d\n", Nodep->type);
+
+ return Nodep->type;
+ } // end of GetType
+
+/******************************************************************/
+/* Return the node class of next sibling of the node. */
+/******************************************************************/
+PXNODE XML2NODE::GetNext(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("GetNext\n");
+
+ if (!Nodep->next)
+ Next = NULL;
+ else // if (!Next)
+ Next = new(g) XML2NODE(Doc, Nodep->next);
+
+ return Next;
+ } // end of GetNext
+
+/******************************************************************/
+/* Return the node class of first children of the node. */
+/******************************************************************/
+PXNODE XML2NODE::GetChild(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("GetChild\n");
+
+ if (!Nodep->children)
+ Children = NULL;
+ else // if (!Children)
+ Children = new(g) XML2NODE(Doc, Nodep->children);
+
+ return Children;
+ } // end of GetChild
+
+/******************************************************************/
+/* Return the content of a node and subnodes. */
+/******************************************************************/
+RCODE XML2NODE::GetContent(PGLOBAL g, char *buf, int len)
+ {
+ RCODE rc = RC_OK;
+
+ if (trace(1))
+ htrc("GetContent\n");
+
+ if (Content)
+ xmlFree(Content);
+
+ if ((Content = xmlNodeGetContent(Nodep))) {
+ char *p1 = (char*)Content, *p2 = buf;
+ bool b = false;
+
+ // Copy content eliminating extra characters
+ for (; *p1; p1++)
+ if ((p2 - buf) < len) {
+ if (strchr(" \t\r\n", *p1)) {
+ if (b) {
+ // This to have one blank between sub-nodes
+ *p2++ = ' ';
+ b = false;
+ } // endif b
+
+ } else {
+ *p2++ = *p1;
+ b = true;
+ } // endif p1
+
+ } else {
+ sprintf(g->Message, "Truncated %-.256s content", Nodep->name);
+ rc = RC_INFO;
+ } // endif len
+
+ *p2 = 0;
+
+ if (trace(1))
+ htrc("GetText buf='%-.256s' len=%d\n", buf, len);
+
+ xmlFree(Content);
+ Content = NULL;
+ } else
+ *buf = '\0';
+
+ if (trace(1))
+ htrc("GetContent: %-.256s\n", buf);
+
+ return rc;
+ } // end of GetContent
+
+/******************************************************************/
+/* Set the content of a node. */
+/******************************************************************/
+bool XML2NODE::SetContent(PGLOBAL g, char *txtp, int len)
+ {
+ if (trace(1))
+ htrc("SetContent: %-.256s\n", txtp);
+
+ xmlChar *buf = xmlEncodeEntitiesReentrant(Docp, BAD_CAST txtp);
+
+ if (trace(1))
+ htrc("SetContent: %-.256s -> %-.256s\n", txtp, buf);
+
+ xmlNodeSetContent(Nodep, buf);
+ xmlFree(buf);
+ return false;
+ } // end of SetContent
+
+/******************************************************************/
+/* Return a clone of this node. */
+/******************************************************************/
+PXNODE XML2NODE::Clone(PGLOBAL g, PXNODE np)
+ {
+ if (trace(1))
+ htrc("Clone: np=%p\n", np);
+
+ if (np) {
+ ((PNODE2)np)->Nodep = Nodep;
+ return np;
+ } else
+ return new(g) XML2NODE(Doc, Nodep);
+
+ } // end of Clone
+
+/******************************************************************/
+/* Return the list of all or matching children that are elements.*/
+/******************************************************************/
+PXLIST XML2NODE::GetChildElements(PGLOBAL g, char *xp, PXLIST lp)
+ {
+ if (trace(1))
+ htrc("GetChildElements: %-.256s\n", xp);
+
+ return SelectNodes(g, (xp) ? xp : (char*)"*", lp);
+ } // end of GetChildElements
+
+/******************************************************************/
+/* Return the list of nodes verifying the passed Xpath. */
+/******************************************************************/
+PXLIST XML2NODE::SelectNodes(PGLOBAL g, char *xp, PXLIST lp)
+ {
+ if (trace(1))
+ htrc("SelectNodes: %-.256s\n", xp);
+
+ xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp);
+
+ if (lp) {
+ ((PLIST2)lp)->Listp = nl;
+ return lp;
+ } else
+ return new(g) XML2NODELIST(Doc, nl);
+
+ } // end of SelectNodes
+
+/******************************************************************/
+/* Return the first node verifying the passed Xapth. */
+/******************************************************************/
+PXNODE XML2NODE::SelectSingleNode(PGLOBAL g, char *xp, PXNODE np)
+ {
+ if (trace(1))
+ htrc("SelectSingleNode: %-.256s\n", xp);
+
+ xmlNodeSetPtr nl = ((PXDOC2)Doc)->GetNodeList(g, Nodep, xp);
+
+ if (nl && nl->nodeNr) {
+ if (np) {
+ ((PNODE2)np)->Nodep = nl->nodeTab[0];
+ return np;
+ } else
+ return new(g) XML2NODE(Doc, nl->nodeTab[0]);
+
+ } else
+ return NULL;
+
+ } // end of SelectSingleNode
+
+/******************************************************************/
+/* Return the node attribute with the specified name. */
+/******************************************************************/
+PXATTR XML2NODE::GetAttribute(PGLOBAL g, char *name, PXATTR ap)
+ {
+ xmlAttrPtr atp;
+
+ if (trace(1))
+ htrc("GetAttribute: %-.256s\n", SVP(name));
+
+ if (name)
+ atp = xmlHasProp(Nodep, BAD_CAST name);
+ else
+ atp = Nodep->properties;
+
+
+ if (atp) {
+ if (ap) {
+ ((PATTR2)ap)->Atrp = atp;
+ ((PATTR2)ap)->Parent = Nodep;
+ return ap;
+ } else
+ return new(g) XML2ATTR(Doc, atp, Nodep);
+
+ } else
+ return NULL;
+
+ } // end of GetAttribute
+
+/******************************************************************/
+/* Add a new child node to this node and return it. */
+/******************************************************************/
+PXNODE XML2NODE::AddChildNode(PGLOBAL g, PCSZ name, PXNODE np)
+ {
+ char *p, *pn, *pf = NULL, *nmp = PlugDup(g, name);
+
+ if (trace(1))
+ htrc("AddChildNode: %-.256s\n", name);
+
+ // Is a prefix specified
+ if ((pn = strchr(nmp, ':'))) {
+ pf = nmp;
+ *pn++ = '\0'; // Separate name from prefix
+ } else
+ pn = nmp;
+
+ // If name has the format m[n] only m is taken as node name
+ if ((p = strchr(pn, '[')))
+ p = BufAlloc(g, pn, int(p - pn));
+ else
+ p = pn;
+
+ xmlNodePtr nop = xmlNewChild(Nodep, NULL, BAD_CAST p, NULL);
+
+ if (!nop)
+ return NULL;
+
+ if (pf) {
+ // Prefixed name, is it the default NS prefix?
+ if (Doc->DefNs && !strcmp(pf, Doc->DefNs))
+ pf = NULL; // Default namespace
+
+ xmlNsPtr nsp = xmlSearchNs(Docp, nop, BAD_CAST pf);
+
+ if (!nsp)
+ nsp = xmlNewNs(nop, NULL, BAD_CAST pf);
+
+ // Set node namespace
+ nop->ns = nsp;
+ *(--p) = ':'; // Restore Xname
+ } else if (Doc->DefNs && xmlSearchNs(Docp, nop, NULL))
+ // Not in default namespace
+ nop->ns = xmlNewNs(nop, BAD_CAST "", NULL);
+
+ if (np)
+ ((PNODE2)np)->Nodep = nop;
+ else
+ np = new(g) XML2NODE(Doc, nop);
+
+ return NewChild(np);
+ } // end of AddChildNode
+
+/******************************************************************/
+/* Add a new property to this node and return it. */
+/******************************************************************/
+PXATTR XML2NODE::AddProperty(PGLOBAL g, char *name, PXATTR ap)
+ {
+ if (trace(1))
+ htrc("AddProperty: %-.256s\n", name);
+
+ xmlAttrPtr atp = xmlNewProp(Nodep, BAD_CAST name, NULL);
+
+ if (atp) {
+ if (ap) {
+ ((PATTR2)ap)->Atrp = atp;
+ ((PATTR2)ap)->Parent = Nodep;
+ return ap;
+ } else
+ return new(g) XML2ATTR(Doc, atp, Nodep);
+
+ } else
+ return NULL;
+
+ } // end of AddProperty
+
+/******************************************************************/
+/* Add a new text node to this node. */
+/******************************************************************/
+void XML2NODE::AddText(PGLOBAL g, PCSZ txtp)
+ {
+ if (trace(1))
+ htrc("AddText: %-.256s\n", txtp);
+
+ // This is to avoid a blank line when inserting a new line
+ xmlNodePtr np = xmlGetLastChild(Nodep);
+
+ if (np && np->type == XML_TEXT_NODE) {
+ xmlUnlinkNode(np);
+ xmlFreeNode(np);
+ } // endif type
+
+ // Add the new text
+ xmlAddChild(Nodep, xmlNewText(BAD_CAST txtp));
+ } // end of AddText
+
+/******************************************************************/
+/* Remove a child node from this node. */
+/******************************************************************/
+void XML2NODE::DeleteChild(PGLOBAL g, PXNODE dnp)
+ {
+ xmlErrorPtr xerr;
+
+ if (trace(1))
+ htrc("DeleteChild: node=%p\n", dnp);
+
+ xmlNodePtr np = ((PNODE2)dnp)->Nodep;
+ xmlNodePtr text = np->next;
+
+ // This is specific to row nodes
+ if (text && text->type == XML_TEXT_NODE) {
+ xmlUnlinkNode(text);
+
+ if ((xerr = xmlGetLastError()))
+ goto err;
+
+ xmlFreeNode(text);
+
+ if ((xerr = xmlGetLastError()))
+ goto err;
+
+ } // endif type
+
+ xmlUnlinkNode(np);
+
+ if ((xerr = xmlGetLastError()))
+ goto err;
+
+ xmlFreeNode(np);
+
+ if ((xerr = xmlGetLastError()))
+ goto err;
+
+ Delete(dnp);
+
+ if ((xerr = xmlGetLastError()))
+ goto err;
+
+ return;
+
+err:
+ if (trace(1))
+ htrc("DeleteChild: errmsg=%-.256s\n", xerr->message);
+
+ xmlResetError(xerr);
+ } // end of DeleteChild
+
+/* -------------------- class XML2NODELIST ---------------------- */
+
+/******************************************************************/
+/* XML2NODELIST constructor. */
+/******************************************************************/
+XML2NODELIST::XML2NODELIST(PXDOC dp, xmlNodeSetPtr lp)
+ : XMLNODELIST(dp)
+ {
+ Listp = lp;
+ } // end of XML2NODELIST constructor
+
+/******************************************************************/
+/* Return the length of the list. */
+/******************************************************************/
+int XML2NODELIST::GetLength(void)
+ {
+ return (Listp) ? Listp->nodeNr : 0;
+ } // end of GetLength
+
+/******************************************************************/
+/* Return the nth element of the list. */
+/******************************************************************/
+PXNODE XML2NODELIST::GetItem(PGLOBAL g, int n, PXNODE np)
+ {
+ if (trace(1))
+ htrc("GetItem: %d\n", n);
+
+ if (!Listp || Listp->nodeNr <= n)
+ return NULL;
+
+ if (np) {
+ ((PNODE2)np)->Nodep = Listp->nodeTab[n];
+ return np;
+ } else
+ return new(g) XML2NODE(Doc, Listp->nodeTab[n]);
+
+ } // end of GetItem
+
+/******************************************************************/
+/* Reset the pointer on the deleted item. */
+/******************************************************************/
+bool XML2NODELIST::DropItem(PGLOBAL g, int n)
+ {
+ if (trace(1))
+ htrc("DropItem: n=%d\n", n);
+
+ // We should do something here
+ if (!Listp || Listp->nodeNr <= n)
+ return true;
+
+ Listp->nodeTab[n] = NULL; // This was causing Valgrind warning
+ return false;
+ } // end of DropItem
+
+/* ---------------------- class XML2ATTR ------------------------ */
+
+/******************************************************************/
+/* XML2ATTR constructor. */
+/******************************************************************/
+XML2ATTR::XML2ATTR(PXDOC dp, xmlAttrPtr ap, xmlNodePtr np)
+ : XMLATTRIBUTE(dp)
+ {
+ Atrp = ap;
+ Parent = np;
+ } // end of XML2ATTR constructor
+
+/******************************************************************/
+/* Return the next sibling of the attribute. */
+/******************************************************************/
+PXATTR XML2ATTR::GetNext(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("Attr GetNext\n");
+
+ if (!Atrp->next)
+ return NULL;
+ else
+ return new(g) XML2ATTR(Doc, Atrp->next, Atrp->parent);
+
+ } // end of GetNext
+
+/******************************************************************/
+/* Return the text of an attribute. */
+/******************************************************************/
+RCODE XML2ATTR::GetText(PGLOBAL g, char *buf, int len)
+ {
+ RCODE rc = RC_OK;
+ xmlChar *txt;
+
+ if (trace(1))
+ htrc("GetText\n");
+
+ if ((txt = xmlGetProp(Atrp->parent, Atrp->name))) {
+ // Copy the text to the buffer
+ if (strlen((char*)txt) >= (unsigned)len) {
+ memcpy(buf, txt, len - 1);
+ buf[len - 1] = 0;
+ sprintf(g->Message, "Truncated %-.256s content", Atrp->name);
+ rc = RC_INFO;
+ } else
+ strcpy(buf, (const char*)txt);
+
+ xmlFree(txt);
+ } else
+ *buf = '\0';
+
+ if (trace(1))
+ htrc("GetText: %-.256s\n", buf);
+
+ return rc;
+ } // end of GetText
+
+/******************************************************************/
+/* Set the content of an attribute. */
+/******************************************************************/
+bool XML2ATTR::SetText(PGLOBAL g, char *txtp, int len)
+ {
+ if (trace(1))
+ htrc("SetText: %-.256s %d\n", txtp, len);
+
+ xmlSetProp(Parent, Atrp->name, BAD_CAST txtp);
+ return false;
+ } // end of SetText
diff --git a/storage/connect/libdoc.h b/storage/connect/libdoc.h
new file mode 100644
index 00000000..a0cead4e
--- /dev/null
+++ b/storage/connect/libdoc.h
@@ -0,0 +1,6 @@
+#ifndef LIBDOC_H_INCLUDED
+#define LIBDOC_H_INCLUDED
+void XmlInitParserLib(void);
+void XmlCleanupParserLib(void);
+void CloseXML2File(PGLOBAL, PFBLOCK, bool);
+#endif
diff --git a/storage/connect/macutil.cpp b/storage/connect/macutil.cpp
new file mode 100644
index 00000000..93cd0bcb
--- /dev/null
+++ b/storage/connect/macutil.cpp
@@ -0,0 +1,318 @@
+/***********************************************************************/
+/* MACUTIL: Author Olivier Bertrand -- 2008-2012 */
+/* From the article and sample code by Khalid Shaikh. */
+/***********************************************************************/
+#if defined(_WIN32)
+#include "my_global.h"
+#else // !_WIN32
+#error This is WINDOWS only DLL
+#endif // !_WIN32
+#include "global.h"
+#include "plgdbsem.h"
+#include "macutil.h"
+
+#if 0 // This is placed here just to know what are the actual values
+#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
+#define MAX_ADAPTER_NAME_LENGTH 256
+#define MAX_ADAPTER_ADDRESS_LENGTH 8
+#define DEFAULT_MINIMUM_ENTITIES 32
+#define MAX_HOSTNAME_LEN 128
+#define MAX_DOMAIN_NAME_LEN 128
+#define MAX_SCOPE_ID_LEN 256
+
+#define BROADCAST_NODETYPE 1
+#define PEER_TO_PEER_NODETYPE 2
+#define MIXED_NODETYPE 4
+#define HYBRID_NODETYPE 8
+
+#define IP_ADAPTER_DDNS_ENABLED 0x01
+#define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX 0x02
+#define IP_ADAPTER_DHCP_ENABLED 0x04
+#define IP_ADAPTER_RECEIVE_ONLY 0x08
+#define IP_ADAPTER_NO_MULTICAST 0x10
+#define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20
+#endif // 0
+
+/***********************************************************************/
+/* Implementation of the MACINFO class. */
+/***********************************************************************/
+MACINFO::MACINFO(bool adap, bool fix)
+ {
+ Fip = NULL;
+ Piaf = NULL;
+ Curp = NULL;
+ Buflen = 0;
+ Fix = fix;
+ Adap = adap;
+ N = -1;
+ } // end of MACINFO constructor
+
+/***********************************************************************/
+/* MACINFO: Return an error message. */
+/***********************************************************************/
+void MACINFO::MakeErrorMsg(PGLOBAL g, DWORD drc)
+ {
+ if (drc == ERROR_BUFFER_OVERFLOW)
+ sprintf(g->Message,
+ "GetAdaptersInfo: Buffer Overflow buflen=%d nbofadap=%d",
+ Buflen, N);
+ else if (drc == ERROR_INVALID_PARAMETER)
+ strcpy(g->Message, "GetAdaptersInfo: Invalid parameters");
+ else if (drc == ERROR_NO_DATA)
+ strcpy(g->Message,
+ "No adapter information exists for the local computer");
+ else if (drc == ERROR_NOT_SUPPORTED)
+ strcpy(g->Message, "GetAdaptersInfo is not supported");
+ else
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
+ 0, g->Message, sizeof(g->Message), NULL);
+
+ } // end of MakeErrorMsg
+
+/***********************************************************************/
+/* MAC: Get the number of found adapters. */
+/***********************************************************************/
+int MACINFO::GetNadap(PGLOBAL g)
+ {
+ if (N < 0) {
+ // Best method
+ if (Adap) {
+ DWORD drc = GetAdaptersInfo(NULL, &Buflen);
+
+ if (drc == ERROR_SUCCESS)
+ N = (Fix) ? 1 : 0;
+ else if (drc == ERROR_BUFFER_OVERFLOW)
+ N = Buflen / sizeof(IP_ADAPTER_INFO);
+ else
+ MakeErrorMsg(g, drc);
+
+ } else
+ N = (Fix) ? 1 : 0;
+
+#if 0
+ // This method returns too many adapters
+ DWORD dw, drc = GetNumberOfInterfaces((PDWORD)&dw);
+
+ if (drc == NO_ERROR) {
+ N = (int)dw;
+ Buflen = N * sizeof(IP_ADAPTER_INFO);
+ } else
+ MakeErrorMsg(g, 0);
+#endif
+ } // endif MaxSize
+
+ return N;
+ } // end of GetNadap
+
+/***********************************************************************/
+/* GetMacInfo: Get info for all found adapters. */
+/***********************************************************************/
+bool MACINFO::GetMacInfo(PGLOBAL g)
+ {
+ DWORD drc;
+
+ if (GetNadap(g) < 0)
+ return true;
+ else if (N == 0)
+ return false;
+
+ Piaf = (PIP_ADAPTER_INFO)PlugSubAlloc(g, NULL, Buflen);
+ drc = GetAdaptersInfo(Piaf, &Buflen);
+
+ if (drc == ERROR_SUCCESS) {
+ Curp = Piaf; // Curp is the first one
+ return false; // Success
+ } // endif drc
+
+ MakeErrorMsg(g, drc);
+ return true;
+ } // end of GetMacInfo
+
+/***********************************************************************/
+/* GetMacInfo: Get info for all found adapters. */
+/***********************************************************************/
+bool MACINFO::GetFixedInfo(PGLOBAL g)
+ {
+ ULONG len = (uint)sizeof(FIXED_INFO);
+ DWORD drc;
+
+ Fip = (FIXED_INFO*)PlugSubAlloc(g, NULL, len);
+ drc = GetNetworkParams(Fip, &len);
+
+ if (drc == ERROR_BUFFER_OVERFLOW) {
+ Fip = (FIXED_INFO*)PlugSubAlloc(g, NULL, len);
+ drc = GetNetworkParams(Fip, &len);
+ } // endif drc
+
+ if (drc != ERROR_SUCCESS) {
+ sprintf(g->Message, "GetNetworkParams failed. Rc=%08x\n", drc);
+ return true;
+ } // endif drc
+
+ return false;
+ } // end of GetFip
+
+#if 0
+#define IF_OTHER_ADAPTERTYPE 0
+#define IF_ETHERNET_ADAPTERTYPE 1
+#define IF_TOKEN_RING_ADAPTERTYPE 2
+#define IF_FDDI_ADAPTERTYPE 3
+#define IF_PPP_ADAPTERTYPE 4
+#define IF_LOOPBACK_ADAPTERTYPE 5
+#endif // 0
+
+/***********************************************************************/
+/* Get next MAC info. */
+/***********************************************************************/
+bool MACINFO::NextMac(void)
+ {
+ if (Curp)
+ Curp = Curp->Next;
+
+ return Curp != NULL;
+ } // end of NextMac
+
+/***********************************************************************/
+/* Get the next MAC address elements. */
+/***********************************************************************/
+bool MACINFO::GetOneInfo(PGLOBAL g, int flag, void *v, int lv)
+ {
+ char *p = NULL, buf[260] = "";
+ unsigned int i;
+ int n = 0;
+
+ if (!Curp && flag >= 10) {
+ // Fix info row, no adapter info available
+ switch (flag) {
+ case 13:
+ case 14:
+ case 19:
+ case 22:
+ case 23:
+ break;
+ default:
+ p = PlugDup(g, "");
+ } // endswitch flag
+
+ } else switch (flag) {
+ // FIXED INFO
+ case 1: // Host Name
+ p = Fip->HostName;
+ break;
+ case 2: // Domain Name
+ p = Fip->DomainName;
+ break;
+ case 3: // DNS IPaddress
+ p = (Fip->CurrentDnsServer)
+ ? (char*)&Fip->CurrentDnsServer->IpAddress
+ : (char*)&Fip->DnsServerList.IpAddress;
+ break;
+ case 4: // Node Type
+ n = (int)Fip->NodeType;
+ break;
+ case 5: // Scope ID ???
+ p = Fip->ScopeId;
+ break;
+ case 6: // Routing enabled
+ n = (int)Fip->EnableRouting;
+ break;
+ case 7: // Proxy enabled
+ n = (int)Fip->EnableProxy;
+ break;
+ case 8: // DNS enabled
+ n = (int)Fip->EnableDns;
+ break;
+ // ADAPTERS INFO
+ case 10: // Name
+ p = Curp->AdapterName;
+ break;
+ case 11: // Description
+ if ((p = strstr(Curp->Description, " - Packet Scheduler Miniport"))) {
+ strncpy(buf, Curp->Description, p - Curp->Description);
+ i = (int)(p - Curp->Description);
+ strncpy(buf, Curp->Description, i);
+ buf[i] = 0;
+ p = buf;
+ } else if ((p = strstr(Curp->Description,
+ " - Miniport d'ordonnancement de paquets"))) {
+ i = (int)(p - Curp->Description);
+ strncpy(buf, Curp->Description, i);
+ buf[i] = 0;
+ p = buf;
+ } else
+ p = Curp->Description;
+
+ break;
+ case 12: // MAC Address
+ for (p = buf, i = 0; i < Curp->AddressLength; i++) {
+ if (i)
+ strcat(p++, "-");
+
+ p += sprintf(p, "%.2X", Curp->Address[i]);
+ } // endfor i
+
+ p = buf;
+ break;
+ case 13: // Type
+#if 0 // This is not found in the SDK
+ switch (Curp->Type) {
+ case IF_ETHERNET_ADAPTERTYPE: p = "Ethernet Adapter"; break;
+ case IF_TOKEN_RING_ADAPTERTYPE: p = "Token Ring Adapter"; break;
+ case IF_FDDI_ADAPTERTYPE: p = "FDDI Adapter"; break;
+ case IF_PPP_ADAPTERTYPE: p = "PPP Adapter"; break;
+ case IF_LOOPBACK_ADAPTERTYPE: p = "Loop Back Adapter"; break;
+// case IF_SLIP_ADAPTERTYPE: p = "Generic Slip Adapter"; break;
+ default:
+ sprintf(buf, "Other Adapter, type=%d", Curp->Type);
+ p = buf;
+ } // endswitch Type
+#endif // 0
+ n = (int)Curp->Type;
+ break;
+ case 14: // DHCP enabled
+ n = (int)Curp->DhcpEnabled;
+ break;
+ case 15: // IP Address
+ p = (Curp->CurrentIpAddress)
+ ? (char*)&Curp->CurrentIpAddress->IpAddress
+ : (char*)&Curp->IpAddressList.IpAddress;
+ break;
+ case 16: // Subnet Mask
+ p = (Curp->CurrentIpAddress)
+ ? (char*)&Curp->CurrentIpAddress->IpMask
+ : (char*)&Curp->IpAddressList.IpMask;
+ break;
+ case 17: // Gateway
+ p = (char*)&Curp->GatewayList.IpAddress;
+ break;
+ case 18: // DHCP Server
+ p = (char*)&Curp->DhcpServer.IpAddress;
+ break;
+ case 19: // Have WINS
+ n = (Curp->HaveWins) ? 1 : 0;
+ break;
+ case 20: // Primary WINS
+ p = (char*)&Curp->PrimaryWinsServer.IpAddress;
+ break;
+ case 21: // Secondary WINS
+ p = (char*)&Curp->SecondaryWinsServer.IpAddress;
+ break;
+ case 22: // Lease obtained
+ n = (int)Curp->LeaseObtained;
+ break;
+ case 23: // Lease expires
+ n = (int)Curp->LeaseExpires;
+ break;
+ default:
+ sprintf(g->Message, "Invalid flag value %d", flag);
+ return true;
+ } // endswitch flag
+
+ if (p)
+ strncpy((char*)v, p, lv);
+ else
+ *((int*)v) = n;
+
+ return false;
+ } // end of GetOneInfo
diff --git a/storage/connect/macutil.h b/storage/connect/macutil.h
new file mode 100644
index 00000000..69a785dc
--- /dev/null
+++ b/storage/connect/macutil.h
@@ -0,0 +1,36 @@
+// MACUTIL.H Olivier Bertrand 2008-2012
+// Get Mac Addresses via GetAdaptersInfo
+#if defined(_WIN32)
+#include <iphlpapi.h>
+#else // !_WIN32
+#error This is WINDOWS only
+#endif // !_WIN32
+#include "block.h"
+
+typedef class MACINFO *MACIP;
+
+/***********************************************************************/
+/* This is the class declaration for MACINFO. */
+/***********************************************************************/
+class DllExport MACINFO : public BLOCK {
+ public:
+ // Constructor
+ MACINFO(bool adap, bool fix);
+
+ // Implementation
+ int GetNadap(PGLOBAL g);
+ bool GetMacInfo(PGLOBAL g);
+ bool GetFixedInfo(PGLOBAL g);
+ void MakeErrorMsg(PGLOBAL g, DWORD drc);
+ bool NextMac(void);
+ bool GetOneInfo(PGLOBAL g, int flag, void *v, int lv);
+
+ // Members
+ FIXED_INFO *Fip; // Points to fixed info structure
+ PIP_ADAPTER_INFO Piaf; // Points on Adapter info array
+ PIP_ADAPTER_INFO Curp; // Points on current Adapt info
+ ULONG Buflen; // Buffer length
+ bool Fix; // true if FixedInfo is needed
+ bool Adap; // true if Piaf is needed
+ int N; // Number of adapters
+ }; // end of class MACINFO
diff --git a/storage/connect/maputil.cpp b/storage/connect/maputil.cpp
new file mode 100644
index 00000000..b722a438
--- /dev/null
+++ b/storage/connect/maputil.cpp
@@ -0,0 +1,200 @@
+#include "my_global.h"
+#ifdef UNIX
+#include "osutil.h"
+#include <errno.h>
+#include <stddef.h>
+#else /* WINDOWS */
+//#include <windows.h>
+#include "osutil.h"
+#endif /* WINDOWS */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "global.h"
+#include "plgdbsem.h"
+#include "maputil.h"
+
+#ifdef _WIN32
+/***********************************************************************/
+/* In Insert mode, just open the file for append. Otherwise */
+/* create the mapping file object. The map handle can be released */
+/* immediately because they will not be used anymore. */
+/* If del is true in DELETE mode, then delete the whole file. */
+/* Returns the file handle that can be used by caller. */
+/***********************************************************************/
+HANDLE CreateFileMap(PGLOBAL g, LPCSTR filename,
+ MEMMAP *mm, MODE mode, bool del)
+ {
+ HANDLE hFile;
+ HANDLE hFileMap;
+ DWORD access, share, disposition;
+
+ memset(mm, 0, sizeof(MEMMAP));
+ *g->Message = '\0';
+
+ switch (mode) {
+ case MODE_READ:
+ access = GENERIC_READ;
+ share = FILE_SHARE_READ;
+ disposition = OPEN_EXISTING;
+ break;
+ case MODE_UPDATE:
+ case MODE_DELETE:
+ access = GENERIC_READ | GENERIC_WRITE;
+ share = 0;
+ disposition = (del) ? TRUNCATE_EXISTING : OPEN_EXISTING;
+ break;
+ case MODE_INSERT:
+ access = GENERIC_WRITE;
+ share = 0;
+ disposition = OPEN_ALWAYS;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_FUNC_MODE), "CreateFileMap", mode);
+ return INVALID_HANDLE_VALUE;
+ } // endswitch
+
+ hFile = CreateFile(filename, access, share, NULL, disposition,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (hFile != INVALID_HANDLE_VALUE)
+ if (mode != MODE_INSERT) {
+ /*****************************************************************/
+ /* Create the file-mapping object. */
+ /*****************************************************************/
+ access = (mode == MODE_READ) ? PAGE_READONLY : PAGE_READWRITE;
+ hFileMap = CreateFileMapping(hFile, NULL, access, 0, 0, NULL);
+
+ if (!hFileMap) {
+ DWORD ler = GetLastError();
+
+ if (ler && ler != 1006) {
+ sprintf(g->Message, MSG(FILE_MAP_ERROR), filename, ler);
+ CloseHandle(hFile);
+ return INVALID_HANDLE_VALUE;
+ } else {
+ sprintf(g->Message, MSG(FILE_IS_EMPTY), filename);
+ return hFile;
+ } // endif ler
+
+ } // endif hFileMap
+
+ access = (mode == MODE_READ) ? FILE_MAP_READ : FILE_MAP_WRITE;
+
+ if (!(mm->memory = MapViewOfFile(hFileMap, access, 0, 0, 0))) {
+ DWORD ler = GetLastError();
+
+ sprintf(g->Message, "Error %ld in MapViewOfFile %s",
+ ler, filename);
+ CloseHandle(hFile);
+ return INVALID_HANDLE_VALUE;
+ } // endif memory
+
+ // lenH is the high-order word of the file size
+ mm->lenL = GetFileSize(hFile, &mm->lenH);
+ CloseHandle(hFileMap); // Not used anymore
+ } else // MODE_INSERT
+ /*****************************************************************/
+ /* The starting point must be the end of file as for append. */
+ /*****************************************************************/
+ SetFilePointer(hFile, 0, NULL, FILE_END);
+
+ return hFile;
+ } // end of CreateFileMap
+
+bool CloseMemMap(LPVOID memory, size_t dwSize)
+ {
+ return (memory) ? !UnmapViewOfFile(memory) : false;
+ } // end of CloseMemMap
+
+#else /* UNIX */
+// Code to handle Linux and Solaris
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/***********************************************************************/
+/* In Insert mode, just open the file for append. Otherwise */
+/* create the mapping file object. The map handle can be released */
+/* immediately because they will not be used anymore. */
+/* If del is true in DELETE mode, then delete the whole file. */
+/* Returns the file handle that can be used by caller. */
+/***********************************************************************/
+HANDLE CreateFileMap(PGLOBAL g, LPCSTR fileName,
+ MEMMAP *mm, MODE mode, bool del)
+ {
+ unsigned int openMode;
+ int protmode;
+ HANDLE fd;
+ size_t filesize;
+ struct stat st;
+
+ memset(mm, 0, sizeof(MEMMAP));
+ *g->Message = '\0';
+
+ switch (mode) {
+ case MODE_READ:
+ openMode = O_RDONLY;
+ protmode = PROT_READ;
+ break;
+ case MODE_UPDATE:
+ case MODE_DELETE:
+ openMode = (del) ? (O_RDWR | O_TRUNC) : O_RDWR;
+ protmode = PROT_READ | PROT_WRITE;
+ break;
+ case MODE_INSERT:
+ openMode = (O_WRONLY | O_CREAT | O_APPEND);
+ protmode = PROT_WRITE;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_FUNC_MODE), "CreateFileMap", mode);
+ return INVALID_HANDLE_VALUE;
+ } // endswitch
+
+ // Try to open the addressed file.
+ fd= global_open(g, MSGID_NONE, fileName, openMode);
+
+ if (fd != INVALID_HANDLE_VALUE && mode != MODE_INSERT) {
+ /* We must know about the size of the file. */
+ if (fstat(fd, &st)) {
+ sprintf(g->Message, MSG(FILE_MAP_ERROR), fileName, errno);
+ close(fd);
+ return INVALID_HANDLE_VALUE;
+ } // endif fstat
+
+ if ((filesize = st.st_size))
+ // Now we are ready to load the file. If mmap() is available we try
+ // this first. If not available or it failed we try to load it.
+ mm->memory = mmap(NULL, filesize, protmode, MAP_SHARED, fd, 0);
+ else
+ mm->memory = 0;
+
+ if (mm->memory != MAP_FAILED) {
+ mm->lenL = (mm->memory != 0) ? filesize : 0;
+ mm->lenH = 0;
+ } else {
+ strcpy(g->Message, "Memory mapping failed");
+ close(fd);
+ return INVALID_HANDLE_VALUE;
+ } // endif memory
+
+ } /* endif fd */
+
+ // mmap() call was successful. ??????????
+ return fd;
+ } // end of CreateFileMap
+
+bool CloseMemMap(void *memory, size_t dwSize)
+ {
+ if (memory) {
+ // All this must be redesigned
+ msync((char*)memory, dwSize, MS_SYNC);
+ return (munmap((char*)memory, dwSize) < 0) ? true : false;
+ } else
+ return false;
+
+ } // end of CloseMemMap
+
+#endif // UNIX
diff --git a/storage/connect/maputil.h b/storage/connect/maputil.h
new file mode 100644
index 00000000..e310488e
--- /dev/null
+++ b/storage/connect/maputil.h
@@ -0,0 +1,21 @@
+#ifndef __MAPUTIL_H__
+#define __MAPUTIL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ void *memory;
+ DWORD lenL;
+ DWORD lenH;
+ } MEMMAP;
+
+DllExport HANDLE CreateFileMap(PGLOBAL, LPCSTR, MEMMAP *, MODE, bool);
+DllExport bool CloseMemMap(void *memory, size_t dwSize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MAPUTIL_H__ */
diff --git a/storage/connect/messages.h b/storage/connect/messages.h
new file mode 100644
index 00000000..b55ec39b
--- /dev/null
+++ b/storage/connect/messages.h
@@ -0,0 +1,13 @@
+/**************************************************************************/
+/* NLS messsages definition. */
+/**************************************************************************/
+#if defined(FRENCH)
+#if defined(CPX)
+#include "frmsg1.h"
+#else /* not CPX */
+#include "frmsg2.h"
+#endif /* CPX */
+#else /* not FRENCH */
+#include "engmsg.h"
+#endif /* FRENCH */
+/* ---------------------------------------------------------------------- */
diff --git a/storage/connect/mini-global.h b/storage/connect/mini-global.h
new file mode 100644
index 00000000..f7127958
--- /dev/null
+++ b/storage/connect/mini-global.h
@@ -0,0 +1,33 @@
+/***********************************************************************/
+/* Definitions needed by the included files. */
+/***********************************************************************/
+#if !defined(MY_GLOBAL_H)
+#define MY_GLOBAL_H
+typedef unsigned int uint;
+typedef unsigned int uint32;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+typedef unsigned long DWORD;
+typedef char *LPSTR;
+typedef const char *LPCSTR;
+typedef int BOOL;
+#if defined(_WINDOWS)
+typedef void *HANDLE;
+#else
+typedef int HANDLE;
+#endif
+typedef char *PSZ;
+typedef const char *PCSZ;
+typedef unsigned char BYTE;
+typedef unsigned char uchar;
+typedef long long longlong;
+typedef unsigned long long ulonglong;
+typedef char my_bool;
+struct charset_info_st {};
+typedef const charset_info_st CHARSET_INFO;
+#define FALSE 0
+#define TRUE 1
+#define Item char
+#define MY_MAX(a,b) ((a>b)?(a):(b))
+#define MY_MIN(a,b) ((a<b)?(a):(b))
+#endif // MY_GLOBAL_H
diff --git a/storage/connect/mongo.cpp b/storage/connect/mongo.cpp
new file mode 100644
index 00000000..a9c48136
--- /dev/null
+++ b/storage/connect/mongo.cpp
@@ -0,0 +1,451 @@
+/************** mongo C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: mongo Version 1.1 */
+/* (C) Copyright to the author Olivier BERTRAND 2021 */
+/* These programs are the MGODEF class execution routines. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "filter.h"
+#if defined(CMGO_SUPPORT)
+#include "tabcmg.h"
+#endif // CMGO_SUPPORT
+#if defined(JAVA_SUPPORT)
+#include "tabjmg.h"
+#endif // JAVA_SUPPORT
+#include "resource.h"
+
+/***********************************************************************/
+/* This should be an option. */
+/***********************************************************************/
+#define MAXCOL 200 /* Default max column nb in result */
+#define TYPE_UNKNOWN 12 /* Must be greater than other types */
+
+bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s);
+bool IsNum(PSZ s);
+int GetDefaultDepth(void);
+bool JsonAllPath(void);
+
+/***********************************************************************/
+/* Make selector json representation for Mongo tables. */
+/***********************************************************************/
+bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s)
+{
+ OPVAL opc = fp->GetOpc();
+
+ s->Append('{');
+
+ if (opc == OP_AND || opc == OP_OR) {
+ if (fp->GetArgType(0) != TYPE_FILTER || fp->GetArgType(1) != TYPE_FILTER)
+ return true;
+
+ s->Append("\"$");
+ s->Append(opc == OP_AND ? "and" : "or");
+ s->Append("\":[");
+
+ if (MakeSelector(g, (PFIL)fp->Arg(0), s))
+ return true;
+
+ s->Append(',');
+
+ if (MakeSelector(g, (PFIL)fp->Arg(1), s))
+ return true;
+
+ s->Append(']');
+ } else {
+ if (fp->GetArgType(0) != TYPE_COLBLK)
+ return true;
+
+ s->Append('"');
+ s->Append(((PCOL)fp->Arg(0))->GetJpath(g, false));
+ s->Append("\":{\"$");
+
+ switch (opc) {
+ case OP_EQ:
+ s->Append("eq");
+ break;
+ case OP_NE:
+ s->Append("ne");
+ break;
+ case OP_GT:
+ s->Append("gt");
+ break;
+ case OP_GE:
+ s->Append("gte");
+ break;
+ case OP_LT:
+ s->Append("lt");
+ break;
+ case OP_LE:
+ s->Append("lte");
+ break;
+ case OP_NULL:
+ case OP_LIKE:
+ case OP_EXIST:
+ default:
+ return true;
+ } // endswitch Opc
+
+ s->Append("\":");
+
+ if (fp->GetArgType(1) == TYPE_COLBLK) {
+ s->Append("\"$");
+ s->Append(((PEXTCOL)fp->Arg(1))->GetJpath(g, false));
+ s->Append('"');
+ } else {
+ char buf[501];
+
+ fp->Arg(1)->Prints(g, buf, 500);
+ s->Append(buf);
+ } // endif Type
+
+ s->Append('}');
+ } // endif opc
+
+ s->Append('}');
+ return false;
+} // end of MakeSelector
+
+/***********************************************************************/
+/* MGOColumns: construct the result blocks containing the description */
+/* of all the columns of a document contained inside MongoDB. */
+/***********************************************************************/
+PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info)
+{
+ static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
+ TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
+ static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
+ FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
+ unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
+ int ncol = sizeof(buftyp) / sizeof(int);
+ int i, n = 0;
+ PCSZ drv;
+ PBCOL bcp;
+ MGODISC *cmgd = NULL;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ if (info) {
+ length[0] = 128;
+ length[7] = 256;
+ goto skipit;
+ } // endif info
+
+ /*********************************************************************/
+ /* Open MongoDB. */
+ /*********************************************************************/
+ drv = GetStringTableOption(g, topt, "Driver", NULL);
+
+ if (drv && toupper(*drv) == 'C') {
+#if defined(CMGO_SUPPORT)
+ cmgd = new(g) CMGDISC(g, (int*)length);
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "C");
+ goto err;
+#endif
+ } else if (drv && toupper(*drv) == 'J') {
+#if defined(JAVA_SUPPORT)
+ cmgd = new(g) JMGDISC(g, (int*)length);
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "Java");
+ goto err;
+#endif
+ } else { // Driver not specified
+#if defined(CMGO_SUPPORT)
+ cmgd = new(g) CMGDISC(g, (int*)length);
+#else
+ cmgd = new(g) JMGDISC(g, (int*)length);
+#endif
+ } // endif drv
+
+ if ((n = cmgd->GetColumns(g, db, uri, topt)) < 0)
+ goto err;
+
+skipit:
+ if (trace(1))
+ htrc("MGOColumns: n=%d len=%d\n", n, length[0]);
+
+ /*********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /*********************************************************************/
+ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, false);
+
+ crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
+ crp->Name = "Nullable";
+ crp->Next->Name = "Bpath";
+
+ if (info || !qrp)
+ return qrp;
+
+ qrp->Nblin = n;
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ for (i = 0, bcp = cmgd->fbcp; bcp; i++, bcp = bcp->Next) {
+ if (bcp->Type == TYPE_UNKNOWN) // Void column
+ bcp->Type = TYPE_STRING;
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(bcp->Name, i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(bcp->Type, i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(bcp->Type), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(bcp->Len, i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(bcp->Len, i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(bcp->Scale, i);
+ crp = crp->Next; // Nullable
+ crp->Kdata->SetValue(bcp->Cbn ? 1 : 0, i);
+ crp = crp->Next; // Field format
+
+ if (crp->Kdata)
+ crp->Kdata->SetValue(bcp->Fmt, i);
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* Return the result pointer. */
+ /*********************************************************************/
+ return qrp;
+
+err:
+ if (cmgd && cmgd->tmgp)
+ cmgd->tmgp->CloseDB(g);
+
+ return NULL;
+} // end of MGOColumns
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+MGODISC::MGODISC(PGLOBAL g, int *lg) {
+ length = lg;
+ fbcp = NULL;
+ pbcp = NULL;
+ tmgp = NULL;
+ drv = NULL;
+ i = ncol = lvl = 0;
+ all = false;
+} // end of MGODISC constructor
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt)
+{
+ PMGODEF tdp;
+
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
+ all = GetBooleanTableOption(g, topt, "Fullarray", false);
+
+ /*********************************************************************/
+ /* Open the MongoDB collection. */
+ /*********************************************************************/
+ tdp = new(g) MGODEF;
+ tdp->Uri = (uri && *uri) ? uri : "mongodb://localhost:27017";
+ tdp->Driver = drv;
+ tdp->Tabname = GetStringTableOption(g, topt, "Name", NULL);
+ tdp->Tabname = GetStringTableOption(g, topt, "Tabname", tdp->Tabname);
+ tdp->Tabschema = GetStringTableOption(g, topt, "Dbname", db);
+ tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0;
+ tdp->Colist = GetStringTableOption(g, topt, "Colist", "all");
+ tdp->Filter = GetStringTableOption(g, topt, "Filter", NULL);
+ tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false);
+ tdp->Version = GetIntegerTableOption(g, topt, "Version", 3);
+ tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper",
+ (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface");
+
+ if (trace(1))
+ htrc("Uri %s coll=%s db=%s colist=%s filter=%s lvl=%d\n",
+ tdp->Uri, tdp->Tabname, tdp->Tabschema, tdp->Colist, tdp->Filter, lvl);
+
+ tmgp = tdp->GetTable(g, MODE_READ);
+ tmgp->SetMode(MODE_READ);
+
+ if (tmgp->OpenDB(g))
+ return -1;
+
+ bcol.Next = NULL;
+ bcol.Name = bcol.Fmt = NULL;
+ bcol.Type = TYPE_UNKNOWN;
+ bcol.Len = bcol.Scale = 0;
+ bcol.Found = true;
+ bcol.Cbn = false;
+
+ if (Init(g))
+ return -1;
+
+ /*********************************************************************/
+ /* Analyse the BSON tree and define columns. */
+ /*********************************************************************/
+ for (i = 1; ; i++) {
+ switch (tmgp->ReadDB(g)) {
+ case RC_EF:
+ return ncol;
+ case RC_FX:
+ return -1;
+ default:
+ GetDoc();
+ } // endswitch ReadDB
+
+ if (Find(g))
+ return -1;
+
+ // Missing columns can be null
+ for (bcp = fbcp; bcp; bcp = bcp->Next) {
+ bcp->Cbn |= !bcp->Found;
+ bcp->Found = false;
+ } // endfor bcp
+
+ } // endfor i
+
+ return ncol;
+} // end of GetColumns
+
+/***********************************************************************/
+/* Add a new column in the column list. */
+/***********************************************************************/
+void MGODISC::AddColumn(PGLOBAL g, PCSZ colname, PCSZ fmt, int k)
+{
+ // Check whether this column was already found
+ for (bcp = fbcp; bcp; bcp = bcp->Next)
+ if (!strcmp(colname, bcp->Name))
+ break;
+
+ if (bcp) {
+ if (bcp->Type != bcol.Type)
+ bcp->Type = TYPE_STRING;
+
+ if (k && *fmt && (!bcp->Fmt || strlen(bcp->Fmt) < strlen(fmt))) {
+ bcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], (signed)strlen(fmt));
+ } // endif *fmt
+
+ bcp->Len = MY_MAX(bcp->Len, bcol.Len);
+ bcp->Scale = MY_MAX(bcp->Scale, bcol.Scale);
+ bcp->Cbn |= bcol.Cbn;
+ bcp->Found = true;
+ } else {
+ // New column
+ bcp = (PBCOL)PlugSubAlloc(g, NULL, sizeof(BCOL));
+ *bcp = bcol;
+ bcp->Cbn |= (i > 1);
+ bcp->Name = PlugDup(g, colname);
+ length[0] = MY_MAX(length[0], (signed)strlen(colname));
+
+ if (k || JsonAllPath()) {
+ bcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], (signed)strlen(fmt));
+ } else
+ bcp->Fmt = NULL;
+
+ if (pbcp) {
+ bcp->Next = pbcp->Next;
+ pbcp->Next = bcp;
+ } else
+ fbcp = bcp;
+
+ ncol++;
+ } // endif jcp
+
+ pbcp = bcp;
+} // end of AddColumn
+
+/* -------------------------- Class MGODEF --------------------------- */
+
+MGODEF::MGODEF(void)
+{
+ Driver = NULL;
+ Uri = NULL;
+ Colist = NULL;
+ Filter = NULL;
+ Base = 0;
+ Version = 0;
+ Pipe = false;
+} // end of MGODEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values. */
+/***********************************************************************/
+bool MGODEF::DefineAM(PGLOBAL g, LPCSTR, int poff)
+{
+ if (EXTDEF::DefineAM(g, "MGO", poff))
+ return true;
+ else if (!Tabschema)
+ Tabschema = GetStringCatInfo(g, "Dbname", "*");
+
+ Driver = GetStringCatInfo(g, "Driver", NULL);
+ Uri = GetStringCatInfo(g, "Connect", "mongodb://localhost:27017");
+ Colist = GetStringCatInfo(g, "Colist", NULL);
+ Filter = GetStringCatInfo(g, "Filter", NULL);
+ Strfy = GetStringCatInfo(g, "Stringify", NULL);
+ Base = GetIntCatInfo("Base", 0) ? 1 : 0;
+ Version = GetIntCatInfo("Version", 3);
+
+ if (Version == 2)
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface");
+ else
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface");
+
+ Pipe = GetBoolCatInfo("Pipeline", false);
+ return false;
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB MGODEF::GetTable(PGLOBAL g, MODE m)
+{
+ if (Driver && toupper(*Driver) == 'C') {
+#if defined(CMGO_SUPPORT)
+ if (Catfunc == FNC_COL)
+ return new(g) TDBGOL(this);
+ else
+ return new(g) TDBCMG(this);
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "C");
+ return NULL;
+#endif
+ } else if (Driver && toupper(*Driver) == 'J') {
+#if defined(JAVA_SUPPORT)
+ if (Catfunc == FNC_COL)
+ return new(g) TDBJGL(this);
+ else
+ return new(g) TDBJMG(this);
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "Java");
+ return NULL;
+#endif
+ } else { // Driver not specified
+#if defined(CMGO_SUPPORT)
+ if (Catfunc == FNC_COL)
+ return new(g) TDBGOL(this);
+ else
+ return new(g) TDBCMG(this);
+#else
+ if (Catfunc == FNC_COL)
+ return new(g) TDBJGL(this);
+ else
+ return new(g) TDBJMG(this);
+#endif
+ } // endif Driver
+
+} // end of GetTable
diff --git a/storage/connect/mongo.h b/storage/connect/mongo.h
new file mode 100644
index 00000000..7e92a7dc
--- /dev/null
+++ b/storage/connect/mongo.h
@@ -0,0 +1,91 @@
+/**************** mongo H Declares Source Code File (.H) ***************/
+/* Name: mongo.h Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2021 */
+/* */
+/* This file contains the common MongoDB classes declares. */
+/***********************************************************************/
+#ifndef __MONGO_H
+#define __MONGO_H
+
+#include "osutil.h"
+#include "block.h"
+#include "colblk.h"
+
+typedef class MGODEF *PMGODEF;
+
+typedef struct _bncol {
+ struct _bncol *Next;
+ char *Name;
+ char *Fmt;
+ int Type;
+ int Len;
+ int Scale;
+ bool Cbn;
+ bool Found;
+} BCOL, *PBCOL;
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+class MGODISC : public BLOCK {
+public:
+ // Constructor
+ MGODISC(PGLOBAL g, int *lg);
+
+ // Methods
+ virtual bool Init(PGLOBAL g) { return false; }
+ virtual void GetDoc(void) {}
+ virtual bool Find(PGLOBAL g) = 0;
+
+ // Functions
+ int GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt);
+ void AddColumn(PGLOBAL g, PCSZ colname, PCSZ fmt, int k);
+
+ // Members
+ BCOL bcol;
+ PBCOL bcp, fbcp, pbcp;
+ PMGODEF tdp;
+ PTDB tmgp;
+ PCSZ drv;
+ int *length;
+ int i, ncol, lvl;
+ bool all;
+}; // end of MGODISC
+
+/***********************************************************************/
+/* MongoDB table. */
+/***********************************************************************/
+class DllExport MGODEF : public EXTDEF { /* Table description */
+ friend class TDBCMG;
+ friend class TDBJMG;
+ friend class TDBGOL;
+ friend class TDBJGL;
+ friend class CMGFAM;
+ friend class MGODISC;
+ friend DllExport PQRYRES MGOColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool);
+public:
+ // Constructor
+ MGODEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) { return "MONGO"; }
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+protected:
+ // Members
+ PCSZ Driver; /* MongoDB Driver (C or JAVA) */
+ PCSZ Uri; /* MongoDB connection URI */
+ PSZ Wrapname; /* Java wrapper name */
+ PCSZ Colist; /* Options list */
+ PCSZ Filter; /* Filtering query */
+ PCSZ Strfy; /* The stringify columns */
+ int Base; /* The array index base */
+ int Version; /* The Java driver version */
+ bool Pipe; /* True is Colist is a pipeline */
+}; // end of MGODEF
+
+#endif // __MONGO_H
diff --git a/storage/connect/msgid.h b/storage/connect/msgid.h
new file mode 100644
index 00000000..cee78aa1
--- /dev/null
+++ b/storage/connect/msgid.h
@@ -0,0 +1,326 @@
+/* Copyright (C) MariaDB Corporation Ab */
+#define MSG_ACCESS_VIOLATN 200
+#define MSG_ADD_BAD_TYPE 201
+#define MSG_ALLOC_ERROR 202
+#define MSG_ANSWER_TYPE 203
+#define MSG_API_CONF_ERROR 204
+#define MSG_APPL_NOT_INIT 205
+#define MSG_ARRAY_BNDS_EXCD 206
+#define MSG_BAD_ARRAY_OPER 207
+#define MSG_BAD_ARRAY_TYPE 208
+#define MSG_BAD_ARRAY_VAL 209
+#define MSG_BAD_BIN_FMT 210
+#define MSG_BAD_BLK_ESTIM 211
+#define MSG_BAD_BLK_SIZE 212
+#define MSG_BAD_BYTE_NUM 213
+#define MSG_BAD_BYTE_READ 214
+#define MSG_BAD_COL_TYPE 215
+#define MSG_BAD_COL_XPATH 216
+#define MSG_BAD_CONST_TYPE 217
+#define MSG_BAD_CONV_TYPE 218
+#define MSG_BAD_DATETIME 219
+#define MSG_BAD_DBF_FILE 220
+#define MSG_BAD_DBF_REC 221
+#define MSG_BAD_DBF_TYPE 222
+#define MSG_BAD_DIRECTORY 223
+#define MSG_BAD_FIELD_RANK 224
+#define MSG_BAD_FIELD_TYPE 225
+#define MSG_BAD_FILE_HANDLE 226
+#define MSG_BAD_FILTER 227
+#define MSG_BAD_FILTER_CONV 228
+#define MSG_BAD_FILTER_OP 229
+#define MSG_BAD_FLD_FORMAT 230
+#define MSG_BAD_FLD_LENGTH 231
+#define MSG_BAD_FREQ_SET 232
+#define MSG_BAD_FUNC_MODE 233
+#define MSG_BAD_HANDLE_VAL 234
+#define MSG_BAD_HEADER 235
+#define MSG_BAD_HEAD_END 236
+#define MSG_BAD_INDEX_FILE 237
+#define MSG_BAD_LINEFLD_FMT 238
+#define MSG_BAD_LINE_LEN 239
+#define MSG_BAD_LRECL 240
+#define MSG_BAD_NODE_TYPE 241
+#define MSG_BAD_OFFSET_VAL 242
+#define MSG_BAD_OPEN_MODE 243
+#define MSG_BAD_PARAM_TYPE 244
+#define MSG_BAD_PARM_COUNT 245
+#define MSG_BAD_QUOTE_FIELD 246
+#define MSG_BAD_READ_NUMBER 247
+#define MSG_BAD_RECFM 248
+#define MSG_BAD_RECFM_VAL 249
+#define MSG_BAD_SET_CASE 250
+#define MSG_BAD_SET_STRING 251
+#define MSG_BAD_SPECIAL_COL 252
+#define MSG_BAD_SPEC_COLUMN 253
+#define MSG_BAD_TABLE_TYPE 254
+#define MSG_BAD_TYPE_LIKE 255
+#define MSG_BAD_VALBLK_INDX 256
+#define MSG_BAD_VALBLK_TYPE 257
+#define MSG_BAD_VALNODE 258
+#define MSG_BAD_VALUE_TYPE 259
+#define MSG_BAD_VAL_UPDATE 260
+#define MSG_BAS_NS_LIST 261
+#define MSG_BIN_F_TOO_LONG 262
+#define MSG_BIN_MODE_FAIL 263
+#define MSG_BLKTYPLEN_MISM 264
+#define MSG_BLK_IS_NULL 265
+#define MSG_BREAKPOINT 266
+#define MSG_BUILD_INDEX 267
+#define MSG_CANNOT_OPEN 268
+#define MSG_CHSIZE_ERROR 269
+#define MSG_COL_ALLOC_ERR 270
+#define MSG_COL_ISNOT_TABLE 271
+#define MSG_COL_NOT_SORTED 272
+#define MSG_COL_NUM_MISM 273
+#define MSG_COM_ERROR 274
+#define MSG_CONCAT_SUBNODE 275
+#define MSG_CONNECT_CANCEL 276
+#define MSG_CONTROL_C_EXIT 277
+#define MSG_DATABASE_LOADED 278
+#define MSG_DATA_MISALIGN 279
+#define MSG_DBASE_FILE 280
+#define MSG_DEF_ALLOC_ERROR 281
+#define MSG_DEL_FILE_ERR 282
+#define MSG_DEL_READ_ERROR 283
+#define MSG_DEL_WRITE_ERROR 284
+#define MSG_DEPREC_FLAG 285
+#define MSG_DLL_LOAD_ERROR 286
+#define MSG_DOM_NOT_SUPP 287
+#define MSG_DVAL_NOTIN_LIST 288
+#define MSG_EMPTY_DOC 289
+#define MSG_EMPTY_FILE 290
+#define MSG_EOF_AFTER_LINE 291
+#define MSG_EOF_INDEX_FILE 292
+#define MSG_ERROR_IN_LSK 293
+#define MSG_ERROR_IN_SFP 294
+#define MSG_ERR_READING_REC 295
+#define MSG_FAIL_ADD_NODE 296
+#define MSG_FETCH_NO_RES 297
+#define MSG_FIELD_TOO_LONG 298
+#define MSG_FILELEN_ERROR 299
+#define MSG_FILE_IS_EMPTY 300
+#define MSG_FILE_MAP_ERR 301
+#define MSG_FILE_MAP_ERROR 302
+#define MSG_FILE_OPEN_YET 303
+#define MSG_FILE_UNFOUND 304
+#define MSG_FLD_TOO_LNG_FOR 305
+#define MSG_FLT_BAD_RESULT 306
+#define MSG_FLT_DENORMAL_OP 307
+#define MSG_FLT_INVALID_OP 308
+#define MSG_FLT_OVERFLOW 309
+#define MSG_FLT_STACK_CHECK 310
+#define MSG_FLT_UNDERFLOW 311
+#define MSG_FLT_ZERO_DIVIDE 312
+#define MSG_FMT_WRITE_NIY 313
+#define MSG_FOXPRO_FILE 314
+#define MSG_FPUTS_ERROR 315
+#define MSG_FSEEK_ERROR 316
+#define MSG_FSETPOS_ERROR 317
+#define MSG_FTELL_ERROR 318
+#define MSG_FUNCTION_ERROR 319
+#define MSG_FUNC_ERRNO 320
+#define MSG_FUNC_ERROR 321
+#define MSG_FUNC_ERR_S 322
+#define MSG_FWRITE_ERROR 323
+#define MSG_GET_DIST_VALS 324
+#define MSG_GET_FUNC_ERR 325
+#define MSG_GLOBAL_ERROR 326
+#define MSG_GUARD_PAGE 327
+#define MSG_GZOPEN_ERROR 328
+#define MSG_ILLEGAL_INSTR 329
+#define MSG_ILL_FILTER_CONV 330
+#define MSG_INDEX_NOT_UNIQ 331
+#define MSG_INDEX_YET_ON 332
+#define MSG_INDX_COL_NOTIN 333
+#define MSG_INDX_EXIST_YET 334
+#define MSG_INIT_FAILED 335
+#define MSG_INT_COL_ERROR 336
+#define MSG_INT_OVERFLOW 337
+#define MSG_INT_ZERO_DIVIDE 338
+#define MSG_INVALID_DISP 339
+#define MSG_INVALID_FTYPE 340
+#define MSG_INVALID_HANDLE 341
+#define MSG_INVALID_OPER 342
+#define MSG_INV_COLUMN_TYPE 343
+#define MSG_INV_COL_TYPE 344
+#define MSG_INV_DEF_READ 345
+#define MSG_INV_DIRCOL_OFST 346
+#define MSG_INV_MAP_POS 347
+#define MSG_INV_RAND_ACC 348
+#define MSG_INV_REC_POS 349
+#define MSG_INV_RESULT_TYPE 350
+#define MSG_INV_UPDT_TABLE 351
+#define MSG_IN_WITHOUT_SUB 352
+#define MSG_KEY_ALLOC_ERR 353
+#define MSG_KEY_ALLOC_ERROR 354
+#define MSG_LINE_TOO_LONG 355
+#define MSG_LIST 356
+#define MSG_LOADING_FAILED 357
+#define MSG_LRECL_TOO_SMALL 358
+#define MSG_MAKE_EMPTY_FILE 359
+#define MSG_MAKING 360
+#define MSG_MALLOC_ERROR 361
+#define MSG_MAP_VIEW_ERROR 362
+#define MSG_MAXSIZE_ERROR 363
+#define MSG_MEM_ALLOC_ERR 364
+#define MSG_MEM_ALLOC_ERROR 365
+#define MSG_MISPLACED_QUOTE 366
+#define MSG_MISSING_ARG 367
+#define MSG_MISSING_FIELD 368
+#define MSG_MISSING_FNAME 369
+#define MSG_MISSING_NODE 370
+#define MSG_MISSING_ROWNODE 371
+#define MSG_MIS_TAG_LIST 372
+#define MSG_MUL_MAKECOL_ERR 373
+#define MSG_NAME_CONV_ERR 374
+#define MSG_NEW_DOC_FAILED 375
+#define MSG_NEW_RETURN_NULL 376
+#define MSG_NEXT_FILE_ERROR 377
+#define MSG_NONCONT_EXCEPT 378
+#define MSG_NOP_ZLIB_INDEX 379
+#define MSG_NOT_A_DBF_FILE 380
+#define MSG_NOT_FIXED_LEN 381
+#define MSG_NO_0DH_HEAD 382
+#define MSG_NO_ACTIVE_DB 383
+#define MSG_NO_CHAR_FROM 384
+#define MSG_NO_DATE_FMT 385
+#define MSG_NO_DEF_FNCCOL 386
+#define MSG_NO_DEF_PIVOTCOL 387
+#define MSG_NO_DIR_INDX_RD 388
+#define MSG_NO_FEAT_SUPPORT 389
+#define MSG_NO_FLD_FORMAT 390
+#define MSG_NO_FORMAT_COL 391
+#define MSG_NO_FORMAT_TYPE 392
+#define MSG_NO_INDEX_READ 393
+#define MSG_NO_KEY_COL 394
+#define MSG_NO_KEY_UPDATE 395
+#define MSG_NO_MAP_INSERT 396
+#define MSG_NO_MATCHING_COL 397
+#define MSG_NO_MATCH_COL 398
+#define MSG_NO_MEMORY 399
+#define MSG_NO_MODE_PADDED 400
+#define MSG_NO_MUL_VCT 401
+#define MSG_NO_ODBC_DELETE 402
+#define MSG_NO_ODBC_DIRECT 403
+#define MSG_NO_ODBC_MUL 404
+#define MSG_NO_ODBC_SPECOL 405
+#define MSG_NO_PART_DEL 406
+#define MSG_NO_PART_MAP 407
+#define MSG_NO_PAR_BLK_INS 408
+#define MSG_NO_PIV_DIR_ACC 409
+#define MSG_NO_READ_32 410
+#define MSG_NO_RECOV_SPACE 411
+#define MSG_NO_ROWID_FOR_AM 412
+#define MSG_NO_ROW_NODE 413
+#define MSG_NO_SECTION_NAME 414
+#define MSG_NO_SEC_UPDATE 415
+#define MSG_NO_SETPOS_YET 416
+#define MSG_NO_SPEC_COL 417
+#define MSG_NO_SUB_VAL 418
+#define MSG_NO_TABCOL_DATA 419
+#define MSG_NO_TABLE_DEL 420
+#define MSG_NO_TAB_DATA 421
+#define MSG_NO_VCT_DELETE 422
+#define MSG_NO_ZIP_DELETE 423
+#define MSG_OPENING 424
+#define MSG_OPEN_EMPTY_FILE 425
+#define MSG_OPEN_ERROR 426
+#define MSG_OPEN_ERROR_IS 427
+#define MSG_OPEN_MODE_ERROR 428
+#define MSG_OPEN_STRERROR 429
+#define MSG_OPTBLK_RD_ERR 430
+#define MSG_OPTBLK_WR_ERR 431
+#define MSG_OPTIMIZING 432
+#define MSG_OPT_BMAP_RD_ERR 433
+#define MSG_OPT_BMAP_WR_ERR 434
+#define MSG_OPT_CANCELLED 435
+#define MSG_OPT_DVAL_RD_ERR 436
+#define MSG_OPT_DVAL_WR_ERR 437
+#define MSG_OPT_HEAD_RD_ERR 438
+#define MSG_OPT_HEAD_WR_ERR 439
+#define MSG_OPT_LOGIC_ERR 440
+#define MSG_OPT_MAX_RD_ERR 441
+#define MSG_OPT_MAX_WR_ERR 442
+#define MSG_OPT_MIN_RD_ERR 443
+#define MSG_OPT_MIN_WR_ERR 444
+#define MSG_OPT_NOT_MATCH 445
+#define MSG_PAGE_ERROR 446
+#define MSG_PARM_CNT_MISS 447
+#define MSG_PREC_VBLP_NULL 448
+#define MSG_PRIV_INSTR 449
+#define MSG_PROCADD_ERROR 450
+#define MSG_QUERY_CANCELLED 451
+#define MSG_RANGE_NO_JOIN 452
+#define MSG_RC_READING 453
+#define MSG_READY 454
+#define MSG_READ_ERROR 455
+#define MSG_READ_ONLY 456
+#define MSG_READ_SEEK_ERROR 457
+#define MSG_REGISTER_ERR 458
+#define MSG_REMOVE_ERROR 459
+#define MSG_RENAME_ERROR 460
+#define MSG_ROWID_NOT_IMPL 461
+#define MSG_SEC_KEY_FIRST 462
+#define MSG_SEC_NAME_FIRST 463
+#define MSG_SEP_IN_FIELD 464
+#define MSG_SEQUENCE_ERROR 465
+#define MSG_SETEOF_ERROR 466
+#define MSG_SETRECPOS_NIY 467
+#define MSG_SET_STR_TRUNC 468
+#define MSG_SFP_ERROR 469
+#define MSG_SHARED_LIB_ERR 470
+#define MSG_SINGLE_STEP 471
+#define MSG_SORTING_VAL 472
+#define MSG_SPCOL_READONLY 473
+#define MSG_SQL_CONF_ERROR 474
+#define MSG_SRCH_CLOSE_ERR 475
+#define MSG_SRC_TABLE_UNDEF 476
+#define MSG_STACK_OVERFLOW 477
+#define MSG_TABDIR_READONLY 478
+#define MSG_TABLE_NOT_OPT 479
+#define MSG_TABLE_NO_INDEX 480
+#define MSG_TABLE_READ_ONLY 481
+#define MSG_TABMUL_READONLY 482
+#define MSG_TOO_MANY_FIELDS 483
+#define MSG_TOO_MANY_JUMPS 484
+#define MSG_TOO_MANY_KEYS 485
+#define MSG_TO_BLK_IS_NULL 486
+#define MSG_TRUNCATE_ERROR 487
+#define MSG_TRUNC_BY_ESTIM 488
+#define MSG_TYPE_MISMATCH 489
+#define MSG_TYPE_VALUE_ERR 490
+#define MSG_UNBALANCE_QUOTE 491
+#define MSG_UNDEFINED_AM 492
+#define MSG_UNKNOWN_EXCPT 493
+#define MSG_UNMATCH_FIL_ARG 494
+#define MSG_UPDATE_ERROR 495
+#define MSG_UPD_ZIP_NOT_IMP 496
+#define MSG_VALSTR_TOO_LONG 497
+#define MSG_VALTYPE_NOMATCH 498
+#define MSG_VALUE_ERROR 499
+#define MSG_VALUE_TOO_BIG 500
+#define MSG_VALUE_TOO_LONG 501
+#define MSG_VAL_ALLOC_ERR 502
+#define MSG_VIR_NO_DELETE 503
+#define MSG_VIR_READ_ONLY 504
+#define MSG_VOID_FIRST_ARG 505
+#define MSG_WORK_AREA 506
+#define MSG_WRITE_SEEK_ERR 507
+#define MSG_WRITE_STRERROR 508
+#define MSG_WRITING 509
+#define MSG_WRITING_ERROR 510
+#define MSG_WS_CONV_ERR 511
+#define MSG_XCOL_MISMATCH 512
+#define MSG_XFILE_READERR 513
+#define MSG_XFILE_WRITERR 514
+#define MSG_XMLTAB_INIT_ERR 515
+#define MSG_XML_INIT_ERROR 516
+#define MSG_XPATH_CNTX_ERR 517
+#define MSG_XPATH_EVAL_ERR 518
+#define MSG_XPATH_NOT_SUPP 519
+#define MSG_ZERO_DIVIDE 520
+#define MSG_FIX_OVFLW_ADD 521
+#define MSG_FIX_OVFLW_TIMES 522
+#define MSG_FIX_UNFLW_ADD 523
+#define MSG_FIX_UNFLW_TIMES 524
diff --git a/storage/connect/mycat.cc b/storage/connect/mycat.cc
new file mode 100644
index 00000000..d4b182b4
--- /dev/null
+++ b/storage/connect/mycat.cc
@@ -0,0 +1,583 @@
+/* Copyright (C) MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*************** Mycat CC Program Source Code File (.CC) ***************/
+/* PROGRAM NAME: MYCAT */
+/* ------------- */
+/* Version 1.8 */
+/* */
+/* Author: Olivier Bertrand 2012 - 2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the DB description related routines. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#define DONT_DEFINE_VOID
+#include <my_global.h>
+
+#if defined(UNIX)
+#include <unistd.h>
+#include <string.h>
+#endif
+#include "handler.h"
+#undef OFFSET
+
+/***********************************************************************/
+/* Include application header files */
+/* */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing DB application declarations. */
+/* tabdos.h is header containing TDBDOS classes declarations. */
+/* MYCAT.h is header containing DB description declarations. */
+/***********************************************************************/
+#if defined(UNIX)
+#include "osutil.h"
+#endif // UNIX
+#include "global.h"
+#include "plgdbsem.h"
+//#include "reldef.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "tabcol.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#include "tabfmt.h"
+#if defined(VCT_SUPPORT)
+#include "tabvct.h"
+#endif // VCT_SUPPORT
+#include "tabsys.h"
+#if defined(_WIN32)
+#include "tabmac.h"
+#include "tabwmi.h"
+#endif // _WIN32
+//#include "tabtbl.h"
+#include "tabxcl.h"
+#include "tabtbl.h"
+#include "taboccur.h"
+#include "tabmul.h"
+#include "tabmysql.h"
+#if defined(ODBC_SUPPORT)
+#define NODBC
+#include "tabodbc.h"
+#endif // ODBC_SUPPORT
+#if defined(JAVA_SUPPORT)
+#define NJDBC
+#include "tabjdbc.h"
+#endif // JAVA_SUPPORT
+#include "tabpivot.h"
+#include "tabvir.h"
+#if defined(BSON_SUPPORT)
+#include "tabbson.h"
+#else
+#include "tabjson.h"
+#endif // BSON_SUPPORT
+#include "ha_connect.h"
+#if defined(XML_SUPPORT)
+#include "tabxml.h"
+#endif // XML_SUPPORT
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+#include "mongo.h"
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
+#if defined(ZIP_SUPPORT)
+#include "tabzip.h"
+#endif // ZIP_SUPPORT
+#if defined(REST_SUPPORT)
+#include "tabrest.h"
+#endif // REST_SUPPORT
+#include "mycat.h"
+
+/***********************************************************************/
+/* Extern static variables. */
+/***********************************************************************/
+#if defined(_WIN32)
+extern "C" HINSTANCE s_hModule; // Saved module handle
+#endif // !_WIN32
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+bool MongoEnabled(void);
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
+#if defined(BSON_SUPPORT)
+bool Force_Bson(void);
+#endif // BSON_SUPPORT
+
+/***********************************************************************/
+/* Get the plugin directory. */
+/***********************************************************************/
+char *GetPluginDir(void)
+{
+ return opt_plugin_dir;
+} // end of GetPluginDir
+
+/***********************************************************************/
+/* Get the lc_messages_dir, it is where error messages for various */
+/* languages are installed, and by default the INSTALL_MYSQLSHAREDIR. */
+/***********************************************************************/
+char *GetMessageDir(void)
+{
+ return lc_messages_dir;
+} // end of GetMessageDir
+
+/***********************************************************************/
+/* Get a unique enum table type ID. */
+/***********************************************************************/
+TABTYPE GetTypeID(const char *type)
+ {
+ return (!type) ? TAB_UNDEF
+ : (!stricmp(type, "DOS")) ? TAB_DOS
+ : (!stricmp(type, "FIX")) ? TAB_FIX
+ : (!stricmp(type, "BIN")) ? TAB_BIN
+ : (!stricmp(type, "CSV")) ? TAB_CSV
+ : (!stricmp(type, "FMT")) ? TAB_FMT
+ : (!stricmp(type, "DBF")) ? TAB_DBF
+#if defined(XML_SUPPORT)
+ : (!stricmp(type, "XML")) ? TAB_XML
+#endif // XML_SUPPORT
+ : (!stricmp(type, "INI")) ? TAB_INI
+ : (!stricmp(type, "VEC")) ? TAB_VEC
+#if defined(ODBC_SUPPORT)
+ : (!stricmp(type, "ODBC")) ? TAB_ODBC
+#endif // ODBC_SUPPORT
+#if defined(JAVA_SUPPORT)
+ : (!stricmp(type, "JDBC")) ? TAB_JDBC
+#endif // JAVA_SUPPORT
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+ : (!stricmp(type, "MONGO") && MongoEnabled()) ? TAB_MONGO
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
+ : (!stricmp(type, "MYSQL")) ? TAB_MYSQL
+ : (!stricmp(type, "MYPRX")) ? TAB_MYSQL
+ : (!stricmp(type, "DIR")) ? TAB_DIR
+#if defined(_WIN32)
+ : (!stricmp(type, "MAC")) ? TAB_MAC
+ : (!stricmp(type, "WMI")) ? TAB_WMI
+#endif // _WIN32
+ : (!stricmp(type, "TBL")) ? TAB_TBL
+ : (!stricmp(type, "XCOL")) ? TAB_XCL
+ : (!stricmp(type, "OCCUR")) ? TAB_OCCUR
+ : (!stricmp(type, "CATLG")) ? TAB_PRX // Legacy
+ : (!stricmp(type, "PROXY")) ? TAB_PRX
+ : (!stricmp(type, "PIVOT")) ? TAB_PIVOT
+ : (!stricmp(type, "VIR")) ? TAB_VIR
+ : (!stricmp(type, "JSON")) ? TAB_JSON
+#if defined(BSON_SUPPORT)
+ : (!stricmp(type, "BSON")) ? TAB_BSON
+#endif // BSON_SUPPORT
+#if defined(ZIP_SUPPORT)
+ : (!stricmp(type, "ZIP")) ? TAB_ZIP
+#endif // ZIP_SUPPORT
+ : (!stricmp(type, "OEM")) ? TAB_OEM : TAB_NIY;
+ } // end of GetTypeID
+
+/***********************************************************************/
+/* Return true for table types based on file. */
+/***********************************************************************/
+bool IsFileType(TABTYPE type)
+ {
+ bool isfile;
+
+ switch (type) {
+ case TAB_DOS:
+ case TAB_FIX:
+ case TAB_BIN:
+ case TAB_CSV:
+ case TAB_FMT:
+ case TAB_DBF:
+ case TAB_XML:
+ case TAB_INI:
+ case TAB_VEC:
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+#endif // BSON_SUPPORT
+ case TAB_REST:
+ // case TAB_ZIP:
+ isfile= true;
+ break;
+ default:
+ isfile= false;
+ break;
+ } // endswitch type
+
+ return isfile;
+ } // end of IsFileType
+
+/***********************************************************************/
+/* Return true for table types returning exact row count. */
+/***********************************************************************/
+bool IsExactType(TABTYPE type)
+ {
+ bool exact;
+
+ switch (type) {
+ case TAB_FIX:
+ case TAB_BIN:
+ case TAB_DBF:
+// case TAB_XML: depends on Multiple || Xpand || Coltype
+// case TAB_JSON: depends on Multiple || Xpand || Coltype
+ case TAB_VEC:
+ case TAB_VIR:
+ exact= true;
+ break;
+ default:
+ exact= false;
+ break;
+ } // endswitch type
+
+ return exact;
+ } // end of IsExactType
+
+/***********************************************************************/
+/* Return true for table types accepting null fields. */
+/***********************************************************************/
+bool IsTypeNullable(TABTYPE type)
+ {
+ bool nullable;
+
+ switch (type) {
+ case TAB_MAC:
+ case TAB_DIR:
+ nullable= false;
+ break;
+ default:
+ nullable= true;
+ break;
+ } // endswitch type
+
+ return nullable;
+ } // end of IsTypeNullable
+
+/***********************************************************************/
+/* Return true for fixed record length tables. */
+/***********************************************************************/
+bool IsTypeFixed(TABTYPE type)
+ {
+ bool fix;
+
+ switch (type) {
+ case TAB_FIX:
+ case TAB_BIN:
+ case TAB_VEC:
+// case TAB_DBF: ???
+ fix= true;
+ break;
+ default:
+ fix= false;
+ break;
+ } // endswitch type
+
+ return fix;
+ } // end of IsTypeFixed
+
+/***********************************************************************/
+/* Return true for table indexable by XINDEX. */
+/***********************************************************************/
+bool IsTypeIndexable(TABTYPE type)
+ {
+ bool idx;
+
+ switch (type) {
+ case TAB_DOS:
+ case TAB_CSV:
+ case TAB_FMT:
+ case TAB_FIX:
+ case TAB_BIN:
+ case TAB_VEC:
+ case TAB_DBF:
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+#endif // BSON_SUPPORT
+ idx= true;
+ break;
+ default:
+ idx= false;
+ break;
+ } // endswitch type
+
+ return idx;
+ } // end of IsTypeIndexable
+
+/***********************************************************************/
+/* Return index type: 0 NO, 1 XINDEX, 2 REMOTE. */
+/***********************************************************************/
+int GetIndexType(TABTYPE type)
+ {
+ int xtyp;
+
+ switch (type) {
+ case TAB_DOS:
+ case TAB_CSV:
+ case TAB_FMT:
+ case TAB_FIX:
+ case TAB_BIN:
+ case TAB_VEC:
+ case TAB_DBF:
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ case TAB_BSON:
+#endif // BSON_SUPPORT
+ xtyp= 1;
+ break;
+ case TAB_MYSQL:
+ case TAB_ODBC:
+ case TAB_JDBC:
+ case TAB_MONGO:
+ xtyp= 2;
+ break;
+ case TAB_VIR:
+ xtyp= 3;
+ break;
+ default:
+ xtyp= 0;
+ break;
+ } // endswitch type
+
+ return xtyp;
+ } // end of GetIndexType
+
+/***********************************************************************/
+/* Get a unique enum catalog function ID. */
+/***********************************************************************/
+uint GetFuncID(const char *func)
+ {
+ uint fnc;
+
+ if (!func)
+ fnc= FNC_NO;
+ else if (!strnicmp(func, "col", 3))
+ fnc= FNC_COL;
+ else if (!strnicmp(func, "tab", 3))
+ fnc= FNC_TABLE;
+ else if (!stricmp(func, "dsn") ||
+ !strnicmp(func, "datasource", 10) ||
+ !strnicmp(func, "source", 6) ||
+ !strnicmp(func, "sqldatasource", 13))
+ fnc= FNC_DSN;
+ else if (!strnicmp(func, "driver", 6) ||
+ !strnicmp(func, "sqldriver", 9))
+ fnc= FNC_DRIVER;
+ else
+ fnc= FNC_NIY;
+
+ return fnc;
+ } // end of GetFuncID
+
+/* ------------------------- Class CATALOG --------------------------- */
+
+/***********************************************************************/
+/* CATALOG Constructor. */
+/***********************************************************************/
+CATALOG::CATALOG(void)
+ {
+#if defined(_WIN32)
+//DataPath= ".\\";
+#else // !_WIN32
+//DataPath= "./";
+#endif // !_WIN32
+ memset(&Ctb, 0, sizeof(CURTAB));
+ Cbuf= NULL;
+ Cblen= 0;
+ DefHuge= false;
+ } // end of CATALOG constructor
+
+/* -------------------------- Class MYCAT ---------------------------- */
+
+/***********************************************************************/
+/* MYCAT Constructor. */
+/***********************************************************************/
+MYCAT::MYCAT(PHC hc) : CATALOG()
+ {
+ Hc= hc;
+ DefHuge= false;
+ } // end of MYCAT constructor
+
+/***********************************************************************/
+/* Nothing to do for CONNECT. */
+/***********************************************************************/
+void MYCAT::Reset(void)
+ {
+ } // end of Reset
+
+/***********************************************************************/
+/* GetTableDesc: retrieve a table descriptor. */
+/* Look for a table descriptor matching the name and type. */
+/***********************************************************************/
+PTABDEF MYCAT::GetTableDesc(PGLOBAL g, PTABLE tablep,
+ LPCSTR type, PRELDEF *)
+{
+ PTABDEF tdp= NULL;
+
+ if (trace(1))
+ htrc("GetTableDesc: name=%s am=%s\n", tablep->GetName(), SVP(type));
+
+ // If not specified get the type of this table
+ //if (!type)
+ // type= Hc->GetStringOption("Type","*");
+
+ tdp= MakeTableDesc(g, tablep, type);
+
+ if (trace(1))
+ htrc("GetTableDesc: tdp=%p\n", tdp);
+
+ return tdp;
+} // end of GetTableDesc
+
+/***********************************************************************/
+/* MakeTableDesc: make a table/view description. */
+/* Note: caller must check if name already exists before calling it. */
+/***********************************************************************/
+PTABDEF MYCAT::MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am)
+ {
+ TABTYPE tc;
+ LPCSTR name= (PSZ)PlugDup(g, tablep->GetName());
+ LPCSTR schema= (PSZ)PlugDup(g, tablep->GetSchema());
+ PTABDEF tdp= NULL;
+
+ if (trace(1))
+ htrc("MakeTableDesc: name=%s schema=%s am=%s\n",
+ name, SVP(schema), SVP(am));
+
+ /*********************************************************************/
+ /* Get a unique enum identifier for types. */
+ /*********************************************************************/
+ if (!am) {
+ tc= Hc->GetRealType();
+ am= Hc->GetStringOption("Type","*");
+ } else
+ tc= GetTypeID(am);
+
+ switch (tc) {
+ case TAB_FIX:
+ case TAB_BIN:
+ case TAB_DBF:
+ case TAB_DOS: tdp= new(g) DOSDEF; break;
+ case TAB_CSV:
+ case TAB_FMT: tdp= new(g) CSVDEF; break;
+ case TAB_INI: tdp= new(g) INIDEF; break;
+ case TAB_DIR: tdp= new(g) DIRDEF; break;
+#if defined(XML_SUPPORT)
+ case TAB_XML: tdp= new(g) XMLDEF; break;
+#endif // XML_SUPPORT
+#if defined(VCT_SUPPORT)
+ case TAB_VEC: tdp= new(g) VCTDEF; break;
+#endif // VCT_SUPPORT
+#if defined(ODBC_SUPPORT)
+ case TAB_ODBC: tdp= new(g) ODBCDEF; break;
+#endif // ODBC_SUPPORT
+#if defined(JAVA_SUPPORT)
+ case TAB_JDBC: tdp= new(g) JDBCDEF; break;
+#endif // JAVA_SUPPORT
+#if defined(_WIN32)
+ case TAB_MAC: tdp= new(g) MACDEF; break;
+ case TAB_WMI: tdp= new(g) WMIDEF; break;
+#endif // _WIN32
+ case TAB_OEM: tdp= new(g) OEMDEF; break;
+ case TAB_TBL: tdp= new(g) TBLDEF; break;
+ case TAB_XCL: tdp= new(g) XCLDEF; break;
+ case TAB_PRX: tdp= new(g) PRXDEF; break;
+ case TAB_OCCUR: tdp= new(g) OCCURDEF; break;
+ case TAB_MYSQL: tdp= new(g) MYSQLDEF; break;
+ case TAB_PIVOT: tdp= new(g) PIVOTDEF; break;
+ case TAB_VIR: tdp= new(g) VIRDEF; break;
+ case TAB_JSON:
+#if defined(BSON_SUPPORT)
+ if (Force_Bson())
+ tdp= new(g) BSONDEF;
+ else
+#endif // BSON_SUPPORT
+ tdp= new(g) JSONDEF;
+
+ break;
+#if defined(BSON_SUPPORT)
+ case TAB_BSON: tdp= new(g) BSONDEF; break;
+#endif // BSON_SUPPORT
+#if defined(ZIP_SUPPORT)
+ case TAB_ZIP: tdp= new(g) ZIPDEF; break;
+#endif // ZIP_SUPPORT
+#if defined(REST_SUPPORT)
+ case TAB_REST: tdp= new (g) RESTDEF; break;
+#endif // REST_SUPPORT
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+ case TAB_MONGO:
+ if (MongoEnabled()) {
+ tdp = new(g) MGODEF;
+ break;
+ } // endif enabled
+ // fall through
+#endif // JAVA_SUPPORT || CMGO_SUPPORT
+ default:
+ sprintf(g->Message, MSG(BAD_TABLE_TYPE), am, name);
+ } // endswitch
+
+ // Do make the table/view definition
+ if (tdp && tdp->Define(g, this, name, schema, am))
+ tdp = NULL;
+
+ if (trace(1))
+ htrc("Table %s made\n", am);
+
+ return tdp;
+ } // end of MakeTableDesc
+
+/***********************************************************************/
+/* Initialize a Table Description Block construction. */
+/***********************************************************************/
+PTDB MYCAT::GetTable(PGLOBAL g, PTABLE tablep, MODE mode, LPCSTR type)
+ {
+ PTABDEF tdp;
+ PTDB tdbp= NULL;
+// LPCSTR name= tablep->GetName();
+
+ if (trace(1))
+ htrc("GetTableDB: name=%s\n", tablep->GetName());
+
+ // Look for the description of the requested table
+ tdp= GetTableDesc(g, tablep, type);
+
+ if (tdp) {
+ if (trace(1))
+ htrc("tdb=%p type=%s\n", tdp, tdp->GetType());
+
+ if (tablep->GetSchema())
+ tdp->Database = SetPath(g, tablep->GetSchema());
+
+ if (trace(2))
+ htrc("Going to get table...\n");
+
+ tdbp= tdp->GetTable(g, mode);
+ } // endif tdp
+
+ if (tdbp) {
+ if (trace(1))
+ htrc("tdbp=%p name=%s amtype=%d\n", tdbp, tdbp->GetName(),
+ tdbp->GetAmType());
+ tablep->SetTo_Tdb(tdbp);
+ tdbp->SetTable(tablep);
+ tdbp->SetMode(mode);
+ } // endif tdbp
+
+ return (tdbp);
+ } // end of GetTable
+
+/***********************************************************************/
+/* ClearDB: Terminates Database usage. */
+/***********************************************************************/
+void MYCAT::ClearDB(PGLOBAL)
+ {
+ } // end of ClearDB
+
+/* ------------------------ End of MYCAT --------------------------- */
diff --git a/storage/connect/mycat.h b/storage/connect/mycat.h
new file mode 100644
index 00000000..147148f4
--- /dev/null
+++ b/storage/connect/mycat.h
@@ -0,0 +1,119 @@
+/* Copyright (C) MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**************** MYCAT H Declares Source Code File (.H) ***************/
+/* Name: MYCAT.H Version 2.4 */
+/* Author: Olivier Bertrand */
+/* This file contains the CONNECT plugin MYCAT class definitions. */
+/***********************************************************************/
+#ifndef __MYCAT__H
+#define __MYCAT__H
+
+#include "block.h"
+#include "catalog.h"
+
+//typedef struct ha_table_option_struct TOS, *PTOS;
+
+/**
+ structure for CREATE TABLE options (table options)
+
+ These can be specified in the CREATE TABLE:
+ CREATE TABLE ( ... ) {...here...}
+*/
+struct ha_table_option_struct {
+ const char *type;
+ const char *filename;
+ const char *optname;
+ const char *tabname;
+ const char *tablist;
+ const char *dbname;
+ const char *separator;
+//const char *connect;
+ const char *qchar;
+ const char *module;
+ const char *subtype;
+ const char *catfunc;
+ const char *srcdef;
+ const char *colist;
+ const char *filter;
+ const char *oplist;
+ const char *data_charset;
+ const char *http;
+ const char *uri;
+ ulonglong lrecl;
+ ulonglong elements;
+//ulonglong estimate;
+ ulonglong multiple;
+ ulonglong header;
+ ulonglong quoted;
+ ulonglong ending;
+ ulonglong compressed;
+ bool mapped;
+ bool huge;
+ bool split;
+ bool readonly;
+ bool sepindex;
+ bool zipped;
+ };
+
+// Possible value for catalog functions
+#define FNC_NO (1 << 0) // Not a catalog table
+#define FNC_COL (1 << 1) // Column catalog function
+#define FNC_TABLE (1 << 2) // Table catalog function
+#define FNC_DSN (1 << 3) // Data Source catalog function
+#define FNC_DRIVER (1 << 4) // Column catalog function
+#define FNC_NIY (1 << 5) // Catalog function NIY
+
+typedef class ha_connect *PHC;
+
+char *GetPluginDir(void);
+char *GetMessageDir(void);
+TABTYPE GetTypeID(const char *type);
+bool IsFileType(TABTYPE type);
+bool IsExactType(TABTYPE type);
+bool IsTypeNullable(TABTYPE type);
+bool IsTypeFixed(TABTYPE type);
+bool IsTypeIndexable(TABTYPE type);
+int GetIndexType(TABTYPE type);
+uint GetFuncID(const char *func);
+
+/***********************************************************************/
+/* MYCAT: class for managing the CONNECT plugin DB items. */
+/***********************************************************************/
+class MYCAT : public CATALOG {
+ public:
+ MYCAT(PHC hc); // Constructor
+
+ // Implementation
+ PHC GetHandler(void) {return Hc;}
+ void SetHandler(PHC hc) {Hc= hc;}
+
+ // Methods
+ void Reset(void);
+ bool StoreIndex(PGLOBAL, PTABDEF) {return false;} // Temporary
+ PTABDEF GetTableDesc(PGLOBAL g, PTABLE tablep,
+ LPCSTR type, PRELDEF *prp = NULL);
+ PTDB GetTable(PGLOBAL g, PTABLE tablep,
+ MODE mode = MODE_READ, LPCSTR type = NULL);
+ void ClearDB(PGLOBAL g);
+
+ protected:
+ PTABDEF MakeTableDesc(PGLOBAL g, PTABLE tablep, LPCSTR am);
+
+ // Members
+ ha_connect *Hc; // The Connect handler
+ }; // end of class MYCAT
+
+#endif /* __MYCAT__H */
diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp
new file mode 100644
index 00000000..ca372847
--- /dev/null
+++ b/storage/connect/myconn.cpp
@@ -0,0 +1,1092 @@
+/************** MyConn C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: MYCONN */
+/* ------------- */
+/* Version 1.9 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2007-2017 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* Implements a connection to MySQL. */
+/* It can optionally use the embedded MySQL library. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* MYCONN.CPP - Source code */
+/* MYCONN.H - MYCONN class declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/************************************************************************/
+#include "my_global.h"
+#if !defined(MYSQL_PREPARED_STATEMENTS)
+#include "my_sys.h"
+#include "mysqld_error.h"
+#endif // !MYSQL_PREPARED_STATEMENTS
+#if defined(_WIN32)
+//#include <windows.h>
+#else // !_WIN32
+#include "osutil.h"
+#endif // !_WIN32
+
+#include "global.h"
+#include "plgdbsem.h"
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+//#include "value.h"
+//#include "valblk.h"
+#include "xobject.h"
+#define DLL_EXPORT // Items are exported from this DLL
+#include "myconn.h"
+
+//extern "C" int zconv;
+int GetConvSize(void);
+extern MYSQL_PLUGIN_IMPORT uint mysqld_port;
+extern MYSQL_PLUGIN_IMPORT char *mysqld_unix_port;
+
+DllExport void PushWarning(PGLOBAL, THD*, int level = 1);
+
+// Returns the current used port
+uint GetDefaultPort(void)
+{
+ return mysqld_port;
+} // end of GetDefaultPort
+
+#if !defined(MYSQL_PREPARED_STATEMENTS)
+/**************************************************************************
+ Alloc struct for use with unbuffered reads. Data is fetched by domand
+ when calling to mysql_fetch_row.
+ mysql_data_seek is a noop.
+
+ No other queries may be specified with the same MYSQL handle.
+ There shouldn't be much processing per row because mysql server shouldn't
+ have to wait for the client (and will not wait more than 30 sec/packet).
+ NOTE: copied from client.c cli_use_result
+**************************************************************************/
+static MYSQL_RES *connect_use_result(MYSQL *mysql)
+{
+ MYSQL_RES *result;
+ DBUG_ENTER("connect_use_result");
+
+ if (!mysql->fields)
+ DBUG_RETURN(NULL);
+
+ if (mysql->status != MYSQL_STATUS_GET_RESULT) {
+ my_message(ER_UNKNOWN_ERROR, "Command out of sync", MYF(0));
+ DBUG_RETURN(NULL);
+ } // endif status
+
+ if (!(result = (MYSQL_RES*) my_malloc(PSI_NOT_INSTRUMENTED,
+ sizeof(*result) + sizeof(ulong) * mysql->field_count,
+ MYF(MY_WME | MY_ZEROFILL))))
+ DBUG_RETURN(NULL);
+
+ result->lengths = (ulong*)(result+1);
+ result->methods = mysql->methods;
+
+ /* Ptrs: to one row */
+ if (!(result->row = (MYSQL_ROW)my_malloc(PSI_NOT_INSTRUMENTED,
+ sizeof(result->row[0]) * (mysql->field_count+1), MYF(MY_WME)))) {
+ my_free(result);
+ DBUG_RETURN(NULL);
+ } // endif row
+
+ result->fields = mysql->fields;
+ result->field_alloc = mysql->field_alloc;
+ result->field_count = mysql->field_count;
+ result->current_field = 0;
+ result->handle = mysql;
+ result->current_row = 0;
+ mysql->fields = 0; /* fields is now in result */
+ clear_alloc_root(&mysql->field_alloc);
+ mysql->status = MYSQL_STATUS_USE_RESULT;
+ mysql->unbuffered_fetch_owner = &result->unbuffered_fetch_cancelled;
+ DBUG_RETURN(result); /* Data is ready to be fetched */
+} // end of connect_use_result
+#endif // !MYSQL_PREPARED_STATEMENTS
+
+/************************************************************************/
+/* MyColumns: constructs the result blocks containing all columns */
+/* of a MySQL table or view. */
+/* info = TRUE to get catalog column information. */
+/************************************************************************/
+PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db,
+ const char *user, const char *pwd,
+ const char *table, const char *colpat,
+ int port, bool info)
+ {
+ int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
+ TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT,
+ TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
+ TYPE_STRING};
+ XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
+ FLD_KEY, FLD_SCALE, FLD_RADIX, FLD_NULL,
+ FLD_REM, FLD_NO, FLD_DEFAULT, FLD_EXTRA,
+ FLD_CHARSET};
+ //unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0};
+ unsigned int length[] = {0, 4, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0};
+ PCSZ fmt;
+ char *fld, *colname, *chset, v, buf[128], uns[16], zero[16];
+ int i, n, nf = 0, ncol = sizeof(buftyp) / sizeof(int);
+ int len, type, prec, rc;
+ bool b;
+ PQRYRES qrp;
+ PCOLRES crp;
+ MYSQLC myc;
+
+ if (!port)
+ port = mysqld_port;
+
+ if (!info) {
+ /********************************************************************/
+ /* Open the connection with the MySQL server. */
+ /********************************************************************/
+ if (myc.Open(g, host, db, user, pwd, port))
+ return NULL;
+
+ /********************************************************************/
+ /* Do an evaluation of the result size. */
+ /********************************************************************/
+ STRING cmd(g, 64, "SHOW FULL COLUMNS FROM ");
+ b = cmd.Append('`');
+ b |= cmd.Append((PSZ)table);
+ b |= cmd.Append('`');
+
+ b |= cmd.Append(" FROM ");
+ b |= cmd.Append((PSZ)(db ? db : PlgGetUser(g)->DBName));
+
+ if (colpat) {
+ b |= cmd.Append(" LIKE ");
+ b |= cmd.Append((PSZ)colpat);
+ } // endif colpat
+
+ if (b) {
+ strcpy(g->Message, "Out of memory");
+ return NULL;
+ } // endif b
+
+ if (trace(1))
+ htrc("MyColumns: cmd='%s'\n", cmd.GetStr());
+
+ if ((n = myc.GetResultSize(g, cmd.GetStr())) < 0) {
+ myc.Close();
+ return NULL;
+ } // endif n
+
+ /********************************************************************/
+ /* Get the size of the name and default columns. */
+ /********************************************************************/
+ length[0] = myc.GetFieldLength(0);
+// length[10] = myc.GetFieldLength(5);
+ } else {
+ n = 0;
+ length[0] = 128;
+ } // endif info
+
+ /**********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /**********************************************************************/
+ if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, true)))
+ return NULL;
+
+ // Some columns must be renamed
+ for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
+ switch (++i) {
+ case 2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break;
+ case 4: crp->Name = "Length"; break;
+ case 5: crp->Name = "Key"; break;
+ case 10: crp->Name = "Date_fmt"; break;
+ case 11: crp->Name = "Default"; break;
+ case 12: crp->Name = "Extra"; break;
+ case 13: crp->Name = "Collation"; break;
+ } // endswitch i
+
+ if (info)
+ return qrp;
+
+ /**********************************************************************/
+ /* Now get the results into blocks. */
+ /**********************************************************************/
+ for (i = 0; i < n; /*i++*/) {
+ if ((rc = myc.Fetch(g, -1)) == RC_FX) {
+ myc.Close();
+ return NULL;
+ } else if (rc == RC_EF)
+ break;
+
+ // Get column name
+ colname = myc.GetCharField(0);
+ crp = qrp->Colresp; // Column_Name
+ crp->Kdata->SetValue(colname, i);
+
+ // Get type, type name, precision, unsigned and zerofill
+ chset = myc.GetCharField(2);
+ fld = myc.GetCharField(1);
+ prec = 0;
+ len = 0;
+// v = (chset && !strcmp(chset, "binary")) ? 'B' : 0;
+ v = 0;
+ *uns = 0;
+ *zero = 0;
+ b = false;
+
+ if (!strnicmp(fld, "enum", 4)) {
+ char *p2, *p1 = fld + 6; // to skip enum('
+
+ while (true) {
+ p2 = strchr(p1, '\'');
+ len = MY_MAX(len, (int)(p2 - p1));
+ if (*++p2 != ',') break;
+ p1 = p2 + 2;
+ } // endwhile
+
+ v = (len > 255) ? 'V' : 0;
+ strcpy(buf, "enum");
+ b = true;
+ } else if (!strnicmp(fld, "set", 3)) {
+ len = (int)strlen(fld) - 2;
+ v = 'V';
+ strcpy(buf, "set");
+ b = true;
+ } else switch ((nf = sscanf(fld, "%[^(](%d,%d", buf, &len, &prec))) {
+ case 3:
+ nf = sscanf(fld, "%[^(](%d,%d) %s %s", buf, &len, &prec, uns, zero);
+ break;
+ case 2:
+ nf = sscanf(fld, "%[^(](%d) %s %s", buf, &len, uns, zero) + 1;
+ break;
+ case 1:
+ nf = sscanf(fld, "%s %s %s", buf, uns, zero) + 2;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_FIELD_TYPE), fld);
+ myc.Close();
+ return NULL;
+ } // endswitch nf
+
+ if ((type = MYSQLtoPLG(buf, &v)) == TYPE_ERROR) {
+ if (v == 'K') {
+ // Skip this column
+ sprintf(g->Message, "Column %s skipped (unsupported type %s)",
+ colname, buf);
+ PushWarning(g, thd);
+ continue;
+ } // endif v
+
+ sprintf(g->Message, "Column %s unsupported type %s", colname, buf);
+ myc.Close();
+ return NULL;
+ } else if (type == TYPE_STRING) {
+ if (v == 'X') {
+ len = GetConvSize();
+ sprintf(g->Message, "Column %s converted to varchar(%d)",
+ colname, len);
+ PushWarning(g, thd);
+ v = 'V';
+ } else
+ len = MY_MIN(len, 4096);
+
+ } // endif type
+
+ qrp->Nblin++;
+ crp = crp->Next; // Data_Type
+ crp->Kdata->SetValue(type, i);
+
+ switch (nf) {
+ case 5: crp->Nulls[i] = 'Z'; break;
+ case 4: crp->Nulls[i] = 'U'; break;
+ default: crp->Nulls[i] = v; break;
+ } // endswitch nf
+
+ if (b) // enum or set
+ nf = sscanf(fld, "%s ", buf); // get values
+
+ crp = crp->Next; // Type_Name
+ crp->Kdata->SetValue(buf, i);
+
+ if (type == TYPE_DATE) {
+ // When creating tables we do need info about date columns
+ fmt = MyDateFmt(buf);
+ len = strlen(fmt);
+ } else
+ fmt = NULL;
+
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(len, i);
+
+ crp = crp->Next; // key (was Length)
+ fld = myc.GetCharField(4);
+ crp->Kdata->SetValue(fld, i);
+
+ crp = crp->Next; // Scale
+ crp->Kdata->SetValue(prec, i);
+
+ crp = crp->Next; // Radix
+ crp->Kdata->SetValue(0, i);
+
+ crp = crp->Next; // Nullable
+ fld = myc.GetCharField(3);
+ crp->Kdata->SetValue((toupper(*fld) == 'Y') ? 1 : 0, i);
+
+ crp = crp->Next; // Remark
+ fld = myc.GetCharField(8);
+ crp->Kdata->SetValue(fld, i);
+
+ crp = crp->Next; // Date format
+// crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i);
+ crp->Kdata->SetValue(fmt, i);
+
+ crp = crp->Next; // New (default)
+ fld = myc.GetCharField(5);
+ crp->Kdata->SetValue(fld, i);
+
+ crp = crp->Next; // New (extra)
+ fld = myc.GetCharField(6);
+ crp->Kdata->SetValue(fld, i);
+
+ crp = crp->Next; // New (charset)
+ fld = chset;
+ crp->Kdata->SetValue(fld, i);
+
+ i++; // Can be skipped
+ } // endfor i
+
+#if 0
+ if (k > 1) {
+ // Multicolumn primary key
+ PVBLK vbp = qrp->Colresp->Next->Next->Next->Next->Kdata;
+
+ for (i = 0; i < n; i++)
+ if (vbp->GetIntValue(i))
+ vbp->SetValue(k, i);
+
+ } // endif k
+#endif // 0
+
+ /**********************************************************************/
+ /* Close MySQL connection. */
+ /**********************************************************************/
+ myc.Close();
+
+ /**********************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /**********************************************************************/
+ return qrp;
+ } // end of MyColumns
+
+/************************************************************************/
+/* SrcColumns: constructs the result blocks containing all columns */
+/* resulting from an SQL source definition query execution. */
+/************************************************************************/
+PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
+ const char *user, const char *pwd,
+ const char *srcdef, int port)
+ {
+ char *query;
+ int w;
+ MYSQLC myc;
+ PQRYRES qrp = NULL;
+
+ if (!port)
+ port = mysqld_port;
+
+ if (!strnicmp(srcdef, "select ", 7) || strstr(srcdef, "%s")) {
+ query = (char *)PlugSubAlloc(g, NULL, strlen(srcdef) + 10);
+
+ if (strstr(srcdef, "%s"))
+ sprintf(query, srcdef, "1=1"); // dummy where clause
+ else
+ strcpy(query, srcdef);
+
+ if (!strnicmp(srcdef, "select ", 7))
+ strcat(query, " LIMIT 0");
+
+ } else
+ query = (char *)srcdef;
+
+ // Open a MySQL connection for this table
+ if (myc.Open(g, host, db, user, pwd, port))
+ return NULL;
+
+ // Send the source command to MySQL
+ if (myc.ExecSQL(g, query, &w) == RC_OK)
+ qrp = myc.GetResult(g, true);
+
+ myc.Close();
+ return qrp;
+ } // end of SrcColumns
+
+/* -------------------------- Class MYSQLC --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the MYSQLC class. */
+/***********************************************************************/
+MYSQLC::MYSQLC(void)
+ {
+ m_DB = NULL;
+#if defined (MYSQL_PREPARED_STATEMENTS)
+ m_Stmt = NULL;
+#endif // MYSQL_PREPARED_STATEMENTS
+ m_Res = NULL;
+ m_Rows = -1;
+ m_Row = NULL;
+ m_Fields = -1;
+ N = 0;
+ m_Use = false;
+ } // end of MYSQLC constructor
+
+/***********************************************************************/
+/* Get the number of lines of the result set. */
+/* Currently we send the Select command and return m_Rows */
+/* Perhaps should we use Select count(*) ... (?????) */
+/* No because here we execute only one query instead of two */
+/* (the select count(*) plus the normal query) */
+/***********************************************************************/
+int MYSQLC::GetResultSize(PGLOBAL g, PSZ sql)
+ {
+ if (m_Rows < 0)
+ if (ExecSQL(g, sql) != RC_OK)
+ return -1;
+
+ return m_Rows;
+ } // end of GetResultSize
+
+/***********************************************************************/
+/* Open a MySQL (remote) connection. */
+/***********************************************************************/
+int MYSQLC::Open(PGLOBAL g, const char *host, const char *db,
+ const char *user, const char *pwd,
+ int pt, const char *csname)
+ {
+ const char *pipe = NULL;
+ //uint cto = 10, nrt = 20;
+ my_bool my_true= 1;
+
+ m_DB = mysql_init(NULL);
+
+ if (!m_DB) {
+ strcpy(g->Message, "mysql_init failed: no memory");
+ return RC_FX;
+ } // endif m_DB
+
+ if (trace(1))
+ htrc("MYSQLC Open: m_DB=%.4X size=%d\n", m_DB, (int)sizeof(*m_DB));
+
+ // Removed to do like FEDERATED does
+//mysql_options(m_DB, MYSQL_READ_DEFAULT_GROUP, "client-mariadb");
+//mysql_options(m_DB, MYSQL_OPT_USE_REMOTE_CONNECTION, NULL);
+//mysql_options(m_DB, MYSQL_OPT_CONNECT_TIMEOUT, &cto);
+//mysql_options(m_DB, MYSQL_OPT_READ_TIMEOUT, &nrt);
+//mysql_options(m_DB, MYSQL_OPT_WRITE_TIMEOUT, ...);
+
+#if defined(_WIN32)
+ if (!strcmp(host, ".")) {
+ mysql_options(m_DB, MYSQL_OPT_NAMED_PIPE, NULL);
+ pipe = mysqld_unix_port;
+ } // endif host
+#else // !_WIN32
+ if (!strcmp(host, "localhost"))
+ pipe = mysqld_unix_port;
+#endif // !_WIN32
+
+#if 0
+ if (pwd && !strcmp(pwd, "*")) {
+ if (GetPromptAnswer(g, "*Enter password:")) {
+ m_DB = NULL;
+ return RC_FX;
+ } else
+ pwd = g->Message;
+
+ } // endif pwd
+#endif // 0
+
+/***********************************************************************/
+/* BUG# 17044 Federated Storage Engine is not UTF8 clean */
+/* Add set names to whatever charset the table is at open of table */
+/* this sets the csname like 'set names utf8'. */
+/***********************************************************************/
+ if (csname)
+ mysql_options(m_DB, MYSQL_SET_CHARSET_NAME, csname);
+
+ // Don't know what this one do but FEDERATED does it
+ mysql_options(m_DB, MYSQL_OPT_USE_THREAD_SPECIFIC_MEMORY,
+ (char*)&my_true);
+
+ if (!mysql_real_connect(m_DB, host, user, pwd, db, pt, pipe,
+ CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS)) {
+#if defined(_DEBUG)
+ sprintf(g->Message, "mysql_real_connect failed: (%d) %s",
+ mysql_errno(m_DB), mysql_error(m_DB));
+#else // !_DEBUG
+ sprintf(g->Message, "(%d) %s", mysql_errno(m_DB), mysql_error(m_DB));
+#endif // !_DEBUG
+ mysql_close(m_DB);
+ m_DB = NULL;
+ return RC_FX;
+ } // endif mysql_real_connect
+
+ return RC_OK;
+ } // end of Open
+
+/***********************************************************************/
+/* Returns true if the connection is still alive. */
+/***********************************************************************/
+bool MYSQLC::Connected(void)
+ {
+//int rc;
+
+ if (!m_DB)
+ return FALSE;
+//else if ((rc = mysql_ping(m_DB)) == CR_SERVER_GONE_ERROR)
+// return FALSE;
+ else
+ return TRUE;
+
+ } // end of Connected
+
+#if 0 // Not used
+/***********************************************************************/
+/* Returns the thread ID of the current MySQL connection. */
+/***********************************************************************/
+ulong MYSQLC::GetThreadID(void)
+ {
+ return (m_DB) ? mysql_thread_id(m_DB) : 0;
+ } // end of GetThreadID
+
+/***********************************************************************/
+/* Returns a string that represents the server version number. */
+/***********************************************************************/
+const char *MYSQLC::ServerInfo(void)
+ {
+ return (m_DB) ? mysql_get_server_info(m_DB) : NULL;
+ } // end of ServerInfo
+
+/***********************************************************************/
+/* Returns the version number of the server as a number that */
+/* represents the MySQL server version in this format: */
+/* major_version*10000 + minor_version *100 + sub_version */
+/***********************************************************************/
+ulong MYSQLC::ServerVersion(void)
+ {
+ return (m_DB) ? mysql_get_server_version(m_DB) : 0;
+ } // end of ServerVersion
+#endif // 0
+
+/**************************************************************************/
+/* KillQuery: Send MySQL a Kill Query command. */
+/**************************************************************************/
+int MYSQLC::KillQuery(ulong id)
+ {
+ char kill[20];
+
+ sprintf(kill, "KILL QUERY %u", (unsigned int) id);
+//return (m_DB) ? mysql_query(m_DB, kill) : 1;
+ return (m_DB) ? mysql_real_query(m_DB, kill, strlen(kill)) : 1;
+ } // end of KillQuery
+
+#if defined (MYSQL_PREPARED_STATEMENTS)
+/***********************************************************************/
+/* Prepare the SQL statement used to insert into a MySQL table. */
+/***********************************************************************/
+int MYSQLC::PrepareSQL(PGLOBAL g, const char *stmt)
+ {
+ if (!m_DB) {
+ strcpy(g->Message, "MySQL not connected");
+ return -4;
+ } else if (m_Stmt)
+ return -1; // should not append
+
+#if defined(ALPHA)
+ if (!(m_Stmt = mysql_prepare(m_DB, stmt, strlen(stmt)))) {
+
+ sprintf(g->Message, "mysql_prepare failed: %s [%s]",
+ mysql_error(m_DB), stmt);
+ return -1;
+ } // endif m_Stmt
+
+ // Return the parameter count from the statement
+ return mysql_param_count(m_Stmt);
+#else // !ALPHA
+ if (!(m_Stmt = mysql_stmt_init(m_DB))) {
+ strcpy(g->Message, "mysql_stmt_init(), out of memory");
+ return -2;
+ } // endif m_Stmt
+
+ if (mysql_stmt_prepare(m_Stmt, stmt, strlen(stmt))) {
+ sprintf(g->Message, "mysql_stmt_prepare() failed: (%d) %s",
+ mysql_stmt_errno(m_Stmt), mysql_stmt_error(m_Stmt));
+ return -3;
+ } // endif prepare
+
+ // Return the parameter count from the statement
+ return mysql_stmt_param_count(m_Stmt);
+#endif // !ALPHA
+ } // end of PrepareSQL
+
+/***********************************************************************/
+/* Bind the parameter buffers. */
+/***********************************************************************/
+int MYSQLC::BindParams(PGLOBAL g, MYSQL_BIND *bind)
+ {
+ if (!m_DB) {
+ strcpy(g->Message, "MySQL not connected");
+ return RC_FX;
+ } else
+ assert(m_Stmt);
+
+#if defined(ALPHA)
+ if (mysql_bind_param(m_Stmt, bind)) {
+ sprintf(g->Message, "mysql_bind_param() failed: %s",
+ mysql_stmt_error(m_Stmt));
+#else // !ALPHA
+ if (mysql_stmt_bind_param(m_Stmt, bind)) {
+ sprintf(g->Message, "mysql_stmt_bind_param() failed: %s",
+ mysql_stmt_error(m_Stmt));
+#endif // !ALPHA
+ return RC_FX;
+ } // endif bind
+
+ return RC_OK;
+
+/***********************************************************************/
+/* Execute a prepared statement. */
+/***********************************************************************/
+int MYSQLC::ExecStmt(PGLOBAL g)
+ {
+ if (!m_DB) {
+ strcpy(g->Message, "MySQL not connected");
+ return RC_FX;
+ } // endif m_DB
+
+#if defined(ALPHA)
+ if (mysql_execute(m_Stmt)) {
+ sprintf(g->Message, "mysql_execute() failed: %s",
+ mysql_stmt_error(m_Stmt));
+ return RC_FX;
+ } // endif execute
+#else // !ALPHA
+ if (mysql_stmt_execute(m_Stmt)) {
+ sprintf(g->Message, "mysql_stmt_execute() failed: %s",
+ mysql_stmt_error(m_Stmt));
+ return RC_FX;
+ } // endif execute
+#endif // !ALPHA
+
+ // Check the total number of affected rows
+ if (mysql_stmt_affected_rows(m_Stmt) != 1) {
+ sprintf(g->Message, "Invalid affected rows by MySQL");
+ return RC_FX;
+ } // endif affected_rows
+
+ return RC_OK;
+ } // end of ExecStmt
+#endif // MYSQL_PREPARED_STATEMENTS
+
+/***********************************************************************/
+/* Exec the Select SQL command and get back the result size in rows. */
+/***********************************************************************/
+int MYSQLC::ExecSQL(PGLOBAL g, const char *query, int *w)
+ {
+ int rc = RC_OK;
+
+ if (!m_DB) {
+ strcpy(g->Message, "MySQL not connected");
+ return RC_FX;
+ } // endif m_DB
+
+ if (w)
+ *w = 0;
+
+ if (m_Rows >= 0)
+ return RC_OK; // Already done
+
+//if (mysql_query(m_DB, query) != 0) {
+ if (mysql_real_query(m_DB, query, strlen(query))) {
+ char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query));
+
+ sprintf(msg, "(%d) %s [%s]", mysql_errno(m_DB),
+ mysql_error(m_DB), query);
+ strncpy(g->Message, msg, sizeof(g->Message) - 1);
+ g->Message[sizeof(g->Message) - 1] = 0;
+ rc = RC_FX;
+//} else if (mysql_field_count(m_DB) > 0) {
+ } else if (m_DB->field_count > 0) {
+ if (m_Use)
+#if defined(MYSQL_PREPARED_STATEMENTS)
+ m_Res = mysql_use_result(m_DB);
+#else // !MYSQL_PREPARED_STATEMENTS)
+ m_Res = connect_use_result(m_DB);
+#endif // !MYSQL_PREPARED_STATEMENTS
+ else
+ m_Res = mysql_store_result(m_DB);
+
+ if (!m_Res) {
+ char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query));
+
+ sprintf(msg, "mysql_store_result failed: %s", mysql_error(m_DB));
+ strncpy(g->Message, msg, sizeof(g->Message) - 1);
+ g->Message[sizeof(g->Message) - 1] = 0;
+ rc = RC_FX;
+ } else {
+ m_Fields = mysql_num_fields(m_Res);
+ m_Rows = (!m_Use) ? (int)mysql_num_rows(m_Res) : 0;
+
+ if (trace(1))
+ htrc("ExecSQL: m_Res=%.4X size=%d m_Fields=%d m_Rows=%d\n",
+ m_Res, sizeof(*m_Res), m_Fields, m_Rows);
+
+ } // endif m_Res
+
+ } else {
+// m_Rows = (int)mysql_affected_rows(m_DB);
+ m_Rows = (int)m_DB->affected_rows;
+ sprintf(g->Message, "Affected rows: %d\n", m_Rows);
+ rc = RC_NF;
+ } // endif field count
+
+ if (w)
+// *w = mysql_warning_count(m_DB);
+ *w = m_DB->warning_count;
+
+ return rc;
+ } // end of ExecSQL
+
+/***********************************************************************/
+/* Get table size by executing "select count(*) from table_name". */
+/***********************************************************************/
+int MYSQLC::GetTableSize(PGLOBAL g __attribute__((unused)), PSZ query)
+ {
+ if (mysql_real_query(m_DB, query, strlen(query))) {
+#if defined(_DEBUG)
+ char *msg = (char*)PlugSubAlloc(g, NULL, 512 + strlen(query));
+
+ sprintf(msg, "(%d) %s [%s]", mysql_errno(m_DB),
+ mysql_error(m_DB), query);
+ strncpy(g->Message, msg, sizeof(g->Message) - 1);
+ g->Message[sizeof(g->Message) - 1] = 0;
+#endif // _DEBUG
+ return -2;
+ } // endif mysql_real_query
+
+ if (!(m_Res = mysql_store_result(m_DB)))
+ return -3;
+
+ // Get the resulting count value
+ m_Rows = (int)mysql_num_rows(m_Res); // Should be 1
+
+ if (m_Rows && (m_Row = mysql_fetch_row(m_Res)))
+ return atoi(*m_Row);
+
+ return -4;
+ } // end of GetTableSize
+
+/***********************************************************************/
+/* Move to a specific row and column */
+/***********************************************************************/
+void MYSQLC::DataSeek(my_ulonglong row)
+ {
+ MYSQL_ROWS *tmp = 0;
+//DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
+
+ if (m_Res->data)
+ for (tmp = m_Res->data->data; row-- && tmp; tmp = tmp->next) ;
+
+ m_Res->current_row = 0;
+ m_Res->data_cursor = tmp;
+ } // end of DataSeek
+
+/***********************************************************************/
+/* Fetch one result line from the query result set. */
+/***********************************************************************/
+int MYSQLC::Fetch(PGLOBAL g, int pos)
+ {
+ if (!m_DB) {
+ strcpy(g->Message, "MySQL not connected");
+ return RC_FX;
+ } // endif m_DB
+
+ if (!m_Res) {
+ // Result set was not initialized
+ strcpy(g->Message, MSG(FETCH_NO_RES));
+ return RC_FX;
+ } else
+ N++;
+
+ if (pos >= 0)
+// mysql_data_seek(m_Res, (my_ulonglong)pos);
+ DataSeek((my_ulonglong)pos);
+
+ m_Row = mysql_fetch_row(m_Res);
+ return (m_Row) ? RC_OK : RC_EF;
+ } // end of Fetch
+
+/***********************************************************************/
+/* Get one field of the current row. */
+/***********************************************************************/
+char *MYSQLC::GetCharField(int i)
+ {
+ if (m_Res && m_Row) {
+#if defined(_DEBUG)
+// MYSQL_FIELD *fld = mysql_fetch_field_direct(m_Res, i);
+#endif // _DEBUG
+ MYSQL_ROW row = m_Row + i;
+
+ return (row) ? (char*)*row : (char*)"<null>";
+ } else
+ return NULL;
+
+ } // end of GetCharField
+
+/***********************************************************************/
+/* Get the max length of the field. */
+/***********************************************************************/
+int MYSQLC::GetFieldLength(int i)
+ {
+ if (m_Res) {
+// MYSQL_FIELD *fld = mysql_fetch_field_direct(m_Res, i);
+// return fld->max_length;
+ return (m_Res)->fields[i].max_length;
+ } else
+ return 0;
+
+ } // end of GetFieldLength
+
+/***********************************************************************/
+/* Return next field of the query results. */
+/***********************************************************************/
+MYSQL_FIELD *MYSQLC::GetNextField(void)
+ {
+ return (m_Res->current_field >= m_Res->field_count) ? NULL
+ : &m_Res->fields[m_Res->current_field++];
+ } // end of GetNextField
+
+/***********************************************************************/
+/* Make a CONNECT result structure from the MySQL result. */
+/***********************************************************************/
+PQRYRES MYSQLC::GetResult(PGLOBAL g, bool pdb)
+ {
+ PCSZ fmt;
+ char *name, v= 0;
+ int n;
+ bool uns;
+ PCOLRES *pcrp, crp;
+ PQRYRES qrp;
+ MYSQL_FIELD *fld;
+ MYSQL_ROW row;
+
+ if (!m_Res || !m_Fields) {
+ sprintf(g->Message, "%s result", (m_Res) ? "Void" : "No");
+ return NULL;
+ } // endif m_Res
+
+ /*********************************************************************/
+ /* Put the result in storage for future retrieval. */
+ /*********************************************************************/
+ qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
+ pcrp = &qrp->Colresp;
+ qrp->Continued = FALSE;
+ qrp->Truncated = FALSE;
+ qrp->Info = FALSE;
+ qrp->Suball = TRUE;
+ qrp->BadLines = 0;
+ qrp->Maxsize = m_Rows;
+ qrp->Maxres = m_Rows;
+ qrp->Nbcol = 0;
+ qrp->Nblin = 0;
+ qrp->Cursor = 0;
+
+//for (fld = mysql_fetch_field(m_Res); fld;
+// fld = mysql_fetch_field(m_Res)) {
+ for (fld = GetNextField(); fld; fld = GetNextField()) {
+ *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
+ crp = *pcrp;
+ pcrp = &crp->Next;
+ memset(crp, 0, sizeof(COLRES));
+ crp->Ncol = ++qrp->Nbcol;
+
+ name = (char*)PlugSubAlloc(g, NULL, fld->name_length + 1);
+ strcpy(name, fld->name);
+ crp->Name = name;
+
+ if ((crp->Type = MYSQLtoPLG(fld->type, &v)) == TYPE_ERROR) {
+ sprintf(g->Message, "Type %d not supported for column %s",
+ fld->type, crp->Name);
+ return NULL;
+ } else if (crp->Type == TYPE_DATE && !pdb)
+ // For direct MySQL connection, display the MySQL date string
+ crp->Type = TYPE_STRING;
+ else
+ crp->Var = v;
+
+ crp->Prec = (crp->Type == TYPE_DOUBLE || crp->Type == TYPE_DECIM)
+ ? fld->decimals : 0;
+ CHARSET_INFO *cs= get_charset(fld->charsetnr, MYF(0));
+ crp->Clen = GetTypeSize(crp->Type, fld->length);
+ crp->Length = fld->length / (cs ? cs->mbmaxlen : 1);
+ uns = (fld->flags & (UNSIGNED_FLAG | ZEROFILL_FLAG)) ? true : false;
+
+ if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
+ crp->Clen, 0, FALSE, TRUE, uns))) {
+ sprintf(g->Message, MSG(INV_RESULT_TYPE),
+ GetFormatType(crp->Type));
+ return NULL;
+ } else if (crp->Type == TYPE_DATE) {
+ fmt = MyDateFmt(fld->type);
+ crp->Kdata->SetFormat(g, fmt, strlen(fmt));
+ } // endif's
+
+ if (fld->flags & NOT_NULL_FLAG)
+ crp->Nulls = NULL;
+ else {
+ if (m_Rows) {
+ crp->Nulls = (char*)PlugSubAlloc(g, NULL, m_Rows);
+ memset(crp->Nulls, ' ', m_Rows);
+ } // endif m_Rows
+
+ crp->Kdata->SetNullable(true);
+ } // endelse fld->flags
+
+ } // endfor fld
+
+ *pcrp = NULL;
+ assert(qrp->Nbcol == m_Fields);
+
+ /*********************************************************************/
+ /* Now fill the allocated result structure. */
+ /*********************************************************************/
+ for (n = 0; n < m_Rows; n++) {
+ if (!(m_Row = mysql_fetch_row(m_Res))) {
+ sprintf(g->Message, "Missing row %d from result", n + 1);
+ return NULL;
+ } // endif m_Row
+
+ for (crp = qrp->Colresp; crp; crp = crp->Next) {
+ if ((row = m_Row + (crp->Ncol - 1))) {
+ if (*row)
+ crp->Kdata->SetValue((PSZ)*row, n);
+ else {
+ if (!*row && crp->Nulls)
+ crp->Nulls[n] = '*'; // Null value
+
+ crp->Kdata->Reset(n);
+ } // endelse *row
+ }
+
+ } // endfor crp
+
+ } // endfor n
+
+ qrp->Nblin = n;
+ return qrp;
+ } // end of GetResult
+
+/***********************************************************************/
+/* Free the current result. */
+/***********************************************************************/
+void MYSQLC::FreeResult(void)
+ {
+ if (m_Res) {
+ mysql_free_result(m_Res);
+ m_Res = NULL;
+ } // endif m_Res
+
+ // Reset the connection
+ m_Row = NULL;
+ m_Rows = -1;
+ m_Fields = -1;
+ N = 0;
+ } // end of FreeResult
+
+/***********************************************************************/
+/* Place the cursor at the beginning of the result set. */
+/***********************************************************************/
+int MYSQLC::Rewind(PGLOBAL g, PSZ sql)
+ {
+ int rc = RC_OK;
+
+ if (m_Res)
+ DataSeek(0);
+ else if (sql)
+ rc = ExecSQL(g, sql);
+
+ return rc;
+ } // end of Rewind
+
+/***********************************************************************/
+/* Exec the Select SQL command and return ncol or afrws (TDBMYEXC). */
+/***********************************************************************/
+int MYSQLC::ExecSQLcmd(PGLOBAL g, const char *query, int *w)
+ {
+ int rc = RC_OK;
+
+ if (!m_DB) {
+ strcpy(g->Message, "MySQL not connected");
+ return RC_FX;
+ } else
+ *w = 0;
+
+ if (!stricmp(query, "Warning") || !stricmp(query, "Note")
+ || !stricmp(query, "Error"))
+ return RC_INFO;
+ else
+ m_Afrw = 0;
+
+//if (mysql_query(m_DB, query) != 0) {
+ if (mysql_real_query(m_DB, query, strlen(query))) {
+ m_Afrw = (int)mysql_errno(m_DB);
+ sprintf(g->Message, "Remote: %s", mysql_error(m_DB));
+ rc = RC_FX;
+//} else if (!(m_Fields = mysql_field_count(m_DB))) {
+ } else if (!(m_Fields = (int)m_DB->field_count)) {
+// m_Afrw = (int)mysql_affected_rows(m_DB);
+ m_Afrw = (int)m_DB->affected_rows;
+ rc = RC_NF;
+ } // endif's
+
+//*w = mysql_warning_count(m_DB);
+ *w = m_DB->warning_count;
+ return rc;
+ } // end of ExecSQLcmd
+
+/***********************************************************************/
+/* Close the connection. */
+/***********************************************************************/
+void MYSQLC::Close(void)
+ {
+ FreeResult();
+
+ if (trace(1))
+ htrc("MYSQLC Close: m_DB=%.4X\n", m_DB);
+
+ mysql_close(m_DB);
+ m_DB = NULL;
+ } // end of Close
+
+#if 0 // not used yet
+/***********************************************************************/
+/* Discard additional results from a stored procedure. */
+/***********************************************************************/
+void MYSQLC::DiscardResults(void)
+ {
+ MYSQL_RES *res;
+
+ while (!mysql_next_result(m_DB)) {
+ res = mysql_store_result(m_DB);
+ mysql_free_result(res);
+ } // endwhile next result
+
+ } // end of DiscardResults
+#endif // 0
diff --git a/storage/connect/myconn.h b/storage/connect/myconn.h
new file mode 100644
index 00000000..5f64f933
--- /dev/null
+++ b/storage/connect/myconn.h
@@ -0,0 +1,105 @@
+/***********************************************************************/
+/* MYCONN.H Olivier Bertrand 2007-2013 */
+/* */
+/* This is the declaration file for the MySQL connection class and */
+/* a few utility functions used to communicate with MySQL. */
+/* */
+/* DO NOT define DLL_EXPORT in your application so these items are */
+/* declared are imported from the Myconn DLL. */
+/***********************************************************************/
+#if defined(_WIN32)
+#include <winsock.h>
+#else // !_WIN32
+#include <sys/socket.h>
+#endif // !_WIN32
+#include <mysql.h>
+#include <errmsg.h>
+#include "myutil.h"
+
+#if defined(_WIN32) && defined(MYCONN_EXPORTS)
+#if defined(DLL_EXPORT)
+#define DllItem _declspec(dllexport)
+#else // !DLL_EXPORT
+#define DllItem _declspec(dllimport)
+#endif // !DLL_EXPORT
+#else // !_WIN32 || !MYCONN_EXPORTS
+#define DllItem
+#endif // !_WIN32
+
+#define MYSQL_ENABLED 0x00000001
+#define MYSQL_LOGON 0x00000002
+
+typedef class MYSQLC *PMYC;
+
+/***********************************************************************/
+/* Prototypes of info functions. */
+/***********************************************************************/
+PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db,
+ const char *user, const char *pwd,
+ const char *table, const char *colpat,
+ int port, bool info);
+
+PQRYRES SrcColumns(PGLOBAL g, const char *host, const char *db,
+ const char *user, const char *pwd,
+ const char *srcdef, int port);
+
+uint GetDefaultPort(void);
+
+/* -------------------------- MYCONN class --------------------------- */
+
+/***********************************************************************/
+/* MYSQLC exported/imported class. A MySQL connection. */
+/***********************************************************************/
+class DllItem MYSQLC {
+ friend class TDBMYSQL;
+ friend class MYSQLCOL;
+ friend class TDBMYEXC;
+ // Construction
+ public:
+ MYSQLC(void);
+
+ // Implementation
+ int GetRows(void) {return m_Rows;}
+ bool Connected(void);
+
+ // Methods
+ int GetResultSize(PGLOBAL g, PSZ sql);
+ int GetTableSize(PGLOBAL g, PSZ query);
+ int Open(PGLOBAL g, const char *host, const char *db,
+ const char *user= "root", const char *pwd= "*",
+ int pt= 0, const char *csname = NULL);
+ int KillQuery(ulong id);
+ int ExecSQL(PGLOBAL g, const char *query, int *w = NULL);
+ int ExecSQLcmd(PGLOBAL g, const char *query, int *w);
+#if defined(MYSQL_PREPARED_STATEMENTS)
+ int PrepareSQL(PGLOBAL g, const char *query);
+ int ExecStmt(PGLOBAL g);
+ int BindParams(PGLOBAL g, MYSQL_BIND *bind);
+#endif // MYSQL_PREPARED_STATEMENTS
+ PQRYRES GetResult(PGLOBAL g, bool pdb = FALSE);
+ int Fetch(PGLOBAL g, int pos);
+ char *GetCharField(int i);
+ int GetFieldLength(int i);
+ int Rewind(PGLOBAL g, PSZ sql);
+ void FreeResult(void);
+ void Close(void);
+
+ protected:
+ MYSQL_FIELD *GetNextField(void);
+ void DataSeek(my_ulonglong row);
+
+ // Members
+ MYSQL *m_DB; // The return from MySQL connection
+#if defined (MYSQL_PREPARED_STATEMENTS)
+ MYSQL_STMT *m_Stmt; // Prepared statement handle
+#endif // MYSQL_PREPARED_STATEMENTS
+ MYSQL_RES *m_Res; // Points to MySQL Result
+ MYSQL_ROW m_Row; // Point to current row
+ int m_Rows; // The number of rows of the result
+ int N;
+ int m_Fields; // The number of result fields
+ int m_Afrw; // The number of affected rows
+ bool m_Use; // Use or store result set
+ const char *csname; // Table charset name
+ }; // end of class MYSQLC
+
diff --git a/storage/connect/mysql-test/connect/disabled.def b/storage/connect/mysql-test/connect/disabled.def
new file mode 100644
index 00000000..5107de7a
--- /dev/null
+++ b/storage/connect/mysql-test/connect/disabled.def
@@ -0,0 +1,27 @@
+##############################################################################
+#
+# List the test cases that are to be disabled temporarily.
+#
+# Separate the test case name and the comment with ':'.
+#
+# <testcasename> : BUG#<xxxx> <date disabled> <disabler> <comment>
+#
+# Do not use any TAB characters for whitespace.
+#
+##############################################################################
+jdbc : Variable settings depend on machine configuration
+jdbc_new : Variable settings depend on machine configuration
+jdbc_oracle : Variable settings depend on machine configuration
+jdbc_postgresql : Variable settings depend on machine configuration
+json_mongo_c : Need MongoDB running and its C Driver installed
+json_java_2 : Need MongoDB running and its Java Driver installed
+json_java_3 : Need MongoDB running and its Java Driver installed
+bson_mongo_c : Need MongoDB running and its C Driver installed
+bson_java_2 : Need MongoDB running and its Java Driver installed
+bson_java_3 : Need MongoDB running and its Java Driver installed
+mongo_c : Need MongoDB running and its C Driver installed
+mongo_java_2 : Need MongoDB running and its Java Driver installed
+mongo_java_3 : Need MongoDB running and its Java Driver installed
+tbl_thread : Bug MDEV-9844,10179,14214 03/01/2018 OB Option THREAD removed
+#bson : Development
+#vcol : Different error code on different versions
diff --git a/storage/connect/mysql-test/connect/my.cnf b/storage/connect/mysql-test/connect/my.cnf
new file mode 100644
index 00000000..6310772d
--- /dev/null
+++ b/storage/connect/mysql-test/connect/my.cnf
@@ -0,0 +1,17 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+!include include/default_client.cnf
+
+[mysqld.1]
+#log-bin= master-bin
+
+[mysqld.2]
+
+[ENV]
+MASTER_MYPORT= @mysqld.1.port
+MASTER_MYSOCK= @mysqld.1.socket
+
+SLAVE_MYPORT= @mysqld.2.port
+SLAVE_MYSOCK= @mysqld.2.socket
+
+PGCLIENTENCODING= UTF8
diff --git a/storage/connect/mysql-test/connect/r/alter.result b/storage/connect/mysql-test/connect/r/alter.result
new file mode 100644
index 00000000..77d77522
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/alter.result
@@ -0,0 +1,274 @@
+#
+# Testing indexing with ALTER on inward table (in-place)
+#
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT;
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+Warning 1105 No file name. Table will use t1.dos
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+CREATE INDEX xc ON t1(c);
+DESCRIBE SELECT * FROM t1 WHERE c = 2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref xc xc 4 const 1
+DROP INDEX xc ON t1;
+CREATE INDEX xd ON t1(d);
+DROP INDEX xd ON t1;
+ALTER TABLE t1 ADD INDEX xc (c), ADD INDEX xd (d);
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 1 xc 1 c A NULL NULL NULL XINDEX
+t1 1 xd 1 d A NULL NULL NULL XINDEX
+ALTER TABLE t1 DROP INDEX xc, DROP INDEX xd;
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+#
+# Testing modifying columns inward table (not in-place)
+#
+ALTER TABLE t1 MODIFY COLUMN c CHAR(5) NOT NULL;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` char(5) NOT NULL,
+ `d` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+ALTER TABLE t1 MODIFY COLUMN c INT NOT NULL;
+#
+# Fails because indexing must be in-place
+#
+ALTER TABLE t1 MODIFY COLUMN c CHAR(10) NOT NULL, ADD INDEX xd (d);
+ERROR 0A000: Alter operations not supported together by CONNECT
+#
+# Testing changing table type (not in-place)
+#
+ALTER TABLE t1 TABLE_TYPE=CSV HEADER=1 QUOTED=1;
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` int(11) NOT NULL,
+ `d` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=CSV `HEADER`=1 `QUOTED`=1
+# create an outward table used to see the t1 file
+CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.csv';
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+SELECT * FROM t2;
+line
+"c","d"
+1,"One"
+2,"Two"
+3,"Three"
+#
+# Testing changing engine
+#
+DROP TABLE t1;
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT;
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+Warning 1105 No file name. Table will use t1.dos
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+ALTER TABLE t1 ADD INDEX xc (c), ADD INDEX xd (d);
+ALTER TABLE t1 ENGINE = MYISAM;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` int(11) NOT NULL,
+ `d` char(10) NOT NULL,
+ KEY `xc` (`c`),
+ KEY `xd` (`d`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 1 xc 1 c A NULL NULL NULL BTREE
+t1 1 xd 1 d A NULL NULL NULL BTREE
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+ALTER TABLE t1 ENGINE = CONNECT TABLE_TYPE=DBF;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` int(11) NOT NULL,
+ `d` char(10) NOT NULL,
+ KEY `xc` (`c`),
+ KEY `xd` (`d`)
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 1 xc 1 c A NULL NULL NULL XINDEX
+t1 1 xd 1 d A NULL NULL NULL XINDEX
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+DROP TABLE t1, t2;
+#
+# Testing ALTER on outward tables
+#
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='tf1.txt' ENDING=1;
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='tf1.txt';
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+SELECT * FROM t2;
+line
+ 1One
+ 2Two
+ 3Three
+#
+# Indexing works the same
+#
+ALTER TABLE t1 ADD INDEX xc (c), ADD INDEX xd (d);
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 1 xc 1 c A NULL NULL NULL XINDEX
+t1 1 xd 1 d A NULL NULL NULL XINDEX
+SELECT d FROM t1 WHERE c = 2;
+d
+Two
+ALTER TABLE t1 DROP INDEX xc, DROP INDEX xd;
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+#
+# Other alterations do not modify the file
+#
+ALTER TABLE t1 MODIFY COLUMN c CHAR(5) NOT NULL;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+SELECT * FROM t2;
+line
+ 1One
+ 2Two
+ 3Three
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` char(5) NOT NULL,
+ `d` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=fix `FILE_NAME`='tf1.txt' `ENDING`=1
+SELECT * FROM t1;
+ERROR HY000: Got error 174 'File tf1.txt is not fixed length, len=66 lrecl=16' from CONNECT
+ALTER TABLE t1 MODIFY COLUMN c INT NOT NULL;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+#
+# Changing column order
+#
+ALTER TABLE t1 MODIFY COLUMN c INT NOT NULL AFTER d;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+SELECT * FROM t2;
+line
+ 1One
+ 2Two
+ 3Three
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `d` char(10) NOT NULL,
+ `c` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=fix `FILE_NAME`='tf1.txt' `ENDING`=1
+# Wrong result
+SELECT * FROM t1;
+d c
+ 1
+ 2
+ 3
+ALTER TABLE t1 MODIFY COLUMN c INT NOT NULL FIRST;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+# What should have been done
+ALTER TABLE t1 MODIFY c INT NOT NULL FLAG=0 AFTER d, MODIFY d CHAR(10) NOT NULL FLAG=11;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `d` char(10) NOT NULL `FLAG`=11,
+ `c` int(11) NOT NULL `FLAG`=0
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=fix `FILE_NAME`='tf1.txt' `ENDING`=1
+SELECT * FROM t1;
+d c
+One 1
+Two 2
+Three 3
+#
+# Changing to another engine is Ok
+# However, the data file is not deleted.
+#
+ALTER TABLE t1 ENGINE=ARIA;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `d` char(10) NOT NULL /* `FLAG`=11 */,
+ `c` int(11) NOT NULL /* `FLAG`=0 */
+) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 /* `TABLE_TYPE`=fix `FILE_NAME`='tf1.txt' `ENDING`=1 */
+set @old_sql_mode=@@sql_mode;
+set sql_mode=ignore_bad_table_options;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `d` char(10) NOT NULL `FLAG`=11,
+ `c` int(11) NOT NULL `FLAG`=0
+) ENGINE=Aria DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 `TABLE_TYPE`=fix `FILE_NAME`='tf1.txt' `ENDING`=1
+set sql_mode=@old_sql_mode;
+SELECT * from t1;
+d c
+One 1
+Two 2
+Three 3
+SELECT * from t2;
+line
+ 1One
+ 2Two
+ 3Three
+#
+# Changing back to CONNECT fails
+# Sure enough, the data file was not deleted.
+#
+ALTER TABLE t1 ENGINE=CONNECT;
+ERROR HY000: Operation denied. Table data would be modified.
+#
+# But changing back to CONNECT succeed
+# if the data file does not exist.
+#
+ALTER TABLE t1 ENGINE=CONNECT;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `d` char(10) NOT NULL `FLAG`=11,
+ `c` int(11) NOT NULL `FLAG`=0
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 PAGE_CHECKSUM=1 `TABLE_TYPE`=fix `FILE_NAME`='tf1.txt' `ENDING`=1
+SELECT * from t1;
+d c
+One 1
+Two 2
+Three 3
+SELECT * from t2;
+line
+ 1One
+ 2Two
+ 3Three
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/r/alter_engine.result b/storage/connect/mysql-test/connect/r/alter_engine.result
new file mode 100644
index 00000000..530574d2
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/alter_engine.result
@@ -0,0 +1,11 @@
+#
+# MDEV-24422 Server crashes in GetTypeID / ha_connect::GetRealType upon
+# altering table engine
+#
+CREATE TABLE t1 (f INT) ENGINE=CONNECT;
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+Warning 1105 No file name. Table will use t1.dos
+ALTER TABLE t1 ENGINE InnoDB;
+ALTER TABLE t1 ENGINE CONNECT;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/alter_xml.result b/storage/connect/mysql-test/connect/r/alter_xml.result
new file mode 100644
index 00000000..d2f882f1
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/alter_xml.result
@@ -0,0 +1,84 @@
+#
+# Testing changing table type (not in-place)
+#
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV HEADER=1 QUOTED=1;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+# This would fail if the top node name is not specified.
+# This is because the XML top node name defaults to the table name.
+# Sure enough the temporary table name begins with '#' and is rejected by XML.
+# Therefore the top node name must be specified (along with the row nodes name).
+ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='xmlsup=domdoc,rownode=row';
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` int(11) NOT NULL,
+ `d` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `HEADER`=1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=domdoc,rownode=row'
+# Let us see the XML file
+CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.xml';
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+SELECT * FROM t2;
+line
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Created by the MariaDB CONNECT Storage Engine-->
+<t1>
+ <row>
+ <TH>c</TH>
+ <TH>d</TH>
+ </row>
+ <row>
+ <c>1</c>
+ <d>One</d>
+ </row>
+ <row>
+ <c>2</c>
+ <d>Two</d>
+ </row>
+ <row>
+ <c>3</c>
+ <d>Three</d>
+ </row>
+</t1>
+# NOTE: The first (ignored) row is due to the remaining HEADER=1 option.
+# Testing field option modification
+ALTER TABLE t1 MODIFY d CHAR(10) NOT NULL XPATH='@', HEADER=0;
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` int(11) NOT NULL,
+ `d` char(10) NOT NULL `XPATH`='@'
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=domdoc,rownode=row' `HEADER`=0
+SELECT * FROM t2;
+line
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Created by the MariaDB CONNECT Storage Engine-->
+<t1>
+ <row d="One">
+ <c>1</c>
+ </row>
+ <row d="Two">
+ <c>2</c>
+ </row>
+ <row d="Three">
+ <c>3</c>
+ </row>
+</t1>
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/r/alter_xml2.result b/storage/connect/mysql-test/connect/r/alter_xml2.result
new file mode 100644
index 00000000..a15be966
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/alter_xml2.result
@@ -0,0 +1,86 @@
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+#
+# Testing changing table type (not in-place)
+#
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV HEADER=1 QUOTED=1;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+# This would fail if the top node name is not specified.
+# This is because the XML top node name defaults to the table name.
+# Sure enough the temporary table name begins with '#' and is rejected by XML.
+# Therefore the top node name must be specified (along with the row nodes name).
+ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='xmlsup=libxml2,rownode=row';
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` int(11) NOT NULL,
+ `d` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `HEADER`=1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=libxml2,rownode=row'
+# Let us see the XML file
+CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.xml';
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+SELECT * FROM t2;
+line
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Created by the MariaDB CONNECT Storage Engine-->
+<t1>
+ <row>
+ <TH>c</TH>
+ <TH>d</TH>
+ </row>
+ <row>
+ <c>1</c>
+ <d>One</d>
+ </row>
+ <row>
+ <c>2</c>
+ <d>Two</d>
+ </row>
+ <row>
+ <c>3</c>
+ <d>Three</d>
+ </row>
+</t1>
+# NOTE: The first (ignored) row is due to the remaining HEADER=1 option.
+# Testing field option modification
+ALTER TABLE t1 MODIFY d CHAR(10) NOT NULL XPATH='@', HEADER=0;
+SELECT * FROM t1;
+c d
+1 One
+2 Two
+3 Three
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` int(11) NOT NULL,
+ `d` char(10) NOT NULL `XPATH`='@'
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `QUOTED`=1 `TABLE_TYPE`=XML `TABNAME`=t1 `OPTION_LIST`='xmlsup=libxml2,rownode=row' `HEADER`=0
+SELECT * FROM t2;
+line
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Created by the MariaDB CONNECT Storage Engine-->
+<t1>
+ <row d="One">
+ <c>1</c>
+ </row>
+ <row d="Two">
+ <c>2</c>
+ </row>
+ <row d="Three">
+ <c>3</c>
+ </row>
+</t1>
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/r/bin.result b/storage/connect/mysql-test/connect/r/bin.result
new file mode 100644
index 00000000..1baa18a1
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/bin.result
@@ -0,0 +1,99 @@
+#
+# Testing errors
+#
+CREATE TABLE t1
+(
+ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=BIN FILE_NAME='nonexistent.txt';
+SELECT * FROM t1;
+ID
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/nonexistent.txt: No such file or directory
+DROP TABLE t1;
+SET time_zone='+00:00';
+CREATE TABLE t1
+(
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL,
+id CHAR(5) NOT NULL FIELD_FORMAT='S',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+dept INT(4) NOT NULL FIELD_FORMAT='S'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+INSERT INTO t1 VALUES (55555,'RONALD','1980-02-26','3333',4444.44,555);
+ERROR HY000: Got error 122 'Value too long for field fig (5 --> 4)' from CONNECT
+INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t1;
+#
+# Testing READONLY tables
+#
+CREATE TABLE t1
+(
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL,
+id CHAR(5) NOT NULL FIELD_FORMAT='S',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+dept INT(4) NOT NULL FIELD_FORMAT='S'
+) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+ERROR HY000: Table 't1' is read only
+ALTER TABLE t1 READONLY=NO;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `fig` int(4) NOT NULL `FIELD_FORMAT`='C',
+ `name` char(10) NOT NULL,
+ `birth` date NOT NULL,
+ `id` char(5) NOT NULL `FIELD_FORMAT`='S',
+ `salary` double(9,2) NOT NULL DEFAULT 0.00 `FIELD_FORMAT`='F',
+ `dept` int(4) NOT NULL `FIELD_FORMAT`='S'
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=BIN `FILE_NAME`='Testbal.dat' `OPTION_LIST`='Endian=Little' `READONLY`=NO
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+7777 BILL 1973-06-30 4444 5555.56 777
+ALTER TABLE t1 READONLY=YES;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `fig` int(4) NOT NULL `FIELD_FORMAT`='C',
+ `name` char(10) NOT NULL,
+ `birth` date NOT NULL,
+ `id` char(5) NOT NULL `FIELD_FORMAT`='S',
+ `salary` double(9,2) NOT NULL DEFAULT 0.00 `FIELD_FORMAT`='F',
+ `dept` int(4) NOT NULL `FIELD_FORMAT`='S'
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=BIN `FILE_NAME`='Testbal.dat' `OPTION_LIST`='Endian=Little' `READONLY`=YES
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+ERROR HY000: Table 't1' is read only
+DROP TABLE t1;
+#
+# Testing that the underlying file is created
+#
+CREATE TABLE t1
+(
+c CHAR(4) NOT NULL FIELD_FORMAT='C'
+) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='bin2.dat';
+INSERT INTO t1 VALUES (10),(20),(300),(4000);
+SELECT * FROM t1;
+c
+10
+20
+300
+4000
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/bson.result b/storage/connect/mysql-test/connect/r/bson.result
new file mode 100644
index 00000000..fd15e020
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/bson.result
@@ -0,0 +1,517 @@
+#
+# Testing doc samples
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15),
+LANG CHAR(2),
+SUBJECT CHAR(32),
+AUTHOR CHAR(64),
+TITLE CHAR(32),
+TRANSLATION CHAR(32),
+TRANSLATOR CHAR(80),
+PUBLISHER CHAR(32),
+DATEPUB int(4)
+) ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+ISBN LANG SUBJECT AUTHOR TITLE TRANSLATION TRANSLATOR PUBLISHER DATEPUB
+9782212090819 fr applications Jean-Christophe Bernadac, François Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+DROP TABLE t1;
+#
+# Testing Jpath. Get the number of authors
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15),
+Language CHAR(2) JPATH='$.LANG',
+Subject CHAR(32) JPATH='$.SUBJECT',
+Authors INT(2) JPATH='$.AUTHOR[#]',
+Title CHAR(32) JPATH='$.TITLE',
+Translation CHAR(32) JPATH='$.TRANSLATION',
+Translator CHAR(80) JPATH='$.TRANSLATOR',
+Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+ISBN Language Subject Authors Title Translation Translator Publisher Location Year
+9782212090819 fr applications 2 Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications 1 XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+DROP TABLE t1;
+#
+# Concatenates the authors
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15),
+Language CHAR(2) JPATH='$.LANG',
+Subject CHAR(32) JPATH='$.SUBJECT',
+AuthorFN CHAR(128) JPATH='$.AUTHOR[" and "].FIRSTNAME',
+AuthorLN CHAR(128) JPATH='$.AUTHOR[" and "].LASTNAME',
+Title CHAR(32) JPATH='$.TITLE',
+Translation CHAR(32) JPATH='$.TRANSLATION',
+Translator CHAR(80) JPATH='$.TRANSLATOR',
+Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
+9782212090819 fr applications Jean-Christophe and François Bernadac and Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+DROP TABLE t1;
+#
+# Testing expanding authors
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15),
+Language CHAR(2) JPATH='$.LANG',
+Subject CHAR(32) JPATH='$.SUBJECT',
+AuthorFN CHAR(128) JPATH='$.AUTHOR[*].FIRSTNAME',
+AuthorLN CHAR(128) JPATH='$.AUTHOR[*].LASTNAME',
+Title CHAR(32) JPATH='$.TITLE',
+Translation CHAR(32) JPATH='$.TRANSLATION',
+Translator CHAR(80) JPATH='$.TRANSLATOR',
+Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
+9782212090819 fr applications Jean-Christophe Bernadac Construire une application XML NULL NULL Eyrolles Paris 1999
+9782212090819 fr applications François Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+UPDATE t1 SET AuthorFN = 'Philippe' WHERE AuthorLN = 'Knab';
+SELECT * FROM t1 WHERE ISBN = '9782212090819';
+ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
+9782212090819 fr applications Jean-Christophe Bernadac Construire une application XML NULL NULL Eyrolles Paris 1999
+9782212090819 fr applications Philippe Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+#
+# To add an author a new table must be created
+#
+CREATE TABLE t2 (
+FIRSTNAME CHAR(32),
+LASTNAME CHAR(32))
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json' OPTION_LIST='Object=$[1].AUTHOR';
+SELECT * FROM t2;
+FIRSTNAME LASTNAME
+William J. Pardi
+INSERT INTO t2 VALUES('Charles','Dickens');
+SELECT * FROM t1;
+ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
+9782212090819 fr applications Jean-Christophe Bernadac Construire une application XML NULL NULL Eyrolles Paris 1999
+9782212090819 fr applications Philippe Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+9782840825685 fr applications Charles Dickens XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+DROP TABLE t1;
+DROP TABLE t2;
+#
+# Check the biblio file has the good format
+#
+CREATE TABLE t1
+(
+line char(255)
+)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='biblio.json';
+SELECT * FROM t1;
+line
+[
+ {
+ "ISBN": "9782212090819",
+ "LANG": "fr",
+ "SUBJECT": "applications",
+ "AUTHOR": [
+ {
+ "FIRSTNAME": "Jean-Christophe",
+ "LASTNAME": "Bernadac"
+ },
+ {
+ "FIRSTNAME": "Philippe",
+ "LASTNAME": "Knab"
+ }
+ ],
+ "TITLE": "Construire une application XML",
+ "PUBLISHER": {
+ "NAME": "Eyrolles",
+ "PLACE": "Paris"
+ },
+ "DATEPUB": 1999
+ },
+ {
+ "ISBN": "9782840825685",
+ "LANG": "fr",
+ "SUBJECT": "applications",
+ "AUTHOR": [
+ {
+ "FIRSTNAME": "William J.",
+ "LASTNAME": "Pardi"
+ },
+ {
+ "FIRSTNAME": "Charles",
+ "LASTNAME": "Dickens"
+ }
+ ],
+ "TITLE": "XML en Action",
+ "TRANSLATION": "adapté de l'anglais par",
+ "TRANSLATOR": {
+ "FIRSTNAME": "James",
+ "LASTNAME": "Guerin"
+ },
+ "PUBLISHER": {
+ "NAME": "Microsoft Press",
+ "PLACE": "Paris"
+ },
+ "DATEPUB": 1999
+ }
+]
+DROP TABLE t1;
+#
+# Testing a pretty=0 file
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15) NOT NULL,
+Language CHAR(2) JPATH='$.LANG',
+Subject CHAR(32) JPATH='$.SUBJECT',
+AuthorFN CHAR(128) JPATH='$.AUTHOR[*].FIRSTNAME',
+AuthorLN CHAR(128) JPATH='$.AUTHOR[*].LASTNAME',
+Title CHAR(32) JPATH='$.TITLE',
+Translation CHAR(32) JPATH='$.TRANSLATED.PREFIX',
+TranslatorFN CHAR(80) JPATH='$.TRANSLATED.TRANSLATOR.FIRSTNAME',
+TranslatorLN CHAR(80) JPATH='$.TRANSLATED.TRANSLATOR.LASTNAME',
+Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+Year int(4) JPATH='$.DATEPUB',
+INDEX IX(ISBN)
+)
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='bib0.json' LRECL=320 OPTION_LIST='Pretty=0';
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 1 IX 1 ISBN A NULL NULL NULL XINDEX
+SELECT * FROM t1;
+ISBN Language Subject AuthorFN AuthorLN Title Translation TranslatorFN TranslatorLN Publisher Location Year
+9782212090819 fr applications Jean-Michel Bernadac Construire une application XML NULL NULL NULL Eyrolles Paris 1999
+9782212090819 fr applications François Knab Construire une application XML NULL NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 2001
+DESCRIBE SELECT * FROM t1 WHERE ISBN = '9782212090819';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref IX IX 15 const 1 Using where
+UPDATE t1 SET AuthorFN = 'Philippe' WHERE ISBN = '9782212090819';
+ERROR HY000: Got error 122 'Cannot write expanded column when Pretty is not 2' from CONNECT
+DROP TABLE t1;
+#
+# A file with 2 arrays
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[*].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[].EXPENSE["+"].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[].EXPENSE[+].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer+Food+Food+Car 69.00
+Joe 4 Beer+Beer+Food+Food+Beer 83.00
+Joe 5 Beer+Food 26.00
+Beth 3 Beer 16.00
+Beth 4 Food+Beer 32.00
+Beth 5 Food+Beer 32.00
+Janet 3 Car+Food+Beer 55.00
+Janet 4 Car 17.00
+Janet 5 Beer+Car+Beer+Food 57.00
+DROP TABLE t1;
+#
+# Now it can be fully expanded
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[*].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[*].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[*].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 3 Beer 16.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+Janet 4 Car 17.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+DROP TABLE t1;
+#
+# A table showing many calculated results
+#
+CREATE TABLE t1 (
+WHO CHAR(12) NOT NULL,
+WEEKS CHAR(12) NOT NULL JPATH='$.WEEK[", "].NUMBER',
+SUMS CHAR(64) NOT NULL JPATH='$.WEEK["+"].EXPENSE[+].AMOUNT',
+SUM DOUBLE(8,2) NOT NULL JPATH='$.WEEK[+].EXPENSE[+].AMOUNT',
+AVGS CHAR(64) NOT NULL JPATH='$.WEEK["+"].EXPENSE[!].AMOUNT',
+SUMAVG DOUBLE(8,2) NOT NULL JPATH='$.WEEK[+].EXPENSE[!].AMOUNT',
+AVGSUM DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[+].AMOUNT',
+AVGAVG DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[!].AMOUNT',
+AVERAGE DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+WHO WEEKS SUMS SUM AVGS SUMAVG AVGSUM AVGAVG AVERAGE
+Joe 3, 4, 5 69.00+83.00+26.00 178.00 17.25+16.60+13.00 46.85 59.33 15.62 16.18
+Beth 3, 4, 5 16.00+32.00+32.00 80.00 16.00+16.00+16.00 48.00 26.67 16.00 16.00
+Janet 3, 4, 5 55.00+17.00+57.00 129.00 18.33+17.00+14.25 49.58 43.00 16.53 16.12
+DROP TABLE t1;
+#
+# Expand expense in 3 one week tables
+#
+CREATE TABLE t2 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[0].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[0].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[0].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t2;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Beth 3 Beer 16.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+CREATE TABLE t3 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[1].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[1].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[1].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t3;
+WHO WEEK WHAT AMOUNT
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+CREATE TABLE t4 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[2].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[2].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[2].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t4;
+WHO WEEK WHAT AMOUNT
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+#
+# The expanded table is made as a TBL table
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32),
+AMOUNT DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t2,t3,t4';
+SELECT * FROM t1;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Beth 3 Beer 16.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+DROP TABLE t1, t2, t3, t4;
+#
+# Three partial JSON tables
+#
+CREATE TABLE t2 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp3.json';
+SELECT * FROM t2;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Beth 3 Beer 16.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+CREATE TABLE t3 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp4.json';
+SELECT * FROM t3;
+WHO WEEK WHAT AMOUNT
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+CREATE TABLE t4 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp5.json';
+SELECT * FROM t4;
+WHO WEEK WHAT AMOUNT
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+#
+# The complete table can be a multiple JSON table
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp*.json' MULTIPLE=1;
+SELECT * FROM t1 ORDER BY WHO, WEEK, WHAT, AMOUNT;
+WHO WEEK WHAT AMOUNT
+Beth 3 Beer 16.00
+Beth 4 Beer 15.00
+Beth 4 Food 17.00
+Beth 5 Beer 20.00
+Beth 5 Food 12.00
+Janet 3 Beer 18.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 4 Car 17.00
+Janet 5 Beer 14.00
+Janet 5 Beer 19.00
+Janet 5 Car 12.00
+Janet 5 Food 12.00
+Joe 3 Beer 18.00
+Joe 3 Car 20.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 4 Beer 14.00
+Joe 4 Beer 16.00
+Joe 4 Beer 19.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+DROP TABLE t1;
+#
+# Or also a partition JSON table
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp%s.json';
+ALTER TABLE t1
+PARTITION BY LIST COLUMNS(WEEK) (
+PARTITION `3` VALUES IN(3),
+PARTITION `4` VALUES IN(4),
+PARTITION `5` VALUES IN(5));
+Warnings:
+Warning 1105 Data repartition in 3 is unchecked
+Warning 1105 Data repartition in 4 is unchecked
+Warning 1105 Data repartition in 5 is unchecked
+SHOW WARNINGS;
+Level Code Message
+Warning 1105 Data repartition in 3 is unchecked
+Warning 1105 Data repartition in 4 is unchecked
+Warning 1105 Data repartition in 5 is unchecked
+SELECT * FROM t1;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Beth 3 Beer 16.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+SELECT * FROM t1 WHERE WEEK = 4;
+WHO WEEK WHAT AMOUNT
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+DROP TABLE t1, t2, t3, t4;
diff --git a/storage/connect/mysql-test/connect/r/bson_java_2.result b/storage/connect/mysql-test/connect/r/bson_java_2.result
new file mode 100644
index 00000000..1c21fc7c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/bson_java_2.result
@@ -0,0 +1,385 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants CONNECTION='mongodb://localhost:27017' LRECL=4096
+OPTION_LIST='Driver=Java,Version=2' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51c"},"address":{"building":"1007","coord":[-73.856077,40.848447],"street":"Morris Park Ave","zipcode":"10462"},"borough":"Bronx","cuisine":"Bakery","grades":[{"date":{"$date":"2014-03-03T00:00:00.000Z"},"grade":"A","score":2},{"date":{"$date":"2013-09-11T00:00:00.000Z"},"grade":"A","score":6},{"date":{"$date":"2013-01-24T00:00:00.000Z"},"grade":"A","score":10},{"date":{"$date":"2011-11-23T00:00:00.000Z"},"grade":"A","score":9},{"date":{"$date":"2011-03-10T00:00:00.000Z"},"grade":"B","score":14}],"name":"Morris Park Bake Shop","restaurant_id":"30075445"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51d"},"address":{"building":"469","coord":[-73.961704,40.662942],"street":"Flatbush Avenue","zipcode":"11225"},"borough":"Brooklyn","cuisine":"Hamburgers","grades":[{"date":{"$date":"2014-12-30T00:00:00.000Z"},"grade":"A","score":8},{"date":{"$date":"2014-07-01T00:00:00.000Z"},"grade":"B","score":23},{"date":{"$date":"2013-04-30T00:00:00.000Z"},"grade":"A","score":12},{"date":{"$date":"2012-05-08T00:00:00.000Z"},"grade":"A","score":12}],"name":"Wendy'S","restaurant_id":"30112340"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51e"},"address":{"building":"351","coord":[-73.98513559999999,40.7676919],"street":"West 57 Street","zipcode":"10019"},"borough":"Manhattan","cuisine":"Irish","grades":[{"date":{"$date":"2014-09-06T00:00:00.000Z"},"grade":"A","score":2},{"date":{"$date":"2013-07-22T00:00:00.000Z"},"grade":"A","score":11},{"date":{"$date":"2012-07-31T00:00:00.000Z"},"grade":"A","score":12},{"date":{"$date":"2011-12-29T00:00:00.000Z"},"grade":"A","score":12}],"name":"Dj Reynolds Pub And Restaurant","restaurant_id":"30191841"}
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=Java,Version=2' DATA_CHARSET=utf8 CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
+_id 1 CHAR 24 24 0 0 _id
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 1024 1024 0 1 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
+grades_grade 1 CHAR 14 14 0 1 grades.0.grade
+grades_score 7 INTEGER 2 2 0 1 grades.0.score
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096 DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='BSON' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=Java,Version=2' `DATA_CHARSET`='utf8' `LRECL`=4096
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_date grades_grade grades_score name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 -73.856077, 40.848447 Morris Park Ave 10462 Bronx Bakery 2014-03-03T00:00:00.000Z A 2 Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 -73.961704, 40.662942 Flatbush Avenue 11225 Brooklyn Hamburgers 2014-12-30T00:00:00.000Z A 8 Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 -73.98513559999999, 40.7676919 West 57 Street 10019 Manhattan Irish 2014-09-06T00:00:00.000Z A 2 Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 -73.98241999999999, 40.579505 Stillwell Avenue 11224 Brooklyn American 2014-06-10T00:00:00.000Z A 5 Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 -73.8601152, 40.7311739 63 Road 11374 Queens Jewish/Kosher 2014-11-24T00:00:00.000Z Z 20 Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"grades":0}' OPTION_LIST='Driver=Java,Version=2,level=0' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 (-73.856077, 40.848447) Morris Park Ave 10462 Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 (-73.961704, 40.662942) Flatbush Avenue 11225 Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 (-73.98513559999999, 40.7676919) West 57 Street 10019 Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 (-73.98241999999999, 40.579505) Stillwell Avenue 11224 Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 (-73.8601152, 40.7311739) 63 Road 11374 Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 8825 (-73.8803827, 40.7643124) Astoria Boulevard 11369 Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 2206 (-74.1377286, 40.6119572) Victory Boulevard 10314 Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 7114 (-73.9068506, 40.6199034) Avenue U 11234 Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 6409 (-74.00528899999999, 40.628886) 11 Avenue 11219 Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 1839 (-73.9482609, 40.6408271) Nostrand Avenue 11226 Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 1970-01-01
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 1970-01-01
+Wendy'S Flatbush Avenue 8 1970-01-01
+Dj Reynolds Pub And Restaurant West 57 Street 2 1970-01-01
+Riviera Caterer Stillwell Avenue 5 1970-01-01
+Tov Kosher Kitchen 63 Road 20 1970-01-01
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 1970-01-01 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 1970-01-01 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 1970-01-01 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 1970-01-01 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 1970-01-01 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 1970-01-01 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 1970-01-01 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 1970-01-01 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 1970-01-01 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 1970-01-01 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 1970-01-01 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 1970-01-01 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 1970-01-01 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 1970-01-01 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 1970-01-01 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 1970-01-01 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 1970-01-01 01:33:34 B 15
+Tout Va Bien Manhattan 1970-01-01 01:33:34 A 13
+Tout Va Bien Manhattan 1970-01-01 01:33:33 C 36
+Tout Va Bien Manhattan 1970-01-01 01:33:33 B 22
+Tout Va Bien Manhattan 1970-01-01 01:33:32 C 36
+Tout Va Bien Manhattan 1970-01-01 01:33:32 C 7
+La Grenouille Manhattan 1970-01-01 01:33:34 A 10
+La Grenouille Manhattan 1970-01-01 01:33:33 A 9
+La Grenouille Manhattan 1970-01-01 01:33:32 A 13
+Le Perigord Manhattan 1970-01-01 01:33:34 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 1970-01-01 01:33:34
+Bistro Sk A 12 1970-01-01 01:33:34
+Bistro Sk B 18 1970-01-01 01:33:33
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"cuisine":0}' CONNECTION='mongodb://localhost:27017' LRECL=4096
+OPTION_LIST='Driver=Java,level=2,version=2';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(18,16) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_date` char(24) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='BSON' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=2' `LRECL`=4096
+SELECT name, borough, address_street, grades_score AS score FROM t1 WHERE grades_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll'
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=BSON TABNAME='cities'
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096 DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=YES' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1;
+item total average
+journal 285 57.00
+notebook 1368 456.00
+paper 23 5.75
+planner 167 41.75
+postcard 23 5.75
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/bson_java_3.result b/storage/connect/mysql-test/connect/r/bson_java_3.result
new file mode 100644
index 00000000..d198ee3f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/bson_java_3.result
@@ -0,0 +1,385 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants CONNECTION='mongodb://localhost:27017' LRECL=4096
+OPTION_LIST='Driver=Java,Version=3' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51c"},"address":{"building":"1007","coord":[-73.856077,40.848447],"street":"Morris Park Ave","zipcode":"10462"},"borough":"Bronx","cuisine":"Bakery","grades":[{"date":{"$date":1393804800000},"grade":"A","score":2},{"date":{"$date":1378857600000},"grade":"A","score":6},{"date":{"$date":1358985600000},"grade":"A","score":10},{"date":{"$date":1322006400000},"grade":"A","score":9},{"date":{"$date":1299715200000},"grade":"B","score":14}],"name":"Morris Park Bake Shop","restaurant_id":"30075445"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51d"},"address":{"building":"469","coord":[-73.961704,40.662942],"street":"Flatbush Avenue","zipcode":"11225"},"borough":"Brooklyn","cuisine":"Hamburgers","grades":[{"date":{"$date":1419897600000},"grade":"A","score":8},{"date":{"$date":1404172800000},"grade":"B","score":23},{"date":{"$date":1367280000000},"grade":"A","score":12},{"date":{"$date":1336435200000},"grade":"A","score":12}],"name":"Wendy'S","restaurant_id":"30112340"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51e"},"address":{"building":"351","coord":[-73.98513559999999,40.7676919],"street":"West 57 Street","zipcode":"10019"},"borough":"Manhattan","cuisine":"Irish","grades":[{"date":{"$date":1409961600000},"grade":"A","score":2},{"date":{"$date":1374451200000},"grade":"A","score":11},{"date":{"$date":1343692800000},"grade":"A","score":12},{"date":{"$date":1325116800000},"grade":"A","score":12}],"name":"Dj Reynolds Pub And Restaurant","restaurant_id":"30191841"}
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=Java,Version=3' DATA_CHARSET=utf8 CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
+_id 1 CHAR 24 24 0 0 _id
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 1024 1024 0 1 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
+grades_grade 1 CHAR 14 14 0 1 grades.0.grade
+grades_score 7 INTEGER 2 2 0 1 grades.0.score
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096 DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='BSON' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=Java,Version=3' `DATA_CHARSET`='utf8' `LRECL`=4096
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_date grades_grade grades_score name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 -73.856077, 40.848447 Morris Park Ave 10462 Bronx Bakery 1393804800 A 2 Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 -73.961704, 40.662942 Flatbush Avenue 11225 Brooklyn Hamburgers 1419897600 A 8 Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 -73.98513559999999, 40.7676919 West 57 Street 10019 Manhattan Irish 1409961600 A 2 Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 -73.98241999999999, 40.579505 Stillwell Avenue 11224 Brooklyn American 1402358400 A 5 Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 -73.8601152, 40.7311739 63 Road 11374 Queens Jewish/Kosher 1416787200 Z 20 Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"grades":0}' OPTION_LIST='Driver=Java,Version=3,level=0' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 (-73.856077, 40.848447) Morris Park Ave 10462 Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 (-73.961704, 40.662942) Flatbush Avenue 11225 Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 (-73.98513559999999, 40.7676919) West 57 Street 10019 Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 (-73.98241999999999, 40.579505) Stillwell Avenue 11224 Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 (-73.8601152, 40.7311739) 63 Road 11374 Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 8825 (-73.8803827, 40.7643124) Astoria Boulevard 11369 Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 2206 (-74.1377286, 40.6119572) Victory Boulevard 10314 Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 7114 (-73.9068506, 40.6199034) Avenue U 11234 Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 6409 (-74.00528899999999, 40.628886) 11 Avenue 11219 Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 1839 (-73.9482609, 40.6408271) Nostrand Avenue 11226 Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 2014-03-03
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 2014-03-03
+Wendy'S Flatbush Avenue 8 2014-12-30
+Dj Reynolds Pub And Restaurant West 57 Street 2 2014-09-06
+Riviera Caterer Stillwell Avenue 5 2014-06-10
+Tov Kosher Kitchen 63 Road 20 2014-11-24
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 2014-10-23 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 2014-08-14 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 2014-09-29 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 2014-02-11 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 2014-10-08 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 2014-06-09 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 2014-10-22 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 2014-07-26 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 2014-12-03 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 2015-01-16 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 2014-08-27 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 2014-06-03 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 2014-08-07 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 2014-12-27 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 2014-10-28 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 2014-08-18 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 2014-11-10 01:00:00 B 15
+Tout Va Bien Manhattan 2014-04-03 02:00:00 A 13
+Tout Va Bien Manhattan 2013-07-17 02:00:00 C 36
+Tout Va Bien Manhattan 2013-02-06 01:00:00 B 22
+Tout Va Bien Manhattan 2012-07-16 02:00:00 C 36
+Tout Va Bien Manhattan 2012-03-08 01:00:00 C 7
+La Grenouille Manhattan 2014-04-09 02:00:00 A 10
+La Grenouille Manhattan 2013-03-05 01:00:00 A 9
+La Grenouille Manhattan 2012-02-02 01:00:00 A 13
+Le Perigord Manhattan 2014-07-14 02:00:00 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 2014-11-21 01:00:00
+Bistro Sk A 12 2014-02-19 01:00:00
+Bistro Sk B 18 2013-06-12 02:00:00
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"cuisine":0}' CONNECTION='mongodb://localhost:27017' LRECL=4096
+OPTION_LIST='Driver=Java,level=2,version=3';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(18,16) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_date` bigint(13) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='BSON' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=3' `LRECL`=4096
+SELECT name, borough, address_street, grades_score AS score FROM t1 WHERE grades_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll'
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=BSON TABNAME='cities'
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096 DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=YES' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1;
+item total average
+journal 285 57.00
+notebook 1368 456.00
+paper 23 5.75
+planner 167 41.75
+postcard 23 5.75
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/bson_mongo_c.result b/storage/connect/mysql-test/connect/r/bson_mongo_c.result
new file mode 100644
index 00000000..e2273be4
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/bson_mongo_c.result
@@ -0,0 +1,385 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants CONNECTION='mongodb://localhost:27017' LRECL=1024
+OPTION_LIST='Driver=C,Version=0' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51c"},"address":{"building":"1007","coord":[-73.8560769999999991,40.8484470000000002],"street":"Morris Park Ave","zipcode":"10462"},"borough":"Bronx","cuisine":"Bakery","grades":[{"date":{"$date":1393804800000},"grade":"A","score":2},{"date":{"$date":1378857600000},"grade":"A","score":6},{"date":{"$date":1358985600000},"grade":"A","score":10},{"date":{"$date":1322006400000},"grade":"A","score":9},{"date":{"$date":1299715200000},"grade":"B","score":14}],"name":"Morris Park Bake Shop","restaurant_id":"30075445"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51d"},"address":{"building":"469","coord":[-73.9617039999999974,40.6629420000000010],"street":"Flatbush Avenue","zipcode":"11225"},"borough":"Brooklyn","cuisine":"Hamburgers","grades":[{"date":{"$date":1419897600000},"grade":"A","score":8},{"date":{"$date":1404172800000},"grade":"B","score":23},{"date":{"$date":1367280000000},"grade":"A","score":12},{"date":{"$date":1336435200000},"grade":"A","score":12}],"name":"Wendy'S","restaurant_id":"30112340"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51e"},"address":{"building":"351","coord":[-73.9851355999999925,40.7676919000000026],"street":"West 57 Street","zipcode":"10019"},"borough":"Manhattan","cuisine":"Irish","grades":[{"date":{"$date":1409961600000},"grade":"A","score":2},{"date":{"$date":1374451200000},"grade":"A","score":11},{"date":{"$date":1343692800000},"grade":"A","score":12},{"date":{"$date":1325116800000},"grade":"A","score":12}],"name":"Dj Reynolds Pub And Restaurant","restaurant_id":"30191841"}
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=C,Version=0' DATA_CHARSET=utf8 CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
+_id 1 CHAR 24 24 0 0 _id
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 1024 1024 0 1 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
+grades_grade 1 CHAR 14 14 0 1 grades.0.grade
+grades_score 7 INTEGER 2 2 0 1 grades.0.score
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='BSON' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=C,Version=0' `DATA_CHARSET`='utf8' `LRECL`=1024
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_date grades_grade grades_score name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 -73.8560769999999991, 40.8484470000000002 Morris Park Ave 10462 Bronx Bakery 1393804800 A 2 Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 -73.9617039999999974, 40.6629420000000010 Flatbush Avenue 11225 Brooklyn Hamburgers 1419897600 A 8 Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 -73.9851355999999925, 40.7676919000000026 West 57 Street 10019 Manhattan Irish 1409961600 A 2 Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 -73.9824199999999905, 40.5795049999999975 Stillwell Avenue 11224 Brooklyn American 1402358400 A 5 Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 -73.8601151999999956, 40.7311739000000017 63 Road 11374 Queens Jewish/Kosher 1416787200 Z 20 Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"projection":{"grades":0}}' OPTION_LIST='Driver=C,Version=0,level=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 (-73.8560769999999991, 40.8484470000000002) Morris Park Ave 10462 Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 (-73.9617039999999974, 40.6629420000000010) Flatbush Avenue 11225 Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 (-73.9851355999999925, 40.7676919000000026) West 57 Street 10019 Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 (-73.9824199999999905, 40.5795049999999975) Stillwell Avenue 11224 Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 (-73.8601151999999956, 40.7311739000000017) 63 Road 11374 Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 8825 (-73.8803826999999984, 40.7643124000000014) Astoria Boulevard 11369 Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 2206 (-74.1377286000000026, 40.6119571999999991) Victory Boulevard 10314 Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 7114 (-73.9068505999999985, 40.6199033999999983) Avenue U 11234 Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 6409 (-74.0052889999999906, 40.6288860000000014) 11 Avenue 11219 Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 1839 (-73.9482608999999940, 40.6408271000000028) Nostrand Avenue 11226 Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 2014-03-03
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 2014-03-03
+Wendy'S Flatbush Avenue 8 2014-12-30
+Dj Reynolds Pub And Restaurant West 57 Street 2 2014-09-06
+Riviera Caterer Stillwell Avenue 5 2014-06-10
+Tov Kosher Kitchen 63 Road 20 2014-11-24
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 2014-10-23 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 2014-08-14 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 2014-09-29 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 2014-02-11 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 2014-10-08 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 2014-06-09 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 2014-10-22 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 2014-07-26 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 2014-12-03 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 2015-01-16 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 2014-08-27 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 2014-06-03 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 2014-08-07 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 2014-12-27 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 2014-10-28 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 2014-08-18 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 2014-11-10 01:00:00 B 15
+Tout Va Bien Manhattan 2014-04-03 02:00:00 A 13
+Tout Va Bien Manhattan 2013-07-17 02:00:00 C 36
+Tout Va Bien Manhattan 2013-02-06 01:00:00 B 22
+Tout Va Bien Manhattan 2012-07-16 02:00:00 C 36
+Tout Va Bien Manhattan 2012-03-08 01:00:00 C 7
+La Grenouille Manhattan 2014-04-09 02:00:00 A 10
+La Grenouille Manhattan 2013-03-05 01:00:00 A 9
+La Grenouille Manhattan 2012-02-02 01:00:00 A 13
+Le Perigord Manhattan 2014-07-14 02:00:00 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 2014-11-21 01:00:00
+Bistro Sk A 12 2014-02-19 01:00:00
+Bistro Sk B 18 2013-06-12 02:00:00
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"projection":{"cuisine":0}}' CONNECTION='mongodb://localhost:27017' LRECL=1024
+OPTION_LIST='Driver=C,level=2,version=0';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(21,16) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_date` bigint(13) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='BSON' `TABNAME`='restaurants' `COLIST`='{"projection":{"cuisine":0}}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=C,level=2,version=0' `LRECL`=1024
+SELECT name, borough, address_street, grades_score AS score FROM t1 WHERE grades_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll'
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=BSON TABNAME='cities'
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=BSON TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=YES' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1;
+item total average
+journal 285 57.00
+notebook 1368 456.00
+paper 23 5.75
+planner 167 41.75
+postcard 23 5.75
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/bson_udf.result b/storage/connect/mysql-test/connect/r/bson_udf.result
new file mode 100644
index 00000000..fef55f7d
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/bson_udf.result
@@ -0,0 +1,685 @@
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=VIR BLOCK_SIZE=5;
+#
+# Test UDF's with constant arguments
+#
+SELECT BsonValue(56, 3.1416, 'foo', NULL);
+ERROR HY000: Can't initialize function 'bsonvalue'; Cannot accept more than 1 argument
+SELECT BsonValue(3.1416);
+BsonValue(3.1416)
+3.1416
+SELECT BsonValue(-80);
+BsonValue(-80)
+-80
+SELECT BsonValue('foo');
+BsonValue('foo')
+foo
+SELECT BsonValue(9223372036854775807);
+BsonValue(9223372036854775807)
+9223372036854775807
+SELECT BsonValue(NULL);
+BsonValue(NULL)
+null
+SELECT BsonValue(TRUE);
+BsonValue(TRUE)
+true
+SELECT BsonValue(FALSE);
+BsonValue(FALSE)
+false
+SELECT BsonValue();
+BsonValue()
+null
+SELECT BsonValue('[11, 22, 33]' json_) FROM t1;
+BsonValue('[11, 22, 33]' json_)
+[11,22,33]
+[11,22,33]
+[11,22,33]
+[11,22,33]
+[11,22,33]
+SELECT Bson_Make_Array();
+Bson_Make_Array()
+[]
+SELECT Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL);
+Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL)
+[56,3.1416,"My name is \"Foo\"",null]
+SELECT Bson_Make_Array(Bson_Make_Array(56, 3.1416, 'foo'), TRUE);
+Bson_Make_Array(Bson_Make_Array(56, 3.1416, 'foo'), TRUE)
+[[56,3.1416,"foo"],true]
+SELECT Bson_Array_Add(Bson_Make_Array(56, 3.1416, 'foo', NULL)) Array;
+ERROR HY000: Can't initialize function 'bson_array_add'; This function must have at least 2 arguments
+SELECT Bson_Array_Add(Bson_Make_Array(56, 3.1416, 'foo', NULL), 'One more') Array;
+Array
+[56,3.1416,"foo",null,"One more"]
+SELECT Bson_Array_Add(BsonValue('one value'), 'One more');
+Bson_Array_Add(BsonValue('one value'), 'One more')
+["one value","One more"]
+SELECT Bson_Array_Add('one value', 'One more');
+Bson_Array_Add('one value', 'One more')
+["one value","One more"]
+SELECT Bson_Array_Add('one value' json_, 'One more');
+Bson_Array_Add('one value' json_, 'One more')
+["one value","One more"]
+SELECT Bson_Array_Add(5 json_, 'One more');
+Bson_Array_Add(5 json_, 'One more')
+[5,"One more"]
+SELECT Bson_Array_Add('[5,3,8,7,9]' json_, 4, 0);
+Bson_Array_Add('[5,3,8,7,9]' json_, 4, 0)
+[4,5,3,8,7,9]
+SELECT Bson_Array_Add('[5,3,8,7,9]' json_, 4, 2) Array;
+Array
+[5,3,4,8,7,9]
+SELECT Bson_Array_Add('[5,3,8,7,9]' json_, 4, 9);
+Bson_Array_Add('[5,3,8,7,9]' json_, 4, 9)
+[5,3,8,7,9,4]
+SELECT Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), '[2]', 33, 1);
+Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), '[2]', 33, 1)
+[1,2,[11,22],"[2]"]
+SELECT Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), 33, '[2]', 1);
+Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), 33, '[2]', 1)
+[1,2,[11,33,22]]
+SELECT Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), 33, 1, '[2]');
+Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), 33, 1, '[2]')
+[1,2,[11,33,22]]
+SELECT Bson_Array_Add_Values(Bson_Make_Array(56, 3.1416, 'machin', NULL), 'One more', 'Two more') Array;
+Array
+[56,3.1416,"machin",null,"One more","Two more"]
+SELECT Bson_Array_Add_Values(Bson_Make_Array(56, 3.1416, 'machin'), 'One more', 'Two more') Array FROM t1;
+Array
+[56,3.1416,"machin","One more","Two more"]
+[56,3.1416,"machin","One more","Two more"]
+[56,3.1416,"machin","One more","Two more"]
+[56,3.1416,"machin","One more","Two more"]
+[56,3.1416,"machin","One more","Two more"]
+SELECT Bson_Array_Add_Values(Bson_Make_Array(56, 3.1416, 'machin'), n) Array FROM t1;
+Array
+[56,3.1416,"machin",1]
+[56,3.1416,"machin",2]
+[56,3.1416,"machin",3]
+[56,3.1416,"machin",4]
+[56,3.1416,"machin",5]
+SELECT Bson_Array_Add_Values(Bson_Make_Array(n, 3.1416, 'machin'), n) Array FROM t1;
+Array
+[1,3.1416,"machin",1]
+[2,3.1416,"machin",2]
+[3,3.1416,"machin",3]
+[4,3.1416,"machin",4]
+[5,3.1416,"machin",5]
+SELECT Bson_Array_Add_Values('[56]', 3.1416, 'machin') Array;
+Array
+[56,3.1416,"machin"]
+SELECT Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0);
+Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0)
+[3.1416,"My name is \"Foo\"",null]
+SELECT Bson_Array_Delete(Bson_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2);
+Bson_Array_Delete(Bson_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2)
+{"56":56,"3.1416":3.1416,"My name is Foo":"My name is Foo","NULL":null}
+Warnings:
+Warning 1105 First argument target is not an array
+SELECT Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2');
+Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2')
+[56,3.1416,"My name is \"Foo\"",null]
+Warnings:
+Warning 1105 Missing or null array index
+SELECT Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2);
+Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2)
+[56,3.1416,"My name is \"Foo\"",null]
+Warnings:
+Warning 1105 First argument target is not an array
+/* WARNING VOID */
+#
+SELECT Bson_Make_Object(56, 3.1416, 'foo', NULL);
+Bson_Make_Object(56, 3.1416, 'foo', NULL)
+{"56":56,"3.1416":3.1416,"foo":"foo","NULL":null}
+SELECT Bson_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty);
+Bson_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty)
+{"qty":56,"price":3.1416,"truc":"foo","garanty":null}
+SELECT Bson_Make_Object();
+Bson_Make_Object()
+{}
+SELECT Bson_Make_Object(Bson_Make_Array(56, 3.1416, 'foo'), NULL);
+Bson_Make_Object(Bson_Make_Array(56, 3.1416, 'foo'), NULL)
+{"Make_Array(56, 3.1416, 'foo')":[56,3.1416,"foo"],"NULL":null}
+SELECT Bson_Make_Array(Bson_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL);
+Bson_Make_Array(Bson_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL)
+[{"qty":56,"price":3.1416,"foo":"foo"},null]
+SELECT Bson_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL);
+Bson_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL)
+{"qty":56,"price":3.1416,"truc":"machin","garanty":null}
+SELECT Bson_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty');
+ERROR HY000: Can't initialize function 'bson_object_key'; This function must have an even number of arguments
+SELECT Bson_Object_Add(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color);
+Bson_Object_Add(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color)
+{"qty":56,"price":3.1416,"truc":"machin","garanty":null,"color":"blue"}
+SELECT Bson_Object_Add(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price);
+Bson_Object_Add(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price)
+{"qty":56,"price":45.99,"truc":"machin","garanty":null}
+SELECT Bson_Object_Add(Bson_File('notexist.json'), 'cheese' item, '[1]', 1);
+Bson_Object_Add(Bson_File('notexist.json'), 'cheese' item, '[1]', 1)
+NULL
+Warnings:
+Warning 1105 Error 2 opening notexist.json
+Warning 1105 No sub-item at '[1]'
+SELECT Bson_Object_Delete(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc');
+Bson_Object_Delete(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc')
+{"qty":56,"price":3.1416,"garanty":null}
+SELECT Bson_Object_Delete(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose');
+Bson_Object_Delete(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose')
+{"qty":56,"price":3.1416,"truc":"machin","garanty":null}
+SELECT Bson_Object_List(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty)) "Key List";
+Key List
+["qty","price","truc","garanty"]
+SELECT Bson_Object_List('{"qty":56, "price":3.1416, "truc":"machin", "garanty":null}') "Key List";
+Key List
+["qty","price","truc","garanty"]
+SELECT Bson_Object_Values('{"One":1,"Two":2,"Three":3}') "Value List";
+Value List
+[1,2,3]
+#
+# Test UDF's with column arguments
+#
+SELECT Bsonset_Def_Prec(2);
+Bsonset_Def_Prec(2)
+2
+CREATE TABLE t2
+(
+ISBN CHAR(15),
+LANG CHAR(2),
+SUBJECT CHAR(32),
+AUTHOR CHAR(64),
+TITLE CHAR(32),
+TRANSLATION CHAR(32),
+TRANSLATOR CHAR(80),
+PUBLISHER CHAR(32),
+DATEPUB int(4)
+) ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT Bson_Make_Array(AUTHOR, TITLE, DATEPUB) FROM t2;
+Bson_Make_Array(AUTHOR, TITLE, DATEPUB)
+[" Jean-Christophe Bernadac, François Knab","Construire une application XML",1999]
+["William J. Pardi","XML en Action",1999]
+SELECT Bson_Make_Object(AUTHOR, TITLE, DATEPUB) FROM t2;
+Bson_Make_Object(AUTHOR, TITLE, DATEPUB)
+{"AUTHOR":" Jean-Christophe Bernadac, François Knab","TITLE":"Construire une application XML","DATEPUB":1999}
+{"AUTHOR":"William J. Pardi","TITLE":"XML en Action","DATEPUB":1999}
+SELECT Bson_Array_Grp(TITLE, DATEPUB) FROM t2;
+ERROR HY000: Can't initialize function 'bson_array_grp'; This function can only accept 1 argument
+SELECT Bson_Array_Grp(TITLE) FROM t2;
+Bson_Array_Grp(TITLE)
+["Construire une application XML","XML en Action"]
+CREATE TABLE t3 (
+SERIALNO CHAR(5) NOT NULL,
+NAME VARCHAR(12) NOT NULL FLAG=6,
+SEX SMALLINT(1) NOT NULL,
+TITLE VARCHAR(15) NOT NULL FLAG=20,
+MANAGER CHAR(5) DEFAULT NULL,
+DEPARTMENT CHAr(4) NOT NULL FLAG=41,
+SECRETARY CHAR(5) DEFAULT NULL FLAG=46,
+SALARY DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=8 FILE_NAME='employee.dat' ENDING=1;
+SELECT Bson_Make_Object(SERIALNO, NAME, TITLE, SALARY) FROM t3 WHERE NAME = 'MERCHANT';
+Bson_Make_Object(SERIALNO, NAME, TITLE, SALARY)
+{"SERIALNO":"78943","NAME":"MERCHANT","TITLE":"SALESMAN","SALARY":8700.00}
+SELECT DEPARTMENT, Bson_Array_Grp(NAME) FROM t3 GROUP BY DEPARTMENT;
+DEPARTMENT Bson_Array_Grp(NAME)
+0021 ["STRONG","SHORTSIGHT"]
+0318 ["BANCROFT","PLUMHEAD","HONEY","TONGHO","WALTER","SHRINKY","WERTHER","MERCHANT","WHEELFOR"]
+0319 ["BULLOZER","QUINN","BROWNY","KITTY","MONAPENNY","MARTIN","FUNNIGUY","BUGHAPPY","FODDERMAN","MESSIFUL"]
+2452 ["BIGHEAD","ORELLY","BIGHORN","SMITH","CHERRY"]
+Warnings:
+Warning 1105 Result truncated to json_grp_size values
+SELECT BsonSet_Grp_Size(30);
+BsonSet_Grp_Size(30)
+30
+SELECT Bson_Make_Object(title, Bson_Array_Grp(name) `json_names`) from t3 GROUP BY title;
+Bson_Make_Object(title, Bson_Array_Grp(name) `json_names`)
+{"title":"ADMINISTRATOR","names":["GOOSEPEN","FUNNIGUY","SHRINKY"]}
+{"title":"DIRECTOR","names":["QUINN","WERTHER","STRONG"]}
+{"title":"ENGINEER","names":["BROWNY","ORELLY","MARTIN","TONGHO","WALTER","SMITH"]}
+{"title":"PROGRAMMER","names":["BUGHAPPY"]}
+{"title":"SALESMAN","names":["WHEELFOR","MERCHANT","BULLOZER","BANCROFT","FODDERMAN"]}
+{"title":"SCIENTIST","names":["BIGHEAD","BIGHORN"]}
+{"title":"SECRETARY","names":["MESSIFUL","HONEY","SHORTSIGHT","CHERRY","MONAPENNY"]}
+{"title":"TYPIST","names":["KITTY","PLUMHEAD"]}
+SELECT Bson_Make_Array(DEPARTMENT, Bson_Array_Grp(NAME)) FROM t3 GROUP BY DEPARTMENT;
+Bson_Make_Array(DEPARTMENT, Bson_Array_Grp(NAME))
+["0021",["STRONG","SHORTSIGHT"]]
+["0318",["BANCROFT","PLUMHEAD","HONEY","TONGHO","WALTER","SHRINKY","WERTHER","MERCHANT","WHEELFOR"]]
+["0319",["BULLOZER","QUINN","BROWNY","KITTY","MONAPENNY","MARTIN","FUNNIGUY","BUGHAPPY","FODDERMAN","MESSIFUL","GOOSEPEN"]]
+["2452",["BIGHEAD","ORELLY","BIGHORN","SMITH","CHERRY"]]
+SELECT Bson_Make_Object(DEPARTMENT, Bson_Array_Grp(NAME) json_NAMES) FROM t3 GROUP BY DEPARTMENT;
+Bson_Make_Object(DEPARTMENT, Bson_Array_Grp(NAME) json_NAMES)
+{"DEPARTMENT":"0021","NAMES":["STRONG","SHORTSIGHT"]}
+{"DEPARTMENT":"0318","NAMES":["BANCROFT","PLUMHEAD","HONEY","TONGHO","WALTER","SHRINKY","WERTHER","MERCHANT","WHEELFOR"]}
+{"DEPARTMENT":"0319","NAMES":["BULLOZER","QUINN","BROWNY","KITTY","MONAPENNY","MARTIN","FUNNIGUY","BUGHAPPY","FODDERMAN","MESSIFUL","GOOSEPEN"]}
+{"DEPARTMENT":"2452","NAMES":["BIGHEAD","ORELLY","BIGHORN","SMITH","CHERRY"]}
+SELECT Bson_Make_Object(DEPARTMENT, Bson_Array_Grp(Bson_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT;
+Bson_Make_Object(DEPARTMENT, Bson_Array_Grp(Bson_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES)
+{"DEPARTMENT":"0021","EMPLOYES":[{"SERIALNO":"87777","NAME":"STRONG","TITLE":"DIRECTOR","SALARY":23000.00},{"SERIALNO":"22222","NAME":"SHORTSIGHT","TITLE":"SECRETARY","SALARY":5500.00}]}
+{"DEPARTMENT":"0318","EMPLOYES":[{"SERIALNO":"74200","NAME":"BANCROFT","TITLE":"SALESMAN","SALARY":9600.00},{"SERIALNO":"24888","NAME":"PLUMHEAD","TITLE":"TYPIST","SALARY":2800.00},{"SERIALNO":"27845","NAME":"HONEY","TITLE":"SECRETARY","SALARY":4900.00},{"SERIALNO":"73452","NAME":"TONGHO","TITLE":"ENGINEER","SALARY":6800.00},{"SERIALNO":"74234","NAME":"WALTER","TITLE":"ENGINEER","SALARY":7400.00},{"SERIALNO":"77777","NAME":"SHRINKY","TITLE":"ADMINISTRATOR","SALARY":7500.00},{"SERIALNO":"70012","NAME":"WERTHER","TITLE":"DIRECTOR","SALARY":14500.00},{"SERIALNO":"78943","NAME":"MERCHANT","TITLE":"SALESMAN","SALARY":8700.00},{"SERIALNO":"73111","NAME":"WHEELFOR","TITLE":"SALESMAN","SALARY":10030.00}]}
+{"DEPARTMENT":"0319","EMPLOYES":[{"SERIALNO":"76543","NAME":"BULLOZER","TITLE":"SALESMAN","SALARY":14800.00},{"SERIALNO":"40567","NAME":"QUINN","TITLE":"DIRECTOR","SALARY":14000.00},{"SERIALNO":"00137","NAME":"BROWNY","TITLE":"ENGINEER","SALARY":10500.00},{"SERIALNO":"12345","NAME":"KITTY","TITLE":"TYPIST","SALARY":3000.45},{"SERIALNO":"33333","NAME":"MONAPENNY","TITLE":"SECRETARY","SALARY":3800.00},{"SERIALNO":"00023","NAME":"MARTIN","TITLE":"ENGINEER","SALARY":10000.00},{"SERIALNO":"07654","NAME":"FUNNIGUY","TITLE":"ADMINISTRATOR","SALARY":8500.00},{"SERIALNO":"45678","NAME":"BUGHAPPY","TITLE":"PROGRAMMER","SALARY":8500.00},{"SERIALNO":"56789","NAME":"FODDERMAN","TITLE":"SALESMAN","SALARY":7000.00},{"SERIALNO":"55555","NAME":"MESSIFUL","TITLE":"SECRETARY","SALARY":5000.50},{"SERIALNO":"98765","NAME":"GOOSEPEN","TITLE":"ADMINISTRATOR","SALARY":4700.00}]}
+{"DEPARTMENT":"2452","EMPLOYES":[{"SERIALNO":"34567","NAME":"BIGHEAD","TITLE":"SCIENTIST","SALARY":8000.00},{"SERIALNO":"31416","NAME":"ORELLY","TITLE":"ENGINEER","SALARY":13400.00},{"SERIALNO":"36666","NAME":"BIGHORN","TITLE":"SCIENTIST","SALARY":11000.00},{"SERIALNO":"02345","NAME":"SMITH","TITLE":"ENGINEER","SALARY":9000.00},{"SERIALNO":"11111","NAME":"CHERRY","TITLE":"SECRETARY","SALARY":4500.00}]}
+SELECT Bson_Make_Object(DEPARTMENT, TITLE, Bson_Array_Grp(Bson_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT, TITLE;
+Bson_Make_Object(DEPARTMENT, TITLE, Bson_Array_Grp(Bson_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES)
+{"DEPARTMENT":"0021","TITLE":"DIRECTOR","EMPLOYES":[{"SERIALNO":"87777","NAME":"STRONG","SALARY":23000.00}]}
+{"DEPARTMENT":"0021","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"22222","NAME":"SHORTSIGHT","SALARY":5500.00}]}
+{"DEPARTMENT":"0318","TITLE":"ADMINISTRATOR","EMPLOYES":[{"SERIALNO":"77777","NAME":"SHRINKY","SALARY":7500.00}]}
+{"DEPARTMENT":"0318","TITLE":"DIRECTOR","EMPLOYES":[{"SERIALNO":"70012","NAME":"WERTHER","SALARY":14500.00}]}
+{"DEPARTMENT":"0318","TITLE":"ENGINEER","EMPLOYES":[{"SERIALNO":"73452","NAME":"TONGHO","SALARY":6800.00},{"SERIALNO":"74234","NAME":"WALTER","SALARY":7400.00}]}
+{"DEPARTMENT":"0318","TITLE":"SALESMAN","EMPLOYES":[{"SERIALNO":"74200","NAME":"BANCROFT","SALARY":9600.00},{"SERIALNO":"78943","NAME":"MERCHANT","SALARY":8700.00},{"SERIALNO":"73111","NAME":"WHEELFOR","SALARY":10030.00}]}
+{"DEPARTMENT":"0318","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"27845","NAME":"HONEY","SALARY":4900.00}]}
+{"DEPARTMENT":"0318","TITLE":"TYPIST","EMPLOYES":[{"SERIALNO":"24888","NAME":"PLUMHEAD","SALARY":2800.00}]}
+{"DEPARTMENT":"0319","TITLE":"ADMINISTRATOR","EMPLOYES":[{"SERIALNO":"98765","NAME":"GOOSEPEN","SALARY":4700.00},{"SERIALNO":"07654","NAME":"FUNNIGUY","SALARY":8500.00}]}
+{"DEPARTMENT":"0319","TITLE":"DIRECTOR","EMPLOYES":[{"SERIALNO":"40567","NAME":"QUINN","SALARY":14000.00}]}
+{"DEPARTMENT":"0319","TITLE":"ENGINEER","EMPLOYES":[{"SERIALNO":"00023","NAME":"MARTIN","SALARY":10000.00},{"SERIALNO":"00137","NAME":"BROWNY","SALARY":10500.00}]}
+{"DEPARTMENT":"0319","TITLE":"PROGRAMMER","EMPLOYES":[{"SERIALNO":"45678","NAME":"BUGHAPPY","SALARY":8500.00}]}
+{"DEPARTMENT":"0319","TITLE":"SALESMAN","EMPLOYES":[{"SERIALNO":"76543","NAME":"BULLOZER","SALARY":14800.00},{"SERIALNO":"56789","NAME":"FODDERMAN","SALARY":7000.00}]}
+{"DEPARTMENT":"0319","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"33333","NAME":"MONAPENNY","SALARY":3800.00},{"SERIALNO":"55555","NAME":"MESSIFUL","SALARY":5000.50}]}
+{"DEPARTMENT":"0319","TITLE":"TYPIST","EMPLOYES":[{"SERIALNO":"12345","NAME":"KITTY","SALARY":3000.45}]}
+{"DEPARTMENT":"2452","TITLE":"ENGINEER","EMPLOYES":[{"SERIALNO":"31416","NAME":"ORELLY","SALARY":13400.00},{"SERIALNO":"02345","NAME":"SMITH","SALARY":9000.00}]}
+{"DEPARTMENT":"2452","TITLE":"SCIENTIST","EMPLOYES":[{"SERIALNO":"34567","NAME":"BIGHEAD","SALARY":8000.00},{"SERIALNO":"36666","NAME":"BIGHORN","SALARY":11000.00}]}
+{"DEPARTMENT":"2452","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"11111","NAME":"CHERRY","SALARY":4500.00}]}
+SELECT Bson_Object_Grp(SALARY) FROM t3;
+ERROR HY000: Can't initialize function 'bson_object_grp'; This function requires 2 arguments (key, value)
+SELECT Bson_Object_Grp(NAME, SALARY) FROM t3;
+Bson_Object_Grp(NAME, SALARY)
+{"BANCROFT":9600.00,"SMITH":9000.00,"MERCHANT":8700.00,"FUNNIGUY":8500.00,"BUGHAPPY":8500.00,"BIGHEAD":8000.00,"SHRINKY":7500.00,"WALTER":7400.00,"FODDERMAN":7000.00,"TONGHO":6800.00,"SHORTSIGHT":5500.00,"MESSIFUL":5000.50,"HONEY":4900.00,"GOOSEPEN":4700.00,"CHERRY":4500.00,"MONAPENNY":3800.00,"KITTY":3000.45,"PLUMHEAD":2800.00,"STRONG":23000.00,"BULLOZER":14800.00,"WERTHER":14500.00,"QUINN":14000.00,"ORELLY":13400.00,"BIGHORN":11000.00,"BROWNY":10500.00,"WHEELFOR":10030.00,"MARTIN":10000.00}
+SELECT Bson_Make_Object(DEPARTMENT, Bson_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT;
+Bson_Make_Object(DEPARTMENT, Bson_Object_Grp(NAME, SALARY) "Json_SALARIES")
+{"DEPARTMENT":"0021","SALARIES":{"STRONG":23000.00,"SHORTSIGHT":5500.00}}
+{"DEPARTMENT":"0318","SALARIES":{"BANCROFT":9600.00,"PLUMHEAD":2800.00,"HONEY":4900.00,"TONGHO":6800.00,"WALTER":7400.00,"SHRINKY":7500.00,"WERTHER":14500.00,"MERCHANT":8700.00,"WHEELFOR":10030.00}}
+{"DEPARTMENT":"0319","SALARIES":{"BULLOZER":14800.00,"QUINN":14000.00,"BROWNY":10500.00,"KITTY":3000.45,"MONAPENNY":3800.00,"MARTIN":10000.00,"FUNNIGUY":8500.00,"BUGHAPPY":8500.00,"FODDERMAN":7000.00,"MESSIFUL":5000.50,"GOOSEPEN":4700.00}}
+{"DEPARTMENT":"2452","SALARIES":{"BIGHEAD":8000.00,"ORELLY":13400.00,"BIGHORN":11000.00,"SMITH":9000.00,"CHERRY":4500.00}}
+SELECT Bson_Array_Grp(NAME) FROM t3;
+Bson_Array_Grp(NAME)
+["BANCROFT","SMITH","MERCHANT","FUNNIGUY","BUGHAPPY","BIGHEAD","SHRINKY","WALTER","FODDERMAN","TONGHO","SHORTSIGHT","MESSIFUL","HONEY","GOOSEPEN","CHERRY","MONAPENNY","KITTY","PLUMHEAD","STRONG","BULLOZER","WERTHER","QUINN","ORELLY","BIGHORN","BROWNY","WHEELFOR","MARTIN"]
+SELECT Bson_Object_Key(name, title) FROM t3 WHERE DEPARTMENT = 318;
+Bson_Object_Key(name, title)
+{"BANCROFT":"SALESMAN"}
+{"MERCHANT":"SALESMAN"}
+{"SHRINKY":"ADMINISTRATOR"}
+{"WALTER":"ENGINEER"}
+{"TONGHO":"ENGINEER"}
+{"HONEY":"SECRETARY"}
+{"PLUMHEAD":"TYPIST"}
+{"WERTHER":"DIRECTOR"}
+{"WHEELFOR":"SALESMAN"}
+SELECT Bson_Object_Grp(name, title) FROM t3 WHERE DEPARTMENT = 318;
+Bson_Object_Grp(name, title)
+{"BANCROFT":"SALESMAN","MERCHANT":"SALESMAN","SHRINKY":"ADMINISTRATOR","WALTER":"ENGINEER","TONGHO":"ENGINEER","HONEY":"SECRETARY","PLUMHEAD":"TYPIST","WERTHER":"DIRECTOR","WHEELFOR":"SALESMAN"}
+#
+# Test value getting UDF's
+#
+SELECT BsonGet_String(Bson_Array_Grp(name),'[#]') FROM t3;
+BsonGet_String(Bson_Array_Grp(name),'[#]')
+27
+SELECT BsonGet_String(Bson_Array_Grp(name),'[","]') FROM t3;
+BsonGet_String(Bson_Array_Grp(name),'[","]')
+BANCROFT,SMITH,MERCHANT,FUNNIGUY,BUGHAPPY,BIGHEAD,SHRINKY,WALTER,FODDERMAN,TONGHO,SHORTSIGHT,MESSIFUL,HONEY,GOOSEPEN,CHERRY,MONAPENNY,KITTY,PLUMHEAD,STRONG,BULLOZER,WERTHER,QUINN,ORELLY,BIGHORN,BROWNY,WHEELFOR,MARTIN
+SELECT BsonGet_String(Bson_Array_Grp(name),'[>]') FROM t3;
+BsonGet_String(Bson_Array_Grp(name),'[>]')
+WHEELFOR
+SET @j1 = '[45,28,36,45,89]';
+SELECT BsonGet_String(@j1,'1');
+BsonGet_String(@j1,'1')
+28
+SELECT BsonGet_String(@j1 json_,'3');
+BsonGet_String(@j1 json_,'3')
+45
+SELECT BsonGet_String(Bson_Make_Array(45,28,36,45,89),'3');
+BsonGet_String(Bson_Make_Array(45,28,36,45,89),'3')
+45
+SELECT BsonGet_String(Bson_Make_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",BsonGet_String(Bson_Make_Array(45,28,36,45,89),'[+]') "sum";
+list egal sum
+45+28+36+45+89 = 243
+SELECT BsonGet_String(Bson_Make_Array(Bson_Make_Array(45,28),Bson_Make_Array(36,45,89)),'1.0');
+BsonGet_String(Bson_Make_Array(Bson_Make_Array(45,28),Bson_Make_Array(36,45,89)),'1.0')
+36
+SELECT BsonGet_String(Bson_Make_Array(Bson_Make_Array(45,28),Bson_Make_Array(36,45,89)),'1.*');
+BsonGet_String(Bson_Make_Array(Bson_Make_Array(45,28),Bson_Make_Array(36,45,89)),'1.*')
+[36,45,89]
+SELECT BsonGet_String(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc');
+BsonGet_String(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc')
+machin
+SET @j2 = '{"qty":56,"price":3.141600,"truc":"machin","garanty":null}';
+SELECT BsonGet_String(@j2 json_,'truc');
+BsonGet_String(@j2 json_,'truc')
+machin
+SELECT BsonGet_String(@j2,'truc');
+BsonGet_String(@j2,'truc')
+machin
+SELECT BsonGet_String(@j2,'chose');
+BsonGet_String(@j2,'chose')
+NULL
+SELECT BsonGet_String(NULL json_, NULL);
+BsonGet_String(NULL json_, NULL)
+NULL
+Warnings:
+Warning 1105
+/* NULL WARNING */
+SELECT department, BsonGet_String(Bson_Make_Object(department, Bson_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+department Sumsal
+0021 28500.00
+0318 72230.00
+0319 89800.95
+2452 45900.00
+SELECT BsonGet_Int(@j1, '4');
+BsonGet_Int(@j1, '4')
+89
+SELECT BsonGet_Int(@j1, '[#]');
+BsonGet_Int(@j1, '[#]')
+5
+SELECT BsonGet_Int(@j1, '[+]');
+BsonGet_Int(@j1, '[+]')
+243
+SELECT BsonGet_Int(@j1 json_, '3');
+BsonGet_Int(@j1 json_, '3')
+45
+SELECT BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '3');
+BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '3')
+45
+SELECT BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '["+"]');
+BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '["+"]')
+45
+SELECT BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '[+]');
+BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '[+]')
+243
+SELECT BsonGet_Int(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '1.0');
+BsonGet_Int(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '1.0')
+36
+SELECT BsonGet_Int(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '0.1');
+BsonGet_Int(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '0.1')
+28
+SELECT BsonGet_Int(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty');
+BsonGet_Int(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty')
+56
+SELECT BsonGet_Int(@j2 json_, 'price');
+BsonGet_Int(@j2 json_, 'price')
+3
+SELECT BsonGet_Int(@j2, 'qty');
+BsonGet_Int(@j2, 'qty')
+56
+SELECT BsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose');
+BsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose')
+NULL
+SELECT BsonGet_Int(BsonGet_String(Bson_Make_Array(Bson_Make_Array(45,28),Bson_Make_Array(36,45,89)), '1.*'), '[+]') sum;
+sum
+170
+SELECT department, BsonGet_Int(Bson_Make_Object(department, Bson_Array_Grp(salary) "Json_salaries"), 'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+department Sumsal
+0021 28500
+0318 72230
+0319 89800
+2452 45900
+SELECT BsonGet_Real(@j1, '2');
+BsonGet_Real(@j1, '2')
+36.000000000000000
+SELECT BsonGet_Real(@j1 json_, '3', 2);
+BsonGet_Real(@j1 json_, '3', 2)
+45.00
+SELECT BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '3');
+BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '3')
+45.000000000000000
+SELECT BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '["+"]');
+BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '["+"]')
+45.000000000000000
+SELECT BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '[+]');
+BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '[+]')
+243.000000000000000
+SELECT BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '[!]');
+BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '[!]')
+48.600000000000000
+SELECT BsonGet_Real(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '1.0');
+BsonGet_Real(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '1.0')
+36.000000000000000
+SELECT BsonGet_Real(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price');
+BsonGet_Real(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price')
+3.141600000000000
+SELECT BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty');
+BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty')
+56.000000000000000
+SELECT BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price');
+BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price')
+3.141600000000000
+SELECT BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price', 4);
+BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price', 4)
+3.1416
+SELECT BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose');
+BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose')
+NULL
+SELECT department, BsonGet_Real(Bson_Make_Object(department, Bson_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+department Sumsal
+0021 28500.000000000000000
+0318 72230.000000000000000
+0319 89800.950000000000000
+2452 45900.000000000000000
+#
+# Documentation examples
+#
+SELECT
+BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '4') "Rank",
+BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '[#]') "Number",
+BsonGet_String(Bson_Make_Array(45,28,36,45,89), '[","]') "Concat",
+BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '[+]') "Sum",
+BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '[!]', 2) "Avg";
+Rank Number Concat Sum Avg
+89 5 45,28,36,45,89 243 48.60
+SELECT
+BsonGet_String('{"qty":7,"price":29.50,"garanty":null}', 'price') "String",
+BsonGet_Int('{"qty":7,"price":29.50,"garanty":null}', 'price') "Int",
+BsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price') "Real";
+String Int Real
+29.50 29 29.500000000000000
+SELECT BsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price', 3) "Real";
+Real
+29.500
+#
+# Testing Locate
+#
+SELECT BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin');
+BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin')
+$.truc
+SELECT BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56);
+BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56)
+$.qty
+SELECT BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416);
+BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416)
+$.price
+SELECT BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose');
+BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose')
+NULL
+SELECT BsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'Jack') Path;
+Path
+$.AUTHORS[1].FN
+SELECT BsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'jack' ci) Path;
+Path
+$.AUTHORS[1].FN
+SELECT BsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"Jack", "LN":"London"}' json_) Path;
+Path
+$.AUTHORS[1]
+SELECT BsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"jack", "LN":"London"}' json_) Path;
+Path
+NULL
+SELECT BsonLocate('[45,28,36,45,89]',36);
+BsonLocate('[45,28,36,45,89]',36)
+$[2]
+SELECT BsonLocate('[45,28,36,45,89]' json_,28.0);
+BsonLocate('[45,28,36,45,89]' json_,28.0)
+NULL
+SELECT Bson_Locate_All('[45,28,36,45,89]',10);
+Bson_Locate_All('[45,28,36,45,89]',10)
+[]
+SELECT Bson_Locate_All('[45,28,36,45,89]',45);
+Bson_Locate_All('[45,28,36,45,89]',45)
+["$[0]","$[3]"]
+SELECT Bson_Locate_All('[[45,28],36,45,89]',45);
+Bson_Locate_All('[[45,28],36,45,89]',45)
+["$[0][0]","$[2]"]
+SELECT Bson_Locate_All('[[45,28,45],36,45,89]',45);
+Bson_Locate_All('[[45,28,45],36,45,89]',45)
+["$[0][0]","$[0][2]","$[2]"]
+SELECT Bson_Locate_All('[[45,28,45],36,45,89]',BsonGet_Int('[3,45]','[1]'));
+Bson_Locate_All('[[45,28,45],36,45,89]',BsonGet_Int('[3,45]','[1]'))
+["$[0][0]","$[0][2]","$[2]"]
+SELECT BsonLocate('[[45,28,45],36,45,89]',45,n) from t1;
+BsonLocate('[[45,28,45],36,45,89]',45,n)
+$[0][0]
+$[0][2]
+$[2]
+NULL
+NULL
+SELECT BsonGet_String(Bson_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) FROM t1;
+BsonGet_String(Bson_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']'))
+$[0][0]
+$[0][2]
+$[2]
+NULL
+NULL
+SELECT BsonGet_String(Bson_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) AS `Path` FROM t1 GROUP BY n HAVING `Path` IS NOT NULL;
+Path
+$[0][0]
+$[0][2]
+$[2]
+SELECT Bson_Locate_All('[45,28,[36,45,89]]',45);
+Bson_Locate_All('[45,28,[36,45,89]]',45)
+["$[0]","$[2][1]"]
+SELECT Bson_Locate_All('[[45,28],[36,45.0,89]]',BsonValue(45.0));
+Bson_Locate_All('[[45,28],[36,45.0,89]]',BsonValue(45.0))
+[]
+SELECT Bson_Locate_All('[[45,28],[36,45.0,89]]',45.0);
+Bson_Locate_All('[[45,28],[36,45.0,89]]',45.0)
+["$[1][1]"]
+SELECT BsonLocate('[[45,28],[36,45,89]]','[36,45,89]' json_);
+BsonLocate('[[45,28],[36,45,89]]','[36,45,89]' json_)
+$[1]
+SELECT BsonLocate('[[45,28],[36,45,89]]','[45,28]' json_);
+BsonLocate('[[45,28],[36,45,89]]','[45,28]' json_)
+$[0]
+SELECT Bson_Locate_All('[[45,28],[[36,45],89]]','45') "All paths";
+All paths
+[]
+SELECT Bson_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_);
+Bson_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_)
+["$[1][0]"]
+SELECT BsonGet_Int(Bson_Locate_All('[[45,28],[[36,45],89]]',45), '[#]') "Nb of occurs";
+Nb of occurs
+2
+SELECT Bson_Locate_All('[[45,28],[[36,45],89]]',45,2);
+Bson_Locate_All('[[45,28],[[36,45],89]]',45,2)
+["$[0][0]"]
+SELECT BsonGet_String(Bson_Locate_All('[45,28,36,45,89]',45),'0');
+BsonGet_String(Bson_Locate_All('[45,28,36,45,89]',45),'0')
+$[0]
+SELECT BsonLocate(Bson_File('test/biblio.json'), 'Knab');
+BsonLocate(Bson_File('test/biblio.json'), 'Knab')
+$[0].AUTHOR[1].LASTNAME
+SELECT Bson_Locate_All('test/biblio.json' jfile_, 'Knab');
+Bson_Locate_All('test/biblio.json' jfile_, 'Knab')
+["$[0].AUTHOR[1].LASTNAME"]
+#
+# Testing json files
+#
+SELECT Bfile_Make('[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},
+{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},
+{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]', 'test/fx.json', 0) AS NewFile;
+NewFile
+test/fx.json
+SELECT Bfile_Make('test/fx.json', 1);
+Bfile_Make('test/fx.json', 1)
+test/fx.json
+SELECT Bfile_Make('test/fx.json' jfile_);
+Bfile_Make('test/fx.json' jfile_)
+test/fx.json
+SELECT Bfile_Make(Bbin_File('test/fx.json'), 0);
+Bfile_Make(Bbin_File('test/fx.json'), 0)
+test/fx.json
+SELECT Bson_File('test/fx.json', 1);
+Bson_File('test/fx.json', 1)
+[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]
+Warnings:
+Warning 1105 File pretty format doesn't match the specified pretty value
+SELECT Bson_File('test/fx.json', 2);
+Bson_File('test/fx.json', 2)
+[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]
+Warnings:
+Warning 1105 File pretty format doesn't match the specified pretty value
+SELECT Bson_File('test/fx.json', 0);
+Bson_File('test/fx.json', 0)
+[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]
+SELECT Bson_File('test/fx.json', '0');
+Bson_File('test/fx.json', '0')
+{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]}
+SELECT Bson_File('test/fx.json', '[?]');
+Bson_File('test/fx.json', '[?]')
+NULL
+Warnings:
+Warning 1105 Invalid function specification ?
+SELECT BsonGet_String(Bson_File('test/fx.json'), '1.*');
+BsonGet_String(Bson_File('test/fx.json'), '1.*')
+{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]}
+SELECT BsonGet_String(Bson_File('test/fx.json'), '1');
+BsonGet_String(Bson_File('test/fx.json'), '1')
+6 car roadster 56000 (6, 9)
+SELECT BsonGet_Int(Bson_File('test/fx.json'), '1.mileage') AS Mileage;
+Mileage
+56000
+SELECT BsonGet_Real(Bson_File('test/fx.json'), '0.price', 2) AS Price;
+Price
+5.65
+SELECT Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 'ratings');
+Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 'ratings')
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4,6]}
+SELECT Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 1, 'ratings');
+Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 1, 'ratings')
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,6,4]}
+SELECT Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 'ratings', 1);
+Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 'ratings', 1)
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,6,4]}
+SELECT Bson_Array_Add(Bson_File('test/fx.json', '2.ratings'), 6, 0);
+Bson_Array_Add(Bson_File('test/fx.json', '2.ratings'), 6, 0)
+[6,2,4]
+SELECT Bson_Array_Delete(Bson_File('test/fx.json', '2'), 'ratings', 1);
+Bson_Array_Delete(Bson_File('test/fx.json', '2'), 'ratings', 1)
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2]}
+SELECT Bson_Object_Add(Bson_File('test/fx.json', '2'), 'france' origin);
+Bson_Object_Add(Bson_File('test/fx.json', '2'), 'france' origin)
+{"_id":7,"type":"food","item":"meat","origin":"france","ratings":[2,4]}
+SELECT Bson_Object_Add(Bson_File('test/fx.json', '2'), 70 H, 'size');
+Bson_Object_Add(Bson_File('test/fx.json', '2'), 70 H, 'size')
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]}
+Warnings:
+Warning 1105 No sub-item at 'size'
+SELECT Bson_Object_Add(Bson_File('test/fx.json', '3'), 70 H, 'size');
+Bson_Object_Add(Bson_File('test/fx.json', '3'), 70 H, 'size')
+{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":70},"ratings":[5,8,7]}
+SELECT Bson_Object_List(Bson_File('test/fx.json', '3.size'));
+Bson_Object_List(Bson_File('test/fx.json', '3.size'))
+["W","L","H"]
+#
+# Testing new functions
+#
+SELECT Bson_Item_Merge('["a","b","c"]','["d","e","f"]') as "Result";
+Result
+["a","b","c","d","e","f"]
+SELECT Bson_Item_Merge(Bson_Make_Array('a','b','c'), Bson_Make_Array('d','e','f')) as "Result";
+Result
+["a","b","c","d","e","f"]
+SELECT
+Bson_Set_Item('[1,2,3,{"quatre":4}]', 'foo', '$[1]', 5, '$[3].cinq') as "Set",
+Bson_Insert_Item('[1,2,3,{"quatre":4}]', 'foo', '$[1]', 5, '$[3].cinq') as "Insert",
+Bson_Update_Item(Bson_Make_Array(1,2,3,Bson_Object_Key('quatre',4)),'foo','$[1]',5,'$[3].cinq') "Update";
+Set Insert Update
+[1,"foo",3,{"quatre":4,"cinq":5}] [1,2,3,{"quatre":4,"cinq":5}] [1,"foo",3,{"quatre":4}]
+SELECT bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','1','[2].Deux');
+bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','1','[2].Deux')
+[1,3,{"quatre":4}]
+SELECT bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','["[1]","[3].Deux"]');
+bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','["[1]","[3].Deux"]')
+[1,3,{"quatre":4}]
+SELECT bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','$.[3].Deux');
+bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','$.[3].Deux')
+[1,2,3,{"quatre":4}]
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+SELECT BsonSet_Grp_Size(10);
+BsonSet_Grp_Size(10)
+10
diff --git a/storage/connect/mysql-test/connect/r/csv.result b/storage/connect/mysql-test/connect/r/csv.result
new file mode 100644
index 00000000..be25a842
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/csv.result
@@ -0,0 +1,221 @@
+SET NAMES utf8;
+#
+# Testing errors
+#
+CREATE TABLE t1
+(
+ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=CSV FILE_NAME='nonexistent.txt';
+SELECT * FROM t1;
+ID
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/nonexistent.txt: No such file or directory
+DROP TABLE t1;
+#
+# Testing examples from the manual
+#
+CREATE TABLE t1
+(
+name CHAR(12) NOT NULL,
+birth DATE NOT NULL DATE_FORMAT='DD/MM/YY',
+children SMALLINT(2) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
+ HEADER=1 SEP_CHAR=';' QUOTED=1;
+SELECT * FROM t1;
+name birth children
+Archibald 2001-05-17 3
+Nabucho 2003-08-12 2
+INSERT INTO t1 VALUES ('RONALD','1980-02-26',4);
+SELECT * FROM t1;
+name birth children
+Archibald 2001-05-17 3
+Nabucho 2003-08-12 2
+RONALD 1980-02-26 4
+DROP TABLE t1;
+SELECT REPLACE(LOAD_FILE('DATADIR/test/people.csv'),'\r\n','\n');;
+REPLACE(LOAD_FILE('DATADIR/test/people.csv'),'\r\n','\n')
+Name;birth;children
+"Archibald";17/05/01;3
+"Nabucho";12/08/03;2
+"RONALD";26/02/80;4
+
+#
+# Testing READONLY tables
+#
+CREATE TABLE t1
+(
+name CHAR(12) NOT NULL,
+birth DATE NOT NULL DATE_FORMAT='DD/MM/YY',
+children SMALLINT(2) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
+ HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+ERROR HY000: Table 't1' is read only
+UPDATE t1 SET children=6 WHERE name='BILL';
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+DELETE FROM t1 WHERE name='BILL';
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+TRUNCATE TABLE t1;
+ERROR HY000: Table 't1' is read only
+SELECT * FROM t1;
+name birth children
+Archibald 2001-05-17 3
+Nabucho 2003-08-12 2
+RONALD 1980-02-26 4
+ALTER TABLE t1 READONLY=no;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `name` char(12) NOT NULL,
+ `birth` date NOT NULL `DATE_FORMAT`='DD/MM/YY',
+ `children` smallint(2) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=CSV `FILE_NAME`='people.csv' `HEADER`=1 `SEP_CHAR`=';' `QUOTED`=1 `READONLY`=no
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+SELECT * FROM t1;
+name birth children
+Archibald 2001-05-17 3
+Nabucho 2003-08-12 2
+RONALD 1980-02-26 4
+BILL 1973-06-30 5
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `name` char(12) NOT NULL,
+ `birth` date NOT NULL `DATE_FORMAT`='DD/MM/YY',
+ `children` smallint(2) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=CSV `FILE_NAME`='people.csv' `HEADER`=1 `SEP_CHAR`=';' `QUOTED`=1 `READONLY`=1
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+ERROR HY000: Table 't1' is read only
+SELECT * FROM t1;
+name birth children
+Archibald 2001-05-17 3
+Nabucho 2003-08-12 2
+RONALD 1980-02-26 4
+BILL 1973-06-30 5
+DROP TABLE t1;
+#
+# Testing that the underlying file is created
+#
+CREATE TABLE t1
+(
+c1 CHAR(12) NOT NULL,
+c2 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='tmp.csv'
+ HEADER=1 SEP_CHAR=',' QUOTED=1;
+INSERT INTO t1 VALUES (10,10),(20,20),(300,300),(4000,4000), ('a b','c d');
+SELECT * FROM t1;
+c1 c2
+10 10
+20 20
+300 300
+4000 4000
+a b c d
+DROP TABLE t1;
+SELECT REPLACE(LOAD_FILE('DATADIR/test/tmp.csv'),'\r\n','\n');;
+REPLACE(LOAD_FILE('DATADIR/test/tmp.csv'),'\r\n','\n')
+"c1","c2"
+"10","10"
+"20","20"
+"300","300"
+"4000","4000"
+"a b","c d"
+
+#
+# Creating a CSV table from a MyISAM table
+#
+CREATE TABLE t1 (a VARCHAR(10) NOT NULL, b INT NOT NULL) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('test1',1), ('test2',2);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t2.csv'
+ AS SELECT * FROM t1;
+SELECT * FROM t2;
+a b
+test1 1
+test2 2
+DROP TABLE t2;
+DROP TABLE t1;
+SELECT REPLACE(LOAD_FILE('DATADIR/test/t2.csv'),'\r\n','\n');;
+REPLACE(LOAD_FILE('DATADIR/test/t2.csv'),'\r\n','\n')
+test1,1
+test2,2
+
+#
+# Testing international data
+#
+CREATE TABLE t1
+(
+c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=utf8;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+c1
+á
+DROP TABLE t1;
+SELECT HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'));;
+HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'))
+C3A10A
+CREATE TABLE t1
+(
+c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=utf8 DATA_CHARSET=latin1;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+c1
+á
+DROP TABLE t1;
+SELECT HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'));;
+HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'))
+E10A
+CREATE TABLE t1
+(
+c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv';
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+c1
+á
+DROP TABLE t1;
+SELECT HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'));;
+HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'))
+E10A
+CREATE TABLE t1
+(
+c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=latin1;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+c1
+á
+DROP TABLE t1;
+SELECT HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'));;
+HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'))
+E10A
+CREATE TABLE t1
+(
+c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=latin1 DATA_CHARSET=utf8;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+c1
+á
+DROP TABLE t1;
+SELECT HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'));;
+HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'))
+C3A10A
+CREATE TABLE t1
+(
+c1 CHAR(12) CHARACTER SET latin1 NOT NULL,
+c2 CHAR(12) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv';
+INSERT INTO t1 VALUES ('á','á');
+SELECT * FROM t1;
+c1 c2
+á á
+DROP TABLE t1;
+SELECT HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'));;
+HEX(REPLACE(LOAD_FILE('DATADIR/test/t1.csv'),'\r\n','\n'))
+E12CC3A10A
diff --git a/storage/connect/mysql-test/connect/r/datest.result b/storage/connect/mysql-test/connect/r/datest.result
new file mode 100644
index 00000000..586741f0
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/datest.result
@@ -0,0 +1,59 @@
+#
+# Testing out of range dates as (var)char
+#
+CREATE TABLE t1 (
+id INT NOT NULL,
+dat CHAR(10) NOT NULL,
+tim CHAR(8) DEFAULT '09:35:08',
+datim CHAR(19) DEFAULT '1789-08-10 14:20:30')
+ENGINE=CONNECT TABLE_TYPE=FIX;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+INSERT INTO t1(id,dat) VALUES(1,'1515-04-01'),(2,'2014-07-26'),(3,'2118-11-02');
+SELECT * FROM t1;
+id dat tim datim
+1 1515-04-01 09:35:08 1789-08-10 14:20:30
+2 2014-07-26 09:35:08 1789-08-10 14:20:30
+3 2118-11-02 09:35:08 1789-08-10 14:20:30
+SELECT id, DATE(datim) FROM t1 LIMIT 1;
+id DATE(datim)
+1 1789-08-10
+SELECT id, DAYNAME(dat) FROM t1;
+id DAYNAME(dat)
+1 Thursday
+2 Saturday
+3 Wednesday
+SELECT id, DAYNAME(datim) FROM t1 LIMIT 1;
+id DAYNAME(datim)
+1 Monday
+SELECT id, TIME(tim) FROM t1 LIMIT 1;
+id TIME(tim)
+1 09:35:08.000000
+DROP TABLE t1;
+#
+# Testing use of dates in where clause (MDEV-8926)
+#
+CREATE TABLE t1 (col1 DATE) ENGINE=CONNECT TABLE_TYPE=CSV;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+INSERT INTO t1 VALUES('2015-01-01'),('2015-02-01'),('2015-03-01'),('2015-04-01');
+SELECT * FROM t1 WHERE col1 = '2015-02-01';
+col1
+2015-02-01
+SELECT * FROM t1 WHERE col1 > '2015-02-01';
+col1
+2015-03-01
+2015-04-01
+SELECT * FROM t1 WHERE col1 >= '2015-02-01';
+col1
+2015-02-01
+2015-03-01
+2015-04-01
+SELECT * FROM t1 WHERE col1 < '2015-02-01';
+col1
+2015-01-01
+SELECT * FROM t1 WHERE col1 <= '2015-02-01';
+col1
+2015-01-01
+2015-02-01
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/dbf.result b/storage/connect/mysql-test/connect/r/dbf.result
new file mode 100644
index 00000000..d7b3fe0f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/dbf.result
@@ -0,0 +1,649 @@
+#
+# Testing errors
+#
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf'
+SELECT * FROM t1;
+a
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/t1.dbf: No such file or directory
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR HY000: Cannot open DATADIR/test/t1.dbf
+SHOW WARNINGS;
+Level Code Message
+Error 1105 Cannot open DATADIR/test/t1.dbf
+Error 1030 Got error 122 "Internal (unspecified) error in handler" from storage engine CONNECT
+CREATE PROCEDURE test.dbf_field(in fieldno INT, in content BLOB) DETERMINISTIC
+BEGIN
+SELECT '---';
+SELECT fieldno AS `FieldN`;
+SELECT TRIM(TRAILING 0x00 FROM LEFT(content, 10)) AS `Name`;
+SELECT SUBSTRING(content, 12, 1) AS `Type`;
+SELECT CONV(HEX(REVERSE(SUBSTRING(content,13,4))),16,10) AS `Offset`;
+SELECT CONV(HEX(REVERSE(SUBSTRING(content,17,1))),16,10) AS `Length`;
+SELECT CONV(HEX(REVERSE(SUBSTRING(content,18,1))),16,10) AS `Dec`;
+SELECT HEX(REVERSE(SUBSTRING(content,19,1))) AS `Flags`;
+-- SELECT CONV(HEX(REVERSE(SUBSTRING(content,20,4))),16,10) AS `Next`;
+-- SELECT CONV(HEX(REVERSE(SUBSTRING(content,24,4))),16,10) AS `Step`;
+END//
+CREATE PROCEDURE test.dbf_header(in fname VARCHAR(1024)) DETERMINISTIC
+BEGIN
+DECLARE content BLOB;
+DECLARE offset INT;
+DECLARE fieldno INT;
+SELECT '--------';
+SELECT LOAD_FILE(fname) INTO content;
+SELECT LENGTH(content) AS FileSize;
+SELECT HEX(LEFT(content, 1)) AS DBF_Version;
+SELECT CONV(HEX(REVERSE(SUBSTRING(content,5,4))),16,10) AS NRecords;
+SELECT CONV(HEX(REVERSE(SUBSTRING(content,9,2))),16,10) AS FirstRecPos;
+SELECT CONV(HEX(REVERSE(SUBSTRING(content,11,2))),16,10) AS RecLength;
+SELECT HEX(REVERSE(SUBSTRING(content,29,2))) AS TableFlags;
+SELECT HEX(REVERSE(SUBSTRING(content,30,1))) AS CodePageMark;
+SET offset=33;
+SET fieldno=0;
+WHILE SUBSTR(content, offset, 1) <> 0x0D AND offset + 32 < LENGTH(content) DO
+CALL dbf_field(fieldno, SUBSTRING(content, offset, 32));
+SET offset=offset + 32;
+SET fieldno=fieldno + 1;
+END WHILE;
+SELECT '--------';
+END//
+#
+# Testing READONLY tables
+#
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf'
+INSERT INTO t1 VALUES (10),(20);
+SELECT * FROM t1;
+a
+10
+20
+ALTER TABLE t1 READONLY=Yes;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf' `READONLY`=Yes
+INSERT INTO t1 VALUES (30);
+ERROR HY000: Table 't1' is read only
+UPDATE t1 SET a=30 WHERE a=10;
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+DELETE FROM t1 WHERE a=10;
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+TRUNCATE TABLE t1;
+ERROR HY000: Table 't1' is read only
+ALTER TABLE t1 READONLY=NO;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1.dbf' `READONLY`=NO
+INSERT INTO t1 VALUES (30);
+SELECT * FROM t1;
+a
+10
+20
+30
+DROP TABLE t1;
+#
+# This SQL script crashed (dbf01.sql)
+#
+CREATE TABLE t1
+(
+a int(11) NOT NULL,
+b char(10) NOT NULL,
+c varchar(10) NOT NULL
+) ENGINE=CONNECT table_type=DBF file_name='t1.dbf';
+INSERT INTO t1 VALUES (1,'1','1');
+INSERT INTO t1 VALUES (2,'2','2');
+SELECT * FROM t1;
+a b c
+1 1 1
+2 2 2
+DROP TABLE t1;
+#
+# Testing that table options in lower case and mixed case are understood:
+#
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT table_type=dbf file_name='t1.dbf';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=dbf `file_name`='t1.dbf'
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+DROP TABLE t1;
+CREATE TABLE t1 (a CHAR(10) NOT NULL) ENGINE=CONNECT Table_Type=dbf File_Name='t1.dbf';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `Table_Type`=dbf `File_Name`='t1.dbf'
+INSERT INTO t1 VALUES ('test');
+SELECT * FROM t1;
+a
+test
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 77
+DBF_Version 03
+NRecords 1
+FirstRecPos 66
+RecLength 11
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type C
+Offset 0
+Length 10
+Dec 0
+Flags 00
+-------- --------
+DROP TABLE t1;
+#
+# Testing multiple columns
+#
+CREATE TABLE t1
+(
+a INT NOT NULL,
+b CHAR(10) NOT NULL,
+c VARCHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (1,'1','1');
+INSERT INTO t1 VALUES (2,'2','2');
+SELECT * FROM t1;
+a b c
+1 1 1
+2 2 2
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 194
+DBF_Version 03
+NRecords 2
+FirstRecPos 130
+RecLength 32
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type N
+Offset 0
+Length 11
+Dec 0
+Flags 00
+--- ---
+FieldN 1
+Name b
+Type C
+Offset 0
+Length 10
+Dec 0
+Flags 00
+--- ---
+FieldN 2
+Name c
+Type C
+Offset 0
+Length 10
+Dec 0
+Flags 00
+-------- --------
+DROP TABLE t1;
+#
+# Testing long column name
+#
+CREATE TABLE t1
+(
+a012345678901234567890123456789 INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR HY000: DBF: Column name 'a012345678901234567890123456789' is too long (max=10)
+#
+# Testing 2 columns with long names (12)
+#
+CREATE TABLE t1
+(
+a0123456789a INT NOT NULL,
+b0123456789b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x11.dbf';
+ERROR HY000: DBF: Column name 'a0123456789a' is too long (max=10)
+#
+# Testing 2 columns with long names (11)
+#
+CREATE TABLE t1
+(
+a012345678a INT NOT NULL,
+b012345678b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x12.dbf';
+ERROR HY000: DBF: Column name 'a012345678a' is too long (max=10)
+#
+# Testing 2 columns name length 10 (maximum possible length)
+#
+CREATE TABLE t1
+(
+a01234567a INT NOT NULL,
+b01234567b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x13.dbf';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a01234567a` int(11) NOT NULL,
+ `b01234567b` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t02x13.dbf'
+INSERT INTO t1 VALUES (1,2);
+SELECT * FROM t1;
+a01234567a b01234567b
+1 2
+DROP TABLE t1;
+#
+# Testing BIGINT
+#
+CREATE TABLE t1
+(
+a bigint NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (0x7FFFFFFFFFFFFFFF);
+INSERT INTO t1 VALUES (-0x8000000000000000);
+SELECT * FROM t1;
+a
+9223372036854775807
+-9223372036854775808
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 108
+DBF_Version 03
+NRecords 2
+FirstRecPos 66
+RecLength 21
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type N
+Offset 0
+Length 20
+Dec 0
+Flags 00
+-------- --------
+DROP TABLE t1;
+#
+# Testing TINYINT
+#
+CREATE TABLE t1
+(
+a TINYINT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+SELECT * FROM t1;
+a
+123
+DROP TABLE t1;
+#
+# Testing SMALLINT
+#
+CREATE TABLE t1
+(
+a SMALLINT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (0x7FFF);
+INSERT INTO t1 VALUES (-0x8000);
+SELECT * FROM t1;
+a
+32767
+-32768
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 80
+DBF_Version 03
+NRecords 2
+FirstRecPos 66
+RecLength 7
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type N
+Offset 0
+Length 6
+Dec 0
+Flags 00
+-------- --------
+DROP TABLE t1;
+#
+# Testing VARCHAR
+#
+CREATE TABLE t1
+(
+a VARCHAR(255) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (REPEAT('a',255));
+SELECT LENGTH(a) FROM t1;
+LENGTH(a)
+255
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 322
+DBF_Version 03
+NRecords 1
+FirstRecPos 66
+RecLength 256
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type C
+Offset 0
+Length 255
+Dec 0
+Flags 00
+-------- --------
+DROP TABLE t1;
+#
+# Testing too long CHAR
+# All columns longer than 255 bytes should be rejected
+#
+CREATE TABLE t1
+(
+a CHAR(86) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR HY000: DBF: Column length too big for 'a' (max=255)
+#
+# Testing too long VARCHAR
+# All columns longer than 255 bytes should be rejected
+#
+CREATE TABLE t1
+(
+a VARCHAR(256) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR HY000: DBF: Column length too big for 'a' (max=255)
+CREATE TABLE t1
+(
+a VARCHAR(86) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR HY000: DBF: Column length too big for 'a' (max=255)
+CREATE TABLE t1
+(
+a VARCHAR(64000) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR HY000: DBF: Column length too big for 'a' (max=255)
+#
+# Testing BLOB
+#
+CREATE TABLE t1
+(
+a BLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR 42000: Storage engine CONNECT doesn't support BLOB/TEXT columns
+CREATE TABLE t1
+(
+a TINYBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR 42000: Storage engine CONNECT doesn't support BLOB/TEXT columns
+CREATE TABLE t1
+(
+a MEDIUMBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR 42000: Storage engine CONNECT doesn't support BLOB/TEXT columns
+CREATE TABLE t1
+(
+a LONGBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+ERROR 42000: Storage engine CONNECT doesn't support BLOB/TEXT columns
+#
+# Testing DATE
+#
+CREATE TABLE t1
+(
+a DATE NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES ('2001-01-01');
+SELECT * FROM t1;
+a
+2001-01-01
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 75
+DBF_Version 03
+NRecords 1
+FirstRecPos 66
+RecLength 9
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type D
+Offset 0
+Length 8
+Dec 0
+Flags 00
+-------- --------
+DROP TABLE t1;
+#
+# Testing FLOAT
+#
+CREATE TABLE t1
+(
+a FLOAT(12,4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+SELECT * FROM t1;
+a
+123.0000
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 79
+DBF_Version 03
+NRecords 1
+FirstRecPos 66
+RecLength 13
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type F
+Offset 0
+Length 12
+Dec 4
+Flags 00
+-------- --------
+DROP TABLE t1;
+#
+# Testing double
+#
+CREATE TABLE t1
+(
+a DOUBLE(20,5) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+INSERT INTO t1 VALUES (123456789.12345);
+SELECT * FROM t1;
+a
+123.00000
+123456789.12345
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 108
+DBF_Version 03
+NRecords 2
+FirstRecPos 66
+RecLength 21
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type F
+Offset 0
+Length 20
+Dec 5
+Flags 00
+-------- --------
+DROP TABLE IF EXISTS t1;
+#
+# Testing ALTER
+#
+CREATE TABLE t1
+(
+a VARCHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1c.dbf';
+INSERT INTO t1 VALUES ('10');
+SELECT * FROM t1;
+a
+10
+CALL dbf_header('MYSQLD_DATADIR/test/t1c.dbf');
+-------- --------
+FileSize 77
+DBF_Version 03
+NRecords 1
+FirstRecPos 66
+RecLength 11
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type C
+Offset 0
+Length 10
+Dec 0
+Flags 00
+-------- --------
+ALTER TABLE t1 MODIFY a VARCHAR(10) NOT NULL;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1c.dbf'
+SELECT * FROM t1;
+a
+10
+CALL dbf_header('MYSQLD_DATADIR/test/t1c.dbf');
+-------- --------
+FileSize 77
+DBF_Version 03
+NRecords 1
+FirstRecPos 66
+RecLength 11
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type C
+Offset 0
+Length 10
+Dec 0
+Flags 00
+-------- --------
+ALTER TABLE t1 MODIFY a INT(10) NOT NULL;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DBF `FILE_NAME`='t1c.dbf'
+SELECT * FROM t1;
+a
+10
+CALL dbf_header('MYSQLD_DATADIR/test/t1c.dbf');
+-------- --------
+FileSize 77
+DBF_Version 03
+NRecords 1
+FirstRecPos 66
+RecLength 11
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name a
+Type C
+Offset 0
+Length 10
+Dec 0
+Flags 00
+-------- --------
+DROP TABLE IF EXISTS t1;
+#
+# Testing NULL
+#
+CREATE TABLE t1
+(
+c1 VARCHAR(10) NOT NULL,
+c2 VARCHAR(10) NOT NULL DEFAULT 'def',
+i1 INT NOT NULL,
+i2 INT NOT NULL DEFAULT 123
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES ('10','10',10,10);
+INSERT INTO t1(c1,i1) VALUES ('20',20);
+INSERT INTO t1 VALUES ('30',DEFAULT,30,DEFAULT);
+SELECT * FROM t1;
+c1 c2 i1 i2
+10 10 10 10
+20 def 20 123
+30 def 30 123
+CALL dbf_header('MYSQLD_DATADIR/test/t1.dbf');
+-------- --------
+FileSize 291
+DBF_Version 03
+NRecords 3
+FirstRecPos 162
+RecLength 43
+TableFlags 0000
+CodePageMark 00
+--- ---
+FieldN 0
+Name c1
+Type C
+Offset 0
+Length 10
+Dec 0
+Flags 00
+--- ---
+FieldN 1
+Name c2
+Type C
+Offset 0
+Length 10
+Dec 0
+Flags 00
+--- ---
+FieldN 2
+Name i1
+Type N
+Offset 0
+Length 11
+Dec 0
+Flags 00
+--- ---
+FieldN 3
+Name i2
+Type N
+Offset 0
+Length 11
+Dec 0
+Flags 00
+-------- --------
+DROP TABLE IF EXISTS t1;
+DROP PROCEDURE test.dbf_field;
+DROP PROCEDURE test.dbf_header;
diff --git a/storage/connect/mysql-test/connect/r/dir.result b/storage/connect/mysql-test/connect/r/dir.result
new file mode 100644
index 00000000..139544b9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/dir.result
@@ -0,0 +1,32 @@
+CREATE TABLE t1 (
+path VARCHAR(256) NOT NULL flag=1,
+fname VARCHAR(256) NOT NULL,
+ftype CHAR(4) NOT NULL,
+size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.txt'
+ OPTION_LIST='subdir=1';
+SELECT * FROM t1;
+path fname ftype size
+SELECT fname, ftype, size FROM t1 ORDER BY fname, ftype, size;
+fname ftype size
+boys .txt 282
+boys2 .txt 282
+boyswin .txt 288
+ALTER TABLE t1 OPTION_LIST='subdir=0';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `path` varchar(256) NOT NULL `flag`=1,
+ `fname` varchar(256) NOT NULL,
+ `ftype` char(4) NOT NULL,
+ `size` double(12,0) NOT NULL `flag`=5
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=DIR `FILE_NAME`='*.txt' `OPTION_LIST`='subdir=0'
+SELECT fname, ftype, size FROM t1 ORDER BY fname, ftype, size;
+fname ftype size
+boys .txt 282
+boyswin .txt 288
+INSERT INTO t1 VALUES ('','','','');
+ERROR 22007: Incorrect double value: '' for column `test`.`t1`.`size` at row 1
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.txt';
+ERROR HY000: Cannot get column info for table type DIR
diff --git a/storage/connect/mysql-test/connect/r/drop-open-error.result b/storage/connect/mysql-test/connect/r/drop-open-error.result
new file mode 100644
index 00000000..34f58a84
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/drop-open-error.result
@@ -0,0 +1,15 @@
+create table t1 (c varchar(8));
+create table tcon engine=connect table_type=mysql CONNECTION='mysql://root@localhost/test/t1' SRCDEF='select c from t1 where c in ("foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar")';
+ERROR HY000: Too long value for 'SRCDEF'
+drop table mdev9949;
+Warnings:
+Warning 1017 Can't find file: './test/mdev9949.dos' (errno: 2 "No such file or directory")
+drop table t1;
+select @@secure_file_priv 'must be NULL';
+must be NULL
+NULL
+create table t1 (a char(16)) engine=myisam;
+insert into t1 values('Hello World!');
+create table t2 engine=connect file_name='foo/bar.txt' as select * from t1;
+ERROR HY000: Got error 174 'Open(a+b) error 2 on foo/bar.txt: No such file or directory' from CONNECT
+drop table t1;
diff --git a/storage/connect/mysql-test/connect/r/endian.result b/storage/connect/mysql-test/connect/r/endian.result
new file mode 100644
index 00000000..a4c81e43
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/endian.result
@@ -0,0 +1,105 @@
+SET time_zone='+00:00';
+#
+# Testing little endian table
+#
+CREATE TABLE t1
+(
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL FIELD_FORMAT='L',
+id CHAR(5) NOT NULL FIELD_FORMAT='L2',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='LF',
+dept INT(4) NOT NULL FIELD_FORMAT='L2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t1;
+CREATE TABLE t1
+(
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL,
+id CHAR(5) NOT NULL FIELD_FORMAT='S',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+dept INT(4) NOT NULL FIELD_FORMAT='S'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
+SELECT * FROM t1;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+#
+# Testing big endian table
+#
+CREATE TABLE t2 (
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL FIELD_FORMAT='B',
+id CHAR(5) NOT NULL FIELD_FORMAT='BS',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
+dept INT(4) NOT NULL FIELD_FORMAT='B2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
+INSERT INTO t2 SELECT * FROM t1;
+SELECT * FROM t2;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t2;
+CREATE TABLE t2 (
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL,
+id CHAR(5) NOT NULL FIELD_FORMAT='S',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+dept INT(4) NOT NULL FIELD_FORMAT='2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
+SELECT * FROM t2;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t2;
+CREATE TABLE t2 (
+fig CHAR(4) NOT NULL,
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL,
+id SMALLINT(5) NOT NULL,
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+dept SMALLINT(4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
+SELECT * FROM t2;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t2;
+CREATE TABLE t2 (
+fig INT(4) NOT NULL FIELD_FORMAT='C',
+name CHAR(10) NOT NULL,
+birth DATE NOT NULL FIELD_FORMAT='B',
+id CHAR(5) NOT NULL FIELD_FORMAT='BS',
+salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
+dept SMALLINT(4) NOT NULL FIELD_FORMAT='B'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
+SELECT * FROM t2;
+fig name birth id salary dept
+5500 ARCHIBALD 1980-01-25 3789 4380.50 318
+123 OLIVER 1953-08-10 23456 3400.68 2158
+3123 FOO 2002-07-23 888 0.00 318
+5555 RONALD 1980-02-26 3333 4444.44 555
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/r/fix.result b/storage/connect/mysql-test/connect/r/fix.result
new file mode 100644
index 00000000..4d620c66
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/fix.result
@@ -0,0 +1,131 @@
+#
+# Testing errors
+#
+CREATE TABLE t1
+(
+ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=DOS FILE_NAME='nonexistent.txt';
+SELECT * FROM t1;
+ID
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/nonexistent.txt: No such file or directory
+DROP TABLE t1;
+#
+# Testing READONLY tables
+#
+CREATE TABLE t1
+(
+id INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.txt';
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+id
+10
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=FIX `FILE_NAME`='t1.txt' `READONLY`=1
+INSERT INTO t1 VALUES (20);
+ERROR HY000: Table 't1' is read only
+UPDATE t1 SET id=20 WHERE id=10;
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+DELETE FROM t1 WHERE id=10;
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+TRUNCATE TABLE t1;
+ERROR HY000: Table 't1' is read only
+ALTER TABLE t1 READONLY=0;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=FIX `FILE_NAME`='t1.txt' `READONLY`=0
+INSERT INTO t1 VALUES (20);
+SELECT * FROM t1;
+id
+10
+20
+DROP TABLE t1;
+#
+# Testing manual examples
+#
+CREATE TABLE t1
+(
+number CHAR(4) not null,
+location CHAR(15) NOT NULL flag=5,
+director CHAR(5) NOT NULL flag=20,
+function CHAR(12) NOT NULL flag=26,
+name CHAR(22) NOT NULL flag=38
+) ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='dept.dat';
+SELECT * FROM t1;
+number location director function name
+0318 KINGSTON 70012 SALES Bank/Insurance
+0021 ARMONK 87777 CHQ Corporate headquarter
+0319 HARRISON 40567 SALES Federal Administration
+2452 POUGHKEEPSIE 31416 DEVELOPMENT Research & development
+DROP TABLE t1;
+CREATE TABLE t1
+(
+name char(12) not null,
+city char(11) not null,
+birth date not null date_format='DD/MM/YYYY',
+hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' ENDING=1;
+SELECT * FROM t1;
+name city birth hired
+John Boston 1986-01-25 2010-06-02
+Henry Boston 1987-06-07 2008-04-01
+George San Jose 1981-08-10 2010-06-02
+Sam Chicago 1979-11-22 2007-10-10
+James Dallas 1992-05-13 2009-12-14
+Bill Boston 1986-09-11 2008-02-10
+DROP TABLE t1;
+CREATE TABLE t1
+(
+name char(12) not null,
+city char(11) not null,
+birth date not null date_format='DD/MM/YYYY',
+hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' LRECL=47 ENDING=1;
+SELECT * FROM t1;
+name city birth hired
+John Boston 1986-01-25 2010-06-02
+Henry Boston 1987-06-07 2008-04-01
+George San Jose 1981-08-10 2010-06-02
+Sam Chicago 1979-11-22 2007-10-10
+James Dallas 1992-05-13 2009-12-14
+Bill Boston 1986-09-11 2008-02-10
+DROP TABLE t1;
+CREATE TABLE t1
+(
+name char(12) not null,
+city char(11) not null,
+birth date not null date_format='DD/MM/YYYY',
+hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boyswin.txt' ENDING=2;
+SELECT * FROM t1;
+name city birth hired
+John Boston 1986-01-25 2010-06-02
+Henry Boston 1987-06-07 2008-04-01
+George San Jose 1981-08-10 2010-06-02
+Sam Chicago 1979-11-22 2007-10-10
+James Dallas 1992-05-13 2009-12-14
+Bill Boston 1986-09-11 2008-02-10
+DROP TABLE t1;
+CREATE TABLE t1
+(
+name char(12) not null,
+city char(11) not null,
+birth date not null date_format='DD/MM/YYYY',
+hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boyswin.txt' LRECL=47 ENDING=2;
+SELECT * FROM t1;
+name city birth hired
+John Boston 1986-01-25 2010-06-02
+Henry Boston 1987-06-07 2008-04-01
+George San Jose 1981-08-10 2010-06-02
+Sam Chicago 1979-11-22 2007-10-10
+James Dallas 1992-05-13 2009-12-14
+Bill Boston 1986-09-11 2008-02-10
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/fmt.result b/storage/connect/mysql-test/connect/r/fmt.result
new file mode 100644
index 00000000..0be10f69
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/fmt.result
@@ -0,0 +1,68 @@
+#
+# Testing errors
+#
+CREATE TABLE t1
+(
+ID INT NOT NULL field_format=' %n%d%n'
+) Engine=CONNECT table_type=FMT file_name='nonexistent.txt';
+SELECT * FROM t1;
+ID
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/nonexistent.txt: No such file or directory
+DROP TABLE t1;
+#
+# Testing update on FMT tables
+#
+CREATE TABLE t1
+(
+id INT NOT NULL field_format=' %n%d%n'
+) ENGINE=CONNECT TABLE_TYPE=FMT FILE_NAME='t1.txt';
+INSERT INTO t1 VALUES (10),(20);
+ERROR HY000: Got error 174 'Writing FMT files is not implemented yet' from CONNECT
+DROP TABLE t1;
+#
+# Testing manual examples
+#
+CREATE TABLE t1
+(
+ID Integer(5) not null field_format=' %n%d%n',
+NAME Char(16) not null field_format=" , '%n%[^']%n'",
+DEPNO Integer(4) not null field_format=' , #%n%d%n',
+SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny.txt';
+SELECT * FROM t1;
+ID NAME DEPNO SALARY
+12345 BERTRAND 200 5009.13
+56 POIROT-DELMOTTE 4256 18009.00
+345 TRUCMUCHE 67 19000.25
+DROP TABLE t1;
+CREATE TABLE t1
+(
+ID Integer(5) not null field_format=' %n%d%n',
+NAME Char(16) not null field_format=" , '%n%[^']%n'",
+DEPNO Integer(4) not null field_format=' , #%n%d%n',
+SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny2.txt';
+SELECT * FROM t1;
+ERROR HY000: Got error 122 'Bad format line 2 field 3 of t1' from CONNECT
+DROP TABLE t1;
+CREATE TABLE t1
+(
+ID Integer(5) not null field_format=' %n%d%n',
+NAME Char(16) not null field_format=' , ''%n%[^'']%m',
+DEPNO Integer(4) not null field_format=''' , #%n%d%m',
+SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny2.txt';
+SELECT * FROM t1;
+ID NAME DEPNO SALARY
+12345 BERTRAND 200 5009.13
+56 POIROT-DELMOTTE 0 18009.00
+345 67 19000.25
+UPDATE t1 SET SALARY=1234;
+ERROR HY000: Got error 174 'Writing FMT files is not implemented yet' from CONNECT
+DELETE FROM t1 WHERE ID=56;
+SELECT * FROM t1;
+ID NAME DEPNO SALARY
+12345 BERTRAND 200 5009.13
+345 67 19000.25
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/general.result b/storage/connect/mysql-test/connect/r/general.result
new file mode 100644
index 00000000..ed2c9031
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/general.result
@@ -0,0 +1,18 @@
+#
+# Testing features not specific to any TABLE_TYPE
+#
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=NON_EXISTING;
+ERROR HY000: Unsupported table type NON_EXISTING
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+ALTER TABLE t1 TABLE_TYPE=NON_EXISTING;
+ERROR HY000: Unsupported table type NON_EXISTING
+SELECT * FROM t1;
+a
+10
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/grant.result b/storage/connect/mysql-test/connect/r/grant.result
new file mode 100644
index 00000000..2e7f0e4b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/grant.result
@@ -0,0 +1,604 @@
+set sql_mode="";
+#
+# Testing FILE privilege
+#
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (
+path VARCHAR(256) NOT NULL flag=1,
+fname VARCHAR(256) NOT NULL,
+ftype CHAR(4) NOT NULL,
+size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.*';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (
+path VARCHAR(256) NOT NULL flag=1,
+fname VARCHAR(256) NOT NULL,
+ftype CHAR(4) NOT NULL,
+size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.*';
+SELECT fname, ftype, size FROM t1 WHERE size>0 AND ftype!='.opt';
+fname ftype size
+t1 .frm 1081
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO t1 VALUES ();
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1 WHERE path='xxx';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET path='yyy' WHERE path='xxx';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (1,1,1,1);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET path=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+disconnect user;
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+DROP USER user@localhost;
+#
+# Testing FILE privileges done
+#
+#
+# Beginning of grant.inc
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN;
+Warnings:
+Warning 1105 No file name. Table will use t1.bin
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+UPDATE t1 SET a=20;
+SELECT * FROM t1;
+a
+20
+DELETE FROM t1;
+SELECT * FROM t1;
+a
+INSERT INTO t1 VALUES(10);
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+a
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+INSERT INTO t1 VALUES (10);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 FILE_NAME='t2.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (2);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET a=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=BIN;
+Warnings:
+Warning 1105 No file name. Table will use t1.bin
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+ALTER TABLE t1 FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+disconnect user;
+DROP USER user@localhost;
+#
+# End of grant.inc
+#
+#
+# Beginning of grant.inc
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+UPDATE t1 SET a=20;
+SELECT * FROM t1;
+a
+20
+DELETE FROM t1;
+SELECT * FROM t1;
+a
+INSERT INTO t1 VALUES(10);
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+a
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+INSERT INTO t1 VALUES (10);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 FILE_NAME='t2.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (2);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET a=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+ALTER TABLE t1 FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+disconnect user;
+DROP USER user@localhost;
+#
+# End of grant.inc
+#
+#
+# Beginning of grant.inc
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF;
+Warnings:
+Warning 1105 No file name. Table will use t1.dbf
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+UPDATE t1 SET a=20;
+SELECT * FROM t1;
+a
+20
+DELETE FROM t1;
+SELECT * FROM t1;
+a
+INSERT INTO t1 VALUES(10);
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+a
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+INSERT INTO t1 VALUES (10);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 FILE_NAME='t2.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (2);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET a=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF;
+Warnings:
+Warning 1105 No file name. Table will use t1.dbf
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+ALTER TABLE t1 FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+disconnect user;
+DROP USER user@localhost;
+#
+# End of grant.inc
+#
+#
+# Beginning of grant.inc
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+UPDATE t1 SET a=20;
+SELECT * FROM t1;
+a
+20
+DELETE FROM t1;
+SELECT * FROM t1;
+a
+INSERT INTO t1 VALUES(10);
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+a
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+INSERT INTO t1 VALUES (10);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 FILE_NAME='t2.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (2);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET a=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+ALTER TABLE t1 FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+disconnect user;
+DROP USER user@localhost;
+#
+# End of grant.inc
+#
+#
+# Beginning of grant.inc
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100;
+Warnings:
+Warning 1105 No file name. Table will use t1.vec
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+UPDATE t1 SET a=20;
+SELECT * FROM t1;
+a
+20
+DELETE FROM t1;
+SELECT * FROM t1;
+a
+INSERT INTO t1 VALUES(10);
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+a
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100 FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100 FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+INSERT INTO t1 VALUES (10);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 FILE_NAME='t2.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (2);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET a=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=VEC MAX_ROWS=100;
+Warnings:
+Warning 1105 No file name. Table will use t1.vec
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+ALTER TABLE t1 FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+disconnect user;
+DROP USER user@localhost;
+#
+# End of grant.inc
+#
+set sql_mode=default;
diff --git a/storage/connect/mysql-test/connect/r/grant2.result b/storage/connect/mysql-test/connect/r/grant2.result
new file mode 100644
index 00000000..2e20dc39
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/grant2.result
@@ -0,0 +1,770 @@
+#
+# MDEV-7574 Security definer views don't work with CONNECT ODBC tables
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+# Testing SQLCOM_SELECT
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE DEFINER=user@localhost SQL SECURITY DEFINER VIEW v1_baddefiner AS SELECT * FROM t1;
+SELECT * FROM t1;
+a
+10
+SELECT * FROM v1_invoker;
+a
+10
+SELECT * FROM v1_definer;
+a
+10
+SELECT * FROM v1_baddefiner;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connect user,localhost,user,,;
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM v1_invoker;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM v1_definer;
+a
+10
+connection default;
+DROP VIEW v1_invoker, v1_definer, v1_baddefiner;
+DROP TABLE t1;
+# Testing SQLCOM_UPDATE
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+UPDATE t1 SET a=11;
+UPDATE v1_invoker SET a=12;
+UPDATE v1_definer SET a=13;
+connection user;
+UPDATE t1 SET a=21;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_invoker SET a=22;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_definer SET a=23;
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_INSERT
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+INSERT INTO t1 VALUES (11);
+INSERT INTO v1_invoker VALUES (12);
+INSERT INTO v1_definer VALUES (13);
+connection user;
+INSERT INTO t1 VALUES (21);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1_invoker VALUES (22);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1_definer VALUES (23);
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_REPLACE
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+REPLACE INTO t1 VALUES (11);
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_invoker VALUES (12);
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer VALUES (13);
+ERROR 42000: CONNECT Unsupported command
+connection user;
+REPLACE INTO t1 VALUES (21);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+REPLACE INTO v1_invoker VALUES (22);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+REPLACE INTO v1_definer VALUES (23);
+ERROR 42000: CONNECT Unsupported command
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_DELETE
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10),(11),(12),(13),(21),(22),(23);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DELETE FROM t1 WHERE a=11;
+DELETE FROM v1_invoker WHERE a=12;
+DELETE FROM v1_definer WHERE a=13;
+connection user;
+DELETE FROM t1 WHERE a=21;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1_invoker WHERE a=22;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1_definer WHERE a=23;
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_LOAD
+connection default;
+CREATE TABLE t1 (a VARCHAR(128)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1;
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker;
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer;
+connection user;
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+LOAD DATA LOCAL INFILE 'MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer;
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_TRUNCATE
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (11);
+connection user;
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_DROP_TABLE
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+connection user;
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_DROP_VIEW
+# DROP VIEW does not need FILE_ACL.
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10),(11),(12),(13),(21),(22),(23);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DROP VIEW v1_invoker, v1_definer;
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+connection user;
+DROP VIEW v1_invoker;
+DROP VIEW v1_definer;
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_CREATE_TABLE
+connection user;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+# Testing SQLCOM_LOCK_TABLES
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+LOCK TABLE t1 READ;
+UNLOCK TABLES;
+LOCK TABLE t1 WRITE;
+UNLOCK TABLES;
+LOCK TABLE v1_invoker READ;
+UNLOCK TABLES;
+LOCK TABLE v1_invoker WRITE;
+UNLOCK TABLES;
+LOCK TABLE v1_definer READ;
+UNLOCK TABLES;
+LOCK TABLE v1_definer WRITE;
+UNLOCK TABLES;
+connection user;
+LOCK TABLE t1 READ;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+LOCK TABLE t1 WRITE;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+LOCK TABLE v1_invoker READ;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+LOCK TABLE v1_invoker WRITE;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+LOCK TABLE v1_definer READ;
+UNLOCK TABLES;
+LOCK TABLE v1_definer WRITE;
+UNLOCK TABLES;
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_UPDATE_MULTI
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE TABLE t2 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t2.fix';
+CREATE TABLE t3 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES (20);
+INSERT INTO t3 VALUES (30);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v2_invoker AS SELECT * FROM t2;
+CREATE SQL SECURITY DEFINER VIEW v2_definer AS SELECT * FROM t2;
+UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+connection user;
+UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+connection default;
+DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer;
+DROP TABLE t1, t2, t3;
+# Testing SQLCOM_DELETE_MULTI
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE TABLE t2 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t2.fix';
+CREATE TABLE t3 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES (20);
+INSERT INTO t3 VALUES (30);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v2_invoker AS SELECT * FROM t2;
+CREATE SQL SECURITY DEFINER VIEW v2_definer AS SELECT * FROM t2;
+DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+connection user;
+DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+connection default;
+DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer;
+DROP TABLE t1, t2, t3;
+# Testing SQLCOM_CREATE_VIEW
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE VIEW v2 AS SELECT * FROM v1_invoker;
+DROP VIEW v2;
+CREATE VIEW v2 AS SELECT * FROM v1_definer;
+DROP VIEW v2;
+connection user;
+CREATE VIEW v2 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v2 AS SELECT * FROM v1_invoker;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v2 AS SELECT * FROM v1_definer;
+DROP VIEW v2;
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_INSERT_SELECT
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1 WHERE a=20;
+INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+connection user;
+INSERT INTO t1 SELECT * FROM t1 WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_REPLACE_SELECT
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+REPLACE INTO t1 SELECT * FROM t1 WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+connection user;
+REPLACE INTO t1 SELECT * FROM t1 WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+ERROR 42000: CONNECT Unsupported command
+connection default;
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+# Testing SQLCOM_RENAME_TABLE
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+RENAME TABLE t1 TO t2;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=fix `FILE_NAME`='t1.fix'
+RENAME TABLE t2 TO t1;
+connection user;
+RENAME TABLE t1 TO t2;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (for ALTER..RENAME)
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 RENAME TO t2;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=fix `FILE_NAME`='t1.fix'
+ALTER TABLE t2 RENAME TO t1;
+connection user;
+ALTER TABLE t1 RENAME TO t2;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (changing ENGINE to non-CONNECT)
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ENGINE=MyISAM;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+connection user;
+ALTER TABLE t1 ENGINE=MyISAM;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (changing ENGINE to CONNECT)
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+DROP TABLE t1;
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (10);
+connection user;
+ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_OPTIMIZE
+connection default;
+CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+connection user;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize Error Access denied; you need (at least one of) the FILE privilege(s) for this operation
+test.t1 optimize Error Got error 122 'This operation requires the FILE privilege' from CONNECT
+test.t1 optimize error Corrupt
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (adding columns)
+connection default;
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ADD b INT;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+connection user;
+ALTER TABLE t1 ADD c INT;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (removing columns)
+connection default;
+CREATE TABLE t1 (a INT,b INT,c INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10,10);
+ALTER TABLE t1 DROP b;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+connection user;
+ALTER TABLE t1 DROP c;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (adding keys)
+connection default;
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+ALTER TABLE t1 ADD KEY(a);
+connection user;
+ALTER TABLE t1 ADD KEY(b);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_ALTER_TABLE (removing keys)
+connection default;
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL, KEY a(a), KEY b(b)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+ALTER TABLE t1 DROP KEY a;
+connection user;
+ALTER TABLE t1 DROP KEY b;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing SQLCOM_CREATE_INDEX and SQLCOM_DROP_INDEX
+connection default;
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+CREATE INDEX a ON t1 (a);
+DROP INDEX a ON t1;
+CREATE INDEX a ON t1 (a);
+connection user;
+CREATE INDEX b ON t1 (b);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP INDEX a ON t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+# Testing stored procedures
+CREATE PROCEDURE p_definer() SQL SECURITY DEFINER
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE PROCEDURE p_invoker() SQL SECURITY INVOKER
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE DEFINER=user@localhost PROCEDURE p_baddefiner() SQL SECURITY DEFINER
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CALL p_definer();
+DROP TABLE t1;
+CALL p_invoker();
+DROP TABLE t1;
+CALL p_baddefiner();
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection user;
+CALL p_invoker();
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CALL p_definer();
+connection default;
+DROP TABLE t1;
+DROP PROCEDURE p_definer;
+DROP PROCEDURE p_invoker;
+DROP PROCEDURE p_baddefiner;
+DROP USER user@localhost;
diff --git a/storage/connect/mysql-test/connect/r/grant3.result b/storage/connect/mysql-test/connect/r/grant3.result
new file mode 100644
index 00000000..2f9d37bd
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/grant3.result
@@ -0,0 +1,5 @@
+create table tcon (i int) engine=Connect table_type=DOS file_name='tcon.dos';
+create table tin (i int);
+create trigger tr after insert on tin for each row insert into tcon values (new.i);
+insert into tin values (1);
+drop table tin,tcon;
diff --git a/storage/connect/mysql-test/connect/r/index.result b/storage/connect/mysql-test/connect/r/index.result
new file mode 100644
index 00000000..bffaaecc
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/index.result
@@ -0,0 +1,141 @@
+#
+# Testing indexing
+#
+CREATE TABLE t1
+(
+matricule INT(4) KEY NOT NULL field_format='Z',
+nom VARCHAR(16) NOT NULL,
+prenom VARCHAR(20) NOT NULL,
+sexe SMALLINT(1) NOT NULL COMMENT 'sexe 1:M 2:F',
+aanais INT(4) NOT NULL,
+mmnais INT(2) NOT NULL,
+ddentree DATE NOT NULL date_format='YYYYMM',
+ddnom DATE NOT NULL date_format='YYYYMM',
+brut INT(5) NOT NULL,
+net DOUBLE(8,2) NOT NULL,
+service INT(2) NOT NULL,
+sitmat CHAR(1) NOT NULL,
+formation CHAR(5) NOT NULL,
+INDEX NP(nom,prenom)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='emp.txt' ENDING=2;
+SELECT * FROM t1 LIMIT 10;
+matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation
+5745 ESCOURCHE BENEDICTE 2 1935 7 1962-12-01 1994-05-01 18345 14275.50 0 M TECHN
+9692 VICENTE LAURENCE 2 1941 8 1967-10-01 1989-01-01 16212 13032.80 0 M ANGL
+9146 NICOLAS ROGER 1 1941 6 1964-07-01 1995-02-01 34173 25098.65 0 M SANS
+2985 TESSEREAU MARIE HELENE 2 1941 9 1967-01-01 1990-01-01 19323 14933.78 0 V SANS
+3368 MOGADOR ALAIN 1 1941 1 1961-09-01 1993-11-01 43303 31420.55 0 C SANS
+7394 CHAUSSEE ERIC DENIS 1 1944 9 1965-11-01 1983-12-01 32002 23583.86 0 M ANGL
+4655 MAILLOT GEORGES 1 1945 5 1970-09-01 1986-12-01 24700 18541.64 0 C ANGL
+2825 CAMILLE NADINE 2 1956 9 1994-01-01 1993-01-01 19494 15050.45 0 M SANS
+1460 BRUYERES JEAN MARC 1 1958 8 1984-08-01 1988-05-01 20902 15980.07 0 M SANS
+4974 LONES GERARD 1 1959 10 1979-01-01 1994-12-01 16081 12916.70 0 M SANS
+SELECT SUM(brut) from t1;
+SUM(brut)
+64319029
+#
+# Testing file mapping
+#
+ALTER TABLE t1 MAPPED=yes;
+SELECT * FROM t1 LIMIT 10;
+matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation
+5745 ESCOURCHE BENEDICTE 2 1935 7 1962-12-01 1994-05-01 18345 14275.50 0 M TECHN
+9692 VICENTE LAURENCE 2 1941 8 1967-10-01 1989-01-01 16212 13032.80 0 M ANGL
+9146 NICOLAS ROGER 1 1941 6 1964-07-01 1995-02-01 34173 25098.65 0 M SANS
+2985 TESSEREAU MARIE HELENE 2 1941 9 1967-01-01 1990-01-01 19323 14933.78 0 V SANS
+3368 MOGADOR ALAIN 1 1941 1 1961-09-01 1993-11-01 43303 31420.55 0 C SANS
+7394 CHAUSSEE ERIC DENIS 1 1944 9 1965-11-01 1983-12-01 32002 23583.86 0 M ANGL
+4655 MAILLOT GEORGES 1 1945 5 1970-09-01 1986-12-01 24700 18541.64 0 C ANGL
+2825 CAMILLE NADINE 2 1956 9 1994-01-01 1993-01-01 19494 15050.45 0 M SANS
+1460 BRUYERES JEAN MARC 1 1958 8 1984-08-01 1988-05-01 20902 15980.07 0 M SANS
+4974 LONES GERARD 1 1959 10 1979-01-01 1994-12-01 16081 12916.70 0 M SANS
+SELECT SUM(brut) FROM t1;
+SUM(brut)
+64319029
+#
+# Test the indexes (made when creating the table)
+#
+SELECT * FROM t1 WHERE matricule = '0091';
+matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation
+91 THIVERNAL DIDIER JEAN 1 1951 10 1980-05-01 1991-10-01 14715 12024.71 1 M SANS
+SELECT * FROM t1 WHERE nom = 'FOCH';
+matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation
+1977 FOCH BERNADETTE 2 1958 3 1992-02-01 1991-02-01 8656 8145.03 1 . SANS
+5707 FOCH DENIS 1 1977 7 1996-07-01 1995-07-01 7803 7679.36 15 C COMPT
+2552 FOCH FRANCK 1 1962 12 1986-06-01 1990-11-01 12882 10745.81 13 M SANS
+2634 FOCH JOCELYNE 2 1953 3 1996-01-01 1995-01-01 12499 10473.09 41 M INFOR
+5765 FOCH ROBERT 1 1957 1 1981-03-01 1993-03-01 16081 12916.32 52 M ALLEM
+4080 FOCH SERGE 1 1959 3 1981-03-01 1981-05-01 11131 9658.24 5 M SANS
+SELECT * FROM t1 WHERE nom = 'FOCH' and prenom = 'DENIS';
+matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation
+5707 FOCH DENIS 1 1977 7 1996-07-01 1995-07-01 7803 7679.36 15 C COMPT
+#
+# Testing UPDATE
+#
+UPDATE t1 SET aanais = aanais + 16;
+UPDATE t1 SET ddentree = adddate(ddentree, interval 16 year);
+UPDATE t1 SET ddnom = adddate(ddnom, interval 16 year);
+SELECT * FROM t1 WHERE nom = 'FOCH';
+matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation
+1977 FOCH BERNADETTE 2 1974 3 2008-02-01 2007-02-01 8656 8145.03 1 . SANS
+5707 FOCH DENIS 1 1993 7 2012-07-01 2011-07-01 7803 7679.36 15 C COMPT
+2552 FOCH FRANCK 1 1978 12 2002-06-01 2006-11-01 12882 10745.81 13 M SANS
+2634 FOCH JOCELYNE 2 1969 3 2012-01-01 2011-01-01 12499 10473.09 41 M INFOR
+5765 FOCH ROBERT 1 1973 1 1997-03-01 2009-03-01 16081 12916.32 52 M ALLEM
+4080 FOCH SERGE 1 1975 3 1997-03-01 1997-05-01 11131 9658.24 5 M SANS
+#
+# Testing JOIN
+#
+create table t2
+(
+sexe INT(1) KEY,
+genre CHAR(8) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='sexe.csv' SEP_CHAR=';' ENDING=2;
+SELECT * FROM t2;
+sexe genre
+0 Inconnu
+1 Masculin
+2 Feminin
+SELECT nom, prenom, genre FROM t1 NATURAL JOIN t2 LIMIT 10;
+nom prenom genre
+ESCOURCHE BENEDICTE Feminin
+VICENTE LAURENCE Feminin
+NICOLAS ROGER Masculin
+TESSEREAU MARIE HELENE Feminin
+MOGADOR ALAIN Masculin
+CHAUSSEE ERIC DENIS Masculin
+MAILLOT GEORGES Masculin
+CAMILLE NADINE Feminin
+BRUYERES JEAN MARC Masculin
+LONES GERARD Masculin
+#
+# Another table
+#
+CREATE TABLE t3 (
+sitmat CHAR(1) KEY,
+situation CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='sitmat.csv' SEP_CHAR=';' ENDING=2;
+SELECT * FROM t3;
+sitmat situation
+. Inconnu
+C Celibataire
+D Divorce
+L Union libre
+M Marie
+S Separe
+V Veuf
+SELECT nom, prenom, genre, situation FROM t1 NATURAL JOIN t2 NATURAL JOIN t3 WHERE nom = 'FOCH';
+nom prenom genre situation
+FOCH BERNADETTE Feminin Inconnu
+FOCH DENIS Masculin Celibataire
+FOCH FRANCK Masculin Marie
+FOCH JOCELYNE Feminin Marie
+FOCH ROBERT Masculin Marie
+FOCH SERGE Masculin Marie
+#
+# Testing DELETE
+#
+DELETE FROM t1;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
diff --git a/storage/connect/mysql-test/connect/r/infoschema-9739.result b/storage/connect/mysql-test/connect/r/infoschema-9739.result
new file mode 100644
index 00000000..4840e981
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/infoschema-9739.result
@@ -0,0 +1,8 @@
+create table t1 (i int) engine=Connect table_type=XML option_list='xmlsup=domdoc';
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+select * from information_schema.tables where table_schema='test' and create_options like '%table_type=XML%';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT MAX_INDEX_LENGTH TEMPORARY
+Warnings:
+Warning 1296 Got error 174 'File t1.xml not found' from CONNECT
+drop table t1;
diff --git a/storage/connect/mysql-test/connect/r/infoschema2-9739.result b/storage/connect/mysql-test/connect/r/infoschema2-9739.result
new file mode 100644
index 00000000..32ca77dc
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/infoschema2-9739.result
@@ -0,0 +1,10 @@
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+create table t1 (i int) engine=Connect table_type=XML option_list='xmlsup=libxml2';
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+select * from information_schema.tables where table_schema='test' and create_options like '%table_type=XML%';
+TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE ENGINE VERSION ROW_FORMAT TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE AUTO_INCREMENT CREATE_TIME UPDATE_TIME CHECK_TIME TABLE_COLLATION CHECKSUM CREATE_OPTIONS TABLE_COMMENT MAX_INDEX_LENGTH TEMPORARY
+Warnings:
+Warning 1296 Got error 174 'File t1.xml not found' from CONNECT
+drop table t1;
diff --git a/storage/connect/mysql-test/connect/r/ini.result b/storage/connect/mysql-test/connect/r/ini.result
new file mode 100644
index 00000000..a377cb3e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/ini.result
@@ -0,0 +1,279 @@
+#
+# Testing errors
+#
+CREATE TABLE t1
+(
+ID INT
+) Engine=CONNECT TABLE_TYPE=INI FILE_NAME='nonexistent.txt';
+SELECT * FROM t1;
+ID
+DROP TABLE t1;
+#
+# Testing examples from the manual
+#
+CREATE TABLE t1
+(
+contact CHAR(16) flag=1,
+name CHAR(20),
+forename CHAR(32),
+hired date date_format='DD/MM/YYYY',
+address CHAR(64),
+city CHAR(20),
+zipcode CHAR(8),
+tel CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='contact.ini';
+SELECT contact, name, hired, city, tel FROM t1;
+contact name hired city tel
+BER Bertrand NULL Issy-les-Mlx 09.54.36.29.60
+WEL Schmitt 1985-02-19 Berlin 03.43.377.360
+UK1 Smith 2003-11-08 London NULL
+UPDATE t1 SET forename= 'Harry' where contact='UK1';
+SELECT * FROM t1 WHERE contact='UK1';
+contact name forename hired address city zipcode tel
+UK1 Smith Harry 2003-11-08 143 Blum Rd. London NW1 2BP NULL
+INSERT INTO t1 (contact,forename) VALUES ('UK1','Harrison');
+SELECT * FROM t1 WHERE contact='UK1';
+contact name forename hired address city zipcode tel
+UK1 Smith Harrison 2003-11-08 143 Blum Rd. London NW1 2BP NULL
+INSERT INTO t1 (contact,forename) VALUES ('UK2','John');
+SELECT * FROM t1 WHERE contact='UK2';
+contact name forename hired address city zipcode tel
+UK2 NULL John NULL NULL NULL NULL NULL
+DROP TABLE t1;
+SELECT REPLACE(REPLACE(LOAD_FILE('DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n');;
+REPLACE(REPLACE(LOAD_FILE('DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n')
+[BER]
+name=Bertrand
+forename=Olivier
+address=21 rue Ferdinand Buisson
+city=Issy-les-Mlx
+zipcode=92130
+tel=09.54.36.29.60
+cell=06.70.06.04.16
+[WEL]
+name=Schmitt
+forename=Bernard
+hired=19/02/1985
+address=64 tiergarten strasse
+city=Berlin
+zipcode=95013
+tel=03.43.377.360
+[UK1]
+name=Smith
+forename=Harrison
+hired=08/11/2003
+address=143 Blum Rd.
+city=London
+zipcode=NW1 2BP
+[UK2]
+forename=John
+
+CREATE TABLE t1
+(
+section CHAR(16) flag=1,
+keyname CHAR(16) flag=2,
+value CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='contact.ini'
+ OPTION_LIST='Layout=Row';
+UPDATE t1 SET value='Paul' WHERE section='UK2' AND keyname='forename';
+SELECT * FROM t1;
+section keyname value
+BER name Bertrand
+BER forename Olivier
+BER address 21 rue Ferdinand Buisson
+BER city Issy-les-Mlx
+BER zipcode 92130
+BER tel 09.54.36.29.60
+BER cell 06.70.06.04.16
+WEL name Schmitt
+WEL forename Bernard
+WEL hired 19/02/1985
+WEL address 64 tiergarten strasse
+WEL city Berlin
+WEL zipcode 95013
+WEL tel 03.43.377.360
+UK1 name Smith
+UK1 forename Harrison
+UK1 hired 08/11/2003
+UK1 address 143 Blum Rd.
+UK1 city London
+UK1 zipcode NW1 2BP
+UK2 forename Paul
+DROP TABLE t1;
+SELECT REPLACE(REPLACE(LOAD_FILE('DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n');;
+REPLACE(REPLACE(LOAD_FILE('DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n')
+[BER]
+name=Bertrand
+forename=Olivier
+address=21 rue Ferdinand Buisson
+city=Issy-les-Mlx
+zipcode=92130
+tel=09.54.36.29.60
+cell=06.70.06.04.16
+[WEL]
+name=Schmitt
+forename=Bernard
+hired=19/02/1985
+address=64 tiergarten strasse
+city=Berlin
+zipcode=95013
+tel=03.43.377.360
+[UK1]
+name=Smith
+forename=Harrison
+hired=08/11/2003
+address=143 Blum Rd.
+city=London
+zipcode=NW1 2BP
+[UK2]
+forename=Paul
+
+#
+# Testing that the underlying file is created
+#
+CREATE TABLE t1
+(
+contact CHAR(12) NOT NULL flag=1,
+c2 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='tmp.ini';
+INSERT INTO t1 VALUES (10,10),(20,20),(300,300),(4000,4000), ('a b','c d');
+SELECT * FROM t1;
+contact c2
+10 10
+20 20
+300 300
+4000 4000
+a b c d
+DROP TABLE t1;
+SELECT REPLACE(REPLACE(LOAD_FILE('DATADIR/test/tmp.ini'),'\r\n','\n'),'\n\n','\n');;
+REPLACE(REPLACE(LOAD_FILE('DATADIR/test/tmp.ini'),'\r\n','\n'),'\n\n','\n')
+[10]
+c2=10
+[20]
+c2=20
+[300]
+c2=300
+[4000]
+c2=4000
+[a b]
+c2=c d
+
+#
+# Testing bad table
+#
+CREATE TABLE t1
+(
+id INT
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.ini';
+INSERT INTO t1 VALUES (10);
+ERROR HY000: Got error 122 'Section name must come first on Insert' from CONNECT
+SELECT * FROM t1;
+id
+DROP TABLE t1;
+#
+# Testing READONLY tables
+#
+CREATE TABLE t1
+(
+contact CHAR(10) flag=1,
+c2 CHAR(60)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.ini';
+INSERT INTO t1 VALUES ('UK',10),('FR',20),('RU',30);
+SELECT * FROM t1;
+contact c2
+UK 10
+FR 20
+RU 30
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `contact` char(10) DEFAULT NULL `flag`=1,
+ `c2` char(60) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=INI `FILE_NAME`='t1.ini' `READONLY`=1
+INSERT INTO t1 VALUES ('US',40);
+ERROR HY000: Table 't1' is read only
+UPDATE t1 SET c2=20 WHERE c2=10;
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+DELETE FROM t1 WHERE c2=10;
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+TRUNCATE TABLE t1;
+ERROR HY000: Table 't1' is read only
+ALTER TABLE t1 READONLY=0;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `contact` char(10) DEFAULT NULL `flag`=1,
+ `c2` char(60) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=INI `FILE_NAME`='t1.ini' `READONLY`=0
+INSERT INTO t1 VALUES ('US',40);
+SELECT * FROM t1;
+contact c2
+UK 10
+FR 20
+RU 30
+US 40
+DROP TABLE t1;
+#
+# Bug: TABLE_TYPE=ini does not clear memory between CREATE TABLEs
+#
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+Warnings:
+Warning 1105 No file name. Table will use t1.ini
+INSERT INTO t1 VALUES ('sec1','val1'),('sec2','val2');
+SELECT sec AS s, val AS v FROM t1;
+s v
+sec1 val1
+sec2 val2
+DROP TABLE t1;
+CREATE TABLE t1 (sec2 CHAR(10) NOT NULL FLAG=1, val2 CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+Warnings:
+Warning 1105 No file name. Table will use t1.ini
+INSERT INTO t1 VALUES ('sec1','val11'),('sec2','val22');
+SELECT sec2 AS s, val2 AS v FROM t1;
+s v
+sec1 val11
+sec2 val22
+SELECT REPLACE(REPLACE(LOAD_FILE('DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n');;
+REPLACE(REPLACE(LOAD_FILE('DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n')
+[sec1]
+val2=val11
+[sec2]
+val2=val22
+
+DROP TABLE t1;
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+Warnings:
+Warning 1105 No file name. Table will use t1.ini
+CREATE TABLE t2 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+Warnings:
+Warning 1105 No file name. Table will use t2.ini
+INSERT INTO t1 VALUES('1sec1','1val1'),('1sec2','1val2');
+INSERT INTO t2 VALUES('2sec1','2val1'),('2sec2','2val2');
+SELECT sec AS s, val AS v FROM t1;
+s v
+1sec1 1val1
+1sec2 1val2
+SELECT REPLACE(REPLACE(LOAD_FILE('DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n');;
+REPLACE(REPLACE(LOAD_FILE('DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n')
+[1sec1]
+val=1val1
+[1sec2]
+val=1val2
+
+SELECT sec AS s, val AS v FROM t2;
+s v
+2sec1 2val1
+2sec2 2val2
+SELECT REPLACE(REPLACE(LOAD_FILE('DATADIR/test/t2.ini'),'\r\n','\n'),'\n\n','\n');;
+REPLACE(REPLACE(LOAD_FILE('DATADIR/test/t2.ini'),'\r\n','\n'),'\n\n','\n')
+[2sec1]
+val=2val1
+[2sec2]
+val=2val2
+
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/r/ini_grant.result b/storage/connect/mysql-test/connect/r/ini_grant.result
new file mode 100644
index 00000000..96d5e192
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/ini_grant.result
@@ -0,0 +1,89 @@
+#
+# Checking FILE privileges
+#
+set sql_mode="";
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+set sql_mode=default;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI;
+Warnings:
+Warning 1105 No file name. Table will use t1.ini
+INSERT INTO t1 VALUES ('sec1','val1');
+SELECT * FROM t1;
+sec val
+sec1 val1
+UPDATE t1 SET val='val11';
+SELECT * FROM t1;
+sec val
+sec1 val11
+DELETE FROM t1;
+SELECT * FROM t1;
+sec val
+INSERT INTO t1 VALUES('sec2','val2');
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+sec val
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+sec val
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES ('sec1','val1');
+connection user;
+SELECT user();
+user()
+user@localhost
+INSERT INTO t1 VALUES ('sec2','val2');
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET val='val11';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES ('sec3','val3');
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET val='val11';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+disconnect user;
+connection default;
+DROP VIEW v1;
+DROP TABLE t1;
+DROP USER user@localhost;
+#
+# Checking FILE privileges: done
+#
diff --git a/storage/connect/mysql-test/connect/r/jdbc.result b/storage/connect/mysql-test/connect/r/jdbc.result
new file mode 100644
index 00000000..b42311b8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/jdbc.result
@@ -0,0 +1,284 @@
+SET GLOBAL time_zone='+0:00';
+SET time_zone='+0:00';
+CREATE DATABASE connect;
+USE connect;
+CREATE TABLE t2 (
+id bigint not null,
+msg varchar(500),
+tm time,
+dt date,
+dtm datetime,
+ts timestamp);
+INSERT INTO t2 VALUES(455000000000, 'A very big number', '18:10:25', '2016-03-16', '1999-12-11 23:01:52', '2015-07-24 09:32:45');
+SELECT * FROM t2;
+id msg tm dt dtm ts
+455000000000 A very big number 18:10:25 2016-03-16 1999-12-11 23:01:52 2015-07-24 09:32:45
+#
+# Testing JDBC connection to MySQL driver
+#
+USE test;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME=t2 CONNECTION='jdbc:mysql://localhost:PORT/connect?user=root&useSSL=false';
+SELECT * FROM t1;
+id msg tm dt dtm ts
+455000000000 A very big number 18:10:25 2016-03-16 1999-12-11 23:01:52 2015-07-24 09:32:45
+INSERT INTO t1 VALUES(786325481247, 'Hello!', '19:45:03', '1933-08-10', '1985-11-12 09:02:44', '2014-06-17 10:32:01');
+Warnings:
+Note 1105 t2: 1 affected rows
+SELECT * FROM t1;
+id msg tm dt dtm ts
+455000000000 A very big number 18:10:25 2016-03-16 1999-12-11 23:01:52 2015-07-24 09:32:45
+786325481247 Hello! 19:45:03 1933-08-10 1985-11-12 09:02:44 2014-06-17 10:32:01
+DELETE FROM t1 WHERE msg = 'Hello!';
+Warnings:
+Note 1105 t2: 1 affected rows
+SELECT * FROM t1;
+id msg tm dt dtm ts
+455000000000 A very big number 18:10:25 2016-03-16 1999-12-11 23:01:52 2015-07-24 09:32:45
+DROP TABLE t1;
+#
+# Testing JDBC view
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC SRCDEF='select id, msg, tm, dt from t2' CONNECTION='jdbc:mysql://localhost:PORT/connect?user=root&useSSL=false';
+SELECT * FROM t1;
+id msg tm dt
+455000000000 A very big number 18:10:25 2016-03-16
+SELECT msg, dt FROM t1;
+msg dt
+A very big number 2016-03-16
+DROP TABLE t1, connect.t2;
+#
+# Testing JDBC write operations
+#
+USE connect;
+CREATE TABLE boys (
+name CHAR(12) NOT NULL,
+city CHAR(11),
+birth DATE DATE_FORMAT='DD/MM/YYYY',
+hired DATE DATE_FORMAT='DD/MM/YYYY' flag=36)
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' ENDING=1;
+SELECT * FROM boys;
+name city birth hired
+John Boston 1986-01-25 2010-06-02
+Henry Boston 1987-06-07 2008-04-01
+George San Jose 1981-08-10 2010-06-02
+Sam Chicago 1979-11-22 2007-10-10
+James Dallas 1992-05-13 2009-12-14
+Bill Boston 1986-09-11 2008-02-10
+USE test;
+CREATE TABLE t3 (
+name CHAR(12) NOT NULL,
+city CHAR(12),
+birth DATE,
+hired DATE);
+INSERT INTO t3 VALUES('Donald','Atlanta','1999-04-01','2016-03-31'),('Mick','New York','1980-01-20','2002-09-11');
+SELECT * FROM t3;
+name city birth hired
+Donald Atlanta 1999-04-01 2016-03-31
+Mick New York 1980-01-20 2002-09-11
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME=boys CONNECTION='jdbc:mysql://localhost:PORT/connect?user=root&useSSL=false' OPTION_LIST='scrollable=1';
+SELECT * FROM t1;
+name city birth hired
+John Boston 1986-01-25 2010-06-02
+Henry Boston 1987-06-07 2008-04-01
+George San Jose 1981-08-10 2010-06-02
+Sam Chicago 1979-11-22 2007-10-10
+James Dallas 1992-05-13 2009-12-14
+Bill Boston 1986-09-11 2008-02-10
+UPDATE t1 SET city = 'Phoenix' WHERE name = 'Henry';
+Warnings:
+Note 1105 boys: 1 affected rows
+INSERT INTO t1 SELECT * FROM t3;
+Warnings:
+Note 1105 boys: 2 affected rows
+INSERT INTO t1 VALUES('Tom','Seatle','2002-03-15',NULL);
+Warnings:
+Note 1105 boys: 1 affected rows
+SELECT * FROM t1;
+name city birth hired
+John Boston 1986-01-25 2010-06-02
+Henry Phoenix 1987-06-07 2008-04-01
+George San Jose 1981-08-10 2010-06-02
+Sam Chicago 1979-11-22 2007-10-10
+James Dallas 1992-05-13 2009-12-14
+Bill Boston 1986-09-11 2008-02-10
+Donald Atlanta 1999-04-01 2016-03-31
+Mick New York 1980-01-20 2002-09-11
+Tom Seatle 2002-03-15 NULL
+DROP TABLE t3;
+#
+# Testing JDBC join operations
+#
+CREATE TABLE t3 (
+name CHAR(9) NOT NULL,
+city CHAR(12) NOT NULL,
+age INT(2))
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='girls.txt' ENDING=1;
+SELECT g.name, b.name, g.city FROM t3 g STRAIGHT_JOIN connect.boys b where g.city = b.city;
+name name city
+Mary John Boston
+Susan Sam Chicago
+Betty Sam Chicago
+Mary Bill Boston
+SELECT g.name, b.name, g.city FROM t3 g STRAIGHT_JOIN t1 b where g.city = b.city;
+name name city
+Mary John Boston
+Susan Sam Chicago
+Betty Sam Chicago
+Mary Bill Boston
+DROP TABLE t1, t3, connect.boys;
+#
+# Testing MariaDB JDBC driver
+#
+USE connect;
+CREATE TABLE emp (
+serialno CHAR(5) NOT NULL,
+name VARCHAR(12) NOT NULL FLAG=6,
+sex TINYINT(1) NOT NULL,
+title VARCHAR(15) NOT NULL FLAG=20,
+manager CHAR(5) NOT NULL,
+department CHAR(4) NOT NULL FLAG=41,
+secretary CHAR(5) NOT NULL FLAG=46,
+salary DOUBLE(8,2) NOT NULL FLAG=52)
+ENGINE=connect TABLE_TYPE=fix FILE_NAME='employee.dat' ENDING=1;
+SELECT * FROM emp;
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+#
+# Option Driver is required to find the Driver class inside the executable jar file
+#
+USE test;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME=emp CONNECTION='jdbc:mariadb://localhost:PORT/connect?user=root' OPTION_LIST='Driver=org.mariadb.jdbc.Driver';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `serialno` char(5) NOT NULL,
+ `name` varchar(12) NOT NULL,
+ `sex` tinyint(3) NOT NULL,
+ `title` varchar(15) NOT NULL,
+ `manager` char(5) NOT NULL,
+ `department` char(4) NOT NULL,
+ `secretary` char(5) NOT NULL,
+ `salary` double(12,2) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mariadb://localhost:PORT/connect?user=root' `TABLE_TYPE`='JDBC' `TABNAME`='emp' `OPTION_LIST`='Driver=org.mariadb.jdbc.Driver'
+SELECT * FROM t1;
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+SELECT name, title, salary FROM t1 WHERE sex = 1;
+name title salary
+SMITH ENGINEER 9000.00
+MERCHANT SALESMAN 8700.00
+FUNNIGUY ADMINISTRATOR 8500.00
+BUGHAPPY PROGRAMMER 8500.00
+BIGHEAD SCIENTIST 8000.00
+WALTER ENGINEER 7400.00
+FODDERMAN SALESMAN 7000.00
+TONGHO ENGINEER 6800.00
+GOOSEPEN ADMINISTRATOR 4700.00
+STRONG DIRECTOR 23000.00
+BULLOZER SALESMAN 14800.00
+WERTHER DIRECTOR 14500.00
+QUINN DIRECTOR 14000.00
+ORELLY ENGINEER 13400.00
+BIGHORN SCIENTIST 11000.00
+BROWNY ENGINEER 10500.00
+WHEELFOR SALESMAN 10030.00
+MARTIN ENGINEER 10000.00
+DROP TABLE t1, connect.emp;
+CREATE TABLE t2 (command varchar(128) not null,number int(5) not null flag=1,message varchar(255) flag=2) ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:mariadb://localhost:PORT/connect' OPTION_LIST='User=root,Execsrc=1';
+SELECT * FROM t2 WHERE command='drop table tx1';
+command number message
+drop table tx1 0 Execute: java.sql.SQLSyntaxErrorException: (conn:24) Unknown table 'connect.tx1'
+Warnings:
+Warning 1105 Execute: java.sql.SQLSyntaxErrorException: (conn:24) Unknown table 'connect.tx1'
+SELECT * FROM t2 WHERE command = 'create table tx1 (a int not null, b char(32), c double(8,2))';
+command number message
+create table tx1 (a int not null, b char(32), c double(8,2)) 0 Affected rows
+Warnings:
+Warning 1105 Affected rows
+SELECT * FROM t2 WHERE command in ('insert into tx1 values(1,''The number one'',456.12)',"insert into tx1(a,b) values(2,'The number two'),(3,'The number three')");
+command number message
+insert into tx1 values(1,'The number one',456.12) 1 Affected rows
+insert into tx1(a,b) values(2,'The number two'),(3,'The number three') 2 Affected rows
+Warnings:
+Warning 1105 Affected rows
+SELECT * FROM t2 WHERE command='update tx1 set c = 3.1416 where a = 2';
+command number message
+update tx1 set c = 3.1416 where a = 2 1 Affected rows
+Warnings:
+Warning 1105 Affected rows
+SELECT * FROM t2 WHERE command='select * from tx1';
+command number message
+select * from tx1 3 Result set column number
+Warnings:
+Warning 1105 Result set column number
+SELECT * FROM t2 WHERE command='delete from tx1 where a = 2';
+command number message
+delete from tx1 where a = 2 1 Affected rows
+Warnings:
+Warning 1105 Affected rows
+SELECT * FROM connect.tx1;
+a b c
+1 The number one 456.12
+3 The number three NULL
+DROP TABLE t2;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=tables CONNECTION='jdbc:mariadb://localhost:PORT/connect' option_list='User=root,Maxres=50';
+SELECT * FROM t1;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+connect NULL tx1 TABLE
+DROP TABLE t1;
+DROP TABLE connect.tx1;
+DROP DATABASE connect;
+SET GLOBAL time_zone=SYSTEM;
+SET time_zone=SYSTEM;
diff --git a/storage/connect/mysql-test/connect/r/jdbc_new.result b/storage/connect/mysql-test/connect/r/jdbc_new.result
new file mode 100644
index 00000000..a47fb9cc
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/jdbc_new.result
@@ -0,0 +1,234 @@
+connect master,127.0.0.1,root,,test,$MASTER_MYPORT,;
+connect slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
+connection master;
+connection slave;
+SET GLOBAL time_zone='+0:00';
+SET time_zone='+0:00';
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+#
+# Testing errors
+#
+connection master;
+SET GLOBAL time_zone='+0:00';
+SET time_zone='+0:00';
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=unknown&useSSL=false';
+ERROR HY000: Connecting: java.sql.SQLException: Access denied for user 'unknown'@'localhost' (using password: NO) rc=-2
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/unknown?user=root&useSSL=false';
+ERROR HY000: Connecting: java.sql.SQLSyntaxErrorException: Unknown database 'unknown' rc=-2
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME='unknown'
+ CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+ERROR HY000: Cannot get columns from unknown
+SHOW CREATE TABLE t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+CREATE TABLE t1 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL,
+ `y` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false' `TABLE_TYPE`=JDBC
+SELECT * FROM t1;
+ERROR HY000: Got error 174 'ExecuteQuery: java.sql.SQLSyntaxErrorException: Unknown column 'x' in 'field list'' from CONNECT
+DROP TABLE t1;
+CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+connection slave;
+ALTER TABLE t1 RENAME t1backup;
+connection master;
+SELECT * FROM t1;
+ERROR HY000: Got error 174 'ExecuteQuery: java.sql.SQLSyntaxErrorException: Table 'test.t1' doesn't exist' from CONNECT
+connection slave;
+ALTER TABLE t1backup RENAME t1;
+connection master;
+DROP TABLE t1;
+#
+# Testing SELECT, etc.
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(10) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false' `TABLE_TYPE`='JDBC'
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME='t1'
+ CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false' `TABLE_TYPE`=JDBC `TABNAME`='t1'
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false' `TABLE_TYPE`=JDBC
+SELECT * FROM t1;
+a b
+0
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(10) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false' `TABLE_TYPE`=JDBC
+SELECT * FROM t1;
+a b
+NULL NULL
+0 0
+1 0
+2 0
+3 0
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+#
+# Testing numeric data types
+#
+CREATE TABLE t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float, g double, h decimal(20,5));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` tinyint(4) DEFAULT NULL,
+ `b` smallint(6) DEFAULT NULL,
+ `c` mediumint(9) DEFAULT NULL,
+ `d` int(11) DEFAULT NULL,
+ `e` bigint(20) DEFAULT NULL,
+ `f` float DEFAULT NULL,
+ `g` double DEFAULT NULL,
+ `h` decimal(20,5) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265);
+connection master;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` tinyint(3) DEFAULT NULL,
+ `b` smallint(5) DEFAULT NULL,
+ `c` int(7) DEFAULT NULL,
+ `d` int(10) DEFAULT NULL,
+ `e` bigint(19) DEFAULT NULL,
+ `f` double(14,0) DEFAULT NULL,
+ `g` double(24,0) DEFAULT NULL,
+ `h` decimal(27,5) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false' `TABLE_TYPE`='JDBC'
+SELECT * FROM t1;
+a b c d e f g h
+100 3333 41235 1234567890 235000000000 3 3 3141.59265
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+#
+# Testing character data types
+#
+CREATE TABLE t1 (a char(12), b varchar(12));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(12) DEFAULT NULL,
+ `b` varchar(12) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES('Welcome','Hello, World');
+SELECT * FROM t1;
+a b
+Welcome Hello, World
+connection master;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(12) DEFAULT NULL,
+ `b` varchar(12) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false' `TABLE_TYPE`='JDBC'
+SELECT * FROM t1;
+a b
+Welcome Hello, World
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+#
+# Testing temporal data types
+#
+CREATE TABLE t1 (a date, b datetime, c time, d timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, e year);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` date DEFAULT NULL,
+ `b` datetime DEFAULT NULL,
+ `c` time DEFAULT NULL,
+ `d` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `e` year(4) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT IGNORE INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23');
+Warnings:
+Note 1265 Data truncated for column 'a' at row 1
+Note 1265 Data truncated for column 'c' at row 1
+Warning 1265 Data truncated for column 'e' at row 1
+SELECT * FROM t1;
+a b c d e
+2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003
+connection master;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` date DEFAULT NULL,
+ `b` datetime DEFAULT NULL,
+ `c` time DEFAULT NULL,
+ `d` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `e` year(4) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='jdbc:mysql://127.0.0.1:SLAVE_PORT/test?user=root&useSSL=false' `TABLE_TYPE`='JDBC'
+SELECT * FROM t1;
+a b c d e
+2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+SET GLOBAL time_zone=SYSTEM;
+SET time_zone=SYSTEM;
+connection master;
+SET GLOBAL time_zone=SYSTEM;
+SET time_zone=SYSTEM;
diff --git a/storage/connect/mysql-test/connect/r/jdbc_oracle.result b/storage/connect/mysql-test/connect/r/jdbc_oracle.result
new file mode 100644
index 00000000..21a2d10f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/jdbc_oracle.result
@@ -0,0 +1,76 @@
+CREATE TABLE t2 (
+command varchar(128) not null,
+number int(5) not null flag=1,
+message varchar(255) flag=2)
+ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:oracle:thin:@localhost:1521:xe'
+OPTION_LIST='User=system,Password=Biscote01,Execsrc=1';
+SELECT * FROM t2 WHERE command = 'drop table employee';
+command number message
+drop table employee 0 Execute: java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
+
+Warnings:
+Warning 1105 Execute: java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
+
+SELECT * FROM t2 WHERE command = 'create table employee (id int not null, name varchar(32), title char(16), salary number(8,2))';
+command number message
+create table employee (id int not null, name varchar(32), title char(16), salary number(8,2)) 0 Affected rows
+Warnings:
+Warning 1105 Affected rows
+SELECT * FROM t2 WHERE command = "insert into employee values(4567,'Johnson', 'Engineer', 12560.50)";
+command number message
+insert into employee values(4567,'Johnson', 'Engineer', 12560.50) 1 Affected rows
+Warnings:
+Warning 1105 Affected rows
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=tables
+CONNECTION='jdbc:oracle:thin:@localhost:1521:xe'
+OPTION_LIST='User=system,Password=Biscote01';
+SELECT * FROM t1 WHERE table_name='employee';
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL SYSTEM EMPLOYEE TABLE NULL
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME='EMPLOYEE' CATFUNC=columns
+CONNECTION='jdbc:oracle:thin:@localhost:1521:xe'
+OPTION_LIST='User=system,Password=Biscote01';
+SELECT * FROM t1;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+NULL SYSTEM EMPLOYEE ID 3 NUMBER 38 0 0 10 0 NULL
+NULL SYSTEM EMPLOYEE NAME 12 VARCHAR2 32 0 NULL 10 1 NULL
+NULL SYSTEM EMPLOYEE TITLE 1 CHAR 16 0 NULL 10 1 NULL
+NULL SYSTEM EMPLOYEE SALARY 3 NUMBER 8 0 2 10 1 NULL
+DROP TABLE t1;
+CREATE SERVER 'oracle' FOREIGN DATA WRAPPER 'oracle.jdbc.driver.OracleDriver' OPTIONS (
+HOST 'jdbc:oracle:thin:@localhost:1521:xe',
+DATABASE 'SYSTEM',
+USER 'system',
+PASSWORD 'Biscote01',
+PORT 0,
+SOCKET '',
+OWNER 'SYSTEM');
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='oracle' tabname='EMPLOYEE';
+SELECT * FROM t1;
+ID NAME TITLE SALARY
+4567 Johnson Engineer 12560.50
+INSERT INTO t1 VALUES(6214, 'Clinton', 'Retired', NULL);
+Warnings:
+Note 1105 EMPLOYEE: 1 affected rows
+UPDATE t1 set name='Trump' WHERE id = 4567;
+Warnings:
+Note 1105 EMPLOYEE: 1 affected rows
+SELECT * FROM t1;
+ID NAME TITLE SALARY
+4567 Trump Engineer 12560.50
+6214 Clinton Retired NULL
+DELETE FROM t1 WHERE id = 6214;
+Warnings:
+Note 1105 EMPLOYEE: 1 affected rows
+SELECT * FROM t1;
+ID NAME TITLE SALARY
+4567 Trump Engineer 12560.50
+DROP TABLE t1;
+SELECT * FROM t2 WHERE command = 'drop table employee';
+command number message
+drop table employee 0 Affected rows
+Warnings:
+Warning 1105 Affected rows
+DROP TABLE t2;
+DROP SERVER 'oracle';
diff --git a/storage/connect/mysql-test/connect/r/jdbc_postgresql.result b/storage/connect/mysql-test/connect/r/jdbc_postgresql.result
new file mode 100644
index 00000000..07cc3c46
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/jdbc_postgresql.result
@@ -0,0 +1,74 @@
+SET GLOBAL connect_class_path='C:/MariaDB-10.2/MariaDB/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar;C:/Jconnectors/postgresql-42.2.1.jar';
+CREATE TABLE t2 (
+command varchar(128) not null,
+number int(5) not null flag=1,
+message varchar(255) flag=2)
+ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono'
+OPTION_LIST='Execsrc=1';
+SELECT * FROM t2 WHERE command='drop table employee';
+command number message
+drop table employee 0 Execute: org.postgresql.util.PSQLException: ERREUR: la table « employee » n'existe pas
+Warnings:
+Warning 1105 Execute: org.postgresql.util.PSQLException: ERREUR: la table « employee » n'existe pas
+SELECT * FROM t2 WHERE command = 'create table employee (id int not null, name varchar(32), title char(16), salary decimal(8,2))';
+command number message
+create table employee (id int not null, name varchar(32), title char(16), salary decimal(8,2)) 0 Affected rows
+Warnings:
+Warning 1105 Affected rows
+SELECT * FROM t2 WHERE command = "insert into employee values(4567,'Johnson', 'Engineer', 12560.50)";
+command number message
+insert into employee values(4567,'Johnson', 'Engineer', 12560.50) 1 Affected rows
+Warnings:
+Warning 1105 Affected rows
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=tables
+CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono'
+OPTION_LIST='Tabtype=TABLE,Maxres=10';
+SELECT * FROM t1;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL public employee TABLE NULL
+NULL public t1 TABLE NULL
+NULL public t2 TABLE NULL
+NULL public tchar TABLE NULL
+NULL public testuuid TABLE NULL
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC tabname=employee CATFUNC=columns
+CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono';
+SELECT * FROM t1;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+NULL public employee id 4 int4 10 0 0 10 0 NULL
+NULL public employee name 12 varchar 32 0 0 10 1 NULL
+NULL public employee title 1 bpchar 16 0 0 10 1 NULL
+NULL public employee salary 2 numeric 8 0 2 10 1 NULL
+DROP TABLE t1;
+CREATE SERVER 'postgresql' FOREIGN DATA WRAPPER 'postgresql' OPTIONS (
+HOST 'localhost',
+DATABASE 'test',
+USER 'postgres',
+PASSWORD 'tinono',
+PORT 0,
+SOCKET '',
+OWNER 'root');
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='postgresql/public.employee';
+SELECT * FROM t1;
+id name title salary
+4567 Johnson Engineer 12560.50
+INSERT INTO t1 VALUES(3126,'Smith', 'Clerk', 5230.00);
+Warnings:
+Note 1105 public.employee: 1 affected rows
+UPDATE t1 SET salary = salary + 100.00;
+Warnings:
+Note 1105 public.employee: 2 affected rows
+SELECT * FROM t1;
+id name title salary
+4567 Johnson Engineer 12660.50
+3126 Smith Clerk 5330.00
+DROP TABLE t1;
+DROP SERVER 'postgresql';
+SELECT * FROM t2 WHERE command='drop table employee';
+command number message
+drop table employee 0 Affected rows
+Warnings:
+Warning 1105 Affected rows
+DROP TABLE t2;
diff --git a/storage/connect/mysql-test/connect/r/json.result b/storage/connect/mysql-test/connect/r/json.result
new file mode 100644
index 00000000..dc527acd
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/json.result
@@ -0,0 +1,517 @@
+#
+# Testing doc samples
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15),
+LANG CHAR(2),
+SUBJECT CHAR(32),
+AUTHOR CHAR(64),
+TITLE CHAR(32),
+TRANSLATION CHAR(32),
+TRANSLATOR CHAR(80),
+PUBLISHER CHAR(32),
+DATEPUB int(4)
+) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+ISBN LANG SUBJECT AUTHOR TITLE TRANSLATION TRANSLATOR PUBLISHER DATEPUB
+9782212090819 fr applications Jean-Christophe Bernadac, François Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+DROP TABLE t1;
+#
+# Testing Jpath. Get the number of authors
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15),
+Language CHAR(2) JPATH='$.LANG',
+Subject CHAR(32) JPATH='$.SUBJECT',
+Authors INT(2) JPATH='$.AUTHOR[#]',
+Title CHAR(32) JPATH='$.TITLE',
+Translation CHAR(32) JPATH='$.TRANSLATION',
+Translator CHAR(80) JPATH='$.TRANSLATOR',
+Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+ISBN Language Subject Authors Title Translation Translator Publisher Location Year
+9782212090819 fr applications 2 Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications 1 XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+DROP TABLE t1;
+#
+# Concatenates the authors
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15),
+Language CHAR(2) JPATH='$.LANG',
+Subject CHAR(32) JPATH='$.SUBJECT',
+AuthorFN CHAR(128) JPATH='$.AUTHOR[" and "].FIRSTNAME',
+AuthorLN CHAR(128) JPATH='$.AUTHOR[" and "].LASTNAME',
+Title CHAR(32) JPATH='$.TITLE',
+Translation CHAR(32) JPATH='$.TRANSLATION',
+Translator CHAR(80) JPATH='$.TRANSLATOR',
+Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
+9782212090819 fr applications Jean-Christophe and François Bernadac and Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+DROP TABLE t1;
+#
+# Testing expanding authors
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15),
+Language CHAR(2) JPATH='$.LANG',
+Subject CHAR(32) JPATH='$.SUBJECT',
+AuthorFN CHAR(128) JPATH='$.AUTHOR[*].FIRSTNAME',
+AuthorLN CHAR(128) JPATH='$.AUTHOR[*].LASTNAME',
+Title CHAR(32) JPATH='$.TITLE',
+Translation CHAR(32) JPATH='$.TRANSLATION',
+Translator CHAR(80) JPATH='$.TRANSLATOR',
+Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
+9782212090819 fr applications Jean-Christophe Bernadac Construire une application XML NULL NULL Eyrolles Paris 1999
+9782212090819 fr applications François Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+UPDATE t1 SET AuthorFN = 'Philippe' WHERE AuthorLN = 'Knab';
+SELECT * FROM t1 WHERE ISBN = '9782212090819';
+ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
+9782212090819 fr applications Jean-Christophe Bernadac Construire une application XML NULL NULL Eyrolles Paris 1999
+9782212090819 fr applications Philippe Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+#
+# To add an author a new table must be created
+#
+CREATE TABLE t2 (
+FIRSTNAME CHAR(32),
+LASTNAME CHAR(32))
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json' OPTION_LIST='Object=$[1].AUTHOR';
+SELECT * FROM t2;
+FIRSTNAME LASTNAME
+William J. Pardi
+INSERT INTO t2 VALUES('Charles','Dickens');
+SELECT * FROM t1;
+ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
+9782212090819 fr applications Jean-Christophe Bernadac Construire une application XML NULL NULL Eyrolles Paris 1999
+9782212090819 fr applications Philippe Knab Construire une application XML NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+9782840825685 fr applications Charles Dickens XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 1999
+DROP TABLE t1;
+DROP TABLE t2;
+#
+# Check the biblio file has the good format
+#
+CREATE TABLE t1
+(
+line char(255)
+)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='biblio.json';
+SELECT * FROM t1;
+line
+[
+ {
+ "ISBN": "9782212090819",
+ "LANG": "fr",
+ "SUBJECT": "applications",
+ "AUTHOR": [
+ {
+ "FIRSTNAME": "Jean-Christophe",
+ "LASTNAME": "Bernadac"
+ },
+ {
+ "FIRSTNAME": "Philippe",
+ "LASTNAME": "Knab"
+ }
+ ],
+ "TITLE": "Construire une application XML",
+ "PUBLISHER": {
+ "NAME": "Eyrolles",
+ "PLACE": "Paris"
+ },
+ "DATEPUB": 1999
+ },
+ {
+ "ISBN": "9782840825685",
+ "LANG": "fr",
+ "SUBJECT": "applications",
+ "AUTHOR": [
+ {
+ "FIRSTNAME": "William J.",
+ "LASTNAME": "Pardi"
+ },
+ {
+ "FIRSTNAME": "Charles",
+ "LASTNAME": "Dickens"
+ }
+ ],
+ "TITLE": "XML en Action",
+ "TRANSLATION": "adapté de l'anglais par",
+ "TRANSLATOR": {
+ "FIRSTNAME": "James",
+ "LASTNAME": "Guerin"
+ },
+ "PUBLISHER": {
+ "NAME": "Microsoft Press",
+ "PLACE": "Paris"
+ },
+ "DATEPUB": 1999
+ }
+]
+DROP TABLE t1;
+#
+# Testing a pretty=0 file
+#
+CREATE TABLE t1
+(
+ISBN CHAR(15) NOT NULL,
+Language CHAR(2) JPATH='$.LANG',
+Subject CHAR(32) JPATH='$.SUBJECT',
+AuthorFN CHAR(128) JPATH='$.AUTHOR[*].FIRSTNAME',
+AuthorLN CHAR(128) JPATH='$.AUTHOR[*].LASTNAME',
+Title CHAR(32) JPATH='$.TITLE',
+Translation CHAR(32) JPATH='$.TRANSLATED.PREFIX',
+TranslatorFN CHAR(80) JPATH='$.TRANSLATED.TRANSLATOR.FIRSTNAME',
+TranslatorLN CHAR(80) JPATH='$.TRANSLATED.TRANSLATOR.LASTNAME',
+Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+Year int(4) JPATH='$.DATEPUB',
+INDEX IX(ISBN)
+)
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bib0.json' LRECL=320 OPTION_LIST='Pretty=0';
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 1 IX 1 ISBN A NULL NULL NULL XINDEX
+SELECT * FROM t1;
+ISBN Language Subject AuthorFN AuthorLN Title Translation TranslatorFN TranslatorLN Publisher Location Year
+9782212090819 fr applications Jean-Michel Bernadac Construire une application XML NULL NULL NULL Eyrolles Paris 1999
+9782212090819 fr applications François Knab Construire une application XML NULL NULL NULL Eyrolles Paris 1999
+9782840825685 fr applications William J. Pardi XML en Action adapté de l'anglais par James Guerin Microsoft Press Paris 2001
+DESCRIBE SELECT * FROM t1 WHERE ISBN = '9782212090819';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref IX IX 15 const 1 Using where
+UPDATE t1 SET AuthorFN = 'Philippe' WHERE ISBN = '9782212090819';
+ERROR HY000: Got error 122 'Cannot write expanded column when Pretty is not 2' from CONNECT
+DROP TABLE t1;
+#
+# A file with 2 arrays
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[*].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[].EXPENSE["+"].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[].EXPENSE[+].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer+Food+Food+Car 69.00
+Joe 4 Beer+Beer+Food+Food+Beer 83.00
+Joe 5 Beer+Food 26.00
+Beth 3 Beer 16.00
+Beth 4 Food+Beer 32.00
+Beth 5 Food+Beer 32.00
+Janet 3 Car+Food+Beer 55.00
+Janet 4 Car 17.00
+Janet 5 Beer+Car+Beer+Food 57.00
+DROP TABLE t1;
+#
+# Now it can be fully expanded
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[*].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[*].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[*].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 3 Beer 16.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+Janet 4 Car 17.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+DROP TABLE t1;
+#
+# A table showing many calculated results
+#
+CREATE TABLE t1 (
+WHO CHAR(12) NOT NULL,
+WEEKS CHAR(12) NOT NULL JPATH='$.WEEK[", "].NUMBER',
+SUMS CHAR(64) NOT NULL JPATH='$.WEEK["+"].EXPENSE[+].AMOUNT',
+SUM DOUBLE(8,2) NOT NULL JPATH='$.WEEK[+].EXPENSE[+].AMOUNT',
+AVGS CHAR(64) NOT NULL JPATH='$.WEEK["+"].EXPENSE[!].AMOUNT',
+SUMAVG DOUBLE(8,2) NOT NULL JPATH='$.WEEK[+].EXPENSE[!].AMOUNT',
+AVGSUM DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[+].AMOUNT',
+AVGAVG DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[!].AMOUNT',
+AVERAGE DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+WHO WEEKS SUMS SUM AVGS SUMAVG AVGSUM AVGAVG AVERAGE
+Joe 3, 4, 5 69.00+83.00+26.00 178.00 17.25+16.60+13.00 46.85 59.33 15.62 16.18
+Beth 3, 4, 5 16.00+32.00+32.00 80.00 16.00+16.00+16.00 48.00 26.67 16.00 16.00
+Janet 3, 4, 5 55.00+17.00+57.00 129.00 18.33+17.00+14.25 49.58 43.00 16.53 16.12
+DROP TABLE t1;
+#
+# Expand expense in 3 one week tables
+#
+CREATE TABLE t2 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[0].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[0].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[0].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t2;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Beth 3 Beer 16.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+CREATE TABLE t3 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[1].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[1].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[1].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t3;
+WHO WEEK WHAT AMOUNT
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+CREATE TABLE t4 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[2].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[2].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[2].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t4;
+WHO WEEK WHAT AMOUNT
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+#
+# The expanded table is made as a TBL table
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32),
+AMOUNT DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t2,t3,t4';
+SELECT * FROM t1;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Beth 3 Beer 16.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+DROP TABLE t1, t2, t3, t4;
+#
+# Three partial JSON tables
+#
+CREATE TABLE t2 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp3.json';
+SELECT * FROM t2;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Beth 3 Beer 16.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+CREATE TABLE t3 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp4.json';
+SELECT * FROM t3;
+WHO WEEK WHAT AMOUNT
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+CREATE TABLE t4 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp5.json';
+SELECT * FROM t4;
+WHO WEEK WHAT AMOUNT
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+#
+# The complete table can be a multiple JSON table
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp*.json' MULTIPLE=1;
+SELECT * FROM t1 ORDER BY WHO, WEEK, WHAT, AMOUNT;
+WHO WEEK WHAT AMOUNT
+Beth 3 Beer 16.00
+Beth 4 Beer 15.00
+Beth 4 Food 17.00
+Beth 5 Beer 20.00
+Beth 5 Food 12.00
+Janet 3 Beer 18.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 4 Car 17.00
+Janet 5 Beer 14.00
+Janet 5 Beer 19.00
+Janet 5 Car 12.00
+Janet 5 Food 12.00
+Joe 3 Beer 18.00
+Joe 3 Car 20.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 4 Beer 14.00
+Joe 4 Beer 16.00
+Joe 4 Beer 19.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+DROP TABLE t1;
+#
+# Or also a partition JSON table
+#
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp%s.json';
+ALTER TABLE t1
+PARTITION BY LIST COLUMNS(WEEK) (
+PARTITION `3` VALUES IN(3),
+PARTITION `4` VALUES IN(4),
+PARTITION `5` VALUES IN(5));
+Warnings:
+Warning 1105 Data repartition in 3 is unchecked
+Warning 1105 Data repartition in 4 is unchecked
+Warning 1105 Data repartition in 5 is unchecked
+SHOW WARNINGS;
+Level Code Message
+Warning 1105 Data repartition in 3 is unchecked
+Warning 1105 Data repartition in 4 is unchecked
+Warning 1105 Data repartition in 5 is unchecked
+SELECT * FROM t1;
+WHO WEEK WHAT AMOUNT
+Joe 3 Beer 18.00
+Joe 3 Food 12.00
+Joe 3 Food 19.00
+Joe 3 Car 20.00
+Beth 3 Beer 16.00
+Janet 3 Car 19.00
+Janet 3 Food 18.00
+Janet 3 Beer 18.00
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+Joe 5 Beer 14.00
+Joe 5 Food 12.00
+Beth 5 Food 12.00
+Beth 5 Beer 20.00
+Janet 5 Beer 14.00
+Janet 5 Car 12.00
+Janet 5 Beer 19.00
+Janet 5 Food 12.00
+SELECT * FROM t1 WHERE WEEK = 4;
+WHO WEEK WHAT AMOUNT
+Joe 4 Beer 19.00
+Joe 4 Beer 16.00
+Joe 4 Food 17.00
+Joe 4 Food 17.00
+Joe 4 Beer 14.00
+Beth 4 Food 17.00
+Beth 4 Beer 15.00
+Janet 4 Car 17.00
+DROP TABLE t1, t2, t3, t4;
diff --git a/storage/connect/mysql-test/connect/r/json_java_2.result b/storage/connect/mysql-test/connect/r/json_java_2.result
new file mode 100644
index 00000000..c0550101
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/json_java_2.result
@@ -0,0 +1,385 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants CONNECTION='mongodb://localhost:27017' LRECL=4096
+OPTION_LIST='Driver=Java,Version=2' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51c"},"address":{"building":"1007","coord":[-73.856077,40.848447],"street":"Morris Park Ave","zipcode":"10462"},"borough":"Bronx","cuisine":"Bakery","grades":[{"date":{"$date":"2014-03-03T00:00:00.000Z"},"grade":"A","score":2},{"date":{"$date":"2013-09-11T00:00:00.000Z"},"grade":"A","score":6},{"date":{"$date":"2013-01-24T00:00:00.000Z"},"grade":"A","score":10},{"date":{"$date":"2011-11-23T00:00:00.000Z"},"grade":"A","score":9},{"date":{"$date":"2011-03-10T00:00:00.000Z"},"grade":"B","score":14}],"name":"Morris Park Bake Shop","restaurant_id":"30075445"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51d"},"address":{"building":"469","coord":[-73.961704,40.662942],"street":"Flatbush Avenue","zipcode":"11225"},"borough":"Brooklyn","cuisine":"Hamburgers","grades":[{"date":{"$date":"2014-12-30T00:00:00.000Z"},"grade":"A","score":8},{"date":{"$date":"2014-07-01T00:00:00.000Z"},"grade":"B","score":23},{"date":{"$date":"2013-04-30T00:00:00.000Z"},"grade":"A","score":12},{"date":{"$date":"2012-05-08T00:00:00.000Z"},"grade":"A","score":12}],"name":"Wendy'S","restaurant_id":"30112340"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51e"},"address":{"building":"351","coord":[-73.985136,40.767692],"street":"West 57 Street","zipcode":"10019"},"borough":"Manhattan","cuisine":"Irish","grades":[{"date":{"$date":"2014-09-06T00:00:00.000Z"},"grade":"A","score":2},{"date":{"$date":"2013-07-22T00:00:00.000Z"},"grade":"A","score":11},{"date":{"$date":"2012-07-31T00:00:00.000Z"},"grade":"A","score":12},{"date":{"$date":"2011-12-29T00:00:00.000Z"},"grade":"A","score":12}],"name":"Dj Reynolds Pub And Restaurant","restaurant_id":"30191841"}
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=Java,Version=2' DATA_CHARSET=utf8 CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
+_id 1 CHAR 24 24 0 0 _id
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 1024 1024 0 1 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
+grades_grade 1 CHAR 14 14 0 1 grades.0.grade
+grades_score 7 INTEGER 2 2 0 1 grades.0.score
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096 DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=Java,Version=2' `DATA_CHARSET`='utf8' `LRECL`=4096
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_date grades_grade grades_score name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 -73.856077, 40.848447 Morris Park Ave 10462 Bronx Bakery 2014-03-03T00:00:00.000Z A 2 Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 -73.961704, 40.662942 Flatbush Avenue 11225 Brooklyn Hamburgers 2014-12-30T00:00:00.000Z A 8 Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 -73.98513559999999, 40.7676919 West 57 Street 10019 Manhattan Irish 2014-09-06T00:00:00.000Z A 2 Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 -73.98241999999999, 40.579505 Stillwell Avenue 11224 Brooklyn American 2014-06-10T00:00:00.000Z A 5 Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 -73.8601152, 40.7311739 63 Road 11374 Queens Jewish/Kosher 2014-11-24T00:00:00.000Z Z 20 Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"grades":0}' OPTION_LIST='Driver=Java,Version=2,level=0' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 (-73.856077, 40.848447) Morris Park Ave 10462 Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 (-73.961704, 40.662942) Flatbush Avenue 11225 Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 (-73.98513559999999, 40.7676919) West 57 Street 10019 Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 (-73.98241999999999, 40.579505) Stillwell Avenue 11224 Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 (-73.8601152, 40.7311739) 63 Road 11374 Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 8825 (-73.8803827, 40.7643124) Astoria Boulevard 11369 Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 2206 (-74.1377286, 40.6119572) Victory Boulevard 10314 Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 7114 (-73.9068506, 40.6199034) Avenue U 11234 Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 6409 (-74.00528899999999, 40.628886) 11 Avenue 11219 Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 1839 (-73.9482609, 40.6408271) Nostrand Avenue 11226 Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 1970-01-01
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 1970-01-01
+Wendy'S Flatbush Avenue 8 1970-01-01
+Dj Reynolds Pub And Restaurant West 57 Street 2 1970-01-01
+Riviera Caterer Stillwell Avenue 5 1970-01-01
+Tov Kosher Kitchen 63 Road 20 1970-01-01
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 1970-01-01 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 1970-01-01 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 1970-01-01 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 1970-01-01 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 1970-01-01 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 1970-01-01 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 1970-01-01 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 1970-01-01 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 1970-01-01 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 1970-01-01 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 1970-01-01 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 1970-01-01 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 1970-01-01 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 1970-01-01 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 1970-01-01 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 1970-01-01 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 1970-01-01 01:33:34 B 15
+Tout Va Bien Manhattan 1970-01-01 01:33:34 A 13
+Tout Va Bien Manhattan 1970-01-01 01:33:33 C 36
+Tout Va Bien Manhattan 1970-01-01 01:33:33 B 22
+Tout Va Bien Manhattan 1970-01-01 01:33:32 C 36
+Tout Va Bien Manhattan 1970-01-01 01:33:32 C 7
+La Grenouille Manhattan 1970-01-01 01:33:34 A 10
+La Grenouille Manhattan 1970-01-01 01:33:33 A 9
+La Grenouille Manhattan 1970-01-01 01:33:32 A 13
+Le Perigord Manhattan 1970-01-01 01:33:34 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 1970-01-01 01:33:34
+Bistro Sk A 12 1970-01-01 01:33:34
+Bistro Sk B 18 1970-01-01 01:33:33
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"cuisine":0}' CONNECTION='mongodb://localhost:27017' LRECL=4096
+OPTION_LIST='Driver=Java,level=2,version=2';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(18,16) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_date` char(24) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=2' `LRECL`=4096
+SELECT name, borough, address_street, grades_score AS score FROM t1 WHERE grades_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll'
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=JSON TABNAME='cities'
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096 DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=YES' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1;
+item total average
+journal 285 57.00
+notebook 1368 456.00
+paper 23 5.75
+planner 167 41.75
+postcard 23 5.75
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/json_java_3.result b/storage/connect/mysql-test/connect/r/json_java_3.result
new file mode 100644
index 00000000..b74f92bf
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/json_java_3.result
@@ -0,0 +1,385 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants CONNECTION='mongodb://localhost:27017' LRECL=4096
+OPTION_LIST='Driver=Java,Version=3' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51c"},"address":{"building":"1007","coord":[-73.856077,40.848447],"street":"Morris Park Ave","zipcode":"10462"},"borough":"Bronx","cuisine":"Bakery","grades":[{"date":{"$date":1393804800000},"grade":"A","score":2},{"date":{"$date":1378857600000},"grade":"A","score":6},{"date":{"$date":1358985600000},"grade":"A","score":10},{"date":{"$date":1322006400000},"grade":"A","score":9},{"date":{"$date":1299715200000},"grade":"B","score":14}],"name":"Morris Park Bake Shop","restaurant_id":"30075445"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51d"},"address":{"building":"469","coord":[-73.961704,40.662942],"street":"Flatbush Avenue","zipcode":"11225"},"borough":"Brooklyn","cuisine":"Hamburgers","grades":[{"date":{"$date":1419897600000},"grade":"A","score":8},{"date":{"$date":1404172800000},"grade":"B","score":23},{"date":{"$date":1367280000000},"grade":"A","score":12},{"date":{"$date":1336435200000},"grade":"A","score":12}],"name":"Wendy'S","restaurant_id":"30112340"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51e"},"address":{"building":"351","coord":[-73.985136,40.767692],"street":"West 57 Street","zipcode":"10019"},"borough":"Manhattan","cuisine":"Irish","grades":[{"date":{"$date":1409961600000},"grade":"A","score":2},{"date":{"$date":1374451200000},"grade":"A","score":11},{"date":{"$date":1343692800000},"grade":"A","score":12},{"date":{"$date":1325116800000},"grade":"A","score":12}],"name":"Dj Reynolds Pub And Restaurant","restaurant_id":"30191841"}
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=Java,Version=3' DATA_CHARSET=utf8 CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
+_id 1 CHAR 24 24 0 0 _id
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 1024 1024 0 1 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
+grades_grade 1 CHAR 14 14 0 1 grades.0.grade
+grades_score 7 INTEGER 2 2 0 1 grades.0.score
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096 DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=Java,Version=3' `DATA_CHARSET`='utf8' `LRECL`=4096
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_date grades_grade grades_score name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 -73.856077, 40.848447 Morris Park Ave 10462 Bronx Bakery 1393804800 A 2 Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 -73.961704, 40.662942 Flatbush Avenue 11225 Brooklyn Hamburgers 1419897600 A 8 Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 -73.98513559999999, 40.7676919 West 57 Street 10019 Manhattan Irish 1409961600 A 2 Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 -73.98241999999999, 40.579505 Stillwell Avenue 11224 Brooklyn American 1402358400 A 5 Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 -73.8601152, 40.7311739 63 Road 11374 Queens Jewish/Kosher 1416787200 Z 20 Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"grades":0}' OPTION_LIST='Driver=Java,Version=3,level=0' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 (-73.856077, 40.848447) Morris Park Ave 10462 Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 (-73.961704, 40.662942) Flatbush Avenue 11225 Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 (-73.98513559999999, 40.7676919) West 57 Street 10019 Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 (-73.98241999999999, 40.579505) Stillwell Avenue 11224 Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 (-73.8601152, 40.7311739) 63 Road 11374 Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 8825 (-73.8803827, 40.7643124) Astoria Boulevard 11369 Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 2206 (-74.1377286, 40.6119572) Victory Boulevard 10314 Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 7114 (-73.9068506, 40.6199034) Avenue U 11234 Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 6409 (-74.00528899999999, 40.628886) 11 Avenue 11219 Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 1839 (-73.9482609, 40.6408271) Nostrand Avenue 11226 Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 2014-03-03
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 2014-03-03
+Wendy'S Flatbush Avenue 8 2014-12-30
+Dj Reynolds Pub And Restaurant West 57 Street 2 2014-09-06
+Riviera Caterer Stillwell Avenue 5 2014-06-10
+Tov Kosher Kitchen 63 Road 20 2014-11-24
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 2014-10-23 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 2014-08-14 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 2014-09-29 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 2014-02-11 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 2014-10-08 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 2014-06-09 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 2014-10-22 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 2014-07-26 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 2014-12-03 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 2015-01-16 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 2014-08-27 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 2014-06-03 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 2014-08-07 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 2014-12-27 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 2014-10-28 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 2014-08-18 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 2014-11-10 01:00:00 B 15
+Tout Va Bien Manhattan 2014-04-03 02:00:00 A 13
+Tout Va Bien Manhattan 2013-07-17 02:00:00 C 36
+Tout Va Bien Manhattan 2013-02-06 01:00:00 B 22
+Tout Va Bien Manhattan 2012-07-16 02:00:00 C 36
+Tout Va Bien Manhattan 2012-03-08 01:00:00 C 7
+La Grenouille Manhattan 2014-04-09 02:00:00 A 10
+La Grenouille Manhattan 2013-03-05 01:00:00 A 9
+La Grenouille Manhattan 2012-02-02 01:00:00 A 13
+Le Perigord Manhattan 2014-07-14 02:00:00 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 2014-11-21 01:00:00
+Bistro Sk A 12 2014-02-19 01:00:00
+Bistro Sk B 18 2013-06-12 02:00:00
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"cuisine":0}' CONNECTION='mongodb://localhost:27017' LRECL=4096
+OPTION_LIST='Driver=Java,level=2,version=3';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(18,16) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_date` bigint(13) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=3' `LRECL`=4096
+SELECT name, borough, address_street, grades_score AS score FROM t1 WHERE grades_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll'
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=JSON TABNAME='cities'
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096 DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=YES' CONNECTION='mongodb://localhost:27017' LRECL=4096;
+SELECT * FROM t1;
+item total average
+journal 285 57.00
+notebook 1368 456.00
+paper 23 5.75
+planner 167 41.75
+postcard 23 5.75
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/json_mongo_c.result b/storage/connect/mysql-test/connect/r/json_mongo_c.result
new file mode 100644
index 00000000..008e41f6
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/json_mongo_c.result
@@ -0,0 +1,385 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants CONNECTION='mongodb://localhost:27017' LRECL=1024
+OPTION_LIST='Driver=C,Version=0' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51c"},"address":{"building":"1007","coord":[-73.856077,40.848447],"street":"Morris Park Ave","zipcode":"10462"},"borough":"Bronx","cuisine":"Bakery","grades":[{"date":{"$date":1393804800000},"grade":"A","score":2},{"date":{"$date":1378857600000},"grade":"A","score":6},{"date":{"$date":1358985600000},"grade":"A","score":10},{"date":{"$date":1322006400000},"grade":"A","score":9},{"date":{"$date":1299715200000},"grade":"B","score":14}],"name":"Morris Park Bake Shop","restaurant_id":"30075445"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51d"},"address":{"building":"469","coord":[-73.961704,40.662942],"street":"Flatbush Avenue","zipcode":"11225"},"borough":"Brooklyn","cuisine":"Hamburgers","grades":[{"date":{"$date":1419897600000},"grade":"A","score":8},{"date":{"$date":1404172800000},"grade":"B","score":23},{"date":{"$date":1367280000000},"grade":"A","score":12},{"date":{"$date":1336435200000},"grade":"A","score":12}],"name":"Wendy'S","restaurant_id":"30112340"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51e"},"address":{"building":"351","coord":[-73.985136,40.767692],"street":"West 57 Street","zipcode":"10019"},"borough":"Manhattan","cuisine":"Irish","grades":[{"date":{"$date":1409961600000},"grade":"A","score":2},{"date":{"$date":1374451200000},"grade":"A","score":11},{"date":{"$date":1343692800000},"grade":"A","score":12},{"date":{"$date":1325116800000},"grade":"A","score":12}],"name":"Dj Reynolds Pub And Restaurant","restaurant_id":"30191841"}
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=C,Version=0' DATA_CHARSET=utf8 CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Jpath
+_id 1 CHAR 24 24 0 0 _id
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 1024 1024 0 1 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_date 1 CHAR 1024 1024 0 1 grades.0.date
+grades_grade 1 CHAR 14 14 0 1 grades.0.grade
+grades_score 7 INTEGER 2 2 0 1 grades.0.score
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(1024) DEFAULT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_date` varchar(1024) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=C,Version=0' `DATA_CHARSET`='utf8' `LRECL`=1024
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_date grades_grade grades_score name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 -73.856076999999999089, 40.848447000000000173 Morris Park Ave 10462 Bronx Bakery 1393804800 A 2 Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 -73.96170399999999745, 40.66294200000000103 Flatbush Avenue 11225 Brooklyn Hamburgers 1419897600 A 8 Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 -73.985135599999992451, 40.767691900000002647 West 57 Street 10019 Manhattan Irish 1409961600 A 2 Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 -73.982419999999990523, 40.579504999999997494 Stillwell Avenue 11224 Brooklyn American 1402358400 A 5 Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 -73.860115199999995639, 40.731173900000001709 63 Road 11374 Queens Jewish/Kosher 1416787200 Z 20 Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"projection":{"grades":0}}' OPTION_LIST='Driver=C,Version=0,level=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 (-73.856076999999999089, 40.848447000000000173) Morris Park Ave 10462 Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 (-73.96170399999999745, 40.66294200000000103) Flatbush Avenue 11225 Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 (-73.985135599999992451, 40.767691900000002647) West 57 Street 10019 Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 (-73.982419999999990523, 40.579504999999997494) Stillwell Avenue 11224 Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 (-73.860115199999995639, 40.731173900000001709) 63 Road 11374 Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 8825 (-73.880382699999998408, 40.764312400000001446) Astoria Boulevard 11369 Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 2206 (-74.137728600000002643, 40.611957199999999091) Victory Boulevard 10314 Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 7114 (-73.906850599999998508, 40.619903399999998328) Avenue U 11234 Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 6409 (-74.005288999999990551, 40.628886000000001388) 11 Avenue 11219 Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 1839 (-73.948260899999993967, 40.640827100000002758) Nostrand Avenue 11226 Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 2014-03-03
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 2014-03-03
+Wendy'S Flatbush Avenue 8 2014-12-30
+Dj Reynolds Pub And Restaurant West 57 Street 2 2014-09-06
+Riviera Caterer Stillwell Avenue 5 2014-06-10
+Tov Kosher Kitchen 63 Road 20 2014-11-24
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 2014-10-23 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 2014-08-14 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 2014-09-29 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 2014-02-11 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 2014-10-08 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 2014-06-09 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 2014-10-22 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 2014-07-26 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 2014-12-03 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 2015-01-16 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 2014-08-27 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 2014-06-03 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 2014-08-07 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 2014-12-27 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 2014-10-28 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 2014-08-18 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 2014-11-10 01:00:00 B 15
+Tout Va Bien Manhattan 2014-04-03 02:00:00 A 13
+Tout Va Bien Manhattan 2013-07-17 02:00:00 C 36
+Tout Va Bien Manhattan 2013-02-06 01:00:00 B 22
+Tout Va Bien Manhattan 2012-07-16 02:00:00 C 36
+Tout Va Bien Manhattan 2012-03-08 01:00:00 C 7
+La Grenouille Manhattan 2014-04-09 02:00:00 A 10
+La Grenouille Manhattan 2013-03-05 01:00:00 A 9
+La Grenouille Manhattan 2012-02-02 01:00:00 A 13
+Le Perigord Manhattan 2014-07-14 02:00:00 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 2014-11-21 01:00:00
+Bistro Sk A 12 2014-02-19 01:00:00
+Bistro Sk B 18 2013-06-12 02:00:00
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"projection":{"cuisine":0}}' CONNECTION='mongodb://localhost:27017' LRECL=1024
+OPTION_LIST='Driver=C,level=2,version=0';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL `JPATH`='_id',
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` double(23,20) DEFAULT NULL `JPATH`='address.coord.0',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_date` bigint(13) DEFAULT NULL `JPATH`='grades.0.date',
+ `grades_grade` char(14) DEFAULT NULL `JPATH`='grades.0.grade',
+ `grades_score` int(2) DEFAULT NULL `JPATH`='grades.0.score',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mongodb://localhost:27017' `TABLE_TYPE`='JSON' `TABNAME`='restaurants' `COLIST`='{"projection":{"cuisine":0}}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=C,level=2,version=0' `LRECL`=1024
+SELECT name, borough, address_street, grades_score AS score FROM t1 WHERE grades_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll'
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=JSON TABNAME='cities'
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=1' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=JSON TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=YES' CONNECTION='mongodb://localhost:27017' LRECL=1024;
+SELECT * FROM t1;
+item total average
+journal 285 57.00
+notebook 1368 456.00
+paper 23 5.75
+planner 167 41.75
+postcard 23 5.75
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/json_udf.result b/storage/connect/mysql-test/connect/r/json_udf.result
new file mode 100644
index 00000000..e3ee84d9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/json_udf.result
@@ -0,0 +1,651 @@
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=VIR BLOCK_SIZE=5;
+#
+# Test UDF's with constant arguments
+#
+SELECT JsonValue(56, 3.1416, 'foo', NULL);
+ERROR HY000: Can't initialize function 'jsonvalue'; Cannot accept more than 1 argument
+SELECT JsonValue(3.1416);
+JsonValue(3.1416)
+3.141600
+SELECT JsonValue(-80);
+JsonValue(-80)
+-80
+SELECT JsonValue('foo');
+JsonValue('foo')
+"foo"
+SELECT JsonValue(9223372036854775807);
+JsonValue(9223372036854775807)
+9223372036854775807
+SELECT JsonValue(NULL);
+JsonValue(NULL)
+null
+SELECT JsonValue(TRUE);
+JsonValue(TRUE)
+true
+SELECT JsonValue(FALSE);
+JsonValue(FALSE)
+false
+SELECT JsonValue();
+JsonValue()
+null
+SELECT JsonValue('[11, 22, 33]' json_) FROM t1;
+JsonValue('[11, 22, 33]' json_)
+[11,22,33]
+[11,22,33]
+[11,22,33]
+[11,22,33]
+[11,22,33]
+SELECT Json_Make_Array();
+Json_Make_Array()
+[]
+SELECT Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL);
+Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL)
+[56,3.141600,"My name is \"Foo\"",null]
+SELECT Json_Make_Array(Json_Make_Array(56, 3.1416, 'foo'), TRUE);
+Json_Make_Array(Json_Make_Array(56, 3.1416, 'foo'), TRUE)
+[[56,3.141600,"foo"],true]
+SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL)) Array;
+ERROR HY000: Can't initialize function 'json_array_add'; This function must have at least 2 arguments
+SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL), 'One more') Array;
+Array
+[56,3.141600,"foo",null,"One more"]
+SELECT Json_Array_Add(JsonValue('one value'), 'One more');
+Json_Array_Add(JsonValue('one value'), 'One more')
+["\"one value\"","One more"]
+SELECT Json_Array_Add('one value', 'One more');
+Json_Array_Add('one value', 'One more')
+["one value","One more"]
+SELECT Json_Array_Add('one value' json_, 'One more');
+Json_Array_Add('one value' json_, 'One more')
+one value
+Warnings:
+Warning 1105 Error 2 opening one value
+SELECT Json_Array_Add(5 json_, 'One more');
+Json_Array_Add(5 json_, 'One more')
+[5,"One more"]
+SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 0);
+Json_Array_Add('[5,3,8,7,9]' json_, 4, 0)
+[4,5,3,8,7,9]
+SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 2) Array;
+Array
+[5,3,4,8,7,9]
+SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 9);
+Json_Array_Add('[5,3,8,7,9]' json_, 4, 9)
+[5,3,8,7,9,4]
+SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), '[2]', 33, 1);
+Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), '[2]', 33, 1)
+[1,2,[11,22],"[2]"]
+SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, '[2]', 1);
+Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, '[2]', 1)
+[1,2,[11,33,22]]
+SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, 1, '[2]');
+Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, 1, '[2]')
+[1,2,[11,33,22]]
+SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin', NULL), 'One more', 'Two more') Array;
+Array
+[56,3.141600,"machin",null,"One more","Two more"]
+SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin'), 'One more', 'Two more') Array FROM t1;
+Array
+[56,3.141600,"machin","One more","Two more"]
+[56,3.141600,"machin","One more","Two more"]
+[56,3.141600,"machin","One more","Two more"]
+[56,3.141600,"machin","One more","Two more"]
+[56,3.141600,"machin","One more","Two more"]
+SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin'), n) Array FROM t1;
+Array
+[56,3.141600,"machin",1]
+[56,3.141600,"machin",2]
+[56,3.141600,"machin",3]
+[56,3.141600,"machin",4]
+[56,3.141600,"machin",5]
+SELECT Json_Array_Add_Values(Json_Make_Array(n, 3.1416, 'machin'), n) Array FROM t1;
+Array
+[1,3.141600,"machin",1]
+[2,3.141600,"machin",2]
+[3,3.141600,"machin",3]
+[4,3.141600,"machin",4]
+[5,3.141600,"machin",5]
+SELECT Json_Array_Add_Values('[56]', 3.1416, 'machin') Array;
+Array
+[56,3.141600,"machin"]
+SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0);
+Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0)
+[3.141600,"My name is \"Foo\"",null]
+SELECT Json_Array_Delete(Json_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2);
+Json_Array_Delete(Json_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2)
+{"56":56,"3.1416":3.141600,"My name is Foo":"My name is Foo","NULL":null}
+Warnings:
+Warning 1105 First argument target is not an array
+SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2');
+Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2')
+[56,3.141600,"My name is \"Foo\"",null]
+Warnings:
+Warning 1105 Missing or null array index
+SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2);
+Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2)
+[56,3.141600,"My name is \"Foo\"",null]
+Warnings:
+Warning 1105 First argument target is not an array
+SELECT Json_Make_Object(56, 3.1416, 'foo', NULL);
+Json_Make_Object(56, 3.1416, 'foo', NULL)
+{"56":56,"3.1416":3.141600,"foo":"foo","NULL":null}
+SELECT Json_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty);
+Json_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty)
+{"qty":56,"price":3.141600,"truc":"foo","garanty":null}
+SELECT Json_Make_Object();
+Json_Make_Object()
+{}
+SELECT Json_Make_Object(Json_Make_Array(56, 3.1416, 'foo'), NULL);
+Json_Make_Object(Json_Make_Array(56, 3.1416, 'foo'), NULL)
+{"Make_Array(56, 3.1416, 'foo')":[56,3.141600,"foo"],"NULL":null}
+SELECT Json_Make_Array(Json_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL);
+Json_Make_Array(Json_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL)
+[{"qty":56,"price":3.141600,"foo":"foo"},null]
+SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL);
+Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL)
+{"qty":56,"price":3.141600,"truc":"machin","garanty":null}
+SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty');
+ERROR HY000: Can't initialize function 'json_object_key'; This function must have an even number of arguments
+SELECT Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color);
+Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color)
+{"qty":56,"price":3.141600,"truc":"machin","garanty":null,"color":"blue"}
+SELECT Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price);
+Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price)
+{"qty":56,"price":45.990000,"truc":"machin","garanty":null}
+SELECT Json_Object_Add(Json_File('notexist.json'), 'cheese' item, '[1]', 1);
+Json_Object_Add(Json_File('notexist.json'), 'cheese' item, '[1]', 1)
+NULL
+Warnings:
+Warning 1105 Error 2 opening notexist.json
+Warning 1105 First argument target is not an object
+SELECT Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc');
+Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc')
+{"qty":56,"price":3.141600,"garanty":null}
+SELECT Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose');
+Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose')
+{"qty":56,"price":3.141600,"truc":"machin","garanty":null}
+SELECT Json_Object_List(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty)) "Key List";
+Key List
+["qty","price","truc","garanty"]
+SELECT Json_Object_List('{"qty":56, "price":3.1416, "truc":"machin", "garanty":null}') "Key List";
+Key List
+["qty","price","truc","garanty"]
+#
+# Test UDF's with column arguments
+#
+CREATE TABLE t2
+(
+ISBN CHAR(15),
+LANG CHAR(2),
+SUBJECT CHAR(32),
+AUTHOR CHAR(64),
+TITLE CHAR(32),
+TRANSLATION CHAR(32),
+TRANSLATOR CHAR(80),
+PUBLISHER CHAR(32),
+DATEPUB int(4)
+) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT Json_Make_Array(AUTHOR, TITLE, DATEPUB) FROM t2;
+Json_Make_Array(AUTHOR, TITLE, DATEPUB)
+[" Jean-Christophe Bernadac, François Knab","Construire une application XML",1999]
+["William J. Pardi","XML en Action",1999]
+SELECT Json_Make_Object(AUTHOR, TITLE, DATEPUB) FROM t2;
+Json_Make_Object(AUTHOR, TITLE, DATEPUB)
+{"AUTHOR":" Jean-Christophe Bernadac, François Knab","TITLE":"Construire une application XML","DATEPUB":1999}
+{"AUTHOR":"William J. Pardi","TITLE":"XML en Action","DATEPUB":1999}
+SELECT Json_Array_Grp(TITLE, DATEPUB) FROM t2;
+ERROR HY000: Can't initialize function 'json_array_grp'; This function can only accept 1 argument
+SELECT Json_Array_Grp(TITLE) FROM t2;
+Json_Array_Grp(TITLE)
+["Construire une application XML","XML en Action"]
+CREATE TABLE t3 (
+SERIALNO CHAR(5) NOT NULL,
+NAME VARCHAR(12) NOT NULL FLAG=6,
+SEX SMALLINT(1) NOT NULL,
+TITLE VARCHAR(15) NOT NULL FLAG=20,
+MANAGER CHAR(5) DEFAULT NULL,
+DEPARTMENT CHAr(4) NOT NULL FLAG=41,
+SECRETARY CHAR(5) DEFAULT NULL FLAG=46,
+SALARY DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=8 FILE_NAME='employee.dat' ENDING=1;
+SELECT Json_Make_Object(SERIALNO, NAME, TITLE, SALARY) FROM t3 WHERE NAME = 'MERCHANT';
+Json_Make_Object(SERIALNO, NAME, TITLE, SALARY)
+{"SERIALNO":"78943","NAME":"MERCHANT","TITLE":"SALESMAN","SALARY":8700.000000}
+SELECT DEPARTMENT, Json_Array_Grp(NAME) FROM t3 GROUP BY DEPARTMENT;
+DEPARTMENT Json_Array_Grp(NAME)
+0021 ["STRONG","SHORTSIGHT"]
+0318 ["BANCROFT","PLUMHEAD","HONEY","TONGHO","WALTER","SHRINKY","WERTHER","MERCHANT","WHEELFOR"]
+0319 ["BULLOZER","QUINN","BROWNY","KITTY","MONAPENNY","MARTIN","FUNNIGUY","BUGHAPPY","FODDERMAN","MESSIFUL"]
+2452 ["BIGHEAD","ORELLY","BIGHORN","SMITH","CHERRY"]
+Warnings:
+Warning 1105 Result truncated to json_grp_size values
+SELECT JsonSet_Grp_Size(30);
+JsonSet_Grp_Size(30)
+30
+SELECT Json_Make_Object(title, Json_Array_Grp(name) `json_names`) from t3 GROUP BY title;
+Json_Make_Object(title, Json_Array_Grp(name) `json_names`)
+{"title":"ADMINISTRATOR","names":["GOOSEPEN","FUNNIGUY","SHRINKY"]}
+{"title":"DIRECTOR","names":["QUINN","WERTHER","STRONG"]}
+{"title":"ENGINEER","names":["BROWNY","ORELLY","MARTIN","TONGHO","WALTER","SMITH"]}
+{"title":"PROGRAMMER","names":["BUGHAPPY"]}
+{"title":"SALESMAN","names":["WHEELFOR","MERCHANT","BULLOZER","BANCROFT","FODDERMAN"]}
+{"title":"SCIENTIST","names":["BIGHEAD","BIGHORN"]}
+{"title":"SECRETARY","names":["MESSIFUL","HONEY","SHORTSIGHT","CHERRY","MONAPENNY"]}
+{"title":"TYPIST","names":["KITTY","PLUMHEAD"]}
+SELECT Json_Make_Array(DEPARTMENT, Json_Array_Grp(NAME)) FROM t3 GROUP BY DEPARTMENT;
+Json_Make_Array(DEPARTMENT, Json_Array_Grp(NAME))
+["0021",["STRONG","SHORTSIGHT"]]
+["0318",["BANCROFT","PLUMHEAD","HONEY","TONGHO","WALTER","SHRINKY","WERTHER","MERCHANT","WHEELFOR"]]
+["0319",["BULLOZER","QUINN","BROWNY","KITTY","MONAPENNY","MARTIN","FUNNIGUY","BUGHAPPY","FODDERMAN","MESSIFUL","GOOSEPEN"]]
+["2452",["BIGHEAD","ORELLY","BIGHORN","SMITH","CHERRY"]]
+SELECT Json_Make_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES) FROM t3 GROUP BY DEPARTMENT;
+Json_Make_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES)
+{"DEPARTMENT":"0021","NAMES":["STRONG","SHORTSIGHT"]}
+{"DEPARTMENT":"0318","NAMES":["BANCROFT","PLUMHEAD","HONEY","TONGHO","WALTER","SHRINKY","WERTHER","MERCHANT","WHEELFOR"]}
+{"DEPARTMENT":"0319","NAMES":["BULLOZER","QUINN","BROWNY","KITTY","MONAPENNY","MARTIN","FUNNIGUY","BUGHAPPY","FODDERMAN","MESSIFUL","GOOSEPEN"]}
+{"DEPARTMENT":"2452","NAMES":["BIGHEAD","ORELLY","BIGHORN","SMITH","CHERRY"]}
+SELECT Json_Make_Object(DEPARTMENT, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT;
+Json_Make_Object(DEPARTMENT, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES)
+{"DEPARTMENT":"0021","EMPLOYES":[{"SERIALNO":"87777","NAME":"STRONG","TITLE":"DIRECTOR","SALARY":23000.000000},{"SERIALNO":"22222","NAME":"SHORTSIGHT","TITLE":"SECRETARY","SALARY":5500.000000}]}
+{"DEPARTMENT":"0318","EMPLOYES":[{"SERIALNO":"74200","NAME":"BANCROFT","TITLE":"SALESMAN","SALARY":9600.000000},{"SERIALNO":"24888","NAME":"PLUMHEAD","TITLE":"TYPIST","SALARY":2800.000000},{"SERIALNO":"27845","NAME":"HONEY","TITLE":"SECRETARY","SALARY":4900.000000},{"SERIALNO":"73452","NAME":"TONGHO","TITLE":"ENGINEER","SALARY":6800.000000},{"SERIALNO":"74234","NAME":"WALTER","TITLE":"ENGINEER","SALARY":7400.000000},{"SERIALNO":"77777","NAME":"SHRINKY","TITLE":"ADMINISTRATOR","SALARY":7500.000000},{"SERIALNO":"70012","NAME":"WERTHER","TITLE":"DIRECTOR","SALARY":14500.000000},{"SERIALNO":"78943","NAME":"MERCHANT","TITLE":"SALESMAN","SALARY":8700.000000},{"SERIALNO":"73111","NAME":"WHEELFOR","TITLE":"SALESMAN","SALARY":10030.000000}]}
+{"DEPARTMENT":"0319","EMPLOYES":[{"SERIALNO":"76543","NAME":"BULLOZER","TITLE":"SALESMAN","SALARY":14800.000000},{"SERIALNO":"40567","NAME":"QUINN","TITLE":"DIRECTOR","SALARY":14000.000000},{"SERIALNO":"00137","NAME":"BROWNY","TITLE":"ENGINEER","SALARY":10500.000000},{"SERIALNO":"12345","NAME":"KITTY","TITLE":"TYPIST","SALARY":3000.450000},{"SERIALNO":"33333","NAME":"MONAPENNY","TITLE":"SECRETARY","SALARY":3800.000000},{"SERIALNO":"00023","NAME":"MARTIN","TITLE":"ENGINEER","SALARY":10000.000000},{"SERIALNO":"07654","NAME":"FUNNIGUY","TITLE":"ADMINISTRATOR","SALARY":8500.000000},{"SERIALNO":"45678","NAME":"BUGHAPPY","TITLE":"PROGRAMMER","SALARY":8500.000000},{"SERIALNO":"56789","NAME":"FODDERMAN","TITLE":"SALESMAN","SALARY":7000.000000},{"SERIALNO":"55555","NAME":"MESSIFUL","TITLE":"SECRETARY","SALARY":5000.500000},{"SERIALNO":"98765","NAME":"GOOSEPEN","TITLE":"ADMINISTRATOR","SALARY":4700.000000}]}
+{"DEPARTMENT":"2452","EMPLOYES":[{"SERIALNO":"34567","NAME":"BIGHEAD","TITLE":"SCIENTIST","SALARY":8000.000000},{"SERIALNO":"31416","NAME":"ORELLY","TITLE":"ENGINEER","SALARY":13400.000000},{"SERIALNO":"36666","NAME":"BIGHORN","TITLE":"SCIENTIST","SALARY":11000.000000},{"SERIALNO":"02345","NAME":"SMITH","TITLE":"ENGINEER","SALARY":9000.000000},{"SERIALNO":"11111","NAME":"CHERRY","TITLE":"SECRETARY","SALARY":4500.000000}]}
+SELECT Json_Make_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT, TITLE;
+Json_Make_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES)
+{"DEPARTMENT":"0021","TITLE":"DIRECTOR","EMPLOYES":[{"SERIALNO":"87777","NAME":"STRONG","SALARY":23000.000000}]}
+{"DEPARTMENT":"0021","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"22222","NAME":"SHORTSIGHT","SALARY":5500.000000}]}
+{"DEPARTMENT":"0318","TITLE":"ADMINISTRATOR","EMPLOYES":[{"SERIALNO":"77777","NAME":"SHRINKY","SALARY":7500.000000}]}
+{"DEPARTMENT":"0318","TITLE":"DIRECTOR","EMPLOYES":[{"SERIALNO":"70012","NAME":"WERTHER","SALARY":14500.000000}]}
+{"DEPARTMENT":"0318","TITLE":"ENGINEER","EMPLOYES":[{"SERIALNO":"73452","NAME":"TONGHO","SALARY":6800.000000},{"SERIALNO":"74234","NAME":"WALTER","SALARY":7400.000000}]}
+{"DEPARTMENT":"0318","TITLE":"SALESMAN","EMPLOYES":[{"SERIALNO":"74200","NAME":"BANCROFT","SALARY":9600.000000},{"SERIALNO":"78943","NAME":"MERCHANT","SALARY":8700.000000},{"SERIALNO":"73111","NAME":"WHEELFOR","SALARY":10030.000000}]}
+{"DEPARTMENT":"0318","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"27845","NAME":"HONEY","SALARY":4900.000000}]}
+{"DEPARTMENT":"0318","TITLE":"TYPIST","EMPLOYES":[{"SERIALNO":"24888","NAME":"PLUMHEAD","SALARY":2800.000000}]}
+{"DEPARTMENT":"0319","TITLE":"ADMINISTRATOR","EMPLOYES":[{"SERIALNO":"98765","NAME":"GOOSEPEN","SALARY":4700.000000},{"SERIALNO":"07654","NAME":"FUNNIGUY","SALARY":8500.000000}]}
+{"DEPARTMENT":"0319","TITLE":"DIRECTOR","EMPLOYES":[{"SERIALNO":"40567","NAME":"QUINN","SALARY":14000.000000}]}
+{"DEPARTMENT":"0319","TITLE":"ENGINEER","EMPLOYES":[{"SERIALNO":"00023","NAME":"MARTIN","SALARY":10000.000000},{"SERIALNO":"00137","NAME":"BROWNY","SALARY":10500.000000}]}
+{"DEPARTMENT":"0319","TITLE":"PROGRAMMER","EMPLOYES":[{"SERIALNO":"45678","NAME":"BUGHAPPY","SALARY":8500.000000}]}
+{"DEPARTMENT":"0319","TITLE":"SALESMAN","EMPLOYES":[{"SERIALNO":"76543","NAME":"BULLOZER","SALARY":14800.000000},{"SERIALNO":"56789","NAME":"FODDERMAN","SALARY":7000.000000}]}
+{"DEPARTMENT":"0319","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"33333","NAME":"MONAPENNY","SALARY":3800.000000},{"SERIALNO":"55555","NAME":"MESSIFUL","SALARY":5000.500000}]}
+{"DEPARTMENT":"0319","TITLE":"TYPIST","EMPLOYES":[{"SERIALNO":"12345","NAME":"KITTY","SALARY":3000.450000}]}
+{"DEPARTMENT":"2452","TITLE":"ENGINEER","EMPLOYES":[{"SERIALNO":"31416","NAME":"ORELLY","SALARY":13400.000000},{"SERIALNO":"02345","NAME":"SMITH","SALARY":9000.000000}]}
+{"DEPARTMENT":"2452","TITLE":"SCIENTIST","EMPLOYES":[{"SERIALNO":"34567","NAME":"BIGHEAD","SALARY":8000.000000},{"SERIALNO":"36666","NAME":"BIGHORN","SALARY":11000.000000}]}
+{"DEPARTMENT":"2452","TITLE":"SECRETARY","EMPLOYES":[{"SERIALNO":"11111","NAME":"CHERRY","SALARY":4500.000000}]}
+SELECT Json_Object_Grp(SALARY) FROM t3;
+ERROR HY000: Can't initialize function 'json_object_grp'; This function requires 2 arguments (key, value)
+SELECT Json_Object_Grp(NAME, SALARY) FROM t3;
+Json_Object_Grp(NAME, SALARY)
+{"BANCROFT":9600.000000,"SMITH":9000.000000,"MERCHANT":8700.000000,"FUNNIGUY":8500.000000,"BUGHAPPY":8500.000000,"BIGHEAD":8000.000000,"SHRINKY":7500.000000,"WALTER":7400.000000,"FODDERMAN":7000.000000,"TONGHO":6800.000000,"SHORTSIGHT":5500.000000,"MESSIFUL":5000.500000,"HONEY":4900.000000,"GOOSEPEN":4700.000000,"CHERRY":4500.000000,"MONAPENNY":3800.000000,"KITTY":3000.450000,"PLUMHEAD":2800.000000,"STRONG":23000.000000,"BULLOZER":14800.000000,"WERTHER":14500.000000,"QUINN":14000.000000,"ORELLY":13400.000000,"BIGHORN":11000.000000,"BROWNY":10500.000000,"WHEELFOR":10030.000000,"MARTIN":10000.000000}
+SELECT Json_Make_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT;
+Json_Make_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES")
+{"DEPARTMENT":"0021","SALARIES":{"STRONG":23000.000000,"SHORTSIGHT":5500.000000}}
+{"DEPARTMENT":"0318","SALARIES":{"BANCROFT":9600.000000,"PLUMHEAD":2800.000000,"HONEY":4900.000000,"TONGHO":6800.000000,"WALTER":7400.000000,"SHRINKY":7500.000000,"WERTHER":14500.000000,"MERCHANT":8700.000000,"WHEELFOR":10030.000000}}
+{"DEPARTMENT":"0319","SALARIES":{"BULLOZER":14800.000000,"QUINN":14000.000000,"BROWNY":10500.000000,"KITTY":3000.450000,"MONAPENNY":3800.000000,"MARTIN":10000.000000,"FUNNIGUY":8500.000000,"BUGHAPPY":8500.000000,"FODDERMAN":7000.000000,"MESSIFUL":5000.500000,"GOOSEPEN":4700.000000}}
+{"DEPARTMENT":"2452","SALARIES":{"BIGHEAD":8000.000000,"ORELLY":13400.000000,"BIGHORN":11000.000000,"SMITH":9000.000000,"CHERRY":4500.000000}}
+SELECT Json_Array_Grp(NAME) FROM t3;
+Json_Array_Grp(NAME)
+["BANCROFT","SMITH","MERCHANT","FUNNIGUY","BUGHAPPY","BIGHEAD","SHRINKY","WALTER","FODDERMAN","TONGHO","SHORTSIGHT","MESSIFUL","HONEY","GOOSEPEN","CHERRY","MONAPENNY","KITTY","PLUMHEAD","STRONG","BULLOZER","WERTHER","QUINN","ORELLY","BIGHORN","BROWNY","WHEELFOR","MARTIN"]
+SELECT Json_Object_Key(name, title) FROM t3 WHERE DEPARTMENT = 318;
+Json_Object_Key(name, title)
+{"BANCROFT":"SALESMAN"}
+{"MERCHANT":"SALESMAN"}
+{"SHRINKY":"ADMINISTRATOR"}
+{"WALTER":"ENGINEER"}
+{"TONGHO":"ENGINEER"}
+{"HONEY":"SECRETARY"}
+{"PLUMHEAD":"TYPIST"}
+{"WERTHER":"DIRECTOR"}
+{"WHEELFOR":"SALESMAN"}
+SELECT Json_Object_Grp(name, title) FROM t3 WHERE DEPARTMENT = 318;
+Json_Object_Grp(name, title)
+{"BANCROFT":"SALESMAN","MERCHANT":"SALESMAN","SHRINKY":"ADMINISTRATOR","WALTER":"ENGINEER","TONGHO":"ENGINEER","HONEY":"SECRETARY","PLUMHEAD":"TYPIST","WERTHER":"DIRECTOR","WHEELFOR":"SALESMAN"}
+#
+# Test value getting UDF's
+#
+SELECT JsonGet_String(Json_Array_Grp(name),'[#]') FROM t3;
+JsonGet_String(Json_Array_Grp(name),'[#]')
+27
+SELECT JsonGet_String(Json_Array_Grp(name),'[","]') FROM t3;
+JsonGet_String(Json_Array_Grp(name),'[","]')
+BANCROFT,SMITH,MERCHANT,FUNNIGUY,BUGHAPPY,BIGHEAD,SHRINKY,WALTER,FODDERMAN,TONGHO,SHORTSIGHT,MESSIFUL,HONEY,GOOSEPEN,CHERRY,MONAPENNY,KITTY,PLUMHEAD,STRONG,BULLOZER,WERTHER,QUINN,ORELLY,BIGHORN,BROWNY,WHEELFOR,MARTIN
+SELECT JsonGet_String(Json_Array_Grp(name),'[>]') FROM t3;
+JsonGet_String(Json_Array_Grp(name),'[>]')
+WHEELFOR
+SET @j1 = '[45,28,36,45,89]';
+SELECT JsonGet_String(@j1,'1');
+JsonGet_String(@j1,'1')
+28
+SELECT JsonGet_String(@j1 json_,'3');
+JsonGet_String(@j1 json_,'3')
+45
+SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'3');
+JsonGet_String(Json_Make_Array(45,28,36,45,89),'3')
+45
+SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",JsonGet_String(Json_Make_Array(45,28,36,45,89),'[+]') "sum";
+list egal sum
+45+28+36+45+89 = 243
+SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.0');
+JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.0')
+36
+SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.*');
+JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.*')
+[36,45,89]
+SELECT JsonGet_String(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc');
+JsonGet_String(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc')
+machin
+SET @j2 = '{"qty":56,"price":3.141600,"truc":"machin","garanty":null}';
+SELECT JsonGet_String(@j2 json_,'truc');
+JsonGet_String(@j2 json_,'truc')
+machin
+SELECT JsonGet_String(@j2,'truc');
+JsonGet_String(@j2,'truc')
+machin
+SELECT JsonGet_String(@j2,'chose');
+JsonGet_String(@j2,'chose')
+NULL
+SELECT JsonGet_String(NULL json_, NULL);
+JsonGet_String(NULL json_, NULL)
+NULL
+Warnings:
+Warning 1105
+SELECT department, JsonGet_String(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+department Sumsal
+0021 28500.000000
+0318 72230.000000
+0319 89800.950000
+2452 45900.000000
+SELECT JsonGet_Int(@j1, '4');
+JsonGet_Int(@j1, '4')
+89
+SELECT JsonGet_Int(@j1, '[#]');
+JsonGet_Int(@j1, '[#]')
+5
+SELECT JsonGet_Int(@j1, '[+]');
+JsonGet_Int(@j1, '[+]')
+243
+SELECT JsonGet_Int(@j1 json_, '3');
+JsonGet_Int(@j1 json_, '3')
+45
+SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '3');
+JsonGet_Int(Json_Make_Array(45,28,36,45,89), '3')
+45
+SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '["+"]');
+JsonGet_Int(Json_Make_Array(45,28,36,45,89), '["+"]')
+45
+SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]');
+JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]')
+243
+SELECT JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0');
+JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0')
+36
+SELECT JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '0.1');
+JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '0.1')
+28
+SELECT JsonGet_Int(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty');
+JsonGet_Int(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty')
+56
+SELECT JsonGet_Int(@j2 json_, 'price');
+JsonGet_Int(@j2 json_, 'price')
+3
+SELECT JsonGet_Int(@j2, 'qty');
+JsonGet_Int(@j2, 'qty')
+56
+SELECT JsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose');
+JsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose')
+NULL
+SELECT JsonGet_Int(JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)), '1.*'), '[+]') sum;
+sum
+170
+SELECT department, JsonGet_Int(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"), 'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+department Sumsal
+0021 28500
+0318 72230
+0319 89800
+2452 45900
+SELECT JsonGet_Real(@j1, '2');
+JsonGet_Real(@j1, '2')
+36.000000000000000
+SELECT JsonGet_Real(@j1 json_, '3', 2);
+JsonGet_Real(@j1 json_, '3', 2)
+45.00
+SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '3');
+JsonGet_Real(Json_Make_Array(45,28,36,45,89), '3')
+45.000000000000000
+SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '["+"]');
+JsonGet_Real(Json_Make_Array(45,28,36,45,89), '["+"]')
+45.000000000000000
+SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[+]');
+JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[+]')
+243.000000000000000
+SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]');
+JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]')
+48.600000000000000
+SELECT JsonGet_Real(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0');
+JsonGet_Real(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0')
+36.000000000000000
+SELECT JsonGet_Real(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price');
+JsonGet_Real(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price')
+3.141600000000000
+SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty');
+JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty')
+56.000000000000000
+SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price');
+JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price')
+3.141600000000000
+SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price', 4);
+JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price', 4)
+3.1416
+SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose');
+JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose')
+NULL
+SELECT department, JsonGet_Real(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+department Sumsal
+0021 28500.000000000000000
+0318 72230.000000000000000
+0319 89800.950000000000000
+2452 45900.000000000000000
+#
+# Documentation examples
+#
+SELECT
+JsonGet_Int(Json_Make_Array(45,28,36,45,89), '4') "Rank",
+JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[#]') "Number",
+JsonGet_String(Json_Make_Array(45,28,36,45,89), '[","]') "Concat",
+JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]') "Sum",
+JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]', 2) "Avg";
+Rank Number Concat Sum Avg
+89 5 45,28,36,45,89 243 48.60
+SELECT
+JsonGet_String('{"qty":7,"price":29.50,"garanty":null}', 'price') "String",
+JsonGet_Int('{"qty":7,"price":29.50,"garanty":null}', 'price') "Int",
+JsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price') "Real";
+String Int Real
+29.50 29 29.500000000000000
+SELECT JsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price', 3) "Real";
+Real
+29.500
+#
+# Testing Locate
+#
+SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin');
+JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin')
+$.truc
+SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56);
+JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56)
+$.qty
+SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416);
+JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416)
+$.price
+SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose');
+JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose')
+NULL
+SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'Jack') Path;
+Path
+$.AUTHORS[1].FN
+SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'jack' ci) Path;
+Path
+$.AUTHORS[1].FN
+SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"Jack", "LN":"London"}' json_) Path;
+Path
+$.AUTHORS[1]
+SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"jack", "LN":"London"}' json_) Path;
+Path
+NULL
+SELECT JsonLocate('[45,28,36,45,89]',36);
+JsonLocate('[45,28,36,45,89]',36)
+$[2]
+SELECT JsonLocate('[45,28,36,45,89]' json_,28.0);
+JsonLocate('[45,28,36,45,89]' json_,28.0)
+NULL
+SELECT Json_Locate_All('[45,28,36,45,89]',10);
+Json_Locate_All('[45,28,36,45,89]',10)
+[]
+SELECT Json_Locate_All('[45,28,36,45,89]',45);
+Json_Locate_All('[45,28,36,45,89]',45)
+["$[0]","$[3]"]
+SELECT Json_Locate_All('[[45,28],36,45,89]',45);
+Json_Locate_All('[[45,28],36,45,89]',45)
+["$[0][0]","$[2]"]
+SELECT Json_Locate_All('[[45,28,45],36,45,89]',45);
+Json_Locate_All('[[45,28,45],36,45,89]',45)
+["$[0][0]","$[0][2]","$[2]"]
+SELECT Json_Locate_All('[[45,28,45],36,45,89]',JsonGet_Int('[3,45]','[1]'));
+Json_Locate_All('[[45,28,45],36,45,89]',JsonGet_Int('[3,45]','[1]'))
+["$[0][0]","$[0][2]","$[2]"]
+SELECT JsonLocate('[[45,28,45],36,45,89]',45,n) from t1;
+JsonLocate('[[45,28,45],36,45,89]',45,n)
+$[0][0]
+$[0][2]
+$[2]
+NULL
+NULL
+SELECT JsonGet_String(Json_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) FROM t1;
+JsonGet_String(Json_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']'))
+$[0][0]
+$[0][2]
+$[2]
+NULL
+NULL
+SELECT JsonGet_String(Json_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) AS `Path` FROM t1 GROUP BY n HAVING `Path` IS NOT NULL;
+Path
+$[0][0]
+$[0][2]
+$[2]
+SELECT Json_Locate_All('[45,28,[36,45,89]]',45);
+Json_Locate_All('[45,28,[36,45,89]]',45)
+["$[0]","$[2][1]"]
+SELECT Json_Locate_All('[[45,28],[36,45.0,89]]',JsonValue(45.0));
+Json_Locate_All('[[45,28],[36,45.0,89]]',JsonValue(45.0))
+[]
+SELECT Json_Locate_All('[[45,28],[36,45.0,89]]',45.0);
+Json_Locate_All('[[45,28],[36,45.0,89]]',45.0)
+["$[1][1]"]
+SELECT JsonLocate('[[45,28],[36,45,89]]','[36,45,89]' json_);
+JsonLocate('[[45,28],[36,45,89]]','[36,45,89]' json_)
+$[1]
+SELECT JsonLocate('[[45,28],[36,45,89]]','[45,28]' json_);
+JsonLocate('[[45,28],[36,45,89]]','[45,28]' json_)
+$[0]
+SELECT Json_Locate_All('[[45,28],[[36,45],89]]','45') "All paths";
+All paths
+[]
+SELECT Json_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_);
+Json_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_)
+["$[1][0]"]
+SELECT JsonGet_Int(Json_Locate_All('[[45,28],[[36,45],89]]',45), '[#]') "Nb of occurs";
+Nb of occurs
+2
+SELECT Json_Locate_All('[[45,28],[[36,45],89]]',45,2);
+Json_Locate_All('[[45,28],[[36,45],89]]',45,2)
+["$[0][0]"]
+SELECT JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'0');
+JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'0')
+$[0]
+SELECT JsonLocate(Json_File('test/biblio.json'), 'Knab');
+JsonLocate(Json_File('test/biblio.json'), 'Knab')
+$[0].AUTHOR[1].LASTNAME
+SELECT Json_Locate_All('test/biblio.json' jfile_, 'Knab');
+Json_Locate_All('test/biblio.json' jfile_, 'Knab')
+["$[0].AUTHOR[1].LASTNAME"]
+#
+# Testing json files
+#
+SELECT Jfile_Make('[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},
+{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},
+{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]', 'test/fx.json', 0) AS NewFile;
+NewFile
+test/fx.json
+SELECT Jfile_Make('test/fx.json', 1);
+Jfile_Make('test/fx.json', 1)
+test/fx.json
+SELECT Jfile_Make('test/fx.json' jfile_);
+Jfile_Make('test/fx.json' jfile_)
+test/fx.json
+SELECT Jfile_Make(Jbin_File('test/fx.json'), 0);
+Jfile_Make(Jbin_File('test/fx.json'), 0)
+test/fx.json
+SELECT Json_File('test/fx.json', 1);
+Json_File('test/fx.json', 1)
+[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]
+Warnings:
+Warning 1105 File pretty format doesn't match the specified pretty value
+SELECT Json_File('test/fx.json', 2);
+Json_File('test/fx.json', 2)
+[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]
+Warnings:
+Warning 1105 File pretty format doesn't match the specified pretty value
+SELECT Json_File('test/fx.json', 0);
+Json_File('test/fx.json', 0)
+[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]
+SELECT Json_File('test/fx.json', '0');
+Json_File('test/fx.json', '0')
+{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]}
+SELECT Json_File('test/fx.json', '[?]');
+Json_File('test/fx.json', '[?]')
+NULL
+Warnings:
+Warning 1105 Invalid function specification ?
+SELECT JsonGet_String(Json_File('test/fx.json'), '1.*');
+JsonGet_String(Json_File('test/fx.json'), '1.*')
+{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]}
+SELECT JsonGet_String(Json_File('test/fx.json'), '1');
+JsonGet_String(Json_File('test/fx.json'), '1')
+6 car roadster 56000 (6, 9)
+SELECT JsonGet_Int(Json_File('test/fx.json'), '1.mileage') AS Mileage;
+Mileage
+56000
+SELECT JsonGet_Real(Json_File('test/fx.json'), '0.price', 2) AS Price;
+Price
+5.65
+SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings');
+Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings')
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4,6]}
+SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 1, 'ratings');
+Json_Array_Add(Json_File('test/fx.json', '2'), 6, 1, 'ratings')
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,6,4]}
+SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings', 1);
+Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings', 1)
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,6,4]}
+SELECT Json_Array_Add(Json_File('test/fx.json', '2.ratings'), 6, 0);
+Json_Array_Add(Json_File('test/fx.json', '2.ratings'), 6, 0)
+[6,2,4]
+SELECT Json_Array_Delete(Json_File('test/fx.json', '2'), 'ratings', 1);
+Json_Array_Delete(Json_File('test/fx.json', '2'), 'ratings', 1)
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2]}
+SELECT Json_Object_Add(Json_File('test/fx.json', '2'), 'france' origin);
+Json_Object_Add(Json_File('test/fx.json', '2'), 'france' origin)
+{"_id":7,"type":"food","item":"meat","origin":"france","ratings":[2,4]}
+SELECT Json_Object_Add(Json_File('test/fx.json', '2'), 70 H, 'size');
+Json_Object_Add(Json_File('test/fx.json', '2'), 70 H, 'size')
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]}
+Warnings:
+Warning 1105 No sub-item at 'size'
+SELECT Json_Object_Add(Json_File('test/fx.json', '3'), 70 H, 'size');
+Json_Object_Add(Json_File('test/fx.json', '3'), 70 H, 'size')
+{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":70},"ratings":[5,8,7]}
+SELECT Json_Object_List(Json_File('test/fx.json', '3.size'));
+Json_Object_List(Json_File('test/fx.json', '3.size'))
+["W","L","H"]
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
diff --git a/storage/connect/mysql-test/connect/r/json_udf_bin.result b/storage/connect/mysql-test/connect/r/json_udf_bin.result
new file mode 100644
index 00000000..c20cf7ce
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/json_udf_bin.result
@@ -0,0 +1,587 @@
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=VIR BLOCK_SIZE=3;
+#
+# Test Jbin UDF's
+#
+SELECT Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), n) from t1;
+Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), n)
+[56,3.141600,"My name is \"Foo\"",null,1]
+[56,3.141600,"My name is \"Foo\"",null,2]
+[56,3.141600,"My name is \"Foo\"",null,3]
+SELECT Json_Array_Add(Jbin_Array(n, 3.1416, 'My name is "Foo"', NULL), n) from t1;
+Json_Array_Add(Jbin_Array(n, 3.1416, 'My name is "Foo"', NULL), n)
+[1,3.141600,"My name is \"Foo\"",null,1]
+[2,3.141600,"My name is \"Foo\"",null,2]
+[3,3.141600,"My name is \"Foo\"",null,3]
+SELECT Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), Jbin_Array('a','b',n)) from t1;
+Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), Jbin_Array('a','b',n))
+[56,3.141600,"My name is \"Foo\"",null,["a","b",1]]
+[56,3.141600,"My name is \"Foo\"",null,["a","b",2]]
+[56,3.141600,"My name is \"Foo\"",null,["a","b",3]]
+SELECT Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), JsonGet_String(Jbin_Array('a','b','c'), '[1]'));
+Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), JsonGet_String(Jbin_Array('a','b','c'), '[1]'))
+[56,3.141600,"My name is \"Foo\"",null,"b"]
+SELECT Json_Array_Delete(Jbin_Array_Add_Values(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), "One more", 2), 4);
+Json_Array_Delete(Jbin_Array_Add_Values(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), "One more", 2), 4)
+[56,3.141600,"My name is \"Foo\"",null,2]
+SELECT Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), NULL), '[1]', 1);
+Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), NULL), '[1]', 1)
+[56,[3.141600],null]
+SELECT Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), TRUE), 1, '[1]');
+Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), TRUE), 1, '[1]')
+[56,[3.141600],true]
+SELECT Json_Make_Array(1, TRUE, 0, FALSE);
+Json_Make_Array(1, TRUE, 0, FALSE)
+[1,true,0,false]
+SELECT Json_Serialize(Jbin_Array(TRUE, FALSE));
+Json_Serialize(Jbin_Array(TRUE, FALSE))
+[true,false]
+SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL);
+Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL)
+{"qty":56,"price":3.141600,"truc":"machin","garanty":null}
+SELECT Json_Serialize(Jbin_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL));
+Json_Serialize(Jbin_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL))
+{"qty":56,"price":3.141600,"truc":"machin","garanty":null}
+SELECT Jbin_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty');
+ERROR HY000: Can't initialize function 'jbin_object_key'; This function must have an even number of arguments
+SELECT Json_Object_Add(Jbin_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color);
+Json_Object_Add(Jbin_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color)
+{"qty":56,"price":3.141600,"truc":"machin","garanty":null,"color":"blue"}
+SELECT Json_Object_Add(Jbin_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price);
+Json_Object_Add(Jbin_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price)
+{"qty":56,"price":45.990000,"truc":"machin","garanty":null}
+SELECT Json_Object_Add(Jbin_Object_Nonull(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color);
+Json_Object_Add(Jbin_Object_Nonull(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color)
+{"qty":56,"price":3.141600,"truc":"machin","color":"blue"}
+SELECT Json_Object_Add(Jbin_Object_Nonull(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price);
+Json_Object_Add(Jbin_Object_Nonull(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price)
+{"qty":56,"price":45.990000,"truc":"machin"}
+#
+# Test Jbin file UDF's
+#
+SELECT Json_Serialize(Jbin_File('gloss.json'));
+Json_Serialize(Jbin_File('gloss.json'))
+{"glossary":{"title":"example glossary","GlossDiv":{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}}}
+SELECT JsonLocate(Jbin_File('gloss.json'),'XML');
+JsonLocate(Jbin_File('gloss.json'),'XML')
+$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso[1]
+SELECT Json_Object_Key('first', 'foo', 'second', Jbin_Array('a', 33));
+Json_Object_Key('first', 'foo', 'second', Jbin_Array('a', 33))
+{"first":"foo","second":["a",33]}
+SELECT Json_Get_Item(Json_Make_Array('a','b','c'), '$[1]');
+Json_Get_Item(Json_Make_Array('a','b','c'), '$[1]')
+NULL
+SELECT Json_Get_Item(Json_Make_Object('foo' AS "first", Json_Make_Array('a', 33) AS "json_second"), '$.second') AS "item";
+item
+["a",33]
+SELECT Json_Get_Item(Jbin_Object('foo' first, Jbin_Array('a', 33) jbin_second), '$.second') item;
+item
+["a",33]
+SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv');
+Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv')
+{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}
+SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv'));
+Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv'))
+{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}
+SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv');
+Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv')
+{"title":"S","GlossList":{"GlossEntry":{"ID":"SGML","SortAs":"SGML","GlossTerm":"Standard Generalized Markup Language","Acronym":"SGML","Abbrev":"ISO 8879:1986","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"GlossSee":"markup"}}}
+SELECT JsonGet_String(Json_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso') lang;
+lang
+GML, XML
+SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso') "See also";
+See also
+["GML","XML"]
+SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso')) "See also";
+See also
+["GML","XML"]
+SELECT JsonGet_String(Json_Get_Item(Json_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso'),'$[0]') lang;
+lang
+GML
+#
+# Test Item Get/Set/Insert/Update UDF's
+#
+SELECT Json_Get_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[]');
+Json_Get_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[]')
+[1,2,{"trois":3,"quatre":4}]
+SELECT Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[1]');
+Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[1]')
+NULL
+SELECT Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$[1]');
+Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$[1]')
+NULL
+SELECT Json_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)));
+Json_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)))
+[1,2,{"trois":3,"quatre":4}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$.foo');
+ERROR HY000: Can't initialize function 'json_set_item'; This function must have an odd number of arguments
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq')
+[1,2,{"trois":3,"quatre":4,"cinq":5}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '$[1]');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '$[1]')
+[1,7,{"trois":3,"quatre":4}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 7, '$[1]');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 7, '$[1]')
+[1,7,{"trois":3,"quatre":4,"cinq":5}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Make_Array(7, 8, 9), '$[1]');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Make_Array(7, 8, 9), '$[1]')
+[1,[7,8,9],{"trois":3,"quatre":4}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2]');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2]')
+[1,2,[7,8,9]]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2].*');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2].*')
+[1,2,{"trois":3,"quatre":4}]
+Warnings:
+Warning 1105 Invalid specification * in a write path
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, '$.foo');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, '$.foo')
+[1,2,{"trois":3,"quatre":4}]
+SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '$[1][2]');
+Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '$[1][2]')
+[1,[7,8,"toto"],{"trois":3,"quatre":4}]
+SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '$[2].nxt.total[]');
+Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '$[2].nxt.total[]')
+[1,[7,8,9],{"trois":3,"quatre":4,"nxt":{"total":[300]}}]
+SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 300, '$[2].nxt.total[]');
+Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 300, '$[2].nxt.total[]')
+[1,[7,8,9,10],{"trois":3,"quatre":4,"cinq":5,"nxt":{"total":[300]}}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[1]', 5, '$[2].cinq', 10, '$[1][]');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[1]', 5, '$[2].cinq', 10, '$[1][]')
+[1,[7,8,9,10],{"trois":3,"quatre":4,"cinq":5}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '$[2].quatre');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '$[2].quatre')
+[1,2,{"trois":3,"quatre":44}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, 'truc');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, 'truc')
+[1,2,{"trois":3,"quatre":4}]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '')
+[1,2,{"trois":3,"quatre":4},5]
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '*');
+Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '*')
+[1,2,{"trois":3,"quatre":4}]
+Warnings:
+Warning 1105 Invalid specification * in a write path
+SELECT Json_Serialize(Jbin_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'));
+Json_Serialize(Jbin_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'))
+[1,2,{"trois":3,"quatre":4,"cinq":5}]
+SELECT Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq');
+Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq')
+[1,2,{"trois":3,"quatre":4,"cinq":5}]
+SELECT Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq');
+Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq')
+[1,2,{"trois":3,"quatre":4}]
+SELECT Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre');
+Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre')
+[1,[7,8,9,10],{"trois":3,"quatre":4,"cinq":5}]
+SELECT Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre');
+Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre')
+[1,[7,8,9],{"trois":3,"quatre":44}]
+SELECT Json_Insert_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]');
+Json_Insert_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]')
+[1,[7,8,9],{"trois":3,"quatre":4,"cinq":5,"nxt":{"total":[300]}}]
+SELECT Json_Update_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]');
+Json_Update_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]')
+[1,[7,10,9],{"trois":3,"quatre":4}]
+SELECT Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]');
+Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]')
+[1,2,{"trois":3,"quatre":4},5]
+SELECT Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]');
+Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]')
+[1,2,{"trois":3,"quatre":4}]
+#
+# Test merging items UDF's
+#
+SELECT Json_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f'));
+Json_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f'))
+["a","b","c","d","e","f"]
+SELECT Json_Item_Merge(Json_Make_Array('a','b','c'), Json_Make_Array('d','e','f')) AS "Result";
+Result
+["a","b","c","d","e","f"]
+SELECT Json_Array_Add(Jbin_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f')), 'and', 3);
+Json_Array_Add(Jbin_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f')), 'and', 3)
+["a","b","c","and","d","e","f"]
+SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d",5 "e",6 "f"));
+Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d",5 "e",6 "f"))
+{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6}
+SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",2 "c"), Jbin_Array('d','e','f'));
+Json_Item_Merge(Jbin_Object(1 "a",2 "b",2 "c"), Jbin_Array('d','e','f'))
+Binary Json object
+Warnings:
+Warning 1105 Second argument is not an object
+SELECT Json_Object_Add(Jbin_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d",5 "e",6 "f")), 'x' AS "and");
+Json_Object_Add(Jbin_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d",5 "e",6 "f")), 'x' AS "and")
+{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"and":"x"}
+SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "a",5 "e",6 "f"));
+Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "a",5 "e",6 "f"))
+{"a":4,"b":2,"c":3,"e":5,"f":6}
+SELECT Json_Item_Merge('foo', Json_Make_Array('d','e','f'));
+ERROR HY000: Can't initialize function 'json_item_merge'; First argument must be a json item
+#
+# Test making file UDF's
+#
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json')
+bt1.json
+SELECT Json_File('bt1.json');
+Json_File('bt1.json')
+[
+ "a",
+ "b",
+ "c"
+]
+
+SELECT Json_File(Jfile_Make(Jbin_File('bt1.json'), 0));
+Json_File(Jfile_Make(Jbin_File('bt1.json'), 0))
+"a"
+"b"
+"c"
+
+SELECT Json_File(Jfile_Make(Jbin_File('bt1.json'), 1));
+Json_File(Jfile_Make(Jbin_File('bt1.json'), 1))
+[
+ "a",
+ "b",
+ "c"
+]
+
+SELECT Json_File(Jfile_Make(Jbin_File('bt1.json'), 2));
+Json_File(Jfile_Make(Jbin_File('bt1.json'), 2))
+[
+ "a",
+ "b",
+ "c"
+]
+
+SELECT Json_File('bt1.json', 0);
+Json_File('bt1.json', 0)
+["a","b","c"]
+Warnings:
+Warning 1105 File pretty format doesn't match the specified pretty value
+SELECT Json_File('bt1.json', 1);
+Json_File('bt1.json', 1)
+["a","b","c"]
+Warnings:
+Warning 1105 File pretty format doesn't match the specified pretty value
+SELECT Json_File('bt1.json', 2);
+Json_File('bt1.json', 2)
+["a","b","c"]
+SELECT Json_Serialize(Jbin_Array('a','b','c'));
+Json_Serialize(Jbin_Array('a','b','c'))
+["a","b","c"]
+SELECT Json_Serialize(Jbin_Array_Add(Jbin_File('not_exist.json'), 'd'));
+Json_Serialize(Jbin_Array_Add(Jbin_File('not_exist.json'), 'd'))
+[null,"d"]
+Warnings:
+Warning 1105 Open(map) error 2 on not_exist.json
+# This does not modify the file
+SELECT Json_Serialize(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'));
+Json_Serialize(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'))
+["a","b","c","d"]
+SELECT Json_File('bt1.json', 2);
+Json_File('bt1.json', 2)
+["a","b","c"]
+# This does modify the file
+SELECT Json_Array_Add(Jbin_File('bt1.json'), 'd');
+Json_Array_Add(Jbin_File('bt1.json'), 'd')
+bt1.json
+SELECT Json_File('bt1.json', 2);
+Json_File('bt1.json', 2)
+["a","b","c","d"]
+# Back to the original file
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json')
+bt1.json
+SELECT Json_Make_Object(Jbin_Array_Add(Jbin_Array('a','b','c'), 'd') "Jbin_foo") AS "Result";
+Result
+{"foo":["a","b","c","d"]}
+SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd')) AS "Result";
+Result
+{"Array_Add(Jbin_File('bt1.json'), 'd')":["a","b","c","d"]}
+SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1") AS "Result";
+Result
+{"bt1":["a","b","c","d"]}
+# This does modify the file
+SELECT Json_Make_Object(Json_Array_Add(Jbin_File('bt1.json'), 'd') "Jfile_bt1") AS "Result";
+Result
+{"bt1":["a","b","c","d"]}
+SELECT Json_File('bt1.json');
+Json_File('bt1.json')
+[
+ "a",
+ "b",
+ "c",
+ "d"
+]
+
+SELECT Json_File(Json_Array_Delete(Jbin_File('bt1.json'), 3), 2);
+Json_File(Json_Array_Delete(Jbin_File('bt1.json'), 3), 2)
+["a","b","c"]
+SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1", n "t1") AS "Result" from t1;
+Result
+{"bt1":["a","b","c","d"],"t1":1}
+{"bt1":["a","b","c","d"],"t1":2}
+{"bt1":["a","b","c","d"],"t1":3}
+SELECT Json_File(Json_Array_Add(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'), 'e')) AS "Result";
+Result
+[
+ "a",
+ "b",
+ "c",
+ "d",
+ "e"
+]
+
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json')
+bt1.json
+SELECT Json_File(Json_Array_Add(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'), 'e')) AS "Result" from t1;
+Result
+[
+ "a",
+ "b",
+ "c",
+ "d",
+ "e"
+]
+
+[
+ "a",
+ "b",
+ "c",
+ "d",
+ "e"
+]
+
+[
+ "a",
+ "b",
+ "c",
+ "d",
+ "e"
+]
+
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json')
+bt1.json
+SELECT Json_Array_Add(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'), n) AS "Result" from t1;
+Result
+bt1.json
+bt1.json
+bt1.json
+# Show modified file
+SELECT Json_File('bt1.json');
+Json_File('bt1.json')
+[
+ "a",
+ "b",
+ "c",
+ "d",
+ 1,
+ "d",
+ 2,
+ "d",
+ 3
+]
+
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json')
+bt1.json
+SELECT Json_Array_Add(Jbin_File('bt1.json'), n) AS "Result" from t1;
+Result
+bt1.json
+bt1.json
+bt1.json
+# Show modified file
+SELECT Json_File('bt1.json');
+Json_File('bt1.json')
+[
+ "a",
+ "b",
+ "c",
+ 1,
+ 2,
+ 3
+]
+
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json')
+bt1.json
+SELECT Json_File(Jbin_Item_Merge(Jbin_File('bt1.json'), Jbin_Array('d','e','f')));
+Json_File(Jbin_Item_Merge(Jbin_File('bt1.json'), Jbin_Array('d','e','f')))
+[
+ "a",
+ "b",
+ "c"
+]
+
+SELECT Json_File(Json_Item_Merge(Jbin_File('bt1.json'), Jbin_Array('d','e','f')));
+Json_File(Json_Item_Merge(Jbin_File('bt1.json'), Jbin_Array('d','e','f')))
+[
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f"
+]
+
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json')
+bt1.json
+# Test DELETE from file
+SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 1)) AS "Result";
+Result
+{"Array_Delete(Jbin_File('bt1.json'), 1)":["a","c"]}
+SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 2) "Jbin_bt1") AS "Result";
+Result
+{"bt1":["a","b"]}
+SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 0) "Jbin_bt1", n "t1") AS "Result" from t1;
+Result
+{"bt1":["b","c"],"t1":1}
+{"bt1":["b","c"],"t1":2}
+{"bt1":["b","c"],"t1":3}
+SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1;
+Result
+{"bt1":["a","b"]}
+{"bt1":["a"]}
+{"bt1":[]}
+SELECT Json_Make_Object(Json_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1;
+Result
+{"bt1":["a","b"]}
+{"bt1":["a"]}
+{"bt1":[]}
+# Show modified file
+SELECT Json_File('bt1.json');
+Json_File('bt1.json')
+[
+
+]
+
+# Object file
+SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0);
+Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0)
+bt2.json
+SELECT Json_File('bt2.json', 0);
+Json_File('bt2.json', 0)
+{"a":1,"b":2,"c":3}
+SELECT Json_File('bt2.json');
+Json_File('bt2.json')
+{"a":1,"b":2,"c":3}
+
+SELECT Json_Serialize(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"));
+Json_Serialize(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"))
+{"a":1,"b":2,"c":3,"d":4}
+# First query (file not modified)
+SELECT Json_Make_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jbin_new") AS "Result";
+Result
+{"new":{"a":1,"b":2,"c":3,"d":4}}
+# First query (file modified)
+SELECT Json_Make_Object(Json_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jfile_new") AS "Result";
+Result
+{"new":{"a":1,"b":2,"c":3,"d":4}}
+SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0);
+Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0)
+bt2.json
+SELECT Json_Make_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d") "Jbin_new", n "t1") AS "Result" from t1;
+Result
+{"new":{"a":1,"b":2,"c":3,"d":4},"t1":1}
+{"new":{"a":1,"b":2,"c":3,"d":4},"t1":2}
+{"new":{"a":1,"b":2,"c":3,"d":4},"t1":3}
+SELECT Json_File(Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), 5 "e")) AS "Result";
+Result
+{"a":1,"b":2,"c":3,"d":4,"e":5}
+
+SELECT Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), 5 "e") AS "Result" from t1;
+Result
+bt2.json
+bt2.json
+bt2.json
+SELECT Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), n "n") AS "Result" from t1;
+Result
+bt2.json
+bt2.json
+bt2.json
+SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0);
+Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0)
+bt2.json
+SELECT Json_Object_Add(Jbin_File('bt2.json'), n) AS "Result" from t1;
+Result
+bt2.json
+bt2.json
+bt2.json
+SELECT Json_File('bt2.json');
+Json_File('bt2.json')
+{"a":1,"b":2,"c":3,"n":3}
+
+SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0);
+Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0)
+bt2.json
+SELECT Json_Serialize(Jbin_Item_Merge(Jbin_File('bt2.json'), Jbin_Object(4 "d",5 "e",6 "f"))) AS "Result";
+Result
+{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6}
+SELECT Json_File(Json_Item_Merge(Jbin_File('bt2.json'), Jbin_Object(4 "d",5 "e",6 "f"))) AS "Result";
+Result
+{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6}
+
+SELECT Json_Item_Merge(Json_Make_Object(1 "a", 2 "b", 3 "c"), Json_Make_Object(4 "d",5 "b",6 "f")) AS "Result";
+Result
+{"a":1,"b":5,"c":3,"d":4,"f":6}
+SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'b')) AS "Result";
+Result
+{"Object_Delete(Jbin_File('bt2.json'), 'b')":{"a":1,"c":3,"d":4,"e":5,"f":6}}
+SELECT Json_Make_Object(Jbin_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result";
+Result
+{"bt1":{"a":1,"d":4,"e":5,"f":6}}
+SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result";
+Result
+{"bt1":{"a":1,"d":4,"e":5,"f":6}}
+SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jfile_bt1") AS "Result";
+Result
+{"bt1":{"a":1,"d":4,"e":5,"f":6}}
+SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'a') "Jbin_bt1", n "t1") AS "Result" from t1;
+Result
+{"bt1":{"d":4,"e":5,"f":6},"t1":1}
+{"bt1":{"d":4,"e":5,"f":6},"t1":2}
+{"bt1":{"d":4,"e":5,"f":6},"t1":3}
+SELECT Json_Serialize(Jbin_Object_List(Jbin_File('bt2.json'))) "Key list";
+Key list
+["d","e","f"]
+SELECT Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0);
+Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0)
+bt3.json
+SELECT Json_Array_Add(Json_File('bt3.json', '$.b'), 66);
+Json_Array_Add(Json_File('bt3.json', '$.b'), 66)
+[44,55,66]
+SELECT Json_Array_Add(Json_File('bt3.json'), 66, '$.b');
+Json_Array_Add(Json_File('bt3.json'), 66, '$.b')
+{"a":1,"b":[44,55,66]}
+SELECT Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66);
+Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66)
+bt3.json
+SELECT Json_File('bt3.json', 3);
+Json_File('bt3.json', 3)
+{"a":1,"b":[44,55,66]}
+SELECT Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0);
+Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0)
+bt3.json
+CREATE TABLE t2 (
+n INT KEY,
+jfile_cols CHAR(12) NOT NULL)
+ENGINE= MYISAM;
+INSERT INTO t2 VALUES(1,'bt3.json');
+# In this table, the jfile_cols column just contains a file name
+UPDATE t2 SET jfile_cols = Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66) WHERE n = 1;
+SELECT JsonGet_String(jfile_cols, '*') FROM t2;
+JsonGet_String(jfile_cols, '*')
+{"a":1,"b":[44,55,66]}
+UPDATE t2 SET jfile_cols = Json_Insert_Item(jfile_cols, 77, '$.b[]') WHERE n = 1;
+SELECT JsonGet_String(jfile_cols, '$.b.*') FROM t2;
+JsonGet_String(jfile_cols, '$.b.*')
+[44,55,66,77]
+UPDATE t2 SET jfile_cols = Json_Insert_Item(Jbin_Insert_Item(jfile_cols, 88, '$.b[]') , 99, '$.b[]') WHERE n = 1;
+SELECT JsonGet_String(jfile_cols, '*') FROM t2;
+JsonGet_String(jfile_cols, '*')
+{"a":1,"b":[44,55,66,77,88,99]}
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/r/mongo_c.result b/storage/connect/mysql-test/connect/r/mongo_c.result
new file mode 100644
index 00000000..5b29bb54
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mongo_c.result
@@ -0,0 +1,381 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+OPTION_LIST='Driver=C,Version=0' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51c"},"address":{"building":"1007","coord":[-73.856077,40.848447],"street":"Morris Park Ave","zipcode":"10462"},"borough":"Bronx","cuisine":"Bakery","grades":[{"date":{"$date":1393804800000.000000},"grade":"A","score":2},{"date":{"$date":1378857600000.000000},"grade":"A","score":6},{"date":{"$date":1358985600000.000000},"grade":"A","score":10},{"date":{"$date":1322006400000.000000},"grade":"A","score":9},{"date":{"$date":1299715200000.000000},"grade":"B","score":14}],"name":"Morris Park Bake Shop","restaurant_id":"30075445"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51d"},"address":{"building":"469","coord":[-73.961704,40.662942],"street":"Flatbush Avenue","zipcode":"11225"},"borough":"Brooklyn","cuisine":"Hamburgers","grades":[{"date":{"$date":1419897600000.000000},"grade":"A","score":8},{"date":{"$date":1404172800000.000000},"grade":"B","score":23},{"date":{"$date":1367280000000.000000},"grade":"A","score":12},{"date":{"$date":1336435200000.000000},"grade":"A","score":12}],"name":"Wendy'S","restaurant_id":"30112340"}
+{"_id":{"$oid":"58ada47de5a51ddfcd5ed51e"},"address":{"building":"351","coord":[-73.985136,40.767692],"street":"West 57 Street","zipcode":"10019"},"borough":"Manhattan","cuisine":"Irish","grades":[{"date":{"$date":1409961600000.000000},"grade":"A","score":2},{"date":{"$date":1374451200000.000000},"grade":"A","score":11},{"date":{"$date":1343692800000.000000},"grade":"A","score":12},{"date":{"$date":1325116800000.000000},"grade":"A","score":12}],"name":"Dj Reynolds Pub And Restaurant","restaurant_id":"30191841"}
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=C,Version=0' DATA_CHARSET=utf8 ;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Bpath
+_id 1 CHAR 24 24 0 0
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 512 512 0 0 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_0 1 CHAR 512 512 0 1 grades.0
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=C,Version=0' DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL,
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` varchar(512) NOT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_0` varchar(512) DEFAULT NULL `JPATH`='grades.0',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=C,Version=0' `DATA_CHARSET`='utf8'
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_0 name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 [-73.856077,40.848447] Morris Park Ave 10462 Bronx Bakery {"date":{"$date":1393804800000},"grade":"A","score":2} Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 [-73.961704,40.662942] Flatbush Avenue 11225 Brooklyn Hamburgers {"date":{"$date":1419897600000},"grade":"A","score":8} Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 [-73.985136,40.767692] West 57 Street 10019 Manhattan Irish {"date":{"$date":1409961600000},"grade":"A","score":2} Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 [-73.982420,40.579505] Stillwell Avenue 11224 Brooklyn American {"date":{"$date":1402358400000},"grade":"A","score":5} Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 [-73.860115,40.731174] 63 Road 11374 Queens Jewish/Kosher {"date":{"$date":1416787200000},"grade":"Z","score":20} Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"projection":{"grades":0}}' OPTION_LIST='Driver=C,Version=0,level=0' ;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c {"building":"1007","coord":[-73.856077,40.848447],"street":"Morris Park Ave","zipcode":"10462"} Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d {"building":"469","coord":[-73.961704,40.662942],"street":"Flatbush Avenue","zipcode":"11225"} Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e {"building":"351","coord":[-73.985136,40.767692],"street":"West 57 Street","zipcode":"10019"} Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f {"building":"2780","coord":[-73.982420,40.579505],"street":"Stillwell Avenue","zipcode":"11224"} Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 {"building":"97-22","coord":[-73.860115,40.731174],"street":"63 Road","zipcode":"11374"} Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 {"building":"8825","coord":[-73.880383,40.764312],"street":"Astoria Boulevard","zipcode":"11369"} Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 {"building":"2206","coord":[-74.137729,40.611957],"street":"Victory Boulevard","zipcode":"10314"} Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 {"building":"7114","coord":[-73.906851,40.619903],"street":"Avenue U","zipcode":"11234"} Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 {"building":"6409","coord":[-74.005289,40.628886],"street":"11 Avenue","zipcode":"11219"} Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 {"building":"1839","coord":[-73.948261,40.640827],"street":"Nostrand Avenue","zipcode":"11226"} Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0' ;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 2014-03-03
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 2014-03-03
+Wendy'S Flatbush Avenue 8 2014-12-30
+Dj Reynolds Pub And Restaurant West 57 Street 2 2014-09-06
+Riviera Caterer Stillwell Avenue 5 2014-06-10
+Tov Kosher Kitchen 63 Road 20 2014-11-24
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 2014-10-23 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 2014-08-14 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 2014-09-29 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 2014-02-11 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 2014-10-08 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 2014-06-09 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 2014-10-22 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 2014-07-26 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 2014-12-03 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 2015-01-16 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 2014-08-27 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 2014-06-03 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 2014-08-07 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 2014-12-27 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 2014-10-28 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 2014-08-18 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=C,Version=0' ;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=1' ;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 2014-11-10 01:00:00 B 15
+Tout Va Bien Manhattan 2014-04-03 02:00:00 A 13
+Tout Va Bien Manhattan 2013-07-17 02:00:00 C 36
+Tout Va Bien Manhattan 2013-02-06 01:00:00 B 22
+Tout Va Bien Manhattan 2012-07-16 02:00:00 C 36
+Tout Va Bien Manhattan 2012-03-08 01:00:00 C 7
+La Grenouille Manhattan 2014-04-09 02:00:00 A 10
+La Grenouille Manhattan 2013-03-05 01:00:00 A 9
+La Grenouille Manhattan 2012-02-02 01:00:00 A 13
+Le Perigord Manhattan 2014-07-14 02:00:00 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 2014-11-21 01:00:00
+Bistro Sk A 12 2014-02-19 01:00:00
+Bistro Sk B 18 2013-06-12 02:00:00
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"projection":{"cuisine":0}}'
+OPTION_LIST='Driver=C,level=2,version=0';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL,
+ `address_building` char(6) NOT NULL `JPATH`='address.building',
+ `address_coord_0` double(12,6) NOT NULL `JPATH`='address.coord.0',
+ `address_street` char(25) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_0_date` datetime NOT NULL `JPATH`='grades.0.date',
+ `grades_0_grade` char(14) NOT NULL `JPATH`='grades.0.grade',
+ `grades_0_score` int(11) NOT NULL `JPATH`='grades.0.score',
+ `name` char(32) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `COLIST`='{"projection":{"cuisine":0}}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=C,level=2,version=0'
+SELECT name, borough, address_street, grades_0_score AS score FROM t1 WHERE grades_0_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll'
+OPTION_LIST='Driver=C,Version=0' ;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=MONGO TABNAME='cities'
+OPTION_LIST='Driver=C,Version=0' DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=1' ;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=C,Version=0' ;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=C,Version=0,Pipeline=YES' ;
+SELECT * FROM t1;
+item total average
+journal 285 57.000000
+notebook 1368 456.000000
+paper 23 5.750000
+planner 167 41.750000
+postcard 23 5.750000
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/mongo_java_2.result b/storage/connect/mysql-test/connect/r/mongo_java_2.result
new file mode 100644
index 00000000..bcedd717
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mongo_java_2.result
@@ -0,0 +1,381 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+OPTION_LIST='Driver=Java,Version=2' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{ "_id" : { "$oid" : "58ada47de5a51ddfcd5ed51c"} , "address" : { "building" : "1007" , "coord" : [ -73.856077 , 40.848447] , "street" : "Morris Park Ave" , "zipcode" : "10462"} , "borough" : "Bronx" , "cuisine" : "Bakery" , "grades" : [ { "date" : { "$date" : "2014-03-03T00:00:00.000Z"} , "grade" : "A" , "score" : 2} , { "date" : { "$date" : "2013-09-11T00:00:00.000Z"} , "grade" : "A" , "score" : 6} , { "date" : { "$date" : "2013-01-24T00:00:00.000Z"} , "grade" : "A" , "score" : 10} , { "date" : { "$date" : "2011-11-23T00:00:00.000Z"} , "grade" : "A" , "score" : 9} , { "date" : { "$date" : "2011-03-10T00:00:00.000Z"} , "grade" : "B" , "score" : 14}] , "name" : "Morris Park Bake Shop" , "restaurant_id" : "30075445"}
+{ "_id" : { "$oid" : "58ada47de5a51ddfcd5ed51d"} , "address" : { "building" : "469" , "coord" : [ -73.961704 , 40.662942] , "street" : "Flatbush Avenue" , "zipcode" : "11225"} , "borough" : "Brooklyn" , "cuisine" : "Hamburgers" , "grades" : [ { "date" : { "$date" : "2014-12-30T00:00:00.000Z"} , "grade" : "A" , "score" : 8} , { "date" : { "$date" : "2014-07-01T00:00:00.000Z"} , "grade" : "B" , "score" : 23} , { "date" : { "$date" : "2013-04-30T00:00:00.000Z"} , "grade" : "A" , "score" : 12} , { "date" : { "$date" : "2012-05-08T00:00:00.000Z"} , "grade" : "A" , "score" : 12}] , "name" : "Wendy'S" , "restaurant_id" : "30112340"}
+{ "_id" : { "$oid" : "58ada47de5a51ddfcd5ed51e"} , "address" : { "building" : "351" , "coord" : [ -73.98513559999999 , 40.7676919] , "street" : "West 57 Street" , "zipcode" : "10019"} , "borough" : "Manhattan" , "cuisine" : "Irish" , "grades" : [ { "date" : { "$date" : "2014-09-06T00:00:00.000Z"} , "grade" : "A" , "score" : 2} , { "date" : { "$date" : "2013-07-22T00:00:00.000Z"} , "grade" : "A" , "score" : 11} , { "date" : { "$date" : "2012-07-31T00:00:00.000Z"} , "grade" : "A" , "score" : 12} , { "date" : { "$date" : "2011-12-29T00:00:00.000Z"} , "grade" : "A" , "score" : 12}] , "name" : "Dj Reynolds Pub And Restaurant" , "restaurant_id" : "30191841"}
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=Java,Version=2' DATA_CHARSET=utf8 ;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Bpath
+_id 1 CHAR 24 24 0 0
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 41 41 0 0 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_0 1 CHAR 99 99 0 1 grades.0
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=Java,Version=2' DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL,
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` char(41) NOT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_0` char(99) DEFAULT NULL `JPATH`='grades.0',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=Java,Version=2' `DATA_CHARSET`='utf8'
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_0 name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 [ -73.856077 , 40.848447] Morris Park Ave 10462 Bronx Bakery { "date" : { "$date" : "2014-03-03T00:00:00.000Z"} , "grade" : "A" , "score" : 2} Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 [ -73.961704 , 40.662942] Flatbush Avenue 11225 Brooklyn Hamburgers { "date" : { "$date" : "2014-12-30T00:00:00.000Z"} , "grade" : "A" , "score" : 8} Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 [ -73.98513559999999 , 40.7676919] West 57 Street 10019 Manhattan Irish { "date" : { "$date" : "2014-09-06T00:00:00.000Z"} , "grade" : "A" , "score" : 2} Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 [ -73.98241999999999 , 40.579505] Stillwell Avenue 11224 Brooklyn American { "date" : { "$date" : "2014-06-10T00:00:00.000Z"} , "grade" : "A" , "score" : 5} Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 [ -73.8601152 , 40.7311739] 63 Road 11374 Queens Jewish/Kosher { "date" : { "$date" : "2014-11-24T00:00:00.000Z"} , "grade" : "Z" , "score" : 20} Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"grades":0}' OPTION_LIST='Driver=Java,Version=2,level=0' ;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c { "building" : "1007" , "coord" : [ -73.856077 , 40.848447] , "street" : "Morris Park Ave" , "zipcode" : "10462"} Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d { "building" : "469" , "coord" : [ -73.961704 , 40.662942] , "street" : "Flatbush Avenue" , "zipcode" : "11225"} Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e { "building" : "351" , "coord" : [ -73.98513559999999 , 40.7676919] , "street" : "West 57 Street" , "zipcode" : "10019"} Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f { "building" : "2780" , "coord" : [ -73.98241999999999 , 40.579505] , "street" : "Stillwell Avenue" , "zipcode" : "11224"} Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 { "building" : "97-22" , "coord" : [ -73.8601152 , 40.7311739] , "street" : "63 Road" , "zipcode" : "11374"} Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 { "building" : "8825" , "coord" : [ -73.8803827 , 40.7643124] , "street" : "Astoria Boulevard" , "zipcode" : "11369"} Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 { "building" : "2206" , "coord" : [ -74.1377286 , 40.6119572] , "street" : "Victory Boulevard" , "zipcode" : "10314"} Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 { "building" : "7114" , "coord" : [ -73.9068506 , 40.6199034] , "street" : "Avenue U" , "zipcode" : "11234"} Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 { "building" : "6409" , "coord" : [ -74.00528899999999 , 40.628886] , "street" : "11 Avenue" , "zipcode" : "11219"} Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 { "building" : "1839" , "coord" : [ -73.9482609 , 40.6408271] , "street" : "Nostrand Avenue" , "zipcode" : "11226"} Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2' ;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 2014-03-03
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 2014-03-03
+Wendy'S Flatbush Avenue 8 2014-12-30
+Dj Reynolds Pub And Restaurant West 57 Street 2 2014-09-06
+Riviera Caterer Stillwell Avenue 5 2014-06-10
+Tov Kosher Kitchen 63 Road 20 2014-11-24
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 2014-10-23 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 2014-08-14 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 2014-09-29 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 2014-02-11 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 2014-10-08 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 2014-06-09 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 2014-10-22 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 2014-07-26 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 2014-12-03 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 2015-01-16 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 2014-08-27 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 2014-06-03 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 2014-08-07 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 2014-12-27 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 2014-10-28 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 2014-08-18 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=Java,Version=2' ;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=1' ;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 2014-11-10 01:00:00 B 15
+Tout Va Bien Manhattan 2014-04-03 02:00:00 A 13
+Tout Va Bien Manhattan 2013-07-17 02:00:00 C 36
+Tout Va Bien Manhattan 2013-02-06 01:00:00 B 22
+Tout Va Bien Manhattan 2012-07-16 02:00:00 C 36
+Tout Va Bien Manhattan 2012-03-08 01:00:00 C 7
+La Grenouille Manhattan 2014-04-09 02:00:00 A 10
+La Grenouille Manhattan 2013-03-05 01:00:00 A 9
+La Grenouille Manhattan 2012-02-02 01:00:00 A 13
+Le Perigord Manhattan 2014-07-14 02:00:00 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 2014-11-21 01:00:00
+Bistro Sk A 12 2014-02-19 01:00:00
+Bistro Sk B 18 2013-06-12 02:00:00
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"cuisine":0}'
+OPTION_LIST='Driver=Java,level=2,version=2';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL,
+ `address_building` char(6) NOT NULL `JPATH`='address.building',
+ `address_coord_0` double(18,14) NOT NULL `JPATH`='address.coord.0',
+ `address_street` char(25) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_0_date` datetime NOT NULL `JPATH`='grades.0.date',
+ `grades_0_grade` char(14) NOT NULL `JPATH`='grades.0.grade',
+ `grades_0_score` int(2) NOT NULL `JPATH`='grades.0.score',
+ `name` char(32) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=2'
+SELECT name, borough, address_street, grades_0_score AS score FROM t1 WHERE grades_0_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll'
+OPTION_LIST='Driver=Java,Version=2' ;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=MONGO TABNAME='cities'
+OPTION_LIST='Driver=Java,Version=2' DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=1' ;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=2' ;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=Java,Version=2,Pipeline=YES' ;
+SELECT * FROM t1;
+item total average
+journal 285 57.00
+notebook 1368 456.00
+paper 23 5.75
+planner 167 41.75
+postcard 23 5.75
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/mongo_java_3.result b/storage/connect/mysql-test/connect/r/mongo_java_3.result
new file mode 100644
index 00000000..3183d498
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mongo_java_3.result
@@ -0,0 +1,381 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+#
+# Test the MONGO table type
+#
+CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+OPTION_LIST='Driver=Java,Version=3' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+Document
+{ "_id" : { "$oid" : "58ada47de5a51ddfcd5ed51c" }, "address" : { "building" : "1007", "coord" : [-73.856077, 40.848447], "street" : "Morris Park Ave", "zipcode" : "10462" }, "borough" : "Bronx", "cuisine" : "Bakery", "grades" : [{ "date" : { "$date" : 1393804800000 }, "grade" : "A", "score" : 2 }, { "date" : { "$date" : 1378857600000 }, "grade" : "A", "score" : 6 }, { "date" : { "$date" : 1358985600000 }, "grade" : "A", "score" : 10 }, { "date" : { "$date" : 1322006400000 }, "grade" : "A", "score" : 9 }, { "date" : { "$date" : 1299715200000 }, "grade" : "B", "score" : 14 }], "name" : "Morris Park Bake Shop", "restaurant_id" : "30075445" }
+{ "_id" : { "$oid" : "58ada47de5a51ddfcd5ed51d" }, "address" : { "building" : "469", "coord" : [-73.961704, 40.662942], "street" : "Flatbush Avenue", "zipcode" : "11225" }, "borough" : "Brooklyn", "cuisine" : "Hamburgers", "grades" : [{ "date" : { "$date" : 1419897600000 }, "grade" : "A", "score" : 8 }, { "date" : { "$date" : 1404172800000 }, "grade" : "B", "score" : 23 }, { "date" : { "$date" : 1367280000000 }, "grade" : "A", "score" : 12 }, { "date" : { "$date" : 1336435200000 }, "grade" : "A", "score" : 12 }], "name" : "Wendy'S", "restaurant_id" : "30112340" }
+{ "_id" : { "$oid" : "58ada47de5a51ddfcd5ed51e" }, "address" : { "building" : "351", "coord" : [-73.98513559999999, 40.7676919], "street" : "West 57 Street", "zipcode" : "10019" }, "borough" : "Manhattan", "cuisine" : "Irish", "grades" : [{ "date" : { "$date" : 1409961600000 }, "grade" : "A", "score" : 2 }, { "date" : { "$date" : 1374451200000 }, "grade" : "A", "score" : 11 }, { "date" : { "$date" : 1343692800000 }, "grade" : "A", "score" : 12 }, { "date" : { "$date" : 1325116800000 }, "grade" : "A", "score" : 12 }], "name" : "Dj Reynolds Pub And Restaurant", "restaurant_id" : "30191841" }
+DROP TABLE t1;
+#
+# Test catfunc
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=Java,Version=3' DATA_CHARSET=utf8 ;
+SELECT * from t1;
+Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Nullable Bpath
+_id 1 CHAR 24 24 0 0
+address_building 1 CHAR 10 10 0 0 address.building
+address_coord 1 CHAR 39 39 0 0 address.coord
+address_street 1 CHAR 38 38 0 0 address.street
+address_zipcode 1 CHAR 5 5 0 0 address.zipcode
+borough 1 CHAR 13 13 0 0
+cuisine 1 CHAR 64 64 0 0
+grades_0 1 CHAR 84 84 0 1 grades.0
+name 1 CHAR 98 98 0 0
+restaurant_id 1 CHAR 8 8 0 0
+DROP TABLE t1;
+#
+# Explicit columns
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3';
+SELECT * FROM t1 LIMIT 10;
+_id name cuisine borough restaurant_id
+58ada47de5a51ddfcd5ed51c Morris Park Bake Shop Bakery Bronx 30075445
+58ada47de5a51ddfcd5ed51d Wendy'S Hamburgers Brooklyn 30112340
+58ada47de5a51ddfcd5ed51e Dj Reynolds Pub And Restaurant Irish Manhattan 30191841
+58ada47de5a51ddfcd5ed51f Riviera Caterer American Brooklyn 40356018
+58ada47de5a51ddfcd5ed520 Tov Kosher Kitchen Jewish/Kosher Queens 40356068
+58ada47de5a51ddfcd5ed521 Brunos On The Boulevard American Queens 40356151
+58ada47de5a51ddfcd5ed522 Kosher Island Jewish/Kosher Staten Island 40356442
+58ada47de5a51ddfcd5ed523 Wilken'S Fine Food Delicatessen Brooklyn 40356483
+58ada47de5a51ddfcd5ed524 Regina Caterers American Brooklyn 40356649
+58ada47de5a51ddfcd5ed525 Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn 40356731
+DROP TABLE t1;
+#
+# Test discovery
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=Java,Version=3' DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL,
+ `address_building` char(10) NOT NULL `JPATH`='address.building',
+ `address_coord` char(39) NOT NULL `JPATH`='address.coord',
+ `address_street` char(38) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `cuisine` char(64) NOT NULL,
+ `grades_0` char(84) DEFAULT NULL `JPATH`='grades.0',
+ `name` char(98) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=Java,Version=3' `DATA_CHARSET`='utf8'
+SELECT * FROM t1 LIMIT 5;
+_id address_building address_coord address_street address_zipcode borough cuisine grades_0 name restaurant_id
+58ada47de5a51ddfcd5ed51c 1007 [-73.856077, 40.848447] Morris Park Ave 10462 Bronx Bakery { "date" : { "$date" : 1393804800000 }, "grade" : "A", "score" : 2 } Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d 469 [-73.961704, 40.662942] Flatbush Avenue 11225 Brooklyn Hamburgers { "date" : { "$date" : 1419897600000 }, "grade" : "A", "score" : 8 } Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e 351 [-73.98513559999999, 40.7676919] West 57 Street 10019 Manhattan Irish { "date" : { "$date" : 1409961600000 }, "grade" : "A", "score" : 2 } Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f 2780 [-73.98241999999999, 40.579505] Stillwell Avenue 11224 Brooklyn American { "date" : { "$date" : 1402358400000 }, "grade" : "A", "score" : 5 } Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 97-22 [-73.8601152, 40.7311739] 63 Road 11374 Queens Jewish/Kosher { "date" : { "$date" : 1416787200000 }, "grade" : "Z", "score" : 20 } Tov Kosher Kitchen 40356068
+DROP TABLE t1;
+#
+# Dropping a column
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='{"grades":0}' OPTION_LIST='Driver=Java,Version=3,level=0' ;
+SELECT * FROM t1 LIMIT 10;
+_id address borough cuisine name restaurant_id
+58ada47de5a51ddfcd5ed51c { "building" : "1007", "coord" : [-73.856077, 40.848447], "street" : "Morris Park Ave", "zipcode" : "10462" } Bronx Bakery Morris Park Bake Shop 30075445
+58ada47de5a51ddfcd5ed51d { "building" : "469", "coord" : [-73.961704, 40.662942], "street" : "Flatbush Avenue", "zipcode" : "11225" } Brooklyn Hamburgers Wendy'S 30112340
+58ada47de5a51ddfcd5ed51e { "building" : "351", "coord" : [-73.98513559999999, 40.7676919], "street" : "West 57 Street", "zipcode" : "10019" } Manhattan Irish Dj Reynolds Pub And Restaurant 30191841
+58ada47de5a51ddfcd5ed51f { "building" : "2780", "coord" : [-73.98241999999999, 40.579505], "street" : "Stillwell Avenue", "zipcode" : "11224" } Brooklyn American Riviera Caterer 40356018
+58ada47de5a51ddfcd5ed520 { "building" : "97-22", "coord" : [-73.8601152, 40.7311739], "street" : "63 Road", "zipcode" : "11374" } Queens Jewish/Kosher Tov Kosher Kitchen 40356068
+58ada47de5a51ddfcd5ed521 { "building" : "8825", "coord" : [-73.8803827, 40.7643124], "street" : "Astoria Boulevard", "zipcode" : "11369" } Queens American Brunos On The Boulevard 40356151
+58ada47de5a51ddfcd5ed522 { "building" : "2206", "coord" : [-74.1377286, 40.6119572], "street" : "Victory Boulevard", "zipcode" : "10314" } Staten Island Jewish/Kosher Kosher Island 40356442
+58ada47de5a51ddfcd5ed523 { "building" : "7114", "coord" : [-73.9068506, 40.6199034], "street" : "Avenue U", "zipcode" : "11234" } Brooklyn Delicatessen Wilken'S Fine Food 40356483
+58ada47de5a51ddfcd5ed524 { "building" : "6409", "coord" : [-74.00528899999999, 40.628886], "street" : "11 Avenue", "zipcode" : "11219" } Brooklyn American Regina Caterers 40356649
+58ada47de5a51ddfcd5ed525 { "building" : "1839", "coord" : [-73.9482609, 40.6408271], "street" : "Nostrand Avenue", "zipcode" : "11226" } Brooklyn Ice Cream, Gelato, Yogurt, Ices Taste The Tropics Ice Cream 40356731
+DROP TABLE t1;
+#
+# Specifying Jpath
+#
+CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3' ;
+SELECT * FROM t1 LIMIT 1;
+_id 58ada47de5a51ddfcd5ed51c
+name Morris Park Bake Shop
+cuisine Bakery
+borough Bronx
+street Morris Park Ave
+building 1007
+zipcode 10462
+grade A
+score 2
+date 2014-03-03
+restaurant_id 30075445
+SELECT name, street, score, date FROM t1 LIMIT 5;
+name street score date
+Morris Park Bake Shop Morris Park Ave 2 2014-03-03
+Wendy'S Flatbush Avenue 8 2014-12-30
+Dj Reynolds Pub And Restaurant West 57 Street 2 2014-09-06
+Riviera Caterer Stillwell Avenue 5 2014-06-10
+Tov Kosher Kitchen 63 Road 20 2014-11-24
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+name cuisine borough
+Morris Park Bake Shop Bakery Bronx
+Wendy'S Hamburgers Brooklyn
+Dj Reynolds Pub And Restaurant Irish Manhattan
+Riviera Caterer American Brooklyn
+Kosher Island Jewish/Kosher Staten Island
+Wilken'S Fine Food Delicatessen Brooklyn
+Regina Caterers American Brooklyn
+Taste The Tropics Ice Cream Ice Cream, Gelato, Yogurt, Ices Brooklyn
+Wild Asia American Bronx
+C & C Catering Service American Brooklyn
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+COUNT(*)
+20687
+SELECT * FROM t1 WHERE cuisine = 'English';
+_id name cuisine borough street building zipcode grade score date restaurant_id
+58ada47de5a51ddfcd5ed83d Tea And Sympathy English Manhattan Greenwich Avenue 108 10011 A 8 2014-10-23 40391531
+58ada47de5a51ddfcd5ed85c Tartine English Manhattan West 11 Street 253 10014 A 11 2014-08-14 40392496
+58ada47de5a51ddfcd5ee1f3 The Park Slope Chipshop English Brooklyn 5 Avenue 383 11215 B 17 2014-09-29 40816202
+58ada47de5a51ddfcd5ee7e4 Pound And Pence English Manhattan Liberty Street 55 10005 A 7 2014-02-11 41022701
+58ada47de5a51ddfcd5ee999 Chip Shop English Brooklyn Atlantic Avenue 129 11201 A 9 2014-10-08 41076583
+58ada47ee5a51ddfcd5efe3f The Breslin Bar & Dining Room English Manhattan West 29 Street 16 10001 A 13 2014-06-09 41443706
+58ada47ee5a51ddfcd5efe99 Highlands Restaurant English Manhattan West 10 Street 150 10014 A 12 2014-10-22 41448559
+58ada47ee5a51ddfcd5f0413 The Fat Radish English Manhattan Orchard Street 17 10002 A 12 2014-07-26 41513545
+58ada47ee5a51ddfcd5f0777 Jones Wood Foundry English Manhattan East 76 Street 401 10021 A 12 2014-12-03 41557377
+58ada47ee5a51ddfcd5f0ea2 Whitehall English Manhattan Greenwich Avenue 19 10014 Z 15 2015-01-16 41625263
+58ada47ee5a51ddfcd5f1004 The Churchill Tavern English Manhattan East 28 Street 45 10016 A 13 2014-08-27 41633327
+58ada47ee5a51ddfcd5f13d5 The Monro English Brooklyn 5 Avenue 481 11215 A 7 2014-06-03 41660253
+58ada47ee5a51ddfcd5f1454 The Cock & Bull English Manhattan West 45 Street 23 10036 A 7 2014-08-07 41664704
+58ada47ee5a51ddfcd5f176e Dear Bushwick English Brooklyn Wilson Avenue 41 11237 A 12 2014-12-27 41690534
+58ada47ee5a51ddfcd5f1e91 Snowdonia Pub English Queens 32 Street 34-55 11106 A 12 2014-10-28 50000290
+58ada47ee5a51ddfcd5f2ddc Oscar'S Place English Manhattan Hudson Street 466 10014 A 10 2014-08-18 50011097
+SELECT * FROM t1 WHERE score = building;
+_id name cuisine borough street building zipcode grade score date restaurant_id
+DROP TABLE t1;
+#
+# Specifying Filter
+#
+CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+OPTION_LIST='Driver=Java,Version=3' ;
+SELECT name FROM t1 WHERE borough = 'Queens';
+name
+La Baraka Restaurant
+Air France Lounge
+Tournesol
+Winegasm
+Cafe Henri
+Bistro 33
+Domaine Wine Bar
+Cafe Triskell
+Cannelle Patisserie
+La Vie
+Dirty Pierres Bistro
+Fresca La Crepe
+Bliss 46 Bistro
+Bear
+Cuisine By Claudette
+Paris Baguette
+The Baroness Bar
+Francis Cafe
+Madame Sou Sou
+Crepe 'N' Tearia
+Aperitif Bayside Llc
+DROP TABLE t1;
+#
+# Testing pipeline
+#
+CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$match":{"cuisine":"French"}},{"$unwind":"$grades"},{"$project":{"_id":0,"name":1,"borough":1,"date":"$grades.date","grade":"$grades.grade","score":"$grades.score"}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=1' ;
+SELECT * FROM t1 LIMIT 10;
+name borough date grade score
+Tout Va Bien Manhattan 2014-11-10 01:00:00 B 15
+Tout Va Bien Manhattan 2014-04-03 02:00:00 A 13
+Tout Va Bien Manhattan 2013-07-17 02:00:00 C 36
+Tout Va Bien Manhattan 2013-02-06 01:00:00 B 22
+Tout Va Bien Manhattan 2012-07-16 02:00:00 C 36
+Tout Va Bien Manhattan 2012-03-08 01:00:00 C 7
+La Grenouille Manhattan 2014-04-09 02:00:00 A 10
+La Grenouille Manhattan 2013-03-05 01:00:00 A 9
+La Grenouille Manhattan 2012-02-02 01:00:00 A 13
+Le Perigord Manhattan 2014-07-14 02:00:00 B 14
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+name grade score date
+Bistro Sk A 10 2014-11-21 01:00:00
+Bistro Sk A 12 2014-02-19 01:00:00
+Bistro Sk B 18 2013-06-12 02:00:00
+DROP TABLE t1;
+#
+# try level 2 discovery
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"$ne":"Manhattan"}}'
+COLIST='{"cuisine":0}'
+OPTION_LIST='Driver=Java,level=2,version=3';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `_id` char(24) NOT NULL,
+ `address_building` char(6) NOT NULL `JPATH`='address.building',
+ `address_coord_0` double(18,14) NOT NULL `JPATH`='address.coord.0',
+ `address_street` char(25) NOT NULL `JPATH`='address.street',
+ `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode',
+ `borough` char(13) NOT NULL,
+ `grades_0_date` datetime NOT NULL `JPATH`='grades.0.date',
+ `grades_0_grade` char(14) NOT NULL `JPATH`='grades.0.grade',
+ `grades_0_score` int(2) NOT NULL `JPATH`='grades.0.score',
+ `name` char(32) NOT NULL,
+ `restaurant_id` char(8) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=3'
+SELECT name, borough, address_street, grades_0_score AS score FROM t1 WHERE grades_0_grade = 'B';
+name borough address_street score
+Le Gamin Brooklyn Vanderbilt Avenue 24
+Bistro 33 Queens Ditmars Boulevard 15
+Dirty Pierres Bistro Queens Station Square 22
+Santos Anne Brooklyn Union Avenue 26
+Le Paddock Brooklyn Prospect Avenue 17
+La Crepe Et La Vie Brooklyn Foster Avenue 24
+Francis Cafe Queens Ditmars Boulevard 19
+DROP TABLE t1;
+#
+# try CRUD operations
+#
+false
+CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll'
+OPTION_LIST='Driver=Java,Version=3' ;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+_id msg
+0 NULL
+1 One
+2 Two
+3 Three
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+_id msg
+1 One
+2 Deux
+3 Three
+DELETE FROM t1;
+DROP TABLE t1;
+true
+#
+# List states whose population is equal or more than 10 millions
+#
+false
+CREATE TABLE t1 (
+_id char(5) NOT NULL,
+city char(16) NOT NULL,
+loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+loc_1 char(12) NOT NULL `JPATH`='loc.1',
+pop int(11) NOT NULL,
+state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=MONGO TABNAME='cities'
+OPTION_LIST='Driver=Java,Version=3' DATA_CHARSET='utf8';
+# Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+state totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+# Using a pipeline for grouping
+CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"$group":{"_id":"$state","totalPop":{"$sum":"$pop"}}},{"$match":{"totalPop":{"$gte":10000000}}},{"$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=1' ;
+SELECT * FROM t1;
+_id totalPop
+CA 29754890
+NY 17990402
+TX 16984601
+FL 12686644
+PA 11881643
+IL 11427576
+OH 10846517
+DROP TABLE t1;
+true
+#
+# Test making array
+#
+CREATE TABLE t1 (
+_id int(4) NOT NULL,
+item CHAR(8) NOT NULL,
+prices_0 INT(6) JPATH='prices.0',
+prices_1 INT(6) JPATH='prices.1',
+prices_2 INT(6) JPATH='prices.2',
+prices_3 INT(6) JPATH='prices.3',
+prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=Java,Version=3' ;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+_id item prices_0 prices_1 prices_2 prices_3 prices_4
+1 journal 87 45 63 12 78
+2 notebook 123 456 789 NULL NULL
+3 paper 5 7 3 8 NULL
+4 planner 25 71 NULL 44 27
+5 postcard 5 7 3 8 NULL
+DROP TABLE t1;
+#
+# Test array aggregation
+#
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=MONGO TABNAME='testcoll'
+COLIST='{"pipeline":[{"$project":{"_id":0,"item":1,"total":{"$sum":"$prices"},"average":{"$avg":"$prices"}}}]}'
+OPTION_LIST='Driver=Java,Version=3,Pipeline=YES' ;
+SELECT * FROM t1;
+item total average
+journal 285 57.00
+notebook 1368 456.00
+paper 23 5.75
+planner 167 41.75
+postcard 23 5.75
+DROP TABLE t1;
+true
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/r/mrr.result b/storage/connect/mysql-test/connect/r/mrr.result
new file mode 100644
index 00000000..0d31daa7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mrr.result
@@ -0,0 +1,117 @@
+#
+# Show MRR setting. The way it is done is because the t3 table cannot be directly based on
+# the information_schema.session_variables table. Not being a CONNECT table, it would be
+# read using an intermediate MYSQL table using the MySQL API and could not reflect the
+# current session variable change (the call would create another session) This would be
+# correct only for querying GLOBAL variables but is not what we want to do here.
+#
+CREATE TABLE t2 (
+name VARCHAR(64) NOT NULL,
+value VARCHAR(1024) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DOS;
+Warnings:
+Warning 1105 No file name. Table will use t2.dos
+INSERT INTO t2 SELECT * FROM information_schema.session_variables WHERE variable_name = 'OPTIMIZER_SWITCH';
+create table t3 (
+name CHAR(32) NOT NULL,
+value CHAR(64) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=XCOL TABNAME=t2 OPTION_LIST='Colname=value';
+SELECT value FROM t3 WHERE value LIKE 'mrr%';
+value
+mrr=off
+mrr_cost_based=off
+mrr_sort_keys=off
+#
+# Testing indexing with MRR OFF
+#
+CREATE TABLE t1
+(
+matricule INT(4) KEY NOT NULL field_format='Z',
+nom VARCHAR(16) NOT NULL,
+prenom VARCHAR(20) NOT NULL,
+sexe SMALLINT(1) NOT NULL COMMENT 'sexe 1:M 2:F',
+aanais INT(4) NOT NULL,
+mmnais INT(2) NOT NULL,
+ddentree DATE NOT NULL date_format='YYYYMM',
+ddnom DATE NOT NULL date_format='YYYYMM',
+brut INT(5) NOT NULL,
+net DOUBLE(8,2) NOT NULL,
+service INT(2) NOT NULL,
+sitmat CHAR(1) NOT NULL,
+formation CHAR(5) NOT NULL,
+INDEX NP(nom,prenom)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='emp.txt' ENDING=2;
+SELECT * FROM t1 LIMIT 10;
+matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation
+5745 ESCOURCHE BENEDICTE 2 1935 7 1962-12-01 1994-05-01 18345 14275.50 0 M TECHN
+9692 VICENTE LAURENCE 2 1941 8 1967-10-01 1989-01-01 16212 13032.80 0 M ANGL
+9146 NICOLAS ROGER 1 1941 6 1964-07-01 1995-02-01 34173 25098.65 0 M SANS
+2985 TESSEREAU MARIE HELENE 2 1941 9 1967-01-01 1990-01-01 19323 14933.78 0 V SANS
+3368 MOGADOR ALAIN 1 1941 1 1961-09-01 1993-11-01 43303 31420.55 0 C SANS
+7394 CHAUSSEE ERIC DENIS 1 1944 9 1965-11-01 1983-12-01 32002 23583.86 0 M ANGL
+4655 MAILLOT GEORGES 1 1945 5 1970-09-01 1986-12-01 24700 18541.64 0 C ANGL
+2825 CAMILLE NADINE 2 1956 9 1994-01-01 1993-01-01 19494 15050.45 0 M SANS
+1460 BRUYERES JEAN MARC 1 1958 8 1984-08-01 1988-05-01 20902 15980.07 0 M SANS
+4974 LONES GERARD 1 1959 10 1979-01-01 1994-12-01 16081 12916.70 0 M SANS
+# Without MRR, the rows are retrieved sorted by name
+SELECT matricule, nom, prenom, sitmat, net FROM t1 WHERE nom IN ('ETANG','FOCH','CERF','ITALIE','ROI');
+matricule nom prenom sitmat net
+5324 CERF CLAUDE M 9503.34
+7703 CERF NICOLE M 12025.61
+3110 CERF VALERIE M 10472.37
+4454 ETANG BEATRICE M 11017.61
+1022 ETANG GERARD L 8729.58
+8222 ETANG LIONEL M 13497.90
+2492 ETANG PASCAL VINCENT M 11986.62
+1977 FOCH BERNADETTE . 8145.03
+5707 FOCH DENIS C 7679.36
+2552 FOCH FRANCK M 10745.81
+2634 FOCH JOCELYNE M 10473.09
+5765 FOCH ROBERT M 12916.32
+4080 FOCH SERGE M 9658.24
+5898 ITALIE DENIS M 9502.41
+7606 ITALIE JACQUES C 7679.45
+1067 ITALIE SVETLANA M 11713.61
+5853 ROI CHANTAL . 8147.06
+2995 ROI JEAN M 11715.50
+2531 ROI MICHEL L 10240.44
+5846 ROI PATRICIA M 15669.57
+#
+# Testing indexing with MRR ON
+#
+SET @@LOCAL.OPTIMIZER_SWITCH='mrr=on';
+# Refresh the t2 table to reflect the change
+UPDATE t2, information_schema.session_variables SET value = variable_value WHERE variable_name = 'OPTIMIZER_SWITCH';
+# Check that MRR is ON for the session
+SELECT value FROM t3 WHERE value LIKE 'mrr%';
+value
+mrr=on
+mrr_cost_based=off
+mrr_sort_keys=off
+# With MRR, the rows are retrieved sorted by their position in the table
+SELECT matricule, nom, prenom, sitmat, net FROM t1 WHERE nom IN ('ETANG','FOCH','CERF','ITALIE','ROI');
+matricule nom prenom sitmat net
+1977 FOCH BERNADETTE . 8145.03
+2995 ROI JEAN M 11715.50
+3110 CERF VALERIE M 10472.37
+5324 CERF CLAUDE M 9503.34
+4080 FOCH SERGE M 9658.24
+4454 ETANG BEATRICE M 11017.61
+5898 ITALIE DENIS M 9502.41
+2552 FOCH FRANCK M 10745.81
+2531 ROI MICHEL L 10240.44
+5853 ROI CHANTAL . 8147.06
+8222 ETANG LIONEL M 13497.90
+5707 FOCH DENIS C 7679.36
+1067 ITALIE SVETLANA M 11713.61
+7606 ITALIE JACQUES C 7679.45
+7703 CERF NICOLE M 12025.61
+2634 FOCH JOCELYNE M 10473.09
+1022 ETANG GERARD L 8729.58
+5846 ROI PATRICIA M 15669.57
+2492 ETANG PASCAL VINCENT M 11986.62
+5765 FOCH ROBERT M 12916.32
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+SET @@LOCAL.OPTIMIZER_SWITCH='mrr=off';
diff --git a/storage/connect/mysql-test/connect/r/mul.result b/storage/connect/mysql-test/connect/r/mul.result
new file mode 100644
index 00000000..d362da13
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mul.result
@@ -0,0 +1,57 @@
+#
+# Testing multiple 1
+#
+CREATE TABLE `t1` (
+`a` char(10) DEFAULT NULL,
+`b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=CSV `sep_char`=';';
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+INSERT INTO t1 VALUES('test1','bla');
+SELECT * FROM t1;
+a b
+test1 bla
+CREATE TABLE `t2` (
+`a` char(10) DEFAULT NULL,
+`b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=CSV `sep_char`=';';
+Warnings:
+Warning 1105 No file name. Table will use t2.csv
+INSERT INTO t2 VALUES('test2','blub');
+SELECT * FROM t2;
+a b
+test2 blub
+CREATE TABLE `t_all` (
+`a` char(10) DEFAULT NULL,
+`b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=CSV `file_name`='t*.csv' `sep_char`=';' `multiple`=1;
+SELECT * FROM t_all order by `a`;
+a b
+test1 bla
+test2 blub
+#
+# Testing multiple 2
+#
+CREATE table fnlist (
+fn char(8) not null
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 table_type=DOS;
+Warnings:
+Warning 1105 No file name. Table will use fnlist.dos
+INSERT INTO fnlist VALUES('t1.csv'),('t2.csv');
+SELECT fn FROM fnlist;
+fn
+t1.csv
+t2.csv
+CREATE TABLE `tblist` (
+`a` char(10) DEFAULT NULL,
+`b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=CSV `file_name`='fnlist.dos' `sep_char`=';' `multiple`=2;
+SELECT * FROM tblist;
+a b
+test1 bla
+test2 blub
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t_all;
+DROP TABLE fnlist;
+DROP TABLE tblist;
diff --git a/storage/connect/mysql-test/connect/r/mul_new.result b/storage/connect/mysql-test/connect/r/mul_new.result
new file mode 100644
index 00000000..ba8112f5
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mul_new.result
@@ -0,0 +1,136 @@
+#
+# Testing multiple 1
+#
+CREATE TABLE t1 (
+Chiffre int(3) NOT NULL,
+Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='num1.csv' LRECL=20 HEADER=1;
+INSERT INTO t1 VALUES(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five'),(6,'Six');
+SELECT * FROM t1;
+Chiffre Lettre
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+6 Six
+CREATE TABLE t2 (
+Chiffre int(3) NOT NULL,
+Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='subdir/num2.csv' LRECL=20 HEADER=1;
+INSERT INTO t2 VALUES(7,'Seven'),(8,'Eight'),(9,'Nine'),(10,'Ten'),(11,'Eleven'),(12,'Twelve');
+SELECT * FROM t2;
+Chiffre Lettre
+7 Seven
+8 Eight
+9 Nine
+10 Ten
+11 Eleven
+12 Twelve
+CREATE TABLE t3 (
+Chiffre int(3) NOT NULL,
+Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='num3.csv' LRECL=20 HEADER=1;
+INSERT INTO t3 VALUES(13,'Thirteen'),(14,'Fourteen'),(15,'Fifteen'),(16,'Sixteen'),(17,'Seventeen'),(18,'Eighteen');
+SELECT * FROM t3;
+Chiffre Lettre
+13 Thirteen
+14 Fourteen
+15 Fifteen
+16 Sixteen
+17 Seventeen
+18 Eighteen
+CREATE TABLE t4 (
+Chiffre int(3) NOT NULL,
+Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='subdir/num4.csv' LRECL=20 HEADER=1;
+INSERT INTO t4 VALUES(19,'Nineteen'),(20,'Twenty'),(21,'Twenty one'),(22,'Twenty two'),(23,'Tenty three'),(24,'Twenty four');
+SELECT * FROM t4;
+Chiffre Lettre
+19 Nineteen
+20 Twenty
+21 Twenty one
+22 Twenty two
+23 Tenty three
+24 Twenty four
+CREATE TABLE t5 (
+Chiffre int(3) NOT NULL,
+Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='num5.csv' LRECL=20 HEADER=1;
+INSERT INTO t5 VALUES(25,'Twenty five'),(26,'Twenty six'),(27,'Twenty seven'),(28,'Twenty eight'),(29,'Tenty eight'),(30,'Thirty');
+SELECT * FROM t5;
+Chiffre Lettre
+25 Twenty five
+26 Twenty six
+27 Twenty seven
+28 Twenty eight
+29 Tenty eight
+30 Thirty
+CREATE TABLE t_all (
+Chiffre int(3) not null,
+Lettre char(16) not null)
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='num?.csv' HEADER=1 LRECL=20 MULTIPLE=1;
+SELECT * FROM t_all ORDER BY Chiffre;
+Chiffre Lettre
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+6 Six
+13 Thirteen
+14 Fourteen
+15 Fifteen
+16 Sixteen
+17 Seventeen
+18 Eighteen
+25 Twenty five
+26 Twenty six
+27 Twenty seven
+28 Twenty eight
+29 Tenty eight
+30 Thirty
+#
+# Testing multiple 3
+#
+ALTER TABLE t_all MULTIPLE=3;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+SELECT * FROM t_all ORDER BY Chiffre;
+Chiffre Lettre
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+6 Six
+7 Seven
+8 Eight
+9 Nine
+10 Ten
+11 Eleven
+12 Twelve
+13 Thirteen
+14 Fourteen
+15 Fifteen
+16 Sixteen
+17 Seventeen
+18 Eighteen
+19 Nineteen
+20 Twenty
+21 Twenty one
+22 Twenty two
+23 Tenty three
+24 Twenty four
+25 Twenty five
+26 Twenty six
+27 Twenty seven
+28 Twenty eight
+29 Tenty eight
+30 Thirty
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+DROP TABLE t5;
+DROP TABLE t_all;
diff --git a/storage/connect/mysql-test/connect/r/mysql.result b/storage/connect/mysql-test/connect/r/mysql.result
new file mode 100644
index 00000000..3ac23394
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql.result
@@ -0,0 +1,296 @@
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+#
+# Testing errors
+#
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root1,port=PORT';
+ERROR HY000: (1045) Access denied for user 'root1'@'localhost' (using password: NO)
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL DBNAME='unknown' TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+ERROR HY000: (1049) Unknown database 'unknown'
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL OPTION_LIST='host=localhost,user=root,port=PORT' DBNAME='unknown' TABNAME='t1';
+ERROR HY000: (1049) Unknown database 'unknown'
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='unknown' OPTION_LIST='host=localhost,user=root,port=PORT';
+ERROR HY000: (1146) Table 'test.unknown' doesn't exist [SHOW FULL COLUMNS FROM `unknown` FROM test]
+SHOW CREATE TABLE t2;
+ERROR 42S02: Table 'test.t2' doesn't exist
+CREATE TABLE t2 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `x` int(11) DEFAULT NULL,
+ `y` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+ERROR HY000: Got error 174 '(1054) Unknown column 'x' in 'field list' [SELECT `x`, `y` FROM `t1`]' from CONNECT
+DROP TABLE t2;
+CREATE TABLE t2 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+ALTER TABLE t1 RENAME t1backup;
+SELECT * FROM t2;
+ERROR HY000: Got error 174 '(1146) Table 'test.t1' doesn't exist [SELECT `a`, `b` FROM `t1`]' from CONNECT
+ALTER TABLE t1backup RENAME t1;
+DROP TABLE t2;
+#
+# Testing SELECT, etc.
+#
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t2;
+CREATE TABLE t2 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t2;
+CREATE TABLE t2 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) NOT NULL,
+ `b` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a b
+0
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t2;
+CREATE TABLE t2 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` char(10) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a b
+NULL NULL
+0 0
+1 0
+2 0
+3 0
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# Testing numeric data types
+#
+CREATE TABLE t1 (a smallint);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` smallint(6) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` smallint(6) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a
+DROP TABLE t2, t1;
+CREATE TABLE t1 (a mediumint);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` mediumint(9) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(9) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a
+DROP TABLE t2, t1;
+CREATE TABLE t1 (a int);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a
+DROP TABLE t2, t1;
+CREATE TABLE t1 (a bigint);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` bigint(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` bigint(20) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a
+DROP TABLE t2, t1;
+#
+# Testing character data types
+#
+CREATE TABLE t1 (a char(10));
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(10) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a
+DROP TABLE t2, t1;
+CREATE TABLE t1 (a varchar(10));
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(10) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` varchar(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a
+DROP TABLE t2, t1;
+#
+# Testing binary data types
+#
+#
+# Testing temporal data types
+#
+CREATE TABLE t1 (a date);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` date DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` date DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `TABNAME`='t1' `OPTION_LIST`='host=localhost,user=root,port=PORT'
+SELECT * FROM t2;
+a
+DROP TABLE t2, t1;
+#
+# MDEV-4877 mysqldump dumps all data from a connect table
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20),(30);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:PORT/test/t1';
+SELECT * FROM t2;
+a
+10
+20
+30
+# Start of mysqldump ------
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@localhost:PORT/test/t1' `TABLE_TYPE`='MYSQL';
+/*!40101 SET character_set_client = @saved_cs_client */;
+# End of mysqldump ------
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# Testing getting unsigned types
+#
+CREATE TABLE t1 (
+a TINYINT UNSIGNED NOT NULL,
+b SMALLINT ZEROFILL NOT NULL,
+c INT UNSIGNED NOT NULL,
+d BIGINT UNSIGNED NOT NULL,
+e CHAR(32) NOT NULL DEFAULT 'Hello') ENGINE=CONNECT TABLE_TYPE=FIX;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+DESCRIBE t1;
+Field Type Null Key Default Extra
+a tinyint(3) unsigned NO NULL
+b smallint(5) unsigned zerofill NO NULL
+c int(10) unsigned NO NULL
+d bigint(20) unsigned NO NULL
+e char(32) NO Hello
+INSERT INTO t1(a,b,c,d) VALUES(255,65535,4294967295,18446744073709551615);
+SELECT * FROM t1;
+a b c d e
+255 65535 4294967295 18446744073709551615 Hello
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME=t1;
+DESCRIBE t2;
+Field Type Null Key Default Extra
+a tinyint(3) unsigned NO NULL
+b smallint(5) unsigned zerofill NO NULL
+c int(10) unsigned NO NULL
+d bigint(20) unsigned NO NULL
+e char(32) NO Hello
+SELECT * FROM t2;
+a b c d e
+255 65535 4294967295 18446744073709551615 Hello
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20),(30);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:PORT/test/t1';
+SELECT * FROM t2;
+a
+10
+20
+30
+ALTER TABLE t2 MODIFY a TINYINT;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` tinyint(4) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@localhost:PORT/test/t1' `TABLE_TYPE`='MYSQL'
+SELECT * FROM t2;
+a
+10
+20
+30
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/mysql_discovery.result b/storage/connect/mysql-test/connect/r/mysql_discovery.result
new file mode 100644
index 00000000..32bd4761
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_discovery.result
@@ -0,0 +1,45 @@
+connect master,127.0.0.1,root,,test,$MASTER_MYPORT,;
+connect slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
+connection master;
+CREATE DATABASE connect;
+connection slave;
+CREATE DATABASE connect;
+connection slave;
+CREATE TABLE t1 (
+`id` int(20) primary key,
+`group` int NOT NULL default 1,
+`a\\b` int NOT NULL default 2,
+`a\\` int unsigned,
+`name` varchar(32) default 'name')
+DEFAULT CHARSET=latin1;
+connection master;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(20) NOT NULL,
+ `group` int(11) NOT NULL DEFAULT 1,
+ `a\\b` int(11) NOT NULL DEFAULT 2,
+ `a\\` int(10) unsigned DEFAULT NULL,
+ `name` varchar(32) DEFAULT 'name'
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`='MYSQL'
+INSERT INTO t1 (id, name) VALUES (1, 'foo');
+INSERT INTO t1 (id, name) VALUES (2, 'fee');
+SELECT * FROM t1;
+id group a\\b a\\ name
+1 1 2 NULL foo
+2 1 2 NULL fee
+DROP TABLE t1;
+connection slave;
+SELECT * FROM t1;
+id group a\\b a\\ name
+1 1 2 NULL foo
+2 1 2 NULL fee
+DROP TABLE t1;
+connection master;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+connection slave;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
diff --git a/storage/connect/mysql-test/connect/r/mysql_exec.result b/storage/connect/mysql-test/connect/r/mysql_exec.result
new file mode 100644
index 00000000..cc772405
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_exec.result
@@ -0,0 +1,76 @@
+connect master,127.0.0.1,root,,test,$MASTER_MYPORT,;
+connect slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
+connection master;
+CREATE DATABASE connect;
+connection slave;
+CREATE DATABASE connect;
+#
+# Checking Sending Commands
+#
+connection master;
+CREATE TABLE t1 (
+command VARCHAR(128) NOT NULL,
+warnings INT(4) NOT NULL FLAG=3,
+number INT(5) NOT NULL FLAG=1,
+message VARCHAR(255) FLAG=2)
+ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test' OPTION_LIST='Execsrc=1,maxerr=2';
+SELECT * FROM t1 WHERE command IN ('Warning','Note',
+'drop table if exists t1',
+'create table t1 (id int key auto_increment, msg varchar(32) not null)',
+"insert into t1(msg) values('One'),(NULL),('Three')",
+"insert into t1 values(2,'Deux') on duplicate key update msg = 'Two'",
+"insert into t1(message) values('Four'),('Five'),('Six')",
+'insert ignore into t1(id) values(NULL)',
+"update t1 set msg = 'Four' where id = 4",
+'select * from t1');
+command warnings number message
+drop table if exists t1 1 0 Affected rows
+Note 0 1051 Unknown table 'test.t1'
+create table t1 (id int key auto_increment, msg varchar(32) not null) 0 0 Affected rows
+insert into t1(msg) values('One'),(NULL),('Three') 1 3 Affected rows
+Warning 0 1048 Column 'msg' cannot be null
+insert into t1 values(2,'Deux') on duplicate key update msg = 'Two' 0 2 Affected rows
+insert into t1(message) values('Four'),('Five'),('Six') 0 1054 Remote: Unknown column 'message' in 'field list'
+insert ignore into t1(id) values(NULL) 1 1 Affected rows
+Warning 0 1364 Field 'msg' doesn't have a default value
+update t1 set msg = 'Four' where id = 4 0 1 Affected rows
+select * from t1 0 2 Result set columns
+Warnings:
+Warning 1105 Result set columns
+#
+# Checking Using Procedure
+#
+DROP PROCEDURE IF EXISTS p1;
+Warnings:
+Note 1305 PROCEDURE test.p1 does not exist
+CREATE PROCEDURE p1(cmd varchar(512))
+READS SQL DATA
+SELECT * FROM t1 WHERE command IN ('Warning','Note',cmd);
+CALL p1('insert ignore into t1(id) values(NULL)');
+command warnings number message
+insert ignore into t1(id) values(NULL) 1 1 Affected rows
+Warning 0 1364 Field 'msg' doesn't have a default value
+Warnings:
+Warning 1105 Affected rows
+CALL p1('update t1 set msg = "Five" where id = 5');
+command warnings number message
+update t1 set msg = "Five" where id = 5 0 1 Affected rows
+Warnings:
+Warning 1105 Affected rows
+DROP PROCEDURE p1;
+DROP TABLE t1;
+connection slave;
+SELECT * FROM t1;
+id msg
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+DROP TABLE t1;
+connection master;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+connection slave;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
diff --git a/storage/connect/mysql-test/connect/r/mysql_grant.result b/storage/connect/mysql-test/connect/r/mysql_grant.result
new file mode 100644
index 00000000..83a906af
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_grant.result
@@ -0,0 +1,73 @@
+#
+# Testing FILE privilege
+#
+set sql_mode="";
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+set sql_mode=default;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=PORT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1remote (a INT NOT NULL);
+INSERT INTO t1remote VALUES (10),(20),(30);
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL TABNAME=t1remote OPTION_LIST='host=localhost,user=root,port=PORT';
+SELECT * FROM t1;
+a
+10
+20
+30
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO t1 VALUES ('xxx');
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1 WHERE a='xxx';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET a='yyy' WHERE a='xxx';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (2);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET a=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+disconnect user;
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1, t1remote;
+DROP USER user@localhost;
+#
+# Testing FILE privileges done
+#
diff --git a/storage/connect/mysql-test/connect/r/mysql_index.result b/storage/connect/mysql-test/connect/r/mysql_index.result
new file mode 100644
index 00000000..54acc7be
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_index.result
@@ -0,0 +1,436 @@
+#
+# Make remote table
+#
+CREATE TABLE t1 (
+id int(11) NOT NULL,
+msg char(100) DEFAULT NULL,
+PRIMARY KEY (id)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES(1,'Un'),(3,'Trois'),(5,'Cinq');
+INSERT INTO t1 VALUES(2,'Two'),(4,'Four'),(6,'Six');
+SELECT * FROM t1;
+id msg
+1 Un
+3 Trois
+5 Cinq
+2 Two
+4 Four
+6 Six
+#
+# Make local MYSQL table with indexed id column
+#
+CREATE TABLE t2 (
+id int(11) NOT NULL,
+msg char(100) DEFAULT NULL,
+PRIMARY KEY (id)
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 TABLE_TYPE=MYSQL TABNAME=t1;
+#
+# Testing SELECT, etc.
+#
+SELECT * FROM t2;
+id msg
+1 Un
+3 Trois
+5 Cinq
+2 Two
+4 Four
+6 Six
+SELECT * FROM t2 WHERE id = 3;
+id msg
+3 Trois
+SELECT * FROM t2 WHERE id IN (2,4);
+id msg
+2 Two
+4 Four
+SELECT * FROM t2 WHERE id IN (2,4) AND msg = 'Two';
+id msg
+2 Two
+SELECT * FROM t2 WHERE id > 4;
+id msg
+5 Cinq
+6 Six
+SELECT * FROM t2 WHERE id >= 3;
+id msg
+3 Trois
+4 Four
+5 Cinq
+6 Six
+SELECT * FROM t2 WHERE id < 3;
+id msg
+1 Un
+2 Two
+SELECT * FROM t2 WHERE id < 2 OR id > 4;
+id msg
+1 Un
+5 Cinq
+6 Six
+SELECT * FROM t2 WHERE id <= 3;
+id msg
+1 Un
+2 Two
+3 Trois
+SELECT * FROM t2 WHERE id BETWEEN 3 AND 5;
+id msg
+3 Trois
+4 Four
+5 Cinq
+SELECT * FROM t2 WHERE id > 2 AND id < 6;
+id msg
+3 Trois
+4 Four
+5 Cinq
+SELECT * FROM t2 ORDER BY id;
+id msg
+1 Un
+2 Two
+3 Trois
+4 Four
+5 Cinq
+6 Six
+UPDATE t2 SET msg = 'Five' WHERE id = 5;
+Warnings:
+Note 1105 t1: 1 affected rows
+SELECT * FROM t2;
+id msg
+1 Un
+3 Trois
+5 Five
+2 Two
+4 Four
+6 Six
+DELETE FROM t2 WHERE id = 4;
+Warnings:
+Note 1105 t1: 1 affected rows
+SELECT * FROM t2;
+id msg
+1 Un
+3 Trois
+5 Five
+2 Two
+6 Six
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# Make local FIX table with indices matricule and nom/prenom
+#
+CREATE TABLE t1
+(
+matricule INT(4) KEY NOT NULL field_format='Z',
+nom VARCHAR(16) NOT NULL,
+prenom VARCHAR(20) NOT NULL,
+sexe SMALLINT(1) NOT NULL COMMENT 'sexe 1:M 2:F',
+aanais INT(4) NOT NULL,
+mmnais INT(2) NOT NULL,
+ddentree DATE NOT NULL date_format='YYYYMM',
+ddnom DATE NOT NULL date_format='YYYYMM',
+brut INT(5) NOT NULL,
+net DOUBLE(8,2) NOT NULL,
+service INT(2) NOT NULL,
+sitmat CHAR(1) NOT NULL,
+formation CHAR(5) NOT NULL,
+INDEX NP(nom,prenom)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='emp.txt' ENDING=2;
+#
+# Make MYSQL table with same indices
+#
+CREATE TABLE t2
+(
+matricule INT(4) KEY NOT NULL,
+nom VARCHAR(16) NOT NULL,
+prenom VARCHAR(20) NOT NULL,
+sexe SMALLINT(1) NOT NULL,
+aanais INT(4) NOT NULL,
+mmnais INT(2) NOT NULL,
+ddentree DATE NOT NULL date_format='YYYYMM',
+ddnom DATE NOT NULL date_format='YYYYMM',
+brut INT(5) NOT NULL,
+net DOUBLE(8,2) NOT NULL,
+service INT(2) NOT NULL,
+sitmat CHAR(1) NOT NULL,
+formation CHAR(5) NOT NULL,
+INDEX NP(nom,prenom)
+) ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTIOn='mysql://root@localhost/test/t1';
+SELECT * FROM t2 limit 10;
+matricule nom prenom sexe aanais mmnais ddentree ddnom brut net service sitmat formation
+5745 ESCOURCHE BENEDICTE 2 1935 7 1962-12-01 1994-05-01 18345 14275.50 0 M TECHN
+9692 VICENTE LAURENCE 2 1941 8 1967-10-01 1989-01-01 16212 13032.80 0 M ANGL
+9146 NICOLAS ROGER 1 1941 6 1964-07-01 1995-02-01 34173 25098.65 0 M SANS
+2985 TESSEREAU MARIE HELENE 2 1941 9 1967-01-01 1990-01-01 19323 14933.78 0 V SANS
+3368 MOGADOR ALAIN 1 1941 1 1961-09-01 1993-11-01 43303 31420.55 0 C SANS
+7394 CHAUSSEE ERIC DENIS 1 1944 9 1965-11-01 1983-12-01 32002 23583.86 0 M ANGL
+4655 MAILLOT GEORGES 1 1945 5 1970-09-01 1986-12-01 24700 18541.64 0 C ANGL
+2825 CAMILLE NADINE 2 1956 9 1994-01-01 1993-01-01 19494 15050.45 0 M SANS
+1460 BRUYERES JEAN MARC 1 1958 8 1984-08-01 1988-05-01 20902 15980.07 0 M SANS
+4974 LONES GERARD 1 1959 10 1979-01-01 1994-12-01 16081 12916.70 0 M SANS
+SELECT matricule, nom, prenom FROM t2 WHERE nom IN ('FOCH','MOGADOR');
+matricule nom prenom
+1977 FOCH BERNADETTE
+5707 FOCH DENIS
+2552 FOCH FRANCK
+2634 FOCH JOCELYNE
+5765 FOCH ROBERT
+4080 FOCH SERGE
+3368 MOGADOR ALAIN
+explain SELECT matricule, nom, prenom FROM t2 WHERE nom IN ('FOCH','MOGADOR');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range NP NP 18 NULL 4 Using where
+SELECT matricule, nom, prenom FROM t2 WHERE nom = 'FOCH' OR nom = 'MOGADOR';
+matricule nom prenom
+1977 FOCH BERNADETTE
+5707 FOCH DENIS
+2552 FOCH FRANCK
+2634 FOCH JOCELYNE
+5765 FOCH ROBERT
+4080 FOCH SERGE
+3368 MOGADOR ALAIN
+SELECT matricule, nom, prenom FROM t2 WHERE nom < 'ADDAX';
+matricule nom prenom
+1122 ACACIAS SERGE
+115 ACHILLE JACQUES
+1340 ABBE MICHELE
+1644 ACARDIE BEATE
+2728 ABOUT CATHERINE MARIE
+2945 ABBEVILLE PASCAL
+307 ABBAYE ANNICK
+3395 ADAM JEAN CLAUDE
+398 ABREUVOIR JEAN LUC
+4038 ADAM JANICK
+4552 ABBADIE MONIQUE
+6124 ABELIAS DELIA
+6314 ABERDEN EVELYNE
+6399 ABEILLES RENE
+6627 ABBAYE GERALD
+7961 ABBE KATIA
+8596 ABEBERRY PATRICK
+8673 ABEL JEAN PIERRE
+895 ABORD CHANTAL
+9270 ABBE SOPHIE
+SELECT matricule, nom, prenom FROM t2 WHERE nom <= 'ABEL';
+matricule nom prenom
+1340 ABBE MICHELE
+2945 ABBEVILLE PASCAL
+307 ABBAYE ANNICK
+4552 ABBADIE MONIQUE
+6399 ABEILLES RENE
+6627 ABBAYE GERALD
+7961 ABBE KATIA
+8596 ABEBERRY PATRICK
+8673 ABEL JEAN PIERRE
+9270 ABBE SOPHIE
+SELECT matricule, nom, prenom FROM t2 WHERE nom > 'YVON';
+matricule nom prenom
+1325 ZOLA CHRISTINE
+4102 ZOUAVES ALAIN
+4859 ZORI CATHERINE
+5357 ZOLA BERNARD
+5441 ZOLA BRIGITTE
+8738 ZILINA JEAN LOUIS
+9742 YZENGREMER MICHEL
+SELECT matricule, nom, prenom FROM t2 WHERE nom >= 'YVON';
+matricule nom prenom
+1325 ZOLA CHRISTINE
+4102 ZOUAVES ALAIN
+4859 ZORI CATHERINE
+5357 ZOLA BERNARD
+5389 YVON CAROLE
+5441 ZOLA BRIGITTE
+8738 ZILINA JEAN LOUIS
+9742 YZENGREMER MICHEL
+SELECT matricule, nom, prenom FROM t2 WHERE nom <= 'ABEL' OR nom > 'YVON';
+matricule nom prenom
+1325 ZOLA CHRISTINE
+1340 ABBE MICHELE
+2945 ABBEVILLE PASCAL
+307 ABBAYE ANNICK
+4102 ZOUAVES ALAIN
+4552 ABBADIE MONIQUE
+4859 ZORI CATHERINE
+5357 ZOLA BERNARD
+5441 ZOLA BRIGITTE
+6399 ABEILLES RENE
+6627 ABBAYE GERALD
+7961 ABBE KATIA
+8596 ABEBERRY PATRICK
+8673 ABEL JEAN PIERRE
+8738 ZILINA JEAN LOUIS
+9270 ABBE SOPHIE
+9742 YZENGREMER MICHEL
+SELECT matricule, nom, prenom FROM t2 WHERE nom > 'HELEN' AND nom < 'HEROS';
+matricule nom prenom
+1291 HERMITAGE XAVIER
+2085 HEOL GUY PAUL
+2579 HERANDIERE PIERRE
+2673 HENNER LILIANE
+3309 HELENE ISABELLE
+403 HERMITTE PHILIPPE
+4050 HERBILLON FRANCOIS
+4254 HENIN SERGE
+4666 HELLEN PIERRE
+5781 HELSINKI DANIELLE
+6185 HERMITTE FRANCOIS
+7093 HERAULTS DANIEL
+7626 HENIN PHILIPPE
+8365 HELIOTROPES LISE
+9096 HELENA PHILIPPE
+9231 HERBILLON MADELEINE
+9716 HENRI JACQUES
+9749 HEROLD ISABELLE
+SELECT matricule, nom, prenom FROM t2 WHERE nom BETWEEN 'HELEN' AND 'HEROS';
+matricule nom prenom
+1291 HERMITAGE XAVIER
+2085 HEOL GUY PAUL
+2579 HERANDIERE PIERRE
+2673 HENNER LILIANE
+3309 HELENE ISABELLE
+403 HERMITTE PHILIPPE
+4050 HERBILLON FRANCOIS
+4254 HENIN SERGE
+4666 HELLEN PIERRE
+5781 HELSINKI DANIELLE
+6185 HERMITTE FRANCOIS
+6199 HELEN MARTIAL
+7093 HERAULTS DANIEL
+7626 HENIN PHILIPPE
+8365 HELIOTROPES LISE
+8445 HEROS SYLVIE
+9096 HELENA PHILIPPE
+9231 HERBILLON MADELEINE
+9716 HENRI JACQUES
+9749 HEROLD ISABELLE
+SELECT matricule, nom, prenom FROM t2 WHERE nom BETWEEN 'HELEN' AND 'HEROS' AND prenom = 'PHILIPPE';
+matricule nom prenom
+403 HERMITTE PHILIPPE
+7626 HENIN PHILIPPE
+9096 HELENA PHILIPPE
+SELECT matricule, nom, prenom FROM t2 ORDER BY nom,prenom LIMIT 10;
+matricule nom prenom
+4552 ABBADIE MONIQUE
+307 ABBAYE ANNICK
+6627 ABBAYE GERALD
+7961 ABBE KATIA
+1340 ABBE MICHELE
+9270 ABBE SOPHIE
+2945 ABBEVILLE PASCAL
+8596 ABEBERRY PATRICK
+6399 ABEILLES RENE
+8673 ABEL JEAN PIERRE
+SELECT a.nom, a.prenom, b.nom FROM t1 a STRAIGHT_JOIN t2 b ON a.prenom = b.prenom WHERE a.nom = 'FOCH' AND a.nom != b.nom;
+nom prenom nom
+FOCH BERNADETTE BERTIN
+FOCH BERNADETTE BOISSY
+FOCH BERNADETTE HUNTZIGER
+FOCH BERNADETTE LATECOERE
+FOCH BERNADETTE LEGER
+FOCH BERNADETTE MONTJUSTIN
+FOCH BERNADETTE ONZE
+FOCH BERNADETTE PALMAROLE
+FOCH BERNADETTE PLOUHARNEL
+FOCH DENIS AMBOISE
+FOCH DENIS BERARD
+FOCH DENIS BERIN
+FOCH DENIS BILLEHOU
+FOCH DENIS BOILEAU
+FOCH DENIS CONNE
+FOCH DENIS COULOUBRIER
+FOCH DENIS COUTURIER
+FOCH DENIS EPINETTES
+FOCH DENIS FIGOURNAS
+FOCH DENIS ISTANBUL
+FOCH DENIS ITALIE
+FOCH DENIS LACATE
+FOCH DENIS MAROLLES
+FOCH DENIS MONTELIER
+FOCH DENIS MONTILS
+FOCH DENIS POINTE
+FOCH DENIS PORTO
+FOCH DENIS REINOTS
+FOCH DENIS REMPART
+FOCH DENIS ROUSSIER
+FOCH DENIS TORTE
+FOCH DENIS TOULON
+FOCH DENIS VALMANTE
+FOCH FRANCK BEARN
+FOCH FRANCK ILLIERS
+FOCH FRANCK JEANPIERRE
+FOCH FRANCK LABBE
+FOCH FRANCK LACOMBE
+FOCH FRANCK LEROY
+FOCH FRANCK MONTALEIGNE
+FOCH FRANCK ORVEAU
+FOCH FRANCK PURPAN
+FOCH FRANCK ROCQUENCOURT
+FOCH FRANCK RUSSIE
+FOCH JOCELYNE ALEXIS
+FOCH JOCELYNE AUGUSTE
+FOCH JOCELYNE BASSE
+FOCH JOCELYNE CARRERE
+FOCH JOCELYNE CHAPELLE
+FOCH JOCELYNE FLEMING
+FOCH JOCELYNE GAMBADES
+FOCH JOCELYNE KENNEDY
+FOCH JOCELYNE PEYBERT
+FOCH JOCELYNE PIED
+FOCH JOCELYNE PONTAROUX
+FOCH ROBERT AGRIANT
+FOCH ROBERT ANNECY
+FOCH ROBERT BONVIN
+FOCH ROBERT CHENIER
+FOCH ROBERT CURAT
+FOCH ROBERT DAUDET
+FOCH ROBERT GIOTERAIE
+FOCH ROBERT GRAFFIANE
+FOCH ROBERT GUILLOTIERE
+FOCH ROBERT LAMOTHE
+FOCH ROBERT MARRONIERS
+FOCH ROBERT NIMES
+FOCH ROBERT NORD
+FOCH ROBERT PEYNIBLOU
+FOCH ROBERT PIECE
+FOCH ROBERT PLAGNE
+FOCH ROBERT POMMERY
+FOCH ROBERT PRESIDENT
+FOCH ROBERT PUJADE
+FOCH ROBERT QUILICHINI
+FOCH ROBERT RIOU
+FOCH ROBERT ROLL
+FOCH ROBERT ROSSA
+FOCH ROBERT SABLONS
+FOCH ROBERT STRASBOURG
+FOCH ROBERT TIRE
+FOCH ROBERT TUBY
+FOCH ROBERT VIARMES
+FOCH SERGE ACACIAS
+FOCH SERGE ANDALUCIA
+FOCH SERGE ARCACHON
+FOCH SERGE BEACH
+FOCH SERGE BELLES
+FOCH SERGE BOUTON
+FOCH SERGE BREUIL
+FOCH SERGE CARREFOUR
+FOCH SERGE CHATEAU
+FOCH SERGE COLLETTE
+FOCH SERGE COOLE
+FOCH SERGE ECLUSE
+FOCH SERGE EGUILLON
+FOCH SERGE GOAS
+FOCH SERGE GREFFIER
+FOCH SERGE HENIN
+FOCH SERGE JARDIN
+FOCH SERGE LEONIE
+FOCH SERGE LOZERE
+FOCH SERGE MARSAT
+FOCH SERGE MONTAGNE
+FOCH SERGE MORIZET
+FOCH SERGE NOVEMBRE
+FOCH SERGE ORANGERIE
+FOCH SERGE PLAISANCE
+FOCH SERGE RESISTANCE
+FOCH SERGE RESTANQUES
+FOCH SERGE ROSSAYS
+FOCH SERGE SARTRE
+FOCH SERGE SAVIGNAC
+FOCH SERGE SEGUR
+FOCH SERGE VANOEL
+FOCH SERGE WILSON
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/mysql_new.result b/storage/connect/mysql-test/connect/r/mysql_new.result
new file mode 100644
index 00000000..0394caac
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/mysql_new.result
@@ -0,0 +1,237 @@
+connect master,127.0.0.1,root,,test,$MASTER_MYPORT,;
+connect slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
+connection master;
+CREATE DATABASE connect;
+connection slave;
+CREATE DATABASE connect;
+connection slave;
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+#
+# Testing errors
+#
+connection master;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://unknown@127.0.0.1:SLAVE_PORT/test/t1';
+ERROR HY000: (1045) Access denied for user 'unknown'@'localhost' (using password: NO)
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/unknown/t1';
+ERROR HY000: (1049) Unknown database 'unknown'
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT' DBNAME='unknown' TABNAME='t1';
+ERROR HY000: (1049) Unknown database 'unknown'
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/unknown';
+ERROR HY000: (1146) Table 'test.unknown' doesn't exist [SHOW FULL COLUMNS FROM `unknown` FROM test]
+SHOW CREATE TABLE t1;
+ERROR 42S02: Table 'test.t1' doesn't exist
+CREATE TABLE t1 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `x` int(11) DEFAULT NULL,
+ `y` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`=MYSQL
+SELECT * FROM t1;
+ERROR HY000: Got error 174 '(1054) Unknown column 'x' in 'field list' [SELECT `x`, `y` FROM `t1`]' from CONNECT
+DROP TABLE t1;
+CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+connection slave;
+ALTER TABLE t1 RENAME t1backup;
+connection master;
+SELECT * FROM t1;
+ERROR HY000: Got error 174 '(1146) Table 'test.t1' doesn't exist [SELECT `a`, `b` FROM `t1`]' from CONNECT
+connection slave;
+ALTER TABLE t1backup RENAME t1;
+connection master;
+DROP TABLE t1;
+#
+# Testing SELECT, etc.
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`='MYSQL'
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1'
+ OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `TABNAME`='t1' `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
+SELECT * FROM t1;
+a b
+NULL NULL
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL
+OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=MYSQL `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
+SELECT * FROM t1;
+a b
+0
+0 test00
+1 test01
+2 test02
+3 test03
+DROP TABLE t1;
+CREATE TABLE t1 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(10) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1' `TABLE_TYPE`=MYSQL
+SELECT * FROM t1;
+a b
+NULL NULL
+0 0
+1 0
+2 0
+3 0
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+#
+# Testing numeric data types
+#
+CREATE TABLE t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float, g double, h decimal(20,5));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` tinyint(4) DEFAULT NULL,
+ `b` smallint(6) DEFAULT NULL,
+ `c` mediumint(9) DEFAULT NULL,
+ `d` int(11) DEFAULT NULL,
+ `e` bigint(20) DEFAULT NULL,
+ `f` float DEFAULT NULL,
+ `g` double DEFAULT NULL,
+ `h` decimal(20,5) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265);
+connection master;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+OPTION_LIST='host=127.0.0.1,user=root,port=SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` tinyint(4) DEFAULT NULL,
+ `b` smallint(6) DEFAULT NULL,
+ `c` int(9) DEFAULT NULL,
+ `d` int(11) DEFAULT NULL,
+ `e` bigint(20) DEFAULT NULL,
+ `f` double DEFAULT NULL,
+ `g` double DEFAULT NULL,
+ `h` decimal(20,5) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MYSQL' `OPTION_LIST`='host=127.0.0.1,user=root,port=SLAVE_PORT'
+SELECT * FROM t1;
+a b c d e f g h
+100 3333 41235 1234567890 235000000000 3.14159 3.14159265 3141.59265
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+#
+# Testing character data types
+#
+CREATE TABLE t1 (a char(12), b varchar(12));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(12) DEFAULT NULL,
+ `b` varchar(12) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES('Welcome','Hello, World');
+SELECT * FROM t1;
+a b
+Welcome Hello, World
+connection master;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(12) DEFAULT NULL,
+ `b` varchar(12) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT' `TABLE_TYPE`='MYSQL'
+SELECT * FROM t1;
+a b
+Welcome Hello, World
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+#
+# Testing temporal data types
+#
+CREATE TABLE t1 (a date, b datetime, c time, d timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, e year);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` date DEFAULT NULL,
+ `b` datetime DEFAULT NULL,
+ `c` time DEFAULT NULL,
+ `d` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `e` year(4) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT IGNORE INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23');
+Warnings:
+Note 1265 Data truncated for column 'a' at row 1
+Note 1265 Data truncated for column 'c' at row 1
+Warning 1265 Data truncated for column 'e' at row 1
+SELECT * FROM t1;
+a b c d e
+2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003
+connection master;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` date DEFAULT NULL,
+ `b` datetime DEFAULT NULL,
+ `c` time DEFAULT NULL,
+ `d` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
+ `e` year(4) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT' `TABLE_TYPE`='MYSQL'
+SELECT * FROM t1;
+a b c d e
+2003-05-27 2003-05-27 10:45:23 10:45:23 2003-05-27 10:45:23 2003
+DROP TABLE t1;
+connection slave;
+DROP TABLE t1;
+connection master;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+connection slave;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
diff --git a/storage/connect/mysql-test/connect/r/null.result b/storage/connect/mysql-test/connect/r/null.result
new file mode 100644
index 00000000..0e4f1f86
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/null.result
@@ -0,0 +1,134 @@
+#
+# Testing FIX null columns
+#
+CREATE TABLE t1
+(
+id INT NOT NULL,
+nb INT,
+msg VARCHAR(12)
+) ENGINE=CONNECT TABLE_TYPE=FIX;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+INSERT INTO t1 values(NULL,1,'Hello');
+ERROR 23000: Column 'id' cannot be null
+INSERT INTO t1 values(10,4,NULL),(20,2,'Hello'),(0,0,'Zero');
+SELECT * FROM t1;
+id nb msg
+10 4 NULL
+20 2 Hello
+0 NULL Zero
+SELECT* FROM t1 WHERE id IS NULL;
+id nb msg
+SELECT * FROM t1 WHERE nb IS NULL;
+id nb msg
+0 NULL Zero
+SELECT * FROM t1 WHERE msg IS NOT NULL;
+id nb msg
+20 2 Hello
+0 NULL Zero
+DROP TABLE t1;
+#
+# Testing CSV null columns
+#
+CREATE TABLE t1
+(
+id INT NOT NULL,
+nb INT,
+msg VARCHAR(12)
+) ENGINE=CONNECT TABLE_TYPE=CSV HEADER=1;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+INSERT INTO t1 values(NULL,1,'Hello');
+ERROR 23000: Column 'id' cannot be null
+INSERT INTO t1 values(10,4,NULL),(20,2,'Hello'),(0,0,'Zero');
+SELECT * FROM t1;
+id nb msg
+10 4 NULL
+20 2 Hello
+0 NULL Zero
+SELECT* FROM t1 WHERE id IS NULL;
+id nb msg
+SELECT * FROM t1 WHERE nb IS NULL;
+id nb msg
+0 NULL Zero
+SELECT * FROM t1 WHERE msg IS NOT NULL;
+id nb msg
+20 2 Hello
+0 NULL Zero
+DROP TABLE t1;
+#
+# Testing BIN null columns
+#
+CREATE TABLE t1
+(
+id INT NOT NULL,
+nb INT,
+msg VARCHAR(12)
+) ENGINE=CONNECT TABLE_TYPE=BIN;
+Warnings:
+Warning 1105 No file name. Table will use t1.bin
+INSERT INTO t1 values(NULL,1,'Hello');
+ERROR 23000: Column 'id' cannot be null
+INSERT INTO t1 values(10,4,NULL),(20,2,'Hello'),(0,0,'Zero');
+SELECT * FROM t1;
+id nb msg
+10 4 NULL
+20 2 Hello
+0 NULL Zero
+SELECT* FROM t1 WHERE id IS NULL;
+id nb msg
+SELECT * FROM t1 WHERE nb IS NULL;
+id nb msg
+0 NULL Zero
+SELECT * FROM t1 WHERE msg IS NOT NULL;
+id nb msg
+20 2 Hello
+0 NULL Zero
+DROP TABLE t1;
+#
+# Testing DBF null columns
+#
+CREATE TABLE t1
+(
+id INT NOT NULL,
+nb INT,
+msg VARCHAR(12)
+) ENGINE=CONNECT TABLE_TYPE=DBF;
+Warnings:
+Warning 1105 No file name. Table will use t1.dbf
+INSERT INTO t1 values(NULL,1,'Hello');
+ERROR 23000: Column 'id' cannot be null
+INSERT INTO t1 values(10,4,NULL),(20,2,'Hello'),(0,0,'Zero');
+SELECT * FROM t1;
+id nb msg
+10 4 NULL
+20 2 Hello
+0 NULL Zero
+SELECT* FROM t1 WHERE id IS NULL;
+id nb msg
+SELECT * FROM t1 WHERE nb IS NULL;
+id nb msg
+0 NULL Zero
+SELECT * FROM t1 WHERE msg IS NOT NULL;
+id nb msg
+20 2 Hello
+0 NULL Zero
+DROP TABLE t1;
+#
+# Testing INI null columns
+#
+CREATE TABLE t1
+(
+`sec` char(8) NOT NULL flag=1,
+`key` char(12)
+) ENGINE=CONNECT TABLE_TYPE=INI;
+Warnings:
+Warning 1105 No file name. Table will use t1.ini
+INSERT INTO t1(sec) values('S1');
+SELECT * FROM t1;
+sec key
+INSERT INTO t1 values('S1','Newval');
+SELECT * FROM t1;
+sec key
+S1 Newval
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/occur.result b/storage/connect/mysql-test/connect/r/occur.result
new file mode 100644
index 00000000..a497dfc9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/occur.result
@@ -0,0 +1,255 @@
+CREATE TABLE employee (
+serialno CHAR(5) NOT NULL,
+name VARCHAR(12) NOT NULL FLAG=6,
+sex TINYINT(1) NOT NULL,
+title VARCHAR(15) NOT NULL FLAG=20,
+manager CHAR(5) DEFAULT NULL,
+department CHAR(4) NOT NULL FLAG=41,
+secretary CHAR(5) DEFAULT NULL FLAG=46,
+salary DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=connect TABLE_TYPE=fix FILE_NAME='employee.dat' ENDING=1;
+SELECT * FROM employee;
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 NULL 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 NULL 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 NULL 3800.00
+12345 KITTY 2 TYPIST 40567 0319 NULL 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 NULL 2800.00
+87777 STRONG 1 DIRECTOR NULL 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+CREATE TABLE occurs (name CHAR(12), sex CHAR(1), title CHAR(15), department CHAR(4), salary DOUBLE(8,2), id_of CHAR(12), id CHAR(5) NOT NULL) ENGINE=CONNECT TABLE_TYPE=OCCUR TABNAME=employee OPTION_LIST='OccurCol=ID,RankCol=ID_OF,Colist=serialno;manager;secretary,port=PORT';;
+SELECT * FROM occurs;
+name sex title department salary id_of id
+BANCROFT 2 SALESMAN 0318 9600.00 serialno 74200
+BANCROFT 2 SALESMAN 0318 9600.00 manager 70012
+BANCROFT 2 SALESMAN 0318 9600.00 secretary 24888
+SMITH 1 ENGINEER 2452 9000.00 serialno 02345
+SMITH 1 ENGINEER 2452 9000.00 manager 31416
+SMITH 1 ENGINEER 2452 9000.00 secretary 11111
+MERCHANT 1 SALESMAN 0318 8700.00 serialno 78943
+MERCHANT 1 SALESMAN 0318 8700.00 manager 70012
+MERCHANT 1 SALESMAN 0318 8700.00 secretary 24888
+FUNNIGUY 1 ADMINISTRATOR 0319 8500.00 serialno 07654
+FUNNIGUY 1 ADMINISTRATOR 0319 8500.00 manager 40567
+FUNNIGUY 1 ADMINISTRATOR 0319 8500.00 secretary 33333
+BUGHAPPY 1 PROGRAMMER 0319 8500.00 serialno 45678
+BUGHAPPY 1 PROGRAMMER 0319 8500.00 manager 40567
+BUGHAPPY 1 PROGRAMMER 0319 8500.00 secretary 12345
+BIGHEAD 1 SCIENTIST 2452 8000.00 serialno 34567
+BIGHEAD 1 SCIENTIST 2452 8000.00 manager 31416
+BIGHEAD 1 SCIENTIST 2452 8000.00 secretary 11111
+SHRINKY 2 ADMINISTRATOR 0318 7500.00 serialno 77777
+SHRINKY 2 ADMINISTRATOR 0318 7500.00 manager 70012
+SHRINKY 2 ADMINISTRATOR 0318 7500.00 secretary 27845
+WALTER 1 ENGINEER 0318 7400.00 serialno 74234
+WALTER 1 ENGINEER 0318 7400.00 manager 70012
+WALTER 1 ENGINEER 0318 7400.00 secretary 24888
+FODDERMAN 1 SALESMAN 0319 7000.00 serialno 56789
+FODDERMAN 1 SALESMAN 0319 7000.00 manager 40567
+FODDERMAN 1 SALESMAN 0319 7000.00 secretary 12345
+TONGHO 1 ENGINEER 0318 6800.00 serialno 73452
+TONGHO 1 ENGINEER 0318 6800.00 manager 70012
+TONGHO 1 ENGINEER 0318 6800.00 secretary 24888
+SHORTSIGHT 2 SECRETARY 0021 5500.00 serialno 22222
+SHORTSIGHT 2 SECRETARY 0021 5500.00 manager 87777
+MESSIFUL 2 SECRETARY 0319 5000.50 serialno 55555
+MESSIFUL 2 SECRETARY 0319 5000.50 manager 40567
+MESSIFUL 2 SECRETARY 0319 5000.50 secretary 12345
+HONEY 2 SECRETARY 0318 4900.00 serialno 27845
+HONEY 2 SECRETARY 0318 4900.00 manager 70012
+HONEY 2 SECRETARY 0318 4900.00 secretary 24888
+GOOSEPEN 1 ADMINISTRATOR 0319 4700.00 serialno 98765
+GOOSEPEN 1 ADMINISTRATOR 0319 4700.00 manager 07654
+GOOSEPEN 1 ADMINISTRATOR 0319 4700.00 secretary 33333
+CHERRY 2 SECRETARY 2452 4500.00 serialno 11111
+CHERRY 2 SECRETARY 2452 4500.00 manager 31416
+MONAPENNY 2 SECRETARY 0319 3800.00 serialno 33333
+MONAPENNY 2 SECRETARY 0319 3800.00 manager 07654
+KITTY 2 TYPIST 0319 3000.45 serialno 12345
+KITTY 2 TYPIST 0319 3000.45 manager 40567
+PLUMHEAD 2 TYPIST 0318 2800.00 serialno 24888
+PLUMHEAD 2 TYPIST 0318 2800.00 manager 27845
+STRONG 1 DIRECTOR 0021 23000.00 serialno 87777
+STRONG 1 DIRECTOR 0021 23000.00 secretary 22222
+BULLOZER 1 SALESMAN 0319 14800.00 serialno 76543
+BULLOZER 1 SALESMAN 0319 14800.00 manager 40567
+BULLOZER 1 SALESMAN 0319 14800.00 secretary 12345
+WERTHER 1 DIRECTOR 0318 14500.00 serialno 70012
+WERTHER 1 DIRECTOR 0318 14500.00 manager 87777
+WERTHER 1 DIRECTOR 0318 14500.00 secretary 27845
+QUINN 1 DIRECTOR 0319 14000.00 serialno 40567
+QUINN 1 DIRECTOR 0319 14000.00 manager 87777
+QUINN 1 DIRECTOR 0319 14000.00 secretary 55555
+ORELLY 1 ENGINEER 2452 13400.00 serialno 31416
+ORELLY 1 ENGINEER 2452 13400.00 manager 87777
+ORELLY 1 ENGINEER 2452 13400.00 secretary 11111
+BIGHORN 1 SCIENTIST 2452 11000.00 serialno 36666
+BIGHORN 1 SCIENTIST 2452 11000.00 manager 31416
+BIGHORN 1 SCIENTIST 2452 11000.00 secretary 11111
+BROWNY 1 ENGINEER 0319 10500.00 serialno 00137
+BROWNY 1 ENGINEER 0319 10500.00 manager 40567
+BROWNY 1 ENGINEER 0319 10500.00 secretary 12345
+WHEELFOR 1 SALESMAN 0318 10030.00 serialno 73111
+WHEELFOR 1 SALESMAN 0318 10030.00 manager 70012
+WHEELFOR 1 SALESMAN 0318 10030.00 secretary 24888
+MARTIN 1 ENGINEER 0319 10000.00 serialno 00023
+MARTIN 1 ENGINEER 0319 10000.00 manager 40567
+MARTIN 1 ENGINEER 0319 10000.00 secretary 12345
+DROP TABLE occurs;
+DROP TABLE employee;
+CREATE TABLE pets (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0,
+cat INT NOT NULL DEFAULT 0,
+rabbit INT NOT NULL DEFAULT 0,
+bird INT NOT NULL DEFAULT 0,
+fish INT NOT NULL DEFAULT 0) ENGINE=MYISAM;
+INSERT INTO pets(name,dog) VALUES('John',2);
+INSERT INTO pets(name,cat) VALUES('Bill',1);
+INSERT INTO pets(name,dog,cat) VALUES('Mary',1,1);
+INSERT INTO pets(name,rabbit) VALUES('Lisbeth',2);
+INSERT INTO pets(name,cat,bird) VALUES('Kevin',2,6);
+INSERT INTO pets(name,dog,fish) VALUES('Donald',1,3);
+SELECT * FROM pets;
+name dog cat rabbit bird fish
+John 2 0 0 0 0
+Bill 0 1 0 0 0
+Mary 1 1 0 0 0
+Lisbeth 0 0 2 0 0
+Kevin 0 2 0 6 0
+Donald 1 0 0 0 3
+CREATE TABLE xpet (name VARCHAR(12) NOT NULL, race CHAR(6) NOT NULL, number INT) ENGINE=CONNECT TABLE_TYPE=OCCUR TABNAME=pets OPTION_LIST='OccurCol=number,RankCol=race,Colist=dog;cat;rabbit;bird;fish,port=PORT';
+SELECT * FROM xpet;
+name race number
+John dog 2
+John cat 0
+John rabbit 0
+John bird 0
+John fish 0
+Bill dog 0
+Bill cat 1
+Bill rabbit 0
+Bill bird 0
+Bill fish 0
+Mary dog 1
+Mary cat 1
+Mary rabbit 0
+Mary bird 0
+Mary fish 0
+Lisbeth dog 0
+Lisbeth cat 0
+Lisbeth rabbit 2
+Lisbeth bird 0
+Lisbeth fish 0
+Kevin dog 0
+Kevin cat 2
+Kevin rabbit 0
+Kevin bird 6
+Kevin fish 0
+Donald dog 1
+Donald cat 0
+Donald rabbit 0
+Donald bird 0
+Donald fish 3
+SELECT name FROM xpet;
+name
+John
+Bill
+Mary
+Lisbeth
+Kevin
+Donald
+SELECT name FROM xpet WHERE race = 'cat' AND number = 0;
+name
+John
+Lisbeth
+Donald
+SELECT name, SUM(number) pets FROM xpet GROUP BY name;
+name pets
+Bill 1
+Donald 4
+John 2
+Kevin 8
+Lisbeth 2
+Mary 2
+ALTER TABLE xpet MODIFY number INT NOT NULL;
+SELECT * FROM xpet;
+name race number
+John dog 2
+Bill cat 1
+Mary dog 1
+Mary cat 1
+Lisbeth rabbit 2
+Kevin cat 2
+Kevin bird 6
+Donald dog 1
+Donald fish 3
+SELECT * FROM xpet WHERE number > 1;
+name race number
+John dog 2
+Lisbeth rabbit 2
+Kevin cat 2
+Kevin bird 6
+Donald fish 3
+SELECT DISTINCT name FROM xpet WHERE number > 1;
+name
+John
+Lisbeth
+Kevin
+Donald
+SELECT name FROM xpet;
+name
+John
+Bill
+Mary
+Lisbeth
+Kevin
+Donald
+SELECT name, race FROM xpet;
+name race
+John
+Bill
+Mary
+Lisbeth
+Kevin
+Donald
+SELECT name, count(*) FROM xpet GROUP BY name, LEAST(number,1);
+name count(*)
+Bill 1
+Donald 2
+John 1
+Kevin 2
+Lisbeth 1
+Mary 2
+SELECT name, number, count(*) FROM xpet GROUP BY name, number;
+name number count(*)
+Bill 1 1
+Donald 1 1
+Donald 3 1
+John 2 1
+Kevin 2 1
+Kevin 6 1
+Lisbeth 2 1
+Mary 1 2
+DROP TABLE xpet;
+DROP TABLE pets;
diff --git a/storage/connect/mysql-test/connect/r/odbc.result b/storage/connect/mysql-test/connect/r/odbc.result
new file mode 100644
index 00000000..4ca7e209
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/odbc.result
@@ -0,0 +1,47 @@
+SET NAMES utf8;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Bad connection string';
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Name` varchar(256) NOT NULL,
+ `Description` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Sources'
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Description` char(128) NOT NULL,
+ `Attributes` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Tables CONNECTION='Not important';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Table_Cat` char(128) DEFAULT NULL,
+ `Table_Schema` char(128) DEFAULT NULL,
+ `Table_Name` char(128) NOT NULL,
+ `Table_Type` char(16) NOT NULL,
+ `Remark` char(255) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='Not important' `TABLE_TYPE`='ODBC' `CATFUNC`='Tables'
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Columns CONNECTION='Not important';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Table_Cat` char(128) DEFAULT NULL,
+ `Table_Schema` char(128) DEFAULT NULL,
+ `Table_Name` char(128) NOT NULL,
+ `Column_Name` char(128) NOT NULL,
+ `Data_Type` smallint(6) NOT NULL,
+ `Type_Name` char(30) NOT NULL,
+ `Column_Size` int(10) NOT NULL,
+ `Buffer_Length` int(10) NOT NULL,
+ `Decimal_Digits` smallint(6) DEFAULT NULL,
+ `Radix` smallint(6) DEFAULT NULL,
+ `Nullable` smallint(6) NOT NULL,
+ `Remarks` char(255) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='Not important' `TABLE_TYPE`='ODBC' `CATFUNC`='Columns'
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/odbc_firebird.result b/storage/connect/mysql-test/connect/r/odbc_firebird.result
new file mode 100644
index 00000000..3c4cd84f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/odbc_firebird.result
@@ -0,0 +1,110 @@
+SET NAMES utf8;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Bad connection string';
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Name` varchar(256) NOT NULL,
+ `Description` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Sources'
+SELECT * FROM t1;
+Name Description
+Excel Files Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
+MS Access Database Microsoft Access Driver (*.mdb, *.accdb)
+ORACLE_TEST Oracle in XE
+SQLServer_Test SQL Server Native Client 11.0
+Firebird Firebird/InterBase(r) driver
+ConnectEngineOracle Oracle in XE
+ConnectEngineSQLServer SQL Server Native Client 11.0
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Description` char(128) NOT NULL,
+ `Attributes` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
+SELECT * FROM t1;
+Description Attributes
+SQL Server APILevel=2;ConnectFunctions=YYY;CPTimeout=60;DriverODBCVer=03.50;FileUsage=0;SQLLevel=1;UsageCount=1;
+Oracle in XE ConnectionFunctions=YYY;DriverODBCVer=03.51;CPTimeout=60;FileUsage=0;APILevel=1;SQLLevel=1;
+SQL Server Native Client 11.0 UsageCount=1;APILevel=2;ConnectFunctions=YYY;CPTimeout=60;DriverODBCVer=03.80;FileUsage=0;SQLLevel=1;
+ODBC Driver 13 for SQL Server UsageCount=1;APILevel=2;ConnectFunctions=YYY;CPTimeout=60;DriverODBCVer=03.80;FileUsage=0;SQLLevel=1;
+SQL Server Native Client RDA 11.0 UsageCount=1;APILevel=2;ConnectFunctions=YYY;CPTimeout=60;DriverODBCVer=03.80;FileUsage=0;SQLLevel=1;
+Firebird/InterBase(r) driver UsageCount=1;FileExtns=*.fdb,*.gdb;APILevel=1;ConnectFunctions=YYY;FileUsage=0;DriverODBCVer=03.51;SQLLevel=1;
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Tables CONNECTION='Not important';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Table_Cat` char(128) DEFAULT NULL,
+ `Table_Schema` char(128) DEFAULT NULL,
+ `Table_Name` char(128) NOT NULL,
+ `Table_Type` char(16) NOT NULL,
+ `Remark` char(255) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='Not important' `TABLE_TYPE`='ODBC' `CATFUNC`='Tables'
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Columns CONNECTION='Not important';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Table_Cat` char(128) DEFAULT NULL,
+ `Table_Schema` char(128) DEFAULT NULL,
+ `Table_Name` char(128) NOT NULL,
+ `Column_Name` char(128) NOT NULL,
+ `Data_Type` smallint(6) NOT NULL,
+ `Type_Name` char(30) NOT NULL,
+ `Column_Size` int(10) NOT NULL,
+ `Buffer_Length` int(10) NOT NULL,
+ `Decimal_Digits` smallint(6) DEFAULT NULL,
+ `Radix` smallint(6) DEFAULT NULL,
+ `Nullable` smallint(6) NOT NULL,
+ `Remarks` char(255) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='Not important' `TABLE_TYPE`='ODBC' `CATFUNC`='Columns'
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC TABNAME='EMPLOYEE' CONNECTION='DSN=Firebird;UID=SYSDBA;PWD=masterkey';
+SELECT * FROM t1;
+EMP_NO FIRST_NAME LAST_NAME PHONE_EXT HIRE_DATE DEPT_NO JOB_CODE JOB_GRADE JOB_COUNTRY SALARY FULL_NAME
+2 Robert Nelson 250 1988-12-28 00:00:00 600 VP 2 USA 105900.00 Nelson, Robert
+4 Bruce Young 233 1988-12-28 00:00:00 621 Eng 2 USA 97500.00 Young, Bruce
+5 Kim Lambert 22 1989-02-06 00:00:00 130 Eng 2 USA 102750.00 Lambert, Kim
+8 Leslie Johnson 410 1989-04-05 00:00:00 180 Mktg 3 USA 64635.00 Johnson, Leslie
+9 Phil Forest 229 1989-04-17 00:00:00 622 Mngr 3 USA 75060.00 Forest, Phil
+11 K. J. Weston 34 1990-01-17 00:00:00 130 SRep 4 USA 86292.94 Weston, K. J.
+12 Terri Lee 256 1990-05-01 00:00:00 000 Admin 4 USA 53793.00 Lee, Terri
+14 Stewart Hall 227 1990-06-04 00:00:00 900 Finan 3 USA 69482.63 Hall, Stewart
+15 Katherine Young 231 1990-06-14 00:00:00 623 Mngr 3 USA 67241.25 Young, Katherine
+20 Chris Papadopoulos 887 1990-01-01 00:00:00 671 Mngr 3 USA 89655.00 Papadopoulos, Chris
+24 Pete Fisher 888 1990-09-12 00:00:00 671 Eng 3 USA 81810.19 Fisher, Pete
+28 Ann Bennet 5 1991-02-01 00:00:00 120 Admin 5 England 22935.00 Bennet, Ann
+29 Roger De Souza 288 1991-02-18 00:00:00 623 Eng 3 USA 69482.63 De Souza, Roger
+34 Janet Baldwin 2 1991-03-21 00:00:00 110 Sales 3 USA 61637.81 Baldwin, Janet
+36 Roger Reeves 6 1991-04-25 00:00:00 120 Sales 3 England 33620.63 Reeves, Roger
+37 Willie Stansbury 7 1991-04-25 00:00:00 120 Eng 4 England 39224.06 Stansbury, Willie
+44 Leslie Phong 216 1991-06-03 00:00:00 623 Eng 4 USA 56034.38 Phong, Leslie
+45 Ashok Ramanathan 209 1991-08-01 00:00:00 621 Eng 3 USA 80689.50 Ramanathan, Ashok
+46 Walter Steadman 210 1991-08-09 00:00:00 900 CFO 1 USA 116100.00 Steadman, Walter
+52 Carol Nordstrom 420 1991-10-02 00:00:00 180 PRel 4 USA 42742.50 Nordstrom, Carol
+61 Luke Leung 3 1992-02-18 00:00:00 110 SRep 4 USA 68805.00 Leung, Luke
+65 Sue Anne O'Brien 877 1992-03-23 00:00:00 670 Admin 5 USA 31275.00 O'Brien, Sue Anne
+71 Jennifer M. Burbank 289 1992-04-15 00:00:00 622 Eng 3 USA 53167.50 Burbank, Jennifer M.
+72 Claudia Sutherland NULL 1992-04-20 00:00:00 140 SRep 4 Canada 100914.00 Sutherland, Claudia
+83 Dana Bishop 290 1992-06-01 00:00:00 621 Eng 3 USA 62550.00 Bishop, Dana
+85 Mary S. MacDonald 477 1992-06-01 00:00:00 100 VP 2 USA 111262.50 MacDonald, Mary S.
+94 Randy Williams 892 1992-08-08 00:00:00 672 Mngr 4 USA 56295.00 Williams, Randy
+105 Oliver H. Bender 255 1992-10-08 00:00:00 000 CEO 1 USA 212850.00 Bender, Oliver H.
+107 Kevin Cook 894 1993-02-01 00:00:00 670 Dir 2 USA 111262.50 Cook, Kevin
+109 Kelly Brown 202 1993-02-04 00:00:00 600 Admin 5 USA 27000.00 Brown, Kelly
+110 Yuki Ichida 22 1993-02-04 00:00:00 115 Eng 3 Japan 6000000.00 Ichida, Yuki
+113 Mary Page 845 1993-04-12 00:00:00 671 Eng 4 USA 48000.00 Page, Mary
+114 Bill Parker 247 1993-06-01 00:00:00 623 Eng 5 USA 35000.00 Parker, Bill
+118 Takashi Yamamoto 23 1993-07-01 00:00:00 115 SRep 4 Japan 7480000.00 Yamamoto, Takashi
+121 Roberto Ferrari 1 1993-07-12 00:00:00 125 SRep 4 Italy 33000.00 Ferrari, Roberto
+127 Michael Yanowski 492 1993-08-09 00:00:00 100 SRep 4 USA 44000.00 Yanowski, Michael
+134 Jacques Glon NULL 1993-08-23 00:00:00 123 SRep 4 France 38500.00 Glon, Jacques
+136 Scott Johnson 265 1993-09-13 00:00:00 623 Doc 3 USA 60000.00 Johnson, Scott
+138 T.J. Green 218 1993-11-01 00:00:00 621 Eng 4 USA 36000.00 Green, T.J.
+141 Pierre Osborne NULL 1994-01-03 00:00:00 121 SRep 4 Switzerland 110000.00 Osborne, Pierre
+144 John Montgomery 820 1994-03-30 00:00:00 672 Eng 5 USA 35000.00 Montgomery, John
+145 Mark Guckenheimer 221 1994-05-02 00:00:00 622 Eng 5 USA 32000.00 Guckenheimer, Mark
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/odbc_oracle.result b/storage/connect/mysql-test/connect/r/odbc_oracle.result
new file mode 100644
index 00000000..317aacef
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/odbc_oracle.result
@@ -0,0 +1,237 @@
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Name` varchar(256) NOT NULL,
+ `Description` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Sources'
+SET NAMES utf8;
+#
+# Checking CATFUNC=Tables
+#
+
+# All tables in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables;
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL MTR T1 TABLE NULL
+NULL MTR T2 TABLE NULL
+NULL MTR V1 VIEW NULL
+DROP TABLE t1;
+# All tables in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='%.%';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL MTR T1 TABLE NULL
+NULL MTR T2 TABLE NULL
+NULL MTR V1 VIEW NULL
+DROP TABLE t1;
+# All tables "T1" in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='%.T1';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL MTR T1 TABLE NULL
+DROP TABLE t1;
+# All tables "T1" in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='T1';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL MTR T1 TABLE NULL
+DROP TABLE t1;
+# Table "T1" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='MTR.T1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL MTR T1 TABLE NULL
+DROP TABLE t1;
+# All tables in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='MTR.%';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL MTR T1 TABLE NULL
+NULL MTR T2 TABLE NULL
+NULL MTR V1 VIEW NULL
+DROP TABLE t1;
+#
+# Checking CATFUNC=Columns
+#
+
+# All columns in all schemas (limited with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Columns;
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+ MTR T1 A 3 DECIMAL 38 40 0 10 1
+ MTR T1 B 6 NUMBER 38 40 NULL NULL 1
+ MTR T2 A 12 VARCHAR2 64 64 NULL NULL 1
+ MTR V1 A 3 DECIMAL 38 40 0 10 1
+ MTR V1 B 6 NUMBER 38 40 NULL NULL 1
+DROP TABLE t1;
+# All columns in all schemas (limited with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Columns TABNAME='%.%';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+ MTR T1 A 3 DECIMAL 38 40 0 10 1
+ MTR T1 B 6 NUMBER 38 40 NULL NULL 1
+ MTR T2 A 12 VARCHAR2 64 64 NULL NULL 1
+ MTR V1 A 3 DECIMAL 38 40 0 10 1
+ MTR V1 B 6 NUMBER 38 40 NULL NULL 1
+DROP TABLE t1;
+# All tables "T1" in all schemas (limited with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew' CATFUNC=Columns TABNAME='%.T1';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+ MTR T1 A 3 DECIMAL 38 40 0 10 1
+ MTR T1 B 6 NUMBER 38 40 NULL NULL 1
+DROP TABLE t1;
+# Table "T1" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Columns TABNAME='MTR.T1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+ MTR T1 A 3 DECIMAL 38 40 0 10 1
+ MTR T1 B 6 NUMBER 38 40 NULL NULL 1
+DROP TABLE t1;
+# All tables "T1" in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Columns TABNAME='%.T1';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+ MTR T1 A 3 DECIMAL 38 40 0 10 1
+ MTR T1 B 6 NUMBER 38 40 NULL NULL 1
+DROP TABLE t1;
+#
+# Checking tables
+#
+
+# Table "T1" in the default schema ("MTR")
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+TABNAME='T1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `A` decimal(40,0) DEFAULT NULL,
+ `B` double DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew' `TABLE_TYPE`='ODBC' `TABNAME`='T1'
+SELECT * FROM t1 ORDER BY A;
+A B
+10 1000000000
+20 1000000000000
+30 1e15
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `A` decimal(40,0) DEFAULT NULL,
+ `B` double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+A B
+10 1000000000
+20 1000000000000
+30 1e15
+DROP TABLE t2;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+A B
+10 1000000000
+20 1000000000000
+30 1e15
+DROP VIEW v1;
+DROP TABLE t1;
+# Table "T1" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+TABNAME='MTR.T1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `A` decimal(40,0) DEFAULT NULL,
+ `B` double DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew' `TABLE_TYPE`='ODBC' `TABNAME`='MTR.T1'
+SELECT * FROM t1;
+A B
+10 1000000000
+20 1000000000000
+30 1e15
+DROP TABLE t1;
+# View "V1" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+TABNAME='MTR.V1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `A` decimal(40,0) DEFAULT NULL,
+ `B` double DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew' `TABLE_TYPE`='ODBC' `TABNAME`='MTR.V1'
+SELECT * FROM t1;
+A B
+10 1000000000
+20 1000000000000
+30 1e15
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `A` decimal(40,0) DEFAULT NULL,
+ `B` double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+A B
+10 1000000000
+20 1000000000000
+30 1e15
+DROP TABLE t2;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+A B
+10 1000000000
+20 1000000000000
+30 1e15
+DROP VIEW v1;
+DROP TABLE t1;
+# Table "T2" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+TABNAME='MTR.T2';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `A` varchar(64) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew' `TABLE_TYPE`='ODBC' `TABNAME`='MTR.T2'
+SELECT * FROM t1;
+A
+test
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `A` varchar(64) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+A
+test
+DROP TABLE t2;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+A
+test
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/odbc_postgresql.result b/storage/connect/mysql-test/connect/r/odbc_postgresql.result
new file mode 100644
index 00000000..dc23dbdb
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/odbc_postgresql.result
@@ -0,0 +1,296 @@
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Name` varchar(256) NOT NULL,
+ `Description` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Sources'
+SET NAMES utf8;
+#
+# Checking CATFUNC=Tables
+#
+
+# All tables in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables;
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+mtr public t2 TABLE
+mtr public v1 VIEW
+mtr schema1 t1 TABLE
+mtr schema1 t2 TABLE
+mtr schema1 v1 VIEW
+DROP TABLE t1;
+# All tables in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.%.%';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+mtr public t2 TABLE
+mtr public v1 VIEW
+mtr schema1 t1 TABLE
+mtr schema1 t2 TABLE
+mtr schema1 v1 VIEW
+DROP TABLE t1;
+# All tables in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.%';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+mtr public t2 TABLE
+mtr public v1 VIEW
+mtr schema1 t1 TABLE
+mtr schema1 t2 TABLE
+mtr schema1 v1 VIEW
+DROP TABLE t1;
+# All tables in the default schema ("public")
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+mtr public t2 TABLE
+mtr public v1 VIEW
+DROP TABLE t1;
+# All tables "t1" in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+mtr schema1 t1 TABLE
+DROP TABLE t1;
+# All tables "t1" in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+mtr schema1 t1 TABLE
+DROP TABLE t1;
+# Table "t1" in the default schema ("public")
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+DROP TABLE t1;
+# Table "t1" in the schema "public"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.public.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+DROP TABLE t1;
+# Table "t1" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.schema1.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr schema1 t1 TABLE
+DROP TABLE t1;
+# All tables "t1" in all schemas (Catalog name is ignored by PostgreSQL)
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='xxx.%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+mtr public t1 TABLE
+mtr schema1 t1 TABLE
+DROP TABLE t1;
+#
+# Checking CATFUNC=Columns
+#
+
+# All columns in the schemas "public" and "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns;
+SELECT * FROM t1 WHERE Table_Schema IN ('public','schema1') ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+mtr public t1 a 4 int4 10 4 0 10 0
+mtr public t2 a 4 int4 10 4 0 10 0
+mtr public v1 a 4 int4 10 4 0 10 1
+mtr schema1 t1 a 1 bpchar 10 40 NULL NULL 0
+mtr schema1 t2 a 1 bpchar 10 40 NULL NULL 0
+mtr schema1 v1 a 1 bpchar 10 40 NULL NULL 1
+DROP TABLE t1;
+# All columns in the schemas "public" and "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.%.%';
+SELECT * FROM t1 WHERE Table_Schema IN ('public','schema1') ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+mtr public t1 a 4 int4 10 4 0 10 0
+mtr public t2 a 4 int4 10 4 0 10 0
+mtr public v1 a 4 int4 10 4 0 10 1
+mtr schema1 t1 a 1 bpchar 10 40 NULL NULL 0
+mtr schema1 t2 a 1 bpchar 10 40 NULL NULL 0
+mtr schema1 v1 a 1 bpchar 10 40 NULL NULL 1
+DROP TABLE t1;
+# All tables "t1" in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+mtr public t1 a 4 int4 10 4 0 10 0
+mtr schema1 t1 a 1 bpchar 10 40 NULL NULL 0
+DROP TABLE t1;
+# Table "t1" in the schema "public"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.public.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+mtr public t1 a 4 int4 10 4 0 10 0
+DROP TABLE t1;
+# Table "t1" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.schema1.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+mtr schema1 t1 a 1 bpchar 10 40 NULL NULL 0
+DROP TABLE t1;
+# All tables "t1" in all schemas (Catalog name is ignored by PostgreSQL)
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='xxx.%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+mtr public t1 a 4 int4 10 4 0 10 0
+mtr schema1 t1 a 1 bpchar 10 40 NULL NULL 0
+DROP TABLE t1;
+#
+# Checking tables
+#
+
+# Table "t1" in the default schema ("public")
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' `TABLE_TYPE`='ODBC'
+SELECT * FROM t1;
+a
+10
+20
+30
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(10) NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+a
+10
+20
+30
+DROP TABLE t2;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+10
+20
+30
+DROP VIEW v1;
+DROP TABLE t1;
+# Table "t1" in the schema "public"
+CREATE TABLE t1 ENGINE=CONNECT TABNAME='public.t1' TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' `TABLE_TYPE`='ODBC' `TABNAME`='public.t1'
+SELECT * FROM t1;
+a
+10
+20
+30
+DROP TABLE t1;
+# Table "t1" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABNAME='schema1.t1' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=utf8 CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' `TABLE_TYPE`='ODBC' `TABNAME`='schema1.t1' `DATA_CHARSET`='utf8'
+SELECT * FROM t1;
+a
+aaa
+bbb
+ccc
+ÑÑÑ
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` char(10) CHARACTER SET utf8 NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+a
+aaa
+bbb
+ccc
+ÑÑÑ
+DROP TABLE t2;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+aaa
+bbb
+ccc
+ÑÑÑ
+DROP VIEW v1;
+DROP TABLE t1;
+# View "v1" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABNAME='schema1.v1' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=utf8 CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' `TABLE_TYPE`='ODBC' `TABNAME`='schema1.v1' `DATA_CHARSET`='utf8'
+SELECT * FROM t1;
+a
+aaa
+bbb
+ccc
+ÑÑÑ
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` char(10) CHARACTER SET utf8 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+a
+aaa
+bbb
+ccc
+ÑÑÑ
+DROP TABLE t2;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+aaa
+bbb
+ccc
+ÑÑÑ
+DROP VIEW v1;
+DROP TABLE t1;
+# Table "t2" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABNAME='schema1.t2' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=utf8 CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' `TABLE_TYPE`='ODBC' `TABNAME`='schema1.t2' `DATA_CHARSET`='utf8'
+SELECT * FROM t1;
+a
+xxx
+yyy
+zzz
+ÄÖÜ
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` char(10) CHARACTER SET utf8 NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+a
+xxx
+yyy
+zzz
+ÄÖÜ
+DROP TABLE t2;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+xxx
+yyy
+zzz
+ÄÖÜ
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/odbc_sqlite3.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result
new file mode 100644
index 00000000..bce69227
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/odbc_sqlite3.result
@@ -0,0 +1,2463 @@
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Description` char(128) NOT NULL,
+ `Attributes` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
+SET NAMES utf8;
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(64) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=utf8 CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' `TABLE_TYPE`='ODBC' `DATA_CHARSET`='utf8'
+SELECT * FROM t1;
+a
+test1
+test2
+теÑÑ‚1
+теÑÑ‚2
+ÆÇÈÉË
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` varchar(64) CHARACTER SET utf8 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+a
+test1
+test2
+теÑÑ‚1
+теÑÑ‚2
+ÆÇÈÉË
+DROP TABLE t2;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+test1
+test2
+теÑÑ‚1
+теÑÑ‚2
+ÆÇÈÉË
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
+SELECT * FROM t1;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+ t1 a 12 varchar(64) 64 64 10 0 1 NULL
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
+SELECT * FROM t1;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL NULL t1 TABLE NULL
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
+SELECT * FROM t1 ORDER BY Table_name;
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+ t000 a 4 INT 9 10 10 0 1 NULL
+ t000 b 4 INT 9 10 10 0 1 NULL
+ t000 c 4 INT 9 10 10 0 1 NULL
+ t000 d 4 INT 9 10 10 0 1 NULL
+ t000 e 4 INT 9 10 10 0 1 NULL
+ t001 a 4 INT 9 10 10 0 1 NULL
+ t001 b 4 INT 9 10 10 0 1 NULL
+ t001 c 4 INT 9 10 10 0 1 NULL
+ t001 d 4 INT 9 10 10 0 1 NULL
+ t001 e 4 INT 9 10 10 0 1 NULL
+ t002 a 4 INT 9 10 10 0 1 NULL
+ t002 b 4 INT 9 10 10 0 1 NULL
+ t002 c 4 INT 9 10 10 0 1 NULL
+ t002 d 4 INT 9 10 10 0 1 NULL
+ t002 e 4 INT 9 10 10 0 1 NULL
+ t003 a 4 INT 9 10 10 0 1 NULL
+ t003 b 4 INT 9 10 10 0 1 NULL
+ t003 c 4 INT 9 10 10 0 1 NULL
+ t003 d 4 INT 9 10 10 0 1 NULL
+ t003 e 4 INT 9 10 10 0 1 NULL
+ t004 a 4 INT 9 10 10 0 1 NULL
+ t004 b 4 INT 9 10 10 0 1 NULL
+ t004 c 4 INT 9 10 10 0 1 NULL
+ t004 d 4 INT 9 10 10 0 1 NULL
+ t004 e 4 INT 9 10 10 0 1 NULL
+ t005 a 4 INT 9 10 10 0 1 NULL
+ t005 b 4 INT 9 10 10 0 1 NULL
+ t005 c 4 INT 9 10 10 0 1 NULL
+ t005 d 4 INT 9 10 10 0 1 NULL
+ t005 e 4 INT 9 10 10 0 1 NULL
+ t006 a 4 INT 9 10 10 0 1 NULL
+ t006 b 4 INT 9 10 10 0 1 NULL
+ t006 c 4 INT 9 10 10 0 1 NULL
+ t006 d 4 INT 9 10 10 0 1 NULL
+ t006 e 4 INT 9 10 10 0 1 NULL
+ t007 a 4 INT 9 10 10 0 1 NULL
+ t007 b 4 INT 9 10 10 0 1 NULL
+ t007 c 4 INT 9 10 10 0 1 NULL
+ t007 d 4 INT 9 10 10 0 1 NULL
+ t007 e 4 INT 9 10 10 0 1 NULL
+ t008 a 4 INT 9 10 10 0 1 NULL
+ t008 b 4 INT 9 10 10 0 1 NULL
+ t008 c 4 INT 9 10 10 0 1 NULL
+ t008 d 4 INT 9 10 10 0 1 NULL
+ t008 e 4 INT 9 10 10 0 1 NULL
+ t009 a 4 INT 9 10 10 0 1 NULL
+ t009 b 4 INT 9 10 10 0 1 NULL
+ t009 c 4 INT 9 10 10 0 1 NULL
+ t009 d 4 INT 9 10 10 0 1 NULL
+ t009 e 4 INT 9 10 10 0 1 NULL
+ t010 a 4 INT 9 10 10 0 1 NULL
+ t010 b 4 INT 9 10 10 0 1 NULL
+ t010 c 4 INT 9 10 10 0 1 NULL
+ t010 d 4 INT 9 10 10 0 1 NULL
+ t010 e 4 INT 9 10 10 0 1 NULL
+ t011 a 4 INT 9 10 10 0 1 NULL
+ t011 b 4 INT 9 10 10 0 1 NULL
+ t011 c 4 INT 9 10 10 0 1 NULL
+ t011 d 4 INT 9 10 10 0 1 NULL
+ t011 e 4 INT 9 10 10 0 1 NULL
+ t012 a 4 INT 9 10 10 0 1 NULL
+ t012 b 4 INT 9 10 10 0 1 NULL
+ t012 c 4 INT 9 10 10 0 1 NULL
+ t012 d 4 INT 9 10 10 0 1 NULL
+ t012 e 4 INT 9 10 10 0 1 NULL
+ t013 a 4 INT 9 10 10 0 1 NULL
+ t013 b 4 INT 9 10 10 0 1 NULL
+ t013 c 4 INT 9 10 10 0 1 NULL
+ t013 d 4 INT 9 10 10 0 1 NULL
+ t013 e 4 INT 9 10 10 0 1 NULL
+ t014 a 4 INT 9 10 10 0 1 NULL
+ t014 b 4 INT 9 10 10 0 1 NULL
+ t014 c 4 INT 9 10 10 0 1 NULL
+ t014 d 4 INT 9 10 10 0 1 NULL
+ t014 e 4 INT 9 10 10 0 1 NULL
+ t015 a 4 INT 9 10 10 0 1 NULL
+ t015 b 4 INT 9 10 10 0 1 NULL
+ t015 c 4 INT 9 10 10 0 1 NULL
+ t015 d 4 INT 9 10 10 0 1 NULL
+ t015 e 4 INT 9 10 10 0 1 NULL
+ t016 a 4 INT 9 10 10 0 1 NULL
+ t016 b 4 INT 9 10 10 0 1 NULL
+ t016 c 4 INT 9 10 10 0 1 NULL
+ t016 d 4 INT 9 10 10 0 1 NULL
+ t016 e 4 INT 9 10 10 0 1 NULL
+ t017 a 4 INT 9 10 10 0 1 NULL
+ t017 b 4 INT 9 10 10 0 1 NULL
+ t017 c 4 INT 9 10 10 0 1 NULL
+ t017 d 4 INT 9 10 10 0 1 NULL
+ t017 e 4 INT 9 10 10 0 1 NULL
+ t018 a 4 INT 9 10 10 0 1 NULL
+ t018 b 4 INT 9 10 10 0 1 NULL
+ t018 c 4 INT 9 10 10 0 1 NULL
+ t018 d 4 INT 9 10 10 0 1 NULL
+ t018 e 4 INT 9 10 10 0 1 NULL
+ t019 a 4 INT 9 10 10 0 1 NULL
+ t019 b 4 INT 9 10 10 0 1 NULL
+ t019 c 4 INT 9 10 10 0 1 NULL
+ t019 d 4 INT 9 10 10 0 1 NULL
+ t019 e 4 INT 9 10 10 0 1 NULL
+ t020 a 4 INT 9 10 10 0 1 NULL
+ t020 b 4 INT 9 10 10 0 1 NULL
+ t020 c 4 INT 9 10 10 0 1 NULL
+ t020 d 4 INT 9 10 10 0 1 NULL
+ t020 e 4 INT 9 10 10 0 1 NULL
+ t021 a 4 INT 9 10 10 0 1 NULL
+ t021 b 4 INT 9 10 10 0 1 NULL
+ t021 c 4 INT 9 10 10 0 1 NULL
+ t021 d 4 INT 9 10 10 0 1 NULL
+ t021 e 4 INT 9 10 10 0 1 NULL
+ t022 a 4 INT 9 10 10 0 1 NULL
+ t022 b 4 INT 9 10 10 0 1 NULL
+ t022 c 4 INT 9 10 10 0 1 NULL
+ t022 d 4 INT 9 10 10 0 1 NULL
+ t022 e 4 INT 9 10 10 0 1 NULL
+ t023 a 4 INT 9 10 10 0 1 NULL
+ t023 b 4 INT 9 10 10 0 1 NULL
+ t023 c 4 INT 9 10 10 0 1 NULL
+ t023 d 4 INT 9 10 10 0 1 NULL
+ t023 e 4 INT 9 10 10 0 1 NULL
+ t024 a 4 INT 9 10 10 0 1 NULL
+ t024 b 4 INT 9 10 10 0 1 NULL
+ t024 c 4 INT 9 10 10 0 1 NULL
+ t024 d 4 INT 9 10 10 0 1 NULL
+ t024 e 4 INT 9 10 10 0 1 NULL
+ t025 a 4 INT 9 10 10 0 1 NULL
+ t025 b 4 INT 9 10 10 0 1 NULL
+ t025 c 4 INT 9 10 10 0 1 NULL
+ t025 d 4 INT 9 10 10 0 1 NULL
+ t025 e 4 INT 9 10 10 0 1 NULL
+ t026 a 4 INT 9 10 10 0 1 NULL
+ t026 b 4 INT 9 10 10 0 1 NULL
+ t026 c 4 INT 9 10 10 0 1 NULL
+ t026 d 4 INT 9 10 10 0 1 NULL
+ t026 e 4 INT 9 10 10 0 1 NULL
+ t027 a 4 INT 9 10 10 0 1 NULL
+ t027 b 4 INT 9 10 10 0 1 NULL
+ t027 c 4 INT 9 10 10 0 1 NULL
+ t027 d 4 INT 9 10 10 0 1 NULL
+ t027 e 4 INT 9 10 10 0 1 NULL
+ t028 a 4 INT 9 10 10 0 1 NULL
+ t028 b 4 INT 9 10 10 0 1 NULL
+ t028 c 4 INT 9 10 10 0 1 NULL
+ t028 d 4 INT 9 10 10 0 1 NULL
+ t028 e 4 INT 9 10 10 0 1 NULL
+ t029 a 4 INT 9 10 10 0 1 NULL
+ t029 b 4 INT 9 10 10 0 1 NULL
+ t029 c 4 INT 9 10 10 0 1 NULL
+ t029 d 4 INT 9 10 10 0 1 NULL
+ t029 e 4 INT 9 10 10 0 1 NULL
+ t030 a 4 INT 9 10 10 0 1 NULL
+ t030 b 4 INT 9 10 10 0 1 NULL
+ t030 c 4 INT 9 10 10 0 1 NULL
+ t030 d 4 INT 9 10 10 0 1 NULL
+ t030 e 4 INT 9 10 10 0 1 NULL
+ t031 a 4 INT 9 10 10 0 1 NULL
+ t031 b 4 INT 9 10 10 0 1 NULL
+ t031 c 4 INT 9 10 10 0 1 NULL
+ t031 d 4 INT 9 10 10 0 1 NULL
+ t031 e 4 INT 9 10 10 0 1 NULL
+ t032 a 4 INT 9 10 10 0 1 NULL
+ t032 b 4 INT 9 10 10 0 1 NULL
+ t032 c 4 INT 9 10 10 0 1 NULL
+ t032 d 4 INT 9 10 10 0 1 NULL
+ t032 e 4 INT 9 10 10 0 1 NULL
+ t033 a 4 INT 9 10 10 0 1 NULL
+ t033 b 4 INT 9 10 10 0 1 NULL
+ t033 c 4 INT 9 10 10 0 1 NULL
+ t033 d 4 INT 9 10 10 0 1 NULL
+ t033 e 4 INT 9 10 10 0 1 NULL
+ t034 a 4 INT 9 10 10 0 1 NULL
+ t034 b 4 INT 9 10 10 0 1 NULL
+ t034 c 4 INT 9 10 10 0 1 NULL
+ t034 d 4 INT 9 10 10 0 1 NULL
+ t034 e 4 INT 9 10 10 0 1 NULL
+ t035 a 4 INT 9 10 10 0 1 NULL
+ t035 b 4 INT 9 10 10 0 1 NULL
+ t035 c 4 INT 9 10 10 0 1 NULL
+ t035 d 4 INT 9 10 10 0 1 NULL
+ t035 e 4 INT 9 10 10 0 1 NULL
+ t036 a 4 INT 9 10 10 0 1 NULL
+ t036 b 4 INT 9 10 10 0 1 NULL
+ t036 c 4 INT 9 10 10 0 1 NULL
+ t036 d 4 INT 9 10 10 0 1 NULL
+ t036 e 4 INT 9 10 10 0 1 NULL
+ t037 a 4 INT 9 10 10 0 1 NULL
+ t037 b 4 INT 9 10 10 0 1 NULL
+ t037 c 4 INT 9 10 10 0 1 NULL
+ t037 d 4 INT 9 10 10 0 1 NULL
+ t037 e 4 INT 9 10 10 0 1 NULL
+ t038 a 4 INT 9 10 10 0 1 NULL
+ t038 b 4 INT 9 10 10 0 1 NULL
+ t038 c 4 INT 9 10 10 0 1 NULL
+ t038 d 4 INT 9 10 10 0 1 NULL
+ t038 e 4 INT 9 10 10 0 1 NULL
+ t039 a 4 INT 9 10 10 0 1 NULL
+ t039 b 4 INT 9 10 10 0 1 NULL
+ t039 c 4 INT 9 10 10 0 1 NULL
+ t039 d 4 INT 9 10 10 0 1 NULL
+ t039 e 4 INT 9 10 10 0 1 NULL
+ t040 a 4 INT 9 10 10 0 1 NULL
+ t040 b 4 INT 9 10 10 0 1 NULL
+ t040 c 4 INT 9 10 10 0 1 NULL
+ t040 d 4 INT 9 10 10 0 1 NULL
+ t040 e 4 INT 9 10 10 0 1 NULL
+ t041 a 4 INT 9 10 10 0 1 NULL
+ t041 b 4 INT 9 10 10 0 1 NULL
+ t041 c 4 INT 9 10 10 0 1 NULL
+ t041 d 4 INT 9 10 10 0 1 NULL
+ t041 e 4 INT 9 10 10 0 1 NULL
+ t042 a 4 INT 9 10 10 0 1 NULL
+ t042 b 4 INT 9 10 10 0 1 NULL
+ t042 c 4 INT 9 10 10 0 1 NULL
+ t042 d 4 INT 9 10 10 0 1 NULL
+ t042 e 4 INT 9 10 10 0 1 NULL
+ t043 a 4 INT 9 10 10 0 1 NULL
+ t043 b 4 INT 9 10 10 0 1 NULL
+ t043 c 4 INT 9 10 10 0 1 NULL
+ t043 d 4 INT 9 10 10 0 1 NULL
+ t043 e 4 INT 9 10 10 0 1 NULL
+ t044 a 4 INT 9 10 10 0 1 NULL
+ t044 b 4 INT 9 10 10 0 1 NULL
+ t044 c 4 INT 9 10 10 0 1 NULL
+ t044 d 4 INT 9 10 10 0 1 NULL
+ t044 e 4 INT 9 10 10 0 1 NULL
+ t045 a 4 INT 9 10 10 0 1 NULL
+ t045 b 4 INT 9 10 10 0 1 NULL
+ t045 c 4 INT 9 10 10 0 1 NULL
+ t045 d 4 INT 9 10 10 0 1 NULL
+ t045 e 4 INT 9 10 10 0 1 NULL
+ t046 a 4 INT 9 10 10 0 1 NULL
+ t046 b 4 INT 9 10 10 0 1 NULL
+ t046 c 4 INT 9 10 10 0 1 NULL
+ t046 d 4 INT 9 10 10 0 1 NULL
+ t046 e 4 INT 9 10 10 0 1 NULL
+ t047 a 4 INT 9 10 10 0 1 NULL
+ t047 b 4 INT 9 10 10 0 1 NULL
+ t047 c 4 INT 9 10 10 0 1 NULL
+ t047 d 4 INT 9 10 10 0 1 NULL
+ t047 e 4 INT 9 10 10 0 1 NULL
+ t048 a 4 INT 9 10 10 0 1 NULL
+ t048 b 4 INT 9 10 10 0 1 NULL
+ t048 c 4 INT 9 10 10 0 1 NULL
+ t048 d 4 INT 9 10 10 0 1 NULL
+ t048 e 4 INT 9 10 10 0 1 NULL
+ t049 a 4 INT 9 10 10 0 1 NULL
+ t049 b 4 INT 9 10 10 0 1 NULL
+ t049 c 4 INT 9 10 10 0 1 NULL
+ t049 d 4 INT 9 10 10 0 1 NULL
+ t049 e 4 INT 9 10 10 0 1 NULL
+ t050 a 4 INT 9 10 10 0 1 NULL
+ t050 b 4 INT 9 10 10 0 1 NULL
+ t050 c 4 INT 9 10 10 0 1 NULL
+ t050 d 4 INT 9 10 10 0 1 NULL
+ t050 e 4 INT 9 10 10 0 1 NULL
+ t051 a 4 INT 9 10 10 0 1 NULL
+ t051 b 4 INT 9 10 10 0 1 NULL
+ t051 c 4 INT 9 10 10 0 1 NULL
+ t051 d 4 INT 9 10 10 0 1 NULL
+ t051 e 4 INT 9 10 10 0 1 NULL
+ t052 a 4 INT 9 10 10 0 1 NULL
+ t052 b 4 INT 9 10 10 0 1 NULL
+ t052 c 4 INT 9 10 10 0 1 NULL
+ t052 d 4 INT 9 10 10 0 1 NULL
+ t052 e 4 INT 9 10 10 0 1 NULL
+ t053 a 4 INT 9 10 10 0 1 NULL
+ t053 b 4 INT 9 10 10 0 1 NULL
+ t053 c 4 INT 9 10 10 0 1 NULL
+ t053 d 4 INT 9 10 10 0 1 NULL
+ t053 e 4 INT 9 10 10 0 1 NULL
+ t054 a 4 INT 9 10 10 0 1 NULL
+ t054 b 4 INT 9 10 10 0 1 NULL
+ t054 c 4 INT 9 10 10 0 1 NULL
+ t054 d 4 INT 9 10 10 0 1 NULL
+ t054 e 4 INT 9 10 10 0 1 NULL
+ t055 a 4 INT 9 10 10 0 1 NULL
+ t055 b 4 INT 9 10 10 0 1 NULL
+ t055 c 4 INT 9 10 10 0 1 NULL
+ t055 d 4 INT 9 10 10 0 1 NULL
+ t055 e 4 INT 9 10 10 0 1 NULL
+ t056 a 4 INT 9 10 10 0 1 NULL
+ t056 b 4 INT 9 10 10 0 1 NULL
+ t056 c 4 INT 9 10 10 0 1 NULL
+ t056 d 4 INT 9 10 10 0 1 NULL
+ t056 e 4 INT 9 10 10 0 1 NULL
+ t057 a 4 INT 9 10 10 0 1 NULL
+ t057 b 4 INT 9 10 10 0 1 NULL
+ t057 c 4 INT 9 10 10 0 1 NULL
+ t057 d 4 INT 9 10 10 0 1 NULL
+ t057 e 4 INT 9 10 10 0 1 NULL
+ t058 a 4 INT 9 10 10 0 1 NULL
+ t058 b 4 INT 9 10 10 0 1 NULL
+ t058 c 4 INT 9 10 10 0 1 NULL
+ t058 d 4 INT 9 10 10 0 1 NULL
+ t058 e 4 INT 9 10 10 0 1 NULL
+ t059 a 4 INT 9 10 10 0 1 NULL
+ t059 b 4 INT 9 10 10 0 1 NULL
+ t059 c 4 INT 9 10 10 0 1 NULL
+ t059 d 4 INT 9 10 10 0 1 NULL
+ t059 e 4 INT 9 10 10 0 1 NULL
+ t060 a 4 INT 9 10 10 0 1 NULL
+ t060 b 4 INT 9 10 10 0 1 NULL
+ t060 c 4 INT 9 10 10 0 1 NULL
+ t060 d 4 INT 9 10 10 0 1 NULL
+ t060 e 4 INT 9 10 10 0 1 NULL
+ t061 a 4 INT 9 10 10 0 1 NULL
+ t061 b 4 INT 9 10 10 0 1 NULL
+ t061 c 4 INT 9 10 10 0 1 NULL
+ t061 d 4 INT 9 10 10 0 1 NULL
+ t061 e 4 INT 9 10 10 0 1 NULL
+ t062 a 4 INT 9 10 10 0 1 NULL
+ t062 b 4 INT 9 10 10 0 1 NULL
+ t062 c 4 INT 9 10 10 0 1 NULL
+ t062 d 4 INT 9 10 10 0 1 NULL
+ t062 e 4 INT 9 10 10 0 1 NULL
+ t063 a 4 INT 9 10 10 0 1 NULL
+ t063 b 4 INT 9 10 10 0 1 NULL
+ t063 c 4 INT 9 10 10 0 1 NULL
+ t063 d 4 INT 9 10 10 0 1 NULL
+ t063 e 4 INT 9 10 10 0 1 NULL
+ t064 a 4 INT 9 10 10 0 1 NULL
+ t064 b 4 INT 9 10 10 0 1 NULL
+ t064 c 4 INT 9 10 10 0 1 NULL
+ t064 d 4 INT 9 10 10 0 1 NULL
+ t064 e 4 INT 9 10 10 0 1 NULL
+ t065 a 4 INT 9 10 10 0 1 NULL
+ t065 b 4 INT 9 10 10 0 1 NULL
+ t065 c 4 INT 9 10 10 0 1 NULL
+ t065 d 4 INT 9 10 10 0 1 NULL
+ t065 e 4 INT 9 10 10 0 1 NULL
+ t066 a 4 INT 9 10 10 0 1 NULL
+ t066 b 4 INT 9 10 10 0 1 NULL
+ t066 c 4 INT 9 10 10 0 1 NULL
+ t066 d 4 INT 9 10 10 0 1 NULL
+ t066 e 4 INT 9 10 10 0 1 NULL
+ t067 a 4 INT 9 10 10 0 1 NULL
+ t067 b 4 INT 9 10 10 0 1 NULL
+ t067 c 4 INT 9 10 10 0 1 NULL
+ t067 d 4 INT 9 10 10 0 1 NULL
+ t067 e 4 INT 9 10 10 0 1 NULL
+ t068 a 4 INT 9 10 10 0 1 NULL
+ t068 b 4 INT 9 10 10 0 1 NULL
+ t068 c 4 INT 9 10 10 0 1 NULL
+ t068 d 4 INT 9 10 10 0 1 NULL
+ t068 e 4 INT 9 10 10 0 1 NULL
+ t069 a 4 INT 9 10 10 0 1 NULL
+ t069 b 4 INT 9 10 10 0 1 NULL
+ t069 c 4 INT 9 10 10 0 1 NULL
+ t069 d 4 INT 9 10 10 0 1 NULL
+ t069 e 4 INT 9 10 10 0 1 NULL
+ t070 a 4 INT 9 10 10 0 1 NULL
+ t070 b 4 INT 9 10 10 0 1 NULL
+ t070 c 4 INT 9 10 10 0 1 NULL
+ t070 d 4 INT 9 10 10 0 1 NULL
+ t070 e 4 INT 9 10 10 0 1 NULL
+ t071 a 4 INT 9 10 10 0 1 NULL
+ t071 b 4 INT 9 10 10 0 1 NULL
+ t071 c 4 INT 9 10 10 0 1 NULL
+ t071 d 4 INT 9 10 10 0 1 NULL
+ t071 e 4 INT 9 10 10 0 1 NULL
+ t072 a 4 INT 9 10 10 0 1 NULL
+ t072 b 4 INT 9 10 10 0 1 NULL
+ t072 c 4 INT 9 10 10 0 1 NULL
+ t072 d 4 INT 9 10 10 0 1 NULL
+ t072 e 4 INT 9 10 10 0 1 NULL
+ t073 a 4 INT 9 10 10 0 1 NULL
+ t073 b 4 INT 9 10 10 0 1 NULL
+ t073 c 4 INT 9 10 10 0 1 NULL
+ t073 d 4 INT 9 10 10 0 1 NULL
+ t073 e 4 INT 9 10 10 0 1 NULL
+ t074 a 4 INT 9 10 10 0 1 NULL
+ t074 b 4 INT 9 10 10 0 1 NULL
+ t074 c 4 INT 9 10 10 0 1 NULL
+ t074 d 4 INT 9 10 10 0 1 NULL
+ t074 e 4 INT 9 10 10 0 1 NULL
+ t075 a 4 INT 9 10 10 0 1 NULL
+ t075 b 4 INT 9 10 10 0 1 NULL
+ t075 c 4 INT 9 10 10 0 1 NULL
+ t075 d 4 INT 9 10 10 0 1 NULL
+ t075 e 4 INT 9 10 10 0 1 NULL
+ t076 a 4 INT 9 10 10 0 1 NULL
+ t076 b 4 INT 9 10 10 0 1 NULL
+ t076 c 4 INT 9 10 10 0 1 NULL
+ t076 d 4 INT 9 10 10 0 1 NULL
+ t076 e 4 INT 9 10 10 0 1 NULL
+ t077 a 4 INT 9 10 10 0 1 NULL
+ t077 b 4 INT 9 10 10 0 1 NULL
+ t077 c 4 INT 9 10 10 0 1 NULL
+ t077 d 4 INT 9 10 10 0 1 NULL
+ t077 e 4 INT 9 10 10 0 1 NULL
+ t078 a 4 INT 9 10 10 0 1 NULL
+ t078 b 4 INT 9 10 10 0 1 NULL
+ t078 c 4 INT 9 10 10 0 1 NULL
+ t078 d 4 INT 9 10 10 0 1 NULL
+ t078 e 4 INT 9 10 10 0 1 NULL
+ t079 a 4 INT 9 10 10 0 1 NULL
+ t079 b 4 INT 9 10 10 0 1 NULL
+ t079 c 4 INT 9 10 10 0 1 NULL
+ t079 d 4 INT 9 10 10 0 1 NULL
+ t079 e 4 INT 9 10 10 0 1 NULL
+ t080 a 4 INT 9 10 10 0 1 NULL
+ t080 b 4 INT 9 10 10 0 1 NULL
+ t080 c 4 INT 9 10 10 0 1 NULL
+ t080 d 4 INT 9 10 10 0 1 NULL
+ t080 e 4 INT 9 10 10 0 1 NULL
+ t081 a 4 INT 9 10 10 0 1 NULL
+ t081 b 4 INT 9 10 10 0 1 NULL
+ t081 c 4 INT 9 10 10 0 1 NULL
+ t081 d 4 INT 9 10 10 0 1 NULL
+ t081 e 4 INT 9 10 10 0 1 NULL
+ t082 a 4 INT 9 10 10 0 1 NULL
+ t082 b 4 INT 9 10 10 0 1 NULL
+ t082 c 4 INT 9 10 10 0 1 NULL
+ t082 d 4 INT 9 10 10 0 1 NULL
+ t082 e 4 INT 9 10 10 0 1 NULL
+ t083 a 4 INT 9 10 10 0 1 NULL
+ t083 b 4 INT 9 10 10 0 1 NULL
+ t083 c 4 INT 9 10 10 0 1 NULL
+ t083 d 4 INT 9 10 10 0 1 NULL
+ t083 e 4 INT 9 10 10 0 1 NULL
+ t084 a 4 INT 9 10 10 0 1 NULL
+ t084 b 4 INT 9 10 10 0 1 NULL
+ t084 c 4 INT 9 10 10 0 1 NULL
+ t084 d 4 INT 9 10 10 0 1 NULL
+ t084 e 4 INT 9 10 10 0 1 NULL
+ t085 a 4 INT 9 10 10 0 1 NULL
+ t085 b 4 INT 9 10 10 0 1 NULL
+ t085 c 4 INT 9 10 10 0 1 NULL
+ t085 d 4 INT 9 10 10 0 1 NULL
+ t085 e 4 INT 9 10 10 0 1 NULL
+ t086 a 4 INT 9 10 10 0 1 NULL
+ t086 b 4 INT 9 10 10 0 1 NULL
+ t086 c 4 INT 9 10 10 0 1 NULL
+ t086 d 4 INT 9 10 10 0 1 NULL
+ t086 e 4 INT 9 10 10 0 1 NULL
+ t087 a 4 INT 9 10 10 0 1 NULL
+ t087 b 4 INT 9 10 10 0 1 NULL
+ t087 c 4 INT 9 10 10 0 1 NULL
+ t087 d 4 INT 9 10 10 0 1 NULL
+ t087 e 4 INT 9 10 10 0 1 NULL
+ t088 a 4 INT 9 10 10 0 1 NULL
+ t088 b 4 INT 9 10 10 0 1 NULL
+ t088 c 4 INT 9 10 10 0 1 NULL
+ t088 d 4 INT 9 10 10 0 1 NULL
+ t088 e 4 INT 9 10 10 0 1 NULL
+ t089 a 4 INT 9 10 10 0 1 NULL
+ t089 b 4 INT 9 10 10 0 1 NULL
+ t089 c 4 INT 9 10 10 0 1 NULL
+ t089 d 4 INT 9 10 10 0 1 NULL
+ t089 e 4 INT 9 10 10 0 1 NULL
+ t090 a 4 INT 9 10 10 0 1 NULL
+ t090 b 4 INT 9 10 10 0 1 NULL
+ t090 c 4 INT 9 10 10 0 1 NULL
+ t090 d 4 INT 9 10 10 0 1 NULL
+ t090 e 4 INT 9 10 10 0 1 NULL
+ t091 a 4 INT 9 10 10 0 1 NULL
+ t091 b 4 INT 9 10 10 0 1 NULL
+ t091 c 4 INT 9 10 10 0 1 NULL
+ t091 d 4 INT 9 10 10 0 1 NULL
+ t091 e 4 INT 9 10 10 0 1 NULL
+ t092 a 4 INT 9 10 10 0 1 NULL
+ t092 b 4 INT 9 10 10 0 1 NULL
+ t092 c 4 INT 9 10 10 0 1 NULL
+ t092 d 4 INT 9 10 10 0 1 NULL
+ t092 e 4 INT 9 10 10 0 1 NULL
+ t093 a 4 INT 9 10 10 0 1 NULL
+ t093 b 4 INT 9 10 10 0 1 NULL
+ t093 c 4 INT 9 10 10 0 1 NULL
+ t093 d 4 INT 9 10 10 0 1 NULL
+ t093 e 4 INT 9 10 10 0 1 NULL
+ t094 a 4 INT 9 10 10 0 1 NULL
+ t094 b 4 INT 9 10 10 0 1 NULL
+ t094 c 4 INT 9 10 10 0 1 NULL
+ t094 d 4 INT 9 10 10 0 1 NULL
+ t094 e 4 INT 9 10 10 0 1 NULL
+ t095 a 4 INT 9 10 10 0 1 NULL
+ t095 b 4 INT 9 10 10 0 1 NULL
+ t095 c 4 INT 9 10 10 0 1 NULL
+ t095 d 4 INT 9 10 10 0 1 NULL
+ t095 e 4 INT 9 10 10 0 1 NULL
+ t096 a 4 INT 9 10 10 0 1 NULL
+ t096 b 4 INT 9 10 10 0 1 NULL
+ t096 c 4 INT 9 10 10 0 1 NULL
+ t096 d 4 INT 9 10 10 0 1 NULL
+ t096 e 4 INT 9 10 10 0 1 NULL
+ t097 a 4 INT 9 10 10 0 1 NULL
+ t097 b 4 INT 9 10 10 0 1 NULL
+ t097 c 4 INT 9 10 10 0 1 NULL
+ t097 d 4 INT 9 10 10 0 1 NULL
+ t097 e 4 INT 9 10 10 0 1 NULL
+ t098 a 4 INT 9 10 10 0 1 NULL
+ t098 b 4 INT 9 10 10 0 1 NULL
+ t098 c 4 INT 9 10 10 0 1 NULL
+ t098 d 4 INT 9 10 10 0 1 NULL
+ t098 e 4 INT 9 10 10 0 1 NULL
+ t099 a 4 INT 9 10 10 0 1 NULL
+ t099 b 4 INT 9 10 10 0 1 NULL
+ t099 c 4 INT 9 10 10 0 1 NULL
+ t099 d 4 INT 9 10 10 0 1 NULL
+ t099 e 4 INT 9 10 10 0 1 NULL
+ t1 a 12 varchar(64) 64 64 10 0 1 NULL
+ t100 a 4 INT 9 10 10 0 1 NULL
+ t100 b 4 INT 9 10 10 0 1 NULL
+ t100 c 4 INT 9 10 10 0 1 NULL
+ t100 d 4 INT 9 10 10 0 1 NULL
+ t100 e 4 INT 9 10 10 0 1 NULL
+ t101 a 4 INT 9 10 10 0 1 NULL
+ t101 b 4 INT 9 10 10 0 1 NULL
+ t101 c 4 INT 9 10 10 0 1 NULL
+ t101 d 4 INT 9 10 10 0 1 NULL
+ t101 e 4 INT 9 10 10 0 1 NULL
+ t102 a 4 INT 9 10 10 0 1 NULL
+ t102 b 4 INT 9 10 10 0 1 NULL
+ t102 c 4 INT 9 10 10 0 1 NULL
+ t102 d 4 INT 9 10 10 0 1 NULL
+ t102 e 4 INT 9 10 10 0 1 NULL
+ t103 a 4 INT 9 10 10 0 1 NULL
+ t103 b 4 INT 9 10 10 0 1 NULL
+ t103 c 4 INT 9 10 10 0 1 NULL
+ t103 d 4 INT 9 10 10 0 1 NULL
+ t103 e 4 INT 9 10 10 0 1 NULL
+ t104 a 4 INT 9 10 10 0 1 NULL
+ t104 b 4 INT 9 10 10 0 1 NULL
+ t104 c 4 INT 9 10 10 0 1 NULL
+ t104 d 4 INT 9 10 10 0 1 NULL
+ t104 e 4 INT 9 10 10 0 1 NULL
+ t105 a 4 INT 9 10 10 0 1 NULL
+ t105 b 4 INT 9 10 10 0 1 NULL
+ t105 c 4 INT 9 10 10 0 1 NULL
+ t105 d 4 INT 9 10 10 0 1 NULL
+ t105 e 4 INT 9 10 10 0 1 NULL
+ t106 a 4 INT 9 10 10 0 1 NULL
+ t106 b 4 INT 9 10 10 0 1 NULL
+ t106 c 4 INT 9 10 10 0 1 NULL
+ t106 d 4 INT 9 10 10 0 1 NULL
+ t106 e 4 INT 9 10 10 0 1 NULL
+ t107 a 4 INT 9 10 10 0 1 NULL
+ t107 b 4 INT 9 10 10 0 1 NULL
+ t107 c 4 INT 9 10 10 0 1 NULL
+ t107 d 4 INT 9 10 10 0 1 NULL
+ t107 e 4 INT 9 10 10 0 1 NULL
+ t108 a 4 INT 9 10 10 0 1 NULL
+ t108 b 4 INT 9 10 10 0 1 NULL
+ t108 c 4 INT 9 10 10 0 1 NULL
+ t108 d 4 INT 9 10 10 0 1 NULL
+ t108 e 4 INT 9 10 10 0 1 NULL
+ t109 a 4 INT 9 10 10 0 1 NULL
+ t109 b 4 INT 9 10 10 0 1 NULL
+ t109 c 4 INT 9 10 10 0 1 NULL
+ t109 d 4 INT 9 10 10 0 1 NULL
+ t109 e 4 INT 9 10 10 0 1 NULL
+ t110 a 4 INT 9 10 10 0 1 NULL
+ t110 b 4 INT 9 10 10 0 1 NULL
+ t110 c 4 INT 9 10 10 0 1 NULL
+ t110 d 4 INT 9 10 10 0 1 NULL
+ t110 e 4 INT 9 10 10 0 1 NULL
+ t111 a 4 INT 9 10 10 0 1 NULL
+ t111 b 4 INT 9 10 10 0 1 NULL
+ t111 c 4 INT 9 10 10 0 1 NULL
+ t111 d 4 INT 9 10 10 0 1 NULL
+ t111 e 4 INT 9 10 10 0 1 NULL
+ t112 a 4 INT 9 10 10 0 1 NULL
+ t112 b 4 INT 9 10 10 0 1 NULL
+ t112 c 4 INT 9 10 10 0 1 NULL
+ t112 d 4 INT 9 10 10 0 1 NULL
+ t112 e 4 INT 9 10 10 0 1 NULL
+ t113 a 4 INT 9 10 10 0 1 NULL
+ t113 b 4 INT 9 10 10 0 1 NULL
+ t113 c 4 INT 9 10 10 0 1 NULL
+ t113 d 4 INT 9 10 10 0 1 NULL
+ t113 e 4 INT 9 10 10 0 1 NULL
+ t114 a 4 INT 9 10 10 0 1 NULL
+ t114 b 4 INT 9 10 10 0 1 NULL
+ t114 c 4 INT 9 10 10 0 1 NULL
+ t114 d 4 INT 9 10 10 0 1 NULL
+ t114 e 4 INT 9 10 10 0 1 NULL
+ t115 a 4 INT 9 10 10 0 1 NULL
+ t115 b 4 INT 9 10 10 0 1 NULL
+ t115 c 4 INT 9 10 10 0 1 NULL
+ t115 d 4 INT 9 10 10 0 1 NULL
+ t115 e 4 INT 9 10 10 0 1 NULL
+ t116 a 4 INT 9 10 10 0 1 NULL
+ t116 b 4 INT 9 10 10 0 1 NULL
+ t116 c 4 INT 9 10 10 0 1 NULL
+ t116 d 4 INT 9 10 10 0 1 NULL
+ t116 e 4 INT 9 10 10 0 1 NULL
+ t117 a 4 INT 9 10 10 0 1 NULL
+ t117 b 4 INT 9 10 10 0 1 NULL
+ t117 c 4 INT 9 10 10 0 1 NULL
+ t117 d 4 INT 9 10 10 0 1 NULL
+ t117 e 4 INT 9 10 10 0 1 NULL
+ t118 a 4 INT 9 10 10 0 1 NULL
+ t118 b 4 INT 9 10 10 0 1 NULL
+ t118 c 4 INT 9 10 10 0 1 NULL
+ t118 d 4 INT 9 10 10 0 1 NULL
+ t118 e 4 INT 9 10 10 0 1 NULL
+ t119 a 4 INT 9 10 10 0 1 NULL
+ t119 b 4 INT 9 10 10 0 1 NULL
+ t119 c 4 INT 9 10 10 0 1 NULL
+ t119 d 4 INT 9 10 10 0 1 NULL
+ t119 e 4 INT 9 10 10 0 1 NULL
+ t120 a 4 INT 9 10 10 0 1 NULL
+ t120 b 4 INT 9 10 10 0 1 NULL
+ t120 c 4 INT 9 10 10 0 1 NULL
+ t120 d 4 INT 9 10 10 0 1 NULL
+ t120 e 4 INT 9 10 10 0 1 NULL
+ t121 a 4 INT 9 10 10 0 1 NULL
+ t121 b 4 INT 9 10 10 0 1 NULL
+ t121 c 4 INT 9 10 10 0 1 NULL
+ t121 d 4 INT 9 10 10 0 1 NULL
+ t121 e 4 INT 9 10 10 0 1 NULL
+ t122 a 4 INT 9 10 10 0 1 NULL
+ t122 b 4 INT 9 10 10 0 1 NULL
+ t122 c 4 INT 9 10 10 0 1 NULL
+ t122 d 4 INT 9 10 10 0 1 NULL
+ t122 e 4 INT 9 10 10 0 1 NULL
+ t123 a 4 INT 9 10 10 0 1 NULL
+ t123 b 4 INT 9 10 10 0 1 NULL
+ t123 c 4 INT 9 10 10 0 1 NULL
+ t123 d 4 INT 9 10 10 0 1 NULL
+ t123 e 4 INT 9 10 10 0 1 NULL
+ t124 a 4 INT 9 10 10 0 1 NULL
+ t124 b 4 INT 9 10 10 0 1 NULL
+ t124 c 4 INT 9 10 10 0 1 NULL
+ t124 d 4 INT 9 10 10 0 1 NULL
+ t124 e 4 INT 9 10 10 0 1 NULL
+ t125 a 4 INT 9 10 10 0 1 NULL
+ t125 b 4 INT 9 10 10 0 1 NULL
+ t125 c 4 INT 9 10 10 0 1 NULL
+ t125 d 4 INT 9 10 10 0 1 NULL
+ t125 e 4 INT 9 10 10 0 1 NULL
+ t126 a 4 INT 9 10 10 0 1 NULL
+ t126 b 4 INT 9 10 10 0 1 NULL
+ t126 c 4 INT 9 10 10 0 1 NULL
+ t126 d 4 INT 9 10 10 0 1 NULL
+ t126 e 4 INT 9 10 10 0 1 NULL
+ t127 a 4 INT 9 10 10 0 1 NULL
+ t127 b 4 INT 9 10 10 0 1 NULL
+ t127 c 4 INT 9 10 10 0 1 NULL
+ t127 d 4 INT 9 10 10 0 1 NULL
+ t127 e 4 INT 9 10 10 0 1 NULL
+ t128 a 4 INT 9 10 10 0 1 NULL
+ t128 b 4 INT 9 10 10 0 1 NULL
+ t128 c 4 INT 9 10 10 0 1 NULL
+ t128 d 4 INT 9 10 10 0 1 NULL
+ t128 e 4 INT 9 10 10 0 1 NULL
+ t129 a 4 INT 9 10 10 0 1 NULL
+ t129 b 4 INT 9 10 10 0 1 NULL
+ t129 c 4 INT 9 10 10 0 1 NULL
+ t129 d 4 INT 9 10 10 0 1 NULL
+ t129 e 4 INT 9 10 10 0 1 NULL
+ t130 a 4 INT 9 10 10 0 1 NULL
+ t130 b 4 INT 9 10 10 0 1 NULL
+ t130 c 4 INT 9 10 10 0 1 NULL
+ t130 d 4 INT 9 10 10 0 1 NULL
+ t130 e 4 INT 9 10 10 0 1 NULL
+ t131 a 4 INT 9 10 10 0 1 NULL
+ t131 b 4 INT 9 10 10 0 1 NULL
+ t131 c 4 INT 9 10 10 0 1 NULL
+ t131 d 4 INT 9 10 10 0 1 NULL
+ t131 e 4 INT 9 10 10 0 1 NULL
+ t132 a 4 INT 9 10 10 0 1 NULL
+ t132 b 4 INT 9 10 10 0 1 NULL
+ t132 c 4 INT 9 10 10 0 1 NULL
+ t132 d 4 INT 9 10 10 0 1 NULL
+ t132 e 4 INT 9 10 10 0 1 NULL
+ t133 a 4 INT 9 10 10 0 1 NULL
+ t133 b 4 INT 9 10 10 0 1 NULL
+ t133 c 4 INT 9 10 10 0 1 NULL
+ t133 d 4 INT 9 10 10 0 1 NULL
+ t133 e 4 INT 9 10 10 0 1 NULL
+ t134 a 4 INT 9 10 10 0 1 NULL
+ t134 b 4 INT 9 10 10 0 1 NULL
+ t134 c 4 INT 9 10 10 0 1 NULL
+ t134 d 4 INT 9 10 10 0 1 NULL
+ t134 e 4 INT 9 10 10 0 1 NULL
+ t135 a 4 INT 9 10 10 0 1 NULL
+ t135 b 4 INT 9 10 10 0 1 NULL
+ t135 c 4 INT 9 10 10 0 1 NULL
+ t135 d 4 INT 9 10 10 0 1 NULL
+ t135 e 4 INT 9 10 10 0 1 NULL
+ t136 a 4 INT 9 10 10 0 1 NULL
+ t136 b 4 INT 9 10 10 0 1 NULL
+ t136 c 4 INT 9 10 10 0 1 NULL
+ t136 d 4 INT 9 10 10 0 1 NULL
+ t136 e 4 INT 9 10 10 0 1 NULL
+ t137 a 4 INT 9 10 10 0 1 NULL
+ t137 b 4 INT 9 10 10 0 1 NULL
+ t137 c 4 INT 9 10 10 0 1 NULL
+ t137 d 4 INT 9 10 10 0 1 NULL
+ t137 e 4 INT 9 10 10 0 1 NULL
+ t138 a 4 INT 9 10 10 0 1 NULL
+ t138 b 4 INT 9 10 10 0 1 NULL
+ t138 c 4 INT 9 10 10 0 1 NULL
+ t138 d 4 INT 9 10 10 0 1 NULL
+ t138 e 4 INT 9 10 10 0 1 NULL
+ t139 a 4 INT 9 10 10 0 1 NULL
+ t139 b 4 INT 9 10 10 0 1 NULL
+ t139 c 4 INT 9 10 10 0 1 NULL
+ t139 d 4 INT 9 10 10 0 1 NULL
+ t139 e 4 INT 9 10 10 0 1 NULL
+ t140 a 4 INT 9 10 10 0 1 NULL
+ t140 b 4 INT 9 10 10 0 1 NULL
+ t140 c 4 INT 9 10 10 0 1 NULL
+ t140 d 4 INT 9 10 10 0 1 NULL
+ t140 e 4 INT 9 10 10 0 1 NULL
+ t141 a 4 INT 9 10 10 0 1 NULL
+ t141 b 4 INT 9 10 10 0 1 NULL
+ t141 c 4 INT 9 10 10 0 1 NULL
+ t141 d 4 INT 9 10 10 0 1 NULL
+ t141 e 4 INT 9 10 10 0 1 NULL
+ t142 a 4 INT 9 10 10 0 1 NULL
+ t142 b 4 INT 9 10 10 0 1 NULL
+ t142 c 4 INT 9 10 10 0 1 NULL
+ t142 d 4 INT 9 10 10 0 1 NULL
+ t142 e 4 INT 9 10 10 0 1 NULL
+ t143 a 4 INT 9 10 10 0 1 NULL
+ t143 b 4 INT 9 10 10 0 1 NULL
+ t143 c 4 INT 9 10 10 0 1 NULL
+ t143 d 4 INT 9 10 10 0 1 NULL
+ t143 e 4 INT 9 10 10 0 1 NULL
+ t144 a 4 INT 9 10 10 0 1 NULL
+ t144 b 4 INT 9 10 10 0 1 NULL
+ t144 c 4 INT 9 10 10 0 1 NULL
+ t144 d 4 INT 9 10 10 0 1 NULL
+ t144 e 4 INT 9 10 10 0 1 NULL
+ t145 a 4 INT 9 10 10 0 1 NULL
+ t145 b 4 INT 9 10 10 0 1 NULL
+ t145 c 4 INT 9 10 10 0 1 NULL
+ t145 d 4 INT 9 10 10 0 1 NULL
+ t145 e 4 INT 9 10 10 0 1 NULL
+ t146 a 4 INT 9 10 10 0 1 NULL
+ t146 b 4 INT 9 10 10 0 1 NULL
+ t146 c 4 INT 9 10 10 0 1 NULL
+ t146 d 4 INT 9 10 10 0 1 NULL
+ t146 e 4 INT 9 10 10 0 1 NULL
+ t147 a 4 INT 9 10 10 0 1 NULL
+ t147 b 4 INT 9 10 10 0 1 NULL
+ t147 c 4 INT 9 10 10 0 1 NULL
+ t147 d 4 INT 9 10 10 0 1 NULL
+ t147 e 4 INT 9 10 10 0 1 NULL
+ t148 a 4 INT 9 10 10 0 1 NULL
+ t148 b 4 INT 9 10 10 0 1 NULL
+ t148 c 4 INT 9 10 10 0 1 NULL
+ t148 d 4 INT 9 10 10 0 1 NULL
+ t148 e 4 INT 9 10 10 0 1 NULL
+ t149 a 4 INT 9 10 10 0 1 NULL
+ t149 b 4 INT 9 10 10 0 1 NULL
+ t149 c 4 INT 9 10 10 0 1 NULL
+ t149 d 4 INT 9 10 10 0 1 NULL
+ t149 e 4 INT 9 10 10 0 1 NULL
+ t150 a 4 INT 9 10 10 0 1 NULL
+ t150 b 4 INT 9 10 10 0 1 NULL
+ t150 c 4 INT 9 10 10 0 1 NULL
+ t150 d 4 INT 9 10 10 0 1 NULL
+ t150 e 4 INT 9 10 10 0 1 NULL
+ t151 a 4 INT 9 10 10 0 1 NULL
+ t151 b 4 INT 9 10 10 0 1 NULL
+ t151 c 4 INT 9 10 10 0 1 NULL
+ t151 d 4 INT 9 10 10 0 1 NULL
+ t151 e 4 INT 9 10 10 0 1 NULL
+ t152 a 4 INT 9 10 10 0 1 NULL
+ t152 b 4 INT 9 10 10 0 1 NULL
+ t152 c 4 INT 9 10 10 0 1 NULL
+ t152 d 4 INT 9 10 10 0 1 NULL
+ t152 e 4 INT 9 10 10 0 1 NULL
+ t153 a 4 INT 9 10 10 0 1 NULL
+ t153 b 4 INT 9 10 10 0 1 NULL
+ t153 c 4 INT 9 10 10 0 1 NULL
+ t153 d 4 INT 9 10 10 0 1 NULL
+ t153 e 4 INT 9 10 10 0 1 NULL
+ t154 a 4 INT 9 10 10 0 1 NULL
+ t154 b 4 INT 9 10 10 0 1 NULL
+ t154 c 4 INT 9 10 10 0 1 NULL
+ t154 d 4 INT 9 10 10 0 1 NULL
+ t154 e 4 INT 9 10 10 0 1 NULL
+ t155 a 4 INT 9 10 10 0 1 NULL
+ t155 b 4 INT 9 10 10 0 1 NULL
+ t155 c 4 INT 9 10 10 0 1 NULL
+ t155 d 4 INT 9 10 10 0 1 NULL
+ t155 e 4 INT 9 10 10 0 1 NULL
+ t156 a 4 INT 9 10 10 0 1 NULL
+ t156 b 4 INT 9 10 10 0 1 NULL
+ t156 c 4 INT 9 10 10 0 1 NULL
+ t156 d 4 INT 9 10 10 0 1 NULL
+ t156 e 4 INT 9 10 10 0 1 NULL
+ t157 a 4 INT 9 10 10 0 1 NULL
+ t157 b 4 INT 9 10 10 0 1 NULL
+ t157 c 4 INT 9 10 10 0 1 NULL
+ t157 d 4 INT 9 10 10 0 1 NULL
+ t157 e 4 INT 9 10 10 0 1 NULL
+ t158 a 4 INT 9 10 10 0 1 NULL
+ t158 b 4 INT 9 10 10 0 1 NULL
+ t158 c 4 INT 9 10 10 0 1 NULL
+ t158 d 4 INT 9 10 10 0 1 NULL
+ t158 e 4 INT 9 10 10 0 1 NULL
+ t159 a 4 INT 9 10 10 0 1 NULL
+ t159 b 4 INT 9 10 10 0 1 NULL
+ t159 c 4 INT 9 10 10 0 1 NULL
+ t159 d 4 INT 9 10 10 0 1 NULL
+ t159 e 4 INT 9 10 10 0 1 NULL
+ t160 a 4 INT 9 10 10 0 1 NULL
+ t160 b 4 INT 9 10 10 0 1 NULL
+ t160 c 4 INT 9 10 10 0 1 NULL
+ t160 d 4 INT 9 10 10 0 1 NULL
+ t160 e 4 INT 9 10 10 0 1 NULL
+ t161 a 4 INT 9 10 10 0 1 NULL
+ t161 b 4 INT 9 10 10 0 1 NULL
+ t161 c 4 INT 9 10 10 0 1 NULL
+ t161 d 4 INT 9 10 10 0 1 NULL
+ t161 e 4 INT 9 10 10 0 1 NULL
+ t162 a 4 INT 9 10 10 0 1 NULL
+ t162 b 4 INT 9 10 10 0 1 NULL
+ t162 c 4 INT 9 10 10 0 1 NULL
+ t162 d 4 INT 9 10 10 0 1 NULL
+ t162 e 4 INT 9 10 10 0 1 NULL
+ t163 a 4 INT 9 10 10 0 1 NULL
+ t163 b 4 INT 9 10 10 0 1 NULL
+ t163 c 4 INT 9 10 10 0 1 NULL
+ t163 d 4 INT 9 10 10 0 1 NULL
+ t163 e 4 INT 9 10 10 0 1 NULL
+ t164 a 4 INT 9 10 10 0 1 NULL
+ t164 b 4 INT 9 10 10 0 1 NULL
+ t164 c 4 INT 9 10 10 0 1 NULL
+ t164 d 4 INT 9 10 10 0 1 NULL
+ t164 e 4 INT 9 10 10 0 1 NULL
+ t165 a 4 INT 9 10 10 0 1 NULL
+ t165 b 4 INT 9 10 10 0 1 NULL
+ t165 c 4 INT 9 10 10 0 1 NULL
+ t165 d 4 INT 9 10 10 0 1 NULL
+ t165 e 4 INT 9 10 10 0 1 NULL
+ t166 a 4 INT 9 10 10 0 1 NULL
+ t166 b 4 INT 9 10 10 0 1 NULL
+ t166 c 4 INT 9 10 10 0 1 NULL
+ t166 d 4 INT 9 10 10 0 1 NULL
+ t166 e 4 INT 9 10 10 0 1 NULL
+ t167 a 4 INT 9 10 10 0 1 NULL
+ t167 b 4 INT 9 10 10 0 1 NULL
+ t167 c 4 INT 9 10 10 0 1 NULL
+ t167 d 4 INT 9 10 10 0 1 NULL
+ t167 e 4 INT 9 10 10 0 1 NULL
+ t168 a 4 INT 9 10 10 0 1 NULL
+ t168 b 4 INT 9 10 10 0 1 NULL
+ t168 c 4 INT 9 10 10 0 1 NULL
+ t168 d 4 INT 9 10 10 0 1 NULL
+ t168 e 4 INT 9 10 10 0 1 NULL
+ t169 a 4 INT 9 10 10 0 1 NULL
+ t169 b 4 INT 9 10 10 0 1 NULL
+ t169 c 4 INT 9 10 10 0 1 NULL
+ t169 d 4 INT 9 10 10 0 1 NULL
+ t169 e 4 INT 9 10 10 0 1 NULL
+ t170 a 4 INT 9 10 10 0 1 NULL
+ t170 b 4 INT 9 10 10 0 1 NULL
+ t170 c 4 INT 9 10 10 0 1 NULL
+ t170 d 4 INT 9 10 10 0 1 NULL
+ t170 e 4 INT 9 10 10 0 1 NULL
+ t171 a 4 INT 9 10 10 0 1 NULL
+ t171 b 4 INT 9 10 10 0 1 NULL
+ t171 c 4 INT 9 10 10 0 1 NULL
+ t171 d 4 INT 9 10 10 0 1 NULL
+ t171 e 4 INT 9 10 10 0 1 NULL
+ t172 a 4 INT 9 10 10 0 1 NULL
+ t172 b 4 INT 9 10 10 0 1 NULL
+ t172 c 4 INT 9 10 10 0 1 NULL
+ t172 d 4 INT 9 10 10 0 1 NULL
+ t172 e 4 INT 9 10 10 0 1 NULL
+ t173 a 4 INT 9 10 10 0 1 NULL
+ t173 b 4 INT 9 10 10 0 1 NULL
+ t173 c 4 INT 9 10 10 0 1 NULL
+ t173 d 4 INT 9 10 10 0 1 NULL
+ t173 e 4 INT 9 10 10 0 1 NULL
+ t174 a 4 INT 9 10 10 0 1 NULL
+ t174 b 4 INT 9 10 10 0 1 NULL
+ t174 c 4 INT 9 10 10 0 1 NULL
+ t174 d 4 INT 9 10 10 0 1 NULL
+ t174 e 4 INT 9 10 10 0 1 NULL
+ t175 a 4 INT 9 10 10 0 1 NULL
+ t175 b 4 INT 9 10 10 0 1 NULL
+ t175 c 4 INT 9 10 10 0 1 NULL
+ t175 d 4 INT 9 10 10 0 1 NULL
+ t175 e 4 INT 9 10 10 0 1 NULL
+ t176 a 4 INT 9 10 10 0 1 NULL
+ t176 b 4 INT 9 10 10 0 1 NULL
+ t176 c 4 INT 9 10 10 0 1 NULL
+ t176 d 4 INT 9 10 10 0 1 NULL
+ t176 e 4 INT 9 10 10 0 1 NULL
+ t177 a 4 INT 9 10 10 0 1 NULL
+ t177 b 4 INT 9 10 10 0 1 NULL
+ t177 c 4 INT 9 10 10 0 1 NULL
+ t177 d 4 INT 9 10 10 0 1 NULL
+ t177 e 4 INT 9 10 10 0 1 NULL
+ t178 a 4 INT 9 10 10 0 1 NULL
+ t178 b 4 INT 9 10 10 0 1 NULL
+ t178 c 4 INT 9 10 10 0 1 NULL
+ t178 d 4 INT 9 10 10 0 1 NULL
+ t178 e 4 INT 9 10 10 0 1 NULL
+ t179 a 4 INT 9 10 10 0 1 NULL
+ t179 b 4 INT 9 10 10 0 1 NULL
+ t179 c 4 INT 9 10 10 0 1 NULL
+ t179 d 4 INT 9 10 10 0 1 NULL
+ t179 e 4 INT 9 10 10 0 1 NULL
+ t180 a 4 INT 9 10 10 0 1 NULL
+ t180 b 4 INT 9 10 10 0 1 NULL
+ t180 c 4 INT 9 10 10 0 1 NULL
+ t180 d 4 INT 9 10 10 0 1 NULL
+ t180 e 4 INT 9 10 10 0 1 NULL
+ t181 a 4 INT 9 10 10 0 1 NULL
+ t181 b 4 INT 9 10 10 0 1 NULL
+ t181 c 4 INT 9 10 10 0 1 NULL
+ t181 d 4 INT 9 10 10 0 1 NULL
+ t181 e 4 INT 9 10 10 0 1 NULL
+ t182 a 4 INT 9 10 10 0 1 NULL
+ t182 b 4 INT 9 10 10 0 1 NULL
+ t182 c 4 INT 9 10 10 0 1 NULL
+ t182 d 4 INT 9 10 10 0 1 NULL
+ t182 e 4 INT 9 10 10 0 1 NULL
+ t183 a 4 INT 9 10 10 0 1 NULL
+ t183 b 4 INT 9 10 10 0 1 NULL
+ t183 c 4 INT 9 10 10 0 1 NULL
+ t183 d 4 INT 9 10 10 0 1 NULL
+ t183 e 4 INT 9 10 10 0 1 NULL
+ t184 a 4 INT 9 10 10 0 1 NULL
+ t184 b 4 INT 9 10 10 0 1 NULL
+ t184 c 4 INT 9 10 10 0 1 NULL
+ t184 d 4 INT 9 10 10 0 1 NULL
+ t184 e 4 INT 9 10 10 0 1 NULL
+ t185 a 4 INT 9 10 10 0 1 NULL
+ t185 b 4 INT 9 10 10 0 1 NULL
+ t185 c 4 INT 9 10 10 0 1 NULL
+ t185 d 4 INT 9 10 10 0 1 NULL
+ t185 e 4 INT 9 10 10 0 1 NULL
+ t186 a 4 INT 9 10 10 0 1 NULL
+ t186 b 4 INT 9 10 10 0 1 NULL
+ t186 c 4 INT 9 10 10 0 1 NULL
+ t186 d 4 INT 9 10 10 0 1 NULL
+ t186 e 4 INT 9 10 10 0 1 NULL
+ t187 a 4 INT 9 10 10 0 1 NULL
+ t187 b 4 INT 9 10 10 0 1 NULL
+ t187 c 4 INT 9 10 10 0 1 NULL
+ t187 d 4 INT 9 10 10 0 1 NULL
+ t187 e 4 INT 9 10 10 0 1 NULL
+ t188 a 4 INT 9 10 10 0 1 NULL
+ t188 b 4 INT 9 10 10 0 1 NULL
+ t188 c 4 INT 9 10 10 0 1 NULL
+ t188 d 4 INT 9 10 10 0 1 NULL
+ t188 e 4 INT 9 10 10 0 1 NULL
+ t189 a 4 INT 9 10 10 0 1 NULL
+ t189 b 4 INT 9 10 10 0 1 NULL
+ t189 c 4 INT 9 10 10 0 1 NULL
+ t189 d 4 INT 9 10 10 0 1 NULL
+ t189 e 4 INT 9 10 10 0 1 NULL
+ t190 a 4 INT 9 10 10 0 1 NULL
+ t190 b 4 INT 9 10 10 0 1 NULL
+ t190 c 4 INT 9 10 10 0 1 NULL
+ t190 d 4 INT 9 10 10 0 1 NULL
+ t190 e 4 INT 9 10 10 0 1 NULL
+ t191 a 4 INT 9 10 10 0 1 NULL
+ t191 b 4 INT 9 10 10 0 1 NULL
+ t191 c 4 INT 9 10 10 0 1 NULL
+ t191 d 4 INT 9 10 10 0 1 NULL
+ t191 e 4 INT 9 10 10 0 1 NULL
+ t192 a 4 INT 9 10 10 0 1 NULL
+ t192 b 4 INT 9 10 10 0 1 NULL
+ t192 c 4 INT 9 10 10 0 1 NULL
+ t192 d 4 INT 9 10 10 0 1 NULL
+ t192 e 4 INT 9 10 10 0 1 NULL
+ t193 a 4 INT 9 10 10 0 1 NULL
+ t193 b 4 INT 9 10 10 0 1 NULL
+ t193 c 4 INT 9 10 10 0 1 NULL
+ t193 d 4 INT 9 10 10 0 1 NULL
+ t193 e 4 INT 9 10 10 0 1 NULL
+ t194 a 4 INT 9 10 10 0 1 NULL
+ t194 b 4 INT 9 10 10 0 1 NULL
+ t194 c 4 INT 9 10 10 0 1 NULL
+ t194 d 4 INT 9 10 10 0 1 NULL
+ t194 e 4 INT 9 10 10 0 1 NULL
+ t195 a 4 INT 9 10 10 0 1 NULL
+ t195 b 4 INT 9 10 10 0 1 NULL
+ t195 c 4 INT 9 10 10 0 1 NULL
+ t195 d 4 INT 9 10 10 0 1 NULL
+ t195 e 4 INT 9 10 10 0 1 NULL
+ t196 a 4 INT 9 10 10 0 1 NULL
+ t196 b 4 INT 9 10 10 0 1 NULL
+ t196 c 4 INT 9 10 10 0 1 NULL
+ t196 d 4 INT 9 10 10 0 1 NULL
+ t196 e 4 INT 9 10 10 0 1 NULL
+ t197 a 4 INT 9 10 10 0 1 NULL
+ t197 b 4 INT 9 10 10 0 1 NULL
+ t197 c 4 INT 9 10 10 0 1 NULL
+ t197 d 4 INT 9 10 10 0 1 NULL
+ t197 e 4 INT 9 10 10 0 1 NULL
+ t198 a 4 INT 9 10 10 0 1 NULL
+ t198 b 4 INT 9 10 10 0 1 NULL
+ t198 c 4 INT 9 10 10 0 1 NULL
+ t198 d 4 INT 9 10 10 0 1 NULL
+ t198 e 4 INT 9 10 10 0 1 NULL
+ t199 a 4 INT 9 10 10 0 1 NULL
+ t199 b 4 INT 9 10 10 0 1 NULL
+ t199 c 4 INT 9 10 10 0 1 NULL
+ t199 d 4 INT 9 10 10 0 1 NULL
+ t199 e 4 INT 9 10 10 0 1 NULL
+ t200 a 4 INT 9 10 10 0 1 NULL
+ t200 b 4 INT 9 10 10 0 1 NULL
+ t200 c 4 INT 9 10 10 0 1 NULL
+ t200 d 4 INT 9 10 10 0 1 NULL
+ t200 e 4 INT 9 10 10 0 1 NULL
+ t201 a 4 INT 9 10 10 0 1 NULL
+ t201 b 4 INT 9 10 10 0 1 NULL
+ t201 c 4 INT 9 10 10 0 1 NULL
+ t201 d 4 INT 9 10 10 0 1 NULL
+ t201 e 4 INT 9 10 10 0 1 NULL
+ t202 a 4 INT 9 10 10 0 1 NULL
+ t202 b 4 INT 9 10 10 0 1 NULL
+ t202 c 4 INT 9 10 10 0 1 NULL
+ t202 d 4 INT 9 10 10 0 1 NULL
+ t202 e 4 INT 9 10 10 0 1 NULL
+ t203 a 4 INT 9 10 10 0 1 NULL
+ t203 b 4 INT 9 10 10 0 1 NULL
+ t203 c 4 INT 9 10 10 0 1 NULL
+ t203 d 4 INT 9 10 10 0 1 NULL
+ t203 e 4 INT 9 10 10 0 1 NULL
+ t204 a 4 INT 9 10 10 0 1 NULL
+ t204 b 4 INT 9 10 10 0 1 NULL
+ t204 c 4 INT 9 10 10 0 1 NULL
+ t204 d 4 INT 9 10 10 0 1 NULL
+ t204 e 4 INT 9 10 10 0 1 NULL
+ t205 a 4 INT 9 10 10 0 1 NULL
+ t205 b 4 INT 9 10 10 0 1 NULL
+ t205 c 4 INT 9 10 10 0 1 NULL
+ t205 d 4 INT 9 10 10 0 1 NULL
+ t205 e 4 INT 9 10 10 0 1 NULL
+ t206 a 4 INT 9 10 10 0 1 NULL
+ t206 b 4 INT 9 10 10 0 1 NULL
+ t206 c 4 INT 9 10 10 0 1 NULL
+ t206 d 4 INT 9 10 10 0 1 NULL
+ t206 e 4 INT 9 10 10 0 1 NULL
+ t207 a 4 INT 9 10 10 0 1 NULL
+ t207 b 4 INT 9 10 10 0 1 NULL
+ t207 c 4 INT 9 10 10 0 1 NULL
+ t207 d 4 INT 9 10 10 0 1 NULL
+ t207 e 4 INT 9 10 10 0 1 NULL
+ t208 a 4 INT 9 10 10 0 1 NULL
+ t208 b 4 INT 9 10 10 0 1 NULL
+ t208 c 4 INT 9 10 10 0 1 NULL
+ t208 d 4 INT 9 10 10 0 1 NULL
+ t208 e 4 INT 9 10 10 0 1 NULL
+ t209 a 4 INT 9 10 10 0 1 NULL
+ t209 b 4 INT 9 10 10 0 1 NULL
+ t209 c 4 INT 9 10 10 0 1 NULL
+ t209 d 4 INT 9 10 10 0 1 NULL
+ t209 e 4 INT 9 10 10 0 1 NULL
+ t210 a 4 INT 9 10 10 0 1 NULL
+ t210 b 4 INT 9 10 10 0 1 NULL
+ t210 c 4 INT 9 10 10 0 1 NULL
+ t210 d 4 INT 9 10 10 0 1 NULL
+ t210 e 4 INT 9 10 10 0 1 NULL
+ t211 a 4 INT 9 10 10 0 1 NULL
+ t211 b 4 INT 9 10 10 0 1 NULL
+ t211 c 4 INT 9 10 10 0 1 NULL
+ t211 d 4 INT 9 10 10 0 1 NULL
+ t211 e 4 INT 9 10 10 0 1 NULL
+ t212 a 4 INT 9 10 10 0 1 NULL
+ t212 b 4 INT 9 10 10 0 1 NULL
+ t212 c 4 INT 9 10 10 0 1 NULL
+ t212 d 4 INT 9 10 10 0 1 NULL
+ t212 e 4 INT 9 10 10 0 1 NULL
+ t213 a 4 INT 9 10 10 0 1 NULL
+ t213 b 4 INT 9 10 10 0 1 NULL
+ t213 c 4 INT 9 10 10 0 1 NULL
+ t213 d 4 INT 9 10 10 0 1 NULL
+ t213 e 4 INT 9 10 10 0 1 NULL
+ t214 a 4 INT 9 10 10 0 1 NULL
+ t214 b 4 INT 9 10 10 0 1 NULL
+ t214 c 4 INT 9 10 10 0 1 NULL
+ t214 d 4 INT 9 10 10 0 1 NULL
+ t214 e 4 INT 9 10 10 0 1 NULL
+ t215 a 4 INT 9 10 10 0 1 NULL
+ t215 b 4 INT 9 10 10 0 1 NULL
+ t215 c 4 INT 9 10 10 0 1 NULL
+ t215 d 4 INT 9 10 10 0 1 NULL
+ t215 e 4 INT 9 10 10 0 1 NULL
+ t216 a 4 INT 9 10 10 0 1 NULL
+ t216 b 4 INT 9 10 10 0 1 NULL
+ t216 c 4 INT 9 10 10 0 1 NULL
+ t216 d 4 INT 9 10 10 0 1 NULL
+ t216 e 4 INT 9 10 10 0 1 NULL
+ t217 a 4 INT 9 10 10 0 1 NULL
+ t217 b 4 INT 9 10 10 0 1 NULL
+ t217 c 4 INT 9 10 10 0 1 NULL
+ t217 d 4 INT 9 10 10 0 1 NULL
+ t217 e 4 INT 9 10 10 0 1 NULL
+ t218 a 4 INT 9 10 10 0 1 NULL
+ t218 b 4 INT 9 10 10 0 1 NULL
+ t218 c 4 INT 9 10 10 0 1 NULL
+ t218 d 4 INT 9 10 10 0 1 NULL
+ t218 e 4 INT 9 10 10 0 1 NULL
+ t219 a 4 INT 9 10 10 0 1 NULL
+ t219 b 4 INT 9 10 10 0 1 NULL
+ t219 c 4 INT 9 10 10 0 1 NULL
+ t219 d 4 INT 9 10 10 0 1 NULL
+ t219 e 4 INT 9 10 10 0 1 NULL
+ t220 a 4 INT 9 10 10 0 1 NULL
+ t220 b 4 INT 9 10 10 0 1 NULL
+ t220 c 4 INT 9 10 10 0 1 NULL
+ t220 d 4 INT 9 10 10 0 1 NULL
+ t220 e 4 INT 9 10 10 0 1 NULL
+ t221 a 4 INT 9 10 10 0 1 NULL
+ t221 b 4 INT 9 10 10 0 1 NULL
+ t221 c 4 INT 9 10 10 0 1 NULL
+ t221 d 4 INT 9 10 10 0 1 NULL
+ t221 e 4 INT 9 10 10 0 1 NULL
+ t222 a 4 INT 9 10 10 0 1 NULL
+ t222 b 4 INT 9 10 10 0 1 NULL
+ t222 c 4 INT 9 10 10 0 1 NULL
+ t222 d 4 INT 9 10 10 0 1 NULL
+ t222 e 4 INT 9 10 10 0 1 NULL
+ t223 a 4 INT 9 10 10 0 1 NULL
+ t223 b 4 INT 9 10 10 0 1 NULL
+ t223 c 4 INT 9 10 10 0 1 NULL
+ t223 d 4 INT 9 10 10 0 1 NULL
+ t223 e 4 INT 9 10 10 0 1 NULL
+ t224 a 4 INT 9 10 10 0 1 NULL
+ t224 b 4 INT 9 10 10 0 1 NULL
+ t224 c 4 INT 9 10 10 0 1 NULL
+ t224 d 4 INT 9 10 10 0 1 NULL
+ t224 e 4 INT 9 10 10 0 1 NULL
+ t225 a 4 INT 9 10 10 0 1 NULL
+ t225 b 4 INT 9 10 10 0 1 NULL
+ t225 c 4 INT 9 10 10 0 1 NULL
+ t225 d 4 INT 9 10 10 0 1 NULL
+ t225 e 4 INT 9 10 10 0 1 NULL
+ t226 a 4 INT 9 10 10 0 1 NULL
+ t226 b 4 INT 9 10 10 0 1 NULL
+ t226 c 4 INT 9 10 10 0 1 NULL
+ t226 d 4 INT 9 10 10 0 1 NULL
+ t226 e 4 INT 9 10 10 0 1 NULL
+ t227 a 4 INT 9 10 10 0 1 NULL
+ t227 b 4 INT 9 10 10 0 1 NULL
+ t227 c 4 INT 9 10 10 0 1 NULL
+ t227 d 4 INT 9 10 10 0 1 NULL
+ t227 e 4 INT 9 10 10 0 1 NULL
+ t228 a 4 INT 9 10 10 0 1 NULL
+ t228 b 4 INT 9 10 10 0 1 NULL
+ t228 c 4 INT 9 10 10 0 1 NULL
+ t228 d 4 INT 9 10 10 0 1 NULL
+ t228 e 4 INT 9 10 10 0 1 NULL
+ t229 a 4 INT 9 10 10 0 1 NULL
+ t229 b 4 INT 9 10 10 0 1 NULL
+ t229 c 4 INT 9 10 10 0 1 NULL
+ t229 d 4 INT 9 10 10 0 1 NULL
+ t229 e 4 INT 9 10 10 0 1 NULL
+ t230 a 4 INT 9 10 10 0 1 NULL
+ t230 b 4 INT 9 10 10 0 1 NULL
+ t230 c 4 INT 9 10 10 0 1 NULL
+ t230 d 4 INT 9 10 10 0 1 NULL
+ t230 e 4 INT 9 10 10 0 1 NULL
+ t231 a 4 INT 9 10 10 0 1 NULL
+ t231 b 4 INT 9 10 10 0 1 NULL
+ t231 c 4 INT 9 10 10 0 1 NULL
+ t231 d 4 INT 9 10 10 0 1 NULL
+ t231 e 4 INT 9 10 10 0 1 NULL
+ t232 a 4 INT 9 10 10 0 1 NULL
+ t232 b 4 INT 9 10 10 0 1 NULL
+ t232 c 4 INT 9 10 10 0 1 NULL
+ t232 d 4 INT 9 10 10 0 1 NULL
+ t232 e 4 INT 9 10 10 0 1 NULL
+ t233 a 4 INT 9 10 10 0 1 NULL
+ t233 b 4 INT 9 10 10 0 1 NULL
+ t233 c 4 INT 9 10 10 0 1 NULL
+ t233 d 4 INT 9 10 10 0 1 NULL
+ t233 e 4 INT 9 10 10 0 1 NULL
+ t234 a 4 INT 9 10 10 0 1 NULL
+ t234 b 4 INT 9 10 10 0 1 NULL
+ t234 c 4 INT 9 10 10 0 1 NULL
+ t234 d 4 INT 9 10 10 0 1 NULL
+ t234 e 4 INT 9 10 10 0 1 NULL
+ t235 a 4 INT 9 10 10 0 1 NULL
+ t235 b 4 INT 9 10 10 0 1 NULL
+ t235 c 4 INT 9 10 10 0 1 NULL
+ t235 d 4 INT 9 10 10 0 1 NULL
+ t235 e 4 INT 9 10 10 0 1 NULL
+ t236 a 4 INT 9 10 10 0 1 NULL
+ t236 b 4 INT 9 10 10 0 1 NULL
+ t236 c 4 INT 9 10 10 0 1 NULL
+ t236 d 4 INT 9 10 10 0 1 NULL
+ t236 e 4 INT 9 10 10 0 1 NULL
+ t237 a 4 INT 9 10 10 0 1 NULL
+ t237 b 4 INT 9 10 10 0 1 NULL
+ t237 c 4 INT 9 10 10 0 1 NULL
+ t237 d 4 INT 9 10 10 0 1 NULL
+ t237 e 4 INT 9 10 10 0 1 NULL
+ t238 a 4 INT 9 10 10 0 1 NULL
+ t238 b 4 INT 9 10 10 0 1 NULL
+ t238 c 4 INT 9 10 10 0 1 NULL
+ t238 d 4 INT 9 10 10 0 1 NULL
+ t238 e 4 INT 9 10 10 0 1 NULL
+ t239 a 4 INT 9 10 10 0 1 NULL
+ t239 b 4 INT 9 10 10 0 1 NULL
+ t239 c 4 INT 9 10 10 0 1 NULL
+ t239 d 4 INT 9 10 10 0 1 NULL
+ t239 e 4 INT 9 10 10 0 1 NULL
+ t240 a 4 INT 9 10 10 0 1 NULL
+ t240 b 4 INT 9 10 10 0 1 NULL
+ t240 c 4 INT 9 10 10 0 1 NULL
+ t240 d 4 INT 9 10 10 0 1 NULL
+ t240 e 4 INT 9 10 10 0 1 NULL
+ t241 a 4 INT 9 10 10 0 1 NULL
+ t241 b 4 INT 9 10 10 0 1 NULL
+ t241 c 4 INT 9 10 10 0 1 NULL
+ t241 d 4 INT 9 10 10 0 1 NULL
+ t241 e 4 INT 9 10 10 0 1 NULL
+ t242 a 4 INT 9 10 10 0 1 NULL
+ t242 b 4 INT 9 10 10 0 1 NULL
+ t242 c 4 INT 9 10 10 0 1 NULL
+ t242 d 4 INT 9 10 10 0 1 NULL
+ t242 e 4 INT 9 10 10 0 1 NULL
+ t243 a 4 INT 9 10 10 0 1 NULL
+ t243 b 4 INT 9 10 10 0 1 NULL
+ t243 c 4 INT 9 10 10 0 1 NULL
+ t243 d 4 INT 9 10 10 0 1 NULL
+ t243 e 4 INT 9 10 10 0 1 NULL
+ t244 a 4 INT 9 10 10 0 1 NULL
+ t244 b 4 INT 9 10 10 0 1 NULL
+ t244 c 4 INT 9 10 10 0 1 NULL
+ t244 d 4 INT 9 10 10 0 1 NULL
+ t244 e 4 INT 9 10 10 0 1 NULL
+ t245 a 4 INT 9 10 10 0 1 NULL
+ t245 b 4 INT 9 10 10 0 1 NULL
+ t245 c 4 INT 9 10 10 0 1 NULL
+ t245 d 4 INT 9 10 10 0 1 NULL
+ t245 e 4 INT 9 10 10 0 1 NULL
+ t246 a 4 INT 9 10 10 0 1 NULL
+ t246 b 4 INT 9 10 10 0 1 NULL
+ t246 c 4 INT 9 10 10 0 1 NULL
+ t246 d 4 INT 9 10 10 0 1 NULL
+ t246 e 4 INT 9 10 10 0 1 NULL
+ t247 a 4 INT 9 10 10 0 1 NULL
+ t247 b 4 INT 9 10 10 0 1 NULL
+ t247 c 4 INT 9 10 10 0 1 NULL
+ t247 d 4 INT 9 10 10 0 1 NULL
+ t247 e 4 INT 9 10 10 0 1 NULL
+ t248 a 4 INT 9 10 10 0 1 NULL
+ t248 b 4 INT 9 10 10 0 1 NULL
+ t248 c 4 INT 9 10 10 0 1 NULL
+ t248 d 4 INT 9 10 10 0 1 NULL
+ t248 e 4 INT 9 10 10 0 1 NULL
+ t249 a 4 INT 9 10 10 0 1 NULL
+ t249 b 4 INT 9 10 10 0 1 NULL
+ t249 c 4 INT 9 10 10 0 1 NULL
+ t249 d 4 INT 9 10 10 0 1 NULL
+ t249 e 4 INT 9 10 10 0 1 NULL
+ t250 a 4 INT 9 10 10 0 1 NULL
+ t250 b 4 INT 9 10 10 0 1 NULL
+ t250 c 4 INT 9 10 10 0 1 NULL
+ t250 d 4 INT 9 10 10 0 1 NULL
+ t250 e 4 INT 9 10 10 0 1 NULL
+ t251 a 4 INT 9 10 10 0 1 NULL
+ t251 b 4 INT 9 10 10 0 1 NULL
+ t251 c 4 INT 9 10 10 0 1 NULL
+ t251 d 4 INT 9 10 10 0 1 NULL
+ t251 e 4 INT 9 10 10 0 1 NULL
+ t252 a 4 INT 9 10 10 0 1 NULL
+ t252 b 4 INT 9 10 10 0 1 NULL
+ t252 c 4 INT 9 10 10 0 1 NULL
+ t252 d 4 INT 9 10 10 0 1 NULL
+ t252 e 4 INT 9 10 10 0 1 NULL
+ t253 a 4 INT 9 10 10 0 1 NULL
+ t253 b 4 INT 9 10 10 0 1 NULL
+ t253 c 4 INT 9 10 10 0 1 NULL
+ t253 d 4 INT 9 10 10 0 1 NULL
+ t253 e 4 INT 9 10 10 0 1 NULL
+ t254 a 4 INT 9 10 10 0 1 NULL
+ t254 b 4 INT 9 10 10 0 1 NULL
+ t254 c 4 INT 9 10 10 0 1 NULL
+ t254 d 4 INT 9 10 10 0 1 NULL
+ t254 e 4 INT 9 10 10 0 1 NULL
+ t255 a 4 INT 9 10 10 0 1 NULL
+ t255 b 4 INT 9 10 10 0 1 NULL
+ t255 c 4 INT 9 10 10 0 1 NULL
+ t255 d 4 INT 9 10 10 0 1 NULL
+ t255 e 4 INT 9 10 10 0 1 NULL
+ t256 a 4 INT 9 10 10 0 1 NULL
+ t256 b 4 INT 9 10 10 0 1 NULL
+ t256 c 4 INT 9 10 10 0 1 NULL
+ t256 d 4 INT 9 10 10 0 1 NULL
+ t256 e 4 INT 9 10 10 0 1 NULL
+ t257 a 4 INT 9 10 10 0 1 NULL
+ t257 b 4 INT 9 10 10 0 1 NULL
+ t257 c 4 INT 9 10 10 0 1 NULL
+ t257 d 4 INT 9 10 10 0 1 NULL
+ t257 e 4 INT 9 10 10 0 1 NULL
+ t258 a 4 INT 9 10 10 0 1 NULL
+ t258 b 4 INT 9 10 10 0 1 NULL
+ t258 c 4 INT 9 10 10 0 1 NULL
+ t258 d 4 INT 9 10 10 0 1 NULL
+ t258 e 4 INT 9 10 10 0 1 NULL
+ t259 a 4 INT 9 10 10 0 1 NULL
+ t259 b 4 INT 9 10 10 0 1 NULL
+ t259 c 4 INT 9 10 10 0 1 NULL
+ t259 d 4 INT 9 10 10 0 1 NULL
+ t259 e 4 INT 9 10 10 0 1 NULL
+ t260 a 4 INT 9 10 10 0 1 NULL
+ t260 b 4 INT 9 10 10 0 1 NULL
+ t260 c 4 INT 9 10 10 0 1 NULL
+ t260 d 4 INT 9 10 10 0 1 NULL
+ t260 e 4 INT 9 10 10 0 1 NULL
+ t261 a 4 INT 9 10 10 0 1 NULL
+ t261 b 4 INT 9 10 10 0 1 NULL
+ t261 c 4 INT 9 10 10 0 1 NULL
+ t261 d 4 INT 9 10 10 0 1 NULL
+ t261 e 4 INT 9 10 10 0 1 NULL
+ t262 a 4 INT 9 10 10 0 1 NULL
+ t262 b 4 INT 9 10 10 0 1 NULL
+ t262 c 4 INT 9 10 10 0 1 NULL
+ t262 d 4 INT 9 10 10 0 1 NULL
+ t262 e 4 INT 9 10 10 0 1 NULL
+ t263 a 4 INT 9 10 10 0 1 NULL
+ t263 b 4 INT 9 10 10 0 1 NULL
+ t263 c 4 INT 9 10 10 0 1 NULL
+ t263 d 4 INT 9 10 10 0 1 NULL
+ t263 e 4 INT 9 10 10 0 1 NULL
+ t264 a 4 INT 9 10 10 0 1 NULL
+ t264 b 4 INT 9 10 10 0 1 NULL
+ t264 c 4 INT 9 10 10 0 1 NULL
+ t264 d 4 INT 9 10 10 0 1 NULL
+ t264 e 4 INT 9 10 10 0 1 NULL
+ t265 a 4 INT 9 10 10 0 1 NULL
+ t265 b 4 INT 9 10 10 0 1 NULL
+ t265 c 4 INT 9 10 10 0 1 NULL
+ t265 d 4 INT 9 10 10 0 1 NULL
+ t265 e 4 INT 9 10 10 0 1 NULL
+ t266 a 4 INT 9 10 10 0 1 NULL
+ t266 b 4 INT 9 10 10 0 1 NULL
+ t266 c 4 INT 9 10 10 0 1 NULL
+ t266 d 4 INT 9 10 10 0 1 NULL
+ t266 e 4 INT 9 10 10 0 1 NULL
+ t267 a 4 INT 9 10 10 0 1 NULL
+ t267 b 4 INT 9 10 10 0 1 NULL
+ t267 c 4 INT 9 10 10 0 1 NULL
+ t267 d 4 INT 9 10 10 0 1 NULL
+ t267 e 4 INT 9 10 10 0 1 NULL
+ t268 a 4 INT 9 10 10 0 1 NULL
+ t268 b 4 INT 9 10 10 0 1 NULL
+ t268 c 4 INT 9 10 10 0 1 NULL
+ t268 d 4 INT 9 10 10 0 1 NULL
+ t268 e 4 INT 9 10 10 0 1 NULL
+ t269 a 4 INT 9 10 10 0 1 NULL
+ t269 b 4 INT 9 10 10 0 1 NULL
+ t269 c 4 INT 9 10 10 0 1 NULL
+ t269 d 4 INT 9 10 10 0 1 NULL
+ t269 e 4 INT 9 10 10 0 1 NULL
+ t270 a 4 INT 9 10 10 0 1 NULL
+ t270 b 4 INT 9 10 10 0 1 NULL
+ t270 c 4 INT 9 10 10 0 1 NULL
+ t270 d 4 INT 9 10 10 0 1 NULL
+ t270 e 4 INT 9 10 10 0 1 NULL
+ t271 a 4 INT 9 10 10 0 1 NULL
+ t271 b 4 INT 9 10 10 0 1 NULL
+ t271 c 4 INT 9 10 10 0 1 NULL
+ t271 d 4 INT 9 10 10 0 1 NULL
+ t271 e 4 INT 9 10 10 0 1 NULL
+ t272 a 4 INT 9 10 10 0 1 NULL
+ t272 b 4 INT 9 10 10 0 1 NULL
+ t272 c 4 INT 9 10 10 0 1 NULL
+ t272 d 4 INT 9 10 10 0 1 NULL
+ t272 e 4 INT 9 10 10 0 1 NULL
+ t273 a 4 INT 9 10 10 0 1 NULL
+ t273 b 4 INT 9 10 10 0 1 NULL
+ t273 c 4 INT 9 10 10 0 1 NULL
+ t273 d 4 INT 9 10 10 0 1 NULL
+ t273 e 4 INT 9 10 10 0 1 NULL
+ t274 a 4 INT 9 10 10 0 1 NULL
+ t274 b 4 INT 9 10 10 0 1 NULL
+ t274 c 4 INT 9 10 10 0 1 NULL
+ t274 d 4 INT 9 10 10 0 1 NULL
+ t274 e 4 INT 9 10 10 0 1 NULL
+ t275 a 4 INT 9 10 10 0 1 NULL
+ t275 b 4 INT 9 10 10 0 1 NULL
+ t275 c 4 INT 9 10 10 0 1 NULL
+ t275 d 4 INT 9 10 10 0 1 NULL
+ t275 e 4 INT 9 10 10 0 1 NULL
+ t276 a 4 INT 9 10 10 0 1 NULL
+ t276 b 4 INT 9 10 10 0 1 NULL
+ t276 c 4 INT 9 10 10 0 1 NULL
+ t276 d 4 INT 9 10 10 0 1 NULL
+ t276 e 4 INT 9 10 10 0 1 NULL
+ t277 a 4 INT 9 10 10 0 1 NULL
+ t277 b 4 INT 9 10 10 0 1 NULL
+ t277 c 4 INT 9 10 10 0 1 NULL
+ t277 d 4 INT 9 10 10 0 1 NULL
+ t277 e 4 INT 9 10 10 0 1 NULL
+ t278 a 4 INT 9 10 10 0 1 NULL
+ t278 b 4 INT 9 10 10 0 1 NULL
+ t278 c 4 INT 9 10 10 0 1 NULL
+ t278 d 4 INT 9 10 10 0 1 NULL
+ t278 e 4 INT 9 10 10 0 1 NULL
+ t279 a 4 INT 9 10 10 0 1 NULL
+ t279 b 4 INT 9 10 10 0 1 NULL
+ t279 c 4 INT 9 10 10 0 1 NULL
+ t279 d 4 INT 9 10 10 0 1 NULL
+ t279 e 4 INT 9 10 10 0 1 NULL
+ t280 a 4 INT 9 10 10 0 1 NULL
+ t280 b 4 INT 9 10 10 0 1 NULL
+ t280 c 4 INT 9 10 10 0 1 NULL
+ t280 d 4 INT 9 10 10 0 1 NULL
+ t280 e 4 INT 9 10 10 0 1 NULL
+ t281 a 4 INT 9 10 10 0 1 NULL
+ t281 b 4 INT 9 10 10 0 1 NULL
+ t281 c 4 INT 9 10 10 0 1 NULL
+ t281 d 4 INT 9 10 10 0 1 NULL
+ t281 e 4 INT 9 10 10 0 1 NULL
+ t282 a 4 INT 9 10 10 0 1 NULL
+ t282 b 4 INT 9 10 10 0 1 NULL
+ t282 c 4 INT 9 10 10 0 1 NULL
+ t282 d 4 INT 9 10 10 0 1 NULL
+ t282 e 4 INT 9 10 10 0 1 NULL
+ t283 a 4 INT 9 10 10 0 1 NULL
+ t283 b 4 INT 9 10 10 0 1 NULL
+ t283 c 4 INT 9 10 10 0 1 NULL
+ t283 d 4 INT 9 10 10 0 1 NULL
+ t283 e 4 INT 9 10 10 0 1 NULL
+ t284 a 4 INT 9 10 10 0 1 NULL
+ t284 b 4 INT 9 10 10 0 1 NULL
+ t284 c 4 INT 9 10 10 0 1 NULL
+ t284 d 4 INT 9 10 10 0 1 NULL
+ t284 e 4 INT 9 10 10 0 1 NULL
+ t285 a 4 INT 9 10 10 0 1 NULL
+ t285 b 4 INT 9 10 10 0 1 NULL
+ t285 c 4 INT 9 10 10 0 1 NULL
+ t285 d 4 INT 9 10 10 0 1 NULL
+ t285 e 4 INT 9 10 10 0 1 NULL
+ t286 a 4 INT 9 10 10 0 1 NULL
+ t286 b 4 INT 9 10 10 0 1 NULL
+ t286 c 4 INT 9 10 10 0 1 NULL
+ t286 d 4 INT 9 10 10 0 1 NULL
+ t286 e 4 INT 9 10 10 0 1 NULL
+ t287 a 4 INT 9 10 10 0 1 NULL
+ t287 b 4 INT 9 10 10 0 1 NULL
+ t287 c 4 INT 9 10 10 0 1 NULL
+ t287 d 4 INT 9 10 10 0 1 NULL
+ t287 e 4 INT 9 10 10 0 1 NULL
+ t288 a 4 INT 9 10 10 0 1 NULL
+ t288 b 4 INT 9 10 10 0 1 NULL
+ t288 c 4 INT 9 10 10 0 1 NULL
+ t288 d 4 INT 9 10 10 0 1 NULL
+ t288 e 4 INT 9 10 10 0 1 NULL
+ t289 a 4 INT 9 10 10 0 1 NULL
+ t289 b 4 INT 9 10 10 0 1 NULL
+ t289 c 4 INT 9 10 10 0 1 NULL
+ t289 d 4 INT 9 10 10 0 1 NULL
+ t289 e 4 INT 9 10 10 0 1 NULL
+ t290 a 4 INT 9 10 10 0 1 NULL
+ t290 b 4 INT 9 10 10 0 1 NULL
+ t290 c 4 INT 9 10 10 0 1 NULL
+ t290 d 4 INT 9 10 10 0 1 NULL
+ t290 e 4 INT 9 10 10 0 1 NULL
+ t291 a 4 INT 9 10 10 0 1 NULL
+ t291 b 4 INT 9 10 10 0 1 NULL
+ t291 c 4 INT 9 10 10 0 1 NULL
+ t291 d 4 INT 9 10 10 0 1 NULL
+ t291 e 4 INT 9 10 10 0 1 NULL
+ t292 a 4 INT 9 10 10 0 1 NULL
+ t292 b 4 INT 9 10 10 0 1 NULL
+ t292 c 4 INT 9 10 10 0 1 NULL
+ t292 d 4 INT 9 10 10 0 1 NULL
+ t292 e 4 INT 9 10 10 0 1 NULL
+ t293 a 4 INT 9 10 10 0 1 NULL
+ t293 b 4 INT 9 10 10 0 1 NULL
+ t293 c 4 INT 9 10 10 0 1 NULL
+ t293 d 4 INT 9 10 10 0 1 NULL
+ t293 e 4 INT 9 10 10 0 1 NULL
+ t294 a 4 INT 9 10 10 0 1 NULL
+ t294 b 4 INT 9 10 10 0 1 NULL
+ t294 c 4 INT 9 10 10 0 1 NULL
+ t294 d 4 INT 9 10 10 0 1 NULL
+ t294 e 4 INT 9 10 10 0 1 NULL
+ t295 a 4 INT 9 10 10 0 1 NULL
+ t295 b 4 INT 9 10 10 0 1 NULL
+ t295 c 4 INT 9 10 10 0 1 NULL
+ t295 d 4 INT 9 10 10 0 1 NULL
+ t295 e 4 INT 9 10 10 0 1 NULL
+ t296 a 4 INT 9 10 10 0 1 NULL
+ t296 b 4 INT 9 10 10 0 1 NULL
+ t296 c 4 INT 9 10 10 0 1 NULL
+ t296 d 4 INT 9 10 10 0 1 NULL
+ t296 e 4 INT 9 10 10 0 1 NULL
+ t297 a 4 INT 9 10 10 0 1 NULL
+ t297 b 4 INT 9 10 10 0 1 NULL
+ t297 c 4 INT 9 10 10 0 1 NULL
+ t297 d 4 INT 9 10 10 0 1 NULL
+ t297 e 4 INT 9 10 10 0 1 NULL
+ t298 a 4 INT 9 10 10 0 1 NULL
+ t298 b 4 INT 9 10 10 0 1 NULL
+ t298 c 4 INT 9 10 10 0 1 NULL
+ t298 d 4 INT 9 10 10 0 1 NULL
+ t298 e 4 INT 9 10 10 0 1 NULL
+ t299 a 4 INT 9 10 10 0 1 NULL
+ t299 b 4 INT 9 10 10 0 1 NULL
+ t299 c 4 INT 9 10 10 0 1 NULL
+ t299 d 4 INT 9 10 10 0 1 NULL
+ t299 e 4 INT 9 10 10 0 1 NULL
+ t300 a 4 INT 9 10 10 0 1 NULL
+ t300 b 4 INT 9 10 10 0 1 NULL
+ t300 c 4 INT 9 10 10 0 1 NULL
+ t300 d 4 INT 9 10 10 0 1 NULL
+ t300 e 4 INT 9 10 10 0 1 NULL
+ t301 a 4 INT 9 10 10 0 1 NULL
+ t301 b 4 INT 9 10 10 0 1 NULL
+ t301 c 4 INT 9 10 10 0 1 NULL
+ t301 d 4 INT 9 10 10 0 1 NULL
+ t301 e 4 INT 9 10 10 0 1 NULL
+ t302 a 4 INT 9 10 10 0 1 NULL
+ t302 b 4 INT 9 10 10 0 1 NULL
+ t302 c 4 INT 9 10 10 0 1 NULL
+ t302 d 4 INT 9 10 10 0 1 NULL
+ t302 e 4 INT 9 10 10 0 1 NULL
+ t303 a 4 INT 9 10 10 0 1 NULL
+ t303 b 4 INT 9 10 10 0 1 NULL
+ t303 c 4 INT 9 10 10 0 1 NULL
+ t303 d 4 INT 9 10 10 0 1 NULL
+ t303 e 4 INT 9 10 10 0 1 NULL
+ t304 a 4 INT 9 10 10 0 1 NULL
+ t304 b 4 INT 9 10 10 0 1 NULL
+ t304 c 4 INT 9 10 10 0 1 NULL
+ t304 d 4 INT 9 10 10 0 1 NULL
+ t304 e 4 INT 9 10 10 0 1 NULL
+ t305 a 4 INT 9 10 10 0 1 NULL
+ t305 b 4 INT 9 10 10 0 1 NULL
+ t305 c 4 INT 9 10 10 0 1 NULL
+ t305 d 4 INT 9 10 10 0 1 NULL
+ t305 e 4 INT 9 10 10 0 1 NULL
+ t306 a 4 INT 9 10 10 0 1 NULL
+ t306 b 4 INT 9 10 10 0 1 NULL
+ t306 c 4 INT 9 10 10 0 1 NULL
+ t306 d 4 INT 9 10 10 0 1 NULL
+ t306 e 4 INT 9 10 10 0 1 NULL
+ t307 a 4 INT 9 10 10 0 1 NULL
+ t307 b 4 INT 9 10 10 0 1 NULL
+ t307 c 4 INT 9 10 10 0 1 NULL
+ t307 d 4 INT 9 10 10 0 1 NULL
+ t307 e 4 INT 9 10 10 0 1 NULL
+ t308 a 4 INT 9 10 10 0 1 NULL
+ t308 b 4 INT 9 10 10 0 1 NULL
+ t308 c 4 INT 9 10 10 0 1 NULL
+ t308 d 4 INT 9 10 10 0 1 NULL
+ t308 e 4 INT 9 10 10 0 1 NULL
+ t309 a 4 INT 9 10 10 0 1 NULL
+ t309 b 4 INT 9 10 10 0 1 NULL
+ t309 c 4 INT 9 10 10 0 1 NULL
+ t309 d 4 INT 9 10 10 0 1 NULL
+ t309 e 4 INT 9 10 10 0 1 NULL
+ t310 a 4 INT 9 10 10 0 1 NULL
+ t310 b 4 INT 9 10 10 0 1 NULL
+ t310 c 4 INT 9 10 10 0 1 NULL
+ t310 d 4 INT 9 10 10 0 1 NULL
+ t310 e 4 INT 9 10 10 0 1 NULL
+ t311 a 4 INT 9 10 10 0 1 NULL
+ t311 b 4 INT 9 10 10 0 1 NULL
+ t311 c 4 INT 9 10 10 0 1 NULL
+ t311 d 4 INT 9 10 10 0 1 NULL
+ t311 e 4 INT 9 10 10 0 1 NULL
+ t312 a 4 INT 9 10 10 0 1 NULL
+ t312 b 4 INT 9 10 10 0 1 NULL
+ t312 c 4 INT 9 10 10 0 1 NULL
+ t312 d 4 INT 9 10 10 0 1 NULL
+ t312 e 4 INT 9 10 10 0 1 NULL
+ t313 a 4 INT 9 10 10 0 1 NULL
+ t313 b 4 INT 9 10 10 0 1 NULL
+ t313 c 4 INT 9 10 10 0 1 NULL
+ t313 d 4 INT 9 10 10 0 1 NULL
+ t313 e 4 INT 9 10 10 0 1 NULL
+ t314 a 4 INT 9 10 10 0 1 NULL
+ t314 b 4 INT 9 10 10 0 1 NULL
+ t314 c 4 INT 9 10 10 0 1 NULL
+ t314 d 4 INT 9 10 10 0 1 NULL
+ t314 e 4 INT 9 10 10 0 1 NULL
+ t315 a 4 INT 9 10 10 0 1 NULL
+ t315 b 4 INT 9 10 10 0 1 NULL
+ t315 c 4 INT 9 10 10 0 1 NULL
+ t315 d 4 INT 9 10 10 0 1 NULL
+ t315 e 4 INT 9 10 10 0 1 NULL
+ t316 a 4 INT 9 10 10 0 1 NULL
+ t316 b 4 INT 9 10 10 0 1 NULL
+ t316 c 4 INT 9 10 10 0 1 NULL
+ t316 d 4 INT 9 10 10 0 1 NULL
+ t316 e 4 INT 9 10 10 0 1 NULL
+ t317 a 4 INT 9 10 10 0 1 NULL
+ t317 b 4 INT 9 10 10 0 1 NULL
+ t317 c 4 INT 9 10 10 0 1 NULL
+ t317 d 4 INT 9 10 10 0 1 NULL
+ t317 e 4 INT 9 10 10 0 1 NULL
+ t318 a 4 INT 9 10 10 0 1 NULL
+ t318 b 4 INT 9 10 10 0 1 NULL
+ t318 c 4 INT 9 10 10 0 1 NULL
+ t318 d 4 INT 9 10 10 0 1 NULL
+ t318 e 4 INT 9 10 10 0 1 NULL
+ t319 a 4 INT 9 10 10 0 1 NULL
+ t319 b 4 INT 9 10 10 0 1 NULL
+ t319 c 4 INT 9 10 10 0 1 NULL
+ t319 d 4 INT 9 10 10 0 1 NULL
+ t319 e 4 INT 9 10 10 0 1 NULL
+ t320 a 4 INT 9 10 10 0 1 NULL
+ t320 b 4 INT 9 10 10 0 1 NULL
+ t320 c 4 INT 9 10 10 0 1 NULL
+ t320 d 4 INT 9 10 10 0 1 NULL
+ t320 e 4 INT 9 10 10 0 1 NULL
+ t321 a 4 INT 9 10 10 0 1 NULL
+ t321 b 4 INT 9 10 10 0 1 NULL
+ t321 c 4 INT 9 10 10 0 1 NULL
+ t321 d 4 INT 9 10 10 0 1 NULL
+ t321 e 4 INT 9 10 10 0 1 NULL
+ t322 a 4 INT 9 10 10 0 1 NULL
+ t322 b 4 INT 9 10 10 0 1 NULL
+ t322 c 4 INT 9 10 10 0 1 NULL
+ t322 d 4 INT 9 10 10 0 1 NULL
+ t322 e 4 INT 9 10 10 0 1 NULL
+ t323 a 4 INT 9 10 10 0 1 NULL
+ t323 b 4 INT 9 10 10 0 1 NULL
+ t323 c 4 INT 9 10 10 0 1 NULL
+ t323 d 4 INT 9 10 10 0 1 NULL
+ t323 e 4 INT 9 10 10 0 1 NULL
+ t324 a 4 INT 9 10 10 0 1 NULL
+ t324 b 4 INT 9 10 10 0 1 NULL
+ t324 c 4 INT 9 10 10 0 1 NULL
+ t324 d 4 INT 9 10 10 0 1 NULL
+ t324 e 4 INT 9 10 10 0 1 NULL
+ t325 a 4 INT 9 10 10 0 1 NULL
+ t325 b 4 INT 9 10 10 0 1 NULL
+ t325 c 4 INT 9 10 10 0 1 NULL
+ t325 d 4 INT 9 10 10 0 1 NULL
+ t325 e 4 INT 9 10 10 0 1 NULL
+ t326 a 4 INT 9 10 10 0 1 NULL
+ t326 b 4 INT 9 10 10 0 1 NULL
+ t326 c 4 INT 9 10 10 0 1 NULL
+ t326 d 4 INT 9 10 10 0 1 NULL
+ t326 e 4 INT 9 10 10 0 1 NULL
+ t327 a 4 INT 9 10 10 0 1 NULL
+ t327 b 4 INT 9 10 10 0 1 NULL
+ t327 c 4 INT 9 10 10 0 1 NULL
+ t327 d 4 INT 9 10 10 0 1 NULL
+ t327 e 4 INT 9 10 10 0 1 NULL
+ t328 a 4 INT 9 10 10 0 1 NULL
+ t328 b 4 INT 9 10 10 0 1 NULL
+ t328 c 4 INT 9 10 10 0 1 NULL
+ t328 d 4 INT 9 10 10 0 1 NULL
+ t328 e 4 INT 9 10 10 0 1 NULL
+ t329 a 4 INT 9 10 10 0 1 NULL
+ t329 b 4 INT 9 10 10 0 1 NULL
+ t329 c 4 INT 9 10 10 0 1 NULL
+ t329 d 4 INT 9 10 10 0 1 NULL
+ t329 e 4 INT 9 10 10 0 1 NULL
+ t330 a 4 INT 9 10 10 0 1 NULL
+ t330 b 4 INT 9 10 10 0 1 NULL
+ t330 c 4 INT 9 10 10 0 1 NULL
+ t330 d 4 INT 9 10 10 0 1 NULL
+ t330 e 4 INT 9 10 10 0 1 NULL
+ t331 a 4 INT 9 10 10 0 1 NULL
+ t331 b 4 INT 9 10 10 0 1 NULL
+ t331 c 4 INT 9 10 10 0 1 NULL
+ t331 d 4 INT 9 10 10 0 1 NULL
+ t331 e 4 INT 9 10 10 0 1 NULL
+ t332 a 4 INT 9 10 10 0 1 NULL
+ t332 b 4 INT 9 10 10 0 1 NULL
+ t332 c 4 INT 9 10 10 0 1 NULL
+ t332 d 4 INT 9 10 10 0 1 NULL
+ t332 e 4 INT 9 10 10 0 1 NULL
+ t333 a 4 INT 9 10 10 0 1 NULL
+ t333 b 4 INT 9 10 10 0 1 NULL
+ t333 c 4 INT 9 10 10 0 1 NULL
+ t333 d 4 INT 9 10 10 0 1 NULL
+ t333 e 4 INT 9 10 10 0 1 NULL
+ t334 a 4 INT 9 10 10 0 1 NULL
+ t334 b 4 INT 9 10 10 0 1 NULL
+ t334 c 4 INT 9 10 10 0 1 NULL
+ t334 d 4 INT 9 10 10 0 1 NULL
+ t334 e 4 INT 9 10 10 0 1 NULL
+ t335 a 4 INT 9 10 10 0 1 NULL
+ t335 b 4 INT 9 10 10 0 1 NULL
+ t335 c 4 INT 9 10 10 0 1 NULL
+ t335 d 4 INT 9 10 10 0 1 NULL
+ t335 e 4 INT 9 10 10 0 1 NULL
+ t336 a 4 INT 9 10 10 0 1 NULL
+ t336 b 4 INT 9 10 10 0 1 NULL
+ t336 c 4 INT 9 10 10 0 1 NULL
+ t336 d 4 INT 9 10 10 0 1 NULL
+ t336 e 4 INT 9 10 10 0 1 NULL
+ t337 a 4 INT 9 10 10 0 1 NULL
+ t337 b 4 INT 9 10 10 0 1 NULL
+ t337 c 4 INT 9 10 10 0 1 NULL
+ t337 d 4 INT 9 10 10 0 1 NULL
+ t337 e 4 INT 9 10 10 0 1 NULL
+ t338 a 4 INT 9 10 10 0 1 NULL
+ t338 b 4 INT 9 10 10 0 1 NULL
+ t338 c 4 INT 9 10 10 0 1 NULL
+ t338 d 4 INT 9 10 10 0 1 NULL
+ t338 e 4 INT 9 10 10 0 1 NULL
+ t339 a 4 INT 9 10 10 0 1 NULL
+ t339 b 4 INT 9 10 10 0 1 NULL
+ t339 c 4 INT 9 10 10 0 1 NULL
+ t339 d 4 INT 9 10 10 0 1 NULL
+ t339 e 4 INT 9 10 10 0 1 NULL
+ t340 a 4 INT 9 10 10 0 1 NULL
+ t340 b 4 INT 9 10 10 0 1 NULL
+ t340 c 4 INT 9 10 10 0 1 NULL
+ t340 d 4 INT 9 10 10 0 1 NULL
+ t340 e 4 INT 9 10 10 0 1 NULL
+ t341 a 4 INT 9 10 10 0 1 NULL
+ t341 b 4 INT 9 10 10 0 1 NULL
+ t341 c 4 INT 9 10 10 0 1 NULL
+ t341 d 4 INT 9 10 10 0 1 NULL
+ t341 e 4 INT 9 10 10 0 1 NULL
+ t342 a 4 INT 9 10 10 0 1 NULL
+ t342 b 4 INT 9 10 10 0 1 NULL
+ t342 c 4 INT 9 10 10 0 1 NULL
+ t342 d 4 INT 9 10 10 0 1 NULL
+ t342 e 4 INT 9 10 10 0 1 NULL
+ t343 a 4 INT 9 10 10 0 1 NULL
+ t343 b 4 INT 9 10 10 0 1 NULL
+ t343 c 4 INT 9 10 10 0 1 NULL
+ t343 d 4 INT 9 10 10 0 1 NULL
+ t343 e 4 INT 9 10 10 0 1 NULL
+ t344 a 4 INT 9 10 10 0 1 NULL
+ t344 b 4 INT 9 10 10 0 1 NULL
+ t344 c 4 INT 9 10 10 0 1 NULL
+ t344 d 4 INT 9 10 10 0 1 NULL
+ t344 e 4 INT 9 10 10 0 1 NULL
+ t345 a 4 INT 9 10 10 0 1 NULL
+ t345 b 4 INT 9 10 10 0 1 NULL
+ t345 c 4 INT 9 10 10 0 1 NULL
+ t345 d 4 INT 9 10 10 0 1 NULL
+ t345 e 4 INT 9 10 10 0 1 NULL
+ t346 a 4 INT 9 10 10 0 1 NULL
+ t346 b 4 INT 9 10 10 0 1 NULL
+ t346 c 4 INT 9 10 10 0 1 NULL
+ t346 d 4 INT 9 10 10 0 1 NULL
+ t346 e 4 INT 9 10 10 0 1 NULL
+ t347 a 4 INT 9 10 10 0 1 NULL
+ t347 b 4 INT 9 10 10 0 1 NULL
+ t347 c 4 INT 9 10 10 0 1 NULL
+ t347 d 4 INT 9 10 10 0 1 NULL
+ t347 e 4 INT 9 10 10 0 1 NULL
+ t348 a 4 INT 9 10 10 0 1 NULL
+ t348 b 4 INT 9 10 10 0 1 NULL
+ t348 c 4 INT 9 10 10 0 1 NULL
+ t348 d 4 INT 9 10 10 0 1 NULL
+ t348 e 4 INT 9 10 10 0 1 NULL
+ t349 a 4 INT 9 10 10 0 1 NULL
+ t349 b 4 INT 9 10 10 0 1 NULL
+ t349 c 4 INT 9 10 10 0 1 NULL
+ t349 d 4 INT 9 10 10 0 1 NULL
+ t349 e 4 INT 9 10 10 0 1 NULL
+ t350 a 4 INT 9 10 10 0 1 NULL
+ t350 b 4 INT 9 10 10 0 1 NULL
+ t350 c 4 INT 9 10 10 0 1 NULL
+ t350 d 4 INT 9 10 10 0 1 NULL
+ t350 e 4 INT 9 10 10 0 1 NULL
+ t351 a 4 INT 9 10 10 0 1 NULL
+ t351 b 4 INT 9 10 10 0 1 NULL
+ t351 c 4 INT 9 10 10 0 1 NULL
+ t351 d 4 INT 9 10 10 0 1 NULL
+ t351 e 4 INT 9 10 10 0 1 NULL
+ t352 a 4 INT 9 10 10 0 1 NULL
+ t352 b 4 INT 9 10 10 0 1 NULL
+ t352 c 4 INT 9 10 10 0 1 NULL
+ t352 d 4 INT 9 10 10 0 1 NULL
+ t352 e 4 INT 9 10 10 0 1 NULL
+ t353 a 4 INT 9 10 10 0 1 NULL
+ t353 b 4 INT 9 10 10 0 1 NULL
+ t353 c 4 INT 9 10 10 0 1 NULL
+ t353 d 4 INT 9 10 10 0 1 NULL
+ t353 e 4 INT 9 10 10 0 1 NULL
+ t354 a 4 INT 9 10 10 0 1 NULL
+ t354 b 4 INT 9 10 10 0 1 NULL
+ t354 c 4 INT 9 10 10 0 1 NULL
+ t354 d 4 INT 9 10 10 0 1 NULL
+ t354 e 4 INT 9 10 10 0 1 NULL
+ t355 a 4 INT 9 10 10 0 1 NULL
+ t355 b 4 INT 9 10 10 0 1 NULL
+ t355 c 4 INT 9 10 10 0 1 NULL
+ t355 d 4 INT 9 10 10 0 1 NULL
+ t355 e 4 INT 9 10 10 0 1 NULL
+ t356 a 4 INT 9 10 10 0 1 NULL
+ t356 b 4 INT 9 10 10 0 1 NULL
+ t356 c 4 INT 9 10 10 0 1 NULL
+ t356 d 4 INT 9 10 10 0 1 NULL
+ t356 e 4 INT 9 10 10 0 1 NULL
+ t357 a 4 INT 9 10 10 0 1 NULL
+ t357 b 4 INT 9 10 10 0 1 NULL
+ t357 c 4 INT 9 10 10 0 1 NULL
+ t357 d 4 INT 9 10 10 0 1 NULL
+ t357 e 4 INT 9 10 10 0 1 NULL
+ t358 a 4 INT 9 10 10 0 1 NULL
+ t358 b 4 INT 9 10 10 0 1 NULL
+ t358 c 4 INT 9 10 10 0 1 NULL
+ t358 d 4 INT 9 10 10 0 1 NULL
+ t358 e 4 INT 9 10 10 0 1 NULL
+ t359 a 4 INT 9 10 10 0 1 NULL
+ t359 b 4 INT 9 10 10 0 1 NULL
+ t359 c 4 INT 9 10 10 0 1 NULL
+ t359 d 4 INT 9 10 10 0 1 NULL
+ t359 e 4 INT 9 10 10 0 1 NULL
+ t360 a 4 INT 9 10 10 0 1 NULL
+ t360 b 4 INT 9 10 10 0 1 NULL
+ t360 c 4 INT 9 10 10 0 1 NULL
+ t360 d 4 INT 9 10 10 0 1 NULL
+ t360 e 4 INT 9 10 10 0 1 NULL
+ t361 a 4 INT 9 10 10 0 1 NULL
+ t361 b 4 INT 9 10 10 0 1 NULL
+ t361 c 4 INT 9 10 10 0 1 NULL
+ t361 d 4 INT 9 10 10 0 1 NULL
+ t361 e 4 INT 9 10 10 0 1 NULL
+ t362 a 4 INT 9 10 10 0 1 NULL
+ t362 b 4 INT 9 10 10 0 1 NULL
+ t362 c 4 INT 9 10 10 0 1 NULL
+ t362 d 4 INT 9 10 10 0 1 NULL
+ t362 e 4 INT 9 10 10 0 1 NULL
+ t363 a 4 INT 9 10 10 0 1 NULL
+ t363 b 4 INT 9 10 10 0 1 NULL
+ t363 c 4 INT 9 10 10 0 1 NULL
+ t363 d 4 INT 9 10 10 0 1 NULL
+ t363 e 4 INT 9 10 10 0 1 NULL
+ t364 a 4 INT 9 10 10 0 1 NULL
+ t364 b 4 INT 9 10 10 0 1 NULL
+ t364 c 4 INT 9 10 10 0 1 NULL
+ t364 d 4 INT 9 10 10 0 1 NULL
+ t364 e 4 INT 9 10 10 0 1 NULL
+ t365 a 4 INT 9 10 10 0 1 NULL
+ t365 b 4 INT 9 10 10 0 1 NULL
+ t365 c 4 INT 9 10 10 0 1 NULL
+ t365 d 4 INT 9 10 10 0 1 NULL
+ t365 e 4 INT 9 10 10 0 1 NULL
+ t366 a 4 INT 9 10 10 0 1 NULL
+ t366 b 4 INT 9 10 10 0 1 NULL
+ t366 c 4 INT 9 10 10 0 1 NULL
+ t366 d 4 INT 9 10 10 0 1 NULL
+ t366 e 4 INT 9 10 10 0 1 NULL
+ t367 a 4 INT 9 10 10 0 1 NULL
+ t367 b 4 INT 9 10 10 0 1 NULL
+ t367 c 4 INT 9 10 10 0 1 NULL
+ t367 d 4 INT 9 10 10 0 1 NULL
+ t367 e 4 INT 9 10 10 0 1 NULL
+ t368 a 4 INT 9 10 10 0 1 NULL
+ t368 b 4 INT 9 10 10 0 1 NULL
+ t368 c 4 INT 9 10 10 0 1 NULL
+ t368 d 4 INT 9 10 10 0 1 NULL
+ t368 e 4 INT 9 10 10 0 1 NULL
+ t369 a 4 INT 9 10 10 0 1 NULL
+ t369 b 4 INT 9 10 10 0 1 NULL
+ t369 c 4 INT 9 10 10 0 1 NULL
+ t369 d 4 INT 9 10 10 0 1 NULL
+ t369 e 4 INT 9 10 10 0 1 NULL
+ t370 a 4 INT 9 10 10 0 1 NULL
+ t370 b 4 INT 9 10 10 0 1 NULL
+ t370 c 4 INT 9 10 10 0 1 NULL
+ t370 d 4 INT 9 10 10 0 1 NULL
+ t370 e 4 INT 9 10 10 0 1 NULL
+ t371 a 4 INT 9 10 10 0 1 NULL
+ t371 b 4 INT 9 10 10 0 1 NULL
+ t371 c 4 INT 9 10 10 0 1 NULL
+ t371 d 4 INT 9 10 10 0 1 NULL
+ t371 e 4 INT 9 10 10 0 1 NULL
+ t372 a 4 INT 9 10 10 0 1 NULL
+ t372 b 4 INT 9 10 10 0 1 NULL
+ t372 c 4 INT 9 10 10 0 1 NULL
+ t372 d 4 INT 9 10 10 0 1 NULL
+ t372 e 4 INT 9 10 10 0 1 NULL
+ t373 a 4 INT 9 10 10 0 1 NULL
+ t373 b 4 INT 9 10 10 0 1 NULL
+ t373 c 4 INT 9 10 10 0 1 NULL
+ t373 d 4 INT 9 10 10 0 1 NULL
+ t373 e 4 INT 9 10 10 0 1 NULL
+ t374 a 4 INT 9 10 10 0 1 NULL
+ t374 b 4 INT 9 10 10 0 1 NULL
+ t374 c 4 INT 9 10 10 0 1 NULL
+ t374 d 4 INT 9 10 10 0 1 NULL
+ t374 e 4 INT 9 10 10 0 1 NULL
+ t375 a 4 INT 9 10 10 0 1 NULL
+ t375 b 4 INT 9 10 10 0 1 NULL
+ t375 c 4 INT 9 10 10 0 1 NULL
+ t375 d 4 INT 9 10 10 0 1 NULL
+ t375 e 4 INT 9 10 10 0 1 NULL
+ t376 a 4 INT 9 10 10 0 1 NULL
+ t376 b 4 INT 9 10 10 0 1 NULL
+ t376 c 4 INT 9 10 10 0 1 NULL
+ t376 d 4 INT 9 10 10 0 1 NULL
+ t376 e 4 INT 9 10 10 0 1 NULL
+ t377 a 4 INT 9 10 10 0 1 NULL
+ t377 b 4 INT 9 10 10 0 1 NULL
+ t377 c 4 INT 9 10 10 0 1 NULL
+ t377 d 4 INT 9 10 10 0 1 NULL
+ t377 e 4 INT 9 10 10 0 1 NULL
+ t378 a 4 INT 9 10 10 0 1 NULL
+ t378 b 4 INT 9 10 10 0 1 NULL
+ t378 c 4 INT 9 10 10 0 1 NULL
+ t378 d 4 INT 9 10 10 0 1 NULL
+ t378 e 4 INT 9 10 10 0 1 NULL
+ t379 a 4 INT 9 10 10 0 1 NULL
+ t379 b 4 INT 9 10 10 0 1 NULL
+ t379 c 4 INT 9 10 10 0 1 NULL
+ t379 d 4 INT 9 10 10 0 1 NULL
+ t379 e 4 INT 9 10 10 0 1 NULL
+ t380 a 4 INT 9 10 10 0 1 NULL
+ t380 b 4 INT 9 10 10 0 1 NULL
+ t380 c 4 INT 9 10 10 0 1 NULL
+ t380 d 4 INT 9 10 10 0 1 NULL
+ t380 e 4 INT 9 10 10 0 1 NULL
+ t381 a 4 INT 9 10 10 0 1 NULL
+ t381 b 4 INT 9 10 10 0 1 NULL
+ t381 c 4 INT 9 10 10 0 1 NULL
+ t381 d 4 INT 9 10 10 0 1 NULL
+ t381 e 4 INT 9 10 10 0 1 NULL
+ t382 a 4 INT 9 10 10 0 1 NULL
+ t382 b 4 INT 9 10 10 0 1 NULL
+ t382 c 4 INT 9 10 10 0 1 NULL
+ t382 d 4 INT 9 10 10 0 1 NULL
+ t382 e 4 INT 9 10 10 0 1 NULL
+ t383 a 4 INT 9 10 10 0 1 NULL
+ t383 b 4 INT 9 10 10 0 1 NULL
+ t383 c 4 INT 9 10 10 0 1 NULL
+ t383 d 4 INT 9 10 10 0 1 NULL
+ t383 e 4 INT 9 10 10 0 1 NULL
+ t384 a 4 INT 9 10 10 0 1 NULL
+ t384 b 4 INT 9 10 10 0 1 NULL
+ t384 c 4 INT 9 10 10 0 1 NULL
+ t384 d 4 INT 9 10 10 0 1 NULL
+ t384 e 4 INT 9 10 10 0 1 NULL
+ t385 a 4 INT 9 10 10 0 1 NULL
+ t385 b 4 INT 9 10 10 0 1 NULL
+ t385 c 4 INT 9 10 10 0 1 NULL
+ t385 d 4 INT 9 10 10 0 1 NULL
+ t385 e 4 INT 9 10 10 0 1 NULL
+ t386 a 4 INT 9 10 10 0 1 NULL
+ t386 b 4 INT 9 10 10 0 1 NULL
+ t386 c 4 INT 9 10 10 0 1 NULL
+ t386 d 4 INT 9 10 10 0 1 NULL
+ t386 e 4 INT 9 10 10 0 1 NULL
+ t387 a 4 INT 9 10 10 0 1 NULL
+ t387 b 4 INT 9 10 10 0 1 NULL
+ t387 c 4 INT 9 10 10 0 1 NULL
+ t387 d 4 INT 9 10 10 0 1 NULL
+ t387 e 4 INT 9 10 10 0 1 NULL
+ t388 a 4 INT 9 10 10 0 1 NULL
+ t388 b 4 INT 9 10 10 0 1 NULL
+ t388 c 4 INT 9 10 10 0 1 NULL
+ t388 d 4 INT 9 10 10 0 1 NULL
+ t388 e 4 INT 9 10 10 0 1 NULL
+ t389 a 4 INT 9 10 10 0 1 NULL
+ t389 b 4 INT 9 10 10 0 1 NULL
+ t389 c 4 INT 9 10 10 0 1 NULL
+ t389 d 4 INT 9 10 10 0 1 NULL
+ t389 e 4 INT 9 10 10 0 1 NULL
+ t390 a 4 INT 9 10 10 0 1 NULL
+ t390 b 4 INT 9 10 10 0 1 NULL
+ t390 c 4 INT 9 10 10 0 1 NULL
+ t390 d 4 INT 9 10 10 0 1 NULL
+ t390 e 4 INT 9 10 10 0 1 NULL
+ t391 a 4 INT 9 10 10 0 1 NULL
+ t391 b 4 INT 9 10 10 0 1 NULL
+ t391 c 4 INT 9 10 10 0 1 NULL
+ t391 d 4 INT 9 10 10 0 1 NULL
+ t391 e 4 INT 9 10 10 0 1 NULL
+ t392 a 4 INT 9 10 10 0 1 NULL
+ t392 b 4 INT 9 10 10 0 1 NULL
+ t392 c 4 INT 9 10 10 0 1 NULL
+ t392 d 4 INT 9 10 10 0 1 NULL
+ t392 e 4 INT 9 10 10 0 1 NULL
+ t393 a 4 INT 9 10 10 0 1 NULL
+ t393 b 4 INT 9 10 10 0 1 NULL
+ t393 c 4 INT 9 10 10 0 1 NULL
+ t393 d 4 INT 9 10 10 0 1 NULL
+ t393 e 4 INT 9 10 10 0 1 NULL
+ t394 a 4 INT 9 10 10 0 1 NULL
+ t394 b 4 INT 9 10 10 0 1 NULL
+ t394 c 4 INT 9 10 10 0 1 NULL
+ t394 d 4 INT 9 10 10 0 1 NULL
+ t394 e 4 INT 9 10 10 0 1 NULL
+ t395 a 4 INT 9 10 10 0 1 NULL
+ t395 b 4 INT 9 10 10 0 1 NULL
+ t395 c 4 INT 9 10 10 0 1 NULL
+ t395 d 4 INT 9 10 10 0 1 NULL
+ t395 e 4 INT 9 10 10 0 1 NULL
+ t396 a 4 INT 9 10 10 0 1 NULL
+ t396 b 4 INT 9 10 10 0 1 NULL
+ t396 c 4 INT 9 10 10 0 1 NULL
+ t396 d 4 INT 9 10 10 0 1 NULL
+ t396 e 4 INT 9 10 10 0 1 NULL
+ t397 a 4 INT 9 10 10 0 1 NULL
+ t397 b 4 INT 9 10 10 0 1 NULL
+ t397 c 4 INT 9 10 10 0 1 NULL
+ t397 d 4 INT 9 10 10 0 1 NULL
+ t397 e 4 INT 9 10 10 0 1 NULL
+ t398 a 4 INT 9 10 10 0 1 NULL
+ t398 b 4 INT 9 10 10 0 1 NULL
+ t398 c 4 INT 9 10 10 0 1 NULL
+ t398 d 4 INT 9 10 10 0 1 NULL
+ t398 e 4 INT 9 10 10 0 1 NULL
+ t399 a 4 INT 9 10 10 0 1 NULL
+ t399 b 4 INT 9 10 10 0 1 NULL
+ t399 c 4 INT 9 10 10 0 1 NULL
+ t399 d 4 INT 9 10 10 0 1 NULL
+ t399 e 4 INT 9 10 10 0 1 NULL
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
+SELECT * FROM t1 ORDER BY Table_name;
+Table_Cat Table_Schema Table_Name Table_Type Remark
+NULL NULL t000 TABLE NULL
+NULL NULL t001 TABLE NULL
+NULL NULL t002 TABLE NULL
+NULL NULL t003 TABLE NULL
+NULL NULL t004 TABLE NULL
+NULL NULL t005 TABLE NULL
+NULL NULL t006 TABLE NULL
+NULL NULL t007 TABLE NULL
+NULL NULL t008 TABLE NULL
+NULL NULL t009 TABLE NULL
+NULL NULL t010 TABLE NULL
+NULL NULL t011 TABLE NULL
+NULL NULL t012 TABLE NULL
+NULL NULL t013 TABLE NULL
+NULL NULL t014 TABLE NULL
+NULL NULL t015 TABLE NULL
+NULL NULL t016 TABLE NULL
+NULL NULL t017 TABLE NULL
+NULL NULL t018 TABLE NULL
+NULL NULL t019 TABLE NULL
+NULL NULL t020 TABLE NULL
+NULL NULL t021 TABLE NULL
+NULL NULL t022 TABLE NULL
+NULL NULL t023 TABLE NULL
+NULL NULL t024 TABLE NULL
+NULL NULL t025 TABLE NULL
+NULL NULL t026 TABLE NULL
+NULL NULL t027 TABLE NULL
+NULL NULL t028 TABLE NULL
+NULL NULL t029 TABLE NULL
+NULL NULL t030 TABLE NULL
+NULL NULL t031 TABLE NULL
+NULL NULL t032 TABLE NULL
+NULL NULL t033 TABLE NULL
+NULL NULL t034 TABLE NULL
+NULL NULL t035 TABLE NULL
+NULL NULL t036 TABLE NULL
+NULL NULL t037 TABLE NULL
+NULL NULL t038 TABLE NULL
+NULL NULL t039 TABLE NULL
+NULL NULL t040 TABLE NULL
+NULL NULL t041 TABLE NULL
+NULL NULL t042 TABLE NULL
+NULL NULL t043 TABLE NULL
+NULL NULL t044 TABLE NULL
+NULL NULL t045 TABLE NULL
+NULL NULL t046 TABLE NULL
+NULL NULL t047 TABLE NULL
+NULL NULL t048 TABLE NULL
+NULL NULL t049 TABLE NULL
+NULL NULL t050 TABLE NULL
+NULL NULL t051 TABLE NULL
+NULL NULL t052 TABLE NULL
+NULL NULL t053 TABLE NULL
+NULL NULL t054 TABLE NULL
+NULL NULL t055 TABLE NULL
+NULL NULL t056 TABLE NULL
+NULL NULL t057 TABLE NULL
+NULL NULL t058 TABLE NULL
+NULL NULL t059 TABLE NULL
+NULL NULL t060 TABLE NULL
+NULL NULL t061 TABLE NULL
+NULL NULL t062 TABLE NULL
+NULL NULL t063 TABLE NULL
+NULL NULL t064 TABLE NULL
+NULL NULL t065 TABLE NULL
+NULL NULL t066 TABLE NULL
+NULL NULL t067 TABLE NULL
+NULL NULL t068 TABLE NULL
+NULL NULL t069 TABLE NULL
+NULL NULL t070 TABLE NULL
+NULL NULL t071 TABLE NULL
+NULL NULL t072 TABLE NULL
+NULL NULL t073 TABLE NULL
+NULL NULL t074 TABLE NULL
+NULL NULL t075 TABLE NULL
+NULL NULL t076 TABLE NULL
+NULL NULL t077 TABLE NULL
+NULL NULL t078 TABLE NULL
+NULL NULL t079 TABLE NULL
+NULL NULL t080 TABLE NULL
+NULL NULL t081 TABLE NULL
+NULL NULL t082 TABLE NULL
+NULL NULL t083 TABLE NULL
+NULL NULL t084 TABLE NULL
+NULL NULL t085 TABLE NULL
+NULL NULL t086 TABLE NULL
+NULL NULL t087 TABLE NULL
+NULL NULL t088 TABLE NULL
+NULL NULL t089 TABLE NULL
+NULL NULL t090 TABLE NULL
+NULL NULL t091 TABLE NULL
+NULL NULL t092 TABLE NULL
+NULL NULL t093 TABLE NULL
+NULL NULL t094 TABLE NULL
+NULL NULL t095 TABLE NULL
+NULL NULL t096 TABLE NULL
+NULL NULL t097 TABLE NULL
+NULL NULL t098 TABLE NULL
+NULL NULL t099 TABLE NULL
+NULL NULL t1 TABLE NULL
+NULL NULL t100 TABLE NULL
+NULL NULL t101 TABLE NULL
+NULL NULL t102 TABLE NULL
+NULL NULL t103 TABLE NULL
+NULL NULL t104 TABLE NULL
+NULL NULL t105 TABLE NULL
+NULL NULL t106 TABLE NULL
+NULL NULL t107 TABLE NULL
+NULL NULL t108 TABLE NULL
+NULL NULL t109 TABLE NULL
+NULL NULL t110 TABLE NULL
+NULL NULL t111 TABLE NULL
+NULL NULL t112 TABLE NULL
+NULL NULL t113 TABLE NULL
+NULL NULL t114 TABLE NULL
+NULL NULL t115 TABLE NULL
+NULL NULL t116 TABLE NULL
+NULL NULL t117 TABLE NULL
+NULL NULL t118 TABLE NULL
+NULL NULL t119 TABLE NULL
+NULL NULL t120 TABLE NULL
+NULL NULL t121 TABLE NULL
+NULL NULL t122 TABLE NULL
+NULL NULL t123 TABLE NULL
+NULL NULL t124 TABLE NULL
+NULL NULL t125 TABLE NULL
+NULL NULL t126 TABLE NULL
+NULL NULL t127 TABLE NULL
+NULL NULL t128 TABLE NULL
+NULL NULL t129 TABLE NULL
+NULL NULL t130 TABLE NULL
+NULL NULL t131 TABLE NULL
+NULL NULL t132 TABLE NULL
+NULL NULL t133 TABLE NULL
+NULL NULL t134 TABLE NULL
+NULL NULL t135 TABLE NULL
+NULL NULL t136 TABLE NULL
+NULL NULL t137 TABLE NULL
+NULL NULL t138 TABLE NULL
+NULL NULL t139 TABLE NULL
+NULL NULL t140 TABLE NULL
+NULL NULL t141 TABLE NULL
+NULL NULL t142 TABLE NULL
+NULL NULL t143 TABLE NULL
+NULL NULL t144 TABLE NULL
+NULL NULL t145 TABLE NULL
+NULL NULL t146 TABLE NULL
+NULL NULL t147 TABLE NULL
+NULL NULL t148 TABLE NULL
+NULL NULL t149 TABLE NULL
+NULL NULL t150 TABLE NULL
+NULL NULL t151 TABLE NULL
+NULL NULL t152 TABLE NULL
+NULL NULL t153 TABLE NULL
+NULL NULL t154 TABLE NULL
+NULL NULL t155 TABLE NULL
+NULL NULL t156 TABLE NULL
+NULL NULL t157 TABLE NULL
+NULL NULL t158 TABLE NULL
+NULL NULL t159 TABLE NULL
+NULL NULL t160 TABLE NULL
+NULL NULL t161 TABLE NULL
+NULL NULL t162 TABLE NULL
+NULL NULL t163 TABLE NULL
+NULL NULL t164 TABLE NULL
+NULL NULL t165 TABLE NULL
+NULL NULL t166 TABLE NULL
+NULL NULL t167 TABLE NULL
+NULL NULL t168 TABLE NULL
+NULL NULL t169 TABLE NULL
+NULL NULL t170 TABLE NULL
+NULL NULL t171 TABLE NULL
+NULL NULL t172 TABLE NULL
+NULL NULL t173 TABLE NULL
+NULL NULL t174 TABLE NULL
+NULL NULL t175 TABLE NULL
+NULL NULL t176 TABLE NULL
+NULL NULL t177 TABLE NULL
+NULL NULL t178 TABLE NULL
+NULL NULL t179 TABLE NULL
+NULL NULL t180 TABLE NULL
+NULL NULL t181 TABLE NULL
+NULL NULL t182 TABLE NULL
+NULL NULL t183 TABLE NULL
+NULL NULL t184 TABLE NULL
+NULL NULL t185 TABLE NULL
+NULL NULL t186 TABLE NULL
+NULL NULL t187 TABLE NULL
+NULL NULL t188 TABLE NULL
+NULL NULL t189 TABLE NULL
+NULL NULL t190 TABLE NULL
+NULL NULL t191 TABLE NULL
+NULL NULL t192 TABLE NULL
+NULL NULL t193 TABLE NULL
+NULL NULL t194 TABLE NULL
+NULL NULL t195 TABLE NULL
+NULL NULL t196 TABLE NULL
+NULL NULL t197 TABLE NULL
+NULL NULL t198 TABLE NULL
+NULL NULL t199 TABLE NULL
+NULL NULL t200 TABLE NULL
+NULL NULL t201 TABLE NULL
+NULL NULL t202 TABLE NULL
+NULL NULL t203 TABLE NULL
+NULL NULL t204 TABLE NULL
+NULL NULL t205 TABLE NULL
+NULL NULL t206 TABLE NULL
+NULL NULL t207 TABLE NULL
+NULL NULL t208 TABLE NULL
+NULL NULL t209 TABLE NULL
+NULL NULL t210 TABLE NULL
+NULL NULL t211 TABLE NULL
+NULL NULL t212 TABLE NULL
+NULL NULL t213 TABLE NULL
+NULL NULL t214 TABLE NULL
+NULL NULL t215 TABLE NULL
+NULL NULL t216 TABLE NULL
+NULL NULL t217 TABLE NULL
+NULL NULL t218 TABLE NULL
+NULL NULL t219 TABLE NULL
+NULL NULL t220 TABLE NULL
+NULL NULL t221 TABLE NULL
+NULL NULL t222 TABLE NULL
+NULL NULL t223 TABLE NULL
+NULL NULL t224 TABLE NULL
+NULL NULL t225 TABLE NULL
+NULL NULL t226 TABLE NULL
+NULL NULL t227 TABLE NULL
+NULL NULL t228 TABLE NULL
+NULL NULL t229 TABLE NULL
+NULL NULL t230 TABLE NULL
+NULL NULL t231 TABLE NULL
+NULL NULL t232 TABLE NULL
+NULL NULL t233 TABLE NULL
+NULL NULL t234 TABLE NULL
+NULL NULL t235 TABLE NULL
+NULL NULL t236 TABLE NULL
+NULL NULL t237 TABLE NULL
+NULL NULL t238 TABLE NULL
+NULL NULL t239 TABLE NULL
+NULL NULL t240 TABLE NULL
+NULL NULL t241 TABLE NULL
+NULL NULL t242 TABLE NULL
+NULL NULL t243 TABLE NULL
+NULL NULL t244 TABLE NULL
+NULL NULL t245 TABLE NULL
+NULL NULL t246 TABLE NULL
+NULL NULL t247 TABLE NULL
+NULL NULL t248 TABLE NULL
+NULL NULL t249 TABLE NULL
+NULL NULL t250 TABLE NULL
+NULL NULL t251 TABLE NULL
+NULL NULL t252 TABLE NULL
+NULL NULL t253 TABLE NULL
+NULL NULL t254 TABLE NULL
+NULL NULL t255 TABLE NULL
+NULL NULL t256 TABLE NULL
+NULL NULL t257 TABLE NULL
+NULL NULL t258 TABLE NULL
+NULL NULL t259 TABLE NULL
+NULL NULL t260 TABLE NULL
+NULL NULL t261 TABLE NULL
+NULL NULL t262 TABLE NULL
+NULL NULL t263 TABLE NULL
+NULL NULL t264 TABLE NULL
+NULL NULL t265 TABLE NULL
+NULL NULL t266 TABLE NULL
+NULL NULL t267 TABLE NULL
+NULL NULL t268 TABLE NULL
+NULL NULL t269 TABLE NULL
+NULL NULL t270 TABLE NULL
+NULL NULL t271 TABLE NULL
+NULL NULL t272 TABLE NULL
+NULL NULL t273 TABLE NULL
+NULL NULL t274 TABLE NULL
+NULL NULL t275 TABLE NULL
+NULL NULL t276 TABLE NULL
+NULL NULL t277 TABLE NULL
+NULL NULL t278 TABLE NULL
+NULL NULL t279 TABLE NULL
+NULL NULL t280 TABLE NULL
+NULL NULL t281 TABLE NULL
+NULL NULL t282 TABLE NULL
+NULL NULL t283 TABLE NULL
+NULL NULL t284 TABLE NULL
+NULL NULL t285 TABLE NULL
+NULL NULL t286 TABLE NULL
+NULL NULL t287 TABLE NULL
+NULL NULL t288 TABLE NULL
+NULL NULL t289 TABLE NULL
+NULL NULL t290 TABLE NULL
+NULL NULL t291 TABLE NULL
+NULL NULL t292 TABLE NULL
+NULL NULL t293 TABLE NULL
+NULL NULL t294 TABLE NULL
+NULL NULL t295 TABLE NULL
+NULL NULL t296 TABLE NULL
+NULL NULL t297 TABLE NULL
+NULL NULL t298 TABLE NULL
+NULL NULL t299 TABLE NULL
+NULL NULL t300 TABLE NULL
+NULL NULL t301 TABLE NULL
+NULL NULL t302 TABLE NULL
+NULL NULL t303 TABLE NULL
+NULL NULL t304 TABLE NULL
+NULL NULL t305 TABLE NULL
+NULL NULL t306 TABLE NULL
+NULL NULL t307 TABLE NULL
+NULL NULL t308 TABLE NULL
+NULL NULL t309 TABLE NULL
+NULL NULL t310 TABLE NULL
+NULL NULL t311 TABLE NULL
+NULL NULL t312 TABLE NULL
+NULL NULL t313 TABLE NULL
+NULL NULL t314 TABLE NULL
+NULL NULL t315 TABLE NULL
+NULL NULL t316 TABLE NULL
+NULL NULL t317 TABLE NULL
+NULL NULL t318 TABLE NULL
+NULL NULL t319 TABLE NULL
+NULL NULL t320 TABLE NULL
+NULL NULL t321 TABLE NULL
+NULL NULL t322 TABLE NULL
+NULL NULL t323 TABLE NULL
+NULL NULL t324 TABLE NULL
+NULL NULL t325 TABLE NULL
+NULL NULL t326 TABLE NULL
+NULL NULL t327 TABLE NULL
+NULL NULL t328 TABLE NULL
+NULL NULL t329 TABLE NULL
+NULL NULL t330 TABLE NULL
+NULL NULL t331 TABLE NULL
+NULL NULL t332 TABLE NULL
+NULL NULL t333 TABLE NULL
+NULL NULL t334 TABLE NULL
+NULL NULL t335 TABLE NULL
+NULL NULL t336 TABLE NULL
+NULL NULL t337 TABLE NULL
+NULL NULL t338 TABLE NULL
+NULL NULL t339 TABLE NULL
+NULL NULL t340 TABLE NULL
+NULL NULL t341 TABLE NULL
+NULL NULL t342 TABLE NULL
+NULL NULL t343 TABLE NULL
+NULL NULL t344 TABLE NULL
+NULL NULL t345 TABLE NULL
+NULL NULL t346 TABLE NULL
+NULL NULL t347 TABLE NULL
+NULL NULL t348 TABLE NULL
+NULL NULL t349 TABLE NULL
+NULL NULL t350 TABLE NULL
+NULL NULL t351 TABLE NULL
+NULL NULL t352 TABLE NULL
+NULL NULL t353 TABLE NULL
+NULL NULL t354 TABLE NULL
+NULL NULL t355 TABLE NULL
+NULL NULL t356 TABLE NULL
+NULL NULL t357 TABLE NULL
+NULL NULL t358 TABLE NULL
+NULL NULL t359 TABLE NULL
+NULL NULL t360 TABLE NULL
+NULL NULL t361 TABLE NULL
+NULL NULL t362 TABLE NULL
+NULL NULL t363 TABLE NULL
+NULL NULL t364 TABLE NULL
+NULL NULL t365 TABLE NULL
+NULL NULL t366 TABLE NULL
+NULL NULL t367 TABLE NULL
+NULL NULL t368 TABLE NULL
+NULL NULL t369 TABLE NULL
+NULL NULL t370 TABLE NULL
+NULL NULL t371 TABLE NULL
+NULL NULL t372 TABLE NULL
+NULL NULL t373 TABLE NULL
+NULL NULL t374 TABLE NULL
+NULL NULL t375 TABLE NULL
+NULL NULL t376 TABLE NULL
+NULL NULL t377 TABLE NULL
+NULL NULL t378 TABLE NULL
+NULL NULL t379 TABLE NULL
+NULL NULL t380 TABLE NULL
+NULL NULL t381 TABLE NULL
+NULL NULL t382 TABLE NULL
+NULL NULL t383 TABLE NULL
+NULL NULL t384 TABLE NULL
+NULL NULL t385 TABLE NULL
+NULL NULL t386 TABLE NULL
+NULL NULL t387 TABLE NULL
+NULL NULL t388 TABLE NULL
+NULL NULL t389 TABLE NULL
+NULL NULL t390 TABLE NULL
+NULL NULL t391 TABLE NULL
+NULL NULL t392 TABLE NULL
+NULL NULL t393 TABLE NULL
+NULL NULL t394 TABLE NULL
+NULL NULL t395 TABLE NULL
+NULL NULL t396 TABLE NULL
+NULL NULL t397 TABLE NULL
+NULL NULL t398 TABLE NULL
+NULL NULL t399 TABLE NULL
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result b/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
new file mode 100644
index 00000000..f9045e73
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/odbc_sqlite3_grant.result
@@ -0,0 +1,86 @@
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Description` char(128) NOT NULL,
+ `Attributes` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Drivers'
+SET NAMES utf8;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(64) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=utf8 CONNECTION='Driver=SQLite3 ODBC Driver;Database=MTR_SUITE_DIR/std_data/test.sqlite3;NoWCHAR=yes' `TABLE_TYPE`='ODBC' `DATA_CHARSET`='utf8'
+SELECT * FROM t1;
+a
+test1
+test2
+теÑÑ‚1
+теÑÑ‚2
+ÆÇÈÉË
+SELECT user();
+user()
+user@localhost
+SELECT * FROM t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO t1 VALUES ('xxx');
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE FROM t1 WHERE a='xxx';
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE t1 SET a='yyy' WHERE a='xxx';
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+TRUNCATE TABLE t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+ALTER TABLE t1 READONLY=1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+# using SQL SECIRITY INVOKER
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+INSERT INTO v1 VALUES (2);
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+UPDATE v1 SET a=123;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+DELETE FROM v1;
+ERROR 28000: Access denied for user 'user'@'localhost' (using password: NO)
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+# using SQL SECIRITY DEFINER
+DROP VIEW v1;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT * FROM t1;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1 WHERE a='test1';
+a
+test1
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+DROP USER user@localhost;
diff --git a/storage/connect/mysql-test/connect/r/odbc_xls.result b/storage/connect/mysql-test/connect/r/odbc_xls.result
new file mode 100644
index 00000000..d379cb5b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/odbc_xls.result
@@ -0,0 +1,26 @@
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `Name` varchar(256) NOT NULL,
+ `Description` varchar(256) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='ODBC' `CATFUNC`='Sources'
+CREATE TABLE contact (Nom VARCHAR(128), Fonction VARCHAR(128), Company VARCHAR(128), Repertoire VARCHAR(30)) ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=DATADIR/test/contacts.xls';;
+SELECT Nom, Fonction FROM contact WHERE Repertoire='ascii';
+Nom Fonction
+Du Halgouet Tanguy NULL
+Vandamme Anna NULL
+Thomas Willy NULL
+Thomas Dominique NULL
+Lemonnier Nathalie Directeur Marketing Client
+Menseau Eric NULL
+DROP TABLE contact;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;;
+SELECT * FROM t1 WHERE Table_name='CONTACT';
+Table_Cat Table_Schema Table_Name Table_Type Remark
+DATADIR/test/contacts NULL CONTACT TABLE NULL
+DROP TABLE t1;
+CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;;
+SELECT * FROM t1 WHERE Table_name='CONTACT' AND Column_name IN ('Nom','Fonction');
+Table_Cat Table_Schema Table_Name Column_Name Data_Type Type_Name Column_Size Buffer_Length Decimal_Digits Radix Nullable Remarks
+DATADIR/test/contacts NULL CONTACT Nom 12 VARCHAR 255 510 NULL NULL 1 NULL
+DATADIR/test/contacts NULL CONTACT Fonction 12 VARCHAR 255 510 NULL NULL 1 NULL
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/part_file.result b/storage/connect/mysql-test/connect/r/part_file.result
new file mode 100644
index 00000000..3dabd946
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/part_file.result
@@ -0,0 +1,343 @@
+set @@global.connect_exact_info=ON;
+# This will be used to see what data files are created
+CREATE TABLE dr1 (
+fname VARCHAR(256) NOT NULL FLAG=2,
+ftype CHAR(8) NOT NULL FLAG=3
+# ,FSIZE INT(6) NOT NULL FLAG=5 removed because Unix size != Windows size
+) engine=CONNECT table_type=DIR file_name='t1#P#*.*';
+#
+# Testing partitioning on inward table
+#
+CREATE TABLE t1 (
+id INT NOT NULL,
+msg VARCHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=CSV AVG_ROW_LENGTH=10
+PARTITION BY RANGE(id) (
+PARTITION first VALUES LESS THAN(10),
+PARTITION middle VALUES LESS THAN(50),
+PARTITION last VALUES LESS THAN(MAXVALUE));
+INSERT INTO t1 VALUES(4, 'four'),(24, 'twenty four');
+INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one');
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+first 2
+middle 3
+last 2
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+24 twenty four
+10 ten
+40 forty
+60 sixty
+81 eighty one
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id > 50;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 last ALL NULL NULL NULL NULL 3 Using where
+SELECT * FROM t1 WHERE id > 50;
+id msg
+60 sixty
+81 eighty one
+UPDATE t1 set id = 41 WHERE msg = 'four';
+ERROR HY000: Got error 174 'Cannot update column id because it is used for partitioning' from CONNECT
+UPDATE t1 set msg = 'quatre' WHERE id = 4;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+t1#P#first .csv
+t1#P#last .csv
+t1#P#middle .csv
+#
+# Altering partitioning on inward table
+#
+ALTER TABLE t1
+PARTITION by range(id) (
+PARTITION first VALUES LESS THAN(11),
+PARTITION middle VALUES LESS THAN(50),
+PARTITION last VALUES LESS THAN(MAXVALUE));
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+first 3
+middle 2
+last 2
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+t1#P#first .csv
+t1#P#last .csv
+t1#P#middle .csv
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id=10;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 first ALL NULL NULL NULL NULL 3 Using where
+SELECT * FROM t1 WHERE id=10;
+id msg
+10 ten
+DELETE FROM t1 WHERE id in (4,60);
+SELECT * FROM t1;
+id msg
+7 seven
+10 ten
+24 twenty four
+40 forty
+81 eighty one
+DROP TABLE t1;
+#
+# Testing partitioning on a void outward table
+#
+ALTER TABLE dr1 FILE_NAME='part*.*';
+CREATE TABLE t1 (
+rwid INT(6) DEFAULT 0 SPECIAL=ROWID,
+rnum INT(6) DEFAULT 0 SPECIAL=ROWNUM,
+prtn VARCHAR(64) DEFAULT '' SPECIAL=PARTID,
+tbn VARCHAR(64) DEFAULT '' SPECIAL=TABID,
+fid VARCHAR(256) DEFAULT '' SPECIAL=FNAME,
+id INT KEY NOT NULL,
+msg VARCHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='part%s.txt';
+ALTER TABLE t1
+PARTITION by range columns(id) (
+PARTITION `1` VALUES LESS THAN(10),
+PARTITION `2` VALUES LESS THAN(50),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 0 PRIMARY 1 id A NULL NULL NULL XINDEX
+INSERT INTO t1(id,msg) VALUES(4, 'four');
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .fnx
+part1 .txt
+INSERT INTO t1(id,msg) VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one');
+INSERT INTO t1(id,msg) VALUES(72,'seventy two'),(20,'twenty'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+1 4
+2 4
+3 3
+SELECT * FROM t1;
+rwid rnum prtn tbn fid id msg
+1 1 1 t1 part1 4 four
+2 2 1 t1 part1 7 seven
+3 3 1 t1 part1 1 one
+4 4 1 t1 part1 8 eight
+1 1 2 t1 part2 10 ten
+2 2 2 t1 part2 40 forty
+3 3 2 t1 part2 20 twenty
+4 4 2 t1 part2 35 thirty five
+1 1 3 t1 part3 60 sixty
+2 2 3 t1 part3 81 eighty one
+3 3 3 t1 part3 72 seventy two
+SELECT * FROM t1 order by id;
+rwid rnum prtn tbn fid id msg
+3 3 1 t1 part1 1 one
+1 1 1 t1 part1 4 four
+2 2 1 t1 part1 7 seven
+4 4 1 t1 part1 8 eight
+1 1 2 t1 part2 10 ten
+3 3 2 t1 part2 20 twenty
+4 4 2 t1 part2 35 thirty five
+2 2 2 t1 part2 40 forty
+1 1 3 t1 part3 60 sixty
+3 3 3 t1 part3 72 seventy two
+2 2 3 t1 part3 81 eighty one
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 2 const PRIMARY PRIMARY 4 const 1
+SELECT * FROM t1 WHERE id = 10;
+rwid rnum prtn tbn fid id msg
+1 1 2 t1 part2 10 ten
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id >= 40;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 2,3 range PRIMARY PRIMARY 4 NULL 4 Using where
+SELECT * FROM t1 WHERE id >= 40;
+rwid rnum prtn tbn fid id msg
+2 2 2 t1 part2 40 forty
+1 1 3 t1 part3 60 sixty
+3 3 3 t1 part3 72 seventy two
+2 2 3 t1 part3 81 eighty one
+SELECT count(*) FROM t1 WHERE id < 10;
+count(*)
+4
+SELECT case when id < 10 then 1 when id < 50 then 2 else 3 end as pn, count(*) FROM t1 group by pn;
+pn count(*)
+1 4
+2 4
+3 3
+SELECT prtn, count(*) FROM t1 group by prtn;
+prtn count(*)
+1 4
+2 4
+3 3
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id > 50;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 3 range PRIMARY PRIMARY 4 NULL 3 Using where
+SELECT * FROM t1 WHERE id = 35;
+rwid rnum prtn tbn fid id msg
+4 4 2 t1 part2 35 thirty five
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .fnx
+part1 .txt
+part2 .fnx
+part2 .txt
+part3 .fnx
+part3 .txt
+# This does not change the partition file data and is WRONG
+ALTER TABLE t1
+PARTITION by range columns(id) (
+PARTITION `1` VALUES LESS THAN(11),
+PARTITION `2` VALUES LESS THAN(70),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+Warnings:
+Warning 1105 Data repartition in 1 is unchecked
+Warning 1105 Data repartition in 2 is unchecked
+Warning 1105 Data repartition in 3 is unchecked
+SELECT CASE WHEN id < 11 THEN 1 WHEN id < 70 THEN 2 ELSE 3 END AS pn, COUNT(*) FROM t1 GROUP BY pn;
+pn COUNT(*)
+1 5
+2 4
+3 2
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+1 4
+2 4
+3 3
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .fnx
+part1 .txt
+part2 .fnx
+part2 .txt
+part3 .fnx
+part3 .txt
+#
+# This is the correct way to change partitioning:
+# Save table values, erase the table, then re-insert saved values in modified table
+#
+CREATE TABLE t2 (
+id INT NOT NULL,
+msg VARCHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=FIX;
+Warnings:
+Warning 1105 No file name. Table will use t2.fix
+INSERT INTO t2 SELECT id, msg FROM t1;
+DELETE FROM t1;
+INSERT INTO t1(id,msg) SELECT * FROM t2;
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+1 5
+2 4
+3 2
+SELECT * FROM t1;
+rwid rnum prtn tbn fid id msg
+1 1 1 t1 part1 4 four
+2 2 1 t1 part1 7 seven
+3 3 1 t1 part1 1 one
+4 4 1 t1 part1 8 eight
+5 5 1 t1 part1 10 ten
+1 1 2 t1 part2 40 forty
+2 2 2 t1 part2 20 twenty
+3 3 2 t1 part2 35 thirty five
+4 4 2 t1 part2 60 sixty
+1 1 3 t1 part3 81 eighty one
+2 2 3 t1 part3 72 seventy two
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .fnx
+part1 .txt
+part2 .fnx
+part2 .txt
+part3 .fnx
+part3 .txt
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# Testing partitioning on a populated outward table
+#
+CREATE TABLE t1 (
+id INT NOT NULL,
+msg VARCHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='part%s.txt'
+PARTITION by range columns(id) (
+PARTITION `1` VALUES LESS THAN(11),
+PARTITION `2` VALUES LESS THAN(70),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+Warnings:
+Warning 1105 Data repartition in 1 is unchecked
+Warning 1105 Data repartition in 2 is unchecked
+Warning 1105 Data repartition in 3 is unchecked
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+1 5
+2 4
+3 2
+SELECT * FROM t1 WHERE id < 11;
+id msg
+4 four
+7 seven
+1 one
+8 eight
+10 ten
+SELECT * FROM t1 WHERE id >= 70;
+id msg
+81 eighty one
+72 seventy two
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .fnx
+part1 .txt
+part2 .fnx
+part2 .txt
+part3 .fnx
+part3 .txt
+#
+# Testing indexing on a partitioned table
+#
+CREATE INDEX XID ON t1(id);
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 1 XID 1 id A NULL NULL NULL XINDEX
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .fnx
+part1 .txt
+part2 .fnx
+part2 .txt
+part3 .fnx
+part3 .txt
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 1 ref XID XID 4 const 1
+DROP INDEX XID ON t1;
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .txt
+part2 .txt
+part3 .txt
+ALTER TABLE t1 ADD PRIMARY KEY (id);
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 0 PRIMARY 1 id A NULL NULL NULL XINDEX
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .fnx
+part1 .txt
+part2 .fnx
+part2 .txt
+part3 .fnx
+part3 .txt
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 1 const PRIMARY PRIMARY 4 const 1
+ALTER TABLE t1 DROP PRIMARY KEY;
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+SELECT * FROM dr1 ORDER BY fname, ftype;
+fname ftype
+part1 .txt
+part2 .txt
+part3 .txt
+DROP TABLE t1;
+DROP TABLE dr1;
+set @@global.connect_exact_info=OFF;
diff --git a/storage/connect/mysql-test/connect/r/part_table.result b/storage/connect/mysql-test/connect/r/part_table.result
new file mode 100644
index 00000000..ee17a1d3
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/part_table.result
@@ -0,0 +1,222 @@
+set @@global.connect_exact_info=ON;
+CREATE TABLE xt1 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=MyISAM;
+INSERT INTO xt1 VALUES(4, 'four'),(7,'seven'),(1,'one'),(8,'eight');
+SELECT * FROM xt1;
+id msg
+4 four
+7 seven
+1 one
+8 eight
+CREATE TABLE xt2 (
+id INT KEY NOT NULL,
+msg VARCHAR(32));
+INSERT INTO xt2 VALUES(10,'ten'),(40,'forty'),(11,'eleven'),(35,'thirty five');
+SELECT * FROM xt2;
+id msg
+10 ten
+40 forty
+11 eleven
+35 thirty five
+CREATE TABLE xt3 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=CSV AVG_ROW_LENGTH=6;
+Warnings:
+Warning 1105 No file name. Table will use xt3.csv
+INSERT INTO xt3 VALUES(60,'sixty'),(81,'eighty one'),(72,'seventy two');
+SELECT * FROM xt3;
+id msg
+60 sixty
+81 eighty one
+72 seventy two
+CREATE TABLE t1 (
+id INT NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=PROXY TABNAME='xt%s'
+PARTITION BY RANGE COLUMNS(id) (
+PARTITION `1` VALUES LESS THAN(10),
+PARTITION `2` VALUES LESS THAN(50),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+Warnings:
+Warning 1105 Data repartition in 1 is unchecked
+Warning 1105 Data repartition in 2 is unchecked
+Warning 1105 Data repartition in 3 is unchecked
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+1 4
+2 4
+3 3
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+1 one
+8 eight
+10 ten
+40 forty
+11 eleven
+35 thirty five
+60 sixty
+81 eighty one
+72 seventy two
+DELETE FROM t1;
+Warnings:
+Note 1105 xt1: 4 affected rows
+Note 1105 xt2: 4 affected rows
+ALTER TABLE t1 ADD INDEX XID(id);
+ERROR HY000: Table type PROXY is not indexable
+INSERT INTO t1 VALUES(4, 'four');
+INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one');
+INSERT INTO t1 VALUES(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+1 4
+2 4
+3 3
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+1 one
+8 eight
+10 ten
+40 forty
+11 eleven
+35 thirty five
+60 sixty
+81 eighty one
+72 seventy two
+EXPLAIN PARTITIONS
+SELECT * FROM t1 WHERE id = 81;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 3 ALL NULL NULL NULL NULL 6 Using where
+DELETE FROM t1;
+Warnings:
+Note 1105 xt1: 4 affected rows
+Note 1105 xt2: 4 affected rows
+DROP TABLE t1;
+CREATE TABLE t1 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='xt%s'
+PARTITION BY RANGE COLUMNS(id) (
+PARTITION `1` VALUES LESS THAN(10),
+PARTITION `2` VALUES LESS THAN(50),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+Warnings:
+Warning 1105 Data repartition in 1 is unchecked
+Warning 1105 Data repartition in 2 is unchecked
+Warning 1105 Data repartition in 3 is unchecked
+SHOW INDEX FROM t1;
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+t1 0 PRIMARY 1 id NULL NULL NULL NULL REMOTE
+INSERT INTO t1 VALUES(4, 'four');
+INSERT INTO t1 VALUES(40, 'forty');
+INSERT INTO t1 VALUES(72,'seventy two');
+INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(60,'sixty'),(81,'eighty one'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+partition_name table_rows
+1 4
+2 4
+3 3
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+1 one
+8 eight
+40 forty
+10 ten
+11 eleven
+35 thirty five
+72 seventy two
+60 sixty
+81 eighty one
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 81;
+id select_type table partitions type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 3 const PRIMARY PRIMARY 4 const 1
+SELECT * FROM t1 WHERE id = 7;
+id msg
+7 seven
+SELECT * FROM t1 WHERE id = 35;
+id msg
+35 thirty five
+UPDATE t1 SET msg = 'number' WHERE id in (60,72);
+Warnings:
+Note 1105 xt3: 2 affected rows
+Note 1105 xt3: 0 affected rows
+UPDATE t1 SET msg = 'soixante' WHERE id = 60;
+Warnings:
+Note 1105 xt3: 1 affected rows
+SELECT * FROM t1 WHERE id > 50;
+id msg
+60 soixante
+72 number
+81 eighty one
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+Warnings:
+Note 1105 xt3: 3 affected rows
+UPDATE t1 SET msg = 'sept' WHERE id = 7;
+Warnings:
+Note 1105 xt1: 1 affected rows
+SELECT * FROM t1;
+id msg
+4 four
+7 sept
+1 one
+8 eight
+40 forty
+10 ten
+11 eleven
+35 thirty five
+72 big
+60 big
+81 big
+DELETE FROM t1 WHERE id in (60,72);
+Warnings:
+Note 1105 xt3: 2 affected rows
+Note 1105 xt3: 0 affected rows
+SELECT * FROM t1;
+id msg
+4 four
+7 sept
+1 one
+8 eight
+40 forty
+10 ten
+11 eleven
+35 thirty five
+81 big
+DROP TABLE t1;
+CREATE TABLE t1 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=MYSQL
+OPTION_LIST='connect=mysql://root@localhost/test/xt%s'
+PARTITION BY RANGE COLUMNS(id) (
+PARTITION `1` VALUES LESS THAN(10),
+PARTITION `2` VALUES LESS THAN(50),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+Warnings:
+Warning 1105 Data repartition in 1 is unchecked
+Warning 1105 Data repartition in 2 is unchecked
+Warning 1105 Data repartition in 3 is unchecked
+SELECT * FROM t1;
+id msg
+4 four
+7 sept
+1 one
+8 eight
+40 forty
+10 ten
+11 eleven
+35 thirty five
+81 big
+DROP TABLE t1;
+DROP TABLE xt1;
+DROP TABLE xt2;
+DROP TABLE xt3;
+set @@global.connect_exact_info=OFF;
diff --git a/storage/connect/mysql-test/connect/r/pivot.result b/storage/connect/mysql-test/connect/r/pivot.result
new file mode 100644
index 00000000..349db89f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/pivot.result
@@ -0,0 +1,251 @@
+#
+# Testing the PIVOT table type
+#
+CREATE TABLE expenses (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+What CHAR(12) NOT NULL,
+Amount DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='expenses.txt' ENDING=2;
+SELECT * FROM expenses;
+Who Week What Amount
+Joe 3 Beer 18.00
+Beth 4 Food 17.00
+Janet 5 Beer 14.00
+Joe 3 Food 12.00
+Joe 4 Beer 19.00
+Janet 5 Car 12.00
+Joe 3 Food 19.00
+Beth 4 Beer 15.00
+Janet 5 Beer 19.00
+Joe 3 Car 20.00
+Joe 4 Beer 16.00
+Beth 5 Food 12.00
+Beth 3 Beer 16.00
+Joe 4 Food 17.00
+Joe 5 Beer 14.00
+Janet 3 Car 19.00
+Joe 4 Food 17.00
+Beth 5 Beer 20.00
+Janet 3 Food 18.00
+Joe 4 Beer 14.00
+Joe 5 Food 12.00
+Janet 3 Beer 18.00
+Janet 4 Car 17.00
+Janet 5 Food 12.00
+#
+# Pivoting from What
+#
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+ALTER TABLE pivex OPTION_LIST='port=PORT';
+SELECT * FROM pivex;
+Who Week Beer Car Food
+Beth 3 16.00 0.00 0.00
+Beth 4 15.00 0.00 17.00
+Beth 5 20.00 0.00 12.00
+Janet 3 18.00 19.00 18.00
+Janet 4 0.00 17.00 0.00
+Janet 5 33.00 12.00 12.00
+Joe 3 18.00 20.00 31.00
+Joe 4 49.00 0.00 34.00
+Joe 5 14.00 0.00 12.00
+#
+# Restricting the columns in a Pivot Table
+#
+ALTER TABLE pivex DROP COLUMN week;
+SELECT * FROM pivex;
+Who Beer Car Food
+Beth 51.00 0.00 29.00
+Janet 51.00 48.00 30.00
+Joe 81.00 20.00 77.00
+#
+# Using a source definition
+#
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what';
+Warnings:
+Warning 1105 Cannot check looping reference
+ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=PORT';
+SELECT * FROM pivex;
+Who Week Beer Car Food
+Beth 4 15.00 0.00 17.00
+Beth 5 20.00 0.00 12.00
+Janet 4 0.00 17.00 0.00
+Janet 5 33.00 12.00 12.00
+Joe 4 49.00 0.00 34.00
+Joe 5 14.00 0.00 12.00
+#
+# Pivoting from Week
+#
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+`3` DOUBLE(8,2) FLAG=1,
+`4` DOUBLE(8,2) FLAG=1,
+`5` DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=PORT';
+SELECT * FROM pivex;
+Who What 3 4 5
+Beth Beer 16.00 15.00 20.00
+Beth Food 0.00 17.00 12.00
+Janet Beer 18.00 0.00 33.00
+Janet Car 19.00 17.00 12.00
+Janet Food 18.00 0.00 12.00
+Joe Beer 18.00 49.00 14.00
+Joe Car 20.00 0.00 0.00
+Joe Food 31.00 34.00 12.00
+#
+# Using scalar functions and expresssions
+#
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+First DOUBLE(8,2) FLAG=1,
+Middle DOUBLE(8,2) FLAG=1,
+Last DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk';
+Warnings:
+Warning 1105 Cannot check looping reference
+ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=PORT';
+SELECT * FROM pivex;
+Who What First Middle Last
+Beth Beer 104.96 98.40 131.20
+Beth Food 0.00 111.52 78.72
+Janet Beer 118.08 0.00 216.48
+Janet Car 124.64 111.52 78.72
+Janet Food 118.08 0.00 78.72
+Joe Beer 118.08 321.44 91.84
+Joe Car 131.20 0.00 0.00
+Joe Food 203.36 223.04 78.72
+DROP TABLE pivex;
+DROP TABLE expenses;
+#
+# Make the PETS table
+#
+CREATE TABLE pets (
+Name VARCHAR(12) NOT NULL,
+Race CHAR(6) NOT NULL,
+Number INT NOT NULL) ENGINE=MYISAM;
+INSERT INTO pets VALUES('John','dog',2);
+INSERT INTO pets VALUES('Bill','cat',1);
+INSERT INTO pets VALUES('Mary','dog',1);
+INSERT INTO pets VALUES('Mary','cat',1);
+INSERT INTO pets VALUES('Lisbeth','rabbit',2);
+INSERT INTO pets VALUES('Kevin','cat',2);
+INSERT INTO pets VALUES('Kevin','bird',6);
+INSERT INTO pets VALUES('Donald','dog',1);
+INSERT INTO pets VALUES('Donald','fish',3);
+SELECT * FROM pets;
+Name Race Number
+John dog 2
+Bill cat 1
+Mary dog 1
+Mary cat 1
+Lisbeth rabbit 2
+Kevin cat 2
+Kevin bird 6
+Donald dog 1
+Donald fish 3
+#
+# Pivot the PETS table
+#
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+rabbit INT NOT NULL DEFAULT 0 FLAG=1,
+bird INT NOT NULL DEFAULT 0 FLAG=1,
+fish INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+name dog cat rabbit bird fish
+John 2 0 0 0 0
+Bill 0 1 0 0 0
+Mary 1 1 0 0 0
+Lisbeth 0 0 2 0 0
+Kevin 0 2 0 6 0
+Donald 1 0 0 0 3
+DROP TABLE pivet;
+#
+# Testing the "data" column list
+#
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+ERROR HY000: Got error 122 'Cannot find matching column' from CONNECT
+ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1';
+SELECT * FROM pivet;
+name dog cat
+John 2 0
+Bill 0 1
+Mary 1 1
+Lisbeth 0 0
+Kevin 0 2
+Donald 1 0
+DROP TABLE pivet;
+#
+# Adding a "dump" column
+#
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+other INT NOT NULL DEFAULT 0 FLAG=2)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+name dog cat other
+John 2 0 0
+Bill 0 1 0
+Mary 1 1 0
+Lisbeth 0 0 2
+Kevin 0 2 6
+Donald 1 0 3
+DROP TABLE pivet;
+DROP TABLE pets;
+#
+# MDEV-5734
+#
+CREATE TABLE fruit (
+`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+`name` varchar(32) NOT NULL,
+`cnt` int(11) DEFAULT NULL,
+PRIMARY KEY (`id`)
+) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
+INSERT INTO fruit VALUES (1,'apple',1),(2,'banana',1),(3,'apple',2),(4,'cherry',4),(5,'durazno',2);
+SELECT * FROM fruit;
+id name cnt
+1 apple 1
+2 banana 1
+3 apple 2
+4 cherry 4
+5 durazno 2
+CREATE TABLE fruit_pivot ENGINE=CONNECT TABLE_TYPE=pivot TABNAME=fruit;
+SELECT * FROM fruit_pivot;
+id apple banana cherry durazno
+1 1 0 0 0
+2 0 1 0 0
+3 2 0 0 0
+4 0 0 4 0
+5 0 0 0 2
+DROP TABLE fruit_pivot;
+DROP TABLE fruit;
diff --git a/storage/connect/mysql-test/connect/r/rest.result b/storage/connect/mysql-test/connect/r/rest.result
new file mode 100644
index 00000000..3c4ec80c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/rest.result
@@ -0,0 +1,19 @@
+#
+# Testing REST query
+#
+CREATE TABLE t1
+ENGINE=CONNECT DATA_CHARSET=utf8 TABLE_TYPE=JSON FILE_NAME='users.json'
+HTTP='http://jsonplaceholder.typicode.com/users';
+SELECT * FROM t1;
+id name username email address_street address_suite address_city address_zipcode address_geo_lat address_geo_lng phone website company_name company_catchPhrase company_bs
+1 Leanne Graham Bret Sincere@april.biz Kulas Light Apt. 556 Gwenborough 92998-3874 -37.3159 81.1496 1-770-736-8031 x56442 hildegard.org Romaguera-Crona Multi-layered client-server neural-net harness real-time e-markets
+2 Ervin Howell Antonette Shanna@melissa.tv Victor Plains Suite 879 Wisokyburgh 90566-7771 -43.9509 -34.4618 010-692-6593 x09125 anastasia.net Deckow-Crist Proactive didactic contingency synergize scalable supply-chains
+3 Clementine Bauch Samantha Nathan@yesenia.net Douglas Extension Suite 847 McKenziehaven 59590-4157 -68.6102 -47.0653 1-463-123-4447 ramiro.info Romaguera-Jacobson Face to face bifurcated interface e-enable strategic applications
+4 Patricia Lebsack Karianne Julianne.OConner@kory.org Hoeger Mall Apt. 692 South Elvis 53919-4257 29.4572 -164.2990 493-170-9623 x156 kale.biz Robel-Corkery Multi-tiered zero tolerance productivity transition cutting-edge web services
+5 Chelsey Dietrich Kamren Lucio_Hettinger@annie.ca Skiles Walks Suite 351 Roscoeview 33263 -31.8129 62.5342 (254)954-1289 demarco.info Keebler LLC User-centric fault-tolerant solution revolutionize end-to-end systems
+6 Mrs. Dennis Schulist Leopoldo_Corkery Karley_Dach@jasper.info Norberto Crossing Apt. 950 South Christy 23505-1337 -71.4197 71.7478 1-477-935-8478 x6430 ola.org Considine-Lockman Synchronised bottom-line interface e-enable innovative applications
+7 Kurtis Weissnat Elwyn.Skiles Telly.Hoeger@billy.biz Rex Trail Suite 280 Howemouth 58804-1099 24.8918 21.8984 210.067.6132 elvis.io Johns Group Configurable multimedia task-force generate enterprise e-tailers
+8 Nicholas Runolfsdottir V Maxime_Nienow Sherwood@rosamond.me Ellsworth Summit Suite 729 Aliyaview 45169 -14.3990 -120.7677 586.493.6943 x140 jacynthe.com Abernathy Group Implemented secondary concept e-enable extensible e-tailers
+9 Glenna Reichert Delphine Chaim_McDermott@dana.io Dayna Park Suite 449 Bartholomebury 76495-3109 24.6463 -168.8889 (775)976-6794 x41206 conrad.com Yost and Sons Switchable contextually-based project aggregate real-time technologies
+10 Clementina DuBuque Moriah.Stanton Rey.Padberg@karina.biz Kattie Turnpike Suite 198 Lebsackbury 31428-2261 -38.2386 57.2232 024-648-3804 ambrose.net Hoeger LLC Centralized empowering task-force target end-to-end models
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/secure_file_priv.result b/storage/connect/mysql-test/connect/r/secure_file_priv.result
new file mode 100644
index 00000000..4acc0fd3
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/secure_file_priv.result
@@ -0,0 +1,8 @@
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='DATADIR/t1.dbf';
+ERROR HY000: The MariaDB server is running with the --secure-file-priv option so it cannot execute this statement
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='SECUREDATADIR/t1.dbf';
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/tbl.result b/storage/connect/mysql-test/connect/r/tbl.result
new file mode 100644
index 00000000..d3d1c550
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/tbl.result
@@ -0,0 +1,143 @@
+#
+# Checking TBL tables
+#
+CREATE TABLE t1 (
+a INT NOT NULL,
+message CHAR(10)) ENGINE=connect;
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+Warning 1105 No file name. Table will use t1.dos
+INSERT INTO t1 VALUES (1,'Testing'),(2,'dos table'),(3,'t1');
+SELECT * FROM t1;
+a message
+1 Testing
+2 dos table
+3 t1
+CREATE TABLE t2 (
+a INT NOT NULL,
+message CHAR(10)) ENGINE=connect TABLE_TYPE=BIN;
+Warnings:
+Warning 1105 No file name. Table will use t2.bin
+INSERT INTO t2 VALUES (1,'Testing'),(2,NULL),(3,'t2');
+SELECT * FROM t2;
+a message
+1 Testing
+2 NULL
+3 t2
+CREATE TABLE t3 (
+a INT NOT NULL,
+message CHAR(10)) ENGINE=connect TABLE_TYPE=CSV;
+Warnings:
+Warning 1105 No file name. Table will use t3.csv
+INSERT INTO t3 VALUES (1,'Testing'),(2,'csv table'),(3,'t3');
+SELECT * FROM t3;
+a message
+1 Testing
+2 csv table
+3 t3
+CREATE TABLE t4 (
+ta INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+message CHAR(20)) ENGINE=MyISAM;
+INSERT INTO t4 (message) VALUES ('Testing'),('myisam table'),('t4');
+SELECT * FROM t4;
+ta message
+1 Testing
+2 myisam table
+3 t4
+CREATE TABLE total (tabname CHAR(8) NOT NULL SPECIAL='TABID', ta TINYINT NOT NULL FLAG=1, message CHAR(20)) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2,t3,t4' OPTION_LIST='port=PORT';
+SELECT * FROM total;
+tabname ta message
+t1 1 Testing
+t1 2 dos table
+t1 3 t1
+t2 1 Testing
+t2 2 NULL
+t2 3 t2
+t3 1 Testing
+t3 2 csv table
+t3 3 t3
+t4 1 Testing
+t4 2 myisam table
+t4 3 t4
+SELECT * FROM total WHERE tabname = 't2';
+tabname ta message
+t2 1 Testing
+t2 2 NULL
+t2 3 t2
+SELECT * FROM total WHERE tabname = 't2' AND ta = 3;
+tabname ta message
+t2 3 t2
+SELECT * FROM total WHERE tabname IN ('t1','t4');
+tabname ta message
+t1 1 Testing
+t1 2 dos table
+t1 3 t1
+t4 1 Testing
+t4 2 myisam table
+t4 3 t4
+SELECT * FROM total WHERE ta = 3 AND tabname IN ('t1','t2');
+tabname ta message
+t1 3 t1
+t2 3 t2
+SELECT * FROM total WHERE tabname <> 't2';
+tabname ta message
+t1 1 Testing
+t1 2 dos table
+t1 3 t1
+t3 1 Testing
+t3 2 csv table
+t3 3 t3
+t4 1 Testing
+t4 2 myisam table
+t4 3 t4
+SELECT * FROM total WHERE tabname != 't2' AND ta = 3;
+tabname ta message
+t1 3 t1
+t3 3 t3
+t4 3 t4
+SELECT * FROM total WHERE tabname NOT IN ('t2','t3');
+tabname ta message
+t1 1 Testing
+t1 2 dos table
+t1 3 t1
+t4 1 Testing
+t4 2 myisam table
+t4 3 t4
+SELECT * FROM total WHERE ta = 3 AND tabname IN ('t2','t3');
+tabname ta message
+t2 3 t2
+t3 3 t3
+SELECT * FROM total WHERE ta = 3 OR tabname IN ('t2','t4');
+tabname ta message
+t1 3 t1
+t2 1 Testing
+t2 2 NULL
+t2 3 t2
+t3 3 t3
+t4 1 Testing
+t4 2 myisam table
+t4 3 t4
+SELECT * FROM total WHERE NOT tabname = 't2';
+tabname ta message
+t1 1 Testing
+t1 2 dos table
+t1 3 t1
+t3 1 Testing
+t3 2 csv table
+t3 3 t3
+t4 1 Testing
+t4 2 myisam table
+t4 3 t4
+SELECT * FROM total WHERE tabname = 't2' OR tabname = 't1';
+tabname ta message
+t1 1 Testing
+t1 2 dos table
+t1 3 t1
+t2 1 Testing
+t2 2 NULL
+t2 3 t2
+DROP TABLE total;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
diff --git a/storage/connect/mysql-test/connect/r/tbl_thread.result b/storage/connect/mysql-test/connect/r/tbl_thread.result
new file mode 100644
index 00000000..3526fc43
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/tbl_thread.result
@@ -0,0 +1,165 @@
+connect master,127.0.0.1,root,,test,$MASTER_MYPORT,;
+connect slave,127.0.0.1,root,,test,$SLAVE_MYPORT,;
+connection master;
+CREATE DATABASE connect;
+connection slave;
+CREATE DATABASE connect;
+connection default;
+#
+# Checking thread TBL tables
+#
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+a b
+0 test00
+1 test01
+2 test02
+3 test03
+connection master;
+CREATE TABLE rt2 (a int, b char(10));
+INSERT INTO rt2 VALUES (4,'test04'),(5,'test05'),(6,'test06'),(7,'test07');
+SELECT * FROM rt2;
+a b
+4 test04
+5 test05
+6 test06
+7 test07
+connection slave;
+USE test;
+CREATE TABLE rt3 (a int, b char(10));
+INSERT INTO rt3 VALUES (8,'test08'),(9,'test09'),(10,'test10'),(11,'test11');
+SELECT * FROM rt3;
+a b
+8 test08
+9 test09
+10 test10
+11 test11
+CREATE TABLE rt4 (a int, b char(10));
+INSERT INTO rt4 VALUES (12,'test12'),(13,'test13'),(14,'test14'),(15,'test15');
+SELECT * FROM rt4;
+a b
+12 test12
+13 test13
+14 test14
+15 test15
+CREATE TABLE rt5 (a int, b char(10));
+INSERT INTO rt5 VALUES (16,'test16'),(17,'test17'),(18,'test18'),(19,'test19');
+SELECT * FROM rt5;
+a b
+16 test16
+17 test17
+18 test18
+19 test19
+connection default;
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:MASTER_PORT/test/rt2';
+SELECT * FROM t2;
+a b
+4 test04
+5 test05
+6 test06
+7 test07
+CREATE TABLE t3 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/rt3';
+SELECT * FROM t3;
+a b
+8 test08
+9 test09
+10 test10
+11 test11
+CREATE TABLE t4 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/rt4';
+SELECT * FROM t4;
+a b
+12 test12
+13 test13
+14 test14
+15 test15
+CREATE TABLE t5 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/rt5';
+SELECT * FROM t5;
+a b
+16 test16
+17 test17
+18 test18
+19 test19
+CREATE TABLE total (a int, b char(10))
+ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2,t3,t4,t5'
+OPTION_LIST='thread=yes,port=PORT';
+set connect_xtrace=96;
+SELECT * FROM total order by a desc;
+a b
+19 test19
+18 test18
+17 test17
+16 test16
+15 test15
+14 test14
+13 test13
+12 test12
+11 test11
+10 test10
+9 test09
+8 test08
+7 test07
+6 test06
+5 test05
+4 test04
+3 test03
+2 test02
+1 test01
+0 test00
+set connect_xtrace=0;
+connection master;
+DROP TABLE rt2;
+connection slave;
+DROP TABLE rt3,rt4,rt5;
+connection default;
+DROP TABLE t1,t2,t3,t4,t5,total;
+#
+# Old thread TBL tables test modified
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL SRCDEF='select 11 as v' OPTION_LIST='port=MASTER_PORT';
+SELECT * FROM t1;
+v
+11
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL SRCDEF='select 22 as v' OPTION_LIST='port=SLAVE_PORT';
+SELECT * FROM t2;
+v
+22
+CREATE TABLE total (v BIGINT(20) UNSIGNED NOT NULL) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2' OPTION_LIST='thread=yes,port=PORT';;
+set connect_xtrace=96;
+SELECT * FROM total order by v desc;
+v
+22
+11
+set connect_xtrace=0;
+DROP TABLE t1,t2,total;
+#
+# Old thread TBL tables test not modified (suppressed until MDEV-10179 is fixed)
+#
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL SRCDEF='select 11 as v';
+SELECT * FROM t1;
+v
+11
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL SRCDEF='select 22 as v';
+SELECT * FROM t2;
+v
+22
+CREATE TABLE total (v BIGINT(20) UNSIGNED NOT NULL) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2' OPTION_LIST='thread=yes,port=PORT';;
+set connect_xtrace=96;
+SELECT * FROM total order by v desc;
+v
+22
+11
+set connect_xtrace=0;
+DROP TABLE total;
+DROP TABLE t1;
+DROP TABLE t2;
+connection master;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+connection slave;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
diff --git a/storage/connect/mysql-test/connect/r/temporary.result b/storage/connect/mysql-test/connect/r/temporary.result
new file mode 100644
index 00000000..c4e992f2
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/temporary.result
@@ -0,0 +1,6 @@
+CREATE TEMPORARY TABLE t1 (a int not null)
+ENGINE=CONNECT table_type=MYSQL CONNECTION='mysql://root@127.0.0.1/test/t2';
+ERROR HY000: Table storage engine 'CONNECT' does not support the create option 'TEMPORARY'
+CREATE TEMPORARY TABLE t1
+ENGINE=CONNECT table_type=MYSQL CONNECTION='mysql://root@127.0.0.1/test/t2';
+ERROR HY000: Table storage engine 'CONNECT' does not support the create option 'TEMPORARY'
diff --git a/storage/connect/mysql-test/connect/r/type_inet6.result b/storage/connect/mysql-test/connect/r/type_inet6.result
new file mode 100644
index 00000000..495a7a51
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/type_inet6.result
@@ -0,0 +1,15 @@
+#
+# MDEV-21764 CONNECT table with INET6 field produces warnings upon SELECT
+#
+CREATE TABLE t1 (a INET6) ENGINE=CONNECT TABLE_TYPE=DOS;
+Warnings:
+Warning 1105 No file name. Table will use t1.dos
+INSERT INTO t1 VALUES ('::');
+INSERT INTO t1 VALUES ('::ffff');
+INSERT INTO t1 VALUES ('ffff::ffff');
+SELECT * FROM t1;
+a
+::
+::ffff
+ffff::ffff
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/unsigned.result b/storage/connect/mysql-test/connect/r/unsigned.result
new file mode 100644
index 00000000..ca5a5ffe
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/unsigned.result
@@ -0,0 +1,61 @@
+#
+# Testing unsigned types
+#
+DROP TABLE IF EXISTS t1;
+Warnings:
+Note 1051 Unknown table 'test.t1'
+CREATE TABLE t1 (
+a TINYINT UNSIGNED NOT NULL,
+b SMALLINT ZEROFILL NOT NULL,
+c INT UNSIGNED NOT NULL,
+d BIGINT UNSIGNED NOT NULL,
+e CHAR(32) NOT NULL DEFAULT '???') ENGINE=CONNECT TABLE_TYPE=FIX;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+DESCRIBE t1;
+Field Type Null Key Default Extra
+a tinyint(3) unsigned NO NULL
+b smallint(5) unsigned zerofill NO NULL
+c int(10) unsigned NO NULL
+d bigint(20) unsigned NO NULL
+e char(32) NO ???
+INSERT INTO t1(a,b,c,d) VALUES(255,65535,4294967295,18446744073709551615);
+SELECT * FROM t1;
+a b c d e
+255 65535 4294967295 18446744073709551615 ???
+UPDATE t1 SET e = d;
+SELECT * FROM t1;
+a b c d e
+255 65535 4294967295 18446744073709551615 18446744073709551615
+UPDATE IGNORE t1 SET c = d;
+Warnings:
+Warning 1264 Out of range value for column 'c' at row 1
+SELECT * FROM t1;
+a b c d e
+255 65535 4294967295 18446744073709551615 18446744073709551615
+UPDATE IGNORE t1 SET c = e;
+Warnings:
+Warning 1264 Out of range value for column 'c' at row 1
+SELECT * FROM t1;
+a b c d e
+255 65535 4294967295 18446744073709551615 18446744073709551615
+UPDATE t1 SET d = e;
+SELECT * FROM t1;
+a b c d e
+255 65535 4294967295 18446744073709551615 18446744073709551615
+DROP TABLE IF EXISTS t2;
+Warnings:
+Note 1051 Unknown table 'test.t2'
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=PROXY TABNAME=t1;
+DESCRIBE t2;
+Field Type Null Key Default Extra
+a tinyint(3) unsigned NO NULL
+b smallint(5) unsigned zerofill NO NULL
+c int(10) unsigned NO NULL
+d bigint(20) unsigned NO NULL
+e char(32) NO NULL
+SELECT * FROM t2;
+a b c d e
+255 65535 4294967295 18446744073709551615 18446744073709551615
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/upd.result b/storage/connect/mysql-test/connect/r/upd.result
new file mode 100644
index 00000000..8faf0089
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/upd.result
@@ -0,0 +1,1629 @@
+SET sql_mode = 'NO_ENGINE_SUBSTITUTION';
+CREATE TABLE employee
+(
+serialno CHAR(5) NOT NULL,
+name VARCHAR(12) NOT NULL FLAG=6,
+sex TINYINT(1) NOT NULL,
+title VARCHAR(15) NOT NULL FLAG=20,
+manager CHAR(5) NOT NULL,
+department CHAR(4) NOT NULL FLAG=41,
+secretary CHAR(5) NOT NULL FLAG=46,
+salary DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=connect TABLE_TYPE=fix FILE_NAME='employee.dat' ENDING=1;
+SELECT * FROM employee;
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+CREATE PROCEDURE test.tst_up() DETERMINISTIC
+BEGIN
+SELECT * FROM t1;
+UPDATE t1 SET salary = salary + 1, title = 'RESEARCH' WHERE title = 'SCIENTIST';
+UPDATE t1 SET salary = salary + 1, title = 'TECHNICIAN' WHERE title = 'ENGINEER';
+UPDATE t1 SET title = 'PUPPET' WHERE name = 'TONGHO';
+UPDATE t1 SET salary = 0. WHERE title = 'XXX';
+SELECT * FROM t1;
+DELETE FROM t1 WHERE title = 'SECRETARY';
+DELETE FROM t1 WHERE title = 'DIRECTOR';
+DELETE FROM t1 WHERE title = 'TYPIST';
+SELECT * FROM t1;
+DELETE FROM t1 LIMIT 3;
+INSERT INTO t1(serialno, name, title, salary) VALUES('66666','NEWMAN','ENGINEER',10000.80);
+SELECT * FROM t1;
+DROP TABLE t1;
+END//
+#
+# Testing DOS table changes
+#
+CREATE TABLE t1 ENGINE=connect AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+Warning 1105 No file name. Table will use t1.dos
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing DOS table changes
+#
+CREATE TABLE t1 ENGINE=connect mapped=yes AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+Warning 1105 No file name. Table will use t1.dos
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing FIX table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=fix AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing FIX table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=fix mapped=yes AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing FIX table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=fix huge=yes AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing CSV table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=csv AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing CSV table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=csv mapped=yes AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing DBF table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=dbf AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.dbf
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing DBF table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=dbf mapped=yes AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.dbf
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing BIN table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=bin AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.bin
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing BIN table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=bin mapped=yes AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.bin
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing BIN table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=bin huge=yes AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.bin
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing VEC table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=vec MAX_ROWS=30 AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.vec
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing VEC table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=vec mapped=yes MAX_ROWS=30 AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.vec
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing VEC table changes
+#
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=vec huge=yes MAX_ROWS=30 AS SELECT * FROM employee;
+Warnings:
+Warning 1105 No file name. Table will use t1.vec
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN 0 ENGINEER 10000.80
+#
+# Testing INI table changes
+#
+CREATE TABLE t1
+(
+serialno CHAR(5) NOT NULL FLAG=1,
+name VARCHAR(12) NOT NULL,
+sex TINYINT(1),
+title VARCHAR(15) NOT NULL,
+manager CHAR(5),
+department CHAR(4),
+secretary CHAR(5),
+salary DOUBLE(8,2) NOT NULL
+) ENGINE=connect TABLE_TYPE=ini;
+Warnings:
+Warning 1105 No file name. Table will use t1.ini
+INSERT INTO t1 SELECT * FROM employee;
+CALL test.tst_up();
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 TECHNICIAN 31416 2452 11111 9001.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+serialno name sex title manager department secretary salary
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 RESEARCH 31416 2452 11111 8001.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 TECHNICIAN 70012 0318 24888 7401.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 PUPPET 70012 0318 24888 6801.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+31416 ORELLY 1 TECHNICIAN 87777 2452 11111 13401.00
+36666 BIGHORN 1 RESEARCH 31416 2452 11111 11001.00
+00137 BROWNY 1 TECHNICIAN 40567 0319 12345 10501.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 TECHNICIAN 40567 0319 12345 10001.00
+66666 NEWMAN NULL ENGINEER NULL NULL NULL 10000.80
+#
+# Testing XML table changes (must be in a separate test)
+#
+DROP PROCEDURE test.tst_up;
+DROP TABLE employee;
+SET sql_mode = DEFAULT;
diff --git a/storage/connect/mysql-test/connect/r/updelx.result b/storage/connect/mysql-test/connect/r/updelx.result
new file mode 100644
index 00000000..bb82afcc
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/updelx.result
@@ -0,0 +1,2570 @@
+#
+# Testing indexed UPDATE and DELETE for all table types
+#
+# CSV table
+CREATE TABLE t1 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=CSV AVG_ROW_LENGTH=6;
+Warnings:
+Warning 1105 No file name. Table will use t1.csv
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=NO BLOCK_SIZE=6;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+DROP TABLE t1;
+# DOS table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16))
+ENGINE=CONNECT TABLE_TYPE=DOS;
+Warnings:
+Warning 1105 No file name. Table will use t1.dos
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=NO BLOCK_SIZE=4;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+DROP TABLE t1;
+# FIX table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16) DISTRIB=CLUSTERED)
+ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=4;
+Warnings:
+Warning 1105 No file name. Table will use t1.fix
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=NO HUGE=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+DROP TABLE t1;
+# BIN table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16) DISTRIB=CLUSTERED)
+ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=8;
+Warnings:
+Warning 1105 No file name. Table will use t1.bin
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=NO HUGE=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+DROP TABLE t1;
+# DBF table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16))
+ENGINE=CONNECT TABLE_TYPE=DBF BLOCK_SIZE=12;
+Warnings:
+Warning 1105 No file name. Table will use t1.dbf
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+DROP TABLE t1;
+# VEC table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16))
+ENGINE=CONNECT TABLE_TYPE=VEC BLOCK_SIZE=6 MAX_ROWS=16;
+Warnings:
+Warning 1105 No file name. Table will use t1.vec
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=NO HUGE=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+DROP TABLE t1;
+# Split VEC table (outward)
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16))
+ENGINE=CONNECT TABLE_TYPE=VEC BLOCK_SIZE=6 FILE_NAME='tx.vec';
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+ALTER TABLE t1 MAPPED=YES;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 thirty five
+8 eight
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 sixty
+81 eighty one
+72 seventy two
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 big
+81 big
+72 big
+11 eleven
+1 one
+35 bof
+8 eight
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 ten
+40 forty
+60 updated
+81 big
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+id msg
+4 four
+7 seven
+10 twin
+40 forty
+60 updated
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+id msg
+60 sixty
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+40 forty
+60 sixty
+81 twin
+72 updated
+11 eleven
+1 one
+35 updated
+8 updated
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+id msg
+7 seven
+10 twin
+60 sixty
+81 twin
+72 updated
+1 one
+8 updated
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+msg
+seven
+twin
+twin
+updated
+updated
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+id
+7
+8
+10
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+id msg
+8 updated
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
+id msg
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/updelx2.result b/storage/connect/mysql-test/connect/r/updelx2.result
new file mode 100644
index 00000000..1ed3709f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/updelx2.result
@@ -0,0 +1,133 @@
+#
+# Testing multiple indexed UPDATE and DELETE
+#
+CREATE TABLE t1 (
+id INT(4) NOT NULL,
+msg VARCHAR(16) NOT NULL,
+INDEX IDM(id,msg))
+ENGINE=CONNECT TABLE_TYPE=DOS;
+Warnings:
+Warning 1105 No file name. Table will use t1.dos
+INSERT INTO t1 VALUES(1,'one'),(4, 'four'),(7,'seven'),(8,'eight'),(10,'ten'),(11,'eleven'),(40,'forty'),(35,'thirty five'),(60,'sixty'),(72,'seventy two'),(81,'eighty one');
+INSERT INTO t1 VALUES(1,'un'),(4, 'quatre'),(7,'sept'),(8,'huit'),(10,'dix'),(11,'onze'),(40,'quarante'),(35,'trente cinq'),(60,'soixante'),(72,'soixante douze'),(81,'quatrevingt un');
+SELECT * FROM t1 IGNORE INDEX (IDM);
+id msg
+1 one
+4 four
+7 seven
+8 eight
+10 ten
+11 eleven
+40 forty
+35 thirty five
+60 sixty
+72 seventy two
+81 eighty one
+1 un
+4 quatre
+7 sept
+8 huit
+10 dix
+11 onze
+40 quarante
+35 trente cinq
+60 soixante
+72 soixante douze
+81 quatrevingt un
+UPDATE t1 SET msg = 'dieci' WHERE id = 10;
+SELECT * FROM t1 IGNORE INDEX (IDM);
+id msg
+1 one
+4 four
+7 seven
+8 eight
+10 dieci
+11 eleven
+40 forty
+35 thirty five
+60 sixty
+72 seventy two
+81 eighty one
+1 un
+4 quatre
+7 sept
+8 huit
+10 dieci
+11 onze
+40 quarante
+35 trente cinq
+60 soixante
+72 soixante douze
+81 quatrevingt un
+UPDATE t1 SET msg = 'septante deux' WHERE id = 72;
+SELECT * FROM t1 IGNORE INDEX (IDM);
+id msg
+1 one
+4 four
+7 seven
+8 eight
+10 dieci
+11 eleven
+40 forty
+35 thirty five
+60 sixty
+72 septante deux
+81 eighty one
+1 un
+4 quatre
+7 sept
+8 huit
+10 dieci
+11 onze
+40 quarante
+35 trente cinq
+60 soixante
+72 septante deux
+81 quatrevingt un
+UPDATE t1 SET id=2, msg='deux' WHERE id=4 AND msg='quatre';
+SELECT * FROM t1 IGNORE INDEX (IDM);
+id msg
+1 one
+4 four
+7 seven
+8 eight
+10 dieci
+11 eleven
+40 forty
+35 thirty five
+60 sixty
+72 septante deux
+81 eighty one
+1 un
+2 deux
+7 sept
+8 huit
+10 dieci
+11 onze
+40 quarante
+35 trente cinq
+60 soixante
+72 septante deux
+81 quatrevingt un
+DELETE FROM t1 WHERE id IN (8,40);
+SELECT * FROM t1 IGNORE INDEX (IDM);
+id msg
+1 one
+4 four
+7 seven
+10 dieci
+11 eleven
+35 thirty five
+60 sixty
+72 septante deux
+81 eighty one
+1 un
+2 deux
+7 sept
+10 dieci
+11 onze
+35 trente cinq
+60 soixante
+72 septante deux
+81 quatrevingt un
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/vcol.result b/storage/connect/mysql-test/connect/r/vcol.result
new file mode 100644
index 00000000..e0fd3720
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/vcol.result
@@ -0,0 +1,29 @@
+create table t1 (
+#linenum int(6) not null default 0 special=rowid,
+name char(12) not null,
+city char(11) not null,
+birth date not null date_format='DD/MM/YYYY',
+hired date not null date_format='DD/MM/YYYY' flag=36,
+agehired int(3) as (floor(datediff(hired,birth)/365.25))
+)
+engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47 ending=1;
+select * from t1;
+name city birth hired agehired
+John Boston 1986-01-25 2010-06-02 24
+Henry Boston 1987-06-07 2008-04-01 20
+George San Jose 1981-08-10 2010-06-02 28
+Sam Chicago 1979-11-22 2007-10-10 27
+James Dallas 1992-05-13 2009-12-14 17
+Bill Boston 1986-09-11 2008-02-10 21
+drop table t1;
+create table t1 (
+#linenum int(6) not null default 0 special=rowid,
+name char(12) not null,
+city char(11) not null,
+birth date not null date_format='DD/MM/YYYY',
+hired date not null date_format='DD/MM/YYYY' flag=36,
+agehired int(3) as (floor(datediff(hired,birth)/365.25)),
+index (agehired)
+)
+engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47 ending=1;
+ERROR 42000: Table handler doesn't support NULL in given index. Please change column 'agehired' to be NOT NULL or use another handler
diff --git a/storage/connect/mysql-test/connect/r/vec.result b/storage/connect/mysql-test/connect/r/vec.result
new file mode 100644
index 00000000..51fb8aee
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/vec.result
@@ -0,0 +1,138 @@
+CREATE TABLE dir1 (
+spath VARCHAR(256) NOT NULL flag=1,
+fname VARCHAR(256) NOT NULL,
+ftype CHAR(4) NOT NULL,
+size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*vec*';
+CREATE TABLE t1
+(
+a INT NOT NULL,
+b CHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=VEC FILE_NAME='t1vec';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=VEC `FILE_NAME`='t1vec'
+SELECT * FROM t1;
+a b
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/t1vec1: No such file or directory
+Warning 1105 Open(rb) error 2 on DATADIR/test/t1vec2: No such file or directory
+INSERT INTO t1 VALUES (0,'test01'), (1,'test01'), (2,'test02'), (3,'test03');
+SELECT * FROM t1;
+a b
+0 test01
+1 test01
+2 test02
+3 test03
+SELECT a FROM t1;
+a
+0
+1
+2
+3
+SELECT b FROM t1;
+b
+test01
+test01
+test02
+test03
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+fname ftype size
+t1vec1 16
+t1vec2 40
+DROP TABLE t1;
+CREATE TABLE t1
+(
+a INT NOT NULL,
+b CHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=VEC FILE_NAME='t1vec' MAX_ROWS=10;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 MAX_ROWS=10 `TABLE_TYPE`=VEC `FILE_NAME`='t1vec'
+SELECT * FROM t1;
+a b
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/t1vec: No such file or directory
+SELECT a FROM t1;
+a
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/t1vec: No such file or directory
+SELECT b FROM t1;
+b
+Warnings:
+Warning 1105 Open(rb) error 2 on DATADIR/test/t1vec: No such file or directory
+INSERT INTO t1 VALUES (0,'test01'), (1,'test01'), (2,'test02'), (3,'test03');
+SELECT * FROM t1;
+a b
+0 test01
+1 test01
+2 test02
+3 test03
+SELECT a FROM t1;
+a
+0
+1
+2
+3
+SELECT b FROM t1;
+b
+test01
+test01
+test02
+test03
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+fname ftype size
+t1vec 1400
+t1vec .blk 8
+#
+# Testing READONLY
+#
+ALTER TABLE t1 READONLY=yes;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 MAX_ROWS=10 `TABLE_TYPE`=VEC `FILE_NAME`='t1vec' `READONLY`=yes
+INSERT INTO t1 VALUES (4,'test04');
+ERROR HY000: Table 't1' is read only
+UPDATE t1 SET b='test04' WHERE a=3;
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+DELETE FROM t1 WHERE a=3;
+ERROR HY000: Got error 174 'Cannot modify this read/only protected table' from CONNECT
+TRUNCATE TABLE t1;
+ERROR HY000: Table 't1' is read only
+ALTER TABLE t1 READONLY=no;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` char(10) NOT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 MAX_ROWS=10 `TABLE_TYPE`=VEC `FILE_NAME`='t1vec' `READONLY`=no
+INSERT INTO t1 VALUES (4,'test04');
+UPDATE t1 SET b='test04a' WHERE a=4;
+DELETE FROM t1 WHERE a=0;
+SELECT * FROM t1;
+a b
+1 test01
+2 test02
+3 test03
+4 test04a
+TRUNCATE TABLE t1;
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+fname ftype size
+t1vec 0
+t1vec .blk 8
+SELECT * FROM t1;
+a b
+DROP TABLE t1;
+#
+# Clean up
+#
+DROP TABLE dir1;
diff --git a/storage/connect/mysql-test/connect/r/xcol.result b/storage/connect/mysql-test/connect/r/xcol.result
new file mode 100644
index 00000000..94d1e061
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xcol.result
@@ -0,0 +1,117 @@
+#
+# Make the children list table
+#
+CREATE TABLE chlist (
+mother char(12) NOT NULL COMMENT 'The mother of the listed children',
+children varchar(30) DEFAULT NULL COMMENT 'The comma separated list of children'
+) ENGINE=CONNECT;
+Warnings:
+Warning 1105 No table_type. Will be set to DOS
+Warning 1105 No file name. Table will use chlist.dos
+INSERT INTO chlist VALUES('Sophia','Vivian, Antony');
+INSERT INTO chlist VALUES('Lisbeth','Lucy,Charles,Diana');
+INSERT INTO chlist VALUES('Corinne',NULL);
+INSERT INTO chlist VALUES('Claude','Marc');
+INSERT INTO chlist VALUES('Janet','Arthur,Sandra,Peter,John');
+SELECT * FROM chlist;
+mother children
+Sophia Vivian, Antony
+Lisbeth Lucy,Charles,Diana
+Corinne NULL
+Claude Marc
+Janet Arthur,Sandra,Peter,John
+#
+# Checking XCOL tables
+#
+CREATE TABLE child ENGINE=CONNECT TABLE_TYPE=XCOL TABNAME=chlist OPTION_LIST='colname=children';
+SELECT * FROM child;
+mother children
+Sophia Vivian
+Sophia Antony
+Lisbeth Lucy
+Lisbeth Charles
+Lisbeth Diana
+Corinne NULL
+Claude Marc
+Janet Arthur
+Janet Sandra
+Janet Peter
+Janet John
+SELECT * FROM child ORDER BY mother;
+mother children
+Claude Marc
+Corinne NULL
+Janet Peter
+Janet Sandra
+Janet Arthur
+Janet John
+Lisbeth Diana
+Lisbeth Charles
+Lisbeth Lucy
+Sophia Antony
+Sophia Vivian
+SELECT * FROM child ORDER BY children;
+mother children
+Corinne NULL
+Sophia Antony
+Janet Arthur
+Lisbeth Charles
+Lisbeth Diana
+Janet John
+Lisbeth Lucy
+Claude Marc
+Janet Peter
+Janet Sandra
+Sophia Vivian
+SELECT mother FROM child;
+mother
+Sophia
+Lisbeth
+Corinne
+Claude
+Janet
+SELECT mother, COUNT(*) FROM child GROUP BY mother;
+mother COUNT(*)
+Claude 1
+Corinne 1
+Janet 1
+Lisbeth 1
+Sophia 1
+SELECT mother, COUNT(children) FROM child GROUP BY mother;
+mother COUNT(children)
+Claude 1
+Corinne 0
+Janet 4
+Lisbeth 3
+Sophia 2
+#
+# Test using special columns
+#
+CREATE TABLE `child2` (
+`row` int NOT NULL SPECIAL=ROWID,
+`num` int NOT NULL SPECIAL=ROWNUM,
+`mother` varchar(12) NOT NULL COMMENT 'The mother of the children',
+`child` varchar(12) NOT NULL COMMENT 'The child name' FLAG=2
+) ENGINE=CONNECT TABLE_TYPE=XCOL TABNAME=chlist `OPTION_LIST`='colname=child';
+SELECT * FROM child2;
+row num mother child
+1 1 Sophia Vivian
+2 2 Sophia Antony
+3 1 Lisbeth Lucy
+4 2 Lisbeth Charles
+5 3 Lisbeth Diana
+7 1 Claude Marc
+8 1 Janet Arthur
+9 2 Janet Sandra
+10 3 Janet Peter
+11 4 Janet John
+# List only first child
+SELECT mother, child FROM child2 where num = 1;
+mother child
+Sophia Vivian
+Lisbeth Lucy
+Claude Marc
+Janet Arthur
+DROP TABLE child;
+DROP TABLE chlist;
+DROP TABLE child2;
diff --git a/storage/connect/mysql-test/connect/r/xml.result b/storage/connect/mysql-test/connect/r/xml.result
new file mode 100644
index 00000000..575c903b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml.result
@@ -0,0 +1,392 @@
+SET NAMES utf8;
+#
+# Testing tag values
+#
+CREATE TABLE t1
+(
+AUTHOR CHAR(50),
+TITLE CHAR(32),
+TRANSLATOR CHAR(40),
+PUBLISHER CHAR(40),
+DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT * FROM t1;
+AUTHOR Jean-Christophe Bernadac
+TITLE Construire une application XML
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+AUTHOR William J. Pardi
+TITLE XML en Action
+TRANSLATOR James Guerin
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+DROP TABLE t1;
+#
+# Testing that tag names are case sensitive
+#
+CREATE TABLE t1
+(
+author CHAR(50),
+TITLE CHAR(32),
+TRANSLATOR CHAR(40),
+PUBLISHER CHAR(40),
+DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT * FROM t1;
+author NULL
+TITLE Construire une application XML
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+author NULL
+TITLE XML en Action
+TRANSLATOR James Guerin
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+DROP TABLE t1;
+#
+# Testing attribute values
+#
+CREATE TABLE t1 (
+ISBN CHAR(15),
+LANG CHAR(2),
+SUBJECT CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='Coltype=@,xmlsup=domdoc';
+SELECT * FROM t1;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+DROP TABLE t1;
+#
+# Testing that attribute names are case sensitive
+#
+CREATE TABLE t1 (
+isbn CHAR(15),
+LANG CHAR(2),
+SUBJECT CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='Coltype=@,xmlsup=domdoc';
+SELECT * FROM t1;
+isbn NULL
+LANG fr
+SUBJECT applications
+isbn NULL
+LANG fr
+SUBJECT applications
+DROP TABLE t1;
+#
+# Testing mixed tag and attribute values
+#
+CREATE TABLE t1 (
+ISBN CHAR(15) FIELD_FORMAT='@',
+LANG CHAR(2) FIELD_FORMAT='@',
+SUBJECT CHAR(32) FIELD_FORMAT='@',
+AUTHOR CHAR(50),
+TITLE CHAR(32),
+TRANSLATOR CHAR(40),
+PUBLISHER CHAR(40),
+DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT * FROM t1;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR Jean-Christophe Bernadac
+TITLE Construire une application XML
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+AUTHOR William J. Pardi
+TITLE XML en Action
+TRANSLATOR James Guerin
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+DROP TABLE t1;
+#
+# Testing INSERT on mixed tag and attribute values
+#
+CREATE TABLE t1 (
+ISBN CHAR(15) FIELD_FORMAT='@',
+LANG CHAR(2) FIELD_FORMAT='@',
+SUBJECT CHAR(32) FIELD_FORMAT='@',
+AUTHOR CHAR(50),
+TITLE CHAR(32),
+TRANSLATOR CHAR(40),
+PUBLISHER CHAR(40),
+DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.xml'
+ TABNAME='BIBLIO'
+ OPTION_LIST='rownode=BOOK,xmlsup=domdoc';
+INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB)
+VALUES('9782212090529','fr','général','Alain Michard',
+'XML, Langage et Applications','Eyrolles Paris',1998);
+SELECT * FROM t1;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR Jean-Christophe Bernadac
+TITLE Construire une application XML
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+AUTHOR William J. Pardi
+TITLE XML en Action
+TRANSLATOR James Guerin
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+ISBN 9782212090529
+LANG fr
+SUBJECT général
+AUTHOR Alain Michard
+TITLE XML, Langage et Applications
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1998
+SELECT LOAD_FILE('MYSQLD_DATADIR/test/xsample2.xml') AS xml;
+xml <?xml version="1.0" encoding="UTF-8"?>
+<BIBLIO SUBJECT="XML">
+ <BOOK ISBN="9782212090819" LANG="fr" SUBJECT="applications">
+ <AUTHOR>
+ <FIRSTNAME>Jean-Christophe</FIRSTNAME>
+ <LASTNAME>Bernadac</LASTNAME>
+ </AUTHOR>
+ <AUTHOR>
+ <FIRSTNAME>François</FIRSTNAME>
+ <LASTNAME>Knab</LASTNAME>
+ </AUTHOR>
+ <TITLE>Construire une application XML</TITLE>
+ <PUBLISHER>
+ <NAME>Eyrolles</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>1999</DATEPUB>
+ </BOOK>
+ <BOOK ISBN="9782840825685" LANG="fr" SUBJECT="applications">
+ <AUTHOR>
+ <FIRSTNAME>William J.</FIRSTNAME>
+ <LASTNAME>Pardi</LASTNAME>
+ </AUTHOR>
+ <TRANSLATOR PREFIX="adapté de l'anglais par">
+ <FIRSTNAME>James</FIRSTNAME>
+ <LASTNAME>Guerin</LASTNAME>
+ </TRANSLATOR>
+ <TITLE>XML en Action</TITLE>
+ <PUBLISHER>
+ <NAME>Microsoft Press</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>1999</DATEPUB>
+ </BOOK>
+ <BOOK ISBN="9782212090529" LANG="fr" SUBJECT="général">
+ <AUTHOR>Alain Michard</AUTHOR>
+ <TITLE>XML, Langage et Applications</TITLE>
+ <PUBLISHER>Eyrolles Paris</PUBLISHER>
+ <DATEPUB>1998</DATEPUB>
+ </BOOK>
+</BIBLIO>
+
+DROP TABLE t1;
+#
+# Testing XPath
+#
+CREATE TABLE t1 (
+isbn CHAR(15) FIELD_FORMAT='@ISBN',
+language CHAR(2) FIELD_FORMAT='@LANG',
+subject CHAR(32) FIELD_FORMAT='@SUBJECT',
+authorfn CHAR(20) FIELD_FORMAT='AUTHOR/FIRSTNAME',
+authorln CHAR(20) FIELD_FORMAT='AUTHOR/LASTNAME',
+title CHAR(32) FIELD_FORMAT='TITLE',
+translated CHAR(32) FIELD_FORMAT='TRANSLATOR/@PREFIX',
+tranfn CHAR(20) FIELD_FORMAT='TRANSLATOR/FIRSTNAME',
+tranln CHAR(20) FIELD_FORMAT='TRANSLATOR/LASTNAME',
+publisher CHAR(20) FIELD_FORMAT='PUBLISHER/NAME',
+location CHAR(20) FIELD_FORMAT='PUBLISHER/PLACE',
+year INT(4) FIELD_FORMAT='DATEPUB'
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=domdoc';
+SELECT * FROM t1;
+isbn 9782212090819
+language fr
+subject applications
+authorfn Jean-Christophe
+authorln Bernadac
+title Construire une application XML
+translated NULL
+tranfn NULL
+tranln NULL
+publisher Eyrolles
+location Paris
+year 1999
+isbn 9782840825685
+language fr
+subject applications
+authorfn William J.
+authorln Pardi
+title XML en Action
+translated adapté de l'anglais par
+tranfn James
+tranln Guerin
+publisher Microsoft Press
+location Paris
+year 1999
+SELECT isbn, title, translated, tranfn, tranln, location FROM t1
+WHERE translated <> '';
+isbn 9782840825685
+title XML en Action
+translated adapté de l'anglais par
+tranfn James
+tranln Guerin
+location Paris
+DROP TABLE t1;
+#
+# Testing that XPath is case sensitive
+#
+CREATE TABLE t1
+(
+isbn CHAR(15) FIELD_FORMAT='@isbn'
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=domdoc';
+SELECT * FROM t1;
+isbn NULL
+isbn NULL
+DROP TABLE t1;
+#
+# Testing character sets
+#
+CREATE TABLE t1
+(
+c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc'
+ DATA_CHARSET=latin1;
+ERROR HY000: DATA_CHARSET='latin1' is not supported for TABLE_TYPE=XML
+CREATE TABLE t1
+(
+c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc'
+ DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table t1
+Create Table CREATE TABLE `t1` (
+ `c` char(16) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=XML `FILE_NAME`='latin1.xml' `OPTION_LIST`='xmlsup=domdoc' `DATA_CHARSET`=utf8
+SELECT c, HEX(c) FROM t1;
+c ÃÂÃÄÅÆÇ
+HEX(c) C1C2C3C4C5C6C7
+DROP TABLE t1;
+CREATE TABLE t1
+(
+c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT c, HEX(c) FROM t1;
+c ÃÂÃÄÅÆÇ
+HEX(c) C1C2C3C4C5C6C7
+DROP TABLE t1;
+CREATE TABLE t1
+(
+c CHAR(16) CHARACTER SET utf8
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT c, HEX(c) FROM t1;
+c ÃÂÃÄÅÆÇ
+HEX(c) C381C382C383C384C385C386C387
+DROP TABLE t1;
+#
+# Conversion from latin1 to cp1251 produces a warning.
+# Question marks are returned.
+#
+CREATE TABLE t1
+(
+c CHAR(16) CHARACTER SET cp1251
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT c, HEX(c) FROM t1;
+c ???????
+HEX(c) 3F3F3F3F3F3F3F
+Warnings:
+Level Warning
+Code 1366
+Message Incorrect string value: '\xC3\x81\xC3\x82\xC3\x83...' for column `test`.`t1`.`c` at row 1
+Level Warning
+Code 1105
+Message Out of range value ÃÂÃÄÅÆÇ for column 'c' at row 1
+DROP TABLE t1;
+#
+# Testing Cyrillic
+#
+#
+# Testing that the underlying file is created with a proper Encoding
+#
+CREATE TABLE t1 (node VARCHAR(50))
+CHARACTER SET latin1
+ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=utf-8';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+SELECT node, hex(node) FROM t1;
+node ÀÃÂÃ
+hex(node) C0C1C2C3
+DROP TABLE t1;
+SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
+SELECT LEFT(@a,38);
+LEFT(@a,38) <?xml version="1.0" encoding="utf-8"?>
+SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node'));
+HEX(EXTRACTVALUE(@a,'/t1/line/node')) C380C381C382C383
+CREATE TABLE t1 (node VARCHAR(50))
+CHARACTER SET latin1
+ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=iso-8859-1';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+SELECT node, hex(node) FROM t1;
+node ÀÃÂÃ
+hex(node) C0C1C2C3
+DROP TABLE t1;
+SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
+SELECT LEFT(@a,43);
+LEFT(@a,43) <?xml version="1.0" encoding="iso-8859-1"?>
+SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node'));
+HEX(EXTRACTVALUE(@a,'/t1/line/node')) C0C1C2C3
+#
+# Testing XML entities
+#
+CREATE TABLE t1 (node VARCHAR(50))
+CHARACTER SET utf8
+ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=iso-8859-1';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3);
+Warnings:
+Level Warning
+Code 1105
+Message warning about characters outside of iso-8859-1
+INSERT INTO t1 VALUES ('&<>"\'');
+SELECT node, hex(node) FROM t1;
+node &<>"'
+hex(node) 263C3E2227
+DROP TABLE t1;
+SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
+SELECT CAST(@a AS CHAR CHARACTER SET latin1);
+CAST(@a AS CHAR CHARACTER SET latin1) <?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Created by the MariaDB CONNECT Storage Engine-->
+<t1>
+ <line>
+ <node>&amp;&lt;&gt;"'</node>
+ </line>
+</t1>
+
diff --git a/storage/connect/mysql-test/connect/r/xml2.result b/storage/connect/mysql-test/connect/r/xml2.result
new file mode 100644
index 00000000..891c6e6f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml2.result
@@ -0,0 +1,400 @@
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+SET NAMES utf8;
+#
+# Testing tag values
+#
+CREATE TABLE t1
+(
+AUTHOR CHAR(50),
+TITLE CHAR(32),
+TRANSLATOR CHAR(40),
+PUBLISHER CHAR(40),
+DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT * FROM t1;
+AUTHOR Jean-Christophe Bernadac
+TITLE Construire une application XML
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+AUTHOR William J. Pardi
+TITLE XML en Action
+TRANSLATOR James Guerin
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+DROP TABLE t1;
+#
+# Testing that tag names are case sensitive
+#
+CREATE TABLE t1
+(
+author CHAR(50),
+TITLE CHAR(32),
+TRANSLATOR CHAR(40),
+PUBLISHER CHAR(40),
+DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT * FROM t1;
+author NULL
+TITLE Construire une application XML
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+author NULL
+TITLE XML en Action
+TRANSLATOR James Guerin
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+DROP TABLE t1;
+#
+# Testing attribute values
+#
+CREATE TABLE t1 (
+ISBN CHAR(15),
+LANG CHAR(2),
+SUBJECT CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='Coltype=@,xmlsup=libxml2';
+SELECT * FROM t1;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+DROP TABLE t1;
+#
+# Testing that attribute names are case sensitive
+#
+CREATE TABLE t1 (
+isbn CHAR(15),
+LANG CHAR(2),
+SUBJECT CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='Coltype=@,xmlsup=libxml2';
+SELECT * FROM t1;
+isbn NULL
+LANG fr
+SUBJECT applications
+isbn NULL
+LANG fr
+SUBJECT applications
+DROP TABLE t1;
+#
+# Testing mixed tag and attribute values
+#
+CREATE TABLE t1 (
+ISBN CHAR(15) XPATH='@',
+LANG CHAR(2) XPATH='@',
+SUBJECT CHAR(32) XPATH='@',
+AUTHOR CHAR(50),
+TITLE CHAR(32),
+TRANSLATOR CHAR(40),
+PUBLISHER CHAR(40),
+DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT * FROM t1;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR Jean-Christophe Bernadac
+TITLE Construire une application XML
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+AUTHOR William J. Pardi
+TITLE XML en Action
+TRANSLATOR James Guerin
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+DROP TABLE t1;
+#
+# Testing INSERT on mixed tag and attribute values
+#
+CREATE TABLE t1 (
+ISBN CHAR(15) XPATH='@',
+LANG CHAR(2) XPATH='@',
+SUBJECT CHAR(32) XPATH='@',
+AUTHOR CHAR(50),
+TITLE CHAR(32),
+TRANSLATOR CHAR(40),
+PUBLISHER CHAR(40),
+DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.xml'
+ TABNAME='BIBLIO'
+ OPTION_LIST='rownode=BOOK,xmlsup=libxml2';
+INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB)
+VALUES('9782212090529','fr','général','Alain Michard',
+'XML, Langage et Applications','Eyrolles Paris',1998);
+SELECT * FROM t1;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR Jean-Christophe Bernadac
+TITLE Construire une application XML
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+AUTHOR William J. Pardi
+TITLE XML en Action
+TRANSLATOR James Guerin
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+ISBN 9782212090529
+LANG fr
+SUBJECT général
+AUTHOR Alain Michard
+TITLE XML, Langage et Applications
+TRANSLATOR NULL
+PUBLISHER Eyrolles Paris
+DATEPUB 1998
+SELECT LOAD_FILE('MYSQLD_DATADIR/test/xsample2.xml') AS xml;
+xml <?xml version="1.0" encoding="UTF-8"?>
+<BIBLIO SUBJECT="XML">
+ <BOOK ISBN="9782212090819" LANG="fr" SUBJECT="applications">
+ <AUTHOR>
+ <FIRSTNAME>Jean-Christophe</FIRSTNAME>
+ <LASTNAME>Bernadac</LASTNAME>
+ </AUTHOR>
+ <AUTHOR>
+ <FIRSTNAME>François</FIRSTNAME>
+ <LASTNAME>Knab</LASTNAME>
+ </AUTHOR>
+ <TITLE>Construire une application XML</TITLE>
+ <PUBLISHER>
+ <NAME>Eyrolles</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>1999</DATEPUB>
+ </BOOK>
+ <BOOK ISBN="9782840825685" LANG="fr" SUBJECT="applications">
+ <AUTHOR>
+ <FIRSTNAME>William J.</FIRSTNAME>
+ <LASTNAME>Pardi</LASTNAME>
+ </AUTHOR>
+ <TRANSLATOR PREFIX="adapté de l'anglais par">
+ <FIRSTNAME>James</FIRSTNAME>
+ <LASTNAME>Guerin</LASTNAME>
+ </TRANSLATOR>
+ <TITLE>XML en Action</TITLE>
+ <PUBLISHER>
+ <NAME>Microsoft Press</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>1999</DATEPUB>
+ </BOOK>
+ <BOOK ISBN="9782212090529" LANG="fr" SUBJECT="général">
+ <AUTHOR>Alain Michard</AUTHOR>
+ <TITLE>XML, Langage et Applications</TITLE>
+ <PUBLISHER>Eyrolles Paris</PUBLISHER>
+ <DATEPUB>1998</DATEPUB>
+ </BOOK>
+</BIBLIO>
+
+DROP TABLE t1;
+#
+# Testing XPath
+#
+CREATE TABLE t1 (
+isbn CHAR(15) XPATH='@ISBN',
+language CHAR(2) XPATH='@LANG',
+subject CHAR(32) XPATH='@SUBJECT',
+authorfn CHAR(20) XPATH='AUTHOR/FIRSTNAME',
+authorln CHAR(20) XPATH='AUTHOR/LASTNAME',
+title CHAR(32) XPATH='TITLE',
+translated CHAR(32) XPATH='TRANSLATOR/@PREFIX',
+tranfn CHAR(20) XPATH='TRANSLATOR/FIRSTNAME',
+tranln CHAR(20) XPATH='TRANSLATOR/LASTNAME',
+publisher CHAR(20) XPATH='PUBLISHER/NAME',
+location CHAR(20) XPATH='PUBLISHER/PLACE',
+year INT(4) XPATH='DATEPUB'
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2';
+SELECT * FROM t1;
+isbn 9782212090819
+language fr
+subject applications
+authorfn Jean-Christophe
+authorln Bernadac
+title Construire une application XML
+translated NULL
+tranfn NULL
+tranln NULL
+publisher Eyrolles
+location Paris
+year 1999
+isbn 9782840825685
+language fr
+subject applications
+authorfn William J.
+authorln Pardi
+title XML en Action
+translated adapté de l'anglais par
+tranfn James
+tranln Guerin
+publisher Microsoft Press
+location Paris
+year 1999
+SELECT isbn, title, translated, tranfn, tranln, location FROM t1
+WHERE translated <> '';
+isbn 9782840825685
+title XML en Action
+translated adapté de l'anglais par
+tranfn James
+tranln Guerin
+location Paris
+DROP TABLE t1;
+#
+# Testing that XPath is case sensitive
+#
+CREATE TABLE t1
+(
+isbn CHAR(15) XPATH='@isbn'
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2';
+SELECT * FROM t1;
+isbn NULL
+isbn NULL
+DROP TABLE t1;
+#
+# Testing character sets
+#
+CREATE TABLE t1
+(
+c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2'
+ DATA_CHARSET=latin1;
+ERROR HY000: DATA_CHARSET='latin1' is not supported for TABLE_TYPE=XML
+CREATE TABLE t1
+(
+c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2'
+ DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+Table t1
+Create Table CREATE TABLE `t1` (
+ `c` char(16) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`=XML `FILE_NAME`='latin1.xml' `OPTION_LIST`='xmlsup=libxml2' `DATA_CHARSET`=utf8
+SELECT c, HEX(c) FROM t1;
+c ÃÂÃÄÅÆÇ
+HEX(c) C1C2C3C4C5C6C7
+DROP TABLE t1;
+CREATE TABLE t1
+(
+c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT c, HEX(c) FROM t1;
+c ÃÂÃÄÅÆÇ
+HEX(c) C1C2C3C4C5C6C7
+DROP TABLE t1;
+CREATE TABLE t1
+(
+c CHAR(16) CHARACTER SET utf8
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT c, HEX(c) FROM t1;
+c ÃÂÃÄÅÆÇ
+HEX(c) C381C382C383C384C385C386C387
+DROP TABLE t1;
+#
+# Conversion from latin1 to cp1251 produces a warning.
+# Question marks are returned.
+#
+CREATE TABLE t1
+(
+c CHAR(16) CHARACTER SET cp1251
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT c, HEX(c) FROM t1;
+c ???????
+HEX(c) 3F3F3F3F3F3F3F
+Warnings:
+Level Warning
+Code 1366
+Message Incorrect string value: '\xC3\x81\xC3\x82\xC3\x83...' for column `test`.`t1`.`c` at row 1
+Level Warning
+Code 1105
+Message Out of range value ÃÂÃÄÅÆÇ for column 'c' at row 1
+DROP TABLE t1;
+#
+# Testing Cyrillic
+#
+#
+# Testing that the underlying file is created with a proper Encoding
+#
+CREATE TABLE t1 (node VARCHAR(50))
+CHARACTER SET latin1
+ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=utf-8';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+SELECT node, hex(node) FROM t1;
+node ÀÃÂÃ
+hex(node) C0C1C2C3
+DROP TABLE t1;
+SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
+SELECT LEFT(@a,38);
+LEFT(@a,38) <?xml version="1.0" encoding="utf-8"?>
+SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node'));
+HEX(EXTRACTVALUE(@a,'/t1/line/node')) C380C381C382C383
+CREATE TABLE t1 (node VARCHAR(50))
+CHARACTER SET latin1
+ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+SELECT node, hex(node) FROM t1;
+node ÀÃÂÃ
+hex(node) C0C1C2C3
+DROP TABLE t1;
+SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
+SELECT LEFT(@a,43);
+LEFT(@a,43) <?xml version="1.0" encoding="iso-8859-1"?>
+SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node'));
+HEX(EXTRACTVALUE(@a,'/t1/line/node')) C0C1C2C3
+#
+# Testing XML entities
+#
+CREATE TABLE t1 (node VARCHAR(50))
+CHARACTER SET utf8
+ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3);
+INSERT INTO t1 VALUES ('&<>"\'');
+SELECT node, hex(node) FROM t1;
+node ÀÃÂÃ
+hex(node) C380C381C382C383
+node ÐБВГ
+hex(node) D090D091D092D093
+node &<>"'
+hex(node) 263C3E2227
+DROP TABLE t1;
+SET @a=LOAD_FILE('MYSQLD_DATADIR/test/t1.xml');
+SELECT CAST(@a AS CHAR CHARACTER SET latin1);
+CAST(@a AS CHAR CHARACTER SET latin1) <?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Created by the MariaDB CONNECT Storage Engine-->
+<t1>
+ <line>
+ <node>ÀÃÂÃ</node>
+ </line>
+ <line>
+ <node>&#1040;&#1041;&#1042;&#1043;</node>
+ </line>
+ <line>
+ <node>&amp;&lt;&gt;"'</node>
+ </line>
+</t1>
+
diff --git a/storage/connect/mysql-test/connect/r/xml2_grant.result b/storage/connect/mysql-test/connect/r/xml2_grant.result
new file mode 100644
index 00000000..a6e6c150
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml2_grant.result
@@ -0,0 +1,107 @@
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+#
+# Beginning of grant.inc
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row';
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+UPDATE t1 SET a=20;
+SELECT * FROM t1;
+a
+20
+DELETE FROM t1;
+SELECT * FROM t1;
+a
+INSERT INTO t1 VALUES(10);
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+a
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row' FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+INSERT INTO t1 VALUES (10);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 FILE_NAME='t2.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (2);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET a=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row';
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+ALTER TABLE t1 FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+disconnect user;
+DROP USER user@localhost;
+#
+# End of grant.inc
+#
diff --git a/storage/connect/mysql-test/connect/r/xml2_html.result b/storage/connect/mysql-test/connect/r/xml2_html.result
new file mode 100644
index 00000000..499108b7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml2_html.result
@@ -0,0 +1,32 @@
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+SET NAMES utf8;
+#
+# Testing HTML like XML file
+#
+CREATE TABLE beers (
+`Name` CHAR(16) XPATH='brandName',
+`Origin` CHAR(16) XPATH='origin',
+`Description` CHAR(32) XPATH='details')
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='beers.xml'
+TABNAME='table' OPTION_LIST='xmlsup=libxml2,rownode=tr,colnode=td';
+SELECT * FROM beers;
+Name Origin Description
+Huntsman Bath, UK Wonderful hop, light alcohol
+Tuborg Danmark In small bottles
+DROP TABLE beers;
+#
+# Testing HTML file
+#
+CREATE TABLE coffee (
+`Name` CHAR(16),
+`Cups` INT(8),
+`Type` CHAR(16),
+`Sugar` CHAR(4))
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='coffee.htm'
+TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=libxml2,Coltype=HTML';
+SELECT * FROM coffee;
+Name Cups Type Sugar
+T. Sexton 10 Espresso No
+J. Dinnen 5 Decaf Yes
+DROP TABLE coffee;
diff --git a/storage/connect/mysql-test/connect/r/xml2_mdev5261.result b/storage/connect/mysql-test/connect/r/xml2_mdev5261.result
new file mode 100644
index 00000000..0ee5712d
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml2_mdev5261.result
@@ -0,0 +1,25 @@
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+SET NAMES utf8;
+CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=libxml2,Rownode=N';
+ERROR HY000: Table type XML is not indexable
+CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=libxml2,Rownode=N';
+DESCRIBE t1;
+Field Type Null Key Default Extra
+i int(11) NO NULL
+ALTER TABLE t1 ADD UNIQUE(i);
+ERROR HY000: Table type XML is not indexable
+CREATE UNIQUE INDEX i ON t1(i);
+ERROR HY000: Table type XML is not indexable
+DESCRIBE t1;
+Field Type Null Key Default Extra
+i int(11) NO NULL
+INSERT INTO t1 VALUES(2),(5),(7);
+SELECT * FROM t1 WHERE i = 5;
+i
+5
+ALTER TABLE t1 DROP INDEX i;
+ERROR 42000: Can't DROP INDEX `i`; check that it exists
+DROP INDEX i ON t1;
+ERROR 42000: Can't DROP INDEX `i`; check that it exists
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/xml2_mult.result b/storage/connect/mysql-test/connect/r/xml2_mult.result
new file mode 100644
index 00000000..0146baa8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml2_mult.result
@@ -0,0 +1,104 @@
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+SET NAMES utf8;
+#
+# Testing expanded values
+#
+CREATE TABLE `bookstore` (
+`category` CHAR(16) NOT NULL XPATH='@',
+`title` VARCHAR(50) NOT NULL,
+`lang` char(2) NOT NULL XPATH='title/@',
+`author` VARCHAR(24) NOT NULL,
+`year` INT(4) NOT NULL,
+`price` DOUBLE(8,2) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=libxml2';
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern 2003 49.99
+WEB XQuery Kick Start en Per Bothner 2003 49.99
+WEB XQuery Kick Start en Kurt Cagle 2003 49.99
+WEB XQuery Kick Start en James Linn 2003 49.99
+WEB XQuery Kick Start en Vaidyanathan Nagarajan 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+SELECT category, title, price FROM bookstore;
+category title price
+COOKING Everyday Italian 30.00
+CHILDREN Harry Potter 29.99
+WEB XQuery Kick Start 49.99
+WEB Learning XML 39.95
+SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%';
+category title author price
+CHILDREN Harry Potter J K. Rowling 29.99
+WEB XQuery Kick Start Kurt Cagle 49.99
+WEB Learning XML Erik T. Ray 39.95
+SELECT category, title, price FROM bookstore WHERE author LIKE 'J%';
+category title price
+CHILDREN Harry Potter 29.99
+WEB XQuery Kick Start 49.99
+WEB XQuery Kick Start 49.99
+#
+# Limiting expanded values
+#
+ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=libxml2';
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern 2003 49.99
+WEB XQuery Kick Start en Per Bothner 2003 49.99
+WEB XQuery Kick Start en Kurt Cagle 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+Warnings:
+Warning 1105 Multiple values limited to 3
+# One line lost because the where clause is applied only on the first 3 rows
+SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
+category title author price
+CHILDREN Harry Potter J K. Rowling 29.99
+WEB XQuery Kick Start James McGovern 49.99
+Warnings:
+Warning 1105 Multiple values limited to 3
+#
+# Testing concatenated values
+#
+ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=libxml2';
+# truncated
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern, Per Both 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+Warnings:
+Warning 1105 Truncated author content
+# increase author size
+ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn, Vaidyanathan Nagarajan 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+#
+# Limiting concatenated values
+#
+ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=libxml2';
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+Warnings:
+Warning 1105 Multiple values limited to 4
+# The where clause is applied on the concatenated column result
+SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
+category title author price
+CHILDREN Harry Potter J K. Rowling 29.99
+WEB XQuery Kick Start James McGovern, Per Bothner, Kurt Cagle, James Linn 49.99
+Warnings:
+Warning 1105 Multiple values limited to 4
+DROP TABLE bookstore;
diff --git a/storage/connect/mysql-test/connect/r/xml2_zip.result b/storage/connect/mysql-test/connect/r/xml2_zip.result
new file mode 100644
index 00000000..e743af32
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml2_zip.result
@@ -0,0 +1,98 @@
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+#
+# Testing zipped XML tables
+#
+CREATE TABLE t1 (
+ISBN CHAR(13) NOT NULL XPATH='@',
+LANG CHAR(2) NOT NULL XPATH='@',
+SUBJECT CHAR(12) NOT NULL XPATH='@',
+AUTHOR_FIRSTNAME CHAR(15) NOT NULL XPATH='AUTHOR/FIRSTNAME',
+AUTHOR_LASTNAME CHAR(8) NOT NULL XPATH='AUTHOR/LASTNAME',
+TRANSLATOR_PREFIX CHAR(24) DEFAULT NULL XPATH='TRANSLATOR/@PREFIX',
+TRANSLATOR_FIRSTNAME CHAR(6) DEFAULT NULL XPATH='TRANSLATOR/FIRSTNAME',
+TRANSLATOR_LASTNAME CHAR(6) DEFAULT NULL XPATH='TRANSLATOR/LASTNAME',
+TITLE CHAR(30) NOT NULL,
+PUBLISHER_NAME CHAR(15) NOT NULL XPATH='PUBLISHER/NAME',
+PUBLISHER_PLACE CHAR(5) NOT NULL XPATH='PUBLISHER/PLACE',
+DATEPUB CHAR(4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES
+OPTION_LIST='depth=0,entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=libxml2,expand=1,mulnode=AUTHOR';
+SELECT * FROM t1;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR_FIRSTNAME Jean-Christophe
+AUTHOR_LASTNAME Bernadac
+TRANSLATOR_PREFIX NULL
+TRANSLATOR_FIRSTNAME NULL
+TRANSLATOR_LASTNAME NULL
+TITLE Construire une application XML
+PUBLISHER_NAME Eyrolles
+PUBLISHER_PLACE Paris
+DATEPUB 1999
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR_FIRSTNAME François
+AUTHOR_LASTNAME Knab
+TRANSLATOR_PREFIX NULL
+TRANSLATOR_FIRSTNAME NULL
+TRANSLATOR_LASTNAME NULL
+TITLE Construire une application XML
+PUBLISHER_NAME Eyrolles
+PUBLISHER_PLACE Paris
+DATEPUB 1999
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+AUTHOR_FIRSTNAME William J.
+AUTHOR_LASTNAME Pardi
+TRANSLATOR_PREFIX adapté de l'anglais par
+TRANSLATOR_FIRSTNAME James
+TRANSLATOR_LASTNAME Guerin
+TITLE XML en Action
+PUBLISHER_NAME Microsoft Press
+PUBLISHER_PLACE Paris
+DATEPUB 1999
+ISBN 9782212090529
+LANG fr
+SUBJECT général
+AUTHOR_FIRSTNAME Alain
+AUTHOR_LASTNAME Michard
+TRANSLATOR_PREFIX NULL
+TRANSLATOR_FIRSTNAME NULL
+TRANSLATOR_LASTNAME NULL
+TITLE XML, Langage et Applications
+PUBLISHER_NAME Eyrolles
+PUBLISHER_PLACE Paris
+DATEPUB 2003
+CREATE TABLE t2
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES
+OPTION_LIST='depth=0,xmlsup=libxml2';
+SELECT * FROM t2;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR Jean-Christophe Bernadac
+TRANSLATOR NULL
+TITLE Construire une application XML
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+AUTHOR William J. Pardi
+TRANSLATOR James Guerin
+TITLE XML en Action
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+ISBN 9782212090529
+LANG fr
+SUBJECT général
+AUTHOR Alain Michard
+TRANSLATOR NULL
+TITLE XML, Langage et Applications
+PUBLISHER Eyrolles Paris
+DATEPUB 2003
+DROP TABLE t1,t2;
diff --git a/storage/connect/mysql-test/connect/r/xml_grant.result b/storage/connect/mysql-test/connect/r/xml_grant.result
new file mode 100644
index 00000000..f1a6ad10
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml_grant.result
@@ -0,0 +1,105 @@
+#
+# Beginning of grant.inc
+#
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+connect user,localhost,user,,;
+connection user;
+SELECT user();
+user()
+user@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row';
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+a
+10
+UPDATE t1 SET a=20;
+SELECT * FROM t1;
+a
+20
+DELETE FROM t1;
+SELECT * FROM t1;
+a
+INSERT INTO t1 VALUES(10);
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+a
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+a
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row' FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row' FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+INSERT INTO t1 VALUES (10);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE t1 SET a=20;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+TRUNCATE TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 READONLY=1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+ALTER TABLE t1 FILE_NAME='t2.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DROP TABLE t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+CREATE VIEW v1 AS SELECT * FROM t1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+# Testing a VIEW created with FILE privileges but accessed with no FILE
+connection default;
+SELECT user();
+user()
+root@localhost
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+connection user;
+SELECT user();
+user()
+user@localhost
+SELECT * FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+INSERT INTO v1 VALUES (2);
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+UPDATE v1 SET a=123;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+DELETE FROM v1;
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+SELECT user();
+user()
+root@localhost
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row';
+Warnings:
+Warning 1105 No file name. Table will use t1.xml
+INSERT INTO t1 VALUES (10);
+connection user;
+SELECT user();
+user()
+user@localhost
+ALTER TABLE t1 FILE_NAME='t1.EXT';
+ERROR 42000: Access denied; you need (at least one of) the FILE privilege(s) for this operation
+connection default;
+DROP TABLE t1;
+disconnect user;
+DROP USER user@localhost;
+#
+# End of grant.inc
+#
diff --git a/storage/connect/mysql-test/connect/r/xml_html.result b/storage/connect/mysql-test/connect/r/xml_html.result
new file mode 100644
index 00000000..308c67ff
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml_html.result
@@ -0,0 +1,30 @@
+SET NAMES utf8;
+#
+# Testing HTML like XML file
+#
+CREATE TABLE beers (
+`Name` CHAR(16) XPATH='brandName',
+`Origin` CHAR(16) XPATH='origin',
+`Description` CHAR(32) XPATH='details')
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='beers.xml'
+TABNAME='table' OPTION_LIST='xmlsup=domdoc,rownode=tr,colnode=td';
+SELECT * FROM beers;
+Name Origin Description
+Huntsman Bath, UK Wonderful hop, light alcohol
+Tuborg Danmark In small bottles
+DROP TABLE beers;
+#
+# Testing HTML file
+#
+CREATE TABLE coffee (
+`Name` CHAR(16),
+`Cups` INT(8),
+`Type` CHAR(16),
+`Sugar` CHAR(4))
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='coffee.htm'
+TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=domdoc,Coltype=HTML';
+SELECT * FROM coffee;
+Name Cups Type Sugar
+T. Sexton 10 Espresso No
+J. Dinnen 5 Decaf Yes
+DROP TABLE coffee;
diff --git a/storage/connect/mysql-test/connect/r/xml_mdev5261.result b/storage/connect/mysql-test/connect/r/xml_mdev5261.result
new file mode 100644
index 00000000..b5ae32c7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml_mdev5261.result
@@ -0,0 +1,23 @@
+SET NAMES utf8;
+CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=domdoc,Rownode=N';
+ERROR HY000: Table type XML is not indexable
+CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=domdoc,Rownode=N';
+DESCRIBE t1;
+Field Type Null Key Default Extra
+i int(11) NO NULL
+ALTER TABLE t1 ADD UNIQUE(i);
+ERROR HY000: Table type XML is not indexable
+CREATE UNIQUE INDEX i ON t1(i);
+ERROR HY000: Table type XML is not indexable
+DESCRIBE t1;
+Field Type Null Key Default Extra
+i int(11) NO NULL
+INSERT INTO t1 VALUES(2),(5),(7);
+SELECT * FROM t1 WHERE i = 5;
+i
+5
+ALTER TABLE t1 DROP INDEX i;
+ERROR 42000: Can't DROP INDEX `i`; check that it exists
+DROP INDEX i ON t1;
+ERROR 42000: Can't DROP INDEX `i`; check that it exists
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/r/xml_mult.result b/storage/connect/mysql-test/connect/r/xml_mult.result
new file mode 100644
index 00000000..9cdc36de
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml_mult.result
@@ -0,0 +1,102 @@
+SET NAMES utf8;
+#
+# Testing expanded values
+#
+CREATE TABLE `bookstore` (
+`category` CHAR(16) NOT NULL XPATH='@',
+`title` VARCHAR(50) NOT NULL,
+`lang` char(2) NOT NULL XPATH='title/@',
+`author` VARCHAR(24) NOT NULL,
+`year` INT(4) NOT NULL,
+`price` DOUBLE(8,2) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=domdoc';
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern 2003 49.99
+WEB XQuery Kick Start en Per Bothner 2003 49.99
+WEB XQuery Kick Start en Kurt Cagle 2003 49.99
+WEB XQuery Kick Start en James Linn 2003 49.99
+WEB XQuery Kick Start en Vaidyanathan Nagarajan 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+SELECT category, title, price FROM bookstore;
+category title price
+COOKING Everyday Italian 30.00
+CHILDREN Harry Potter 29.99
+WEB XQuery Kick Start 49.99
+WEB Learning XML 39.95
+SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%';
+category title author price
+CHILDREN Harry Potter J K. Rowling 29.99
+WEB XQuery Kick Start Kurt Cagle 49.99
+WEB Learning XML Erik T. Ray 39.95
+SELECT category, title, price FROM bookstore WHERE author LIKE 'J%';
+category title price
+CHILDREN Harry Potter 29.99
+WEB XQuery Kick Start 49.99
+WEB XQuery Kick Start 49.99
+#
+# Limiting expanded values
+#
+ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=domdoc';
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern 2003 49.99
+WEB XQuery Kick Start en Per Bothner 2003 49.99
+WEB XQuery Kick Start en Kurt Cagle 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+Warnings:
+Warning 1105 Multiple values limited to 3
+# One line lost because the where clause is applied only on the first 3 rows
+SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
+category title author price
+CHILDREN Harry Potter J K. Rowling 29.99
+WEB XQuery Kick Start James McGovern 49.99
+Warnings:
+Warning 1105 Multiple values limited to 3
+#
+# Testing concatenated values
+#
+ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=domdoc';
+# truncated
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern, Per Both 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+Warnings:
+Warning 1105 Truncated author content
+# increase author size
+ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL;
+Warnings:
+Warning 1105 This is an outward table, table data were not modified.
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn, Vaidyanathan Nagarajan 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+#
+# Limiting concatenated values
+#
+ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=domdoc';
+SELECT * FROM bookstore;
+category title lang author year price
+COOKING Everyday Italian en Giada De Laurentiis 2005 30.00
+CHILDREN Harry Potter en J K. Rowling 2005 29.99
+WEB XQuery Kick Start en James McGovern, Per Bothner, Kurt Cagle, James Linn 2003 49.99
+WEB Learning XML en Erik T. Ray 2003 39.95
+Warnings:
+Warning 1105 Multiple values limited to 4
+# The where clause is applied on the concatenated column result
+SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
+category title author price
+CHILDREN Harry Potter J K. Rowling 29.99
+WEB XQuery Kick Start James McGovern, Per Bothner, Kurt Cagle, James Linn 49.99
+Warnings:
+Warning 1105 Multiple values limited to 4
+DROP TABLE bookstore;
diff --git a/storage/connect/mysql-test/connect/r/xml_zip.result b/storage/connect/mysql-test/connect/r/xml_zip.result
new file mode 100644
index 00000000..5f17249b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/xml_zip.result
@@ -0,0 +1,96 @@
+#
+# Testing zipped XML tables
+#
+CREATE TABLE t1 (
+ISBN CHAR(13) NOT NULL XPATH='@',
+LANG CHAR(2) NOT NULL XPATH='@',
+SUBJECT CHAR(12) NOT NULL XPATH='@',
+AUTHOR_FIRSTNAME CHAR(15) NOT NULL XPATH='AUTHOR/FIRSTNAME',
+AUTHOR_LASTNAME CHAR(8) NOT NULL XPATH='AUTHOR/LASTNAME',
+TRANSLATOR_PREFIX CHAR(24) DEFAULT NULL XPATH='TRANSLATOR/@PREFIX',
+TRANSLATOR_FIRSTNAME CHAR(6) DEFAULT NULL XPATH='TRANSLATOR/FIRSTNAME',
+TRANSLATOR_LASTNAME CHAR(6) DEFAULT NULL XPATH='TRANSLATOR/LASTNAME',
+TITLE CHAR(30) NOT NULL,
+PUBLISHER_NAME CHAR(15) NOT NULL XPATH='PUBLISHER/NAME',
+PUBLISHER_PLACE CHAR(5) NOT NULL XPATH='PUBLISHER/PLACE',
+DATEPUB CHAR(4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES
+OPTION_LIST='depth=0,entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=domdoc,expand=1,mulnode=AUTHOR';
+SELECT * FROM t1;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR_FIRSTNAME Jean-Christophe
+AUTHOR_LASTNAME Bernadac
+TRANSLATOR_PREFIX NULL
+TRANSLATOR_FIRSTNAME NULL
+TRANSLATOR_LASTNAME NULL
+TITLE Construire une application XML
+PUBLISHER_NAME Eyrolles
+PUBLISHER_PLACE Paris
+DATEPUB 1999
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR_FIRSTNAME François
+AUTHOR_LASTNAME Knab
+TRANSLATOR_PREFIX NULL
+TRANSLATOR_FIRSTNAME NULL
+TRANSLATOR_LASTNAME NULL
+TITLE Construire une application XML
+PUBLISHER_NAME Eyrolles
+PUBLISHER_PLACE Paris
+DATEPUB 1999
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+AUTHOR_FIRSTNAME William J.
+AUTHOR_LASTNAME Pardi
+TRANSLATOR_PREFIX adapté de l'anglais par
+TRANSLATOR_FIRSTNAME James
+TRANSLATOR_LASTNAME Guerin
+TITLE XML en Action
+PUBLISHER_NAME Microsoft Press
+PUBLISHER_PLACE Paris
+DATEPUB 1999
+ISBN 9782212090529
+LANG fr
+SUBJECT général
+AUTHOR_FIRSTNAME Alain
+AUTHOR_LASTNAME Michard
+TRANSLATOR_PREFIX NULL
+TRANSLATOR_FIRSTNAME NULL
+TRANSLATOR_LASTNAME NULL
+TITLE XML, Langage et Applications
+PUBLISHER_NAME Eyrolles
+PUBLISHER_PLACE Paris
+DATEPUB 2003
+CREATE TABLE t2
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES
+OPTION_LIST='depth=0,xmlsup=domdoc';
+SELECT * FROM t2;
+ISBN 9782212090819
+LANG fr
+SUBJECT applications
+AUTHOR Jean-Christophe Bernadac
+TRANSLATOR NULL
+TITLE Construire une application XML
+PUBLISHER Eyrolles Paris
+DATEPUB 1999
+ISBN 9782840825685
+LANG fr
+SUBJECT applications
+AUTHOR William J. Pardi
+TRANSLATOR James Guerin
+TITLE XML en Action
+PUBLISHER Microsoft Press Paris
+DATEPUB 1999
+ISBN 9782212090529
+LANG fr
+SUBJECT général
+AUTHOR Alain Michard
+TRANSLATOR NULL
+TITLE XML, Langage et Applications
+PUBLISHER Eyrolles Paris
+DATEPUB 2003
+DROP TABLE t1,t2;
diff --git a/storage/connect/mysql-test/connect/r/zip.result b/storage/connect/mysql-test/connect/r/zip.result
new file mode 100644
index 00000000..c696252c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/r/zip.result
@@ -0,0 +1,240 @@
+#
+# Testing zipped DOS tables
+#
+CREATE TABLE t1 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='newdos.zip'
+OPTION_LIST='ENTRY=new1.dos' ZIPPED=1;
+INSERT INTO t1 VALUES(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five'),(6,'Six'),(7,'Seven'),(8,'Eight'),(9,'Nine'),(10,'Ten');
+SELECT * FROM t1;
+digit letter
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+6 Six
+7 Seven
+8 Eight
+9 Nine
+10 Ten
+CREATE TABLE t2 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='newdos.zip'
+OPTION_LIST='ENTRY=new2.dos,APPEND=1' ZIPPED=1;
+INSERT INTO t2 VALUES(11,'Eleven'),(12,'Twelve'),(13,'Thirteen'),(14,'Fourteen'),(15,'Fiften'),(16,'Sixteen'),(17,'Seventeen'),(18,'Eighteen'),(19,'Nineteen'),(20,'Twenty');
+SELECT * FROM t2;
+digit letter
+11 Eleven
+12 Twelve
+13 Thirteen
+14 Fourteen
+15 Fiften
+16 Sixteen
+17 Seventeen
+18 Eighteen
+19 Nineteen
+20 Twenty
+CREATE TABLE t3 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='newdos.zip'
+OPTION_LIST='MULENTRIES=1' ZIPPED=1;
+SELECT * FROM t3;
+digit letter
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+6 Six
+7 Seven
+8 Eight
+9 Nine
+10 Ten
+11 Eleven
+12 Twelve
+13 Thirteen
+14 Fourteen
+15 Fiften
+16 Sixteen
+17 Seventeen
+18 Eighteen
+19 Nineteen
+20 Twenty
+CREATE TABLE t4 (
+fn VARCHAR(256)NOT NULL,
+cmpsize BIGINT NOT NULL FLAG=1,
+uncsize BIGINT NOT NULL FLAG=2,
+method INT NOT NULL FLAG=3)
+ENGINE=CONNECT TABLE_TYPE=ZIP FILE_NAME='newdos.zip';
+SELECT * FROM t4;
+fn cmpsize uncsize method
+new1.dos 67 79 8
+new2.dos 77 112 8
+DROP TABLE t1,t2,t3,t4;
+#
+# Testing zipped CSV tables
+#
+CREATE TABLE t1 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='newcsv.zip'
+OPTION_LIST='ENTRY=new1.csv' HEADER=1 ZIPPED=1;
+INSERT INTO t1 VALUES(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five'),(6,'Six'),(7,'Seven'),(8,'Eight'),(9,'Nine'),(10,'Ten');
+SELECT * FROM t1;
+digit letter
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+6 Six
+7 Seven
+8 Eight
+9 Nine
+10 Ten
+CREATE TABLE td1
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='newcsv.zip'
+OPTION_LIST='ENTRY=new1.csv' HEADER=1 ZIPPED=1;
+SELECT * FROM td1;
+digit letter
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+6 Six
+7 Seven
+8 Eight
+9 Nine
+10 Ten
+DROP TABLE td1;
+CREATE TABLE t2 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='newcsv.zip'
+OPTION_LIST='ENTRY=new2.csv,APPEND=1' HEADER=1 ZIPPED=1;
+INSERT INTO t2 VALUES(11,'Eleven'),(12,'Twelve'),(13,'Thirteen'),(14,'Fourteen'),(15,'Fiften'),(16,'Sixteen'),(17,'Seventeen'),(18,'Eighteen'),(19,'Nineteen'),(20,'Twenty');
+SELECT * FROM t2;
+digit letter
+11 Eleven
+12 Twelve
+13 Thirteen
+14 Fourteen
+15 Fiften
+16 Sixteen
+17 Seventeen
+18 Eighteen
+19 Nineteen
+20 Twenty
+CREATE TABLE t3
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='newcsv.zip'
+OPTION_LIST='MULENTRIES=1' HEADER=1 ZIPPED=1;
+SELECT * FROM t3;
+digit letter
+1 One
+2 Two
+3 Three
+4 Four
+5 Five
+6 Six
+7 Seven
+8 Eight
+9 Nine
+10 Ten
+11 Eleven
+12 Twelve
+13 Thirteen
+14 Fourteen
+15 Fiften
+16 Sixteen
+17 Seventeen
+18 Eighteen
+19 Nineteen
+20 Twenty
+CREATE TABLE t4 (
+fn VARCHAR(256)NOT NULL,
+cmpsize BIGINT NOT NULL FLAG=1,
+uncsize BIGINT NOT NULL FLAG=2,
+method INT NOT NULL FLAG=3)
+ENGINE=CONNECT TABLE_TYPE=ZIP FILE_NAME='newcsv.zip';
+SELECT * FROM t4;
+fn cmpsize uncsize method
+new1.csv 79 83 8
+new2.csv 94 125 8
+DROP TABLE t1,t2,t3,t4;
+#
+# Testing zipped JSON tables
+#
+CREATE TABLE t1 (
+_id INT(2) NOT NULL,
+name_first CHAR(9) NOT NULL JPATH='$.name.first',
+name_aka CHAR(4) DEFAULT NULL JPATH='$.name.aka',
+name_last CHAR(10) NOT NULL JPATH='$.name.last',
+title CHAR(12) DEFAULT NULL,
+birth CHAR(20) DEFAULT NULL,
+death CHAR(20) DEFAULT NULL,
+contribs CHAR(50) NOT NULL JPATH='$.contribs',
+awards_award CHAR(42) DEFAULT NULL JPATH='$.awards.award',
+awards_year CHAR(4) DEFAULT NULL JPATH='$.awards.year',
+awards_by CHAR(38) DEFAULT NULL JPATH='$.awards.by'
+) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bios.zip' OPTION_LIST='ENTRY=bios.json,LOAD=bios.json' ZIPPED=YES;
+SELECT * FROM t1;
+_id name_first name_aka name_last title birth death contribs awards_award awards_year awards_by
+1 John NULL Backus NULL 1924-12-03T05:00:00Z 2007-03-17T04:00:00Z Fortran, ALGOL, Backus-Naur Form, FP W.W. McDowell Award 1967 IEEE Computer Society
+2 John NULL McCarthy NULL 1927-09-04T04:00:00Z 2011-12-24T05:00:00Z Lisp, Artificial Intelligence, ALGOL Turing Award 1971 ACM
+3 Grace NULL Hopper Rear Admiral 1906-12-09T05:00:00Z 1992-01-01T05:00:00Z UNIVAC, compiler, FLOW-MATIC, COBOL Computer Sciences Man of the Year 1969 Data Processing Management Association
+4 Kristen NULL Nygaard NULL 1926-08-27T04:00:00Z 2002-08-10T04:00:00Z OOP, Simula Rosing Prize 1999 Norwegian Data Association
+5 Ole-Johan NULL Dahl NULL 1931-10-12T04:00:00Z 2002-06-29T04:00:00Z OOP, Simula Rosing Prize 1999 Norwegian Data Association
+6 Guido NULL van Rossum NULL 1956-01-31T05:00:00Z NULL Python Award for the Advancement of Free Software 2001 Free Software Foundation
+7 Dennis NULL Ritchie NULL 1941-09-09T04:00:00Z 2011-10-12T04:00:00Z UNIX, C Turing Award 1983 ACM
+8 Yukihiro Matz Matsumoto NULL 1965-04-14T04:00:00Z NULL Ruby Award for the Advancement of Free Software 2011 Free Software Foundation
+9 James NULL Gosling NULL 1955-05-19T04:00:00Z NULL Java The Economist Innovation Award 2002 The Economist
+10 Martin NULL Odersky NULL NULL NULL Scala NULL NULL NULL
+CREATE TABLE t2
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bios.zip' ZIPPED=1
+OPTION_LIST='DEPTH=5';
+SELECT * FROM t2;
+_id name_first name_aka name_last title birth death contribs awards_award awards_year awards_by
+1 John NULL Backus NULL 1924-12-03T05:00:00Z 2007-03-17T04:00:00Z Fortran W.W. McDowell Award 1967 IEEE Computer Society
+2 John NULL McCarthy NULL 1927-09-04T04:00:00Z 2011-12-24T05:00:00Z Lisp Turing Award 1971 ACM
+3 Grace NULL Hopper Rear Admiral 1906-12-09T05:00:00Z 1992-01-01T05:00:00Z UNIVAC Computer Sciences Man of the Year 1969 Data Processing Management Association
+4 Kristen NULL Nygaard NULL 1926-08-27T04:00:00Z 2002-08-10T04:00:00Z OOP Rosing Prize 1999 Norwegian Data Association
+5 Ole-Johan NULL Dahl NULL 1931-10-12T04:00:00Z 2002-06-29T04:00:00Z OOP Rosing Prize 1999 Norwegian Data Association
+6 Guido NULL van Rossum NULL 1956-01-31T05:00:00Z NULL Python Award for the Advancement of Free Software 2001 Free Software Foundation
+7 Dennis NULL Ritchie NULL 1941-09-09T04:00:00Z 2011-10-12T04:00:00Z UNIX Turing Award 1983 ACM
+8 Yukihiro Matz Matsumoto NULL 1965-04-14T04:00:00Z NULL Ruby Award for the Advancement of Free Software 2011 Free Software Foundation
+9 James NULL Gosling NULL 1955-05-19T04:00:00Z NULL Java The Economist Innovation Award 2002 The Economist
+10 Martin NULL Odersky NULL NULL NULL Scala NULL NULL NULL
+CREATE TABLE t3 (
+_id INT(2) NOT NULL,
+firstname CHAR(9) NOT NULL JPATH='$.name.first',
+aka CHAR(4) DEFAULT NULL JPATH='$.name.aka',
+lastname CHAR(10) NOT NULL JPATH='$.name.last',
+title CHAR(12) DEFAULT NULL,
+birth date DEFAULT NULL date_format="YYYY-DD-MM'T'hh:mm:ss'Z'",
+death date DEFAULT NULL date_format="YYYY-DD-MM'T'hh:mm:ss'Z'",
+contribs CHAR(64) NOT NULL JPATH='$.contribs.[", "]',
+award CHAR(42) DEFAULT NULL JPATH='$.awards[*].award',
+year CHAR(4) DEFAULT NULL JPATH='$.awards[*].year',
+`by` CHAR(38) DEFAULT NULL JPATH='$.awards[*].by'
+) ENGINE=CONNECT TABLE_TYPE='json' FILE_NAME='bios.zip' ZIPPED=YES;
+SELECT * FROM t3 WHERE _id = 1;
+_id firstname aka lastname title birth death contribs award year by
+1 John NULL Backus NULL 1924-03-12 2008-05-03 Fortran, ALGOL, Backus-Naur Form, FP W.W. McDowell Award 1967 IEEE Computer Society
+1 John NULL Backus NULL 1924-03-12 2008-05-03 Fortran, ALGOL, Backus-Naur Form, FP National Medal of Science 1975 National Science Foundation
+1 John NULL Backus NULL 1924-03-12 2008-05-03 Fortran, ALGOL, Backus-Naur Form, FP Turing Award 1977 ACM
+1 John NULL Backus NULL 1924-03-12 2008-05-03 Fortran, ALGOL, Backus-Naur Form, FP Draper Prize 1993 National Academy of Engineering
+CREATE TABLE t4 (
+fn VARCHAR(256)NOT NULL,
+cmpsize BIGINT NOT NULL FLAG=1,
+uncsize BIGINT NOT NULL FLAG=2,
+method INT NOT NULL FLAG=3)
+ENGINE=CONNECT TABLE_TYPE=ZIP FILE_NAME='bios.zip';
+SELECT * FROM t4;
+fn cmpsize uncsize method
+bios.json 1096 6848 8
+DROP TABLE t1,t2,t3,t4;
diff --git a/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar b/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar
new file mode 100644
index 00000000..33b29e76
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/JavaWrappers.jar
Binary files differ
diff --git a/storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar b/storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar
new file mode 100644
index 00000000..8525da74
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/JdbcMariaDB.jar
Binary files differ
diff --git a/storage/connect/mysql-test/connect/std_data/Mongo2.jar b/storage/connect/mysql-test/connect/std_data/Mongo2.jar
new file mode 100644
index 00000000..d51cc5d2
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/Mongo2.jar
Binary files differ
diff --git a/storage/connect/mysql-test/connect/std_data/Mongo3.jar b/storage/connect/mysql-test/connect/std_data/Mongo3.jar
new file mode 100644
index 00000000..f84e089e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/Mongo3.jar
Binary files differ
diff --git a/storage/connect/mysql-test/connect/std_data/Testbal.dat b/storage/connect/mysql-test/connect/std_data/Testbal.dat
new file mode 100644
index 00000000..b3f0e26e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/Testbal.dat
Binary files differ
diff --git a/storage/connect/mysql-test/connect/std_data/beers.xml b/storage/connect/mysql-test/connect/std_data/beers.xml
new file mode 100644
index 00000000..1abc77fe
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/beers.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<Beers>
+ <table>
+ <th><td>Name</td><td>Origin</td><td>Description</td></th>
+ <tr>
+ <td><brandName>Huntsman</brandName></td>
+ <td><origin>Bath, UK</origin></td>
+ <td><details>Wonderful hop, light alcohol</details></td>
+ </tr>
+ <tr>
+ <td><brandName>Tuborg</brandName></td>
+ <td><origin>Danmark</origin></td>
+ <td><details>In small bottles</details></td>
+ </tr>
+ </table>
+</Beers>
diff --git a/storage/connect/mysql-test/connect/std_data/bib0.json b/storage/connect/mysql-test/connect/std_data/bib0.json
new file mode 100644
index 00000000..2dabf0fd
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/bib0.json
@@ -0,0 +1,2 @@
+{"ISBN":"9782212090819","LANG":"fr","SUBJECT":"applications","AUTHOR":[{"FIRSTNAME":"Jean-Michel","LASTNAME":"Bernadac"},{"FIRSTNAME":"François","LASTNAME":"Knab"}],"TITLE":"Construire une application XML","PUBLISHER":{"NAME":"Eyrolles","PLACE":"Paris"},"DATEPUB":1999}
+{"ISBN":"9782840825685","LANG":"fr","SUBJECT":"applications","AUTHOR":[{"FIRSTNAME":"William J.","LASTNAME":"Pardi"}],"TITLE":"XML en Action","TRANSLATED":{"PREFIX":"adapté de l'anglais par","TRANSLATOR":{"FIRSTNAME":"James","LASTNAME":"Guerin"}},"PUBLISHER":{"NAME":"Microsoft Press","PLACE":"Paris"},"DATEPUB":2001}
diff --git a/storage/connect/mysql-test/connect/std_data/biblio.json b/storage/connect/mysql-test/connect/std_data/biblio.json
new file mode 100644
index 00000000..dcf95922
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/biblio.json
@@ -0,0 +1,43 @@
+[
+ {
+ "ISBN": "9782212090819",
+ "LANG": "fr",
+ "SUBJECT": "applications",
+ "AUTHOR": [
+ {
+ "FIRSTNAME": "Jean-Christophe",
+ "LASTNAME": "Bernadac"
+ },
+ {
+ "FIRSTNAME": "François",
+ "LASTNAME": "Knab"
+ }
+ ],
+ "TITLE": "Construire une application XML",
+ "PUBLISHER": {
+ "NAME": "Eyrolles",
+ "PLACE": "Paris"
+ },
+ "DATEPUB": 1999
+ },
+ {
+ "ISBN": "9782840825685",
+ "LANG": "fr",
+ "SUBJECT": "applications",
+ "AUTHOR": {
+ "FIRSTNAME": "William J.",
+ "LASTNAME": "Pardi"
+ },
+ "TITLE": "XML en Action",
+ "TRANSLATION": "adapté de l'anglais par",
+ "TRANSLATOR": {
+ "FIRSTNAME": "James",
+ "LASTNAME": "Guerin"
+ },
+ "PUBLISHER": {
+ "NAME": "Microsoft Press",
+ "PLACE": "Paris"
+ },
+ "DATEPUB": 1999
+ }
+]
diff --git a/storage/connect/mysql-test/connect/std_data/bios.json b/storage/connect/mysql-test/connect/std_data/bios.json
new file mode 100644
index 00000000..85e4ecb9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/bios.json
@@ -0,0 +1,273 @@
+[
+ {
+ "_id" : 1,
+ "name" : {
+ "first" : "John",
+ "last" : "Backus"
+ },
+ "birth" : "1924-12-03T05:00:00Z",
+ "death" : "2007-03-17T04:00:00Z",
+ "contribs" : [
+ "Fortran",
+ "ALGOL",
+ "Backus-Naur Form",
+ "FP"
+ ],
+ "awards" : [
+ {
+ "award" : "W.W. McDowell Award",
+ "year" : 1967,
+ "by" : "IEEE Computer Society"
+ },
+ {
+ "award" : "National Medal of Science",
+ "year" : 1975,
+ "by" : "National Science Foundation"
+ },
+ {
+ "award" : "Turing Award",
+ "year" : 1977,
+ "by" : "ACM"
+ },
+ {
+ "award" : "Draper Prize",
+ "year" : 1993,
+ "by" : "National Academy of Engineering"
+ }
+ ]
+ },
+ {
+ "_id" : 2,
+ "name" : {
+ "first" : "John",
+ "last" : "McCarthy"
+ },
+ "birth" : "1927-09-04T04:00:00Z",
+ "death" : "2011-12-24T05:00:00Z",
+ "contribs" : [
+ "Lisp",
+ "Artificial Intelligence",
+ "ALGOL"
+ ],
+ "awards" : [
+ {
+ "award" : "Turing Award",
+ "year" : 1971,
+ "by" : "ACM"
+ },
+ {
+ "award" : "Kyoto Prize",
+ "year" : 1988,
+ "by" : "Inamori Foundation"
+ },
+ {
+ "award" : "National Medal of Science",
+ "year" : 1990,
+ "by" : "National Science Foundation"
+ }
+ ]
+ },
+ {
+ "_id" : 3,
+ "name" : {
+ "first" : "Grace",
+ "last" : "Hopper"
+ },
+ "title" : "Rear Admiral",
+ "birth" : "1906-12-09T05:00:00Z",
+ "death" : "1992-01-01T05:00:00Z",
+ "contribs" : [
+ "UNIVAC",
+ "compiler",
+ "FLOW-MATIC",
+ "COBOL"
+ ],
+ "awards" : [
+ {
+ "award" : "Computer Sciences Man of the Year",
+ "year" : 1969,
+ "by" : "Data Processing Management Association"
+ },
+ {
+ "award" : "Distinguished Fellow",
+ "year" : 1973,
+ "by" : " British Computer Society"
+ },
+ {
+ "award" : "W. W. McDowell Award",
+ "year" : 1976,
+ "by" : "IEEE Computer Society"
+ },
+ {
+ "award" : "National Medal of Technology",
+ "year" : 1991,
+ "by" : "United States"
+ }
+ ]
+ },
+ {
+ "_id" : 4,
+ "name" : {
+ "first" : "Kristen",
+ "last" : "Nygaard"
+ },
+ "birth" : "1926-08-27T04:00:00Z",
+ "death" : "2002-08-10T04:00:00Z",
+ "contribs" : [
+ "OOP",
+ "Simula"
+ ],
+ "awards" : [
+ {
+ "award" : "Rosing Prize",
+ "year" : 1999,
+ "by" : "Norwegian Data Association"
+ },
+ {
+ "award" : "Turing Award",
+ "year" : 2001,
+ "by" : "ACM"
+ },
+ {
+ "award" : "IEEE John von Neumann Medal",
+ "year" : 2001,
+ "by" : "IEEE"
+ }
+ ]
+ },
+ {
+ "_id" : 5,
+ "name" : {
+ "first" : "Ole-Johan",
+ "last" : "Dahl"
+ },
+ "birth" : "1931-10-12T04:00:00Z",
+ "death" : "2002-06-29T04:00:00Z",
+ "contribs" : [
+ "OOP",
+ "Simula"
+ ],
+ "awards" : [
+ {
+ "award" : "Rosing Prize",
+ "year" : 1999,
+ "by" : "Norwegian Data Association"
+ },
+ {
+ "award" : "Turing Award",
+ "year" : 2001,
+ "by" : "ACM"
+ },
+ {
+ "award" : "IEEE John von Neumann Medal",
+ "year" : 2001,
+ "by" : "IEEE"
+ }
+ ]
+ },
+ {
+ "_id" : 6,
+ "name" : {
+ "first" : "Guido",
+ "last" : "van Rossum"
+ },
+ "birth" : "1956-01-31T05:00:00Z",
+ "contribs" : [
+ "Python"
+ ],
+ "awards" : [
+ {
+ "award" : "Award for the Advancement of Free Software",
+ "year" : 2001,
+ "by" : "Free Software Foundation"
+ },
+ {
+ "award" : "NLUUG Award",
+ "year" : 2003,
+ "by" : "NLUUG"
+ }
+ ]
+ },
+ {
+ "_id" : 7,
+ "name" : {
+ "first" : "Dennis",
+ "last" : "Ritchie"
+ },
+ "birth" : "1941-09-09T04:00:00Z",
+ "death" : "2011-10-12T04:00:00Z",
+ "contribs" : [
+ "UNIX",
+ "C"
+ ],
+ "awards" : [
+ {
+ "award" : "Turing Award",
+ "year" : 1983,
+ "by" : "ACM"
+ },
+ {
+ "award" : "National Medal of Technology",
+ "year" : 1998,
+ "by" : "United States"
+ },
+ {
+ "award" : "Japan Prize",
+ "year" : 2011,
+ "by" : "The Japan Prize Foundation"
+ }
+ ]
+ },
+ {
+ "_id" : 8,
+ "name" : {
+ "first" : "Yukihiro",
+ "aka" : "Matz",
+ "last" : "Matsumoto"
+ },
+ "birth" : "1965-04-14T04:00:00Z",
+ "contribs" : [
+ "Ruby"
+ ],
+ "awards" : [
+ {
+ "award" : "Award for the Advancement of Free Software",
+ "year" : "2011",
+ "by" : "Free Software Foundation"
+ }
+ ]
+ },
+ {
+ "_id" : 9,
+ "name" : {
+ "first" : "James",
+ "last" : "Gosling"
+ },
+ "birth" : "1955-05-19T04:00:00Z",
+ "contribs" : [
+ "Java"
+ ],
+ "awards" : [
+ {
+ "award" : "The Economist Innovation Award",
+ "year" : 2002,
+ "by" : "The Economist"
+ },
+ {
+ "award" : "Officer of the Order of Canada",
+ "year" : 2007,
+ "by" : "Canada"
+ }
+ ]
+ },
+ {
+ "_id" : 10,
+ "name" : {
+ "first" : "Martin",
+ "last" : "Odersky"
+ },
+ "contribs" : [
+ "Scala"
+ ]
+ }
+]
diff --git a/storage/connect/mysql-test/connect/std_data/bookstore.xml b/storage/connect/mysql-test/connect/std_data/bookstore.xml
new file mode 100644
index 00000000..540fa540
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/bookstore.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<bookstore>
+ <book category="COOKING">
+ <title lang="en">Everyday Italian</title>
+ <author>Giada De Laurentiis</author>
+ <year>2005</year>
+ <price>30.00</price>
+ </book>
+ <book category="CHILDREN">
+ <title lang="en">Harry Potter</title>
+ <author>J K. Rowling</author>
+ <year>2005</year>
+ <price>29.99</price>
+ </book>
+ <book category="WEB">
+ <title lang="en">XQuery Kick Start</title>
+ <author>James McGovern</author>
+ <author>Per Bothner</author>
+ <author>Kurt Cagle</author>
+ <author>James Linn</author>
+ <author>Vaidyanathan Nagarajan</author>
+ <year>2003</year>
+ <price>49.99</price>
+ </book>
+ <book category="WEB">
+ <title lang="en">Learning XML</title>
+ <author>Erik T. Ray</author>
+ <year>2003</year>
+ <price>39.95</price>
+ </book>
+</bookstore>
diff --git a/storage/connect/mysql-test/connect/std_data/boys.txt b/storage/connect/mysql-test/connect/std_data/boys.txt
new file mode 100644
index 00000000..ada3b2dc
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/boys.txt
@@ -0,0 +1,6 @@
+John Boston 25/01/1986 02/06/2010
+Henry Boston 07/06/1987 01/04/2008
+George San Jose 10/08/1981 02/06/2010
+Sam Chicago 22/11/1979 10/10/2007
+James Dallas 13/05/1992 14/12/2009
+Bill Boston 11/09/1986 10/02/2008
diff --git a/storage/connect/mysql-test/connect/std_data/boyswin.txt b/storage/connect/mysql-test/connect/std_data/boyswin.txt
new file mode 100644
index 00000000..bf6eee62
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/boyswin.txt
@@ -0,0 +1,6 @@
+John Boston 25/01/1986 02/06/2010
+Henry Boston 07/06/1987 01/04/2008
+George San Jose 10/08/1981 02/06/2010
+Sam Chicago 22/11/1979 10/10/2007
+James Dallas 13/05/1992 14/12/2009
+Bill Boston 11/09/1986 10/02/2008
diff --git a/storage/connect/mysql-test/connect/std_data/cities.json b/storage/connect/mysql-test/connect/std_data/cities.json
new file mode 100644
index 00000000..dc13a5e0
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/cities.json
@@ -0,0 +1,29353 @@
+{ "_id" : "01001", "city" : "AGAWAM", "loc" : [ -72.622739, 42.070206 ], "pop" : 15338, "state" : "MA" }
+{ "_id" : "01002", "city" : "CUSHMAN", "loc" : [ -72.51564999999999, 42.377017 ], "pop" : 36963, "state" : "MA" }
+{ "_id" : "01005", "city" : "BARRE", "loc" : [ -72.10835400000001, 42.409698 ], "pop" : 4546, "state" : "MA" }
+{ "_id" : "01007", "city" : "BELCHERTOWN", "loc" : [ -72.41095300000001, 42.275103 ], "pop" : 10579, "state" : "MA" }
+{ "_id" : "01008", "city" : "BLANDFORD", "loc" : [ -72.936114, 42.182949 ], "pop" : 1240, "state" : "MA" }
+{ "_id" : "01010", "city" : "BRIMFIELD", "loc" : [ -72.188455, 42.116543 ], "pop" : 3706, "state" : "MA" }
+{ "_id" : "01011", "city" : "CHESTER", "loc" : [ -72.988761, 42.279421 ], "pop" : 1688, "state" : "MA" }
+{ "_id" : "01012", "city" : "CHESTERFIELD", "loc" : [ -72.833309, 42.38167 ], "pop" : 177, "state" : "MA" }
+{ "_id" : "01013", "city" : "CHICOPEE", "loc" : [ -72.607962, 42.162046 ], "pop" : 23396, "state" : "MA" }
+{ "_id" : "01020", "city" : "CHICOPEE", "loc" : [ -72.576142, 42.176443 ], "pop" : 31495, "state" : "MA" }
+{ "_id" : "01022", "city" : "WESTOVER AFB", "loc" : [ -72.558657, 42.196672 ], "pop" : 1764, "state" : "MA" }
+{ "_id" : "01026", "city" : "CUMMINGTON", "loc" : [ -72.905767, 42.435296 ], "pop" : 1484, "state" : "MA" }
+{ "_id" : "01027", "city" : "MOUNT TOM", "loc" : [ -72.67992099999999, 42.264319 ], "pop" : 16864, "state" : "MA" }
+{ "_id" : "01028", "city" : "EAST LONGMEADOW", "loc" : [ -72.505565, 42.067203 ], "pop" : 13367, "state" : "MA" }
+{ "_id" : "01030", "city" : "FEEDING HILLS", "loc" : [ -72.675077, 42.07182 ], "pop" : 11985, "state" : "MA" }
+{ "_id" : "01031", "city" : "GILBERTVILLE", "loc" : [ -72.19858499999999, 42.332194 ], "pop" : 2385, "state" : "MA" }
+{ "_id" : "01032", "city" : "GOSHEN", "loc" : [ -72.844092, 42.466234 ], "pop" : 122, "state" : "MA" }
+{ "_id" : "01033", "city" : "GRANBY", "loc" : [ -72.52000099999999, 42.255704 ], "pop" : 5526, "state" : "MA" }
+{ "_id" : "01034", "city" : "TOLLAND", "loc" : [ -72.908793, 42.070234 ], "pop" : 1652, "state" : "MA" }
+{ "_id" : "01035", "city" : "HADLEY", "loc" : [ -72.571499, 42.36062 ], "pop" : 4231, "state" : "MA" }
+{ "_id" : "01036", "city" : "HAMPDEN", "loc" : [ -72.43182299999999, 42.064756 ], "pop" : 4709, "state" : "MA" }
+{ "_id" : "01038", "city" : "HATFIELD", "loc" : [ -72.61673500000001, 42.38439 ], "pop" : 3184, "state" : "MA" }
+{ "_id" : "01039", "city" : "HAYDENVILLE", "loc" : [ -72.70317799999999, 42.381799 ], "pop" : 1387, "state" : "MA" }
+{ "_id" : "01040", "city" : "HOLYOKE", "loc" : [ -72.626193, 42.202007 ], "pop" : 43704, "state" : "MA" }
+{ "_id" : "01050", "city" : "HUNTINGTON", "loc" : [ -72.873341, 42.265301 ], "pop" : 2084, "state" : "MA" }
+{ "_id" : "01053", "city" : "LEEDS", "loc" : [ -72.70340299999999, 42.354292 ], "pop" : 1350, "state" : "MA" }
+{ "_id" : "01054", "city" : "LEVERETT", "loc" : [ -72.499334, 42.46823 ], "pop" : 1748, "state" : "MA" }
+{ "_id" : "01056", "city" : "LUDLOW", "loc" : [ -72.471012, 42.172823 ], "pop" : 18820, "state" : "MA" }
+{ "_id" : "01057", "city" : "MONSON", "loc" : [ -72.31963399999999, 42.101017 ], "pop" : 8194, "state" : "MA" }
+{ "_id" : "01060", "city" : "FLORENCE", "loc" : [ -72.654245, 42.324662 ], "pop" : 27939, "state" : "MA" }
+{ "_id" : "01068", "city" : "OAKHAM", "loc" : [ -72.051265, 42.348033 ], "pop" : 1503, "state" : "MA" }
+{ "_id" : "01069", "city" : "PALMER", "loc" : [ -72.328785, 42.176233 ], "pop" : 9778, "state" : "MA" }
+{ "_id" : "01070", "city" : "PLAINFIELD", "loc" : [ -72.918289, 42.514393 ], "pop" : 571, "state" : "MA" }
+{ "_id" : "01071", "city" : "RUSSELL", "loc" : [ -72.840343, 42.147063 ], "pop" : 608, "state" : "MA" }
+{ "_id" : "01072", "city" : "SHUTESBURY", "loc" : [ -72.421342, 42.481968 ], "pop" : 1533, "state" : "MA" }
+{ "_id" : "01073", "city" : "SOUTHAMPTON", "loc" : [ -72.719381, 42.224697 ], "pop" : 4478, "state" : "MA" }
+{ "_id" : "01075", "city" : "SOUTH HADLEY", "loc" : [ -72.581137, 42.237537 ], "pop" : 16699, "state" : "MA" }
+{ "_id" : "01077", "city" : "SOUTHWICK", "loc" : [ -72.770588, 42.051099 ], "pop" : 7667, "state" : "MA" }
+{ "_id" : "01080", "city" : "THREE RIVERS", "loc" : [ -72.362352, 42.181894 ], "pop" : 2425, "state" : "MA" }
+{ "_id" : "01081", "city" : "WALES", "loc" : [ -72.20459200000001, 42.062734 ], "pop" : 1732, "state" : "MA" }
+{ "_id" : "01082", "city" : "WARE", "loc" : [ -72.258285, 42.261831 ], "pop" : 9808, "state" : "MA" }
+{ "_id" : "01085", "city" : "MONTGOMERY", "loc" : [ -72.754318, 42.129484 ], "pop" : 40117, "state" : "MA" }
+{ "_id" : "01089", "city" : "WEST SPRINGFIELD", "loc" : [ -72.641109, 42.115066 ], "pop" : 27537, "state" : "MA" }
+{ "_id" : "01092", "city" : "WEST WARREN", "loc" : [ -72.203639, 42.20734 ], "pop" : 4441, "state" : "MA" }
+{ "_id" : "01095", "city" : "WILBRAHAM", "loc" : [ -72.446415, 42.124506 ], "pop" : 12635, "state" : "MA" }
+{ "_id" : "01096", "city" : "WILLIAMSBURG", "loc" : [ -72.77798900000001, 42.408522 ], "pop" : 2295, "state" : "MA" }
+{ "_id" : "01098", "city" : "WORTHINGTON", "loc" : [ -72.931427, 42.384293 ], "pop" : 877, "state" : "MA" }
+{ "_id" : "01103", "city" : "SPRINGFIELD", "loc" : [ -72.588735, 42.1029 ], "pop" : 2323, "state" : "MA" }
+{ "_id" : "01104", "city" : "SPRINGFIELD", "loc" : [ -72.577769, 42.128848 ], "pop" : 22115, "state" : "MA" }
+{ "_id" : "01105", "city" : "SPRINGFIELD", "loc" : [ -72.578312, 42.099931 ], "pop" : 14970, "state" : "MA" }
+{ "_id" : "01106", "city" : "LONGMEADOW", "loc" : [ -72.5676, 42.050658 ], "pop" : 15688, "state" : "MA" }
+{ "_id" : "01107", "city" : "SPRINGFIELD", "loc" : [ -72.606544, 42.117907 ], "pop" : 12739, "state" : "MA" }
+{ "_id" : "01108", "city" : "SPRINGFIELD", "loc" : [ -72.558432, 42.085314 ], "pop" : 25519, "state" : "MA" }
+{ "_id" : "01109", "city" : "SPRINGFIELD", "loc" : [ -72.554349, 42.114455 ], "pop" : 32635, "state" : "MA" }
+{ "_id" : "01118", "city" : "SPRINGFIELD", "loc" : [ -72.527445, 42.092937 ], "pop" : 14618, "state" : "MA" }
+{ "_id" : "01119", "city" : "SPRINGFIELD", "loc" : [ -72.51211000000001, 42.12473 ], "pop" : 13040, "state" : "MA" }
+{ "_id" : "01128", "city" : "SPRINGFIELD", "loc" : [ -72.48890299999999, 42.094397 ], "pop" : 3272, "state" : "MA" }
+{ "_id" : "01129", "city" : "SPRINGFIELD", "loc" : [ -72.487622, 42.122263 ], "pop" : 6831, "state" : "MA" }
+{ "_id" : "01151", "city" : "INDIAN ORCHARD", "loc" : [ -72.505048, 42.153225 ], "pop" : 8702, "state" : "MA" }
+{ "_id" : "01201", "city" : "PITTSFIELD", "loc" : [ -73.24708800000001, 42.453086 ], "pop" : 50655, "state" : "MA" }
+{ "_id" : "01220", "city" : "ADAMS", "loc" : [ -73.117225, 42.622319 ], "pop" : 9901, "state" : "MA" }
+{ "_id" : "01222", "city" : "ASHLEY FALLS", "loc" : [ -73.320195, 42.059552 ], "pop" : 561, "state" : "MA" }
+{ "_id" : "01223", "city" : "BECKET", "loc" : [ -73.12032499999999, 42.359363 ], "pop" : 1070, "state" : "MA" }
+{ "_id" : "01225", "city" : "CHESHIRE", "loc" : [ -73.15796400000001, 42.561059 ], "pop" : 3094, "state" : "MA" }
+{ "_id" : "01226", "city" : "DALTON", "loc" : [ -73.160259, 42.475046 ], "pop" : 7357, "state" : "MA" }
+{ "_id" : "01230", "city" : "GREAT BARRINGTON", "loc" : [ -73.36065000000001, 42.195922 ], "pop" : 10603, "state" : "MA" }
+{ "_id" : "01235", "city" : "PERU", "loc" : [ -73.092433, 42.434604 ], "pop" : 2559, "state" : "MA" }
+{ "_id" : "01236", "city" : "HOUSATONIC", "loc" : [ -73.374544, 42.265296 ], "pop" : 802, "state" : "MA" }
+{ "_id" : "01237", "city" : "HANCOCK", "loc" : [ -73.24873700000001, 42.541961 ], "pop" : 2328, "state" : "MA" }
+{ "_id" : "01238", "city" : "LEE", "loc" : [ -73.231696, 42.298994 ], "pop" : 6916, "state" : "MA" }
+{ "_id" : "01240", "city" : "LENOX", "loc" : [ -73.271322, 42.364241 ], "pop" : 5001, "state" : "MA" }
+{ "_id" : "01243", "city" : "MIDDLEFIELD", "loc" : [ -73.006226, 42.34795 ], "pop" : 384, "state" : "MA" }
+{ "_id" : "01245", "city" : "WEST OTIS", "loc" : [ -73.213452, 42.187847 ], "pop" : 329, "state" : "MA" }
+{ "_id" : "01247", "city" : "CLARKSBURG", "loc" : [ -73.10999, 42.69865 ], "pop" : 19054, "state" : "MA" }
+{ "_id" : "01253", "city" : "OTIS", "loc" : [ -73.082093, 42.18988 ], "pop" : 1060, "state" : "MA" }
+{ "_id" : "01254", "city" : "RICHMOND", "loc" : [ -73.364457, 42.378398 ], "pop" : 1134, "state" : "MA" }
+{ "_id" : "01255", "city" : "SANDISFIELD", "loc" : [ -73.116285, 42.109429 ], "pop" : 651, "state" : "MA" }
+{ "_id" : "01256", "city" : "SAVOY", "loc" : [ -73.023281, 42.576964 ], "pop" : 632, "state" : "MA" }
+{ "_id" : "01257", "city" : "SHEFFIELD", "loc" : [ -73.361091, 42.100102 ], "pop" : 1839, "state" : "MA" }
+{ "_id" : "01258", "city" : "SOUTH EGREMONT", "loc" : [ -73.456575, 42.101153 ], "pop" : 135, "state" : "MA" }
+{ "_id" : "01259", "city" : "SOUTHFIELD", "loc" : [ -73.26093299999999, 42.078014 ], "pop" : 622, "state" : "MA" }
+{ "_id" : "01262", "city" : "STOCKBRIDGE", "loc" : [ -73.32226300000001, 42.30104 ], "pop" : 2200, "state" : "MA" }
+{ "_id" : "01266", "city" : "WEST STOCKBRIDGE", "loc" : [ -73.38251, 42.334752 ], "pop" : 1173, "state" : "MA" }
+{ "_id" : "01267", "city" : "WILLIAMSTOWN", "loc" : [ -73.20363999999999, 42.708883 ], "pop" : 8220, "state" : "MA" }
+{ "_id" : "01270", "city" : "WINDSOR", "loc" : [ -73.04661, 42.509494 ], "pop" : 770, "state" : "MA" }
+{ "_id" : "01301", "city" : "LEYDEN", "loc" : [ -72.60184700000001, 42.601222 ], "pop" : 18968, "state" : "MA" }
+{ "_id" : "01330", "city" : "ASHFIELD", "loc" : [ -72.810998, 42.523207 ], "pop" : 1535, "state" : "MA" }
+{ "_id" : "01331", "city" : "NEW SALEM", "loc" : [ -72.21464400000001, 42.592065 ], "pop" : 14077, "state" : "MA" }
+{ "_id" : "01337", "city" : "LEYDEN", "loc" : [ -72.563439, 42.683784 ], "pop" : 2426, "state" : "MA" }
+{ "_id" : "01338", "city" : "BUCKLAND", "loc" : [ -72.764124, 42.615174 ], "pop" : 16, "state" : "MA" }
+{ "_id" : "01339", "city" : "HAWLEY", "loc" : [ -72.880162, 42.621802 ], "pop" : 1325, "state" : "MA" }
+{ "_id" : "01340", "city" : "COLRAIN", "loc" : [ -72.726508, 42.67905 ], "pop" : 2050, "state" : "MA" }
+{ "_id" : "01341", "city" : "CONWAY", "loc" : [ -72.702473, 42.513832 ], "pop" : 1524, "state" : "MA" }
+{ "_id" : "01342", "city" : "DEERFIELD", "loc" : [ -72.60723400000001, 42.540636 ], "pop" : 1281, "state" : "MA" }
+{ "_id" : "01344", "city" : "ERVING", "loc" : [ -72.41663800000001, 42.604957 ], "pop" : 635, "state" : "MA" }
+{ "_id" : "01346", "city" : "HEATH", "loc" : [ -72.839101, 42.685347 ], "pop" : 174, "state" : "MA" }
+{ "_id" : "01349", "city" : "MILLERS FALLS", "loc" : [ -72.494626, 42.576206 ], "pop" : 1893, "state" : "MA" }
+{ "_id" : "01350", "city" : "MONROE", "loc" : [ -72.960156, 42.723885 ], "pop" : 97, "state" : "MA" }
+{ "_id" : "01351", "city" : "MONTAGUE", "loc" : [ -72.532837, 42.542864 ], "pop" : 1699, "state" : "MA" }
+{ "_id" : "01355", "city" : "NEW SALEM", "loc" : [ -72.306241, 42.514643 ], "pop" : 456, "state" : "MA" }
+{ "_id" : "01360", "city" : "NORTHFIELD", "loc" : [ -72.45099500000001, 42.688705 ], "pop" : 2829, "state" : "MA" }
+{ "_id" : "01364", "city" : "NEW SALEM", "loc" : [ -72.30586700000001, 42.591231 ], "pop" : 8544, "state" : "MA" }
+{ "_id" : "01366", "city" : "PETERSHAM", "loc" : [ -72.18934900000001, 42.489761 ], "pop" : 1131, "state" : "MA" }
+{ "_id" : "01367", "city" : "ROWE", "loc" : [ -72.925776, 42.695289 ], "pop" : 630, "state" : "MA" }
+{ "_id" : "01370", "city" : "SHELBURNE FALLS", "loc" : [ -72.739059, 42.602203 ], "pop" : 4525, "state" : "MA" }
+{ "_id" : "01373", "city" : "SOUTH DEERFIELD", "loc" : [ -72.615268, 42.475616 ], "pop" : 5118, "state" : "MA" }
+{ "_id" : "01375", "city" : "SUNDERLAND", "loc" : [ -72.56756900000001, 42.453947 ], "pop" : 3399, "state" : "MA" }
+{ "_id" : "01376", "city" : "TURNERS FALLS", "loc" : [ -72.54701, 42.606521 ], "pop" : 7100, "state" : "MA" }
+{ "_id" : "01379", "city" : "WENDELL", "loc" : [ -72.400851, 42.565644 ], "pop" : 393, "state" : "MA" }
+{ "_id" : "01420", "city" : "FITCHBURG", "loc" : [ -71.803133, 42.579563 ], "pop" : 41194, "state" : "MA" }
+{ "_id" : "01430", "city" : "ASHBURNHAM", "loc" : [ -71.92666, 42.649614 ], "pop" : 5433, "state" : "MA" }
+{ "_id" : "01431", "city" : "ASHBY", "loc" : [ -71.817369, 42.674462 ], "pop" : 2649, "state" : "MA" }
+{ "_id" : "01432", "city" : "AYER", "loc" : [ -71.578763, 42.55914 ], "pop" : 6871, "state" : "MA" }
+{ "_id" : "01433", "city" : "FT DEVENS", "loc" : [ -71.621819, 42.532416 ], "pop" : 8480, "state" : "MA" }
+{ "_id" : "01436", "city" : "BALDWINVILLE", "loc" : [ -72.06464699999999, 42.593568 ], "pop" : 4386, "state" : "MA" }
+{ "_id" : "01440", "city" : "GARDNER", "loc" : [ -71.9898, 42.57405 ], "pop" : 20125, "state" : "MA" }
+{ "_id" : "01450", "city" : "GROTON", "loc" : [ -71.55837099999999, 42.612351 ], "pop" : 7504, "state" : "MA" }
+{ "_id" : "01451", "city" : "HARVARD", "loc" : [ -71.575293, 42.498565 ], "pop" : 4445, "state" : "MA" }
+{ "_id" : "01452", "city" : "HUBBARDSTON", "loc" : [ -72.001159, 42.486538 ], "pop" : 2797, "state" : "MA" }
+{ "_id" : "01453", "city" : "LEOMINSTER", "loc" : [ -71.756308, 42.52744 ], "pop" : 38145, "state" : "MA" }
+{ "_id" : "01460", "city" : "LITTLETON", "loc" : [ -71.487667, 42.540132 ], "pop" : 7066, "state" : "MA" }
+{ "_id" : "01462", "city" : "LUNENBURG", "loc" : [ -71.726642, 42.58843 ], "pop" : 9117, "state" : "MA" }
+{ "_id" : "01463", "city" : "PEPPERELL", "loc" : [ -71.59339199999999, 42.668888 ], "pop" : 10178, "state" : "MA" }
+{ "_id" : "01464", "city" : "SHIRLEY CENTER", "loc" : [ -71.646444, 42.558653 ], "pop" : 6118, "state" : "MA" }
+{ "_id" : "01468", "city" : "TEMPLETON", "loc" : [ -72.064971, 42.545976 ], "pop" : 2058, "state" : "MA" }
+{ "_id" : "01469", "city" : "TOWNSEND", "loc" : [ -71.689646, 42.652511 ], "pop" : 6112, "state" : "MA" }
+{ "_id" : "01473", "city" : "WESTMINSTER", "loc" : [ -71.909599, 42.548319 ], "pop" : 6191, "state" : "MA" }
+{ "_id" : "01474", "city" : "W TOWNSEND", "loc" : [ -71.74057000000001, 42.670404 ], "pop" : 2452, "state" : "MA" }
+{ "_id" : "01475", "city" : "WINCHENDON", "loc" : [ -72.047524, 42.678943 ], "pop" : 8805, "state" : "MA" }
+{ "_id" : "01501", "city" : "AUBURN", "loc" : [ -71.839144, 42.205502 ], "pop" : 15007, "state" : "MA" }
+{ "_id" : "01503", "city" : "BERLIN", "loc" : [ -71.635634, 42.384438 ], "pop" : 2293, "state" : "MA" }
+{ "_id" : "01504", "city" : "BLACKSTONE", "loc" : [ -71.52691, 42.028708 ], "pop" : 8023, "state" : "MA" }
+{ "_id" : "01505", "city" : "BOYLSTON", "loc" : [ -71.731042, 42.337727 ], "pop" : 3517, "state" : "MA" }
+{ "_id" : "01506", "city" : "BROOKFIELD", "loc" : [ -72.098887, 42.199141 ], "pop" : 2968, "state" : "MA" }
+{ "_id" : "01507", "city" : "CHARLTON", "loc" : [ -71.96638400000001, 42.137902 ], "pop" : 9576, "state" : "MA" }
+{ "_id" : "01510", "city" : "CLINTON", "loc" : [ -71.682847, 42.418147 ], "pop" : 13269, "state" : "MA" }
+{ "_id" : "01515", "city" : "EAST BROOKFIELD", "loc" : [ -72.048078, 42.219308 ], "pop" : 2033, "state" : "MA" }
+{ "_id" : "01516", "city" : "EAST DOUGLAS", "loc" : [ -71.72661100000001, 42.060566 ], "pop" : 5594, "state" : "MA" }
+{ "_id" : "01518", "city" : "FISKDALE", "loc" : [ -72.11776399999999, 42.122762 ], "pop" : 774, "state" : "MA" }
+{ "_id" : "01519", "city" : "GRAFTON", "loc" : [ -71.686848, 42.200371 ], "pop" : 4910, "state" : "MA" }
+{ "_id" : "01520", "city" : "HOLDEN", "loc" : [ -71.84142, 42.341983 ], "pop" : 12051, "state" : "MA" }
+{ "_id" : "01521", "city" : "HOLLAND", "loc" : [ -72.15437300000001, 42.040264 ], "pop" : 747, "state" : "MA" }
+{ "_id" : "01522", "city" : "JEFFERSON", "loc" : [ -71.87058, 42.375519 ], "pop" : 2478, "state" : "MA" }
+{ "_id" : "01523", "city" : "LANCASTER", "loc" : [ -71.686831, 42.450984 ], "pop" : 6018, "state" : "MA" }
+{ "_id" : "01524", "city" : "LEICESTER", "loc" : [ -71.918829, 42.237047 ], "pop" : 6527, "state" : "MA" }
+{ "_id" : "01527", "city" : "MILLBURY", "loc" : [ -71.764438, 42.196779 ], "pop" : 12228, "state" : "MA" }
+{ "_id" : "01529", "city" : "MILLVILLE", "loc" : [ -71.579813, 42.033102 ], "pop" : 2236, "state" : "MA" }
+{ "_id" : "01531", "city" : "NEW BRAINTREE", "loc" : [ -72.13064199999999, 42.31977 ], "pop" : 881, "state" : "MA" }
+{ "_id" : "01532", "city" : "NORTHBOROUGH", "loc" : [ -71.646372, 42.318242 ], "pop" : 11930, "state" : "MA" }
+{ "_id" : "01534", "city" : "NORTHBRIDGE", "loc" : [ -71.65636600000001, 42.1494 ], "pop" : 4564, "state" : "MA" }
+{ "_id" : "01535", "city" : "NORTH BROOKFIELD", "loc" : [ -72.08212899999999, 42.266455 ], "pop" : 4755, "state" : "MA" }
+{ "_id" : "01536", "city" : "NORTH GRAFTON", "loc" : [ -71.70369100000001, 42.229726 ], "pop" : 5401, "state" : "MA" }
+{ "_id" : "01537", "city" : "NORTH OXFORD", "loc" : [ -71.885953, 42.16549 ], "pop" : 3031, "state" : "MA" }
+{ "_id" : "01540", "city" : "OXFORD", "loc" : [ -71.86867700000001, 42.11285 ], "pop" : 9557, "state" : "MA" }
+{ "_id" : "01541", "city" : "PRINCETON", "loc" : [ -71.876245, 42.450812 ], "pop" : 3189, "state" : "MA" }
+{ "_id" : "01542", "city" : "ROCHDALE", "loc" : [ -71.906882, 42.199685 ], "pop" : 1154, "state" : "MA" }
+{ "_id" : "01543", "city" : "RUTLAND", "loc" : [ -71.94895099999999, 42.376199 ], "pop" : 4936, "state" : "MA" }
+{ "_id" : "01545", "city" : "SHREWSBURY", "loc" : [ -71.72050299999999, 42.284801 ], "pop" : 24146, "state" : "MA" }
+{ "_id" : "01550", "city" : "SOUTHBRIDGE", "loc" : [ -72.035347, 42.075024 ], "pop" : 17816, "state" : "MA" }
+{ "_id" : "01560", "city" : "SOUTH GRAFTON", "loc" : [ -71.692725, 42.176042 ], "pop" : 2719, "state" : "MA" }
+{ "_id" : "01562", "city" : "SPENCER", "loc" : [ -71.990617, 42.244103 ], "pop" : 11598, "state" : "MA" }
+{ "_id" : "01564", "city" : "STERLING", "loc" : [ -71.775192, 42.435351 ], "pop" : 6481, "state" : "MA" }
+{ "_id" : "01566", "city" : "STURBRIDGE", "loc" : [ -72.084233, 42.112619 ], "pop" : 7001, "state" : "MA" }
+{ "_id" : "01568", "city" : "WEST UPTON", "loc" : [ -71.608014, 42.173275 ], "pop" : 4682, "state" : "MA" }
+{ "_id" : "01569", "city" : "UXBRIDGE", "loc" : [ -71.632869, 42.074426 ], "pop" : 10364, "state" : "MA" }
+{ "_id" : "01570", "city" : "DUDLEY HILL", "loc" : [ -71.839467, 42.047574 ], "pop" : 3735, "state" : "MA" }
+{ "_id" : "01571", "city" : "DUDLEY", "loc" : [ -71.89322799999999, 42.048894 ], "pop" : 22001, "state" : "MA" }
+{ "_id" : "01581", "city" : "WESTBOROUGH", "loc" : [ -71.617604, 42.267891 ], "pop" : 14132, "state" : "MA" }
+{ "_id" : "01583", "city" : "WEST BOYLSTON", "loc" : [ -71.783822, 42.35836 ], "pop" : 6611, "state" : "MA" }
+{ "_id" : "01585", "city" : "WEST BROOKFIELD", "loc" : [ -72.15113700000001, 42.244137 ], "pop" : 3528, "state" : "MA" }
+{ "_id" : "01588", "city" : "WHITINSVILLE", "loc" : [ -71.664357, 42.115319 ], "pop" : 8807, "state" : "MA" }
+{ "_id" : "01590", "city" : "WILKINSONVILLE", "loc" : [ -71.74841600000001, 42.140586 ], "pop" : 6719, "state" : "MA" }
+{ "_id" : "01602", "city" : "WORCESTER", "loc" : [ -71.841678, 42.270251 ], "pop" : 19988, "state" : "MA" }
+{ "_id" : "01603", "city" : "WORCESTER", "loc" : [ -71.83799500000001, 42.245033 ], "pop" : 18605, "state" : "MA" }
+{ "_id" : "01604", "city" : "WORCESTER", "loc" : [ -71.774626, 42.254084 ], "pop" : 29036, "state" : "MA" }
+{ "_id" : "01605", "city" : "WORCESTER", "loc" : [ -71.78879499999999, 42.289391 ], "pop" : 25695, "state" : "MA" }
+{ "_id" : "01606", "city" : "WORCESTER", "loc" : [ -71.79577399999999, 42.311029 ], "pop" : 18213, "state" : "MA" }
+{ "_id" : "01607", "city" : "WORCESTER", "loc" : [ -71.793837, 42.230294 ], "pop" : 9048, "state" : "MA" }
+{ "_id" : "01608", "city" : "WORCESTER", "loc" : [ -71.800262, 42.262425 ], "pop" : 3646, "state" : "MA" }
+{ "_id" : "01609", "city" : "WORCESTER", "loc" : [ -71.81745600000001, 42.275387 ], "pop" : 21905, "state" : "MA" }
+{ "_id" : "01610", "city" : "WORCESTER", "loc" : [ -71.81079800000001, 42.249186 ], "pop" : 23720, "state" : "MA" }
+{ "_id" : "01611", "city" : "CHERRY VALLEY", "loc" : [ -71.874971, 42.237287 ], "pop" : 2510, "state" : "MA" }
+{ "_id" : "01612", "city" : "PAXTON", "loc" : [ -71.92023399999999, 42.306646 ], "pop" : 4047, "state" : "MA" }
+{ "_id" : "01701", "city" : "FRAMINGHAM", "loc" : [ -71.42548600000001, 42.300665 ], "pop" : 65046, "state" : "MA" }
+{ "_id" : "01718", "city" : "VILLAGE OF NAGOG", "loc" : [ -71.422354, 42.514941 ], "pop" : 2330, "state" : "MA" }
+{ "_id" : "01719", "city" : "BOXBORO", "loc" : [ -71.51822900000001, 42.486876 ], "pop" : 3343, "state" : "MA" }
+{ "_id" : "01720", "city" : "ACTON", "loc" : [ -71.448255, 42.475076 ], "pop" : 15514, "state" : "MA" }
+{ "_id" : "01721", "city" : "ASHLAND", "loc" : [ -71.458347, 42.253909 ], "pop" : 12066, "state" : "MA" }
+{ "_id" : "01730", "city" : "BEDFORD", "loc" : [ -71.276796, 42.484287 ], "pop" : 16147, "state" : "MA" }
+{ "_id" : "01740", "city" : "BOLTON", "loc" : [ -71.60759299999999, 42.436523 ], "pop" : 3134, "state" : "MA" }
+{ "_id" : "01741", "city" : "CARLISLE", "loc" : [ -71.35189200000001, 42.528562 ], "pop" : 4333, "state" : "MA" }
+{ "_id" : "01742", "city" : "CONCORD", "loc" : [ -71.374741, 42.456701 ], "pop" : 17076, "state" : "MA" }
+{ "_id" : "01745", "city" : "SOUTHBOROUGH", "loc" : [ -71.502256, 42.293221 ], "pop" : 506, "state" : "MA" }
+{ "_id" : "01746", "city" : "HOLLISTON", "loc" : [ -71.436059, 42.202641 ], "pop" : 12917, "state" : "MA" }
+{ "_id" : "01747", "city" : "HOPEDALE", "loc" : [ -71.537601, 42.126796 ], "pop" : 5649, "state" : "MA" }
+{ "_id" : "01748", "city" : "HOPKINTON", "loc" : [ -71.53017800000001, 42.219046 ], "pop" : 9191, "state" : "MA" }
+{ "_id" : "01749", "city" : "HUDSON", "loc" : [ -71.560896, 42.391796 ], "pop" : 17233, "state" : "MA" }
+{ "_id" : "01752", "city" : "MARLBOROUGH", "loc" : [ -71.54335500000001, 42.350861 ], "pop" : 31813, "state" : "MA" }
+{ "_id" : "01754", "city" : "MAYNARD", "loc" : [ -71.454975, 42.432118 ], "pop" : 10325, "state" : "MA" }
+{ "_id" : "01756", "city" : "MENDON", "loc" : [ -71.549882, 42.096744 ], "pop" : 4010, "state" : "MA" }
+{ "_id" : "01757", "city" : "MILFORD", "loc" : [ -71.527402, 42.151142 ], "pop" : 25372, "state" : "MA" }
+{ "_id" : "01760", "city" : "NATICK", "loc" : [ -71.35741, 42.287476 ], "pop" : 30432, "state" : "MA" }
+{ "_id" : "01770", "city" : "SHERBORN", "loc" : [ -71.37871699999999, 42.233088 ], "pop" : 3998, "state" : "MA" }
+{ "_id" : "01772", "city" : "SOUTHBOROUGH", "loc" : [ -71.531997, 42.293919 ], "pop" : 6122, "state" : "MA" }
+{ "_id" : "01773", "city" : "LINCOLN", "loc" : [ -71.313723, 42.421723 ], "pop" : 4515, "state" : "MA" }
+{ "_id" : "01775", "city" : "STOW", "loc" : [ -71.515019, 42.430785 ], "pop" : 5328, "state" : "MA" }
+{ "_id" : "01776", "city" : "SUDBURY", "loc" : [ -71.42815899999999, 42.383655 ], "pop" : 14358, "state" : "MA" }
+{ "_id" : "01778", "city" : "WAYLAND", "loc" : [ -71.35878099999999, 42.348629 ], "pop" : 11874, "state" : "MA" }
+{ "_id" : "01801", "city" : "WOBURN", "loc" : [ -71.157404, 42.482894 ], "pop" : 36152, "state" : "MA" }
+{ "_id" : "01803", "city" : "BURLINGTON", "loc" : [ -71.20043699999999, 42.508942 ], "pop" : 23093, "state" : "MA" }
+{ "_id" : "01810", "city" : "ANDOVER", "loc" : [ -71.156481, 42.64956 ], "pop" : 29161, "state" : "MA" }
+{ "_id" : "01821", "city" : "BILLERICA", "loc" : [ -71.25175400000001, 42.551874 ], "pop" : 28899, "state" : "MA" }
+{ "_id" : "01824", "city" : "SOUTH CHELMSFORD", "loc" : [ -71.35752100000001, 42.59356 ], "pop" : 24457, "state" : "MA" }
+{ "_id" : "01826", "city" : "DRACUT", "loc" : [ -71.318592, 42.676422 ], "pop" : 25594, "state" : "MA" }
+{ "_id" : "01827", "city" : "DUNSTABLE", "loc" : [ -71.49520099999999, 42.673917 ], "pop" : 2166, "state" : "MA" }
+{ "_id" : "01830", "city" : "HAVERHILL", "loc" : [ -71.072057, 42.785605 ], "pop" : 22445, "state" : "MA" }
+{ "_id" : "01832", "city" : "HAVERHILL", "loc" : [ -71.10951900000001, 42.779154 ], "pop" : 16860, "state" : "MA" }
+{ "_id" : "01833", "city" : "GEORGETOWN", "loc" : [ -70.98223900000001, 42.728067 ], "pop" : 6384, "state" : "MA" }
+{ "_id" : "01834", "city" : "GROVELAND", "loc" : [ -71.027018, 42.753027 ], "pop" : 5214, "state" : "MA" }
+{ "_id" : "01835", "city" : "BRADFORD", "loc" : [ -71.08548999999999, 42.758597 ], "pop" : 12078, "state" : "MA" }
+{ "_id" : "01840", "city" : "LAWRENCE", "loc" : [ -71.16381, 42.707958 ], "pop" : 2728, "state" : "MA" }
+{ "_id" : "01841", "city" : "LAWRENCE", "loc" : [ -71.16699699999999, 42.711545 ], "pop" : 45555, "state" : "MA" }
+{ "_id" : "01843", "city" : "LAWRENCE", "loc" : [ -71.160506, 42.691053 ], "pop" : 22285, "state" : "MA" }
+{ "_id" : "01844", "city" : "METHUEN", "loc" : [ -71.181031, 42.728019 ], "pop" : 39664, "state" : "MA" }
+{ "_id" : "01845", "city" : "NORTH ANDOVER", "loc" : [ -71.109004, 42.682583 ], "pop" : 22792, "state" : "MA" }
+{ "_id" : "01850", "city" : "LOWELL", "loc" : [ -71.30507799999999, 42.656035 ], "pop" : 15434, "state" : "MA" }
+{ "_id" : "01851", "city" : "LOWELL", "loc" : [ -71.332882, 42.631548 ], "pop" : 28154, "state" : "MA" }
+{ "_id" : "01852", "city" : "LOWELL", "loc" : [ -71.298331, 42.634413 ], "pop" : 33379, "state" : "MA" }
+{ "_id" : "01854", "city" : "LOWELL", "loc" : [ -71.335464, 42.649254 ], "pop" : 26472, "state" : "MA" }
+{ "_id" : "01860", "city" : "MERRIMAC", "loc" : [ -71.00465800000001, 42.834629 ], "pop" : 5196, "state" : "MA" }
+{ "_id" : "01862", "city" : "NORTH BILLERICA", "loc" : [ -71.290217, 42.575694 ], "pop" : 8720, "state" : "MA" }
+{ "_id" : "01863", "city" : "NORTH CHELMSFORD", "loc" : [ -71.390834, 42.634737 ], "pop" : 7878, "state" : "MA" }
+{ "_id" : "01864", "city" : "NORTH READING", "loc" : [ -71.094711, 42.581898 ], "pop" : 12002, "state" : "MA" }
+{ "_id" : "01867", "city" : "READING", "loc" : [ -71.109021, 42.527986 ], "pop" : 22539, "state" : "MA" }
+{ "_id" : "01876", "city" : "TEWKSBURY", "loc" : [ -71.223224, 42.60283 ], "pop" : 27269, "state" : "MA" }
+{ "_id" : "01879", "city" : "TYNGSBORO", "loc" : [ -71.415766, 42.672383 ], "pop" : 8643, "state" : "MA" }
+{ "_id" : "01880", "city" : "WAKEFIELD", "loc" : [ -71.068471, 42.500886 ], "pop" : 24830, "state" : "MA" }
+{ "_id" : "01886", "city" : "GRANITEVILLE", "loc" : [ -71.438143, 42.589959 ], "pop" : 16430, "state" : "MA" }
+{ "_id" : "01887", "city" : "WILMINGTON", "loc" : [ -71.17230600000001, 42.558143 ], "pop" : 17647, "state" : "MA" }
+{ "_id" : "01890", "city" : "WINCHESTER", "loc" : [ -71.14407, 42.453028 ], "pop" : 20232, "state" : "MA" }
+{ "_id" : "01901", "city" : "LYNN", "loc" : [ -70.945516, 42.463378 ], "pop" : 1187, "state" : "MA" }
+{ "_id" : "01902", "city" : "LYNN", "loc" : [ -70.94198900000001, 42.469814 ], "pop" : 41625, "state" : "MA" }
+{ "_id" : "01904", "city" : "EAST LYNN", "loc" : [ -70.96279800000001, 42.487453 ], "pop" : 17073, "state" : "MA" }
+{ "_id" : "01905", "city" : "WEST LYNN", "loc" : [ -70.97382500000001, 42.46453 ], "pop" : 21360, "state" : "MA" }
+{ "_id" : "01906", "city" : "SAUGUS", "loc" : [ -71.011093, 42.463344 ], "pop" : 25487, "state" : "MA" }
+{ "_id" : "01907", "city" : "SWAMPSCOTT", "loc" : [ -70.909774, 42.474611 ], "pop" : 13650, "state" : "MA" }
+{ "_id" : "01908", "city" : "NAHANT", "loc" : [ -70.927739, 42.426098 ], "pop" : 3828, "state" : "MA" }
+{ "_id" : "01913", "city" : "AMESBURY", "loc" : [ -70.93668099999999, 42.855879 ], "pop" : 14970, "state" : "MA" }
+{ "_id" : "01915", "city" : "BEVERLY", "loc" : [ -70.875939, 42.560825 ], "pop" : 38259, "state" : "MA" }
+{ "_id" : "01921", "city" : "BOXFORD", "loc" : [ -71.01137199999999, 42.679719 ], "pop" : 6249, "state" : "MA" }
+{ "_id" : "01922", "city" : "BYFIELD", "loc" : [ -70.935053, 42.756792 ], "pop" : 2006, "state" : "MA" }
+{ "_id" : "01923", "city" : "DANVERS", "loc" : [ -70.94246099999999, 42.569402 ], "pop" : 23977, "state" : "MA" }
+{ "_id" : "01929", "city" : "ESSEX", "loc" : [ -70.782794, 42.628629 ], "pop" : 3260, "state" : "MA" }
+{ "_id" : "01930", "city" : "GLOUCESTER", "loc" : [ -70.672149, 42.620836 ], "pop" : 28716, "state" : "MA" }
+{ "_id" : "01938", "city" : "IPSWICH", "loc" : [ -70.84935299999999, 42.680877 ], "pop" : 11864, "state" : "MA" }
+{ "_id" : "01940", "city" : "LYNNFIELD", "loc" : [ -71.033873, 42.532711 ], "pop" : 11274, "state" : "MA" }
+{ "_id" : "01944", "city" : "MANCHESTER", "loc" : [ -70.76743399999999, 42.57963 ], "pop" : 5286, "state" : "MA" }
+{ "_id" : "01945", "city" : "MARBLEHEAD", "loc" : [ -70.865291, 42.498431 ], "pop" : 19971, "state" : "MA" }
+{ "_id" : "01949", "city" : "MIDDLETON", "loc" : [ -71.013004, 42.594184 ], "pop" : 4921, "state" : "MA" }
+{ "_id" : "01950", "city" : "NEWBURYPORT", "loc" : [ -70.884668, 42.812964 ], "pop" : 16317, "state" : "MA" }
+{ "_id" : "01951", "city" : "NEWBURY", "loc" : [ -70.84737699999999, 42.783475 ], "pop" : 3710, "state" : "MA" }
+{ "_id" : "01952", "city" : "SALISBURY", "loc" : [ -70.858822, 42.850678 ], "pop" : 6879, "state" : "MA" }
+{ "_id" : "01960", "city" : "PEABODY", "loc" : [ -70.96119400000001, 42.532579 ], "pop" : 47685, "state" : "MA" }
+{ "_id" : "01966", "city" : "ROCKPORT", "loc" : [ -70.619424, 42.657973 ], "pop" : 7482, "state" : "MA" }
+{ "_id" : "01969", "city" : "ROWLEY", "loc" : [ -70.90696, 42.713753 ], "pop" : 4368, "state" : "MA" }
+{ "_id" : "01970", "city" : "SALEM", "loc" : [ -70.90034300000001, 42.515114 ], "pop" : 37642, "state" : "MA" }
+{ "_id" : "01982", "city" : "SOUTH HAMILTON", "loc" : [ -70.856132, 42.618478 ], "pop" : 7288, "state" : "MA" }
+{ "_id" : "01983", "city" : "TOPSFIELD", "loc" : [ -70.948843, 42.641546 ], "pop" : 5763, "state" : "MA" }
+{ "_id" : "01984", "city" : "WENHAM", "loc" : [ -70.87862199999999, 42.60166 ], "pop" : 4148, "state" : "MA" }
+{ "_id" : "01985", "city" : "WEST NEWBURY", "loc" : [ -70.977811, 42.794865 ], "pop" : 3421, "state" : "MA" }
+{ "_id" : "02019", "city" : "BELLINGHAM", "loc" : [ -71.476829, 42.074573 ], "pop" : 14873, "state" : "MA" }
+{ "_id" : "02021", "city" : "CANTON", "loc" : [ -71.135536, 42.164454 ], "pop" : 18530, "state" : "MA" }
+{ "_id" : "02025", "city" : "COHASSET", "loc" : [ -70.812788, 42.239484 ], "pop" : 7075, "state" : "MA" }
+{ "_id" : "02026", "city" : "DEDHAM", "loc" : [ -71.163741, 42.243685 ], "pop" : 23782, "state" : "MA" }
+{ "_id" : "02030", "city" : "DOVER", "loc" : [ -71.285363, 42.236233 ], "pop" : 4915, "state" : "MA" }
+{ "_id" : "02032", "city" : "EAST WALPOLE", "loc" : [ -71.2179, 42.15324 ], "pop" : 3844, "state" : "MA" }
+{ "_id" : "02035", "city" : "FOXBORO", "loc" : [ -71.24412700000001, 42.064938 ], "pop" : 14293, "state" : "MA" }
+{ "_id" : "02038", "city" : "FRANKLIN", "loc" : [ -71.40578600000001, 42.09347 ], "pop" : 22128, "state" : "MA" }
+{ "_id" : "02043", "city" : "HINGHAM", "loc" : [ -70.891051, 42.224485 ], "pop" : 19821, "state" : "MA" }
+{ "_id" : "02045", "city" : "HULL", "loc" : [ -70.87544200000001, 42.285346 ], "pop" : 10466, "state" : "MA" }
+{ "_id" : "02048", "city" : "MANSFIELD", "loc" : [ -71.217775, 42.021238 ], "pop" : 16676, "state" : "MA" }
+{ "_id" : "02050", "city" : "MARSHFIELD", "loc" : [ -70.69931, 42.106177 ], "pop" : 21782, "state" : "MA" }
+{ "_id" : "02052", "city" : "MEDFIELD", "loc" : [ -71.304813, 42.184525 ], "pop" : 10531, "state" : "MA" }
+{ "_id" : "02053", "city" : "MEDWAY", "loc" : [ -71.42171500000001, 42.151363 ], "pop" : 9902, "state" : "MA" }
+{ "_id" : "02054", "city" : "MILLIS", "loc" : [ -71.360693, 42.166938 ], "pop" : 7613, "state" : "MA" }
+{ "_id" : "02056", "city" : "NORFOLK", "loc" : [ -71.32693399999999, 42.117746 ], "pop" : 9259, "state" : "MA" }
+{ "_id" : "02061", "city" : "NORWELL", "loc" : [ -70.82172, 42.159574 ], "pop" : 9279, "state" : "MA" }
+{ "_id" : "02062", "city" : "NORWOOD", "loc" : [ -71.20331299999999, 42.186843 ], "pop" : 28700, "state" : "MA" }
+{ "_id" : "02066", "city" : "SCITUATE", "loc" : [ -70.752476, 42.203235 ], "pop" : 16535, "state" : "MA" }
+{ "_id" : "02067", "city" : "SHARON", "loc" : [ -71.175872, 42.109388 ], "pop" : 15873, "state" : "MA" }
+{ "_id" : "02071", "city" : "SOUTH WALPOLE", "loc" : [ -71.275235, 42.099203 ], "pop" : 752, "state" : "MA" }
+{ "_id" : "02072", "city" : "STOUGHTON", "loc" : [ -71.10735699999999, 42.125279 ], "pop" : 26777, "state" : "MA" }
+{ "_id" : "02081", "city" : "WALPOLE", "loc" : [ -71.254391, 42.144413 ], "pop" : 15615, "state" : "MA" }
+{ "_id" : "02090", "city" : "WESTWOOD", "loc" : [ -71.210426, 42.214824 ], "pop" : 12557, "state" : "MA" }
+{ "_id" : "02093", "city" : "WRENTHAM", "loc" : [ -71.339568, 42.061746 ], "pop" : 9006, "state" : "MA" }
+{ "_id" : "02108", "city" : "BOSTON", "loc" : [ -71.068432, 42.357603 ], "pop" : 3697, "state" : "MA" }
+{ "_id" : "02109", "city" : "BOSTON", "loc" : [ -71.053386, 42.362963 ], "pop" : 3926, "state" : "MA" }
+{ "_id" : "02110", "city" : "BOSTON", "loc" : [ -71.051417, 42.357636 ], "pop" : 957, "state" : "MA" }
+{ "_id" : "02111", "city" : "BOSTON", "loc" : [ -71.0629, 42.350348 ], "pop" : 3759, "state" : "MA" }
+{ "_id" : "02113", "city" : "BOSTON", "loc" : [ -71.055958, 42.365656 ], "pop" : 6698, "state" : "MA" }
+{ "_id" : "02114", "city" : "BOSTON", "loc" : [ -71.06823, 42.361111 ], "pop" : 10246, "state" : "MA" }
+{ "_id" : "02115", "city" : "BOSTON", "loc" : [ -71.092215, 42.342706 ], "pop" : 25597, "state" : "MA" }
+{ "_id" : "02116", "city" : "BOSTON", "loc" : [ -71.076798, 42.349201 ], "pop" : 17459, "state" : "MA" }
+{ "_id" : "02118", "city" : "ROXBURY", "loc" : [ -71.075627, 42.340154 ], "pop" : 21914, "state" : "MA" }
+{ "_id" : "02119", "city" : "ROXBURY", "loc" : [ -71.086923, 42.322414 ], "pop" : 25207, "state" : "MA" }
+{ "_id" : "02120", "city" : "ROXBURY", "loc" : [ -71.097978, 42.332844 ], "pop" : 14212, "state" : "MA" }
+{ "_id" : "02121", "city" : "DORCHESTER", "loc" : [ -71.08305, 42.307503 ], "pop" : 25602, "state" : "MA" }
+{ "_id" : "02122", "city" : "DORCHESTER", "loc" : [ -71.05830400000001, 42.297278 ], "pop" : 21266, "state" : "MA" }
+{ "_id" : "02124", "city" : "DORCHESTER", "loc" : [ -71.072898, 42.287984 ], "pop" : 48560, "state" : "MA" }
+{ "_id" : "02125", "city" : "DORCHESTER", "loc" : [ -71.061924, 42.315305 ], "pop" : 31393, "state" : "MA" }
+{ "_id" : "02126", "city" : "MATTAPAN", "loc" : [ -71.09387099999999, 42.273889 ], "pop" : 27808, "state" : "MA" }
+{ "_id" : "02127", "city" : "SOUTH BOSTON", "loc" : [ -71.043792, 42.333454 ], "pop" : 29170, "state" : "MA" }
+{ "_id" : "02128", "city" : "EAST BOSTON", "loc" : [ -71.028682, 42.378137 ], "pop" : 32941, "state" : "MA" }
+{ "_id" : "02129", "city" : "CHARLESTOWN", "loc" : [ -71.062715, 42.377815 ], "pop" : 14775, "state" : "MA" }
+{ "_id" : "02130", "city" : "JAMAICA PLAIN", "loc" : [ -71.11149500000001, 42.312596 ], "pop" : 36571, "state" : "MA" }
+{ "_id" : "02131", "city" : "ROSLINDALE", "loc" : [ -71.129543, 42.283615 ], "pop" : 32677, "state" : "MA" }
+{ "_id" : "02132", "city" : "WEST ROXBURY", "loc" : [ -71.158868, 42.27868 ], "pop" : 26366, "state" : "MA" }
+{ "_id" : "02134", "city" : "ALLSTON", "loc" : [ -71.13286600000001, 42.353519 ], "pop" : 23775, "state" : "MA" }
+{ "_id" : "02135", "city" : "BRIGHTON", "loc" : [ -71.156599, 42.34779 ], "pop" : 35011, "state" : "MA" }
+{ "_id" : "02136", "city" : "HYDE PARK", "loc" : [ -71.126052, 42.253989 ], "pop" : 24260, "state" : "MA" }
+{ "_id" : "02138", "city" : "CAMBRIDGE", "loc" : [ -71.12561100000001, 42.377045 ], "pop" : 33841, "state" : "MA" }
+{ "_id" : "02139", "city" : "CAMBRIDGE", "loc" : [ -71.10415500000001, 42.364688 ], "pop" : 33149, "state" : "MA" }
+{ "_id" : "02140", "city" : "NORTH CAMBRIDGE", "loc" : [ -71.129379, 42.391366 ], "pop" : 16313, "state" : "MA" }
+{ "_id" : "02141", "city" : "EAST CAMBRIDGE", "loc" : [ -71.08827700000001, 42.370701 ], "pop" : 10392, "state" : "MA" }
+{ "_id" : "02142", "city" : "CAMBRIDGE", "loc" : [ -71.083011, 42.362025 ], "pop" : 1336, "state" : "MA" }
+{ "_id" : "02143", "city" : "SOMERVILLE", "loc" : [ -71.102814, 42.382945 ], "pop" : 25597, "state" : "MA" }
+{ "_id" : "02144", "city" : "SOMERVILLE", "loc" : [ -71.12205899999999, 42.40032 ], "pop" : 26374, "state" : "MA" }
+{ "_id" : "02145", "city" : "SOMERVILLE", "loc" : [ -71.092944, 42.390678 ], "pop" : 24422, "state" : "MA" }
+{ "_id" : "02146", "city" : "BROOKLINE", "loc" : [ -71.128917, 42.339158 ], "pop" : 56614, "state" : "MA" }
+{ "_id" : "02148", "city" : "MALDEN", "loc" : [ -71.060507, 42.42911 ], "pop" : 54114, "state" : "MA" }
+{ "_id" : "02149", "city" : "EVERETT", "loc" : [ -71.05144799999999, 42.411199 ], "pop" : 35493, "state" : "MA" }
+{ "_id" : "02150", "city" : "CHELSEA", "loc" : [ -71.032521, 42.396252 ], "pop" : 28790, "state" : "MA" }
+{ "_id" : "02151", "city" : "REVERE", "loc" : [ -71.00516500000001, 42.413767 ], "pop" : 42766, "state" : "MA" }
+{ "_id" : "02152", "city" : "WINTHROP", "loc" : [ -70.98004299999999, 42.376294 ], "pop" : 18907, "state" : "MA" }
+{ "_id" : "02154", "city" : "NORTH WALTHAM", "loc" : [ -71.236497, 42.382492 ], "pop" : 57871, "state" : "MA" }
+{ "_id" : "02155", "city" : "MEDFORD", "loc" : [ -71.10868600000001, 42.417335 ], "pop" : 57338, "state" : "MA" }
+{ "_id" : "02158", "city" : "NEWTONVILLE", "loc" : [ -71.1902, 42.353835 ], "pop" : 13271, "state" : "MA" }
+{ "_id" : "02159", "city" : "NEWTON CENTER", "loc" : [ -71.191839, 42.318889 ], "pop" : 18726, "state" : "MA" }
+{ "_id" : "02160", "city" : "NEWTONVILLE", "loc" : [ -71.208771, 42.351961 ], "pop" : 8872, "state" : "MA" }
+{ "_id" : "02161", "city" : "NEWTON HIGHLANDS", "loc" : [ -71.20934699999999, 42.318512 ], "pop" : 6657, "state" : "MA" }
+{ "_id" : "02162", "city" : "NEWTONVILLE", "loc" : [ -71.258025, 42.330296 ], "pop" : 1427, "state" : "MA" }
+{ "_id" : "02163", "city" : "CAMBRIDGE", "loc" : [ -71.141879, 42.364005 ], "pop" : 0, "state" : "MA" }
+{ "_id" : "02164", "city" : "NEWTON UPPER FAL", "loc" : [ -71.221615, 42.312562 ], "pop" : 2597, "state" : "MA" }
+{ "_id" : "02165", "city" : "NEWTONVILLE", "loc" : [ -71.22795000000001, 42.352366 ], "pop" : 12027, "state" : "MA" }
+{ "_id" : "02166", "city" : "AUBURNDALE", "loc" : [ -71.247598, 42.345928 ], "pop" : 6123, "state" : "MA" }
+{ "_id" : "02167", "city" : "BOSTON COLLEGE", "loc" : [ -71.16271999999999, 42.31903 ], "pop" : 15619, "state" : "MA" }
+{ "_id" : "02168", "city" : "WABAN", "loc" : [ -71.23070300000001, 42.327049 ], "pop" : 5759, "state" : "MA" }
+{ "_id" : "02169", "city" : "QUINCY", "loc" : [ -70.997816, 42.249133 ], "pop" : 48920, "state" : "MA" }
+{ "_id" : "02170", "city" : "QUINCY", "loc" : [ -71.01864399999999, 42.26713 ], "pop" : 18330, "state" : "MA" }
+{ "_id" : "02171", "city" : "QUINCY", "loc" : [ -71.024141, 42.282519 ], "pop" : 18251, "state" : "MA" }
+{ "_id" : "02172", "city" : "EAST WATERTOWN", "loc" : [ -71.180266, 42.371497 ], "pop" : 33930, "state" : "MA" }
+{ "_id" : "02173", "city" : "LEXINGTON", "loc" : [ -71.225916, 42.445384 ], "pop" : 28994, "state" : "MA" }
+{ "_id" : "02174", "city" : "ARLINGTON", "loc" : [ -71.16251699999999, 42.417098 ], "pop" : 44539, "state" : "MA" }
+{ "_id" : "02176", "city" : "MELROSE", "loc" : [ -71.063191, 42.458066 ], "pop" : 28228, "state" : "MA" }
+{ "_id" : "02178", "city" : "BELMONT", "loc" : [ -71.17464699999999, 42.389656 ], "pop" : 24733, "state" : "MA" }
+{ "_id" : "02180", "city" : "STONEHAM", "loc" : [ -71.09780000000001, 42.482778 ], "pop" : 22147, "state" : "MA" }
+{ "_id" : "02181", "city" : "WELLESLEY", "loc" : [ -71.287966, 42.305593 ], "pop" : 26615, "state" : "MA" }
+{ "_id" : "02184", "city" : "BRAINTREE", "loc" : [ -70.99630399999999, 42.209284 ], "pop" : 33836, "state" : "MA" }
+{ "_id" : "02186", "city" : "MILTON", "loc" : [ -71.077051, 42.253663 ], "pop" : 25558, "state" : "MA" }
+{ "_id" : "02188", "city" : "WEYMOUTH", "loc" : [ -70.958248, 42.211327 ], "pop" : 13187, "state" : "MA" }
+{ "_id" : "02189", "city" : "WEYMOUTH", "loc" : [ -70.93167099999999, 42.211606 ], "pop" : 14055, "state" : "MA" }
+{ "_id" : "02190", "city" : "WEYMOUTH", "loc" : [ -70.94869, 42.172817 ], "pop" : 17668, "state" : "MA" }
+{ "_id" : "02191", "city" : "WEYMOUTH", "loc" : [ -70.944318, 42.243564 ], "pop" : 9153, "state" : "MA" }
+{ "_id" : "02192", "city" : "NEEDHAM", "loc" : [ -71.23517200000001, 42.278908 ], "pop" : 19570, "state" : "MA" }
+{ "_id" : "02193", "city" : "WESTON", "loc" : [ -71.300291, 42.359422 ], "pop" : 10221, "state" : "MA" }
+{ "_id" : "02194", "city" : "NEEDHAM", "loc" : [ -71.234363, 42.297702 ], "pop" : 8006, "state" : "MA" }
+{ "_id" : "02199", "city" : "BOSTON", "loc" : [ -71.082543, 42.347873 ], "pop" : 886, "state" : "MA" }
+{ "_id" : "02210", "city" : "BOSTON", "loc" : [ -71.046511, 42.348921 ], "pop" : 308, "state" : "MA" }
+{ "_id" : "02215", "city" : "BOSTON", "loc" : [ -71.102689, 42.347088 ], "pop" : 17769, "state" : "MA" }
+{ "_id" : "02322", "city" : "AVON", "loc" : [ -71.043738, 42.125825 ], "pop" : 4594, "state" : "MA" }
+{ "_id" : "02324", "city" : "BRIDGEWATER", "loc" : [ -70.97234, 41.977341 ], "pop" : 21198, "state" : "MA" }
+{ "_id" : "02330", "city" : "CARVER", "loc" : [ -70.767754, 41.888265 ], "pop" : 10573, "state" : "MA" }
+{ "_id" : "02332", "city" : "DUXBURY", "loc" : [ -70.716257, 42.039936 ], "pop" : 13913, "state" : "MA" }
+{ "_id" : "02333", "city" : "EAST BRIDGEWATER", "loc" : [ -70.944964, 42.031478 ], "pop" : 11104, "state" : "MA" }
+{ "_id" : "02338", "city" : "HALIFAX", "loc" : [ -70.84479399999999, 42.000159 ], "pop" : 6526, "state" : "MA" }
+{ "_id" : "02339", "city" : "HANOVER", "loc" : [ -70.857006, 42.121406 ], "pop" : 11912, "state" : "MA" }
+{ "_id" : "02341", "city" : "HANSON", "loc" : [ -70.865053, 42.061627 ], "pop" : 9037, "state" : "MA" }
+{ "_id" : "02343", "city" : "HOLBROOK", "loc" : [ -71.008273, 42.14641 ], "pop" : 11041, "state" : "MA" }
+{ "_id" : "02346", "city" : "MIDDLEBORO", "loc" : [ -70.892965, 41.888396 ], "pop" : 17867, "state" : "MA" }
+{ "_id" : "02347", "city" : "LAKEVILLE", "loc" : [ -70.958195, 41.837377 ], "pop" : 7785, "state" : "MA" }
+{ "_id" : "02351", "city" : "ABINGTON", "loc" : [ -70.95429300000001, 42.116715 ], "pop" : 13849, "state" : "MA" }
+{ "_id" : "02356", "city" : "NORTH EASTON", "loc" : [ -71.112337, 42.058956 ], "pop" : 10397, "state" : "MA" }
+{ "_id" : "02359", "city" : "PEMBROKE", "loc" : [ -70.80440400000001, 42.062072 ], "pop" : 14535, "state" : "MA" }
+{ "_id" : "02360", "city" : "PLYMOUTH", "loc" : [ -70.642004, 41.910404 ], "pop" : 45629, "state" : "MA" }
+{ "_id" : "02364", "city" : "KINGSTON", "loc" : [ -70.740993, 41.995022 ], "pop" : 9045, "state" : "MA" }
+{ "_id" : "02367", "city" : "PLYMPTON", "loc" : [ -70.804582, 41.96549 ], "pop" : 2384, "state" : "MA" }
+{ "_id" : "02368", "city" : "RANDOLPH", "loc" : [ -71.05139200000001, 42.173587 ], "pop" : 30057, "state" : "MA" }
+{ "_id" : "02370", "city" : "ROCKLAND", "loc" : [ -70.913263, 42.129286 ], "pop" : 16123, "state" : "MA" }
+{ "_id" : "02375", "city" : "SOUTH EASTON", "loc" : [ -71.098814, 42.025704 ], "pop" : 9247, "state" : "MA" }
+{ "_id" : "02379", "city" : "WEST BRIDGEWATER", "loc" : [ -71.016054, 42.025511 ], "pop" : 6440, "state" : "MA" }
+{ "_id" : "02382", "city" : "WHITMAN", "loc" : [ -70.93812699999999, 42.081603 ], "pop" : 13208, "state" : "MA" }
+{ "_id" : "02401", "city" : "BROCKTON", "loc" : [ -71.03434799999999, 42.081571 ], "pop" : 59498, "state" : "MA" }
+{ "_id" : "02402", "city" : "BROCKTON", "loc" : [ -71.001947, 42.088396 ], "pop" : 33290, "state" : "MA" }
+{ "_id" : "02532", "city" : "ONSET", "loc" : [ -70.59316800000001, 41.752918 ], "pop" : 12047, "state" : "MA" }
+{ "_id" : "02535", "city" : "CHILMARK", "loc" : [ -70.741613, 41.357523 ], "pop" : 952, "state" : "MA" }
+{ "_id" : "02536", "city" : "TEATICKET", "loc" : [ -70.565174, 41.58504 ], "pop" : 15976, "state" : "MA" }
+{ "_id" : "02537", "city" : "EAST SANDWICH", "loc" : [ -70.46822, 41.684603 ], "pop" : 7254, "state" : "MA" }
+{ "_id" : "02538", "city" : "EAST WAREHAM", "loc" : [ -70.653237, 41.768247 ], "pop" : 4778, "state" : "MA" }
+{ "_id" : "02539", "city" : "EDGARTOWN", "loc" : [ -70.53389300000001, 41.388856 ], "pop" : 3062, "state" : "MA" }
+{ "_id" : "02540", "city" : "FALMOUTH", "loc" : [ -70.621663, 41.564754 ], "pop" : 8588, "state" : "MA" }
+{ "_id" : "02542", "city" : "OTIS A F B", "loc" : [ -70.57383, 41.660927 ], "pop" : 2078, "state" : "MA" }
+{ "_id" : "02543", "city" : "WOODS HOLE", "loc" : [ -70.66431, 41.526272 ], "pop" : 833, "state" : "MA" }
+{ "_id" : "02554", "city" : "NANTUCKET", "loc" : [ -70.093216, 41.272529 ], "pop" : 6012, "state" : "MA" }
+{ "_id" : "02556", "city" : "NORTH FALMOUTH", "loc" : [ -70.623043, 41.641677 ], "pop" : 2651, "state" : "MA" }
+{ "_id" : "02559", "city" : "POCASSET", "loc" : [ -70.610512, 41.688115 ], "pop" : 3907, "state" : "MA" }
+{ "_id" : "02563", "city" : "SANDWICH", "loc" : [ -70.469325, 41.698304 ], "pop" : 9007, "state" : "MA" }
+{ "_id" : "02568", "city" : "VINEYARD HAVEN", "loc" : [ -70.593737, 41.449955 ], "pop" : 5924, "state" : "MA" }
+{ "_id" : "02571", "city" : "WAREHAM", "loc" : [ -70.71159400000001, 41.754084 ], "pop" : 9304, "state" : "MA" }
+{ "_id" : "02575", "city" : "WEST TISBURY", "loc" : [ -70.65580199999999, 41.413717 ], "pop" : 1603, "state" : "MA" }
+{ "_id" : "02576", "city" : "WEST WAREHAM", "loc" : [ -70.764179, 41.779617 ], "pop" : 3919, "state" : "MA" }
+{ "_id" : "02601", "city" : "WEST YARMOUTH", "loc" : [ -70.298176, 41.653682 ], "pop" : 14543, "state" : "MA" }
+{ "_id" : "02630", "city" : "BARNSTABLE", "loc" : [ -70.300067, 41.698289 ], "pop" : 1776, "state" : "MA" }
+{ "_id" : "02631", "city" : "BREWSTER", "loc" : [ -70.069868, 41.749179 ], "pop" : 8535, "state" : "MA" }
+{ "_id" : "02632", "city" : "CENTERVILLE", "loc" : [ -70.353196, 41.660585 ], "pop" : 10636, "state" : "MA" }
+{ "_id" : "02633", "city" : "SOUTH CHATHAM", "loc" : [ -69.98075799999999, 41.687634 ], "pop" : 4744, "state" : "MA" }
+{ "_id" : "02635", "city" : "COTUIT", "loc" : [ -70.433431, 41.696025 ], "pop" : 3266, "state" : "MA" }
+{ "_id" : "02638", "city" : "DENNIS", "loc" : [ -70.19105399999999, 41.732166 ], "pop" : 3216, "state" : "MA" }
+{ "_id" : "02639", "city" : "DENNIS PORT", "loc" : [ -70.132711, 41.664873 ], "pop" : 2510, "state" : "MA" }
+{ "_id" : "02642", "city" : "EASTHAM", "loc" : [ -69.984865, 41.840781 ], "pop" : 4582, "state" : "MA" }
+{ "_id" : "02644", "city" : "FORESTDALE", "loc" : [ -70.51431700000001, 41.682695 ], "pop" : 2712, "state" : "MA" }
+{ "_id" : "02645", "city" : "HARWICH", "loc" : [ -70.057929, 41.70082 ], "pop" : 7363, "state" : "MA" }
+{ "_id" : "02646", "city" : "HARWICH PORT", "loc" : [ -70.07675500000001, 41.67128 ], "pop" : 1843, "state" : "MA" }
+{ "_id" : "02648", "city" : "MARSTONS MILLS", "loc" : [ -70.416321, 41.670274 ], "pop" : 5777, "state" : "MA" }
+{ "_id" : "02649", "city" : "MASHPEE", "loc" : [ -70.485361, 41.618116 ], "pop" : 4469, "state" : "MA" }
+{ "_id" : "02650", "city" : "NORTH CHATHAM", "loc" : [ -69.966607, 41.70298 ], "pop" : 995, "state" : "MA" }
+{ "_id" : "02652", "city" : "NORTH TRURO", "loc" : [ -70.08750999999999, 42.033779 ], "pop" : 834, "state" : "MA" }
+{ "_id" : "02653", "city" : "ORLEANS", "loc" : [ -69.982198, 41.779161 ], "pop" : 5860, "state" : "MA" }
+{ "_id" : "02655", "city" : "OSTERVILLE", "loc" : [ -70.383726, 41.63005 ], "pop" : 2330, "state" : "MA" }
+{ "_id" : "02657", "city" : "PROVINCETOWN", "loc" : [ -70.186504, 42.053364 ], "pop" : 3561, "state" : "MA" }
+{ "_id" : "02659", "city" : "SOUTH CHATHAM", "loc" : [ -70.024106, 41.680126 ], "pop" : 840, "state" : "MA" }
+{ "_id" : "02660", "city" : "SOUTH DENNIS", "loc" : [ -70.15851000000001, 41.709711 ], "pop" : 6680, "state" : "MA" }
+{ "_id" : "02664", "city" : "BASS RIVER", "loc" : [ -70.19731, 41.672805 ], "pop" : 8514, "state" : "MA" }
+{ "_id" : "02666", "city" : "TRURO", "loc" : [ -70.05636199999999, 41.998792 ], "pop" : 739, "state" : "MA" }
+{ "_id" : "02667", "city" : "WELLFLEET", "loc" : [ -70.018587, 41.928934 ], "pop" : 2373, "state" : "MA" }
+{ "_id" : "02668", "city" : "WEST BARNSTABLE", "loc" : [ -70.371985, 41.700212 ], "pop" : 2311, "state" : "MA" }
+{ "_id" : "02670", "city" : "WEST DENNIS", "loc" : [ -70.168092, 41.662557 ], "pop" : 1347, "state" : "MA" }
+{ "_id" : "02671", "city" : "WEST HARWICH", "loc" : [ -70.113501, 41.669367 ], "pop" : 1061, "state" : "MA" }
+{ "_id" : "02673", "city" : "WEST YARMOUTH", "loc" : [ -70.23629699999999, 41.661367 ], "pop" : 6972, "state" : "MA" }
+{ "_id" : "02675", "city" : "YARMOUTH PORT", "loc" : [ -70.227014, 41.705149 ], "pop" : 5735, "state" : "MA" }
+{ "_id" : "02702", "city" : "ASSONET", "loc" : [ -71.06073600000001, 41.797458 ], "pop" : 3614, "state" : "MA" }
+{ "_id" : "02703", "city" : "ATTLEBORO", "loc" : [ -71.30092, 41.929599 ], "pop" : 38528, "state" : "MA" }
+{ "_id" : "02713", "city" : "CUTTYHUNK", "loc" : [ -70.87854, 41.443601 ], "pop" : 98, "state" : "MA" }
+{ "_id" : "02715", "city" : "DIGHTON", "loc" : [ -71.142723, 41.812505 ], "pop" : 1828, "state" : "MA" }
+{ "_id" : "02717", "city" : "EAST FREETOWN", "loc" : [ -70.967709, 41.763455 ], "pop" : 4883, "state" : "MA" }
+{ "_id" : "02718", "city" : "EAST TAUNTON", "loc" : [ -71.01922500000001, 41.873585 ], "pop" : 4800, "state" : "MA" }
+{ "_id" : "02719", "city" : "FAIRHAVEN", "loc" : [ -70.889608, 41.640924 ], "pop" : 16141, "state" : "MA" }
+{ "_id" : "02720", "city" : "FALL RIVER", "loc" : [ -71.13999099999999, 41.718221 ], "pop" : 30600, "state" : "MA" }
+{ "_id" : "02721", "city" : "FALL RIVER", "loc" : [ -71.15742400000001, 41.688305 ], "pop" : 26884, "state" : "MA" }
+{ "_id" : "02723", "city" : "FALL RIVER", "loc" : [ -71.133214, 41.692612 ], "pop" : 16801, "state" : "MA" }
+{ "_id" : "02724", "city" : "FALL RIVER", "loc" : [ -71.17482200000001, 41.684975 ], "pop" : 18141, "state" : "MA" }
+{ "_id" : "02725", "city" : "SOMERSET", "loc" : [ -71.177971, 41.722299 ], "pop" : 2528, "state" : "MA" }
+{ "_id" : "02726", "city" : "SOMERSET", "loc" : [ -71.14920600000001, 41.756012 ], "pop" : 15117, "state" : "MA" }
+{ "_id" : "02738", "city" : "MARION", "loc" : [ -70.761261, 41.709526 ], "pop" : 4496, "state" : "MA" }
+{ "_id" : "02739", "city" : "MATTAPOISETT", "loc" : [ -70.816357, 41.661845 ], "pop" : 5850, "state" : "MA" }
+{ "_id" : "02740", "city" : "NEW BEDFORD", "loc" : [ -70.9372, 41.634749 ], "pop" : 46426, "state" : "MA" }
+{ "_id" : "02743", "city" : "ACUSHNET", "loc" : [ -70.908652, 41.6997 ], "pop" : 9601, "state" : "MA" }
+{ "_id" : "02744", "city" : "NEW BEDFORD", "loc" : [ -70.916746, 41.612716 ], "pop" : 13424, "state" : "MA" }
+{ "_id" : "02745", "city" : "NEW BEDFORD", "loc" : [ -70.935545, 41.691337 ], "pop" : 23661, "state" : "MA" }
+{ "_id" : "02746", "city" : "NEW BEDFORD", "loc" : [ -70.93243, 41.659972 ], "pop" : 16236, "state" : "MA" }
+{ "_id" : "02747", "city" : "NORTH DARTMOUTH", "loc" : [ -70.995769, 41.633789 ], "pop" : 16383, "state" : "MA" }
+{ "_id" : "02748", "city" : "PADANARAM VILLAG", "loc" : [ -70.956521, 41.591728 ], "pop" : 10980, "state" : "MA" }
+{ "_id" : "02760", "city" : "NORTH ATTLEBORO", "loc" : [ -71.329757, 41.977542 ], "pop" : 22289, "state" : "MA" }
+{ "_id" : "02762", "city" : "PLAINVILLE", "loc" : [ -71.327454, 42.012403 ], "pop" : 6874, "state" : "MA" }
+{ "_id" : "02763", "city" : "NORTH ATTLEBORO", "loc" : [ -71.31035300000001, 41.970979 ], "pop" : 2737, "state" : "MA" }
+{ "_id" : "02764", "city" : "NORTH DIGHTON", "loc" : [ -71.148523, 41.852874 ], "pop" : 3779, "state" : "MA" }
+{ "_id" : "02766", "city" : "NORTON", "loc" : [ -71.189441, 41.971801 ], "pop" : 14329, "state" : "MA" }
+{ "_id" : "02767", "city" : "RAYNHAM", "loc" : [ -71.04685600000001, 41.932361 ], "pop" : 9804, "state" : "MA" }
+{ "_id" : "02769", "city" : "REHOBOTH", "loc" : [ -71.254453, 41.85152 ], "pop" : 7762, "state" : "MA" }
+{ "_id" : "02770", "city" : "ROCHESTER", "loc" : [ -70.85225699999999, 41.759082 ], "pop" : 3270, "state" : "MA" }
+{ "_id" : "02771", "city" : "SEEKONK", "loc" : [ -71.322406, 41.837835 ], "pop" : 13375, "state" : "MA" }
+{ "_id" : "02777", "city" : "SWANSEA", "loc" : [ -71.21216699999999, 41.74734 ], "pop" : 15865, "state" : "MA" }
+{ "_id" : "02779", "city" : "BERKLEY", "loc" : [ -71.076534, 41.835325 ], "pop" : 4438, "state" : "MA" }
+{ "_id" : "02780", "city" : "TAUNTON", "loc" : [ -71.10261, 41.905007 ], "pop" : 44894, "state" : "MA" }
+{ "_id" : "02790", "city" : "WESTPORT", "loc" : [ -71.08900300000001, 41.621127 ], "pop" : 14154, "state" : "MA" }
+{ "_id" : "02804", "city" : "ASHAWAY", "loc" : [ -71.783745, 41.423054 ], "pop" : 2472, "state" : "RI" }
+{ "_id" : "02806", "city" : "BARRINGTON", "loc" : [ -71.317497, 41.744334 ], "pop" : 15849, "state" : "RI" }
+{ "_id" : "02807", "city" : "BLOCK ISLAND", "loc" : [ -71.574825, 41.171546 ], "pop" : 836, "state" : "RI" }
+{ "_id" : "02808", "city" : "BRADFORD", "loc" : [ -71.746453, 41.411448 ], "pop" : 2184, "state" : "RI" }
+{ "_id" : "02809", "city" : "BRISTOL", "loc" : [ -71.26755799999999, 41.68247 ], "pop" : 21625, "state" : "RI" }
+{ "_id" : "02812", "city" : "RICHMOND", "loc" : [ -71.650279, 41.46941 ], "pop" : 1011, "state" : "RI" }
+{ "_id" : "02813", "city" : "CHARLESTOWN", "loc" : [ -71.661455, 41.400749 ], "pop" : 6663, "state" : "RI" }
+{ "_id" : "02814", "city" : "CHEPACHET", "loc" : [ -71.679483, 41.91549 ], "pop" : 8191, "state" : "RI" }
+{ "_id" : "02815", "city" : "CLAYVILLE", "loc" : [ -71.67058900000001, 41.777762 ], "pop" : 45, "state" : "RI" }
+{ "_id" : "02816", "city" : "COVENTRY", "loc" : [ -71.57679400000001, 41.69143 ], "pop" : 29842, "state" : "RI" }
+{ "_id" : "02817", "city" : "WEST GREENWICH", "loc" : [ -71.64354899999999, 41.639977 ], "pop" : 3246, "state" : "RI" }
+{ "_id" : "02818", "city" : "EAST GREENWICH", "loc" : [ -71.474009, 41.649777 ], "pop" : 16180, "state" : "RI" }
+{ "_id" : "02822", "city" : "EXETER", "loc" : [ -71.607626, 41.574031 ], "pop" : 3774, "state" : "RI" }
+{ "_id" : "02825", "city" : "FOSTER", "loc" : [ -71.71874800000001, 41.781455 ], "pop" : 5175, "state" : "RI" }
+{ "_id" : "02827", "city" : "GREENE", "loc" : [ -71.735607, 41.706151 ], "pop" : 1241, "state" : "RI" }
+{ "_id" : "02828", "city" : "GREENVILLE", "loc" : [ -71.556923, 41.873409 ], "pop" : 6945, "state" : "RI" }
+{ "_id" : "02830", "city" : "HARRISVILLE", "loc" : [ -71.65340500000001, 41.976379 ], "pop" : 6384, "state" : "RI" }
+{ "_id" : "02831", "city" : "HOPE", "loc" : [ -71.56122499999999, 41.751603 ], "pop" : 3653, "state" : "RI" }
+{ "_id" : "02832", "city" : "RICHMOND", "loc" : [ -71.73486200000001, 41.506974 ], "pop" : 3466, "state" : "RI" }
+{ "_id" : "02835", "city" : "JAMESTOWN", "loc" : [ -71.376108, 41.516405 ], "pop" : 4999, "state" : "RI" }
+{ "_id" : "02836", "city" : "RICHMOND", "loc" : [ -71.683992, 41.477694 ], "pop" : 183, "state" : "RI" }
+{ "_id" : "02837", "city" : "LITTLE COMPTON", "loc" : [ -71.161215, 41.52204 ], "pop" : 3341, "state" : "RI" }
+{ "_id" : "02838", "city" : "MANVILLE", "loc" : [ -71.474113, 41.96888 ], "pop" : 3259, "state" : "RI" }
+{ "_id" : "02840", "city" : "MIDDLETOWN", "loc" : [ -71.30347999999999, 41.504502 ], "pop" : 47687, "state" : "RI" }
+{ "_id" : "02852", "city" : "NORTH KINGSTOWN", "loc" : [ -71.46249400000001, 41.589426 ], "pop" : 22325, "state" : "RI" }
+{ "_id" : "02857", "city" : "NORTH SCITUATE", "loc" : [ -71.62418700000001, 41.8439 ], "pop" : 9563, "state" : "RI" }
+{ "_id" : "02858", "city" : "OAKLAND", "loc" : [ -71.64292500000001, 41.963637 ], "pop" : 462, "state" : "RI" }
+{ "_id" : "02859", "city" : "PASCOAG", "loc" : [ -71.70986600000001, 41.962728 ], "pop" : 7156, "state" : "RI" }
+{ "_id" : "02860", "city" : "PAWTUCKET", "loc" : [ -71.39071300000001, 41.872873 ], "pop" : 45442, "state" : "RI" }
+{ "_id" : "02861", "city" : "PAWTUCKET", "loc" : [ -71.35600100000001, 41.881384 ], "pop" : 27013, "state" : "RI" }
+{ "_id" : "02863", "city" : "CENTRAL FALLS", "loc" : [ -71.394527, 41.888263 ], "pop" : 17380, "state" : "RI" }
+{ "_id" : "02864", "city" : "CUMBERLAND", "loc" : [ -71.415419, 41.948352 ], "pop" : 29327, "state" : "RI" }
+{ "_id" : "02865", "city" : "LINCOLN", "loc" : [ -71.434777, 41.908906 ], "pop" : 14765, "state" : "RI" }
+{ "_id" : "02871", "city" : "PORTSMOUTH", "loc" : [ -71.25201800000001, 41.594397 ], "pop" : 16707, "state" : "RI" }
+{ "_id" : "02872", "city" : "PRUDENCE ISLAND", "loc" : [ -71.31182699999999, 41.613606 ], "pop" : 150, "state" : "RI" }
+{ "_id" : "02874", "city" : "SAUNDERSTOWN", "loc" : [ -71.44269300000001, 41.510528 ], "pop" : 3196, "state" : "RI" }
+{ "_id" : "02876", "city" : "SLATERSVILLE", "loc" : [ -71.5682, 42.001478 ], "pop" : 639, "state" : "RI" }
+{ "_id" : "02877", "city" : "SLOCUM", "loc" : [ -71.53716900000001, 41.521237 ], "pop" : 1114, "state" : "RI" }
+{ "_id" : "02878", "city" : "TIVERTON", "loc" : [ -71.180823, 41.633839 ], "pop" : 14310, "state" : "RI" }
+{ "_id" : "02879", "city" : "NARRAGANSETT", "loc" : [ -71.525138, 41.430195 ], "pop" : 13422, "state" : "RI" }
+{ "_id" : "02881", "city" : "KINGSTON", "loc" : [ -71.529239, 41.480295 ], "pop" : 7683, "state" : "RI" }
+{ "_id" : "02882", "city" : "NARRAGANSETT", "loc" : [ -71.46164, 41.435313 ], "pop" : 13596, "state" : "RI" }
+{ "_id" : "02883", "city" : "PEACE DALE", "loc" : [ -71.500057, 41.45157 ], "pop" : 1652, "state" : "RI" }
+{ "_id" : "02885", "city" : "WARREN", "loc" : [ -71.27016500000001, 41.725618 ], "pop" : 11385, "state" : "RI" }
+{ "_id" : "02886", "city" : "WARWICK", "loc" : [ -71.447591, 41.702601 ], "pop" : 40845, "state" : "RI" }
+{ "_id" : "02888", "city" : "WARWICK", "loc" : [ -71.40836, 41.74936 ], "pop" : 20869, "state" : "RI" }
+{ "_id" : "02889", "city" : "WARWICK", "loc" : [ -71.390146, 41.714069 ], "pop" : 20849, "state" : "RI" }
+{ "_id" : "02891", "city" : "WESTERLY", "loc" : [ -71.81264299999999, 41.369128 ], "pop" : 20290, "state" : "RI" }
+{ "_id" : "02892", "city" : "RICHMOND", "loc" : [ -71.599076, 41.506716 ], "pop" : 3943, "state" : "RI" }
+{ "_id" : "02893", "city" : "WEST WARWICK", "loc" : [ -71.518349, 41.700433 ], "pop" : 27821, "state" : "RI" }
+{ "_id" : "02894", "city" : "WOOD RIVER JUNCT", "loc" : [ -71.709512, 41.453771 ], "pop" : 684, "state" : "RI" }
+{ "_id" : "02895", "city" : "NORTH SMITHFIELD", "loc" : [ -71.513683, 41.99948 ], "pop" : 53733, "state" : "RI" }
+{ "_id" : "02898", "city" : "RICHMOND", "loc" : [ -71.68397299999999, 41.523362 ], "pop" : 1508, "state" : "RI" }
+{ "_id" : "02903", "city" : "PROVIDENCE", "loc" : [ -71.415801, 41.820002 ], "pop" : 9093, "state" : "RI" }
+{ "_id" : "02904", "city" : "CENTREDALE", "loc" : [ -71.438102, 41.860461 ], "pop" : 28119, "state" : "RI" }
+{ "_id" : "02905", "city" : "CRANSTON", "loc" : [ -71.40314600000001, 41.786568 ], "pop" : 24885, "state" : "RI" }
+{ "_id" : "02906", "city" : "PROVIDENCE", "loc" : [ -71.397065, 41.835104 ], "pop" : 31069, "state" : "RI" }
+{ "_id" : "02907", "city" : "CRANSTON", "loc" : [ -71.42403899999999, 41.800842 ], "pop" : 25668, "state" : "RI" }
+{ "_id" : "02908", "city" : "PROVIDENCE", "loc" : [ -71.437684, 41.838294 ], "pop" : 35933, "state" : "RI" }
+{ "_id" : "02909", "city" : "CRANSTON", "loc" : [ -71.448165, 41.816777 ], "pop" : 34261, "state" : "RI" }
+{ "_id" : "02910", "city" : "CRANSTON", "loc" : [ -71.43833100000001, 41.776572 ], "pop" : 21128, "state" : "RI" }
+{ "_id" : "02911", "city" : "CENTREDALE", "loc" : [ -71.474058, 41.853412 ], "pop" : 13858, "state" : "RI" }
+{ "_id" : "02914", "city" : "EAST PROVIDENCE", "loc" : [ -71.368785, 41.813777 ], "pop" : 22965, "state" : "RI" }
+{ "_id" : "02915", "city" : "RIVERSIDE", "loc" : [ -71.35424399999999, 41.772313 ], "pop" : 18934, "state" : "RI" }
+{ "_id" : "02916", "city" : "RUMFORD", "loc" : [ -71.35593799999999, 41.842472 ], "pop" : 8550, "state" : "RI" }
+{ "_id" : "02917", "city" : "SMITHFIELD", "loc" : [ -71.52066600000001, 41.896382 ], "pop" : 12213, "state" : "RI" }
+{ "_id" : "02919", "city" : "CRANSTON", "loc" : [ -71.497646, 41.826431 ], "pop" : 26575, "state" : "RI" }
+{ "_id" : "02920", "city" : "CRANSTON", "loc" : [ -71.465889, 41.77157 ], "pop" : 37385, "state" : "RI" }
+{ "_id" : "02921", "city" : "CRANSTON", "loc" : [ -71.506102, 41.761357 ], "pop" : 6502, "state" : "RI" }
+{ "_id" : "03031", "city" : "AMHERST", "loc" : [ -71.607536, 42.856944 ], "pop" : 8998, "state" : "NH" }
+{ "_id" : "03032", "city" : "AUBURN", "loc" : [ -71.344892, 42.992529 ], "pop" : 4085, "state" : "NH" }
+{ "_id" : "03033", "city" : "BROOKLINE", "loc" : [ -71.666254, 42.738442 ], "pop" : 2410, "state" : "NH" }
+{ "_id" : "03034", "city" : "CANDIA", "loc" : [ -71.304857, 43.058514 ], "pop" : 3557, "state" : "NH" }
+{ "_id" : "03036", "city" : "CHESTER", "loc" : [ -71.244962, 42.967756 ], "pop" : 2691, "state" : "NH" }
+{ "_id" : "03037", "city" : "DEERFIELD", "loc" : [ -71.25126400000001, 43.137756 ], "pop" : 3124, "state" : "NH" }
+{ "_id" : "03038", "city" : "DERRY", "loc" : [ -71.30197099999999, 42.887404 ], "pop" : 29556, "state" : "NH" }
+{ "_id" : "03042", "city" : "EPPING", "loc" : [ -71.076367, 43.041052 ], "pop" : 6797, "state" : "NH" }
+{ "_id" : "03043", "city" : "FRANCESTOWN", "loc" : [ -71.81131000000001, 42.991952 ], "pop" : 1219, "state" : "NH" }
+{ "_id" : "03044", "city" : "FREMONT", "loc" : [ -71.121836, 42.984016 ], "pop" : 2677, "state" : "NH" }
+{ "_id" : "03045", "city" : "DUNBARTON", "loc" : [ -71.56264, 43.018224 ], "pop" : 9428, "state" : "NH" }
+{ "_id" : "03047", "city" : "GREENFIELD", "loc" : [ -71.872755, 42.949277 ], "pop" : 1422, "state" : "NH" }
+{ "_id" : "03048", "city" : "MASON", "loc" : [ -71.784487, 42.7489 ], "pop" : 3443, "state" : "NH" }
+{ "_id" : "03049", "city" : "HOLLIS", "loc" : [ -71.577206, 42.748513 ], "pop" : 5705, "state" : "NH" }
+{ "_id" : "03051", "city" : "HUDSON", "loc" : [ -71.412144, 42.769038 ], "pop" : 26489, "state" : "NH" }
+{ "_id" : "03053", "city" : "LONDONDERRY", "loc" : [ -71.37719, 42.865555 ], "pop" : 19687, "state" : "NH" }
+{ "_id" : "03054", "city" : "MERRIMACK", "loc" : [ -71.51278000000001, 42.866689 ], "pop" : 21632, "state" : "NH" }
+{ "_id" : "03055", "city" : "MILFORD", "loc" : [ -71.660569, 42.828497 ], "pop" : 11795, "state" : "NH" }
+{ "_id" : "03057", "city" : "MONT VERNON", "loc" : [ -71.676243, 42.897597 ], "pop" : 1812, "state" : "NH" }
+{ "_id" : "03060", "city" : "NASHUA", "loc" : [ -71.466684, 42.756395 ], "pop" : 41438, "state" : "NH" }
+{ "_id" : "03062", "city" : "NASHUA", "loc" : [ -71.489282, 42.723472 ], "pop" : 23927, "state" : "NH" }
+{ "_id" : "03063", "city" : "NASHUA", "loc" : [ -71.513156, 42.771686 ], "pop" : 14891, "state" : "NH" }
+{ "_id" : "03070", "city" : "NEW BOSTON", "loc" : [ -71.686402, 42.97217 ], "pop" : 2701, "state" : "NH" }
+{ "_id" : "03071", "city" : "NEW IPSWICH", "loc" : [ -71.870318, 42.751142 ], "pop" : 4014, "state" : "NH" }
+{ "_id" : "03076", "city" : "PELHAM", "loc" : [ -71.304551, 42.72881 ], "pop" : 6012, "state" : "NH" }
+{ "_id" : "03077", "city" : "RAYMOND", "loc" : [ -71.191159, 43.032512 ], "pop" : 9005, "state" : "NH" }
+{ "_id" : "03079", "city" : "SALEM", "loc" : [ -71.21760999999999, 42.78465 ], "pop" : 25746, "state" : "NH" }
+{ "_id" : "03082", "city" : "LYNDEBOROUGH", "loc" : [ -71.774373, 42.895449 ], "pop" : 1294, "state" : "NH" }
+{ "_id" : "03084", "city" : "TEMPLE", "loc" : [ -71.85234699999999, 42.820035 ], "pop" : 1194, "state" : "NH" }
+{ "_id" : "03086", "city" : "WILTON", "loc" : [ -71.75406599999999, 42.836761 ], "pop" : 3122, "state" : "NH" }
+{ "_id" : "03087", "city" : "WINDHAM", "loc" : [ -71.306735, 42.805106 ], "pop" : 9000, "state" : "NH" }
+{ "_id" : "03101", "city" : "MANCHESTER", "loc" : [ -71.463255, 42.992858 ], "pop" : 2697, "state" : "NH" }
+{ "_id" : "03102", "city" : "MANCHESTER", "loc" : [ -71.488433, 42.99442 ], "pop" : 29308, "state" : "NH" }
+{ "_id" : "03103", "city" : "MANCHESTER", "loc" : [ -71.449325, 42.965563 ], "pop" : 36613, "state" : "NH" }
+{ "_id" : "03104", "city" : "MANCHESTER", "loc" : [ -71.448233, 43.007307 ], "pop" : 29950, "state" : "NH" }
+{ "_id" : "03106", "city" : "HOOKSETT", "loc" : [ -71.444446, 43.061708 ], "pop" : 8668, "state" : "NH" }
+{ "_id" : "03109", "city" : "MANCHESTER", "loc" : [ -71.41347399999999, 42.971349 ], "pop" : 7884, "state" : "NH" }
+{ "_id" : "03110", "city" : "BEDFORD", "loc" : [ -71.52127, 42.940307 ], "pop" : 12468, "state" : "NH" }
+{ "_id" : "03216", "city" : "ANDOVER", "loc" : [ -71.78295199999999, 43.428668 ], "pop" : 1638, "state" : "NH" }
+{ "_id" : "03217", "city" : "ASHLAND", "loc" : [ -71.61208499999999, 43.703428 ], "pop" : 2056, "state" : "NH" }
+{ "_id" : "03218", "city" : "BARNSTEAD", "loc" : [ -71.286946, 43.36513 ], "pop" : 793, "state" : "NH" }
+{ "_id" : "03220", "city" : "BELMONT", "loc" : [ -71.488991, 43.451189 ], "pop" : 2997, "state" : "NH" }
+{ "_id" : "03221", "city" : "BRADFORD", "loc" : [ -71.98504800000001, 43.294343 ], "pop" : 3273, "state" : "NH" }
+{ "_id" : "03222", "city" : "BRISTOL", "loc" : [ -71.750664, 43.611994 ], "pop" : 4288, "state" : "NH" }
+{ "_id" : "03223", "city" : "BEEBE RIVER", "loc" : [ -71.63614200000001, 43.888507 ], "pop" : 2802, "state" : "NH" }
+{ "_id" : "03224", "city" : "CANTERBURY", "loc" : [ -71.557008, 43.357041 ], "pop" : 2085, "state" : "NH" }
+{ "_id" : "03225", "city" : "CENTER BARNSTEAD", "loc" : [ -71.24244, 43.356563 ], "pop" : 2307, "state" : "NH" }
+{ "_id" : "03226", "city" : "CENTER HARBOR", "loc" : [ -71.47973, 43.710688 ], "pop" : 470, "state" : "NH" }
+{ "_id" : "03227", "city" : "CENTER SANDWICH", "loc" : [ -71.450614, 43.816169 ], "pop" : 615, "state" : "NH" }
+{ "_id" : "03229", "city" : "HOPKINTON", "loc" : [ -71.696299, 43.218898 ], "pop" : 6071, "state" : "NH" }
+{ "_id" : "03230", "city" : "DANBURY", "loc" : [ -71.869074, 43.5115 ], "pop" : 1098, "state" : "NH" }
+{ "_id" : "03231", "city" : "EAST ANDOVER", "loc" : [ -71.75960600000001, 43.47766 ], "pop" : 177, "state" : "NH" }
+{ "_id" : "03232", "city" : "EAST HEBRON", "loc" : [ -71.76790699999999, 43.696969 ], "pop" : 47, "state" : "NH" }
+{ "_id" : "03234", "city" : "EPSOM", "loc" : [ -71.35457599999999, 43.217398 ], "pop" : 2931, "state" : "NH" }
+{ "_id" : "03235", "city" : "FRANKLIN", "loc" : [ -71.64912200000001, 43.442569 ], "pop" : 9780, "state" : "NH" }
+{ "_id" : "03237", "city" : "GILMANTON", "loc" : [ -71.412063, 43.417476 ], "pop" : 1308, "state" : "NH" }
+{ "_id" : "03240", "city" : "GRAFTON", "loc" : [ -71.96338900000001, 43.572743 ], "pop" : 890, "state" : "NH" }
+{ "_id" : "03241", "city" : "HEBRON", "loc" : [ -71.82696, 43.718571 ], "pop" : 657, "state" : "NH" }
+{ "_id" : "03242", "city" : "HENNIKER", "loc" : [ -71.815921, 43.179091 ], "pop" : 4151, "state" : "NH" }
+{ "_id" : "03243", "city" : "HILL", "loc" : [ -71.729168, 43.527422 ], "pop" : 778, "state" : "NH" }
+{ "_id" : "03244", "city" : "HILLSBORO", "loc" : [ -71.902818, 43.120709 ], "pop" : 5246, "state" : "NH" }
+{ "_id" : "03246", "city" : "GILFORD", "loc" : [ -71.452907, 43.538713 ], "pop" : 24409, "state" : "NH" }
+{ "_id" : "03251", "city" : "LINCOLN", "loc" : [ -71.672707, 44.058159 ], "pop" : 1229, "state" : "NH" }
+{ "_id" : "03253", "city" : "MEREDITH", "loc" : [ -71.51132699999999, 43.650208 ], "pop" : 5959, "state" : "NH" }
+{ "_id" : "03254", "city" : "MOULTONBOROUGH", "loc" : [ -71.392245, 43.728133 ], "pop" : 3208, "state" : "NH" }
+{ "_id" : "03256", "city" : "NEW HAMPTON", "loc" : [ -71.643513, 43.618393 ], "pop" : 1214, "state" : "NH" }
+{ "_id" : "03257", "city" : "NEW LONDON", "loc" : [ -71.985674, 43.414501 ], "pop" : 3280, "state" : "NH" }
+{ "_id" : "03259", "city" : "NORTH SANDWICH", "loc" : [ -71.385025, 43.845182 ], "pop" : 338, "state" : "NH" }
+{ "_id" : "03261", "city" : "NORTHWOOD", "loc" : [ -71.200423, 43.206965 ], "pop" : 3013, "state" : "NH" }
+{ "_id" : "03262", "city" : "NORTH WOODSTOCK", "loc" : [ -71.697684, 44.019831 ], "pop" : 1091, "state" : "NH" }
+{ "_id" : "03263", "city" : "PITTSFIELD", "loc" : [ -71.33302999999999, 43.287384 ], "pop" : 5806, "state" : "NH" }
+{ "_id" : "03264", "city" : "PLYMOUTH", "loc" : [ -71.684714, 43.763524 ], "pop" : 8980, "state" : "NH" }
+{ "_id" : "03266", "city" : "RUMNEY", "loc" : [ -71.84801899999999, 43.804389 ], "pop" : 1912, "state" : "NH" }
+{ "_id" : "03268", "city" : "SALISBURY", "loc" : [ -71.70446800000001, 43.406652 ], "pop" : 140, "state" : "NH" }
+{ "_id" : "03269", "city" : "SANBORNTON", "loc" : [ -71.600348, 43.549552 ], "pop" : 699, "state" : "NH" }
+{ "_id" : "03275", "city" : "ALLENSTOWN", "loc" : [ -71.439663, 43.147554 ], "pop" : 11565, "state" : "NH" }
+{ "_id" : "03276", "city" : "TILTON", "loc" : [ -71.57741300000001, 43.46033 ], "pop" : 7356, "state" : "NH" }
+{ "_id" : "03278", "city" : "WARNER", "loc" : [ -71.83534899999999, 43.303512 ], "pop" : 3265, "state" : "NH" }
+{ "_id" : "03279", "city" : "WARREN", "loc" : [ -71.89013, 43.944667 ], "pop" : 886, "state" : "NH" }
+{ "_id" : "03280", "city" : "WASHINGTON", "loc" : [ -72.082407, 43.174705 ], "pop" : 628, "state" : "NH" }
+{ "_id" : "03281", "city" : "WEARE", "loc" : [ -71.70376, 43.071422 ], "pop" : 7481, "state" : "NH" }
+{ "_id" : "03282", "city" : "WENTWORTH", "loc" : [ -71.909651, 43.868456 ], "pop" : 556, "state" : "NH" }
+{ "_id" : "03284", "city" : "WEST SPRINGFIELD", "loc" : [ -72.057855, 43.491615 ], "pop" : 788, "state" : "NH" }
+{ "_id" : "03287", "city" : "WILMOT FLAT", "loc" : [ -71.900983, 43.432177 ], "pop" : 931, "state" : "NH" }
+{ "_id" : "03290", "city" : "NOTTINGHAM", "loc" : [ -71.110983, 43.119632 ], "pop" : 598, "state" : "NH" }
+{ "_id" : "03291", "city" : "WEST NOTTINGHAM", "loc" : [ -71.111006, 43.133971 ], "pop" : 27, "state" : "NH" }
+{ "_id" : "03301", "city" : "CONCORD", "loc" : [ -71.527734, 43.218525 ], "pop" : 34035, "state" : "NH" }
+{ "_id" : "03303", "city" : "BOSCAWEN", "loc" : [ -71.612723, 43.285285 ], "pop" : 12046, "state" : "NH" }
+{ "_id" : "03304", "city" : "BOW", "loc" : [ -71.544814, 43.138788 ], "pop" : 5500, "state" : "NH" }
+{ "_id" : "03431", "city" : "SURRY", "loc" : [ -72.28954, 42.943127 ], "pop" : 23882, "state" : "NH" }
+{ "_id" : "03440", "city" : "ANTRIM", "loc" : [ -71.938698, 43.059547 ], "pop" : 3379, "state" : "NH" }
+{ "_id" : "03441", "city" : "ASHUELOT", "loc" : [ -72.434899, 42.785057 ], "pop" : 285, "state" : "NH" }
+{ "_id" : "03442", "city" : "BENNINGTON", "loc" : [ -71.91534, 43.010309 ], "pop" : 1236, "state" : "NH" }
+{ "_id" : "03443", "city" : "CHESTERFIELD", "loc" : [ -72.487219, 42.900785 ], "pop" : 1455, "state" : "NH" }
+{ "_id" : "03444", "city" : "DUBLIN", "loc" : [ -72.050538, 42.897198 ], "pop" : 1474, "state" : "NH" }
+{ "_id" : "03445", "city" : "EAST SULLIVAN", "loc" : [ -72.191778, 42.994005 ], "pop" : 169, "state" : "NH" }
+{ "_id" : "03446", "city" : "EAST SWANZEY", "loc" : [ -72.249298, 42.884137 ], "pop" : 796, "state" : "NH" }
+{ "_id" : "03447", "city" : "FITZWILLIAM", "loc" : [ -72.145014, 42.7611 ], "pop" : 2016, "state" : "NH" }
+{ "_id" : "03448", "city" : "GILSUM", "loc" : [ -72.263272, 43.043105 ], "pop" : 745, "state" : "NH" }
+{ "_id" : "03449", "city" : "HANCOCK", "loc" : [ -71.981858, 42.976817 ], "pop" : 1526, "state" : "NH" }
+{ "_id" : "03450", "city" : "HARRISVILLE", "loc" : [ -72.09724300000001, 42.939874 ], "pop" : 981, "state" : "NH" }
+{ "_id" : "03451", "city" : "HINSDALE", "loc" : [ -72.501474, 42.802714 ], "pop" : 3936, "state" : "NH" }
+{ "_id" : "03452", "city" : "JAFFREY", "loc" : [ -72.027514, 42.81779 ], "pop" : 5334, "state" : "NH" }
+{ "_id" : "03455", "city" : "MARLBOROUGH", "loc" : [ -72.201292, 42.898804 ], "pop" : 1927, "state" : "NH" }
+{ "_id" : "03456", "city" : "MARLOW", "loc" : [ -72.21087900000001, 43.132585 ], "pop" : 650, "state" : "NH" }
+{ "_id" : "03457", "city" : "MUNSONVILLE", "loc" : [ -72.133702, 42.998646 ], "pop" : 535, "state" : "NH" }
+{ "_id" : "03458", "city" : "PETERBOROUGH", "loc" : [ -71.94696399999999, 42.88559 ], "pop" : 5713, "state" : "NH" }
+{ "_id" : "03461", "city" : "RINDGE", "loc" : [ -72.01903799999999, 42.754391 ], "pop" : 4968, "state" : "NH" }
+{ "_id" : "03462", "city" : "SPOFFORD", "loc" : [ -72.41027699999999, 42.911973 ], "pop" : 1266, "state" : "NH" }
+{ "_id" : "03464", "city" : "STODDARD", "loc" : [ -72.108811, 43.073944 ], "pop" : 622, "state" : "NH" }
+{ "_id" : "03465", "city" : "TROY", "loc" : [ -72.184753, 42.82697 ], "pop" : 2097, "state" : "NH" }
+{ "_id" : "03466", "city" : "WEST CHESTERFIEL", "loc" : [ -72.511216, 42.873152 ], "pop" : 391, "state" : "NH" }
+{ "_id" : "03467", "city" : "WESTMORELAND", "loc" : [ -72.435784, 42.968999 ], "pop" : 1596, "state" : "NH" }
+{ "_id" : "03469", "city" : "WEST SWANZEY", "loc" : [ -72.29768799999999, 42.870313 ], "pop" : 5440, "state" : "NH" }
+{ "_id" : "03470", "city" : "RICHMOND", "loc" : [ -72.36367199999999, 42.773922 ], "pop" : 4625, "state" : "NH" }
+{ "_id" : "03561", "city" : "LITTLETON", "loc" : [ -71.776816, 44.311187 ], "pop" : 6663, "state" : "NH" }
+{ "_id" : "03570", "city" : "BERLIN", "loc" : [ -71.18923599999999, 44.48107 ], "pop" : 12892, "state" : "NH" }
+{ "_id" : "03574", "city" : "BETHLEHEM", "loc" : [ -71.682929, 44.280846 ], "pop" : 1885, "state" : "NH" }
+{ "_id" : "03576", "city" : "COLEBROOK", "loc" : [ -71.47934100000001, 44.907776 ], "pop" : 4232, "state" : "NH" }
+{ "_id" : "03579", "city" : "ERROL", "loc" : [ -71.143612, 44.800273 ], "pop" : 366, "state" : "NH" }
+{ "_id" : "03580", "city" : "FRANCONIA", "loc" : [ -71.751822, 44.205273 ], "pop" : 1090, "state" : "NH" }
+{ "_id" : "03581", "city" : "GORHAM", "loc" : [ -71.17998299999999, 44.399601 ], "pop" : 3610, "state" : "NH" }
+{ "_id" : "03582", "city" : "GROVETON", "loc" : [ -71.506421, 44.598367 ], "pop" : 2527, "state" : "NH" }
+{ "_id" : "03583", "city" : "JEFFERSON", "loc" : [ -71.45183400000001, 44.399907 ], "pop" : 986, "state" : "NH" }
+{ "_id" : "03584", "city" : "LANCASTER", "loc" : [ -71.55911500000001, 44.492074 ], "pop" : 3825, "state" : "NH" }
+{ "_id" : "03585", "city" : "LISBON", "loc" : [ -71.896565, 44.214837 ], "pop" : 2295, "state" : "NH" }
+{ "_id" : "03588", "city" : "MILAN", "loc" : [ -71.181031, 44.586968 ], "pop" : 987, "state" : "NH" }
+{ "_id" : "03590", "city" : "NORTH STRATFORD", "loc" : [ -71.564368, 44.714915 ], "pop" : 927, "state" : "NH" }
+{ "_id" : "03592", "city" : "PITTSBURG", "loc" : [ -71.36359299999999, 45.086564 ], "pop" : 1104, "state" : "NH" }
+{ "_id" : "03598", "city" : "WHITEFIELD", "loc" : [ -71.603453, 44.36811 ], "pop" : 3139, "state" : "NH" }
+{ "_id" : "03602", "city" : "ALSTEAD", "loc" : [ -72.328052, 43.126484 ], "pop" : 1721, "state" : "NH" }
+{ "_id" : "03603", "city" : "CHARLESTOWN", "loc" : [ -72.40638, 43.257339 ], "pop" : 4678, "state" : "NH" }
+{ "_id" : "03605", "city" : "EAST LEMPSTER", "loc" : [ -72.16620500000001, 43.21863 ], "pop" : 323, "state" : "NH" }
+{ "_id" : "03607", "city" : "SOUTH ACWORTH", "loc" : [ -72.341053, 43.176942 ], "pop" : 1008, "state" : "NH" }
+{ "_id" : "03608", "city" : "WALPOLE", "loc" : [ -72.41548899999999, 43.076533 ], "pop" : 2466, "state" : "NH" }
+{ "_id" : "03609", "city" : "NORTH WALPOLE", "loc" : [ -72.44825299999999, 43.142759 ], "pop" : 744, "state" : "NH" }
+{ "_id" : "03740", "city" : "BATH", "loc" : [ -71.95674099999999, 44.173419 ], "pop" : 155, "state" : "NH" }
+{ "_id" : "03741", "city" : "CANAAN", "loc" : [ -72.029724, 43.660092 ], "pop" : 3065, "state" : "NH" }
+{ "_id" : "03743", "city" : "CLAREMONT", "loc" : [ -72.342186, 43.367942 ], "pop" : 14820, "state" : "NH" }
+{ "_id" : "03745", "city" : "CORNISH", "loc" : [ -72.339426, 43.496339 ], "pop" : 2275, "state" : "NH" }
+{ "_id" : "03748", "city" : "ENFIELD", "loc" : [ -72.127014, 43.625584 ], "pop" : 4118, "state" : "NH" }
+{ "_id" : "03750", "city" : "ETNA", "loc" : [ -72.212479, 43.711333 ], "pop" : 944, "state" : "NH" }
+{ "_id" : "03752", "city" : "GOSHEN", "loc" : [ -72.124117, 43.302623 ], "pop" : 742, "state" : "NH" }
+{ "_id" : "03753", "city" : "GRANTHAM", "loc" : [ -72.133437, 43.510324 ], "pop" : 1247, "state" : "NH" }
+{ "_id" : "03755", "city" : "HANOVER", "loc" : [ -72.28496, 43.704532 ], "pop" : 7070, "state" : "NH" }
+{ "_id" : "03765", "city" : "HAVERHILL", "loc" : [ -72.057276, 44.039438 ], "pop" : 498, "state" : "NH" }
+{ "_id" : "03766", "city" : "LEBANON", "loc" : [ -72.242818, 43.644688 ], "pop" : 9032, "state" : "NH" }
+{ "_id" : "03768", "city" : "LYME", "loc" : [ -72.161993, 43.791327 ], "pop" : 2172, "state" : "NH" }
+{ "_id" : "03770", "city" : "MERIDEN", "loc" : [ -72.275644, 43.529873 ], "pop" : 126, "state" : "NH" }
+{ "_id" : "03771", "city" : "MONROE", "loc" : [ -72.02502800000001, 44.273358 ], "pop" : 760, "state" : "NH" }
+{ "_id" : "03773", "city" : "NEWPORT", "loc" : [ -72.183789, 43.353228 ], "pop" : 8073, "state" : "NH" }
+{ "_id" : "03774", "city" : "NORTH HAVERHILL", "loc" : [ -72.01911200000001, 44.097841 ], "pop" : 1744, "state" : "NH" }
+{ "_id" : "03777", "city" : "ORFORD", "loc" : [ -72.097846, 43.894101 ], "pop" : 1008, "state" : "NH" }
+{ "_id" : "03779", "city" : "PIERMONT", "loc" : [ -72.081299, 43.990572 ], "pop" : 431, "state" : "NH" }
+{ "_id" : "03780", "city" : "PIKE", "loc" : [ -72.009587, 44.025511 ], "pop" : 751, "state" : "NH" }
+{ "_id" : "03781", "city" : "PLAINFIELD", "loc" : [ -72.270398, 43.551919 ], "pop" : 1314, "state" : "NH" }
+{ "_id" : "03782", "city" : "SUNAPEE", "loc" : [ -72.095044, 43.386816 ], "pop" : 2570, "state" : "NH" }
+{ "_id" : "03784", "city" : "WEST LEBANON", "loc" : [ -72.300735, 43.64401 ], "pop" : 3784, "state" : "NH" }
+{ "_id" : "03785", "city" : "WOODSVILLE", "loc" : [ -71.989215, 44.138549 ], "pop" : 2292, "state" : "NH" }
+{ "_id" : "03801", "city" : "NEWINGTON", "loc" : [ -70.780412, 43.066524 ], "pop" : 27430, "state" : "NH" }
+{ "_id" : "03809", "city" : "ALTON", "loc" : [ -71.229709, 43.46302 ], "pop" : 2939, "state" : "NH" }
+{ "_id" : "03810", "city" : "ALTON BAY", "loc" : [ -71.24888, 43.484468 ], "pop" : 157, "state" : "NH" }
+{ "_id" : "03811", "city" : "ATKINSON", "loc" : [ -71.16030000000001, 42.836981 ], "pop" : 5145, "state" : "NH" }
+{ "_id" : "03812", "city" : "BARTLETT", "loc" : [ -71.2491, 44.08656 ], "pop" : 1379, "state" : "NH" }
+{ "_id" : "03813", "city" : "CENTER CONWAY", "loc" : [ -71.060677, 43.98776 ], "pop" : 2394, "state" : "NH" }
+{ "_id" : "03814", "city" : "CENTER OSSIPEE", "loc" : [ -71.134882, 43.768189 ], "pop" : 2492, "state" : "NH" }
+{ "_id" : "03815", "city" : "CENTER STRAFFORD", "loc" : [ -71.107122, 43.262888 ], "pop" : 436, "state" : "NH" }
+{ "_id" : "03816", "city" : "CENTER TUFTONBOR", "loc" : [ -71.26505899999999, 43.690205 ], "pop" : 885, "state" : "NH" }
+{ "_id" : "03817", "city" : "CHOCORUA", "loc" : [ -71.24071600000001, 43.890851 ], "pop" : 70, "state" : "NH" }
+{ "_id" : "03818", "city" : "CONWAY", "loc" : [ -71.15028, 43.974161 ], "pop" : 1875, "state" : "NH" }
+{ "_id" : "03819", "city" : "DANVILLE", "loc" : [ -71.120985, 42.923432 ], "pop" : 2471, "state" : "NH" }
+{ "_id" : "03820", "city" : "MADBURY", "loc" : [ -70.88488099999999, 43.190006 ], "pop" : 27182, "state" : "NH" }
+{ "_id" : "03824", "city" : "LEE", "loc" : [ -70.952333, 43.133821 ], "pop" : 15487, "state" : "NH" }
+{ "_id" : "03825", "city" : "BARRINGTON", "loc" : [ -71.03767499999999, 43.2027 ], "pop" : 5842, "state" : "NH" }
+{ "_id" : "03826", "city" : "EAST HAMPSTEAD", "loc" : [ -71.127978, 42.887656 ], "pop" : 1880, "state" : "NH" }
+{ "_id" : "03827", "city" : "SOUTH HAMPTON", "loc" : [ -70.976904, 42.911289 ], "pop" : 3197, "state" : "NH" }
+{ "_id" : "03830", "city" : "EAST WAKEFIELD", "loc" : [ -71.007712, 43.641022 ], "pop" : 675, "state" : "NH" }
+{ "_id" : "03833", "city" : "BRENTWOOD", "loc" : [ -70.96430599999999, 42.977169 ], "pop" : 14374, "state" : "NH" }
+{ "_id" : "03835", "city" : "FARMINGTON", "loc" : [ -71.06469300000001, 43.388373 ], "pop" : 4676, "state" : "NH" }
+{ "_id" : "03836", "city" : "FREEDOM", "loc" : [ -71.062815, 43.817242 ], "pop" : 935, "state" : "NH" }
+{ "_id" : "03837", "city" : "GILMANTON IRON W", "loc" : [ -71.330315, 43.425281 ], "pop" : 1301, "state" : "NH" }
+{ "_id" : "03838", "city" : "GLEN", "loc" : [ -71.192457, 44.101777 ], "pop" : 84, "state" : "NH" }
+{ "_id" : "03839", "city" : "GONIC", "loc" : [ -70.976642, 43.268374 ], "pop" : 4474, "state" : "NH" }
+{ "_id" : "03840", "city" : "GREENLAND", "loc" : [ -70.847476, 43.035294 ], "pop" : 2450, "state" : "NH" }
+{ "_id" : "03841", "city" : "HAMPSTEAD", "loc" : [ -71.175802, 42.881957 ], "pop" : 5291, "state" : "NH" }
+{ "_id" : "03842", "city" : "HAMPTON", "loc" : [ -70.824336, 42.935883 ], "pop" : 12278, "state" : "NH" }
+{ "_id" : "03844", "city" : "HAMPTON FALLS", "loc" : [ -70.887608, 42.926323 ], "pop" : 1503, "state" : "NH" }
+{ "_id" : "03845", "city" : "INTERVALE", "loc" : [ -71.119415, 44.095479 ], "pop" : 1811, "state" : "NH" }
+{ "_id" : "03846", "city" : "JACKSON", "loc" : [ -71.187808, 44.166989 ], "pop" : 689, "state" : "NH" }
+{ "_id" : "03848", "city" : "KINGSTON", "loc" : [ -71.063914, 42.913258 ], "pop" : 6111, "state" : "NH" }
+{ "_id" : "03849", "city" : "MADISON", "loc" : [ -71.125412, 43.915206 ], "pop" : 1669, "state" : "NH" }
+{ "_id" : "03852", "city" : "MILTON MILLS", "loc" : [ -70.969729, 43.502494 ], "pop" : 514, "state" : "NH" }
+{ "_id" : "03853", "city" : "MIRROR LAKE", "loc" : [ -71.272858, 43.636552 ], "pop" : 696, "state" : "NH" }
+{ "_id" : "03854", "city" : "NEW CASTLE", "loc" : [ -70.719922, 43.068114 ], "pop" : 840, "state" : "NH" }
+{ "_id" : "03855", "city" : "NEW DURHAM", "loc" : [ -71.140828, 43.443045 ], "pop" : 2148, "state" : "NH" }
+{ "_id" : "03857", "city" : "NEWMARKET", "loc" : [ -70.95531699999999, 43.072628 ], "pop" : 9049, "state" : "NH" }
+{ "_id" : "03858", "city" : "NEWTON", "loc" : [ -71.04202100000001, 42.867805 ], "pop" : 2944, "state" : "NH" }
+{ "_id" : "03860", "city" : "NORTH CONWAY", "loc" : [ -71.123811, 44.033613 ], "pop" : 3458, "state" : "NH" }
+{ "_id" : "03862", "city" : "NORTH HAMPTON", "loc" : [ -70.82673800000001, 42.977625 ], "pop" : 3637, "state" : "NH" }
+{ "_id" : "03864", "city" : "OSSIPEE", "loc" : [ -71.11287299999999, 43.694506 ], "pop" : 1490, "state" : "NH" }
+{ "_id" : "03865", "city" : "PLAISTOW", "loc" : [ -71.093397, 42.835551 ], "pop" : 7124, "state" : "NH" }
+{ "_id" : "03867", "city" : "ROCHESTER", "loc" : [ -71.055753, 43.309203 ], "pop" : 3793, "state" : "NH" }
+{ "_id" : "03868", "city" : "EAST ROCHESTER", "loc" : [ -70.968581, 43.31256 ], "pop" : 20616, "state" : "NH" }
+{ "_id" : "03869", "city" : "ROLLINSFORD", "loc" : [ -70.833207, 43.226936 ], "pop" : 2395, "state" : "NH" }
+{ "_id" : "03870", "city" : "RYE", "loc" : [ -70.765153, 43.009468 ], "pop" : 4415, "state" : "NH" }
+{ "_id" : "03872", "city" : "SANBORNVILLE", "loc" : [ -71.020005, 43.551278 ], "pop" : 2382, "state" : "NH" }
+{ "_id" : "03873", "city" : "SANDOWN", "loc" : [ -71.18606, 42.930819 ], "pop" : 4060, "state" : "NH" }
+{ "_id" : "03874", "city" : "SEABROOK", "loc" : [ -70.86463999999999, 42.88536 ], "pop" : 6503, "state" : "NH" }
+{ "_id" : "03875", "city" : "SILVER LAKE", "loc" : [ -71.190501, 43.878974 ], "pop" : 640, "state" : "NH" }
+{ "_id" : "03878", "city" : "SOMERSWORTH", "loc" : [ -70.87558900000001, 43.252546 ], "pop" : 11170, "state" : "NH" }
+{ "_id" : "03882", "city" : "SOUTH EFFINGHAM", "loc" : [ -71.002109, 43.721216 ], "pop" : 201, "state" : "NH" }
+{ "_id" : "03883", "city" : "SOUTH TAMWORTH", "loc" : [ -71.311654, 43.833613 ], "pop" : 188, "state" : "NH" }
+{ "_id" : "03884", "city" : "STRAFFORD", "loc" : [ -71.162475, 43.250575 ], "pop" : 1618, "state" : "NH" }
+{ "_id" : "03885", "city" : "STRATHAM", "loc" : [ -70.899714, 43.019432 ], "pop" : 4967, "state" : "NH" }
+{ "_id" : "03886", "city" : "TAMWORTH", "loc" : [ -71.264454, 43.862049 ], "pop" : 1285, "state" : "NH" }
+{ "_id" : "03887", "city" : "UNION", "loc" : [ -71.02085700000001, 43.4382 ], "pop" : 4229, "state" : "NH" }
+{ "_id" : "03890", "city" : "WEST OSSIPEE", "loc" : [ -71.205141, 43.835956 ], "pop" : 362, "state" : "NH" }
+{ "_id" : "03894", "city" : "WOLFEBORO", "loc" : [ -71.190843, 43.594996 ], "pop" : 5586, "state" : "NH" }
+{ "_id" : "03901", "city" : "BERWICK", "loc" : [ -70.85503799999999, 43.28992 ], "pop" : 5942, "state" : "ME" }
+{ "_id" : "03902", "city" : "CAPE NEDDICK", "loc" : [ -70.639685, 43.213318 ], "pop" : 953, "state" : "ME" }
+{ "_id" : "03903", "city" : "ELIOT", "loc" : [ -70.78221600000001, 43.130943 ], "pop" : 6506, "state" : "ME" }
+{ "_id" : "03904", "city" : "KITTERY", "loc" : [ -70.742876, 43.092128 ], "pop" : 3537, "state" : "ME" }
+{ "_id" : "03905", "city" : "KITTERY POINT", "loc" : [ -70.712108, 43.097571 ], "pop" : 4589, "state" : "ME" }
+{ "_id" : "03906", "city" : "NORTH BERWICK", "loc" : [ -70.72117299999999, 43.325401 ], "pop" : 6465, "state" : "ME" }
+{ "_id" : "03907", "city" : "OGUNQUIT", "loc" : [ -70.597176, 43.228457 ], "pop" : 852, "state" : "ME" }
+{ "_id" : "03908", "city" : "SOUTH BERWICK", "loc" : [ -70.785949, 43.229201 ], "pop" : 5982, "state" : "ME" }
+{ "_id" : "03909", "city" : "YORK", "loc" : [ -70.657826, 43.154447 ], "pop" : 8477, "state" : "ME" }
+{ "_id" : "04001", "city" : "ACTON", "loc" : [ -70.93068700000001, 43.549405 ], "pop" : 767, "state" : "ME" }
+{ "_id" : "04002", "city" : "ALFRED", "loc" : [ -70.69608700000001, 43.487503 ], "pop" : 4730, "state" : "ME" }
+{ "_id" : "04003", "city" : "BAILEY ISLAND", "loc" : [ -69.995175, 43.734147 ], "pop" : 464, "state" : "ME" }
+{ "_id" : "04005", "city" : "ARUNDEL", "loc" : [ -70.47192800000001, 43.483647 ], "pop" : 23646, "state" : "ME" }
+{ "_id" : "04006", "city" : "BIDDEFORD POOL", "loc" : [ -70.352024, 43.442722 ], "pop" : 269, "state" : "ME" }
+{ "_id" : "04008", "city" : "BOWDOINHAM", "loc" : [ -69.91884899999999, 44.036806 ], "pop" : 4328, "state" : "ME" }
+{ "_id" : "04009", "city" : "BRIDGTON", "loc" : [ -70.724081, 44.052049 ], "pop" : 3980, "state" : "ME" }
+{ "_id" : "04010", "city" : "BROWNFIELD", "loc" : [ -70.90322500000001, 43.971316 ], "pop" : 1148, "state" : "ME" }
+{ "_id" : "04011", "city" : "BIRCH ISLAND", "loc" : [ -69.95546899999999, 43.897591 ], "pop" : 22557, "state" : "ME" }
+{ "_id" : "04013", "city" : "BUSTINS ISLAND", "loc" : [ -70.042247, 43.79602 ], "pop" : 0, "state" : "ME" }
+{ "_id" : "04015", "city" : "CASCO", "loc" : [ -70.52601300000001, 43.959623 ], "pop" : 3010, "state" : "ME" }
+{ "_id" : "04016", "city" : "CENTER LOVELL", "loc" : [ -70.883618, 44.168139 ], "pop" : 148, "state" : "ME" }
+{ "_id" : "04017", "city" : "CHEBEAGUE ISLAND", "loc" : [ -70.116878, 43.735363 ], "pop" : 337, "state" : "ME" }
+{ "_id" : "04019", "city" : "CLIFF ISLAND", "loc" : [ -70.107097, 43.695547 ], "pop" : 87, "state" : "ME" }
+{ "_id" : "04020", "city" : "CORNISH", "loc" : [ -70.77843300000001, 43.779612 ], "pop" : 1736, "state" : "ME" }
+{ "_id" : "04021", "city" : "CUMBERLAND CENTE", "loc" : [ -70.2484, 43.809818 ], "pop" : 8544, "state" : "ME" }
+{ "_id" : "04022", "city" : "DENMARK", "loc" : [ -70.79240900000001, 43.975499 ], "pop" : 679, "state" : "ME" }
+{ "_id" : "04024", "city" : "EAST BALDWIN", "loc" : [ -70.692159, 43.864604 ], "pop" : 976, "state" : "ME" }
+{ "_id" : "04027", "city" : "WEST LEBANON", "loc" : [ -70.91098599999999, 43.410304 ], "pop" : 5224, "state" : "ME" }
+{ "_id" : "04029", "city" : "NORTH SEBAGO", "loc" : [ -70.633865, 43.882247 ], "pop" : 597, "state" : "ME" }
+{ "_id" : "04030", "city" : "EAST WATERBORO", "loc" : [ -70.69062599999999, 43.599537 ], "pop" : 1153, "state" : "ME" }
+{ "_id" : "04032", "city" : "FREEPORT", "loc" : [ -70.113854, 43.851093 ], "pop" : 8081, "state" : "ME" }
+{ "_id" : "04037", "city" : "FRYEBURG", "loc" : [ -70.966841, 44.031278 ], "pop" : 2551, "state" : "ME" }
+{ "_id" : "04038", "city" : "GORHAM", "loc" : [ -70.467968, 43.684329 ], "pop" : 13642, "state" : "ME" }
+{ "_id" : "04039", "city" : "GRAY", "loc" : [ -70.342939, 43.894202 ], "pop" : 5383, "state" : "ME" }
+{ "_id" : "04040", "city" : "HARRISON", "loc" : [ -70.65385499999999, 44.107099 ], "pop" : 2274, "state" : "ME" }
+{ "_id" : "04041", "city" : "HIRAM", "loc" : [ -70.853076, 43.862217 ], "pop" : 1905, "state" : "ME" }
+{ "_id" : "04042", "city" : "HOLLIS CENTER", "loc" : [ -70.605074, 43.594578 ], "pop" : 2243, "state" : "ME" }
+{ "_id" : "04043", "city" : "KENNEBUNK", "loc" : [ -70.547802, 43.388055 ], "pop" : 7826, "state" : "ME" }
+{ "_id" : "04046", "city" : "KENNEBUNKPORT", "loc" : [ -70.47286699999999, 43.392288 ], "pop" : 5220, "state" : "ME" }
+{ "_id" : "04047", "city" : "KEZAR FALLS", "loc" : [ -70.892717, 43.785361 ], "pop" : 852, "state" : "ME" }
+{ "_id" : "04048", "city" : "LIMERICK", "loc" : [ -70.786556, 43.696265 ], "pop" : 2982, "state" : "ME" }
+{ "_id" : "04049", "city" : "LIMINGTON", "loc" : [ -70.675178, 43.726031 ], "pop" : 776, "state" : "ME" }
+{ "_id" : "04050", "city" : "LONG ISLAND", "loc" : [ -70.15509, 43.692014 ], "pop" : 201, "state" : "ME" }
+{ "_id" : "04051", "city" : "LOVELL", "loc" : [ -70.929951, 44.161404 ], "pop" : 763, "state" : "ME" }
+{ "_id" : "04053", "city" : "MEREPOINT", "loc" : [ -70.00346999999999, 43.843496 ], "pop" : 269, "state" : "ME" }
+{ "_id" : "04055", "city" : "NAPLES", "loc" : [ -70.598754, 43.968121 ], "pop" : 2868, "state" : "ME" }
+{ "_id" : "04058", "city" : "NORTH FRYEBURG", "loc" : [ -70.981286, 44.132936 ], "pop" : 185, "state" : "ME" }
+{ "_id" : "04060", "city" : "NORTH SHAPLEIGH", "loc" : [ -70.874392, 43.583458 ], "pop" : 302, "state" : "ME" }
+{ "_id" : "04061", "city" : "NORTH WATERBORO", "loc" : [ -70.729799, 43.639976 ], "pop" : 1516, "state" : "ME" }
+{ "_id" : "04062", "city" : "WINDHAM", "loc" : [ -70.414281, 43.795771 ], "pop" : 13482, "state" : "ME" }
+{ "_id" : "04064", "city" : "OLD ORCHARD BEAC", "loc" : [ -70.392053, 43.517449 ], "pop" : 8451, "state" : "ME" }
+{ "_id" : "04066", "city" : "ORRS ISLAND", "loc" : [ -69.966793, 43.77267 ], "pop" : 861, "state" : "ME" }
+{ "_id" : "04068", "city" : "PORTER", "loc" : [ -70.924266, 43.826216 ], "pop" : 985, "state" : "ME" }
+{ "_id" : "04069", "city" : "POWNAL", "loc" : [ -70.195497, 43.890042 ], "pop" : 1690, "state" : "ME" }
+{ "_id" : "04071", "city" : "RAYMOND", "loc" : [ -70.449834, 43.921917 ], "pop" : 3516, "state" : "ME" }
+{ "_id" : "04072", "city" : "SACO", "loc" : [ -70.454632, 43.520946 ], "pop" : 16192, "state" : "ME" }
+{ "_id" : "04073", "city" : "SANFORD", "loc" : [ -70.75847899999999, 43.428541 ], "pop" : 15723, "state" : "ME" }
+{ "_id" : "04074", "city" : "SCARBOROUGH", "loc" : [ -70.345668, 43.583476 ], "pop" : 12550, "state" : "ME" }
+{ "_id" : "04075", "city" : "SEBAGO LAKE", "loc" : [ -70.573454, 43.758355 ], "pop" : 4141, "state" : "ME" }
+{ "_id" : "04076", "city" : "SHAPLEIGH", "loc" : [ -70.828619, 43.567353 ], "pop" : 314, "state" : "ME" }
+{ "_id" : "04077", "city" : "SOUTH CASCO", "loc" : [ -70.51293800000001, 43.876736 ], "pop" : 250, "state" : "ME" }
+{ "_id" : "04079", "city" : "SOUTH HARPSWELL", "loc" : [ -69.993709, 43.781932 ], "pop" : 1767, "state" : "ME" }
+{ "_id" : "04081", "city" : "SOUTH WATERFORD", "loc" : [ -70.792061, 44.151256 ], "pop" : 439, "state" : "ME" }
+{ "_id" : "04083", "city" : "SPRINGVALE", "loc" : [ -70.806445, 43.471499 ], "pop" : 5472, "state" : "ME" }
+{ "_id" : "04084", "city" : "STANDISH", "loc" : [ -70.48065699999999, 43.814211 ], "pop" : 1592, "state" : "ME" }
+{ "_id" : "04085", "city" : "STEEP FALLS", "loc" : [ -70.645627, 43.757137 ], "pop" : 2060, "state" : "ME" }
+{ "_id" : "04086", "city" : "PEJEPSCOT", "loc" : [ -69.964479, 43.941286 ], "pop" : 8535, "state" : "ME" }
+{ "_id" : "04087", "city" : "WATERBORO", "loc" : [ -70.743115, 43.566097 ], "pop" : 1797, "state" : "ME" }
+{ "_id" : "04090", "city" : "WELLS", "loc" : [ -70.59688300000001, 43.314352 ], "pop" : 5590, "state" : "ME" }
+{ "_id" : "04091", "city" : "WEST BALDWIN", "loc" : [ -70.749015, 43.829873 ], "pop" : 770, "state" : "ME" }
+{ "_id" : "04092", "city" : "WESTBROOK", "loc" : [ -70.35803300000001, 43.684268 ], "pop" : 16121, "state" : "ME" }
+{ "_id" : "04093", "city" : "WEST BUXTON", "loc" : [ -70.601546, 43.661586 ], "pop" : 4910, "state" : "ME" }
+{ "_id" : "04095", "city" : "MAPLEWOOD", "loc" : [ -70.913476, 43.643417 ], "pop" : 1126, "state" : "ME" }
+{ "_id" : "04096", "city" : "YARMOUTH", "loc" : [ -70.174958, 43.800933 ], "pop" : 3068, "state" : "ME" }
+{ "_id" : "04101", "city" : "PORTLAND", "loc" : [ -70.258864, 43.660564 ], "pop" : 17147, "state" : "ME" }
+{ "_id" : "04102", "city" : "PORTLAND", "loc" : [ -70.28981, 43.660168 ], "pop" : 17660, "state" : "ME" }
+{ "_id" : "04103", "city" : "PORTLAND", "loc" : [ -70.2876, 43.687568 ], "pop" : 28461, "state" : "ME" }
+{ "_id" : "04105", "city" : "FALMOUTH", "loc" : [ -70.26253, 43.734038 ], "pop" : 7609, "state" : "ME" }
+{ "_id" : "04106", "city" : "SOUTH PORTLAND", "loc" : [ -70.270878, 43.631847 ], "pop" : 23131, "state" : "ME" }
+{ "_id" : "04107", "city" : "CAPE ELIZABETH", "loc" : [ -70.230099, 43.601735 ], "pop" : 8854, "state" : "ME" }
+{ "_id" : "04108", "city" : "PEAKS ISLAND", "loc" : [ -70.194017, 43.658921 ], "pop" : 775, "state" : "ME" }
+{ "_id" : "04109", "city" : "CUSHING ISLAND", "loc" : [ -70.202201, 43.674971 ], "pop" : 28, "state" : "ME" }
+{ "_id" : "04110", "city" : "CUMBERLAND FORES", "loc" : [ -70.188333, 43.774485 ], "pop" : 2879, "state" : "ME" }
+{ "_id" : "04210", "city" : "AUBURN", "loc" : [ -70.238978, 44.094785 ], "pop" : 24160, "state" : "ME" }
+{ "_id" : "04216", "city" : "ANDOVER", "loc" : [ -70.79666, 44.663703 ], "pop" : 878, "state" : "ME" }
+{ "_id" : "04217", "city" : "BETHEL", "loc" : [ -70.803685, 44.416176 ], "pop" : 2775, "state" : "ME" }
+{ "_id" : "04219", "city" : "BRYANT POND", "loc" : [ -70.643468, 44.395714 ], "pop" : 1563, "state" : "ME" }
+{ "_id" : "04220", "city" : "BUCKFIELD", "loc" : [ -70.36829299999999, 44.287676 ], "pop" : 1551, "state" : "ME" }
+{ "_id" : "04221", "city" : "CANTON", "loc" : [ -70.321719, 44.418894 ], "pop" : 1673, "state" : "ME" }
+{ "_id" : "04223", "city" : "DANVILLE", "loc" : [ -70.27205499999999, 44.036528 ], "pop" : 1086, "state" : "ME" }
+{ "_id" : "04224", "city" : "DIXFIELD", "loc" : [ -70.424099, 44.554799 ], "pop" : 3032, "state" : "ME" }
+{ "_id" : "04225", "city" : "DRYDEN", "loc" : [ -70.223962, 44.600218 ], "pop" : 4520, "state" : "ME" }
+{ "_id" : "04226", "city" : "EAST ANDOVER", "loc" : [ -70.729555, 44.603011 ], "pop" : 154, "state" : "ME" }
+{ "_id" : "04228", "city" : "EAST LIVERMORE", "loc" : [ -70.130334, 44.399402 ], "pop" : 560, "state" : "ME" }
+{ "_id" : "04231", "city" : "EAST STONEHAM", "loc" : [ -70.852936, 44.238201 ], "pop" : 429, "state" : "ME" }
+{ "_id" : "04235", "city" : "FRYE", "loc" : [ -70.565319, 44.599482 ], "pop" : 28, "state" : "ME" }
+{ "_id" : "04236", "city" : "GREENE", "loc" : [ -70.145532, 44.189059 ], "pop" : 3661, "state" : "ME" }
+{ "_id" : "04237", "city" : "HANOVER", "loc" : [ -70.716735, 44.495875 ], "pop" : 272, "state" : "ME" }
+{ "_id" : "04238", "city" : "HEBRON", "loc" : [ -70.37536900000001, 44.202136 ], "pop" : 826, "state" : "ME" }
+{ "_id" : "04239", "city" : "JAY", "loc" : [ -70.209883, 44.515994 ], "pop" : 4631, "state" : "ME" }
+{ "_id" : "04240", "city" : "LEWISTON", "loc" : [ -70.191619, 44.098538 ], "pop" : 40173, "state" : "ME" }
+{ "_id" : "04250", "city" : "LISBON", "loc" : [ -70.113933, 44.025511 ], "pop" : 3633, "state" : "ME" }
+{ "_id" : "04252", "city" : "LISBON FALLS", "loc" : [ -70.073375, 43.997759 ], "pop" : 8095, "state" : "ME" }
+{ "_id" : "04254", "city" : "LIVERMORE FALLS", "loc" : [ -70.193614, 44.445756 ], "pop" : 4845, "state" : "ME" }
+{ "_id" : "04256", "city" : "MECHANIC FALLS", "loc" : [ -70.368206, 44.099957 ], "pop" : 6247, "state" : "ME" }
+{ "_id" : "04257", "city" : "MEXICO", "loc" : [ -70.535797, 44.562776 ], "pop" : 3316, "state" : "ME" }
+{ "_id" : "04259", "city" : "MONMOUTH", "loc" : [ -70.02627, 44.22083 ], "pop" : 1838, "state" : "ME" }
+{ "_id" : "04260", "city" : "NEW GLOUCESTER", "loc" : [ -70.297381, 43.960835 ], "pop" : 3916, "state" : "ME" }
+{ "_id" : "04261", "city" : "NEWRY", "loc" : [ -70.79261099999999, 44.407937 ], "pop" : 300, "state" : "ME" }
+{ "_id" : "04263", "city" : "LEEDS", "loc" : [ -70.125277, 44.28343 ], "pop" : 1669, "state" : "ME" }
+{ "_id" : "04265", "city" : "NORTH MONMOUTH", "loc" : [ -70.036686, 44.275328 ], "pop" : 616, "state" : "ME" }
+{ "_id" : "04266", "city" : "NORTH TURNER", "loc" : [ -70.256147, 44.335031 ], "pop" : 953, "state" : "ME" }
+{ "_id" : "04267", "city" : "NORTH WATERFORD", "loc" : [ -70.717393, 44.206511 ], "pop" : 1168, "state" : "ME" }
+{ "_id" : "04268", "city" : "NORWAY", "loc" : [ -70.560135, 44.212654 ], "pop" : 5258, "state" : "ME" }
+{ "_id" : "04270", "city" : "OXFORD", "loc" : [ -70.509799, 44.11183 ], "pop" : 2822, "state" : "ME" }
+{ "_id" : "04273", "city" : "POLAND", "loc" : [ -70.41181899999999, 44.059187 ], "pop" : 179, "state" : "ME" }
+{ "_id" : "04274", "city" : "POLAND SPRING", "loc" : [ -70.37966400000001, 44.021162 ], "pop" : 1375, "state" : "ME" }
+{ "_id" : "04275", "city" : "ROXBURY", "loc" : [ -70.609188, 44.65657 ], "pop" : 548, "state" : "ME" }
+{ "_id" : "04276", "city" : "RUMFORD", "loc" : [ -70.564475, 44.543446 ], "pop" : 7035, "state" : "ME" }
+{ "_id" : "04278", "city" : "RUMFORD CENTER", "loc" : [ -70.700058, 44.592334 ], "pop" : 92, "state" : "ME" }
+{ "_id" : "04279", "city" : "RUMFORD POINT", "loc" : [ -70.700276, 44.557104 ], "pop" : 36, "state" : "ME" }
+{ "_id" : "04280", "city" : "SABATTUS", "loc" : [ -70.074792, 44.113269 ], "pop" : 4809, "state" : "ME" }
+{ "_id" : "04281", "city" : "SOUTH PARIS", "loc" : [ -70.50117899999999, 44.216674 ], "pop" : 6054, "state" : "ME" }
+{ "_id" : "04282", "city" : "TURNER", "loc" : [ -70.249444, 44.255669 ], "pop" : 3365, "state" : "ME" }
+{ "_id" : "04284", "city" : "WAYNE", "loc" : [ -70.0712, 44.349283 ], "pop" : 546, "state" : "ME" }
+{ "_id" : "04285", "city" : "WELD", "loc" : [ -70.42489999999999, 44.701624 ], "pop" : 430, "state" : "ME" }
+{ "_id" : "04289", "city" : "WEST PARIS", "loc" : [ -70.573167, 44.32527 ], "pop" : 2149, "state" : "ME" }
+{ "_id" : "04290", "city" : "PERU", "loc" : [ -70.443459, 44.494408 ], "pop" : 1541, "state" : "ME" }
+{ "_id" : "04291", "city" : "WEST POLAND", "loc" : [ -70.450166, 44.047167 ], "pop" : 733, "state" : "ME" }
+{ "_id" : "04292", "city" : "WEST SUMNER", "loc" : [ -70.43231400000001, 44.372804 ], "pop" : 761, "state" : "ME" }
+{ "_id" : "04294", "city" : "WILTON", "loc" : [ -70.296064, 44.59107 ], "pop" : 227, "state" : "ME" }
+{ "_id" : "04330", "city" : "AUGUSTA", "loc" : [ -69.766548, 44.323228 ], "pop" : 25195, "state" : "ME" }
+{ "_id" : "04341", "city" : "COOPERS MILLS", "loc" : [ -69.507672, 44.258823 ], "pop" : 1082, "state" : "ME" }
+{ "_id" : "04342", "city" : "DRESDEN", "loc" : [ -69.745726, 44.078507 ], "pop" : 1336, "state" : "ME" }
+{ "_id" : "04344", "city" : "FARMINGDALE", "loc" : [ -69.791313, 44.25233 ], "pop" : 2917, "state" : "ME" }
+{ "_id" : "04345", "city" : "GARDINER", "loc" : [ -69.785774, 44.207029 ], "pop" : 8387, "state" : "ME" }
+{ "_id" : "04346", "city" : "RANDOLPH", "loc" : [ -69.774918, 44.228704 ], "pop" : 6619, "state" : "ME" }
+{ "_id" : "04347", "city" : "HALLOWELL", "loc" : [ -69.80573800000001, 44.286414 ], "pop" : 2613, "state" : "ME" }
+{ "_id" : "04348", "city" : "JEFFERSON", "loc" : [ -69.483895, 44.189419 ], "pop" : 1488, "state" : "ME" }
+{ "_id" : "04349", "city" : "KENTS HILL", "loc" : [ -70.074822, 44.438259 ], "pop" : 755, "state" : "ME" }
+{ "_id" : "04350", "city" : "LITCHFIELD", "loc" : [ -69.958071, 44.163437 ], "pop" : 2354, "state" : "ME" }
+{ "_id" : "04351", "city" : "MANCHESTER", "loc" : [ -69.884657, 44.308375 ], "pop" : 603, "state" : "ME" }
+{ "_id" : "04352", "city" : "MOUNT VERNON", "loc" : [ -69.990336, 44.499342 ], "pop" : 1396, "state" : "ME" }
+{ "_id" : "04353", "city" : "NORTH WHITEFIELD", "loc" : [ -69.602164, 44.217844 ], "pop" : 1931, "state" : "ME" }
+{ "_id" : "04354", "city" : "PALERMO", "loc" : [ -69.43337, 44.384282 ], "pop" : 752, "state" : "ME" }
+{ "_id" : "04355", "city" : "READFIELD", "loc" : [ -69.95063399999999, 44.403221 ], "pop" : 1725, "state" : "ME" }
+{ "_id" : "04357", "city" : "RICHMOND", "loc" : [ -69.821077, 44.104213 ], "pop" : 3072, "state" : "ME" }
+{ "_id" : "04358", "city" : "SOUTH CHINA", "loc" : [ -69.58036, 44.395334 ], "pop" : 182, "state" : "ME" }
+{ "_id" : "04361", "city" : "WEEKS MILLS", "loc" : [ -69.541738, 44.407543 ], "pop" : 2942, "state" : "ME" }
+{ "_id" : "04363", "city" : "WINDSOR", "loc" : [ -69.58058699999999, 44.300878 ], "pop" : 1618, "state" : "ME" }
+{ "_id" : "04364", "city" : "WINTHROP", "loc" : [ -69.973128, 44.314031 ], "pop" : 7929, "state" : "ME" }
+{ "_id" : "04401", "city" : "BANGOR", "loc" : [ -68.791839, 44.824199 ], "pop" : 40434, "state" : "ME" }
+{ "_id" : "04406", "city" : "ABBOT VILLAGE", "loc" : [ -69.52513999999999, 45.279838 ], "pop" : 1193, "state" : "ME" }
+{ "_id" : "04408", "city" : "AURORA", "loc" : [ -68.295929, 44.886113 ], "pop" : 141, "state" : "ME" }
+{ "_id" : "04410", "city" : "BRADFORD", "loc" : [ -68.923491, 45.08552 ], "pop" : 1103, "state" : "ME" }
+{ "_id" : "04411", "city" : "BRADLEY", "loc" : [ -68.626328, 44.901454 ], "pop" : 1136, "state" : "ME" }
+{ "_id" : "04412", "city" : "BREWER", "loc" : [ -68.753896, 44.787433 ], "pop" : 9021, "state" : "ME" }
+{ "_id" : "04413", "city" : "BROOKTON", "loc" : [ -67.70782800000001, 45.5686 ], "pop" : 236, "state" : "ME" }
+{ "_id" : "04414", "city" : "BROWNVILLE", "loc" : [ -69.042331, 45.341229 ], "pop" : 1426, "state" : "ME" }
+{ "_id" : "04416", "city" : "BUCKSPORT", "loc" : [ -68.77682299999999, 44.601546 ], "pop" : 5340, "state" : "ME" }
+{ "_id" : "04417", "city" : "BURLINGTON", "loc" : [ -68.442701, 45.218438 ], "pop" : 643, "state" : "ME" }
+{ "_id" : "04418", "city" : "CARDVILLE", "loc" : [ -68.60327700000001, 45.077599 ], "pop" : 1309, "state" : "ME" }
+{ "_id" : "04419", "city" : "CARMEL", "loc" : [ -68.99415, 44.805315 ], "pop" : 3328, "state" : "ME" }
+{ "_id" : "04422", "city" : "CHARLESTON", "loc" : [ -69.086856, 45.067017 ], "pop" : 1819, "state" : "ME" }
+{ "_id" : "04423", "city" : "COSTIGAN", "loc" : [ -68.61296900000001, 44.975336 ], "pop" : 1895, "state" : "ME" }
+{ "_id" : "04424", "city" : "DANFORTH", "loc" : [ -67.86877800000001, 45.668654 ], "pop" : 965, "state" : "ME" }
+{ "_id" : "04426", "city" : "DOVER FOXCROFT", "loc" : [ -69.204472, 45.18774 ], "pop" : 5924, "state" : "ME" }
+{ "_id" : "04427", "city" : "EAST CORINTH", "loc" : [ -69.008532, 44.983655 ], "pop" : 2177, "state" : "ME" }
+{ "_id" : "04428", "city" : "EAST EDDINGTON", "loc" : [ -68.61883, 44.820642 ], "pop" : 2263, "state" : "ME" }
+{ "_id" : "04429", "city" : "EAST HOLDEN", "loc" : [ -68.648307, 44.742209 ], "pop" : 4472, "state" : "ME" }
+{ "_id" : "04430", "city" : "EAST MILLINOCKET", "loc" : [ -68.572822, 45.629967 ], "pop" : 2198, "state" : "ME" }
+{ "_id" : "04431", "city" : "EAST ORLAND", "loc" : [ -68.70174, 44.57249 ], "pop" : 1281, "state" : "ME" }
+{ "_id" : "04433", "city" : "ENFIELD", "loc" : [ -68.605802, 45.266477 ], "pop" : 1483, "state" : "ME" }
+{ "_id" : "04434", "city" : "ETNA", "loc" : [ -69.13222500000001, 44.793232 ], "pop" : 966, "state" : "ME" }
+{ "_id" : "04435", "city" : "EXETER", "loc" : [ -69.107934, 44.967927 ], "pop" : 561, "state" : "ME" }
+{ "_id" : "04438", "city" : "FRANKFORT", "loc" : [ -68.933981, 44.59794 ], "pop" : 1141, "state" : "ME" }
+{ "_id" : "04441", "city" : "GREENVILLE", "loc" : [ -69.58437600000001, 45.471566 ], "pop" : 2054, "state" : "ME" }
+{ "_id" : "04442", "city" : "GREENVILLE JUNCT", "loc" : [ -69.63752599999999, 45.488394 ], "pop" : 99, "state" : "ME" }
+{ "_id" : "04443", "city" : "GUILFORD", "loc" : [ -69.397491, 45.173455 ], "pop" : 2833, "state" : "ME" }
+{ "_id" : "04444", "city" : "HAMPDEN", "loc" : [ -68.87305000000001, 44.741073 ], "pop" : 6756, "state" : "ME" }
+{ "_id" : "04446", "city" : "HAYNESVILLE", "loc" : [ -67.98858, 45.837991 ], "pop" : 244, "state" : "ME" }
+{ "_id" : "04448", "city" : "SEBOEIS", "loc" : [ -68.669252, 45.247813 ], "pop" : 1628, "state" : "ME" }
+{ "_id" : "04449", "city" : "HUDSON", "loc" : [ -68.88783100000001, 44.991415 ], "pop" : 1048, "state" : "ME" }
+{ "_id" : "04450", "city" : "KENDUSKEAG", "loc" : [ -68.934179, 44.918251 ], "pop" : 1234, "state" : "ME" }
+{ "_id" : "04451", "city" : "KINGMAN", "loc" : [ -68.23662, 45.598433 ], "pop" : 378, "state" : "ME" }
+{ "_id" : "04453", "city" : "LAGRANGE", "loc" : [ -68.83448, 45.178918 ], "pop" : 707, "state" : "ME" }
+{ "_id" : "04455", "city" : "LEE", "loc" : [ -68.290885, 45.363504 ], "pop" : 832, "state" : "ME" }
+{ "_id" : "04456", "city" : "LEVANT", "loc" : [ -68.98367, 44.884279 ], "pop" : 1627, "state" : "ME" }
+{ "_id" : "04457", "city" : "LINCOLN", "loc" : [ -68.507693, 45.350832 ], "pop" : 4715, "state" : "ME" }
+{ "_id" : "04458", "city" : "LINCOLN CENTER", "loc" : [ -68.457065, 45.431731 ], "pop" : 1556, "state" : "ME" }
+{ "_id" : "04459", "city" : "MATTAWAMKEAG", "loc" : [ -68.35195, 45.526387 ], "pop" : 841, "state" : "ME" }
+{ "_id" : "04460", "city" : "MEDWAY", "loc" : [ -68.52270900000001, 45.60704 ], "pop" : 1986, "state" : "ME" }
+{ "_id" : "04461", "city" : "MILFORD", "loc" : [ -68.629597, 44.939263 ], "pop" : 1732, "state" : "ME" }
+{ "_id" : "04462", "city" : "MILLINOCKET", "loc" : [ -68.710117, 45.659563 ], "pop" : 7265, "state" : "ME" }
+{ "_id" : "04463", "city" : "DERBY", "loc" : [ -68.977098, 45.250697 ], "pop" : 3091, "state" : "ME" }
+{ "_id" : "04464", "city" : "MONSON", "loc" : [ -69.48798600000001, 45.298088 ], "pop" : 263, "state" : "ME" }
+{ "_id" : "04468", "city" : "OLD TOWN", "loc" : [ -68.67496, 44.943044 ], "pop" : 9290, "state" : "ME" }
+{ "_id" : "04471", "city" : "NORTH AMITY", "loc" : [ -67.83774099999999, 45.805639 ], "pop" : 138, "state" : "ME" }
+{ "_id" : "04472", "city" : "ORLAND", "loc" : [ -68.731312, 44.545818 ], "pop" : 524, "state" : "ME" }
+{ "_id" : "04473", "city" : "ORONO", "loc" : [ -68.675466, 44.892472 ], "pop" : 10484, "state" : "ME" }
+{ "_id" : "04474", "city" : "ORRINGTON", "loc" : [ -68.78759700000001, 44.726347 ], "pop" : 3309, "state" : "ME" }
+{ "_id" : "04475", "city" : "PASSADUMKEAG", "loc" : [ -68.604328, 45.183687 ], "pop" : 428, "state" : "ME" }
+{ "_id" : "04476", "city" : "PENOBSCOT", "loc" : [ -68.757409, 44.434371 ], "pop" : 2290, "state" : "ME" }
+{ "_id" : "04478", "city" : "ROCKWOOD", "loc" : [ -69.822442, 45.659329 ], "pop" : 367, "state" : "ME" }
+{ "_id" : "04479", "city" : "SANGERVILLE", "loc" : [ -69.321772, 45.140571 ], "pop" : 984, "state" : "ME" }
+{ "_id" : "04487", "city" : "SPRINGFIELD", "loc" : [ -68.11075599999999, 45.42638 ], "pop" : 985, "state" : "ME" }
+{ "_id" : "04488", "city" : "STETSON", "loc" : [ -69.106877, 44.884337 ], "pop" : 738, "state" : "ME" }
+{ "_id" : "04490", "city" : "TOPSFIELD", "loc" : [ -67.747253, 45.430403 ], "pop" : 274, "state" : "ME" }
+{ "_id" : "04491", "city" : "VANCEBORO", "loc" : [ -67.463419, 45.558761 ], "pop" : 217, "state" : "ME" }
+{ "_id" : "04492", "city" : "WAITE", "loc" : [ -67.64281200000001, 45.357741 ], "pop" : 233, "state" : "ME" }
+{ "_id" : "04495", "city" : "WINN", "loc" : [ -68.357465, 45.456786 ], "pop" : 479, "state" : "ME" }
+{ "_id" : "04496", "city" : "WINTERPORT", "loc" : [ -68.886174, 44.655247 ], "pop" : 3175, "state" : "ME" }
+{ "_id" : "04497", "city" : "WYTOPITLOCK", "loc" : [ -68.105541, 45.664476 ], "pop" : 384, "state" : "ME" }
+{ "_id" : "04530", "city" : "BATH", "loc" : [ -69.826565, 43.906155 ], "pop" : 12628, "state" : "ME" }
+{ "_id" : "04537", "city" : "BOOTHBAY", "loc" : [ -69.62732200000001, 43.894497 ], "pop" : 1701, "state" : "ME" }
+{ "_id" : "04538", "city" : "CAPITOL ISLAND", "loc" : [ -69.61844000000001, 43.854559 ], "pop" : 2800, "state" : "ME" }
+{ "_id" : "04539", "city" : "BRISTOL", "loc" : [ -69.495367, 43.951864 ], "pop" : 1220, "state" : "ME" }
+{ "_id" : "04541", "city" : "CHAMBERLAIN", "loc" : [ -69.49861799999999, 43.884154 ], "pop" : 482, "state" : "ME" }
+{ "_id" : "04543", "city" : "DAMARISCOTTA", "loc" : [ -69.504237, 44.029313 ], "pop" : 1217, "state" : "ME" }
+{ "_id" : "04544", "city" : "EAST BOOTHBAY", "loc" : [ -69.593903, 43.826241 ], "pop" : 156, "state" : "ME" }
+{ "_id" : "04547", "city" : "FRIENDSHIP", "loc" : [ -69.29160400000001, 44.006741 ], "pop" : 2085, "state" : "ME" }
+{ "_id" : "04548", "city" : "MAC MAHAN", "loc" : [ -69.747424, 43.819649 ], "pop" : 936, "state" : "ME" }
+{ "_id" : "04551", "city" : "MEDOMAK", "loc" : [ -69.43066399999999, 44.006292 ], "pop" : 540, "state" : "ME" }
+{ "_id" : "04553", "city" : "NEWCASTLE", "loc" : [ -69.533113, 44.049866 ], "pop" : 1551, "state" : "ME" }
+{ "_id" : "04554", "city" : "NEW HARBOR", "loc" : [ -69.50793400000001, 43.860541 ], "pop" : 362, "state" : "ME" }
+{ "_id" : "04555", "city" : "NOBLEBORO", "loc" : [ -69.482786, 44.094301 ], "pop" : 1455, "state" : "ME" }
+{ "_id" : "04556", "city" : "EDGECOMB", "loc" : [ -69.619742, 43.979179 ], "pop" : 1238, "state" : "ME" }
+{ "_id" : "04558", "city" : "PEMAQUID", "loc" : [ -69.528919, 43.892389 ], "pop" : 103, "state" : "ME" }
+{ "_id" : "04562", "city" : "PHIPPSBURG", "loc" : [ -69.814982, 43.768816 ], "pop" : 426, "state" : "ME" }
+{ "_id" : "04563", "city" : "CUSHING", "loc" : [ -69.27206099999999, 43.986741 ], "pop" : 12, "state" : "ME" }
+{ "_id" : "04564", "city" : "ROUND POND", "loc" : [ -69.46617000000001, 43.924983 ], "pop" : 159, "state" : "ME" }
+{ "_id" : "04565", "city" : "SEBASCO ESTATES", "loc" : [ -69.857557, 43.769342 ], "pop" : 479, "state" : "ME" }
+{ "_id" : "04567", "city" : "SMALL POINT", "loc" : [ -69.84116299999999, 43.731724 ], "pop" : 66, "state" : "ME" }
+{ "_id" : "04568", "city" : "SOUTH BRISTOL", "loc" : [ -69.561367, 43.867714 ], "pop" : 476, "state" : "ME" }
+{ "_id" : "04570", "city" : "SQUIRREL ISLAND", "loc" : [ -69.63097399999999, 43.809031 ], "pop" : 3, "state" : "ME" }
+{ "_id" : "04571", "city" : "TREVETT", "loc" : [ -69.674601, 43.893508 ], "pop" : 338, "state" : "ME" }
+{ "_id" : "04572", "city" : "WALDOBORO", "loc" : [ -69.374537, 44.104601 ], "pop" : 4702, "state" : "ME" }
+{ "_id" : "04573", "city" : "WALPOLE", "loc" : [ -69.55165, 43.946235 ], "pop" : 349, "state" : "ME" }
+{ "_id" : "04574", "city" : "WASHINGTON", "loc" : [ -69.384237, 44.269281 ], "pop" : 1261, "state" : "ME" }
+{ "_id" : "04576", "city" : "WEST SOUTHPORT", "loc" : [ -69.667343, 43.823775 ], "pop" : 642, "state" : "ME" }
+{ "_id" : "04578", "city" : "WISCASSET", "loc" : [ -69.682576, 44.007444 ], "pop" : 5928, "state" : "ME" }
+{ "_id" : "04579", "city" : "WOOLWICH", "loc" : [ -69.789098, 43.950317 ], "pop" : 1781, "state" : "ME" }
+{ "_id" : "04605", "city" : "ELLSWORTH", "loc" : [ -68.412093, 44.554824 ], "pop" : 10671, "state" : "ME" }
+{ "_id" : "04606", "city" : "ADDISON", "loc" : [ -67.714573, 44.583038 ], "pop" : 1114, "state" : "ME" }
+{ "_id" : "04607", "city" : "GOULDSBORO", "loc" : [ -68.08985699999999, 44.473054 ], "pop" : 1064, "state" : "ME" }
+{ "_id" : "04609", "city" : "BAR HARBOR", "loc" : [ -68.24479100000001, 44.373799 ], "pop" : 5513, "state" : "ME" }
+{ "_id" : "04611", "city" : "BEALS", "loc" : [ -67.605554, 44.512967 ], "pop" : 667, "state" : "ME" }
+{ "_id" : "04612", "city" : "BERNARD", "loc" : [ -68.35803, 44.241543 ], "pop" : 186, "state" : "ME" }
+{ "_id" : "04613", "city" : "BIRCH HARBOR", "loc" : [ -68.03168599999999, 44.384195 ], "pop" : 229, "state" : "ME" }
+{ "_id" : "04614", "city" : "BLUE HILL", "loc" : [ -68.58851300000001, 44.434265 ], "pop" : 1417, "state" : "ME" }
+{ "_id" : "04615", "city" : "BLUE HILL FALLS", "loc" : [ -68.590282, 44.390244 ], "pop" : 375, "state" : "ME" }
+{ "_id" : "04616", "city" : "BROOKLIN", "loc" : [ -68.556518, 44.254134 ], "pop" : 260, "state" : "ME" }
+{ "_id" : "04617", "city" : "BROOKSVILLE", "loc" : [ -68.731279, 44.375635 ], "pop" : 594, "state" : "ME" }
+{ "_id" : "04618", "city" : "BUCKS HARBOR", "loc" : [ -67.396382, 44.624762 ], "pop" : 402, "state" : "ME" }
+{ "_id" : "04619", "city" : "CALAIS", "loc" : [ -67.26408000000001, 45.171478 ], "pop" : 3963, "state" : "ME" }
+{ "_id" : "04622", "city" : "CHERRYFIELD", "loc" : [ -67.943617, 44.622791 ], "pop" : 1341, "state" : "ME" }
+{ "_id" : "04623", "city" : "COLUMBIA FALLS", "loc" : [ -67.75341, 44.66988 ], "pop" : 960, "state" : "ME" }
+{ "_id" : "04624", "city" : "COREA", "loc" : [ -67.985032, 44.405281 ], "pop" : 507, "state" : "ME" }
+{ "_id" : "04626", "city" : "CUTLER", "loc" : [ -67.249869, 44.67531 ], "pop" : 779, "state" : "ME" }
+{ "_id" : "04627", "city" : "DEER ISLE", "loc" : [ -68.644839, 44.233951 ], "pop" : 949, "state" : "ME" }
+{ "_id" : "04628", "city" : "DENNYSVILLE", "loc" : [ -67.224431, 44.896105 ], "pop" : 684, "state" : "ME" }
+{ "_id" : "04630", "city" : "EAST MACHIAS", "loc" : [ -67.38206599999999, 44.742362 ], "pop" : 1574, "state" : "ME" }
+{ "_id" : "04631", "city" : "EASTPORT", "loc" : [ -67.00739, 44.919966 ], "pop" : 2514, "state" : "ME" }
+{ "_id" : "04634", "city" : "FRANKLIN", "loc" : [ -68.241653, 44.608734 ], "pop" : 1433, "state" : "ME" }
+{ "_id" : "04640", "city" : "HANCOCK", "loc" : [ -68.2402, 44.50459 ], "pop" : 769, "state" : "ME" }
+{ "_id" : "04642", "city" : "HARBORSIDE", "loc" : [ -68.800901, 44.338584 ], "pop" : 122, "state" : "ME" }
+{ "_id" : "04643", "city" : "HARRINGTON", "loc" : [ -67.814722, 44.612218 ], "pop" : 986, "state" : "ME" }
+{ "_id" : "04645", "city" : "ISLE AU HAUT", "loc" : [ -68.620598, 44.056057 ], "pop" : 46, "state" : "ME" }
+{ "_id" : "04648", "city" : "JONESBORO", "loc" : [ -67.577692, 44.658153 ], "pop" : 585, "state" : "ME" }
+{ "_id" : "04649", "city" : "JONESPORT", "loc" : [ -67.604403, 44.550936 ], "pop" : 1520, "state" : "ME" }
+{ "_id" : "04650", "city" : "LITTLE DEER ISLE", "loc" : [ -68.70666300000001, 44.285213 ], "pop" : 235, "state" : "ME" }
+{ "_id" : "04652", "city" : "LUBEC", "loc" : [ -67.04601599999999, 44.834772 ], "pop" : 2349, "state" : "ME" }
+{ "_id" : "04653", "city" : "BASS HARBOR", "loc" : [ -68.380387, 44.1993 ], "pop" : 827, "state" : "ME" }
+{ "_id" : "04654", "city" : "MACHIAS", "loc" : [ -67.481996, 44.72154 ], "pop" : 3766, "state" : "ME" }
+{ "_id" : "04655", "city" : "MACHIASPORT", "loc" : [ -67.40727699999999, 44.682039 ], "pop" : 602, "state" : "ME" }
+{ "_id" : "04656", "city" : "MANSET", "loc" : [ -68.314408, 44.262573 ], "pop" : 445, "state" : "ME" }
+{ "_id" : "04657", "city" : "MEDDYBEMPS", "loc" : [ -67.382852, 45.019306 ], "pop" : 242, "state" : "ME" }
+{ "_id" : "04658", "city" : "MILBRIDGE", "loc" : [ -67.884433, 44.536601 ], "pop" : 1587, "state" : "ME" }
+{ "_id" : "04660", "city" : "MOUNT DESERT", "loc" : [ -68.352253, 44.311547 ], "pop" : 2184, "state" : "ME" }
+{ "_id" : "04661", "city" : "NORTH BROOKLIN", "loc" : [ -68.577326, 44.308469 ], "pop" : 674, "state" : "ME" }
+{ "_id" : "04666", "city" : "PEMBROKE", "loc" : [ -67.200204, 44.965396 ], "pop" : 1151, "state" : "ME" }
+{ "_id" : "04667", "city" : "PERRY", "loc" : [ -67.092882, 44.988824 ], "pop" : 781, "state" : "ME" }
+{ "_id" : "04668", "city" : "PRINCETON", "loc" : [ -67.600826, 45.213091 ], "pop" : 1918, "state" : "ME" }
+{ "_id" : "04669", "city" : "PROSPECT HARBOR", "loc" : [ -68.02794299999999, 44.419489 ], "pop" : 385, "state" : "ME" }
+{ "_id" : "04671", "city" : "ROBBINSTON", "loc" : [ -67.14330099999999, 45.067007 ], "pop" : 495, "state" : "ME" }
+{ "_id" : "04673", "city" : "SARGENTVILLE", "loc" : [ -68.70522099999999, 44.3345 ], "pop" : 43, "state" : "ME" }
+{ "_id" : "04676", "city" : "SEDGWICK", "loc" : [ -68.637659, 44.33552 ], "pop" : 908, "state" : "ME" }
+{ "_id" : "04677", "city" : "SORRENTO", "loc" : [ -68.178665, 44.490696 ], "pop" : 295, "state" : "ME" }
+{ "_id" : "04678", "city" : "SOUTH GOULDSBORO", "loc" : [ -68.030406, 44.47163 ], "pop" : 58, "state" : "ME" }
+{ "_id" : "04679", "city" : "SOUTHWEST HARBOR", "loc" : [ -68.326471, 44.2823 ], "pop" : 927, "state" : "ME" }
+{ "_id" : "04680", "city" : "STEUBEN", "loc" : [ -67.95031899999999, 44.497082 ], "pop" : 773, "state" : "ME" }
+{ "_id" : "04681", "city" : "STONINGTON", "loc" : [ -68.674617, 44.175197 ], "pop" : 1746, "state" : "ME" }
+{ "_id" : "04683", "city" : "SUNSET", "loc" : [ -68.707002, 44.217404 ], "pop" : 149, "state" : "ME" }
+{ "_id" : "04684", "city" : "SURRY", "loc" : [ -68.506272, 44.488272 ], "pop" : 1004, "state" : "ME" }
+{ "_id" : "04690", "city" : "WEST TREMONT", "loc" : [ -68.380365, 44.252778 ], "pop" : 119, "state" : "ME" }
+{ "_id" : "04693", "city" : "WINTER HARBOR", "loc" : [ -68.084316, 44.390038 ], "pop" : 1157, "state" : "ME" }
+{ "_id" : "04694", "city" : "WOODLAND", "loc" : [ -67.417519, 45.133234 ], "pop" : 2909, "state" : "ME" }
+{ "_id" : "04730", "city" : "HOULTON", "loc" : [ -67.86301400000001, 46.11885 ], "pop" : 10382, "state" : "ME" }
+{ "_id" : "04732", "city" : "ASHLAND", "loc" : [ -68.387608, 46.618438 ], "pop" : 2022, "state" : "ME" }
+{ "_id" : "04733", "city" : "BENEDICTA", "loc" : [ -68.408855, 45.812484 ], "pop" : 192, "state" : "ME" }
+{ "_id" : "04735", "city" : "BRIDGEWATER", "loc" : [ -67.841469, 46.422154 ], "pop" : 652, "state" : "ME" }
+{ "_id" : "04736", "city" : "CARIBOU", "loc" : [ -68.020352, 46.870569 ], "pop" : 10928, "state" : "ME" }
+{ "_id" : "04737", "city" : "CLAYTON LAKE", "loc" : [ -69.626445, 46.629805 ], "pop" : 54, "state" : "ME" }
+{ "_id" : "04740", "city" : "EASTON", "loc" : [ -67.901777, 46.635697 ], "pop" : 1056, "state" : "ME" }
+{ "_id" : "04742", "city" : "FORT FAIRFIELD", "loc" : [ -67.840204, 46.762272 ], "pop" : 4474, "state" : "ME" }
+{ "_id" : "04743", "city" : "FORT KENT", "loc" : [ -68.590855, 47.196857 ], "pop" : 6076, "state" : "ME" }
+{ "_id" : "04746", "city" : "GRAND ISLE", "loc" : [ -68.15423800000001, 47.304428 ], "pop" : 318, "state" : "ME" }
+{ "_id" : "04747", "city" : "ISLAND FALLS", "loc" : [ -68.266722, 46.016866 ], "pop" : 1444, "state" : "ME" }
+{ "_id" : "04749", "city" : "LILLE", "loc" : [ -68.110393, 47.263623 ], "pop" : 253, "state" : "ME" }
+{ "_id" : "04750", "city" : "LIMESTONE", "loc" : [ -67.84508599999999, 46.924786 ], "pop" : 2693, "state" : "ME" }
+{ "_id" : "04751", "city" : "LORING AFB", "loc" : [ -67.89858, 46.9416 ], "pop" : 7844, "state" : "ME" }
+{ "_id" : "04756", "city" : "MADAWASKA", "loc" : [ -68.33280999999999, 47.329447 ], "pop" : 5860, "state" : "ME" }
+{ "_id" : "04757", "city" : "MAPLETON", "loc" : [ -68.153584, 46.674634 ], "pop" : 1982, "state" : "ME" }
+{ "_id" : "04758", "city" : "MARS HILL", "loc" : [ -67.862973, 46.522268 ], "pop" : 2010, "state" : "ME" }
+{ "_id" : "04760", "city" : "MONTICELLO", "loc" : [ -67.84143899999999, 46.300658 ], "pop" : 1174, "state" : "ME" }
+{ "_id" : "04762", "city" : "NEW SWEDEN", "loc" : [ -68.11545, 46.955916 ], "pop" : 935, "state" : "ME" }
+{ "_id" : "04763", "city" : "OAKFIELD", "loc" : [ -68.129805, 46.108753 ], "pop" : 1113, "state" : "ME" }
+{ "_id" : "04764", "city" : "OXBOW", "loc" : [ -68.521792, 46.401955 ], "pop" : 76, "state" : "ME" }
+{ "_id" : "04765", "city" : "PATTEN", "loc" : [ -68.464669, 46.01316 ], "pop" : 1595, "state" : "ME" }
+{ "_id" : "04768", "city" : "PORTAGE", "loc" : [ -68.487675, 46.775303 ], "pop" : 445, "state" : "ME" }
+{ "_id" : "04769", "city" : "PRESQUE ISLE", "loc" : [ -68.01179, 46.684151 ], "pop" : 11058, "state" : "ME" }
+{ "_id" : "04772", "city" : "SAINT AGATHA", "loc" : [ -68.32323700000001, 47.238655 ], "pop" : 919, "state" : "ME" }
+{ "_id" : "04773", "city" : "SAINT DAVID", "loc" : [ -68.231368, 47.334328 ], "pop" : 285, "state" : "ME" }
+{ "_id" : "04774", "city" : "SAINT FRANCIS", "loc" : [ -68.950309, 47.14071 ], "pop" : 1048, "state" : "ME" }
+{ "_id" : "04776", "city" : "SHERMAN MILLS", "loc" : [ -68.369587, 45.877727 ], "pop" : 1139, "state" : "ME" }
+{ "_id" : "04777", "city" : "SHERMAN STATION", "loc" : [ -68.461844, 45.885892 ], "pop" : 527, "state" : "ME" }
+{ "_id" : "04779", "city" : "SINCLAIR", "loc" : [ -68.267922, 47.174384 ], "pop" : 216, "state" : "ME" }
+{ "_id" : "04780", "city" : "SMYRNA MILLS", "loc" : [ -68.206363, 46.146412 ], "pop" : 453, "state" : "ME" }
+{ "_id" : "04781", "city" : "SOLDIER POND", "loc" : [ -68.59808099999999, 47.151529 ], "pop" : 484, "state" : "ME" }
+{ "_id" : "04783", "city" : "STOCKHOLM", "loc" : [ -68.208614, 47.064299 ], "pop" : 665, "state" : "ME" }
+{ "_id" : "04785", "city" : "VAN BUREN", "loc" : [ -67.94589000000001, 47.158857 ], "pop" : 3391, "state" : "ME" }
+{ "_id" : "04786", "city" : "WASHBURN", "loc" : [ -68.133836, 46.788271 ], "pop" : 2783, "state" : "ME" }
+{ "_id" : "04787", "city" : "WESTFIELD", "loc" : [ -67.89736499999999, 46.508687 ], "pop" : 854, "state" : "ME" }
+{ "_id" : "04841", "city" : "ROCKLAND", "loc" : [ -69.113938, 44.112326 ], "pop" : 8975, "state" : "ME" }
+{ "_id" : "04843", "city" : "CAMDEN", "loc" : [ -69.07668200000001, 44.213718 ], "pop" : 5060, "state" : "ME" }
+{ "_id" : "04847", "city" : "HOPE", "loc" : [ -69.146743, 44.258902 ], "pop" : 143, "state" : "ME" }
+{ "_id" : "04848", "city" : "ISLESBORO", "loc" : [ -68.907346, 44.30823 ], "pop" : 580, "state" : "ME" }
+{ "_id" : "04849", "city" : "LINCOLNVILLE", "loc" : [ -69.082446, 44.304825 ], "pop" : 2458, "state" : "ME" }
+{ "_id" : "04852", "city" : "MONHEGAN", "loc" : [ -69.316429, 43.764222 ], "pop" : 88, "state" : "ME" }
+{ "_id" : "04853", "city" : "NORTH HAVEN", "loc" : [ -68.866744, 44.143598 ], "pop" : 333, "state" : "ME" }
+{ "_id" : "04854", "city" : "OWLS HEAD", "loc" : [ -69.089416, 44.073186 ], "pop" : 1624, "state" : "ME" }
+{ "_id" : "04856", "city" : "ROCKPORT", "loc" : [ -69.090114, 44.188787 ], "pop" : 1421, "state" : "ME" }
+{ "_id" : "04857", "city" : "SAINT GEORGE", "loc" : [ -69.201984, 43.998687 ], "pop" : 225, "state" : "ME" }
+{ "_id" : "04858", "city" : "SOUTH THOMASTON", "loc" : [ -69.135937, 44.037785 ], "pop" : 1172, "state" : "ME" }
+{ "_id" : "04859", "city" : "SPRUCE HEAD", "loc" : [ -69.17071, 44.010405 ], "pop" : 719, "state" : "ME" }
+{ "_id" : "04860", "city" : "TENANTS HARBOR", "loc" : [ -69.23150099999999, 43.955473 ], "pop" : 1322, "state" : "ME" }
+{ "_id" : "04861", "city" : "THOMASTON", "loc" : [ -69.18880299999999, 44.084568 ], "pop" : 3560, "state" : "ME" }
+{ "_id" : "04862", "city" : "UNION", "loc" : [ -69.25243500000001, 44.242404 ], "pop" : 3853, "state" : "ME" }
+{ "_id" : "04863", "city" : "VINALHAVEN", "loc" : [ -68.836816, 44.03968 ], "pop" : 1139, "state" : "ME" }
+{ "_id" : "04864", "city" : "WARREN", "loc" : [ -69.247894, 44.127066 ], "pop" : 2816, "state" : "ME" }
+{ "_id" : "04865", "city" : "WEST ROCKPORT", "loc" : [ -69.151049, 44.181966 ], "pop" : 555, "state" : "ME" }
+{ "_id" : "04901", "city" : "WINSLOW", "loc" : [ -69.63591700000001, 44.547967 ], "pop" : 24915, "state" : "ME" }
+{ "_id" : "04910", "city" : "ALBION", "loc" : [ -69.46828600000001, 44.535527 ], "pop" : 2616, "state" : "ME" }
+{ "_id" : "04911", "city" : "ANSON", "loc" : [ -69.93085600000001, 44.783107 ], "pop" : 1698, "state" : "ME" }
+{ "_id" : "04912", "city" : "ATHENS", "loc" : [ -69.669482, 44.938844 ], "pop" : 897, "state" : "ME" }
+{ "_id" : "04915", "city" : "BELFAST", "loc" : [ -69.014753, 44.435436 ], "pop" : 9637, "state" : "ME" }
+{ "_id" : "04917", "city" : "BELGRADE", "loc" : [ -69.860636, 44.46875 ], "pop" : 1513, "state" : "ME" }
+{ "_id" : "04918", "city" : "BELGRADE LAKES", "loc" : [ -69.863681, 44.511103 ], "pop" : 316, "state" : "ME" }
+{ "_id" : "04920", "city" : "BINGHAM", "loc" : [ -69.885721, 45.068241 ], "pop" : 1712, "state" : "ME" }
+{ "_id" : "04921", "city" : "BROOKS", "loc" : [ -69.140393, 44.567807 ], "pop" : 1846, "state" : "ME" }
+{ "_id" : "04922", "city" : "BURNHAM", "loc" : [ -69.380049, 44.684766 ], "pop" : 961, "state" : "ME" }
+{ "_id" : "04923", "city" : "CAMBRIDGE", "loc" : [ -69.44193, 45.051281 ], "pop" : 863, "state" : "ME" }
+{ "_id" : "04924", "city" : "CANAAN", "loc" : [ -69.54977700000001, 44.744976 ], "pop" : 1083, "state" : "ME" }
+{ "_id" : "04925", "city" : "CARATUNK", "loc" : [ -69.93861699999999, 45.240999 ], "pop" : 124, "state" : "ME" }
+{ "_id" : "04927", "city" : "CLINTON", "loc" : [ -69.52840500000001, 44.643995 ], "pop" : 4598, "state" : "ME" }
+{ "_id" : "04928", "city" : "CORINNA", "loc" : [ -69.23234100000001, 44.926045 ], "pop" : 2363, "state" : "ME" }
+{ "_id" : "04929", "city" : "DETROIT", "loc" : [ -69.316081, 44.777526 ], "pop" : 751, "state" : "ME" }
+{ "_id" : "04930", "city" : "DEXTER", "loc" : [ -69.27965399999999, 45.020347 ], "pop" : 5875, "state" : "ME" }
+{ "_id" : "04932", "city" : "DIXMONT", "loc" : [ -69.102532, 44.699078 ], "pop" : 1660, "state" : "ME" }
+{ "_id" : "04936", "city" : "EUSTIS", "loc" : [ -70.457067, 45.162559 ], "pop" : 539, "state" : "ME" }
+{ "_id" : "04937", "city" : "BENTON STATION", "loc" : [ -69.63321000000001, 44.609639 ], "pop" : 6718, "state" : "ME" }
+{ "_id" : "04938", "city" : "FARMINGTON", "loc" : [ -70.13287800000001, 44.665339 ], "pop" : 9133, "state" : "ME" }
+{ "_id" : "04941", "city" : "FREEDOM", "loc" : [ -69.319045, 44.463311 ], "pop" : 1775, "state" : "ME" }
+{ "_id" : "04942", "city" : "WELLINGTON", "loc" : [ -69.56871, 45.003926 ], "pop" : 1217, "state" : "ME" }
+{ "_id" : "04943", "city" : "HARTLAND", "loc" : [ -69.471754, 44.878155 ], "pop" : 1821, "state" : "ME" }
+{ "_id" : "04945", "city" : "JACKMAN", "loc" : [ -70.249227, 45.635081 ], "pop" : 1207, "state" : "ME" }
+{ "_id" : "04947", "city" : "KINGFIELD", "loc" : [ -70.183177, 44.985403 ], "pop" : 1501, "state" : "ME" }
+{ "_id" : "04949", "city" : "LIBERTY", "loc" : [ -69.33058, 44.374085 ], "pop" : 790, "state" : "ME" }
+{ "_id" : "04950", "city" : "MADISON", "loc" : [ -69.8449, 44.809623 ], "pop" : 4725, "state" : "ME" }
+{ "_id" : "04951", "city" : "MONROE", "loc" : [ -69.03169, 44.592674 ], "pop" : 616, "state" : "ME" }
+{ "_id" : "04952", "city" : "MORRILL", "loc" : [ -69.147105, 44.410693 ], "pop" : 1433, "state" : "ME" }
+{ "_id" : "04953", "city" : "NEWPORT", "loc" : [ -69.267498, 44.839264 ], "pop" : 3272, "state" : "ME" }
+{ "_id" : "04954", "city" : "NEW PORTLAND", "loc" : [ -70.092857, 44.885571 ], "pop" : 312, "state" : "ME" }
+{ "_id" : "04955", "city" : "NEW SHARON", "loc" : [ -70.013927, 44.645803 ], "pop" : 1175, "state" : "ME" }
+{ "_id" : "04956", "city" : "NEW VINEYARD", "loc" : [ -70.121953, 44.796658 ], "pop" : 661, "state" : "ME" }
+{ "_id" : "04957", "city" : "NORRIDGEWOCK", "loc" : [ -69.830583, 44.68994 ], "pop" : 4520, "state" : "ME" }
+{ "_id" : "04958", "city" : "NORTH ANSON", "loc" : [ -69.911946, 44.879662 ], "pop" : 1967, "state" : "ME" }
+{ "_id" : "04961", "city" : "NORTH NEW PORTLA", "loc" : [ -70.043268, 44.95524 ], "pop" : 537, "state" : "ME" }
+{ "_id" : "04962", "city" : "NORTH VASSALBORO", "loc" : [ -69.57808, 44.477748 ], "pop" : 2457, "state" : "ME" }
+{ "_id" : "04963", "city" : "OAKLAND", "loc" : [ -69.740082, 44.51729 ], "pop" : 8695, "state" : "ME" }
+{ "_id" : "04965", "city" : "PALMYRA", "loc" : [ -69.381084, 44.857578 ], "pop" : 1093, "state" : "ME" }
+{ "_id" : "04966", "city" : "PHILLIPS", "loc" : [ -70.360079, 44.837486 ], "pop" : 1930, "state" : "ME" }
+{ "_id" : "04967", "city" : "PITTSFIELD", "loc" : [ -69.40223, 44.787109 ], "pop" : 4719, "state" : "ME" }
+{ "_id" : "04969", "city" : "PLYMOUTH", "loc" : [ -69.226562, 44.769938 ], "pop" : 974, "state" : "ME" }
+{ "_id" : "04970", "city" : "RANGELEY", "loc" : [ -70.66584400000001, 44.96306 ], "pop" : 1391, "state" : "ME" }
+{ "_id" : "04971", "city" : "SAINT ALBANS", "loc" : [ -69.399179, 44.929264 ], "pop" : 1575, "state" : "ME" }
+{ "_id" : "04973", "city" : "SEARSMONT", "loc" : [ -69.219579, 44.377035 ], "pop" : 422, "state" : "ME" }
+{ "_id" : "04974", "city" : "SEARSPORT", "loc" : [ -68.93112499999999, 44.487672 ], "pop" : 1927, "state" : "ME" }
+{ "_id" : "04976", "city" : "SKOWHEGAN", "loc" : [ -69.697571, 44.777212 ], "pop" : 10166, "state" : "ME" }
+{ "_id" : "04978", "city" : "SMITHFIELD", "loc" : [ -69.807496, 44.630107 ], "pop" : 715, "state" : "ME" }
+{ "_id" : "04979", "city" : "SOLON", "loc" : [ -69.833018, 44.967605 ], "pop" : 1236, "state" : "ME" }
+{ "_id" : "04981", "city" : "STOCKTON SPRINGS", "loc" : [ -68.855974, 44.514056 ], "pop" : 1925, "state" : "ME" }
+{ "_id" : "04982", "city" : "STRATTON", "loc" : [ -70.431928, 45.123197 ], "pop" : 262, "state" : "ME" }
+{ "_id" : "04983", "city" : "STRONG", "loc" : [ -70.222054, 44.82236 ], "pop" : 1631, "state" : "ME" }
+{ "_id" : "04984", "city" : "TEMPLE", "loc" : [ -70.24263500000001, 44.695417 ], "pop" : 560, "state" : "ME" }
+{ "_id" : "04985", "city" : "WEST FORKS", "loc" : [ -69.98405700000001, 45.383905 ], "pop" : 86, "state" : "ME" }
+{ "_id" : "04986", "city" : "THORNDIKE", "loc" : [ -69.24865800000001, 44.574406 ], "pop" : 962, "state" : "ME" }
+{ "_id" : "04987", "city" : "TROY", "loc" : [ -69.25488, 44.675657 ], "pop" : 802, "state" : "ME" }
+{ "_id" : "04988", "city" : "UNITY", "loc" : [ -69.332778, 44.600676 ], "pop" : 1817, "state" : "ME" }
+{ "_id" : "04989", "city" : "VASSALBORO", "loc" : [ -69.651904, 44.440455 ], "pop" : 1929, "state" : "ME" }
+{ "_id" : "05001", "city" : "WHITE RIVER JUNC", "loc" : [ -72.350351, 43.663431 ], "pop" : 9500, "state" : "VT" }
+{ "_id" : "05032", "city" : "BETHEL", "loc" : [ -72.652807, 43.819464 ], "pop" : 2725, "state" : "VT" }
+{ "_id" : "05033", "city" : "BRADFORD", "loc" : [ -72.140638, 44.0006 ], "pop" : 2480, "state" : "VT" }
+{ "_id" : "05034", "city" : "BRIDGEWATER", "loc" : [ -72.646704, 43.580428 ], "pop" : 130, "state" : "VT" }
+{ "_id" : "05035", "city" : "BRIDGEWATER CORN", "loc" : [ -72.68221200000001, 43.602147 ], "pop" : 662, "state" : "VT" }
+{ "_id" : "05036", "city" : "BROOKFIELD", "loc" : [ -72.595259, 44.032083 ], "pop" : 453, "state" : "VT" }
+{ "_id" : "05037", "city" : "BROWNSVILLE", "loc" : [ -72.494405, 43.464584 ], "pop" : 415, "state" : "VT" }
+{ "_id" : "05038", "city" : "CHELSEA", "loc" : [ -72.479303, 44.003931 ], "pop" : 1022, "state" : "VT" }
+{ "_id" : "05039", "city" : "CORINTH", "loc" : [ -72.282241, 44.032533 ], "pop" : 1035, "state" : "VT" }
+{ "_id" : "05040", "city" : "EAST CORINTH", "loc" : [ -72.215144, 44.061851 ], "pop" : 279, "state" : "VT" }
+{ "_id" : "05041", "city" : "EAST RANDOLPH", "loc" : [ -72.54874599999999, 43.955297 ], "pop" : 322, "state" : "VT" }
+{ "_id" : "05042", "city" : "RYEGATE", "loc" : [ -72.072669, 44.193453 ], "pop" : 328, "state" : "VT" }
+{ "_id" : "05043", "city" : "EAST THETFORD", "loc" : [ -72.19668, 43.825757 ], "pop" : 657, "state" : "VT" }
+{ "_id" : "05045", "city" : "FAIRLEE", "loc" : [ -72.190214, 43.90105 ], "pop" : 1631, "state" : "VT" }
+{ "_id" : "05046", "city" : "GROTON", "loc" : [ -72.21754799999999, 44.220435 ], "pop" : 862, "state" : "VT" }
+{ "_id" : "05048", "city" : "HARTLAND", "loc" : [ -72.41310300000001, 43.570764 ], "pop" : 1730, "state" : "VT" }
+{ "_id" : "05051", "city" : "NEWBURY", "loc" : [ -72.107231, 44.096555 ], "pop" : 1488, "state" : "VT" }
+{ "_id" : "05052", "city" : "NORTH HARTLAND", "loc" : [ -72.352591, 43.596721 ], "pop" : 429, "state" : "VT" }
+{ "_id" : "05053", "city" : "NORTH POMFRET", "loc" : [ -72.494287, 43.720401 ], "pop" : 254, "state" : "VT" }
+{ "_id" : "05055", "city" : "NORWICH", "loc" : [ -72.30162, 43.740373 ], "pop" : 2969, "state" : "VT" }
+{ "_id" : "05056", "city" : "PLYMOUTH", "loc" : [ -72.710655, 43.498653 ], "pop" : 319, "state" : "VT" }
+{ "_id" : "05058", "city" : "POST MILLS", "loc" : [ -72.26203099999999, 43.893288 ], "pop" : 511, "state" : "VT" }
+{ "_id" : "05060", "city" : "RANDOLPH", "loc" : [ -72.67258, 43.944399 ], "pop" : 4421, "state" : "VT" }
+{ "_id" : "05061", "city" : "RANDOLPH CENTER", "loc" : [ -72.596975, 43.9379 ], "pop" : 1567, "state" : "VT" }
+{ "_id" : "05062", "city" : "READING", "loc" : [ -72.570446, 43.47935 ], "pop" : 614, "state" : "VT" }
+{ "_id" : "05065", "city" : "SHARON", "loc" : [ -72.424283, 43.774843 ], "pop" : 599, "state" : "VT" }
+{ "_id" : "05067", "city" : "SOUTH POMFRET", "loc" : [ -72.534907, 43.679665 ], "pop" : 281, "state" : "VT" }
+{ "_id" : "05068", "city" : "SOUTH ROYALTON", "loc" : [ -72.523228, 43.808931 ], "pop" : 3169, "state" : "VT" }
+{ "_id" : "05069", "city" : "SOUTH RYEGATE", "loc" : [ -72.129558, 44.211075 ], "pop" : 730, "state" : "VT" }
+{ "_id" : "05070", "city" : "SOUTH STRAFFORD", "loc" : [ -72.36995899999999, 43.828238 ], "pop" : 331, "state" : "VT" }
+{ "_id" : "05071", "city" : "SOUTH WOODSTOCK", "loc" : [ -72.538383, 43.560137 ], "pop" : 406, "state" : "VT" }
+{ "_id" : "05072", "city" : "STRAFFORD", "loc" : [ -72.36363, 43.872306 ], "pop" : 554, "state" : "VT" }
+{ "_id" : "05073", "city" : "TAFTSVILLE", "loc" : [ -72.467331, 43.629819 ], "pop" : 35, "state" : "VT" }
+{ "_id" : "05075", "city" : "THETFORD CENTER", "loc" : [ -72.266204, 43.814883 ], "pop" : 1014, "state" : "VT" }
+{ "_id" : "05077", "city" : "TUNBRIDGE", "loc" : [ -72.478578, 43.9169 ], "pop" : 1352, "state" : "VT" }
+{ "_id" : "05079", "city" : "VERSHIRE", "loc" : [ -72.31901499999999, 43.961811 ], "pop" : 565, "state" : "VT" }
+{ "_id" : "05081", "city" : "WELLS RIVER", "loc" : [ -72.052958, 44.152438 ], "pop" : 473, "state" : "VT" }
+{ "_id" : "05083", "city" : "WEST FAIRLEE", "loc" : [ -72.26163, 43.92232 ], "pop" : 153, "state" : "VT" }
+{ "_id" : "05084", "city" : "WEST HARTFORD", "loc" : [ -72.44461800000001, 43.716068 ], "pop" : 135, "state" : "VT" }
+{ "_id" : "05086", "city" : "WEST TOPSHAM", "loc" : [ -72.270051, 44.119925 ], "pop" : 1050, "state" : "VT" }
+{ "_id" : "05089", "city" : "WINDSOR", "loc" : [ -72.41099800000001, 43.476032 ], "pop" : 5406, "state" : "VT" }
+{ "_id" : "05091", "city" : "WOODSTOCK", "loc" : [ -72.538455, 43.62482 ], "pop" : 3742, "state" : "VT" }
+{ "_id" : "05101", "city" : "BELLOWS FALLS", "loc" : [ -72.466373, 43.148198 ], "pop" : 5433, "state" : "VT" }
+{ "_id" : "05141", "city" : "CAMBRIDGEPORT", "loc" : [ -72.565511, 43.153363 ], "pop" : 118, "state" : "VT" }
+{ "_id" : "05142", "city" : "CAVENDISH", "loc" : [ -72.609247, 43.376621 ], "pop" : 258, "state" : "VT" }
+{ "_id" : "05143", "city" : "CHESTER", "loc" : [ -72.60312500000001, 43.283124 ], "pop" : 3449, "state" : "VT" }
+{ "_id" : "05146", "city" : "GRAFTON", "loc" : [ -72.597229, 43.160095 ], "pop" : 823, "state" : "VT" }
+{ "_id" : "05148", "city" : "BROMLEY MTN", "loc" : [ -72.801756, 43.223961 ], "pop" : 986, "state" : "VT" }
+{ "_id" : "05149", "city" : "LUDLOW", "loc" : [ -72.70018399999999, 43.392909 ], "pop" : 2420, "state" : "VT" }
+{ "_id" : "05150", "city" : "NORTH SPRINGFIEL", "loc" : [ -72.529096, 43.335452 ], "pop" : 824, "state" : "VT" }
+{ "_id" : "05151", "city" : "PERKINSVILLE", "loc" : [ -72.50381299999999, 43.387885 ], "pop" : 1181, "state" : "VT" }
+{ "_id" : "05152", "city" : "PERU", "loc" : [ -72.886797, 43.256532 ], "pop" : 458, "state" : "VT" }
+{ "_id" : "05153", "city" : "PROCTORSVILLE", "loc" : [ -72.61962, 43.4005 ], "pop" : 1065, "state" : "VT" }
+{ "_id" : "05154", "city" : "SAXTONS RIVER", "loc" : [ -72.508107, 43.137861 ], "pop" : 681, "state" : "VT" }
+{ "_id" : "05155", "city" : "SOUTH LONDONDERR", "loc" : [ -72.811787, 43.183082 ], "pop" : 546, "state" : "VT" }
+{ "_id" : "05156", "city" : "SPRINGFIELD", "loc" : [ -72.477769, 43.303433 ], "pop" : 9231, "state" : "VT" }
+{ "_id" : "05161", "city" : "WESTON", "loc" : [ -72.79352299999999, 43.29409 ], "pop" : 488, "state" : "VT" }
+{ "_id" : "05201", "city" : "BENNINGTON", "loc" : [ -73.19232100000001, 42.882658 ], "pop" : 14757, "state" : "VT" }
+{ "_id" : "05250", "city" : "ARLINGTON", "loc" : [ -73.159364, 43.085681 ], "pop" : 3006, "state" : "VT" }
+{ "_id" : "05251", "city" : "DORSET", "loc" : [ -73.07660300000001, 43.263561 ], "pop" : 1402, "state" : "VT" }
+{ "_id" : "05252", "city" : "EAST ARLINGTON", "loc" : [ -73.138904, 43.063801 ], "pop" : 443, "state" : "VT" }
+{ "_id" : "05253", "city" : "EAST DORSET", "loc" : [ -73.008146, 43.236982 ], "pop" : 516, "state" : "VT" }
+{ "_id" : "05255", "city" : "MANCHESTER CENTE", "loc" : [ -73.052313, 43.175223 ], "pop" : 3622, "state" : "VT" }
+{ "_id" : "05257", "city" : "NORTH BENNINGTON", "loc" : [ -73.237531, 42.92385 ], "pop" : 2037, "state" : "VT" }
+{ "_id" : "05260", "city" : "NORTH POWNAL", "loc" : [ -73.25342999999999, 42.809775 ], "pop" : 523, "state" : "VT" }
+{ "_id" : "05261", "city" : "POWNAL", "loc" : [ -73.21624, 42.787955 ], "pop" : 2962, "state" : "VT" }
+{ "_id" : "05262", "city" : "SHAFTSBURY", "loc" : [ -73.21659099999999, 42.96144 ], "pop" : 3363, "state" : "VT" }
+{ "_id" : "05301", "city" : "BRATTLEBORO", "loc" : [ -72.593322, 42.857353 ], "pop" : 17522, "state" : "VT" }
+{ "_id" : "05340", "city" : "BONDVILLE", "loc" : [ -72.912768, 43.161831 ], "pop" : 482, "state" : "VT" }
+{ "_id" : "05341", "city" : "EAST DOVER", "loc" : [ -72.78303200000001, 42.950508 ], "pop" : 253, "state" : "VT" }
+{ "_id" : "05342", "city" : "JACKSONVILLE", "loc" : [ -72.807121, 42.777752 ], "pop" : 406, "state" : "VT" }
+{ "_id" : "05343", "city" : "JAMAICA", "loc" : [ -72.794409, 43.104235 ], "pop" : 603, "state" : "VT" }
+{ "_id" : "05345", "city" : "NEWFANE", "loc" : [ -72.678078, 42.97043 ], "pop" : 1389, "state" : "VT" }
+{ "_id" : "05346", "city" : "PUTNEY", "loc" : [ -72.512272, 43.035561 ], "pop" : 4971, "state" : "VT" }
+{ "_id" : "05350", "city" : "READSBORO", "loc" : [ -72.960886, 42.78367 ], "pop" : 762, "state" : "VT" }
+{ "_id" : "05352", "city" : "STAMFORD", "loc" : [ -73.069068, 42.76962 ], "pop" : 773, "state" : "VT" }
+{ "_id" : "05353", "city" : "TOWNSHEND", "loc" : [ -72.668676, 43.062174 ], "pop" : 920, "state" : "VT" }
+{ "_id" : "05354", "city" : "VERNON", "loc" : [ -72.51154699999999, 42.756468 ], "pop" : 1850, "state" : "VT" }
+{ "_id" : "05355", "city" : "WARDSBORO", "loc" : [ -72.807687, 43.032649 ], "pop" : 573, "state" : "VT" }
+{ "_id" : "05356", "city" : "MOUNT SNOW", "loc" : [ -72.854235, 42.956029 ], "pop" : 743, "state" : "VT" }
+{ "_id" : "05358", "city" : "WEST HALIFAX", "loc" : [ -72.750142, 42.776103 ], "pop" : 202, "state" : "VT" }
+{ "_id" : "05359", "city" : "WEST TOWNSHEND", "loc" : [ -72.720985, 43.130044 ], "pop" : 402, "state" : "VT" }
+{ "_id" : "05360", "city" : "WEST WARDSBORO", "loc" : [ -72.880537, 43.047221 ], "pop" : 228, "state" : "VT" }
+{ "_id" : "05361", "city" : "WHITINGHAM", "loc" : [ -72.85600100000001, 42.790071 ], "pop" : 921, "state" : "VT" }
+{ "_id" : "05362", "city" : "WILLIAMSVILLE", "loc" : [ -72.658406, 42.948151 ], "pop" : 166, "state" : "VT" }
+{ "_id" : "05363", "city" : "WILMINGTON", "loc" : [ -72.861316, 42.881216 ], "pop" : 2053, "state" : "VT" }
+{ "_id" : "05401", "city" : "BURLINGTON", "loc" : [ -73.219875, 44.484023 ], "pop" : 39127, "state" : "VT" }
+{ "_id" : "05403", "city" : "SOUTH BURLINGTON", "loc" : [ -73.17961699999999, 44.451324 ], "pop" : 12809, "state" : "VT" }
+{ "_id" : "05404", "city" : "WINOOSKI", "loc" : [ -73.18741300000001, 44.494898 ], "pop" : 6649, "state" : "VT" }
+{ "_id" : "05405", "city" : "UNIV OF VERMONT", "loc" : [ -73.2002, 44.477733 ], "pop" : 0, "state" : "VT" }
+{ "_id" : "05440", "city" : "ALBURG", "loc" : [ -73.280963, 44.968454 ], "pop" : 1362, "state" : "VT" }
+{ "_id" : "05441", "city" : "BAKERSFIELD", "loc" : [ -72.796834, 44.790518 ], "pop" : 973, "state" : "VT" }
+{ "_id" : "05443", "city" : "BRISTOL", "loc" : [ -73.071742, 44.146031 ], "pop" : 6685, "state" : "VT" }
+{ "_id" : "05444", "city" : "CAMBRIDGE", "loc" : [ -72.865728, 44.651013 ], "pop" : 3491, "state" : "VT" }
+{ "_id" : "05445", "city" : "CHARLOTTE", "loc" : [ -73.227969, 44.311277 ], "pop" : 3009, "state" : "VT" }
+{ "_id" : "05446", "city" : "COLCHESTER", "loc" : [ -73.20221600000001, 44.535956 ], "pop" : 14731, "state" : "VT" }
+{ "_id" : "05447", "city" : "EAST BERKSHIRE", "loc" : [ -72.706564, 44.929798 ], "pop" : 94, "state" : "VT" }
+{ "_id" : "05448", "city" : "EAST FAIRFIELD", "loc" : [ -72.910995, 44.801805 ], "pop" : 1076, "state" : "VT" }
+{ "_id" : "05450", "city" : "ENOSBURG FALLS", "loc" : [ -72.791037, 44.898491 ], "pop" : 2268, "state" : "VT" }
+{ "_id" : "05452", "city" : "ESSEX JUNCTION", "loc" : [ -73.090644, 44.503466 ], "pop" : 17050, "state" : "VT" }
+{ "_id" : "05454", "city" : "FAIRFAX", "loc" : [ -73.024078, 44.692387 ], "pop" : 2990, "state" : "VT" }
+{ "_id" : "05455", "city" : "FAIRFIELD", "loc" : [ -73.022187, 44.784087 ], "pop" : 359, "state" : "VT" }
+{ "_id" : "05456", "city" : "FERRISBURG", "loc" : [ -73.25857499999999, 44.212822 ], "pop" : 951, "state" : "VT" }
+{ "_id" : "05457", "city" : "FRANKLIN", "loc" : [ -72.903694, 44.961408 ], "pop" : 1475, "state" : "VT" }
+{ "_id" : "05458", "city" : "GRAND ISLE", "loc" : [ -73.30561, 44.719711 ], "pop" : 1590, "state" : "VT" }
+{ "_id" : "05459", "city" : "HIGHGATE CENTER", "loc" : [ -73.015468, 44.940395 ], "pop" : 1567, "state" : "VT" }
+{ "_id" : "05461", "city" : "HINESBURG", "loc" : [ -73.097955, 44.334621 ], "pop" : 3187, "state" : "VT" }
+{ "_id" : "05462", "city" : "HUNTINGTON", "loc" : [ -72.996432, 44.322655 ], "pop" : 2223, "state" : "VT" }
+{ "_id" : "05463", "city" : "ISLE LA MOTTE", "loc" : [ -73.339095, 44.874829 ], "pop" : 408, "state" : "VT" }
+{ "_id" : "05464", "city" : "SMUGGLERS NOTCH", "loc" : [ -72.78057699999999, 44.662499 ], "pop" : 300, "state" : "VT" }
+{ "_id" : "05465", "city" : "JERICHO CENTER", "loc" : [ -72.979398, 44.484318 ], "pop" : 3449, "state" : "VT" }
+{ "_id" : "05468", "city" : "MILTON", "loc" : [ -73.131692, 44.648275 ], "pop" : 10627, "state" : "VT" }
+{ "_id" : "05471", "city" : "MONTGOMERY CENTE", "loc" : [ -72.599352, 44.874606 ], "pop" : 603, "state" : "VT" }
+{ "_id" : "05472", "city" : "NEW HAVEN", "loc" : [ -73.17346999999999, 44.112575 ], "pop" : 858, "state" : "VT" }
+{ "_id" : "05473", "city" : "NORTH FERRISBURG", "loc" : [ -73.203254, 44.251461 ], "pop" : 1126, "state" : "VT" }
+{ "_id" : "05474", "city" : "NORTH HERO", "loc" : [ -73.28416900000001, 44.829392 ], "pop" : 502, "state" : "VT" }
+{ "_id" : "05476", "city" : "RICHFORD", "loc" : [ -72.690472, 44.971453 ], "pop" : 3794, "state" : "VT" }
+{ "_id" : "05477", "city" : "BOLTON VALLEY", "loc" : [ -72.993256, 44.399846 ], "pop" : 3758, "state" : "VT" }
+{ "_id" : "05478", "city" : "SAINT ALBANS", "loc" : [ -73.08902500000001, 44.811138 ], "pop" : 13555, "state" : "VT" }
+{ "_id" : "05482", "city" : "SHELBURNE", "loc" : [ -73.217124, 44.389967 ], "pop" : 5871, "state" : "VT" }
+{ "_id" : "05483", "city" : "SHELDON", "loc" : [ -72.952989, 44.887167 ], "pop" : 1556, "state" : "VT" }
+{ "_id" : "05486", "city" : "SOUTH HERO", "loc" : [ -73.31134400000001, 44.640044 ], "pop" : 1456, "state" : "VT" }
+{ "_id" : "05487", "city" : "STARKSBORO", "loc" : [ -73.0157, 44.2261 ], "pop" : 1020, "state" : "VT" }
+{ "_id" : "05488", "city" : "SWANTON", "loc" : [ -73.12112399999999, 44.916754 ], "pop" : 6570, "state" : "VT" }
+{ "_id" : "05489", "city" : "UNDERHILL", "loc" : [ -72.925845, 44.539069 ], "pop" : 3637, "state" : "VT" }
+{ "_id" : "05491", "city" : "VERGENNES", "loc" : [ -73.279293, 44.132569 ], "pop" : 6041, "state" : "VT" }
+{ "_id" : "05492", "city" : "WATERVILLE", "loc" : [ -72.759557, 44.712375 ], "pop" : 532, "state" : "VT" }
+{ "_id" : "05494", "city" : "WESTFORD", "loc" : [ -73.006021, 44.618191 ], "pop" : 1102, "state" : "VT" }
+{ "_id" : "05495", "city" : "WILLISTON", "loc" : [ -73.095704, 44.436745 ], "pop" : 5592, "state" : "VT" }
+{ "_id" : "05602", "city" : "MONTPELIER", "loc" : [ -72.576992, 44.264082 ], "pop" : 12475, "state" : "VT" }
+{ "_id" : "05640", "city" : "ADAMANT", "loc" : [ -72.504649, 44.35747 ], "pop" : 456, "state" : "VT" }
+{ "_id" : "05641", "city" : "BARRE", "loc" : [ -72.493619, 44.194522 ], "pop" : 14994, "state" : "VT" }
+{ "_id" : "05647", "city" : "CABOT", "loc" : [ -72.306443, 44.404215 ], "pop" : 1043, "state" : "VT" }
+{ "_id" : "05648", "city" : "CALAIS", "loc" : [ -72.474113, 44.393438 ], "pop" : 319, "state" : "VT" }
+{ "_id" : "05649", "city" : "EAST BARRE", "loc" : [ -72.446003, 44.158277 ], "pop" : 381, "state" : "VT" }
+{ "_id" : "05650", "city" : "EAST CALAIS", "loc" : [ -72.439829, 44.355599 ], "pop" : 746, "state" : "VT" }
+{ "_id" : "05651", "city" : "EAST MONTPELIER", "loc" : [ -72.492636, 44.282844 ], "pop" : 1018, "state" : "VT" }
+{ "_id" : "05652", "city" : "EDEN", "loc" : [ -72.58629999999999, 44.734267 ], "pop" : 913, "state" : "VT" }
+{ "_id" : "05653", "city" : "EDEN MILLS", "loc" : [ -72.513447, 44.693123 ], "pop" : 155, "state" : "VT" }
+{ "_id" : "05654", "city" : "GRANITEVILLE", "loc" : [ -72.48452899999999, 44.157326 ], "pop" : 2321, "state" : "VT" }
+{ "_id" : "05655", "city" : "HYDE PARK", "loc" : [ -72.594971, 44.622453 ], "pop" : 2094, "state" : "VT" }
+{ "_id" : "05656", "city" : "JOHNSON", "loc" : [ -72.671154, 44.64204 ], "pop" : 3156, "state" : "VT" }
+{ "_id" : "05658", "city" : "MARSHFIELD", "loc" : [ -72.374994, 44.321841 ], "pop" : 1331, "state" : "VT" }
+{ "_id" : "05660", "city" : "MORETOWN", "loc" : [ -72.74939500000001, 44.259602 ], "pop" : 1896, "state" : "VT" }
+{ "_id" : "05661", "city" : "MORRISVILLE", "loc" : [ -72.602625, 44.554335 ], "pop" : 4935, "state" : "VT" }
+{ "_id" : "05663", "city" : "RIVERTON", "loc" : [ -72.659795, 44.149961 ], "pop" : 6245, "state" : "VT" }
+{ "_id" : "05666", "city" : "NORTH MONTPELIER", "loc" : [ -72.482119, 44.256612 ], "pop" : 469, "state" : "VT" }
+{ "_id" : "05667", "city" : "PLAINFIELD", "loc" : [ -72.42243000000001, 44.262164 ], "pop" : 1304, "state" : "VT" }
+{ "_id" : "05669", "city" : "ROXBURY", "loc" : [ -72.720151, 44.084571 ], "pop" : 575, "state" : "VT" }
+{ "_id" : "05672", "city" : "STOWE", "loc" : [ -72.69228200000001, 44.469512 ], "pop" : 3433, "state" : "VT" }
+{ "_id" : "05673", "city" : "WAITSFIELD", "loc" : [ -72.828321, 44.188917 ], "pop" : 1751, "state" : "VT" }
+{ "_id" : "05674", "city" : "SUGARBUSH VALLEY", "loc" : [ -72.848179, 44.114222 ], "pop" : 1172, "state" : "VT" }
+{ "_id" : "05675", "city" : "WASHGTIN", "loc" : [ -72.430002, 44.086448 ], "pop" : 1022, "state" : "VT" }
+{ "_id" : "05676", "city" : "WATERBURY", "loc" : [ -72.779768, 44.345103 ], "pop" : 4751, "state" : "VT" }
+{ "_id" : "05677", "city" : "WATERBURY CENTER", "loc" : [ -72.708006, 44.382797 ], "pop" : 1645, "state" : "VT" }
+{ "_id" : "05679", "city" : "WILLIAMSTOWN", "loc" : [ -72.53811, 44.118191 ], "pop" : 2964, "state" : "VT" }
+{ "_id" : "05680", "city" : "WOLCOTT", "loc" : [ -72.484416, 44.555753 ], "pop" : 1850, "state" : "VT" }
+{ "_id" : "05681", "city" : "WOODBURY", "loc" : [ -72.417766, 44.432507 ], "pop" : 766, "state" : "VT" }
+{ "_id" : "05682", "city" : "WORCESTER", "loc" : [ -72.560925, 44.394389 ], "pop" : 906, "state" : "VT" }
+{ "_id" : "05701", "city" : "RUTLAND", "loc" : [ -72.97077299999999, 43.614131 ], "pop" : 22576, "state" : "VT" }
+{ "_id" : "05730", "city" : "BELMONT", "loc" : [ -72.825701, 43.428441 ], "pop" : 223, "state" : "VT" }
+{ "_id" : "05732", "city" : "HUBBARDTON", "loc" : [ -73.206424, 43.622413 ], "pop" : 914, "state" : "VT" }
+{ "_id" : "05733", "city" : "BRANDON", "loc" : [ -73.088182, 43.806467 ], "pop" : 5027, "state" : "VT" }
+{ "_id" : "05734", "city" : "BRIDPORT", "loc" : [ -73.34755699999999, 43.95383 ], "pop" : 641, "state" : "VT" }
+{ "_id" : "05735", "city" : "CASTLETON", "loc" : [ -73.17079699999999, 43.622312 ], "pop" : 2897, "state" : "VT" }
+{ "_id" : "05736", "city" : "CENTER RUTLAND", "loc" : [ -73.016986, 43.602345 ], "pop" : 299, "state" : "VT" }
+{ "_id" : "05737", "city" : "CHITTENDEN", "loc" : [ -72.936001, 43.703382 ], "pop" : 526, "state" : "VT" }
+{ "_id" : "05738", "city" : "CUTTINGSVILLE", "loc" : [ -72.869089, 43.522084 ], "pop" : 1101, "state" : "VT" }
+{ "_id" : "05739", "city" : "DANBY", "loc" : [ -73.01285, 43.358341 ], "pop" : 1170, "state" : "VT" }
+{ "_id" : "05742", "city" : "EAST WALLINGFORD", "loc" : [ -72.88437500000001, 43.446063 ], "pop" : 588, "state" : "VT" }
+{ "_id" : "05743", "city" : "FAIR HAVEN", "loc" : [ -73.27006799999999, 43.62345 ], "pop" : 4283, "state" : "VT" }
+{ "_id" : "05744", "city" : "FLORENCE", "loc" : [ -73.078988, 43.709294 ], "pop" : 257, "state" : "VT" }
+{ "_id" : "05746", "city" : "GAYSVILLE", "loc" : [ -72.731149, 43.752912 ], "pop" : 198, "state" : "VT" }
+{ "_id" : "05747", "city" : "GRANVILLE", "loc" : [ -72.8245, 43.984912 ], "pop" : 309, "state" : "VT" }
+{ "_id" : "05748", "city" : "HANCOCK", "loc" : [ -72.913285, 43.912525 ], "pop" : 98, "state" : "VT" }
+{ "_id" : "05751", "city" : "KILLINGTON", "loc" : [ -72.79631000000001, 43.663364 ], "pop" : 738, "state" : "VT" }
+{ "_id" : "05753", "city" : "BREAD LOAF", "loc" : [ -73.16613, 44.007042 ], "pop" : 9990, "state" : "VT" }
+{ "_id" : "05757", "city" : "MIDDLETOWN SPRIN", "loc" : [ -73.11452, 43.484864 ], "pop" : 966, "state" : "VT" }
+{ "_id" : "05758", "city" : "MOUNT HOLLY", "loc" : [ -72.795562, 43.44865 ], "pop" : 693, "state" : "VT" }
+{ "_id" : "05759", "city" : "NORTH CLARENDON", "loc" : [ -72.956096, 43.552208 ], "pop" : 2517, "state" : "VT" }
+{ "_id" : "05760", "city" : "ORWELL", "loc" : [ -73.294855, 43.783722 ], "pop" : 1315, "state" : "VT" }
+{ "_id" : "05761", "city" : "PAWLET", "loc" : [ -73.14440399999999, 43.358679 ], "pop" : 935, "state" : "VT" }
+{ "_id" : "05762", "city" : "PITTSFIELD", "loc" : [ -72.853376, 43.753823 ], "pop" : 450, "state" : "VT" }
+{ "_id" : "05763", "city" : "PITTSFORD", "loc" : [ -73.013492, 43.71524 ], "pop" : 2864, "state" : "VT" }
+{ "_id" : "05764", "city" : "POULTNEY", "loc" : [ -73.225281, 43.53321 ], "pop" : 4012, "state" : "VT" }
+{ "_id" : "05765", "city" : "PROCTOR", "loc" : [ -73.03481600000001, 43.657951 ], "pop" : 1868, "state" : "VT" }
+{ "_id" : "05766", "city" : "RIPTON", "loc" : [ -73.01873999999999, 43.992862 ], "pop" : 433, "state" : "VT" }
+{ "_id" : "05767", "city" : "ROCHESTER", "loc" : [ -72.815917, 43.880382 ], "pop" : 1551, "state" : "VT" }
+{ "_id" : "05769", "city" : "SALISBURY", "loc" : [ -73.100793, 43.90172 ], "pop" : 1885, "state" : "VT" }
+{ "_id" : "05770", "city" : "SHOREHAM", "loc" : [ -73.305385, 43.886214 ], "pop" : 946, "state" : "VT" }
+{ "_id" : "05772", "city" : "STOCKBRIDGE", "loc" : [ -72.78139400000001, 43.773808 ], "pop" : 124, "state" : "VT" }
+{ "_id" : "05773", "city" : "WALLINGFORD", "loc" : [ -72.98772200000001, 43.4573 ], "pop" : 2172, "state" : "VT" }
+{ "_id" : "05774", "city" : "WELLS", "loc" : [ -73.202684, 43.430456 ], "pop" : 837, "state" : "VT" }
+{ "_id" : "05775", "city" : "WEST PAWLET", "loc" : [ -73.23132699999999, 43.36673 ], "pop" : 604, "state" : "VT" }
+{ "_id" : "05776", "city" : "WEST RUPERT", "loc" : [ -73.20284700000001, 43.261792 ], "pop" : 654, "state" : "VT" }
+{ "_id" : "05777", "city" : "WEST RUTLAND", "loc" : [ -73.04242000000001, 43.578072 ], "pop" : 3415, "state" : "VT" }
+{ "_id" : "05778", "city" : "LEICESTER JUNCTI", "loc" : [ -73.213312, 43.874972 ], "pop" : 615, "state" : "VT" }
+{ "_id" : "05819", "city" : "SAINT JOHNSBURY", "loc" : [ -72.005062, 44.427195 ], "pop" : 8797, "state" : "VT" }
+{ "_id" : "05820", "city" : "ALBANY", "loc" : [ -72.34181, 44.734427 ], "pop" : 782, "state" : "VT" }
+{ "_id" : "05821", "city" : "BARNET", "loc" : [ -72.078326, 44.317923 ], "pop" : 1415, "state" : "VT" }
+{ "_id" : "05822", "city" : "BARTON", "loc" : [ -72.160005, 44.739465 ], "pop" : 1270, "state" : "VT" }
+{ "_id" : "05824", "city" : "CONCORD", "loc" : [ -71.867554, 44.446055 ], "pop" : 1242, "state" : "VT" }
+{ "_id" : "05825", "city" : "COVENTRY", "loc" : [ -72.254471, 44.880853 ], "pop" : 722, "state" : "VT" }
+{ "_id" : "05826", "city" : "CRAFTSBURY", "loc" : [ -72.366007, 44.64341 ], "pop" : 623, "state" : "VT" }
+{ "_id" : "05827", "city" : "CRAFTSBURY COMMO", "loc" : [ -72.41457800000001, 44.652917 ], "pop" : 399, "state" : "VT" }
+{ "_id" : "05828", "city" : "DANVILLE", "loc" : [ -72.113319, 44.433241 ], "pop" : 1482, "state" : "VT" }
+{ "_id" : "05829", "city" : "DERBY", "loc" : [ -72.13755500000001, 44.950182 ], "pop" : 2607, "state" : "VT" }
+{ "_id" : "05830", "city" : "DERBY LINE", "loc" : [ -72.082367, 44.990183 ], "pop" : 2040, "state" : "VT" }
+{ "_id" : "05832", "city" : "EAST BURKE", "loc" : [ -71.93567400000001, 44.607849 ], "pop" : 875, "state" : "VT" }
+{ "_id" : "05833", "city" : "EAST CHARLESTON", "loc" : [ -71.97627, 44.829896 ], "pop" : 246, "state" : "VT" }
+{ "_id" : "05836", "city" : "EAST HARDWICK", "loc" : [ -72.30335100000001, 44.528833 ], "pop" : 493, "state" : "VT" }
+{ "_id" : "05837", "city" : "EAST HAVEN", "loc" : [ -71.867491, 44.651724 ], "pop" : 269, "state" : "VT" }
+{ "_id" : "05839", "city" : "GLOVER", "loc" : [ -72.203819, 44.719979 ], "pop" : 795, "state" : "VT" }
+{ "_id" : "05841", "city" : "GREENSBORO", "loc" : [ -72.285017, 44.595069 ], "pop" : 461, "state" : "VT" }
+{ "_id" : "05842", "city" : "GREENSBORO BEND", "loc" : [ -72.252478, 44.548488 ], "pop" : 405, "state" : "VT" }
+{ "_id" : "05843", "city" : "HARDWICK", "loc" : [ -72.36381799999999, 44.507026 ], "pop" : 2450, "state" : "VT" }
+{ "_id" : "05845", "city" : "IRASBURG", "loc" : [ -72.276269, 44.808056 ], "pop" : 907, "state" : "VT" }
+{ "_id" : "05846", "city" : "ISLAND POND", "loc" : [ -71.88396400000001, 44.809452 ], "pop" : 1585, "state" : "VT" }
+{ "_id" : "05847", "city" : "LOWELL", "loc" : [ -72.450132, 44.796107 ], "pop" : 594, "state" : "VT" }
+{ "_id" : "05850", "city" : "LYNDON CENTER", "loc" : [ -72.03106200000001, 44.54719 ], "pop" : 519, "state" : "VT" }
+{ "_id" : "05851", "city" : "LYNDONVILLE", "loc" : [ -72.009168, 44.540766 ], "pop" : 5417, "state" : "VT" }
+{ "_id" : "05853", "city" : "MORGAN CTR", "loc" : [ -71.994052, 44.90659 ], "pop" : 497, "state" : "VT" }
+{ "_id" : "05855", "city" : "NEWPORT", "loc" : [ -72.20650500000001, 44.939344 ], "pop" : 4773, "state" : "VT" }
+{ "_id" : "05857", "city" : "NEWPORT CENTER", "loc" : [ -72.29741199999999, 44.944175 ], "pop" : 1367, "state" : "VT" }
+{ "_id" : "05858", "city" : "NORTH CONCORD", "loc" : [ -71.78666200000001, 44.550099 ], "pop" : 191, "state" : "VT" }
+{ "_id" : "05859", "city" : "JAY PEAK", "loc" : [ -72.45723099999999, 44.961861 ], "pop" : 370, "state" : "VT" }
+{ "_id" : "05860", "city" : "ORLEANS", "loc" : [ -72.165328, 44.80544 ], "pop" : 2467, "state" : "VT" }
+{ "_id" : "05862", "city" : "PEACHAM", "loc" : [ -72.17703899999999, 44.335563 ], "pop" : 627, "state" : "VT" }
+{ "_id" : "05866", "city" : "SHEFFIELD", "loc" : [ -72.12392699999999, 44.61784 ], "pop" : 600, "state" : "VT" }
+{ "_id" : "05867", "city" : "SUTTON", "loc" : [ -72.02113300000001, 44.646543 ], "pop" : 854, "state" : "VT" }
+{ "_id" : "05868", "city" : "TROY", "loc" : [ -72.39380800000001, 44.959381 ], "pop" : 1609, "state" : "VT" }
+{ "_id" : "05871", "city" : "WEST BURKE", "loc" : [ -71.95717999999999, 44.663647 ], "pop" : 885, "state" : "VT" }
+{ "_id" : "05872", "city" : "WEST CHARLESTON", "loc" : [ -72.05209000000001, 44.872894 ], "pop" : 598, "state" : "VT" }
+{ "_id" : "05873", "city" : "WEST DANVILLE", "loc" : [ -72.21977099999999, 44.446509 ], "pop" : 1130, "state" : "VT" }
+{ "_id" : "05874", "city" : "WESTFIELD", "loc" : [ -72.439628, 44.882457 ], "pop" : 398, "state" : "VT" }
+{ "_id" : "05875", "city" : "WEST GLOVER", "loc" : [ -72.259936, 44.703145 ], "pop" : 265, "state" : "VT" }
+{ "_id" : "05901", "city" : "AVERILL", "loc" : [ -71.70026799999999, 44.992304 ], "pop" : 7, "state" : "VT" }
+{ "_id" : "05902", "city" : "BEECHER FALLS", "loc" : [ -71.519901, 45.006103 ], "pop" : 579, "state" : "VT" }
+{ "_id" : "05903", "city" : "CANAAN", "loc" : [ -71.560214, 44.976439 ], "pop" : 542, "state" : "VT" }
+{ "_id" : "05904", "city" : "GILMAN", "loc" : [ -71.71786, 44.413985 ], "pop" : 322, "state" : "VT" }
+{ "_id" : "05905", "city" : "GUILDHALL", "loc" : [ -71.599057, 44.690218 ], "pop" : 848, "state" : "VT" }
+{ "_id" : "05906", "city" : "LUNENBURG", "loc" : [ -71.69304, 44.466262 ], "pop" : 854, "state" : "VT" }
+{ "_id" : "05907", "city" : "NORTON", "loc" : [ -71.78843999999999, 44.988781 ], "pop" : 171, "state" : "VT" }
+{ "_id" : "06001", "city" : "AVON", "loc" : [ -72.865323, 41.790498 ], "pop" : 13988, "state" : "CT" }
+{ "_id" : "06002", "city" : "BLOOMFIELD", "loc" : [ -72.72493, 41.831647 ], "pop" : 19524, "state" : "CT" }
+{ "_id" : "06010", "city" : "BRISTOL", "loc" : [ -72.930193, 41.682293 ], "pop" : 60670, "state" : "CT" }
+{ "_id" : "06013", "city" : "BURLINGTON", "loc" : [ -72.94438599999999, 41.757296 ], "pop" : 7017, "state" : "CT" }
+{ "_id" : "06016", "city" : "WINDSORVILLE", "loc" : [ -72.543667, 41.911405 ], "pop" : 5067, "state" : "CT" }
+{ "_id" : "06018", "city" : "CANAAN", "loc" : [ -73.323177, 42.024821 ], "pop" : 2948, "state" : "CT" }
+{ "_id" : "06019", "city" : "CANTON", "loc" : [ -72.898731, 41.838401 ], "pop" : 4125, "state" : "CT" }
+{ "_id" : "06020", "city" : "CANTON CENTER", "loc" : [ -72.90584699999999, 41.871586 ], "pop" : 192, "state" : "CT" }
+{ "_id" : "06021", "city" : "COLEBROOK", "loc" : [ -73.104069, 42.028217 ], "pop" : 203, "state" : "CT" }
+{ "_id" : "06022", "city" : "COLLINSVILLE", "loc" : [ -72.92827, 41.851319 ], "pop" : 4630, "state" : "CT" }
+{ "_id" : "06023", "city" : "EAST BERLIN", "loc" : [ -72.719007, 41.61277 ], "pop" : 1021, "state" : "CT" }
+{ "_id" : "06024", "city" : "EAST CANAAN", "loc" : [ -73.278462, 42.011686 ], "pop" : 519, "state" : "CT" }
+{ "_id" : "06026", "city" : "EAST GRANBY", "loc" : [ -72.74588900000001, 41.932215 ], "pop" : 4301, "state" : "CT" }
+{ "_id" : "06027", "city" : "EAST HARTLAND", "loc" : [ -72.92421299999999, 42.001617 ], "pop" : 1833, "state" : "CT" }
+{ "_id" : "06029", "city" : "ELLINGTON", "loc" : [ -72.462599, 41.911417 ], "pop" : 9070, "state" : "CT" }
+{ "_id" : "06031", "city" : "FALLS VILLAGE", "loc" : [ -73.351659, 41.95784 ], "pop" : 1192, "state" : "CT" }
+{ "_id" : "06032", "city" : "FARMINGTON", "loc" : [ -72.841476, 41.72839 ], "pop" : 14953, "state" : "CT" }
+{ "_id" : "06033", "city" : "GLASTONBURY", "loc" : [ -72.572705, 41.707329 ], "pop" : 24287, "state" : "CT" }
+{ "_id" : "06035", "city" : "GRANBY", "loc" : [ -72.79937700000001, 41.960227 ], "pop" : 6939, "state" : "CT" }
+{ "_id" : "06037", "city" : "BERLIN", "loc" : [ -72.770482, 41.620826 ], "pop" : 15755, "state" : "CT" }
+{ "_id" : "06039", "city" : "LAKEVILLE", "loc" : [ -73.43765999999999, 41.951631 ], "pop" : 2086, "state" : "CT" }
+{ "_id" : "06040", "city" : "MANCHESTER", "loc" : [ -72.52444, 41.777732 ], "pop" : 51618, "state" : "CT" }
+{ "_id" : "06043", "city" : "BOLTON", "loc" : [ -72.43958000000001, 41.768888 ], "pop" : 4569, "state" : "CT" }
+{ "_id" : "06051", "city" : "NEW BRITAIN", "loc" : [ -72.77220800000001, 41.666683 ], "pop" : 28705, "state" : "CT" }
+{ "_id" : "06052", "city" : "NEW BRITAIN", "loc" : [ -72.798858, 41.658792 ], "pop" : 8798, "state" : "CT" }
+{ "_id" : "06053", "city" : "NEW BRITAIN", "loc" : [ -72.790835, 41.686667 ], "pop" : 37995, "state" : "CT" }
+{ "_id" : "06057", "city" : "NEW HARTFORD", "loc" : [ -73.010369, 41.846797 ], "pop" : 4521, "state" : "CT" }
+{ "_id" : "06058", "city" : "NORFOLK", "loc" : [ -73.199197, 41.985386 ], "pop" : 2060, "state" : "CT" }
+{ "_id" : "06059", "city" : "NORTH CANTON", "loc" : [ -72.90414, 41.923516 ], "pop" : 783, "state" : "CT" }
+{ "_id" : "06060", "city" : "NORTH GRANBY", "loc" : [ -72.84093799999999, 42.021925 ], "pop" : 1455, "state" : "CT" }
+{ "_id" : "06062", "city" : "PLAINVILLE", "loc" : [ -72.864373, 41.672653 ], "pop" : 17320, "state" : "CT" }
+{ "_id" : "06063", "city" : "PLEASANT VALLEY", "loc" : [ -72.982675, 41.924873 ], "pop" : 838, "state" : "CT" }
+{ "_id" : "06065", "city" : "RIVERTON", "loc" : [ -73.025469, 41.961395 ], "pop" : 155, "state" : "CT" }
+{ "_id" : "06066", "city" : "VERNON ROCKVILLE", "loc" : [ -72.464855, 41.850073 ], "pop" : 31966, "state" : "CT" }
+{ "_id" : "06067", "city" : "ROCKY HILL", "loc" : [ -72.663197, 41.658295 ], "pop" : 16638, "state" : "CT" }
+{ "_id" : "06068", "city" : "SALISBURY", "loc" : [ -73.421492, 42.001452 ], "pop" : 1686, "state" : "CT" }
+{ "_id" : "06069", "city" : "SHARON", "loc" : [ -73.457758, 41.871446 ], "pop" : 2794, "state" : "CT" }
+{ "_id" : "06070", "city" : "SIMSBURY", "loc" : [ -72.82126700000001, 41.873712 ], "pop" : 14589, "state" : "CT" }
+{ "_id" : "06071", "city" : "SOMERS", "loc" : [ -72.45826599999999, 41.997813 ], "pop" : 9685, "state" : "CT" }
+{ "_id" : "06073", "city" : "SOUTH GLASTONBUR", "loc" : [ -72.55430800000001, 41.660682 ], "pop" : 3614, "state" : "CT" }
+{ "_id" : "06074", "city" : "SOUTH WINDSOR", "loc" : [ -72.557585, 41.834081 ], "pop" : 22090, "state" : "CT" }
+{ "_id" : "06076", "city" : "STAFFORD SPRINGS", "loc" : [ -72.289857, 41.966127 ], "pop" : 12392, "state" : "CT" }
+{ "_id" : "06078", "city" : "SUFFIELD", "loc" : [ -72.641997, 41.990029 ], "pop" : 8518, "state" : "CT" }
+{ "_id" : "06081", "city" : "TARIFFVILLE", "loc" : [ -72.767786, 41.907715 ], "pop" : 1477, "state" : "CT" }
+{ "_id" : "06082", "city" : "ENFIELD", "loc" : [ -72.565218, 41.989016 ], "pop" : 45558, "state" : "CT" }
+{ "_id" : "06084", "city" : "TOLLAND", "loc" : [ -72.37178900000001, 41.869647 ], "pop" : 10973, "state" : "CT" }
+{ "_id" : "06085", "city" : "UNIONVILLE", "loc" : [ -72.887406, 41.747711 ], "pop" : 5604, "state" : "CT" }
+{ "_id" : "06088", "city" : "EAST WINDSOR", "loc" : [ -72.60294500000001, 41.9099 ], "pop" : 4988, "state" : "CT" }
+{ "_id" : "06089", "city" : "WEATOGUE", "loc" : [ -72.825254, 41.837152 ], "pop" : 2308, "state" : "CT" }
+{ "_id" : "06090", "city" : "WEST GRANBY", "loc" : [ -72.855496, 41.965509 ], "pop" : 948, "state" : "CT" }
+{ "_id" : "06092", "city" : "WEST SIMSBURY", "loc" : [ -72.857749, 41.871797 ], "pop" : 3691, "state" : "CT" }
+{ "_id" : "06093", "city" : "WEST SUFFIELD", "loc" : [ -72.736232, 42.011464 ], "pop" : 2912, "state" : "CT" }
+{ "_id" : "06095", "city" : "WINDSOR", "loc" : [ -72.663893, 41.856122 ], "pop" : 27815, "state" : "CT" }
+{ "_id" : "06096", "city" : "WINDSOR LOCKS", "loc" : [ -72.645762, 41.926078 ], "pop" : 12358, "state" : "CT" }
+{ "_id" : "06098", "city" : "WINSTED", "loc" : [ -73.06634099999999, 41.925214 ], "pop" : 14584, "state" : "CT" }
+{ "_id" : "06103", "city" : "HARTFORD", "loc" : [ -72.675966, 41.767196 ], "pop" : 1202, "state" : "CT" }
+{ "_id" : "06105", "city" : "HARTFORD", "loc" : [ -72.70100600000001, 41.769116 ], "pop" : 20887, "state" : "CT" }
+{ "_id" : "06106", "city" : "HARTFORD", "loc" : [ -72.694734, 41.749841 ], "pop" : 47841, "state" : "CT" }
+{ "_id" : "06107", "city" : "W HARTFORD", "loc" : [ -72.75322, 41.755553 ], "pop" : 18466, "state" : "CT" }
+{ "_id" : "06108", "city" : "EAST HARTFORD", "loc" : [ -72.618014, 41.780291 ], "pop" : 23698, "state" : "CT" }
+{ "_id" : "06109", "city" : "WETHERSFIELD", "loc" : [ -72.67630800000001, 41.701332 ], "pop" : 25583, "state" : "CT" }
+{ "_id" : "06110", "city" : "W HARTFORD", "loc" : [ -72.73369099999999, 41.732566 ], "pop" : 11817, "state" : "CT" }
+{ "_id" : "06111", "city" : "MAPLE HILL", "loc" : [ -72.729747, 41.686402 ], "pop" : 29192, "state" : "CT" }
+{ "_id" : "06112", "city" : "HARTFORD", "loc" : [ -72.69641, 41.79053 ], "pop" : 29714, "state" : "CT" }
+{ "_id" : "06114", "city" : "HARTFORD", "loc" : [ -72.68072600000001, 41.740293 ], "pop" : 23302, "state" : "CT" }
+{ "_id" : "06117", "city" : "W HARTFORD", "loc" : [ -72.745689, 41.790021 ], "pop" : 14774, "state" : "CT" }
+{ "_id" : "06118", "city" : "EAST HARTFORD", "loc" : [ -72.610265, 41.747211 ], "pop" : 26754, "state" : "CT" }
+{ "_id" : "06119", "city" : "W HARTFORD", "loc" : [ -72.726799, 41.762765 ], "pop" : 15066, "state" : "CT" }
+{ "_id" : "06120", "city" : "HARTFORD", "loc" : [ -72.67580700000001, 41.78596 ], "pop" : 16739, "state" : "CT" }
+{ "_id" : "06226", "city" : "WILLIMANTIC", "loc" : [ -72.213396, 41.714918 ], "pop" : 16023, "state" : "CT" }
+{ "_id" : "06231", "city" : "AMSTON", "loc" : [ -72.36460099999999, 41.628969 ], "pop" : 2887, "state" : "CT" }
+{ "_id" : "06232", "city" : "ANDOVER", "loc" : [ -72.37671899999999, 41.733215 ], "pop" : 2546, "state" : "CT" }
+{ "_id" : "06234", "city" : "BROOKLYN", "loc" : [ -71.95412899999999, 41.780747 ], "pop" : 4835, "state" : "CT" }
+{ "_id" : "06235", "city" : "CHAPLIN", "loc" : [ -72.137197, 41.802584 ], "pop" : 902, "state" : "CT" }
+{ "_id" : "06237", "city" : "COLUMBIA", "loc" : [ -72.30717, 41.697274 ], "pop" : 4510, "state" : "CT" }
+{ "_id" : "06238", "city" : "COVENTRY", "loc" : [ -72.333249, 41.782195 ], "pop" : 10776, "state" : "CT" }
+{ "_id" : "06239", "city" : "DANIELSON", "loc" : [ -71.880703, 41.798246 ], "pop" : 12754, "state" : "CT" }
+{ "_id" : "06241", "city" : "DAYVILLE", "loc" : [ -71.868342, 41.854045 ], "pop" : 5860, "state" : "CT" }
+{ "_id" : "06242", "city" : "EASTFORD", "loc" : [ -72.089451, 41.877104 ], "pop" : 76, "state" : "CT" }
+{ "_id" : "06243", "city" : "EAST KILLINGLY", "loc" : [ -71.798534, 41.848756 ], "pop" : 25, "state" : "CT" }
+{ "_id" : "06247", "city" : "HAMPTON", "loc" : [ -72.06797899999999, 41.761668 ], "pop" : 2139, "state" : "CT" }
+{ "_id" : "06248", "city" : "HEBRON", "loc" : [ -72.39855300000001, 41.684161 ], "pop" : 4192, "state" : "CT" }
+{ "_id" : "06249", "city" : "LEBANON", "loc" : [ -72.244035, 41.632988 ], "pop" : 6043, "state" : "CT" }
+{ "_id" : "06250", "city" : "MANSFIELD CENTER", "loc" : [ -72.20111199999999, 41.769814 ], "pop" : 4306, "state" : "CT" }
+{ "_id" : "06254", "city" : "NORTH FRANKLIN", "loc" : [ -72.142544, 41.616141 ], "pop" : 1654, "state" : "CT" }
+{ "_id" : "06255", "city" : "NORTH GROSVENORD", "loc" : [ -71.902734, 41.987878 ], "pop" : 5641, "state" : "CT" }
+{ "_id" : "06256", "city" : "NORTH WINDHAM", "loc" : [ -72.160106, 41.745144 ], "pop" : 3825, "state" : "CT" }
+{ "_id" : "06259", "city" : "POMFRET CENTER", "loc" : [ -71.98201, 41.869683 ], "pop" : 3325, "state" : "CT" }
+{ "_id" : "06260", "city" : "PUTNAM", "loc" : [ -71.896804, 41.91853 ], "pop" : 9031, "state" : "CT" }
+{ "_id" : "06262", "city" : "QUINEBAUG", "loc" : [ -71.939137, 42.021747 ], "pop" : 72, "state" : "CT" }
+{ "_id" : "06264", "city" : "SCOTLAND", "loc" : [ -72.07826300000001, 41.689849 ], "pop" : 102, "state" : "CT" }
+{ "_id" : "06266", "city" : "SOUTH WINDHAM", "loc" : [ -72.16811199999999, 41.667724 ], "pop" : 372, "state" : "CT" }
+{ "_id" : "06268", "city" : "STORRS MANSFIELD", "loc" : [ -72.257172, 41.805364 ], "pop" : 16117, "state" : "CT" }
+{ "_id" : "06277", "city" : "THOMPSON", "loc" : [ -71.837587, 41.980285 ], "pop" : 2960, "state" : "CT" }
+{ "_id" : "06278", "city" : "WARRENVILLE", "loc" : [ -72.15873000000001, 41.86434 ], "pop" : 2720, "state" : "CT" }
+{ "_id" : "06279", "city" : "WEST WILLINGTON", "loc" : [ -72.272774, 41.873996 ], "pop" : 5981, "state" : "CT" }
+{ "_id" : "06280", "city" : "WINDHAM", "loc" : [ -72.15261, 41.702652 ], "pop" : 3337, "state" : "CT" }
+{ "_id" : "06281", "city" : "WOODSTOCK", "loc" : [ -72.00402699999999, 41.960218 ], "pop" : 5698, "state" : "CT" }
+{ "_id" : "06282", "city" : "WOODSTOCK VALLEY", "loc" : [ -72.09366, 41.915296 ], "pop" : 1099, "state" : "CT" }
+{ "_id" : "06320", "city" : "NEW LONDON", "loc" : [ -72.106245, 41.350718 ], "pop" : 28367, "state" : "CT" }
+{ "_id" : "06330", "city" : "BALTIC", "loc" : [ -72.077499, 41.62629 ], "pop" : 3188, "state" : "CT" }
+{ "_id" : "06331", "city" : "CANTERBURY", "loc" : [ -72.000985, 41.684403 ], "pop" : 4345, "state" : "CT" }
+{ "_id" : "06333", "city" : "EAST LYME", "loc" : [ -72.23298699999999, 41.366806 ], "pop" : 6095, "state" : "CT" }
+{ "_id" : "06334", "city" : "BOZRAH", "loc" : [ -72.17107799999999, 41.546515 ], "pop" : 2297, "state" : "CT" }
+{ "_id" : "06335", "city" : "GALES FERRY", "loc" : [ -72.06719, 41.42852 ], "pop" : 6994, "state" : "CT" }
+{ "_id" : "06336", "city" : "GILMAN", "loc" : [ -72.126623, 41.58117 ], "pop" : 156, "state" : "CT" }
+{ "_id" : "06339", "city" : "LEDYARD", "loc" : [ -71.995626, 41.44014 ], "pop" : 7602, "state" : "CT" }
+{ "_id" : "06340", "city" : "GROTON", "loc" : [ -72.057947, 41.357171 ], "pop" : 32435, "state" : "CT" }
+{ "_id" : "06349", "city" : "GROTON", "loc" : [ -72.090058, 41.397648 ], "pop" : 5398, "state" : "CT" }
+{ "_id" : "06351", "city" : "JEWETT CITY", "loc" : [ -71.98075900000001, 41.605182 ], "pop" : 11674, "state" : "CT" }
+{ "_id" : "06353", "city" : "MONTVILLE", "loc" : [ -72.126476, 41.445331 ], "pop" : 258, "state" : "CT" }
+{ "_id" : "06354", "city" : "MOOSUP", "loc" : [ -71.884962, 41.721031 ], "pop" : 7048, "state" : "CT" }
+{ "_id" : "06355", "city" : "MYSTIC", "loc" : [ -71.97736399999999, 41.361626 ], "pop" : 11183, "state" : "CT" }
+{ "_id" : "06357", "city" : "NIANTIC", "loc" : [ -72.210819, 41.3253 ], "pop" : 9245, "state" : "CT" }
+{ "_id" : "06359", "city" : "NORTH STONINGTON", "loc" : [ -71.87270100000001, 41.453113 ], "pop" : 4882, "state" : "CT" }
+{ "_id" : "06360", "city" : "NORWICH", "loc" : [ -72.08494, 41.537055 ], "pop" : 30145, "state" : "CT" }
+{ "_id" : "06365", "city" : "PRESTON", "loc" : [ -72.021079, 41.522061 ], "pop" : 11191, "state" : "CT" }
+{ "_id" : "06370", "city" : "OAKDALE", "loc" : [ -72.190358, 41.470573 ], "pop" : 6505, "state" : "CT" }
+{ "_id" : "06371", "city" : "OLD LYME", "loc" : [ -72.30856199999999, 41.334745 ], "pop" : 8484, "state" : "CT" }
+{ "_id" : "06374", "city" : "PLAINFIELD", "loc" : [ -71.92196800000001, 41.67753 ], "pop" : 6533, "state" : "CT" }
+{ "_id" : "06375", "city" : "QUAKER HILL", "loc" : [ -72.11722, 41.40324 ], "pop" : 2886, "state" : "CT" }
+{ "_id" : "06377", "city" : "STERLING", "loc" : [ -71.819588, 41.715629 ], "pop" : 2324, "state" : "CT" }
+{ "_id" : "06378", "city" : "STONINGTON", "loc" : [ -71.915544, 41.366437 ], "pop" : 5282, "state" : "CT" }
+{ "_id" : "06379", "city" : "PAWCATUCK", "loc" : [ -71.84776100000001, 41.373475 ], "pop" : 8082, "state" : "CT" }
+{ "_id" : "06380", "city" : "TAFTVILLE", "loc" : [ -72.052877, 41.565263 ], "pop" : 2538, "state" : "CT" }
+{ "_id" : "06382", "city" : "UNCASVILLE", "loc" : [ -72.112556, 41.462168 ], "pop" : 9909, "state" : "CT" }
+{ "_id" : "06384", "city" : "VOLUNTOWN", "loc" : [ -71.855002, 41.583053 ], "pop" : 3167, "state" : "CT" }
+{ "_id" : "06385", "city" : "WATERFORD", "loc" : [ -72.145816, 41.346853 ], "pop" : 15217, "state" : "CT" }
+{ "_id" : "06390", "city" : "FISHERS ISLAND", "loc" : [ -72.01783399999999, 41.263934 ], "pop" : 329, "state" : "NY" }
+{ "_id" : "06401", "city" : "ANSONIA", "loc" : [ -73.07421100000001, 41.342712 ], "pop" : 18430, "state" : "CT" }
+{ "_id" : "06403", "city" : "BEACON FALLS", "loc" : [ -73.059656, 41.436917 ], "pop" : 5083, "state" : "CT" }
+{ "_id" : "06405", "city" : "BRANFORD", "loc" : [ -72.810643, 41.279991 ], "pop" : 27726, "state" : "CT" }
+{ "_id" : "06409", "city" : "CENTERBROOK", "loc" : [ -72.41731, 41.34743 ], "pop" : 483, "state" : "CT" }
+{ "_id" : "06410", "city" : "CHESHIRE", "loc" : [ -72.90812699999999, 41.505473 ], "pop" : 25684, "state" : "CT" }
+{ "_id" : "06412", "city" : "CHESTER", "loc" : [ -72.464293, 41.404903 ], "pop" : 3417, "state" : "CT" }
+{ "_id" : "06413", "city" : "CLINTON", "loc" : [ -72.527973, 41.29117 ], "pop" : 12772, "state" : "CT" }
+{ "_id" : "06415", "city" : "COLCHESTER", "loc" : [ -72.344123, 41.566198 ], "pop" : 10978, "state" : "CT" }
+{ "_id" : "06416", "city" : "CROMWELL", "loc" : [ -72.66631700000001, 41.61049 ], "pop" : 12286, "state" : "CT" }
+{ "_id" : "06417", "city" : "DEEP RIVER", "loc" : [ -72.44856799999999, 41.376478 ], "pop" : 4332, "state" : "CT" }
+{ "_id" : "06418", "city" : "DERBY", "loc" : [ -73.080035, 41.322858 ], "pop" : 12199, "state" : "CT" }
+{ "_id" : "06419", "city" : "KILLINGWORTH", "loc" : [ -72.571192, 41.369622 ], "pop" : 4809, "state" : "CT" }
+{ "_id" : "06420", "city" : "SALEM", "loc" : [ -72.272454, 41.496627 ], "pop" : 4041, "state" : "CT" }
+{ "_id" : "06422", "city" : "DURHAM", "loc" : [ -72.68752000000001, 41.464951 ], "pop" : 5737, "state" : "CT" }
+{ "_id" : "06423", "city" : "EAST HADDAM", "loc" : [ -72.40587600000001, 41.469575 ], "pop" : 3451, "state" : "CT" }
+{ "_id" : "06424", "city" : "EAST HAMPTON", "loc" : [ -72.509345, 41.576058 ], "pop" : 10309, "state" : "CT" }
+{ "_id" : "06426", "city" : "ESSEX", "loc" : [ -72.39650399999999, 41.354944 ], "pop" : 2710, "state" : "CT" }
+{ "_id" : "06430", "city" : "FAIRFIELD", "loc" : [ -73.257109, 41.166442 ], "pop" : 40889, "state" : "CT" }
+{ "_id" : "06432", "city" : "FAIRFIELD", "loc" : [ -73.23540800000001, 41.201651 ], "pop" : 8634, "state" : "CT" }
+{ "_id" : "06437", "city" : "GUILFORD", "loc" : [ -72.69678999999999, 41.31537 ], "pop" : 19717, "state" : "CT" }
+{ "_id" : "06438", "city" : "HADDAM", "loc" : [ -72.504988, 41.462718 ], "pop" : 2245, "state" : "CT" }
+{ "_id" : "06441", "city" : "HIGGANUM", "loc" : [ -72.575143, 41.468246 ], "pop" : 4248, "state" : "CT" }
+{ "_id" : "06442", "city" : "IVORYTON", "loc" : [ -72.440387, 41.342101 ], "pop" : 2748, "state" : "CT" }
+{ "_id" : "06443", "city" : "MADISON", "loc" : [ -72.61525399999999, 41.309019 ], "pop" : 15488, "state" : "CT" }
+{ "_id" : "06447", "city" : "MARLBOROUGH", "loc" : [ -72.460871, 41.641226 ], "pop" : 5535, "state" : "CT" }
+{ "_id" : "06450", "city" : "MERIDEN", "loc" : [ -72.799734, 41.533396 ], "pop" : 59441, "state" : "CT" }
+{ "_id" : "06455", "city" : "MIDDLEFIELD", "loc" : [ -72.71862400000001, 41.516789 ], "pop" : 2515, "state" : "CT" }
+{ "_id" : "06457", "city" : "MIDDLETOWN", "loc" : [ -72.66522500000001, 41.556895 ], "pop" : 42846, "state" : "CT" }
+{ "_id" : "06460", "city" : "MILFORD", "loc" : [ -73.054948, 41.217466 ], "pop" : 49940, "state" : "CT" }
+{ "_id" : "06468", "city" : "MONROE", "loc" : [ -73.224333, 41.331171 ], "pop" : 16845, "state" : "CT" }
+{ "_id" : "06469", "city" : "MOODUS", "loc" : [ -72.441879, 41.507807 ], "pop" : 2634, "state" : "CT" }
+{ "_id" : "06470", "city" : "NEWTOWN", "loc" : [ -73.316744, 41.393095 ], "pop" : 12787, "state" : "CT" }
+{ "_id" : "06471", "city" : "NORTH BRANFORD", "loc" : [ -72.776034, 41.327985 ], "pop" : 6767, "state" : "CT" }
+{ "_id" : "06472", "city" : "NORTHFORD", "loc" : [ -72.78090899999999, 41.396219 ], "pop" : 6229, "state" : "CT" }
+{ "_id" : "06473", "city" : "NORTH HAVEN", "loc" : [ -72.85852, 41.382156 ], "pop" : 22481, "state" : "CT" }
+{ "_id" : "06475", "city" : "OLD SAYBROOK", "loc" : [ -72.38502200000001, 41.291297 ], "pop" : 9552, "state" : "CT" }
+{ "_id" : "06477", "city" : "ORANGE", "loc" : [ -73.02872499999999, 41.281527 ], "pop" : 12828, "state" : "CT" }
+{ "_id" : "06478", "city" : "OXFORD", "loc" : [ -73.12961, 41.420237 ], "pop" : 9286, "state" : "CT" }
+{ "_id" : "06479", "city" : "PLANTSVILLE", "loc" : [ -72.89903099999999, 41.579747 ], "pop" : 10024, "state" : "CT" }
+{ "_id" : "06480", "city" : "PORTLAND", "loc" : [ -72.612797, 41.585223 ], "pop" : 8673, "state" : "CT" }
+{ "_id" : "06481", "city" : "ROCKFALL", "loc" : [ -72.699674, 41.534094 ], "pop" : 1330, "state" : "CT" }
+{ "_id" : "06482", "city" : "SANDY HOOK", "loc" : [ -73.24852199999999, 41.408706 ], "pop" : 8046, "state" : "CT" }
+{ "_id" : "06483", "city" : "SEYMOUR", "loc" : [ -73.081745, 41.386209 ], "pop" : 13660, "state" : "CT" }
+{ "_id" : "06484", "city" : "SHELTON", "loc" : [ -73.129439, 41.304689 ], "pop" : 35447, "state" : "CT" }
+{ "_id" : "06488", "city" : "SOUTHBURY", "loc" : [ -73.22407699999999, 41.476695 ], "pop" : 15818, "state" : "CT" }
+{ "_id" : "06489", "city" : "SOUTHINGTON", "loc" : [ -72.872681, 41.605221 ], "pop" : 28567, "state" : "CT" }
+{ "_id" : "06490", "city" : "SOUTHPORT", "loc" : [ -73.290205, 41.14527 ], "pop" : 3701, "state" : "CT" }
+{ "_id" : "06492", "city" : "WALLINGFORD", "loc" : [ -72.82217900000001, 41.459997 ], "pop" : 40838, "state" : "CT" }
+{ "_id" : "06497", "city" : "STRATFORD", "loc" : [ -73.135594, 41.2044 ], "pop" : 49495, "state" : "CT" }
+{ "_id" : "06498", "city" : "WESTBROOK", "loc" : [ -72.45631299999999, 41.292662 ], "pop" : 5377, "state" : "CT" }
+{ "_id" : "06510", "city" : "NEW HAVEN", "loc" : [ -72.92706, 41.308701 ], "pop" : 4448, "state" : "CT" }
+{ "_id" : "06511", "city" : "NEW HAVEN", "loc" : [ -72.931771, 41.318364 ], "pop" : 54142, "state" : "CT" }
+{ "_id" : "06512", "city" : "EAST HAVEN", "loc" : [ -72.874144, 41.280522 ], "pop" : 28963, "state" : "CT" }
+{ "_id" : "06513", "city" : "EAST HAVEN", "loc" : [ -72.882554, 41.314215 ], "pop" : 31342, "state" : "CT" }
+{ "_id" : "06514", "city" : "HAMDEN", "loc" : [ -72.93613000000001, 41.361987 ], "pop" : 23883, "state" : "CT" }
+{ "_id" : "06515", "city" : "NEW HAVEN", "loc" : [ -72.96644499999999, 41.329301 ], "pop" : 18603, "state" : "CT" }
+{ "_id" : "06516", "city" : "WEST HAVEN", "loc" : [ -72.963842, 41.270079 ], "pop" : 53642, "state" : "CT" }
+{ "_id" : "06517", "city" : "HAMDEN", "loc" : [ -72.91167799999999, 41.348393 ], "pop" : 14604, "state" : "CT" }
+{ "_id" : "06518", "city" : "HAMDEN", "loc" : [ -72.911001, 41.409664 ], "pop" : 13802, "state" : "CT" }
+{ "_id" : "06519", "city" : "NEW HAVEN", "loc" : [ -72.937307, 41.296284 ], "pop" : 19410, "state" : "CT" }
+{ "_id" : "06524", "city" : "BETHANY", "loc" : [ -73.000704, 41.426194 ], "pop" : 4730, "state" : "CT" }
+{ "_id" : "06525", "city" : "WOODBRIDGE", "loc" : [ -73.013902, 41.351668 ], "pop" : 7802, "state" : "CT" }
+{ "_id" : "06604", "city" : "BRIDGEPORT", "loc" : [ -73.201859, 41.179574 ], "pop" : 28219, "state" : "CT" }
+{ "_id" : "06605", "city" : "BRIDGEPORT", "loc" : [ -73.216251, 41.166796 ], "pop" : 23800, "state" : "CT" }
+{ "_id" : "06606", "city" : "BRIDGEPORT", "loc" : [ -73.208619, 41.20907 ], "pop" : 41879, "state" : "CT" }
+{ "_id" : "06607", "city" : "BRIDGEPORT", "loc" : [ -73.165048, 41.178382 ], "pop" : 9292, "state" : "CT" }
+{ "_id" : "06608", "city" : "BRIDGEPORT", "loc" : [ -73.181141, 41.189466 ], "pop" : 17721, "state" : "CT" }
+{ "_id" : "06610", "city" : "BRIDGEPORT", "loc" : [ -73.16877100000001, 41.200508 ], "pop" : 20727, "state" : "CT" }
+{ "_id" : "06611", "city" : "TRUMBULL", "loc" : [ -73.211063, 41.25641 ], "pop" : 32213, "state" : "CT" }
+{ "_id" : "06612", "city" : "EASTON", "loc" : [ -73.287108, 41.252328 ], "pop" : 6213, "state" : "CT" }
+{ "_id" : "06702", "city" : "WATERBURY", "loc" : [ -73.038545, 41.556568 ], "pop" : 4522, "state" : "CT" }
+{ "_id" : "06704", "city" : "WATERBURY", "loc" : [ -73.03180500000001, 41.575435 ], "pop" : 26018, "state" : "CT" }
+{ "_id" : "06705", "city" : "WATERBURY", "loc" : [ -72.996268, 41.550328 ], "pop" : 25128, "state" : "CT" }
+{ "_id" : "06706", "city" : "WATERBURY", "loc" : [ -73.03064000000001, 41.536261 ], "pop" : 15431, "state" : "CT" }
+{ "_id" : "06708", "city" : "WATERBURY", "loc" : [ -73.06449499999999, 41.551102 ], "pop" : 27661, "state" : "CT" }
+{ "_id" : "06710", "city" : "WATERBURY", "loc" : [ -73.04682099999999, 41.567503 ], "pop" : 9921, "state" : "CT" }
+{ "_id" : "06712", "city" : "PROSPECT", "loc" : [ -72.978803, 41.502198 ], "pop" : 7775, "state" : "CT" }
+{ "_id" : "06716", "city" : "WOLCOTT", "loc" : [ -72.982799, 41.596995 ], "pop" : 13787, "state" : "CT" }
+{ "_id" : "06750", "city" : "BANTAM", "loc" : [ -73.252028, 41.721483 ], "pop" : 1418, "state" : "CT" }
+{ "_id" : "06751", "city" : "BETHLEHEM", "loc" : [ -73.209098, 41.638683 ], "pop" : 3071, "state" : "CT" }
+{ "_id" : "06752", "city" : "BRIDGEWATER", "loc" : [ -73.360936, 41.528684 ], "pop" : 1654, "state" : "CT" }
+{ "_id" : "06754", "city" : "WARREN", "loc" : [ -73.36747200000001, 41.770084 ], "pop" : 1278, "state" : "CT" }
+{ "_id" : "06755", "city" : "GAYLORDSVILLE", "loc" : [ -73.483524, 41.648635 ], "pop" : 890, "state" : "CT" }
+{ "_id" : "06756", "city" : "GOSHEN", "loc" : [ -73.242876, 41.833452 ], "pop" : 2314, "state" : "CT" }
+{ "_id" : "06757", "city" : "KENT", "loc" : [ -73.45834499999999, 41.731619 ], "pop" : 2035, "state" : "CT" }
+{ "_id" : "06758", "city" : "LAKESIDE", "loc" : [ -73.238235, 41.69001 ], "pop" : 997, "state" : "CT" }
+{ "_id" : "06759", "city" : "LITCHFIELD", "loc" : [ -73.200011, 41.754069 ], "pop" : 5573, "state" : "CT" }
+{ "_id" : "06762", "city" : "MIDDLEBURY", "loc" : [ -73.11306999999999, 41.534277 ], "pop" : 6338, "state" : "CT" }
+{ "_id" : "06763", "city" : "MORRIS", "loc" : [ -73.176509, 41.688121 ], "pop" : 849, "state" : "CT" }
+{ "_id" : "06770", "city" : "NAUGATUCK", "loc" : [ -73.049342, 41.492039 ], "pop" : 30625, "state" : "CT" }
+{ "_id" : "06776", "city" : "NEW MILFORD", "loc" : [ -73.412752, 41.581745 ], "pop" : 22750, "state" : "CT" }
+{ "_id" : "06777", "city" : "NEW PRESTON MARB", "loc" : [ -73.349296, 41.689373 ], "pop" : 1697, "state" : "CT" }
+{ "_id" : "06778", "city" : "NORTHFIELD", "loc" : [ -73.132079, 41.707382 ], "pop" : 442, "state" : "CT" }
+{ "_id" : "06779", "city" : "OAKVILLE", "loc" : [ -73.087311, 41.590932 ], "pop" : 8455, "state" : "CT" }
+{ "_id" : "06782", "city" : "PLYMOUTH", "loc" : [ -73.044887, 41.661121 ], "pop" : 2910, "state" : "CT" }
+{ "_id" : "06783", "city" : "ROXBURY", "loc" : [ -73.299346, 41.5509 ], "pop" : 1825, "state" : "CT" }
+{ "_id" : "06784", "city" : "SHERMAN", "loc" : [ -73.494694, 41.571366 ], "pop" : 2808, "state" : "CT" }
+{ "_id" : "06785", "city" : "SOUTH KENT", "loc" : [ -73.46902300000001, 41.695051 ], "pop" : 719, "state" : "CT" }
+{ "_id" : "06786", "city" : "TERRYVILLE", "loc" : [ -73.009214, 41.676197 ], "pop" : 8912, "state" : "CT" }
+{ "_id" : "06787", "city" : "THOMASTON", "loc" : [ -73.08855699999999, 41.678643 ], "pop" : 8179, "state" : "CT" }
+{ "_id" : "06790", "city" : "TORRINGTON", "loc" : [ -73.115579, 41.813065 ], "pop" : 33969, "state" : "CT" }
+{ "_id" : "06791", "city" : "HARWINTON", "loc" : [ -73.072819, 41.770145 ], "pop" : 5228, "state" : "CT" }
+{ "_id" : "06793", "city" : "WASHINGTON DEPOT", "loc" : [ -73.29351800000001, 41.634595 ], "pop" : 1381, "state" : "CT" }
+{ "_id" : "06794", "city" : "WASHINGTON DEPOT", "loc" : [ -73.327352, 41.655924 ], "pop" : 1323, "state" : "CT" }
+{ "_id" : "06795", "city" : "WATERTOWN", "loc" : [ -73.122122, 41.605654 ], "pop" : 12021, "state" : "CT" }
+{ "_id" : "06796", "city" : "WEST CORNWALL", "loc" : [ -73.331271, 41.868888 ], "pop" : 1042, "state" : "CT" }
+{ "_id" : "06798", "city" : "WOODBURY", "loc" : [ -73.208264, 41.552061 ], "pop" : 8131, "state" : "CT" }
+{ "_id" : "06801", "city" : "BETHEL", "loc" : [ -73.40082700000001, 41.381298 ], "pop" : 17538, "state" : "CT" }
+{ "_id" : "06804", "city" : "BROOKFIELD", "loc" : [ -73.397986, 41.46504 ], "pop" : 14223, "state" : "CT" }
+{ "_id" : "06807", "city" : "COS COB", "loc" : [ -73.593498, 41.052952 ], "pop" : 7000, "state" : "CT" }
+{ "_id" : "06810", "city" : "DANBURY", "loc" : [ -73.453165, 41.391663 ], "pop" : 37764, "state" : "CT" }
+{ "_id" : "06811", "city" : "DANBURY", "loc" : [ -73.471587, 41.423983 ], "pop" : 27609, "state" : "CT" }
+{ "_id" : "06812", "city" : "NEW FAIRFIELD", "loc" : [ -73.497784, 41.472999 ], "pop" : 13013, "state" : "CT" }
+{ "_id" : "06820", "city" : "DARIEN", "loc" : [ -73.485254, 41.076759 ], "pop" : 18062, "state" : "CT" }
+{ "_id" : "06830", "city" : "BYRAM", "loc" : [ -73.630047, 41.030238 ], "pop" : 22685, "state" : "CT" }
+{ "_id" : "06831", "city" : "GREENWICH", "loc" : [ -73.65940500000001, 41.054885 ], "pop" : 14545, "state" : "CT" }
+{ "_id" : "06840", "city" : "NEW CANAAN", "loc" : [ -73.494356, 41.151024 ], "pop" : 17937, "state" : "CT" }
+{ "_id" : "06850", "city" : "NORWALK", "loc" : [ -73.435827, 41.12222 ], "pop" : 17332, "state" : "CT" }
+{ "_id" : "06851", "city" : "NORWALK", "loc" : [ -73.40580199999999, 41.132346 ], "pop" : 24412, "state" : "CT" }
+{ "_id" : "06853", "city" : "NORWALK", "loc" : [ -73.439667, 41.070243 ], "pop" : 3979, "state" : "CT" }
+{ "_id" : "06854", "city" : "NORWALK", "loc" : [ -73.42848499999999, 41.095722 ], "pop" : 25358, "state" : "CT" }
+{ "_id" : "06855", "city" : "NORWALK", "loc" : [ -73.40111899999999, 41.101382 ], "pop" : 7311, "state" : "CT" }
+{ "_id" : "06870", "city" : "OLD GREENWICH", "loc" : [ -73.56725299999999, 41.035437 ], "pop" : 6511, "state" : "CT" }
+{ "_id" : "06877", "city" : "RIDGEFIELD", "loc" : [ -73.49726800000001, 41.297683 ], "pop" : 21691, "state" : "CT" }
+{ "_id" : "06878", "city" : "RIVERSIDE", "loc" : [ -73.581136, 41.037998 ], "pop" : 7765, "state" : "CT" }
+{ "_id" : "06880", "city" : "WESTPORT", "loc" : [ -73.34957900000001, 41.143433 ], "pop" : 24705, "state" : "CT" }
+{ "_id" : "06883", "city" : "WESTON", "loc" : [ -73.37147400000001, 41.219499 ], "pop" : 8517, "state" : "CT" }
+{ "_id" : "06896", "city" : "WEST REDDING", "loc" : [ -73.3935, 41.306915 ], "pop" : 7183, "state" : "CT" }
+{ "_id" : "06897", "city" : "WILTON", "loc" : [ -73.438323, 41.201761 ], "pop" : 15795, "state" : "CT" }
+{ "_id" : "06901", "city" : "STAMFORD", "loc" : [ -73.539039, 41.053083 ], "pop" : 5860, "state" : "CT" }
+{ "_id" : "06902", "city" : "STAMFORD", "loc" : [ -73.53742800000001, 41.052552 ], "pop" : 54605, "state" : "CT" }
+{ "_id" : "06903", "city" : "STAMFORD", "loc" : [ -73.56835599999999, 41.135235 ], "pop" : 14172, "state" : "CT" }
+{ "_id" : "06905", "city" : "RIDGEWAY", "loc" : [ -73.543757, 41.082576 ], "pop" : 17839, "state" : "CT" }
+{ "_id" : "06906", "city" : "STAMFORD", "loc" : [ -73.523563, 41.069218 ], "pop" : 7019, "state" : "CT" }
+{ "_id" : "06907", "city" : "STAMFORD", "loc" : [ -73.520297, 41.094206 ], "pop" : 8498, "state" : "CT" }
+{ "_id" : "07001", "city" : "AVENEL", "loc" : [ -74.278522, 40.582568 ], "pop" : 14953, "state" : "NJ" }
+{ "_id" : "07002", "city" : "BAYONNE", "loc" : [ -74.119169, 40.666399 ], "pop" : 61444, "state" : "NJ" }
+{ "_id" : "07003", "city" : "BLOOMFIELD", "loc" : [ -74.18907400000001, 40.803456 ], "pop" : 46131, "state" : "NJ" }
+{ "_id" : "07004", "city" : "FAIRFIELD", "loc" : [ -74.296027, 40.882178 ], "pop" : 7567, "state" : "NJ" }
+{ "_id" : "07005", "city" : "BOONTON", "loc" : [ -74.414035, 40.911528 ], "pop" : 13961, "state" : "NJ" }
+{ "_id" : "07006", "city" : "WEST CALDWELL", "loc" : [ -74.276771, 40.849059 ], "pop" : 24946, "state" : "NJ" }
+{ "_id" : "07008", "city" : "CARTERET", "loc" : [ -74.231345, 40.582278 ], "pop" : 19025, "state" : "NJ" }
+{ "_id" : "07009", "city" : "CEDAR GROVE", "loc" : [ -74.22967199999999, 40.85344 ], "pop" : 11787, "state" : "NJ" }
+{ "_id" : "07010", "city" : "CLIFFSIDE PARK", "loc" : [ -73.987982, 40.822168 ], "pop" : 20687, "state" : "NJ" }
+{ "_id" : "07011", "city" : "CLIFTON", "loc" : [ -74.142459, 40.878876 ], "pop" : 31569, "state" : "NJ" }
+{ "_id" : "07012", "city" : "CLIFTON", "loc" : [ -74.16117199999999, 40.848835 ], "pop" : 10107, "state" : "NJ" }
+{ "_id" : "07013", "city" : "CLIFTON", "loc" : [ -74.171144, 40.869334 ], "pop" : 25503, "state" : "NJ" }
+{ "_id" : "07014", "city" : "CLIFTON", "loc" : [ -74.137682, 40.834375 ], "pop" : 4288, "state" : "NJ" }
+{ "_id" : "07016", "city" : "CRANFORD", "loc" : [ -74.305685, 40.655357 ], "pop" : 22866, "state" : "NJ" }
+{ "_id" : "07017", "city" : "EAST ORANGE", "loc" : [ -74.207723, 40.769614 ], "pop" : 41737, "state" : "NJ" }
+{ "_id" : "07018", "city" : "EAST ORANGE", "loc" : [ -74.21982199999999, 40.755799 ], "pop" : 32618, "state" : "NJ" }
+{ "_id" : "07020", "city" : "EDGEWATER", "loc" : [ -73.973821, 40.831654 ], "pop" : 5001, "state" : "NJ" }
+{ "_id" : "07021", "city" : "ESSEX FELLS", "loc" : [ -74.27970500000001, 40.827924 ], "pop" : 2102, "state" : "NJ" }
+{ "_id" : "07022", "city" : "FAIRVIEW", "loc" : [ -73.999967, 40.816985 ], "pop" : 10682, "state" : "NJ" }
+{ "_id" : "07023", "city" : "FANWOOD", "loc" : [ -74.386762, 40.641856 ], "pop" : 6528, "state" : "NJ" }
+{ "_id" : "07024", "city" : "FORT LEE", "loc" : [ -73.97445500000001, 40.850312 ], "pop" : 32030, "state" : "NJ" }
+{ "_id" : "07026", "city" : "GARFIELD", "loc" : [ -74.108141, 40.878886 ], "pop" : 26727, "state" : "NJ" }
+{ "_id" : "07027", "city" : "GARWOOD", "loc" : [ -74.323864, 40.65121 ], "pop" : 4277, "state" : "NJ" }
+{ "_id" : "07028", "city" : "GLEN RIDGE", "loc" : [ -74.205477, 40.804015 ], "pop" : 7751, "state" : "NJ" }
+{ "_id" : "07029", "city" : "KEARNY", "loc" : [ -74.155871, 40.74754 ], "pop" : 15587, "state" : "NJ" }
+{ "_id" : "07030", "city" : "HOBOKEN", "loc" : [ -74.03286300000001, 40.7445 ], "pop" : 33397, "state" : "NJ" }
+{ "_id" : "07031", "city" : "NORTH ARLINGTON", "loc" : [ -74.134288, 40.78977 ], "pop" : 13629, "state" : "NJ" }
+{ "_id" : "07032", "city" : "KEARNY", "loc" : [ -74.147108, 40.76466 ], "pop" : 34869, "state" : "NJ" }
+{ "_id" : "07033", "city" : "KENILWORTH", "loc" : [ -74.294419, 40.675869 ], "pop" : 7516, "state" : "NJ" }
+{ "_id" : "07034", "city" : "LAKE HIAWATHA", "loc" : [ -74.38301300000001, 40.88252 ], "pop" : 9361, "state" : "NJ" }
+{ "_id" : "07035", "city" : "LINCOLN PARK", "loc" : [ -74.29951199999999, 40.920769 ], "pop" : 10814, "state" : "NJ" }
+{ "_id" : "07036", "city" : "LINDEN", "loc" : [ -74.255567, 40.635366 ], "pop" : 37859, "state" : "NJ" }
+{ "_id" : "07039", "city" : "LIVINGSTON", "loc" : [ -74.3202, 40.789633 ], "pop" : 26677, "state" : "NJ" }
+{ "_id" : "07040", "city" : "MAPLEWOOD", "loc" : [ -74.265573, 40.727906 ], "pop" : 21588, "state" : "NJ" }
+{ "_id" : "07041", "city" : "MILLBURN", "loc" : [ -74.301469, 40.722798 ], "pop" : 6501, "state" : "NJ" }
+{ "_id" : "07042", "city" : "MONTCLAIR", "loc" : [ -74.21646699999999, 40.81307 ], "pop" : 24938, "state" : "NJ" }
+{ "_id" : "07043", "city" : "MONTCLAIR", "loc" : [ -74.201104, 40.843023 ], "pop" : 11891, "state" : "NJ" }
+{ "_id" : "07044", "city" : "VERONA", "loc" : [ -74.242847, 40.831928 ], "pop" : 13583, "state" : "NJ" }
+{ "_id" : "07045", "city" : "MONTVILLE", "loc" : [ -74.36456, 40.904914 ], "pop" : 6571, "state" : "NJ" }
+{ "_id" : "07046", "city" : "MOUNTAIN LAKES", "loc" : [ -74.441487, 40.890447 ], "pop" : 4250, "state" : "NJ" }
+{ "_id" : "07047", "city" : "NORTH BERGEN", "loc" : [ -74.017715, 40.793019 ], "pop" : 50823, "state" : "NJ" }
+{ "_id" : "07050", "city" : "ORANGE", "loc" : [ -74.2355, 40.769223 ], "pop" : 28789, "state" : "NJ" }
+{ "_id" : "07052", "city" : "WEST ORANGE", "loc" : [ -74.256765, 40.785926 ], "pop" : 38639, "state" : "NJ" }
+{ "_id" : "07054", "city" : "PARSIPPANY", "loc" : [ -74.411663, 40.862106 ], "pop" : 27179, "state" : "NJ" }
+{ "_id" : "07055", "city" : "PASSAIC", "loc" : [ -74.128348, 40.860132 ], "pop" : 58325, "state" : "NJ" }
+{ "_id" : "07057", "city" : "WALLINGTON", "loc" : [ -74.10793700000001, 40.85356 ], "pop" : 10816, "state" : "NJ" }
+{ "_id" : "07058", "city" : "PINE BROOK", "loc" : [ -74.350009, 40.874207 ], "pop" : 4345, "state" : "NJ" }
+{ "_id" : "07059", "city" : "WARREN", "loc" : [ -74.510456, 40.631787 ], "pop" : 10867, "state" : "NJ" }
+{ "_id" : "07060", "city" : "NORTH PLAINFIELD", "loc" : [ -74.425298, 40.61978 ], "pop" : 43471, "state" : "NJ" }
+{ "_id" : "07062", "city" : "NORTH PLAINFIELD", "loc" : [ -74.406042, 40.631992 ], "pop" : 12756, "state" : "NJ" }
+{ "_id" : "07063", "city" : "NORTH PLAINFIELD", "loc" : [ -74.445325, 40.604838 ], "pop" : 14285, "state" : "NJ" }
+{ "_id" : "07064", "city" : "PORT READING", "loc" : [ -74.24664300000001, 40.570935 ], "pop" : 4083, "state" : "NJ" }
+{ "_id" : "07065", "city" : "RAHWAY", "loc" : [ -74.281881, 40.608668 ], "pop" : 25296, "state" : "NJ" }
+{ "_id" : "07066", "city" : "CLARK", "loc" : [ -74.310581, 40.620256 ], "pop" : 14973, "state" : "NJ" }
+{ "_id" : "07067", "city" : "COLONIA", "loc" : [ -74.316368, 40.593743 ], "pop" : 18488, "state" : "NJ" }
+{ "_id" : "07068", "city" : "ROSELAND", "loc" : [ -74.304688, 40.82034 ], "pop" : 4820, "state" : "NJ" }
+{ "_id" : "07070", "city" : "RUTHERFORD", "loc" : [ -74.112146, 40.829245 ], "pop" : 17790, "state" : "NJ" }
+{ "_id" : "07071", "city" : "LYNDHURST", "loc" : [ -74.12452999999999, 40.809433 ], "pop" : 18423, "state" : "NJ" }
+{ "_id" : "07072", "city" : "CARLSTADT", "loc" : [ -74.09249800000001, 40.840298 ], "pop" : 5541, "state" : "NJ" }
+{ "_id" : "07073", "city" : "EAST RUTHERFORD", "loc" : [ -74.104069, 40.838527 ], "pop" : 7874, "state" : "NJ" }
+{ "_id" : "07074", "city" : "MOONACHIE", "loc" : [ -74.056646, 40.839352 ], "pop" : 2817, "state" : "NJ" }
+{ "_id" : "07075", "city" : "WOOD RIDGE", "loc" : [ -74.087845, 40.849348 ], "pop" : 7548, "state" : "NJ" }
+{ "_id" : "07076", "city" : "SCOTCH PLAINS", "loc" : [ -74.381663, 40.642162 ], "pop" : 18514, "state" : "NJ" }
+{ "_id" : "07077", "city" : "SEWAREN", "loc" : [ -74.26073599999999, 40.554181 ], "pop" : 2463, "state" : "NJ" }
+{ "_id" : "07078", "city" : "SHORT HILLS", "loc" : [ -74.327085, 40.73678 ], "pop" : 12129, "state" : "NJ" }
+{ "_id" : "07079", "city" : "SOUTH ORANGE", "loc" : [ -74.257532, 40.746453 ], "pop" : 16115, "state" : "NJ" }
+{ "_id" : "07080", "city" : "SOUTH PLAINFIELD", "loc" : [ -74.41469499999999, 40.583884 ], "pop" : 20540, "state" : "NJ" }
+{ "_id" : "07081", "city" : "SPRINGFIELD", "loc" : [ -74.322705, 40.701461 ], "pop" : 13452, "state" : "NJ" }
+{ "_id" : "07082", "city" : "TOWACO", "loc" : [ -74.34280699999999, 40.927691 ], "pop" : 4355, "state" : "NJ" }
+{ "_id" : "07083", "city" : "UNION", "loc" : [ -74.267653, 40.695184 ], "pop" : 46608, "state" : "NJ" }
+{ "_id" : "07087", "city" : "WEEHAWKEN", "loc" : [ -74.030558, 40.768153 ], "pop" : 69646, "state" : "NJ" }
+{ "_id" : "07088", "city" : "VAUXHALL", "loc" : [ -74.28287400000001, 40.717927 ], "pop" : 3481, "state" : "NJ" }
+{ "_id" : "07090", "city" : "WESTFIELD", "loc" : [ -74.345056, 40.647851 ], "pop" : 31885, "state" : "NJ" }
+{ "_id" : "07092", "city" : "MOUNTAINSIDE", "loc" : [ -74.358785, 40.678461 ], "pop" : 6660, "state" : "NJ" }
+{ "_id" : "07093", "city" : "GUTTENBERG", "loc" : [ -74.01285900000001, 40.788192 ], "pop" : 44735, "state" : "NJ" }
+{ "_id" : "07094", "city" : "SECAUCUS", "loc" : [ -74.063416, 40.79101 ], "pop" : 14061, "state" : "NJ" }
+{ "_id" : "07095", "city" : "WOODBRIDGE", "loc" : [ -74.284542, 40.555973 ], "pop" : 15827, "state" : "NJ" }
+{ "_id" : "07102", "city" : "NEWARK", "loc" : [ -74.17650500000001, 40.73201 ], "pop" : 10328, "state" : "NJ" }
+{ "_id" : "07103", "city" : "NEWARK", "loc" : [ -74.196364, 40.736975 ], "pop" : 36949, "state" : "NJ" }
+{ "_id" : "07104", "city" : "NEWARK", "loc" : [ -74.1695, 40.766446 ], "pop" : 47183, "state" : "NJ" }
+{ "_id" : "07105", "city" : "NEWARK", "loc" : [ -74.156346, 40.727086 ], "pop" : 38104, "state" : "NJ" }
+{ "_id" : "07106", "city" : "NEWARK", "loc" : [ -74.233023, 40.741485 ], "pop" : 35013, "state" : "NJ" }
+{ "_id" : "07107", "city" : "NEWARK", "loc" : [ -74.18816, 40.760656 ], "pop" : 36649, "state" : "NJ" }
+{ "_id" : "07108", "city" : "NEWARK", "loc" : [ -74.201538, 40.723647 ], "pop" : 29730, "state" : "NJ" }
+{ "_id" : "07109", "city" : "BELLEVILLE", "loc" : [ -74.16311899999999, 40.79458 ], "pop" : 34924, "state" : "NJ" }
+{ "_id" : "07110", "city" : "NUTLEY", "loc" : [ -74.158934, 40.818548 ], "pop" : 26441, "state" : "NJ" }
+{ "_id" : "07111", "city" : "IRVINGTON", "loc" : [ -74.23127100000001, 40.7261 ], "pop" : 60986, "state" : "NJ" }
+{ "_id" : "07112", "city" : "NEWARK", "loc" : [ -74.21307299999999, 40.71071 ], "pop" : 30356, "state" : "NJ" }
+{ "_id" : "07114", "city" : "NEWARK", "loc" : [ -74.189105, 40.708246 ], "pop" : 11260, "state" : "NJ" }
+{ "_id" : "07201", "city" : "ELIZABETH", "loc" : [ -74.204335, 40.67169 ], "pop" : 25826, "state" : "NJ" }
+{ "_id" : "07202", "city" : "ELIZABETH", "loc" : [ -74.22154399999999, 40.65652 ], "pop" : 33981, "state" : "NJ" }
+{ "_id" : "07203", "city" : "ROSELLE", "loc" : [ -74.261044, 40.652972 ], "pop" : 20159, "state" : "NJ" }
+{ "_id" : "07204", "city" : "ROSELLE PARK", "loc" : [ -74.267003, 40.665134 ], "pop" : 12784, "state" : "NJ" }
+{ "_id" : "07205", "city" : "HILLSIDE", "loc" : [ -74.228065, 40.696811 ], "pop" : 20860, "state" : "NJ" }
+{ "_id" : "07206", "city" : "ELIZABETH", "loc" : [ -74.192487, 40.653207 ], "pop" : 23830, "state" : "NJ" }
+{ "_id" : "07208", "city" : "ELIZABETH", "loc" : [ -74.22392000000001, 40.674659 ], "pop" : 26609, "state" : "NJ" }
+{ "_id" : "07302", "city" : "JERSEY CITY", "loc" : [ -74.04687800000001, 40.722126 ], "pop" : 32876, "state" : "NJ" }
+{ "_id" : "07304", "city" : "JERSEY CITY", "loc" : [ -74.07535799999999, 40.717973 ], "pop" : 42101, "state" : "NJ" }
+{ "_id" : "07305", "city" : "JERSEY CITY", "loc" : [ -74.088998, 40.702007 ], "pop" : 58655, "state" : "NJ" }
+{ "_id" : "07306", "city" : "JERSEY CITY", "loc" : [ -74.06603800000001, 40.732125 ], "pop" : 53257, "state" : "NJ" }
+{ "_id" : "07307", "city" : "JERSEY CITY", "loc" : [ -74.049752, 40.748167 ], "pop" : 40704, "state" : "NJ" }
+{ "_id" : "07310", "city" : "JERSEY CITY", "loc" : [ -74.043149, 40.732354 ], "pop" : 944, "state" : "NJ" }
+{ "_id" : "07401", "city" : "ALLENDALE", "loc" : [ -74.134185, 41.032654 ], "pop" : 5907, "state" : "NJ" }
+{ "_id" : "07403", "city" : "BLOOMINGDALE", "loc" : [ -74.33375599999999, 41.012845 ], "pop" : 7520, "state" : "NJ" }
+{ "_id" : "07405", "city" : "KINNELON", "loc" : [ -74.364065, 40.992118 ], "pop" : 15325, "state" : "NJ" }
+{ "_id" : "07407", "city" : "ELMWOOD PARK", "loc" : [ -74.120896, 40.906896 ], "pop" : 17649, "state" : "NJ" }
+{ "_id" : "07410", "city" : "FAIR LAWN", "loc" : [ -74.11660000000001, 40.934297 ], "pop" : 30522, "state" : "NJ" }
+{ "_id" : "07416", "city" : "FRANKLIN", "loc" : [ -74.58649, 41.116355 ], "pop" : 5380, "state" : "NJ" }
+{ "_id" : "07417", "city" : "FRANKLIN LAKES", "loc" : [ -74.211347, 41.008095 ], "pop" : 9873, "state" : "NJ" }
+{ "_id" : "07418", "city" : "GLENWOOD", "loc" : [ -74.48848099999999, 41.235618 ], "pop" : 2446, "state" : "NJ" }
+{ "_id" : "07419", "city" : "HAMBURG", "loc" : [ -74.587379, 41.146714 ], "pop" : 4198, "state" : "NJ" }
+{ "_id" : "07420", "city" : "HASKELL", "loc" : [ -74.296542, 41.030111 ], "pop" : 4813, "state" : "NJ" }
+{ "_id" : "07421", "city" : "HEWITT", "loc" : [ -74.368566, 41.170867 ], "pop" : 6907, "state" : "NJ" }
+{ "_id" : "07422", "city" : "HIGHLAND LAKES", "loc" : [ -74.456442, 41.182622 ], "pop" : 7615, "state" : "NJ" }
+{ "_id" : "07423", "city" : "HO HO KUS", "loc" : [ -74.102532, 41.000412 ], "pop" : 3967, "state" : "NJ" }
+{ "_id" : "07424", "city" : "WEST PATERSON", "loc" : [ -74.21145, 40.885353 ], "pop" : 22626, "state" : "NJ" }
+{ "_id" : "07430", "city" : "MAHWAH", "loc" : [ -74.155974, 41.074473 ], "pop" : 17991, "state" : "NJ" }
+{ "_id" : "07432", "city" : "MIDLAND PARK", "loc" : [ -74.14090400000001, 40.995668 ], "pop" : 6693, "state" : "NJ" }
+{ "_id" : "07435", "city" : "NEWFOUNDLAND", "loc" : [ -74.435857, 41.064691 ], "pop" : 1624, "state" : "NJ" }
+{ "_id" : "07436", "city" : "OAKLAND", "loc" : [ -74.233754, 41.029436 ], "pop" : 11997, "state" : "NJ" }
+{ "_id" : "07438", "city" : "MILTON", "loc" : [ -74.50880100000001, 41.028401 ], "pop" : 10453, "state" : "NJ" }
+{ "_id" : "07439", "city" : "OGDENSBURG", "loc" : [ -74.59818799999999, 41.076707 ], "pop" : 2722, "state" : "NJ" }
+{ "_id" : "07440", "city" : "PEQUANNOCK", "loc" : [ -74.29601, 40.947308 ], "pop" : 4932, "state" : "NJ" }
+{ "_id" : "07442", "city" : "POMPTON LAKES", "loc" : [ -74.287566, 40.999284 ], "pop" : 10539, "state" : "NJ" }
+{ "_id" : "07444", "city" : "POMPTON PLAINS", "loc" : [ -74.301602, 40.965515 ], "pop" : 8028, "state" : "NJ" }
+{ "_id" : "07446", "city" : "RAMSEY", "loc" : [ -74.14446700000001, 41.057743 ], "pop" : 13135, "state" : "NJ" }
+{ "_id" : "07450", "city" : "RIDGEWOOD", "loc" : [ -74.113134, 40.982023 ], "pop" : 24452, "state" : "NJ" }
+{ "_id" : "07452", "city" : "GLEN ROCK", "loc" : [ -74.125367, 40.960183 ], "pop" : 10942, "state" : "NJ" }
+{ "_id" : "07456", "city" : "RINGWOOD", "loc" : [ -74.265872, 41.092816 ], "pop" : 12645, "state" : "NJ" }
+{ "_id" : "07457", "city" : "RIVERDALE", "loc" : [ -74.308756, 40.993109 ], "pop" : 2365, "state" : "NJ" }
+{ "_id" : "07458", "city" : "UPPER SADDLE RIV", "loc" : [ -74.09677499999999, 41.053083 ], "pop" : 10148, "state" : "NJ" }
+{ "_id" : "07460", "city" : "STOCKHOLM", "loc" : [ -74.528256, 41.099204 ], "pop" : 3375, "state" : "NJ" }
+{ "_id" : "07461", "city" : "SUSSEX", "loc" : [ -74.59915599999999, 41.229211 ], "pop" : 15969, "state" : "NJ" }
+{ "_id" : "07462", "city" : "VERNON", "loc" : [ -74.533196, 41.184981 ], "pop" : 6460, "state" : "NJ" }
+{ "_id" : "07463", "city" : "WALDWICK", "loc" : [ -74.124259, 41.012968 ], "pop" : 9720, "state" : "NJ" }
+{ "_id" : "07465", "city" : "WANAQUE", "loc" : [ -74.27896800000001, 41.054447 ], "pop" : 4941, "state" : "NJ" }
+{ "_id" : "07470", "city" : "WAYNE", "loc" : [ -74.246565, 40.947112 ], "pop" : 46815, "state" : "NJ" }
+{ "_id" : "07480", "city" : "WEST MILFORD", "loc" : [ -74.374996, 41.091513 ], "pop" : 15417, "state" : "NJ" }
+{ "_id" : "07481", "city" : "WYCKOFF", "loc" : [ -74.166009, 40.997834 ], "pop" : 15372, "state" : "NJ" }
+{ "_id" : "07501", "city" : "PATERSON", "loc" : [ -74.167141, 40.914273 ], "pop" : 33364, "state" : "NJ" }
+{ "_id" : "07502", "city" : "PATERSON", "loc" : [ -74.19323799999999, 40.919926 ], "pop" : 12698, "state" : "NJ" }
+{ "_id" : "07503", "city" : "PATERSON", "loc" : [ -74.15727200000001, 40.897046 ], "pop" : 18683, "state" : "NJ" }
+{ "_id" : "07504", "city" : "PATERSON", "loc" : [ -74.145247, 40.912179 ], "pop" : 12152, "state" : "NJ" }
+{ "_id" : "07505", "city" : "PATERSON", "loc" : [ -74.171947, 40.915581 ], "pop" : 1837, "state" : "NJ" }
+{ "_id" : "07506", "city" : "HAWTHORNE", "loc" : [ -74.156897, 40.956355 ], "pop" : 16920, "state" : "NJ" }
+{ "_id" : "07508", "city" : "HALEDON", "loc" : [ -74.182599, 40.945689 ], "pop" : 19757, "state" : "NJ" }
+{ "_id" : "07512", "city" : "TOTOWA", "loc" : [ -74.21675, 40.904811 ], "pop" : 10147, "state" : "NJ" }
+{ "_id" : "07513", "city" : "PATERSON", "loc" : [ -74.152862, 40.906994 ], "pop" : 10088, "state" : "NJ" }
+{ "_id" : "07514", "city" : "PATERSON", "loc" : [ -74.146717, 40.924764 ], "pop" : 18860, "state" : "NJ" }
+{ "_id" : "07522", "city" : "PATERSON", "loc" : [ -74.178078, 40.925168 ], "pop" : 21813, "state" : "NJ" }
+{ "_id" : "07524", "city" : "PATERSON", "loc" : [ -74.155457, 40.930916 ], "pop" : 11887, "state" : "NJ" }
+{ "_id" : "07601", "city" : "HACKENSACK", "loc" : [ -74.050301, 40.888191 ], "pop" : 36963, "state" : "NJ" }
+{ "_id" : "07603", "city" : "BOGOTA", "loc" : [ -74.028122, 40.874441 ], "pop" : 7824, "state" : "NJ" }
+{ "_id" : "07604", "city" : "HASBROUCK HEIGHT", "loc" : [ -74.075971, 40.862241 ], "pop" : 11499, "state" : "NJ" }
+{ "_id" : "07605", "city" : "LEONIA", "loc" : [ -73.98787299999999, 40.862929 ], "pop" : 8326, "state" : "NJ" }
+{ "_id" : "07606", "city" : "SOUTH HACKENSACK", "loc" : [ -74.045601, 40.863391 ], "pop" : 2150, "state" : "NJ" }
+{ "_id" : "07607", "city" : "MAYWOOD", "loc" : [ -74.062916, 40.902412 ], "pop" : 9473, "state" : "NJ" }
+{ "_id" : "07608", "city" : "TETERBORO", "loc" : [ -74.054204, 40.86175 ], "pop" : 22, "state" : "NJ" }
+{ "_id" : "07620", "city" : "ALPINE", "loc" : [ -73.930842, 40.951097 ], "pop" : 1716, "state" : "NJ" }
+{ "_id" : "07621", "city" : "BERGENFIELD", "loc" : [ -73.998918, 40.923837 ], "pop" : 24613, "state" : "NJ" }
+{ "_id" : "07624", "city" : "CLOSTER", "loc" : [ -73.958985, 40.972051 ], "pop" : 8101, "state" : "NJ" }
+{ "_id" : "07626", "city" : "CRESSKILL", "loc" : [ -73.96520599999999, 40.941847 ], "pop" : 7633, "state" : "NJ" }
+{ "_id" : "07627", "city" : "DEMAREST", "loc" : [ -73.960221, 40.954775 ], "pop" : 4718, "state" : "NJ" }
+{ "_id" : "07628", "city" : "DUMONT", "loc" : [ -73.99213899999999, 40.944692 ], "pop" : 17187, "state" : "NJ" }
+{ "_id" : "07630", "city" : "EMERSON", "loc" : [ -74.028515, 40.975459 ], "pop" : 6519, "state" : "NJ" }
+{ "_id" : "07631", "city" : "ENGLEWOOD", "loc" : [ -73.977182, 40.894251 ], "pop" : 24869, "state" : "NJ" }
+{ "_id" : "07632", "city" : "ENGLEWOOD CLIFFS", "loc" : [ -73.954449, 40.882043 ], "pop" : 5644, "state" : "NJ" }
+{ "_id" : "07640", "city" : "HARRINGTON PARK", "loc" : [ -73.980017, 40.991791 ], "pop" : 4628, "state" : "NJ" }
+{ "_id" : "07641", "city" : "HAWORTH", "loc" : [ -73.987376, 40.960808 ], "pop" : 3384, "state" : "NJ" }
+{ "_id" : "07642", "city" : "HILLSDALE", "loc" : [ -74.042625, 41.006945 ], "pop" : 9771, "state" : "NJ" }
+{ "_id" : "07643", "city" : "LITTLE FERRY", "loc" : [ -74.040502, 40.849319 ], "pop" : 9970, "state" : "NJ" }
+{ "_id" : "07644", "city" : "LODI", "loc" : [ -74.083827, 40.876363 ], "pop" : 22345, "state" : "NJ" }
+{ "_id" : "07645", "city" : "MONTVALE", "loc" : [ -74.03836200000001, 41.049458 ], "pop" : 6935, "state" : "NJ" }
+{ "_id" : "07646", "city" : "NEW MILFORD", "loc" : [ -74.01951699999999, 40.933115 ], "pop" : 15799, "state" : "NJ" }
+{ "_id" : "07647", "city" : "ROCKLEIGH", "loc" : [ -73.952375, 41.011196 ], "pop" : 4833, "state" : "NJ" }
+{ "_id" : "07648", "city" : "NORWOOD", "loc" : [ -73.95817, 40.995231 ], "pop" : 4858, "state" : "NJ" }
+{ "_id" : "07649", "city" : "ORADELL", "loc" : [ -74.033525, 40.953456 ], "pop" : 8069, "state" : "NJ" }
+{ "_id" : "07650", "city" : "PALISADES PARK", "loc" : [ -73.995436, 40.846238 ], "pop" : 14536, "state" : "NJ" }
+{ "_id" : "07652", "city" : "PARAMUS", "loc" : [ -74.06724, 40.947683 ], "pop" : 25085, "state" : "NJ" }
+{ "_id" : "07656", "city" : "PARK RIDGE", "loc" : [ -74.039574, 41.034349 ], "pop" : 8120, "state" : "NJ" }
+{ "_id" : "07657", "city" : "RIDGEFIELD", "loc" : [ -74.001531, 40.832568 ], "pop" : 9753, "state" : "NJ" }
+{ "_id" : "07660", "city" : "RIDGEFIELD PARK", "loc" : [ -74.02296200000001, 40.856218 ], "pop" : 12454, "state" : "NJ" }
+{ "_id" : "07661", "city" : "RIVER EDGE", "loc" : [ -74.03924000000001, 40.926476 ], "pop" : 10603, "state" : "NJ" }
+{ "_id" : "07662", "city" : "SADDLE BROOK", "loc" : [ -74.091296, 40.904928 ], "pop" : 18883, "state" : "NJ" }
+{ "_id" : "07666", "city" : "TEANECK", "loc" : [ -74.011928, 40.89148 ], "pop" : 37822, "state" : "NJ" }
+{ "_id" : "07670", "city" : "TENAFLY", "loc" : [ -73.965906, 40.921596 ], "pop" : 13297, "state" : "NJ" }
+{ "_id" : "07675", "city" : "OLD TAPPAN", "loc" : [ -74.03258599999999, 41.001696 ], "pop" : 39036, "state" : "NJ" }
+{ "_id" : "07701", "city" : "SUBURBAN", "loc" : [ -74.080003, 40.354083 ], "pop" : 22320, "state" : "NJ" }
+{ "_id" : "07702", "city" : "SHREWSBURY", "loc" : [ -74.058892, 40.328198 ], "pop" : 3096, "state" : "NJ" }
+{ "_id" : "07703", "city" : "FORT MONMOUTH", "loc" : [ -74.039001, 40.317667 ], "pop" : 919, "state" : "NJ" }
+{ "_id" : "07704", "city" : "FAIR HAVEN", "loc" : [ -74.03889100000001, 40.359873 ], "pop" : 5176, "state" : "NJ" }
+{ "_id" : "07711", "city" : "ALLENHURST", "loc" : [ -74.00670599999999, 40.236675 ], "pop" : 2030, "state" : "NJ" }
+{ "_id" : "07712", "city" : "OCEAN", "loc" : [ -74.02948600000001, 40.235571 ], "pop" : 35939, "state" : "NJ" }
+{ "_id" : "07716", "city" : "ATLANTIC HIGHLAN", "loc" : [ -74.032411, 40.40772 ], "pop" : 8440, "state" : "NJ" }
+{ "_id" : "07717", "city" : "AVON BY THE SEA", "loc" : [ -74.01673700000001, 40.191796 ], "pop" : 2165, "state" : "NJ" }
+{ "_id" : "07718", "city" : "BELFORD", "loc" : [ -74.088887, 40.417281 ], "pop" : 6601, "state" : "NJ" }
+{ "_id" : "07719", "city" : "WALL", "loc" : [ -74.047247, 40.17434 ], "pop" : 19146, "state" : "NJ" }
+{ "_id" : "07720", "city" : "BRADLEY BEACH", "loc" : [ -74.013166, 40.202308 ], "pop" : 4475, "state" : "NJ" }
+{ "_id" : "07721", "city" : "CLIFFWOOD", "loc" : [ -74.235759, 40.435281 ], "pop" : 2332, "state" : "NJ" }
+{ "_id" : "07722", "city" : "COLTS NECK", "loc" : [ -74.177988, 40.301225 ], "pop" : 8623, "state" : "NJ" }
+{ "_id" : "07723", "city" : "DEAL", "loc" : [ -74.001998, 40.250568 ], "pop" : 1722, "state" : "NJ" }
+{ "_id" : "07724", "city" : "EATONTOWN", "loc" : [ -74.06977999999999, 40.302815 ], "pop" : 23682, "state" : "NJ" }
+{ "_id" : "07726", "city" : "MANALAPAN", "loc" : [ -74.330613, 40.306274 ], "pop" : 28928, "state" : "NJ" }
+{ "_id" : "07727", "city" : "FARMINGDALE", "loc" : [ -74.177864, 40.204312 ], "pop" : 4794, "state" : "NJ" }
+{ "_id" : "07728", "city" : "FREEHOLD", "loc" : [ -74.276822, 40.245776 ], "pop" : 42567, "state" : "NJ" }
+{ "_id" : "07730", "city" : "HAZLET", "loc" : [ -74.179896, 40.422554 ], "pop" : 17181, "state" : "NJ" }
+{ "_id" : "07731", "city" : "HOWELL", "loc" : [ -74.213683, 40.148096 ], "pop" : 31114, "state" : "NJ" }
+{ "_id" : "07732", "city" : "FORT HANCOCK", "loc" : [ -73.99091199999999, 40.402377 ], "pop" : 4962, "state" : "NJ" }
+{ "_id" : "07733", "city" : "HOLMDEL", "loc" : [ -74.17397099999999, 40.385853 ], "pop" : 11165, "state" : "NJ" }
+{ "_id" : "07734", "city" : "KEANSBURG", "loc" : [ -74.130633, 40.441363 ], "pop" : 21931, "state" : "NJ" }
+{ "_id" : "07735", "city" : "KEYPORT", "loc" : [ -74.199563, 40.439862 ], "pop" : 21082, "state" : "NJ" }
+{ "_id" : "07737", "city" : "LEONARDO", "loc" : [ -74.062265, 40.417704 ], "pop" : 5027, "state" : "NJ" }
+{ "_id" : "07738", "city" : "LINCROFT", "loc" : [ -74.120469, 40.33689 ], "pop" : 6214, "state" : "NJ" }
+{ "_id" : "07739", "city" : "LITTLE SILVER", "loc" : [ -74.041319, 40.335393 ], "pop" : 5683, "state" : "NJ" }
+{ "_id" : "07740", "city" : "LONG BRANCH", "loc" : [ -73.991176, 40.299204 ], "pop" : 29053, "state" : "NJ" }
+{ "_id" : "07746", "city" : "MARLBORO", "loc" : [ -74.26387099999999, 40.31825 ], "pop" : 14956, "state" : "NJ" }
+{ "_id" : "07747", "city" : "MATAWAN", "loc" : [ -74.237955, 40.410876 ], "pop" : 26130, "state" : "NJ" }
+{ "_id" : "07748", "city" : "NEW MONMOUTH", "loc" : [ -74.113908, 40.396018 ], "pop" : 22727, "state" : "NJ" }
+{ "_id" : "07750", "city" : "MONMOUTH BEACH", "loc" : [ -73.98089, 40.333032 ], "pop" : 3329, "state" : "NJ" }
+{ "_id" : "07751", "city" : "MORGANVILLE", "loc" : [ -74.277863, 40.352917 ], "pop" : 11680, "state" : "NJ" }
+{ "_id" : "07753", "city" : "NEPTUNE CITY", "loc" : [ -74.054045, 40.211153 ], "pop" : 32147, "state" : "NJ" }
+{ "_id" : "07755", "city" : "OAKHURST", "loc" : [ -74.018413, 40.26479 ], "pop" : 5637, "state" : "NJ" }
+{ "_id" : "07756", "city" : "OCEAN GROVE", "loc" : [ -74.009306, 40.211606 ], "pop" : 4723, "state" : "NJ" }
+{ "_id" : "07757", "city" : "OCEANPORT", "loc" : [ -74.016372, 40.31573 ], "pop" : 5227, "state" : "NJ" }
+{ "_id" : "07758", "city" : "PORT MONMOUTH", "loc" : [ -74.108259, 40.428886 ], "pop" : 4698, "state" : "NJ" }
+{ "_id" : "07760", "city" : "SEA BRIGHT", "loc" : [ -74.000618, 40.371829 ], "pop" : 9700, "state" : "NJ" }
+{ "_id" : "07762", "city" : "SPRING LAKE", "loc" : [ -74.037885, 40.154198 ], "pop" : 9384, "state" : "NJ" }
+{ "_id" : "07764", "city" : "WEST LONG BRANCH", "loc" : [ -74.016221, 40.287811 ], "pop" : 7666, "state" : "NJ" }
+{ "_id" : "07801", "city" : "MINE HILL", "loc" : [ -74.559702, 40.887218 ], "pop" : 25588, "state" : "NJ" }
+{ "_id" : "07821", "city" : "ANDOVER", "loc" : [ -74.75241800000001, 40.961386 ], "pop" : 8931, "state" : "NJ" }
+{ "_id" : "07822", "city" : "AUGUSTA", "loc" : [ -74.684753, 41.145086 ], "pop" : 1555, "state" : "NJ" }
+{ "_id" : "07823", "city" : "BELVIDERE", "loc" : [ -75.05026100000001, 40.830819 ], "pop" : 5790, "state" : "NJ" }
+{ "_id" : "07825", "city" : "BLAIRSTOWN", "loc" : [ -74.965097, 40.967386 ], "pop" : 8815, "state" : "NJ" }
+{ "_id" : "07826", "city" : "BRANCHVILLE", "loc" : [ -74.75002499999999, 41.170512 ], "pop" : 5009, "state" : "NJ" }
+{ "_id" : "07827", "city" : "MONTAGUE", "loc" : [ -74.753956, 41.302259 ], "pop" : 3228, "state" : "NJ" }
+{ "_id" : "07828", "city" : "BUDD LAKE", "loc" : [ -74.742552, 40.873108 ], "pop" : 11588, "state" : "NJ" }
+{ "_id" : "07830", "city" : "CALIFON", "loc" : [ -74.815218, 40.716209 ], "pop" : 5526, "state" : "NJ" }
+{ "_id" : "07832", "city" : "COLUMBIA", "loc" : [ -75.05498299999999, 40.938805 ], "pop" : 3185, "state" : "NJ" }
+{ "_id" : "07834", "city" : "DENVILLE", "loc" : [ -74.484379, 40.889735 ], "pop" : 14075, "state" : "NJ" }
+{ "_id" : "07836", "city" : "FLANDERS", "loc" : [ -74.70188, 40.845316 ], "pop" : 10548, "state" : "NJ" }
+{ "_id" : "07838", "city" : "GREAT MEADOWS", "loc" : [ -74.941806, 40.85196 ], "pop" : 2303, "state" : "NJ" }
+{ "_id" : "07840", "city" : "HACKETTSTOWN", "loc" : [ -74.834315, 40.852891 ], "pop" : 23440, "state" : "NJ" }
+{ "_id" : "07843", "city" : "HOPATCONG", "loc" : [ -74.66163, 40.938983 ], "pop" : 11920, "state" : "NJ" }
+{ "_id" : "07847", "city" : "KENVIL", "loc" : [ -74.62098400000001, 40.881901 ], "pop" : 1356, "state" : "NJ" }
+{ "_id" : "07848", "city" : "LAFAYETTE", "loc" : [ -74.69122299999999, 41.076099 ], "pop" : 2992, "state" : "NJ" }
+{ "_id" : "07849", "city" : "LAKE HOPATCONG", "loc" : [ -74.61443800000001, 40.965882 ], "pop" : 7241, "state" : "NJ" }
+{ "_id" : "07850", "city" : "LANDING", "loc" : [ -74.65542499999999, 40.908684 ], "pop" : 6482, "state" : "NJ" }
+{ "_id" : "07851", "city" : "LAYTON", "loc" : [ -74.81721899999999, 41.205913 ], "pop" : 807, "state" : "NJ" }
+{ "_id" : "07852", "city" : "LEDGEWOOD", "loc" : [ -74.655405, 40.878028 ], "pop" : 997, "state" : "NJ" }
+{ "_id" : "07853", "city" : "LONG VALLEY", "loc" : [ -74.78698, 40.787817 ], "pop" : 12345, "state" : "NJ" }
+{ "_id" : "07856", "city" : "MOUNT ARLINGTON", "loc" : [ -74.636331, 40.928267 ], "pop" : 2240, "state" : "NJ" }
+{ "_id" : "07857", "city" : "NETCONG", "loc" : [ -74.698454, 40.898497 ], "pop" : 3330, "state" : "NJ" }
+{ "_id" : "07860", "city" : "FREDON TOWNSHIP", "loc" : [ -74.780191, 41.058275 ], "pop" : 25022, "state" : "NJ" }
+{ "_id" : "07863", "city" : "OXFORD", "loc" : [ -75.00194, 40.810537 ], "pop" : 2610, "state" : "NJ" }
+{ "_id" : "07865", "city" : "PORT MURRAY", "loc" : [ -74.91674999999999, 40.790615 ], "pop" : 2124, "state" : "NJ" }
+{ "_id" : "07866", "city" : "ROCKAWAY", "loc" : [ -74.50937, 40.922916 ], "pop" : 20388, "state" : "NJ" }
+{ "_id" : "07869", "city" : "RANDOLPH", "loc" : [ -74.572519, 40.845557 ], "pop" : 20870, "state" : "NJ" }
+{ "_id" : "07871", "city" : "SPARTA", "loc" : [ -74.64070100000001, 41.027697 ], "pop" : 15324, "state" : "NJ" }
+{ "_id" : "07874", "city" : "STANHOPE", "loc" : [ -74.70044, 40.921743 ], "pop" : 9375, "state" : "NJ" }
+{ "_id" : "07876", "city" : "SUCCASUNNA", "loc" : [ -74.65360099999999, 40.85385 ], "pop" : 10640, "state" : "NJ" }
+{ "_id" : "07881", "city" : "WALLPACK CENTER", "loc" : [ -74.91759500000001, 41.134332 ], "pop" : 67, "state" : "NJ" }
+{ "_id" : "07882", "city" : "WASHINGTON", "loc" : [ -74.991361, 40.75818 ], "pop" : 13409, "state" : "NJ" }
+{ "_id" : "07885", "city" : "WHARTON", "loc" : [ -74.58634000000001, 40.913883 ], "pop" : 7842, "state" : "NJ" }
+{ "_id" : "07901", "city" : "SUMMIT", "loc" : [ -74.364159, 40.71494 ], "pop" : 20151, "state" : "NJ" }
+{ "_id" : "07920", "city" : "BASKING RIDGE", "loc" : [ -74.560463, 40.678937 ], "pop" : 17810, "state" : "NJ" }
+{ "_id" : "07921", "city" : "BEDMINSTER", "loc" : [ -74.643236, 40.657109 ], "pop" : 6515, "state" : "NJ" }
+{ "_id" : "07922", "city" : "BERKELEY HEIGHTS", "loc" : [ -74.43459900000001, 40.67522 ], "pop" : 11155, "state" : "NJ" }
+{ "_id" : "07924", "city" : "BERNARDSVILLE", "loc" : [ -74.57781199999999, 40.72251 ], "pop" : 6454, "state" : "NJ" }
+{ "_id" : "07927", "city" : "CEDAR KNOLLS", "loc" : [ -74.456861, 40.822335 ], "pop" : 3449, "state" : "NJ" }
+{ "_id" : "07928", "city" : "CHATHAM", "loc" : [ -74.401701, 40.730526 ], "pop" : 16708, "state" : "NJ" }
+{ "_id" : "07930", "city" : "CHESTER", "loc" : [ -74.677649, 40.789193 ], "pop" : 6635, "state" : "NJ" }
+{ "_id" : "07931", "city" : "FAR HILLS", "loc" : [ -74.653959, 40.704035 ], "pop" : 2728, "state" : "NJ" }
+{ "_id" : "07932", "city" : "FLORHAM PARK", "loc" : [ -74.392819, 40.775701 ], "pop" : 8473, "state" : "NJ" }
+{ "_id" : "07933", "city" : "GILLETTE", "loc" : [ -74.46813400000001, 40.687678 ], "pop" : 3296, "state" : "NJ" }
+{ "_id" : "07934", "city" : "GLADSTONE", "loc" : [ -74.67065599999999, 40.721948 ], "pop" : 887, "state" : "NJ" }
+{ "_id" : "07935", "city" : "GREEN VILLAGE", "loc" : [ -74.451685, 40.741618 ], "pop" : 893, "state" : "NJ" }
+{ "_id" : "07936", "city" : "EAST HANOVER", "loc" : [ -74.36357, 40.819165 ], "pop" : 9904, "state" : "NJ" }
+{ "_id" : "07940", "city" : "MADISON", "loc" : [ -74.417868, 40.759939 ], "pop" : 15960, "state" : "NJ" }
+{ "_id" : "07945", "city" : "MENDHAM", "loc" : [ -74.60003500000001, 40.778919 ], "pop" : 7756, "state" : "NJ" }
+{ "_id" : "07946", "city" : "MILLINGTON", "loc" : [ -74.518292, 40.672716 ], "pop" : 2506, "state" : "NJ" }
+{ "_id" : "07950", "city" : "GREYSTONE PARK", "loc" : [ -74.479645, 40.843982 ], "pop" : 16528, "state" : "NJ" }
+{ "_id" : "07960", "city" : "MORRISTOWN", "loc" : [ -74.48728800000001, 40.795236 ], "pop" : 38516, "state" : "NJ" }
+{ "_id" : "07974", "city" : "NEW PROVIDENCE", "loc" : [ -74.40229100000001, 40.700403 ], "pop" : 11838, "state" : "NJ" }
+{ "_id" : "07976", "city" : "NEW VERNON", "loc" : [ -74.484471, 40.734685 ], "pop" : 682, "state" : "NJ" }
+{ "_id" : "07980", "city" : "STIRLING", "loc" : [ -74.49683, 40.677366 ], "pop" : 2355, "state" : "NJ" }
+{ "_id" : "07981", "city" : "WHIPPANY", "loc" : [ -74.419971, 40.821862 ], "pop" : 7233, "state" : "NJ" }
+{ "_id" : "08002", "city" : "CHERRY HILL", "loc" : [ -75.017538, 39.930808 ], "pop" : 21271, "state" : "NJ" }
+{ "_id" : "08003", "city" : "CHERRY HILL", "loc" : [ -74.970568, 39.880453 ], "pop" : 29058, "state" : "NJ" }
+{ "_id" : "08004", "city" : "WINSLOW", "loc" : [ -74.879368, 39.770909 ], "pop" : 14312, "state" : "NJ" }
+{ "_id" : "08005", "city" : "BARNEGAT", "loc" : [ -74.246988, 39.755248 ], "pop" : 13036, "state" : "NJ" }
+{ "_id" : "08007", "city" : "BARRINGTON", "loc" : [ -75.056361, 39.865062 ], "pop" : 5185, "state" : "NJ" }
+{ "_id" : "08008", "city" : "HARVEY CEDARS", "loc" : [ -74.18903299999999, 39.636347 ], "pop" : 8647, "state" : "NJ" }
+{ "_id" : "08009", "city" : "BERLIN", "loc" : [ -74.930808, 39.778839 ], "pop" : 14034, "state" : "NJ" }
+{ "_id" : "08010", "city" : "BEVERLY", "loc" : [ -74.91136299999999, 40.056452 ], "pop" : 11361, "state" : "NJ" }
+{ "_id" : "08012", "city" : "WASHINGTON", "loc" : [ -75.058747, 39.774104 ], "pop" : 35874, "state" : "NJ" }
+{ "_id" : "08014", "city" : "BRIDGEPORT", "loc" : [ -75.34782, 39.801616 ], "pop" : 702, "state" : "NJ" }
+{ "_id" : "08015", "city" : "BROWNS MILLS", "loc" : [ -74.565549, 39.95974 ], "pop" : 21735, "state" : "NJ" }
+{ "_id" : "08016", "city" : "BURLINGTON", "loc" : [ -74.845353, 40.068015 ], "pop" : 25065, "state" : "NJ" }
+{ "_id" : "08019", "city" : "CHATSWORTH", "loc" : [ -74.52561900000001, 39.801945 ], "pop" : 215, "state" : "NJ" }
+{ "_id" : "08020", "city" : "CLARKSBORO", "loc" : [ -75.22365499999999, 39.799228 ], "pop" : 3169, "state" : "NJ" }
+{ "_id" : "08021", "city" : "LAUREL SPRINGS", "loc" : [ -75.003997, 39.80703 ], "pop" : 48953, "state" : "NJ" }
+{ "_id" : "08022", "city" : "COLUMBUS", "loc" : [ -74.68988, 40.064238 ], "pop" : 5709, "state" : "NJ" }
+{ "_id" : "08026", "city" : "GIBBSBORO", "loc" : [ -74.970996, 39.836532 ], "pop" : 2383, "state" : "NJ" }
+{ "_id" : "08027", "city" : "GIBBSTOWN", "loc" : [ -75.275128, 39.82314 ], "pop" : 5102, "state" : "NJ" }
+{ "_id" : "08028", "city" : "GLASSBORO", "loc" : [ -75.11724700000001, 39.706823 ], "pop" : 15492, "state" : "NJ" }
+{ "_id" : "08029", "city" : "GLENDORA", "loc" : [ -75.069744, 39.840376 ], "pop" : 5205, "state" : "NJ" }
+{ "_id" : "08030", "city" : "GLOUCESTER CITY", "loc" : [ -75.116962, 39.891105 ], "pop" : 14454, "state" : "NJ" }
+{ "_id" : "08031", "city" : "BELLMAWR", "loc" : [ -75.094368, 39.868878 ], "pop" : 12568, "state" : "NJ" }
+{ "_id" : "08033", "city" : "HADDONFIELD", "loc" : [ -75.041726, 39.895449 ], "pop" : 17496, "state" : "NJ" }
+{ "_id" : "08034", "city" : "CHERRY HILL", "loc" : [ -75.00076199999999, 39.9074 ], "pop" : 18836, "state" : "NJ" }
+{ "_id" : "08035", "city" : "HADDON HEIGHTS", "loc" : [ -75.06639, 39.878832 ], "pop" : 8034, "state" : "NJ" }
+{ "_id" : "08037", "city" : "BATSTO", "loc" : [ -74.790735, 39.638878 ], "pop" : 22484, "state" : "NJ" }
+{ "_id" : "08041", "city" : "JOBSTOWN", "loc" : [ -74.68730499999999, 40.038698 ], "pop" : 115, "state" : "NJ" }
+{ "_id" : "08043", "city" : "VOORHEES", "loc" : [ -74.964614, 39.850422 ], "pop" : 21308, "state" : "NJ" }
+{ "_id" : "08045", "city" : "LAWNSIDE", "loc" : [ -75.03168100000001, 39.867601 ], "pop" : 2840, "state" : "NJ" }
+{ "_id" : "08046", "city" : "WILLINGBORO", "loc" : [ -74.883482, 40.028959 ], "pop" : 36471, "state" : "NJ" }
+{ "_id" : "08048", "city" : "LUMBERTON", "loc" : [ -74.806736, 39.96512 ], "pop" : 170, "state" : "NJ" }
+{ "_id" : "08049", "city" : "MAGNOLIA", "loc" : [ -75.039254, 39.853807 ], "pop" : 5931, "state" : "NJ" }
+{ "_id" : "08050", "city" : "MANAHAWKIN", "loc" : [ -74.260391, 39.705017 ], "pop" : 12188, "state" : "NJ" }
+{ "_id" : "08051", "city" : "MANTUA", "loc" : [ -75.17853100000001, 39.786983 ], "pop" : 8080, "state" : "NJ" }
+{ "_id" : "08052", "city" : "MAPLE SHADE", "loc" : [ -74.99464399999999, 39.951085 ], "pop" : 19365, "state" : "NJ" }
+{ "_id" : "08053", "city" : "MARLTON", "loc" : [ -74.90674, 39.884517 ], "pop" : 33299, "state" : "NJ" }
+{ "_id" : "08054", "city" : "MOUNT LAUREL", "loc" : [ -74.903588, 39.947808 ], "pop" : 29805, "state" : "NJ" }
+{ "_id" : "08055", "city" : "MEDFORD LAKES", "loc" : [ -74.823384, 39.868099 ], "pop" : 25033, "state" : "NJ" }
+{ "_id" : "08056", "city" : "MICKLETON", "loc" : [ -75.24977699999999, 39.785653 ], "pop" : 1850, "state" : "NJ" }
+{ "_id" : "08057", "city" : "MOORESTOWN", "loc" : [ -74.953323, 39.9683 ], "pop" : 16092, "state" : "NJ" }
+{ "_id" : "08059", "city" : "MOUNT EPHRAIM", "loc" : [ -75.09289, 39.882749 ], "pop" : 5267, "state" : "NJ" }
+{ "_id" : "08060", "city" : "EASTAMPTON TWP", "loc" : [ -74.79552200000001, 39.993028 ], "pop" : 31606, "state" : "NJ" }
+{ "_id" : "08061", "city" : "MOUNT ROYAL", "loc" : [ -75.208153, 39.809741 ], "pop" : 239, "state" : "NJ" }
+{ "_id" : "08062", "city" : "MULLICA HILL", "loc" : [ -75.20654, 39.725228 ], "pop" : 8720, "state" : "NJ" }
+{ "_id" : "08063", "city" : "NATIONAL PARK", "loc" : [ -75.17939699999999, 39.866412 ], "pop" : 3398, "state" : "NJ" }
+{ "_id" : "08065", "city" : "PALMYRA", "loc" : [ -75.025685, 40.003654 ], "pop" : 6916, "state" : "NJ" }
+{ "_id" : "08066", "city" : "PAULSBORO", "loc" : [ -75.224233, 39.831157 ], "pop" : 10269, "state" : "NJ" }
+{ "_id" : "08067", "city" : "PEDRICKTOWN", "loc" : [ -75.412046, 39.743451 ], "pop" : 1565, "state" : "NJ" }
+{ "_id" : "08068", "city" : "PEMBERTON", "loc" : [ -74.66762900000001, 39.971206 ], "pop" : 11000, "state" : "NJ" }
+{ "_id" : "08069", "city" : "CARNEYS POINT", "loc" : [ -75.46562299999999, 39.717938 ], "pop" : 14138, "state" : "NJ" }
+{ "_id" : "08070", "city" : "PENNSVILLE", "loc" : [ -75.51553, 39.649107 ], "pop" : 12717, "state" : "NJ" }
+{ "_id" : "08071", "city" : "PITMAN", "loc" : [ -75.129679, 39.731162 ], "pop" : 9697, "state" : "NJ" }
+{ "_id" : "08075", "city" : "DELANCO", "loc" : [ -74.95612800000001, 40.024684 ], "pop" : 24468, "state" : "NJ" }
+{ "_id" : "08077", "city" : "CINNAMINSON", "loc" : [ -74.995141, 39.996393 ], "pop" : 17498, "state" : "NJ" }
+{ "_id" : "08078", "city" : "RUNNEMEDE", "loc" : [ -75.074224, 39.850825 ], "pop" : 8589, "state" : "NJ" }
+{ "_id" : "08079", "city" : "SALEM", "loc" : [ -75.452096, 39.559124 ], "pop" : 14129, "state" : "NJ" }
+{ "_id" : "08080", "city" : "SEWELL", "loc" : [ -75.08985199999999, 39.747345 ], "pop" : 23121, "state" : "NJ" }
+{ "_id" : "08081", "city" : "SICKLERVILLE", "loc" : [ -74.986385, 39.735385 ], "pop" : 29949, "state" : "NJ" }
+{ "_id" : "08083", "city" : "SOMERDALE", "loc" : [ -75.030913, 39.839988 ], "pop" : 11913, "state" : "NJ" }
+{ "_id" : "08084", "city" : "STRATFORD", "loc" : [ -75.014707, 39.828798 ], "pop" : 7217, "state" : "NJ" }
+{ "_id" : "08085", "city" : "SWEDESBORO", "loc" : [ -75.336202, 39.752853 ], "pop" : 7968, "state" : "NJ" }
+{ "_id" : "08086", "city" : "THOROFARE", "loc" : [ -75.176698, 39.859178 ], "pop" : 3395, "state" : "NJ" }
+{ "_id" : "08087", "city" : "TUCKERTON", "loc" : [ -74.364586, 39.588149 ], "pop" : 17728, "state" : "NJ" }
+{ "_id" : "08088", "city" : "SOUTHAMPTON", "loc" : [ -74.71102500000001, 39.867631 ], "pop" : 25480, "state" : "NJ" }
+{ "_id" : "08089", "city" : "WATERFORD WORKS", "loc" : [ -74.860933, 39.721512 ], "pop" : 4344, "state" : "NJ" }
+{ "_id" : "08090", "city" : "WENONAH", "loc" : [ -75.153644, 39.799283 ], "pop" : 9129, "state" : "NJ" }
+{ "_id" : "08091", "city" : "WEST BERLIN", "loc" : [ -74.941678, 39.81959 ], "pop" : 5244, "state" : "NJ" }
+{ "_id" : "08092", "city" : "WEST CREEK", "loc" : [ -74.28850799999999, 39.662665 ], "pop" : 2502, "state" : "NJ" }
+{ "_id" : "08093", "city" : "WESTVILLE", "loc" : [ -75.132278, 39.860494 ], "pop" : 9696, "state" : "NJ" }
+{ "_id" : "08094", "city" : "WILLIAMSTOWN", "loc" : [ -74.97102700000001, 39.665006 ], "pop" : 30978, "state" : "NJ" }
+{ "_id" : "08096", "city" : "DEPTFORD", "loc" : [ -75.13796600000001, 39.829477 ], "pop" : 34147, "state" : "NJ" }
+{ "_id" : "08097", "city" : "WOODBURY HEIGHTS", "loc" : [ -75.15297200000001, 39.814162 ], "pop" : 3625, "state" : "NJ" }
+{ "_id" : "08098", "city" : "WOODSTOWN", "loc" : [ -75.324806, 39.645663 ], "pop" : 8013, "state" : "NJ" }
+{ "_id" : "08102", "city" : "CAMDEN", "loc" : [ -75.118644, 39.951244 ], "pop" : 10107, "state" : "NJ" }
+{ "_id" : "08103", "city" : "CAMDEN", "loc" : [ -75.11170799999999, 39.935099 ], "pop" : 17818, "state" : "NJ" }
+{ "_id" : "08104", "city" : "CAMDEN", "loc" : [ -75.10783499999999, 39.918575 ], "pop" : 26375, "state" : "NJ" }
+{ "_id" : "08105", "city" : "CAMDEN", "loc" : [ -75.086382, 39.948417 ], "pop" : 34450, "state" : "NJ" }
+{ "_id" : "08106", "city" : "AUDUBON", "loc" : [ -75.072425, 39.891035 ], "pop" : 10355, "state" : "NJ" }
+{ "_id" : "08107", "city" : "OAKLYN", "loc" : [ -75.08489, 39.90799 ], "pop" : 14161, "state" : "NJ" }
+{ "_id" : "08108", "city" : "COLLINGSWOOD", "loc" : [ -75.063383, 39.915682 ], "pop" : 18125, "state" : "NJ" }
+{ "_id" : "08109", "city" : "MERCHANTVILLE", "loc" : [ -75.048204, 39.95193 ], "pop" : 22294, "state" : "NJ" }
+{ "_id" : "08110", "city" : "DELAIR", "loc" : [ -75.063446, 39.962742 ], "pop" : 15447, "state" : "NJ" }
+{ "_id" : "08201", "city" : "SMITHVILLE", "loc" : [ -74.503106, 39.462368 ], "pop" : 26645, "state" : "NJ" }
+{ "_id" : "08202", "city" : "AVALON", "loc" : [ -74.72617700000001, 39.095095 ], "pop" : 1813, "state" : "NJ" }
+{ "_id" : "08203", "city" : "BRIGANTINE", "loc" : [ -74.377644, 39.403709 ], "pop" : 9388, "state" : "NJ" }
+{ "_id" : "08204", "city" : "NORTH CAPE MAY", "loc" : [ -74.92624000000001, 38.969208 ], "pop" : 18084, "state" : "NJ" }
+{ "_id" : "08210", "city" : "CAPE MAY COURT H", "loc" : [ -74.826846, 39.101434 ], "pop" : 13521, "state" : "NJ" }
+{ "_id" : "08215", "city" : "EGG HARBOR CITY", "loc" : [ -74.617709, 39.533123 ], "pop" : 10362, "state" : "NJ" }
+{ "_id" : "08221", "city" : "LINWOOD", "loc" : [ -74.580744, 39.346883 ], "pop" : 9353, "state" : "NJ" }
+{ "_id" : "08223", "city" : "MARMORA", "loc" : [ -74.659297, 39.258562 ], "pop" : 4420, "state" : "NJ" }
+{ "_id" : "08225", "city" : "NORTHFIELD", "loc" : [ -74.55523700000001, 39.370256 ], "pop" : 7503, "state" : "NJ" }
+{ "_id" : "08226", "city" : "OCEAN CITY", "loc" : [ -74.587514, 39.270894 ], "pop" : 15512, "state" : "NJ" }
+{ "_id" : "08230", "city" : "OCEAN VIEW", "loc" : [ -74.707548, 39.215425 ], "pop" : 4443, "state" : "NJ" }
+{ "_id" : "08232", "city" : "PLEASANTVILLE", "loc" : [ -74.55236499999999, 39.401518 ], "pop" : 30292, "state" : "NJ" }
+{ "_id" : "08241", "city" : "PORT REPUBLIC", "loc" : [ -74.490263, 39.527196 ], "pop" : 992, "state" : "NJ" }
+{ "_id" : "08242", "city" : "RIO GRANDE", "loc" : [ -74.875642, 39.019583 ], "pop" : 2943, "state" : "NJ" }
+{ "_id" : "08243", "city" : "TOWNSENDS INLET", "loc" : [ -74.701432, 39.144929 ], "pop" : 2675, "state" : "NJ" }
+{ "_id" : "08244", "city" : "SOMERS POINT", "loc" : [ -74.600796, 39.322308 ], "pop" : 11227, "state" : "NJ" }
+{ "_id" : "08247", "city" : "STONE HARBOR", "loc" : [ -74.762049, 39.053338 ], "pop" : 1076, "state" : "NJ" }
+{ "_id" : "08248", "city" : "STRATHMERE", "loc" : [ -74.655446, 39.199246 ], "pop" : 163, "state" : "NJ" }
+{ "_id" : "08251", "city" : "VILLAS", "loc" : [ -74.935396, 39.021943 ], "pop" : 9308, "state" : "NJ" }
+{ "_id" : "08260", "city" : "NORTH WILDWOOD", "loc" : [ -74.819096, 38.989901 ], "pop" : 14194, "state" : "NJ" }
+{ "_id" : "08270", "city" : "CORBIN CITY", "loc" : [ -74.802628, 39.248915 ], "pop" : 7370, "state" : "NJ" }
+{ "_id" : "08302", "city" : "SEABROOK", "loc" : [ -75.22672799999999, 39.445294 ], "pop" : 45485, "state" : "NJ" }
+{ "_id" : "08310", "city" : "BUENA", "loc" : [ -74.889495, 39.536988 ], "pop" : 1501, "state" : "NJ" }
+{ "_id" : "08311", "city" : "CEDARVILLE", "loc" : [ -75.19936199999999, 39.337028 ], "pop" : 1521, "state" : "NJ" }
+{ "_id" : "08312", "city" : "CLAYTON", "loc" : [ -75.094188, 39.658969 ], "pop" : 6584, "state" : "NJ" }
+{ "_id" : "08314", "city" : "DELMONT", "loc" : [ -74.970505, 39.202258 ], "pop" : 135, "state" : "NJ" }
+{ "_id" : "08317", "city" : "DOROTHY", "loc" : [ -74.831577, 39.40313 ], "pop" : 1018, "state" : "NJ" }
+{ "_id" : "08318", "city" : "ELMER", "loc" : [ -75.163023, 39.569146 ], "pop" : 8050, "state" : "NJ" }
+{ "_id" : "08319", "city" : "ESTELL MANOR", "loc" : [ -74.816512, 39.37825 ], "pop" : 1130, "state" : "NJ" }
+{ "_id" : "08322", "city" : "FRANKLINVILLE", "loc" : [ -75.04088, 39.615557 ], "pop" : 10484, "state" : "NJ" }
+{ "_id" : "08324", "city" : "HEISLERVILLE", "loc" : [ -74.993942, 39.245013 ], "pop" : 264, "state" : "NJ" }
+{ "_id" : "08326", "city" : "LANDISVILLE", "loc" : [ -74.93768799999999, 39.523942 ], "pop" : 1915, "state" : "NJ" }
+{ "_id" : "08327", "city" : "LEESBURG", "loc" : [ -75.001211, 39.238724 ], "pop" : 49, "state" : "NJ" }
+{ "_id" : "08328", "city" : "MALAGA", "loc" : [ -75.058155, 39.575495 ], "pop" : 1348, "state" : "NJ" }
+{ "_id" : "08330", "city" : "MAYS LANDING", "loc" : [ -74.69619, 39.432011 ], "pop" : 24487, "state" : "NJ" }
+{ "_id" : "08332", "city" : "MILLVILLE", "loc" : [ -75.02931100000001, 39.367313 ], "pop" : 36591, "state" : "NJ" }
+{ "_id" : "08340", "city" : "MILMAY", "loc" : [ -74.866671, 39.445078 ], "pop" : 463, "state" : "NJ" }
+{ "_id" : "08341", "city" : "MINOTOLA", "loc" : [ -74.946685, 39.515512 ], "pop" : 1548, "state" : "NJ" }
+{ "_id" : "08343", "city" : "MONROEVILLE", "loc" : [ -75.156848, 39.644224 ], "pop" : 5068, "state" : "NJ" }
+{ "_id" : "08344", "city" : "NEWFIELD", "loc" : [ -75.027558, 39.555257 ], "pop" : 5363, "state" : "NJ" }
+{ "_id" : "08345", "city" : "NEWPORT", "loc" : [ -75.17164699999999, 39.283205 ], "pop" : 1190, "state" : "NJ" }
+{ "_id" : "08346", "city" : "NEWTONVILLE", "loc" : [ -74.859049, 39.564477 ], "pop" : 682, "state" : "NJ" }
+{ "_id" : "08349", "city" : "PORT NORRIS", "loc" : [ -75.050608, 39.256263 ], "pop" : 2726, "state" : "NJ" }
+{ "_id" : "08350", "city" : "RICHLAND", "loc" : [ -74.87761500000001, 39.485048 ], "pop" : 1046, "state" : "NJ" }
+{ "_id" : "08360", "city" : "VINELAND", "loc" : [ -75.00908699999999, 39.48177 ], "pop" : 56319, "state" : "NJ" }
+{ "_id" : "08401", "city" : "ATLANTIC CITY", "loc" : [ -74.431727, 39.366411 ], "pop" : 31907, "state" : "NJ" }
+{ "_id" : "08402", "city" : "MARGATE CITY", "loc" : [ -74.509038, 39.328621 ], "pop" : 9484, "state" : "NJ" }
+{ "_id" : "08403", "city" : "LONGPORT", "loc" : [ -74.542143, 39.309712 ], "pop" : 318, "state" : "NJ" }
+{ "_id" : "08406", "city" : "VENTNOR CITY", "loc" : [ -74.472343, 39.345992 ], "pop" : 19050, "state" : "NJ" }
+{ "_id" : "08501", "city" : "ALLENTOWN", "loc" : [ -74.59093, 40.158922 ], "pop" : 4041, "state" : "NJ" }
+{ "_id" : "08502", "city" : "BELLE MEAD", "loc" : [ -74.62899299999999, 40.467732 ], "pop" : 12677, "state" : "NJ" }
+{ "_id" : "08505", "city" : "BORDENTOWN", "loc" : [ -74.703249, 40.143141 ], "pop" : 12835, "state" : "NJ" }
+{ "_id" : "08510", "city" : "CLARKSBURG", "loc" : [ -74.434387, 40.199751 ], "pop" : 3364, "state" : "NJ" }
+{ "_id" : "08511", "city" : "COOKSTOWN", "loc" : [ -74.559524, 40.048109 ], "pop" : 262, "state" : "NJ" }
+{ "_id" : "08512", "city" : "CRANBURY", "loc" : [ -74.506531, 40.303868 ], "pop" : 13743, "state" : "NJ" }
+{ "_id" : "08514", "city" : "CREAMRIDGE", "loc" : [ -74.499425, 40.127907 ], "pop" : 3522, "state" : "NJ" }
+{ "_id" : "08515", "city" : "CROSSWICKS", "loc" : [ -74.666838, 40.158353 ], "pop" : 1700, "state" : "NJ" }
+{ "_id" : "08518", "city" : "FLORENCE", "loc" : [ -74.805515, 40.118025 ], "pop" : 5091, "state" : "NJ" }
+{ "_id" : "08520", "city" : "HIGHTSTOWN", "loc" : [ -74.52499299999999, 40.266885 ], "pop" : 25674, "state" : "NJ" }
+{ "_id" : "08525", "city" : "HOPEWELL", "loc" : [ -74.77096299999999, 40.390224 ], "pop" : 3858, "state" : "NJ" }
+{ "_id" : "08526", "city" : "IMLAYSTOWN", "loc" : [ -74.51093899999999, 40.166215 ], "pop" : 17, "state" : "NJ" }
+{ "_id" : "08527", "city" : "JACKSON", "loc" : [ -74.301709, 40.120964 ], "pop" : 33075, "state" : "NJ" }
+{ "_id" : "08528", "city" : "KINGSTON", "loc" : [ -74.61607100000001, 40.380465 ], "pop" : 160, "state" : "NJ" }
+{ "_id" : "08530", "city" : "LAMBERTVILLE", "loc" : [ -74.926605, 40.373122 ], "pop" : 6466, "state" : "NJ" }
+{ "_id" : "08533", "city" : "NEW EGYPT", "loc" : [ -74.506721, 40.071343 ], "pop" : 4601, "state" : "NJ" }
+{ "_id" : "08534", "city" : "PENNINGTON", "loc" : [ -74.794352, 40.333858 ], "pop" : 7690, "state" : "NJ" }
+{ "_id" : "08535", "city" : "PERRINEVILLE", "loc" : [ -74.440381, 40.214971 ], "pop" : 329, "state" : "NJ" }
+{ "_id" : "08536", "city" : "PLAINSBORO", "loc" : [ -74.568836, 40.332432 ], "pop" : 13008, "state" : "NJ" }
+{ "_id" : "08540", "city" : "PRINCETON", "loc" : [ -74.640832, 40.366633 ], "pop" : 33831, "state" : "NJ" }
+{ "_id" : "08542", "city" : "PRINCETON", "loc" : [ -74.659378, 40.353545 ], "pop" : 2675, "state" : "NJ" }
+{ "_id" : "08544", "city" : "PRINCETON UNIVER", "loc" : [ -74.65754, 40.346029 ], "pop" : 4227, "state" : "NJ" }
+{ "_id" : "08550", "city" : "PRINCETON JUNCTI", "loc" : [ -74.61459600000001, 40.297684 ], "pop" : 5807, "state" : "NJ" }
+{ "_id" : "08551", "city" : "RINGOES", "loc" : [ -74.828839, 40.44587 ], "pop" : 5106, "state" : "NJ" }
+{ "_id" : "08553", "city" : "ROCKY HILL", "loc" : [ -74.64004199999999, 40.400985 ], "pop" : 693, "state" : "NJ" }
+{ "_id" : "08554", "city" : "ROEBLING", "loc" : [ -74.777224, 40.115352 ], "pop" : 3826, "state" : "NJ" }
+{ "_id" : "08556", "city" : "ROSEMONT", "loc" : [ -74.991928, 40.422005 ], "pop" : 42, "state" : "NJ" }
+{ "_id" : "08558", "city" : "SKILLMAN", "loc" : [ -74.693828, 40.417312 ], "pop" : 3935, "state" : "NJ" }
+{ "_id" : "08559", "city" : "STOCKTON", "loc" : [ -74.95541900000001, 40.43974 ], "pop" : 6090, "state" : "NJ" }
+{ "_id" : "08560", "city" : "TITUSVILLE", "loc" : [ -74.865469, 40.307728 ], "pop" : 3354, "state" : "NJ" }
+{ "_id" : "08562", "city" : "WRIGHTSTOWN", "loc" : [ -74.573098, 40.071953 ], "pop" : 3116, "state" : "NJ" }
+{ "_id" : "08608", "city" : "TRENTON", "loc" : [ -74.762237, 40.220437 ], "pop" : 827, "state" : "NJ" }
+{ "_id" : "08609", "city" : "HAMILTON", "loc" : [ -74.742598, 40.223338 ], "pop" : 15904, "state" : "NJ" }
+{ "_id" : "08610", "city" : "HAMILTON", "loc" : [ -74.71720500000001, 40.19894 ], "pop" : 29852, "state" : "NJ" }
+{ "_id" : "08611", "city" : "HAMILTON", "loc" : [ -74.751997, 40.207297 ], "pop" : 25084, "state" : "NJ" }
+{ "_id" : "08618", "city" : "TRENTON", "loc" : [ -74.782062, 40.237687 ], "pop" : 40280, "state" : "NJ" }
+{ "_id" : "08619", "city" : "MERCERVILLE", "loc" : [ -74.690377, 40.241977 ], "pop" : 23627, "state" : "NJ" }
+{ "_id" : "08620", "city" : "YARDVILLE", "loc" : [ -74.671699, 40.178477 ], "pop" : 12373, "state" : "NJ" }
+{ "_id" : "08628", "city" : "WEST TRENTON", "loc" : [ -74.82618600000001, 40.267232 ], "pop" : 8335, "state" : "NJ" }
+{ "_id" : "08629", "city" : "HAMILTON", "loc" : [ -74.732764, 40.219843 ], "pop" : 10670, "state" : "NJ" }
+{ "_id" : "08638", "city" : "TRENTON", "loc" : [ -74.762699, 40.251006 ], "pop" : 26982, "state" : "NJ" }
+{ "_id" : "08640", "city" : "FORT DIX", "loc" : [ -74.618296, 40.009946 ], "pop" : 10101, "state" : "NJ" }
+{ "_id" : "08641", "city" : "MC GUIRE AFB", "loc" : [ -74.588195, 40.044026 ], "pop" : 9971, "state" : "NJ" }
+{ "_id" : "08648", "city" : "LAWRENCEVILLE", "loc" : [ -74.723956, 40.277646 ], "pop" : 25497, "state" : "NJ" }
+{ "_id" : "08690", "city" : "HAMILTON", "loc" : [ -74.659138, 40.223852 ], "pop" : 21547, "state" : "NJ" }
+{ "_id" : "08691", "city" : "HAMILTON", "loc" : [ -74.606262, 40.231785 ], "pop" : 6524, "state" : "NJ" }
+{ "_id" : "08701", "city" : "LAKEWOOD", "loc" : [ -74.204199, 40.085043 ], "pop" : 47458, "state" : "NJ" }
+{ "_id" : "08721", "city" : "BAYVILLE", "loc" : [ -74.190529, 39.914708 ], "pop" : 18991, "state" : "NJ" }
+{ "_id" : "08722", "city" : "BEACHWOOD", "loc" : [ -74.196145, 39.930246 ], "pop" : 9324, "state" : "NJ" }
+{ "_id" : "08723", "city" : "OSBORNSVILLE", "loc" : [ -74.12685999999999, 40.040817 ], "pop" : 28128, "state" : "NJ" }
+{ "_id" : "08724", "city" : "BRICK", "loc" : [ -74.11523699999999, 40.087432 ], "pop" : 34507, "state" : "NJ" }
+{ "_id" : "08730", "city" : "BRIELLE", "loc" : [ -74.06351100000001, 40.107727 ], "pop" : 4290, "state" : "NJ" }
+{ "_id" : "08731", "city" : "FORKED RIVER", "loc" : [ -74.197301, 39.844425 ], "pop" : 16664, "state" : "NJ" }
+{ "_id" : "08732", "city" : "ISLAND HEIGHTS", "loc" : [ -74.146787, 39.943197 ], "pop" : 1470, "state" : "NJ" }
+{ "_id" : "08733", "city" : "LAKEHURST NAEC", "loc" : [ -74.29090100000001, 40.020054 ], "pop" : 14205, "state" : "NJ" }
+{ "_id" : "08734", "city" : "LANOKA HARBOR", "loc" : [ -74.166765, 39.861993 ], "pop" : 5473, "state" : "NJ" }
+{ "_id" : "08735", "city" : "LAVALLETTE", "loc" : [ -74.070424, 39.977486 ], "pop" : 3985, "state" : "NJ" }
+{ "_id" : "08736", "city" : "MANASQUAN", "loc" : [ -74.061055, 40.121693 ], "pop" : 10341, "state" : "NJ" }
+{ "_id" : "08738", "city" : "MANTOLOKING", "loc" : [ -74.05618800000001, 40.026125 ], "pop" : 1186, "state" : "NJ" }
+{ "_id" : "08740", "city" : "OCEAN GATE", "loc" : [ -74.13512799999999, 39.925975 ], "pop" : 2028, "state" : "NJ" }
+{ "_id" : "08741", "city" : "PINE BEACH", "loc" : [ -74.167992, 39.934746 ], "pop" : 2354, "state" : "NJ" }
+{ "_id" : "08742", "city" : "BAY HEAD", "loc" : [ -74.065719, 40.080226 ], "pop" : 25071, "state" : "NJ" }
+{ "_id" : "08750", "city" : "SEA GIRT", "loc" : [ -74.043604, 40.134522 ], "pop" : 3624, "state" : "NJ" }
+{ "_id" : "08751", "city" : "SEASIDE HEIGHTS", "loc" : [ -74.07647900000001, 39.946639 ], "pop" : 4044, "state" : "NJ" }
+{ "_id" : "08752", "city" : "SEASIDE PARK", "loc" : [ -74.079521, 39.922175 ], "pop" : 2369, "state" : "NJ" }
+{ "_id" : "08753", "city" : "TOMS RIVER", "loc" : [ -74.156508, 39.977083 ], "pop" : 58001, "state" : "NJ" }
+{ "_id" : "08755", "city" : "TOMS RIVER", "loc" : [ -74.222819, 39.999946 ], "pop" : 14892, "state" : "NJ" }
+{ "_id" : "08757", "city" : "TOMS RIVER", "loc" : [ -74.25116800000001, 39.971471 ], "pop" : 29794, "state" : "NJ" }
+{ "_id" : "08758", "city" : "WARETOWN", "loc" : [ -74.195376, 39.789646 ], "pop" : 4774, "state" : "NJ" }
+{ "_id" : "08759", "city" : "WHITING", "loc" : [ -74.360713, 39.950983 ], "pop" : 16321, "state" : "NJ" }
+{ "_id" : "08801", "city" : "ANNANDALE", "loc" : [ -74.88551200000001, 40.628731 ], "pop" : 6465, "state" : "NJ" }
+{ "_id" : "08802", "city" : "PATTENBURG", "loc" : [ -75.01585, 40.650175 ], "pop" : 2176, "state" : "NJ" }
+{ "_id" : "08804", "city" : "BLOOMSBURY", "loc" : [ -75.09663999999999, 40.64366 ], "pop" : 2111, "state" : "NJ" }
+{ "_id" : "08805", "city" : "BOUND BROOK", "loc" : [ -74.53973499999999, 40.568115 ], "pop" : 11275, "state" : "NJ" }
+{ "_id" : "08807", "city" : "BRIDGEWATER", "loc" : [ -74.626741, 40.590388 ], "pop" : 26496, "state" : "NJ" }
+{ "_id" : "08809", "city" : "CLINTON", "loc" : [ -74.908846, 40.641194 ], "pop" : 2994, "state" : "NJ" }
+{ "_id" : "08810", "city" : "DAYTON", "loc" : [ -74.51110199999999, 40.38249 ], "pop" : 6198, "state" : "NJ" }
+{ "_id" : "08812", "city" : "GREEN BROOK", "loc" : [ -74.47187, 40.594237 ], "pop" : 10892, "state" : "NJ" }
+{ "_id" : "08816", "city" : "EAST BRUNSWICK", "loc" : [ -74.406381, 40.428395 ], "pop" : 42319, "state" : "NJ" }
+{ "_id" : "08817", "city" : "EDISON", "loc" : [ -74.39728599999999, 40.517079 ], "pop" : 41245, "state" : "NJ" }
+{ "_id" : "08820", "city" : "EDISON", "loc" : [ -74.358863, 40.57804 ], "pop" : 33581, "state" : "NJ" }
+{ "_id" : "08822", "city" : "FLEMINGTON", "loc" : [ -74.845316, 40.517976 ], "pop" : 23579, "state" : "NJ" }
+{ "_id" : "08823", "city" : "FRANKLIN PARK", "loc" : [ -74.536908, 40.442097 ], "pop" : 154, "state" : "NJ" }
+{ "_id" : "08824", "city" : "KENDALL PARK", "loc" : [ -74.552921, 40.4208 ], "pop" : 10272, "state" : "NJ" }
+{ "_id" : "08825", "city" : "FRENCHTOWN", "loc" : [ -75.03246799999999, 40.520795 ], "pop" : 4383, "state" : "NJ" }
+{ "_id" : "08826", "city" : "GLEN GARDNER", "loc" : [ -74.916207, 40.713437 ], "pop" : 5525, "state" : "NJ" }
+{ "_id" : "08827", "city" : "HAMPTON", "loc" : [ -74.962221, 40.677351 ], "pop" : 4441, "state" : "NJ" }
+{ "_id" : "08828", "city" : "HELMETTA", "loc" : [ -74.420393, 40.377742 ], "pop" : 1211, "state" : "NJ" }
+{ "_id" : "08829", "city" : "HIGH BRIDGE", "loc" : [ -74.89366699999999, 40.668438 ], "pop" : 3886, "state" : "NJ" }
+{ "_id" : "08830", "city" : "ISELIN", "loc" : [ -74.316677, 40.571593 ], "pop" : 16313, "state" : "NJ" }
+{ "_id" : "08831", "city" : "JAMESBURG", "loc" : [ -74.43356799999999, 40.342475 ], "pop" : 15743, "state" : "NJ" }
+{ "_id" : "08832", "city" : "KEASBEY", "loc" : [ -74.302119, 40.519171 ], "pop" : 2746, "state" : "NJ" }
+{ "_id" : "08833", "city" : "LEBANON", "loc" : [ -74.829035, 40.646623 ], "pop" : 7270, "state" : "NJ" }
+{ "_id" : "08835", "city" : "MANVILLE", "loc" : [ -74.593377, 40.539871 ], "pop" : 10419, "state" : "NJ" }
+{ "_id" : "08836", "city" : "MARTINSVILLE", "loc" : [ -74.557191, 40.599962 ], "pop" : 3024, "state" : "NJ" }
+{ "_id" : "08837", "city" : "EDISON", "loc" : [ -74.337503, 40.532476 ], "pop" : 9447, "state" : "NJ" }
+{ "_id" : "08840", "city" : "METUCHEN", "loc" : [ -74.351721, 40.54493 ], "pop" : 20017, "state" : "NJ" }
+{ "_id" : "08846", "city" : "MIDDLESEX", "loc" : [ -74.500835, 40.575882 ], "pop" : 13055, "state" : "NJ" }
+{ "_id" : "08848", "city" : "MILFORD", "loc" : [ -75.102519, 40.592942 ], "pop" : 7586, "state" : "NJ" }
+{ "_id" : "08850", "city" : "MILLTOWN", "loc" : [ -74.439046, 40.449346 ], "pop" : 8362, "state" : "NJ" }
+{ "_id" : "08852", "city" : "MONMOUTH JUNCTIO", "loc" : [ -74.547021, 40.394391 ], "pop" : 6881, "state" : "NJ" }
+{ "_id" : "08853", "city" : "NESHANIC STATION", "loc" : [ -74.71434000000001, 40.509551 ], "pop" : 9526, "state" : "NJ" }
+{ "_id" : "08854", "city" : "PISCATAWAY", "loc" : [ -74.458996, 40.55152 ], "pop" : 47038, "state" : "NJ" }
+{ "_id" : "08857", "city" : "OLD BRIDGE", "loc" : [ -74.323553, 40.398045 ], "pop" : 33884, "state" : "NJ" }
+{ "_id" : "08859", "city" : "PARLIN", "loc" : [ -74.304981, 40.458701 ], "pop" : 20773, "state" : "NJ" }
+{ "_id" : "08861", "city" : "PERTH AMBOY", "loc" : [ -74.27542699999999, 40.517551 ], "pop" : 43920, "state" : "NJ" }
+{ "_id" : "08863", "city" : "FORDS", "loc" : [ -74.311707, 40.53925 ], "pop" : 13568, "state" : "NJ" }
+{ "_id" : "08865", "city" : "ALPHA", "loc" : [ -75.1741, 40.692819 ], "pop" : 28782, "state" : "NJ" }
+{ "_id" : "08867", "city" : "PITTSTOWN", "loc" : [ -74.957587, 40.599169 ], "pop" : 5635, "state" : "NJ" }
+{ "_id" : "08869", "city" : "RARITAN", "loc" : [ -74.637691, 40.57109 ], "pop" : 6306, "state" : "NJ" }
+{ "_id" : "08872", "city" : "SAYREVILLE", "loc" : [ -74.347808, 40.459958 ], "pop" : 14405, "state" : "NJ" }
+{ "_id" : "08873", "city" : "SOMERSET", "loc" : [ -74.50126, 40.500743 ], "pop" : 36850, "state" : "NJ" }
+{ "_id" : "08876", "city" : "NORTH BRANCH", "loc" : [ -74.645926, 40.549393 ], "pop" : 34212, "state" : "NJ" }
+{ "_id" : "08879", "city" : "LAURENCE HARBOR", "loc" : [ -74.27863499999999, 40.464733 ], "pop" : 20993, "state" : "NJ" }
+{ "_id" : "08880", "city" : "SOUTH BOUND BROO", "loc" : [ -74.529078, 40.552804 ], "pop" : 4330, "state" : "NJ" }
+{ "_id" : "08882", "city" : "SOUTH RIVER", "loc" : [ -74.380099, 40.444363 ], "pop" : 13692, "state" : "NJ" }
+{ "_id" : "08884", "city" : "SPOTSWOOD", "loc" : [ -74.389377, 40.384679 ], "pop" : 13444, "state" : "NJ" }
+{ "_id" : "08886", "city" : "STEWARTSVILLE", "loc" : [ -75.082517, 40.695703 ], "pop" : 3582, "state" : "NJ" }
+{ "_id" : "08887", "city" : "THREE BRIDGES", "loc" : [ -74.79980500000001, 40.52156 ], "pop" : 378, "state" : "NJ" }
+{ "_id" : "08889", "city" : "WHITEHOUSE STATI", "loc" : [ -74.764129, 40.599872 ], "pop" : 8303, "state" : "NJ" }
+{ "_id" : "08901", "city" : "NEW BRUNSWICK", "loc" : [ -74.448193, 40.489073 ], "pop" : 41710, "state" : "NJ" }
+{ "_id" : "08902", "city" : "NORTH BRUNSWICK", "loc" : [ -74.482285, 40.453767 ], "pop" : 31071, "state" : "NJ" }
+{ "_id" : "08904", "city" : "HIGHLAND PARK", "loc" : [ -74.426602, 40.499141 ], "pop" : 13165, "state" : "NJ" }
+{ "_id" : "10001", "city" : "NEW YORK", "loc" : [ -73.99670500000001, 40.74838 ], "pop" : 18913, "state" : "NY" }
+{ "_id" : "10002", "city" : "NEW YORK", "loc" : [ -73.98768099999999, 40.715231 ], "pop" : 84143, "state" : "NY" }
+{ "_id" : "10003", "city" : "NEW YORK", "loc" : [ -73.989223, 40.731253 ], "pop" : 51224, "state" : "NY" }
+{ "_id" : "10004", "city" : "GOVERNORS ISLAND", "loc" : [ -74.019025, 40.693604 ], "pop" : 3593, "state" : "NY" }
+{ "_id" : "10005", "city" : "NEW YORK", "loc" : [ -74.00834399999999, 40.705649 ], "pop" : 202, "state" : "NY" }
+{ "_id" : "10006", "city" : "NEW YORK", "loc" : [ -74.013474, 40.708451 ], "pop" : 119, "state" : "NY" }
+{ "_id" : "10007", "city" : "NEW YORK", "loc" : [ -74.00702200000001, 40.713905 ], "pop" : 3374, "state" : "NY" }
+{ "_id" : "10009", "city" : "NEW YORK", "loc" : [ -73.979591, 40.726188 ], "pop" : 57426, "state" : "NY" }
+{ "_id" : "10010", "city" : "NEW YORK", "loc" : [ -73.981328, 40.737476 ], "pop" : 24907, "state" : "NY" }
+{ "_id" : "10011", "city" : "NEW YORK", "loc" : [ -73.99963, 40.740225 ], "pop" : 46560, "state" : "NY" }
+{ "_id" : "10012", "city" : "NEW YORK", "loc" : [ -73.998284, 40.72553 ], "pop" : 26365, "state" : "NY" }
+{ "_id" : "10013", "city" : "NEW YORK", "loc" : [ -74.002529, 40.718511 ], "pop" : 21860, "state" : "NY" }
+{ "_id" : "10014", "city" : "NEW YORK", "loc" : [ -74.005421, 40.73393 ], "pop" : 31147, "state" : "NY" }
+{ "_id" : "10016", "city" : "NEW YORK", "loc" : [ -73.978134, 40.744281 ], "pop" : 51561, "state" : "NY" }
+{ "_id" : "10017", "city" : "NEW YORK", "loc" : [ -73.97066100000001, 40.75172 ], "pop" : 12465, "state" : "NY" }
+{ "_id" : "10018", "city" : "NEW YORK", "loc" : [ -73.992503, 40.754713 ], "pop" : 4834, "state" : "NY" }
+{ "_id" : "10019", "city" : "NEW YORK", "loc" : [ -73.985834, 40.765069 ], "pop" : 36602, "state" : "NY" }
+{ "_id" : "10020", "city" : "NEW YORK", "loc" : [ -73.982347, 40.759729 ], "pop" : 393, "state" : "NY" }
+{ "_id" : "10021", "city" : "NEW YORK", "loc" : [ -73.958805, 40.768476 ], "pop" : 106564, "state" : "NY" }
+{ "_id" : "10022", "city" : "NEW YORK", "loc" : [ -73.965703, 40.757091 ], "pop" : 31870, "state" : "NY" }
+{ "_id" : "10023", "city" : "NEW YORK", "loc" : [ -73.982652, 40.77638 ], "pop" : 57385, "state" : "NY" }
+{ "_id" : "10024", "city" : "NEW YORK", "loc" : [ -73.97638499999999, 40.786446 ], "pop" : 65141, "state" : "NY" }
+{ "_id" : "10025", "city" : "NEW YORK", "loc" : [ -73.968312, 40.797466 ], "pop" : 100027, "state" : "NY" }
+{ "_id" : "10026", "city" : "NEW YORK", "loc" : [ -73.953069, 40.801942 ], "pop" : 28453, "state" : "NY" }
+{ "_id" : "10027", "city" : "NEW YORK", "loc" : [ -73.954978, 40.811556 ], "pop" : 54631, "state" : "NY" }
+{ "_id" : "10028", "city" : "NEW YORK", "loc" : [ -73.952866, 40.776267 ], "pop" : 42757, "state" : "NY" }
+{ "_id" : "10029", "city" : "NEW YORK", "loc" : [ -73.94475, 40.791817 ], "pop" : 74643, "state" : "NY" }
+{ "_id" : "10030", "city" : "NEW YORK", "loc" : [ -73.94259700000001, 40.818333 ], "pop" : 21132, "state" : "NY" }
+{ "_id" : "10031", "city" : "NEW YORK", "loc" : [ -73.950712, 40.82455 ], "pop" : 55989, "state" : "NY" }
+{ "_id" : "10032", "city" : "NEW YORK", "loc" : [ -73.94197800000001, 40.83819 ], "pop" : 61332, "state" : "NY" }
+{ "_id" : "10033", "city" : "NEW YORK", "loc" : [ -73.935649, 40.84955 ], "pop" : 58648, "state" : "NY" }
+{ "_id" : "10034", "city" : "NEW YORK", "loc" : [ -73.922077, 40.866222 ], "pop" : 41131, "state" : "NY" }
+{ "_id" : "10035", "city" : "NEW YORK", "loc" : [ -73.93709800000001, 40.801116 ], "pop" : 28099, "state" : "NY" }
+{ "_id" : "10036", "city" : "NEW YORK", "loc" : [ -73.991826, 40.759724 ], "pop" : 16748, "state" : "NY" }
+{ "_id" : "10037", "city" : "NEW YORK", "loc" : [ -73.93810000000001, 40.813491 ], "pop" : 14982, "state" : "NY" }
+{ "_id" : "10038", "city" : "NEW YORK", "loc" : [ -74.00129800000001, 40.710092 ], "pop" : 14015, "state" : "NY" }
+{ "_id" : "10039", "city" : "NEW YORK", "loc" : [ -73.938266, 40.826458 ], "pop" : 25293, "state" : "NY" }
+{ "_id" : "10040", "city" : "NEW YORK", "loc" : [ -73.92960100000001, 40.858308 ], "pop" : 39780, "state" : "NY" }
+{ "_id" : "10044", "city" : "NEW YORK", "loc" : [ -73.949136, 40.762998 ], "pop" : 8190, "state" : "NY" }
+{ "_id" : "10128", "city" : "NEW YORK", "loc" : [ -73.95111199999999, 40.781618 ], "pop" : 52311, "state" : "NY" }
+{ "_id" : "10280", "city" : "NEW YORK", "loc" : [ -74.016323, 40.710537 ], "pop" : 5574, "state" : "NY" }
+{ "_id" : "10301", "city" : "STATEN ISLAND", "loc" : [ -74.092663, 40.631602 ], "pop" : 35314, "state" : "NY" }
+{ "_id" : "10302", "city" : "STATEN ISLAND", "loc" : [ -74.137918, 40.630597 ], "pop" : 13369, "state" : "NY" }
+{ "_id" : "10303", "city" : "STATEN ISLAND", "loc" : [ -74.160679, 40.630062 ], "pop" : 17695, "state" : "NY" }
+{ "_id" : "10304", "city" : "STATEN ISLAND", "loc" : [ -74.087836, 40.610249 ], "pop" : 33028, "state" : "NY" }
+{ "_id" : "10305", "city" : "STATEN ISLAND", "loc" : [ -74.076795, 40.597296 ], "pop" : 30513, "state" : "NY" }
+{ "_id" : "10306", "city" : "STATEN ISLAND", "loc" : [ -74.118386, 40.568183 ], "pop" : 49849, "state" : "NY" }
+{ "_id" : "10307", "city" : "STATEN ISLAND", "loc" : [ -74.244482, 40.508452 ], "pop" : 7627, "state" : "NY" }
+{ "_id" : "10308", "city" : "STATEN ISLAND", "loc" : [ -74.152649, 40.55181 ], "pop" : 24947, "state" : "NY" }
+{ "_id" : "10309", "city" : "STATEN ISLAND", "loc" : [ -74.211572, 40.535179 ], "pop" : 18651, "state" : "NY" }
+{ "_id" : "10310", "city" : "STATEN ISLAND", "loc" : [ -74.11715, 40.632427 ], "pop" : 20282, "state" : "NY" }
+{ "_id" : "10312", "city" : "STATEN ISLAND", "loc" : [ -74.179165, 40.545745 ], "pop" : 49584, "state" : "NY" }
+{ "_id" : "10314", "city" : "STATEN ISLAND", "loc" : [ -74.147218, 40.603915 ], "pop" : 78118, "state" : "NY" }
+{ "_id" : "10451", "city" : "BRONX", "loc" : [ -73.921735, 40.8222 ], "pop" : 42854, "state" : "NY" }
+{ "_id" : "10452", "city" : "BRONX", "loc" : [ -73.921555, 40.837594 ], "pop" : 55890, "state" : "NY" }
+{ "_id" : "10453", "city" : "BRONX", "loc" : [ -73.912937, 40.852047 ], "pop" : 70544, "state" : "NY" }
+{ "_id" : "10454", "city" : "BRONX", "loc" : [ -73.919821, 40.808549 ], "pop" : 35994, "state" : "NY" }
+{ "_id" : "10455", "city" : "BRONX", "loc" : [ -73.907172, 40.815309 ], "pop" : 31882, "state" : "NY" }
+{ "_id" : "10456", "city" : "BRONX", "loc" : [ -73.909893, 40.831557 ], "pop" : 70157, "state" : "NY" }
+{ "_id" : "10457", "city" : "BRONX", "loc" : [ -73.899907, 40.848635 ], "pop" : 62133, "state" : "NY" }
+{ "_id" : "10458", "city" : "BRONX", "loc" : [ -73.889464, 40.863307 ], "pop" : 70612, "state" : "NY" }
+{ "_id" : "10459", "city" : "BRONX", "loc" : [ -73.894047, 40.824699 ], "pop" : 30983, "state" : "NY" }
+{ "_id" : "10460", "city" : "BRONX", "loc" : [ -73.879409, 40.840949 ], "pop" : 47250, "state" : "NY" }
+{ "_id" : "10461", "city" : "BRONX", "loc" : [ -73.840953, 40.846506 ], "pop" : 45273, "state" : "NY" }
+{ "_id" : "10462", "city" : "BRONX", "loc" : [ -73.860185, 40.843369 ], "pop" : 61478, "state" : "NY" }
+{ "_id" : "10463", "city" : "BRONX", "loc" : [ -73.90673700000001, 40.879812 ], "pop" : 67435, "state" : "NY" }
+{ "_id" : "10464", "city" : "BRONX", "loc" : [ -73.787436, 40.846941 ], "pop" : 4113, "state" : "NY" }
+{ "_id" : "10465", "city" : "BRONX", "loc" : [ -73.819581, 40.826065 ], "pop" : 37457, "state" : "NY" }
+{ "_id" : "10466", "city" : "BRONX", "loc" : [ -73.85033300000001, 40.890375 ], "pop" : 58394, "state" : "NY" }
+{ "_id" : "10467", "city" : "BRONX", "loc" : [ -73.871242, 40.873671 ], "pop" : 85710, "state" : "NY" }
+{ "_id" : "10468", "city" : "BRONX", "loc" : [ -73.90025900000001, 40.866231 ], "pop" : 65854, "state" : "NY" }
+{ "_id" : "10469", "city" : "BRONX", "loc" : [ -73.849465, 40.870193 ], "pop" : 53962, "state" : "NY" }
+{ "_id" : "10470", "city" : "BRONX", "loc" : [ -73.862194, 40.900029 ], "pop" : 13254, "state" : "NY" }
+{ "_id" : "10471", "city" : "BRONX", "loc" : [ -73.905283, 40.901084 ], "pop" : 23348, "state" : "NY" }
+{ "_id" : "10472", "city" : "BRONX", "loc" : [ -73.871557, 40.829464 ], "pop" : 61122, "state" : "NY" }
+{ "_id" : "10473", "city" : "BRONX", "loc" : [ -73.860626, 40.819364 ], "pop" : 53981, "state" : "NY" }
+{ "_id" : "10474", "city" : "BRONX", "loc" : [ -73.886376, 40.801518 ], "pop" : 22823, "state" : "NY" }
+{ "_id" : "10475", "city" : "BRONX", "loc" : [ -73.827817, 40.872903 ], "pop" : 37045, "state" : "NY" }
+{ "_id" : "10501", "city" : "AMAWALK", "loc" : [ -73.761079, 41.294618 ], "pop" : 745, "state" : "NY" }
+{ "_id" : "10502", "city" : "ARDSLEY", "loc" : [ -73.841311, 41.011332 ], "pop" : 5529, "state" : "NY" }
+{ "_id" : "10504", "city" : "ARMONK", "loc" : [ -73.700942, 41.136002 ], "pop" : 7077, "state" : "NY" }
+{ "_id" : "10506", "city" : "BEDFORD", "loc" : [ -73.635548, 41.190913 ], "pop" : 4332, "state" : "NY" }
+{ "_id" : "10507", "city" : "BEDFORD HILLS", "loc" : [ -73.691517, 41.234439 ], "pop" : 6161, "state" : "NY" }
+{ "_id" : "10509", "city" : "BREWSTER", "loc" : [ -73.59917900000001, 41.409704 ], "pop" : 15852, "state" : "NY" }
+{ "_id" : "10510", "city" : "BRIARCLIFF MANOR", "loc" : [ -73.83495600000001, 41.144364 ], "pop" : 8509, "state" : "NY" }
+{ "_id" : "10511", "city" : "BUCHANAN", "loc" : [ -73.941238, 41.258285 ], "pop" : 2008, "state" : "NY" }
+{ "_id" : "10512", "city" : "CARMEL", "loc" : [ -73.68152600000001, 41.443216 ], "pop" : 20716, "state" : "NY" }
+{ "_id" : "10514", "city" : "CHAPPAQUA", "loc" : [ -73.771458, 41.170497 ], "pop" : 11097, "state" : "NY" }
+{ "_id" : "10516", "city" : "COLD SPRING", "loc" : [ -73.933485, 41.44142 ], "pop" : 4904, "state" : "NY" }
+{ "_id" : "10518", "city" : "CROSS RIVER", "loc" : [ -73.60202700000001, 41.27218 ], "pop" : 691, "state" : "NY" }
+{ "_id" : "10520", "city" : "CROTON ON HUDSON", "loc" : [ -73.892408, 41.218037 ], "pop" : 12527, "state" : "NY" }
+{ "_id" : "10522", "city" : "DOBBS FERRY", "loc" : [ -73.866494, 41.011835 ], "pop" : 9896, "state" : "NY" }
+{ "_id" : "10523", "city" : "ELMSFORD", "loc" : [ -73.813597, 41.057171 ], "pop" : 6266, "state" : "NY" }
+{ "_id" : "10524", "city" : "GARRISON", "loc" : [ -73.92000299999999, 41.362065 ], "pop" : 3572, "state" : "NY" }
+{ "_id" : "10527", "city" : "GRANITE SPRINGS", "loc" : [ -73.75300799999999, 41.309791 ], "pop" : 963, "state" : "NY" }
+{ "_id" : "10528", "city" : "HARRISON", "loc" : [ -73.718068, 40.971876 ], "pop" : 11601, "state" : "NY" }
+{ "_id" : "10530", "city" : "HARTSDALE", "loc" : [ -73.80740400000001, 41.019658 ], "pop" : 13995, "state" : "NY" }
+{ "_id" : "10532", "city" : "HAWTHORNE", "loc" : [ -73.80168500000001, 41.095316 ], "pop" : 7258, "state" : "NY" }
+{ "_id" : "10533", "city" : "IRVINGTON", "loc" : [ -73.859666, 41.038113 ], "pop" : 7498, "state" : "NY" }
+{ "_id" : "10535", "city" : "JEFFERSON VALLEY", "loc" : [ -73.794697, 41.338522 ], "pop" : 213, "state" : "NY" }
+{ "_id" : "10536", "city" : "KATONAH", "loc" : [ -73.68411500000001, 41.270884 ], "pop" : 12263, "state" : "NY" }
+{ "_id" : "10537", "city" : "LAKE PEEKSKILL", "loc" : [ -73.883787, 41.337437 ], "pop" : 1604, "state" : "NY" }
+{ "_id" : "10538", "city" : "LARCHMONT", "loc" : [ -73.75715, 40.935055 ], "pop" : 16840, "state" : "NY" }
+{ "_id" : "10541", "city" : "MAHOPAC", "loc" : [ -73.750755, 41.371708 ], "pop" : 23687, "state" : "NY" }
+{ "_id" : "10543", "city" : "MAMARONECK", "loc" : [ -73.73503700000001, 40.952481 ], "pop" : 18193, "state" : "NY" }
+{ "_id" : "10546", "city" : "MILLWOOD", "loc" : [ -73.792626, 41.201519 ], "pop" : 681, "state" : "NY" }
+{ "_id" : "10547", "city" : "MOHEGAN LAKE", "loc" : [ -73.850836, 41.314348 ], "pop" : 5753, "state" : "NY" }
+{ "_id" : "10548", "city" : "MONTROSE", "loc" : [ -73.944593, 41.249585 ], "pop" : 4350, "state" : "NY" }
+{ "_id" : "10549", "city" : "MOUNT KISCO", "loc" : [ -73.729921, 41.204966 ], "pop" : 14361, "state" : "NY" }
+{ "_id" : "10550", "city" : "MOUNT VERNON", "loc" : [ -73.83796100000001, 40.907863 ], "pop" : 37889, "state" : "NY" }
+{ "_id" : "10552", "city" : "MOUNT VERNON", "loc" : [ -73.829919, 40.923056 ], "pop" : 18167, "state" : "NY" }
+{ "_id" : "10553", "city" : "MOUNT VERNON", "loc" : [ -73.82211100000001, 40.908645 ], "pop" : 12452, "state" : "NY" }
+{ "_id" : "10560", "city" : "NORTH SALEM", "loc" : [ -73.592947, 41.341388 ], "pop" : 2601, "state" : "NY" }
+{ "_id" : "10562", "city" : "OSSINING", "loc" : [ -73.853791, 41.167344 ], "pop" : 29926, "state" : "NY" }
+{ "_id" : "10566", "city" : "CORTLANDT MANOR", "loc" : [ -73.902562, 41.293722 ], "pop" : 37431, "state" : "NY" }
+{ "_id" : "10570", "city" : "PLEASANTVILLE", "loc" : [ -73.78448400000001, 41.134977 ], "pop" : 11812, "state" : "NY" }
+{ "_id" : "10573", "city" : "RYE BROOK", "loc" : [ -73.672045, 41.007755 ], "pop" : 32552, "state" : "NY" }
+{ "_id" : "10576", "city" : "POUND RIDGE", "loc" : [ -73.573215, 41.204196 ], "pop" : 4720, "state" : "NY" }
+{ "_id" : "10577", "city" : "PURCHASE", "loc" : [ -73.71562900000001, 41.038396 ], "pop" : 4453, "state" : "NY" }
+{ "_id" : "10578", "city" : "PURDYS", "loc" : [ -73.654313, 41.322427 ], "pop" : 2534, "state" : "NY" }
+{ "_id" : "10579", "city" : "PUTNAM VALLEY", "loc" : [ -73.85024, 41.372815 ], "pop" : 7453, "state" : "NY" }
+{ "_id" : "10580", "city" : "RYE", "loc" : [ -73.690721, 40.973403 ], "pop" : 16479, "state" : "NY" }
+{ "_id" : "10583", "city" : "HEATHCOTE", "loc" : [ -73.797566, 40.988365 ], "pop" : 35302, "state" : "NY" }
+{ "_id" : "10588", "city" : "SHRUB OAK", "loc" : [ -73.82732, 41.328608 ], "pop" : 2103, "state" : "NY" }
+{ "_id" : "10589", "city" : "SOMERS", "loc" : [ -73.695145, 41.334568 ], "pop" : 6618, "state" : "NY" }
+{ "_id" : "10590", "city" : "SOUTH SALEM", "loc" : [ -73.54022399999999, 41.255261 ], "pop" : 6936, "state" : "NY" }
+{ "_id" : "10591", "city" : "NORTH TARRYTOWN", "loc" : [ -73.859335, 41.078108 ], "pop" : 20080, "state" : "NY" }
+{ "_id" : "10594", "city" : "THORNWOOD", "loc" : [ -73.773329, 41.118163 ], "pop" : 5455, "state" : "NY" }
+{ "_id" : "10595", "city" : "VALHALLA", "loc" : [ -73.777596, 41.085559 ], "pop" : 5255, "state" : "NY" }
+{ "_id" : "10597", "city" : "WACCABUC", "loc" : [ -73.603207, 41.303208 ], "pop" : 415, "state" : "NY" }
+{ "_id" : "10598", "city" : "YORKTOWN HEIGHTS", "loc" : [ -73.79239800000001, 41.299947 ], "pop" : 28501, "state" : "NY" }
+{ "_id" : "10601", "city" : "WHITE PLAINS", "loc" : [ -73.765231, 41.032955 ], "pop" : 8397, "state" : "NY" }
+{ "_id" : "10603", "city" : "WHITE PLAINS", "loc" : [ -73.77758, 41.049913 ], "pop" : 14342, "state" : "NY" }
+{ "_id" : "10604", "city" : "EAST WHITE PLAIN", "loc" : [ -73.750727, 41.043295 ], "pop" : 8899, "state" : "NY" }
+{ "_id" : "10605", "city" : "WHITE PLAINS", "loc" : [ -73.755247, 41.014053 ], "pop" : 17843, "state" : "NY" }
+{ "_id" : "10606", "city" : "WHITE PLAINS", "loc" : [ -73.778097, 41.024714 ], "pop" : 13436, "state" : "NY" }
+{ "_id" : "10607", "city" : "WHITE PLAINS", "loc" : [ -73.81169199999999, 41.039813 ], "pop" : 7148, "state" : "NY" }
+{ "_id" : "10701", "city" : "YONKERS", "loc" : [ -73.888317, 40.940716 ], "pop" : 59476, "state" : "NY" }
+{ "_id" : "10703", "city" : "YONKERS", "loc" : [ -73.88516300000001, 40.951763 ], "pop" : 19958, "state" : "NY" }
+{ "_id" : "10704", "city" : "YONKERS", "loc" : [ -73.859347, 40.917633 ], "pop" : 31604, "state" : "NY" }
+{ "_id" : "10705", "city" : "YONKERS", "loc" : [ -73.89504100000001, 40.917665 ], "pop" : 36141, "state" : "NY" }
+{ "_id" : "10706", "city" : "HASTINGS ON HUDS", "loc" : [ -73.875912, 40.99071 ], "pop" : 8546, "state" : "NY" }
+{ "_id" : "10707", "city" : "TUCKAHOE", "loc" : [ -73.819771, 40.95691 ], "pop" : 15275, "state" : "NY" }
+{ "_id" : "10708", "city" : "BRONXVILLE", "loc" : [ -73.83533199999999, 40.939133 ], "pop" : 20406, "state" : "NY" }
+{ "_id" : "10709", "city" : "EASTCHESTER", "loc" : [ -73.80858000000001, 40.954966 ], "pop" : 2515, "state" : "NY" }
+{ "_id" : "10710", "city" : "YONKERS", "loc" : [ -73.843435, 40.965574 ], "pop" : 24952, "state" : "NY" }
+{ "_id" : "10801", "city" : "NEW ROCHELLE", "loc" : [ -73.787729, 40.916628 ], "pop" : 30929, "state" : "NY" }
+{ "_id" : "10803", "city" : "PELHAM", "loc" : [ -73.807304, 40.904455 ], "pop" : 11997, "state" : "NY" }
+{ "_id" : "10804", "city" : "NEW ROCHELLE", "loc" : [ -73.786018, 40.948335 ], "pop" : 14359, "state" : "NY" }
+{ "_id" : "10805", "city" : "NEW ROCHELLE", "loc" : [ -73.781043, 40.900236 ], "pop" : 18471, "state" : "NY" }
+{ "_id" : "10901", "city" : "SUFFERN", "loc" : [ -74.124098, 41.117654 ], "pop" : 21296, "state" : "NY" }
+{ "_id" : "10911", "city" : "BEAR MOUNTAIN", "loc" : [ -73.99610800000001, 41.306734 ], "pop" : 14, "state" : "NY" }
+{ "_id" : "10913", "city" : "BLAUVELT", "loc" : [ -73.962924, 41.062597 ], "pop" : 4770, "state" : "NY" }
+{ "_id" : "10916", "city" : "CAMPBELL HALL", "loc" : [ -74.250466, 41.442993 ], "pop" : 3065, "state" : "NY" }
+{ "_id" : "10917", "city" : "CENTRAL VALLEY", "loc" : [ -74.12203599999999, 41.326836 ], "pop" : 1407, "state" : "NY" }
+{ "_id" : "10918", "city" : "CHESTER", "loc" : [ -74.26511600000001, 41.355381 ], "pop" : 9196, "state" : "NY" }
+{ "_id" : "10919", "city" : "CIRCLEVILLE", "loc" : [ -74.38504399999999, 41.524387 ], "pop" : 79, "state" : "NY" }
+{ "_id" : "10920", "city" : "CONGERS", "loc" : [ -73.94131, 41.148689 ], "pop" : 8088, "state" : "NY" }
+{ "_id" : "10921", "city" : "FLORIDA", "loc" : [ -74.352805, 41.329507 ], "pop" : 2698, "state" : "NY" }
+{ "_id" : "10923", "city" : "GARNERVILLE", "loc" : [ -74.000501, 41.202057 ], "pop" : 9650, "state" : "NY" }
+{ "_id" : "10924", "city" : "GOSHEN", "loc" : [ -74.330162, 41.394586 ], "pop" : 11019, "state" : "NY" }
+{ "_id" : "10925", "city" : "GREENWOOD LAKE", "loc" : [ -74.30000699999999, 41.212718 ], "pop" : 4723, "state" : "NY" }
+{ "_id" : "10926", "city" : "HARRIMAN", "loc" : [ -74.155805, 41.299681 ], "pop" : 3249, "state" : "NY" }
+{ "_id" : "10927", "city" : "HAVERSTRAW", "loc" : [ -73.968959, 41.197095 ], "pop" : 9438, "state" : "NY" }
+{ "_id" : "10928", "city" : "HIGHLAND FALLS", "loc" : [ -73.97461800000001, 41.358177 ], "pop" : 5704, "state" : "NY" }
+{ "_id" : "10930", "city" : "HIGHLAND MILLS", "loc" : [ -74.11967799999999, 41.353592 ], "pop" : 5629, "state" : "NY" }
+{ "_id" : "10931", "city" : "HILLBURN", "loc" : [ -74.17019500000001, 41.123981 ], "pop" : 892, "state" : "NY" }
+{ "_id" : "10940", "city" : "SCOTCHTOWN", "loc" : [ -74.412023, 41.457222 ], "pop" : 51211, "state" : "NY" }
+{ "_id" : "10950", "city" : "MONROE", "loc" : [ -74.18852099999999, 41.328578 ], "pop" : 30829, "state" : "NY" }
+{ "_id" : "10952", "city" : "MONSEY", "loc" : [ -74.0736, 41.116255 ], "pop" : 25251, "state" : "NY" }
+{ "_id" : "10954", "city" : "BARDONIA", "loc" : [ -74.00958900000001, 41.099176 ], "pop" : 16390, "state" : "NY" }
+{ "_id" : "10956", "city" : "NEW CITY", "loc" : [ -73.996206, 41.147247 ], "pop" : 33340, "state" : "NY" }
+{ "_id" : "10958", "city" : "NEW HAMPTON", "loc" : [ -74.443483, 41.362714 ], "pop" : 3918, "state" : "NY" }
+{ "_id" : "10960", "city" : "NYACK", "loc" : [ -73.92522599999999, 41.091351 ], "pop" : 14542, "state" : "NY" }
+{ "_id" : "10962", "city" : "ORANGEBURG", "loc" : [ -73.96087300000001, 41.044183 ], "pop" : 6324, "state" : "NY" }
+{ "_id" : "10963", "city" : "OTISVILLE", "loc" : [ -74.52941300000001, 41.481806 ], "pop" : 4748, "state" : "NY" }
+{ "_id" : "10964", "city" : "PALISADES", "loc" : [ -73.92498500000001, 41.010263 ], "pop" : 996, "state" : "NY" }
+{ "_id" : "10965", "city" : "PEARL RIVER", "loc" : [ -74.01587000000001, 41.062939 ], "pop" : 14791, "state" : "NY" }
+{ "_id" : "10968", "city" : "PIERMONT", "loc" : [ -73.91918699999999, 41.03955 ], "pop" : 2104, "state" : "NY" }
+{ "_id" : "10969", "city" : "PINE ISLAND", "loc" : [ -74.379457, 41.323796 ], "pop" : 589, "state" : "NY" }
+{ "_id" : "10970", "city" : "POMONA", "loc" : [ -74.043564, 41.190105 ], "pop" : 7356, "state" : "NY" }
+{ "_id" : "10973", "city" : "SLATE HILL", "loc" : [ -74.484658, 41.376004 ], "pop" : 2127, "state" : "NY" }
+{ "_id" : "10974", "city" : "STERLINGTON", "loc" : [ -74.188107, 41.16047 ], "pop" : 3322, "state" : "NY" }
+{ "_id" : "10975", "city" : "SOUTHFIELDS", "loc" : [ -74.176182, 41.247959 ], "pop" : 5, "state" : "NY" }
+{ "_id" : "10976", "city" : "SPARKILL", "loc" : [ -73.92288000000001, 41.025573 ], "pop" : 894, "state" : "NY" }
+{ "_id" : "10977", "city" : "CHESTNUT RIDGE", "loc" : [ -74.04625299999999, 41.117977 ], "pop" : 43435, "state" : "NY" }
+{ "_id" : "10980", "city" : "STONY POINT", "loc" : [ -73.99616399999999, 41.229174 ], "pop" : 11437, "state" : "NY" }
+{ "_id" : "10983", "city" : "TAPPAN", "loc" : [ -73.949065, 41.027751 ], "pop" : 6181, "state" : "NY" }
+{ "_id" : "10984", "city" : "THIELLS", "loc" : [ -74.015441, 41.207826 ], "pop" : 3971, "state" : "NY" }
+{ "_id" : "10985", "city" : "THOMPSON RIDGE", "loc" : [ -74.37744499999999, 41.580957 ], "pop" : 82, "state" : "NY" }
+{ "_id" : "10986", "city" : "TOMKINS COVE", "loc" : [ -73.98916, 41.259763 ], "pop" : 1615, "state" : "NY" }
+{ "_id" : "10987", "city" : "TUXEDO PARK", "loc" : [ -74.215912, 41.192486 ], "pop" : 2481, "state" : "NY" }
+{ "_id" : "10989", "city" : "VALLEY COTTAGE", "loc" : [ -73.943006, 41.118338 ], "pop" : 9132, "state" : "NY" }
+{ "_id" : "10990", "city" : "WARWICK", "loc" : [ -74.36037, 41.265563 ], "pop" : 16960, "state" : "NY" }
+{ "_id" : "10992", "city" : "WASHINGTONVILLE", "loc" : [ -74.1601, 41.423701 ], "pop" : 8842, "state" : "NY" }
+{ "_id" : "10993", "city" : "WEST HAVERSTRAW", "loc" : [ -73.982123, 41.209016 ], "pop" : 3591, "state" : "NY" }
+{ "_id" : "10994", "city" : "WEST NYACK", "loc" : [ -73.97684599999999, 41.097324 ], "pop" : 6655, "state" : "NY" }
+{ "_id" : "10996", "city" : "WEST POINT", "loc" : [ -73.97366599999999, 41.394545 ], "pop" : 7979, "state" : "NY" }
+{ "_id" : "10998", "city" : "WESTTOWN", "loc" : [ -74.55294600000001, 41.321414 ], "pop" : 2097, "state" : "NY" }
+{ "_id" : "11001", "city" : "FLORAL PARK", "loc" : [ -73.70576, 40.723586 ], "pop" : 26498, "state" : "NY" }
+{ "_id" : "11003", "city" : "ALDEN MANOR", "loc" : [ -73.70575100000001, 40.699615 ], "pop" : 34741, "state" : "NY" }
+{ "_id" : "11004", "city" : "GLEN OAKS", "loc" : [ -73.71143600000001, 40.7481 ], "pop" : 19058, "state" : "NY" }
+{ "_id" : "11010", "city" : "FRANKLIN SQUARE", "loc" : [ -73.67580700000001, 40.701049 ], "pop" : 24595, "state" : "NY" }
+{ "_id" : "11020", "city" : "GREAT NECK", "loc" : [ -73.718918, 40.774235 ], "pop" : 6144, "state" : "NY" }
+{ "_id" : "11021", "city" : "GREAT NECK", "loc" : [ -73.726984, 40.786674 ], "pop" : 17198, "state" : "NY" }
+{ "_id" : "11023", "city" : "GREAT NECK", "loc" : [ -73.734257, 40.799307 ], "pop" : 7981, "state" : "NY" }
+{ "_id" : "11024", "city" : "KINGS POINT CONT", "loc" : [ -73.74139099999999, 40.813307 ], "pop" : 7298, "state" : "NY" }
+{ "_id" : "11030", "city" : "PLANDOME", "loc" : [ -73.68836899999999, 40.798641 ], "pop" : 15271, "state" : "NY" }
+{ "_id" : "11040", "city" : "HILLSIDE MANOR", "loc" : [ -73.68042, 40.743926 ], "pop" : 37695, "state" : "NY" }
+{ "_id" : "11042", "city" : "NEW HYDE PARK", "loc" : [ -73.69497800000001, 40.7602 ], "pop" : 1, "state" : "NY" }
+{ "_id" : "11050", "city" : "PORT WASHINGTON", "loc" : [ -73.69635599999999, 40.834995 ], "pop" : 28264, "state" : "NY" }
+{ "_id" : "11101", "city" : "ASTORIA", "loc" : [ -73.939393, 40.750316 ], "pop" : 23142, "state" : "NY" }
+{ "_id" : "11102", "city" : "ASTORIA", "loc" : [ -73.926462, 40.77063 ], "pop" : 30078, "state" : "NY" }
+{ "_id" : "11103", "city" : "ASTORIA", "loc" : [ -73.914886, 40.762651 ], "pop" : 38597, "state" : "NY" }
+{ "_id" : "11104", "city" : "SUNNYSIDE", "loc" : [ -73.921556, 40.743641 ], "pop" : 25898, "state" : "NY" }
+{ "_id" : "11105", "city" : "ASTORIA", "loc" : [ -73.910965, 40.77627 ], "pop" : 37297, "state" : "NY" }
+{ "_id" : "11106", "city" : "ASTORIA", "loc" : [ -73.92952699999999, 40.760813 ], "pop" : 36515, "state" : "NY" }
+{ "_id" : "11201", "city" : "BROOKLYN", "loc" : [ -73.99034, 40.694021 ], "pop" : 46980, "state" : "NY" }
+{ "_id" : "11203", "city" : "BROOKLYN", "loc" : [ -73.934888, 40.650496 ], "pop" : 80566, "state" : "NY" }
+{ "_id" : "11204", "city" : "BROOKLYN", "loc" : [ -73.985623, 40.617871 ], "pop" : 64780, "state" : "NY" }
+{ "_id" : "11205", "city" : "BROOKLYN", "loc" : [ -73.96662000000001, 40.692433 ], "pop" : 36852, "state" : "NY" }
+{ "_id" : "11206", "city" : "BROOKLYN", "loc" : [ -73.943617, 40.701195 ], "pop" : 74825, "state" : "NY" }
+{ "_id" : "11207", "city" : "BROOKLYN", "loc" : [ -73.893957, 40.670486 ], "pop" : 83158, "state" : "NY" }
+{ "_id" : "11208", "city" : "BROOKLYN", "loc" : [ -73.873649, 40.676191 ], "pop" : 78322, "state" : "NY" }
+{ "_id" : "11209", "city" : "BROOKLYN", "loc" : [ -74.030304, 40.625106 ], "pop" : 62346, "state" : "NY" }
+{ "_id" : "11210", "city" : "BROOKLYN", "loc" : [ -73.946682, 40.628064 ], "pop" : 62445, "state" : "NY" }
+{ "_id" : "11211", "city" : "BROOKLYN", "loc" : [ -73.956283, 40.709476 ], "pop" : 78338, "state" : "NY" }
+{ "_id" : "11212", "city" : "BROOKLYN", "loc" : [ -73.914483, 40.662474 ], "pop" : 87079, "state" : "NY" }
+{ "_id" : "11213", "city" : "BROOKLYN", "loc" : [ -73.93665, 40.669961 ], "pop" : 62607, "state" : "NY" }
+{ "_id" : "11214", "city" : "BROOKLYN", "loc" : [ -73.99681, 40.601563 ], "pop" : 73076, "state" : "NY" }
+{ "_id" : "11215", "city" : "BROOKLYN", "loc" : [ -73.982783, 40.666863 ], "pop" : 63338, "state" : "NY" }
+{ "_id" : "11216", "city" : "BROOKLYN", "loc" : [ -73.949639, 40.67943 ], "pop" : 58862, "state" : "NY" }
+{ "_id" : "11217", "city" : "BROOKLYN", "loc" : [ -73.979797, 40.68165 ], "pop" : 36232, "state" : "NY" }
+{ "_id" : "11218", "city" : "BROOKLYN", "loc" : [ -73.97580600000001, 40.642373 ], "pop" : 66569, "state" : "NY" }
+{ "_id" : "11219", "city" : "BROOKLYN", "loc" : [ -73.996011, 40.633568 ], "pop" : 73527, "state" : "NY" }
+{ "_id" : "11220", "city" : "BROOKLYN", "loc" : [ -74.01328700000001, 40.641165 ], "pop" : 76923, "state" : "NY" }
+{ "_id" : "11221", "city" : "BROOKLYN", "loc" : [ -73.927373, 40.690695 ], "pop" : 70583, "state" : "NY" }
+{ "_id" : "11222", "city" : "BROOKLYN", "loc" : [ -73.94984599999999, 40.727164 ], "pop" : 38158, "state" : "NY" }
+{ "_id" : "11223", "city" : "BROOKLYN", "loc" : [ -73.97429099999999, 40.597874 ], "pop" : 70904, "state" : "NY" }
+{ "_id" : "11224", "city" : "BROOKLYN", "loc" : [ -73.988395, 40.576729 ], "pop" : 52480, "state" : "NY" }
+{ "_id" : "11225", "city" : "BROOKLYN", "loc" : [ -73.954588, 40.662776 ], "pop" : 66752, "state" : "NY" }
+{ "_id" : "11226", "city" : "BROOKLYN", "loc" : [ -73.956985, 40.646694 ], "pop" : 111396, "state" : "NY" }
+{ "_id" : "11228", "city" : "BROOKLYN", "loc" : [ -74.012067, 40.617441 ], "pop" : 39220, "state" : "NY" }
+{ "_id" : "11229", "city" : "BROOKLYN", "loc" : [ -73.94749, 40.601094 ], "pop" : 72660, "state" : "NY" }
+{ "_id" : "11230", "city" : "BROOKLYN", "loc" : [ -73.965007, 40.622493 ], "pop" : 72733, "state" : "NY" }
+{ "_id" : "11231", "city" : "BROOKLYN", "loc" : [ -74.00141000000001, 40.679437 ], "pop" : 32101, "state" : "NY" }
+{ "_id" : "11232", "city" : "BROOKLYN", "loc" : [ -74.001797, 40.652113 ], "pop" : 22777, "state" : "NY" }
+{ "_id" : "11233", "city" : "BROOKLYN", "loc" : [ -73.921104, 40.678415 ], "pop" : 58827, "state" : "NY" }
+{ "_id" : "11234", "city" : "BROOKLYN", "loc" : [ -73.92391499999999, 40.620475 ], "pop" : 74953, "state" : "NY" }
+{ "_id" : "11235", "city" : "BROOKLYN", "loc" : [ -73.953599, 40.583898 ], "pop" : 67088, "state" : "NY" }
+{ "_id" : "11236", "city" : "BROOKLYN", "loc" : [ -73.902764, 40.640685 ], "pop" : 77253, "state" : "NY" }
+{ "_id" : "11237", "city" : "BROOKLYN", "loc" : [ -73.917979, 40.700616 ], "pop" : 48339, "state" : "NY" }
+{ "_id" : "11238", "city" : "BROOKLYN", "loc" : [ -73.964387, 40.679015 ], "pop" : 42507, "state" : "NY" }
+{ "_id" : "11239", "city" : "BROOKLYN", "loc" : [ -73.882375, 40.649748 ], "pop" : 14948, "state" : "NY" }
+{ "_id" : "11251", "city" : "BROOKLYN NAVY YA", "loc" : [ -73.966511, 40.703578 ], "pop" : 18, "state" : "NY" }
+{ "_id" : "11354", "city" : "FLUSHING", "loc" : [ -73.82414199999999, 40.766722 ], "pop" : 51947, "state" : "NY" }
+{ "_id" : "11355", "city" : "FLUSHING", "loc" : [ -73.822609, 40.753573 ], "pop" : 69164, "state" : "NY" }
+{ "_id" : "11356", "city" : "COLLEGE POINT", "loc" : [ -73.844955, 40.785511 ], "pop" : 17723, "state" : "NY" }
+{ "_id" : "11357", "city" : "WHITESTONE", "loc" : [ -73.809594, 40.785147 ], "pop" : 39093, "state" : "NY" }
+{ "_id" : "11358", "city" : "FLUSHING", "loc" : [ -73.79678800000001, 40.760636 ], "pop" : 34045, "state" : "NY" }
+{ "_id" : "11359", "city" : "FORT TOTTEN", "loc" : [ -73.777244, 40.789967 ], "pop" : 734, "state" : "NY" }
+{ "_id" : "11360", "city" : "BAYSIDE", "loc" : [ -73.781216, 40.780684 ], "pop" : 20337, "state" : "NY" }
+{ "_id" : "11361", "city" : "BAYSIDE", "loc" : [ -73.774457, 40.76268 ], "pop" : 25529, "state" : "NY" }
+{ "_id" : "11362", "city" : "LITTLE NECK", "loc" : [ -73.73262200000001, 40.759131 ], "pop" : 16226, "state" : "NY" }
+{ "_id" : "11363", "city" : "LITTLE NECK", "loc" : [ -73.745401, 40.772166 ], "pop" : 6909, "state" : "NY" }
+{ "_id" : "11364", "city" : "FLUSHING", "loc" : [ -73.758646, 40.745847 ], "pop" : 32080, "state" : "NY" }
+{ "_id" : "11365", "city" : "FRESH MEADOWS", "loc" : [ -73.79506000000001, 40.737424 ], "pop" : 34087, "state" : "NY" }
+{ "_id" : "11366", "city" : "FRESH MEADOWS", "loc" : [ -73.794922, 40.727231 ], "pop" : 12089, "state" : "NY" }
+{ "_id" : "11367", "city" : "FLUSHING", "loc" : [ -73.81953, 40.727966 ], "pop" : 36877, "state" : "NY" }
+{ "_id" : "11368", "city" : "CORONA", "loc" : [ -73.861069, 40.745288 ], "pop" : 75746, "state" : "NY" }
+{ "_id" : "11369", "city" : "EAST ELMHURST", "loc" : [ -73.873902, 40.761254 ], "pop" : 28106, "state" : "NY" }
+{ "_id" : "11370", "city" : "EAST ELMHURST", "loc" : [ -73.891586, 40.761111 ], "pop" : 23910, "state" : "NY" }
+{ "_id" : "11371", "city" : "FLUSHING", "loc" : [ -73.873535, 40.772117 ], "pop" : 49, "state" : "NY" }
+{ "_id" : "11372", "city" : "JACKSON HEIGHTS", "loc" : [ -73.882975, 40.751329 ], "pop" : 57726, "state" : "NY" }
+{ "_id" : "11373", "city" : "JACKSON HEIGHTS", "loc" : [ -73.878551, 40.740388 ], "pop" : 88241, "state" : "NY" }
+{ "_id" : "11374", "city" : "REGO PARK", "loc" : [ -73.860191, 40.72775 ], "pop" : 40024, "state" : "NY" }
+{ "_id" : "11375", "city" : "FOREST HILLS", "loc" : [ -73.847306, 40.722854 ], "pop" : 65180, "state" : "NY" }
+{ "_id" : "11377", "city" : "WOODSIDE", "loc" : [ -73.90691099999999, 40.744972 ], "pop" : 75894, "state" : "NY" }
+{ "_id" : "11378", "city" : "MASPETH", "loc" : [ -73.899682, 40.723865 ], "pop" : 31292, "state" : "NY" }
+{ "_id" : "11379", "city" : "MIDDLE VILLAGE", "loc" : [ -73.879228, 40.717286 ], "pop" : 28981, "state" : "NY" }
+{ "_id" : "11385", "city" : "RIDGEWOOD", "loc" : [ -73.89612200000001, 40.703613 ], "pop" : 85732, "state" : "NY" }
+{ "_id" : "11411", "city" : "CAMBRIA HEIGHTS", "loc" : [ -73.73744499999999, 40.694741 ], "pop" : 20094, "state" : "NY" }
+{ "_id" : "11412", "city" : "KEW GARDENS", "loc" : [ -73.758641, 40.698097 ], "pop" : 32003, "state" : "NY" }
+{ "_id" : "11413", "city" : "SPRINGFIELD GARD", "loc" : [ -73.75071, 40.67295 ], "pop" : 36679, "state" : "NY" }
+{ "_id" : "11414", "city" : "KEW GARDENS", "loc" : [ -73.84504099999999, 40.660603 ], "pop" : 27256, "state" : "NY" }
+{ "_id" : "11415", "city" : "KEW GARDENS", "loc" : [ -73.82971499999999, 40.706865 ], "pop" : 16703, "state" : "NY" }
+{ "_id" : "11416", "city" : "OZONE PARK", "loc" : [ -73.85139700000001, 40.683753 ], "pop" : 17876, "state" : "NY" }
+{ "_id" : "11417", "city" : "OZONE PARK", "loc" : [ -73.84477800000001, 40.676854 ], "pop" : 22768, "state" : "NY" }
+{ "_id" : "11418", "city" : "RICHMOND HILL", "loc" : [ -73.834484, 40.698171 ], "pop" : 29382, "state" : "NY" }
+{ "_id" : "11419", "city" : "S RICHMOND HILL", "loc" : [ -73.823871, 40.688113 ], "pop" : 37530, "state" : "NY" }
+{ "_id" : "11420", "city" : "S OZONE PARK", "loc" : [ -73.81577299999999, 40.675379 ], "pop" : 38096, "state" : "NY" }
+{ "_id" : "11421", "city" : "WOODHAVEN", "loc" : [ -73.858514, 40.691345 ], "pop" : 29442, "state" : "NY" }
+{ "_id" : "11422", "city" : "ROSEDALE", "loc" : [ -73.735265, 40.662141 ], "pop" : 26674, "state" : "NY" }
+{ "_id" : "11423", "city" : "HOLLIS", "loc" : [ -73.767685, 40.714156 ], "pop" : 29102, "state" : "NY" }
+{ "_id" : "11426", "city" : "BELLEROSE", "loc" : [ -73.723018, 40.734735 ], "pop" : 18145, "state" : "NY" }
+{ "_id" : "11427", "city" : "QUEENS VILLAGE", "loc" : [ -73.748908, 40.727707 ], "pop" : 21004, "state" : "NY" }
+{ "_id" : "11428", "city" : "QUEENS VILLAGE", "loc" : [ -73.743312, 40.720756 ], "pop" : 16793, "state" : "NY" }
+{ "_id" : "11429", "city" : "QUEENS VILLAGE", "loc" : [ -73.740064, 40.70902 ], "pop" : 24311, "state" : "NY" }
+{ "_id" : "11430", "city" : "JAMAICA", "loc" : [ -73.782663, 40.647221 ], "pop" : 398, "state" : "NY" }
+{ "_id" : "11432", "city" : "JAMAICA", "loc" : [ -73.79442, 40.711867 ], "pop" : 53011, "state" : "NY" }
+{ "_id" : "11433", "city" : "JAMAICA", "loc" : [ -73.78766899999999, 40.69691 ], "pop" : 26325, "state" : "NY" }
+{ "_id" : "11434", "city" : "JAMAICA", "loc" : [ -73.77584, 40.677483 ], "pop" : 50464, "state" : "NY" }
+{ "_id" : "11435", "city" : "JAMAICA", "loc" : [ -73.811121, 40.702934 ], "pop" : 47987, "state" : "NY" }
+{ "_id" : "11436", "city" : "JAMAICA", "loc" : [ -73.79659599999999, 40.676347 ], "pop" : 17020, "state" : "NY" }
+{ "_id" : "11501", "city" : "MINEOLA", "loc" : [ -73.63976099999999, 40.746927 ], "pop" : 19087, "state" : "NY" }
+{ "_id" : "11507", "city" : "ALBERTSON", "loc" : [ -73.651419, 40.77032 ], "pop" : 7091, "state" : "NY" }
+{ "_id" : "11509", "city" : "ATLANTIC BEACH", "loc" : [ -73.725545, 40.588652 ], "pop" : 2831, "state" : "NY" }
+{ "_id" : "11510", "city" : "BALDWIN", "loc" : [ -73.60968800000001, 40.654755 ], "pop" : 30959, "state" : "NY" }
+{ "_id" : "11514", "city" : "CARLE PLACE", "loc" : [ -73.611941, 40.75115 ], "pop" : 4863, "state" : "NY" }
+{ "_id" : "11516", "city" : "CEDARHURST", "loc" : [ -73.726404, 40.623619 ], "pop" : 7113, "state" : "NY" }
+{ "_id" : "11518", "city" : "EAST ROCKAWAY", "loc" : [ -73.667376, 40.640445 ], "pop" : 11027, "state" : "NY" }
+{ "_id" : "11520", "city" : "FREEPORT", "loc" : [ -73.58661499999999, 40.65359 ], "pop" : 40662, "state" : "NY" }
+{ "_id" : "11530", "city" : "GARDEN CITY", "loc" : [ -73.648718, 40.72452 ], "pop" : 27951, "state" : "NY" }
+{ "_id" : "11542", "city" : "GLEN COVE", "loc" : [ -73.62772, 40.864958 ], "pop" : 24997, "state" : "NY" }
+{ "_id" : "11545", "city" : "GLEN HEAD", "loc" : [ -73.60763, 40.828098 ], "pop" : 13565, "state" : "NY" }
+{ "_id" : "11548", "city" : "GREENVALE", "loc" : [ -73.626124, 40.812503 ], "pop" : 1021, "state" : "NY" }
+{ "_id" : "11550", "city" : "HEMPSTEAD", "loc" : [ -73.61764100000001, 40.70492 ], "pop" : 50933, "state" : "NY" }
+{ "_id" : "11552", "city" : "WEST HEMPSTEAD", "loc" : [ -73.653859, 40.692915 ], "pop" : 22972, "state" : "NY" }
+{ "_id" : "11553", "city" : "UNIONDALE", "loc" : [ -73.591995, 40.702029 ], "pop" : 20397, "state" : "NY" }
+{ "_id" : "11554", "city" : "EAST MEADOW", "loc" : [ -73.556088, 40.714915 ], "pop" : 36692, "state" : "NY" }
+{ "_id" : "11557", "city" : "HEWLETT", "loc" : [ -73.695667, 40.640392 ], "pop" : 8023, "state" : "NY" }
+{ "_id" : "11558", "city" : "ISLAND PARK", "loc" : [ -73.655411, 40.604044 ], "pop" : 8857, "state" : "NY" }
+{ "_id" : "11559", "city" : "LAWRENCE", "loc" : [ -73.732969, 40.61396 ], "pop" : 6703, "state" : "NY" }
+{ "_id" : "11560", "city" : "LOCUST VALLEY", "loc" : [ -73.59271, 40.881728 ], "pop" : 6771, "state" : "NY" }
+{ "_id" : "11561", "city" : "LONG BEACH", "loc" : [ -73.65946700000001, 40.587697 ], "pop" : 39066, "state" : "NY" }
+{ "_id" : "11563", "city" : "LYNBROOK", "loc" : [ -73.674143, 40.657107 ], "pop" : 22659, "state" : "NY" }
+{ "_id" : "11565", "city" : "MALVERNE", "loc" : [ -73.673073, 40.674982 ], "pop" : 8660, "state" : "NY" }
+{ "_id" : "11566", "city" : "NORTH MERRICK", "loc" : [ -73.555001, 40.668312 ], "pop" : 36427, "state" : "NY" }
+{ "_id" : "11568", "city" : "OLD WESTBURY", "loc" : [ -73.587515, 40.78821 ], "pop" : 5524, "state" : "NY" }
+{ "_id" : "11570", "city" : "ROCKVILLE CENTRE", "loc" : [ -73.63800000000001, 40.663745 ], "pop" : 27127, "state" : "NY" }
+{ "_id" : "11572", "city" : "OCEANSIDE", "loc" : [ -73.637533, 40.636199 ], "pop" : 31406, "state" : "NY" }
+{ "_id" : "11575", "city" : "ROOSEVELT", "loc" : [ -73.586697, 40.680171 ], "pop" : 14595, "state" : "NY" }
+{ "_id" : "11576", "city" : "ROSLYN", "loc" : [ -73.653362, 40.790668 ], "pop" : 13114, "state" : "NY" }
+{ "_id" : "11577", "city" : "ROSLYN HEIGHTS", "loc" : [ -73.640292, 40.784497 ], "pop" : 10665, "state" : "NY" }
+{ "_id" : "11579", "city" : "SEA CLIFF", "loc" : [ -73.643598, 40.845984 ], "pop" : 5068, "state" : "NY" }
+{ "_id" : "11580", "city" : "VALLEY STREAM", "loc" : [ -73.705738, 40.674184 ], "pop" : 34327, "state" : "NY" }
+{ "_id" : "11581", "city" : "NORTH WOODMERE", "loc" : [ -73.710705, 40.651838 ], "pop" : 19582, "state" : "NY" }
+{ "_id" : "11590", "city" : "WESTBURY", "loc" : [ -73.57226, 40.755749 ], "pop" : 38026, "state" : "NY" }
+{ "_id" : "11596", "city" : "WILLISTON PARK", "loc" : [ -73.644892, 40.759198 ], "pop" : 11057, "state" : "NY" }
+{ "_id" : "11598", "city" : "WOODMERE", "loc" : [ -73.714146, 40.63262 ], "pop" : 13084, "state" : "NY" }
+{ "_id" : "11691", "city" : "FAR ROCKAWAY", "loc" : [ -73.757971, 40.600645 ], "pop" : 52162, "state" : "NY" }
+{ "_id" : "11692", "city" : "FAR ROCKAWAY", "loc" : [ -73.79744599999999, 40.59257 ], "pop" : 21192, "state" : "NY" }
+{ "_id" : "11693", "city" : "FAR ROCKAWAY", "loc" : [ -73.819804, 40.607644 ], "pop" : 1630, "state" : "NY" }
+{ "_id" : "11694", "city" : "FAR ROCKAWAY", "loc" : [ -73.839192, 40.579471 ], "pop" : 21972, "state" : "NY" }
+{ "_id" : "11696", "city" : "INWOOD", "loc" : [ -73.746988, 40.617784 ], "pop" : 6660, "state" : "NY" }
+{ "_id" : "11697", "city" : "FAR ROCKAWAY", "loc" : [ -73.914873, 40.560032 ], "pop" : 3690, "state" : "NY" }
+{ "_id" : "11701", "city" : "AMITYVILLE", "loc" : [ -73.417106, 40.684197 ], "pop" : 29047, "state" : "NY" }
+{ "_id" : "11702", "city" : "OAK BEACH", "loc" : [ -73.324583, 40.634183 ], "pop" : 456, "state" : "NY" }
+{ "_id" : "11703", "city" : "NORTH BABYLON", "loc" : [ -73.323581, 40.732102 ], "pop" : 17916, "state" : "NY" }
+{ "_id" : "11704", "city" : "WEST BABYLON", "loc" : [ -73.354591, 40.713476 ], "pop" : 45519, "state" : "NY" }
+{ "_id" : "11705", "city" : "BAYPORT", "loc" : [ -73.05420700000001, 40.744408 ], "pop" : 7616, "state" : "NY" }
+{ "_id" : "11706", "city" : "KISMET", "loc" : [ -73.252708, 40.733744 ], "pop" : 5507, "state" : "NY" }
+{ "_id" : "11709", "city" : "BAYVILLE", "loc" : [ -73.560141, 40.907382 ], "pop" : 7185, "state" : "NY" }
+{ "_id" : "11710", "city" : "NORTH BELLMORE", "loc" : [ -73.53451699999999, 40.677028 ], "pop" : 34237, "state" : "NY" }
+{ "_id" : "11713", "city" : "BELLPORT", "loc" : [ -72.94689099999999, 40.77327 ], "pop" : 7927, "state" : "NY" }
+{ "_id" : "11714", "city" : "BETHPAGE", "loc" : [ -73.485727, 40.740014 ], "pop" : 21957, "state" : "NY" }
+{ "_id" : "11715", "city" : "BLUE POINT", "loc" : [ -73.035213, 40.750089 ], "pop" : 4189, "state" : "NY" }
+{ "_id" : "11716", "city" : "BOHEMIA", "loc" : [ -73.116339, 40.767788 ], "pop" : 10448, "state" : "NY" }
+{ "_id" : "11717", "city" : "WEST BRENTWOOD", "loc" : [ -73.248189, 40.777918 ], "pop" : 60425, "state" : "NY" }
+{ "_id" : "11718", "city" : "BRIGHTWATERS", "loc" : [ -73.264639, 40.727957 ], "pop" : 20866, "state" : "NY" }
+{ "_id" : "11719", "city" : "BROOKHAVEN", "loc" : [ -72.89212499999999, 40.78428 ], "pop" : 7493, "state" : "NY" }
+{ "_id" : "11720", "city" : "CENTEREACH", "loc" : [ -73.08216299999999, 40.870508 ], "pop" : 27519, "state" : "NY" }
+{ "_id" : "11721", "city" : "CENTERPORT", "loc" : [ -73.3754, 40.892899 ], "pop" : 5770, "state" : "NY" }
+{ "_id" : "11722", "city" : "CENTRAL ISLIP", "loc" : [ -73.196145, 40.786618 ], "pop" : 29418, "state" : "NY" }
+{ "_id" : "11724", "city" : "COLD SPRING HARB", "loc" : [ -73.45003199999999, 40.863056 ], "pop" : 2860, "state" : "NY" }
+{ "_id" : "11725", "city" : "COMMACK", "loc" : [ -73.27992399999999, 40.843032 ], "pop" : 29847, "state" : "NY" }
+{ "_id" : "11726", "city" : "COPIAGUE", "loc" : [ -73.396271, 40.677833 ], "pop" : 15640, "state" : "NY" }
+{ "_id" : "11727", "city" : "CORAM", "loc" : [ -73.00688100000001, 40.884988 ], "pop" : 25002, "state" : "NY" }
+{ "_id" : "11729", "city" : "DEER PARK", "loc" : [ -73.32572, 40.759083 ], "pop" : 32146, "state" : "NY" }
+{ "_id" : "11730", "city" : "EAST ISLIP", "loc" : [ -73.180471, 40.72816 ], "pop" : 15777, "state" : "NY" }
+{ "_id" : "11731", "city" : "ELWOOD", "loc" : [ -73.319506, 40.867066 ], "pop" : 30333, "state" : "NY" }
+{ "_id" : "11732", "city" : "EAST NORWICH", "loc" : [ -73.534876, 40.847162 ], "pop" : 3276, "state" : "NY" }
+{ "_id" : "11733", "city" : "SETAUKET", "loc" : [ -73.101467, 40.930004 ], "pop" : 16470, "state" : "NY" }
+{ "_id" : "11735", "city" : "SOUTH FARMINGDAL", "loc" : [ -73.445055, 40.725061 ], "pop" : 31358, "state" : "NY" }
+{ "_id" : "11738", "city" : "FARMINGVILLE", "loc" : [ -73.04125000000001, 40.836602 ], "pop" : 14967, "state" : "NY" }
+{ "_id" : "11740", "city" : "GREENLAWN", "loc" : [ -73.36464100000001, 40.862121 ], "pop" : 9967, "state" : "NY" }
+{ "_id" : "11741", "city" : "HOLBROOK", "loc" : [ -73.071789, 40.796426 ], "pop" : 25964, "state" : "NY" }
+{ "_id" : "11742", "city" : "HOLTSVILLE", "loc" : [ -73.04161000000001, 40.810478 ], "pop" : 10141, "state" : "NY" }
+{ "_id" : "11743", "city" : "HALESITE", "loc" : [ -73.41092399999999, 40.866945 ], "pop" : 41511, "state" : "NY" }
+{ "_id" : "11746", "city" : "DIX HILLS", "loc" : [ -73.375472, 40.821754 ], "pop" : 62162, "state" : "NY" }
+{ "_id" : "11747", "city" : "MELVILLE", "loc" : [ -73.402963, 40.794606 ], "pop" : 14534, "state" : "NY" }
+{ "_id" : "11751", "city" : "ISLIP", "loc" : [ -73.22211, 40.734821 ], "pop" : 21721, "state" : "NY" }
+{ "_id" : "11752", "city" : "ISLIP TERRACE", "loc" : [ -73.18274599999999, 40.75482 ], "pop" : 9514, "state" : "NY" }
+{ "_id" : "11753", "city" : "JERICHO", "loc" : [ -73.533067, 40.788118 ], "pop" : 9837, "state" : "NY" }
+{ "_id" : "11754", "city" : "KINGS PARK", "loc" : [ -73.243763, 40.886121 ], "pop" : 19036, "state" : "NY" }
+{ "_id" : "11755", "city" : "LAKE GROVE", "loc" : [ -73.11675099999999, 40.856681 ], "pop" : 8245, "state" : "NY" }
+{ "_id" : "11756", "city" : "LEVITTOWN", "loc" : [ -73.516578, 40.725428 ], "pop" : 44967, "state" : "NY" }
+{ "_id" : "11757", "city" : "LINDENHURST", "loc" : [ -73.374493, 40.688373 ], "pop" : 44726, "state" : "NY" }
+{ "_id" : "11758", "city" : "NORTH MASSAPEQUA", "loc" : [ -73.46972700000001, 40.685738 ], "pop" : 42863, "state" : "NY" }
+{ "_id" : "11762", "city" : "MASSAPEQUA PARK", "loc" : [ -73.444447, 40.680673 ], "pop" : 31693, "state" : "NY" }
+{ "_id" : "11763", "city" : "MEDFORD", "loc" : [ -72.985214, 40.817416 ], "pop" : 20669, "state" : "NY" }
+{ "_id" : "11764", "city" : "MILLER PLACE", "loc" : [ -72.991349, 40.943572 ], "pop" : 9601, "state" : "NY" }
+{ "_id" : "11765", "city" : "MILL NECK", "loc" : [ -73.55260199999999, 40.88574 ], "pop" : 877, "state" : "NY" }
+{ "_id" : "11766", "city" : "MOUNT SINAI", "loc" : [ -73.012732, 40.927092 ], "pop" : 8759, "state" : "NY" }
+{ "_id" : "11767", "city" : "NESCONSET", "loc" : [ -73.1482, 40.846206 ], "pop" : 9681, "state" : "NY" }
+{ "_id" : "11768", "city" : "NORTHPORT", "loc" : [ -73.330889, 40.905062 ], "pop" : 21714, "state" : "NY" }
+{ "_id" : "11769", "city" : "OAKDALE", "loc" : [ -73.12969, 40.738224 ], "pop" : 9366, "state" : "NY" }
+{ "_id" : "11771", "city" : "OYSTER BAY", "loc" : [ -73.52721200000001, 40.866012 ], "pop" : 9806, "state" : "NY" }
+{ "_id" : "11772", "city" : "DAVIS PARK", "loc" : [ -72.998108, 40.773501 ], "pop" : 40962, "state" : "NY" }
+{ "_id" : "11776", "city" : "PORT JEFFERSON S", "loc" : [ -73.052136, 40.911722 ], "pop" : 19800, "state" : "NY" }
+{ "_id" : "11777", "city" : "PORT JEFFERSON", "loc" : [ -73.061093, 40.945687 ], "pop" : 8512, "state" : "NY" }
+{ "_id" : "11778", "city" : "ROCKY POINT", "loc" : [ -72.935681, 40.949206 ], "pop" : 11913, "state" : "NY" }
+{ "_id" : "11779", "city" : "LAKE RONKONKOMA", "loc" : [ -73.1208, 40.820763 ], "pop" : 43424, "state" : "NY" }
+{ "_id" : "11780", "city" : "SAINT JAMES", "loc" : [ -73.159121, 40.881299 ], "pop" : 14211, "state" : "NY" }
+{ "_id" : "11782", "city" : "CHERRY GROVE", "loc" : [ -73.082297, 40.74606 ], "pop" : 15718, "state" : "NY" }
+{ "_id" : "11783", "city" : "SEAFORD", "loc" : [ -73.491015, 40.679513 ], "pop" : 21644, "state" : "NY" }
+{ "_id" : "11784", "city" : "SELDEN", "loc" : [ -73.044848, 40.869883 ], "pop" : 23753, "state" : "NY" }
+{ "_id" : "11786", "city" : "SHOREHAM", "loc" : [ -72.892685, 40.948493 ], "pop" : 5114, "state" : "NY" }
+{ "_id" : "11787", "city" : "SMITHTOWN", "loc" : [ -73.21381599999999, 40.854186 ], "pop" : 29932, "state" : "NY" }
+{ "_id" : "11788", "city" : "HAUPPAUGE", "loc" : [ -73.195762, 40.823069 ], "pop" : 19713, "state" : "NY" }
+{ "_id" : "11789", "city" : "SOUND BEACH", "loc" : [ -72.974172, 40.956707 ], "pop" : 6497, "state" : "NY" }
+{ "_id" : "11790", "city" : "STONY BROOK", "loc" : [ -73.125085, 40.900257 ], "pop" : 13767, "state" : "NY" }
+{ "_id" : "11791", "city" : "SYOSSET", "loc" : [ -73.502397, 40.81462 ], "pop" : 24949, "state" : "NY" }
+{ "_id" : "11792", "city" : "WADING RIVER", "loc" : [ -72.834774, 40.952049 ], "pop" : 6186, "state" : "NY" }
+{ "_id" : "11793", "city" : "WANTAGH", "loc" : [ -73.51033, 40.684998 ], "pop" : 31972, "state" : "NY" }
+{ "_id" : "11794", "city" : "SUNY STONY BROOK", "loc" : [ -73.125456, 40.914127 ], "pop" : 5504, "state" : "NY" }
+{ "_id" : "11795", "city" : "WEST ISLIP", "loc" : [ -73.30072, 40.711734 ], "pop" : 39344, "state" : "NY" }
+{ "_id" : "11796", "city" : "WEST SAYVILLE", "loc" : [ -73.100019, 40.731971 ], "pop" : 3575, "state" : "NY" }
+{ "_id" : "11797", "city" : "WOODBURY", "loc" : [ -73.47161199999999, 40.815441 ], "pop" : 8104, "state" : "NY" }
+{ "_id" : "11798", "city" : "WHEATLEY HEIGHTS", "loc" : [ -73.36596, 40.753258 ], "pop" : 13312, "state" : "NY" }
+{ "_id" : "11801", "city" : "HICKSVILLE", "loc" : [ -73.52297, 40.762305 ], "pop" : 38307, "state" : "NY" }
+{ "_id" : "11803", "city" : "PLAINVIEW", "loc" : [ -73.481638, 40.778099 ], "pop" : 28207, "state" : "NY" }
+{ "_id" : "11804", "city" : "OLD BETHPAGE", "loc" : [ -73.457481, 40.764991 ], "pop" : 5233, "state" : "NY" }
+{ "_id" : "11901", "city" : "RIVERHEAD", "loc" : [ -72.651966, 40.926202 ], "pop" : 20705, "state" : "NY" }
+{ "_id" : "11933", "city" : "CALVERTON", "loc" : [ -72.74229, 40.929662 ], "pop" : 3954, "state" : "NY" }
+{ "_id" : "11934", "city" : "CENTER MORICHES", "loc" : [ -72.797048, 40.799657 ], "pop" : 6265, "state" : "NY" }
+{ "_id" : "11935", "city" : "CUTCHOGUE", "loc" : [ -72.480255, 41.013918 ], "pop" : 3678, "state" : "NY" }
+{ "_id" : "11937", "city" : "EAST HAMPTON", "loc" : [ -72.17895799999999, 40.992964 ], "pop" : 12205, "state" : "NY" }
+{ "_id" : "11939", "city" : "EAST MARION", "loc" : [ -72.34186, 41.126425 ], "pop" : 717, "state" : "NY" }
+{ "_id" : "11940", "city" : "EAST MORICHES", "loc" : [ -72.753778, 40.808975 ], "pop" : 3822, "state" : "NY" }
+{ "_id" : "11941", "city" : "EASTPORT", "loc" : [ -72.705388, 40.809947 ], "pop" : 1331, "state" : "NY" }
+{ "_id" : "11942", "city" : "EAST QUOGUE", "loc" : [ -72.58129700000001, 40.84277 ], "pop" : 4181, "state" : "NY" }
+{ "_id" : "11944", "city" : "GREENPORT", "loc" : [ -72.36741499999999, 41.103905 ], "pop" : 3657, "state" : "NY" }
+{ "_id" : "11946", "city" : "HAMPTON BAYS", "loc" : [ -72.52020899999999, 40.872596 ], "pop" : 9586, "state" : "NY" }
+{ "_id" : "11948", "city" : "LAUREL", "loc" : [ -72.55404, 40.9674 ], "pop" : 954, "state" : "NY" }
+{ "_id" : "11949", "city" : "MANORVILLE", "loc" : [ -72.800208, 40.842102 ], "pop" : 9660, "state" : "NY" }
+{ "_id" : "11950", "city" : "MASTIC", "loc" : [ -72.85660799999999, 40.80644 ], "pop" : 20374, "state" : "NY" }
+{ "_id" : "11951", "city" : "MASTIC BEACH", "loc" : [ -72.853701, 40.765653 ], "pop" : 18812, "state" : "NY" }
+{ "_id" : "11952", "city" : "MATTITUCK", "loc" : [ -72.53629599999999, 40.994336 ], "pop" : 3896, "state" : "NY" }
+{ "_id" : "11953", "city" : "MIDDLE ISLAND", "loc" : [ -72.952539, 40.878212 ], "pop" : 9411, "state" : "NY" }
+{ "_id" : "11954", "city" : "MONTAUK", "loc" : [ -71.943963, 41.045853 ], "pop" : 3008, "state" : "NY" }
+{ "_id" : "11955", "city" : "MORICHES", "loc" : [ -72.822918, 40.809502 ], "pop" : 2045, "state" : "NY" }
+{ "_id" : "11957", "city" : "ORIENT", "loc" : [ -72.28789399999999, 41.143741 ], "pop" : 817, "state" : "NY" }
+{ "_id" : "11961", "city" : "RIDGE", "loc" : [ -72.88813500000001, 40.901846 ], "pop" : 12817, "state" : "NY" }
+{ "_id" : "11963", "city" : "SAG HARBOR", "loc" : [ -72.30674, 40.981996 ], "pop" : 7384, "state" : "NY" }
+{ "_id" : "11964", "city" : "SHELTER ISLAND", "loc" : [ -72.33661600000001, 41.064046 ], "pop" : 1144, "state" : "NY" }
+{ "_id" : "11965", "city" : "SHELTER ISLAND H", "loc" : [ -72.34808200000001, 41.074205 ], "pop" : 1119, "state" : "NY" }
+{ "_id" : "11967", "city" : "SHIRLEY", "loc" : [ -72.876043, 40.743932 ], "pop" : 97, "state" : "NY" }
+{ "_id" : "11968", "city" : "SOUTHAMPTON", "loc" : [ -72.41027099999999, 40.904341 ], "pop" : 10810, "state" : "NY" }
+{ "_id" : "11971", "city" : "SOUTHOLD", "loc" : [ -72.429039, 41.05555 ], "pop" : 5788, "state" : "NY" }
+{ "_id" : "11976", "city" : "WATER MILL", "loc" : [ -72.349069, 40.920929 ], "pop" : 1410, "state" : "NY" }
+{ "_id" : "11977", "city" : "WESTHAMPTON", "loc" : [ -72.66993100000001, 40.818031 ], "pop" : 1306, "state" : "NY" }
+{ "_id" : "11978", "city" : "WESTHAMPTON BEAC", "loc" : [ -72.644757, 40.822783 ], "pop" : 2863, "state" : "NY" }
+{ "_id" : "11980", "city" : "YAPHANK", "loc" : [ -72.917435, 40.837037 ], "pop" : 5366, "state" : "NY" }
+{ "_id" : "12007", "city" : "ALCOVE", "loc" : [ -74.034721, 42.453818 ], "pop" : 233, "state" : "NY" }
+{ "_id" : "12008", "city" : "ALPLAUS", "loc" : [ -73.900188, 42.857329 ], "pop" : 340, "state" : "NY" }
+{ "_id" : "12009", "city" : "ALTAMONT", "loc" : [ -74.019339, 42.70627 ], "pop" : 5683, "state" : "NY" }
+{ "_id" : "12010", "city" : "WEST CHARLTON", "loc" : [ -74.18393, 42.948822 ], "pop" : 32028, "state" : "NY" }
+{ "_id" : "12015", "city" : "ATHENS", "loc" : [ -73.815175, 42.2736 ], "pop" : 2538, "state" : "NY" }
+{ "_id" : "12017", "city" : "AUSTERLITZ", "loc" : [ -73.454965, 42.322272 ], "pop" : 355, "state" : "NY" }
+{ "_id" : "12018", "city" : "AVERILL PARK", "loc" : [ -73.550437, 42.636511 ], "pop" : 6528, "state" : "NY" }
+{ "_id" : "12019", "city" : "BALLSTON LAKE", "loc" : [ -73.855171, 42.919176 ], "pop" : 16331, "state" : "NY" }
+{ "_id" : "12020", "city" : "BALLSTON SPA", "loc" : [ -73.84858, 43.004956 ], "pop" : 25126, "state" : "NY" }
+{ "_id" : "12022", "city" : "BERLIN", "loc" : [ -73.370186, 42.691893 ], "pop" : 275, "state" : "NY" }
+{ "_id" : "12023", "city" : "BERNE", "loc" : [ -74.14657699999999, 42.610848 ], "pop" : 2293, "state" : "NY" }
+{ "_id" : "12024", "city" : "BRAINARD", "loc" : [ -73.61587400000001, 42.405101 ], "pop" : 285, "state" : "NY" }
+{ "_id" : "12025", "city" : "BROADALBIN", "loc" : [ -74.168367, 43.072687 ], "pop" : 4055, "state" : "NY" }
+{ "_id" : "12027", "city" : "BURNT HILLS", "loc" : [ -73.89604300000001, 42.932902 ], "pop" : 945, "state" : "NY" }
+{ "_id" : "12028", "city" : "BUSKIRK", "loc" : [ -73.44967699999999, 42.960134 ], "pop" : 1272, "state" : "NY" }
+{ "_id" : "12029", "city" : "CANAAN", "loc" : [ -73.41588900000001, 42.413168 ], "pop" : 1298, "state" : "NY" }
+{ "_id" : "12031", "city" : "CARLISLE", "loc" : [ -74.456284, 42.749754 ], "pop" : 420, "state" : "NY" }
+{ "_id" : "12032", "city" : "CAROGA LAKE", "loc" : [ -74.516915, 43.192159 ], "pop" : 545, "state" : "NY" }
+{ "_id" : "12033", "city" : "CASTLETON ON HUD", "loc" : [ -73.709529, 42.538243 ], "pop" : 7029, "state" : "NY" }
+{ "_id" : "12035", "city" : "CENTRAL BRIDGE", "loc" : [ -74.345107, 42.73696 ], "pop" : 315, "state" : "NY" }
+{ "_id" : "12036", "city" : "CHARLOTTEVILLE", "loc" : [ -74.68186300000001, 42.533034 ], "pop" : 166, "state" : "NY" }
+{ "_id" : "12037", "city" : "CHATHAM", "loc" : [ -73.587281, 42.349578 ], "pop" : 4616, "state" : "NY" }
+{ "_id" : "12041", "city" : "CLARKSVILLE", "loc" : [ -73.96877499999999, 42.566974 ], "pop" : 388, "state" : "NY" }
+{ "_id" : "12042", "city" : "CLIMAX", "loc" : [ -73.862459, 42.370808 ], "pop" : 316, "state" : "NY" }
+{ "_id" : "12043", "city" : "COBLESKILL", "loc" : [ -74.493866, 42.684047 ], "pop" : 7419, "state" : "NY" }
+{ "_id" : "12046", "city" : "COEYMANS HOLLOW", "loc" : [ -73.920588, 42.486537 ], "pop" : 979, "state" : "NY" }
+{ "_id" : "12047", "city" : "COHOES", "loc" : [ -73.712356, 42.775362 ], "pop" : 19033, "state" : "NY" }
+{ "_id" : "12051", "city" : "COXSACKIE", "loc" : [ -73.819881, 42.350142 ], "pop" : 5615, "state" : "NY" }
+{ "_id" : "12052", "city" : "CROPSEYVILLE", "loc" : [ -73.471869, 42.766718 ], "pop" : 1339, "state" : "NY" }
+{ "_id" : "12053", "city" : "DELANSON", "loc" : [ -74.18680999999999, 42.74802 ], "pop" : 4476, "state" : "NY" }
+{ "_id" : "12054", "city" : "DELMAR", "loc" : [ -73.837329, 42.61579 ], "pop" : 15502, "state" : "NY" }
+{ "_id" : "12055", "city" : "DORMANSVILLE", "loc" : [ -74.198966, 42.437859 ], "pop" : 465, "state" : "NY" }
+{ "_id" : "12056", "city" : "DUANESBURG", "loc" : [ -74.083911, 42.770839 ], "pop" : 2675, "state" : "NY" }
+{ "_id" : "12057", "city" : "WHITE CREEK", "loc" : [ -73.351974, 42.961527 ], "pop" : 2252, "state" : "NY" }
+{ "_id" : "12058", "city" : "EARLTON", "loc" : [ -73.906222, 42.352689 ], "pop" : 1015, "state" : "NY" }
+{ "_id" : "12059", "city" : "EAST BERNE", "loc" : [ -74.055488, 42.61913 ], "pop" : 2224, "state" : "NY" }
+{ "_id" : "12060", "city" : "EAST CHATHAM", "loc" : [ -73.49026000000001, 42.433028 ], "pop" : 1695, "state" : "NY" }
+{ "_id" : "12061", "city" : "EAST GREENBUSH", "loc" : [ -73.682644, 42.595096 ], "pop" : 7282, "state" : "NY" }
+{ "_id" : "12062", "city" : "EAST NASSAU", "loc" : [ -73.498407, 42.535215 ], "pop" : 2088, "state" : "NY" }
+{ "_id" : "12064", "city" : "EAST WORCESTER", "loc" : [ -74.676348, 42.621423 ], "pop" : 322, "state" : "NY" }
+{ "_id" : "12065", "city" : "CLIFTON PARK", "loc" : [ -73.785094, 42.849865 ], "pop" : 31352, "state" : "NY" }
+{ "_id" : "12066", "city" : "ESPERANCE", "loc" : [ -74.288246, 42.771677 ], "pop" : 1254, "state" : "NY" }
+{ "_id" : "12067", "city" : "FEURA BUSH", "loc" : [ -73.923743, 42.554998 ], "pop" : 1142, "state" : "NY" }
+{ "_id" : "12068", "city" : "FONDA", "loc" : [ -74.402129, 42.957078 ], "pop" : 2307, "state" : "NY" }
+{ "_id" : "12070", "city" : "FORT JOHNSON", "loc" : [ -74.248436, 42.976535 ], "pop" : 1811, "state" : "NY" }
+{ "_id" : "12071", "city" : "FULTONHAM", "loc" : [ -74.38759, 42.585914 ], "pop" : 379, "state" : "NY" }
+{ "_id" : "12072", "city" : "FULTONVILLE", "loc" : [ -74.359765, 42.903601 ], "pop" : 2356, "state" : "NY" }
+{ "_id" : "12074", "city" : "GALWAY", "loc" : [ -74.029043, 43.021693 ], "pop" : 3988, "state" : "NY" }
+{ "_id" : "12075", "city" : "GHENT", "loc" : [ -73.64864, 42.303637 ], "pop" : 2381, "state" : "NY" }
+{ "_id" : "12076", "city" : "GILBOA", "loc" : [ -74.40027499999999, 42.410835 ], "pop" : 1400, "state" : "NY" }
+{ "_id" : "12077", "city" : "GLENMONT", "loc" : [ -73.795884, 42.597147 ], "pop" : 4298, "state" : "NY" }
+{ "_id" : "12078", "city" : "GLOVERSVILLE", "loc" : [ -74.337526, 43.061603 ], "pop" : 25292, "state" : "NY" }
+{ "_id" : "12083", "city" : "GREENVILLE", "loc" : [ -74.022222, 42.411342 ], "pop" : 3645, "state" : "NY" }
+{ "_id" : "12084", "city" : "GUILDERLAND", "loc" : [ -73.897454, 42.697273 ], "pop" : 4112, "state" : "NY" }
+{ "_id" : "12086", "city" : "HAGAMAN", "loc" : [ -74.166764, 42.959715 ], "pop" : 114, "state" : "NY" }
+{ "_id" : "12087", "city" : "HANNACROIX", "loc" : [ -73.86802900000001, 42.428533 ], "pop" : 1665, "state" : "NY" }
+{ "_id" : "12090", "city" : "HOOSICK FALLS", "loc" : [ -73.35810499999999, 42.893712 ], "pop" : 5910, "state" : "NY" }
+{ "_id" : "12092", "city" : "HOWES CAVE", "loc" : [ -74.364825, 42.704526 ], "pop" : 2351, "state" : "NY" }
+{ "_id" : "12093", "city" : "JEFFERSON", "loc" : [ -74.611744, 42.499869 ], "pop" : 1353, "state" : "NY" }
+{ "_id" : "12094", "city" : "JOHNSONVILLE", "loc" : [ -73.49889899999999, 42.876875 ], "pop" : 2010, "state" : "NY" }
+{ "_id" : "12095", "city" : "JOHNSTOWN", "loc" : [ -74.37148999999999, 43.006923 ], "pop" : 13170, "state" : "NY" }
+{ "_id" : "12106", "city" : "KINDERHOOK", "loc" : [ -73.718259, 42.376675 ], "pop" : 2795, "state" : "NY" }
+{ "_id" : "12108", "city" : "LAKE PLEASANT", "loc" : [ -74.422563, 43.472543 ], "pop" : 487, "state" : "NY" }
+{ "_id" : "12110", "city" : "LATHAM", "loc" : [ -73.762985, 42.74616 ], "pop" : 20091, "state" : "NY" }
+{ "_id" : "12113", "city" : "LAWYERSVILLE", "loc" : [ -74.506969, 42.692682 ], "pop" : 91, "state" : "NY" }
+{ "_id" : "12115", "city" : "MALDEN BRIDGE", "loc" : [ -73.587958, 42.460201 ], "pop" : 56, "state" : "NY" }
+{ "_id" : "12116", "city" : "MARYLAND", "loc" : [ -74.90303299999999, 42.537075 ], "pop" : 871, "state" : "NY" }
+{ "_id" : "12117", "city" : "MAYFIELD", "loc" : [ -74.24439700000001, 43.141133 ], "pop" : 3046, "state" : "NY" }
+{ "_id" : "12118", "city" : "MECHANICVILLE", "loc" : [ -73.67317300000001, 42.967613 ], "pop" : 5890, "state" : "NY" }
+{ "_id" : "12120", "city" : "MEDUSA", "loc" : [ -74.131524, 42.451504 ], "pop" : 617, "state" : "NY" }
+{ "_id" : "12121", "city" : "MELROSE", "loc" : [ -73.60766700000001, 42.841163 ], "pop" : 1968, "state" : "NY" }
+{ "_id" : "12122", "city" : "MIDDLEBURGH", "loc" : [ -74.329168, 42.563734 ], "pop" : 4005, "state" : "NY" }
+{ "_id" : "12123", "city" : "NASSAU", "loc" : [ -73.61175299999999, 42.527141 ], "pop" : 5560, "state" : "NY" }
+{ "_id" : "12125", "city" : "NEW LEBANON", "loc" : [ -73.377295, 42.475865 ], "pop" : 557, "state" : "NY" }
+{ "_id" : "12130", "city" : "NIVERVILLE", "loc" : [ -73.485614, 42.927575 ], "pop" : 300, "state" : "NY" }
+{ "_id" : "12131", "city" : "NORTH BLENHEIM", "loc" : [ -74.428174, 42.489938 ], "pop" : 50, "state" : "NY" }
+{ "_id" : "12134", "city" : "EDINBURG", "loc" : [ -74.168361, 43.237126 ], "pop" : 3216, "state" : "NY" }
+{ "_id" : "12135", "city" : "NORTON HILL", "loc" : [ -74.078945, 42.420014 ], "pop" : 163, "state" : "NY" }
+{ "_id" : "12136", "city" : "OLD CHATHAM", "loc" : [ -73.55446999999999, 42.435692 ], "pop" : 1037, "state" : "NY" }
+{ "_id" : "12137", "city" : "PATTERSONVILLE", "loc" : [ -74.123126, 42.84995 ], "pop" : 1423, "state" : "NY" }
+{ "_id" : "12138", "city" : "TACONIC LAKE", "loc" : [ -73.371033, 42.736367 ], "pop" : 3891, "state" : "NY" }
+{ "_id" : "12139", "city" : "PISECO", "loc" : [ -74.52628199999999, 43.448125 ], "pop" : 223, "state" : "NY" }
+{ "_id" : "12140", "city" : "POESTENKILL", "loc" : [ -73.588846, 42.679548 ], "pop" : 1904, "state" : "NY" }
+{ "_id" : "12143", "city" : "RAVENA", "loc" : [ -73.821991, 42.475371 ], "pop" : 5976, "state" : "NY" }
+{ "_id" : "12144", "city" : "RENSSELAER", "loc" : [ -73.721895, 42.635855 ], "pop" : 19146, "state" : "NY" }
+{ "_id" : "12147", "city" : "RENSSELAERVILLE", "loc" : [ -74.147431, 42.513288 ], "pop" : 547, "state" : "NY" }
+{ "_id" : "12148", "city" : "REXFORD", "loc" : [ -73.87009999999999, 42.852411 ], "pop" : 2306, "state" : "NY" }
+{ "_id" : "12149", "city" : "RICHMONDVILLE", "loc" : [ -74.571001, 42.642445 ], "pop" : 1502, "state" : "NY" }
+{ "_id" : "12150", "city" : "ROTTERDAM JUNCTI", "loc" : [ -74.046857, 42.87296 ], "pop" : 1128, "state" : "NY" }
+{ "_id" : "12151", "city" : "ROUND LAKE", "loc" : [ -73.770127, 42.925994 ], "pop" : 451, "state" : "NY" }
+{ "_id" : "12153", "city" : "SAND LAKE", "loc" : [ -73.498949, 42.637912 ], "pop" : 851, "state" : "NY" }
+{ "_id" : "12154", "city" : "SCHAGHTICOKE", "loc" : [ -73.61542799999999, 42.914356 ], "pop" : 3035, "state" : "NY" }
+{ "_id" : "12155", "city" : "SCHENEVUS", "loc" : [ -74.814863, 42.59004 ], "pop" : 1895, "state" : "NY" }
+{ "_id" : "12156", "city" : "SCHODACK LANDING", "loc" : [ -73.747996, 42.481644 ], "pop" : 902, "state" : "NY" }
+{ "_id" : "12157", "city" : "SCHOHARIE", "loc" : [ -74.30473000000001, 42.661503 ], "pop" : 4095, "state" : "NY" }
+{ "_id" : "12158", "city" : "SELKIRK", "loc" : [ -73.81286299999999, 42.54861 ], "pop" : 6062, "state" : "NY" }
+{ "_id" : "12159", "city" : "SLINGERLANDS", "loc" : [ -73.871065, 42.648461 ], "pop" : 5431, "state" : "NY" }
+{ "_id" : "12160", "city" : "SLOANSVILLE", "loc" : [ -74.36417400000001, 42.759852 ], "pop" : 1152, "state" : "NY" }
+{ "_id" : "12164", "city" : "SPECULATOR", "loc" : [ -74.36667, 43.504159 ], "pop" : 400, "state" : "NY" }
+{ "_id" : "12165", "city" : "SPENCERTOWN", "loc" : [ -73.500754, 42.30908 ], "pop" : 127, "state" : "NY" }
+{ "_id" : "12166", "city" : "SPRAKERS", "loc" : [ -74.453558, 42.848446 ], "pop" : 1608, "state" : "NY" }
+{ "_id" : "12167", "city" : "STAMFORD", "loc" : [ -74.609831, 42.417409 ], "pop" : 2734, "state" : "NY" }
+{ "_id" : "12168", "city" : "STEPHENTOWN", "loc" : [ -73.42244700000001, 42.523323 ], "pop" : 1036, "state" : "NY" }
+{ "_id" : "12169", "city" : "STEPHENTOWN", "loc" : [ -73.37496400000001, 42.556224 ], "pop" : 1566, "state" : "NY" }
+{ "_id" : "12170", "city" : "STILLWATER", "loc" : [ -73.697163, 42.905652 ], "pop" : 9226, "state" : "NY" }
+{ "_id" : "12173", "city" : "STUYVESANT", "loc" : [ -73.761329, 42.359572 ], "pop" : 1806, "state" : "NY" }
+{ "_id" : "12175", "city" : "SUMMIT", "loc" : [ -74.574952, 42.587122 ], "pop" : 1247, "state" : "NY" }
+{ "_id" : "12176", "city" : "SURPRISE", "loc" : [ -73.95154100000001, 42.361171 ], "pop" : 162, "state" : "NY" }
+{ "_id" : "12180", "city" : "TROY", "loc" : [ -73.668263, 42.728748 ], "pop" : 56849, "state" : "NY" }
+{ "_id" : "12182", "city" : "TROY", "loc" : [ -73.664806, 42.782921 ], "pop" : 14688, "state" : "NY" }
+{ "_id" : "12183", "city" : "GREEN ISLAND", "loc" : [ -73.693707, 42.743812 ], "pop" : 2432, "state" : "NY" }
+{ "_id" : "12184", "city" : "VALATIE", "loc" : [ -73.668322, 42.432051 ], "pop" : 8072, "state" : "NY" }
+{ "_id" : "12185", "city" : "VALLEY FALLS", "loc" : [ -73.543674, 42.885458 ], "pop" : 1835, "state" : "NY" }
+{ "_id" : "12186", "city" : "VOORHEESVILLE", "loc" : [ -73.944773, 42.643108 ], "pop" : 7069, "state" : "NY" }
+{ "_id" : "12187", "city" : "WARNERVILLE", "loc" : [ -74.48704600000001, 42.638826 ], "pop" : 782, "state" : "NY" }
+{ "_id" : "12188", "city" : "WATERFORD", "loc" : [ -73.69948100000001, 42.809957 ], "pop" : 11576, "state" : "NY" }
+{ "_id" : "12189", "city" : "WATERVLIET", "loc" : [ -73.71234200000001, 42.729843 ], "pop" : 16509, "state" : "NY" }
+{ "_id" : "12190", "city" : "WELLS", "loc" : [ -74.288583, 43.401219 ], "pop" : 706, "state" : "NY" }
+{ "_id" : "12192", "city" : "WEST COXSACKIE", "loc" : [ -73.817033, 42.415055 ], "pop" : 1982, "state" : "NY" }
+{ "_id" : "12193", "city" : "WESTERLO", "loc" : [ -74.039383, 42.515621 ], "pop" : 1880, "state" : "NY" }
+{ "_id" : "12194", "city" : "WEST FULTON", "loc" : [ -74.463105, 42.550615 ], "pop" : 72, "state" : "NY" }
+{ "_id" : "12196", "city" : "WEST SAND LAKE", "loc" : [ -73.610896, 42.637969 ], "pop" : 2511, "state" : "NY" }
+{ "_id" : "12197", "city" : "WORCESTER", "loc" : [ -74.72992000000001, 42.604889 ], "pop" : 2239, "state" : "NY" }
+{ "_id" : "12198", "city" : "WYNANTSKILL", "loc" : [ -73.63826, 42.687785 ], "pop" : 6192, "state" : "NY" }
+{ "_id" : "12202", "city" : "ALBANY", "loc" : [ -73.764071, 42.641314 ], "pop" : 11097, "state" : "NY" }
+{ "_id" : "12203", "city" : "MC KOWNVILLE", "loc" : [ -73.821988, 42.676757 ], "pop" : 33356, "state" : "NY" }
+{ "_id" : "12204", "city" : "ALBANY", "loc" : [ -73.735364, 42.684667 ], "pop" : 6927, "state" : "NY" }
+{ "_id" : "12205", "city" : "ROESSLEVILLE", "loc" : [ -73.82017399999999, 42.713116 ], "pop" : 26008, "state" : "NY" }
+{ "_id" : "12206", "city" : "ALBANY", "loc" : [ -73.774406, 42.668326 ], "pop" : 17230, "state" : "NY" }
+{ "_id" : "12207", "city" : "ALBANY", "loc" : [ -73.75232699999999, 42.658133 ], "pop" : 2709, "state" : "NY" }
+{ "_id" : "12208", "city" : "ALBANY", "loc" : [ -73.796357, 42.655989 ], "pop" : 22041, "state" : "NY" }
+{ "_id" : "12209", "city" : "ALBANY", "loc" : [ -73.78538500000001, 42.641665 ], "pop" : 10008, "state" : "NY" }
+{ "_id" : "12210", "city" : "ALBANY", "loc" : [ -73.76052, 42.65677 ], "pop" : 9374, "state" : "NY" }
+{ "_id" : "12211", "city" : "LOUDONVILLE", "loc" : [ -73.769982, 42.704693 ], "pop" : 12283, "state" : "NY" }
+{ "_id" : "12302", "city" : "MAYFAIR", "loc" : [ -73.955051, 42.858839 ], "pop" : 27516, "state" : "NY" }
+{ "_id" : "12303", "city" : "ROTTERDAM", "loc" : [ -73.938776, 42.769645 ], "pop" : 28448, "state" : "NY" }
+{ "_id" : "12304", "city" : "SCHENECTADY", "loc" : [ -73.909432, 42.784083 ], "pop" : 20431, "state" : "NY" }
+{ "_id" : "12305", "city" : "SCHENECTADY", "loc" : [ -73.939786, 42.816131 ], "pop" : 6253, "state" : "NY" }
+{ "_id" : "12306", "city" : "SCHENECTADY", "loc" : [ -73.98087599999999, 42.790384 ], "pop" : 23182, "state" : "NY" }
+{ "_id" : "12307", "city" : "SCHENECTADY", "loc" : [ -73.93634900000001, 42.804653 ], "pop" : 8534, "state" : "NY" }
+{ "_id" : "12308", "city" : "SCHENECTADY", "loc" : [ -73.920591, 42.817928 ], "pop" : 14055, "state" : "NY" }
+{ "_id" : "12309", "city" : "NISKAYUNA", "loc" : [ -73.87826800000001, 42.796168 ], "pop" : 27928, "state" : "NY" }
+{ "_id" : "12401", "city" : "EDDYVILLE", "loc" : [ -74.02357499999999, 41.930126 ], "pop" : 32883, "state" : "NY" }
+{ "_id" : "12404", "city" : "ACCORD", "loc" : [ -74.235336, 41.808308 ], "pop" : 2695, "state" : "NY" }
+{ "_id" : "12405", "city" : "ACRA", "loc" : [ -74.085723, 42.330367 ], "pop" : 525, "state" : "NY" }
+{ "_id" : "12406", "city" : "ARKVILLE", "loc" : [ -74.554453, 42.082262 ], "pop" : 141, "state" : "NY" }
+{ "_id" : "12407", "city" : "ASHLAND", "loc" : [ -74.307925, 42.237174 ], "pop" : 28, "state" : "NY" }
+{ "_id" : "12409", "city" : "SHADY", "loc" : [ -74.17129799999999, 42.041991 ], "pop" : 960, "state" : "NY" }
+{ "_id" : "12410", "city" : "OLIVEREA", "loc" : [ -74.44665500000001, 42.143884 ], "pop" : 69, "state" : "NY" }
+{ "_id" : "12411", "city" : "BLOOMINGTON", "loc" : [ -74.066889, 41.856165 ], "pop" : 148, "state" : "NY" }
+{ "_id" : "12412", "city" : "BOICEVILLE", "loc" : [ -74.26580800000001, 42.004761 ], "pop" : 556, "state" : "NY" }
+{ "_id" : "12413", "city" : "CAIRO", "loc" : [ -74.01154, 42.30965 ], "pop" : 3057, "state" : "NY" }
+{ "_id" : "12414", "city" : "CATSKILL", "loc" : [ -73.89853599999999, 42.227598 ], "pop" : 12128, "state" : "NY" }
+{ "_id" : "12416", "city" : "CHICHESTER", "loc" : [ -74.281565, 42.087965 ], "pop" : 642, "state" : "NY" }
+{ "_id" : "12418", "city" : "CORNWALLVILLE", "loc" : [ -74.16309200000001, 42.362874 ], "pop" : 380, "state" : "NY" }
+{ "_id" : "12419", "city" : "COTTEKILL", "loc" : [ -74.103774, 41.846706 ], "pop" : 399, "state" : "NY" }
+{ "_id" : "12421", "city" : "DENVER", "loc" : [ -74.540654, 42.252204 ], "pop" : 62, "state" : "NY" }
+{ "_id" : "12422", "city" : "DURHAM", "loc" : [ -74.184926, 42.402037 ], "pop" : 216, "state" : "NY" }
+{ "_id" : "12423", "city" : "EAST DURHAM", "loc" : [ -74.11169, 42.385978 ], "pop" : 1097, "state" : "NY" }
+{ "_id" : "12424", "city" : "EAST JEWETT", "loc" : [ -74.207981, 42.280567 ], "pop" : 241, "state" : "NY" }
+{ "_id" : "12427", "city" : "ELKA PARK", "loc" : [ -74.124539, 42.164309 ], "pop" : 389, "state" : "NY" }
+{ "_id" : "12428", "city" : "ELLENVILLE", "loc" : [ -74.414125, 41.721805 ], "pop" : 6902, "state" : "NY" }
+{ "_id" : "12430", "city" : "HALCOTT CENTER", "loc" : [ -74.531908, 42.178765 ], "pop" : 1151, "state" : "NY" }
+{ "_id" : "12431", "city" : "FREEHOLD", "loc" : [ -74.06226599999999, 42.3815 ], "pop" : 255, "state" : "NY" }
+{ "_id" : "12433", "city" : "GLENFORD", "loc" : [ -74.153154, 42.005342 ], "pop" : 354, "state" : "NY" }
+{ "_id" : "12434", "city" : "GRAND GORGE", "loc" : [ -74.531173, 42.387358 ], "pop" : 13, "state" : "NY" }
+{ "_id" : "12435", "city" : "GREENFIELD PARK", "loc" : [ -74.52007399999999, 41.728133 ], "pop" : 241, "state" : "NY" }
+{ "_id" : "12439", "city" : "EAST WINDHAM", "loc" : [ -74.21306300000001, 42.259032 ], "pop" : 57, "state" : "NY" }
+{ "_id" : "12440", "city" : "HIGH FALLS", "loc" : [ -74.131122, 41.816749 ], "pop" : 2168, "state" : "NY" }
+{ "_id" : "12442", "city" : "HUNTER", "loc" : [ -74.20375300000001, 42.237316 ], "pop" : 616, "state" : "NY" }
+{ "_id" : "12443", "city" : "HURLEY", "loc" : [ -74.06873, 41.932743 ], "pop" : 1229, "state" : "NY" }
+{ "_id" : "12444", "city" : "JEWETT", "loc" : [ -74.279274, 42.269383 ], "pop" : 231, "state" : "NY" }
+{ "_id" : "12446", "city" : "KERHONKSON", "loc" : [ -74.30345699999999, 41.793866 ], "pop" : 4220, "state" : "NY" }
+{ "_id" : "12448", "city" : "LAKE HILL", "loc" : [ -74.212338, 42.073271 ], "pop" : 73, "state" : "NY" }
+{ "_id" : "12449", "city" : "LAKE KATRINE", "loc" : [ -73.992379, 41.991787 ], "pop" : 3763, "state" : "NY" }
+{ "_id" : "12450", "city" : "LANESVILLE", "loc" : [ -74.19714999999999, 42.189149 ], "pop" : 1131, "state" : "NY" }
+{ "_id" : "12451", "city" : "LEEDS", "loc" : [ -73.94572599999999, 42.304506 ], "pop" : 779, "state" : "NY" }
+{ "_id" : "12454", "city" : "MAPLECREST", "loc" : [ -74.165522, 42.299485 ], "pop" : 342, "state" : "NY" }
+{ "_id" : "12455", "city" : "KELLY CORNERS", "loc" : [ -74.648853, 42.163702 ], "pop" : 2756, "state" : "NY" }
+{ "_id" : "12456", "city" : "MOUNT MARION", "loc" : [ -74.00021099999999, 42.035704 ], "pop" : 753, "state" : "NY" }
+{ "_id" : "12457", "city" : "MOUNT TREMPER", "loc" : [ -74.248481, 42.043545 ], "pop" : 941, "state" : "NY" }
+{ "_id" : "12458", "city" : "NAPANOCH", "loc" : [ -74.380354, 41.758965 ], "pop" : 3502, "state" : "NY" }
+{ "_id" : "12460", "city" : "OAK HILL", "loc" : [ -74.152832, 42.406902 ], "pop" : 294, "state" : "NY" }
+{ "_id" : "12461", "city" : "KRUMVILLE", "loc" : [ -74.246954, 41.895906 ], "pop" : 1423, "state" : "NY" }
+{ "_id" : "12463", "city" : "PALENVILLE", "loc" : [ -74.01667399999999, 42.17294 ], "pop" : 1195, "state" : "NY" }
+{ "_id" : "12464", "city" : "PHOENICIA", "loc" : [ -74.33932799999999, 42.054426 ], "pop" : 966, "state" : "NY" }
+{ "_id" : "12465", "city" : "PINE HILL", "loc" : [ -74.487562, 42.133974 ], "pop" : 392, "state" : "NY" }
+{ "_id" : "12466", "city" : "PORT EWEN", "loc" : [ -73.987161, 41.913113 ], "pop" : 7283, "state" : "NY" }
+{ "_id" : "12468", "city" : "PRATTSVILLE", "loc" : [ -74.38950199999999, 42.297904 ], "pop" : 1669, "state" : "NY" }
+{ "_id" : "12469", "city" : "PRESTON HOLLOW", "loc" : [ -74.24199, 42.456348 ], "pop" : 421, "state" : "NY" }
+{ "_id" : "12470", "city" : "PURLING", "loc" : [ -74.01138, 42.275497 ], "pop" : 516, "state" : "NY" }
+{ "_id" : "12472", "city" : "ROSENDALE", "loc" : [ -74.072999, 41.840248 ], "pop" : 2939, "state" : "NY" }
+{ "_id" : "12473", "city" : "ROUND TOP", "loc" : [ -74.052279, 42.267782 ], "pop" : 454, "state" : "NY" }
+{ "_id" : "12474", "city" : "ROXBURY", "loc" : [ -74.540519, 42.311688 ], "pop" : 2178, "state" : "NY" }
+{ "_id" : "12477", "city" : "SAUGERTIES", "loc" : [ -73.97968400000001, 42.07376 ], "pop" : 18932, "state" : "NY" }
+{ "_id" : "12480", "city" : "SHANDAKEN", "loc" : [ -74.40908399999999, 42.108353 ], "pop" : 593, "state" : "NY" }
+{ "_id" : "12481", "city" : "SHOKAN", "loc" : [ -74.21194300000001, 41.976678 ], "pop" : 1494, "state" : "NY" }
+{ "_id" : "12482", "city" : "SOUTH CAIRO", "loc" : [ -73.963982, 42.27338 ], "pop" : 360, "state" : "NY" }
+{ "_id" : "12484", "city" : "STONE RIDGE", "loc" : [ -74.169748, 41.861562 ], "pop" : 2389, "state" : "NY" }
+{ "_id" : "12485", "city" : "TANNERSVILLE", "loc" : [ -74.10144099999999, 42.203179 ], "pop" : 492, "state" : "NY" }
+{ "_id" : "12486", "city" : "TILLSON", "loc" : [ -74.072219, 41.816279 ], "pop" : 377, "state" : "NY" }
+{ "_id" : "12487", "city" : "ULSTER PARK", "loc" : [ -73.994843, 41.865109 ], "pop" : 3625, "state" : "NY" }
+{ "_id" : "12491", "city" : "WEST HURLEY", "loc" : [ -74.11523200000001, 41.990816 ], "pop" : 2365, "state" : "NY" }
+{ "_id" : "12492", "city" : "WEST KILL", "loc" : [ -74.361994, 42.204584 ], "pop" : 413, "state" : "NY" }
+{ "_id" : "12494", "city" : "WEST SHOKAN", "loc" : [ -74.285117, 41.955478 ], "pop" : 809, "state" : "NY" }
+{ "_id" : "12495", "city" : "WILLOW", "loc" : [ -74.20253700000001, 42.092318 ], "pop" : 145, "state" : "NY" }
+{ "_id" : "12496", "city" : "WINDHAM", "loc" : [ -74.262017, 42.317465 ], "pop" : 1559, "state" : "NY" }
+{ "_id" : "12498", "city" : "WOODSTOCK", "loc" : [ -74.111974, 42.034793 ], "pop" : 4827, "state" : "NY" }
+{ "_id" : "12501", "city" : "AMENIA", "loc" : [ -73.554158, 41.844695 ], "pop" : 2325, "state" : "NY" }
+{ "_id" : "12502", "city" : "ANCRAM", "loc" : [ -73.642368, 42.085093 ], "pop" : 600, "state" : "NY" }
+{ "_id" : "12503", "city" : "ANCRAMDALE", "loc" : [ -73.58187, 42.038103 ], "pop" : 918, "state" : "NY" }
+{ "_id" : "12507", "city" : "BARRYTOWN", "loc" : [ -73.92148400000001, 42.0006 ], "pop" : 388, "state" : "NY" }
+{ "_id" : "12508", "city" : "BEACON", "loc" : [ -73.963384, 41.509681 ], "pop" : 20022, "state" : "NY" }
+{ "_id" : "12513", "city" : "CLAVERACK", "loc" : [ -73.72284399999999, 42.2183 ], "pop" : 447, "state" : "NY" }
+{ "_id" : "12514", "city" : "CLINTON CORNERS", "loc" : [ -73.765867, 41.869262 ], "pop" : 2667, "state" : "NY" }
+{ "_id" : "12515", "city" : "CLINTONDALE", "loc" : [ -74.055713, 41.674939 ], "pop" : 1171, "state" : "NY" }
+{ "_id" : "12516", "city" : "COPAKE", "loc" : [ -73.552588, 42.111329 ], "pop" : 1511, "state" : "NY" }
+{ "_id" : "12517", "city" : "COPAKE FALLS", "loc" : [ -73.510773, 42.136737 ], "pop" : 163, "state" : "NY" }
+{ "_id" : "12518", "city" : "CORNWALL", "loc" : [ -74.053877, 41.430944 ], "pop" : 8120, "state" : "NY" }
+{ "_id" : "12520", "city" : "CORNWALL ON HUDS", "loc" : [ -74.01641100000001, 41.443031 ], "pop" : 2980, "state" : "NY" }
+{ "_id" : "12521", "city" : "CRARYVILLE", "loc" : [ -73.657128, 42.175961 ], "pop" : 1377, "state" : "NY" }
+{ "_id" : "12522", "city" : "DOVER PLAINS", "loc" : [ -73.587024, 41.735054 ], "pop" : 4775, "state" : "NY" }
+{ "_id" : "12523", "city" : "ELIZAVILLE", "loc" : [ -73.781814, 42.090173 ], "pop" : 2158, "state" : "NY" }
+{ "_id" : "12524", "city" : "FISHKILL", "loc" : [ -73.89791, 41.540352 ], "pop" : 11165, "state" : "NY" }
+{ "_id" : "12525", "city" : "GARDINER", "loc" : [ -74.16715499999999, 41.657615 ], "pop" : 3900, "state" : "NY" }
+{ "_id" : "12526", "city" : "GERMANTOWN", "loc" : [ -73.86245099999999, 42.1219 ], "pop" : 4061, "state" : "NY" }
+{ "_id" : "12528", "city" : "HIGHLAND", "loc" : [ -73.992825, 41.716691 ], "pop" : 11011, "state" : "NY" }
+{ "_id" : "12529", "city" : "HILLSDALE", "loc" : [ -73.548306, 42.186816 ], "pop" : 3084, "state" : "NY" }
+{ "_id" : "12531", "city" : "HOLMES", "loc" : [ -73.662751, 41.532461 ], "pop" : 3248, "state" : "NY" }
+{ "_id" : "12533", "city" : "HOPEWELL JUNCTIO", "loc" : [ -73.79758099999999, 41.576639 ], "pop" : 18770, "state" : "NY" }
+{ "_id" : "12534", "city" : "HUDSON", "loc" : [ -73.75524799999999, 42.246978 ], "pop" : 21205, "state" : "NY" }
+{ "_id" : "12538", "city" : "HYDE PARK", "loc" : [ -73.906347, 41.788724 ], "pop" : 15184, "state" : "NY" }
+{ "_id" : "12540", "city" : "LAGRANGEVILLE", "loc" : [ -73.744955, 41.661471 ], "pop" : 5539, "state" : "NY" }
+{ "_id" : "12542", "city" : "MARLBORO", "loc" : [ -73.988017, 41.605612 ], "pop" : 4489, "state" : "NY" }
+{ "_id" : "12543", "city" : "MAYBROOK", "loc" : [ -74.216312, 41.48865 ], "pop" : 2860, "state" : "NY" }
+{ "_id" : "12545", "city" : "MILLBROOK", "loc" : [ -73.688491, 41.780334 ], "pop" : 4503, "state" : "NY" }
+{ "_id" : "12546", "city" : "MILLERTON", "loc" : [ -73.52870900000001, 41.953623 ], "pop" : 3131, "state" : "NY" }
+{ "_id" : "12547", "city" : "MILTON", "loc" : [ -73.977194, 41.653487 ], "pop" : 2834, "state" : "NY" }
+{ "_id" : "12548", "city" : "MODENA", "loc" : [ -74.103578, 41.650347 ], "pop" : 810, "state" : "NY" }
+{ "_id" : "12549", "city" : "MONTGOMERY", "loc" : [ -74.253417, 41.53332 ], "pop" : 7421, "state" : "NY" }
+{ "_id" : "12550", "city" : "MIDDLE HOPE", "loc" : [ -74.03598, 41.517833 ], "pop" : 47939, "state" : "NY" }
+{ "_id" : "12553", "city" : "NEW WINDSOR", "loc" : [ -74.056596, 41.472374 ], "pop" : 20576, "state" : "NY" }
+{ "_id" : "12561", "city" : "MOHONK LAKE", "loc" : [ -74.08387500000001, 41.743346 ], "pop" : 16394, "state" : "NY" }
+{ "_id" : "12563", "city" : "PATTERSON", "loc" : [ -73.58149, 41.488761 ], "pop" : 6107, "state" : "NY" }
+{ "_id" : "12564", "city" : "PAWLING", "loc" : [ -73.594847, 41.574893 ], "pop" : 4511, "state" : "NY" }
+{ "_id" : "12566", "city" : "PINE BUSH", "loc" : [ -74.326311, 41.617758 ], "pop" : 7589, "state" : "NY" }
+{ "_id" : "12567", "city" : "PINE PLAINS", "loc" : [ -73.66022700000001, 41.989569 ], "pop" : 2771, "state" : "NY" }
+{ "_id" : "12569", "city" : "PLEASANT VALLEY", "loc" : [ -73.81427600000001, 41.747032 ], "pop" : 7978, "state" : "NY" }
+{ "_id" : "12570", "city" : "POUGHQUAG", "loc" : [ -73.67832799999999, 41.61936 ], "pop" : 3867, "state" : "NY" }
+{ "_id" : "12571", "city" : "RED HOOK", "loc" : [ -73.85457700000001, 42.006439 ], "pop" : 8890, "state" : "NY" }
+{ "_id" : "12572", "city" : "RHINEBECK", "loc" : [ -73.88875400000001, 41.927206 ], "pop" : 9458, "state" : "NY" }
+{ "_id" : "12575", "city" : "ROCK TAVERN", "loc" : [ -74.16588, 41.457523 ], "pop" : 2202, "state" : "NY" }
+{ "_id" : "12577", "city" : "SALISBURY MILLS", "loc" : [ -74.12137800000001, 41.449714 ], "pop" : 573, "state" : "NY" }
+{ "_id" : "12578", "city" : "SALT POINT", "loc" : [ -73.801329, 41.805041 ], "pop" : 1521, "state" : "NY" }
+{ "_id" : "12580", "city" : "STAATSBURG", "loc" : [ -73.898838, 41.850193 ], "pop" : 2957, "state" : "NY" }
+{ "_id" : "12581", "city" : "STANFORDVILLE", "loc" : [ -73.694467, 41.887726 ], "pop" : 2356, "state" : "NY" }
+{ "_id" : "12582", "city" : "STORMVILLE", "loc" : [ -73.725548, 41.551193 ], "pop" : 6735, "state" : "NY" }
+{ "_id" : "12583", "city" : "TIVOLI", "loc" : [ -73.902514, 42.057945 ], "pop" : 1614, "state" : "NY" }
+{ "_id" : "12585", "city" : "VERBANK", "loc" : [ -73.71841000000001, 41.722664 ], "pop" : 989, "state" : "NY" }
+{ "_id" : "12586", "city" : "WALDEN", "loc" : [ -74.176395, 41.559631 ], "pop" : 10479, "state" : "NY" }
+{ "_id" : "12589", "city" : "WALLKILL", "loc" : [ -74.14385299999999, 41.615952 ], "pop" : 11209, "state" : "NY" }
+{ "_id" : "12590", "city" : "NEW HAMBURG", "loc" : [ -73.89058799999999, 41.592199 ], "pop" : 31950, "state" : "NY" }
+{ "_id" : "12592", "city" : "WASSAIC", "loc" : [ -73.554382, 41.775884 ], "pop" : 2064, "state" : "NY" }
+{ "_id" : "12594", "city" : "WINGDALE", "loc" : [ -73.555621, 41.653824 ], "pop" : 3716, "state" : "NY" }
+{ "_id" : "12601", "city" : "SOUTH ROAD", "loc" : [ -73.9218, 41.702082 ], "pop" : 38212, "state" : "NY" }
+{ "_id" : "12603", "city" : "ARLINGTON", "loc" : [ -73.885217, 41.676775 ], "pop" : 40724, "state" : "NY" }
+{ "_id" : "12701", "city" : "MONTICELLO", "loc" : [ -74.700748, 41.65158 ], "pop" : 12122, "state" : "NY" }
+{ "_id" : "12719", "city" : "BARRYVILLE", "loc" : [ -74.915234, 41.491162 ], "pop" : 772, "state" : "NY" }
+{ "_id" : "12720", "city" : "BETHEL", "loc" : [ -74.893984, 41.669326 ], "pop" : 139, "state" : "NY" }
+{ "_id" : "12721", "city" : "BLOOMINGBURG", "loc" : [ -74.430351, 41.564427 ], "pop" : 6139, "state" : "NY" }
+{ "_id" : "12723", "city" : "CALLICOON", "loc" : [ -75.025688, 41.7754 ], "pop" : 2492, "state" : "NY" }
+{ "_id" : "12725", "city" : "CLARYVILLE", "loc" : [ -74.529287, 41.965666 ], "pop" : 137, "state" : "NY" }
+{ "_id" : "12726", "city" : "FOSTERDALE", "loc" : [ -74.980687, 41.698208 ], "pop" : 1120, "state" : "NY" }
+{ "_id" : "12727", "city" : "COCHECTON CENTER", "loc" : [ -74.977116, 41.645776 ], "pop" : 131, "state" : "NY" }
+{ "_id" : "12729", "city" : "CUDDEBACKVILLE", "loc" : [ -74.59756400000001, 41.477601 ], "pop" : 1191, "state" : "NY" }
+{ "_id" : "12732", "city" : "ELDRED", "loc" : [ -74.89676900000001, 41.532793 ], "pop" : 899, "state" : "NY" }
+{ "_id" : "12733", "city" : "FALLSBURG", "loc" : [ -74.615409, 41.7273 ], "pop" : 866, "state" : "NY" }
+{ "_id" : "12734", "city" : "GROSSINGER", "loc" : [ -74.754873, 41.730029 ], "pop" : 851, "state" : "NY" }
+{ "_id" : "12736", "city" : "FREMONT CENTER", "loc" : [ -75.029635, 41.847134 ], "pop" : 349, "state" : "NY" }
+{ "_id" : "12737", "city" : "GLEN SPEY", "loc" : [ -74.799493, 41.48576 ], "pop" : 840, "state" : "NY" }
+{ "_id" : "12738", "city" : "GLEN WILD", "loc" : [ -74.58328899999999, 41.654536 ], "pop" : 158, "state" : "NY" }
+{ "_id" : "12739", "city" : "GODEFFROY", "loc" : [ -74.605716, 41.442347 ], "pop" : 615, "state" : "NY" }
+{ "_id" : "12740", "city" : "GRAHAMSVILLE", "loc" : [ -74.512697, 41.880659 ], "pop" : 1305, "state" : "NY" }
+{ "_id" : "12741", "city" : "MILESES", "loc" : [ -75.09980899999999, 41.831288 ], "pop" : 73, "state" : "NY" }
+{ "_id" : "12742", "city" : "HARRIS", "loc" : [ -74.7218, 41.714055 ], "pop" : 272, "state" : "NY" }
+{ "_id" : "12743", "city" : "HIGHLAND LAKE", "loc" : [ -74.851615, 41.530925 ], "pop" : 292, "state" : "NY" }
+{ "_id" : "12745", "city" : "HORTONVILLE", "loc" : [ -75.026329, 41.78568 ], "pop" : 59, "state" : "NY" }
+{ "_id" : "12746", "city" : "HUGUENOT", "loc" : [ -74.64261, 41.437162 ], "pop" : 885, "state" : "NY" }
+{ "_id" : "12747", "city" : "HURLEYVILLE", "loc" : [ -74.65344, 41.760882 ], "pop" : 3303, "state" : "NY" }
+{ "_id" : "12748", "city" : "JEFFERSONVILLE", "loc" : [ -74.919574, 41.778394 ], "pop" : 1698, "state" : "NY" }
+{ "_id" : "12750", "city" : "KENOZA LAKE", "loc" : [ -74.935384, 41.777802 ], "pop" : 443, "state" : "NY" }
+{ "_id" : "12751", "city" : "KIAMESHA LAKE", "loc" : [ -74.67240200000001, 41.683825 ], "pop" : 320, "state" : "NY" }
+{ "_id" : "12752", "city" : "LAKE HUNTINGTON", "loc" : [ -74.994933, 41.678158 ], "pop" : 111, "state" : "NY" }
+{ "_id" : "12753", "city" : "LEW BEACH", "loc" : [ -74.728835, 42.015762 ], "pop" : 126, "state" : "NY" }
+{ "_id" : "12754", "city" : "LIBERTY", "loc" : [ -74.748397, 41.79618 ], "pop" : 7361, "state" : "NY" }
+{ "_id" : "12758", "city" : "LIVINGSTON MANOR", "loc" : [ -74.827028, 41.87779 ], "pop" : 4510, "state" : "NY" }
+{ "_id" : "12759", "city" : "LOCH SHELDRAKE", "loc" : [ -74.661406, 41.778899 ], "pop" : 466, "state" : "NY" }
+{ "_id" : "12760", "city" : "LONG EDDY", "loc" : [ -75.094157, 41.864359 ], "pop" : 279, "state" : "NY" }
+{ "_id" : "12762", "city" : "MONGAUP VALLEY", "loc" : [ -74.802772, 41.681017 ], "pop" : 228, "state" : "NY" }
+{ "_id" : "12763", "city" : "MOUNTAIN DALE", "loc" : [ -74.53576200000001, 41.691763 ], "pop" : 841, "state" : "NY" }
+{ "_id" : "12764", "city" : "NARROWSBURG", "loc" : [ -75.010687, 41.592108 ], "pop" : 1576, "state" : "NY" }
+{ "_id" : "12765", "city" : "NEVERSINK", "loc" : [ -74.61272599999999, 41.849205 ], "pop" : 868, "state" : "NY" }
+{ "_id" : "12766", "city" : "NORTH BRANCH", "loc" : [ -74.982388, 41.814184 ], "pop" : 409, "state" : "NY" }
+{ "_id" : "12768", "city" : "PARKSVILLE", "loc" : [ -74.735933, 41.851686 ], "pop" : 1199, "state" : "NY" }
+{ "_id" : "12770", "city" : "POND EDDY", "loc" : [ -74.84102900000001, 41.451068 ], "pop" : 448, "state" : "NY" }
+{ "_id" : "12771", "city" : "PORT JERVIS", "loc" : [ -74.66909699999999, 41.378557 ], "pop" : 14959, "state" : "NY" }
+{ "_id" : "12775", "city" : "ROCK HILL", "loc" : [ -74.58722299999999, 41.613351 ], "pop" : 1027, "state" : "NY" }
+{ "_id" : "12776", "city" : "COOK FALLS", "loc" : [ -74.923704, 41.945774 ], "pop" : 2737, "state" : "NY" }
+{ "_id" : "12777", "city" : "FORESTBURGH", "loc" : [ -74.724087, 41.569093 ], "pop" : 581, "state" : "NY" }
+{ "_id" : "12779", "city" : "SOUTH FALLSBURG", "loc" : [ -74.644401, 41.704192 ], "pop" : 1838, "state" : "NY" }
+{ "_id" : "12780", "city" : "SPARROWBUSH", "loc" : [ -74.723647, 41.435886 ], "pop" : 1527, "state" : "NY" }
+{ "_id" : "12782", "city" : "SUNDOWN", "loc" : [ -74.550838, 41.823822 ], "pop" : 635, "state" : "NY" }
+{ "_id" : "12783", "city" : "SWAN LAKE", "loc" : [ -74.834092, 41.728479 ], "pop" : 1707, "state" : "NY" }
+{ "_id" : "12786", "city" : "WHITE LAKE", "loc" : [ -74.865437, 41.648498 ], "pop" : 178, "state" : "NY" }
+{ "_id" : "12787", "city" : "WHITE SULPHUR SP", "loc" : [ -74.828065, 41.790042 ], "pop" : 161, "state" : "NY" }
+{ "_id" : "12788", "city" : "WOODBOURNE", "loc" : [ -74.592828, 41.770807 ], "pop" : 2561, "state" : "NY" }
+{ "_id" : "12789", "city" : "WOODRIDGE", "loc" : [ -74.581518, 41.716955 ], "pop" : 2047, "state" : "NY" }
+{ "_id" : "12790", "city" : "WURTSBORO", "loc" : [ -74.503891, 41.587667 ], "pop" : 4589, "state" : "NY" }
+{ "_id" : "12791", "city" : "YOUNGSVILLE", "loc" : [ -74.88877599999999, 41.803238 ], "pop" : 115, "state" : "NY" }
+{ "_id" : "12792", "city" : "YULAN", "loc" : [ -74.926224, 41.538378 ], "pop" : 107, "state" : "NY" }
+{ "_id" : "12801", "city" : "QUEENSBURY", "loc" : [ -73.648816, 43.312539 ], "pop" : 15023, "state" : "NY" }
+{ "_id" : "12803", "city" : "SOUTH GLENS FALL", "loc" : [ -73.637947, 43.283911 ], "pop" : 8758, "state" : "NY" }
+{ "_id" : "12804", "city" : "QUEENSBURY", "loc" : [ -73.68184599999999, 43.328983 ], "pop" : 20993, "state" : "NY" }
+{ "_id" : "12808", "city" : "ADIRONDACK", "loc" : [ -73.78248600000001, 43.716479 ], "pop" : 105, "state" : "NY" }
+{ "_id" : "12809", "city" : "ARGYLE", "loc" : [ -73.46407600000001, 43.238084 ], "pop" : 2930, "state" : "NY" }
+{ "_id" : "12810", "city" : "ATHOL", "loc" : [ -73.88169499999999, 43.483872 ], "pop" : 588, "state" : "NY" }
+{ "_id" : "12812", "city" : "BLUE MOUNTAIN LA", "loc" : [ -74.42983099999999, 43.837499 ], "pop" : 234, "state" : "NY" }
+{ "_id" : "12814", "city" : "BOLTON LANDING", "loc" : [ -73.671392, 43.576641 ], "pop" : 1298, "state" : "NY" }
+{ "_id" : "12815", "city" : "BRANT LAKE", "loc" : [ -73.72045799999999, 43.698875 ], "pop" : 807, "state" : "NY" }
+{ "_id" : "12816", "city" : "CAMBRIDGE", "loc" : [ -73.38137500000001, 43.046585 ], "pop" : 4243, "state" : "NY" }
+{ "_id" : "12817", "city" : "CHESTERTOWN", "loc" : [ -73.806641, 43.645053 ], "pop" : 2141, "state" : "NY" }
+{ "_id" : "12819", "city" : "CLEMONS", "loc" : [ -73.432613, 43.643544 ], "pop" : 169, "state" : "NY" }
+{ "_id" : "12821", "city" : "COMSTOCK", "loc" : [ -73.360607, 43.456706 ], "pop" : 1226, "state" : "NY" }
+{ "_id" : "12822", "city" : "CORINTH", "loc" : [ -73.836901, 43.242569 ], "pop" : 6492, "state" : "NY" }
+{ "_id" : "12823", "city" : "COSSAYUNA", "loc" : [ -73.41237, 43.175059 ], "pop" : 241, "state" : "NY" }
+{ "_id" : "12824", "city" : "DIAMOND POINT", "loc" : [ -73.700123, 43.515553 ], "pop" : 770, "state" : "NY" }
+{ "_id" : "12826", "city" : "EAST GREENWICH", "loc" : [ -73.392425, 43.157918 ], "pop" : 116, "state" : "NY" }
+{ "_id" : "12827", "city" : "FORT ANN", "loc" : [ -73.478381, 43.428457 ], "pop" : 6818, "state" : "NY" }
+{ "_id" : "12828", "city" : "FORT EDWARD", "loc" : [ -73.58216899999999, 43.265321 ], "pop" : 5507, "state" : "NY" }
+{ "_id" : "12831", "city" : "GANSEVOORT", "loc" : [ -73.70526700000001, 43.180343 ], "pop" : 14485, "state" : "NY" }
+{ "_id" : "12832", "city" : "GRANVILLE", "loc" : [ -73.297825, 43.377562 ], "pop" : 6201, "state" : "NY" }
+{ "_id" : "12833", "city" : "GREENFIELD CENTE", "loc" : [ -73.860193, 43.122488 ], "pop" : 4753, "state" : "NY" }
+{ "_id" : "12834", "city" : "THOMSON", "loc" : [ -73.506658, 43.096183 ], "pop" : 6028, "state" : "NY" }
+{ "_id" : "12835", "city" : "HADLEY", "loc" : [ -73.949905, 43.301268 ], "pop" : 1840, "state" : "NY" }
+{ "_id" : "12836", "city" : "HAGUE", "loc" : [ -73.528172, 43.74631 ], "pop" : 692, "state" : "NY" }
+{ "_id" : "12837", "city" : "HAMPTON", "loc" : [ -73.273072, 43.462135 ], "pop" : 419, "state" : "NY" }
+{ "_id" : "12838", "city" : "HARTFORD", "loc" : [ -73.404946, 43.349281 ], "pop" : 679, "state" : "NY" }
+{ "_id" : "12839", "city" : "HUDSON FALLS", "loc" : [ -73.574607, 43.314863 ], "pop" : 12866, "state" : "NY" }
+{ "_id" : "12842", "city" : "INDIAN LAKE", "loc" : [ -74.27663800000001, 43.760594 ], "pop" : 1247, "state" : "NY" }
+{ "_id" : "12843", "city" : "JOHNSBURG", "loc" : [ -74.021254, 43.634081 ], "pop" : 1437, "state" : "NY" }
+{ "_id" : "12844", "city" : "PILOT KNOB", "loc" : [ -73.62988300000001, 43.515561 ], "pop" : 23, "state" : "NY" }
+{ "_id" : "12845", "city" : "LAKE GEORGE", "loc" : [ -73.697547, 43.416725 ], "pop" : 4677, "state" : "NY" }
+{ "_id" : "12846", "city" : "LAKE LUZERNE", "loc" : [ -73.822821, 43.316487 ], "pop" : 2816, "state" : "NY" }
+{ "_id" : "12847", "city" : "LONG LAKE", "loc" : [ -74.46624300000001, 43.947653 ], "pop" : 930, "state" : "NY" }
+{ "_id" : "12849", "city" : "MIDDLE GRANVILLE", "loc" : [ -73.303077, 43.450773 ], "pop" : 249, "state" : "NY" }
+{ "_id" : "12850", "city" : "MIDDLE GROVE", "loc" : [ -74.016687, 43.097548 ], "pop" : 1760, "state" : "NY" }
+{ "_id" : "12851", "city" : "MINERVA", "loc" : [ -73.983542, 43.781058 ], "pop" : 308, "state" : "NY" }
+{ "_id" : "12852", "city" : "NEWCOMB", "loc" : [ -74.12991100000001, 43.945991 ], "pop" : 544, "state" : "NY" }
+{ "_id" : "12853", "city" : "NORTH CREEK", "loc" : [ -73.892802, 43.713802 ], "pop" : 2447, "state" : "NY" }
+{ "_id" : "12854", "city" : "NORTH GRANVILLE", "loc" : [ -73.33011399999999, 43.506212 ], "pop" : 185, "state" : "NY" }
+{ "_id" : "12855", "city" : "NORTH HUDSON", "loc" : [ -73.712065, 43.986872 ], "pop" : 266, "state" : "NY" }
+{ "_id" : "12857", "city" : "OLMSTEDVILLE", "loc" : [ -73.93347900000001, 43.779931 ], "pop" : 450, "state" : "NY" }
+{ "_id" : "12858", "city" : "PARADOX", "loc" : [ -73.64495599999999, 43.891382 ], "pop" : 29, "state" : "NY" }
+{ "_id" : "12859", "city" : "PORTER CORNERS", "loc" : [ -73.88391799999999, 43.172358 ], "pop" : 1028, "state" : "NY" }
+{ "_id" : "12860", "city" : "POTTERSVILLE", "loc" : [ -73.756438, 43.692956 ], "pop" : 252, "state" : "NY" }
+{ "_id" : "12861", "city" : "PUTNAM STATION", "loc" : [ -73.412299, 43.755976 ], "pop" : 477, "state" : "NY" }
+{ "_id" : "12863", "city" : "ROCK CITY FALLS", "loc" : [ -73.92152299999999, 43.066248 ], "pop" : 553, "state" : "NY" }
+{ "_id" : "12865", "city" : "SALEM", "loc" : [ -73.332703, 43.182785 ], "pop" : 1965, "state" : "NY" }
+{ "_id" : "12866", "city" : "WILTON", "loc" : [ -73.780644, 43.080094 ], "pop" : 30086, "state" : "NY" }
+{ "_id" : "12870", "city" : "SCHROON LAKE", "loc" : [ -73.767382, 43.841159 ], "pop" : 1656, "state" : "NY" }
+{ "_id" : "12871", "city" : "SCHUYLERVILLE", "loc" : [ -73.60068, 43.087778 ], "pop" : 3929, "state" : "NY" }
+{ "_id" : "12872", "city" : "SEVERANCE", "loc" : [ -73.730127, 43.876903 ], "pop" : 36, "state" : "NY" }
+{ "_id" : "12873", "city" : "SHUSHAN", "loc" : [ -73.323148, 43.110575 ], "pop" : 755, "state" : "NY" }
+{ "_id" : "12874", "city" : "SILVER BAY", "loc" : [ -73.507062, 43.697804 ], "pop" : 7, "state" : "NY" }
+{ "_id" : "12878", "city" : "STONY CREEK", "loc" : [ -73.949467, 43.421389 ], "pop" : 625, "state" : "NY" }
+{ "_id" : "12883", "city" : "TICONDEROGA", "loc" : [ -73.442592, 43.846302 ], "pop" : 5149, "state" : "NY" }
+{ "_id" : "12885", "city" : "WARRENSBURG", "loc" : [ -73.79202100000001, 43.500253 ], "pop" : 4399, "state" : "NY" }
+{ "_id" : "12886", "city" : "WEVERTOWN", "loc" : [ -73.930909, 43.64129 ], "pop" : 137, "state" : "NY" }
+{ "_id" : "12887", "city" : "WHITEHALL", "loc" : [ -73.38641200000001, 43.5531 ], "pop" : 5372, "state" : "NY" }
+{ "_id" : "12901", "city" : "PLATTSBURGH", "loc" : [ -73.465969, 44.692715 ], "pop" : 40905, "state" : "NY" }
+{ "_id" : "12910", "city" : "ALTONA", "loc" : [ -73.640767, 44.881584 ], "pop" : 2456, "state" : "NY" }
+{ "_id" : "12911", "city" : "AU SABLE CHASM", "loc" : [ -73.508976, 44.521594 ], "pop" : 514, "state" : "NY" }
+{ "_id" : "12912", "city" : "AU SABLE FORKS", "loc" : [ -73.685672, 44.44994 ], "pop" : 2143, "state" : "NY" }
+{ "_id" : "12913", "city" : "BLOOMINGDALE", "loc" : [ -74.08293, 44.398477 ], "pop" : 1016, "state" : "NY" }
+{ "_id" : "12914", "city" : "BOMBAY", "loc" : [ -74.59473699999999, 44.947861 ], "pop" : 1042, "state" : "NY" }
+{ "_id" : "12916", "city" : "BRUSHTON", "loc" : [ -74.522274, 44.828212 ], "pop" : 1936, "state" : "NY" }
+{ "_id" : "12917", "city" : "BURKE", "loc" : [ -74.17311599999999, 44.917722 ], "pop" : 1279, "state" : "NY" }
+{ "_id" : "12918", "city" : "CADYVILLE", "loc" : [ -73.670242, 44.686473 ], "pop" : 2122, "state" : "NY" }
+{ "_id" : "12919", "city" : "CHAMPLAIN", "loc" : [ -73.446603, 44.977292 ], "pop" : 2827, "state" : "NY" }
+{ "_id" : "12920", "city" : "CHATEAUGAY", "loc" : [ -74.07409800000001, 44.908768 ], "pop" : 2088, "state" : "NY" }
+{ "_id" : "12921", "city" : "CHAZY", "loc" : [ -73.450076, 44.888379 ], "pop" : 2664, "state" : "NY" }
+{ "_id" : "12922", "city" : "CHILDWOLD", "loc" : [ -74.675878, 44.286715 ], "pop" : 0, "state" : "NY" }
+{ "_id" : "12923", "city" : "CHURUBUSCO", "loc" : [ -73.935484, 44.943232 ], "pop" : 663, "state" : "NY" }
+{ "_id" : "12924", "city" : "KEESEVILLE", "loc" : [ -73.567971, 44.504814 ], "pop" : 377, "state" : "NY" }
+{ "_id" : "12926", "city" : "CONSTABLE", "loc" : [ -74.329713, 44.941688 ], "pop" : 1949, "state" : "NY" }
+{ "_id" : "12928", "city" : "CROWN POINT", "loc" : [ -73.466486, 43.952633 ], "pop" : 1963, "state" : "NY" }
+{ "_id" : "12930", "city" : "DICKINSON CENTER", "loc" : [ -74.552346, 44.723328 ], "pop" : 549, "state" : "NY" }
+{ "_id" : "12932", "city" : "ELIZABETHTOWN", "loc" : [ -73.601131, 44.224518 ], "pop" : 1274, "state" : "NY" }
+{ "_id" : "12934", "city" : "ELLENBURG CENTER", "loc" : [ -73.86854599999999, 44.844353 ], "pop" : 1494, "state" : "NY" }
+{ "_id" : "12935", "city" : "ELLENBURG DEPOT", "loc" : [ -73.787572, 44.916266 ], "pop" : 981, "state" : "NY" }
+{ "_id" : "12936", "city" : "ESSEX", "loc" : [ -73.373147, 44.280695 ], "pop" : 406, "state" : "NY" }
+{ "_id" : "12937", "city" : "FORT COVINGTON", "loc" : [ -74.492879, 44.973096 ], "pop" : 1568, "state" : "NY" }
+{ "_id" : "12938", "city" : "NICHOLVILLE", "loc" : [ -74.53647100000001, 44.638703 ], "pop" : 1229, "state" : "NY" }
+{ "_id" : "12941", "city" : "JAY", "loc" : [ -73.72470199999999, 44.373351 ], "pop" : 1245, "state" : "NY" }
+{ "_id" : "12942", "city" : "KEENE", "loc" : [ -73.79145699999999, 44.25548 ], "pop" : 520, "state" : "NY" }
+{ "_id" : "12943", "city" : "SAINT HUBERTS", "loc" : [ -73.795923, 44.177978 ], "pop" : 392, "state" : "NY" }
+{ "_id" : "12944", "city" : "KEESEVILLE", "loc" : [ -73.474538, 44.499933 ], "pop" : 4129, "state" : "NY" }
+{ "_id" : "12945", "city" : "UPPER SAINT REGI", "loc" : [ -74.243336, 44.359392 ], "pop" : 412, "state" : "NY" }
+{ "_id" : "12946", "city" : "NORTH POLE", "loc" : [ -73.98635400000001, 44.274986 ], "pop" : 4656, "state" : "NY" }
+{ "_id" : "12949", "city" : "LAWRENCEVILLE", "loc" : [ -74.662927, 44.758988 ], "pop" : 41, "state" : "NY" }
+{ "_id" : "12950", "city" : "LEWIS", "loc" : [ -73.54912899999999, 44.307507 ], "pop" : 432, "state" : "NY" }
+{ "_id" : "12952", "city" : "LYON MOUNTAIN", "loc" : [ -73.91945200000001, 44.725491 ], "pop" : 623, "state" : "NY" }
+{ "_id" : "12953", "city" : "MALONE", "loc" : [ -74.29280799999999, 44.848164 ], "pop" : 13798, "state" : "NY" }
+{ "_id" : "12955", "city" : "MERRILL", "loc" : [ -73.97783200000001, 44.799364 ], "pop" : 452, "state" : "NY" }
+{ "_id" : "12956", "city" : "MINEVILLE", "loc" : [ -73.523588, 44.087631 ], "pop" : 1868, "state" : "NY" }
+{ "_id" : "12957", "city" : "MOIRA", "loc" : [ -74.560273, 44.850412 ], "pop" : 1511, "state" : "NY" }
+{ "_id" : "12958", "city" : "MOOERS", "loc" : [ -73.58341299999999, 44.959244 ], "pop" : 1569, "state" : "NY" }
+{ "_id" : "12959", "city" : "MOOERS FORKS", "loc" : [ -73.672967, 44.960232 ], "pop" : 963, "state" : "NY" }
+{ "_id" : "12960", "city" : "MORIAH", "loc" : [ -73.507862, 44.043755 ], "pop" : 889, "state" : "NY" }
+{ "_id" : "12961", "city" : "MORIAH CENTER", "loc" : [ -73.511071, 44.066197 ], "pop" : 209, "state" : "NY" }
+{ "_id" : "12962", "city" : "MORRISONVILLE", "loc" : [ -73.577168, 44.68936 ], "pop" : 4665, "state" : "NY" }
+{ "_id" : "12964", "city" : "NEW RUSSIA", "loc" : [ -73.605881, 44.159532 ], "pop" : 216, "state" : "NY" }
+{ "_id" : "12965", "city" : "NICHOLVILLE", "loc" : [ -74.653379, 44.708182 ], "pop" : 153, "state" : "NY" }
+{ "_id" : "12966", "city" : "BANGOR", "loc" : [ -74.413369, 44.829997 ], "pop" : 2867, "state" : "NY" }
+{ "_id" : "12967", "city" : "NORTH LAWRENCE", "loc" : [ -74.665307, 44.774982 ], "pop" : 943, "state" : "NY" }
+{ "_id" : "12968", "city" : "ONCHIOTA", "loc" : [ -74.170991, 44.458163 ], "pop" : 1407, "state" : "NY" }
+{ "_id" : "12969", "city" : "OWLS HEAD", "loc" : [ -74.134173, 44.730791 ], "pop" : 329, "state" : "NY" }
+{ "_id" : "12970", "city" : "PAUL SMITHS", "loc" : [ -74.26643199999999, 44.444967 ], "pop" : 245, "state" : "NY" }
+{ "_id" : "12972", "city" : "PERU", "loc" : [ -73.52932199999999, 44.585109 ], "pop" : 5640, "state" : "NY" }
+{ "_id" : "12973", "city" : "PIERCEFIELD", "loc" : [ -74.573228, 44.234037 ], "pop" : 112, "state" : "NY" }
+{ "_id" : "12974", "city" : "PORT HENRY", "loc" : [ -73.47054199999999, 44.04645 ], "pop" : 1841, "state" : "NY" }
+{ "_id" : "12978", "city" : "REDFORD", "loc" : [ -73.801948, 44.606926 ], "pop" : 495, "state" : "NY" }
+{ "_id" : "12979", "city" : "ROUSES POINT", "loc" : [ -73.369083, 44.988413 ], "pop" : 2508, "state" : "NY" }
+{ "_id" : "12980", "city" : "SAINT REGIS FALL", "loc" : [ -74.66032, 44.677298 ], "pop" : 321, "state" : "NY" }
+{ "_id" : "12981", "city" : "SARANAC", "loc" : [ -73.748135, 44.703168 ], "pop" : 6545, "state" : "NY" }
+{ "_id" : "12983", "city" : "SARANAC LAKE", "loc" : [ -74.13295100000001, 44.324331 ], "pop" : 9125, "state" : "NY" }
+{ "_id" : "12985", "city" : "SCHUYLER FALLS", "loc" : [ -73.689481, 44.588224 ], "pop" : 652, "state" : "NY" }
+{ "_id" : "12986", "city" : "SUNMOUNT", "loc" : [ -74.463172, 44.228461 ], "pop" : 6379, "state" : "NY" }
+{ "_id" : "12987", "city" : "UPPER JAY", "loc" : [ -73.807864, 44.325586 ], "pop" : 159, "state" : "NY" }
+{ "_id" : "12989", "city" : "VERMONTVILLE", "loc" : [ -74.057278, 44.460134 ], "pop" : 623, "state" : "NY" }
+{ "_id" : "12992", "city" : "WEST CHAZY", "loc" : [ -73.511188, 44.796967 ], "pop" : 3944, "state" : "NY" }
+{ "_id" : "12993", "city" : "WESTPORT", "loc" : [ -73.470223, 44.204983 ], "pop" : 2007, "state" : "NY" }
+{ "_id" : "12994", "city" : "WHALLONSBURG", "loc" : [ -73.432205, 44.292637 ], "pop" : 169, "state" : "NY" }
+{ "_id" : "12996", "city" : "WILLSBORO", "loc" : [ -73.396292, 44.360396 ], "pop" : 1729, "state" : "NY" }
+{ "_id" : "12997", "city" : "WILMINGTON", "loc" : [ -73.816553, 44.387976 ], "pop" : 958, "state" : "NY" }
+{ "_id" : "13021", "city" : "AUBURN", "loc" : [ -76.562605, 42.929958 ], "pop" : 43447, "state" : "NY" }
+{ "_id" : "13026", "city" : "AURORA", "loc" : [ -76.67749000000001, 42.747231 ], "pop" : 1557, "state" : "NY" }
+{ "_id" : "13027", "city" : "BALDWINSVILLE", "loc" : [ -76.323718, 43.162039 ], "pop" : 28132, "state" : "NY" }
+{ "_id" : "13028", "city" : "BERNHARDS BAY", "loc" : [ -75.937299, 43.271722 ], "pop" : 1228, "state" : "NY" }
+{ "_id" : "13029", "city" : "BREWERTON", "loc" : [ -76.135132, 43.225194 ], "pop" : 4823, "state" : "NY" }
+{ "_id" : "13030", "city" : "BRIDGEPORT", "loc" : [ -75.970009, 43.159015 ], "pop" : 4507, "state" : "NY" }
+{ "_id" : "13031", "city" : "CAMILLUS", "loc" : [ -76.280728, 43.041651 ], "pop" : 15236, "state" : "NY" }
+{ "_id" : "13032", "city" : "CANASTOTA", "loc" : [ -75.76019700000001, 43.087764 ], "pop" : 12909, "state" : "NY" }
+{ "_id" : "13033", "city" : "CATO", "loc" : [ -76.564791, 43.179443 ], "pop" : 3873, "state" : "NY" }
+{ "_id" : "13034", "city" : "CAYUGA", "loc" : [ -76.70240200000001, 42.914198 ], "pop" : 2357, "state" : "NY" }
+{ "_id" : "13035", "city" : "CAZENOVIA", "loc" : [ -75.839229, 42.937955 ], "pop" : 7748, "state" : "NY" }
+{ "_id" : "13036", "city" : "CENTRAL SQUARE", "loc" : [ -76.18485200000001, 43.308986 ], "pop" : 7720, "state" : "NY" }
+{ "_id" : "13037", "city" : "CHITTENANGO", "loc" : [ -75.87684, 43.05524 ], "pop" : 8756, "state" : "NY" }
+{ "_id" : "13039", "city" : "CICERO", "loc" : [ -76.09618500000001, 43.170693 ], "pop" : 12600, "state" : "NY" }
+{ "_id" : "13040", "city" : "CINCINNATUS", "loc" : [ -75.903029, 42.538539 ], "pop" : 2416, "state" : "NY" }
+{ "_id" : "13041", "city" : "CLAY", "loc" : [ -76.170748, 43.173734 ], "pop" : 8609, "state" : "NY" }
+{ "_id" : "13042", "city" : "CLEVELAND", "loc" : [ -75.853691, 43.243199 ], "pop" : 2428, "state" : "NY" }
+{ "_id" : "13044", "city" : "CONSTANTIA", "loc" : [ -76.004155, 43.272751 ], "pop" : 2603, "state" : "NY" }
+{ "_id" : "13045", "city" : "CORTLAND", "loc" : [ -76.185675, 42.595175 ], "pop" : 29180, "state" : "NY" }
+{ "_id" : "13050", "city" : "CUYLER", "loc" : [ -75.938367, 42.740571 ], "pop" : 920, "state" : "NY" }
+{ "_id" : "13052", "city" : "DE RUYTER", "loc" : [ -75.858226, 42.749444 ], "pop" : 1914, "state" : "NY" }
+{ "_id" : "13053", "city" : "DRYDEN", "loc" : [ -76.28722399999999, 42.486118 ], "pop" : 4659, "state" : "NY" }
+{ "_id" : "13054", "city" : "DURHAMVILLE", "loc" : [ -75.671409, 43.157912 ], "pop" : 1470, "state" : "NY" }
+{ "_id" : "13055", "city" : "EAST FREETOWN", "loc" : [ -75.998924, 42.579845 ], "pop" : 833, "state" : "NY" }
+{ "_id" : "13057", "city" : "EAST SYRACUSE", "loc" : [ -76.05578, 43.073359 ], "pop" : 14722, "state" : "NY" }
+{ "_id" : "13060", "city" : "ELBRIDGE", "loc" : [ -76.435164, 43.025246 ], "pop" : 1770, "state" : "NY" }
+{ "_id" : "13061", "city" : "ERIEVILLE", "loc" : [ -75.754255, 42.856166 ], "pop" : 1100, "state" : "NY" }
+{ "_id" : "13063", "city" : "FABIUS", "loc" : [ -75.983645, 42.853117 ], "pop" : 1785, "state" : "NY" }
+{ "_id" : "13066", "city" : "FAYETTEVILLE", "loc" : [ -76.014503, 43.026774 ], "pop" : 11793, "state" : "NY" }
+{ "_id" : "13068", "city" : "FREEVILLE", "loc" : [ -76.36362200000001, 42.499768 ], "pop" : 5181, "state" : "NY" }
+{ "_id" : "13069", "city" : "FULTON", "loc" : [ -76.40342, 43.321108 ], "pop" : 23858, "state" : "NY" }
+{ "_id" : "13071", "city" : "GENOA", "loc" : [ -76.54175499999999, 42.674624 ], "pop" : 1160, "state" : "NY" }
+{ "_id" : "13072", "city" : "GEORGETOWN", "loc" : [ -75.74427900000001, 42.763059 ], "pop" : 611, "state" : "NY" }
+{ "_id" : "13073", "city" : "GROTON", "loc" : [ -76.363286, 42.58549 ], "pop" : 5940, "state" : "NY" }
+{ "_id" : "13074", "city" : "HANNIBAL", "loc" : [ -76.54603400000001, 43.311115 ], "pop" : 5248, "state" : "NY" }
+{ "_id" : "13076", "city" : "HASTINGS", "loc" : [ -76.14770799999999, 43.35268 ], "pop" : 2259, "state" : "NY" }
+{ "_id" : "13077", "city" : "HOMER", "loc" : [ -76.18783000000001, 42.672586 ], "pop" : 7192, "state" : "NY" }
+{ "_id" : "13078", "city" : "JAMESVILLE", "loc" : [ -76.076571, 42.982973 ], "pop" : 8230, "state" : "NY" }
+{ "_id" : "13080", "city" : "JORDAN", "loc" : [ -76.45977999999999, 43.065141 ], "pop" : 4766, "state" : "NY" }
+{ "_id" : "13081", "city" : "KING FERRY", "loc" : [ -76.62160299999999, 42.66351 ], "pop" : 979, "state" : "NY" }
+{ "_id" : "13082", "city" : "KIRKVILLE", "loc" : [ -75.955003, 43.098095 ], "pop" : 4798, "state" : "NY" }
+{ "_id" : "13083", "city" : "LACONA", "loc" : [ -76.050335, 43.642883 ], "pop" : 2199, "state" : "NY" }
+{ "_id" : "13084", "city" : "LA FAYETTE", "loc" : [ -76.106116, 42.890959 ], "pop" : 4450, "state" : "NY" }
+{ "_id" : "13085", "city" : "LEBANON", "loc" : [ -75.67758499999999, 42.77451 ], "pop" : 164, "state" : "NY" }
+{ "_id" : "13088", "city" : "LIVERPOOL", "loc" : [ -76.186999, 43.109925 ], "pop" : 23093, "state" : "NY" }
+{ "_id" : "13090", "city" : "BAYBERRY", "loc" : [ -76.223269, 43.148048 ], "pop" : 31387, "state" : "NY" }
+{ "_id" : "13092", "city" : "LOCKE", "loc" : [ -76.415436, 42.655789 ], "pop" : 2746, "state" : "NY" }
+{ "_id" : "13101", "city" : "MC GRAW", "loc" : [ -76.081958, 42.594758 ], "pop" : 2511, "state" : "NY" }
+{ "_id" : "13103", "city" : "MALLORY", "loc" : [ -76.089208, 43.33782 ], "pop" : 1267, "state" : "NY" }
+{ "_id" : "13104", "city" : "MANLIUS", "loc" : [ -75.97034499999999, 42.990441 ], "pop" : 12754, "state" : "NY" }
+{ "_id" : "13108", "city" : "MARCELLUS", "loc" : [ -76.33228, 42.982056 ], "pop" : 6077, "state" : "NY" }
+{ "_id" : "13110", "city" : "MARIETTA", "loc" : [ -76.28055000000001, 42.897441 ], "pop" : 1778, "state" : "NY" }
+{ "_id" : "13111", "city" : "MARTVILLE", "loc" : [ -76.628936, 43.26608 ], "pop" : 1342, "state" : "NY" }
+{ "_id" : "13112", "city" : "MEMPHIS", "loc" : [ -76.40300999999999, 43.093438 ], "pop" : 1888, "state" : "NY" }
+{ "_id" : "13114", "city" : "MEXICO", "loc" : [ -76.24458799999999, 43.460533 ], "pop" : 6641, "state" : "NY" }
+{ "_id" : "13116", "city" : "MINOA", "loc" : [ -76.009812, 43.077212 ], "pop" : 3790, "state" : "NY" }
+{ "_id" : "13118", "city" : "MORAVIA", "loc" : [ -76.39897999999999, 42.735456 ], "pop" : 6267, "state" : "NY" }
+{ "_id" : "13120", "city" : "NEDROW", "loc" : [ -76.15293200000001, 42.955855 ], "pop" : 2349, "state" : "NY" }
+{ "_id" : "13122", "city" : "NEW WOODSTOCK", "loc" : [ -75.86352599999999, 42.844135 ], "pop" : 842, "state" : "NY" }
+{ "_id" : "13124", "city" : "NORTH PITCHER", "loc" : [ -75.81635900000001, 42.637243 ], "pop" : 160, "state" : "NY" }
+{ "_id" : "13126", "city" : "OSWEGO", "loc" : [ -76.497489, 43.443836 ], "pop" : 38426, "state" : "NY" }
+{ "_id" : "13131", "city" : "PARISH", "loc" : [ -76.10002299999999, 43.415295 ], "pop" : 3039, "state" : "NY" }
+{ "_id" : "13132", "city" : "PENNELLVILLE", "loc" : [ -76.23946599999999, 43.260946 ], "pop" : 4566, "state" : "NY" }
+{ "_id" : "13135", "city" : "PHOENIX", "loc" : [ -76.306449, 43.24679 ], "pop" : 5342, "state" : "NY" }
+{ "_id" : "13136", "city" : "PITCHER", "loc" : [ -75.846464, 42.596941 ], "pop" : 678, "state" : "NY" }
+{ "_id" : "13140", "city" : "PORT BYRON", "loc" : [ -76.644919, 43.042653 ], "pop" : 4391, "state" : "NY" }
+{ "_id" : "13141", "city" : "PREBLE", "loc" : [ -76.214105, 42.79501 ], "pop" : 502, "state" : "NY" }
+{ "_id" : "13142", "city" : "PULASKI", "loc" : [ -76.125231, 43.55617 ], "pop" : 7355, "state" : "NY" }
+{ "_id" : "13143", "city" : "RED CREEK", "loc" : [ -76.714556, 43.229068 ], "pop" : 3289, "state" : "NY" }
+{ "_id" : "13144", "city" : "RICHLAND", "loc" : [ -76.00291799999999, 43.577578 ], "pop" : 1267, "state" : "NY" }
+{ "_id" : "13145", "city" : "SANDY CREEK", "loc" : [ -76.126439, 43.651681 ], "pop" : 801, "state" : "NY" }
+{ "_id" : "13146", "city" : "SAVANNAH", "loc" : [ -76.75646999999999, 43.093439 ], "pop" : 2141, "state" : "NY" }
+{ "_id" : "13147", "city" : "VENICE CENTER", "loc" : [ -76.574175, 42.778472 ], "pop" : 1520, "state" : "NY" }
+{ "_id" : "13148", "city" : "SENECA FALLS", "loc" : [ -76.79253799999999, 42.909377 ], "pop" : 10987, "state" : "NY" }
+{ "_id" : "13152", "city" : "SKANEATELES", "loc" : [ -76.405174, 42.925751 ], "pop" : 9182, "state" : "NY" }
+{ "_id" : "13155", "city" : "SOUTH OTSELIC", "loc" : [ -75.766919, 42.66256 ], "pop" : 789, "state" : "NY" }
+{ "_id" : "13156", "city" : "STERLING", "loc" : [ -76.67473099999999, 43.329578 ], "pop" : 2252, "state" : "NY" }
+{ "_id" : "13158", "city" : "TRUXTON", "loc" : [ -76.018946, 42.708547 ], "pop" : 593, "state" : "NY" }
+{ "_id" : "13159", "city" : "TULLY", "loc" : [ -76.13936, 42.806977 ], "pop" : 4777, "state" : "NY" }
+{ "_id" : "13160", "city" : "UNION SPRINGS", "loc" : [ -76.673959, 42.833546 ], "pop" : 1984, "state" : "NY" }
+{ "_id" : "13164", "city" : "WARNERS", "loc" : [ -76.290413, 43.09317 ], "pop" : 816, "state" : "NY" }
+{ "_id" : "13165", "city" : "WATERLOO", "loc" : [ -76.87549799999999, 42.904515 ], "pop" : 10845, "state" : "NY" }
+{ "_id" : "13166", "city" : "WEEDSPORT", "loc" : [ -76.542502, 43.048882 ], "pop" : 5847, "state" : "NY" }
+{ "_id" : "13167", "city" : "WEST MONROE", "loc" : [ -76.079747, 43.288235 ], "pop" : 3369, "state" : "NY" }
+{ "_id" : "13202", "city" : "SYRACUSE", "loc" : [ -76.14885599999999, 43.040988 ], "pop" : 5442, "state" : "NY" }
+{ "_id" : "13203", "city" : "SYRACUSE", "loc" : [ -76.136931, 43.060703 ], "pop" : 17585, "state" : "NY" }
+{ "_id" : "13204", "city" : "SYRACUSE", "loc" : [ -76.17576699999999, 43.044398 ], "pop" : 25414, "state" : "NY" }
+{ "_id" : "13205", "city" : "SYRACUSE", "loc" : [ -76.14518, 43.012314 ], "pop" : 23048, "state" : "NY" }
+{ "_id" : "13206", "city" : "SYRACUSE", "loc" : [ -76.110226, 43.06773 ], "pop" : 17644, "state" : "NY" }
+{ "_id" : "13207", "city" : "SYRACUSE", "loc" : [ -76.16501, 43.019482 ], "pop" : 16380, "state" : "NY" }
+{ "_id" : "13208", "city" : "SYRACUSE", "loc" : [ -76.148616, 43.073007 ], "pop" : 22242, "state" : "NY" }
+{ "_id" : "13209", "city" : "SOLVAY", "loc" : [ -76.23844800000001, 43.078204 ], "pop" : 13467, "state" : "NY" }
+{ "_id" : "13210", "city" : "SYRACUSE", "loc" : [ -76.12816599999999, 43.035414 ], "pop" : 31197, "state" : "NY" }
+{ "_id" : "13211", "city" : "MATTYDALE", "loc" : [ -76.14218099999999, 43.09951 ], "pop" : 6940, "state" : "NY" }
+{ "_id" : "13212", "city" : "NORTH SYRACUSE", "loc" : [ -76.13729499999999, 43.130623 ], "pop" : 22829, "state" : "NY" }
+{ "_id" : "13214", "city" : "DE WITT", "loc" : [ -76.07844, 43.042529 ], "pop" : 9501, "state" : "NY" }
+{ "_id" : "13215", "city" : "ONONDAGA", "loc" : [ -76.211851, 42.997544 ], "pop" : 12557, "state" : "NY" }
+{ "_id" : "13219", "city" : "SYRACUSE", "loc" : [ -76.226159, 43.040943 ], "pop" : 16166, "state" : "NY" }
+{ "_id" : "13224", "city" : "SYRACUSE", "loc" : [ -76.104609, 43.042134 ], "pop" : 9845, "state" : "NY" }
+{ "_id" : "13301", "city" : "ALDER CREEK", "loc" : [ -75.213748, 43.415659 ], "pop" : 74, "state" : "NY" }
+{ "_id" : "13302", "city" : "ALTMAR", "loc" : [ -75.971934, 43.497022 ], "pop" : 1761, "state" : "NY" }
+{ "_id" : "13303", "city" : "AVA", "loc" : [ -75.450919, 43.344519 ], "pop" : 1708, "state" : "NY" }
+{ "_id" : "13304", "city" : "BARNEVELD", "loc" : [ -75.16115600000001, 43.223697 ], "pop" : 1383, "state" : "NY" }
+{ "_id" : "13308", "city" : "BLOSSVALE", "loc" : [ -75.687313, 43.230293 ], "pop" : 4489, "state" : "NY" }
+{ "_id" : "13309", "city" : "BOONVILLE", "loc" : [ -75.34397300000001, 43.478615 ], "pop" : 5768, "state" : "NY" }
+{ "_id" : "13310", "city" : "BOUCKVILLE", "loc" : [ -75.567841, 42.894024 ], "pop" : 650, "state" : "NY" }
+{ "_id" : "13314", "city" : "BROOKFIELD", "loc" : [ -75.34385899999999, 42.807538 ], "pop" : 5, "state" : "NY" }
+{ "_id" : "13315", "city" : "BURLINGTON FLATS", "loc" : [ -75.169044, 42.75162 ], "pop" : 1145, "state" : "NY" }
+{ "_id" : "13316", "city" : "CAMDEN", "loc" : [ -75.75425799999999, 43.339197 ], "pop" : 6987, "state" : "NY" }
+{ "_id" : "13317", "city" : "AMES", "loc" : [ -74.583522, 42.88239 ], "pop" : 3986, "state" : "NY" }
+{ "_id" : "13318", "city" : "CASSVILLE", "loc" : [ -75.260704, 42.906931 ], "pop" : 1566, "state" : "NY" }
+{ "_id" : "13319", "city" : "CHADWICKS", "loc" : [ -75.26564500000001, 43.022563 ], "pop" : 274, "state" : "NY" }
+{ "_id" : "13320", "city" : "CHERRY VALLEY", "loc" : [ -74.744439, 42.782315 ], "pop" : 1642, "state" : "NY" }
+{ "_id" : "13322", "city" : "CLAYVILLE", "loc" : [ -75.206126, 42.97119 ], "pop" : 641, "state" : "NY" }
+{ "_id" : "13323", "city" : "CLINTON", "loc" : [ -75.38079, 43.05856 ], "pop" : 12483, "state" : "NY" }
+{ "_id" : "13324", "city" : "COLD BROOK", "loc" : [ -74.997651, 43.302391 ], "pop" : 1853, "state" : "NY" }
+{ "_id" : "13325", "city" : "CONSTABLEVILLE", "loc" : [ -75.458406, 43.562982 ], "pop" : 931, "state" : "NY" }
+{ "_id" : "13326", "city" : "COOPERSTOWN", "loc" : [ -74.918148, 42.70319 ], "pop" : 5402, "state" : "NY" }
+{ "_id" : "13327", "city" : "CROGHAN", "loc" : [ -75.354192, 43.909461 ], "pop" : 1841, "state" : "NY" }
+{ "_id" : "13328", "city" : "DEANSBORO", "loc" : [ -75.438309, 42.981788 ], "pop" : 639, "state" : "NY" }
+{ "_id" : "13329", "city" : "DOLGEVILLE", "loc" : [ -74.76430499999999, 43.104161 ], "pop" : 4205, "state" : "NY" }
+{ "_id" : "13331", "city" : "EAGLE BAY", "loc" : [ -74.96538099999999, 43.723659 ], "pop" : 1416, "state" : "NY" }
+{ "_id" : "13332", "city" : "EARLVILLE", "loc" : [ -75.541653, 42.752218 ], "pop" : 2413, "state" : "NY" }
+{ "_id" : "13333", "city" : "EAST SPRINGFIELD", "loc" : [ -74.75974100000001, 42.832947 ], "pop" : 0, "state" : "NY" }
+{ "_id" : "13334", "city" : "EATON", "loc" : [ -75.631359, 42.848417 ], "pop" : 1583, "state" : "NY" }
+{ "_id" : "13335", "city" : "EDMESTON", "loc" : [ -75.252522, 42.730281 ], "pop" : 788, "state" : "NY" }
+{ "_id" : "13337", "city" : "FLY CREEK", "loc" : [ -74.986921, 42.725177 ], "pop" : 1033, "state" : "NY" }
+{ "_id" : "13338", "city" : "FORESTPORT", "loc" : [ -75.178742, 43.473651 ], "pop" : 1013, "state" : "NY" }
+{ "_id" : "13339", "city" : "FORT PLAIN", "loc" : [ -74.643298, 42.937158 ], "pop" : 6144, "state" : "NY" }
+{ "_id" : "13340", "city" : "FRANKFORT", "loc" : [ -75.10715500000001, 43.044041 ], "pop" : 8546, "state" : "NY" }
+{ "_id" : "13342", "city" : "GARRATTSVILLE", "loc" : [ -75.23270100000001, 42.635634 ], "pop" : 293, "state" : "NY" }
+{ "_id" : "13343", "city" : "GLENFIELD", "loc" : [ -75.366902, 43.732306 ], "pop" : 1909, "state" : "NY" }
+{ "_id" : "13345", "city" : "GREIG", "loc" : [ -75.312393, 43.689184 ], "pop" : 456, "state" : "NY" }
+{ "_id" : "13346", "city" : "HAMILTON", "loc" : [ -75.54338199999999, 42.82306 ], "pop" : 5821, "state" : "NY" }
+{ "_id" : "13348", "city" : "HARTWICK", "loc" : [ -75.055009, 42.695033 ], "pop" : 1424, "state" : "NY" }
+{ "_id" : "13350", "city" : "HERKIMER", "loc" : [ -74.98757000000001, 43.030696 ], "pop" : 10090, "state" : "NY" }
+{ "_id" : "13353", "city" : "HOFFMEISTER", "loc" : [ -74.739974, 43.391545 ], "pop" : 106, "state" : "NY" }
+{ "_id" : "13354", "city" : "HOLLAND PATENT", "loc" : [ -75.253506, 43.248406 ], "pop" : 3970, "state" : "NY" }
+{ "_id" : "13355", "city" : "HUBBARDSVILLE", "loc" : [ -75.436707, 42.823663 ], "pop" : 810, "state" : "NY" }
+{ "_id" : "13357", "city" : "ILION", "loc" : [ -75.04836, 43.006391 ], "pop" : 11603, "state" : "NY" }
+{ "_id" : "13360", "city" : "INLET", "loc" : [ -74.784631, 43.748024 ], "pop" : 343, "state" : "NY" }
+{ "_id" : "13361", "city" : "JORDANVILLE", "loc" : [ -74.820919, 42.89478 ], "pop" : 395, "state" : "NY" }
+{ "_id" : "13363", "city" : "LEE CENTER", "loc" : [ -75.505532, 43.314804 ], "pop" : 2076, "state" : "NY" }
+{ "_id" : "13365", "city" : "LITTLE FALLS", "loc" : [ -74.860598, 43.047371 ], "pop" : 10379, "state" : "NY" }
+{ "_id" : "13367", "city" : "BEAVER RIVER", "loc" : [ -75.47537800000001, 43.801055 ], "pop" : 8238, "state" : "NY" }
+{ "_id" : "13368", "city" : "LYONS FALLS", "loc" : [ -75.355312, 43.626165 ], "pop" : 1210, "state" : "NY" }
+{ "_id" : "13401", "city" : "MC CONNELLSVILLE", "loc" : [ -75.652477, 43.289552 ], "pop" : 412, "state" : "NY" }
+{ "_id" : "13402", "city" : "MADISON", "loc" : [ -75.50756199999999, 42.896854 ], "pop" : 1472, "state" : "NY" }
+{ "_id" : "13403", "city" : "MARCY", "loc" : [ -75.278335, 43.163926 ], "pop" : 7937, "state" : "NY" }
+{ "_id" : "13406", "city" : "MIDDLEVILLE", "loc" : [ -74.92397800000001, 43.136933 ], "pop" : 180, "state" : "NY" }
+{ "_id" : "13407", "city" : "MOHAWK", "loc" : [ -74.985298, 42.989986 ], "pop" : 5907, "state" : "NY" }
+{ "_id" : "13408", "city" : "MORRISVILLE", "loc" : [ -75.648656, 42.910805 ], "pop" : 4491, "state" : "NY" }
+{ "_id" : "13409", "city" : "MUNNSVILLE", "loc" : [ -75.594032, 42.986326 ], "pop" : 2116, "state" : "NY" }
+{ "_id" : "13411", "city" : "NEW BERLIN", "loc" : [ -75.34740600000001, 42.622414 ], "pop" : 2569, "state" : "NY" }
+{ "_id" : "13413", "city" : "NEW HARTFORD", "loc" : [ -75.29055099999999, 43.065412 ], "pop" : 14035, "state" : "NY" }
+{ "_id" : "13415", "city" : "NEW LISBON", "loc" : [ -75.32743600000001, 42.578968 ], "pop" : 19, "state" : "NY" }
+{ "_id" : "13416", "city" : "NEWPORT", "loc" : [ -74.986133, 43.180002 ], "pop" : 2554, "state" : "NY" }
+{ "_id" : "13417", "city" : "NEW YORK MILLS", "loc" : [ -75.29369, 43.100038 ], "pop" : 3646, "state" : "NY" }
+{ "_id" : "13418", "city" : "NORTH BROOKFIELD", "loc" : [ -75.381489, 42.850088 ], "pop" : 258, "state" : "NY" }
+{ "_id" : "13420", "city" : "OLD FORGE", "loc" : [ -74.893511, 43.74347 ], "pop" : 221, "state" : "NY" }
+{ "_id" : "13421", "city" : "ONEIDA", "loc" : [ -75.650814, 43.086248 ], "pop" : 11876, "state" : "NY" }
+{ "_id" : "13424", "city" : "ORISKANY", "loc" : [ -75.34343699999999, 43.152427 ], "pop" : 3566, "state" : "NY" }
+{ "_id" : "13425", "city" : "ORISKANY FALLS", "loc" : [ -75.483807, 42.957585 ], "pop" : 2192, "state" : "NY" }
+{ "_id" : "13428", "city" : "PALATINE BRIDGE", "loc" : [ -74.570825, 42.922119 ], "pop" : 1738, "state" : "NY" }
+{ "_id" : "13431", "city" : "POLAND", "loc" : [ -75.07313000000001, 43.211458 ], "pop" : 1789, "state" : "NY" }
+{ "_id" : "13433", "city" : "PORT LEYDEN", "loc" : [ -75.326257, 43.580245 ], "pop" : 1951, "state" : "NY" }
+{ "_id" : "13436", "city" : "RAQUETTE LAKE", "loc" : [ -74.537959, 43.866224 ], "pop" : 0, "state" : "NY" }
+{ "_id" : "13437", "city" : "REDFIELD", "loc" : [ -75.82423, 43.565794 ], "pop" : 482, "state" : "NY" }
+{ "_id" : "13438", "city" : "REMSEN", "loc" : [ -75.161618, 43.338456 ], "pop" : 4400, "state" : "NY" }
+{ "_id" : "13439", "city" : "RICHFIELD SPRING", "loc" : [ -74.992214, 42.850298 ], "pop" : 3825, "state" : "NY" }
+{ "_id" : "13440", "city" : "ROME", "loc" : [ -75.449758, 43.219349 ], "pop" : 56424, "state" : "NY" }
+{ "_id" : "13450", "city" : "ROSEBOOM", "loc" : [ -74.74160999999999, 42.788246 ], "pop" : 8, "state" : "NY" }
+{ "_id" : "13452", "city" : "SAINT JOHNSVILLE", "loc" : [ -74.64604, 43.016995 ], "pop" : 4992, "state" : "NY" }
+{ "_id" : "13454", "city" : "SALISBURY CENTER", "loc" : [ -74.78093200000001, 43.162509 ], "pop" : 896, "state" : "NY" }
+{ "_id" : "13456", "city" : "SAUQUOIT", "loc" : [ -75.26259, 43.007291 ], "pop" : 5652, "state" : "NY" }
+{ "_id" : "13459", "city" : "SHARON SPRINGS", "loc" : [ -74.591911, 42.763357 ], "pop" : 2919, "state" : "NY" }
+{ "_id" : "13460", "city" : "SHERBURNE", "loc" : [ -75.48302700000001, 42.685885 ], "pop" : 4013, "state" : "NY" }
+{ "_id" : "13461", "city" : "SHERRILL", "loc" : [ -75.598975, 43.070397 ], "pop" : 2864, "state" : "NY" }
+{ "_id" : "13464", "city" : "SMYRNA", "loc" : [ -75.61212399999999, 42.689565 ], "pop" : 1209, "state" : "NY" }
+{ "_id" : "13466", "city" : "SOUTH EDMESTON", "loc" : [ -75.262919, 42.676754 ], "pop" : 1224, "state" : "NY" }
+{ "_id" : "13468", "city" : "SPRINGFIELD CENT", "loc" : [ -74.938051, 42.850106 ], "pop" : 1402, "state" : "NY" }
+{ "_id" : "13469", "city" : "STITTVILLE", "loc" : [ -75.28985400000001, 43.222889 ], "pop" : 567, "state" : "NY" }
+{ "_id" : "13470", "city" : "STRATFORD", "loc" : [ -74.67678600000001, 43.179101 ], "pop" : 773, "state" : "NY" }
+{ "_id" : "13471", "city" : "TABERG", "loc" : [ -75.602706, 43.336571 ], "pop" : 2393, "state" : "NY" }
+{ "_id" : "13473", "city" : "TURIN", "loc" : [ -75.41319900000001, 43.644074 ], "pop" : 1004, "state" : "NY" }
+{ "_id" : "13475", "city" : "VAN HORNESVILLE", "loc" : [ -74.83466199999999, 42.894812 ], "pop" : 40, "state" : "NY" }
+{ "_id" : "13476", "city" : "VERNON", "loc" : [ -75.56272, 43.094509 ], "pop" : 4118, "state" : "NY" }
+{ "_id" : "13477", "city" : "VERNON CENTER", "loc" : [ -75.521028, 43.044309 ], "pop" : 1440, "state" : "NY" }
+{ "_id" : "13478", "city" : "VERONA", "loc" : [ -75.572399, 43.147311 ], "pop" : 2325, "state" : "NY" }
+{ "_id" : "13480", "city" : "WATERVILLE", "loc" : [ -75.381466, 42.933244 ], "pop" : 4059, "state" : "NY" }
+{ "_id" : "13482", "city" : "WEST BURLINGTON", "loc" : [ -75.190603, 42.706229 ], "pop" : 22, "state" : "NY" }
+{ "_id" : "13483", "city" : "WESTDALE", "loc" : [ -75.822587, 43.411671 ], "pop" : 161, "state" : "NY" }
+{ "_id" : "13485", "city" : "WEST EDMESTON", "loc" : [ -75.30372300000001, 42.794543 ], "pop" : 1337, "state" : "NY" }
+{ "_id" : "13486", "city" : "WESTERNVILLE", "loc" : [ -75.315118, 43.329413 ], "pop" : 657, "state" : "NY" }
+{ "_id" : "13488", "city" : "WESTFORD", "loc" : [ -75.10037800000001, 42.503512 ], "pop" : 253, "state" : "NY" }
+{ "_id" : "13489", "city" : "WEST LEYDEN", "loc" : [ -75.51270700000001, 43.459713 ], "pop" : 500, "state" : "NY" }
+{ "_id" : "13490", "city" : "WESTMORELAND", "loc" : [ -75.453259, 43.101686 ], "pop" : 904, "state" : "NY" }
+{ "_id" : "13491", "city" : "WEST WINFIELD", "loc" : [ -75.183491, 42.882566 ], "pop" : 3825, "state" : "NY" }
+{ "_id" : "13492", "city" : "WHITESBORO", "loc" : [ -75.309479, 43.115805 ], "pop" : 10411, "state" : "NY" }
+{ "_id" : "13493", "city" : "WILLIAMSTOWN", "loc" : [ -75.904411, 43.410559 ], "pop" : 1798, "state" : "NY" }
+{ "_id" : "13494", "city" : "WOODGATE", "loc" : [ -75.119111, 43.54881 ], "pop" : 169, "state" : "NY" }
+{ "_id" : "13495", "city" : "YORKVILLE", "loc" : [ -75.275565, 43.111582 ], "pop" : 2482, "state" : "NY" }
+{ "_id" : "13501", "city" : "UTICA", "loc" : [ -75.23146300000001, 43.087112 ], "pop" : 40223, "state" : "NY" }
+{ "_id" : "13502", "city" : "UTICA", "loc" : [ -75.23138299999999, 43.106723 ], "pop" : 36632, "state" : "NY" }
+{ "_id" : "13601", "city" : "WATERTOWN", "loc" : [ -75.912212, 43.974258 ], "pop" : 39515, "state" : "NY" }
+{ "_id" : "13602", "city" : "FORT DRUM", "loc" : [ -75.753972, 44.035434 ], "pop" : 11895, "state" : "NY" }
+{ "_id" : "13603", "city" : "FORT DRUM", "loc" : [ -75.791884, 44.072122 ], "pop" : 30, "state" : "NY" }
+{ "_id" : "13605", "city" : "SMITHVILLE", "loc" : [ -76.05430200000001, 43.81614 ], "pop" : 4489, "state" : "NY" }
+{ "_id" : "13606", "city" : "ADAMS CENTER", "loc" : [ -76.00415, 43.863106 ], "pop" : 2649, "state" : "NY" }
+{ "_id" : "13607", "city" : "POINT VIVIAN", "loc" : [ -75.93061899999999, 44.326982 ], "pop" : 2024, "state" : "NY" }
+{ "_id" : "13608", "city" : "ANTWERP", "loc" : [ -75.60048399999999, 44.235775 ], "pop" : 1830, "state" : "NY" }
+{ "_id" : "13611", "city" : "BELLEVILLE", "loc" : [ -76.115053, 43.785373 ], "pop" : 72, "state" : "NY" }
+{ "_id" : "13612", "city" : "BLACK RIVER", "loc" : [ -75.795777, 44.004156 ], "pop" : 3651, "state" : "NY" }
+{ "_id" : "13613", "city" : "BRASHER FALLS", "loc" : [ -74.747303, 44.846718 ], "pop" : 1950, "state" : "NY" }
+{ "_id" : "13614", "city" : "BRIER HILL", "loc" : [ -75.672203, 44.552542 ], "pop" : 481, "state" : "NY" }
+{ "_id" : "13616", "city" : "CALCIUM", "loc" : [ -75.849884, 44.026484 ], "pop" : 1839, "state" : "NY" }
+{ "_id" : "13617", "city" : "CANTON", "loc" : [ -75.162792, 44.592442 ], "pop" : 11781, "state" : "NY" }
+{ "_id" : "13618", "city" : "CAPE VINCENT", "loc" : [ -76.31644300000001, 44.124419 ], "pop" : 1207, "state" : "NY" }
+{ "_id" : "13619", "city" : "CARTHAGE", "loc" : [ -75.61600799999999, 43.981039 ], "pop" : 11741, "state" : "NY" }
+{ "_id" : "13620", "city" : "CASTORLAND", "loc" : [ -75.460432, 43.88432 ], "pop" : 2335, "state" : "NY" }
+{ "_id" : "13621", "city" : "CHASE MILLS", "loc" : [ -75.073002, 44.867246 ], "pop" : 431, "state" : "NY" }
+{ "_id" : "13622", "city" : "CHAUMONT", "loc" : [ -76.12316300000001, 44.08481 ], "pop" : 2329, "state" : "NY" }
+{ "_id" : "13624", "city" : "FRONTENAC", "loc" : [ -76.107056, 44.217016 ], "pop" : 5480, "state" : "NY" }
+{ "_id" : "13625", "city" : "COLTON", "loc" : [ -74.932672, 44.50156 ], "pop" : 2382, "state" : "NY" }
+{ "_id" : "13626", "city" : "COPENHAGEN", "loc" : [ -75.683913, 43.880136 ], "pop" : 1891, "state" : "NY" }
+{ "_id" : "13630", "city" : "DE KALB JUNCTION", "loc" : [ -75.287088, 44.489551 ], "pop" : 1320, "state" : "NY" }
+{ "_id" : "13633", "city" : "DE PEYSTER", "loc" : [ -75.43281399999999, 44.541341 ], "pop" : 95, "state" : "NY" }
+{ "_id" : "13634", "city" : "DEXTER", "loc" : [ -76.06498999999999, 44.006923 ], "pop" : 3753, "state" : "NY" }
+{ "_id" : "13635", "city" : "EDWARDS", "loc" : [ -75.25222599999999, 44.311048 ], "pop" : 1069, "state" : "NY" }
+{ "_id" : "13636", "city" : "ELLISBURG", "loc" : [ -76.125871, 43.737202 ], "pop" : 372, "state" : "NY" }
+{ "_id" : "13637", "city" : "EVANS MILLS", "loc" : [ -75.830516, 44.081668 ], "pop" : 3041, "state" : "NY" }
+{ "_id" : "13638", "city" : "FELTS MILLS", "loc" : [ -75.752443, 44.020374 ], "pop" : 384, "state" : "NY" }
+{ "_id" : "13642", "city" : "GOUVERNEUR", "loc" : [ -75.46506100000001, 44.328302 ], "pop" : 8425, "state" : "NY" }
+{ "_id" : "13646", "city" : "HAMMOND", "loc" : [ -75.672749, 44.450155 ], "pop" : 2287, "state" : "NY" }
+{ "_id" : "13648", "city" : "HARRISVILLE", "loc" : [ -75.32515100000001, 44.161294 ], "pop" : 2395, "state" : "NY" }
+{ "_id" : "13650", "city" : "HENDERSON", "loc" : [ -76.235212, 43.846742 ], "pop" : 300, "state" : "NY" }
+{ "_id" : "13652", "city" : "HERMON", "loc" : [ -75.19866399999999, 44.444845 ], "pop" : 1636, "state" : "NY" }
+{ "_id" : "13654", "city" : "HEUVELTON", "loc" : [ -75.420345, 44.593034 ], "pop" : 2487, "state" : "NY" }
+{ "_id" : "13655", "city" : "HOGANSBURG", "loc" : [ -74.662649, 44.982511 ], "pop" : 1774, "state" : "NY" }
+{ "_id" : "13656", "city" : "LA FARGEVILLE", "loc" : [ -75.956902, 44.198709 ], "pop" : 2443, "state" : "NY" }
+{ "_id" : "13658", "city" : "LISBON", "loc" : [ -75.269364, 44.718424 ], "pop" : 1265, "state" : "NY" }
+{ "_id" : "13659", "city" : "LORRAINE", "loc" : [ -75.905339, 43.756845 ], "pop" : 462, "state" : "NY" }
+{ "_id" : "13660", "city" : "MADRID", "loc" : [ -75.14134, 44.768978 ], "pop" : 1840, "state" : "NY" }
+{ "_id" : "13661", "city" : "MANNSVILLE", "loc" : [ -76.08203, 43.717905 ], "pop" : 1750, "state" : "NY" }
+{ "_id" : "13662", "city" : "MASSENA", "loc" : [ -74.886205, 44.932411 ], "pop" : 16145, "state" : "NY" }
+{ "_id" : "13665", "city" : "NATURAL BRIDGE", "loc" : [ -75.503883, 44.062982 ], "pop" : 954, "state" : "NY" }
+{ "_id" : "13666", "city" : "NEWTON FALLS", "loc" : [ -74.98456, 44.198584 ], "pop" : 351, "state" : "NY" }
+{ "_id" : "13667", "city" : "NORFOLK", "loc" : [ -74.957736, 44.84235 ], "pop" : 4313, "state" : "NY" }
+{ "_id" : "13668", "city" : "NORWOOD", "loc" : [ -74.999188, 44.747193 ], "pop" : 4305, "state" : "NY" }
+{ "_id" : "13669", "city" : "OGDENSBURG", "loc" : [ -75.477403, 44.690203 ], "pop" : 19659, "state" : "NY" }
+{ "_id" : "13670", "city" : "OSWEGATCHIE", "loc" : [ -75.06594699999999, 44.193328 ], "pop" : 287, "state" : "NY" }
+{ "_id" : "13672", "city" : "PARISHVILLE", "loc" : [ -74.794062, 44.592655 ], "pop" : 300, "state" : "NY" }
+{ "_id" : "13673", "city" : "PHILADELPHIA", "loc" : [ -75.709917, 44.158896 ], "pop" : 2393, "state" : "NY" }
+{ "_id" : "13675", "city" : "PLESSIS", "loc" : [ -75.849577, 44.277364 ], "pop" : 111, "state" : "NY" }
+{ "_id" : "13676", "city" : "POTSDAM", "loc" : [ -74.968076, 44.659246 ], "pop" : 16342, "state" : "NY" }
+{ "_id" : "13679", "city" : "REDWOOD", "loc" : [ -75.814975, 44.321077 ], "pop" : 1735, "state" : "NY" }
+{ "_id" : "13680", "city" : "RENSSELAER FALLS", "loc" : [ -75.32261, 44.590635 ], "pop" : 1027, "state" : "NY" }
+{ "_id" : "13681", "city" : "RICHVILLE", "loc" : [ -75.402455, 44.40454 ], "pop" : 1502, "state" : "NY" }
+{ "_id" : "13682", "city" : "RODMAN", "loc" : [ -75.87187900000001, 43.862217 ], "pop" : 1097, "state" : "NY" }
+{ "_id" : "13684", "city" : "DEGRASSE", "loc" : [ -75.113778, 44.380668 ], "pop" : 717, "state" : "NY" }
+{ "_id" : "13685", "city" : "SACKETS HARBOR", "loc" : [ -76.105039, 43.93983 ], "pop" : 1943, "state" : "NY" }
+{ "_id" : "13687", "city" : "SOUTH COLTON", "loc" : [ -74.860726, 44.504097 ], "pop" : 169, "state" : "NY" }
+{ "_id" : "13690", "city" : "STAR LAKE", "loc" : [ -75.03301500000001, 44.157762 ], "pop" : 1108, "state" : "NY" }
+{ "_id" : "13691", "city" : "THERESA", "loc" : [ -75.801419, 44.211288 ], "pop" : 2558, "state" : "NY" }
+{ "_id" : "13693", "city" : "THREE MILE BAY", "loc" : [ -76.26893, 44.055102 ], "pop" : 250, "state" : "NY" }
+{ "_id" : "13694", "city" : "WADDINGTON", "loc" : [ -75.204887, 44.856373 ], "pop" : 1380, "state" : "NY" }
+{ "_id" : "13695", "city" : "WANAKENA", "loc" : [ -75.090765, 44.2184 ], "pop" : 705, "state" : "NY" }
+{ "_id" : "13696", "city" : "WEST STOCKHOLM", "loc" : [ -74.891932, 44.728951 ], "pop" : 301, "state" : "NY" }
+{ "_id" : "13697", "city" : "WINTHROP", "loc" : [ -74.806586, 44.758289 ], "pop" : 2805, "state" : "NY" }
+{ "_id" : "13698", "city" : "WOODVILLE", "loc" : [ -76.17200200000001, 43.781245 ], "pop" : 847, "state" : "NY" }
+{ "_id" : "13730", "city" : "AFTON", "loc" : [ -75.536604, 42.241737 ], "pop" : 2801, "state" : "NY" }
+{ "_id" : "13731", "city" : "ANDES", "loc" : [ -74.788726, 42.156925 ], "pop" : 985, "state" : "NY" }
+{ "_id" : "13732", "city" : "APALACHIN", "loc" : [ -76.15194, 42.055579 ], "pop" : 8712, "state" : "NY" }
+{ "_id" : "13733", "city" : "BAINBRIDGE", "loc" : [ -75.489411, 42.311975 ], "pop" : 5073, "state" : "NY" }
+{ "_id" : "13734", "city" : "BARTON", "loc" : [ -76.398349, 42.069534 ], "pop" : 2081, "state" : "NY" }
+{ "_id" : "13736", "city" : "BERKSHIRE", "loc" : [ -76.192008, 42.307435 ], "pop" : 2652, "state" : "NY" }
+{ "_id" : "13739", "city" : "BLOOMVILLE", "loc" : [ -74.807118, 42.352236 ], "pop" : 1022, "state" : "NY" }
+{ "_id" : "13740", "city" : "BOVINA CENTER", "loc" : [ -74.76611200000001, 42.27094 ], "pop" : 492, "state" : "NY" }
+{ "_id" : "13743", "city" : "CANDOR", "loc" : [ -76.332196, 42.206274 ], "pop" : 4850, "state" : "NY" }
+{ "_id" : "13744", "city" : "CASTLE CREEK", "loc" : [ -75.90874599999999, 42.256805 ], "pop" : 581, "state" : "NY" }
+{ "_id" : "13746", "city" : "CHENANGO FORKS", "loc" : [ -75.824236, 42.263659 ], "pop" : 3833, "state" : "NY" }
+{ "_id" : "13748", "city" : "CONKLIN", "loc" : [ -75.807624, 42.045429 ], "pop" : 4058, "state" : "NY" }
+{ "_id" : "13750", "city" : "DAVENPORT", "loc" : [ -74.83570899999999, 42.471081 ], "pop" : 777, "state" : "NY" }
+{ "_id" : "13751", "city" : "DAVENPORT CENTER", "loc" : [ -74.906975, 42.452303 ], "pop" : 62, "state" : "NY" }
+{ "_id" : "13752", "city" : "DE LANCEY", "loc" : [ -74.922899, 42.188984 ], "pop" : 785, "state" : "NY" }
+{ "_id" : "13753", "city" : "MEREDITH", "loc" : [ -74.92282299999999, 42.287851 ], "pop" : 5399, "state" : "NY" }
+{ "_id" : "13754", "city" : "DEPOSIT", "loc" : [ -75.42874500000001, 42.066581 ], "pop" : 3047, "state" : "NY" }
+{ "_id" : "13755", "city" : "DOWNSVILLE", "loc" : [ -75.015216, 42.071634 ], "pop" : 615, "state" : "NY" }
+{ "_id" : "13756", "city" : "EAST BRANCH", "loc" : [ -75.12518900000001, 41.984366 ], "pop" : 839, "state" : "NY" }
+{ "_id" : "13757", "city" : "EAST MEREDITH", "loc" : [ -74.89869899999999, 42.410098 ], "pop" : 1478, "state" : "NY" }
+{ "_id" : "13760", "city" : "ENDWELL", "loc" : [ -76.056927, 42.114089 ], "pop" : 46236, "state" : "NY" }
+{ "_id" : "13775", "city" : "FRANKLIN", "loc" : [ -75.148475, 42.342117 ], "pop" : 1807, "state" : "NY" }
+{ "_id" : "13776", "city" : "GILBERTSVILLE", "loc" : [ -75.360929, 42.432951 ], "pop" : 10, "state" : "NY" }
+{ "_id" : "13777", "city" : "GLEN AUBREY", "loc" : [ -75.98054399999999, 42.257289 ], "pop" : 1380, "state" : "NY" }
+{ "_id" : "13778", "city" : "GREENE", "loc" : [ -75.75954, 42.337301 ], "pop" : 5025, "state" : "NY" }
+{ "_id" : "13780", "city" : "GUILFORD", "loc" : [ -75.48231800000001, 42.426901 ], "pop" : 738, "state" : "NY" }
+{ "_id" : "13782", "city" : "HAMDEN", "loc" : [ -74.998391, 42.17873 ], "pop" : 928, "state" : "NY" }
+{ "_id" : "13783", "city" : "CADOSIA", "loc" : [ -75.265306, 41.959667 ], "pop" : 2766, "state" : "NY" }
+{ "_id" : "13786", "city" : "HARPERSFIELD", "loc" : [ -74.687059, 42.449901 ], "pop" : 309, "state" : "NY" }
+{ "_id" : "13787", "city" : "HARPURSVILLE", "loc" : [ -75.654538, 42.18232 ], "pop" : 4349, "state" : "NY" }
+{ "_id" : "13788", "city" : "HOBART", "loc" : [ -74.675889, 42.359409 ], "pop" : 975, "state" : "NY" }
+{ "_id" : "13790", "city" : "JOHNSON CITY", "loc" : [ -75.968492, 42.126683 ], "pop" : 20788, "state" : "NY" }
+{ "_id" : "13795", "city" : "KIRKWOOD", "loc" : [ -75.796711, 42.069463 ], "pop" : 4133, "state" : "NY" }
+{ "_id" : "13796", "city" : "LAURENS", "loc" : [ -75.12794700000001, 42.538261 ], "pop" : 1703, "state" : "NY" }
+{ "_id" : "13797", "city" : "LISLE", "loc" : [ -76.030237, 42.340923 ], "pop" : 2331, "state" : "NY" }
+{ "_id" : "13801", "city" : "MC DONOUGH", "loc" : [ -75.762305, 42.506807 ], "pop" : 881, "state" : "NY" }
+{ "_id" : "13802", "city" : "MAINE", "loc" : [ -76.05952600000001, 42.196204 ], "pop" : 254, "state" : "NY" }
+{ "_id" : "13803", "city" : "MARATHON", "loc" : [ -76.039526, 42.452725 ], "pop" : 3586, "state" : "NY" }
+{ "_id" : "13804", "city" : "MASONVILLE", "loc" : [ -75.215485, 42.262346 ], "pop" : 15, "state" : "NY" }
+{ "_id" : "13806", "city" : "MERIDALE", "loc" : [ -74.98025800000001, 42.377987 ], "pop" : 16, "state" : "NY" }
+{ "_id" : "13807", "city" : "MILFORD", "loc" : [ -74.968498, 42.614801 ], "pop" : 1409, "state" : "NY" }
+{ "_id" : "13808", "city" : "MORRIS", "loc" : [ -75.244764, 42.547807 ], "pop" : 1359, "state" : "NY" }
+{ "_id" : "13809", "city" : "MOUNT UPTON", "loc" : [ -75.400268, 42.408064 ], "pop" : 1462, "state" : "NY" }
+{ "_id" : "13810", "city" : "MOUNT VISION", "loc" : [ -75.126366, 42.606763 ], "pop" : 1261, "state" : "NY" }
+{ "_id" : "13811", "city" : "NEWARK VALLEY", "loc" : [ -76.16248, 42.228136 ], "pop" : 4968, "state" : "NY" }
+{ "_id" : "13812", "city" : "NICHOLS", "loc" : [ -76.36103900000001, 42.031961 ], "pop" : 2888, "state" : "NY" }
+{ "_id" : "13813", "city" : "NINEVEH", "loc" : [ -75.54840900000001, 42.162481 ], "pop" : 975, "state" : "NY" }
+{ "_id" : "13815", "city" : "NORWICH", "loc" : [ -75.52743100000001, 42.54145 ], "pop" : 15380, "state" : "NY" }
+{ "_id" : "13820", "city" : "ONEONTA", "loc" : [ -75.049072, 42.462453 ], "pop" : 18196, "state" : "NY" }
+{ "_id" : "13825", "city" : "OTEGO", "loc" : [ -75.207883, 42.41333 ], "pop" : 5075, "state" : "NY" }
+{ "_id" : "13826", "city" : "OUAQUAGA", "loc" : [ -75.647351, 42.119293 ], "pop" : 75, "state" : "NY" }
+{ "_id" : "13827", "city" : "OWEGO", "loc" : [ -76.252797, 42.113809 ], "pop" : 11378, "state" : "NY" }
+{ "_id" : "13830", "city" : "BRISBEN", "loc" : [ -75.606256, 42.443375 ], "pop" : 5086, "state" : "NY" }
+{ "_id" : "13832", "city" : "PLYMOUTH", "loc" : [ -75.61716300000001, 42.633592 ], "pop" : 445, "state" : "NY" }
+{ "_id" : "13833", "city" : "SANITARIA SPRING", "loc" : [ -75.790978, 42.195735 ], "pop" : 4777, "state" : "NY" }
+{ "_id" : "13834", "city" : "PORTLANDVILLE", "loc" : [ -74.97605900000001, 42.510303 ], "pop" : 916, "state" : "NY" }
+{ "_id" : "13835", "city" : "RICHFORD", "loc" : [ -76.18650100000001, 42.394521 ], "pop" : 1383, "state" : "NY" }
+{ "_id" : "13838", "city" : "SIDNEY", "loc" : [ -75.3908, 42.307368 ], "pop" : 4946, "state" : "NY" }
+{ "_id" : "13839", "city" : "SIDNEY CENTER", "loc" : [ -75.287057, 42.244085 ], "pop" : 2020, "state" : "NY" }
+{ "_id" : "13841", "city" : "SMITHVILLE FLATS", "loc" : [ -75.823719, 42.398894 ], "pop" : 484, "state" : "NY" }
+{ "_id" : "13842", "city" : "SOUTH KORTRIGHT", "loc" : [ -74.72590099999999, 42.376994 ], "pop" : 253, "state" : "NY" }
+{ "_id" : "13843", "city" : "SOUTH NEW BERLIN", "loc" : [ -75.35249, 42.530569 ], "pop" : 2702, "state" : "NY" }
+{ "_id" : "13844", "city" : "SOUTH PLYMOUTH", "loc" : [ -75.633, 42.605254 ], "pop" : 510, "state" : "NY" }
+{ "_id" : "13846", "city" : "TREADWELL", "loc" : [ -75.05875399999999, 42.362963 ], "pop" : 60, "state" : "NY" }
+{ "_id" : "13849", "city" : "UNADILLA", "loc" : [ -75.336589, 42.325199 ], "pop" : 4027, "state" : "NY" }
+{ "_id" : "13850", "city" : "VESTAL", "loc" : [ -76.011757, 42.077106 ], "pop" : 27686, "state" : "NY" }
+{ "_id" : "13856", "city" : "WALTON", "loc" : [ -75.153177, 42.175647 ], "pop" : 7282, "state" : "NY" }
+{ "_id" : "13859", "city" : "WELLS BRIDGE", "loc" : [ -75.25656499999999, 42.357973 ], "pop" : 232, "state" : "NY" }
+{ "_id" : "13861", "city" : "WEST ONEONTA", "loc" : [ -75.09568899999999, 42.453854 ], "pop" : 3471, "state" : "NY" }
+{ "_id" : "13862", "city" : "WHITNEY POINT", "loc" : [ -75.952231, 42.338449 ], "pop" : 4105, "state" : "NY" }
+{ "_id" : "13863", "city" : "WILLET", "loc" : [ -75.90143399999999, 42.452044 ], "pop" : 188, "state" : "NY" }
+{ "_id" : "13864", "city" : "WILLSEYVILLE", "loc" : [ -76.38972099999999, 42.302915 ], "pop" : 697, "state" : "NY" }
+{ "_id" : "13865", "city" : "WINDSOR", "loc" : [ -75.672828, 42.074482 ], "pop" : 6820, "state" : "NY" }
+{ "_id" : "13901", "city" : "BINGHAMTON", "loc" : [ -75.886517, 42.146307 ], "pop" : 21666, "state" : "NY" }
+{ "_id" : "13903", "city" : "BINGHAMTON", "loc" : [ -75.897676, 42.081102 ], "pop" : 20353, "state" : "NY" }
+{ "_id" : "13904", "city" : "BINGHAMTON", "loc" : [ -75.865269, 42.11714 ], "pop" : 10257, "state" : "NY" }
+{ "_id" : "13905", "city" : "BINGHAMTON", "loc" : [ -75.930865, 42.115051 ], "pop" : 30741, "state" : "NY" }
+{ "_id" : "14001", "city" : "AKRON", "loc" : [ -78.508365, 43.024944 ], "pop" : 7924, "state" : "NY" }
+{ "_id" : "14003", "city" : "ALABAMA", "loc" : [ -78.385231, 43.071888 ], "pop" : 68, "state" : "NY" }
+{ "_id" : "14004", "city" : "ALDEN", "loc" : [ -78.525707, 42.89839 ], "pop" : 12711, "state" : "NY" }
+{ "_id" : "14005", "city" : "ALEXANDER", "loc" : [ -78.25888999999999, 42.915851 ], "pop" : 1692, "state" : "NY" }
+{ "_id" : "14006", "city" : "ANGOLA", "loc" : [ -79.049651, 42.636581 ], "pop" : 11509, "state" : "NY" }
+{ "_id" : "14008", "city" : "APPLETON", "loc" : [ -78.63721700000001, 43.310535 ], "pop" : 940, "state" : "NY" }
+{ "_id" : "14009", "city" : "ARCADE", "loc" : [ -78.41341799999999, 42.562995 ], "pop" : 4898, "state" : "NY" }
+{ "_id" : "14011", "city" : "ATTICA", "loc" : [ -78.279826, 42.849918 ], "pop" : 9372, "state" : "NY" }
+{ "_id" : "14012", "city" : "BARKER", "loc" : [ -78.54200400000001, 43.336779 ], "pop" : 2441, "state" : "NY" }
+{ "_id" : "14013", "city" : "BASOM", "loc" : [ -78.395143, 43.080724 ], "pop" : 2062, "state" : "NY" }
+{ "_id" : "14020", "city" : "BATAVIA", "loc" : [ -78.192869, 43.000316 ], "pop" : 22835, "state" : "NY" }
+{ "_id" : "14024", "city" : "BLISS", "loc" : [ -78.258084, 42.579936 ], "pop" : 1498, "state" : "NY" }
+{ "_id" : "14025", "city" : "BOSTON", "loc" : [ -78.73909, 42.631384 ], "pop" : 2617, "state" : "NY" }
+{ "_id" : "14026", "city" : "BOWMANSVILLE", "loc" : [ -78.68296100000001, 42.947826 ], "pop" : 285, "state" : "NY" }
+{ "_id" : "14028", "city" : "BURT", "loc" : [ -78.714097, 43.322089 ], "pop" : 2363, "state" : "NY" }
+{ "_id" : "14030", "city" : "CHAFFEE", "loc" : [ -78.502543, 42.560492 ], "pop" : 1481, "state" : "NY" }
+{ "_id" : "14031", "city" : "CLARENCE", "loc" : [ -78.61622800000001, 42.980965 ], "pop" : 7712, "state" : "NY" }
+{ "_id" : "14032", "city" : "CLARENCE CENTER", "loc" : [ -78.63903000000001, 43.0362 ], "pop" : 3996, "state" : "NY" }
+{ "_id" : "14033", "city" : "COLDEN", "loc" : [ -78.692078, 42.655052 ], "pop" : 2380, "state" : "NY" }
+{ "_id" : "14034", "city" : "COLLINS", "loc" : [ -78.892974, 42.500082 ], "pop" : 2194, "state" : "NY" }
+{ "_id" : "14036", "city" : "CORFU", "loc" : [ -78.392906, 42.977734 ], "pop" : 4841, "state" : "NY" }
+{ "_id" : "14037", "city" : "COWLESVILLE", "loc" : [ -78.44813600000001, 42.811245 ], "pop" : 1017, "state" : "NY" }
+{ "_id" : "14039", "city" : "DALE", "loc" : [ -78.174865, 42.826284 ], "pop" : 72, "state" : "NY" }
+{ "_id" : "14040", "city" : "DARIEN CENTER", "loc" : [ -78.387782, 42.894806 ], "pop" : 1817, "state" : "NY" }
+{ "_id" : "14041", "city" : "DAYTON", "loc" : [ -78.981842, 42.423075 ], "pop" : 246, "state" : "NY" }
+{ "_id" : "14042", "city" : "DELEVAN", "loc" : [ -78.479326, 42.492598 ], "pop" : 4516, "state" : "NY" }
+{ "_id" : "14043", "city" : "DEPEW", "loc" : [ -78.704052, 42.904973 ], "pop" : 26460, "state" : "NY" }
+{ "_id" : "14047", "city" : "DERBY", "loc" : [ -78.98336500000001, 42.697445 ], "pop" : 6436, "state" : "NY" }
+{ "_id" : "14048", "city" : "VAN BUREN BAY", "loc" : [ -79.32936599999999, 42.475907 ], "pop" : 20303, "state" : "NY" }
+{ "_id" : "14051", "city" : "SWORMVILLE", "loc" : [ -78.705035, 43.029168 ], "pop" : 12714, "state" : "NY" }
+{ "_id" : "14052", "city" : "EAST AURORA", "loc" : [ -78.601992, 42.770138 ], "pop" : 17244, "state" : "NY" }
+{ "_id" : "14054", "city" : "EAST BETHANY", "loc" : [ -78.13420600000001, 42.916619 ], "pop" : 1569, "state" : "NY" }
+{ "_id" : "14055", "city" : "EAST CONCORD", "loc" : [ -78.610972, 42.546585 ], "pop" : 1216, "state" : "NY" }
+{ "_id" : "14057", "city" : "EDEN", "loc" : [ -78.878077, 42.650552 ], "pop" : 7427, "state" : "NY" }
+{ "_id" : "14058", "city" : "ELBA", "loc" : [ -78.170383, 43.089739 ], "pop" : 2331, "state" : "NY" }
+{ "_id" : "14059", "city" : "ELMA", "loc" : [ -78.63425700000001, 42.834002 ], "pop" : 8130, "state" : "NY" }
+{ "_id" : "14060", "city" : "FARMERSVILLE STA", "loc" : [ -78.291533, 42.44827 ], "pop" : 395, "state" : "NY" }
+{ "_id" : "14062", "city" : "FORESTVILLE", "loc" : [ -79.160743, 42.448229 ], "pop" : 2858, "state" : "NY" }
+{ "_id" : "14063", "city" : "FREDONIA", "loc" : [ -79.33391399999999, 42.433345 ], "pop" : 10738, "state" : "NY" }
+{ "_id" : "14065", "city" : "FREEDOM", "loc" : [ -78.35012999999999, 42.489693 ], "pop" : 2001, "state" : "NY" }
+{ "_id" : "14066", "city" : "GAINESVILLE", "loc" : [ -78.17951600000001, 42.61897 ], "pop" : 1536, "state" : "NY" }
+{ "_id" : "14067", "city" : "GASPORT", "loc" : [ -78.57453599999999, 43.210587 ], "pop" : 6010, "state" : "NY" }
+{ "_id" : "14068", "city" : "GETZVILLE", "loc" : [ -78.753184, 43.023989 ], "pop" : 5685, "state" : "NY" }
+{ "_id" : "14069", "city" : "GLENWOOD", "loc" : [ -78.638634, 42.600094 ], "pop" : 632, "state" : "NY" }
+{ "_id" : "14070", "city" : "GOWANDA", "loc" : [ -78.933902, 42.471202 ], "pop" : 6665, "state" : "NY" }
+{ "_id" : "14072", "city" : "GRAND ISLAND", "loc" : [ -78.959059, 43.018266 ], "pop" : 17561, "state" : "NY" }
+{ "_id" : "14075", "city" : "HAMBURG", "loc" : [ -78.838853, 42.733404 ], "pop" : 38851, "state" : "NY" }
+{ "_id" : "14080", "city" : "HOLLAND", "loc" : [ -78.54388899999999, 42.639582 ], "pop" : 4004, "state" : "NY" }
+{ "_id" : "14081", "city" : "IRVING", "loc" : [ -79.059634, 42.573866 ], "pop" : 2993, "state" : "NY" }
+{ "_id" : "14082", "city" : "JAVA CENTER", "loc" : [ -78.392527, 42.66342 ], "pop" : 613, "state" : "NY" }
+{ "_id" : "14083", "city" : "JAVA VILLAGE", "loc" : [ -78.44101000000001, 42.676852 ], "pop" : 35, "state" : "NY" }
+{ "_id" : "14085", "city" : "LAKE VIEW", "loc" : [ -78.932693, 42.721535 ], "pop" : 4936, "state" : "NY" }
+{ "_id" : "14086", "city" : "LANCASTER", "loc" : [ -78.663085, 42.901681 ], "pop" : 24540, "state" : "NY" }
+{ "_id" : "14091", "city" : "LAWTONS", "loc" : [ -78.921222, 42.540364 ], "pop" : 1510, "state" : "NY" }
+{ "_id" : "14092", "city" : "LEWISTON", "loc" : [ -79.021547, 43.172165 ], "pop" : 10540, "state" : "NY" }
+{ "_id" : "14094", "city" : "LOCKPORT", "loc" : [ -78.69234400000001, 43.159987 ], "pop" : 48398, "state" : "NY" }
+{ "_id" : "14098", "city" : "LYNDONVILLE", "loc" : [ -78.381057, 43.323312 ], "pop" : 3109, "state" : "NY" }
+{ "_id" : "14101", "city" : "MACHIAS", "loc" : [ -78.50586, 42.408271 ], "pop" : 1860, "state" : "NY" }
+{ "_id" : "14102", "city" : "MARILLA", "loc" : [ -78.558656, 42.833216 ], "pop" : 1063, "state" : "NY" }
+{ "_id" : "14103", "city" : "MEDINA", "loc" : [ -78.387422, 43.218428 ], "pop" : 12042, "state" : "NY" }
+{ "_id" : "14105", "city" : "MIDDLEPORT", "loc" : [ -78.484055, 43.218257 ], "pop" : 3929, "state" : "NY" }
+{ "_id" : "14108", "city" : "NEWFANE", "loc" : [ -78.70697199999999, 43.272443 ], "pop" : 5261, "state" : "NY" }
+{ "_id" : "14111", "city" : "NORTH COLLINS", "loc" : [ -78.91073, 42.589648 ], "pop" : 2429, "state" : "NY" }
+{ "_id" : "14113", "city" : "NORTH JAVA", "loc" : [ -78.337958, 42.677631 ], "pop" : 606, "state" : "NY" }
+{ "_id" : "14120", "city" : "NORTH TONAWANDA", "loc" : [ -78.85099700000001, 43.049828 ], "pop" : 51399, "state" : "NY" }
+{ "_id" : "14125", "city" : "OAKFIELD", "loc" : [ -78.270179, 43.071726 ], "pop" : 3760, "state" : "NY" }
+{ "_id" : "14127", "city" : "ORCHARD PARK", "loc" : [ -78.751834, 42.763891 ], "pop" : 26554, "state" : "NY" }
+{ "_id" : "14129", "city" : "PERRYSBURG", "loc" : [ -78.998108, 42.472289 ], "pop" : 2198, "state" : "NY" }
+{ "_id" : "14131", "city" : "RANSOMVILLE", "loc" : [ -78.89815900000001, 43.228602 ], "pop" : 5836, "state" : "NY" }
+{ "_id" : "14132", "city" : "SANBORN", "loc" : [ -78.878522, 43.141879 ], "pop" : 5167, "state" : "NY" }
+{ "_id" : "14134", "city" : "SARDINIA", "loc" : [ -78.506415, 42.532976 ], "pop" : 133, "state" : "NY" }
+{ "_id" : "14136", "city" : "SILVER CREEK", "loc" : [ -79.16280500000001, 42.535675 ], "pop" : 5768, "state" : "NY" }
+{ "_id" : "14138", "city" : "SOUTH DAYTON", "loc" : [ -79.050132, 42.371803 ], "pop" : 1600, "state" : "NY" }
+{ "_id" : "14139", "city" : "SOUTH WALES", "loc" : [ -78.545219, 42.706271 ], "pop" : 2269, "state" : "NY" }
+{ "_id" : "14141", "city" : "SPRINGVILLE", "loc" : [ -78.68471700000001, 42.519982 ], "pop" : 7146, "state" : "NY" }
+{ "_id" : "14143", "city" : "STAFFORD", "loc" : [ -78.089783, 42.982894 ], "pop" : 2076, "state" : "NY" }
+{ "_id" : "14145", "city" : "STRYKERSVILLE", "loc" : [ -78.434714, 42.724892 ], "pop" : 1374, "state" : "NY" }
+{ "_id" : "14150", "city" : "TONAWANDA", "loc" : [ -78.85472, 43.002837 ], "pop" : 53410, "state" : "NY" }
+{ "_id" : "14167", "city" : "VARYSBURG", "loc" : [ -78.316749, 42.745935 ], "pop" : 1782, "state" : "NY" }
+{ "_id" : "14170", "city" : "WEST FALLS", "loc" : [ -78.677937, 42.70532 ], "pop" : 2217, "state" : "NY" }
+{ "_id" : "14171", "city" : "WEST VALLEY", "loc" : [ -78.627978, 42.43153 ], "pop" : 2600, "state" : "NY" }
+{ "_id" : "14172", "city" : "WILSON", "loc" : [ -78.82439599999999, 43.29681 ], "pop" : 3441, "state" : "NY" }
+{ "_id" : "14174", "city" : "YOUNGSTOWN", "loc" : [ -79.024545, 43.246075 ], "pop" : 5728, "state" : "NY" }
+{ "_id" : "14201", "city" : "BUFFALO", "loc" : [ -78.884575, 42.896659 ], "pop" : 16682, "state" : "NY" }
+{ "_id" : "14202", "city" : "BUFFALO", "loc" : [ -78.877948, 42.887038 ], "pop" : 2828, "state" : "NY" }
+{ "_id" : "14203", "city" : "BUFFALO", "loc" : [ -78.868143, 42.893938 ], "pop" : 1211, "state" : "NY" }
+{ "_id" : "14204", "city" : "BUFFALO", "loc" : [ -78.859736, 42.883978 ], "pop" : 10962, "state" : "NY" }
+{ "_id" : "14206", "city" : "BUFFALO", "loc" : [ -78.81037499999999, 42.881132 ], "pop" : 25496, "state" : "NY" }
+{ "_id" : "14207", "city" : "BUFFALO", "loc" : [ -78.89781499999999, 42.949062 ], "pop" : 23890, "state" : "NY" }
+{ "_id" : "14208", "city" : "BUFFALO", "loc" : [ -78.850487, 42.915416 ], "pop" : 14705, "state" : "NY" }
+{ "_id" : "14209", "city" : "BUFFALO", "loc" : [ -78.865629, 42.913 ], "pop" : 8865, "state" : "NY" }
+{ "_id" : "14210", "city" : "BUFFALO", "loc" : [ -78.82055, 42.861432 ], "pop" : 18506, "state" : "NY" }
+{ "_id" : "14211", "city" : "BUFFALO", "loc" : [ -78.82247700000001, 42.908153 ], "pop" : 38411, "state" : "NY" }
+{ "_id" : "14212", "city" : "BUFFALO", "loc" : [ -78.82445800000001, 42.894553 ], "pop" : 19935, "state" : "NY" }
+{ "_id" : "14213", "city" : "BUFFALO", "loc" : [ -78.889461, 42.916675 ], "pop" : 32876, "state" : "NY" }
+{ "_id" : "14214", "city" : "BUFFALO", "loc" : [ -78.83740299999999, 42.941429 ], "pop" : 21770, "state" : "NY" }
+{ "_id" : "14215", "city" : "BUFFALO", "loc" : [ -78.811504, 42.933536 ], "pop" : 46789, "state" : "NY" }
+{ "_id" : "14216", "city" : "BUFFALO", "loc" : [ -78.859865, 42.949914 ], "pop" : 24852, "state" : "NY" }
+{ "_id" : "14217", "city" : "KENMORE", "loc" : [ -78.87294799999999, 42.968618 ], "pop" : 25547, "state" : "NY" }
+{ "_id" : "14218", "city" : "LACKAWANNA", "loc" : [ -78.817263, 42.818301 ], "pop" : 22309, "state" : "NY" }
+{ "_id" : "14219", "city" : "BLASDELL", "loc" : [ -78.822228, 42.790039 ], "pop" : 13376, "state" : "NY" }
+{ "_id" : "14220", "city" : "BUFFALO", "loc" : [ -78.81820500000001, 42.844138 ], "pop" : 28994, "state" : "NY" }
+{ "_id" : "14221", "city" : "WILLIAMSVILLE", "loc" : [ -78.738044, 42.985621 ], "pop" : 54703, "state" : "NY" }
+{ "_id" : "14222", "city" : "BUFFALO", "loc" : [ -78.876333, 42.916401 ], "pop" : 12712, "state" : "NY" }
+{ "_id" : "14223", "city" : "BUFFALO", "loc" : [ -78.845, 42.973088 ], "pop" : 25995, "state" : "NY" }
+{ "_id" : "14224", "city" : "WEST SENECA", "loc" : [ -78.75109, 42.836162 ], "pop" : 41539, "state" : "NY" }
+{ "_id" : "14225", "city" : "CHEEKTOWAGA", "loc" : [ -78.76085500000001, 42.928642 ], "pop" : 37707, "state" : "NY" }
+{ "_id" : "14226", "city" : "AMHERST", "loc" : [ -78.79984899999999, 42.967232 ], "pop" : 31912, "state" : "NY" }
+{ "_id" : "14227", "city" : "CHEEKTOWAGA", "loc" : [ -78.741936, 42.877467 ], "pop" : 25240, "state" : "NY" }
+{ "_id" : "14228", "city" : "AMHERST", "loc" : [ -78.774604, 43.018414 ], "pop" : 1813, "state" : "NY" }
+{ "_id" : "14301", "city" : "NIAGARA FALLS", "loc" : [ -79.041443, 43.095467 ], "pop" : 15756, "state" : "NY" }
+{ "_id" : "14303", "city" : "NIAGARA FALLS", "loc" : [ -79.036958, 43.087777 ], "pop" : 8616, "state" : "NY" }
+{ "_id" : "14304", "city" : "NIAGARA FALLS", "loc" : [ -78.964375, 43.090844 ], "pop" : 30527, "state" : "NY" }
+{ "_id" : "14305", "city" : "NIAGARA FALLS", "loc" : [ -79.03780399999999, 43.114648 ], "pop" : 22726, "state" : "NY" }
+{ "_id" : "14410", "city" : "ADAMS BASIN", "loc" : [ -77.853905, 43.190644 ], "pop" : 989, "state" : "NY" }
+{ "_id" : "14411", "city" : "ALBION", "loc" : [ -78.206846, 43.239827 ], "pop" : 12743, "state" : "NY" }
+{ "_id" : "14414", "city" : "AVON", "loc" : [ -77.72739799999999, 42.903034 ], "pop" : 6187, "state" : "NY" }
+{ "_id" : "14415", "city" : "BELLONA", "loc" : [ -77.021737, 42.755442 ], "pop" : 182, "state" : "NY" }
+{ "_id" : "14416", "city" : "BERGEN", "loc" : [ -77.96033, 43.086937 ], "pop" : 3092, "state" : "NY" }
+{ "_id" : "14418", "city" : "BRANCHPORT", "loc" : [ -77.20516499999999, 42.606537 ], "pop" : 1126, "state" : "NY" }
+{ "_id" : "14420", "city" : "BROCKPORT", "loc" : [ -77.936797, 43.21284 ], "pop" : 17492, "state" : "NY" }
+{ "_id" : "14422", "city" : "BYRON", "loc" : [ -78.062912, 43.073794 ], "pop" : 2499, "state" : "NY" }
+{ "_id" : "14423", "city" : "CALEDONIA", "loc" : [ -77.849295, 42.956661 ], "pop" : 4942, "state" : "NY" }
+{ "_id" : "14424", "city" : "CANANDAIGUA", "loc" : [ -77.284561, 42.868866 ], "pop" : 20748, "state" : "NY" }
+{ "_id" : "14425", "city" : "CANANDAIGUA", "loc" : [ -77.341139, 42.959591 ], "pop" : 10082, "state" : "NY" }
+{ "_id" : "14427", "city" : "CASTILE", "loc" : [ -78.054728, 42.635883 ], "pop" : 2169, "state" : "NY" }
+{ "_id" : "14428", "city" : "CLIFTON", "loc" : [ -77.860339, 43.089617 ], "pop" : 6481, "state" : "NY" }
+{ "_id" : "14432", "city" : "CLIFTON SPRINGS", "loc" : [ -77.143975, 42.963175 ], "pop" : 5060, "state" : "NY" }
+{ "_id" : "14433", "city" : "CLYDE", "loc" : [ -76.87246399999999, 43.085549 ], "pop" : 4565, "state" : "NY" }
+{ "_id" : "14435", "city" : "CONESUS", "loc" : [ -77.67469, 42.721643 ], "pop" : 2364, "state" : "NY" }
+{ "_id" : "14437", "city" : "DANSVILLE", "loc" : [ -77.71090700000001, 42.569975 ], "pop" : 8804, "state" : "NY" }
+{ "_id" : "14441", "city" : "DRESDEN", "loc" : [ -76.956389, 42.684565 ], "pop" : 381, "state" : "NY" }
+{ "_id" : "14445", "city" : "EAST ROCHESTER", "loc" : [ -77.490596, 43.112808 ], "pop" : 8868, "state" : "NY" }
+{ "_id" : "14450", "city" : "FAIRPORT", "loc" : [ -77.435956, 43.089198 ], "pop" : 37337, "state" : "NY" }
+{ "_id" : "14454", "city" : "GENESEO", "loc" : [ -77.79955200000001, 42.793783 ], "pop" : 9551, "state" : "NY" }
+{ "_id" : "14456", "city" : "GENEVA", "loc" : [ -76.991349, 42.86372 ], "pop" : 20112, "state" : "NY" }
+{ "_id" : "14462", "city" : "GROVELAND", "loc" : [ -77.757334, 42.676046 ], "pop" : 483, "state" : "NY" }
+{ "_id" : "14464", "city" : "HAMLIN", "loc" : [ -77.926996, 43.307577 ], "pop" : 7355, "state" : "NY" }
+{ "_id" : "14466", "city" : "HEMLOCK", "loc" : [ -77.58199, 42.779957 ], "pop" : 1160, "state" : "NY" }
+{ "_id" : "14467", "city" : "HENRIETTA", "loc" : [ -77.612224, 43.048264 ], "pop" : 8450, "state" : "NY" }
+{ "_id" : "14468", "city" : "HILTON", "loc" : [ -77.790511, 43.292344 ], "pop" : 15837, "state" : "NY" }
+{ "_id" : "14469", "city" : "BLOOMFIELD", "loc" : [ -77.45998299999999, 42.885101 ], "pop" : 6129, "state" : "NY" }
+{ "_id" : "14470", "city" : "HULBERTON", "loc" : [ -78.040392, 43.225494 ], "pop" : 8375, "state" : "NY" }
+{ "_id" : "14471", "city" : "HONEOYE", "loc" : [ -77.50543399999999, 42.768637 ], "pop" : 2704, "state" : "NY" }
+{ "_id" : "14472", "city" : "HONEOYE FALLS", "loc" : [ -77.57812, 42.969499 ], "pop" : 6768, "state" : "NY" }
+{ "_id" : "14475", "city" : "IONIA", "loc" : [ -77.50086, 42.938002 ], "pop" : 232, "state" : "NY" }
+{ "_id" : "14476", "city" : "KENDALL", "loc" : [ -78.030359, 43.328415 ], "pop" : 2186, "state" : "NY" }
+{ "_id" : "14477", "city" : "KENT", "loc" : [ -78.135533, 43.334064 ], "pop" : 2040, "state" : "NY" }
+{ "_id" : "14478", "city" : "BLUFF POINT", "loc" : [ -77.105197, 42.601032 ], "pop" : 1555, "state" : "NY" }
+{ "_id" : "14480", "city" : "LAKEVILLE", "loc" : [ -77.714865, 42.82957 ], "pop" : 724, "state" : "NY" }
+{ "_id" : "14481", "city" : "LEICESTER", "loc" : [ -77.898976, 42.773903 ], "pop" : 1881, "state" : "NY" }
+{ "_id" : "14482", "city" : "LE ROY", "loc" : [ -77.985097, 42.977377 ], "pop" : 9037, "state" : "NY" }
+{ "_id" : "14485", "city" : "LIMA", "loc" : [ -77.608305, 42.901234 ], "pop" : 4666, "state" : "NY" }
+{ "_id" : "14486", "city" : "LINWOOD", "loc" : [ -77.910422, 42.884721 ], "pop" : 860, "state" : "NY" }
+{ "_id" : "14487", "city" : "LIVONIA", "loc" : [ -77.663472, 42.813514 ], "pop" : 6108, "state" : "NY" }
+{ "_id" : "14489", "city" : "LYONS", "loc" : [ -76.989575, 43.07768 ], "pop" : 8168, "state" : "NY" }
+{ "_id" : "14502", "city" : "MACEDON", "loc" : [ -77.337199, 43.078366 ], "pop" : 8486, "state" : "NY" }
+{ "_id" : "14504", "city" : "MANCHESTER", "loc" : [ -77.229733, 42.969874 ], "pop" : 1522, "state" : "NY" }
+{ "_id" : "14505", "city" : "MARION", "loc" : [ -77.186277, 43.154612 ], "pop" : 4663, "state" : "NY" }
+{ "_id" : "14506", "city" : "MENDON", "loc" : [ -77.50013, 42.995307 ], "pop" : 864, "state" : "NY" }
+{ "_id" : "14507", "city" : "MIDDLESEX", "loc" : [ -77.280509, 42.697624 ], "pop" : 1256, "state" : "NY" }
+{ "_id" : "14510", "city" : "TUSCARORA", "loc" : [ -77.86108299999999, 42.705431 ], "pop" : 7145, "state" : "NY" }
+{ "_id" : "14512", "city" : "NAPLES", "loc" : [ -77.390106, 42.640425 ], "pop" : 4616, "state" : "NY" }
+{ "_id" : "14513", "city" : "NEWARK", "loc" : [ -77.09460199999999, 43.051909 ], "pop" : 14670, "state" : "NY" }
+{ "_id" : "14514", "city" : "NORTH CHILI", "loc" : [ -77.800518, 43.118601 ], "pop" : 4014, "state" : "NY" }
+{ "_id" : "14516", "city" : "NORTH ROSE", "loc" : [ -76.91515200000001, 43.196439 ], "pop" : 2428, "state" : "NY" }
+{ "_id" : "14517", "city" : "NUNDA", "loc" : [ -77.91800600000001, 42.586708 ], "pop" : 2439, "state" : "NY" }
+{ "_id" : "14519", "city" : "ONTARIO", "loc" : [ -77.308781, 43.229092 ], "pop" : 10016, "state" : "NY" }
+{ "_id" : "14521", "city" : "HAYT CORNERS", "loc" : [ -76.821575, 42.676979 ], "pop" : 3225, "state" : "NY" }
+{ "_id" : "14522", "city" : "PALMYRA", "loc" : [ -77.22179800000001, 43.062192 ], "pop" : 9486, "state" : "NY" }
+{ "_id" : "14525", "city" : "LINWOOD", "loc" : [ -78.014698, 42.880088 ], "pop" : 2628, "state" : "NY" }
+{ "_id" : "14526", "city" : "PENFIELD", "loc" : [ -77.45604299999999, 43.139638 ], "pop" : 16675, "state" : "NY" }
+{ "_id" : "14527", "city" : "PENN YAN", "loc" : [ -77.05687, 42.664548 ], "pop" : 11609, "state" : "NY" }
+{ "_id" : "14530", "city" : "PERRY", "loc" : [ -78.005882, 42.722852 ], "pop" : 6218, "state" : "NY" }
+{ "_id" : "14532", "city" : "PHELPS", "loc" : [ -77.047264, 42.958178 ], "pop" : 4366, "state" : "NY" }
+{ "_id" : "14533", "city" : "WADSWORTH", "loc" : [ -77.88254499999999, 42.84269 ], "pop" : 2094, "state" : "NY" }
+{ "_id" : "14534", "city" : "PITTSFORD", "loc" : [ -77.514067, 43.069511 ], "pop" : 27413, "state" : "NY" }
+{ "_id" : "14536", "city" : "PORTAGEVILLE", "loc" : [ -78.085635, 42.556957 ], "pop" : 980, "state" : "NY" }
+{ "_id" : "14541", "city" : "MAC DOUGALL", "loc" : [ -76.853582, 42.761378 ], "pop" : 3150, "state" : "NY" }
+{ "_id" : "14543", "city" : "WEST RUSH", "loc" : [ -77.665381, 42.998934 ], "pop" : 2481, "state" : "NY" }
+{ "_id" : "14544", "city" : "RUSHVILLE", "loc" : [ -77.239538, 42.75973 ], "pop" : 1948, "state" : "NY" }
+{ "_id" : "14545", "city" : "SCOTTSBURG", "loc" : [ -77.682633, 42.658907 ], "pop" : 612, "state" : "NY" }
+{ "_id" : "14546", "city" : "SCOTTSVILLE", "loc" : [ -77.77425599999999, 43.02462 ], "pop" : 5604, "state" : "NY" }
+{ "_id" : "14548", "city" : "SHORTSVILLE", "loc" : [ -77.227312, 42.969034 ], "pop" : 4524, "state" : "NY" }
+{ "_id" : "14550", "city" : "ROCK GLEN", "loc" : [ -78.092994, 42.669446 ], "pop" : 1824, "state" : "NY" }
+{ "_id" : "14551", "city" : "SODUS", "loc" : [ -77.05141, 43.221681 ], "pop" : 5831, "state" : "NY" }
+{ "_id" : "14555", "city" : "SODUS POINT", "loc" : [ -76.98833, 43.265058 ], "pop" : 1058, "state" : "NY" }
+{ "_id" : "14559", "city" : "SPENCERPORT", "loc" : [ -77.804333, 43.189502 ], "pop" : 14137, "state" : "NY" }
+{ "_id" : "14560", "city" : "SPRINGWATER", "loc" : [ -77.57750299999999, 42.677598 ], "pop" : 2319, "state" : "NY" }
+{ "_id" : "14561", "city" : "STANLEY", "loc" : [ -77.12070199999999, 42.830277 ], "pop" : 3102, "state" : "NY" }
+{ "_id" : "14564", "city" : "VICTOR", "loc" : [ -77.41798199999999, 42.986597 ], "pop" : 7322, "state" : "NY" }
+{ "_id" : "14568", "city" : "WALWORTH", "loc" : [ -77.28582, 43.140161 ], "pop" : 5461, "state" : "NY" }
+{ "_id" : "14569", "city" : "WARSAW", "loc" : [ -78.142899, 42.741035 ], "pop" : 5811, "state" : "NY" }
+{ "_id" : "14571", "city" : "WATERPORT", "loc" : [ -78.242958, 43.332563 ], "pop" : 1669, "state" : "NY" }
+{ "_id" : "14572", "city" : "WAYLAND", "loc" : [ -77.590613, 42.559274 ], "pop" : 5626, "state" : "NY" }
+{ "_id" : "14580", "city" : "WEBSTER", "loc" : [ -77.46158699999999, 43.219563 ], "pop" : 35072, "state" : "NY" }
+{ "_id" : "14586", "city" : "WEST HENRIETTA", "loc" : [ -77.68713099999999, 43.039667 ], "pop" : 5397, "state" : "NY" }
+{ "_id" : "14589", "city" : "WILLIAMSON", "loc" : [ -77.170011, 43.242071 ], "pop" : 7947, "state" : "NY" }
+{ "_id" : "14590", "city" : "WOLCOTT", "loc" : [ -76.821748, 43.234129 ], "pop" : 5356, "state" : "NY" }
+{ "_id" : "14591", "city" : "WYOMING", "loc" : [ -78.083292, 42.83175 ], "pop" : 2074, "state" : "NY" }
+{ "_id" : "14604", "city" : "ROCHESTER", "loc" : [ -77.607978, 43.157729 ], "pop" : 1434, "state" : "NY" }
+{ "_id" : "14605", "city" : "ROCHESTER", "loc" : [ -77.600711, 43.169758 ], "pop" : 15196, "state" : "NY" }
+{ "_id" : "14606", "city" : "ROCHESTER", "loc" : [ -77.684488, 43.168455 ], "pop" : 29822, "state" : "NY" }
+{ "_id" : "14607", "city" : "ROCHESTER", "loc" : [ -77.588976, 43.150086 ], "pop" : 16479, "state" : "NY" }
+{ "_id" : "14608", "city" : "ROCHESTER", "loc" : [ -77.625803, 43.152144 ], "pop" : 14631, "state" : "NY" }
+{ "_id" : "14609", "city" : "ROCHESTER", "loc" : [ -77.56370099999999, 43.174001 ], "pop" : 45805, "state" : "NY" }
+{ "_id" : "14610", "city" : "ROCHESTER", "loc" : [ -77.54950100000001, 43.14524 ], "pop" : 15167, "state" : "NY" }
+{ "_id" : "14611", "city" : "ROCHESTER", "loc" : [ -77.639353, 43.148375 ], "pop" : 15951, "state" : "NY" }
+{ "_id" : "14612", "city" : "ROCHESTER", "loc" : [ -77.665228, 43.256576 ], "pop" : 35820, "state" : "NY" }
+{ "_id" : "14613", "city" : "ROCHESTER", "loc" : [ -77.639276, 43.18308 ], "pop" : 15525, "state" : "NY" }
+{ "_id" : "14614", "city" : "ROCHESTER", "loc" : [ -77.61418999999999, 43.155823 ], "pop" : 1430, "state" : "NY" }
+{ "_id" : "14615", "city" : "ROCHESTER", "loc" : [ -77.652118, 43.20575 ], "pop" : 16000, "state" : "NY" }
+{ "_id" : "14616", "city" : "GREECE", "loc" : [ -77.65123800000001, 43.232359 ], "pop" : 26500, "state" : "NY" }
+{ "_id" : "14617", "city" : "ROCHESTER", "loc" : [ -77.599442, 43.220258 ], "pop" : 24296, "state" : "NY" }
+{ "_id" : "14618", "city" : "TWELVE CORNERS", "loc" : [ -77.558801, 43.115416 ], "pop" : 21912, "state" : "NY" }
+{ "_id" : "14619", "city" : "ROCHESTER", "loc" : [ -77.6481, 43.136685 ], "pop" : 19393, "state" : "NY" }
+{ "_id" : "14620", "city" : "ROCHESTER", "loc" : [ -77.606239, 43.131711 ], "pop" : 29819, "state" : "NY" }
+{ "_id" : "14621", "city" : "ROCHESTER", "loc" : [ -77.60428400000001, 43.183362 ], "pop" : 36055, "state" : "NY" }
+{ "_id" : "14622", "city" : "ROCHESTER", "loc" : [ -77.55549000000001, 43.213959 ], "pop" : 12489, "state" : "NY" }
+{ "_id" : "14623", "city" : "ROCHESTER", "loc" : [ -77.634412, 43.083371 ], "pop" : 25127, "state" : "NY" }
+{ "_id" : "14624", "city" : "WESTGATE", "loc" : [ -77.733552, 43.12589 ], "pop" : 35748, "state" : "NY" }
+{ "_id" : "14625", "city" : "PANORAMA", "loc" : [ -77.50318799999999, 43.14949 ], "pop" : 12009, "state" : "NY" }
+{ "_id" : "14626", "city" : "ROCHESTER", "loc" : [ -77.703996, 43.21257 ], "pop" : 25574, "state" : "NY" }
+{ "_id" : "14701", "city" : "JAMESTOWN", "loc" : [ -79.243989, 42.092845 ], "pop" : 45344, "state" : "NY" }
+{ "_id" : "14706", "city" : "ALLEGANY", "loc" : [ -78.499883, 42.091827 ], "pop" : 7885, "state" : "NY" }
+{ "_id" : "14708", "city" : "ALMA", "loc" : [ -78.040012, 42.016859 ], "pop" : 200, "state" : "NY" }
+{ "_id" : "14709", "city" : "ANGELICA", "loc" : [ -77.994671, 42.326339 ], "pop" : 1046, "state" : "NY" }
+{ "_id" : "14710", "city" : "ASHVILLE", "loc" : [ -79.405624, 42.108376 ], "pop" : 2450, "state" : "NY" }
+{ "_id" : "14711", "city" : "BELFAST", "loc" : [ -78.094281, 42.320013 ], "pop" : 2210, "state" : "NY" }
+{ "_id" : "14712", "city" : "BEMUS POINT", "loc" : [ -79.35808, 42.151346 ], "pop" : 3591, "state" : "NY" }
+{ "_id" : "14714", "city" : "BLACK CREEK", "loc" : [ -78.23124900000001, 42.285528 ], "pop" : 757, "state" : "NY" }
+{ "_id" : "14715", "city" : "BOLIVAR", "loc" : [ -78.144834, 42.070442 ], "pop" : 3173, "state" : "NY" }
+{ "_id" : "14716", "city" : "BROCTON", "loc" : [ -79.43443000000001, 42.393973 ], "pop" : 1863, "state" : "NY" }
+{ "_id" : "14717", "city" : "CANEADEA", "loc" : [ -78.197321, 42.370304 ], "pop" : 798, "state" : "NY" }
+{ "_id" : "14718", "city" : "CASSADAGA", "loc" : [ -79.29928200000001, 42.350356 ], "pop" : 1977, "state" : "NY" }
+{ "_id" : "14719", "city" : "CATTARAUGUS", "loc" : [ -78.88852799999999, 42.333291 ], "pop" : 3853, "state" : "NY" }
+{ "_id" : "14721", "city" : "CERES", "loc" : [ -78.27268599999999, 41.99939 ], "pop" : 33, "state" : "NY" }
+{ "_id" : "14723", "city" : "CHERRY CREEK", "loc" : [ -79.12027500000001, 42.312725 ], "pop" : 1408, "state" : "NY" }
+{ "_id" : "14724", "city" : "CLYMER", "loc" : [ -79.668532, 42.055699 ], "pop" : 2810, "state" : "NY" }
+{ "_id" : "14726", "city" : "CONEWANGO VALLEY", "loc" : [ -79.021956, 42.262467 ], "pop" : 1562, "state" : "NY" }
+{ "_id" : "14727", "city" : "CUBA", "loc" : [ -78.275074, 42.18819 ], "pop" : 5306, "state" : "NY" }
+{ "_id" : "14728", "city" : "DEWITTVILLE", "loc" : [ -79.419303, 42.239413 ], "pop" : 1159, "state" : "NY" }
+{ "_id" : "14729", "city" : "EAST OTTO", "loc" : [ -78.743167, 42.3971 ], "pop" : 1050, "state" : "NY" }
+{ "_id" : "14731", "city" : "ELLICOTTVILLE", "loc" : [ -78.66064, 42.295873 ], "pop" : 1767, "state" : "NY" }
+{ "_id" : "14733", "city" : "FALCONER", "loc" : [ -79.189499, 42.123915 ], "pop" : 3812, "state" : "NY" }
+{ "_id" : "14735", "city" : "FILLMORE", "loc" : [ -78.10623200000001, 42.463605 ], "pop" : 2463, "state" : "NY" }
+{ "_id" : "14736", "city" : "FINDLEY LAKE", "loc" : [ -79.734908, 42.120401 ], "pop" : 77, "state" : "NY" }
+{ "_id" : "14737", "city" : "FRANKLINVILLE", "loc" : [ -78.440043, 42.338823 ], "pop" : 3965, "state" : "NY" }
+{ "_id" : "14738", "city" : "FREWSBURG", "loc" : [ -79.13179700000001, 42.052753 ], "pop" : 3919, "state" : "NY" }
+{ "_id" : "14739", "city" : "FRIENDSHIP", "loc" : [ -78.13588, 42.190666 ], "pop" : 3214, "state" : "NY" }
+{ "_id" : "14740", "city" : "GERRY", "loc" : [ -79.16486500000001, 42.214728 ], "pop" : 1836, "state" : "NY" }
+{ "_id" : "14741", "city" : "GREAT VALLEY", "loc" : [ -78.620811, 42.208292 ], "pop" : 2217, "state" : "NY" }
+{ "_id" : "14743", "city" : "ISCHUA", "loc" : [ -78.400611, 42.179747 ], "pop" : 2635, "state" : "NY" }
+{ "_id" : "14744", "city" : "HOUGHTON", "loc" : [ -78.109506, 42.411567 ], "pop" : 173, "state" : "NY" }
+{ "_id" : "14747", "city" : "KENNEDY", "loc" : [ -79.096416, 42.150776 ], "pop" : 2719, "state" : "NY" }
+{ "_id" : "14748", "city" : "KILL BUCK", "loc" : [ -78.64260400000001, 42.141005 ], "pop" : 47, "state" : "NY" }
+{ "_id" : "14750", "city" : "LAKEWOOD", "loc" : [ -79.32912399999999, 42.097256 ], "pop" : 5113, "state" : "NY" }
+{ "_id" : "14753", "city" : "LIMESTONE", "loc" : [ -78.631979, 42.063945 ], "pop" : 1981, "state" : "NY" }
+{ "_id" : "14754", "city" : "LITTLE GENESEE", "loc" : [ -78.235056, 42.023964 ], "pop" : 1240, "state" : "NY" }
+{ "_id" : "14755", "city" : "LITTLE VALLEY", "loc" : [ -78.809286, 42.254121 ], "pop" : 2311, "state" : "NY" }
+{ "_id" : "14757", "city" : "MAYVILLE", "loc" : [ -79.496325, 42.240906 ], "pop" : 3378, "state" : "NY" }
+{ "_id" : "14760", "city" : "OLEAN", "loc" : [ -78.423265, 42.0787 ], "pop" : 22055, "state" : "NY" }
+{ "_id" : "14767", "city" : "PANAMA", "loc" : [ -79.48153600000001, 42.056965 ], "pop" : 2437, "state" : "NY" }
+{ "_id" : "14769", "city" : "PORTLAND", "loc" : [ -79.458894, 42.385792 ], "pop" : 2001, "state" : "NY" }
+{ "_id" : "14770", "city" : "PORTVILLE", "loc" : [ -78.33135299999999, 42.027253 ], "pop" : 1743, "state" : "NY" }
+{ "_id" : "14772", "city" : "RANDOLPH", "loc" : [ -78.96003399999999, 42.163143 ], "pop" : 4253, "state" : "NY" }
+{ "_id" : "14775", "city" : "RIPLEY", "loc" : [ -79.712103, 42.248175 ], "pop" : 2876, "state" : "NY" }
+{ "_id" : "14777", "city" : "RUSHFORD", "loc" : [ -78.18670400000001, 42.417216 ], "pop" : 2701, "state" : "NY" }
+{ "_id" : "14779", "city" : "SALAMANCA", "loc" : [ -78.73042, 42.16035 ], "pop" : 8632, "state" : "NY" }
+{ "_id" : "14781", "city" : "SHERMAN", "loc" : [ -79.585742, 42.163124 ], "pop" : 2184, "state" : "NY" }
+{ "_id" : "14782", "city" : "SINCLAIRVILLE", "loc" : [ -79.267297, 42.24548 ], "pop" : 3065, "state" : "NY" }
+{ "_id" : "14784", "city" : "STOCKTON", "loc" : [ -79.375792, 42.318195 ], "pop" : 1894, "state" : "NY" }
+{ "_id" : "14787", "city" : "WESTFIELD", "loc" : [ -79.57264600000001, 42.321977 ], "pop" : 5872, "state" : "NY" }
+{ "_id" : "14801", "city" : "ADDISON", "loc" : [ -77.26602699999999, 42.09825 ], "pop" : 4967, "state" : "NY" }
+{ "_id" : "14802", "city" : "ALFRED", "loc" : [ -77.79295, 42.255165 ], "pop" : 4559, "state" : "NY" }
+{ "_id" : "14803", "city" : "ALFRED STATION", "loc" : [ -77.77808400000001, 42.255799 ], "pop" : 1071, "state" : "NY" }
+{ "_id" : "14804", "city" : "ALMOND", "loc" : [ -77.77796499999999, 42.316036 ], "pop" : 1642, "state" : "NY" }
+{ "_id" : "14805", "city" : "ALPINE", "loc" : [ -76.734775, 42.351014 ], "pop" : 1098, "state" : "NY" }
+{ "_id" : "14806", "city" : "ANDOVER", "loc" : [ -77.792008, 42.157454 ], "pop" : 2489, "state" : "NY" }
+{ "_id" : "14807", "city" : "ARKPORT", "loc" : [ -77.691778, 42.422466 ], "pop" : 2937, "state" : "NY" }
+{ "_id" : "14808", "city" : "ATLANTA", "loc" : [ -77.480091, 42.556269 ], "pop" : 472, "state" : "NY" }
+{ "_id" : "14809", "city" : "WALLACE", "loc" : [ -77.434254, 42.41513 ], "pop" : 2448, "state" : "NY" }
+{ "_id" : "14810", "city" : "VETERANS ADMINIS", "loc" : [ -77.323255, 42.345451 ], "pop" : 12982, "state" : "NY" }
+{ "_id" : "14812", "city" : "BEAVER DAMS", "loc" : [ -76.971953, 42.279763 ], "pop" : 3765, "state" : "NY" }
+{ "_id" : "14813", "city" : "BELMONT", "loc" : [ -78.01103000000001, 42.233409 ], "pop" : 1773, "state" : "NY" }
+{ "_id" : "14814", "city" : "BIG FLATS", "loc" : [ -76.952721, 42.145509 ], "pop" : 1892, "state" : "NY" }
+{ "_id" : "14815", "city" : "BRADFORD", "loc" : [ -77.09134, 42.382517 ], "pop" : 944, "state" : "NY" }
+{ "_id" : "14816", "city" : "BREESPORT", "loc" : [ -76.73612, 42.19392 ], "pop" : 160, "state" : "NY" }
+{ "_id" : "14817", "city" : "BROOKTONDALE", "loc" : [ -76.366844, 42.37653 ], "pop" : 2665, "state" : "NY" }
+{ "_id" : "14818", "city" : "BURDETT", "loc" : [ -76.82921899999999, 42.439442 ], "pop" : 1714, "state" : "NY" }
+{ "_id" : "14819", "city" : "CAMERON", "loc" : [ -77.440341, 42.21284 ], "pop" : 698, "state" : "NY" }
+{ "_id" : "14820", "city" : "CAMERON MILLS", "loc" : [ -77.364976, 42.192547 ], "pop" : 723, "state" : "NY" }
+{ "_id" : "14821", "city" : "CAMPBELL", "loc" : [ -77.206619, 42.238569 ], "pop" : 2966, "state" : "NY" }
+{ "_id" : "14822", "city" : "CANASERAGA", "loc" : [ -77.795374, 42.458504 ], "pop" : 1458, "state" : "NY" }
+{ "_id" : "14823", "city" : "CANISTEO", "loc" : [ -77.58970600000001, 42.263503 ], "pop" : 3945, "state" : "NY" }
+{ "_id" : "14824", "city" : "CAYUTA", "loc" : [ -76.697367, 42.277445 ], "pop" : 599, "state" : "NY" }
+{ "_id" : "14825", "city" : "CHEMUNG", "loc" : [ -76.62022399999999, 42.039243 ], "pop" : 615, "state" : "NY" }
+{ "_id" : "14826", "city" : "COHOCTON", "loc" : [ -77.499763, 42.500315 ], "pop" : 2286, "state" : "NY" }
+{ "_id" : "14830", "city" : "CORNING", "loc" : [ -77.047546, 42.138331 ], "pop" : 19957, "state" : "NY" }
+{ "_id" : "14836", "city" : "DALTON", "loc" : [ -77.928889, 42.544895 ], "pop" : 875, "state" : "NY" }
+{ "_id" : "14837", "city" : "DUNDEE", "loc" : [ -77.002773, 42.505261 ], "pop" : 5125, "state" : "NY" }
+{ "_id" : "14838", "city" : "ERIN", "loc" : [ -76.68194200000001, 42.185898 ], "pop" : 2053, "state" : "NY" }
+{ "_id" : "14839", "city" : "GREENWOOD", "loc" : [ -77.63604100000001, 42.139809 ], "pop" : 927, "state" : "NY" }
+{ "_id" : "14840", "city" : "HAMMONDSPORT", "loc" : [ -77.19770200000001, 42.431217 ], "pop" : 3068, "state" : "NY" }
+{ "_id" : "14841", "city" : "HECTOR", "loc" : [ -76.878597, 42.49658 ], "pop" : 147, "state" : "NY" }
+{ "_id" : "14842", "city" : "HIMROD", "loc" : [ -76.950774, 42.594455 ], "pop" : 726, "state" : "NY" }
+{ "_id" : "14843", "city" : "HORNELL", "loc" : [ -77.656907, 42.327393 ], "pop" : 14311, "state" : "NY" }
+{ "_id" : "14845", "city" : "HORSEHEADS", "loc" : [ -76.83453900000001, 42.180493 ], "pop" : 20799, "state" : "NY" }
+{ "_id" : "14846", "city" : "HUNT", "loc" : [ -77.98183899999999, 42.538821 ], "pop" : 1236, "state" : "NY" }
+{ "_id" : "14847", "city" : "INTERLAKEN", "loc" : [ -76.726798, 42.616524 ], "pop" : 2148, "state" : "NY" }
+{ "_id" : "14850", "city" : "ITHACA COLLEGE", "loc" : [ -76.49291100000001, 42.448497 ], "pop" : 40760, "state" : "NY" }
+{ "_id" : "14853", "city" : "ITHACA", "loc" : [ -76.48870700000001, 42.443087 ], "pop" : 20379, "state" : "NY" }
+{ "_id" : "14855", "city" : "JASPER", "loc" : [ -77.499909, 42.128962 ], "pop" : 870, "state" : "NY" }
+{ "_id" : "14858", "city" : "LINDLEY", "loc" : [ -77.154132, 42.042483 ], "pop" : 1765, "state" : "NY" }
+{ "_id" : "14859", "city" : "LOCKWOOD", "loc" : [ -76.536618, 42.114943 ], "pop" : 951, "state" : "NY" }
+{ "_id" : "14860", "city" : "LODI", "loc" : [ -76.833904, 42.596555 ], "pop" : 1209, "state" : "NY" }
+{ "_id" : "14861", "city" : "LOWMAN", "loc" : [ -76.693005, 42.06938 ], "pop" : 2338, "state" : "NY" }
+{ "_id" : "14864", "city" : "MILLPORT", "loc" : [ -76.83923299999999, 42.258084 ], "pop" : 1432, "state" : "NY" }
+{ "_id" : "14865", "city" : "MONTOUR FALLS", "loc" : [ -76.839581, 42.343678 ], "pop" : 2851, "state" : "NY" }
+{ "_id" : "14867", "city" : "NEWFIELD", "loc" : [ -76.591978, 42.362137 ], "pop" : 5311, "state" : "NY" }
+{ "_id" : "14869", "city" : "ODESSA", "loc" : [ -76.771698, 42.360947 ], "pop" : 1471, "state" : "NY" }
+{ "_id" : "14870", "city" : "PAINTED POST", "loc" : [ -77.11937500000001, 42.170967 ], "pop" : 9269, "state" : "NY" }
+{ "_id" : "14871", "city" : "PINE CITY", "loc" : [ -76.881519, 42.041938 ], "pop" : 4911, "state" : "NY" }
+{ "_id" : "14872", "city" : "PINE VALLEY", "loc" : [ -76.865206, 42.234795 ], "pop" : 252, "state" : "NY" }
+{ "_id" : "14873", "city" : "PRATTSBURG", "loc" : [ -77.282455, 42.526918 ], "pop" : 2534, "state" : "NY" }
+{ "_id" : "14874", "city" : "PULTENEY", "loc" : [ -77.16910799999999, 42.523275 ], "pop" : 504, "state" : "NY" }
+{ "_id" : "14877", "city" : "REXVILLE", "loc" : [ -77.676663, 42.072645 ], "pop" : 539, "state" : "NY" }
+{ "_id" : "14878", "city" : "ROCK STREAM", "loc" : [ -76.936436, 42.448511 ], "pop" : 703, "state" : "NY" }
+{ "_id" : "14879", "city" : "SAVONA", "loc" : [ -77.20834499999999, 42.30407 ], "pop" : 1982, "state" : "NY" }
+{ "_id" : "14880", "city" : "SCIO", "loc" : [ -77.990026, 42.169703 ], "pop" : 2491, "state" : "NY" }
+{ "_id" : "14881", "city" : "SLATERVILLE SPRI", "loc" : [ -76.31567699999999, 42.401119 ], "pop" : 107, "state" : "NY" }
+{ "_id" : "14882", "city" : "LANSING", "loc" : [ -76.53745499999999, 42.564494 ], "pop" : 4043, "state" : "NY" }
+{ "_id" : "14883", "city" : "SPENCER", "loc" : [ -76.489853, 42.246736 ], "pop" : 3829, "state" : "NY" }
+{ "_id" : "14884", "city" : "SWAIN", "loc" : [ -77.88899000000001, 42.477314 ], "pop" : 267, "state" : "NY" }
+{ "_id" : "14885", "city" : "TROUPSBURG", "loc" : [ -77.550208, 42.050083 ], "pop" : 831, "state" : "NY" }
+{ "_id" : "14886", "city" : "TRUMANSBURG", "loc" : [ -76.668145, 42.520987 ], "pop" : 6379, "state" : "NY" }
+{ "_id" : "14888", "city" : "VALOIS", "loc" : [ -76.860879, 42.524304 ], "pop" : 547, "state" : "NY" }
+{ "_id" : "14889", "city" : "VAN ETTEN", "loc" : [ -76.571663, 42.208455 ], "pop" : 1477, "state" : "NY" }
+{ "_id" : "14891", "city" : "WATKINS GLEN", "loc" : [ -76.90215000000001, 42.377121 ], "pop" : 4584, "state" : "NY" }
+{ "_id" : "14892", "city" : "WAVERLY", "loc" : [ -76.53330800000001, 42.017228 ], "pop" : 8262, "state" : "NY" }
+{ "_id" : "14894", "city" : "WELLSBURG", "loc" : [ -76.77231500000001, 42.027317 ], "pop" : 2829, "state" : "NY" }
+{ "_id" : "14895", "city" : "WELLSVILLE", "loc" : [ -77.94190999999999, 42.110757 ], "pop" : 9645, "state" : "NY" }
+{ "_id" : "14897", "city" : "WHITESVILLE", "loc" : [ -77.810615, 42.045586 ], "pop" : 1178, "state" : "NY" }
+{ "_id" : "14898", "city" : "WOODHULL", "loc" : [ -77.420333, 42.073638 ], "pop" : 1318, "state" : "NY" }
+{ "_id" : "14901", "city" : "ELMIRA", "loc" : [ -76.811977, 42.100769 ], "pop" : 19037, "state" : "NY" }
+{ "_id" : "14903", "city" : "ELMIRA HEIGHTS", "loc" : [ -76.84357199999999, 42.130203 ], "pop" : 7918, "state" : "NY" }
+{ "_id" : "14904", "city" : "ELMIRA", "loc" : [ -76.803735, 42.072866 ], "pop" : 18103, "state" : "NY" }
+{ "_id" : "14905", "city" : "ELMIRA", "loc" : [ -76.839686, 42.086919 ], "pop" : 10018, "state" : "NY" }
+{ "_id" : "15001", "city" : "MACARTHUR", "loc" : [ -80.281567, 40.604424 ], "pop" : 36849, "state" : "PA" }
+{ "_id" : "15003", "city" : "FAIROAKS", "loc" : [ -80.21977800000001, 40.595368 ], "pop" : 13449, "state" : "PA" }
+{ "_id" : "15005", "city" : "BADEN", "loc" : [ -80.198471, 40.641595 ], "pop" : 10068, "state" : "PA" }
+{ "_id" : "15007", "city" : "BAKERSTOWN", "loc" : [ -79.93095599999999, 40.647826 ], "pop" : 782, "state" : "PA" }
+{ "_id" : "15009", "city" : "BEAVER", "loc" : [ -80.336528, 40.697184 ], "pop" : 14968, "state" : "PA" }
+{ "_id" : "15010", "city" : "RACINE", "loc" : [ -80.33987999999999, 40.766234 ], "pop" : 30623, "state" : "PA" }
+{ "_id" : "15012", "city" : "ROSTRAVER", "loc" : [ -79.83454, 40.14368 ], "pop" : 18967, "state" : "PA" }
+{ "_id" : "15014", "city" : "BRACKENRIDGE", "loc" : [ -79.74137500000001, 40.608223 ], "pop" : 3674, "state" : "PA" }
+{ "_id" : "15015", "city" : "BRADFORDWOODS", "loc" : [ -80.08230500000001, 40.634175 ], "pop" : 2319, "state" : "PA" }
+{ "_id" : "15017", "city" : "BRIDGEVILLE", "loc" : [ -80.11529299999999, 40.347195 ], "pop" : 12705, "state" : "PA" }
+{ "_id" : "15018", "city" : "BUENA VISTA", "loc" : [ -79.79187400000001, 40.278635 ], "pop" : 1186, "state" : "PA" }
+{ "_id" : "15019", "city" : "BULGER", "loc" : [ -80.36219199999999, 40.405119 ], "pop" : 1118, "state" : "PA" }
+{ "_id" : "15021", "city" : "PARIS", "loc" : [ -80.444485, 40.390114 ], "pop" : 5527, "state" : "PA" }
+{ "_id" : "15022", "city" : "CHARLEROI", "loc" : [ -79.92001999999999, 40.140402 ], "pop" : 11800, "state" : "PA" }
+{ "_id" : "15024", "city" : "CHESWICK", "loc" : [ -79.841002, 40.568117 ], "pop" : 9823, "state" : "PA" }
+{ "_id" : "15025", "city" : "LARGE", "loc" : [ -79.910096, 40.298917 ], "pop" : 17031, "state" : "PA" }
+{ "_id" : "15026", "city" : "CLINTON", "loc" : [ -80.342282, 40.513148 ], "pop" : 2543, "state" : "PA" }
+{ "_id" : "15027", "city" : "CONWAY", "loc" : [ -80.234899, 40.664917 ], "pop" : 2438, "state" : "PA" }
+{ "_id" : "15030", "city" : "CREIGHTON", "loc" : [ -79.78176999999999, 40.582051 ], "pop" : 1761, "state" : "PA" }
+{ "_id" : "15031", "city" : "CUDDY", "loc" : [ -80.16443200000001, 40.360069 ], "pop" : 1037, "state" : "PA" }
+{ "_id" : "15033", "city" : "DONORA", "loc" : [ -79.861858, 40.176821 ], "pop" : 5928, "state" : "PA" }
+{ "_id" : "15034", "city" : "DRAVOSBURG", "loc" : [ -79.889461, 40.352676 ], "pop" : 2377, "state" : "PA" }
+{ "_id" : "15035", "city" : "EAST MC KEESPORT", "loc" : [ -79.80788099999999, 40.383944 ], "pop" : 2698, "state" : "PA" }
+{ "_id" : "15037", "city" : "ELIZABETH", "loc" : [ -79.856842, 40.265575 ], "pop" : 12937, "state" : "PA" }
+{ "_id" : "15042", "city" : "FREEDOM", "loc" : [ -80.214663, 40.683023 ], "pop" : 9416, "state" : "PA" }
+{ "_id" : "15043", "city" : "GEORGETOWN", "loc" : [ -80.49002299999999, 40.574275 ], "pop" : 2810, "state" : "PA" }
+{ "_id" : "15044", "city" : "GIBSONIA", "loc" : [ -79.94430699999999, 40.625233 ], "pop" : 18318, "state" : "PA" }
+{ "_id" : "15045", "city" : "GLASSPORT", "loc" : [ -79.888324, 40.325952 ], "pop" : 5582, "state" : "PA" }
+{ "_id" : "15049", "city" : "HARWICK", "loc" : [ -79.805115, 40.557433 ], "pop" : 1111, "state" : "PA" }
+{ "_id" : "15050", "city" : "HOOKSTOWN", "loc" : [ -80.436268, 40.542929 ], "pop" : 2933, "state" : "PA" }
+{ "_id" : "15051", "city" : "INDIANOLA", "loc" : [ -79.881765, 40.576605 ], "pop" : 1539, "state" : "PA" }
+{ "_id" : "15052", "city" : "INDUSTRY", "loc" : [ -80.415085, 40.667101 ], "pop" : 2908, "state" : "PA" }
+{ "_id" : "15053", "city" : "JOFFRE", "loc" : [ -80.391542, 40.381027 ], "pop" : 1634, "state" : "PA" }
+{ "_id" : "15055", "city" : "LAWRENCE", "loc" : [ -80.144029, 40.311615 ], "pop" : 1933, "state" : "PA" }
+{ "_id" : "15056", "city" : "LEETSDALE", "loc" : [ -80.209874, 40.566165 ], "pop" : 1387, "state" : "PA" }
+{ "_id" : "15057", "city" : "MC DONALD", "loc" : [ -80.256204, 40.369664 ], "pop" : 9077, "state" : "PA" }
+{ "_id" : "15059", "city" : "MIDLAND", "loc" : [ -80.468952, 40.658962 ], "pop" : 6476, "state" : "PA" }
+{ "_id" : "15060", "city" : "MIDWAY", "loc" : [ -80.29209, 40.367974 ], "pop" : 1043, "state" : "PA" }
+{ "_id" : "15061", "city" : "MONACA", "loc" : [ -80.291743, 40.671847 ], "pop" : 13344, "state" : "PA" }
+{ "_id" : "15062", "city" : "MONESSEN", "loc" : [ -79.883526, 40.152379 ], "pop" : 9906, "state" : "PA" }
+{ "_id" : "15063", "city" : "MONONGAHELA", "loc" : [ -79.924127, 40.193728 ], "pop" : 13183, "state" : "PA" }
+{ "_id" : "15064", "city" : "MORGAN", "loc" : [ -80.15406400000001, 40.360433 ], "pop" : 1751, "state" : "PA" }
+{ "_id" : "15065", "city" : "NATRONA", "loc" : [ -79.725621, 40.628862 ], "pop" : 13305, "state" : "PA" }
+{ "_id" : "15066", "city" : "NEW BRIGHTON", "loc" : [ -80.29722, 40.739333 ], "pop" : 12222, "state" : "PA" }
+{ "_id" : "15067", "city" : "NEW EAGLE", "loc" : [ -79.953408, 40.206573 ], "pop" : 2222, "state" : "PA" }
+{ "_id" : "15068", "city" : "ARNOLD", "loc" : [ -79.741547, 40.571179 ], "pop" : 41922, "state" : "PA" }
+{ "_id" : "15071", "city" : "NOBLESTOWN", "loc" : [ -80.20261499999999, 40.428734 ], "pop" : 11012, "state" : "PA" }
+{ "_id" : "15074", "city" : "ROCHESTER", "loc" : [ -80.26031500000001, 40.715745 ], "pop" : 10784, "state" : "PA" }
+{ "_id" : "15076", "city" : "RUSSELLTON", "loc" : [ -79.837102, 40.614344 ], "pop" : 1437, "state" : "PA" }
+{ "_id" : "15077", "city" : "SHIPPINGPORT", "loc" : [ -80.419866, 40.626012 ], "pop" : 227, "state" : "PA" }
+{ "_id" : "15078", "city" : "SLOVAN", "loc" : [ -80.39923899999999, 40.363086 ], "pop" : 1620, "state" : "PA" }
+{ "_id" : "15083", "city" : "SUTERSVILLE", "loc" : [ -79.79222300000001, 40.238207 ], "pop" : 1467, "state" : "PA" }
+{ "_id" : "15084", "city" : "TARENTUM", "loc" : [ -79.78520399999999, 40.618651 ], "pop" : 10752, "state" : "PA" }
+{ "_id" : "15085", "city" : "LEVEL GREEN", "loc" : [ -79.755157, 40.385155 ], "pop" : 3345, "state" : "PA" }
+{ "_id" : "15086", "city" : "WARRENDALE", "loc" : [ -80.08070499999999, 40.664149 ], "pop" : 379, "state" : "PA" }
+{ "_id" : "15089", "city" : "WEST NEWTON", "loc" : [ -79.757976, 40.207549 ], "pop" : 7641, "state" : "PA" }
+{ "_id" : "15090", "city" : "WEXFORD", "loc" : [ -80.064879, 40.612044 ], "pop" : 14960, "state" : "PA" }
+{ "_id" : "15101", "city" : "ALLISON PARK", "loc" : [ -79.96651199999999, 40.569975 ], "pop" : 22474, "state" : "PA" }
+{ "_id" : "15102", "city" : "BETHEL PARK", "loc" : [ -80.039793, 40.320984 ], "pop" : 31160, "state" : "PA" }
+{ "_id" : "15104", "city" : "RANKIN", "loc" : [ -79.864352, 40.406304 ], "pop" : 13915, "state" : "PA" }
+{ "_id" : "15106", "city" : "CARNEGIE", "loc" : [ -80.091532, 40.402941 ], "pop" : 19539, "state" : "PA" }
+{ "_id" : "15108", "city" : "MOON TWP", "loc" : [ -80.18969, 40.513245 ], "pop" : 35285, "state" : "PA" }
+{ "_id" : "15110", "city" : "DUQUESNE", "loc" : [ -79.852244, 40.370449 ], "pop" : 8525, "state" : "PA" }
+{ "_id" : "15112", "city" : "EAST PITTSBURGH", "loc" : [ -79.83889000000001, 40.403577 ], "pop" : 4145, "state" : "PA" }
+{ "_id" : "15116", "city" : "GLENSHAW", "loc" : [ -79.96435099999999, 40.537492 ], "pop" : 16588, "state" : "PA" }
+{ "_id" : "15120", "city" : "MUNHALL", "loc" : [ -79.90419900000001, 40.394171 ], "pop" : 21866, "state" : "PA" }
+{ "_id" : "15122", "city" : "W MIFFLIN FIN", "loc" : [ -79.89429, 40.366535 ], "pop" : 22805, "state" : "PA" }
+{ "_id" : "15126", "city" : "IMPERIAL", "loc" : [ -80.264861, 40.458384 ], "pop" : 3626, "state" : "PA" }
+{ "_id" : "15129", "city" : "LIBRARY", "loc" : [ -80.001144, 40.292199 ], "pop" : 11353, "state" : "PA" }
+{ "_id" : "15131", "city" : "WHITE OAK", "loc" : [ -79.810519, 40.341147 ], "pop" : 9410, "state" : "PA" }
+{ "_id" : "15132", "city" : "MC KEESPORT", "loc" : [ -79.84520000000001, 40.341713 ], "pop" : 27694, "state" : "PA" }
+{ "_id" : "15133", "city" : "MC KEESPORT", "loc" : [ -79.866759, 40.332835 ], "pop" : 7385, "state" : "PA" }
+{ "_id" : "15135", "city" : "BOSTON", "loc" : [ -79.812844, 40.304412 ], "pop" : 5385, "state" : "PA" }
+{ "_id" : "15136", "city" : "MC KEES ROCKS", "loc" : [ -80.08756700000001, 40.471742 ], "pop" : 25092, "state" : "PA" }
+{ "_id" : "15137", "city" : "NORTH VERSAILLES", "loc" : [ -79.812427, 40.376248 ], "pop" : 12237, "state" : "PA" }
+{ "_id" : "15139", "city" : "OAKMONT", "loc" : [ -79.836865, 40.519647 ], "pop" : 6961, "state" : "PA" }
+{ "_id" : "15140", "city" : "PITCAIRN", "loc" : [ -79.776951, 40.404787 ], "pop" : 4083, "state" : "PA" }
+{ "_id" : "15142", "city" : "PRESTO", "loc" : [ -80.12092199999999, 40.384664 ], "pop" : 864, "state" : "PA" }
+{ "_id" : "15143", "city" : "SEWICKLEY", "loc" : [ -80.157848, 40.557031 ], "pop" : 15849, "state" : "PA" }
+{ "_id" : "15144", "city" : "SPRINGDALE", "loc" : [ -79.784447, 40.543999 ], "pop" : 4858, "state" : "PA" }
+{ "_id" : "15145", "city" : "TURTLE CREEK", "loc" : [ -79.822046, 40.41135 ], "pop" : 8157, "state" : "PA" }
+{ "_id" : "15146", "city" : "MONROEVILLE", "loc" : [ -79.76227900000001, 40.429026 ], "pop" : 29228, "state" : "PA" }
+{ "_id" : "15147", "city" : "VERONA", "loc" : [ -79.834535, 40.492727 ], "pop" : 20843, "state" : "PA" }
+{ "_id" : "15148", "city" : "WALL", "loc" : [ -79.803033, 40.393416 ], "pop" : 3074, "state" : "PA" }
+{ "_id" : "15201", "city" : "ARSENAL", "loc" : [ -79.952524, 40.474536 ], "pop" : 15278, "state" : "PA" }
+{ "_id" : "15202", "city" : "BELLEVUE", "loc" : [ -80.06696599999999, 40.501321 ], "pop" : 22168, "state" : "PA" }
+{ "_id" : "15203", "city" : "CARSON", "loc" : [ -79.97755600000001, 40.425439 ], "pop" : 11012, "state" : "PA" }
+{ "_id" : "15204", "city" : "CORLISS", "loc" : [ -80.06105599999999, 40.455569 ], "pop" : 10266, "state" : "PA" }
+{ "_id" : "15205", "city" : "CRAFTON", "loc" : [ -80.073393, 40.438045 ], "pop" : 24562, "state" : "PA" }
+{ "_id" : "15206", "city" : "EAST LIBERTY", "loc" : [ -79.919267, 40.468885 ], "pop" : 37220, "state" : "PA" }
+{ "_id" : "15207", "city" : "HAZELWOOD", "loc" : [ -79.93393500000001, 40.401206 ], "pop" : 15095, "state" : "PA" }
+{ "_id" : "15208", "city" : "HOMEWOOD", "loc" : [ -79.89847399999999, 40.454955 ], "pop" : 16136, "state" : "PA" }
+{ "_id" : "15209", "city" : "MILLVALE", "loc" : [ -79.97401000000001, 40.49718 ], "pop" : 15034, "state" : "PA" }
+{ "_id" : "15210", "city" : "MOUNT OLIVER", "loc" : [ -79.987405, 40.408541 ], "pop" : 35727, "state" : "PA" }
+{ "_id" : "15211", "city" : "MOUNT WASHINGTON", "loc" : [ -80.012156, 40.42908 ], "pop" : 13333, "state" : "PA" }
+{ "_id" : "15212", "city" : "ALLEGHENY", "loc" : [ -80.01312799999999, 40.468873 ], "pop" : 35280, "state" : "PA" }
+{ "_id" : "15213", "city" : "OAKLAND", "loc" : [ -79.95442799999999, 40.44372 ], "pop" : 31142, "state" : "PA" }
+{ "_id" : "15214", "city" : "OBSERVATORY", "loc" : [ -80.01393, 40.481309 ], "pop" : 19981, "state" : "PA" }
+{ "_id" : "15215", "city" : "ASPINWALL", "loc" : [ -79.917513, 40.499225 ], "pop" : 12801, "state" : "PA" }
+{ "_id" : "15216", "city" : "SOUTH HILLS", "loc" : [ -80.03572699999999, 40.399584 ], "pop" : 26700, "state" : "PA" }
+{ "_id" : "15217", "city" : "SQUIRREL HILL", "loc" : [ -79.92497299999999, 40.431852 ], "pop" : 27450, "state" : "PA" }
+{ "_id" : "15218", "city" : "SWISSVALE", "loc" : [ -79.887591, 40.424468 ], "pop" : 16501, "state" : "PA" }
+{ "_id" : "15219", "city" : "UPTOWN", "loc" : [ -79.97722899999999, 40.44539 ], "pop" : 18924, "state" : "PA" }
+{ "_id" : "15220", "city" : "PARKWAY CENTER", "loc" : [ -80.051202, 40.417405 ], "pop" : 19228, "state" : "PA" }
+{ "_id" : "15221", "city" : "WILKINSBURG", "loc" : [ -79.870243, 40.438352 ], "pop" : 39410, "state" : "PA" }
+{ "_id" : "15222", "city" : "DOWNTOWN", "loc" : [ -80.000556, 40.442111 ], "pop" : 1763, "state" : "PA" }
+{ "_id" : "15223", "city" : "ETNA", "loc" : [ -79.95144999999999, 40.50428 ], "pop" : 7261, "state" : "PA" }
+{ "_id" : "15224", "city" : "BLOOMFIELD", "loc" : [ -79.94544500000001, 40.464215 ], "pop" : 14742, "state" : "PA" }
+{ "_id" : "15225", "city" : "NEVILLE ISLAND", "loc" : [ -80.137027, 40.513819 ], "pop" : 1273, "state" : "PA" }
+{ "_id" : "15226", "city" : "BROOKLINE", "loc" : [ -80.015759, 40.394628 ], "pop" : 15607, "state" : "PA" }
+{ "_id" : "15227", "city" : "BRENTWOOD", "loc" : [ -79.97581599999999, 40.37619 ], "pop" : 27563, "state" : "PA" }
+{ "_id" : "15228", "city" : "MOUNT LEBANON", "loc" : [ -80.04318600000001, 40.371326 ], "pop" : 18660, "state" : "PA" }
+{ "_id" : "15229", "city" : "WEST VIEW", "loc" : [ -80.035685, 40.519321 ], "pop" : 15127, "state" : "PA" }
+{ "_id" : "15232", "city" : "SHADYSIDE", "loc" : [ -79.932557, 40.453598 ], "pop" : 10936, "state" : "PA" }
+{ "_id" : "15233", "city" : "KILBUCK", "loc" : [ -80.029965, 40.460425 ], "pop" : 5918, "state" : "PA" }
+{ "_id" : "15234", "city" : "CASTLE SHANNON", "loc" : [ -80.01790699999999, 40.369424 ], "pop" : 14952, "state" : "PA" }
+{ "_id" : "15235", "city" : "PENN HILLS", "loc" : [ -79.826892, 40.4605 ], "pop" : 41997, "state" : "PA" }
+{ "_id" : "15236", "city" : "CASTE VILLAGE", "loc" : [ -79.976894, 40.345244 ], "pop" : 36047, "state" : "PA" }
+{ "_id" : "15237", "city" : "MC KNIGHT", "loc" : [ -80.03493899999999, 40.552238 ], "pop" : 39733, "state" : "PA" }
+{ "_id" : "15238", "city" : "BLAWNOX", "loc" : [ -79.87742299999999, 40.515077 ], "pop" : 10776, "state" : "PA" }
+{ "_id" : "15239", "city" : "PLUM", "loc" : [ -79.734505, 40.477693 ], "pop" : 20793, "state" : "PA" }
+{ "_id" : "15241", "city" : "UPPER SAINT CLAI", "loc" : [ -80.07921, 40.332174 ], "pop" : 20276, "state" : "PA" }
+{ "_id" : "15243", "city" : "CEDARHURST", "loc" : [ -80.072425, 40.373797 ], "pop" : 14242, "state" : "PA" }
+{ "_id" : "15301", "city" : "WASHINGTON", "loc" : [ -80.255957, 40.171687 ], "pop" : 48612, "state" : "PA" }
+{ "_id" : "15310", "city" : "ALEPPO", "loc" : [ -80.45791800000001, 39.824647 ], "pop" : 656, "state" : "PA" }
+{ "_id" : "15311", "city" : "AMITY", "loc" : [ -80.19486499999999, 40.061786 ], "pop" : 1458, "state" : "PA" }
+{ "_id" : "15312", "city" : "AVELLA", "loc" : [ -80.456503, 40.273386 ], "pop" : 3681, "state" : "PA" }
+{ "_id" : "15313", "city" : "BEALLSVILLE", "loc" : [ -80.02505600000001, 40.064503 ], "pop" : 530, "state" : "PA" }
+{ "_id" : "15314", "city" : "BENTLEYVILLE", "loc" : [ -80.006987, 40.118702 ], "pop" : 2673, "state" : "PA" }
+{ "_id" : "15317", "city" : "MC MURRAY", "loc" : [ -80.153153, 40.270743 ], "pop" : 29555, "state" : "PA" }
+{ "_id" : "15320", "city" : "CARMICHAELS", "loc" : [ -79.971007, 39.882548 ], "pop" : 6702, "state" : "PA" }
+{ "_id" : "15321", "city" : "CECIL", "loc" : [ -80.20437, 40.322813 ], "pop" : 3257, "state" : "PA" }
+{ "_id" : "15322", "city" : "CLARKSVILLE", "loc" : [ -80.01238600000001, 39.994064 ], "pop" : 3186, "state" : "PA" }
+{ "_id" : "15323", "city" : "CLAYSVILLE", "loc" : [ -80.385904, 40.137557 ], "pop" : 6836, "state" : "PA" }
+{ "_id" : "15324", "city" : "COKEBURG", "loc" : [ -80.065152, 40.100801 ], "pop" : 854, "state" : "PA" }
+{ "_id" : "15327", "city" : "DILLINER", "loc" : [ -79.977135, 39.755536 ], "pop" : 2407, "state" : "PA" }
+{ "_id" : "15329", "city" : "PROSPERITY", "loc" : [ -80.261257, 40.0224 ], "pop" : 1633, "state" : "PA" }
+{ "_id" : "15330", "city" : "EIGHTY FOUR", "loc" : [ -80.06269500000001, 40.186821 ], "pop" : 5021, "state" : "PA" }
+{ "_id" : "15331", "city" : "ELLSWORTH", "loc" : [ -80.020364, 40.107321 ], "pop" : 1040, "state" : "PA" }
+{ "_id" : "15332", "city" : "FINLEYVILLE", "loc" : [ -79.97530999999999, 40.259301 ], "pop" : 8838, "state" : "PA" }
+{ "_id" : "15333", "city" : "FREDERICKTOWN", "loc" : [ -80.03093699999999, 40.023749 ], "pop" : 770, "state" : "PA" }
+{ "_id" : "15337", "city" : "GRAYSVILLE", "loc" : [ -80.395223, 39.909165 ], "pop" : 468, "state" : "PA" }
+{ "_id" : "15338", "city" : "GREENSBORO", "loc" : [ -79.93992, 39.804482 ], "pop" : 2164, "state" : "PA" }
+{ "_id" : "15340", "city" : "HICKORY", "loc" : [ -80.302508, 40.292511 ], "pop" : 2064, "state" : "PA" }
+{ "_id" : "15341", "city" : "HOLBROOK", "loc" : [ -80.338455, 39.848878 ], "pop" : 1247, "state" : "PA" }
+{ "_id" : "15342", "city" : "HOUSTON", "loc" : [ -80.22093700000001, 40.242492 ], "pop" : 6060, "state" : "PA" }
+{ "_id" : "15344", "city" : "JEFFERSON", "loc" : [ -80.050286, 39.933391 ], "pop" : 2154, "state" : "PA" }
+{ "_id" : "15345", "city" : "MARIANNA", "loc" : [ -80.11450600000001, 40.033067 ], "pop" : 2695, "state" : "PA" }
+{ "_id" : "15346", "city" : "MATHER", "loc" : [ -80.085353, 39.945226 ], "pop" : 2856, "state" : "PA" }
+{ "_id" : "15349", "city" : "DAVISTOWN", "loc" : [ -80.096763, 39.744289 ], "pop" : 1719, "state" : "PA" }
+{ "_id" : "15352", "city" : "NEW FREEPORT", "loc" : [ -80.454228, 39.750728 ], "pop" : 833, "state" : "PA" }
+{ "_id" : "15353", "city" : "NINEVEH", "loc" : [ -80.312809, 39.974328 ], "pop" : 884, "state" : "PA" }
+{ "_id" : "15357", "city" : "RICES LANDING", "loc" : [ -79.98570100000001, 39.943993 ], "pop" : 2095, "state" : "PA" }
+{ "_id" : "15359", "city" : "ROGERSVILLE", "loc" : [ -80.283665, 39.900515 ], "pop" : 313, "state" : "PA" }
+{ "_id" : "15360", "city" : "SCENERY HILL", "loc" : [ -80.091414, 40.099378 ], "pop" : 2027, "state" : "PA" }
+{ "_id" : "15362", "city" : "SPRAGGS", "loc" : [ -80.262186, 39.761038 ], "pop" : 1682, "state" : "PA" }
+{ "_id" : "15363", "city" : "STRABANE", "loc" : [ -80.146156, 40.216914 ], "pop" : 2386, "state" : "PA" }
+{ "_id" : "15364", "city" : "SYCAMORE", "loc" : [ -80.228199, 39.95273 ], "pop" : 395, "state" : "PA" }
+{ "_id" : "15367", "city" : "VENETIA", "loc" : [ -80.059849, 40.275451 ], "pop" : 3568, "state" : "PA" }
+{ "_id" : "15370", "city" : "WAYNESBURG", "loc" : [ -80.179524, 39.891691 ], "pop" : 11246, "state" : "PA" }
+{ "_id" : "15376", "city" : "WEST ALEXANDER", "loc" : [ -80.49776900000001, 40.106514 ], "pop" : 1642, "state" : "PA" }
+{ "_id" : "15377", "city" : "WEST FINLEY", "loc" : [ -80.44080599999999, 39.991397 ], "pop" : 1313, "state" : "PA" }
+{ "_id" : "15380", "city" : "WIND RIDGE", "loc" : [ -80.464665, 39.897106 ], "pop" : 554, "state" : "PA" }
+{ "_id" : "15401", "city" : "UNIONTOWN", "loc" : [ -79.728216, 39.889733 ], "pop" : 34582, "state" : "PA" }
+{ "_id" : "15410", "city" : "ADAH", "loc" : [ -79.890827, 39.883101 ], "pop" : 596, "state" : "PA" }
+{ "_id" : "15411", "city" : "ADDISON", "loc" : [ -79.319334, 39.761195 ], "pop" : 1158, "state" : "PA" }
+{ "_id" : "15412", "city" : "ALLENPORT", "loc" : [ -79.85419400000001, 40.089845 ], "pop" : 665, "state" : "PA" }
+{ "_id" : "15413", "city" : "ALLISON", "loc" : [ -79.875675, 39.982566 ], "pop" : 326, "state" : "PA" }
+{ "_id" : "15417", "city" : "WEST BROWNSVILLE", "loc" : [ -79.920609, 40.02671 ], "pop" : 9133, "state" : "PA" }
+{ "_id" : "15419", "city" : "CALIFORNIA", "loc" : [ -79.895319, 40.062529 ], "pop" : 5778, "state" : "PA" }
+{ "_id" : "15423", "city" : "COAL CENTER", "loc" : [ -79.8839, 40.097272 ], "pop" : 482, "state" : "PA" }
+{ "_id" : "15424", "city" : "LISTONBURG", "loc" : [ -79.351304, 39.821247 ], "pop" : 1998, "state" : "PA" }
+{ "_id" : "15425", "city" : "SOUTH CONNELLSVI", "loc" : [ -79.587838, 40.025037 ], "pop" : 25516, "state" : "PA" }
+{ "_id" : "15427", "city" : "DAISYTOWN", "loc" : [ -79.96703599999999, 40.074349 ], "pop" : 1858, "state" : "PA" }
+{ "_id" : "15428", "city" : "DAWSON", "loc" : [ -79.660224, 40.063767 ], "pop" : 1673, "state" : "PA" }
+{ "_id" : "15431", "city" : "DUNBAR", "loc" : [ -79.64305, 39.972171 ], "pop" : 2947, "state" : "PA" }
+{ "_id" : "15432", "city" : "DUNLEVY", "loc" : [ -79.862703, 40.115077 ], "pop" : 417, "state" : "PA" }
+{ "_id" : "15433", "city" : "EAST MILLSBORO", "loc" : [ -79.966442, 39.982214 ], "pop" : 104, "state" : "PA" }
+{ "_id" : "15434", "city" : "ELCO", "loc" : [ -79.87583600000001, 40.079671 ], "pop" : 373, "state" : "PA" }
+{ "_id" : "15436", "city" : "FAIRCHANCE", "loc" : [ -79.75505099999999, 39.822876 ], "pop" : 1918, "state" : "PA" }
+{ "_id" : "15437", "city" : "FARMINGTON", "loc" : [ -79.583185, 39.806995 ], "pop" : 3296, "state" : "PA" }
+{ "_id" : "15438", "city" : "FAYETTE CITY", "loc" : [ -79.836584, 40.098799 ], "pop" : 921, "state" : "PA" }
+{ "_id" : "15440", "city" : "GIBBON GLADE", "loc" : [ -79.57360300000001, 39.736357 ], "pop" : 94, "state" : "PA" }
+{ "_id" : "15442", "city" : "GRINDSTONE", "loc" : [ -79.840447, 40.008415 ], "pop" : 6843, "state" : "PA" }
+{ "_id" : "15444", "city" : "HILLER", "loc" : [ -79.899936, 40.004496 ], "pop" : 2028, "state" : "PA" }
+{ "_id" : "15445", "city" : "HOPWOOD", "loc" : [ -79.705945, 39.868868 ], "pop" : 3367, "state" : "PA" }
+{ "_id" : "15446", "city" : "INDIAN HEAD", "loc" : [ -79.393387, 40.020195 ], "pop" : 181, "state" : "PA" }
+{ "_id" : "15450", "city" : "LA BELLE", "loc" : [ -79.93702399999999, 39.973829 ], "pop" : 2169, "state" : "PA" }
+{ "_id" : "15451", "city" : "LAKE LYNN", "loc" : [ -79.86184, 39.750065 ], "pop" : 2217, "state" : "PA" }
+{ "_id" : "15456", "city" : "LEMONT FURNACE", "loc" : [ -79.647684, 39.931057 ], "pop" : 1638, "state" : "PA" }
+{ "_id" : "15458", "city" : "LAMBERTON", "loc" : [ -79.859022, 39.890185 ], "pop" : 4703, "state" : "PA" }
+{ "_id" : "15459", "city" : "MARKLEYSBURG", "loc" : [ -79.46003, 39.759723 ], "pop" : 2052, "state" : "PA" }
+{ "_id" : "15461", "city" : "GRAYS LANDING", "loc" : [ -79.89381299999999, 39.83495 ], "pop" : 6033, "state" : "PA" }
+{ "_id" : "15462", "city" : "MELCROFT", "loc" : [ -79.3587, 40.064789 ], "pop" : 77, "state" : "PA" }
+{ "_id" : "15463", "city" : "MERRITTSTOWN", "loc" : [ -79.874447, 39.964854 ], "pop" : 1830, "state" : "PA" }
+{ "_id" : "15464", "city" : "MILL RUN", "loc" : [ -79.462219, 39.967985 ], "pop" : 1972, "state" : "PA" }
+{ "_id" : "15468", "city" : "NEW SALEM", "loc" : [ -79.80407, 39.940747 ], "pop" : 4509, "state" : "PA" }
+{ "_id" : "15469", "city" : "NORMALVILLE", "loc" : [ -79.41506099999999, 40.041793 ], "pop" : 3814, "state" : "PA" }
+{ "_id" : "15470", "city" : "OHIOPYLE", "loc" : [ -79.48846, 39.873202 ], "pop" : 815, "state" : "PA" }
+{ "_id" : "15472", "city" : "OLIVER", "loc" : [ -79.71560100000001, 39.911659 ], "pop" : 2395, "state" : "PA" }
+{ "_id" : "15473", "city" : "LAYTON", "loc" : [ -79.754384, 40.085724 ], "pop" : 1833, "state" : "PA" }
+{ "_id" : "15474", "city" : "POINT MARION", "loc" : [ -79.89898599999999, 39.735124 ], "pop" : 1474, "state" : "PA" }
+{ "_id" : "15475", "city" : "REPUBLIC", "loc" : [ -79.902914, 39.961427 ], "pop" : 641, "state" : "PA" }
+{ "_id" : "15477", "city" : "ROSCOE", "loc" : [ -79.865617, 40.078686 ], "pop" : 802, "state" : "PA" }
+{ "_id" : "15478", "city" : "SMITHFIELD", "loc" : [ -79.81268, 39.792306 ], "pop" : 2163, "state" : "PA" }
+{ "_id" : "15479", "city" : "VAN METER", "loc" : [ -79.73127700000001, 40.144267 ], "pop" : 1009, "state" : "PA" }
+{ "_id" : "15480", "city" : "SMOCK", "loc" : [ -79.76782799999999, 39.996096 ], "pop" : 986, "state" : "PA" }
+{ "_id" : "15482", "city" : "STAR JUNCTION", "loc" : [ -79.755461, 40.083198 ], "pop" : 2803, "state" : "PA" }
+{ "_id" : "15483", "city" : "STOCKDALE", "loc" : [ -79.850103, 40.082567 ], "pop" : 630, "state" : "PA" }
+{ "_id" : "15486", "city" : "VANDERBILT", "loc" : [ -79.69551800000001, 40.024581 ], "pop" : 2706, "state" : "PA" }
+{ "_id" : "15488", "city" : "WALTERSBURG", "loc" : [ -79.78033600000001, 39.990465 ], "pop" : 237, "state" : "PA" }
+{ "_id" : "15490", "city" : "WHITE", "loc" : [ -79.425117, 40.072596 ], "pop" : 138, "state" : "PA" }
+{ "_id" : "15501", "city" : "SOMERSET", "loc" : [ -79.080814, 40.024813 ], "pop" : 18303, "state" : "PA" }
+{ "_id" : "15521", "city" : "ALUM BANK", "loc" : [ -78.620591, 40.185833 ], "pop" : 2175, "state" : "PA" }
+{ "_id" : "15522", "city" : "BEDFORD", "loc" : [ -78.526071, 39.990838 ], "pop" : 10788, "state" : "PA" }
+{ "_id" : "15530", "city" : "BERLIN", "loc" : [ -78.96369199999999, 39.918847 ], "pop" : 4459, "state" : "PA" }
+{ "_id" : "15531", "city" : "BOSWELL", "loc" : [ -79.036179, 40.191807 ], "pop" : 1681, "state" : "PA" }
+{ "_id" : "15533", "city" : "BREEZEWOOD", "loc" : [ -78.245271, 39.990521 ], "pop" : 999, "state" : "PA" }
+{ "_id" : "15534", "city" : "BUFFALO MILLS", "loc" : [ -78.69962, 39.922025 ], "pop" : 445, "state" : "PA" }
+{ "_id" : "15535", "city" : "CLEARVILLE", "loc" : [ -78.43917999999999, 39.853284 ], "pop" : 2304, "state" : "PA" }
+{ "_id" : "15536", "city" : "CRYSTAL SPRING", "loc" : [ -78.225836, 39.919973 ], "pop" : 643, "state" : "PA" }
+{ "_id" : "15537", "city" : "EVERETT", "loc" : [ -78.371315, 40.009808 ], "pop" : 7289, "state" : "PA" }
+{ "_id" : "15538", "city" : "GLENCOE", "loc" : [ -78.827522, 39.909046 ], "pop" : 1350, "state" : "PA" }
+{ "_id" : "15540", "city" : "FORT HILL", "loc" : [ -79.23535, 39.877282 ], "pop" : 305, "state" : "PA" }
+{ "_id" : "15541", "city" : "FRIEDENS", "loc" : [ -78.90329800000001, 40.010997 ], "pop" : 2065, "state" : "PA" }
+{ "_id" : "15542", "city" : "GARRETT", "loc" : [ -79.061561, 39.864581 ], "pop" : 520, "state" : "PA" }
+{ "_id" : "15545", "city" : "HYNDMAN", "loc" : [ -78.733512, 39.804857 ], "pop" : 2732, "state" : "PA" }
+{ "_id" : "15546", "city" : "JENNERS", "loc" : [ -79.054571, 40.147321 ], "pop" : 4586, "state" : "PA" }
+{ "_id" : "15550", "city" : "MANNS CHOICE", "loc" : [ -78.642259, 39.980787 ], "pop" : 1579, "state" : "PA" }
+{ "_id" : "15551", "city" : "MARKLETON", "loc" : [ -79.287851, 39.869096 ], "pop" : 288, "state" : "PA" }
+{ "_id" : "15552", "city" : "MEYERSDALE", "loc" : [ -79.026141, 39.790489 ], "pop" : 9276, "state" : "PA" }
+{ "_id" : "15554", "city" : "NEW PARIS", "loc" : [ -78.58856900000001, 40.118876 ], "pop" : 3982, "state" : "PA" }
+{ "_id" : "15557", "city" : "ROCKWOOD", "loc" : [ -79.18654600000001, 39.937296 ], "pop" : 5125, "state" : "PA" }
+{ "_id" : "15558", "city" : "SALISBURY", "loc" : [ -79.083516, 39.753052 ], "pop" : 716, "state" : "PA" }
+{ "_id" : "15559", "city" : "SCHELLSBURG", "loc" : [ -78.648194, 40.04869 ], "pop" : 1523, "state" : "PA" }
+{ "_id" : "15562", "city" : "SPRINGS", "loc" : [ -79.08895, 39.748895 ], "pop" : 82, "state" : "PA" }
+{ "_id" : "15563", "city" : "STOYSTOWN", "loc" : [ -78.955978, 40.109886 ], "pop" : 2690, "state" : "PA" }
+{ "_id" : "15601", "city" : "GREENSBURG", "loc" : [ -79.542439, 40.307359 ], "pop" : 52186, "state" : "PA" }
+{ "_id" : "15610", "city" : "ACME", "loc" : [ -79.482747, 40.104891 ], "pop" : 3862, "state" : "PA" }
+{ "_id" : "15611", "city" : "ADAMSBURG", "loc" : [ -79.656469, 40.312577 ], "pop" : 255, "state" : "PA" }
+{ "_id" : "15612", "city" : "ALVERTON", "loc" : [ -79.55860800000001, 40.127866 ], "pop" : 2166, "state" : "PA" }
+{ "_id" : "15613", "city" : "APOLLO", "loc" : [ -79.577158, 40.556481 ], "pop" : 18588, "state" : "PA" }
+{ "_id" : "15615", "city" : "ARDARA", "loc" : [ -79.73353299999999, 40.362993 ], "pop" : 450, "state" : "PA" }
+{ "_id" : "15616", "city" : "ARMBRUST", "loc" : [ -79.553884, 40.236097 ], "pop" : 500, "state" : "PA" }
+{ "_id" : "15617", "city" : "ARONA", "loc" : [ -79.659104, 40.26799 ], "pop" : 397, "state" : "PA" }
+{ "_id" : "15618", "city" : "AVONMORE", "loc" : [ -79.485264, 40.522125 ], "pop" : 3306, "state" : "PA" }
+{ "_id" : "15620", "city" : "BRADENVILLE", "loc" : [ -79.309679, 40.296094 ], "pop" : 139, "state" : "PA" }
+{ "_id" : "15622", "city" : "CHAMPION", "loc" : [ -79.324719, 40.043976 ], "pop" : 109, "state" : "PA" }
+{ "_id" : "15625", "city" : "DARRAGH", "loc" : [ -79.67803600000001, 40.260377 ], "pop" : 159, "state" : "PA" }
+{ "_id" : "15626", "city" : "DELMONT", "loc" : [ -79.57638, 40.413901 ], "pop" : 2852, "state" : "PA" }
+{ "_id" : "15627", "city" : "DERRY", "loc" : [ -79.33258499999999, 40.334931 ], "pop" : 10610, "state" : "PA" }
+{ "_id" : "15628", "city" : "DONEGAL", "loc" : [ -79.38104300000001, 40.099613 ], "pop" : 584, "state" : "PA" }
+{ "_id" : "15631", "city" : "EVERSON", "loc" : [ -79.587277, 40.091144 ], "pop" : 868, "state" : "PA" }
+{ "_id" : "15632", "city" : "EXPORT", "loc" : [ -79.61102099999999, 40.425185 ], "pop" : 8364, "state" : "PA" }
+{ "_id" : "15634", "city" : "GRAPEVILLE", "loc" : [ -79.603189, 40.303804 ], "pop" : 683, "state" : "PA" }
+{ "_id" : "15636", "city" : "HARRISON CITY", "loc" : [ -79.679754, 40.372455 ], "pop" : 12018, "state" : "PA" }
+{ "_id" : "15637", "city" : "HERMINIE", "loc" : [ -79.717164, 40.245485 ], "pop" : 3820, "state" : "PA" }
+{ "_id" : "15639", "city" : "HUNKER", "loc" : [ -79.582364, 40.214947 ], "pop" : 1592, "state" : "PA" }
+{ "_id" : "15641", "city" : "HYDE PARK", "loc" : [ -79.589884, 40.631102 ], "pop" : 542, "state" : "PA" }
+{ "_id" : "15642", "city" : "NORTH HUNTINGDON", "loc" : [ -79.723855, 40.319227 ], "pop" : 36415, "state" : "PA" }
+{ "_id" : "15644", "city" : "JEANNETTE", "loc" : [ -79.614412, 40.32947 ], "pop" : 20989, "state" : "PA" }
+{ "_id" : "15646", "city" : "JONES MILLS", "loc" : [ -79.339933, 40.07977 ], "pop" : 226, "state" : "PA" }
+{ "_id" : "15647", "city" : "LARIMER", "loc" : [ -79.736627, 40.351842 ], "pop" : 1731, "state" : "PA" }
+{ "_id" : "15650", "city" : "LATROBE", "loc" : [ -79.41027800000001, 40.292625 ], "pop" : 29529, "state" : "PA" }
+{ "_id" : "15655", "city" : "LAUGHLINTOWN", "loc" : [ -79.18058000000001, 40.208025 ], "pop" : 436, "state" : "PA" }
+{ "_id" : "15656", "city" : "LEECHBURG", "loc" : [ -79.62010100000001, 40.634398 ], "pop" : 11552, "state" : "PA" }
+{ "_id" : "15658", "city" : "WILPEN", "loc" : [ -79.236666, 40.245133 ], "pop" : 9229, "state" : "PA" }
+{ "_id" : "15661", "city" : "LOYALHANNA", "loc" : [ -79.344157, 40.30199 ], "pop" : 564, "state" : "PA" }
+{ "_id" : "15663", "city" : "MADISON", "loc" : [ -79.675978, 40.246669 ], "pop" : 539, "state" : "PA" }
+{ "_id" : "15665", "city" : "MANOR", "loc" : [ -79.671221, 40.33822 ], "pop" : 3848, "state" : "PA" }
+{ "_id" : "15666", "city" : "MOUNT PLEASANT", "loc" : [ -79.513383, 40.174179 ], "pop" : 15336, "state" : "PA" }
+{ "_id" : "15668", "city" : "MURRYSVILLE", "loc" : [ -79.68415400000001, 40.446674 ], "pop" : 10965, "state" : "PA" }
+{ "_id" : "15670", "city" : "NEW ALEXANDRIA", "loc" : [ -79.39659399999999, 40.398112 ], "pop" : 2658, "state" : "PA" }
+{ "_id" : "15671", "city" : "NEW DERRY", "loc" : [ -79.30086300000001, 40.333334 ], "pop" : 2950, "state" : "PA" }
+{ "_id" : "15672", "city" : "NEW STANTON", "loc" : [ -79.61818700000001, 40.223345 ], "pop" : 3237, "state" : "PA" }
+{ "_id" : "15675", "city" : "PENN", "loc" : [ -79.641336, 40.330081 ], "pop" : 619, "state" : "PA" }
+{ "_id" : "15677", "city" : "RECTOR", "loc" : [ -79.247331, 40.186444 ], "pop" : 376, "state" : "PA" }
+{ "_id" : "15678", "city" : "RILLTON", "loc" : [ -79.728211, 40.282454 ], "pop" : 1050, "state" : "PA" }
+{ "_id" : "15679", "city" : "RUFFS DALE", "loc" : [ -79.627743, 40.158458 ], "pop" : 6385, "state" : "PA" }
+{ "_id" : "15681", "city" : "SALTSBURG", "loc" : [ -79.44284399999999, 40.479239 ], "pop" : 3922, "state" : "PA" }
+{ "_id" : "15683", "city" : "SCOTTDALE", "loc" : [ -79.593017, 40.102948 ], "pop" : 6132, "state" : "PA" }
+{ "_id" : "15684", "city" : "SLICKVILLE", "loc" : [ -79.506654, 40.465347 ], "pop" : 318, "state" : "PA" }
+{ "_id" : "15686", "city" : "SPRING CHURCH", "loc" : [ -79.454487, 40.615329 ], "pop" : 1291, "state" : "PA" }
+{ "_id" : "15687", "city" : "STAHLSTOWN", "loc" : [ -79.34447299999999, 40.138593 ], "pop" : 2555, "state" : "PA" }
+{ "_id" : "15688", "city" : "TARRS", "loc" : [ -79.566101, 40.161915 ], "pop" : 385, "state" : "PA" }
+{ "_id" : "15690", "city" : "PARK", "loc" : [ -79.56553099999999, 40.605883 ], "pop" : 9409, "state" : "PA" }
+{ "_id" : "15692", "city" : "WESTMORELAND CIT", "loc" : [ -79.547696, 40.276802 ], "pop" : 2293, "state" : "PA" }
+{ "_id" : "15697", "city" : "YOUNGWOOD", "loc" : [ -79.582291, 40.239482 ], "pop" : 3319, "state" : "PA" }
+{ "_id" : "15698", "city" : "YUKON", "loc" : [ -79.68494099999999, 40.215529 ], "pop" : 726, "state" : "PA" }
+{ "_id" : "15701", "city" : "INDIANA", "loc" : [ -79.15959599999999, 40.619628 ], "pop" : 28962, "state" : "PA" }
+{ "_id" : "15711", "city" : "ANITA", "loc" : [ -78.96663700000001, 41.001806 ], "pop" : 586, "state" : "PA" }
+{ "_id" : "15713", "city" : "AULTMAN", "loc" : [ -79.219791, 40.540083 ], "pop" : 162, "state" : "PA" }
+{ "_id" : "15714", "city" : "BARNESBORO", "loc" : [ -78.777058, 40.673307 ], "pop" : 3878, "state" : "PA" }
+{ "_id" : "15716", "city" : "BLACK LICK", "loc" : [ -79.193231, 40.466905 ], "pop" : 1100, "state" : "PA" }
+{ "_id" : "15717", "city" : "BLAIRSVILLE", "loc" : [ -79.25332899999999, 40.441262 ], "pop" : 9738, "state" : "PA" }
+{ "_id" : "15720", "city" : "BRUSH VALLEY", "loc" : [ -79.05876499999999, 40.528565 ], "pop" : 1811, "state" : "PA" }
+{ "_id" : "15721", "city" : "BURNSIDE", "loc" : [ -78.78648800000001, 40.813431 ], "pop" : 350, "state" : "PA" }
+{ "_id" : "15722", "city" : "CARROLLTOWN", "loc" : [ -78.703676, 40.589054 ], "pop" : 2644, "state" : "PA" }
+{ "_id" : "15724", "city" : "CHERRY TREE", "loc" : [ -78.847357, 40.755387 ], "pop" : 2220, "state" : "PA" }
+{ "_id" : "15725", "city" : "CLARKSBURG", "loc" : [ -79.367676, 40.503933 ], "pop" : 1369, "state" : "PA" }
+{ "_id" : "15728", "city" : "CLYMER", "loc" : [ -79.01186300000001, 40.668811 ], "pop" : 1499, "state" : "PA" }
+{ "_id" : "15729", "city" : "COMMODORE", "loc" : [ -78.913371, 40.701588 ], "pop" : 3259, "state" : "PA" }
+{ "_id" : "15730", "city" : "COOLSPRING", "loc" : [ -78.922015, 40.951816 ], "pop" : 44, "state" : "PA" }
+{ "_id" : "15732", "city" : "CREEKSIDE", "loc" : [ -79.201396, 40.719892 ], "pop" : 2198, "state" : "PA" }
+{ "_id" : "15739", "city" : "ERNEST", "loc" : [ -79.096937, 40.704255 ], "pop" : 3841, "state" : "PA" }
+{ "_id" : "15742", "city" : "GLEN CAMPBELL", "loc" : [ -78.855538, 40.850766 ], "pop" : 1308, "state" : "PA" }
+{ "_id" : "15744", "city" : "HAMILTON", "loc" : [ -79.093987, 40.921432 ], "pop" : 0, "state" : "PA" }
+{ "_id" : "15747", "city" : "HOME", "loc" : [ -79.16408199999999, 40.783441 ], "pop" : 926, "state" : "PA" }
+{ "_id" : "15748", "city" : "GRACETON", "loc" : [ -79.183942, 40.538375 ], "pop" : 3677, "state" : "PA" }
+{ "_id" : "15753", "city" : "LA JOSE", "loc" : [ -78.62336999999999, 40.830118 ], "pop" : 1119, "state" : "PA" }
+{ "_id" : "15754", "city" : "LUCERNEMINES", "loc" : [ -79.157349, 40.545313 ], "pop" : 3227, "state" : "PA" }
+{ "_id" : "15757", "city" : "MC GEES MILLS", "loc" : [ -78.72038999999999, 40.889251 ], "pop" : 1792, "state" : "PA" }
+{ "_id" : "15758", "city" : "MARCHAND", "loc" : [ -79.045151, 40.875411 ], "pop" : 1302, "state" : "PA" }
+{ "_id" : "15759", "city" : "MARION CENTER", "loc" : [ -79.02524, 40.78135 ], "pop" : 2085, "state" : "PA" }
+{ "_id" : "15760", "city" : "MARSTELLER", "loc" : [ -78.813356, 40.65004 ], "pop" : 959, "state" : "PA" }
+{ "_id" : "15762", "city" : "NICKTOWN", "loc" : [ -78.81139400000001, 40.601623 ], "pop" : 1395, "state" : "PA" }
+{ "_id" : "15763", "city" : "NORTHPOINT", "loc" : [ -79.125657, 40.903703 ], "pop" : 49, "state" : "PA" }
+{ "_id" : "15764", "city" : "OLIVEBURG", "loc" : [ -79.038197, 40.996379 ], "pop" : 8, "state" : "PA" }
+{ "_id" : "15765", "city" : "PENN RUN", "loc" : [ -78.971597, 40.626825 ], "pop" : 4258, "state" : "PA" }
+{ "_id" : "15767", "city" : "PUNXSUTAWNEY", "loc" : [ -78.968056, 40.947937 ], "pop" : 12377, "state" : "PA" }
+{ "_id" : "15770", "city" : "RINGGOLD", "loc" : [ -79.176581, 40.999731 ], "pop" : 692, "state" : "PA" }
+{ "_id" : "15771", "city" : "ROCHESTER MILLS", "loc" : [ -78.997985, 40.819482 ], "pop" : 253, "state" : "PA" }
+{ "_id" : "15772", "city" : "ROSSITER", "loc" : [ -78.94135300000001, 40.884553 ], "pop" : 1858, "state" : "PA" }
+{ "_id" : "15773", "city" : "SAINT BENEDICT", "loc" : [ -78.738332, 40.611845 ], "pop" : 1544, "state" : "PA" }
+{ "_id" : "15774", "city" : "SHELOCTA", "loc" : [ -79.31907, 40.638787 ], "pop" : 7854, "state" : "PA" }
+{ "_id" : "15775", "city" : "SPANGLER", "loc" : [ -78.76906099999999, 40.648082 ], "pop" : 2851, "state" : "PA" }
+{ "_id" : "15776", "city" : "SPRANKLE MILLS", "loc" : [ -79.077809, 41.01846 ], "pop" : 980, "state" : "PA" }
+{ "_id" : "15777", "city" : "STARFORD", "loc" : [ -78.980317, 40.700971 ], "pop" : 850, "state" : "PA" }
+{ "_id" : "15778", "city" : "TIMBLIN", "loc" : [ -79.20135000000001, 40.968387 ], "pop" : 178, "state" : "PA" }
+{ "_id" : "15780", "city" : "VALIER", "loc" : [ -79.083263, 40.922851 ], "pop" : 44, "state" : "PA" }
+{ "_id" : "15784", "city" : "WORTHVILLE", "loc" : [ -79.138685, 41.023767 ], "pop" : 65, "state" : "PA" }
+{ "_id" : "15801", "city" : "DU BOIS", "loc" : [ -78.752698, 41.126039 ], "pop" : 17345, "state" : "PA" }
+{ "_id" : "15821", "city" : "BENEZETT", "loc" : [ -78.35762099999999, 41.325318 ], "pop" : 243, "state" : "PA" }
+{ "_id" : "15823", "city" : "BROCKPORT", "loc" : [ -78.712829, 41.28217 ], "pop" : 1646, "state" : "PA" }
+{ "_id" : "15824", "city" : "BROCKWAY", "loc" : [ -78.81156799999999, 41.240564 ], "pop" : 6361, "state" : "PA" }
+{ "_id" : "15825", "city" : "HAZEN", "loc" : [ -79.06410099999999, 41.159986 ], "pop" : 9303, "state" : "PA" }
+{ "_id" : "15827", "city" : "BYRNEDALE", "loc" : [ -78.505126, 41.286459 ], "pop" : 1892, "state" : "PA" }
+{ "_id" : "15828", "city" : "CLARINGTON", "loc" : [ -79.146557, 41.323272 ], "pop" : 311, "state" : "PA" }
+{ "_id" : "15829", "city" : "CORSICA", "loc" : [ -79.175567, 41.182983 ], "pop" : 1070, "state" : "PA" }
+{ "_id" : "15832", "city" : "DRIFTWOOD", "loc" : [ -78.163194, 41.376396 ], "pop" : 526, "state" : "PA" }
+{ "_id" : "15834", "city" : "EMPORIUM", "loc" : [ -78.25360999999999, 41.517689 ], "pop" : 5219, "state" : "PA" }
+{ "_id" : "15840", "city" : "FALLS CREEK", "loc" : [ -78.812791, 41.145505 ], "pop" : 1422, "state" : "PA" }
+{ "_id" : "15845", "city" : "JOHNSONBURG", "loc" : [ -78.67825999999999, 41.492823 ], "pop" : 3350, "state" : "PA" }
+{ "_id" : "15846", "city" : "KERSEY", "loc" : [ -78.60151999999999, 41.356271 ], "pop" : 3392, "state" : "PA" }
+{ "_id" : "15848", "city" : "LUTHERSBURG", "loc" : [ -78.74275799999999, 41.05321 ], "pop" : 2249, "state" : "PA" }
+{ "_id" : "15849", "city" : "PENFIELD", "loc" : [ -78.579111, 41.208519 ], "pop" : 1395, "state" : "PA" }
+{ "_id" : "15851", "city" : "REYNOLDSVILLE", "loc" : [ -78.896147, 41.062935 ], "pop" : 8758, "state" : "PA" }
+{ "_id" : "15853", "city" : "PORTLAND MILLS", "loc" : [ -78.729715, 41.431566 ], "pop" : 7419, "state" : "PA" }
+{ "_id" : "15856", "city" : "ROCKTON", "loc" : [ -78.657662, 41.080571 ], "pop" : 833, "state" : "PA" }
+{ "_id" : "15857", "city" : "SAINT MARYS", "loc" : [ -78.550533, 41.428949 ], "pop" : 14020, "state" : "PA" }
+{ "_id" : "15860", "city" : "SIGEL", "loc" : [ -79.053957, 41.309921 ], "pop" : 1103, "state" : "PA" }
+{ "_id" : "15861", "city" : "SINNAMAHONING", "loc" : [ -78.06607, 41.376197 ], "pop" : 168, "state" : "PA" }
+{ "_id" : "15864", "city" : "SUMMERVILLE", "loc" : [ -79.172583, 41.105822 ], "pop" : 1749, "state" : "PA" }
+{ "_id" : "15865", "city" : "SYKESVILLE", "loc" : [ -78.819508, 41.05137 ], "pop" : 1387, "state" : "PA" }
+{ "_id" : "15868", "city" : "WEEDVILLE", "loc" : [ -78.495165, 41.268502 ], "pop" : 195, "state" : "PA" }
+{ "_id" : "15870", "city" : "WILCOX", "loc" : [ -78.682295, 41.573471 ], "pop" : 1870, "state" : "PA" }
+{ "_id" : "15901", "city" : "JOHNSTOWN", "loc" : [ -78.91408, 40.325957 ], "pop" : 6649, "state" : "PA" }
+{ "_id" : "15902", "city" : "JOHNSTOWN", "loc" : [ -78.896905, 40.307787 ], "pop" : 16012, "state" : "PA" }
+{ "_id" : "15904", "city" : "JOHNSTOWN", "loc" : [ -78.86538299999999, 40.285026 ], "pop" : 16858, "state" : "PA" }
+{ "_id" : "15905", "city" : "JOHNSTOWN", "loc" : [ -78.943006, 40.307188 ], "pop" : 22509, "state" : "PA" }
+{ "_id" : "15906", "city" : "JOHNSTOWN", "loc" : [ -78.938317, 40.352193 ], "pop" : 13249, "state" : "PA" }
+{ "_id" : "15909", "city" : "JOHNSTOWN", "loc" : [ -78.862284, 40.387965 ], "pop" : 7944, "state" : "PA" }
+{ "_id" : "15920", "city" : "ARMAGH", "loc" : [ -79.01305499999999, 40.442452 ], "pop" : 2839, "state" : "PA" }
+{ "_id" : "15923", "city" : "BOLIVAR", "loc" : [ -79.160546, 40.367289 ], "pop" : 2043, "state" : "PA" }
+{ "_id" : "15924", "city" : "CAIRNBROOK", "loc" : [ -78.81008199999999, 40.114472 ], "pop" : 2178, "state" : "PA" }
+{ "_id" : "15926", "city" : "CENTRAL CITY", "loc" : [ -78.844753, 40.091257 ], "pop" : 2886, "state" : "PA" }
+{ "_id" : "15927", "city" : "COLVER", "loc" : [ -78.778432, 40.541086 ], "pop" : 1531, "state" : "PA" }
+{ "_id" : "15928", "city" : "DAVIDSVILLE", "loc" : [ -78.936333, 40.224451 ], "pop" : 244, "state" : "PA" }
+{ "_id" : "15931", "city" : "EBENSBURG", "loc" : [ -78.726294, 40.480105 ], "pop" : 9386, "state" : "PA" }
+{ "_id" : "15935", "city" : "HOLLSOPPLE", "loc" : [ -78.951471, 40.234301 ], "pop" : 7012, "state" : "PA" }
+{ "_id" : "15936", "city" : "HOOVERSVILLE", "loc" : [ -78.91407100000001, 40.148776 ], "pop" : 731, "state" : "PA" }
+{ "_id" : "15938", "city" : "LILLY", "loc" : [ -78.62306, 40.423844 ], "pop" : 2252, "state" : "PA" }
+{ "_id" : "15940", "city" : "LORETTO", "loc" : [ -78.629357, 40.510484 ], "pop" : 2771, "state" : "PA" }
+{ "_id" : "15942", "city" : "MINERAL POINT", "loc" : [ -78.835201, 40.379253 ], "pop" : 420, "state" : "PA" }
+{ "_id" : "15943", "city" : "NANTY GLO", "loc" : [ -78.837504, 40.470435 ], "pop" : 4680, "state" : "PA" }
+{ "_id" : "15944", "city" : "NEW FLORENCE", "loc" : [ -79.09680299999999, 40.382266 ], "pop" : 3949, "state" : "PA" }
+{ "_id" : "15945", "city" : "PARKHILL", "loc" : [ -78.869432, 40.359385 ], "pop" : 120, "state" : "PA" }
+{ "_id" : "15946", "city" : "PURITAN", "loc" : [ -78.671753, 40.384201 ], "pop" : 8160, "state" : "PA" }
+{ "_id" : "15949", "city" : "ROBINSON", "loc" : [ -79.137928, 40.407655 ], "pop" : 829, "state" : "PA" }
+{ "_id" : "15951", "city" : "SAINT MICHAEL", "loc" : [ -78.782999, 40.336248 ], "pop" : 1425, "state" : "PA" }
+{ "_id" : "15952", "city" : "SALIX", "loc" : [ -78.74370399999999, 40.300627 ], "pop" : 6215, "state" : "PA" }
+{ "_id" : "15953", "city" : "SEANOR", "loc" : [ -78.890897, 40.231191 ], "pop" : 18, "state" : "PA" }
+{ "_id" : "15954", "city" : "SEWARD", "loc" : [ -79.023224, 40.409907 ], "pop" : 1348, "state" : "PA" }
+{ "_id" : "15955", "city" : "SIDMAN", "loc" : [ -78.745966, 40.329873 ], "pop" : 1235, "state" : "PA" }
+{ "_id" : "15956", "city" : "SOUTH FORK", "loc" : [ -78.78867099999999, 40.362877 ], "pop" : 2497, "state" : "PA" }
+{ "_id" : "15957", "city" : "STRONGSTOWN", "loc" : [ -78.912961, 40.56279 ], "pop" : 678, "state" : "PA" }
+{ "_id" : "15958", "city" : "SUMMERHILL", "loc" : [ -78.755979, 40.388959 ], "pop" : 2215, "state" : "PA" }
+{ "_id" : "15960", "city" : "TWIN ROCKS", "loc" : [ -78.860488, 40.518254 ], "pop" : 1535, "state" : "PA" }
+{ "_id" : "15961", "city" : "VINTONDALE", "loc" : [ -78.94267000000001, 40.493949 ], "pop" : 2141, "state" : "PA" }
+{ "_id" : "15963", "city" : "WINDBER", "loc" : [ -78.83028899999999, 40.228695 ], "pop" : 11421, "state" : "PA" }
+{ "_id" : "16001", "city" : "BON AIRE", "loc" : [ -79.902717, 40.862096 ], "pop" : 55158, "state" : "PA" }
+{ "_id" : "16020", "city" : "BOYERS", "loc" : [ -79.904692, 41.109205 ], "pop" : 974, "state" : "PA" }
+{ "_id" : "16022", "city" : "BRUIN", "loc" : [ -79.729051, 41.057078 ], "pop" : 637, "state" : "PA" }
+{ "_id" : "16023", "city" : "MARWOOD", "loc" : [ -79.77085099999999, 40.779723 ], "pop" : 3483, "state" : "PA" }
+{ "_id" : "16025", "city" : "CHICORA", "loc" : [ -79.74623699999999, 40.945768 ], "pop" : 4673, "state" : "PA" }
+{ "_id" : "16028", "city" : "EAST BRADY", "loc" : [ -79.63018700000001, 40.974373 ], "pop" : 2069, "state" : "PA" }
+{ "_id" : "16030", "city" : "EAU CLAIRE", "loc" : [ -79.79809299999999, 41.13478 ], "pop" : 371, "state" : "PA" }
+{ "_id" : "16033", "city" : "EVANS CITY", "loc" : [ -80.059195, 40.780795 ], "pop" : 6859, "state" : "PA" }
+{ "_id" : "16034", "city" : "FENELTON", "loc" : [ -79.73715199999999, 40.855464 ], "pop" : 1753, "state" : "PA" }
+{ "_id" : "16036", "city" : "FOXBURG", "loc" : [ -79.653443, 41.160239 ], "pop" : 988, "state" : "PA" }
+{ "_id" : "16037", "city" : "HARMONY", "loc" : [ -80.13811699999999, 40.849646 ], "pop" : 2049, "state" : "PA" }
+{ "_id" : "16038", "city" : "HARRISVILLE", "loc" : [ -79.97963900000001, 41.163087 ], "pop" : 3617, "state" : "PA" }
+{ "_id" : "16040", "city" : "HILLIARDS", "loc" : [ -79.821456, 41.100894 ], "pop" : 1092, "state" : "PA" }
+{ "_id" : "16041", "city" : "KARNS CITY", "loc" : [ -79.71601699999999, 41.002193 ], "pop" : 3032, "state" : "PA" }
+{ "_id" : "16045", "city" : "LYNDORA", "loc" : [ -79.921401, 40.855071 ], "pop" : 2232, "state" : "PA" }
+{ "_id" : "16046", "city" : "MARS", "loc" : [ -80.035769, 40.700514 ], "pop" : 10192, "state" : "PA" }
+{ "_id" : "16049", "city" : "PARKER", "loc" : [ -79.68888800000001, 41.100891 ], "pop" : 3131, "state" : "PA" }
+{ "_id" : "16050", "city" : "PETROLIA", "loc" : [ -79.771069, 41.044208 ], "pop" : 491, "state" : "PA" }
+{ "_id" : "16051", "city" : "PORTERSVILLE", "loc" : [ -80.172965, 40.948651 ], "pop" : 3642, "state" : "PA" }
+{ "_id" : "16052", "city" : "PROSPECT", "loc" : [ -80.067903, 40.904941 ], "pop" : 2224, "state" : "PA" }
+{ "_id" : "16053", "city" : "RENFREW", "loc" : [ -79.97700399999999, 40.810003 ], "pop" : 3180, "state" : "PA" }
+{ "_id" : "16055", "city" : "SARVER", "loc" : [ -79.74243, 40.714285 ], "pop" : 8370, "state" : "PA" }
+{ "_id" : "16056", "city" : "SAXONBURG", "loc" : [ -79.835222, 40.736099 ], "pop" : 4693, "state" : "PA" }
+{ "_id" : "16057", "city" : "SLIPPERY ROCK", "loc" : [ -80.046847, 41.045412 ], "pop" : 12443, "state" : "PA" }
+{ "_id" : "16059", "city" : "VALENCIA", "loc" : [ -79.92352700000001, 40.701831 ], "pop" : 6437, "state" : "PA" }
+{ "_id" : "16061", "city" : "WEST SUNBURY", "loc" : [ -79.875134, 41.002601 ], "pop" : 1999, "state" : "PA" }
+{ "_id" : "16063", "city" : "ZELIENOPLE", "loc" : [ -80.128564, 40.73136 ], "pop" : 18300, "state" : "PA" }
+{ "_id" : "16101", "city" : "NEW CASTLE", "loc" : [ -80.32844900000001, 40.99222 ], "pop" : 36694, "state" : "PA" }
+{ "_id" : "16102", "city" : "NEW CASTLE", "loc" : [ -80.390704, 40.967745 ], "pop" : 7186, "state" : "PA" }
+{ "_id" : "16105", "city" : "NESHANNOCK", "loc" : [ -80.342191, 41.033502 ], "pop" : 14292, "state" : "PA" }
+{ "_id" : "16110", "city" : "ADAMSVILLE", "loc" : [ -80.376544, 41.506677 ], "pop" : 287, "state" : "PA" }
+{ "_id" : "16111", "city" : "ATLANTIC", "loc" : [ -80.28625099999999, 41.533313 ], "pop" : 2390, "state" : "PA" }
+{ "_id" : "16112", "city" : "BESSEMER", "loc" : [ -80.493689, 40.975493 ], "pop" : 1611, "state" : "PA" }
+{ "_id" : "16114", "city" : "CLARKS MILLS", "loc" : [ -80.175223, 41.385141 ], "pop" : 1351, "state" : "PA" }
+{ "_id" : "16115", "city" : "DARLINGTON", "loc" : [ -80.455611, 40.796839 ], "pop" : 3397, "state" : "PA" }
+{ "_id" : "16116", "city" : "EDINBURG", "loc" : [ -80.463178, 41.027614 ], "pop" : 3240, "state" : "PA" }
+{ "_id" : "16117", "city" : "ELLPORT", "loc" : [ -80.27460600000001, 40.859024 ], "pop" : 19193, "state" : "PA" }
+{ "_id" : "16120", "city" : "ENON VALLEY", "loc" : [ -80.46118199999999, 40.8721 ], "pop" : 2421, "state" : "PA" }
+{ "_id" : "16121", "city" : "FARRELL", "loc" : [ -80.49444200000001, 41.210995 ], "pop" : 7619, "state" : "PA" }
+{ "_id" : "16123", "city" : "FOMBELL", "loc" : [ -80.207312, 40.812527 ], "pop" : 2611, "state" : "PA" }
+{ "_id" : "16124", "city" : "FREDONIA", "loc" : [ -80.26987099999999, 41.324141 ], "pop" : 1772, "state" : "PA" }
+{ "_id" : "16125", "city" : "SHENANGO", "loc" : [ -80.38034399999999, 41.399403 ], "pop" : 19982, "state" : "PA" }
+{ "_id" : "16127", "city" : "GROVE CITY", "loc" : [ -80.084138, 41.160704 ], "pop" : 14568, "state" : "PA" }
+{ "_id" : "16130", "city" : "HADLEY", "loc" : [ -80.153544, 41.43302 ], "pop" : 3623, "state" : "PA" }
+{ "_id" : "16131", "city" : "HARTSTOWN", "loc" : [ -80.381321, 41.550875 ], "pop" : 406, "state" : "PA" }
+{ "_id" : "16133", "city" : "JACKSON CENTER", "loc" : [ -80.10372599999999, 41.280134 ], "pop" : 1959, "state" : "PA" }
+{ "_id" : "16134", "city" : "WESTFORD", "loc" : [ -80.456459, 41.506031 ], "pop" : 3328, "state" : "PA" }
+{ "_id" : "16137", "city" : "MERCER", "loc" : [ -80.23401800000001, 41.23254 ], "pop" : 11036, "state" : "PA" }
+{ "_id" : "16141", "city" : "NEW GALILEE", "loc" : [ -80.39390400000001, 40.856891 ], "pop" : 1852, "state" : "PA" }
+{ "_id" : "16142", "city" : "NEW WILMINGTON", "loc" : [ -80.324541, 41.138155 ], "pop" : 9268, "state" : "PA" }
+{ "_id" : "16143", "city" : "PULASKI", "loc" : [ -80.468515, 41.094215 ], "pop" : 3898, "state" : "PA" }
+{ "_id" : "16145", "city" : "SANDY LAKE", "loc" : [ -80.04974, 41.338337 ], "pop" : 843, "state" : "PA" }
+{ "_id" : "16146", "city" : "SHARON", "loc" : [ -80.499342, 41.231552 ], "pop" : 17457, "state" : "PA" }
+{ "_id" : "16148", "city" : "HERMITAGE", "loc" : [ -80.45303, 41.232601 ], "pop" : 14573, "state" : "PA" }
+{ "_id" : "16150", "city" : "SHARPSVILLE", "loc" : [ -80.465642, 41.267648 ], "pop" : 8962, "state" : "PA" }
+{ "_id" : "16153", "city" : "STONEBORO", "loc" : [ -80.097613, 41.34385 ], "pop" : 2249, "state" : "PA" }
+{ "_id" : "16154", "city" : "TRANSFER", "loc" : [ -80.419742, 41.324401 ], "pop" : 2662, "state" : "PA" }
+{ "_id" : "16156", "city" : "VOLANT", "loc" : [ -80.244129, 41.093767 ], "pop" : 2114, "state" : "PA" }
+{ "_id" : "16157", "city" : "WAMPUM", "loc" : [ -80.339184, 40.881879 ], "pop" : 5466, "state" : "PA" }
+{ "_id" : "16159", "city" : "WEST MIDDLESEX", "loc" : [ -80.452759, 41.174054 ], "pop" : 5604, "state" : "PA" }
+{ "_id" : "16201", "city" : "KITTANNING", "loc" : [ -79.51067500000001, 40.815516 ], "pop" : 19140, "state" : "PA" }
+{ "_id" : "16210", "city" : "ADRIAN", "loc" : [ -79.50744400000001, 40.904902 ], "pop" : 726, "state" : "PA" }
+{ "_id" : "16212", "city" : "CADOGAN", "loc" : [ -79.57982699999999, 40.75392 ], "pop" : 427, "state" : "PA" }
+{ "_id" : "16213", "city" : "CALLENSBURG", "loc" : [ -79.55695, 41.132379 ], "pop" : 688, "state" : "PA" }
+{ "_id" : "16214", "city" : "CLARION", "loc" : [ -79.377268, 41.212272 ], "pop" : 8740, "state" : "PA" }
+{ "_id" : "16217", "city" : "COOKSBURG", "loc" : [ -79.19708, 41.338366 ], "pop" : 36, "state" : "PA" }
+{ "_id" : "16218", "city" : "COWANSVILLE", "loc" : [ -79.594607, 40.922985 ], "pop" : 1089, "state" : "PA" }
+{ "_id" : "16222", "city" : "DAYTON", "loc" : [ -79.268551, 40.874101 ], "pop" : 1974, "state" : "PA" }
+{ "_id" : "16224", "city" : "FAIRMOUNT CITY", "loc" : [ -79.27840500000001, 41.042861 ], "pop" : 2104, "state" : "PA" }
+{ "_id" : "16225", "city" : "FISHER", "loc" : [ -79.247033, 41.266737 ], "pop" : 407, "state" : "PA" }
+{ "_id" : "16226", "city" : "FORD CITY", "loc" : [ -79.51222, 40.738407 ], "pop" : 6576, "state" : "PA" }
+{ "_id" : "16229", "city" : "FREEPORT", "loc" : [ -79.66299100000001, 40.703277 ], "pop" : 4517, "state" : "PA" }
+{ "_id" : "16232", "city" : "KNOX", "loc" : [ -79.51940399999999, 41.224518 ], "pop" : 7489, "state" : "PA" }
+{ "_id" : "16233", "city" : "LEEPER", "loc" : [ -79.302179, 41.367074 ], "pop" : 487, "state" : "PA" }
+{ "_id" : "16234", "city" : "LIMESTONE", "loc" : [ -79.29929199999999, 41.133396 ], "pop" : 1686, "state" : "PA" }
+{ "_id" : "16235", "city" : "LUCINDA", "loc" : [ -79.375372, 41.312377 ], "pop" : 1281, "state" : "PA" }
+{ "_id" : "16236", "city" : "MC GRANN", "loc" : [ -79.53086, 40.76929 ], "pop" : 3844, "state" : "PA" }
+{ "_id" : "16238", "city" : "MANORVILLE", "loc" : [ -79.521333, 40.786256 ], "pop" : 418, "state" : "PA" }
+{ "_id" : "16239", "city" : "MARIENVILLE", "loc" : [ -79.13058100000001, 41.462237 ], "pop" : 1374, "state" : "PA" }
+{ "_id" : "16240", "city" : "MAYPORT", "loc" : [ -79.261701, 40.99059 ], "pop" : 1058, "state" : "PA" }
+{ "_id" : "16242", "city" : "NEW BETHLEHEM", "loc" : [ -79.352654, 40.9999 ], "pop" : 4698, "state" : "PA" }
+{ "_id" : "16248", "city" : "HUEY", "loc" : [ -79.510677, 41.039434 ], "pop" : 3629, "state" : "PA" }
+{ "_id" : "16249", "city" : "RURAL VALLEY", "loc" : [ -79.299102, 40.788488 ], "pop" : 3499, "state" : "PA" }
+{ "_id" : "16254", "city" : "SHIPPENVILLE", "loc" : [ -79.433199, 41.247491 ], "pop" : 2448, "state" : "PA" }
+{ "_id" : "16255", "city" : "SLIGO", "loc" : [ -79.480485, 41.11394 ], "pop" : 1213, "state" : "PA" }
+{ "_id" : "16256", "city" : "SMICKSBURG", "loc" : [ -79.161432, 40.837193 ], "pop" : 2236, "state" : "PA" }
+{ "_id" : "16258", "city" : "STRATTANVILLE", "loc" : [ -79.308188, 41.195498 ], "pop" : 2086, "state" : "PA" }
+{ "_id" : "16259", "city" : "TEMPLETON", "loc" : [ -79.449884, 40.941884 ], "pop" : 1654, "state" : "PA" }
+{ "_id" : "16260", "city" : "VOWINCKEL", "loc" : [ -79.274553, 41.378642 ], "pop" : 1615, "state" : "PA" }
+{ "_id" : "16262", "city" : "CRAIGSVILLE", "loc" : [ -79.638525, 40.834442 ], "pop" : 3065, "state" : "PA" }
+{ "_id" : "16301", "city" : "OIL CITY", "loc" : [ -79.691648, 41.431936 ], "pop" : 19792, "state" : "PA" }
+{ "_id" : "16311", "city" : "CARLTON", "loc" : [ -80.020302, 41.481541 ], "pop" : 282, "state" : "PA" }
+{ "_id" : "16313", "city" : "CLARENDON", "loc" : [ -79.171949, 41.730224 ], "pop" : 422, "state" : "PA" }
+{ "_id" : "16314", "city" : "COCHRANTON", "loc" : [ -80.05726900000001, 41.520487 ], "pop" : 3010, "state" : "PA" }
+{ "_id" : "16316", "city" : "CONNEAUT LAKE", "loc" : [ -80.308567, 41.6189 ], "pop" : 3849, "state" : "PA" }
+{ "_id" : "16317", "city" : "COOPERSTOWN", "loc" : [ -79.875676, 41.497998 ], "pop" : 506, "state" : "PA" }
+{ "_id" : "16319", "city" : "CRANBERRY", "loc" : [ -79.719121, 41.337184 ], "pop" : 353, "state" : "PA" }
+{ "_id" : "16321", "city" : "EAST HICKORY", "loc" : [ -79.38548299999999, 41.5691 ], "pop" : 282, "state" : "PA" }
+{ "_id" : "16323", "city" : "FRANKLIN", "loc" : [ -79.83089, 41.404775 ], "pop" : 18357, "state" : "PA" }
+{ "_id" : "16326", "city" : "FRYBURG", "loc" : [ -79.41340099999999, 41.371736 ], "pop" : 1880, "state" : "PA" }
+{ "_id" : "16327", "city" : "GUYS MILLS", "loc" : [ -79.97143699999999, 41.633265 ], "pop" : 2825, "state" : "PA" }
+{ "_id" : "16329", "city" : "IRVINE", "loc" : [ -79.286303, 41.843283 ], "pop" : 479, "state" : "PA" }
+{ "_id" : "16331", "city" : "KOSSUTH", "loc" : [ -79.588249, 41.290215 ], "pop" : 43, "state" : "PA" }
+{ "_id" : "16332", "city" : "LICKINGVILLE", "loc" : [ -79.371516, 41.3789 ], "pop" : 22, "state" : "PA" }
+{ "_id" : "16333", "city" : "LUDLOW", "loc" : [ -78.924345, 41.728409 ], "pop" : 612, "state" : "PA" }
+{ "_id" : "16334", "city" : "MARBLE", "loc" : [ -79.44592900000001, 41.326077 ], "pop" : 27, "state" : "PA" }
+{ "_id" : "16335", "city" : "MEADVILLE", "loc" : [ -80.148787, 41.633847 ], "pop" : 31290, "state" : "PA" }
+{ "_id" : "16340", "city" : "PITTSFIELD", "loc" : [ -79.419619, 41.836629 ], "pop" : 3172, "state" : "PA" }
+{ "_id" : "16341", "city" : "PLEASANTVILLE", "loc" : [ -79.5685, 41.586696 ], "pop" : 2211, "state" : "PA" }
+{ "_id" : "16342", "city" : "POLK", "loc" : [ -79.93461000000001, 41.358315 ], "pop" : 3159, "state" : "PA" }
+{ "_id" : "16345", "city" : "RUSSELL", "loc" : [ -79.12707899999999, 41.946106 ], "pop" : 3833, "state" : "PA" }
+{ "_id" : "16346", "city" : "SENECA", "loc" : [ -79.67590199999999, 41.374436 ], "pop" : 3723, "state" : "PA" }
+{ "_id" : "16347", "city" : "SHEFFIELD", "loc" : [ -79.034814, 41.70053 ], "pop" : 2382, "state" : "PA" }
+{ "_id" : "16350", "city" : "SUGAR GROVE", "loc" : [ -79.318609, 41.947542 ], "pop" : 3592, "state" : "PA" }
+{ "_id" : "16351", "city" : "TIDIOUTE", "loc" : [ -79.375224, 41.703008 ], "pop" : 2458, "state" : "PA" }
+{ "_id" : "16353", "city" : "TIONESTA", "loc" : [ -79.366332, 41.511616 ], "pop" : 2293, "state" : "PA" }
+{ "_id" : "16354", "city" : "TITUSVILLE", "loc" : [ -79.68549400000001, 41.638163 ], "pop" : 14509, "state" : "PA" }
+{ "_id" : "16360", "city" : "TOWNVILLE", "loc" : [ -79.876679, 41.685581 ], "pop" : 1047, "state" : "PA" }
+{ "_id" : "16362", "city" : "UTICA", "loc" : [ -79.940292, 41.479848 ], "pop" : 1863, "state" : "PA" }
+{ "_id" : "16364", "city" : "VENUS", "loc" : [ -79.50476500000001, 41.376113 ], "pop" : 534, "state" : "PA" }
+{ "_id" : "16365", "city" : "NORTH WARREN", "loc" : [ -79.14286, 41.845265 ], "pop" : 22507, "state" : "PA" }
+{ "_id" : "16371", "city" : "YOUNGSVILLE", "loc" : [ -79.318708, 41.853654 ], "pop" : 1853, "state" : "PA" }
+{ "_id" : "16372", "city" : "CLINTONVILLE", "loc" : [ -79.87338, 41.20022 ], "pop" : 525, "state" : "PA" }
+{ "_id" : "16373", "city" : "EMLENTON", "loc" : [ -79.746996, 41.202769 ], "pop" : 3119, "state" : "PA" }
+{ "_id" : "16374", "city" : "KENNERDELL", "loc" : [ -79.739313, 41.284762 ], "pop" : 1318, "state" : "PA" }
+{ "_id" : "16401", "city" : "LUNDYS LANE", "loc" : [ -80.37527300000001, 41.885882 ], "pop" : 4286, "state" : "PA" }
+{ "_id" : "16402", "city" : "BEAR LAKE", "loc" : [ -79.461365, 41.97006 ], "pop" : 1042, "state" : "PA" }
+{ "_id" : "16403", "city" : "CAMBRIDGE SPRING", "loc" : [ -80.028003, 41.794611 ], "pop" : 5770, "state" : "PA" }
+{ "_id" : "16404", "city" : "CENTERVILLE", "loc" : [ -79.79004, 41.724316 ], "pop" : 2119, "state" : "PA" }
+{ "_id" : "16405", "city" : "COLUMBUS", "loc" : [ -79.57307299999999, 41.938152 ], "pop" : 1751, "state" : "PA" }
+{ "_id" : "16406", "city" : "CONNEAUTVILLE", "loc" : [ -80.344516, 41.745455 ], "pop" : 2542, "state" : "PA" }
+{ "_id" : "16407", "city" : "CORRY", "loc" : [ -79.65674199999999, 41.922593 ], "pop" : 10654, "state" : "PA" }
+{ "_id" : "16410", "city" : "CRANESVILLE", "loc" : [ -80.308528, 41.916222 ], "pop" : 1783, "state" : "PA" }
+{ "_id" : "16411", "city" : "EAST SPRINGFIELD", "loc" : [ -80.430336, 41.979363 ], "pop" : 1318, "state" : "PA" }
+{ "_id" : "16412", "city" : "EDINBORO", "loc" : [ -80.135604, 41.875629 ], "pop" : 12914, "state" : "PA" }
+{ "_id" : "16415", "city" : "FAIRVIEW", "loc" : [ -80.239508, 42.040741 ], "pop" : 7876, "state" : "PA" }
+{ "_id" : "16417", "city" : "GIRARD", "loc" : [ -80.317756, 41.989573 ], "pop" : 8190, "state" : "PA" }
+{ "_id" : "16420", "city" : "GRAND VALLEY", "loc" : [ -79.546944, 41.77315 ], "pop" : 59, "state" : "PA" }
+{ "_id" : "16421", "city" : "HARBORCREEK", "loc" : [ -79.941648, 42.176719 ], "pop" : 3533, "state" : "PA" }
+{ "_id" : "16423", "city" : "LAKE CITY", "loc" : [ -80.33883400000001, 42.020361 ], "pop" : 3674, "state" : "PA" }
+{ "_id" : "16424", "city" : "ESPYVILLE", "loc" : [ -80.426911, 41.663535 ], "pop" : 5520, "state" : "PA" }
+{ "_id" : "16426", "city" : "MC KEAN", "loc" : [ -80.147336, 41.999035 ], "pop" : 4099, "state" : "PA" }
+{ "_id" : "16428", "city" : "NORTH EAST", "loc" : [ -79.833179, 42.200793 ], "pop" : 12531, "state" : "PA" }
+{ "_id" : "16433", "city" : "SAEGERTOWN", "loc" : [ -80.147857, 41.726753 ], "pop" : 5094, "state" : "PA" }
+{ "_id" : "16434", "city" : "SPARTANSBURG", "loc" : [ -79.684916, 41.793648 ], "pop" : 2785, "state" : "PA" }
+{ "_id" : "16435", "city" : "SPRINGBORO", "loc" : [ -80.375276, 41.811348 ], "pop" : 2131, "state" : "PA" }
+{ "_id" : "16436", "city" : "SPRING CREEK", "loc" : [ -79.56554, 41.846832 ], "pop" : 191, "state" : "PA" }
+{ "_id" : "16438", "city" : "UNION CITY", "loc" : [ -79.84546400000001, 41.893851 ], "pop" : 8890, "state" : "PA" }
+{ "_id" : "16440", "city" : "VENANGO", "loc" : [ -80.125353, 41.791968 ], "pop" : 918, "state" : "PA" }
+{ "_id" : "16441", "city" : "WATERFORD", "loc" : [ -79.99963, 41.960266 ], "pop" : 9247, "state" : "PA" }
+{ "_id" : "16442", "city" : "WATTSBURG", "loc" : [ -79.836282, 42.039114 ], "pop" : 2463, "state" : "PA" }
+{ "_id" : "16443", "city" : "WEST SPRINGFIELD", "loc" : [ -80.46501000000001, 41.94646 ], "pop" : 1375, "state" : "PA" }
+{ "_id" : "16501", "city" : "ERIE", "loc" : [ -80.08601, 42.125962 ], "pop" : 1956, "state" : "PA" }
+{ "_id" : "16502", "city" : "ERIE", "loc" : [ -80.097607, 42.113332 ], "pop" : 18640, "state" : "PA" }
+{ "_id" : "16503", "city" : "ERIE", "loc" : [ -80.063976, 42.126506 ], "pop" : 19019, "state" : "PA" }
+{ "_id" : "16504", "city" : "ERIE", "loc" : [ -80.05208, 42.1108 ], "pop" : 17680, "state" : "PA" }
+{ "_id" : "16505", "city" : "PRESQUE ISLE", "loc" : [ -80.161902, 42.097526 ], "pop" : 17753, "state" : "PA" }
+{ "_id" : "16506", "city" : "ERIE", "loc" : [ -80.14843999999999, 42.073801 ], "pop" : 19269, "state" : "PA" }
+{ "_id" : "16507", "city" : "ERIE", "loc" : [ -80.08642399999999, 42.131579 ], "pop" : 10936, "state" : "PA" }
+{ "_id" : "16508", "city" : "ERIE", "loc" : [ -80.09354399999999, 42.097577 ], "pop" : 17645, "state" : "PA" }
+{ "_id" : "16509", "city" : "ERIE", "loc" : [ -80.066827, 42.076326 ], "pop" : 24232, "state" : "PA" }
+{ "_id" : "16510", "city" : "WESLEYVILLE", "loc" : [ -80.00375200000001, 42.123673 ], "pop" : 26455, "state" : "PA" }
+{ "_id" : "16511", "city" : "ERIE", "loc" : [ -80.01766499999999, 42.15529 ], "pop" : 11355, "state" : "PA" }
+{ "_id" : "16565", "city" : "ERIE", "loc" : [ -80.10011, 42.0687 ], "pop" : 97, "state" : "PA" }
+{ "_id" : "16601", "city" : "ALTOONA", "loc" : [ -78.408901, 40.520945 ], "pop" : 31560, "state" : "PA" }
+{ "_id" : "16602", "city" : "ALTOONA", "loc" : [ -78.390533, 40.50524 ], "pop" : 32649, "state" : "PA" }
+{ "_id" : "16611", "city" : "BARREE", "loc" : [ -78.107066, 40.549901 ], "pop" : 2765, "state" : "PA" }
+{ "_id" : "16613", "city" : "ASHVILLE", "loc" : [ -78.534639, 40.551266 ], "pop" : 1275, "state" : "PA" }
+{ "_id" : "16616", "city" : "BECCARIA", "loc" : [ -78.508036, 40.757938 ], "pop" : 1571, "state" : "PA" }
+{ "_id" : "16617", "city" : "BELLWOOD", "loc" : [ -78.337234, 40.60394 ], "pop" : 8152, "state" : "PA" }
+{ "_id" : "16620", "city" : "BRISBIN", "loc" : [ -78.35263399999999, 40.838711 ], "pop" : 369, "state" : "PA" }
+{ "_id" : "16621", "city" : "BROAD TOP", "loc" : [ -78.14060000000001, 40.201891 ], "pop" : 331, "state" : "PA" }
+{ "_id" : "16622", "city" : "CALVIN", "loc" : [ -78.023697, 40.298667 ], "pop" : 1190, "state" : "PA" }
+{ "_id" : "16623", "city" : "CASSVILLE", "loc" : [ -78.02717800000001, 40.293977 ], "pop" : 183, "state" : "PA" }
+{ "_id" : "16625", "city" : "CLAYSBURG", "loc" : [ -78.479658, 40.329243 ], "pop" : 3890, "state" : "PA" }
+{ "_id" : "16627", "city" : "COALPORT", "loc" : [ -78.53523800000001, 40.750323 ], "pop" : 940, "state" : "PA" }
+{ "_id" : "16630", "city" : "CRESSON", "loc" : [ -78.586068, 40.460779 ], "pop" : 5829, "state" : "PA" }
+{ "_id" : "16634", "city" : "DUDLEY", "loc" : [ -78.183823, 40.219453 ], "pop" : 616, "state" : "PA" }
+{ "_id" : "16635", "city" : "DUNCANSVILLE", "loc" : [ -78.43832999999999, 40.426228 ], "pop" : 13889, "state" : "PA" }
+{ "_id" : "16636", "city" : "DYSART", "loc" : [ -78.527072, 40.60885 ], "pop" : 769, "state" : "PA" }
+{ "_id" : "16637", "city" : "EAST FREEDOM", "loc" : [ -78.447519, 40.328197 ], "pop" : 2871, "state" : "PA" }
+{ "_id" : "16639", "city" : "FALLENTIMBER", "loc" : [ -78.465912, 40.671924 ], "pop" : 684, "state" : "PA" }
+{ "_id" : "16640", "city" : "FLINTON", "loc" : [ -78.48148999999999, 40.701615 ], "pop" : 1589, "state" : "PA" }
+{ "_id" : "16641", "city" : "GALLITZIN", "loc" : [ -78.555435, 40.48772 ], "pop" : 2852, "state" : "PA" }
+{ "_id" : "16645", "city" : "GLEN HOPE", "loc" : [ -78.499869, 40.798405 ], "pop" : 187, "state" : "PA" }
+{ "_id" : "16646", "city" : "HASTINGS", "loc" : [ -78.702924, 40.665874 ], "pop" : 2616, "state" : "PA" }
+{ "_id" : "16647", "city" : "HESSTON", "loc" : [ -78.12810899999999, 40.412139 ], "pop" : 956, "state" : "PA" }
+{ "_id" : "16648", "city" : "HOLLIDAYSBURG", "loc" : [ -78.368627, 40.438727 ], "pop" : 12867, "state" : "PA" }
+{ "_id" : "16650", "city" : "HOPEWELL", "loc" : [ -78.31289700000001, 40.119225 ], "pop" : 2440, "state" : "PA" }
+{ "_id" : "16651", "city" : "HOUTZDALE", "loc" : [ -78.3618, 40.830538 ], "pop" : 2825, "state" : "PA" }
+{ "_id" : "16652", "city" : "HUNTINGDON", "loc" : [ -78.005028, 40.502274 ], "pop" : 16288, "state" : "PA" }
+{ "_id" : "16655", "city" : "IMLER", "loc" : [ -78.51671899999999, 40.23186 ], "pop" : 3037, "state" : "PA" }
+{ "_id" : "16656", "city" : "IRVONA", "loc" : [ -78.560243, 40.801744 ], "pop" : 1183, "state" : "PA" }
+{ "_id" : "16657", "city" : "JAMES CREEK", "loc" : [ -78.188678, 40.356672 ], "pop" : 485, "state" : "PA" }
+{ "_id" : "16659", "city" : "LOYSBURG", "loc" : [ -78.38643500000001, 40.174577 ], "pop" : 656, "state" : "PA" }
+{ "_id" : "16661", "city" : "MADERA", "loc" : [ -78.427475, 40.827086 ], "pop" : 1389, "state" : "PA" }
+{ "_id" : "16662", "city" : "MARTINSBURG", "loc" : [ -78.324367, 40.295082 ], "pop" : 5016, "state" : "PA" }
+{ "_id" : "16664", "city" : "NEW ENTERPRISE", "loc" : [ -78.425916, 40.200013 ], "pop" : 1898, "state" : "PA" }
+{ "_id" : "16666", "city" : "OSCEOLA MILLS", "loc" : [ -78.275705, 40.872208 ], "pop" : 4346, "state" : "PA" }
+{ "_id" : "16667", "city" : "ST CLAIRSVILLE", "loc" : [ -78.509928, 40.158583 ], "pop" : 174, "state" : "PA" }
+{ "_id" : "16668", "city" : "PATTON", "loc" : [ -78.63502800000001, 40.623045 ], "pop" : 4737, "state" : "PA" }
+{ "_id" : "16669", "city" : "PETERSBURG", "loc" : [ -77.998402, 40.602968 ], "pop" : 2175, "state" : "PA" }
+{ "_id" : "16671", "city" : "RAMEY", "loc" : [ -78.399821, 40.801511 ], "pop" : 538, "state" : "PA" }
+{ "_id" : "16673", "city" : "ROARING SPRING", "loc" : [ -78.39284000000001, 40.327747 ], "pop" : 4942, "state" : "PA" }
+{ "_id" : "16674", "city" : "ROBERTSDALE", "loc" : [ -78.11169599999999, 40.178674 ], "pop" : 727, "state" : "PA" }
+{ "_id" : "16678", "city" : "SAXTON", "loc" : [ -78.247137, 40.223301 ], "pop" : 3031, "state" : "PA" }
+{ "_id" : "16679", "city" : "SIX MILE RUN", "loc" : [ -78.210814, 40.157583 ], "pop" : 1670, "state" : "PA" }
+{ "_id" : "16680", "city" : "SMITHMILL", "loc" : [ -78.39944199999999, 40.767808 ], "pop" : 1192, "state" : "PA" }
+{ "_id" : "16683", "city" : "SPRUCE CREEK", "loc" : [ -78.136083, 40.621767 ], "pop" : 281, "state" : "PA" }
+{ "_id" : "16685", "city" : "TODD", "loc" : [ -78.100354, 40.25775 ], "pop" : 889, "state" : "PA" }
+{ "_id" : "16686", "city" : "TYRONE", "loc" : [ -78.241905, 40.661905 ], "pop" : 11290, "state" : "PA" }
+{ "_id" : "16689", "city" : "WATERFALL", "loc" : [ -78.047708, 40.073871 ], "pop" : 1168, "state" : "PA" }
+{ "_id" : "16691", "city" : "WELLS TANNERY", "loc" : [ -78.140269, 40.100996 ], "pop" : 563, "state" : "PA" }
+{ "_id" : "16692", "city" : "WESTOVER", "loc" : [ -78.73548099999999, 40.76152 ], "pop" : 1550, "state" : "PA" }
+{ "_id" : "16693", "city" : "GANISTER", "loc" : [ -78.22555, 40.437356 ], "pop" : 4799, "state" : "PA" }
+{ "_id" : "16695", "city" : "WOODBURY", "loc" : [ -78.366573, 40.21847 ], "pop" : 741, "state" : "PA" }
+{ "_id" : "16701", "city" : "BRADFORD", "loc" : [ -78.65396699999999, 41.954678 ], "pop" : 18738, "state" : "PA" }
+{ "_id" : "16720", "city" : "AUSTIN", "loc" : [ -78.090812, 41.629649 ], "pop" : 1123, "state" : "PA" }
+{ "_id" : "16724", "city" : "CROSBY", "loc" : [ -78.37463700000001, 41.713356 ], "pop" : 593, "state" : "PA" }
+{ "_id" : "16726", "city" : "ORMSBY", "loc" : [ -78.566743, 41.826327 ], "pop" : 369, "state" : "PA" }
+{ "_id" : "16727", "city" : "DERRICK CITY", "loc" : [ -78.56256399999999, 41.972577 ], "pop" : 623, "state" : "PA" }
+{ "_id" : "16729", "city" : "DUKE CENTER", "loc" : [ -78.49226899999999, 41.954017 ], "pop" : 1122, "state" : "PA" }
+{ "_id" : "16731", "city" : "ELDRED", "loc" : [ -78.38843900000001, 41.948925 ], "pop" : 2616, "state" : "PA" }
+{ "_id" : "16732", "city" : "GIFFORD", "loc" : [ -78.584604, 41.860715 ], "pop" : 586, "state" : "PA" }
+{ "_id" : "16734", "city" : "JAMES CITY", "loc" : [ -78.85052, 41.593116 ], "pop" : 551, "state" : "PA" }
+{ "_id" : "16735", "city" : "KANE", "loc" : [ -78.79777799999999, 41.661861 ], "pop" : 6600, "state" : "PA" }
+{ "_id" : "16738", "city" : "LEWIS RUN", "loc" : [ -78.680498, 41.821123 ], "pop" : 2617, "state" : "PA" }
+{ "_id" : "16740", "city" : "MOUNT JEWETT", "loc" : [ -78.64461300000001, 41.724737 ], "pop" : 1039, "state" : "PA" }
+{ "_id" : "16743", "city" : "PORT ALLEGANY", "loc" : [ -78.279909, 41.816919 ], "pop" : 4468, "state" : "PA" }
+{ "_id" : "16744", "city" : "REW", "loc" : [ -78.53540599999999, 41.912222 ], "pop" : 614, "state" : "PA" }
+{ "_id" : "16745", "city" : "RIXFORD", "loc" : [ -78.458647, 41.934606 ], "pop" : 514, "state" : "PA" }
+{ "_id" : "16746", "city" : "ROULETTE", "loc" : [ -78.15384299999999, 41.773795 ], "pop" : 1354, "state" : "PA" }
+{ "_id" : "16748", "city" : "SHINGLEHOUSE", "loc" : [ -78.19062, 41.957176 ], "pop" : 3390, "state" : "PA" }
+{ "_id" : "16749", "city" : "SMETHPORT", "loc" : [ -78.470229, 41.802063 ], "pop" : 4375, "state" : "PA" }
+{ "_id" : "16750", "city" : "TURTLEPOINT", "loc" : [ -78.330793, 41.884665 ], "pop" : 720, "state" : "PA" }
+{ "_id" : "16801", "city" : "STATE COLLEGE", "loc" : [ -77.852279, 40.792522 ], "pop" : 42278, "state" : "PA" }
+{ "_id" : "16803", "city" : "STATE COLLEGE", "loc" : [ -77.892578, 40.808162 ], "pop" : 20669, "state" : "PA" }
+{ "_id" : "16820", "city" : "AARONSBURG", "loc" : [ -77.38797700000001, 40.876944 ], "pop" : 100, "state" : "PA" }
+{ "_id" : "16821", "city" : "ALLPORT", "loc" : [ -78.21038, 40.975039 ], "pop" : 275, "state" : "PA" }
+{ "_id" : "16822", "city" : "BEECH CREEK", "loc" : [ -77.58511799999999, 41.084507 ], "pop" : 1723, "state" : "PA" }
+{ "_id" : "16823", "city" : "PLEASANT GAP", "loc" : [ -77.7642, 40.909377 ], "pop" : 23418, "state" : "PA" }
+{ "_id" : "16827", "city" : "BOALSBURG", "loc" : [ -77.782236, 40.779344 ], "pop" : 3787, "state" : "PA" }
+{ "_id" : "16828", "city" : "CENTRE HALL", "loc" : [ -77.67422500000001, 40.825429 ], "pop" : 4223, "state" : "PA" }
+{ "_id" : "16829", "city" : "CLARENCE", "loc" : [ -77.931213, 41.058482 ], "pop" : 123, "state" : "PA" }
+{ "_id" : "16830", "city" : "CLEARFIELD", "loc" : [ -78.443488, 41.02103 ], "pop" : 14648, "state" : "PA" }
+{ "_id" : "16832", "city" : "COBURN", "loc" : [ -77.49217299999999, 40.867818 ], "pop" : 836, "state" : "PA" }
+{ "_id" : "16833", "city" : "CURWENSVILLE", "loc" : [ -78.527247, 40.965972 ], "pop" : 4085, "state" : "PA" }
+{ "_id" : "16836", "city" : "FRENCHVILLE", "loc" : [ -78.234465, 41.103794 ], "pop" : 1278, "state" : "PA" }
+{ "_id" : "16837", "city" : "GLEN RICHEY", "loc" : [ -78.47521500000001, 40.938209 ], "pop" : 331, "state" : "PA" }
+{ "_id" : "16838", "city" : "GRAMPIAN", "loc" : [ -78.59491300000001, 40.981768 ], "pop" : 3187, "state" : "PA" }
+{ "_id" : "16839", "city" : "GRASSFLAT", "loc" : [ -78.128354, 40.995881 ], "pop" : 2208, "state" : "PA" }
+{ "_id" : "16840", "city" : "HAWK RUN", "loc" : [ -78.213787, 40.941215 ], "pop" : 2224, "state" : "PA" }
+{ "_id" : "16841", "city" : "HOWARD", "loc" : [ -77.67017800000001, 41.020315 ], "pop" : 3723, "state" : "PA" }
+{ "_id" : "16844", "city" : "JULIAN", "loc" : [ -77.933243, 40.891709 ], "pop" : 2461, "state" : "PA" }
+{ "_id" : "16845", "city" : "KARTHAUS", "loc" : [ -78.087509, 41.113635 ], "pop" : 932, "state" : "PA" }
+{ "_id" : "16852", "city" : "MADISONBURG", "loc" : [ -77.49495899999999, 40.933407 ], "pop" : 678, "state" : "PA" }
+{ "_id" : "16854", "city" : "MILLHEIM", "loc" : [ -77.450531, 40.896314 ], "pop" : 1978, "state" : "PA" }
+{ "_id" : "16858", "city" : "MORRISDALE", "loc" : [ -78.23571699999999, 41.000128 ], "pop" : 1235, "state" : "PA" }
+{ "_id" : "16859", "city" : "MOSHANNON", "loc" : [ -78.009469, 41.03419 ], "pop" : 516, "state" : "PA" }
+{ "_id" : "16860", "city" : "MUNSON", "loc" : [ -78.18621, 40.966704 ], "pop" : 110, "state" : "PA" }
+{ "_id" : "16861", "city" : "NEW MILLPORT", "loc" : [ -78.49454299999999, 40.885302 ], "pop" : 657, "state" : "PA" }
+{ "_id" : "16863", "city" : "OLANTA", "loc" : [ -78.500079, 40.905621 ], "pop" : 47, "state" : "PA" }
+{ "_id" : "16864", "city" : "ORVISTON", "loc" : [ -77.620306, 41.075386 ], "pop" : 1023, "state" : "PA" }
+{ "_id" : "16865", "city" : "PENNSYLVANIA FUR", "loc" : [ -77.95406800000001, 40.728194 ], "pop" : 2558, "state" : "PA" }
+{ "_id" : "16866", "city" : "PHILIPSBURG", "loc" : [ -78.219008, 40.886252 ], "pop" : 7810, "state" : "PA" }
+{ "_id" : "16870", "city" : "PORT MATILDA", "loc" : [ -78.078795, 40.801819 ], "pop" : 1890, "state" : "PA" }
+{ "_id" : "16871", "city" : "POTTERSDALE", "loc" : [ -78.03405600000001, 41.186798 ], "pop" : 34, "state" : "PA" }
+{ "_id" : "16872", "city" : "REBERSBURG", "loc" : [ -77.405322, 40.954906 ], "pop" : 816, "state" : "PA" }
+{ "_id" : "16874", "city" : "SNOW SHOE", "loc" : [ -77.95228, 41.037581 ], "pop" : 1917, "state" : "PA" }
+{ "_id" : "16875", "city" : "SPRING MILLS", "loc" : [ -77.57403100000001, 40.857753 ], "pop" : 1805, "state" : "PA" }
+{ "_id" : "16877", "city" : "WARRIORS MARK", "loc" : [ -78.077478, 40.741414 ], "pop" : 2760, "state" : "PA" }
+{ "_id" : "16878", "city" : "WEST DECATUR", "loc" : [ -78.31293599999999, 40.949305 ], "pop" : 2226, "state" : "PA" }
+{ "_id" : "16879", "city" : "WINBURNE", "loc" : [ -78.156235, 40.967779 ], "pop" : 387, "state" : "PA" }
+{ "_id" : "16881", "city" : "WOODLAND", "loc" : [ -78.321445, 41.009833 ], "pop" : 2571, "state" : "PA" }
+{ "_id" : "16882", "city" : "WOODWARD", "loc" : [ -77.348269, 40.911574 ], "pop" : 183, "state" : "PA" }
+{ "_id" : "16901", "city" : "WELLSBORO", "loc" : [ -77.30802, 41.737343 ], "pop" : 9906, "state" : "PA" }
+{ "_id" : "16912", "city" : "BLOSSBURG", "loc" : [ -77.079711, 41.669771 ], "pop" : 2123, "state" : "PA" }
+{ "_id" : "16914", "city" : "COLUMBIA CROSS R", "loc" : [ -76.79324200000001, 41.846282 ], "pop" : 2398, "state" : "PA" }
+{ "_id" : "16915", "city" : "OSWAYO", "loc" : [ -78.003861, 41.781529 ], "pop" : 5171, "state" : "PA" }
+{ "_id" : "16917", "city" : "COVINGTON", "loc" : [ -77.108795, 41.739297 ], "pop" : 1417, "state" : "PA" }
+{ "_id" : "16920", "city" : "ELKLAND", "loc" : [ -77.31339199999999, 41.988165 ], "pop" : 1910, "state" : "PA" }
+{ "_id" : "16921", "city" : "GAINES", "loc" : [ -77.568001, 41.747134 ], "pop" : 544, "state" : "PA" }
+{ "_id" : "16922", "city" : "GALETON", "loc" : [ -77.65475600000001, 41.723006 ], "pop" : 2050, "state" : "PA" }
+{ "_id" : "16923", "city" : "NORTH BINGHAM", "loc" : [ -77.87358500000001, 41.935312 ], "pop" : 1585, "state" : "PA" }
+{ "_id" : "16925", "city" : "GILLETT", "loc" : [ -76.77132899999999, 41.956826 ], "pop" : 4273, "state" : "PA" }
+{ "_id" : "16926", "city" : "GRANVILLE SUMMIT", "loc" : [ -76.721829, 41.697299 ], "pop" : 1447, "state" : "PA" }
+{ "_id" : "16927", "city" : "HARRISON VALLEY", "loc" : [ -77.687665, 41.949824 ], "pop" : 1476, "state" : "PA" }
+{ "_id" : "16928", "city" : "KNOXVILLE", "loc" : [ -77.435678, 41.959557 ], "pop" : 893, "state" : "PA" }
+{ "_id" : "16929", "city" : "LAWRENCEVILLE", "loc" : [ -77.11355, 41.978266 ], "pop" : 1915, "state" : "PA" }
+{ "_id" : "16930", "city" : "LIBERTY", "loc" : [ -77.119505, 41.565571 ], "pop" : 893, "state" : "PA" }
+{ "_id" : "16932", "city" : "MAINESBURG", "loc" : [ -76.96815599999999, 41.790029 ], "pop" : 1140, "state" : "PA" }
+{ "_id" : "16933", "city" : "MANSFIELD", "loc" : [ -77.07163, 41.812288 ], "pop" : 7111, "state" : "PA" }
+{ "_id" : "16935", "city" : "MIDDLEBURY CENTE", "loc" : [ -77.314764, 41.891706 ], "pop" : 2549, "state" : "PA" }
+{ "_id" : "16936", "city" : "MILLERTON", "loc" : [ -76.974766, 41.962467 ], "pop" : 2072, "state" : "PA" }
+{ "_id" : "16937", "city" : "MILLS", "loc" : [ -77.762051, 41.902482 ], "pop" : 653, "state" : "PA" }
+{ "_id" : "16938", "city" : "MORRIS", "loc" : [ -77.29197499999999, 41.54752 ], "pop" : 959, "state" : "PA" }
+{ "_id" : "16939", "city" : "MORRIS RUN", "loc" : [ -77.02776900000001, 41.672943 ], "pop" : 496, "state" : "PA" }
+{ "_id" : "16940", "city" : "NELSON", "loc" : [ -77.24190900000001, 41.978719 ], "pop" : 599, "state" : "PA" }
+{ "_id" : "16941", "city" : "GENESEE", "loc" : [ -77.773995, 41.981963 ], "pop" : 47, "state" : "PA" }
+{ "_id" : "16942", "city" : "OSCEOLA", "loc" : [ -77.353983, 41.984765 ], "pop" : 609, "state" : "PA" }
+{ "_id" : "16943", "city" : "SABINSVILLE", "loc" : [ -77.537825, 41.856414 ], "pop" : 576, "state" : "PA" }
+{ "_id" : "16946", "city" : "TIOGA", "loc" : [ -77.13929400000001, 41.912454 ], "pop" : 1796, "state" : "PA" }
+{ "_id" : "16947", "city" : "TROY", "loc" : [ -76.771143, 41.77815 ], "pop" : 3476, "state" : "PA" }
+{ "_id" : "16948", "city" : "ULYSSES", "loc" : [ -77.712557, 41.845903 ], "pop" : 727, "state" : "PA" }
+{ "_id" : "16950", "city" : "LITTLE MARSH", "loc" : [ -77.530975, 41.919063 ], "pop" : 2844, "state" : "PA" }
+{ "_id" : "17002", "city" : "ALLENSVILLE", "loc" : [ -77.829396, 40.524921 ], "pop" : 1135, "state" : "PA" }
+{ "_id" : "17003", "city" : "ANNVILLE", "loc" : [ -76.544676, 40.345608 ], "pop" : 12173, "state" : "PA" }
+{ "_id" : "17004", "city" : "BELLEVILLE", "loc" : [ -77.735823, 40.601571 ], "pop" : 4203, "state" : "PA" }
+{ "_id" : "17005", "city" : "BERRYSBURG", "loc" : [ -76.811207, 40.60199 ], "pop" : 376, "state" : "PA" }
+{ "_id" : "17006", "city" : "BLAIN", "loc" : [ -77.511736, 40.329314 ], "pop" : 755, "state" : "PA" }
+{ "_id" : "17007", "city" : "BOILING SPRINGS", "loc" : [ -77.119489, 40.144873 ], "pop" : 4331, "state" : "PA" }
+{ "_id" : "17009", "city" : "BURNHAM", "loc" : [ -77.562459, 40.636119 ], "pop" : 2005, "state" : "PA" }
+{ "_id" : "17011", "city" : "SHIREMANSTOWN", "loc" : [ -76.92911100000001, 40.238071 ], "pop" : 33023, "state" : "PA" }
+{ "_id" : "17013", "city" : "CARLISLE BARRACK", "loc" : [ -77.19952600000001, 40.203877 ], "pop" : 50939, "state" : "PA" }
+{ "_id" : "17014", "city" : "COCOLAMUS", "loc" : [ -77.10674899999999, 40.656706 ], "pop" : 887, "state" : "PA" }
+{ "_id" : "17017", "city" : "DALMATIA", "loc" : [ -76.879713, 40.648315 ], "pop" : 1694, "state" : "PA" }
+{ "_id" : "17018", "city" : "DAUPHIN", "loc" : [ -76.928304, 40.384581 ], "pop" : 4523, "state" : "PA" }
+{ "_id" : "17019", "city" : "DILLSBURG", "loc" : [ -77.03386999999999, 40.096373 ], "pop" : 11814, "state" : "PA" }
+{ "_id" : "17020", "city" : "DUNCANNON", "loc" : [ -77.047254, 40.408678 ], "pop" : 10021, "state" : "PA" }
+{ "_id" : "17021", "city" : "EAST WATERFORD", "loc" : [ -77.652789, 40.354191 ], "pop" : 929, "state" : "PA" }
+{ "_id" : "17022", "city" : "ELIZABETHTOWN", "loc" : [ -76.60254500000001, 40.155331 ], "pop" : 21808, "state" : "PA" }
+{ "_id" : "17023", "city" : "ELIZABETHVILLE", "loc" : [ -76.83548399999999, 40.55497 ], "pop" : 4564, "state" : "PA" }
+{ "_id" : "17024", "city" : "ELLIOTTSBURG", "loc" : [ -77.270348, 40.362428 ], "pop" : 1125, "state" : "PA" }
+{ "_id" : "17025", "city" : "ENOLA", "loc" : [ -76.943208, 40.292178 ], "pop" : 13103, "state" : "PA" }
+{ "_id" : "17026", "city" : "FREDERICKSBURG", "loc" : [ -76.42674, 40.452392 ], "pop" : 2382, "state" : "PA" }
+{ "_id" : "17028", "city" : "GRANTVILLE", "loc" : [ -76.671331, 40.360629 ], "pop" : 4569, "state" : "PA" }
+{ "_id" : "17029", "city" : "GRANVILLE", "loc" : [ -77.61335800000001, 40.547868 ], "pop" : 1293, "state" : "PA" }
+{ "_id" : "17030", "city" : "GRATZ", "loc" : [ -76.718851, 40.610424 ], "pop" : 696, "state" : "PA" }
+{ "_id" : "17031", "city" : "GREEN PARK", "loc" : [ -77.32009600000001, 40.375143 ], "pop" : 347, "state" : "PA" }
+{ "_id" : "17032", "city" : "HALIFAX", "loc" : [ -76.89404, 40.47603 ], "pop" : 7648, "state" : "PA" }
+{ "_id" : "17033", "city" : "HERSHEY", "loc" : [ -76.654518, 40.263767 ], "pop" : 20514, "state" : "PA" }
+{ "_id" : "17034", "city" : "HIGHSPIRE", "loc" : [ -76.785303, 40.208348 ], "pop" : 2670, "state" : "PA" }
+{ "_id" : "17035", "city" : "HONEY GROVE", "loc" : [ -77.57607, 40.430903 ], "pop" : 884, "state" : "PA" }
+{ "_id" : "17036", "city" : "HUMMELSTOWN", "loc" : [ -76.70937499999999, 40.278199 ], "pop" : 8178, "state" : "PA" }
+{ "_id" : "17037", "city" : "ICKESBURG", "loc" : [ -77.34291, 40.434154 ], "pop" : 1828, "state" : "PA" }
+{ "_id" : "17038", "city" : "JONESTOWN", "loc" : [ -76.50384200000001, 40.43607 ], "pop" : 5098, "state" : "PA" }
+{ "_id" : "17040", "city" : "LANDISBURG", "loc" : [ -77.319146, 40.332644 ], "pop" : 1140, "state" : "PA" }
+{ "_id" : "17042", "city" : "CLEONA", "loc" : [ -76.425895, 40.335912 ], "pop" : 61993, "state" : "PA" }
+{ "_id" : "17043", "city" : "WORMLEYSBURG", "loc" : [ -76.89757, 40.247158 ], "pop" : 5340, "state" : "PA" }
+{ "_id" : "17044", "city" : "LEWISTOWN", "loc" : [ -77.57558, 40.599439 ], "pop" : 19311, "state" : "PA" }
+{ "_id" : "17045", "city" : "LIVERPOOL", "loc" : [ -77.00832699999999, 40.575272 ], "pop" : 3951, "state" : "PA" }
+{ "_id" : "17047", "city" : "LOYSVILLE", "loc" : [ -77.41382299999999, 40.36576 ], "pop" : 1850, "state" : "PA" }
+{ "_id" : "17048", "city" : "LYKENS", "loc" : [ -76.70735999999999, 40.590919 ], "pop" : 2904, "state" : "PA" }
+{ "_id" : "17049", "city" : "MC ALISTERVILLE", "loc" : [ -77.2602, 40.646916 ], "pop" : 3073, "state" : "PA" }
+{ "_id" : "17051", "city" : "MC VEYTOWN", "loc" : [ -77.718625, 40.504593 ], "pop" : 3685, "state" : "PA" }
+{ "_id" : "17052", "city" : "MAPLETON DEPOT", "loc" : [ -77.960444, 40.386414 ], "pop" : 1329, "state" : "PA" }
+{ "_id" : "17053", "city" : "MARYSVILLE", "loc" : [ -76.972204, 40.335062 ], "pop" : 4561, "state" : "PA" }
+{ "_id" : "17055", "city" : "HAMPDEN", "loc" : [ -76.99493, 40.212669 ], "pop" : 51902, "state" : "PA" }
+{ "_id" : "17057", "city" : "MIDDLETOWN", "loc" : [ -76.733127, 40.204086 ], "pop" : 21545, "state" : "PA" }
+{ "_id" : "17058", "city" : "MIFFLIN", "loc" : [ -77.41314, 40.570842 ], "pop" : 1189, "state" : "PA" }
+{ "_id" : "17059", "city" : "MIFFLINTOWN", "loc" : [ -77.376119, 40.572666 ], "pop" : 5646, "state" : "PA" }
+{ "_id" : "17060", "city" : "MILL CREEK", "loc" : [ -77.917689, 40.447102 ], "pop" : 1002, "state" : "PA" }
+{ "_id" : "17061", "city" : "MILLERSBURG", "loc" : [ -76.930483, 40.558743 ], "pop" : 6135, "state" : "PA" }
+{ "_id" : "17062", "city" : "MILLERSTOWN", "loc" : [ -77.12977600000001, 40.550548 ], "pop" : 1589, "state" : "PA" }
+{ "_id" : "17063", "city" : "MILROY", "loc" : [ -77.55673899999999, 40.72033 ], "pop" : 3627, "state" : "PA" }
+{ "_id" : "17065", "city" : "MOUNT HOLLY SPRI", "loc" : [ -77.19080700000001, 40.118356 ], "pop" : 2857, "state" : "PA" }
+{ "_id" : "17066", "city" : "MOUNT UNION", "loc" : [ -77.863704, 40.390106 ], "pop" : 7218, "state" : "PA" }
+{ "_id" : "17067", "city" : "MYERSTOWN", "loc" : [ -76.314328, 40.378949 ], "pop" : 12843, "state" : "PA" }
+{ "_id" : "17068", "city" : "NEW BLOOMFIELD", "loc" : [ -77.193836, 40.419325 ], "pop" : 3066, "state" : "PA" }
+{ "_id" : "17070", "city" : "NEW CUMBERLAND", "loc" : [ -76.868909, 40.215105 ], "pop" : 15037, "state" : "PA" }
+{ "_id" : "17071", "city" : "NEW GERMANTOWN", "loc" : [ -77.579701, 40.305749 ], "pop" : 455, "state" : "PA" }
+{ "_id" : "17073", "city" : "NEWMANSTOWN", "loc" : [ -76.2426, 40.317938 ], "pop" : 3560, "state" : "PA" }
+{ "_id" : "17074", "city" : "NEWPORT", "loc" : [ -77.16586599999999, 40.482662 ], "pop" : 6378, "state" : "PA" }
+{ "_id" : "17076", "city" : "OAKLAND MILLS", "loc" : [ -77.319244, 40.614748 ], "pop" : 457, "state" : "PA" }
+{ "_id" : "17078", "city" : "PALMYRA", "loc" : [ -76.58861, 40.301055 ], "pop" : 14239, "state" : "PA" }
+{ "_id" : "17082", "city" : "PORT ROYAL", "loc" : [ -77.430958, 40.51068 ], "pop" : 3319, "state" : "PA" }
+{ "_id" : "17084", "city" : "REEDSVILLE", "loc" : [ -77.611589, 40.672189 ], "pop" : 3320, "state" : "PA" }
+{ "_id" : "17086", "city" : "RICHFIELD", "loc" : [ -77.12229600000001, 40.688424 ], "pop" : 1673, "state" : "PA" }
+{ "_id" : "17087", "city" : "RICHLAND", "loc" : [ -76.26544699999999, 40.380595 ], "pop" : 3367, "state" : "PA" }
+{ "_id" : "17090", "city" : "SHERMANS DALE", "loc" : [ -77.18085600000001, 40.329898 ], "pop" : 5128, "state" : "PA" }
+{ "_id" : "17094", "city" : "THOMPSONTOWN", "loc" : [ -77.207551, 40.590782 ], "pop" : 2515, "state" : "PA" }
+{ "_id" : "17097", "city" : "WICONISCO", "loc" : [ -76.709084, 40.567511 ], "pop" : 1702, "state" : "PA" }
+{ "_id" : "17098", "city" : "WILLIAMSTOWN", "loc" : [ -76.622259, 40.580761 ], "pop" : 2655, "state" : "PA" }
+{ "_id" : "17099", "city" : "YEAGERTOWN", "loc" : [ -77.56882299999999, 40.643558 ], "pop" : 2197, "state" : "PA" }
+{ "_id" : "17101", "city" : "HARRISBURG", "loc" : [ -76.883079, 40.261767 ], "pop" : 2151, "state" : "PA" }
+{ "_id" : "17102", "city" : "HARRISBURG", "loc" : [ -76.89104399999999, 40.27278 ], "pop" : 8862, "state" : "PA" }
+{ "_id" : "17103", "city" : "PENBROOK", "loc" : [ -76.863812, 40.273852 ], "pop" : 12335, "state" : "PA" }
+{ "_id" : "17104", "city" : "HARRISBURG", "loc" : [ -76.859397, 40.259683 ], "pop" : 21882, "state" : "PA" }
+{ "_id" : "17109", "city" : "COLONIAL PARK", "loc" : [ -76.82261200000001, 40.29122 ], "pop" : 22952, "state" : "PA" }
+{ "_id" : "17110", "city" : "HARRISBURG", "loc" : [ -76.886246, 40.302957 ], "pop" : 19314, "state" : "PA" }
+{ "_id" : "17111", "city" : "SWATARA", "loc" : [ -76.79391800000001, 40.266058 ], "pop" : 22558, "state" : "PA" }
+{ "_id" : "17112", "city" : "HARRISBURG", "loc" : [ -76.791438, 40.335208 ], "pop" : 27559, "state" : "PA" }
+{ "_id" : "17113", "city" : "STEELTON", "loc" : [ -76.827568, 40.234007 ], "pop" : 9841, "state" : "PA" }
+{ "_id" : "17201", "city" : "CHAMBERSBURG", "loc" : [ -77.657928, 39.931318 ], "pop" : 41893, "state" : "PA" }
+{ "_id" : "17211", "city" : "ARTEMAS", "loc" : [ -78.40313999999999, 39.757465 ], "pop" : 481, "state" : "PA" }
+{ "_id" : "17212", "city" : "BIG COVE TANNERY", "loc" : [ -78.012366, 39.889704 ], "pop" : 2178, "state" : "PA" }
+{ "_id" : "17213", "city" : "BLAIRS MILLS", "loc" : [ -77.769473, 40.254804 ], "pop" : 551, "state" : "PA" }
+{ "_id" : "17214", "city" : "BLUE RIDGE SUMMI", "loc" : [ -77.469836, 39.726951 ], "pop" : 1090, "state" : "PA" }
+{ "_id" : "17215", "city" : "BURNT CABINS", "loc" : [ -77.901718, 40.075278 ], "pop" : 155, "state" : "PA" }
+{ "_id" : "17217", "city" : "CONCORD", "loc" : [ -77.70313299999999, 40.245842 ], "pop" : 109, "state" : "PA" }
+{ "_id" : "17219", "city" : "DOYLESBURG", "loc" : [ -77.68620300000001, 40.217195 ], "pop" : 905, "state" : "PA" }
+{ "_id" : "17220", "city" : "DRY RUN", "loc" : [ -77.76457000000001, 40.174744 ], "pop" : 499, "state" : "PA" }
+{ "_id" : "17221", "city" : "FANNETTSBURG", "loc" : [ -77.82101, 40.071692 ], "pop" : 628, "state" : "PA" }
+{ "_id" : "17222", "city" : "FAYETTEVILLE", "loc" : [ -77.53095999999999, 39.906543 ], "pop" : 9459, "state" : "PA" }
+{ "_id" : "17223", "city" : "FORT LITTLETON", "loc" : [ -77.975678, 40.054372 ], "pop" : 750, "state" : "PA" }
+{ "_id" : "17224", "city" : "FORT LOUDON", "loc" : [ -77.898365, 39.954692 ], "pop" : 1412, "state" : "PA" }
+{ "_id" : "17225", "city" : "GREENCASTLE", "loc" : [ -77.746956, 39.781827 ], "pop" : 14553, "state" : "PA" }
+{ "_id" : "17228", "city" : "HARRISONVILLE", "loc" : [ -78.08407699999999, 39.976137 ], "pop" : 1410, "state" : "PA" }
+{ "_id" : "17229", "city" : "HUSTONTOWN", "loc" : [ -78.01483500000001, 40.044111 ], "pop" : 245, "state" : "PA" }
+{ "_id" : "17232", "city" : "LURGAN", "loc" : [ -77.635063, 40.127422 ], "pop" : 845, "state" : "PA" }
+{ "_id" : "17233", "city" : "MC CONNELLSBURG", "loc" : [ -77.990117, 39.944251 ], "pop" : 2529, "state" : "PA" }
+{ "_id" : "17236", "city" : "MERCERSBURG", "loc" : [ -77.907259, 39.819519 ], "pop" : 7735, "state" : "PA" }
+{ "_id" : "17237", "city" : "MONT ALTO", "loc" : [ -77.553676, 39.841689 ], "pop" : 1601, "state" : "PA" }
+{ "_id" : "17238", "city" : "NEEDMORE", "loc" : [ -78.143935, 39.871279 ], "pop" : 1208, "state" : "PA" }
+{ "_id" : "17239", "city" : "NEELYTON", "loc" : [ -77.85801499999999, 40.137051 ], "pop" : 816, "state" : "PA" }
+{ "_id" : "17240", "city" : "NEWBURG", "loc" : [ -77.56691499999999, 40.13333 ], "pop" : 2350, "state" : "PA" }
+{ "_id" : "17241", "city" : "NEWVILLE", "loc" : [ -77.411401, 40.185468 ], "pop" : 9740, "state" : "PA" }
+{ "_id" : "17243", "city" : "ORBISONIA", "loc" : [ -77.906924, 40.238872 ], "pop" : 2368, "state" : "PA" }
+{ "_id" : "17244", "city" : "ORRSTOWN", "loc" : [ -77.639762, 40.07305 ], "pop" : 2281, "state" : "PA" }
+{ "_id" : "17246", "city" : "PLEASANT HALL", "loc" : [ -77.703148, 40.04135 ], "pop" : 366, "state" : "PA" }
+{ "_id" : "17252", "city" : "SAINT THOMAS", "loc" : [ -77.7908, 39.924052 ], "pop" : 4109, "state" : "PA" }
+{ "_id" : "17255", "city" : "SHADE GAP", "loc" : [ -77.868045, 40.172976 ], "pop" : 416, "state" : "PA" }
+{ "_id" : "17257", "city" : "SHIPPENSBURG", "loc" : [ -77.51947699999999, 40.051359 ], "pop" : 19302, "state" : "PA" }
+{ "_id" : "17260", "city" : "SHIRLEYSBURG", "loc" : [ -77.870062, 40.316768 ], "pop" : 1416, "state" : "PA" }
+{ "_id" : "17262", "city" : "SPRING RUN", "loc" : [ -77.74052500000001, 40.14663 ], "pop" : 796, "state" : "PA" }
+{ "_id" : "17264", "city" : "THREE SPRINGS", "loc" : [ -77.99412, 40.183437 ], "pop" : 2197, "state" : "PA" }
+{ "_id" : "17265", "city" : "UPPERSTRASBURG", "loc" : [ -77.736791, 40.05799 ], "pop" : 499, "state" : "PA" }
+{ "_id" : "17266", "city" : "WALNUT BOTTOM", "loc" : [ -77.408984, 40.086042 ], "pop" : 1157, "state" : "PA" }
+{ "_id" : "17267", "city" : "WARFORDSBURG", "loc" : [ -78.198627, 39.769765 ], "pop" : 2988, "state" : "PA" }
+{ "_id" : "17268", "city" : "WAYNESBORO", "loc" : [ -77.567363, 39.763504 ], "pop" : 25878, "state" : "PA" }
+{ "_id" : "17271", "city" : "WILLOW HILL", "loc" : [ -77.796947, 40.113694 ], "pop" : 409, "state" : "PA" }
+{ "_id" : "17301", "city" : "ABBOTTSTOWN", "loc" : [ -76.993077, 39.888099 ], "pop" : 1777, "state" : "PA" }
+{ "_id" : "17302", "city" : "AIRVILLE", "loc" : [ -76.401179, 39.821012 ], "pop" : 1685, "state" : "PA" }
+{ "_id" : "17304", "city" : "ASPERS", "loc" : [ -77.228657, 39.976533 ], "pop" : 2894, "state" : "PA" }
+{ "_id" : "17307", "city" : "BIGLERVILLE", "loc" : [ -77.288549, 39.928119 ], "pop" : 5280, "state" : "PA" }
+{ "_id" : "17309", "city" : "BROGUE", "loc" : [ -76.488236, 39.883044 ], "pop" : 5123, "state" : "PA" }
+{ "_id" : "17313", "city" : "YOE", "loc" : [ -76.644794, 39.900127 ], "pop" : 8691, "state" : "PA" }
+{ "_id" : "17314", "city" : "DELTA", "loc" : [ -76.34410099999999, 39.751754 ], "pop" : 4910, "state" : "PA" }
+{ "_id" : "17315", "city" : "DOVER", "loc" : [ -76.855485, 40.006158 ], "pop" : 20094, "state" : "PA" }
+{ "_id" : "17316", "city" : "EAST BERLIN", "loc" : [ -77.00725199999999, 39.964546 ], "pop" : 5538, "state" : "PA" }
+{ "_id" : "17319", "city" : "ETTERS", "loc" : [ -76.801861, 40.154506 ], "pop" : 6135, "state" : "PA" }
+{ "_id" : "17320", "city" : "GREENSTONE", "loc" : [ -77.376824, 39.762694 ], "pop" : 4709, "state" : "PA" }
+{ "_id" : "17321", "city" : "FAWN GROVE", "loc" : [ -76.43923700000001, 39.751024 ], "pop" : 1938, "state" : "PA" }
+{ "_id" : "17322", "city" : "FELTON", "loc" : [ -76.593721, 39.836006 ], "pop" : 3128, "state" : "PA" }
+{ "_id" : "17324", "city" : "GARDNERS", "loc" : [ -77.187725, 40.042759 ], "pop" : 4246, "state" : "PA" }
+{ "_id" : "17325", "city" : "GETTYSBURG", "loc" : [ -77.222313, 39.832044 ], "pop" : 23574, "state" : "PA" }
+{ "_id" : "17327", "city" : "GLEN ROCK", "loc" : [ -76.747713, 39.781326 ], "pop" : 7217, "state" : "PA" }
+{ "_id" : "17329", "city" : "BRODBECKS", "loc" : [ -76.86204600000001, 39.759907 ], "pop" : 2230, "state" : "PA" }
+{ "_id" : "17331", "city" : "HANOVER", "loc" : [ -76.981196, 39.794286 ], "pop" : 37367, "state" : "PA" }
+{ "_id" : "17339", "city" : "LEWISBERRY", "loc" : [ -76.87000399999999, 40.146295 ], "pop" : 5338, "state" : "PA" }
+{ "_id" : "17340", "city" : "LITTLESTOWN", "loc" : [ -77.100326, 39.749549 ], "pop" : 7758, "state" : "PA" }
+{ "_id" : "17344", "city" : "MC SHERRYSTOWN", "loc" : [ -77.01496, 39.804832 ], "pop" : 3838, "state" : "PA" }
+{ "_id" : "17345", "city" : "MANCHESTER", "loc" : [ -76.733245, 40.069461 ], "pop" : 8095, "state" : "PA" }
+{ "_id" : "17347", "city" : "MOUNT WOLF", "loc" : [ -76.69657599999999, 40.071126 ], "pop" : 3083, "state" : "PA" }
+{ "_id" : "17349", "city" : "NEW FREEDOM", "loc" : [ -76.68406400000001, 39.742266 ], "pop" : 6346, "state" : "PA" }
+{ "_id" : "17350", "city" : "NEW OXFORD", "loc" : [ -77.06433, 39.877459 ], "pop" : 9674, "state" : "PA" }
+{ "_id" : "17352", "city" : "NEW PARK", "loc" : [ -76.504167, 39.760027 ], "pop" : 1190, "state" : "PA" }
+{ "_id" : "17353", "city" : "ORRTANNA", "loc" : [ -77.38059199999999, 39.881032 ], "pop" : 2066, "state" : "PA" }
+{ "_id" : "17356", "city" : "RED LION", "loc" : [ -76.608075, 39.902572 ], "pop" : 12737, "state" : "PA" }
+{ "_id" : "17360", "city" : "SEVEN VALLEYS", "loc" : [ -76.738336, 39.855613 ], "pop" : 5219, "state" : "PA" }
+{ "_id" : "17361", "city" : "SHREWSBURY", "loc" : [ -76.67482699999999, 39.760133 ], "pop" : 3749, "state" : "PA" }
+{ "_id" : "17362", "city" : "SPRING GROVE", "loc" : [ -76.87735600000001, 39.857208 ], "pop" : 13901, "state" : "PA" }
+{ "_id" : "17363", "city" : "STEWARTSTOWN", "loc" : [ -76.597037, 39.771962 ], "pop" : 5865, "state" : "PA" }
+{ "_id" : "17364", "city" : "THOMASVILLE", "loc" : [ -76.882159, 39.934619 ], "pop" : 3435, "state" : "PA" }
+{ "_id" : "17365", "city" : "WELLSVILLE", "loc" : [ -76.944315, 40.055721 ], "pop" : 2456, "state" : "PA" }
+{ "_id" : "17366", "city" : "WINDSOR", "loc" : [ -76.55912600000001, 39.923271 ], "pop" : 5489, "state" : "PA" }
+{ "_id" : "17368", "city" : "WRIGHTSVILLE", "loc" : [ -76.526971, 39.996559 ], "pop" : 7677, "state" : "PA" }
+{ "_id" : "17370", "city" : "YORK HAVEN", "loc" : [ -76.773725, 40.122154 ], "pop" : 4948, "state" : "PA" }
+{ "_id" : "17372", "city" : "YORK SPRINGS", "loc" : [ -77.10613600000001, 40.00839 ], "pop" : 3042, "state" : "PA" }
+{ "_id" : "17401", "city" : "YORK", "loc" : [ -76.726887, 39.963539 ], "pop" : 2439, "state" : "PA" }
+{ "_id" : "17402", "city" : "EAST YORK", "loc" : [ -76.674578, 39.971508 ], "pop" : 35648, "state" : "PA" }
+{ "_id" : "17403", "city" : "YORK", "loc" : [ -76.712998, 39.94943 ], "pop" : 40210, "state" : "PA" }
+{ "_id" : "17404", "city" : "WEST YORK", "loc" : [ -76.768987, 39.961988 ], "pop" : 49524, "state" : "PA" }
+{ "_id" : "17406", "city" : "HELLAM", "loc" : [ -76.592646, 39.998249 ], "pop" : 6095, "state" : "PA" }
+{ "_id" : "17407", "city" : "JACOBUS", "loc" : [ -76.714634, 39.880203 ], "pop" : 1872, "state" : "PA" }
+{ "_id" : "17501", "city" : "AKRON", "loc" : [ -76.20529500000001, 40.157086 ], "pop" : 4286, "state" : "PA" }
+{ "_id" : "17502", "city" : "BAINBRIDGE", "loc" : [ -76.672589, 40.1086 ], "pop" : 2688, "state" : "PA" }
+{ "_id" : "17505", "city" : "BIRD IN HAND", "loc" : [ -76.183036, 40.056109 ], "pop" : 862, "state" : "PA" }
+{ "_id" : "17509", "city" : "NINEPOINTS", "loc" : [ -76.025983, 39.935632 ], "pop" : 4517, "state" : "PA" }
+{ "_id" : "17512", "city" : "COLUMBIA", "loc" : [ -76.48622, 40.039079 ], "pop" : 17454, "state" : "PA" }
+{ "_id" : "17516", "city" : "CONESTOGA", "loc" : [ -76.35747499999999, 39.940303 ], "pop" : 4493, "state" : "PA" }
+{ "_id" : "17517", "city" : "DENVER", "loc" : [ -76.11568800000001, 40.229671 ], "pop" : 10737, "state" : "PA" }
+{ "_id" : "17518", "city" : "DRUMORE", "loc" : [ -76.245684, 39.838399 ], "pop" : 1191, "state" : "PA" }
+{ "_id" : "17519", "city" : "EAST EARL", "loc" : [ -76.02763400000001, 40.139475 ], "pop" : 4249, "state" : "PA" }
+{ "_id" : "17520", "city" : "EAST PETERSBURG", "loc" : [ -76.351169, 40.100781 ], "pop" : 4387, "state" : "PA" }
+{ "_id" : "17522", "city" : "EPHRATA", "loc" : [ -76.18209299999999, 40.175641 ], "pop" : 25859, "state" : "PA" }
+{ "_id" : "17527", "city" : "GAP", "loc" : [ -75.997801, 40.002018 ], "pop" : 4318, "state" : "PA" }
+{ "_id" : "17529", "city" : "GORDONVILLE", "loc" : [ -76.11063, 40.035304 ], "pop" : 4429, "state" : "PA" }
+{ "_id" : "17532", "city" : "HOLTWOOD", "loc" : [ -76.300822, 39.863146 ], "pop" : 2526, "state" : "PA" }
+{ "_id" : "17535", "city" : "KINZERS", "loc" : [ -76.04932599999999, 40.005326 ], "pop" : 2524, "state" : "PA" }
+{ "_id" : "17536", "city" : "KIRKWOOD", "loc" : [ -76.093315, 39.82571 ], "pop" : 2384, "state" : "PA" }
+{ "_id" : "17538", "city" : "SALUNGA", "loc" : [ -76.414975, 40.08825 ], "pop" : 5489, "state" : "PA" }
+{ "_id" : "17540", "city" : "LEOLA", "loc" : [ -76.192109, 40.096448 ], "pop" : 9624, "state" : "PA" }
+{ "_id" : "17543", "city" : "BRUNNERVILLE", "loc" : [ -76.29926, 40.162573 ], "pop" : 29376, "state" : "PA" }
+{ "_id" : "17545", "city" : "MANHEIM", "loc" : [ -76.416794, 40.170229 ], "pop" : 16992, "state" : "PA" }
+{ "_id" : "17547", "city" : "MARIETTA", "loc" : [ -76.564527, 40.066442 ], "pop" : 5751, "state" : "PA" }
+{ "_id" : "17551", "city" : "MILLERSVILLE", "loc" : [ -76.356568, 39.998213 ], "pop" : 8021, "state" : "PA" }
+{ "_id" : "17552", "city" : "FLORIN", "loc" : [ -76.50755100000001, 40.106828 ], "pop" : 12282, "state" : "PA" }
+{ "_id" : "17554", "city" : "MOUNTVILLE", "loc" : [ -76.427694, 40.042742 ], "pop" : 4192, "state" : "PA" }
+{ "_id" : "17555", "city" : "NARVON", "loc" : [ -75.975584, 40.125165 ], "pop" : 7239, "state" : "PA" }
+{ "_id" : "17557", "city" : "NEW HOLLAND", "loc" : [ -76.080136, 40.100511 ], "pop" : 11604, "state" : "PA" }
+{ "_id" : "17560", "city" : "NEW PROVIDENCE", "loc" : [ -76.22431899999999, 39.909776 ], "pop" : 5330, "state" : "PA" }
+{ "_id" : "17562", "city" : "PARADISE", "loc" : [ -76.108074, 39.985249 ], "pop" : 2757, "state" : "PA" }
+{ "_id" : "17563", "city" : "PEACH BOTTOM", "loc" : [ -76.17908300000001, 39.770511 ], "pop" : 4352, "state" : "PA" }
+{ "_id" : "17565", "city" : "PEQUEA", "loc" : [ -76.320866, 39.905765 ], "pop" : 1800, "state" : "PA" }
+{ "_id" : "17566", "city" : "QUARRYVILLE", "loc" : [ -76.146462, 39.894932 ], "pop" : 9361, "state" : "PA" }
+{ "_id" : "17569", "city" : "REINHOLDS", "loc" : [ -76.101332, 40.268758 ], "pop" : 4665, "state" : "PA" }
+{ "_id" : "17572", "city" : "RONKS", "loc" : [ -76.166132, 40.020754 ], "pop" : 2964, "state" : "PA" }
+{ "_id" : "17576", "city" : "SMOKETOWN", "loc" : [ -76.22007000000001, 40.040651 ], "pop" : 2141, "state" : "PA" }
+{ "_id" : "17578", "city" : "STEVENS", "loc" : [ -76.162604, 40.219397 ], "pop" : 6511, "state" : "PA" }
+{ "_id" : "17579", "city" : "STRASBURG", "loc" : [ -76.18482400000001, 39.970075 ], "pop" : 5694, "state" : "PA" }
+{ "_id" : "17581", "city" : "TERRE HILL", "loc" : [ -76.05108300000001, 40.158539 ], "pop" : 1282, "state" : "PA" }
+{ "_id" : "17582", "city" : "WASHINGTON BORO", "loc" : [ -76.4402, 39.988118 ], "pop" : 2214, "state" : "PA" }
+{ "_id" : "17584", "city" : "WILLOW STREET", "loc" : [ -76.27524, 39.967003 ], "pop" : 7176, "state" : "PA" }
+{ "_id" : "17601", "city" : "NEFFSVILLE", "loc" : [ -76.31988800000001, 40.075381 ], "pop" : 41062, "state" : "PA" }
+{ "_id" : "17602", "city" : "LANCASTER", "loc" : [ -76.284364, 40.033514 ], "pop" : 40850, "state" : "PA" }
+{ "_id" : "17603", "city" : "ROHRERSTOWN", "loc" : [ -76.33158299999999, 40.030475 ], "pop" : 55173, "state" : "PA" }
+{ "_id" : "17701", "city" : "SOUTH WILLIAMSPO", "loc" : [ -77.020571, 41.247217 ], "pop" : 58844, "state" : "PA" }
+{ "_id" : "17723", "city" : "CAMMAL", "loc" : [ -77.46202099999999, 41.380901 ], "pop" : 246, "state" : "PA" }
+{ "_id" : "17724", "city" : "CANTON", "loc" : [ -76.858188, 41.653784 ], "pop" : 5189, "state" : "PA" }
+{ "_id" : "17727", "city" : "CEDAR RUN", "loc" : [ -77.48891, 41.498972 ], "pop" : 102, "state" : "PA" }
+{ "_id" : "17728", "city" : "COGAN STATION", "loc" : [ -77.068996, 41.31517 ], "pop" : 4582, "state" : "PA" }
+{ "_id" : "17729", "city" : "CROSS FORK", "loc" : [ -77.80953, 41.473672 ], "pop" : 184, "state" : "PA" }
+{ "_id" : "17737", "city" : "HUGHESVILLE", "loc" : [ -76.71411000000001, 41.255952 ], "pop" : 6489, "state" : "PA" }
+{ "_id" : "17740", "city" : "SALLADASBURG", "loc" : [ -77.242704, 41.200733 ], "pop" : 11484, "state" : "PA" }
+{ "_id" : "17742", "city" : "LAIRDSVILLE", "loc" : [ -76.58893, 41.233549 ], "pop" : 914, "state" : "PA" }
+{ "_id" : "17744", "city" : "LINDEN", "loc" : [ -77.152652, 41.247216 ], "pop" : 2994, "state" : "PA" }
+{ "_id" : "17745", "city" : "LOCK HAVEN", "loc" : [ -77.44358800000001, 41.142497 ], "pop" : 16448, "state" : "PA" }
+{ "_id" : "17747", "city" : "LOGANTON", "loc" : [ -77.320397, 41.028317 ], "pop" : 2326, "state" : "PA" }
+{ "_id" : "17751", "city" : "MILL HALL", "loc" : [ -77.483609, 41.086688 ], "pop" : 7510, "state" : "PA" }
+{ "_id" : "17752", "city" : "MONTGOMERY", "loc" : [ -76.883933, 41.178778 ], "pop" : 5539, "state" : "PA" }
+{ "_id" : "17754", "city" : "MONTOURSVILLE", "loc" : [ -76.903035, 41.266252 ], "pop" : 11266, "state" : "PA" }
+{ "_id" : "17756", "city" : "MUNCY", "loc" : [ -76.76325799999999, 41.213715 ], "pop" : 8627, "state" : "PA" }
+{ "_id" : "17758", "city" : "MUNCY VALLEY", "loc" : [ -76.541518, 41.381206 ], "pop" : 1548, "state" : "PA" }
+{ "_id" : "17763", "city" : "RALSTON", "loc" : [ -76.95835, 41.503817 ], "pop" : 588, "state" : "PA" }
+{ "_id" : "17764", "city" : "RENOVO", "loc" : [ -77.74478999999999, 41.333376 ], "pop" : 3639, "state" : "PA" }
+{ "_id" : "17765", "city" : "ROARING BRANCH", "loc" : [ -76.942053, 41.569234 ], "pop" : 448, "state" : "PA" }
+{ "_id" : "17768", "city" : "SHUNK", "loc" : [ -76.745521, 41.553574 ], "pop" : 300, "state" : "PA" }
+{ "_id" : "17771", "city" : "TROUT RUN", "loc" : [ -77.009776, 41.412481 ], "pop" : 4449, "state" : "PA" }
+{ "_id" : "17772", "city" : "TURBOTVILLE", "loc" : [ -76.742493, 41.111867 ], "pop" : 3902, "state" : "PA" }
+{ "_id" : "17774", "city" : "UNITYVILLE", "loc" : [ -76.51831799999999, 41.243552 ], "pop" : 871, "state" : "PA" }
+{ "_id" : "17776", "city" : "WATERVILLE", "loc" : [ -77.36036799999999, 41.31136 ], "pop" : 334, "state" : "PA" }
+{ "_id" : "17777", "city" : "WATSONTOWN", "loc" : [ -76.85319200000001, 41.102006 ], "pop" : 6601, "state" : "PA" }
+{ "_id" : "17778", "city" : "WESTPORT", "loc" : [ -77.931496, 41.27445 ], "pop" : 25, "state" : "PA" }
+{ "_id" : "17779", "city" : "WOOLRICH", "loc" : [ -77.331307, 41.188734 ], "pop" : 4694, "state" : "PA" }
+{ "_id" : "17801", "city" : "SUNBURY", "loc" : [ -76.77761099999999, 40.855122 ], "pop" : 17335, "state" : "PA" }
+{ "_id" : "17810", "city" : "ALLENWOOD", "loc" : [ -76.972362, 41.126424 ], "pop" : 2666, "state" : "PA" }
+{ "_id" : "17812", "city" : "BEAVER SPRINGS", "loc" : [ -77.231801, 40.752766 ], "pop" : 1575, "state" : "PA" }
+{ "_id" : "17813", "city" : "BEAVERTOWN", "loc" : [ -77.169112, 40.777378 ], "pop" : 2226, "state" : "PA" }
+{ "_id" : "17814", "city" : "BENTON", "loc" : [ -76.340632, 41.223142 ], "pop" : 5292, "state" : "PA" }
+{ "_id" : "17815", "city" : "BLOOMSBURG", "loc" : [ -76.438379, 41.011528 ], "pop" : 25338, "state" : "PA" }
+{ "_id" : "17820", "city" : "CATAWISSA", "loc" : [ -76.441586, 40.918031 ], "pop" : 6334, "state" : "PA" }
+{ "_id" : "17821", "city" : "DANVILLE", "loc" : [ -76.62289699999999, 40.979895 ], "pop" : 17269, "state" : "PA" }
+{ "_id" : "17823", "city" : "DORNSIFE", "loc" : [ -76.76260000000001, 40.757092 ], "pop" : 432, "state" : "PA" }
+{ "_id" : "17824", "city" : "ELYSBURG", "loc" : [ -76.556924, 40.863871 ], "pop" : 2165, "state" : "PA" }
+{ "_id" : "17827", "city" : "FREEBURG", "loc" : [ -76.94296300000001, 40.767498 ], "pop" : 1080, "state" : "PA" }
+{ "_id" : "17828", "city" : "GOWEN CITY", "loc" : [ -76.528149, 40.751141 ], "pop" : 646, "state" : "PA" }
+{ "_id" : "17830", "city" : "HERNDON", "loc" : [ -76.80076099999999, 40.691789 ], "pop" : 2089, "state" : "PA" }
+{ "_id" : "17832", "city" : "MARION HEIGHTS", "loc" : [ -76.465137, 40.804576 ], "pop" : 837, "state" : "PA" }
+{ "_id" : "17834", "city" : "KULPMONT", "loc" : [ -76.474384, 40.793278 ], "pop" : 3183, "state" : "PA" }
+{ "_id" : "17835", "city" : "LAURELTON", "loc" : [ -77.20521100000001, 40.91268 ], "pop" : 448, "state" : "PA" }
+{ "_id" : "17836", "city" : "LECK KILL", "loc" : [ -76.62710800000001, 40.710135 ], "pop" : 626, "state" : "PA" }
+{ "_id" : "17837", "city" : "LEWISBURG", "loc" : [ -76.90987800000001, 40.970205 ], "pop" : 18821, "state" : "PA" }
+{ "_id" : "17841", "city" : "MC CLURE", "loc" : [ -77.37579100000001, 40.699084 ], "pop" : 4901, "state" : "PA" }
+{ "_id" : "17842", "city" : "MIDDLEBURG", "loc" : [ -77.046798, 40.797656 ], "pop" : 6546, "state" : "PA" }
+{ "_id" : "17843", "city" : "BEAVER SPRINGS", "loc" : [ -76.970366, 40.810917 ], "pop" : 1791, "state" : "PA" }
+{ "_id" : "17844", "city" : "MIFFLINBURG", "loc" : [ -77.050515, 40.921826 ], "pop" : 8379, "state" : "PA" }
+{ "_id" : "17845", "city" : "MILLMONT", "loc" : [ -77.194142, 40.880324 ], "pop" : 2111, "state" : "PA" }
+{ "_id" : "17846", "city" : "MILLVILLE", "loc" : [ -76.52076700000001, 41.126051 ], "pop" : 5496, "state" : "PA" }
+{ "_id" : "17847", "city" : "MILTON", "loc" : [ -76.839817, 41.01681 ], "pop" : 9223, "state" : "PA" }
+{ "_id" : "17850", "city" : "MONTANDON", "loc" : [ -76.851024, 40.975936 ], "pop" : 3167, "state" : "PA" }
+{ "_id" : "17851", "city" : "MOUNT CARMEL", "loc" : [ -76.419466, 40.795535 ], "pop" : 9925, "state" : "PA" }
+{ "_id" : "17853", "city" : "MOUNT PLEASANT M", "loc" : [ -77.005241, 40.700185 ], "pop" : 1876, "state" : "PA" }
+{ "_id" : "17855", "city" : "NEW BERLIN", "loc" : [ -76.986124, 40.880212 ], "pop" : 904, "state" : "PA" }
+{ "_id" : "17856", "city" : "NEW COLUMBIA", "loc" : [ -76.90185099999999, 41.054108 ], "pop" : 3072, "state" : "PA" }
+{ "_id" : "17857", "city" : "NORTHUMBERLAND", "loc" : [ -76.79079400000001, 40.904355 ], "pop" : 7326, "state" : "PA" }
+{ "_id" : "17859", "city" : "ORANGEVILLE", "loc" : [ -76.38097, 41.10156 ], "pop" : 2625, "state" : "PA" }
+{ "_id" : "17860", "city" : "PAXINOS", "loc" : [ -76.635041, 40.844809 ], "pop" : 1684, "state" : "PA" }
+{ "_id" : "17864", "city" : "PORT TREVORTON", "loc" : [ -76.908215, 40.699593 ], "pop" : 2911, "state" : "PA" }
+{ "_id" : "17866", "city" : "RANSHAW", "loc" : [ -76.498242, 40.803039 ], "pop" : 124, "state" : "PA" }
+{ "_id" : "17867", "city" : "REBUCK", "loc" : [ -76.740605, 40.712544 ], "pop" : 620, "state" : "PA" }
+{ "_id" : "17868", "city" : "RIVERSIDE", "loc" : [ -76.637458, 40.951269 ], "pop" : 1991, "state" : "PA" }
+{ "_id" : "17870", "city" : "SELINSGROVE", "loc" : [ -76.86825, 40.822372 ], "pop" : 14796, "state" : "PA" }
+{ "_id" : "17872", "city" : "EXCELSIOR", "loc" : [ -76.56111799999999, 40.790336 ], "pop" : 20982, "state" : "PA" }
+{ "_id" : "17877", "city" : "SNYDERTOWN", "loc" : [ -76.67494499999999, 40.874097 ], "pop" : 416, "state" : "PA" }
+{ "_id" : "17878", "city" : "STILLWATER", "loc" : [ -76.369624, 41.151517 ], "pop" : 523, "state" : "PA" }
+{ "_id" : "17881", "city" : "TREVORTON", "loc" : [ -76.67023399999999, 40.781867 ], "pop" : 2067, "state" : "PA" }
+{ "_id" : "17888", "city" : "WILBURTON", "loc" : [ -76.392922, 40.812087 ], "pop" : 98, "state" : "PA" }
+{ "_id" : "17889", "city" : "WINFIELD", "loc" : [ -76.871833, 40.890805 ], "pop" : 2071, "state" : "PA" }
+{ "_id" : "17901", "city" : "POTTSVILLE", "loc" : [ -76.212318, 40.683978 ], "pop" : 27703, "state" : "PA" }
+{ "_id" : "17921", "city" : "ASHLAND", "loc" : [ -76.342972, 40.773231 ], "pop" : 8328, "state" : "PA" }
+{ "_id" : "17922", "city" : "AUBURN", "loc" : [ -76.13439, 40.596157 ], "pop" : 2444, "state" : "PA" }
+{ "_id" : "17923", "city" : "BRANCHDALE", "loc" : [ -76.33278799999999, 40.664328 ], "pop" : 835, "state" : "PA" }
+{ "_id" : "17925", "city" : "BROCKTON", "loc" : [ -76.049874, 40.763162 ], "pop" : 1230, "state" : "PA" }
+{ "_id" : "17927", "city" : "CENTRALIA", "loc" : [ -76.357325, 40.81375 ], "pop" : 1006, "state" : "PA" }
+{ "_id" : "17929", "city" : "CRESSONA", "loc" : [ -76.19502799999999, 40.628361 ], "pop" : 2240, "state" : "PA" }
+{ "_id" : "17931", "city" : "FRACKVILLE", "loc" : [ -76.231137, 40.782537 ], "pop" : 7039, "state" : "PA" }
+{ "_id" : "17935", "city" : "GIRARDVILLE", "loc" : [ -76.28581, 40.792162 ], "pop" : 1892, "state" : "PA" }
+{ "_id" : "17938", "city" : "HEGINS", "loc" : [ -76.473168, 40.666898 ], "pop" : 2499, "state" : "PA" }
+{ "_id" : "17941", "city" : "KLINGERSTOWN", "loc" : [ -76.65070900000001, 40.667571 ], "pop" : 508, "state" : "PA" }
+{ "_id" : "17948", "city" : "MAHANOY CITY", "loc" : [ -76.139601, 40.812302 ], "pop" : 5209, "state" : "PA" }
+{ "_id" : "17954", "city" : "MINERSVILLE", "loc" : [ -76.261533, 40.690637 ], "pop" : 4998, "state" : "PA" }
+{ "_id" : "17957", "city" : "MUIR", "loc" : [ -76.468205, 40.613614 ], "pop" : 374, "state" : "PA" }
+{ "_id" : "17959", "city" : "KASKA", "loc" : [ -76.11348, 40.722728 ], "pop" : 2826, "state" : "PA" }
+{ "_id" : "17960", "city" : "NEW RINGGOLD", "loc" : [ -75.948409, 40.714851 ], "pop" : 4284, "state" : "PA" }
+{ "_id" : "17961", "city" : "ORWIGSBURG", "loc" : [ -76.08399900000001, 40.643071 ], "pop" : 6928, "state" : "PA" }
+{ "_id" : "17963", "city" : "PINE GROVE", "loc" : [ -76.326913, 40.567093 ], "pop" : 12239, "state" : "PA" }
+{ "_id" : "17964", "city" : "PITMAN", "loc" : [ -76.523297, 40.704868 ], "pop" : 992, "state" : "PA" }
+{ "_id" : "17965", "city" : "PORT CARBON", "loc" : [ -76.16604599999999, 40.697731 ], "pop" : 2260, "state" : "PA" }
+{ "_id" : "17967", "city" : "RINGTOWN", "loc" : [ -76.23493000000001, 40.855854 ], "pop" : 2311, "state" : "PA" }
+{ "_id" : "17968", "city" : "SACRAMENTO", "loc" : [ -76.61283299999999, 40.635238 ], "pop" : 347, "state" : "PA" }
+{ "_id" : "17970", "city" : "SAINT CLAIR", "loc" : [ -76.192381, 40.719273 ], "pop" : 4091, "state" : "PA" }
+{ "_id" : "17972", "city" : "SCHUYLKILL HAVEN", "loc" : [ -76.169973, 40.630571 ], "pop" : 6199, "state" : "PA" }
+{ "_id" : "17976", "city" : "SHENANDOAH", "loc" : [ -76.203502, 40.816744 ], "pop" : 11159, "state" : "PA" }
+{ "_id" : "17978", "city" : "SPRING GLEN", "loc" : [ -76.635018, 40.633447 ], "pop" : 288, "state" : "PA" }
+{ "_id" : "17980", "city" : "TOWER CITY", "loc" : [ -76.550022, 40.584475 ], "pop" : 3905, "state" : "PA" }
+{ "_id" : "17981", "city" : "DONALDSON", "loc" : [ -76.398796, 40.626842 ], "pop" : 2629, "state" : "PA" }
+{ "_id" : "17983", "city" : "VALLEY VIEW", "loc" : [ -76.544843, 40.644467 ], "pop" : 2007, "state" : "PA" }
+{ "_id" : "17985", "city" : "ZION GROVE", "loc" : [ -76.231032, 40.937152 ], "pop" : 2070, "state" : "PA" }
+{ "_id" : "18011", "city" : "ALBURTIS", "loc" : [ -75.62112999999999, 40.486201 ], "pop" : 4844, "state" : "PA" }
+{ "_id" : "18013", "city" : "ROSETO", "loc" : [ -75.195644, 40.854907 ], "pop" : 16916, "state" : "PA" }
+{ "_id" : "18014", "city" : "BATH", "loc" : [ -75.40855999999999, 40.755144 ], "pop" : 11601, "state" : "PA" }
+{ "_id" : "18015", "city" : "BETHLEHEM", "loc" : [ -75.38050699999999, 40.600167 ], "pop" : 29778, "state" : "PA" }
+{ "_id" : "18017", "city" : "BUTZTOWN", "loc" : [ -75.35823000000001, 40.65168 ], "pop" : 46369, "state" : "PA" }
+{ "_id" : "18018", "city" : "BETHLEHEM", "loc" : [ -75.392827, 40.627849 ], "pop" : 32072, "state" : "PA" }
+{ "_id" : "18031", "city" : "BREINIGSVILLE", "loc" : [ -75.655269, 40.552621 ], "pop" : 3437, "state" : "PA" }
+{ "_id" : "18032", "city" : "CATASAUQUA", "loc" : [ -75.46926999999999, 40.655696 ], "pop" : 9663, "state" : "PA" }
+{ "_id" : "18034", "city" : "CENTER VALLEY", "loc" : [ -75.42420799999999, 40.539594 ], "pop" : 5250, "state" : "PA" }
+{ "_id" : "18035", "city" : "CHERRYVILLE", "loc" : [ -75.552133, 40.738476 ], "pop" : 905, "state" : "PA" }
+{ "_id" : "18036", "city" : "COOPERSBURG", "loc" : [ -75.388778, 40.507553 ], "pop" : 10656, "state" : "PA" }
+{ "_id" : "18037", "city" : "COPLAY", "loc" : [ -75.51882500000001, 40.684865 ], "pop" : 6015, "state" : "PA" }
+{ "_id" : "18038", "city" : "DANIELSVILLE", "loc" : [ -75.518604, 40.786636 ], "pop" : 2004, "state" : "PA" }
+{ "_id" : "18041", "city" : "EAST GREENVILLE", "loc" : [ -75.505618, 40.411876 ], "pop" : 6266, "state" : "PA" }
+{ "_id" : "18042", "city" : "FORKS TOWNSHIP", "loc" : [ -75.23582, 40.6867 ], "pop" : 65784, "state" : "PA" }
+{ "_id" : "18049", "city" : "EMMAUS", "loc" : [ -75.500991, 40.529295 ], "pop" : 16204, "state" : "PA" }
+{ "_id" : "18051", "city" : "FOGELSVILLE", "loc" : [ -75.656794, 40.59304 ], "pop" : 2175, "state" : "PA" }
+{ "_id" : "18052", "city" : "HOKENDAUQUA", "loc" : [ -75.495383, 40.647479 ], "pop" : 23666, "state" : "PA" }
+{ "_id" : "18053", "city" : "GERMANSVILLE", "loc" : [ -75.714687, 40.711826 ], "pop" : 975, "state" : "PA" }
+{ "_id" : "18054", "city" : "GREEN LANE", "loc" : [ -75.435148, 40.353377 ], "pop" : 6020, "state" : "PA" }
+{ "_id" : "18055", "city" : "HELLERTOWN", "loc" : [ -75.325513, 40.581715 ], "pop" : 11759, "state" : "PA" }
+{ "_id" : "18056", "city" : "HEREFORD", "loc" : [ -75.579983, 40.448659 ], "pop" : 3026, "state" : "PA" }
+{ "_id" : "18058", "city" : "KUNKLETOWN", "loc" : [ -75.47597399999999, 40.899891 ], "pop" : 4924, "state" : "PA" }
+{ "_id" : "18062", "city" : "MACUNGIE", "loc" : [ -75.56661800000001, 40.528543 ], "pop" : 10376, "state" : "PA" }
+{ "_id" : "18064", "city" : "NAZARETH", "loc" : [ -75.31993199999999, 40.744962 ], "pop" : 19236, "state" : "PA" }
+{ "_id" : "18066", "city" : "NEW TRIPOLI", "loc" : [ -75.741739, 40.654544 ], "pop" : 4684, "state" : "PA" }
+{ "_id" : "18067", "city" : "NORTHAMPTON", "loc" : [ -75.48742, 40.699765 ], "pop" : 13792, "state" : "PA" }
+{ "_id" : "18069", "city" : "OREFIELD", "loc" : [ -75.59739500000001, 40.624826 ], "pop" : 6397, "state" : "PA" }
+{ "_id" : "18070", "city" : "PALM", "loc" : [ -75.533124, 40.43167 ], "pop" : 512, "state" : "PA" }
+{ "_id" : "18071", "city" : "PALMERTON", "loc" : [ -75.601119, 40.816976 ], "pop" : 11535, "state" : "PA" }
+{ "_id" : "18072", "city" : "PEN ARGYL", "loc" : [ -75.270115, 40.85182 ], "pop" : 9736, "state" : "PA" }
+{ "_id" : "18073", "city" : "PENNSBURG", "loc" : [ -75.486608, 40.391138 ], "pop" : 5126, "state" : "PA" }
+{ "_id" : "18074", "city" : "PERKIOMENVILLE", "loc" : [ -75.50218, 40.31566 ], "pop" : 4053, "state" : "PA" }
+{ "_id" : "18076", "city" : "RED HILL", "loc" : [ -75.484613, 40.375807 ], "pop" : 1807, "state" : "PA" }
+{ "_id" : "18077", "city" : "RIEGELSVILLE", "loc" : [ -75.219064, 40.57824 ], "pop" : 1924, "state" : "PA" }
+{ "_id" : "18078", "city" : "SCHNECKSVILLE", "loc" : [ -75.623924, 40.681949 ], "pop" : 6843, "state" : "PA" }
+{ "_id" : "18080", "city" : "EMERALD", "loc" : [ -75.621612, 40.740695 ], "pop" : 11316, "state" : "PA" }
+{ "_id" : "18087", "city" : "TREXLERTOWN", "loc" : [ -75.602293, 40.554418 ], "pop" : 690, "state" : "PA" }
+{ "_id" : "18088", "city" : "WALNUTPORT", "loc" : [ -75.565749, 40.76147 ], "pop" : 7180, "state" : "PA" }
+{ "_id" : "18091", "city" : "WIND GAP", "loc" : [ -75.32637800000001, 40.816922 ], "pop" : 1740, "state" : "PA" }
+{ "_id" : "18092", "city" : "ZIONSVILLE", "loc" : [ -75.526146, 40.473425 ], "pop" : 2312, "state" : "PA" }
+{ "_id" : "18101", "city" : "ALLENTOWN", "loc" : [ -75.470955, 40.602729 ], "pop" : 3638, "state" : "PA" }
+{ "_id" : "18102", "city" : "ALLENTOWN", "loc" : [ -75.478139, 40.606818 ], "pop" : 41873, "state" : "PA" }
+{ "_id" : "18103", "city" : "ALLENTOWN", "loc" : [ -75.464521, 40.589145 ], "pop" : 59074, "state" : "PA" }
+{ "_id" : "18104", "city" : "ALLENTOWN", "loc" : [ -75.522499, 40.601849 ], "pop" : 33989, "state" : "PA" }
+{ "_id" : "18106", "city" : "WESCOSVILLE", "loc" : [ -75.566424, 40.561451 ], "pop" : 6260, "state" : "PA" }
+{ "_id" : "18201", "city" : "WEST HAZLETON", "loc" : [ -75.978193, 40.962107 ], "pop" : 38788, "state" : "PA" }
+{ "_id" : "18210", "city" : "ALBRIGHTSVILLE", "loc" : [ -75.58420599999999, 40.974786 ], "pop" : 3862, "state" : "PA" }
+{ "_id" : "18211", "city" : "ANDREAS", "loc" : [ -75.834247, 40.746457 ], "pop" : 1235, "state" : "PA" }
+{ "_id" : "18214", "city" : "BARNESVILLE", "loc" : [ -76.06108999999999, 40.813811 ], "pop" : 1949, "state" : "PA" }
+{ "_id" : "18216", "city" : "BEAVER MEADOWS", "loc" : [ -75.940648, 40.922672 ], "pop" : 2470, "state" : "PA" }
+{ "_id" : "18218", "city" : "COALDALE", "loc" : [ -75.91038500000001, 40.821942 ], "pop" : 2531, "state" : "PA" }
+{ "_id" : "18220", "city" : "DELANO", "loc" : [ -76.069462, 40.841048 ], "pop" : 605, "state" : "PA" }
+{ "_id" : "18222", "city" : "DRUMS", "loc" : [ -75.97676, 41.025525 ], "pop" : 6008, "state" : "PA" }
+{ "_id" : "18224", "city" : "FREELAND", "loc" : [ -75.888001, 41.019557 ], "pop" : 6311, "state" : "PA" }
+{ "_id" : "18229", "city" : "JIM THORPE", "loc" : [ -75.739665, 40.870002 ], "pop" : 5048, "state" : "PA" }
+{ "_id" : "18232", "city" : "LANSFORD", "loc" : [ -75.882834, 40.831444 ], "pop" : 4583, "state" : "PA" }
+{ "_id" : "18235", "city" : "WEISSPORT", "loc" : [ -75.70608799999999, 40.830024 ], "pop" : 17675, "state" : "PA" }
+{ "_id" : "18237", "city" : "MCADOO", "loc" : [ -75.997117, 40.89791 ], "pop" : 4184, "state" : "PA" }
+{ "_id" : "18240", "city" : "NESQUEHONING", "loc" : [ -75.82389000000001, 40.862608 ], "pop" : 3364, "state" : "PA" }
+{ "_id" : "18245", "city" : "QUAKAKE", "loc" : [ -75.982477, 40.849337 ], "pop" : 1292, "state" : "PA" }
+{ "_id" : "18246", "city" : "ROCK GLEN", "loc" : [ -76.16376099999999, 40.964628 ], "pop" : 1938, "state" : "PA" }
+{ "_id" : "18248", "city" : "SHEPPTON", "loc" : [ -76.137952, 40.888073 ], "pop" : 1374, "state" : "PA" }
+{ "_id" : "18249", "city" : "SUGARLOAF", "loc" : [ -76.07165500000001, 40.997126 ], "pop" : 5007, "state" : "PA" }
+{ "_id" : "18250", "city" : "SUMMIT HILL", "loc" : [ -75.869275, 40.825524 ], "pop" : 3332, "state" : "PA" }
+{ "_id" : "18252", "city" : "TAMAQUA", "loc" : [ -75.97353, 40.798319 ], "pop" : 10446, "state" : "PA" }
+{ "_id" : "18255", "city" : "WEATHERLY", "loc" : [ -75.830635, 40.941085 ], "pop" : 4295, "state" : "PA" }
+{ "_id" : "18301", "city" : "EAST STROUDSBURG", "loc" : [ -75.173463, 41.036714 ], "pop" : 26726, "state" : "PA" }
+{ "_id" : "18321", "city" : "BARTONSVILLE", "loc" : [ -75.29672600000001, 41.008007 ], "pop" : 553, "state" : "PA" }
+{ "_id" : "18322", "city" : "BRODHEADSVILLE", "loc" : [ -75.410415, 40.930862 ], "pop" : 1834, "state" : "PA" }
+{ "_id" : "18324", "city" : "BUSHKILL", "loc" : [ -75.01320699999999, 41.128476 ], "pop" : 2483, "state" : "PA" }
+{ "_id" : "18325", "city" : "CANADENSIS", "loc" : [ -75.257288, 41.233791 ], "pop" : 2194, "state" : "PA" }
+{ "_id" : "18326", "city" : "CRESCO", "loc" : [ -75.26822799999999, 41.160605 ], "pop" : 3074, "state" : "PA" }
+{ "_id" : "18327", "city" : "DELAWARE WATER G", "loc" : [ -75.149987, 40.982863 ], "pop" : 1052, "state" : "PA" }
+{ "_id" : "18328", "city" : "DINGMANS FERRY", "loc" : [ -74.938018, 41.239966 ], "pop" : 3705, "state" : "PA" }
+{ "_id" : "18330", "city" : "EFFORT", "loc" : [ -75.452286, 40.966946 ], "pop" : 3817, "state" : "PA" }
+{ "_id" : "18331", "city" : "GILBERT", "loc" : [ -75.43137299999999, 40.908866 ], "pop" : 405, "state" : "PA" }
+{ "_id" : "18332", "city" : "HENRYVILLE", "loc" : [ -75.279753, 41.088912 ], "pop" : 1927, "state" : "PA" }
+{ "_id" : "18333", "city" : "KRESGEVILLE", "loc" : [ -75.507437, 40.898156 ], "pop" : 1125, "state" : "PA" }
+{ "_id" : "18334", "city" : "LONG POND", "loc" : [ -75.448245, 41.067732 ], "pop" : 667, "state" : "PA" }
+{ "_id" : "18336", "city" : "MATAMORAS", "loc" : [ -74.71535799999999, 41.367437 ], "pop" : 3391, "state" : "PA" }
+{ "_id" : "18337", "city" : "MILFORD", "loc" : [ -74.88236000000001, 41.322816 ], "pop" : 6668, "state" : "PA" }
+{ "_id" : "18340", "city" : "MILLRIFT", "loc" : [ -74.773876, 41.358265 ], "pop" : 649, "state" : "PA" }
+{ "_id" : "18343", "city" : "MOUNT BETHEL", "loc" : [ -75.11154500000001, 40.900839 ], "pop" : 3966, "state" : "PA" }
+{ "_id" : "18344", "city" : "MOUNT POCONO", "loc" : [ -75.352868, 41.121558 ], "pop" : 2465, "state" : "PA" }
+{ "_id" : "18346", "city" : "POCONO SUMMIT", "loc" : [ -75.413554, 41.103989 ], "pop" : 1509, "state" : "PA" }
+{ "_id" : "18347", "city" : "POCONO LAKE", "loc" : [ -75.555863, 41.118661 ], "pop" : 1943, "state" : "PA" }
+{ "_id" : "18350", "city" : "POCONO PINES", "loc" : [ -75.476038, 41.105387 ], "pop" : 866, "state" : "PA" }
+{ "_id" : "18352", "city" : "REEDERS", "loc" : [ -75.278113, 40.989533 ], "pop" : 481, "state" : "PA" }
+{ "_id" : "18353", "city" : "SAYLORSBURG", "loc" : [ -75.37476100000001, 40.917179 ], "pop" : 6970, "state" : "PA" }
+{ "_id" : "18354", "city" : "SCIOTA", "loc" : [ -75.293779, 40.928282 ], "pop" : 4155, "state" : "PA" }
+{ "_id" : "18355", "city" : "SCOTRUN", "loc" : [ -75.32646, 41.075147 ], "pop" : 966, "state" : "PA" }
+{ "_id" : "18360", "city" : "STROUDSBURG", "loc" : [ -75.24852, 40.987697 ], "pop" : 17668, "state" : "PA" }
+{ "_id" : "18370", "city" : "SWIFTWATER", "loc" : [ -75.34827799999999, 41.087936 ], "pop" : 838, "state" : "PA" }
+{ "_id" : "18371", "city" : "TAMIMENT", "loc" : [ -74.952614, 41.168112 ], "pop" : 557, "state" : "PA" }
+{ "_id" : "18372", "city" : "TANNERSVILLE", "loc" : [ -75.309984, 41.048202 ], "pop" : 2353, "state" : "PA" }
+{ "_id" : "18401", "city" : "ALDENVILLE", "loc" : [ -75.36749, 41.642679 ], "pop" : 422, "state" : "PA" }
+{ "_id" : "18403", "city" : "EYNON", "loc" : [ -75.555232, 41.495633 ], "pop" : 6489, "state" : "PA" }
+{ "_id" : "18405", "city" : "BEACH LAKE", "loc" : [ -75.11649, 41.603403 ], "pop" : 918, "state" : "PA" }
+{ "_id" : "18407", "city" : "SIMPSON", "loc" : [ -75.507363, 41.583481 ], "pop" : 16409, "state" : "PA" }
+{ "_id" : "18411", "city" : "CLARKS SUMMIT", "loc" : [ -75.705713, 41.487795 ], "pop" : 23088, "state" : "PA" }
+{ "_id" : "18414", "city" : "DALTON", "loc" : [ -75.703737, 41.539496 ], "pop" : 7621, "state" : "PA" }
+{ "_id" : "18415", "city" : "DAMASCUS", "loc" : [ -75.131151, 41.736623 ], "pop" : 1206, "state" : "PA" }
+{ "_id" : "18417", "city" : "EQUINUNK", "loc" : [ -75.189081, 41.811712 ], "pop" : 663, "state" : "PA" }
+{ "_id" : "18419", "city" : "FACTORYVILLE", "loc" : [ -75.765182, 41.576168 ], "pop" : 4402, "state" : "PA" }
+{ "_id" : "18421", "city" : "BROWNDALE", "loc" : [ -75.48725, 41.654587 ], "pop" : 3728, "state" : "PA" }
+{ "_id" : "18424", "city" : "GOULDSBORO", "loc" : [ -75.503653, 41.2448 ], "pop" : 2805, "state" : "PA" }
+{ "_id" : "18425", "city" : "GREELEY", "loc" : [ -75.012491, 41.437238 ], "pop" : 1121, "state" : "PA" }
+{ "_id" : "18426", "city" : "GREENTOWN", "loc" : [ -75.28191099999999, 41.332145 ], "pop" : 1592, "state" : "PA" }
+{ "_id" : "18427", "city" : "HAMLIN", "loc" : [ -75.354232, 41.401477 ], "pop" : 1575, "state" : "PA" }
+{ "_id" : "18428", "city" : "HAWLEY", "loc" : [ -75.197822, 41.478685 ], "pop" : 2817, "state" : "PA" }
+{ "_id" : "18430", "city" : "HERRICK CENTER", "loc" : [ -75.50438699999999, 41.76434 ], "pop" : 218, "state" : "PA" }
+{ "_id" : "18431", "city" : "HONESDALE", "loc" : [ -75.25279, 41.579227 ], "pop" : 12655, "state" : "PA" }
+{ "_id" : "18433", "city" : "MAYFIELD", "loc" : [ -75.542948, 41.532723 ], "pop" : 4274, "state" : "PA" }
+{ "_id" : "18434", "city" : "JESSUP", "loc" : [ -75.56889099999999, 41.472443 ], "pop" : 4349, "state" : "PA" }
+{ "_id" : "18435", "city" : "LACKAWAXEN", "loc" : [ -75.074859, 41.504272 ], "pop" : 1711, "state" : "PA" }
+{ "_id" : "18436", "city" : "LAKE ARIEL", "loc" : [ -75.431257, 41.439476 ], "pop" : 7939, "state" : "PA" }
+{ "_id" : "18437", "city" : "LAKE COMO", "loc" : [ -75.32308, 41.866553 ], "pop" : 415, "state" : "PA" }
+{ "_id" : "18438", "city" : "LAKEVILLE", "loc" : [ -75.260717, 41.422278 ], "pop" : 1028, "state" : "PA" }
+{ "_id" : "18439", "city" : "LAKEWOOD", "loc" : [ -75.383824, 41.817138 ], "pop" : 653, "state" : "PA" }
+{ "_id" : "18441", "city" : "LENOXVILLE", "loc" : [ -75.631934, 41.667713 ], "pop" : 587, "state" : "PA" }
+{ "_id" : "18443", "city" : "MILANVILLE", "loc" : [ -75.08817999999999, 41.649208 ], "pop" : 922, "state" : "PA" }
+{ "_id" : "18444", "city" : "MOSCOW", "loc" : [ -75.530137, 41.343194 ], "pop" : 10881, "state" : "PA" }
+{ "_id" : "18445", "city" : "NEWFOUNDLAND", "loc" : [ -75.33840499999999, 41.304125 ], "pop" : 659, "state" : "PA" }
+{ "_id" : "18446", "city" : "NICHOLSON", "loc" : [ -75.764073, 41.641198 ], "pop" : 3513, "state" : "PA" }
+{ "_id" : "18447", "city" : "OLYPHANT", "loc" : [ -75.601502, 41.467709 ], "pop" : 7421, "state" : "PA" }
+{ "_id" : "18451", "city" : "PAUPACK", "loc" : [ -75.23032000000001, 41.381197 ], "pop" : 887, "state" : "PA" }
+{ "_id" : "18452", "city" : "PECKVILLE", "loc" : [ -75.589884, 41.482124 ], "pop" : 6252, "state" : "PA" }
+{ "_id" : "18453", "city" : "PLEASANT MOUNT", "loc" : [ -75.398944, 41.732204 ], "pop" : 1232, "state" : "PA" }
+{ "_id" : "18455", "city" : "PRESTON PARK", "loc" : [ -75.38314699999999, 41.867264 ], "pop" : 224, "state" : "PA" }
+{ "_id" : "18456", "city" : "PROMPTON", "loc" : [ -75.32074900000001, 41.582031 ], "pop" : 552, "state" : "PA" }
+{ "_id" : "18458", "city" : "SHOHOLA", "loc" : [ -74.917962, 41.418193 ], "pop" : 1586, "state" : "PA" }
+{ "_id" : "18460", "city" : "SOUTH STERLING", "loc" : [ -75.381443, 41.271222 ], "pop" : 922, "state" : "PA" }
+{ "_id" : "18461", "city" : "STARLIGHT", "loc" : [ -75.32123799999999, 41.925087 ], "pop" : 431, "state" : "PA" }
+{ "_id" : "18462", "city" : "STARRUCCA", "loc" : [ -75.449001, 41.890739 ], "pop" : 333, "state" : "PA" }
+{ "_id" : "18463", "city" : "STERLING", "loc" : [ -75.39446700000001, 41.341912 ], "pop" : 689, "state" : "PA" }
+{ "_id" : "18464", "city" : "TAFTON", "loc" : [ -75.101598, 41.369445 ], "pop" : 2752, "state" : "PA" }
+{ "_id" : "18465", "city" : "THOMPSON", "loc" : [ -75.534215, 41.83395 ], "pop" : 1277, "state" : "PA" }
+{ "_id" : "18466", "city" : "TOBYHANNA", "loc" : [ -75.39178099999999, 41.183638 ], "pop" : 6668, "state" : "PA" }
+{ "_id" : "18469", "city" : "TYLER HILL", "loc" : [ -75.154246, 41.670873 ], "pop" : 592, "state" : "PA" }
+{ "_id" : "18470", "city" : "UNION DALE", "loc" : [ -75.546476, 41.707941 ], "pop" : 1325, "state" : "PA" }
+{ "_id" : "18472", "city" : "WAYMART", "loc" : [ -75.40647800000001, 41.570276 ], "pop" : 3922, "state" : "PA" }
+{ "_id" : "18503", "city" : "SCRANTON", "loc" : [ -75.664205, 41.409517 ], "pop" : 720, "state" : "PA" }
+{ "_id" : "18504", "city" : "SCRANTON", "loc" : [ -75.686081, 41.412777 ], "pop" : 22279, "state" : "PA" }
+{ "_id" : "18505", "city" : "SCRANTON", "loc" : [ -75.665738, 41.39145 ], "pop" : 21733, "state" : "PA" }
+{ "_id" : "18507", "city" : "MOOSIC", "loc" : [ -75.71709300000001, 41.361492 ], "pop" : 5339, "state" : "PA" }
+{ "_id" : "18508", "city" : "SCRANTON", "loc" : [ -75.66252900000001, 41.438917 ], "pop" : 13555, "state" : "PA" }
+{ "_id" : "18509", "city" : "SCRANTON", "loc" : [ -75.64645400000001, 41.427353 ], "pop" : 15432, "state" : "PA" }
+{ "_id" : "18510", "city" : "SCRANTON", "loc" : [ -75.648397, 41.408039 ], "pop" : 14306, "state" : "PA" }
+{ "_id" : "18512", "city" : "DUNMORE", "loc" : [ -75.62294, 41.426184 ], "pop" : 14428, "state" : "PA" }
+{ "_id" : "18517", "city" : "TAYLOR", "loc" : [ -75.71584799999999, 41.390442 ], "pop" : 5738, "state" : "PA" }
+{ "_id" : "18518", "city" : "OLD FORGE", "loc" : [ -75.739075, 41.370076 ], "pop" : 8834, "state" : "PA" }
+{ "_id" : "18519", "city" : "DICKSON CITY", "loc" : [ -75.624343, 41.462306 ], "pop" : 5012, "state" : "PA" }
+{ "_id" : "18603", "city" : "BERWICK", "loc" : [ -76.244269, 41.066477 ], "pop" : 19977, "state" : "PA" }
+{ "_id" : "18610", "city" : "BLAKESLEE", "loc" : [ -75.53430899999999, 41.048502 ], "pop" : 426, "state" : "PA" }
+{ "_id" : "18612", "city" : "COLLEGE MISERICO", "loc" : [ -75.958911, 41.363762 ], "pop" : 13726, "state" : "PA" }
+{ "_id" : "18614", "city" : "DUSHORE", "loc" : [ -76.402145, 41.523213 ], "pop" : 1739, "state" : "PA" }
+{ "_id" : "18615", "city" : "FALLS", "loc" : [ -75.856004, 41.466677 ], "pop" : 2349, "state" : "PA" }
+{ "_id" : "18616", "city" : "FORKSVILLE", "loc" : [ -76.60079, 41.526925 ], "pop" : 1080, "state" : "PA" }
+{ "_id" : "18617", "city" : "GLEN LYON", "loc" : [ -76.074578, 41.174635 ], "pop" : 2082, "state" : "PA" }
+{ "_id" : "18618", "city" : "HARVEYS LAKE", "loc" : [ -76.04506000000001, 41.359181 ], "pop" : 3404, "state" : "PA" }
+{ "_id" : "18619", "city" : "HILLSGROVE", "loc" : [ -76.697914, 41.448159 ], "pop" : 337, "state" : "PA" }
+{ "_id" : "18621", "city" : "HUNLOCK CREEK", "loc" : [ -76.087915, 41.245923 ], "pop" : 4207, "state" : "PA" }
+{ "_id" : "18622", "city" : "HUNTINGTON MILLS", "loc" : [ -76.19734200000001, 41.200905 ], "pop" : 345, "state" : "PA" }
+{ "_id" : "18623", "city" : "LACEYVILLE", "loc" : [ -76.142566, 41.66621 ], "pop" : 3195, "state" : "PA" }
+{ "_id" : "18624", "city" : "LAKE HARMONY", "loc" : [ -75.633129, 41.05424 ], "pop" : 1203, "state" : "PA" }
+{ "_id" : "18628", "city" : "LOPEZ", "loc" : [ -76.300206, 41.418002 ], "pop" : 600, "state" : "PA" }
+{ "_id" : "18629", "city" : "MEHOOPANY", "loc" : [ -76.10346199999999, 41.558695 ], "pop" : 1630, "state" : "PA" }
+{ "_id" : "18630", "city" : "MESHOPPEN", "loc" : [ -76.01546399999999, 41.639163 ], "pop" : 3307, "state" : "PA" }
+{ "_id" : "18631", "city" : "MIFFLINVILLE", "loc" : [ -76.292396, 41.023473 ], "pop" : 2297, "state" : "PA" }
+{ "_id" : "18632", "city" : "MILDRED", "loc" : [ -76.38312999999999, 41.479236 ], "pop" : 500, "state" : "PA" }
+{ "_id" : "18634", "city" : "NANTICOKE", "loc" : [ -76.004419, 41.19634 ], "pop" : 14778, "state" : "PA" }
+{ "_id" : "18635", "city" : "NESCOPECK", "loc" : [ -76.19808999999999, 41.046887 ], "pop" : 2723, "state" : "PA" }
+{ "_id" : "18636", "city" : "NOXEN", "loc" : [ -76.045952, 41.418131 ], "pop" : 1653, "state" : "PA" }
+{ "_id" : "18640", "city" : "PITTSTON", "loc" : [ -75.78849200000001, 41.317501 ], "pop" : 18888, "state" : "PA" }
+{ "_id" : "18641", "city" : "AVOCA", "loc" : [ -75.74465499999999, 41.330857 ], "pop" : 6485, "state" : "PA" }
+{ "_id" : "18642", "city" : "DURYEA", "loc" : [ -75.761104, 41.348557 ], "pop" : 4262, "state" : "PA" }
+{ "_id" : "18643", "city" : "WEST PITTSTON", "loc" : [ -75.81665099999999, 41.337964 ], "pop" : 13853, "state" : "PA" }
+{ "_id" : "18644", "city" : "WYOMING", "loc" : [ -75.854071, 41.319713 ], "pop" : 8126, "state" : "PA" }
+{ "_id" : "18651", "city" : "PLYMOUTH", "loc" : [ -75.948064, 41.245798 ], "pop" : 11895, "state" : "PA" }
+{ "_id" : "18655", "city" : "MOCANAQUA", "loc" : [ -76.167096, 41.176674 ], "pop" : 6324, "state" : "PA" }
+{ "_id" : "18656", "city" : "SWEET VALLEY", "loc" : [ -76.13390699999999, 41.30663 ], "pop" : 3237, "state" : "PA" }
+{ "_id" : "18657", "city" : "CENTER MORELAND", "loc" : [ -75.94104299999999, 41.550687 ], "pop" : 9921, "state" : "PA" }
+{ "_id" : "18660", "city" : "WAPWALLOPEN", "loc" : [ -76.085729, 41.06797 ], "pop" : 1198, "state" : "PA" }
+{ "_id" : "18661", "city" : "WHITE HAVEN", "loc" : [ -75.77149199999999, 41.079049 ], "pop" : 4435, "state" : "PA" }
+{ "_id" : "18701", "city" : "WILKES BARRE", "loc" : [ -75.884063, 41.244892 ], "pop" : 4320, "state" : "PA" }
+{ "_id" : "18702", "city" : "HANOVER TOWNSHIP", "loc" : [ -75.88255700000001, 41.236512 ], "pop" : 54119, "state" : "PA" }
+{ "_id" : "18704", "city" : "KINGSTON", "loc" : [ -75.890338, 41.274223 ], "pop" : 33661, "state" : "PA" }
+{ "_id" : "18705", "city" : "WILKES BARRE", "loc" : [ -75.845309, 41.268921 ], "pop" : 17504, "state" : "PA" }
+{ "_id" : "18706", "city" : "ASHLEY", "loc" : [ -75.91815699999999, 41.206709 ], "pop" : 7980, "state" : "PA" }
+{ "_id" : "18707", "city" : "MOUNTAIN TOP", "loc" : [ -75.937642, 41.134975 ], "pop" : 13244, "state" : "PA" }
+{ "_id" : "18708", "city" : "SHAVERTOWN", "loc" : [ -75.97108, 41.299802 ], "pop" : 12656, "state" : "PA" }
+{ "_id" : "18709", "city" : "LUZERNE", "loc" : [ -75.893475, 41.284257 ], "pop" : 3157, "state" : "PA" }
+{ "_id" : "18801", "city" : "MONTROSE", "loc" : [ -75.88205499999999, 41.839584 ], "pop" : 6624, "state" : "PA" }
+{ "_id" : "18810", "city" : "ATHENS", "loc" : [ -76.488855, 41.949002 ], "pop" : 7602, "state" : "PA" }
+{ "_id" : "18812", "city" : "BRACKNEY", "loc" : [ -75.937527, 41.966614 ], "pop" : 1645, "state" : "PA" }
+{ "_id" : "18817", "city" : "EAST SMITHFIELD", "loc" : [ -76.61720699999999, 41.863115 ], "pop" : 1520, "state" : "PA" }
+{ "_id" : "18818", "city" : "FRIENDSVILLE", "loc" : [ -76.02569, 41.916445 ], "pop" : 1844, "state" : "PA" }
+{ "_id" : "18821", "city" : "GREAT BEND", "loc" : [ -75.732742, 41.977513 ], "pop" : 1654, "state" : "PA" }
+{ "_id" : "18822", "city" : "HALLSTEAD", "loc" : [ -75.782595, 41.959798 ], "pop" : 2970, "state" : "PA" }
+{ "_id" : "18823", "city" : "HARFORD", "loc" : [ -75.67863199999999, 41.779891 ], "pop" : 1155, "state" : "PA" }
+{ "_id" : "18824", "city" : "HOP BOTTOM", "loc" : [ -75.78965599999999, 41.693196 ], "pop" : 1088, "state" : "PA" }
+{ "_id" : "18825", "city" : "JACKSON", "loc" : [ -75.60913600000001, 41.864881 ], "pop" : 668, "state" : "PA" }
+{ "_id" : "18826", "city" : "KINGSLEY", "loc" : [ -75.783101, 41.765856 ], "pop" : 1159, "state" : "PA" }
+{ "_id" : "18828", "city" : "LAWTON", "loc" : [ -76.09121399999999, 41.757294 ], "pop" : 15, "state" : "PA" }
+{ "_id" : "18829", "city" : "LE RAYSVILLE", "loc" : [ -76.179604, 41.843415 ], "pop" : 1020, "state" : "PA" }
+{ "_id" : "18830", "city" : "LITTLE MEADOWS", "loc" : [ -76.118472, 41.976593 ], "pop" : 750, "state" : "PA" }
+{ "_id" : "18831", "city" : "MILAN", "loc" : [ -76.532777, 41.896555 ], "pop" : 328, "state" : "PA" }
+{ "_id" : "18832", "city" : "MONROETON", "loc" : [ -76.500995, 41.699387 ], "pop" : 2332, "state" : "PA" }
+{ "_id" : "18833", "city" : "NEW ALBANY", "loc" : [ -76.43983, 41.59867 ], "pop" : 1390, "state" : "PA" }
+{ "_id" : "18834", "city" : "NEW MILFORD", "loc" : [ -75.717113, 41.866409 ], "pop" : 2684, "state" : "PA" }
+{ "_id" : "18837", "city" : "ROME", "loc" : [ -76.301498, 41.863403 ], "pop" : 2053, "state" : "PA" }
+{ "_id" : "18839", "city" : "RUSHVILLE", "loc" : [ -76.050955, 41.776893 ], "pop" : 1228, "state" : "PA" }
+{ "_id" : "18840", "city" : "SAYRE", "loc" : [ -76.52175699999999, 41.984222 ], "pop" : 10320, "state" : "PA" }
+{ "_id" : "18842", "city" : "SOUTH GIBSON", "loc" : [ -75.606723, 41.754373 ], "pop" : 402, "state" : "PA" }
+{ "_id" : "18844", "city" : "SPRINGVILLE", "loc" : [ -75.902472, 41.714684 ], "pop" : 2003, "state" : "PA" }
+{ "_id" : "18845", "city" : "STEVENSVILLE", "loc" : [ -76.171696, 41.771782 ], "pop" : 401, "state" : "PA" }
+{ "_id" : "18846", "city" : "SUGAR RUN", "loc" : [ -76.25978499999999, 41.604057 ], "pop" : 1057, "state" : "PA" }
+{ "_id" : "18847", "city" : "SUSQUEHANNA", "loc" : [ -75.586249, 41.948669 ], "pop" : 5137, "state" : "PA" }
+{ "_id" : "18848", "city" : "TOWANDA", "loc" : [ -76.464527, 41.763758 ], "pop" : 7449, "state" : "PA" }
+{ "_id" : "18850", "city" : "ULSTER", "loc" : [ -76.487574, 41.840809 ], "pop" : 2049, "state" : "PA" }
+{ "_id" : "18851", "city" : "WARREN CENTER", "loc" : [ -76.196445, 41.939389 ], "pop" : 927, "state" : "PA" }
+{ "_id" : "18853", "city" : "WYALUSING", "loc" : [ -76.27543300000001, 41.701499 ], "pop" : 3439, "state" : "PA" }
+{ "_id" : "18854", "city" : "WYSOX", "loc" : [ -76.383397, 41.782621 ], "pop" : 2121, "state" : "PA" }
+{ "_id" : "18901", "city" : "NEW BRITAIN", "loc" : [ -75.129987, 40.320391 ], "pop" : 33133, "state" : "PA" }
+{ "_id" : "18913", "city" : "CARVERSVILLE", "loc" : [ -75.06312699999999, 40.39079 ], "pop" : 579, "state" : "PA" }
+{ "_id" : "18914", "city" : "CHALFONT", "loc" : [ -75.214938, 40.289175 ], "pop" : 12838, "state" : "PA" }
+{ "_id" : "18915", "city" : "COLMAR", "loc" : [ -75.26686100000001, 40.271814 ], "pop" : 2168, "state" : "PA" }
+{ "_id" : "18917", "city" : "DUBLIN", "loc" : [ -75.204453, 40.371996 ], "pop" : 1985, "state" : "PA" }
+{ "_id" : "18920", "city" : "ERWINNA", "loc" : [ -75.080372, 40.508689 ], "pop" : 573, "state" : "PA" }
+{ "_id" : "18923", "city" : "FOUNTAINVILLE", "loc" : [ -75.153627, 40.336815 ], "pop" : 261, "state" : "PA" }
+{ "_id" : "18925", "city" : "FURLONG", "loc" : [ -75.06494600000001, 40.294518 ], "pop" : 3789, "state" : "PA" }
+{ "_id" : "18927", "city" : "HILLTOWN", "loc" : [ -75.27118, 40.34762 ], "pop" : 881, "state" : "PA" }
+{ "_id" : "18929", "city" : "JAMISON", "loc" : [ -75.096093, 40.256599 ], "pop" : 3797, "state" : "PA" }
+{ "_id" : "18930", "city" : "KINTNERSVILLE", "loc" : [ -75.211708, 40.531009 ], "pop" : 2997, "state" : "PA" }
+{ "_id" : "18932", "city" : "LINE LEXINGTON", "loc" : [ -75.25553499999999, 40.288781 ], "pop" : 301, "state" : "PA" }
+{ "_id" : "18933", "city" : "LUMBERVILLE", "loc" : [ -75.055166, 40.407103 ], "pop" : 382, "state" : "PA" }
+{ "_id" : "18934", "city" : "MECHANICSVILLE", "loc" : [ -75.062962, 40.343821 ], "pop" : 429, "state" : "PA" }
+{ "_id" : "18936", "city" : "MONTGOMERYVILLE", "loc" : [ -75.23464300000001, 40.251353 ], "pop" : 5520, "state" : "PA" }
+{ "_id" : "18938", "city" : "NEW HOPE", "loc" : [ -74.983889, 40.355613 ], "pop" : 7111, "state" : "PA" }
+{ "_id" : "18940", "city" : "GEORGE SCHOOL", "loc" : [ -74.94313, 40.245817 ], "pop" : 21946, "state" : "PA" }
+{ "_id" : "18942", "city" : "OTTSVILLE", "loc" : [ -75.157009, 40.459239 ], "pop" : 2976, "state" : "PA" }
+{ "_id" : "18944", "city" : "PERKASIE", "loc" : [ -75.264803, 40.376526 ], "pop" : 18235, "state" : "PA" }
+{ "_id" : "18947", "city" : "PIPERSVILLE", "loc" : [ -75.107398, 40.4262 ], "pop" : 3856, "state" : "PA" }
+{ "_id" : "18951", "city" : "QUAKERTOWN", "loc" : [ -75.350667, 40.4411 ], "pop" : 28546, "state" : "PA" }
+{ "_id" : "18954", "city" : "RICHBORO", "loc" : [ -75.00293600000001, 40.216672 ], "pop" : 8006, "state" : "PA" }
+{ "_id" : "18955", "city" : "RICHLANDTOWN", "loc" : [ -75.32192999999999, 40.472166 ], "pop" : 1199, "state" : "PA" }
+{ "_id" : "18960", "city" : "SELLERSVILLE", "loc" : [ -75.31895299999999, 40.362024 ], "pop" : 8387, "state" : "PA" }
+{ "_id" : "18964", "city" : "BETHTON", "loc" : [ -75.32133899999999, 40.312796 ], "pop" : 9350, "state" : "PA" }
+{ "_id" : "18966", "city" : "HOLLAND", "loc" : [ -75.005994, 40.190212 ], "pop" : 38866, "state" : "PA" }
+{ "_id" : "18969", "city" : "TELFORD", "loc" : [ -75.352001, 40.320478 ], "pop" : 10929, "state" : "PA" }
+{ "_id" : "18972", "city" : "UPPER BLACK EDDY", "loc" : [ -75.12585799999999, 40.541093 ], "pop" : 3443, "state" : "PA" }
+{ "_id" : "18974", "city" : "WARMINSTER", "loc" : [ -75.090513, 40.206676 ], "pop" : 37759, "state" : "PA" }
+{ "_id" : "18976", "city" : "WARRINGTON", "loc" : [ -75.135392, 40.246438 ], "pop" : 13862, "state" : "PA" }
+{ "_id" : "18977", "city" : "WASHINGTON CROSS", "loc" : [ -74.882859, 40.291906 ], "pop" : 2824, "state" : "PA" }
+{ "_id" : "19001", "city" : "OGONTZ CAMPUS", "loc" : [ -75.128918, 40.128141 ], "pop" : 17302, "state" : "PA" }
+{ "_id" : "19002", "city" : "MAPLE GLEN", "loc" : [ -75.207234, 40.166318 ], "pop" : 24133, "state" : "PA" }
+{ "_id" : "19003", "city" : "ARDMORE", "loc" : [ -75.29665, 40.001971 ], "pop" : 12443, "state" : "PA" }
+{ "_id" : "19004", "city" : "BALA CYNWYD", "loc" : [ -75.23421, 40.01179 ], "pop" : 9239, "state" : "PA" }
+{ "_id" : "19006", "city" : "HUNTINGDON VALLE", "loc" : [ -75.05897899999999, 40.129686 ], "pop" : 19866, "state" : "PA" }
+{ "_id" : "19007", "city" : "TULLYTOWN", "loc" : [ -74.86071800000001, 40.109174 ], "pop" : 22334, "state" : "PA" }
+{ "_id" : "19008", "city" : "BROOMALL", "loc" : [ -75.360214, 39.974666 ], "pop" : 20432, "state" : "PA" }
+{ "_id" : "19010", "city" : "BRYN MAWR", "loc" : [ -75.329487, 40.023618 ], "pop" : 21826, "state" : "PA" }
+{ "_id" : "19012", "city" : "CHELTENHAM", "loc" : [ -75.10477400000001, 40.060327 ], "pop" : 6912, "state" : "PA" }
+{ "_id" : "19013", "city" : "CHESTER", "loc" : [ -75.37468699999999, 39.849817 ], "pop" : 49144, "state" : "PA" }
+{ "_id" : "19014", "city" : "ASTON", "loc" : [ -75.43321, 39.864282 ], "pop" : 18171, "state" : "PA" }
+{ "_id" : "19015", "city" : "BROOKHAVEN", "loc" : [ -75.38848299999999, 39.865355 ], "pop" : 17321, "state" : "PA" }
+{ "_id" : "19018", "city" : "PRIMOS SECANE", "loc" : [ -75.299592, 39.923579 ], "pop" : 23885, "state" : "PA" }
+{ "_id" : "19020", "city" : "BENSALEM", "loc" : [ -74.937753, 40.110881 ], "pop" : 51884, "state" : "PA" }
+{ "_id" : "19021", "city" : "CROYDON", "loc" : [ -74.89907700000001, 40.093322 ], "pop" : 10198, "state" : "PA" }
+{ "_id" : "19022", "city" : "CRUM LYNNE", "loc" : [ -75.337397, 39.868457 ], "pop" : 769, "state" : "PA" }
+{ "_id" : "19023", "city" : "COLLINGDALE", "loc" : [ -75.266226, 39.916732 ], "pop" : 23274, "state" : "PA" }
+{ "_id" : "19025", "city" : "DRESHER", "loc" : [ -75.162379, 40.143141 ], "pop" : 4089, "state" : "PA" }
+{ "_id" : "19026", "city" : "PILGRIM GARDENS", "loc" : [ -75.303479, 39.949197 ], "pop" : 32559, "state" : "PA" }
+{ "_id" : "19029", "city" : "LESTER", "loc" : [ -75.293521, 39.866864 ], "pop" : 4440, "state" : "PA" }
+{ "_id" : "19030", "city" : "FAIRLESS HILLS", "loc" : [ -74.851923, 40.174822 ], "pop" : 13433, "state" : "PA" }
+{ "_id" : "19031", "city" : "FLOURTOWN", "loc" : [ -75.21147999999999, 40.106774 ], "pop" : 4284, "state" : "PA" }
+{ "_id" : "19032", "city" : "FOLCROFT", "loc" : [ -75.282117, 39.890508 ], "pop" : 7399, "state" : "PA" }
+{ "_id" : "19033", "city" : "FOLSOM", "loc" : [ -75.329567, 39.890129 ], "pop" : 7677, "state" : "PA" }
+{ "_id" : "19034", "city" : "FORT WASHINGTON", "loc" : [ -75.202175, 40.138592 ], "pop" : 6787, "state" : "PA" }
+{ "_id" : "19035", "city" : "GLADWYNE", "loc" : [ -75.282082, 40.045118 ], "pop" : 3742, "state" : "PA" }
+{ "_id" : "19036", "city" : "GLENOLDEN", "loc" : [ -75.29455900000001, 39.904848 ], "pop" : 14390, "state" : "PA" }
+{ "_id" : "19038", "city" : "GLENSIDE", "loc" : [ -75.15496400000001, 40.10959 ], "pop" : 23067, "state" : "PA" }
+{ "_id" : "19040", "city" : "HATBORO", "loc" : [ -75.10718199999999, 40.178547 ], "pop" : 21765, "state" : "PA" }
+{ "_id" : "19041", "city" : "HAVERFORD", "loc" : [ -75.312116, 40.009739 ], "pop" : 6560, "state" : "PA" }
+{ "_id" : "19043", "city" : "HOLMES", "loc" : [ -75.308674, 39.900284 ], "pop" : 2747, "state" : "PA" }
+{ "_id" : "19044", "city" : "HORSHAM", "loc" : [ -75.147932, 40.182057 ], "pop" : 15131, "state" : "PA" }
+{ "_id" : "19046", "city" : "MEADOWBROOK", "loc" : [ -75.117273, 40.100477 ], "pop" : 14402, "state" : "PA" }
+{ "_id" : "19047", "city" : "PENNDEL", "loc" : [ -74.91510100000001, 40.175055 ], "pop" : 34108, "state" : "PA" }
+{ "_id" : "19050", "city" : "YEADON", "loc" : [ -75.264872, 39.93779 ], "pop" : 30411, "state" : "PA" }
+{ "_id" : "19053", "city" : "FEASTERVILLE TRE", "loc" : [ -74.98375799999999, 40.151188 ], "pop" : 24877, "state" : "PA" }
+{ "_id" : "19054", "city" : "LEVITTOWN", "loc" : [ -74.823138, 40.168142 ], "pop" : 16390, "state" : "PA" }
+{ "_id" : "19055", "city" : "LEVITTOWN", "loc" : [ -74.83714000000001, 40.148329 ], "pop" : 14924, "state" : "PA" }
+{ "_id" : "19056", "city" : "LEVITTOWN", "loc" : [ -74.882632, 40.151861 ], "pop" : 15227, "state" : "PA" }
+{ "_id" : "19057", "city" : "LEVITTOWN", "loc" : [ -74.861366, 40.143359 ], "pop" : 17014, "state" : "PA" }
+{ "_id" : "19061", "city" : "BOOTHWYN", "loc" : [ -75.44830899999999, 39.833934 ], "pop" : 21328, "state" : "PA" }
+{ "_id" : "19063", "city" : "GLEN RIDDLE LIMA", "loc" : [ -75.40722599999999, 39.915562 ], "pop" : 36385, "state" : "PA" }
+{ "_id" : "19064", "city" : "SPRINGFIELD", "loc" : [ -75.333786, 39.929599 ], "pop" : 25179, "state" : "PA" }
+{ "_id" : "19066", "city" : "MERION STATION", "loc" : [ -75.250302, 40.003043 ], "pop" : 5633, "state" : "PA" }
+{ "_id" : "19067", "city" : "YARDLEY", "loc" : [ -74.822153, 40.212064 ], "pop" : 47492, "state" : "PA" }
+{ "_id" : "19070", "city" : "MORTON", "loc" : [ -75.323785, 39.906292 ], "pop" : 6517, "state" : "PA" }
+{ "_id" : "19072", "city" : "NARBERTH", "loc" : [ -75.2594, 40.01768 ], "pop" : 9846, "state" : "PA" }
+{ "_id" : "19073", "city" : "NEWTOWN SQUARE", "loc" : [ -75.406997, 39.986292 ], "pop" : 15024, "state" : "PA" }
+{ "_id" : "19074", "city" : "NORWOOD", "loc" : [ -75.297247, 39.887026 ], "pop" : 6189, "state" : "PA" }
+{ "_id" : "19075", "city" : "ORELAND", "loc" : [ -75.18685000000001, 40.113197 ], "pop" : 7397, "state" : "PA" }
+{ "_id" : "19076", "city" : "PROSPECT PARK", "loc" : [ -75.308165, 39.885737 ], "pop" : 6769, "state" : "PA" }
+{ "_id" : "19078", "city" : "RIDLEY PARK", "loc" : [ -75.321517, 39.878411 ], "pop" : 12624, "state" : "PA" }
+{ "_id" : "19079", "city" : "SHARON HILL", "loc" : [ -75.269524, 39.903511 ], "pop" : 9893, "state" : "PA" }
+{ "_id" : "19081", "city" : "SWARTHMORE", "loc" : [ -75.34742799999999, 39.896724 ], "pop" : 9885, "state" : "PA" }
+{ "_id" : "19082", "city" : "UPPER DARBY", "loc" : [ -75.268128, 39.95785 ], "pop" : 36400, "state" : "PA" }
+{ "_id" : "19083", "city" : "HAVERTOWN", "loc" : [ -75.310613, 39.97736 ], "pop" : 36702, "state" : "PA" }
+{ "_id" : "19085", "city" : "VILLANOVA", "loc" : [ -75.345866, 40.039875 ], "pop" : 7034, "state" : "PA" }
+{ "_id" : "19086", "city" : "WALLINGFORD", "loc" : [ -75.372131, 39.887054 ], "pop" : 11005, "state" : "PA" }
+{ "_id" : "19087", "city" : "RADNOR", "loc" : [ -75.40416, 40.059554 ], "pop" : 30671, "state" : "PA" }
+{ "_id" : "19090", "city" : "WILLOW GROVE NAS", "loc" : [ -75.121297, 40.146725 ], "pop" : 19558, "state" : "PA" }
+{ "_id" : "19094", "city" : "WOODLYN", "loc" : [ -75.34630900000001, 39.875993 ], "pop" : 5186, "state" : "PA" }
+{ "_id" : "19095", "city" : "WYNCOTE", "loc" : [ -75.152417, 40.086673 ], "pop" : 6164, "state" : "PA" }
+{ "_id" : "19096", "city" : "WYNNEWOOD", "loc" : [ -75.27598399999999, 40 ], "pop" : 8285, "state" : "PA" }
+{ "_id" : "19102", "city" : "PHILADELPHIA", "loc" : [ -75.16610900000001, 39.948908 ], "pop" : 3623, "state" : "PA" }
+{ "_id" : "19103", "city" : "PHILADELPHIA", "loc" : [ -75.174136, 39.951285 ], "pop" : 17665, "state" : "PA" }
+{ "_id" : "19104", "city" : "PHILADELPHIA", "loc" : [ -75.202445, 39.959732 ], "pop" : 51295, "state" : "PA" }
+{ "_id" : "19106", "city" : "PHILADELPHIA", "loc" : [ -75.147271, 39.94742 ], "pop" : 7043, "state" : "PA" }
+{ "_id" : "19107", "city" : "PHILADELPHIA", "loc" : [ -75.159339, 39.94867 ], "pop" : 9634, "state" : "PA" }
+{ "_id" : "19111", "city" : "PHILADELPHIA", "loc" : [ -75.08179199999999, 40.059635 ], "pop" : 61416, "state" : "PA" }
+{ "_id" : "19112", "city" : "PHILADELPHIA", "loc" : [ -75.178207, 39.889252 ], "pop" : 4516, "state" : "PA" }
+{ "_id" : "19113", "city" : "PHILADELPHIA", "loc" : [ -75.27519599999999, 39.864998 ], "pop" : 0, "state" : "PA" }
+{ "_id" : "19114", "city" : "PHILADELPHIA", "loc" : [ -74.999032, 40.063356 ], "pop" : 31199, "state" : "PA" }
+{ "_id" : "19115", "city" : "PHILADELPHIA", "loc" : [ -75.04103600000001, 40.090286 ], "pop" : 31339, "state" : "PA" }
+{ "_id" : "19116", "city" : "PHILADELPHIA", "loc" : [ -75.019803, 40.116599 ], "pop" : 32898, "state" : "PA" }
+{ "_id" : "19117", "city" : "ELKINS PARK", "loc" : [ -75.127669, 40.075798 ], "pop" : 12813, "state" : "PA" }
+{ "_id" : "19118", "city" : "PHILADELPHIA", "loc" : [ -75.20059999999999, 40.081247 ], "pop" : 19549, "state" : "PA" }
+{ "_id" : "19119", "city" : "PHILADELPHIA", "loc" : [ -75.186564, 40.054681 ], "pop" : 29935, "state" : "PA" }
+{ "_id" : "19120", "city" : "PHILADELPHIA", "loc" : [ -75.121256, 40.034254 ], "pop" : 63223, "state" : "PA" }
+{ "_id" : "19121", "city" : "PHILADELPHIA", "loc" : [ -75.17400499999999, 39.981085 ], "pop" : 46705, "state" : "PA" }
+{ "_id" : "19122", "city" : "PHILADELPHIA", "loc" : [ -75.145882, 39.978014 ], "pop" : 21177, "state" : "PA" }
+{ "_id" : "19123", "city" : "PHILADELPHIA", "loc" : [ -75.15096800000001, 39.965975 ], "pop" : 12270, "state" : "PA" }
+{ "_id" : "19124", "city" : "PHILADELPHIA", "loc" : [ -75.08952600000001, 40.017798 ], "pop" : 60009, "state" : "PA" }
+{ "_id" : "19125", "city" : "PHILADELPHIA", "loc" : [ -75.12615599999999, 39.978751 ], "pop" : 24521, "state" : "PA" }
+{ "_id" : "19126", "city" : "PHILADELPHIA", "loc" : [ -75.137854, 40.056839 ], "pop" : 22000, "state" : "PA" }
+{ "_id" : "19127", "city" : "PHILADELPHIA", "loc" : [ -75.22416699999999, 40.027512 ], "pop" : 6028, "state" : "PA" }
+{ "_id" : "19128", "city" : "PHILADELPHIA", "loc" : [ -75.223084, 40.040247 ], "pop" : 36845, "state" : "PA" }
+{ "_id" : "19129", "city" : "PHILADELPHIA", "loc" : [ -75.186149, 40.011816 ], "pop" : 13430, "state" : "PA" }
+{ "_id" : "19130", "city" : "PHILADELPHIA", "loc" : [ -75.173467, 39.967677 ], "pop" : 21544, "state" : "PA" }
+{ "_id" : "19131", "city" : "PHILADELPHIA", "loc" : [ -75.22822600000001, 39.98447 ], "pop" : 48270, "state" : "PA" }
+{ "_id" : "19132", "city" : "PHILADELPHIA", "loc" : [ -75.16982, 39.995393 ], "pop" : 49011, "state" : "PA" }
+{ "_id" : "19133", "city" : "PHILADELPHIA", "loc" : [ -75.141505, 39.992467 ], "pop" : 32608, "state" : "PA" }
+{ "_id" : "19134", "city" : "PHILADELPHIA", "loc" : [ -75.11328399999999, 39.99252 ], "pop" : 58607, "state" : "PA" }
+{ "_id" : "19135", "city" : "PHILADELPHIA", "loc" : [ -75.051827, 40.024694 ], "pop" : 32188, "state" : "PA" }
+{ "_id" : "19136", "city" : "PHILADELPHIA", "loc" : [ -75.024388, 40.042159 ], "pop" : 40682, "state" : "PA" }
+{ "_id" : "19137", "city" : "PHILADELPHIA", "loc" : [ -75.072654, 40.000849 ], "pop" : 8395, "state" : "PA" }
+{ "_id" : "19138", "city" : "PHILADELPHIA", "loc" : [ -75.156898, 40.05683 ], "pop" : 37458, "state" : "PA" }
+{ "_id" : "19139", "city" : "PHILADELPHIA", "loc" : [ -75.230301, 39.961166 ], "pop" : 48467, "state" : "PA" }
+{ "_id" : "19140", "city" : "PHILADELPHIA", "loc" : [ -75.14562599999999, 40.011771 ], "pop" : 62864, "state" : "PA" }
+{ "_id" : "19141", "city" : "PHILADELPHIA", "loc" : [ -75.14510900000001, 40.036473 ], "pop" : 38546, "state" : "PA" }
+{ "_id" : "19142", "city" : "PHILADELPHIA", "loc" : [ -75.233796, 39.922332 ], "pop" : 29171, "state" : "PA" }
+{ "_id" : "19143", "city" : "PHILADELPHIA", "loc" : [ -75.228819, 39.944815 ], "pop" : 80454, "state" : "PA" }
+{ "_id" : "19144", "city" : "PHILADELPHIA", "loc" : [ -75.17309899999999, 40.033773 ], "pop" : 46612, "state" : "PA" }
+{ "_id" : "19145", "city" : "PHILADELPHIA", "loc" : [ -75.181194, 39.922724 ], "pop" : 52538, "state" : "PA" }
+{ "_id" : "19146", "city" : "PHILADELPHIA", "loc" : [ -75.17936400000001, 39.937949 ], "pop" : 38870, "state" : "PA" }
+{ "_id" : "19147", "city" : "PHILADELPHIA", "loc" : [ -75.156324, 39.936175 ], "pop" : 34634, "state" : "PA" }
+{ "_id" : "19148", "city" : "PHILADELPHIA", "loc" : [ -75.159538, 39.92068 ], "pop" : 49685, "state" : "PA" }
+{ "_id" : "19149", "city" : "PHILADELPHIA", "loc" : [ -75.066374, 40.036915 ], "pop" : 47535, "state" : "PA" }
+{ "_id" : "19150", "city" : "PHILADELPHIA", "loc" : [ -75.170621, 40.07262 ], "pop" : 27609, "state" : "PA" }
+{ "_id" : "19151", "city" : "PHILADELPHIA", "loc" : [ -75.254492, 39.977199 ], "pop" : 36265, "state" : "PA" }
+{ "_id" : "19152", "city" : "PHILADELPHIA", "loc" : [ -75.047079, 40.060571 ], "pop" : 31225, "state" : "PA" }
+{ "_id" : "19153", "city" : "PHILADELPHIA", "loc" : [ -75.24443100000001, 39.905512 ], "pop" : 13375, "state" : "PA" }
+{ "_id" : "19154", "city" : "PHILADELPHIA", "loc" : [ -74.97805200000001, 40.089738 ], "pop" : 38023, "state" : "PA" }
+{ "_id" : "19301", "city" : "PAOLI", "loc" : [ -75.482702, 40.04259 ], "pop" : 6969, "state" : "PA" }
+{ "_id" : "19310", "city" : "ATGLEN", "loc" : [ -75.970343, 39.945782 ], "pop" : 2318, "state" : "PA" }
+{ "_id" : "19311", "city" : "AVONDALE", "loc" : [ -75.768694, 39.821904 ], "pop" : 4161, "state" : "PA" }
+{ "_id" : "19312", "city" : "BERWYN", "loc" : [ -75.447457, 40.041184 ], "pop" : 9482, "state" : "PA" }
+{ "_id" : "19317", "city" : "CHADDS FORD", "loc" : [ -75.588515, 39.864769 ], "pop" : 4522, "state" : "PA" }
+{ "_id" : "19319", "city" : "CHEYNEY", "loc" : [ -75.548738, 39.917496 ], "pop" : 198, "state" : "PA" }
+{ "_id" : "19320", "city" : "COATESVILLE", "loc" : [ -75.825299, 39.984313 ], "pop" : 39595, "state" : "PA" }
+{ "_id" : "19330", "city" : "COCHRANVILLE", "loc" : [ -75.921381, 39.875686 ], "pop" : 3425, "state" : "PA" }
+{ "_id" : "19333", "city" : "DEVON", "loc" : [ -75.422691, 40.045181 ], "pop" : 6290, "state" : "PA" }
+{ "_id" : "19335", "city" : "DOWNINGTOWN", "loc" : [ -75.718261, 40.016078 ], "pop" : 35056, "state" : "PA" }
+{ "_id" : "19341", "city" : "EXTON", "loc" : [ -75.643196, 40.046817 ], "pop" : 12495, "state" : "PA" }
+{ "_id" : "19342", "city" : "GLEN MILLS", "loc" : [ -75.50487200000001, 39.901515 ], "pop" : 11632, "state" : "PA" }
+{ "_id" : "19343", "city" : "GLENMOORE", "loc" : [ -75.771103, 40.084602 ], "pop" : 6959, "state" : "PA" }
+{ "_id" : "19344", "city" : "HONEY BROOK", "loc" : [ -75.88432, 40.083227 ], "pop" : 8615, "state" : "PA" }
+{ "_id" : "19346", "city" : "KELTON", "loc" : [ -75.875827, 39.795501 ], "pop" : 816, "state" : "PA" }
+{ "_id" : "19348", "city" : "KENNETT SQUARE", "loc" : [ -75.70001999999999, 39.855033 ], "pop" : 16663, "state" : "PA" }
+{ "_id" : "19350", "city" : "LANDENBERG", "loc" : [ -75.78070700000001, 39.769558 ], "pop" : 4787, "state" : "PA" }
+{ "_id" : "19352", "city" : "LINCOLN UNIVERSI", "loc" : [ -75.881784, 39.780905 ], "pop" : 6834, "state" : "PA" }
+{ "_id" : "19355", "city" : "FRAZER", "loc" : [ -75.53302100000001, 40.037123 ], "pop" : 21709, "state" : "PA" }
+{ "_id" : "19362", "city" : "NOTTINGHAM", "loc" : [ -76.035551, 39.74411 ], "pop" : 2814, "state" : "PA" }
+{ "_id" : "19363", "city" : "OXFORD", "loc" : [ -75.981522, 39.782704 ], "pop" : 11545, "state" : "PA" }
+{ "_id" : "19365", "city" : "PARKESBURG", "loc" : [ -75.926041, 39.965388 ], "pop" : 5420, "state" : "PA" }
+{ "_id" : "19372", "city" : "THORNDALE", "loc" : [ -75.76285900000001, 40.000127 ], "pop" : 1712, "state" : "PA" }
+{ "_id" : "19373", "city" : "THORNTON", "loc" : [ -75.531344, 39.904127 ], "pop" : 2305, "state" : "PA" }
+{ "_id" : "19374", "city" : "TOUGHKENAMON", "loc" : [ -75.782533, 39.825117 ], "pop" : 1045, "state" : "PA" }
+{ "_id" : "19380", "city" : "WEST CHESTER", "loc" : [ -75.596231, 39.984458 ], "pop" : 40656, "state" : "PA" }
+{ "_id" : "19382", "city" : "WEST CHESTER", "loc" : [ -75.58819699999999, 39.944081 ], "pop" : 44164, "state" : "PA" }
+{ "_id" : "19390", "city" : "WEST GROVE", "loc" : [ -75.837374, 39.825314 ], "pop" : 7248, "state" : "PA" }
+{ "_id" : "19401", "city" : "NORRISTOWN", "loc" : [ -75.33044599999999, 40.124464 ], "pop" : 46735, "state" : "PA" }
+{ "_id" : "19403", "city" : "EAGLEVILLE", "loc" : [ -75.38467199999999, 40.14335 ], "pop" : 39184, "state" : "PA" }
+{ "_id" : "19405", "city" : "BRIDGEPORT", "loc" : [ -75.340234, 40.103042 ], "pop" : 5163, "state" : "PA" }
+{ "_id" : "19406", "city" : "KING OF PRUSSIA", "loc" : [ -75.373706, 40.095581 ], "pop" : 21049, "state" : "PA" }
+{ "_id" : "19422", "city" : "PENLLYN", "loc" : [ -75.279656, 40.15939 ], "pop" : 16645, "state" : "PA" }
+{ "_id" : "19425", "city" : "CHESTER SPRINGS", "loc" : [ -75.639769, 40.097781 ], "pop" : 4413, "state" : "PA" }
+{ "_id" : "19426", "city" : "COLLEGEVILLE", "loc" : [ -75.448762, 40.189277 ], "pop" : 16453, "state" : "PA" }
+{ "_id" : "19428", "city" : "WEST CONSHOHOCKE", "loc" : [ -75.301332, 40.079848 ], "pop" : 15924, "state" : "PA" }
+{ "_id" : "19435", "city" : "FREDERICK", "loc" : [ -75.531975, 40.299924 ], "pop" : 728, "state" : "PA" }
+{ "_id" : "19436", "city" : "GWYNEDD", "loc" : [ -75.25074600000001, 40.202089 ], "pop" : 540, "state" : "PA" }
+{ "_id" : "19438", "city" : "HARLEYSVILLE", "loc" : [ -75.388335, 40.265922 ], "pop" : 16027, "state" : "PA" }
+{ "_id" : "19440", "city" : "HATFIELD", "loc" : [ -75.297507, 40.277826 ], "pop" : 16686, "state" : "PA" }
+{ "_id" : "19444", "city" : "LAFAYETTE HILL", "loc" : [ -75.260052, 40.089597 ], "pop" : 8312, "state" : "PA" }
+{ "_id" : "19446", "city" : "LANSDALE", "loc" : [ -75.295512, 40.237776 ], "pop" : 41034, "state" : "PA" }
+{ "_id" : "19453", "city" : "MONT CLARE", "loc" : [ -75.499931, 40.13642 ], "pop" : 1749, "state" : "PA" }
+{ "_id" : "19454", "city" : "NORTH WALES", "loc" : [ -75.256483, 40.216593 ], "pop" : 14886, "state" : "PA" }
+{ "_id" : "19460", "city" : "PHOENIXVILLE", "loc" : [ -75.527192, 40.126704 ], "pop" : 30460, "state" : "PA" }
+{ "_id" : "19462", "city" : "PLYMOUTH MEETING", "loc" : [ -75.27955900000001, 40.107735 ], "pop" : 5206, "state" : "PA" }
+{ "_id" : "19464", "city" : "SANATOGA", "loc" : [ -75.639256, 40.242989 ], "pop" : 53017, "state" : "PA" }
+{ "_id" : "19468", "city" : "LIMERICK", "loc" : [ -75.530548, 40.19286 ], "pop" : 13825, "state" : "PA" }
+{ "_id" : "19473", "city" : "SCHWENKSVILLE", "loc" : [ -75.460155, 40.247087 ], "pop" : 13139, "state" : "PA" }
+{ "_id" : "19475", "city" : "SPRING CITY", "loc" : [ -75.56968999999999, 40.176477 ], "pop" : 7988, "state" : "PA" }
+{ "_id" : "19477", "city" : "SPRING HOUSE", "loc" : [ -75.23750099999999, 40.186954 ], "pop" : 2129, "state" : "PA" }
+{ "_id" : "19492", "city" : "ZIEGLERSVILLE", "loc" : [ -75.485462, 40.281673 ], "pop" : 290, "state" : "PA" }
+{ "_id" : "19501", "city" : "ADAMSTOWN", "loc" : [ -76.05654199999999, 40.242992 ], "pop" : 1108, "state" : "PA" }
+{ "_id" : "19503", "city" : "BALLY", "loc" : [ -75.58748300000001, 40.400557 ], "pop" : 973, "state" : "PA" }
+{ "_id" : "19504", "city" : "BARTO", "loc" : [ -75.574889, 40.381501 ], "pop" : 2509, "state" : "PA" }
+{ "_id" : "19505", "city" : "BECHTELSVILLE", "loc" : [ -75.62570100000001, 40.379454 ], "pop" : 3640, "state" : "PA" }
+{ "_id" : "19506", "city" : "BERNVILLE", "loc" : [ -76.12473199999999, 40.455061 ], "pop" : 6245, "state" : "PA" }
+{ "_id" : "19507", "city" : "BETHEL", "loc" : [ -76.274209, 40.480834 ], "pop" : 3523, "state" : "PA" }
+{ "_id" : "19508", "city" : "BIRDSBORO", "loc" : [ -75.834373, 40.256304 ], "pop" : 15266, "state" : "PA" }
+{ "_id" : "19510", "city" : "BLANDON", "loc" : [ -75.883681, 40.443492 ], "pop" : 2663, "state" : "PA" }
+{ "_id" : "19512", "city" : "BOYERTOWN", "loc" : [ -75.66036800000001, 40.333905 ], "pop" : 17139, "state" : "PA" }
+{ "_id" : "19518", "city" : "DOUGLASSVILLE", "loc" : [ -75.739673, 40.270876 ], "pop" : 7852, "state" : "PA" }
+{ "_id" : "19520", "city" : "ELVERSON", "loc" : [ -75.786563, 40.156781 ], "pop" : 4592, "state" : "PA" }
+{ "_id" : "19522", "city" : "EVANSVILLE", "loc" : [ -75.81440000000001, 40.446766 ], "pop" : 11505, "state" : "PA" }
+{ "_id" : "19525", "city" : "GILBERTSVILLE", "loc" : [ -75.595296, 40.305941 ], "pop" : 7250, "state" : "PA" }
+{ "_id" : "19526", "city" : "HAMBURG", "loc" : [ -75.98736100000001, 40.548799 ], "pop" : 9959, "state" : "PA" }
+{ "_id" : "19529", "city" : "KEMPTON", "loc" : [ -75.85127, 40.632794 ], "pop" : 2387, "state" : "PA" }
+{ "_id" : "19530", "city" : "KUTZTOWN", "loc" : [ -75.777395, 40.521354 ], "pop" : 13345, "state" : "PA" }
+{ "_id" : "19533", "city" : "LEESPORT", "loc" : [ -75.994421, 40.415216 ], "pop" : 6199, "state" : "PA" }
+{ "_id" : "19534", "city" : "LENHARTSVILLE", "loc" : [ -75.850002, 40.575284 ], "pop" : 1840, "state" : "PA" }
+{ "_id" : "19539", "city" : "MERTZTOWN", "loc" : [ -75.687202, 40.499183 ], "pop" : 4058, "state" : "PA" }
+{ "_id" : "19540", "city" : "MOHNTON", "loc" : [ -75.98332000000001, 40.258442 ], "pop" : 8402, "state" : "PA" }
+{ "_id" : "19541", "city" : "MOHRSVILLE", "loc" : [ -76.012491, 40.478307 ], "pop" : 3473, "state" : "PA" }
+{ "_id" : "19543", "city" : "MORGANTOWN", "loc" : [ -75.89980199999999, 40.155248 ], "pop" : 2121, "state" : "PA" }
+{ "_id" : "19547", "city" : "OLEY", "loc" : [ -75.77057499999999, 40.383312 ], "pop" : 3949, "state" : "PA" }
+{ "_id" : "19549", "city" : "PORT CLINTON", "loc" : [ -76.026652, 40.581787 ], "pop" : 328, "state" : "PA" }
+{ "_id" : "19551", "city" : "ROBESONIA", "loc" : [ -76.13659, 40.355281 ], "pop" : 5310, "state" : "PA" }
+{ "_id" : "19555", "city" : "SHOEMAKERSVILLE", "loc" : [ -75.960313, 40.495495 ], "pop" : 3947, "state" : "PA" }
+{ "_id" : "19560", "city" : "TEMPLE", "loc" : [ -75.904582, 40.402504 ], "pop" : 7503, "state" : "PA" }
+{ "_id" : "19562", "city" : "TOPTON", "loc" : [ -75.701528, 40.502941 ], "pop" : 1987, "state" : "PA" }
+{ "_id" : "19565", "city" : "WERNERSVILLE", "loc" : [ -76.09014000000001, 40.329289 ], "pop" : 5056, "state" : "PA" }
+{ "_id" : "19567", "city" : "WOMELSDORF", "loc" : [ -76.198511, 40.374333 ], "pop" : 4034, "state" : "PA" }
+{ "_id" : "19601", "city" : "READING", "loc" : [ -75.935132, 40.346621 ], "pop" : 29968, "state" : "PA" }
+{ "_id" : "19602", "city" : "READING", "loc" : [ -75.919229, 40.330604 ], "pop" : 16303, "state" : "PA" }
+{ "_id" : "19604", "city" : "READING", "loc" : [ -75.91426199999999, 40.350721 ], "pop" : 22987, "state" : "PA" }
+{ "_id" : "19605", "city" : "READING", "loc" : [ -75.93276899999999, 40.38859 ], "pop" : 13878, "state" : "PA" }
+{ "_id" : "19606", "city" : "MOUNT PENN", "loc" : [ -75.868178, 40.325109 ], "pop" : 27732, "state" : "PA" }
+{ "_id" : "19607", "city" : "SHILLINGTON", "loc" : [ -75.953103, 40.299696 ], "pop" : 19281, "state" : "PA" }
+{ "_id" : "19608", "city" : "SINKING SPRING", "loc" : [ -76.024086, 40.31449 ], "pop" : 13037, "state" : "PA" }
+{ "_id" : "19609", "city" : "WEST LAWN", "loc" : [ -75.995347, 40.325778 ], "pop" : 9845, "state" : "PA" }
+{ "_id" : "19610", "city" : "WYOMISSING", "loc" : [ -75.976382, 40.333478 ], "pop" : 12394, "state" : "PA" }
+{ "_id" : "19611", "city" : "READING", "loc" : [ -75.944188, 40.324989 ], "pop" : 10763, "state" : "PA" }
+{ "_id" : "19701", "city" : "BEAR", "loc" : [ -75.674729, 39.610187 ], "pop" : 21384, "state" : "DE" }
+{ "_id" : "19702", "city" : "NEWARK", "loc" : [ -75.69933899999999, 39.634869 ], "pop" : 30402, "state" : "DE" }
+{ "_id" : "19703", "city" : "CLAYMONT", "loc" : [ -75.46494, 39.804432 ], "pop" : 16699, "state" : "DE" }
+{ "_id" : "19707", "city" : "HOCKESSIN", "loc" : [ -75.688873, 39.77604 ], "pop" : 13149, "state" : "DE" }
+{ "_id" : "19709", "city" : "MIDDLETOWN", "loc" : [ -75.683183, 39.481535 ], "pop" : 10243, "state" : "DE" }
+{ "_id" : "19711", "city" : "NEWARK", "loc" : [ -75.737534, 39.701129 ], "pop" : 50573, "state" : "DE" }
+{ "_id" : "19713", "city" : "NEWARK", "loc" : [ -75.715101, 39.669881 ], "pop" : 30699, "state" : "DE" }
+{ "_id" : "19720", "city" : "MANOR", "loc" : [ -75.589938, 39.67703 ], "pop" : 46906, "state" : "DE" }
+{ "_id" : "19734", "city" : "TOWNSEND", "loc" : [ -75.683368, 39.381882 ], "pop" : 4512, "state" : "DE" }
+{ "_id" : "19801", "city" : "WILMINGTON", "loc" : [ -75.54965799999999, 39.737752 ], "pop" : 15151, "state" : "DE" }
+{ "_id" : "19802", "city" : "WILMINGTON", "loc" : [ -75.534041, 39.75638 ], "pop" : 27411, "state" : "DE" }
+{ "_id" : "19803", "city" : "TALLEYVILLE", "loc" : [ -75.531076, 39.793236 ], "pop" : 20901, "state" : "DE" }
+{ "_id" : "19804", "city" : "NEWPORT", "loc" : [ -75.612815, 39.720854 ], "pop" : 18306, "state" : "DE" }
+{ "_id" : "19805", "city" : "WILMINGTON", "loc" : [ -75.582724, 39.743375 ], "pop" : 40087, "state" : "DE" }
+{ "_id" : "19806", "city" : "WILMINGTON", "loc" : [ -75.563503, 39.757076 ], "pop" : 9645, "state" : "DE" }
+{ "_id" : "19807", "city" : "GREENVILLE", "loc" : [ -75.60720499999999, 39.782206 ], "pop" : 7176, "state" : "DE" }
+{ "_id" : "19808", "city" : "MARSHALLTON", "loc" : [ -75.66389100000001, 39.734737 ], "pop" : 34260, "state" : "DE" }
+{ "_id" : "19809", "city" : "EDGEMOOR", "loc" : [ -75.494592, 39.771913 ], "pop" : 14285, "state" : "DE" }
+{ "_id" : "19810", "city" : "EDGEMOOR", "loc" : [ -75.505999, 39.819377 ], "pop" : 26334, "state" : "DE" }
+{ "_id" : "19901", "city" : "DOVER", "loc" : [ -75.535983, 39.156639 ], "pop" : 46005, "state" : "DE" }
+{ "_id" : "19902", "city" : "DOVER AFB", "loc" : [ -75.478966, 39.120246 ], "pop" : 5500, "state" : "DE" }
+{ "_id" : "19930", "city" : "BETHANY BEACH", "loc" : [ -75.067396, 38.531009 ], "pop" : 769, "state" : "DE" }
+{ "_id" : "19931", "city" : "BETHEL", "loc" : [ -75.624298, 38.568517 ], "pop" : 108, "state" : "DE" }
+{ "_id" : "19933", "city" : "BRIDGEVILLE", "loc" : [ -75.608768, 38.736628 ], "pop" : 4353, "state" : "DE" }
+{ "_id" : "19934", "city" : "CAMDEN WYOMING", "loc" : [ -75.596559, 39.099099 ], "pop" : 8877, "state" : "DE" }
+{ "_id" : "19938", "city" : "CLAYTON", "loc" : [ -75.690361, 39.256395 ], "pop" : 4906, "state" : "DE" }
+{ "_id" : "19939", "city" : "DAGSBORO", "loc" : [ -75.21133, 38.559559 ], "pop" : 2593, "state" : "DE" }
+{ "_id" : "19940", "city" : "DELMAR", "loc" : [ -75.57588699999999, 38.476955 ], "pop" : 4257, "state" : "DE" }
+{ "_id" : "19941", "city" : "ELLENDALE", "loc" : [ -75.40558799999999, 38.805737 ], "pop" : 2445, "state" : "DE" }
+{ "_id" : "19943", "city" : "FELTON", "loc" : [ -75.58290599999999, 39.022538 ], "pop" : 7282, "state" : "DE" }
+{ "_id" : "19945", "city" : "FRANKFORD", "loc" : [ -75.200633, 38.51767 ], "pop" : 5500, "state" : "DE" }
+{ "_id" : "19946", "city" : "FREDERICA", "loc" : [ -75.454458, 39.034188 ], "pop" : 2725, "state" : "DE" }
+{ "_id" : "19947", "city" : "GEORGETOWN", "loc" : [ -75.393198, 38.679006 ], "pop" : 11371, "state" : "DE" }
+{ "_id" : "19950", "city" : "GREENWOOD", "loc" : [ -75.593547, 38.817519 ], "pop" : 4279, "state" : "DE" }
+{ "_id" : "19951", "city" : "HARBESON", "loc" : [ -75.22362099999999, 38.672294 ], "pop" : 598, "state" : "DE" }
+{ "_id" : "19952", "city" : "HARRINGTON", "loc" : [ -75.58426799999999, 38.924031 ], "pop" : 7972, "state" : "DE" }
+{ "_id" : "19953", "city" : "HARTLY", "loc" : [ -75.693476, 39.15421 ], "pop" : 3558, "state" : "DE" }
+{ "_id" : "19954", "city" : "HOUSTON", "loc" : [ -75.506354, 38.91143 ], "pop" : 1776, "state" : "DE" }
+{ "_id" : "19956", "city" : "LAUREL", "loc" : [ -75.563052, 38.553695 ], "pop" : 9283, "state" : "DE" }
+{ "_id" : "19958", "city" : "LEWES", "loc" : [ -75.174702, 38.738149 ], "pop" : 9503, "state" : "DE" }
+{ "_id" : "19960", "city" : "LINCOLN", "loc" : [ -75.399961, 38.86128 ], "pop" : 4435, "state" : "DE" }
+{ "_id" : "19962", "city" : "MAGNOLIA", "loc" : [ -75.508321, 39.07353 ], "pop" : 4567, "state" : "DE" }
+{ "_id" : "19963", "city" : "MILFORD", "loc" : [ -75.429877, 38.921801 ], "pop" : 12187, "state" : "DE" }
+{ "_id" : "19964", "city" : "MARYDEL", "loc" : [ -75.728661, 39.099794 ], "pop" : 975, "state" : "DE" }
+{ "_id" : "19966", "city" : "LONG NECK", "loc" : [ -75.25554700000001, 38.593436 ], "pop" : 11962, "state" : "DE" }
+{ "_id" : "19967", "city" : "MILLVILLE", "loc" : [ -75.10776199999999, 38.558946 ], "pop" : 623, "state" : "DE" }
+{ "_id" : "19968", "city" : "MILTON", "loc" : [ -75.295298, 38.768687 ], "pop" : 4656, "state" : "DE" }
+{ "_id" : "19970", "city" : "MILLVILLE", "loc" : [ -75.096518, 38.555528 ], "pop" : 1532, "state" : "DE" }
+{ "_id" : "19971", "city" : "DEWEY BEACH", "loc" : [ -75.10734600000001, 38.714715 ], "pop" : 6249, "state" : "DE" }
+{ "_id" : "19973", "city" : "SEAFORD", "loc" : [ -75.604122, 38.640358 ], "pop" : 18404, "state" : "DE" }
+{ "_id" : "19975", "city" : "SELBYVILLE", "loc" : [ -75.157325, 38.465357 ], "pop" : 4478, "state" : "DE" }
+{ "_id" : "19977", "city" : "SMYRNA", "loc" : [ -75.600832, 39.293379 ], "pop" : 14164, "state" : "DE" }
+{ "_id" : "19979", "city" : "VIOLA", "loc" : [ -75.572605, 39.041872 ], "pop" : 153, "state" : "DE" }
+{ "_id" : "20001", "city" : "WASHINGTON", "loc" : [ -77.017691, 38.912217 ], "pop" : 34745, "state" : "DC" }
+{ "_id" : "20002", "city" : "WASHINGTON", "loc" : [ -76.990055, 38.902365 ], "pop" : 56756, "state" : "DC" }
+{ "_id" : "20003", "city" : "WASHINGTON", "loc" : [ -76.98953899999999, 38.882941 ], "pop" : 24818, "state" : "DC" }
+{ "_id" : "20004", "city" : "WASHINGTON", "loc" : [ -77.026303, 38.892955 ], "pop" : 11, "state" : "DC" }
+{ "_id" : "20005", "city" : "WASHINGTON", "loc" : [ -77.03123600000001, 38.906731 ], "pop" : 9862, "state" : "DC" }
+{ "_id" : "20006", "city" : "WASHINGTON", "loc" : [ -77.044701, 38.896444 ], "pop" : 2317, "state" : "DC" }
+{ "_id" : "20007", "city" : "WASHINGTON", "loc" : [ -77.07404200000001, 38.914365 ], "pop" : 27076, "state" : "DC" }
+{ "_id" : "20008", "city" : "WASHINGTON", "loc" : [ -77.05993599999999, 38.936282 ], "pop" : 26736, "state" : "DC" }
+{ "_id" : "20009", "city" : "WASHINGTON", "loc" : [ -77.037504, 38.920202 ], "pop" : 47086, "state" : "DC" }
+{ "_id" : "20010", "city" : "WASHINGTON", "loc" : [ -77.032183, 38.93272 ], "pop" : 28849, "state" : "DC" }
+{ "_id" : "20011", "city" : "WASHINGTON", "loc" : [ -77.020251, 38.951786 ], "pop" : 62924, "state" : "DC" }
+{ "_id" : "20012", "city" : "WASHINGTON", "loc" : [ -77.028248, 38.975712 ], "pop" : 15081, "state" : "DC" }
+{ "_id" : "20015", "city" : "WASHINGTON", "loc" : [ -77.067961, 38.965768 ], "pop" : 14569, "state" : "DC" }
+{ "_id" : "20016", "city" : "WASHINGTON", "loc" : [ -77.086037, 38.938117 ], "pop" : 31042, "state" : "DC" }
+{ "_id" : "20017", "city" : "WASHINGTON", "loc" : [ -76.994038, 38.936723 ], "pop" : 19548, "state" : "DC" }
+{ "_id" : "20018", "city" : "WASHINGTON", "loc" : [ -76.976159, 38.927724 ], "pop" : 18298, "state" : "DC" }
+{ "_id" : "20019", "city" : "WASHINGTON", "loc" : [ -76.93758800000001, 38.890237 ], "pop" : 59492, "state" : "DC" }
+{ "_id" : "20020", "city" : "WASHINGTON", "loc" : [ -76.974187, 38.860039 ], "pop" : 54339, "state" : "DC" }
+{ "_id" : "20024", "city" : "WASHINGTON", "loc" : [ -77.01602800000001, 38.875939 ], "pop" : 11562, "state" : "DC" }
+{ "_id" : "20032", "city" : "WASHINGTON", "loc" : [ -76.999549, 38.833843 ], "pop" : 40265, "state" : "DC" }
+{ "_id" : "20036", "city" : "WASHINGTON", "loc" : [ -77.041434, 38.908704 ], "pop" : 4146, "state" : "DC" }
+{ "_id" : "20037", "city" : "WASHINGTON", "loc" : [ -77.050448, 38.901446 ], "pop" : 11046, "state" : "DC" }
+{ "_id" : "20301", "city" : "PENTAGON", "loc" : [ -77.038196, 38.891019 ], "pop" : 21, "state" : "DC" }
+{ "_id" : "20331", "city" : "ANDREWS AFB", "loc" : [ -76.886695, 38.800324 ], "pop" : 10228, "state" : "MD" }
+{ "_id" : "20336", "city" : "WASHINGTON", "loc" : [ -77.014827, 38.839473 ], "pop" : 6311, "state" : "DC" }
+{ "_id" : "20601", "city" : "WALDORF", "loc" : [ -76.877787, 38.637065 ], "pop" : 18548, "state" : "MD" }
+{ "_id" : "20602", "city" : "SAINT CHARLES", "loc" : [ -76.903414, 38.601545 ], "pop" : 20663, "state" : "MD" }
+{ "_id" : "20603", "city" : "SAINT CHARLES", "loc" : [ -76.96115399999999, 38.624929 ], "pop" : 11184, "state" : "MD" }
+{ "_id" : "20606", "city" : "ABELL", "loc" : [ -76.74410399999999, 38.249554 ], "pop" : 601, "state" : "MD" }
+{ "_id" : "20607", "city" : "ACCOKEEK", "loc" : [ -77.016217, 38.671992 ], "pop" : 4043, "state" : "MD" }
+{ "_id" : "20608", "city" : "AQUASCO", "loc" : [ -76.714947, 38.582496 ], "pop" : 939, "state" : "MD" }
+{ "_id" : "20609", "city" : "AVENUE", "loc" : [ -76.74655300000001, 38.282624 ], "pop" : 699, "state" : "MD" }
+{ "_id" : "20611", "city" : "BEL ALTON", "loc" : [ -76.97887299999999, 38.473141 ], "pop" : 582, "state" : "MD" }
+{ "_id" : "20613", "city" : "BRANDYWINE", "loc" : [ -76.832033, 38.692203 ], "pop" : 7627, "state" : "MD" }
+{ "_id" : "20615", "city" : "BROOMES ISLAND", "loc" : [ -76.547763, 38.417963 ], "pop" : 404, "state" : "MD" }
+{ "_id" : "20616", "city" : "BRYANS ROAD", "loc" : [ -77.076589, 38.641468 ], "pop" : 3792, "state" : "MD" }
+{ "_id" : "20617", "city" : "BRYANTOWN", "loc" : [ -76.84653900000001, 38.542638 ], "pop" : 722, "state" : "MD" }
+{ "_id" : "20618", "city" : "BUSHWOOD", "loc" : [ -76.792863, 38.284439 ], "pop" : 934, "state" : "MD" }
+{ "_id" : "20619", "city" : "CALIFORNIA", "loc" : [ -76.531228, 38.300648 ], "pop" : 5485, "state" : "MD" }
+{ "_id" : "20620", "city" : "CALLAWAY", "loc" : [ -76.52096299999999, 38.227521 ], "pop" : 1394, "state" : "MD" }
+{ "_id" : "20621", "city" : "MADDOX", "loc" : [ -76.782343, 38.333197 ], "pop" : 1240, "state" : "MD" }
+{ "_id" : "20622", "city" : "CHARLOTTE HALL", "loc" : [ -76.803792, 38.474977 ], "pop" : 3454, "state" : "MD" }
+{ "_id" : "20623", "city" : "CHELTENHAM", "loc" : [ -76.83685199999999, 38.753094 ], "pop" : 712, "state" : "MD" }
+{ "_id" : "20624", "city" : "CLEMENTS", "loc" : [ -76.72641900000001, 38.340716 ], "pop" : 303, "state" : "MD" }
+{ "_id" : "20626", "city" : "COLTONS POINT", "loc" : [ -76.76464900000001, 38.236963 ], "pop" : 694, "state" : "MD" }
+{ "_id" : "20628", "city" : "DAMERON", "loc" : [ -76.357474, 38.153271 ], "pop" : 330, "state" : "MD" }
+{ "_id" : "20630", "city" : "DRAYDEN", "loc" : [ -76.473095, 38.171875 ], "pop" : 413, "state" : "MD" }
+{ "_id" : "20632", "city" : "FAULKNER", "loc" : [ -76.972937, 38.438221 ], "pop" : 459, "state" : "MD" }
+{ "_id" : "20634", "city" : "GREAT MILLS", "loc" : [ -76.49536500000001, 38.267431 ], "pop" : 4203, "state" : "MD" }
+{ "_id" : "20636", "city" : "HOLLYWOOD", "loc" : [ -76.56264400000001, 38.352356 ], "pop" : 6785, "state" : "MD" }
+{ "_id" : "20637", "city" : "HUGHESVILLE", "loc" : [ -76.781677, 38.520712 ], "pop" : 4078, "state" : "MD" }
+{ "_id" : "20639", "city" : "HUNTINGTOWN", "loc" : [ -76.600268, 38.609453 ], "pop" : 8290, "state" : "MD" }
+{ "_id" : "20640", "city" : "PISGAH", "loc" : [ -77.148357, 38.588855 ], "pop" : 8227, "state" : "MD" }
+{ "_id" : "20645", "city" : "ISSUE", "loc" : [ -76.867527, 38.304327 ], "pop" : 87, "state" : "MD" }
+{ "_id" : "20646", "city" : "LA PLATA", "loc" : [ -76.986498, 38.525673 ], "pop" : 16900, "state" : "MD" }
+{ "_id" : "20650", "city" : "LEONARDTOWN", "loc" : [ -76.638037, 38.277425 ], "pop" : 8922, "state" : "MD" }
+{ "_id" : "20653", "city" : "LEXINGTON PARK", "loc" : [ -76.45292999999999, 38.249452 ], "pop" : 17082, "state" : "MD" }
+{ "_id" : "20656", "city" : "LOVEVILLE", "loc" : [ -76.67708, 38.347438 ], "pop" : 248, "state" : "MD" }
+{ "_id" : "20657", "city" : "LUSBY", "loc" : [ -76.43464, 38.366128 ], "pop" : 8990, "state" : "MD" }
+{ "_id" : "20658", "city" : "RISON", "loc" : [ -77.156329, 38.557335 ], "pop" : 1826, "state" : "MD" }
+{ "_id" : "20659", "city" : "MECHANICSVILLE", "loc" : [ -76.725399, 38.429319 ], "pop" : 17326, "state" : "MD" }
+{ "_id" : "20662", "city" : "NANJEMOY", "loc" : [ -77.198296, 38.446161 ], "pop" : 2793, "state" : "MD" }
+{ "_id" : "20664", "city" : "NEWBURG", "loc" : [ -76.91749900000001, 38.329782 ], "pop" : 3612, "state" : "MD" }
+{ "_id" : "20667", "city" : "PARK HALL", "loc" : [ -76.44152200000001, 38.224364 ], "pop" : 224, "state" : "MD" }
+{ "_id" : "20670", "city" : "PATUXENT RIVER", "loc" : [ -76.438061, 38.279089 ], "pop" : 3015, "state" : "MD" }
+{ "_id" : "20674", "city" : "PINEY POINT", "loc" : [ -76.504716, 38.139667 ], "pop" : 1114, "state" : "MD" }
+{ "_id" : "20675", "city" : "POMFRET", "loc" : [ -77.009314, 38.585541 ], "pop" : 1410, "state" : "MD" }
+{ "_id" : "20676", "city" : "PORT REPUBLIC", "loc" : [ -76.534865, 38.495237 ], "pop" : 2647, "state" : "MD" }
+{ "_id" : "20677", "city" : "PORT TOBACCO", "loc" : [ -77.041856, 38.499353 ], "pop" : 1149, "state" : "MD" }
+{ "_id" : "20678", "city" : "PRINCE FREDERICK", "loc" : [ -76.595495, 38.533629 ], "pop" : 6802, "state" : "MD" }
+{ "_id" : "20680", "city" : "RIDGE", "loc" : [ -76.371071, 38.116883 ], "pop" : 1245, "state" : "MD" }
+{ "_id" : "20684", "city" : "SAINT INIGOES", "loc" : [ -76.408328, 38.14406 ], "pop" : 583, "state" : "MD" }
+{ "_id" : "20685", "city" : "SAINT LEONARD", "loc" : [ -76.511017, 38.45013 ], "pop" : 3895, "state" : "MD" }
+{ "_id" : "20687", "city" : "SCOTLAND", "loc" : [ -76.347684, 38.082772 ], "pop" : 356, "state" : "MD" }
+{ "_id" : "20688", "city" : "SOLOMONS", "loc" : [ -76.45888600000001, 38.334067 ], "pop" : 661, "state" : "MD" }
+{ "_id" : "20689", "city" : "SUNDERLAND", "loc" : [ -76.576697, 38.648968 ], "pop" : 1664, "state" : "MD" }
+{ "_id" : "20690", "city" : "TALL TIMBERS", "loc" : [ -76.539897, 38.165318 ], "pop" : 255, "state" : "MD" }
+{ "_id" : "20692", "city" : "VALLEY LEE", "loc" : [ -76.508689, 38.189937 ], "pop" : 667, "state" : "MD" }
+{ "_id" : "20693", "city" : "WELCOME", "loc" : [ -77.095006, 38.467206 ], "pop" : 334, "state" : "MD" }
+{ "_id" : "20695", "city" : "WHITE PLAINS", "loc" : [ -76.980233, 38.594848 ], "pop" : 3721, "state" : "MD" }
+{ "_id" : "20701", "city" : "ANNAPOLIS JUNCTI", "loc" : [ -76.798068, 39.130983 ], "pop" : 32, "state" : "MD" }
+{ "_id" : "20705", "city" : "BELTSVILLE", "loc" : [ -76.92416799999999, 39.045524 ], "pop" : 18146, "state" : "MD" }
+{ "_id" : "20706", "city" : "LANHAM", "loc" : [ -76.85509999999999, 38.967537 ], "pop" : 33471, "state" : "MD" }
+{ "_id" : "20707", "city" : "LAUREL", "loc" : [ -76.87204300000001, 39.107687 ], "pop" : 31065, "state" : "MD" }
+{ "_id" : "20708", "city" : "MONTPELIER", "loc" : [ -76.847725, 39.068376 ], "pop" : 23523, "state" : "MD" }
+{ "_id" : "20710", "city" : "BLADENSBURG", "loc" : [ -76.920327, 38.945215 ], "pop" : 7716, "state" : "MD" }
+{ "_id" : "20711", "city" : "LOTHIAN", "loc" : [ -76.66280999999999, 38.802933 ], "pop" : 5081, "state" : "MD" }
+{ "_id" : "20712", "city" : "MOUNT RAINIER", "loc" : [ -76.965152, 38.943072 ], "pop" : 8422, "state" : "MD" }
+{ "_id" : "20714", "city" : "NORTH BEACH", "loc" : [ -76.53670099999999, 38.711884 ], "pop" : 2292, "state" : "MD" }
+{ "_id" : "20715", "city" : "BOWIE", "loc" : [ -76.743497, 38.979696 ], "pop" : 25296, "state" : "MD" }
+{ "_id" : "20716", "city" : "MITCHELLVILLE", "loc" : [ -76.731979, 38.927482 ], "pop" : 13580, "state" : "MD" }
+{ "_id" : "20720", "city" : "BOWIE", "loc" : [ -76.789526, 38.973733 ], "pop" : 8239, "state" : "MD" }
+{ "_id" : "20721", "city" : "MITCHELLVILLE", "loc" : [ -76.80526999999999, 38.919588 ], "pop" : 10551, "state" : "MD" }
+{ "_id" : "20722", "city" : "BRENTWOOD", "loc" : [ -76.953062, 38.940701 ], "pop" : 5769, "state" : "MD" }
+{ "_id" : "20723", "city" : "LAUREL", "loc" : [ -76.84345, 39.120806 ], "pop" : 10457, "state" : "MD" }
+{ "_id" : "20724", "city" : "LAUREL", "loc" : [ -76.815485, 39.095801 ], "pop" : 7656, "state" : "MD" }
+{ "_id" : "20732", "city" : "CHESAPEAKE BEACH", "loc" : [ -76.537629, 38.669798 ], "pop" : 4856, "state" : "MD" }
+{ "_id" : "20733", "city" : "CHURCHTON", "loc" : [ -76.524773, 38.801791 ], "pop" : 2539, "state" : "MD" }
+{ "_id" : "20735", "city" : "CLINTON", "loc" : [ -76.90257699999999, 38.754892 ], "pop" : 26417, "state" : "MD" }
+{ "_id" : "20736", "city" : "OWINGS", "loc" : [ -76.606093, 38.695507 ], "pop" : 6876, "state" : "MD" }
+{ "_id" : "20737", "city" : "RIVERDALE", "loc" : [ -76.914658, 38.960067 ], "pop" : 16328, "state" : "MD" }
+{ "_id" : "20740", "city" : "COLLEGE PARK", "loc" : [ -76.929891, 38.996303 ], "pop" : 29336, "state" : "MD" }
+{ "_id" : "20743", "city" : "CAPITAL HEIGHTS", "loc" : [ -76.906665, 38.88385 ], "pop" : 40459, "state" : "MD" }
+{ "_id" : "20744", "city" : "FORT WASHINGTON", "loc" : [ -76.983531, 38.758656 ], "pop" : 44735, "state" : "MD" }
+{ "_id" : "20745", "city" : "OXON HILL", "loc" : [ -76.98977600000001, 38.810764 ], "pop" : 29487, "state" : "MD" }
+{ "_id" : "20746", "city" : "SUITLAND", "loc" : [ -76.922156, 38.842453 ], "pop" : 30601, "state" : "MD" }
+{ "_id" : "20747", "city" : "DISTRICT HEIGHTS", "loc" : [ -76.889132, 38.853887 ], "pop" : 35872, "state" : "MD" }
+{ "_id" : "20748", "city" : "TEMPLE HILLS", "loc" : [ -76.94778599999999, 38.822159 ], "pop" : 40471, "state" : "MD" }
+{ "_id" : "20751", "city" : "DEALE", "loc" : [ -76.551498, 38.782909 ], "pop" : 1909, "state" : "MD" }
+{ "_id" : "20754", "city" : "DUNKIRK", "loc" : [ -76.642658, 38.740763 ], "pop" : 5919, "state" : "MD" }
+{ "_id" : "20755", "city" : "FORT GEORGE G ME", "loc" : [ -76.745013, 39.112923 ], "pop" : 11110, "state" : "MD" }
+{ "_id" : "20758", "city" : "FRIENDSHIP", "loc" : [ -76.600093, 38.739077 ], "pop" : 853, "state" : "MD" }
+{ "_id" : "20759", "city" : "FULTON", "loc" : [ -76.92999, 39.150179 ], "pop" : 1640, "state" : "MD" }
+{ "_id" : "20763", "city" : "SAVAGE", "loc" : [ -76.82181799999999, 39.137962 ], "pop" : 2227, "state" : "MD" }
+{ "_id" : "20764", "city" : "SHADY SIDE", "loc" : [ -76.510884, 38.836794 ], "pop" : 2957, "state" : "MD" }
+{ "_id" : "20769", "city" : "GLENN DALE", "loc" : [ -76.805336, 38.976632 ], "pop" : 3242, "state" : "MD" }
+{ "_id" : "20770", "city" : "GREENBELT", "loc" : [ -76.88396400000001, 38.999559 ], "pop" : 21125, "state" : "MD" }
+{ "_id" : "20772", "city" : "UPPER MARLBORO", "loc" : [ -76.798028, 38.837717 ], "pop" : 49684, "state" : "MD" }
+{ "_id" : "20776", "city" : "HARWOOD", "loc" : [ -76.614458, 38.858152 ], "pop" : 3765, "state" : "MD" }
+{ "_id" : "20777", "city" : "HIGHLAND", "loc" : [ -76.968643, 39.184252 ], "pop" : 2596, "state" : "MD" }
+{ "_id" : "20778", "city" : "WEST RIVER", "loc" : [ -76.539113, 38.825194 ], "pop" : 1026, "state" : "MD" }
+{ "_id" : "20779", "city" : "TRACYS LANDING", "loc" : [ -76.57523999999999, 38.767101 ], "pop" : 413, "state" : "MD" }
+{ "_id" : "20781", "city" : "HYATTSVILLE", "loc" : [ -76.934652, 38.95063 ], "pop" : 11716, "state" : "MD" }
+{ "_id" : "20782", "city" : "WEST HYATTSVILLE", "loc" : [ -76.966632, 38.963575 ], "pop" : 28026, "state" : "MD" }
+{ "_id" : "20783", "city" : "ADELPHI", "loc" : [ -76.97472, 38.993751 ], "pop" : 40007, "state" : "MD" }
+{ "_id" : "20784", "city" : "LANDOVER HILLS", "loc" : [ -76.888829, 38.951541 ], "pop" : 27339, "state" : "MD" }
+{ "_id" : "20785", "city" : "LANDOVER", "loc" : [ -76.882243, 38.91992 ], "pop" : 38732, "state" : "MD" }
+{ "_id" : "20794", "city" : "JESSUP", "loc" : [ -76.792239, 39.148399 ], "pop" : 11789, "state" : "MD" }
+{ "_id" : "20812", "city" : "GLEN ECHO", "loc" : [ -77.143457, 38.969333 ], "pop" : 234, "state" : "MD" }
+{ "_id" : "20814", "city" : "BETHESDA", "loc" : [ -77.102165, 39.000343 ], "pop" : 21704, "state" : "MD" }
+{ "_id" : "20815", "city" : "CHEVY CHASE", "loc" : [ -77.08198400000001, 38.977955 ], "pop" : 25264, "state" : "MD" }
+{ "_id" : "20816", "city" : "BETHESDA", "loc" : [ -77.11528, 38.958485 ], "pop" : 14700, "state" : "MD" }
+{ "_id" : "20817", "city" : "WEST BETHESDA", "loc" : [ -77.13723899999999, 38.999659 ], "pop" : 33484, "state" : "MD" }
+{ "_id" : "20818", "city" : "CABIN JOHN", "loc" : [ -77.15911, 38.974302 ], "pop" : 1120, "state" : "MD" }
+{ "_id" : "20832", "city" : "OLNEY", "loc" : [ -77.074949, 39.152591 ], "pop" : 20376, "state" : "MD" }
+{ "_id" : "20833", "city" : "BROOKEVILLE", "loc" : [ -77.06026, 39.187082 ], "pop" : 3612, "state" : "MD" }
+{ "_id" : "20837", "city" : "POOLESVILLE", "loc" : [ -77.406717, 39.138597 ], "pop" : 4692, "state" : "MD" }
+{ "_id" : "20838", "city" : "BARNESVILLE", "loc" : [ -77.376426, 39.223321 ], "pop" : 130, "state" : "MD" }
+{ "_id" : "20839", "city" : "BEALLSVILLE", "loc" : [ -77.41440299999999, 39.167095 ], "pop" : 72, "state" : "MD" }
+{ "_id" : "20841", "city" : "BOYDS", "loc" : [ -77.316731, 39.210042 ], "pop" : 2402, "state" : "MD" }
+{ "_id" : "20842", "city" : "DICKERSON", "loc" : [ -77.419853, 39.212615 ], "pop" : 1726, "state" : "MD" }
+{ "_id" : "20850", "city" : "ROCKVILLE", "loc" : [ -77.167973, 39.087037 ], "pop" : 24215, "state" : "MD" }
+{ "_id" : "20851", "city" : "ROCKVILLE", "loc" : [ -77.12344899999999, 39.076265 ], "pop" : 11494, "state" : "MD" }
+{ "_id" : "20852", "city" : "ROCKVILLE", "loc" : [ -77.12041600000001, 39.049628 ], "pop" : 32913, "state" : "MD" }
+{ "_id" : "20853", "city" : "ROCKVILLE", "loc" : [ -77.095037, 39.088738 ], "pop" : 27339, "state" : "MD" }
+{ "_id" : "20854", "city" : "POTOMAC", "loc" : [ -77.192151, 39.03877 ], "pop" : 44211, "state" : "MD" }
+{ "_id" : "20855", "city" : "DERWOOD", "loc" : [ -77.147707, 39.134539 ], "pop" : 17235, "state" : "MD" }
+{ "_id" : "20860", "city" : "SANDY SPRING", "loc" : [ -77.029071, 39.150319 ], "pop" : 1890, "state" : "MD" }
+{ "_id" : "20861", "city" : "ASHTON", "loc" : [ -76.99242, 39.151027 ], "pop" : 1318, "state" : "MD" }
+{ "_id" : "20862", "city" : "BRINKLOW", "loc" : [ -77.016338, 39.183777 ], "pop" : 286, "state" : "MD" }
+{ "_id" : "20866", "city" : "BURTONSVILLE", "loc" : [ -76.933851, 39.092151 ], "pop" : 14497, "state" : "MD" }
+{ "_id" : "20868", "city" : "SPENCERVILLE", "loc" : [ -76.959802, 39.121343 ], "pop" : 278, "state" : "MD" }
+{ "_id" : "20871", "city" : "CLARKSBURG", "loc" : [ -77.273579, 39.263719 ], "pop" : 2674, "state" : "MD" }
+{ "_id" : "20872", "city" : "DAMASCUS", "loc" : [ -77.213088, 39.27606 ], "pop" : 10446, "state" : "MD" }
+{ "_id" : "20874", "city" : "DARNESTOWN", "loc" : [ -77.269935, 39.17039 ], "pop" : 33549, "state" : "MD" }
+{ "_id" : "20876", "city" : "GERMANTOWN", "loc" : [ -77.235829, 39.188001 ], "pop" : 11734, "state" : "MD" }
+{ "_id" : "20877", "city" : "GAITHERSBURG", "loc" : [ -77.188993, 39.14187 ], "pop" : 25136, "state" : "MD" }
+{ "_id" : "20878", "city" : "DARNESTOWN", "loc" : [ -77.236434, 39.115534 ], "pop" : 45367, "state" : "MD" }
+{ "_id" : "20879", "city" : "LAYTONSVILLE", "loc" : [ -77.194599, 39.172597 ], "pop" : 46879, "state" : "MD" }
+{ "_id" : "20882", "city" : "LAYTONSVILLE", "loc" : [ -77.174718, 39.238345 ], "pop" : 9795, "state" : "MD" }
+{ "_id" : "20895", "city" : "KENSINGTON", "loc" : [ -77.07928099999999, 39.029803 ], "pop" : 21848, "state" : "MD" }
+{ "_id" : "20901", "city" : "SILVER SPRING", "loc" : [ -77.00761300000001, 39.019106 ], "pop" : 33858, "state" : "MD" }
+{ "_id" : "20902", "city" : "WHEATON", "loc" : [ -77.04634799999999, 39.04158 ], "pop" : 40299, "state" : "MD" }
+{ "_id" : "20903", "city" : "SILVER SPRING", "loc" : [ -76.98464800000001, 39.009513 ], "pop" : 16724, "state" : "MD" }
+{ "_id" : "20904", "city" : "COLESVILLE", "loc" : [ -76.976399, 39.06524 ], "pop" : 39991, "state" : "MD" }
+{ "_id" : "20905", "city" : "COLESVILLE", "loc" : [ -76.98992800000001, 39.102438 ], "pop" : 16800, "state" : "MD" }
+{ "_id" : "20906", "city" : "ASPEN HILL", "loc" : [ -77.063233, 39.081041 ], "pop" : 52694, "state" : "MD" }
+{ "_id" : "20910", "city" : "SILVER SPRING", "loc" : [ -77.033776, 38.998198 ], "pop" : 31954, "state" : "MD" }
+{ "_id" : "20912", "city" : "TAKOMA PARK", "loc" : [ -77.000715, 38.983214 ], "pop" : 24356, "state" : "MD" }
+{ "_id" : "21001", "city" : "ABERDEEN", "loc" : [ -76.18053999999999, 39.510886 ], "pop" : 19229, "state" : "MD" }
+{ "_id" : "21005", "city" : "ABERDEEN PROVING", "loc" : [ -76.130295, 39.472434 ], "pop" : 5294, "state" : "MD" }
+{ "_id" : "21009", "city" : "ABINGDON", "loc" : [ -76.29972600000001, 39.47444 ], "pop" : 12664, "state" : "MD" }
+{ "_id" : "21010", "city" : "GUNPOWDER", "loc" : [ -76.274261, 39.398249 ], "pop" : 1082, "state" : "MD" }
+{ "_id" : "21012", "city" : "ARNOLD", "loc" : [ -76.49406, 39.047587 ], "pop" : 19404, "state" : "MD" }
+{ "_id" : "21013", "city" : "BALDWIN", "loc" : [ -76.492711, 39.519395 ], "pop" : 4945, "state" : "MD" }
+{ "_id" : "21014", "city" : "BEL AIR", "loc" : [ -76.356431, 39.539367 ], "pop" : 18477, "state" : "MD" }
+{ "_id" : "21015", "city" : "BEL AIR", "loc" : [ -76.31532900000001, 39.530252 ], "pop" : 23254, "state" : "MD" }
+{ "_id" : "21017", "city" : "BELCAMP", "loc" : [ -76.24201100000001, 39.475626 ], "pop" : 2957, "state" : "MD" }
+{ "_id" : "21021", "city" : "BRADSHAW", "loc" : [ -76.38939999999999, 39.428113 ], "pop" : 699, "state" : "MD" }
+{ "_id" : "21028", "city" : "CHURCHVILLE", "loc" : [ -76.24896200000001, 39.564845 ], "pop" : 3038, "state" : "MD" }
+{ "_id" : "21029", "city" : "CLARKSVILLE", "loc" : [ -76.94227100000001, 39.194362 ], "pop" : 3147, "state" : "MD" }
+{ "_id" : "21030", "city" : "COCKEYSVILLE HUN", "loc" : [ -76.62865499999999, 39.473554 ], "pop" : 20331, "state" : "MD" }
+{ "_id" : "21031", "city" : "COCKEYSVILLE HUN", "loc" : [ -76.65984400000001, 39.502623 ], "pop" : 159, "state" : "MD" }
+{ "_id" : "21032", "city" : "CROWNSVILLE", "loc" : [ -76.59347699999999, 39.048889 ], "pop" : 7269, "state" : "MD" }
+{ "_id" : "21034", "city" : "DARLINGTON", "loc" : [ -76.227795, 39.654032 ], "pop" : 3298, "state" : "MD" }
+{ "_id" : "21035", "city" : "DAVIDSONVILLE", "loc" : [ -76.637542, 38.937364 ], "pop" : 6070, "state" : "MD" }
+{ "_id" : "21036", "city" : "DAYTON", "loc" : [ -76.99675499999999, 39.233882 ], "pop" : 1707, "state" : "MD" }
+{ "_id" : "21037", "city" : "EDGEWATER BEACH", "loc" : [ -76.540374, 38.922511 ], "pop" : 14576, "state" : "MD" }
+{ "_id" : "21040", "city" : "EDGEWOOD", "loc" : [ -76.30555, 39.427725 ], "pop" : 22058, "state" : "MD" }
+{ "_id" : "21042", "city" : "ELLICOTT CITY", "loc" : [ -76.861362, 39.272632 ], "pop" : 29589, "state" : "MD" }
+{ "_id" : "21043", "city" : "DANIELS", "loc" : [ -76.803929, 39.258216 ], "pop" : 19217, "state" : "MD" }
+{ "_id" : "21044", "city" : "COLUMBIA", "loc" : [ -76.87880699999999, 39.214103 ], "pop" : 32695, "state" : "MD" }
+{ "_id" : "21045", "city" : "COLUMBIA", "loc" : [ -76.83223, 39.205052 ], "pop" : 32658, "state" : "MD" }
+{ "_id" : "21046", "city" : "COLUMBIA", "loc" : [ -76.853796, 39.170236 ], "pop" : 13591, "state" : "MD" }
+{ "_id" : "21047", "city" : "FALLSTON", "loc" : [ -76.43277, 39.527048 ], "pop" : 10230, "state" : "MD" }
+{ "_id" : "21048", "city" : "PATAPSCO", "loc" : [ -76.909862, 39.508645 ], "pop" : 7680, "state" : "MD" }
+{ "_id" : "21050", "city" : "FOREST HILL", "loc" : [ -76.400767, 39.57549 ], "pop" : 9029, "state" : "MD" }
+{ "_id" : "21051", "city" : "FORK", "loc" : [ -76.450361, 39.472937 ], "pop" : 136, "state" : "MD" }
+{ "_id" : "21053", "city" : "FREELAND", "loc" : [ -76.72234899999999, 39.693957 ], "pop" : 2482, "state" : "MD" }
+{ "_id" : "21054", "city" : "GAMBRILLS", "loc" : [ -76.681877, 39.04069 ], "pop" : 7441, "state" : "MD" }
+{ "_id" : "21056", "city" : "GIBSON ISLAND", "loc" : [ -76.432418, 39.07511 ], "pop" : 335, "state" : "MD" }
+{ "_id" : "21057", "city" : "GLEN ARM", "loc" : [ -76.515331, 39.457484 ], "pop" : 3679, "state" : "MD" }
+{ "_id" : "21061", "city" : "GLEN BURNIE", "loc" : [ -76.61886199999999, 39.158968 ], "pop" : 75692, "state" : "MD" }
+{ "_id" : "21071", "city" : "GLYNDON", "loc" : [ -76.78756799999999, 39.492782 ], "pop" : 1761, "state" : "MD" }
+{ "_id" : "21074", "city" : "GREENMOUNT", "loc" : [ -76.849397, 39.61352 ], "pop" : 10443, "state" : "MD" }
+{ "_id" : "21076", "city" : "HANOVER", "loc" : [ -76.721535, 39.155069 ], "pop" : 6265, "state" : "MD" }
+{ "_id" : "21078", "city" : "HAVRE DE GRACE", "loc" : [ -76.117144, 39.552312 ], "pop" : 13536, "state" : "MD" }
+{ "_id" : "21082", "city" : "HYDES", "loc" : [ -76.469538, 39.474049 ], "pop" : 883, "state" : "MD" }
+{ "_id" : "21084", "city" : "JARRETTSVILLE", "loc" : [ -76.46842700000001, 39.616241 ], "pop" : 6667, "state" : "MD" }
+{ "_id" : "21085", "city" : "JOPPA", "loc" : [ -76.354102, 39.424208 ], "pop" : 15006, "state" : "MD" }
+{ "_id" : "21087", "city" : "KINGSVILLE", "loc" : [ -76.41473000000001, 39.455775 ], "pop" : 4283, "state" : "MD" }
+{ "_id" : "21088", "city" : "LINEBORO", "loc" : [ -76.839476, 39.718498 ], "pop" : 94, "state" : "MD" }
+{ "_id" : "21090", "city" : "LINTHICUM HEIGHT", "loc" : [ -76.657477, 39.208331 ], "pop" : 9777, "state" : "MD" }
+{ "_id" : "21093", "city" : "LUTHERVILLE", "loc" : [ -76.633791, 39.438636 ], "pop" : 31560, "state" : "MD" }
+{ "_id" : "21102", "city" : "MANCHESTER", "loc" : [ -76.89407300000001, 39.674746 ], "pop" : 5476, "state" : "MD" }
+{ "_id" : "21104", "city" : "MARRIOTTSVILLE", "loc" : [ -76.913241, 39.334154 ], "pop" : 1482, "state" : "MD" }
+{ "_id" : "21107", "city" : "MILLERS", "loc" : [ -76.82388400000001, 39.683224 ], "pop" : 3218, "state" : "MD" }
+{ "_id" : "21108", "city" : "MILLERSVILLE", "loc" : [ -76.61902000000001, 39.104102 ], "pop" : 16436, "state" : "MD" }
+{ "_id" : "21111", "city" : "HEREFORD", "loc" : [ -76.592957, 39.576611 ], "pop" : 4615, "state" : "MD" }
+{ "_id" : "21113", "city" : "ODENTON", "loc" : [ -76.699583, 39.076197 ], "pop" : 8201, "state" : "MD" }
+{ "_id" : "21114", "city" : "CROFTON", "loc" : [ -76.680166, 39.011163 ], "pop" : 15590, "state" : "MD" }
+{ "_id" : "21117", "city" : "OWINGS MILLS", "loc" : [ -76.776934, 39.42688 ], "pop" : 24913, "state" : "MD" }
+{ "_id" : "21120", "city" : "BENTLEY SPRINGS", "loc" : [ -76.67759100000001, 39.649937 ], "pop" : 5320, "state" : "MD" }
+{ "_id" : "21122", "city" : "RIVIERA BEACH", "loc" : [ -76.516248, 39.129284 ], "pop" : 51386, "state" : "MD" }
+{ "_id" : "21128", "city" : "PERRY HALL", "loc" : [ -76.450987, 39.401013 ], "pop" : 6075, "state" : "MD" }
+{ "_id" : "21131", "city" : "JACKSONVILLE", "loc" : [ -76.564623, 39.506978 ], "pop" : 6703, "state" : "MD" }
+{ "_id" : "21132", "city" : "PYLESVILLE", "loc" : [ -76.41125599999999, 39.695905 ], "pop" : 2782, "state" : "MD" }
+{ "_id" : "21133", "city" : "RANDALLSTOWN", "loc" : [ -76.800245, 39.374571 ], "pop" : 23994, "state" : "MD" }
+{ "_id" : "21136", "city" : "REISTERSTOWN", "loc" : [ -76.813452, 39.45996 ], "pop" : 24812, "state" : "MD" }
+{ "_id" : "21140", "city" : "RIVA", "loc" : [ -76.585437, 38.950391 ], "pop" : 3165, "state" : "MD" }
+{ "_id" : "21144", "city" : "SEVERN", "loc" : [ -76.697953, 39.127543 ], "pop" : 25272, "state" : "MD" }
+{ "_id" : "21146", "city" : "SEVERNA PARK", "loc" : [ -76.55774599999999, 39.081078 ], "pop" : 23392, "state" : "MD" }
+{ "_id" : "21152", "city" : "GLENCOE", "loc" : [ -76.66910900000001, 39.543086 ], "pop" : 4450, "state" : "MD" }
+{ "_id" : "21154", "city" : "ROCKS", "loc" : [ -76.330174, 39.649928 ], "pop" : 5018, "state" : "MD" }
+{ "_id" : "21155", "city" : "FOWBELSBURG", "loc" : [ -76.81623, 39.56394 ], "pop" : 2487, "state" : "MD" }
+{ "_id" : "21156", "city" : "UPPER FALLS", "loc" : [ -76.400604, 39.43967 ], "pop" : 464, "state" : "MD" }
+{ "_id" : "21157", "city" : "CARROLLTON", "loc" : [ -76.99404, 39.555654 ], "pop" : 37148, "state" : "MD" }
+{ "_id" : "21158", "city" : "UNIONTOWN", "loc" : [ -77.036946, 39.655464 ], "pop" : 8491, "state" : "MD" }
+{ "_id" : "21160", "city" : "WHITEFORD", "loc" : [ -76.31601499999999, 39.707709 ], "pop" : 1766, "state" : "MD" }
+{ "_id" : "21161", "city" : "WHITE HALL", "loc" : [ -76.566639, 39.66176 ], "pop" : 4970, "state" : "MD" }
+{ "_id" : "21162", "city" : "WHITE MARSH", "loc" : [ -76.413189, 39.392315 ], "pop" : 2521, "state" : "MD" }
+{ "_id" : "21163", "city" : "GRANITE", "loc" : [ -76.85757, 39.339151 ], "pop" : 2115, "state" : "MD" }
+{ "_id" : "21201", "city" : "BALTIMORE", "loc" : [ -76.625203, 39.29463 ], "pop" : 16256, "state" : "MD" }
+{ "_id" : "21202", "city" : "BALTIMORE", "loc" : [ -76.607499, 39.299844 ], "pop" : 28656, "state" : "MD" }
+{ "_id" : "21204", "city" : "EUDOWOOD", "loc" : [ -76.603224, 39.402517 ], "pop" : 37257, "state" : "MD" }
+{ "_id" : "21205", "city" : "BALTIMORE", "loc" : [ -76.579915, 39.300871 ], "pop" : 23763, "state" : "MD" }
+{ "_id" : "21206", "city" : "BALTIMORE", "loc" : [ -76.541135, 39.336494 ], "pop" : 52114, "state" : "MD" }
+{ "_id" : "21207", "city" : "GWYNN OAK", "loc" : [ -76.734064, 39.329628 ], "pop" : 76002, "state" : "MD" }
+{ "_id" : "21208", "city" : "PIKESVILLE", "loc" : [ -76.72901299999999, 39.376359 ], "pop" : 27723, "state" : "MD" }
+{ "_id" : "21209", "city" : "BALTIMORE", "loc" : [ -76.674431, 39.371622 ], "pop" : 20673, "state" : "MD" }
+{ "_id" : "21210", "city" : "BALTIMORE", "loc" : [ -76.632099, 39.350727 ], "pop" : 12581, "state" : "MD" }
+{ "_id" : "21211", "city" : "BALTIMORE", "loc" : [ -76.63362499999999, 39.331642 ], "pop" : 19797, "state" : "MD" }
+{ "_id" : "21212", "city" : "BALTIMORE", "loc" : [ -76.609989, 39.362571 ], "pop" : 35680, "state" : "MD" }
+{ "_id" : "21213", "city" : "BALTIMORE", "loc" : [ -76.581012, 39.312667 ], "pop" : 47171, "state" : "MD" }
+{ "_id" : "21214", "city" : "BALTIMORE", "loc" : [ -76.564375, 39.35206 ], "pop" : 20949, "state" : "MD" }
+{ "_id" : "21215", "city" : "BALTIMORE", "loc" : [ -76.67939699999999, 39.344572 ], "pop" : 74402, "state" : "MD" }
+{ "_id" : "21216", "city" : "BALTIMORE", "loc" : [ -76.66989100000001, 39.309349 ], "pop" : 42501, "state" : "MD" }
+{ "_id" : "21217", "city" : "BALTIMORE", "loc" : [ -76.639267, 39.306416 ], "pop" : 52502, "state" : "MD" }
+{ "_id" : "21218", "city" : "BALTIMORE", "loc" : [ -76.6048, 39.3265 ], "pop" : 56677, "state" : "MD" }
+{ "_id" : "21219", "city" : "DUNDALK SPARROWS", "loc" : [ -76.44693700000001, 39.229068 ], "pop" : 9467, "state" : "MD" }
+{ "_id" : "21220", "city" : "MIDDLE RIVER", "loc" : [ -76.415255, 39.340098 ], "pop" : 37336, "state" : "MD" }
+{ "_id" : "21221", "city" : "ESSEX", "loc" : [ -76.453259, 39.308553 ], "pop" : 44117, "state" : "MD" }
+{ "_id" : "21222", "city" : "DUNDALK SPARROWS", "loc" : [ -76.502484, 39.26486 ], "pop" : 58181, "state" : "MD" }
+{ "_id" : "21223", "city" : "BALTIMORE", "loc" : [ -76.647586, 39.287 ], "pop" : 39003, "state" : "MD" }
+{ "_id" : "21224", "city" : "BALTIMORE", "loc" : [ -76.556831, 39.287558 ], "pop" : 53629, "state" : "MD" }
+{ "_id" : "21225", "city" : "BROOKLYN CURTIS", "loc" : [ -76.615026, 39.233343 ], "pop" : 35032, "state" : "MD" }
+{ "_id" : "21226", "city" : "BROOKLYN CURTIS", "loc" : [ -76.569147, 39.209315 ], "pop" : 5478, "state" : "MD" }
+{ "_id" : "21227", "city" : "HALETHORPE", "loc" : [ -76.696872, 39.230893 ], "pop" : 45430, "state" : "MD" }
+{ "_id" : "21228", "city" : "CATONSVILLE", "loc" : [ -76.74012399999999, 39.27825 ], "pop" : 43630, "state" : "MD" }
+{ "_id" : "21229", "city" : "BALTIMORE", "loc" : [ -76.689885, 39.285645 ], "pop" : 53962, "state" : "MD" }
+{ "_id" : "21230", "city" : "BALTIMORE", "loc" : [ -76.626193, 39.269943 ], "pop" : 34901, "state" : "MD" }
+{ "_id" : "21231", "city" : "BALTIMORE", "loc" : [ -76.589956, 39.289193 ], "pop" : 15928, "state" : "MD" }
+{ "_id" : "21234", "city" : "PARKVILLE", "loc" : [ -76.54176699999999, 39.387581 ], "pop" : 66477, "state" : "MD" }
+{ "_id" : "21236", "city" : "NOTTINGHAM", "loc" : [ -76.487106, 39.391412 ], "pop" : 33099, "state" : "MD" }
+{ "_id" : "21237", "city" : "ROSEDALE", "loc" : [ -76.50138699999999, 39.336054 ], "pop" : 24835, "state" : "MD" }
+{ "_id" : "21239", "city" : "BALTIMORE", "loc" : [ -76.589082, 39.360977 ], "pop" : 31935, "state" : "MD" }
+{ "_id" : "21240", "city" : "BALTIMORE", "loc" : [ -76.648287, 39.17185 ], "pop" : 1, "state" : "MD" }
+{ "_id" : "21401", "city" : "CAPE SAINT CLAIR", "loc" : [ -76.503139, 38.999645 ], "pop" : 44757, "state" : "MD" }
+{ "_id" : "21402", "city" : "NAVAL ACADEMY", "loc" : [ -76.48079, 38.982436 ], "pop" : 5780, "state" : "MD" }
+{ "_id" : "21403", "city" : "ANNAPOLIS", "loc" : [ -76.49102999999999, 38.952394 ], "pop" : 26587, "state" : "MD" }
+{ "_id" : "21502", "city" : "CRESAPTOWN", "loc" : [ -78.77744199999999, 39.644796 ], "pop" : 44371, "state" : "MD" }
+{ "_id" : "21520", "city" : "ACCIDENT", "loc" : [ -79.30846699999999, 39.635504 ], "pop" : 1968, "state" : "MD" }
+{ "_id" : "21521", "city" : "BARTON", "loc" : [ -79.02813, 39.533135 ], "pop" : 1305, "state" : "MD" }
+{ "_id" : "21522", "city" : "BITTINGER", "loc" : [ -79.214247, 39.597786 ], "pop" : 479, "state" : "MD" }
+{ "_id" : "21523", "city" : "BLOOMINGTON", "loc" : [ -79.11370700000001, 39.487764 ], "pop" : 898, "state" : "MD" }
+{ "_id" : "21530", "city" : "FLINTSTONE", "loc" : [ -78.573949, 39.699288 ], "pop" : 1102, "state" : "MD" }
+{ "_id" : "21531", "city" : "FRIENDSVILLE", "loc" : [ -79.42191200000001, 39.666502 ], "pop" : 2021, "state" : "MD" }
+{ "_id" : "21532", "city" : "FROSTBURG", "loc" : [ -78.930559, 39.649359 ], "pop" : 15702, "state" : "MD" }
+{ "_id" : "21536", "city" : "JENNINGS", "loc" : [ -79.15166499999999, 39.684436 ], "pop" : 3138, "state" : "MD" }
+{ "_id" : "21538", "city" : "SHALLMAR", "loc" : [ -79.202528, 39.396275 ], "pop" : 759, "state" : "MD" }
+{ "_id" : "21539", "city" : "LONACONING", "loc" : [ -78.991477, 39.575703 ], "pop" : 3494, "state" : "MD" }
+{ "_id" : "21540", "city" : "LUKE", "loc" : [ -79.059365, 39.477392 ], "pop" : 184, "state" : "MD" }
+{ "_id" : "21541", "city" : "SANG RUN", "loc" : [ -79.36413400000001, 39.559709 ], "pop" : 1673, "state" : "MD" }
+{ "_id" : "21545", "city" : "MOUNT SAVAGE", "loc" : [ -78.873892, 39.699128 ], "pop" : 2067, "state" : "MD" }
+{ "_id" : "21550", "city" : "DEER PARK", "loc" : [ -79.38966000000001, 39.399993 ], "pop" : 13531, "state" : "MD" }
+{ "_id" : "21555", "city" : "OLDTOWN", "loc" : [ -78.604373, 39.584598 ], "pop" : 2079, "state" : "MD" }
+{ "_id" : "21557", "city" : "RAWLINGS", "loc" : [ -78.90623100000001, 39.521363 ], "pop" : 1919, "state" : "MD" }
+{ "_id" : "21561", "city" : "SWANTON", "loc" : [ -79.240165, 39.476361 ], "pop" : 1719, "state" : "MD" }
+{ "_id" : "21562", "city" : "MCCOOLE", "loc" : [ -79.030726, 39.482625 ], "pop" : 3976, "state" : "MD" }
+{ "_id" : "21601", "city" : "EASTON", "loc" : [ -76.07577499999999, 38.77682 ], "pop" : 16439, "state" : "MD" }
+{ "_id" : "21607", "city" : "BARCLAY", "loc" : [ -75.860079, 39.129871 ], "pop" : 592, "state" : "MD" }
+{ "_id" : "21610", "city" : "BETTERTON", "loc" : [ -76.06393799999999, 39.365509 ], "pop" : 485, "state" : "MD" }
+{ "_id" : "21612", "city" : "BOZMAN", "loc" : [ -76.27641, 38.751493 ], "pop" : 847, "state" : "MD" }
+{ "_id" : "21613", "city" : "CAMBRIDGE", "loc" : [ -76.08735799999999, 38.564282 ], "pop" : 16908, "state" : "MD" }
+{ "_id" : "21617", "city" : "CENTREVILLE", "loc" : [ -76.04497499999999, 39.056423 ], "pop" : 5834, "state" : "MD" }
+{ "_id" : "21619", "city" : "CHESTER", "loc" : [ -76.284183, 38.958296 ], "pop" : 4199, "state" : "MD" }
+{ "_id" : "21620", "city" : "CHESTERTOWN", "loc" : [ -76.080214, 39.212517 ], "pop" : 10618, "state" : "MD" }
+{ "_id" : "21622", "city" : "CHURCH CREEK", "loc" : [ -76.169569, 38.427815 ], "pop" : 593, "state" : "MD" }
+{ "_id" : "21623", "city" : "CHURCH HILL", "loc" : [ -75.988028, 39.145958 ], "pop" : 813, "state" : "MD" }
+{ "_id" : "21625", "city" : "CORDOVA", "loc" : [ -76.00287899999999, 38.870426 ], "pop" : 2346, "state" : "MD" }
+{ "_id" : "21626", "city" : "CRAPO", "loc" : [ -76.11420699999999, 38.329541 ], "pop" : 173, "state" : "MD" }
+{ "_id" : "21628", "city" : "CRUMPTON", "loc" : [ -75.919522, 39.233019 ], "pop" : 689, "state" : "MD" }
+{ "_id" : "21629", "city" : "DENTON", "loc" : [ -75.836071, 38.877928 ], "pop" : 7126, "state" : "MD" }
+{ "_id" : "21631", "city" : "EAST NEW MARKET", "loc" : [ -75.956766, 38.592095 ], "pop" : 2156, "state" : "MD" }
+{ "_id" : "21632", "city" : "FEDERALSBURG", "loc" : [ -75.77537599999999, 38.714681 ], "pop" : 5535, "state" : "MD" }
+{ "_id" : "21634", "city" : "FISHING CREEK", "loc" : [ -76.21678300000001, 38.316292 ], "pop" : 580, "state" : "MD" }
+{ "_id" : "21635", "city" : "GALENA", "loc" : [ -75.871673, 39.337417 ], "pop" : 1087, "state" : "MD" }
+{ "_id" : "21636", "city" : "GOLDSBORO", "loc" : [ -75.792604, 39.022957 ], "pop" : 1179, "state" : "MD" }
+{ "_id" : "21637", "city" : "GOLTS", "loc" : [ -75.805521, 39.355598 ], "pop" : 533, "state" : "MD" }
+{ "_id" : "21638", "city" : "GRASONVILLE", "loc" : [ -76.199701, 38.945602 ], "pop" : 3225, "state" : "MD" }
+{ "_id" : "21639", "city" : "GREENSBORO", "loc" : [ -75.80591099999999, 38.961632 ], "pop" : 3516, "state" : "MD" }
+{ "_id" : "21640", "city" : "HENDERSON", "loc" : [ -75.794787, 39.067197 ], "pop" : 1391, "state" : "MD" }
+{ "_id" : "21643", "city" : "WILLIAMSBURG", "loc" : [ -75.866254, 38.642826 ], "pop" : 4625, "state" : "MD" }
+{ "_id" : "21644", "city" : "INGLESIDE", "loc" : [ -75.89174800000001, 39.124654 ], "pop" : 159, "state" : "MD" }
+{ "_id" : "21645", "city" : "KENNEDYVILLE", "loc" : [ -75.981797, 39.297835 ], "pop" : 1807, "state" : "MD" }
+{ "_id" : "21647", "city" : "MCDANIEL", "loc" : [ -76.280593, 38.819213 ], "pop" : 610, "state" : "MD" }
+{ "_id" : "21649", "city" : "MARYDEL", "loc" : [ -75.762247, 39.108169 ], "pop" : 1195, "state" : "MD" }
+{ "_id" : "21650", "city" : "MASSEY", "loc" : [ -75.821483, 39.312569 ], "pop" : 112, "state" : "MD" }
+{ "_id" : "21651", "city" : "MILLINGTON", "loc" : [ -75.84996599999999, 39.257989 ], "pop" : 2003, "state" : "MD" }
+{ "_id" : "21654", "city" : "OXFORD", "loc" : [ -76.153783, 38.686358 ], "pop" : 1350, "state" : "MD" }
+{ "_id" : "21655", "city" : "PRESTON", "loc" : [ -75.916284, 38.746456 ], "pop" : 4425, "state" : "MD" }
+{ "_id" : "21657", "city" : "QUEEN ANNE", "loc" : [ -75.977655, 38.945583 ], "pop" : 1092, "state" : "MD" }
+{ "_id" : "21658", "city" : "QUEENSTOWN", "loc" : [ -76.152646, 38.956235 ], "pop" : 3330, "state" : "MD" }
+{ "_id" : "21659", "city" : "RHODESDALE", "loc" : [ -75.774945, 38.602985 ], "pop" : 2276, "state" : "MD" }
+{ "_id" : "21660", "city" : "RIDGELY", "loc" : [ -75.88482500000001, 38.956787 ], "pop" : 2754, "state" : "MD" }
+{ "_id" : "21661", "city" : "ROCK HALL", "loc" : [ -76.230467, 39.134371 ], "pop" : 2770, "state" : "MD" }
+{ "_id" : "21662", "city" : "ROYAL OAK", "loc" : [ -76.187788, 38.72883 ], "pop" : 889, "state" : "MD" }
+{ "_id" : "21663", "city" : "SAINT MICHAELS", "loc" : [ -76.221547, 38.782965 ], "pop" : 3247, "state" : "MD" }
+{ "_id" : "21665", "city" : "SHERWOOD", "loc" : [ -76.327822, 38.73741 ], "pop" : 262, "state" : "MD" }
+{ "_id" : "21666", "city" : "STEVENSVILLE", "loc" : [ -76.337087, 38.939399 ], "pop" : 8630, "state" : "MD" }
+{ "_id" : "21667", "city" : "STILL POND", "loc" : [ -76.052156, 39.327624 ], "pop" : 289, "state" : "MD" }
+{ "_id" : "21668", "city" : "SUDLERSVILLE", "loc" : [ -75.849968, 39.182339 ], "pop" : 2014, "state" : "MD" }
+{ "_id" : "21669", "city" : "TAYLORS ISLAND", "loc" : [ -76.296406, 38.463095 ], "pop" : 246, "state" : "MD" }
+{ "_id" : "21671", "city" : "TILGHMAN", "loc" : [ -76.337653, 38.706309 ], "pop" : 745, "state" : "MD" }
+{ "_id" : "21672", "city" : "TODDVILLE", "loc" : [ -76.059634, 38.272592 ], "pop" : 361, "state" : "MD" }
+{ "_id" : "21673", "city" : "TRAPPE", "loc" : [ -76.05067, 38.66466 ], "pop" : 2958, "state" : "MD" }
+{ "_id" : "21675", "city" : "WINGATE", "loc" : [ -76.086303, 38.289898 ], "pop" : 160, "state" : "MD" }
+{ "_id" : "21676", "city" : "WITTMAN", "loc" : [ -76.29931000000001, 38.789187 ], "pop" : 338, "state" : "MD" }
+{ "_id" : "21677", "city" : "WOOLFORD", "loc" : [ -76.20405700000001, 38.5066 ], "pop" : 459, "state" : "MD" }
+{ "_id" : "21678", "city" : "WORTON", "loc" : [ -76.10078, 39.296346 ], "pop" : 1680, "state" : "MD" }
+{ "_id" : "21679", "city" : "WYE MILLS", "loc" : [ -76.081366, 38.928114 ], "pop" : 270, "state" : "MD" }
+{ "_id" : "21701", "city" : "LEWISTOWN", "loc" : [ -77.400875, 39.408235 ], "pop" : 35492, "state" : "MD" }
+{ "_id" : "21702", "city" : "FORT DETRICK", "loc" : [ -77.44736899999999, 39.436532 ], "pop" : 33704, "state" : "MD" }
+{ "_id" : "21710", "city" : "DOUBS", "loc" : [ -77.447693, 39.306452 ], "pop" : 2085, "state" : "MD" }
+{ "_id" : "21711", "city" : "BIG POOL", "loc" : [ -78.01044899999999, 39.645685 ], "pop" : 1083, "state" : "MD" }
+{ "_id" : "21713", "city" : "FAHRNEY KEEDY ME", "loc" : [ -77.683522, 39.532244 ], "pop" : 10501, "state" : "MD" }
+{ "_id" : "21716", "city" : "BRUNSWICK", "loc" : [ -77.623002, 39.316356 ], "pop" : 5160, "state" : "MD" }
+{ "_id" : "21718", "city" : "BURKITTSVILLE", "loc" : [ -77.626508, 39.397066 ], "pop" : 285, "state" : "MD" }
+{ "_id" : "21719", "city" : "FORT RITCHIE", "loc" : [ -77.495609, 39.707341 ], "pop" : 2672, "state" : "MD" }
+{ "_id" : "21722", "city" : "BIG SPRING", "loc" : [ -77.912592, 39.661693 ], "pop" : 3661, "state" : "MD" }
+{ "_id" : "21723", "city" : "COOKSVILLE", "loc" : [ -77.005076, 39.321109 ], "pop" : 353, "state" : "MD" }
+{ "_id" : "21725", "city" : "DETOUR", "loc" : [ -77.248272, 39.614661 ], "pop" : 970, "state" : "MD" }
+{ "_id" : "21727", "city" : "EMMITSBURG", "loc" : [ -77.335658, 39.694044 ], "pop" : 5095, "state" : "MD" }
+{ "_id" : "21733", "city" : "FAIR PLAY", "loc" : [ -77.76146799999999, 39.542279 ], "pop" : 153, "state" : "MD" }
+{ "_id" : "21737", "city" : "GLENELG", "loc" : [ -77.005703, 39.262064 ], "pop" : 681, "state" : "MD" }
+{ "_id" : "21738", "city" : "GLENWOOD", "loc" : [ -77.014821, 39.279519 ], "pop" : 1632, "state" : "MD" }
+{ "_id" : "21740", "city" : "HAGERSTOWN", "loc" : [ -77.73721500000001, 39.632022 ], "pop" : 47679, "state" : "MD" }
+{ "_id" : "21742", "city" : "HAGERSTOWN", "loc" : [ -77.69210200000001, 39.657291 ], "pop" : 28398, "state" : "MD" }
+{ "_id" : "21750", "city" : "HANCOCK", "loc" : [ -78.17624600000001, 39.699083 ], "pop" : 4275, "state" : "MD" }
+{ "_id" : "21754", "city" : "IJAMSVILLE", "loc" : [ -77.296363, 39.326737 ], "pop" : 4078, "state" : "MD" }
+{ "_id" : "21755", "city" : "JEFFERSON", "loc" : [ -77.544061, 39.365291 ], "pop" : 4132, "state" : "MD" }
+{ "_id" : "21756", "city" : "KEEDYSVILLE", "loc" : [ -77.694427, 39.456323 ], "pop" : 2546, "state" : "MD" }
+{ "_id" : "21757", "city" : "KEYMAR", "loc" : [ -77.281661, 39.565619 ], "pop" : 1691, "state" : "MD" }
+{ "_id" : "21758", "city" : "KNOXVILLE", "loc" : [ -77.651286, 39.347891 ], "pop" : 3534, "state" : "MD" }
+{ "_id" : "21764", "city" : "LINWOOD", "loc" : [ -77.118443, 39.577654 ], "pop" : 591, "state" : "MD" }
+{ "_id" : "21766", "city" : "LITTLE ORLEANS", "loc" : [ -78.378139, 39.687593 ], "pop" : 699, "state" : "MD" }
+{ "_id" : "21767", "city" : "MAUGANSVILLE", "loc" : [ -77.749915, 39.6996 ], "pop" : 598, "state" : "MD" }
+{ "_id" : "21769", "city" : "MIDDLETOWN", "loc" : [ -77.550241, 39.441586 ], "pop" : 8732, "state" : "MD" }
+{ "_id" : "21770", "city" : "MONROVIA", "loc" : [ -77.249442, 39.351248 ], "pop" : 5033, "state" : "MD" }
+{ "_id" : "21771", "city" : "MOUNT AIRY", "loc" : [ -77.172347, 39.388131 ], "pop" : 21912, "state" : "MD" }
+{ "_id" : "21773", "city" : "MYERSVILLE", "loc" : [ -77.551322, 39.528194 ], "pop" : 3363, "state" : "MD" }
+{ "_id" : "21776", "city" : "NEW WINDSOR", "loc" : [ -77.103397, 39.516233 ], "pop" : 4576, "state" : "MD" }
+{ "_id" : "21777", "city" : "POINT OF ROCKS", "loc" : [ -77.53276200000001, 39.279089 ], "pop" : 812, "state" : "MD" }
+{ "_id" : "21778", "city" : "ROCKY RIDGE", "loc" : [ -77.329635, 39.605696 ], "pop" : 988, "state" : "MD" }
+{ "_id" : "21779", "city" : "ROHRERSVILLE", "loc" : [ -77.657977, 39.443052 ], "pop" : 200, "state" : "MD" }
+{ "_id" : "21780", "city" : "SABILLASVILLE", "loc" : [ -77.469323, 39.682772 ], "pop" : 1605, "state" : "MD" }
+{ "_id" : "21782", "city" : "SHARPSBURG", "loc" : [ -77.75107199999999, 39.442394 ], "pop" : 3624, "state" : "MD" }
+{ "_id" : "21783", "city" : "SMITHSBURG", "loc" : [ -77.57056300000001, 39.647036 ], "pop" : 6857, "state" : "MD" }
+{ "_id" : "21784", "city" : "CARROLLTOWNE", "loc" : [ -76.961439, 39.39887 ], "pop" : 28493, "state" : "MD" }
+{ "_id" : "21787", "city" : "TANEYTOWN", "loc" : [ -77.16905800000001, 39.665798 ], "pop" : 7612, "state" : "MD" }
+{ "_id" : "21788", "city" : "GRACEHAM", "loc" : [ -77.405114, 39.606576 ], "pop" : 8929, "state" : "MD" }
+{ "_id" : "21790", "city" : "TUSCARORA", "loc" : [ -77.51011, 39.266689 ], "pop" : 134, "state" : "MD" }
+{ "_id" : "21791", "city" : "UNIONVILLE", "loc" : [ -77.194346, 39.541484 ], "pop" : 3942, "state" : "MD" }
+{ "_id" : "21793", "city" : "WALKERSVILLE", "loc" : [ -77.34838999999999, 39.47875 ], "pop" : 8957, "state" : "MD" }
+{ "_id" : "21794", "city" : "WEST FRIENDSHIP", "loc" : [ -76.966031, 39.293447 ], "pop" : 937, "state" : "MD" }
+{ "_id" : "21795", "city" : "WILLIAMSPORT", "loc" : [ -77.808705, 39.593023 ], "pop" : 8739, "state" : "MD" }
+{ "_id" : "21797", "city" : "WOODBINE", "loc" : [ -77.06469800000001, 39.346438 ], "pop" : 6224, "state" : "MD" }
+{ "_id" : "21798", "city" : "WOODSBORO", "loc" : [ -77.29718699999999, 39.531121 ], "pop" : 1771, "state" : "MD" }
+{ "_id" : "21801", "city" : "SALISBURY", "loc" : [ -75.59223799999999, 38.362996 ], "pop" : 52905, "state" : "MD" }
+{ "_id" : "21811", "city" : "BERLIN", "loc" : [ -75.18655699999999, 38.347514 ], "pop" : 11613, "state" : "MD" }
+{ "_id" : "21813", "city" : "BISHOPVILLE", "loc" : [ -75.18554399999999, 38.429609 ], "pop" : 1902, "state" : "MD" }
+{ "_id" : "21814", "city" : "BIVALVE", "loc" : [ -75.89140999999999, 38.295337 ], "pop" : 307, "state" : "MD" }
+{ "_id" : "21816", "city" : "CHANCE", "loc" : [ -75.93919200000001, 38.178504 ], "pop" : 415, "state" : "MD" }
+{ "_id" : "21817", "city" : "CRISFIELD", "loc" : [ -75.842882, 37.984496 ], "pop" : 5342, "state" : "MD" }
+{ "_id" : "21820", "city" : "DAMES QUARTER", "loc" : [ -75.900082, 38.190568 ], "pop" : 192, "state" : "MD" }
+{ "_id" : "21821", "city" : "DEAL ISLAND", "loc" : [ -75.94955899999999, 38.153326 ], "pop" : 259, "state" : "MD" }
+{ "_id" : "21822", "city" : "EDEN", "loc" : [ -75.648167, 38.276155 ], "pop" : 1042, "state" : "MD" }
+{ "_id" : "21824", "city" : "EWELL", "loc" : [ -76.03506, 37.99379 ], "pop" : 252, "state" : "MD" }
+{ "_id" : "21826", "city" : "FRUITLAND", "loc" : [ -75.622782, 38.322523 ], "pop" : 3771, "state" : "MD" }
+{ "_id" : "21829", "city" : "GIRDLETREE", "loc" : [ -75.390232, 38.095815 ], "pop" : 495, "state" : "MD" }
+{ "_id" : "21830", "city" : "HEBRON", "loc" : [ -75.69626700000001, 38.402597 ], "pop" : 2415, "state" : "MD" }
+{ "_id" : "21835", "city" : "LINKWOOD", "loc" : [ -75.963015, 38.540317 ], "pop" : 576, "state" : "MD" }
+{ "_id" : "21837", "city" : "MARDELA SPRINGS", "loc" : [ -75.74144200000001, 38.486386 ], "pop" : 3039, "state" : "MD" }
+{ "_id" : "21838", "city" : "MARION STATION", "loc" : [ -75.757903, 38.026637 ], "pop" : 2323, "state" : "MD" }
+{ "_id" : "21840", "city" : "NANTICOKE", "loc" : [ -75.90212699999999, 38.267211 ], "pop" : 358, "state" : "MD" }
+{ "_id" : "21841", "city" : "NEWARK", "loc" : [ -75.289316, 38.248875 ], "pop" : 765, "state" : "MD" }
+{ "_id" : "21842", "city" : "OCEAN CITY", "loc" : [ -75.081011, 38.379248 ], "pop" : 6914, "state" : "MD" }
+{ "_id" : "21849", "city" : "PARSONSBURG", "loc" : [ -75.473658, 38.391392 ], "pop" : 2407, "state" : "MD" }
+{ "_id" : "21850", "city" : "PITTSVILLE", "loc" : [ -75.407589, 38.375465 ], "pop" : 1997, "state" : "MD" }
+{ "_id" : "21851", "city" : "POCOMOKE CITY", "loc" : [ -75.555038, 38.071369 ], "pop" : 7527, "state" : "MD" }
+{ "_id" : "21853", "city" : "PRINCESS ANNE", "loc" : [ -75.70723700000001, 38.191929 ], "pop" : 10343, "state" : "MD" }
+{ "_id" : "21856", "city" : "QUANTICO", "loc" : [ -75.78510199999999, 38.333888 ], "pop" : 1029, "state" : "MD" }
+{ "_id" : "21863", "city" : "SNOW HILL", "loc" : [ -75.40498700000001, 38.186794 ], "pop" : 5195, "state" : "MD" }
+{ "_id" : "21864", "city" : "STOCKTON", "loc" : [ -75.41076200000001, 38.045155 ], "pop" : 691, "state" : "MD" }
+{ "_id" : "21865", "city" : "TYASKIN", "loc" : [ -75.869032, 38.30706 ], "pop" : 504, "state" : "MD" }
+{ "_id" : "21866", "city" : "TYLERTON", "loc" : [ -76.023036, 37.967436 ], "pop" : 112, "state" : "MD" }
+{ "_id" : "21869", "city" : "VIENNA", "loc" : [ -75.87292600000001, 38.477376 ], "pop" : 1119, "state" : "MD" }
+{ "_id" : "21870", "city" : "WENONA", "loc" : [ -75.94402100000001, 38.133222 ], "pop" : 358, "state" : "MD" }
+{ "_id" : "21871", "city" : "WESTOVER", "loc" : [ -75.74056299999999, 38.10099 ], "pop" : 1881, "state" : "MD" }
+{ "_id" : "21872", "city" : "WHALEYSVILLE", "loc" : [ -75.28886799999999, 38.404169 ], "pop" : 758, "state" : "MD" }
+{ "_id" : "21874", "city" : "WILLARDS", "loc" : [ -75.355161, 38.393853 ], "pop" : 1895, "state" : "MD" }
+{ "_id" : "21875", "city" : "DELMAR", "loc" : [ -75.55828, 38.44451 ], "pop" : 3712, "state" : "MD" }
+{ "_id" : "21901", "city" : "NORTH EAST", "loc" : [ -75.953805, 39.604535 ], "pop" : 10560, "state" : "MD" }
+{ "_id" : "21903", "city" : "PERRYVILLE", "loc" : [ -76.05922700000001, 39.564894 ], "pop" : 4678, "state" : "MD" }
+{ "_id" : "21904", "city" : "BAINBRIDGE", "loc" : [ -76.08370600000001, 39.622264 ], "pop" : 5507, "state" : "MD" }
+{ "_id" : "21911", "city" : "RISING SUN", "loc" : [ -76.049164, 39.688176 ], "pop" : 7798, "state" : "MD" }
+{ "_id" : "21912", "city" : "WARWICK", "loc" : [ -75.799592, 39.428261 ], "pop" : 745, "state" : "MD" }
+{ "_id" : "21913", "city" : "CECILTON", "loc" : [ -75.86539500000001, 39.40151 ], "pop" : 611, "state" : "MD" }
+{ "_id" : "21914", "city" : "CHARLESTOWN", "loc" : [ -75.97953699999999, 39.57287 ], "pop" : 638, "state" : "MD" }
+{ "_id" : "21915", "city" : "CHESAPEAKE CITY", "loc" : [ -75.840581, 39.513308 ], "pop" : 2823, "state" : "MD" }
+{ "_id" : "21917", "city" : "COLORA", "loc" : [ -76.09336399999999, 39.669515 ], "pop" : 1868, "state" : "MD" }
+{ "_id" : "21918", "city" : "CONOWINGO", "loc" : [ -76.15719799999999, 39.67775 ], "pop" : 3025, "state" : "MD" }
+{ "_id" : "21919", "city" : "EARLEVILLE", "loc" : [ -75.94031, 39.427105 ], "pop" : 2196, "state" : "MD" }
+{ "_id" : "21921", "city" : "ELKTON", "loc" : [ -75.84584, 39.626434 ], "pop" : 30901, "state" : "MD" }
+{ "_id" : "22001", "city" : "ALDIE", "loc" : [ -77.602281, 38.957878 ], "pop" : 1574, "state" : "VA" }
+{ "_id" : "22002", "city" : "AMISSVILLE", "loc" : [ -78.038053, 38.710055 ], "pop" : 1581, "state" : "VA" }
+{ "_id" : "22003", "city" : "ANNANDALE", "loc" : [ -77.21424500000001, 38.830699 ], "pop" : 50054, "state" : "VA" }
+{ "_id" : "22010", "city" : "ARCOLA", "loc" : [ -77.538721, 38.973626 ], "pop" : 61, "state" : "VA" }
+{ "_id" : "22011", "city" : "ASHBURN", "loc" : [ -77.48061199999999, 39.039918 ], "pop" : 3979, "state" : "VA" }
+{ "_id" : "22012", "city" : "BLUEMONT", "loc" : [ -77.831416, 39.097732 ], "pop" : 557, "state" : "VA" }
+{ "_id" : "22013", "city" : "BRISTOW", "loc" : [ -77.57884300000001, 38.74644 ], "pop" : 1568, "state" : "VA" }
+{ "_id" : "22014", "city" : "BROAD RUN", "loc" : [ -77.68611, 38.828653 ], "pop" : 344, "state" : "VA" }
+{ "_id" : "22015", "city" : "BURKE", "loc" : [ -77.28175, 38.789408 ], "pop" : 41783, "state" : "VA" }
+{ "_id" : "22018", "city" : "CATHARPIN", "loc" : [ -77.561155, 38.853007 ], "pop" : 647, "state" : "VA" }
+{ "_id" : "22019", "city" : "CATLETT", "loc" : [ -77.653548, 38.635067 ], "pop" : 4180, "state" : "VA" }
+{ "_id" : "22020", "city" : "CENTREVILLE", "loc" : [ -77.45117500000001, 38.841805 ], "pop" : 33039, "state" : "VA" }
+{ "_id" : "22021", "city" : "CHANTILLY", "loc" : [ -77.435436, 38.884131 ], "pop" : 14835, "state" : "VA" }
+{ "_id" : "22024", "city" : "CLIFTON", "loc" : [ -77.406955, 38.800662 ], "pop" : 9554, "state" : "VA" }
+{ "_id" : "22025", "city" : "DELAPLANE", "loc" : [ -77.930176, 38.911293 ], "pop" : 916, "state" : "VA" }
+{ "_id" : "22026", "city" : "DUMFRIES", "loc" : [ -77.33870400000001, 38.602344 ], "pop" : 17563, "state" : "VA" }
+{ "_id" : "22027", "city" : "DUNN LORING", "loc" : [ -77.221351, 38.895368 ], "pop" : 1084, "state" : "VA" }
+{ "_id" : "22030", "city" : "FAIRFAX", "loc" : [ -77.324151, 38.845826 ], "pop" : 32754, "state" : "VA" }
+{ "_id" : "22031", "city" : "FAIRFAX", "loc" : [ -77.264937, 38.860353 ], "pop" : 22035, "state" : "VA" }
+{ "_id" : "22032", "city" : "FAIRFAX", "loc" : [ -77.29252700000001, 38.817729 ], "pop" : 29971, "state" : "VA" }
+{ "_id" : "22033", "city" : "FAIRFAX", "loc" : [ -77.388451, 38.877627 ], "pop" : 20873, "state" : "VA" }
+{ "_id" : "22039", "city" : "FAIRFAX STATION", "loc" : [ -77.306388, 38.760205 ], "pop" : 14491, "state" : "VA" }
+{ "_id" : "22041", "city" : "BAILEYS CROSSROA", "loc" : [ -77.136928, 38.848506 ], "pop" : 21801, "state" : "VA" }
+{ "_id" : "22042", "city" : "MOSBY", "loc" : [ -77.19227100000001, 38.866272 ], "pop" : 28441, "state" : "VA" }
+{ "_id" : "22043", "city" : "PIMMIT", "loc" : [ -77.20005, 38.901226 ], "pop" : 20928, "state" : "VA" }
+{ "_id" : "22044", "city" : "SEVEN CORNERS", "loc" : [ -77.150819, 38.863544 ], "pop" : 10100, "state" : "VA" }
+{ "_id" : "22046", "city" : "FALLS CHURCH", "loc" : [ -77.18023100000001, 38.88559 ], "pop" : 14864, "state" : "VA" }
+{ "_id" : "22060", "city" : "FORT BELVOIR", "loc" : [ -77.143315, 38.694699 ], "pop" : 6013, "state" : "VA" }
+{ "_id" : "22065", "city" : "GAINESVILLE", "loc" : [ -77.618673, 38.823192 ], "pop" : 3929, "state" : "VA" }
+{ "_id" : "22066", "city" : "GREAT FALLS", "loc" : [ -77.30828700000001, 39.003893 ], "pop" : 13542, "state" : "VA" }
+{ "_id" : "22068", "city" : "HAMILTON", "loc" : [ -77.663538, 39.135741 ], "pop" : 2821, "state" : "VA" }
+{ "_id" : "22069", "city" : "HAYMARKET", "loc" : [ -77.647485, 38.876234 ], "pop" : 5103, "state" : "VA" }
+{ "_id" : "22070", "city" : "HERNDON", "loc" : [ -77.386573, 38.977833 ], "pop" : 30669, "state" : "VA" }
+{ "_id" : "22071", "city" : "HERNDON", "loc" : [ -77.395155, 38.919537 ], "pop" : 21490, "state" : "VA" }
+{ "_id" : "22075", "city" : "LEESBURG", "loc" : [ -77.565918, 39.116517 ], "pop" : 21011, "state" : "VA" }
+{ "_id" : "22079", "city" : "MASON NECK", "loc" : [ -77.21800399999999, 38.704716 ], "pop" : 17438, "state" : "VA" }
+{ "_id" : "22080", "city" : "LOVETTSVILLE", "loc" : [ -77.639144, 39.265367 ], "pop" : 3631, "state" : "VA" }
+{ "_id" : "22090", "city" : "LAKE ANNE", "loc" : [ -77.33760700000001, 38.964439 ], "pop" : 12710, "state" : "VA" }
+{ "_id" : "22091", "city" : "RESTON", "loc" : [ -77.35144, 38.935007 ], "pop" : 28381, "state" : "VA" }
+{ "_id" : "22094", "city" : "RESTON", "loc" : [ -77.350757, 38.975627 ], "pop" : 5491, "state" : "VA" }
+{ "_id" : "22101", "city" : "MC LEAN", "loc" : [ -77.17062799999999, 38.932624 ], "pop" : 27236, "state" : "VA" }
+{ "_id" : "22102", "city" : "WEST MCLEAN", "loc" : [ -77.221934, 38.936318 ], "pop" : 15809, "state" : "VA" }
+{ "_id" : "22110", "city" : "MANASSAS", "loc" : [ -77.489474, 38.768922 ], "pop" : 50680, "state" : "VA" }
+{ "_id" : "22111", "city" : "MANASSAS PARK", "loc" : [ -77.44568, 38.736143 ], "pop" : 32739, "state" : "VA" }
+{ "_id" : "22115", "city" : "MARSHALL", "loc" : [ -77.887567, 38.831584 ], "pop" : 5195, "state" : "VA" }
+{ "_id" : "22117", "city" : "MIDDLEBURG", "loc" : [ -77.735511, 38.996438 ], "pop" : 2908, "state" : "VA" }
+{ "_id" : "22123", "city" : "NOKESVILLE", "loc" : [ -77.534249, 38.685015 ], "pop" : 6729, "state" : "VA" }
+{ "_id" : "22124", "city" : "OAKTON", "loc" : [ -77.323345, 38.885187 ], "pop" : 13019, "state" : "VA" }
+{ "_id" : "22129", "city" : "PAEONIAN SPRINGS", "loc" : [ -77.619845, 39.159792 ], "pop" : 488, "state" : "VA" }
+{ "_id" : "22130", "city" : "PARIS", "loc" : [ -77.893855, 38.989926 ], "pop" : 317, "state" : "VA" }
+{ "_id" : "22132", "city" : "HILLSBORO", "loc" : [ -77.721305, 39.150484 ], "pop" : 5373, "state" : "VA" }
+{ "_id" : "22134", "city" : "QUANTICO", "loc" : [ -77.335819, 38.531039 ], "pop" : 9039, "state" : "VA" }
+{ "_id" : "22141", "city" : "ROUND HILL", "loc" : [ -77.783305, 39.113378 ], "pop" : 1926, "state" : "VA" }
+{ "_id" : "22150", "city" : "SPRINGFIELD", "loc" : [ -77.186582, 38.779718 ], "pop" : 16811, "state" : "VA" }
+{ "_id" : "22151", "city" : "NORTH SPRINGFIEL", "loc" : [ -77.213908, 38.803323 ], "pop" : 15979, "state" : "VA" }
+{ "_id" : "22152", "city" : "WEST SPRINGFIELD", "loc" : [ -77.233243, 38.776488 ], "pop" : 26803, "state" : "VA" }
+{ "_id" : "22153", "city" : "SPRINGFIELD", "loc" : [ -77.237026, 38.744859 ], "pop" : 32161, "state" : "VA" }
+{ "_id" : "22170", "city" : "STERLING", "loc" : [ -77.398624, 39.02147 ], "pop" : 38891, "state" : "VA" }
+{ "_id" : "22171", "city" : "THE PLAINS", "loc" : [ -77.772092, 38.87393 ], "pop" : 2071, "state" : "VA" }
+{ "_id" : "22172", "city" : "TRIANGLE", "loc" : [ -77.32287700000001, 38.550894 ], "pop" : 5181, "state" : "VA" }
+{ "_id" : "22176", "city" : "UPPERVILLE", "loc" : [ -77.848438, 39.008747 ], "pop" : 755, "state" : "VA" }
+{ "_id" : "22180", "city" : "VIENNA", "loc" : [ -77.253219, 38.893527 ], "pop" : 20795, "state" : "VA" }
+{ "_id" : "22181", "city" : "VIENNA", "loc" : [ -77.288048, 38.897695 ], "pop" : 12462, "state" : "VA" }
+{ "_id" : "22182", "city" : "VIENNA", "loc" : [ -77.264876, 38.928005 ], "pop" : 19121, "state" : "VA" }
+{ "_id" : "22186", "city" : "AIRLIE", "loc" : [ -77.764809, 38.72593 ], "pop" : 24248, "state" : "VA" }
+{ "_id" : "22190", "city" : "WATERFORD", "loc" : [ -77.642134, 39.208102 ], "pop" : 264, "state" : "VA" }
+{ "_id" : "22191", "city" : "WOODBRIDGE", "loc" : [ -77.268264, 38.635573 ], "pop" : 30657, "state" : "VA" }
+{ "_id" : "22192", "city" : "LAKERIDGE", "loc" : [ -77.305221, 38.68328 ], "pop" : 38960, "state" : "VA" }
+{ "_id" : "22193", "city" : "DALE CITY", "loc" : [ -77.343238, 38.647188 ], "pop" : 47213, "state" : "VA" }
+{ "_id" : "22201", "city" : "ARLINGTON", "loc" : [ -77.093197, 38.887103 ], "pop" : 22034, "state" : "VA" }
+{ "_id" : "22202", "city" : "ARLINGTON", "loc" : [ -77.059228, 38.856547 ], "pop" : 17453, "state" : "VA" }
+{ "_id" : "22203", "city" : "ARLINGTON", "loc" : [ -77.11419100000001, 38.873799 ], "pop" : 14553, "state" : "VA" }
+{ "_id" : "22204", "city" : "ARLINGTON", "loc" : [ -77.099688, 38.858962 ], "pop" : 41844, "state" : "VA" }
+{ "_id" : "22205", "city" : "ARLINGTON", "loc" : [ -77.139488, 38.883557 ], "pop" : 15285, "state" : "VA" }
+{ "_id" : "22206", "city" : "ARLINGTON", "loc" : [ -77.09045999999999, 38.841508 ], "pop" : 17628, "state" : "VA" }
+{ "_id" : "22207", "city" : "ARLINGTON", "loc" : [ -77.126287, 38.903321 ], "pop" : 27999, "state" : "VA" }
+{ "_id" : "22209", "city" : "ARLINGTON", "loc" : [ -77.07531, 38.8926 ], "pop" : 10118, "state" : "VA" }
+{ "_id" : "22211", "city" : "ARLINGTON", "loc" : [ -77.080258, 38.8795 ], "pop" : 2432, "state" : "VA" }
+{ "_id" : "22213", "city" : "ARLINGTON", "loc" : [ -77.16329500000001, 38.895375 ], "pop" : 2095, "state" : "VA" }
+{ "_id" : "22301", "city" : "ALEXANDRIA", "loc" : [ -77.05890100000001, 38.820042 ], "pop" : 12109, "state" : "VA" }
+{ "_id" : "22302", "city" : "ALEXANDRIA", "loc" : [ -77.092412, 38.83354 ], "pop" : 17021, "state" : "VA" }
+{ "_id" : "22303", "city" : "JEFFERSON MANOR", "loc" : [ -77.07660799999999, 38.791143 ], "pop" : 12662, "state" : "VA" }
+{ "_id" : "22304", "city" : "ALEXANDRIA", "loc" : [ -77.12098899999999, 38.814871 ], "pop" : 33747, "state" : "VA" }
+{ "_id" : "22305", "city" : "ALEXANDRIA", "loc" : [ -77.06403899999999, 38.837184 ], "pop" : 13514, "state" : "VA" }
+{ "_id" : "22306", "city" : "COMMUNITY", "loc" : [ -77.08538900000001, 38.755769 ], "pop" : 24374, "state" : "VA" }
+{ "_id" : "22307", "city" : "BELLE VIEW", "loc" : [ -77.062511, 38.77056 ], "pop" : 9821, "state" : "VA" }
+{ "_id" : "22308", "city" : "WELLINGTON", "loc" : [ -77.06063899999999, 38.729122 ], "pop" : 12023, "state" : "VA" }
+{ "_id" : "22309", "city" : "ENGLESIDE", "loc" : [ -77.10813899999999, 38.727855 ], "pop" : 27479, "state" : "VA" }
+{ "_id" : "22310", "city" : "FRANCONIA", "loc" : [ -77.13170700000001, 38.769132 ], "pop" : 39438, "state" : "VA" }
+{ "_id" : "22311", "city" : "ALEXANDRIA", "loc" : [ -77.119962, 38.832039 ], "pop" : 11388, "state" : "VA" }
+{ "_id" : "22312", "city" : "ALEXANDRIA", "loc" : [ -77.148438, 38.819099 ], "pop" : 23848, "state" : "VA" }
+{ "_id" : "22314", "city" : "ALEXANDRIA", "loc" : [ -77.05286700000001, 38.806018 ], "pop" : 20606, "state" : "VA" }
+{ "_id" : "22401", "city" : "FREDERICKSBURG", "loc" : [ -77.477152, 38.299538 ], "pop" : 19027, "state" : "VA" }
+{ "_id" : "22405", "city" : "FALMOUTH", "loc" : [ -77.404537, 38.314557 ], "pop" : 20039, "state" : "VA" }
+{ "_id" : "22406", "city" : "FREDERICKSBURG", "loc" : [ -77.534892, 38.379627 ], "pop" : 7583, "state" : "VA" }
+{ "_id" : "22407", "city" : "FREDERICKSBURG", "loc" : [ -77.547584, 38.268803 ], "pop" : 27852, "state" : "VA" }
+{ "_id" : "22408", "city" : "FREDERICKSBURG", "loc" : [ -77.468068, 38.248141 ], "pop" : 9433, "state" : "VA" }
+{ "_id" : "22427", "city" : "BOWLING GREEN", "loc" : [ -77.18024200000001, 38.013651 ], "pop" : 559, "state" : "VA" }
+{ "_id" : "22432", "city" : "BURGESS", "loc" : [ -76.354164, 37.868682 ], "pop" : 478, "state" : "VA" }
+{ "_id" : "22433", "city" : "BURR HILL", "loc" : [ -77.876166, 38.365841 ], "pop" : 121, "state" : "VA" }
+{ "_id" : "22435", "city" : "CALLAO", "loc" : [ -76.573245, 37.977268 ], "pop" : 1808, "state" : "VA" }
+{ "_id" : "22436", "city" : "CARET", "loc" : [ -76.915254, 37.971255 ], "pop" : 675, "state" : "VA" }
+{ "_id" : "22437", "city" : "CENTER CROSS", "loc" : [ -76.75483699999999, 37.792875 ], "pop" : 408, "state" : "VA" }
+{ "_id" : "22438", "city" : "CHAMPLAIN", "loc" : [ -76.971942, 38.021422 ], "pop" : 187, "state" : "VA" }
+{ "_id" : "22439", "city" : "CHANCE", "loc" : [ -77.021051, 38.084061 ], "pop" : 45, "state" : "VA" }
+{ "_id" : "22443", "city" : "OAK GROVE", "loc" : [ -76.98115799999999, 38.229076 ], "pop" : 6864, "state" : "VA" }
+{ "_id" : "22448", "city" : "DAHLGREN", "loc" : [ -77.042905, 38.337485 ], "pop" : 1509, "state" : "VA" }
+{ "_id" : "22454", "city" : "HOWERTONS", "loc" : [ -76.837022, 37.840429 ], "pop" : 1795, "state" : "VA" }
+{ "_id" : "22460", "city" : "FARNHAM", "loc" : [ -76.605011, 37.873972 ], "pop" : 1356, "state" : "VA" }
+{ "_id" : "22469", "city" : "HAGUE", "loc" : [ -76.661574, 38.057289 ], "pop" : 2243, "state" : "VA" }
+{ "_id" : "22473", "city" : "HEATHSVILLE", "loc" : [ -76.41783, 37.907187 ], "pop" : 2670, "state" : "VA" }
+{ "_id" : "22476", "city" : "HUSTLE", "loc" : [ -77.03642600000001, 38.022219 ], "pop" : 782, "state" : "VA" }
+{ "_id" : "22480", "city" : "IRVINGTON", "loc" : [ -76.416016, 37.664516 ], "pop" : 717, "state" : "VA" }
+{ "_id" : "22482", "city" : "KILMARNOCK", "loc" : [ -76.381986, 37.716222 ], "pop" : 1436, "state" : "VA" }
+{ "_id" : "22485", "city" : "KING GEORGE", "loc" : [ -77.126023, 38.281142 ], "pop" : 9088, "state" : "VA" }
+{ "_id" : "22488", "city" : "KINSALE", "loc" : [ -76.585525, 38.050472 ], "pop" : 1537, "state" : "VA" }
+{ "_id" : "22503", "city" : "LANCASTER", "loc" : [ -76.5102, 37.750091 ], "pop" : 4140, "state" : "VA" }
+{ "_id" : "22504", "city" : "LANEVIEW", "loc" : [ -76.711732, 37.768138 ], "pop" : 179, "state" : "VA" }
+{ "_id" : "22508", "city" : "LOCUST GROVE", "loc" : [ -77.77087400000001, 38.335202 ], "pop" : 4357, "state" : "VA" }
+{ "_id" : "22509", "city" : "LORETTO", "loc" : [ -76.966888, 38.062055 ], "pop" : 38, "state" : "VA" }
+{ "_id" : "22511", "city" : "LOTTSBURG", "loc" : [ -76.501763, 37.979228 ], "pop" : 1250, "state" : "VA" }
+{ "_id" : "22514", "city" : "MILFORD", "loc" : [ -77.31849800000001, 38.005834 ], "pop" : 3385, "state" : "VA" }
+{ "_id" : "22520", "city" : "MONTROSS", "loc" : [ -76.78280599999999, 38.110483 ], "pop" : 4836, "state" : "VA" }
+{ "_id" : "22534", "city" : "PARTLOW", "loc" : [ -77.658574, 38.064146 ], "pop" : 2057, "state" : "VA" }
+{ "_id" : "22535", "city" : "PORT ROYAL", "loc" : [ -77.183657, 38.162088 ], "pop" : 421, "state" : "VA" }
+{ "_id" : "22538", "city" : "RAPPAHANNOCK ACA", "loc" : [ -77.287437, 38.201817 ], "pop" : 637, "state" : "VA" }
+{ "_id" : "22539", "city" : "REEDVILLE", "loc" : [ -76.282864, 37.856964 ], "pop" : 2037, "state" : "VA" }
+{ "_id" : "22542", "city" : "RHOADESVILLE", "loc" : [ -77.923044, 38.286324 ], "pop" : 1072, "state" : "VA" }
+{ "_id" : "22546", "city" : "RUTHER GLEN", "loc" : [ -77.47135, 37.945059 ], "pop" : 7242, "state" : "VA" }
+{ "_id" : "22553", "city" : "SNELL", "loc" : [ -77.64868800000001, 38.19953 ], "pop" : 17034, "state" : "VA" }
+{ "_id" : "22554", "city" : "STAFFORD", "loc" : [ -77.430618, 38.458629 ], "pop" : 36544, "state" : "VA" }
+{ "_id" : "22559", "city" : "SUPPLY", "loc" : [ -77.109689, 38.082544 ], "pop" : 387, "state" : "VA" }
+{ "_id" : "22560", "city" : "TAPPAHANNOCK", "loc" : [ -76.91245499999999, 37.914551 ], "pop" : 4270, "state" : "VA" }
+{ "_id" : "22567", "city" : "UNIONVILLE", "loc" : [ -77.919299, 38.238302 ], "pop" : 1754, "state" : "VA" }
+{ "_id" : "22568", "city" : "MINE RUN", "loc" : [ -77.81949299999999, 38.266106 ], "pop" : 314, "state" : "VA" }
+{ "_id" : "22572", "city" : "NOMINI GROVE", "loc" : [ -76.73651700000001, 37.949992 ], "pop" : 5917, "state" : "VA" }
+{ "_id" : "22576", "city" : "WEEMS", "loc" : [ -76.43132300000001, 37.684678 ], "pop" : 2125, "state" : "VA" }
+{ "_id" : "22578", "city" : "WINDMILL POINT", "loc" : [ -76.36862600000001, 37.647458 ], "pop" : 2474, "state" : "VA" }
+{ "_id" : "22579", "city" : "WICOMICO CHURCH", "loc" : [ -76.356522, 37.779027 ], "pop" : 2285, "state" : "VA" }
+{ "_id" : "22580", "city" : "WOODFORD", "loc" : [ -77.439879, 38.084664 ], "pop" : 6047, "state" : "VA" }
+{ "_id" : "22601", "city" : "WINCHESTER", "loc" : [ -78.182697, 39.185803 ], "pop" : 45537, "state" : "VA" }
+{ "_id" : "22610", "city" : "BROWNTOWN", "loc" : [ -78.279111, 38.827272 ], "pop" : 1522, "state" : "VA" }
+{ "_id" : "22611", "city" : "BERRYVILLE", "loc" : [ -77.96875900000001, 39.153178 ], "pop" : 8339, "state" : "VA" }
+{ "_id" : "22620", "city" : "BOYCE", "loc" : [ -78.020302, 39.069797 ], "pop" : 2984, "state" : "VA" }
+{ "_id" : "22624", "city" : "CLEAR BROOK", "loc" : [ -78.098788, 39.265461 ], "pop" : 2656, "state" : "VA" }
+{ "_id" : "22625", "city" : "WHITACRE", "loc" : [ -78.299724, 39.3762 ], "pop" : 1229, "state" : "VA" }
+{ "_id" : "22627", "city" : "FLINT HILL", "loc" : [ -78.075558, 38.733653 ], "pop" : 276, "state" : "VA" }
+{ "_id" : "22630", "city" : "FRONT ROYAL", "loc" : [ -78.17961699999999, 38.926783 ], "pop" : 22951, "state" : "VA" }
+{ "_id" : "22637", "city" : "GORE", "loc" : [ -78.34168699999999, 39.288685 ], "pop" : 2000, "state" : "VA" }
+{ "_id" : "22639", "city" : "HUME", "loc" : [ -77.99489199999999, 38.827318 ], "pop" : 517, "state" : "VA" }
+{ "_id" : "22640", "city" : "HUNTLY", "loc" : [ -78.130104, 38.813333 ], "pop" : 782, "state" : "VA" }
+{ "_id" : "22641", "city" : "LEBANON CHURCH", "loc" : [ -78.359511, 39.056242 ], "pop" : 1075, "state" : "VA" }
+{ "_id" : "22642", "city" : "LINDEN", "loc" : [ -78.047847, 38.881181 ], "pop" : 352, "state" : "VA" }
+{ "_id" : "22643", "city" : "MARKHAM", "loc" : [ -77.994252, 38.930001 ], "pop" : 429, "state" : "VA" }
+{ "_id" : "22644", "city" : "MAURERTOWN", "loc" : [ -78.46581500000001, 38.944052 ], "pop" : 1483, "state" : "VA" }
+{ "_id" : "22645", "city" : "MIDDLETOWN", "loc" : [ -78.28145499999999, 39.036676 ], "pop" : 2239, "state" : "VA" }
+{ "_id" : "22649", "city" : "RELIANCE", "loc" : [ -78.249152, 39.000946 ], "pop" : 145, "state" : "VA" }
+{ "_id" : "22650", "city" : "RILEYVILLE", "loc" : [ -78.387326, 38.756374 ], "pop" : 997, "state" : "VA" }
+{ "_id" : "22652", "city" : "SAINT DAVIDS CHU", "loc" : [ -78.439989, 38.827683 ], "pop" : 1004, "state" : "VA" }
+{ "_id" : "22654", "city" : "STAR TANNERY", "loc" : [ -78.43430600000001, 39.090803 ], "pop" : 332, "state" : "VA" }
+{ "_id" : "22655", "city" : "STEPHENS CITY", "loc" : [ -78.19067699999999, 39.083415 ], "pop" : 10954, "state" : "VA" }
+{ "_id" : "22656", "city" : "STEPHENSON", "loc" : [ -78.094105, 39.197285 ], "pop" : 2721, "state" : "VA" }
+{ "_id" : "22657", "city" : "STRASBURG", "loc" : [ -78.33862000000001, 38.988417 ], "pop" : 5756, "state" : "VA" }
+{ "_id" : "22660", "city" : "TOMS BROOK", "loc" : [ -78.403757, 38.97016 ], "pop" : 2796, "state" : "VA" }
+{ "_id" : "22663", "city" : "WHITE POST", "loc" : [ -78.11046, 39.057956 ], "pop" : 778, "state" : "VA" }
+{ "_id" : "22664", "city" : "WOODSTOCK", "loc" : [ -78.521704, 38.887024 ], "pop" : 6899, "state" : "VA" }
+{ "_id" : "22701", "city" : "RACCOON FORD", "loc" : [ -78.00406, 38.48115 ], "pop" : 21359, "state" : "VA" }
+{ "_id" : "22709", "city" : "ARODA", "loc" : [ -78.236615, 38.325626 ], "pop" : 1509, "state" : "VA" }
+{ "_id" : "22712", "city" : "MORRISVILLE", "loc" : [ -77.800436, 38.569667 ], "pop" : 3863, "state" : "VA" }
+{ "_id" : "22713", "city" : "BOSTON", "loc" : [ -78.142285, 38.538241 ], "pop" : 557, "state" : "VA" }
+{ "_id" : "22714", "city" : "BRANDY STATION", "loc" : [ -77.903745, 38.511003 ], "pop" : 721, "state" : "VA" }
+{ "_id" : "22715", "city" : "BRIGHTWOOD", "loc" : [ -78.16980100000001, 38.411365 ], "pop" : 1048, "state" : "VA" }
+{ "_id" : "22716", "city" : "CASTLETON", "loc" : [ -78.120801, 38.603235 ], "pop" : 536, "state" : "VA" }
+{ "_id" : "22718", "city" : "ELKWOOD", "loc" : [ -77.817031, 38.465229 ], "pop" : 414, "state" : "VA" }
+{ "_id" : "22719", "city" : "ETLAN", "loc" : [ -78.26379300000001, 38.509458 ], "pop" : 167, "state" : "VA" }
+{ "_id" : "22720", "city" : "GOLDVEIN", "loc" : [ -77.639488, 38.488641 ], "pop" : 1154, "state" : "VA" }
+{ "_id" : "22722", "city" : "HAYWOOD", "loc" : [ -78.179759, 38.46861 ], "pop" : 139, "state" : "VA" }
+{ "_id" : "22724", "city" : "JEFFERSONTON", "loc" : [ -77.906943, 38.625578 ], "pop" : 1000, "state" : "VA" }
+{ "_id" : "22725", "city" : "LEON", "loc" : [ -78.154579, 38.45724 ], "pop" : 109, "state" : "VA" }
+{ "_id" : "22726", "city" : "LIGNUM", "loc" : [ -77.82995699999999, 38.395625 ], "pop" : 176, "state" : "VA" }
+{ "_id" : "22727", "city" : "AYLOR", "loc" : [ -78.296458, 38.384495 ], "pop" : 4344, "state" : "VA" }
+{ "_id" : "22728", "city" : "MIDLAND", "loc" : [ -77.712709, 38.567061 ], "pop" : 1847, "state" : "VA" }
+{ "_id" : "22729", "city" : "MITCHELLS", "loc" : [ -78.01054600000001, 38.374429 ], "pop" : 39, "state" : "VA" }
+{ "_id" : "22731", "city" : "PRATTS", "loc" : [ -78.272212, 38.349207 ], "pop" : 88, "state" : "VA" }
+{ "_id" : "22732", "city" : "RADIANT", "loc" : [ -78.179799, 38.322706 ], "pop" : 756, "state" : "VA" }
+{ "_id" : "22733", "city" : "RAPIDAN", "loc" : [ -78.047607, 38.339217 ], "pop" : 1216, "state" : "VA" }
+{ "_id" : "22734", "city" : "REMINGTON", "loc" : [ -77.761365, 38.535091 ], "pop" : 2377, "state" : "VA" }
+{ "_id" : "22735", "city" : "REVA", "loc" : [ -78.157195, 38.460446 ], "pop" : 2134, "state" : "VA" }
+{ "_id" : "22736", "city" : "RICHARDSVILLE", "loc" : [ -77.71951900000001, 38.392388 ], "pop" : 238, "state" : "VA" }
+{ "_id" : "22737", "city" : "RIXEYVILLE", "loc" : [ -78.028229, 38.585168 ], "pop" : 2540, "state" : "VA" }
+{ "_id" : "22738", "city" : "UNO", "loc" : [ -78.26535800000001, 38.274342 ], "pop" : 477, "state" : "VA" }
+{ "_id" : "22740", "city" : "SPERRYVILLE", "loc" : [ -78.246571, 38.620252 ], "pop" : 1553, "state" : "VA" }
+{ "_id" : "22741", "city" : "STEVENSBURG", "loc" : [ -77.88423, 38.444135 ], "pop" : 220, "state" : "VA" }
+{ "_id" : "22742", "city" : "SUMERDUCK", "loc" : [ -77.70435999999999, 38.467355 ], "pop" : 1146, "state" : "VA" }
+{ "_id" : "22743", "city" : "SYRIA", "loc" : [ -78.32293900000001, 38.497229 ], "pop" : 526, "state" : "VA" }
+{ "_id" : "22746", "city" : "VIEWTOWN", "loc" : [ -78.025769, 38.645704 ], "pop" : 172, "state" : "VA" }
+{ "_id" : "22747", "city" : "WASHINGTON", "loc" : [ -78.1566, 38.707838 ], "pop" : 1448, "state" : "VA" }
+{ "_id" : "22749", "city" : "WOODVILLE", "loc" : [ -78.173855, 38.648176 ], "pop" : 371, "state" : "VA" }
+{ "_id" : "22801", "city" : "HARRISONBURG", "loc" : [ -78.871438, 38.448864 ], "pop" : 42027, "state" : "VA" }
+{ "_id" : "22810", "city" : "BASYE", "loc" : [ -78.767363, 38.795806 ], "pop" : 43, "state" : "VA" }
+{ "_id" : "22811", "city" : "BERGTON", "loc" : [ -78.966752, 38.792509 ], "pop" : 341, "state" : "VA" }
+{ "_id" : "22812", "city" : "BRIDGEWATER", "loc" : [ -78.993684, 38.385866 ], "pop" : 7160, "state" : "VA" }
+{ "_id" : "22815", "city" : "BROADWAY", "loc" : [ -78.787494, 38.608336 ], "pop" : 7106, "state" : "VA" }
+{ "_id" : "22820", "city" : "CRIDERS", "loc" : [ -78.99735699999999, 38.749656 ], "pop" : 445, "state" : "VA" }
+{ "_id" : "22821", "city" : "MONTEZUMA", "loc" : [ -78.993731, 38.433864 ], "pop" : 4777, "state" : "VA" }
+{ "_id" : "22824", "city" : "EDINBURG", "loc" : [ -78.60033, 38.843206 ], "pop" : 5079, "state" : "VA" }
+{ "_id" : "22827", "city" : "ELKTON", "loc" : [ -78.632143, 38.40252 ], "pop" : 10331, "state" : "VA" }
+{ "_id" : "22830", "city" : "FULKS RUN", "loc" : [ -78.935799, 38.633871 ], "pop" : 1255, "state" : "VA" }
+{ "_id" : "22831", "city" : "HINTON", "loc" : [ -79.01008400000001, 38.483378 ], "pop" : 798, "state" : "VA" }
+{ "_id" : "22832", "city" : "KEEZLETOWN", "loc" : [ -78.77699800000001, 38.439588 ], "pop" : 1204, "state" : "VA" }
+{ "_id" : "22834", "city" : "LINVILLE", "loc" : [ -78.896102, 38.555733 ], "pop" : 1866, "state" : "VA" }
+{ "_id" : "22835", "city" : "LURAY", "loc" : [ -78.459559, 38.654839 ], "pop" : 10559, "state" : "VA" }
+{ "_id" : "22840", "city" : "MC GAHEYSVILLE", "loc" : [ -78.741128, 38.371228 ], "pop" : 2100, "state" : "VA" }
+{ "_id" : "22841", "city" : "MOUNT CRAWFORD", "loc" : [ -78.895679, 38.345656 ], "pop" : 2070, "state" : "VA" }
+{ "_id" : "22842", "city" : "CONICVILLE", "loc" : [ -78.676655, 38.768819 ], "pop" : 4601, "state" : "VA" }
+{ "_id" : "22843", "city" : "MOUNT SOLON", "loc" : [ -79.10283200000001, 38.332755 ], "pop" : 1995, "state" : "VA" }
+{ "_id" : "22844", "city" : "NEW MARKET", "loc" : [ -78.67143299999999, 38.660555 ], "pop" : 3502, "state" : "VA" }
+{ "_id" : "22845", "city" : "ORKNEY SPRINGS", "loc" : [ -78.811106, 38.793708 ], "pop" : 266, "state" : "VA" }
+{ "_id" : "22846", "city" : "MONTEVIDEO", "loc" : [ -78.79790300000001, 38.369729 ], "pop" : 704, "state" : "VA" }
+{ "_id" : "22847", "city" : "SHENANDOAH CAVER", "loc" : [ -78.698866, 38.714443 ], "pop" : 352, "state" : "VA" }
+{ "_id" : "22849", "city" : "SHENANDOAH", "loc" : [ -78.608975, 38.501034 ], "pop" : 5174, "state" : "VA" }
+{ "_id" : "22851", "city" : "STANLEY", "loc" : [ -78.509263, 38.566036 ], "pop" : 4604, "state" : "VA" }
+{ "_id" : "22853", "city" : "TIMBERVILLE", "loc" : [ -78.771702, 38.647606 ], "pop" : 3494, "state" : "VA" }
+{ "_id" : "22901", "city" : "CHARLOTTESVILLE", "loc" : [ -78.490869, 38.054752 ], "pop" : 62708, "state" : "VA" }
+{ "_id" : "22903", "city" : "UNIVERSITY", "loc" : [ -78.505758, 38.032728 ], "pop" : 25301, "state" : "VA" }
+{ "_id" : "22920", "city" : "AFTON", "loc" : [ -78.84104600000001, 37.962624 ], "pop" : 2783, "state" : "VA" }
+{ "_id" : "22922", "city" : "TYE RIVER", "loc" : [ -78.91847300000001, 37.687713 ], "pop" : 1439, "state" : "VA" }
+{ "_id" : "22923", "city" : "BURNLEYS", "loc" : [ -78.31271599999999, 38.199648 ], "pop" : 1389, "state" : "VA" }
+{ "_id" : "22929", "city" : "COBHAM", "loc" : [ -78.37849, 38.037835 ], "pop" : 45, "state" : "VA" }
+{ "_id" : "22931", "city" : "COVESVILLE", "loc" : [ -78.71274099999999, 37.907974 ], "pop" : 304, "state" : "VA" }
+{ "_id" : "22932", "city" : "YANCEY MILLS", "loc" : [ -78.70440499999999, 38.081288 ], "pop" : 4292, "state" : "VA" }
+{ "_id" : "22935", "city" : "BOONESVILLE", "loc" : [ -78.55461200000001, 38.253276 ], "pop" : 566, "state" : "VA" }
+{ "_id" : "22936", "city" : "EARLYSVILLE", "loc" : [ -78.491945, 38.157761 ], "pop" : 4294, "state" : "VA" }
+{ "_id" : "22937", "city" : "ESMONT", "loc" : [ -78.610646, 37.812543 ], "pop" : 1157, "state" : "VA" }
+{ "_id" : "22938", "city" : "FABER", "loc" : [ -78.756495, 37.847545 ], "pop" : 958, "state" : "VA" }
+{ "_id" : "22939", "city" : "WOODROW WILSON", "loc" : [ -78.969579, 38.097361 ], "pop" : 1374, "state" : "VA" }
+{ "_id" : "22940", "city" : "MISSION HOME", "loc" : [ -78.595906, 38.206217 ], "pop" : 1023, "state" : "VA" }
+{ "_id" : "22942", "city" : "CASHS CORNER", "loc" : [ -78.195195, 38.107261 ], "pop" : 5852, "state" : "VA" }
+{ "_id" : "22943", "city" : "GREENWOOD", "loc" : [ -78.783282, 38.041545 ], "pop" : 516, "state" : "VA" }
+{ "_id" : "22946", "city" : "KEENE", "loc" : [ -78.561386, 37.931273 ], "pop" : 26, "state" : "VA" }
+{ "_id" : "22947", "city" : "BOYD TAVERN", "loc" : [ -78.340429, 38.001265 ], "pop" : 2081, "state" : "VA" }
+{ "_id" : "22948", "city" : "LOCUST DALE", "loc" : [ -78.10157599999999, 38.334043 ], "pop" : 155, "state" : "VA" }
+{ "_id" : "22949", "city" : "LOVINGSTON", "loc" : [ -78.868433, 37.792405 ], "pop" : 1459, "state" : "VA" }
+{ "_id" : "22951", "city" : "LOWESVILLE", "loc" : [ -79.08334600000001, 37.749797 ], "pop" : 175, "state" : "VA" }
+{ "_id" : "22952", "city" : "SHERANDO", "loc" : [ -78.95150599999999, 37.997903 ], "pop" : 2267, "state" : "VA" }
+{ "_id" : "22958", "city" : "WINTERGREEN", "loc" : [ -78.89397200000001, 37.860398 ], "pop" : 53, "state" : "VA" }
+{ "_id" : "22959", "city" : "ALBERENE", "loc" : [ -78.695414, 37.961992 ], "pop" : 3134, "state" : "VA" }
+{ "_id" : "22960", "city" : "MONTFORD", "loc" : [ -78.091224, 38.233937 ], "pop" : 8781, "state" : "VA" }
+{ "_id" : "22963", "city" : "BYBEE", "loc" : [ -78.297983, 37.881807 ], "pop" : 5689, "state" : "VA" }
+{ "_id" : "22964", "city" : "PINEY RIVER", "loc" : [ -79.020571, 37.715785 ], "pop" : 257, "state" : "VA" }
+{ "_id" : "22967", "city" : "ROSELAND", "loc" : [ -78.97117299999999, 37.807697 ], "pop" : 2333, "state" : "VA" }
+{ "_id" : "22968", "city" : "ADVANCE MILLS", "loc" : [ -78.39103299999999, 38.233871 ], "pop" : 5764, "state" : "VA" }
+{ "_id" : "22969", "city" : "SCHUYLER", "loc" : [ -78.692475, 37.797584 ], "pop" : 1128, "state" : "VA" }
+{ "_id" : "22971", "city" : "ROCKFISH", "loc" : [ -78.824608, 37.747974 ], "pop" : 1100, "state" : "VA" }
+{ "_id" : "22972", "city" : "SOMERSET", "loc" : [ -78.25042000000001, 38.204657 ], "pop" : 720, "state" : "VA" }
+{ "_id" : "22973", "city" : "GEER", "loc" : [ -78.470755, 38.302556 ], "pop" : 4114, "state" : "VA" }
+{ "_id" : "22974", "city" : "TROY", "loc" : [ -78.253494, 37.9636 ], "pop" : 1868, "state" : "VA" }
+{ "_id" : "22980", "city" : "WAYNESBORO", "loc" : [ -78.90346099999999, 38.077412 ], "pop" : 26450, "state" : "VA" }
+{ "_id" : "23002", "city" : "AMELIA COURT HOU", "loc" : [ -77.95517700000001, 37.35017 ], "pop" : 6923, "state" : "VA" }
+{ "_id" : "23004", "city" : "ARVONIA", "loc" : [ -78.38888, 37.671355 ], "pop" : 1114, "state" : "VA" }
+{ "_id" : "23005", "city" : "ASHLAND", "loc" : [ -77.478373, 37.73948 ], "pop" : 14800, "state" : "VA" }
+{ "_id" : "23009", "city" : "AYLETT", "loc" : [ -77.188473, 37.822113 ], "pop" : 1374, "state" : "VA" }
+{ "_id" : "23011", "city" : "BARHAMSVILLE", "loc" : [ -76.832097, 37.461662 ], "pop" : 698, "state" : "VA" }
+{ "_id" : "23015", "city" : "BEAVERDAM", "loc" : [ -77.63082900000001, 37.903767 ], "pop" : 2328, "state" : "VA" }
+{ "_id" : "23016", "city" : "BEAVERLETT", "loc" : [ -76.322425, 37.41587 ], "pop" : 262, "state" : "VA" }
+{ "_id" : "23021", "city" : "BOHANNON", "loc" : [ -76.36136, 37.390457 ], "pop" : 143, "state" : "VA" }
+{ "_id" : "23022", "city" : "BREMO BLUFF", "loc" : [ -78.26715799999999, 37.745256 ], "pop" : 1058, "state" : "VA" }
+{ "_id" : "23023", "city" : "BRUINGTON", "loc" : [ -76.94019900000001, 37.780112 ], "pop" : 172, "state" : "VA" }
+{ "_id" : "23024", "city" : "BUMPASS", "loc" : [ -77.79661400000001, 37.898381 ], "pop" : 4399, "state" : "VA" }
+{ "_id" : "23025", "city" : "MILES", "loc" : [ -76.393959, 37.427339 ], "pop" : 39, "state" : "VA" }
+{ "_id" : "23027", "city" : "TAMWORTH", "loc" : [ -78.128699, 37.641314 ], "pop" : 1143, "state" : "VA" }
+{ "_id" : "23029", "city" : "CAUTHORNVILLE", "loc" : [ -77.039625, 37.858957 ], "pop" : 380, "state" : "VA" }
+{ "_id" : "23030", "city" : "CHARLES CITY", "loc" : [ -77.108183, 37.366271 ], "pop" : 4216, "state" : "VA" }
+{ "_id" : "23032", "city" : "CHURCH VIEW", "loc" : [ -76.66287, 37.674956 ], "pop" : 493, "state" : "VA" }
+{ "_id" : "23037", "city" : "COLOGNE", "loc" : [ -76.683356, 37.555866 ], "pop" : 95, "state" : "VA" }
+{ "_id" : "23038", "city" : "COLUMBIA", "loc" : [ -78.17940299999999, 37.714707 ], "pop" : 641, "state" : "VA" }
+{ "_id" : "23039", "city" : "CROZIER", "loc" : [ -77.793958, 37.671764 ], "pop" : 937, "state" : "VA" }
+{ "_id" : "23040", "city" : "CUMBERLAND", "loc" : [ -78.258149, 37.501861 ], "pop" : 3429, "state" : "VA" }
+{ "_id" : "23043", "city" : "DELTAVILLE", "loc" : [ -76.34678099999999, 37.554852 ], "pop" : 1565, "state" : "VA" }
+{ "_id" : "23045", "city" : "DIGGS", "loc" : [ -76.287172, 37.436273 ], "pop" : 491, "state" : "VA" }
+{ "_id" : "23047", "city" : "DOSWELL", "loc" : [ -77.51252100000001, 37.841682 ], "pop" : 2111, "state" : "VA" }
+{ "_id" : "23050", "city" : "DUTTON", "loc" : [ -76.435782, 37.486897 ], "pop" : 416, "state" : "VA" }
+{ "_id" : "23055", "city" : "FORK UNION", "loc" : [ -78.23549800000001, 37.771526 ], "pop" : 620, "state" : "VA" }
+{ "_id" : "23060", "city" : "GLEN ALLEN", "loc" : [ -77.53401599999999, 37.662848 ], "pop" : 19953, "state" : "VA" }
+{ "_id" : "23061", "city" : "PINERO", "loc" : [ -76.55331200000001, 37.41922 ], "pop" : 14924, "state" : "VA" }
+{ "_id" : "23062", "city" : "GLOUCESTER POINT", "loc" : [ -76.49585999999999, 37.258534 ], "pop" : 2558, "state" : "VA" }
+{ "_id" : "23063", "city" : "GOOCHLAND", "loc" : [ -78.011216, 37.768789 ], "pop" : 4772, "state" : "VA" }
+{ "_id" : "23065", "city" : "GUM SPRING", "loc" : [ -77.907049, 37.818374 ], "pop" : 480, "state" : "VA" }
+{ "_id" : "23066", "city" : "GWYNN", "loc" : [ -76.29042, 37.500594 ], "pop" : 681, "state" : "VA" }
+{ "_id" : "23069", "city" : "HANOVER", "loc" : [ -77.321572, 37.770116 ], "pop" : 3796, "state" : "VA" }
+{ "_id" : "23070", "city" : "HARDYVILLE", "loc" : [ -76.418937, 37.547821 ], "pop" : 546, "state" : "VA" }
+{ "_id" : "23071", "city" : "HARTFIELD", "loc" : [ -76.476949, 37.559437 ], "pop" : 797, "state" : "VA" }
+{ "_id" : "23072", "city" : "HAYES", "loc" : [ -76.49045700000001, 37.291577 ], "pop" : 11051, "state" : "VA" }
+{ "_id" : "23075", "city" : "HIGHLAND SPRINGS", "loc" : [ -77.32261, 37.543723 ], "pop" : 9373, "state" : "VA" }
+{ "_id" : "23079", "city" : "JAMAICA", "loc" : [ -76.688962, 37.729997 ], "pop" : 383, "state" : "VA" }
+{ "_id" : "23080", "city" : "JAMES STORE", "loc" : [ -76.464972, 37.480594 ], "pop" : 795, "state" : "VA" }
+{ "_id" : "23083", "city" : "JETERSVILLE", "loc" : [ -78.104011, 37.31757 ], "pop" : 1396, "state" : "VA" }
+{ "_id" : "23084", "city" : "KENTS STORE", "loc" : [ -78.12077600000001, 37.89425 ], "pop" : 882, "state" : "VA" }
+{ "_id" : "23085", "city" : "KING AND QUEEN C", "loc" : [ -76.86305900000001, 37.717644 ], "pop" : 548, "state" : "VA" }
+{ "_id" : "23086", "city" : "KING WILLIAM", "loc" : [ -77.09983699999999, 37.720194 ], "pop" : 3887, "state" : "VA" }
+{ "_id" : "23089", "city" : "LANEXA", "loc" : [ -76.90268399999999, 37.419391 ], "pop" : 3609, "state" : "VA" }
+{ "_id" : "23091", "city" : "LITTLE PLYMOUTH", "loc" : [ -76.825456, 37.664218 ], "pop" : 103, "state" : "VA" }
+{ "_id" : "23092", "city" : "LOCUST HILL", "loc" : [ -76.501857, 37.598328 ], "pop" : 375, "state" : "VA" }
+{ "_id" : "23093", "city" : "LOUISA", "loc" : [ -78.034666, 38.01317 ], "pop" : 7503, "state" : "VA" }
+{ "_id" : "23102", "city" : "DABNEYS", "loc" : [ -77.871032, 37.703193 ], "pop" : 2927, "state" : "VA" }
+{ "_id" : "23103", "city" : "MANAKIN SABOT", "loc" : [ -77.70769900000001, 37.638036 ], "pop" : 5177, "state" : "VA" }
+{ "_id" : "23106", "city" : "MANQUIN", "loc" : [ -77.186016, 37.718441 ], "pop" : 628, "state" : "VA" }
+{ "_id" : "23108", "city" : "MASCOT", "loc" : [ -76.73832400000001, 37.60683 ], "pop" : 104, "state" : "VA" }
+{ "_id" : "23109", "city" : "MATHEWS", "loc" : [ -76.354416, 37.438349 ], "pop" : 760, "state" : "VA" }
+{ "_id" : "23110", "city" : "SHANGHAI", "loc" : [ -76.78398, 37.641698 ], "pop" : 331, "state" : "VA" }
+{ "_id" : "23111", "city" : "MECHANICSVILLE", "loc" : [ -77.33946400000001, 37.628146 ], "pop" : 35675, "state" : "VA" }
+{ "_id" : "23112", "city" : "MIDLOTHIAN", "loc" : [ -77.65445800000001, 37.431027 ], "pop" : 24114, "state" : "VA" }
+{ "_id" : "23113", "city" : "MIDLOTHIAN", "loc" : [ -77.642864, 37.510893 ], "pop" : 21858, "state" : "VA" }
+{ "_id" : "23117", "city" : "MINERAL", "loc" : [ -77.878069, 37.998609 ], "pop" : 5080, "state" : "VA" }
+{ "_id" : "23118", "city" : "MOBJACK", "loc" : [ -76.355244, 37.377579 ], "pop" : 204, "state" : "VA" }
+{ "_id" : "23119", "city" : "MOON", "loc" : [ -76.306472, 37.449276 ], "pop" : 629, "state" : "VA" }
+{ "_id" : "23120", "city" : "MOSELEY", "loc" : [ -77.758458, 37.426026 ], "pop" : 1852, "state" : "VA" }
+{ "_id" : "23123", "city" : "NEW CANTON", "loc" : [ -78.31123100000001, 37.664499 ], "pop" : 1546, "state" : "VA" }
+{ "_id" : "23124", "city" : "NEW KENT", "loc" : [ -77.074242, 37.553013 ], "pop" : 1376, "state" : "VA" }
+{ "_id" : "23125", "city" : "NEW POINT", "loc" : [ -76.28346500000001, 37.349291 ], "pop" : 153, "state" : "VA" }
+{ "_id" : "23126", "city" : "NEWTOWN", "loc" : [ -77.11382500000001, 37.878236 ], "pop" : 926, "state" : "VA" }
+{ "_id" : "23128", "city" : "NORTH", "loc" : [ -76.370661, 37.477066 ], "pop" : 1621, "state" : "VA" }
+{ "_id" : "23129", "city" : "OILVILLE", "loc" : [ -77.769955, 37.708879 ], "pop" : 198, "state" : "VA" }
+{ "_id" : "23130", "city" : "ONEMO", "loc" : [ -76.294056, 37.398517 ], "pop" : 582, "state" : "VA" }
+{ "_id" : "23138", "city" : "BAVON", "loc" : [ -76.304463, 37.374252 ], "pop" : 475, "state" : "VA" }
+{ "_id" : "23139", "city" : "POWHATAN", "loc" : [ -77.879761, 37.556442 ], "pop" : 14488, "state" : "VA" }
+{ "_id" : "23140", "city" : "PROVIDENCE FORGE", "loc" : [ -77.071117, 37.425907 ], "pop" : 3211, "state" : "VA" }
+{ "_id" : "23141", "city" : "QUINTON", "loc" : [ -77.148607, 37.518466 ], "pop" : 4589, "state" : "VA" }
+{ "_id" : "23146", "city" : "ROCKVILLE", "loc" : [ -77.699994, 37.733729 ], "pop" : 1872, "state" : "VA" }
+{ "_id" : "23148", "city" : "INDIAN NECK", "loc" : [ -77.08420599999999, 37.905052 ], "pop" : 191, "state" : "VA" }
+{ "_id" : "23149", "city" : "SALUDA", "loc" : [ -76.592082, 37.594944 ], "pop" : 3215, "state" : "VA" }
+{ "_id" : "23150", "city" : "SANDSTON", "loc" : [ -77.27578, 37.515658 ], "pop" : 9402, "state" : "VA" }
+{ "_id" : "23153", "city" : "SANDY HOOK", "loc" : [ -77.90455300000001, 37.751892 ], "pop" : 152, "state" : "VA" }
+{ "_id" : "23156", "city" : "PLAIN VIEW", "loc" : [ -76.726901, 37.569811 ], "pop" : 696, "state" : "VA" }
+{ "_id" : "23161", "city" : "STEVENSVILLE", "loc" : [ -76.935228, 37.714577 ], "pop" : 59, "state" : "VA" }
+{ "_id" : "23163", "city" : "SHADOW", "loc" : [ -76.318617, 37.361945 ], "pop" : 309, "state" : "VA" }
+{ "_id" : "23168", "city" : "TOANO", "loc" : [ -76.82526300000001, 37.39013 ], "pop" : 2784, "state" : "VA" }
+{ "_id" : "23169", "city" : "SYRINGA", "loc" : [ -76.454876, 37.597824 ], "pop" : 706, "state" : "VA" }
+{ "_id" : "23175", "city" : "REMLIK", "loc" : [ -76.612611, 37.655003 ], "pop" : 698, "state" : "VA" }
+{ "_id" : "23176", "city" : "WAKE", "loc" : [ -76.432327, 37.568077 ], "pop" : 368, "state" : "VA" }
+{ "_id" : "23177", "city" : "WALKERTON", "loc" : [ -77.018475, 37.755437 ], "pop" : 1152, "state" : "VA" }
+{ "_id" : "23179", "city" : "WARNER", "loc" : [ -76.64616700000001, 37.651127 ], "pop" : 37, "state" : "VA" }
+{ "_id" : "23180", "city" : "WATER VIEW", "loc" : [ -76.62268, 37.710486 ], "pop" : 273, "state" : "VA" }
+{ "_id" : "23181", "city" : "WEST POINT", "loc" : [ -76.82373, 37.555604 ], "pop" : 4365, "state" : "VA" }
+{ "_id" : "23185", "city" : "MERRIMAC", "loc" : [ -76.701686, 37.262698 ], "pop" : 34777, "state" : "VA" }
+{ "_id" : "23188", "city" : "WILLIAMSBURG", "loc" : [ -76.763424, 37.317768 ], "pop" : 14957, "state" : "VA" }
+{ "_id" : "23192", "city" : "MONTPELIER", "loc" : [ -77.692441, 37.817729 ], "pop" : 4472, "state" : "VA" }
+{ "_id" : "23219", "city" : "RICHMOND", "loc" : [ -77.437798, 37.546265 ], "pop" : 2780, "state" : "VA" }
+{ "_id" : "23220", "city" : "RICHMOND", "loc" : [ -77.458798, 37.549808 ], "pop" : 29776, "state" : "VA" }
+{ "_id" : "23221", "city" : "RICHMOND", "loc" : [ -77.4845, 37.558301 ], "pop" : 14452, "state" : "VA" }
+{ "_id" : "23222", "city" : "RICHMOND", "loc" : [ -77.426725, 37.574802 ], "pop" : 30214, "state" : "VA" }
+{ "_id" : "23223", "city" : "RICHMOND", "loc" : [ -77.394772, 37.547721 ], "pop" : 42379, "state" : "VA" }
+{ "_id" : "23224", "city" : "RICHMOND", "loc" : [ -77.471014, 37.495512 ], "pop" : 32681, "state" : "VA" }
+{ "_id" : "23225", "city" : "RICHMOND", "loc" : [ -77.50470900000001, 37.515842 ], "pop" : 37289, "state" : "VA" }
+{ "_id" : "23226", "city" : "RICHMOND", "loc" : [ -77.519657, 37.582473 ], "pop" : 18085, "state" : "VA" }
+{ "_id" : "23227", "city" : "BELLEVUE", "loc" : [ -77.446309, 37.604181 ], "pop" : 21661, "state" : "VA" }
+{ "_id" : "23228", "city" : "LAKESIDE", "loc" : [ -77.493308, 37.623503 ], "pop" : 30611, "state" : "VA" }
+{ "_id" : "23229", "city" : "REGENCY", "loc" : [ -77.566202, 37.596351 ], "pop" : 32028, "state" : "VA" }
+{ "_id" : "23230", "city" : "WEST END", "loc" : [ -77.49682799999999, 37.588376 ], "pop" : 6447, "state" : "VA" }
+{ "_id" : "23231", "city" : "RICHMOND", "loc" : [ -77.368002, 37.491529 ], "pop" : 23773, "state" : "VA" }
+{ "_id" : "23233", "city" : "RIDGE", "loc" : [ -77.61493299999999, 37.619354 ], "pop" : 32811, "state" : "VA" }
+{ "_id" : "23234", "city" : "AMPTHILL", "loc" : [ -77.469798, 37.453158 ], "pop" : 36331, "state" : "VA" }
+{ "_id" : "23235", "city" : "BON AIR", "loc" : [ -77.56510299999999, 37.512034 ], "pop" : 30860, "state" : "VA" }
+{ "_id" : "23236", "city" : "RICHMOND", "loc" : [ -77.585413, 37.478165 ], "pop" : 24305, "state" : "VA" }
+{ "_id" : "23237", "city" : "RICHMOND", "loc" : [ -77.461471, 37.401145 ], "pop" : 19154, "state" : "VA" }
+{ "_id" : "23294", "city" : "RICHMOND", "loc" : [ -77.545125, 37.632923 ], "pop" : 14713, "state" : "VA" }
+{ "_id" : "23301", "city" : "ACCOMAC", "loc" : [ -75.680272, 37.71588 ], "pop" : 2562, "state" : "VA" }
+{ "_id" : "23302", "city" : "ASSAWOMAN", "loc" : [ -75.52966000000001, 37.86629 ], "pop" : 82, "state" : "VA" }
+{ "_id" : "23306", "city" : "BELLE HAVEN", "loc" : [ -75.869443, 37.56448 ], "pop" : 344, "state" : "VA" }
+{ "_id" : "23307", "city" : "BIRDSNEST", "loc" : [ -75.904347, 37.432077 ], "pop" : 1057, "state" : "VA" }
+{ "_id" : "23308", "city" : "BLOXOM", "loc" : [ -75.615568, 37.827264 ], "pop" : 1581, "state" : "VA" }
+{ "_id" : "23310", "city" : "CAPE CHARLES", "loc" : [ -75.972129, 37.279874 ], "pop" : 6259, "state" : "VA" }
+{ "_id" : "23314", "city" : "CARROLLTON", "loc" : [ -76.542963, 36.954994 ], "pop" : 3990, "state" : "VA" }
+{ "_id" : "23315", "city" : "CARRSVILLE", "loc" : [ -76.83647999999999, 36.74544 ], "pop" : 1273, "state" : "VA" }
+{ "_id" : "23320", "city" : "CHESAPEAKE", "loc" : [ -76.23842999999999, 36.735246 ], "pop" : 55836, "state" : "VA" }
+{ "_id" : "23321", "city" : "BOWERS HILL", "loc" : [ -76.411012, 36.827964 ], "pop" : 23561, "state" : "VA" }
+{ "_id" : "23322", "city" : "FENTRESS", "loc" : [ -76.213064, 36.634008 ], "pop" : 10023, "state" : "VA" }
+{ "_id" : "23323", "city" : "CHESAPEAKE", "loc" : [ -76.339743, 36.763424 ], "pop" : 24412, "state" : "VA" }
+{ "_id" : "23324", "city" : "CHESAPEAKE", "loc" : [ -76.26655700000001, 36.805568 ], "pop" : 21531, "state" : "VA" }
+{ "_id" : "23325", "city" : "CHESAPEAKE", "loc" : [ -76.240555, 36.813963 ], "pop" : 16543, "state" : "VA" }
+{ "_id" : "23336", "city" : "CHINCOTEAGUE", "loc" : [ -75.371369, 37.927682 ], "pop" : 3581, "state" : "VA" }
+{ "_id" : "23337", "city" : "WALLOPS ISLAND", "loc" : [ -75.506503, 37.827338 ], "pop" : 0, "state" : "VA" }
+{ "_id" : "23350", "city" : "EXMORE", "loc" : [ -75.85262400000001, 37.511689 ], "pop" : 4678, "state" : "VA" }
+{ "_id" : "23354", "city" : "FRANKTOWN", "loc" : [ -75.888971, 37.462009 ], "pop" : 474, "state" : "VA" }
+{ "_id" : "23356", "city" : "GREENBACKVILLE", "loc" : [ -75.40289900000001, 38.006404 ], "pop" : 400, "state" : "VA" }
+{ "_id" : "23357", "city" : "GREENBUSH", "loc" : [ -75.6664, 37.768121 ], "pop" : 821, "state" : "VA" }
+{ "_id" : "23359", "city" : "HALLWOOD", "loc" : [ -75.561334, 37.853644 ], "pop" : 322, "state" : "VA" }
+{ "_id" : "23395", "city" : "HORNTOWN", "loc" : [ -75.471608, 37.969916 ], "pop" : 132, "state" : "VA" }
+{ "_id" : "23396", "city" : "HORSEY", "loc" : [ -75.56236, 37.933232 ], "pop" : 200, "state" : "VA" }
+{ "_id" : "23399", "city" : "JENKINS BRIDGE", "loc" : [ -75.63194300000001, 37.919219 ], "pop" : 301, "state" : "VA" }
+{ "_id" : "23404", "city" : "LOCUSTVILLE", "loc" : [ -75.673508, 37.6534 ], "pop" : 92, "state" : "VA" }
+{ "_id" : "23405", "city" : "MACHIPONGO", "loc" : [ -75.908241, 37.401429 ], "pop" : 593, "state" : "VA" }
+{ "_id" : "23407", "city" : "MAPPSVILLE", "loc" : [ -75.569886, 37.835419 ], "pop" : 835, "state" : "VA" }
+{ "_id" : "23409", "city" : "MEARS", "loc" : [ -75.635443, 37.869189 ], "pop" : 110, "state" : "VA" }
+{ "_id" : "23410", "city" : "MELFA", "loc" : [ -75.745355, 37.6407 ], "pop" : 2987, "state" : "VA" }
+{ "_id" : "23415", "city" : "NEW CHURCH", "loc" : [ -75.511188, 37.952527 ], "pop" : 2915, "state" : "VA" }
+{ "_id" : "23416", "city" : "OAK HALL", "loc" : [ -75.606483, 37.953686 ], "pop" : 130, "state" : "VA" }
+{ "_id" : "23417", "city" : "ONANCOCK", "loc" : [ -75.752798, 37.710237 ], "pop" : 3914, "state" : "VA" }
+{ "_id" : "23418", "city" : "ONLEY", "loc" : [ -75.6992, 37.670422 ], "pop" : 97, "state" : "VA" }
+{ "_id" : "23420", "city" : "PAINTER", "loc" : [ -75.806612, 37.582821 ], "pop" : 3782, "state" : "VA" }
+{ "_id" : "23421", "city" : "PARKSLEY", "loc" : [ -75.638634, 37.774404 ], "pop" : 3466, "state" : "VA" }
+{ "_id" : "23426", "city" : "SANFORD", "loc" : [ -75.69570400000001, 37.92433 ], "pop" : 679, "state" : "VA" }
+{ "_id" : "23430", "city" : "SMITHFIELD", "loc" : [ -76.63682, 36.981057 ], "pop" : 11389, "state" : "VA" }
+{ "_id" : "23432", "city" : "SUFFOLK", "loc" : [ -76.559811, 36.866823 ], "pop" : 1396, "state" : "VA" }
+{ "_id" : "23433", "city" : "SUFFOLK", "loc" : [ -76.49285999999999, 36.909027 ], "pop" : 1219, "state" : "VA" }
+{ "_id" : "23434", "city" : "SUFFOLK", "loc" : [ -76.593147, 36.730433 ], "pop" : 33717, "state" : "VA" }
+{ "_id" : "23435", "city" : "SUFFOLK", "loc" : [ -76.466397, 36.854427 ], "pop" : 8556, "state" : "VA" }
+{ "_id" : "23436", "city" : "SUFFOLK", "loc" : [ -76.514157, 36.892625 ], "pop" : 766, "state" : "VA" }
+{ "_id" : "23437", "city" : "SUFFOLK", "loc" : [ -76.79204300000001, 36.652611 ], "pop" : 4414, "state" : "VA" }
+{ "_id" : "23438", "city" : "SUFFOLK", "loc" : [ -76.68709699999999, 36.591311 ], "pop" : 2073, "state" : "VA" }
+{ "_id" : "23440", "city" : "TANGIER", "loc" : [ -75.993003, 37.824485 ], "pop" : 700, "state" : "VA" }
+{ "_id" : "23442", "city" : "TEMPERANCEVILLE", "loc" : [ -75.55283, 37.895421 ], "pop" : 1670, "state" : "VA" }
+{ "_id" : "23451", "city" : "VIRGINIA BEACH", "loc" : [ -76.00192800000001, 36.858451 ], "pop" : 37212, "state" : "VA" }
+{ "_id" : "23452", "city" : "VIRGINIA BEACH", "loc" : [ -76.096142, 36.83481 ], "pop" : 61895, "state" : "VA" }
+{ "_id" : "23454", "city" : "VIRGINIA BEACH", "loc" : [ -76.023723, 36.828187 ], "pop" : 59937, "state" : "VA" }
+{ "_id" : "23455", "city" : "VIRGINIA BEACH", "loc" : [ -76.144552, 36.888121 ], "pop" : 43055, "state" : "VA" }
+{ "_id" : "23456", "city" : "VIRGINIA BEACH", "loc" : [ -76.089162, 36.779851 ], "pop" : 55909, "state" : "VA" }
+{ "_id" : "23457", "city" : "BLACKWATER BRIDG", "loc" : [ -76.03781600000001, 36.624793 ], "pop" : 3448, "state" : "VA" }
+{ "_id" : "23459", "city" : "VIRGINIA BEACH", "loc" : [ -76.017122, 36.9216 ], "pop" : 1164, "state" : "VA" }
+{ "_id" : "23462", "city" : "VIRGINIA BEACH", "loc" : [ -76.15218400000001, 36.839193 ], "pop" : 58632, "state" : "VA" }
+{ "_id" : "23464", "city" : "VIRGINIA BEACH", "loc" : [ -76.175909, 36.797772 ], "pop" : 67276, "state" : "VA" }
+{ "_id" : "23481", "city" : "WALTERS", "loc" : [ -76.87015599999999, 36.708974 ], "pop" : 698, "state" : "VA" }
+{ "_id" : "23487", "city" : "WINDSOR", "loc" : [ -76.732372, 36.836881 ], "pop" : 4773, "state" : "VA" }
+{ "_id" : "23502", "city" : "NORFOLK", "loc" : [ -76.214253, 36.854648 ], "pop" : 21227, "state" : "VA" }
+{ "_id" : "23503", "city" : "NORFOLK", "loc" : [ -76.252008, 36.944196 ], "pop" : 32435, "state" : "VA" }
+{ "_id" : "23504", "city" : "NORFOLK", "loc" : [ -76.26862800000001, 36.858554 ], "pop" : 25706, "state" : "VA" }
+{ "_id" : "23505", "city" : "NORFOLK", "loc" : [ -76.28748, 36.91675 ], "pop" : 30687, "state" : "VA" }
+{ "_id" : "23507", "city" : "NORFOLK", "loc" : [ -76.30038500000001, 36.864506 ], "pop" : 6514, "state" : "VA" }
+{ "_id" : "23508", "city" : "NORFOLK", "loc" : [ -76.30035599999999, 36.885922 ], "pop" : 19729, "state" : "VA" }
+{ "_id" : "23509", "city" : "NORFOLK", "loc" : [ -76.260361, 36.878743 ], "pop" : 12539, "state" : "VA" }
+{ "_id" : "23510", "city" : "NORFOLK", "loc" : [ -76.287784, 36.852929 ], "pop" : 4731, "state" : "VA" }
+{ "_id" : "23511", "city" : "FLEET", "loc" : [ -76.309206, 36.951164 ], "pop" : 28108, "state" : "VA" }
+{ "_id" : "23513", "city" : "NORFOLK", "loc" : [ -76.23957799999999, 36.891395 ], "pop" : 31348, "state" : "VA" }
+{ "_id" : "23517", "city" : "NORFOLK", "loc" : [ -76.29451899999999, 36.869547 ], "pop" : 4433, "state" : "VA" }
+{ "_id" : "23518", "city" : "NORFOLK", "loc" : [ -76.216027, 36.920246 ], "pop" : 35119, "state" : "VA" }
+{ "_id" : "23521", "city" : "NAVAL AMPHIBIOUS", "loc" : [ -76.163715, 36.916923 ], "pop" : 4541, "state" : "VA" }
+{ "_id" : "23523", "city" : "NORFOLK", "loc" : [ -76.27012499999999, 36.82942 ], "pop" : 8682, "state" : "VA" }
+{ "_id" : "23601", "city" : "NEWPORT NEWS", "loc" : [ -76.460722, 37.057951 ], "pop" : 24325, "state" : "VA" }
+{ "_id" : "23602", "city" : "NEWPORT NEWS", "loc" : [ -76.53212499999999, 37.131684 ], "pop" : 68525, "state" : "VA" }
+{ "_id" : "23603", "city" : "NEWPORT NEWS", "loc" : [ -76.582059, 37.198887 ], "pop" : 3368, "state" : "VA" }
+{ "_id" : "23604", "city" : "NEWPORT NEWS", "loc" : [ -76.589727, 37.122112 ], "pop" : 9967, "state" : "VA" }
+{ "_id" : "23605", "city" : "NEWPORT NEWS", "loc" : [ -76.43315800000001, 37.015583 ], "pop" : 12649, "state" : "VA" }
+{ "_id" : "23606", "city" : "NEWPORT NEWS", "loc" : [ -76.496724, 37.076777 ], "pop" : 22429, "state" : "VA" }
+{ "_id" : "23607", "city" : "NEWPORT NEWS", "loc" : [ -76.41646900000001, 36.986352 ], "pop" : 28785, "state" : "VA" }
+{ "_id" : "23651", "city" : "HAMPTON", "loc" : [ -76.296896, 37.029671 ], "pop" : 3325, "state" : "VA" }
+{ "_id" : "23661", "city" : "HAMPTON", "loc" : [ -76.38008499999999, 37.007432 ], "pop" : 15313, "state" : "VA" }
+{ "_id" : "23662", "city" : "POQUOSON", "loc" : [ -76.380702, 37.131252 ], "pop" : 11005, "state" : "VA" }
+{ "_id" : "23663", "city" : "HAMPTON", "loc" : [ -76.319875, 37.03181 ], "pop" : 16889, "state" : "VA" }
+{ "_id" : "23664", "city" : "HAMPTON", "loc" : [ -76.296639, 37.056611 ], "pop" : 7832, "state" : "VA" }
+{ "_id" : "23665", "city" : "HAMPTON", "loc" : [ -76.40993899999999, 37.100565 ], "pop" : 15146, "state" : "VA" }
+{ "_id" : "23666", "city" : "HAMPTON", "loc" : [ -76.409617, 37.046241 ], "pop" : 44985, "state" : "VA" }
+{ "_id" : "23669", "city" : "HAMPTON", "loc" : [ -76.342573, 37.043559 ], "pop" : 41855, "state" : "VA" }
+{ "_id" : "23690", "city" : "YORKTOWN", "loc" : [ -76.54234599999999, 37.228657 ], "pop" : 3216, "state" : "VA" }
+{ "_id" : "23692", "city" : "GRAFTON", "loc" : [ -76.459648, 37.170859 ], "pop" : 14188, "state" : "VA" }
+{ "_id" : "23693", "city" : "TABB", "loc" : [ -76.450743, 37.122586 ], "pop" : 2807, "state" : "VA" }
+{ "_id" : "23696", "city" : "SEAFORD", "loc" : [ -76.42899199999999, 37.188468 ], "pop" : 3009, "state" : "VA" }
+{ "_id" : "23701", "city" : "PORTSMOUTH", "loc" : [ -76.36714000000001, 36.808902 ], "pop" : 29788, "state" : "VA" }
+{ "_id" : "23702", "city" : "PORTSMOUTH", "loc" : [ -76.32697899999999, 36.803534 ], "pop" : 12599, "state" : "VA" }
+{ "_id" : "23703", "city" : "PORTSMOUTH", "loc" : [ -76.386872, 36.869501 ], "pop" : 22512, "state" : "VA" }
+{ "_id" : "23704", "city" : "PORTSMOUTH", "loc" : [ -76.314604, 36.829821 ], "pop" : 23634, "state" : "VA" }
+{ "_id" : "23707", "city" : "PORTSMOUTH", "loc" : [ -76.34401099999999, 36.836234 ], "pop" : 15199, "state" : "VA" }
+{ "_id" : "23709", "city" : "PORTSMOUTH", "loc" : [ -76.305188, 36.813883 ], "pop" : 216, "state" : "VA" }
+{ "_id" : "23801", "city" : "FORT LEE", "loc" : [ -77.33405, 37.244738 ], "pop" : 8817, "state" : "VA" }
+{ "_id" : "23803", "city" : "ETTRICK", "loc" : [ -77.43259399999999, 37.220001 ], "pop" : 41772, "state" : "VA" }
+{ "_id" : "23805", "city" : "PETERSBURG", "loc" : [ -77.385385, 37.181937 ], "pop" : 16432, "state" : "VA" }
+{ "_id" : "23821", "city" : "ALBERTA", "loc" : [ -77.905518, 36.880609 ], "pop" : 1553, "state" : "VA" }
+{ "_id" : "23824", "city" : "BLACKSTONE", "loc" : [ -77.985063, 37.091578 ], "pop" : 6351, "state" : "VA" }
+{ "_id" : "23827", "city" : "BOYKINS", "loc" : [ -77.197519, 36.595061 ], "pop" : 1595, "state" : "VA" }
+{ "_id" : "23828", "city" : "BRANCHVILLE", "loc" : [ -77.27044100000001, 36.578701 ], "pop" : 619, "state" : "VA" }
+{ "_id" : "23829", "city" : "CAPRON", "loc" : [ -77.239363, 36.724332 ], "pop" : 2364, "state" : "VA" }
+{ "_id" : "23830", "city" : "CARSON", "loc" : [ -77.43509299999999, 37.039311 ], "pop" : 1343, "state" : "VA" }
+{ "_id" : "23831", "city" : "CHESTER", "loc" : [ -77.41557, 37.342934 ], "pop" : 24788, "state" : "VA" }
+{ "_id" : "23832", "city" : "CHESTERFIELD", "loc" : [ -77.566799, 37.392327 ], "pop" : 25716, "state" : "VA" }
+{ "_id" : "23833", "city" : "CHURCH ROAD", "loc" : [ -77.66458799999999, 37.194964 ], "pop" : 1515, "state" : "VA" }
+{ "_id" : "23834", "city" : "COLONIAL HEIGHTS", "loc" : [ -77.403829, 37.269968 ], "pop" : 21056, "state" : "VA" }
+{ "_id" : "23837", "city" : "COURTLAND", "loc" : [ -77.078272, 36.722516 ], "pop" : 3570, "state" : "VA" }
+{ "_id" : "23839", "city" : "DENDRON", "loc" : [ -76.896642, 37.098076 ], "pop" : 805, "state" : "VA" }
+{ "_id" : "23840", "city" : "DEWITT", "loc" : [ -77.64255799999999, 37.053522 ], "pop" : 1385, "state" : "VA" }
+{ "_id" : "23841", "city" : "DINWIDDIE", "loc" : [ -77.558539, 37.083283 ], "pop" : 2781, "state" : "VA" }
+{ "_id" : "23842", "city" : "DISPUTANTA", "loc" : [ -77.273172, 37.148268 ], "pop" : 4938, "state" : "VA" }
+{ "_id" : "23843", "city" : "DOLPHIN", "loc" : [ -77.788719, 36.831774 ], "pop" : 982, "state" : "VA" }
+{ "_id" : "23844", "city" : "DREWRYVILLE", "loc" : [ -77.359098, 36.685433 ], "pop" : 743, "state" : "VA" }
+{ "_id" : "23845", "city" : "EBONY", "loc" : [ -77.999431, 36.584993 ], "pop" : 568, "state" : "VA" }
+{ "_id" : "23846", "city" : "ELBERON", "loc" : [ -76.83372300000001, 37.070133 ], "pop" : 715, "state" : "VA" }
+{ "_id" : "23847", "city" : "EMPORIA", "loc" : [ -77.56295299999999, 36.685689 ], "pop" : 13950, "state" : "VA" }
+{ "_id" : "23850", "city" : "AMMON", "loc" : [ -77.737189, 37.139672 ], "pop" : 1315, "state" : "VA" }
+{ "_id" : "23851", "city" : "FRANKLIN", "loc" : [ -76.939108, 36.678625 ], "pop" : 12786, "state" : "VA" }
+{ "_id" : "23856", "city" : "FREEMAN", "loc" : [ -77.720772, 36.789342 ], "pop" : 920, "state" : "VA" }
+{ "_id" : "23857", "city" : "GASBURG", "loc" : [ -77.90292700000001, 36.576552 ], "pop" : 771, "state" : "VA" }
+{ "_id" : "23859", "city" : "HANDSOM", "loc" : [ -77.023797, 36.609854 ], "pop" : 371, "state" : "VA" }
+{ "_id" : "23860", "city" : "HOPEWELL", "loc" : [ -77.295013, 37.287576 ], "pop" : 25764, "state" : "VA" }
+{ "_id" : "23866", "city" : "IVOR", "loc" : [ -76.886146, 36.907099 ], "pop" : 2205, "state" : "VA" }
+{ "_id" : "23867", "city" : "JARRATT", "loc" : [ -77.48316199999999, 36.819129 ], "pop" : 2055, "state" : "VA" }
+{ "_id" : "23868", "city" : "TRIPLET", "loc" : [ -77.838437, 36.744874 ], "pop" : 6357, "state" : "VA" }
+{ "_id" : "23872", "city" : "MC KENNEY", "loc" : [ -77.73955599999999, 36.998609 ], "pop" : 1866, "state" : "VA" }
+{ "_id" : "23874", "city" : "NEWSOMS", "loc" : [ -77.106949, 36.614814 ], "pop" : 1193, "state" : "VA" }
+{ "_id" : "23875", "city" : "PRINCE GEORGE", "loc" : [ -77.27470599999999, 37.233339 ], "pop" : 7713, "state" : "VA" }
+{ "_id" : "23876", "city" : "RAWLINGS", "loc" : [ -77.82371999999999, 36.953043 ], "pop" : 527, "state" : "VA" }
+{ "_id" : "23878", "city" : "SEDLEY", "loc" : [ -77.012531, 36.790752 ], "pop" : 491, "state" : "VA" }
+{ "_id" : "23879", "city" : "SKIPPERS", "loc" : [ -77.543663, 36.579685 ], "pop" : 196, "state" : "VA" }
+{ "_id" : "23881", "city" : "SPRING GROVE", "loc" : [ -76.99233700000001, 37.190098 ], "pop" : 1746, "state" : "VA" }
+{ "_id" : "23882", "city" : "STONY CREEK", "loc" : [ -77.444276, 36.936132 ], "pop" : 2889, "state" : "VA" }
+{ "_id" : "23883", "city" : "SURRY", "loc" : [ -76.76514, 37.126024 ], "pop" : 2271, "state" : "VA" }
+{ "_id" : "23885", "city" : "SUTHERLAND", "loc" : [ -77.56546299999999, 37.190149 ], "pop" : 2470, "state" : "VA" }
+{ "_id" : "23887", "city" : "VALENTINES", "loc" : [ -77.83840499999999, 36.565024 ], "pop" : 188, "state" : "VA" }
+{ "_id" : "23888", "city" : "WAKEFIELD", "loc" : [ -76.97898000000001, 36.975734 ], "pop" : 2790, "state" : "VA" }
+{ "_id" : "23889", "city" : "WARFIELD", "loc" : [ -77.76731700000001, 36.901122 ], "pop" : 580, "state" : "VA" }
+{ "_id" : "23890", "city" : "WAVERLY", "loc" : [ -77.105453, 37.025032 ], "pop" : 4581, "state" : "VA" }
+{ "_id" : "23893", "city" : "WHITE PLAINS", "loc" : [ -77.959245, 36.633549 ], "pop" : 522, "state" : "VA" }
+{ "_id" : "23894", "city" : "WILSONS", "loc" : [ -77.835193, 37.115678 ], "pop" : 592, "state" : "VA" }
+{ "_id" : "23897", "city" : "YALE", "loc" : [ -77.286986, 36.837279 ], "pop" : 626, "state" : "VA" }
+{ "_id" : "23898", "city" : "ZUNI", "loc" : [ -76.81096700000001, 36.843666 ], "pop" : 2162, "state" : "VA" }
+{ "_id" : "23901", "city" : "FARMVILLE", "loc" : [ -78.40759199999999, 37.302692 ], "pop" : 14084, "state" : "VA" }
+{ "_id" : "23915", "city" : "BASKERVILLE", "loc" : [ -78.27904700000001, 36.723595 ], "pop" : 1114, "state" : "VA" }
+{ "_id" : "23917", "city" : "BOYDTON", "loc" : [ -78.375174, 36.654422 ], "pop" : 2613, "state" : "VA" }
+{ "_id" : "23919", "city" : "BRACEY", "loc" : [ -78.105862, 36.576295 ], "pop" : 1127, "state" : "VA" }
+{ "_id" : "23920", "city" : "BRODNAX", "loc" : [ -77.98984299999999, 36.731879 ], "pop" : 2571, "state" : "VA" }
+{ "_id" : "23921", "city" : "BUCKINGHAM", "loc" : [ -78.59853699999999, 37.583335 ], "pop" : 2056, "state" : "VA" }
+{ "_id" : "23922", "city" : "BURKEVILLE", "loc" : [ -78.196084, 37.195203 ], "pop" : 3751, "state" : "VA" }
+{ "_id" : "23923", "city" : "CHARLOTTE COURT", "loc" : [ -78.660622, 37.086379 ], "pop" : 2061, "state" : "VA" }
+{ "_id" : "23924", "city" : "CHASE CITY", "loc" : [ -78.455268, 36.805305 ], "pop" : 5715, "state" : "VA" }
+{ "_id" : "23927", "city" : "CLARKSVILLE", "loc" : [ -78.53529399999999, 36.631437 ], "pop" : 2736, "state" : "VA" }
+{ "_id" : "23930", "city" : "CREWE", "loc" : [ -78.10586600000001, 37.165676 ], "pop" : 5565, "state" : "VA" }
+{ "_id" : "23934", "city" : "CULLEN", "loc" : [ -78.645912, 37.155211 ], "pop" : 596, "state" : "VA" }
+{ "_id" : "23936", "city" : "SPROUSES CORNER", "loc" : [ -78.46092899999999, 37.545804 ], "pop" : 5330, "state" : "VA" }
+{ "_id" : "23937", "city" : "DRAKES BRANCH", "loc" : [ -78.561542, 36.968767 ], "pop" : 1509, "state" : "VA" }
+{ "_id" : "23938", "city" : "DUNDAS", "loc" : [ -78.01001599999999, 36.90532 ], "pop" : 407, "state" : "VA" }
+{ "_id" : "23942", "city" : "GREEN BAY", "loc" : [ -78.30719499999999, 37.123417 ], "pop" : 838, "state" : "VA" }
+{ "_id" : "23944", "city" : "KENBRIDGE", "loc" : [ -78.12423800000001, 36.932965 ], "pop" : 4269, "state" : "VA" }
+{ "_id" : "23947", "city" : "KEYSVILLE", "loc" : [ -78.46991199999999, 37.041086 ], "pop" : 3670, "state" : "VA" }
+{ "_id" : "23950", "city" : "BLACKRIDGE", "loc" : [ -78.095251, 36.68609 ], "pop" : 3036, "state" : "VA" }
+{ "_id" : "23952", "city" : "LUNENBURG", "loc" : [ -78.290644, 36.922624 ], "pop" : 156, "state" : "VA" }
+{ "_id" : "23954", "city" : "MEHERRIN", "loc" : [ -78.38735699999999, 37.101283 ], "pop" : 1429, "state" : "VA" }
+{ "_id" : "23958", "city" : "PAMPLIN", "loc" : [ -78.65166000000001, 37.265333 ], "pop" : 2298, "state" : "VA" }
+{ "_id" : "23959", "city" : "PHENIX", "loc" : [ -78.791195, 37.092506 ], "pop" : 900, "state" : "VA" }
+{ "_id" : "23960", "city" : "PROSPECT", "loc" : [ -78.546162, 37.305838 ], "pop" : 1661, "state" : "VA" }
+{ "_id" : "23962", "city" : "RANDOLPH", "loc" : [ -78.69924899999999, 36.963079 ], "pop" : 600, "state" : "VA" }
+{ "_id" : "23963", "city" : "RED HOUSE", "loc" : [ -78.81446699999999, 37.191431 ], "pop" : 616, "state" : "VA" }
+{ "_id" : "23964", "city" : "RED OAK", "loc" : [ -78.632057, 36.772403 ], "pop" : 667, "state" : "VA" }
+{ "_id" : "23966", "city" : "RICE", "loc" : [ -78.279262, 37.272132 ], "pop" : 1973, "state" : "VA" }
+{ "_id" : "23967", "city" : "SAXE", "loc" : [ -78.605699, 36.90569 ], "pop" : 1095, "state" : "VA" }
+{ "_id" : "23968", "city" : "SKIPWITH", "loc" : [ -78.530552, 36.731704 ], "pop" : 1177, "state" : "VA" }
+{ "_id" : "23970", "city" : "SOUTH HILL", "loc" : [ -78.15338800000001, 36.712388 ], "pop" : 7056, "state" : "VA" }
+{ "_id" : "23974", "city" : "VICTORIA", "loc" : [ -78.23724300000001, 36.983543 ], "pop" : 4027, "state" : "VA" }
+{ "_id" : "23976", "city" : "WYLLIESBURG", "loc" : [ -78.612655, 36.838968 ], "pop" : 945, "state" : "VA" }
+{ "_id" : "24011", "city" : "ROANOKE", "loc" : [ -79.942019, 37.268997 ], "pop" : 150, "state" : "VA" }
+{ "_id" : "24012", "city" : "ROANOKE", "loc" : [ -79.932179, 37.302912 ], "pop" : 22982, "state" : "VA" }
+{ "_id" : "24013", "city" : "ROANOKE", "loc" : [ -79.924747, 37.267685 ], "pop" : 8347, "state" : "VA" }
+{ "_id" : "24014", "city" : "ROANOKE", "loc" : [ -79.946332, 37.23268 ], "pop" : 21753, "state" : "VA" }
+{ "_id" : "24015", "city" : "ROANOKE", "loc" : [ -79.980694, 37.258363 ], "pop" : 15358, "state" : "VA" }
+{ "_id" : "24016", "city" : "ROANOKE", "loc" : [ -79.953495, 37.270407 ], "pop" : 9782, "state" : "VA" }
+{ "_id" : "24017", "city" : "ROANOKE", "loc" : [ -79.99024799999999, 37.293655 ], "pop" : 24776, "state" : "VA" }
+{ "_id" : "24018", "city" : "CAVE SPRING", "loc" : [ -80.021749, 37.231554 ], "pop" : 24993, "state" : "VA" }
+{ "_id" : "24019", "city" : "HOLLINS", "loc" : [ -79.956328, 37.33585 ], "pop" : 23189, "state" : "VA" }
+{ "_id" : "24053", "city" : "ARARAT", "loc" : [ -80.50933999999999, 36.613946 ], "pop" : 960, "state" : "VA" }
+{ "_id" : "24054", "city" : "AXTON", "loc" : [ -79.73963999999999, 36.654839 ], "pop" : 4428, "state" : "VA" }
+{ "_id" : "24055", "city" : "BASSETT", "loc" : [ -80.005506, 36.753425 ], "pop" : 14101, "state" : "VA" }
+{ "_id" : "24059", "city" : "BENT MOUNTAIN", "loc" : [ -80.145501, 37.206793 ], "pop" : 2388, "state" : "VA" }
+{ "_id" : "24060", "city" : "WHITETHORNE", "loc" : [ -80.427313, 37.228804 ], "pop" : 42796, "state" : "VA" }
+{ "_id" : "24064", "city" : "BLUE RIDGE", "loc" : [ -79.817178, 37.388542 ], "pop" : 1669, "state" : "VA" }
+{ "_id" : "24065", "city" : "BOONES MILL", "loc" : [ -79.95555400000001, 37.13313 ], "pop" : 6767, "state" : "VA" }
+{ "_id" : "24066", "city" : "LITHIA", "loc" : [ -79.705287, 37.52844 ], "pop" : 4145, "state" : "VA" }
+{ "_id" : "24067", "city" : "CALLAWAY", "loc" : [ -80.049592, 37.028495 ], "pop" : 2012, "state" : "VA" }
+{ "_id" : "24069", "city" : "CASCADE", "loc" : [ -79.657438, 36.592697 ], "pop" : 1435, "state" : "VA" }
+{ "_id" : "24070", "city" : "CATAWBA", "loc" : [ -80.128384, 37.369649 ], "pop" : 3747, "state" : "VA" }
+{ "_id" : "24072", "city" : "SIMPSONS", "loc" : [ -80.23674699999999, 37.032642 ], "pop" : 1048, "state" : "VA" }
+{ "_id" : "24073", "city" : "CHRISTIANSBURG", "loc" : [ -80.418774, 37.135286 ], "pop" : 20714, "state" : "VA" }
+{ "_id" : "24076", "city" : "CLAUDVILLE", "loc" : [ -80.44417900000001, 36.583899 ], "pop" : 1576, "state" : "VA" }
+{ "_id" : "24077", "city" : "CLOVERDALE", "loc" : [ -79.91276499999999, 37.366293 ], "pop" : 582, "state" : "VA" }
+{ "_id" : "24078", "city" : "COLLINSVILLE", "loc" : [ -79.914192, 36.72379 ], "pop" : 7668, "state" : "VA" }
+{ "_id" : "24079", "city" : "COPPER HILL", "loc" : [ -80.152469, 37.055568 ], "pop" : 1765, "state" : "VA" }
+{ "_id" : "24082", "city" : "CRITZ", "loc" : [ -80.12976500000001, 36.621059 ], "pop" : 260, "state" : "VA" }
+{ "_id" : "24083", "city" : "DALEVILLE", "loc" : [ -79.92109499999999, 37.41253 ], "pop" : 1408, "state" : "VA" }
+{ "_id" : "24084", "city" : "DUBLIN", "loc" : [ -80.669696, 37.098879 ], "pop" : 9521, "state" : "VA" }
+{ "_id" : "24085", "city" : "EAGLE ROCK", "loc" : [ -79.817215, 37.666727 ], "pop" : 2939, "state" : "VA" }
+{ "_id" : "24086", "city" : "EGGLESTON", "loc" : [ -80.65275800000001, 37.290576 ], "pop" : 374, "state" : "VA" }
+{ "_id" : "24087", "city" : "IRONTO", "loc" : [ -80.249658, 37.212651 ], "pop" : 4216, "state" : "VA" }
+{ "_id" : "24088", "city" : "FERRUM", "loc" : [ -80.03492300000001, 36.916834 ], "pop" : 4389, "state" : "VA" }
+{ "_id" : "24089", "city" : "FIELDALE", "loc" : [ -79.965245, 36.706414 ], "pop" : 2594, "state" : "VA" }
+{ "_id" : "24090", "city" : "FINCASTLE", "loc" : [ -79.851116, 37.491099 ], "pop" : 2843, "state" : "VA" }
+{ "_id" : "24091", "city" : "ALUM RIDGE", "loc" : [ -80.31905399999999, 36.919523 ], "pop" : 4833, "state" : "VA" }
+{ "_id" : "24092", "city" : "GLADEHILL", "loc" : [ -79.77627099999999, 37.016866 ], "pop" : 2047, "state" : "VA" }
+{ "_id" : "24093", "city" : "GLEN LYN", "loc" : [ -80.86335800000001, 37.366853 ], "pop" : 126, "state" : "VA" }
+{ "_id" : "24094", "city" : "GOLDBOND", "loc" : [ -80.66315, 37.387221 ], "pop" : 53, "state" : "VA" }
+{ "_id" : "24095", "city" : "GOODVIEW", "loc" : [ -79.72628400000001, 37.347167 ], "pop" : 1686, "state" : "VA" }
+{ "_id" : "24101", "city" : "HARDY", "loc" : [ -79.81266100000001, 37.214473 ], "pop" : 5955, "state" : "VA" }
+{ "_id" : "24102", "city" : "HENRY", "loc" : [ -79.99036, 36.839322 ], "pop" : 1393, "state" : "VA" }
+{ "_id" : "24104", "city" : "HUDDLESTON", "loc" : [ -79.491017, 37.144155 ], "pop" : 2299, "state" : "VA" }
+{ "_id" : "24105", "city" : "INDIAN VALLEY", "loc" : [ -80.57571, 36.898993 ], "pop" : 502, "state" : "VA" }
+{ "_id" : "24112", "city" : "MARTINSVILLE", "loc" : [ -79.869136, 36.687067 ], "pop" : 35994, "state" : "VA" }
+{ "_id" : "24120", "city" : "MEADOWS OF DAN", "loc" : [ -80.402227, 36.72504 ], "pop" : 1532, "state" : "VA" }
+{ "_id" : "24121", "city" : "MONETA", "loc" : [ -79.652111, 37.178383 ], "pop" : 4586, "state" : "VA" }
+{ "_id" : "24122", "city" : "MONTVALE", "loc" : [ -79.717462, 37.40696 ], "pop" : 1747, "state" : "VA" }
+{ "_id" : "24124", "city" : "NARROWS", "loc" : [ -80.85485, 37.319846 ], "pop" : 5250, "state" : "VA" }
+{ "_id" : "24127", "city" : "NEW CASTLE", "loc" : [ -80.17041999999999, 37.487132 ], "pop" : 3400, "state" : "VA" }
+{ "_id" : "24128", "city" : "NEWPORT", "loc" : [ -80.50991999999999, 37.306852 ], "pop" : 1578, "state" : "VA" }
+{ "_id" : "24131", "city" : "PAINT BANK", "loc" : [ -80.254436, 37.574482 ], "pop" : 153, "state" : "VA" }
+{ "_id" : "24133", "city" : "PATRICK SPRINGS", "loc" : [ -80.138769, 36.674435 ], "pop" : 2789, "state" : "VA" }
+{ "_id" : "24134", "city" : "PEARISBURG", "loc" : [ -80.726703, 37.304121 ], "pop" : 5279, "state" : "VA" }
+{ "_id" : "24136", "city" : "MOUNTAIN LAKE", "loc" : [ -80.61550699999999, 37.33027 ], "pop" : 3087, "state" : "VA" }
+{ "_id" : "24137", "city" : "PENHOOK", "loc" : [ -79.66449299999999, 36.920125 ], "pop" : 1768, "state" : "VA" }
+{ "_id" : "24138", "city" : "PILOT", "loc" : [ -80.322901, 37.056476 ], "pop" : 882, "state" : "VA" }
+{ "_id" : "24139", "city" : "PITTSVILLE", "loc" : [ -79.47941299999999, 36.971578 ], "pop" : 415, "state" : "VA" }
+{ "_id" : "24141", "city" : "FAIRLAWN", "loc" : [ -80.571721, 37.135816 ], "pop" : 22335, "state" : "VA" }
+{ "_id" : "24147", "city" : "RICH CREEK", "loc" : [ -80.82271799999999, 37.385048 ], "pop" : 947, "state" : "VA" }
+{ "_id" : "24148", "city" : "RIDGEWAY", "loc" : [ -79.86859, 36.5874 ], "pop" : 7953, "state" : "VA" }
+{ "_id" : "24149", "city" : "RINER", "loc" : [ -80.435309, 37.032209 ], "pop" : 2947, "state" : "VA" }
+{ "_id" : "24150", "city" : "RIPPLEMEAD", "loc" : [ -80.671728, 37.366455 ], "pop" : 37, "state" : "VA" }
+{ "_id" : "24151", "city" : "ROCKY MOUNT", "loc" : [ -79.883959, 36.989101 ], "pop" : 15579, "state" : "VA" }
+{ "_id" : "24153", "city" : "SALEM", "loc" : [ -80.069185, 37.2853 ], "pop" : 30570, "state" : "VA" }
+{ "_id" : "24161", "city" : "SANDY LEVEL", "loc" : [ -79.561404, 36.991042 ], "pop" : 512, "state" : "VA" }
+{ "_id" : "24162", "city" : "SHAWSVILLE", "loc" : [ -80.27153, 37.146619 ], "pop" : 2571, "state" : "VA" }
+{ "_id" : "24165", "city" : "SPENCER", "loc" : [ -80.037345, 36.59676 ], "pop" : 1537, "state" : "VA" }
+{ "_id" : "24167", "city" : "STAFFORDSVILLE", "loc" : [ -80.740334, 37.245378 ], "pop" : 464, "state" : "VA" }
+{ "_id" : "24168", "city" : "STANLEYTOWN", "loc" : [ -79.93548199999999, 36.734759 ], "pop" : 153, "state" : "VA" }
+{ "_id" : "24171", "city" : "STUART", "loc" : [ -80.23923000000001, 36.651744 ], "pop" : 7990, "state" : "VA" }
+{ "_id" : "24174", "city" : "THAXTON", "loc" : [ -79.652187, 37.360008 ], "pop" : 1136, "state" : "VA" }
+{ "_id" : "24175", "city" : "TROUTVILLE", "loc" : [ -79.878636, 37.401855 ], "pop" : 9211, "state" : "VA" }
+{ "_id" : "24176", "city" : "UNION HALL", "loc" : [ -79.686447, 37.013111 ], "pop" : 804, "state" : "VA" }
+{ "_id" : "24179", "city" : "STEWARTSVILLE", "loc" : [ -79.835466, 37.271139 ], "pop" : 18205, "state" : "VA" }
+{ "_id" : "24184", "city" : "WIRTZ", "loc" : [ -79.757254, 37.081794 ], "pop" : 1675, "state" : "VA" }
+{ "_id" : "24185", "city" : "WOOLWINE", "loc" : [ -80.27742600000001, 36.792076 ], "pop" : 898, "state" : "VA" }
+{ "_id" : "24201", "city" : "BRISTOL", "loc" : [ -82.18229700000001, 36.618093 ], "pop" : 23166, "state" : "VA" }
+{ "_id" : "24210", "city" : "ABINGDON", "loc" : [ -82.019989, 36.691644 ], "pop" : 25429, "state" : "VA" }
+{ "_id" : "24216", "city" : "EXETER", "loc" : [ -82.791394, 36.906001 ], "pop" : 2916, "state" : "VA" }
+{ "_id" : "24217", "city" : "BEE", "loc" : [ -82.185632, 37.101358 ], "pop" : 495, "state" : "VA" }
+{ "_id" : "24219", "city" : "BIG STONE GAP", "loc" : [ -82.762727, 36.858073 ], "pop" : 10858, "state" : "VA" }
+{ "_id" : "24220", "city" : "BIRCHLEAF", "loc" : [ -82.248346, 37.169481 ], "pop" : 997, "state" : "VA" }
+{ "_id" : "24221", "city" : "BLACKWATER", "loc" : [ -82.98658, 36.639011 ], "pop" : 1008, "state" : "VA" }
+{ "_id" : "24224", "city" : "CASTLEWOOD", "loc" : [ -82.28757400000001, 36.876409 ], "pop" : 7166, "state" : "VA" }
+{ "_id" : "24225", "city" : "CLEVELAND", "loc" : [ -82.131758, 36.950215 ], "pop" : 1966, "state" : "VA" }
+{ "_id" : "24226", "city" : "CLINCHCO", "loc" : [ -82.342476, 37.140581 ], "pop" : 2059, "state" : "VA" }
+{ "_id" : "24228", "city" : "CLINTWOOD", "loc" : [ -82.445339, 37.159206 ], "pop" : 7866, "state" : "VA" }
+{ "_id" : "24230", "city" : "COEBURN", "loc" : [ -82.47349699999999, 36.960489 ], "pop" : 11745, "state" : "VA" }
+{ "_id" : "24236", "city" : "DAMASCUS", "loc" : [ -81.77763299999999, 36.640264 ], "pop" : 3312, "state" : "VA" }
+{ "_id" : "24237", "city" : "DANTE", "loc" : [ -82.281519, 37.005419 ], "pop" : 1168, "state" : "VA" }
+{ "_id" : "24239", "city" : "DAVENPORT", "loc" : [ -82.122946, 37.068044 ], "pop" : 49, "state" : "VA" }
+{ "_id" : "24243", "city" : "DRYDEN", "loc" : [ -82.93047799999999, 36.781825 ], "pop" : 2185, "state" : "VA" }
+{ "_id" : "24244", "city" : "CLINCHPORT", "loc" : [ -82.80651, 36.704402 ], "pop" : 5688, "state" : "VA" }
+{ "_id" : "24245", "city" : "DUNGANNON", "loc" : [ -82.496025, 36.82416 ], "pop" : 1231, "state" : "VA" }
+{ "_id" : "24248", "city" : "EWING", "loc" : [ -83.50473700000001, 36.623694 ], "pop" : 2599, "state" : "VA" }
+{ "_id" : "24250", "city" : "FORT BLACKMORE", "loc" : [ -82.610178, 36.743828 ], "pop" : 1085, "state" : "VA" }
+{ "_id" : "24251", "city" : "GATE CITY", "loc" : [ -82.61117900000001, 36.646026 ], "pop" : 7641, "state" : "VA" }
+{ "_id" : "24256", "city" : "HAYSI", "loc" : [ -82.28530600000001, 37.220552 ], "pop" : 3813, "state" : "VA" }
+{ "_id" : "24258", "city" : "HILTONS", "loc" : [ -82.429929, 36.649778 ], "pop" : 1937, "state" : "VA" }
+{ "_id" : "24260", "city" : "COUNCIL", "loc" : [ -81.996883, 37.027292 ], "pop" : 6162, "state" : "VA" }
+{ "_id" : "24263", "city" : "JONESVILLE", "loc" : [ -83.13615, 36.689647 ], "pop" : 6275, "state" : "VA" }
+{ "_id" : "24265", "city" : "KEOKEE", "loc" : [ -82.977161, 36.823931 ], "pop" : 1807, "state" : "VA" }
+{ "_id" : "24266", "city" : "LEBANON", "loc" : [ -82.09563, 36.880895 ], "pop" : 7818, "state" : "VA" }
+{ "_id" : "24269", "city" : "MC CLURE", "loc" : [ -82.38055300000001, 37.081412 ], "pop" : 124, "state" : "VA" }
+{ "_id" : "24270", "city" : "MENDOTA", "loc" : [ -82.264888, 36.722302 ], "pop" : 675, "state" : "VA" }
+{ "_id" : "24271", "city" : "NICKELSVILLE", "loc" : [ -82.42017199999999, 36.750221 ], "pop" : 2749, "state" : "VA" }
+{ "_id" : "24272", "city" : "NORA", "loc" : [ -82.35002299999999, 37.018229 ], "pop" : 514, "state" : "VA" }
+{ "_id" : "24273", "city" : "NORTON", "loc" : [ -82.624923, 36.937797 ], "pop" : 4145, "state" : "VA" }
+{ "_id" : "24277", "city" : "PENNINGTON GAP", "loc" : [ -83.022299, 36.750752 ], "pop" : 5859, "state" : "VA" }
+{ "_id" : "24279", "city" : "POUND", "loc" : [ -82.601555, 37.092734 ], "pop" : 5330, "state" : "VA" }
+{ "_id" : "24280", "city" : "ROSEDALE", "loc" : [ -81.88879300000001, 36.973981 ], "pop" : 2492, "state" : "VA" }
+{ "_id" : "24281", "city" : "ROSE HILL", "loc" : [ -83.34856499999999, 36.658257 ], "pop" : 2404, "state" : "VA" }
+{ "_id" : "24282", "city" : "SAINT CHARLES", "loc" : [ -83.051838, 36.831515 ], "pop" : 485, "state" : "VA" }
+{ "_id" : "24283", "city" : "SAINT PAUL", "loc" : [ -82.34184399999999, 36.932295 ], "pop" : 2680, "state" : "VA" }
+{ "_id" : "24285", "city" : "STONEGA", "loc" : [ -82.819194, 36.950176 ], "pop" : 670, "state" : "VA" }
+{ "_id" : "24289", "city" : "TRAMMEL", "loc" : [ -82.217563, 37.022959 ], "pop" : 51, "state" : "VA" }
+{ "_id" : "24290", "city" : "WEBER CITY", "loc" : [ -82.545227, 36.620213 ], "pop" : 2981, "state" : "VA" }
+{ "_id" : "24292", "city" : "WHITETOP", "loc" : [ -81.583938, 36.610559 ], "pop" : 642, "state" : "VA" }
+{ "_id" : "24293", "city" : "WISE", "loc" : [ -82.594679, 36.975 ], "pop" : 8957, "state" : "VA" }
+{ "_id" : "24301", "city" : "PULASKI", "loc" : [ -80.770961, 37.056708 ], "pop" : 16576, "state" : "VA" }
+{ "_id" : "24311", "city" : "ATKINS", "loc" : [ -81.404791, 36.866532 ], "pop" : 1108, "state" : "VA" }
+{ "_id" : "24312", "city" : "AUSTINVILLE", "loc" : [ -80.858322, 36.819461 ], "pop" : 2488, "state" : "VA" }
+{ "_id" : "24313", "city" : "BARREN SPRINGS", "loc" : [ -80.809006, 36.907787 ], "pop" : 575, "state" : "VA" }
+{ "_id" : "24314", "city" : "BASTIAN", "loc" : [ -81.19885499999999, 37.15742 ], "pop" : 1656, "state" : "VA" }
+{ "_id" : "24315", "city" : "BLAND", "loc" : [ -81.020064, 37.137644 ], "pop" : 3261, "state" : "VA" }
+{ "_id" : "24316", "city" : "BROADFORD", "loc" : [ -81.65938800000001, 36.93299 ], "pop" : 132, "state" : "VA" }
+{ "_id" : "24317", "city" : "CANA", "loc" : [ -80.670452, 36.59574 ], "pop" : 3363, "state" : "VA" }
+{ "_id" : "24318", "city" : "CERES", "loc" : [ -81.364272, 37.00456 ], "pop" : 833, "state" : "VA" }
+{ "_id" : "24319", "city" : "CHILHOWIE", "loc" : [ -81.665103, 36.771912 ], "pop" : 6087, "state" : "VA" }
+{ "_id" : "24322", "city" : "CRIPPLE CREEK", "loc" : [ -81.103928, 36.808612 ], "pop" : 157, "state" : "VA" }
+{ "_id" : "24323", "city" : "CROCKETT", "loc" : [ -81.208883, 36.876755 ], "pop" : 347, "state" : "VA" }
+{ "_id" : "24324", "city" : "DRAPER", "loc" : [ -80.818752, 36.969743 ], "pop" : 1161, "state" : "VA" }
+{ "_id" : "24325", "city" : "DUGSPUR", "loc" : [ -80.612348, 36.814546 ], "pop" : 1241, "state" : "VA" }
+{ "_id" : "24326", "city" : "ELK CREEK", "loc" : [ -81.19148800000001, 36.730579 ], "pop" : 1161, "state" : "VA" }
+{ "_id" : "24328", "city" : "FANCY GAP", "loc" : [ -80.69074999999999, 36.663972 ], "pop" : 1929, "state" : "VA" }
+{ "_id" : "24330", "city" : "FRIES", "loc" : [ -81.00415700000001, 36.724683 ], "pop" : 4077, "state" : "VA" }
+{ "_id" : "24333", "city" : "GALAX", "loc" : [ -80.911744, 36.656503 ], "pop" : 17442, "state" : "VA" }
+{ "_id" : "24340", "city" : "GLADE SPRING", "loc" : [ -81.767639, 36.7779 ], "pop" : 4384, "state" : "VA" }
+{ "_id" : "24343", "city" : "HILLSVILLE", "loc" : [ -80.71973, 36.744225 ], "pop" : 10578, "state" : "VA" }
+{ "_id" : "24347", "city" : "ALLISONIA", "loc" : [ -80.63817299999999, 36.997815 ], "pop" : 2062, "state" : "VA" }
+{ "_id" : "24348", "city" : "INDEPENDENCE", "loc" : [ -81.158202, 36.629444 ], "pop" : 3760, "state" : "VA" }
+{ "_id" : "24350", "city" : "IVANHOE", "loc" : [ -80.97791100000001, 36.827225 ], "pop" : 1006, "state" : "VA" }
+{ "_id" : "24351", "city" : "LAMBSBURG", "loc" : [ -80.760133, 36.577483 ], "pop" : 528, "state" : "VA" }
+{ "_id" : "24352", "city" : "LAUREL FORK", "loc" : [ -80.514776, 36.707347 ], "pop" : 714, "state" : "VA" }
+{ "_id" : "24354", "city" : "MARION", "loc" : [ -81.534914, 36.827316 ], "pop" : 16672, "state" : "VA" }
+{ "_id" : "24360", "city" : "FOSTER FALLS", "loc" : [ -80.921391, 36.91708 ], "pop" : 4621, "state" : "VA" }
+{ "_id" : "24361", "city" : "MEADOWVIEW", "loc" : [ -81.85120499999999, 36.761175 ], "pop" : 6288, "state" : "VA" }
+{ "_id" : "24363", "city" : "MOUTH OF WILSON", "loc" : [ -81.39545200000001, 36.610379 ], "pop" : 1735, "state" : "VA" }
+{ "_id" : "24366", "city" : "ROCKY GAP", "loc" : [ -81.155236, 37.244242 ], "pop" : 510, "state" : "VA" }
+{ "_id" : "24368", "city" : "RURAL RETREAT", "loc" : [ -81.28787199999999, 36.883616 ], "pop" : 4350, "state" : "VA" }
+{ "_id" : "24370", "city" : "SALTVILLE", "loc" : [ -81.740201, 36.892699 ], "pop" : 6739, "state" : "VA" }
+{ "_id" : "24373", "city" : "SEVEN MILE FORD", "loc" : [ -81.645672, 36.815329 ], "pop" : 155, "state" : "VA" }
+{ "_id" : "24374", "city" : "SPEEDWELL", "loc" : [ -81.183404, 36.799843 ], "pop" : 633, "state" : "VA" }
+{ "_id" : "24375", "city" : "SUGAR GROVE", "loc" : [ -81.40844300000001, 36.773633 ], "pop" : 1237, "state" : "VA" }
+{ "_id" : "24377", "city" : "TANNERSVILLE", "loc" : [ -81.628017, 36.976331 ], "pop" : 271, "state" : "VA" }
+{ "_id" : "24378", "city" : "TROUT DALE", "loc" : [ -81.43500400000001, 36.68546 ], "pop" : 1261, "state" : "VA" }
+{ "_id" : "24380", "city" : "WILLIS", "loc" : [ -80.490861, 36.874927 ], "pop" : 2769, "state" : "VA" }
+{ "_id" : "24381", "city" : "WOODLAWN", "loc" : [ -80.882437, 36.787948 ], "pop" : 218, "state" : "VA" }
+{ "_id" : "24382", "city" : "WYTHEVILLE", "loc" : [ -81.094082, 36.940669 ], "pop" : 13788, "state" : "VA" }
+{ "_id" : "24401", "city" : "WOODRUM", "loc" : [ -79.07519000000001, 38.145104 ], "pop" : 34323, "state" : "VA" }
+{ "_id" : "24413", "city" : "BLUE GRASS", "loc" : [ -79.561272, 38.515231 ], "pop" : 201, "state" : "VA" }
+{ "_id" : "24416", "city" : "BUENA VISTA", "loc" : [ -79.352311, 37.739585 ], "pop" : 8464, "state" : "VA" }
+{ "_id" : "24421", "city" : "CHURCHVILLE", "loc" : [ -79.179126, 38.234605 ], "pop" : 3411, "state" : "VA" }
+{ "_id" : "24422", "city" : "CLIFTON FORGE", "loc" : [ -79.805423, 37.820342 ], "pop" : 7486, "state" : "VA" }
+{ "_id" : "24426", "city" : "ALLEGHANY", "loc" : [ -80.003176, 37.784203 ], "pop" : 16958, "state" : "VA" }
+{ "_id" : "24430", "city" : "CRAIGSVILLE", "loc" : [ -79.36188300000001, 38.076826 ], "pop" : 3008, "state" : "VA" }
+{ "_id" : "24431", "city" : "CRIMORA", "loc" : [ -78.841275, 38.168422 ], "pop" : 2153, "state" : "VA" }
+{ "_id" : "24432", "city" : "DEERFIELD", "loc" : [ -79.41518600000001, 38.184231 ], "pop" : 389, "state" : "VA" }
+{ "_id" : "24433", "city" : "DOE HILL", "loc" : [ -79.482176, 38.390248 ], "pop" : 265, "state" : "VA" }
+{ "_id" : "24435", "city" : "FAIRFIELD", "loc" : [ -79.297922, 37.877825 ], "pop" : 1314, "state" : "VA" }
+{ "_id" : "24437", "city" : "FORT DEFIANCE", "loc" : [ -78.93258299999999, 38.210928 ], "pop" : 824, "state" : "VA" }
+{ "_id" : "24439", "city" : "GOSHEN", "loc" : [ -79.47732499999999, 37.987813 ], "pop" : 1173, "state" : "VA" }
+{ "_id" : "24440", "city" : "GREENVILLE", "loc" : [ -79.135876, 38.001804 ], "pop" : 1975, "state" : "VA" }
+{ "_id" : "24441", "city" : "GROTTOES", "loc" : [ -78.82552800000001, 38.248371 ], "pop" : 3879, "state" : "VA" }
+{ "_id" : "24442", "city" : "HEAD WATERS", "loc" : [ -79.435272, 38.294611 ], "pop" : 87, "state" : "VA" }
+{ "_id" : "24444", "city" : "HIGHTOWN", "loc" : [ -79.592927, 38.464597 ], "pop" : 192, "state" : "VA" }
+{ "_id" : "24445", "city" : "HOT SPRINGS", "loc" : [ -79.871662, 37.963784 ], "pop" : 2506, "state" : "VA" }
+{ "_id" : "24450", "city" : "LEXINGTON", "loc" : [ -79.458111, 37.788463 ], "pop" : 14306, "state" : "VA" }
+{ "_id" : "24458", "city" : "MC DOWELL", "loc" : [ -79.49879799999999, 38.326588 ], "pop" : 353, "state" : "VA" }
+{ "_id" : "24459", "city" : "MIDDLEBROOK", "loc" : [ -79.281165, 38.024158 ], "pop" : 527, "state" : "VA" }
+{ "_id" : "24460", "city" : "MILLBORO SPRING", "loc" : [ -79.640649, 38.005795 ], "pop" : 1586, "state" : "VA" }
+{ "_id" : "24464", "city" : "MONTEBELLO", "loc" : [ -79.06107900000001, 37.839931 ], "pop" : 579, "state" : "VA" }
+{ "_id" : "24465", "city" : "MONTEREY", "loc" : [ -79.59407, 38.405821 ], "pop" : 1335, "state" : "VA" }
+{ "_id" : "24467", "city" : "MOUNT SIDNEY", "loc" : [ -78.97296, 38.261185 ], "pop" : 1787, "state" : "VA" }
+{ "_id" : "24468", "city" : "MUSTOE", "loc" : [ -79.659137, 38.286216 ], "pop" : 202, "state" : "VA" }
+{ "_id" : "24471", "city" : "PORT REPUBLIC", "loc" : [ -78.810388, 38.317167 ], "pop" : 1196, "state" : "VA" }
+{ "_id" : "24472", "city" : "RAPHINE", "loc" : [ -79.221903, 37.937353 ], "pop" : 2238, "state" : "VA" }
+{ "_id" : "24473", "city" : "ROCKBRIDGE BATHS", "loc" : [ -79.387421, 37.896458 ], "pop" : 677, "state" : "VA" }
+{ "_id" : "24475", "city" : "SPOTTSWOOD", "loc" : [ -79.221141, 37.968418 ], "pop" : 393, "state" : "VA" }
+{ "_id" : "24477", "city" : "STUARTS DRAFT", "loc" : [ -79.029821, 38.014423 ], "pop" : 5317, "state" : "VA" }
+{ "_id" : "24479", "city" : "SWOOPE", "loc" : [ -79.187281, 38.159117 ], "pop" : 1477, "state" : "VA" }
+{ "_id" : "24482", "city" : "VERONA", "loc" : [ -79.005872, 38.203726 ], "pop" : 4491, "state" : "VA" }
+{ "_id" : "24483", "city" : "VESUVIUS", "loc" : [ -79.21348500000001, 37.83777 ], "pop" : 548, "state" : "VA" }
+{ "_id" : "24484", "city" : "BOLAR", "loc" : [ -79.80779200000001, 38.085119 ], "pop" : 940, "state" : "VA" }
+{ "_id" : "24485", "city" : "WEST AUGUSTA", "loc" : [ -79.320139, 38.274397 ], "pop" : 350, "state" : "VA" }
+{ "_id" : "24486", "city" : "WEYERS CAVE", "loc" : [ -78.92345400000001, 38.293145 ], "pop" : 2190, "state" : "VA" }
+{ "_id" : "24487", "city" : "BURNSVILLE", "loc" : [ -79.65060699999999, 38.177907 ], "pop" : 170, "state" : "VA" }
+{ "_id" : "24501", "city" : "LYNCHBURG", "loc" : [ -79.171464, 37.386228 ], "pop" : 27264, "state" : "VA" }
+{ "_id" : "24502", "city" : "TIMBERLAKE", "loc" : [ -79.211783, 37.359635 ], "pop" : 28755, "state" : "VA" }
+{ "_id" : "24503", "city" : "LYNCHBURG", "loc" : [ -79.204982, 37.437646 ], "pop" : 17816, "state" : "VA" }
+{ "_id" : "24504", "city" : "LYNCHBURG", "loc" : [ -79.12142, 37.390422 ], "pop" : 10889, "state" : "VA" }
+{ "_id" : "24517", "city" : "ALTAVISTA", "loc" : [ -79.291145, 37.122162 ], "pop" : 4043, "state" : "VA" }
+{ "_id" : "24520", "city" : "ALTON", "loc" : [ -79.02023699999999, 36.589352 ], "pop" : 2557, "state" : "VA" }
+{ "_id" : "24521", "city" : "AMHERST", "loc" : [ -79.050572, 37.602677 ], "pop" : 7343, "state" : "VA" }
+{ "_id" : "24522", "city" : "APPOMATTOX", "loc" : [ -78.822445, 37.352951 ], "pop" : 8904, "state" : "VA" }
+{ "_id" : "24523", "city" : "BEDFORD", "loc" : [ -79.53310999999999, 37.315345 ], "pop" : 16245, "state" : "VA" }
+{ "_id" : "24526", "city" : "BIG ISLAND", "loc" : [ -79.382706, 37.530556 ], "pop" : 1313, "state" : "VA" }
+{ "_id" : "24527", "city" : "BLAIRS", "loc" : [ -79.37886899999999, 36.667408 ], "pop" : 5007, "state" : "VA" }
+{ "_id" : "24528", "city" : "BROOKNEAL", "loc" : [ -78.922679, 37.082663 ], "pop" : 4364, "state" : "VA" }
+{ "_id" : "24529", "city" : "BUFFALO JUNCTION", "loc" : [ -78.60926600000001, 36.61676 ], "pop" : 3300, "state" : "VA" }
+{ "_id" : "24530", "city" : "CALLANDS", "loc" : [ -79.62877899999999, 36.764748 ], "pop" : 2143, "state" : "VA" }
+{ "_id" : "24531", "city" : "CHATHAM", "loc" : [ -79.429659, 36.83099 ], "pop" : 7825, "state" : "VA" }
+{ "_id" : "24534", "city" : "CLOVER", "loc" : [ -78.78618, 36.863695 ], "pop" : 1516, "state" : "VA" }
+{ "_id" : "24536", "city" : "COLEMAN FALLS", "loc" : [ -79.315757, 37.488659 ], "pop" : 286, "state" : "VA" }
+{ "_id" : "24538", "city" : "CONCORD", "loc" : [ -78.98035299999999, 37.336953 ], "pop" : 3845, "state" : "VA" }
+{ "_id" : "24539", "city" : "CRYSTAL HILL", "loc" : [ -78.970634, 36.873217 ], "pop" : 280, "state" : "VA" }
+{ "_id" : "24540", "city" : "DANVILLE", "loc" : [ -79.412441, 36.621789 ], "pop" : 32061, "state" : "VA" }
+{ "_id" : "24541", "city" : "DANVILLE", "loc" : [ -79.441112, 36.577937 ], "pop" : 33751, "state" : "VA" }
+{ "_id" : "24549", "city" : "DRY FORK", "loc" : [ -79.457966, 36.743008 ], "pop" : 1989, "state" : "VA" }
+{ "_id" : "24550", "city" : "EVINGTON", "loc" : [ -79.231723, 37.261049 ], "pop" : 4961, "state" : "VA" }
+{ "_id" : "24551", "city" : "FOREST", "loc" : [ -79.279116, 37.337878 ], "pop" : 12905, "state" : "VA" }
+{ "_id" : "24553", "city" : "GLADSTONE", "loc" : [ -78.850838, 37.547252 ], "pop" : 2025, "state" : "VA" }
+{ "_id" : "24554", "city" : "GLADYS", "loc" : [ -79.104794, 37.138581 ], "pop" : 3511, "state" : "VA" }
+{ "_id" : "24555", "city" : "GLASGOW", "loc" : [ -79.45898, 37.643 ], "pop" : 1604, "state" : "VA" }
+{ "_id" : "24556", "city" : "GOODE", "loc" : [ -79.381277, 37.348098 ], "pop" : 2516, "state" : "VA" }
+{ "_id" : "24557", "city" : "GRETNA", "loc" : [ -79.338874, 36.969515 ], "pop" : 8304, "state" : "VA" }
+{ "_id" : "24558", "city" : "HALIFAX", "loc" : [ -78.94149400000001, 36.762571 ], "pop" : 7127, "state" : "VA" }
+{ "_id" : "24562", "city" : "HOWARDSVILLE", "loc" : [ -78.58235500000001, 37.765891 ], "pop" : 21, "state" : "VA" }
+{ "_id" : "24563", "city" : "HURT", "loc" : [ -79.299995, 37.079787 ], "pop" : 5283, "state" : "VA" }
+{ "_id" : "24565", "city" : "JAVA", "loc" : [ -79.187034, 36.858582 ], "pop" : 1111, "state" : "VA" }
+{ "_id" : "24566", "city" : "KEELING", "loc" : [ -79.278284, 36.715577 ], "pop" : 2651, "state" : "VA" }
+{ "_id" : "24569", "city" : "LONG ISLAND", "loc" : [ -79.121933, 37.064374 ], "pop" : 1308, "state" : "VA" }
+{ "_id" : "24570", "city" : "LOWRY", "loc" : [ -79.45559900000001, 37.33361 ], "pop" : 1342, "state" : "VA" }
+{ "_id" : "24571", "city" : "LYNCH STATION", "loc" : [ -79.329716, 37.152826 ], "pop" : 2819, "state" : "VA" }
+{ "_id" : "24572", "city" : "MADISON HEIGHTS", "loc" : [ -79.11408900000001, 37.453102 ], "pop" : 15389, "state" : "VA" }
+{ "_id" : "24574", "city" : "MONROE", "loc" : [ -79.17034, 37.541366 ], "pop" : 5050, "state" : "VA" }
+{ "_id" : "24577", "city" : "LENNIG", "loc" : [ -78.989766, 36.944179 ], "pop" : 5018, "state" : "VA" }
+{ "_id" : "24578", "city" : "NATURAL BRIDGE", "loc" : [ -79.533045, 37.660625 ], "pop" : 1236, "state" : "VA" }
+{ "_id" : "24579", "city" : "NATURAL BRIDGE S", "loc" : [ -79.503905, 37.595667 ], "pop" : 1419, "state" : "VA" }
+{ "_id" : "24580", "city" : "NELSON", "loc" : [ -78.670959, 36.558558 ], "pop" : 131, "state" : "VA" }
+{ "_id" : "24586", "city" : "RINGGOLD", "loc" : [ -79.298835, 36.603483 ], "pop" : 4728, "state" : "VA" }
+{ "_id" : "24588", "city" : "RUSTBURG", "loc" : [ -79.12150699999999, 37.25454 ], "pop" : 4723, "state" : "VA" }
+{ "_id" : "24589", "city" : "SCOTTSBURG", "loc" : [ -78.786601, 36.786194 ], "pop" : 2965, "state" : "VA" }
+{ "_id" : "24590", "city" : "SCOTTSVILLE", "loc" : [ -78.47398099999999, 37.804937 ], "pop" : 5769, "state" : "VA" }
+{ "_id" : "24592", "city" : "SOUTH BOSTON", "loc" : [ -78.918829, 36.696335 ], "pop" : 12624, "state" : "VA" }
+{ "_id" : "24593", "city" : "SPOUT SPRING", "loc" : [ -78.90588700000001, 37.364345 ], "pop" : 872, "state" : "VA" }
+{ "_id" : "24594", "city" : "SUTHERLIN", "loc" : [ -79.19495000000001, 36.625831 ], "pop" : 1018, "state" : "VA" }
+{ "_id" : "24597", "city" : "INGRAM", "loc" : [ -79.110874, 36.786684 ], "pop" : 1648, "state" : "VA" }
+{ "_id" : "24598", "city" : "VIRGILINA", "loc" : [ -78.760516, 36.606231 ], "pop" : 2435, "state" : "VA" }
+{ "_id" : "24599", "city" : "WINGINA", "loc" : [ -78.755709, 37.641473 ], "pop" : 833, "state" : "VA" }
+{ "_id" : "24602", "city" : "BANDY", "loc" : [ -81.6508, 37.166112 ], "pop" : 2348, "state" : "VA" }
+{ "_id" : "24603", "city" : "CONAWAY", "loc" : [ -82.22459600000001, 37.318638 ], "pop" : 1151, "state" : "VA" }
+{ "_id" : "24605", "city" : "BLUEFIELD", "loc" : [ -81.325114, 37.249512 ], "pop" : 10931, "state" : "VA" }
+{ "_id" : "24609", "city" : "CEDAR BLUFF", "loc" : [ -81.76678800000001, 37.079076 ], "pop" : 3486, "state" : "VA" }
+{ "_id" : "24613", "city" : "FALLS MILLS", "loc" : [ -81.318234, 37.271023 ], "pop" : 960, "state" : "VA" }
+{ "_id" : "24614", "city" : "GRUNDY", "loc" : [ -82.106077, 37.296678 ], "pop" : 10245, "state" : "VA" }
+{ "_id" : "24620", "city" : "HURLEY", "loc" : [ -82.02616399999999, 37.401741 ], "pop" : 5296, "state" : "VA" }
+{ "_id" : "24622", "city" : "JEWELL VALLEY", "loc" : [ -81.810654, 37.222372 ], "pop" : 1213, "state" : "VA" }
+{ "_id" : "24627", "city" : "MAVISDALE", "loc" : [ -82.221599, 37.200817 ], "pop" : 141, "state" : "VA" }
+{ "_id" : "24630", "city" : "TIPTOP", "loc" : [ -81.525256, 37.152447 ], "pop" : 6771, "state" : "VA" }
+{ "_id" : "24631", "city" : "PATTERSON", "loc" : [ -81.99157700000001, 37.184074 ], "pop" : 1356, "state" : "VA" }
+{ "_id" : "24634", "city" : "PILGRIMS KNOB", "loc" : [ -81.911896, 37.298944 ], "pop" : 766, "state" : "VA" }
+{ "_id" : "24637", "city" : "POUNDING MILL", "loc" : [ -81.730052, 37.059584 ], "pop" : 3942, "state" : "VA" }
+{ "_id" : "24639", "city" : "RAVEN", "loc" : [ -81.889557, 37.148056 ], "pop" : 3441, "state" : "VA" }
+{ "_id" : "24641", "city" : "RICHLANDS", "loc" : [ -81.812286, 37.094051 ], "pop" : 8026, "state" : "VA" }
+{ "_id" : "24646", "city" : "ROWE", "loc" : [ -82.02738100000001, 37.127593 ], "pop" : 1531, "state" : "VA" }
+{ "_id" : "24649", "city" : "SWORDS CREEK", "loc" : [ -81.908385, 37.073792 ], "pop" : 2756, "state" : "VA" }
+{ "_id" : "24651", "city" : "TAZEWELL", "loc" : [ -81.50997599999999, 37.107773 ], "pop" : 7023, "state" : "VA" }
+{ "_id" : "24656", "city" : "VANSANT", "loc" : [ -82.12771499999999, 37.173811 ], "pop" : 4724, "state" : "VA" }
+{ "_id" : "24657", "city" : "WHITEWOOD", "loc" : [ -81.890361, 37.264409 ], "pop" : 731, "state" : "VA" }
+{ "_id" : "24701", "city" : "BLUEWELL", "loc" : [ -81.229023, 37.279788 ], "pop" : 22561, "state" : "WV" }
+{ "_id" : "24712", "city" : "ATHENS", "loc" : [ -80.997362, 37.432298 ], "pop" : 2863, "state" : "WV" }
+{ "_id" : "24714", "city" : "BEESON", "loc" : [ -81.206215, 37.490894 ], "pop" : 140, "state" : "WV" }
+{ "_id" : "24715", "city" : "BRAMWELL", "loc" : [ -81.32556, 37.332114 ], "pop" : 762, "state" : "WV" }
+{ "_id" : "24726", "city" : "HERNDON", "loc" : [ -81.346777, 37.526431 ], "pop" : 2220, "state" : "WV" }
+{ "_id" : "24731", "city" : "KEGLEY", "loc" : [ -81.140117, 37.408384 ], "pop" : 259, "state" : "WV" }
+{ "_id" : "24733", "city" : "LASHMEET", "loc" : [ -81.21384500000001, 37.441997 ], "pop" : 730, "state" : "WV" }
+{ "_id" : "24736", "city" : "DOTT", "loc" : [ -81.268017, 37.441778 ], "pop" : 1365, "state" : "WV" }
+{ "_id" : "24740", "city" : "ELGOOD", "loc" : [ -81.086386, 37.366817 ], "pop" : 29167, "state" : "WV" }
+{ "_id" : "24747", "city" : "DUHRING", "loc" : [ -81.218766, 37.38889 ], "pop" : 5336, "state" : "WV" }
+{ "_id" : "24801", "city" : "WELCH", "loc" : [ -81.534412, 37.400032 ], "pop" : 11143, "state" : "WV" }
+{ "_id" : "24810", "city" : "MC DOWELL", "loc" : [ -81.387601, 37.414348 ], "pop" : 1968, "state" : "WV" }
+{ "_id" : "24818", "city" : "BRENTON", "loc" : [ -81.649502, 37.584362 ], "pop" : 1908, "state" : "WV" }
+{ "_id" : "24819", "city" : "VALLSCREEK", "loc" : [ -81.69552, 37.295548 ], "pop" : 4476, "state" : "WV" }
+{ "_id" : "24822", "city" : "CLEAR FORK", "loc" : [ -81.689268, 37.646301 ], "pop" : 1173, "state" : "WV" }
+{ "_id" : "24823", "city" : "COAL MOUNTAIN", "loc" : [ -81.70786200000001, 37.688486 ], "pop" : 850, "state" : "WV" }
+{ "_id" : "24827", "city" : "CYCLONE", "loc" : [ -81.650458, 37.74466 ], "pop" : 1328, "state" : "WV" }
+{ "_id" : "24828", "city" : "ASCO", "loc" : [ -81.667889, 37.468339 ], "pop" : 2765, "state" : "WV" }
+{ "_id" : "24834", "city" : "FANROCK", "loc" : [ -81.623631, 37.562721 ], "pop" : 120, "state" : "WV" }
+{ "_id" : "24839", "city" : "HANOVER", "loc" : [ -81.81361699999999, 37.563029 ], "pop" : 1523, "state" : "WV" }
+{ "_id" : "24844", "city" : "IAEGER", "loc" : [ -81.811992, 37.449878 ], "pop" : 5720, "state" : "WV" }
+{ "_id" : "24849", "city" : "JESSE", "loc" : [ -81.562831, 37.660844 ], "pop" : 585, "state" : "WV" }
+{ "_id" : "24850", "city" : "JOLO", "loc" : [ -81.831602, 37.332431 ], "pop" : 3086, "state" : "WV" }
+{ "_id" : "24859", "city" : "MARIANNA", "loc" : [ -81.576052, 37.611425 ], "pop" : 1008, "state" : "WV" }
+{ "_id" : "24860", "city" : "MATHENY", "loc" : [ -81.59571099999999, 37.661956 ], "pop" : 1139, "state" : "WV" }
+{ "_id" : "24862", "city" : "MOHAWK", "loc" : [ -81.914174, 37.487926 ], "pop" : 1705, "state" : "WV" }
+{ "_id" : "24868", "city" : "ALGOMA", "loc" : [ -81.41583900000001, 37.395262 ], "pop" : 2158, "state" : "WV" }
+{ "_id" : "24869", "city" : "NORTH SPRING", "loc" : [ -81.797276, 37.517954 ], "pop" : 226, "state" : "WV" }
+{ "_id" : "24870", "city" : "OCEANA", "loc" : [ -81.62156400000001, 37.703874 ], "pop" : 4243, "state" : "WV" }
+{ "_id" : "24873", "city" : "PAYNESVILLE", "loc" : [ -81.68449, 37.365273 ], "pop" : 1895, "state" : "WV" }
+{ "_id" : "24874", "city" : "PINEVILLE", "loc" : [ -81.533642, 37.584022 ], "pop" : 4142, "state" : "WV" }
+{ "_id" : "24882", "city" : "SIMON", "loc" : [ -81.758566, 37.619708 ], "pop" : 782, "state" : "WV" }
+{ "_id" : "24884", "city" : "SQUIRE", "loc" : [ -81.580478, 37.237019 ], "pop" : 995, "state" : "WV" }
+{ "_id" : "24901", "city" : "LEWISBURG", "loc" : [ -80.440669, 37.808253 ], "pop" : 8645, "state" : "WV" }
+{ "_id" : "24910", "city" : "DAWSON", "loc" : [ -80.671306, 37.730148 ], "pop" : 4475, "state" : "WV" }
+{ "_id" : "24915", "city" : "ARBOVALE", "loc" : [ -79.793403, 38.454575 ], "pop" : 528, "state" : "WV" }
+{ "_id" : "24916", "city" : "ASBURY", "loc" : [ -80.565319, 37.848766 ], "pop" : 598, "state" : "WV" }
+{ "_id" : "24917", "city" : "AUTO", "loc" : [ -80.117105, 37.981697 ], "pop" : 379, "state" : "WV" }
+{ "_id" : "24918", "city" : "BALLARD", "loc" : [ -80.76139000000001, 37.49803 ], "pop" : 1194, "state" : "WV" }
+{ "_id" : "24919", "city" : "BALLENGEE", "loc" : [ -80.74033900000001, 37.616931 ], "pop" : 184, "state" : "WV" }
+{ "_id" : "24920", "city" : "BARTOW", "loc" : [ -79.795242, 38.551266 ], "pop" : 748, "state" : "WV" }
+{ "_id" : "24923", "city" : "BOZOO", "loc" : [ -80.814954, 37.457015 ], "pop" : 651, "state" : "WV" }
+{ "_id" : "24924", "city" : "BUCKEYE", "loc" : [ -80.139342, 38.181506 ], "pop" : 550, "state" : "WV" }
+{ "_id" : "24925", "city" : "CALDWELL", "loc" : [ -80.377298, 37.773488 ], "pop" : 312, "state" : "WV" }
+{ "_id" : "24927", "city" : "STONY BOTTOM", "loc" : [ -79.885278, 38.433659 ], "pop" : 844, "state" : "WV" }
+{ "_id" : "24928", "city" : "CLINTONVILLE", "loc" : [ -80.626192, 37.906141 ], "pop" : 373, "state" : "WV" }
+{ "_id" : "24931", "city" : "CRAWLEY", "loc" : [ -80.6309, 37.939676 ], "pop" : 286, "state" : "WV" }
+{ "_id" : "24934", "city" : "DUNMORE", "loc" : [ -79.855557, 38.363605 ], "pop" : 265, "state" : "WV" }
+{ "_id" : "24935", "city" : "INDIAN MILLS", "loc" : [ -80.81492299999999, 37.56005 ], "pop" : 368, "state" : "WV" }
+{ "_id" : "24936", "city" : "FORT SPRING", "loc" : [ -80.566723, 37.745661 ], "pop" : 397, "state" : "WV" }
+{ "_id" : "24938", "city" : "ANTHONY", "loc" : [ -80.36469200000001, 37.90361 ], "pop" : 814, "state" : "WV" }
+{ "_id" : "24941", "city" : "GAP MILLS", "loc" : [ -80.390497, 37.527978 ], "pop" : 289, "state" : "WV" }
+{ "_id" : "24942", "city" : "GLACE", "loc" : [ -80.37471600000001, 37.609381 ], "pop" : 399, "state" : "WV" }
+{ "_id" : "24943", "city" : "GRASSY MEADOWS", "loc" : [ -80.73023999999999, 37.842757 ], "pop" : 185, "state" : "WV" }
+{ "_id" : "24944", "city" : "GREEN BANK", "loc" : [ -79.801535, 38.409664 ], "pop" : 365, "state" : "WV" }
+{ "_id" : "24945", "city" : "GREENVILLE", "loc" : [ -80.67612800000001, 37.521184 ], "pop" : 1139, "state" : "WV" }
+{ "_id" : "24946", "city" : "DROOP", "loc" : [ -80.244578, 38.125942 ], "pop" : 1393, "state" : "WV" }
+{ "_id" : "24950", "city" : "KIEFFER", "loc" : [ -80.59022, 37.942998 ], "pop" : 2, "state" : "WV" }
+{ "_id" : "24951", "city" : "LINDSIDE", "loc" : [ -80.62027999999999, 37.481651 ], "pop" : 810, "state" : "WV" }
+{ "_id" : "24954", "city" : "MINNEHAHA SPRING", "loc" : [ -80.060884, 38.229303 ], "pop" : 3713, "state" : "WV" }
+{ "_id" : "24957", "city" : "MAXWELTON", "loc" : [ -80.427492, 37.900465 ], "pop" : 139, "state" : "WV" }
+{ "_id" : "24958", "city" : "MEADOW BLUFF", "loc" : [ -80.728162, 37.89587 ], "pop" : 233, "state" : "WV" }
+{ "_id" : "24962", "city" : "PENCE SPRINGS", "loc" : [ -80.709234, 37.676694 ], "pop" : 310, "state" : "WV" }
+{ "_id" : "24963", "city" : "PETERSTOWN", "loc" : [ -80.76860499999999, 37.414709 ], "pop" : 3117, "state" : "WV" }
+{ "_id" : "24966", "city" : "RENICK", "loc" : [ -80.36529400000001, 37.992168 ], "pop" : 1530, "state" : "WV" }
+{ "_id" : "24970", "city" : "RONCEVERTE", "loc" : [ -80.462583, 37.741758 ], "pop" : 4167, "state" : "WV" }
+{ "_id" : "24974", "city" : "SECONDCREEK", "loc" : [ -80.41807900000001, 37.660246 ], "pop" : 452, "state" : "WV" }
+{ "_id" : "24976", "city" : "PICKAWAY", "loc" : [ -80.51690499999999, 37.662078 ], "pop" : 971, "state" : "WV" }
+{ "_id" : "24977", "city" : "SMOOT", "loc" : [ -80.668038, 37.877166 ], "pop" : 634, "state" : "WV" }
+{ "_id" : "24980", "city" : "SWEET SPRINGS", "loc" : [ -80.298959, 37.611159 ], "pop" : 571, "state" : "WV" }
+{ "_id" : "24981", "city" : "TALCOTT", "loc" : [ -80.746143, 37.649079 ], "pop" : 511, "state" : "WV" }
+{ "_id" : "24983", "city" : "UNION", "loc" : [ -80.524767, 37.580175 ], "pop" : 1737, "state" : "WV" }
+{ "_id" : "24984", "city" : "WAITEVILLE", "loc" : [ -80.463447, 37.464514 ], "pop" : 62, "state" : "WV" }
+{ "_id" : "24985", "city" : "WAYSIDE", "loc" : [ -80.745806, 37.593657 ], "pop" : 421, "state" : "WV" }
+{ "_id" : "24986", "city" : "NEOLA", "loc" : [ -80.27464000000001, 37.814618 ], "pop" : 5096, "state" : "WV" }
+{ "_id" : "24991", "city" : "TROUT", "loc" : [ -80.517321, 37.94421 ], "pop" : 998, "state" : "WV" }
+{ "_id" : "24993", "city" : "WOLFCREEK", "loc" : [ -80.611254, 37.618788 ], "pop" : 249, "state" : "WV" }
+{ "_id" : "25003", "city" : "ALUM CREEK", "loc" : [ -81.786258, 38.285814 ], "pop" : 1450, "state" : "WV" }
+{ "_id" : "25004", "city" : "AMEAGLE", "loc" : [ -81.406507, 37.964068 ], "pop" : 623, "state" : "WV" }
+{ "_id" : "25005", "city" : "AMMA", "loc" : [ -81.253182, 38.545518 ], "pop" : 414, "state" : "WV" }
+{ "_id" : "25007", "city" : "ARNETT", "loc" : [ -81.435484, 37.850214 ], "pop" : 2073, "state" : "WV" }
+{ "_id" : "25008", "city" : "ARTIE", "loc" : [ -81.378772, 37.918139 ], "pop" : 407, "state" : "WV" }
+{ "_id" : "25009", "city" : "ASHFORD", "loc" : [ -81.711324, 38.182291 ], "pop" : 1329, "state" : "WV" }
+{ "_id" : "25010", "city" : "BALD KNOB", "loc" : [ -81.62294300000001, 37.844023 ], "pop" : 666, "state" : "WV" }
+{ "_id" : "25013", "city" : "BARRETT", "loc" : [ -81.64831, 37.880201 ], "pop" : 50, "state" : "WV" }
+{ "_id" : "25015", "city" : "DIAMOND", "loc" : [ -81.50581200000001, 38.225381 ], "pop" : 7120, "state" : "WV" }
+{ "_id" : "25018", "city" : "BENTREE", "loc" : [ -81.21565, 38.297088 ], "pop" : 377, "state" : "WV" }
+{ "_id" : "25019", "city" : "FOLA", "loc" : [ -81.106838, 38.365947 ], "pop" : 793, "state" : "WV" }
+{ "_id" : "25021", "city" : "BIM", "loc" : [ -81.688047, 37.893437 ], "pop" : 1061, "state" : "WV" }
+{ "_id" : "25024", "city" : "BLOOMINGROSE", "loc" : [ -81.636737, 38.141189 ], "pop" : 191, "state" : "WV" }
+{ "_id" : "25025", "city" : "BLOUNT", "loc" : [ -81.40519399999999, 38.312116 ], "pop" : 583, "state" : "WV" }
+{ "_id" : "25028", "city" : "BOB WHITE", "loc" : [ -81.720884, 37.958711 ], "pop" : 570, "state" : "WV" }
+{ "_id" : "25030", "city" : "BOMONT", "loc" : [ -81.21999, 38.407295 ], "pop" : 129, "state" : "WV" }
+{ "_id" : "25033", "city" : "BUFFALO", "loc" : [ -81.94997100000001, 38.60924 ], "pop" : 1898, "state" : "WV" }
+{ "_id" : "25034", "city" : "BURNWELL", "loc" : [ -81.37647, 38.053014 ], "pop" : 23, "state" : "WV" }
+{ "_id" : "25035", "city" : "CABIN CREEK", "loc" : [ -81.515258, 38.185795 ], "pop" : 1289, "state" : "WV" }
+{ "_id" : "25039", "city" : "CEDAR GROVE", "loc" : [ -81.406711, 38.213286 ], "pop" : 3463, "state" : "WV" }
+{ "_id" : "25043", "city" : "CLAY", "loc" : [ -81.069588, 38.476354 ], "pop" : 2881, "state" : "WV" }
+{ "_id" : "25044", "city" : "CLEAR CREEK", "loc" : [ -81.320866, 37.89158 ], "pop" : 262, "state" : "WV" }
+{ "_id" : "25045", "city" : "QUICK", "loc" : [ -81.356039, 38.477687 ], "pop" : 5864, "state" : "WV" }
+{ "_id" : "25046", "city" : "CLIO", "loc" : [ -81.307188, 38.572686 ], "pop" : 458, "state" : "WV" }
+{ "_id" : "25047", "city" : "CLOTHIER", "loc" : [ -81.988142, 37.79333 ], "pop" : 1379, "state" : "WV" }
+{ "_id" : "25048", "city" : "COLCORD", "loc" : [ -81.443699, 37.949166 ], "pop" : 405, "state" : "WV" }
+{ "_id" : "25049", "city" : "COMFORT", "loc" : [ -81.596177, 38.137191 ], "pop" : 889, "state" : "WV" }
+{ "_id" : "25051", "city" : "COSTA", "loc" : [ -81.708015, 38.164693 ], "pop" : 134, "state" : "WV" }
+{ "_id" : "25053", "city" : "DANVILLE", "loc" : [ -81.85422699999999, 38.03356 ], "pop" : 4129, "state" : "WV" }
+{ "_id" : "25059", "city" : "DIXIE", "loc" : [ -81.186249, 38.26631 ], "pop" : 795, "state" : "WV" }
+{ "_id" : "25060", "city" : "DOROTHY", "loc" : [ -81.496842, 37.96219 ], "pop" : 524, "state" : "WV" }
+{ "_id" : "25062", "city" : "DRY CREEK", "loc" : [ -81.481398, 37.860686 ], "pop" : 209, "state" : "WV" }
+{ "_id" : "25063", "city" : "DUCK", "loc" : [ -80.976416, 38.564652 ], "pop" : 679, "state" : "WV" }
+{ "_id" : "25064", "city" : "DUNBAR", "loc" : [ -81.742467, 38.368271 ], "pop" : 11543, "state" : "WV" }
+{ "_id" : "25071", "city" : "FRAME", "loc" : [ -81.481739, 38.432317 ], "pop" : 10333, "state" : "WV" }
+{ "_id" : "25079", "city" : "FALLING ROCK", "loc" : [ -81.38087400000001, 38.475579 ], "pop" : 353, "state" : "WV" }
+{ "_id" : "25081", "city" : "FOSTER", "loc" : [ -81.76587600000001, 38.090819 ], "pop" : 1584, "state" : "WV" }
+{ "_id" : "25082", "city" : "FRAZIERS BOTTOM", "loc" : [ -82.01106799999999, 38.551678 ], "pop" : 911, "state" : "WV" }
+{ "_id" : "25083", "city" : "WHITTAKER", "loc" : [ -81.386231, 38.189406 ], "pop" : 2542, "state" : "WV" }
+{ "_id" : "25085", "city" : "GAULEY BRIDGE", "loc" : [ -81.19596, 38.168899 ], "pop" : 826, "state" : "WV" }
+{ "_id" : "25088", "city" : "GLEN", "loc" : [ -81.223401, 38.368989 ], "pop" : 74, "state" : "WV" }
+{ "_id" : "25093", "city" : "GORDON", "loc" : [ -81.67131999999999, 37.978191 ], "pop" : 251, "state" : "WV" }
+{ "_id" : "25103", "city" : "HANSFORD", "loc" : [ -81.395026, 38.127158 ], "pop" : 165, "state" : "WV" }
+{ "_id" : "25105", "city" : "HARRISON", "loc" : [ -80.916068, 38.498979 ], "pop" : 163, "state" : "WV" }
+{ "_id" : "25106", "city" : "HENDERSON", "loc" : [ -82.136381, 38.826512 ], "pop" : 747, "state" : "WV" }
+{ "_id" : "25107", "city" : "HERNSHAW", "loc" : [ -81.61298600000001, 38.194212 ], "pop" : 745, "state" : "WV" }
+{ "_id" : "25108", "city" : "HEWETT", "loc" : [ -81.850919, 37.958097 ], "pop" : 625, "state" : "WV" }
+{ "_id" : "25111", "city" : "INDORE", "loc" : [ -81.157495, 38.339672 ], "pop" : 1173, "state" : "WV" }
+{ "_id" : "25113", "city" : "BIG OTTER", "loc" : [ -81.033506, 38.530476 ], "pop" : 145, "state" : "WV" }
+{ "_id" : "25114", "city" : "RAMAGE", "loc" : [ -81.80030499999999, 37.957023 ], "pop" : 593, "state" : "WV" }
+{ "_id" : "25115", "city" : "KANAWHA FALLS", "loc" : [ -81.162753, 38.107932 ], "pop" : 98, "state" : "WV" }
+{ "_id" : "25118", "city" : "KIMBERLY", "loc" : [ -81.321721, 38.124928 ], "pop" : 108, "state" : "WV" }
+{ "_id" : "25119", "city" : "KINCAID", "loc" : [ -81.26897, 38.032065 ], "pop" : 94, "state" : "WV" }
+{ "_id" : "25121", "city" : "LAKE", "loc" : [ -81.95115199999999, 37.946191 ], "pop" : 3384, "state" : "WV" }
+{ "_id" : "25122", "city" : "CARBON", "loc" : [ -81.451228, 38.098249 ], "pop" : 2581, "state" : "WV" }
+{ "_id" : "25123", "city" : "ARBUCKLE", "loc" : [ -81.909244, 38.753046 ], "pop" : 2325, "state" : "WV" }
+{ "_id" : "25124", "city" : "LIBERTY", "loc" : [ -81.767813, 38.619978 ], "pop" : 1050, "state" : "WV" }
+{ "_id" : "25125", "city" : "LIZEMORES", "loc" : [ -81.16325500000001, 38.336609 ], "pop" : 84, "state" : "WV" }
+{ "_id" : "25130", "city" : "MADISON", "loc" : [ -81.793757, 38.044426 ], "pop" : 4476, "state" : "WV" }
+{ "_id" : "25132", "city" : "MAMMOTH", "loc" : [ -81.350893, 38.258319 ], "pop" : 486, "state" : "WV" }
+{ "_id" : "25133", "city" : "MAYSEL", "loc" : [ -81.122653, 38.493924 ], "pop" : 223, "state" : "WV" }
+{ "_id" : "25136", "city" : "MONTGOMERY", "loc" : [ -81.28135399999999, 38.141232 ], "pop" : 10392, "state" : "WV" }
+{ "_id" : "25139", "city" : "MOUNT CARBON", "loc" : [ -81.33337299999999, 38.160097 ], "pop" : 0, "state" : "WV" }
+{ "_id" : "25140", "city" : "NAOMA", "loc" : [ -81.521372, 37.915381 ], "pop" : 864, "state" : "WV" }
+{ "_id" : "25141", "city" : "NEBO", "loc" : [ -81.025657, 38.627069 ], "pop" : 222, "state" : "WV" }
+{ "_id" : "25142", "city" : "NELLIS", "loc" : [ -81.73990499999999, 38.152066 ], "pop" : 104, "state" : "WV" }
+{ "_id" : "25143", "city" : "NITRO", "loc" : [ -81.829311, 38.419323 ], "pop" : 9525, "state" : "WV" }
+{ "_id" : "25148", "city" : "ORGAS", "loc" : [ -81.57383, 38.073646 ], "pop" : 840, "state" : "WV" }
+{ "_id" : "25150", "city" : "OVAPA", "loc" : [ -81.14846, 38.523398 ], "pop" : 525, "state" : "WV" }
+{ "_id" : "25154", "city" : "PEYTONA", "loc" : [ -81.701836, 38.124952 ], "pop" : 754, "state" : "WV" }
+{ "_id" : "25158", "city" : "PLINY", "loc" : [ -82.015494, 38.614206 ], "pop" : 352, "state" : "WV" }
+{ "_id" : "25159", "city" : "LANHAM", "loc" : [ -81.80511, 38.488297 ], "pop" : 5813, "state" : "WV" }
+{ "_id" : "25160", "city" : "POND GAP", "loc" : [ -81.28658, 38.290434 ], "pop" : 394, "state" : "WV" }
+{ "_id" : "25161", "city" : "POWELLTON", "loc" : [ -81.31792299999999, 38.099172 ], "pop" : 1148, "state" : "WV" }
+{ "_id" : "25163", "city" : "WILLIAMS MOUNTAI", "loc" : [ -81.623901, 38.008351 ], "pop" : 684, "state" : "WV" }
+{ "_id" : "25164", "city" : "PIGEON", "loc" : [ -81.226286, 38.472167 ], "pop" : 1064, "state" : "WV" }
+{ "_id" : "25165", "city" : "RACINE", "loc" : [ -81.655742, 38.149524 ], "pop" : 539, "state" : "WV" }
+{ "_id" : "25168", "city" : "RED HOUSE", "loc" : [ -81.90447399999999, 38.546298 ], "pop" : 3472, "state" : "WV" }
+{ "_id" : "25169", "city" : "RIDGEVIEW", "loc" : [ -81.772548, 38.148576 ], "pop" : 793, "state" : "WV" }
+{ "_id" : "25172", "city" : "ROBERTSBURG", "loc" : [ -81.9109, 38.644143 ], "pop" : 590, "state" : "WV" }
+{ "_id" : "25173", "city" : "ROBSON", "loc" : [ -81.248758, 38.097263 ], "pop" : 39, "state" : "WV" }
+{ "_id" : "25174", "city" : "ROCK CREEK", "loc" : [ -81.48367399999999, 37.836673 ], "pop" : 533, "state" : "WV" }
+{ "_id" : "25177", "city" : "SAINT ALBANS", "loc" : [ -81.83046299999999, 38.37743 ], "pop" : 24409, "state" : "WV" }
+{ "_id" : "25180", "city" : "SAXON", "loc" : [ -81.43227899999999, 37.786108 ], "pop" : 154, "state" : "WV" }
+{ "_id" : "25181", "city" : "SETH", "loc" : [ -81.639258, 38.097057 ], "pop" : 1095, "state" : "WV" }
+{ "_id" : "25187", "city" : "SOUTHSIDE", "loc" : [ -81.996596, 38.711994 ], "pop" : 446, "state" : "WV" }
+{ "_id" : "25189", "city" : "STICKNEY", "loc" : [ -81.497001, 37.876844 ], "pop" : 18, "state" : "WV" }
+{ "_id" : "25193", "city" : "SYLVESTER", "loc" : [ -81.54915099999999, 38.009075 ], "pop" : 1020, "state" : "WV" }
+{ "_id" : "25202", "city" : "TORNADO", "loc" : [ -81.847555, 38.335697 ], "pop" : 1500, "state" : "WV" }
+{ "_id" : "25203", "city" : "TURTLE CREEK", "loc" : [ -81.853499, 38.042715 ], "pop" : 669, "state" : "WV" }
+{ "_id" : "25204", "city" : "BANDYTOWN", "loc" : [ -81.635204, 37.921015 ], "pop" : 500, "state" : "WV" }
+{ "_id" : "25206", "city" : "VAN", "loc" : [ -81.702175, 37.971152 ], "pop" : 9, "state" : "WV" }
+{ "_id" : "25209", "city" : "GARRISON", "loc" : [ -81.534013, 37.978677 ], "pop" : 681, "state" : "WV" }
+{ "_id" : "25213", "city" : "WINFIELD", "loc" : [ -81.889965, 38.507178 ], "pop" : 3958, "state" : "WV" }
+{ "_id" : "25214", "city" : "WINIFREDE", "loc" : [ -81.558747, 38.185245 ], "pop" : 126, "state" : "WV" }
+{ "_id" : "25231", "city" : "ADVENT", "loc" : [ -81.572063, 38.623595 ], "pop" : 189, "state" : "WV" }
+{ "_id" : "25234", "city" : "ARNOLDSBURG", "loc" : [ -81.155135, 38.822704 ], "pop" : 1683, "state" : "WV" }
+{ "_id" : "25235", "city" : "FLOE", "loc" : [ -81.090126, 38.671201 ], "pop" : 886, "state" : "WV" }
+{ "_id" : "25239", "city" : "COTTAGEVILLE", "loc" : [ -81.818609, 38.863285 ], "pop" : 1183, "state" : "WV" }
+{ "_id" : "25241", "city" : "EVANS", "loc" : [ -81.790858, 38.811281 ], "pop" : 1296, "state" : "WV" }
+{ "_id" : "25243", "city" : "GANDEEVILLE", "loc" : [ -81.424329, 38.703382 ], "pop" : 715, "state" : "WV" }
+{ "_id" : "25244", "city" : "GAY", "loc" : [ -81.570301, 38.797842 ], "pop" : 1037, "state" : "WV" }
+{ "_id" : "25245", "city" : "GIVEN", "loc" : [ -81.682542, 38.713046 ], "pop" : 994, "state" : "WV" }
+{ "_id" : "25246", "city" : "HARMONY", "loc" : [ -81.50763600000001, 38.692086 ], "pop" : 372, "state" : "WV" }
+{ "_id" : "25248", "city" : "ROMANCE", "loc" : [ -81.651717, 38.623894 ], "pop" : 1880, "state" : "WV" }
+{ "_id" : "25249", "city" : "KENTUCK", "loc" : [ -81.596018, 38.663886 ], "pop" : 718, "state" : "WV" }
+{ "_id" : "25251", "city" : "LEFT HAND", "loc" : [ -81.246675, 38.606288 ], "pop" : 397, "state" : "WV" }
+{ "_id" : "25252", "city" : "DUNCAN", "loc" : [ -81.57245, 38.957552 ], "pop" : 743, "state" : "WV" }
+{ "_id" : "25253", "city" : "LETART", "loc" : [ -81.975129, 38.931079 ], "pop" : 4478, "state" : "WV" }
+{ "_id" : "25255", "city" : "LETTER GAP", "loc" : [ -80.883768, 38.897074 ], "pop" : 217, "state" : "WV" }
+{ "_id" : "25256", "city" : "LINDEN", "loc" : [ -81.229061, 38.698938 ], "pop" : 270, "state" : "WV" }
+{ "_id" : "25258", "city" : "LOCKNEY", "loc" : [ -80.945075, 38.852919 ], "pop" : 89, "state" : "WV" }
+{ "_id" : "25259", "city" : "LOONEYVILLE", "loc" : [ -81.28219, 38.664113 ], "pop" : 600, "state" : "WV" }
+{ "_id" : "25260", "city" : "MASON", "loc" : [ -82.028215, 39.006442 ], "pop" : 2598, "state" : "WV" }
+{ "_id" : "25261", "city" : "MILLSTONE", "loc" : [ -81.08635200000001, 38.86029 ], "pop" : 748, "state" : "WV" }
+{ "_id" : "25262", "city" : "MILLWOOD", "loc" : [ -81.824832, 38.896206 ], "pop" : 1379, "state" : "WV" }
+{ "_id" : "25264", "city" : "MOUNT ALTO", "loc" : [ -81.87837399999999, 38.863937 ], "pop" : 275, "state" : "WV" }
+{ "_id" : "25266", "city" : "ULER", "loc" : [ -81.167579, 38.605219 ], "pop" : 724, "state" : "WV" }
+{ "_id" : "25267", "city" : "NORMANTOWN", "loc" : [ -80.941936, 38.880173 ], "pop" : 183, "state" : "WV" }
+{ "_id" : "25268", "city" : "MINNORA", "loc" : [ -81.09614000000001, 38.735979 ], "pop" : 641, "state" : "WV" }
+{ "_id" : "25270", "city" : "REEDY", "loc" : [ -81.419785, 38.837119 ], "pop" : 3014, "state" : "WV" }
+{ "_id" : "25271", "city" : "RIPLEY", "loc" : [ -81.701987, 38.809042 ], "pop" : 6580, "state" : "WV" }
+{ "_id" : "25272", "city" : "ROCK CASTLE", "loc" : [ -81.767414, 38.708357 ], "pop" : 82, "state" : "WV" }
+{ "_id" : "25274", "city" : "SAND RIDGE", "loc" : [ -81.032372, 38.850721 ], "pop" : 163, "state" : "WV" }
+{ "_id" : "25275", "city" : "SANDYVILLE", "loc" : [ -81.654315, 38.909282 ], "pop" : 1611, "state" : "WV" }
+{ "_id" : "25276", "city" : "SPENCER", "loc" : [ -81.33026, 38.789696 ], "pop" : 6007, "state" : "WV" }
+{ "_id" : "25279", "city" : "STATTS MILLS", "loc" : [ -81.615579, 38.74076 ], "pop" : 368, "state" : "WV" }
+{ "_id" : "25280", "city" : "STUMPTOWN", "loc" : [ -80.970026, 38.831619 ], "pop" : 275, "state" : "WV" }
+{ "_id" : "25281", "city" : "TARIFF", "loc" : [ -81.212361, 38.652707 ], "pop" : 191, "state" : "WV" }
+{ "_id" : "25283", "city" : "VALLEY FORK", "loc" : [ -81.15217699999999, 38.486906 ], "pop" : 530, "state" : "WV" }
+{ "_id" : "25285", "city" : "WALLBACK", "loc" : [ -81.093535, 38.57254 ], "pop" : 181, "state" : "WV" }
+{ "_id" : "25286", "city" : "WALTON", "loc" : [ -81.395757, 38.602264 ], "pop" : 1961, "state" : "WV" }
+{ "_id" : "25287", "city" : "WEST COLUMBIA", "loc" : [ -82.090529, 38.926169 ], "pop" : 1009, "state" : "WV" }
+{ "_id" : "25301", "city" : "CHARLESTON", "loc" : [ -81.630606, 38.349 ], "pop" : 4139, "state" : "WV" }
+{ "_id" : "25302", "city" : "BIG CHIMNEY", "loc" : [ -81.623876, 38.383178 ], "pop" : 20267, "state" : "WV" }
+{ "_id" : "25303", "city" : "SOUTH CHARLESTON", "loc" : [ -81.684079, 38.359226 ], "pop" : 8198, "state" : "WV" }
+{ "_id" : "25304", "city" : "CHARLESTON", "loc" : [ -81.590272, 38.317289 ], "pop" : 9368, "state" : "WV" }
+{ "_id" : "25306", "city" : "MALDEN", "loc" : [ -81.536813, 38.30028 ], "pop" : 7992, "state" : "WV" }
+{ "_id" : "25309", "city" : "SOUTH CHARLESTON", "loc" : [ -81.73446199999999, 38.344903 ], "pop" : 10179, "state" : "WV" }
+{ "_id" : "25311", "city" : "CHARLESTON", "loc" : [ -81.599282, 38.349032 ], "pop" : 10091, "state" : "WV" }
+{ "_id" : "25312", "city" : "CHARLESTON", "loc" : [ -81.674688, 38.409563 ], "pop" : 13224, "state" : "WV" }
+{ "_id" : "25313", "city" : "CROSS LANES", "loc" : [ -81.764877, 38.424982 ], "pop" : 13061, "state" : "WV" }
+{ "_id" : "25314", "city" : "CHARLESTON", "loc" : [ -81.668988, 38.327442 ], "pop" : 17108, "state" : "WV" }
+{ "_id" : "25315", "city" : "MARMET", "loc" : [ -81.554361, 38.233309 ], "pop" : 4317, "state" : "WV" }
+{ "_id" : "25320", "city" : "SISSONVILLE", "loc" : [ -81.62958500000001, 38.509586 ], "pop" : 7220, "state" : "WV" }
+{ "_id" : "25401", "city" : "MARTINSBURG", "loc" : [ -77.958915, 39.459959 ], "pop" : 36800, "state" : "WV" }
+{ "_id" : "25411", "city" : "HANCOCK", "loc" : [ -78.219217, 39.58736 ], "pop" : 9219, "state" : "WV" }
+{ "_id" : "25413", "city" : "BUNKER HILL", "loc" : [ -78.04871799999999, 39.327554 ], "pop" : 5419, "state" : "WV" }
+{ "_id" : "25414", "city" : "CHARLES TOWN", "loc" : [ -77.85625400000001, 39.277085 ], "pop" : 14351, "state" : "WV" }
+{ "_id" : "25419", "city" : "FALLING WATERS", "loc" : [ -77.88515200000001, 39.586473 ], "pop" : 4428, "state" : "WV" }
+{ "_id" : "25420", "city" : "GERRARDSTOWN", "loc" : [ -78.114119, 39.378039 ], "pop" : 2481, "state" : "WV" }
+{ "_id" : "25422", "city" : "GREAT CACAPON", "loc" : [ -78.33311999999999, 39.583557 ], "pop" : 1108, "state" : "WV" }
+{ "_id" : "25425", "city" : "HARPERS FERRY", "loc" : [ -77.76944899999999, 39.315283 ], "pop" : 7126, "state" : "WV" }
+{ "_id" : "25427", "city" : "CHERRY RUN", "loc" : [ -78.056016, 39.547034 ], "pop" : 7415, "state" : "WV" }
+{ "_id" : "25428", "city" : "INWOOD", "loc" : [ -78.02418900000001, 39.370093 ], "pop" : 3646, "state" : "WV" }
+{ "_id" : "25430", "city" : "KEARNEYSVILLE", "loc" : [ -77.95876199999999, 39.321994 ], "pop" : 3468, "state" : "WV" }
+{ "_id" : "25431", "city" : "LEVELS", "loc" : [ -78.55078, 39.497637 ], "pop" : 28, "state" : "WV" }
+{ "_id" : "25434", "city" : "PAW PAW", "loc" : [ -78.458573, 39.492297 ], "pop" : 1696, "state" : "WV" }
+{ "_id" : "25437", "city" : "POINTS", "loc" : [ -78.564148, 39.457208 ], "pop" : 106, "state" : "WV" }
+{ "_id" : "25438", "city" : "RANSON", "loc" : [ -77.860572, 39.299531 ], "pop" : 3010, "state" : "WV" }
+{ "_id" : "25442", "city" : "SHENANDOAH JUNCT", "loc" : [ -77.88924, 39.371084 ], "pop" : 1907, "state" : "WV" }
+{ "_id" : "25443", "city" : "SHEPHERDSTOWN", "loc" : [ -77.815819, 39.431124 ], "pop" : 5388, "state" : "WV" }
+{ "_id" : "25444", "city" : "SLANESVILLE", "loc" : [ -78.505971, 39.402631 ], "pop" : 468, "state" : "WV" }
+{ "_id" : "25446", "city" : "SUMMIT POINT", "loc" : [ -77.958552, 39.233753 ], "pop" : 676, "state" : "WV" }
+{ "_id" : "25501", "city" : "ALKOL", "loc" : [ -81.98397199999999, 38.160884 ], "pop" : 1161, "state" : "WV" }
+{ "_id" : "25502", "city" : "APPLE GROVE", "loc" : [ -82.172556, 38.713066 ], "pop" : 115, "state" : "WV" }
+{ "_id" : "25503", "city" : "ASHTON", "loc" : [ -82.108907, 38.657102 ], "pop" : 1494, "state" : "WV" }
+{ "_id" : "25504", "city" : "BARBOURSVILLE", "loc" : [ -82.295973, 38.389272 ], "pop" : 10205, "state" : "WV" }
+{ "_id" : "25505", "city" : "BIG CREEK", "loc" : [ -82.01605600000001, 38.004555 ], "pop" : 712, "state" : "WV" }
+{ "_id" : "25506", "city" : "BRANCHLAND", "loc" : [ -82.268367, 38.269444 ], "pop" : 642, "state" : "WV" }
+{ "_id" : "25508", "city" : "CHAPMANVILLE", "loc" : [ -82.051241, 37.938535 ], "pop" : 8874, "state" : "WV" }
+{ "_id" : "25510", "city" : "CULLODEN", "loc" : [ -82.068963, 38.419831 ], "pop" : 2569, "state" : "WV" }
+{ "_id" : "25511", "city" : "DUNLOW", "loc" : [ -82.38266, 38.02829 ], "pop" : 835, "state" : "WV" }
+{ "_id" : "25512", "city" : "EAST LYNN", "loc" : [ -82.32793100000001, 38.199474 ], "pop" : 1722, "state" : "WV" }
+{ "_id" : "25514", "city" : "FORT GAY", "loc" : [ -82.554124, 38.133496 ], "pop" : 3499, "state" : "WV" }
+{ "_id" : "25515", "city" : "GALLIPOLIS FERRY", "loc" : [ -82.153496, 38.765028 ], "pop" : 2121, "state" : "WV" }
+{ "_id" : "25517", "city" : "RADNOR", "loc" : [ -82.46692, 38.088908 ], "pop" : 2111, "state" : "WV" }
+{ "_id" : "25520", "city" : "GLENWOOD", "loc" : [ -82.14343100000001, 38.544936 ], "pop" : 3201, "state" : "WV" }
+{ "_id" : "25521", "city" : "GRIFFITHSVILLE", "loc" : [ -81.982028, 38.246985 ], "pop" : 521, "state" : "WV" }
+{ "_id" : "25523", "city" : "HAMLIN", "loc" : [ -82.10469500000001, 38.289556 ], "pop" : 2993, "state" : "WV" }
+{ "_id" : "25524", "city" : "FERRELLSBURG", "loc" : [ -82.15535800000001, 38.008878 ], "pop" : 1611, "state" : "WV" }
+{ "_id" : "25526", "city" : "HURRICANE", "loc" : [ -81.99432899999999, 38.425741 ], "pop" : 16250, "state" : "WV" }
+{ "_id" : "25529", "city" : "JULIAN", "loc" : [ -81.86418500000001, 38.126437 ], "pop" : 670, "state" : "WV" }
+{ "_id" : "25530", "city" : "KENOVA", "loc" : [ -82.573649, 38.386031 ], "pop" : 7491, "state" : "WV" }
+{ "_id" : "25534", "city" : "COVE GAP", "loc" : [ -82.25620600000001, 38.077744 ], "pop" : 326, "state" : "WV" }
+{ "_id" : "25535", "city" : "LAVALETTE", "loc" : [ -82.428707, 38.33046 ], "pop" : 5928, "state" : "WV" }
+{ "_id" : "25537", "city" : "LESAGE", "loc" : [ -82.29566699999999, 38.477028 ], "pop" : 2972, "state" : "WV" }
+{ "_id" : "25540", "city" : "MIDKIFF", "loc" : [ -82.15422700000001, 38.143908 ], "pop" : 470, "state" : "WV" }
+{ "_id" : "25541", "city" : "MILTON", "loc" : [ -82.14578400000001, 38.413981 ], "pop" : 7168, "state" : "WV" }
+{ "_id" : "25544", "city" : "MYRA", "loc" : [ -82.135097, 38.21978 ], "pop" : 146, "state" : "WV" }
+{ "_id" : "25545", "city" : "ONA", "loc" : [ -82.218093, 38.452851 ], "pop" : 5959, "state" : "WV" }
+{ "_id" : "25546", "city" : "PALERMO", "loc" : [ -82.046018, 38.12817 ], "pop" : 115, "state" : "WV" }
+{ "_id" : "25547", "city" : "PECKS MILL", "loc" : [ -81.96538200000001, 37.929784 ], "pop" : 117, "state" : "WV" }
+{ "_id" : "25550", "city" : "POINT PLEASANT", "loc" : [ -82.113247, 38.863249 ], "pop" : 7981, "state" : "WV" }
+{ "_id" : "25555", "city" : "PRICHARD", "loc" : [ -82.57529700000001, 38.230009 ], "pop" : 1215, "state" : "WV" }
+{ "_id" : "25557", "city" : "RANGER", "loc" : [ -82.19078, 38.155608 ], "pop" : 5703, "state" : "WV" }
+{ "_id" : "25559", "city" : "SALT ROCK", "loc" : [ -82.247041, 38.326542 ], "pop" : 1482, "state" : "WV" }
+{ "_id" : "25560", "city" : "SCOTT DEPOT", "loc" : [ -81.900481, 38.450063 ], "pop" : 5893, "state" : "WV" }
+{ "_id" : "25563", "city" : "SIAS", "loc" : [ -82.085779, 38.189434 ], "pop" : 384, "state" : "WV" }
+{ "_id" : "25564", "city" : "SOD", "loc" : [ -81.86814, 38.262967 ], "pop" : 3529, "state" : "WV" }
+{ "_id" : "25565", "city" : "MORRISVALE", "loc" : [ -81.991778, 38.077015 ], "pop" : 1449, "state" : "WV" }
+{ "_id" : "25567", "city" : "SUMERCO", "loc" : [ -81.894317, 38.205292 ], "pop" : 638, "state" : "WV" }
+{ "_id" : "25568", "city" : "SWEETLAND", "loc" : [ -82.034464, 38.262874 ], "pop" : 378, "state" : "WV" }
+{ "_id" : "25570", "city" : "WAYNE", "loc" : [ -82.433926, 38.225814 ], "pop" : 4992, "state" : "WV" }
+{ "_id" : "25571", "city" : "WEST HAMLIN", "loc" : [ -82.184348, 38.288571 ], "pop" : 1612, "state" : "WV" }
+{ "_id" : "25572", "city" : "WOODVILLE", "loc" : [ -81.911281, 38.157027 ], "pop" : 262, "state" : "WV" }
+{ "_id" : "25573", "city" : "YAWKEY", "loc" : [ -81.956828, 38.219252 ], "pop" : 690, "state" : "WV" }
+{ "_id" : "25601", "city" : "WEST LOGAN", "loc" : [ -82.002092, 37.847488 ], "pop" : 14143, "state" : "WV" }
+{ "_id" : "25607", "city" : "ROBINETTE", "loc" : [ -81.758912, 37.795586 ], "pop" : 2986, "state" : "WV" }
+{ "_id" : "25608", "city" : "BAISDEN", "loc" : [ -81.93275800000001, 37.571492 ], "pop" : 1183, "state" : "WV" }
+{ "_id" : "25617", "city" : "DAVIN", "loc" : [ -81.805706, 37.726499 ], "pop" : 2388, "state" : "WV" }
+{ "_id" : "25621", "city" : "GILBERT", "loc" : [ -81.866468, 37.594153 ], "pop" : 2027, "state" : "WV" }
+{ "_id" : "25623", "city" : "HAMPDEN", "loc" : [ -81.947014, 37.639691 ], "pop" : 1352, "state" : "WV" }
+{ "_id" : "25632", "city" : "EARLING", "loc" : [ -81.92929100000001, 37.774266 ], "pop" : 847, "state" : "WV" }
+{ "_id" : "25635", "city" : "HUNT", "loc" : [ -81.865228, 37.729525 ], "pop" : 3932, "state" : "WV" }
+{ "_id" : "25638", "city" : "BARNABUS", "loc" : [ -82.004931, 37.722368 ], "pop" : 2369, "state" : "WV" }
+{ "_id" : "25650", "city" : "VERNER", "loc" : [ -81.864801, 37.64554 ], "pop" : 1487, "state" : "WV" }
+{ "_id" : "25651", "city" : "WHARNCLIFFE", "loc" : [ -81.956604, 37.545161 ], "pop" : 428, "state" : "WV" }
+{ "_id" : "25654", "city" : "DEHUE", "loc" : [ -81.872699, 37.866513 ], "pop" : 2524, "state" : "WV" }
+{ "_id" : "25661", "city" : "WILLIAMSON", "loc" : [ -82.264163, 37.690248 ], "pop" : 8866, "state" : "WV" }
+{ "_id" : "25666", "city" : "BREEDEN", "loc" : [ -82.25474800000001, 37.919751 ], "pop" : 773, "state" : "WV" }
+{ "_id" : "25669", "city" : "CRUM", "loc" : [ -82.46235900000001, 37.938879 ], "pop" : 763, "state" : "WV" }
+{ "_id" : "25670", "city" : "MYRTLE", "loc" : [ -82.131922, 37.703833 ], "pop" : 4639, "state" : "WV" }
+{ "_id" : "25671", "city" : "DINGESS", "loc" : [ -82.195108, 37.870336 ], "pop" : 2012, "state" : "WV" }
+{ "_id" : "25674", "city" : "KERMIT", "loc" : [ -82.374065, 37.864246 ], "pop" : 3549, "state" : "WV" }
+{ "_id" : "25676", "city" : "LENORE", "loc" : [ -82.269336, 37.799436 ], "pop" : 2521, "state" : "WV" }
+{ "_id" : "25678", "city" : "LOBATA", "loc" : [ -82.14569400000001, 37.649539 ], "pop" : 3232, "state" : "WV" }
+{ "_id" : "25682", "city" : "MEADOR", "loc" : [ -82.065904, 37.592373 ], "pop" : 1640, "state" : "WV" }
+{ "_id" : "25694", "city" : "THACKER", "loc" : [ -82.12733299999999, 37.608293 ], "pop" : 1064, "state" : "WV" }
+{ "_id" : "25699", "city" : "WILSONDALE", "loc" : [ -82.38135800000001, 37.951598 ], "pop" : 897, "state" : "WV" }
+{ "_id" : "25701", "city" : "HUNTINGTON", "loc" : [ -82.442348, 38.409726 ], "pop" : 20896, "state" : "WV" }
+{ "_id" : "25702", "city" : "HUNTINGTON", "loc" : [ -82.39108299999999, 38.42862 ], "pop" : 7290, "state" : "WV" }
+{ "_id" : "25703", "city" : "HUNTINGTON", "loc" : [ -82.42266600000001, 38.421116 ], "pop" : 6570, "state" : "WV" }
+{ "_id" : "25704", "city" : "HUNTINGTON", "loc" : [ -82.503646, 38.384943 ], "pop" : 18311, "state" : "WV" }
+{ "_id" : "25705", "city" : "HUNTINGTON", "loc" : [ -82.36901, 38.409588 ], "pop" : 22276, "state" : "WV" }
+{ "_id" : "25801", "city" : "BECKLEY", "loc" : [ -81.206084, 37.793214 ], "pop" : 45196, "state" : "WV" }
+{ "_id" : "25811", "city" : "AMIGO", "loc" : [ -81.34914499999999, 37.59211 ], "pop" : 684, "state" : "WV" }
+{ "_id" : "25812", "city" : "ANSTED", "loc" : [ -81.09548700000001, 38.13686 ], "pop" : 1451, "state" : "WV" }
+{ "_id" : "25813", "city" : "BEAVER", "loc" : [ -81.073104, 37.751581 ], "pop" : 4868, "state" : "WV" }
+{ "_id" : "25817", "city" : "BOLT", "loc" : [ -81.415612, 37.767303 ], "pop" : 524, "state" : "WV" }
+{ "_id" : "25820", "city" : "CAMP CREEK", "loc" : [ -81.111073, 37.484053 ], "pop" : 65, "state" : "WV" }
+{ "_id" : "25825", "city" : "COOL RIDGE", "loc" : [ -81.10527999999999, 37.65735 ], "pop" : 1731, "state" : "WV" }
+{ "_id" : "25827", "city" : "CRAB ORCHARD", "loc" : [ -81.249098, 37.720515 ], "pop" : 5209, "state" : "WV" }
+{ "_id" : "25831", "city" : "CLIFFTOP", "loc" : [ -80.947114, 37.903615 ], "pop" : 1432, "state" : "WV" }
+{ "_id" : "25832", "city" : "DANIELS", "loc" : [ -81.13910799999999, 37.732247 ], "pop" : 2533, "state" : "WV" }
+{ "_id" : "25837", "city" : "EDMOND", "loc" : [ -81.032634, 38.054441 ], "pop" : 69, "state" : "WV" }
+{ "_id" : "25839", "city" : "FAIRDALE", "loc" : [ -81.401758, 37.786578 ], "pop" : 175, "state" : "WV" }
+{ "_id" : "25840", "city" : "CUNARD", "loc" : [ -81.080969, 38.062774 ], "pop" : 8013, "state" : "WV" }
+{ "_id" : "25841", "city" : "FLAT TOP", "loc" : [ -81.127976, 37.550028 ], "pop" : 623, "state" : "WV" }
+{ "_id" : "25843", "city" : "GHENT", "loc" : [ -81.101921, 37.62079 ], "pop" : 749, "state" : "WV" }
+{ "_id" : "25844", "city" : "GLEN DANIEL", "loc" : [ -81.403294, 37.754698 ], "pop" : 123, "state" : "WV" }
+{ "_id" : "25845", "city" : "GLEN FORK", "loc" : [ -81.540209, 37.644691 ], "pop" : 189, "state" : "WV" }
+{ "_id" : "25847", "city" : "SULLIVAN", "loc" : [ -81.13048000000001, 37.790384 ], "pop" : 99, "state" : "WV" }
+{ "_id" : "25848", "city" : "GLEN ROGERS", "loc" : [ -81.428989, 37.721685 ], "pop" : 367, "state" : "WV" }
+{ "_id" : "25854", "city" : "HICO", "loc" : [ -80.963763, 38.109373 ], "pop" : 721, "state" : "WV" }
+{ "_id" : "25857", "city" : "JOSEPHINE", "loc" : [ -81.217584, 37.622135 ], "pop" : 476, "state" : "WV" }
+{ "_id" : "25862", "city" : "LANSING", "loc" : [ -81.02772, 38.110793 ], "pop" : 89, "state" : "WV" }
+{ "_id" : "25864", "city" : "LAWTON", "loc" : [ -80.99244899999999, 37.865779 ], "pop" : 17, "state" : "WV" }
+{ "_id" : "25865", "city" : "LESTER", "loc" : [ -81.30954199999999, 37.726522 ], "pop" : 1157, "state" : "WV" }
+{ "_id" : "25868", "city" : "LOOKOUT", "loc" : [ -80.92006000000001, 38.052822 ], "pop" : 338, "state" : "WV" }
+{ "_id" : "25870", "city" : "MABEN", "loc" : [ -81.39137100000001, 37.654294 ], "pop" : 415, "state" : "WV" }
+{ "_id" : "25876", "city" : "SAULSVILLE", "loc" : [ -81.457706, 37.655573 ], "pop" : 624, "state" : "WV" }
+{ "_id" : "25880", "city" : "MOUNT HOPE", "loc" : [ -81.170419, 37.911048 ], "pop" : 4348, "state" : "WV" }
+{ "_id" : "25882", "city" : "MULLENS", "loc" : [ -81.389015, 37.584172 ], "pop" : 2590, "state" : "WV" }
+{ "_id" : "25901", "city" : "HARVEY", "loc" : [ -81.13442499999999, 37.984874 ], "pop" : 14805, "state" : "WV" }
+{ "_id" : "25902", "city" : "ODD", "loc" : [ -81.187183, 37.592997 ], "pop" : 577, "state" : "WV" }
+{ "_id" : "25908", "city" : "WINDING GULF", "loc" : [ -81.231022, 37.643456 ], "pop" : 13, "state" : "WV" }
+{ "_id" : "25912", "city" : "RAMSEY", "loc" : [ -81.015047, 38.178142 ], "pop" : 460, "state" : "WV" }
+{ "_id" : "25913", "city" : "RAVENCLIFF", "loc" : [ -81.496736, 37.697961 ], "pop" : 1457, "state" : "WV" }
+{ "_id" : "25915", "city" : "EAST GULF", "loc" : [ -81.294753, 37.628587 ], "pop" : 1183, "state" : "WV" }
+{ "_id" : "25917", "city" : "SCARBRO", "loc" : [ -81.24573100000001, 37.947073 ], "pop" : 1074, "state" : "WV" }
+{ "_id" : "25918", "city" : "ABRAHAM", "loc" : [ -81.1023, 37.697802 ], "pop" : 2548, "state" : "WV" }
+{ "_id" : "25920", "city" : "SLAB FORK", "loc" : [ -81.22792800000001, 37.679605 ], "pop" : 2872, "state" : "WV" }
+{ "_id" : "25922", "city" : "SPANISHBURG", "loc" : [ -81.10694100000001, 37.46314 ], "pop" : 883, "state" : "WV" }
+{ "_id" : "25928", "city" : "STEPHENSON", "loc" : [ -81.33391399999999, 37.579847 ], "pop" : 441, "state" : "WV" }
+{ "_id" : "25932", "city" : "SURVEYOR", "loc" : [ -81.33919, 37.748 ], "pop" : 416, "state" : "WV" }
+{ "_id" : "25936", "city" : "THURMOND", "loc" : [ -81.071428, 37.955437 ], "pop" : 62, "state" : "WV" }
+{ "_id" : "25938", "city" : "VICTOR", "loc" : [ -81.032223, 38.140194 ], "pop" : 516, "state" : "WV" }
+{ "_id" : "25951", "city" : "HINTON", "loc" : [ -80.867779, 37.663983 ], "pop" : 6150, "state" : "WV" }
+{ "_id" : "25958", "city" : "CHARMCO", "loc" : [ -80.707745, 37.98948 ], "pop" : 1643, "state" : "WV" }
+{ "_id" : "25962", "city" : "RAINELLE", "loc" : [ -80.78206400000001, 37.966112 ], "pop" : 3320, "state" : "WV" }
+{ "_id" : "25965", "city" : "ELTON", "loc" : [ -80.82520700000001, 37.846825 ], "pop" : 208, "state" : "WV" }
+{ "_id" : "25966", "city" : "GREEN SULPHUR SP", "loc" : [ -80.839922, 37.808553 ], "pop" : 742, "state" : "WV" }
+{ "_id" : "25969", "city" : "STREETER", "loc" : [ -80.995717, 37.639732 ], "pop" : 1270, "state" : "WV" }
+{ "_id" : "25971", "city" : "LERONA", "loc" : [ -80.979574, 37.492498 ], "pop" : 507, "state" : "WV" }
+{ "_id" : "25976", "city" : "MEADOW BRIDGE", "loc" : [ -80.852144, 37.878048 ], "pop" : 1446, "state" : "WV" }
+{ "_id" : "25977", "city" : "MEADOW CREEK", "loc" : [ -80.91742000000001, 37.804824 ], "pop" : 157, "state" : "WV" }
+{ "_id" : "25978", "city" : "NIMITZ", "loc" : [ -80.94462, 37.628584 ], "pop" : 577, "state" : "WV" }
+{ "_id" : "25979", "city" : "PIPESTEM", "loc" : [ -80.94634499999999, 37.530345 ], "pop" : 677, "state" : "WV" }
+{ "_id" : "25981", "city" : "MARFRANCE", "loc" : [ -80.717286, 38.051937 ], "pop" : 1936, "state" : "WV" }
+{ "_id" : "25984", "city" : "KESSLER", "loc" : [ -80.689971, 37.963882 ], "pop" : 1464, "state" : "WV" }
+{ "_id" : "25985", "city" : "SANDSTONE", "loc" : [ -80.87156400000001, 37.759879 ], "pop" : 435, "state" : "WV" }
+{ "_id" : "25986", "city" : "SPRING DALE", "loc" : [ -80.81499599999999, 37.86947 ], "pop" : 79, "state" : "WV" }
+{ "_id" : "25988", "city" : "TRUE", "loc" : [ -80.930837, 37.580031 ], "pop" : 340, "state" : "WV" }
+{ "_id" : "25989", "city" : "WHITE OAK", "loc" : [ -81.058875, 37.68008 ], "pop" : 284, "state" : "WV" }
+{ "_id" : "26003", "city" : "ELM GROVE", "loc" : [ -80.685126, 40.072736 ], "pop" : 49136, "state" : "WV" }
+{ "_id" : "26031", "city" : "BENWOOD", "loc" : [ -80.71603, 40.013299 ], "pop" : 4032, "state" : "WV" }
+{ "_id" : "26032", "city" : "BETHANY", "loc" : [ -80.55463, 40.202 ], "pop" : 487, "state" : "WV" }
+{ "_id" : "26033", "city" : "CAMERON", "loc" : [ -80.56687599999999, 39.82272 ], "pop" : 2743, "state" : "WV" }
+{ "_id" : "26034", "city" : "CHESTER", "loc" : [ -80.55843900000001, 40.598109 ], "pop" : 5966, "state" : "WV" }
+{ "_id" : "26035", "city" : "COLLIERS", "loc" : [ -80.549341, 40.348391 ], "pop" : 2602, "state" : "WV" }
+{ "_id" : "26036", "city" : "DALLAS", "loc" : [ -80.550804, 39.978343 ], "pop" : 822, "state" : "WV" }
+{ "_id" : "26037", "city" : "FOLLANSBEE", "loc" : [ -80.584954, 40.329552 ], "pop" : 7676, "state" : "WV" }
+{ "_id" : "26038", "city" : "GLEN DALE", "loc" : [ -80.732263, 39.959732 ], "pop" : 3418, "state" : "WV" }
+{ "_id" : "26039", "city" : "GLEN EASTON", "loc" : [ -80.66606899999999, 39.853121 ], "pop" : 2477, "state" : "WV" }
+{ "_id" : "26040", "city" : "MC MECHEN", "loc" : [ -80.73081999999999, 39.987793 ], "pop" : 2130, "state" : "WV" }
+{ "_id" : "26041", "city" : "MOUNDSVILLE", "loc" : [ -80.730971, 39.914819 ], "pop" : 18627, "state" : "WV" }
+{ "_id" : "26047", "city" : "NEW CUMBERLAND", "loc" : [ -80.590108, 40.522777 ], "pop" : 5779, "state" : "WV" }
+{ "_id" : "26050", "city" : "NEWELL", "loc" : [ -80.60112599999999, 40.613971 ], "pop" : 2316, "state" : "WV" }
+{ "_id" : "26055", "city" : "PROCTOR", "loc" : [ -80.761779, 39.720683 ], "pop" : 1785, "state" : "WV" }
+{ "_id" : "26059", "city" : "TRIADELPHIA", "loc" : [ -80.59529000000001, 40.069945 ], "pop" : 2320, "state" : "WV" }
+{ "_id" : "26060", "city" : "VALLEY GROVE", "loc" : [ -80.555059, 40.094649 ], "pop" : 1705, "state" : "WV" }
+{ "_id" : "26062", "city" : "WEIRTON", "loc" : [ -80.568307, 40.413673 ], "pop" : 25107, "state" : "WV" }
+{ "_id" : "26070", "city" : "WELLSBURG", "loc" : [ -80.59606100000001, 40.254792 ], "pop" : 12292, "state" : "WV" }
+{ "_id" : "26101", "city" : "PARKERSBURG", "loc" : [ -81.53541199999999, 39.264433 ], "pop" : 35886, "state" : "WV" }
+{ "_id" : "26104", "city" : "NORTH PARKERSBUR", "loc" : [ -81.52610900000001, 39.285316 ], "pop" : 9260, "state" : "WV" }
+{ "_id" : "26105", "city" : "VIENNA", "loc" : [ -81.54114300000001, 39.325089 ], "pop" : 11696, "state" : "WV" }
+{ "_id" : "26133", "city" : "BELLEVILLE", "loc" : [ -81.69231600000001, 39.131417 ], "pop" : 1240, "state" : "WV" }
+{ "_id" : "26134", "city" : "WILLOW ISLAND", "loc" : [ -81.27880999999999, 39.367927 ], "pop" : 1562, "state" : "WV" }
+{ "_id" : "26135", "city" : "BENS RUN", "loc" : [ -81.066534, 39.44641 ], "pop" : 282, "state" : "WV" }
+{ "_id" : "26136", "city" : "BIG BEND", "loc" : [ -81.13603000000001, 38.971941 ], "pop" : 844, "state" : "WV" }
+{ "_id" : "26137", "city" : "NOBE", "loc" : [ -81.069813, 38.996306 ], "pop" : 371, "state" : "WV" }
+{ "_id" : "26138", "city" : "BROHARD", "loc" : [ -81.177528, 39.033756 ], "pop" : 23, "state" : "WV" }
+{ "_id" : "26141", "city" : "CRESTON", "loc" : [ -81.23690499999999, 38.937805 ], "pop" : 340, "state" : "WV" }
+{ "_id" : "26142", "city" : "DAVISVILLE", "loc" : [ -81.47986299999999, 39.212635 ], "pop" : 3667, "state" : "WV" }
+{ "_id" : "26143", "city" : "ELIZABETH", "loc" : [ -81.398889, 39.056618 ], "pop" : 3052, "state" : "WV" }
+{ "_id" : "26145", "city" : "FIVE FORKS", "loc" : [ -81.086623, 38.975331 ], "pop" : 78, "state" : "WV" }
+{ "_id" : "26146", "city" : "FRIENDLY", "loc" : [ -81.034544, 39.502444 ], "pop" : 1073, "state" : "WV" }
+{ "_id" : "26147", "city" : "GRANTSVILLE", "loc" : [ -81.076294, 38.932436 ], "pop" : 1873, "state" : "WV" }
+{ "_id" : "26148", "city" : "MACFARLAN", "loc" : [ -81.177627, 39.08058 ], "pop" : 437, "state" : "WV" }
+{ "_id" : "26149", "city" : "MIDDLEBOURNE", "loc" : [ -80.886067, 39.50537 ], "pop" : 2527, "state" : "WV" }
+{ "_id" : "26150", "city" : "MINERALWELLS", "loc" : [ -81.519096, 39.179846 ], "pop" : 5463, "state" : "WV" }
+{ "_id" : "26151", "city" : "MOUNT ZION", "loc" : [ -81.119473, 38.877455 ], "pop" : 227, "state" : "WV" }
+{ "_id" : "26152", "city" : "MUNDAY", "loc" : [ -81.204048, 39.021423 ], "pop" : 117, "state" : "WV" }
+{ "_id" : "26153", "city" : "MURRAYSVILLE", "loc" : [ -81.771368, 39.059143 ], "pop" : 452, "state" : "WV" }
+{ "_id" : "26155", "city" : "NEW MARTINSVILLE", "loc" : [ -80.85654100000001, 39.658798 ], "pop" : 7617, "state" : "WV" }
+{ "_id" : "26159", "city" : "PADEN CITY", "loc" : [ -80.92648199999999, 39.604408 ], "pop" : 3513, "state" : "WV" }
+{ "_id" : "26160", "city" : "PALESTINE", "loc" : [ -81.42803000000001, 38.974141 ], "pop" : 935, "state" : "WV" }
+{ "_id" : "26161", "city" : "PETROLEUM", "loc" : [ -81.240607, 39.174139 ], "pop" : 419, "state" : "WV" }
+{ "_id" : "26164", "city" : "RAVENSWOOD", "loc" : [ -81.752377, 38.94675 ], "pop" : 6428, "state" : "WV" }
+{ "_id" : "26167", "city" : "READER", "loc" : [ -80.751583, 39.583595 ], "pop" : 2289, "state" : "WV" }
+{ "_id" : "26169", "city" : "ROCKPORT", "loc" : [ -81.571333, 39.079774 ], "pop" : 1068, "state" : "WV" }
+{ "_id" : "26170", "city" : "SAINT MARYS", "loc" : [ -81.172499, 39.38597 ], "pop" : 5523, "state" : "WV" }
+{ "_id" : "26173", "city" : "SHERMAN", "loc" : [ -81.70091600000001, 39.013094 ], "pop" : 749, "state" : "WV" }
+{ "_id" : "26175", "city" : "SISTERSVILLE", "loc" : [ -80.98182799999999, 39.558365 ], "pop" : 3113, "state" : "WV" }
+{ "_id" : "26178", "city" : "SMITHVILLE", "loc" : [ -81.061953, 39.067078 ], "pop" : 590, "state" : "WV" }
+{ "_id" : "26179", "city" : "TANNER", "loc" : [ -80.95971900000001, 38.966435 ], "pop" : 389, "state" : "WV" }
+{ "_id" : "26180", "city" : "WALKER", "loc" : [ -81.386577, 39.182082 ], "pop" : 3218, "state" : "WV" }
+{ "_id" : "26181", "city" : "NEW ENGLAND", "loc" : [ -81.640719, 39.233911 ], "pop" : 8532, "state" : "WV" }
+{ "_id" : "26184", "city" : "WAVERLY", "loc" : [ -81.38193800000001, 39.315681 ], "pop" : 2836, "state" : "WV" }
+{ "_id" : "26185", "city" : "WICK", "loc" : [ -80.96804400000001, 39.421653 ], "pop" : 479, "state" : "WV" }
+{ "_id" : "26186", "city" : "WILEYVILLE", "loc" : [ -80.647251, 39.662593 ], "pop" : 343, "state" : "WV" }
+{ "_id" : "26187", "city" : "WILLIAMSTOWN", "loc" : [ -81.456608, 39.38243 ], "pop" : 5207, "state" : "WV" }
+{ "_id" : "26201", "city" : "TENNERTON", "loc" : [ -80.21782399999999, 38.98407 ], "pop" : 16829, "state" : "WV" }
+{ "_id" : "26202", "city" : "FENWICK", "loc" : [ -80.634972, 38.244657 ], "pop" : 393, "state" : "WV" }
+{ "_id" : "26203", "city" : "ERBACON", "loc" : [ -80.57423199999999, 38.541864 ], "pop" : 318, "state" : "WV" }
+{ "_id" : "26205", "city" : "CRAIGSVILLE", "loc" : [ -80.64438, 38.325389 ], "pop" : 3070, "state" : "WV" }
+{ "_id" : "26206", "city" : "COWEN", "loc" : [ -80.53580700000001, 38.413273 ], "pop" : 2469, "state" : "WV" }
+{ "_id" : "26208", "city" : "GAULEY MILLS", "loc" : [ -80.591408, 38.379246 ], "pop" : 1191, "state" : "WV" }
+{ "_id" : "26210", "city" : "ADRIAN", "loc" : [ -80.288663, 38.913422 ], "pop" : 794, "state" : "WV" }
+{ "_id" : "26214", "city" : "CENTURY", "loc" : [ -80.17568799999999, 39.093287 ], "pop" : 235, "state" : "WV" }
+{ "_id" : "26215", "city" : "CLEVELAND", "loc" : [ -80.342849, 38.839225 ], "pop" : 456, "state" : "WV" }
+{ "_id" : "26217", "city" : "DIANA", "loc" : [ -80.431962, 38.575471 ], "pop" : 1172, "state" : "WV" }
+{ "_id" : "26218", "city" : "ALEXANDER", "loc" : [ -80.274339, 38.851145 ], "pop" : 2398, "state" : "WV" }
+{ "_id" : "26222", "city" : "REPLETE", "loc" : [ -80.402345, 38.679583 ], "pop" : 730, "state" : "WV" }
+{ "_id" : "26224", "city" : "HELVETIA", "loc" : [ -80.138167, 38.771258 ], "pop" : 27, "state" : "WV" }
+{ "_id" : "26228", "city" : "KANAWHA HEAD", "loc" : [ -80.37273399999999, 38.76183 ], "pop" : 171, "state" : "WV" }
+{ "_id" : "26230", "city" : "PICKENS", "loc" : [ -80.209784, 38.684242 ], "pop" : 382, "state" : "WV" }
+{ "_id" : "26234", "city" : "ROCK CAVE", "loc" : [ -80.316276, 38.781128 ], "pop" : 649, "state" : "WV" }
+{ "_id" : "26236", "city" : "SELBYVILLE", "loc" : [ -80.312955, 38.719393 ], "pop" : 40, "state" : "WV" }
+{ "_id" : "26237", "city" : "TALLMANSVILLE", "loc" : [ -80.15799, 38.856405 ], "pop" : 507, "state" : "WV" }
+{ "_id" : "26238", "city" : "VOLGA", "loc" : [ -80.143209, 39.068445 ], "pop" : 969, "state" : "WV" }
+{ "_id" : "26241", "city" : "ELKINS", "loc" : [ -79.847115, 38.925304 ], "pop" : 14027, "state" : "WV" }
+{ "_id" : "26250", "city" : "BELINGTON", "loc" : [ -79.94950799999999, 39.024439 ], "pop" : 5189, "state" : "WV" }
+{ "_id" : "26253", "city" : "BEVERLY", "loc" : [ -79.865121, 38.828021 ], "pop" : 3206, "state" : "WV" }
+{ "_id" : "26254", "city" : "WYMER", "loc" : [ -79.619347, 38.934863 ], "pop" : 128, "state" : "WV" }
+{ "_id" : "26257", "city" : "COALTON", "loc" : [ -79.976724, 38.91438 ], "pop" : 1422, "state" : "WV" }
+{ "_id" : "26260", "city" : "DAVIS", "loc" : [ -79.456278, 39.088227 ], "pop" : 1459, "state" : "WV" }
+{ "_id" : "26261", "city" : "RICHWOOD", "loc" : [ -80.544481, 38.222988 ], "pop" : 4129, "state" : "WV" }
+{ "_id" : "26263", "city" : "DRYFORK", "loc" : [ -79.45340299999999, 38.957616 ], "pop" : 116, "state" : "WV" }
+{ "_id" : "26264", "city" : "DURBIN", "loc" : [ -79.793464, 38.616313 ], "pop" : 75, "state" : "WV" }
+{ "_id" : "26266", "city" : "UPPERGLADE", "loc" : [ -80.496464, 38.418528 ], "pop" : 383, "state" : "WV" }
+{ "_id" : "26267", "city" : "ELLAMORE", "loc" : [ -80.09261100000001, 38.933966 ], "pop" : 482, "state" : "WV" }
+{ "_id" : "26268", "city" : "GLADY", "loc" : [ -79.734202, 38.866925 ], "pop" : 615, "state" : "WV" }
+{ "_id" : "26269", "city" : "HAMBLETON", "loc" : [ -79.641565, 39.116836 ], "pop" : 930, "state" : "WV" }
+{ "_id" : "26270", "city" : "HARMAN", "loc" : [ -79.52459899999999, 38.923369 ], "pop" : 700, "state" : "WV" }
+{ "_id" : "26271", "city" : "HENDRICKS", "loc" : [ -79.630302, 39.074814 ], "pop" : 318, "state" : "WV" }
+{ "_id" : "26273", "city" : "HUTTONSVILLE", "loc" : [ -79.97754399999999, 38.678433 ], "pop" : 1072, "state" : "WV" }
+{ "_id" : "26276", "city" : "KERENS", "loc" : [ -79.77542699999999, 39.029854 ], "pop" : 569, "state" : "WV" }
+{ "_id" : "26278", "city" : "MABIE", "loc" : [ -80.01306099999999, 38.822158 ], "pop" : 427, "state" : "WV" }
+{ "_id" : "26280", "city" : "MILL CREEK", "loc" : [ -79.97856899999999, 38.732493 ], "pop" : 2219, "state" : "WV" }
+{ "_id" : "26282", "city" : "MONTERVILLE", "loc" : [ -80.12239099999999, 38.551707 ], "pop" : 79, "state" : "WV" }
+{ "_id" : "26283", "city" : "MONTROSE", "loc" : [ -79.78957699999999, 39.096357 ], "pop" : 1513, "state" : "WV" }
+{ "_id" : "26287", "city" : "PARSONS", "loc" : [ -79.67344799999999, 39.105857 ], "pop" : 2432, "state" : "WV" }
+{ "_id" : "26288", "city" : "BOLAIR", "loc" : [ -80.399798, 38.476362 ], "pop" : 3914, "state" : "WV" }
+{ "_id" : "26289", "city" : "RED CREEK", "loc" : [ -79.53009, 39.019628 ], "pop" : 318, "state" : "WV" }
+{ "_id" : "26291", "city" : "SLATYFORK", "loc" : [ -80.040353, 38.381207 ], "pop" : 448, "state" : "WV" }
+{ "_id" : "26292", "city" : "THOMAS", "loc" : [ -79.503, 39.150517 ], "pop" : 966, "state" : "WV" }
+{ "_id" : "26293", "city" : "VALLEY BEND", "loc" : [ -79.916037, 38.784903 ], "pop" : 804, "state" : "WV" }
+{ "_id" : "26294", "city" : "MINGO", "loc" : [ -80.044911, 38.536637 ], "pop" : 1013, "state" : "WV" }
+{ "_id" : "26296", "city" : "JOB", "loc" : [ -79.55775199999999, 38.808289 ], "pop" : 384, "state" : "WV" }
+{ "_id" : "26299", "city" : "BOGGS", "loc" : [ -80.607389, 38.482119 ], "pop" : 544, "state" : "WV" }
+{ "_id" : "26301", "city" : "NUTTER FORT STON", "loc" : [ -80.34868299999999, 39.278422 ], "pop" : 33089, "state" : "WV" }
+{ "_id" : "26320", "city" : "WILBUR", "loc" : [ -80.81715699999999, 39.429757 ], "pop" : 1201, "state" : "WV" }
+{ "_id" : "26321", "city" : "ALUM BRIDGE", "loc" : [ -80.688196, 39.042474 ], "pop" : 1015, "state" : "WV" }
+{ "_id" : "26322", "city" : "ALVY", "loc" : [ -80.668921, 39.451106 ], "pop" : 143, "state" : "WV" }
+{ "_id" : "26325", "city" : "AUBURN", "loc" : [ -80.883656, 39.086382 ], "pop" : 326, "state" : "WV" }
+{ "_id" : "26327", "city" : "BEREA", "loc" : [ -80.92232199999999, 39.130452 ], "pop" : 106, "state" : "WV" }
+{ "_id" : "26328", "city" : "BLANDVILLE", "loc" : [ -80.735856, 39.265169 ], "pop" : 35, "state" : "WV" }
+{ "_id" : "26330", "city" : "BRIDGEPORT", "loc" : [ -80.24269200000001, 39.29537 ], "pop" : 11747, "state" : "WV" }
+{ "_id" : "26332", "city" : "BRISTOL", "loc" : [ -80.510541, 39.290425 ], "pop" : 1424, "state" : "WV" }
+{ "_id" : "26335", "city" : "GEM", "loc" : [ -80.65898900000001, 38.850391 ], "pop" : 1513, "state" : "WV" }
+{ "_id" : "26337", "city" : "CAIRO", "loc" : [ -81.155427, 39.23249 ], "pop" : 1379, "state" : "WV" }
+{ "_id" : "26338", "city" : "CAMDEN", "loc" : [ -80.591531, 39.089268 ], "pop" : 584, "state" : "WV" }
+{ "_id" : "26339", "city" : "CENTER POINT", "loc" : [ -80.635227, 39.412472 ], "pop" : 121, "state" : "WV" }
+{ "_id" : "26342", "city" : "COXS MILLS", "loc" : [ -80.87459200000001, 39.002102 ], "pop" : 796, "state" : "WV" }
+{ "_id" : "26343", "city" : "CRAWFORD", "loc" : [ -80.400749, 38.840065 ], "pop" : 517, "state" : "WV" }
+{ "_id" : "26346", "city" : "HIGHLAND", "loc" : [ -81.060382, 39.282364 ], "pop" : 880, "state" : "WV" }
+{ "_id" : "26347", "city" : "WENDEL", "loc" : [ -80.128179, 39.271069 ], "pop" : 2620, "state" : "WV" }
+{ "_id" : "26348", "city" : "FOLSOM", "loc" : [ -80.525806, 39.469345 ], "pop" : 359, "state" : "WV" }
+{ "_id" : "26351", "city" : "BALDWIN", "loc" : [ -80.82783000000001, 38.933619 ], "pop" : 2768, "state" : "WV" }
+{ "_id" : "26354", "city" : "GRAFTON", "loc" : [ -80.028509, 39.341386 ], "pop" : 10102, "state" : "WV" }
+{ "_id" : "26360", "city" : "GREENWOOD", "loc" : [ -80.878899, 39.290761 ], "pop" : 454, "state" : "WV" }
+{ "_id" : "26362", "city" : "MAHONE", "loc" : [ -81.045967, 39.199608 ], "pop" : 2962, "state" : "WV" }
+{ "_id" : "26367", "city" : "HAZELGREEN", "loc" : [ -80.98057799999999, 39.063075 ], "pop" : 203, "state" : "WV" }
+{ "_id" : "26372", "city" : "HORNER", "loc" : [ -80.365576, 38.972628 ], "pop" : 365, "state" : "WV" }
+{ "_id" : "26374", "city" : "INDEPENDENCE", "loc" : [ -79.882161, 39.446372 ], "pop" : 1227, "state" : "WV" }
+{ "_id" : "26376", "city" : "WILDCAT", "loc" : [ -80.477002, 38.767689 ], "pop" : 589, "state" : "WV" }
+{ "_id" : "26377", "city" : "JACKSONBURG", "loc" : [ -80.643697, 39.541553 ], "pop" : 406, "state" : "WV" }
+{ "_id" : "26378", "city" : "JANE LEW", "loc" : [ -80.431059, 39.109989 ], "pop" : 4529, "state" : "WV" }
+{ "_id" : "26383", "city" : "LIMA", "loc" : [ -80.72470300000001, 39.438973 ], "pop" : 153, "state" : "WV" }
+{ "_id" : "26384", "city" : "LINN", "loc" : [ -80.730046, 38.957294 ], "pop" : 759, "state" : "WV" }
+{ "_id" : "26385", "city" : "LOST CREEK", "loc" : [ -80.377674, 39.172528 ], "pop" : 3740, "state" : "WV" }
+{ "_id" : "26386", "city" : "LUMBERPORT", "loc" : [ -80.36763500000001, 39.378108 ], "pop" : 2300, "state" : "WV" }
+{ "_id" : "26404", "city" : "MEADOWBROOK", "loc" : [ -80.32566799999999, 39.335367 ], "pop" : 1373, "state" : "WV" }
+{ "_id" : "26405", "city" : "KASSON", "loc" : [ -79.92157400000001, 39.212271 ], "pop" : 1382, "state" : "WV" }
+{ "_id" : "26408", "city" : "MOUNT CLARE", "loc" : [ -80.289948, 39.210708 ], "pop" : 1558, "state" : "WV" }
+{ "_id" : "26409", "city" : "NEWBERNE", "loc" : [ -80.902838, 39.040743 ], "pop" : 86, "state" : "WV" }
+{ "_id" : "26410", "city" : "NEWBURG", "loc" : [ -79.828036, 39.402722 ], "pop" : 1206, "state" : "WV" }
+{ "_id" : "26411", "city" : "NEW MILTON", "loc" : [ -80.707617, 39.189917 ], "pop" : 783, "state" : "WV" }
+{ "_id" : "26412", "city" : "ORLANDO", "loc" : [ -80.56012200000001, 38.885349 ], "pop" : 209, "state" : "WV" }
+{ "_id" : "26415", "city" : "TOLL GATE", "loc" : [ -80.958482, 39.292064 ], "pop" : 2597, "state" : "WV" }
+{ "_id" : "26416", "city" : "BROADDUS", "loc" : [ -80.03853100000001, 39.150789 ], "pop" : 7934, "state" : "WV" }
+{ "_id" : "26419", "city" : "HASTINGS", "loc" : [ -80.67721299999999, 39.565069 ], "pop" : 881, "state" : "WV" }
+{ "_id" : "26421", "city" : "PULLMAN", "loc" : [ -80.934685, 39.190013 ], "pop" : 247, "state" : "WV" }
+{ "_id" : "26423", "city" : "ROANOKE", "loc" : [ -80.498537, 38.930494 ], "pop" : 576, "state" : "WV" }
+{ "_id" : "26425", "city" : "MANHEIM", "loc" : [ -79.642977, 39.221575 ], "pop" : 404, "state" : "WV" }
+{ "_id" : "26426", "city" : "SALEM", "loc" : [ -80.589792, 39.294761 ], "pop" : 5874, "state" : "WV" }
+{ "_id" : "26431", "city" : "SHINNSTON", "loc" : [ -80.283399, 39.388809 ], "pop" : 6044, "state" : "WV" }
+{ "_id" : "26437", "city" : "SMITHFIELD", "loc" : [ -80.558245, 39.5134 ], "pop" : 775, "state" : "WV" }
+{ "_id" : "26439", "city" : "STOUTS MILLS", "loc" : [ -80.741131, 38.893335 ], "pop" : 717, "state" : "WV" }
+{ "_id" : "26440", "city" : "THORNTON", "loc" : [ -79.909645, 39.332879 ], "pop" : 1144, "state" : "WV" }
+{ "_id" : "26443", "city" : "TROY", "loc" : [ -80.754921, 39.083881 ], "pop" : 115, "state" : "WV" }
+{ "_id" : "26444", "city" : "TUNNELTON", "loc" : [ -79.747818, 39.362502 ], "pop" : 4076, "state" : "WV" }
+{ "_id" : "26447", "city" : "WALKERSVILLE", "loc" : [ -80.480221, 38.850738 ], "pop" : 737, "state" : "WV" }
+{ "_id" : "26448", "city" : "WALLACE", "loc" : [ -80.486468, 39.411667 ], "pop" : 1372, "state" : "WV" }
+{ "_id" : "26451", "city" : "WEST MILFORD", "loc" : [ -80.363049, 39.203906 ], "pop" : 1365, "state" : "WV" }
+{ "_id" : "26452", "city" : "WESTON", "loc" : [ -80.47365600000001, 39.041104 ], "pop" : 9912, "state" : "WV" }
+{ "_id" : "26456", "city" : "WEST UNION", "loc" : [ -80.791057, 39.276185 ], "pop" : 3133, "state" : "WV" }
+{ "_id" : "26462", "city" : "WOLF SUMMIT", "loc" : [ -80.438704, 39.232985 ], "pop" : 1116, "state" : "WV" }
+{ "_id" : "26505", "city" : "STAR CITY", "loc" : [ -79.95422499999999, 39.633858 ], "pop" : 70185, "state" : "WV" }
+{ "_id" : "26519", "city" : "ALBRIGHT", "loc" : [ -79.635811, 39.570116 ], "pop" : 858, "state" : "WV" }
+{ "_id" : "26521", "city" : "BLACKSVILLE", "loc" : [ -80.232646, 39.695821 ], "pop" : 13, "state" : "WV" }
+{ "_id" : "26525", "city" : "BRUCETON MILLS", "loc" : [ -79.61594100000001, 39.645394 ], "pop" : 3857, "state" : "WV" }
+{ "_id" : "26529", "city" : "CORE", "loc" : [ -80.23068000000001, 39.654037 ], "pop" : 453, "state" : "WV" }
+{ "_id" : "26537", "city" : "KINGWOOD", "loc" : [ -79.70629, 39.481912 ], "pop" : 6716, "state" : "WV" }
+{ "_id" : "26541", "city" : "MAIDSVILLE", "loc" : [ -80.08319299999999, 39.709308 ], "pop" : 2047, "state" : "WV" }
+{ "_id" : "26542", "city" : "CASCADE", "loc" : [ -79.80099300000001, 39.576413 ], "pop" : 658, "state" : "WV" }
+{ "_id" : "26546", "city" : "PURSGLOVE", "loc" : [ -80.061798, 39.699543 ], "pop" : 322, "state" : "WV" }
+{ "_id" : "26547", "city" : "REEDSVILLE", "loc" : [ -79.810061, 39.51823 ], "pop" : 3551, "state" : "WV" }
+{ "_id" : "26554", "city" : "MONONGAH", "loc" : [ -80.146041, 39.472677 ], "pop" : 41565, "state" : "WV" }
+{ "_id" : "26560", "city" : "BAXTER", "loc" : [ -80.14169099999999, 39.536056 ], "pop" : 748, "state" : "WV" }
+{ "_id" : "26561", "city" : "BIG RUN", "loc" : [ -80.58371699999999, 39.59414 ], "pop" : 647, "state" : "WV" }
+{ "_id" : "26562", "city" : "COBURN", "loc" : [ -80.405931, 39.667984 ], "pop" : 697, "state" : "WV" }
+{ "_id" : "26568", "city" : "ENTERPRISE", "loc" : [ -80.316704, 39.425998 ], "pop" : 1800, "state" : "WV" }
+{ "_id" : "26570", "city" : "FAIRVIEW", "loc" : [ -80.25291799999999, 39.610335 ], "pop" : 2406, "state" : "WV" }
+{ "_id" : "26571", "city" : "FARMINGTON", "loc" : [ -80.256643, 39.50287 ], "pop" : 3622, "state" : "WV" }
+{ "_id" : "26575", "city" : "HUNDRED", "loc" : [ -80.474552, 39.691744 ], "pop" : 1214, "state" : "WV" }
+{ "_id" : "26581", "city" : "LITTLETON", "loc" : [ -80.569478, 39.659205 ], "pop" : 458, "state" : "WV" }
+{ "_id" : "26582", "city" : "MANNINGTON", "loc" : [ -80.355243, 39.522031 ], "pop" : 5323, "state" : "WV" }
+{ "_id" : "26585", "city" : "METZ", "loc" : [ -80.416815, 39.607762 ], "pop" : 924, "state" : "WV" }
+{ "_id" : "26587", "city" : "RACHEL", "loc" : [ -80.295694, 39.52254 ], "pop" : 274, "state" : "WV" }
+{ "_id" : "26588", "city" : "RIVESVILLE", "loc" : [ -80.141744, 39.556839 ], "pop" : 2938, "state" : "WV" }
+{ "_id" : "26589", "city" : "WADESTOWN", "loc" : [ -80.327462, 39.636926 ], "pop" : 329, "state" : "WV" }
+{ "_id" : "26590", "city" : "WANA", "loc" : [ -80.30510599999999, 39.702072 ], "pop" : 272, "state" : "WV" }
+{ "_id" : "26591", "city" : "WORTHINGTON", "loc" : [ -80.290468, 39.452213 ], "pop" : 1506, "state" : "WV" }
+{ "_id" : "26601", "city" : "HEROLD", "loc" : [ -80.681072, 38.673855 ], "pop" : 3517, "state" : "WV" }
+{ "_id" : "26610", "city" : "BIRCH RIVER", "loc" : [ -80.745873, 38.491424 ], "pop" : 1440, "state" : "WV" }
+{ "_id" : "26611", "city" : "FLOWER", "loc" : [ -80.84034200000001, 38.839711 ], "pop" : 308, "state" : "WV" }
+{ "_id" : "26615", "city" : "COPEN", "loc" : [ -80.728481, 38.830556 ], "pop" : 161, "state" : "WV" }
+{ "_id" : "26617", "city" : "DILLE", "loc" : [ -80.853784, 38.474704 ], "pop" : 410, "state" : "WV" }
+{ "_id" : "26618", "city" : "ELMIRA", "loc" : [ -80.984972, 38.658907 ], "pop" : 276, "state" : "WV" }
+{ "_id" : "26619", "city" : "RIFFLE", "loc" : [ -80.768123, 38.806866 ], "pop" : 230, "state" : "WV" }
+{ "_id" : "26620", "city" : "FALLS MILL", "loc" : [ -80.550618, 38.77566 ], "pop" : 25, "state" : "WV" }
+{ "_id" : "26621", "city" : "CORLEY", "loc" : [ -80.63847800000001, 38.724475 ], "pop" : 658, "state" : "WV" }
+{ "_id" : "26623", "city" : "CLEM", "loc" : [ -80.877416, 38.636828 ], "pop" : 1276, "state" : "WV" }
+{ "_id" : "26624", "city" : "GASSAWAY", "loc" : [ -80.786339, 38.686193 ], "pop" : 2665, "state" : "WV" }
+{ "_id" : "26626", "city" : "GLENDON", "loc" : [ -80.939459, 38.610857 ], "pop" : 223, "state" : "WV" }
+{ "_id" : "26627", "city" : "HEATERS", "loc" : [ -80.642884, 38.755807 ], "pop" : 368, "state" : "WV" }
+{ "_id" : "26629", "city" : "TESLA", "loc" : [ -80.706293, 38.581046 ], "pop" : 1325, "state" : "WV" }
+{ "_id" : "26631", "city" : "NAPIER", "loc" : [ -80.584104, 38.77462 ], "pop" : 107, "state" : "WV" }
+{ "_id" : "26633", "city" : "NICUT", "loc" : [ -81.011, 38.715133 ], "pop" : 151, "state" : "WV" }
+{ "_id" : "26634", "city" : "PERKINS", "loc" : [ -80.919336, 38.809049 ], "pop" : 242, "state" : "WV" }
+{ "_id" : "26636", "city" : "ROSEDALE", "loc" : [ -80.906127, 38.770103 ], "pop" : 88, "state" : "WV" }
+{ "_id" : "26638", "city" : "SHOCK", "loc" : [ -80.96866300000001, 38.757527 ], "pop" : 250, "state" : "WV" }
+{ "_id" : "26639", "city" : "STRANGE CREEK", "loc" : [ -80.903077, 38.573823 ], "pop" : 206, "state" : "WV" }
+{ "_id" : "26641", "city" : "WILSIE", "loc" : [ -80.86805099999999, 38.672723 ], "pop" : 150, "state" : "WV" }
+{ "_id" : "26651", "city" : "SUMMERSVILLE", "loc" : [ -80.835278, 38.30089 ], "pop" : 6520, "state" : "WV" }
+{ "_id" : "26656", "city" : "BELVA", "loc" : [ -81.156572, 38.249105 ], "pop" : 415, "state" : "WV" }
+{ "_id" : "26660", "city" : "CALVIN", "loc" : [ -80.70162999999999, 38.327679 ], "pop" : 603, "state" : "WV" }
+{ "_id" : "26662", "city" : "CANVAS", "loc" : [ -80.744637, 38.262445 ], "pop" : 1163, "state" : "WV" }
+{ "_id" : "26667", "city" : "DRENNEN", "loc" : [ -81.00886800000001, 38.258729 ], "pop" : 263, "state" : "WV" }
+{ "_id" : "26671", "city" : "GILBOA", "loc" : [ -80.952232, 38.298304 ], "pop" : 422, "state" : "WV" }
+{ "_id" : "26674", "city" : "JODIE", "loc" : [ -81.134657, 38.208319 ], "pop" : 510, "state" : "WV" }
+{ "_id" : "26675", "city" : "KESLERS CROSS LA", "loc" : [ -80.93336499999999, 38.225762 ], "pop" : 188, "state" : "WV" }
+{ "_id" : "26676", "city" : "LEIVASY", "loc" : [ -80.717213, 38.135019 ], "pop" : 1107, "state" : "WV" }
+{ "_id" : "26678", "city" : "MOUNT LOOKOUT", "loc" : [ -80.91077, 38.182109 ], "pop" : 1029, "state" : "WV" }
+{ "_id" : "26679", "city" : "RUNA", "loc" : [ -80.820204, 38.197064 ], "pop" : 1698, "state" : "WV" }
+{ "_id" : "26680", "city" : "RUSSELVILLE", "loc" : [ -80.885777, 38.10829 ], "pop" : 99, "state" : "WV" }
+{ "_id" : "26681", "city" : "NETTIE", "loc" : [ -80.69527100000001, 38.209042 ], "pop" : 1196, "state" : "WV" }
+{ "_id" : "26683", "city" : "POE", "loc" : [ -80.952167, 38.256458 ], "pop" : 818, "state" : "WV" }
+{ "_id" : "26684", "city" : "POOL", "loc" : [ -80.885907, 38.146004 ], "pop" : 112, "state" : "WV" }
+{ "_id" : "26690", "city" : "SWISS", "loc" : [ -81.080703, 38.279058 ], "pop" : 684, "state" : "WV" }
+{ "_id" : "26691", "city" : "TIOGA", "loc" : [ -80.661663, 38.375989 ], "pop" : 808, "state" : "WV" }
+{ "_id" : "26704", "city" : "AUGUSTA", "loc" : [ -78.59308900000001, 39.299821 ], "pop" : 2769, "state" : "WV" }
+{ "_id" : "26705", "city" : "AMBOY", "loc" : [ -79.571088, 39.304719 ], "pop" : 1143, "state" : "WV" }
+{ "_id" : "26710", "city" : "BURLINGTON", "loc" : [ -78.912278, 39.388709 ], "pop" : 3883, "state" : "WV" }
+{ "_id" : "26711", "city" : "CAPON BRIDGE", "loc" : [ -78.46441299999999, 39.280198 ], "pop" : 997, "state" : "WV" }
+{ "_id" : "26713", "city" : "CORINTH", "loc" : [ -79.50396499999999, 39.43183 ], "pop" : 503, "state" : "WV" }
+{ "_id" : "26714", "city" : "DELRAY", "loc" : [ -78.639427, 39.179564 ], "pop" : 467, "state" : "WV" }
+{ "_id" : "26716", "city" : "EGLON", "loc" : [ -79.510919, 39.292514 ], "pop" : 249, "state" : "WV" }
+{ "_id" : "26717", "city" : "ELK GARDEN", "loc" : [ -79.153871, 39.363088 ], "pop" : 1168, "state" : "WV" }
+{ "_id" : "26719", "city" : "FORT ASHBY", "loc" : [ -78.77429600000001, 39.497045 ], "pop" : 2212, "state" : "WV" }
+{ "_id" : "26720", "city" : "GORMANIA", "loc" : [ -79.340136, 39.271499 ], "pop" : 823, "state" : "WV" }
+{ "_id" : "26722", "city" : "GREEN SPRING", "loc" : [ -78.627191, 39.502931 ], "pop" : 739, "state" : "WV" }
+{ "_id" : "26726", "city" : "SCHERR", "loc" : [ -78.98866700000001, 39.430406 ], "pop" : 9579, "state" : "WV" }
+{ "_id" : "26729", "city" : "KIRBY", "loc" : [ -78.73146800000001, 39.195588 ], "pop" : 303, "state" : "WV" }
+{ "_id" : "26731", "city" : "LAHMANSVILLE", "loc" : [ -79.043319, 39.164225 ], "pop" : 32, "state" : "WV" }
+{ "_id" : "26734", "city" : "MEDLEY", "loc" : [ -79.0984, 39.236079 ], "pop" : 430, "state" : "WV" }
+{ "_id" : "26739", "city" : "MOUNT STORM", "loc" : [ -79.225454, 39.265224 ], "pop" : 861, "state" : "WV" }
+{ "_id" : "26743", "city" : "NEW CREEK", "loc" : [ -79.04521200000001, 39.361155 ], "pop" : 1417, "state" : "WV" }
+{ "_id" : "26750", "city" : "PIEDMONT", "loc" : [ -79.048862, 39.479901 ], "pop" : 1094, "state" : "WV" }
+{ "_id" : "26753", "city" : "PATTERSON CREEK", "loc" : [ -78.792006, 39.581796 ], "pop" : 5929, "state" : "WV" }
+{ "_id" : "26755", "city" : "RIO", "loc" : [ -78.69354800000001, 39.180663 ], "pop" : 47, "state" : "WV" }
+{ "_id" : "26757", "city" : "ROMNEY", "loc" : [ -78.748075, 39.342369 ], "pop" : 4007, "state" : "WV" }
+{ "_id" : "26761", "city" : "SHANKS", "loc" : [ -78.69953099999999, 39.284859 ], "pop" : 779, "state" : "WV" }
+{ "_id" : "26763", "city" : "SPRINGFIELD", "loc" : [ -78.695019, 39.462996 ], "pop" : 1321, "state" : "WV" }
+{ "_id" : "26764", "city" : "HOPEMONT", "loc" : [ -79.55723399999999, 39.441575 ], "pop" : 4487, "state" : "WV" }
+{ "_id" : "26765", "city" : "THREE CHURCHES", "loc" : [ -78.661061, 39.351578 ], "pop" : 1253, "state" : "WV" }
+{ "_id" : "26767", "city" : "WILEY FORD", "loc" : [ -78.774992, 39.613308 ], "pop" : 1139, "state" : "WV" }
+{ "_id" : "26769", "city" : "HORSE SHOE RUN", "loc" : [ -79.51231199999999, 39.252842 ], "pop" : 367, "state" : "WV" }
+{ "_id" : "26801", "city" : "BAKER", "loc" : [ -78.774826, 39.065588 ], "pop" : 1321, "state" : "WV" }
+{ "_id" : "26802", "city" : "BRANDYWINE", "loc" : [ -79.20962900000001, 38.635701 ], "pop" : 941, "state" : "WV" }
+{ "_id" : "26804", "city" : "CIRCLEVILLE", "loc" : [ -79.53672, 38.623039 ], "pop" : 658, "state" : "WV" }
+{ "_id" : "26806", "city" : "FORT SEYBERT", "loc" : [ -79.140781, 38.739489 ], "pop" : 167, "state" : "WV" }
+{ "_id" : "26807", "city" : "FRANKLIN", "loc" : [ -79.353776, 38.639985 ], "pop" : 2733, "state" : "WV" }
+{ "_id" : "26808", "city" : "HIGH VIEW", "loc" : [ -78.442548, 39.222497 ], "pop" : 922, "state" : "WV" }
+{ "_id" : "26810", "city" : "LOST CITY", "loc" : [ -78.822684, 38.895361 ], "pop" : 190, "state" : "WV" }
+{ "_id" : "26811", "city" : "LOST RIVER", "loc" : [ -78.79317, 38.93448 ], "pop" : 167, "state" : "WV" }
+{ "_id" : "26812", "city" : "MATHIAS", "loc" : [ -78.88141299999999, 38.874443 ], "pop" : 1228, "state" : "WV" }
+{ "_id" : "26813", "city" : "MOYERS", "loc" : [ -79.383011, 38.500561 ], "pop" : 461, "state" : "WV" }
+{ "_id" : "26814", "city" : "RIVERTON", "loc" : [ -79.465531, 38.697871 ], "pop" : 348, "state" : "WV" }
+{ "_id" : "26815", "city" : "SUGAR GROVE", "loc" : [ -79.290329, 38.52011 ], "pop" : 512, "state" : "WV" }
+{ "_id" : "26816", "city" : "ARTHUR", "loc" : [ -79.099576, 39.101237 ], "pop" : 581, "state" : "WV" }
+{ "_id" : "26817", "city" : "BLOOMERY", "loc" : [ -78.381561, 39.328606 ], "pop" : 675, "state" : "WV" }
+{ "_id" : "26818", "city" : "FISHER", "loc" : [ -78.988756, 39.04796 ], "pop" : 1, "state" : "WV" }
+{ "_id" : "26824", "city" : "JUNCTION", "loc" : [ -78.832785, 39.330441 ], "pop" : 200, "state" : "WV" }
+{ "_id" : "26833", "city" : "MAYSVILLE", "loc" : [ -79.19370000000001, 39.071174 ], "pop" : 2615, "state" : "WV" }
+{ "_id" : "26836", "city" : "RIG", "loc" : [ -78.97793, 39.056812 ], "pop" : 6314, "state" : "WV" }
+{ "_id" : "26838", "city" : "MILAM", "loc" : [ -79.072936, 38.812526 ], "pop" : 30, "state" : "WV" }
+{ "_id" : "26845", "city" : "OLD FIELDS", "loc" : [ -78.95094400000001, 39.150245 ], "pop" : 120, "state" : "WV" }
+{ "_id" : "26847", "city" : "DORCAS", "loc" : [ -79.130701, 38.976602 ], "pop" : 4991, "state" : "WV" }
+{ "_id" : "26851", "city" : "WARDENSVILLE", "loc" : [ -78.617457, 39.056238 ], "pop" : 1606, "state" : "WV" }
+{ "_id" : "26852", "city" : "PURGITSVILLE", "loc" : [ -78.905951, 39.268065 ], "pop" : 672, "state" : "WV" }
+{ "_id" : "26855", "city" : "CABINS", "loc" : [ -79.27833200000001, 38.951199 ], "pop" : 95, "state" : "WV" }
+{ "_id" : "26865", "city" : "LEHEW", "loc" : [ -78.494998, 39.183038 ], "pop" : 190, "state" : "WV" }
+{ "_id" : "26866", "city" : "UPPER TRACT", "loc" : [ -79.258589, 38.794952 ], "pop" : 1161, "state" : "WV" }
+{ "_id" : "26884", "city" : "SENECA ROCKS", "loc" : [ -79.386577, 38.829615 ], "pop" : 840, "state" : "WV" }
+{ "_id" : "26886", "city" : "ONEGO", "loc" : [ -79.45070200000001, 38.801718 ], "pop" : 233, "state" : "WV" }
+{ "_id" : "27006", "city" : "ADVANCE", "loc" : [ -80.44630100000001, 36.006496 ], "pop" : 3325, "state" : "NC" }
+{ "_id" : "27007", "city" : "ARARAT", "loc" : [ -80.608887, 36.386932 ], "pop" : 3101, "state" : "NC" }
+{ "_id" : "27009", "city" : "BELEWS CREEK", "loc" : [ -80.09298800000001, 36.226874 ], "pop" : 1556, "state" : "NC" }
+{ "_id" : "27011", "city" : "BOONVILLE", "loc" : [ -80.63569, 36.234012 ], "pop" : 262, "state" : "NC" }
+{ "_id" : "27012", "city" : "CLEMMONS", "loc" : [ -80.39623, 36.034112 ], "pop" : 12694, "state" : "NC" }
+{ "_id" : "27013", "city" : "CLEVELAND", "loc" : [ -80.711254, 35.737397 ], "pop" : 4070, "state" : "NC" }
+{ "_id" : "27016", "city" : "DANBURY", "loc" : [ -80.219354, 36.455857 ], "pop" : 1560, "state" : "NC" }
+{ "_id" : "27017", "city" : "DOBSON", "loc" : [ -80.710065, 36.369826 ], "pop" : 6092, "state" : "NC" }
+{ "_id" : "27018", "city" : "EAST BEND", "loc" : [ -80.52840500000001, 36.203152 ], "pop" : 6140, "state" : "NC" }
+{ "_id" : "27019", "city" : "GERMANTON", "loc" : [ -80.225432, 36.272513 ], "pop" : 4428, "state" : "NC" }
+{ "_id" : "27020", "city" : "HAMPTONVILLE", "loc" : [ -80.813687, 36.124248 ], "pop" : 4691, "state" : "NC" }
+{ "_id" : "27021", "city" : "KING", "loc" : [ -80.355957, 36.295033 ], "pop" : 12631, "state" : "NC" }
+{ "_id" : "27022", "city" : "LAWSONVILLE", "loc" : [ -80.210291, 36.513228 ], "pop" : 1550, "state" : "NC" }
+{ "_id" : "27023", "city" : "LEWISVILLE", "loc" : [ -80.420638, 36.0967 ], "pop" : 7165, "state" : "NC" }
+{ "_id" : "27024", "city" : "LOWGAP", "loc" : [ -80.78886199999999, 36.503041 ], "pop" : 5065, "state" : "NC" }
+{ "_id" : "27025", "city" : "MADISON", "loc" : [ -79.96543800000001, 36.369507 ], "pop" : 10393, "state" : "NC" }
+{ "_id" : "27027", "city" : "MAYODAN", "loc" : [ -79.95674200000001, 36.427677 ], "pop" : 6545, "state" : "NC" }
+{ "_id" : "27028", "city" : "MOCKSVILLE", "loc" : [ -80.536965, 35.922007 ], "pop" : 24999, "state" : "NC" }
+{ "_id" : "27030", "city" : "MOUNT AIRY", "loc" : [ -80.61187099999999, 36.500739 ], "pop" : 29155, "state" : "NC" }
+{ "_id" : "27040", "city" : "PFAFFTOWN", "loc" : [ -80.37982599999999, 36.166914 ], "pop" : 8160, "state" : "NC" }
+{ "_id" : "27041", "city" : "PILOT MOUNTAIN", "loc" : [ -80.492065, 36.41094 ], "pop" : 7058, "state" : "NC" }
+{ "_id" : "27042", "city" : "PINE HALL", "loc" : [ -80.049533, 36.348178 ], "pop" : 377, "state" : "NC" }
+{ "_id" : "27043", "city" : "PINNACLE", "loc" : [ -80.439111, 36.333905 ], "pop" : 4275, "state" : "NC" }
+{ "_id" : "27045", "city" : "RURAL HALL", "loc" : [ -80.293643, 36.229251 ], "pop" : 6635, "state" : "NC" }
+{ "_id" : "27046", "city" : "SANDY RIDGE", "loc" : [ -80.085857, 36.489973 ], "pop" : 1580, "state" : "NC" }
+{ "_id" : "27047", "city" : "SILOAM", "loc" : [ -80.577162, 36.300208 ], "pop" : 524, "state" : "NC" }
+{ "_id" : "27048", "city" : "STONEVILLE", "loc" : [ -79.901297, 36.470483 ], "pop" : 4166, "state" : "NC" }
+{ "_id" : "27050", "city" : "TOBACCOVILLE", "loc" : [ -80.391549, 36.233627 ], "pop" : 2697, "state" : "NC" }
+{ "_id" : "27051", "city" : "WALKERTOWN", "loc" : [ -80.162865, 36.179999 ], "pop" : 6199, "state" : "NC" }
+{ "_id" : "27052", "city" : "WALNUT COVE", "loc" : [ -80.148414, 36.318872 ], "pop" : 9048, "state" : "NC" }
+{ "_id" : "27053", "city" : "WESTFIELD", "loc" : [ -80.367739, 36.467405 ], "pop" : 3500, "state" : "NC" }
+{ "_id" : "27054", "city" : "WOODLEAF", "loc" : [ -80.60394100000001, 35.787564 ], "pop" : 2735, "state" : "NC" }
+{ "_id" : "27055", "city" : "YADKINVILLE", "loc" : [ -80.65302, 36.127694 ], "pop" : 11978, "state" : "NC" }
+{ "_id" : "27101", "city" : "WINSTON SALEM", "loc" : [ -80.222798, 36.10237 ], "pop" : 19333, "state" : "NC" }
+{ "_id" : "27103", "city" : "WINSTON SALEM", "loc" : [ -80.302509, 36.067127 ], "pop" : 24299, "state" : "NC" }
+{ "_id" : "27104", "city" : "WINSTON SALEM", "loc" : [ -80.322423, 36.091985 ], "pop" : 23677, "state" : "NC" }
+{ "_id" : "27105", "city" : "WINSTON SALEM", "loc" : [ -80.237646, 36.144039 ], "pop" : 40194, "state" : "NC" }
+{ "_id" : "27106", "city" : "WINSTON SALEM", "loc" : [ -80.306866, 36.142762 ], "pop" : 35209, "state" : "NC" }
+{ "_id" : "27107", "city" : "WINSTON SALEM", "loc" : [ -80.193265, 36.040324 ], "pop" : 33085, "state" : "NC" }
+{ "_id" : "27127", "city" : "WINSTON SALEM", "loc" : [ -80.260946, 36.042534 ], "pop" : 20784, "state" : "NC" }
+{ "_id" : "27203", "city" : "FARMER", "loc" : [ -79.819678, 35.693496 ], "pop" : 41541, "state" : "NC" }
+{ "_id" : "27207", "city" : "BEAR CREEK", "loc" : [ -79.372606, 35.612882 ], "pop" : 3894, "state" : "NC" }
+{ "_id" : "27208", "city" : "BENNETT", "loc" : [ -79.522524, 35.567269 ], "pop" : 1218, "state" : "NC" }
+{ "_id" : "27209", "city" : "BISCOE", "loc" : [ -79.75955500000001, 35.325654 ], "pop" : 3528, "state" : "NC" }
+{ "_id" : "27212", "city" : "BLANCH", "loc" : [ -79.304185, 36.533839 ], "pop" : 94, "state" : "NC" }
+{ "_id" : "27214", "city" : "BROWNS SUMMIT", "loc" : [ -79.71008, 36.201868 ], "pop" : 5688, "state" : "NC" }
+{ "_id" : "27215", "city" : "GLEN RAVEN", "loc" : [ -79.462152, 36.072011 ], "pop" : 29107, "state" : "NC" }
+{ "_id" : "27217", "city" : "BURLINGTON", "loc" : [ -79.411447, 36.1288 ], "pop" : 30651, "state" : "NC" }
+{ "_id" : "27229", "city" : "CANDOR", "loc" : [ -79.787623, 35.22335 ], "pop" : 967, "state" : "NC" }
+{ "_id" : "27231", "city" : "CEDAR GROVE", "loc" : [ -79.166588, 36.201986 ], "pop" : 1594, "state" : "NC" }
+{ "_id" : "27233", "city" : "CLIMAX", "loc" : [ -79.701858, 35.934512 ], "pop" : 1085, "state" : "NC" }
+{ "_id" : "27235", "city" : "COLFAX", "loc" : [ -80.010276, 36.100272 ], "pop" : 1983, "state" : "NC" }
+{ "_id" : "27239", "city" : "DENTON", "loc" : [ -80.09592600000001, 35.619567 ], "pop" : 7102, "state" : "NC" }
+{ "_id" : "27242", "city" : "EAGLE SPRINGS", "loc" : [ -79.630983, 35.335957 ], "pop" : 1742, "state" : "NC" }
+{ "_id" : "27243", "city" : "EFLAND", "loc" : [ -79.18841500000001, 36.091166 ], "pop" : 2661, "state" : "NC" }
+{ "_id" : "27244", "city" : "ELON COLLEGE", "loc" : [ -79.502334, 36.146638 ], "pop" : 10269, "state" : "NC" }
+{ "_id" : "27248", "city" : "FRANKLINVILLE", "loc" : [ -79.713178, 35.791739 ], "pop" : 4613, "state" : "NC" }
+{ "_id" : "27249", "city" : "GIBSONVILLE", "loc" : [ -79.568454, 36.118304 ], "pop" : 8409, "state" : "NC" }
+{ "_id" : "27252", "city" : "GOLDSTON", "loc" : [ -79.33852, 35.56428 ], "pop" : 1814, "state" : "NC" }
+{ "_id" : "27253", "city" : "GRAHAM", "loc" : [ -79.381384, 36.030967 ], "pop" : 19723, "state" : "NC" }
+{ "_id" : "27258", "city" : "HAW RIVER", "loc" : [ -79.334557, 36.055085 ], "pop" : 4964, "state" : "NC" }
+{ "_id" : "27260", "city" : "HIGH POINT", "loc" : [ -80.011673, 35.959313 ], "pop" : 36887, "state" : "NC" }
+{ "_id" : "27262", "city" : "HIGH POINT", "loc" : [ -80.010677, 35.973406 ], "pop" : 11401, "state" : "NC" }
+{ "_id" : "27263", "city" : "ARCHDALE", "loc" : [ -79.961764, 35.910757 ], "pop" : 17140, "state" : "NC" }
+{ "_id" : "27265", "city" : "HIGH POINT", "loc" : [ -80.00357099999999, 36.003584 ], "pop" : 22310, "state" : "NC" }
+{ "_id" : "27278", "city" : "HILLSBOROUGH", "loc" : [ -79.091416, 36.07558 ], "pop" : 15811, "state" : "NC" }
+{ "_id" : "27281", "city" : "JACKSON SPRINGS", "loc" : [ -79.66853500000001, 35.225941 ], "pop" : 2167, "state" : "NC" }
+{ "_id" : "27282", "city" : "JAMESTOWN", "loc" : [ -79.929286, 35.998993 ], "pop" : 9812, "state" : "NC" }
+{ "_id" : "27283", "city" : "JULIAN", "loc" : [ -79.63862899999999, 35.95429 ], "pop" : 2894, "state" : "NC" }
+{ "_id" : "27284", "city" : "KERNERSVILLE", "loc" : [ -80.08311500000001, 36.116534 ], "pop" : 34795, "state" : "NC" }
+{ "_id" : "27288", "city" : "EDEN", "loc" : [ -79.75899800000001, 36.500003 ], "pop" : 26675, "state" : "NC" }
+{ "_id" : "27291", "city" : "LEASBURG", "loc" : [ -79.194188, 36.415113 ], "pop" : 2700, "state" : "NC" }
+{ "_id" : "27292", "city" : "LEXINGTON", "loc" : [ -80.262049, 35.82306 ], "pop" : 69179, "state" : "NC" }
+{ "_id" : "27298", "city" : "LIBERTY", "loc" : [ -79.582144, 35.872878 ], "pop" : 7303, "state" : "NC" }
+{ "_id" : "27299", "city" : "LINWOOD", "loc" : [ -80.374895, 35.75623 ], "pop" : 2823, "state" : "NC" }
+{ "_id" : "27301", "city" : "MC LEANSVILLE", "loc" : [ -79.66838799999999, 36.116291 ], "pop" : 5200, "state" : "NC" }
+{ "_id" : "27302", "city" : "MEBANE", "loc" : [ -79.271895, 36.097862 ], "pop" : 14650, "state" : "NC" }
+{ "_id" : "27305", "city" : "MILTON", "loc" : [ -79.208699, 36.515784 ], "pop" : 1383, "state" : "NC" }
+{ "_id" : "27306", "city" : "MOUNT GILEAD", "loc" : [ -79.98708999999999, 35.227447 ], "pop" : 5829, "state" : "NC" }
+{ "_id" : "27310", "city" : "OAK RIDGE", "loc" : [ -79.980366, 36.167315 ], "pop" : 2231, "state" : "NC" }
+{ "_id" : "27311", "city" : "PELHAM", "loc" : [ -79.47360500000001, 36.489912 ], "pop" : 3964, "state" : "NC" }
+{ "_id" : "27312", "city" : "PITTSBORO", "loc" : [ -79.17550900000001, 35.769436 ], "pop" : 10601, "state" : "NC" }
+{ "_id" : "27313", "city" : "PLEASANT GARDEN", "loc" : [ -79.754943, 35.952243 ], "pop" : 4064, "state" : "NC" }
+{ "_id" : "27314", "city" : "PROSPECT HILL", "loc" : [ -79.215644, 36.293195 ], "pop" : 1116, "state" : "NC" }
+{ "_id" : "27315", "city" : "PROVIDENCE", "loc" : [ -79.36306, 36.48314 ], "pop" : 3462, "state" : "NC" }
+{ "_id" : "27316", "city" : "COLERIDGE", "loc" : [ -79.63510100000001, 35.708349 ], "pop" : 5238, "state" : "NC" }
+{ "_id" : "27317", "city" : "RANDLEMAN", "loc" : [ -79.801794, 35.848805 ], "pop" : 14220, "state" : "NC" }
+{ "_id" : "27320", "city" : "REIDSVILLE", "loc" : [ -79.66421200000001, 36.343209 ], "pop" : 34283, "state" : "NC" }
+{ "_id" : "27325", "city" : "ROBBINS", "loc" : [ -79.58203399999999, 35.452839 ], "pop" : 6383, "state" : "NC" }
+{ "_id" : "27326", "city" : "RUFFIN", "loc" : [ -79.560551, 36.442763 ], "pop" : 4138, "state" : "NC" }
+{ "_id" : "27330", "city" : "COLON", "loc" : [ -79.176446, 35.464148 ], "pop" : 39537, "state" : "NC" }
+{ "_id" : "27341", "city" : "SEAGROVE", "loc" : [ -79.69786999999999, 35.528309 ], "pop" : 4656, "state" : "NC" }
+{ "_id" : "27343", "city" : "SEMORA", "loc" : [ -79.094168, 36.511414 ], "pop" : 1214, "state" : "NC" }
+{ "_id" : "27344", "city" : "SILER CITY", "loc" : [ -79.45662400000001, 35.735392 ], "pop" : 12298, "state" : "NC" }
+{ "_id" : "27349", "city" : "SNOW CAMP", "loc" : [ -79.427893, 35.906583 ], "pop" : 3424, "state" : "NC" }
+{ "_id" : "27350", "city" : "SOPHIA", "loc" : [ -79.898634, 35.829845 ], "pop" : 4165, "state" : "NC" }
+{ "_id" : "27355", "city" : "STALEY", "loc" : [ -79.584391, 35.801485 ], "pop" : 1747, "state" : "NC" }
+{ "_id" : "27356", "city" : "STAR", "loc" : [ -79.782607, 35.421113 ], "pop" : 3077, "state" : "NC" }
+{ "_id" : "27357", "city" : "STOKESDALE", "loc" : [ -79.970528, 36.255217 ], "pop" : 3807, "state" : "NC" }
+{ "_id" : "27358", "city" : "SUMMERFIELD", "loc" : [ -79.890136, 36.224454 ], "pop" : 5937, "state" : "NC" }
+{ "_id" : "27360", "city" : "THOMASVILLE", "loc" : [ -80.09128, 35.87128 ], "pop" : 32777, "state" : "NC" }
+{ "_id" : "27370", "city" : "TRINITY", "loc" : [ -79.990206, 35.842949 ], "pop" : 14290, "state" : "NC" }
+{ "_id" : "27371", "city" : "TROY", "loc" : [ -79.909252, 35.377702 ], "pop" : 9536, "state" : "NC" }
+{ "_id" : "27376", "city" : "WEST END", "loc" : [ -79.53598, 35.251239 ], "pop" : 5480, "state" : "NC" }
+{ "_id" : "27377", "city" : "WHITSETT", "loc" : [ -79.597151, 36.032981 ], "pop" : 2345, "state" : "NC" }
+{ "_id" : "27379", "city" : "YANCEYVILLE", "loc" : [ -79.346485, 36.390695 ], "pop" : 3011, "state" : "NC" }
+{ "_id" : "27401", "city" : "GREENSBORO", "loc" : [ -79.768151, 36.069741 ], "pop" : 19389, "state" : "NC" }
+{ "_id" : "27403", "city" : "GREENSBORO", "loc" : [ -79.82018100000001, 36.064147 ], "pop" : 21666, "state" : "NC" }
+{ "_id" : "27405", "city" : "GREENSBORO", "loc" : [ -79.77330000000001, 36.121408 ], "pop" : 46387, "state" : "NC" }
+{ "_id" : "27406", "city" : "GREENSBORO", "loc" : [ -79.78205800000001, 36.021969 ], "pop" : 45221, "state" : "NC" }
+{ "_id" : "27407", "city" : "GREENSBORO", "loc" : [ -79.862647, 36.033442 ], "pop" : 29591, "state" : "NC" }
+{ "_id" : "27408", "city" : "GREENSBORO", "loc" : [ -79.816531, 36.1064 ], "pop" : 19970, "state" : "NC" }
+{ "_id" : "27409", "city" : "GREENSBORO", "loc" : [ -79.908602, 36.077683 ], "pop" : 8734, "state" : "NC" }
+{ "_id" : "27410", "city" : "GREENSBORO", "loc" : [ -79.87936500000001, 36.103164 ], "pop" : 33819, "state" : "NC" }
+{ "_id" : "27501", "city" : "ANGIER", "loc" : [ -78.724931, 35.489725 ], "pop" : 6349, "state" : "NC" }
+{ "_id" : "27502", "city" : "APEX", "loc" : [ -78.840816, 35.722504 ], "pop" : 19391, "state" : "NC" }
+{ "_id" : "27503", "city" : "BAHAMA", "loc" : [ -78.89028399999999, 36.156581 ], "pop" : 3276, "state" : "NC" }
+{ "_id" : "27504", "city" : "BENSON", "loc" : [ -78.54213, 35.403661 ], "pop" : 9995, "state" : "NC" }
+{ "_id" : "27505", "city" : "BROADWAY", "loc" : [ -79.043547, 35.418088 ], "pop" : 5551, "state" : "NC" }
+{ "_id" : "27507", "city" : "BULLOCK", "loc" : [ -78.56458000000001, 36.507642 ], "pop" : 1423, "state" : "NC" }
+{ "_id" : "27509", "city" : "BUTNER", "loc" : [ -78.7636, 36.135939 ], "pop" : 6310, "state" : "NC" }
+{ "_id" : "27510", "city" : "CARRBORO", "loc" : [ -79.08183200000001, 35.912409 ], "pop" : 10049, "state" : "NC" }
+{ "_id" : "27511", "city" : "CARY", "loc" : [ -78.77856800000001, 35.764119 ], "pop" : 31040, "state" : "NC" }
+{ "_id" : "27513", "city" : "CARY", "loc" : [ -78.794061, 35.795642 ], "pop" : 15082, "state" : "NC" }
+{ "_id" : "27514", "city" : "CHAPEL HILL", "loc" : [ -79.037189, 35.920322 ], "pop" : 39733, "state" : "NC" }
+{ "_id" : "27516", "city" : "CHAPEL HILL", "loc" : [ -79.099867, 35.916175 ], "pop" : 21377, "state" : "NC" }
+{ "_id" : "27520", "city" : "CLAYTON", "loc" : [ -78.451013, 35.63484 ], "pop" : 15067, "state" : "NC" }
+{ "_id" : "27521", "city" : "COATS", "loc" : [ -78.66270400000001, 35.40822 ], "pop" : 4437, "state" : "NC" }
+{ "_id" : "27522", "city" : "CREEDMOOR", "loc" : [ -78.647587, 36.112433 ], "pop" : 7620, "state" : "NC" }
+{ "_id" : "27524", "city" : "FOUR OAKS", "loc" : [ -78.415282, 35.404017 ], "pop" : 9270, "state" : "NC" }
+{ "_id" : "27525", "city" : "FRANKLINTON", "loc" : [ -78.448618, 36.095505 ], "pop" : 8242, "state" : "NC" }
+{ "_id" : "27526", "city" : "FUQUAY VARINA", "loc" : [ -78.790807, 35.579952 ], "pop" : 16537, "state" : "NC" }
+{ "_id" : "27529", "city" : "GARNER", "loc" : [ -78.597527, 35.681254 ], "pop" : 21063, "state" : "NC" }
+{ "_id" : "27530", "city" : "GRANTHAM", "loc" : [ -78.01581299999999, 35.382585 ], "pop" : 37791, "state" : "NC" }
+{ "_id" : "27531", "city" : "SEYMOUR JOHNSON", "loc" : [ -77.96431200000001, 35.352611 ], "pop" : 4747, "state" : "NC" }
+{ "_id" : "27534", "city" : "GOLDSBORO", "loc" : [ -77.92206899999999, 35.36643 ], "pop" : 31892, "state" : "NC" }
+{ "_id" : "27536", "city" : "HENDERSON", "loc" : [ -78.39808600000001, 36.330068 ], "pop" : 36983, "state" : "NC" }
+{ "_id" : "27540", "city" : "HOLLY SPRINGS", "loc" : [ -78.845816, 35.626263 ], "pop" : 2282, "state" : "NC" }
+{ "_id" : "27541", "city" : "HURDLE MILLS", "loc" : [ -79.08266, 36.251788 ], "pop" : 2773, "state" : "NC" }
+{ "_id" : "27542", "city" : "KENLY", "loc" : [ -78.138227, 35.607742 ], "pop" : 6729, "state" : "NC" }
+{ "_id" : "27544", "city" : "KITTRELL", "loc" : [ -78.42407300000001, 36.204175 ], "pop" : 2967, "state" : "NC" }
+{ "_id" : "27545", "city" : "KNIGHTDALE", "loc" : [ -78.489814, 35.778926 ], "pop" : 11525, "state" : "NC" }
+{ "_id" : "27546", "city" : "LILLINGTON", "loc" : [ -78.921223, 35.331954 ], "pop" : 23302, "state" : "NC" }
+{ "_id" : "27549", "city" : "LOUISBURG", "loc" : [ -78.25862499999999, 36.05781 ], "pop" : 20285, "state" : "NC" }
+{ "_id" : "27551", "city" : "MACON", "loc" : [ -77.99870900000001, 36.444697 ], "pop" : 4044, "state" : "NC" }
+{ "_id" : "27553", "city" : "MANSON", "loc" : [ -78.29525, 36.460264 ], "pop" : 1976, "state" : "NC" }
+{ "_id" : "27557", "city" : "MIDDLESEX", "loc" : [ -78.20616200000001, 35.766499 ], "pop" : 4318, "state" : "NC" }
+{ "_id" : "27559", "city" : "MONCURE", "loc" : [ -79.083915, 35.630615 ], "pop" : 2695, "state" : "NC" }
+{ "_id" : "27560", "city" : "MORRISVILLE", "loc" : [ -78.846594, 35.834371 ], "pop" : 3922, "state" : "NC" }
+{ "_id" : "27562", "city" : "NEW HILL", "loc" : [ -78.93653399999999, 35.680877 ], "pop" : 991, "state" : "NC" }
+{ "_id" : "27563", "city" : "NORLINA", "loc" : [ -78.189455, 36.475364 ], "pop" : 3605, "state" : "NC" }
+{ "_id" : "27565", "city" : "OXFORD", "loc" : [ -78.613433, 36.331269 ], "pop" : 20568, "state" : "NC" }
+{ "_id" : "27569", "city" : "PRINCETON", "loc" : [ -78.167368, 35.455833 ], "pop" : 5378, "state" : "NC" }
+{ "_id" : "27571", "city" : "ROLESVILLE", "loc" : [ -78.46584300000001, 35.915575 ], "pop" : 3975, "state" : "NC" }
+{ "_id" : "27572", "city" : "ROUGEMONT", "loc" : [ -78.901867, 36.239251 ], "pop" : 4253, "state" : "NC" }
+{ "_id" : "27573", "city" : "ROXBORO", "loc" : [ -78.973698, 36.405902 ], "pop" : 22321, "state" : "NC" }
+{ "_id" : "27576", "city" : "SELMA", "loc" : [ -78.264025, 35.556531 ], "pop" : 13335, "state" : "NC" }
+{ "_id" : "27577", "city" : "SMITHFIELD", "loc" : [ -78.347866, 35.50684 ], "pop" : 15031, "state" : "NC" }
+{ "_id" : "27581", "city" : "STEM", "loc" : [ -78.70012, 36.21004 ], "pop" : 2421, "state" : "NC" }
+{ "_id" : "27583", "city" : "TIMBERLAKE", "loc" : [ -78.935287, 36.291763 ], "pop" : 3424, "state" : "NC" }
+{ "_id" : "27587", "city" : "WAKE FOREST", "loc" : [ -78.539213, 35.981544 ], "pop" : 11878, "state" : "NC" }
+{ "_id" : "27589", "city" : "WARRENTON", "loc" : [ -78.159389, 36.353944 ], "pop" : 8240, "state" : "NC" }
+{ "_id" : "27591", "city" : "WENDELL", "loc" : [ -78.392601, 35.797964 ], "pop" : 12418, "state" : "NC" }
+{ "_id" : "27592", "city" : "WILLOW SPRING", "loc" : [ -78.671738, 35.547031 ], "pop" : 4672, "state" : "NC" }
+{ "_id" : "27596", "city" : "YOUNGSVILLE", "loc" : [ -78.441198, 36.007782 ], "pop" : 4549, "state" : "NC" }
+{ "_id" : "27597", "city" : "ZEBULON", "loc" : [ -78.317368, 35.832078 ], "pop" : 10153, "state" : "NC" }
+{ "_id" : "27601", "city" : "RALEIGH", "loc" : [ -78.63243900000001, 35.772701 ], "pop" : 9810, "state" : "NC" }
+{ "_id" : "27603", "city" : "RALEIGH", "loc" : [ -78.656265, 35.707569 ], "pop" : 25366, "state" : "NC" }
+{ "_id" : "27604", "city" : "RALEIGH", "loc" : [ -78.579949, 35.833407 ], "pop" : 35217, "state" : "NC" }
+{ "_id" : "27605", "city" : "RALEIGH", "loc" : [ -78.653025, 35.790795 ], "pop" : 4169, "state" : "NC" }
+{ "_id" : "27606", "city" : "RALEIGH", "loc" : [ -78.711189, 35.764499 ], "pop" : 29446, "state" : "NC" }
+{ "_id" : "27607", "city" : "RALEIGH", "loc" : [ -78.687747, 35.801385 ], "pop" : 19515, "state" : "NC" }
+{ "_id" : "27608", "city" : "RALEIGH", "loc" : [ -78.646277, 35.807746 ], "pop" : 10130, "state" : "NC" }
+{ "_id" : "27609", "city" : "RALEIGH", "loc" : [ -78.631654, 35.847989 ], "pop" : 29872, "state" : "NC" }
+{ "_id" : "27610", "city" : "RALEIGH", "loc" : [ -78.60075999999999, 35.766674 ], "pop" : 32494, "state" : "NC" }
+{ "_id" : "27612", "city" : "RALEIGH", "loc" : [ -78.684119, 35.851997 ], "pop" : 20962, "state" : "NC" }
+{ "_id" : "27613", "city" : "RALEIGH", "loc" : [ -78.70505900000001, 35.894932 ], "pop" : 19518, "state" : "NC" }
+{ "_id" : "27614", "city" : "RALEIGH", "loc" : [ -78.643339, 35.945711 ], "pop" : 7200, "state" : "NC" }
+{ "_id" : "27615", "city" : "RALEIGH", "loc" : [ -78.63927700000001, 35.888744 ], "pop" : 29771, "state" : "NC" }
+{ "_id" : "27701", "city" : "DURHAM", "loc" : [ -78.896613, 35.996725 ], "pop" : 20284, "state" : "NC" }
+{ "_id" : "27703", "city" : "DURHAM", "loc" : [ -78.843874, 35.978122 ], "pop" : 24362, "state" : "NC" }
+{ "_id" : "27704", "city" : "DURHAM", "loc" : [ -78.876437, 36.038297 ], "pop" : 23460, "state" : "NC" }
+{ "_id" : "27705", "city" : "DURHAM", "loc" : [ -78.947776, 36.021846 ], "pop" : 32916, "state" : "NC" }
+{ "_id" : "27706", "city" : "DURHAM", "loc" : [ -78.937524, 36.002427 ], "pop" : 4790, "state" : "NC" }
+{ "_id" : "27707", "city" : "DURHAM", "loc" : [ -78.931484, 35.963076 ], "pop" : 36264, "state" : "NC" }
+{ "_id" : "27712", "city" : "DURHAM", "loc" : [ -78.929919, 36.091779 ], "pop" : 15138, "state" : "NC" }
+{ "_id" : "27713", "city" : "RESEARCH TRIANGL", "loc" : [ -78.916641, 35.916105 ], "pop" : 19493, "state" : "NC" }
+{ "_id" : "27801", "city" : "ROCKY MOUNT", "loc" : [ -77.76081600000001, 35.94265 ], "pop" : 25072, "state" : "NC" }
+{ "_id" : "27803", "city" : "ROCKY MOUNT", "loc" : [ -77.835022, 35.923784 ], "pop" : 20416, "state" : "NC" }
+{ "_id" : "27804", "city" : "WESLEYAN COLLEGE", "loc" : [ -77.82754300000001, 35.979634 ], "pop" : 24367, "state" : "NC" }
+{ "_id" : "27805", "city" : "AULANDER", "loc" : [ -77.114086, 36.147452 ], "pop" : 4880, "state" : "NC" }
+{ "_id" : "27806", "city" : "AURORA", "loc" : [ -76.799448, 35.302282 ], "pop" : 2957, "state" : "NC" }
+{ "_id" : "27807", "city" : "BAILEY", "loc" : [ -78.089226, 35.807167 ], "pop" : 4399, "state" : "NC" }
+{ "_id" : "27808", "city" : "BATH", "loc" : [ -76.771531, 35.470161 ], "pop" : 1915, "state" : "NC" }
+{ "_id" : "27809", "city" : "BATTLEBORO", "loc" : [ -77.431107, 35.84387 ], "pop" : 808, "state" : "NC" }
+{ "_id" : "27810", "city" : "BELHAVEN", "loc" : [ -76.623574, 35.520493 ], "pop" : 4130, "state" : "NC" }
+{ "_id" : "27812", "city" : "BETHEL", "loc" : [ -77.374765, 35.790885 ], "pop" : 3116, "state" : "NC" }
+{ "_id" : "27814", "city" : "BLOUNTS CREEK", "loc" : [ -76.925004, 35.382029 ], "pop" : 1272, "state" : "NC" }
+{ "_id" : "27816", "city" : "CASTALIA", "loc" : [ -78.070452, 36.090124 ], "pop" : 2623, "state" : "NC" }
+{ "_id" : "27817", "city" : "CHOCOWINITY", "loc" : [ -77.08680099999999, 35.481409 ], "pop" : 5553, "state" : "NC" }
+{ "_id" : "27818", "city" : "COMO", "loc" : [ -77.051526, 36.497818 ], "pop" : 1484, "state" : "NC" }
+{ "_id" : "27820", "city" : "CONWAY", "loc" : [ -77.250243, 36.416382 ], "pop" : 3474, "state" : "NC" }
+{ "_id" : "27821", "city" : "EDWARD", "loc" : [ -76.87938800000001, 35.323588 ], "pop" : 122, "state" : "NC" }
+{ "_id" : "27822", "city" : "ELM CITY", "loc" : [ -77.856032, 35.810954 ], "pop" : 8507, "state" : "NC" }
+{ "_id" : "27823", "city" : "ENFIELD", "loc" : [ -77.712907, 36.197331 ], "pop" : 8876, "state" : "NC" }
+{ "_id" : "27824", "city" : "MIDDLETOWN", "loc" : [ -76.037434, 35.49806 ], "pop" : 1822, "state" : "NC" }
+{ "_id" : "27826", "city" : "FAIRFIELD", "loc" : [ -76.231768, 35.565873 ], "pop" : 585, "state" : "NC" }
+{ "_id" : "27828", "city" : "FARMVILLE", "loc" : [ -77.579303, 35.580606 ], "pop" : 8260, "state" : "NC" }
+{ "_id" : "27829", "city" : "FOUNTAIN", "loc" : [ -77.621448, 35.669436 ], "pop" : 1419, "state" : "NC" }
+{ "_id" : "27830", "city" : "EUREKA", "loc" : [ -77.996302, 35.518558 ], "pop" : 6803, "state" : "NC" }
+{ "_id" : "27831", "city" : "GARYSBURG", "loc" : [ -77.571905, 36.476147 ], "pop" : 2824, "state" : "NC" }
+{ "_id" : "27832", "city" : "GASTON", "loc" : [ -77.682379, 36.51153 ], "pop" : 2560, "state" : "NC" }
+{ "_id" : "27834", "city" : "GREENVILLE", "loc" : [ -77.397542, 35.619221 ], "pop" : 35377, "state" : "NC" }
+{ "_id" : "27837", "city" : "GRIMESLAND", "loc" : [ -77.256612, 35.558005 ], "pop" : 6998, "state" : "NC" }
+{ "_id" : "27839", "city" : "HALIFAX", "loc" : [ -77.56072500000001, 36.30492 ], "pop" : 4264, "state" : "NC" }
+{ "_id" : "27840", "city" : "HAMILTON", "loc" : [ -77.21762, 35.944119 ], "pop" : 1060, "state" : "NC" }
+{ "_id" : "27842", "city" : "HENRICO", "loc" : [ -77.854625, 36.527409 ], "pop" : 800, "state" : "NC" }
+{ "_id" : "27843", "city" : "HOBGOOD", "loc" : [ -77.436959, 36.004281 ], "pop" : 2408, "state" : "NC" }
+{ "_id" : "27844", "city" : "HOLLISTER", "loc" : [ -77.931916, 36.25898 ], "pop" : 2691, "state" : "NC" }
+{ "_id" : "27845", "city" : "JACKSON", "loc" : [ -77.468144, 36.386984 ], "pop" : 2703, "state" : "NC" }
+{ "_id" : "27846", "city" : "JAMESVILLE", "loc" : [ -76.898332, 35.78385 ], "pop" : 3141, "state" : "NC" }
+{ "_id" : "27847", "city" : "KELFORD", "loc" : [ -77.259214, 36.199173 ], "pop" : 150, "state" : "NC" }
+{ "_id" : "27848", "city" : "LASKER", "loc" : [ -77.348266, 36.376664 ], "pop" : 80, "state" : "NC" }
+{ "_id" : "27849", "city" : "LEWISTON WOODVIL", "loc" : [ -77.206631, 36.134416 ], "pop" : 634, "state" : "NC" }
+{ "_id" : "27850", "city" : "LITTLETON", "loc" : [ -77.85281500000001, 36.416877 ], "pop" : 4388, "state" : "NC" }
+{ "_id" : "27851", "city" : "LUCAMA", "loc" : [ -78.019687, 35.641504 ], "pop" : 4537, "state" : "NC" }
+{ "_id" : "27852", "city" : "CRISP", "loc" : [ -77.596442, 35.773741 ], "pop" : 4145, "state" : "NC" }
+{ "_id" : "27853", "city" : "MARGARETTSVILLE", "loc" : [ -77.325997, 36.524494 ], "pop" : 289, "state" : "NC" }
+{ "_id" : "27855", "city" : "MURFREESBORO", "loc" : [ -77.10269599999999, 36.43192 ], "pop" : 6186, "state" : "NC" }
+{ "_id" : "27856", "city" : "NASHVILLE", "loc" : [ -77.959485, 35.98428 ], "pop" : 12069, "state" : "NC" }
+{ "_id" : "27857", "city" : "OAK CITY", "loc" : [ -77.30036200000001, 35.959736 ], "pop" : 2268, "state" : "NC" }
+{ "_id" : "27858", "city" : "GREENVILLE", "loc" : [ -77.348505, 35.586567 ], "pop" : 31246, "state" : "NC" }
+{ "_id" : "27859", "city" : "PALMYRA", "loc" : [ -77.364288, 36.106268 ], "pop" : 344, "state" : "NC" }
+{ "_id" : "27860", "city" : "PANTEGO", "loc" : [ -76.698848, 35.620058 ], "pop" : 1915, "state" : "NC" }
+{ "_id" : "27862", "city" : "PENDLETON", "loc" : [ -77.191112, 36.493676 ], "pop" : 1127, "state" : "NC" }
+{ "_id" : "27863", "city" : "PIKEVILLE", "loc" : [ -77.957787, 35.49289 ], "pop" : 1968, "state" : "NC" }
+{ "_id" : "27864", "city" : "PINETOPS", "loc" : [ -77.691952, 35.819611 ], "pop" : 5935, "state" : "NC" }
+{ "_id" : "27865", "city" : "PINETOWN", "loc" : [ -76.807565, 35.57576 ], "pop" : 1829, "state" : "NC" }
+{ "_id" : "27866", "city" : "PLEASANT HILL", "loc" : [ -77.519217, 36.521246 ], "pop" : 639, "state" : "NC" }
+{ "_id" : "27869", "city" : "RICH SQUARE", "loc" : [ -77.296947, 36.277256 ], "pop" : 2621, "state" : "NC" }
+{ "_id" : "27870", "city" : "ROANOKE RAPIDS", "loc" : [ -77.67306000000001, 36.446146 ], "pop" : 25628, "state" : "NC" }
+{ "_id" : "27871", "city" : "ROBERSONVILLE", "loc" : [ -77.26004, 35.821797 ], "pop" : 4941, "state" : "NC" }
+{ "_id" : "27872", "city" : "ROXOBEL", "loc" : [ -77.22706100000001, 36.194464 ], "pop" : 623, "state" : "NC" }
+{ "_id" : "27873", "city" : "SARATOGA", "loc" : [ -77.767613, 35.662778 ], "pop" : 1870, "state" : "NC" }
+{ "_id" : "27874", "city" : "SCOTLAND NECK", "loc" : [ -77.427274, 36.130141 ], "pop" : 5219, "state" : "NC" }
+{ "_id" : "27875", "city" : "SCRANTON", "loc" : [ -76.49170599999999, 35.525039 ], "pop" : 1184, "state" : "NC" }
+{ "_id" : "27876", "city" : "SEABOARD", "loc" : [ -77.411306, 36.488552 ], "pop" : 1767, "state" : "NC" }
+{ "_id" : "27880", "city" : "SIMS", "loc" : [ -78.085854, 35.74351 ], "pop" : 2214, "state" : "NC" }
+{ "_id" : "27882", "city" : "SPRING HOPE", "loc" : [ -78.10850000000001, 35.930193 ], "pop" : 6180, "state" : "NC" }
+{ "_id" : "27883", "city" : "STANTONSBURG", "loc" : [ -77.837773, 35.593998 ], "pop" : 2117, "state" : "NC" }
+{ "_id" : "27884", "city" : "STOKES", "loc" : [ -77.272178, 35.710402 ], "pop" : 922, "state" : "NC" }
+{ "_id" : "27885", "city" : "SWANQUARTER", "loc" : [ -76.287521, 35.422207 ], "pop" : 1203, "state" : "NC" }
+{ "_id" : "27886", "city" : "TARBORO", "loc" : [ -77.542067, 35.898257 ], "pop" : 16144, "state" : "NC" }
+{ "_id" : "27888", "city" : "WALSTONBURG", "loc" : [ -77.698336, 35.588204 ], "pop" : 2649, "state" : "NC" }
+{ "_id" : "27889", "city" : "WASHINGTON", "loc" : [ -77.140356, 35.588392 ], "pop" : 865, "state" : "NC" }
+{ "_id" : "27890", "city" : "WELDON", "loc" : [ -77.60346, 36.420643 ], "pop" : 2819, "state" : "NC" }
+{ "_id" : "27891", "city" : "WHITAKERS", "loc" : [ -77.71674299999999, 36.075797 ], "pop" : 6281, "state" : "NC" }
+{ "_id" : "27892", "city" : "WILLIAMSTON", "loc" : [ -77.048344, 35.660154 ], "pop" : 36648, "state" : "NC" }
+{ "_id" : "27893", "city" : "WILSON", "loc" : [ -77.92273299999999, 35.727022 ], "pop" : 47823, "state" : "NC" }
+{ "_id" : "27897", "city" : "GEORGE", "loc" : [ -77.197782, 36.320465 ], "pop" : 2164, "state" : "NC" }
+{ "_id" : "27909", "city" : "ELIZABETH CITY", "loc" : [ -76.24454799999999, 36.295051 ], "pop" : 31298, "state" : "NC" }
+{ "_id" : "27910", "city" : "AHOSKIE", "loc" : [ -76.99663200000001, 36.295737 ], "pop" : 11451, "state" : "NC" }
+{ "_id" : "27916", "city" : "AYDLETT", "loc" : [ -75.902914, 36.304469 ], "pop" : 356, "state" : "NC" }
+{ "_id" : "27917", "city" : "BARCO", "loc" : [ -75.97928400000001, 36.358778 ], "pop" : 1031, "state" : "NC" }
+{ "_id" : "27919", "city" : "BELVIDERE", "loc" : [ -76.543586, 36.309644 ], "pop" : 1614, "state" : "NC" }
+{ "_id" : "27921", "city" : "CAMDEN", "loc" : [ -76.150002, 36.324985 ], "pop" : 2439, "state" : "NC" }
+{ "_id" : "27922", "city" : "COFIELD", "loc" : [ -76.874568, 36.333316 ], "pop" : 661, "state" : "NC" }
+{ "_id" : "27923", "city" : "COINJOCK", "loc" : [ -75.934012, 36.375064 ], "pop" : 434, "state" : "NC" }
+{ "_id" : "27924", "city" : "COLERAIN", "loc" : [ -76.854799, 36.190083 ], "pop" : 3709, "state" : "NC" }
+{ "_id" : "27925", "city" : "COLUMBIA", "loc" : [ -76.234481, 35.905664 ], "pop" : 3650, "state" : "NC" }
+{ "_id" : "27926", "city" : "CORAPEAKE", "loc" : [ -76.597852, 36.517946 ], "pop" : 1377, "state" : "NC" }
+{ "_id" : "27927", "city" : "COROLLA", "loc" : [ -75.81321699999999, 36.320646 ], "pop" : 288, "state" : "NC" }
+{ "_id" : "27928", "city" : "CRESWELL", "loc" : [ -76.419555, 35.865303 ], "pop" : 2287, "state" : "NC" }
+{ "_id" : "27929", "city" : "CURRITUCK", "loc" : [ -75.988399, 36.429691 ], "pop" : 498, "state" : "NC" }
+{ "_id" : "27932", "city" : "EDENTON", "loc" : [ -76.622384, 36.090777 ], "pop" : 11572, "state" : "NC" }
+{ "_id" : "27935", "city" : "EURE", "loc" : [ -76.846341, 36.434117 ], "pop" : 1346, "state" : "NC" }
+{ "_id" : "27937", "city" : "GATES", "loc" : [ -76.764563, 36.503618 ], "pop" : 2598, "state" : "NC" }
+{ "_id" : "27938", "city" : "GATESVILLE", "loc" : [ -76.732462, 36.407171 ], "pop" : 1398, "state" : "NC" }
+{ "_id" : "27939", "city" : "GRANDY", "loc" : [ -75.876808, 36.233889 ], "pop" : 908, "state" : "NC" }
+{ "_id" : "27941", "city" : "HARBINGER", "loc" : [ -75.81214300000001, 36.086392 ], "pop" : 189, "state" : "NC" }
+{ "_id" : "27942", "city" : "HARRELLSVILLE", "loc" : [ -76.77667700000001, 36.286586 ], "pop" : 1046, "state" : "NC" }
+{ "_id" : "27944", "city" : "DURANTS NECK", "loc" : [ -76.424299, 36.177058 ], "pop" : 9357, "state" : "NC" }
+{ "_id" : "27946", "city" : "HOBBSVILLE", "loc" : [ -76.617813, 36.354303 ], "pop" : 722, "state" : "NC" }
+{ "_id" : "27947", "city" : "JARVISBURG", "loc" : [ -75.859469, 36.173963 ], "pop" : 653, "state" : "NC" }
+{ "_id" : "27948", "city" : "KILL DEVIL HILLS", "loc" : [ -75.67565399999999, 36.008793 ], "pop" : 7870, "state" : "NC" }
+{ "_id" : "27949", "city" : "SOUTHERN SHORES", "loc" : [ -75.725373, 36.100694 ], "pop" : 4046, "state" : "NC" }
+{ "_id" : "27950", "city" : "KNOTTS ISLAND", "loc" : [ -75.970247, 36.523167 ], "pop" : 1493, "state" : "NC" }
+{ "_id" : "27953", "city" : "EAST LAKE", "loc" : [ -75.94440400000001, 35.887191 ], "pop" : 139, "state" : "NC" }
+{ "_id" : "27954", "city" : "MANTEO", "loc" : [ -75.671418, 35.894774 ], "pop" : 5726, "state" : "NC" }
+{ "_id" : "27956", "city" : "MAPLE", "loc" : [ -76.003874, 36.398686 ], "pop" : 321, "state" : "NC" }
+{ "_id" : "27957", "city" : "MERRY HILL", "loc" : [ -76.77755999999999, 36.087121 ], "pop" : 1187, "state" : "NC" }
+{ "_id" : "27958", "city" : "MOYOCK", "loc" : [ -76.114575, 36.487094 ], "pop" : 5475, "state" : "NC" }
+{ "_id" : "27959", "city" : "NAGS HEAD", "loc" : [ -75.567592, 35.347209 ], "pop" : 4085, "state" : "NC" }
+{ "_id" : "27962", "city" : "PLYMOUTH", "loc" : [ -76.74314800000001, 35.850826 ], "pop" : 7951, "state" : "NC" }
+{ "_id" : "27964", "city" : "POINT HARBOR", "loc" : [ -75.79828500000001, 36.078114 ], "pop" : 65, "state" : "NC" }
+{ "_id" : "27965", "city" : "POPLAR BRANCH", "loc" : [ -75.88301800000001, 36.257028 ], "pop" : 733, "state" : "NC" }
+{ "_id" : "27966", "city" : "POWELLS POINT", "loc" : [ -75.827314, 36.120674 ], "pop" : 959, "state" : "NC" }
+{ "_id" : "27970", "city" : "ROPER", "loc" : [ -76.580918, 35.899413 ], "pop" : 3869, "state" : "NC" }
+{ "_id" : "27973", "city" : "SHAWBORO", "loc" : [ -76.09445100000001, 36.377875 ], "pop" : 333, "state" : "NC" }
+{ "_id" : "27974", "city" : "SHILOH", "loc" : [ -76.04316799999999, 36.258449 ], "pop" : 1378, "state" : "NC" }
+{ "_id" : "27976", "city" : "SOUTH MILLS", "loc" : [ -76.303284, 36.453576 ], "pop" : 2087, "state" : "NC" }
+{ "_id" : "27978", "city" : "STUMPY POINT", "loc" : [ -75.77909, 35.863007 ], "pop" : 880, "state" : "NC" }
+{ "_id" : "27979", "city" : "SUNBURY", "loc" : [ -76.609568, 36.431605 ], "pop" : 1711, "state" : "NC" }
+{ "_id" : "27980", "city" : "TYNER", "loc" : [ -76.642796, 36.250239 ], "pop" : 1563, "state" : "NC" }
+{ "_id" : "27983", "city" : "WINDSOR", "loc" : [ -76.933612, 36.015881 ], "pop" : 9205, "state" : "NC" }
+{ "_id" : "27986", "city" : "WINTON", "loc" : [ -76.936007, 36.382616 ], "pop" : 1443, "state" : "NC" }
+{ "_id" : "28001", "city" : "ALBEMARLE", "loc" : [ -80.204363, 35.357276 ], "pop" : 26329, "state" : "NC" }
+{ "_id" : "28006", "city" : "ALEXIS", "loc" : [ -81.102204, 35.383613 ], "pop" : 4724, "state" : "NC" }
+{ "_id" : "28012", "city" : "BELMONT", "loc" : [ -81.044016, 35.244029 ], "pop" : 19504, "state" : "NC" }
+{ "_id" : "28016", "city" : "BESSEMER CITY", "loc" : [ -81.28635, 35.284904 ], "pop" : 8858, "state" : "NC" }
+{ "_id" : "28018", "city" : "BOSTIC", "loc" : [ -81.81183, 35.453259 ], "pop" : 3094, "state" : "NC" }
+{ "_id" : "28020", "city" : "CASAR", "loc" : [ -81.63574199999999, 35.514496 ], "pop" : 1646, "state" : "NC" }
+{ "_id" : "28021", "city" : "CHERRYVILLE", "loc" : [ -81.350893, 35.374742 ], "pop" : 16445, "state" : "NC" }
+{ "_id" : "28023", "city" : "CHINA GROVE", "loc" : [ -80.59004, 35.5669 ], "pop" : 13040, "state" : "NC" }
+{ "_id" : "28025", "city" : "CONCORD", "loc" : [ -80.530027, 35.371614 ], "pop" : 15094, "state" : "NC" }
+{ "_id" : "28027", "city" : "CONCORD", "loc" : [ -80.61622699999999, 35.414115 ], "pop" : 39900, "state" : "NC" }
+{ "_id" : "28032", "city" : "CRAMERTON", "loc" : [ -81.083061, 35.23965 ], "pop" : 2835, "state" : "NC" }
+{ "_id" : "28033", "city" : "CROUSE", "loc" : [ -81.34185100000001, 35.483722 ], "pop" : 5431, "state" : "NC" }
+{ "_id" : "28034", "city" : "DALLAS", "loc" : [ -81.1862, 35.334853 ], "pop" : 13328, "state" : "NC" }
+{ "_id" : "28036", "city" : "CORNELIUS", "loc" : [ -80.857229, 35.495692 ], "pop" : 7301, "state" : "NC" }
+{ "_id" : "28037", "city" : "DENVER", "loc" : [ -80.989785, 35.483677 ], "pop" : 6776, "state" : "NC" }
+{ "_id" : "28040", "city" : "ELLENBORO", "loc" : [ -81.770652, 35.334426 ], "pop" : 8287, "state" : "NC" }
+{ "_id" : "28043", "city" : "ALEXANDER MILLS", "loc" : [ -81.86424700000001, 35.301753 ], "pop" : 25940, "state" : "NC" }
+{ "_id" : "28052", "city" : "GASTONIA", "loc" : [ -81.219449, 35.244917 ], "pop" : 37403, "state" : "NC" }
+{ "_id" : "28054", "city" : "GASTONIA", "loc" : [ -81.145409, 35.200537 ], "pop" : 15997, "state" : "NC" }
+{ "_id" : "28056", "city" : "GASTONIA", "loc" : [ -81.14962199999999, 35.258331 ], "pop" : 33472, "state" : "NC" }
+{ "_id" : "28071", "city" : "GOLD HILL", "loc" : [ -80.334558, 35.549784 ], "pop" : 977, "state" : "NC" }
+{ "_id" : "28073", "city" : "GROVER", "loc" : [ -81.45518199999999, 35.183639 ], "pop" : 2011, "state" : "NC" }
+{ "_id" : "28075", "city" : "HARRISBURG", "loc" : [ -80.659401, 35.324731 ], "pop" : 8810, "state" : "NC" }
+{ "_id" : "28078", "city" : "CORNELIUS", "loc" : [ -80.864664, 35.421992 ], "pop" : 15259, "state" : "NC" }
+{ "_id" : "28079", "city" : "INDIAN TRAIL", "loc" : [ -80.65974300000001, 35.08307 ], "pop" : 13274, "state" : "NC" }
+{ "_id" : "28080", "city" : "IRON STATION", "loc" : [ -81.10700900000001, 35.465654 ], "pop" : 9616, "state" : "NC" }
+{ "_id" : "28081", "city" : "KANNAPOLIS", "loc" : [ -80.635875, 35.502016 ], "pop" : 25583, "state" : "NC" }
+{ "_id" : "28083", "city" : "KANNAPOLIS", "loc" : [ -80.601536, 35.484807 ], "pop" : 14113, "state" : "NC" }
+{ "_id" : "28086", "city" : "KINGS MOUNTAIN", "loc" : [ -81.380567, 35.251578 ], "pop" : 21012, "state" : "NC" }
+{ "_id" : "28088", "city" : "LANDIS", "loc" : [ -80.612926, 35.5435 ], "pop" : 2651, "state" : "NC" }
+{ "_id" : "28090", "city" : "LAWNDALE", "loc" : [ -81.533625, 35.444932 ], "pop" : 6842, "state" : "NC" }
+{ "_id" : "28091", "city" : "LILESVILLE", "loc" : [ -79.97208000000001, 34.968914 ], "pop" : 2923, "state" : "NC" }
+{ "_id" : "28092", "city" : "BOGER CITY", "loc" : [ -81.228039, 35.482138 ], "pop" : 24325, "state" : "NC" }
+{ "_id" : "28097", "city" : "LOCUST", "loc" : [ -80.42106099999999, 35.270416 ], "pop" : 3077, "state" : "NC" }
+{ "_id" : "28098", "city" : "LOWELL", "loc" : [ -81.096037, 35.265481 ], "pop" : 3424, "state" : "NC" }
+{ "_id" : "28103", "city" : "MARSHVILLE", "loc" : [ -80.378113, 35.016684 ], "pop" : 7900, "state" : "NC" }
+{ "_id" : "28105", "city" : "STALLINGS", "loc" : [ -80.713568, 35.121879 ], "pop" : 18586, "state" : "NC" }
+{ "_id" : "28107", "city" : "MIDLAND", "loc" : [ -80.531853, 35.247724 ], "pop" : 4012, "state" : "NC" }
+{ "_id" : "28110", "city" : "MONROE", "loc" : [ -80.53722999999999, 35.017775 ], "pop" : 34880, "state" : "NC" }
+{ "_id" : "28112", "city" : "MONROE", "loc" : [ -80.553952, 34.894621 ], "pop" : 9986, "state" : "NC" }
+{ "_id" : "28114", "city" : "MOORESBORO", "loc" : [ -81.67217100000001, 35.248389 ], "pop" : 7554, "state" : "NC" }
+{ "_id" : "28115", "city" : "MOORESVILLE", "loc" : [ -80.82262900000001, 35.577358 ], "pop" : 28805, "state" : "NC" }
+{ "_id" : "28119", "city" : "MORVEN", "loc" : [ -80.002529, 34.85106 ], "pop" : 1808, "state" : "NC" }
+{ "_id" : "28120", "city" : "MOUNT HOLLY", "loc" : [ -81.030567, 35.311872 ], "pop" : 14505, "state" : "NC" }
+{ "_id" : "28124", "city" : "MOUNT PLEASANT", "loc" : [ -80.417081, 35.414576 ], "pop" : 4640, "state" : "NC" }
+{ "_id" : "28125", "city" : "MOUNT ULLA", "loc" : [ -80.72386, 35.638934 ], "pop" : 683, "state" : "NC" }
+{ "_id" : "28127", "city" : "NEW LONDON", "loc" : [ -80.205737, 35.428518 ], "pop" : 5156, "state" : "NC" }
+{ "_id" : "28128", "city" : "NORWOOD", "loc" : [ -80.14326, 35.227493 ], "pop" : 7069, "state" : "NC" }
+{ "_id" : "28129", "city" : "OAKBORO", "loc" : [ -80.341272, 35.245997 ], "pop" : 6336, "state" : "NC" }
+{ "_id" : "28133", "city" : "PEACHLAND", "loc" : [ -80.282943, 35.005434 ], "pop" : 3310, "state" : "NC" }
+{ "_id" : "28134", "city" : "PINEVILLE", "loc" : [ -80.885852, 35.070942 ], "pop" : 4457, "state" : "NC" }
+{ "_id" : "28135", "city" : "POLKTON", "loc" : [ -80.153812, 34.982288 ], "pop" : 6679, "state" : "NC" }
+{ "_id" : "28137", "city" : "RICHFIELD", "loc" : [ -80.267135, 35.511035 ], "pop" : 2307, "state" : "NC" }
+{ "_id" : "28138", "city" : "ROCKWELL", "loc" : [ -80.422568, 35.549437 ], "pop" : 8739, "state" : "NC" }
+{ "_id" : "28139", "city" : "RUTHERFORDTON", "loc" : [ -81.97810699999999, 35.37058 ], "pop" : 10091, "state" : "NC" }
+{ "_id" : "28144", "city" : "SALISBURY", "loc" : [ -80.488945, 35.651498 ], "pop" : 34563, "state" : "NC" }
+{ "_id" : "28146", "city" : "SALISBURY", "loc" : [ -80.46569, 35.667564 ], "pop" : 23261, "state" : "NC" }
+{ "_id" : "28150", "city" : "KINGSTOWN", "loc" : [ -81.58157300000001, 35.347075 ], "pop" : 13326, "state" : "NC" }
+{ "_id" : "28152", "city" : "SHELBY", "loc" : [ -81.53367299999999, 35.268889 ], "pop" : 31162, "state" : "NC" }
+{ "_id" : "28159", "city" : "SPENCER", "loc" : [ -80.431049, 35.695312 ], "pop" : 4083, "state" : "NC" }
+{ "_id" : "28160", "city" : "SPINDALE", "loc" : [ -81.92514199999999, 35.360131 ], "pop" : 4017, "state" : "NC" }
+{ "_id" : "28163", "city" : "STANFIELD", "loc" : [ -80.44067200000001, 35.21061 ], "pop" : 2436, "state" : "NC" }
+{ "_id" : "28164", "city" : "STANLEY", "loc" : [ -81.095921, 35.351565 ], "pop" : 6510, "state" : "NC" }
+{ "_id" : "28166", "city" : "TROUTMAN", "loc" : [ -80.882229, 35.686271 ], "pop" : 5013, "state" : "NC" }
+{ "_id" : "28167", "city" : "UNION MILLS", "loc" : [ -81.96845999999999, 35.47324 ], "pop" : 3731, "state" : "NC" }
+{ "_id" : "28168", "city" : "VALE", "loc" : [ -81.458887, 35.518796 ], "pop" : 3422, "state" : "NC" }
+{ "_id" : "28170", "city" : "WADESBORO", "loc" : [ -80.069586, 34.980938 ], "pop" : 9765, "state" : "NC" }
+{ "_id" : "28173", "city" : "WEDDINGTON", "loc" : [ -80.727901, 34.955334 ], "pop" : 14423, "state" : "NC" }
+{ "_id" : "28174", "city" : "WINGATE", "loc" : [ -80.44759500000001, 34.984666 ], "pop" : 2747, "state" : "NC" }
+{ "_id" : "28202", "city" : "CHARLOTTE", "loc" : [ -80.841864, 35.229002 ], "pop" : 5143, "state" : "NC" }
+{ "_id" : "28203", "city" : "CHARLOTTE", "loc" : [ -80.858279, 35.208139 ], "pop" : 10274, "state" : "NC" }
+{ "_id" : "28204", "city" : "CHARLOTTE", "loc" : [ -80.823149, 35.213178 ], "pop" : 6114, "state" : "NC" }
+{ "_id" : "28205", "city" : "CHARLOTTE", "loc" : [ -80.788129, 35.219951 ], "pop" : 44092, "state" : "NC" }
+{ "_id" : "28206", "city" : "CHARLOTTE", "loc" : [ -80.826505, 35.252173 ], "pop" : 13051, "state" : "NC" }
+{ "_id" : "28207", "city" : "CHARLOTTE", "loc" : [ -80.827248, 35.193474 ], "pop" : 7921, "state" : "NC" }
+{ "_id" : "28208", "city" : "CHARLOTTE", "loc" : [ -80.89635199999999, 35.235795 ], "pop" : 38236, "state" : "NC" }
+{ "_id" : "28209", "city" : "CHARLOTTE", "loc" : [ -80.855926, 35.179629 ], "pop" : 18190, "state" : "NC" }
+{ "_id" : "28210", "city" : "CHARLOTTE", "loc" : [ -80.857749, 35.131586 ], "pop" : 35211, "state" : "NC" }
+{ "_id" : "28211", "city" : "CHARLOTTE", "loc" : [ -80.793244, 35.167653 ], "pop" : 25478, "state" : "NC" }
+{ "_id" : "28212", "city" : "CHARLOTTE", "loc" : [ -80.744777, 35.190797 ], "pop" : 30347, "state" : "NC" }
+{ "_id" : "28213", "city" : "CHARLOTTE", "loc" : [ -80.750079, 35.317868 ], "pop" : 20336, "state" : "NC" }
+{ "_id" : "28214", "city" : "CHARLOTTE", "loc" : [ -80.95708999999999, 35.273095 ], "pop" : 16852, "state" : "NC" }
+{ "_id" : "28215", "city" : "CHARLOTTE", "loc" : [ -80.738669, 35.243962 ], "pop" : 27936, "state" : "NC" }
+{ "_id" : "28216", "city" : "CHARLOTTE", "loc" : [ -80.870216, 35.283377 ], "pop" : 22464, "state" : "NC" }
+{ "_id" : "28217", "city" : "CHARLOTTE", "loc" : [ -81.007848, 35.0972 ], "pop" : 2795, "state" : "NC" }
+{ "_id" : "28226", "city" : "CHARLOTTE", "loc" : [ -80.816675, 35.086856 ], "pop" : 41260, "state" : "NC" }
+{ "_id" : "28227", "city" : "CHARLOTTE", "loc" : [ -80.684634, 35.193612 ], "pop" : 33273, "state" : "NC" }
+{ "_id" : "28262", "city" : "CHARLOTTE", "loc" : [ -80.775958, 35.272506 ], "pop" : 15114, "state" : "NC" }
+{ "_id" : "28269", "city" : "CHARLOTTE", "loc" : [ -80.820941, 35.288635 ], "pop" : 6659, "state" : "NC" }
+{ "_id" : "28270", "city" : "CHARLOTTE", "loc" : [ -80.76687200000001, 35.135473 ], "pop" : 13791, "state" : "NC" }
+{ "_id" : "28273", "city" : "CHARLOTTE", "loc" : [ -80.89667300000001, 35.159646 ], "pop" : 19148, "state" : "NC" }
+{ "_id" : "28277", "city" : "CHARLOTTE", "loc" : [ -80.800174, 35.134486 ], "pop" : 6737, "state" : "NC" }
+{ "_id" : "28278", "city" : "CHARLOTTE", "loc" : [ -80.960421, 35.146685 ], "pop" : 5411, "state" : "NC" }
+{ "_id" : "28301", "city" : "EAST FAYETTEVILL", "loc" : [ -78.84225499999999, 35.05099 ], "pop" : 35253, "state" : "NC" }
+{ "_id" : "28303", "city" : "BONNIE DOONE", "loc" : [ -78.96013499999999, 35.084046 ], "pop" : 35745, "state" : "NC" }
+{ "_id" : "28304", "city" : "FAYETTEVILLE", "loc" : [ -78.970494, 35.025683 ], "pop" : 33868, "state" : "NC" }
+{ "_id" : "28305", "city" : "FAYETTEVILLE", "loc" : [ -78.904658, 35.056022 ], "pop" : 6670, "state" : "NC" }
+{ "_id" : "28306", "city" : "FAYETTEVILLE", "loc" : [ -78.936408, 35.001874 ], "pop" : 20122, "state" : "NC" }
+{ "_id" : "28307", "city" : "FORT BRAGG", "loc" : [ -79.00245700000001, 35.141649 ], "pop" : 37688, "state" : "NC" }
+{ "_id" : "28311", "city" : "FAYETTEVILLE", "loc" : [ -78.898217, 35.129416 ], "pop" : 29497, "state" : "NC" }
+{ "_id" : "28314", "city" : "FAYETTEVILLE", "loc" : [ -79.00798500000001, 35.058322 ], "pop" : 34856, "state" : "NC" }
+{ "_id" : "28315", "city" : "ABERDEEN", "loc" : [ -79.44503899999999, 35.121641 ], "pop" : 7767, "state" : "NC" }
+{ "_id" : "28318", "city" : "AUTRYVILLE", "loc" : [ -78.60211099999999, 35.099673 ], "pop" : 4129, "state" : "NC" }
+{ "_id" : "28320", "city" : "BLADENBORO", "loc" : [ -78.779295, 34.565832 ], "pop" : 7957, "state" : "NC" }
+{ "_id" : "28323", "city" : "BUNNLEVEL", "loc" : [ -78.855189, 35.281057 ], "pop" : 4749, "state" : "NC" }
+{ "_id" : "28326", "city" : "JOHNSONVILLE", "loc" : [ -79.268826, 35.313581 ], "pop" : 1851, "state" : "NC" }
+{ "_id" : "28327", "city" : "CARTHAGE", "loc" : [ -79.396939, 35.306066 ], "pop" : 11774, "state" : "NC" }
+{ "_id" : "28328", "city" : "CLINTON", "loc" : [ -78.326007, 35.015143 ], "pop" : 17737, "state" : "NC" }
+{ "_id" : "28333", "city" : "DUDLEY", "loc" : [ -78.02727400000001, 35.292564 ], "pop" : 8450, "state" : "NC" }
+{ "_id" : "28334", "city" : "DUNN", "loc" : [ -78.61507899999999, 35.316511 ], "pop" : 15795, "state" : "NC" }
+{ "_id" : "28337", "city" : "ELIZABETHTOWN", "loc" : [ -78.574693, 34.64714 ], "pop" : 10444, "state" : "NC" }
+{ "_id" : "28338", "city" : "ELLERBE", "loc" : [ -79.75236099999999, 35.091422 ], "pop" : 4245, "state" : "NC" }
+{ "_id" : "28339", "city" : "ERWIN", "loc" : [ -78.685935, 35.328651 ], "pop" : 5574, "state" : "NC" }
+{ "_id" : "28340", "city" : "MCDONALD", "loc" : [ -79.128596, 34.481402 ], "pop" : 10978, "state" : "NC" }
+{ "_id" : "28341", "city" : "FAISON", "loc" : [ -78.117983, 35.119884 ], "pop" : 2658, "state" : "NC" }
+{ "_id" : "28343", "city" : "GIBSON", "loc" : [ -79.583854, 34.754857 ], "pop" : 1638, "state" : "NC" }
+{ "_id" : "28344", "city" : "GODWIN", "loc" : [ -78.66247199999999, 35.196919 ], "pop" : 1886, "state" : "NC" }
+{ "_id" : "28345", "city" : "HAMLET", "loc" : [ -79.702217, 34.889375 ], "pop" : 13443, "state" : "NC" }
+{ "_id" : "28347", "city" : "HOFFMAN", "loc" : [ -79.56002700000001, 35.032607 ], "pop" : 1073, "state" : "NC" }
+{ "_id" : "28348", "city" : "HOPE MILLS", "loc" : [ -78.93536400000001, 34.953564 ], "pop" : 18396, "state" : "NC" }
+{ "_id" : "28349", "city" : "KENANSVILLE", "loc" : [ -77.967743, 35.039621 ], "pop" : 4998, "state" : "NC" }
+{ "_id" : "28351", "city" : "LAUREL HILL", "loc" : [ -79.54913500000001, 34.823831 ], "pop" : 5726, "state" : "NC" }
+{ "_id" : "28352", "city" : "LAURINBURG", "loc" : [ -79.467316, 34.759869 ], "pop" : 23387, "state" : "NC" }
+{ "_id" : "28356", "city" : "LINDEN", "loc" : [ -78.800361, 35.227645 ], "pop" : 2903, "state" : "NC" }
+{ "_id" : "28357", "city" : "LUMBER BRIDGE", "loc" : [ -79.066417, 34.876192 ], "pop" : 1343, "state" : "NC" }
+{ "_id" : "28358", "city" : "LUMBERTON", "loc" : [ -79.008309, 34.629301 ], "pop" : 42871, "state" : "NC" }
+{ "_id" : "28363", "city" : "MARSTON", "loc" : [ -79.659554, 34.989628 ], "pop" : 963, "state" : "NC" }
+{ "_id" : "28364", "city" : "MAXTON", "loc" : [ -79.309725, 34.733435 ], "pop" : 11494, "state" : "NC" }
+{ "_id" : "28365", "city" : "MOUNT OLIVE", "loc" : [ -78.09833999999999, 35.210923 ], "pop" : 8636, "state" : "NC" }
+{ "_id" : "28366", "city" : "NEWTON GROVE", "loc" : [ -78.42603699999999, 35.221258 ], "pop" : 6775, "state" : "NC" }
+{ "_id" : "28369", "city" : "ORRUM", "loc" : [ -79.031037, 34.447347 ], "pop" : 1915, "state" : "NC" }
+{ "_id" : "28371", "city" : "PARKTON", "loc" : [ -78.996943, 34.900569 ], "pop" : 2195, "state" : "NC" }
+{ "_id" : "28372", "city" : "PEMBROKE", "loc" : [ -79.18337, 34.690198 ], "pop" : 10673, "state" : "NC" }
+{ "_id" : "28374", "city" : "PINEHURST", "loc" : [ -79.47319400000001, 35.188408 ], "pop" : 5803, "state" : "NC" }
+{ "_id" : "28376", "city" : "RAEFORD", "loc" : [ -79.22275999999999, 34.989009 ], "pop" : 20742, "state" : "NC" }
+{ "_id" : "28377", "city" : "RED SPRINGS", "loc" : [ -79.163619, 34.808315 ], "pop" : 8683, "state" : "NC" }
+{ "_id" : "28379", "city" : "ROCKINGHAM", "loc" : [ -79.766566, 34.933613 ], "pop" : 24282, "state" : "NC" }
+{ "_id" : "28382", "city" : "ROSEBORO", "loc" : [ -78.504109, 34.994081 ], "pop" : 6495, "state" : "NC" }
+{ "_id" : "28383", "city" : "ROWLAND", "loc" : [ -79.261843, 34.588664 ], "pop" : 7047, "state" : "NC" }
+{ "_id" : "28384", "city" : "SAINT PAULS", "loc" : [ -78.973077, 34.800962 ], "pop" : 7976, "state" : "NC" }
+{ "_id" : "28385", "city" : "SALEMBURG", "loc" : [ -78.471385, 35.051459 ], "pop" : 2821, "state" : "NC" }
+{ "_id" : "28386", "city" : "SHANNON", "loc" : [ -79.180617, 34.898762 ], "pop" : 2120, "state" : "NC" }
+{ "_id" : "28387", "city" : "SOUTHERN PINES", "loc" : [ -79.39568199999999, 35.169747 ], "pop" : 11523, "state" : "NC" }
+{ "_id" : "28390", "city" : "SPRING LAKE", "loc" : [ -78.978555, 35.182981 ], "pop" : 11537, "state" : "NC" }
+{ "_id" : "28391", "city" : "STEDMAN", "loc" : [ -78.69493199999999, 35.034749 ], "pop" : 4776, "state" : "NC" }
+{ "_id" : "28392", "city" : "TAR HEEL", "loc" : [ -78.81341, 34.746541 ], "pop" : 1989, "state" : "NC" }
+{ "_id" : "28393", "city" : "TURKEY", "loc" : [ -78.212086, 34.985673 ], "pop" : 3224, "state" : "NC" }
+{ "_id" : "28394", "city" : "VASS", "loc" : [ -79.25618900000001, 35.217133 ], "pop" : 3932, "state" : "NC" }
+{ "_id" : "28395", "city" : "WADE", "loc" : [ -78.724929, 35.160559 ], "pop" : 1369, "state" : "NC" }
+{ "_id" : "28396", "city" : "WAGRAM", "loc" : [ -79.39594, 34.904432 ], "pop" : 3007, "state" : "NC" }
+{ "_id" : "28398", "city" : "BOWDENS", "loc" : [ -78.08673899999999, 34.99818 ], "pop" : 5817, "state" : "NC" }
+{ "_id" : "28399", "city" : "WHITE OAK", "loc" : [ -78.73014000000001, 34.766206 ], "pop" : 1292, "state" : "NC" }
+{ "_id" : "28401", "city" : "CAPE FEAR", "loc" : [ -77.937856, 34.225304 ], "pop" : 21522, "state" : "NC" }
+{ "_id" : "28403", "city" : "WILMINGTON", "loc" : [ -77.886213, 34.223653 ], "pop" : 25319, "state" : "NC" }
+{ "_id" : "28405", "city" : "OGDEN", "loc" : [ -77.852937, 34.264065 ], "pop" : 26744, "state" : "NC" }
+{ "_id" : "28409", "city" : "WILMINGTON", "loc" : [ -77.87227, 34.166256 ], "pop" : 17418, "state" : "NC" }
+{ "_id" : "28412", "city" : "WILMINGTON", "loc" : [ -77.914137, 34.157173 ], "pop" : 13932, "state" : "NC" }
+{ "_id" : "28420", "city" : "ASH", "loc" : [ -78.50563699999999, 34.065871 ], "pop" : 2212, "state" : "NC" }
+{ "_id" : "28421", "city" : "ATKINSON", "loc" : [ -78.167108, 34.530445 ], "pop" : 1418, "state" : "NC" }
+{ "_id" : "28422", "city" : "BOLIVIA", "loc" : [ -78.16813999999999, 34.025962 ], "pop" : 3392, "state" : "NC" }
+{ "_id" : "28423", "city" : "BOLTON", "loc" : [ -78.337177, 34.309085 ], "pop" : 3071, "state" : "NC" }
+{ "_id" : "28425", "city" : "BURGAW", "loc" : [ -77.94031699999999, 34.548679 ], "pop" : 6405, "state" : "NC" }
+{ "_id" : "28428", "city" : "CAROLINA BEACH", "loc" : [ -77.896289, 34.036599 ], "pop" : 4524, "state" : "NC" }
+{ "_id" : "28429", "city" : "CASTLE HAYNE", "loc" : [ -77.91085, 34.323596 ], "pop" : 7329, "state" : "NC" }
+{ "_id" : "28430", "city" : "CERRO GORDO", "loc" : [ -78.921571, 34.302483 ], "pop" : 1742, "state" : "NC" }
+{ "_id" : "28431", "city" : "CHADBOURN", "loc" : [ -78.826683, 34.322303 ], "pop" : 2015, "state" : "NC" }
+{ "_id" : "28432", "city" : "CLARENDON", "loc" : [ -78.788844, 34.199517 ], "pop" : 3940, "state" : "NC" }
+{ "_id" : "28433", "city" : "CLARKTON", "loc" : [ -78.631271, 34.503011 ], "pop" : 3493, "state" : "NC" }
+{ "_id" : "28434", "city" : "COUNCIL", "loc" : [ -78.411511, 34.429042 ], "pop" : 2768, "state" : "NC" }
+{ "_id" : "28435", "city" : "CURRIE", "loc" : [ -78.092516, 34.449668 ], "pop" : 2094, "state" : "NC" }
+{ "_id" : "28436", "city" : "DELCO", "loc" : [ -78.19168999999999, 34.327419 ], "pop" : 229, "state" : "NC" }
+{ "_id" : "28438", "city" : "EVERGREEN", "loc" : [ -78.884638, 34.375234 ], "pop" : 3906, "state" : "NC" }
+{ "_id" : "28439", "city" : "FAIR BLUFF", "loc" : [ -79.01750199999999, 34.302275 ], "pop" : 1931, "state" : "NC" }
+{ "_id" : "28441", "city" : "GARLAND", "loc" : [ -78.34142, 34.822906 ], "pop" : 4133, "state" : "NC" }
+{ "_id" : "28442", "city" : "HALLSBORO", "loc" : [ -78.60427199999999, 34.318087 ], "pop" : 2551, "state" : "NC" }
+{ "_id" : "28443", "city" : "HAMPSTEAD", "loc" : [ -77.662808, 34.3879 ], "pop" : 8159, "state" : "NC" }
+{ "_id" : "28444", "city" : "HARRELLS", "loc" : [ -78.24297300000001, 34.676918 ], "pop" : 1635, "state" : "NC" }
+{ "_id" : "28445", "city" : "SURF CITY", "loc" : [ -77.51005000000001, 34.4644 ], "pop" : 1279, "state" : "NC" }
+{ "_id" : "28447", "city" : "IVANHOE", "loc" : [ -78.162333, 34.697169 ], "pop" : 352, "state" : "NC" }
+{ "_id" : "28448", "city" : "KELLY", "loc" : [ -78.294161, 34.459064 ], "pop" : 723, "state" : "NC" }
+{ "_id" : "28449", "city" : "KURE BEACH", "loc" : [ -77.909875, 33.992707 ], "pop" : 568, "state" : "NC" }
+{ "_id" : "28450", "city" : "LAKE WACCAMAW", "loc" : [ -78.51020800000001, 34.339359 ], "pop" : 1941, "state" : "NC" }
+{ "_id" : "28451", "city" : "LELAND", "loc" : [ -78.05781500000001, 34.267952 ], "pop" : 7803, "state" : "NC" }
+{ "_id" : "28452", "city" : "LONGWOOD", "loc" : [ -78.531531, 33.950059 ], "pop" : 1913, "state" : "NC" }
+{ "_id" : "28453", "city" : "MAGNOLIA", "loc" : [ -78.04321299999999, 34.895702 ], "pop" : 2056, "state" : "NC" }
+{ "_id" : "28454", "city" : "MAPLE HILL", "loc" : [ -77.736588, 34.617753 ], "pop" : 2095, "state" : "NC" }
+{ "_id" : "28455", "city" : "NAKINA", "loc" : [ -78.657005, 34.115293 ], "pop" : 1581, "state" : "NC" }
+{ "_id" : "28456", "city" : "RIEGELWOOD", "loc" : [ -78.257473, 34.34706 ], "pop" : 2038, "state" : "NC" }
+{ "_id" : "28457", "city" : "ROCKY POINT", "loc" : [ -77.92344799999999, 34.434418 ], "pop" : 4657, "state" : "NC" }
+{ "_id" : "28458", "city" : "ROSE HILL", "loc" : [ -78.01662399999999, 34.823462 ], "pop" : 4421, "state" : "NC" }
+{ "_id" : "28459", "city" : "SHALLOTTE", "loc" : [ -78.41068, 33.943011 ], "pop" : 6537, "state" : "NC" }
+{ "_id" : "28460", "city" : "SNEADS FERRY", "loc" : [ -77.403801, 34.542589 ], "pop" : 4586, "state" : "NC" }
+{ "_id" : "28461", "city" : "BOILING SPRING L", "loc" : [ -78.045551, 34.012137 ], "pop" : 8878, "state" : "NC" }
+{ "_id" : "28462", "city" : "HOLDEN BEACH", "loc" : [ -78.29608899999999, 33.962504 ], "pop" : 7513, "state" : "NC" }
+{ "_id" : "28463", "city" : "TABOR CITY", "loc" : [ -78.823178, 34.123314 ], "pop" : 6573, "state" : "NC" }
+{ "_id" : "28464", "city" : "TEACHEY", "loc" : [ -78.022091, 34.770036 ], "pop" : 1461, "state" : "NC" }
+{ "_id" : "28465", "city" : "OAK ISLAND", "loc" : [ -78.125455, 33.916122 ], "pop" : 4752, "state" : "NC" }
+{ "_id" : "28466", "city" : "WALLACE", "loc" : [ -77.942922, 34.754166 ], "pop" : 7328, "state" : "NC" }
+{ "_id" : "28467", "city" : "CALABASH", "loc" : [ -78.574406, 33.904668 ], "pop" : 3061, "state" : "NC" }
+{ "_id" : "28468", "city" : "SUNSET BEACH", "loc" : [ -78.519955, 33.883569 ], "pop" : 1347, "state" : "NC" }
+{ "_id" : "28469", "city" : "OCEAN ISLE BEACH", "loc" : [ -78.429849, 33.891271 ], "pop" : 493, "state" : "NC" }
+{ "_id" : "28471", "city" : "WATHA", "loc" : [ -78.007351, 34.620725 ], "pop" : 1327, "state" : "NC" }
+{ "_id" : "28472", "city" : "WHITEVILLE", "loc" : [ -78.716048, 34.324142 ], "pop" : 18066, "state" : "NC" }
+{ "_id" : "28478", "city" : "WILLARD", "loc" : [ -78.023445, 34.684451 ], "pop" : 2456, "state" : "NC" }
+{ "_id" : "28479", "city" : "WINNABOW", "loc" : [ -78.056211, 34.214511 ], "pop" : 3084, "state" : "NC" }
+{ "_id" : "28480", "city" : "WRIGHTSVILLE BEA", "loc" : [ -77.79816599999999, 34.212228 ], "pop" : 2928, "state" : "NC" }
+{ "_id" : "28501", "city" : "KINSTON", "loc" : [ -77.58596900000001, 35.278333 ], "pop" : 44135, "state" : "NC" }
+{ "_id" : "28508", "city" : "ALBERTSON", "loc" : [ -77.851517, 35.117647 ], "pop" : 2644, "state" : "NC" }
+{ "_id" : "28510", "city" : "ARAPAHOE", "loc" : [ -76.814909, 35.0055 ], "pop" : 1378, "state" : "NC" }
+{ "_id" : "28511", "city" : "ATLANTIC", "loc" : [ -76.352097, 34.888827 ], "pop" : 808, "state" : "NC" }
+{ "_id" : "28512", "city" : "PINE KNOLL SHORE", "loc" : [ -76.815163, 34.697295 ], "pop" : 1441, "state" : "NC" }
+{ "_id" : "28513", "city" : "AYDEN", "loc" : [ -77.40512699999999, 35.456471 ], "pop" : 8831, "state" : "NC" }
+{ "_id" : "28515", "city" : "BAYBORO", "loc" : [ -76.75179300000001, 35.152598 ], "pop" : 1853, "state" : "NC" }
+{ "_id" : "28516", "city" : "BEAUFORT", "loc" : [ -76.622834, 34.758037 ], "pop" : 10606, "state" : "NC" }
+{ "_id" : "28518", "city" : "BEULAVILLE", "loc" : [ -77.769655, 34.933962 ], "pop" : 7278, "state" : "NC" }
+{ "_id" : "28520", "city" : "CEDAR ISLAND", "loc" : [ -76.08049, 35.074881 ], "pop" : 1029, "state" : "NC" }
+{ "_id" : "28521", "city" : "CHINQUAPIN", "loc" : [ -77.76357299999999, 34.827609 ], "pop" : 1334, "state" : "NC" }
+{ "_id" : "28523", "city" : "COVE CITY", "loc" : [ -77.296306, 35.202274 ], "pop" : 2007, "state" : "NC" }
+{ "_id" : "28525", "city" : "DEEP RUN", "loc" : [ -77.69275, 35.162991 ], "pop" : 4252, "state" : "NC" }
+{ "_id" : "28526", "city" : "DOVER", "loc" : [ -77.372688, 35.262652 ], "pop" : 2198, "state" : "NC" }
+{ "_id" : "28527", "city" : "ERNUL", "loc" : [ -77.050164, 35.254693 ], "pop" : 303, "state" : "NC" }
+{ "_id" : "28528", "city" : "GLOUCESTER", "loc" : [ -76.527627, 34.685645 ], "pop" : 0, "state" : "NC" }
+{ "_id" : "28529", "city" : "GRANTSBORO", "loc" : [ -76.884387, 35.122186 ], "pop" : 3485, "state" : "NC" }
+{ "_id" : "28530", "city" : "GRIFTON", "loc" : [ -77.41930000000001, 35.375681 ], "pop" : 3029, "state" : "NC" }
+{ "_id" : "28531", "city" : "HARKERS ISLAND", "loc" : [ -76.558301, 34.69663 ], "pop" : 1761, "state" : "NC" }
+{ "_id" : "28532", "city" : "HAVELOCK", "loc" : [ -76.89004199999999, 34.896753 ], "pop" : 25957, "state" : "NC" }
+{ "_id" : "28537", "city" : "HOBUCKEN", "loc" : [ -76.569602, 35.251838 ], "pop" : 323, "state" : "NC" }
+{ "_id" : "28538", "city" : "HOOKERTON", "loc" : [ -77.565555, 35.437976 ], "pop" : 2112, "state" : "NC" }
+{ "_id" : "28539", "city" : "HUBERT", "loc" : [ -77.207928, 34.69929 ], "pop" : 8527, "state" : "NC" }
+{ "_id" : "28540", "city" : "JACKSONVILLE", "loc" : [ -77.46281500000001, 34.737456 ], "pop" : 52792, "state" : "NC" }
+{ "_id" : "28542", "city" : "CAMP LEJEUNE", "loc" : [ -77.3373, 34.665806 ], "pop" : 23717, "state" : "NC" }
+{ "_id" : "28543", "city" : "TARAWA TERRACE", "loc" : [ -77.38311400000001, 34.73542 ], "pop" : 11054, "state" : "NC" }
+{ "_id" : "28544", "city" : "MIDWAY PARK", "loc" : [ -77.320001, 34.726994 ], "pop" : 6799, "state" : "NC" }
+{ "_id" : "28546", "city" : "JACKSONVILLE", "loc" : [ -77.378097, 34.77401 ], "pop" : 27976, "state" : "NC" }
+{ "_id" : "28551", "city" : "LA GRANGE", "loc" : [ -77.76862, 35.305381 ], "pop" : 6686, "state" : "NC" }
+{ "_id" : "28552", "city" : "LOWLAND", "loc" : [ -76.57769999999999, 35.305955 ], "pop" : 367, "state" : "NC" }
+{ "_id" : "28553", "city" : "MARSHALLBERG", "loc" : [ -76.517323, 34.726472 ], "pop" : 565, "state" : "NC" }
+{ "_id" : "28555", "city" : "MAYSVILLE", "loc" : [ -77.23145599999999, 34.869077 ], "pop" : 3899, "state" : "NC" }
+{ "_id" : "28556", "city" : "MERRITT", "loc" : [ -76.69940099999999, 35.1228 ], "pop" : 1146, "state" : "NC" }
+{ "_id" : "28557", "city" : "MOREHEAD CITY", "loc" : [ -76.753069, 34.72532 ], "pop" : 13985, "state" : "NC" }
+{ "_id" : "28560", "city" : "NEW BERN", "loc" : [ -77.03194499999999, 35.101941 ], "pop" : 24585, "state" : "NC" }
+{ "_id" : "28562", "city" : "NEW BERN", "loc" : [ -77.102874, 35.100434 ], "pop" : 20936, "state" : "NC" }
+{ "_id" : "28570", "city" : "NEWPORT", "loc" : [ -76.90694499999999, 34.755076 ], "pop" : 18841, "state" : "NC" }
+{ "_id" : "28571", "city" : "ORIENTAL", "loc" : [ -76.701521, 35.036406 ], "pop" : 1985, "state" : "NC" }
+{ "_id" : "28572", "city" : "PINK HILL", "loc" : [ -77.712148, 35.066351 ], "pop" : 2201, "state" : "NC" }
+{ "_id" : "28573", "city" : "POLLOCKSVILLE", "loc" : [ -77.22872700000001, 35.015105 ], "pop" : 2406, "state" : "NC" }
+{ "_id" : "28574", "city" : "RICHLANDS", "loc" : [ -77.586305, 34.862426 ], "pop" : 8868, "state" : "NC" }
+{ "_id" : "28577", "city" : "SEALEVEL", "loc" : [ -76.38977800000001, 34.876949 ], "pop" : 521, "state" : "NC" }
+{ "_id" : "28578", "city" : "SEVEN SPRINGS", "loc" : [ -77.914621, 35.210466 ], "pop" : 2228, "state" : "NC" }
+{ "_id" : "28579", "city" : "SMYRNA", "loc" : [ -76.51531300000001, 34.773384 ], "pop" : 651, "state" : "NC" }
+{ "_id" : "28580", "city" : "SNOW HILL", "loc" : [ -77.695565, 35.443848 ], "pop" : 9637, "state" : "NC" }
+{ "_id" : "28581", "city" : "STACY", "loc" : [ -76.428877, 34.84124 ], "pop" : 264, "state" : "NC" }
+{ "_id" : "28582", "city" : "STELLA", "loc" : [ -77.130807, 34.777672 ], "pop" : 365, "state" : "NC" }
+{ "_id" : "28584", "city" : "SWANSBORO", "loc" : [ -77.135013, 34.699066 ], "pop" : 2535, "state" : "NC" }
+{ "_id" : "28585", "city" : "TRENTON", "loc" : [ -77.459473, 35.074481 ], "pop" : 5058, "state" : "NC" }
+{ "_id" : "28586", "city" : "VANCEBORO", "loc" : [ -77.171618, 35.306255 ], "pop" : 5627, "state" : "NC" }
+{ "_id" : "28587", "city" : "VANDEMERE", "loc" : [ -76.657088, 35.195298 ], "pop" : 835, "state" : "NC" }
+{ "_id" : "28590", "city" : "WINTERVILLE", "loc" : [ -77.39097, 35.533582 ], "pop" : 8382, "state" : "NC" }
+{ "_id" : "28594", "city" : "EMERALD ISLE", "loc" : [ -77.025961, 34.666195 ], "pop" : 2432, "state" : "NC" }
+{ "_id" : "28601", "city" : "HICKORY", "loc" : [ -81.328858, 35.75757 ], "pop" : 44977, "state" : "NC" }
+{ "_id" : "28602", "city" : "HICKORY", "loc" : [ -81.36122899999999, 35.68837 ], "pop" : 21020, "state" : "NC" }
+{ "_id" : "28604", "city" : "BANNER ELK", "loc" : [ -81.841194, 36.170461 ], "pop" : 4570, "state" : "NC" }
+{ "_id" : "28605", "city" : "BLOWING ROCK", "loc" : [ -81.750968, 36.094594 ], "pop" : 2372, "state" : "NC" }
+{ "_id" : "28606", "city" : "BOOMER", "loc" : [ -81.313704, 36.055192 ], "pop" : 2146, "state" : "NC" }
+{ "_id" : "28607", "city" : "BOONE", "loc" : [ -81.666025, 36.214237 ], "pop" : 24897, "state" : "NC" }
+{ "_id" : "28609", "city" : "CATAWBA", "loc" : [ -81.050307, 35.675708 ], "pop" : 1767, "state" : "NC" }
+{ "_id" : "28610", "city" : "CLAREMONT", "loc" : [ -81.129672, 35.721053 ], "pop" : 8902, "state" : "NC" }
+{ "_id" : "28611", "city" : "COLLETTSVILLE", "loc" : [ -81.674188, 35.951946 ], "pop" : 2121, "state" : "NC" }
+{ "_id" : "28612", "city" : "CONNELLYS SPRING", "loc" : [ -81.492958, 35.706972 ], "pop" : 15391, "state" : "NC" }
+{ "_id" : "28613", "city" : "CONOVER", "loc" : [ -81.216455, 35.731343 ], "pop" : 15222, "state" : "NC" }
+{ "_id" : "28615", "city" : "CRESTON", "loc" : [ -81.65062399999999, 36.449959 ], "pop" : 2527, "state" : "NC" }
+{ "_id" : "28617", "city" : "CRUMPLER", "loc" : [ -81.403886, 36.464057 ], "pop" : 2532, "state" : "NC" }
+{ "_id" : "28618", "city" : "DEEP GAP", "loc" : [ -81.516265, 36.213573 ], "pop" : 1176, "state" : "NC" }
+{ "_id" : "28621", "city" : "ELKIN", "loc" : [ -80.85536500000001, 36.28723 ], "pop" : 10672, "state" : "NC" }
+{ "_id" : "28622", "city" : "ELK PARK", "loc" : [ -81.963882, 36.164623 ], "pop" : 3223, "state" : "NC" }
+{ "_id" : "28623", "city" : "ENNICE", "loc" : [ -80.977141, 36.525278 ], "pop" : 1509, "state" : "NC" }
+{ "_id" : "28624", "city" : "FERGUSON", "loc" : [ -81.38640700000001, 36.128316 ], "pop" : 1551, "state" : "NC" }
+{ "_id" : "28626", "city" : "FLEETWOOD", "loc" : [ -81.514008, 36.281382 ], "pop" : 1693, "state" : "NC" }
+{ "_id" : "28627", "city" : "GLADE VALLEY", "loc" : [ -81.01678200000001, 36.442889 ], "pop" : 1115, "state" : "NC" }
+{ "_id" : "28630", "city" : "GRANITE FALLS", "loc" : [ -81.457145, 35.819663 ], "pop" : 17749, "state" : "NC" }
+{ "_id" : "28631", "city" : "GRASSY CREEK", "loc" : [ -81.44675100000001, 36.541524 ], "pop" : 837, "state" : "NC" }
+{ "_id" : "28634", "city" : "HARMONY", "loc" : [ -80.75846199999999, 35.957975 ], "pop" : 3881, "state" : "NC" }
+{ "_id" : "28635", "city" : "HAYS", "loc" : [ -81.11611600000001, 36.310015 ], "pop" : 1085, "state" : "NC" }
+{ "_id" : "28636", "city" : "HIDDENITE", "loc" : [ -81.048663, 35.95045 ], "pop" : 1703, "state" : "NC" }
+{ "_id" : "28638", "city" : "HUDSON", "loc" : [ -81.48974699999999, 35.840295 ], "pop" : 9771, "state" : "NC" }
+{ "_id" : "28640", "city" : "JEFFERSON", "loc" : [ -81.439626, 36.408987 ], "pop" : 3080, "state" : "NC" }
+{ "_id" : "28642", "city" : "JONESVILLE", "loc" : [ -80.787029, 36.228571 ], "pop" : 7105, "state" : "NC" }
+{ "_id" : "28643", "city" : "LANSING", "loc" : [ -81.52692500000001, 36.517641 ], "pop" : 3211, "state" : "NC" }
+{ "_id" : "28644", "city" : "LAUREL SPRINGS", "loc" : [ -81.26061, 36.444897 ], "pop" : 1837, "state" : "NC" }
+{ "_id" : "28645", "city" : "LENOIR", "loc" : [ -81.539793, 35.914935 ], "pop" : 39525, "state" : "NC" }
+{ "_id" : "28648", "city" : "LONGISLAND", "loc" : [ -80.990403, 35.665814 ], "pop" : 279, "state" : "NC" }
+{ "_id" : "28649", "city" : "MC GRADY", "loc" : [ -81.19120700000001, 36.310345 ], "pop" : 1261, "state" : "NC" }
+{ "_id" : "28650", "city" : "MAIDEN", "loc" : [ -81.174492, 35.575884 ], "pop" : 7388, "state" : "NC" }
+{ "_id" : "28651", "city" : "MILLERS CREEK", "loc" : [ -81.24853299999999, 36.211949 ], "pop" : 7018, "state" : "NC" }
+{ "_id" : "28654", "city" : "MORAVIAN FALLS", "loc" : [ -81.178073, 36.078762 ], "pop" : 3071, "state" : "NC" }
+{ "_id" : "28655", "city" : "MORGANTON", "loc" : [ -81.704216, 35.73458 ], "pop" : 50932, "state" : "NC" }
+{ "_id" : "28657", "city" : "FRANK", "loc" : [ -81.952276, 36.040203 ], "pop" : 8906, "state" : "NC" }
+{ "_id" : "28658", "city" : "NEWTON", "loc" : [ -81.242546, 35.649766 ], "pop" : 20759, "state" : "NC" }
+{ "_id" : "28659", "city" : "NORTH WILKESBORO", "loc" : [ -81.128603, 36.20174 ], "pop" : 20167, "state" : "NC" }
+{ "_id" : "28660", "city" : "OLIN", "loc" : [ -80.851084, 35.959333 ], "pop" : 723, "state" : "NC" }
+{ "_id" : "28665", "city" : "PURLEAR", "loc" : [ -81.352773, 36.196391 ], "pop" : 1102, "state" : "NC" }
+{ "_id" : "28668", "city" : "ROARING GAP", "loc" : [ -81.018781, 36.383553 ], "pop" : 21, "state" : "NC" }
+{ "_id" : "28669", "city" : "ROARING RIVER", "loc" : [ -81.000373, 36.191561 ], "pop" : 978, "state" : "NC" }
+{ "_id" : "28670", "city" : "RONDA", "loc" : [ -80.926964, 36.20594 ], "pop" : 2739, "state" : "NC" }
+{ "_id" : "28673", "city" : "SHERRILLS FORD", "loc" : [ -81.03385900000001, 35.596244 ], "pop" : 5567, "state" : "NC" }
+{ "_id" : "28675", "city" : "SPARTA", "loc" : [ -81.138442, 36.508851 ], "pop" : 5746, "state" : "NC" }
+{ "_id" : "28676", "city" : "STATE ROAD", "loc" : [ -80.86529400000001, 36.34218 ], "pop" : 3080, "state" : "NC" }
+{ "_id" : "28677", "city" : "STATESVILLE", "loc" : [ -80.894009, 35.799022 ], "pop" : 52895, "state" : "NC" }
+{ "_id" : "28678", "city" : "STONY POINT", "loc" : [ -81.06413499999999, 35.866109 ], "pop" : 5212, "state" : "NC" }
+{ "_id" : "28679", "city" : "SUGAR GROVE", "loc" : [ -81.844094, 36.262672 ], "pop" : 1631, "state" : "NC" }
+{ "_id" : "28681", "city" : "TAYLORSVILLE", "loc" : [ -81.212429, 35.901046 ], "pop" : 19679, "state" : "NC" }
+{ "_id" : "28682", "city" : "TERRELL", "loc" : [ -80.963064, 35.583587 ], "pop" : 440, "state" : "NC" }
+{ "_id" : "28683", "city" : "THURMOND", "loc" : [ -80.931674, 36.356188 ], "pop" : 556, "state" : "NC" }
+{ "_id" : "28684", "city" : "TODD", "loc" : [ -81.58740299999999, 36.324527 ], "pop" : 1039, "state" : "NC" }
+{ "_id" : "28685", "city" : "TRAPHILL", "loc" : [ -81.015126, 36.330097 ], "pop" : 1781, "state" : "NC" }
+{ "_id" : "28686", "city" : "TRIPLETT", "loc" : [ -81.489649, 36.181685 ], "pop" : 64, "state" : "NC" }
+{ "_id" : "28689", "city" : "UNION GROVE", "loc" : [ -80.89669499999999, 36.036947 ], "pop" : 2264, "state" : "NC" }
+{ "_id" : "28690", "city" : "VALDESE", "loc" : [ -81.56695999999999, 35.744739 ], "pop" : 4227, "state" : "NC" }
+{ "_id" : "28691", "city" : "VALLE CRUCIS", "loc" : [ -81.880563, 36.207041 ], "pop" : 238, "state" : "NC" }
+{ "_id" : "28692", "city" : "VILAS", "loc" : [ -81.765203, 36.257375 ], "pop" : 3022, "state" : "NC" }
+{ "_id" : "28693", "city" : "WARRENSVILLE", "loc" : [ -81.546522, 36.45723 ], "pop" : 994, "state" : "NC" }
+{ "_id" : "28694", "city" : "WEST JEFFERSON", "loc" : [ -81.487218, 36.377648 ], "pop" : 6348, "state" : "NC" }
+{ "_id" : "28697", "city" : "WILKESBORO", "loc" : [ -81.157292, 36.135857 ], "pop" : 11889, "state" : "NC" }
+{ "_id" : "28698", "city" : "ZIONVILLE", "loc" : [ -81.747567, 36.319437 ], "pop" : 1633, "state" : "NC" }
+{ "_id" : "28701", "city" : "ALEXANDER", "loc" : [ -82.631134, 35.706394 ], "pop" : 2960, "state" : "NC" }
+{ "_id" : "28702", "city" : "ALMOND", "loc" : [ -83.578406, 35.3295 ], "pop" : 678, "state" : "NC" }
+{ "_id" : "28703", "city" : "AQUONE", "loc" : [ -83.56621800000001, 35.240254 ], "pop" : 1423, "state" : "NC" }
+{ "_id" : "28704", "city" : "ARDEN", "loc" : [ -82.535372, 35.463666 ], "pop" : 11386, "state" : "NC" }
+{ "_id" : "28705", "city" : "BAKERSVILLE", "loc" : [ -82.171133, 36.028588 ], "pop" : 6862, "state" : "NC" }
+{ "_id" : "28708", "city" : "BALSAM GROVE", "loc" : [ -82.87795, 35.229751 ], "pop" : 342, "state" : "NC" }
+{ "_id" : "28709", "city" : "BARNARDSVILLE", "loc" : [ -82.456682, 35.77483 ], "pop" : 2757, "state" : "NC" }
+{ "_id" : "28711", "city" : "BLACK MOUNTAIN S", "loc" : [ -82.325087, 35.612494 ], "pop" : 11914, "state" : "NC" }
+{ "_id" : "28712", "city" : "BREVARD", "loc" : [ -82.740444, 35.22076 ], "pop" : 14212, "state" : "NC" }
+{ "_id" : "28713", "city" : "BRYSON CITY", "loc" : [ -83.439246, 35.424128 ], "pop" : 7248, "state" : "NC" }
+{ "_id" : "28714", "city" : "BURNSVILLE", "loc" : [ -82.287623, 35.902974 ], "pop" : 13735, "state" : "NC" }
+{ "_id" : "28715", "city" : "CANDLER", "loc" : [ -82.700081, 35.537626 ], "pop" : 15823, "state" : "NC" }
+{ "_id" : "28716", "city" : "CANTON", "loc" : [ -82.841291, 35.512651 ], "pop" : 14331, "state" : "NC" }
+{ "_id" : "28717", "city" : "CASHIERS", "loc" : [ -83.087074, 35.097117 ], "pop" : 1099, "state" : "NC" }
+{ "_id" : "28719", "city" : "CHEROKEE", "loc" : [ -83.31444, 35.50937 ], "pop" : 3339, "state" : "NC" }
+{ "_id" : "28721", "city" : "CLYDE", "loc" : [ -82.921582, 35.559654 ], "pop" : 7400, "state" : "NC" }
+{ "_id" : "28722", "city" : "COLUMBUS", "loc" : [ -82.120631, 35.241031 ], "pop" : 5976, "state" : "NC" }
+{ "_id" : "28723", "city" : "CULLOWHEE", "loc" : [ -83.147522, 35.240876 ], "pop" : 2886, "state" : "NC" }
+{ "_id" : "28726", "city" : "EAST FLAT ROCK", "loc" : [ -82.420423, 35.279868 ], "pop" : 3770, "state" : "NC" }
+{ "_id" : "28729", "city" : "ETOWAH", "loc" : [ -82.597705, 35.317192 ], "pop" : 2461, "state" : "NC" }
+{ "_id" : "28730", "city" : "FAIRVIEW", "loc" : [ -82.398534, 35.525759 ], "pop" : 5156, "state" : "NC" }
+{ "_id" : "28731", "city" : "FLAT ROCK", "loc" : [ -82.39156800000001, 35.288993 ], "pop" : 4240, "state" : "NC" }
+{ "_id" : "28732", "city" : "FLETCHER", "loc" : [ -82.496559, 35.44989 ], "pop" : 7201, "state" : "NC" }
+{ "_id" : "28733", "city" : "FONTANA DAM", "loc" : [ -83.81763100000001, 35.428187 ], "pop" : 187, "state" : "NC" }
+{ "_id" : "28734", "city" : "FRANKLIN", "loc" : [ -83.388479, 35.180984 ], "pop" : 16689, "state" : "NC" }
+{ "_id" : "28735", "city" : "GERTON", "loc" : [ -82.30620399999999, 35.468723 ], "pop" : 280, "state" : "NC" }
+{ "_id" : "28736", "city" : "GLENVILLE", "loc" : [ -83.09003300000001, 35.188164 ], "pop" : 125, "state" : "NC" }
+{ "_id" : "28738", "city" : "HAZELWOOD", "loc" : [ -83.004284, 35.476877 ], "pop" : 1759, "state" : "NC" }
+{ "_id" : "28739", "city" : "HENDERSONVILLE", "loc" : [ -82.499995, 35.319213 ], "pop" : 26125, "state" : "NC" }
+{ "_id" : "28740", "city" : "GREENMOUNTAIN", "loc" : [ -82.28786700000001, 35.995619 ], "pop" : 1471, "state" : "NC" }
+{ "_id" : "28741", "city" : "HIGHLANDS", "loc" : [ -83.216044, 35.070546 ], "pop" : 2685, "state" : "NC" }
+{ "_id" : "28742", "city" : "HORSE SHOE", "loc" : [ -82.598128, 35.370267 ], "pop" : 4069, "state" : "NC" }
+{ "_id" : "28743", "city" : "HOT SPRINGS", "loc" : [ -82.812011, 35.816175 ], "pop" : 3595, "state" : "NC" }
+{ "_id" : "28745", "city" : "LAKE JUNALUSKA", "loc" : [ -82.970235, 35.525916 ], "pop" : 539, "state" : "NC" }
+{ "_id" : "28746", "city" : "LAKE LURE", "loc" : [ -82.175203, 35.446447 ], "pop" : 1843, "state" : "NC" }
+{ "_id" : "28747", "city" : "LAKE TOXAWAY", "loc" : [ -82.91908100000001, 35.145052 ], "pop" : 1849, "state" : "NC" }
+{ "_id" : "28748", "city" : "LEICESTER", "loc" : [ -82.710622, 35.649781 ], "pop" : 7709, "state" : "NC" }
+{ "_id" : "28751", "city" : "MAGGIE VALLEY", "loc" : [ -83.092928, 35.52006 ], "pop" : 1989, "state" : "NC" }
+{ "_id" : "28752", "city" : "MARION", "loc" : [ -82.017993, 35.681916 ], "pop" : 24988, "state" : "NC" }
+{ "_id" : "28753", "city" : "WALNUT", "loc" : [ -82.656577, 35.856074 ], "pop" : 7623, "state" : "NC" }
+{ "_id" : "28754", "city" : "MARS HILL", "loc" : [ -82.525352, 35.852825 ], "pop" : 5949, "state" : "NC" }
+{ "_id" : "28756", "city" : "MILL SPRING", "loc" : [ -82.155733, 35.333792 ], "pop" : 3075, "state" : "NC" }
+{ "_id" : "28761", "city" : "NEBO", "loc" : [ -81.905581, 35.673158 ], "pop" : 5018, "state" : "NC" }
+{ "_id" : "28762", "city" : "OLD FORT", "loc" : [ -82.168621, 35.616948 ], "pop" : 5594, "state" : "NC" }
+{ "_id" : "28763", "city" : "OTTO", "loc" : [ -83.384755, 35.062668 ], "pop" : 2297, "state" : "NC" }
+{ "_id" : "28766", "city" : "PENROSE", "loc" : [ -82.62223899999999, 35.252407 ], "pop" : 653, "state" : "NC" }
+{ "_id" : "28768", "city" : "PISGAH FOREST", "loc" : [ -82.669516, 35.259931 ], "pop" : 5623, "state" : "NC" }
+{ "_id" : "28771", "city" : "ROBBINSVILLE", "loc" : [ -83.788775, 35.325932 ], "pop" : 6879, "state" : "NC" }
+{ "_id" : "28772", "city" : "ROSMAN", "loc" : [ -82.818916, 35.119695 ], "pop" : 2779, "state" : "NC" }
+{ "_id" : "28773", "city" : "SALUDA", "loc" : [ -82.330595, 35.238341 ], "pop" : 1451, "state" : "NC" }
+{ "_id" : "28774", "city" : "SAPPHIRE", "loc" : [ -83.001924, 35.066578 ], "pop" : 62, "state" : "NC" }
+{ "_id" : "28775", "city" : "SCALY MOUNTAIN", "loc" : [ -83.31133800000001, 35.024036 ], "pop" : 405, "state" : "NC" }
+{ "_id" : "28777", "city" : "SPRUCE PINE", "loc" : [ -82.070492, 35.905971 ], "pop" : 7570, "state" : "NC" }
+{ "_id" : "28778", "city" : "WARREN WILSON CO", "loc" : [ -82.40649000000001, 35.604843 ], "pop" : 5911, "state" : "NC" }
+{ "_id" : "28779", "city" : "SYLVA", "loc" : [ -83.20305399999999, 35.348055 ], "pop" : 16275, "state" : "NC" }
+{ "_id" : "28780", "city" : "TAPOCO", "loc" : [ -83.905415, 35.442023 ], "pop" : 130, "state" : "NC" }
+{ "_id" : "28781", "city" : "TOPTON", "loc" : [ -83.74511699999999, 35.230604 ], "pop" : 481, "state" : "NC" }
+{ "_id" : "28782", "city" : "TRYON", "loc" : [ -82.23942, 35.215703 ], "pop" : 3914, "state" : "NC" }
+{ "_id" : "28783", "city" : "TUCKASEGEE", "loc" : [ -83.07486400000001, 35.259934 ], "pop" : 1096, "state" : "NC" }
+{ "_id" : "28786", "city" : "WAYNESVILLE", "loc" : [ -82.99134599999999, 35.501767 ], "pop" : 20924, "state" : "NC" }
+{ "_id" : "28787", "city" : "WEAVERVILLE", "loc" : [ -82.549109, 35.712642 ], "pop" : 11884, "state" : "NC" }
+{ "_id" : "28789", "city" : "WHITTIER", "loc" : [ -83.287239, 35.446934 ], "pop" : 5368, "state" : "NC" }
+{ "_id" : "28790", "city" : "ZIRCONIA", "loc" : [ -82.457368, 35.215291 ], "pop" : 2350, "state" : "NC" }
+{ "_id" : "28792", "city" : "HENDERSONVILLE", "loc" : [ -82.42644300000001, 35.361342 ], "pop" : 21037, "state" : "NC" }
+{ "_id" : "28801", "city" : "ASHEVILLE", "loc" : [ -82.556533, 35.597075 ], "pop" : 13316, "state" : "NC" }
+{ "_id" : "28803", "city" : "ASHEVILLE", "loc" : [ -82.518021, 35.539291 ], "pop" : 20904, "state" : "NC" }
+{ "_id" : "28804", "city" : "ASHEVILLE", "loc" : [ -82.56462500000001, 35.63743 ], "pop" : 16709, "state" : "NC" }
+{ "_id" : "28805", "city" : "ASHEVILLE", "loc" : [ -82.491781, 35.600363 ], "pop" : 15335, "state" : "NC" }
+{ "_id" : "28806", "city" : "ASHEVILLE", "loc" : [ -82.607787, 35.580814 ], "pop" : 30809, "state" : "NC" }
+{ "_id" : "28901", "city" : "ANDREWS", "loc" : [ -83.822836, 35.195948 ], "pop" : 4469, "state" : "NC" }
+{ "_id" : "28902", "city" : "BRASSTOWN", "loc" : [ -83.966773, 35.031392 ], "pop" : 1390, "state" : "NC" }
+{ "_id" : "28904", "city" : "HAYESVILLE", "loc" : [ -83.78668, 35.04172 ], "pop" : 5965, "state" : "NC" }
+{ "_id" : "28905", "city" : "MARBLE", "loc" : [ -83.93806499999999, 35.14748 ], "pop" : 3230, "state" : "NC" }
+{ "_id" : "28906", "city" : "UNAKA", "loc" : [ -84.101454, 35.079228 ], "pop" : 11333, "state" : "NC" }
+{ "_id" : "28909", "city" : "WARNE", "loc" : [ -83.90454099999999, 35.002437 ], "pop" : 457, "state" : "NC" }
+{ "_id" : "29001", "city" : "ALCOLU", "loc" : [ -80.178782, 33.768402 ], "pop" : 2319, "state" : "SC" }
+{ "_id" : "29003", "city" : "BAMBERG", "loc" : [ -81.01774399999999, 33.277915 ], "pop" : 7096, "state" : "SC" }
+{ "_id" : "29006", "city" : "BATESBURG", "loc" : [ -81.54898799999999, 33.938595 ], "pop" : 9300, "state" : "SC" }
+{ "_id" : "29009", "city" : "BETHUNE", "loc" : [ -80.36620600000001, 34.42012 ], "pop" : 2172, "state" : "SC" }
+{ "_id" : "29010", "city" : "BISHOPVILLE", "loc" : [ -80.27498799999999, 34.224101 ], "pop" : 11965, "state" : "SC" }
+{ "_id" : "29014", "city" : "BLACKSTOCK", "loc" : [ -81.12485700000001, 34.577876 ], "pop" : 249, "state" : "SC" }
+{ "_id" : "29015", "city" : "BLAIR", "loc" : [ -81.345945, 34.496668 ], "pop" : 895, "state" : "SC" }
+{ "_id" : "29016", "city" : "BLYTHEWOOD", "loc" : [ -80.975756, 34.191112 ], "pop" : 7321, "state" : "SC" }
+{ "_id" : "29018", "city" : "BOWMAN", "loc" : [ -80.670868, 33.347466 ], "pop" : 3993, "state" : "SC" }
+{ "_id" : "29020", "city" : "CAMDEN", "loc" : [ -80.590997, 34.269636 ], "pop" : 20667, "state" : "SC" }
+{ "_id" : "29030", "city" : "CAMERON", "loc" : [ -80.64660499999999, 33.557789 ], "pop" : 2356, "state" : "SC" }
+{ "_id" : "29031", "city" : "CARLISLE", "loc" : [ -81.50910500000001, 34.614332 ], "pop" : 2021, "state" : "SC" }
+{ "_id" : "29032", "city" : "CASSATT", "loc" : [ -80.499993, 34.342414 ], "pop" : 2164, "state" : "SC" }
+{ "_id" : "29033", "city" : "CAYCE", "loc" : [ -81.06708399999999, 33.962567 ], "pop" : 12191, "state" : "SC" }
+{ "_id" : "29036", "city" : "CHAPIN", "loc" : [ -81.33181999999999, 34.131158 ], "pop" : 8744, "state" : "SC" }
+{ "_id" : "29037", "city" : "CHAPPELLS", "loc" : [ -81.83525299999999, 34.235834 ], "pop" : 940, "state" : "SC" }
+{ "_id" : "29038", "city" : "COPE", "loc" : [ -80.963111, 33.372555 ], "pop" : 1962, "state" : "SC" }
+{ "_id" : "29039", "city" : "CORDOVA", "loc" : [ -80.88571899999999, 33.42753 ], "pop" : 2808, "state" : "SC" }
+{ "_id" : "29040", "city" : "DALZELL", "loc" : [ -80.466533, 34.014412 ], "pop" : 7540, "state" : "SC" }
+{ "_id" : "29042", "city" : "DENMARK", "loc" : [ -81.14072, 33.320925 ], "pop" : 6602, "state" : "SC" }
+{ "_id" : "29044", "city" : "EASTOVER", "loc" : [ -80.699647, 33.915274 ], "pop" : 4666, "state" : "SC" }
+{ "_id" : "29045", "city" : "ELGIN", "loc" : [ -80.81129199999999, 34.161963 ], "pop" : 9447, "state" : "SC" }
+{ "_id" : "29046", "city" : "ELLIOTT", "loc" : [ -80.17544100000001, 34.117149 ], "pop" : 1235, "state" : "SC" }
+{ "_id" : "29047", "city" : "ELLOREE", "loc" : [ -80.56784, 33.490608 ], "pop" : 4202, "state" : "SC" }
+{ "_id" : "29048", "city" : "EUTAWVILLE", "loc" : [ -80.31998299999999, 33.392189 ], "pop" : 4298, "state" : "SC" }
+{ "_id" : "29051", "city" : "GABLE", "loc" : [ -80.081377, 33.840989 ], "pop" : 790, "state" : "SC" }
+{ "_id" : "29052", "city" : "GADSDEN", "loc" : [ -80.753199, 33.845461 ], "pop" : 2235, "state" : "SC" }
+{ "_id" : "29053", "city" : "GASTON", "loc" : [ -81.117395, 33.833712 ], "pop" : 7863, "state" : "SC" }
+{ "_id" : "29054", "city" : "GILBERT", "loc" : [ -81.39136000000001, 33.95805 ], "pop" : 4018, "state" : "SC" }
+{ "_id" : "29055", "city" : "GREAT FALLS", "loc" : [ -80.913263, 34.57053 ], "pop" : 3562, "state" : "SC" }
+{ "_id" : "29056", "city" : "GREELEYVILLE", "loc" : [ -79.98022, 33.59664 ], "pop" : 2773, "state" : "SC" }
+{ "_id" : "29058", "city" : "HEATH SPRINGS", "loc" : [ -80.71031000000001, 34.602422 ], "pop" : 5101, "state" : "SC" }
+{ "_id" : "29059", "city" : "HOLLY HILL", "loc" : [ -80.402393, 33.327586 ], "pop" : 4959, "state" : "SC" }
+{ "_id" : "29061", "city" : "HOPKINS", "loc" : [ -80.84490599999999, 33.934868 ], "pop" : 12297, "state" : "SC" }
+{ "_id" : "29063", "city" : "IRMO", "loc" : [ -81.19655299999999, 34.110254 ], "pop" : 15479, "state" : "SC" }
+{ "_id" : "29065", "city" : "JENKINSVILLE", "loc" : [ -81.271153, 34.271693 ], "pop" : 809, "state" : "SC" }
+{ "_id" : "29067", "city" : "KERSHAW", "loc" : [ -80.554633, 34.557809 ], "pop" : 8189, "state" : "SC" }
+{ "_id" : "29069", "city" : "LAMAR", "loc" : [ -80.030134, 34.189044 ], "pop" : 6964, "state" : "SC" }
+{ "_id" : "29070", "city" : "LEESVILLE", "loc" : [ -81.45975300000001, 33.913169 ], "pop" : 8605, "state" : "SC" }
+{ "_id" : "29072", "city" : "LEXINGTON", "loc" : [ -81.23586, 33.972383 ], "pop" : 33576, "state" : "SC" }
+{ "_id" : "29073", "city" : "LEXINGTON", "loc" : [ -81.235102, 33.863206 ], "pop" : 4683, "state" : "SC" }
+{ "_id" : "29075", "city" : "LITTLE MOUNTAIN", "loc" : [ -81.418375, 34.167569 ], "pop" : 3322, "state" : "SC" }
+{ "_id" : "29077", "city" : "LONE STAR", "loc" : [ -80.645025, 33.673574 ], "pop" : 1030, "state" : "SC" }
+{ "_id" : "29078", "city" : "LUGOFF", "loc" : [ -80.71471200000001, 34.22961 ], "pop" : 8991, "state" : "SC" }
+{ "_id" : "29080", "city" : "LYNCHBURG", "loc" : [ -80.098821, 34.052603 ], "pop" : 2091, "state" : "SC" }
+{ "_id" : "29081", "city" : "EHRHARDT", "loc" : [ -81.022137, 33.104436 ], "pop" : 1525, "state" : "SC" }
+{ "_id" : "29082", "city" : "LODGE", "loc" : [ -80.934641, 32.982263 ], "pop" : 1877, "state" : "SC" }
+{ "_id" : "29101", "city" : "MC BEE", "loc" : [ -80.254434, 34.46056 ], "pop" : 2331, "state" : "SC" }
+{ "_id" : "29102", "city" : "PAXVILLE", "loc" : [ -80.222078, 33.667716 ], "pop" : 14407, "state" : "SC" }
+{ "_id" : "29104", "city" : "SAINT CHARLES", "loc" : [ -80.234927, 34.046463 ], "pop" : 2403, "state" : "SC" }
+{ "_id" : "29105", "city" : "MONETTA", "loc" : [ -81.536299, 33.774729 ], "pop" : 2068, "state" : "SC" }
+{ "_id" : "29107", "city" : "NEESES", "loc" : [ -81.083433, 33.534282 ], "pop" : 3416, "state" : "SC" }
+{ "_id" : "29108", "city" : "NEWBERRY", "loc" : [ -81.615741, 34.284661 ], "pop" : 15468, "state" : "SC" }
+{ "_id" : "29111", "city" : "NEW ZION", "loc" : [ -80.014753, 33.795736 ], "pop" : 1072, "state" : "SC" }
+{ "_id" : "29112", "city" : "NORTH", "loc" : [ -81.060096, 33.621121 ], "pop" : 3410, "state" : "SC" }
+{ "_id" : "29113", "city" : "NORWAY", "loc" : [ -81.10974400000001, 33.453402 ], "pop" : 2487, "state" : "SC" }
+{ "_id" : "29114", "city" : "OLANTA", "loc" : [ -79.91534900000001, 33.928545 ], "pop" : 2415, "state" : "SC" }
+{ "_id" : "29115", "city" : "ORANGEBURG", "loc" : [ -80.85928199999999, 33.502545 ], "pop" : 43095, "state" : "SC" }
+{ "_id" : "29123", "city" : "PELION", "loc" : [ -81.25016100000001, 33.776628 ], "pop" : 3139, "state" : "SC" }
+{ "_id" : "29125", "city" : "PINEWOOD", "loc" : [ -80.497761, 33.764216 ], "pop" : 937, "state" : "SC" }
+{ "_id" : "29126", "city" : "POMARIA", "loc" : [ -81.449973, 34.306281 ], "pop" : 3278, "state" : "SC" }
+{ "_id" : "29127", "city" : "PROSPERITY", "loc" : [ -81.532353, 34.183243 ], "pop" : 4782, "state" : "SC" }
+{ "_id" : "29128", "city" : "REMBERT", "loc" : [ -80.494544, 34.108467 ], "pop" : 5577, "state" : "SC" }
+{ "_id" : "29129", "city" : "RIDGE SPRING", "loc" : [ -81.65594900000001, 33.871403 ], "pop" : 2172, "state" : "SC" }
+{ "_id" : "29130", "city" : "RIDGEWAY", "loc" : [ -80.92881300000001, 34.316651 ], "pop" : 4405, "state" : "SC" }
+{ "_id" : "29131", "city" : "RIMINI", "loc" : [ -80.47267100000001, 33.672155 ], "pop" : 778, "state" : "SC" }
+{ "_id" : "29133", "city" : "ROWESVILLE", "loc" : [ -80.83311500000001, 33.370257 ], "pop" : 488, "state" : "SC" }
+{ "_id" : "29135", "city" : "FORT MOTTE", "loc" : [ -80.856286, 33.694212 ], "pop" : 9367, "state" : "SC" }
+{ "_id" : "29137", "city" : "SALLEY", "loc" : [ -81.31841799999999, 33.597233 ], "pop" : 2537, "state" : "SC" }
+{ "_id" : "29138", "city" : "SALUDA", "loc" : [ -81.775398, 34.017451 ], "pop" : 9586, "state" : "SC" }
+{ "_id" : "29142", "city" : "SANTEE", "loc" : [ -80.480498, 33.483533 ], "pop" : 1891, "state" : "SC" }
+{ "_id" : "29145", "city" : "SILVERSTREET", "loc" : [ -81.703684, 34.235553 ], "pop" : 1851, "state" : "SC" }
+{ "_id" : "29146", "city" : "SPRINGFIELD", "loc" : [ -81.249858, 33.534265 ], "pop" : 2184, "state" : "SC" }
+{ "_id" : "29148", "city" : "SUMMERTON", "loc" : [ -80.36056600000001, 33.594578 ], "pop" : 5946, "state" : "SC" }
+{ "_id" : "29150", "city" : "OSWEGO", "loc" : [ -80.32100800000001, 33.928199 ], "pop" : 46394, "state" : "SC" }
+{ "_id" : "29152", "city" : "SHAW A F B", "loc" : [ -80.481093, 33.980262 ], "pop" : 13353, "state" : "SC" }
+{ "_id" : "29154", "city" : "SUMTER", "loc" : [ -80.402761, 33.882067 ], "pop" : 24816, "state" : "SC" }
+{ "_id" : "29160", "city" : "SWANSEA", "loc" : [ -81.093309, 33.733917 ], "pop" : 3822, "state" : "SC" }
+{ "_id" : "29161", "city" : "TIMMONSVILLE", "loc" : [ -79.937845, 34.101241 ], "pop" : 6644, "state" : "SC" }
+{ "_id" : "29162", "city" : "TURBEVILLE", "loc" : [ -79.985174, 33.87857 ], "pop" : 3138, "state" : "SC" }
+{ "_id" : "29163", "city" : "VANCE", "loc" : [ -80.461716, 33.413882 ], "pop" : 3445, "state" : "SC" }
+{ "_id" : "29164", "city" : "WAGENER", "loc" : [ -81.39952, 33.649417 ], "pop" : 3278, "state" : "SC" }
+{ "_id" : "29166", "city" : "WARD", "loc" : [ -81.728341, 33.884856 ], "pop" : 823, "state" : "SC" }
+{ "_id" : "29168", "city" : "WEDGEFIELD", "loc" : [ -80.49871899999999, 33.943002 ], "pop" : 5490, "state" : "SC" }
+{ "_id" : "29169", "city" : "WEST COLUMBIA", "loc" : [ -81.088836, 33.995024 ], "pop" : 18309, "state" : "SC" }
+{ "_id" : "29170", "city" : "WEST COLUMBIA", "loc" : [ -81.140474, 33.956751 ], "pop" : 17399, "state" : "SC" }
+{ "_id" : "29172", "city" : "WEST COLUMBIA", "loc" : [ -81.091008, 33.900022 ], "pop" : 9939, "state" : "SC" }
+{ "_id" : "29175", "city" : "WESTVILLE", "loc" : [ -80.579554, 34.449177 ], "pop" : 867, "state" : "SC" }
+{ "_id" : "29178", "city" : "WHITMIRE", "loc" : [ -81.605981, 34.495485 ], "pop" : 3677, "state" : "SC" }
+{ "_id" : "29180", "city" : "WINNSBORO", "loc" : [ -81.10899000000001, 34.381008 ], "pop" : 16188, "state" : "SC" }
+{ "_id" : "29201", "city" : "COLUMBIA", "loc" : [ -81.033418, 34.0004 ], "pop" : 18758, "state" : "SC" }
+{ "_id" : "29203", "city" : "COLUMBIA", "loc" : [ -81.026462, 34.063452 ], "pop" : 45907, "state" : "SC" }
+{ "_id" : "29204", "city" : "COLUMBIA", "loc" : [ -81.00464700000001, 34.026037 ], "pop" : 23682, "state" : "SC" }
+{ "_id" : "29205", "city" : "COLUMBIA", "loc" : [ -80.999731, 33.990309 ], "pop" : 27239, "state" : "SC" }
+{ "_id" : "29206", "city" : "COLUMBIA", "loc" : [ -80.953152, 34.024655 ], "pop" : 25605, "state" : "SC" }
+{ "_id" : "29209", "city" : "COLUMBIA", "loc" : [ -80.935525, 33.965863 ], "pop" : 26378, "state" : "SC" }
+{ "_id" : "29210", "city" : "COLUMBIA", "loc" : [ -81.11006, 34.047863 ], "pop" : 37526, "state" : "SC" }
+{ "_id" : "29212", "city" : "COLUMBIA", "loc" : [ -81.17961699999999, 34.072613 ], "pop" : 22080, "state" : "SC" }
+{ "_id" : "29223", "city" : "COLUMBIA", "loc" : [ -80.91667, 34.085267 ], "pop" : 42346, "state" : "SC" }
+{ "_id" : "29301", "city" : "SPARTANBURG", "loc" : [ -81.965377, 34.935211 ], "pop" : 45811, "state" : "SC" }
+{ "_id" : "29302", "city" : "SPARTANBURG", "loc" : [ -81.873625, 34.956283 ], "pop" : 36446, "state" : "SC" }
+{ "_id" : "29303", "city" : "VALLEY FALLS", "loc" : [ -81.957566, 34.993728 ], "pop" : 29166, "state" : "SC" }
+{ "_id" : "29321", "city" : "BUFFALO", "loc" : [ -81.682576, 34.724703 ], "pop" : 1810, "state" : "SC" }
+{ "_id" : "29322", "city" : "CAMPOBELLO", "loc" : [ -82.140343, 35.108003 ], "pop" : 7479, "state" : "SC" }
+{ "_id" : "29323", "city" : "CHESNEE", "loc" : [ -81.86782700000001, 35.115398 ], "pop" : 14714, "state" : "SC" }
+{ "_id" : "29325", "city" : "CLINTON", "loc" : [ -81.87717000000001, 34.470692 ], "pop" : 16265, "state" : "SC" }
+{ "_id" : "29330", "city" : "COWPENS", "loc" : [ -81.822019, 35.038979 ], "pop" : 5279, "state" : "SC" }
+{ "_id" : "29332", "city" : "CROSS HILL", "loc" : [ -81.984278, 34.269274 ], "pop" : 1089, "state" : "SC" }
+{ "_id" : "29334", "city" : "DUNCAN", "loc" : [ -82.125821, 34.917645 ], "pop" : 5512, "state" : "SC" }
+{ "_id" : "29335", "city" : "ENOREE", "loc" : [ -81.92373000000001, 34.670952 ], "pop" : 3310, "state" : "SC" }
+{ "_id" : "29340", "city" : "GAFFNEY", "loc" : [ -81.649061, 35.061508 ], "pop" : 32761, "state" : "SC" }
+{ "_id" : "29349", "city" : "INMAN", "loc" : [ -82.054013, 35.052795 ], "pop" : 23348, "state" : "SC" }
+{ "_id" : "29351", "city" : "JOANNA", "loc" : [ -81.81907, 34.406795 ], "pop" : 2592, "state" : "SC" }
+{ "_id" : "29353", "city" : "KELTON", "loc" : [ -81.684218, 34.837368 ], "pop" : 3504, "state" : "SC" }
+{ "_id" : "29355", "city" : "KINARDS", "loc" : [ -81.71975, 34.355219 ], "pop" : 678, "state" : "SC" }
+{ "_id" : "29356", "city" : "LANDRUM", "loc" : [ -82.211473, 35.156486 ], "pop" : 6521, "state" : "SC" }
+{ "_id" : "29360", "city" : "ORA", "loc" : [ -82.026774, 34.500714 ], "pop" : 21437, "state" : "SC" }
+{ "_id" : "29365", "city" : "LYMAN", "loc" : [ -82.143479, 34.968443 ], "pop" : 4515, "state" : "SC" }
+{ "_id" : "29369", "city" : "MOORE", "loc" : [ -82.017893, 34.883453 ], "pop" : 6791, "state" : "SC" }
+{ "_id" : "29370", "city" : "MOUNTVILLE", "loc" : [ -81.958429, 34.340791 ], "pop" : 1139, "state" : "SC" }
+{ "_id" : "29372", "city" : "PACOLET", "loc" : [ -81.758703, 34.901708 ], "pop" : 4129, "state" : "SC" }
+{ "_id" : "29374", "city" : "GLENN SPRINGS", "loc" : [ -81.85785300000001, 34.774808 ], "pop" : 4588, "state" : "SC" }
+{ "_id" : "29376", "city" : "ROEBUCK", "loc" : [ -81.95255, 34.8688 ], "pop" : 5009, "state" : "SC" }
+{ "_id" : "29379", "city" : "UNION", "loc" : [ -81.62023499999999, 34.726855 ], "pop" : 22553, "state" : "SC" }
+{ "_id" : "29384", "city" : "WATERLOO", "loc" : [ -82.087968, 34.33673 ], "pop" : 2992, "state" : "SC" }
+{ "_id" : "29385", "city" : "WELLFORD", "loc" : [ -82.09270600000001, 34.951394 ], "pop" : 6637, "state" : "SC" }
+{ "_id" : "29388", "city" : "WOODRUFF", "loc" : [ -82.044658, 34.757864 ], "pop" : 10206, "state" : "SC" }
+{ "_id" : "29401", "city" : "CHARLESTON", "loc" : [ -79.93706899999999, 32.779506 ], "pop" : 12475, "state" : "SC" }
+{ "_id" : "29403", "city" : "CHARLESTON", "loc" : [ -79.94928299999999, 32.797575 ], "pop" : 24620, "state" : "SC" }
+{ "_id" : "29404", "city" : "CHARLESTON", "loc" : [ -80.06768700000001, 32.895816 ], "pop" : 5420, "state" : "SC" }
+{ "_id" : "29405", "city" : "CHARLESTON", "loc" : [ -79.97644200000001, 32.851206 ], "pop" : 30621, "state" : "SC" }
+{ "_id" : "29406", "city" : "NORTH CHARLESTON", "loc" : [ -80.001053, 32.903035 ], "pop" : 27726, "state" : "SC" }
+{ "_id" : "29407", "city" : "CHARLESTON", "loc" : [ -80.00595300000001, 32.799322 ], "pop" : 38597, "state" : "SC" }
+{ "_id" : "29412", "city" : "CHARLESTON", "loc" : [ -79.95472700000001, 32.732319 ], "pop" : 29969, "state" : "SC" }
+{ "_id" : "29414", "city" : "CHARLESTON", "loc" : [ -80.05675599999999, 32.821538 ], "pop" : 19404, "state" : "SC" }
+{ "_id" : "29418", "city" : "CHARLESTON", "loc" : [ -80.055126, 32.907135 ], "pop" : 39784, "state" : "SC" }
+{ "_id" : "29420", "city" : "CHARLESTON", "loc" : [ -80.08646299999999, 32.933096 ], "pop" : 11598, "state" : "SC" }
+{ "_id" : "29426", "city" : "JERICHO", "loc" : [ -80.368197, 32.749318 ], "pop" : 1723, "state" : "SC" }
+{ "_id" : "29429", "city" : "AWENDAW", "loc" : [ -79.686075, 32.951475 ], "pop" : 1831, "state" : "SC" }
+{ "_id" : "29431", "city" : "BONNEAU", "loc" : [ -79.92164, 33.297332 ], "pop" : 7431, "state" : "SC" }
+{ "_id" : "29432", "city" : "BRANCHVILLE", "loc" : [ -80.805931, 33.262802 ], "pop" : 2165, "state" : "SC" }
+{ "_id" : "29434", "city" : "CORDESVILLE", "loc" : [ -79.920492, 33.162127 ], "pop" : 1382, "state" : "SC" }
+{ "_id" : "29435", "city" : "COTTAGEVILLE", "loc" : [ -80.47941400000001, 32.961171 ], "pop" : 4105, "state" : "SC" }
+{ "_id" : "29436", "city" : "CROSS", "loc" : [ -80.185901, 33.336373 ], "pop" : 3016, "state" : "SC" }
+{ "_id" : "29437", "city" : "DORCHESTER", "loc" : [ -80.403398, 33.124688 ], "pop" : 928, "state" : "SC" }
+{ "_id" : "29438", "city" : "EDISTO ISLAND", "loc" : [ -80.30701000000001, 32.548572 ], "pop" : 1669, "state" : "SC" }
+{ "_id" : "29440", "city" : "GEORGETOWN", "loc" : [ -79.323459, 33.430776 ], "pop" : 29148, "state" : "SC" }
+{ "_id" : "29445", "city" : "MOUNT HOLLY", "loc" : [ -80.019948, 32.988699 ], "pop" : 44954, "state" : "SC" }
+{ "_id" : "29446", "city" : "GREEN POND", "loc" : [ -80.528035, 32.662827 ], "pop" : 2068, "state" : "SC" }
+{ "_id" : "29448", "city" : "HARLEYVILLE", "loc" : [ -80.45009400000001, 33.220511 ], "pop" : 3289, "state" : "SC" }
+{ "_id" : "29449", "city" : "MEGGETT", "loc" : [ -80.25956600000001, 32.722306 ], "pop" : 6397, "state" : "SC" }
+{ "_id" : "29450", "city" : "HUGER", "loc" : [ -79.807254, 33.018436 ], "pop" : 1964, "state" : "SC" }
+{ "_id" : "29451", "city" : "ISLE OF PALMS", "loc" : [ -79.772949, 32.794252 ], "pop" : 3680, "state" : "SC" }
+{ "_id" : "29453", "city" : "SHULERVILLE", "loc" : [ -79.715551, 33.228797 ], "pop" : 1852, "state" : "SC" }
+{ "_id" : "29455", "city" : "JOHNS ISLAND", "loc" : [ -80.094294, 32.709697 ], "pop" : 11756, "state" : "SC" }
+{ "_id" : "29456", "city" : "LADSON", "loc" : [ -80.12570100000001, 32.993019 ], "pop" : 16216, "state" : "SC" }
+{ "_id" : "29458", "city" : "MC CLELLANVILLE", "loc" : [ -79.47998200000001, 33.10472 ], "pop" : 3020, "state" : "SC" }
+{ "_id" : "29461", "city" : "OAKLEY", "loc" : [ -80.036576, 33.163071 ], "pop" : 17822, "state" : "SC" }
+{ "_id" : "29464", "city" : "MOUNT PLEASANT", "loc" : [ -79.852031, 32.816211 ], "pop" : 35432, "state" : "SC" }
+{ "_id" : "29468", "city" : "PINEVILLE", "loc" : [ -80.093181, 33.419926 ], "pop" : 1411, "state" : "SC" }
+{ "_id" : "29469", "city" : "PINOPOLIS", "loc" : [ -80.039761, 33.224125 ], "pop" : 958, "state" : "SC" }
+{ "_id" : "29470", "city" : "RAVENEL", "loc" : [ -80.222346, 32.788088 ], "pop" : 3248, "state" : "SC" }
+{ "_id" : "29471", "city" : "REEVESVILLE", "loc" : [ -80.66725, 33.187213 ], "pop" : 1342, "state" : "SC" }
+{ "_id" : "29472", "city" : "RIDGEVILLE", "loc" : [ -80.308611, 33.108017 ], "pop" : 7494, "state" : "SC" }
+{ "_id" : "29474", "city" : "ROUND O", "loc" : [ -80.573882, 32.940516 ], "pop" : 64, "state" : "SC" }
+{ "_id" : "29475", "city" : "RUFFIN", "loc" : [ -80.813653, 33.010319 ], "pop" : 269, "state" : "SC" }
+{ "_id" : "29477", "city" : "SAINT GEORGE", "loc" : [ -80.573246, 33.184532 ], "pop" : 6940, "state" : "SC" }
+{ "_id" : "29479", "city" : "ALVIN", "loc" : [ -79.937635, 33.405953 ], "pop" : 5483, "state" : "SC" }
+{ "_id" : "29481", "city" : "SMOAKS", "loc" : [ -80.81302100000001, 33.096319 ], "pop" : 2074, "state" : "SC" }
+{ "_id" : "29482", "city" : "SULLIVANS ISLAND", "loc" : [ -79.839905, 32.763652 ], "pop" : 1623, "state" : "SC" }
+{ "_id" : "29483", "city" : "SUMMERVILLE", "loc" : [ -80.173852, 33.028045 ], "pop" : 45292, "state" : "SC" }
+{ "_id" : "29485", "city" : "SUMMERVILLE", "loc" : [ -80.183082, 32.975556 ], "pop" : 24856, "state" : "SC" }
+{ "_id" : "29487", "city" : "WADMALAW ISLAND", "loc" : [ -80.182867, 32.652854 ], "pop" : 2570, "state" : "SC" }
+{ "_id" : "29488", "city" : "RITTER", "loc" : [ -80.679225, 32.897367 ], "pop" : 24002, "state" : "SC" }
+{ "_id" : "29492", "city" : "WANDO", "loc" : [ -79.86533, 32.962223 ], "pop" : 1433, "state" : "SC" }
+{ "_id" : "29501", "city" : "FLORENCE", "loc" : [ -79.772786, 34.18375 ], "pop" : 66990, "state" : "SC" }
+{ "_id" : "29505", "city" : "FLORENCE", "loc" : [ -79.775983, 34.256368 ], "pop" : 1440, "state" : "SC" }
+{ "_id" : "29506", "city" : "QUINBY", "loc" : [ -79.79454699999999, 34.245178 ], "pop" : 0, "state" : "SC" }
+{ "_id" : "29510", "city" : "ANDREWS", "loc" : [ -79.560438, 33.452525 ], "pop" : 9845, "state" : "SC" }
+{ "_id" : "29511", "city" : "AYNOR", "loc" : [ -79.17773, 33.982271 ], "pop" : 6786, "state" : "SC" }
+{ "_id" : "29512", "city" : "BENNETTSVILLE", "loc" : [ -79.689826, 34.625501 ], "pop" : 15751, "state" : "SC" }
+{ "_id" : "29516", "city" : "BLENHEIM", "loc" : [ -79.65942200000001, 34.502033 ], "pop" : 2123, "state" : "SC" }
+{ "_id" : "29518", "city" : "CADES", "loc" : [ -79.817567, 33.812017 ], "pop" : 2748, "state" : "SC" }
+{ "_id" : "29520", "city" : "CHERAW", "loc" : [ -79.91741399999999, 34.686275 ], "pop" : 13063, "state" : "SC" }
+{ "_id" : "29525", "city" : "CLIO", "loc" : [ -79.545255, 34.58052 ], "pop" : 2870, "state" : "SC" }
+{ "_id" : "29526", "city" : "CONWAY", "loc" : [ -79.055712, 33.873066 ], "pop" : 17560, "state" : "SC" }
+{ "_id" : "29527", "city" : "BUCKSPORT", "loc" : [ -79.050836, 33.77922 ], "pop" : 19781, "state" : "SC" }
+{ "_id" : "29530", "city" : "COWARD", "loc" : [ -79.75152300000001, 33.990514 ], "pop" : 2098, "state" : "SC" }
+{ "_id" : "29532", "city" : "DARLINGTON", "loc" : [ -79.873221, 34.300294 ], "pop" : 22271, "state" : "SC" }
+{ "_id" : "29536", "city" : "DILLON", "loc" : [ -79.377015, 34.414553 ], "pop" : 9113, "state" : "SC" }
+{ "_id" : "29541", "city" : "EFFINGHAM", "loc" : [ -79.791822, 34.094571 ], "pop" : 8031, "state" : "SC" }
+{ "_id" : "29543", "city" : "FORK", "loc" : [ -79.250063, 34.28733 ], "pop" : 916, "state" : "SC" }
+{ "_id" : "29544", "city" : "GALIVANTS FERRY", "loc" : [ -79.105915, 34.123801 ], "pop" : 1129, "state" : "SC" }
+{ "_id" : "29545", "city" : "GREEN SEA", "loc" : [ -79.051613, 34.205105 ], "pop" : 1814, "state" : "SC" }
+{ "_id" : "29546", "city" : "GRESHAM", "loc" : [ -79.356426, 33.906941 ], "pop" : 2262, "state" : "SC" }
+{ "_id" : "29547", "city" : "SOUTH OF THE BOR", "loc" : [ -79.377871, 34.484556 ], "pop" : 4643, "state" : "SC" }
+{ "_id" : "29550", "city" : "HARTSVILLE", "loc" : [ -80.084237, 34.375616 ], "pop" : 27888, "state" : "SC" }
+{ "_id" : "29554", "city" : "HEMINGWAY", "loc" : [ -79.44889499999999, 33.741887 ], "pop" : 5578, "state" : "SC" }
+{ "_id" : "29555", "city" : "JOHNSONVILLE", "loc" : [ -79.478256, 33.829873 ], "pop" : 6115, "state" : "SC" }
+{ "_id" : "29556", "city" : "KINGSTREE", "loc" : [ -79.783221, 33.687841 ], "pop" : 16365, "state" : "SC" }
+{ "_id" : "29560", "city" : "LAKE CITY", "loc" : [ -79.741794, 33.865473 ], "pop" : 11664, "state" : "SC" }
+{ "_id" : "29563", "city" : "LAKE VIEW", "loc" : [ -79.192869, 34.34449 ], "pop" : 3513, "state" : "SC" }
+{ "_id" : "29564", "city" : "LANE", "loc" : [ -79.871545, 33.50827 ], "pop" : 1730, "state" : "SC" }
+{ "_id" : "29565", "city" : "LATTA", "loc" : [ -79.441704, 34.339829 ], "pop" : 6435, "state" : "SC" }
+{ "_id" : "29566", "city" : "LITTLE RIVER", "loc" : [ -78.650829, 33.876806 ], "pop" : 6473, "state" : "SC" }
+{ "_id" : "29567", "city" : "LITTLE ROCK", "loc" : [ -79.326948, 34.404803 ], "pop" : 4489, "state" : "SC" }
+{ "_id" : "29568", "city" : "LONGS", "loc" : [ -78.793359, 33.906408 ], "pop" : 5936, "state" : "SC" }
+{ "_id" : "29569", "city" : "LORIS", "loc" : [ -78.916096, 34.055756 ], "pop" : 11189, "state" : "SC" }
+{ "_id" : "29570", "city" : "MC COLL", "loc" : [ -79.559741, 34.670406 ], "pop" : 5224, "state" : "SC" }
+{ "_id" : "29571", "city" : "MARION", "loc" : [ -79.389822, 34.156195 ], "pop" : 16285, "state" : "SC" }
+{ "_id" : "29572", "city" : "MYRTLE BEACH", "loc" : [ -78.80444799999999, 33.758701 ], "pop" : 7039, "state" : "SC" }
+{ "_id" : "29574", "city" : "MULLINS", "loc" : [ -79.254155, 34.204441 ], "pop" : 12118, "state" : "SC" }
+{ "_id" : "29575", "city" : "SURFSIDE BEACH", "loc" : [ -78.995228, 33.625245 ], "pop" : 24545, "state" : "SC" }
+{ "_id" : "29576", "city" : "MURRELLS INLET", "loc" : [ -79.05275, 33.550717 ], "pop" : 4209, "state" : "SC" }
+{ "_id" : "29577", "city" : "MYRTLE BEACH", "loc" : [ -78.913697, 33.699363 ], "pop" : 31917, "state" : "SC" }
+{ "_id" : "29580", "city" : "NESMITH", "loc" : [ -79.551301, 33.591652 ], "pop" : 3297, "state" : "SC" }
+{ "_id" : "29581", "city" : "NICHOLS", "loc" : [ -79.162493, 34.242629 ], "pop" : 1258, "state" : "SC" }
+{ "_id" : "29582", "city" : "CHERRY GROVE BEA", "loc" : [ -78.67792, 33.822801 ], "pop" : 9910, "state" : "SC" }
+{ "_id" : "29583", "city" : "PAMPLICO", "loc" : [ -79.592917, 33.992166 ], "pop" : 6291, "state" : "SC" }
+{ "_id" : "29584", "city" : "PATRICK", "loc" : [ -80.064984, 34.559823 ], "pop" : 3800, "state" : "SC" }
+{ "_id" : "29585", "city" : "PAWLEYS ISLAND", "loc" : [ -79.134128, 33.450825 ], "pop" : 5445, "state" : "SC" }
+{ "_id" : "29590", "city" : "SALTERS", "loc" : [ -79.83002399999999, 33.561138 ], "pop" : 1932, "state" : "SC" }
+{ "_id" : "29591", "city" : "SCRANTON", "loc" : [ -79.773101, 33.92813 ], "pop" : 4122, "state" : "SC" }
+{ "_id" : "29592", "city" : "SELLERS", "loc" : [ -79.436948, 34.269522 ], "pop" : 1976, "state" : "SC" }
+{ "_id" : "29593", "city" : "SOCIETY HILL", "loc" : [ -79.886494, 34.451161 ], "pop" : 3278, "state" : "SC" }
+{ "_id" : "29596", "city" : "WALLACE", "loc" : [ -79.801142, 34.730704 ], "pop" : 3398, "state" : "SC" }
+{ "_id" : "29601", "city" : "GREENVILLE", "loc" : [ -82.406049, 34.847165 ], "pop" : 11198, "state" : "SC" }
+{ "_id" : "29605", "city" : "GREENVILLE", "loc" : [ -82.393218, 34.800117 ], "pop" : 32092, "state" : "SC" }
+{ "_id" : "29607", "city" : "GREENVILLE", "loc" : [ -82.35155, 34.828507 ], "pop" : 26926, "state" : "SC" }
+{ "_id" : "29609", "city" : "GREENVILLE", "loc" : [ -82.400195, 34.892101 ], "pop" : 35346, "state" : "SC" }
+{ "_id" : "29611", "city" : "GREENVILLE", "loc" : [ -82.449296, 34.85331 ], "pop" : 43522, "state" : "SC" }
+{ "_id" : "29615", "city" : "GREENVILLE", "loc" : [ -82.31981500000001, 34.866095 ], "pop" : 25818, "state" : "SC" }
+{ "_id" : "29620", "city" : "ABBEVILLE", "loc" : [ -82.378452, 34.18186 ], "pop" : 11344, "state" : "SC" }
+{ "_id" : "29621", "city" : "ANDERSON", "loc" : [ -82.630436, 34.526051 ], "pop" : 24256, "state" : "SC" }
+{ "_id" : "29624", "city" : "ANDERSON", "loc" : [ -82.677052, 34.474807 ], "pop" : 26962, "state" : "SC" }
+{ "_id" : "29625", "city" : "ANDERSON", "loc" : [ -82.70868, 34.527134 ], "pop" : 20105, "state" : "SC" }
+{ "_id" : "29627", "city" : "BELTON", "loc" : [ -82.51010599999999, 34.508715 ], "pop" : 11371, "state" : "SC" }
+{ "_id" : "29628", "city" : "CALHOUN FALLS", "loc" : [ -82.580544, 34.099912 ], "pop" : 3289, "state" : "SC" }
+{ "_id" : "29630", "city" : "CENTRAL", "loc" : [ -82.79472699999999, 34.74007 ], "pop" : 8226, "state" : "SC" }
+{ "_id" : "29631", "city" : "CLEMSON", "loc" : [ -82.825003, 34.683061 ], "pop" : 17987, "state" : "SC" }
+{ "_id" : "29635", "city" : "CLEVELAND", "loc" : [ -82.609256, 35.06537 ], "pop" : 960, "state" : "SC" }
+{ "_id" : "29638", "city" : "SHOALS JUNCTION", "loc" : [ -82.36661599999999, 34.399772 ], "pop" : 1347, "state" : "SC" }
+{ "_id" : "29639", "city" : "DUE WEST", "loc" : [ -82.400164, 34.334425 ], "pop" : 3499, "state" : "SC" }
+{ "_id" : "29640", "city" : "EASLEY", "loc" : [ -82.57955200000001, 34.829031 ], "pop" : 37862, "state" : "SC" }
+{ "_id" : "29642", "city" : "EASLEY", "loc" : [ -82.561716, 34.960694 ], "pop" : 830, "state" : "SC" }
+{ "_id" : "29643", "city" : "FAIR PLAY", "loc" : [ -82.99987400000001, 34.577548 ], "pop" : 6110, "state" : "SC" }
+{ "_id" : "29644", "city" : "FOUNTAIN INN", "loc" : [ -82.264593, 34.653334 ], "pop" : 15233, "state" : "SC" }
+{ "_id" : "29645", "city" : "ORA", "loc" : [ -82.15703499999999, 34.580984 ], "pop" : 9987, "state" : "SC" }
+{ "_id" : "29646", "city" : "GREENWOOD", "loc" : [ -82.156211, 34.175802 ], "pop" : 23138, "state" : "SC" }
+{ "_id" : "29649", "city" : "GREENWOOD", "loc" : [ -82.15818899999999, 34.222988 ], "pop" : 18588, "state" : "SC" }
+{ "_id" : "29650", "city" : "GREER", "loc" : [ -82.267442, 34.8968 ], "pop" : 16460, "state" : "SC" }
+{ "_id" : "29651", "city" : "GREER", "loc" : [ -82.220857, 34.94532 ], "pop" : 26573, "state" : "SC" }
+{ "_id" : "29653", "city" : "HODGES", "loc" : [ -82.214225, 34.288167 ], "pop" : 5262, "state" : "SC" }
+{ "_id" : "29654", "city" : "HONEA PATH", "loc" : [ -82.425471, 34.441723 ], "pop" : 7621, "state" : "SC" }
+{ "_id" : "29655", "city" : "IVA", "loc" : [ -82.657437, 34.319847 ], "pop" : 5342, "state" : "SC" }
+{ "_id" : "29657", "city" : "LIBERTY", "loc" : [ -82.697429, 34.787189 ], "pop" : 9519, "state" : "SC" }
+{ "_id" : "29658", "city" : "LONG CREEK", "loc" : [ -83.18472800000001, 34.754954 ], "pop" : 1972, "state" : "SC" }
+{ "_id" : "29659", "city" : "LOWNDESVILLE", "loc" : [ -82.571021, 34.26624 ], "pop" : 2565, "state" : "SC" }
+{ "_id" : "29661", "city" : "MARIETTA", "loc" : [ -82.513622, 35.029644 ], "pop" : 6321, "state" : "SC" }
+{ "_id" : "29662", "city" : "MAULDIN", "loc" : [ -82.303507, 34.780675 ], "pop" : 8871, "state" : "SC" }
+{ "_id" : "29664", "city" : "MOUNTAIN REST", "loc" : [ -83.11340199999999, 34.854119 ], "pop" : 1717, "state" : "SC" }
+{ "_id" : "29666", "city" : "NINETY SIX", "loc" : [ -82.029185, 34.165198 ], "pop" : 8668, "state" : "SC" }
+{ "_id" : "29667", "city" : "CATEECHEE", "loc" : [ -82.755492, 34.765472 ], "pop" : 738, "state" : "SC" }
+{ "_id" : "29669", "city" : "PELZER", "loc" : [ -82.46733399999999, 34.646063 ], "pop" : 3224, "state" : "SC" }
+{ "_id" : "29670", "city" : "PENDLETON", "loc" : [ -82.740623, 34.63694 ], "pop" : 12288, "state" : "SC" }
+{ "_id" : "29671", "city" : "PICKENS", "loc" : [ -82.70578399999999, 34.902403 ], "pop" : 16227, "state" : "SC" }
+{ "_id" : "29673", "city" : "PIEDMONT", "loc" : [ -82.47021599999999, 34.724433 ], "pop" : 24083, "state" : "SC" }
+{ "_id" : "29676", "city" : "SALEM", "loc" : [ -82.96068699999999, 34.872836 ], "pop" : 4091, "state" : "SC" }
+{ "_id" : "29678", "city" : "SENECA", "loc" : [ -82.936162, 34.682797 ], "pop" : 20361, "state" : "SC" }
+{ "_id" : "29681", "city" : "SIMPSONVILLE", "loc" : [ -82.255009, 34.751228 ], "pop" : 28438, "state" : "SC" }
+{ "_id" : "29682", "city" : "SIX MILE", "loc" : [ -82.82779499999999, 34.828287 ], "pop" : 2757, "state" : "SC" }
+{ "_id" : "29684", "city" : "STARR", "loc" : [ -82.68971000000001, 34.396196 ], "pop" : 2995, "state" : "SC" }
+{ "_id" : "29685", "city" : "SUNSET", "loc" : [ -82.80763899999999, 34.970617 ], "pop" : 850, "state" : "SC" }
+{ "_id" : "29686", "city" : "TAMASSEE", "loc" : [ -82.986138, 34.898229 ], "pop" : 156, "state" : "SC" }
+{ "_id" : "29687", "city" : "TAYLORS", "loc" : [ -82.31968000000001, 34.924517 ], "pop" : 32831, "state" : "SC" }
+{ "_id" : "29688", "city" : "TIGERVILLE", "loc" : [ -82.35823600000001, 35.094443 ], "pop" : 231, "state" : "SC" }
+{ "_id" : "29689", "city" : "TOWNVILLE", "loc" : [ -82.89633000000001, 34.522638 ], "pop" : 1784, "state" : "SC" }
+{ "_id" : "29690", "city" : "TRAVELERS REST", "loc" : [ -82.427179, 35.003929 ], "pop" : 14029, "state" : "SC" }
+{ "_id" : "29691", "city" : "WALHALLA", "loc" : [ -83.03877799999999, 34.768902 ], "pop" : 14047, "state" : "SC" }
+{ "_id" : "29692", "city" : "WARE SHOALS", "loc" : [ -82.26779000000001, 34.402491 ], "pop" : 4442, "state" : "SC" }
+{ "_id" : "29693", "city" : "MADISON", "loc" : [ -83.110782, 34.658857 ], "pop" : 8933, "state" : "SC" }
+{ "_id" : "29696", "city" : "WEST UNION", "loc" : [ -83.03988699999999, 34.751572 ], "pop" : 170, "state" : "SC" }
+{ "_id" : "29697", "city" : "WILLIAMSTON", "loc" : [ -82.51100599999999, 34.620572 ], "pop" : 13511, "state" : "SC" }
+{ "_id" : "29702", "city" : "CHEROKEE FALLS", "loc" : [ -81.508004, 35.115047 ], "pop" : 7481, "state" : "SC" }
+{ "_id" : "29704", "city" : "CATAWBA", "loc" : [ -80.93415400000001, 34.850712 ], "pop" : 2451, "state" : "SC" }
+{ "_id" : "29706", "city" : "CHESTER", "loc" : [ -81.21856, 34.714897 ], "pop" : 21920, "state" : "SC" }
+{ "_id" : "29709", "city" : "CHESTERFIELD", "loc" : [ -80.09577, 34.727834 ], "pop" : 6286, "state" : "SC" }
+{ "_id" : "29710", "city" : "LAKE WYLIE", "loc" : [ -81.186358, 35.110728 ], "pop" : 17905, "state" : "SC" }
+{ "_id" : "29712", "city" : "EDGEMOOR", "loc" : [ -80.98909500000001, 34.797006 ], "pop" : 1725, "state" : "SC" }
+{ "_id" : "29714", "city" : "FORT LAWN", "loc" : [ -80.909175, 34.70064 ], "pop" : 2106, "state" : "SC" }
+{ "_id" : "29715", "city" : "TEGA CAY", "loc" : [ -80.95855899999999, 35.026001 ], "pop" : 17343, "state" : "SC" }
+{ "_id" : "29717", "city" : "HICKORY GROVE", "loc" : [ -81.430599, 34.970833 ], "pop" : 932, "state" : "SC" }
+{ "_id" : "29718", "city" : "JEFFERSON", "loc" : [ -80.363934, 34.654581 ], "pop" : 3257, "state" : "SC" }
+{ "_id" : "29720", "city" : "LANCASTER", "loc" : [ -80.76157600000001, 34.749006 ], "pop" : 43745, "state" : "SC" }
+{ "_id" : "29726", "city" : "MC CONNELLS", "loc" : [ -81.23680299999999, 34.867667 ], "pop" : 1431, "state" : "SC" }
+{ "_id" : "29727", "city" : "MOUNT CROGHAN", "loc" : [ -80.242791, 34.743895 ], "pop" : 1584, "state" : "SC" }
+{ "_id" : "29728", "city" : "PAGELAND", "loc" : [ -80.396615, 34.772193 ], "pop" : 7778, "state" : "SC" }
+{ "_id" : "29729", "city" : "RICHBURG", "loc" : [ -80.98906100000001, 34.682185 ], "pop" : 2393, "state" : "SC" }
+{ "_id" : "29730", "city" : "ROCK HILL", "loc" : [ -81.01290400000001, 34.915068 ], "pop" : 41461, "state" : "SC" }
+{ "_id" : "29732", "city" : "ROCK HILL", "loc" : [ -81.04888099999999, 34.968066 ], "pop" : 30532, "state" : "SC" }
+{ "_id" : "29741", "city" : "RUBY", "loc" : [ -80.190966, 34.737928 ], "pop" : 478, "state" : "SC" }
+{ "_id" : "29742", "city" : "SHARON", "loc" : [ -81.372907, 34.908396 ], "pop" : 1175, "state" : "SC" }
+{ "_id" : "29743", "city" : "SMYRNA", "loc" : [ -81.389606, 35.030784 ], "pop" : 877, "state" : "SC" }
+{ "_id" : "29745", "city" : "YORK", "loc" : [ -81.224462, 34.994669 ], "pop" : 17279, "state" : "SC" }
+{ "_id" : "29801", "city" : "AIKEN", "loc" : [ -81.71942900000001, 33.553024 ], "pop" : 51233, "state" : "SC" }
+{ "_id" : "29803", "city" : "AIKEN", "loc" : [ -81.594702, 33.531868 ], "pop" : 743, "state" : "SC" }
+{ "_id" : "29809", "city" : "NEW ELLENTON", "loc" : [ -81.687376, 33.417242 ], "pop" : 2586, "state" : "SC" }
+{ "_id" : "29810", "city" : "ALLENDALE", "loc" : [ -81.32025400000001, 33.007676 ], "pop" : 5704, "state" : "SC" }
+{ "_id" : "29812", "city" : "BARNWELL", "loc" : [ -81.35231, 33.233492 ], "pop" : 11016, "state" : "SC" }
+{ "_id" : "29817", "city" : "BLACKVILLE", "loc" : [ -81.271844, 33.364476 ], "pop" : 4254, "state" : "SC" }
+{ "_id" : "29819", "city" : "BRADLEY", "loc" : [ -82.20272300000001, 34.032587 ], "pop" : 1287, "state" : "SC" }
+{ "_id" : "29821", "city" : "CLARKS HILL", "loc" : [ -82.14875000000001, 33.65052 ], "pop" : 439, "state" : "SC" }
+{ "_id" : "29824", "city" : "EDGEFIELD", "loc" : [ -81.96602, 33.805553 ], "pop" : 6884, "state" : "SC" }
+{ "_id" : "29827", "city" : "FAIRFAX", "loc" : [ -81.25864, 32.951455 ], "pop" : 4017, "state" : "SC" }
+{ "_id" : "29829", "city" : "GRANITEVILLE", "loc" : [ -81.81468599999999, 33.563016 ], "pop" : 2858, "state" : "SC" }
+{ "_id" : "29831", "city" : "JACKSON", "loc" : [ -81.797628, 33.338886 ], "pop" : 2810, "state" : "SC" }
+{ "_id" : "29832", "city" : "JOHNSTON", "loc" : [ -81.797242, 33.823075 ], "pop" : 4616, "state" : "SC" }
+{ "_id" : "29835", "city" : "MC CORMICK", "loc" : [ -82.271862, 33.914646 ], "pop" : 5426, "state" : "SC" }
+{ "_id" : "29836", "city" : "MARTIN", "loc" : [ -81.500304, 33.109286 ], "pop" : 566, "state" : "SC" }
+{ "_id" : "29838", "city" : "MODOC", "loc" : [ -82.203469, 33.724894 ], "pop" : 380, "state" : "SC" }
+{ "_id" : "29840", "city" : "MOUNT CARMEL", "loc" : [ -82.43607, 33.970323 ], "pop" : 1354, "state" : "SC" }
+{ "_id" : "29841", "city" : "BEECH ISLAND", "loc" : [ -81.934794, 33.517766 ], "pop" : 45886, "state" : "SC" }
+{ "_id" : "29843", "city" : "OLAR", "loc" : [ -81.16404199999999, 33.18364 ], "pop" : 1503, "state" : "SC" }
+{ "_id" : "29845", "city" : "PLUM BRANCH", "loc" : [ -82.248041, 33.832893 ], "pop" : 1144, "state" : "SC" }
+{ "_id" : "29847", "city" : "TRENTON", "loc" : [ -81.853392, 33.693757 ], "pop" : 2825, "state" : "SC" }
+{ "_id" : "29848", "city" : "TROY", "loc" : [ -82.294077, 33.955654 ], "pop" : 125, "state" : "SC" }
+{ "_id" : "29849", "city" : "ULMER", "loc" : [ -81.22129200000001, 33.057597 ], "pop" : 1241, "state" : "SC" }
+{ "_id" : "29851", "city" : "WARRENVILLE", "loc" : [ -81.829397, 33.519917 ], "pop" : 8739, "state" : "SC" }
+{ "_id" : "29853", "city" : "WILLISTON", "loc" : [ -81.416146, 33.392608 ], "pop" : 5011, "state" : "SC" }
+{ "_id" : "29856", "city" : "WINDSOR", "loc" : [ -81.513626, 33.467446 ], "pop" : 2264, "state" : "SC" }
+{ "_id" : "29902", "city" : "BURTON", "loc" : [ -80.70902599999999, 32.418035 ], "pop" : 43849, "state" : "SC" }
+{ "_id" : "29910", "city" : "BLUFFTON", "loc" : [ -80.872079, 32.251275 ], "pop" : 6912, "state" : "SC" }
+{ "_id" : "29911", "city" : "BRUNSON", "loc" : [ -81.180719, 32.941297 ], "pop" : 1422, "state" : "SC" }
+{ "_id" : "29916", "city" : "EARLY BRANCH", "loc" : [ -81.030011, 32.628893 ], "pop" : 1494, "state" : "SC" }
+{ "_id" : "29918", "city" : "ESTILL", "loc" : [ -81.21776800000001, 32.737514 ], "pop" : 6210, "state" : "SC" }
+{ "_id" : "29920", "city" : "ST HELENA ISLAND", "loc" : [ -80.533863, 32.380213 ], "pop" : 4669, "state" : "SC" }
+{ "_id" : "29922", "city" : "GARNETT", "loc" : [ -81.23962899999999, 32.600666 ], "pop" : 61, "state" : "SC" }
+{ "_id" : "29924", "city" : "HAMPTON", "loc" : [ -81.09733300000001, 32.87288 ], "pop" : 5987, "state" : "SC" }
+{ "_id" : "29926", "city" : "HILTON HEAD ISLA", "loc" : [ -80.728088, 32.229426 ], "pop" : 9480, "state" : "SC" }
+{ "_id" : "29927", "city" : "HARDEEVILLE", "loc" : [ -81.06686500000001, 32.263512 ], "pop" : 4948, "state" : "SC" }
+{ "_id" : "29928", "city" : "HILTON HEAD ISLA", "loc" : [ -80.75657699999999, 32.158718 ], "pop" : 14504, "state" : "SC" }
+{ "_id" : "29929", "city" : "ISLANDTON", "loc" : [ -80.891589, 32.950324 ], "pop" : 119, "state" : "SC" }
+{ "_id" : "29932", "city" : "LURAY", "loc" : [ -81.223506, 32.86177 ], "pop" : 687, "state" : "SC" }
+{ "_id" : "29934", "city" : "PINELAND", "loc" : [ -81.17611599999999, 32.602065 ], "pop" : 925, "state" : "SC" }
+{ "_id" : "29935", "city" : "PORT ROYAL", "loc" : [ -80.69278, 32.384205 ], "pop" : 2526, "state" : "SC" }
+{ "_id" : "29936", "city" : "COOSAWATCHIE", "loc" : [ -80.94943499999999, 32.491938 ], "pop" : 6342, "state" : "SC" }
+{ "_id" : "29940", "city" : "SEABROOK", "loc" : [ -80.740793, 32.526884 ], "pop" : 915, "state" : "SC" }
+{ "_id" : "29943", "city" : "TILLMAN", "loc" : [ -81.077567, 32.492719 ], "pop" : 1679, "state" : "SC" }
+{ "_id" : "29944", "city" : "VARNVILLE", "loc" : [ -81.028839, 32.834893 ], "pop" : 1890, "state" : "SC" }
+{ "_id" : "29945", "city" : "YEMASSEE", "loc" : [ -80.812932, 32.642983 ], "pop" : 5421, "state" : "SC" }
+{ "_id" : "30001", "city" : "AUSTELL", "loc" : [ -84.605026, 33.807226 ], "pop" : 25021, "state" : "GA" }
+{ "_id" : "30002", "city" : "AVONDALE ESTATES", "loc" : [ -84.26069099999999, 33.771727 ], "pop" : 4459, "state" : "GA" }
+{ "_id" : "30021", "city" : "CLARKSTON", "loc" : [ -84.23882500000001, 33.810107 ], "pop" : 17325, "state" : "GA" }
+{ "_id" : "30027", "city" : "CONLEY", "loc" : [ -84.32757100000001, 33.645104 ], "pop" : 6815, "state" : "GA" }
+{ "_id" : "30030", "city" : "DECATUR", "loc" : [ -84.295044, 33.769883 ], "pop" : 23185, "state" : "GA" }
+{ "_id" : "30032", "city" : "DECATUR", "loc" : [ -84.263165, 33.740825 ], "pop" : 56056, "state" : "GA" }
+{ "_id" : "30033", "city" : "DECATUR", "loc" : [ -84.281918, 33.812305 ], "pop" : 22071, "state" : "GA" }
+{ "_id" : "30034", "city" : "DECATUR", "loc" : [ -84.24893899999999, 33.695385 ], "pop" : 32312, "state" : "GA" }
+{ "_id" : "30035", "city" : "DECATUR", "loc" : [ -84.21429999999999, 33.72784 ], "pop" : 15062, "state" : "GA" }
+{ "_id" : "30038", "city" : "LITHONIA", "loc" : [ -84.16099699999999, 33.682311 ], "pop" : 15583, "state" : "GA" }
+{ "_id" : "30049", "city" : "ELLENWOOD", "loc" : [ -84.26433299999999, 33.635376 ], "pop" : 16742, "state" : "GA" }
+{ "_id" : "30050", "city" : "FOREST PARK", "loc" : [ -84.367075, 33.609737 ], "pop" : 26825, "state" : "GA" }
+{ "_id" : "30057", "city" : "LITHIA SPRINGS", "loc" : [ -84.66081, 33.772999 ], "pop" : 14533, "state" : "GA" }
+{ "_id" : "30058", "city" : "CENTERVILLE GWIN", "loc" : [ -84.09929099999999, 33.746412 ], "pop" : 37322, "state" : "GA" }
+{ "_id" : "30059", "city" : "MABLETON", "loc" : [ -84.565062, 33.816572 ], "pop" : 22519, "state" : "GA" }
+{ "_id" : "30060", "city" : "MARIETTA", "loc" : [ -84.564881, 33.909199 ], "pop" : 52530, "state" : "GA" }
+{ "_id" : "30062", "city" : "MARIETTA", "loc" : [ -84.463291, 34.002521 ], "pop" : 52642, "state" : "GA" }
+{ "_id" : "30064", "city" : "MARIETTA", "loc" : [ -84.607584, 33.934285 ], "pop" : 30260, "state" : "GA" }
+{ "_id" : "30066", "city" : "MARIETTA", "loc" : [ -84.503817, 34.037807 ], "pop" : 41948, "state" : "GA" }
+{ "_id" : "30067", "city" : "MARIETTA", "loc" : [ -84.473251, 33.928198 ], "pop" : 40460, "state" : "GA" }
+{ "_id" : "30068", "city" : "MARIETTA", "loc" : [ -84.43854899999999, 33.967861 ], "pop" : 29488, "state" : "GA" }
+{ "_id" : "30071", "city" : "NORCROSS", "loc" : [ -84.197158, 33.938145 ], "pop" : 16266, "state" : "GA" }
+{ "_id" : "30073", "city" : "POWDER SPRINGS", "loc" : [ -84.68564499999999, 33.875377 ], "pop" : 27767, "state" : "GA" }
+{ "_id" : "30075", "city" : "ROSWELL", "loc" : [ -84.385901, 34.040832 ], "pop" : 32144, "state" : "GA" }
+{ "_id" : "30076", "city" : "ROSWELL", "loc" : [ -84.310408, 34.021324 ], "pop" : 34027, "state" : "GA" }
+{ "_id" : "30079", "city" : "SCOTTDALE", "loc" : [ -84.258521, 33.793396 ], "pop" : 3288, "state" : "GA" }
+{ "_id" : "30080", "city" : "SMYRNA", "loc" : [ -84.502284, 33.879602 ], "pop" : 36899, "state" : "GA" }
+{ "_id" : "30082", "city" : "SMYRNA", "loc" : [ -84.538234, 33.863051 ], "pop" : 17917, "state" : "GA" }
+{ "_id" : "30083", "city" : "STONE MOUNTAIN", "loc" : [ -84.20175399999999, 33.794233 ], "pop" : 48785, "state" : "GA" }
+{ "_id" : "30084", "city" : "TUCKER", "loc" : [ -84.21602, 33.856986 ], "pop" : 29307, "state" : "GA" }
+{ "_id" : "30087", "city" : "STONE MOUNTAIN", "loc" : [ -84.128829, 33.811511 ], "pop" : 27251, "state" : "GA" }
+{ "_id" : "30088", "city" : "STONE MOUNTAIN", "loc" : [ -84.18022000000001, 33.75798 ], "pop" : 24029, "state" : "GA" }
+{ "_id" : "30092", "city" : "NORCROSS", "loc" : [ -84.243787, 33.967688 ], "pop" : 19901, "state" : "GA" }
+{ "_id" : "30093", "city" : "NORCROSS", "loc" : [ -84.183953, 33.905964 ], "pop" : 32345, "state" : "GA" }
+{ "_id" : "30101", "city" : "ACWORTH", "loc" : [ -84.647741, 34.075627 ], "pop" : 37976, "state" : "GA" }
+{ "_id" : "30103", "city" : "ADAIRSVILLE", "loc" : [ -84.91763400000001, 34.359527 ], "pop" : 7273, "state" : "GA" }
+{ "_id" : "30104", "city" : "ARAGON", "loc" : [ -85.069559, 34.066556 ], "pop" : 4692, "state" : "GA" }
+{ "_id" : "30105", "city" : "ARMUCHEE", "loc" : [ -85.184298, 34.441082 ], "pop" : 2131, "state" : "GA" }
+{ "_id" : "30107", "city" : "BALL GROUND", "loc" : [ -84.375756, 34.339262 ], "pop" : 4064, "state" : "GA" }
+{ "_id" : "30108", "city" : "BOWDON", "loc" : [ -85.25329000000001, 33.537259 ], "pop" : 7318, "state" : "GA" }
+{ "_id" : "30110", "city" : "BREMEN", "loc" : [ -85.128638, 33.730872 ], "pop" : 8495, "state" : "GA" }
+{ "_id" : "30113", "city" : "BUCHANAN", "loc" : [ -85.15055099999999, 33.82828 ], "pop" : 5931, "state" : "GA" }
+{ "_id" : "30114", "city" : "CANTON", "loc" : [ -84.457756, 34.205874 ], "pop" : 35773, "state" : "GA" }
+{ "_id" : "30117", "city" : "CARROLLTON", "loc" : [ -85.081211, 33.579751 ], "pop" : 40344, "state" : "GA" }
+{ "_id" : "30120", "city" : "CARTERSVILLE", "loc" : [ -84.820401, 34.186975 ], "pop" : 33846, "state" : "GA" }
+{ "_id" : "30124", "city" : "CAVE SPRING", "loc" : [ -85.337906, 34.116683 ], "pop" : 2650, "state" : "GA" }
+{ "_id" : "30125", "city" : "CEDARTOWN", "loc" : [ -85.24590000000001, 34.011196 ], "pop" : 20720, "state" : "GA" }
+{ "_id" : "30130", "city" : "CUMMING", "loc" : [ -84.146762, 34.220197 ], "pop" : 35496, "state" : "GA" }
+{ "_id" : "30132", "city" : "DALLAS", "loc" : [ -84.827791, 33.916315 ], "pop" : 28118, "state" : "GA" }
+{ "_id" : "30134", "city" : "DOUGLASVILLE", "loc" : [ -84.747719, 33.760645 ], "pop" : 17182, "state" : "GA" }
+{ "_id" : "30135", "city" : "DOUGLASVILLE", "loc" : [ -84.745441, 33.698936 ], "pop" : 32887, "state" : "GA" }
+{ "_id" : "30136", "city" : "DULUTH", "loc" : [ -84.15793600000001, 33.98619 ], "pop" : 30932, "state" : "GA" }
+{ "_id" : "30137", "city" : "EMERSON", "loc" : [ -84.75704500000001, 34.119969 ], "pop" : 1353, "state" : "GA" }
+{ "_id" : "30139", "city" : "FAIRMOUNT", "loc" : [ -84.76687800000001, 34.465241 ], "pop" : 3405, "state" : "GA" }
+{ "_id" : "30140", "city" : "FELTON", "loc" : [ -85.220781, 33.887066 ], "pop" : 489, "state" : "GA" }
+{ "_id" : "30141", "city" : "HIRAM", "loc" : [ -84.769875, 33.867286 ], "pop" : 6613, "state" : "GA" }
+{ "_id" : "30143", "city" : "JASPER", "loc" : [ -84.475881, 34.461965 ], "pop" : 8256, "state" : "GA" }
+{ "_id" : "30144", "city" : "KENNESAW", "loc" : [ -84.60466, 34.028656 ], "pop" : 37120, "state" : "GA" }
+{ "_id" : "30145", "city" : "KINGSTON", "loc" : [ -84.997299, 34.250053 ], "pop" : 2534, "state" : "GA" }
+{ "_id" : "30147", "city" : "LINDALE", "loc" : [ -85.182491, 34.170741 ], "pop" : 3502, "state" : "GA" }
+{ "_id" : "30148", "city" : "MARBLE HILL", "loc" : [ -84.33715100000001, 34.415353 ], "pop" : 98, "state" : "GA" }
+{ "_id" : "30153", "city" : "ROCKMART", "loc" : [ -85.05937, 33.997912 ], "pop" : 8946, "state" : "GA" }
+{ "_id" : "30161", "city" : "ROME", "loc" : [ -85.146501, 34.250726 ], "pop" : 33058, "state" : "GA" }
+{ "_id" : "30165", "city" : "ROME", "loc" : [ -85.223122, 34.283679 ], "pop" : 32739, "state" : "GA" }
+{ "_id" : "30170", "city" : "ROOPVILLE", "loc" : [ -85.167148, 33.432226 ], "pop" : 2952, "state" : "GA" }
+{ "_id" : "30171", "city" : "PINE LOG", "loc" : [ -84.780315, 34.392732 ], "pop" : 2257, "state" : "GA" }
+{ "_id" : "30173", "city" : "SILVER CREEK", "loc" : [ -85.142933, 34.159272 ], "pop" : 5968, "state" : "GA" }
+{ "_id" : "30174", "city" : "SUWANEE", "loc" : [ -84.082391, 34.057245 ], "pop" : 5965, "state" : "GA" }
+{ "_id" : "30175", "city" : "TALKING ROCK", "loc" : [ -84.49115399999999, 34.539356 ], "pop" : 3037, "state" : "GA" }
+{ "_id" : "30176", "city" : "TALLAPOOSA", "loc" : [ -85.30004700000001, 33.760174 ], "pop" : 6172, "state" : "GA" }
+{ "_id" : "30177", "city" : "TATE", "loc" : [ -84.36529899999999, 34.42387 ], "pop" : 4286, "state" : "GA" }
+{ "_id" : "30178", "city" : "TAYLORSVILLE", "loc" : [ -84.973859, 34.122941 ], "pop" : 2360, "state" : "GA" }
+{ "_id" : "30179", "city" : "TEMPLE", "loc" : [ -85.01331500000001, 33.767687 ], "pop" : 7111, "state" : "GA" }
+{ "_id" : "30180", "city" : "VILLA RICA", "loc" : [ -84.929697, 33.71729 ], "pop" : 12063, "state" : "GA" }
+{ "_id" : "30182", "city" : "WACO", "loc" : [ -85.219674, 33.683986 ], "pop" : 2297, "state" : "GA" }
+{ "_id" : "30183", "city" : "WALESKA", "loc" : [ -84.561981, 34.321662 ], "pop" : 3576, "state" : "GA" }
+{ "_id" : "30184", "city" : "WHITE", "loc" : [ -84.738327, 34.271683 ], "pop" : 3231, "state" : "GA" }
+{ "_id" : "30185", "city" : "WHITESBURG", "loc" : [ -84.925426, 33.511093 ], "pop" : 3115, "state" : "GA" }
+{ "_id" : "30187", "city" : "WINSTON", "loc" : [ -84.86391500000001, 33.663419 ], "pop" : 6850, "state" : "GA" }
+{ "_id" : "30188", "city" : "WOODSTOCK", "loc" : [ -84.511683, 34.106005 ], "pop" : 33172, "state" : "GA" }
+{ "_id" : "30201", "city" : "ALPHARETTA", "loc" : [ -84.29516700000001, 34.107677 ], "pop" : 19393, "state" : "GA" }
+{ "_id" : "30202", "city" : "ALPHARETTA", "loc" : [ -84.238972, 34.035487 ], "pop" : 24814, "state" : "GA" }
+{ "_id" : "30203", "city" : "AUBURN", "loc" : [ -83.824128, 34.007758 ], "pop" : 6457, "state" : "GA" }
+{ "_id" : "30204", "city" : "BARNESVILLE", "loc" : [ -84.15147, 33.045713 ], "pop" : 9595, "state" : "GA" }
+{ "_id" : "30205", "city" : "BROOKS", "loc" : [ -84.476941, 33.298433 ], "pop" : 1662, "state" : "GA" }
+{ "_id" : "30206", "city" : "CONCORD", "loc" : [ -84.447025, 33.099836 ], "pop" : 1591, "state" : "GA" }
+{ "_id" : "30207", "city" : "CONYERS", "loc" : [ -84.019818, 33.682932 ], "pop" : 24526, "state" : "GA" }
+{ "_id" : "30208", "city" : "CONYERS", "loc" : [ -84.01268899999999, 33.607711 ], "pop" : 24236, "state" : "GA" }
+{ "_id" : "30209", "city" : "STARRSVILLE", "loc" : [ -83.89075200000001, 33.570328 ], "pop" : 35231, "state" : "GA" }
+{ "_id" : "30211", "city" : "DACULA", "loc" : [ -83.883849, 33.988234 ], "pop" : 7320, "state" : "GA" }
+{ "_id" : "30213", "city" : "FAIRBURN", "loc" : [ -84.58085699999999, 33.56482 ], "pop" : 14110, "state" : "GA" }
+{ "_id" : "30214", "city" : "WOOLSEY", "loc" : [ -84.46358600000001, 33.448054 ], "pop" : 35007, "state" : "GA" }
+{ "_id" : "30216", "city" : "FLOVILLA", "loc" : [ -83.907938, 33.250012 ], "pop" : 2238, "state" : "GA" }
+{ "_id" : "30217", "city" : "GLENN", "loc" : [ -85.105459, 33.291073 ], "pop" : 7230, "state" : "GA" }
+{ "_id" : "30218", "city" : "ALVATON", "loc" : [ -84.58057599999999, 33.149902 ], "pop" : 2327, "state" : "GA" }
+{ "_id" : "30220", "city" : "GRANTVILLE", "loc" : [ -84.83497699999999, 33.247253 ], "pop" : 1825, "state" : "GA" }
+{ "_id" : "30221", "city" : "GRAYSON", "loc" : [ -83.97984599999999, 33.898344 ], "pop" : 5528, "state" : "GA" }
+{ "_id" : "30222", "city" : "STOVALL", "loc" : [ -84.74217299999999, 33.037169 ], "pop" : 4507, "state" : "GA" }
+{ "_id" : "30223", "city" : "GRIFFIN", "loc" : [ -84.27275899999999, 33.2549 ], "pop" : 53247, "state" : "GA" }
+{ "_id" : "30228", "city" : "HAMPTON", "loc" : [ -84.29474399999999, 33.412398 ], "pop" : 10969, "state" : "GA" }
+{ "_id" : "30230", "city" : "HOGANSVILLE", "loc" : [ -84.93085600000001, 33.164382 ], "pop" : 6378, "state" : "GA" }
+{ "_id" : "30233", "city" : "JACKSON", "loc" : [ -83.978391, 33.282006 ], "pop" : 13206, "state" : "GA" }
+{ "_id" : "30234", "city" : "JENKINSBURG", "loc" : [ -84.026122, 33.318619 ], "pop" : 1242, "state" : "GA" }
+{ "_id" : "30236", "city" : "JONESBORO", "loc" : [ -84.358968, 33.524236 ], "pop" : 55409, "state" : "GA" }
+{ "_id" : "30240", "city" : "LA GRANGE", "loc" : [ -85.039511, 33.034025 ], "pop" : 43081, "state" : "GA" }
+{ "_id" : "30243", "city" : "LAWRENCEVILLE", "loc" : [ -84.014944, 34.005049 ], "pop" : 24119, "state" : "GA" }
+{ "_id" : "30244", "city" : "LAWRENCEVILLE", "loc" : [ -84.08165200000001, 33.923781 ], "pop" : 37778, "state" : "GA" }
+{ "_id" : "30245", "city" : "LAWRENCEVILLE", "loc" : [ -83.996413, 33.944293 ], "pop" : 30171, "state" : "GA" }
+{ "_id" : "30247", "city" : "LILBURN", "loc" : [ -84.119595, 33.873182 ], "pop" : 46637, "state" : "GA" }
+{ "_id" : "30248", "city" : "LOCUST GROVE", "loc" : [ -84.09824999999999, 33.344936 ], "pop" : 5812, "state" : "GA" }
+{ "_id" : "30249", "city" : "LOGANVILLE", "loc" : [ -83.903631, 33.83366 ], "pop" : 14843, "state" : "GA" }
+{ "_id" : "30251", "city" : "LUTHERSVILLE", "loc" : [ -84.757707, 33.179817 ], "pop" : 3389, "state" : "GA" }
+{ "_id" : "30253", "city" : "MC DONOUGH", "loc" : [ -84.135751, 33.46466 ], "pop" : 18550, "state" : "GA" }
+{ "_id" : "30255", "city" : "MANSFIELD", "loc" : [ -83.727638, 33.540373 ], "pop" : 1438, "state" : "GA" }
+{ "_id" : "30256", "city" : "MEANSVILLE", "loc" : [ -84.31693799999999, 33.013387 ], "pop" : 1668, "state" : "GA" }
+{ "_id" : "30257", "city" : "MILNER", "loc" : [ -84.175909, 33.141023 ], "pop" : 3789, "state" : "GA" }
+{ "_id" : "30258", "city" : "MOLENA", "loc" : [ -84.45578, 32.997845 ], "pop" : 2055, "state" : "GA" }
+{ "_id" : "30259", "city" : "MORELAND", "loc" : [ -84.75655999999999, 33.273437 ], "pop" : 2056, "state" : "GA" }
+{ "_id" : "30260", "city" : "MORROW", "loc" : [ -84.32469500000001, 33.584934 ], "pop" : 20584, "state" : "GA" }
+{ "_id" : "30262", "city" : "NEWBORN", "loc" : [ -83.668396, 33.494923 ], "pop" : 1491, "state" : "GA" }
+{ "_id" : "30263", "city" : "RAYMOND", "loc" : [ -84.816952, 33.389404 ], "pop" : 32379, "state" : "GA" }
+{ "_id" : "30265", "city" : "NEWNAN", "loc" : [ -84.712062, 33.39576 ], "pop" : 5345, "state" : "GA" }
+{ "_id" : "30267", "city" : "OXFORD", "loc" : [ -83.863517, 33.686474 ], "pop" : 10601, "state" : "GA" }
+{ "_id" : "30268", "city" : "PALMETTO", "loc" : [ -84.678999, 33.524195 ], "pop" : 5838, "state" : "GA" }
+{ "_id" : "30269", "city" : "PEACHTREE CITY", "loc" : [ -84.563478, 33.391467 ], "pop" : 18724, "state" : "GA" }
+{ "_id" : "30273", "city" : "REX", "loc" : [ -84.278228, 33.580805 ], "pop" : 7218, "state" : "GA" }
+{ "_id" : "30274", "city" : "RIVERDALE", "loc" : [ -84.40034799999999, 33.553126 ], "pop" : 23621, "state" : "GA" }
+{ "_id" : "30276", "city" : "SENOIA", "loc" : [ -84.591779, 33.284459 ], "pop" : 4653, "state" : "GA" }
+{ "_id" : "30277", "city" : "SHARPSBURG", "loc" : [ -84.654027, 33.401287 ], "pop" : 5956, "state" : "GA" }
+{ "_id" : "30278", "city" : "SNELLVILLE", "loc" : [ -84.02801100000001, 33.848607 ], "pop" : 34314, "state" : "GA" }
+{ "_id" : "30279", "city" : "SOCIAL CIRCLE", "loc" : [ -83.706149, 33.656386 ], "pop" : 4598, "state" : "GA" }
+{ "_id" : "30281", "city" : "STOCKBRIDGE", "loc" : [ -84.21648999999999, 33.563343 ], "pop" : 25401, "state" : "GA" }
+{ "_id" : "30285", "city" : "THE ROCK", "loc" : [ -84.24235899999999, 32.971734 ], "pop" : 333, "state" : "GA" }
+{ "_id" : "30286", "city" : "THOMASTON", "loc" : [ -84.33240000000001, 32.901534 ], "pop" : 22925, "state" : "GA" }
+{ "_id" : "30290", "city" : "TYRONE", "loc" : [ -84.591357, 33.471948 ], "pop" : 3555, "state" : "GA" }
+{ "_id" : "30291", "city" : "UNION CITY", "loc" : [ -84.549853, 33.583155 ], "pop" : 7411, "state" : "GA" }
+{ "_id" : "30292", "city" : "WILLIAMSON", "loc" : [ -84.379493, 33.159838 ], "pop" : 2940, "state" : "GA" }
+{ "_id" : "30293", "city" : "WOODBURY", "loc" : [ -84.59863199999999, 32.981318 ], "pop" : 3648, "state" : "GA" }
+{ "_id" : "30295", "city" : "ZEBULON", "loc" : [ -84.310827, 33.100235 ], "pop" : 2470, "state" : "GA" }
+{ "_id" : "30296", "city" : "RIVERDALE", "loc" : [ -84.43644999999999, 33.566716 ], "pop" : 18577, "state" : "GA" }
+{ "_id" : "30303", "city" : "ATLANTA", "loc" : [ -84.388846, 33.752504 ], "pop" : 1845, "state" : "GA" }
+{ "_id" : "30305", "city" : "ATLANTA", "loc" : [ -84.38514499999999, 33.831963 ], "pop" : 19122, "state" : "GA" }
+{ "_id" : "30306", "city" : "ATLANTA", "loc" : [ -84.351418, 33.786027 ], "pop" : 20081, "state" : "GA" }
+{ "_id" : "30307", "city" : "ATLANTA", "loc" : [ -84.33595699999999, 33.769138 ], "pop" : 16330, "state" : "GA" }
+{ "_id" : "30308", "city" : "ATLANTA", "loc" : [ -84.375744, 33.771839 ], "pop" : 8549, "state" : "GA" }
+{ "_id" : "30309", "city" : "ATLANTA", "loc" : [ -84.388338, 33.798407 ], "pop" : 14766, "state" : "GA" }
+{ "_id" : "30310", "city" : "ATLANTA", "loc" : [ -84.42317300000001, 33.727849 ], "pop" : 34017, "state" : "GA" }
+{ "_id" : "30311", "city" : "ATLANTA", "loc" : [ -84.470219, 33.722957 ], "pop" : 34880, "state" : "GA" }
+{ "_id" : "30312", "city" : "ATLANTA", "loc" : [ -84.378125, 33.746749 ], "pop" : 17683, "state" : "GA" }
+{ "_id" : "30313", "city" : "ATLANTA", "loc" : [ -84.39352, 33.76825 ], "pop" : 8038, "state" : "GA" }
+{ "_id" : "30314", "city" : "ATLANTA", "loc" : [ -84.425546, 33.756103 ], "pop" : 26649, "state" : "GA" }
+{ "_id" : "30315", "city" : "ATLANTA", "loc" : [ -84.380771, 33.705062 ], "pop" : 41061, "state" : "GA" }
+{ "_id" : "30316", "city" : "ATLANTA", "loc" : [ -84.333913, 33.721686 ], "pop" : 34668, "state" : "GA" }
+{ "_id" : "30317", "city" : "ATLANTA", "loc" : [ -84.31685, 33.749788 ], "pop" : 16395, "state" : "GA" }
+{ "_id" : "30318", "city" : "ATLANTA", "loc" : [ -84.445432, 33.786454 ], "pop" : 53894, "state" : "GA" }
+{ "_id" : "30319", "city" : "ATLANTA", "loc" : [ -84.33509100000001, 33.868728 ], "pop" : 32138, "state" : "GA" }
+{ "_id" : "30324", "city" : "ATLANTA", "loc" : [ -84.354867, 33.820609 ], "pop" : 15044, "state" : "GA" }
+{ "_id" : "30326", "city" : "ATLANTA", "loc" : [ -84.358232, 33.848168 ], "pop" : 125, "state" : "GA" }
+{ "_id" : "30327", "city" : "ATLANTA", "loc" : [ -84.419966, 33.862723 ], "pop" : 18467, "state" : "GA" }
+{ "_id" : "30328", "city" : "SANDY SPRINGS", "loc" : [ -84.38114299999999, 33.936295 ], "pop" : 24238, "state" : "GA" }
+{ "_id" : "30329", "city" : "ATLANTA", "loc" : [ -84.32140200000001, 33.823555 ], "pop" : 17013, "state" : "GA" }
+{ "_id" : "30330", "city" : "ATLANTA", "loc" : [ -84.434735, 33.70645 ], "pop" : 643, "state" : "GA" }
+{ "_id" : "30331", "city" : "ATLANTA", "loc" : [ -84.52046799999999, 33.72241 ], "pop" : 38185, "state" : "GA" }
+{ "_id" : "30334", "city" : "ATLANTA", "loc" : [ -84.388188, 33.74715 ], "pop" : 0, "state" : "GA" }
+{ "_id" : "30336", "city" : "ATLANTA", "loc" : [ -84.51002800000001, 33.78534 ], "pop" : 1228, "state" : "GA" }
+{ "_id" : "30337", "city" : "COLLEGE PARK", "loc" : [ -84.460849, 33.644227 ], "pop" : 18106, "state" : "GA" }
+{ "_id" : "30338", "city" : "DUNWOODY", "loc" : [ -84.316529, 33.944313 ], "pop" : 23565, "state" : "GA" }
+{ "_id" : "30339", "city" : "ATLANTA", "loc" : [ -84.462879, 33.87125 ], "pop" : 11158, "state" : "GA" }
+{ "_id" : "30340", "city" : "DORAVILLE", "loc" : [ -84.248265, 33.896377 ], "pop" : 22862, "state" : "GA" }
+{ "_id" : "30341", "city" : "CHAMBLEE", "loc" : [ -84.286969, 33.886727 ], "pop" : 26846, "state" : "GA" }
+{ "_id" : "30342", "city" : "ATLANTA", "loc" : [ -84.376091, 33.884245 ], "pop" : 19057, "state" : "GA" }
+{ "_id" : "30344", "city" : "EAST POINT", "loc" : [ -84.457292, 33.676214 ], "pop" : 33489, "state" : "GA" }
+{ "_id" : "30345", "city" : "ATLANTA", "loc" : [ -84.28696100000001, 33.851347 ], "pop" : 19825, "state" : "GA" }
+{ "_id" : "30346", "city" : "ATLANTA", "loc" : [ -84.333354, 33.926717 ], "pop" : 18, "state" : "GA" }
+{ "_id" : "30349", "city" : "ATLANTA", "loc" : [ -84.481258, 33.605331 ], "pop" : 48116, "state" : "GA" }
+{ "_id" : "30350", "city" : "ATLANTA", "loc" : [ -84.34114599999999, 33.979471 ], "pop" : 24573, "state" : "GA" }
+{ "_id" : "30354", "city" : "HAPEVILLE", "loc" : [ -84.38702499999999, 33.66546 ], "pop" : 16349, "state" : "GA" }
+{ "_id" : "30360", "city" : "ATLANTA", "loc" : [ -84.27164500000001, 33.937772 ], "pop" : 16023, "state" : "GA" }
+{ "_id" : "30401", "city" : "OAK PARK", "loc" : [ -82.338668, 32.581938 ], "pop" : 12918, "state" : "GA" }
+{ "_id" : "30410", "city" : "AILEY", "loc" : [ -82.47619, 32.214262 ], "pop" : 1004, "state" : "GA" }
+{ "_id" : "30411", "city" : "ALAMO", "loc" : [ -82.794445, 32.13298 ], "pop" : 2584, "state" : "GA" }
+{ "_id" : "30413", "city" : "BARTOW", "loc" : [ -82.470788, 32.863186 ], "pop" : 945, "state" : "GA" }
+{ "_id" : "30415", "city" : "BROOKLET", "loc" : [ -81.62800300000001, 32.294046 ], "pop" : 4850, "state" : "GA" }
+{ "_id" : "30417", "city" : "CLAXTON", "loc" : [ -81.90803200000001, 32.165009 ], "pop" : 8724, "state" : "GA" }
+{ "_id" : "30420", "city" : "COBBTOWN", "loc" : [ -82.133274, 32.264237 ], "pop" : 1482, "state" : "GA" }
+{ "_id" : "30421", "city" : "COLLINS", "loc" : [ -82.10948, 32.185228 ], "pop" : 1298, "state" : "GA" }
+{ "_id" : "30425", "city" : "GARFIELD", "loc" : [ -82.085599, 32.600776 ], "pop" : 593, "state" : "GA" }
+{ "_id" : "30426", "city" : "GIRARD", "loc" : [ -81.710581, 33.043689 ], "pop" : 1074, "state" : "GA" }
+{ "_id" : "30427", "city" : "GLENNVILLE", "loc" : [ -81.948313, 31.946708 ], "pop" : 7702, "state" : "GA" }
+{ "_id" : "30428", "city" : "GLENWOOD", "loc" : [ -82.675881, 32.157243 ], "pop" : 2319, "state" : "GA" }
+{ "_id" : "30434", "city" : "LOUISVILLE", "loc" : [ -82.383616, 33.016342 ], "pop" : 7089, "state" : "GA" }
+{ "_id" : "30436", "city" : "LYONS", "loc" : [ -82.307783, 32.171148 ], "pop" : 8675, "state" : "GA" }
+{ "_id" : "30438", "city" : "MANASSAS", "loc" : [ -82.052925, 32.096551 ], "pop" : 955, "state" : "GA" }
+{ "_id" : "30439", "city" : "METTER", "loc" : [ -82.060722, 32.401034 ], "pop" : 7744, "state" : "GA" }
+{ "_id" : "30441", "city" : "MIDVILLE", "loc" : [ -82.20418100000001, 32.863794 ], "pop" : 1533, "state" : "GA" }
+{ "_id" : "30442", "city" : "MILLEN", "loc" : [ -81.96180699999999, 32.787739 ], "pop" : 7700, "state" : "GA" }
+{ "_id" : "30445", "city" : "MOUNT VERNON", "loc" : [ -82.58672, 32.18398 ], "pop" : 3097, "state" : "GA" }
+{ "_id" : "30446", "city" : "NEWINGTON", "loc" : [ -81.532686, 32.588385 ], "pop" : 2296, "state" : "GA" }
+{ "_id" : "30450", "city" : "PORTAL", "loc" : [ -81.912257, 32.55504 ], "pop" : 3160, "state" : "GA" }
+{ "_id" : "30452", "city" : "REGISTER", "loc" : [ -81.872828, 32.338235 ], "pop" : 1655, "state" : "GA" }
+{ "_id" : "30453", "city" : "REIDSVILLE", "loc" : [ -82.147809, 32.054759 ], "pop" : 6286, "state" : "GA" }
+{ "_id" : "30454", "city" : "ROCKLEDGE", "loc" : [ -82.747939, 32.391507 ], "pop" : 160, "state" : "GA" }
+{ "_id" : "30455", "city" : "ROCKY FORD", "loc" : [ -81.741749, 32.656863 ], "pop" : 1554, "state" : "GA" }
+{ "_id" : "30456", "city" : "SARDIS", "loc" : [ -81.773039, 32.980946 ], "pop" : 1901, "state" : "GA" }
+{ "_id" : "30457", "city" : "SOPERTON", "loc" : [ -82.587098, 32.386861 ], "pop" : 5996, "state" : "GA" }
+{ "_id" : "30458", "city" : "STATESBORO", "loc" : [ -81.773956, 32.440841 ], "pop" : 33469, "state" : "GA" }
+{ "_id" : "30467", "city" : "HILTONIA", "loc" : [ -81.633394, 32.77627 ], "pop" : 9991, "state" : "GA" }
+{ "_id" : "30470", "city" : "TARRYTOWN", "loc" : [ -82.51693299999999, 32.290623 ], "pop" : 1181, "state" : "GA" }
+{ "_id" : "30471", "city" : "TWIN CITY", "loc" : [ -82.197856, 32.612926 ], "pop" : 5531, "state" : "GA" }
+{ "_id" : "30473", "city" : "UVALDA", "loc" : [ -82.50887899999999, 32.048271 ], "pop" : 1881, "state" : "GA" }
+{ "_id" : "30474", "city" : "VIDALIA", "loc" : [ -82.406724, 32.193408 ], "pop" : 15396, "state" : "GA" }
+{ "_id" : "30477", "city" : "WADLEY", "loc" : [ -82.40245899999999, 32.874742 ], "pop" : 3376, "state" : "GA" }
+{ "_id" : "30501", "city" : "GAINESVILLE", "loc" : [ -83.825596, 34.307269 ], "pop" : 22334, "state" : "GA" }
+{ "_id" : "30504", "city" : "GAINESVILLE", "loc" : [ -83.879311, 34.272281 ], "pop" : 10061, "state" : "GA" }
+{ "_id" : "30506", "city" : "GAINESVILLE", "loc" : [ -83.888211, 34.356227 ], "pop" : 22232, "state" : "GA" }
+{ "_id" : "30507", "city" : "GAINESVILLE", "loc" : [ -83.771625, 34.25915 ], "pop" : 13327, "state" : "GA" }
+{ "_id" : "30510", "city" : "ALTO", "loc" : [ -83.601996, 34.459079 ], "pop" : 4701, "state" : "GA" }
+{ "_id" : "30511", "city" : "BALDWIN", "loc" : [ -83.529781, 34.456411 ], "pop" : 3969, "state" : "GA" }
+{ "_id" : "30512", "city" : "BLAIRSVILLE", "loc" : [ -83.99202699999999, 34.876253 ], "pop" : 11360, "state" : "GA" }
+{ "_id" : "30513", "city" : "BLUE RIDGE", "loc" : [ -84.328087, 34.855523 ], "pop" : 4844, "state" : "GA" }
+{ "_id" : "30516", "city" : "BOWERSVILLE", "loc" : [ -83.04836400000001, 34.399592 ], "pop" : 2082, "state" : "GA" }
+{ "_id" : "30517", "city" : "BRASELTON", "loc" : [ -83.78116199999999, 34.138941 ], "pop" : 3142, "state" : "GA" }
+{ "_id" : "30518", "city" : "BUFORD", "loc" : [ -83.996459, 34.112373 ], "pop" : 24810, "state" : "GA" }
+{ "_id" : "30520", "city" : "CANON", "loc" : [ -83.126693, 34.347766 ], "pop" : 1393, "state" : "GA" }
+{ "_id" : "30521", "city" : "CARNESVILLE", "loc" : [ -83.27920899999999, 34.394723 ], "pop" : 4135, "state" : "GA" }
+{ "_id" : "30522", "city" : "CHERRYLOG", "loc" : [ -84.443136, 34.773711 ], "pop" : 2150, "state" : "GA" }
+{ "_id" : "30523", "city" : "CLARKESVILLE", "loc" : [ -83.524304, 34.644993 ], "pop" : 8931, "state" : "GA" }
+{ "_id" : "30525", "city" : "CLAYTON", "loc" : [ -83.40655, 34.882569 ], "pop" : 6700, "state" : "GA" }
+{ "_id" : "30527", "city" : "CLERMONT", "loc" : [ -83.78531099999999, 34.476091 ], "pop" : 2336, "state" : "GA" }
+{ "_id" : "30528", "city" : "CLEVELAND", "loc" : [ -83.749985, 34.583949 ], "pop" : 11036, "state" : "GA" }
+{ "_id" : "30529", "city" : "COMMERCE", "loc" : [ -83.44801099999999, 34.213413 ], "pop" : 8792, "state" : "GA" }
+{ "_id" : "30531", "city" : "CORNELIA", "loc" : [ -83.54527, 34.520882 ], "pop" : 7597, "state" : "GA" }
+{ "_id" : "30533", "city" : "DAHLONEGA", "loc" : [ -83.979838, 34.529949 ], "pop" : 15003, "state" : "GA" }
+{ "_id" : "30534", "city" : "JUNO", "loc" : [ -84.10370500000001, 34.394331 ], "pop" : 10196, "state" : "GA" }
+{ "_id" : "30535", "city" : "DEMOREST", "loc" : [ -83.569625, 34.575564 ], "pop" : 3521, "state" : "GA" }
+{ "_id" : "30537", "city" : "SKY VALLEY", "loc" : [ -83.38011299999999, 34.979659 ], "pop" : 328, "state" : "GA" }
+{ "_id" : "30538", "city" : "EASTANOLLEE", "loc" : [ -83.258685, 34.50366 ], "pop" : 1478, "state" : "GA" }
+{ "_id" : "30539", "city" : "EAST ELLIJAY", "loc" : [ -84.473062, 34.682636 ], "pop" : 314, "state" : "GA" }
+{ "_id" : "30540", "city" : "ELLIJAY", "loc" : [ -84.48122600000001, 34.677514 ], "pop" : 9672, "state" : "GA" }
+{ "_id" : "30541", "city" : "EPWORTH", "loc" : [ -84.441593, 34.944249 ], "pop" : 1523, "state" : "GA" }
+{ "_id" : "30542", "city" : "FLOWERY BRANCH", "loc" : [ -83.902407, 34.181893 ], "pop" : 9361, "state" : "GA" }
+{ "_id" : "30543", "city" : "GILLSVILLE", "loc" : [ -83.675681, 34.300148 ], "pop" : 1585, "state" : "GA" }
+{ "_id" : "30545", "city" : "HELEN", "loc" : [ -83.739936, 34.686601 ], "pop" : 469, "state" : "GA" }
+{ "_id" : "30546", "city" : "HIAWASSEE", "loc" : [ -83.7478, 34.937667 ], "pop" : 5067, "state" : "GA" }
+{ "_id" : "30547", "city" : "HOMER", "loc" : [ -83.497432, 34.356312 ], "pop" : 2949, "state" : "GA" }
+{ "_id" : "30548", "city" : "HOSCHTON", "loc" : [ -83.780253, 34.086578 ], "pop" : 3444, "state" : "GA" }
+{ "_id" : "30549", "city" : "JEFFERSON", "loc" : [ -83.570813, 34.106197 ], "pop" : 8795, "state" : "GA" }
+{ "_id" : "30552", "city" : "LAKEMONT", "loc" : [ -83.403763, 34.761697 ], "pop" : 338, "state" : "GA" }
+{ "_id" : "30553", "city" : "LAVONIA", "loc" : [ -83.11299200000001, 34.452758 ], "pop" : 5797, "state" : "GA" }
+{ "_id" : "30554", "city" : "LULA", "loc" : [ -83.69445899999999, 34.398513 ], "pop" : 3365, "state" : "GA" }
+{ "_id" : "30555", "city" : "MC CAYSVILLE", "loc" : [ -84.36829400000001, 34.952212 ], "pop" : 4720, "state" : "GA" }
+{ "_id" : "30557", "city" : "MARTIN", "loc" : [ -83.168553, 34.515482 ], "pop" : 1601, "state" : "GA" }
+{ "_id" : "30558", "city" : "MAYSVILLE", "loc" : [ -83.584019, 34.273627 ], "pop" : 4456, "state" : "GA" }
+{ "_id" : "30559", "city" : "MINERAL BLUFF", "loc" : [ -84.25406599999999, 34.934112 ], "pop" : 2180, "state" : "GA" }
+{ "_id" : "30560", "city" : "MORGANTON", "loc" : [ -84.211479, 34.871382 ], "pop" : 2558, "state" : "GA" }
+{ "_id" : "30563", "city" : "MOUNT AIRY", "loc" : [ -83.471272, 34.567825 ], "pop" : 2813, "state" : "GA" }
+{ "_id" : "30564", "city" : "MURRAYVILLE", "loc" : [ -83.894919, 34.434167 ], "pop" : 2126, "state" : "GA" }
+{ "_id" : "30565", "city" : "NICHOLSON", "loc" : [ -83.421031, 34.097016 ], "pop" : 3352, "state" : "GA" }
+{ "_id" : "30566", "city" : "OAKWOOD", "loc" : [ -83.894013, 34.237196 ], "pop" : 6584, "state" : "GA" }
+{ "_id" : "30567", "city" : "PENDERGRASS", "loc" : [ -83.66335599999999, 34.179634 ], "pop" : 1956, "state" : "GA" }
+{ "_id" : "30568", "city" : "RABUN GAP", "loc" : [ -83.39012200000001, 34.957552 ], "pop" : 1828, "state" : "GA" }
+{ "_id" : "30571", "city" : "SAUTEE NACOOCHEE", "loc" : [ -83.693116, 34.716245 ], "pop" : 1504, "state" : "GA" }
+{ "_id" : "30572", "city" : "SUCHES", "loc" : [ -84.049582, 34.72529 ], "pop" : 800, "state" : "GA" }
+{ "_id" : "30575", "city" : "TALMO", "loc" : [ -83.71872, 34.19506 ], "pop" : 1153, "state" : "GA" }
+{ "_id" : "30576", "city" : "TIGER", "loc" : [ -83.433317, 34.81741 ], "pop" : 2454, "state" : "GA" }
+{ "_id" : "30577", "city" : "TOCCOA", "loc" : [ -83.31144, 34.566474 ], "pop" : 20324, "state" : "GA" }
+{ "_id" : "30582", "city" : "YOUNG HARRIS", "loc" : [ -83.86882, 34.958791 ], "pop" : 1687, "state" : "GA" }
+{ "_id" : "30601", "city" : "ATHENS", "loc" : [ -83.363174, 33.976097 ], "pop" : 15661, "state" : "GA" }
+{ "_id" : "30605", "city" : "ATHENS", "loc" : [ -83.352508, 33.932097 ], "pop" : 33299, "state" : "GA" }
+{ "_id" : "30606", "city" : "ATHENS", "loc" : [ -83.418019, 33.946085 ], "pop" : 29839, "state" : "GA" }
+{ "_id" : "30607", "city" : "ATHENS", "loc" : [ -83.427761, 34.006978 ], "pop" : 7056, "state" : "GA" }
+{ "_id" : "30619", "city" : "ARNOLDSVILLE", "loc" : [ -83.234137, 33.880338 ], "pop" : 648, "state" : "GA" }
+{ "_id" : "30620", "city" : "BETHLEHEM", "loc" : [ -83.728227, 33.926116 ], "pop" : 2181, "state" : "GA" }
+{ "_id" : "30621", "city" : "BISHOP", "loc" : [ -83.477655, 33.808091 ], "pop" : 3620, "state" : "GA" }
+{ "_id" : "30622", "city" : "BOGART", "loc" : [ -83.50546, 33.934038 ], "pop" : 7245, "state" : "GA" }
+{ "_id" : "30624", "city" : "BOWMAN", "loc" : [ -83.028437, 34.19193 ], "pop" : 2315, "state" : "GA" }
+{ "_id" : "30625", "city" : "BUCKHEAD", "loc" : [ -83.343484, 33.536842 ], "pop" : 1222, "state" : "GA" }
+{ "_id" : "30627", "city" : "CARLTON", "loc" : [ -83.003827, 33.985217 ], "pop" : 2046, "state" : "GA" }
+{ "_id" : "30628", "city" : "COLBERT", "loc" : [ -83.21906, 34.038246 ], "pop" : 5943, "state" : "GA" }
+{ "_id" : "30629", "city" : "COMER", "loc" : [ -83.121978, 34.088776 ], "pop" : 3134, "state" : "GA" }
+{ "_id" : "30630", "city" : "CRAWFORD", "loc" : [ -83.189319, 33.909533 ], "pop" : 2883, "state" : "GA" }
+{ "_id" : "30631", "city" : "CRAWFORDVILLE", "loc" : [ -82.88723400000001, 33.570801 ], "pop" : 1915, "state" : "GA" }
+{ "_id" : "30633", "city" : "DANIELSVILLE", "loc" : [ -83.275841, 34.170799 ], "pop" : 7119, "state" : "GA" }
+{ "_id" : "30634", "city" : "DEWY ROSE", "loc" : [ -82.940894, 34.172052 ], "pop" : 1138, "state" : "GA" }
+{ "_id" : "30635", "city" : "ELBERTON", "loc" : [ -82.844765, 34.108202 ], "pop" : 15503, "state" : "GA" }
+{ "_id" : "30641", "city" : "GOOD HOPE", "loc" : [ -83.59495200000001, 33.761346 ], "pop" : 1031, "state" : "GA" }
+{ "_id" : "30642", "city" : "GREENSBORO", "loc" : [ -83.170192, 33.563682 ], "pop" : 6206, "state" : "GA" }
+{ "_id" : "30643", "city" : "HARTWELL", "loc" : [ -82.929576, 34.357124 ], "pop" : 14886, "state" : "GA" }
+{ "_id" : "30646", "city" : "HULL", "loc" : [ -83.311029, 34.04781 ], "pop" : 5142, "state" : "GA" }
+{ "_id" : "30648", "city" : "LEXINGTON", "loc" : [ -83.085809, 33.879913 ], "pop" : 1712, "state" : "GA" }
+{ "_id" : "30650", "city" : "MADISON", "loc" : [ -83.461781, 33.594681 ], "pop" : 8855, "state" : "GA" }
+{ "_id" : "30655", "city" : "MONROE", "loc" : [ -83.707221, 33.808141 ], "pop" : 18405, "state" : "GA" }
+{ "_id" : "30660", "city" : "PHILOMATH", "loc" : [ -82.909975, 33.783593 ], "pop" : 1137, "state" : "GA" }
+{ "_id" : "30662", "city" : "ROYSTON", "loc" : [ -83.140614, 34.277793 ], "pop" : 8836, "state" : "GA" }
+{ "_id" : "30663", "city" : "RUTLEDGE", "loc" : [ -83.60230199999999, 33.616316 ], "pop" : 2161, "state" : "GA" }
+{ "_id" : "30666", "city" : "STATHAM", "loc" : [ -83.58929999999999, 33.960233 ], "pop" : 3758, "state" : "GA" }
+{ "_id" : "30667", "city" : "STEPHENS", "loc" : [ -83.11590200000001, 33.771471 ], "pop" : 1069, "state" : "GA" }
+{ "_id" : "30668", "city" : "DANBURG", "loc" : [ -82.69555800000001, 33.883294 ], "pop" : 2293, "state" : "GA" }
+{ "_id" : "30669", "city" : "UNION POINT", "loc" : [ -83.087913, 33.634544 ], "pop" : 3561, "state" : "GA" }
+{ "_id" : "30673", "city" : "WASHINGTON", "loc" : [ -82.742912, 33.726541 ], "pop" : 7699, "state" : "GA" }
+{ "_id" : "30677", "city" : "WATKINSVILLE", "loc" : [ -83.40804300000001, 33.854247 ], "pop" : 7723, "state" : "GA" }
+{ "_id" : "30678", "city" : "WHITE PLAINS", "loc" : [ -83.090845, 33.484338 ], "pop" : 1596, "state" : "GA" }
+{ "_id" : "30680", "city" : "WINDER", "loc" : [ -83.711473, 33.998544 ], "pop" : 16981, "state" : "GA" }
+{ "_id" : "30683", "city" : "WINTERVILLE", "loc" : [ -83.290645, 33.954253 ], "pop" : 3056, "state" : "GA" }
+{ "_id" : "30701", "city" : "CALHOUN", "loc" : [ -84.934545, 34.496456 ], "pop" : 22017, "state" : "GA" }
+{ "_id" : "30705", "city" : "CHATSWORTH", "loc" : [ -84.794293, 34.758929 ], "pop" : 22271, "state" : "GA" }
+{ "_id" : "30707", "city" : "CHICKAMAUGA", "loc" : [ -85.322136, 34.857963 ], "pop" : 13545, "state" : "GA" }
+{ "_id" : "30708", "city" : "CISCO", "loc" : [ -84.717382, 34.847405 ], "pop" : 978, "state" : "GA" }
+{ "_id" : "30710", "city" : "COHUTTA", "loc" : [ -84.945801, 34.932635 ], "pop" : 5052, "state" : "GA" }
+{ "_id" : "30711", "city" : "CRANDALL", "loc" : [ -84.764533, 34.941225 ], "pop" : 2901, "state" : "GA" }
+{ "_id" : "30720", "city" : "DALTON", "loc" : [ -84.987477, 34.76352 ], "pop" : 20680, "state" : "GA" }
+{ "_id" : "30721", "city" : "DALTON", "loc" : [ -84.933871, 34.77922 ], "pop" : 36051, "state" : "GA" }
+{ "_id" : "30725", "city" : "FLINTSTONE", "loc" : [ -85.35244299999999, 34.925162 ], "pop" : 2775, "state" : "GA" }
+{ "_id" : "30728", "city" : "LA FAYETTE", "loc" : [ -85.260212, 34.692008 ], "pop" : 16287, "state" : "GA" }
+{ "_id" : "30730", "city" : "LYERLY", "loc" : [ -85.403826, 34.402958 ], "pop" : 2585, "state" : "GA" }
+{ "_id" : "30731", "city" : "CLOUDLAND", "loc" : [ -85.459723, 34.570909 ], "pop" : 3222, "state" : "GA" }
+{ "_id" : "30733", "city" : "PLAINVILLE", "loc" : [ -85.031204, 34.41447 ], "pop" : 1589, "state" : "GA" }
+{ "_id" : "30734", "city" : "RANGER", "loc" : [ -84.727018, 34.540361 ], "pop" : 2015, "state" : "GA" }
+{ "_id" : "30735", "city" : "HILL CITY", "loc" : [ -84.916251, 34.591996 ], "pop" : 2926, "state" : "GA" }
+{ "_id" : "30736", "city" : "RINGGOLD", "loc" : [ -85.15490800000001, 34.92052 ], "pop" : 25360, "state" : "GA" }
+{ "_id" : "30738", "city" : "RISING FAWN", "loc" : [ -85.47107800000001, 34.853491 ], "pop" : 4036, "state" : "GA" }
+{ "_id" : "30739", "city" : "ROCK SPRING", "loc" : [ -85.24148099999999, 34.806534 ], "pop" : 4181, "state" : "GA" }
+{ "_id" : "30740", "city" : "ROCKY FACE", "loc" : [ -85.05614300000001, 34.774456 ], "pop" : 6029, "state" : "GA" }
+{ "_id" : "30741", "city" : "ROSSVILLE", "loc" : [ -85.296785, 34.953481 ], "pop" : 18436, "state" : "GA" }
+{ "_id" : "30742", "city" : "FORT OGLETHORPE", "loc" : [ -85.242812, 34.964082 ], "pop" : 14807, "state" : "GA" }
+{ "_id" : "30746", "city" : "SUGAR VALLEY", "loc" : [ -85.026048, 34.551929 ], "pop" : 1340, "state" : "GA" }
+{ "_id" : "30747", "city" : "SUMMERVILLE", "loc" : [ -85.336224, 34.485899 ], "pop" : 10748, "state" : "GA" }
+{ "_id" : "30750", "city" : "LOOKOUT MOUNTAIN", "loc" : [ -85.379384, 34.933512 ], "pop" : 2818, "state" : "GA" }
+{ "_id" : "30752", "city" : "TRENTON", "loc" : [ -85.517118, 34.901681 ], "pop" : 7930, "state" : "GA" }
+{ "_id" : "30753", "city" : "TRION", "loc" : [ -85.311156, 34.54679 ], "pop" : 5963, "state" : "GA" }
+{ "_id" : "30755", "city" : "TUNNEL HILL", "loc" : [ -85.046815, 34.854129 ], "pop" : 6947, "state" : "GA" }
+{ "_id" : "30757", "city" : "WILDWOOD", "loc" : [ -85.43045600000001, 34.977911 ], "pop" : 586, "state" : "GA" }
+{ "_id" : "30802", "city" : "APPLING", "loc" : [ -82.285631, 33.627088 ], "pop" : 2255, "state" : "GA" }
+{ "_id" : "30803", "city" : "AVERA", "loc" : [ -82.514965, 33.140997 ], "pop" : 836, "state" : "GA" }
+{ "_id" : "30805", "city" : "BLYTHE", "loc" : [ -82.20304400000001, 33.294088 ], "pop" : 297, "state" : "GA" }
+{ "_id" : "30808", "city" : "DEARING", "loc" : [ -82.395512, 33.40702 ], "pop" : 4632, "state" : "GA" }
+{ "_id" : "30809", "city" : "EVANS", "loc" : [ -82.139775, 33.541194 ], "pop" : 12788, "state" : "GA" }
+{ "_id" : "30810", "city" : "GIBSON", "loc" : [ -82.57659099999999, 33.247097 ], "pop" : 1649, "state" : "GA" }
+{ "_id" : "30813", "city" : "GROVETOWN", "loc" : [ -82.240937, 33.476622 ], "pop" : 13283, "state" : "GA" }
+{ "_id" : "30814", "city" : "HARLEM", "loc" : [ -82.309659, 33.417007 ], "pop" : 4318, "state" : "GA" }
+{ "_id" : "30815", "city" : "HEPHZIBAH", "loc" : [ -82.088689, 33.343328 ], "pop" : 27838, "state" : "GA" }
+{ "_id" : "30816", "city" : "KEYSVILLE", "loc" : [ -82.183368, 33.17191 ], "pop" : 135, "state" : "GA" }
+{ "_id" : "30817", "city" : "LINCOLNTON", "loc" : [ -82.44348100000001, 33.777335 ], "pop" : 7028, "state" : "GA" }
+{ "_id" : "30818", "city" : "MATTHEWS", "loc" : [ -82.28674700000001, 33.217582 ], "pop" : 607, "state" : "GA" }
+{ "_id" : "30820", "city" : "MITCHELL", "loc" : [ -82.68165399999999, 33.20515 ], "pop" : 708, "state" : "GA" }
+{ "_id" : "30821", "city" : "NORWOOD", "loc" : [ -82.735575, 33.478921 ], "pop" : 882, "state" : "GA" }
+{ "_id" : "30822", "city" : "PERKINS", "loc" : [ -81.869573, 32.905747 ], "pop" : 549, "state" : "GA" }
+{ "_id" : "30823", "city" : "STAPLETON", "loc" : [ -82.459704, 33.189423 ], "pop" : 884, "state" : "GA" }
+{ "_id" : "30824", "city" : "THOMSON", "loc" : [ -82.494204, 33.477363 ], "pop" : 15487, "state" : "GA" }
+{ "_id" : "30828", "city" : "WARRENTON", "loc" : [ -82.63567999999999, 33.40914 ], "pop" : 4091, "state" : "GA" }
+{ "_id" : "30830", "city" : "WAYNESBORO", "loc" : [ -81.990797, 33.101254 ], "pop" : 12213, "state" : "GA" }
+{ "_id" : "30833", "city" : "WRENS", "loc" : [ -82.380962, 33.210397 ], "pop" : 4782, "state" : "GA" }
+{ "_id" : "30901", "city" : "AUGUSTA", "loc" : [ -81.972959, 33.460084 ], "pop" : 24496, "state" : "GA" }
+{ "_id" : "30904", "city" : "AUGUSTA", "loc" : [ -82.01307799999999, 33.47374 ], "pop" : 30408, "state" : "GA" }
+{ "_id" : "30905", "city" : "FORT GORDON", "loc" : [ -82.139179, 33.419032 ], "pop" : 9260, "state" : "GA" }
+{ "_id" : "30906", "city" : "PEACH ORCHARD", "loc" : [ -82.038358, 33.402024 ], "pop" : 58646, "state" : "GA" }
+{ "_id" : "30907", "city" : "MARTINEZ", "loc" : [ -82.09950499999999, 33.511692 ], "pop" : 42573, "state" : "GA" }
+{ "_id" : "30909", "city" : "FOREST HILLS", "loc" : [ -82.060439, 33.480932 ], "pop" : 32202, "state" : "GA" }
+{ "_id" : "31001", "city" : "ABBEVILLE", "loc" : [ -83.306845, 31.96484 ], "pop" : 1991, "state" : "GA" }
+{ "_id" : "31002", "city" : "ADRIAN", "loc" : [ -82.569508, 32.563505 ], "pop" : 2880, "state" : "GA" }
+{ "_id" : "31003", "city" : "ALLENTOWN", "loc" : [ -83.189796, 32.653829 ], "pop" : 1099, "state" : "GA" }
+{ "_id" : "31005", "city" : "BONAIRE", "loc" : [ -83.604736, 32.546037 ], "pop" : 5095, "state" : "GA" }
+{ "_id" : "31006", "city" : "BUTLER", "loc" : [ -84.234308, 32.572597 ], "pop" : 4731, "state" : "GA" }
+{ "_id" : "31007", "city" : "BYROMVILLE", "loc" : [ -83.899128, 32.185192 ], "pop" : 1672, "state" : "GA" }
+{ "_id" : "31008", "city" : "POWERSVILLE", "loc" : [ -83.762244, 32.647384 ], "pop" : 8205, "state" : "GA" }
+{ "_id" : "31009", "city" : "CADWELL", "loc" : [ -83.02676700000001, 32.317395 ], "pop" : 1501, "state" : "GA" }
+{ "_id" : "31011", "city" : "CHAUNCEY", "loc" : [ -83.050804, 32.083532 ], "pop" : 1954, "state" : "GA" }
+{ "_id" : "31012", "city" : "CHESTER", "loc" : [ -83.174029, 32.398152 ], "pop" : 1517, "state" : "GA" }
+{ "_id" : "31014", "city" : "COCHRAN", "loc" : [ -83.322886, 32.398066 ], "pop" : 11373, "state" : "GA" }
+{ "_id" : "31015", "city" : "CORDELE", "loc" : [ -83.783507, 31.956625 ], "pop" : 18662, "state" : "GA" }
+{ "_id" : "31016", "city" : "CULLODEN", "loc" : [ -84.04562799999999, 32.830078 ], "pop" : 2501, "state" : "GA" }
+{ "_id" : "31017", "city" : "DANVILLE", "loc" : [ -83.303298, 32.593017 ], "pop" : 2221, "state" : "GA" }
+{ "_id" : "31018", "city" : "DAVISBORO", "loc" : [ -82.622738, 32.944296 ], "pop" : 2032, "state" : "GA" }
+{ "_id" : "31019", "city" : "DEXTER", "loc" : [ -83.05277100000001, 32.435639 ], "pop" : 1705, "state" : "GA" }
+{ "_id" : "31020", "city" : "DRY BRANCH", "loc" : [ -83.495105, 32.70499 ], "pop" : 3702, "state" : "GA" }
+{ "_id" : "31021", "city" : "EAST DUBLIN", "loc" : [ -82.90367999999999, 32.547794 ], "pop" : 32030, "state" : "GA" }
+{ "_id" : "31022", "city" : "DUDLEY", "loc" : [ -83.089918, 32.525879 ], "pop" : 966, "state" : "GA" }
+{ "_id" : "31023", "city" : "EASTMAN", "loc" : [ -83.185959, 32.208425 ], "pop" : 11744, "state" : "GA" }
+{ "_id" : "31024", "city" : "EATONTON", "loc" : [ -83.36277, 33.312723 ], "pop" : 13086, "state" : "GA" }
+{ "_id" : "31025", "city" : "ELKO", "loc" : [ -83.730388, 32.333648 ], "pop" : 934, "state" : "GA" }
+{ "_id" : "31028", "city" : "CENTERVILLE", "loc" : [ -83.676773, 32.634375 ], "pop" : 2764, "state" : "GA" }
+{ "_id" : "31029", "city" : "FORSYTH", "loc" : [ -83.93620900000001, 33.050764 ], "pop" : 8959, "state" : "GA" }
+{ "_id" : "31030", "city" : "FORT VALLEY", "loc" : [ -83.888727, 32.54956 ], "pop" : 14027, "state" : "GA" }
+{ "_id" : "31031", "city" : "STEVENS POTTERY", "loc" : [ -83.32041599999999, 32.909212 ], "pop" : 5415, "state" : "GA" }
+{ "_id" : "31032", "city" : "GRAY", "loc" : [ -83.539951, 33.017177 ], "pop" : 8781, "state" : "GA" }
+{ "_id" : "31033", "city" : "HADDOCK", "loc" : [ -83.431219, 33.051888 ], "pop" : 1193, "state" : "GA" }
+{ "_id" : "31035", "city" : "HARRISON", "loc" : [ -82.71593, 32.842007 ], "pop" : 1737, "state" : "GA" }
+{ "_id" : "31036", "city" : "HAWKINSVILLE", "loc" : [ -83.49476300000001, 32.277834 ], "pop" : 9154, "state" : "GA" }
+{ "_id" : "31037", "city" : "HELENA", "loc" : [ -82.91782000000001, 32.078093 ], "pop" : 1526, "state" : "GA" }
+{ "_id" : "31038", "city" : "ROUND OAK", "loc" : [ -83.68709200000001, 33.179994 ], "pop" : 811, "state" : "GA" }
+{ "_id" : "31041", "city" : "IDEAL", "loc" : [ -84.148149, 32.393022 ], "pop" : 1924, "state" : "GA" }
+{ "_id" : "31042", "city" : "IRWINTON", "loc" : [ -83.173963, 32.808849 ], "pop" : 447, "state" : "GA" }
+{ "_id" : "31044", "city" : "JEFFERSONVILLE", "loc" : [ -83.385896, 32.741096 ], "pop" : 3953, "state" : "GA" }
+{ "_id" : "31045", "city" : "JEWELL", "loc" : [ -82.732803, 33.328754 ], "pop" : 1105, "state" : "GA" }
+{ "_id" : "31046", "city" : "JULIETTE", "loc" : [ -83.82352899999999, 33.119412 ], "pop" : 687, "state" : "GA" }
+{ "_id" : "31047", "city" : "KATHLEEN", "loc" : [ -83.61284000000001, 32.467218 ], "pop" : 563, "state" : "GA" }
+{ "_id" : "31049", "city" : "KITE", "loc" : [ -82.527361, 32.707833 ], "pop" : 1196, "state" : "GA" }
+{ "_id" : "31050", "city" : "KNOXVILLE", "loc" : [ -83.943011, 32.64724 ], "pop" : 2134, "state" : "GA" }
+{ "_id" : "31052", "city" : "LIZELLA", "loc" : [ -83.82500899999999, 32.777316 ], "pop" : 6992, "state" : "GA" }
+{ "_id" : "31054", "city" : "MC INTYRE", "loc" : [ -83.203953, 32.84679 ], "pop" : 3295, "state" : "GA" }
+{ "_id" : "31055", "city" : "MC RAE", "loc" : [ -82.887665, 32.043529 ], "pop" : 4906, "state" : "GA" }
+{ "_id" : "31057", "city" : "MARSHALLVILLE", "loc" : [ -83.943478, 32.452003 ], "pop" : 2008, "state" : "GA" }
+{ "_id" : "31058", "city" : "MAUK", "loc" : [ -84.399906, 32.509016 ], "pop" : 319, "state" : "GA" }
+{ "_id" : "31060", "city" : "MILAN", "loc" : [ -83.05884500000001, 31.961797 ], "pop" : 1627, "state" : "GA" }
+{ "_id" : "31061", "city" : "MILLEDGEVILLE", "loc" : [ -83.237943, 33.079958 ], "pop" : 39173, "state" : "GA" }
+{ "_id" : "31063", "city" : "MONTEZUMA", "loc" : [ -84.004139, 32.302615 ], "pop" : 6160, "state" : "GA" }
+{ "_id" : "31064", "city" : "MONTICELLO", "loc" : [ -83.714049, 33.311797 ], "pop" : 5328, "state" : "GA" }
+{ "_id" : "31065", "city" : "MONTROSE", "loc" : [ -83.16011899999999, 32.561867 ], "pop" : 587, "state" : "GA" }
+{ "_id" : "31066", "city" : "MUSELLA", "loc" : [ -84.045591, 32.820228 ], "pop" : 121, "state" : "GA" }
+{ "_id" : "31068", "city" : "OGLETHORPE", "loc" : [ -84.08299100000001, 32.284186 ], "pop" : 2951, "state" : "GA" }
+{ "_id" : "31069", "city" : "PERRY", "loc" : [ -83.728258, 32.46051 ], "pop" : 13945, "state" : "GA" }
+{ "_id" : "31070", "city" : "PINEHURST", "loc" : [ -83.72085300000001, 32.196692 ], "pop" : 917, "state" : "GA" }
+{ "_id" : "31071", "city" : "PINEVIEW", "loc" : [ -83.515835, 32.090728 ], "pop" : 1154, "state" : "GA" }
+{ "_id" : "31072", "city" : "PITTS", "loc" : [ -83.55788, 31.942533 ], "pop" : 1278, "state" : "GA" }
+{ "_id" : "31075", "city" : "RENTZ", "loc" : [ -82.91398700000001, 32.363834 ], "pop" : 3037, "state" : "GA" }
+{ "_id" : "31076", "city" : "REYNOLDS", "loc" : [ -84.101134, 32.55411 ], "pop" : 2455, "state" : "GA" }
+{ "_id" : "31077", "city" : "RHINE", "loc" : [ -83.19831000000001, 32.011303 ], "pop" : 1449, "state" : "GA" }
+{ "_id" : "31078", "city" : "ROBERTA", "loc" : [ -84.045114, 32.722152 ], "pop" : 2803, "state" : "GA" }
+{ "_id" : "31079", "city" : "ROCHELLE", "loc" : [ -83.44497800000001, 31.949119 ], "pop" : 2585, "state" : "GA" }
+{ "_id" : "31081", "city" : "RUPERT", "loc" : [ -84.273753, 32.432524 ], "pop" : 208, "state" : "GA" }
+{ "_id" : "31082", "city" : "DEEPSTEP", "loc" : [ -82.816934, 32.986972 ], "pop" : 10459, "state" : "GA" }
+{ "_id" : "31085", "city" : "SHADY DALE", "loc" : [ -83.704031, 33.401353 ], "pop" : 1606, "state" : "GA" }
+{ "_id" : "31087", "city" : "DEVEREUX", "loc" : [ -82.98594799999999, 33.265516 ], "pop" : 8908, "state" : "GA" }
+{ "_id" : "31088", "city" : "WARNER ROBINS", "loc" : [ -83.641578, 32.593365 ], "pop" : 34526, "state" : "GA" }
+{ "_id" : "31089", "city" : "TENNILLE", "loc" : [ -82.840024, 32.9063 ], "pop" : 3696, "state" : "GA" }
+{ "_id" : "31090", "city" : "TOOMSBORO", "loc" : [ -83.08442700000001, 32.821895 ], "pop" : 1129, "state" : "GA" }
+{ "_id" : "31091", "city" : "UNADILLA", "loc" : [ -83.74467, 32.255766 ], "pop" : 2623, "state" : "GA" }
+{ "_id" : "31092", "city" : "VIENNA", "loc" : [ -83.792198, 32.091291 ], "pop" : 4689, "state" : "GA" }
+{ "_id" : "31093", "city" : "WARNER ROBINS", "loc" : [ -83.639466, 32.636839 ], "pop" : 27107, "state" : "GA" }
+{ "_id" : "31094", "city" : "WARTHEN", "loc" : [ -82.803899, 33.125455 ], "pop" : 1188, "state" : "GA" }
+{ "_id" : "31096", "city" : "WRIGHTSVILLE", "loc" : [ -82.726206, 32.721866 ], "pop" : 5755, "state" : "GA" }
+{ "_id" : "31097", "city" : "YATESVILLE", "loc" : [ -84.15925300000001, 32.915592 ], "pop" : 1188, "state" : "GA" }
+{ "_id" : "31098", "city" : "ROBINS A F B", "loc" : [ -83.58775, 32.60958 ], "pop" : 3228, "state" : "GA" }
+{ "_id" : "31201", "city" : "HUBER", "loc" : [ -83.598686, 32.84386 ], "pop" : 31882, "state" : "GA" }
+{ "_id" : "31204", "city" : "MACON", "loc" : [ -83.67663400000001, 32.842393 ], "pop" : 38186, "state" : "GA" }
+{ "_id" : "31206", "city" : "WILSON AIRPORT", "loc" : [ -83.682303, 32.780758 ], "pop" : 42528, "state" : "GA" }
+{ "_id" : "31210", "city" : "MACON", "loc" : [ -83.745537, 32.892565 ], "pop" : 31255, "state" : "GA" }
+{ "_id" : "31211", "city" : "MACON", "loc" : [ -83.602062, 32.886905 ], "pop" : 16668, "state" : "GA" }
+{ "_id" : "31301", "city" : "ALLENHURST", "loc" : [ -81.618577, 31.774059 ], "pop" : 3075, "state" : "GA" }
+{ "_id" : "31302", "city" : "BLOOMINGDALE", "loc" : [ -81.308465, 32.117654 ], "pop" : 3297, "state" : "GA" }
+{ "_id" : "31303", "city" : "CLYO", "loc" : [ -81.30857, 32.512646 ], "pop" : 400, "state" : "GA" }
+{ "_id" : "31304", "city" : "CRESCENT", "loc" : [ -81.389219, 31.49675 ], "pop" : 2362, "state" : "GA" }
+{ "_id" : "31305", "city" : "DARIEN", "loc" : [ -81.431175, 31.382574 ], "pop" : 3067, "state" : "GA" }
+{ "_id" : "31308", "city" : "ELLABELL", "loc" : [ -81.498302, 32.127304 ], "pop" : 1309, "state" : "GA" }
+{ "_id" : "31309", "city" : "FLEMING", "loc" : [ -81.423165, 31.864477 ], "pop" : 548, "state" : "GA" }
+{ "_id" : "31312", "city" : "GUYTON", "loc" : [ -81.389593, 32.31399 ], "pop" : 4025, "state" : "GA" }
+{ "_id" : "31313", "city" : "HINESVILLE", "loc" : [ -81.607214, 31.851296 ], "pop" : 42962, "state" : "GA" }
+{ "_id" : "31314", "city" : "FORT STEWART", "loc" : [ -81.440489, 31.979085 ], "pop" : 0, "state" : "GA" }
+{ "_id" : "31316", "city" : "LUDOWICI", "loc" : [ -81.74531500000001, 31.770477 ], "pop" : 6139, "state" : "GA" }
+{ "_id" : "31319", "city" : "MERIDIAN", "loc" : [ -81.42391499999999, 31.411068 ], "pop" : 672, "state" : "GA" }
+{ "_id" : "31320", "city" : "MIDWAY", "loc" : [ -81.390897, 31.801803 ], "pop" : 4486, "state" : "GA" }
+{ "_id" : "31321", "city" : "PEMBROKE", "loc" : [ -81.553341, 32.157088 ], "pop" : 6571, "state" : "GA" }
+{ "_id" : "31322", "city" : "POOLER", "loc" : [ -81.251958, 32.114931 ], "pop" : 4036, "state" : "GA" }
+{ "_id" : "31323", "city" : "RICEBORO", "loc" : [ -81.467134, 31.735696 ], "pop" : 1737, "state" : "GA" }
+{ "_id" : "31324", "city" : "RICHMOND HILL", "loc" : [ -81.294026, 31.896152 ], "pop" : 7455, "state" : "GA" }
+{ "_id" : "31326", "city" : "RINCON", "loc" : [ -81.28777700000001, 32.235632 ], "pop" : 14502, "state" : "GA" }
+{ "_id" : "31327", "city" : "SAPELO ISLAND", "loc" : [ -81.267933, 31.421948 ], "pop" : 120, "state" : "GA" }
+{ "_id" : "31328", "city" : "TYBEE ISLAND", "loc" : [ -80.850938, 32.006797 ], "pop" : 3106, "state" : "GA" }
+{ "_id" : "31329", "city" : "STILLWELL", "loc" : [ -81.326435, 32.4121 ], "pop" : 6761, "state" : "GA" }
+{ "_id" : "31331", "city" : "TOWNSEND", "loc" : [ -81.418204, 31.567339 ], "pop" : 2413, "state" : "GA" }
+{ "_id" : "31401", "city" : "SAVANNAH", "loc" : [ -81.102394, 32.067631 ], "pop" : 37544, "state" : "GA" }
+{ "_id" : "31404", "city" : "STATE COLLEGE", "loc" : [ -81.068704, 32.044178 ], "pop" : 33927, "state" : "GA" }
+{ "_id" : "31405", "city" : "SAVANNAH", "loc" : [ -81.12419199999999, 32.039119 ], "pop" : 28739, "state" : "GA" }
+{ "_id" : "31406", "city" : "SAVANNAH", "loc" : [ -81.097893, 31.988993 ], "pop" : 34024, "state" : "GA" }
+{ "_id" : "31407", "city" : "PORT WENTWORTH", "loc" : [ -81.162891, 32.148075 ], "pop" : 2883, "state" : "GA" }
+{ "_id" : "31408", "city" : "GARDEN CITY", "loc" : [ -81.168181, 32.109245 ], "pop" : 12548, "state" : "GA" }
+{ "_id" : "31409", "city" : "SAVANNAH", "loc" : [ -81.158371, 32.002104 ], "pop" : 3509, "state" : "GA" }
+{ "_id" : "31410", "city" : "SAVANNAH", "loc" : [ -80.983859, 32.016188 ], "pop" : 15808, "state" : "GA" }
+{ "_id" : "31411", "city" : "SAVANNAH", "loc" : [ -81.03807399999999, 31.926801 ], "pop" : 4707, "state" : "GA" }
+{ "_id" : "31419", "city" : "M M", "loc" : [ -81.177387, 31.985149 ], "pop" : 32901, "state" : "GA" }
+{ "_id" : "31501", "city" : "OKEFENOKEE", "loc" : [ -82.364512, 31.219686 ], "pop" : 33068, "state" : "GA" }
+{ "_id" : "31510", "city" : "ALMA", "loc" : [ -82.4633, 31.546525 ], "pop" : 9566, "state" : "GA" }
+{ "_id" : "31512", "city" : "AMBROSE", "loc" : [ -82.997637, 31.536712 ], "pop" : 2853, "state" : "GA" }
+{ "_id" : "31513", "city" : "BAXLEY", "loc" : [ -82.348643, 31.783663 ], "pop" : 14099, "state" : "GA" }
+{ "_id" : "31516", "city" : "BLACKSHEAR", "loc" : [ -82.261708, 31.293063 ], "pop" : 9612, "state" : "GA" }
+{ "_id" : "31518", "city" : "BRISTOL", "loc" : [ -82.249594, 31.40278 ], "pop" : 996, "state" : "GA" }
+{ "_id" : "31519", "city" : "BROXTON", "loc" : [ -82.904954, 31.648426 ], "pop" : 2915, "state" : "GA" }
+{ "_id" : "31520", "city" : "GLYNCO", "loc" : [ -81.493045, 31.169652 ], "pop" : 21343, "state" : "GA" }
+{ "_id" : "31522", "city" : "SAINT SIMONS ISL", "loc" : [ -81.38242099999999, 31.16916 ], "pop" : 12924, "state" : "GA" }
+{ "_id" : "31525", "city" : "BRUNSWICK", "loc" : [ -81.511365, 31.230411 ], "pop" : 27079, "state" : "GA" }
+{ "_id" : "31527", "city" : "JEKYLL ISLAND", "loc" : [ -81.41280999999999, 31.074049 ], "pop" : 1150, "state" : "GA" }
+{ "_id" : "31532", "city" : "DENTON", "loc" : [ -82.720146, 31.745842 ], "pop" : 1457, "state" : "GA" }
+{ "_id" : "31533", "city" : "DOUGLAS", "loc" : [ -82.846468, 31.497287 ], "pop" : 19607, "state" : "GA" }
+{ "_id" : "31537", "city" : "FOLKSTON", "loc" : [ -82.011617, 30.850838 ], "pop" : 6486, "state" : "GA" }
+{ "_id" : "31539", "city" : "HAZLEHURST", "loc" : [ -82.590947, 31.860569 ], "pop" : 10577, "state" : "GA" }
+{ "_id" : "31542", "city" : "HOBOKEN", "loc" : [ -82.183847, 31.183777 ], "pop" : 3481, "state" : "GA" }
+{ "_id" : "31543", "city" : "HORTENSE", "loc" : [ -81.95956099999999, 31.319949 ], "pop" : 968, "state" : "GA" }
+{ "_id" : "31544", "city" : "JACKSONVILLE", "loc" : [ -82.975003, 31.848079 ], "pop" : 905, "state" : "GA" }
+{ "_id" : "31545", "city" : "JESUP", "loc" : [ -81.88706000000001, 31.604326 ], "pop" : 17180, "state" : "GA" }
+{ "_id" : "31548", "city" : "KINGSLAND", "loc" : [ -81.707483, 30.797681 ], "pop" : 8781, "state" : "GA" }
+{ "_id" : "31549", "city" : "LUMBER CITY", "loc" : [ -82.707312, 31.925124 ], "pop" : 2036, "state" : "GA" }
+{ "_id" : "31550", "city" : "MANOR", "loc" : [ -82.574173, 31.108829 ], "pop" : 794, "state" : "GA" }
+{ "_id" : "31551", "city" : "MERSHON", "loc" : [ -82.216995, 31.478279 ], "pop" : 365, "state" : "GA" }
+{ "_id" : "31552", "city" : "MILLWOOD", "loc" : [ -82.644148, 31.250566 ], "pop" : 500, "state" : "GA" }
+{ "_id" : "31553", "city" : "NAHUNTA", "loc" : [ -81.972212, 31.182652 ], "pop" : 3158, "state" : "GA" }
+{ "_id" : "31554", "city" : "NICHOLLS", "loc" : [ -82.603207, 31.449812 ], "pop" : 3615, "state" : "GA" }
+{ "_id" : "31555", "city" : "ODUM", "loc" : [ -81.99430099999999, 31.699916 ], "pop" : 2851, "state" : "GA" }
+{ "_id" : "31557", "city" : "PATTERSON", "loc" : [ -82.127444, 31.390338 ], "pop" : 2355, "state" : "GA" }
+{ "_id" : "31558", "city" : "SAINT MARYS", "loc" : [ -81.56521100000001, 30.773467 ], "pop" : 15655, "state" : "GA" }
+{ "_id" : "31560", "city" : "SCREVEN", "loc" : [ -82.039742, 31.516846 ], "pop" : 2325, "state" : "GA" }
+{ "_id" : "31563", "city" : "SURRENCY", "loc" : [ -82.198218, 31.648931 ], "pop" : 1643, "state" : "GA" }
+{ "_id" : "31565", "city" : "WAVERLY", "loc" : [ -81.56967, 31.042672 ], "pop" : 331, "state" : "GA" }
+{ "_id" : "31566", "city" : "WAYNESVILLE", "loc" : [ -81.803928, 31.244792 ], "pop" : 3248, "state" : "GA" }
+{ "_id" : "31567", "city" : "WEST GREEN", "loc" : [ -82.756417, 31.592271 ], "pop" : 1940, "state" : "GA" }
+{ "_id" : "31568", "city" : "WHITE OAK", "loc" : [ -81.80823700000001, 31.034037 ], "pop" : 892, "state" : "GA" }
+{ "_id" : "31569", "city" : "WOODBINE", "loc" : [ -81.678313, 30.943692 ], "pop" : 4508, "state" : "GA" }
+{ "_id" : "31601", "city" : "CLYATTVILLE", "loc" : [ -83.27716599999999, 30.810578 ], "pop" : 32232, "state" : "GA" }
+{ "_id" : "31602", "city" : "BEMISS", "loc" : [ -83.27329899999999, 30.890268 ], "pop" : 32292, "state" : "GA" }
+{ "_id" : "31620", "city" : "ADEL", "loc" : [ -83.421346, 31.125143 ], "pop" : 9661, "state" : "GA" }
+{ "_id" : "31622", "city" : "ALAPAHA", "loc" : [ -83.21321, 31.394027 ], "pop" : 1675, "state" : "GA" }
+{ "_id" : "31624", "city" : "AXSON", "loc" : [ -82.731945, 31.303455 ], "pop" : 912, "state" : "GA" }
+{ "_id" : "31625", "city" : "BARNEY", "loc" : [ -83.521934, 31.007424 ], "pop" : 895, "state" : "GA" }
+{ "_id" : "31626", "city" : "BOSTON", "loc" : [ -83.797085, 30.785547 ], "pop" : 2808, "state" : "GA" }
+{ "_id" : "31629", "city" : "DIXIE", "loc" : [ -83.67918, 30.772213 ], "pop" : 1462, "state" : "GA" }
+{ "_id" : "31630", "city" : "DU PONT", "loc" : [ -82.855518, 30.999996 ], "pop" : 502, "state" : "GA" }
+{ "_id" : "31631", "city" : "FARGO", "loc" : [ -82.580056, 30.716587 ], "pop" : 560, "state" : "GA" }
+{ "_id" : "31632", "city" : "HAHIRA", "loc" : [ -83.357366, 30.941593 ], "pop" : 6921, "state" : "GA" }
+{ "_id" : "31634", "city" : "COGDELL", "loc" : [ -82.743103, 31.044991 ], "pop" : 5098, "state" : "GA" }
+{ "_id" : "31635", "city" : "LAKELAND", "loc" : [ -83.088859, 31.038107 ], "pop" : 4289, "state" : "GA" }
+{ "_id" : "31636", "city" : "LAKE PARK", "loc" : [ -83.175293, 30.690615 ], "pop" : 4491, "state" : "GA" }
+{ "_id" : "31637", "city" : "LENOX", "loc" : [ -83.44813499999999, 31.266405 ], "pop" : 1993, "state" : "GA" }
+{ "_id" : "31638", "city" : "MORVEN", "loc" : [ -83.44979600000001, 30.893733 ], "pop" : 3416, "state" : "GA" }
+{ "_id" : "31639", "city" : "NASHVILLE", "loc" : [ -83.23194599999999, 31.207379 ], "pop" : 8396, "state" : "GA" }
+{ "_id" : "31641", "city" : "NAYLOR", "loc" : [ -83.12236799999999, 30.89846 ], "pop" : 1110, "state" : "GA" }
+{ "_id" : "31642", "city" : "PEARSON", "loc" : [ -82.85909599999999, 31.310583 ], "pop" : 3590, "state" : "GA" }
+{ "_id" : "31643", "city" : "QUITMAN", "loc" : [ -83.556748, 30.779699 ], "pop" : 8028, "state" : "GA" }
+{ "_id" : "31645", "city" : "RAY CITY", "loc" : [ -83.21428299999999, 31.08247 ], "pop" : 1859, "state" : "GA" }
+{ "_id" : "31646", "city" : "SAINT GEORGE", "loc" : [ -82.083367, 30.559161 ], "pop" : 2010, "state" : "GA" }
+{ "_id" : "31647", "city" : "SPARKS", "loc" : [ -83.447586, 31.178984 ], "pop" : 1772, "state" : "GA" }
+{ "_id" : "31648", "city" : "STATENVILLE", "loc" : [ -82.97986299999999, 30.725503 ], "pop" : 1269, "state" : "GA" }
+{ "_id" : "31649", "city" : "STOCKTON", "loc" : [ -83.013944, 31.022865 ], "pop" : 1242, "state" : "GA" }
+{ "_id" : "31650", "city" : "WILLACOOCHEE", "loc" : [ -83.04493100000001, 31.345481 ], "pop" : 1704, "state" : "GA" }
+{ "_id" : "31701", "city" : "ALBANY", "loc" : [ -84.161923, 31.567783 ], "pop" : 25698, "state" : "GA" }
+{ "_id" : "31704", "city" : "MARINE CORPS LOG", "loc" : [ -84.05081199999999, 31.550099 ], "pop" : 1306, "state" : "GA" }
+{ "_id" : "31705", "city" : "BRIDGEBORO", "loc" : [ -84.09008900000001, 31.550851 ], "pop" : 35997, "state" : "GA" }
+{ "_id" : "31707", "city" : "ALBANY", "loc" : [ -84.211834, 31.578908 ], "pop" : 36439, "state" : "GA" }
+{ "_id" : "31709", "city" : "GEORGIA SOUTHWES", "loc" : [ -84.224729, 32.07077 ], "pop" : 23590, "state" : "GA" }
+{ "_id" : "31711", "city" : "ANDERSONVILLE", "loc" : [ -84.10101, 32.129907 ], "pop" : 984, "state" : "GA" }
+{ "_id" : "31712", "city" : "ARABI", "loc" : [ -83.72856, 31.862923 ], "pop" : 1349, "state" : "GA" }
+{ "_id" : "31713", "city" : "ARLINGTON", "loc" : [ -84.72572, 31.445597 ], "pop" : 1402, "state" : "GA" }
+{ "_id" : "31714", "city" : "ASHBURN", "loc" : [ -83.660775, 31.705877 ], "pop" : 6047, "state" : "GA" }
+{ "_id" : "31715", "city" : "ATTAPULGUS", "loc" : [ -84.486008, 30.750639 ], "pop" : 3131, "state" : "GA" }
+{ "_id" : "31716", "city" : "BACONTON", "loc" : [ -84.11345, 31.387804 ], "pop" : 2566, "state" : "GA" }
+{ "_id" : "31717", "city" : "BAINBRIDGE", "loc" : [ -84.573975, 30.897865 ], "pop" : 17739, "state" : "GA" }
+{ "_id" : "31723", "city" : "BLAKELY", "loc" : [ -84.93528499999999, 31.371854 ], "pop" : 8405, "state" : "GA" }
+{ "_id" : "31724", "city" : "BLUFFTON", "loc" : [ -84.87717499999999, 31.556189 ], "pop" : 799, "state" : "GA" }
+{ "_id" : "31725", "city" : "BRINSON", "loc" : [ -84.667112, 30.960957 ], "pop" : 2877, "state" : "GA" }
+{ "_id" : "31726", "city" : "BRONWOOD", "loc" : [ -84.35938899999999, 31.821591 ], "pop" : 1075, "state" : "GA" }
+{ "_id" : "31728", "city" : "CAIRO", "loc" : [ -84.196246, 30.892462 ], "pop" : 15393, "state" : "GA" }
+{ "_id" : "31729", "city" : "CALVARY", "loc" : [ -84.32267, 30.747036 ], "pop" : 1442, "state" : "GA" }
+{ "_id" : "31730", "city" : "CAMILLA", "loc" : [ -84.22968299999999, 31.219915 ], "pop" : 9207, "state" : "GA" }
+{ "_id" : "31733", "city" : "CHULA", "loc" : [ -83.550864, 31.543855 ], "pop" : 2425, "state" : "GA" }
+{ "_id" : "31734", "city" : "CLIMAX", "loc" : [ -84.443217, 30.85731 ], "pop" : 1764, "state" : "GA" }
+{ "_id" : "31735", "city" : "COBB", "loc" : [ -83.95808700000001, 31.961708 ], "pop" : 881, "state" : "GA" }
+{ "_id" : "31736", "city" : "COLEMAN", "loc" : [ -84.874471, 31.656831 ], "pop" : 359, "state" : "GA" }
+{ "_id" : "31737", "city" : "COLQUITT", "loc" : [ -84.730896, 31.161871 ], "pop" : 6277, "state" : "GA" }
+{ "_id" : "31738", "city" : "COOLIDGE", "loc" : [ -83.87524500000001, 30.985908 ], "pop" : 1970, "state" : "GA" }
+{ "_id" : "31740", "city" : "CUTHBERT", "loc" : [ -84.78887400000001, 31.769073 ], "pop" : 5708, "state" : "GA" }
+{ "_id" : "31741", "city" : "DAMASCUS", "loc" : [ -84.72004699999999, 31.341528 ], "pop" : 1534, "state" : "GA" }
+{ "_id" : "31742", "city" : "GRAVES", "loc" : [ -84.43078199999999, 31.759846 ], "pop" : 8731, "state" : "GA" }
+{ "_id" : "31743", "city" : "DE SOTO", "loc" : [ -84.027101, 31.950186 ], "pop" : 112, "state" : "GA" }
+{ "_id" : "31744", "city" : "DOERUN", "loc" : [ -83.925316, 31.313647 ], "pop" : 1738, "state" : "GA" }
+{ "_id" : "31745", "city" : "DONALSONVILLE", "loc" : [ -84.887024, 30.981801 ], "pop" : 7468, "state" : "GA" }
+{ "_id" : "31746", "city" : "EDISON", "loc" : [ -84.745626, 31.564979 ], "pop" : 1711, "state" : "GA" }
+{ "_id" : "31749", "city" : "ENIGMA", "loc" : [ -83.35515700000001, 31.373599 ], "pop" : 2223, "state" : "GA" }
+{ "_id" : "31750", "city" : "FITZGERALD", "loc" : [ -83.249534, 31.724769 ], "pop" : 16245, "state" : "GA" }
+{ "_id" : "31751", "city" : "FORT GAINES", "loc" : [ -85.03937500000001, 31.646353 ], "pop" : 2565, "state" : "GA" }
+{ "_id" : "31754", "city" : "GEORGETOWN", "loc" : [ -85.07113699999999, 31.884763 ], "pop" : 1415, "state" : "GA" }
+{ "_id" : "31756", "city" : "HARTSFIELD", "loc" : [ -83.970364, 31.217316 ], "pop" : 285, "state" : "GA" }
+{ "_id" : "31759", "city" : "IRON CITY", "loc" : [ -84.796632, 30.994728 ], "pop" : 1542, "state" : "GA" }
+{ "_id" : "31760", "city" : "IRWINVILLE", "loc" : [ -83.401708, 31.654238 ], "pop" : 1887, "state" : "GA" }
+{ "_id" : "31761", "city" : "JAKIN", "loc" : [ -84.994845, 31.175064 ], "pop" : 1918, "state" : "GA" }
+{ "_id" : "31762", "city" : "LEARY", "loc" : [ -84.509486, 31.505924 ], "pop" : 1017, "state" : "GA" }
+{ "_id" : "31763", "city" : "LEESBURG", "loc" : [ -84.159263, 31.681161 ], "pop" : 14641, "state" : "GA" }
+{ "_id" : "31764", "city" : "LESLIE", "loc" : [ -84.07834, 31.953952 ], "pop" : 1273, "state" : "GA" }
+{ "_id" : "31765", "city" : "MEIGS", "loc" : [ -84.082375, 31.062536 ], "pop" : 1705, "state" : "GA" }
+{ "_id" : "31766", "city" : "MORGAN", "loc" : [ -84.61779799999999, 31.556557 ], "pop" : 883, "state" : "GA" }
+{ "_id" : "31767", "city" : "SPRINGVALE", "loc" : [ -85.05725099999999, 31.823432 ], "pop" : 850, "state" : "GA" }
+{ "_id" : "31768", "city" : "MOULTRIE", "loc" : [ -83.764089, 31.179244 ], "pop" : 34351, "state" : "GA" }
+{ "_id" : "31770", "city" : "NEWTON", "loc" : [ -84.441107, 31.313426 ], "pop" : 3615, "state" : "GA" }
+{ "_id" : "31771", "city" : "NORMAN PARK", "loc" : [ -83.94044, 31.069128 ], "pop" : 301, "state" : "GA" }
+{ "_id" : "31772", "city" : "OAKFIELD", "loc" : [ -83.97059, 31.779768 ], "pop" : 149, "state" : "GA" }
+{ "_id" : "31773", "city" : "OCHLOCKNEE", "loc" : [ -84.0326, 30.959407 ], "pop" : 2665, "state" : "GA" }
+{ "_id" : "31774", "city" : "OCILLA", "loc" : [ -83.256542, 31.592944 ], "pop" : 5784, "state" : "GA" }
+{ "_id" : "31775", "city" : "OMEGA", "loc" : [ -83.593936, 31.360432 ], "pop" : 2154, "state" : "GA" }
+{ "_id" : "31777", "city" : "PARROTT", "loc" : [ -84.501152, 31.872016 ], "pop" : 886, "state" : "GA" }
+{ "_id" : "31778", "city" : "PAVO", "loc" : [ -83.74085599999999, 30.940142 ], "pop" : 3573, "state" : "GA" }
+{ "_id" : "31779", "city" : "PELHAM", "loc" : [ -84.156367, 31.127233 ], "pop" : 7123, "state" : "GA" }
+{ "_id" : "31780", "city" : "PLAINS", "loc" : [ -84.358638, 32.033908 ], "pop" : 3377, "state" : "GA" }
+{ "_id" : "31781", "city" : "POULAN", "loc" : [ -83.761554, 31.467206 ], "pop" : 3119, "state" : "GA" }
+{ "_id" : "31783", "city" : "REBECCA", "loc" : [ -83.523478, 31.797921 ], "pop" : 630, "state" : "GA" }
+{ "_id" : "31784", "city" : "SALE CITY", "loc" : [ -84.04219500000001, 31.260004 ], "pop" : 1379, "state" : "GA" }
+{ "_id" : "31786", "city" : "SHELLMAN", "loc" : [ -84.61661599999999, 31.743407 ], "pop" : 1900, "state" : "GA" }
+{ "_id" : "31787", "city" : "SMITHVILLE", "loc" : [ -84.22706599999999, 31.884692 ], "pop" : 1570, "state" : "GA" }
+{ "_id" : "31789", "city" : "SUMNER", "loc" : [ -83.724463, 31.53925 ], "pop" : 1125, "state" : "GA" }
+{ "_id" : "31790", "city" : "SYCAMORE", "loc" : [ -83.606363, 31.655329 ], "pop" : 2026, "state" : "GA" }
+{ "_id" : "31791", "city" : "SYLVESTER", "loc" : [ -83.860731, 31.539268 ], "pop" : 9573, "state" : "GA" }
+{ "_id" : "31792", "city" : "THOMASVILLE", "loc" : [ -83.969616, 30.838543 ], "pop" : 28319, "state" : "GA" }
+{ "_id" : "31794", "city" : "ABAC", "loc" : [ -83.498867, 31.451722 ], "pop" : 27906, "state" : "GA" }
+{ "_id" : "31795", "city" : "TY TY", "loc" : [ -83.621989, 31.45595 ], "pop" : 2513, "state" : "GA" }
+{ "_id" : "31796", "city" : "WARWICK", "loc" : [ -83.920092, 31.734495 ], "pop" : 2650, "state" : "GA" }
+{ "_id" : "31797", "city" : "WHIGHAM", "loc" : [ -84.315771, 30.90701 ], "pop" : 2987, "state" : "GA" }
+{ "_id" : "31798", "city" : "WRAY", "loc" : [ -83.107484, 31.595229 ], "pop" : 978, "state" : "GA" }
+{ "_id" : "31801", "city" : "JUNIPER", "loc" : [ -84.612951, 32.565562 ], "pop" : 1407, "state" : "GA" }
+{ "_id" : "31803", "city" : "TAZEWELL", "loc" : [ -84.52734700000001, 32.354198 ], "pop" : 5590, "state" : "GA" }
+{ "_id" : "31804", "city" : "CATAULA", "loc" : [ -84.92069100000001, 32.624246 ], "pop" : 1108, "state" : "GA" }
+{ "_id" : "31805", "city" : "CUSSETA", "loc" : [ -84.764537, 32.299026 ], "pop" : 2290, "state" : "GA" }
+{ "_id" : "31806", "city" : "ELLAVILLE", "loc" : [ -84.30386799999999, 32.23901 ], "pop" : 3599, "state" : "GA" }
+{ "_id" : "31807", "city" : "ELLERSLIE", "loc" : [ -84.877197, 32.661718 ], "pop" : 2153, "state" : "GA" }
+{ "_id" : "31808", "city" : "FORTSON", "loc" : [ -85.001654, 32.628841 ], "pop" : 1780, "state" : "GA" }
+{ "_id" : "31811", "city" : "HAMILTON", "loc" : [ -84.884753, 32.741795 ], "pop" : 1587, "state" : "GA" }
+{ "_id" : "31812", "city" : "JUNCTION CITY", "loc" : [ -84.45741, 32.608046 ], "pop" : 472, "state" : "GA" }
+{ "_id" : "31815", "city" : "LUMPKIN", "loc" : [ -84.802227, 32.043465 ], "pop" : 2144, "state" : "GA" }
+{ "_id" : "31816", "city" : "MANCHESTER", "loc" : [ -84.63116599999999, 32.8721 ], "pop" : 7721, "state" : "GA" }
+{ "_id" : "31820", "city" : "MIDLAND", "loc" : [ -84.855851, 32.561587 ], "pop" : 4725, "state" : "GA" }
+{ "_id" : "31821", "city" : "OMAHA", "loc" : [ -84.900792, 32.165234 ], "pop" : 884, "state" : "GA" }
+{ "_id" : "31822", "city" : "PINE MOUNTAIN", "loc" : [ -84.89595300000001, 32.873488 ], "pop" : 3548, "state" : "GA" }
+{ "_id" : "31823", "city" : "PINE MOUNTAIN VA", "loc" : [ -84.823874, 32.791849 ], "pop" : 887, "state" : "GA" }
+{ "_id" : "31824", "city" : "PRESTON", "loc" : [ -84.548918, 32.074031 ], "pop" : 1690, "state" : "GA" }
+{ "_id" : "31825", "city" : "RICHLAND", "loc" : [ -84.666724, 32.084578 ], "pop" : 2626, "state" : "GA" }
+{ "_id" : "31826", "city" : "SHILOH", "loc" : [ -84.74117099999999, 32.806678 ], "pop" : 1478, "state" : "GA" }
+{ "_id" : "31827", "city" : "TALBOTTON", "loc" : [ -84.546206, 32.679702 ], "pop" : 2324, "state" : "GA" }
+{ "_id" : "31829", "city" : "UPATOI", "loc" : [ -84.74481900000001, 32.560057 ], "pop" : 725, "state" : "GA" }
+{ "_id" : "31830", "city" : "WARM SPRINGS", "loc" : [ -84.82172799999999, 32.895558 ], "pop" : 819, "state" : "GA" }
+{ "_id" : "31831", "city" : "WAVERLY HALL", "loc" : [ -84.742463, 32.679326 ], "pop" : 2323, "state" : "GA" }
+{ "_id" : "31832", "city" : "WESTON", "loc" : [ -84.575579, 31.963665 ], "pop" : 573, "state" : "GA" }
+{ "_id" : "31833", "city" : "WEST POINT", "loc" : [ -85.119714, 32.833683 ], "pop" : 8499, "state" : "GA" }
+{ "_id" : "31836", "city" : "WOODLAND", "loc" : [ -84.595187, 32.806066 ], "pop" : 2377, "state" : "GA" }
+{ "_id" : "31901", "city" : "COLUMBUS", "loc" : [ -84.979456, 32.473035 ], "pop" : 9694, "state" : "GA" }
+{ "_id" : "31903", "city" : "COLUMBUS", "loc" : [ -84.948127, 32.424513 ], "pop" : 25362, "state" : "GA" }
+{ "_id" : "31904", "city" : "COLUMBUS", "loc" : [ -84.978475, 32.516091 ], "pop" : 29254, "state" : "GA" }
+{ "_id" : "31905", "city" : "CUSTER TERRACE", "loc" : [ -84.94526399999999, 32.369728 ], "pop" : 22869, "state" : "GA" }
+{ "_id" : "31906", "city" : "COLUMBUS", "loc" : [ -84.94842199999999, 32.463819 ], "pop" : 26061, "state" : "GA" }
+{ "_id" : "31907", "city" : "COLUMBUS", "loc" : [ -84.89798999999999, 32.477909 ], "pop" : 54915, "state" : "GA" }
+{ "_id" : "31909", "city" : "COLUMBUS", "loc" : [ -84.927404, 32.536913 ], "pop" : 20880, "state" : "GA" }
+{ "_id" : "32008", "city" : "BRANFORD", "loc" : [ -82.899288, 29.939472 ], "pop" : 2439, "state" : "FL" }
+{ "_id" : "32009", "city" : "BRYCEVILLE", "loc" : [ -81.972397, 30.419274 ], "pop" : 1875, "state" : "FL" }
+{ "_id" : "32011", "city" : "CALLAHAN", "loc" : [ -81.814465, 30.551958 ], "pop" : 9111, "state" : "FL" }
+{ "_id" : "32013", "city" : "DAY", "loc" : [ -83.28505199999999, 30.149666 ], "pop" : 1567, "state" : "FL" }
+{ "_id" : "32033", "city" : "ELKTON", "loc" : [ -81.46199, 29.788243 ], "pop" : 1557, "state" : "FL" }
+{ "_id" : "32034", "city" : "AMELIA ISLAND", "loc" : [ -81.468829, 30.635388 ], "pop" : 19016, "state" : "FL" }
+{ "_id" : "32038", "city" : "FORT WHITE", "loc" : [ -82.687938, 29.92073 ], "pop" : 3439, "state" : "FL" }
+{ "_id" : "32040", "city" : "GLEN SAINT MARY", "loc" : [ -82.20405599999999, 30.286058 ], "pop" : 6467, "state" : "FL" }
+{ "_id" : "32043", "city" : "GREEN COVE SPRIN", "loc" : [ -81.72618199999999, 30.00425 ], "pop" : 16033, "state" : "FL" }
+{ "_id" : "32044", "city" : "HAMPTON", "loc" : [ -82.148347, 29.857511 ], "pop" : 1274, "state" : "FL" }
+{ "_id" : "32046", "city" : "HILLIARD", "loc" : [ -81.93453, 30.688367 ], "pop" : 6486, "state" : "FL" }
+{ "_id" : "32052", "city" : "JASPER", "loc" : [ -82.932186, 30.502914 ], "pop" : 6588, "state" : "FL" }
+{ "_id" : "32053", "city" : "JENNINGS", "loc" : [ -83.13497099999999, 30.548243 ], "pop" : 2977, "state" : "FL" }
+{ "_id" : "32054", "city" : "LAKE BUTLER", "loc" : [ -82.382796, 30.003485 ], "pop" : 8658, "state" : "FL" }
+{ "_id" : "32055", "city" : "LAKE CITY", "loc" : [ -82.659888, 30.165239 ], "pop" : 38018, "state" : "FL" }
+{ "_id" : "32058", "city" : "LAWTEY", "loc" : [ -82.10554399999999, 30.047164 ], "pop" : 4108, "state" : "FL" }
+{ "_id" : "32059", "city" : "LEE", "loc" : [ -83.284392, 30.397863 ], "pop" : 1260, "state" : "FL" }
+{ "_id" : "32060", "city" : "BOYS RANCH", "loc" : [ -83.02499400000001, 30.286622 ], "pop" : 19075, "state" : "FL" }
+{ "_id" : "32061", "city" : "LULU", "loc" : [ -82.538481, 30.07544 ], "pop" : 295, "state" : "FL" }
+{ "_id" : "32062", "city" : "MC ALPIN", "loc" : [ -82.966182, 30.150899 ], "pop" : 2062, "state" : "FL" }
+{ "_id" : "32063", "city" : "MACCLENNY", "loc" : [ -82.132475, 30.273671 ], "pop" : 9749, "state" : "FL" }
+{ "_id" : "32065", "city" : "ORANGE PARK", "loc" : [ -81.774199, 30.138233 ], "pop" : 19248, "state" : "FL" }
+{ "_id" : "32066", "city" : "MAYO", "loc" : [ -83.146208, 30.039979 ], "pop" : 3475, "state" : "FL" }
+{ "_id" : "32068", "city" : "MIDDLEBURG", "loc" : [ -81.864476, 30.083984 ], "pop" : 23245, "state" : "FL" }
+{ "_id" : "32071", "city" : "O BRIEN", "loc" : [ -82.93004999999999, 30.038114 ], "pop" : 1305, "state" : "FL" }
+{ "_id" : "32073", "city" : "ORANGE PARK", "loc" : [ -81.72906999999999, 30.16369 ], "pop" : 37281, "state" : "FL" }
+{ "_id" : "32082", "city" : "PONTE VEDRA BEAC", "loc" : [ -81.386383, 30.215326 ], "pop" : 14727, "state" : "FL" }
+{ "_id" : "32083", "city" : "RAIFORD", "loc" : [ -82.20012, 30.070379 ], "pop" : 1594, "state" : "FL" }
+{ "_id" : "32084", "city" : "SAINT AUGUSTINE", "loc" : [ -81.298367, 29.880457 ], "pop" : 24906, "state" : "FL" }
+{ "_id" : "32086", "city" : "SAINT AUGUSTINE", "loc" : [ -81.323734, 29.828514 ], "pop" : 16939, "state" : "FL" }
+{ "_id" : "32087", "city" : "SANDERSON", "loc" : [ -82.33774099999999, 30.302536 ], "pop" : 2270, "state" : "FL" }
+{ "_id" : "32091", "city" : "STARKE", "loc" : [ -82.11851799999999, 29.958299 ], "pop" : 15058, "state" : "FL" }
+{ "_id" : "32092", "city" : "SAINT AUGUSTINE", "loc" : [ -81.52637900000001, 29.947511 ], "pop" : 4702, "state" : "FL" }
+{ "_id" : "32094", "city" : "WELLBORN", "loc" : [ -82.850532, 30.179624 ], "pop" : 1621, "state" : "FL" }
+{ "_id" : "32095", "city" : "SAINT AUGUSTINE", "loc" : [ -81.34762600000001, 29.905726 ], "pop" : 12132, "state" : "FL" }
+{ "_id" : "32096", "city" : "WHITE SPRINGS", "loc" : [ -82.776453, 30.338749 ], "pop" : 1671, "state" : "FL" }
+{ "_id" : "32097", "city" : "YULEE", "loc" : [ -81.590603, 30.622225 ], "pop" : 7453, "state" : "FL" }
+{ "_id" : "32102", "city" : "ASTOR", "loc" : [ -81.539929, 29.165031 ], "pop" : 2092, "state" : "FL" }
+{ "_id" : "32110", "city" : "BUNNELL", "loc" : [ -81.324431, 29.45616 ], "pop" : 4925, "state" : "FL" }
+{ "_id" : "32112", "city" : "CRESCENT CITY", "loc" : [ -81.557909, 29.445438 ], "pop" : 7481, "state" : "FL" }
+{ "_id" : "32113", "city" : "CITRA", "loc" : [ -82.106222, 29.39182 ], "pop" : 3340, "state" : "FL" }
+{ "_id" : "32114", "city" : "DAYTONA BEACH", "loc" : [ -81.037071, 29.201168 ], "pop" : 34235, "state" : "FL" }
+{ "_id" : "32117", "city" : "HOLLY HILL", "loc" : [ -81.054698, 29.236006 ], "pop" : 22599, "state" : "FL" }
+{ "_id" : "32118", "city" : "DAYTONA BEACH", "loc" : [ -81.009469, 29.221874 ], "pop" : 17009, "state" : "FL" }
+{ "_id" : "32119", "city" : "DUNLAWTON", "loc" : [ -81.022142, 29.152526 ], "pop" : 36500, "state" : "FL" }
+{ "_id" : "32124", "city" : "PORT ORANGE", "loc" : [ -81.106746, 29.122456 ], "pop" : 7360, "state" : "FL" }
+{ "_id" : "32127", "city" : "PORT ORANGE", "loc" : [ -80.98835099999999, 29.1124 ], "pop" : 25925, "state" : "FL" }
+{ "_id" : "32130", "city" : "DE LEON SPRINGS", "loc" : [ -81.34876199999999, 29.116592 ], "pop" : 2267, "state" : "FL" }
+{ "_id" : "32131", "city" : "EAST PALATKA", "loc" : [ -81.587879, 29.660861 ], "pop" : 5851, "state" : "FL" }
+{ "_id" : "32132", "city" : "EDGEWATER", "loc" : [ -80.91034399999999, 28.981801 ], "pop" : 6690, "state" : "FL" }
+{ "_id" : "32134", "city" : "SALT SPRINGS", "loc" : [ -81.88775699999999, 29.279554 ], "pop" : 14324, "state" : "FL" }
+{ "_id" : "32136", "city" : "FLAGLER BEACH", "loc" : [ -81.13028799999999, 29.474978 ], "pop" : 4608, "state" : "FL" }
+{ "_id" : "32137", "city" : "PALM COAST", "loc" : [ -81.21899000000001, 29.556515 ], "pop" : 18194, "state" : "FL" }
+{ "_id" : "32139", "city" : "GEORGETOWN", "loc" : [ -81.629783, 29.403315 ], "pop" : 1839, "state" : "FL" }
+{ "_id" : "32140", "city" : "FLORAHOME", "loc" : [ -81.862224, 29.758105 ], "pop" : 1475, "state" : "FL" }
+{ "_id" : "32141", "city" : "EDGEWATER", "loc" : [ -80.896869, 28.945481 ], "pop" : 11379, "state" : "FL" }
+{ "_id" : "32145", "city" : "HASTINGS", "loc" : [ -81.490908, 29.705147 ], "pop" : 2189, "state" : "FL" }
+{ "_id" : "32148", "city" : "INTERLACHEN", "loc" : [ -81.889432, 29.627001 ], "pop" : 15416, "state" : "FL" }
+{ "_id" : "32159", "city" : "LADY LAKE", "loc" : [ -81.92559799999999, 28.929939 ], "pop" : 11493, "state" : "FL" }
+{ "_id" : "32168", "city" : "NEW SMYRNA BEACH", "loc" : [ -80.95843600000001, 29.024672 ], "pop" : 17624, "state" : "FL" }
+{ "_id" : "32169", "city" : "NEW SMYRNA BEACH", "loc" : [ -80.888463, 29.017196 ], "pop" : 9169, "state" : "FL" }
+{ "_id" : "32174", "city" : "ORMOND BEACH", "loc" : [ -81.088216, 29.283305 ], "pop" : 34477, "state" : "FL" }
+{ "_id" : "32176", "city" : "ORMOND BEACH", "loc" : [ -81.058432, 29.322192 ], "pop" : 15383, "state" : "FL" }
+{ "_id" : "32177", "city" : "PALATKA", "loc" : [ -81.659452, 29.657748 ], "pop" : 24263, "state" : "FL" }
+{ "_id" : "32179", "city" : "OCKLAWAHA", "loc" : [ -81.88569, 29.064308 ], "pop" : 4385, "state" : "FL" }
+{ "_id" : "32180", "city" : "PIERSON", "loc" : [ -81.43532999999999, 29.222596 ], "pop" : 7341, "state" : "FL" }
+{ "_id" : "32181", "city" : "POMONA PARK", "loc" : [ -81.63073900000001, 29.502106 ], "pop" : 1006, "state" : "FL" }
+{ "_id" : "32187", "city" : "SAN MATEO", "loc" : [ -81.5921, 29.588827 ], "pop" : 1864, "state" : "FL" }
+{ "_id" : "32189", "city" : "SATSUMA", "loc" : [ -81.640596, 29.559354 ], "pop" : 3490, "state" : "FL" }
+{ "_id" : "32190", "city" : "SEVILLE", "loc" : [ -81.527894, 29.320084 ], "pop" : 436, "state" : "FL" }
+{ "_id" : "32195", "city" : "WEIRSDALE", "loc" : [ -81.893168, 28.978182 ], "pop" : 3034, "state" : "FL" }
+{ "_id" : "32202", "city" : "JACKSONVILLE", "loc" : [ -81.651672, 30.329882 ], "pop" : 4724, "state" : "FL" }
+{ "_id" : "32204", "city" : "JACKSONVILLE", "loc" : [ -81.685445, 30.318899 ], "pop" : 8839, "state" : "FL" }
+{ "_id" : "32205", "city" : "JACKSONVILLE", "loc" : [ -81.72203399999999, 30.317236 ], "pop" : 46463, "state" : "FL" }
+{ "_id" : "32206", "city" : "JACKSONVILLE", "loc" : [ -81.648769, 30.351073 ], "pop" : 23301, "state" : "FL" }
+{ "_id" : "32207", "city" : "JACKSONVILLE", "loc" : [ -81.63205000000001, 30.290766 ], "pop" : 35661, "state" : "FL" }
+{ "_id" : "32208", "city" : "JACKSONVILLE", "loc" : [ -81.688939, 30.393664 ], "pop" : 35615, "state" : "FL" }
+{ "_id" : "32209", "city" : "JACKSONVILLE", "loc" : [ -81.691974, 30.35841 ], "pop" : 42856, "state" : "FL" }
+{ "_id" : "32210", "city" : "JACKSONVILLE", "loc" : [ -81.74731199999999, 30.268743 ], "pop" : 54548, "state" : "FL" }
+{ "_id" : "32211", "city" : "JACKSONVILLE", "loc" : [ -81.58824799999999, 30.348034 ], "pop" : 54199, "state" : "FL" }
+{ "_id" : "32212", "city" : "JACKSONVILLE N A", "loc" : [ -81.68848, 30.220905 ], "pop" : 2517, "state" : "FL" }
+{ "_id" : "32215", "city" : "CECIL FIELD NAS", "loc" : [ -81.66314199999999, 30.23295 ], "pop" : 0, "state" : "FL" }
+{ "_id" : "32216", "city" : "JACKSONVILLE", "loc" : [ -81.547387, 30.293907 ], "pop" : 58867, "state" : "FL" }
+{ "_id" : "32217", "city" : "JACKSONVILLE", "loc" : [ -81.616956, 30.240678 ], "pop" : 19356, "state" : "FL" }
+{ "_id" : "32218", "city" : "JACKSONVILLE", "loc" : [ -81.662631, 30.45067 ], "pop" : 30493, "state" : "FL" }
+{ "_id" : "32219", "city" : "JACKSONVILLE", "loc" : [ -81.763451, 30.403365 ], "pop" : 9570, "state" : "FL" }
+{ "_id" : "32220", "city" : "JACKSONVILLE", "loc" : [ -81.817572, 30.329003 ], "pop" : 9389, "state" : "FL" }
+{ "_id" : "32221", "city" : "JACKSONVILLE", "loc" : [ -81.82023100000001, 30.283707 ], "pop" : 18244, "state" : "FL" }
+{ "_id" : "32222", "city" : "JACKSONVILLE", "loc" : [ -81.813081, 30.229176 ], "pop" : 4093, "state" : "FL" }
+{ "_id" : "32223", "city" : "JACKSONVILLE", "loc" : [ -81.62996099999999, 30.154817 ], "pop" : 19120, "state" : "FL" }
+{ "_id" : "32224", "city" : "JACKSONVILLE", "loc" : [ -81.440427, 30.303076 ], "pop" : 2535, "state" : "FL" }
+{ "_id" : "32225", "city" : "JACKSONVILLE", "loc" : [ -81.506092, 30.350968 ], "pop" : 26551, "state" : "FL" }
+{ "_id" : "32226", "city" : "JACKSONVILLE", "loc" : [ -81.544808, 30.473485 ], "pop" : 6880, "state" : "FL" }
+{ "_id" : "32227", "city" : "JACKSONVILLE BEA", "loc" : [ -81.405424, 30.388275 ], "pop" : 9055, "state" : "FL" }
+{ "_id" : "32233", "city" : "ATLANTIC BEACH", "loc" : [ -81.41586599999999, 30.348258 ], "pop" : 23412, "state" : "FL" }
+{ "_id" : "32234", "city" : "BALDWIN", "loc" : [ -81.978345, 30.229562 ], "pop" : 5830, "state" : "FL" }
+{ "_id" : "32244", "city" : "JACKSONVILLE", "loc" : [ -81.75557999999999, 30.223137 ], "pop" : 37603, "state" : "FL" }
+{ "_id" : "32250", "city" : "JACKSONVILLE BEA", "loc" : [ -81.406243, 30.28319 ], "pop" : 22392, "state" : "FL" }
+{ "_id" : "32256", "city" : "JACKSONVILLE", "loc" : [ -81.55713900000001, 30.221356 ], "pop" : 17293, "state" : "FL" }
+{ "_id" : "32257", "city" : "JACKSONVILLE", "loc" : [ -81.605042, 30.192703 ], "pop" : 30022, "state" : "FL" }
+{ "_id" : "32258", "city" : "JACKSONVILLE", "loc" : [ -81.573864, 30.145944 ], "pop" : 7261, "state" : "FL" }
+{ "_id" : "32259", "city" : "JACKSONVILLE", "loc" : [ -81.621701, 30.095578 ], "pop" : 6677, "state" : "FL" }
+{ "_id" : "32266", "city" : "NEPTUNE BEACH", "loc" : [ -81.405123, 30.31548 ], "pop" : 6816, "state" : "FL" }
+{ "_id" : "32301", "city" : "TALLAHASSEE", "loc" : [ -84.259337, 30.428563 ], "pop" : 21329, "state" : "FL" }
+{ "_id" : "32303", "city" : "TALLAHASSEE", "loc" : [ -84.318946, 30.487433 ], "pop" : 36053, "state" : "FL" }
+{ "_id" : "32304", "city" : "TALLAHASSEE", "loc" : [ -84.32113200000001, 30.447752 ], "pop" : 33437, "state" : "FL" }
+{ "_id" : "32306", "city" : "TALLAHASSEE", "loc" : [ -84.29559399999999, 30.442152 ], "pop" : 1690, "state" : "FL" }
+{ "_id" : "32308", "city" : "TALLAHASSEE", "loc" : [ -84.206903, 30.507725 ], "pop" : 34857, "state" : "FL" }
+{ "_id" : "32310", "city" : "TALLAHASSEE", "loc" : [ -84.32980000000001, 30.399125 ], "pop" : 30379, "state" : "FL" }
+{ "_id" : "32311", "city" : "TALLAHASSEE", "loc" : [ -84.186995, 30.415625 ], "pop" : 17005, "state" : "FL" }
+{ "_id" : "32312", "city" : "TALLAHASSEE", "loc" : [ -84.262708, 30.518474 ], "pop" : 17743, "state" : "FL" }
+{ "_id" : "32320", "city" : "APALACHICOLA", "loc" : [ -85.006264, 29.725465 ], "pop" : 3859, "state" : "FL" }
+{ "_id" : "32321", "city" : "BRISTOL", "loc" : [ -84.946558, 30.422279 ], "pop" : 4078, "state" : "FL" }
+{ "_id" : "32322", "city" : "CARRABELLE", "loc" : [ -84.635845, 29.869205 ], "pop" : 2138, "state" : "FL" }
+{ "_id" : "32324", "city" : "CHATTAHOOCHEE", "loc" : [ -84.82804400000001, 30.683394 ], "pop" : 6325, "state" : "FL" }
+{ "_id" : "32327", "city" : "CRAWFORDVILLE", "loc" : [ -84.32047900000001, 30.210831 ], "pop" : 10004, "state" : "FL" }
+{ "_id" : "32328", "city" : "SAINT GEORGE ISL", "loc" : [ -84.87009999999999, 29.733906 ], "pop" : 2541, "state" : "FL" }
+{ "_id" : "32331", "city" : "GREENVILLE", "loc" : [ -83.647397, 30.451199 ], "pop" : 4107, "state" : "FL" }
+{ "_id" : "32333", "city" : "HAVANA", "loc" : [ -84.41434, 30.609242 ], "pop" : 9767, "state" : "FL" }
+{ "_id" : "32334", "city" : "HOSFORD", "loc" : [ -84.80543299999999, 30.363875 ], "pop" : 1491, "state" : "FL" }
+{ "_id" : "32336", "city" : "LAMONT", "loc" : [ -83.900266, 30.365341 ], "pop" : 1409, "state" : "FL" }
+{ "_id" : "32340", "city" : "MADISON", "loc" : [ -83.406678, 30.480209 ], "pop" : 11339, "state" : "FL" }
+{ "_id" : "32344", "city" : "MONTICELLO", "loc" : [ -83.892454, 30.519681 ], "pop" : 9578, "state" : "FL" }
+{ "_id" : "32346", "city" : "PANACEA", "loc" : [ -84.391212, 30.015322 ], "pop" : 1292, "state" : "FL" }
+{ "_id" : "32347", "city" : "PERRY", "loc" : [ -83.585021, 30.097489 ], "pop" : 15401, "state" : "FL" }
+{ "_id" : "32350", "city" : "PINETTA", "loc" : [ -83.340463, 30.599703 ], "pop" : 642, "state" : "FL" }
+{ "_id" : "32351", "city" : "QUINCY", "loc" : [ -84.60945, 30.586675 ], "pop" : 25013, "state" : "FL" }
+{ "_id" : "32356", "city" : "SALEM", "loc" : [ -83.385828, 29.823815 ], "pop" : 264, "state" : "FL" }
+{ "_id" : "32358", "city" : "SOPCHOPPY", "loc" : [ -84.454877, 30.071353 ], "pop" : 3335, "state" : "FL" }
+{ "_id" : "32359", "city" : "STEINHATCHEE", "loc" : [ -83.372332, 29.673871 ], "pop" : 1415, "state" : "FL" }
+{ "_id" : "32401", "city" : "PANAMA CITY", "loc" : [ -85.64940300000001, 30.160624 ], "pop" : 24968, "state" : "FL" }
+{ "_id" : "32403", "city" : "PANAMA CITY", "loc" : [ -85.57622499999999, 30.058252 ], "pop" : 5333, "state" : "FL" }
+{ "_id" : "32404", "city" : "PANAMA CITY", "loc" : [ -85.57626399999999, 30.165291 ], "pop" : 30101, "state" : "FL" }
+{ "_id" : "32405", "city" : "PANAMA CITY", "loc" : [ -85.672686, 30.194949 ], "pop" : 25701, "state" : "FL" }
+{ "_id" : "32407", "city" : "PANAMA CITY BEAC", "loc" : [ -85.791984, 30.194623 ], "pop" : 3115, "state" : "FL" }
+{ "_id" : "32408", "city" : "PANAMA CITY BEAC", "loc" : [ -85.763628, 30.160859 ], "pop" : 9702, "state" : "FL" }
+{ "_id" : "32409", "city" : "SOUTHPORT", "loc" : [ -85.644536, 30.310679 ], "pop" : 5001, "state" : "FL" }
+{ "_id" : "32413", "city" : "PANAMA CITY BEAC", "loc" : [ -85.904946, 30.245835 ], "pop" : 5646, "state" : "FL" }
+{ "_id" : "32420", "city" : "ALFORD", "loc" : [ -85.34838000000001, 30.714106 ], "pop" : 576, "state" : "FL" }
+{ "_id" : "32421", "city" : "ALTHA", "loc" : [ -85.17043, 30.531882 ], "pop" : 3280, "state" : "FL" }
+{ "_id" : "32423", "city" : "BASCOM", "loc" : [ -85.09721999999999, 30.951365 ], "pop" : 1011, "state" : "FL" }
+{ "_id" : "32424", "city" : "BLOUNTSTOWN", "loc" : [ -85.062022, 30.4394 ], "pop" : 6984, "state" : "FL" }
+{ "_id" : "32425", "city" : "BONIFAY", "loc" : [ -85.68996199999999, 30.846369 ], "pop" : 9342, "state" : "FL" }
+{ "_id" : "32426", "city" : "CAMPBELLTON", "loc" : [ -85.37659600000001, 30.95629 ], "pop" : 741, "state" : "FL" }
+{ "_id" : "32427", "city" : "CARYVILLE", "loc" : [ -85.79978699999999, 30.796878 ], "pop" : 2517, "state" : "FL" }
+{ "_id" : "32428", "city" : "CHIPLEY", "loc" : [ -85.54864600000001, 30.710658 ], "pop" : 11248, "state" : "FL" }
+{ "_id" : "32430", "city" : "CLARKSVILLE", "loc" : [ -85.189806, 30.356834 ], "pop" : 129, "state" : "FL" }
+{ "_id" : "32431", "city" : "COTTONDALE", "loc" : [ -85.38467199999999, 30.800359 ], "pop" : 3333, "state" : "FL" }
+{ "_id" : "32433", "city" : "DE FUNIAK SPRING", "loc" : [ -86.138006, 30.751783 ], "pop" : 15496, "state" : "FL" }
+{ "_id" : "32437", "city" : "EBRO", "loc" : [ -85.88806599999999, 30.435181 ], "pop" : 361, "state" : "FL" }
+{ "_id" : "32438", "city" : "FOUNTAIN", "loc" : [ -85.429272, 30.475327 ], "pop" : 1869, "state" : "FL" }
+{ "_id" : "32439", "city" : "FREEPORT", "loc" : [ -86.168441, 30.489596 ], "pop" : 744, "state" : "FL" }
+{ "_id" : "32440", "city" : "GRACEVILLE", "loc" : [ -85.513622, 30.942601 ], "pop" : 5353, "state" : "FL" }
+{ "_id" : "32442", "city" : "GRAND RIDGE", "loc" : [ -85.020954, 30.714831 ], "pop" : 1708, "state" : "FL" }
+{ "_id" : "32443", "city" : "GREENWOOD", "loc" : [ -85.15549, 30.852506 ], "pop" : 4058, "state" : "FL" }
+{ "_id" : "32444", "city" : "LYNN HAVEN", "loc" : [ -85.646658, 30.236165 ], "pop" : 12205, "state" : "FL" }
+{ "_id" : "32445", "city" : "MALONE", "loc" : [ -85.16387400000001, 30.960245 ], "pop" : 1046, "state" : "FL" }
+{ "_id" : "32446", "city" : "MARIANNA", "loc" : [ -85.229367, 30.758587 ], "pop" : 17908, "state" : "FL" }
+{ "_id" : "32449", "city" : "KINARD", "loc" : [ -85.206467, 30.263241 ], "pop" : 297, "state" : "FL" }
+{ "_id" : "32455", "city" : "PONCE DE LEON", "loc" : [ -85.954633, 30.704146 ], "pop" : 2200, "state" : "FL" }
+{ "_id" : "32456", "city" : "PORT SAINT JOE", "loc" : [ -85.298787, 29.83539 ], "pop" : 7490, "state" : "FL" }
+{ "_id" : "32459", "city" : "SANTA ROSA BEACH", "loc" : [ -86.24580899999999, 30.365883 ], "pop" : 5039, "state" : "FL" }
+{ "_id" : "32460", "city" : "SNEADS", "loc" : [ -84.933655, 30.727619 ], "pop" : 6334, "state" : "FL" }
+{ "_id" : "32462", "city" : "VERNON", "loc" : [ -85.755286, 30.62668 ], "pop" : 4111, "state" : "FL" }
+{ "_id" : "32464", "city" : "WESTVILLE", "loc" : [ -85.91297299999999, 30.874689 ], "pop" : 3081, "state" : "FL" }
+{ "_id" : "32465", "city" : "WEWAHITCHKA", "loc" : [ -85.20483, 30.093255 ], "pop" : 4014, "state" : "FL" }
+{ "_id" : "32466", "city" : "YOUNGSTOWN", "loc" : [ -85.516881, 30.326913 ], "pop" : 3634, "state" : "FL" }
+{ "_id" : "32501", "city" : "PENSACOLA", "loc" : [ -87.224763, 30.422282 ], "pop" : 16485, "state" : "FL" }
+{ "_id" : "32503", "city" : "PENSACOLA", "loc" : [ -87.210432, 30.456406 ], "pop" : 34491, "state" : "FL" }
+{ "_id" : "32504", "city" : "PENSACOLA", "loc" : [ -87.187242, 30.487299 ], "pop" : 23077, "state" : "FL" }
+{ "_id" : "32505", "city" : "PENSACOLA", "loc" : [ -87.258937, 30.448069 ], "pop" : 29026, "state" : "FL" }
+{ "_id" : "32506", "city" : "PENSACOLA", "loc" : [ -87.309185, 30.412912 ], "pop" : 29834, "state" : "FL" }
+{ "_id" : "32507", "city" : "PENSACOLA", "loc" : [ -87.312558, 30.373707 ], "pop" : 23525, "state" : "FL" }
+{ "_id" : "32508", "city" : "PENSACOLA", "loc" : [ -87.274945, 30.351063 ], "pop" : 3688, "state" : "FL" }
+{ "_id" : "32514", "city" : "PENSACOLA", "loc" : [ -87.216723, 30.524148 ], "pop" : 30185, "state" : "FL" }
+{ "_id" : "32526", "city" : "PENSACOLA", "loc" : [ -87.317925, 30.475593 ], "pop" : 28674, "state" : "FL" }
+{ "_id" : "32531", "city" : "BAKER", "loc" : [ -86.677015, 30.831569 ], "pop" : 3389, "state" : "FL" }
+{ "_id" : "32533", "city" : "CANTONMENT", "loc" : [ -87.325052, 30.614253 ], "pop" : 19829, "state" : "FL" }
+{ "_id" : "32534", "city" : "PENSACOLA", "loc" : [ -87.279324, 30.530065 ], "pop" : 12046, "state" : "FL" }
+{ "_id" : "32535", "city" : "CENTURY", "loc" : [ -87.32158200000001, 30.968742 ], "pop" : 5422, "state" : "FL" }
+{ "_id" : "32536", "city" : "CRESTVIEW", "loc" : [ -86.553678, 30.77061 ], "pop" : 21799, "state" : "FL" }
+{ "_id" : "32541", "city" : "SANDESTIN", "loc" : [ -86.484903, 30.397198 ], "pop" : 8080, "state" : "FL" }
+{ "_id" : "32542", "city" : "EGLIN A F B", "loc" : [ -86.61595800000001, 30.479409 ], "pop" : 13431, "state" : "FL" }
+{ "_id" : "32547", "city" : "FORT WALTON BEAC", "loc" : [ -86.627487, 30.447297 ], "pop" : 27344, "state" : "FL" }
+{ "_id" : "32548", "city" : "FORT WALTON BEAC", "loc" : [ -86.62147899999999, 30.415262 ], "pop" : 21791, "state" : "FL" }
+{ "_id" : "32561", "city" : "GULF BREEZE", "loc" : [ -87.043875, 30.3847 ], "pop" : 27875, "state" : "FL" }
+{ "_id" : "32564", "city" : "HOLT", "loc" : [ -86.704638, 30.72522 ], "pop" : 1821, "state" : "FL" }
+{ "_id" : "32565", "city" : "JAY", "loc" : [ -87.13323699999999, 30.898488 ], "pop" : 5952, "state" : "FL" }
+{ "_id" : "32566", "city" : "NAVARRE", "loc" : [ -86.937102, 30.590261 ], "pop" : 5537, "state" : "FL" }
+{ "_id" : "32567", "city" : "LAUREL HILL", "loc" : [ -86.400323, 30.95236 ], "pop" : 2967, "state" : "FL" }
+{ "_id" : "32568", "city" : "WALNUT HILL", "loc" : [ -87.449628, 30.870043 ], "pop" : 3604, "state" : "FL" }
+{ "_id" : "32569", "city" : "MARY ESTHER", "loc" : [ -86.71271900000001, 30.412186 ], "pop" : 9382, "state" : "FL" }
+{ "_id" : "32570", "city" : "MILTON", "loc" : [ -87.04727800000001, 30.660413 ], "pop" : 20038, "state" : "FL" }
+{ "_id" : "32571", "city" : "PACE", "loc" : [ -87.15033, 30.616173 ], "pop" : 15661, "state" : "FL" }
+{ "_id" : "32578", "city" : "NICEVILLE", "loc" : [ -86.41446000000001, 30.495771 ], "pop" : 25146, "state" : "FL" }
+{ "_id" : "32579", "city" : "SHALIMAR", "loc" : [ -86.571724, 30.445565 ], "pop" : 9327, "state" : "FL" }
+{ "_id" : "32580", "city" : "VALPARAISO", "loc" : [ -86.50091399999999, 30.509197 ], "pop" : 4964, "state" : "FL" }
+{ "_id" : "32583", "city" : "MILTON", "loc" : [ -87.066273, 30.576058 ], "pop" : 9457, "state" : "FL" }
+{ "_id" : "32601", "city" : "GAINESVILLE", "loc" : [ -82.310046, 29.645029 ], "pop" : 31328, "state" : "FL" }
+{ "_id" : "32603", "city" : "GAINESVILLE", "loc" : [ -82.34928600000001, 29.651484 ], "pop" : 5271, "state" : "FL" }
+{ "_id" : "32605", "city" : "GAINESVILLE", "loc" : [ -82.36794, 29.678458 ], "pop" : 21349, "state" : "FL" }
+{ "_id" : "32606", "city" : "GAINESVILLE", "loc" : [ -82.40232399999999, 29.695393 ], "pop" : 18408, "state" : "FL" }
+{ "_id" : "32607", "city" : "GAINESVILLE", "loc" : [ -82.40325199999999, 29.645618 ], "pop" : 21103, "state" : "FL" }
+{ "_id" : "32608", "city" : "GAINESVILLE", "loc" : [ -82.387282, 29.613204 ], "pop" : 22945, "state" : "FL" }
+{ "_id" : "32609", "city" : "GAINESVILLE", "loc" : [ -82.308032, 29.70053 ], "pop" : 17668, "state" : "FL" }
+{ "_id" : "32611", "city" : "GAINESVILLE", "loc" : [ -82.35092, 29.644148 ], "pop" : 8023, "state" : "FL" }
+{ "_id" : "32615", "city" : "SANTA FE", "loc" : [ -82.480531, 29.796996 ], "pop" : 9414, "state" : "FL" }
+{ "_id" : "32617", "city" : "ANTHONY", "loc" : [ -82.12615700000001, 29.304785 ], "pop" : 6296, "state" : "FL" }
+{ "_id" : "32618", "city" : "ARCHER", "loc" : [ -82.51084, 29.559738 ], "pop" : 6188, "state" : "FL" }
+{ "_id" : "32619", "city" : "BELL", "loc" : [ -82.871106, 29.78373 ], "pop" : 2446, "state" : "FL" }
+{ "_id" : "32621", "city" : "BRONSON", "loc" : [ -82.635644, 29.460952 ], "pop" : 2111, "state" : "FL" }
+{ "_id" : "32622", "city" : "BROOKER", "loc" : [ -82.29563400000001, 29.919028 ], "pop" : 1194, "state" : "FL" }
+{ "_id" : "32625", "city" : "CEDAR KEY", "loc" : [ -83.01679300000001, 29.171006 ], "pop" : 1173, "state" : "FL" }
+{ "_id" : "32626", "city" : "CHIEFLAND", "loc" : [ -82.88089600000001, 29.483243 ], "pop" : 7498, "state" : "FL" }
+{ "_id" : "32631", "city" : "EARLETON", "loc" : [ -82.11376199999999, 29.722159 ], "pop" : 1014, "state" : "FL" }
+{ "_id" : "32640", "city" : "HAWTHORNE", "loc" : [ -82.105625, 29.573998 ], "pop" : 4151, "state" : "FL" }
+{ "_id" : "32643", "city" : "HIGH SPRINGS", "loc" : [ -82.615628, 29.841022 ], "pop" : 7557, "state" : "FL" }
+{ "_id" : "32648", "city" : "HORSESHOE BEACH", "loc" : [ -83.26158700000001, 29.48689 ], "pop" : 652, "state" : "FL" }
+{ "_id" : "32656", "city" : "KEYSTONE HEIGHTS", "loc" : [ -81.989885, 29.797579 ], "pop" : 8011, "state" : "FL" }
+{ "_id" : "32666", "city" : "MELROSE", "loc" : [ -82.027863, 29.732456 ], "pop" : 5507, "state" : "FL" }
+{ "_id" : "32667", "city" : "MICANOPY", "loc" : [ -82.279698, 29.526029 ], "pop" : 2409, "state" : "FL" }
+{ "_id" : "32668", "city" : "MORRISTON", "loc" : [ -82.491668, 29.28126 ], "pop" : 2054, "state" : "FL" }
+{ "_id" : "32669", "city" : "NEWBERRY", "loc" : [ -82.585188, 29.660906 ], "pop" : 5491, "state" : "FL" }
+{ "_id" : "32680", "city" : "OLD TOWN", "loc" : [ -83.057393, 29.624558 ], "pop" : 9494, "state" : "FL" }
+{ "_id" : "32686", "city" : "REDDICK", "loc" : [ -82.243995, 29.375352 ], "pop" : 10006, "state" : "FL" }
+{ "_id" : "32693", "city" : "TRENTON", "loc" : [ -82.80934499999999, 29.626375 ], "pop" : 6925, "state" : "FL" }
+{ "_id" : "32694", "city" : "WALDO", "loc" : [ -82.160791, 29.787096 ], "pop" : 1676, "state" : "FL" }
+{ "_id" : "32696", "city" : "WILLISTON", "loc" : [ -82.485601, 29.397737 ], "pop" : 7664, "state" : "FL" }
+{ "_id" : "32701", "city" : "ALTAMONTE SPRING", "loc" : [ -81.371908, 28.662728 ], "pop" : 21392, "state" : "FL" }
+{ "_id" : "32702", "city" : "ALTOONA", "loc" : [ -81.632322, 29.021935 ], "pop" : 1743, "state" : "FL" }
+{ "_id" : "32703", "city" : "HUNT CLUB", "loc" : [ -81.48514900000001, 28.661865 ], "pop" : 34100, "state" : "FL" }
+{ "_id" : "32707", "city" : "CASSELBERRY", "loc" : [ -81.31221499999999, 28.661671 ], "pop" : 30933, "state" : "FL" }
+{ "_id" : "32708", "city" : "WINTER SPRINGS", "loc" : [ -81.281367, 28.683097 ], "pop" : 27311, "state" : "FL" }
+{ "_id" : "32709", "city" : "CHRISTMAS", "loc" : [ -81.01157000000001, 28.546244 ], "pop" : 2331, "state" : "FL" }
+{ "_id" : "32712", "city" : "APOPKA", "loc" : [ -81.513615, 28.711976 ], "pop" : 20208, "state" : "FL" }
+{ "_id" : "32713", "city" : "DEBARY", "loc" : [ -81.306506, 28.884573 ], "pop" : 9491, "state" : "FL" }
+{ "_id" : "32714", "city" : "FOREST CITY", "loc" : [ -81.40853300000001, 28.664983 ], "pop" : 29133, "state" : "FL" }
+{ "_id" : "32720", "city" : "DELAND", "loc" : [ -81.334853, 29.02659 ], "pop" : 23152, "state" : "FL" }
+{ "_id" : "32724", "city" : "DELAND", "loc" : [ -81.28634099999999, 29.04225 ], "pop" : 21715, "state" : "FL" }
+{ "_id" : "32725", "city" : "DELTONA", "loc" : [ -81.24730700000001, 28.898897 ], "pop" : 27678, "state" : "FL" }
+{ "_id" : "32726", "city" : "EUSTIS", "loc" : [ -81.64512999999999, 28.857686 ], "pop" : 19585, "state" : "FL" }
+{ "_id" : "32730", "city" : "FERN PARK", "loc" : [ -81.341837, 28.651161 ], "pop" : 4815, "state" : "FL" }
+{ "_id" : "32732", "city" : "GENEVA", "loc" : [ -81.11136999999999, 28.750299 ], "pop" : 3827, "state" : "FL" }
+{ "_id" : "32735", "city" : "GRAND ISLAND", "loc" : [ -81.739093, 28.886552 ], "pop" : 1416, "state" : "FL" }
+{ "_id" : "32738", "city" : "DELTONA", "loc" : [ -81.192171, 28.909311 ], "pop" : 22426, "state" : "FL" }
+{ "_id" : "32744", "city" : "LAKE HELEN", "loc" : [ -81.233367, 28.980567 ], "pop" : 3229, "state" : "FL" }
+{ "_id" : "32746", "city" : "HEATHROW", "loc" : [ -81.338075, 28.752352 ], "pop" : 9959, "state" : "FL" }
+{ "_id" : "32750", "city" : "LONGWOOD", "loc" : [ -81.355238, 28.711994 ], "pop" : 27633, "state" : "FL" }
+{ "_id" : "32751", "city" : "EATONVILLE", "loc" : [ -81.354598, 28.631284 ], "pop" : 19834, "state" : "FL" }
+{ "_id" : "32754", "city" : "MIMS", "loc" : [ -80.86627799999999, 28.697383 ], "pop" : 8943, "state" : "FL" }
+{ "_id" : "32757", "city" : "MOUNT DORA", "loc" : [ -81.64559300000001, 28.792787 ], "pop" : 15757, "state" : "FL" }
+{ "_id" : "32759", "city" : "OAK HILL", "loc" : [ -80.855063, 28.869985 ], "pop" : 2261, "state" : "FL" }
+{ "_id" : "32763", "city" : "ORANGE CITY", "loc" : [ -81.29952400000001, 28.945291 ], "pop" : 12946, "state" : "FL" }
+{ "_id" : "32764", "city" : "OSTEEN", "loc" : [ -81.15622399999999, 28.842617 ], "pop" : 2215, "state" : "FL" }
+{ "_id" : "32765", "city" : "OVIEDO", "loc" : [ -81.206593, 28.651256 ], "pop" : 19519, "state" : "FL" }
+{ "_id" : "32766", "city" : "CHULUOTA", "loc" : [ -81.11823699999999, 28.640634 ], "pop" : 3280, "state" : "FL" }
+{ "_id" : "32767", "city" : "PAISLEY", "loc" : [ -81.50300900000001, 28.999323 ], "pop" : 1963, "state" : "FL" }
+{ "_id" : "32771", "city" : "SANFORD", "loc" : [ -81.285044, 28.801307 ], "pop" : 27016, "state" : "FL" }
+{ "_id" : "32773", "city" : "SANFORD", "loc" : [ -81.282042, 28.764385 ], "pop" : 19707, "state" : "FL" }
+{ "_id" : "32776", "city" : "SORRENTO", "loc" : [ -81.53231700000001, 28.803519 ], "pop" : 5382, "state" : "FL" }
+{ "_id" : "32778", "city" : "TAVARES", "loc" : [ -81.73405, 28.801027 ], "pop" : 12131, "state" : "FL" }
+{ "_id" : "32779", "city" : "SPRINGS PLAZA", "loc" : [ -81.42276699999999, 28.703978 ], "pop" : 27075, "state" : "FL" }
+{ "_id" : "32780", "city" : "TITUSVILLE", "loc" : [ -80.819141, 28.569712 ], "pop" : 28649, "state" : "FL" }
+{ "_id" : "32784", "city" : "DONA VISTA", "loc" : [ -81.67165300000001, 28.931443 ], "pop" : 7866, "state" : "FL" }
+{ "_id" : "32789", "city" : "WINTER PARK", "loc" : [ -81.353436, 28.597824 ], "pop" : 24236, "state" : "FL" }
+{ "_id" : "32792", "city" : "ALOMA", "loc" : [ -81.30211199999999, 28.60779 ], "pop" : 44973, "state" : "FL" }
+{ "_id" : "32796", "city" : "TITUSVILLE", "loc" : [ -80.842915, 28.627078 ], "pop" : 19916, "state" : "FL" }
+{ "_id" : "32798", "city" : "ZELLWOOD", "loc" : [ -81.57617399999999, 28.71944 ], "pop" : 1930, "state" : "FL" }
+{ "_id" : "32801", "city" : "ORLANDO", "loc" : [ -81.372668, 28.539882 ], "pop" : 9275, "state" : "FL" }
+{ "_id" : "32803", "city" : "ORLANDO", "loc" : [ -81.35346199999999, 28.555897 ], "pop" : 19992, "state" : "FL" }
+{ "_id" : "32804", "city" : "FAIRVILLA", "loc" : [ -81.391955, 28.576547 ], "pop" : 18087, "state" : "FL" }
+{ "_id" : "32805", "city" : "ORLANDO", "loc" : [ -81.404516, 28.5302 ], "pop" : 29117, "state" : "FL" }
+{ "_id" : "32806", "city" : "ORLANDO", "loc" : [ -81.35696799999999, 28.513958 ], "pop" : 25996, "state" : "FL" }
+{ "_id" : "32807", "city" : "AZALEA PARK", "loc" : [ -81.305274, 28.544924 ], "pop" : 28087, "state" : "FL" }
+{ "_id" : "32808", "city" : "PINE HILLS", "loc" : [ -81.44758, 28.580463 ], "pop" : 42278, "state" : "FL" }
+{ "_id" : "32809", "city" : "PINE CASTLE", "loc" : [ -81.38175099999999, 28.461916 ], "pop" : 17602, "state" : "FL" }
+{ "_id" : "32810", "city" : "LOCKHART", "loc" : [ -81.42585200000001, 28.622183 ], "pop" : 23781, "state" : "FL" }
+{ "_id" : "32811", "city" : "ORLO VISTA", "loc" : [ -81.442014, 28.516082 ], "pop" : 21545, "state" : "FL" }
+{ "_id" : "32812", "city" : "ORLANDO", "loc" : [ -81.328816, 28.49981 ], "pop" : 26888, "state" : "FL" }
+{ "_id" : "32813", "city" : "NAVAL TRAINING C", "loc" : [ -81.32896599999999, 28.570467 ], "pop" : 9216, "state" : "FL" }
+{ "_id" : "32815", "city" : "KENNEDY SPACE CE", "loc" : [ -80.58248, 28.498821 ], "pop" : 1, "state" : "FL" }
+{ "_id" : "32817", "city" : "UNION PARK", "loc" : [ -81.25353699999999, 28.590251 ], "pop" : 20723, "state" : "FL" }
+{ "_id" : "32818", "city" : "ORLANDO", "loc" : [ -81.484618, 28.580147 ], "pop" : 26887, "state" : "FL" }
+{ "_id" : "32819", "city" : "SAND LAKE", "loc" : [ -81.452484, 28.467258 ], "pop" : 4434, "state" : "FL" }
+{ "_id" : "32820", "city" : "UNION PARK", "loc" : [ -81.11062800000001, 28.578256 ], "pop" : 2587, "state" : "FL" }
+{ "_id" : "32821", "city" : "ORLANDO", "loc" : [ -81.46660199999999, 28.395724 ], "pop" : 9982, "state" : "FL" }
+{ "_id" : "32822", "city" : "VENTURA", "loc" : [ -81.293874, 28.504765 ], "pop" : 33986, "state" : "FL" }
+{ "_id" : "32824", "city" : "ORLANDO", "loc" : [ -81.36218700000001, 28.393157 ], "pop" : 8225, "state" : "FL" }
+{ "_id" : "32825", "city" : "ORLANDO", "loc" : [ -81.257081, 28.546865 ], "pop" : 26373, "state" : "FL" }
+{ "_id" : "32826", "city" : "ORLANDO", "loc" : [ -81.19070499999999, 28.582601 ], "pop" : 12369, "state" : "FL" }
+{ "_id" : "32827", "city" : "ORLANDO", "loc" : [ -81.342979, 28.43168 ], "pop" : 3831, "state" : "FL" }
+{ "_id" : "32828", "city" : "ORLANDO", "loc" : [ -81.179489, 28.552297 ], "pop" : 3249, "state" : "FL" }
+{ "_id" : "32829", "city" : "ORLANDO", "loc" : [ -81.260778, 28.484877 ], "pop" : 3848, "state" : "FL" }
+{ "_id" : "32830", "city" : "LAKE BUENA VISTA", "loc" : [ -81.519034, 28.369378 ], "pop" : 6, "state" : "FL" }
+{ "_id" : "32831", "city" : "ORLANDO", "loc" : [ -81.191768, 28.488229 ], "pop" : 1123, "state" : "FL" }
+{ "_id" : "32832", "city" : "ORLANDO", "loc" : [ -81.188807, 28.377428 ], "pop" : 1863, "state" : "FL" }
+{ "_id" : "32833", "city" : "UNION PARK", "loc" : [ -81.098129, 28.531797 ], "pop" : 3748, "state" : "FL" }
+{ "_id" : "32835", "city" : "ORLANDO", "loc" : [ -81.478663, 28.528885 ], "pop" : 20343, "state" : "FL" }
+{ "_id" : "32836", "city" : "ORLANDO", "loc" : [ -81.49563999999999, 28.460842 ], "pop" : 21329, "state" : "FL" }
+{ "_id" : "32837", "city" : "ORLANDO", "loc" : [ -81.41788200000001, 28.394861 ], "pop" : 13075, "state" : "FL" }
+{ "_id" : "32839", "city" : "ORLANDO", "loc" : [ -81.408162, 28.487102 ], "pop" : 33946, "state" : "FL" }
+{ "_id" : "32901", "city" : "MELBOURNE", "loc" : [ -80.620015, 28.069132 ], "pop" : 21138, "state" : "FL" }
+{ "_id" : "32903", "city" : "INDIALANTIC", "loc" : [ -80.57871799999999, 28.109059 ], "pop" : 11020, "state" : "FL" }
+{ "_id" : "32904", "city" : "MELBOURNE VILLAG", "loc" : [ -80.668577, 28.073177 ], "pop" : 15441, "state" : "FL" }
+{ "_id" : "32905", "city" : "PALM BAY", "loc" : [ -80.599087, 28.014605 ], "pop" : 26367, "state" : "FL" }
+{ "_id" : "32907", "city" : "PALM BAY", "loc" : [ -80.673889, 28.016849 ], "pop" : 25674, "state" : "FL" }
+{ "_id" : "32908", "city" : "PALM BAY", "loc" : [ -80.689426, 27.981636 ], "pop" : 3272, "state" : "FL" }
+{ "_id" : "32909", "city" : "PALM BAY", "loc" : [ -80.647327, 27.96936 ], "pop" : 12028, "state" : "FL" }
+{ "_id" : "32920", "city" : "CAPE CANAVERAL", "loc" : [ -80.60426699999999, 28.39034 ], "pop" : 7655, "state" : "FL" }
+{ "_id" : "32922", "city" : "COCOA", "loc" : [ -80.746455, 28.367183 ], "pop" : 17316, "state" : "FL" }
+{ "_id" : "32925", "city" : "PATRICK A F B", "loc" : [ -80.60712599999999, 28.259896 ], "pop" : 597, "state" : "FL" }
+{ "_id" : "32926", "city" : "COCOA", "loc" : [ -80.786969, 28.390987 ], "pop" : 17930, "state" : "FL" }
+{ "_id" : "32927", "city" : "PORT SAINT JOHN", "loc" : [ -80.79111399999999, 28.46844 ], "pop" : 17351, "state" : "FL" }
+{ "_id" : "32931", "city" : "COCOA BEACH", "loc" : [ -80.612066, 28.332451 ], "pop" : 14989, "state" : "FL" }
+{ "_id" : "32934", "city" : "EAU GALLIE", "loc" : [ -80.691683, 28.136822 ], "pop" : 9539, "state" : "FL" }
+{ "_id" : "32935", "city" : "MELBOURNE", "loc" : [ -80.65235300000001, 28.138385 ], "pop" : 34153, "state" : "FL" }
+{ "_id" : "32937", "city" : "INDIAN HARBOR BE", "loc" : [ -80.598671, 28.178571 ], "pop" : 28921, "state" : "FL" }
+{ "_id" : "32940", "city" : "MELBOURNE", "loc" : [ -80.68495900000001, 28.206136 ], "pop" : 5360, "state" : "FL" }
+{ "_id" : "32948", "city" : "FELLSMERE", "loc" : [ -80.601947, 27.764273 ], "pop" : 2936, "state" : "FL" }
+{ "_id" : "32951", "city" : "MELBOURNE BEACH", "loc" : [ -80.53893600000001, 28.021923 ], "pop" : 8060, "state" : "FL" }
+{ "_id" : "32952", "city" : "MERRITT ISLAND", "loc" : [ -80.67818, 28.328607 ], "pop" : 12919, "state" : "FL" }
+{ "_id" : "32953", "city" : "MERRITT ISLAND", "loc" : [ -80.695865, 28.391234 ], "pop" : 23338, "state" : "FL" }
+{ "_id" : "32955", "city" : "ROCKLEDGE", "loc" : [ -80.73193000000001, 28.313441 ], "pop" : 20576, "state" : "FL" }
+{ "_id" : "32958", "city" : "SEBASTIAN", "loc" : [ -80.478432, 27.790082 ], "pop" : 14084, "state" : "FL" }
+{ "_id" : "32960", "city" : "VERO BEACH", "loc" : [ -80.403075, 27.632985 ], "pop" : 19207, "state" : "FL" }
+{ "_id" : "32962", "city" : "VERO BEACH", "loc" : [ -80.392251, 27.588486 ], "pop" : 17462, "state" : "FL" }
+{ "_id" : "32963", "city" : "INDIAN RIVER SHO", "loc" : [ -80.360916, 27.653623 ], "pop" : 10980, "state" : "FL" }
+{ "_id" : "32966", "city" : "VERO BEACH", "loc" : [ -80.47939, 27.637214 ], "pop" : 10687, "state" : "FL" }
+{ "_id" : "32967", "city" : "VERO BEACH", "loc" : [ -80.44161699999999, 27.697223 ], "pop" : 9607, "state" : "FL" }
+{ "_id" : "32968", "city" : "VERO BEACH", "loc" : [ -80.43822299999999, 27.59993 ], "pop" : 5238, "state" : "FL" }
+{ "_id" : "32976", "city" : "BAREFOOT BAY", "loc" : [ -80.516051, 27.878146 ], "pop" : 7870, "state" : "FL" }
+{ "_id" : "33004", "city" : "DANIA", "loc" : [ -80.144728, 26.047557 ], "pop" : 12552, "state" : "FL" }
+{ "_id" : "33009", "city" : "HALLANDALE", "loc" : [ -80.140737, 25.985019 ], "pop" : 33743, "state" : "FL" }
+{ "_id" : "33010", "city" : "HIALEAH", "loc" : [ -80.280801, 25.832536 ], "pop" : 40437, "state" : "FL" }
+{ "_id" : "33012", "city" : "HIALEAH", "loc" : [ -80.30589999999999, 25.865395 ], "pop" : 73194, "state" : "FL" }
+{ "_id" : "33013", "city" : "HIALEAH", "loc" : [ -80.272533, 25.859351 ], "pop" : 30108, "state" : "FL" }
+{ "_id" : "33014", "city" : "HIALEAH", "loc" : [ -80.30625499999999, 25.896349 ], "pop" : 35873, "state" : "FL" }
+{ "_id" : "33015", "city" : "HIALEAH", "loc" : [ -80.316545, 25.938841 ], "pop" : 31171, "state" : "FL" }
+{ "_id" : "33016", "city" : "HIALEAH", "loc" : [ -80.33681, 25.880262 ], "pop" : 32053, "state" : "FL" }
+{ "_id" : "33019", "city" : "HOLLYWOOD", "loc" : [ -80.121931, 26.007011 ], "pop" : 12115, "state" : "FL" }
+{ "_id" : "33020", "city" : "HOLLYWOOD", "loc" : [ -80.15166000000001, 26.016091 ], "pop" : 35468, "state" : "FL" }
+{ "_id" : "33021", "city" : "HOLLYWOOD", "loc" : [ -80.18908500000001, 26.021836 ], "pop" : 39987, "state" : "FL" }
+{ "_id" : "33023", "city" : "MIRAMAR", "loc" : [ -80.21603500000001, 25.987516 ], "pop" : 54274, "state" : "FL" }
+{ "_id" : "33024", "city" : "PEMBROKE PINES", "loc" : [ -80.240183, 26.024273 ], "pop" : 54411, "state" : "FL" }
+{ "_id" : "33025", "city" : "HOLLYWOOD", "loc" : [ -80.271236, 25.992061 ], "pop" : 24778, "state" : "FL" }
+{ "_id" : "33026", "city" : "HOLLYWOOD", "loc" : [ -80.29744100000001, 26.022927 ], "pop" : 21473, "state" : "FL" }
+{ "_id" : "33027", "city" : "HOLLYWOOD", "loc" : [ -80.32483999999999, 25.997449 ], "pop" : 6955, "state" : "FL" }
+{ "_id" : "33028", "city" : "HOLLYWOOD", "loc" : [ -80.330797, 26.024804 ], "pop" : 186, "state" : "FL" }
+{ "_id" : "33029", "city" : "PEMBROKE PINES", "loc" : [ -80.42840700000001, 26.01375 ], "pop" : 2882, "state" : "FL" }
+{ "_id" : "33030", "city" : "HOMESTEAD", "loc" : [ -80.483853, 25.476639 ], "pop" : 26721, "state" : "FL" }
+{ "_id" : "33031", "city" : "HOMESTEAD", "loc" : [ -80.507463, 25.532314 ], "pop" : 5880, "state" : "FL" }
+{ "_id" : "33032", "city" : "PRINCETON", "loc" : [ -80.40918000000001, 25.521191 ], "pop" : 18070, "state" : "FL" }
+{ "_id" : "33033", "city" : "HOMESTEAD", "loc" : [ -80.438014, 25.490576 ], "pop" : 25439, "state" : "FL" }
+{ "_id" : "33034", "city" : "FLORIDA CITY", "loc" : [ -80.548438, 25.396332 ], "pop" : 12115, "state" : "FL" }
+{ "_id" : "33035", "city" : "HOMESTEAD", "loc" : [ -80.45715300000001, 25.457338 ], "pop" : 1727, "state" : "FL" }
+{ "_id" : "33036", "city" : "ISLAMORADA", "loc" : [ -80.629953, 24.923331 ], "pop" : 3810, "state" : "FL" }
+{ "_id" : "33037", "city" : "OCEAN REEF", "loc" : [ -80.40608400000001, 25.140214 ], "pop" : 12076, "state" : "FL" }
+{ "_id" : "33039", "city" : "HOMESTEAD AIR FO", "loc" : [ -80.390513, 25.499088 ], "pop" : 6538, "state" : "FL" }
+{ "_id" : "33040", "city" : "NAVAL AIR STATIO", "loc" : [ -81.762179, 24.565313 ], "pop" : 32986, "state" : "FL" }
+{ "_id" : "33042", "city" : "SUMMERLAND KEY", "loc" : [ -81.49356400000001, 24.655322 ], "pop" : 3952, "state" : "FL" }
+{ "_id" : "33043", "city" : "BIG PINE KEY", "loc" : [ -81.36202900000001, 24.679996 ], "pop" : 5956, "state" : "FL" }
+{ "_id" : "33050", "city" : "MARATHON", "loc" : [ -81.03858099999999, 24.727919 ], "pop" : 12792, "state" : "FL" }
+{ "_id" : "33054", "city" : "OPA LOCKA", "loc" : [ -80.247004, 25.909662 ], "pop" : 30405, "state" : "FL" }
+{ "_id" : "33055", "city" : "CAROL CITY", "loc" : [ -80.27729100000001, 25.944076 ], "pop" : 40586, "state" : "FL" }
+{ "_id" : "33056", "city" : "CAROL CITY", "loc" : [ -80.248059, 25.946906 ], "pop" : 31968, "state" : "FL" }
+{ "_id" : "33060", "city" : "POMPANO BEACH", "loc" : [ -80.12345999999999, 26.231529 ], "pop" : 32292, "state" : "FL" }
+{ "_id" : "33062", "city" : "POMPANO BEACH", "loc" : [ -80.094133, 26.234314 ], "pop" : 20836, "state" : "FL" }
+{ "_id" : "33063", "city" : "MARGATE", "loc" : [ -80.211483, 26.249221 ], "pop" : 37607, "state" : "FL" }
+{ "_id" : "33064", "city" : "LIGHTHOUSE POINT", "loc" : [ -80.11243899999999, 26.278698 ], "pop" : 50084, "state" : "FL" }
+{ "_id" : "33065", "city" : "CORAL SPRINGS", "loc" : [ -80.255578, 26.271403 ], "pop" : 43659, "state" : "FL" }
+{ "_id" : "33066", "city" : "MARGATE", "loc" : [ -80.17787800000001, 26.254237 ], "pop" : 16494, "state" : "FL" }
+{ "_id" : "33067", "city" : "NORTH CORAL SPRI", "loc" : [ -80.22188, 26.305134 ], "pop" : 7227, "state" : "FL" }
+{ "_id" : "33068", "city" : "POMPANO BEACH", "loc" : [ -80.22054, 26.216021 ], "pop" : 41835, "state" : "FL" }
+{ "_id" : "33069", "city" : "POMPANO BEACH", "loc" : [ -80.16348600000001, 26.228817 ], "pop" : 20158, "state" : "FL" }
+{ "_id" : "33070", "city" : "TAVERNIER", "loc" : [ -80.521816, 25.010788 ], "pop" : 6196, "state" : "FL" }
+{ "_id" : "33071", "city" : "POMPANO BEACH", "loc" : [ -80.260085, 26.243515 ], "pop" : 28251, "state" : "FL" }
+{ "_id" : "33073", "city" : "POMPANO BEACH", "loc" : [ -80.180966, 26.299693 ], "pop" : 7091, "state" : "FL" }
+{ "_id" : "33076", "city" : "POMPANO BEACH", "loc" : [ -80.248086, 26.291902 ], "pop" : 4728, "state" : "FL" }
+{ "_id" : "33122", "city" : "MIAMI", "loc" : [ -80.320733, 25.7911 ], "pop" : 8, "state" : "FL" }
+{ "_id" : "33125", "city" : "MIAMI", "loc" : [ -80.234118, 25.782547 ], "pop" : 47761, "state" : "FL" }
+{ "_id" : "33126", "city" : "MIAMI", "loc" : [ -80.291932, 25.776255 ], "pop" : 39861, "state" : "FL" }
+{ "_id" : "33127", "city" : "MIAMI", "loc" : [ -80.20512100000001, 25.814344 ], "pop" : 29900, "state" : "FL" }
+{ "_id" : "33128", "city" : "MIAMI", "loc" : [ -80.20885800000001, 25.775612 ], "pop" : 6965, "state" : "FL" }
+{ "_id" : "33129", "city" : "MIAMI", "loc" : [ -80.201301, 25.755926 ], "pop" : 10225, "state" : "FL" }
+{ "_id" : "33130", "city" : "MIAMI", "loc" : [ -80.205888, 25.767197 ], "pop" : 21777, "state" : "FL" }
+{ "_id" : "33131", "city" : "MIAMI", "loc" : [ -80.18950599999999, 25.762852 ], "pop" : 2614, "state" : "FL" }
+{ "_id" : "33132", "city" : "MIAMI", "loc" : [ -80.179996, 25.786712 ], "pop" : 5198, "state" : "FL" }
+{ "_id" : "33133", "city" : "CORAL GABLES", "loc" : [ -80.243639, 25.732251 ], "pop" : 28672, "state" : "FL" }
+{ "_id" : "33134", "city" : "CORAL GABLES", "loc" : [ -80.269576, 25.755582 ], "pop" : 33492, "state" : "FL" }
+{ "_id" : "33135", "city" : "MIAMI", "loc" : [ -80.231746, 25.766391 ], "pop" : 35425, "state" : "FL" }
+{ "_id" : "33136", "city" : "MIAMI", "loc" : [ -80.204232, 25.786385 ], "pop" : 14040, "state" : "FL" }
+{ "_id" : "33137", "city" : "MIAMI", "loc" : [ -80.189663, 25.815648 ], "pop" : 19862, "state" : "FL" }
+{ "_id" : "33138", "city" : "MIAMI SHORES", "loc" : [ -80.18526, 25.850208 ], "pop" : 30108, "state" : "FL" }
+{ "_id" : "33139", "city" : "CARL FISHER", "loc" : [ -80.13637799999999, 25.785179 ], "pop" : 48971, "state" : "FL" }
+{ "_id" : "33140", "city" : "MIAMI", "loc" : [ -80.127921, 25.819505 ], "pop" : 13057, "state" : "FL" }
+{ "_id" : "33141", "city" : "NORTH BAY VILLAG", "loc" : [ -80.133578, 25.852384 ], "pop" : 29489, "state" : "FL" }
+{ "_id" : "33142", "city" : "MIAMI", "loc" : [ -80.232023, 25.812966 ], "pop" : 52262, "state" : "FL" }
+{ "_id" : "33143", "city" : "SOUTH MIAMI", "loc" : [ -80.301408, 25.700252 ], "pop" : 28410, "state" : "FL" }
+{ "_id" : "33144", "city" : "MIAMI", "loc" : [ -80.309631, 25.762563 ], "pop" : 22968, "state" : "FL" }
+{ "_id" : "33145", "city" : "CORAL GABLES", "loc" : [ -80.235134, 25.752648 ], "pop" : 28170, "state" : "FL" }
+{ "_id" : "33146", "city" : "CORAL GABLES", "loc" : [ -80.274649, 25.720089 ], "pop" : 13791, "state" : "FL" }
+{ "_id" : "33147", "city" : "MIAMI", "loc" : [ -80.236558, 25.850675 ], "pop" : 49395, "state" : "FL" }
+{ "_id" : "33149", "city" : "KEY BISCAYNE", "loc" : [ -80.162475, 25.692104 ], "pop" : 8854, "state" : "FL" }
+{ "_id" : "33150", "city" : "MIAMI", "loc" : [ -80.206968, 25.851214 ], "pop" : 28408, "state" : "FL" }
+{ "_id" : "33154", "city" : "BAL HARBOUR", "loc" : [ -80.127055, 25.879094 ], "pop" : 17312, "state" : "FL" }
+{ "_id" : "33155", "city" : "MIAMI", "loc" : [ -80.31032, 25.7392 ], "pop" : 42864, "state" : "FL" }
+{ "_id" : "33156", "city" : "KENDALL", "loc" : [ -80.30853500000001, 25.66767 ], "pop" : 27901, "state" : "FL" }
+{ "_id" : "33157", "city" : "PERRINE", "loc" : [ -80.352473, 25.604384 ], "pop" : 57749, "state" : "FL" }
+{ "_id" : "33158", "city" : "MIAMI", "loc" : [ -80.318703, 25.636433 ], "pop" : 6037, "state" : "FL" }
+{ "_id" : "33160", "city" : "NORTH MIAMI BEAC", "loc" : [ -80.135141, 25.936086 ], "pop" : 26987, "state" : "FL" }
+{ "_id" : "33161", "city" : "NORTH MIAMI", "loc" : [ -80.182034, 25.893806 ], "pop" : 44800, "state" : "FL" }
+{ "_id" : "33162", "city" : "NORTH MIAMI BEAC", "loc" : [ -80.177238, 25.92807 ], "pop" : 37052, "state" : "FL" }
+{ "_id" : "33165", "city" : "OLYMPIA HEIGHTS", "loc" : [ -80.359084, 25.735353 ], "pop" : 56064, "state" : "FL" }
+{ "_id" : "33166", "city" : "MIAMI SPRINGS", "loc" : [ -80.29902, 25.817473 ], "pop" : 21066, "state" : "FL" }
+{ "_id" : "33167", "city" : "MIAMI", "loc" : [ -80.229168, 25.885605 ], "pop" : 18840, "state" : "FL" }
+{ "_id" : "33168", "city" : "MIAMI", "loc" : [ -80.210106, 25.890232 ], "pop" : 21629, "state" : "FL" }
+{ "_id" : "33169", "city" : "MIAMI", "loc" : [ -80.21436, 25.944083 ], "pop" : 30294, "state" : "FL" }
+{ "_id" : "33170", "city" : "QUAIL HEIGHTS", "loc" : [ -80.3981, 25.558847 ], "pop" : 6842, "state" : "FL" }
+{ "_id" : "33172", "city" : "MIAMI", "loc" : [ -80.357232, 25.773523 ], "pop" : 29823, "state" : "FL" }
+{ "_id" : "33173", "city" : "MIAMI", "loc" : [ -80.361824, 25.699242 ], "pop" : 33787, "state" : "FL" }
+{ "_id" : "33174", "city" : "MIAMI", "loc" : [ -80.36112799999999, 25.762779 ], "pop" : 27442, "state" : "FL" }
+{ "_id" : "33175", "city" : "OLYMPIA HEIGHTS", "loc" : [ -80.408226, 25.733677 ], "pop" : 41712, "state" : "FL" }
+{ "_id" : "33176", "city" : "MIAMI", "loc" : [ -80.362667, 25.657449 ], "pop" : 47435, "state" : "FL" }
+{ "_id" : "33177", "city" : "QUAIL HEIGHTS", "loc" : [ -80.39377, 25.593255 ], "pop" : 25043, "state" : "FL" }
+{ "_id" : "33178", "city" : "MIAMI", "loc" : [ -80.35492499999999, 25.814079 ], "pop" : 3146, "state" : "FL" }
+{ "_id" : "33179", "city" : "MIAMI", "loc" : [ -80.181382, 25.957095 ], "pop" : 31877, "state" : "FL" }
+{ "_id" : "33180", "city" : "OJUS", "loc" : [ -80.139447, 25.961902 ], "pop" : 14167, "state" : "FL" }
+{ "_id" : "33181", "city" : "NORTH MIAMI BEAC", "loc" : [ -80.160329, 25.896548 ], "pop" : 14089, "state" : "FL" }
+{ "_id" : "33182", "city" : "MIAMI", "loc" : [ -80.41664299999999, 25.787678 ], "pop" : 4983, "state" : "FL" }
+{ "_id" : "33183", "city" : "MIAMI", "loc" : [ -80.412969, 25.699977 ], "pop" : 32077, "state" : "FL" }
+{ "_id" : "33184", "city" : "MIAMI", "loc" : [ -80.402997, 25.757382 ], "pop" : 19617, "state" : "FL" }
+{ "_id" : "33185", "city" : "OLYMPIA HEIGHTS", "loc" : [ -80.437366, 25.718082 ], "pop" : 3606, "state" : "FL" }
+{ "_id" : "33186", "city" : "MIAMI", "loc" : [ -80.408501, 25.669437 ], "pop" : 43611, "state" : "FL" }
+{ "_id" : "33187", "city" : "QUAIL HEIGHTS", "loc" : [ -80.47136999999999, 25.597112 ], "pop" : 6882, "state" : "FL" }
+{ "_id" : "33189", "city" : "QUAIL HEIGHTS", "loc" : [ -80.35085100000001, 25.57431 ], "pop" : 15680, "state" : "FL" }
+{ "_id" : "33190", "city" : "QUAIL HEIGHTS", "loc" : [ -80.35381, 25.560935 ], "pop" : 2807, "state" : "FL" }
+{ "_id" : "33193", "city" : "MIAMI", "loc" : [ -80.44008700000001, 25.696365 ], "pop" : 17432, "state" : "FL" }
+{ "_id" : "33196", "city" : "MIAMI", "loc" : [ -80.441031, 25.661502 ], "pop" : 14612, "state" : "FL" }
+{ "_id" : "33301", "city" : "FORT LAUDERDALE", "loc" : [ -80.128778, 26.121561 ], "pop" : 12040, "state" : "FL" }
+{ "_id" : "33304", "city" : "OAKLAND PARK", "loc" : [ -80.125283, 26.137908 ], "pop" : 18976, "state" : "FL" }
+{ "_id" : "33305", "city" : "OAKLAND PARK", "loc" : [ -80.127768, 26.153115 ], "pop" : 11018, "state" : "FL" }
+{ "_id" : "33306", "city" : "OAKLAND PARK", "loc" : [ -80.112572, 26.165091 ], "pop" : 3424, "state" : "FL" }
+{ "_id" : "33308", "city" : "OAKLAND PARK", "loc" : [ -80.107674, 26.187883 ], "pop" : 28624, "state" : "FL" }
+{ "_id" : "33309", "city" : "FORT LAUDERDALE", "loc" : [ -80.17462399999999, 26.181698 ], "pop" : 28226, "state" : "FL" }
+{ "_id" : "33311", "city" : "FORT LAUDERDALE", "loc" : [ -80.172786, 26.142104 ], "pop" : 65378, "state" : "FL" }
+{ "_id" : "33312", "city" : "FORT LAUDERDALE", "loc" : [ -80.181038, 26.096819 ], "pop" : 44230, "state" : "FL" }
+{ "_id" : "33313", "city" : "CITY OF SUNRISE", "loc" : [ -80.223142, 26.151145 ], "pop" : 46804, "state" : "FL" }
+{ "_id" : "33314", "city" : "DAVIE", "loc" : [ -80.22503399999999, 26.068199 ], "pop" : 19621, "state" : "FL" }
+{ "_id" : "33315", "city" : "FORT LAUDERDALE", "loc" : [ -80.15407999999999, 26.098885 ], "pop" : 12849, "state" : "FL" }
+{ "_id" : "33316", "city" : "FORT LAUDERDALE", "loc" : [ -80.125951, 26.104193 ], "pop" : 11206, "state" : "FL" }
+{ "_id" : "33317", "city" : "PLANTATION", "loc" : [ -80.224272, 26.113536 ], "pop" : 31518, "state" : "FL" }
+{ "_id" : "33319", "city" : "TAMARAC", "loc" : [ -80.225413, 26.181153 ], "pop" : 36178, "state" : "FL" }
+{ "_id" : "33321", "city" : "TAMARAC", "loc" : [ -80.26435600000001, 26.212072 ], "pop" : 29504, "state" : "FL" }
+{ "_id" : "33322", "city" : "SUNRISE", "loc" : [ -80.27195399999999, 26.151923 ], "pop" : 37348, "state" : "FL" }
+{ "_id" : "33323", "city" : "SUNRISE", "loc" : [ -80.30758299999999, 26.164641 ], "pop" : 10658, "state" : "FL" }
+{ "_id" : "33324", "city" : "PLANTATION", "loc" : [ -80.271019, 26.113639 ], "pop" : 29427, "state" : "FL" }
+{ "_id" : "33325", "city" : "DAVIE", "loc" : [ -80.321952, 26.10862 ], "pop" : 19539, "state" : "FL" }
+{ "_id" : "33326", "city" : "DAVIE", "loc" : [ -80.369941, 26.114338 ], "pop" : 8393, "state" : "FL" }
+{ "_id" : "33327", "city" : "FORT LAUDERDALE", "loc" : [ -80.40645000000001, 26.097291 ], "pop" : 4605, "state" : "FL" }
+{ "_id" : "33328", "city" : "DAVIE", "loc" : [ -80.27202200000001, 26.060708 ], "pop" : 17233, "state" : "FL" }
+{ "_id" : "33330", "city" : "DAVIE", "loc" : [ -80.312907, 26.055479 ], "pop" : 9371, "state" : "FL" }
+{ "_id" : "33331", "city" : "DAVIE", "loc" : [ -80.36453299999999, 26.044366 ], "pop" : 6928, "state" : "FL" }
+{ "_id" : "33332", "city" : "DAVIE", "loc" : [ -80.41298999999999, 26.054436 ], "pop" : 1511, "state" : "FL" }
+{ "_id" : "33334", "city" : "OAKLAND PARK", "loc" : [ -80.13551099999999, 26.181514 ], "pop" : 29072, "state" : "FL" }
+{ "_id" : "33351", "city" : "TAMARAC", "loc" : [ -80.273376, 26.177148 ], "pop" : 26228, "state" : "FL" }
+{ "_id" : "33388", "city" : "FORT LAUDERDALE", "loc" : [ -80.250587, 26.117586 ], "pop" : 435, "state" : "FL" }
+{ "_id" : "33401", "city" : "WEST PALM BEACH", "loc" : [ -80.06587399999999, 26.713956 ], "pop" : 19833, "state" : "FL" }
+{ "_id" : "33403", "city" : "LAKE PARK", "loc" : [ -80.073078, 26.803187 ], "pop" : 8743, "state" : "FL" }
+{ "_id" : "33404", "city" : "RIVIERA BEACH", "loc" : [ -80.06852000000001, 26.781343 ], "pop" : 27997, "state" : "FL" }
+{ "_id" : "33405", "city" : "WEST PALM BEACH", "loc" : [ -80.058234, 26.669968 ], "pop" : 18164, "state" : "FL" }
+{ "_id" : "33406", "city" : "GLEN RIDGE", "loc" : [ -80.09302599999999, 26.655582 ], "pop" : 23595, "state" : "FL" }
+{ "_id" : "33407", "city" : "WEST PALM BEACH", "loc" : [ -80.072492, 26.749154 ], "pop" : 25017, "state" : "FL" }
+{ "_id" : "33408", "city" : "NORTH PALM BEACH", "loc" : [ -80.060334, 26.828854 ], "pop" : 17968, "state" : "FL" }
+{ "_id" : "33409", "city" : "HAVERHILL", "loc" : [ -80.09634699999999, 26.713218 ], "pop" : 16142, "state" : "FL" }
+{ "_id" : "33410", "city" : "PALM BEACH GARDE", "loc" : [ -80.087304, 26.844373 ], "pop" : 23249, "state" : "FL" }
+{ "_id" : "33411", "city" : "ROYAL PALM BEACH", "loc" : [ -80.209898, 26.700539 ], "pop" : 21027, "state" : "FL" }
+{ "_id" : "33412", "city" : "WEST PALM BEACH", "loc" : [ -80.248203, 26.805526 ], "pop" : 312, "state" : "FL" }
+{ "_id" : "33413", "city" : "WEST PALM BEACH", "loc" : [ -80.140474, 26.67616 ], "pop" : 4864, "state" : "FL" }
+{ "_id" : "33414", "city" : "WEST PALM BEACH", "loc" : [ -80.25299, 26.662707 ], "pop" : 22046, "state" : "FL" }
+{ "_id" : "33415", "city" : "HAVERHILL", "loc" : [ -80.127966, 26.655722 ], "pop" : 35663, "state" : "FL" }
+{ "_id" : "33417", "city" : "HAVERHILL", "loc" : [ -80.124764, 26.713006 ], "pop" : 25892, "state" : "FL" }
+{ "_id" : "33418", "city" : "PALM BEACH GARDE", "loc" : [ -80.132533, 26.838977 ], "pop" : 15974, "state" : "FL" }
+{ "_id" : "33426", "city" : "BOYNTON BEACH", "loc" : [ -80.083427, 26.51747 ], "pop" : 9390, "state" : "FL" }
+{ "_id" : "33428", "city" : "BOCA RATON", "loc" : [ -80.210942, 26.344605 ], "pop" : 24103, "state" : "FL" }
+{ "_id" : "33430", "city" : "BELLE GLADE", "loc" : [ -80.672392, 26.684289 ], "pop" : 22652, "state" : "FL" }
+{ "_id" : "33431", "city" : "BOCA RATON", "loc" : [ -80.097488, 26.379929 ], "pop" : 13075, "state" : "FL" }
+{ "_id" : "33432", "city" : "BOCA RATON", "loc" : [ -80.08442100000001, 26.34619 ], "pop" : 17141, "state" : "FL" }
+{ "_id" : "33433", "city" : "BOCA RATON", "loc" : [ -80.15639899999999, 26.346409 ], "pop" : 35495, "state" : "FL" }
+{ "_id" : "33434", "city" : "BOCA RATON", "loc" : [ -80.174858, 26.383909 ], "pop" : 19075, "state" : "FL" }
+{ "_id" : "33435", "city" : "BRINY BREEZES", "loc" : [ -80.06424, 26.529161 ], "pop" : 28536, "state" : "FL" }
+{ "_id" : "33436", "city" : "VILLAGE OF GOLF", "loc" : [ -80.10642300000001, 26.526862 ], "pop" : 19263, "state" : "FL" }
+{ "_id" : "33437", "city" : "BOYNTON BEACH", "loc" : [ -80.141812, 26.531187 ], "pop" : 14809, "state" : "FL" }
+{ "_id" : "33438", "city" : "CANAL POINT", "loc" : [ -80.629931, 26.859279 ], "pop" : 1494, "state" : "FL" }
+{ "_id" : "33440", "city" : "CLEWISTON", "loc" : [ -80.94924899999999, 26.717171 ], "pop" : 14427, "state" : "FL" }
+{ "_id" : "33441", "city" : "DEERFIELD BEACH", "loc" : [ -80.09917299999999, 26.309556 ], "pop" : 24529, "state" : "FL" }
+{ "_id" : "33442", "city" : "DEERFIELD BEACH", "loc" : [ -80.14124200000001, 26.312365 ], "pop" : 21532, "state" : "FL" }
+{ "_id" : "33444", "city" : "DELRAY BEACH", "loc" : [ -80.07932099999999, 26.456445 ], "pop" : 18450, "state" : "FL" }
+{ "_id" : "33445", "city" : "DELRAY BEACH", "loc" : [ -80.105397, 26.456359 ], "pop" : 20740, "state" : "FL" }
+{ "_id" : "33446", "city" : "DELRAY BEACH", "loc" : [ -80.158016, 26.451717 ], "pop" : 13016, "state" : "FL" }
+{ "_id" : "33455", "city" : "HOBE SOUND", "loc" : [ -80.150851, 27.081306 ], "pop" : 15209, "state" : "FL" }
+{ "_id" : "33458", "city" : "JUPITER", "loc" : [ -80.120091, 26.933938 ], "pop" : 23869, "state" : "FL" }
+{ "_id" : "33460", "city" : "LAKE WORTH", "loc" : [ -80.05599599999999, 26.618207 ], "pop" : 28653, "state" : "FL" }
+{ "_id" : "33461", "city" : "LAKE WORTH", "loc" : [ -80.094573, 26.62316 ], "pop" : 30905, "state" : "FL" }
+{ "_id" : "33462", "city" : "LANTANA", "loc" : [ -80.077264, 26.576766 ], "pop" : 30704, "state" : "FL" }
+{ "_id" : "33463", "city" : "GREENACRES", "loc" : [ -80.130503, 26.609609 ], "pop" : 28841, "state" : "FL" }
+{ "_id" : "33467", "city" : "LAKE WORTH", "loc" : [ -80.168299, 26.610366 ], "pop" : 21547, "state" : "FL" }
+{ "_id" : "33469", "city" : "TEQUESTA", "loc" : [ -80.100161, 26.966066 ], "pop" : 11781, "state" : "FL" }
+{ "_id" : "33470", "city" : "LOXAHATCHEE", "loc" : [ -80.27600700000001, 26.738295 ], "pop" : 14094, "state" : "FL" }
+{ "_id" : "33471", "city" : "MOORE HAVEN", "loc" : [ -81.21877600000001, 26.832749 ], "pop" : 4724, "state" : "FL" }
+{ "_id" : "33476", "city" : "PAHOKEE", "loc" : [ -80.662897, 26.814199 ], "pop" : 8354, "state" : "FL" }
+{ "_id" : "33477", "city" : "JUPITER", "loc" : [ -80.077034, 26.921701 ], "pop" : 7748, "state" : "FL" }
+{ "_id" : "33478", "city" : "JUPITER", "loc" : [ -80.214388, 26.921242 ], "pop" : 10534, "state" : "FL" }
+{ "_id" : "33480", "city" : "PALM BEACH", "loc" : [ -80.038825, 26.72065 ], "pop" : 6588, "state" : "FL" }
+{ "_id" : "33483", "city" : "DELRAY BEACH", "loc" : [ -80.065637, 26.45457 ], "pop" : 10326, "state" : "FL" }
+{ "_id" : "33484", "city" : "DELRAY BEACH", "loc" : [ -80.13459, 26.454272 ], "pop" : 19141, "state" : "FL" }
+{ "_id" : "33486", "city" : "BOCA RATON", "loc" : [ -80.110418, 26.348099 ], "pop" : 19601, "state" : "FL" }
+{ "_id" : "33487", "city" : "HIGHLAND BEACH", "loc" : [ -80.089072, 26.409142 ], "pop" : 14606, "state" : "FL" }
+{ "_id" : "33493", "city" : "SOUTH BAY", "loc" : [ -80.73121399999999, 26.670126 ], "pop" : 3723, "state" : "FL" }
+{ "_id" : "33496", "city" : "BOCA RATON", "loc" : [ -80.181287, 26.402975 ], "pop" : 7116, "state" : "FL" }
+{ "_id" : "33498", "city" : "BOCA RATON", "loc" : [ -80.216087, 26.390693 ], "pop" : 5871, "state" : "FL" }
+{ "_id" : "33510", "city" : "BRANDON", "loc" : [ -82.296554, 27.955112 ], "pop" : 20184, "state" : "FL" }
+{ "_id" : "33511", "city" : "BRANDON", "loc" : [ -82.288116, 27.905649 ], "pop" : 29861, "state" : "FL" }
+{ "_id" : "33513", "city" : "BUSHNELL", "loc" : [ -82.155297, 28.661062 ], "pop" : 8728, "state" : "FL" }
+{ "_id" : "33514", "city" : "CENTER HILL", "loc" : [ -81.996289, 28.663484 ], "pop" : 1202, "state" : "FL" }
+{ "_id" : "33525", "city" : "RIDGE MANOR", "loc" : [ -82.207936, 28.386912 ], "pop" : 29328, "state" : "FL" }
+{ "_id" : "33527", "city" : "DOVER", "loc" : [ -82.21384500000001, 27.991975 ], "pop" : 13171, "state" : "FL" }
+{ "_id" : "33534", "city" : "GIBSONTON", "loc" : [ -82.369831, 27.841059 ], "pop" : 7010, "state" : "FL" }
+{ "_id" : "33538", "city" : "LAKE PANASOFFKEE", "loc" : [ -82.136279, 28.795261 ], "pop" : 3617, "state" : "FL" }
+{ "_id" : "33540", "city" : "ZEPHYRHILLS", "loc" : [ -82.168347, 28.24096 ], "pop" : 15608, "state" : "FL" }
+{ "_id" : "33541", "city" : "ZEPHYRHILLS", "loc" : [ -82.20565999999999, 28.231063 ], "pop" : 17575, "state" : "FL" }
+{ "_id" : "33543", "city" : "WESLEY CHAPEL", "loc" : [ -82.288956, 28.210365 ], "pop" : 4073, "state" : "FL" }
+{ "_id" : "33544", "city" : "ZEPHYRHILLS", "loc" : [ -82.34932999999999, 28.263664 ], "pop" : 5989, "state" : "FL" }
+{ "_id" : "33547", "city" : "LITHIA", "loc" : [ -82.135679, 27.829349 ], "pop" : 6780, "state" : "FL" }
+{ "_id" : "33549", "city" : "LUTZ", "loc" : [ -82.461045, 28.136688 ], "pop" : 30905, "state" : "FL" }
+{ "_id" : "33556", "city" : "ODESSA", "loc" : [ -82.590506, 28.142072 ], "pop" : 7046, "state" : "FL" }
+{ "_id" : "33565", "city" : "PLANT CITY", "loc" : [ -82.157554, 28.069855 ], "pop" : 13299, "state" : "FL" }
+{ "_id" : "33566", "city" : "PLANT CITY", "loc" : [ -82.113816, 28.009448 ], "pop" : 19533, "state" : "FL" }
+{ "_id" : "33567", "city" : "PLANT CITY", "loc" : [ -82.14626800000001, 27.976167 ], "pop" : 18937, "state" : "FL" }
+{ "_id" : "33569", "city" : "RIVERVIEW", "loc" : [ -82.312473, 27.844952 ], "pop" : 21930, "state" : "FL" }
+{ "_id" : "33570", "city" : "RUSKIN", "loc" : [ -82.435501, 27.701501 ], "pop" : 14654, "state" : "FL" }
+{ "_id" : "33572", "city" : "APOLLO BEACH", "loc" : [ -82.41019900000001, 27.771553 ], "pop" : 6074, "state" : "FL" }
+{ "_id" : "33573", "city" : "SUN CITY CENTER", "loc" : [ -82.353832, 27.714711 ], "pop" : 9070, "state" : "FL" }
+{ "_id" : "33576", "city" : "SAN ANTONIO", "loc" : [ -82.288237, 28.337139 ], "pop" : 1396, "state" : "FL" }
+{ "_id" : "33584", "city" : "SEFFNER", "loc" : [ -82.28629599999999, 27.992199 ], "pop" : 20956, "state" : "FL" }
+{ "_id" : "33592", "city" : "THONOTOSASSA", "loc" : [ -82.308212, 28.061747 ], "pop" : 9009, "state" : "FL" }
+{ "_id" : "33594", "city" : "VALRICO", "loc" : [ -82.246557, 27.912435 ], "pop" : 27594, "state" : "FL" }
+{ "_id" : "33597", "city" : "RIDGE MANOR ESTA", "loc" : [ -82.092975, 28.577492 ], "pop" : 5880, "state" : "FL" }
+{ "_id" : "33598", "city" : "WIMAUMA", "loc" : [ -82.315136, 27.701497 ], "pop" : 7538, "state" : "FL" }
+{ "_id" : "33602", "city" : "TAMPA", "loc" : [ -82.45972, 27.961381 ], "pop" : 8473, "state" : "FL" }
+{ "_id" : "33603", "city" : "TAMPA", "loc" : [ -82.462997, 27.984534 ], "pop" : 19614, "state" : "FL" }
+{ "_id" : "33604", "city" : "TAMPA", "loc" : [ -82.457848, 28.017312 ], "pop" : 34243, "state" : "FL" }
+{ "_id" : "33605", "city" : "TAMPA", "loc" : [ -82.433368, 27.967078 ], "pop" : 19813, "state" : "FL" }
+{ "_id" : "33606", "city" : "TAMPA", "loc" : [ -82.467035, 27.933828 ], "pop" : 14191, "state" : "FL" }
+{ "_id" : "33607", "city" : "TAMPA", "loc" : [ -82.489535, 27.962538 ], "pop" : 22386, "state" : "FL" }
+{ "_id" : "33608", "city" : "TAMPA", "loc" : [ -82.507097, 27.865916 ], "pop" : 3578, "state" : "FL" }
+{ "_id" : "33609", "city" : "TAMPA", "loc" : [ -82.50572, 27.942456 ], "pop" : 15797, "state" : "FL" }
+{ "_id" : "33610", "city" : "TAMPA", "loc" : [ -82.404584, 27.995125 ], "pop" : 34244, "state" : "FL" }
+{ "_id" : "33611", "city" : "TAMPA", "loc" : [ -82.506714, 27.891422 ], "pop" : 30070, "state" : "FL" }
+{ "_id" : "33612", "city" : "TAMPA", "loc" : [ -82.450018, 28.050187 ], "pop" : 36784, "state" : "FL" }
+{ "_id" : "33613", "city" : "TAMPA", "loc" : [ -82.445519, 28.077184 ], "pop" : 24849, "state" : "FL" }
+{ "_id" : "33614", "city" : "TAMPA", "loc" : [ -82.503393, 28.00914 ], "pop" : 39021, "state" : "FL" }
+{ "_id" : "33615", "city" : "TAMPA", "loc" : [ -82.580495, 28.008057 ], "pop" : 36532, "state" : "FL" }
+{ "_id" : "33616", "city" : "TAMPA", "loc" : [ -82.52029, 27.87418 ], "pop" : 11318, "state" : "FL" }
+{ "_id" : "33617", "city" : "TAMPA", "loc" : [ -82.394876, 28.038358 ], "pop" : 38114, "state" : "FL" }
+{ "_id" : "33618", "city" : "CARROLLWOOD", "loc" : [ -82.493291, 28.075875 ], "pop" : 20229, "state" : "FL" }
+{ "_id" : "33619", "city" : "TAMPA", "loc" : [ -82.375558, 27.93824 ], "pop" : 27185, "state" : "FL" }
+{ "_id" : "33620", "city" : "TAMPA", "loc" : [ -82.409188, 28.069465 ], "pop" : 3757, "state" : "FL" }
+{ "_id" : "33624", "city" : "CARROLLWOOD", "loc" : [ -82.524944, 28.077194 ], "pop" : 39616, "state" : "FL" }
+{ "_id" : "33625", "city" : "TAMPA", "loc" : [ -82.558987, 28.072551 ], "pop" : 14778, "state" : "FL" }
+{ "_id" : "33626", "city" : "TAMPA", "loc" : [ -82.616378, 28.050932 ], "pop" : 2213, "state" : "FL" }
+{ "_id" : "33629", "city" : "TAMPA", "loc" : [ -82.507897, 27.92102 ], "pop" : 21545, "state" : "FL" }
+{ "_id" : "33634", "city" : "TAMPA", "loc" : [ -82.556006, 28.006783 ], "pop" : 18712, "state" : "FL" }
+{ "_id" : "33635", "city" : "TAMPA", "loc" : [ -82.604822, 28.03013 ], "pop" : 6241, "state" : "FL" }
+{ "_id" : "33637", "city" : "TAMPA", "loc" : [ -82.365876, 28.03377 ], "pop" : 9673, "state" : "FL" }
+{ "_id" : "33647", "city" : "TAMPA", "loc" : [ -82.367751, 28.114698 ], "pop" : 5866, "state" : "FL" }
+{ "_id" : "33701", "city" : "SAINT PETERSBURG", "loc" : [ -82.638609, 27.772318 ], "pop" : 15737, "state" : "FL" }
+{ "_id" : "33702", "city" : "SAINT PETERSBURG", "loc" : [ -82.644795, 27.842712 ], "pop" : 28888, "state" : "FL" }
+{ "_id" : "33703", "city" : "SAINT PETERSBURG", "loc" : [ -82.62639299999999, 27.816957 ], "pop" : 23348, "state" : "FL" }
+{ "_id" : "33704", "city" : "SAINT PETERSBURG", "loc" : [ -82.637289, 27.795435 ], "pop" : 17112, "state" : "FL" }
+{ "_id" : "33705", "city" : "SAINT PETERSBURG", "loc" : [ -82.64349, 27.739113 ], "pop" : 28261, "state" : "FL" }
+{ "_id" : "33706", "city" : "SAINT PETERSBURG", "loc" : [ -82.75164599999999, 27.745606 ], "pop" : 18974, "state" : "FL" }
+{ "_id" : "33707", "city" : "SAINT PETERSBURG", "loc" : [ -82.72079100000001, 27.75487 ], "pop" : 23630, "state" : "FL" }
+{ "_id" : "33708", "city" : "MADEIRA BEACH", "loc" : [ -82.80077900000001, 27.816529 ], "pop" : 18018, "state" : "FL" }
+{ "_id" : "33709", "city" : "KENNETH CITY", "loc" : [ -82.729845, 27.817427 ], "pop" : 26024, "state" : "FL" }
+{ "_id" : "33710", "city" : "SAINT PETERSBURG", "loc" : [ -82.72428499999999, 27.789798 ], "pop" : 32402, "state" : "FL" }
+{ "_id" : "33711", "city" : "SAINT PETERSBURG", "loc" : [ -82.689708, 27.74649 ], "pop" : 18084, "state" : "FL" }
+{ "_id" : "33712", "city" : "SAINT PETERSBURG", "loc" : [ -82.666298, 27.735336 ], "pop" : 27715, "state" : "FL" }
+{ "_id" : "33713", "city" : "SAINT PETERSBURG", "loc" : [ -82.67793899999999, 27.789015 ], "pop" : 29160, "state" : "FL" }
+{ "_id" : "33714", "city" : "SAINT PETERSBURG", "loc" : [ -82.677612, 27.817621 ], "pop" : 18227, "state" : "FL" }
+{ "_id" : "33715", "city" : "TIERRA VERDE", "loc" : [ -82.71564600000001, 27.694792 ], "pop" : 3877, "state" : "FL" }
+{ "_id" : "33716", "city" : "SAINT PETERSBURG", "loc" : [ -82.640039, 27.873764 ], "pop" : 9328, "state" : "FL" }
+{ "_id" : "33801", "city" : "LAKELAND", "loc" : [ -81.939153, 28.038134 ], "pop" : 45005, "state" : "FL" }
+{ "_id" : "33803", "city" : "LAKELAND", "loc" : [ -81.95228299999999, 28.014045 ], "pop" : 23761, "state" : "FL" }
+{ "_id" : "33805", "city" : "LAKELAND", "loc" : [ -81.96091, 28.072006 ], "pop" : 19676, "state" : "FL" }
+{ "_id" : "33809", "city" : "LAKELAND", "loc" : [ -81.984219, 28.123356 ], "pop" : 39958, "state" : "FL" }
+{ "_id" : "33811", "city" : "SOUTHSIDE", "loc" : [ -82.00723600000001, 27.966284 ], "pop" : 11456, "state" : "FL" }
+{ "_id" : "33813", "city" : "SOUTHSIDE", "loc" : [ -81.933187, 27.969534 ], "pop" : 28497, "state" : "FL" }
+{ "_id" : "33821", "city" : "ARCADIA", "loc" : [ -81.86575499999999, 27.18996 ], "pop" : 23865, "state" : "FL" }
+{ "_id" : "33823", "city" : "AUBURNDALE", "loc" : [ -81.812234, 28.072443 ], "pop" : 24489, "state" : "FL" }
+{ "_id" : "33825", "city" : "AVON PARK", "loc" : [ -81.501486, 27.600085 ], "pop" : 16945, "state" : "FL" }
+{ "_id" : "33827", "city" : "BABSON PARK", "loc" : [ -81.534221, 27.831698 ], "pop" : 1901, "state" : "FL" }
+{ "_id" : "33830", "city" : "BARTOW", "loc" : [ -81.812684, 27.895664 ], "pop" : 25968, "state" : "FL" }
+{ "_id" : "33834", "city" : "DUETTE", "loc" : [ -81.84505799999999, 27.627738 ], "pop" : 3700, "state" : "FL" }
+{ "_id" : "33837", "city" : "DAVENPORT", "loc" : [ -81.607912, 28.196265 ], "pop" : 8268, "state" : "FL" }
+{ "_id" : "33838", "city" : "DUNDEE", "loc" : [ -81.621207, 28.019412 ], "pop" : 2335, "state" : "FL" }
+{ "_id" : "33839", "city" : "EAGLE LAKE", "loc" : [ -81.75635699999999, 27.978661 ], "pop" : 1456, "state" : "FL" }
+{ "_id" : "33841", "city" : "FORT MEADE", "loc" : [ -81.782346, 27.746356 ], "pop" : 8169, "state" : "FL" }
+{ "_id" : "33843", "city" : "FROSTPROOF", "loc" : [ -81.51477800000001, 27.721058 ], "pop" : 8747, "state" : "FL" }
+{ "_id" : "33844", "city" : "GRENELEFE", "loc" : [ -81.614712, 28.095073 ], "pop" : 23835, "state" : "FL" }
+{ "_id" : "33849", "city" : "KATHLEEN", "loc" : [ -82.043499, 28.205224 ], "pop" : 1096, "state" : "FL" }
+{ "_id" : "33850", "city" : "LAKE ALFRED", "loc" : [ -81.727138, 28.089483 ], "pop" : 3916, "state" : "FL" }
+{ "_id" : "33852", "city" : "LAKE PLACID", "loc" : [ -81.364918, 27.294474 ], "pop" : 13767, "state" : "FL" }
+{ "_id" : "33853", "city" : "LAKE WALES", "loc" : [ -81.548805, 27.903734 ], "pop" : 32570, "state" : "FL" }
+{ "_id" : "33857", "city" : "LORIDA", "loc" : [ -81.196533, 27.414952 ], "pop" : 1186, "state" : "FL" }
+{ "_id" : "33860", "city" : "MULBERRY", "loc" : [ -82.00148900000001, 27.90202 ], "pop" : 13338, "state" : "FL" }
+{ "_id" : "33865", "city" : "ONA", "loc" : [ -81.92805, 27.412657 ], "pop" : 885, "state" : "FL" }
+{ "_id" : "33868", "city" : "POLK CITY", "loc" : [ -81.80828200000001, 28.19867 ], "pop" : 7604, "state" : "FL" }
+{ "_id" : "33870", "city" : "SEBRING", "loc" : [ -81.435712, 27.492391 ], "pop" : 19922, "state" : "FL" }
+{ "_id" : "33872", "city" : "SEBRING", "loc" : [ -81.48724199999999, 27.470289 ], "pop" : 15390, "state" : "FL" }
+{ "_id" : "33873", "city" : "WAUCHULA", "loc" : [ -81.807388, 27.551742 ], "pop" : 11513, "state" : "FL" }
+{ "_id" : "33880", "city" : "ELOISE", "loc" : [ -81.751507, 27.999296 ], "pop" : 30803, "state" : "FL" }
+{ "_id" : "33881", "city" : "WINTER HAVEN", "loc" : [ -81.732485, 28.045219 ], "pop" : 25957, "state" : "FL" }
+{ "_id" : "33884", "city" : "CYPRESS GARDENS", "loc" : [ -81.678905, 27.994901 ], "pop" : 14771, "state" : "FL" }
+{ "_id" : "33890", "city" : "ZOLFO SPRINGS", "loc" : [ -81.742328, 27.480042 ], "pop" : 3515, "state" : "FL" }
+{ "_id" : "33901", "city" : "FORT MYERS", "loc" : [ -81.8725, 26.620403 ], "pop" : 22150, "state" : "FL" }
+{ "_id" : "33903", "city" : "FORT MYERS", "loc" : [ -81.909632, 26.678138 ], "pop" : 20015, "state" : "FL" }
+{ "_id" : "33904", "city" : "CAPE CORAL CENTR", "loc" : [ -81.952243, 26.57746 ], "pop" : 29483, "state" : "FL" }
+{ "_id" : "33905", "city" : "TICE", "loc" : [ -81.785341, 26.676472 ], "pop" : 25029, "state" : "FL" }
+{ "_id" : "33907", "city" : "FORT MYERS", "loc" : [ -81.873558, 26.568057 ], "pop" : 19015, "state" : "FL" }
+{ "_id" : "33908", "city" : "FORT MYERS", "loc" : [ -81.927589, 26.502518 ], "pop" : 17050, "state" : "FL" }
+{ "_id" : "33909", "city" : "CAPE CORAL CENTR", "loc" : [ -81.95890900000001, 26.680276 ], "pop" : 8622, "state" : "FL" }
+{ "_id" : "33912", "city" : "FORT MYERS", "loc" : [ -81.82455400000001, 26.49722 ], "pop" : 20141, "state" : "FL" }
+{ "_id" : "33913", "city" : "FORT MYERS", "loc" : [ -81.706469, 26.522808 ], "pop" : 473, "state" : "FL" }
+{ "_id" : "33914", "city" : "CAPE CORAL CENTR", "loc" : [ -81.990915, 26.56971 ], "pop" : 15782, "state" : "FL" }
+{ "_id" : "33916", "city" : "FORT MYERS", "loc" : [ -81.842946, 26.646595 ], "pop" : 17673, "state" : "FL" }
+{ "_id" : "33917", "city" : "FORT MYERS", "loc" : [ -81.859447, 26.707947 ], "pop" : 24751, "state" : "FL" }
+{ "_id" : "33919", "city" : "COLLEGE PARKWAY", "loc" : [ -81.900587, 26.554159 ], "pop" : 22641, "state" : "FL" }
+{ "_id" : "33920", "city" : "ALVA", "loc" : [ -81.63505499999999, 26.714657 ], "pop" : 3044, "state" : "FL" }
+{ "_id" : "33922", "city" : "BOKEELIA", "loc" : [ -82.140064, 26.662726 ], "pop" : 2979, "state" : "FL" }
+{ "_id" : "33923", "city" : "BONITA SPRINGS", "loc" : [ -81.789963, 26.348035 ], "pop" : 19697, "state" : "FL" }
+{ "_id" : "33924", "city" : "CAPTIVA", "loc" : [ -82.261017, 26.750541 ], "pop" : 831, "state" : "FL" }
+{ "_id" : "33927", "city" : "EL JOBEAN", "loc" : [ -82.19956999999999, 26.97608 ], "pop" : 91, "state" : "FL" }
+{ "_id" : "33928", "city" : "ESTERO", "loc" : [ -81.810244, 26.435052 ], "pop" : 1846, "state" : "FL" }
+{ "_id" : "33931", "city" : "FORT MYERS BEACH", "loc" : [ -81.924543, 26.451952 ], "pop" : 10612, "state" : "FL" }
+{ "_id" : "33934", "city" : "IMMOKALEE", "loc" : [ -81.445365, 26.409794 ], "pop" : 18066, "state" : "FL" }
+{ "_id" : "33935", "city" : "LABELLE", "loc" : [ -81.434027, 26.732093 ], "pop" : 11346, "state" : "FL" }
+{ "_id" : "33936", "city" : "LEHIGH ACRES", "loc" : [ -81.61046, 26.615302 ], "pop" : 10851, "state" : "FL" }
+{ "_id" : "33937", "city" : "MARCO ISLAND", "loc" : [ -81.720394, 25.939568 ], "pop" : 9495, "state" : "FL" }
+{ "_id" : "33940", "city" : "NAPLES", "loc" : [ -81.802196, 26.171391 ], "pop" : 20934, "state" : "FL" }
+{ "_id" : "33942", "city" : "NAPLES", "loc" : [ -81.766125, 26.201578 ], "pop" : 23719, "state" : "FL" }
+{ "_id" : "33943", "city" : "OCHOPEE", "loc" : [ -81.311228, 25.87998 ], "pop" : 1257, "state" : "FL" }
+{ "_id" : "33946", "city" : "PLACIDA", "loc" : [ -82.261638, 26.819301 ], "pop" : 126, "state" : "FL" }
+{ "_id" : "33947", "city" : "PLACIDA", "loc" : [ -82.293778, 26.90039 ], "pop" : 7811, "state" : "FL" }
+{ "_id" : "33948", "city" : "PORT CHARLOTTE", "loc" : [ -82.14117299999999, 26.98268 ], "pop" : 12212, "state" : "FL" }
+{ "_id" : "33950", "city" : "PUNTA GORDA", "loc" : [ -82.053166, 26.915163 ], "pop" : 15495, "state" : "FL" }
+{ "_id" : "33952", "city" : "PORT CHARLOTTE", "loc" : [ -82.096372, 26.990475 ], "pop" : 27923, "state" : "FL" }
+{ "_id" : "33953", "city" : "PORT CHARLOTTE", "loc" : [ -82.211743, 27.004008 ], "pop" : 1982, "state" : "FL" }
+{ "_id" : "33954", "city" : "PORT CHARLOTTE", "loc" : [ -82.110782, 27.022815 ], "pop" : 3993, "state" : "FL" }
+{ "_id" : "33955", "city" : "PUNTA GORDA", "loc" : [ -81.954712, 26.823981 ], "pop" : 5206, "state" : "FL" }
+{ "_id" : "33956", "city" : "SAINT JAMES CITY", "loc" : [ -82.09159099999999, 26.529012 ], "pop" : 3653, "state" : "FL" }
+{ "_id" : "33957", "city" : "SANIBEL", "loc" : [ -82.086825, 26.4514 ], "pop" : 5999, "state" : "FL" }
+{ "_id" : "33960", "city" : "VENUS", "loc" : [ -81.35941200000001, 27.13463 ], "pop" : 925, "state" : "FL" }
+{ "_id" : "33961", "city" : "NAPLES", "loc" : [ -81.658635, 26.027721 ], "pop" : 7121, "state" : "FL" }
+{ "_id" : "33962", "city" : "NAPLES", "loc" : [ -81.749661, 26.113096 ], "pop" : 28714, "state" : "FL" }
+{ "_id" : "33963", "city" : "NAPLES", "loc" : [ -81.808092, 26.263499 ], "pop" : 14863, "state" : "FL" }
+{ "_id" : "33964", "city" : "NAPLES", "loc" : [ -81.64043599999999, 26.211253 ], "pop" : 5869, "state" : "FL" }
+{ "_id" : "33971", "city" : "LEHIGH ACRES", "loc" : [ -81.66582200000001, 26.602252 ], "pop" : 11401, "state" : "FL" }
+{ "_id" : "33980", "city" : "PORT CHARLOTTE", "loc" : [ -82.058886, 26.983969 ], "pop" : 7753, "state" : "FL" }
+{ "_id" : "33981", "city" : "PORT CHARLOTTE", "loc" : [ -82.23877400000001, 26.937925 ], "pop" : 5758, "state" : "FL" }
+{ "_id" : "33982", "city" : "PUNTA GORDA", "loc" : [ -81.95448399999999, 26.966751 ], "pop" : 6235, "state" : "FL" }
+{ "_id" : "33983", "city" : "PUNTA GORDA", "loc" : [ -82.016268, 27.007398 ], "pop" : 7319, "state" : "FL" }
+{ "_id" : "33990", "city" : "CAPE CORAL CENTR", "loc" : [ -81.945967, 26.630893 ], "pop" : 16975, "state" : "FL" }
+{ "_id" : "33991", "city" : "CAPE CORAL CENTR", "loc" : [ -82.006703, 26.628881 ], "pop" : 5352, "state" : "FL" }
+{ "_id" : "33999", "city" : "NAPLES", "loc" : [ -81.70927, 26.191612 ], "pop" : 21226, "state" : "FL" }
+{ "_id" : "34202", "city" : "BRADEN RIVER", "loc" : [ -82.431487, 27.46521 ], "pop" : 6618, "state" : "FL" }
+{ "_id" : "34203", "city" : "BRADEN RIVER", "loc" : [ -82.54040000000001, 27.444871 ], "pop" : 22408, "state" : "FL" }
+{ "_id" : "34205", "city" : "WESTGATE", "loc" : [ -82.584733, 27.480896 ], "pop" : 31114, "state" : "FL" }
+{ "_id" : "34207", "city" : "COLLEGE PLAZA", "loc" : [ -82.58062700000001, 27.439663 ], "pop" : 27775, "state" : "FL" }
+{ "_id" : "34208", "city" : "BRADEN RIVER", "loc" : [ -82.53696100000001, 27.485881 ], "pop" : 20668, "state" : "FL" }
+{ "_id" : "34209", "city" : "PALMA SOLA", "loc" : [ -82.62763099999999, 27.487909 ], "pop" : 30012, "state" : "FL" }
+{ "_id" : "34210", "city" : "BRADENTON", "loc" : [ -82.635752, 27.454393 ], "pop" : 11345, "state" : "FL" }
+{ "_id" : "34215", "city" : "CORTEZ", "loc" : [ -82.700642, 27.472686 ], "pop" : 1657, "state" : "FL" }
+{ "_id" : "34217", "city" : "BRADENTON BEACH", "loc" : [ -82.72102700000001, 27.515149 ], "pop" : 6554, "state" : "FL" }
+{ "_id" : "34219", "city" : "PARRISH", "loc" : [ -82.39600900000001, 27.557162 ], "pop" : 3811, "state" : "FL" }
+{ "_id" : "34221", "city" : "PALMETTO", "loc" : [ -82.562957, 27.542946 ], "pop" : 23994, "state" : "FL" }
+{ "_id" : "34222", "city" : "ELLENTON", "loc" : [ -82.50060000000001, 27.53818 ], "pop" : 8252, "state" : "FL" }
+{ "_id" : "34223", "city" : "ENGLEWOOD", "loc" : [ -82.359886, 26.966743 ], "pop" : 15705, "state" : "FL" }
+{ "_id" : "34224", "city" : "GROVE CITY", "loc" : [ -82.31173099999999, 26.92504 ], "pop" : 5110, "state" : "FL" }
+{ "_id" : "34228", "city" : "WHITNEY BEACH", "loc" : [ -82.638403, 27.38669 ], "pop" : 5937, "state" : "FL" }
+{ "_id" : "34229", "city" : "OSPREY", "loc" : [ -82.485339, 27.18384 ], "pop" : 3612, "state" : "FL" }
+{ "_id" : "34231", "city" : "SOUTH TRAIL", "loc" : [ -82.51379300000001, 27.26757 ], "pop" : 32813, "state" : "FL" }
+{ "_id" : "34232", "city" : "FOREST LAKES", "loc" : [ -82.47570899999999, 27.320056 ], "pop" : 29847, "state" : "FL" }
+{ "_id" : "34233", "city" : "SARASOTA", "loc" : [ -82.47698, 27.286614 ], "pop" : 11476, "state" : "FL" }
+{ "_id" : "34234", "city" : "MEADOWS VILLAGE", "loc" : [ -82.53518200000001, 27.365355 ], "pop" : 20243, "state" : "FL" }
+{ "_id" : "34235", "city" : "SARASOTA", "loc" : [ -82.484759, 27.367162 ], "pop" : 11275, "state" : "FL" }
+{ "_id" : "34236", "city" : "SARASOTA", "loc" : [ -82.548624, 27.331588 ], "pop" : 10942, "state" : "FL" }
+{ "_id" : "34237", "city" : "SARASOTA", "loc" : [ -82.512778, 27.336915 ], "pop" : 15902, "state" : "FL" }
+{ "_id" : "34238", "city" : "SARASOTA SQUARE", "loc" : [ -82.48289800000001, 27.243834 ], "pop" : 5493, "state" : "FL" }
+{ "_id" : "34239", "city" : "SARASOTA", "loc" : [ -82.51954499999999, 27.311137 ], "pop" : 15949, "state" : "FL" }
+{ "_id" : "34240", "city" : "SARASOTA", "loc" : [ -82.385594, 27.32765 ], "pop" : 4943, "state" : "FL" }
+{ "_id" : "34241", "city" : "SARASOTA", "loc" : [ -82.41811199999999, 27.282179 ], "pop" : 8902, "state" : "FL" }
+{ "_id" : "34242", "city" : "CRESCENT BEACH", "loc" : [ -82.546932, 27.266025 ], "pop" : 10594, "state" : "FL" }
+{ "_id" : "34243", "city" : "SARASOTA", "loc" : [ -82.530299, 27.407235 ], "pop" : 14096, "state" : "FL" }
+{ "_id" : "34251", "city" : "MYAKKA CITY", "loc" : [ -82.18489700000001, 27.364764 ], "pop" : 1636, "state" : "FL" }
+{ "_id" : "34275", "city" : "NOKOMIS", "loc" : [ -82.451779, 27.138398 ], "pop" : 13638, "state" : "FL" }
+{ "_id" : "34285", "city" : "VENICE", "loc" : [ -82.44983000000001, 27.093312 ], "pop" : 9069, "state" : "FL" }
+{ "_id" : "34287", "city" : "NORTH PORT", "loc" : [ -82.24161599999999, 27.047839 ], "pop" : 16491, "state" : "FL" }
+{ "_id" : "34292", "city" : "MID VENICE", "loc" : [ -82.41511199999999, 27.103245 ], "pop" : 13901, "state" : "FL" }
+{ "_id" : "34293", "city" : "SOUTH VENICE", "loc" : [ -82.404096, 27.053022 ], "pop" : 26720, "state" : "FL" }
+{ "_id" : "34601", "city" : "BROOKSVILLE", "loc" : [ -82.37367399999999, 28.565805 ], "pop" : 20190, "state" : "FL" }
+{ "_id" : "34602", "city" : "RIDGE MANOR WEST", "loc" : [ -82.29054499999999, 28.511167 ], "pop" : 4940, "state" : "FL" }
+{ "_id" : "34606", "city" : "SPRING HILL", "loc" : [ -82.598084, 28.46551 ], "pop" : 18190, "state" : "FL" }
+{ "_id" : "34607", "city" : "SPRING HILL", "loc" : [ -82.626671, 28.506546 ], "pop" : 5420, "state" : "FL" }
+{ "_id" : "34608", "city" : "SPRING HILL", "loc" : [ -82.556206, 28.479696 ], "pop" : 16755, "state" : "FL" }
+{ "_id" : "34609", "city" : "SPRING HILL", "loc" : [ -82.49989600000001, 28.477611 ], "pop" : 19824, "state" : "FL" }
+{ "_id" : "34610", "city" : "SHADY HILLS", "loc" : [ -82.530148, 28.405084 ], "pop" : 9958, "state" : "FL" }
+{ "_id" : "34613", "city" : "BROOKSVILLE", "loc" : [ -82.521286, 28.546558 ], "pop" : 9899, "state" : "FL" }
+{ "_id" : "34614", "city" : "BROOKSVILLE", "loc" : [ -82.523613, 28.662244 ], "pop" : 3687, "state" : "FL" }
+{ "_id" : "34615", "city" : "CLEARWATER", "loc" : [ -82.780807, 27.986241 ], "pop" : 30847, "state" : "FL" }
+{ "_id" : "34616", "city" : "CLEARWATER", "loc" : [ -82.786711, 27.945624 ], "pop" : 28460, "state" : "FL" }
+{ "_id" : "34619", "city" : "CLEARWATER", "loc" : [ -82.717248, 27.976503 ], "pop" : 15886, "state" : "FL" }
+{ "_id" : "34620", "city" : "CLEARWATER", "loc" : [ -82.715885, 27.913981 ], "pop" : 15769, "state" : "FL" }
+{ "_id" : "34621", "city" : "CLEARWATER", "loc" : [ -82.72371800000001, 28.02961 ], "pop" : 16102, "state" : "FL" }
+{ "_id" : "34622", "city" : "AIRPORT", "loc" : [ -82.67687599999999, 27.896713 ], "pop" : 3190, "state" : "FL" }
+{ "_id" : "34623", "city" : "CLEARWATER", "loc" : [ -82.747405, 28.002734 ], "pop" : 20280, "state" : "FL" }
+{ "_id" : "34624", "city" : "CLEARWATER", "loc" : [ -82.74348500000001, 27.93595 ], "pop" : 27315, "state" : "FL" }
+{ "_id" : "34625", "city" : "CLEARWATER", "loc" : [ -82.745504, 27.973063 ], "pop" : 10394, "state" : "FL" }
+{ "_id" : "34630", "city" : "CLEARWATER", "loc" : [ -82.822281, 27.984526 ], "pop" : 6231, "state" : "FL" }
+{ "_id" : "34635", "city" : "BELLEAIR BEACH", "loc" : [ -82.840486, 27.917605 ], "pop" : 7736, "state" : "FL" }
+{ "_id" : "34639", "city" : "LAND O LAKES", "loc" : [ -82.45471999999999, 28.225849 ], "pop" : 11815, "state" : "FL" }
+{ "_id" : "34640", "city" : "BELLEAIR BLUFFS", "loc" : [ -82.80197800000001, 27.915835 ], "pop" : 22793, "state" : "FL" }
+{ "_id" : "34641", "city" : "LARGO", "loc" : [ -82.75937, 27.907547 ], "pop" : 24087, "state" : "FL" }
+{ "_id" : "34642", "city" : "SEMINOLE", "loc" : [ -82.796896, 27.844571 ], "pop" : 24078, "state" : "FL" }
+{ "_id" : "34643", "city" : "LARGO", "loc" : [ -82.762806, 27.880334 ], "pop" : 17707, "state" : "FL" }
+{ "_id" : "34644", "city" : "LARGO", "loc" : [ -82.82628699999999, 27.883597 ], "pop" : 20162, "state" : "FL" }
+{ "_id" : "34646", "city" : "LARGO", "loc" : [ -82.826978, 27.852906 ], "pop" : 11284, "state" : "FL" }
+{ "_id" : "34647", "city" : "LARGO", "loc" : [ -82.758701, 27.851549 ], "pop" : 15130, "state" : "FL" }
+{ "_id" : "34648", "city" : "LARGO", "loc" : [ -82.795946, 27.884391 ], "pop" : 13347, "state" : "FL" }
+{ "_id" : "34652", "city" : "NEW PORT RICHEY", "loc" : [ -82.732721, 28.232574 ], "pop" : 22422, "state" : "FL" }
+{ "_id" : "34653", "city" : "NEW PORT RICHEY", "loc" : [ -82.6986, 28.244398 ], "pop" : 26729, "state" : "FL" }
+{ "_id" : "34654", "city" : "NEW PORT RICHEY", "loc" : [ -82.626423, 28.302201 ], "pop" : 13750, "state" : "FL" }
+{ "_id" : "34655", "city" : "NEW PORT RICHEY", "loc" : [ -82.680729, 28.212898 ], "pop" : 13849, "state" : "FL" }
+{ "_id" : "34665", "city" : "PINELLAS PARK", "loc" : [ -82.71335000000001, 27.840313 ], "pop" : 24459, "state" : "FL" }
+{ "_id" : "34666", "city" : "PINELLAS PARK", "loc" : [ -82.70935299999999, 27.860742 ], "pop" : 19840, "state" : "FL" }
+{ "_id" : "34667", "city" : "HUDSON", "loc" : [ -82.675669, 28.364763 ], "pop" : 26410, "state" : "FL" }
+{ "_id" : "34668", "city" : "PORT RICHEY", "loc" : [ -82.692714, 28.301148 ], "pop" : 39471, "state" : "FL" }
+{ "_id" : "34669", "city" : "HUDSON", "loc" : [ -82.628793, 28.350634 ], "pop" : 8577, "state" : "FL" }
+{ "_id" : "34677", "city" : "OLDSMAR", "loc" : [ -82.68477799999999, 28.046035 ], "pop" : 12858, "state" : "FL" }
+{ "_id" : "34683", "city" : "PALM HARBOR", "loc" : [ -82.758488, 28.066248 ], "pop" : 42350, "state" : "FL" }
+{ "_id" : "34684", "city" : "LAKE TARPON", "loc" : [ -82.726573, 28.073963 ], "pop" : 21753, "state" : "FL" }
+{ "_id" : "34685", "city" : "PALM HARBOR", "loc" : [ -82.69635700000001, 28.096725 ], "pop" : 2278, "state" : "FL" }
+{ "_id" : "34689", "city" : "TARPON SPRINGS", "loc" : [ -82.74302299999999, 28.138465 ], "pop" : 26381, "state" : "FL" }
+{ "_id" : "34690", "city" : "HOLIDAY", "loc" : [ -82.727935, 28.191273 ], "pop" : 11980, "state" : "FL" }
+{ "_id" : "34691", "city" : "HOLIDAY", "loc" : [ -82.755965, 28.191336 ], "pop" : 16548, "state" : "FL" }
+{ "_id" : "34695", "city" : "SAFETY HARBOR", "loc" : [ -82.696658, 28.009608 ], "pop" : 16853, "state" : "FL" }
+{ "_id" : "34698", "city" : "DUNEDIN", "loc" : [ -82.77943399999999, 28.028382 ], "pop" : 15304, "state" : "FL" }
+{ "_id" : "34705", "city" : "ASTATULA", "loc" : [ -81.71947299999999, 28.708754 ], "pop" : 1831, "state" : "FL" }
+{ "_id" : "34711", "city" : "CLERMONT", "loc" : [ -81.757407, 28.552541 ], "pop" : 15109, "state" : "FL" }
+{ "_id" : "34731", "city" : "FRUITLAND PARK", "loc" : [ -81.899755, 28.863949 ], "pop" : 8513, "state" : "FL" }
+{ "_id" : "34736", "city" : "GROVELAND", "loc" : [ -81.874526, 28.564445 ], "pop" : 8692, "state" : "FL" }
+{ "_id" : "34737", "city" : "HOWEY IN THE HIL", "loc" : [ -81.78998300000001, 28.709818 ], "pop" : 1370, "state" : "FL" }
+{ "_id" : "34739", "city" : "KENANSVILLE", "loc" : [ -81.050049, 27.876698 ], "pop" : 736, "state" : "FL" }
+{ "_id" : "34741", "city" : "KISSIMMEE", "loc" : [ -81.42420799999999, 28.305056 ], "pop" : 23576, "state" : "FL" }
+{ "_id" : "34743", "city" : "BUENA VENTURA LA", "loc" : [ -81.356044, 28.329656 ], "pop" : 14287, "state" : "FL" }
+{ "_id" : "34744", "city" : "KISSIMMEE", "loc" : [ -81.368122, 28.307807 ], "pop" : 21101, "state" : "FL" }
+{ "_id" : "34746", "city" : "KISSIMMEE", "loc" : [ -81.467478, 28.26796 ], "pop" : 12922, "state" : "FL" }
+{ "_id" : "34748", "city" : "LEESBURG", "loc" : [ -81.885772, 28.807965 ], "pop" : 21309, "state" : "FL" }
+{ "_id" : "34756", "city" : "MONTVERDE", "loc" : [ -81.679368, 28.597153 ], "pop" : 2216, "state" : "FL" }
+{ "_id" : "34758", "city" : "KISSIMMEE", "loc" : [ -81.487014, 28.198436 ], "pop" : 6306, "state" : "FL" }
+{ "_id" : "34759", "city" : "POINCIANA", "loc" : [ -81.458984, 28.124786 ], "pop" : 2430, "state" : "FL" }
+{ "_id" : "34761", "city" : "OCOEE", "loc" : [ -81.532618, 28.583685 ], "pop" : 14171, "state" : "FL" }
+{ "_id" : "34762", "city" : "OKAHUMPKA", "loc" : [ -81.883949, 28.737257 ], "pop" : 1779, "state" : "FL" }
+{ "_id" : "34769", "city" : "SAINT CLOUD", "loc" : [ -81.287626, 28.247992 ], "pop" : 15024, "state" : "FL" }
+{ "_id" : "34771", "city" : "SAINT CLOUD", "loc" : [ -81.200311, 28.27301 ], "pop" : 5870, "state" : "FL" }
+{ "_id" : "34772", "city" : "SAINT CLOUD", "loc" : [ -81.264493, 28.190518 ], "pop" : 6041, "state" : "FL" }
+{ "_id" : "34773", "city" : "SAINT CLOUD", "loc" : [ -81.01755199999999, 28.129295 ], "pop" : 1000, "state" : "FL" }
+{ "_id" : "34785", "city" : "WILDWOOD", "loc" : [ -82.03473, 28.845353 ], "pop" : 10604, "state" : "FL" }
+{ "_id" : "34786", "city" : "WINDERMERE", "loc" : [ -81.535411, 28.50061 ], "pop" : 5725, "state" : "FL" }
+{ "_id" : "34787", "city" : "WINTER GARDEN", "loc" : [ -81.591127, 28.542321 ], "pop" : 18939, "state" : "FL" }
+{ "_id" : "34788", "city" : "HAINES CREEK", "loc" : [ -81.781159, 28.85744 ], "pop" : 12883, "state" : "FL" }
+{ "_id" : "34797", "city" : "YALAHA", "loc" : [ -81.826324, 28.744443 ], "pop" : 1061, "state" : "FL" }
+{ "_id" : "34945", "city" : "FORT PIERCE", "loc" : [ -80.443963, 27.438233 ], "pop" : 3711, "state" : "FL" }
+{ "_id" : "34946", "city" : "FORT PIERCE", "loc" : [ -80.35996, 27.50077 ], "pop" : 10873, "state" : "FL" }
+{ "_id" : "34947", "city" : "FORT PIERCE", "loc" : [ -80.359185, 27.449281 ], "pop" : 10882, "state" : "FL" }
+{ "_id" : "34949", "city" : "FORT PIERCE", "loc" : [ -80.26146799999999, 27.389594 ], "pop" : 8853, "state" : "FL" }
+{ "_id" : "34950", "city" : "FORT PIERCE", "loc" : [ -80.3385, 27.448567 ], "pop" : 19708, "state" : "FL" }
+{ "_id" : "34951", "city" : "FORT PIERCE", "loc" : [ -80.40519500000001, 27.539097 ], "pop" : 6821, "state" : "FL" }
+{ "_id" : "34952", "city" : "PORT SAINT LUCIE", "loc" : [ -80.297971, 27.288895 ], "pop" : 23437, "state" : "FL" }
+{ "_id" : "34953", "city" : "PORT SAINT LUCIE", "loc" : [ -80.379323, 27.262506 ], "pop" : 11796, "state" : "FL" }
+{ "_id" : "34956", "city" : "INDIANTOWN", "loc" : [ -80.480277, 27.061461 ], "pop" : 7823, "state" : "FL" }
+{ "_id" : "34957", "city" : "JENSEN BEACH", "loc" : [ -80.227656, 27.235568 ], "pop" : 13656, "state" : "FL" }
+{ "_id" : "34972", "city" : "BASINGER", "loc" : [ -80.847853, 27.311532 ], "pop" : 14955, "state" : "FL" }
+{ "_id" : "34974", "city" : "OKEECHOBEE", "loc" : [ -80.84103, 27.200224 ], "pop" : 18122, "state" : "FL" }
+{ "_id" : "34981", "city" : "FORT PIERCE", "loc" : [ -80.362257, 27.404882 ], "pop" : 3243, "state" : "FL" }
+{ "_id" : "34982", "city" : "FORT PIERCE", "loc" : [ -80.32463300000001, 27.390764 ], "pop" : 20061, "state" : "FL" }
+{ "_id" : "34983", "city" : "PORT SAINT LUCIE", "loc" : [ -80.345029, 27.309444 ], "pop" : 22031, "state" : "FL" }
+{ "_id" : "34984", "city" : "PORT SAINT LUCIE", "loc" : [ -80.338936, 27.265476 ], "pop" : 7091, "state" : "FL" }
+{ "_id" : "34986", "city" : "PORT SAINT LUCIE", "loc" : [ -80.40304500000001, 27.32148 ], "pop" : 610, "state" : "FL" }
+{ "_id" : "34987", "city" : "PORT SAINT LUCIE", "loc" : [ -80.477052, 27.260595 ], "pop" : 67, "state" : "FL" }
+{ "_id" : "34988", "city" : "PORT SAINT LUCIE", "loc" : [ -80.51725999999999, 27.323233 ], "pop" : 416, "state" : "FL" }
+{ "_id" : "34990", "city" : "PALM CITY", "loc" : [ -80.291646, 27.165646 ], "pop" : 13225, "state" : "FL" }
+{ "_id" : "34994", "city" : "STUART", "loc" : [ -80.25378600000001, 27.196834 ], "pop" : 14524, "state" : "FL" }
+{ "_id" : "34996", "city" : "STUART", "loc" : [ -80.21637800000001, 27.192857 ], "pop" : 7410, "state" : "FL" }
+{ "_id" : "34997", "city" : "STUART", "loc" : [ -80.212937, 27.139817 ], "pop" : 25374, "state" : "FL" }
+{ "_id" : "35004", "city" : "ACMAR", "loc" : [ -86.51557, 33.584132 ], "pop" : 6055, "state" : "AL" }
+{ "_id" : "35005", "city" : "ADAMSVILLE", "loc" : [ -86.959727, 33.588437 ], "pop" : 10616, "state" : "AL" }
+{ "_id" : "35006", "city" : "ADGER", "loc" : [ -87.167455, 33.434277 ], "pop" : 3205, "state" : "AL" }
+{ "_id" : "35007", "city" : "KEYSTONE", "loc" : [ -86.812861, 33.236868 ], "pop" : 14218, "state" : "AL" }
+{ "_id" : "35010", "city" : "NEW SITE", "loc" : [ -85.951086, 32.941445 ], "pop" : 19942, "state" : "AL" }
+{ "_id" : "35014", "city" : "ALPINE", "loc" : [ -86.208934, 33.331165 ], "pop" : 3062, "state" : "AL" }
+{ "_id" : "35016", "city" : "ARAB", "loc" : [ -86.489638, 34.328339 ], "pop" : 13650, "state" : "AL" }
+{ "_id" : "35019", "city" : "BAILEYTON", "loc" : [ -86.62129899999999, 34.268298 ], "pop" : 1781, "state" : "AL" }
+{ "_id" : "35020", "city" : "BESSEMER", "loc" : [ -86.947547, 33.409002 ], "pop" : 40549, "state" : "AL" }
+{ "_id" : "35023", "city" : "HUEYTOWN", "loc" : [ -86.999607, 33.414625 ], "pop" : 39677, "state" : "AL" }
+{ "_id" : "35031", "city" : "BLOUNTSVILLE", "loc" : [ -86.568628, 34.092937 ], "pop" : 9058, "state" : "AL" }
+{ "_id" : "35033", "city" : "BREMEN", "loc" : [ -87.00428100000001, 33.973664 ], "pop" : 3448, "state" : "AL" }
+{ "_id" : "35034", "city" : "BRENT", "loc" : [ -87.211387, 32.93567 ], "pop" : 3791, "state" : "AL" }
+{ "_id" : "35035", "city" : "BRIERFIELD", "loc" : [ -86.951672, 33.042747 ], "pop" : 1282, "state" : "AL" }
+{ "_id" : "35040", "city" : "CALERA", "loc" : [ -86.755987, 33.1098 ], "pop" : 4675, "state" : "AL" }
+{ "_id" : "35042", "city" : "CENTREVILLE", "loc" : [ -87.11924, 32.950324 ], "pop" : 4902, "state" : "AL" }
+{ "_id" : "35043", "city" : "CHELSEA", "loc" : [ -86.614132, 33.371582 ], "pop" : 4781, "state" : "AL" }
+{ "_id" : "35044", "city" : "COOSA PINES", "loc" : [ -86.337622, 33.266928 ], "pop" : 7985, "state" : "AL" }
+{ "_id" : "35045", "city" : "CLANTON", "loc" : [ -86.642472, 32.835532 ], "pop" : 13990, "state" : "AL" }
+{ "_id" : "35049", "city" : "CLEVELAND", "loc" : [ -86.559355, 33.992106 ], "pop" : 2369, "state" : "AL" }
+{ "_id" : "35051", "city" : "COLUMBIANA", "loc" : [ -86.616145, 33.176964 ], "pop" : 4486, "state" : "AL" }
+{ "_id" : "35053", "city" : "CRANE HILL", "loc" : [ -87.048395, 34.082117 ], "pop" : 2270, "state" : "AL" }
+{ "_id" : "35054", "city" : "CROPWELL", "loc" : [ -86.28002600000001, 33.506448 ], "pop" : 4171, "state" : "AL" }
+{ "_id" : "35055", "city" : "CULLMAN", "loc" : [ -86.82977700000001, 34.176146 ], "pop" : 31708, "state" : "AL" }
+{ "_id" : "35061", "city" : "DOLOMITE", "loc" : [ -86.956435, 33.465424 ], "pop" : 1476, "state" : "AL" }
+{ "_id" : "35062", "city" : "DORA", "loc" : [ -87.040148, 33.734947 ], "pop" : 11017, "state" : "AL" }
+{ "_id" : "35063", "city" : "EMPIRE", "loc" : [ -87.016139, 33.825589 ], "pop" : 2429, "state" : "AL" }
+{ "_id" : "35064", "city" : "FAIRFIELD", "loc" : [ -86.918262, 33.473494 ], "pop" : 12106, "state" : "AL" }
+{ "_id" : "35068", "city" : "COALBURG", "loc" : [ -86.813614, 33.611283 ], "pop" : 5909, "state" : "AL" }
+{ "_id" : "35071", "city" : "GARDENDALE", "loc" : [ -86.822481, 33.71891 ], "pop" : 17968, "state" : "AL" }
+{ "_id" : "35072", "city" : "GOODWATER", "loc" : [ -86.078149, 33.074642 ], "pop" : 3813, "state" : "AL" }
+{ "_id" : "35073", "city" : "ALDEN", "loc" : [ -86.948221, 33.63356 ], "pop" : 4429, "state" : "AL" }
+{ "_id" : "35077", "city" : "HANCEVILLE", "loc" : [ -86.78484400000001, 34.051569 ], "pop" : 10186, "state" : "AL" }
+{ "_id" : "35078", "city" : "HARPERSVILLE", "loc" : [ -86.429441, 33.36746 ], "pop" : 4905, "state" : "AL" }
+{ "_id" : "35079", "city" : "HAYDEN", "loc" : [ -86.81767000000001, 33.885806 ], "pop" : 6533, "state" : "AL" }
+{ "_id" : "35080", "city" : "HELENA", "loc" : [ -86.81378599999999, 33.316978 ], "pop" : 9938, "state" : "AL" }
+{ "_id" : "35083", "city" : "HOLLY POND", "loc" : [ -86.617441, 34.190085 ], "pop" : 3838, "state" : "AL" }
+{ "_id" : "35085", "city" : "JEMISON", "loc" : [ -86.718052, 32.980539 ], "pop" : 7202, "state" : "AL" }
+{ "_id" : "35087", "city" : "JOPPA", "loc" : [ -86.551939, 34.283739 ], "pop" : 987, "state" : "AL" }
+{ "_id" : "35089", "city" : "KELLYTON", "loc" : [ -86.04839699999999, 32.979068 ], "pop" : 1584, "state" : "AL" }
+{ "_id" : "35091", "city" : "KIMBERLY", "loc" : [ -86.80841700000001, 33.768355 ], "pop" : 1045, "state" : "AL" }
+{ "_id" : "35094", "city" : "LEEDS", "loc" : [ -86.57482400000001, 33.528333 ], "pop" : 10421, "state" : "AL" }
+{ "_id" : "35096", "city" : "LINCOLN", "loc" : [ -86.111152, 33.605913 ], "pop" : 5033, "state" : "AL" }
+{ "_id" : "35098", "city" : "LOGAN", "loc" : [ -87.038115, 34.184079 ], "pop" : 2379, "state" : "AL" }
+{ "_id" : "35111", "city" : "MC CALLA", "loc" : [ -87.102379, 33.284546 ], "pop" : 8147, "state" : "AL" }
+{ "_id" : "35114", "city" : "MAYLENE", "loc" : [ -86.87274499999999, 33.231694 ], "pop" : 3727, "state" : "AL" }
+{ "_id" : "35115", "city" : "MONTEVALLO", "loc" : [ -86.862228, 33.124765 ], "pop" : 11638, "state" : "AL" }
+{ "_id" : "35116", "city" : "MORRIS", "loc" : [ -86.77255100000001, 33.739172 ], "pop" : 3622, "state" : "AL" }
+{ "_id" : "35117", "city" : "MOUNT OLIVE", "loc" : [ -86.87170999999999, 33.67678 ], "pop" : 3841, "state" : "AL" }
+{ "_id" : "35118", "city" : "SYLVAN SPRINGS", "loc" : [ -87.043998, 33.540696 ], "pop" : 3948, "state" : "AL" }
+{ "_id" : "35120", "city" : "ODENVILLE", "loc" : [ -86.408952, 33.675611 ], "pop" : 1123, "state" : "AL" }
+{ "_id" : "35121", "city" : "ONEONTA", "loc" : [ -86.474118, 33.925858 ], "pop" : 8956, "state" : "AL" }
+{ "_id" : "35124", "city" : "INDIAN SPRINGS", "loc" : [ -86.80617599999999, 33.31046 ], "pop" : 7412, "state" : "AL" }
+{ "_id" : "35125", "city" : "PELL CITY", "loc" : [ -86.34315100000001, 33.597889 ], "pop" : 17981, "state" : "AL" }
+{ "_id" : "35126", "city" : "DIXIANA", "loc" : [ -86.656542, 33.708131 ], "pop" : 17068, "state" : "AL" }
+{ "_id" : "35127", "city" : "PLEASANT GROVE", "loc" : [ -86.976586, 33.488336 ], "pop" : 8458, "state" : "AL" }
+{ "_id" : "35130", "city" : "QUINTON", "loc" : [ -87.10066, 33.656065 ], "pop" : 2198, "state" : "AL" }
+{ "_id" : "35131", "city" : "RAGLAND", "loc" : [ -86.1619, 33.736677 ], "pop" : 2797, "state" : "AL" }
+{ "_id" : "35133", "city" : "REMLAP", "loc" : [ -86.641662, 33.846204 ], "pop" : 6013, "state" : "AL" }
+{ "_id" : "35135", "city" : "RIVERSIDE", "loc" : [ -86.198341, 33.608832 ], "pop" : 1004, "state" : "AL" }
+{ "_id" : "35136", "city" : "ROCKFORD", "loc" : [ -86.24000599999999, 32.877957 ], "pop" : 1819, "state" : "AL" }
+{ "_id" : "35143", "city" : "SHELBY", "loc" : [ -86.553606, 33.078483 ], "pop" : 1846, "state" : "AL" }
+{ "_id" : "35146", "city" : "SPRINGVILLE", "loc" : [ -86.439407, 33.738647 ], "pop" : 8723, "state" : "AL" }
+{ "_id" : "35147", "city" : "STERRETT", "loc" : [ -86.491732, 33.446103 ], "pop" : 617, "state" : "AL" }
+{ "_id" : "35148", "city" : "SUMITON", "loc" : [ -87.044545, 33.768005 ], "pop" : 3066, "state" : "AL" }
+{ "_id" : "35150", "city" : "SYLACAUGA", "loc" : [ -86.27125700000001, 33.171675 ], "pop" : 24424, "state" : "AL" }
+{ "_id" : "35160", "city" : "TALLADEGA", "loc" : [ -86.11335200000001, 33.435445 ], "pop" : 29778, "state" : "AL" }
+{ "_id" : "35171", "city" : "THORSBY", "loc" : [ -86.746724, 32.923755 ], "pop" : 4131, "state" : "AL" }
+{ "_id" : "35172", "city" : "TRAFFORD", "loc" : [ -86.743414, 33.819038 ], "pop" : 909, "state" : "AL" }
+{ "_id" : "35173", "city" : "TRUSSVILLE", "loc" : [ -86.598068, 33.633932 ], "pop" : 13367, "state" : "AL" }
+{ "_id" : "35175", "city" : "UNION GROVE", "loc" : [ -86.462793, 34.409345 ], "pop" : 4921, "state" : "AL" }
+{ "_id" : "35176", "city" : "VANDIVER", "loc" : [ -86.501278, 33.480704 ], "pop" : 1066, "state" : "AL" }
+{ "_id" : "35178", "city" : "VINCENT", "loc" : [ -86.39942499999999, 33.401049 ], "pop" : 295, "state" : "AL" }
+{ "_id" : "35179", "city" : "VINEMONT", "loc" : [ -86.91251200000001, 34.262121 ], "pop" : 8852, "state" : "AL" }
+{ "_id" : "35180", "city" : "WARRIOR", "loc" : [ -86.819849, 33.852862 ], "pop" : 530, "state" : "AL" }
+{ "_id" : "35183", "city" : "WEOGUFKA", "loc" : [ -86.304203, 33.02381 ], "pop" : 1249, "state" : "AL" }
+{ "_id" : "35184", "city" : "WEST BLOCTON", "loc" : [ -87.13694, 33.142431 ], "pop" : 5276, "state" : "AL" }
+{ "_id" : "35186", "city" : "WILSONVILLE", "loc" : [ -86.529894, 33.229255 ], "pop" : 5224, "state" : "AL" }
+{ "_id" : "35188", "city" : "WOODSTOCK", "loc" : [ -87.16346900000001, 33.169808 ], "pop" : 691, "state" : "AL" }
+{ "_id" : "35203", "city" : "BIRMINGHAM", "loc" : [ -86.80662599999999, 33.520994 ], "pop" : 4064, "state" : "AL" }
+{ "_id" : "35204", "city" : "BIRMINGHAM", "loc" : [ -86.837198, 33.51795 ], "pop" : 18193, "state" : "AL" }
+{ "_id" : "35205", "city" : "BIRMINGHAM", "loc" : [ -86.805937, 33.495144 ], "pop" : 23024, "state" : "AL" }
+{ "_id" : "35206", "city" : "BIRMINGHAM", "loc" : [ -86.719854, 33.567797 ], "pop" : 22050, "state" : "AL" }
+{ "_id" : "35207", "city" : "BIRMINGHAM", "loc" : [ -86.815344, 33.559383 ], "pop" : 13901, "state" : "AL" }
+{ "_id" : "35208", "city" : "BIRMINGHAM", "loc" : [ -86.879884, 33.497658 ], "pop" : 19328, "state" : "AL" }
+{ "_id" : "35209", "city" : "HOMEWOOD", "loc" : [ -86.806738, 33.469624 ], "pop" : 24973, "state" : "AL" }
+{ "_id" : "35210", "city" : "IRONDALE", "loc" : [ -86.685697, 33.532797 ], "pop" : 15047, "state" : "AL" }
+{ "_id" : "35211", "city" : "BIRMINGHAM", "loc" : [ -86.85903999999999, 33.481565 ], "pop" : 35836, "state" : "AL" }
+{ "_id" : "35212", "city" : "BIRMINGHAM", "loc" : [ -86.74952399999999, 33.540883 ], "pop" : 17865, "state" : "AL" }
+{ "_id" : "35213", "city" : "CRESTLINE HEIGHT", "loc" : [ -86.742108, 33.508195 ], "pop" : 13191, "state" : "AL" }
+{ "_id" : "35214", "city" : "BIRMINGHAM", "loc" : [ -86.886989, 33.555445 ], "pop" : 23293, "state" : "AL" }
+{ "_id" : "35215", "city" : "CENTER POINT", "loc" : [ -86.693197, 33.635447 ], "pop" : 43862, "state" : "AL" }
+{ "_id" : "35216", "city" : "VESTAVIA HILLS", "loc" : [ -86.790425, 33.41531 ], "pop" : 29224, "state" : "AL" }
+{ "_id" : "35217", "city" : "BIRMINGHAM", "loc" : [ -86.764995, 33.5887 ], "pop" : 17366, "state" : "AL" }
+{ "_id" : "35218", "city" : "BIRMINGHAM", "loc" : [ -86.892993, 33.505972 ], "pop" : 12137, "state" : "AL" }
+{ "_id" : "35221", "city" : "BIRMINGHAM", "loc" : [ -86.89349300000001, 33.452316 ], "pop" : 5850, "state" : "AL" }
+{ "_id" : "35222", "city" : "BIRMINGHAM", "loc" : [ -86.76657899999999, 33.521859 ], "pop" : 10035, "state" : "AL" }
+{ "_id" : "35223", "city" : "MOUNTAIN BROOK", "loc" : [ -86.73658399999999, 33.488726 ], "pop" : 11117, "state" : "AL" }
+{ "_id" : "35224", "city" : "BIRMINGHAM", "loc" : [ -86.93419299999999, 33.519126 ], "pop" : 7894, "state" : "AL" }
+{ "_id" : "35226", "city" : "BLUFF PARK", "loc" : [ -86.83125699999999, 33.403675 ], "pop" : 23992, "state" : "AL" }
+{ "_id" : "35228", "city" : "MIDFIELD", "loc" : [ -86.914703, 33.462446 ], "pop" : 9294, "state" : "AL" }
+{ "_id" : "35233", "city" : "BIRMINGHAM", "loc" : [ -86.800257, 33.506161 ], "pop" : 842, "state" : "AL" }
+{ "_id" : "35234", "city" : "BIRMINGHAM", "loc" : [ -86.80685, 33.53775 ], "pop" : 10928, "state" : "AL" }
+{ "_id" : "35235", "city" : "CENTER POINT", "loc" : [ -86.661051, 33.618045 ], "pop" : 15873, "state" : "AL" }
+{ "_id" : "35242", "city" : "SHOAL CREEK", "loc" : [ -86.705511, 33.401559 ], "pop" : 16228, "state" : "AL" }
+{ "_id" : "35243", "city" : "CAHABA HEIGHTS", "loc" : [ -86.74367599999999, 33.446053 ], "pop" : 13091, "state" : "AL" }
+{ "_id" : "35244", "city" : "HOOVER", "loc" : [ -86.776381, 33.371776 ], "pop" : 9758, "state" : "AL" }
+{ "_id" : "35401", "city" : "TUSCALOOSA", "loc" : [ -87.56266599999999, 33.196891 ], "pop" : 42124, "state" : "AL" }
+{ "_id" : "35404", "city" : "HOLT", "loc" : [ -87.488079, 33.210914 ], "pop" : 21997, "state" : "AL" }
+{ "_id" : "35405", "city" : "TUSCALOOSA", "loc" : [ -87.51443500000001, 33.161704 ], "pop" : 23663, "state" : "AL" }
+{ "_id" : "35406", "city" : "TUSCALOOSA", "loc" : [ -87.536035, 33.272174 ], "pop" : 12578, "state" : "AL" }
+{ "_id" : "35441", "city" : "STEWART", "loc" : [ -87.708558, 32.872354 ], "pop" : 1745, "state" : "AL" }
+{ "_id" : "35442", "city" : "ALICEVILLE", "loc" : [ -88.16668900000001, 33.122813 ], "pop" : 5196, "state" : "AL" }
+{ "_id" : "35443", "city" : "BOLIGEE", "loc" : [ -88.026652, 32.774646 ], "pop" : 1073, "state" : "AL" }
+{ "_id" : "35444", "city" : "BROOKWOOD", "loc" : [ -87.30902500000001, 33.277523 ], "pop" : 2319, "state" : "AL" }
+{ "_id" : "35446", "city" : "BUHL", "loc" : [ -87.718886, 33.249448 ], "pop" : 1662, "state" : "AL" }
+{ "_id" : "35447", "city" : "CARROLLTON", "loc" : [ -88.132122, 33.248506 ], "pop" : 5007, "state" : "AL" }
+{ "_id" : "35452", "city" : "COKER", "loc" : [ -87.636528, 33.252612 ], "pop" : 5747, "state" : "AL" }
+{ "_id" : "35453", "city" : "COTTONDALE", "loc" : [ -87.387051, 33.176667 ], "pop" : 4727, "state" : "AL" }
+{ "_id" : "35456", "city" : "DUNCANVILLE", "loc" : [ -87.49497700000001, 33.082815 ], "pop" : 5514, "state" : "AL" }
+{ "_id" : "35457", "city" : "ECHOLA", "loc" : [ -87.807202, 33.316559 ], "pop" : 223, "state" : "AL" }
+{ "_id" : "35458", "city" : "ELROD", "loc" : [ -87.801429, 33.343678 ], "pop" : 809, "state" : "AL" }
+{ "_id" : "35459", "city" : "EMELLE", "loc" : [ -88.305747, 32.754963 ], "pop" : 491, "state" : "AL" }
+{ "_id" : "35460", "city" : "EPES", "loc" : [ -88.16144300000001, 32.763371 ], "pop" : 1391, "state" : "AL" }
+{ "_id" : "35461", "city" : "ETHELSVILLE", "loc" : [ -88.221987, 33.386816 ], "pop" : 719, "state" : "AL" }
+{ "_id" : "35462", "city" : "EUTAW", "loc" : [ -87.930297, 32.888871 ], "pop" : 6586, "state" : "AL" }
+{ "_id" : "35463", "city" : "FOSTERS", "loc" : [ -87.735688, 33.135859 ], "pop" : 2100, "state" : "AL" }
+{ "_id" : "35464", "city" : "GAINESVILLE", "loc" : [ -88.271558, 32.908364 ], "pop" : 1051, "state" : "AL" }
+{ "_id" : "35466", "city" : "GORDO", "loc" : [ -87.900504, 33.346917 ], "pop" : 4333, "state" : "AL" }
+{ "_id" : "35469", "city" : "KNOXVILLE", "loc" : [ -87.791855, 32.982423 ], "pop" : 373, "state" : "AL" }
+{ "_id" : "35470", "city" : "COATOPA", "loc" : [ -88.173592, 32.588509 ], "pop" : 6055, "state" : "AL" }
+{ "_id" : "35474", "city" : "CYPRESS", "loc" : [ -87.615134, 32.978853 ], "pop" : 2659, "state" : "AL" }
+{ "_id" : "35476", "city" : "NORTHPORT", "loc" : [ -87.591441, 33.283425 ], "pop" : 20114, "state" : "AL" }
+{ "_id" : "35480", "city" : "RALPH", "loc" : [ -87.744984, 33.062868 ], "pop" : 927, "state" : "AL" }
+{ "_id" : "35481", "city" : "REFORM", "loc" : [ -88.02027699999999, 33.395945 ], "pop" : 4062, "state" : "AL" }
+{ "_id" : "35490", "city" : "VANCE", "loc" : [ -87.257362, 33.17498 ], "pop" : 1234, "state" : "AL" }
+{ "_id" : "35501", "city" : "JASPER", "loc" : [ -87.249144, 33.871672 ], "pop" : 30600, "state" : "AL" }
+{ "_id" : "35540", "city" : "ADDISON", "loc" : [ -87.194766, 34.205571 ], "pop" : 3263, "state" : "AL" }
+{ "_id" : "35541", "city" : "ARLEY", "loc" : [ -87.182761, 34.063234 ], "pop" : 2645, "state" : "AL" }
+{ "_id" : "35542", "city" : "BANKSTON", "loc" : [ -87.68965, 33.70083 ], "pop" : 651, "state" : "AL" }
+{ "_id" : "35543", "city" : "BEAR CREEK", "loc" : [ -87.686083, 34.213469 ], "pop" : 3748, "state" : "AL" }
+{ "_id" : "35544", "city" : "BEAVERTON", "loc" : [ -88.01567, 33.942877 ], "pop" : 1014, "state" : "AL" }
+{ "_id" : "35546", "city" : "BERRY", "loc" : [ -87.622563, 33.694485 ], "pop" : 4887, "state" : "AL" }
+{ "_id" : "35548", "city" : "BRILLIANT", "loc" : [ -87.756315, 34.037702 ], "pop" : 2515, "state" : "AL" }
+{ "_id" : "35549", "city" : "CARBON HILL", "loc" : [ -87.540328, 33.909252 ], "pop" : 3597, "state" : "AL" }
+{ "_id" : "35550", "city" : "CORDOVA", "loc" : [ -87.18406, 33.768033 ], "pop" : 5273, "state" : "AL" }
+{ "_id" : "35552", "city" : "DETROIT", "loc" : [ -88.16063, 34.010874 ], "pop" : 938, "state" : "AL" }
+{ "_id" : "35553", "city" : "DOUBLE SPRINGS", "loc" : [ -87.397431, 34.138682 ], "pop" : 4797, "state" : "AL" }
+{ "_id" : "35554", "city" : "ELDRIDGE", "loc" : [ -87.61939700000001, 33.931546 ], "pop" : 421, "state" : "AL" }
+{ "_id" : "35555", "city" : "FAYETTE", "loc" : [ -87.834647, 33.697397 ], "pop" : 10776, "state" : "AL" }
+{ "_id" : "35563", "city" : "GUIN", "loc" : [ -87.90237999999999, 33.967624 ], "pop" : 3948, "state" : "AL" }
+{ "_id" : "35564", "city" : "HACKLEBURG", "loc" : [ -87.86076199999999, 34.267803 ], "pop" : 2828, "state" : "AL" }
+{ "_id" : "35565", "city" : "HALEYVILLE", "loc" : [ -87.593811, 34.231423 ], "pop" : 9141, "state" : "AL" }
+{ "_id" : "35570", "city" : "HAMILTON", "loc" : [ -88.008521, 34.153413 ], "pop" : 11184, "state" : "AL" }
+{ "_id" : "35571", "city" : "HODGES", "loc" : [ -87.959023, 34.341664 ], "pop" : 798, "state" : "AL" }
+{ "_id" : "35572", "city" : "HOUSTON", "loc" : [ -87.26183, 34.118042 ], "pop" : 429, "state" : "AL" }
+{ "_id" : "35574", "city" : "KENNEDY", "loc" : [ -88.05172, 33.574964 ], "pop" : 3618, "state" : "AL" }
+{ "_id" : "35575", "city" : "LYNN", "loc" : [ -87.53981400000001, 34.052984 ], "pop" : 1778, "state" : "AL" }
+{ "_id" : "35576", "city" : "MILLPORT", "loc" : [ -88.200003, 33.54013 ], "pop" : 2286, "state" : "AL" }
+{ "_id" : "35578", "city" : "NAUVOO", "loc" : [ -87.43244900000001, 33.929859 ], "pop" : 5004, "state" : "AL" }
+{ "_id" : "35579", "city" : "OAKMAN", "loc" : [ -87.368574, 33.700174 ], "pop" : 3700, "state" : "AL" }
+{ "_id" : "35580", "city" : "PARRISH", "loc" : [ -87.265773, 33.721307 ], "pop" : 4775, "state" : "AL" }
+{ "_id" : "35581", "city" : "PHIL CAMPBELL", "loc" : [ -87.715431, 34.347018 ], "pop" : 5345, "state" : "AL" }
+{ "_id" : "35582", "city" : "RED BAY", "loc" : [ -88.112914, 34.451259 ], "pop" : 5159, "state" : "AL" }
+{ "_id" : "35585", "city" : "SPRUCE PINE", "loc" : [ -87.712149, 34.384796 ], "pop" : 465, "state" : "AL" }
+{ "_id" : "35586", "city" : "SULLIGENT", "loc" : [ -88.150774, 33.8549 ], "pop" : 4489, "state" : "AL" }
+{ "_id" : "35587", "city" : "TOWNLEY", "loc" : [ -87.437248, 33.84702 ], "pop" : 1819, "state" : "AL" }
+{ "_id" : "35592", "city" : "VERNON", "loc" : [ -88.097919, 33.761285 ], "pop" : 4752, "state" : "AL" }
+{ "_id" : "35593", "city" : "VINA", "loc" : [ -88.077422, 34.37116 ], "pop" : 888, "state" : "AL" }
+{ "_id" : "35594", "city" : "WINFIELD", "loc" : [ -87.79716000000001, 33.930256 ], "pop" : 6750, "state" : "AL" }
+{ "_id" : "35601", "city" : "DECATUR", "loc" : [ -86.98868, 34.589599 ], "pop" : 36696, "state" : "AL" }
+{ "_id" : "35603", "city" : "DECATUR", "loc" : [ -87.000389, 34.548417 ], "pop" : 17861, "state" : "AL" }
+{ "_id" : "35610", "city" : "ANDERSON", "loc" : [ -87.272327, 34.951777 ], "pop" : 2039, "state" : "AL" }
+{ "_id" : "35611", "city" : "ATHENS", "loc" : [ -86.970733, 34.803604 ], "pop" : 35441, "state" : "AL" }
+{ "_id" : "35616", "city" : "CHEROKEE", "loc" : [ -87.97244499999999, 34.744188 ], "pop" : 4811, "state" : "AL" }
+{ "_id" : "35618", "city" : "COURTLAND", "loc" : [ -87.314255, 34.671866 ], "pop" : 2733, "state" : "AL" }
+{ "_id" : "35619", "city" : "DANVILLE", "loc" : [ -87.05318699999999, 34.452189 ], "pop" : 4614, "state" : "AL" }
+{ "_id" : "35620", "city" : "ELKMONT", "loc" : [ -86.91045200000001, 34.915241 ], "pop" : 8013, "state" : "AL" }
+{ "_id" : "35621", "city" : "EVA", "loc" : [ -86.704427, 34.347778 ], "pop" : 3977, "state" : "AL" }
+{ "_id" : "35622", "city" : "FALKVILLE", "loc" : [ -86.91308600000001, 34.347653 ], "pop" : 5392, "state" : "AL" }
+{ "_id" : "35630", "city" : "FLORENCE", "loc" : [ -87.655985, 34.830547 ], "pop" : 38725, "state" : "AL" }
+{ "_id" : "35633", "city" : "FLORENCE", "loc" : [ -87.739778, 34.882471 ], "pop" : 16478, "state" : "AL" }
+{ "_id" : "35640", "city" : "HARTSELLE", "loc" : [ -86.924235, 34.448206 ], "pop" : 17963, "state" : "AL" }
+{ "_id" : "35643", "city" : "HILLSBORO", "loc" : [ -87.180379, 34.64763 ], "pop" : 1967, "state" : "AL" }
+{ "_id" : "35645", "city" : "KILLEN", "loc" : [ -87.508185, 34.901632 ], "pop" : 11758, "state" : "AL" }
+{ "_id" : "35646", "city" : "LEIGHTON", "loc" : [ -87.522133, 34.710982 ], "pop" : 3046, "state" : "AL" }
+{ "_id" : "35647", "city" : "LESTER", "loc" : [ -87.143396, 34.918364 ], "pop" : 3108, "state" : "AL" }
+{ "_id" : "35648", "city" : "LEXINGTON", "loc" : [ -87.393519, 34.955924 ], "pop" : 2241, "state" : "AL" }
+{ "_id" : "35650", "city" : "MOULTON", "loc" : [ -87.222385, 34.505836 ], "pop" : 17288, "state" : "AL" }
+{ "_id" : "35651", "city" : "MOUNT HOPE", "loc" : [ -87.451453, 34.462969 ], "pop" : 1821, "state" : "AL" }
+{ "_id" : "35652", "city" : "ROGERSVILLE", "loc" : [ -87.323671, 34.849544 ], "pop" : 6521, "state" : "AL" }
+{ "_id" : "35653", "city" : "RUSSELLVILLE", "loc" : [ -87.72572599999999, 34.506568 ], "pop" : 17767, "state" : "AL" }
+{ "_id" : "35660", "city" : "SHEFFIELD", "loc" : [ -87.697057, 34.757829 ], "pop" : 10685, "state" : "AL" }
+{ "_id" : "35661", "city" : "MUSCLE SHOALS", "loc" : [ -87.630443, 34.756136 ], "pop" : 11777, "state" : "AL" }
+{ "_id" : "35670", "city" : "SOMERVILLE", "loc" : [ -86.80093100000001, 34.499548 ], "pop" : 5184, "state" : "AL" }
+{ "_id" : "35671", "city" : "TANNER", "loc" : [ -86.989152, 34.713037 ], "pop" : 2578, "state" : "AL" }
+{ "_id" : "35672", "city" : "TOWN CREEK", "loc" : [ -87.42619500000001, 34.649138 ], "pop" : 9049, "state" : "AL" }
+{ "_id" : "35673", "city" : "TRINITY", "loc" : [ -87.09126999999999, 34.591771 ], "pop" : 1758, "state" : "AL" }
+{ "_id" : "35674", "city" : "TUSCUMBIA", "loc" : [ -87.68325900000001, 34.687432 ], "pop" : 17880, "state" : "AL" }
+{ "_id" : "35677", "city" : "WATERLOO", "loc" : [ -87.962412, 34.93568 ], "pop" : 1899, "state" : "AL" }
+{ "_id" : "35739", "city" : "ARDMORE", "loc" : [ -86.83461200000001, 34.980447 ], "pop" : 1898, "state" : "AL" }
+{ "_id" : "35740", "city" : "BRIDGEPORT", "loc" : [ -85.727681, 34.944638 ], "pop" : 3988, "state" : "AL" }
+{ "_id" : "35741", "city" : "BROWNSBORO", "loc" : [ -86.468703, 34.716733 ], "pop" : 1793, "state" : "AL" }
+{ "_id" : "35744", "city" : "DUTTON", "loc" : [ -85.906729, 34.604558 ], "pop" : 2948, "state" : "AL" }
+{ "_id" : "35745", "city" : "ESTILLFORK", "loc" : [ -86.171571, 34.913017 ], "pop" : 718, "state" : "AL" }
+{ "_id" : "35746", "city" : "FACKLER", "loc" : [ -85.98464800000001, 34.82589 ], "pop" : 396, "state" : "AL" }
+{ "_id" : "35747", "city" : "GRANT", "loc" : [ -86.259041, 34.495902 ], "pop" : 8345, "state" : "AL" }
+{ "_id" : "35748", "city" : "GURLEY", "loc" : [ -86.39402800000001, 34.713964 ], "pop" : 4642, "state" : "AL" }
+{ "_id" : "35749", "city" : "HARVEST", "loc" : [ -86.74992899999999, 34.82732 ], "pop" : 5701, "state" : "AL" }
+{ "_id" : "35750", "city" : "HAZEL GREEN", "loc" : [ -86.593484, 34.949627 ], "pop" : 7751, "state" : "AL" }
+{ "_id" : "35751", "city" : "HOLLYTREE", "loc" : [ -86.233627, 34.798979 ], "pop" : 260, "state" : "AL" }
+{ "_id" : "35752", "city" : "HOLLYWOOD", "loc" : [ -85.95317300000001, 34.730428 ], "pop" : 2038, "state" : "AL" }
+{ "_id" : "35754", "city" : "LACEYS SPRING", "loc" : [ -86.612869, 34.499647 ], "pop" : 7040, "state" : "AL" }
+{ "_id" : "35755", "city" : "LANGSTON", "loc" : [ -86.10563, 34.497831 ], "pop" : 1041, "state" : "AL" }
+{ "_id" : "35758", "city" : "TRIANA", "loc" : [ -86.750951, 34.713409 ], "pop" : 24398, "state" : "AL" }
+{ "_id" : "35759", "city" : "MERIDIANVILLE", "loc" : [ -86.578879, 34.861779 ], "pop" : 2597, "state" : "AL" }
+{ "_id" : "35760", "city" : "NEW HOPE", "loc" : [ -86.3961, 34.549445 ], "pop" : 4075, "state" : "AL" }
+{ "_id" : "35761", "city" : "NEW MARKET", "loc" : [ -86.448742, 34.899991 ], "pop" : 5825, "state" : "AL" }
+{ "_id" : "35763", "city" : "BIG COVE", "loc" : [ -86.466577, 34.612859 ], "pop" : 3156, "state" : "AL" }
+{ "_id" : "35764", "city" : "PAINT ROCK", "loc" : [ -86.332562, 34.667122 ], "pop" : 553, "state" : "AL" }
+{ "_id" : "35765", "city" : "PISGAH", "loc" : [ -85.803044, 34.688601 ], "pop" : 3717, "state" : "AL" }
+{ "_id" : "35766", "city" : "PRINCETON", "loc" : [ -86.250068, 34.840217 ], "pop" : 273, "state" : "AL" }
+{ "_id" : "35768", "city" : "HYTOP", "loc" : [ -86.05133600000001, 34.67227 ], "pop" : 16934, "state" : "AL" }
+{ "_id" : "35771", "city" : "SECTION", "loc" : [ -85.99400199999999, 34.543275 ], "pop" : 2590, "state" : "AL" }
+{ "_id" : "35772", "city" : "STEVENSON", "loc" : [ -85.850803, 34.876885 ], "pop" : 5210, "state" : "AL" }
+{ "_id" : "35773", "city" : "TONEY", "loc" : [ -86.699951, 34.911644 ], "pop" : 5953, "state" : "AL" }
+{ "_id" : "35774", "city" : "TRENTON", "loc" : [ -86.291264, 34.740065 ], "pop" : 381, "state" : "AL" }
+{ "_id" : "35775", "city" : "VALHERMOSO SPRIN", "loc" : [ -86.678, 34.538145 ], "pop" : 667, "state" : "AL" }
+{ "_id" : "35776", "city" : "WOODVILLE", "loc" : [ -86.22960999999999, 34.668927 ], "pop" : 2222, "state" : "AL" }
+{ "_id" : "35801", "city" : "HUNTSVILLE", "loc" : [ -86.567318, 34.726866 ], "pop" : 25513, "state" : "AL" }
+{ "_id" : "35802", "city" : "HUNTSVILLE", "loc" : [ -86.56034699999999, 34.667922 ], "pop" : 21069, "state" : "AL" }
+{ "_id" : "35803", "city" : "HUNTSVILLE", "loc" : [ -86.55096, 34.620506 ], "pop" : 23380, "state" : "AL" }
+{ "_id" : "35805", "city" : "HUNTSVILLE", "loc" : [ -86.61649300000001, 34.705943 ], "pop" : 24637, "state" : "AL" }
+{ "_id" : "35806", "city" : "HUNTSVILLE", "loc" : [ -86.670411, 34.744765 ], "pop" : 10121, "state" : "AL" }
+{ "_id" : "35808", "city" : "HUNTSVILLE", "loc" : [ -86.65382099999999, 34.684525 ], "pop" : 4988, "state" : "AL" }
+{ "_id" : "35810", "city" : "HUNTSVILLE", "loc" : [ -86.60906300000001, 34.778378 ], "pop" : 32896, "state" : "AL" }
+{ "_id" : "35811", "city" : "HUNTSVILLE", "loc" : [ -86.543786, 34.778949 ], "pop" : 19008, "state" : "AL" }
+{ "_id" : "35816", "city" : "HUNTSVILLE", "loc" : [ -86.624948, 34.738864 ], "pop" : 13736, "state" : "AL" }
+{ "_id" : "35824", "city" : "HUNTSVILLE", "loc" : [ -86.72948599999999, 34.658321 ], "pop" : 770, "state" : "AL" }
+{ "_id" : "35901", "city" : "SOUTHSIDE", "loc" : [ -86.010279, 33.997248 ], "pop" : 44165, "state" : "AL" }
+{ "_id" : "35903", "city" : "HOKES BLUFF", "loc" : [ -85.928724, 33.997057 ], "pop" : 20057, "state" : "AL" }
+{ "_id" : "35904", "city" : "GADSDEN", "loc" : [ -86.04947900000001, 34.021694 ], "pop" : 7002, "state" : "AL" }
+{ "_id" : "35905", "city" : "GLENCOE", "loc" : [ -85.92758600000001, 33.956787 ], "pop" : 4256, "state" : "AL" }
+{ "_id" : "35950", "city" : "ALBERTVILLE", "loc" : [ -86.206447, 34.273859 ], "pop" : 21033, "state" : "AL" }
+{ "_id" : "35952", "city" : "SNEAD", "loc" : [ -86.35087900000001, 34.042916 ], "pop" : 9472, "state" : "AL" }
+{ "_id" : "35953", "city" : "ASHVILLE", "loc" : [ -86.255167, 33.837366 ], "pop" : 5988, "state" : "AL" }
+{ "_id" : "35954", "city" : "ATTALLA", "loc" : [ -86.096717, 34.029597 ], "pop" : 11904, "state" : "AL" }
+{ "_id" : "35957", "city" : "BOAZ", "loc" : [ -86.148003, 34.173686 ], "pop" : 16955, "state" : "AL" }
+{ "_id" : "35958", "city" : "BRYANT", "loc" : [ -85.632445, 34.945026 ], "pop" : 1700, "state" : "AL" }
+{ "_id" : "35959", "city" : "CEDAR BLUFF", "loc" : [ -85.60256699999999, 34.241662 ], "pop" : 3574, "state" : "AL" }
+{ "_id" : "35960", "city" : "CENTRE", "loc" : [ -85.609229, 34.111592 ], "pop" : 10294, "state" : "AL" }
+{ "_id" : "35961", "city" : "COLLINSVILLE", "loc" : [ -85.861969, 34.267957 ], "pop" : 3245, "state" : "AL" }
+{ "_id" : "35962", "city" : "CROSSVILLE", "loc" : [ -86.030575, 34.258784 ], "pop" : 4874, "state" : "AL" }
+{ "_id" : "35963", "city" : "DAWSON", "loc" : [ -85.92916099999999, 34.356838 ], "pop" : 1531, "state" : "AL" }
+{ "_id" : "35966", "city" : "FLAT ROCK", "loc" : [ -85.708372, 34.807598 ], "pop" : 2141, "state" : "AL" }
+{ "_id" : "35967", "city" : "FORT PAYNE", "loc" : [ -85.712394, 34.436792 ], "pop" : 15893, "state" : "AL" }
+{ "_id" : "35971", "city" : "FYFFE", "loc" : [ -85.928849, 34.437284 ], "pop" : 3453, "state" : "AL" }
+{ "_id" : "35972", "city" : "GALLANT", "loc" : [ -86.234606, 33.997586 ], "pop" : 337, "state" : "AL" }
+{ "_id" : "35973", "city" : "GAYLESVILLE", "loc" : [ -85.558893, 34.357324 ], "pop" : 2291, "state" : "AL" }
+{ "_id" : "35974", "city" : "GERALDINE", "loc" : [ -86.04039299999999, 34.343864 ], "pop" : 3291, "state" : "AL" }
+{ "_id" : "35975", "city" : "GROVEOAK", "loc" : [ -86.04002300000001, 34.435874 ], "pop" : 1098, "state" : "AL" }
+{ "_id" : "35976", "city" : "GUNTERSVILLE", "loc" : [ -86.305463, 34.32193 ], "pop" : 11234, "state" : "AL" }
+{ "_id" : "35978", "city" : "HENAGAR", "loc" : [ -85.72738099999999, 34.618604 ], "pop" : 2973, "state" : "AL" }
+{ "_id" : "35979", "city" : "HIGDON", "loc" : [ -85.622507, 34.873247 ], "pop" : 1324, "state" : "AL" }
+{ "_id" : "35980", "city" : "HORTON", "loc" : [ -86.317318, 34.190033 ], "pop" : 4195, "state" : "AL" }
+{ "_id" : "35981", "city" : "IDER", "loc" : [ -85.641577, 34.735059 ], "pop" : 5161, "state" : "AL" }
+{ "_id" : "35983", "city" : "LEESBURG", "loc" : [ -85.77051, 34.191083 ], "pop" : 3189, "state" : "AL" }
+{ "_id" : "35984", "city" : "MENTONE", "loc" : [ -85.57772799999999, 34.587236 ], "pop" : 2099, "state" : "AL" }
+{ "_id" : "35986", "city" : "RAINSVILLE", "loc" : [ -85.844605, 34.498884 ], "pop" : 7498, "state" : "AL" }
+{ "_id" : "35987", "city" : "STEELE", "loc" : [ -86.22892899999999, 33.941679 ], "pop" : 1830, "state" : "AL" }
+{ "_id" : "35988", "city" : "SYLVANIA", "loc" : [ -85.79212800000001, 34.558962 ], "pop" : 2318, "state" : "AL" }
+{ "_id" : "35989", "city" : "VALLEY HEAD", "loc" : [ -85.627208, 34.5697 ], "pop" : 1211, "state" : "AL" }
+{ "_id" : "36003", "city" : "AUTAUGAVILLE", "loc" : [ -86.714938, 32.462462 ], "pop" : 2641, "state" : "AL" }
+{ "_id" : "36004", "city" : "EUFAULA", "loc" : [ -85.23965699999999, 31.786701 ], "pop" : 2669, "state" : "AL" }
+{ "_id" : "36005", "city" : "BANKS", "loc" : [ -85.79984399999999, 31.836792 ], "pop" : 1857, "state" : "AL" }
+{ "_id" : "36006", "city" : "BILLINGSLEY", "loc" : [ -86.716301, 32.610578 ], "pop" : 1869, "state" : "AL" }
+{ "_id" : "36009", "city" : "BRANTLEY", "loc" : [ -86.274343, 31.570963 ], "pop" : 2623, "state" : "AL" }
+{ "_id" : "36010", "city" : "BRUNDIDGE", "loc" : [ -85.817668, 31.701324 ], "pop" : 4320, "state" : "AL" }
+{ "_id" : "36013", "city" : "CECIL", "loc" : [ -86.011241, 32.300891 ], "pop" : 407, "state" : "AL" }
+{ "_id" : "36016", "city" : "CLAYTON", "loc" : [ -85.45093199999999, 31.887413 ], "pop" : 3106, "state" : "AL" }
+{ "_id" : "36017", "city" : "CLIO", "loc" : [ -85.590419, 31.68521 ], "pop" : 3178, "state" : "AL" }
+{ "_id" : "36022", "city" : "DEATSVILLE", "loc" : [ -86.338211, 32.613405 ], "pop" : 5913, "state" : "AL" }
+{ "_id" : "36024", "city" : "ECLECTIC", "loc" : [ -86.031614, 32.65419 ], "pop" : 6105, "state" : "AL" }
+{ "_id" : "36025", "city" : "ELMORE", "loc" : [ -86.31613400000001, 32.545378 ], "pop" : 3114, "state" : "AL" }
+{ "_id" : "36026", "city" : "EQUALITY", "loc" : [ -86.105064, 32.813908 ], "pop" : 1121, "state" : "AL" }
+{ "_id" : "36027", "city" : "EUFAULA", "loc" : [ -85.165605, 31.905063 ], "pop" : 14189, "state" : "AL" }
+{ "_id" : "36028", "city" : "DOZIER", "loc" : [ -86.366315, 31.506614 ], "pop" : 741, "state" : "AL" }
+{ "_id" : "36029", "city" : "FITZPATRICK", "loc" : [ -85.888329, 32.151607 ], "pop" : 736, "state" : "AL" }
+{ "_id" : "36030", "city" : "FOREST HOME", "loc" : [ -86.786377, 31.85318 ], "pop" : 1528, "state" : "AL" }
+{ "_id" : "36031", "city" : "FORT DAVIS", "loc" : [ -85.700688, 32.28945 ], "pop" : 891, "state" : "AL" }
+{ "_id" : "36032", "city" : "FORT DEPOSIT", "loc" : [ -86.576142, 31.995979 ], "pop" : 2435, "state" : "AL" }
+{ "_id" : "36033", "city" : "GEORGIANA", "loc" : [ -86.733965, 31.628662 ], "pop" : 3672, "state" : "AL" }
+{ "_id" : "36034", "city" : "GLENWOOD", "loc" : [ -86.17097200000001, 31.664143 ], "pop" : 109, "state" : "AL" }
+{ "_id" : "36035", "city" : "GOSHEN", "loc" : [ -86.104851, 31.82497 ], "pop" : 2056, "state" : "AL" }
+{ "_id" : "36036", "city" : "GRADY", "loc" : [ -86.12924599999999, 32.019397 ], "pop" : 1811, "state" : "AL" }
+{ "_id" : "36037", "city" : "GREENVILLE", "loc" : [ -86.622919, 31.810036 ], "pop" : 15476, "state" : "AL" }
+{ "_id" : "36038", "city" : "GANTT", "loc" : [ -86.419836, 31.416909 ], "pop" : 3298, "state" : "AL" }
+{ "_id" : "36039", "city" : "HARDAWAY", "loc" : [ -85.883837, 32.312939 ], "pop" : 354, "state" : "AL" }
+{ "_id" : "36040", "city" : "HAYNEVILLE", "loc" : [ -86.654994, 32.195707 ], "pop" : 5010, "state" : "AL" }
+{ "_id" : "36041", "city" : "HIGHLAND HOME", "loc" : [ -86.297111, 31.928292 ], "pop" : 3068, "state" : "AL" }
+{ "_id" : "36042", "city" : "HONORAVILLE", "loc" : [ -86.39806400000001, 31.878397 ], "pop" : 838, "state" : "AL" }
+{ "_id" : "36043", "city" : "HOPE HULL", "loc" : [ -86.39318900000001, 32.224256 ], "pop" : 2961, "state" : "AL" }
+{ "_id" : "36046", "city" : "LAPINE", "loc" : [ -86.27853399999999, 31.985423 ], "pop" : 338, "state" : "AL" }
+{ "_id" : "36047", "city" : "LETOHATCHEE", "loc" : [ -86.488013, 32.086199 ], "pop" : 2348, "state" : "AL" }
+{ "_id" : "36048", "city" : "LOUISVILLE", "loc" : [ -85.55806200000001, 31.794262 ], "pop" : 2279, "state" : "AL" }
+{ "_id" : "36049", "city" : "LUVERNE", "loc" : [ -86.256601, 31.70739 ], "pop" : 4274, "state" : "AL" }
+{ "_id" : "36051", "city" : "MARBURY", "loc" : [ -86.510138, 32.639373 ], "pop" : 3573, "state" : "AL" }
+{ "_id" : "36052", "city" : "MATHEWS", "loc" : [ -86.041262, 32.128288 ], "pop" : 836, "state" : "AL" }
+{ "_id" : "36053", "city" : "MIDWAY", "loc" : [ -85.53152300000001, 32.09552 ], "pop" : 1873, "state" : "AL" }
+{ "_id" : "36054", "city" : "MILLBROOK", "loc" : [ -86.364125, 32.499485 ], "pop" : 9049, "state" : "AL" }
+{ "_id" : "36061", "city" : "PEROTE", "loc" : [ -85.74773, 32.003459 ], "pop" : 1792, "state" : "AL" }
+{ "_id" : "36064", "city" : "PIKE ROAD", "loc" : [ -86.09589, 32.335705 ], "pop" : 3398, "state" : "AL" }
+{ "_id" : "36066", "city" : "PRATTVILLE", "loc" : [ -86.42997, 32.478695 ], "pop" : 11059, "state" : "AL" }
+{ "_id" : "36067", "city" : "PRATTVILLE", "loc" : [ -86.48307200000001, 32.471501 ], "pop" : 16536, "state" : "AL" }
+{ "_id" : "36069", "city" : "RAMER", "loc" : [ -86.246329, 32.067745 ], "pop" : 1712, "state" : "AL" }
+{ "_id" : "36071", "city" : "RUTLEDGE", "loc" : [ -86.34846400000001, 31.755867 ], "pop" : 1976, "state" : "AL" }
+{ "_id" : "36075", "city" : "SHORTER", "loc" : [ -85.91616, 32.383585 ], "pop" : 1876, "state" : "AL" }
+{ "_id" : "36078", "city" : "TALLASSEE", "loc" : [ -85.89781000000001, 32.550997 ], "pop" : 12046, "state" : "AL" }
+{ "_id" : "36080", "city" : "TITUS", "loc" : [ -86.239334, 32.690019 ], "pop" : 2683, "state" : "AL" }
+{ "_id" : "36081", "city" : "TROY", "loc" : [ -85.965493, 31.794471 ], "pop" : 19358, "state" : "AL" }
+{ "_id" : "36083", "city" : "TUSKEGEE", "loc" : [ -85.68606, 32.431623 ], "pop" : 10687, "state" : "AL" }
+{ "_id" : "36088", "city" : "TUSKEGEE INSTITU", "loc" : [ -85.714848, 32.417699 ], "pop" : 6915, "state" : "AL" }
+{ "_id" : "36089", "city" : "UNION SPRINGS", "loc" : [ -85.678746, 32.166252 ], "pop" : 7555, "state" : "AL" }
+{ "_id" : "36091", "city" : "VERBENA", "loc" : [ -86.543753, 32.759565 ], "pop" : 3702, "state" : "AL" }
+{ "_id" : "36092", "city" : "WETUMPKA", "loc" : [ -86.188039, 32.54509 ], "pop" : 13725, "state" : "AL" }
+{ "_id" : "36104", "city" : "MONTGOMERY", "loc" : [ -86.30812899999999, 32.373037 ], "pop" : 17086, "state" : "AL" }
+{ "_id" : "36105", "city" : "MONTGOMERY", "loc" : [ -86.31044900000001, 32.32573 ], "pop" : 16486, "state" : "AL" }
+{ "_id" : "36106", "city" : "MONTGOMERY", "loc" : [ -86.267278, 32.354268 ], "pop" : 15744, "state" : "AL" }
+{ "_id" : "36107", "city" : "MONTGOMERY", "loc" : [ -86.27988499999999, 32.380405 ], "pop" : 10345, "state" : "AL" }
+{ "_id" : "36108", "city" : "MONTGOMERY", "loc" : [ -86.352904, 32.341682 ], "pop" : 30780, "state" : "AL" }
+{ "_id" : "36109", "city" : "MONTGOMERY", "loc" : [ -86.243394, 32.383443 ], "pop" : 25282, "state" : "AL" }
+{ "_id" : "36110", "city" : "MONTGOMERY", "loc" : [ -86.274997, 32.421686 ], "pop" : 12551, "state" : "AL" }
+{ "_id" : "36111", "city" : "MONTGOMERY", "loc" : [ -86.27154299999999, 32.337363 ], "pop" : 11600, "state" : "AL" }
+{ "_id" : "36113", "city" : "MAXWELL A F B", "loc" : [ -86.35584799999999, 32.388133 ], "pop" : 2788, "state" : "AL" }
+{ "_id" : "36115", "city" : "GUNTER AFS", "loc" : [ -86.247327, 32.406814 ], "pop" : 1348, "state" : "AL" }
+{ "_id" : "36116", "city" : "MONTGOMERY", "loc" : [ -86.24205600000001, 32.312943 ], "pop" : 32314, "state" : "AL" }
+{ "_id" : "36117", "city" : "MONTGOMERY", "loc" : [ -86.18329900000001, 32.373568 ], "pop" : 21623, "state" : "AL" }
+{ "_id" : "36201", "city" : "ANNISTON", "loc" : [ -85.83815199999999, 33.653896 ], "pop" : 38370, "state" : "AL" }
+{ "_id" : "36203", "city" : "OXFORD", "loc" : [ -85.83347000000001, 33.596829 ], "pop" : 12407, "state" : "AL" }
+{ "_id" : "36205", "city" : "FORT MC CLELLAN", "loc" : [ -85.801467, 33.710168 ], "pop" : 4128, "state" : "AL" }
+{ "_id" : "36206", "city" : "ANNISTON", "loc" : [ -85.838904, 33.719124 ], "pop" : 10915, "state" : "AL" }
+{ "_id" : "36250", "city" : "ALEXANDRIA", "loc" : [ -85.892447, 33.780785 ], "pop" : 5776, "state" : "AL" }
+{ "_id" : "36251", "city" : "ASHLAND", "loc" : [ -85.828976, 33.247363 ], "pop" : 4518, "state" : "AL" }
+{ "_id" : "36255", "city" : "CRAGFORD", "loc" : [ -85.710797, 33.217148 ], "pop" : 796, "state" : "AL" }
+{ "_id" : "36256", "city" : "DAVISTON", "loc" : [ -85.75383100000001, 33.033471 ], "pop" : 2334, "state" : "AL" }
+{ "_id" : "36258", "city" : "DELTA", "loc" : [ -85.67927899999999, 33.457303 ], "pop" : 1405, "state" : "AL" }
+{ "_id" : "36260", "city" : "EASTABOGA", "loc" : [ -85.96075, 33.603132 ], "pop" : 3999, "state" : "AL" }
+{ "_id" : "36262", "city" : "FRUITHURST", "loc" : [ -85.43814, 33.771732 ], "pop" : 1473, "state" : "AL" }
+{ "_id" : "36263", "city" : "GRAHAM", "loc" : [ -85.334034, 33.462976 ], "pop" : 374, "state" : "AL" }
+{ "_id" : "36264", "city" : "HEFLIN", "loc" : [ -85.588471, 33.611515 ], "pop" : 6577, "state" : "AL" }
+{ "_id" : "36265", "city" : "JACKSONVILLE", "loc" : [ -85.77518000000001, 33.830966 ], "pop" : 16438, "state" : "AL" }
+{ "_id" : "36266", "city" : "LINEVILLE", "loc" : [ -85.73460900000001, 33.328613 ], "pop" : 4345, "state" : "AL" }
+{ "_id" : "36267", "city" : "MILLERVILLE", "loc" : [ -85.96900100000001, 33.158959 ], "pop" : 863, "state" : "AL" }
+{ "_id" : "36268", "city" : "MUNFORD", "loc" : [ -85.936322, 33.540987 ], "pop" : 4998, "state" : "AL" }
+{ "_id" : "36269", "city" : "MUSCADINE", "loc" : [ -85.378907, 33.752913 ], "pop" : 265, "state" : "AL" }
+{ "_id" : "36270", "city" : "NEWELL", "loc" : [ -85.505925, 33.440172 ], "pop" : 2407, "state" : "AL" }
+{ "_id" : "36271", "city" : "OHATCHEE", "loc" : [ -86.025357, 33.778779 ], "pop" : 3369, "state" : "AL" }
+{ "_id" : "36272", "city" : "PIEDMONT", "loc" : [ -85.64599699999999, 33.838946 ], "pop" : 12921, "state" : "AL" }
+{ "_id" : "36273", "city" : "RANBURNE", "loc" : [ -85.378604, 33.561627 ], "pop" : 3696, "state" : "AL" }
+{ "_id" : "36274", "city" : "ROCK MILLS", "loc" : [ -85.357854, 33.156443 ], "pop" : 9430, "state" : "AL" }
+{ "_id" : "36276", "city" : "WADLEY", "loc" : [ -85.551344, 33.149192 ], "pop" : 1949, "state" : "AL" }
+{ "_id" : "36277", "city" : "WEAVER", "loc" : [ -85.810666, 33.756286 ], "pop" : 7453, "state" : "AL" }
+{ "_id" : "36278", "city" : "WEDOWEE", "loc" : [ -85.473737, 33.301854 ], "pop" : 3101, "state" : "AL" }
+{ "_id" : "36279", "city" : "WELLINGTON", "loc" : [ -85.915325, 33.863843 ], "pop" : 2137, "state" : "AL" }
+{ "_id" : "36280", "city" : "WOODLAND", "loc" : [ -85.353768, 33.355453 ], "pop" : 2291, "state" : "AL" }
+{ "_id" : "36301", "city" : "TAYLOR", "loc" : [ -85.418036, 31.202888 ], "pop" : 32689, "state" : "AL" }
+{ "_id" : "36303", "city" : "NAPIER FIELD", "loc" : [ -85.412462, 31.255239 ], "pop" : 32407, "state" : "AL" }
+{ "_id" : "36310", "city" : "ABBEVILLE", "loc" : [ -85.279044, 31.575479 ], "pop" : 5416, "state" : "AL" }
+{ "_id" : "36311", "city" : "ARITON", "loc" : [ -85.707716, 31.582996 ], "pop" : 1434, "state" : "AL" }
+{ "_id" : "36312", "city" : "ASHFORD", "loc" : [ -85.253488, 31.1888 ], "pop" : 5115, "state" : "AL" }
+{ "_id" : "36314", "city" : "BLACK", "loc" : [ -85.745634, 31.01318 ], "pop" : 183, "state" : "AL" }
+{ "_id" : "36316", "city" : "CHANCELLOR", "loc" : [ -85.91089700000001, 31.173379 ], "pop" : 620, "state" : "AL" }
+{ "_id" : "36317", "city" : "CLOPTON", "loc" : [ -85.482308, 31.602843 ], "pop" : 157, "state" : "AL" }
+{ "_id" : "36318", "city" : "COFFEE SPRINGS", "loc" : [ -85.918224, 31.138758 ], "pop" : 750, "state" : "AL" }
+{ "_id" : "36319", "city" : "COLUMBIA", "loc" : [ -85.145488, 31.335235 ], "pop" : 2934, "state" : "AL" }
+{ "_id" : "36320", "city" : "COTTONWOOD", "loc" : [ -85.375665, 31.098934 ], "pop" : 8517, "state" : "AL" }
+{ "_id" : "36322", "city" : "DALEVILLE", "loc" : [ -85.730473, 31.281091 ], "pop" : 8885, "state" : "AL" }
+{ "_id" : "36323", "city" : "ELBA", "loc" : [ -86.07772799999999, 31.41373 ], "pop" : 6662, "state" : "AL" }
+{ "_id" : "36330", "city" : "ENTERPRISE", "loc" : [ -85.842111, 31.340789 ], "pop" : 29102, "state" : "AL" }
+{ "_id" : "36340", "city" : "GENEVA", "loc" : [ -85.884748, 31.041445 ], "pop" : 5471, "state" : "AL" }
+{ "_id" : "36343", "city" : "GORDON", "loc" : [ -85.123412, 31.10019 ], "pop" : 2017, "state" : "AL" }
+{ "_id" : "36344", "city" : "HARTFORD", "loc" : [ -85.719204, 31.08598 ], "pop" : 4819, "state" : "AL" }
+{ "_id" : "36345", "city" : "HEADLAND", "loc" : [ -85.332277, 31.353406 ], "pop" : 4595, "state" : "AL" }
+{ "_id" : "36346", "city" : "JACK", "loc" : [ -86.043083, 31.552392 ], "pop" : 1517, "state" : "AL" }
+{ "_id" : "36349", "city" : "MALVERN", "loc" : [ -85.522327, 31.157528 ], "pop" : 1686, "state" : "AL" }
+{ "_id" : "36350", "city" : "MIDLAND CITY", "loc" : [ -85.51303299999999, 31.36716 ], "pop" : 4854, "state" : "AL" }
+{ "_id" : "36351", "city" : "NEW BROCKTON", "loc" : [ -85.940386, 31.36898 ], "pop" : 1809, "state" : "AL" }
+{ "_id" : "36352", "city" : "NEWTON", "loc" : [ -85.59922899999999, 31.331064 ], "pop" : 1660, "state" : "AL" }
+{ "_id" : "36353", "city" : "NEWVILLE", "loc" : [ -85.32874099999999, 31.440295 ], "pop" : 1525, "state" : "AL" }
+{ "_id" : "36360", "city" : "OZARK", "loc" : [ -85.643629, 31.439069 ], "pop" : 19017, "state" : "AL" }
+{ "_id" : "36362", "city" : "FORT RUCKER", "loc" : [ -85.721374, 31.348011 ], "pop" : 7607, "state" : "AL" }
+{ "_id" : "36370", "city" : "PANSEY", "loc" : [ -85.23854900000001, 31.131778 ], "pop" : 595, "state" : "AL" }
+{ "_id" : "36373", "city" : "SHORTERVILLE", "loc" : [ -85.14584000000001, 31.625627 ], "pop" : 2503, "state" : "AL" }
+{ "_id" : "36374", "city" : "SKIPPERVILLE", "loc" : [ -85.549578, 31.551588 ], "pop" : 1048, "state" : "AL" }
+{ "_id" : "36375", "city" : "SLOCOMB", "loc" : [ -85.582954, 31.095558 ], "pop" : 4504, "state" : "AL" }
+{ "_id" : "36376", "city" : "WEBB", "loc" : [ -85.254385, 31.265618 ], "pop" : 1810, "state" : "AL" }
+{ "_id" : "36401", "city" : "EVERGREEN", "loc" : [ -86.925771, 31.458009 ], "pop" : 8556, "state" : "AL" }
+{ "_id" : "36419", "city" : "ALLEN", "loc" : [ -87.66746000000001, 31.624266 ], "pop" : 0, "state" : "AL" }
+{ "_id" : "36420", "city" : "ANDALUSIA", "loc" : [ -86.49046800000001, 31.297142 ], "pop" : 16920, "state" : "AL" }
+{ "_id" : "36425", "city" : "BEATRICE", "loc" : [ -87.17191200000001, 31.727324 ], "pop" : 1620, "state" : "AL" }
+{ "_id" : "36426", "city" : "EAST BREWTON", "loc" : [ -87.067325, 31.118926 ], "pop" : 15479, "state" : "AL" }
+{ "_id" : "36432", "city" : "CASTLEBERRY", "loc" : [ -87.026754, 31.326113 ], "pop" : 2881, "state" : "AL" }
+{ "_id" : "36435", "city" : "COY", "loc" : [ -87.39255799999999, 31.888851 ], "pop" : 1109, "state" : "AL" }
+{ "_id" : "36436", "city" : "DICKINSON", "loc" : [ -87.65692900000001, 31.717167 ], "pop" : 272, "state" : "AL" }
+{ "_id" : "36441", "city" : "FLOMATON", "loc" : [ -87.26636499999999, 31.040233 ], "pop" : 3585, "state" : "AL" }
+{ "_id" : "36442", "city" : "FLORALA", "loc" : [ -86.338528, 31.017194 ], "pop" : 3421, "state" : "AL" }
+{ "_id" : "36444", "city" : "FRANKLIN", "loc" : [ -87.441237, 31.723815 ], "pop" : 154, "state" : "AL" }
+{ "_id" : "36445", "city" : "FRISCO CITY", "loc" : [ -87.381744, 31.423478 ], "pop" : 6179, "state" : "AL" }
+{ "_id" : "36446", "city" : "FULTON", "loc" : [ -87.708065, 31.790947 ], "pop" : 2163, "state" : "AL" }
+{ "_id" : "36451", "city" : "GROVE HILL", "loc" : [ -87.763571, 31.675502 ], "pop" : 4089, "state" : "AL" }
+{ "_id" : "36453", "city" : "KINSTON", "loc" : [ -86.069532, 31.262118 ], "pop" : 3523, "state" : "AL" }
+{ "_id" : "36454", "city" : "LENOX", "loc" : [ -87.19671, 31.327261 ], "pop" : 515, "state" : "AL" }
+{ "_id" : "36456", "city" : "MC KENZIE", "loc" : [ -86.735615, 31.54495 ], "pop" : 1222, "state" : "AL" }
+{ "_id" : "36460", "city" : "MONROEVILLE", "loc" : [ -87.340993, 31.51533 ], "pop" : 10492, "state" : "AL" }
+{ "_id" : "36467", "city" : "OPP", "loc" : [ -86.257105, 31.279861 ], "pop" : 9901, "state" : "AL" }
+{ "_id" : "36471", "city" : "PETERMAN", "loc" : [ -87.259984, 31.589953 ], "pop" : 1826, "state" : "AL" }
+{ "_id" : "36473", "city" : "RANGE", "loc" : [ -87.319739, 31.30169 ], "pop" : 208, "state" : "AL" }
+{ "_id" : "36474", "city" : "RED LEVEL", "loc" : [ -86.61208999999999, 31.439931 ], "pop" : 2005, "state" : "AL" }
+{ "_id" : "36475", "city" : "REPTON", "loc" : [ -87.172039, 31.425569 ], "pop" : 1750, "state" : "AL" }
+{ "_id" : "36477", "city" : "SAMSON", "loc" : [ -86.06741599999999, 31.104918 ], "pop" : 4790, "state" : "AL" }
+{ "_id" : "36480", "city" : "URIAH", "loc" : [ -87.57051800000001, 31.313467 ], "pop" : 1648, "state" : "AL" }
+{ "_id" : "36481", "city" : "VREDENBURGH", "loc" : [ -87.416184, 31.73443 ], "pop" : 2040, "state" : "AL" }
+{ "_id" : "36482", "city" : "WHATLEY", "loc" : [ -87.656502, 31.639453 ], "pop" : 790, "state" : "AL" }
+{ "_id" : "36483", "city" : "WING", "loc" : [ -86.56119, 31.148127 ], "pop" : 1583, "state" : "AL" }
+{ "_id" : "36502", "city" : "ATMORE", "loc" : [ -87.487347, 31.057245 ], "pop" : 15948, "state" : "AL" }
+{ "_id" : "36505", "city" : "AXIS", "loc" : [ -88.04273999999999, 31.006817 ], "pop" : 140, "state" : "AL" }
+{ "_id" : "36507", "city" : "BAY MINETTE", "loc" : [ -87.76443999999999, 30.86354 ], "pop" : 17816, "state" : "AL" }
+{ "_id" : "36509", "city" : "BAYOU LA BATRE", "loc" : [ -88.250697, 30.407983 ], "pop" : 4901, "state" : "AL" }
+{ "_id" : "36510", "city" : "BIGBEE", "loc" : [ -88.165294, 31.589072 ], "pop" : 264, "state" : "AL" }
+{ "_id" : "36511", "city" : "BON SECOUR", "loc" : [ -87.721355, 30.328883 ], "pop" : 2001, "state" : "AL" }
+{ "_id" : "36515", "city" : "CARLTON", "loc" : [ -87.837793, 31.322449 ], "pop" : 30, "state" : "AL" }
+{ "_id" : "36518", "city" : "CHATOM", "loc" : [ -88.269887, 31.487638 ], "pop" : 3094, "state" : "AL" }
+{ "_id" : "36521", "city" : "CHUNCHULA", "loc" : [ -88.13112599999999, 30.991178 ], "pop" : 1322, "state" : "AL" }
+{ "_id" : "36522", "city" : "CITRONELLE", "loc" : [ -88.254949, 31.042533 ], "pop" : 7233, "state" : "AL" }
+{ "_id" : "36523", "city" : "CODEN", "loc" : [ -88.16827600000001, 30.418834 ], "pop" : 3897, "state" : "AL" }
+{ "_id" : "36524", "city" : "COFFEEVILLE", "loc" : [ -88.07154199999999, 31.78428 ], "pop" : 1374, "state" : "AL" }
+{ "_id" : "36525", "city" : "CREOLA", "loc" : [ -88.017414, 30.901267 ], "pop" : 2569, "state" : "AL" }
+{ "_id" : "36526", "city" : "DAPHNE", "loc" : [ -87.889522, 30.61972 ], "pop" : 14607, "state" : "AL" }
+{ "_id" : "36527", "city" : "SPANISH FORT", "loc" : [ -87.88668, 30.695852 ], "pop" : 5486, "state" : "AL" }
+{ "_id" : "36528", "city" : "DAUPHIN ISLAND", "loc" : [ -88.109644, 30.252057 ], "pop" : 824, "state" : "AL" }
+{ "_id" : "36529", "city" : "DEER PARK", "loc" : [ -88.32731, 31.184892 ], "pop" : 723, "state" : "AL" }
+{ "_id" : "36530", "city" : "ELBERTA", "loc" : [ -87.58896, 30.394239 ], "pop" : 2551, "state" : "AL" }
+{ "_id" : "36532", "city" : "FAIRHOPE", "loc" : [ -87.883546, 30.50116 ], "pop" : 16331, "state" : "AL" }
+{ "_id" : "36535", "city" : "FOLEY", "loc" : [ -87.685737, 30.400664 ], "pop" : 8520, "state" : "AL" }
+{ "_id" : "36538", "city" : "FRANKVILLE", "loc" : [ -88.133185, 31.64684 ], "pop" : 472, "state" : "AL" }
+{ "_id" : "36539", "city" : "FRUITDALE", "loc" : [ -88.376597, 31.348843 ], "pop" : 848, "state" : "AL" }
+{ "_id" : "36540", "city" : "GAINESTOWN", "loc" : [ -87.682176, 31.425822 ], "pop" : 301, "state" : "AL" }
+{ "_id" : "36541", "city" : "GRAND BAY", "loc" : [ -88.32825, 30.498288 ], "pop" : 10344, "state" : "AL" }
+{ "_id" : "36542", "city" : "FORT MORGAN", "loc" : [ -87.712795, 30.268954 ], "pop" : 4930, "state" : "AL" }
+{ "_id" : "36544", "city" : "IRVINGTON", "loc" : [ -88.239563, 30.480241 ], "pop" : 6181, "state" : "AL" }
+{ "_id" : "36545", "city" : "JACKSON", "loc" : [ -87.867192, 31.513098 ], "pop" : 9679, "state" : "AL" }
+{ "_id" : "36548", "city" : "LEROY", "loc" : [ -87.968672, 31.491021 ], "pop" : 1086, "state" : "AL" }
+{ "_id" : "36549", "city" : "LILLIAN", "loc" : [ -87.474452, 30.39724 ], "pop" : 3833, "state" : "AL" }
+{ "_id" : "36550", "city" : "LITTLE RIVER", "loc" : [ -87.754796, 31.22459 ], "pop" : 649, "state" : "AL" }
+{ "_id" : "36551", "city" : "LOXLEY", "loc" : [ -87.75624000000001, 30.617964 ], "pop" : 2712, "state" : "AL" }
+{ "_id" : "36553", "city" : "MC INTOSH", "loc" : [ -88.051102, 31.236108 ], "pop" : 4211, "state" : "AL" }
+{ "_id" : "36555", "city" : "MAGNOLIA SPRINGS", "loc" : [ -87.785781, 30.394497 ], "pop" : 1088, "state" : "AL" }
+{ "_id" : "36558", "city" : "MILLRY", "loc" : [ -88.35587200000001, 31.626871 ], "pop" : 2825, "state" : "AL" }
+{ "_id" : "36560", "city" : "MOUNT VERNON", "loc" : [ -88.035044, 31.097375 ], "pop" : 5053, "state" : "AL" }
+{ "_id" : "36561", "city" : "ORANGE BEACH", "loc" : [ -87.555888, 30.290596 ], "pop" : 2549, "state" : "AL" }
+{ "_id" : "36562", "city" : "PERDIDO", "loc" : [ -87.62837399999999, 30.98058 ], "pop" : 986, "state" : "AL" }
+{ "_id" : "36567", "city" : "ROBERTSDALE", "loc" : [ -87.63726800000001, 30.561608 ], "pop" : 3519, "state" : "AL" }
+{ "_id" : "36569", "city" : "SAINT STEPHENS", "loc" : [ -88.052094, 31.533028 ], "pop" : 688, "state" : "AL" }
+{ "_id" : "36570", "city" : "SALITPA", "loc" : [ -87.95961800000001, 31.654667 ], "pop" : 896, "state" : "AL" }
+{ "_id" : "36571", "city" : "SARALAND", "loc" : [ -88.09338700000001, 30.833197 ], "pop" : 13151, "state" : "AL" }
+{ "_id" : "36572", "city" : "SATSUMA", "loc" : [ -88.05331200000001, 30.851628 ], "pop" : 6197, "state" : "AL" }
+{ "_id" : "36574", "city" : "SEMINOLE", "loc" : [ -87.46593799999999, 30.504806 ], "pop" : 606, "state" : "AL" }
+{ "_id" : "36575", "city" : "SEMMES", "loc" : [ -88.266705, 30.754408 ], "pop" : 9329, "state" : "AL" }
+{ "_id" : "36576", "city" : "SILVERHILL", "loc" : [ -87.745676, 30.522237 ], "pop" : 8001, "state" : "AL" }
+{ "_id" : "36579", "city" : "STOCKTON", "loc" : [ -87.86332299999999, 31.01293 ], "pop" : 1214, "state" : "AL" }
+{ "_id" : "36580", "city" : "SUMMERDALE", "loc" : [ -87.699183, 30.475225 ], "pop" : 881, "state" : "AL" }
+{ "_id" : "36582", "city" : "THEODORE", "loc" : [ -88.18074799999999, 30.544374 ], "pop" : 20185, "state" : "AL" }
+{ "_id" : "36583", "city" : "TIBBIE", "loc" : [ -88.266828, 31.373742 ], "pop" : 327, "state" : "AL" }
+{ "_id" : "36584", "city" : "VINEGAR BEND", "loc" : [ -88.386466, 31.25841 ], "pop" : 475, "state" : "AL" }
+{ "_id" : "36585", "city" : "WAGARVILLE", "loc" : [ -88.070519, 31.410205 ], "pop" : 1681, "state" : "AL" }
+{ "_id" : "36586", "city" : "WALKER SPRINGS", "loc" : [ -87.83535500000001, 31.626166 ], "pop" : 1001, "state" : "AL" }
+{ "_id" : "36587", "city" : "WILMER", "loc" : [ -88.333196, 30.813745 ], "pop" : 5905, "state" : "AL" }
+{ "_id" : "36602", "city" : "MOBILE", "loc" : [ -88.04530800000001, 30.688828 ], "pop" : 1263, "state" : "AL" }
+{ "_id" : "36603", "city" : "MOBILE", "loc" : [ -88.05622, 30.692141 ], "pop" : 12162, "state" : "AL" }
+{ "_id" : "36604", "city" : "MOBILE", "loc" : [ -88.067804, 30.681963 ], "pop" : 11498, "state" : "AL" }
+{ "_id" : "36605", "city" : "MOBILE", "loc" : [ -88.08464600000001, 30.634117 ], "pop" : 31621, "state" : "AL" }
+{ "_id" : "36606", "city" : "MOBILE", "loc" : [ -88.100909, 30.672899 ], "pop" : 18247, "state" : "AL" }
+{ "_id" : "36607", "city" : "MOBILE", "loc" : [ -88.10290000000001, 30.697486 ], "pop" : 8610, "state" : "AL" }
+{ "_id" : "36608", "city" : "MOBILE", "loc" : [ -88.18778399999999, 30.69636 ], "pop" : 37600, "state" : "AL" }
+{ "_id" : "36609", "city" : "MOBILE", "loc" : [ -88.161806, 30.660527 ], "pop" : 23687, "state" : "AL" }
+{ "_id" : "36610", "city" : "PRICHARD", "loc" : [ -88.083761, 30.737846 ], "pop" : 24919, "state" : "AL" }
+{ "_id" : "36611", "city" : "CHICKASAW", "loc" : [ -88.08497300000001, 30.766821 ], "pop" : 6660, "state" : "AL" }
+{ "_id" : "36612", "city" : "MOBILE", "loc" : [ -88.11311000000001, 30.751844 ], "pop" : 6096, "state" : "AL" }
+{ "_id" : "36613", "city" : "EIGHT MILE", "loc" : [ -88.182311, 30.795074 ], "pop" : 13517, "state" : "AL" }
+{ "_id" : "36615", "city" : "BROOKLEY FIELD", "loc" : [ -88.068871, 30.631199 ], "pop" : 864, "state" : "AL" }
+{ "_id" : "36617", "city" : "MOBILE", "loc" : [ -88.091796, 30.714522 ], "pop" : 17882, "state" : "AL" }
+{ "_id" : "36618", "city" : "MOBILE", "loc" : [ -88.175753, 30.732178 ], "pop" : 14887, "state" : "AL" }
+{ "_id" : "36619", "city" : "MOBILE", "loc" : [ -88.19464499999999, 30.592803 ], "pop" : 12728, "state" : "AL" }
+{ "_id" : "36693", "city" : "MOBILE", "loc" : [ -88.158843, 30.631076 ], "pop" : 17704, "state" : "AL" }
+{ "_id" : "36695", "city" : "MOBILE", "loc" : [ -88.22924500000001, 30.647431 ], "pop" : 21467, "state" : "AL" }
+{ "_id" : "36701", "city" : "SELMA", "loc" : [ -87.02452700000001, 32.419719 ], "pop" : 26569, "state" : "AL" }
+{ "_id" : "36703", "city" : "SELMA", "loc" : [ -87.01354600000001, 32.415553 ], "pop" : 12931, "state" : "AL" }
+{ "_id" : "36720", "city" : "ALBERTA", "loc" : [ -87.34250299999999, 32.144889 ], "pop" : 1340, "state" : "AL" }
+{ "_id" : "36722", "city" : "ARLINGTON", "loc" : [ -87.559691, 32.066784 ], "pop" : 1098, "state" : "AL" }
+{ "_id" : "36726", "city" : "CAMDEN", "loc" : [ -87.29504900000001, 32.004732 ], "pop" : 4948, "state" : "AL" }
+{ "_id" : "36727", "city" : "CAMPBELL", "loc" : [ -88.006072, 31.963512 ], "pop" : 392, "state" : "AL" }
+{ "_id" : "36728", "city" : "CATHERINE", "loc" : [ -87.48362299999999, 32.182 ], "pop" : 366, "state" : "AL" }
+{ "_id" : "36732", "city" : "DEMOPOLIS", "loc" : [ -87.839669, 32.490792 ], "pop" : 9992, "state" : "AL" }
+{ "_id" : "36736", "city" : "DIXONS MILLS", "loc" : [ -87.745356, 32.067209 ], "pop" : 2635, "state" : "AL" }
+{ "_id" : "36738", "city" : "FAUNSDALE", "loc" : [ -87.61807899999999, 32.423259 ], "pop" : 831, "state" : "AL" }
+{ "_id" : "36740", "city" : "FORKLAND", "loc" : [ -87.881676, 32.644661 ], "pop" : 2121, "state" : "AL" }
+{ "_id" : "36742", "city" : "GALLION", "loc" : [ -87.698542, 32.529771 ], "pop" : 599, "state" : "AL" }
+{ "_id" : "36744", "city" : "GREENSBORO", "loc" : [ -87.59049400000001, 32.716721 ], "pop" : 7680, "state" : "AL" }
+{ "_id" : "36748", "city" : "LINDEN", "loc" : [ -87.79535799999999, 32.305343 ], "pop" : 5438, "state" : "AL" }
+{ "_id" : "36749", "city" : "JONES", "loc" : [ -86.88926600000001, 32.608515 ], "pop" : 428, "state" : "AL" }
+{ "_id" : "36750", "city" : "MAPLESVILLE", "loc" : [ -86.87170399999999, 32.804507 ], "pop" : 1995, "state" : "AL" }
+{ "_id" : "36751", "city" : "LOWER PEACH TREE", "loc" : [ -87.568224, 31.850365 ], "pop" : 323, "state" : "AL" }
+{ "_id" : "36752", "city" : "BURKVILLE", "loc" : [ -86.60986800000001, 32.300292 ], "pop" : 1478, "state" : "AL" }
+{ "_id" : "36754", "city" : "MAGNOLIA", "loc" : [ -87.699815, 32.141931 ], "pop" : 222, "state" : "AL" }
+{ "_id" : "36756", "city" : "MARION", "loc" : [ -87.33143699999999, 32.646301 ], "pop" : 7284, "state" : "AL" }
+{ "_id" : "36758", "city" : "PLANTERSVILLE", "loc" : [ -86.947531, 32.617608 ], "pop" : 946, "state" : "AL" }
+{ "_id" : "36759", "city" : "MARION JUNCTION", "loc" : [ -87.27018099999999, 32.426589 ], "pop" : 796, "state" : "AL" }
+{ "_id" : "36761", "city" : "BOYS RANCH", "loc" : [ -86.92497, 32.095387 ], "pop" : 1714, "state" : "AL" }
+{ "_id" : "36762", "city" : "MORVIN", "loc" : [ -87.972897, 31.967305 ], "pop" : 24, "state" : "AL" }
+{ "_id" : "36765", "city" : "NEWBERN", "loc" : [ -87.56147199999999, 32.551465 ], "pop" : 1131, "state" : "AL" }
+{ "_id" : "36767", "city" : "ORRVILLE", "loc" : [ -87.221368, 32.294859 ], "pop" : 2680, "state" : "AL" }
+{ "_id" : "36768", "city" : "PINE APPLE", "loc" : [ -87.004667, 31.926522 ], "pop" : 1658, "state" : "AL" }
+{ "_id" : "36769", "city" : "PINE HILL", "loc" : [ -87.57708599999999, 31.973546 ], "pop" : 2623, "state" : "AL" }
+{ "_id" : "36771", "city" : "PRAIRIE", "loc" : [ -87.448723, 32.084762 ], "pop" : 112, "state" : "AL" }
+{ "_id" : "36773", "city" : "SAFFORD", "loc" : [ -87.369345, 32.300242 ], "pop" : 715, "state" : "AL" }
+{ "_id" : "36775", "city" : "SARDIS", "loc" : [ -86.99195899999999, 32.284358 ], "pop" : 1683, "state" : "AL" }
+{ "_id" : "36776", "city" : "SAWYERVILLE", "loc" : [ -87.740201, 32.757796 ], "pop" : 1684, "state" : "AL" }
+{ "_id" : "36779", "city" : "SPROTT", "loc" : [ -87.141599, 32.654376 ], "pop" : 1191, "state" : "AL" }
+{ "_id" : "36782", "city" : "SWEET WATER", "loc" : [ -87.922755, 32.077272 ], "pop" : 2444, "state" : "AL" }
+{ "_id" : "36783", "city" : "THOMASTON", "loc" : [ -87.597438, 32.253776 ], "pop" : 1527, "state" : "AL" }
+{ "_id" : "36784", "city" : "THOMASVILLE", "loc" : [ -87.75984200000001, 31.906728 ], "pop" : 6229, "state" : "AL" }
+{ "_id" : "36785", "city" : "BENTON", "loc" : [ -86.85986699999999, 32.281924 ], "pop" : 1396, "state" : "AL" }
+{ "_id" : "36786", "city" : "UNIONTOWN", "loc" : [ -87.493398, 32.446966 ], "pop" : 4173, "state" : "AL" }
+{ "_id" : "36790", "city" : "STANTON", "loc" : [ -86.886848, 32.709631 ], "pop" : 916, "state" : "AL" }
+{ "_id" : "36792", "city" : "RANDOLPH", "loc" : [ -86.90701, 32.888834 ], "pop" : 434, "state" : "AL" }
+{ "_id" : "36793", "city" : "LAWLEY", "loc" : [ -86.95670800000001, 32.864558 ], "pop" : 337, "state" : "AL" }
+{ "_id" : "36801", "city" : "OPELIKA", "loc" : [ -85.35862899999999, 32.627771 ], "pop" : 32808, "state" : "AL" }
+{ "_id" : "36830", "city" : "AUBURN", "loc" : [ -85.489001, 32.602043 ], "pop" : 38908, "state" : "AL" }
+{ "_id" : "36850", "city" : "CAMP HILL", "loc" : [ -85.64738, 32.782749 ], "pop" : 2422, "state" : "AL" }
+{ "_id" : "36852", "city" : "CUSSETA", "loc" : [ -85.215791, 32.803194 ], "pop" : 4597, "state" : "AL" }
+{ "_id" : "36853", "city" : "DADEVILLE", "loc" : [ -85.77039499999999, 32.82239 ], "pop" : 7620, "state" : "AL" }
+{ "_id" : "36854", "city" : "VALLEY", "loc" : [ -85.17491099999999, 32.811349 ], "pop" : 9504, "state" : "AL" }
+{ "_id" : "36855", "city" : "FIVE POINTS", "loc" : [ -85.324264, 33.042408 ], "pop" : 2400, "state" : "AL" }
+{ "_id" : "36858", "city" : "HATCHECHUBBEE", "loc" : [ -85.302882, 32.284531 ], "pop" : 772, "state" : "AL" }
+{ "_id" : "36860", "city" : "HURTSBORO", "loc" : [ -85.395903, 32.245429 ], "pop" : 1727, "state" : "AL" }
+{ "_id" : "36861", "city" : "JACKSONS GAP", "loc" : [ -85.848662, 32.879698 ], "pop" : 2236, "state" : "AL" }
+{ "_id" : "36862", "city" : "LAFAYETTE", "loc" : [ -85.44256300000001, 32.925237 ], "pop" : 7045, "state" : "AL" }
+{ "_id" : "36863", "city" : "LANETT", "loc" : [ -85.21608000000001, 32.861609 ], "pop" : 12083, "state" : "AL" }
+{ "_id" : "36866", "city" : "NOTASULGA", "loc" : [ -85.68707000000001, 32.543727 ], "pop" : 3361, "state" : "AL" }
+{ "_id" : "36867", "city" : "PHENIX CITY", "loc" : [ -85.095082, 32.407816 ], "pop" : 13632, "state" : "AL" }
+{ "_id" : "36869", "city" : "PHENIX CITY", "loc" : [ -85.018118, 32.470647 ], "pop" : 28320, "state" : "AL" }
+{ "_id" : "36871", "city" : "PITTSVIEW", "loc" : [ -85.131248, 32.173346 ], "pop" : 1525, "state" : "AL" }
+{ "_id" : "36874", "city" : "SALEM", "loc" : [ -85.183966, 32.621157 ], "pop" : 2773, "state" : "AL" }
+{ "_id" : "36875", "city" : "SEALE", "loc" : [ -85.167733, 32.305339 ], "pop" : 1949, "state" : "AL" }
+{ "_id" : "36877", "city" : "SMITHS", "loc" : [ -85.100027, 32.520072 ], "pop" : 10605, "state" : "AL" }
+{ "_id" : "36879", "city" : "WAVERLY", "loc" : [ -85.51437199999999, 32.763167 ], "pop" : 1689, "state" : "AL" }
+{ "_id" : "36904", "city" : "BUTLER", "loc" : [ -88.206391, 32.082906 ], "pop" : 4957, "state" : "AL" }
+{ "_id" : "36907", "city" : "CUBA", "loc" : [ -88.36108299999999, 32.410973 ], "pop" : 1184, "state" : "AL" }
+{ "_id" : "36908", "city" : "GILBERTOWN", "loc" : [ -88.326514, 31.866602 ], "pop" : 1606, "state" : "AL" }
+{ "_id" : "36910", "city" : "JACHIN", "loc" : [ -88.233356, 32.244174 ], "pop" : 480, "state" : "AL" }
+{ "_id" : "36912", "city" : "LISMAN", "loc" : [ -88.323419, 32.217722 ], "pop" : 2313, "state" : "AL" }
+{ "_id" : "36915", "city" : "NEEDHAM", "loc" : [ -88.345798, 32.012165 ], "pop" : 618, "state" : "AL" }
+{ "_id" : "36916", "city" : "PENNINGTON", "loc" : [ -88.09310000000001, 32.226245 ], "pop" : 1459, "state" : "AL" }
+{ "_id" : "36919", "city" : "SILAS", "loc" : [ -88.30914900000001, 31.766754 ], "pop" : 2600, "state" : "AL" }
+{ "_id" : "36921", "city" : "TOXEY", "loc" : [ -88.31793999999999, 31.93153 ], "pop" : 1980, "state" : "AL" }
+{ "_id" : "36922", "city" : "WARD", "loc" : [ -88.29711399999999, 32.334063 ], "pop" : 274, "state" : "AL" }
+{ "_id" : "36925", "city" : "YORK", "loc" : [ -88.268304, 32.472765 ], "pop" : 5728, "state" : "AL" }
+{ "_id" : "37010", "city" : "ADAMS", "loc" : [ -87.122626, 36.558174 ], "pop" : 2660, "state" : "TN" }
+{ "_id" : "37012", "city" : "ALEXANDRIA", "loc" : [ -86.037171, 36.071147 ], "pop" : 993, "state" : "TN" }
+{ "_id" : "37013", "city" : "ANTIOCH", "loc" : [ -86.65915099999999, 36.059517 ], "pop" : 36988, "state" : "TN" }
+{ "_id" : "37014", "city" : "ARRINGTON", "loc" : [ -86.564515, 35.904876 ], "pop" : 12171, "state" : "TN" }
+{ "_id" : "37015", "city" : "ASHLAND CITY", "loc" : [ -87.044719, 36.273132 ], "pop" : 10940, "state" : "TN" }
+{ "_id" : "37016", "city" : "AUBURNTOWN", "loc" : [ -86.10753200000001, 35.974392 ], "pop" : 933, "state" : "TN" }
+{ "_id" : "37018", "city" : "BEECHGROVE", "loc" : [ -86.204644, 35.644733 ], "pop" : 650, "state" : "TN" }
+{ "_id" : "37019", "city" : "BELFAST", "loc" : [ -86.70948199999999, 35.406905 ], "pop" : 425, "state" : "TN" }
+{ "_id" : "37020", "city" : "BELL BUCKLE", "loc" : [ -86.394908, 35.638105 ], "pop" : 2899, "state" : "TN" }
+{ "_id" : "37022", "city" : "BETHPAGE", "loc" : [ -86.314572, 36.518575 ], "pop" : 4132, "state" : "TN" }
+{ "_id" : "37023", "city" : "BIG ROCK", "loc" : [ -87.737838, 36.571606 ], "pop" : 258, "state" : "TN" }
+{ "_id" : "37025", "city" : "BON AQUA", "loc" : [ -87.299564, 35.947073 ], "pop" : 3984, "state" : "TN" }
+{ "_id" : "37026", "city" : "BRADYVILLE", "loc" : [ -86.09119, 35.705278 ], "pop" : 1570, "state" : "TN" }
+{ "_id" : "37027", "city" : "BRENTWOOD", "loc" : [ -86.790947, 36.006272 ], "pop" : 24280, "state" : "TN" }
+{ "_id" : "37028", "city" : "BUMPUS MILLS", "loc" : [ -87.861434, 36.622618 ], "pop" : 411, "state" : "TN" }
+{ "_id" : "37029", "city" : "BURNS", "loc" : [ -87.306061, 36.047066 ], "pop" : 4449, "state" : "TN" }
+{ "_id" : "37030", "city" : "DEFEATED", "loc" : [ -85.96969, 36.255617 ], "pop" : 5318, "state" : "TN" }
+{ "_id" : "37031", "city" : "CASTALIAN SPRING", "loc" : [ -86.315545, 36.382108 ], "pop" : 1544, "state" : "TN" }
+{ "_id" : "37032", "city" : "CEDAR HILL", "loc" : [ -87.027523, 36.506163 ], "pop" : 2527, "state" : "TN" }
+{ "_id" : "37033", "city" : "CENTERVILLE", "loc" : [ -87.477473, 35.779685 ], "pop" : 5955, "state" : "TN" }
+{ "_id" : "37034", "city" : "CHAPEL HILL", "loc" : [ -86.683584, 35.63542 ], "pop" : 2912, "state" : "TN" }
+{ "_id" : "37035", "city" : "CHAPMANSBORO", "loc" : [ -87.111288, 36.378078 ], "pop" : 3248, "state" : "TN" }
+{ "_id" : "37036", "city" : "CHARLOTTE", "loc" : [ -87.281554, 36.232612 ], "pop" : 4205, "state" : "TN" }
+{ "_id" : "37037", "city" : "CHRISTIANA", "loc" : [ -86.407932, 35.740877 ], "pop" : 3173, "state" : "TN" }
+{ "_id" : "37040", "city" : "CLARKSVILLE", "loc" : [ -87.348997, 36.522014 ], "pop" : 24920, "state" : "TN" }
+{ "_id" : "37042", "city" : "CLARKSVILLE", "loc" : [ -87.418621, 36.585315 ], "pop" : 43296, "state" : "TN" }
+{ "_id" : "37043", "city" : "CLARKSVILLE", "loc" : [ -87.27565300000001, 36.5107 ], "pop" : 23166, "state" : "TN" }
+{ "_id" : "37046", "city" : "COLLEGE GROVE", "loc" : [ -86.749516, 35.783166 ], "pop" : 4321, "state" : "TN" }
+{ "_id" : "37047", "city" : "CORNERSVILLE", "loc" : [ -86.82862, 35.34088 ], "pop" : 1631, "state" : "TN" }
+{ "_id" : "37048", "city" : "COTTONTOWN", "loc" : [ -86.60333799999999, 36.491231 ], "pop" : 4724, "state" : "TN" }
+{ "_id" : "37049", "city" : "CROSS PLAINS", "loc" : [ -86.67608799999999, 36.553068 ], "pop" : 2269, "state" : "TN" }
+{ "_id" : "37050", "city" : "CUMBERLAND CITY", "loc" : [ -87.63494, 36.366924 ], "pop" : 1208, "state" : "TN" }
+{ "_id" : "37051", "city" : "CUMBERLAND FURNA", "loc" : [ -87.40658500000001, 36.316146 ], "pop" : 2288, "state" : "TN" }
+{ "_id" : "37052", "city" : "CUNNINGHAM", "loc" : [ -87.42454600000001, 36.378926 ], "pop" : 2163, "state" : "TN" }
+{ "_id" : "37055", "city" : "DICKSON", "loc" : [ -87.39953199999999, 36.076014 ], "pop" : 17724, "state" : "TN" }
+{ "_id" : "37057", "city" : "DIXON SPRINGS", "loc" : [ -86.05334999999999, 36.445538 ], "pop" : 1269, "state" : "TN" }
+{ "_id" : "37058", "city" : "DOVER", "loc" : [ -87.83833300000001, 36.507521 ], "pop" : 5972, "state" : "TN" }
+{ "_id" : "37059", "city" : "DOWELLTOWN", "loc" : [ -85.90553300000001, 35.972485 ], "pop" : 1416, "state" : "TN" }
+{ "_id" : "37060", "city" : "EAGLEVILLE", "loc" : [ -86.63265199999999, 35.749243 ], "pop" : 1562, "state" : "TN" }
+{ "_id" : "37061", "city" : "ERIN", "loc" : [ -87.67896399999999, 36.306684 ], "pop" : 4804, "state" : "TN" }
+{ "_id" : "37062", "city" : "FAIRVIEW", "loc" : [ -87.132065, 35.975528 ], "pop" : 7203, "state" : "TN" }
+{ "_id" : "37064", "city" : "FRANKLIN", "loc" : [ -86.878833, 35.932782 ], "pop" : 40509, "state" : "TN" }
+{ "_id" : "37066", "city" : "GALLATIN", "loc" : [ -86.45116, 36.383438 ], "pop" : 27321, "state" : "TN" }
+{ "_id" : "37072", "city" : "GOODLETTSVILLE", "loc" : [ -86.721215, 36.341677 ], "pop" : 20825, "state" : "TN" }
+{ "_id" : "37073", "city" : "GREENBRIER", "loc" : [ -86.79135599999999, 36.422914 ], "pop" : 8597, "state" : "TN" }
+{ "_id" : "37074", "city" : "HARTSVILLE", "loc" : [ -86.17040799999999, 36.394728 ], "pop" : 5511, "state" : "TN" }
+{ "_id" : "37075", "city" : "HENDERSONVILLE", "loc" : [ -86.607157, 36.305425 ], "pop" : 38730, "state" : "TN" }
+{ "_id" : "37076", "city" : "HERMITAGE", "loc" : [ -86.600162, 36.184814 ], "pop" : 23765, "state" : "TN" }
+{ "_id" : "37078", "city" : "HURRICANE MILLS", "loc" : [ -87.767129, 35.974859 ], "pop" : 2200, "state" : "TN" }
+{ "_id" : "37079", "city" : "INDIAN MOUND", "loc" : [ -87.680368, 36.494593 ], "pop" : 1615, "state" : "TN" }
+{ "_id" : "37080", "city" : "JOELTON", "loc" : [ -86.91630600000001, 36.328974 ], "pop" : 6749, "state" : "TN" }
+{ "_id" : "37082", "city" : "KINGSTON SPRINGS", "loc" : [ -87.115646, 36.095324 ], "pop" : 4037, "state" : "TN" }
+{ "_id" : "37083", "city" : "LAFAYETTE", "loc" : [ -86.02421699999999, 36.538955 ], "pop" : 8686, "state" : "TN" }
+{ "_id" : "37085", "city" : "LASCASSAS", "loc" : [ -86.31119200000001, 35.949535 ], "pop" : 2463, "state" : "TN" }
+{ "_id" : "37086", "city" : "LA VERGNE", "loc" : [ -86.559969, 36.012714 ], "pop" : 6115, "state" : "TN" }
+{ "_id" : "37087", "city" : "LEBANON", "loc" : [ -86.302367, 36.209792 ], "pop" : 33656, "state" : "TN" }
+{ "_id" : "37091", "city" : "LEWISBURG", "loc" : [ -86.781204, 35.459615 ], "pop" : 16217, "state" : "TN" }
+{ "_id" : "37095", "city" : "GASSAWAY", "loc" : [ -85.98544800000001, 35.974593 ], "pop" : 2236, "state" : "TN" }
+{ "_id" : "37096", "city" : "FLATWOODS", "loc" : [ -87.865582, 35.599784 ], "pop" : 4172, "state" : "TN" }
+{ "_id" : "37097", "city" : "LOBELVILLE", "loc" : [ -87.82510600000001, 35.746659 ], "pop" : 2357, "state" : "TN" }
+{ "_id" : "37098", "city" : "WRIGLEY", "loc" : [ -87.317199, 35.892216 ], "pop" : 3257, "state" : "TN" }
+{ "_id" : "37101", "city" : "MC EWEN", "loc" : [ -87.64221000000001, 36.118477 ], "pop" : 3963, "state" : "TN" }
+{ "_id" : "37110", "city" : "PLAZA", "loc" : [ -85.79160899999999, 35.697358 ], "pop" : 25113, "state" : "TN" }
+{ "_id" : "37115", "city" : "MADISON", "loc" : [ -86.70455699999999, 36.260386 ], "pop" : 31511, "state" : "TN" }
+{ "_id" : "37118", "city" : "MILTON", "loc" : [ -86.182377, 35.922085 ], "pop" : 894, "state" : "TN" }
+{ "_id" : "37122", "city" : "MOUNT JULIET", "loc" : [ -86.50234399999999, 36.189684 ], "pop" : 24498, "state" : "TN" }
+{ "_id" : "37129", "city" : "MURFREESBORO", "loc" : [ -86.41809000000001, 35.871019 ], "pop" : 26477, "state" : "TN" }
+{ "_id" : "37130", "city" : "MURFREESBORO", "loc" : [ -86.36467500000001, 35.847792 ], "pop" : 35559, "state" : "TN" }
+{ "_id" : "37134", "city" : "NEW JOHNSONVILLE", "loc" : [ -87.95469300000001, 36.008775 ], "pop" : 2812, "state" : "TN" }
+{ "_id" : "37135", "city" : "NOLENSVILLE", "loc" : [ -86.682868, 35.930723 ], "pop" : 3813, "state" : "TN" }
+{ "_id" : "37137", "city" : "NUNNELLY", "loc" : [ -87.50666099999999, 35.87627 ], "pop" : 2176, "state" : "TN" }
+{ "_id" : "37138", "city" : "OLD HICKORY", "loc" : [ -86.611704, 36.241564 ], "pop" : 17329, "state" : "TN" }
+{ "_id" : "37140", "city" : "ONLY", "loc" : [ -87.665451, 35.867888 ], "pop" : 199, "state" : "TN" }
+{ "_id" : "37141", "city" : "ORLINDA", "loc" : [ -86.69900199999999, 36.611045 ], "pop" : 614, "state" : "TN" }
+{ "_id" : "37142", "city" : "PALMYRA", "loc" : [ -87.491359, 36.417568 ], "pop" : 1118, "state" : "TN" }
+{ "_id" : "37143", "city" : "PEGRAM", "loc" : [ -87.03161299999999, 36.11291 ], "pop" : 2742, "state" : "TN" }
+{ "_id" : "37144", "city" : "PETERSBURG", "loc" : [ -86.644728, 35.292416 ], "pop" : 3214, "state" : "TN" }
+{ "_id" : "37145", "city" : "PLEASANT SHADE", "loc" : [ -85.908057, 36.348924 ], "pop" : 1901, "state" : "TN" }
+{ "_id" : "37146", "city" : "PLEASANT VIEW", "loc" : [ -87.03948, 36.378281 ], "pop" : 2424, "state" : "TN" }
+{ "_id" : "37147", "city" : "PLEASANTVILLE", "loc" : [ -87.65366400000001, 35.668373 ], "pop" : 534, "state" : "TN" }
+{ "_id" : "37148", "city" : "PORTLAND", "loc" : [ -86.505923, 36.567306 ], "pop" : 12790, "state" : "TN" }
+{ "_id" : "37149", "city" : "READYVILLE", "loc" : [ -86.241483, 35.798878 ], "pop" : 4572, "state" : "TN" }
+{ "_id" : "37150", "city" : "RED BOILING SPRI", "loc" : [ -85.846333, 36.531283 ], "pop" : 4862, "state" : "TN" }
+{ "_id" : "37151", "city" : "RIDDLETON", "loc" : [ -86.03348200000001, 36.350581 ], "pop" : 572, "state" : "TN" }
+{ "_id" : "37153", "city" : "ROCKVALE", "loc" : [ -86.535196, 35.74503 ], "pop" : 1776, "state" : "TN" }
+{ "_id" : "37160", "city" : "ROYAL", "loc" : [ -86.463425, 35.488313 ], "pop" : 22781, "state" : "TN" }
+{ "_id" : "37166", "city" : "SMITHVILLE", "loc" : [ -85.804562, 35.929907 ], "pop" : 10587, "state" : "TN" }
+{ "_id" : "37167", "city" : "SMYRNA", "loc" : [ -86.504818, 35.965611 ], "pop" : 23049, "state" : "TN" }
+{ "_id" : "37171", "city" : "SOUTHSIDE", "loc" : [ -87.30608700000001, 36.362588 ], "pop" : 951, "state" : "TN" }
+{ "_id" : "37172", "city" : "SPRINGFIELD", "loc" : [ -86.876901, 36.50182 ], "pop" : 21214, "state" : "TN" }
+{ "_id" : "37174", "city" : "SPRING HILL", "loc" : [ -86.90480700000001, 35.717294 ], "pop" : 2891, "state" : "TN" }
+{ "_id" : "37175", "city" : "STEWART", "loc" : [ -87.872495, 36.324055 ], "pop" : 897, "state" : "TN" }
+{ "_id" : "37178", "city" : "TENNESSEE RIDGE", "loc" : [ -87.780761, 36.329712 ], "pop" : 1558, "state" : "TN" }
+{ "_id" : "37179", "city" : "THOMPSONS STATIO", "loc" : [ -87.004875, 35.831006 ], "pop" : 3945, "state" : "TN" }
+{ "_id" : "37180", "city" : "UNIONVILLE", "loc" : [ -86.563852, 35.622416 ], "pop" : 1772, "state" : "TN" }
+{ "_id" : "37181", "city" : "VANLEER", "loc" : [ -87.45653, 36.223738 ], "pop" : 1531, "state" : "TN" }
+{ "_id" : "37183", "city" : "WARTRACE", "loc" : [ -86.327736, 35.512299 ], "pop" : 2119, "state" : "TN" }
+{ "_id" : "37184", "city" : "WATERTOWN", "loc" : [ -86.143411, 36.095268 ], "pop" : 3640, "state" : "TN" }
+{ "_id" : "37185", "city" : "WAVERLY", "loc" : [ -87.799108, 36.099664 ], "pop" : 6820, "state" : "TN" }
+{ "_id" : "37186", "city" : "WESTMORELAND", "loc" : [ -86.23529600000001, 36.575554 ], "pop" : 6695, "state" : "TN" }
+{ "_id" : "37187", "city" : "WHITE BLUFF", "loc" : [ -87.21901, 36.12531 ], "pop" : 5230, "state" : "TN" }
+{ "_id" : "37188", "city" : "WHITE HOUSE", "loc" : [ -86.670524, 36.460048 ], "pop" : 6240, "state" : "TN" }
+{ "_id" : "37189", "city" : "WHITES CREEK", "loc" : [ -86.82922000000001, 36.274377 ], "pop" : 4189, "state" : "TN" }
+{ "_id" : "37190", "city" : "WOODBURY", "loc" : [ -86.050044, 35.814254 ], "pop" : 6141, "state" : "TN" }
+{ "_id" : "37191", "city" : "WOODLAWN", "loc" : [ -87.539331, 36.514695 ], "pop" : 2568, "state" : "TN" }
+{ "_id" : "37201", "city" : "NASHVILLE", "loc" : [ -86.778441, 36.167028 ], "pop" : 1579, "state" : "TN" }
+{ "_id" : "37203", "city" : "NASHVILLE", "loc" : [ -86.79392199999999, 36.146802 ], "pop" : 13524, "state" : "TN" }
+{ "_id" : "37204", "city" : "MELROSE", "loc" : [ -86.781808, 36.114628 ], "pop" : 12448, "state" : "TN" }
+{ "_id" : "37205", "city" : "NASHVILLE", "loc" : [ -86.868954, 36.111432 ], "pop" : 23323, "state" : "TN" }
+{ "_id" : "37206", "city" : "NASHVILLE", "loc" : [ -86.741106, 36.179813 ], "pop" : 28446, "state" : "TN" }
+{ "_id" : "37207", "city" : "NASHVILLE", "loc" : [ -86.77400799999999, 36.2195 ], "pop" : 35260, "state" : "TN" }
+{ "_id" : "37208", "city" : "NASHVILLE", "loc" : [ -86.807563, 36.176196 ], "pop" : 15535, "state" : "TN" }
+{ "_id" : "37209", "city" : "NASHVILLE", "loc" : [ -86.860212, 36.154592 ], "pop" : 33560, "state" : "TN" }
+{ "_id" : "37210", "city" : "NASHVILLE", "loc" : [ -86.74104199999999, 36.137904 ], "pop" : 17173, "state" : "TN" }
+{ "_id" : "37211", "city" : "NASHVILLE", "loc" : [ -86.72403799999999, 36.072486 ], "pop" : 51478, "state" : "TN" }
+{ "_id" : "37212", "city" : "NASHVILLE", "loc" : [ -86.800555, 36.133681 ], "pop" : 16492, "state" : "TN" }
+{ "_id" : "37213", "city" : "NASHVILLE", "loc" : [ -86.76055599999999, 36.165512 ], "pop" : 356, "state" : "TN" }
+{ "_id" : "37214", "city" : "NASHVILLE", "loc" : [ -86.660854, 36.163339 ], "pop" : 24935, "state" : "TN" }
+{ "_id" : "37215", "city" : "NASHVILLE", "loc" : [ -86.821917, 36.098584 ], "pop" : 20452, "state" : "TN" }
+{ "_id" : "37216", "city" : "NASHVILLE", "loc" : [ -86.72568699999999, 36.212491 ], "pop" : 20045, "state" : "TN" }
+{ "_id" : "37217", "city" : "NASHVILLE", "loc" : [ -86.666585, 36.10585 ], "pop" : 26242, "state" : "TN" }
+{ "_id" : "37218", "city" : "NASHVILLE", "loc" : [ -86.845583, 36.207062 ], "pop" : 14312, "state" : "TN" }
+{ "_id" : "37219", "city" : "NASHVILLE", "loc" : [ -86.783676, 36.167768 ], "pop" : 268, "state" : "TN" }
+{ "_id" : "37220", "city" : "NASHVILLE", "loc" : [ -86.769654, 36.064139 ], "pop" : 6230, "state" : "TN" }
+{ "_id" : "37221", "city" : "BELLEVUE", "loc" : [ -86.943674, 36.071512 ], "pop" : 21880, "state" : "TN" }
+{ "_id" : "37228", "city" : "NASHVILLE", "loc" : [ -86.80526399999999, 36.190145 ], "pop" : 612, "state" : "TN" }
+{ "_id" : "37301", "city" : "ALTAMONT", "loc" : [ -85.763508, 35.425776 ], "pop" : 988, "state" : "TN" }
+{ "_id" : "37302", "city" : "APISON", "loc" : [ -85.01640399999999, 35.014926 ], "pop" : 1614, "state" : "TN" }
+{ "_id" : "37303", "city" : "ATHENS", "loc" : [ -84.60426099999999, 35.457389 ], "pop" : 21571, "state" : "TN" }
+{ "_id" : "37305", "city" : "BEERSHEBA SPRING", "loc" : [ -85.68212800000001, 35.470371 ], "pop" : 1067, "state" : "TN" }
+{ "_id" : "37306", "city" : "BELVIDERE", "loc" : [ -86.172827, 35.141499 ], "pop" : 4670, "state" : "TN" }
+{ "_id" : "37307", "city" : "BENTON", "loc" : [ -84.654433, 35.172953 ], "pop" : 3164, "state" : "TN" }
+{ "_id" : "37308", "city" : "BIRCHWOOD", "loc" : [ -84.96183499999999, 35.351968 ], "pop" : 2732, "state" : "TN" }
+{ "_id" : "37309", "city" : "CALHOUN", "loc" : [ -84.738105, 35.374614 ], "pop" : 3597, "state" : "TN" }
+{ "_id" : "37310", "city" : "CHARLESTON", "loc" : [ -84.766639, 35.255644 ], "pop" : 1921, "state" : "TN" }
+{ "_id" : "37311", "city" : "CLEVELAND", "loc" : [ -84.875006, 35.131257 ], "pop" : 40633, "state" : "TN" }
+{ "_id" : "37312", "city" : "CLEVELAND", "loc" : [ -84.84755699999999, 35.202309 ], "pop" : 28081, "state" : "TN" }
+{ "_id" : "37313", "city" : "COALMONT", "loc" : [ -85.655097, 35.386197 ], "pop" : 786, "state" : "TN" }
+{ "_id" : "37317", "city" : "POSTELLE", "loc" : [ -84.38396400000001, 35.024987 ], "pop" : 3155, "state" : "TN" }
+{ "_id" : "37318", "city" : "COWAN", "loc" : [ -86.019007, 35.170121 ], "pop" : 2713, "state" : "TN" }
+{ "_id" : "37321", "city" : "DAYTON", "loc" : [ -85.01345499999999, 35.500186 ], "pop" : 15965, "state" : "TN" }
+{ "_id" : "37322", "city" : "DECATUR", "loc" : [ -84.80805100000001, 35.507166 ], "pop" : 3718, "state" : "TN" }
+{ "_id" : "37324", "city" : "DECHERD", "loc" : [ -86.058859, 35.232598 ], "pop" : 6576, "state" : "TN" }
+{ "_id" : "37325", "city" : "DELANO", "loc" : [ -84.602366, 35.261234 ], "pop" : 1830, "state" : "TN" }
+{ "_id" : "37327", "city" : "DUNLAP", "loc" : [ -85.39251299999999, 35.384175 ], "pop" : 6883, "state" : "TN" }
+{ "_id" : "37328", "city" : "ELORA", "loc" : [ -86.34811000000001, 35.029496 ], "pop" : 1257, "state" : "TN" }
+{ "_id" : "37329", "city" : "ENGLEWOOD", "loc" : [ -84.483265, 35.427245 ], "pop" : 3419, "state" : "TN" }
+{ "_id" : "37330", "city" : "ESTILL SPRINGS", "loc" : [ -86.139561, 35.270508 ], "pop" : 5778, "state" : "TN" }
+{ "_id" : "37331", "city" : "ETOWAH", "loc" : [ -84.528305, 35.331443 ], "pop" : 8246, "state" : "TN" }
+{ "_id" : "37332", "city" : "EVENSVILLE", "loc" : [ -85.022773, 35.615346 ], "pop" : 99, "state" : "TN" }
+{ "_id" : "37333", "city" : "FARNER", "loc" : [ -84.320904, 35.144894 ], "pop" : 672, "state" : "TN" }
+{ "_id" : "37334", "city" : "FAYETTEVILLE", "loc" : [ -86.56644799999999, 35.152678 ], "pop" : 11009, "state" : "TN" }
+{ "_id" : "37335", "city" : "FLINTVILLE", "loc" : [ -86.497974, 35.042782 ], "pop" : 6020, "state" : "TN" }
+{ "_id" : "37336", "city" : "GEORGETOWN", "loc" : [ -84.912684, 35.293241 ], "pop" : 3768, "state" : "TN" }
+{ "_id" : "37337", "city" : "GRANDVIEW", "loc" : [ -84.861464, 35.760843 ], "pop" : 626, "state" : "TN" }
+{ "_id" : "37338", "city" : "GRAYSVILLE", "loc" : [ -85.17904, 35.44842 ], "pop" : 1067, "state" : "TN" }
+{ "_id" : "37339", "city" : "GRUETLI LAAGER", "loc" : [ -85.66977300000001, 35.363464 ], "pop" : 1929, "state" : "TN" }
+{ "_id" : "37340", "city" : "GUILD", "loc" : [ -85.511568, 35.017834 ], "pop" : 1183, "state" : "TN" }
+{ "_id" : "37341", "city" : "HARRISON", "loc" : [ -85.094532, 35.167898 ], "pop" : 10247, "state" : "TN" }
+{ "_id" : "37342", "city" : "HILLSBORO", "loc" : [ -85.97242199999999, 35.369933 ], "pop" : 2075, "state" : "TN" }
+{ "_id" : "37343", "city" : "HIXSON", "loc" : [ -85.218215, 35.159112 ], "pop" : 35100, "state" : "TN" }
+{ "_id" : "37345", "city" : "HUNTLAND", "loc" : [ -86.269435, 35.051198 ], "pop" : 2016, "state" : "TN" }
+{ "_id" : "37347", "city" : "KIMBALL", "loc" : [ -85.61473700000001, 35.066603 ], "pop" : 7076, "state" : "TN" }
+{ "_id" : "37348", "city" : "KELSO", "loc" : [ -86.468343, 35.102356 ], "pop" : 759, "state" : "TN" }
+{ "_id" : "37350", "city" : "LOOKOUT MOUNTAIN", "loc" : [ -85.35056400000001, 34.994825 ], "pop" : 1899, "state" : "TN" }
+{ "_id" : "37352", "city" : "LYNCHBURG", "loc" : [ -86.37201899999999, 35.270642 ], "pop" : 2888, "state" : "TN" }
+{ "_id" : "37353", "city" : "MC DONALD", "loc" : [ -84.989198, 35.086902 ], "pop" : 819, "state" : "TN" }
+{ "_id" : "37354", "city" : "HIWASSEE COLLEGE", "loc" : [ -84.351899, 35.500917 ], "pop" : 10509, "state" : "TN" }
+{ "_id" : "37355", "city" : "MANCHESTER", "loc" : [ -86.081568, 35.495846 ], "pop" : 19173, "state" : "TN" }
+{ "_id" : "37356", "city" : "MONTEAGLE", "loc" : [ -85.822795, 35.240172 ], "pop" : 2206, "state" : "TN" }
+{ "_id" : "37357", "city" : "MORRISON", "loc" : [ -85.889895, 35.60002 ], "pop" : 5654, "state" : "TN" }
+{ "_id" : "37359", "city" : "MULBERRY", "loc" : [ -86.421685, 35.19413 ], "pop" : 495, "state" : "TN" }
+{ "_id" : "37360", "city" : "NORMANDY", "loc" : [ -86.255712, 35.429628 ], "pop" : 1308, "state" : "TN" }
+{ "_id" : "37361", "city" : "OCOEE", "loc" : [ -84.713565, 35.102473 ], "pop" : 1206, "state" : "TN" }
+{ "_id" : "37362", "city" : "OLDFORT", "loc" : [ -84.72187700000001, 35.03654 ], "pop" : 1522, "state" : "TN" }
+{ "_id" : "37363", "city" : "OOLTEWAH", "loc" : [ -85.063495, 35.078104 ], "pop" : 17419, "state" : "TN" }
+{ "_id" : "37365", "city" : "PALMER", "loc" : [ -85.564272, 35.374062 ], "pop" : 1685, "state" : "TN" }
+{ "_id" : "37366", "city" : "PELHAM", "loc" : [ -85.84408000000001, 35.314045 ], "pop" : 671, "state" : "TN" }
+{ "_id" : "37367", "city" : "PIKEVILLE", "loc" : [ -85.20765299999999, 35.640769 ], "pop" : 7869, "state" : "TN" }
+{ "_id" : "37369", "city" : "RELIANCE", "loc" : [ -84.54103000000001, 35.180664 ], "pop" : 1777, "state" : "TN" }
+{ "_id" : "37370", "city" : "RICEVILLE", "loc" : [ -84.646247, 35.344615 ], "pop" : 2785, "state" : "TN" }
+{ "_id" : "37373", "city" : "SALE CREEK", "loc" : [ -85.102323, 35.385806 ], "pop" : 2464, "state" : "TN" }
+{ "_id" : "37374", "city" : "SEQUATCHIE", "loc" : [ -85.637084, 35.163396 ], "pop" : 1463, "state" : "TN" }
+{ "_id" : "37375", "city" : "SEWANEE", "loc" : [ -85.91258999999999, 35.201101 ], "pop" : 2785, "state" : "TN" }
+{ "_id" : "37376", "city" : "SHERWOOD", "loc" : [ -85.923841, 35.099164 ], "pop" : 885, "state" : "TN" }
+{ "_id" : "37377", "city" : "SIGNAL MOUNTAIN", "loc" : [ -85.336243, 35.149424 ], "pop" : 14032, "state" : "TN" }
+{ "_id" : "37379", "city" : "SODDY DAISY", "loc" : [ -85.163009, 35.252686 ], "pop" : 19646, "state" : "TN" }
+{ "_id" : "37380", "city" : "SOUTH PITTSBURG", "loc" : [ -85.722498, 35.028046 ], "pop" : 6151, "state" : "TN" }
+{ "_id" : "37381", "city" : "SPRING CITY", "loc" : [ -84.84196799999999, 35.682072 ], "pop" : 7787, "state" : "TN" }
+{ "_id" : "37385", "city" : "TELLICO PLAINS", "loc" : [ -84.306785, 35.356237 ], "pop" : 6459, "state" : "TN" }
+{ "_id" : "37387", "city" : "TRACY CITY", "loc" : [ -85.736187, 35.272081 ], "pop" : 3980, "state" : "TN" }
+{ "_id" : "37388", "city" : "DICKEL", "loc" : [ -86.22069, 35.35841 ], "pop" : 22193, "state" : "TN" }
+{ "_id" : "37391", "city" : "TURTLETOWN", "loc" : [ -84.354381, 35.108089 ], "pop" : 910, "state" : "TN" }
+{ "_id" : "37396", "city" : "WHITESIDE", "loc" : [ -85.398499, 35.066289 ], "pop" : 192, "state" : "TN" }
+{ "_id" : "37397", "city" : "WHITWELL", "loc" : [ -85.50111200000001, 35.197228 ], "pop" : 9051, "state" : "TN" }
+{ "_id" : "37398", "city" : "WINCHESTER", "loc" : [ -86.113038, 35.186398 ], "pop" : 5753, "state" : "TN" }
+{ "_id" : "37402", "city" : "CHATTANOOGA", "loc" : [ -85.316126, 35.046288 ], "pop" : 3455, "state" : "TN" }
+{ "_id" : "37403", "city" : "CHATTANOOGA", "loc" : [ -85.296516, 35.045045 ], "pop" : 3700, "state" : "TN" }
+{ "_id" : "37404", "city" : "CHATTANOOGA", "loc" : [ -85.272229, 35.030634 ], "pop" : 15345, "state" : "TN" }
+{ "_id" : "37405", "city" : "CHATTANOOGA", "loc" : [ -85.308224, 35.076801 ], "pop" : 12005, "state" : "TN" }
+{ "_id" : "37406", "city" : "CHATTANOOGA", "loc" : [ -85.247839, 35.061446 ], "pop" : 15684, "state" : "TN" }
+{ "_id" : "37407", "city" : "CHATTANOOGA", "loc" : [ -85.284913, 35.002361 ], "pop" : 8138, "state" : "TN" }
+{ "_id" : "37408", "city" : "CHATTANOOGA", "loc" : [ -85.306809, 35.029236 ], "pop" : 2131, "state" : "TN" }
+{ "_id" : "37409", "city" : "CHATTANOOGA", "loc" : [ -85.33101600000001, 34.99809 ], "pop" : 2848, "state" : "TN" }
+{ "_id" : "37410", "city" : "CHATTANOOGA", "loc" : [ -85.313762, 35.001787 ], "pop" : 6068, "state" : "TN" }
+{ "_id" : "37411", "city" : "CHATTANOOGA", "loc" : [ -85.23558300000001, 35.02706 ], "pop" : 18421, "state" : "TN" }
+{ "_id" : "37412", "city" : "EAST RIDGE", "loc" : [ -85.23795699999999, 34.996726 ], "pop" : 20711, "state" : "TN" }
+{ "_id" : "37415", "city" : "RED BANK", "loc" : [ -85.28633000000001, 35.117668 ], "pop" : 21549, "state" : "TN" }
+{ "_id" : "37416", "city" : "CHATTANOOGA", "loc" : [ -85.175656, 35.094246 ], "pop" : 14197, "state" : "TN" }
+{ "_id" : "37419", "city" : "CHATTANOOGA", "loc" : [ -85.36869799999999, 35.033092 ], "pop" : 5253, "state" : "TN" }
+{ "_id" : "37421", "city" : "CHATTANOOGA", "loc" : [ -85.14594, 35.024986 ], "pop" : 32802, "state" : "TN" }
+{ "_id" : "37601", "city" : "JOHNSON CITY", "loc" : [ -82.34077499999999, 36.333872 ], "pop" : 27978, "state" : "TN" }
+{ "_id" : "37604", "city" : "JOHNSON CITY", "loc" : [ -82.38104199999999, 36.310744 ], "pop" : 31353, "state" : "TN" }
+{ "_id" : "37615", "city" : "GRAY", "loc" : [ -82.44712800000001, 36.41006 ], "pop" : 12119, "state" : "TN" }
+{ "_id" : "37616", "city" : "AFTON", "loc" : [ -82.746667, 36.204166 ], "pop" : 3469, "state" : "TN" }
+{ "_id" : "37617", "city" : "BLOUNTVILLE", "loc" : [ -82.36555799999999, 36.53562 ], "pop" : 14517, "state" : "TN" }
+{ "_id" : "37618", "city" : "BLUFF CITY", "loc" : [ -82.236181, 36.477391 ], "pop" : 11146, "state" : "TN" }
+{ "_id" : "37620", "city" : "BRISTOL", "loc" : [ -82.181864, 36.568643 ], "pop" : 36852, "state" : "TN" }
+{ "_id" : "37640", "city" : "BUTLER", "loc" : [ -81.985614, 36.328158 ], "pop" : 3479, "state" : "TN" }
+{ "_id" : "37641", "city" : "CHUCKEY", "loc" : [ -82.66744799999999, 36.221142 ], "pop" : 6362, "state" : "TN" }
+{ "_id" : "37642", "city" : "CHURCH HILL", "loc" : [ -82.725184, 36.539926 ], "pop" : 9106, "state" : "TN" }
+{ "_id" : "37643", "city" : "ELIZABETHTON", "loc" : [ -82.201481, 36.344548 ], "pop" : 32046, "state" : "TN" }
+{ "_id" : "37645", "city" : "MOUNT CARMEL", "loc" : [ -82.653217, 36.562913 ], "pop" : 6249, "state" : "TN" }
+{ "_id" : "37650", "city" : "ERWIN", "loc" : [ -82.41631, 36.134193 ], "pop" : 11635, "state" : "TN" }
+{ "_id" : "37656", "city" : "FALL BRANCH", "loc" : [ -82.62560499999999, 36.415839 ], "pop" : 1964, "state" : "TN" }
+{ "_id" : "37657", "city" : "FLAG POND", "loc" : [ -82.56230100000001, 36.008507 ], "pop" : 1066, "state" : "TN" }
+{ "_id" : "37658", "city" : "HAMPTON", "loc" : [ -82.189144, 36.257743 ], "pop" : 4828, "state" : "TN" }
+{ "_id" : "37659", "city" : "JONESBOROUGH", "loc" : [ -82.490225, 36.295426 ], "pop" : 18736, "state" : "TN" }
+{ "_id" : "37660", "city" : "BLOOMINGDALE", "loc" : [ -82.554034, 36.552766 ], "pop" : 37726, "state" : "TN" }
+{ "_id" : "37663", "city" : "COLONIAL HEIGHTS", "loc" : [ -82.4948, 36.4693 ], "pop" : 12097, "state" : "TN" }
+{ "_id" : "37664", "city" : "KINGSPORT", "loc" : [ -82.516835, 36.520834 ], "pop" : 22289, "state" : "TN" }
+{ "_id" : "37665", "city" : "LYNN GARDEN", "loc" : [ -82.569906, 36.578305 ], "pop" : 6024, "state" : "TN" }
+{ "_id" : "37680", "city" : "LAUREL BLOOMERY", "loc" : [ -81.725537, 36.574946 ], "pop" : 670, "state" : "TN" }
+{ "_id" : "37681", "city" : "WASHINGTON COLLE", "loc" : [ -82.61709, 36.236968 ], "pop" : 4354, "state" : "TN" }
+{ "_id" : "37683", "city" : "MOUNTAIN CITY", "loc" : [ -81.813999, 36.465724 ], "pop" : 9205, "state" : "TN" }
+{ "_id" : "37686", "city" : "PINEY FLATS", "loc" : [ -82.333957, 36.446122 ], "pop" : 5130, "state" : "TN" }
+{ "_id" : "37687", "city" : "ROAN MOUNTAIN", "loc" : [ -82.081041, 36.177333 ], "pop" : 4234, "state" : "TN" }
+{ "_id" : "37688", "city" : "SHADY VALLEY", "loc" : [ -81.906797, 36.527218 ], "pop" : 1053, "state" : "TN" }
+{ "_id" : "37690", "city" : "TELFORD", "loc" : [ -82.536935, 36.245053 ], "pop" : 2662, "state" : "TN" }
+{ "_id" : "37691", "city" : "TRADE", "loc" : [ -81.757234, 36.368328 ], "pop" : 763, "state" : "TN" }
+{ "_id" : "37692", "city" : "UNICOI", "loc" : [ -82.321957, 36.206585 ], "pop" : 3838, "state" : "TN" }
+{ "_id" : "37694", "city" : "WATAUGA", "loc" : [ -82.26826199999999, 36.370157 ], "pop" : 2033, "state" : "TN" }
+{ "_id" : "37701", "city" : "ALCOA", "loc" : [ -83.980895, 35.78522 ], "pop" : 5891, "state" : "TN" }
+{ "_id" : "37705", "city" : "ANDERSONVILLE", "loc" : [ -84.054399, 36.191514 ], "pop" : 5761, "state" : "TN" }
+{ "_id" : "37708", "city" : "BEAN STATION", "loc" : [ -83.31424800000001, 36.32493 ], "pop" : 5255, "state" : "TN" }
+{ "_id" : "37709", "city" : "BLAINE", "loc" : [ -83.67827200000001, 36.15832 ], "pop" : 2556, "state" : "TN" }
+{ "_id" : "37710", "city" : "DEVONIA", "loc" : [ -84.215968, 36.185426 ], "pop" : 2225, "state" : "TN" }
+{ "_id" : "37711", "city" : "BULLS GAP", "loc" : [ -83.03149000000001, 36.325707 ], "pop" : 5876, "state" : "TN" }
+{ "_id" : "37713", "city" : "BYBEE", "loc" : [ -83.163071, 36.073957 ], "pop" : 2911, "state" : "TN" }
+{ "_id" : "37714", "city" : "CARYVILLE", "loc" : [ -84.18979400000001, 36.285422 ], "pop" : 3811, "state" : "TN" }
+{ "_id" : "37715", "city" : "CLAIRFIELD", "loc" : [ -83.93969300000001, 36.565026 ], "pop" : 1239, "state" : "TN" }
+{ "_id" : "37716", "city" : "CLINTON", "loc" : [ -84.189735, 36.08688 ], "pop" : 21075, "state" : "TN" }
+{ "_id" : "37721", "city" : "CORRYTON", "loc" : [ -83.813, 36.120011 ], "pop" : 7557, "state" : "TN" }
+{ "_id" : "37722", "city" : "COSBY", "loc" : [ -83.218743, 35.834693 ], "pop" : 3800, "state" : "TN" }
+{ "_id" : "37723", "city" : "CRAB ORCHARD", "loc" : [ -84.858577, 35.889763 ], "pop" : 2307, "state" : "TN" }
+{ "_id" : "37724", "city" : "CUMBERLAND GAP", "loc" : [ -83.681049, 36.550381 ], "pop" : 3142, "state" : "TN" }
+{ "_id" : "37725", "city" : "DANDRIDGE", "loc" : [ -83.40443500000001, 36.001798 ], "pop" : 8707, "state" : "TN" }
+{ "_id" : "37726", "city" : "DEER LODGE", "loc" : [ -84.819074, 36.217584 ], "pop" : 538, "state" : "TN" }
+{ "_id" : "37727", "city" : "DEL RIO", "loc" : [ -83.01500799999999, 35.882967 ], "pop" : 1616, "state" : "TN" }
+{ "_id" : "37729", "city" : "DUFF", "loc" : [ -84.01246999999999, 36.411035 ], "pop" : 4265, "state" : "TN" }
+{ "_id" : "37731", "city" : "EIDSON", "loc" : [ -83.08271999999999, 36.499522 ], "pop" : 901, "state" : "TN" }
+{ "_id" : "37737", "city" : "FRIENDSVILLE", "loc" : [ -84.10606900000001, 35.752302 ], "pop" : 4186, "state" : "TN" }
+{ "_id" : "37738", "city" : "GATLINBURG", "loc" : [ -83.48740599999999, 35.728976 ], "pop" : 4352, "state" : "TN" }
+{ "_id" : "37742", "city" : "GREENBACK", "loc" : [ -84.170959, 35.656738 ], "pop" : 3272, "state" : "TN" }
+{ "_id" : "37743", "city" : "BAILEYTON", "loc" : [ -82.833136, 36.160807 ], "pop" : 39225, "state" : "TN" }
+{ "_id" : "37748", "city" : "HARRIMAN", "loc" : [ -84.51552599999999, 35.934785 ], "pop" : 18558, "state" : "TN" }
+{ "_id" : "37752", "city" : "HARROGATE", "loc" : [ -83.60726200000001, 36.576718 ], "pop" : 4683, "state" : "TN" }
+{ "_id" : "37753", "city" : "HARTFORD", "loc" : [ -83.099642, 35.825597 ], "pop" : 733, "state" : "TN" }
+{ "_id" : "37754", "city" : "HEISKELL", "loc" : [ -84.043826, 36.115027 ], "pop" : 2945, "state" : "TN" }
+{ "_id" : "37755", "city" : "HELENWOOD", "loc" : [ -84.538088, 36.43294 ], "pop" : 2583, "state" : "TN" }
+{ "_id" : "37756", "city" : "HUNTSVILLE", "loc" : [ -84.428832, 36.398329 ], "pop" : 4760, "state" : "TN" }
+{ "_id" : "37757", "city" : "JACKSBORO", "loc" : [ -84.192835, 36.326615 ], "pop" : 4967, "state" : "TN" }
+{ "_id" : "37760", "city" : "JEFFERSON CITY", "loc" : [ -83.480982, 36.11633 ], "pop" : 9438, "state" : "TN" }
+{ "_id" : "37762", "city" : "JELLICO", "loc" : [ -84.118067, 36.554407 ], "pop" : 6317, "state" : "TN" }
+{ "_id" : "37763", "city" : "KINGSTON", "loc" : [ -84.49705400000001, 35.852807 ], "pop" : 11002, "state" : "TN" }
+{ "_id" : "37764", "city" : "KODAK", "loc" : [ -83.61711099999999, 35.972215 ], "pop" : 4104, "state" : "TN" }
+{ "_id" : "37765", "city" : "KYLES FORD", "loc" : [ -83.050712, 36.572072 ], "pop" : 931, "state" : "TN" }
+{ "_id" : "37766", "city" : "MORLEY", "loc" : [ -84.11156800000001, 36.368967 ], "pop" : 14939, "state" : "TN" }
+{ "_id" : "37769", "city" : "LAKE CITY", "loc" : [ -84.13856699999999, 36.203223 ], "pop" : 6099, "state" : "TN" }
+{ "_id" : "37770", "city" : "LANCING", "loc" : [ -84.71351900000001, 36.145644 ], "pop" : 2345, "state" : "TN" }
+{ "_id" : "37771", "city" : "LENOIR CITY", "loc" : [ -84.26650100000001, 35.810391 ], "pop" : 18523, "state" : "TN" }
+{ "_id" : "37774", "city" : "LOUDON", "loc" : [ -84.34362, 35.729211 ], "pop" : 11116, "state" : "TN" }
+{ "_id" : "37777", "city" : "LOUISVILLE", "loc" : [ -84.008895, 35.837465 ], "pop" : 9618, "state" : "TN" }
+{ "_id" : "37778", "city" : "LOWLAND", "loc" : [ -83.244592, 36.164016 ], "pop" : 166, "state" : "TN" }
+{ "_id" : "37779", "city" : "LUTTRELL", "loc" : [ -83.75997599999999, 36.200136 ], "pop" : 3554, "state" : "TN" }
+{ "_id" : "37801", "city" : "MARYVILLE", "loc" : [ -83.914541, 35.782449 ], "pop" : 24011, "state" : "TN" }
+{ "_id" : "37804", "city" : "MARYVILLE", "loc" : [ -84.004491, 35.715659 ], "pop" : 31758, "state" : "TN" }
+{ "_id" : "37806", "city" : "MASCOT", "loc" : [ -83.741101, 36.084421 ], "pop" : 2781, "state" : "TN" }
+{ "_id" : "37807", "city" : "MAYNARDVILLE", "loc" : [ -83.840261, 36.234274 ], "pop" : 8998, "state" : "TN" }
+{ "_id" : "37809", "city" : "MIDWAY", "loc" : [ -83.02814100000001, 36.150995 ], "pop" : 824, "state" : "TN" }
+{ "_id" : "37810", "city" : "MOHAWK", "loc" : [ -83.09018500000001, 36.186919 ], "pop" : 1765, "state" : "TN" }
+{ "_id" : "37811", "city" : "MOORESBURG", "loc" : [ -83.20949899999999, 36.362082 ], "pop" : 2628, "state" : "TN" }
+{ "_id" : "37813", "city" : "MORRISTOWN", "loc" : [ -83.275519, 36.195672 ], "pop" : 15333, "state" : "TN" }
+{ "_id" : "37814", "city" : "MORRISTOWN", "loc" : [ -83.31185000000001, 36.224782 ], "pop" : 26285, "state" : "TN" }
+{ "_id" : "37818", "city" : "MOSHEIM", "loc" : [ -82.967399, 36.183883 ], "pop" : 4337, "state" : "TN" }
+{ "_id" : "37819", "city" : "NEWCOMB", "loc" : [ -84.17984800000001, 36.542768 ], "pop" : 52, "state" : "TN" }
+{ "_id" : "37820", "city" : "NEW MARKET", "loc" : [ -83.56725299999999, 36.081037 ], "pop" : 5751, "state" : "TN" }
+{ "_id" : "37821", "city" : "NEWPORT", "loc" : [ -83.202749, 35.954431 ], "pop" : 16780, "state" : "TN" }
+{ "_id" : "37825", "city" : "NEW TAZEWELL", "loc" : [ -83.64694900000001, 36.424475 ], "pop" : 5602, "state" : "TN" }
+{ "_id" : "37826", "city" : "NIOTA", "loc" : [ -84.57214999999999, 35.581924 ], "pop" : 2182, "state" : "TN" }
+{ "_id" : "37829", "city" : "OAKDALE", "loc" : [ -84.575295, 36.009962 ], "pop" : 3901, "state" : "TN" }
+{ "_id" : "37830", "city" : "OAK RIDGE", "loc" : [ -84.262297, 36.01588 ], "pop" : 27605, "state" : "TN" }
+{ "_id" : "37840", "city" : "OLIVER SPRINGS", "loc" : [ -84.34863199999999, 36.036616 ], "pop" : 1324, "state" : "TN" }
+{ "_id" : "37841", "city" : "ONEIDA", "loc" : [ -84.529319, 36.505259 ], "pop" : 7010, "state" : "TN" }
+{ "_id" : "37843", "city" : "PARROTTSVILLE", "loc" : [ -83.073627, 35.998297 ], "pop" : 3301, "state" : "TN" }
+{ "_id" : "37845", "city" : "PETROS", "loc" : [ -84.439914, 36.055903 ], "pop" : 4330, "state" : "TN" }
+{ "_id" : "37846", "city" : "PHILADELPHIA", "loc" : [ -84.450221, 35.664214 ], "pop" : 1523, "state" : "TN" }
+{ "_id" : "37847", "city" : "PIONEER", "loc" : [ -84.290672, 36.469465 ], "pop" : 476, "state" : "TN" }
+{ "_id" : "37848", "city" : "POWDER SPRINGS", "loc" : [ -83.672921, 36.254899 ], "pop" : 381, "state" : "TN" }
+{ "_id" : "37849", "city" : "POWELL", "loc" : [ -84.039987, 36.043454 ], "pop" : 14646, "state" : "TN" }
+{ "_id" : "37852", "city" : "ROBBINS", "loc" : [ -84.590417, 36.352693 ], "pop" : 2639, "state" : "TN" }
+{ "_id" : "37853", "city" : "ROCKFORD", "loc" : [ -83.941202, 35.830519 ], "pop" : 3347, "state" : "TN" }
+{ "_id" : "37854", "city" : "ROCKWOOD", "loc" : [ -84.68418800000001, 35.858677 ], "pop" : 10384, "state" : "TN" }
+{ "_id" : "37857", "city" : "ROGERSVILLE", "loc" : [ -83.010786, 36.416196 ], "pop" : 10374, "state" : "TN" }
+{ "_id" : "37860", "city" : "RUSSELLVILLE", "loc" : [ -83.19138, 36.256684 ], "pop" : 2329, "state" : "TN" }
+{ "_id" : "37861", "city" : "RUTLEDGE", "loc" : [ -83.512468, 36.250078 ], "pop" : 6019, "state" : "TN" }
+{ "_id" : "37862", "city" : "SEVIERVILLE", "loc" : [ -83.53862100000001, 35.845192 ], "pop" : 30351, "state" : "TN" }
+{ "_id" : "37863", "city" : "PIGEON FORGE", "loc" : [ -83.563821, 35.792222 ], "pop" : 3063, "state" : "TN" }
+{ "_id" : "37865", "city" : "SEYMOUR", "loc" : [ -83.749511, 35.869984 ], "pop" : 8527, "state" : "TN" }
+{ "_id" : "37866", "city" : "SHARPS CHAPEL", "loc" : [ -83.81268, 36.368498 ], "pop" : 1405, "state" : "TN" }
+{ "_id" : "37869", "city" : "SNEEDVILLE", "loc" : [ -83.252892, 36.527515 ], "pop" : 5203, "state" : "TN" }
+{ "_id" : "37870", "city" : "SPEEDWELL", "loc" : [ -83.813495, 36.479723 ], "pop" : 2895, "state" : "TN" }
+{ "_id" : "37871", "city" : "STRAWBERRY PLAIN", "loc" : [ -83.677724, 36.041462 ], "pop" : 5600, "state" : "TN" }
+{ "_id" : "37872", "city" : "SUNBRIGHT", "loc" : [ -84.69842, 36.262234 ], "pop" : 2210, "state" : "TN" }
+{ "_id" : "37873", "city" : "SURGOINSVILLE", "loc" : [ -82.830597, 36.474066 ], "pop" : 7229, "state" : "TN" }
+{ "_id" : "37874", "city" : "SWEETWATER", "loc" : [ -84.430424, 35.595703 ], "pop" : 11415, "state" : "TN" }
+{ "_id" : "37877", "city" : "TALBOTT", "loc" : [ -83.412864, 36.159958 ], "pop" : 6279, "state" : "TN" }
+{ "_id" : "37878", "city" : "TALLASSEE", "loc" : [ -84.003338, 35.583663 ], "pop" : 376, "state" : "TN" }
+{ "_id" : "37879", "city" : "TAZEWELL", "loc" : [ -83.55521899999999, 36.471012 ], "pop" : 8567, "state" : "TN" }
+{ "_id" : "37880", "city" : "TEN MILE", "loc" : [ -84.654848, 35.686175 ], "pop" : 4355, "state" : "TN" }
+{ "_id" : "37881", "city" : "THORN HILL", "loc" : [ -83.365973, 36.391687 ], "pop" : 1676, "state" : "TN" }
+{ "_id" : "37882", "city" : "TOWNSEND", "loc" : [ -83.75715700000001, 35.678385 ], "pop" : 1951, "state" : "TN" }
+{ "_id" : "37883", "city" : "TREADWAY", "loc" : [ -83.219138, 36.428202 ], "pop" : 78, "state" : "TN" }
+{ "_id" : "37885", "city" : "VONORE", "loc" : [ -84.177829, 35.535364 ], "pop" : 1541, "state" : "TN" }
+{ "_id" : "37886", "city" : "WALLAND", "loc" : [ -83.824307, 35.753311 ], "pop" : 3972, "state" : "TN" }
+{ "_id" : "37887", "city" : "WARTBURG", "loc" : [ -84.56518800000001, 36.101609 ], "pop" : 3976, "state" : "TN" }
+{ "_id" : "37888", "city" : "WASHBURN", "loc" : [ -83.59368499999999, 36.310649 ], "pop" : 1737, "state" : "TN" }
+{ "_id" : "37890", "city" : "BANEBERRY", "loc" : [ -83.287921, 36.090299 ], "pop" : 4639, "state" : "TN" }
+{ "_id" : "37891", "city" : "WHITESBURG", "loc" : [ -83.145844, 36.262125 ], "pop" : 2265, "state" : "TN" }
+{ "_id" : "37892", "city" : "WINFIELD", "loc" : [ -84.434026, 36.559825 ], "pop" : 1375, "state" : "TN" }
+{ "_id" : "37902", "city" : "KNOXVILLE", "loc" : [ -83.92091499999999, 35.962516 ], "pop" : 1457, "state" : "TN" }
+{ "_id" : "37909", "city" : "KNOXVILLE", "loc" : [ -84.023501, 35.945978 ], "pop" : 13265, "state" : "TN" }
+{ "_id" : "37912", "city" : "KNOXVILLE", "loc" : [ -83.977317, 36.005492 ], "pop" : 16919, "state" : "TN" }
+{ "_id" : "37914", "city" : "KNOXVILLE", "loc" : [ -83.84962400000001, 35.991755 ], "pop" : 19867, "state" : "TN" }
+{ "_id" : "37915", "city" : "KNOXVILLE", "loc" : [ -83.901005, 35.972074 ], "pop" : 6546, "state" : "TN" }
+{ "_id" : "37916", "city" : "KNOXVILLE", "loc" : [ -83.933576, 35.955584 ], "pop" : 11449, "state" : "TN" }
+{ "_id" : "37917", "city" : "KNOXVILLE", "loc" : [ -83.915216, 35.99803 ], "pop" : 25362, "state" : "TN" }
+{ "_id" : "37918", "city" : "KNOXVILLE", "loc" : [ -83.922558, 36.050054 ], "pop" : 32073, "state" : "TN" }
+{ "_id" : "37919", "city" : "KNOXVILLE", "loc" : [ -84.001468, 35.924385 ], "pop" : 25653, "state" : "TN" }
+{ "_id" : "37920", "city" : "KIMBERLIN HEIGHT", "loc" : [ -83.87979300000001, 35.922976 ], "pop" : 35762, "state" : "TN" }
+{ "_id" : "37921", "city" : "KARNS", "loc" : [ -83.982894, 35.976297 ], "pop" : 26904, "state" : "TN" }
+{ "_id" : "37922", "city" : "CONCORD", "loc" : [ -84.127332, 35.877697 ], "pop" : 31414, "state" : "TN" }
+{ "_id" : "37923", "city" : "KNOXVILLE", "loc" : [ -84.076116, 35.933127 ], "pop" : 22830, "state" : "TN" }
+{ "_id" : "37924", "city" : "KNOXVILLE", "loc" : [ -83.80207, 36.032044 ], "pop" : 8103, "state" : "TN" }
+{ "_id" : "37931", "city" : "KNOXVILLE", "loc" : [ -84.12007199999999, 35.992363 ], "pop" : 17247, "state" : "TN" }
+{ "_id" : "37932", "city" : "CONCORD FARRAGUT", "loc" : [ -84.169591, 35.923619 ], "pop" : 7975, "state" : "TN" }
+{ "_id" : "37938", "city" : "KNOXVILLE", "loc" : [ -83.94596799999999, 36.105473 ], "pop" : 10705, "state" : "TN" }
+{ "_id" : "38001", "city" : "ALAMO", "loc" : [ -89.17646499999999, 35.801697 ], "pop" : 6528, "state" : "TN" }
+{ "_id" : "38002", "city" : "ARLINGTON", "loc" : [ -89.729502, 35.275171 ], "pop" : 6781, "state" : "TN" }
+{ "_id" : "38004", "city" : "ATOKA", "loc" : [ -89.8216, 35.421337 ], "pop" : 4848, "state" : "TN" }
+{ "_id" : "38006", "city" : "BELLS", "loc" : [ -89.072857, 35.71976 ], "pop" : 3092, "state" : "TN" }
+{ "_id" : "38008", "city" : "BOLIVAR", "loc" : [ -89.00072299999999, 35.246082 ], "pop" : 10327, "state" : "TN" }
+{ "_id" : "38011", "city" : "BRIGHTON", "loc" : [ -89.752477, 35.470328 ], "pop" : 9668, "state" : "TN" }
+{ "_id" : "38012", "city" : "BROWNSVILLE", "loc" : [ -89.26235200000001, 35.609957 ], "pop" : 16497, "state" : "TN" }
+{ "_id" : "38015", "city" : "BURLISON", "loc" : [ -89.817729, 35.53995 ], "pop" : 2314, "state" : "TN" }
+{ "_id" : "38017", "city" : "COLLIERVILLE", "loc" : [ -89.67672399999999, 35.055077 ], "pop" : 16164, "state" : "TN" }
+{ "_id" : "38018", "city" : "CORDOVA", "loc" : [ -89.77893400000001, 35.156349 ], "pop" : 21777, "state" : "TN" }
+{ "_id" : "38019", "city" : "COVINGTON", "loc" : [ -89.650144, 35.559838 ], "pop" : 13631, "state" : "TN" }
+{ "_id" : "38023", "city" : "DRUMMONDS", "loc" : [ -89.923649, 35.445203 ], "pop" : 4891, "state" : "TN" }
+{ "_id" : "38024", "city" : "DYERSBURG", "loc" : [ -89.383644, 36.044447 ], "pop" : 27839, "state" : "TN" }
+{ "_id" : "38028", "city" : "EADS", "loc" : [ -89.67600400000001, 35.15512 ], "pop" : 1715, "state" : "TN" }
+{ "_id" : "38030", "city" : "FINLEY", "loc" : [ -89.513403, 36.016938 ], "pop" : 830, "state" : "TN" }
+{ "_id" : "38034", "city" : "FRIENDSHIP", "loc" : [ -89.20413600000001, 35.897642 ], "pop" : 1626, "state" : "TN" }
+{ "_id" : "38037", "city" : "GATES", "loc" : [ -89.459182, 35.843942 ], "pop" : 2508, "state" : "TN" }
+{ "_id" : "38039", "city" : "GRAND JUNCTION", "loc" : [ -89.153415, 35.065885 ], "pop" : 1827, "state" : "TN" }
+{ "_id" : "38040", "city" : "HALLS", "loc" : [ -89.414671, 35.886232 ], "pop" : 3755, "state" : "TN" }
+{ "_id" : "38041", "city" : "FORT PILLOW", "loc" : [ -89.637542, 35.682868 ], "pop" : 4298, "state" : "TN" }
+{ "_id" : "38042", "city" : "HICKORY VALLEY", "loc" : [ -89.130905, 35.157959 ], "pop" : 269, "state" : "TN" }
+{ "_id" : "38044", "city" : "HORNSBY", "loc" : [ -88.82631499999999, 35.219706 ], "pop" : 946, "state" : "TN" }
+{ "_id" : "38049", "city" : "MASON", "loc" : [ -89.551805, 35.438012 ], "pop" : 2275, "state" : "TN" }
+{ "_id" : "38052", "city" : "MIDDLETON", "loc" : [ -88.904625, 35.0818 ], "pop" : 3147, "state" : "TN" }
+{ "_id" : "38053", "city" : "MILLINGTON", "loc" : [ -89.905422, 35.318463 ], "pop" : 38216, "state" : "TN" }
+{ "_id" : "38057", "city" : "MOSCOW", "loc" : [ -89.35950800000001, 35.058796 ], "pop" : 3436, "state" : "TN" }
+{ "_id" : "38059", "city" : "NEWBERN", "loc" : [ -89.251364, 36.100875 ], "pop" : 5426, "state" : "TN" }
+{ "_id" : "38060", "city" : "OAKLAND", "loc" : [ -89.55176400000001, 35.222929 ], "pop" : 5935, "state" : "TN" }
+{ "_id" : "38061", "city" : "POCAHONTAS", "loc" : [ -88.811559, 35.031476 ], "pop" : 570, "state" : "TN" }
+{ "_id" : "38063", "city" : "RIPLEY", "loc" : [ -89.534975, 35.752651 ], "pop" : 12930, "state" : "TN" }
+{ "_id" : "38066", "city" : "ROSSVILLE", "loc" : [ -89.567848, 35.076758 ], "pop" : 3730, "state" : "TN" }
+{ "_id" : "38067", "city" : "SAULSBURY", "loc" : [ -89.076868, 35.049786 ], "pop" : 914, "state" : "TN" }
+{ "_id" : "38068", "city" : "SOMERVILLE", "loc" : [ -89.391813, 35.277218 ], "pop" : 11757, "state" : "TN" }
+{ "_id" : "38069", "city" : "STANTON", "loc" : [ -89.33262999999999, 35.448171 ], "pop" : 2940, "state" : "TN" }
+{ "_id" : "38075", "city" : "WHITEVILLE", "loc" : [ -89.133692, 35.319104 ], "pop" : 3044, "state" : "TN" }
+{ "_id" : "38076", "city" : "WILLISTON", "loc" : [ -89.390584, 35.166595 ], "pop" : 701, "state" : "TN" }
+{ "_id" : "38079", "city" : "TIPTONVILLE", "loc" : [ -89.464922, 36.384583 ], "pop" : 4762, "state" : "TN" }
+{ "_id" : "38080", "city" : "RIDGELY", "loc" : [ -89.485765, 36.263849 ], "pop" : 1819, "state" : "TN" }
+{ "_id" : "38103", "city" : "MEMPHIS", "loc" : [ -90.047995, 35.144001 ], "pop" : 4144, "state" : "TN" }
+{ "_id" : "38104", "city" : "MEMPHIS", "loc" : [ -90.004625, 35.133393 ], "pop" : 29496, "state" : "TN" }
+{ "_id" : "38105", "city" : "MEMPHIS", "loc" : [ -90.03304199999999, 35.149748 ], "pop" : 11143, "state" : "TN" }
+{ "_id" : "38106", "city" : "MEMPHIS", "loc" : [ -90.03299699999999, 35.102124 ], "pop" : 40444, "state" : "TN" }
+{ "_id" : "38107", "city" : "MEMPHIS", "loc" : [ -90.020077, 35.183136 ], "pop" : 43502, "state" : "TN" }
+{ "_id" : "38108", "city" : "MEMPHIS", "loc" : [ -89.968238, 35.178655 ], "pop" : 31902, "state" : "TN" }
+{ "_id" : "38109", "city" : "MEMPHIS", "loc" : [ -90.073238, 35.042538 ], "pop" : 60508, "state" : "TN" }
+{ "_id" : "38111", "city" : "MEMPHIS", "loc" : [ -89.945745, 35.107573 ], "pop" : 43484, "state" : "TN" }
+{ "_id" : "38112", "city" : "MEMPHIS", "loc" : [ -89.97289499999999, 35.148277 ], "pop" : 21266, "state" : "TN" }
+{ "_id" : "38113", "city" : "MEMPHIS", "loc" : [ -90.079426, 35.111201 ], "pop" : 68, "state" : "TN" }
+{ "_id" : "38114", "city" : "MEMPHIS", "loc" : [ -89.98254, 35.098094 ], "pop" : 38708, "state" : "TN" }
+{ "_id" : "38115", "city" : "HICKORY HILL", "loc" : [ -89.86082, 35.054405 ], "pop" : 34144, "state" : "TN" }
+{ "_id" : "38116", "city" : "MEMPHIS", "loc" : [ -90.012314, 35.030298 ], "pop" : 46906, "state" : "TN" }
+{ "_id" : "38117", "city" : "MEMPHIS", "loc" : [ -89.903367, 35.112357 ], "pop" : 27149, "state" : "TN" }
+{ "_id" : "38118", "city" : "MEMPHIS", "loc" : [ -89.92653799999999, 35.051421 ], "pop" : 45507, "state" : "TN" }
+{ "_id" : "38119", "city" : "MEMPHIS", "loc" : [ -89.85014200000001, 35.082101 ], "pop" : 20234, "state" : "TN" }
+{ "_id" : "38120", "city" : "MEMPHIS", "loc" : [ -89.86511900000001, 35.120654 ], "pop" : 12552, "state" : "TN" }
+{ "_id" : "38122", "city" : "MEMPHIS", "loc" : [ -89.926844, 35.157166 ], "pop" : 23692, "state" : "TN" }
+{ "_id" : "38125", "city" : "MEMPHIS", "loc" : [ -89.81235700000001, 35.031249 ], "pop" : 10280, "state" : "TN" }
+{ "_id" : "38126", "city" : "MEMPHIS", "loc" : [ -90.042444, 35.125518 ], "pop" : 16391, "state" : "TN" }
+{ "_id" : "38127", "city" : "MEMPHIS", "loc" : [ -90.029623, 35.250982 ], "pop" : 8047, "state" : "TN" }
+{ "_id" : "38128", "city" : "MEMPHIS", "loc" : [ -89.94131400000001, 35.221273 ], "pop" : 54198, "state" : "TN" }
+{ "_id" : "38131", "city" : "MEMPHIS", "loc" : [ -90.003699, 35.0655 ], "pop" : 312, "state" : "TN" }
+{ "_id" : "38132", "city" : "MEMPHIS", "loc" : [ -89.98862699999999, 35.071967 ], "pop" : 2, "state" : "TN" }
+{ "_id" : "38133", "city" : "MEMPHIS", "loc" : [ -89.80356399999999, 35.205362 ], "pop" : 13227, "state" : "TN" }
+{ "_id" : "38134", "city" : "BARTLETT", "loc" : [ -89.86409, 35.188639 ], "pop" : 40805, "state" : "TN" }
+{ "_id" : "38135", "city" : "MEMPHIS", "loc" : [ -89.85087799999999, 35.232301 ], "pop" : 13428, "state" : "TN" }
+{ "_id" : "38138", "city" : "GERMANTOWN", "loc" : [ -89.80526, 35.088344 ], "pop" : 22061, "state" : "TN" }
+{ "_id" : "38139", "city" : "GERMANTOWN", "loc" : [ -89.770281, 35.087414 ], "pop" : 11771, "state" : "TN" }
+{ "_id" : "38141", "city" : "MEMPHIS", "loc" : [ -89.84916, 35.023091 ], "pop" : 16247, "state" : "TN" }
+{ "_id" : "38201", "city" : "MC KENZIE", "loc" : [ -88.51341600000001, 36.127195 ], "pop" : 6780, "state" : "TN" }
+{ "_id" : "38220", "city" : "ATWOOD", "loc" : [ -88.624656, 35.966345 ], "pop" : 2599, "state" : "TN" }
+{ "_id" : "38221", "city" : "BIG SANDY", "loc" : [ -88.062732, 36.228515 ], "pop" : 2647, "state" : "TN" }
+{ "_id" : "38222", "city" : "BUCHANAN", "loc" : [ -88.151464, 36.414624 ], "pop" : 3352, "state" : "TN" }
+{ "_id" : "38224", "city" : "COTTAGE GROVE", "loc" : [ -88.461421, 36.34789 ], "pop" : 1645, "state" : "TN" }
+{ "_id" : "38225", "city" : "DRESDEN", "loc" : [ -88.696291, 36.295042 ], "pop" : 5475, "state" : "TN" }
+{ "_id" : "38226", "city" : "DUKEDOM", "loc" : [ -88.692553, 36.479645 ], "pop" : 933, "state" : "TN" }
+{ "_id" : "38229", "city" : "GLEASON", "loc" : [ -88.618441, 36.211737 ], "pop" : 3307, "state" : "TN" }
+{ "_id" : "38230", "city" : "GREENFIELD", "loc" : [ -88.74532000000001, 36.148502 ], "pop" : 4682, "state" : "TN" }
+{ "_id" : "38231", "city" : "HENRY", "loc" : [ -88.453609, 36.201343 ], "pop" : 1520, "state" : "TN" }
+{ "_id" : "38232", "city" : "HORNBEAK", "loc" : [ -89.305617, 36.359594 ], "pop" : 3042, "state" : "TN" }
+{ "_id" : "38233", "city" : "KENTON", "loc" : [ -89.022879, 36.190583 ], "pop" : 1446, "state" : "TN" }
+{ "_id" : "38236", "city" : "MANSFIELD", "loc" : [ -88.285934, 36.184744 ], "pop" : 1091, "state" : "TN" }
+{ "_id" : "38237", "city" : "MARTIN", "loc" : [ -88.855395, 36.342467 ], "pop" : 13540, "state" : "TN" }
+{ "_id" : "38240", "city" : "OBION", "loc" : [ -89.28052, 36.265679 ], "pop" : 3419, "state" : "TN" }
+{ "_id" : "38241", "city" : "PALMERSVILLE", "loc" : [ -88.614178, 36.394772 ], "pop" : 1471, "state" : "TN" }
+{ "_id" : "38242", "city" : "PARIS", "loc" : [ -88.30932799999999, 36.300519 ], "pop" : 16597, "state" : "TN" }
+{ "_id" : "38251", "city" : "PURYEAR", "loc" : [ -88.347193, 36.445632 ], "pop" : 2292, "state" : "TN" }
+{ "_id" : "38253", "city" : "RIVES", "loc" : [ -89.037632, 36.263665 ], "pop" : 2424, "state" : "TN" }
+{ "_id" : "38255", "city" : "SHARON", "loc" : [ -88.847661, 36.239454 ], "pop" : 2564, "state" : "TN" }
+{ "_id" : "38256", "city" : "SPRINGVILLE", "loc" : [ -88.14594099999999, 36.265033 ], "pop" : 1391, "state" : "TN" }
+{ "_id" : "38257", "city" : "SOUTH FULTON", "loc" : [ -88.880781, 36.481386 ], "pop" : 4676, "state" : "TN" }
+{ "_id" : "38258", "city" : "TREZEVANT", "loc" : [ -88.61003599999999, 36.017213 ], "pop" : 2052, "state" : "TN" }
+{ "_id" : "38259", "city" : "TRIMBLE", "loc" : [ -89.18626500000001, 36.201113 ], "pop" : 792, "state" : "TN" }
+{ "_id" : "38260", "city" : "TROY", "loc" : [ -89.161058, 36.341644 ], "pop" : 1588, "state" : "TN" }
+{ "_id" : "38261", "city" : "UNION CITY", "loc" : [ -89.06666199999999, 36.426311 ], "pop" : 17007, "state" : "TN" }
+{ "_id" : "38301", "city" : "JACKSON", "loc" : [ -88.81401099999999, 35.610222 ], "pop" : 39275, "state" : "TN" }
+{ "_id" : "38305", "city" : "JACKSON", "loc" : [ -88.82812699999999, 35.682875 ], "pop" : 28992, "state" : "TN" }
+{ "_id" : "38310", "city" : "ADAMSVILLE", "loc" : [ -88.41336699999999, 35.25561 ], "pop" : 3042, "state" : "TN" }
+{ "_id" : "38311", "city" : "BATH SPRINGS", "loc" : [ -88.12863, 35.452111 ], "pop" : 920, "state" : "TN" }
+{ "_id" : "38313", "city" : "BEECH BLUFF", "loc" : [ -88.639634, 35.592156 ], "pop" : 2682, "state" : "TN" }
+{ "_id" : "38315", "city" : "BETHEL SPRINGS", "loc" : [ -88.64397200000001, 35.228893 ], "pop" : 2457, "state" : "TN" }
+{ "_id" : "38316", "city" : "BRADFORD", "loc" : [ -88.804593, 36.064474 ], "pop" : 2884, "state" : "TN" }
+{ "_id" : "38317", "city" : "BRUCETON", "loc" : [ -88.25180400000001, 36.026792 ], "pop" : 2035, "state" : "TN" }
+{ "_id" : "38318", "city" : "BUENA VISTA", "loc" : [ -88.292576, 35.943119 ], "pop" : 165, "state" : "TN" }
+{ "_id" : "38320", "city" : "CAMDEN", "loc" : [ -88.111853, 36.055578 ], "pop" : 8922, "state" : "TN" }
+{ "_id" : "38321", "city" : "CEDAR GROVE", "loc" : [ -88.55170200000001, 35.861261 ], "pop" : 1150, "state" : "TN" }
+{ "_id" : "38326", "city" : "COUNCE", "loc" : [ -88.293567, 35.039415 ], "pop" : 2015, "state" : "TN" }
+{ "_id" : "38327", "city" : "CRUMP", "loc" : [ -88.335641, 35.221641 ], "pop" : 1507, "state" : "TN" }
+{ "_id" : "38328", "city" : "DARDEN", "loc" : [ -88.217688, 35.662962 ], "pop" : 533, "state" : "TN" }
+{ "_id" : "38329", "city" : "DECATURVILLE", "loc" : [ -88.133413, 35.558455 ], "pop" : 2806, "state" : "TN" }
+{ "_id" : "38330", "city" : "DYER", "loc" : [ -89.019226, 36.071578 ], "pop" : 4695, "state" : "TN" }
+{ "_id" : "38332", "city" : "ENVILLE", "loc" : [ -88.420613, 35.439321 ], "pop" : 1041, "state" : "TN" }
+{ "_id" : "38333", "city" : "EVA", "loc" : [ -88.028036, 36.078814 ], "pop" : 1536, "state" : "TN" }
+{ "_id" : "38334", "city" : "FINGER", "loc" : [ -88.606709, 35.325208 ], "pop" : 1840, "state" : "TN" }
+{ "_id" : "38337", "city" : "GADSDEN", "loc" : [ -88.992947, 35.779867 ], "pop" : 2132, "state" : "TN" }
+{ "_id" : "38339", "city" : "GUYS", "loc" : [ -88.52076099999999, 35.014211 ], "pop" : 689, "state" : "TN" }
+{ "_id" : "38340", "city" : "HENDERSON", "loc" : [ -88.639774, 35.426929 ], "pop" : 10311, "state" : "TN" }
+{ "_id" : "38341", "city" : "HOLLADAY", "loc" : [ -88.091183, 35.895143 ], "pop" : 1419, "state" : "TN" }
+{ "_id" : "38342", "city" : "HOLLOW ROCK", "loc" : [ -88.29013500000001, 36.056524 ], "pop" : 2547, "state" : "TN" }
+{ "_id" : "38343", "city" : "HUMBOLDT", "loc" : [ -88.905652, 35.836993 ], "pop" : 13410, "state" : "TN" }
+{ "_id" : "38344", "city" : "HUNTINGDON", "loc" : [ -88.42021099999999, 36.006228 ], "pop" : 7034, "state" : "TN" }
+{ "_id" : "38345", "city" : "HURON", "loc" : [ -88.519549, 35.614377 ], "pop" : 1665, "state" : "TN" }
+{ "_id" : "38347", "city" : "JACKS CREEK", "loc" : [ -88.501865, 35.478206 ], "pop" : 288, "state" : "TN" }
+{ "_id" : "38348", "city" : "LAVINIA", "loc" : [ -88.632442, 35.85834 ], "pop" : 1183, "state" : "TN" }
+{ "_id" : "38351", "city" : "LEXINGTON", "loc" : [ -88.392743, 35.651195 ], "pop" : 13554, "state" : "TN" }
+{ "_id" : "38352", "city" : "LURAY", "loc" : [ -88.578422, 35.598846 ], "pop" : 94, "state" : "TN" }
+{ "_id" : "38355", "city" : "MEDINA", "loc" : [ -88.762655, 35.808088 ], "pop" : 1303, "state" : "TN" }
+{ "_id" : "38356", "city" : "MEDON", "loc" : [ -88.871656, 35.471804 ], "pop" : 1486, "state" : "TN" }
+{ "_id" : "38357", "city" : "MICHIE", "loc" : [ -88.44046299999999, 35.060306 ], "pop" : 2297, "state" : "TN" }
+{ "_id" : "38358", "city" : "MILAN", "loc" : [ -88.768844, 35.925089 ], "pop" : 11377, "state" : "TN" }
+{ "_id" : "38359", "city" : "MILLEDGEVILLE", "loc" : [ -88.399125, 35.345175 ], "pop" : 449, "state" : "TN" }
+{ "_id" : "38361", "city" : "MORRIS CHAPEL", "loc" : [ -88.317599, 35.302562 ], "pop" : 1272, "state" : "TN" }
+{ "_id" : "38362", "city" : "OAKFIELD", "loc" : [ -88.802145, 35.754756 ], "pop" : 2239, "state" : "TN" }
+{ "_id" : "38363", "city" : "PARSONS", "loc" : [ -88.11953200000001, 35.66635 ], "pop" : 5906, "state" : "TN" }
+{ "_id" : "38366", "city" : "PINSON", "loc" : [ -88.730396, 35.478059 ], "pop" : 2598, "state" : "TN" }
+{ "_id" : "38367", "city" : "RAMER", "loc" : [ -88.601733, 35.064181 ], "pop" : 2804, "state" : "TN" }
+{ "_id" : "38368", "city" : "REAGAN", "loc" : [ -88.35077800000001, 35.50957 ], "pop" : 804, "state" : "TN" }
+{ "_id" : "38369", "city" : "RUTHERFORD", "loc" : [ -88.984863, 36.130027 ], "pop" : 2265, "state" : "TN" }
+{ "_id" : "38370", "city" : "SALTILLO", "loc" : [ -88.247225, 35.381467 ], "pop" : 1007, "state" : "TN" }
+{ "_id" : "38371", "city" : "SARDIS", "loc" : [ -88.3058, 35.438598 ], "pop" : 1068, "state" : "TN" }
+{ "_id" : "38372", "city" : "SAVANNAH", "loc" : [ -88.200541, 35.202272 ], "pop" : 15773, "state" : "TN" }
+{ "_id" : "38374", "city" : "SCOTTS HILL", "loc" : [ -88.240476, 35.504992 ], "pop" : 1657, "state" : "TN" }
+{ "_id" : "38375", "city" : "SELMER", "loc" : [ -88.595832, 35.169124 ], "pop" : 7264, "state" : "TN" }
+{ "_id" : "38376", "city" : "SHILOH", "loc" : [ -88.350717, 35.119545 ], "pop" : 438, "state" : "TN" }
+{ "_id" : "38379", "city" : "STANTONVILLE", "loc" : [ -88.436432, 35.180946 ], "pop" : 1580, "state" : "TN" }
+{ "_id" : "38380", "city" : "SUGAR TREE", "loc" : [ -88.03224899999999, 35.791993 ], "pop" : 179, "state" : "TN" }
+{ "_id" : "38381", "city" : "TOONE", "loc" : [ -88.935286, 35.357421 ], "pop" : 2333, "state" : "TN" }
+{ "_id" : "38382", "city" : "TRENTON", "loc" : [ -88.950655, 35.971246 ], "pop" : 9011, "state" : "TN" }
+{ "_id" : "38387", "city" : "WESTPORT", "loc" : [ -88.336364, 35.916918 ], "pop" : 906, "state" : "TN" }
+{ "_id" : "38388", "city" : "WILDERSVILLE", "loc" : [ -88.438794, 35.769772 ], "pop" : 2828, "state" : "TN" }
+{ "_id" : "38390", "city" : "YUMA", "loc" : [ -88.381878, 35.867964 ], "pop" : 1063, "state" : "TN" }
+{ "_id" : "38391", "city" : "DENMARK", "loc" : [ -88.975892, 35.557059 ], "pop" : 1760, "state" : "TN" }
+{ "_id" : "38392", "city" : "MERCER", "loc" : [ -89.03728, 35.481828 ], "pop" : 609, "state" : "TN" }
+{ "_id" : "38401", "city" : "COLUMBIA", "loc" : [ -87.038032, 35.615577 ], "pop" : 38459, "state" : "TN" }
+{ "_id" : "38425", "city" : "CLIFTON", "loc" : [ -87.94996999999999, 35.381948 ], "pop" : 1775, "state" : "TN" }
+{ "_id" : "38449", "city" : "ARDMORE", "loc" : [ -86.879555, 35.057445 ], "pop" : 3560, "state" : "TN" }
+{ "_id" : "38450", "city" : "COLLINWOOD", "loc" : [ -87.71848799999999, 35.163525 ], "pop" : 2558, "state" : "TN" }
+{ "_id" : "38451", "city" : "CULLEOKA", "loc" : [ -87.00050299999999, 35.474914 ], "pop" : 2476, "state" : "TN" }
+{ "_id" : "38452", "city" : "CYPRESS INN", "loc" : [ -87.78833, 35.057945 ], "pop" : 764, "state" : "TN" }
+{ "_id" : "38453", "city" : "ARDMORE", "loc" : [ -86.91002400000001, 35.003654 ], "pop" : 204, "state" : "TN" }
+{ "_id" : "38454", "city" : "DUCK RIVER", "loc" : [ -87.342336, 35.738599 ], "pop" : 1027, "state" : "TN" }
+{ "_id" : "38456", "city" : "ETHRIDGE", "loc" : [ -87.303912, 35.332648 ], "pop" : 3854, "state" : "TN" }
+{ "_id" : "38457", "city" : "FIVE POINTS", "loc" : [ -87.296128, 35.031046 ], "pop" : 798, "state" : "TN" }
+{ "_id" : "38459", "city" : "FRANKEWING", "loc" : [ -86.781818, 35.177854 ], "pop" : 1670, "state" : "TN" }
+{ "_id" : "38460", "city" : "GOODSPRING", "loc" : [ -87.127788, 35.116709 ], "pop" : 889, "state" : "TN" }
+{ "_id" : "38461", "city" : "HAMPSHIRE", "loc" : [ -87.325135, 35.591482 ], "pop" : 1059, "state" : "TN" }
+{ "_id" : "38462", "city" : "KIMMINS", "loc" : [ -87.55461, 35.540837 ], "pop" : 8004, "state" : "TN" }
+{ "_id" : "38463", "city" : "IRON CITY", "loc" : [ -87.64732100000001, 35.056283 ], "pop" : 2249, "state" : "TN" }
+{ "_id" : "38464", "city" : "LAWRENCEBURG", "loc" : [ -87.352582, 35.250668 ], "pop" : 18681, "state" : "TN" }
+{ "_id" : "38468", "city" : "LEOMA", "loc" : [ -87.316773, 35.138177 ], "pop" : 3568, "state" : "TN" }
+{ "_id" : "38469", "city" : "LORETTO", "loc" : [ -87.42697800000001, 35.072797 ], "pop" : 3369, "state" : "TN" }
+{ "_id" : "38471", "city" : "LUTTS", "loc" : [ -87.892291, 35.113842 ], "pop" : 1070, "state" : "TN" }
+{ "_id" : "38472", "city" : "LYNNVILLE", "loc" : [ -87.062877, 35.379235 ], "pop" : 2712, "state" : "TN" }
+{ "_id" : "38473", "city" : "MINOR HILL", "loc" : [ -87.15219399999999, 35.050034 ], "pop" : 1482, "state" : "TN" }
+{ "_id" : "38474", "city" : "MOUNT PLEASANT", "loc" : [ -87.203678, 35.530084 ], "pop" : 7952, "state" : "TN" }
+{ "_id" : "38475", "city" : "OLIVEHILL", "loc" : [ -88.03903800000001, 35.266711 ], "pop" : 443, "state" : "TN" }
+{ "_id" : "38476", "city" : "PRIMM SPRINGS", "loc" : [ -87.25304300000001, 35.810364 ], "pop" : 346, "state" : "TN" }
+{ "_id" : "38477", "city" : "PROSPECT", "loc" : [ -87.01738400000001, 35.066626 ], "pop" : 1843, "state" : "TN" }
+{ "_id" : "38478", "city" : "PULASKI", "loc" : [ -87.03926300000001, 35.209274 ], "pop" : 15310, "state" : "TN" }
+{ "_id" : "38481", "city" : "SAINT JOSEPH", "loc" : [ -87.501807, 35.037556 ], "pop" : 881, "state" : "TN" }
+{ "_id" : "38482", "city" : "SANTA FE", "loc" : [ -87.151543, 35.75877 ], "pop" : 2001, "state" : "TN" }
+{ "_id" : "38483", "city" : "SUMMERTOWN", "loc" : [ -87.31983, 35.430673 ], "pop" : 3302, "state" : "TN" }
+{ "_id" : "38485", "city" : "WAYNESBORO", "loc" : [ -87.739498, 35.322019 ], "pop" : 6381, "state" : "TN" }
+{ "_id" : "38486", "city" : "WESTPOINT", "loc" : [ -87.538025, 35.139302 ], "pop" : 717, "state" : "TN" }
+{ "_id" : "38487", "city" : "WILLIAMSPORT", "loc" : [ -87.225692, 35.64937 ], "pop" : 1199, "state" : "TN" }
+{ "_id" : "38488", "city" : "TAFT", "loc" : [ -86.644672, 35.051731 ], "pop" : 4681, "state" : "TN" }
+{ "_id" : "38501", "city" : "ALGOOD", "loc" : [ -85.49531, 36.174261 ], "pop" : 41805, "state" : "TN" }
+{ "_id" : "38504", "city" : "ALLARDT", "loc" : [ -84.850784, 36.374889 ], "pop" : 3284, "state" : "TN" }
+{ "_id" : "38541", "city" : "ALLONS", "loc" : [ -85.319744, 36.497002 ], "pop" : 1641, "state" : "TN" }
+{ "_id" : "38542", "city" : "ALLRED", "loc" : [ -85.176084, 36.366838 ], "pop" : 2, "state" : "TN" }
+{ "_id" : "38543", "city" : "ALPINE", "loc" : [ -85.152153, 36.380324 ], "pop" : 441, "state" : "TN" }
+{ "_id" : "38544", "city" : "BAXTER", "loc" : [ -85.637766, 36.124917 ], "pop" : 5871, "state" : "TN" }
+{ "_id" : "38545", "city" : "BLOOMINGTON SPRI", "loc" : [ -85.64785999999999, 36.219454 ], "pop" : 1089, "state" : "TN" }
+{ "_id" : "38547", "city" : "BRUSH CREEK", "loc" : [ -86.02034399999999, 36.110673 ], "pop" : 656, "state" : "TN" }
+{ "_id" : "38548", "city" : "BUFFALO VALLEY", "loc" : [ -85.75887899999999, 36.183311 ], "pop" : 704, "state" : "TN" }
+{ "_id" : "38549", "city" : "BYRDSTOWN", "loc" : [ -85.145647, 36.570869 ], "pop" : 2898, "state" : "TN" }
+{ "_id" : "38551", "city" : "CELINA", "loc" : [ -85.496551, 36.547491 ], "pop" : 4102, "state" : "TN" }
+{ "_id" : "38552", "city" : "CHESTNUT MOUND", "loc" : [ -85.837402, 36.192877 ], "pop" : 784, "state" : "TN" }
+{ "_id" : "38553", "city" : "CLARKRANGE", "loc" : [ -84.977737, 36.211188 ], "pop" : 1843, "state" : "TN" }
+{ "_id" : "38554", "city" : "CRAWFORD", "loc" : [ -85.16876499999999, 36.23611 ], "pop" : 1213, "state" : "TN" }
+{ "_id" : "38555", "city" : "FAIRFIELD GLADE", "loc" : [ -85.017171, 35.944041 ], "pop" : 26993, "state" : "TN" }
+{ "_id" : "38556", "city" : "JAMESTOWN", "loc" : [ -84.935721, 36.424471 ], "pop" : 7728, "state" : "TN" }
+{ "_id" : "38559", "city" : "DOYLE", "loc" : [ -85.498997, 35.872206 ], "pop" : 1802, "state" : "TN" }
+{ "_id" : "38560", "city" : "ELMWOOD", "loc" : [ -85.880843, 36.235468 ], "pop" : 937, "state" : "TN" }
+{ "_id" : "38562", "city" : "GAINESBORO", "loc" : [ -85.635509, 36.343767 ], "pop" : 6883, "state" : "TN" }
+{ "_id" : "38563", "city" : "GORDONSVILLE", "loc" : [ -86.000818, 36.184317 ], "pop" : 2630, "state" : "TN" }
+{ "_id" : "38564", "city" : "GRANVILLE", "loc" : [ -85.747533, 36.276847 ], "pop" : 381, "state" : "TN" }
+{ "_id" : "38565", "city" : "GRIMSLEY", "loc" : [ -85.01549, 36.243353 ], "pop" : 1092, "state" : "TN" }
+{ "_id" : "38567", "city" : "HICKMAN", "loc" : [ -85.902297, 36.119653 ], "pop" : 836, "state" : "TN" }
+{ "_id" : "38568", "city" : "HILHAM", "loc" : [ -85.43691800000001, 36.391492 ], "pop" : 1976, "state" : "TN" }
+{ "_id" : "38569", "city" : "LANCASTER", "loc" : [ -85.85509500000001, 36.09542 ], "pop" : 261, "state" : "TN" }
+{ "_id" : "38570", "city" : "LIVINGSTON", "loc" : [ -85.32052299999999, 36.389012 ], "pop" : 7274, "state" : "TN" }
+{ "_id" : "38573", "city" : "MONROE", "loc" : [ -85.216385, 36.464201 ], "pop" : 1951, "state" : "TN" }
+{ "_id" : "38574", "city" : "MONTEREY", "loc" : [ -85.254198, 36.150862 ], "pop" : 5030, "state" : "TN" }
+{ "_id" : "38575", "city" : "MOSS", "loc" : [ -85.677235, 36.596623 ], "pop" : 980, "state" : "TN" }
+{ "_id" : "38577", "city" : "PALL MALL", "loc" : [ -85.03838500000001, 36.578066 ], "pop" : 1537, "state" : "TN" }
+{ "_id" : "38578", "city" : "PLEASANT HILL", "loc" : [ -85.16694, 36.01121 ], "pop" : 4954, "state" : "TN" }
+{ "_id" : "38579", "city" : "QUEBECK", "loc" : [ -85.538189, 35.825379 ], "pop" : 1250, "state" : "TN" }
+{ "_id" : "38580", "city" : "RICKMAN", "loc" : [ -85.380572, 36.301933 ], "pop" : 2109, "state" : "TN" }
+{ "_id" : "38581", "city" : "BONE CAVE", "loc" : [ -85.63515599999999, 35.743813 ], "pop" : 3954, "state" : "TN" }
+{ "_id" : "38582", "city" : "SILVER POINT", "loc" : [ -85.733801, 36.100562 ], "pop" : 954, "state" : "TN" }
+{ "_id" : "38583", "city" : "RAVENSCROFT", "loc" : [ -85.478582, 35.954664 ], "pop" : 16814, "state" : "TN" }
+{ "_id" : "38585", "city" : "SPENCER", "loc" : [ -85.42866100000001, 35.727871 ], "pop" : 3954, "state" : "TN" }
+{ "_id" : "38587", "city" : "WALLING", "loc" : [ -85.618509, 35.869543 ], "pop" : 641, "state" : "TN" }
+{ "_id" : "38588", "city" : "WHITLEYVILLE", "loc" : [ -85.68987300000001, 36.515839 ], "pop" : 1272, "state" : "TN" }
+{ "_id" : "38589", "city" : "WILDER", "loc" : [ -85.07471700000001, 36.230526 ], "pop" : 178, "state" : "TN" }
+{ "_id" : "38601", "city" : "ABBEVILLE", "loc" : [ -89.56883500000001, 34.455553 ], "pop" : 4649, "state" : "MS" }
+{ "_id" : "38603", "city" : "CANNON", "loc" : [ -89.205428, 34.79456 ], "pop" : 3226, "state" : "MS" }
+{ "_id" : "38606", "city" : "BATESVILLE", "loc" : [ -89.91418, 34.331651 ], "pop" : 9879, "state" : "MS" }
+{ "_id" : "38610", "city" : "BLUE MOUNTAIN", "loc" : [ -89.008775, 34.670986 ], "pop" : 3857, "state" : "MS" }
+{ "_id" : "38611", "city" : "BYHALIA", "loc" : [ -89.676332, 34.885351 ], "pop" : 11054, "state" : "MS" }
+{ "_id" : "38614", "city" : "STOVALL", "loc" : [ -90.577755, 34.204984 ], "pop" : 26774, "state" : "MS" }
+{ "_id" : "38617", "city" : "COAHOMA", "loc" : [ -90.472748, 34.36247 ], "pop" : 3055, "state" : "MS" }
+{ "_id" : "38618", "city" : "COLDWATER", "loc" : [ -89.98688199999999, 34.692362 ], "pop" : 7247, "state" : "MS" }
+{ "_id" : "38619", "city" : "COMO", "loc" : [ -89.915508, 34.513728 ], "pop" : 3568, "state" : "MS" }
+{ "_id" : "38620", "city" : "COURTLAND", "loc" : [ -89.93959099999999, 34.25958 ], "pop" : 6765, "state" : "MS" }
+{ "_id" : "38621", "city" : "ASKEW", "loc" : [ -90.185524, 34.453966 ], "pop" : 4693, "state" : "MS" }
+{ "_id" : "38625", "city" : "DUMAS", "loc" : [ -88.80722900000001, 34.64915 ], "pop" : 2219, "state" : "MS" }
+{ "_id" : "38626", "city" : "DUNDEE", "loc" : [ -90.38907, 34.528181 ], "pop" : 1443, "state" : "MS" }
+{ "_id" : "38627", "city" : "ETTA", "loc" : [ -89.176706, 34.435231 ], "pop" : 1560, "state" : "MS" }
+{ "_id" : "38629", "city" : "FALKNER", "loc" : [ -88.952493, 34.841682 ], "pop" : 1408, "state" : "MS" }
+{ "_id" : "38632", "city" : "HERNANDO", "loc" : [ -90.00948699999999, 34.809588 ], "pop" : 10894, "state" : "MS" }
+{ "_id" : "38633", "city" : "HICKORY FLAT", "loc" : [ -89.186229, 34.624362 ], "pop" : 1692, "state" : "MS" }
+{ "_id" : "38635", "city" : "HOLLY SPRINGS", "loc" : [ -89.48971400000001, 34.747061 ], "pop" : 12519, "state" : "MS" }
+{ "_id" : "38637", "city" : "HORN LAKE", "loc" : [ -90.050719, 34.9519 ], "pop" : 14436, "state" : "MS" }
+{ "_id" : "38641", "city" : "LAKE CORMORANT", "loc" : [ -90.16079499999999, 34.893733 ], "pop" : 1587, "state" : "MS" }
+{ "_id" : "38642", "city" : "LAMAR", "loc" : [ -89.31632999999999, 34.927072 ], "pop" : 2761, "state" : "MS" }
+{ "_id" : "38643", "city" : "LAMBERT", "loc" : [ -90.262991, 34.183719 ], "pop" : 3378, "state" : "MS" }
+{ "_id" : "38645", "city" : "LYON", "loc" : [ -90.498147, 34.247369 ], "pop" : 1132, "state" : "MS" }
+{ "_id" : "38646", "city" : "MARKS", "loc" : [ -90.28160200000001, 34.260735 ], "pop" : 4715, "state" : "MS" }
+{ "_id" : "38647", "city" : "MICHIGAN CITY", "loc" : [ -89.136173, 34.931849 ], "pop" : 1574, "state" : "MS" }
+{ "_id" : "38650", "city" : "MYRTLE", "loc" : [ -89.115701, 34.540209 ], "pop" : 2613, "state" : "MS" }
+{ "_id" : "38651", "city" : "NESBIT", "loc" : [ -90.012199, 34.899189 ], "pop" : 4098, "state" : "MS" }
+{ "_id" : "38652", "city" : "NEW ALBANY", "loc" : [ -89.003058, 34.485051 ], "pop" : 14109, "state" : "MS" }
+{ "_id" : "38654", "city" : "OLIVE BRANCH", "loc" : [ -89.854427, 34.94414 ], "pop" : 14069, "state" : "MS" }
+{ "_id" : "38655", "city" : "LAFAYETTE", "loc" : [ -89.49692, 34.354354 ], "pop" : 22599, "state" : "MS" }
+{ "_id" : "38657", "city" : "PLEASANT GROVE", "loc" : [ -90.10249399999999, 34.469951 ], "pop" : 80, "state" : "MS" }
+{ "_id" : "38658", "city" : "POPE", "loc" : [ -90.002735, 34.190559 ], "pop" : 1860, "state" : "MS" }
+{ "_id" : "38659", "city" : "POTTS CAMP", "loc" : [ -89.315073, 34.604742 ], "pop" : 1580, "state" : "MS" }
+{ "_id" : "38661", "city" : "RED BANKS", "loc" : [ -89.519839, 34.875039 ], "pop" : 4860, "state" : "MS" }
+{ "_id" : "38663", "city" : "RIPLEY", "loc" : [ -88.923973, 34.750912 ], "pop" : 8895, "state" : "MS" }
+{ "_id" : "38664", "city" : "ROBINSONVILLE", "loc" : [ -90.30517399999999, 34.809329 ], "pop" : 547, "state" : "MS" }
+{ "_id" : "38665", "city" : "SAVAGE", "loc" : [ -90.138193, 34.611981 ], "pop" : 1936, "state" : "MS" }
+{ "_id" : "38666", "city" : "SARDIS", "loc" : [ -89.922083, 34.427573 ], "pop" : 5023, "state" : "MS" }
+{ "_id" : "38668", "city" : "SENATOBIA", "loc" : [ -89.885501, 34.632306 ], "pop" : 12249, "state" : "MS" }
+{ "_id" : "38670", "city" : "SLEDGE", "loc" : [ -90.20904, 34.382347 ], "pop" : 201, "state" : "MS" }
+{ "_id" : "38671", "city" : "SOUTHAVEN", "loc" : [ -89.999173, 34.977074 ], "pop" : 19174, "state" : "MS" }
+{ "_id" : "38673", "city" : "TAYLOR", "loc" : [ -89.627278, 34.284878 ], "pop" : 2374, "state" : "MS" }
+{ "_id" : "38674", "city" : "TIPLERSVILLE", "loc" : [ -88.915684, 34.90294 ], "pop" : 909, "state" : "MS" }
+{ "_id" : "38676", "city" : "TUNICA", "loc" : [ -90.368515, 34.688355 ], "pop" : 6174, "state" : "MS" }
+{ "_id" : "38677", "city" : "UNIVERSITY", "loc" : [ -89.582742, 34.364513 ], "pop" : 1902, "state" : "MS" }
+{ "_id" : "38680", "city" : "WALLS", "loc" : [ -90.120789, 34.964051 ], "pop" : 2181, "state" : "MS" }
+{ "_id" : "38683", "city" : "WALNUT", "loc" : [ -88.905337, 34.952732 ], "pop" : 2553, "state" : "MS" }
+{ "_id" : "38685", "city" : "WATERFORD", "loc" : [ -89.468298, 34.640248 ], "pop" : 892, "state" : "MS" }
+{ "_id" : "38701", "city" : "GREENVILLE", "loc" : [ -91.04679299999999, 33.378737 ], "pop" : 35884, "state" : "MS" }
+{ "_id" : "38703", "city" : "GREENVILLE", "loc" : [ -91.022795, 33.408494 ], "pop" : 18560, "state" : "MS" }
+{ "_id" : "38720", "city" : "ALLIGATOR", "loc" : [ -90.738214, 34.129425 ], "pop" : 969, "state" : "MS" }
+{ "_id" : "38721", "city" : "ANGUILLA", "loc" : [ -90.809535, 33.01213 ], "pop" : 2557, "state" : "MS" }
+{ "_id" : "38725", "city" : "BENOIT", "loc" : [ -91.033765, 33.644795 ], "pop" : 1554, "state" : "MS" }
+{ "_id" : "38726", "city" : "BEULAH", "loc" : [ -90.979545, 33.787954 ], "pop" : 467, "state" : "MS" }
+{ "_id" : "38730", "city" : "BOYLE", "loc" : [ -90.733503, 33.685369 ], "pop" : 1934, "state" : "MS" }
+{ "_id" : "38732", "city" : "CLEVELAND", "loc" : [ -90.73087099999999, 33.743002 ], "pop" : 20953, "state" : "MS" }
+{ "_id" : "38736", "city" : "DODDSVILLE", "loc" : [ -90.52637, 33.630045 ], "pop" : 309, "state" : "MS" }
+{ "_id" : "38737", "city" : "DREW", "loc" : [ -90.540606, 33.867031 ], "pop" : 7680, "state" : "MS" }
+{ "_id" : "38740", "city" : "DUNCAN", "loc" : [ -90.765191, 34.046966 ], "pop" : 885, "state" : "MS" }
+{ "_id" : "38744", "city" : "GLEN ALLAN", "loc" : [ -91.009193, 33.025361 ], "pop" : 734, "state" : "MS" }
+{ "_id" : "38746", "city" : "GUNNISON", "loc" : [ -90.931899, 33.943886 ], "pop" : 1248, "state" : "MS" }
+{ "_id" : "38748", "city" : "PERCY", "loc" : [ -90.84857, 33.177917 ], "pop" : 4499, "state" : "MS" }
+{ "_id" : "38751", "city" : "BAIRD", "loc" : [ -90.654144, 33.449075 ], "pop" : 13001, "state" : "MS" }
+{ "_id" : "38753", "city" : "INVERNESS", "loc" : [ -90.605065, 33.348964 ], "pop" : 2140, "state" : "MS" }
+{ "_id" : "38754", "city" : "ISOLA", "loc" : [ -90.604027, 33.247112 ], "pop" : 1674, "state" : "MS" }
+{ "_id" : "38756", "city" : "ELIZABETH", "loc" : [ -90.89280100000001, 33.410025 ], "pop" : 8047, "state" : "MS" }
+{ "_id" : "38759", "city" : "MERIGOLD", "loc" : [ -90.725571, 33.837252 ], "pop" : 738, "state" : "MS" }
+{ "_id" : "38761", "city" : "MOORHEAD", "loc" : [ -90.51425, 33.478325 ], "pop" : 4623, "state" : "MS" }
+{ "_id" : "38762", "city" : "MOUND BAYOU", "loc" : [ -90.73024700000001, 33.886023 ], "pop" : 3485, "state" : "MS" }
+{ "_id" : "38769", "city" : "ROSEDALE", "loc" : [ -90.992289, 33.843166 ], "pop" : 3726, "state" : "MS" }
+{ "_id" : "38771", "city" : "RULEVILLE", "loc" : [ -90.552657, 33.724052 ], "pop" : 4153, "state" : "MS" }
+{ "_id" : "38773", "city" : "SHAW", "loc" : [ -90.81427499999999, 33.587388 ], "pop" : 3596, "state" : "MS" }
+{ "_id" : "38774", "city" : "SHELBY", "loc" : [ -90.762461, 33.949058 ], "pop" : 3037, "state" : "MS" }
+{ "_id" : "38778", "city" : "SUNFLOWER", "loc" : [ -90.638732, 33.584696 ], "pop" : 961, "state" : "MS" }
+{ "_id" : "38780", "city" : "WAYSIDE", "loc" : [ -91.024801, 33.261023 ], "pop" : 198, "state" : "MS" }
+{ "_id" : "38801", "city" : "TUPELO", "loc" : [ -88.72085300000001, 34.253834 ], "pop" : 40381, "state" : "MS" }
+{ "_id" : "38821", "city" : "AMORY", "loc" : [ -88.470917, 33.9844 ], "pop" : 11765, "state" : "MS" }
+{ "_id" : "38824", "city" : "BALDWYN", "loc" : [ -88.63748, 34.527959 ], "pop" : 6965, "state" : "MS" }
+{ "_id" : "38826", "city" : "BELDEN", "loc" : [ -88.816011, 34.278663 ], "pop" : 4441, "state" : "MS" }
+{ "_id" : "38827", "city" : "BELMONT", "loc" : [ -88.230912, 34.51025 ], "pop" : 2511, "state" : "MS" }
+{ "_id" : "38828", "city" : "BLUE SPRINGS", "loc" : [ -88.859004, 34.427286 ], "pop" : 2808, "state" : "MS" }
+{ "_id" : "38829", "city" : "BOONEVILLE", "loc" : [ -88.544299, 34.669431 ], "pop" : 16363, "state" : "MS" }
+{ "_id" : "38833", "city" : "BURNSVILLE", "loc" : [ -88.306962, 34.857885 ], "pop" : 3574, "state" : "MS" }
+{ "_id" : "38834", "city" : "KOSSUTH", "loc" : [ -88.54388400000001, 34.93236 ], "pop" : 22984, "state" : "MS" }
+{ "_id" : "38838", "city" : "DENNIS", "loc" : [ -88.21167, 34.549735 ], "pop" : 1315, "state" : "MS" }
+{ "_id" : "38841", "city" : "ECRU", "loc" : [ -88.955956, 34.337106 ], "pop" : 3862, "state" : "MS" }
+{ "_id" : "38843", "city" : "FULTON", "loc" : [ -88.379262, 34.274543 ], "pop" : 14877, "state" : "MS" }
+{ "_id" : "38844", "city" : "GATTMAN", "loc" : [ -88.258779, 33.87417 ], "pop" : 408, "state" : "MS" }
+{ "_id" : "38846", "city" : "GLEN", "loc" : [ -88.43585899999999, 34.877981 ], "pop" : 5578, "state" : "MS" }
+{ "_id" : "38847", "city" : "GOLDEN", "loc" : [ -88.18415899999999, 34.481214 ], "pop" : 639, "state" : "MS" }
+{ "_id" : "38848", "city" : "GREENWOOD SPRING", "loc" : [ -88.312333, 33.99344 ], "pop" : 1934, "state" : "MS" }
+{ "_id" : "38849", "city" : "GUNTOWN", "loc" : [ -88.701059, 34.429882 ], "pop" : 4504, "state" : "MS" }
+{ "_id" : "38850", "city" : "HOULKA", "loc" : [ -89.05311399999999, 34.056145 ], "pop" : 2571, "state" : "MS" }
+{ "_id" : "38851", "city" : "HOUSTON", "loc" : [ -88.967005, 33.902554 ], "pop" : 8781, "state" : "MS" }
+{ "_id" : "38852", "city" : "IUKA", "loc" : [ -88.198289, 34.808891 ], "pop" : 7497, "state" : "MS" }
+{ "_id" : "38855", "city" : "MANTACHIE", "loc" : [ -88.49603399999999, 34.358677 ], "pop" : 4273, "state" : "MS" }
+{ "_id" : "38856", "city" : "MARIETTA", "loc" : [ -88.449764, 34.501089 ], "pop" : 1054, "state" : "MS" }
+{ "_id" : "38857", "city" : "MOOREVILLE", "loc" : [ -88.59504, 34.280792 ], "pop" : 3880, "state" : "MS" }
+{ "_id" : "38858", "city" : "NETTLETON", "loc" : [ -88.60520099999999, 34.082065 ], "pop" : 6781, "state" : "MS" }
+{ "_id" : "38859", "city" : "NEW SITE", "loc" : [ -88.43502100000001, 34.561693 ], "pop" : 1187, "state" : "MS" }
+{ "_id" : "38860", "city" : "EGYPT", "loc" : [ -88.759843, 33.989015 ], "pop" : 5258, "state" : "MS" }
+{ "_id" : "38862", "city" : "PLANTERSVILLE", "loc" : [ -88.633456, 34.201073 ], "pop" : 2913, "state" : "MS" }
+{ "_id" : "38863", "city" : "PONTOTOC", "loc" : [ -88.986829, 34.217004 ], "pop" : 10723, "state" : "MS" }
+{ "_id" : "38864", "city" : "SAREPTA", "loc" : [ -89.163625, 34.178943 ], "pop" : 2365, "state" : "MS" }
+{ "_id" : "38865", "city" : "RIENZI", "loc" : [ -88.579454, 34.796789 ], "pop" : 3162, "state" : "MS" }
+{ "_id" : "38866", "city" : "SALTILLO", "loc" : [ -88.66736, 34.383128 ], "pop" : 2324, "state" : "MS" }
+{ "_id" : "38868", "city" : "SHANNON", "loc" : [ -88.734206, 34.121035 ], "pop" : 4454, "state" : "MS" }
+{ "_id" : "38870", "city" : "SMITHVILLE", "loc" : [ -88.390027, 34.064813 ], "pop" : 1375, "state" : "MS" }
+{ "_id" : "38871", "city" : "THAXTON", "loc" : [ -89.15146799999999, 34.313563 ], "pop" : 3171, "state" : "MS" }
+{ "_id" : "38873", "city" : "TISHOMINGO", "loc" : [ -88.21939500000001, 34.647753 ], "pop" : 2143, "state" : "MS" }
+{ "_id" : "38876", "city" : "TREMONT", "loc" : [ -88.23921199999999, 34.233516 ], "pop" : 871, "state" : "MS" }
+{ "_id" : "38878", "city" : "VARDAMAN", "loc" : [ -89.192117, 33.919042 ], "pop" : 2866, "state" : "MS" }
+{ "_id" : "38901", "city" : "GRENADA", "loc" : [ -89.80873800000001, 33.775094 ], "pop" : 12322, "state" : "MS" }
+{ "_id" : "38912", "city" : "AVALON", "loc" : [ -90.022077, 33.633683 ], "pop" : 782, "state" : "MS" }
+{ "_id" : "38913", "city" : "BANNER", "loc" : [ -89.41538300000001, 34.094911 ], "pop" : 819, "state" : "MS" }
+{ "_id" : "38914", "city" : "BIG CREEK", "loc" : [ -89.437833, 33.851359 ], "pop" : 461, "state" : "MS" }
+{ "_id" : "38915", "city" : "BRUCE", "loc" : [ -89.348387, 34.006628 ], "pop" : 4085, "state" : "MS" }
+{ "_id" : "38916", "city" : "CALHOUN CITY", "loc" : [ -89.317809, 33.840776 ], "pop" : 5416, "state" : "MS" }
+{ "_id" : "38917", "city" : "CARROLLTON", "loc" : [ -89.950633, 33.520765 ], "pop" : 2683, "state" : "MS" }
+{ "_id" : "38920", "city" : "CASCILLA", "loc" : [ -90.036163, 33.907905 ], "pop" : 2101, "state" : "MS" }
+{ "_id" : "38921", "city" : "CHARLESTON", "loc" : [ -90.111559, 33.972621 ], "pop" : 7077, "state" : "MS" }
+{ "_id" : "38922", "city" : "COFFEEVILLE", "loc" : [ -89.67817700000001, 33.921468 ], "pop" : 6937, "state" : "MS" }
+{ "_id" : "38923", "city" : "COILA", "loc" : [ -89.991516, 33.373111 ], "pop" : 1529, "state" : "MS" }
+{ "_id" : "38924", "city" : "CRUGER", "loc" : [ -90.231577, 33.310977 ], "pop" : 897, "state" : "MS" }
+{ "_id" : "38925", "city" : "DUCK HILL", "loc" : [ -89.733425, 33.686475 ], "pop" : 4223, "state" : "MS" }
+{ "_id" : "38927", "city" : "ENID", "loc" : [ -90.004392, 34.126345 ], "pop" : 916, "state" : "MS" }
+{ "_id" : "38929", "city" : "GORE SPRINGS", "loc" : [ -89.57544900000001, 33.724529 ], "pop" : 261, "state" : "MS" }
+{ "_id" : "38930", "city" : "GREENWOOD", "loc" : [ -90.172589, 33.515884 ], "pop" : 27931, "state" : "MS" }
+{ "_id" : "38940", "city" : "HOLCOMB", "loc" : [ -89.90195799999999, 33.760385 ], "pop" : 3690, "state" : "MS" }
+{ "_id" : "38941", "city" : "ITTA BENA", "loc" : [ -90.339421, 33.479838 ], "pop" : 6178, "state" : "MS" }
+{ "_id" : "38943", "city" : "MC CARLEY", "loc" : [ -89.851281, 33.586383 ], "pop" : 941, "state" : "MS" }
+{ "_id" : "38944", "city" : "MINTER CITY", "loc" : [ -90.31327, 33.751525 ], "pop" : 1064, "state" : "MS" }
+{ "_id" : "38948", "city" : "OAKLAND", "loc" : [ -89.887748, 34.075552 ], "pop" : 1276, "state" : "MS" }
+{ "_id" : "38949", "city" : "WATER VALLEY", "loc" : [ -89.421408, 34.176817 ], "pop" : 302, "state" : "MS" }
+{ "_id" : "38950", "city" : "PHILIPP", "loc" : [ -90.209086, 33.757391 ], "pop" : 520, "state" : "MS" }
+{ "_id" : "38951", "city" : "PITTSBORO", "loc" : [ -89.337622, 33.944326 ], "pop" : 1053, "state" : "MS" }
+{ "_id" : "38952", "city" : "SCHLATER", "loc" : [ -90.361976, 33.624439 ], "pop" : 915, "state" : "MS" }
+{ "_id" : "38953", "city" : "SCOBEY", "loc" : [ -89.891019, 33.92526 ], "pop" : 228, "state" : "MS" }
+{ "_id" : "38954", "city" : "SIDON", "loc" : [ -90.177937, 33.40946 ], "pop" : 2212, "state" : "MS" }
+{ "_id" : "38961", "city" : "TILLATOBA", "loc" : [ -89.89446100000001, 33.985229 ], "pop" : 621, "state" : "MS" }
+{ "_id" : "38963", "city" : "TUTWILER", "loc" : [ -90.37534100000001, 33.98195 ], "pop" : 4627, "state" : "MS" }
+{ "_id" : "38964", "city" : "VANCE", "loc" : [ -90.375246, 34.093639 ], "pop" : 299, "state" : "MS" }
+{ "_id" : "38965", "city" : "WATER VALLEY", "loc" : [ -89.637986, 34.152466 ], "pop" : 5850, "state" : "MS" }
+{ "_id" : "38967", "city" : "WINONA", "loc" : [ -89.727655, 33.485753 ], "pop" : 7877, "state" : "MS" }
+{ "_id" : "39038", "city" : "BELZONI", "loc" : [ -90.492435, 33.18421 ], "pop" : 7600, "state" : "MS" }
+{ "_id" : "39039", "city" : "BENTON", "loc" : [ -90.281516, 32.815772 ], "pop" : 1114, "state" : "MS" }
+{ "_id" : "39040", "city" : "BENTONIA", "loc" : [ -90.372156, 32.700015 ], "pop" : 4325, "state" : "MS" }
+{ "_id" : "39041", "city" : "BOLTON", "loc" : [ -90.447436, 32.377751 ], "pop" : 3484, "state" : "MS" }
+{ "_id" : "39042", "city" : "BRANDON", "loc" : [ -89.964029, 32.303803 ], "pop" : 41141, "state" : "MS" }
+{ "_id" : "39044", "city" : "BRAXTON", "loc" : [ -89.967225, 32.001581 ], "pop" : 1704, "state" : "MS" }
+{ "_id" : "39045", "city" : "CAMDEN", "loc" : [ -89.892838, 32.794832 ], "pop" : 1835, "state" : "MS" }
+{ "_id" : "39046", "city" : "CANTON", "loc" : [ -90.006079, 32.620543 ], "pop" : 21725, "state" : "MS" }
+{ "_id" : "39049", "city" : "CARLISLE", "loc" : [ -90.779904, 32.101322 ], "pop" : 334, "state" : "MS" }
+{ "_id" : "39051", "city" : "EDINBURG", "loc" : [ -89.535274, 32.788635 ], "pop" : 11122, "state" : "MS" }
+{ "_id" : "39055", "city" : "CHURCH HILL", "loc" : [ -91.21490300000001, 31.67864 ], "pop" : 1079, "state" : "MS" }
+{ "_id" : "39056", "city" : "CLINTON", "loc" : [ -90.32289299999999, 32.341079 ], "pop" : 25262, "state" : "MS" }
+{ "_id" : "39057", "city" : "CONEHATTA", "loc" : [ -89.268956, 32.466974 ], "pop" : 2117, "state" : "MS" }
+{ "_id" : "39059", "city" : "CRYSTAL SPRINGS", "loc" : [ -90.374439, 31.993329 ], "pop" : 10787, "state" : "MS" }
+{ "_id" : "39063", "city" : "DURANT", "loc" : [ -89.86116, 33.082756 ], "pop" : 3459, "state" : "MS" }
+{ "_id" : "39066", "city" : "EDWARDS", "loc" : [ -90.598392, 32.316008 ], "pop" : 4144, "state" : "MS" }
+{ "_id" : "39067", "city" : "ETHEL", "loc" : [ -89.49470700000001, 33.152587 ], "pop" : 2047, "state" : "MS" }
+{ "_id" : "39069", "city" : "FAYETTE", "loc" : [ -91.058226, 31.712058 ], "pop" : 6319, "state" : "MS" }
+{ "_id" : "39071", "city" : "FLORA", "loc" : [ -90.32350599999999, 32.557832 ], "pop" : 3973, "state" : "MS" }
+{ "_id" : "39073", "city" : "FLORENCE", "loc" : [ -90.121672, 32.153002 ], "pop" : 14251, "state" : "MS" }
+{ "_id" : "39074", "city" : "FOREST", "loc" : [ -89.467201, 32.346999 ], "pop" : 6588, "state" : "MS" }
+{ "_id" : "39078", "city" : "GEORGETOWN", "loc" : [ -90.21273600000001, 31.855198 ], "pop" : 2065, "state" : "MS" }
+{ "_id" : "39079", "city" : "GOODMAN", "loc" : [ -89.982145, 32.972133 ], "pop" : 3487, "state" : "MS" }
+{ "_id" : "39082", "city" : "HARRISVILLE", "loc" : [ -90.10535900000001, 31.967552 ], "pop" : 2885, "state" : "MS" }
+{ "_id" : "39083", "city" : "HAZLEHURST", "loc" : [ -90.405078, 31.856188 ], "pop" : 12269, "state" : "MS" }
+{ "_id" : "39086", "city" : "HERMANVILLE", "loc" : [ -90.844588, 31.956374 ], "pop" : 1683, "state" : "MS" }
+{ "_id" : "39088", "city" : "HOLLY BLUFF", "loc" : [ -90.704486, 32.824216 ], "pop" : 218, "state" : "MS" }
+{ "_id" : "39090", "city" : "KOSCIUSKO", "loc" : [ -89.572351, 33.0446 ], "pop" : 11597, "state" : "MS" }
+{ "_id" : "39092", "city" : "LAKE", "loc" : [ -89.341354, 32.345909 ], "pop" : 704, "state" : "MS" }
+{ "_id" : "39094", "city" : "LENA", "loc" : [ -89.549435, 32.644588 ], "pop" : 3622, "state" : "MS" }
+{ "_id" : "39095", "city" : "LEXINGTON", "loc" : [ -90.055674, 33.125043 ], "pop" : 7252, "state" : "MS" }
+{ "_id" : "39096", "city" : "LORMAN", "loc" : [ -91.095691, 31.838257 ], "pop" : 668, "state" : "MS" }
+{ "_id" : "39097", "city" : "LOUISE", "loc" : [ -90.589321, 32.991945 ], "pop" : 1670, "state" : "MS" }
+{ "_id" : "39108", "city" : "MC COOL", "loc" : [ -89.326806, 33.163206 ], "pop" : 1438, "state" : "MS" }
+{ "_id" : "39109", "city" : "MADDEN", "loc" : [ -89.38170100000001, 32.708665 ], "pop" : 1586, "state" : "MS" }
+{ "_id" : "39110", "city" : "MADISON", "loc" : [ -90.108744, 32.467065 ], "pop" : 12100, "state" : "MS" }
+{ "_id" : "39111", "city" : "MAGEE", "loc" : [ -89.750325, 31.849513 ], "pop" : 7590, "state" : "MS" }
+{ "_id" : "39113", "city" : "MAYERSVILLE", "loc" : [ -91.028628, 32.901276 ], "pop" : 1657, "state" : "MS" }
+{ "_id" : "39114", "city" : "MENDENHALL", "loc" : [ -89.809494, 31.949425 ], "pop" : 10110, "state" : "MS" }
+{ "_id" : "39116", "city" : "MIZE", "loc" : [ -89.574135, 31.847285 ], "pop" : 2858, "state" : "MS" }
+{ "_id" : "39117", "city" : "MORTON", "loc" : [ -89.551222, 32.436105 ], "pop" : 15400, "state" : "MS" }
+{ "_id" : "39119", "city" : "MOUNT OLIVE", "loc" : [ -89.672387, 31.734582 ], "pop" : 3060, "state" : "MS" }
+{ "_id" : "39120", "city" : "NATCHEZ", "loc" : [ -91.364214, 31.54924 ], "pop" : 34738, "state" : "MS" }
+{ "_id" : "39140", "city" : "NEWHEBRON", "loc" : [ -90.01526, 31.73004 ], "pop" : 1184, "state" : "MS" }
+{ "_id" : "39144", "city" : "PATTISON", "loc" : [ -90.828306, 31.851025 ], "pop" : 855, "state" : "MS" }
+{ "_id" : "39145", "city" : "PELAHATCHIE", "loc" : [ -89.79134999999999, 32.317994 ], "pop" : 1661, "state" : "MS" }
+{ "_id" : "39146", "city" : "PICKENS", "loc" : [ -89.973707, 32.890519 ], "pop" : 1574, "state" : "MS" }
+{ "_id" : "39149", "city" : "PINOLA", "loc" : [ -90.008775, 31.827732 ], "pop" : 1664, "state" : "MS" }
+{ "_id" : "39150", "city" : "PORT GIBSON", "loc" : [ -91.02303000000001, 31.926604 ], "pop" : 8498, "state" : "MS" }
+{ "_id" : "39152", "city" : "PULASKI", "loc" : [ -89.650521, 32.270845 ], "pop" : 1447, "state" : "MS" }
+{ "_id" : "39153", "city" : "RALEIGH", "loc" : [ -89.50881800000001, 32.05084 ], "pop" : 8944, "state" : "MS" }
+{ "_id" : "39154", "city" : "LEARNED", "loc" : [ -90.424088, 32.23922 ], "pop" : 7530, "state" : "MS" }
+{ "_id" : "39156", "city" : "REDWOOD", "loc" : [ -90.785899, 32.486699 ], "pop" : 912, "state" : "MS" }
+{ "_id" : "39157", "city" : "RIDGELAND", "loc" : [ -90.12069700000001, 32.412165 ], "pop" : 13226, "state" : "MS" }
+{ "_id" : "39159", "city" : "ROLLING FORK", "loc" : [ -90.883274, 32.873317 ], "pop" : 4509, "state" : "MS" }
+{ "_id" : "39160", "city" : "SALLIS", "loc" : [ -89.755182, 33.000981 ], "pop" : 3093, "state" : "MS" }
+{ "_id" : "39162", "city" : "SATARTIA", "loc" : [ -90.596458, 32.612515 ], "pop" : 496, "state" : "MS" }
+{ "_id" : "39166", "city" : "SILVER CITY", "loc" : [ -90.49279799999999, 33.05071 ], "pop" : 1190, "state" : "MS" }
+{ "_id" : "39168", "city" : "TAYLORSVILLE", "loc" : [ -89.404875, 31.839388 ], "pop" : 2996, "state" : "MS" }
+{ "_id" : "39169", "city" : "TCHULA", "loc" : [ -90.250012, 33.162388 ], "pop" : 3976, "state" : "MS" }
+{ "_id" : "39170", "city" : "TERRY", "loc" : [ -90.32414300000001, 32.114683 ], "pop" : 5538, "state" : "MS" }
+{ "_id" : "39175", "city" : "UTICA", "loc" : [ -90.604724, 32.122897 ], "pop" : 4630, "state" : "MS" }
+{ "_id" : "39176", "city" : "VAIDEN", "loc" : [ -89.757023, 33.33433 ], "pop" : 1987, "state" : "MS" }
+{ "_id" : "39177", "city" : "VALLEY PARK", "loc" : [ -90.854209, 32.632258 ], "pop" : 252, "state" : "MS" }
+{ "_id" : "39179", "city" : "PICKENS", "loc" : [ -90.085477, 32.817424 ], "pop" : 1417, "state" : "MS" }
+{ "_id" : "39180", "city" : "VICKSBURG", "loc" : [ -90.85065, 32.325824 ], "pop" : 46968, "state" : "MS" }
+{ "_id" : "39189", "city" : "WALNUT GROVE", "loc" : [ -89.410538, 32.613418 ], "pop" : 2098, "state" : "MS" }
+{ "_id" : "39191", "city" : "WESSON", "loc" : [ -90.413106, 31.690055 ], "pop" : 4187, "state" : "MS" }
+{ "_id" : "39192", "city" : "WEST", "loc" : [ -89.769526, 33.1883 ], "pop" : 2069, "state" : "MS" }
+{ "_id" : "39194", "city" : "YAZOO CITY", "loc" : [ -90.40314499999999, 32.85937 ], "pop" : 17936, "state" : "MS" }
+{ "_id" : "39201", "city" : "JACKSON", "loc" : [ -90.186655, 32.293502 ], "pop" : 771, "state" : "MS" }
+{ "_id" : "39202", "city" : "JACKSON", "loc" : [ -90.178194, 32.314883 ], "pop" : 10979, "state" : "MS" }
+{ "_id" : "39203", "city" : "JACKSON", "loc" : [ -90.20206399999999, 32.308145 ], "pop" : 15641, "state" : "MS" }
+{ "_id" : "39204", "city" : "JACKSON", "loc" : [ -90.23057900000001, 32.283162 ], "pop" : 19655, "state" : "MS" }
+{ "_id" : "39206", "city" : "JACKSON", "loc" : [ -90.173787, 32.369956 ], "pop" : 25312, "state" : "MS" }
+{ "_id" : "39208", "city" : "PEARL", "loc" : [ -90.10271400000001, 32.276837 ], "pop" : 25545, "state" : "MS" }
+{ "_id" : "39209", "city" : "JACKSON", "loc" : [ -90.244626, 32.318422 ], "pop" : 34407, "state" : "MS" }
+{ "_id" : "39211", "city" : "JACKSON", "loc" : [ -90.12929699999999, 32.373924 ], "pop" : 25567, "state" : "MS" }
+{ "_id" : "39212", "city" : "JACKSON", "loc" : [ -90.261201, 32.24347 ], "pop" : 35321, "state" : "MS" }
+{ "_id" : "39213", "city" : "JACKSON", "loc" : [ -90.217099, 32.355288 ], "pop" : 33311, "state" : "MS" }
+{ "_id" : "39216", "city" : "JACKSON", "loc" : [ -90.17081399999999, 32.338574 ], "pop" : 3824, "state" : "MS" }
+{ "_id" : "39218", "city" : "RICHLAND", "loc" : [ -90.15623100000001, 32.215224 ], "pop" : 4563, "state" : "MS" }
+{ "_id" : "39269", "city" : "JACKSON", "loc" : [ -90.188503, 32.30085 ], "pop" : 0, "state" : "MS" }
+{ "_id" : "39301", "city" : "MERIDIAN", "loc" : [ -88.655973, 32.357441 ], "pop" : 28014, "state" : "MS" }
+{ "_id" : "39305", "city" : "MERIDIAN", "loc" : [ -88.67832199999999, 32.440129 ], "pop" : 16175, "state" : "MS" }
+{ "_id" : "39307", "city" : "MERIDIAN", "loc" : [ -88.74359800000001, 32.373591 ], "pop" : 20402, "state" : "MS" }
+{ "_id" : "39320", "city" : "BAILEY", "loc" : [ -88.69908599999999, 32.475417 ], "pop" : 2495, "state" : "MS" }
+{ "_id" : "39322", "city" : "BUCKATUNNA", "loc" : [ -88.52573, 31.507976 ], "pop" : 2477, "state" : "MS" }
+{ "_id" : "39323", "city" : "CHUNKY", "loc" : [ -88.946968, 32.247156 ], "pop" : 79, "state" : "MS" }
+{ "_id" : "39325", "city" : "COLLINSVILLE", "loc" : [ -88.815532, 32.518278 ], "pop" : 4385, "state" : "MS" }
+{ "_id" : "39326", "city" : "DALEVILLE", "loc" : [ -88.66094200000001, 32.551124 ], "pop" : 549, "state" : "MS" }
+{ "_id" : "39327", "city" : "DECATUR", "loc" : [ -89.116832, 32.435798 ], "pop" : 3595, "state" : "MS" }
+{ "_id" : "39328", "city" : "DE KALB", "loc" : [ -88.733158, 32.716235 ], "pop" : 5219, "state" : "MS" }
+{ "_id" : "39330", "city" : "ENTERPRISE", "loc" : [ -88.84735000000001, 32.156266 ], "pop" : 1444, "state" : "MS" }
+{ "_id" : "39332", "city" : "HICKORY", "loc" : [ -89.009254, 32.320012 ], "pop" : 2504, "state" : "MS" }
+{ "_id" : "39335", "city" : "LAUDERDALE", "loc" : [ -88.495569, 32.502186 ], "pop" : 2190, "state" : "MS" }
+{ "_id" : "39336", "city" : "LAWRENCE", "loc" : [ -89.27243199999999, 32.287614 ], "pop" : 86, "state" : "MS" }
+{ "_id" : "39337", "city" : "LITTLE ROCK", "loc" : [ -89.181382, 32.540288 ], "pop" : 896, "state" : "MS" }
+{ "_id" : "39338", "city" : "LOUIN", "loc" : [ -89.21993500000001, 32.099713 ], "pop" : 1991, "state" : "MS" }
+{ "_id" : "39339", "city" : "LOUISVILLE", "loc" : [ -89.02865300000001, 33.105824 ], "pop" : 16290, "state" : "MS" }
+{ "_id" : "39341", "city" : "MACON", "loc" : [ -88.578093, 33.102674 ], "pop" : 6634, "state" : "MS" }
+{ "_id" : "39345", "city" : "NEWTON", "loc" : [ -89.18395099999999, 32.324448 ], "pop" : 6779, "state" : "MS" }
+{ "_id" : "39346", "city" : "NOXAPATER", "loc" : [ -89.12207600000001, 32.97895 ], "pop" : 2870, "state" : "MS" }
+{ "_id" : "39347", "city" : "PACHUTA", "loc" : [ -88.86529299999999, 32.008105 ], "pop" : 916, "state" : "MS" }
+{ "_id" : "39348", "city" : "PAULDING", "loc" : [ -89.058441, 32.016744 ], "pop" : 485, "state" : "MS" }
+{ "_id" : "39350", "city" : "PHILADELPHIA", "loc" : [ -89.115371, 32.757224 ], "pop" : 24316, "state" : "MS" }
+{ "_id" : "39352", "city" : "PORTERVILLE", "loc" : [ -88.498425, 32.636833 ], "pop" : 1202, "state" : "MS" }
+{ "_id" : "39354", "city" : "PRESTON", "loc" : [ -88.813013, 32.853659 ], "pop" : 1937, "state" : "MS" }
+{ "_id" : "39355", "city" : "QUITMAN", "loc" : [ -88.678803, 32.066845 ], "pop" : 8822, "state" : "MS" }
+{ "_id" : "39356", "city" : "ROSE HILL", "loc" : [ -89.001053, 32.148931 ], "pop" : 1725, "state" : "MS" }
+{ "_id" : "39358", "city" : "SCOOBA", "loc" : [ -88.48827199999999, 32.840197 ], "pop" : 2087, "state" : "MS" }
+{ "_id" : "39360", "city" : "MATHERVILLE", "loc" : [ -88.725866, 31.903082 ], "pop" : 3442, "state" : "MS" }
+{ "_id" : "39361", "city" : "SHUQUALAK", "loc" : [ -88.559393, 32.976933 ], "pop" : 1323, "state" : "MS" }
+{ "_id" : "39362", "city" : "STATE LINE", "loc" : [ -88.51711, 31.391619 ], "pop" : 1382, "state" : "MS" }
+{ "_id" : "39363", "city" : "STONEWALL", "loc" : [ -88.774827, 32.156396 ], "pop" : 2690, "state" : "MS" }
+{ "_id" : "39364", "city" : "TOOMSUBA", "loc" : [ -88.489225, 32.429583 ], "pop" : 1346, "state" : "MS" }
+{ "_id" : "39365", "city" : "UNION", "loc" : [ -89.049522, 32.537329 ], "pop" : 4684, "state" : "MS" }
+{ "_id" : "39366", "city" : "VOSSBURG", "loc" : [ -88.969598, 31.972301 ], "pop" : 1357, "state" : "MS" }
+{ "_id" : "39367", "city" : "WAYNESBORO", "loc" : [ -88.67822099999999, 31.675447 ], "pop" : 17046, "state" : "MS" }
+{ "_id" : "39401", "city" : "HATTIESBURG", "loc" : [ -89.306471, 31.314553 ], "pop" : 41866, "state" : "MS" }
+{ "_id" : "39402", "city" : "HATTIESBURG", "loc" : [ -89.37751, 31.309753 ], "pop" : 25479, "state" : "MS" }
+{ "_id" : "39421", "city" : "BASSFIELD", "loc" : [ -89.702735, 31.503695 ], "pop" : 3605, "state" : "MS" }
+{ "_id" : "39422", "city" : "BAY SPRINGS", "loc" : [ -89.233768, 31.944939 ], "pop" : 6778, "state" : "MS" }
+{ "_id" : "39423", "city" : "BEAUMONT", "loc" : [ -88.905492, 31.136763 ], "pop" : 1883, "state" : "MS" }
+{ "_id" : "39425", "city" : "BROOKLYN", "loc" : [ -89.23372000000001, 30.998852 ], "pop" : 2080, "state" : "MS" }
+{ "_id" : "39426", "city" : "CARRIERE", "loc" : [ -89.57792999999999, 30.617772 ], "pop" : 12978, "state" : "MS" }
+{ "_id" : "39427", "city" : "CARSON", "loc" : [ -89.77582099999999, 31.558501 ], "pop" : 1381, "state" : "MS" }
+{ "_id" : "39428", "city" : "COLLINS", "loc" : [ -89.543809, 31.670712 ], "pop" : 9457, "state" : "MS" }
+{ "_id" : "39429", "city" : "COLUMBIA", "loc" : [ -89.799785, 31.255877 ], "pop" : 19891, "state" : "MS" }
+{ "_id" : "39437", "city" : "ELLISVILLE", "loc" : [ -89.223073, 31.579663 ], "pop" : 10632, "state" : "MS" }
+{ "_id" : "39439", "city" : "HEIDELBERG", "loc" : [ -88.998052, 31.882031 ], "pop" : 3416, "state" : "MS" }
+{ "_id" : "39440", "city" : "LAUREL", "loc" : [ -89.13115500000001, 31.705444 ], "pop" : 45040, "state" : "MS" }
+{ "_id" : "39451", "city" : "LEAKESVILLE", "loc" : [ -88.559546, 31.123825 ], "pop" : 4858, "state" : "MS" }
+{ "_id" : "39452", "city" : "AGRICOLA", "loc" : [ -88.593391, 30.866722 ], "pop" : 17844, "state" : "MS" }
+{ "_id" : "39455", "city" : "LUMBERTON", "loc" : [ -89.45425400000001, 31.053356 ], "pop" : 6096, "state" : "MS" }
+{ "_id" : "39456", "city" : "LEAF", "loc" : [ -88.81947, 31.078449 ], "pop" : 1061, "state" : "MS" }
+{ "_id" : "39459", "city" : "MOSELLE", "loc" : [ -89.320633, 31.483626 ], "pop" : 2350, "state" : "MS" }
+{ "_id" : "39461", "city" : "NEELY", "loc" : [ -88.71983, 31.179325 ], "pop" : 1059, "state" : "MS" }
+{ "_id" : "39462", "city" : "NEW AUGUSTA", "loc" : [ -89.028611, 31.130907 ], "pop" : 2152, "state" : "MS" }
+{ "_id" : "39464", "city" : "OVETT", "loc" : [ -89.039613, 31.47377 ], "pop" : 1113, "state" : "MS" }
+{ "_id" : "39465", "city" : "PETAL", "loc" : [ -89.222239, 31.347181 ], "pop" : 15799, "state" : "MS" }
+{ "_id" : "39466", "city" : "PICAYUNE", "loc" : [ -89.69102100000001, 30.541796 ], "pop" : 20116, "state" : "MS" }
+{ "_id" : "39470", "city" : "POPLARVILLE", "loc" : [ -89.564751, 30.852362 ], "pop" : 7682, "state" : "MS" }
+{ "_id" : "39474", "city" : "PRENTISS", "loc" : [ -89.873497, 31.605655 ], "pop" : 9065, "state" : "MS" }
+{ "_id" : "39475", "city" : "PURVIS", "loc" : [ -89.462301, 31.149562 ], "pop" : 4493, "state" : "MS" }
+{ "_id" : "39476", "city" : "RICHTON", "loc" : [ -88.910079, 31.343364 ], "pop" : 7378, "state" : "MS" }
+{ "_id" : "39478", "city" : "SANDY HOOK", "loc" : [ -89.818343, 31.047904 ], "pop" : 448, "state" : "MS" }
+{ "_id" : "39479", "city" : "SEMINARY", "loc" : [ -89.481585, 31.528485 ], "pop" : 4010, "state" : "MS" }
+{ "_id" : "39480", "city" : "SOSO", "loc" : [ -89.308223, 31.75941 ], "pop" : 2890, "state" : "MS" }
+{ "_id" : "39481", "city" : "STRINGER", "loc" : [ -89.26214400000001, 31.844721 ], "pop" : 1367, "state" : "MS" }
+{ "_id" : "39482", "city" : "SUMRALL", "loc" : [ -89.57772300000001, 31.359972 ], "pop" : 4741, "state" : "MS" }
+{ "_id" : "39483", "city" : "FOXWORTH", "loc" : [ -89.93107500000001, 31.247325 ], "pop" : 4317, "state" : "MS" }
+{ "_id" : "39501", "city" : "GULFPORT", "loc" : [ -89.097618, 30.382556 ], "pop" : 25894, "state" : "MS" }
+{ "_id" : "39503", "city" : "GULFPORT", "loc" : [ -89.08855200000001, 30.460105 ], "pop" : 26830, "state" : "MS" }
+{ "_id" : "39507", "city" : "GULFPORT", "loc" : [ -89.035347, 30.396248 ], "pop" : 18144, "state" : "MS" }
+{ "_id" : "39520", "city" : "DIAMONDHEAD", "loc" : [ -89.397356, 30.324275 ], "pop" : 20156, "state" : "MS" }
+{ "_id" : "39530", "city" : "BILOXI", "loc" : [ -88.897143, 30.403478 ], "pop" : 22245, "state" : "MS" }
+{ "_id" : "39531", "city" : "BILOXI", "loc" : [ -88.960499, 30.40334 ], "pop" : 18541, "state" : "MS" }
+{ "_id" : "39532", "city" : "NORTH BAY", "loc" : [ -88.918846, 30.452031 ], "pop" : 25296, "state" : "MS" }
+{ "_id" : "39553", "city" : "GAUTIER", "loc" : [ -88.64117299999999, 30.398032 ], "pop" : 13240, "state" : "MS" }
+{ "_id" : "39560", "city" : "LONG BEACH", "loc" : [ -89.16457699999999, 30.359756 ], "pop" : 17826, "state" : "MS" }
+{ "_id" : "39561", "city" : "MC HENRY", "loc" : [ -89.153631, 30.697463 ], "pop" : 375, "state" : "MS" }
+{ "_id" : "39563", "city" : "KREOLE", "loc" : [ -88.526015, 30.402773 ], "pop" : 15657, "state" : "MS" }
+{ "_id" : "39564", "city" : "OCEAN SPRINGS", "loc" : [ -88.78009900000001, 30.440433 ], "pop" : 34238, "state" : "MS" }
+{ "_id" : "39567", "city" : "PASCAGOULA", "loc" : [ -88.51647199999999, 30.530301 ], "pop" : 16025, "state" : "MS" }
+{ "_id" : "39571", "city" : "PASS CHRISTIAN", "loc" : [ -89.28426899999999, 30.398918 ], "pop" : 14427, "state" : "MS" }
+{ "_id" : "39573", "city" : "PERKINSTON", "loc" : [ -89.139985, 30.76686 ], "pop" : 3743, "state" : "MS" }
+{ "_id" : "39574", "city" : "SAUCIER", "loc" : [ -89.147729, 30.596082 ], "pop" : 6520, "state" : "MS" }
+{ "_id" : "39576", "city" : "WAVELAND", "loc" : [ -89.383679, 30.29138 ], "pop" : 5967, "state" : "MS" }
+{ "_id" : "39577", "city" : "WIGGINS", "loc" : [ -89.132369, 30.86095 ], "pop" : 6632, "state" : "MS" }
+{ "_id" : "39581", "city" : "PASCAGOULA", "loc" : [ -88.52885999999999, 30.366377 ], "pop" : 27619, "state" : "MS" }
+{ "_id" : "39601", "city" : "BROOKHAVEN", "loc" : [ -90.451995, 31.58581 ], "pop" : 20910, "state" : "MS" }
+{ "_id" : "39629", "city" : "BOGUE CHITTO", "loc" : [ -90.47318300000001, 31.456344 ], "pop" : 7068, "state" : "MS" }
+{ "_id" : "39631", "city" : "CENTREVILLE", "loc" : [ -91.095985, 31.089329 ], "pop" : 4055, "state" : "MS" }
+{ "_id" : "39633", "city" : "CROSBY", "loc" : [ -91.023712, 31.299406 ], "pop" : 574, "state" : "MS" }
+{ "_id" : "39638", "city" : "GLOSTER", "loc" : [ -90.92404500000001, 31.19033 ], "pop" : 6389, "state" : "MS" }
+{ "_id" : "39641", "city" : "JAYESS", "loc" : [ -90.186386, 31.403577 ], "pop" : 1621, "state" : "MS" }
+{ "_id" : "39643", "city" : "KOKOMO", "loc" : [ -89.98241899999999, 31.177688 ], "pop" : 888, "state" : "MS" }
+{ "_id" : "39645", "city" : "LIBERTY", "loc" : [ -90.71334899999999, 31.138427 ], "pop" : 2950, "state" : "MS" }
+{ "_id" : "39647", "city" : "MC CALL CREEK", "loc" : [ -90.783581, 31.490772 ], "pop" : 3017, "state" : "MS" }
+{ "_id" : "39648", "city" : "MC COMB", "loc" : [ -90.43244900000001, 31.221594 ], "pop" : 23551, "state" : "MS" }
+{ "_id" : "39652", "city" : "MAGNOLIA", "loc" : [ -90.48311, 31.121745 ], "pop" : 7831, "state" : "MS" }
+{ "_id" : "39653", "city" : "MEADVILLE", "loc" : [ -90.85783499999999, 31.428489 ], "pop" : 1673, "state" : "MS" }
+{ "_id" : "39654", "city" : "MONTICELLO", "loc" : [ -90.12796, 31.523776 ], "pop" : 4517, "state" : "MS" }
+{ "_id" : "39656", "city" : "OAK VALE", "loc" : [ -89.98273, 31.441953 ], "pop" : 321, "state" : "MS" }
+{ "_id" : "39657", "city" : "OSYKA", "loc" : [ -90.478977, 31.021747 ], "pop" : 1143, "state" : "MS" }
+{ "_id" : "39661", "city" : "ROXIE", "loc" : [ -91.06247500000001, 31.504043 ], "pop" : 3526, "state" : "MS" }
+{ "_id" : "39662", "city" : "RUTH", "loc" : [ -90.28667299999999, 31.379495 ], "pop" : 415, "state" : "MS" }
+{ "_id" : "39663", "city" : "SILVER CREEK", "loc" : [ -90.017332, 31.575535 ], "pop" : 2862, "state" : "MS" }
+{ "_id" : "39664", "city" : "SMITHDALE", "loc" : [ -90.675236, 31.367203 ], "pop" : 1247, "state" : "MS" }
+{ "_id" : "39665", "city" : "SONTAG", "loc" : [ -90.180125, 31.645313 ], "pop" : 1953, "state" : "MS" }
+{ "_id" : "39666", "city" : "SUMMIT", "loc" : [ -90.46542700000001, 31.29752 ], "pop" : 6696, "state" : "MS" }
+{ "_id" : "39667", "city" : "TYLERTOWN", "loc" : [ -90.116918, 31.146552 ], "pop" : 14352, "state" : "MS" }
+{ "_id" : "39668", "city" : "UNION CHURCH", "loc" : [ -90.82592200000001, 31.710474 ], "pop" : 587, "state" : "MS" }
+{ "_id" : "39669", "city" : "WOODVILLE", "loc" : [ -91.307596, 31.145913 ], "pop" : 6400, "state" : "MS" }
+{ "_id" : "39701", "city" : "COLUMBUS", "loc" : [ -88.426194, 33.537699 ], "pop" : 32609, "state" : "MS" }
+{ "_id" : "39702", "city" : "COLUMBUS", "loc" : [ -88.35538699999999, 33.481175 ], "pop" : 21004, "state" : "MS" }
+{ "_id" : "39730", "city" : "ABERDEEN", "loc" : [ -88.538033, 33.828439 ], "pop" : 15769, "state" : "MS" }
+{ "_id" : "39735", "city" : "ACKERMAN", "loc" : [ -89.20139, 33.351684 ], "pop" : 5027, "state" : "MS" }
+{ "_id" : "39739", "city" : "BROOKSVILLE", "loc" : [ -88.501351, 33.213961 ], "pop" : 4598, "state" : "MS" }
+{ "_id" : "39740", "city" : "CALEDONIA", "loc" : [ -88.314537, 33.686461 ], "pop" : 2008, "state" : "MS" }
+{ "_id" : "39741", "city" : "CEDARBLUFF", "loc" : [ -88.826712, 33.61616 ], "pop" : 1063, "state" : "MS" }
+{ "_id" : "39743", "city" : "CRAWFORD", "loc" : [ -88.56711900000001, 33.321922 ], "pop" : 2310, "state" : "MS" }
+{ "_id" : "39744", "city" : "TOMNOLEN", "loc" : [ -89.304542, 33.568908 ], "pop" : 5686, "state" : "MS" }
+{ "_id" : "39745", "city" : "FRENCH CAMP", "loc" : [ -89.39458500000001, 33.338319 ], "pop" : 1426, "state" : "MS" }
+{ "_id" : "39746", "city" : "HAMILTON", "loc" : [ -88.44784, 33.801141 ], "pop" : 726, "state" : "MS" }
+{ "_id" : "39747", "city" : "KILMICHAEL", "loc" : [ -89.569577, 33.416476 ], "pop" : 2351, "state" : "MS" }
+{ "_id" : "39750", "city" : "MABEN", "loc" : [ -89.065887, 33.526179 ], "pop" : 1286, "state" : "MS" }
+{ "_id" : "39751", "city" : "MANTEE", "loc" : [ -89.122906, 33.665493 ], "pop" : 1813, "state" : "MS" }
+{ "_id" : "39752", "city" : "MATHISTON", "loc" : [ -89.12747899999999, 33.541493 ], "pop" : 3213, "state" : "MS" }
+{ "_id" : "39755", "city" : "PHEBA", "loc" : [ -88.951842, 33.596056 ], "pop" : 740, "state" : "MS" }
+{ "_id" : "39756", "city" : "PRAIRIE", "loc" : [ -88.63346300000001, 33.795113 ], "pop" : 135, "state" : "MS" }
+{ "_id" : "39759", "city" : "SESSUMS", "loc" : [ -88.817637, 33.450125 ], "pop" : 36268, "state" : "MS" }
+{ "_id" : "39766", "city" : "STEENS", "loc" : [ -88.327755, 33.56708 ], "pop" : 1377, "state" : "MS" }
+{ "_id" : "39767", "city" : "STEWART", "loc" : [ -89.479, 33.510097 ], "pop" : 892, "state" : "MS" }
+{ "_id" : "39769", "city" : "STURGIS", "loc" : [ -89.04727, 33.35702 ], "pop" : 814, "state" : "MS" }
+{ "_id" : "39772", "city" : "WEIR", "loc" : [ -89.28041899999999, 33.264464 ], "pop" : 1402, "state" : "MS" }
+{ "_id" : "39773", "city" : "WEST POINT", "loc" : [ -88.68226, 33.626496 ], "pop" : 19317, "state" : "MS" }
+{ "_id" : "39776", "city" : "WOODLAND", "loc" : [ -89.02555700000001, 33.80661 ], "pop" : 2276, "state" : "MS" }
+{ "_id" : "40003", "city" : "BAGDAD", "loc" : [ -85.06514199999999, 38.260811 ], "pop" : 1272, "state" : "KY" }
+{ "_id" : "40004", "city" : "BARDSTOWN", "loc" : [ -85.461343, 37.80835 ], "pop" : 16176, "state" : "KY" }
+{ "_id" : "40006", "city" : "BEDFORD", "loc" : [ -85.31333100000001, 38.586363 ], "pop" : 3359, "state" : "KY" }
+{ "_id" : "40007", "city" : "BETHLEHEM", "loc" : [ -85.064874, 38.402433 ], "pop" : 353, "state" : "KY" }
+{ "_id" : "40008", "city" : "BLOOMFIELD", "loc" : [ -85.286209, 37.907979 ], "pop" : 2461, "state" : "KY" }
+{ "_id" : "40009", "city" : "BRADFORDSVILLE", "loc" : [ -85.14359899999999, 37.46622 ], "pop" : 1136, "state" : "KY" }
+{ "_id" : "40010", "city" : "BUCKNER", "loc" : [ -85.47405999999999, 38.363008 ], "pop" : 34, "state" : "KY" }
+{ "_id" : "40011", "city" : "CAMPBELLSBURG", "loc" : [ -85.16109400000001, 38.523083 ], "pop" : 1960, "state" : "KY" }
+{ "_id" : "40012", "city" : "CHAPLIN", "loc" : [ -85.201472, 37.902541 ], "pop" : 443, "state" : "KY" }
+{ "_id" : "40013", "city" : "DEATSVILLE", "loc" : [ -85.48415900000001, 37.896386 ], "pop" : 4763, "state" : "KY" }
+{ "_id" : "40014", "city" : "CRESTWOOD", "loc" : [ -85.461038, 38.332637 ], "pop" : 10779, "state" : "KY" }
+{ "_id" : "40019", "city" : "EMINENCE", "loc" : [ -85.17816000000001, 38.369606 ], "pop" : 2493, "state" : "KY" }
+{ "_id" : "40022", "city" : "FINCHVILLE", "loc" : [ -85.347573, 38.156064 ], "pop" : 1040, "state" : "KY" }
+{ "_id" : "40023", "city" : "FISHERVILLE", "loc" : [ -85.42822200000001, 38.165154 ], "pop" : 937, "state" : "KY" }
+{ "_id" : "40026", "city" : "GOSHEN", "loc" : [ -85.57081599999999, 38.411294 ], "pop" : 3626, "state" : "KY" }
+{ "_id" : "40028", "city" : "HOWARDSTOWN", "loc" : [ -85.55476899999999, 37.566393 ], "pop" : 218, "state" : "KY" }
+{ "_id" : "40031", "city" : "LA GRANGE", "loc" : [ -85.392819, 38.402897 ], "pop" : 13280, "state" : "KY" }
+{ "_id" : "40033", "city" : "LEBANON", "loc" : [ -85.266811, 37.565834 ], "pop" : 10672, "state" : "KY" }
+{ "_id" : "40036", "city" : "LOCKPORT", "loc" : [ -84.958635, 38.421874 ], "pop" : 742, "state" : "KY" }
+{ "_id" : "40037", "city" : "LORETTO", "loc" : [ -85.411297, 37.642112 ], "pop" : 2586, "state" : "KY" }
+{ "_id" : "40040", "city" : "MACKVILLE", "loc" : [ -85.085201, 37.724703 ], "pop" : 1753, "state" : "KY" }
+{ "_id" : "40045", "city" : "MILTON", "loc" : [ -85.36593000000001, 38.692489 ], "pop" : 2535, "state" : "KY" }
+{ "_id" : "40046", "city" : "MOUNT EDEN", "loc" : [ -85.164114, 38.035238 ], "pop" : 597, "state" : "KY" }
+{ "_id" : "40047", "city" : "MOUNT WASHINGTON", "loc" : [ -85.55863100000001, 38.045206 ], "pop" : 8785, "state" : "KY" }
+{ "_id" : "40050", "city" : "NEW CASTLE", "loc" : [ -85.175567, 38.437368 ], "pop" : 2017, "state" : "KY" }
+{ "_id" : "40051", "city" : "TRAPPIST", "loc" : [ -85.557694, 37.666327 ], "pop" : 3698, "state" : "KY" }
+{ "_id" : "40055", "city" : "PENDLETON", "loc" : [ -85.317019, 38.480918 ], "pop" : 975, "state" : "KY" }
+{ "_id" : "40056", "city" : "PEWEE VALLEY", "loc" : [ -85.483377, 38.303945 ], "pop" : 2622, "state" : "KY" }
+{ "_id" : "40057", "city" : "CROPPER", "loc" : [ -85.087198, 38.358718 ], "pop" : 2669, "state" : "KY" }
+{ "_id" : "40059", "city" : "PROSPECT", "loc" : [ -85.608287, 38.355987 ], "pop" : 7454, "state" : "KY" }
+{ "_id" : "40060", "city" : "RAYWICK", "loc" : [ -85.43003, 37.537959 ], "pop" : 981, "state" : "KY" }
+{ "_id" : "40061", "city" : "SAINT CATHARINE", "loc" : [ -85.27106000000001, 37.699126 ], "pop" : 39, "state" : "KY" }
+{ "_id" : "40062", "city" : "SAINT FRANCIS", "loc" : [ -85.464208, 37.628644 ], "pop" : 39, "state" : "KY" }
+{ "_id" : "40065", "city" : "SHELBYVILLE", "loc" : [ -85.224271, 38.216222 ], "pop" : 14843, "state" : "KY" }
+{ "_id" : "40067", "city" : "SIMPSONVILLE", "loc" : [ -85.354797, 38.231186 ], "pop" : 2443, "state" : "KY" }
+{ "_id" : "40068", "city" : "SMITHFIELD", "loc" : [ -85.265579, 38.393308 ], "pop" : 1250, "state" : "KY" }
+{ "_id" : "40069", "city" : "MAUD", "loc" : [ -85.24047299999999, 37.701352 ], "pop" : 6314, "state" : "KY" }
+{ "_id" : "40070", "city" : "SULPHUR", "loc" : [ -85.252021, 38.492062 ], "pop" : 466, "state" : "KY" }
+{ "_id" : "40071", "city" : "TAYLORSVILLE", "loc" : [ -85.38286100000001, 38.047054 ], "pop" : 7048, "state" : "KY" }
+{ "_id" : "40075", "city" : "TURNERS STATION", "loc" : [ -85.13251200000001, 38.550361 ], "pop" : 611, "state" : "KY" }
+{ "_id" : "40076", "city" : "WADDY", "loc" : [ -85.12882999999999, 38.105445 ], "pop" : 1510, "state" : "KY" }
+{ "_id" : "40077", "city" : "WESTPORT", "loc" : [ -85.45242, 38.492068 ], "pop" : 500, "state" : "KY" }
+{ "_id" : "40078", "city" : "WILLISBURG", "loc" : [ -85.13618700000001, 37.837333 ], "pop" : 2245, "state" : "KY" }
+{ "_id" : "40104", "city" : "BATTLETOWN", "loc" : [ -86.299104, 38.039295 ], "pop" : 2532, "state" : "KY" }
+{ "_id" : "40106", "city" : "BIG SPRING", "loc" : [ -86.19179099999999, 37.798795 ], "pop" : 315, "state" : "KY" }
+{ "_id" : "40107", "city" : "BOSTON", "loc" : [ -85.619927, 37.763991 ], "pop" : 2589, "state" : "KY" }
+{ "_id" : "40108", "city" : "BRANDENBURG", "loc" : [ -86.10835899999999, 37.96624 ], "pop" : 6480, "state" : "KY" }
+{ "_id" : "40109", "city" : "BROOKS", "loc" : [ -85.771344, 38.054576 ], "pop" : 4447, "state" : "KY" }
+{ "_id" : "40111", "city" : "CLOVERPORT", "loc" : [ -86.595401, 37.822125 ], "pop" : 2852, "state" : "KY" }
+{ "_id" : "40114", "city" : "CONSTANTINE", "loc" : [ -86.24009, 37.679412 ], "pop" : 67, "state" : "KY" }
+{ "_id" : "40115", "city" : "CUSTER", "loc" : [ -86.271006, 37.742593 ], "pop" : 47, "state" : "KY" }
+{ "_id" : "40117", "city" : "EKRON", "loc" : [ -86.154212, 37.91129 ], "pop" : 2565, "state" : "KY" }
+{ "_id" : "40118", "city" : "FAIRDALE", "loc" : [ -85.754924, 38.108668 ], "pop" : 8297, "state" : "KY" }
+{ "_id" : "40119", "city" : "GLEN DEAN", "loc" : [ -86.51074699999999, 37.569353 ], "pop" : 770, "state" : "KY" }
+{ "_id" : "40121", "city" : "FORT KNOX", "loc" : [ -85.948909, 37.892798 ], "pop" : 15407, "state" : "KY" }
+{ "_id" : "40140", "city" : "GARFIELD", "loc" : [ -86.316868, 37.814508 ], "pop" : 613, "state" : "KY" }
+{ "_id" : "40142", "city" : "GUSTON", "loc" : [ -86.215515, 37.89511 ], "pop" : 1525, "state" : "KY" }
+{ "_id" : "40143", "city" : "MOOLEYVILLE", "loc" : [ -86.416856, 37.772548 ], "pop" : 3995, "state" : "KY" }
+{ "_id" : "40144", "city" : "LOCUST HILL", "loc" : [ -86.37779, 37.742925 ], "pop" : 1648, "state" : "KY" }
+{ "_id" : "40145", "city" : "HUDSON", "loc" : [ -86.301238, 37.650613 ], "pop" : 55, "state" : "KY" }
+{ "_id" : "40146", "city" : "IRVINGTON", "loc" : [ -86.29653399999999, 37.876239 ], "pop" : 2335, "state" : "KY" }
+{ "_id" : "40150", "city" : "LEBANON JUNCTION", "loc" : [ -85.72464100000001, 37.851054 ], "pop" : 5051, "state" : "KY" }
+{ "_id" : "40152", "city" : "MC DANIELS", "loc" : [ -86.397278, 37.595251 ], "pop" : 44, "state" : "KY" }
+{ "_id" : "40157", "city" : "PAYNEVILLE", "loc" : [ -86.408164, 38.030128 ], "pop" : 504, "state" : "KY" }
+{ "_id" : "40160", "city" : "RADCLIFF", "loc" : [ -85.94040800000001, 37.826652 ], "pop" : 21490, "state" : "KY" }
+{ "_id" : "40161", "city" : "RHODELIA", "loc" : [ -86.304079, 37.968538 ], "pop" : 1322, "state" : "KY" }
+{ "_id" : "40162", "city" : "RINEYVILLE", "loc" : [ -85.995395, 37.75249 ], "pop" : 4542, "state" : "KY" }
+{ "_id" : "40164", "city" : "SE REE", "loc" : [ -86.399176, 37.676018 ], "pop" : 299, "state" : "KY" }
+{ "_id" : "40165", "city" : "SHEPHERDSVILLE", "loc" : [ -85.688767, 38.004515 ], "pop" : 18649, "state" : "KY" }
+{ "_id" : "40170", "city" : "STEPHENSPORT", "loc" : [ -86.523961, 37.904781 ], "pop" : 134, "state" : "KY" }
+{ "_id" : "40171", "city" : "UNION STAR", "loc" : [ -86.461519, 37.961589 ], "pop" : 606, "state" : "KY" }
+{ "_id" : "40175", "city" : "VINE GROVE", "loc" : [ -86.006888, 37.858937 ], "pop" : 13294, "state" : "KY" }
+{ "_id" : "40176", "city" : "WEBSTER", "loc" : [ -86.403204, 37.923936 ], "pop" : 258, "state" : "KY" }
+{ "_id" : "40177", "city" : "WEST POINT", "loc" : [ -85.95450200000001, 37.995408 ], "pop" : 1235, "state" : "KY" }
+{ "_id" : "40178", "city" : "WESTVIEW", "loc" : [ -86.427286, 37.679196 ], "pop" : 223, "state" : "KY" }
+{ "_id" : "40202", "city" : "LOUISVILLE", "loc" : [ -85.747646, 38.250734 ], "pop" : 5221, "state" : "KY" }
+{ "_id" : "40203", "city" : "LOUISVILLE", "loc" : [ -85.762595, 38.245332 ], "pop" : 19432, "state" : "KY" }
+{ "_id" : "40204", "city" : "LOUISVILLE", "loc" : [ -85.72493799999999, 38.236936 ], "pop" : 16467, "state" : "KY" }
+{ "_id" : "40205", "city" : "LOUISVILLE", "loc" : [ -85.688542, 38.22217 ], "pop" : 24979, "state" : "KY" }
+{ "_id" : "40206", "city" : "SAINT MATTHEWS", "loc" : [ -85.697581, 38.256495 ], "pop" : 20604, "state" : "KY" }
+{ "_id" : "40207", "city" : "SAINT MATTHEWS", "loc" : [ -85.649689, 38.257908 ], "pop" : 30193, "state" : "KY" }
+{ "_id" : "40208", "city" : "LOUISVILLE", "loc" : [ -85.76482300000001, 38.219988 ], "pop" : 13523, "state" : "KY" }
+{ "_id" : "40209", "city" : "LOUISVILLE", "loc" : [ -85.751904, 38.190125 ], "pop" : 2752, "state" : "KY" }
+{ "_id" : "40210", "city" : "LOUISVILLE", "loc" : [ -85.790548, 38.230585 ], "pop" : 18623, "state" : "KY" }
+{ "_id" : "40211", "city" : "LOUISVILLE", "loc" : [ -85.81265, 38.241958 ], "pop" : 26422, "state" : "KY" }
+{ "_id" : "40212", "city" : "LOUISVILLE", "loc" : [ -85.804479, 38.265116 ], "pop" : 21605, "state" : "KY" }
+{ "_id" : "40213", "city" : "LOUISVILLE", "loc" : [ -85.71064200000001, 38.183929 ], "pop" : 21288, "state" : "KY" }
+{ "_id" : "40214", "city" : "LOUISVILLE", "loc" : [ -85.77802699999999, 38.159318 ], "pop" : 42198, "state" : "KY" }
+{ "_id" : "40215", "city" : "LOUISVILLE", "loc" : [ -85.784707, 38.191319 ], "pop" : 24661, "state" : "KY" }
+{ "_id" : "40216", "city" : "SHIVELY", "loc" : [ -85.831771, 38.186138 ], "pop" : 41719, "state" : "KY" }
+{ "_id" : "40217", "city" : "LOUISVILLE", "loc" : [ -85.740371, 38.21736 ], "pop" : 13213, "state" : "KY" }
+{ "_id" : "40218", "city" : "BUECHEL", "loc" : [ -85.65483399999999, 38.191084 ], "pop" : 31434, "state" : "KY" }
+{ "_id" : "40219", "city" : "OKOLONA", "loc" : [ -85.680548, 38.141291 ], "pop" : 38009, "state" : "KY" }
+{ "_id" : "40220", "city" : "LOUISVILLE", "loc" : [ -85.624489, 38.21494 ], "pop" : 29012, "state" : "KY" }
+{ "_id" : "40222", "city" : "LYNDON", "loc" : [ -85.611183, 38.263825 ], "pop" : 19924, "state" : "KY" }
+{ "_id" : "40223", "city" : "ANCHORAGE", "loc" : [ -85.561151, 38.253688 ], "pop" : 19766, "state" : "KY" }
+{ "_id" : "40228", "city" : "BUECHEL", "loc" : [ -85.630967, 38.1392 ], "pop" : 9192, "state" : "KY" }
+{ "_id" : "40229", "city" : "OKOLONA", "loc" : [ -85.67188899999999, 38.090655 ], "pop" : 26878, "state" : "KY" }
+{ "_id" : "40241", "city" : "LYNDON", "loc" : [ -85.582421, 38.301509 ], "pop" : 14137, "state" : "KY" }
+{ "_id" : "40242", "city" : "LYNDON", "loc" : [ -85.59022400000001, 38.276858 ], "pop" : 9742, "state" : "KY" }
+{ "_id" : "40243", "city" : "MIDDLETOWN", "loc" : [ -85.537381, 38.240115 ], "pop" : 9317, "state" : "KY" }
+{ "_id" : "40245", "city" : "LOUISVILLE", "loc" : [ -85.484461, 38.268273 ], "pop" : 8662, "state" : "KY" }
+{ "_id" : "40258", "city" : "PLEASURE RIDGE P", "loc" : [ -85.862505, 38.142369 ], "pop" : 24515, "state" : "KY" }
+{ "_id" : "40272", "city" : "VALLEY STATION", "loc" : [ -85.858701, 38.097063 ], "pop" : 32843, "state" : "KY" }
+{ "_id" : "40291", "city" : "FERN CREEK", "loc" : [ -85.59451300000001, 38.15205 ], "pop" : 22429, "state" : "KY" }
+{ "_id" : "40299", "city" : "JEFFERSONTOWN", "loc" : [ -85.56894699999999, 38.188491 ], "pop" : 23882, "state" : "KY" }
+{ "_id" : "40311", "city" : "CARLISLE", "loc" : [ -84.027902, 38.321233 ], "pop" : 6825, "state" : "KY" }
+{ "_id" : "40312", "city" : "WESTBEND", "loc" : [ -83.934693, 37.860571 ], "pop" : 5408, "state" : "KY" }
+{ "_id" : "40313", "city" : "CLEARFIELD", "loc" : [ -83.32728899999999, 38.143992 ], "pop" : 1942, "state" : "KY" }
+{ "_id" : "40316", "city" : "DENNISTON", "loc" : [ -83.513136, 37.919068 ], "pop" : 238, "state" : "KY" }
+{ "_id" : "40322", "city" : "SCRANTON", "loc" : [ -83.642405, 37.946031 ], "pop" : 3175, "state" : "KY" }
+{ "_id" : "40324", "city" : "GEORGETOWN", "loc" : [ -84.556179, 38.211712 ], "pop" : 18666, "state" : "KY" }
+{ "_id" : "40327", "city" : "GRATZ", "loc" : [ -84.942882, 38.478104 ], "pop" : 216, "state" : "KY" }
+{ "_id" : "40328", "city" : "GRAVEL SWITCH", "loc" : [ -85.082403, 37.575802 ], "pop" : 962, "state" : "KY" }
+{ "_id" : "40330", "city" : "CORNISHVILLE", "loc" : [ -84.84675, 37.769989 ], "pop" : 17727, "state" : "KY" }
+{ "_id" : "40336", "city" : "JINKS", "loc" : [ -83.996172, 37.705051 ], "pop" : 13349, "state" : "KY" }
+{ "_id" : "40337", "city" : "JEFFERSONVILLE", "loc" : [ -83.855778, 37.964004 ], "pop" : 4303, "state" : "KY" }
+{ "_id" : "40339", "city" : "KEENE", "loc" : [ -84.65192399999999, 37.941057 ], "pop" : 253, "state" : "KY" }
+{ "_id" : "40341", "city" : "LAMERO", "loc" : [ -84.162353, 37.319166 ], "pop" : 25, "state" : "KY" }
+{ "_id" : "40342", "city" : "LAWRENCEBURG", "loc" : [ -84.92993800000001, 38.018853 ], "pop" : 13485, "state" : "KY" }
+{ "_id" : "40345", "city" : "MARIBA", "loc" : [ -83.553692, 37.913527 ], "pop" : 374, "state" : "KY" }
+{ "_id" : "40346", "city" : "MEANS", "loc" : [ -83.725343, 37.928382 ], "pop" : 324, "state" : "KY" }
+{ "_id" : "40347", "city" : "MIDWAY", "loc" : [ -84.69284500000001, 38.148741 ], "pop" : 2079, "state" : "KY" }
+{ "_id" : "40350", "city" : "MOOREFIELD", "loc" : [ -83.892889, 38.292627 ], "pop" : 383, "state" : "KY" }
+{ "_id" : "40351", "city" : "MOREHEAD", "loc" : [ -83.443645, 38.199047 ], "pop" : 18413, "state" : "KY" }
+{ "_id" : "40353", "city" : "MOUNT STERLING", "loc" : [ -83.938774, 38.054822 ], "pop" : 15242, "state" : "KY" }
+{ "_id" : "40355", "city" : "NEW LIBERTY", "loc" : [ -84.90106400000001, 38.624556 ], "pop" : 2262, "state" : "KY" }
+{ "_id" : "40356", "city" : "NICHOLASVILLE", "loc" : [ -84.56459, 37.880794 ], "pop" : 22920, "state" : "KY" }
+{ "_id" : "40358", "city" : "OLYMPIA", "loc" : [ -83.758456, 38.061089 ], "pop" : 640, "state" : "KY" }
+{ "_id" : "40359", "city" : "OWENTON", "loc" : [ -84.808632, 38.4986 ], "pop" : 6326, "state" : "KY" }
+{ "_id" : "40360", "city" : "OWINGSVILLE", "loc" : [ -83.756439, 38.153196 ], "pop" : 4583, "state" : "KY" }
+{ "_id" : "40361", "city" : "PARIS", "loc" : [ -84.24498699999999, 38.208293 ], "pop" : 18722, "state" : "KY" }
+{ "_id" : "40365", "city" : "POMEROYTON", "loc" : [ -83.526315, 37.874352 ], "pop" : 480, "state" : "KY" }
+{ "_id" : "40370", "city" : "SADIEVILLE", "loc" : [ -84.53842400000001, 38.390816 ], "pop" : 2694, "state" : "KY" }
+{ "_id" : "40371", "city" : "SALT LICK", "loc" : [ -83.631619, 38.104031 ], "pop" : 2687, "state" : "KY" }
+{ "_id" : "40372", "city" : "BONDVILLE", "loc" : [ -84.884546, 37.915078 ], "pop" : 1684, "state" : "KY" }
+{ "_id" : "40374", "city" : "SHARPSBURG", "loc" : [ -83.893199, 38.214742 ], "pop" : 1685, "state" : "KY" }
+{ "_id" : "40376", "city" : "SLADE", "loc" : [ -83.68485200000001, 37.788958 ], "pop" : 318, "state" : "KY" }
+{ "_id" : "40379", "city" : "STAMPING GROUND", "loc" : [ -84.68182400000001, 38.288802 ], "pop" : 3757, "state" : "KY" }
+{ "_id" : "40380", "city" : "PATSEY", "loc" : [ -83.829947, 37.842703 ], "pop" : 5966, "state" : "KY" }
+{ "_id" : "40383", "city" : "VERSAILLES", "loc" : [ -84.728683, 38.041301 ], "pop" : 18204, "state" : "KY" }
+{ "_id" : "40385", "city" : "BYBEE", "loc" : [ -84.11706100000001, 37.766833 ], "pop" : 1433, "state" : "KY" }
+{ "_id" : "40387", "city" : "KOREA", "loc" : [ -83.47305, 37.965353 ], "pop" : 501, "state" : "KY" }
+{ "_id" : "40390", "city" : "HIGH BRIDGE", "loc" : [ -84.66207900000001, 37.862141 ], "pop" : 5600, "state" : "KY" }
+{ "_id" : "40391", "city" : "WINCHESTER", "loc" : [ -84.178894, 37.987161 ], "pop" : 29149, "state" : "KY" }
+{ "_id" : "40402", "city" : "MOORES CREEK", "loc" : [ -83.959737, 37.306965 ], "pop" : 1941, "state" : "KY" }
+{ "_id" : "40403", "city" : "BEREA", "loc" : [ -84.274919, 37.579942 ], "pop" : 16561, "state" : "KY" }
+{ "_id" : "40409", "city" : "BRODHEAD", "loc" : [ -84.43358000000001, 37.381524 ], "pop" : 2596, "state" : "KY" }
+{ "_id" : "40415", "city" : "COBHILL", "loc" : [ -83.840053, 37.743428 ], "pop" : 284, "state" : "KY" }
+{ "_id" : "40417", "city" : "CONWAY", "loc" : [ -84.308072, 37.479933 ], "pop" : 2806, "state" : "KY" }
+{ "_id" : "40419", "city" : "CRAB ORCHARD", "loc" : [ -84.49391199999999, 37.446523 ], "pop" : 5197, "state" : "KY" }
+{ "_id" : "40422", "city" : "DANVILLE", "loc" : [ -84.77469600000001, 37.646524 ], "pop" : 19483, "state" : "KY" }
+{ "_id" : "40426", "city" : "DREYFUS", "loc" : [ -84.154495, 37.650696 ], "pop" : 562, "state" : "KY" }
+{ "_id" : "40437", "city" : "HUSTONVILLE", "loc" : [ -84.85277499999999, 37.459503 ], "pop" : 2965, "state" : "KY" }
+{ "_id" : "40440", "city" : "JUNCTION CITY", "loc" : [ -84.80278199999999, 37.582157 ], "pop" : 3582, "state" : "KY" }
+{ "_id" : "40442", "city" : "KINGS MOUNTAIN", "loc" : [ -84.714764, 37.381795 ], "pop" : 2385, "state" : "KY" }
+{ "_id" : "40444", "city" : "LANCASTER", "loc" : [ -84.596912, 37.658391 ], "pop" : 8664, "state" : "KY" }
+{ "_id" : "40445", "city" : "LIVINGSTON", "loc" : [ -84.231776, 37.307391 ], "pop" : 1320, "state" : "KY" }
+{ "_id" : "40447", "city" : "CLOVER BOTTOM", "loc" : [ -84.00896, 37.431678 ], "pop" : 8071, "state" : "KY" }
+{ "_id" : "40456", "city" : "CLIMAX", "loc" : [ -84.354882, 37.336609 ], "pop" : 5636, "state" : "KY" }
+{ "_id" : "40460", "city" : "ORLANDO", "loc" : [ -84.25280100000001, 37.373405 ], "pop" : 1429, "state" : "KY" }
+{ "_id" : "40461", "city" : "PAINT LICK", "loc" : [ -84.426869, 37.609231 ], "pop" : 3361, "state" : "KY" }
+{ "_id" : "40464", "city" : "PARKSVILLE", "loc" : [ -84.92813200000001, 37.577768 ], "pop" : 893, "state" : "KY" }
+{ "_id" : "40468", "city" : "PERRYVILLE", "loc" : [ -84.966508, 37.637494 ], "pop" : 2019, "state" : "KY" }
+{ "_id" : "40471", "city" : "PRYSE", "loc" : [ -83.842586, 37.684068 ], "pop" : 250, "state" : "KY" }
+{ "_id" : "40472", "city" : "RAVENNA", "loc" : [ -83.93865700000001, 37.686711 ], "pop" : 798, "state" : "KY" }
+{ "_id" : "40475", "city" : "RICHMOND", "loc" : [ -84.295526, 37.754605 ], "pop" : 37946, "state" : "KY" }
+{ "_id" : "40481", "city" : "SANDGAP", "loc" : [ -84.056676, 37.487097 ], "pop" : 837, "state" : "KY" }
+{ "_id" : "40484", "city" : "STANFORD", "loc" : [ -84.691177, 37.524529 ], "pop" : 9072, "state" : "KY" }
+{ "_id" : "40486", "city" : "ELIAS", "loc" : [ -83.87067399999999, 37.343023 ], "pop" : 837, "state" : "KY" }
+{ "_id" : "40489", "city" : "WAYNESBURG", "loc" : [ -84.665486, 37.349932 ], "pop" : 4024, "state" : "KY" }
+{ "_id" : "40502", "city" : "LEXINGTON", "loc" : [ -84.485423, 38.017394 ], "pop" : 30886, "state" : "KY" }
+{ "_id" : "40503", "city" : "LEXINGTON", "loc" : [ -84.52821, 38.001002 ], "pop" : 33537, "state" : "KY" }
+{ "_id" : "40504", "city" : "LEXINGTON", "loc" : [ -84.543325, 38.040628 ], "pop" : 22397, "state" : "KY" }
+{ "_id" : "40505", "city" : "LEXINGTON", "loc" : [ -84.458338, 38.061201 ], "pop" : 28344, "state" : "KY" }
+{ "_id" : "40507", "city" : "LEXINGTON", "loc" : [ -84.495289, 38.046385 ], "pop" : 2291, "state" : "KY" }
+{ "_id" : "40508", "city" : "LEXINGTON", "loc" : [ -84.49643500000001, 38.04754 ], "pop" : 25161, "state" : "KY" }
+{ "_id" : "40509", "city" : "LEXINGTON", "loc" : [ -84.427419, 38.010166 ], "pop" : 9029, "state" : "KY" }
+{ "_id" : "40510", "city" : "LEXINGTON", "loc" : [ -84.59104600000001, 38.070211 ], "pop" : 1467, "state" : "KY" }
+{ "_id" : "40511", "city" : "LEXINGTON", "loc" : [ -84.500671, 38.093233 ], "pop" : 16309, "state" : "KY" }
+{ "_id" : "40513", "city" : "LEXINGTON", "loc" : [ -84.58152200000001, 38.01388 ], "pop" : 3383, "state" : "KY" }
+{ "_id" : "40514", "city" : "LEXINGTON", "loc" : [ -84.576667, 37.983291 ], "pop" : 6252, "state" : "KY" }
+{ "_id" : "40515", "city" : "LEXINGTON", "loc" : [ -84.47075100000001, 37.965102 ], "pop" : 20125, "state" : "KY" }
+{ "_id" : "40516", "city" : "LEXINGTON", "loc" : [ -84.35480200000001, 38.054355 ], "pop" : 1294, "state" : "KY" }
+{ "_id" : "40517", "city" : "LEXINGTON", "loc" : [ -84.481588, 37.984864 ], "pop" : 26787, "state" : "KY" }
+{ "_id" : "40601", "city" : "HATTON", "loc" : [ -84.88061, 38.192831 ], "pop" : 46563, "state" : "KY" }
+{ "_id" : "40701", "city" : "CORBIN", "loc" : [ -84.10208, 36.934429 ], "pop" : 17476, "state" : "KY" }
+{ "_id" : "40724", "city" : "BUSH", "loc" : [ -83.976117, 37.070874 ], "pop" : 5759, "state" : "KY" }
+{ "_id" : "40729", "city" : "SYMBOL", "loc" : [ -84.14567599999999, 37.190779 ], "pop" : 8589, "state" : "KY" }
+{ "_id" : "40734", "city" : "GRAY", "loc" : [ -83.982799, 36.946743 ], "pop" : 2418, "state" : "KY" }
+{ "_id" : "40737", "city" : "KEAVY", "loc" : [ -84.14360600000001, 37.015604 ], "pop" : 1323, "state" : "KY" }
+{ "_id" : "40740", "city" : "LILY", "loc" : [ -84.08071, 37.002295 ], "pop" : 7471, "state" : "KY" }
+{ "_id" : "40741", "city" : "SASSER", "loc" : [ -84.097498, 37.101605 ], "pop" : 20329, "state" : "KY" }
+{ "_id" : "40754", "city" : "NEVISDALE", "loc" : [ -84.111113, 36.663711 ], "pop" : 157, "state" : "KY" }
+{ "_id" : "40759", "city" : "ROCKHOLDS", "loc" : [ -84.10404800000001, 36.824216 ], "pop" : 1433, "state" : "KY" }
+{ "_id" : "40763", "city" : "SILER", "loc" : [ -83.964192, 36.720352 ], "pop" : 151, "state" : "KY" }
+{ "_id" : "40769", "city" : "PLEASANT VIEW", "loc" : [ -84.143592, 36.735535 ], "pop" : 20235, "state" : "KY" }
+{ "_id" : "40771", "city" : "WOODBINE", "loc" : [ -84.08274299999999, 36.918793 ], "pop" : 10, "state" : "KY" }
+{ "_id" : "40801", "city" : "AGES BROOKSIDE", "loc" : [ -83.235294, 36.840734 ], "pop" : 164, "state" : "KY" }
+{ "_id" : "40806", "city" : "BAXTER", "loc" : [ -83.314082, 36.874913 ], "pop" : 2151, "state" : "KY" }
+{ "_id" : "40807", "city" : "BENHAM", "loc" : [ -82.90939899999999, 36.957377 ], "pop" : 98, "state" : "KY" }
+{ "_id" : "40808", "city" : "BIG LAUREL", "loc" : [ -83.156468, 37.002795 ], "pop" : 0, "state" : "KY" }
+{ "_id" : "40810", "city" : "LEWIS CREEK", "loc" : [ -83.35390099999999, 36.912348 ], "pop" : 567, "state" : "KY" }
+{ "_id" : "40813", "city" : "CALVIN", "loc" : [ -83.737144, 36.707818 ], "pop" : 2047, "state" : "KY" }
+{ "_id" : "40815", "city" : "CRUMMIES", "loc" : [ -83.265719, 36.74619 ], "pop" : 154, "state" : "KY" }
+{ "_id" : "40818", "city" : "COALGOOD", "loc" : [ -83.238782, 36.793394 ], "pop" : 1218, "state" : "KY" }
+{ "_id" : "40819", "city" : "COLDIRON", "loc" : [ -83.40959100000001, 36.877718 ], "pop" : 392, "state" : "KY" }
+{ "_id" : "40820", "city" : "CRANKS", "loc" : [ -83.203948, 36.760228 ], "pop" : 529, "state" : "KY" }
+{ "_id" : "40823", "city" : "CUMBERLAND", "loc" : [ -82.977052, 36.971085 ], "pop" : 6601, "state" : "KY" }
+{ "_id" : "40824", "city" : "DAYHOIT", "loc" : [ -83.394329, 36.864603 ], "pop" : 44, "state" : "KY" }
+{ "_id" : "40825", "city" : "DIZNEY", "loc" : [ -83.117659, 36.817697 ], "pop" : 42, "state" : "KY" }
+{ "_id" : "40826", "city" : "EOLIA", "loc" : [ -82.77061999999999, 37.061767 ], "pop" : 676, "state" : "KY" }
+{ "_id" : "40828", "city" : "LOUELLEN", "loc" : [ -83.181648, 36.855294 ], "pop" : 4578, "state" : "KY" }
+{ "_id" : "40829", "city" : "GRAYS KNOB", "loc" : [ -83.323998, 36.811105 ], "pop" : 3057, "state" : "KY" }
+{ "_id" : "40830", "city" : "GULSTON", "loc" : [ -83.326227, 36.765622 ], "pop" : 456, "state" : "KY" }
+{ "_id" : "40831", "city" : "CHEVROLET", "loc" : [ -83.31957300000001, 36.84999 ], "pop" : 6636, "state" : "KY" }
+{ "_id" : "40843", "city" : "HOLMES MILL", "loc" : [ -82.994304, 36.875652 ], "pop" : 624, "state" : "KY" }
+{ "_id" : "40845", "city" : "HULEN", "loc" : [ -83.555132, 36.771449 ], "pop" : 2719, "state" : "KY" }
+{ "_id" : "40846", "city" : "KEITH", "loc" : [ -83.361367, 36.871241 ], "pop" : 185, "state" : "KY" }
+{ "_id" : "40847", "city" : "KENVIR", "loc" : [ -83.16055, 36.777596 ], "pop" : 346, "state" : "KY" }
+{ "_id" : "40849", "city" : "LEJUNIOR", "loc" : [ -83.19048600000001, 36.921199 ], "pop" : 1536, "state" : "KY" }
+{ "_id" : "40855", "city" : "LYNCH", "loc" : [ -82.915629, 36.997856 ], "pop" : 125, "state" : "KY" }
+{ "_id" : "40858", "city" : "MOZELLE", "loc" : [ -83.413499, 37.003666 ], "pop" : 2762, "state" : "KY" }
+{ "_id" : "40861", "city" : "OVEN FORK", "loc" : [ -82.818484, 37.053929 ], "pop" : 356, "state" : "KY" }
+{ "_id" : "40862", "city" : "PARTRIDGE", "loc" : [ -82.877168, 37.012932 ], "pop" : 861, "state" : "KY" }
+{ "_id" : "40863", "city" : "PATHFORK", "loc" : [ -83.462925, 36.752071 ], "pop" : 545, "state" : "KY" }
+{ "_id" : "40865", "city" : "PUTNEY", "loc" : [ -83.26079300000001, 36.925907 ], "pop" : 348, "state" : "KY" }
+{ "_id" : "40867", "city" : "SMITH", "loc" : [ -83.32090599999999, 36.71869 ], "pop" : 312, "state" : "KY" }
+{ "_id" : "40868", "city" : "STINNETT", "loc" : [ -83.390742, 37.08835 ], "pop" : 324, "state" : "KY" }
+{ "_id" : "40870", "city" : "TOTZ", "loc" : [ -83.201891, 36.970968 ], "pop" : 301, "state" : "KY" }
+{ "_id" : "40873", "city" : "WALLINS CREEK", "loc" : [ -83.41896800000001, 36.816532 ], "pop" : 3386, "state" : "KY" }
+{ "_id" : "40902", "city" : "ARJAY", "loc" : [ -83.641537, 36.828342 ], "pop" : 1676, "state" : "KY" }
+{ "_id" : "40903", "city" : "ARTEMUS", "loc" : [ -83.832886, 36.838837 ], "pop" : 520, "state" : "KY" }
+{ "_id" : "40906", "city" : "BAILEY SWITCH", "loc" : [ -83.899316, 36.864807 ], "pop" : 8506, "state" : "KY" }
+{ "_id" : "40913", "city" : "BEVERLY", "loc" : [ -83.556031, 36.944179 ], "pop" : 63, "state" : "KY" }
+{ "_id" : "40914", "city" : "BIG CREEK", "loc" : [ -83.633095, 37.14168 ], "pop" : 3877, "state" : "KY" }
+{ "_id" : "40915", "city" : "BIMBLE", "loc" : [ -83.82817900000001, 36.886751 ], "pop" : 836, "state" : "KY" }
+{ "_id" : "40921", "city" : "BRYANTS STORE", "loc" : [ -83.930729, 36.783087 ], "pop" : 907, "state" : "KY" }
+{ "_id" : "40923", "city" : "CANNON", "loc" : [ -83.84249800000001, 36.94888 ], "pop" : 2396, "state" : "KY" }
+{ "_id" : "40927", "city" : "CLOSPLINT", "loc" : [ -83.099766, 36.89227 ], "pop" : 1472, "state" : "KY" }
+{ "_id" : "40930", "city" : "DEWITT", "loc" : [ -83.73156, 36.8738 ], "pop" : 379, "state" : "KY" }
+{ "_id" : "40935", "city" : "SALT GUM", "loc" : [ -83.77139699999999, 36.834531 ], "pop" : 1706, "state" : "KY" }
+{ "_id" : "40940", "city" : "FONDE", "loc" : [ -83.895022, 36.64455 ], "pop" : 1326, "state" : "KY" }
+{ "_id" : "40943", "city" : "GIRDLER", "loc" : [ -83.85388, 36.969096 ], "pop" : 229, "state" : "KY" }
+{ "_id" : "40946", "city" : "GREEN ROAD", "loc" : [ -83.895768, 36.998937 ], "pop" : 360, "state" : "KY" }
+{ "_id" : "40949", "city" : "HEIDRICK", "loc" : [ -83.86650899999999, 36.892696 ], "pop" : 1362, "state" : "KY" }
+{ "_id" : "40953", "city" : "HINKLE", "loc" : [ -83.780441, 36.875323 ], "pop" : 269, "state" : "KY" }
+{ "_id" : "40958", "city" : "KETTLE ISLAND", "loc" : [ -83.58918300000001, 36.809344 ], "pop" : 710, "state" : "KY" }
+{ "_id" : "40962", "city" : "BRIGHT SHADE", "loc" : [ -83.768291, 37.142321 ], "pop" : 13727, "state" : "KY" }
+{ "_id" : "40964", "city" : "MARY ALICE", "loc" : [ -83.424408, 36.706797 ], "pop" : 115, "state" : "KY" }
+{ "_id" : "40965", "city" : "MIDDLESBORO", "loc" : [ -83.723079, 36.617188 ], "pop" : 14900, "state" : "KY" }
+{ "_id" : "40970", "city" : "MILLS", "loc" : [ -83.605305, 36.940659 ], "pop" : 471, "state" : "KY" }
+{ "_id" : "40972", "city" : "ONEIDA", "loc" : [ -83.655467, 37.2677 ], "pop" : 2371, "state" : "KY" }
+{ "_id" : "40977", "city" : "CALLAWAY", "loc" : [ -83.698502, 36.751302 ], "pop" : 7658, "state" : "KY" }
+{ "_id" : "40979", "city" : "ROARK", "loc" : [ -83.506201, 37.024432 ], "pop" : 463, "state" : "KY" }
+{ "_id" : "40982", "city" : "SCALF", "loc" : [ -83.72655399999999, 36.91748 ], "pop" : 600, "state" : "KY" }
+{ "_id" : "40983", "city" : "SEXTONS CREEK", "loc" : [ -83.798378, 37.27334 ], "pop" : 1776, "state" : "KY" }
+{ "_id" : "40988", "city" : "STONEY FORK", "loc" : [ -83.538504, 36.889184 ], "pop" : 387, "state" : "KY" }
+{ "_id" : "40995", "city" : "TROSPER", "loc" : [ -83.831442, 36.782564 ], "pop" : 1245, "state" : "KY" }
+{ "_id" : "40997", "city" : "WALKER", "loc" : [ -83.66160000000001, 36.891138 ], "pop" : 120, "state" : "KY" }
+{ "_id" : "40999", "city" : "WOOLLUM", "loc" : [ -83.847202, 37.009657 ], "pop" : 219, "state" : "KY" }
+{ "_id" : "41001", "city" : "ALEXANDRIA", "loc" : [ -84.394329, 38.940605 ], "pop" : 11858, "state" : "KY" }
+{ "_id" : "41002", "city" : "AUGUSTA", "loc" : [ -83.995352, 38.762991 ], "pop" : 1902, "state" : "KY" }
+{ "_id" : "41003", "city" : "BERRY", "loc" : [ -84.361118, 38.515974 ], "pop" : 2083, "state" : "KY" }
+{ "_id" : "41004", "city" : "BROOKSVILLE", "loc" : [ -84.078649, 38.664387 ], "pop" : 4309, "state" : "KY" }
+{ "_id" : "41005", "city" : "RABBIT HASH", "loc" : [ -84.74142000000001, 39.032411 ], "pop" : 8322, "state" : "KY" }
+{ "_id" : "41006", "city" : "BUTLER", "loc" : [ -84.34457999999999, 38.801328 ], "pop" : 4743, "state" : "KY" }
+{ "_id" : "41007", "city" : "CALIFORNIA", "loc" : [ -84.309794, 38.900614 ], "pop" : 3427, "state" : "KY" }
+{ "_id" : "41008", "city" : "CARROLLTON", "loc" : [ -85.173036, 38.669565 ], "pop" : 7072, "state" : "KY" }
+{ "_id" : "41010", "city" : "CORINTH", "loc" : [ -84.584596, 38.53021 ], "pop" : 1701, "state" : "KY" }
+{ "_id" : "41011", "city" : "COVINGTON", "loc" : [ -84.52121, 39.070839 ], "pop" : 29098, "state" : "KY" }
+{ "_id" : "41014", "city" : "ROUSE", "loc" : [ -84.505061, 39.066593 ], "pop" : 8607, "state" : "KY" }
+{ "_id" : "41015", "city" : "LATONIA", "loc" : [ -84.498858, 39.021686 ], "pop" : 19857, "state" : "KY" }
+{ "_id" : "41016", "city" : "LUDLOW", "loc" : [ -84.548304, 39.088946 ], "pop" : 7210, "state" : "KY" }
+{ "_id" : "41017", "city" : "DIXIE", "loc" : [ -84.56961099999999, 39.032378 ], "pop" : 34285, "state" : "KY" }
+{ "_id" : "41018", "city" : "ERLANGER", "loc" : [ -84.597745, 39.008238 ], "pop" : 23909, "state" : "KY" }
+{ "_id" : "41030", "city" : "CRITTENDEN", "loc" : [ -84.598202, 38.774107 ], "pop" : 2630, "state" : "KY" }
+{ "_id" : "41031", "city" : "CYNTHIANA", "loc" : [ -84.294921, 38.396403 ], "pop" : 13375, "state" : "KY" }
+{ "_id" : "41033", "city" : "DEMOSSVILLE", "loc" : [ -84.47080200000001, 38.75165 ], "pop" : 1292, "state" : "KY" }
+{ "_id" : "41034", "city" : "DOVER", "loc" : [ -83.871793, 38.691016 ], "pop" : 1991, "state" : "KY" }
+{ "_id" : "41035", "city" : "DRY RIDGE", "loc" : [ -84.62373599999999, 38.704854 ], "pop" : 6092, "state" : "KY" }
+{ "_id" : "41039", "city" : "EWING", "loc" : [ -83.873317, 38.415651 ], "pop" : 2396, "state" : "KY" }
+{ "_id" : "41040", "city" : "FALMOUTH", "loc" : [ -84.345124, 38.664304 ], "pop" : 6779, "state" : "KY" }
+{ "_id" : "41041", "city" : "FLEMINGSBURG", "loc" : [ -83.70796799999999, 38.427983 ], "pop" : 6549, "state" : "KY" }
+{ "_id" : "41042", "city" : "FLORENCE", "loc" : [ -84.64196099999999, 38.994065 ], "pop" : 34010, "state" : "KY" }
+{ "_id" : "41043", "city" : "FOSTER", "loc" : [ -84.156593, 38.75064 ], "pop" : 1479, "state" : "KY" }
+{ "_id" : "41044", "city" : "GERMANTOWN", "loc" : [ -83.960616, 38.707534 ], "pop" : 88, "state" : "KY" }
+{ "_id" : "41045", "city" : "GHENT", "loc" : [ -85.055662, 38.718823 ], "pop" : 980, "state" : "KY" }
+{ "_id" : "41046", "city" : "GLENCOE", "loc" : [ -84.81155200000001, 38.722946 ], "pop" : 589, "state" : "KY" }
+{ "_id" : "41048", "city" : "HEBRON", "loc" : [ -84.700745, 39.07553 ], "pop" : 3497, "state" : "KY" }
+{ "_id" : "41049", "city" : "HILLSBORO", "loc" : [ -83.66967, 38.29294 ], "pop" : 1981, "state" : "KY" }
+{ "_id" : "41051", "city" : "INDEPENDENCE", "loc" : [ -84.547912, 38.935407 ], "pop" : 12778, "state" : "KY" }
+{ "_id" : "41052", "city" : "JONESVILLE", "loc" : [ -84.76367, 38.648251 ], "pop" : 295, "state" : "KY" }
+{ "_id" : "41055", "city" : "MAYS LICK", "loc" : [ -83.87487400000001, 38.52692 ], "pop" : 1786, "state" : "KY" }
+{ "_id" : "41056", "city" : "LIMESTONE SQ", "loc" : [ -83.758858, 38.619716 ], "pop" : 12889, "state" : "KY" }
+{ "_id" : "41059", "city" : "MELBOURNE", "loc" : [ -84.353751, 39.006699 ], "pop" : 2688, "state" : "KY" }
+{ "_id" : "41063", "city" : "MORNING VIEW", "loc" : [ -84.506918, 38.83942 ], "pop" : 3938, "state" : "KY" }
+{ "_id" : "41064", "city" : "MOUNT OLIVET", "loc" : [ -84.047977, 38.521751 ], "pop" : 2124, "state" : "KY" }
+{ "_id" : "41071", "city" : "SOUTHGATE", "loc" : [ -84.48651099999999, 39.082847 ], "pop" : 22918, "state" : "KY" }
+{ "_id" : "41073", "city" : "BELLEVUE", "loc" : [ -84.478746, 39.102431 ], "pop" : 6997, "state" : "KY" }
+{ "_id" : "41074", "city" : "DAYTON", "loc" : [ -84.471155, 39.111428 ], "pop" : 6576, "state" : "KY" }
+{ "_id" : "41075", "city" : "FORT THOMAS", "loc" : [ -84.45234000000001, 39.078634 ], "pop" : 16165, "state" : "KY" }
+{ "_id" : "41076", "city" : "NEWPORT", "loc" : [ -84.440792, 39.026184 ], "pop" : 11237, "state" : "KY" }
+{ "_id" : "41080", "city" : "PETERSBURG", "loc" : [ -84.837104, 39.041561 ], "pop" : 1219, "state" : "KY" }
+{ "_id" : "41083", "city" : "SANDERS", "loc" : [ -84.973151, 38.661004 ], "pop" : 516, "state" : "KY" }
+{ "_id" : "41085", "city" : "SILVER GROVE", "loc" : [ -84.390849, 39.034262 ], "pop" : 1210, "state" : "KY" }
+{ "_id" : "41086", "city" : "SPARTA", "loc" : [ -84.881334, 38.725582 ], "pop" : 1186, "state" : "KY" }
+{ "_id" : "41091", "city" : "UNION", "loc" : [ -84.72735900000001, 38.943511 ], "pop" : 4468, "state" : "KY" }
+{ "_id" : "41092", "city" : "VERONA", "loc" : [ -84.69072199999999, 38.839012 ], "pop" : 2169, "state" : "KY" }
+{ "_id" : "41093", "city" : "WALLINGFORD", "loc" : [ -83.562532, 38.337449 ], "pop" : 1366, "state" : "KY" }
+{ "_id" : "41094", "city" : "WALTON", "loc" : [ -84.63276999999999, 38.887491 ], "pop" : 6253, "state" : "KY" }
+{ "_id" : "41095", "city" : "WARSAW", "loc" : [ -84.84958399999999, 38.780704 ], "pop" : 3618, "state" : "KY" }
+{ "_id" : "41097", "city" : "WILLIAMSTOWN", "loc" : [ -84.57441, 38.629191 ], "pop" : 5019, "state" : "KY" }
+{ "_id" : "41098", "city" : "WORTHVILLE", "loc" : [ -85.066321, 38.617948 ], "pop" : 724, "state" : "KY" }
+{ "_id" : "41101", "city" : "WESTWOOD", "loc" : [ -82.702709, 38.443038 ], "pop" : 17464, "state" : "KY" }
+{ "_id" : "41102", "city" : "ASHLAND", "loc" : [ -82.644721, 38.461255 ], "pop" : 24865, "state" : "KY" }
+{ "_id" : "41121", "city" : "ARGILLITE", "loc" : [ -82.809442, 38.432228 ], "pop" : 467, "state" : "KY" }
+{ "_id" : "41124", "city" : "BLAINE", "loc" : [ -82.851347, 38.026974 ], "pop" : 982, "state" : "KY" }
+{ "_id" : "41127", "city" : "CAMP DIX", "loc" : [ -83.28779299999999, 38.508044 ], "pop" : 269, "state" : "KY" }
+{ "_id" : "41129", "city" : "CATLETTSBURG", "loc" : [ -82.632065, 38.379946 ], "pop" : 8851, "state" : "KY" }
+{ "_id" : "41132", "city" : "DENTON", "loc" : [ -82.82692400000001, 38.295212 ], "pop" : 452, "state" : "KY" }
+{ "_id" : "41135", "city" : "HEAD OF GRASSY", "loc" : [ -83.261786, 38.367225 ], "pop" : 435, "state" : "KY" }
+{ "_id" : "41137", "city" : "FIREBRICK", "loc" : [ -83.04320300000001, 38.687785 ], "pop" : 279, "state" : "KY" }
+{ "_id" : "41139", "city" : "FLATWOODS", "loc" : [ -82.72122, 38.518776 ], "pop" : 8397, "state" : "KY" }
+{ "_id" : "41141", "city" : "GARRISON", "loc" : [ -83.200036, 38.586915 ], "pop" : 3066, "state" : "KY" }
+{ "_id" : "41143", "city" : "FULTZ", "loc" : [ -82.965087, 38.328037 ], "pop" : 11771, "state" : "KY" }
+{ "_id" : "41144", "city" : "LYNN", "loc" : [ -82.868396, 38.547969 ], "pop" : 11666, "state" : "KY" }
+{ "_id" : "41146", "city" : "HITCHINS", "loc" : [ -82.92026799999999, 38.254585 ], "pop" : 3187, "state" : "KY" }
+{ "_id" : "41149", "city" : "ISONVILLE", "loc" : [ -83.050607, 38.046229 ], "pop" : 890, "state" : "KY" }
+{ "_id" : "41159", "city" : "MARTHA", "loc" : [ -82.95576, 38.015228 ], "pop" : 706, "state" : "KY" }
+{ "_id" : "41163", "city" : "OLDTOWN", "loc" : [ -82.95695000000001, 38.441153 ], "pop" : 690, "state" : "KY" }
+{ "_id" : "41164", "city" : "LAWTON", "loc" : [ -83.16898500000001, 38.336275 ], "pop" : 5763, "state" : "KY" }
+{ "_id" : "41166", "city" : "QUINCY", "loc" : [ -83.105647, 38.627059 ], "pop" : 512, "state" : "KY" }
+{ "_id" : "41168", "city" : "RUSH", "loc" : [ -82.747602, 38.30893 ], "pop" : 1502, "state" : "KY" }
+{ "_id" : "41169", "city" : "RACELAND", "loc" : [ -82.715632, 38.522575 ], "pop" : 6469, "state" : "KY" }
+{ "_id" : "41170", "city" : "SAINT PAUL", "loc" : [ -83.067931, 38.665445 ], "pop" : 222, "state" : "KY" }
+{ "_id" : "41171", "city" : "BURKE", "loc" : [ -83.12725, 38.129368 ], "pop" : 5319, "state" : "KY" }
+{ "_id" : "41174", "city" : "SOUTH PORTSMOUTH", "loc" : [ -83.01621799999999, 38.708706 ], "pop" : 813, "state" : "KY" }
+{ "_id" : "41175", "city" : "MALONETON", "loc" : [ -82.94637299999999, 38.709269 ], "pop" : 4923, "state" : "KY" }
+{ "_id" : "41177", "city" : "STEPHENS", "loc" : [ -82.983689, 38.114625 ], "pop" : 261, "state" : "KY" }
+{ "_id" : "41179", "city" : "TRINITY", "loc" : [ -83.355448, 38.551511 ], "pop" : 5141, "state" : "KY" }
+{ "_id" : "41180", "city" : "WEBBVILLE", "loc" : [ -82.789743, 38.163377 ], "pop" : 1654, "state" : "KY" }
+{ "_id" : "41183", "city" : "WORTHINGTON", "loc" : [ -82.739553, 38.551102 ], "pop" : 1829, "state" : "KY" }
+{ "_id" : "41189", "city" : "TOLLESBORO", "loc" : [ -83.560458, 38.572332 ], "pop" : 3061, "state" : "KY" }
+{ "_id" : "41201", "city" : "ADAMS", "loc" : [ -82.702437, 37.991375 ], "pop" : 2540, "state" : "KY" }
+{ "_id" : "41204", "city" : "BOONS CAMP", "loc" : [ -82.67043, 37.821609 ], "pop" : 260, "state" : "KY" }
+{ "_id" : "41214", "city" : "DAVELLA", "loc" : [ -82.58672900000001, 37.790019 ], "pop" : 766, "state" : "KY" }
+{ "_id" : "41215", "city" : "DENVER", "loc" : [ -82.86304800000001, 37.796582 ], "pop" : 573, "state" : "KY" }
+{ "_id" : "41216", "city" : "EAST POINT", "loc" : [ -82.828801, 37.708578 ], "pop" : 1014, "state" : "KY" }
+{ "_id" : "41219", "city" : "ELNA", "loc" : [ -82.882825, 37.938594 ], "pop" : 766, "state" : "KY" }
+{ "_id" : "41220", "city" : "FUGET", "loc" : [ -82.911422, 37.902164 ], "pop" : 285, "state" : "KY" }
+{ "_id" : "41222", "city" : "HAGERHILL", "loc" : [ -82.81491, 37.803511 ], "pop" : 739, "state" : "KY" }
+{ "_id" : "41224", "city" : "JOB", "loc" : [ -82.520421, 37.867149 ], "pop" : 4231, "state" : "KY" }
+{ "_id" : "41226", "city" : "KEATON", "loc" : [ -82.95610499999999, 37.968049 ], "pop" : 354, "state" : "KY" }
+{ "_id" : "41228", "city" : "LEANDER", "loc" : [ -82.831045, 37.761904 ], "pop" : 1037, "state" : "KY" }
+{ "_id" : "41230", "city" : "CLIFFORD", "loc" : [ -82.617598, 38.094332 ], "pop" : 8123, "state" : "KY" }
+{ "_id" : "41231", "city" : "LOVELY", "loc" : [ -82.363794, 37.792109 ], "pop" : 958, "state" : "KY" }
+{ "_id" : "41234", "city" : "MEALLY", "loc" : [ -82.74417699999999, 37.796498 ], "pop" : 925, "state" : "KY" }
+{ "_id" : "41237", "city" : "OFFUTT", "loc" : [ -82.70812599999999, 37.852766 ], "pop" : 462, "state" : "KY" }
+{ "_id" : "41238", "city" : "MANILA", "loc" : [ -82.928079, 37.826409 ], "pop" : 1430, "state" : "KY" }
+{ "_id" : "41240", "city" : "NIPPA", "loc" : [ -82.805162, 37.819293 ], "pop" : 4095, "state" : "KY" }
+{ "_id" : "41250", "city" : "LAURA", "loc" : [ -82.44875399999999, 37.763752 ], "pop" : 1700, "state" : "KY" }
+{ "_id" : "41254", "city" : "RIVER", "loc" : [ -82.67094400000001, 37.875063 ], "pop" : 169, "state" : "KY" }
+{ "_id" : "41255", "city" : "SITKA", "loc" : [ -82.844554, 37.892187 ], "pop" : 598, "state" : "KY" }
+{ "_id" : "41256", "city" : "BARNETTS CREEK", "loc" : [ -82.85742999999999, 37.838463 ], "pop" : 1267, "state" : "KY" }
+{ "_id" : "41257", "city" : "STAMBAUGH", "loc" : [ -82.76779000000001, 37.84112 ], "pop" : 165, "state" : "KY" }
+{ "_id" : "41258", "city" : "RICEVILLE", "loc" : [ -82.911269, 37.743408 ], "pop" : 816, "state" : "KY" }
+{ "_id" : "41260", "city" : "THELMA", "loc" : [ -82.775532, 37.798745 ], "pop" : 3956, "state" : "KY" }
+{ "_id" : "41262", "city" : "DAVISPORT", "loc" : [ -82.59926900000001, 37.879292 ], "pop" : 1923, "state" : "KY" }
+{ "_id" : "41263", "city" : "TUTOR KEY", "loc" : [ -82.735106, 37.860527 ], "pop" : 33, "state" : "KY" }
+{ "_id" : "41265", "city" : "VAN LEAR", "loc" : [ -82.703236, 37.692916 ], "pop" : 3387, "state" : "KY" }
+{ "_id" : "41266", "city" : "FUGET", "loc" : [ -82.911224, 37.902927 ], "pop" : 764, "state" : "KY" }
+{ "_id" : "41267", "city" : "HODE", "loc" : [ -82.432192, 37.858088 ], "pop" : 2656, "state" : "KY" }
+{ "_id" : "41269", "city" : "WHITEHOUSE", "loc" : [ -82.775328, 37.895347 ], "pop" : 2105, "state" : "KY" }
+{ "_id" : "41271", "city" : "WILLIAMSPORT", "loc" : [ -82.710455, 37.81416 ], "pop" : 295, "state" : "KY" }
+{ "_id" : "41274", "city" : "WITTENSVILLE", "loc" : [ -82.80998700000001, 37.870297 ], "pop" : 689, "state" : "KY" }
+{ "_id" : "41301", "city" : "FLAT", "loc" : [ -83.516395, 37.750243 ], "pop" : 5038, "state" : "KY" }
+{ "_id" : "41306", "city" : "ALTRO", "loc" : [ -83.395749, 37.356346 ], "pop" : 436, "state" : "KY" }
+{ "_id" : "41311", "city" : "VADA", "loc" : [ -83.702337, 37.581891 ], "pop" : 6877, "state" : "KY" }
+{ "_id" : "41314", "city" : "MORRIS FORK", "loc" : [ -83.660624, 37.478717 ], "pop" : 2675, "state" : "KY" }
+{ "_id" : "41315", "city" : "BURKHART", "loc" : [ -83.27339600000001, 37.687451 ], "pop" : 233, "state" : "KY" }
+{ "_id" : "41317", "city" : "CLAYHOLE", "loc" : [ -83.281254, 37.466076 ], "pop" : 2294, "state" : "KY" }
+{ "_id" : "41321", "city" : "DECOY", "loc" : [ -83.02895599999999, 37.49046 ], "pop" : 184, "state" : "KY" }
+{ "_id" : "41327", "city" : "GILLMORE", "loc" : [ -83.348026, 37.697155 ], "pop" : 44, "state" : "KY" }
+{ "_id" : "41328", "city" : "GREEN HALL", "loc" : [ -83.780693, 37.368938 ], "pop" : 185, "state" : "KY" }
+{ "_id" : "41331", "city" : "HADDIX", "loc" : [ -83.376176, 37.492249 ], "pop" : 513, "state" : "KY" }
+{ "_id" : "41332", "city" : "GRASSY CREEK", "loc" : [ -83.39891799999999, 37.775989 ], "pop" : 978, "state" : "KY" }
+{ "_id" : "41338", "city" : "ISLAND CITY", "loc" : [ -83.717991, 37.389926 ], "pop" : 526, "state" : "KY" }
+{ "_id" : "41339", "city" : "CANOE", "loc" : [ -83.39690400000001, 37.557378 ], "pop" : 6384, "state" : "KY" }
+{ "_id" : "41340", "city" : "LAMBRIC", "loc" : [ -83.100888, 37.579455 ], "pop" : 14, "state" : "KY" }
+{ "_id" : "41342", "city" : "LEE CITY", "loc" : [ -83.325474, 37.731163 ], "pop" : 233, "state" : "KY" }
+{ "_id" : "41343", "city" : "LEECO", "loc" : [ -83.692806, 37.698933 ], "pop" : 66, "state" : "KY" }
+{ "_id" : "41346", "city" : "LITTLE", "loc" : [ -83.382373, 37.432158 ], "pop" : 247, "state" : "KY" }
+{ "_id" : "41348", "city" : "HARDSHELL", "loc" : [ -83.328889, 37.484106 ], "pop" : 375, "state" : "KY" }
+{ "_id" : "41351", "city" : "MISTLETOE", "loc" : [ -83.588078, 37.331428 ], "pop" : 72, "state" : "KY" }
+{ "_id" : "41357", "city" : "NOCTOR", "loc" : [ -83.270831, 37.569915 ], "pop" : 771, "state" : "KY" }
+{ "_id" : "41358", "city" : "OLD LANDING", "loc" : [ -83.805784, 37.639678 ], "pop" : 253, "state" : "KY" }
+{ "_id" : "41360", "city" : "PINE RIDGE", "loc" : [ -83.632059, 37.774872 ], "pop" : 334, "state" : "KY" }
+{ "_id" : "41363", "city" : "QUICKSAND", "loc" : [ -83.365098, 37.532947 ], "pop" : 727, "state" : "KY" }
+{ "_id" : "41364", "city" : "RICETOWN", "loc" : [ -83.61506199999999, 37.409305 ], "pop" : 672, "state" : "KY" }
+{ "_id" : "41365", "city" : "ROGERS", "loc" : [ -83.65667000000001, 37.739538 ], "pop" : 288, "state" : "KY" }
+{ "_id" : "41366", "city" : "ROUSSEAU", "loc" : [ -83.21472, 37.63491 ], "pop" : 104, "state" : "KY" }
+{ "_id" : "41367", "city" : "ROWDY", "loc" : [ -83.20403, 37.413063 ], "pop" : 245, "state" : "KY" }
+{ "_id" : "41369", "city" : "SALDEE", "loc" : [ -83.373268, 37.455799 ], "pop" : 118, "state" : "KY" }
+{ "_id" : "41377", "city" : "TALBERT", "loc" : [ -83.448185, 37.399505 ], "pop" : 352, "state" : "KY" }
+{ "_id" : "41385", "city" : "VANCLEVE", "loc" : [ -83.38055300000001, 37.64768 ], "pop" : 1335, "state" : "KY" }
+{ "_id" : "41386", "city" : "VINCENT", "loc" : [ -83.784628, 37.443733 ], "pop" : 586, "state" : "KY" }
+{ "_id" : "41390", "city" : "WHICK", "loc" : [ -83.374707, 37.41022 ], "pop" : 235, "state" : "KY" }
+{ "_id" : "41396", "city" : "ZACHARIAH", "loc" : [ -83.677244, 37.674917 ], "pop" : 36, "state" : "KY" }
+{ "_id" : "41397", "city" : "ZOE", "loc" : [ -83.668778, 37.666371 ], "pop" : 190, "state" : "KY" }
+{ "_id" : "41407", "city" : "CANEY", "loc" : [ -83.291662, 37.809847 ], "pop" : 1754, "state" : "KY" }
+{ "_id" : "41409", "city" : "CARVER", "loc" : [ -83.06900899999999, 37.650274 ], "pop" : 368, "state" : "KY" }
+{ "_id" : "41412", "city" : "COTTLE", "loc" : [ -83.220078, 37.892975 ], "pop" : 73, "state" : "KY" }
+{ "_id" : "41419", "city" : "EDNA", "loc" : [ -83.179973, 37.799813 ], "pop" : 312, "state" : "KY" }
+{ "_id" : "41421", "city" : "ELKFORK", "loc" : [ -83.077112, 37.940358 ], "pop" : 2081, "state" : "KY" }
+{ "_id" : "41422", "city" : "ELSIE", "loc" : [ -83.142321, 37.768875 ], "pop" : 84, "state" : "KY" }
+{ "_id" : "41425", "city" : "EZEL", "loc" : [ -83.388835, 37.903985 ], "pop" : 1488, "state" : "KY" }
+{ "_id" : "41441", "city" : "HENDRICKS", "loc" : [ -83.098108, 37.70505 ], "pop" : 377, "state" : "KY" }
+{ "_id" : "41447", "city" : "LENOX", "loc" : [ -83.18159300000001, 37.967224 ], "pop" : 550, "state" : "KY" }
+{ "_id" : "41464", "city" : "ROYALTON", "loc" : [ -82.98666900000001, 37.652116 ], "pop" : 1550, "state" : "KY" }
+{ "_id" : "41465", "city" : "BETHANNA", "loc" : [ -83.055443, 37.763499 ], "pop" : 8442, "state" : "KY" }
+{ "_id" : "41466", "city" : "SEITZ", "loc" : [ -83.174941, 37.668402 ], "pop" : 395, "state" : "KY" }
+{ "_id" : "41472", "city" : "BLAIRS MILL", "loc" : [ -83.279926, 37.949746 ], "pop" : 4700, "state" : "KY" }
+{ "_id" : "41474", "city" : "WHITE OAK", "loc" : [ -83.204869, 37.849769 ], "pop" : 361, "state" : "KY" }
+{ "_id" : "41501", "city" : "BROAD BOTTOM", "loc" : [ -82.52017499999999, 37.506833 ], "pop" : 17362, "state" : "KY" }
+{ "_id" : "41503", "city" : "SOUTH WILLIAMSON", "loc" : [ -82.288608, 37.666991 ], "pop" : 899, "state" : "KY" }
+{ "_id" : "41512", "city" : "ASHCAMP", "loc" : [ -82.461269, 37.258909 ], "pop" : 2274, "state" : "KY" }
+{ "_id" : "41513", "city" : "BELCHER", "loc" : [ -82.396536, 37.3137 ], "pop" : 111, "state" : "KY" }
+{ "_id" : "41514", "city" : "BELFRY", "loc" : [ -82.257301, 37.64011 ], "pop" : 1744, "state" : "KY" }
+{ "_id" : "41519", "city" : "CANADA", "loc" : [ -82.35330999999999, 37.637816 ], "pop" : 817, "state" : "KY" }
+{ "_id" : "41522", "city" : "SENTERVILLE", "loc" : [ -82.353337, 37.302649 ], "pop" : 1988, "state" : "KY" }
+{ "_id" : "41524", "city" : "BIGGS", "loc" : [ -82.25746599999999, 37.361002 ], "pop" : 724, "state" : "KY" }
+{ "_id" : "41527", "city" : "FOREST HILLS", "loc" : [ -82.299145, 37.643238 ], "pop" : 363, "state" : "KY" }
+{ "_id" : "41528", "city" : "FREEBURN", "loc" : [ -82.143378, 37.551188 ], "pop" : 1749, "state" : "KY" }
+{ "_id" : "41529", "city" : "AFLEX", "loc" : [ -82.30796100000001, 37.689943 ], "pop" : 802, "state" : "KY" }
+{ "_id" : "41531", "city" : "HARDY", "loc" : [ -82.255236, 37.602652 ], "pop" : 1693, "state" : "KY" }
+{ "_id" : "41535", "city" : "HUDDY", "loc" : [ -82.25004, 37.566819 ], "pop" : 513, "state" : "KY" }
+{ "_id" : "41536", "city" : "JAMBOREE", "loc" : [ -82.089129, 37.485976 ], "pop" : 848, "state" : "KY" }
+{ "_id" : "41537", "city" : "PAYNE GAP", "loc" : [ -82.630045, 37.186328 ], "pop" : 3615, "state" : "KY" }
+{ "_id" : "41539", "city" : "KIMPER", "loc" : [ -82.31804099999999, 37.469588 ], "pop" : 2317, "state" : "KY" }
+{ "_id" : "41540", "city" : "LICK CREEK", "loc" : [ -82.325456, 37.347969 ], "pop" : 221, "state" : "KY" }
+{ "_id" : "41543", "city" : "MC ANDREWS", "loc" : [ -82.25579999999999, 37.544986 ], "pop" : 830, "state" : "KY" }
+{ "_id" : "41544", "city" : "MC CARR", "loc" : [ -82.167365, 37.596944 ], "pop" : 1054, "state" : "KY" }
+{ "_id" : "41545", "city" : "MC COMBS", "loc" : [ -82.54822799999999, 37.593432 ], "pop" : 173, "state" : "KY" }
+{ "_id" : "41546", "city" : "MC VEIGH", "loc" : [ -82.22280000000001, 37.534249 ], "pop" : 603, "state" : "KY" }
+{ "_id" : "41548", "city" : "MOUTHCARD", "loc" : [ -82.305424, 37.333908 ], "pop" : 156, "state" : "KY" }
+{ "_id" : "41551", "city" : "PAW PAW", "loc" : [ -82.134942, 37.435562 ], "pop" : 228, "state" : "KY" }
+{ "_id" : "41553", "city" : "PHELPS", "loc" : [ -82.158378, 37.498736 ], "pop" : 2947, "state" : "KY" }
+{ "_id" : "41554", "city" : "PHYLLIS", "loc" : [ -82.266786, 37.422152 ], "pop" : 891, "state" : "KY" }
+{ "_id" : "41555", "city" : "PINSONFORK", "loc" : [ -82.19536600000001, 37.565137 ], "pop" : 568, "state" : "KY" }
+{ "_id" : "41557", "city" : "FISHTRAP", "loc" : [ -82.426256, 37.524072 ], "pop" : 3807, "state" : "KY" }
+{ "_id" : "41559", "city" : "REGINA", "loc" : [ -82.37369700000001, 37.359686 ], "pop" : 1559, "state" : "KY" }
+{ "_id" : "41560", "city" : "ROBINSON CREEK", "loc" : [ -82.567679, 37.334708 ], "pop" : 6715, "state" : "KY" }
+{ "_id" : "41562", "city" : "SHELBIANA", "loc" : [ -82.455321, 37.375478 ], "pop" : 9187, "state" : "KY" }
+{ "_id" : "41563", "city" : "SHELBY GAP", "loc" : [ -82.575149, 37.232743 ], "pop" : 952, "state" : "KY" }
+{ "_id" : "41564", "city" : "SIDNEY", "loc" : [ -82.338666, 37.580225 ], "pop" : 1727, "state" : "KY" }
+{ "_id" : "41565", "city" : "SPEIGHT", "loc" : [ -82.71650200000001, 37.262473 ], "pop" : 17, "state" : "KY" }
+{ "_id" : "41566", "city" : "STEELE", "loc" : [ -82.20707899999999, 37.40292 ], "pop" : 1321, "state" : "KY" }
+{ "_id" : "41567", "city" : "STONE", "loc" : [ -82.28898700000001, 37.560639 ], "pop" : 1239, "state" : "KY" }
+{ "_id" : "41568", "city" : "ARGO", "loc" : [ -82.073522, 37.530336 ], "pop" : 471, "state" : "KY" }
+{ "_id" : "41570", "city" : "TURKEY CREEK", "loc" : [ -82.32022499999999, 37.659347 ], "pop" : 264, "state" : "KY" }
+{ "_id" : "41571", "city" : "VARNEY", "loc" : [ -82.350976, 37.698541 ], "pop" : 827, "state" : "KY" }
+{ "_id" : "41572", "city" : "ETTY", "loc" : [ -82.649445, 37.313669 ], "pop" : 2622, "state" : "KY" }
+{ "_id" : "41601", "city" : "ALLEN", "loc" : [ -82.63627200000001, 37.566182 ], "pop" : 1768, "state" : "KY" }
+{ "_id" : "41602", "city" : "AUXIER", "loc" : [ -82.767736, 37.721847 ], "pop" : 2461, "state" : "KY" }
+{ "_id" : "41603", "city" : "BANNER", "loc" : [ -82.69736899999999, 37.577051 ], "pop" : 1043, "state" : "KY" }
+{ "_id" : "41604", "city" : "LIGON", "loc" : [ -82.680295, 37.372179 ], "pop" : 956, "state" : "KY" }
+{ "_id" : "41605", "city" : "BETSY LAYNE", "loc" : [ -82.700249, 37.531593 ], "pop" : 353, "state" : "KY" }
+{ "_id" : "41606", "city" : "BEVINSVILLE", "loc" : [ -82.712468, 37.338488 ], "pop" : 3200, "state" : "KY" }
+{ "_id" : "41607", "city" : "BLUE RIVER", "loc" : [ -82.827361, 37.648097 ], "pop" : 247, "state" : "KY" }
+{ "_id" : "41614", "city" : "CRAYNOR", "loc" : [ -82.69176, 37.408673 ], "pop" : 260, "state" : "KY" }
+{ "_id" : "41615", "city" : "DANA", "loc" : [ -82.670501, 37.546653 ], "pop" : 227, "state" : "KY" }
+{ "_id" : "41616", "city" : "DAVID", "loc" : [ -82.892748, 37.604387 ], "pop" : 60, "state" : "KY" }
+{ "_id" : "41622", "city" : "EASTERN", "loc" : [ -82.82649600000001, 37.532386 ], "pop" : 509, "state" : "KY" }
+{ "_id" : "41626", "city" : "ENDICOTT", "loc" : [ -82.627608, 37.681936 ], "pop" : 42, "state" : "KY" }
+{ "_id" : "41627", "city" : "ESTILL", "loc" : [ -82.81962900000001, 37.46201 ], "pop" : 263, "state" : "KY" }
+{ "_id" : "41629", "city" : "GALVESTON", "loc" : [ -82.661868, 37.478249 ], "pop" : 1030, "state" : "KY" }
+{ "_id" : "41630", "city" : "GARRETT", "loc" : [ -82.846192, 37.486126 ], "pop" : 1408, "state" : "KY" }
+{ "_id" : "41631", "city" : "GRETHEL", "loc" : [ -82.739575, 37.459599 ], "pop" : 2126, "state" : "KY" }
+{ "_id" : "41632", "city" : "WALDO", "loc" : [ -82.93574, 37.546661 ], "pop" : 699, "state" : "KY" }
+{ "_id" : "41633", "city" : "HALO", "loc" : [ -82.73060599999999, 37.307629 ], "pop" : 119, "state" : "KY" }
+{ "_id" : "41635", "city" : "HAROLD", "loc" : [ -82.621595, 37.504184 ], "pop" : 1286, "state" : "KY" }
+{ "_id" : "41636", "city" : "BUCKINGHAM", "loc" : [ -82.73245, 37.393499 ], "pop" : 879, "state" : "KY" }
+{ "_id" : "41637", "city" : "PYRMID", "loc" : [ -82.864919, 37.513484 ], "pop" : 568, "state" : "KY" }
+{ "_id" : "41639", "city" : "HONAKER", "loc" : [ -82.667534, 37.514977 ], "pop" : 772, "state" : "KY" }
+{ "_id" : "41640", "city" : "ELMROCK", "loc" : [ -82.836764, 37.506204 ], "pop" : 115, "state" : "KY" }
+{ "_id" : "41642", "city" : "IVEL", "loc" : [ -82.64268, 37.555443 ], "pop" : 1038, "state" : "KY" }
+{ "_id" : "41643", "city" : "LACKEY", "loc" : [ -82.798012, 37.464283 ], "pop" : 591, "state" : "KY" }
+{ "_id" : "41645", "city" : "LANGLEY", "loc" : [ -82.797648, 37.538079 ], "pop" : 648, "state" : "KY" }
+{ "_id" : "41647", "city" : "EAST MC DOWELL", "loc" : [ -82.745018, 37.425232 ], "pop" : 376, "state" : "KY" }
+{ "_id" : "41649", "city" : "HITE", "loc" : [ -82.74785199999999, 37.563267 ], "pop" : 4649, "state" : "KY" }
+{ "_id" : "41653", "city" : "EMMA", "loc" : [ -82.788135, 37.649462 ], "pop" : 9573, "state" : "KY" }
+{ "_id" : "41655", "city" : "PRINTER", "loc" : [ -82.70602700000001, 37.505485 ], "pop" : 243, "state" : "KY" }
+{ "_id" : "41659", "city" : "STANVILLE", "loc" : [ -82.669174, 37.578386 ], "pop" : 309, "state" : "KY" }
+{ "_id" : "41660", "city" : "TEABERRY", "loc" : [ -82.640456, 37.421955 ], "pop" : 2248, "state" : "KY" }
+{ "_id" : "41666", "city" : "WAYLAND", "loc" : [ -82.80103699999999, 37.436709 ], "pop" : 928, "state" : "KY" }
+{ "_id" : "41701", "city" : "DARFORK", "loc" : [ -83.199845, 37.252641 ], "pop" : 11851, "state" : "KY" }
+{ "_id" : "41712", "city" : "ARY", "loc" : [ -83.139253, 37.354364 ], "pop" : 331, "state" : "KY" }
+{ "_id" : "41714", "city" : "BEAR BRANCH", "loc" : [ -83.494449, 37.210894 ], "pop" : 400, "state" : "KY" }
+{ "_id" : "41719", "city" : "BLUE DIAMOND", "loc" : [ -83.228579, 37.310812 ], "pop" : 861, "state" : "KY" }
+{ "_id" : "41721", "city" : "BUCKHORN", "loc" : [ -83.49364799999999, 37.301036 ], "pop" : 640, "state" : "KY" }
+{ "_id" : "41722", "city" : "TRIBBEY", "loc" : [ -83.15848699999999, 37.328174 ], "pop" : 2312, "state" : "KY" }
+{ "_id" : "41723", "city" : "BUSY", "loc" : [ -83.30070499999999, 37.26316 ], "pop" : 967, "state" : "KY" }
+{ "_id" : "41725", "city" : "CARRIE", "loc" : [ -83.041549, 37.297995 ], "pop" : 457, "state" : "KY" }
+{ "_id" : "41727", "city" : "CHAVIES", "loc" : [ -83.33146600000001, 37.355545 ], "pop" : 564, "state" : "KY" }
+{ "_id" : "41728", "city" : "CINDA", "loc" : [ -83.302886, 37.09667 ], "pop" : 584, "state" : "KY" }
+{ "_id" : "41729", "city" : "COMBS", "loc" : [ -83.20229399999999, 37.291321 ], "pop" : 1001, "state" : "KY" }
+{ "_id" : "41730", "city" : "CONFLUENCE", "loc" : [ -83.37110199999999, 37.271904 ], "pop" : 184, "state" : "KY" }
+{ "_id" : "41731", "city" : "ULVAH", "loc" : [ -83.035127, 37.120385 ], "pop" : 1289, "state" : "KY" }
+{ "_id" : "41732", "city" : "CUTSHIN", "loc" : [ -83.247304, 37.108109 ], "pop" : 1591, "state" : "KY" }
+{ "_id" : "41733", "city" : "DAISY", "loc" : [ -83.095095, 37.115936 ], "pop" : 77, "state" : "KY" }
+{ "_id" : "41735", "city" : "DELPHIA", "loc" : [ -83.095574, 37.023317 ], "pop" : 349, "state" : "KY" }
+{ "_id" : "41736", "city" : "DICE", "loc" : [ -83.20533500000001, 37.382539 ], "pop" : 1251, "state" : "KY" }
+{ "_id" : "41740", "city" : "BEARVILLE", "loc" : [ -83.068449, 37.322096 ], "pop" : 1961, "state" : "KY" }
+{ "_id" : "41743", "city" : "FISTY", "loc" : [ -83.108251, 37.356348 ], "pop" : 172, "state" : "KY" }
+{ "_id" : "41745", "city" : "GAYS CREEK", "loc" : [ -83.455607, 37.350421 ], "pop" : 369, "state" : "KY" }
+{ "_id" : "41746", "city" : "HAPPY", "loc" : [ -83.081408, 37.195047 ], "pop" : 784, "state" : "KY" }
+{ "_id" : "41749", "city" : "DRYHILL", "loc" : [ -83.415668, 37.154604 ], "pop" : 5507, "state" : "KY" }
+{ "_id" : "41754", "city" : "NAPFOR", "loc" : [ -83.305913, 37.318325 ], "pop" : 2357, "state" : "KY" }
+{ "_id" : "41756", "city" : "LEATHERWOOD", "loc" : [ -83.15125399999999, 37.040503 ], "pop" : 241, "state" : "KY" }
+{ "_id" : "41759", "city" : "ANCO", "loc" : [ -83.03212499999999, 37.233926 ], "pop" : 1442, "state" : "KY" }
+{ "_id" : "41760", "city" : "SCUDDY", "loc" : [ -83.093242, 37.212182 ], "pop" : 296, "state" : "KY" }
+{ "_id" : "41763", "city" : "SLEMP", "loc" : [ -83.11694, 37.08037 ], "pop" : 1012, "state" : "KY" }
+{ "_id" : "41764", "city" : "SMILAX", "loc" : [ -83.284533, 37.166314 ], "pop" : 634, "state" : "KY" }
+{ "_id" : "41765", "city" : "TALCUM", "loc" : [ -83.047864, 37.383621 ], "pop" : 375, "state" : "KY" }
+{ "_id" : "41772", "city" : "VEST", "loc" : [ -83.06265, 37.408732 ], "pop" : 312, "state" : "KY" }
+{ "_id" : "41773", "city" : "VICCO", "loc" : [ -83.09979199999999, 37.189826 ], "pop" : 3072, "state" : "KY" }
+{ "_id" : "41774", "city" : "FARLER", "loc" : [ -83.158299, 37.150655 ], "pop" : 1364, "state" : "KY" }
+{ "_id" : "41775", "city" : "WENDOVER", "loc" : [ -83.350185, 37.129115 ], "pop" : 314, "state" : "KY" }
+{ "_id" : "41776", "city" : "FREW", "loc" : [ -83.292655, 37.192435 ], "pop" : 474, "state" : "KY" }
+{ "_id" : "41777", "city" : "BIG ROCK", "loc" : [ -83.227006, 37.043019 ], "pop" : 405, "state" : "KY" }
+{ "_id" : "41801", "city" : "AMBURGEY", "loc" : [ -83.000483, 37.26716 ], "pop" : 329, "state" : "KY" }
+{ "_id" : "41804", "city" : "CARCASSONNE", "loc" : [ -82.940189, 37.134266 ], "pop" : 552, "state" : "KY" }
+{ "_id" : "41805", "city" : "BRINKLEY", "loc" : [ -82.91397600000001, 37.262613 ], "pop" : 1204, "state" : "KY" }
+{ "_id" : "41811", "city" : "CROWN", "loc" : [ -82.847442, 37.159125 ], "pop" : 295, "state" : "KY" }
+{ "_id" : "41812", "city" : "DEANE", "loc" : [ -82.799722, 37.23332 ], "pop" : 1400, "state" : "KY" }
+{ "_id" : "41815", "city" : "ERMINE", "loc" : [ -82.822118, 37.174612 ], "pop" : 3231, "state" : "KY" }
+{ "_id" : "41817", "city" : "LARKSLANE", "loc" : [ -82.89384699999999, 37.377663 ], "pop" : 1287, "state" : "KY" }
+{ "_id" : "41819", "city" : "GILLY", "loc" : [ -83.069317, 36.990109 ], "pop" : 555, "state" : "KY" }
+{ "_id" : "41821", "city" : "SKYLINE", "loc" : [ -83.020354, 37.069879 ], "pop" : 426, "state" : "KY" }
+{ "_id" : "41822", "city" : "HINDMAN", "loc" : [ -82.952653, 37.327607 ], "pop" : 2965, "state" : "KY" }
+{ "_id" : "41823", "city" : "HOLLYBUSH", "loc" : [ -82.831509, 37.337608 ], "pop" : 380, "state" : "KY" }
+{ "_id" : "41824", "city" : "ISOM", "loc" : [ -82.913348, 37.196027 ], "pop" : 714, "state" : "KY" }
+{ "_id" : "41825", "city" : "JACKHORN", "loc" : [ -82.691856, 37.171685 ], "pop" : 1380, "state" : "KY" }
+{ "_id" : "41826", "city" : "JEREMIAH", "loc" : [ -82.92683599999999, 37.165127 ], "pop" : 623, "state" : "KY" }
+{ "_id" : "41828", "city" : "PUNCHEON", "loc" : [ -82.78472499999999, 37.270944 ], "pop" : 293, "state" : "KY" }
+{ "_id" : "41829", "city" : "KONA", "loc" : [ -82.752469, 37.166814 ], "pop" : 607, "state" : "KY" }
+{ "_id" : "41831", "city" : "SOFT SHELL", "loc" : [ -82.956428, 37.383737 ], "pop" : 765, "state" : "KY" }
+{ "_id" : "41832", "city" : "LETCHER", "loc" : [ -82.980908, 37.155 ], "pop" : 571, "state" : "KY" }
+{ "_id" : "41833", "city" : "LINEFORK", "loc" : [ -82.919765, 37.051399 ], "pop" : 860, "state" : "KY" }
+{ "_id" : "41834", "city" : "LITTCARR", "loc" : [ -82.965098, 37.271457 ], "pop" : 468, "state" : "KY" }
+{ "_id" : "41836", "city" : "MALLIE", "loc" : [ -82.871364, 37.334623 ], "pop" : 792, "state" : "KY" }
+{ "_id" : "41838", "city" : "MILLSTONE", "loc" : [ -82.7533, 37.151615 ], "pop" : 247, "state" : "KY" }
+{ "_id" : "41839", "city" : "MOUSIE", "loc" : [ -82.901768, 37.433125 ], "pop" : 795, "state" : "KY" }
+{ "_id" : "41840", "city" : "FLEMING NEON", "loc" : [ -82.69755499999999, 37.212056 ], "pop" : 2563, "state" : "KY" }
+{ "_id" : "41843", "city" : "OMAHA", "loc" : [ -82.830417, 37.311528 ], "pop" : 336, "state" : "KY" }
+{ "_id" : "41844", "city" : "RAVEN", "loc" : [ -82.82916400000001, 37.363252 ], "pop" : 197, "state" : "KY" }
+{ "_id" : "41845", "city" : "PREMIUM", "loc" : [ -82.95811500000001, 37.068587 ], "pop" : 311, "state" : "KY" }
+{ "_id" : "41847", "city" : "REDFOX", "loc" : [ -82.871865, 37.25311 ], "pop" : 974, "state" : "KY" }
+{ "_id" : "41848", "city" : "ROXANA", "loc" : [ -83.034488, 37.090502 ], "pop" : 117, "state" : "KY" }
+{ "_id" : "41849", "city" : "SECO", "loc" : [ -82.735832, 37.176523 ], "pop" : 791, "state" : "KY" }
+{ "_id" : "41855", "city" : "THORNTON", "loc" : [ -82.73820000000001, 37.129622 ], "pop" : 635, "state" : "KY" }
+{ "_id" : "41858", "city" : "DAY RURAL", "loc" : [ -82.838768, 37.115463 ], "pop" : 4678, "state" : "KY" }
+{ "_id" : "41859", "city" : "DEMA", "loc" : [ -82.852313, 37.421491 ], "pop" : 468, "state" : "KY" }
+{ "_id" : "41861", "city" : "RAVEN", "loc" : [ -82.826064, 37.404328 ], "pop" : 128, "state" : "KY" }
+{ "_id" : "41862", "city" : "DRY CREEK", "loc" : [ -82.781036, 37.346979 ], "pop" : 1605, "state" : "KY" }
+{ "_id" : "42001", "city" : "PADUCAH", "loc" : [ -88.66320399999999, 37.063377 ], "pop" : 27002, "state" : "KY" }
+{ "_id" : "42003", "city" : "PADUCAH", "loc" : [ -88.593388, 37.036833 ], "pop" : 29932, "state" : "KY" }
+{ "_id" : "42020", "city" : "ALMO", "loc" : [ -88.308666, 36.712805 ], "pop" : 1509, "state" : "KY" }
+{ "_id" : "42021", "city" : "ARLINGTON", "loc" : [ -88.94383500000001, 36.800117 ], "pop" : 1780, "state" : "KY" }
+{ "_id" : "42023", "city" : "BARDWELL", "loc" : [ -89.020855, 36.863387 ], "pop" : 1957, "state" : "KY" }
+{ "_id" : "42024", "city" : "BARLOW", "loc" : [ -89.04081499999999, 37.049279 ], "pop" : 1335, "state" : "KY" }
+{ "_id" : "42025", "city" : "BENTON", "loc" : [ -88.35477299999999, 36.880649 ], "pop" : 15886, "state" : "KY" }
+{ "_id" : "42027", "city" : "BOAZ", "loc" : [ -88.622288, 36.929974 ], "pop" : 1609, "state" : "KY" }
+{ "_id" : "42028", "city" : "BURNA", "loc" : [ -88.39418499999999, 37.231514 ], "pop" : 453, "state" : "KY" }
+{ "_id" : "42029", "city" : "CALVERT CITY", "loc" : [ -88.38111499999999, 37.014741 ], "pop" : 4479, "state" : "KY" }
+{ "_id" : "42031", "city" : "CLINTON", "loc" : [ -88.967574, 36.667531 ], "pop" : 4143, "state" : "KY" }
+{ "_id" : "42032", "city" : "COLUMBUS", "loc" : [ -89.098288, 36.755505 ], "pop" : 454, "state" : "KY" }
+{ "_id" : "42035", "city" : "CUNNINGHAM", "loc" : [ -88.872815, 36.896256 ], "pop" : 1501, "state" : "KY" }
+{ "_id" : "42036", "city" : "DEXTER", "loc" : [ -88.180695, 36.70313 ], "pop" : 1800, "state" : "KY" }
+{ "_id" : "42038", "city" : "EDDYVILLE", "loc" : [ -88.04939, 37.066385 ], "pop" : 4402, "state" : "KY" }
+{ "_id" : "42039", "city" : "FANCY FARM", "loc" : [ -88.791785, 36.77674 ], "pop" : 1423, "state" : "KY" }
+{ "_id" : "42040", "city" : "FARMINGTON", "loc" : [ -88.547832, 36.686903 ], "pop" : 2821, "state" : "KY" }
+{ "_id" : "42041", "city" : "CRUTCHFIELD", "loc" : [ -88.889224, 36.528678 ], "pop" : 5955, "state" : "KY" }
+{ "_id" : "42044", "city" : "GILBERTSVILLE", "loc" : [ -88.274856, 36.962465 ], "pop" : 3285, "state" : "KY" }
+{ "_id" : "42045", "city" : "IUKA", "loc" : [ -88.261382, 37.05781 ], "pop" : 2210, "state" : "KY" }
+{ "_id" : "42047", "city" : "HAMPTON", "loc" : [ -88.364897, 37.334764 ], "pop" : 922, "state" : "KY" }
+{ "_id" : "42048", "city" : "HARDIN", "loc" : [ -88.262153, 36.776233 ], "pop" : 3246, "state" : "KY" }
+{ "_id" : "42049", "city" : "HAZEL", "loc" : [ -88.331862, 36.542215 ], "pop" : 3235, "state" : "KY" }
+{ "_id" : "42050", "city" : "HICKMAN", "loc" : [ -89.194667, 36.559269 ], "pop" : 3676, "state" : "KY" }
+{ "_id" : "42051", "city" : "HICKORY", "loc" : [ -88.678782, 36.847783 ], "pop" : 3140, "state" : "KY" }
+{ "_id" : "42053", "city" : "KEVIL", "loc" : [ -88.876366, 37.087231 ], "pop" : 5019, "state" : "KY" }
+{ "_id" : "42054", "city" : "KIRKSEY", "loc" : [ -88.423815, 36.673092 ], "pop" : 3190, "state" : "KY" }
+{ "_id" : "42055", "city" : "KUTTAWA", "loc" : [ -88.14981299999999, 37.061871 ], "pop" : 2222, "state" : "KY" }
+{ "_id" : "42056", "city" : "LA CENTER", "loc" : [ -88.972954, 37.083019 ], "pop" : 1563, "state" : "KY" }
+{ "_id" : "42058", "city" : "LEDBETTER", "loc" : [ -88.486503, 37.049167 ], "pop" : 2278, "state" : "KY" }
+{ "_id" : "42064", "city" : "MARION", "loc" : [ -88.100471, 37.325426 ], "pop" : 8733, "state" : "KY" }
+{ "_id" : "42066", "city" : "MAYFIELD", "loc" : [ -88.650637, 36.732686 ], "pop" : 16321, "state" : "KY" }
+{ "_id" : "42069", "city" : "MELBER", "loc" : [ -88.752037, 36.919658 ], "pop" : 1187, "state" : "KY" }
+{ "_id" : "42071", "city" : "MURRAY", "loc" : [ -88.30324899999999, 36.609915 ], "pop" : 20388, "state" : "KY" }
+{ "_id" : "42076", "city" : "NEW CONCORD", "loc" : [ -88.09547999999999, 36.550003 ], "pop" : 922, "state" : "KY" }
+{ "_id" : "42078", "city" : "SALEM", "loc" : [ -88.27113900000001, 37.255346 ], "pop" : 1801, "state" : "KY" }
+{ "_id" : "42079", "city" : "SEDALIA", "loc" : [ -88.594813, 36.588208 ], "pop" : 1983, "state" : "KY" }
+{ "_id" : "42081", "city" : "CARRSVILLE", "loc" : [ -88.383593, 37.12269 ], "pop" : 1200, "state" : "KY" }
+{ "_id" : "42082", "city" : "SYMSONIA", "loc" : [ -88.528576, 36.871544 ], "pop" : 2725, "state" : "KY" }
+{ "_id" : "42083", "city" : "TILINE", "loc" : [ -88.254679, 37.162773 ], "pop" : 198, "state" : "KY" }
+{ "_id" : "42085", "city" : "WATER VALLEY", "loc" : [ -88.80837099999999, 36.569358 ], "pop" : 409, "state" : "KY" }
+{ "_id" : "42086", "city" : "WEST PADUCAH", "loc" : [ -88.76107500000001, 37.092239 ], "pop" : 2223, "state" : "KY" }
+{ "_id" : "42087", "city" : "WICKLIFFE", "loc" : [ -89.01769299999999, 36.967969 ], "pop" : 2605, "state" : "KY" }
+{ "_id" : "42088", "city" : "WINGO", "loc" : [ -88.73944899999999, 36.625282 ], "pop" : 2643, "state" : "KY" }
+{ "_id" : "42101", "city" : "PLUM SPRINGS", "loc" : [ -86.45589099999999, 37.007874 ], "pop" : 40671, "state" : "KY" }
+{ "_id" : "42103", "city" : "BOWLING GREEN", "loc" : [ -86.393321, 36.96629 ], "pop" : 11391, "state" : "KY" }
+{ "_id" : "42104", "city" : "BOWLING GREEN", "loc" : [ -86.448077, 36.937537 ], "pop" : 14948, "state" : "KY" }
+{ "_id" : "42120", "city" : "ADOLPHUS", "loc" : [ -86.26359600000001, 36.677486 ], "pop" : 1976, "state" : "KY" }
+{ "_id" : "42122", "city" : "ALVATON", "loc" : [ -86.363213, 36.86296 ], "pop" : 2934, "state" : "KY" }
+{ "_id" : "42123", "city" : "AUSTIN", "loc" : [ -85.98502999999999, 36.812376 ], "pop" : 425, "state" : "KY" }
+{ "_id" : "42124", "city" : "BEAUMONT", "loc" : [ -85.64882900000001, 36.88758 ], "pop" : 206, "state" : "KY" }
+{ "_id" : "42127", "city" : "CAVE CITY", "loc" : [ -85.944283, 37.11696 ], "pop" : 6283, "state" : "KY" }
+{ "_id" : "42129", "city" : "SUBTLE", "loc" : [ -85.592741, 36.985197 ], "pop" : 4020, "state" : "KY" }
+{ "_id" : "42130", "city" : "EIGHTY EIGHT", "loc" : [ -85.828076, 36.939238 ], "pop" : 2716, "state" : "KY" }
+{ "_id" : "42131", "city" : "ETOILE", "loc" : [ -85.91727899999999, 36.813428 ], "pop" : 138, "state" : "KY" }
+{ "_id" : "42133", "city" : "FOUNTAIN RUN", "loc" : [ -85.952023, 36.72002 ], "pop" : 1568, "state" : "KY" }
+{ "_id" : "42134", "city" : "FRANKLIN", "loc" : [ -86.570043, 36.725353 ], "pop" : 14684, "state" : "KY" }
+{ "_id" : "42140", "city" : "GAMALIEL", "loc" : [ -85.81335300000001, 36.654037 ], "pop" : 1377, "state" : "KY" }
+{ "_id" : "42141", "city" : "GLASGOW", "loc" : [ -85.92205300000001, 36.988189 ], "pop" : 21079, "state" : "KY" }
+{ "_id" : "42151", "city" : "HESTAND", "loc" : [ -85.569799, 36.653473 ], "pop" : 386, "state" : "KY" }
+{ "_id" : "42153", "city" : "HOLLAND", "loc" : [ -86.049756, 36.667316 ], "pop" : 330, "state" : "KY" }
+{ "_id" : "42154", "city" : "KNOB LICK", "loc" : [ -85.71369799999999, 36.996922 ], "pop" : 656, "state" : "KY" }
+{ "_id" : "42155", "city" : "LAMB", "loc" : [ -85.885413, 36.799768 ], "pop" : 189, "state" : "KY" }
+{ "_id" : "42156", "city" : "LUCAS", "loc" : [ -86.035678, 36.837594 ], "pop" : 415, "state" : "KY" }
+{ "_id" : "42157", "city" : "MOUNT HERMAN", "loc" : [ -85.81916200000001, 36.808982 ], "pop" : 816, "state" : "KY" }
+{ "_id" : "42159", "city" : "OAKLAND", "loc" : [ -86.285934, 37.007595 ], "pop" : 2879, "state" : "KY" }
+{ "_id" : "42160", "city" : "PARK CITY", "loc" : [ -86.077619, 37.057926 ], "pop" : 1351, "state" : "KY" }
+{ "_id" : "42163", "city" : "ROCKY HILL", "loc" : [ -86.11009, 37.067481 ], "pop" : 139, "state" : "KY" }
+{ "_id" : "42164", "city" : "SCOTTSVILLE", "loc" : [ -86.192863, 36.761437 ], "pop" : 11611, "state" : "KY" }
+{ "_id" : "42166", "city" : "SUMMER SHADE", "loc" : [ -85.708322, 36.888345 ], "pop" : 2281, "state" : "KY" }
+{ "_id" : "42167", "city" : "T VILLE", "loc" : [ -85.696842, 36.713085 ], "pop" : 8016, "state" : "KY" }
+{ "_id" : "42169", "city" : "WILLOW SHADE", "loc" : [ -85.62203, 36.858183 ], "pop" : 126, "state" : "KY" }
+{ "_id" : "42170", "city" : "WOODBURN", "loc" : [ -86.562291, 36.855688 ], "pop" : 1573, "state" : "KY" }
+{ "_id" : "42171", "city" : "SMITHS GROVE", "loc" : [ -86.19375700000001, 37.058104 ], "pop" : 4650, "state" : "KY" }
+{ "_id" : "42202", "city" : "ADAIRVILLE", "loc" : [ -86.85852300000001, 36.691385 ], "pop" : 2481, "state" : "KY" }
+{ "_id" : "42204", "city" : "ALLENSVILLE", "loc" : [ -87.02444199999999, 36.694744 ], "pop" : 842, "state" : "KY" }
+{ "_id" : "42206", "city" : "AUBURN", "loc" : [ -86.719813, 36.881755 ], "pop" : 4192, "state" : "KY" }
+{ "_id" : "42207", "city" : "BEE SPRING", "loc" : [ -86.279377, 37.29754 ], "pop" : 1480, "state" : "KY" }
+{ "_id" : "42210", "city" : "REEDYVILLE", "loc" : [ -86.27400299999999, 37.18817 ], "pop" : 2296, "state" : "KY" }
+{ "_id" : "42211", "city" : "GOLDEN POND", "loc" : [ -87.84124300000001, 36.846421 ], "pop" : 9683, "state" : "KY" }
+{ "_id" : "42214", "city" : "CENTER", "loc" : [ -85.670455, 37.100897 ], "pop" : 2051, "state" : "KY" }
+{ "_id" : "42215", "city" : "CERULEAN", "loc" : [ -87.66484800000001, 36.949619 ], "pop" : 1654, "state" : "KY" }
+{ "_id" : "42217", "city" : "CROFTON", "loc" : [ -87.48907199999999, 37.034387 ], "pop" : 3531, "state" : "KY" }
+{ "_id" : "42220", "city" : "ELKTON", "loc" : [ -87.167833, 36.909403 ], "pop" : 7207, "state" : "KY" }
+{ "_id" : "42223", "city" : "FORT CAMPBELL", "loc" : [ -87.459706, 36.653584 ], "pop" : 18861, "state" : "KY" }
+{ "_id" : "42232", "city" : "GRACEY", "loc" : [ -87.6545, 36.856393 ], "pop" : 92, "state" : "KY" }
+{ "_id" : "42234", "city" : "TINY TOWN", "loc" : [ -87.170931, 36.664268 ], "pop" : 2307, "state" : "KY" }
+{ "_id" : "42236", "city" : "HERNDON", "loc" : [ -87.608215, 36.708469 ], "pop" : 810, "state" : "KY" }
+{ "_id" : "42240", "city" : "HOPKINSVILLE", "loc" : [ -87.485148, 36.862053 ], "pop" : 39331, "state" : "KY" }
+{ "_id" : "42250", "city" : "HUFF", "loc" : [ -86.38211200000001, 37.234241 ], "pop" : 92, "state" : "KY" }
+{ "_id" : "42252", "city" : "JETSON", "loc" : [ -86.520872, 37.240367 ], "pop" : 1375, "state" : "KY" }
+{ "_id" : "42254", "city" : "LA FAYETTE", "loc" : [ -87.65634, 36.658165 ], "pop" : 123, "state" : "KY" }
+{ "_id" : "42256", "city" : "LEWISBURG", "loc" : [ -86.988748, 37.003747 ], "pop" : 3241, "state" : "KY" }
+{ "_id" : "42257", "city" : "LINDSEYVILLE", "loc" : [ -86.296384, 37.22813 ], "pop" : 601, "state" : "KY" }
+{ "_id" : "42259", "city" : "MAMMOTH CAVE NAT", "loc" : [ -86.178112, 37.274385 ], "pop" : 1354, "state" : "KY" }
+{ "_id" : "42261", "city" : "LOGANSPORT", "loc" : [ -86.703726, 37.19102 ], "pop" : 5488, "state" : "KY" }
+{ "_id" : "42262", "city" : "OAK GROVE", "loc" : [ -87.42551400000001, 36.665225 ], "pop" : 3556, "state" : "KY" }
+{ "_id" : "42265", "city" : "OLMSTEAD", "loc" : [ -86.981846, 36.78463 ], "pop" : 1529, "state" : "KY" }
+{ "_id" : "42266", "city" : "PEMBROKE", "loc" : [ -87.331892, 36.798221 ], "pop" : 1221, "state" : "KY" }
+{ "_id" : "42268", "city" : "QUALITY", "loc" : [ -86.86905299999999, 37.035402 ], "pop" : 1436, "state" : "KY" }
+{ "_id" : "42273", "city" : "ROCHESTER", "loc" : [ -86.85921, 37.204778 ], "pop" : 669, "state" : "KY" }
+{ "_id" : "42274", "city" : "BROWNING", "loc" : [ -86.58538900000001, 36.939859 ], "pop" : 1592, "state" : "KY" }
+{ "_id" : "42275", "city" : "ROUNDHILL", "loc" : [ -86.40697400000001, 37.25601 ], "pop" : 405, "state" : "KY" }
+{ "_id" : "42276", "city" : "DAYSVILLE", "loc" : [ -86.88870799999999, 36.853074 ], "pop" : 12585, "state" : "KY" }
+{ "_id" : "42280", "city" : "SHARON GROVE", "loc" : [ -87.10029, 36.927754 ], "pop" : 651, "state" : "KY" }
+{ "_id" : "42284", "city" : "SUNFISH", "loc" : [ -86.390826, 37.3022 ], "pop" : 483, "state" : "KY" }
+{ "_id" : "42285", "city" : "KYROCK", "loc" : [ -86.29568999999999, 37.252343 ], "pop" : 416, "state" : "KY" }
+{ "_id" : "42286", "city" : "TRENTON", "loc" : [ -87.261098, 36.731384 ], "pop" : 1209, "state" : "KY" }
+{ "_id" : "42287", "city" : "WELCHS CREEK", "loc" : [ -86.637139, 37.30856 ], "pop" : 2972, "state" : "KY" }
+{ "_id" : "42301", "city" : "OWENSBORO", "loc" : [ -87.155394, 37.751255 ], "pop" : 40043, "state" : "KY" }
+{ "_id" : "42303", "city" : "OWENSBORO", "loc" : [ -87.080252, 37.755884 ], "pop" : 32552, "state" : "KY" }
+{ "_id" : "42320", "city" : "BEAVER DAM", "loc" : [ -86.87293200000001, 37.386958 ], "pop" : 6508, "state" : "KY" }
+{ "_id" : "42321", "city" : "BEECH CREEK", "loc" : [ -87.12385399999999, 37.183704 ], "pop" : 303, "state" : "KY" }
+{ "_id" : "42323", "city" : "BEECHMONT", "loc" : [ -87.03934, 37.177552 ], "pop" : 2431, "state" : "KY" }
+{ "_id" : "42324", "city" : "BELTON", "loc" : [ -86.977369, 37.151056 ], "pop" : 1137, "state" : "KY" }
+{ "_id" : "42325", "city" : "BREMEN", "loc" : [ -87.232989, 37.342955 ], "pop" : 3631, "state" : "KY" }
+{ "_id" : "42326", "city" : "BROWDER", "loc" : [ -86.97819699999999, 37.259333 ], "pop" : 0, "state" : "KY" }
+{ "_id" : "42327", "city" : "CALHOUN", "loc" : [ -87.27730699999999, 37.574997 ], "pop" : 3734, "state" : "KY" }
+{ "_id" : "42328", "city" : "CENTERTOWN", "loc" : [ -87.00902000000001, 37.407918 ], "pop" : 1434, "state" : "KY" }
+{ "_id" : "42330", "city" : "CENTRAL CITY", "loc" : [ -87.12023600000001, 37.300699 ], "pop" : 8187, "state" : "KY" }
+{ "_id" : "42333", "city" : "CROMWELL", "loc" : [ -86.769964, 37.341765 ], "pop" : 356, "state" : "KY" }
+{ "_id" : "42337", "city" : "DRAKESBORO", "loc" : [ -87.047966, 37.213588 ], "pop" : 1552, "state" : "KY" }
+{ "_id" : "42338", "city" : "DUNDEE", "loc" : [ -86.760446, 37.551052 ], "pop" : 255, "state" : "KY" }
+{ "_id" : "42339", "city" : "DUNMOR", "loc" : [ -87.00789, 37.083967 ], "pop" : 534, "state" : "KY" }
+{ "_id" : "42343", "city" : "FORDSVILLE", "loc" : [ -86.726251, 37.629738 ], "pop" : 2108, "state" : "KY" }
+{ "_id" : "42344", "city" : "GRAHAM", "loc" : [ -87.25784899999999, 37.225836 ], "pop" : 2837, "state" : "KY" }
+{ "_id" : "42345", "city" : "GREENVILLE", "loc" : [ -87.18061299999999, 37.207642 ], "pop" : 8616, "state" : "KY" }
+{ "_id" : "42347", "city" : "HARTFORD", "loc" : [ -86.91798199999999, 37.478533 ], "pop" : 4628, "state" : "KY" }
+{ "_id" : "42348", "city" : "HAWESVILLE", "loc" : [ -86.76380399999999, 37.850318 ], "pop" : 4194, "state" : "KY" }
+{ "_id" : "42349", "city" : "HORSE BRANCH", "loc" : [ -86.698734, 37.423417 ], "pop" : 1880, "state" : "KY" }
+{ "_id" : "42350", "city" : "ISLAND", "loc" : [ -87.16921000000001, 37.447109 ], "pop" : 1453, "state" : "KY" }
+{ "_id" : "42351", "city" : "LEWISPORT", "loc" : [ -86.895712, 37.909016 ], "pop" : 4102, "state" : "KY" }
+{ "_id" : "42352", "city" : "LIVERMORE", "loc" : [ -87.12386100000001, 37.504453 ], "pop" : 2336, "state" : "KY" }
+{ "_id" : "42355", "city" : "MACEO", "loc" : [ -86.999915, 37.843601 ], "pop" : 2223, "state" : "KY" }
+{ "_id" : "42358", "city" : "NARROWS", "loc" : [ -86.68671999999999, 37.569072 ], "pop" : 124, "state" : "KY" }
+{ "_id" : "42361", "city" : "OLATON", "loc" : [ -86.728223, 37.498666 ], "pop" : 1838, "state" : "KY" }
+{ "_id" : "42365", "city" : "PENROD", "loc" : [ -86.998181, 37.116725 ], "pop" : 354, "state" : "KY" }
+{ "_id" : "42366", "city" : "PHILPOT", "loc" : [ -86.937172, 37.718317 ], "pop" : 6890, "state" : "KY" }
+{ "_id" : "42368", "city" : "REYNOLDS STATION", "loc" : [ -86.77942, 37.696533 ], "pop" : 1389, "state" : "KY" }
+{ "_id" : "42369", "city" : "ROCKPORT", "loc" : [ -86.97462400000001, 37.326871 ], "pop" : 647, "state" : "KY" }
+{ "_id" : "42371", "city" : "RUMSEY", "loc" : [ -87.280644, 37.50762 ], "pop" : 836, "state" : "KY" }
+{ "_id" : "42372", "city" : "SACRAMENTO", "loc" : [ -87.273584, 37.417687 ], "pop" : 1265, "state" : "KY" }
+{ "_id" : "42376", "city" : "UTICA", "loc" : [ -87.059082, 37.620559 ], "pop" : 4800, "state" : "KY" }
+{ "_id" : "42378", "city" : "WHITESVILLE", "loc" : [ -86.869912, 37.683402 ], "pop" : 640, "state" : "KY" }
+{ "_id" : "42404", "city" : "CLAY", "loc" : [ -87.836793, 37.475599 ], "pop" : 2708, "state" : "KY" }
+{ "_id" : "42406", "city" : "CORYDON", "loc" : [ -87.700033, 37.744284 ], "pop" : 3688, "state" : "KY" }
+{ "_id" : "42408", "city" : "DAWSON SPRINGS", "loc" : [ -87.68205, 37.196386 ], "pop" : 6728, "state" : "KY" }
+{ "_id" : "42409", "city" : "DIXON", "loc" : [ -87.701904, 37.510587 ], "pop" : 1093, "state" : "KY" }
+{ "_id" : "42410", "city" : "EARLINGTON", "loc" : [ -87.522679, 37.267899 ], "pop" : 2445, "state" : "KY" }
+{ "_id" : "42411", "city" : "FREDONIA", "loc" : [ -88.011229, 37.212956 ], "pop" : 1557, "state" : "KY" }
+{ "_id" : "42413", "city" : "HANSON", "loc" : [ -87.47513499999999, 37.438246 ], "pop" : 2329, "state" : "KY" }
+{ "_id" : "42420", "city" : "HENDERSON", "loc" : [ -87.563228, 37.827393 ], "pop" : 34941, "state" : "KY" }
+{ "_id" : "42431", "city" : "MADISONVILLE", "loc" : [ -87.49532600000001, 37.325551 ], "pop" : 26866, "state" : "KY" }
+{ "_id" : "42436", "city" : "MANITOU", "loc" : [ -87.56117999999999, 37.407972 ], "pop" : 1425, "state" : "KY" }
+{ "_id" : "42437", "city" : "HENSHAW", "loc" : [ -87.87685999999999, 37.663935 ], "pop" : 10346, "state" : "KY" }
+{ "_id" : "42441", "city" : "NEBO", "loc" : [ -87.686521, 37.368255 ], "pop" : 1639, "state" : "KY" }
+{ "_id" : "42442", "city" : "NORTONVILLE", "loc" : [ -87.460505, 37.183367 ], "pop" : 2811, "state" : "KY" }
+{ "_id" : "42445", "city" : "PRINCETON", "loc" : [ -87.863226, 37.115097 ], "pop" : 11736, "state" : "KY" }
+{ "_id" : "42450", "city" : "PROVIDENCE", "loc" : [ -87.750512, 37.404958 ], "pop" : 4778, "state" : "KY" }
+{ "_id" : "42451", "city" : "REED", "loc" : [ -87.37038200000001, 37.858764 ], "pop" : 1072, "state" : "KY" }
+{ "_id" : "42452", "city" : "ROBARDS", "loc" : [ -87.526596, 37.675836 ], "pop" : 1416, "state" : "KY" }
+{ "_id" : "42453", "city" : "SAINT CHARLES", "loc" : [ -87.55386, 37.176635 ], "pop" : 848, "state" : "KY" }
+{ "_id" : "42455", "city" : "SEBREE", "loc" : [ -87.52548899999999, 37.588921 ], "pop" : 2911, "state" : "KY" }
+{ "_id" : "42456", "city" : "SLAUGHTERS", "loc" : [ -87.50534399999999, 37.5054 ], "pop" : 914, "state" : "KY" }
+{ "_id" : "42458", "city" : "SPOTTSVILLE", "loc" : [ -87.424682, 37.839948 ], "pop" : 1534, "state" : "KY" }
+{ "_id" : "42459", "city" : "STURGIS", "loc" : [ -87.99645700000001, 37.548669 ], "pop" : 5483, "state" : "KY" }
+{ "_id" : "42461", "city" : "UNIONTOWN", "loc" : [ -87.92633499999999, 37.767741 ], "pop" : 1555, "state" : "KY" }
+{ "_id" : "42462", "city" : "WAVERLY", "loc" : [ -87.80668799999999, 37.742985 ], "pop" : 1521, "state" : "KY" }
+{ "_id" : "42464", "city" : "WHITE PLAINS", "loc" : [ -87.36441499999999, 37.178765 ], "pop" : 1877, "state" : "KY" }
+{ "_id" : "42501", "city" : "ALCALDE", "loc" : [ -84.60436199999999, 37.073853 ], "pop" : 28546, "state" : "KY" }
+{ "_id" : "42516", "city" : "BETHELRIDGE", "loc" : [ -84.778971, 37.22459 ], "pop" : 550, "state" : "KY" }
+{ "_id" : "42518", "city" : "BRONSTON", "loc" : [ -84.63141299999999, 36.952488 ], "pop" : 2417, "state" : "KY" }
+{ "_id" : "42519", "city" : "SLOANS VALLEY", "loc" : [ -84.565237, 36.96145 ], "pop" : 2843, "state" : "KY" }
+{ "_id" : "42528", "city" : "DUNNVILLE", "loc" : [ -84.929507, 37.176894 ], "pop" : 2308, "state" : "KY" }
+{ "_id" : "42532", "city" : "JABEZ", "loc" : [ -84.863157, 37.066884 ], "pop" : 364, "state" : "KY" }
+{ "_id" : "42539", "city" : "LIBERTY", "loc" : [ -84.971864, 37.314553 ], "pop" : 7831, "state" : "KY" }
+{ "_id" : "42541", "city" : "MIDDLEBURG", "loc" : [ -84.832103, 37.359082 ], "pop" : 697, "state" : "KY" }
+{ "_id" : "42544", "city" : "POINTER", "loc" : [ -84.766245, 37.064216 ], "pop" : 3861, "state" : "KY" }
+{ "_id" : "42553", "city" : "SCIENCE HILL", "loc" : [ -84.64865, 37.168333 ], "pop" : 2899, "state" : "KY" }
+{ "_id" : "42554", "city" : "SHOPVILLE", "loc" : [ -84.44593999999999, 37.174243 ], "pop" : 3258, "state" : "KY" }
+{ "_id" : "42555", "city" : "SLOANS VALLEY", "loc" : [ -84.37620099999999, 36.968617 ], "pop" : 0, "state" : "KY" }
+{ "_id" : "42558", "city" : "TATEVILLE", "loc" : [ -84.43836400000001, 36.973892 ], "pop" : 0, "state" : "KY" }
+{ "_id" : "42566", "city" : "YOSEMITE", "loc" : [ -84.81241199999999, 37.307355 ], "pop" : 380, "state" : "KY" }
+{ "_id" : "42567", "city" : "PULASKI", "loc" : [ -84.605593, 37.247038 ], "pop" : 5867, "state" : "KY" }
+{ "_id" : "42601", "city" : "AARON", "loc" : [ -85.19911399999999, 36.812827 ], "pop" : 270, "state" : "KY" }
+{ "_id" : "42602", "city" : "ALBANY", "loc" : [ -85.140677, 36.68569 ], "pop" : 6419, "state" : "KY" }
+{ "_id" : "42603", "city" : "ALPHA", "loc" : [ -85.092405, 36.779735 ], "pop" : 2163, "state" : "KY" }
+{ "_id" : "42611", "city" : "COOPERSVILLE", "loc" : [ -84.718717, 36.722168 ], "pop" : 350, "state" : "KY" }
+{ "_id" : "42613", "city" : "DELTA", "loc" : [ -84.68402399999999, 36.801658 ], "pop" : 639, "state" : "KY" }
+{ "_id" : "42629", "city" : "JAMESTOWN", "loc" : [ -85.096844, 36.967955 ], "pop" : 5140, "state" : "KY" }
+{ "_id" : "42633", "city" : "PUEBLO", "loc" : [ -84.839251, 36.842723 ], "pop" : 13523, "state" : "KY" }
+{ "_id" : "42634", "city" : "PARKERS LAKE", "loc" : [ -84.443642, 36.834689 ], "pop" : 1952, "state" : "KY" }
+{ "_id" : "42635", "city" : "HOLLYHILL", "loc" : [ -84.412745, 36.663677 ], "pop" : 4865, "state" : "KY" }
+{ "_id" : "42638", "city" : "REVELO", "loc" : [ -84.472189, 36.673363 ], "pop" : 221, "state" : "KY" }
+{ "_id" : "42640", "city" : "ROCKYBRANCH", "loc" : [ -84.81017900000001, 36.668512 ], "pop" : 79, "state" : "KY" }
+{ "_id" : "42642", "city" : "WEBBS CROSS ROAD", "loc" : [ -85.042873, 37.056683 ], "pop" : 9569, "state" : "KY" }
+{ "_id" : "42643", "city" : "SAWYER", "loc" : [ -84.361745, 36.925337 ], "pop" : 288, "state" : "KY" }
+{ "_id" : "42647", "city" : "STEARNS", "loc" : [ -84.51648400000001, 36.708184 ], "pop" : 4201, "state" : "KY" }
+{ "_id" : "42649", "city" : "STRUNK", "loc" : [ -84.430801, 36.619068 ], "pop" : 481, "state" : "KY" }
+{ "_id" : "42653", "city" : "WIBORG", "loc" : [ -84.46836399999999, 36.738597 ], "pop" : 3595, "state" : "KY" }
+{ "_id" : "42655", "city" : "WINDY", "loc" : [ -84.961122, 36.778411 ], "pop" : 2481, "state" : "KY" }
+{ "_id" : "42701", "city" : "E TOWN", "loc" : [ -85.858977, 37.706973 ], "pop" : 31300, "state" : "KY" }
+{ "_id" : "42711", "city" : "BAKERTON", "loc" : [ -85.331723, 36.871151 ], "pop" : 222, "state" : "KY" }
+{ "_id" : "42712", "city" : "BIG CLIFTY", "loc" : [ -86.139498, 37.527801 ], "pop" : 1459, "state" : "KY" }
+{ "_id" : "42713", "city" : "BONNIEVILLE", "loc" : [ -85.895996, 37.374141 ], "pop" : 1627, "state" : "KY" }
+{ "_id" : "42714", "city" : "BOW", "loc" : [ -85.301935, 36.708119 ], "pop" : 697, "state" : "KY" }
+{ "_id" : "42715", "city" : "BREEDING", "loc" : [ -85.407822, 36.981043 ], "pop" : 692, "state" : "KY" }
+{ "_id" : "42716", "city" : "BUFFALO", "loc" : [ -85.643411, 37.47864 ], "pop" : 1614, "state" : "KY" }
+{ "_id" : "42717", "city" : "BURKESVILLE", "loc" : [ -85.39702800000001, 36.806791 ], "pop" : 4891, "state" : "KY" }
+{ "_id" : "42718", "city" : "CAMPBELLSVILLE", "loc" : [ -85.35075500000001, 37.346618 ], "pop" : 19358, "state" : "KY" }
+{ "_id" : "42721", "city" : "CANEYVILLE", "loc" : [ -86.470207, 37.422168 ], "pop" : 3148, "state" : "KY" }
+{ "_id" : "42722", "city" : "CANMER", "loc" : [ -85.720292, 37.269562 ], "pop" : 465, "state" : "KY" }
+{ "_id" : "42723", "city" : "CASEY CREEK", "loc" : [ -85.20764800000001, 37.273479 ], "pop" : 1102, "state" : "KY" }
+{ "_id" : "42724", "city" : "STEPHENSBURG", "loc" : [ -86.006046, 37.660339 ], "pop" : 3153, "state" : "KY" }
+{ "_id" : "42726", "city" : "WAX", "loc" : [ -86.160219, 37.427896 ], "pop" : 3001, "state" : "KY" }
+{ "_id" : "42728", "city" : "MONTPELIER", "loc" : [ -85.269265, 37.116408 ], "pop" : 10012, "state" : "KY" }
+{ "_id" : "42729", "city" : "CUB RUN", "loc" : [ -86.08132000000001, 37.314855 ], "pop" : 609, "state" : "KY" }
+{ "_id" : "42730", "city" : "CUNDIFF", "loc" : [ -85.274434, 36.957125 ], "pop" : 429, "state" : "KY" }
+{ "_id" : "42731", "city" : "DUBRE", "loc" : [ -85.568281, 36.891998 ], "pop" : 210, "state" : "KY" }
+{ "_id" : "42732", "city" : "E VIEW", "loc" : [ -86.119153, 37.61478 ], "pop" : 2728, "state" : "KY" }
+{ "_id" : "42733", "city" : "ELK HORN", "loc" : [ -85.19176400000001, 37.339287 ], "pop" : 637, "state" : "KY" }
+{ "_id" : "42735", "city" : "FAIRPLAY", "loc" : [ -85.32621399999999, 37.035626 ], "pop" : 557, "state" : "KY" }
+{ "_id" : "42736", "city" : "FINLEY", "loc" : [ -85.35244899999999, 37.454549 ], "pop" : 1153, "state" : "KY" }
+{ "_id" : "42740", "city" : "GLENDALE", "loc" : [ -85.892101, 37.603398 ], "pop" : 991, "state" : "KY" }
+{ "_id" : "42741", "city" : "GLENS FORK", "loc" : [ -85.240117, 37.018195 ], "pop" : 788, "state" : "KY" }
+{ "_id" : "42742", "city" : "GRADYVILLE", "loc" : [ -85.42753, 37.054438 ], "pop" : 775, "state" : "KY" }
+{ "_id" : "42743", "city" : "GREENSBURG", "loc" : [ -85.523639, 37.243009 ], "pop" : 8471, "state" : "KY" }
+{ "_id" : "42746", "city" : "HARDYVILLE", "loc" : [ -85.75417400000001, 37.224905 ], "pop" : 1234, "state" : "KY" }
+{ "_id" : "42748", "city" : "HODGENVILLE", "loc" : [ -85.723206, 37.574566 ], "pop" : 6666, "state" : "KY" }
+{ "_id" : "42749", "city" : "HORSE CAVE", "loc" : [ -85.87854900000001, 37.184939 ], "pop" : 5282, "state" : "KY" }
+{ "_id" : "42752", "city" : "KETTLE", "loc" : [ -85.40917, 36.694573 ], "pop" : 991, "state" : "KY" }
+{ "_id" : "42753", "city" : "KNIFLEY", "loc" : [ -85.112844, 37.231886 ], "pop" : 648, "state" : "KY" }
+{ "_id" : "42754", "city" : "SADLER", "loc" : [ -86.30371, 37.493098 ], "pop" : 13023, "state" : "KY" }
+{ "_id" : "42757", "city" : "MAGNOLIA", "loc" : [ -85.730823, 37.416464 ], "pop" : 2960, "state" : "KY" }
+{ "_id" : "42761", "city" : "MILLTOWN", "loc" : [ -85.444181, 37.103415 ], "pop" : 625, "state" : "KY" }
+{ "_id" : "42762", "city" : "MILLWOOD", "loc" : [ -86.37982100000001, 37.460879 ], "pop" : 561, "state" : "KY" }
+{ "_id" : "42764", "city" : "MOUNT SHERMAN", "loc" : [ -85.631381, 37.453408 ], "pop" : 589, "state" : "KY" }
+{ "_id" : "42765", "city" : "MUNFORDVILLE", "loc" : [ -85.920141, 37.289812 ], "pop" : 4085, "state" : "KY" }
+{ "_id" : "42768", "city" : "PEYTONSBURG", "loc" : [ -85.371663, 36.646299 ], "pop" : 272, "state" : "KY" }
+{ "_id" : "42776", "city" : "SONORA", "loc" : [ -85.92296899999999, 37.52207 ], "pop" : 2396, "state" : "KY" }
+{ "_id" : "42782", "city" : "SUMMERSVILLE", "loc" : [ -85.619376, 37.34186 ], "pop" : 778, "state" : "KY" }
+{ "_id" : "42784", "city" : "UPTON", "loc" : [ -85.908619, 37.456802 ], "pop" : 2272, "state" : "KY" }
+{ "_id" : "42788", "city" : "WHITE MILLS", "loc" : [ -86.039519, 37.543765 ], "pop" : 540, "state" : "KY" }
+{ "_id" : "43001", "city" : "ALEXANDRIA", "loc" : [ -82.60768299999999, 40.105965 ], "pop" : 2485, "state" : "OH" }
+{ "_id" : "43002", "city" : "AMLIN", "loc" : [ -83.179157, 40.07203 ], "pop" : 1699, "state" : "OH" }
+{ "_id" : "43003", "city" : "ASHLEY", "loc" : [ -82.954201, 40.416264 ], "pop" : 3009, "state" : "OH" }
+{ "_id" : "43004", "city" : "BLACKLICK", "loc" : [ -82.807857, 40.020952 ], "pop" : 2288, "state" : "OH" }
+{ "_id" : "43006", "city" : "BRINKHAVEN", "loc" : [ -82.155289, 40.458346 ], "pop" : 378, "state" : "OH" }
+{ "_id" : "43009", "city" : "CABLE", "loc" : [ -83.64696000000001, 40.178411 ], "pop" : 1660, "state" : "OH" }
+{ "_id" : "43011", "city" : "CENTERBURG", "loc" : [ -82.68003899999999, 40.286513 ], "pop" : 4437, "state" : "OH" }
+{ "_id" : "43013", "city" : "CROTON", "loc" : [ -82.698948, 40.237603 ], "pop" : 1197, "state" : "OH" }
+{ "_id" : "43014", "city" : "DANVILLE", "loc" : [ -82.26385500000001, 40.455693 ], "pop" : 2033, "state" : "OH" }
+{ "_id" : "43015", "city" : "DELAWARE", "loc" : [ -83.072312, 40.293186 ], "pop" : 29384, "state" : "OH" }
+{ "_id" : "43017", "city" : "DUBLIN", "loc" : [ -83.114633, 40.109297 ], "pop" : 34840, "state" : "OH" }
+{ "_id" : "43019", "city" : "FREDERICKTOWN", "loc" : [ -82.585711, 40.497613 ], "pop" : 10647, "state" : "OH" }
+{ "_id" : "43021", "city" : "GALENA", "loc" : [ -82.895937, 40.191546 ], "pop" : 4893, "state" : "OH" }
+{ "_id" : "43022", "city" : "GAMBIER", "loc" : [ -82.382752, 40.378241 ], "pop" : 3903, "state" : "OH" }
+{ "_id" : "43023", "city" : "GRANVILLE", "loc" : [ -82.51939900000001, 40.078791 ], "pop" : 9523, "state" : "OH" }
+{ "_id" : "43025", "city" : "HEBRON", "loc" : [ -82.491868, 39.953464 ], "pop" : 7920, "state" : "OH" }
+{ "_id" : "43026", "city" : "HILLIARD", "loc" : [ -83.138333, 40.032187 ], "pop" : 25442, "state" : "OH" }
+{ "_id" : "43028", "city" : "HOWARD", "loc" : [ -82.33335099999999, 40.415818 ], "pop" : 1972, "state" : "OH" }
+{ "_id" : "43029", "city" : "IRWIN", "loc" : [ -83.458699, 40.128352 ], "pop" : 498, "state" : "OH" }
+{ "_id" : "43031", "city" : "JOHNSTOWN", "loc" : [ -82.697284, 40.14452 ], "pop" : 7550, "state" : "OH" }
+{ "_id" : "43036", "city" : "MAGNETIC SPRINGS", "loc" : [ -83.26714200000001, 40.358023 ], "pop" : 708, "state" : "OH" }
+{ "_id" : "43037", "city" : "MARTINSBURG", "loc" : [ -82.356691, 40.267954 ], "pop" : 370, "state" : "OH" }
+{ "_id" : "43040", "city" : "MARYSVILLE", "loc" : [ -83.362213, 40.247723 ], "pop" : 19644, "state" : "OH" }
+{ "_id" : "43044", "city" : "MECHANICSBURG", "loc" : [ -83.572352, 40.064659 ], "pop" : 5390, "state" : "OH" }
+{ "_id" : "43045", "city" : "MILFORD CENTER", "loc" : [ -83.437333, 40.181666 ], "pop" : 1260, "state" : "OH" }
+{ "_id" : "43046", "city" : "MILLERSPORT", "loc" : [ -82.52834799999999, 39.899307 ], "pop" : 3171, "state" : "OH" }
+{ "_id" : "43050", "city" : "MOUNT VERNON", "loc" : [ -82.487286, 40.384937 ], "pop" : 24421, "state" : "OH" }
+{ "_id" : "43054", "city" : "NEW ALBANY", "loc" : [ -82.798793, 40.084686 ], "pop" : 3520, "state" : "OH" }
+{ "_id" : "43055", "city" : "NEWARK", "loc" : [ -82.40456500000001, 40.072429 ], "pop" : 56412, "state" : "OH" }
+{ "_id" : "43056", "city" : "HEATH", "loc" : [ -82.38752700000001, 40.019659 ], "pop" : 13336, "state" : "OH" }
+{ "_id" : "43060", "city" : "NORTH LEWISBURG", "loc" : [ -83.561476, 40.222871 ], "pop" : 1407, "state" : "OH" }
+{ "_id" : "43061", "city" : "OSTRANDER", "loc" : [ -83.197813, 40.273971 ], "pop" : 2622, "state" : "OH" }
+{ "_id" : "43062", "city" : "PATASKALA", "loc" : [ -82.668656, 40.000925 ], "pop" : 15470, "state" : "OH" }
+{ "_id" : "43064", "city" : "PLAIN CITY", "loc" : [ -83.269049, 40.097356 ], "pop" : 8323, "state" : "OH" }
+{ "_id" : "43065", "city" : "SHAWNEE HILLS", "loc" : [ -83.074921, 40.152652 ], "pop" : 14955, "state" : "OH" }
+{ "_id" : "43066", "city" : "RADNOR", "loc" : [ -83.178074, 40.391779 ], "pop" : 1150, "state" : "OH" }
+{ "_id" : "43067", "city" : "RAYMOND", "loc" : [ -83.36492699999999, 40.247321 ], "pop" : 576, "state" : "OH" }
+{ "_id" : "43068", "city" : "REYNOLDSBURG", "loc" : [ -82.803454, 39.955145 ], "pop" : 35820, "state" : "OH" }
+{ "_id" : "43071", "city" : "SAINT LOUISVILLE", "loc" : [ -82.356015, 40.181776 ], "pop" : 2389, "state" : "OH" }
+{ "_id" : "43072", "city" : "SAINT PARIS", "loc" : [ -83.96306199999999, 40.105755 ], "pop" : 5963, "state" : "OH" }
+{ "_id" : "43074", "city" : "SUNBURY", "loc" : [ -82.851051, 40.265499 ], "pop" : 7508, "state" : "OH" }
+{ "_id" : "43076", "city" : "THORNVILLE", "loc" : [ -82.407059, 39.897364 ], "pop" : 8187, "state" : "OH" }
+{ "_id" : "43078", "city" : "URBANA", "loc" : [ -83.76714200000001, 40.106639 ], "pop" : 20175, "state" : "OH" }
+{ "_id" : "43080", "city" : "UTICA", "loc" : [ -82.413459, 40.244137 ], "pop" : 5502, "state" : "OH" }
+{ "_id" : "43081", "city" : "WESTERVILLE", "loc" : [ -82.910504, 40.114569 ], "pop" : 49023, "state" : "OH" }
+{ "_id" : "43084", "city" : "WOODSTOCK", "loc" : [ -83.546149, 40.181644 ], "pop" : 793, "state" : "OH" }
+{ "_id" : "43085", "city" : "WORTHINGTON", "loc" : [ -83.010069, 40.105155 ], "pop" : 27229, "state" : "OH" }
+{ "_id" : "43102", "city" : "AMANDA", "loc" : [ -82.755236, 39.625104 ], "pop" : 3730, "state" : "OH" }
+{ "_id" : "43103", "city" : "ASHVILLE", "loc" : [ -82.94456700000001, 39.731576 ], "pop" : 9050, "state" : "OH" }
+{ "_id" : "43105", "city" : "BALTIMORE", "loc" : [ -82.62402299999999, 39.864452 ], "pop" : 5765, "state" : "OH" }
+{ "_id" : "43106", "city" : "BLOOMINGBURG", "loc" : [ -83.409521, 39.628617 ], "pop" : 1643, "state" : "OH" }
+{ "_id" : "43107", "city" : "HIDE A WAY HILLS", "loc" : [ -82.42547999999999, 39.698807 ], "pop" : 3087, "state" : "OH" }
+{ "_id" : "43110", "city" : "CANAL WINCHESTER", "loc" : [ -82.80436899999999, 39.83486 ], "pop" : 8444, "state" : "OH" }
+{ "_id" : "43112", "city" : "CARROLL", "loc" : [ -82.708358, 39.795743 ], "pop" : 3914, "state" : "OH" }
+{ "_id" : "43113", "city" : "CIRCLEVILLE", "loc" : [ -82.92996599999999, 39.598836 ], "pop" : 22337, "state" : "OH" }
+{ "_id" : "43115", "city" : "CLARKSBURG", "loc" : [ -83.156282, 39.490432 ], "pop" : 1523, "state" : "OH" }
+{ "_id" : "43119", "city" : "GALLOWAY", "loc" : [ -83.183848, 39.936604 ], "pop" : 9984, "state" : "OH" }
+{ "_id" : "43123", "city" : "GROVE CITY", "loc" : [ -83.083944, 39.881382 ], "pop" : 33730, "state" : "OH" }
+{ "_id" : "43125", "city" : "GROVEPORT", "loc" : [ -82.887219, 39.858137 ], "pop" : 7728, "state" : "OH" }
+{ "_id" : "43128", "city" : "JEFFERSONVILLE", "loc" : [ -83.56873, 39.65896 ], "pop" : 2359, "state" : "OH" }
+{ "_id" : "43130", "city" : "LANCASTER", "loc" : [ -82.60307400000001, 39.718697 ], "pop" : 54451, "state" : "OH" }
+{ "_id" : "43135", "city" : "LAURELVILLE", "loc" : [ -82.721219, 39.4757 ], "pop" : 4552, "state" : "OH" }
+{ "_id" : "43137", "city" : "LOCKBOURNE", "loc" : [ -82.97636900000001, 39.814236 ], "pop" : 1423, "state" : "OH" }
+{ "_id" : "43138", "city" : "LOGAN", "loc" : [ -82.412594, 39.537175 ], "pop" : 16011, "state" : "OH" }
+{ "_id" : "43140", "city" : "LONDON", "loc" : [ -83.443899, 39.900074 ], "pop" : 20432, "state" : "OH" }
+{ "_id" : "43143", "city" : "MOUNT STERLING", "loc" : [ -83.280618, 39.717506 ], "pop" : 4912, "state" : "OH" }
+{ "_id" : "43145", "city" : "NEW HOLLAND", "loc" : [ -83.250429, 39.558897 ], "pop" : 1768, "state" : "OH" }
+{ "_id" : "43146", "city" : "ORIENT", "loc" : [ -83.15431700000001, 39.795386 ], "pop" : 13491, "state" : "OH" }
+{ "_id" : "43147", "city" : "PICKERINGTON", "loc" : [ -82.75626699999999, 39.906062 ], "pop" : 18424, "state" : "OH" }
+{ "_id" : "43148", "city" : "PLEASANTVILLE", "loc" : [ -82.504268, 39.822684 ], "pop" : 1272, "state" : "OH" }
+{ "_id" : "43149", "city" : "ROCKBRIDGE", "loc" : [ -82.562572, 39.550907 ], "pop" : 2063, "state" : "OH" }
+{ "_id" : "43150", "city" : "RUSHVILLE", "loc" : [ -82.427981, 39.767375 ], "pop" : 1558, "state" : "OH" }
+{ "_id" : "43152", "city" : "SOUTH BLOOMINGVI", "loc" : [ -82.639404, 39.374145 ], "pop" : 1429, "state" : "OH" }
+{ "_id" : "43153", "city" : "SOUTH SOLON", "loc" : [ -83.59698400000001, 39.742295 ], "pop" : 766, "state" : "OH" }
+{ "_id" : "43154", "city" : "STOUTSVILLE", "loc" : [ -82.81927899999999, 39.60672 ], "pop" : 1666, "state" : "OH" }
+{ "_id" : "43155", "city" : "SUGAR GROVE", "loc" : [ -82.532113, 39.627699 ], "pop" : 1572, "state" : "OH" }
+{ "_id" : "43160", "city" : "WASHINGTON COURT", "loc" : [ -83.438817, 39.534346 ], "pop" : 21357, "state" : "OH" }
+{ "_id" : "43162", "city" : "WEST JEFFERSON", "loc" : [ -83.28530600000001, 39.942409 ], "pop" : 7411, "state" : "OH" }
+{ "_id" : "43164", "city" : "WILLIAMSPORT", "loc" : [ -83.12505299999999, 39.611739 ], "pop" : 2192, "state" : "OH" }
+{ "_id" : "43201", "city" : "COLUMBUS", "loc" : [ -83.004732, 39.995157 ], "pop" : 37110, "state" : "OH" }
+{ "_id" : "43202", "city" : "COLUMBUS", "loc" : [ -83.011842, 40.020084 ], "pop" : 21526, "state" : "OH" }
+{ "_id" : "43203", "city" : "COLUMBUS", "loc" : [ -82.969131, 39.971925 ], "pop" : 11047, "state" : "OH" }
+{ "_id" : "43204", "city" : "COLUMBUS", "loc" : [ -83.07799900000001, 39.952333 ], "pop" : 38794, "state" : "OH" }
+{ "_id" : "43205", "city" : "COLUMBUS", "loc" : [ -82.96435200000001, 39.956905 ], "pop" : 17567, "state" : "OH" }
+{ "_id" : "43206", "city" : "COLUMBUS", "loc" : [ -82.974845, 39.942639 ], "pop" : 26587, "state" : "OH" }
+{ "_id" : "43207", "city" : "COLUMBUS", "loc" : [ -82.97033399999999, 39.904565 ], "pop" : 44404, "state" : "OH" }
+{ "_id" : "43209", "city" : "BEXLEY", "loc" : [ -82.92659500000001, 39.958999 ], "pop" : 29574, "state" : "OH" }
+{ "_id" : "43210", "city" : "COLUMBUS", "loc" : [ -83.01640399999999, 40.002804 ], "pop" : 10690, "state" : "OH" }
+{ "_id" : "43211", "city" : "COLUMBUS", "loc" : [ -82.973196, 40.011792 ], "pop" : 28031, "state" : "OH" }
+{ "_id" : "43212", "city" : "COLUMBUS", "loc" : [ -83.045579, 39.987381 ], "pop" : 18478, "state" : "OH" }
+{ "_id" : "43213", "city" : "WHITEHALL", "loc" : [ -82.878275, 39.967146 ], "pop" : 29375, "state" : "OH" }
+{ "_id" : "43214", "city" : "COLUMBUS", "loc" : [ -83.01875, 40.053482 ], "pop" : 26080, "state" : "OH" }
+{ "_id" : "43215", "city" : "COLUMBUS", "loc" : [ -83.004383, 39.967106 ], "pop" : 10145, "state" : "OH" }
+{ "_id" : "43217", "city" : "COLUMBUS", "loc" : [ -82.94748300000001, 39.806209 ], "pop" : 2150, "state" : "OH" }
+{ "_id" : "43219", "city" : "SHEPARD", "loc" : [ -82.936459, 40.004394 ], "pop" : 24841, "state" : "OH" }
+{ "_id" : "43220", "city" : "COLUMBUS", "loc" : [ -83.066911, 40.049484 ], "pop" : 24378, "state" : "OH" }
+{ "_id" : "43221", "city" : "UPPER ARLINGTON", "loc" : [ -83.064592, 40.015431 ], "pop" : 21283, "state" : "OH" }
+{ "_id" : "43222", "city" : "COLUMBUS", "loc" : [ -83.031109, 39.957628 ], "pop" : 7019, "state" : "OH" }
+{ "_id" : "43223", "city" : "COLUMBUS", "loc" : [ -83.046344, 39.938753 ], "pop" : 30538, "state" : "OH" }
+{ "_id" : "43224", "city" : "COLUMBUS", "loc" : [ -82.968947, 40.042493 ], "pop" : 41442, "state" : "OH" }
+{ "_id" : "43227", "city" : "COLUMBUS", "loc" : [ -82.890298, 39.944394 ], "pop" : 24945, "state" : "OH" }
+{ "_id" : "43228", "city" : "LINCOLN VILLAGE", "loc" : [ -83.123858, 39.947876 ], "pop" : 37615, "state" : "OH" }
+{ "_id" : "43229", "city" : "COLUMBUS", "loc" : [ -82.972568, 40.083886 ], "pop" : 45798, "state" : "OH" }
+{ "_id" : "43230", "city" : "GAHANNA", "loc" : [ -82.882429, 40.038458 ], "pop" : 34342, "state" : "OH" }
+{ "_id" : "43231", "city" : "COLUMBUS", "loc" : [ -82.938275, 40.080984 ], "pop" : 14519, "state" : "OH" }
+{ "_id" : "43232", "city" : "COLUMBUS", "loc" : [ -82.866432, 39.923024 ], "pop" : 38848, "state" : "OH" }
+{ "_id" : "43235", "city" : "WEST WORTHINGTON", "loc" : [ -83.059287, 40.101271 ], "pop" : 34051, "state" : "OH" }
+{ "_id" : "43302", "city" : "MARION", "loc" : [ -83.127056, 40.587648 ], "pop" : 50967, "state" : "OH" }
+{ "_id" : "43310", "city" : "BELLE CENTER", "loc" : [ -83.768773, 40.502371 ], "pop" : 2057, "state" : "OH" }
+{ "_id" : "43311", "city" : "BELLEFONTAINE", "loc" : [ -83.757076, 40.360472 ], "pop" : 16796, "state" : "OH" }
+{ "_id" : "43314", "city" : "CALEDONIA", "loc" : [ -82.992465, 40.627239 ], "pop" : 3120, "state" : "OH" }
+{ "_id" : "43315", "city" : "CARDINGTON", "loc" : [ -82.933728, 40.506583 ], "pop" : 4739, "state" : "OH" }
+{ "_id" : "43316", "city" : "CAREY", "loc" : [ -83.383578, 40.948599 ], "pop" : 6177, "state" : "OH" }
+{ "_id" : "43318", "city" : "DE GRAFF", "loc" : [ -83.9153, 40.305773 ], "pop" : 3452, "state" : "OH" }
+{ "_id" : "43319", "city" : "EAST LIBERTY", "loc" : [ -83.58622099999999, 40.307682 ], "pop" : 1351, "state" : "OH" }
+{ "_id" : "43320", "city" : "EDISON", "loc" : [ -82.90230099999999, 40.590475 ], "pop" : 1319, "state" : "OH" }
+{ "_id" : "43321", "city" : "FULTON", "loc" : [ -82.83624399999999, 40.465013 ], "pop" : 1181, "state" : "OH" }
+{ "_id" : "43323", "city" : "HARPSTER", "loc" : [ -83.23428, 40.747541 ], "pop" : 719, "state" : "OH" }
+{ "_id" : "43324", "city" : "HUNTSVILLE", "loc" : [ -83.792748, 40.441295 ], "pop" : 1953, "state" : "OH" }
+{ "_id" : "43326", "city" : "KENTON", "loc" : [ -83.611087, 40.640433 ], "pop" : 15332, "state" : "OH" }
+{ "_id" : "43331", "city" : "LAKEVIEW", "loc" : [ -83.90813900000001, 40.503033 ], "pop" : 5722, "state" : "OH" }
+{ "_id" : "43332", "city" : "LA RUE", "loc" : [ -83.373397, 40.578879 ], "pop" : 2120, "state" : "OH" }
+{ "_id" : "43333", "city" : "LEWISTOWN", "loc" : [ -83.92089300000001, 40.42768 ], "pop" : 958, "state" : "OH" }
+{ "_id" : "43334", "city" : "MARENGO", "loc" : [ -82.812136, 40.389512 ], "pop" : 3338, "state" : "OH" }
+{ "_id" : "43335", "city" : "MARTEL", "loc" : [ -82.90586, 40.670775 ], "pop" : 659, "state" : "OH" }
+{ "_id" : "43337", "city" : "MORRAL", "loc" : [ -83.204606, 40.695366 ], "pop" : 1035, "state" : "OH" }
+{ "_id" : "43338", "city" : "MOUNT GILEAD", "loc" : [ -82.806235, 40.538371 ], "pop" : 8271, "state" : "OH" }
+{ "_id" : "43340", "city" : "MOUNT VICTORY", "loc" : [ -83.494165, 40.52321 ], "pop" : 1015, "state" : "OH" }
+{ "_id" : "43341", "city" : "NEW BLOOMINGTON", "loc" : [ -83.322351, 40.607301 ], "pop" : 1428, "state" : "OH" }
+{ "_id" : "43342", "city" : "PROSPECT", "loc" : [ -83.176295, 40.472659 ], "pop" : 3365, "state" : "OH" }
+{ "_id" : "43343", "city" : "QUINCY", "loc" : [ -83.974411, 40.287606 ], "pop" : 1147, "state" : "OH" }
+{ "_id" : "43344", "city" : "RICHWOOD", "loc" : [ -83.31363899999999, 40.43698 ], "pop" : 4055, "state" : "OH" }
+{ "_id" : "43345", "city" : "RIDGEWAY", "loc" : [ -83.570161, 40.520923 ], "pop" : 857, "state" : "OH" }
+{ "_id" : "43346", "city" : "ROUNDHEAD", "loc" : [ -83.848502, 40.580337 ], "pop" : 641, "state" : "OH" }
+{ "_id" : "43347", "city" : "RUSHSYLVANIA", "loc" : [ -83.659789, 40.465808 ], "pop" : 1544, "state" : "OH" }
+{ "_id" : "43348", "city" : "RUSSELLS POINT", "loc" : [ -83.879825, 40.474956 ], "pop" : 2416, "state" : "OH" }
+{ "_id" : "43350", "city" : "SPARTA", "loc" : [ -82.697034, 40.373492 ], "pop" : 966, "state" : "OH" }
+{ "_id" : "43351", "city" : "UPPER SANDUSKY", "loc" : [ -83.29771100000001, 40.824876 ], "pop" : 9778, "state" : "OH" }
+{ "_id" : "43356", "city" : "WALDO", "loc" : [ -83.070609, 40.460544 ], "pop" : 1170, "state" : "OH" }
+{ "_id" : "43357", "city" : "WEST LIBERTY", "loc" : [ -83.752763, 40.262541 ], "pop" : 4148, "state" : "OH" }
+{ "_id" : "43358", "city" : "WEST MANSFIELD", "loc" : [ -83.52427400000001, 40.404284 ], "pop" : 2580, "state" : "OH" }
+{ "_id" : "43359", "city" : "WHARTON", "loc" : [ -83.463016, 40.861216 ], "pop" : 378, "state" : "OH" }
+{ "_id" : "43360", "city" : "ZANESFIELD", "loc" : [ -83.664832, 40.302396 ], "pop" : 1171, "state" : "OH" }
+{ "_id" : "43402", "city" : "BOWLING GREEN", "loc" : [ -83.650749, 41.381513 ], "pop" : 34468, "state" : "OH" }
+{ "_id" : "43406", "city" : "BRADNER", "loc" : [ -83.4456, 41.329789 ], "pop" : 1934, "state" : "OH" }
+{ "_id" : "43407", "city" : "BURGOON", "loc" : [ -83.247455, 41.267986 ], "pop" : 572, "state" : "OH" }
+{ "_id" : "43410", "city" : "CLYDE", "loc" : [ -82.991849, 41.302397 ], "pop" : 9650, "state" : "OH" }
+{ "_id" : "43412", "city" : "CURTICE", "loc" : [ -83.285825, 41.647736 ], "pop" : 2426, "state" : "OH" }
+{ "_id" : "43413", "city" : "CYGNET", "loc" : [ -83.61415100000001, 41.247024 ], "pop" : 1516, "state" : "OH" }
+{ "_id" : "43416", "city" : "ELMORE", "loc" : [ -83.27673, 41.468144 ], "pop" : 3230, "state" : "OH" }
+{ "_id" : "43420", "city" : "FREMONT", "loc" : [ -83.118095, 41.349792 ], "pop" : 31615, "state" : "OH" }
+{ "_id" : "43430", "city" : "GENOA", "loc" : [ -83.35898400000001, 41.530005 ], "pop" : 5405, "state" : "OH" }
+{ "_id" : "43431", "city" : "GIBSONBURG", "loc" : [ -83.335762, 41.380474 ], "pop" : 3874, "state" : "OH" }
+{ "_id" : "43432", "city" : "ELLISTON", "loc" : [ -83.261135, 41.527136 ], "pop" : 115, "state" : "OH" }
+{ "_id" : "43435", "city" : "MILLERSVILLE", "loc" : [ -83.323184, 41.318005 ], "pop" : 1427, "state" : "OH" }
+{ "_id" : "43436", "city" : "ISLE SAINT GEORG", "loc" : [ -82.819275, 41.713668 ], "pop" : 38, "state" : "OH" }
+{ "_id" : "43438", "city" : "KELLEYS ISLAND", "loc" : [ -82.706811, 41.600755 ], "pop" : 172, "state" : "OH" }
+{ "_id" : "43439", "city" : "LACARNE", "loc" : [ -83.02400400000001, 41.527846 ], "pop" : 1457, "state" : "OH" }
+{ "_id" : "43440", "city" : "LAKESIDE", "loc" : [ -82.77139200000001, 41.52913 ], "pop" : 4410, "state" : "OH" }
+{ "_id" : "43442", "city" : "LINDSEY", "loc" : [ -83.21347400000001, 41.414747 ], "pop" : 1646, "state" : "OH" }
+{ "_id" : "43443", "city" : "LUCKEY", "loc" : [ -83.46739599999999, 41.451669 ], "pop" : 1771, "state" : "OH" }
+{ "_id" : "43445", "city" : "BONO", "loc" : [ -83.345536, 41.596249 ], "pop" : 3895, "state" : "OH" }
+{ "_id" : "43447", "city" : "MILLBURY", "loc" : [ -83.43808300000001, 41.56106 ], "pop" : 3100, "state" : "OH" }
+{ "_id" : "43449", "city" : "OAK HARBOR", "loc" : [ -83.127764, 41.523556 ], "pop" : 9620, "state" : "OH" }
+{ "_id" : "43450", "city" : "PEMBERVILLE", "loc" : [ -83.473642, 41.402258 ], "pop" : 2569, "state" : "OH" }
+{ "_id" : "43451", "city" : "PORTAGE", "loc" : [ -83.614299, 41.312702 ], "pop" : 1304, "state" : "OH" }
+{ "_id" : "43452", "city" : "PORT CLINTON", "loc" : [ -82.909368, 41.521535 ], "pop" : 11851, "state" : "OH" }
+{ "_id" : "43456", "city" : "PUT IN BAY", "loc" : [ -82.822593, 41.651356 ], "pop" : 518, "state" : "OH" }
+{ "_id" : "43457", "city" : "RISINGSUN", "loc" : [ -83.43259, 41.270639 ], "pop" : 1756, "state" : "OH" }
+{ "_id" : "43460", "city" : "ROSSFORD", "loc" : [ -83.563793, 41.604908 ], "pop" : 5861, "state" : "OH" }
+{ "_id" : "43462", "city" : "RUDOLPH", "loc" : [ -83.683212, 41.296734 ], "pop" : 1737, "state" : "OH" }
+{ "_id" : "43464", "city" : "VICKERY", "loc" : [ -82.89895300000001, 41.39099 ], "pop" : 1976, "state" : "OH" }
+{ "_id" : "43465", "city" : "WALBRIDGE", "loc" : [ -83.493008, 41.586067 ], "pop" : 4597, "state" : "OH" }
+{ "_id" : "43466", "city" : "WAYNE", "loc" : [ -83.47006500000001, 41.299312 ], "pop" : 1572, "state" : "OH" }
+{ "_id" : "43469", "city" : "WOODVILLE", "loc" : [ -83.364643, 41.451206 ], "pop" : 2968, "state" : "OH" }
+{ "_id" : "43501", "city" : "ALVORDTON", "loc" : [ -84.43553300000001, 41.662489 ], "pop" : 954, "state" : "OH" }
+{ "_id" : "43502", "city" : "ARCHBOLD", "loc" : [ -84.304833, 41.533255 ], "pop" : 6565, "state" : "OH" }
+{ "_id" : "43504", "city" : "BERKEY", "loc" : [ -83.830972, 41.698892 ], "pop" : 843, "state" : "OH" }
+{ "_id" : "43506", "city" : "BRYAN", "loc" : [ -84.56287, 41.474839 ], "pop" : 14693, "state" : "OH" }
+{ "_id" : "43511", "city" : "CUSTAR", "loc" : [ -83.834919, 41.295318 ], "pop" : 1049, "state" : "OH" }
+{ "_id" : "43512", "city" : "DEFIANCE", "loc" : [ -84.362583, 41.279858 ], "pop" : 29859, "state" : "OH" }
+{ "_id" : "43515", "city" : "DELTA", "loc" : [ -83.9866, 41.557695 ], "pop" : 11110, "state" : "OH" }
+{ "_id" : "43516", "city" : "DESHLER", "loc" : [ -83.896434, 41.223945 ], "pop" : 4043, "state" : "OH" }
+{ "_id" : "43517", "city" : "EDGERTON", "loc" : [ -84.734937, 41.442496 ], "pop" : 3663, "state" : "OH" }
+{ "_id" : "43518", "city" : "EDON", "loc" : [ -84.757002, 41.584219 ], "pop" : 2688, "state" : "OH" }
+{ "_id" : "43521", "city" : "FAYETTE", "loc" : [ -84.32500400000001, 41.671716 ], "pop" : 2248, "state" : "OH" }
+{ "_id" : "43522", "city" : "GRAND RAPIDS", "loc" : [ -83.85524599999999, 41.437855 ], "pop" : 3362, "state" : "OH" }
+{ "_id" : "43524", "city" : "HAMLER", "loc" : [ -84.071989, 41.212874 ], "pop" : 1949, "state" : "OH" }
+{ "_id" : "43525", "city" : "HASKINS", "loc" : [ -83.70585800000001, 41.465159 ], "pop" : 549, "state" : "OH" }
+{ "_id" : "43526", "city" : "HICKSVILLE", "loc" : [ -84.758852, 41.303378 ], "pop" : 5541, "state" : "OH" }
+{ "_id" : "43527", "city" : "HOLGATE", "loc" : [ -84.144735, 41.254859 ], "pop" : 2032, "state" : "OH" }
+{ "_id" : "43528", "city" : "HOLLAND", "loc" : [ -83.725712, 41.622629 ], "pop" : 10773, "state" : "OH" }
+{ "_id" : "43532", "city" : "LIBERTY CENTER", "loc" : [ -83.985889, 41.451371 ], "pop" : 3933, "state" : "OH" }
+{ "_id" : "43533", "city" : "LYONS", "loc" : [ -84.06235100000001, 41.690546 ], "pop" : 1395, "state" : "OH" }
+{ "_id" : "43534", "city" : "MC CLURE", "loc" : [ -83.942482, 41.377309 ], "pop" : 1876, "state" : "OH" }
+{ "_id" : "43535", "city" : "MALINTA", "loc" : [ -84.045731, 41.308425 ], "pop" : 1121, "state" : "OH" }
+{ "_id" : "43536", "city" : "MARK CENTER", "loc" : [ -84.62778, 41.291669 ], "pop" : 963, "state" : "OH" }
+{ "_id" : "43537", "city" : "MAUMEE", "loc" : [ -83.66283, 41.581682 ], "pop" : 22993, "state" : "OH" }
+{ "_id" : "43540", "city" : "METAMORA", "loc" : [ -83.925972, 41.695233 ], "pop" : 1531, "state" : "OH" }
+{ "_id" : "43542", "city" : "MONCLOVA", "loc" : [ -83.775718, 41.568416 ], "pop" : 2286, "state" : "OH" }
+{ "_id" : "43543", "city" : "MONTPELIER", "loc" : [ -84.61470300000001, 41.59821 ], "pop" : 7569, "state" : "OH" }
+{ "_id" : "43545", "city" : "NAPOLEON", "loc" : [ -84.143271, 41.390969 ], "pop" : 14196, "state" : "OH" }
+{ "_id" : "43548", "city" : "NEW BAVARIA", "loc" : [ -84.19133600000001, 41.208649 ], "pop" : 523, "state" : "OH" }
+{ "_id" : "43549", "city" : "NEY", "loc" : [ -84.526921, 41.378083 ], "pop" : 1801, "state" : "OH" }
+{ "_id" : "43551", "city" : "PERRYSBURG", "loc" : [ -83.592727, 41.542926 ], "pop" : 29621, "state" : "OH" }
+{ "_id" : "43554", "city" : "PIONEER", "loc" : [ -84.53632399999999, 41.665619 ], "pop" : 2350, "state" : "OH" }
+{ "_id" : "43556", "city" : "SHERWOOD", "loc" : [ -84.541674, 41.294593 ], "pop" : 1686, "state" : "OH" }
+{ "_id" : "43557", "city" : "STRYKER", "loc" : [ -84.408914, 41.486123 ], "pop" : 2607, "state" : "OH" }
+{ "_id" : "43558", "city" : "SWANTON", "loc" : [ -83.871821, 41.594497 ], "pop" : 10729, "state" : "OH" }
+{ "_id" : "43560", "city" : "SYLVANIA", "loc" : [ -83.70682499999999, 41.707985 ], "pop" : 24564, "state" : "OH" }
+{ "_id" : "43566", "city" : "WATERVILLE", "loc" : [ -83.733142, 41.502248 ], "pop" : 5918, "state" : "OH" }
+{ "_id" : "43567", "city" : "WAUSEON", "loc" : [ -84.153745, 41.566796 ], "pop" : 10493, "state" : "OH" }
+{ "_id" : "43569", "city" : "WESTON", "loc" : [ -83.797336, 41.351593 ], "pop" : 2560, "state" : "OH" }
+{ "_id" : "43570", "city" : "WEST UNITY", "loc" : [ -84.442066, 41.575645 ], "pop" : 3305, "state" : "OH" }
+{ "_id" : "43571", "city" : "WHITEHOUSE", "loc" : [ -83.81151, 41.519432 ], "pop" : 5199, "state" : "OH" }
+{ "_id" : "43602", "city" : "TOLEDO", "loc" : [ -83.55474700000001, 41.647984 ], "pop" : 4084, "state" : "OH" }
+{ "_id" : "43604", "city" : "TOLEDO", "loc" : [ -83.52494900000001, 41.661415 ], "pop" : 5506, "state" : "OH" }
+{ "_id" : "43605", "city" : "OREGON", "loc" : [ -83.51234100000001, 41.640701 ], "pop" : 33168, "state" : "OH" }
+{ "_id" : "43606", "city" : "TOLEDO", "loc" : [ -83.605992, 41.671213 ], "pop" : 29111, "state" : "OH" }
+{ "_id" : "43607", "city" : "TOLEDO", "loc" : [ -83.597419, 41.650417 ], "pop" : 30240, "state" : "OH" }
+{ "_id" : "43608", "city" : "TOLEDO", "loc" : [ -83.53435899999999, 41.677908 ], "pop" : 21427, "state" : "OH" }
+{ "_id" : "43609", "city" : "TOLEDO", "loc" : [ -83.577282, 41.629761 ], "pop" : 29228, "state" : "OH" }
+{ "_id" : "43610", "city" : "TOLEDO", "loc" : [ -83.557303, 41.676693 ], "pop" : 8374, "state" : "OH" }
+{ "_id" : "43611", "city" : "TOLEDO", "loc" : [ -83.489203, 41.704507 ], "pop" : 23349, "state" : "OH" }
+{ "_id" : "43612", "city" : "TOLEDO", "loc" : [ -83.565622, 41.704567 ], "pop" : 33408, "state" : "OH" }
+{ "_id" : "43613", "city" : "TOLEDO", "loc" : [ -83.603397, 41.703913 ], "pop" : 35327, "state" : "OH" }
+{ "_id" : "43614", "city" : "TOLEDO", "loc" : [ -83.62917, 41.60279 ], "pop" : 31020, "state" : "OH" }
+{ "_id" : "43615", "city" : "TOLEDO", "loc" : [ -83.67058299999999, 41.649197 ], "pop" : 38173, "state" : "OH" }
+{ "_id" : "43616", "city" : "OREGON", "loc" : [ -83.471366, 41.641842 ], "pop" : 15713, "state" : "OH" }
+{ "_id" : "43617", "city" : "TOLEDO", "loc" : [ -83.716967, 41.666765 ], "pop" : 7449, "state" : "OH" }
+{ "_id" : "43618", "city" : "OREGON", "loc" : [ -83.392302, 41.665636 ], "pop" : 3379, "state" : "OH" }
+{ "_id" : "43619", "city" : "NORTHWOOD", "loc" : [ -83.48056, 41.607986 ], "pop" : 7526, "state" : "OH" }
+{ "_id" : "43620", "city" : "TOLEDO", "loc" : [ -83.553602, 41.66536 ], "pop" : 8471, "state" : "OH" }
+{ "_id" : "43623", "city" : "TOLEDO", "loc" : [ -83.64340799999999, 41.707968 ], "pop" : 21315, "state" : "OH" }
+{ "_id" : "43624", "city" : "TOLEDO", "loc" : [ -83.545005, 41.65627 ], "pop" : 1596, "state" : "OH" }
+{ "_id" : "43701", "city" : "SONORA", "loc" : [ -82.008898, 39.944265 ], "pop" : 56655, "state" : "OH" }
+{ "_id" : "43713", "city" : "SOMERTON", "loc" : [ -81.171295, 39.9812 ], "pop" : 7140, "state" : "OH" }
+{ "_id" : "43716", "city" : "BEALLSVILLE", "loc" : [ -81.014358, 39.872601 ], "pop" : 716, "state" : "OH" }
+{ "_id" : "43718", "city" : "BELMONT", "loc" : [ -81.006564, 40.03202 ], "pop" : 3229, "state" : "OH" }
+{ "_id" : "43719", "city" : "BETHESDA", "loc" : [ -81.076742, 40.019221 ], "pop" : 2464, "state" : "OH" }
+{ "_id" : "43720", "city" : "BLUE ROCK", "loc" : [ -81.891023, 39.799996 ], "pop" : 1001, "state" : "OH" }
+{ "_id" : "43723", "city" : "BYESVILLE", "loc" : [ -81.548485, 39.962336 ], "pop" : 5164, "state" : "OH" }
+{ "_id" : "43724", "city" : "CALDWELL", "loc" : [ -81.51528, 39.746651 ], "pop" : 7043, "state" : "OH" }
+{ "_id" : "43725", "city" : "CLAYSVILLE", "loc" : [ -81.59127700000001, 40.030501 ], "pop" : 21261, "state" : "OH" }
+{ "_id" : "43727", "city" : "CHANDLERSVILLE", "loc" : [ -81.830084, 39.889659 ], "pop" : 1368, "state" : "OH" }
+{ "_id" : "43728", "city" : "CHESTERHILL", "loc" : [ -81.877286, 39.495277 ], "pop" : 1323, "state" : "OH" }
+{ "_id" : "43730", "city" : "HEMLOCK", "loc" : [ -82.097737, 39.634902 ], "pop" : 3374, "state" : "OH" }
+{ "_id" : "43731", "city" : "CROOKSVILLE", "loc" : [ -82.084018, 39.762321 ], "pop" : 4609, "state" : "OH" }
+{ "_id" : "43732", "city" : "CUMBERLAND", "loc" : [ -81.625925, 39.874092 ], "pop" : 1831, "state" : "OH" }
+{ "_id" : "43734", "city" : "DUNCAN FALLS", "loc" : [ -81.911665, 39.877777 ], "pop" : 957, "state" : "OH" }
+{ "_id" : "43739", "city" : "GLENFORD", "loc" : [ -82.302592, 39.869935 ], "pop" : 1632, "state" : "OH" }
+{ "_id" : "43746", "city" : "HOPEWELL", "loc" : [ -82.175619, 39.96008 ], "pop" : 1160, "state" : "OH" }
+{ "_id" : "43747", "city" : "JERUSALEM", "loc" : [ -81.092088, 39.848831 ], "pop" : 2037, "state" : "OH" }
+{ "_id" : "43748", "city" : "JUNCTION CITY", "loc" : [ -82.31552499999999, 39.696531 ], "pop" : 2577, "state" : "OH" }
+{ "_id" : "43749", "city" : "GUERNSEY", "loc" : [ -81.53036, 40.166544 ], "pop" : 2109, "state" : "OH" }
+{ "_id" : "43754", "city" : "LEWISVILLE", "loc" : [ -81.231583, 39.768379 ], "pop" : 1366, "state" : "OH" }
+{ "_id" : "43755", "city" : "LORE CITY", "loc" : [ -81.44785299999999, 40.045854 ], "pop" : 1487, "state" : "OH" }
+{ "_id" : "43756", "city" : "MC CONNELSVILLE", "loc" : [ -81.837625, 39.670014 ], "pop" : 4784, "state" : "OH" }
+{ "_id" : "43758", "city" : "MALTA", "loc" : [ -81.912746, 39.648212 ], "pop" : 3127, "state" : "OH" }
+{ "_id" : "43760", "city" : "MOUNT PERRY", "loc" : [ -82.188039, 39.878798 ], "pop" : 1550, "state" : "OH" }
+{ "_id" : "43762", "city" : "NEW CONCORD", "loc" : [ -81.738727, 40.008798 ], "pop" : 4770, "state" : "OH" }
+{ "_id" : "43764", "city" : "NEW LEXINGTON", "loc" : [ -82.20188400000001, 39.717438 ], "pop" : 8536, "state" : "OH" }
+{ "_id" : "43766", "city" : "NEW STRAITSVILLE", "loc" : [ -82.24880400000001, 39.586872 ], "pop" : 1669, "state" : "OH" }
+{ "_id" : "43767", "city" : "NORWICH", "loc" : [ -81.802425, 39.993438 ], "pop" : 1142, "state" : "OH" }
+{ "_id" : "43771", "city" : "PHILO", "loc" : [ -81.917479, 39.845773 ], "pop" : 1374, "state" : "OH" }
+{ "_id" : "43772", "city" : "PLEASANT CITY", "loc" : [ -81.55797, 39.909514 ], "pop" : 1231, "state" : "OH" }
+{ "_id" : "43773", "city" : "QUAKER CITY", "loc" : [ -81.289883, 39.986576 ], "pop" : 2139, "state" : "OH" }
+{ "_id" : "43777", "city" : "ROSEVILLE", "loc" : [ -82.079212, 39.818656 ], "pop" : 4293, "state" : "OH" }
+{ "_id" : "43778", "city" : "SALESVILLE", "loc" : [ -81.372793, 40.008146 ], "pop" : 1009, "state" : "OH" }
+{ "_id" : "43779", "city" : "SARAHSVILLE", "loc" : [ -81.467825, 39.793846 ], "pop" : 947, "state" : "OH" }
+{ "_id" : "43780", "city" : "SENECAVILLE", "loc" : [ -81.458043, 39.933719 ], "pop" : 3014, "state" : "OH" }
+{ "_id" : "43782", "city" : "SHAWNEE", "loc" : [ -82.208459, 39.610984 ], "pop" : 1019, "state" : "OH" }
+{ "_id" : "43783", "city" : "SOMERSET", "loc" : [ -82.29911, 39.793615 ], "pop" : 2541, "state" : "OH" }
+{ "_id" : "43787", "city" : "PENNSVILLE", "loc" : [ -81.82525099999999, 39.561434 ], "pop" : 1865, "state" : "OH" }
+{ "_id" : "43788", "city" : "SUMMERFIELD", "loc" : [ -81.331993, 39.803597 ], "pop" : 1151, "state" : "OH" }
+{ "_id" : "43793", "city" : "ANTIOCH", "loc" : [ -81.10336, 39.753063 ], "pop" : 5231, "state" : "OH" }
+{ "_id" : "43802", "city" : "ADAMSVILLE", "loc" : [ -81.871847, 40.07929 ], "pop" : 943, "state" : "OH" }
+{ "_id" : "43804", "city" : "BALTIC", "loc" : [ -81.679171, 40.447568 ], "pop" : 2225, "state" : "OH" }
+{ "_id" : "43811", "city" : "CONESVILLE", "loc" : [ -81.89507399999999, 40.180441 ], "pop" : 696, "state" : "OH" }
+{ "_id" : "43812", "city" : "COSHOCTON", "loc" : [ -81.866033, 40.275412 ], "pop" : 21561, "state" : "OH" }
+{ "_id" : "43821", "city" : "ADAMS MILLS", "loc" : [ -82.018807, 40.112941 ], "pop" : 4204, "state" : "OH" }
+{ "_id" : "43822", "city" : "FRAZEYSBURG", "loc" : [ -82.129279, 40.131616 ], "pop" : 2746, "state" : "OH" }
+{ "_id" : "43824", "city" : "FRESNO", "loc" : [ -81.762297, 40.371126 ], "pop" : 2777, "state" : "OH" }
+{ "_id" : "43830", "city" : "NASHPORT", "loc" : [ -82.09976, 40.038588 ], "pop" : 3579, "state" : "OH" }
+{ "_id" : "43832", "city" : "NEWCOMERSTOWN", "loc" : [ -81.593969, 40.273895 ], "pop" : 7574, "state" : "OH" }
+{ "_id" : "43837", "city" : "PORT WASHINGTON", "loc" : [ -81.521518, 40.340359 ], "pop" : 1190, "state" : "OH" }
+{ "_id" : "43840", "city" : "STONE CREEK", "loc" : [ -81.589018, 40.405188 ], "pop" : 1208, "state" : "OH" }
+{ "_id" : "43843", "city" : "WALHONDING", "loc" : [ -82.20935900000001, 40.362037 ], "pop" : 937, "state" : "OH" }
+{ "_id" : "43844", "city" : "WARSAW", "loc" : [ -82.055989, 40.317243 ], "pop" : 3177, "state" : "OH" }
+{ "_id" : "43845", "city" : "WEST LAFAYETTE", "loc" : [ -81.736102, 40.271829 ], "pop" : 4667, "state" : "OH" }
+{ "_id" : "43901", "city" : "ADENA", "loc" : [ -80.88153800000001, 40.212581 ], "pop" : 1690, "state" : "OH" }
+{ "_id" : "43902", "city" : "ALLEDONIA", "loc" : [ -80.957753, 39.905271 ], "pop" : 499, "state" : "OH" }
+{ "_id" : "43903", "city" : "AMSTERDAM", "loc" : [ -80.959554, 40.473131 ], "pop" : 819, "state" : "OH" }
+{ "_id" : "43906", "city" : "BELLAIRE", "loc" : [ -80.763813, 40.020399 ], "pop" : 10480, "state" : "OH" }
+{ "_id" : "43907", "city" : "MOOREFIELD", "loc" : [ -80.996244, 40.264537 ], "pop" : 5925, "state" : "OH" }
+{ "_id" : "43908", "city" : "BERGHOLZ", "loc" : [ -80.88615299999999, 40.47771 ], "pop" : 3392, "state" : "OH" }
+{ "_id" : "43910", "city" : "BLOOMINGDALE", "loc" : [ -80.807214, 40.3742 ], "pop" : 3925, "state" : "OH" }
+{ "_id" : "43912", "city" : "BRIDGEPORT", "loc" : [ -80.774682, 40.075184 ], "pop" : 7706, "state" : "OH" }
+{ "_id" : "43913", "city" : "BRILLIANT", "loc" : [ -80.63194900000001, 40.268283 ], "pop" : 2057, "state" : "OH" }
+{ "_id" : "43915", "city" : "CLARINGTON", "loc" : [ -80.911311, 39.781908 ], "pop" : 1890, "state" : "OH" }
+{ "_id" : "43917", "city" : "DILLONVALE", "loc" : [ -80.802843, 40.212132 ], "pop" : 5972, "state" : "OH" }
+{ "_id" : "43920", "city" : "CALCUTTA", "loc" : [ -80.578669, 40.645918 ], "pop" : 25993, "state" : "OH" }
+{ "_id" : "43930", "city" : "HAMMONDSVILLE", "loc" : [ -80.729918, 40.579909 ], "pop" : 1060, "state" : "OH" }
+{ "_id" : "43932", "city" : "IRONDALE", "loc" : [ -80.791546, 40.511052 ], "pop" : 496, "state" : "OH" }
+{ "_id" : "43933", "city" : "ARMSTRONG MILLS", "loc" : [ -80.882181, 39.956304 ], "pop" : 1795, "state" : "OH" }
+{ "_id" : "43935", "city" : "MARTINS FERRY", "loc" : [ -80.736125, 40.103597 ], "pop" : 10605, "state" : "OH" }
+{ "_id" : "43938", "city" : "MINGO JUNCTION", "loc" : [ -80.625021, 40.320256 ], "pop" : 6388, "state" : "OH" }
+{ "_id" : "43942", "city" : "POWHATAN POINT", "loc" : [ -80.8168, 39.867935 ], "pop" : 2694, "state" : "OH" }
+{ "_id" : "43943", "city" : "RAYLAND", "loc" : [ -80.71253400000001, 40.208274 ], "pop" : 4623, "state" : "OH" }
+{ "_id" : "43944", "city" : "RICHMOND", "loc" : [ -80.76128, 40.426061 ], "pop" : 2326, "state" : "OH" }
+{ "_id" : "43945", "city" : "SALINEVILLE", "loc" : [ -80.83497699999999, 40.619525 ], "pop" : 3617, "state" : "OH" }
+{ "_id" : "43946", "city" : "SARDIS", "loc" : [ -80.924308, 39.652639 ], "pop" : 2785, "state" : "OH" }
+{ "_id" : "43947", "city" : "SHADYSIDE", "loc" : [ -80.764309, 39.967497 ], "pop" : 5918, "state" : "OH" }
+{ "_id" : "43950", "city" : "SAINT CLAIRSVILL", "loc" : [ -80.90228500000001, 40.083439 ], "pop" : 14292, "state" : "OH" }
+{ "_id" : "43952", "city" : "WINTERSVILLE", "loc" : [ -80.66115000000001, 40.370638 ], "pop" : 35873, "state" : "OH" }
+{ "_id" : "43963", "city" : "TILTONSVILLE", "loc" : [ -80.699647, 40.168075 ], "pop" : 872, "state" : "OH" }
+{ "_id" : "43964", "city" : "TORONTO", "loc" : [ -80.632504, 40.473298 ], "pop" : 11981, "state" : "OH" }
+{ "_id" : "43968", "city" : "WELLSVILLE", "loc" : [ -80.66209499999999, 40.617099 ], "pop" : 8315, "state" : "OH" }
+{ "_id" : "43971", "city" : "YORKVILLE", "loc" : [ -80.70773699999999, 40.158051 ], "pop" : 1213, "state" : "OH" }
+{ "_id" : "43973", "city" : "FREEPORT", "loc" : [ -81.276955, 40.192502 ], "pop" : 1905, "state" : "OH" }
+{ "_id" : "43976", "city" : "HOPEDALE", "loc" : [ -80.902136, 40.349647 ], "pop" : 1501, "state" : "OH" }
+{ "_id" : "43977", "city" : "FLUSHING", "loc" : [ -81.07572999999999, 40.145144 ], "pop" : 2719, "state" : "OH" }
+{ "_id" : "43983", "city" : "PIEDMONT", "loc" : [ -81.214494, 40.150716 ], "pop" : 420, "state" : "OH" }
+{ "_id" : "43986", "city" : "JEWETT", "loc" : [ -81.000379, 40.37446 ], "pop" : 1998, "state" : "OH" }
+{ "_id" : "43988", "city" : "SCIO", "loc" : [ -81.10157700000001, 40.40116 ], "pop" : 2640, "state" : "OH" }
+{ "_id" : "44001", "city" : "SOUTH AMHERST", "loc" : [ -82.228165, 41.390506 ], "pop" : 18839, "state" : "OH" }
+{ "_id" : "44003", "city" : "ANDOVER", "loc" : [ -80.575374, 41.622488 ], "pop" : 3491, "state" : "OH" }
+{ "_id" : "44004", "city" : "ASHTABULA", "loc" : [ -80.794681, 41.867877 ], "pop" : 37480, "state" : "OH" }
+{ "_id" : "44010", "city" : "AUSTINBURG", "loc" : [ -80.858422, 41.75536 ], "pop" : 1902, "state" : "OH" }
+{ "_id" : "44011", "city" : "AVON", "loc" : [ -82.020359, 41.446713 ], "pop" : 7332, "state" : "OH" }
+{ "_id" : "44012", "city" : "AVON LAKE", "loc" : [ -82.011094, 41.501904 ], "pop" : 15061, "state" : "OH" }
+{ "_id" : "44017", "city" : "BEREA", "loc" : [ -81.861756, 41.367557 ], "pop" : 18561, "state" : "OH" }
+{ "_id" : "44021", "city" : "BURTON", "loc" : [ -81.15262, 41.452702 ], "pop" : 6677, "state" : "OH" }
+{ "_id" : "44022", "city" : "CHAGRIN FALLS", "loc" : [ -81.361437, 41.418577 ], "pop" : 29184, "state" : "OH" }
+{ "_id" : "44024", "city" : "CHARDON", "loc" : [ -81.205629, 41.571862 ], "pop" : 20339, "state" : "OH" }
+{ "_id" : "44026", "city" : "CHESTERLAND", "loc" : [ -81.342102, 41.534378 ], "pop" : 12510, "state" : "OH" }
+{ "_id" : "44028", "city" : "COLUMBIA STATION", "loc" : [ -81.934398, 41.318708 ], "pop" : 8436, "state" : "OH" }
+{ "_id" : "44030", "city" : "CONNEAUT", "loc" : [ -80.580257, 41.934479 ], "pop" : 16612, "state" : "OH" }
+{ "_id" : "44032", "city" : "DORSET", "loc" : [ -80.668334, 41.658972 ], "pop" : 1536, "state" : "OH" }
+{ "_id" : "44035", "city" : "ELYRIA", "loc" : [ -82.10508799999999, 41.372353 ], "pop" : 66674, "state" : "OH" }
+{ "_id" : "44039", "city" : "NORTH RIDGEVILLE", "loc" : [ -82.00332299999999, 41.396432 ], "pop" : 21574, "state" : "OH" }
+{ "_id" : "44040", "city" : "GATES MILLS", "loc" : [ -81.415021, 41.532368 ], "pop" : 2879, "state" : "OH" }
+{ "_id" : "44041", "city" : "GENEVA", "loc" : [ -80.947363, 41.802864 ], "pop" : 14694, "state" : "OH" }
+{ "_id" : "44044", "city" : "GRAFTON", "loc" : [ -82.043098, 41.28537 ], "pop" : 12127, "state" : "OH" }
+{ "_id" : "44046", "city" : "HUNTSBURG", "loc" : [ -81.05718299999999, 41.530559 ], "pop" : 1804, "state" : "OH" }
+{ "_id" : "44047", "city" : "JEFFERSON", "loc" : [ -80.75616599999999, 41.733513 ], "pop" : 8242, "state" : "OH" }
+{ "_id" : "44048", "city" : "KINGSVILLE", "loc" : [ -80.66009200000001, 41.872311 ], "pop" : 2192, "state" : "OH" }
+{ "_id" : "44050", "city" : "LAGRANGE", "loc" : [ -82.12791799999999, 41.242278 ], "pop" : 5092, "state" : "OH" }
+{ "_id" : "44052", "city" : "LORAIN", "loc" : [ -82.17103899999999, 41.457796 ], "pop" : 35989, "state" : "OH" }
+{ "_id" : "44053", "city" : "LORAIN", "loc" : [ -82.203833, 41.432002 ], "pop" : 16141, "state" : "OH" }
+{ "_id" : "44054", "city" : "SHEFFIELD LAKE", "loc" : [ -82.096497, 41.482276 ], "pop" : 11685, "state" : "OH" }
+{ "_id" : "44055", "city" : "LORAIN", "loc" : [ -82.134992, 41.436131 ], "pop" : 22919, "state" : "OH" }
+{ "_id" : "44056", "city" : "MACEDONIA", "loc" : [ -81.499578, 41.322236 ], "pop" : 7470, "state" : "OH" }
+{ "_id" : "44057", "city" : "MADISON", "loc" : [ -81.058819, 41.805367 ], "pop" : 18357, "state" : "OH" }
+{ "_id" : "44060", "city" : "MENTOR", "loc" : [ -81.342133, 41.689468 ], "pop" : 60109, "state" : "OH" }
+{ "_id" : "44062", "city" : "MIDDLEFIELD", "loc" : [ -81.03733800000001, 41.445547 ], "pop" : 11700, "state" : "OH" }
+{ "_id" : "44064", "city" : "MONTVILLE", "loc" : [ -81.057036, 41.603446 ], "pop" : 1867, "state" : "OH" }
+{ "_id" : "44065", "city" : "NEWBURY", "loc" : [ -81.23452, 41.475022 ], "pop" : 2907, "state" : "OH" }
+{ "_id" : "44067", "city" : "NORTHFIELD", "loc" : [ -81.54294299999999, 41.320821 ], "pop" : 14014, "state" : "OH" }
+{ "_id" : "44070", "city" : "NORTH OLMSTED", "loc" : [ -81.913056, 41.420129 ], "pop" : 34123, "state" : "OH" }
+{ "_id" : "44072", "city" : "NOVELTY", "loc" : [ -81.334228, 41.476288 ], "pop" : 4736, "state" : "OH" }
+{ "_id" : "44074", "city" : "OBERLIN", "loc" : [ -82.222863, 41.28987 ], "pop" : 11631, "state" : "OH" }
+{ "_id" : "44076", "city" : "EAST ORWELL", "loc" : [ -80.839671, 41.533456 ], "pop" : 3814, "state" : "OH" }
+{ "_id" : "44077", "city" : "FAIRPORT HARBOR", "loc" : [ -81.24366499999999, 41.714014 ], "pop" : 43783, "state" : "OH" }
+{ "_id" : "44081", "city" : "PERRY", "loc" : [ -81.14331199999999, 41.767916 ], "pop" : 5571, "state" : "OH" }
+{ "_id" : "44082", "city" : "PIERPONT", "loc" : [ -80.57411399999999, 41.767661 ], "pop" : 1460, "state" : "OH" }
+{ "_id" : "44084", "city" : "ROAMING SHORES", "loc" : [ -80.88513399999999, 41.6651 ], "pop" : 2979, "state" : "OH" }
+{ "_id" : "44085", "city" : "ROAMING SHORES", "loc" : [ -80.832075, 41.602629 ], "pop" : 1810, "state" : "OH" }
+{ "_id" : "44086", "city" : "THOMPSON", "loc" : [ -81.057318, 41.676189 ], "pop" : 2668, "state" : "OH" }
+{ "_id" : "44087", "city" : "TWINSBURG", "loc" : [ -81.455912, 41.328851 ], "pop" : 11274, "state" : "OH" }
+{ "_id" : "44089", "city" : "VERMILION", "loc" : [ -82.355417, 41.409989 ], "pop" : 15058, "state" : "OH" }
+{ "_id" : "44090", "city" : "WELLINGTON", "loc" : [ -82.22691500000001, 41.171178 ], "pop" : 9870, "state" : "OH" }
+{ "_id" : "44092", "city" : "WICKLIFFE", "loc" : [ -81.46917500000001, 41.604565 ], "pop" : 18334, "state" : "OH" }
+{ "_id" : "44093", "city" : "WILLIAMSFIELD", "loc" : [ -80.596378, 41.538296 ], "pop" : 1817, "state" : "OH" }
+{ "_id" : "44094", "city" : "WILLOUGHBY", "loc" : [ -81.407619, 41.630229 ], "pop" : 30153, "state" : "OH" }
+{ "_id" : "44095", "city" : "WILLOWICK", "loc" : [ -81.44788699999999, 41.649822 ], "pop" : 37473, "state" : "OH" }
+{ "_id" : "44099", "city" : "WINDSOR", "loc" : [ -80.966745, 41.56233 ], "pop" : 2085, "state" : "OH" }
+{ "_id" : "44102", "city" : "CLEVELAND", "loc" : [ -81.739791, 41.473508 ], "pop" : 53416, "state" : "OH" }
+{ "_id" : "44103", "city" : "CLEVELAND", "loc" : [ -81.640475, 41.515726 ], "pop" : 28288, "state" : "OH" }
+{ "_id" : "44104", "city" : "CLEVELAND", "loc" : [ -81.62450200000001, 41.480924 ], "pop" : 34766, "state" : "OH" }
+{ "_id" : "44105", "city" : "CLEVELAND", "loc" : [ -81.61900199999999, 41.450912 ], "pop" : 56341, "state" : "OH" }
+{ "_id" : "44106", "city" : "CLEVELAND", "loc" : [ -81.60757, 41.508359 ], "pop" : 35787, "state" : "OH" }
+{ "_id" : "44107", "city" : "EDGEWATER", "loc" : [ -81.79714300000001, 41.482654 ], "pop" : 59702, "state" : "OH" }
+{ "_id" : "44108", "city" : "CLEVELAND", "loc" : [ -81.608974, 41.53492 ], "pop" : 40401, "state" : "OH" }
+{ "_id" : "44109", "city" : "CLEVELAND", "loc" : [ -81.703315, 41.445768 ], "pop" : 47515, "state" : "OH" }
+{ "_id" : "44110", "city" : "CLEVELAND", "loc" : [ -81.57327600000001, 41.563557 ], "pop" : 26613, "state" : "OH" }
+{ "_id" : "44111", "city" : "CLEVELAND", "loc" : [ -81.78435, 41.457066 ], "pop" : 43366, "state" : "OH" }
+{ "_id" : "44112", "city" : "EAST CLEVELAND", "loc" : [ -81.576262, 41.535517 ], "pop" : 41340, "state" : "OH" }
+{ "_id" : "44113", "city" : "CLEVELAND", "loc" : [ -81.701848, 41.481648 ], "pop" : 20211, "state" : "OH" }
+{ "_id" : "44114", "city" : "CLEVELAND", "loc" : [ -81.67425, 41.506351 ], "pop" : 4673, "state" : "OH" }
+{ "_id" : "44115", "city" : "CLEVELAND", "loc" : [ -81.66700899999999, 41.494574 ], "pop" : 7035, "state" : "OH" }
+{ "_id" : "44116", "city" : "ROCKY RIVER", "loc" : [ -81.851246, 41.469401 ], "pop" : 20410, "state" : "OH" }
+{ "_id" : "44117", "city" : "EUCLID", "loc" : [ -81.52568599999999, 41.569615 ], "pop" : 12371, "state" : "OH" }
+{ "_id" : "44118", "city" : "CLEVELAND HEIGHT", "loc" : [ -81.553945, 41.501213 ], "pop" : 45619, "state" : "OH" }
+{ "_id" : "44119", "city" : "CLEVELAND", "loc" : [ -81.54675899999999, 41.588238 ], "pop" : 13654, "state" : "OH" }
+{ "_id" : "44120", "city" : "CLEVELAND", "loc" : [ -81.583911, 41.471433 ], "pop" : 49357, "state" : "OH" }
+{ "_id" : "44121", "city" : "SOUTH EUCLID", "loc" : [ -81.53375800000001, 41.526019 ], "pop" : 37107, "state" : "OH" }
+{ "_id" : "44122", "city" : "BEACHWOOD", "loc" : [ -81.523172, 41.470109 ], "pop" : 35115, "state" : "OH" }
+{ "_id" : "44123", "city" : "SHORE", "loc" : [ -81.524325, 41.604416 ], "pop" : 18724, "state" : "OH" }
+{ "_id" : "44124", "city" : "LYNDHURST MAYFIE", "loc" : [ -81.46801000000001, 41.514349 ], "pop" : 41699, "state" : "OH" }
+{ "_id" : "44125", "city" : "GARFIELD HEIGHTS", "loc" : [ -81.605385, 41.415792 ], "pop" : 31020, "state" : "OH" }
+{ "_id" : "44126", "city" : "FAIRVIEW PARK", "loc" : [ -81.856381, 41.4433 ], "pop" : 18145, "state" : "OH" }
+{ "_id" : "44127", "city" : "CLEVELAND", "loc" : [ -81.648999, 41.470125 ], "pop" : 9046, "state" : "OH" }
+{ "_id" : "44128", "city" : "CLEVELAND", "loc" : [ -81.548574, 41.441565 ], "pop" : 35258, "state" : "OH" }
+{ "_id" : "44129", "city" : "PARMA", "loc" : [ -81.734604, 41.396474 ], "pop" : 30370, "state" : "OH" }
+{ "_id" : "44130", "city" : "MIDPARK", "loc" : [ -81.77485799999999, 41.377178 ], "pop" : 52198, "state" : "OH" }
+{ "_id" : "44131", "city" : "INDEPENDENCE", "loc" : [ -81.66421, 41.380905 ], "pop" : 20594, "state" : "OH" }
+{ "_id" : "44132", "city" : "NOBLE", "loc" : [ -81.499056, 41.608516 ], "pop" : 16398, "state" : "OH" }
+{ "_id" : "44133", "city" : "NORTH ROYALTON", "loc" : [ -81.74565699999999, 41.323164 ], "pop" : 23197, "state" : "OH" }
+{ "_id" : "44134", "city" : "PARMA", "loc" : [ -81.705726, 41.390764 ], "pop" : 41397, "state" : "OH" }
+{ "_id" : "44135", "city" : "CLEVELAND", "loc" : [ -81.804433, 41.434177 ], "pop" : 31032, "state" : "OH" }
+{ "_id" : "44136", "city" : "STRONGSVILLE", "loc" : [ -81.828457, 41.313218 ], "pop" : 35308, "state" : "OH" }
+{ "_id" : "44137", "city" : "MAPLE HEIGHTS", "loc" : [ -81.560339, 41.410513 ], "pop" : 26945, "state" : "OH" }
+{ "_id" : "44138", "city" : "OLMSTED FALLS", "loc" : [ -81.915769, 41.373351 ], "pop" : 15722, "state" : "OH" }
+{ "_id" : "44139", "city" : "SOLON", "loc" : [ -81.442082, 41.386597 ], "pop" : 18830, "state" : "OH" }
+{ "_id" : "44140", "city" : "BAY VILLAGE", "loc" : [ -81.92886799999999, 41.484137 ], "pop" : 17000, "state" : "OH" }
+{ "_id" : "44141", "city" : "BRECKSVILLE", "loc" : [ -81.62608299999999, 41.316554 ], "pop" : 12172, "state" : "OH" }
+{ "_id" : "44142", "city" : "BROOKPARK", "loc" : [ -81.81181100000001, 41.397944 ], "pop" : 22865, "state" : "OH" }
+{ "_id" : "44143", "city" : "RICHMOND HEIGHTS", "loc" : [ -81.48471499999999, 41.552195 ], "pop" : 21114, "state" : "OH" }
+{ "_id" : "44144", "city" : "BROOKLYN", "loc" : [ -81.73522199999999, 41.434419 ], "pop" : 22288, "state" : "OH" }
+{ "_id" : "44145", "city" : "WESTLAKE", "loc" : [ -81.92177100000001, 41.453459 ], "pop" : 27099, "state" : "OH" }
+{ "_id" : "44146", "city" : "BEDFORD", "loc" : [ -81.52315, 41.392067 ], "pop" : 33014, "state" : "OH" }
+{ "_id" : "44147", "city" : "BROADVIEW HEIGHT", "loc" : [ -81.680879, 41.32907 ], "pop" : 11951, "state" : "OH" }
+{ "_id" : "44201", "city" : "ATWATER", "loc" : [ -81.19845599999999, 41.033487 ], "pop" : 7081, "state" : "OH" }
+{ "_id" : "44202", "city" : "REMINDERVILLE", "loc" : [ -81.36042399999999, 41.320935 ], "pop" : 11547, "state" : "OH" }
+{ "_id" : "44203", "city" : "NORTON", "loc" : [ -81.615314, 41.018589 ], "pop" : 42160, "state" : "OH" }
+{ "_id" : "44212", "city" : "BRUNSWICK", "loc" : [ -81.827968, 41.247053 ], "pop" : 32435, "state" : "OH" }
+{ "_id" : "44214", "city" : "BURBANK", "loc" : [ -81.99575299999999, 40.963725 ], "pop" : 1298, "state" : "OH" }
+{ "_id" : "44215", "city" : "CHIPPEWA LAKE", "loc" : [ -81.909173, 41.06719 ], "pop" : 2714, "state" : "OH" }
+{ "_id" : "44216", "city" : "CLINTON", "loc" : [ -81.587079, 40.939062 ], "pop" : 8830, "state" : "OH" }
+{ "_id" : "44217", "city" : "CRESTON", "loc" : [ -81.921083, 40.978846 ], "pop" : 6602, "state" : "OH" }
+{ "_id" : "44221", "city" : "CUYAHOGA FALLS", "loc" : [ -81.478961, 41.140082 ], "pop" : 32009, "state" : "OH" }
+{ "_id" : "44223", "city" : "CUYAHOGA FALLS", "loc" : [ -81.51071899999999, 41.146448 ], "pop" : 14757, "state" : "OH" }
+{ "_id" : "44224", "city" : "STOW", "loc" : [ -81.438017, 41.174808 ], "pop" : 31912, "state" : "OH" }
+{ "_id" : "44230", "city" : "DOYLESTOWN", "loc" : [ -81.684845, 40.965042 ], "pop" : 7451, "state" : "OH" }
+{ "_id" : "44231", "city" : "GARRETTSVILLE", "loc" : [ -81.070365, 41.298803 ], "pop" : 7352, "state" : "OH" }
+{ "_id" : "44233", "city" : "HINCKLEY", "loc" : [ -81.74527, 41.241872 ], "pop" : 5845, "state" : "OH" }
+{ "_id" : "44234", "city" : "HIRAM", "loc" : [ -81.14644, 41.332253 ], "pop" : 3775, "state" : "OH" }
+{ "_id" : "44235", "city" : "HOMERVILLE", "loc" : [ -82.12495699999999, 41.02669 ], "pop" : 1196, "state" : "OH" }
+{ "_id" : "44236", "city" : "HUDSON", "loc" : [ -81.43665900000001, 41.245836 ], "pop" : 18695, "state" : "OH" }
+{ "_id" : "44240", "city" : "KENT", "loc" : [ -81.34976, 41.14492 ], "pop" : 43071, "state" : "OH" }
+{ "_id" : "44241", "city" : "STREETSBORO", "loc" : [ -81.33829799999999, 41.249099 ], "pop" : 10735, "state" : "OH" }
+{ "_id" : "44253", "city" : "LITCHFIELD", "loc" : [ -82.015674, 41.166847 ], "pop" : 2506, "state" : "OH" }
+{ "_id" : "44254", "city" : "LODI", "loc" : [ -82.014661, 41.032713 ], "pop" : 4776, "state" : "OH" }
+{ "_id" : "44255", "city" : "MANTUA", "loc" : [ -81.22825899999999, 41.294141 ], "pop" : 7324, "state" : "OH" }
+{ "_id" : "44256", "city" : "MEDINA", "loc" : [ -81.858351, 41.140415 ], "pop" : 35686, "state" : "OH" }
+{ "_id" : "44260", "city" : "MOGADORE", "loc" : [ -81.358963, 41.038196 ], "pop" : 12947, "state" : "OH" }
+{ "_id" : "44262", "city" : "MUNROE FALLS", "loc" : [ -81.43756500000001, 41.14202 ], "pop" : 5375, "state" : "OH" }
+{ "_id" : "44264", "city" : "PENINSULA", "loc" : [ -81.540013, 41.225579 ], "pop" : 1886, "state" : "OH" }
+{ "_id" : "44266", "city" : "RAVENNA", "loc" : [ -81.233656, 41.164886 ], "pop" : 31700, "state" : "OH" }
+{ "_id" : "44270", "city" : "RITTMAN", "loc" : [ -81.782599, 40.968381 ], "pop" : 8270, "state" : "OH" }
+{ "_id" : "44272", "city" : "ROOTSTOWN", "loc" : [ -81.202642, 41.099534 ], "pop" : 3556, "state" : "OH" }
+{ "_id" : "44273", "city" : "SEVILLE", "loc" : [ -81.856199, 41.022731 ], "pop" : 3611, "state" : "OH" }
+{ "_id" : "44275", "city" : "SPENCER", "loc" : [ -82.099907, 41.098287 ], "pop" : 2595, "state" : "OH" }
+{ "_id" : "44276", "city" : "STERLING", "loc" : [ -81.85191399999999, 40.953263 ], "pop" : 1838, "state" : "OH" }
+{ "_id" : "44278", "city" : "TALLMADGE", "loc" : [ -81.425966, 41.097492 ], "pop" : 15402, "state" : "OH" }
+{ "_id" : "44280", "city" : "VALLEY CITY", "loc" : [ -81.92446700000001, 41.236806 ], "pop" : 3711, "state" : "OH" }
+{ "_id" : "44281", "city" : "WADSWORTH", "loc" : [ -81.73737300000001, 41.038375 ], "pop" : 24707, "state" : "OH" }
+{ "_id" : "44286", "city" : "RICHFIELD", "loc" : [ -81.64666800000001, 41.23712 ], "pop" : 4724, "state" : "OH" }
+{ "_id" : "44287", "city" : "WEST SALEM", "loc" : [ -82.106638, 40.948514 ], "pop" : 5351, "state" : "OH" }
+{ "_id" : "44288", "city" : "WINDHAM", "loc" : [ -81.053451, 41.239244 ], "pop" : 4561, "state" : "OH" }
+{ "_id" : "44301", "city" : "AKRON", "loc" : [ -81.520048, 41.044852 ], "pop" : 18356, "state" : "OH" }
+{ "_id" : "44302", "city" : "AKRON", "loc" : [ -81.54201500000001, 41.091988 ], "pop" : 6835, "state" : "OH" }
+{ "_id" : "44303", "city" : "AKRON", "loc" : [ -81.53860899999999, 41.102508 ], "pop" : 8658, "state" : "OH" }
+{ "_id" : "44304", "city" : "AKRON", "loc" : [ -81.508526, 41.080808 ], "pop" : 9521, "state" : "OH" }
+{ "_id" : "44305", "city" : "AKRON", "loc" : [ -81.464409, 41.076029 ], "pop" : 25788, "state" : "OH" }
+{ "_id" : "44306", "city" : "AKRON", "loc" : [ -81.49155399999999, 41.04791 ], "pop" : 25758, "state" : "OH" }
+{ "_id" : "44307", "city" : "AKRON", "loc" : [ -81.54878600000001, 41.069465 ], "pop" : 9945, "state" : "OH" }
+{ "_id" : "44308", "city" : "AKRON", "loc" : [ -81.519363, 41.079576 ], "pop" : 1113, "state" : "OH" }
+{ "_id" : "44310", "city" : "AKRON", "loc" : [ -81.500586, 41.107547 ], "pop" : 25482, "state" : "OH" }
+{ "_id" : "44311", "city" : "AKRON", "loc" : [ -81.520005, 41.063784 ], "pop" : 9040, "state" : "OH" }
+{ "_id" : "44312", "city" : "AKRON", "loc" : [ -81.43852800000001, 41.033442 ], "pop" : 32097, "state" : "OH" }
+{ "_id" : "44313", "city" : "AKRON", "loc" : [ -81.568487, 41.121995 ], "pop" : 23501, "state" : "OH" }
+{ "_id" : "44314", "city" : "AKRON", "loc" : [ -81.559825, 41.040774 ], "pop" : 21289, "state" : "OH" }
+{ "_id" : "44319", "city" : "AKRON", "loc" : [ -81.53467999999999, 40.97912 ], "pop" : 21902, "state" : "OH" }
+{ "_id" : "44320", "city" : "AKRON", "loc" : [ -81.56744, 41.083496 ], "pop" : 25910, "state" : "OH" }
+{ "_id" : "44321", "city" : "COPLEY", "loc" : [ -81.648045, 41.103139 ], "pop" : 8756, "state" : "OH" }
+{ "_id" : "44333", "city" : "FAIRLAWN", "loc" : [ -81.62385, 41.146734 ], "pop" : 15383, "state" : "OH" }
+{ "_id" : "44401", "city" : "BERLIN CENTER", "loc" : [ -80.934104, 41.024319 ], "pop" : 2771, "state" : "OH" }
+{ "_id" : "44402", "city" : "BRISTOLVILLE", "loc" : [ -80.85683899999999, 41.379749 ], "pop" : 3220, "state" : "OH" }
+{ "_id" : "44403", "city" : "BROOKFIELD", "loc" : [ -80.578767, 41.247957 ], "pop" : 5819, "state" : "OH" }
+{ "_id" : "44404", "city" : "BURGHILL", "loc" : [ -80.54406, 41.334688 ], "pop" : 802, "state" : "OH" }
+{ "_id" : "44405", "city" : "CAMPBELL", "loc" : [ -80.589721, 41.077829 ], "pop" : 10027, "state" : "OH" }
+{ "_id" : "44406", "city" : "CANFIELD", "loc" : [ -80.75643599999999, 41.029328 ], "pop" : 16683, "state" : "OH" }
+{ "_id" : "44408", "city" : "COLUMBIANA", "loc" : [ -80.697473, 40.885279 ], "pop" : 9868, "state" : "OH" }
+{ "_id" : "44410", "city" : "CORTLAND", "loc" : [ -80.73274499999999, 41.325125 ], "pop" : 15687, "state" : "OH" }
+{ "_id" : "44411", "city" : "DEERFIELD", "loc" : [ -81.05282699999999, 41.03586 ], "pop" : 2323, "state" : "OH" }
+{ "_id" : "44412", "city" : "DIAMOND", "loc" : [ -81.0425, 41.093473 ], "pop" : 1854, "state" : "OH" }
+{ "_id" : "44413", "city" : "EAST PALESTINE", "loc" : [ -80.546513, 40.840554 ], "pop" : 7493, "state" : "OH" }
+{ "_id" : "44417", "city" : "FARMDALE", "loc" : [ -80.662818, 41.392301 ], "pop" : 1781, "state" : "OH" }
+{ "_id" : "44418", "city" : "FOWLER", "loc" : [ -80.60589400000001, 41.334851 ], "pop" : 1692, "state" : "OH" }
+{ "_id" : "44420", "city" : "GIRARD", "loc" : [ -80.693305, 41.161136 ], "pop" : 16480, "state" : "OH" }
+{ "_id" : "44423", "city" : "HANOVERTON", "loc" : [ -80.914445, 40.773116 ], "pop" : 2461, "state" : "OH" }
+{ "_id" : "44425", "city" : "HUBBARD", "loc" : [ -80.57619200000001, 41.162401 ], "pop" : 15616, "state" : "OH" }
+{ "_id" : "44427", "city" : "KENSINGTON", "loc" : [ -80.938079, 40.71418 ], "pop" : 1463, "state" : "OH" }
+{ "_id" : "44428", "city" : "KINSMAN", "loc" : [ -80.57650599999999, 41.435442 ], "pop" : 3397, "state" : "OH" }
+{ "_id" : "44429", "city" : "LAKE MILTON", "loc" : [ -80.97235000000001, 41.101354 ], "pop" : 3984, "state" : "OH" }
+{ "_id" : "44430", "city" : "LEAVITTSBURG", "loc" : [ -80.886922, 41.244498 ], "pop" : 4368, "state" : "OH" }
+{ "_id" : "44431", "city" : "LEETONIA", "loc" : [ -80.758453, 40.863077 ], "pop" : 4281, "state" : "OH" }
+{ "_id" : "44432", "city" : "LISBON", "loc" : [ -80.758674, 40.759154 ], "pop" : 11236, "state" : "OH" }
+{ "_id" : "44436", "city" : "LOWELLVILLE", "loc" : [ -80.541551, 41.050256 ], "pop" : 3882, "state" : "OH" }
+{ "_id" : "44437", "city" : "MC DONALD", "loc" : [ -80.73116899999999, 41.158026 ], "pop" : 4868, "state" : "OH" }
+{ "_id" : "44438", "city" : "MASURY", "loc" : [ -80.53256500000001, 41.22552 ], "pop" : 5864, "state" : "OH" }
+{ "_id" : "44440", "city" : "MINERAL RIDGE", "loc" : [ -80.75529299999999, 41.131843 ], "pop" : 921, "state" : "OH" }
+{ "_id" : "44441", "city" : "NEGLEY", "loc" : [ -80.564497, 40.774601 ], "pop" : 2222, "state" : "OH" }
+{ "_id" : "44442", "city" : "NEW MIDDLETOWN", "loc" : [ -80.553415, 40.964607 ], "pop" : 3396, "state" : "OH" }
+{ "_id" : "44443", "city" : "NEW SPRINGFIELD", "loc" : [ -80.58558499999999, 40.926517 ], "pop" : 2547, "state" : "OH" }
+{ "_id" : "44444", "city" : "NEWTON FALLS", "loc" : [ -80.970135, 41.191047 ], "pop" : 11623, "state" : "OH" }
+{ "_id" : "44445", "city" : "NEW WATERFORD", "loc" : [ -80.62085500000001, 40.848941 ], "pop" : 3141, "state" : "OH" }
+{ "_id" : "44446", "city" : "NILES", "loc" : [ -80.755775, 41.182414 ], "pop" : 27450, "state" : "OH" }
+{ "_id" : "44449", "city" : "NORTH BENTON", "loc" : [ -81.01616799999999, 40.987579 ], "pop" : 892, "state" : "OH" }
+{ "_id" : "44450", "city" : "NORTH BLOOMFIELD", "loc" : [ -80.80683500000001, 41.456887 ], "pop" : 3393, "state" : "OH" }
+{ "_id" : "44451", "city" : "NORTH JACKSON", "loc" : [ -80.86225, 41.088044 ], "pop" : 2448, "state" : "OH" }
+{ "_id" : "44452", "city" : "NORTH LIMA", "loc" : [ -80.654911, 40.964866 ], "pop" : 2657, "state" : "OH" }
+{ "_id" : "44454", "city" : "PETERSBURG", "loc" : [ -80.540031, 40.904861 ], "pop" : 650, "state" : "OH" }
+{ "_id" : "44455", "city" : "ROGERS", "loc" : [ -80.620237, 40.778943 ], "pop" : 1418, "state" : "OH" }
+{ "_id" : "44460", "city" : "SALEM", "loc" : [ -80.86188300000001, 40.900024 ], "pop" : 26756, "state" : "OH" }
+{ "_id" : "44470", "city" : "SOUTHINGTON", "loc" : [ -80.948474, 41.298312 ], "pop" : 3019, "state" : "OH" }
+{ "_id" : "44471", "city" : "STRUTHERS", "loc" : [ -80.59848700000001, 41.050847 ], "pop" : 12318, "state" : "OH" }
+{ "_id" : "44473", "city" : "VIENNA", "loc" : [ -80.65499800000001, 41.217478 ], "pop" : 5638, "state" : "OH" }
+{ "_id" : "44481", "city" : "WARREN", "loc" : [ -80.87180600000001, 41.172426 ], "pop" : 5407, "state" : "OH" }
+{ "_id" : "44483", "city" : "WARREN", "loc" : [ -80.81644799999999, 41.263878 ], "pop" : 30257, "state" : "OH" }
+{ "_id" : "44484", "city" : "WARREN", "loc" : [ -80.76424299999999, 41.231819 ], "pop" : 25898, "state" : "OH" }
+{ "_id" : "44485", "city" : "WARREN", "loc" : [ -80.84413600000001, 41.240511 ], "pop" : 24847, "state" : "OH" }
+{ "_id" : "44490", "city" : "WASHINGTONVILLE", "loc" : [ -80.763137, 40.897331 ], "pop" : 482, "state" : "OH" }
+{ "_id" : "44491", "city" : "WEST FARMINGTON", "loc" : [ -80.96724500000001, 41.350849 ], "pop" : 768, "state" : "OH" }
+{ "_id" : "44502", "city" : "YOUNGSTOWN", "loc" : [ -80.640905, 41.077366 ], "pop" : 13671, "state" : "OH" }
+{ "_id" : "44503", "city" : "YOUNGSTOWN", "loc" : [ -80.650007, 41.102016 ], "pop" : 1315, "state" : "OH" }
+{ "_id" : "44504", "city" : "YOUNGSTOWN", "loc" : [ -80.653887, 41.123686 ], "pop" : 5845, "state" : "OH" }
+{ "_id" : "44505", "city" : "YOUNGSTOWN", "loc" : [ -80.627748, 41.125748 ], "pop" : 25106, "state" : "OH" }
+{ "_id" : "44506", "city" : "YOUNGSTOWN", "loc" : [ -80.625916, 41.096045 ], "pop" : 5619, "state" : "OH" }
+{ "_id" : "44507", "city" : "YOUNGSTOWN", "loc" : [ -80.65533600000001, 41.073236 ], "pop" : 10501, "state" : "OH" }
+{ "_id" : "44509", "city" : "YOUNGSTOWN", "loc" : [ -80.694463, 41.10498 ], "pop" : 14399, "state" : "OH" }
+{ "_id" : "44510", "city" : "YOUNGSTOWN", "loc" : [ -80.667204, 41.119714 ], "pop" : 4513, "state" : "OH" }
+{ "_id" : "44511", "city" : "YOUNGSTOWN", "loc" : [ -80.69309800000001, 41.070402 ], "pop" : 27278, "state" : "OH" }
+{ "_id" : "44512", "city" : "BOARDMAN", "loc" : [ -80.666629, 41.031985 ], "pop" : 35628, "state" : "OH" }
+{ "_id" : "44514", "city" : "POLAND", "loc" : [ -80.610254, 41.023258 ], "pop" : 21694, "state" : "OH" }
+{ "_id" : "44515", "city" : "AUSTINTOWN", "loc" : [ -80.743966, 41.093903 ], "pop" : 27130, "state" : "OH" }
+{ "_id" : "44601", "city" : "ALLIANCE", "loc" : [ -81.11819300000001, 40.915842 ], "pop" : 35230, "state" : "OH" }
+{ "_id" : "44606", "city" : "APPLE CREEK", "loc" : [ -81.809256, 40.755118 ], "pop" : 7286, "state" : "OH" }
+{ "_id" : "44608", "city" : "BEACH CITY", "loc" : [ -81.58512899999999, 40.656199 ], "pop" : 2321, "state" : "OH" }
+{ "_id" : "44609", "city" : "BELOIT", "loc" : [ -80.98966900000001, 40.895678 ], "pop" : 3205, "state" : "OH" }
+{ "_id" : "44611", "city" : "BIG PRAIRIE", "loc" : [ -82.072048, 40.618777 ], "pop" : 1956, "state" : "OH" }
+{ "_id" : "44612", "city" : "BOLIVAR", "loc" : [ -81.44635599999999, 40.634692 ], "pop" : 4225, "state" : "OH" }
+{ "_id" : "44613", "city" : "BREWSTER", "loc" : [ -81.598752, 40.714387 ], "pop" : 2129, "state" : "OH" }
+{ "_id" : "44614", "city" : "CANAL FULTON", "loc" : [ -81.577269, 40.88871 ], "pop" : 10310, "state" : "OH" }
+{ "_id" : "44615", "city" : "CARROLLTON", "loc" : [ -81.081789, 40.578663 ], "pop" : 10052, "state" : "OH" }
+{ "_id" : "44618", "city" : "DALTON", "loc" : [ -81.70077999999999, 40.779326 ], "pop" : 6069, "state" : "OH" }
+{ "_id" : "44620", "city" : "DELLROY", "loc" : [ -81.19856, 40.586143 ], "pop" : 1844, "state" : "OH" }
+{ "_id" : "44621", "city" : "DENNISON", "loc" : [ -81.320301, 40.408885 ], "pop" : 4573, "state" : "OH" }
+{ "_id" : "44622", "city" : "DOVER", "loc" : [ -81.476321, 40.534338 ], "pop" : 17042, "state" : "OH" }
+{ "_id" : "44624", "city" : "DUNDEE", "loc" : [ -81.676519, 40.639441 ], "pop" : 3871, "state" : "OH" }
+{ "_id" : "44625", "city" : "EAST ROCHESTER", "loc" : [ -81.01749, 40.756288 ], "pop" : 1531, "state" : "OH" }
+{ "_id" : "44626", "city" : "EAST SPARTA", "loc" : [ -81.368728, 40.697065 ], "pop" : 2908, "state" : "OH" }
+{ "_id" : "44627", "city" : "FREDERICKSBURG", "loc" : [ -81.851812, 40.685953 ], "pop" : 3336, "state" : "OH" }
+{ "_id" : "44628", "city" : "GLENMONT", "loc" : [ -82.150538, 40.521682 ], "pop" : 1908, "state" : "OH" }
+{ "_id" : "44629", "city" : "GNADENHUTTEN", "loc" : [ -81.40585799999999, 40.372123 ], "pop" : 5892, "state" : "OH" }
+{ "_id" : "44632", "city" : "HARTVILLE", "loc" : [ -81.32387300000001, 40.961798 ], "pop" : 8318, "state" : "OH" }
+{ "_id" : "44633", "city" : "HOLMESVILLE", "loc" : [ -81.927476, 40.633042 ], "pop" : 2145, "state" : "OH" }
+{ "_id" : "44634", "city" : "HOMEWORTH", "loc" : [ -81.065473, 40.859192 ], "pop" : 3400, "state" : "OH" }
+{ "_id" : "44637", "city" : "KILLBUCK", "loc" : [ -81.983721, 40.4933 ], "pop" : 1868, "state" : "OH" }
+{ "_id" : "44638", "city" : "LAKEVILLE", "loc" : [ -82.145477, 40.651965 ], "pop" : 1516, "state" : "OH" }
+{ "_id" : "44641", "city" : "LOUISVILLE", "loc" : [ -81.25946399999999, 40.847729 ], "pop" : 18994, "state" : "OH" }
+{ "_id" : "44643", "city" : "MAGNOLIA", "loc" : [ -81.307607, 40.651414 ], "pop" : 2166, "state" : "OH" }
+{ "_id" : "44644", "city" : "MALVERN", "loc" : [ -81.18378, 40.684532 ], "pop" : 4761, "state" : "OH" }
+{ "_id" : "44645", "city" : "MARSHALLVILLE", "loc" : [ -81.722527, 40.906677 ], "pop" : 1838, "state" : "OH" }
+{ "_id" : "44646", "city" : "MASSILLON", "loc" : [ -81.497263, 40.811605 ], "pop" : 45092, "state" : "OH" }
+{ "_id" : "44647", "city" : "MASSILLON", "loc" : [ -81.553252, 40.795918 ], "pop" : 17715, "state" : "OH" }
+{ "_id" : "44651", "city" : "MECHANICSTOWN", "loc" : [ -80.956025, 40.626279 ], "pop" : 709, "state" : "OH" }
+{ "_id" : "44654", "city" : "MILLERSBURG", "loc" : [ -81.83238299999999, 40.556683 ], "pop" : 20350, "state" : "OH" }
+{ "_id" : "44656", "city" : "ZOARVILLE", "loc" : [ -81.354561, 40.625686 ], "pop" : 2969, "state" : "OH" }
+{ "_id" : "44657", "city" : "MINERVA", "loc" : [ -81.103076, 40.742049 ], "pop" : 10547, "state" : "OH" }
+{ "_id" : "44662", "city" : "NAVARRE", "loc" : [ -81.533824, 40.720405 ], "pop" : 10006, "state" : "OH" }
+{ "_id" : "44663", "city" : "NEW PHILADELPHIA", "loc" : [ -81.435827, 40.484539 ], "pop" : 24640, "state" : "OH" }
+{ "_id" : "44666", "city" : "NORTH LAWRENCE", "loc" : [ -81.629946, 40.838652 ], "pop" : 2528, "state" : "OH" }
+{ "_id" : "44667", "city" : "ORRVILLE", "loc" : [ -81.774109, 40.845836 ], "pop" : 11983, "state" : "OH" }
+{ "_id" : "44669", "city" : "PARIS", "loc" : [ -81.15398999999999, 40.801413 ], "pop" : 1338, "state" : "OH" }
+{ "_id" : "44672", "city" : "SEBRING", "loc" : [ -81.023191, 40.922694 ], "pop" : 6276, "state" : "OH" }
+{ "_id" : "44675", "city" : "SHERRODSVILLE", "loc" : [ -81.23394500000001, 40.518418 ], "pop" : 1330, "state" : "OH" }
+{ "_id" : "44676", "city" : "SHREVE", "loc" : [ -82.03245099999999, 40.692584 ], "pop" : 4312, "state" : "OH" }
+{ "_id" : "44677", "city" : "SMITHVILLE", "loc" : [ -81.863328, 40.859228 ], "pop" : 2695, "state" : "OH" }
+{ "_id" : "44680", "city" : "STRASBURG", "loc" : [ -81.536646, 40.60028 ], "pop" : 3201, "state" : "OH" }
+{ "_id" : "44681", "city" : "SUGARCREEK", "loc" : [ -81.66035599999999, 40.514785 ], "pop" : 4772, "state" : "OH" }
+{ "_id" : "44683", "city" : "UHRICHSVILLE", "loc" : [ -81.33736500000001, 40.390502 ], "pop" : 6925, "state" : "OH" }
+{ "_id" : "44685", "city" : "UNIONTOWN", "loc" : [ -81.421108, 40.963694 ], "pop" : 21009, "state" : "OH" }
+{ "_id" : "44688", "city" : "WAYNESBURG", "loc" : [ -81.265891, 40.682881 ], "pop" : 3149, "state" : "OH" }
+{ "_id" : "44689", "city" : "WILMOT", "loc" : [ -81.63524700000001, 40.656723 ], "pop" : 286, "state" : "OH" }
+{ "_id" : "44691", "city" : "WOOSTER", "loc" : [ -81.948272, 40.809354 ], "pop" : 35504, "state" : "OH" }
+{ "_id" : "44695", "city" : "BOWERSTON", "loc" : [ -81.18624, 40.437056 ], "pop" : 1484, "state" : "OH" }
+{ "_id" : "44699", "city" : "TIPPECANOE", "loc" : [ -81.291937, 40.279748 ], "pop" : 1184, "state" : "OH" }
+{ "_id" : "44702", "city" : "CANTON", "loc" : [ -81.373946, 40.80267 ], "pop" : 1208, "state" : "OH" }
+{ "_id" : "44703", "city" : "CANTON", "loc" : [ -81.381439, 40.809791 ], "pop" : 11520, "state" : "OH" }
+{ "_id" : "44704", "city" : "CANTON", "loc" : [ -81.353701, 40.799076 ], "pop" : 5408, "state" : "OH" }
+{ "_id" : "44705", "city" : "CANTON", "loc" : [ -81.33990300000001, 40.825866 ], "pop" : 21271, "state" : "OH" }
+{ "_id" : "44706", "city" : "CANTON", "loc" : [ -81.411903, 40.767959 ], "pop" : 19443, "state" : "OH" }
+{ "_id" : "44707", "city" : "NORTH INDUSTRY", "loc" : [ -81.360407, 40.776885 ], "pop" : 11010, "state" : "OH" }
+{ "_id" : "44708", "city" : "CANTON", "loc" : [ -81.424116, 40.81196 ], "pop" : 25891, "state" : "OH" }
+{ "_id" : "44709", "city" : "NORTH CANTON", "loc" : [ -81.385947, 40.837227 ], "pop" : 19371, "state" : "OH" }
+{ "_id" : "44710", "city" : "CANTON", "loc" : [ -81.416946, 40.791107 ], "pop" : 9928, "state" : "OH" }
+{ "_id" : "44714", "city" : "CANTON", "loc" : [ -81.360963, 40.827174 ], "pop" : 8988, "state" : "OH" }
+{ "_id" : "44718", "city" : "JACKSON BELDEN", "loc" : [ -81.448514, 40.85479 ], "pop" : 10407, "state" : "OH" }
+{ "_id" : "44720", "city" : "NORTH CANTON", "loc" : [ -81.413464, 40.889919 ], "pop" : 33193, "state" : "OH" }
+{ "_id" : "44721", "city" : "CANTON", "loc" : [ -81.33279, 40.883446 ], "pop" : 10254, "state" : "OH" }
+{ "_id" : "44730", "city" : "EAST CANTON", "loc" : [ -81.278295, 40.784983 ], "pop" : 6154, "state" : "OH" }
+{ "_id" : "44802", "city" : "ALVADA", "loc" : [ -83.376982, 41.046284 ], "pop" : 1955, "state" : "OH" }
+{ "_id" : "44804", "city" : "ARCADIA", "loc" : [ -83.50194999999999, 41.111562 ], "pop" : 1142, "state" : "OH" }
+{ "_id" : "44805", "city" : "ASHLAND", "loc" : [ -82.31893100000001, 40.855892 ], "pop" : 27072, "state" : "OH" }
+{ "_id" : "44807", "city" : "CARROTHERS", "loc" : [ -82.88972099999999, 41.077755 ], "pop" : 2792, "state" : "OH" }
+{ "_id" : "44811", "city" : "BELLEVUE", "loc" : [ -82.85765000000001, 41.268432 ], "pop" : 14361, "state" : "OH" }
+{ "_id" : "44813", "city" : "BELLVILLE", "loc" : [ -82.517516, 40.613604 ], "pop" : 6432, "state" : "OH" }
+{ "_id" : "44814", "city" : "BERLIN HEIGHTS", "loc" : [ -82.47771299999999, 41.320519 ], "pop" : 2485, "state" : "OH" }
+{ "_id" : "44817", "city" : "BLOOMDALE", "loc" : [ -83.572356, 41.181489 ], "pop" : 1331, "state" : "OH" }
+{ "_id" : "44818", "city" : "BLOOMVILLE", "loc" : [ -82.989874, 41.018206 ], "pop" : 2572, "state" : "OH" }
+{ "_id" : "44820", "city" : "BUCYRUS", "loc" : [ -82.969829, 40.810306 ], "pop" : 19018, "state" : "OH" }
+{ "_id" : "44822", "city" : "BUTLER", "loc" : [ -82.398984, 40.543754 ], "pop" : 3870, "state" : "OH" }
+{ "_id" : "44824", "city" : "CASTALIA", "loc" : [ -82.799426, 41.387229 ], "pop" : 4027, "state" : "OH" }
+{ "_id" : "44825", "city" : "CHATFIELD", "loc" : [ -83.021432, 40.956637 ], "pop" : 514, "state" : "OH" }
+{ "_id" : "44826", "city" : "COLLINS", "loc" : [ -82.490402, 41.245023 ], "pop" : 1934, "state" : "OH" }
+{ "_id" : "44827", "city" : "CRESTLINE", "loc" : [ -82.736723, 40.792714 ], "pop" : 6723, "state" : "OH" }
+{ "_id" : "44830", "city" : "FOSTORIA", "loc" : [ -83.413938, 41.162346 ], "pop" : 20686, "state" : "OH" }
+{ "_id" : "44833", "city" : "GALION", "loc" : [ -82.793943, 40.730316 ], "pop" : 19069, "state" : "OH" }
+{ "_id" : "44836", "city" : "GREEN SPRINGS", "loc" : [ -83.088549, 41.228111 ], "pop" : 3752, "state" : "OH" }
+{ "_id" : "44837", "city" : "GREENWICH", "loc" : [ -82.51334, 41.04068 ], "pop" : 3054, "state" : "OH" }
+{ "_id" : "44839", "city" : "SHINROCK", "loc" : [ -82.555491, 41.390662 ], "pop" : 10386, "state" : "OH" }
+{ "_id" : "44840", "city" : "JEROMESVILLE", "loc" : [ -82.186134, 40.813366 ], "pop" : 4052, "state" : "OH" }
+{ "_id" : "44841", "city" : "KANSAS", "loc" : [ -83.329829, 41.212543 ], "pop" : 893, "state" : "OH" }
+{ "_id" : "44842", "city" : "LOUDONVILLE", "loc" : [ -82.23559, 40.636059 ], "pop" : 4767, "state" : "OH" }
+{ "_id" : "44843", "city" : "LUCAS", "loc" : [ -82.408671, 40.70389 ], "pop" : 2127, "state" : "OH" }
+{ "_id" : "44844", "city" : "MC CUTCHENVILLE", "loc" : [ -83.26366899999999, 40.975225 ], "pop" : 515, "state" : "OH" }
+{ "_id" : "44845", "city" : "MELMORE", "loc" : [ -83.143238, 41.038954 ], "pop" : 1611, "state" : "OH" }
+{ "_id" : "44846", "city" : "MILAN", "loc" : [ -82.612565, 41.311065 ], "pop" : 3568, "state" : "OH" }
+{ "_id" : "44847", "city" : "MONROEVILLE", "loc" : [ -82.70233, 41.218074 ], "pop" : 2721, "state" : "OH" }
+{ "_id" : "44849", "city" : "NEVADA", "loc" : [ -83.12656699999999, 40.825946 ], "pop" : 2464, "state" : "OH" }
+{ "_id" : "44851", "city" : "NEW LONDON", "loc" : [ -82.39658799999999, 41.090575 ], "pop" : 4243, "state" : "OH" }
+{ "_id" : "44853", "city" : "NEW RIEGEL", "loc" : [ -83.24180699999999, 41.036058 ], "pop" : 1483, "state" : "OH" }
+{ "_id" : "44854", "city" : "NEW WASHINGTON", "loc" : [ -82.850359, 40.957076 ], "pop" : 1679, "state" : "OH" }
+{ "_id" : "44855", "city" : "NORTH FAIRFIELD", "loc" : [ -82.599801, 41.102987 ], "pop" : 1229, "state" : "OH" }
+{ "_id" : "44857", "city" : "NORWALK", "loc" : [ -82.60785, 41.240314 ], "pop" : 21687, "state" : "OH" }
+{ "_id" : "44859", "city" : "NOVA", "loc" : [ -82.33843899999999, 41.028215 ], "pop" : 1565, "state" : "OH" }
+{ "_id" : "44864", "city" : "PERRYSVILLE", "loc" : [ -82.321307, 40.660626 ], "pop" : 2818, "state" : "OH" }
+{ "_id" : "44865", "city" : "PLYMOUTH", "loc" : [ -82.66349200000001, 41.00031 ], "pop" : 4122, "state" : "OH" }
+{ "_id" : "44866", "city" : "POLK", "loc" : [ -82.212587, 40.934293 ], "pop" : 2293, "state" : "OH" }
+{ "_id" : "44867", "city" : "REPUBLIC", "loc" : [ -83.019407, 41.125876 ], "pop" : 1735, "state" : "OH" }
+{ "_id" : "44870", "city" : "SANDUSKY", "loc" : [ -82.70632999999999, 41.434878 ], "pop" : 44129, "state" : "OH" }
+{ "_id" : "44874", "city" : "SAVANNAH", "loc" : [ -82.344272, 40.945382 ], "pop" : 2983, "state" : "OH" }
+{ "_id" : "44875", "city" : "SHELBY", "loc" : [ -82.654949, 40.878432 ], "pop" : 14736, "state" : "OH" }
+{ "_id" : "44878", "city" : "SHILOH", "loc" : [ -82.522155, 40.934015 ], "pop" : 4297, "state" : "OH" }
+{ "_id" : "44880", "city" : "SULLIVAN", "loc" : [ -82.21721700000001, 41.036818 ], "pop" : 1772, "state" : "OH" }
+{ "_id" : "44882", "city" : "SYCAMORE", "loc" : [ -83.149176, 40.941299 ], "pop" : 2610, "state" : "OH" }
+{ "_id" : "44883", "city" : "TIFFIN", "loc" : [ -83.18435599999999, 41.123822 ], "pop" : 28310, "state" : "OH" }
+{ "_id" : "44887", "city" : "TIRO", "loc" : [ -82.797032, 40.880992 ], "pop" : 1471, "state" : "OH" }
+{ "_id" : "44889", "city" : "WAKEMAN", "loc" : [ -82.378168, 41.263748 ], "pop" : 6464, "state" : "OH" }
+{ "_id" : "44890", "city" : "WILLARD", "loc" : [ -82.72880499999999, 41.062787 ], "pop" : 11156, "state" : "OH" }
+{ "_id" : "44902", "city" : "MANSFIELD", "loc" : [ -82.512269, 40.755937 ], "pop" : 8504, "state" : "OH" }
+{ "_id" : "44903", "city" : "MANSFIELD", "loc" : [ -82.52538, 40.762258 ], "pop" : 26575, "state" : "OH" }
+{ "_id" : "44904", "city" : "LEXINGTON", "loc" : [ -82.590605, 40.682568 ], "pop" : 12466, "state" : "OH" }
+{ "_id" : "44905", "city" : "LINCOLN", "loc" : [ -82.474609, 40.777173 ], "pop" : 16221, "state" : "OH" }
+{ "_id" : "44906", "city" : "MANSFIELD", "loc" : [ -82.55929500000001, 40.762679 ], "pop" : 16809, "state" : "OH" }
+{ "_id" : "44907", "city" : "MANSFIELD", "loc" : [ -82.51983300000001, 40.734483 ], "pop" : 14891, "state" : "OH" }
+{ "_id" : "45001", "city" : "ADDYSTON", "loc" : [ -84.709602, 39.137364 ], "pop" : 1198, "state" : "OH" }
+{ "_id" : "45002", "city" : "CLEVES", "loc" : [ -84.733969, 39.193707 ], "pop" : 10249, "state" : "OH" }
+{ "_id" : "45003", "city" : "COLLEGE CORNER", "loc" : [ -84.804951, 39.575453 ], "pop" : 708, "state" : "OH" }
+{ "_id" : "45005", "city" : "CARLISLE", "loc" : [ -84.305881, 39.547839 ], "pop" : 29720, "state" : "OH" }
+{ "_id" : "45011", "city" : "HAMILTON", "loc" : [ -84.52211699999999, 39.405906 ], "pop" : 41229, "state" : "OH" }
+{ "_id" : "45013", "city" : "ROSSVILLE", "loc" : [ -84.606655, 39.40619 ], "pop" : 48553, "state" : "OH" }
+{ "_id" : "45014", "city" : "FAIRFIELD", "loc" : [ -84.547881, 39.326602 ], "pop" : 41880, "state" : "OH" }
+{ "_id" : "45015", "city" : "LINDENWALD", "loc" : [ -84.551187, 39.367152 ], "pop" : 13310, "state" : "OH" }
+{ "_id" : "45030", "city" : "HARRISON", "loc" : [ -84.78368, 39.259208 ], "pop" : 15218, "state" : "OH" }
+{ "_id" : "45036", "city" : "OTTERBIEN HOME", "loc" : [ -84.218754, 39.442047 ], "pop" : 24354, "state" : "OH" }
+{ "_id" : "45039", "city" : "MAINEVILLE", "loc" : [ -84.252567, 39.313878 ], "pop" : 12215, "state" : "OH" }
+{ "_id" : "45040", "city" : "MASON", "loc" : [ -84.31493500000001, 39.335741 ], "pop" : 18803, "state" : "OH" }
+{ "_id" : "45042", "city" : "MIDDLETOWN", "loc" : [ -84.389601, 39.532121 ], "pop" : 27251, "state" : "OH" }
+{ "_id" : "45044", "city" : "EXCELLO", "loc" : [ -84.383461, 39.485259 ], "pop" : 38868, "state" : "OH" }
+{ "_id" : "45050", "city" : "MONROE", "loc" : [ -84.365196, 39.441285 ], "pop" : 4352, "state" : "OH" }
+{ "_id" : "45052", "city" : "NORTH BEND", "loc" : [ -84.727261, 39.153605 ], "pop" : 4013, "state" : "OH" }
+{ "_id" : "45053", "city" : "OKEANA", "loc" : [ -84.776149, 39.353732 ], "pop" : 2894, "state" : "OH" }
+{ "_id" : "45054", "city" : "OREGONIA", "loc" : [ -84.051136, 39.414479 ], "pop" : 1405, "state" : "OH" }
+{ "_id" : "45056", "city" : "MIAMI UNIVERSITY", "loc" : [ -84.738518, 39.503838 ], "pop" : 26075, "state" : "OH" }
+{ "_id" : "45064", "city" : "SOMERVILLE", "loc" : [ -84.621911, 39.555366 ], "pop" : 902, "state" : "OH" }
+{ "_id" : "45065", "city" : "SOUTH LEBANON", "loc" : [ -84.21078300000001, 39.371451 ], "pop" : 2774, "state" : "OH" }
+{ "_id" : "45066", "city" : "SPRINGBORO", "loc" : [ -84.228774, 39.562975 ], "pop" : 9106, "state" : "OH" }
+{ "_id" : "45067", "city" : "TRENTON", "loc" : [ -84.45976899999999, 39.479937 ], "pop" : 7072, "state" : "OH" }
+{ "_id" : "45068", "city" : "WAYNESVILLE", "loc" : [ -84.081518, 39.528489 ], "pop" : 6880, "state" : "OH" }
+{ "_id" : "45069", "city" : "WEST CHESTER", "loc" : [ -84.39978600000001, 39.340243 ], "pop" : 32613, "state" : "OH" }
+{ "_id" : "45101", "city" : "ABERDEEN", "loc" : [ -83.763723, 38.670864 ], "pop" : 2176, "state" : "OH" }
+{ "_id" : "45102", "city" : "AMELIA", "loc" : [ -84.211174, 39.021138 ], "pop" : 15931, "state" : "OH" }
+{ "_id" : "45103", "city" : "BATAVIA", "loc" : [ -84.14512499999999, 39.095661 ], "pop" : 14416, "state" : "OH" }
+{ "_id" : "45106", "city" : "BETHEL", "loc" : [ -84.09195, 38.94236 ], "pop" : 10408, "state" : "OH" }
+{ "_id" : "45107", "city" : "BLANCHESTER", "loc" : [ -83.973977, 39.303442 ], "pop" : 6158, "state" : "OH" }
+{ "_id" : "45111", "city" : "CAMP DENNISON", "loc" : [ -84.289659, 39.196212 ], "pop" : 482, "state" : "OH" }
+{ "_id" : "45113", "city" : "CLARKSVILLE", "loc" : [ -83.959407, 39.404233 ], "pop" : 1434, "state" : "OH" }
+{ "_id" : "45118", "city" : "FAYETTEVILLE", "loc" : [ -83.950087, 39.186214 ], "pop" : 3177, "state" : "OH" }
+{ "_id" : "45120", "city" : "FELICITY", "loc" : [ -84.098581, 38.826248 ], "pop" : 2662, "state" : "OH" }
+{ "_id" : "45121", "city" : "GEORGETOWN", "loc" : [ -83.909153, 38.871708 ], "pop" : 7474, "state" : "OH" }
+{ "_id" : "45122", "city" : "GOSHEN", "loc" : [ -84.118764, 39.220931 ], "pop" : 11742, "state" : "OH" }
+{ "_id" : "45123", "city" : "GREENFIELD", "loc" : [ -83.389805, 39.347763 ], "pop" : 8106, "state" : "OH" }
+{ "_id" : "45130", "city" : "HAMERSVILLE", "loc" : [ -83.99306199999999, 38.919962 ], "pop" : 3415, "state" : "OH" }
+{ "_id" : "45133", "city" : "HILLSBORO", "loc" : [ -83.60640600000001, 39.167877 ], "pop" : 19825, "state" : "OH" }
+{ "_id" : "45135", "city" : "LEESBURG", "loc" : [ -83.548146, 39.345767 ], "pop" : 3684, "state" : "OH" }
+{ "_id" : "45140", "city" : "LOVELAND", "loc" : [ -84.258802, 39.244484 ], "pop" : 29488, "state" : "OH" }
+{ "_id" : "45142", "city" : "LYNCHBURG", "loc" : [ -83.80212400000001, 39.211931 ], "pop" : 4539, "state" : "OH" }
+{ "_id" : "45144", "city" : "MANCHESTER", "loc" : [ -83.618064, 38.698167 ], "pop" : 4303, "state" : "OH" }
+{ "_id" : "45146", "city" : "MARTINSVILLE", "loc" : [ -83.800545, 39.312705 ], "pop" : 1413, "state" : "OH" }
+{ "_id" : "45148", "city" : "MIDLAND", "loc" : [ -83.893131, 39.29169 ], "pop" : 1488, "state" : "OH" }
+{ "_id" : "45150", "city" : "DAY HEIGHTS", "loc" : [ -84.243814, 39.179987 ], "pop" : 24709, "state" : "OH" }
+{ "_id" : "45152", "city" : "MORROW", "loc" : [ -84.11808499999999, 39.347619 ], "pop" : 5498, "state" : "OH" }
+{ "_id" : "45153", "city" : "MOSCOW", "loc" : [ -84.195824, 38.858255 ], "pop" : 1957, "state" : "OH" }
+{ "_id" : "45154", "city" : "MOUNT ORAB", "loc" : [ -83.948027, 39.045368 ], "pop" : 8247, "state" : "OH" }
+{ "_id" : "45157", "city" : "NEW RICHMOND", "loc" : [ -84.237903, 38.953663 ], "pop" : 8660, "state" : "OH" }
+{ "_id" : "45159", "city" : "NEW VIENNA", "loc" : [ -83.688171, 39.332058 ], "pop" : 2213, "state" : "OH" }
+{ "_id" : "45162", "city" : "PLEASANT PLAIN", "loc" : [ -84.09673600000001, 39.288382 ], "pop" : 2911, "state" : "OH" }
+{ "_id" : "45167", "city" : "RIPLEY", "loc" : [ -83.822677, 38.755095 ], "pop" : 3742, "state" : "OH" }
+{ "_id" : "45168", "city" : "RUSSELLVILLE", "loc" : [ -83.76245900000001, 38.851128 ], "pop" : 1600, "state" : "OH" }
+{ "_id" : "45169", "city" : "SABINA", "loc" : [ -83.65025199999999, 39.490022 ], "pop" : 4866, "state" : "OH" }
+{ "_id" : "45171", "city" : "SARDINIA", "loc" : [ -83.796649, 38.983232 ], "pop" : 3377, "state" : "OH" }
+{ "_id" : "45174", "city" : "TERRACE PARK", "loc" : [ -84.30976200000001, 39.160155 ], "pop" : 2133, "state" : "OH" }
+{ "_id" : "45176", "city" : "WILLIAMSBURG", "loc" : [ -84.043167, 39.075345 ], "pop" : 5038, "state" : "OH" }
+{ "_id" : "45177", "city" : "WILMINGTON", "loc" : [ -83.84165299999999, 39.448788 ], "pop" : 18361, "state" : "OH" }
+{ "_id" : "45202", "city" : "CINCINNATI", "loc" : [ -84.50195600000001, 39.107225 ], "pop" : 6428, "state" : "OH" }
+{ "_id" : "45203", "city" : "CINCINNATI", "loc" : [ -84.525684, 39.10754 ], "pop" : 5327, "state" : "OH" }
+{ "_id" : "45204", "city" : "CINCINNATI", "loc" : [ -84.566794, 39.102498 ], "pop" : 11444, "state" : "OH" }
+{ "_id" : "45205", "city" : "CINCINNATI", "loc" : [ -84.575672, 39.110439 ], "pop" : 23052, "state" : "OH" }
+{ "_id" : "45206", "city" : "CINCINNATI", "loc" : [ -84.485258, 39.126916 ], "pop" : 14017, "state" : "OH" }
+{ "_id" : "45207", "city" : "CINCINNATI", "loc" : [ -84.47062099999999, 39.139747 ], "pop" : 8156, "state" : "OH" }
+{ "_id" : "45208", "city" : "CINCINNATI", "loc" : [ -84.435474, 39.136082 ], "pop" : 19557, "state" : "OH" }
+{ "_id" : "45209", "city" : "CINCINNATI", "loc" : [ -84.42783300000001, 39.151578 ], "pop" : 12082, "state" : "OH" }
+{ "_id" : "45210", "city" : "CINCINNATI", "loc" : [ -84.513535, 39.112579 ], "pop" : 11349, "state" : "OH" }
+{ "_id" : "45211", "city" : "CINCINNATI", "loc" : [ -84.59671400000001, 39.152401 ], "pop" : 44072, "state" : "OH" }
+{ "_id" : "45212", "city" : "NORWOOD", "loc" : [ -84.452765, 39.162505 ], "pop" : 26737, "state" : "OH" }
+{ "_id" : "45213", "city" : "TAFT", "loc" : [ -84.418701, 39.182905 ], "pop" : 14333, "state" : "OH" }
+{ "_id" : "45214", "city" : "CINCINNATI", "loc" : [ -84.541442, 39.120642 ], "pop" : 12013, "state" : "OH" }
+{ "_id" : "45215", "city" : "LOCKLAND", "loc" : [ -84.457168, 39.230063 ], "pop" : 34166, "state" : "OH" }
+{ "_id" : "45216", "city" : "ELMWOOD PLACE", "loc" : [ -84.479232, 39.199183 ], "pop" : 10261, "state" : "OH" }
+{ "_id" : "45217", "city" : "SAINT BERNARD", "loc" : [ -84.497424, 39.161715 ], "pop" : 8838, "state" : "OH" }
+{ "_id" : "45218", "city" : "GREENHILLS", "loc" : [ -84.51960800000001, 39.266573 ], "pop" : 4680, "state" : "OH" }
+{ "_id" : "45219", "city" : "CINCINNATI", "loc" : [ -84.513127, 39.127027 ], "pop" : 21619, "state" : "OH" }
+{ "_id" : "45220", "city" : "CINCINNATI", "loc" : [ -84.521738, 39.143183 ], "pop" : 15449, "state" : "OH" }
+{ "_id" : "45223", "city" : "CINCINNATI", "loc" : [ -84.54780700000001, 39.169619 ], "pop" : 15639, "state" : "OH" }
+{ "_id" : "45224", "city" : "COLLEGE HILL", "loc" : [ -84.53883, 39.203079 ], "pop" : 23394, "state" : "OH" }
+{ "_id" : "45225", "city" : "CINCINNATI", "loc" : [ -84.55326700000001, 39.144654 ], "pop" : 13324, "state" : "OH" }
+{ "_id" : "45226", "city" : "CINCINNATI", "loc" : [ -84.431194, 39.117356 ], "pop" : 5711, "state" : "OH" }
+{ "_id" : "45227", "city" : "MADISONVILLE", "loc" : [ -84.38721099999999, 39.15431 ], "pop" : 21393, "state" : "OH" }
+{ "_id" : "45228", "city" : "CINCINNATI", "loc" : [ -84.42353900000001, 39.066448 ], "pop" : 538, "state" : "OH" }
+{ "_id" : "45229", "city" : "CINCINNATI", "loc" : [ -84.48918399999999, 39.149016 ], "pop" : 19811, "state" : "OH" }
+{ "_id" : "45230", "city" : "ANDERSON", "loc" : [ -84.378727, 39.080861 ], "pop" : 26856, "state" : "OH" }
+{ "_id" : "45231", "city" : "CINCINNATI", "loc" : [ -84.543702, 39.241827 ], "pop" : 44838, "state" : "OH" }
+{ "_id" : "45232", "city" : "CINCINNATI", "loc" : [ -84.514101, 39.185926 ], "pop" : 9364, "state" : "OH" }
+{ "_id" : "45233", "city" : "SAYLOR PARK", "loc" : [ -84.669411, 39.11928 ], "pop" : 15452, "state" : "OH" }
+{ "_id" : "45236", "city" : "TAFT", "loc" : [ -84.394746, 39.207302 ], "pop" : 26113, "state" : "OH" }
+{ "_id" : "45237", "city" : "CINCINNATI", "loc" : [ -84.45799700000001, 39.18797 ], "pop" : 25445, "state" : "OH" }
+{ "_id" : "45238", "city" : "WESTERN HILLS", "loc" : [ -84.608805, 39.111667 ], "pop" : 48302, "state" : "OH" }
+{ "_id" : "45239", "city" : "GROESBECK", "loc" : [ -84.57922499999999, 39.207995 ], "pop" : 27024, "state" : "OH" }
+{ "_id" : "45240", "city" : "PARKDALE", "loc" : [ -84.52629899999999, 39.286424 ], "pop" : 27517, "state" : "OH" }
+{ "_id" : "45241", "city" : "SHARONVILLE", "loc" : [ -84.391161, 39.276745 ], "pop" : 21992, "state" : "OH" }
+{ "_id" : "45242", "city" : "SYCAMORE", "loc" : [ -84.359919, 39.239881 ], "pop" : 21183, "state" : "OH" }
+{ "_id" : "45243", "city" : "MADEIRA", "loc" : [ -84.35934899999999, 39.187847 ], "pop" : 14999, "state" : "OH" }
+{ "_id" : "45244", "city" : "NEWTOWN", "loc" : [ -84.347765, 39.107091 ], "pop" : 12310, "state" : "OH" }
+{ "_id" : "45245", "city" : "NEWTOWN", "loc" : [ -84.277383, 39.091293 ], "pop" : 36134, "state" : "OH" }
+{ "_id" : "45246", "city" : "GLENDALE", "loc" : [ -84.472353, 39.28751 ], "pop" : 13861, "state" : "OH" }
+{ "_id" : "45247", "city" : "GROESBECK", "loc" : [ -84.631608, 39.207604 ], "pop" : 16834, "state" : "OH" }
+{ "_id" : "45248", "city" : "WESTWOOD", "loc" : [ -84.651535, 39.159056 ], "pop" : 20735, "state" : "OH" }
+{ "_id" : "45249", "city" : "SYCAMORE", "loc" : [ -84.326673, 39.275946 ], "pop" : 10312, "state" : "OH" }
+{ "_id" : "45251", "city" : "GROESBECK", "loc" : [ -84.587987, 39.253005 ], "pop" : 22487, "state" : "OH" }
+{ "_id" : "45252", "city" : "CINCINNATI", "loc" : [ -84.62832, 39.266803 ], "pop" : 3302, "state" : "OH" }
+{ "_id" : "45255", "city" : "ANDERSON", "loc" : [ -84.33077400000001, 39.070642 ], "pop" : 15600, "state" : "OH" }
+{ "_id" : "45302", "city" : "ANNA", "loc" : [ -84.21034400000001, 40.405105 ], "pop" : 3483, "state" : "OH" }
+{ "_id" : "45303", "city" : "ANSONIA", "loc" : [ -84.640642, 40.215064 ], "pop" : 2230, "state" : "OH" }
+{ "_id" : "45304", "city" : "CASTINE", "loc" : [ -84.53702, 39.988367 ], "pop" : 8201, "state" : "OH" }
+{ "_id" : "45305", "city" : "BELLBROOK", "loc" : [ -84.08244999999999, 39.640187 ], "pop" : 8162, "state" : "OH" }
+{ "_id" : "45306", "city" : "BOTKINS", "loc" : [ -84.177994, 40.465897 ], "pop" : 2168, "state" : "OH" }
+{ "_id" : "45308", "city" : "BRADFORD", "loc" : [ -84.429288, 40.128558 ], "pop" : 6966, "state" : "OH" }
+{ "_id" : "45309", "city" : "BROOKVILLE", "loc" : [ -84.416464, 39.841393 ], "pop" : 11613, "state" : "OH" }
+{ "_id" : "45311", "city" : "CAMDEN", "loc" : [ -84.61000799999999, 39.613391 ], "pop" : 8394, "state" : "OH" }
+{ "_id" : "45312", "city" : "CASSTOWN", "loc" : [ -84.108799, 40.071578 ], "pop" : 1283, "state" : "OH" }
+{ "_id" : "45314", "city" : "CEDARVILLE", "loc" : [ -83.801253, 39.748424 ], "pop" : 4685, "state" : "OH" }
+{ "_id" : "45315", "city" : "CLAYTON", "loc" : [ -84.33989, 39.855124 ], "pop" : 2269, "state" : "OH" }
+{ "_id" : "45317", "city" : "CONOVER", "loc" : [ -84.02829699999999, 40.145694 ], "pop" : 1053, "state" : "OH" }
+{ "_id" : "45318", "city" : "COVINGTON", "loc" : [ -84.34964600000001, 40.11756 ], "pop" : 3154, "state" : "OH" }
+{ "_id" : "45320", "city" : "EATON", "loc" : [ -84.65084899999999, 39.742572 ], "pop" : 13779, "state" : "OH" }
+{ "_id" : "45321", "city" : "ELDORADO", "loc" : [ -84.67859199999999, 39.888209 ], "pop" : 1168, "state" : "OH" }
+{ "_id" : "45322", "city" : "UNION", "loc" : [ -84.309515, 39.873976 ], "pop" : 20297, "state" : "OH" }
+{ "_id" : "45323", "city" : "ENON", "loc" : [ -83.938464, 39.866282 ], "pop" : 5820, "state" : "OH" }
+{ "_id" : "45324", "city" : "FAIRBORN", "loc" : [ -84.019789, 39.805311 ], "pop" : 35733, "state" : "OH" }
+{ "_id" : "45325", "city" : "FARMERSVILLE", "loc" : [ -84.420507, 39.686684 ], "pop" : 2292, "state" : "OH" }
+{ "_id" : "45326", "city" : "FLETCHER", "loc" : [ -84.13303999999999, 40.152622 ], "pop" : 1752, "state" : "OH" }
+{ "_id" : "45327", "city" : "GERMANTOWN", "loc" : [ -84.376384, 39.6244 ], "pop" : 8187, "state" : "OH" }
+{ "_id" : "45331", "city" : "GREENVILLE", "loc" : [ -84.63418900000001, 40.098726 ], "pop" : 23035, "state" : "OH" }
+{ "_id" : "45332", "city" : "HOLLANSBURG", "loc" : [ -84.79008, 39.989862 ], "pop" : 789, "state" : "OH" }
+{ "_id" : "45333", "city" : "HOUSTON", "loc" : [ -84.352109, 40.253478 ], "pop" : 1613, "state" : "OH" }
+{ "_id" : "45334", "city" : "JACKSON CENTER", "loc" : [ -84.045677, 40.435802 ], "pop" : 2318, "state" : "OH" }
+{ "_id" : "45335", "city" : "JAMESTOWN", "loc" : [ -83.750417, 39.642848 ], "pop" : 6956, "state" : "OH" }
+{ "_id" : "45337", "city" : "LAURA", "loc" : [ -84.3994, 39.978492 ], "pop" : 2602, "state" : "OH" }
+{ "_id" : "45338", "city" : "LEWISBURG", "loc" : [ -84.53685, 39.853404 ], "pop" : 5582, "state" : "OH" }
+{ "_id" : "45339", "city" : "LUDLOW FALLS", "loc" : [ -84.33339100000001, 39.987091 ], "pop" : 1888, "state" : "OH" }
+{ "_id" : "45340", "city" : "MAPLEWOOD", "loc" : [ -84.076657, 40.343743 ], "pop" : 2071, "state" : "OH" }
+{ "_id" : "45341", "city" : "MEDWAY", "loc" : [ -84.026808, 39.879774 ], "pop" : 4385, "state" : "OH" }
+{ "_id" : "45342", "city" : "MIAMISBURG", "loc" : [ -84.267477, 39.632095 ], "pop" : 27356, "state" : "OH" }
+{ "_id" : "45344", "city" : "NEW CARLISLE", "loc" : [ -84.021704, 39.930025 ], "pop" : 17912, "state" : "OH" }
+{ "_id" : "45345", "city" : "NEW LEBANON", "loc" : [ -84.395591, 39.739798 ], "pop" : 7359, "state" : "OH" }
+{ "_id" : "45346", "city" : "NEW MADISON", "loc" : [ -84.722211, 39.968711 ], "pop" : 2519, "state" : "OH" }
+{ "_id" : "45347", "city" : "NEW PARIS", "loc" : [ -84.779337, 39.861718 ], "pop" : 3783, "state" : "OH" }
+{ "_id" : "45348", "city" : "NEW WESTON", "loc" : [ -84.630792, 40.334923 ], "pop" : 1266, "state" : "OH" }
+{ "_id" : "45356", "city" : "PIQUA", "loc" : [ -84.25305299999999, 40.148621 ], "pop" : 24508, "state" : "OH" }
+{ "_id" : "45359", "city" : "PLEASANT HILL", "loc" : [ -84.34363399999999, 40.053136 ], "pop" : 2553, "state" : "OH" }
+{ "_id" : "45362", "city" : "ROSSBURG", "loc" : [ -84.626419, 40.29465 ], "pop" : 1450, "state" : "OH" }
+{ "_id" : "45363", "city" : "RUSSIA", "loc" : [ -84.412255, 40.234065 ], "pop" : 911, "state" : "OH" }
+{ "_id" : "45365", "city" : "SIDNEY", "loc" : [ -84.162223, 40.287357 ], "pop" : 27517, "state" : "OH" }
+{ "_id" : "45368", "city" : "SELMA", "loc" : [ -83.660787, 39.846939 ], "pop" : 4143, "state" : "OH" }
+{ "_id" : "45369", "city" : "SOUTH VIENNA", "loc" : [ -83.61570399999999, 39.94732 ], "pop" : 3814, "state" : "OH" }
+{ "_id" : "45370", "city" : "SPRING VALLEY", "loc" : [ -84.10158300000001, 39.602761 ], "pop" : 5950, "state" : "OH" }
+{ "_id" : "45371", "city" : "PHONETON", "loc" : [ -84.17150100000001, 39.943577 ], "pop" : 14967, "state" : "OH" }
+{ "_id" : "45373", "city" : "TROY", "loc" : [ -84.20315100000001, 40.037394 ], "pop" : 29422, "state" : "OH" }
+{ "_id" : "45377", "city" : "VANDALIA", "loc" : [ -84.20226599999999, 39.888273 ], "pop" : 14355, "state" : "OH" }
+{ "_id" : "45380", "city" : "VERSAILLES", "loc" : [ -84.49569700000001, 40.227284 ], "pop" : 4921, "state" : "OH" }
+{ "_id" : "45381", "city" : "WEST ALEXANDRIA", "loc" : [ -84.535214, 39.725898 ], "pop" : 5707, "state" : "OH" }
+{ "_id" : "45382", "city" : "WEST MANCHESTER", "loc" : [ -84.619383, 39.902564 ], "pop" : 1599, "state" : "OH" }
+{ "_id" : "45383", "city" : "WEST MILTON", "loc" : [ -84.324237, 39.953077 ], "pop" : 6095, "state" : "OH" }
+{ "_id" : "45385", "city" : "XENIA", "loc" : [ -83.93687799999999, 39.684204 ], "pop" : 36683, "state" : "OH" }
+{ "_id" : "45387", "city" : "YELLOW SPRINGS", "loc" : [ -83.889066, 39.799569 ], "pop" : 5743, "state" : "OH" }
+{ "_id" : "45388", "city" : "YORKSHIRE", "loc" : [ -84.483587, 40.328328 ], "pop" : 1054, "state" : "OH" }
+{ "_id" : "45390", "city" : "UNION CITY", "loc" : [ -84.783209, 40.201773 ], "pop" : 4123, "state" : "OH" }
+{ "_id" : "45402", "city" : "DAYTON", "loc" : [ -84.189508, 39.756305 ], "pop" : 2811, "state" : "OH" }
+{ "_id" : "45403", "city" : "DAYTON", "loc" : [ -84.14980199999999, 39.761728 ], "pop" : 19567, "state" : "OH" }
+{ "_id" : "45404", "city" : "DAYTON", "loc" : [ -84.16215699999999, 39.78619 ], "pop" : 14396, "state" : "OH" }
+{ "_id" : "45405", "city" : "DAYTON", "loc" : [ -84.21354599999999, 39.78993 ], "pop" : 25151, "state" : "OH" }
+{ "_id" : "45406", "city" : "DAYTON", "loc" : [ -84.237297, 39.782148 ], "pop" : 31024, "state" : "OH" }
+{ "_id" : "45407", "city" : "DAYTON", "loc" : [ -84.224232, 39.762699 ], "pop" : 13708, "state" : "OH" }
+{ "_id" : "45408", "city" : "DAYTON", "loc" : [ -84.22896299999999, 39.739526 ], "pop" : 13177, "state" : "OH" }
+{ "_id" : "45409", "city" : "DAYTON", "loc" : [ -84.182495, 39.728496 ], "pop" : 12633, "state" : "OH" }
+{ "_id" : "45410", "city" : "DAYTON", "loc" : [ -84.16001, 39.74743 ], "pop" : 19743, "state" : "OH" }
+{ "_id" : "45414", "city" : "DAYTON", "loc" : [ -84.202444, 39.828528 ], "pop" : 23033, "state" : "OH" }
+{ "_id" : "45415", "city" : "DAYTON", "loc" : [ -84.26132800000001, 39.835488 ], "pop" : 12885, "state" : "OH" }
+{ "_id" : "45416", "city" : "TROTWOOD", "loc" : [ -84.25982399999999, 39.805541 ], "pop" : 6905, "state" : "OH" }
+{ "_id" : "45417", "city" : "DAYTON", "loc" : [ -84.246961, 39.752812 ], "pop" : 14617, "state" : "OH" }
+{ "_id" : "45418", "city" : "DAYTON", "loc" : [ -84.267696, 39.716251 ], "pop" : 6913, "state" : "OH" }
+{ "_id" : "45419", "city" : "DAYTON", "loc" : [ -84.163656, 39.715486 ], "pop" : 17079, "state" : "OH" }
+{ "_id" : "45420", "city" : "KETTERING", "loc" : [ -84.133892, 39.721286 ], "pop" : 26955, "state" : "OH" }
+{ "_id" : "45424", "city" : "HUBER HEIGHTS", "loc" : [ -84.123287, 39.845339 ], "pop" : 48120, "state" : "OH" }
+{ "_id" : "45426", "city" : "TROTWOOD", "loc" : [ -84.298283, 39.810548 ], "pop" : 17853, "state" : "OH" }
+{ "_id" : "45427", "city" : "DAYTON", "loc" : [ -84.28188400000001, 39.754527 ], "pop" : 13469, "state" : "OH" }
+{ "_id" : "45429", "city" : "KETTERING", "loc" : [ -84.156077, 39.686392 ], "pop" : 27574, "state" : "OH" }
+{ "_id" : "45430", "city" : "BEAVERCREEK", "loc" : [ -84.083596, 39.709381 ], "pop" : 6511, "state" : "OH" }
+{ "_id" : "45431", "city" : "BEAVERCREEK", "loc" : [ -84.099802, 39.765396 ], "pop" : 25772, "state" : "OH" }
+{ "_id" : "45432", "city" : "BEAVERCREEK", "loc" : [ -84.094157, 39.740774 ], "pop" : 14917, "state" : "OH" }
+{ "_id" : "45433", "city" : "DAYTON", "loc" : [ -84.059048, 39.813758 ], "pop" : 2298, "state" : "OH" }
+{ "_id" : "45434", "city" : "BEAVERCREEK", "loc" : [ -84.040385, 39.716552 ], "pop" : 8855, "state" : "OH" }
+{ "_id" : "45439", "city" : "WEST CARROLLTON", "loc" : [ -84.21626000000001, 39.689617 ], "pop" : 9866, "state" : "OH" }
+{ "_id" : "45440", "city" : "DAYTON", "loc" : [ -84.113573, 39.674854 ], "pop" : 17129, "state" : "OH" }
+{ "_id" : "45449", "city" : "WEST CARROLLTON", "loc" : [ -84.237887, 39.662098 ], "pop" : 20391, "state" : "OH" }
+{ "_id" : "45458", "city" : "CENTERVILLE", "loc" : [ -84.16269699999999, 39.615755 ], "pop" : 16364, "state" : "OH" }
+{ "_id" : "45459", "city" : "CENTERVILLE", "loc" : [ -84.166422, 39.645957 ], "pop" : 25767, "state" : "OH" }
+{ "_id" : "45502", "city" : "SPRINGFIELD", "loc" : [ -83.84133799999999, 39.930486 ], "pop" : 16510, "state" : "OH" }
+{ "_id" : "45503", "city" : "SPRINGFIELD", "loc" : [ -83.78043, 39.9528 ], "pop" : 30547, "state" : "OH" }
+{ "_id" : "45504", "city" : "SPRINGFIELD", "loc" : [ -83.83430199999999, 39.940793 ], "pop" : 19854, "state" : "OH" }
+{ "_id" : "45505", "city" : "SPRINGFIELD", "loc" : [ -83.78559300000001, 39.910588 ], "pop" : 23956, "state" : "OH" }
+{ "_id" : "45506", "city" : "SPRINGFIELD", "loc" : [ -83.827512, 39.910418 ], "pop" : 19027, "state" : "OH" }
+{ "_id" : "45601", "city" : "CHILLICOTHE", "loc" : [ -82.98949, 39.337997 ], "pop" : 54615, "state" : "OH" }
+{ "_id" : "45612", "city" : "BAINBRIDGE", "loc" : [ -83.276268, 39.213116 ], "pop" : 4356, "state" : "OH" }
+{ "_id" : "45613", "city" : "BEAVER", "loc" : [ -82.847469, 39.023847 ], "pop" : 2953, "state" : "OH" }
+{ "_id" : "45614", "city" : "BIDWELL", "loc" : [ -82.27009200000001, 38.927647 ], "pop" : 3572, "state" : "OH" }
+{ "_id" : "45616", "city" : "BLUE CREEK", "loc" : [ -83.35268000000001, 38.756451 ], "pop" : 1436, "state" : "OH" }
+{ "_id" : "45619", "city" : "CHESAPEAKE", "loc" : [ -82.45044799999999, 38.455089 ], "pop" : 8076, "state" : "OH" }
+{ "_id" : "45620", "city" : "CHESHIRE", "loc" : [ -82.123537, 38.958678 ], "pop" : 1007, "state" : "OH" }
+{ "_id" : "45622", "city" : "CREOLA", "loc" : [ -82.493835, 39.3497 ], "pop" : 535, "state" : "OH" }
+{ "_id" : "45623", "city" : "CROWN CITY", "loc" : [ -82.265717, 38.613548 ], "pop" : 2677, "state" : "OH" }
+{ "_id" : "45628", "city" : "FRANKFORT", "loc" : [ -83.203356, 39.391015 ], "pop" : 3985, "state" : "OH" }
+{ "_id" : "45629", "city" : "FRANKLIN FURNACE", "loc" : [ -82.814477, 38.628216 ], "pop" : 3956, "state" : "OH" }
+{ "_id" : "45631", "city" : "GALLIPOLIS", "loc" : [ -82.22902000000001, 38.814781 ], "pop" : 18163, "state" : "OH" }
+{ "_id" : "45634", "city" : "HAMDEN", "loc" : [ -82.50997599999999, 39.168497 ], "pop" : 1554, "state" : "OH" }
+{ "_id" : "45638", "city" : "IRONTON", "loc" : [ -82.665351, 38.529429 ], "pop" : 21093, "state" : "OH" }
+{ "_id" : "45640", "city" : "JACKSON", "loc" : [ -82.647209, 39.042821 ], "pop" : 13373, "state" : "OH" }
+{ "_id" : "45644", "city" : "KINGSTON", "loc" : [ -82.84880800000001, 39.441432 ], "pop" : 1347, "state" : "OH" }
+{ "_id" : "45645", "city" : "KITTS HILL", "loc" : [ -82.548897, 38.564945 ], "pop" : 2837, "state" : "OH" }
+{ "_id" : "45646", "city" : "LATHAM", "loc" : [ -83.328294, 39.080436 ], "pop" : 351, "state" : "OH" }
+{ "_id" : "45647", "city" : "LONDONDERRY", "loc" : [ -82.783288, 39.272283 ], "pop" : 1481, "state" : "OH" }
+{ "_id" : "45648", "city" : "LUCASVILLE", "loc" : [ -82.99400900000001, 38.893832 ], "pop" : 12974, "state" : "OH" }
+{ "_id" : "45651", "city" : "ALLENSVILLE", "loc" : [ -82.49069900000001, 39.255326 ], "pop" : 5028, "state" : "OH" }
+{ "_id" : "45652", "city" : "MC DERMOTT", "loc" : [ -83.06889200000001, 38.836203 ], "pop" : 2932, "state" : "OH" }
+{ "_id" : "45653", "city" : "MINFORD", "loc" : [ -82.855538, 38.875087 ], "pop" : 3969, "state" : "OH" }
+{ "_id" : "45654", "city" : "NEW PLYMOUTH", "loc" : [ -82.389172, 39.388421 ], "pop" : 804, "state" : "OH" }
+{ "_id" : "45656", "city" : "OAK HILL", "loc" : [ -82.58834299999999, 38.891559 ], "pop" : 6036, "state" : "OH" }
+{ "_id" : "45657", "city" : "OTWAY", "loc" : [ -83.222172, 38.85203 ], "pop" : 2287, "state" : "OH" }
+{ "_id" : "45658", "city" : "PATRIOT", "loc" : [ -82.427491, 38.77702 ], "pop" : 2202, "state" : "OH" }
+{ "_id" : "45659", "city" : "PEDRO", "loc" : [ -82.647722, 38.650323 ], "pop" : 3870, "state" : "OH" }
+{ "_id" : "45660", "city" : "PEEBLES", "loc" : [ -83.36869799999999, 38.986885 ], "pop" : 7298, "state" : "OH" }
+{ "_id" : "45661", "city" : "IDAHO", "loc" : [ -83.076742, 39.040196 ], "pop" : 4342, "state" : "OH" }
+{ "_id" : "45662", "city" : "NEW BOSTON", "loc" : [ -82.94864, 38.757252 ], "pop" : 33275, "state" : "OH" }
+{ "_id" : "45663", "city" : "PORTSMOUTH", "loc" : [ -83.047657, 38.749222 ], "pop" : 8485, "state" : "OH" }
+{ "_id" : "45669", "city" : "PROCTORVILLE", "loc" : [ -82.352294, 38.463461 ], "pop" : 8976, "state" : "OH" }
+{ "_id" : "45670", "city" : "RADCLIFF", "loc" : [ -82.354243, 39.105205 ], "pop" : 1413, "state" : "OH" }
+{ "_id" : "45671", "city" : "RARDEN", "loc" : [ -83.237337, 38.943388 ], "pop" : 524, "state" : "OH" }
+{ "_id" : "45672", "city" : "RAY", "loc" : [ -82.69080099999999, 39.207678 ], "pop" : 1472, "state" : "OH" }
+{ "_id" : "45673", "city" : "RICHMOND DALE", "loc" : [ -82.814913, 39.203922 ], "pop" : 454, "state" : "OH" }
+{ "_id" : "45675", "city" : "ROCK CAMP", "loc" : [ -82.563832, 38.522145 ], "pop" : 435, "state" : "OH" }
+{ "_id" : "45678", "city" : "SCOTTOWN", "loc" : [ -82.39668500000001, 38.594034 ], "pop" : 1433, "state" : "OH" }
+{ "_id" : "45679", "city" : "SEAMAN", "loc" : [ -83.593625, 38.962072 ], "pop" : 3482, "state" : "OH" }
+{ "_id" : "45680", "city" : "SOUTH POINT", "loc" : [ -82.55288299999999, 38.433856 ], "pop" : 13272, "state" : "OH" }
+{ "_id" : "45681", "city" : "SOUTH SALEM", "loc" : [ -83.271953, 39.302137 ], "pop" : 1001, "state" : "OH" }
+{ "_id" : "45682", "city" : "SOUTH WEBSTER", "loc" : [ -82.720151, 38.819967 ], "pop" : 2094, "state" : "OH" }
+{ "_id" : "45684", "city" : "STOUT", "loc" : [ -83.208984, 38.654588 ], "pop" : 1342, "state" : "OH" }
+{ "_id" : "45685", "city" : "THURMAN", "loc" : [ -82.404996, 38.898786 ], "pop" : 2291, "state" : "OH" }
+{ "_id" : "45686", "city" : "VINTON", "loc" : [ -82.35701400000001, 38.978338 ], "pop" : 1898, "state" : "OH" }
+{ "_id" : "45688", "city" : "WATERLOO", "loc" : [ -82.517399, 38.718152 ], "pop" : 385, "state" : "OH" }
+{ "_id" : "45690", "city" : "WAVERLY", "loc" : [ -83.004874, 39.126445 ], "pop" : 14422, "state" : "OH" }
+{ "_id" : "45692", "city" : "WELLSTON", "loc" : [ -82.548474, 39.118897 ], "pop" : 9486, "state" : "OH" }
+{ "_id" : "45693", "city" : "WEST UNION", "loc" : [ -83.533349, 38.801702 ], "pop" : 8656, "state" : "OH" }
+{ "_id" : "45694", "city" : "WHEELERSBURG", "loc" : [ -82.82043400000001, 38.741793 ], "pop" : 10537, "state" : "OH" }
+{ "_id" : "45696", "city" : "WILLOW WOOD", "loc" : [ -82.453, 38.593976 ], "pop" : 665, "state" : "OH" }
+{ "_id" : "45697", "city" : "WINCHESTER", "loc" : [ -83.66613700000001, 38.935283 ], "pop" : 3146, "state" : "OH" }
+{ "_id" : "45701", "city" : "ATHENS", "loc" : [ -82.102011, 39.317824 ], "pop" : 28523, "state" : "OH" }
+{ "_id" : "45710", "city" : "ALBANY", "loc" : [ -82.217727, 39.209664 ], "pop" : 4090, "state" : "OH" }
+{ "_id" : "45711", "city" : "AMESVILLE", "loc" : [ -81.96497599999999, 39.408641 ], "pop" : 1661, "state" : "OH" }
+{ "_id" : "45714", "city" : "BELPRE", "loc" : [ -81.596795, 39.286772 ], "pop" : 9237, "state" : "OH" }
+{ "_id" : "45715", "city" : "BEVERLY", "loc" : [ -81.63458799999999, 39.571435 ], "pop" : 2715, "state" : "OH" }
+{ "_id" : "45723", "city" : "COOLVILLE", "loc" : [ -81.83286699999999, 39.214131 ], "pop" : 5023, "state" : "OH" }
+{ "_id" : "45724", "city" : "CUTLER", "loc" : [ -81.76573, 39.404172 ], "pop" : 2624, "state" : "OH" }
+{ "_id" : "45727", "city" : "DEXTER CITY", "loc" : [ -81.467151, 39.652585 ], "pop" : 277, "state" : "OH" }
+{ "_id" : "45729", "city" : "FLEMING", "loc" : [ -81.65644399999999, 39.392806 ], "pop" : 1864, "state" : "OH" }
+{ "_id" : "45732", "city" : "GLOUSTER", "loc" : [ -82.08712800000001, 39.497837 ], "pop" : 6226, "state" : "OH" }
+{ "_id" : "45734", "city" : "RINARD MILLS", "loc" : [ -81.18915200000001, 39.659384 ], "pop" : 535, "state" : "OH" }
+{ "_id" : "45735", "city" : "GUYSVILLE", "loc" : [ -81.926841, 39.294368 ], "pop" : 359, "state" : "OH" }
+{ "_id" : "45741", "city" : "DEXTER", "loc" : [ -82.23118599999999, 39.056325 ], "pop" : 1613, "state" : "OH" }
+{ "_id" : "45742", "city" : "LITTLE HOCKING", "loc" : [ -81.70710699999999, 39.280046 ], "pop" : 3346, "state" : "OH" }
+{ "_id" : "45743", "city" : "LONG BOTTOM", "loc" : [ -81.88874800000001, 39.08015 ], "pop" : 1692, "state" : "OH" }
+{ "_id" : "45744", "city" : "LOWELL", "loc" : [ -81.519679, 39.53847 ], "pop" : 1741, "state" : "OH" }
+{ "_id" : "45745", "city" : "WARNER", "loc" : [ -81.35451999999999, 39.593895 ], "pop" : 1900, "state" : "OH" }
+{ "_id" : "45746", "city" : "MACKSBURG", "loc" : [ -81.44708799999999, 39.620356 ], "pop" : 445, "state" : "OH" }
+{ "_id" : "45750", "city" : "MARIETTA", "loc" : [ -81.464438, 39.428141 ], "pop" : 25904, "state" : "OH" }
+{ "_id" : "45760", "city" : "MIDDLEPORT", "loc" : [ -82.060012, 38.999312 ], "pop" : 3433, "state" : "OH" }
+{ "_id" : "45761", "city" : "MILLFIELD", "loc" : [ -82.111328, 39.407711 ], "pop" : 2656, "state" : "OH" }
+{ "_id" : "45764", "city" : "NELSONVILLE", "loc" : [ -82.23088300000001, 39.455635 ], "pop" : 8924, "state" : "OH" }
+{ "_id" : "45766", "city" : "NEW MARSHFIELD", "loc" : [ -82.22251300000001, 39.338295 ], "pop" : 2321, "state" : "OH" }
+{ "_id" : "45767", "city" : "NEW MATAMORAS", "loc" : [ -81.093998, 39.528819 ], "pop" : 3032, "state" : "OH" }
+{ "_id" : "45768", "city" : "NEWPORT", "loc" : [ -81.24017499999999, 39.39711 ], "pop" : 1645, "state" : "OH" }
+{ "_id" : "45769", "city" : "POMEROY", "loc" : [ -82.033145, 39.060729 ], "pop" : 5509, "state" : "OH" }
+{ "_id" : "45770", "city" : "PORTLAND", "loc" : [ -81.813548, 38.999919 ], "pop" : 905, "state" : "OH" }
+{ "_id" : "45771", "city" : "RACINE", "loc" : [ -81.925759, 38.978551 ], "pop" : 3774, "state" : "OH" }
+{ "_id" : "45772", "city" : "REEDSVILLE", "loc" : [ -81.792433, 39.149002 ], "pop" : 1305, "state" : "OH" }
+{ "_id" : "45773", "city" : "RENO", "loc" : [ -81.38043, 39.378408 ], "pop" : 2673, "state" : "OH" }
+{ "_id" : "45775", "city" : "RUTLAND", "loc" : [ -82.121914, 39.045653 ], "pop" : 1598, "state" : "OH" }
+{ "_id" : "45776", "city" : "SHADE", "loc" : [ -82.021755, 39.212862 ], "pop" : 1890, "state" : "OH" }
+{ "_id" : "45778", "city" : "STEWART", "loc" : [ -81.892884, 39.32133 ], "pop" : 975, "state" : "OH" }
+{ "_id" : "45780", "city" : "THE PLAINS", "loc" : [ -82.134148, 39.366177 ], "pop" : 3567, "state" : "OH" }
+{ "_id" : "45784", "city" : "VINCENT", "loc" : [ -81.67426500000001, 39.337446 ], "pop" : 1524, "state" : "OH" }
+{ "_id" : "45786", "city" : "WATERFORD", "loc" : [ -81.655917, 39.515904 ], "pop" : 3932, "state" : "OH" }
+{ "_id" : "45788", "city" : "WHIPPLE", "loc" : [ -81.36363900000001, 39.480975 ], "pop" : 1835, "state" : "OH" }
+{ "_id" : "45789", "city" : "WINGETT RUN", "loc" : [ -81.28399899999999, 39.542813 ], "pop" : 365, "state" : "OH" }
+{ "_id" : "45801", "city" : "LIMA", "loc" : [ -84.097296, 40.764066 ], "pop" : 27344, "state" : "OH" }
+{ "_id" : "45804", "city" : "LIMA", "loc" : [ -84.089023, 40.727476 ], "pop" : 19289, "state" : "OH" }
+{ "_id" : "45805", "city" : "LIMA", "loc" : [ -84.14591, 40.739911 ], "pop" : 23080, "state" : "OH" }
+{ "_id" : "45806", "city" : "CRIDERSVILLE", "loc" : [ -84.144049, 40.675926 ], "pop" : 12250, "state" : "OH" }
+{ "_id" : "45807", "city" : "ELIDA", "loc" : [ -84.163966, 40.791599 ], "pop" : 9531, "state" : "OH" }
+{ "_id" : "45810", "city" : "ADA", "loc" : [ -83.81540200000001, 40.770931 ], "pop" : 7299, "state" : "OH" }
+{ "_id" : "45812", "city" : "ALGER", "loc" : [ -83.825011, 40.705967 ], "pop" : 2394, "state" : "OH" }
+{ "_id" : "45813", "city" : "ANTWERP", "loc" : [ -84.74479599999999, 41.188736 ], "pop" : 3039, "state" : "OH" }
+{ "_id" : "45814", "city" : "ARLINGTON", "loc" : [ -83.668536, 40.876109 ], "pop" : 2603, "state" : "OH" }
+{ "_id" : "45817", "city" : "BLUFFTON", "loc" : [ -83.891397, 40.878978 ], "pop" : 6055, "state" : "OH" }
+{ "_id" : "45821", "city" : "CECIL", "loc" : [ -84.62964599999999, 41.217355 ], "pop" : 1527, "state" : "OH" }
+{ "_id" : "45822", "city" : "CARTHAGENA", "loc" : [ -84.57006699999999, 40.546074 ], "pop" : 18799, "state" : "OH" }
+{ "_id" : "45827", "city" : "CLOVERDALE", "loc" : [ -84.29382, 41.037934 ], "pop" : 1225, "state" : "OH" }
+{ "_id" : "45828", "city" : "COLDWATER", "loc" : [ -84.651653, 40.484557 ], "pop" : 6677, "state" : "OH" }
+{ "_id" : "45830", "city" : "COLUMBUS GROVE", "loc" : [ -84.07046699999999, 40.91372 ], "pop" : 6030, "state" : "OH" }
+{ "_id" : "45831", "city" : "CONTINENTAL", "loc" : [ -84.235778, 41.114769 ], "pop" : 3518, "state" : "OH" }
+{ "_id" : "45832", "city" : "CONVOY", "loc" : [ -84.723772, 40.926998 ], "pop" : 2134, "state" : "OH" }
+{ "_id" : "45833", "city" : "DELPHOS", "loc" : [ -84.32467800000001, 40.833619 ], "pop" : 10062, "state" : "OH" }
+{ "_id" : "45835", "city" : "DOLA", "loc" : [ -83.68937099999999, 40.787645 ], "pop" : 256, "state" : "OH" }
+{ "_id" : "45836", "city" : "DUNKIRK", "loc" : [ -83.633912, 40.782375 ], "pop" : 1522, "state" : "OH" }
+{ "_id" : "45840", "city" : "FINDLAY", "loc" : [ -83.645656, 41.044903 ], "pop" : 48109, "state" : "OH" }
+{ "_id" : "45841", "city" : "JENERA", "loc" : [ -83.725628, 40.900388 ], "pop" : 335, "state" : "OH" }
+{ "_id" : "45843", "city" : "PATTERSON", "loc" : [ -83.509771, 40.79955 ], "pop" : 3333, "state" : "OH" }
+{ "_id" : "45844", "city" : "FORT JENNINGS", "loc" : [ -84.237381, 40.948393 ], "pop" : 5287, "state" : "OH" }
+{ "_id" : "45845", "city" : "FORT LORAMIE", "loc" : [ -84.37413100000001, 40.330632 ], "pop" : 2639, "state" : "OH" }
+{ "_id" : "45846", "city" : "FORT RECOVERY", "loc" : [ -84.76125, 40.401829 ], "pop" : 3555, "state" : "OH" }
+{ "_id" : "45849", "city" : "GROVER HILL", "loc" : [ -84.49560099999999, 41.024497 ], "pop" : 1113, "state" : "OH" }
+{ "_id" : "45850", "city" : "HARROD", "loc" : [ -83.94364899999999, 40.717657 ], "pop" : 4897, "state" : "OH" }
+{ "_id" : "45851", "city" : "HAVILAND", "loc" : [ -84.6139, 41.032911 ], "pop" : 659, "state" : "OH" }
+{ "_id" : "45856", "city" : "LEIPSIC", "loc" : [ -83.995723, 41.109197 ], "pop" : 4657, "state" : "OH" }
+{ "_id" : "45858", "city" : "MC COMB", "loc" : [ -83.801423, 41.112498 ], "pop" : 2298, "state" : "OH" }
+{ "_id" : "45860", "city" : "MARIA STEIN", "loc" : [ -84.50757900000001, 40.406225 ], "pop" : 2284, "state" : "OH" }
+{ "_id" : "45862", "city" : "MENDON", "loc" : [ -84.51515000000001, 40.677737 ], "pop" : 1527, "state" : "OH" }
+{ "_id" : "45863", "city" : "MIDDLE POINT", "loc" : [ -84.417495, 40.873147 ], "pop" : 2691, "state" : "OH" }
+{ "_id" : "45865", "city" : "MINSTER", "loc" : [ -84.372895, 40.390983 ], "pop" : 4436, "state" : "OH" }
+{ "_id" : "45867", "city" : "MOUNT BLANCHARD", "loc" : [ -83.555286, 40.892929 ], "pop" : 957, "state" : "OH" }
+{ "_id" : "45868", "city" : "MOUNT CORY", "loc" : [ -83.809285, 40.943717 ], "pop" : 1553, "state" : "OH" }
+{ "_id" : "45869", "city" : "NEW BREMEN", "loc" : [ -84.38209999999999, 40.438917 ], "pop" : 3400, "state" : "OH" }
+{ "_id" : "45871", "city" : "NEW KNOXVILLE", "loc" : [ -84.311797, 40.50386 ], "pop" : 2003, "state" : "OH" }
+{ "_id" : "45872", "city" : "NORTH BALTIMORE", "loc" : [ -83.680581, 41.186703 ], "pop" : 3820, "state" : "OH" }
+{ "_id" : "45873", "city" : "OAKWOOD", "loc" : [ -84.396923, 41.090788 ], "pop" : 3129, "state" : "OH" }
+{ "_id" : "45874", "city" : "OHIO CITY", "loc" : [ -84.673063, 40.785428 ], "pop" : 3117, "state" : "OH" }
+{ "_id" : "45875", "city" : "GILBOA", "loc" : [ -84.047293, 41.029747 ], "pop" : 10177, "state" : "OH" }
+{ "_id" : "45876", "city" : "OTTOVILLE", "loc" : [ -84.347392, 40.937218 ], "pop" : 1972, "state" : "OH" }
+{ "_id" : "45877", "city" : "PANDORA", "loc" : [ -83.952073, 40.95087 ], "pop" : 2026, "state" : "OH" }
+{ "_id" : "45879", "city" : "PAULDING", "loc" : [ -84.572227, 41.141016 ], "pop" : 6565, "state" : "OH" }
+{ "_id" : "45880", "city" : "PAYNE", "loc" : [ -84.734127, 41.08069 ], "pop" : 2766, "state" : "OH" }
+{ "_id" : "45881", "city" : "RAWSON", "loc" : [ -83.806951, 41.000135 ], "pop" : 955, "state" : "OH" }
+{ "_id" : "45882", "city" : "ROCKFORD", "loc" : [ -84.664174, 40.677077 ], "pop" : 3038, "state" : "OH" }
+{ "_id" : "45883", "city" : "SAINT HENRY", "loc" : [ -84.63333799999999, 40.409138 ], "pop" : 3615, "state" : "OH" }
+{ "_id" : "45885", "city" : "SAINT MARYS", "loc" : [ -84.39439900000001, 40.543988 ], "pop" : 13066, "state" : "OH" }
+{ "_id" : "45886", "city" : "SCOTT", "loc" : [ -84.58445500000001, 40.989238 ], "pop" : 397, "state" : "OH" }
+{ "_id" : "45887", "city" : "SPENCERVILLE", "loc" : [ -84.34125, 40.703767 ], "pop" : 5745, "state" : "OH" }
+{ "_id" : "45889", "city" : "VAN BUREN", "loc" : [ -83.647302, 41.132691 ], "pop" : 1232, "state" : "OH" }
+{ "_id" : "45890", "city" : "VANLUE", "loc" : [ -83.497062, 40.958314 ], "pop" : 901, "state" : "OH" }
+{ "_id" : "45891", "city" : "VAN WERT", "loc" : [ -84.59036399999999, 40.868927 ], "pop" : 16625, "state" : "OH" }
+{ "_id" : "45894", "city" : "VENEDOCIA", "loc" : [ -84.46204, 40.768454 ], "pop" : 966, "state" : "OH" }
+{ "_id" : "45895", "city" : "WAPAKONETA", "loc" : [ -84.177378, 40.568978 ], "pop" : 16364, "state" : "OH" }
+{ "_id" : "45896", "city" : "WAYNESFIELD", "loc" : [ -83.95847500000001, 40.607185 ], "pop" : 1648, "state" : "OH" }
+{ "_id" : "45898", "city" : "WILLSHIRE", "loc" : [ -84.77773000000001, 40.734618 ], "pop" : 1265, "state" : "OH" }
+{ "_id" : "46001", "city" : "ALEXANDRIA", "loc" : [ -85.668148, 40.256081 ], "pop" : 11011, "state" : "IN" }
+{ "_id" : "46011", "city" : "ANDERSON", "loc" : [ -85.72530500000001, 40.114577 ], "pop" : 17280, "state" : "IN" }
+{ "_id" : "46012", "city" : "ANDERSON", "loc" : [ -85.65359100000001, 40.130947 ], "pop" : 20949, "state" : "IN" }
+{ "_id" : "46013", "city" : "ANDERSON", "loc" : [ -85.68007299999999, 40.061865 ], "pop" : 17037, "state" : "IN" }
+{ "_id" : "46016", "city" : "ANDERSON", "loc" : [ -85.684566, 40.098799 ], "pop" : 22838, "state" : "IN" }
+{ "_id" : "46017", "city" : "CHESTERFIELD", "loc" : [ -85.601493, 40.096431 ], "pop" : 6038, "state" : "IN" }
+{ "_id" : "46030", "city" : "ARCADIA", "loc" : [ -86.040882, 40.17758 ], "pop" : 4137, "state" : "IN" }
+{ "_id" : "46031", "city" : "ATLANTA", "loc" : [ -85.93394499999999, 40.146964 ], "pop" : 2450, "state" : "IN" }
+{ "_id" : "46032", "city" : "CARMEL", "loc" : [ -86.124545, 39.971232 ], "pop" : 40090, "state" : "IN" }
+{ "_id" : "46034", "city" : "CICERO", "loc" : [ -86.024844, 40.126781 ], "pop" : 4309, "state" : "IN" }
+{ "_id" : "46035", "city" : "COLFAX", "loc" : [ -86.659271, 40.195619 ], "pop" : 1343, "state" : "IN" }
+{ "_id" : "46036", "city" : "ELWOOD", "loc" : [ -85.839055, 40.280278 ], "pop" : 13598, "state" : "IN" }
+{ "_id" : "46038", "city" : "FISHERS", "loc" : [ -86.023048, 39.957486 ], "pop" : 11918, "state" : "IN" }
+{ "_id" : "46039", "city" : "FOREST", "loc" : [ -86.320098, 40.375728 ], "pop" : 879, "state" : "IN" }
+{ "_id" : "46040", "city" : "FORTVILLE", "loc" : [ -85.81855400000001, 39.922835 ], "pop" : 5887, "state" : "IN" }
+{ "_id" : "46041", "city" : "HILLISBURG", "loc" : [ -86.511387, 40.288404 ], "pop" : 20713, "state" : "IN" }
+{ "_id" : "46044", "city" : "FRANKTON", "loc" : [ -85.77911, 40.228548 ], "pop" : 3723, "state" : "IN" }
+{ "_id" : "46048", "city" : "INGALLS", "loc" : [ -85.825596, 40.000237 ], "pop" : 763, "state" : "IN" }
+{ "_id" : "46049", "city" : "KEMPTON", "loc" : [ -86.1887, 40.275946 ], "pop" : 1501, "state" : "IN" }
+{ "_id" : "46050", "city" : "KIRKLIN", "loc" : [ -86.33237200000001, 40.203066 ], "pop" : 2038, "state" : "IN" }
+{ "_id" : "46051", "city" : "LAPEL", "loc" : [ -85.84395000000001, 40.085429 ], "pop" : 3221, "state" : "IN" }
+{ "_id" : "46052", "city" : "LEBANON", "loc" : [ -86.464074, 40.044894 ], "pop" : 17322, "state" : "IN" }
+{ "_id" : "46055", "city" : "MC CORDSVILLE", "loc" : [ -85.909502, 39.901823 ], "pop" : 1450, "state" : "IN" }
+{ "_id" : "46056", "city" : "MARKLEVILLE", "loc" : [ -85.622736, 39.994385 ], "pop" : 2957, "state" : "IN" }
+{ "_id" : "46057", "city" : "MICHIGANTOWN", "loc" : [ -86.37530599999999, 40.310823 ], "pop" : 2207, "state" : "IN" }
+{ "_id" : "46058", "city" : "MULBERRY", "loc" : [ -86.661261, 40.343299 ], "pop" : 1938, "state" : "IN" }
+{ "_id" : "46060", "city" : "NOBLESVILLE", "loc" : [ -86.016294, 40.056292 ], "pop" : 26318, "state" : "IN" }
+{ "_id" : "46064", "city" : "PENDLETON", "loc" : [ -85.794614, 39.979237 ], "pop" : 13824, "state" : "IN" }
+{ "_id" : "46065", "city" : "ROSSVILLE", "loc" : [ -86.607966, 40.410928 ], "pop" : 2217, "state" : "IN" }
+{ "_id" : "46068", "city" : "SHARPSVILLE", "loc" : [ -86.10864100000001, 40.373232 ], "pop" : 3570, "state" : "IN" }
+{ "_id" : "46069", "city" : "SHERIDAN", "loc" : [ -86.23674099999999, 40.110407 ], "pop" : 7155, "state" : "IN" }
+{ "_id" : "46070", "city" : "SUMMITVILLE", "loc" : [ -85.640261, 40.339833 ], "pop" : 1902, "state" : "IN" }
+{ "_id" : "46071", "city" : "THORNTOWN", "loc" : [ -86.589822, 40.113335 ], "pop" : 4159, "state" : "IN" }
+{ "_id" : "46072", "city" : "TIPTON", "loc" : [ -86.043291, 40.281725 ], "pop" : 8060, "state" : "IN" }
+{ "_id" : "46074", "city" : "WESTFIELD", "loc" : [ -86.149907, 40.048868 ], "pop" : 6841, "state" : "IN" }
+{ "_id" : "46075", "city" : "WHITESTOWN", "loc" : [ -86.35071600000001, 40.00002 ], "pop" : 1378, "state" : "IN" }
+{ "_id" : "46076", "city" : "WINDFALL", "loc" : [ -85.947624, 40.366891 ], "pop" : 1535, "state" : "IN" }
+{ "_id" : "46077", "city" : "ZIONSVILLE", "loc" : [ -86.276737, 39.956111 ], "pop" : 9759, "state" : "IN" }
+{ "_id" : "46104", "city" : "ARLINGTON", "loc" : [ -85.582775, 39.648791 ], "pop" : 1194, "state" : "IN" }
+{ "_id" : "46105", "city" : "BAINBRIDGE", "loc" : [ -86.771119, 39.740664 ], "pop" : 3147, "state" : "IN" }
+{ "_id" : "46106", "city" : "BARGERSVILLE", "loc" : [ -86.179687, 39.499989 ], "pop" : 3310, "state" : "IN" }
+{ "_id" : "46107", "city" : "BEECH GROVE", "loc" : [ -86.093299, 39.715434 ], "pop" : 13051, "state" : "IN" }
+{ "_id" : "46110", "city" : "BOGGSTOWN", "loc" : [ -85.915965, 39.568331 ], "pop" : 958, "state" : "IN" }
+{ "_id" : "46112", "city" : "BROWNSBURG", "loc" : [ -86.386933, 39.846605 ], "pop" : 18768, "state" : "IN" }
+{ "_id" : "46113", "city" : "CAMBY", "loc" : [ -86.31181100000001, 39.640501 ], "pop" : 2681, "state" : "IN" }
+{ "_id" : "46115", "city" : "CARTHAGE", "loc" : [ -85.575382, 39.746627 ], "pop" : 1910, "state" : "IN" }
+{ "_id" : "46117", "city" : "CHARLOTTESVILLE", "loc" : [ -85.653599, 39.811981 ], "pop" : 1762, "state" : "IN" }
+{ "_id" : "46118", "city" : "CLAYTON", "loc" : [ -86.495921, 39.668154 ], "pop" : 4566, "state" : "IN" }
+{ "_id" : "46120", "city" : "CLOVERDALE", "loc" : [ -86.814021, 39.543442 ], "pop" : 7062, "state" : "IN" }
+{ "_id" : "46121", "city" : "COATESVILLE", "loc" : [ -86.63144699999999, 39.693041 ], "pop" : 1992, "state" : "IN" }
+{ "_id" : "46122", "city" : "DANVILLE", "loc" : [ -86.534254, 39.762815 ], "pop" : 8632, "state" : "IN" }
+{ "_id" : "46124", "city" : "EDINBURGH", "loc" : [ -85.97071200000001, 39.362601 ], "pop" : 5115, "state" : "IN" }
+{ "_id" : "46126", "city" : "FAIRLAND", "loc" : [ -85.891284, 39.629467 ], "pop" : 6682, "state" : "IN" }
+{ "_id" : "46127", "city" : "FALMOUTH", "loc" : [ -85.352423, 39.743617 ], "pop" : 531, "state" : "IN" }
+{ "_id" : "46128", "city" : "FILLMORE", "loc" : [ -86.746861, 39.647518 ], "pop" : 1711, "state" : "IN" }
+{ "_id" : "46130", "city" : "FOUNTAINTOWN", "loc" : [ -85.78482700000001, 39.675131 ], "pop" : 1555, "state" : "IN" }
+{ "_id" : "46131", "city" : "FRANKLIN", "loc" : [ -86.06075199999999, 39.485389 ], "pop" : 14959, "state" : "IN" }
+{ "_id" : "46133", "city" : "GLENWOOD", "loc" : [ -85.273532, 39.612436 ], "pop" : 149, "state" : "IN" }
+{ "_id" : "46135", "city" : "GREENCASTLE", "loc" : [ -86.86861399999999, 39.649487 ], "pop" : 13300, "state" : "IN" }
+{ "_id" : "46140", "city" : "GREENFIELD", "loc" : [ -85.81410200000001, 39.790204 ], "pop" : 28919, "state" : "IN" }
+{ "_id" : "46142", "city" : "GREENWOOD", "loc" : [ -86.148993, 39.622398 ], "pop" : 24735, "state" : "IN" }
+{ "_id" : "46143", "city" : "GREENWOOD", "loc" : [ -86.13091900000001, 39.596037 ], "pop" : 24633, "state" : "IN" }
+{ "_id" : "46147", "city" : "JAMESTOWN", "loc" : [ -86.623561, 39.95789 ], "pop" : 2355, "state" : "IN" }
+{ "_id" : "46148", "city" : "KNIGHTSTOWN", "loc" : [ -85.52614800000001, 39.806029 ], "pop" : 3842, "state" : "IN" }
+{ "_id" : "46149", "city" : "LIZTON", "loc" : [ -86.542857, 39.884326 ], "pop" : 1586, "state" : "IN" }
+{ "_id" : "46150", "city" : "MANILLA", "loc" : [ -85.635369, 39.575711 ], "pop" : 1696, "state" : "IN" }
+{ "_id" : "46151", "city" : "CENTERTON", "loc" : [ -86.42901000000001, 39.447646 ], "pop" : 31539, "state" : "IN" }
+{ "_id" : "46156", "city" : "MILROY", "loc" : [ -85.50437100000001, 39.495474 ], "pop" : 2154, "state" : "IN" }
+{ "_id" : "46157", "city" : "MONROVIA", "loc" : [ -86.48936999999999, 39.571397 ], "pop" : 2205, "state" : "IN" }
+{ "_id" : "46158", "city" : "MOORESVILLE", "loc" : [ -86.36417299999999, 39.591469 ], "pop" : 18800, "state" : "IN" }
+{ "_id" : "46160", "city" : "MORGANTOWN", "loc" : [ -86.280297, 39.362841 ], "pop" : 2193, "state" : "IN" }
+{ "_id" : "46161", "city" : "MORRISTOWN", "loc" : [ -85.69341900000001, 39.667477 ], "pop" : 2215, "state" : "IN" }
+{ "_id" : "46162", "city" : "NEEDHAM", "loc" : [ -86.00409399999999, 39.477935 ], "pop" : 2353, "state" : "IN" }
+{ "_id" : "46163", "city" : "NEW PALESTINE", "loc" : [ -85.90515000000001, 39.723264 ], "pop" : 3794, "state" : "IN" }
+{ "_id" : "46164", "city" : "NINEVEH", "loc" : [ -86.097641, 39.365597 ], "pop" : 3528, "state" : "IN" }
+{ "_id" : "46165", "city" : "NORTH SALEM", "loc" : [ -86.63883300000001, 39.867051 ], "pop" : 1541, "state" : "IN" }
+{ "_id" : "46166", "city" : "PARAGON", "loc" : [ -86.577867, 39.404203 ], "pop" : 1244, "state" : "IN" }
+{ "_id" : "46167", "city" : "PITTSBORO", "loc" : [ -86.46454799999999, 39.861529 ], "pop" : 3466, "state" : "IN" }
+{ "_id" : "46168", "city" : "AVON", "loc" : [ -86.395061, 39.716036 ], "pop" : 29182, "state" : "IN" }
+{ "_id" : "46171", "city" : "REELSVILLE", "loc" : [ -86.94998, 39.546416 ], "pop" : 2027, "state" : "IN" }
+{ "_id" : "46172", "city" : "ROACHDALE", "loc" : [ -86.79022500000001, 39.832545 ], "pop" : 2293, "state" : "IN" }
+{ "_id" : "46173", "city" : "RUSHVILLE", "loc" : [ -85.43212, 39.619232 ], "pop" : 11721, "state" : "IN" }
+{ "_id" : "46175", "city" : "RUSSELLVILLE", "loc" : [ -86.96697500000001, 39.836598 ], "pop" : 775, "state" : "IN" }
+{ "_id" : "46176", "city" : "SHELBYVILLE", "loc" : [ -85.787515, 39.50434 ], "pop" : 24691, "state" : "IN" }
+{ "_id" : "46180", "city" : "STILESVILLE", "loc" : [ -86.61819, 39.639113 ], "pop" : 1135, "state" : "IN" }
+{ "_id" : "46181", "city" : "TRAFALGAR", "loc" : [ -86.18379299999999, 39.369585 ], "pop" : 3538, "state" : "IN" }
+{ "_id" : "46182", "city" : "WALDRON", "loc" : [ -85.664407, 39.468849 ], "pop" : 1878, "state" : "IN" }
+{ "_id" : "46184", "city" : "NEW WHITELAND", "loc" : [ -86.093476, 39.555313 ], "pop" : 7226, "state" : "IN" }
+{ "_id" : "46186", "city" : "WILKINSON", "loc" : [ -85.61436, 39.895668 ], "pop" : 2567, "state" : "IN" }
+{ "_id" : "46201", "city" : "INDIANAPOLIS", "loc" : [ -86.109348, 39.775006 ], "pop" : 42096, "state" : "IN" }
+{ "_id" : "46202", "city" : "INDIANAPOLIS", "loc" : [ -86.159502, 39.785063 ], "pop" : 15672, "state" : "IN" }
+{ "_id" : "46203", "city" : "INDIANAPOLIS", "loc" : [ -86.117859, 39.743025 ], "pop" : 42566, "state" : "IN" }
+{ "_id" : "46204", "city" : "INDIANAPOLIS", "loc" : [ -86.153491, 39.771986 ], "pop" : 4327, "state" : "IN" }
+{ "_id" : "46205", "city" : "INDIANAPOLIS", "loc" : [ -86.138582, 39.826761 ], "pop" : 35328, "state" : "IN" }
+{ "_id" : "46208", "city" : "INDIANAPOLIS", "loc" : [ -86.179444, 39.829905 ], "pop" : 39610, "state" : "IN" }
+{ "_id" : "46214", "city" : "EAGLE CREEK", "loc" : [ -86.289952, 39.792678 ], "pop" : 16644, "state" : "IN" }
+{ "_id" : "46216", "city" : "FORT BENJAMIN HA", "loc" : [ -86.016688, 39.857731 ], "pop" : 1566, "state" : "IN" }
+{ "_id" : "46217", "city" : "SOUTHPORT", "loc" : [ -86.175394, 39.664141 ], "pop" : 16644, "state" : "IN" }
+{ "_id" : "46218", "city" : "INDIANAPOLIS", "loc" : [ -86.10142500000001, 39.80817 ], "pop" : 39965, "state" : "IN" }
+{ "_id" : "46219", "city" : "INDIANAPOLIS", "loc" : [ -86.049533, 39.782092 ], "pop" : 38198, "state" : "IN" }
+{ "_id" : "46220", "city" : "INDIANAPOLIS", "loc" : [ -86.11815, 39.864685 ], "pop" : 35482, "state" : "IN" }
+{ "_id" : "46221", "city" : "INDIANAPOLIS", "loc" : [ -86.19243, 39.750885 ], "pop" : 7920, "state" : "IN" }
+{ "_id" : "46222", "city" : "INDIANAPOLIS", "loc" : [ -86.21357399999999, 39.788971 ], "pop" : 39240, "state" : "IN" }
+{ "_id" : "46224", "city" : "SPEEDWAY", "loc" : [ -86.25730799999999, 39.798674 ], "pop" : 32130, "state" : "IN" }
+{ "_id" : "46225", "city" : "INDIANAPOLIS", "loc" : [ -86.156944, 39.740599 ], "pop" : 8464, "state" : "IN" }
+{ "_id" : "46226", "city" : "LAWRENCE", "loc" : [ -86.048945, 39.836969 ], "pop" : 47144, "state" : "IN" }
+{ "_id" : "46227", "city" : "SOUTHPORT", "loc" : [ -86.129817, 39.675 ], "pop" : 52257, "state" : "IN" }
+{ "_id" : "46229", "city" : "CUMBERLAND", "loc" : [ -85.98382599999999, 39.792219 ], "pop" : 19914, "state" : "IN" }
+{ "_id" : "46231", "city" : "BRIDGEPORT", "loc" : [ -86.31828899999999, 39.740637 ], "pop" : 5531, "state" : "IN" }
+{ "_id" : "46234", "city" : "CLERMONT", "loc" : [ -86.324117, 39.788438 ], "pop" : 13865, "state" : "IN" }
+{ "_id" : "46236", "city" : "OAKLANDON", "loc" : [ -85.98505900000001, 39.849588 ], "pop" : 31475, "state" : "IN" }
+{ "_id" : "46237", "city" : "SOUTHPORT", "loc" : [ -86.07890999999999, 39.686777 ], "pop" : 18919, "state" : "IN" }
+{ "_id" : "46239", "city" : "WANAMAKER", "loc" : [ -86.00820899999999, 39.721826 ], "pop" : 8611, "state" : "IN" }
+{ "_id" : "46240", "city" : "NORA", "loc" : [ -86.129548, 39.9057 ], "pop" : 17553, "state" : "IN" }
+{ "_id" : "46241", "city" : "PARK FLETCHER", "loc" : [ -86.250856, 39.723814 ], "pop" : 44731, "state" : "IN" }
+{ "_id" : "46250", "city" : "CASTLETON", "loc" : [ -86.069112, 39.9069 ], "pop" : 17196, "state" : "IN" }
+{ "_id" : "46254", "city" : "EAGLE CREEK", "loc" : [ -86.2638, 39.841379 ], "pop" : 23015, "state" : "IN" }
+{ "_id" : "46256", "city" : "CASTLETON", "loc" : [ -86.023877, 39.90114 ], "pop" : 20589, "state" : "IN" }
+{ "_id" : "46259", "city" : "ACTON", "loc" : [ -85.992603, 39.660901 ], "pop" : 3642, "state" : "IN" }
+{ "_id" : "46260", "city" : "NORA", "loc" : [ -86.184809, 39.897488 ], "pop" : 29718, "state" : "IN" }
+{ "_id" : "46268", "city" : "NEW AUGUSTA", "loc" : [ -86.222104, 39.900296 ], "pop" : 14109, "state" : "IN" }
+{ "_id" : "46278", "city" : "NEW AUGUSTA", "loc" : [ -86.291455, 39.883858 ], "pop" : 4727, "state" : "IN" }
+{ "_id" : "46280", "city" : "NORA", "loc" : [ -86.13894000000001, 39.938417 ], "pop" : 5281, "state" : "IN" }
+{ "_id" : "46290", "city" : "NORA", "loc" : [ -86.167118, 39.93077 ], "pop" : 75, "state" : "IN" }
+{ "_id" : "46303", "city" : "EAST CEDAR LAKE", "loc" : [ -87.444509, 41.377338 ], "pop" : 11557, "state" : "IN" }
+{ "_id" : "46304", "city" : "PORTER", "loc" : [ -87.050196, 41.603949 ], "pop" : 19024, "state" : "IN" }
+{ "_id" : "46307", "city" : "CROWN POINT", "loc" : [ -87.355586, 41.423571 ], "pop" : 37816, "state" : "IN" }
+{ "_id" : "46310", "city" : "DEMOTTE", "loc" : [ -87.249129, 41.171319 ], "pop" : 10188, "state" : "IN" }
+{ "_id" : "46311", "city" : "DYER", "loc" : [ -87.510803, 41.491976 ], "pop" : 13426, "state" : "IN" }
+{ "_id" : "46312", "city" : "EAST CHICAGO", "loc" : [ -87.462734, 41.634893 ], "pop" : 33775, "state" : "IN" }
+{ "_id" : "46319", "city" : "GRIFFITH", "loc" : [ -87.422837, 41.53352 ], "pop" : 19758, "state" : "IN" }
+{ "_id" : "46320", "city" : "HAMMOND", "loc" : [ -87.50791099999999, 41.609929 ], "pop" : 16636, "state" : "IN" }
+{ "_id" : "46321", "city" : "MUNSTER", "loc" : [ -87.50110100000001, 41.554438 ], "pop" : 19906, "state" : "IN" }
+{ "_id" : "46322", "city" : "HIGHLAND", "loc" : [ -87.45691100000001, 41.55005 ], "pop" : 24029, "state" : "IN" }
+{ "_id" : "46323", "city" : "HAMMOND", "loc" : [ -87.45319600000001, 41.587755 ], "pop" : 23456, "state" : "IN" }
+{ "_id" : "46324", "city" : "HAMMOND", "loc" : [ -87.503393, 41.583954 ], "pop" : 23585, "state" : "IN" }
+{ "_id" : "46327", "city" : "HAMMOND", "loc" : [ -87.51134999999999, 41.632695 ], "pop" : 12384, "state" : "IN" }
+{ "_id" : "46340", "city" : "HANNA", "loc" : [ -86.77592199999999, 41.408767 ], "pop" : 941, "state" : "IN" }
+{ "_id" : "46341", "city" : "HEBRON", "loc" : [ -87.20879100000001, 41.315537 ], "pop" : 6230, "state" : "IN" }
+{ "_id" : "46342", "city" : "HOBART", "loc" : [ -87.252499, 41.526281 ], "pop" : 32127, "state" : "IN" }
+{ "_id" : "46347", "city" : "KOUTS", "loc" : [ -87.02404300000001, 41.309085 ], "pop" : 3244, "state" : "IN" }
+{ "_id" : "46348", "city" : "LA CROSSE", "loc" : [ -86.868216, 41.315709 ], "pop" : 1352, "state" : "IN" }
+{ "_id" : "46349", "city" : "LAKE VILLAGE", "loc" : [ -87.44542199999999, 41.138741 ], "pop" : 2208, "state" : "IN" }
+{ "_id" : "46350", "city" : "LA PORTE", "loc" : [ -86.70765400000001, 41.599438 ], "pop" : 36301, "state" : "IN" }
+{ "_id" : "46356", "city" : "LOWELL", "loc" : [ -87.419072, 41.284531 ], "pop" : 12579, "state" : "IN" }
+{ "_id" : "46360", "city" : "MICHIGAN CITY", "loc" : [ -86.869899, 41.698031 ], "pop" : 55392, "state" : "IN" }
+{ "_id" : "46365", "city" : "MILL CREEK", "loc" : [ -86.547247, 41.556102 ], "pop" : 2091, "state" : "IN" }
+{ "_id" : "46366", "city" : "NORTH JUDSON", "loc" : [ -86.696601, 41.224372 ], "pop" : 8426, "state" : "IN" }
+{ "_id" : "46368", "city" : "PORTAGE", "loc" : [ -87.17568900000001, 41.567201 ], "pop" : 40860, "state" : "IN" }
+{ "_id" : "46371", "city" : "ROLLING PRAIRIE", "loc" : [ -86.584092, 41.72286 ], "pop" : 3694, "state" : "IN" }
+{ "_id" : "46373", "city" : "SAINT JOHN", "loc" : [ -87.476376, 41.44949 ], "pop" : 4786, "state" : "IN" }
+{ "_id" : "46374", "city" : "SAN PIERRE", "loc" : [ -86.87253200000001, 41.21108 ], "pop" : 1499, "state" : "IN" }
+{ "_id" : "46375", "city" : "SCHERERVILLE", "loc" : [ -87.460532, 41.492233 ], "pop" : 14152, "state" : "IN" }
+{ "_id" : "46382", "city" : "UNION MILLS", "loc" : [ -86.83551199999999, 41.460236 ], "pop" : 3155, "state" : "IN" }
+{ "_id" : "46383", "city" : "VALPARAISO", "loc" : [ -87.075866, 41.475661 ], "pop" : 53439, "state" : "IN" }
+{ "_id" : "46390", "city" : "WANATAH", "loc" : [ -86.876439, 41.384477 ], "pop" : 711, "state" : "IN" }
+{ "_id" : "46391", "city" : "WESTVILLE", "loc" : [ -86.90131700000001, 41.536516 ], "pop" : 6212, "state" : "IN" }
+{ "_id" : "46392", "city" : "WHEATFIELD", "loc" : [ -87.06987599999999, 41.177948 ], "pop" : 5415, "state" : "IN" }
+{ "_id" : "46394", "city" : "WHITING", "loc" : [ -87.50053699999999, 41.678656 ], "pop" : 13157, "state" : "IN" }
+{ "_id" : "46402", "city" : "GARY", "loc" : [ -87.338548, 41.599711 ], "pop" : 10873, "state" : "IN" }
+{ "_id" : "46403", "city" : "GARY", "loc" : [ -87.258984, 41.603612 ], "pop" : 16489, "state" : "IN" }
+{ "_id" : "46404", "city" : "GARY", "loc" : [ -87.373153, 41.589937 ], "pop" : 23031, "state" : "IN" }
+{ "_id" : "46405", "city" : "LAKE STATION", "loc" : [ -87.262209, 41.568629 ], "pop" : 12437, "state" : "IN" }
+{ "_id" : "46406", "city" : "GARY", "loc" : [ -87.40621, 41.587806 ], "pop" : 15132, "state" : "IN" }
+{ "_id" : "46407", "city" : "GARY", "loc" : [ -87.334958, 41.580429 ], "pop" : 21360, "state" : "IN" }
+{ "_id" : "46408", "city" : "GARY", "loc" : [ -87.35883, 41.542178 ], "pop" : 21586, "state" : "IN" }
+{ "_id" : "46409", "city" : "GARY", "loc" : [ -87.32712600000001, 41.541247 ], "pop" : 14119, "state" : "IN" }
+{ "_id" : "46410", "city" : "MERRILLVILLE", "loc" : [ -87.350932, 41.4957 ], "pop" : 30765, "state" : "IN" }
+{ "_id" : "46501", "city" : "ARGOS", "loc" : [ -86.250573, 41.230827 ], "pop" : 3630, "state" : "IN" }
+{ "_id" : "46504", "city" : "BOURBON", "loc" : [ -86.11743800000001, 41.309785 ], "pop" : 2976, "state" : "IN" }
+{ "_id" : "46506", "city" : "BREMEN", "loc" : [ -86.19323, 41.446701 ], "pop" : 13832, "state" : "IN" }
+{ "_id" : "46507", "city" : "BRISTOL", "loc" : [ -85.82619200000001, 41.716885 ], "pop" : 7086, "state" : "IN" }
+{ "_id" : "46510", "city" : "CLAYPOOL", "loc" : [ -85.868571, 41.116497 ], "pop" : 4891, "state" : "IN" }
+{ "_id" : "46511", "city" : "CULVER MILITARY", "loc" : [ -86.412888, 41.22307 ], "pop" : 3289, "state" : "IN" }
+{ "_id" : "46514", "city" : "ELKHART", "loc" : [ -85.972949, 41.710083 ], "pop" : 33830, "state" : "IN" }
+{ "_id" : "46516", "city" : "ELKHART", "loc" : [ -85.962137, 41.676333 ], "pop" : 29971, "state" : "IN" }
+{ "_id" : "46517", "city" : "ELKHART", "loc" : [ -85.972849, 41.646922 ], "pop" : 17983, "state" : "IN" }
+{ "_id" : "46524", "city" : "ETNA GREEN", "loc" : [ -86.034995, 41.291789 ], "pop" : 1290, "state" : "IN" }
+{ "_id" : "46526", "city" : "FORAKER", "loc" : [ -85.837988, 41.584484 ], "pop" : 41317, "state" : "IN" }
+{ "_id" : "46530", "city" : "GRANGER", "loc" : [ -86.141104, 41.742704 ], "pop" : 17591, "state" : "IN" }
+{ "_id" : "46531", "city" : "GROVERTOWN", "loc" : [ -86.52890499999999, 41.321969 ], "pop" : 1077, "state" : "IN" }
+{ "_id" : "46532", "city" : "HAMLET", "loc" : [ -86.53213, 41.393338 ], "pop" : 4314, "state" : "IN" }
+{ "_id" : "46534", "city" : "OBER", "loc" : [ -86.610715, 41.29006 ], "pop" : 7437, "state" : "IN" }
+{ "_id" : "46536", "city" : "LAKEVILLE", "loc" : [ -86.27144, 41.525328 ], "pop" : 3355, "state" : "IN" }
+{ "_id" : "46538", "city" : "LEESBURG", "loc" : [ -85.816028, 41.326592 ], "pop" : 1823, "state" : "IN" }
+{ "_id" : "46539", "city" : "MENTONE", "loc" : [ -86.029918, 41.161494 ], "pop" : 2163, "state" : "IN" }
+{ "_id" : "46540", "city" : "MIDDLEBURY", "loc" : [ -85.711443, 41.675415 ], "pop" : 7737, "state" : "IN" }
+{ "_id" : "46542", "city" : "MILFORD", "loc" : [ -85.85543800000001, 41.401141 ], "pop" : 4861, "state" : "IN" }
+{ "_id" : "46543", "city" : "MILLERSBURG", "loc" : [ -85.707249, 41.533513 ], "pop" : 2078, "state" : "IN" }
+{ "_id" : "46544", "city" : "MISHAWAKA", "loc" : [ -86.162301, 41.650659 ], "pop" : 29911, "state" : "IN" }
+{ "_id" : "46545", "city" : "MISHAWAKA", "loc" : [ -86.168232, 41.683498 ], "pop" : 23031, "state" : "IN" }
+{ "_id" : "46550", "city" : "NAPPANEE", "loc" : [ -85.994534, 41.449297 ], "pop" : 10640, "state" : "IN" }
+{ "_id" : "46552", "city" : "NEW CARLISLE", "loc" : [ -86.48382700000001, 41.705115 ], "pop" : 3574, "state" : "IN" }
+{ "_id" : "46553", "city" : "NEW PARIS", "loc" : [ -85.83383000000001, 41.491652 ], "pop" : 2723, "state" : "IN" }
+{ "_id" : "46554", "city" : "NORTH LIBERTY", "loc" : [ -86.41332800000001, 41.542507 ], "pop" : 4056, "state" : "IN" }
+{ "_id" : "46555", "city" : "NORTH WEBSTER", "loc" : [ -85.70787199999999, 41.308423 ], "pop" : 6197, "state" : "IN" }
+{ "_id" : "46556", "city" : "SAINT MARYS", "loc" : [ -86.242893, 41.70057 ], "pop" : 6903, "state" : "IN" }
+{ "_id" : "46561", "city" : "OSCEOLA", "loc" : [ -86.078883, 41.674074 ], "pop" : 8029, "state" : "IN" }
+{ "_id" : "46562", "city" : "PIERCETON", "loc" : [ -85.706119, 41.212406 ], "pop" : 3128, "state" : "IN" }
+{ "_id" : "46563", "city" : "INWOOD", "loc" : [ -86.32408700000001, 41.333897 ], "pop" : 16087, "state" : "IN" }
+{ "_id" : "46565", "city" : "SHIPSHEWANA", "loc" : [ -85.593198, 41.663257 ], "pop" : 3850, "state" : "IN" }
+{ "_id" : "46567", "city" : "SYRACUSE", "loc" : [ -85.718352, 41.40649 ], "pop" : 7695, "state" : "IN" }
+{ "_id" : "46570", "city" : "TIPPECANOE", "loc" : [ -86.10950800000001, 41.216609 ], "pop" : 1188, "state" : "IN" }
+{ "_id" : "46571", "city" : "TOPEKA", "loc" : [ -85.531668, 41.563441 ], "pop" : 5749, "state" : "IN" }
+{ "_id" : "46573", "city" : "WAKARUSA", "loc" : [ -86.02052399999999, 41.540073 ], "pop" : 2776, "state" : "IN" }
+{ "_id" : "46574", "city" : "WALKERTON", "loc" : [ -86.451018, 41.445748 ], "pop" : 5279, "state" : "IN" }
+{ "_id" : "46580", "city" : "WARSAW", "loc" : [ -85.85078, 41.24377 ], "pop" : 22851, "state" : "IN" }
+{ "_id" : "46590", "city" : "WINONA LAKE", "loc" : [ -85.83053099999999, 41.211007 ], "pop" : 7559, "state" : "IN" }
+{ "_id" : "46601", "city" : "SOUTH BEND", "loc" : [ -86.253489, 41.672699 ], "pop" : 5479, "state" : "IN" }
+{ "_id" : "46613", "city" : "SOUTH BEND", "loc" : [ -86.247865, 41.654636 ], "pop" : 11827, "state" : "IN" }
+{ "_id" : "46614", "city" : "SOUTH BEND", "loc" : [ -86.243278, 41.625461 ], "pop" : 27521, "state" : "IN" }
+{ "_id" : "46615", "city" : "SOUTH BEND", "loc" : [ -86.210375, 41.67413 ], "pop" : 15580, "state" : "IN" }
+{ "_id" : "46616", "city" : "SOUTH BEND", "loc" : [ -86.26473900000001, 41.691894 ], "pop" : 8132, "state" : "IN" }
+{ "_id" : "46617", "city" : "SOUTH BEND", "loc" : [ -86.2351, 41.684966 ], "pop" : 11057, "state" : "IN" }
+{ "_id" : "46619", "city" : "SOUTH BEND", "loc" : [ -86.31526599999999, 41.667397 ], "pop" : 19880, "state" : "IN" }
+{ "_id" : "46628", "city" : "SOUTH BEND", "loc" : [ -86.294929, 41.701525 ], "pop" : 24914, "state" : "IN" }
+{ "_id" : "46635", "city" : "SOUTH BEND", "loc" : [ -86.20780600000001, 41.716768 ], "pop" : 6989, "state" : "IN" }
+{ "_id" : "46637", "city" : "SOUTH BEND", "loc" : [ -86.240694, 41.729936 ], "pop" : 16351, "state" : "IN" }
+{ "_id" : "46701", "city" : "ALBION", "loc" : [ -85.41418299999999, 41.348217 ], "pop" : 6907, "state" : "IN" }
+{ "_id" : "46702", "city" : "ANDREWS", "loc" : [ -85.60672599999999, 40.861792 ], "pop" : 2138, "state" : "IN" }
+{ "_id" : "46703", "city" : "ANGOLA", "loc" : [ -85.019803, 41.656321 ], "pop" : 15134, "state" : "IN" }
+{ "_id" : "46705", "city" : "ASHLEY", "loc" : [ -85.05038500000001, 41.534651 ], "pop" : 1272, "state" : "IN" }
+{ "_id" : "46706", "city" : "AUBURN", "loc" : [ -85.046848, 41.359001 ], "pop" : 12503, "state" : "IN" }
+{ "_id" : "46710", "city" : "AVILLA", "loc" : [ -85.241418, 41.36894 ], "pop" : 2154, "state" : "IN" }
+{ "_id" : "46711", "city" : "LINN GROVE", "loc" : [ -84.934271, 40.661517 ], "pop" : 6577, "state" : "IN" }
+{ "_id" : "46714", "city" : "BLUFFTON", "loc" : [ -85.162199, 40.736837 ], "pop" : 14669, "state" : "IN" }
+{ "_id" : "46721", "city" : "BUTLER", "loc" : [ -84.878716, 41.42873 ], "pop" : 5982, "state" : "IN" }
+{ "_id" : "46723", "city" : "CHURUBUSCO", "loc" : [ -85.324364, 41.228988 ], "pop" : 6796, "state" : "IN" }
+{ "_id" : "46725", "city" : "COLUMBIA CITY", "loc" : [ -85.473736, 41.161855 ], "pop" : 17282, "state" : "IN" }
+{ "_id" : "46730", "city" : "CORUNNA", "loc" : [ -85.137028, 41.450377 ], "pop" : 2373, "state" : "IN" }
+{ "_id" : "46731", "city" : "CRAIGVILLE", "loc" : [ -85.090379, 40.793034 ], "pop" : 323, "state" : "IN" }
+{ "_id" : "46732", "city" : "CROMWELL", "loc" : [ -85.603133, 41.37514 ], "pop" : 2872, "state" : "IN" }
+{ "_id" : "46733", "city" : "DECATUR", "loc" : [ -84.931432, 40.827333 ], "pop" : 19069, "state" : "IN" }
+{ "_id" : "46737", "city" : "FREMONT", "loc" : [ -84.94524699999999, 41.733125 ], "pop" : 4248, "state" : "IN" }
+{ "_id" : "46738", "city" : "GARRETT", "loc" : [ -85.13467, 41.348216 ], "pop" : 6459, "state" : "IN" }
+{ "_id" : "46740", "city" : "GENEVA", "loc" : [ -84.962074, 40.607129 ], "pop" : 3676, "state" : "IN" }
+{ "_id" : "46741", "city" : "GRABILL", "loc" : [ -84.94059300000001, 41.210753 ], "pop" : 4267, "state" : "IN" }
+{ "_id" : "46742", "city" : "HAMILTON", "loc" : [ -84.89509200000001, 41.5566 ], "pop" : 2344, "state" : "IN" }
+{ "_id" : "46743", "city" : "HARLAN", "loc" : [ -84.838635, 41.228468 ], "pop" : 653, "state" : "IN" }
+{ "_id" : "46745", "city" : "HOAGLAND", "loc" : [ -85.00751, 40.952375 ], "pop" : 1483, "state" : "IN" }
+{ "_id" : "46746", "city" : "HOWE", "loc" : [ -85.472746, 41.728594 ], "pop" : 6040, "state" : "IN" }
+{ "_id" : "46747", "city" : "HELMER", "loc" : [ -85.141953, 41.559887 ], "pop" : 2012, "state" : "IN" }
+{ "_id" : "46748", "city" : "HUNTERTOWN", "loc" : [ -85.16772400000001, 41.239113 ], "pop" : 2265, "state" : "IN" }
+{ "_id" : "46750", "city" : "HUNTINGTON", "loc" : [ -85.505438, 40.881128 ], "pop" : 23716, "state" : "IN" }
+{ "_id" : "46755", "city" : "KENDALLVILLE", "loc" : [ -85.260874, 41.448206 ], "pop" : 11784, "state" : "IN" }
+{ "_id" : "46759", "city" : "KEYSTONE", "loc" : [ -85.276748, 40.589667 ], "pop" : 518, "state" : "IN" }
+{ "_id" : "46760", "city" : "KIMMELL", "loc" : [ -85.51873399999999, 41.363103 ], "pop" : 2095, "state" : "IN" }
+{ "_id" : "46761", "city" : "LAGRANGE", "loc" : [ -85.40401, 41.652008 ], "pop" : 8410, "state" : "IN" }
+{ "_id" : "46763", "city" : "LAOTTO", "loc" : [ -85.19008599999999, 41.299119 ], "pop" : 3483, "state" : "IN" }
+{ "_id" : "46764", "city" : "LARWILL", "loc" : [ -85.61386899999999, 41.164623 ], "pop" : 1496, "state" : "IN" }
+{ "_id" : "46765", "city" : "LEO", "loc" : [ -85.03009299999999, 41.224864 ], "pop" : 3047, "state" : "IN" }
+{ "_id" : "46766", "city" : "LIBERTY CENTER", "loc" : [ -85.277411, 40.700159 ], "pop" : 1027, "state" : "IN" }
+{ "_id" : "46767", "city" : "LIGONIER", "loc" : [ -85.59272, 41.466175 ], "pop" : 5212, "state" : "IN" }
+{ "_id" : "46770", "city" : "MARKLE", "loc" : [ -85.373994, 40.837972 ], "pop" : 3084, "state" : "IN" }
+{ "_id" : "46772", "city" : "MONROE", "loc" : [ -84.844128, 40.700523 ], "pop" : 873, "state" : "IN" }
+{ "_id" : "46773", "city" : "MONROEVILLE", "loc" : [ -84.89373000000001, 40.987044 ], "pop" : 4093, "state" : "IN" }
+{ "_id" : "46774", "city" : "NEW HAVEN", "loc" : [ -85.01173, 41.069856 ], "pop" : 12742, "state" : "IN" }
+{ "_id" : "46776", "city" : "ORLAND", "loc" : [ -85.146512, 41.730884 ], "pop" : 1326, "state" : "IN" }
+{ "_id" : "46777", "city" : "OSSIAN", "loc" : [ -85.15704100000001, 40.880611 ], "pop" : 5394, "state" : "IN" }
+{ "_id" : "46779", "city" : "PLEASANT LAKE", "loc" : [ -85.021276, 41.584255 ], "pop" : 1625, "state" : "IN" }
+{ "_id" : "46781", "city" : "PONETO", "loc" : [ -85.25618799999999, 40.641871 ], "pop" : 709, "state" : "IN" }
+{ "_id" : "46783", "city" : "ROANOKE", "loc" : [ -85.35263, 40.960003 ], "pop" : 4973, "state" : "IN" }
+{ "_id" : "46784", "city" : "ROME CITY", "loc" : [ -85.374303, 41.484907 ], "pop" : 3040, "state" : "IN" }
+{ "_id" : "46785", "city" : "SAINT JOE", "loc" : [ -84.90425, 41.324049 ], "pop" : 1161, "state" : "IN" }
+{ "_id" : "46787", "city" : "SOUTH WHITLEY", "loc" : [ -85.61425199999999, 41.072635 ], "pop" : 3791, "state" : "IN" }
+{ "_id" : "46788", "city" : "SPENCERVILLE", "loc" : [ -84.93975, 41.269555 ], "pop" : 1905, "state" : "IN" }
+{ "_id" : "46791", "city" : "UNIONDALE", "loc" : [ -85.273206, 40.871658 ], "pop" : 2419, "state" : "IN" }
+{ "_id" : "46792", "city" : "WARREN", "loc" : [ -85.41833699999999, 40.688646 ], "pop" : 2404, "state" : "IN" }
+{ "_id" : "46793", "city" : "WATERLOO", "loc" : [ -85.022103, 41.440216 ], "pop" : 3802, "state" : "IN" }
+{ "_id" : "46794", "city" : "WAWAKA", "loc" : [ -85.48042700000001, 41.483251 ], "pop" : 1545, "state" : "IN" }
+{ "_id" : "46795", "city" : "WOLCOTTVILLE", "loc" : [ -85.314986, 41.556972 ], "pop" : 5921, "state" : "IN" }
+{ "_id" : "46797", "city" : "WOODBURN", "loc" : [ -84.892871, 41.136102 ], "pop" : 5044, "state" : "IN" }
+{ "_id" : "46798", "city" : "YODER", "loc" : [ -85.19582800000001, 40.937059 ], "pop" : 691, "state" : "IN" }
+{ "_id" : "46802", "city" : "FORT WAYNE", "loc" : [ -85.15431, 41.070717 ], "pop" : 10837, "state" : "IN" }
+{ "_id" : "46803", "city" : "FORT WAYNE", "loc" : [ -85.10736199999999, 41.069452 ], "pop" : 13295, "state" : "IN" }
+{ "_id" : "46804", "city" : "FORT WAYNE", "loc" : [ -85.256013, 41.050843 ], "pop" : 23713, "state" : "IN" }
+{ "_id" : "46805", "city" : "FORT WAYNE", "loc" : [ -85.118865, 41.097663 ], "pop" : 22657, "state" : "IN" }
+{ "_id" : "46806", "city" : "FORT WAYNE", "loc" : [ -85.113496, 41.047988 ], "pop" : 28184, "state" : "IN" }
+{ "_id" : "46807", "city" : "FORT WAYNE", "loc" : [ -85.14616700000001, 41.049054 ], "pop" : 18346, "state" : "IN" }
+{ "_id" : "46808", "city" : "FORT WAYNE", "loc" : [ -85.162121, 41.093877 ], "pop" : 19401, "state" : "IN" }
+{ "_id" : "46809", "city" : "FORT WAYNE", "loc" : [ -85.18340000000001, 41.02543 ], "pop" : 9804, "state" : "IN" }
+{ "_id" : "46815", "city" : "FORT WAYNE", "loc" : [ -85.062397, 41.105318 ], "pop" : 25377, "state" : "IN" }
+{ "_id" : "46816", "city" : "FORT WAYNE", "loc" : [ -85.097573, 41.016519 ], "pop" : 15507, "state" : "IN" }
+{ "_id" : "46818", "city" : "FORT WAYNE", "loc" : [ -85.206686, 41.146847 ], "pop" : 10155, "state" : "IN" }
+{ "_id" : "46819", "city" : "FORT WAYNE", "loc" : [ -85.152743, 41.005167 ], "pop" : 9139, "state" : "IN" }
+{ "_id" : "46825", "city" : "FORT WAYNE", "loc" : [ -85.12315599999999, 41.146482 ], "pop" : 19522, "state" : "IN" }
+{ "_id" : "46835", "city" : "FORT WAYNE", "loc" : [ -85.06853099999999, 41.137051 ], "pop" : 26758, "state" : "IN" }
+{ "_id" : "46845", "city" : "FORT WAYNE", "loc" : [ -85.119088, 41.195783 ], "pop" : 9168, "state" : "IN" }
+{ "_id" : "46901", "city" : "KOKOMO", "loc" : [ -86.145273, 40.49884 ], "pop" : 37261, "state" : "IN" }
+{ "_id" : "46902", "city" : "KOKOMO", "loc" : [ -86.135227, 40.450856 ], "pop" : 36889, "state" : "IN" }
+{ "_id" : "46910", "city" : "AKRON", "loc" : [ -86.03947100000001, 41.038921 ], "pop" : 2617, "state" : "IN" }
+{ "_id" : "46911", "city" : "AMBOY", "loc" : [ -85.949726, 40.610505 ], "pop" : 1555, "state" : "IN" }
+{ "_id" : "46913", "city" : "BRINGHURST", "loc" : [ -86.520369, 40.516294 ], "pop" : 212, "state" : "IN" }
+{ "_id" : "46914", "city" : "BUNKER HILL", "loc" : [ -86.09614999999999, 40.642267 ], "pop" : 3073, "state" : "IN" }
+{ "_id" : "46917", "city" : "CAMDEN", "loc" : [ -86.51521700000001, 40.599588 ], "pop" : 1527, "state" : "IN" }
+{ "_id" : "46919", "city" : "CONVERSE", "loc" : [ -85.876299, 40.577031 ], "pop" : 1353, "state" : "IN" }
+{ "_id" : "46920", "city" : "CUTLER", "loc" : [ -86.446172, 40.4785 ], "pop" : 2495, "state" : "IN" }
+{ "_id" : "46923", "city" : "DELPHI", "loc" : [ -86.678849, 40.57339 ], "pop" : 7576, "state" : "IN" }
+{ "_id" : "46926", "city" : "CHILI", "loc" : [ -86.076953, 40.869363 ], "pop" : 5339, "state" : "IN" }
+{ "_id" : "46928", "city" : "FAIRMOUNT", "loc" : [ -85.67132700000001, 40.418755 ], "pop" : 6230, "state" : "IN" }
+{ "_id" : "46929", "city" : "FLORA", "loc" : [ -86.501572, 40.544467 ], "pop" : 3249, "state" : "IN" }
+{ "_id" : "46932", "city" : "GALVESTON", "loc" : [ -86.1972, 40.586249 ], "pop" : 3059, "state" : "IN" }
+{ "_id" : "46933", "city" : "GAS CITY", "loc" : [ -85.60553299999999, 40.487895 ], "pop" : 6975, "state" : "IN" }
+{ "_id" : "46936", "city" : "GREENTOWN", "loc" : [ -85.958195, 40.479096 ], "pop" : 5785, "state" : "IN" }
+{ "_id" : "46938", "city" : "JONESBORO", "loc" : [ -85.63649599999999, 40.481456 ], "pop" : 3989, "state" : "IN" }
+{ "_id" : "46939", "city" : "KEWANNA", "loc" : [ -86.40605499999999, 41.008706 ], "pop" : 1966, "state" : "IN" }
+{ "_id" : "46940", "city" : "LA FONTAINE", "loc" : [ -85.697138, 40.690896 ], "pop" : 2947, "state" : "IN" }
+{ "_id" : "46941", "city" : "LAGRO", "loc" : [ -85.72044699999999, 40.819897 ], "pop" : 2255, "state" : "IN" }
+{ "_id" : "46947", "city" : "LOGANSPORT", "loc" : [ -86.359888, 40.760377 ], "pop" : 27829, "state" : "IN" }
+{ "_id" : "46950", "city" : "LUCERNE", "loc" : [ -86.407726, 40.861434 ], "pop" : 809, "state" : "IN" }
+{ "_id" : "46951", "city" : "MACY", "loc" : [ -86.126428, 40.961838 ], "pop" : 633, "state" : "IN" }
+{ "_id" : "46952", "city" : "MARION", "loc" : [ -85.674127, 40.574333 ], "pop" : 24986, "state" : "IN" }
+{ "_id" : "46953", "city" : "MARION", "loc" : [ -85.661624, 40.53592 ], "pop" : 22079, "state" : "IN" }
+{ "_id" : "46960", "city" : "MONTEREY", "loc" : [ -86.51786199999999, 41.138334 ], "pop" : 997, "state" : "IN" }
+{ "_id" : "46962", "city" : "NORTH MANCHESTER", "loc" : [ -85.784184, 40.998603 ], "pop" : 10772, "state" : "IN" }
+{ "_id" : "46970", "city" : "PERU", "loc" : [ -86.068044, 40.749203 ], "pop" : 19549, "state" : "IN" }
+{ "_id" : "46971", "city" : "GRISSOM AIR FORC", "loc" : [ -86.14729199999999, 40.663546 ], "pop" : 4364, "state" : "IN" }
+{ "_id" : "46974", "city" : "ROANN", "loc" : [ -85.88988500000001, 40.906649 ], "pop" : 1612, "state" : "IN" }
+{ "_id" : "46975", "city" : "ROCHESTER", "loc" : [ -86.23100700000001, 41.065493 ], "pop" : 14259, "state" : "IN" }
+{ "_id" : "46978", "city" : "ROYAL CENTER", "loc" : [ -86.507751, 40.864499 ], "pop" : 1558, "state" : "IN" }
+{ "_id" : "46979", "city" : "RUSSIAVILLE", "loc" : [ -86.267467, 40.415086 ], "pop" : 1724, "state" : "IN" }
+{ "_id" : "46982", "city" : "SILVER LAKE", "loc" : [ -85.87920699999999, 41.074318 ], "pop" : 1566, "state" : "IN" }
+{ "_id" : "46985", "city" : "STAR CITY", "loc" : [ -86.54040500000001, 40.960176 ], "pop" : 951, "state" : "IN" }
+{ "_id" : "46986", "city" : "SWAYZEE", "loc" : [ -85.826542, 40.511199 ], "pop" : 1891, "state" : "IN" }
+{ "_id" : "46988", "city" : "TWELVE MILE", "loc" : [ -86.21259499999999, 40.854661 ], "pop" : 873, "state" : "IN" }
+{ "_id" : "46989", "city" : "UPLAND", "loc" : [ -85.499049, 40.454841 ], "pop" : 6027, "state" : "IN" }
+{ "_id" : "46990", "city" : "URBANA", "loc" : [ -85.748481, 40.898655 ], "pop" : 505, "state" : "IN" }
+{ "_id" : "46991", "city" : "LANDESS", "loc" : [ -85.481891, 40.63199 ], "pop" : 3670, "state" : "IN" }
+{ "_id" : "46992", "city" : "WABASH", "loc" : [ -85.83212399999999, 40.790947 ], "pop" : 17371, "state" : "IN" }
+{ "_id" : "46994", "city" : "WALTON", "loc" : [ -86.280501, 40.677225 ], "pop" : 4935, "state" : "IN" }
+{ "_id" : "46996", "city" : "WINAMAC", "loc" : [ -86.630697, 41.056242 ], "pop" : 6857, "state" : "IN" }
+{ "_id" : "47001", "city" : "AURORA", "loc" : [ -84.945188, 39.071897 ], "pop" : 9435, "state" : "IN" }
+{ "_id" : "47006", "city" : "BATESVILLE", "loc" : [ -85.222053, 39.300057 ], "pop" : 6963, "state" : "IN" }
+{ "_id" : "47010", "city" : "BATH", "loc" : [ -84.836007, 39.499237 ], "pop" : 197, "state" : "IN" }
+{ "_id" : "47011", "city" : "BENNINGTON", "loc" : [ -85.07189700000001, 38.875993 ], "pop" : 1376, "state" : "IN" }
+{ "_id" : "47012", "city" : "BROOKVILLE", "loc" : [ -84.99942299999999, 39.421305 ], "pop" : 9204, "state" : "IN" }
+{ "_id" : "47016", "city" : "CEDAR GROVE", "loc" : [ -84.892402, 39.345891 ], "pop" : 1522, "state" : "IN" }
+{ "_id" : "47017", "city" : "CROSS PLAINS", "loc" : [ -85.21221, 38.949046 ], "pop" : 802, "state" : "IN" }
+{ "_id" : "47018", "city" : "DILLSBORO", "loc" : [ -85.05499399999999, 38.996195 ], "pop" : 3699, "state" : "IN" }
+{ "_id" : "47020", "city" : "FLORENCE", "loc" : [ -84.93987199999999, 38.822436 ], "pop" : 1019, "state" : "IN" }
+{ "_id" : "47021", "city" : "FRIENDSHIP", "loc" : [ -85.215296, 39.114591 ], "pop" : 218, "state" : "IN" }
+{ "_id" : "47022", "city" : "GUILFORD", "loc" : [ -84.961586, 39.205855 ], "pop" : 2595, "state" : "IN" }
+{ "_id" : "47023", "city" : "HOLTON", "loc" : [ -85.37394500000001, 39.049817 ], "pop" : 2384, "state" : "IN" }
+{ "_id" : "47024", "city" : "LAUREL", "loc" : [ -85.208044, 39.491573 ], "pop" : 3041, "state" : "IN" }
+{ "_id" : "47025", "city" : "LAWRENCEBURG", "loc" : [ -84.865819, 39.140123 ], "pop" : 15358, "state" : "IN" }
+{ "_id" : "47030", "city" : "METAMORA", "loc" : [ -85.15044, 39.428775 ], "pop" : 1085, "state" : "IN" }
+{ "_id" : "47031", "city" : "MILAN", "loc" : [ -85.13242, 39.150333 ], "pop" : 3877, "state" : "IN" }
+{ "_id" : "47032", "city" : "MOORES HILL", "loc" : [ -85.063806, 39.094459 ], "pop" : 2729, "state" : "IN" }
+{ "_id" : "47036", "city" : "OLDENBURG", "loc" : [ -85.22223, 39.359797 ], "pop" : 1398, "state" : "IN" }
+{ "_id" : "47037", "city" : "OSGOOD", "loc" : [ -85.293812, 39.157342 ], "pop" : 4785, "state" : "IN" }
+{ "_id" : "47038", "city" : "PATRIOT", "loc" : [ -84.85154300000001, 38.853691 ], "pop" : 1265, "state" : "IN" }
+{ "_id" : "47040", "city" : "RISING SUN", "loc" : [ -84.88067599999999, 38.956667 ], "pop" : 4500, "state" : "IN" }
+{ "_id" : "47041", "city" : "SUNMAN", "loc" : [ -85.11592899999999, 39.262307 ], "pop" : 4719, "state" : "IN" }
+{ "_id" : "47042", "city" : "VERSAILLES", "loc" : [ -85.223489, 39.051074 ], "pop" : 4753, "state" : "IN" }
+{ "_id" : "47043", "city" : "VEVAY", "loc" : [ -85.085217, 38.772423 ], "pop" : 3974, "state" : "IN" }
+{ "_id" : "47060", "city" : "W HARRISON", "loc" : [ -84.878027, 39.266727 ], "pop" : 5338, "state" : "IN" }
+{ "_id" : "47102", "city" : "AUSTIN", "loc" : [ -85.796188, 38.747801 ], "pop" : 6713, "state" : "IN" }
+{ "_id" : "47106", "city" : "BORDEN", "loc" : [ -85.92147300000001, 38.436171 ], "pop" : 4080, "state" : "IN" }
+{ "_id" : "47108", "city" : "CAMPBELLSBURG", "loc" : [ -86.235846, 38.669037 ], "pop" : 2900, "state" : "IN" }
+{ "_id" : "47110", "city" : "CENTRAL", "loc" : [ -86.19738099999999, 38.094543 ], "pop" : 779, "state" : "IN" }
+{ "_id" : "47111", "city" : "CHARLESTOWN", "loc" : [ -85.660614, 38.456778 ], "pop" : 9896, "state" : "IN" }
+{ "_id" : "47112", "city" : "CORYDON", "loc" : [ -86.114465, 38.218865 ], "pop" : 10928, "state" : "IN" }
+{ "_id" : "47114", "city" : "CRANDALL", "loc" : [ -86.069804, 38.28927 ], "pop" : 239, "state" : "IN" }
+{ "_id" : "47115", "city" : "DEPAUW", "loc" : [ -86.210857, 38.336078 ], "pop" : 3269, "state" : "IN" }
+{ "_id" : "47116", "city" : "ECKERTY", "loc" : [ -86.60593900000001, 38.318548 ], "pop" : 971, "state" : "IN" }
+{ "_id" : "47117", "city" : "ELIZABETH", "loc" : [ -85.95887399999999, 38.124389 ], "pop" : 3273, "state" : "IN" }
+{ "_id" : "47118", "city" : "ENGLISH", "loc" : [ -86.442875, 38.325807 ], "pop" : 3424, "state" : "IN" }
+{ "_id" : "47119", "city" : "FLOYDS KNOBS", "loc" : [ -85.89955500000001, 38.351006 ], "pop" : 9954, "state" : "IN" }
+{ "_id" : "47120", "city" : "FREDERICKSBURG", "loc" : [ -86.17825499999999, 38.482118 ], "pop" : 1846, "state" : "IN" }
+{ "_id" : "47122", "city" : "GEORGETOWN", "loc" : [ -85.961704, 38.302943 ], "pop" : 4446, "state" : "IN" }
+{ "_id" : "47123", "city" : "GRANTSBURG", "loc" : [ -86.466043, 38.289183 ], "pop" : 154, "state" : "IN" }
+{ "_id" : "47124", "city" : "GREENVILLE", "loc" : [ -86.00829899999999, 38.353533 ], "pop" : 1162, "state" : "IN" }
+{ "_id" : "47125", "city" : "HARDINSBURG", "loc" : [ -86.317983, 38.462599 ], "pop" : 2496, "state" : "IN" }
+{ "_id" : "47126", "city" : "HENRYVILLE", "loc" : [ -85.773403, 38.539829 ], "pop" : 2648, "state" : "IN" }
+{ "_id" : "47129", "city" : "CLARKSVILLE", "loc" : [ -85.524438, 38.537273 ], "pop" : 379, "state" : "IN" }
+{ "_id" : "47130", "city" : "JEFFERSONVILLE", "loc" : [ -85.735885, 38.307767 ], "pop" : 56543, "state" : "IN" }
+{ "_id" : "47135", "city" : "LACONIA", "loc" : [ -86.08441500000001, 38.052703 ], "pop" : 1058, "state" : "IN" }
+{ "_id" : "47136", "city" : "LANESVILLE", "loc" : [ -85.95931400000001, 38.244817 ], "pop" : 3524, "state" : "IN" }
+{ "_id" : "47137", "city" : "LEAVENWORTH", "loc" : [ -86.35986200000001, 38.194244 ], "pop" : 1152, "state" : "IN" }
+{ "_id" : "47138", "city" : "LEXINGTON", "loc" : [ -85.65891499999999, 38.650643 ], "pop" : 2803, "state" : "IN" }
+{ "_id" : "47140", "city" : "MARENGO", "loc" : [ -86.357784, 38.373603 ], "pop" : 1539, "state" : "IN" }
+{ "_id" : "47141", "city" : "MARYSVILLE", "loc" : [ -85.630809, 38.554488 ], "pop" : 828, "state" : "IN" }
+{ "_id" : "47142", "city" : "MAUCKPORT", "loc" : [ -86.184622, 38.04366 ], "pop" : 520, "state" : "IN" }
+{ "_id" : "47143", "city" : "MEMPHIS", "loc" : [ -85.777501, 38.464181 ], "pop" : 2381, "state" : "IN" }
+{ "_id" : "47145", "city" : "MILLTOWN", "loc" : [ -86.300344, 38.344453 ], "pop" : 1724, "state" : "IN" }
+{ "_id" : "47147", "city" : "NABB", "loc" : [ -85.521704, 38.612768 ], "pop" : 2246, "state" : "IN" }
+{ "_id" : "47150", "city" : "NEW ALBANY", "loc" : [ -85.822085, 38.308919 ], "pop" : 44969, "state" : "IN" }
+{ "_id" : "47160", "city" : "NEW MIDDLETOWN", "loc" : [ -86.055261, 38.144199 ], "pop" : 1593, "state" : "IN" }
+{ "_id" : "47161", "city" : "NEW SALISBURY", "loc" : [ -86.088731, 38.339885 ], "pop" : 4814, "state" : "IN" }
+{ "_id" : "47162", "city" : "NEW WASHINGTON", "loc" : [ -85.45987, 38.557521 ], "pop" : 380, "state" : "IN" }
+{ "_id" : "47163", "city" : "OTISCO", "loc" : [ -85.66470200000001, 38.542342 ], "pop" : 1738, "state" : "IN" }
+{ "_id" : "47164", "city" : "PALMYRA", "loc" : [ -86.088778, 38.410484 ], "pop" : 814, "state" : "IN" }
+{ "_id" : "47165", "city" : "PEKIN", "loc" : [ -86.017045, 38.49308 ], "pop" : 5351, "state" : "IN" }
+{ "_id" : "47166", "city" : "RAMSEY", "loc" : [ -86.130768, 38.335442 ], "pop" : 1146, "state" : "IN" }
+{ "_id" : "47167", "city" : "SALEM", "loc" : [ -86.07874200000001, 38.607138 ], "pop" : 10949, "state" : "IN" }
+{ "_id" : "47170", "city" : "SCOTTSBURG", "loc" : [ -85.798654, 38.688499 ], "pop" : 13114, "state" : "IN" }
+{ "_id" : "47172", "city" : "SPEED", "loc" : [ -85.763518, 38.390331 ], "pop" : 8658, "state" : "IN" }
+{ "_id" : "47174", "city" : "SULPHUR", "loc" : [ -86.487296, 38.227194 ], "pop" : 303, "state" : "IN" }
+{ "_id" : "47175", "city" : "TASWELL", "loc" : [ -86.538675, 38.346302 ], "pop" : 950, "state" : "IN" }
+{ "_id" : "47177", "city" : "UNDERWOOD", "loc" : [ -85.767211, 38.590251 ], "pop" : 818, "state" : "IN" }
+{ "_id" : "47201", "city" : "COLUMBUS", "loc" : [ -85.93174500000001, 39.205507 ], "pop" : 40769, "state" : "IN" }
+{ "_id" : "47203", "city" : "COLUMBUS", "loc" : [ -85.885497, 39.230097 ], "pop" : 15656, "state" : "IN" }
+{ "_id" : "47220", "city" : "BROWNSTOWN", "loc" : [ -86.048619, 38.883593 ], "pop" : 4963, "state" : "IN" }
+{ "_id" : "47223", "city" : "BUTLERVILLE", "loc" : [ -85.494415, 39.120598 ], "pop" : 813, "state" : "IN" }
+{ "_id" : "47224", "city" : "CANAAN", "loc" : [ -85.268896, 38.869644 ], "pop" : 936, "state" : "IN" }
+{ "_id" : "47227", "city" : "COMMISKEY", "loc" : [ -85.643384, 38.852629 ], "pop" : 896, "state" : "IN" }
+{ "_id" : "47228", "city" : "CORTLAND", "loc" : [ -86.000918, 38.991546 ], "pop" : 1680, "state" : "IN" }
+{ "_id" : "47229", "city" : "CROTHERSVILLE", "loc" : [ -85.846965, 38.806672 ], "pop" : 3865, "state" : "IN" }
+{ "_id" : "47230", "city" : "DEPUTY", "loc" : [ -85.63040700000001, 38.775891 ], "pop" : 1448, "state" : "IN" }
+{ "_id" : "47231", "city" : "DUPONT", "loc" : [ -85.50920499999999, 38.890504 ], "pop" : 716, "state" : "IN" }
+{ "_id" : "47232", "city" : "ELIZABETHTOWN", "loc" : [ -85.81531099999999, 39.124291 ], "pop" : 1222, "state" : "IN" }
+{ "_id" : "47234", "city" : "FLAT ROCK", "loc" : [ -85.67588600000001, 39.407503 ], "pop" : 1496, "state" : "IN" }
+{ "_id" : "47235", "city" : "FREETOWN", "loc" : [ -86.12405099999999, 38.995728 ], "pop" : 1380, "state" : "IN" }
+{ "_id" : "47236", "city" : "GRAMMER", "loc" : [ -85.718338, 39.159192 ], "pop" : 412, "state" : "IN" }
+{ "_id" : "47240", "city" : "ADAMS", "loc" : [ -85.47353200000001, 39.331223 ], "pop" : 19250, "state" : "IN" }
+{ "_id" : "47243", "city" : "HANOVER", "loc" : [ -85.476316, 38.71378 ], "pop" : 4900, "state" : "IN" }
+{ "_id" : "47244", "city" : "HARTSVILLE", "loc" : [ -85.70046000000001, 39.273318 ], "pop" : 543, "state" : "IN" }
+{ "_id" : "47246", "city" : "HOPE", "loc" : [ -85.766538, 39.25733 ], "pop" : 5676, "state" : "IN" }
+{ "_id" : "47250", "city" : "MADISON", "loc" : [ -85.40701900000001, 38.764866 ], "pop" : 20596, "state" : "IN" }
+{ "_id" : "47260", "city" : "MEDORA", "loc" : [ -86.189733, 38.825505 ], "pop" : 1576, "state" : "IN" }
+{ "_id" : "47264", "city" : "NORMAN", "loc" : [ -86.20793399999999, 38.929996 ], "pop" : 1834, "state" : "IN" }
+{ "_id" : "47265", "city" : "NORTH VERNON", "loc" : [ -85.627216, 39.001763 ], "pop" : 13466, "state" : "IN" }
+{ "_id" : "47270", "city" : "PARIS CROSSING", "loc" : [ -85.74872499999999, 38.855843 ], "pop" : 972, "state" : "IN" }
+{ "_id" : "47272", "city" : "SAINT PAUL", "loc" : [ -85.599374, 39.427747 ], "pop" : 1389, "state" : "IN" }
+{ "_id" : "47273", "city" : "SCIPIO", "loc" : [ -85.71285899999999, 39.066544 ], "pop" : 5043, "state" : "IN" }
+{ "_id" : "47274", "city" : "SEYMOUR", "loc" : [ -85.88247699999999, 38.957133 ], "pop" : 21094, "state" : "IN" }
+{ "_id" : "47281", "city" : "VALLONIA", "loc" : [ -86.068997, 38.817413 ], "pop" : 1338, "state" : "IN" }
+{ "_id" : "47282", "city" : "VERNON", "loc" : [ -85.598377, 38.96887 ], "pop" : 2277, "state" : "IN" }
+{ "_id" : "47283", "city" : "WESTPORT", "loc" : [ -85.585596, 39.174856 ], "pop" : 3065, "state" : "IN" }
+{ "_id" : "47302", "city" : "MUNCIE", "loc" : [ -85.380689, 40.168414 ], "pop" : 29709, "state" : "IN" }
+{ "_id" : "47303", "city" : "MUNCIE", "loc" : [ -85.37896600000001, 40.217992 ], "pop" : 26033, "state" : "IN" }
+{ "_id" : "47304", "city" : "MUNCIE", "loc" : [ -85.429115, 40.211134 ], "pop" : 28452, "state" : "IN" }
+{ "_id" : "47305", "city" : "MUNCIE", "loc" : [ -85.386163, 40.193299 ], "pop" : 5251, "state" : "IN" }
+{ "_id" : "47306", "city" : "BALL STATE UNIVE", "loc" : [ -85.41015299999999, 40.192739 ], "pop" : 3259, "state" : "IN" }
+{ "_id" : "47320", "city" : "ALBANY", "loc" : [ -85.257987, 40.292049 ], "pop" : 4625, "state" : "IN" }
+{ "_id" : "47325", "city" : "BROWNSVILLE", "loc" : [ -84.98806999999999, 39.684485 ], "pop" : 850, "state" : "IN" }
+{ "_id" : "47326", "city" : "BRYANT", "loc" : [ -84.911748, 40.54462 ], "pop" : 1350, "state" : "IN" }
+{ "_id" : "47327", "city" : "CAMBRIDGE CITY", "loc" : [ -85.16845499999999, 39.818171 ], "pop" : 4998, "state" : "IN" }
+{ "_id" : "47330", "city" : "CENTERVILLE", "loc" : [ -85.00317, 39.808103 ], "pop" : 5475, "state" : "IN" }
+{ "_id" : "47331", "city" : "CONNERSVILLE", "loc" : [ -85.14643100000001, 39.643508 ], "pop" : 25503, "state" : "IN" }
+{ "_id" : "47334", "city" : "DALEVILLE", "loc" : [ -85.511016, 40.125738 ], "pop" : 5063, "state" : "IN" }
+{ "_id" : "47336", "city" : "DUNKIRK", "loc" : [ -85.22554100000001, 40.388291 ], "pop" : 4413, "state" : "IN" }
+{ "_id" : "47338", "city" : "EATON", "loc" : [ -85.354387, 40.337673 ], "pop" : 3637, "state" : "IN" }
+{ "_id" : "47339", "city" : "ECONOMY", "loc" : [ -85.08780299999999, 39.971215 ], "pop" : 677, "state" : "IN" }
+{ "_id" : "47340", "city" : "FARMLAND", "loc" : [ -85.125381, 40.194454 ], "pop" : 1784, "state" : "IN" }
+{ "_id" : "47341", "city" : "FOUNTAIN CITY", "loc" : [ -84.908996, 39.963429 ], "pop" : 2020, "state" : "IN" }
+{ "_id" : "47342", "city" : "GASTON", "loc" : [ -85.489842, 40.29479 ], "pop" : 4594, "state" : "IN" }
+{ "_id" : "47345", "city" : "GREENS FORK", "loc" : [ -85.049413, 39.89163 ], "pop" : 1054, "state" : "IN" }
+{ "_id" : "47346", "city" : "HAGERSTOWN", "loc" : [ -85.16009099999999, 39.92277 ], "pop" : 3906, "state" : "IN" }
+{ "_id" : "47348", "city" : "HARTFORD CITY", "loc" : [ -85.375771, 40.454106 ], "pop" : 9762, "state" : "IN" }
+{ "_id" : "47352", "city" : "LEWISVILLE", "loc" : [ -85.36211, 39.828288 ], "pop" : 1219, "state" : "IN" }
+{ "_id" : "47353", "city" : "LIBERTY", "loc" : [ -84.908947, 39.612645 ], "pop" : 6126, "state" : "IN" }
+{ "_id" : "47354", "city" : "LOSANTVILLE", "loc" : [ -85.21084999999999, 40.047492 ], "pop" : 1768, "state" : "IN" }
+{ "_id" : "47355", "city" : "LYNN", "loc" : [ -84.93003, 40.051863 ], "pop" : 3544, "state" : "IN" }
+{ "_id" : "47356", "city" : "MIDDLETOWN", "loc" : [ -85.536778, 40.047488 ], "pop" : 4613, "state" : "IN" }
+{ "_id" : "47357", "city" : "MILTON", "loc" : [ -85.142267, 39.776279 ], "pop" : 1488, "state" : "IN" }
+{ "_id" : "47358", "city" : "MODOC", "loc" : [ -85.091904, 40.05816 ], "pop" : 1253, "state" : "IN" }
+{ "_id" : "47359", "city" : "MONTPELIER", "loc" : [ -85.251339, 40.557656 ], "pop" : 3753, "state" : "IN" }
+{ "_id" : "47360", "city" : "MOORELAND", "loc" : [ -85.258065, 39.994066 ], "pop" : 1265, "state" : "IN" }
+{ "_id" : "47362", "city" : "NEW CASTLE", "loc" : [ -85.366322, 39.920765 ], "pop" : 25888, "state" : "IN" }
+{ "_id" : "47368", "city" : "PARKER CITY", "loc" : [ -85.196265, 40.193841 ], "pop" : 1818, "state" : "IN" }
+{ "_id" : "47369", "city" : "PENNVILLE", "loc" : [ -85.14916599999999, 40.508195 ], "pop" : 1236, "state" : "IN" }
+{ "_id" : "47371", "city" : "PORTLAND", "loc" : [ -84.992825, 40.430564 ], "pop" : 13186, "state" : "IN" }
+{ "_id" : "47373", "city" : "REDKEY", "loc" : [ -85.16196600000001, 40.326491 ], "pop" : 2971, "state" : "IN" }
+{ "_id" : "47374", "city" : "RICHMOND", "loc" : [ -84.89360600000001, 39.83244 ], "pop" : 50516, "state" : "IN" }
+{ "_id" : "47380", "city" : "RIDGEVILLE", "loc" : [ -85.03710100000001, 40.280359 ], "pop" : 1343, "state" : "IN" }
+{ "_id" : "47381", "city" : "SALAMONIA", "loc" : [ -84.855098, 40.358234 ], "pop" : 741, "state" : "IN" }
+{ "_id" : "47382", "city" : "SARATOGA", "loc" : [ -84.950846, 40.257365 ], "pop" : 1244, "state" : "IN" }
+{ "_id" : "47383", "city" : "SELMA", "loc" : [ -85.273765, 40.169295 ], "pop" : 4009, "state" : "IN" }
+{ "_id" : "47384", "city" : "SHIRLEY", "loc" : [ -85.518151, 39.91582 ], "pop" : 2292, "state" : "IN" }
+{ "_id" : "47385", "city" : "SPICELAND", "loc" : [ -85.445043, 39.827078 ], "pop" : 2270, "state" : "IN" }
+{ "_id" : "47386", "city" : "SPRINGPORT", "loc" : [ -85.36886699999999, 40.008848 ], "pop" : 3393, "state" : "IN" }
+{ "_id" : "47387", "city" : "STRAUGHN", "loc" : [ -85.272406, 39.831946 ], "pop" : 1300, "state" : "IN" }
+{ "_id" : "47388", "city" : "SULPHUR SPRINGS", "loc" : [ -85.440747, 40.011121 ], "pop" : 1242, "state" : "IN" }
+{ "_id" : "47390", "city" : "UNION CITY", "loc" : [ -84.826787, 40.202372 ], "pop" : 5393, "state" : "IN" }
+{ "_id" : "47392", "city" : "WEBSTER", "loc" : [ -84.942908, 39.905701 ], "pop" : 540, "state" : "IN" }
+{ "_id" : "47393", "city" : "WILLIAMSBURG", "loc" : [ -84.998442, 39.958005 ], "pop" : 1272, "state" : "IN" }
+{ "_id" : "47394", "city" : "WINCHESTER", "loc" : [ -85.004366, 40.16959 ], "pop" : 8830, "state" : "IN" }
+{ "_id" : "47396", "city" : "YORKTOWN", "loc" : [ -85.49599499999999, 40.183581 ], "pop" : 5027, "state" : "IN" }
+{ "_id" : "47401", "city" : "BLOOMINGTON", "loc" : [ -86.508262, 39.140057 ], "pop" : 31456, "state" : "IN" }
+{ "_id" : "47403", "city" : "BLOOMINGTON", "loc" : [ -86.57686699999999, 39.12632 ], "pop" : 23435, "state" : "IN" }
+{ "_id" : "47404", "city" : "BLOOMINGTON", "loc" : [ -86.57572, 39.195026 ], "pop" : 15079, "state" : "IN" }
+{ "_id" : "47408", "city" : "WOODBRIDGE", "loc" : [ -86.505836, 39.183175 ], "pop" : 30907, "state" : "IN" }
+{ "_id" : "47421", "city" : "BEDFORD", "loc" : [ -86.487072, 38.872881 ], "pop" : 27071, "state" : "IN" }
+{ "_id" : "47424", "city" : "BLOOMFIELD", "loc" : [ -86.867549, 39.029542 ], "pop" : 9014, "state" : "IN" }
+{ "_id" : "47427", "city" : "COAL CITY", "loc" : [ -86.988297, 39.257304 ], "pop" : 1647, "state" : "IN" }
+{ "_id" : "47429", "city" : "ELLETTSVILLE", "loc" : [ -86.619635, 39.254477 ], "pop" : 4960, "state" : "IN" }
+{ "_id" : "47431", "city" : "FREEDOM", "loc" : [ -86.850027, 39.215147 ], "pop" : 1003, "state" : "IN" }
+{ "_id" : "47432", "city" : "FRENCH LICK", "loc" : [ -86.61955500000001, 38.532351 ], "pop" : 3920, "state" : "IN" }
+{ "_id" : "47433", "city" : "GOSPORT", "loc" : [ -86.6583, 39.344969 ], "pop" : 2269, "state" : "IN" }
+{ "_id" : "47436", "city" : "HELTONVILLE", "loc" : [ -86.370328, 38.948014 ], "pop" : 1402, "state" : "IN" }
+{ "_id" : "47438", "city" : "JASONVILLE", "loc" : [ -87.202292, 39.172333 ], "pop" : 4340, "state" : "IN" }
+{ "_id" : "47441", "city" : "LINTON", "loc" : [ -87.172286, 39.046139 ], "pop" : 9233, "state" : "IN" }
+{ "_id" : "47443", "city" : "LYONS", "loc" : [ -87.101595, 38.971731 ], "pop" : 1706, "state" : "IN" }
+{ "_id" : "47446", "city" : "MITCHELL", "loc" : [ -86.476096, 38.742625 ], "pop" : 9516, "state" : "IN" }
+{ "_id" : "47448", "city" : "NASHVILLE", "loc" : [ -86.22199000000001, 39.236712 ], "pop" : 11751, "state" : "IN" }
+{ "_id" : "47449", "city" : "NEWBERRY", "loc" : [ -87.008055, 38.922905 ], "pop" : 386, "state" : "IN" }
+{ "_id" : "47451", "city" : "OOLITIC", "loc" : [ -86.52461700000001, 38.89378 ], "pop" : 1493, "state" : "IN" }
+{ "_id" : "47452", "city" : "ORLEANS", "loc" : [ -86.453157, 38.653464 ], "pop" : 4309, "state" : "IN" }
+{ "_id" : "47453", "city" : "OWENSBURG", "loc" : [ -86.744122, 38.952216 ], "pop" : 1497, "state" : "IN" }
+{ "_id" : "47454", "city" : "PAOLI", "loc" : [ -86.44902, 38.550697 ], "pop" : 6790, "state" : "IN" }
+{ "_id" : "47456", "city" : "QUINCY", "loc" : [ -86.80250599999999, 39.439521 ], "pop" : 2959, "state" : "IN" }
+{ "_id" : "47459", "city" : "SOLSBERRY", "loc" : [ -86.737843, 39.119047 ], "pop" : 1832, "state" : "IN" }
+{ "_id" : "47460", "city" : "SPENCER", "loc" : [ -86.77894000000001, 39.289067 ], "pop" : 10170, "state" : "IN" }
+{ "_id" : "47462", "city" : "SPRINGVILLE", "loc" : [ -86.613879, 38.950655 ], "pop" : 1726, "state" : "IN" }
+{ "_id" : "47465", "city" : "SWITZ CITY", "loc" : [ -87.05023799999999, 39.036937 ], "pop" : 1347, "state" : "IN" }
+{ "_id" : "47468", "city" : "UNIONVILLE", "loc" : [ -86.418947, 39.251396 ], "pop" : 1111, "state" : "IN" }
+{ "_id" : "47469", "city" : "WEST BADEN SPRIN", "loc" : [ -86.613826, 38.585501 ], "pop" : 1757, "state" : "IN" }
+{ "_id" : "47470", "city" : "WILLIAMS", "loc" : [ -86.628488, 38.773478 ], "pop" : 1960, "state" : "IN" }
+{ "_id" : "47471", "city" : "WORTHINGTON", "loc" : [ -86.99905800000001, 39.12298 ], "pop" : 2365, "state" : "IN" }
+{ "_id" : "47501", "city" : "WASHINGTON", "loc" : [ -87.17065599999999, 38.653568 ], "pop" : 15495, "state" : "IN" }
+{ "_id" : "47512", "city" : "BICKNELL", "loc" : [ -87.31371799999999, 38.77272 ], "pop" : 4470, "state" : "IN" }
+{ "_id" : "47513", "city" : "BIRDSEYE", "loc" : [ -86.710193, 38.30058 ], "pop" : 1591, "state" : "IN" }
+{ "_id" : "47514", "city" : "BRANCHVILLE", "loc" : [ -86.585866, 38.157189 ], "pop" : 1314, "state" : "IN" }
+{ "_id" : "47515", "city" : "SIBERIA", "loc" : [ -86.72181500000001, 38.163101 ], "pop" : 912, "state" : "IN" }
+{ "_id" : "47516", "city" : "BRUCEVILLE", "loc" : [ -87.431299, 38.756279 ], "pop" : 1167, "state" : "IN" }
+{ "_id" : "47519", "city" : "CANNELBURG", "loc" : [ -86.96686800000001, 38.694696 ], "pop" : 1265, "state" : "IN" }
+{ "_id" : "47520", "city" : "MOUNT PLEASANT", "loc" : [ -86.732617, 37.910851 ], "pop" : 2290, "state" : "IN" }
+{ "_id" : "47521", "city" : "CELESTINE", "loc" : [ -86.756809, 38.387789 ], "pop" : 858, "state" : "IN" }
+{ "_id" : "47522", "city" : "CRANE NAVAL DEPO", "loc" : [ -86.86547299999999, 38.849618 ], "pop" : 371, "state" : "IN" }
+{ "_id" : "47523", "city" : "DALE", "loc" : [ -87.00698199999999, 38.170638 ], "pop" : 3459, "state" : "IN" }
+{ "_id" : "47524", "city" : "DECKER", "loc" : [ -87.553713, 38.507629 ], "pop" : 621, "state" : "IN" }
+{ "_id" : "47525", "city" : "DERBY", "loc" : [ -86.57695099999999, 38.023933 ], "pop" : 485, "state" : "IN" }
+{ "_id" : "47527", "city" : "DUBOIS", "loc" : [ -86.78319, 38.472824 ], "pop" : 2200, "state" : "IN" }
+{ "_id" : "47528", "city" : "EDWARDSPORT", "loc" : [ -87.251856, 38.810584 ], "pop" : 497, "state" : "IN" }
+{ "_id" : "47529", "city" : "ELNORA", "loc" : [ -87.065243, 38.822284 ], "pop" : 2373, "state" : "IN" }
+{ "_id" : "47531", "city" : "EVANSTON", "loc" : [ -86.836422, 38.022436 ], "pop" : 163, "state" : "IN" }
+{ "_id" : "47532", "city" : "FERDINAND", "loc" : [ -86.860669, 38.233582 ], "pop" : 3725, "state" : "IN" }
+{ "_id" : "47537", "city" : "GENTRYVILLE", "loc" : [ -87.04413700000001, 38.085458 ], "pop" : 824, "state" : "IN" }
+{ "_id" : "47541", "city" : "HOLLAND", "loc" : [ -87.008768, 38.23851 ], "pop" : 2072, "state" : "IN" }
+{ "_id" : "47542", "city" : "HUNTINGBURG", "loc" : [ -86.953299, 38.297902 ], "pop" : 7415, "state" : "IN" }
+{ "_id" : "47546", "city" : "HAYSVILLE", "loc" : [ -86.940787, 38.404392 ], "pop" : 16927, "state" : "IN" }
+{ "_id" : "47550", "city" : "BUFFALOVILLE", "loc" : [ -86.962908, 38.047904 ], "pop" : 202, "state" : "IN" }
+{ "_id" : "47551", "city" : "LEOPOLD", "loc" : [ -86.60442999999999, 38.101138 ], "pop" : 623, "state" : "IN" }
+{ "_id" : "47552", "city" : "LINCOLN CITY", "loc" : [ -86.98720400000001, 38.127565 ], "pop" : 233, "state" : "IN" }
+{ "_id" : "47553", "city" : "LOOGOOTEE", "loc" : [ -86.913658, 38.662901 ], "pop" : 6068, "state" : "IN" }
+{ "_id" : "47555", "city" : "MAGNET", "loc" : [ -86.48353, 38.088165 ], "pop" : 240, "state" : "IN" }
+{ "_id" : "47556", "city" : "MARIAH HILL", "loc" : [ -86.831593, 38.149493 ], "pop" : 1317, "state" : "IN" }
+{ "_id" : "47557", "city" : "MONROE CITY", "loc" : [ -87.364136, 38.60015 ], "pop" : 1915, "state" : "IN" }
+{ "_id" : "47558", "city" : "MONTGOMERY", "loc" : [ -87.047603, 38.652146 ], "pop" : 2675, "state" : "IN" }
+{ "_id" : "47561", "city" : "OAKTOWN", "loc" : [ -87.387877, 38.857939 ], "pop" : 2569, "state" : "IN" }
+{ "_id" : "47562", "city" : "ODON", "loc" : [ -86.97521399999999, 38.818666 ], "pop" : 4198, "state" : "IN" }
+{ "_id" : "47564", "city" : "OTWELL", "loc" : [ -87.09854799999999, 38.466221 ], "pop" : 912, "state" : "IN" }
+{ "_id" : "47567", "city" : "PETERSBURG", "loc" : [ -87.28829399999999, 38.478929 ], "pop" : 6614, "state" : "IN" }
+{ "_id" : "47568", "city" : "PLAINVILLE", "loc" : [ -87.157822, 38.791507 ], "pop" : 895, "state" : "IN" }
+{ "_id" : "47574", "city" : "ROME", "loc" : [ -86.595787, 37.937561 ], "pop" : 297, "state" : "IN" }
+{ "_id" : "47575", "city" : "KYANA", "loc" : [ -86.82485800000001, 38.332222 ], "pop" : 2012, "state" : "IN" }
+{ "_id" : "47576", "city" : "SAINT CROIX", "loc" : [ -86.603511, 38.239773 ], "pop" : 325, "state" : "IN" }
+{ "_id" : "47577", "city" : "SAINT MEINRAD", "loc" : [ -86.842916, 38.181946 ], "pop" : 652, "state" : "IN" }
+{ "_id" : "47578", "city" : "SANDBORN", "loc" : [ -87.20253200000001, 38.881743 ], "pop" : 919, "state" : "IN" }
+{ "_id" : "47579", "city" : "SANTA CLAUS", "loc" : [ -86.90352799999999, 38.094496 ], "pop" : 2323, "state" : "IN" }
+{ "_id" : "47580", "city" : "SCHNELLVILLE", "loc" : [ -86.756506, 38.341436 ], "pop" : 199, "state" : "IN" }
+{ "_id" : "47581", "city" : "SHOALS", "loc" : [ -86.776094, 38.679103 ], "pop" : 4562, "state" : "IN" }
+{ "_id" : "47585", "city" : "STENDAL", "loc" : [ -87.12045000000001, 38.283472 ], "pop" : 596, "state" : "IN" }
+{ "_id" : "47586", "city" : "TELL CITY", "loc" : [ -86.745704, 37.965505 ], "pop" : 11583, "state" : "IN" }
+{ "_id" : "47587", "city" : "TOBINSPORT", "loc" : [ -86.634128, 37.874726 ], "pop" : 151, "state" : "IN" }
+{ "_id" : "47588", "city" : "TROY", "loc" : [ -86.797766, 37.997994 ], "pop" : 727, "state" : "IN" }
+{ "_id" : "47590", "city" : "VELPEN", "loc" : [ -87.098996, 38.367981 ], "pop" : 393, "state" : "IN" }
+{ "_id" : "47591", "city" : "VINCENNES", "loc" : [ -87.509806, 38.67344 ], "pop" : 26841, "state" : "IN" }
+{ "_id" : "47597", "city" : "WHEATLAND", "loc" : [ -87.30620399999999, 38.667055 ], "pop" : 885, "state" : "IN" }
+{ "_id" : "47598", "city" : "WINSLOW", "loc" : [ -87.222328, 38.363951 ], "pop" : 3994, "state" : "IN" }
+{ "_id" : "47601", "city" : "BOONVILLE", "loc" : [ -87.261994, 38.047435 ], "pop" : 11964, "state" : "IN" }
+{ "_id" : "47610", "city" : "CHANDLER", "loc" : [ -87.375552, 38.042304 ], "pop" : 5641, "state" : "IN" }
+{ "_id" : "47611", "city" : "CHRISNEY", "loc" : [ -87.070421, 38.005995 ], "pop" : 1455, "state" : "IN" }
+{ "_id" : "47612", "city" : "CYNTHIANA", "loc" : [ -87.711518, 38.174299 ], "pop" : 1277, "state" : "IN" }
+{ "_id" : "47613", "city" : "ELBERFELD", "loc" : [ -87.41794299999999, 38.205267 ], "pop" : 3361, "state" : "IN" }
+{ "_id" : "47615", "city" : "GRANDVIEW", "loc" : [ -86.956774, 37.970297 ], "pop" : 1990, "state" : "IN" }
+{ "_id" : "47616", "city" : "GRIFFIN", "loc" : [ -87.916631, 38.206858 ], "pop" : 329, "state" : "IN" }
+{ "_id" : "47619", "city" : "LYNNVILLE", "loc" : [ -87.293486, 38.196085 ], "pop" : 1329, "state" : "IN" }
+{ "_id" : "47620", "city" : "MOUNT VERNON", "loc" : [ -87.856887, 37.950569 ], "pop" : 16037, "state" : "IN" }
+{ "_id" : "47630", "city" : "NEWBURGH", "loc" : [ -87.393798, 37.963746 ], "pop" : 21793, "state" : "IN" }
+{ "_id" : "47631", "city" : "NEW HARMONY", "loc" : [ -87.917186, 38.124502 ], "pop" : 1432, "state" : "IN" }
+{ "_id" : "47633", "city" : "POSEYVILLE", "loc" : [ -87.802747, 38.171986 ], "pop" : 2009, "state" : "IN" }
+{ "_id" : "47634", "city" : "RICHLAND", "loc" : [ -87.200957, 37.913599 ], "pop" : 2862, "state" : "IN" }
+{ "_id" : "47635", "city" : "ROCKPORT", "loc" : [ -87.07701, 37.885803 ], "pop" : 4850, "state" : "IN" }
+{ "_id" : "47637", "city" : "TENNYSON", "loc" : [ -87.13875, 38.123207 ], "pop" : 1378, "state" : "IN" }
+{ "_id" : "47638", "city" : "WADESVILLE", "loc" : [ -87.754295, 38.082791 ], "pop" : 3614, "state" : "IN" }
+{ "_id" : "47639", "city" : "HAUBSTADT", "loc" : [ -87.57982699999999, 38.189536 ], "pop" : 3568, "state" : "IN" }
+{ "_id" : "47640", "city" : "HAZLETON", "loc" : [ -87.49834799999999, 38.462283 ], "pop" : 1214, "state" : "IN" }
+{ "_id" : "47647", "city" : "BUCKSKIN", "loc" : [ -87.43077, 38.220867 ], "pop" : 236, "state" : "IN" }
+{ "_id" : "47648", "city" : "FORT BRANCH", "loc" : [ -87.56823300000001, 38.247136 ], "pop" : 4031, "state" : "IN" }
+{ "_id" : "47649", "city" : "FRANCISCO", "loc" : [ -87.453621, 38.332953 ], "pop" : 1503, "state" : "IN" }
+{ "_id" : "47660", "city" : "OAKLAND CITY", "loc" : [ -87.351907, 38.336053 ], "pop" : 4244, "state" : "IN" }
+{ "_id" : "47665", "city" : "OWENSVILLE", "loc" : [ -87.709052, 38.274414 ], "pop" : 3159, "state" : "IN" }
+{ "_id" : "47666", "city" : "PATOKA", "loc" : [ -87.595789, 38.414296 ], "pop" : 1434, "state" : "IN" }
+{ "_id" : "47670", "city" : "PRINCETON", "loc" : [ -87.569069, 38.352502 ], "pop" : 11579, "state" : "IN" }
+{ "_id" : "47708", "city" : "EVANSVILLE", "loc" : [ -87.571973, 37.971818 ], "pop" : 857, "state" : "IN" }
+{ "_id" : "47710", "city" : "EVANSVILLE", "loc" : [ -87.574569, 38.008617 ], "pop" : 22336, "state" : "IN" }
+{ "_id" : "47711", "city" : "EVANSVILLE", "loc" : [ -87.535236, 38.076377 ], "pop" : 9387, "state" : "IN" }
+{ "_id" : "47712", "city" : "EVANSVILLE", "loc" : [ -87.634682, 37.998484 ], "pop" : 35603, "state" : "IN" }
+{ "_id" : "47713", "city" : "EVANSVILLE", "loc" : [ -87.55768, 37.962326 ], "pop" : 14121, "state" : "IN" }
+{ "_id" : "47714", "city" : "EVANSVILLE", "loc" : [ -87.529302, 37.959076 ], "pop" : 27381, "state" : "IN" }
+{ "_id" : "47715", "city" : "EVANSVILLE", "loc" : [ -87.48552599999999, 37.967815 ], "pop" : 30611, "state" : "IN" }
+{ "_id" : "47720", "city" : "EVANSVILLE", "loc" : [ -87.538793, 37.998832 ], "pop" : 25504, "state" : "IN" }
+{ "_id" : "47802", "city" : "TERRE HAUTE", "loc" : [ -87.402019, 39.40697 ], "pop" : 29656, "state" : "IN" }
+{ "_id" : "47803", "city" : "TERRE HAUTE", "loc" : [ -87.353967, 39.465696 ], "pop" : 17709, "state" : "IN" }
+{ "_id" : "47804", "city" : "TERRE HAUTE", "loc" : [ -87.39449399999999, 39.493665 ], "pop" : 11573, "state" : "IN" }
+{ "_id" : "47805", "city" : "NORTH TERRE HAUT", "loc" : [ -87.341109, 39.535981 ], "pop" : 13652, "state" : "IN" }
+{ "_id" : "47807", "city" : "TERRE HAUTE", "loc" : [ -87.400859, 39.470974 ], "pop" : 19106, "state" : "IN" }
+{ "_id" : "47832", "city" : "BLOOMINGDALE", "loc" : [ -87.255967, 39.834808 ], "pop" : 770, "state" : "IN" }
+{ "_id" : "47833", "city" : "BOWLING GREEN", "loc" : [ -87.00524900000001, 39.381209 ], "pop" : 734, "state" : "IN" }
+{ "_id" : "47834", "city" : "BRAZIL", "loc" : [ -87.12776700000001, 39.521041 ], "pop" : 18960, "state" : "IN" }
+{ "_id" : "47836", "city" : "BRIDGETON", "loc" : [ -87.18139600000001, 39.648366 ], "pop" : 818, "state" : "IN" }
+{ "_id" : "47837", "city" : "CARBON", "loc" : [ -87.064455, 39.57463 ], "pop" : 790, "state" : "IN" }
+{ "_id" : "47838", "city" : "CARLISLE", "loc" : [ -87.366738, 38.976297 ], "pop" : 2324, "state" : "IN" }
+{ "_id" : "47840", "city" : "CENTERPOINT", "loc" : [ -87.09347, 39.390989 ], "pop" : 955, "state" : "IN" }
+{ "_id" : "47841", "city" : "CLAY CITY", "loc" : [ -87.108244, 39.2727 ], "pop" : 2275, "state" : "IN" }
+{ "_id" : "47842", "city" : "CLINTON", "loc" : [ -87.4208, 39.659142 ], "pop" : 9250, "state" : "IN" }
+{ "_id" : "47846", "city" : "CORY", "loc" : [ -87.195644, 39.343545 ], "pop" : 259, "state" : "IN" }
+{ "_id" : "47847", "city" : "DANA", "loc" : [ -87.501018, 39.752829 ], "pop" : 1833, "state" : "IN" }
+{ "_id" : "47848", "city" : "DUGGER", "loc" : [ -87.259867, 39.069057 ], "pop" : 1144, "state" : "IN" }
+{ "_id" : "47849", "city" : "FAIRBANKS", "loc" : [ -87.518483, 39.212865 ], "pop" : 655, "state" : "IN" }
+{ "_id" : "47850", "city" : "FARMERSBURG", "loc" : [ -87.502365, 39.268456 ], "pop" : 335, "state" : "IN" }
+{ "_id" : "47854", "city" : "HILLSDALE", "loc" : [ -87.40410199999999, 39.771235 ], "pop" : 858, "state" : "IN" }
+{ "_id" : "47858", "city" : "LEWIS", "loc" : [ -87.26368100000001, 39.273261 ], "pop" : 308, "state" : "IN" }
+{ "_id" : "47859", "city" : "MARSHALL", "loc" : [ -87.178032, 39.906216 ], "pop" : 617, "state" : "IN" }
+{ "_id" : "47861", "city" : "MEROM", "loc" : [ -87.539675, 39.032307 ], "pop" : 649, "state" : "IN" }
+{ "_id" : "47862", "city" : "MONTEZUMA", "loc" : [ -87.360679, 39.796061 ], "pop" : 1444, "state" : "IN" }
+{ "_id" : "47866", "city" : "PIMENTO", "loc" : [ -87.379186, 39.289792 ], "pop" : 1123, "state" : "IN" }
+{ "_id" : "47868", "city" : "POLAND", "loc" : [ -86.963103, 39.446195 ], "pop" : 292, "state" : "IN" }
+{ "_id" : "47872", "city" : "ROCKVILLE", "loc" : [ -87.197794, 39.768152 ], "pop" : 7895, "state" : "IN" }
+{ "_id" : "47874", "city" : "ROSEDALE", "loc" : [ -87.308592, 39.62391 ], "pop" : 3463, "state" : "IN" }
+{ "_id" : "47879", "city" : "SHELBURN", "loc" : [ -87.361194, 39.209924 ], "pop" : 5300, "state" : "IN" }
+{ "_id" : "47882", "city" : "SULLIVAN", "loc" : [ -87.410235, 39.101018 ], "pop" : 8921, "state" : "IN" }
+{ "_id" : "47885", "city" : "SANDFORD", "loc" : [ -87.46708599999999, 39.49384 ], "pop" : 11459, "state" : "IN" }
+{ "_id" : "47901", "city" : "LAFAYETTE", "loc" : [ -86.888358, 40.417743 ], "pop" : 2971, "state" : "IN" }
+{ "_id" : "47904", "city" : "LAFAYETTE", "loc" : [ -86.873464, 40.427649 ], "pop" : 15231, "state" : "IN" }
+{ "_id" : "47905", "city" : "LAFAYETTE", "loc" : [ -86.860236, 40.400054 ], "pop" : 53104, "state" : "IN" }
+{ "_id" : "47906", "city" : "WEST LAFAYETTE", "loc" : [ -86.923661, 40.444025 ], "pop" : 54702, "state" : "IN" }
+{ "_id" : "47917", "city" : "AMBIA", "loc" : [ -87.47955399999999, 40.479328 ], "pop" : 794, "state" : "IN" }
+{ "_id" : "47918", "city" : "ATTICA", "loc" : [ -87.224108, 40.281127 ], "pop" : 5523, "state" : "IN" }
+{ "_id" : "47920", "city" : "BATTLE GROUND", "loc" : [ -86.823784, 40.5248 ], "pop" : 1646, "state" : "IN" }
+{ "_id" : "47921", "city" : "BOSWELL", "loc" : [ -87.378947, 40.518021 ], "pop" : 1118, "state" : "IN" }
+{ "_id" : "47922", "city" : "BROOK", "loc" : [ -87.35268499999999, 40.865534 ], "pop" : 1341, "state" : "IN" }
+{ "_id" : "47923", "city" : "BROOKSTON", "loc" : [ -86.875311, 40.601088 ], "pop" : 3200, "state" : "IN" }
+{ "_id" : "47926", "city" : "BURNETTSVILLE", "loc" : [ -86.574744, 40.707753 ], "pop" : 2102, "state" : "IN" }
+{ "_id" : "47928", "city" : "CAYUGA", "loc" : [ -87.459019, 39.930028 ], "pop" : 3160, "state" : "IN" }
+{ "_id" : "47929", "city" : "CHALMERS", "loc" : [ -86.862621, 40.669265 ], "pop" : 809, "state" : "IN" }
+{ "_id" : "47930", "city" : "CLARKS HILL", "loc" : [ -86.760766, 40.262805 ], "pop" : 2119, "state" : "IN" }
+{ "_id" : "47932", "city" : "COVINGTON", "loc" : [ -87.38187600000001, 40.132618 ], "pop" : 4711, "state" : "IN" }
+{ "_id" : "47933", "city" : "CRAWFORDSVILLE", "loc" : [ -86.90742400000001, 40.032524 ], "pop" : 22838, "state" : "IN" }
+{ "_id" : "47940", "city" : "DARLINGTON", "loc" : [ -86.764505, 40.111778 ], "pop" : 1941, "state" : "IN" }
+{ "_id" : "47942", "city" : "EARL PARK", "loc" : [ -87.423199, 40.694465 ], "pop" : 903, "state" : "IN" }
+{ "_id" : "47943", "city" : "FAIR OAKS", "loc" : [ -87.197031, 41.072862 ], "pop" : 1254, "state" : "IN" }
+{ "_id" : "47944", "city" : "FOWLER", "loc" : [ -87.30901900000001, 40.625511 ], "pop" : 3762, "state" : "IN" }
+{ "_id" : "47946", "city" : "FRANCESVILLE", "loc" : [ -86.85534, 40.97094 ], "pop" : 1808, "state" : "IN" }
+{ "_id" : "47948", "city" : "GOODLAND", "loc" : [ -87.299858, 40.766872 ], "pop" : 1341, "state" : "IN" }
+{ "_id" : "47949", "city" : "HILLSBORO", "loc" : [ -87.154509, 40.083452 ], "pop" : 2318, "state" : "IN" }
+{ "_id" : "47950", "city" : "IDAVILLE", "loc" : [ -86.655647, 40.767372 ], "pop" : 673, "state" : "IN" }
+{ "_id" : "47951", "city" : "KENTLAND", "loc" : [ -87.44707099999999, 40.787678 ], "pop" : 2609, "state" : "IN" }
+{ "_id" : "47952", "city" : "CATES", "loc" : [ -87.30354800000001, 39.989383 ], "pop" : 2183, "state" : "IN" }
+{ "_id" : "47954", "city" : "LADOGA", "loc" : [ -86.80309800000001, 39.91325 ], "pop" : 2405, "state" : "IN" }
+{ "_id" : "47955", "city" : "LINDEN", "loc" : [ -86.89054899999999, 40.183316 ], "pop" : 1274, "state" : "IN" }
+{ "_id" : "47957", "city" : "MEDARYVILLE", "loc" : [ -86.880844, 41.089734 ], "pop" : 2030, "state" : "IN" }
+{ "_id" : "47959", "city" : "MONON", "loc" : [ -86.86353699999999, 40.861176 ], "pop" : 3119, "state" : "IN" }
+{ "_id" : "47960", "city" : "MONTICELLO", "loc" : [ -86.754999, 40.762556 ], "pop" : 13599, "state" : "IN" }
+{ "_id" : "47963", "city" : "MOROCCO", "loc" : [ -87.41871, 40.964547 ], "pop" : 2461, "state" : "IN" }
+{ "_id" : "47967", "city" : "NEW RICHMOND", "loc" : [ -86.978925, 40.18118 ], "pop" : 909, "state" : "IN" }
+{ "_id" : "47968", "city" : "NEW ROSS", "loc" : [ -86.752768, 39.988266 ], "pop" : 1440, "state" : "IN" }
+{ "_id" : "47970", "city" : "OTTERBEIN", "loc" : [ -87.12249, 40.517013 ], "pop" : 1527, "state" : "IN" }
+{ "_id" : "47971", "city" : "OXFORD", "loc" : [ -87.252576, 40.521708 ], "pop" : 1641, "state" : "IN" }
+{ "_id" : "47974", "city" : "PERRYSVILLE", "loc" : [ -87.464787, 40.073697 ], "pop" : 1672, "state" : "IN" }
+{ "_id" : "47975", "city" : "PINE VILLAGE", "loc" : [ -87.231724, 40.432759 ], "pop" : 1310, "state" : "IN" }
+{ "_id" : "47977", "city" : "REMINGTON", "loc" : [ -87.15994000000001, 40.766653 ], "pop" : 1937, "state" : "IN" }
+{ "_id" : "47978", "city" : "COLLEGEVILLE", "loc" : [ -87.13373300000001, 40.947731 ], "pop" : 9776, "state" : "IN" }
+{ "_id" : "47980", "city" : "REYNOLDS", "loc" : [ -86.86914, 40.760608 ], "pop" : 1148, "state" : "IN" }
+{ "_id" : "47981", "city" : "ROMNEY", "loc" : [ -86.90441199999999, 40.2605 ], "pop" : 694, "state" : "IN" }
+{ "_id" : "47985", "city" : "TANGIER", "loc" : [ -87.341551, 39.920601 ], "pop" : 711, "state" : "IN" }
+{ "_id" : "47987", "city" : "VEEDERSBURG", "loc" : [ -87.260167, 40.118616 ], "pop" : 3081, "state" : "IN" }
+{ "_id" : "47989", "city" : "WAVELAND", "loc" : [ -87.01776, 39.901996 ], "pop" : 1548, "state" : "IN" }
+{ "_id" : "47990", "city" : "WAYNETOWN", "loc" : [ -87.051165, 40.085788 ], "pop" : 1529, "state" : "IN" }
+{ "_id" : "47991", "city" : "WEST LEBANON", "loc" : [ -87.43667600000001, 40.241491 ], "pop" : 2957, "state" : "IN" }
+{ "_id" : "47992", "city" : "WESTPOINT", "loc" : [ -87.05747700000001, 40.358052 ], "pop" : 145, "state" : "IN" }
+{ "_id" : "47993", "city" : "MARSHFIELD", "loc" : [ -87.278689, 40.309435 ], "pop" : 3591, "state" : "IN" }
+{ "_id" : "47994", "city" : "WINGATE", "loc" : [ -87.066441, 40.166594 ], "pop" : 552, "state" : "IN" }
+{ "_id" : "47995", "city" : "WOLCOTT", "loc" : [ -87.028997, 40.751613 ], "pop" : 1909, "state" : "IN" }
+{ "_id" : "48001", "city" : "PEARL BEACH", "loc" : [ -82.560159, 42.630704 ], "pop" : 11783, "state" : "MI" }
+{ "_id" : "48002", "city" : "BERLIN", "loc" : [ -82.886809, 42.919864 ], "pop" : 1333, "state" : "MI" }
+{ "_id" : "48003", "city" : "ALMONT", "loc" : [ -83.036221, 42.926007 ], "pop" : 5315, "state" : "MI" }
+{ "_id" : "48004", "city" : "ANCHORVILLE", "loc" : [ -82.70939199999999, 42.711817 ], "pop" : 5360, "state" : "MI" }
+{ "_id" : "48005", "city" : "ARMADA", "loc" : [ -82.889905, 42.840903 ], "pop" : 4819, "state" : "MI" }
+{ "_id" : "48006", "city" : "GREENWOOD", "loc" : [ -82.678141, 43.056424 ], "pop" : 2325, "state" : "MI" }
+{ "_id" : "48009", "city" : "BIRMINGHAM", "loc" : [ -83.213255, 42.544396 ], "pop" : 19611, "state" : "MI" }
+{ "_id" : "48014", "city" : "MUSSEY", "loc" : [ -82.92518800000001, 43.019976 ], "pop" : 4304, "state" : "MI" }
+{ "_id" : "48015", "city" : "CENTER LINE", "loc" : [ -83.02477, 42.47879 ], "pop" : 8923, "state" : "MI" }
+{ "_id" : "48017", "city" : "CLAWSON", "loc" : [ -83.150317, 42.536468 ], "pop" : 14008, "state" : "MI" }
+{ "_id" : "48021", "city" : "EASTPOINTE", "loc" : [ -82.945896, 42.465756 ], "pop" : 35073, "state" : "MI" }
+{ "_id" : "48022", "city" : "EMMETT", "loc" : [ -82.785402, 42.987239 ], "pop" : 2335, "state" : "MI" }
+{ "_id" : "48023", "city" : "IRA", "loc" : [ -82.63767300000001, 42.680651 ], "pop" : 3781, "state" : "MI" }
+{ "_id" : "48025", "city" : "FRANKLIN", "loc" : [ -83.251852, 42.521891 ], "pop" : 13880, "state" : "MI" }
+{ "_id" : "48026", "city" : "FRASER", "loc" : [ -82.94696399999999, 42.542252 ], "pop" : 20605, "state" : "MI" }
+{ "_id" : "48027", "city" : "WALES", "loc" : [ -82.621728, 43.000058 ], "pop" : 3285, "state" : "MI" }
+{ "_id" : "48028", "city" : "HARSENS ISLAND", "loc" : [ -82.586049, 42.585043 ], "pop" : 1091, "state" : "MI" }
+{ "_id" : "48030", "city" : "HAZEL PARK", "loc" : [ -83.09818199999999, 42.460768 ], "pop" : 20218, "state" : "MI" }
+{ "_id" : "48032", "city" : "GRANT TOWNSHIP", "loc" : [ -82.554734, 43.134584 ], "pop" : 1498, "state" : "MI" }
+{ "_id" : "48034", "city" : "SOUTHFIELD", "loc" : [ -83.28829500000001, 42.477676 ], "pop" : 28647, "state" : "MI" }
+{ "_id" : "48039", "city" : "COTTRELLVILLE", "loc" : [ -82.514034, 42.721291 ], "pop" : 10057, "state" : "MI" }
+{ "_id" : "48040", "city" : "MARYSVILLE", "loc" : [ -82.48134400000001, 42.913534 ], "pop" : 8515, "state" : "MI" }
+{ "_id" : "48041", "city" : "RILEY", "loc" : [ -82.769623, 42.905955 ], "pop" : 3328, "state" : "MI" }
+{ "_id" : "48043", "city" : "MOUNT CLEMENS", "loc" : [ -82.894052, 42.577562 ], "pop" : 67489, "state" : "MI" }
+{ "_id" : "48044", "city" : "MACOMB", "loc" : [ -82.946845, 42.616456 ], "pop" : 51044, "state" : "MI" }
+{ "_id" : "48045", "city" : "SELFRIDGE A N G", "loc" : [ -82.836395, 42.602743 ], "pop" : 34104, "state" : "MI" }
+{ "_id" : "48047", "city" : "CHESTERFIELD", "loc" : [ -82.780102, 42.675344 ], "pop" : 22480, "state" : "MI" }
+{ "_id" : "48048", "city" : "LENOX", "loc" : [ -82.82024800000001, 42.732958 ], "pop" : 4800, "state" : "MI" }
+{ "_id" : "48049", "city" : "RUBY", "loc" : [ -82.538252, 43.026861 ], "pop" : 2316, "state" : "MI" }
+{ "_id" : "48060", "city" : "PORT HURON", "loc" : [ -82.45993799999999, 42.995843 ], "pop" : 58197, "state" : "MI" }
+{ "_id" : "48062", "city" : "RICHMOND", "loc" : [ -82.730052, 42.812743 ], "pop" : 12587, "state" : "MI" }
+{ "_id" : "48065", "city" : "BRUCE", "loc" : [ -83.019204, 42.803513 ], "pop" : 13552, "state" : "MI" }
+{ "_id" : "48066", "city" : "ROSEVILLE", "loc" : [ -82.93868000000001, 42.503423 ], "pop" : 51539, "state" : "MI" }
+{ "_id" : "48067", "city" : "ROYAL OAK", "loc" : [ -83.136584, 42.490579 ], "pop" : 27820, "state" : "MI" }
+{ "_id" : "48069", "city" : "PLEASANT RIDGE", "loc" : [ -83.143771, 42.47104 ], "pop" : 2895, "state" : "MI" }
+{ "_id" : "48070", "city" : "HUNTINGTON WOODS", "loc" : [ -83.17490599999999, 42.482538 ], "pop" : 9107, "state" : "MI" }
+{ "_id" : "48071", "city" : "MADISON HEIGHTS", "loc" : [ -83.102699, 42.501605 ], "pop" : 32196, "state" : "MI" }
+{ "_id" : "48072", "city" : "BERKLEY", "loc" : [ -83.188683, 42.502755 ], "pop" : 22323, "state" : "MI" }
+{ "_id" : "48073", "city" : "ROYAL OAK", "loc" : [ -83.157027, 42.519047 ], "pop" : 32093, "state" : "MI" }
+{ "_id" : "48074", "city" : "KIMBALL", "loc" : [ -82.574516, 42.922072 ], "pop" : 4496, "state" : "MI" }
+{ "_id" : "48075", "city" : "SOUTHFIELD", "loc" : [ -83.225539, 42.463831 ], "pop" : 22758, "state" : "MI" }
+{ "_id" : "48076", "city" : "LATHRUP VILLAGE", "loc" : [ -83.22971, 42.499915 ], "pop" : 29081, "state" : "MI" }
+{ "_id" : "48079", "city" : "SAINT CLAIR", "loc" : [ -82.513256, 42.825453 ], "pop" : 11681, "state" : "MI" }
+{ "_id" : "48080", "city" : "SAINT CLAIR SHOR", "loc" : [ -82.900674, 42.463474 ], "pop" : 25179, "state" : "MI" }
+{ "_id" : "48081", "city" : "SAINT CLAIR SHOR", "loc" : [ -82.89995399999999, 42.49538 ], "pop" : 23479, "state" : "MI" }
+{ "_id" : "48082", "city" : "SAINT CLAIR SHOR", "loc" : [ -82.886538, 42.526627 ], "pop" : 19975, "state" : "MI" }
+{ "_id" : "48083", "city" : "TROY", "loc" : [ -83.113771, 42.559668 ], "pop" : 20459, "state" : "MI" }
+{ "_id" : "48084", "city" : "TROY", "loc" : [ -83.179947, 42.562696 ], "pop" : 13010, "state" : "MI" }
+{ "_id" : "48089", "city" : "WARREN", "loc" : [ -82.99738499999999, 42.468494 ], "pop" : 35861, "state" : "MI" }
+{ "_id" : "48091", "city" : "WARREN", "loc" : [ -83.059263, 42.466463 ], "pop" : 33165, "state" : "MI" }
+{ "_id" : "48092", "city" : "WARREN", "loc" : [ -83.064278, 42.512459 ], "pop" : 25781, "state" : "MI" }
+{ "_id" : "48093", "city" : "WARREN", "loc" : [ -82.996764, 42.514943 ], "pop" : 50327, "state" : "MI" }
+{ "_id" : "48094", "city" : "WASHINGTON", "loc" : [ -83.026805, 42.726202 ], "pop" : 10975, "state" : "MI" }
+{ "_id" : "48097", "city" : "BROCKWAY", "loc" : [ -82.797899, 43.122429 ], "pop" : 5665, "state" : "MI" }
+{ "_id" : "48098", "city" : "TROY", "loc" : [ -83.14500099999999, 42.598118 ], "pop" : 39379, "state" : "MI" }
+{ "_id" : "48101", "city" : "ALLEN PARK", "loc" : [ -83.212001, 42.25223 ], "pop" : 31167, "state" : "MI" }
+{ "_id" : "48103", "city" : "ANN ARBOR", "loc" : [ -83.783998, 42.279379 ], "pop" : 41263, "state" : "MI" }
+{ "_id" : "48104", "city" : "ANN ARBOR", "loc" : [ -83.728156, 42.26939 ], "pop" : 47564, "state" : "MI" }
+{ "_id" : "48105", "city" : "ANN ARBOR", "loc" : [ -83.706756, 42.304247 ], "pop" : 28543, "state" : "MI" }
+{ "_id" : "48108", "city" : "ANN ARBOR", "loc" : [ -83.701481, 42.232782 ], "pop" : 17948, "state" : "MI" }
+{ "_id" : "48109", "city" : "ANN ARBOR", "loc" : [ -83.715363, 42.293 ], "pop" : 0, "state" : "MI" }
+{ "_id" : "48111", "city" : "BELLEVILLE", "loc" : [ -83.48542500000001, 42.194858 ], "pop" : 35436, "state" : "MI" }
+{ "_id" : "48116", "city" : "BRIGHTON", "loc" : [ -83.775628, 42.537069 ], "pop" : 37205, "state" : "MI" }
+{ "_id" : "48117", "city" : "CARLETON", "loc" : [ -83.375502, 42.052941 ], "pop" : 8144, "state" : "MI" }
+{ "_id" : "48118", "city" : "CHELSEA", "loc" : [ -84.03339200000001, 42.320692 ], "pop" : 9504, "state" : "MI" }
+{ "_id" : "48120", "city" : "DEARBORN", "loc" : [ -83.160488, 42.305295 ], "pop" : 6325, "state" : "MI" }
+{ "_id" : "48122", "city" : "MELVINDALE", "loc" : [ -83.182573, 42.281229 ], "pop" : 11226, "state" : "MI" }
+{ "_id" : "48124", "city" : "DEARBORN", "loc" : [ -83.25356499999999, 42.294141 ], "pop" : 34078, "state" : "MI" }
+{ "_id" : "48125", "city" : "DEARBORN HEIGHTS", "loc" : [ -83.260603, 42.276824 ], "pop" : 24715, "state" : "MI" }
+{ "_id" : "48126", "city" : "DEARBORN", "loc" : [ -83.180065, 42.334882 ], "pop" : 37807, "state" : "MI" }
+{ "_id" : "48127", "city" : "DEARBORN HEIGHTS", "loc" : [ -83.286383, 42.335317 ], "pop" : 36123, "state" : "MI" }
+{ "_id" : "48128", "city" : "DEARBORN", "loc" : [ -83.27013100000001, 42.319981 ], "pop" : 11076, "state" : "MI" }
+{ "_id" : "48130", "city" : "DEXTER", "loc" : [ -83.90002800000001, 42.35832 ], "pop" : 8216, "state" : "MI" }
+{ "_id" : "48131", "city" : "DUNDEE", "loc" : [ -83.652165, 41.951435 ], "pop" : 6521, "state" : "MI" }
+{ "_id" : "48133", "city" : "ERIE", "loc" : [ -83.495797, 41.782935 ], "pop" : 5101, "state" : "MI" }
+{ "_id" : "48134", "city" : "FLAT ROCK", "loc" : [ -83.27952500000001, 42.105521 ], "pop" : 11180, "state" : "MI" }
+{ "_id" : "48135", "city" : "GARDEN CITY", "loc" : [ -83.340236, 42.32415 ], "pop" : 31846, "state" : "MI" }
+{ "_id" : "48137", "city" : "GREGORY", "loc" : [ -84.046588, 42.450671 ], "pop" : 3323, "state" : "MI" }
+{ "_id" : "48138", "city" : "GROSSE ILE", "loc" : [ -83.153828, 42.13465 ], "pop" : 9783, "state" : "MI" }
+{ "_id" : "48140", "city" : "IDA", "loc" : [ -83.591561, 41.854928 ], "pop" : 2690, "state" : "MI" }
+{ "_id" : "48141", "city" : "INKSTER", "loc" : [ -83.31462999999999, 42.294041 ], "pop" : 30772, "state" : "MI" }
+{ "_id" : "48144", "city" : "LAMBERTVILLE", "loc" : [ -83.625865, 41.753055 ], "pop" : 7959, "state" : "MI" }
+{ "_id" : "48145", "city" : "LA SALLE", "loc" : [ -83.47148799999999, 41.858489 ], "pop" : 3800, "state" : "MI" }
+{ "_id" : "48146", "city" : "LINCOLN PARK", "loc" : [ -83.180688, 42.242211 ], "pop" : 41763, "state" : "MI" }
+{ "_id" : "48150", "city" : "LIVONIA", "loc" : [ -83.36494, 42.361503 ], "pop" : 27644, "state" : "MI" }
+{ "_id" : "48152", "city" : "LIVONIA", "loc" : [ -83.363603, 42.425793 ], "pop" : 30199, "state" : "MI" }
+{ "_id" : "48154", "city" : "LIVONIA", "loc" : [ -83.377157, 42.395796 ], "pop" : 43007, "state" : "MI" }
+{ "_id" : "48157", "city" : "LUNA PIER", "loc" : [ -83.436165, 41.815368 ], "pop" : 1758, "state" : "MI" }
+{ "_id" : "48158", "city" : "MANCHESTER", "loc" : [ -84.033247, 42.155545 ], "pop" : 6163, "state" : "MI" }
+{ "_id" : "48159", "city" : "MAYBEE", "loc" : [ -83.51790200000001, 42.028822 ], "pop" : 3822, "state" : "MI" }
+{ "_id" : "48160", "city" : "MILAN", "loc" : [ -83.67763600000001, 42.091373 ], "pop" : 12411, "state" : "MI" }
+{ "_id" : "48161", "city" : "DETROIT BEACH", "loc" : [ -83.404848, 41.92751 ], "pop" : 55630, "state" : "MI" }
+{ "_id" : "48164", "city" : "NEW BOSTON", "loc" : [ -83.35885500000001, 42.144899 ], "pop" : 9809, "state" : "MI" }
+{ "_id" : "48165", "city" : "NEW HUDSON", "loc" : [ -83.63423299999999, 42.507647 ], "pop" : 4233, "state" : "MI" }
+{ "_id" : "48166", "city" : "NEWPORT", "loc" : [ -83.280438, 41.976582 ], "pop" : 5651, "state" : "MI" }
+{ "_id" : "48167", "city" : "NORTHVILLE", "loc" : [ -83.479355, 42.426245 ], "pop" : 30177, "state" : "MI" }
+{ "_id" : "48169", "city" : "PINCKNEY", "loc" : [ -83.909918, 42.459579 ], "pop" : 13071, "state" : "MI" }
+{ "_id" : "48170", "city" : "PLYMOUTH", "loc" : [ -83.479946, 42.36882 ], "pop" : 35389, "state" : "MI" }
+{ "_id" : "48173", "city" : "GIBRALTAR", "loc" : [ -83.216196, 42.07918 ], "pop" : 9594, "state" : "MI" }
+{ "_id" : "48174", "city" : "ROMULUS", "loc" : [ -83.358288, 42.220304 ], "pop" : 23471, "state" : "MI" }
+{ "_id" : "48176", "city" : "SALINE", "loc" : [ -83.784936, 42.169844 ], "pop" : 13356, "state" : "MI" }
+{ "_id" : "48178", "city" : "SOUTH LYON", "loc" : [ -83.658951, 42.456678 ], "pop" : 15616, "state" : "MI" }
+{ "_id" : "48179", "city" : "SOUTH ROCKWOOD", "loc" : [ -83.266302, 42.062405 ], "pop" : 3204, "state" : "MI" }
+{ "_id" : "48180", "city" : "TAYLOR", "loc" : [ -83.267269, 42.231738 ], "pop" : 70811, "state" : "MI" }
+{ "_id" : "48182", "city" : "TEMPERANCE", "loc" : [ -83.579739, 41.768229 ], "pop" : 15581, "state" : "MI" }
+{ "_id" : "48183", "city" : "WOODHAVEN", "loc" : [ -83.218142, 42.134304 ], "pop" : 38874, "state" : "MI" }
+{ "_id" : "48184", "city" : "WAYNE", "loc" : [ -83.375812, 42.276805 ], "pop" : 19911, "state" : "MI" }
+{ "_id" : "48185", "city" : "WESTLAND", "loc" : [ -83.374908, 42.318882 ], "pop" : 84712, "state" : "MI" }
+{ "_id" : "48187", "city" : "CANTON", "loc" : [ -83.46952400000001, 42.332013 ], "pop" : 39308, "state" : "MI" }
+{ "_id" : "48188", "city" : "CANTON", "loc" : [ -83.465007, 42.290997 ], "pop" : 17741, "state" : "MI" }
+{ "_id" : "48189", "city" : "WHITMORE LAKE", "loc" : [ -83.78282, 42.428904 ], "pop" : 11639, "state" : "MI" }
+{ "_id" : "48191", "city" : "WILLIS", "loc" : [ -83.568741, 42.129249 ], "pop" : 2574, "state" : "MI" }
+{ "_id" : "48192", "city" : "RIVERVIEW", "loc" : [ -83.182112, 42.196065 ], "pop" : 50509, "state" : "MI" }
+{ "_id" : "48195", "city" : "SOUTHGATE", "loc" : [ -83.19991899999999, 42.204434 ], "pop" : 30771, "state" : "MI" }
+{ "_id" : "48197", "city" : "YPSILANTI", "loc" : [ -83.63362100000001, 42.232544 ], "pop" : 46790, "state" : "MI" }
+{ "_id" : "48198", "city" : "YPSILANTI", "loc" : [ -83.582972, 42.24388 ], "pop" : 39534, "state" : "MI" }
+{ "_id" : "48201", "city" : "DETROIT", "loc" : [ -83.06039800000001, 42.347429 ], "pop" : 15920, "state" : "MI" }
+{ "_id" : "48202", "city" : "DETROIT", "loc" : [ -83.07961299999999, 42.377033 ], "pop" : 24565, "state" : "MI" }
+{ "_id" : "48203", "city" : "HIGHLAND PARK", "loc" : [ -83.100909, 42.421155 ], "pop" : 53352, "state" : "MI" }
+{ "_id" : "48204", "city" : "DETROIT", "loc" : [ -83.142151, 42.366098 ], "pop" : 48856, "state" : "MI" }
+{ "_id" : "48205", "city" : "DETROIT", "loc" : [ -82.981279, 42.431259 ], "pop" : 65127, "state" : "MI" }
+{ "_id" : "48206", "city" : "DETROIT", "loc" : [ -83.108695, 42.374893 ], "pop" : 38035, "state" : "MI" }
+{ "_id" : "48207", "city" : "DETROIT", "loc" : [ -83.027101, 42.352373 ], "pop" : 25703, "state" : "MI" }
+{ "_id" : "48208", "city" : "DETROIT", "loc" : [ -83.09271099999999, 42.34947 ], "pop" : 14925, "state" : "MI" }
+{ "_id" : "48209", "city" : "DETROIT", "loc" : [ -83.115464, 42.309746 ], "pop" : 38839, "state" : "MI" }
+{ "_id" : "48210", "city" : "DETROIT", "loc" : [ -83.130281, 42.337603 ], "pop" : 39833, "state" : "MI" }
+{ "_id" : "48211", "city" : "DETROIT", "loc" : [ -83.04094499999999, 42.380922 ], "pop" : 13911, "state" : "MI" }
+{ "_id" : "48212", "city" : "HAMTRAMCK", "loc" : [ -83.05826500000001, 42.408117 ], "pop" : 42830, "state" : "MI" }
+{ "_id" : "48213", "city" : "DETROIT", "loc" : [ -82.99253, 42.39816 ], "pop" : 52700, "state" : "MI" }
+{ "_id" : "48214", "city" : "DETROIT", "loc" : [ -82.993798, 42.366944 ], "pop" : 39584, "state" : "MI" }
+{ "_id" : "48215", "city" : "DETROIT", "loc" : [ -82.951319, 42.377272 ], "pop" : 24493, "state" : "MI" }
+{ "_id" : "48216", "city" : "DETROIT", "loc" : [ -83.082656, 42.327467 ], "pop" : 8592, "state" : "MI" }
+{ "_id" : "48217", "city" : "DETROIT", "loc" : [ -83.154545, 42.271914 ], "pop" : 11634, "state" : "MI" }
+{ "_id" : "48218", "city" : "RIVER ROUGE", "loc" : [ -83.136432, 42.269229 ], "pop" : 11314, "state" : "MI" }
+{ "_id" : "48219", "city" : "DETROIT", "loc" : [ -83.249495, 42.426033 ], "pop" : 63058, "state" : "MI" }
+{ "_id" : "48220", "city" : "FERNDALE", "loc" : [ -83.13625999999999, 42.458564 ], "pop" : 28698, "state" : "MI" }
+{ "_id" : "48221", "city" : "DETROIT", "loc" : [ -83.149976, 42.425998 ], "pop" : 48068, "state" : "MI" }
+{ "_id" : "48223", "city" : "DETROIT", "loc" : [ -83.245403, 42.394453 ], "pop" : 39612, "state" : "MI" }
+{ "_id" : "48224", "city" : "DETROIT", "loc" : [ -82.944061, 42.409808 ], "pop" : 52938, "state" : "MI" }
+{ "_id" : "48225", "city" : "HARPER WOODS", "loc" : [ -82.92888499999999, 42.437658 ], "pop" : 14937, "state" : "MI" }
+{ "_id" : "48226", "city" : "DETROIT", "loc" : [ -83.04843200000001, 42.333346 ], "pop" : 5502, "state" : "MI" }
+{ "_id" : "48227", "city" : "DETROIT", "loc" : [ -83.193732, 42.388303 ], "pop" : 68390, "state" : "MI" }
+{ "_id" : "48228", "city" : "DETROIT", "loc" : [ -83.216753, 42.35473 ], "pop" : 67215, "state" : "MI" }
+{ "_id" : "48229", "city" : "ECORSE", "loc" : [ -83.148943, 42.251881 ], "pop" : 12164, "state" : "MI" }
+{ "_id" : "48230", "city" : "GROSSE POINTE", "loc" : [ -82.92439400000001, 42.384694 ], "pop" : 19302, "state" : "MI" }
+{ "_id" : "48234", "city" : "DETROIT", "loc" : [ -83.04338300000001, 42.4337 ], "pop" : 47768, "state" : "MI" }
+{ "_id" : "48235", "city" : "DETROIT", "loc" : [ -83.19512400000001, 42.426098 ], "pop" : 57165, "state" : "MI" }
+{ "_id" : "48236", "city" : "GROSSE POINTE", "loc" : [ -82.900248, 42.427404 ], "pop" : 32076, "state" : "MI" }
+{ "_id" : "48237", "city" : "OAK PARK", "loc" : [ -83.183993, 42.466151 ], "pop" : 28884, "state" : "MI" }
+{ "_id" : "48238", "city" : "DETROIT", "loc" : [ -83.14114499999999, 42.395932 ], "pop" : 50599, "state" : "MI" }
+{ "_id" : "48239", "city" : "REDFORD", "loc" : [ -83.28895, 42.375554 ], "pop" : 39218, "state" : "MI" }
+{ "_id" : "48240", "city" : "REDFORD", "loc" : [ -83.30166, 42.426354 ], "pop" : 20297, "state" : "MI" }
+{ "_id" : "48242", "city" : "DETROIT", "loc" : [ -83.377081, 42.220718 ], "pop" : 211, "state" : "MI" }
+{ "_id" : "48301", "city" : "BLOOMFIELD TOWNS", "loc" : [ -83.2771, 42.545044 ], "pop" : 15338, "state" : "MI" }
+{ "_id" : "48302", "city" : "BLOOMFIELD TOWNS", "loc" : [ -83.296271, 42.583237 ], "pop" : 17017, "state" : "MI" }
+{ "_id" : "48304", "city" : "BLOOMFIELD TOWNS", "loc" : [ -83.234011, 42.593764 ], "pop" : 16057, "state" : "MI" }
+{ "_id" : "48306", "city" : "ROCHESTER HILLS", "loc" : [ -83.164215, 42.710684 ], "pop" : 15755, "state" : "MI" }
+{ "_id" : "48307", "city" : "ROCHESTER HILLS", "loc" : [ -83.129124, 42.660185 ], "pop" : 31734, "state" : "MI" }
+{ "_id" : "48309", "city" : "ROCHESTER HILLS", "loc" : [ -83.181842, 42.666848 ], "pop" : 27450, "state" : "MI" }
+{ "_id" : "48310", "city" : "STERLING HEIGHTS", "loc" : [ -83.07013499999999, 42.564782 ], "pop" : 42255, "state" : "MI" }
+{ "_id" : "48312", "city" : "STERLING HEIGHTS", "loc" : [ -83.00289600000001, 42.559203 ], "pop" : 33163, "state" : "MI" }
+{ "_id" : "48313", "city" : "STERLING HEIGHTS", "loc" : [ -82.99976599999999, 42.600498 ], "pop" : 33890, "state" : "MI" }
+{ "_id" : "48314", "city" : "STERLING HEIGHTS", "loc" : [ -83.03445499999999, 42.612352 ], "pop" : 8502, "state" : "MI" }
+{ "_id" : "48315", "city" : "SHELBY TOWNSHIP", "loc" : [ -82.99654700000001, 42.663694 ], "pop" : 11783, "state" : "MI" }
+{ "_id" : "48316", "city" : "SHELBY TOWNSHIP", "loc" : [ -83.060928, 42.682668 ], "pop" : 15039, "state" : "MI" }
+{ "_id" : "48317", "city" : "SHELBY TOWNSHIP", "loc" : [ -83.048109, 42.640462 ], "pop" : 24775, "state" : "MI" }
+{ "_id" : "48320", "city" : "SYLVAN LAKE", "loc" : [ -83.339551, 42.610449 ], "pop" : 4688, "state" : "MI" }
+{ "_id" : "48322", "city" : "WEST BLOOMFIELD", "loc" : [ -83.379313, 42.542366 ], "pop" : 26119, "state" : "MI" }
+{ "_id" : "48323", "city" : "ORCHARD LAKE", "loc" : [ -83.369342, 42.570171 ], "pop" : 15797, "state" : "MI" }
+{ "_id" : "48324", "city" : "ORCHARD LAKE", "loc" : [ -83.39553600000001, 42.598109 ], "pop" : 13719, "state" : "MI" }
+{ "_id" : "48326", "city" : "AUBURN HILLS", "loc" : [ -83.237489, 42.658345 ], "pop" : 16184, "state" : "MI" }
+{ "_id" : "48327", "city" : "WATERFORD", "loc" : [ -83.407602, 42.643751 ], "pop" : 17213, "state" : "MI" }
+{ "_id" : "48328", "city" : "WATERFORD", "loc" : [ -83.354624, 42.642944 ], "pop" : 24330, "state" : "MI" }
+{ "_id" : "48329", "city" : "WATERFORD", "loc" : [ -83.38786899999999, 42.687663 ], "pop" : 25125, "state" : "MI" }
+{ "_id" : "48331", "city" : "FARMINGTON HILLS", "loc" : [ -83.405433, 42.510042 ], "pop" : 19626, "state" : "MI" }
+{ "_id" : "48334", "city" : "FARMINGTON HILLS", "loc" : [ -83.35198, 42.506798 ], "pop" : 17513, "state" : "MI" }
+{ "_id" : "48335", "city" : "FARMINGTON HILLS", "loc" : [ -83.40013399999999, 42.463055 ], "pop" : 19715, "state" : "MI" }
+{ "_id" : "48336", "city" : "FARMINGTON HILLS", "loc" : [ -83.345465, 42.460938 ], "pop" : 25680, "state" : "MI" }
+{ "_id" : "48340", "city" : "PONTIAC", "loc" : [ -83.28933499999999, 42.667955 ], "pop" : 23663, "state" : "MI" }
+{ "_id" : "48341", "city" : "PONTIAC", "loc" : [ -83.304149, 42.629449 ], "pop" : 22685, "state" : "MI" }
+{ "_id" : "48342", "city" : "PONTIAC", "loc" : [ -83.279236, 42.643856 ], "pop" : 24663, "state" : "MI" }
+{ "_id" : "48346", "city" : "INDEPENDENCE", "loc" : [ -83.405658, 42.721637 ], "pop" : 17459, "state" : "MI" }
+{ "_id" : "48348", "city" : "INDEPENDENCE", "loc" : [ -83.390568, 42.772414 ], "pop" : 14635, "state" : "MI" }
+{ "_id" : "48350", "city" : "SPRINGFIELD", "loc" : [ -83.520022, 42.75413 ], "pop" : 5949, "state" : "MI" }
+{ "_id" : "48353", "city" : "HARTLAND", "loc" : [ -83.714674, 42.63561 ], "pop" : 4584, "state" : "MI" }
+{ "_id" : "48356", "city" : "HIGHLAND", "loc" : [ -83.58951, 42.669187 ], "pop" : 8161, "state" : "MI" }
+{ "_id" : "48357", "city" : "HIGHLAND", "loc" : [ -83.637013, 42.659453 ], "pop" : 7376, "state" : "MI" }
+{ "_id" : "48359", "city" : "ORION", "loc" : [ -83.291701, 42.720779 ], "pop" : 5264, "state" : "MI" }
+{ "_id" : "48360", "city" : "ORION", "loc" : [ -83.282792, 42.742212 ], "pop" : 6725, "state" : "MI" }
+{ "_id" : "48362", "city" : "ORION", "loc" : [ -83.253208, 42.780598 ], "pop" : 11862, "state" : "MI" }
+{ "_id" : "48363", "city" : "OAKLAND", "loc" : [ -83.171116, 42.773179 ], "pop" : 3716, "state" : "MI" }
+{ "_id" : "48367", "city" : "ADDISON TOWNSHIP", "loc" : [ -83.13808899999999, 42.836423 ], "pop" : 3963, "state" : "MI" }
+{ "_id" : "48370", "city" : "OXFORD", "loc" : [ -83.20045500000001, 42.826451 ], "pop" : 1267, "state" : "MI" }
+{ "_id" : "48371", "city" : "OXFORD", "loc" : [ -83.282892, 42.822272 ], "pop" : 13306, "state" : "MI" }
+{ "_id" : "48374", "city" : "NOVI", "loc" : [ -83.522423, 42.473495 ], "pop" : 5302, "state" : "MI" }
+{ "_id" : "48375", "city" : "NOVI", "loc" : [ -83.457741, 42.460354 ], "pop" : 19067, "state" : "MI" }
+{ "_id" : "48377", "city" : "NOVI", "loc" : [ -83.472838, 42.513616 ], "pop" : 6011, "state" : "MI" }
+{ "_id" : "48380", "city" : "MILFORD", "loc" : [ -83.650796, 42.601951 ], "pop" : 4050, "state" : "MI" }
+{ "_id" : "48381", "city" : "MILFORD", "loc" : [ -83.592404, 42.575841 ], "pop" : 10297, "state" : "MI" }
+{ "_id" : "48382", "city" : "COMMERCE TOWNSHI", "loc" : [ -83.49467, 42.589424 ], "pop" : 16939, "state" : "MI" }
+{ "_id" : "48383", "city" : "WHITE LAKE", "loc" : [ -83.539838, 42.658004 ], "pop" : 7528, "state" : "MI" }
+{ "_id" : "48386", "city" : "WHITE LAKE", "loc" : [ -83.473809, 42.641003 ], "pop" : 14778, "state" : "MI" }
+{ "_id" : "48390", "city" : "WOLVERINE LAKE", "loc" : [ -83.479623, 42.550384 ], "pop" : 15904, "state" : "MI" }
+{ "_id" : "48393", "city" : "WIXOM", "loc" : [ -83.528486, 42.534037 ], "pop" : 9337, "state" : "MI" }
+{ "_id" : "48401", "city" : "APPLEGATE", "loc" : [ -82.647865, 43.361899 ], "pop" : 1338, "state" : "MI" }
+{ "_id" : "48412", "city" : "ATTICA", "loc" : [ -83.166842, 43.054673 ], "pop" : 5780, "state" : "MI" }
+{ "_id" : "48413", "city" : "BAD AXE", "loc" : [ -83.00537799999999, 43.806745 ], "pop" : 7321, "state" : "MI" }
+{ "_id" : "48414", "city" : "BANCROFT", "loc" : [ -84.12072499999999, 42.881957 ], "pop" : 7199, "state" : "MI" }
+{ "_id" : "48415", "city" : "BIRCH RUN", "loc" : [ -83.79028700000001, 43.264868 ], "pop" : 7961, "state" : "MI" }
+{ "_id" : "48416", "city" : "BROWN CITY", "loc" : [ -82.99783600000001, 43.217073 ], "pop" : 4646, "state" : "MI" }
+{ "_id" : "48417", "city" : "BURT", "loc" : [ -83.95107299999999, 43.24043 ], "pop" : 5487, "state" : "MI" }
+{ "_id" : "48418", "city" : "BYRON", "loc" : [ -83.97297, 42.805928 ], "pop" : 3085, "state" : "MI" }
+{ "_id" : "48419", "city" : "CARSONVILLE", "loc" : [ -82.602169, 43.425805 ], "pop" : 2621, "state" : "MI" }
+{ "_id" : "48420", "city" : "CLIO", "loc" : [ -83.724949, 43.177885 ], "pop" : 21345, "state" : "MI" }
+{ "_id" : "48421", "city" : "COLUMBIAVILLE", "loc" : [ -83.381055, 43.150334 ], "pop" : 6499, "state" : "MI" }
+{ "_id" : "48422", "city" : "CROSWELL", "loc" : [ -82.63372099999999, 43.262245 ], "pop" : 5931, "state" : "MI" }
+{ "_id" : "48423", "city" : "DAVISON", "loc" : [ -83.526771, 43.034777 ], "pop" : 26713, "state" : "MI" }
+{ "_id" : "48426", "city" : "DECKER", "loc" : [ -83.06379099999999, 43.477532 ], "pop" : 480, "state" : "MI" }
+{ "_id" : "48427", "city" : "DECKERVILLE", "loc" : [ -82.71911799999999, 43.515087 ], "pop" : 4623, "state" : "MI" }
+{ "_id" : "48428", "city" : "DRYDEN", "loc" : [ -83.150066, 42.937772 ], "pop" : 3095, "state" : "MI" }
+{ "_id" : "48429", "city" : "DURAND", "loc" : [ -83.987651, 42.91171 ], "pop" : 7797, "state" : "MI" }
+{ "_id" : "48430", "city" : "FENTON", "loc" : [ -83.72935099999999, 42.785098 ], "pop" : 25337, "state" : "MI" }
+{ "_id" : "48432", "city" : "FILION", "loc" : [ -82.982483, 43.901362 ], "pop" : 988, "state" : "MI" }
+{ "_id" : "48433", "city" : "FLUSHING", "loc" : [ -83.84239100000001, 43.071954 ], "pop" : 23082, "state" : "MI" }
+{ "_id" : "48435", "city" : "FOSTORIA", "loc" : [ -83.379593, 43.264504 ], "pop" : 2242, "state" : "MI" }
+{ "_id" : "48436", "city" : "GAINES", "loc" : [ -83.885488, 42.881333 ], "pop" : 2931, "state" : "MI" }
+{ "_id" : "48438", "city" : "GOODRICH", "loc" : [ -83.484459, 42.914734 ], "pop" : 5184, "state" : "MI" }
+{ "_id" : "48439", "city" : "GRAND BLANC", "loc" : [ -83.626414, 42.928163 ], "pop" : 30329, "state" : "MI" }
+{ "_id" : "48441", "city" : "HARBOR BEACH", "loc" : [ -82.688608, 43.831249 ], "pop" : 4046, "state" : "MI" }
+{ "_id" : "48442", "city" : "HOLLY", "loc" : [ -83.612737, 42.790494 ], "pop" : 15119, "state" : "MI" }
+{ "_id" : "48444", "city" : "IMLAY CITY", "loc" : [ -83.07079899999999, 43.042512 ], "pop" : 6493, "state" : "MI" }
+{ "_id" : "48445", "city" : "KINDE", "loc" : [ -82.97552899999999, 43.948003 ], "pop" : 1082, "state" : "MI" }
+{ "_id" : "48446", "city" : "LAPEER", "loc" : [ -83.333153, 43.057879 ], "pop" : 27632, "state" : "MI" }
+{ "_id" : "48449", "city" : "LENNON", "loc" : [ -83.927908, 42.969323 ], "pop" : 3778, "state" : "MI" }
+{ "_id" : "48450", "city" : "LEXINGTON", "loc" : [ -82.530103, 43.24348 ], "pop" : 3815, "state" : "MI" }
+{ "_id" : "48451", "city" : "LINDEN", "loc" : [ -83.79928099999999, 42.810379 ], "pop" : 10127, "state" : "MI" }
+{ "_id" : "48453", "city" : "MARLETTE", "loc" : [ -83.057253, 43.339882 ], "pop" : 4869, "state" : "MI" }
+{ "_id" : "48454", "city" : "MELVIN", "loc" : [ -82.839277, 43.19304 ], "pop" : 816, "state" : "MI" }
+{ "_id" : "48455", "city" : "METAMORA", "loc" : [ -83.318371, 42.942365 ], "pop" : 6719, "state" : "MI" }
+{ "_id" : "48456", "city" : "MINDEN CITY", "loc" : [ -82.72986299999999, 43.681393 ], "pop" : 1637, "state" : "MI" }
+{ "_id" : "48457", "city" : "MONTROSE", "loc" : [ -83.882411, 43.175381 ], "pop" : 7181, "state" : "MI" }
+{ "_id" : "48458", "city" : "MOUNT MORRIS", "loc" : [ -83.68952299999999, 43.11601 ], "pop" : 27347, "state" : "MI" }
+{ "_id" : "48460", "city" : "NEW LOTHROP", "loc" : [ -83.98514400000001, 43.138781 ], "pop" : 3206, "state" : "MI" }
+{ "_id" : "48461", "city" : "NORTH BRANCH", "loc" : [ -83.226664, 43.206887 ], "pop" : 6106, "state" : "MI" }
+{ "_id" : "48462", "city" : "ORTONVILLE", "loc" : [ -83.428811, 42.840943 ], "pop" : 10315, "state" : "MI" }
+{ "_id" : "48463", "city" : "OTISVILLE", "loc" : [ -83.51718700000001, 43.170584 ], "pop" : 4130, "state" : "MI" }
+{ "_id" : "48464", "city" : "OTTER LAKE", "loc" : [ -83.42421899999999, 43.218334 ], "pop" : 2442, "state" : "MI" }
+{ "_id" : "48465", "city" : "PALMS", "loc" : [ -82.70173699999999, 43.625671 ], "pop" : 611, "state" : "MI" }
+{ "_id" : "48466", "city" : "PECK", "loc" : [ -82.81929, 43.26938 ], "pop" : 1658, "state" : "MI" }
+{ "_id" : "48467", "city" : "PORT AUSTIN", "loc" : [ -82.99842700000001, 44.022292 ], "pop" : 2508, "state" : "MI" }
+{ "_id" : "48468", "city" : "PORT HOPE", "loc" : [ -82.752893, 43.927989 ], "pop" : 1490, "state" : "MI" }
+{ "_id" : "48469", "city" : "PORT SANILAC", "loc" : [ -82.54679400000001, 43.43292 ], "pop" : 254, "state" : "MI" }
+{ "_id" : "48470", "city" : "RUTH", "loc" : [ -82.74139599999999, 43.740436 ], "pop" : 1162, "state" : "MI" }
+{ "_id" : "48471", "city" : "SANDUSKY", "loc" : [ -82.84093900000001, 43.405541 ], "pop" : 4198, "state" : "MI" }
+{ "_id" : "48472", "city" : "SNOVER", "loc" : [ -82.930063, 43.488649 ], "pop" : 2301, "state" : "MI" }
+{ "_id" : "48473", "city" : "SWARTZ CREEK", "loc" : [ -83.81700499999999, 42.946776 ], "pop" : 18263, "state" : "MI" }
+{ "_id" : "48475", "city" : "UBLY", "loc" : [ -82.96401299999999, 43.689631 ], "pop" : 2802, "state" : "MI" }
+{ "_id" : "48502", "city" : "FLINT", "loc" : [ -83.68776800000001, 43.012321 ], "pop" : 1359, "state" : "MI" }
+{ "_id" : "48503", "city" : "FLINT", "loc" : [ -83.691429, 43.012836 ], "pop" : 33451, "state" : "MI" }
+{ "_id" : "48504", "city" : "NORTHWEST", "loc" : [ -83.72990799999999, 43.04247 ], "pop" : 40445, "state" : "MI" }
+{ "_id" : "48505", "city" : "FLINT", "loc" : [ -83.700093, 43.063369 ], "pop" : 42423, "state" : "MI" }
+{ "_id" : "48506", "city" : "NORTHEAST", "loc" : [ -83.640192, 43.052596 ], "pop" : 35154, "state" : "MI" }
+{ "_id" : "48507", "city" : "FLINT", "loc" : [ -83.688999, 42.97303 ], "pop" : 37656, "state" : "MI" }
+{ "_id" : "48509", "city" : "NORTHEAST", "loc" : [ -83.606295, 43.024493 ], "pop" : 9432, "state" : "MI" }
+{ "_id" : "48519", "city" : "SOUTHEAST", "loc" : [ -83.61042399999999, 42.993847 ], "pop" : 6081, "state" : "MI" }
+{ "_id" : "48529", "city" : "SOUTHEAST", "loc" : [ -83.671064, 42.97268 ], "pop" : 11092, "state" : "MI" }
+{ "_id" : "48532", "city" : "NORTHWEST", "loc" : [ -83.768576, 43.01021 ], "pop" : 20367, "state" : "MI" }
+{ "_id" : "48601", "city" : "SAGINAW", "loc" : [ -83.915626, 43.404692 ], "pop" : 55547, "state" : "MI" }
+{ "_id" : "48602", "city" : "SAGINAW", "loc" : [ -83.97445500000001, 43.424838 ], "pop" : 34096, "state" : "MI" }
+{ "_id" : "48603", "city" : "SAGINAW", "loc" : [ -84.03028, 43.43251 ], "pop" : 49303, "state" : "MI" }
+{ "_id" : "48604", "city" : "SAGINAW", "loc" : [ -83.951421, 43.473223 ], "pop" : 11937, "state" : "MI" }
+{ "_id" : "48607", "city" : "SAGINAW", "loc" : [ -83.931872, 43.430141 ], "pop" : 3436, "state" : "MI" }
+{ "_id" : "48610", "city" : "ALGER", "loc" : [ -84.18719, 44.139488 ], "pop" : 2015, "state" : "MI" }
+{ "_id" : "48611", "city" : "AUBURN", "loc" : [ -84.10267, 43.607988 ], "pop" : 6154, "state" : "MI" }
+{ "_id" : "48612", "city" : "BEAVERTON", "loc" : [ -84.424059, 43.886576 ], "pop" : 9682, "state" : "MI" }
+{ "_id" : "48613", "city" : "BENTLEY", "loc" : [ -84.144738, 43.886028 ], "pop" : 1022, "state" : "MI" }
+{ "_id" : "48614", "city" : "BRANT", "loc" : [ -84.297849, 43.25484 ], "pop" : 1572, "state" : "MI" }
+{ "_id" : "48615", "city" : "BRECKENRIDGE", "loc" : [ -84.502319, 43.393463 ], "pop" : 2266, "state" : "MI" }
+{ "_id" : "48616", "city" : "CHESANING", "loc" : [ -84.112156, 43.182387 ], "pop" : 4567, "state" : "MI" }
+{ "_id" : "48617", "city" : "CLARE", "loc" : [ -84.763463, 43.822318 ], "pop" : 6635, "state" : "MI" }
+{ "_id" : "48618", "city" : "COLEMAN", "loc" : [ -84.591058, 43.749397 ], "pop" : 5866, "state" : "MI" }
+{ "_id" : "48619", "city" : "COMINS", "loc" : [ -84.026061, 44.826354 ], "pop" : 515, "state" : "MI" }
+{ "_id" : "48620", "city" : "EDENVILLE", "loc" : [ -84.396227, 43.802757 ], "pop" : 237, "state" : "MI" }
+{ "_id" : "48621", "city" : "FAIRVIEW", "loc" : [ -84.052532, 44.72046 ], "pop" : 1785, "state" : "MI" }
+{ "_id" : "48622", "city" : "FARWELL", "loc" : [ -84.87540199999999, 43.834163 ], "pop" : 4456, "state" : "MI" }
+{ "_id" : "48623", "city" : "FREELAND", "loc" : [ -84.18217300000001, 43.516134 ], "pop" : 10892, "state" : "MI" }
+{ "_id" : "48624", "city" : "GLADWIN", "loc" : [ -84.496801, 44.029618 ], "pop" : 11790, "state" : "MI" }
+{ "_id" : "48625", "city" : "HARRISON", "loc" : [ -84.77289, 44.028478 ], "pop" : 9223, "state" : "MI" }
+{ "_id" : "48626", "city" : "HEMLOCK", "loc" : [ -84.226563, 43.409911 ], "pop" : 5711, "state" : "MI" }
+{ "_id" : "48628", "city" : "HOPE", "loc" : [ -84.329605, 43.788167 ], "pop" : 1339, "state" : "MI" }
+{ "_id" : "48629", "city" : "HOUGHTON LAKE", "loc" : [ -84.742175, 44.341327 ], "pop" : 5625, "state" : "MI" }
+{ "_id" : "48631", "city" : "KAWKAWLIN", "loc" : [ -83.99265699999999, 43.679399 ], "pop" : 3935, "state" : "MI" }
+{ "_id" : "48632", "city" : "LAKE", "loc" : [ -84.97859699999999, 43.850164 ], "pop" : 7779, "state" : "MI" }
+{ "_id" : "48634", "city" : "LINWOOD", "loc" : [ -84.013341, 43.737448 ], "pop" : 4719, "state" : "MI" }
+{ "_id" : "48635", "city" : "LUPTON", "loc" : [ -83.99047299999999, 44.397578 ], "pop" : 1784, "state" : "MI" }
+{ "_id" : "48636", "city" : "LUZERNE", "loc" : [ -84.246742, 44.629594 ], "pop" : 744, "state" : "MI" }
+{ "_id" : "48637", "city" : "MERRILL", "loc" : [ -84.33075700000001, 43.393892 ], "pop" : 2702, "state" : "MI" }
+{ "_id" : "48640", "city" : "MIDLAND", "loc" : [ -84.26796, 43.637562 ], "pop" : 26370, "state" : "MI" }
+{ "_id" : "48642", "city" : "MIDLAND", "loc" : [ -84.197941, 43.637488 ], "pop" : 24643, "state" : "MI" }
+{ "_id" : "48647", "city" : "MIO", "loc" : [ -84.13526400000001, 44.666481 ], "pop" : 3508, "state" : "MI" }
+{ "_id" : "48649", "city" : "OAKLEY", "loc" : [ -84.209379, 43.150533 ], "pop" : 3506, "state" : "MI" }
+{ "_id" : "48650", "city" : "PINCONNING", "loc" : [ -84.008162, 43.849079 ], "pop" : 8659, "state" : "MI" }
+{ "_id" : "48651", "city" : "PRUDENVILLE", "loc" : [ -84.662747, 44.297394 ], "pop" : 4484, "state" : "MI" }
+{ "_id" : "48652", "city" : "RHODES", "loc" : [ -84.213402, 43.851745 ], "pop" : 2034, "state" : "MI" }
+{ "_id" : "48653", "city" : "ROSCOMMON", "loc" : [ -84.66009200000001, 44.483908 ], "pop" : 8311, "state" : "MI" }
+{ "_id" : "48654", "city" : "ROSE CITY", "loc" : [ -84.125562, 44.41672 ], "pop" : 2962, "state" : "MI" }
+{ "_id" : "48655", "city" : "SAINT CHARLES", "loc" : [ -84.159785, 43.286271 ], "pop" : 6272, "state" : "MI" }
+{ "_id" : "48656", "city" : "SAINT HELEN", "loc" : [ -84.42470400000001, 44.366489 ], "pop" : 3686, "state" : "MI" }
+{ "_id" : "48657", "city" : "SANFORD", "loc" : [ -84.39544600000001, 43.720352 ], "pop" : 5154, "state" : "MI" }
+{ "_id" : "48658", "city" : "STANDISH", "loc" : [ -83.943297, 43.973287 ], "pop" : 5314, "state" : "MI" }
+{ "_id" : "48659", "city" : "STERLING", "loc" : [ -84.012567, 44.067837 ], "pop" : 2855, "state" : "MI" }
+{ "_id" : "48661", "city" : "WEST BRANCH", "loc" : [ -84.228623, 44.279032 ], "pop" : 7739, "state" : "MI" }
+{ "_id" : "48662", "city" : "WHEELER", "loc" : [ -84.424335, 43.396224 ], "pop" : 2144, "state" : "MI" }
+{ "_id" : "48701", "city" : "AKRON", "loc" : [ -83.53926199999999, 43.584373 ], "pop" : 1694, "state" : "MI" }
+{ "_id" : "48703", "city" : "AU GRES", "loc" : [ -83.70202399999999, 44.033802 ], "pop" : 1568, "state" : "MI" }
+{ "_id" : "48705", "city" : "BARTON CITY", "loc" : [ -83.599372, 44.701956 ], "pop" : 755, "state" : "MI" }
+{ "_id" : "48706", "city" : "UNIVERSITY CENTE", "loc" : [ -83.91988499999999, 43.612165 ], "pop" : 41677, "state" : "MI" }
+{ "_id" : "48708", "city" : "BAY CITY", "loc" : [ -83.878073, 43.58205 ], "pop" : 29918, "state" : "MI" }
+{ "_id" : "48720", "city" : "BAY PORT", "loc" : [ -83.35246100000001, 43.837744 ], "pop" : 1693, "state" : "MI" }
+{ "_id" : "48721", "city" : "BLACK RIVER", "loc" : [ -83.34071, 44.813842 ], "pop" : 373, "state" : "MI" }
+{ "_id" : "48722", "city" : "BRIDGEPORT", "loc" : [ -83.854906, 43.355309 ], "pop" : 3792, "state" : "MI" }
+{ "_id" : "48723", "city" : "CARO", "loc" : [ -83.38346900000001, 43.483272 ], "pop" : 11389, "state" : "MI" }
+{ "_id" : "48725", "city" : "CASEVILLE", "loc" : [ -83.265924, 43.94292 ], "pop" : 2939, "state" : "MI" }
+{ "_id" : "48726", "city" : "CASS CITY", "loc" : [ -83.173264, 43.579677 ], "pop" : 7414, "state" : "MI" }
+{ "_id" : "48727", "city" : "CLIFFORD", "loc" : [ -83.174105, 43.309953 ], "pop" : 1444, "state" : "MI" }
+{ "_id" : "48728", "city" : "CURRAN", "loc" : [ -83.83198899999999, 44.733606 ], "pop" : 188, "state" : "MI" }
+{ "_id" : "48729", "city" : "DEFORD", "loc" : [ -83.170244, 43.473482 ], "pop" : 556, "state" : "MI" }
+{ "_id" : "48730", "city" : "EAST TAWAS", "loc" : [ -83.47762899999999, 44.300823 ], "pop" : 5006, "state" : "MI" }
+{ "_id" : "48731", "city" : "ELKTON", "loc" : [ -83.178642, 43.834437 ], "pop" : 2292, "state" : "MI" }
+{ "_id" : "48732", "city" : "ESSEXVILLE", "loc" : [ -83.821659, 43.606908 ], "pop" : 12019, "state" : "MI" }
+{ "_id" : "48733", "city" : "FAIRGROVE", "loc" : [ -83.583534, 43.512574 ], "pop" : 3175, "state" : "MI" }
+{ "_id" : "48734", "city" : "FRANKENMUTH", "loc" : [ -83.74748200000001, 43.340965 ], "pop" : 6931, "state" : "MI" }
+{ "_id" : "48735", "city" : "GAGETOWN", "loc" : [ -83.262788, 43.654251 ], "pop" : 759, "state" : "MI" }
+{ "_id" : "48737", "city" : "GLENNIE", "loc" : [ -83.689948, 44.558234 ], "pop" : 1153, "state" : "MI" }
+{ "_id" : "48738", "city" : "GREENBUSH", "loc" : [ -83.326883, 44.548044 ], "pop" : 1121, "state" : "MI" }
+{ "_id" : "48739", "city" : "HALE", "loc" : [ -83.83594100000001, 44.38189 ], "pop" : 3317, "state" : "MI" }
+{ "_id" : "48740", "city" : "HARRISVILLE", "loc" : [ -83.34242999999999, 44.654595 ], "pop" : 2250, "state" : "MI" }
+{ "_id" : "48741", "city" : "KINGSTON", "loc" : [ -83.184727, 43.398153 ], "pop" : 2475, "state" : "MI" }
+{ "_id" : "48742", "city" : "LINCOLN", "loc" : [ -83.39466899999999, 44.711124 ], "pop" : 1167, "state" : "MI" }
+{ "_id" : "48743", "city" : "LONG LAKE", "loc" : [ -83.817058, 44.448465 ], "pop" : 349, "state" : "MI" }
+{ "_id" : "48744", "city" : "MAYVILLE", "loc" : [ -83.372529, 43.356156 ], "pop" : 4271, "state" : "MI" }
+{ "_id" : "48745", "city" : "MIKADO", "loc" : [ -83.435518, 44.583275 ], "pop" : 1392, "state" : "MI" }
+{ "_id" : "48746", "city" : "MILLINGTON", "loc" : [ -83.561944, 43.271772 ], "pop" : 8752, "state" : "MI" }
+{ "_id" : "48747", "city" : "MUNGER", "loc" : [ -83.76722100000001, 43.528585 ], "pop" : 1898, "state" : "MI" }
+{ "_id" : "48748", "city" : "NATIONAL CITY", "loc" : [ -83.683948, 44.313746 ], "pop" : 1823, "state" : "MI" }
+{ "_id" : "48749", "city" : "OMER", "loc" : [ -83.842956, 44.049939 ], "pop" : 965, "state" : "MI" }
+{ "_id" : "48750", "city" : "OSCODA", "loc" : [ -83.361908, 44.446485 ], "pop" : 14188, "state" : "MI" }
+{ "_id" : "48754", "city" : "OWENDALE", "loc" : [ -83.23070300000001, 43.720648 ], "pop" : 1833, "state" : "MI" }
+{ "_id" : "48755", "city" : "PIGEON", "loc" : [ -83.275508, 43.817909 ], "pop" : 1891, "state" : "MI" }
+{ "_id" : "48756", "city" : "PRESCOTT", "loc" : [ -84.021197, 44.20999 ], "pop" : 4816, "state" : "MI" }
+{ "_id" : "48757", "city" : "REESE", "loc" : [ -83.70152899999999, 43.453094 ], "pop" : 2830, "state" : "MI" }
+{ "_id" : "48759", "city" : "SEBEWAING", "loc" : [ -83.436622, 43.728888 ], "pop" : 3203, "state" : "MI" }
+{ "_id" : "48760", "city" : "SILVERWOOD", "loc" : [ -83.271974, 43.31413 ], "pop" : 964, "state" : "MI" }
+{ "_id" : "48761", "city" : "SOUTH BRANCH", "loc" : [ -83.868574, 44.501403 ], "pop" : 968, "state" : "MI" }
+{ "_id" : "48762", "city" : "SPRUCE", "loc" : [ -83.504391, 44.822443 ], "pop" : 1531, "state" : "MI" }
+{ "_id" : "48763", "city" : "TAWAS CITY", "loc" : [ -83.544905, 44.267485 ], "pop" : 3868, "state" : "MI" }
+{ "_id" : "48765", "city" : "TURNER", "loc" : [ -83.650679, 44.10543 ], "pop" : 2664, "state" : "MI" }
+{ "_id" : "48766", "city" : "TWINING", "loc" : [ -83.849118, 44.12929 ], "pop" : 934, "state" : "MI" }
+{ "_id" : "48767", "city" : "UNIONVILLE", "loc" : [ -83.469898, 43.647341 ], "pop" : 2111, "state" : "MI" }
+{ "_id" : "48768", "city" : "VASSAR", "loc" : [ -83.58444900000001, 43.369052 ], "pop" : 9979, "state" : "MI" }
+{ "_id" : "48770", "city" : "WHITTEMORE", "loc" : [ -83.806842, 44.232514 ], "pop" : 1754, "state" : "MI" }
+{ "_id" : "48801", "city" : "ALMA", "loc" : [ -84.663484, 43.380877 ], "pop" : 11018, "state" : "MI" }
+{ "_id" : "48806", "city" : "ASHLEY", "loc" : [ -84.48796, 43.189103 ], "pop" : 2278, "state" : "MI" }
+{ "_id" : "48807", "city" : "BANNISTER", "loc" : [ -84.359679, 43.161537 ], "pop" : 1499, "state" : "MI" }
+{ "_id" : "48808", "city" : "BATH", "loc" : [ -84.45454700000001, 42.820563 ], "pop" : 3695, "state" : "MI" }
+{ "_id" : "48809", "city" : "BELDING", "loc" : [ -85.231272, 43.088546 ], "pop" : 8995, "state" : "MI" }
+{ "_id" : "48811", "city" : "CARSON CITY", "loc" : [ -84.865334, 43.169496 ], "pop" : 4190, "state" : "MI" }
+{ "_id" : "48813", "city" : "CHARLOTTE", "loc" : [ -84.83518100000001, 42.570169 ], "pop" : 17424, "state" : "MI" }
+{ "_id" : "48815", "city" : "CLARKSVILLE", "loc" : [ -85.24938400000001, 42.830177 ], "pop" : 2027, "state" : "MI" }
+{ "_id" : "48817", "city" : "CORUNNA", "loc" : [ -84.027618, 43.041402 ], "pop" : 3906, "state" : "MI" }
+{ "_id" : "48818", "city" : "CRYSTAL", "loc" : [ -84.899328, 43.262382 ], "pop" : 2279, "state" : "MI" }
+{ "_id" : "48819", "city" : "DANSVILLE", "loc" : [ -84.293932, 42.550485 ], "pop" : 2338, "state" : "MI" }
+{ "_id" : "48820", "city" : "DEWITT", "loc" : [ -84.579654, 42.842784 ], "pop" : 10811, "state" : "MI" }
+{ "_id" : "48821", "city" : "DIMONDALE", "loc" : [ -84.64859300000001, 42.650094 ], "pop" : 5131, "state" : "MI" }
+{ "_id" : "48822", "city" : "EAGLE", "loc" : [ -84.758971, 42.826306 ], "pop" : 1937, "state" : "MI" }
+{ "_id" : "48823", "city" : "EAST LANSING", "loc" : [ -84.476409, 42.738805 ], "pop" : 61997, "state" : "MI" }
+{ "_id" : "48827", "city" : "EATON RAPIDS", "loc" : [ -84.65654499999999, 42.516624 ], "pop" : 12987, "state" : "MI" }
+{ "_id" : "48829", "city" : "EDMORE", "loc" : [ -85.028003, 43.411578 ], "pop" : 2515, "state" : "MI" }
+{ "_id" : "48831", "city" : "CARLAND", "loc" : [ -84.39096499999999, 43.086918 ], "pop" : 2487, "state" : "MI" }
+{ "_id" : "48832", "city" : "ELWELL", "loc" : [ -84.763103, 43.410565 ], "pop" : 1006, "state" : "MI" }
+{ "_id" : "48834", "city" : "FENWICK", "loc" : [ -85.06656599999999, 43.149682 ], "pop" : 1440, "state" : "MI" }
+{ "_id" : "48835", "city" : "FOWLER", "loc" : [ -84.759969, 42.994144 ], "pop" : 2253, "state" : "MI" }
+{ "_id" : "48836", "city" : "FOWLERVILLE", "loc" : [ -84.072085, 42.661438 ], "pop" : 8519, "state" : "MI" }
+{ "_id" : "48837", "city" : "GRAND LEDGE", "loc" : [ -84.737314, 42.752924 ], "pop" : 16000, "state" : "MI" }
+{ "_id" : "48838", "city" : "GREENVILLE", "loc" : [ -85.24970500000001, 43.17926 ], "pop" : 12208, "state" : "MI" }
+{ "_id" : "48840", "city" : "HASLETT", "loc" : [ -84.398887, 42.753088 ], "pop" : 10679, "state" : "MI" }
+{ "_id" : "48841", "city" : "HENDERSON", "loc" : [ -84.185777, 43.081708 ], "pop" : 534, "state" : "MI" }
+{ "_id" : "48842", "city" : "HOLT", "loc" : [ -84.524232, 42.639401 ], "pop" : 15960, "state" : "MI" }
+{ "_id" : "48843", "city" : "HOWELL", "loc" : [ -83.92480999999999, 42.615933 ], "pop" : 28075, "state" : "MI" }
+{ "_id" : "48845", "city" : "HUBBARDSTON", "loc" : [ -84.81728200000001, 43.082776 ], "pop" : 1407, "state" : "MI" }
+{ "_id" : "48846", "city" : "IONIA", "loc" : [ -85.07098499999999, 42.98592 ], "pop" : 18602, "state" : "MI" }
+{ "_id" : "48847", "city" : "ITHACA", "loc" : [ -84.60883, 43.282808 ], "pop" : 6418, "state" : "MI" }
+{ "_id" : "48848", "city" : "LAINGSBURG", "loc" : [ -84.352991, 42.86271 ], "pop" : 8214, "state" : "MI" }
+{ "_id" : "48849", "city" : "LAKE ODESSA", "loc" : [ -85.135667, 42.786335 ], "pop" : 5386, "state" : "MI" }
+{ "_id" : "48850", "city" : "LAKEVIEW", "loc" : [ -85.292421, 43.42694 ], "pop" : 6000, "state" : "MI" }
+{ "_id" : "48851", "city" : "LYONS", "loc" : [ -84.92094299999999, 42.963429 ], "pop" : 2488, "state" : "MI" }
+{ "_id" : "48854", "city" : "MASON", "loc" : [ -84.45609, 42.579588 ], "pop" : 17286, "state" : "MI" }
+{ "_id" : "48856", "city" : "MIDDLETON", "loc" : [ -84.75522100000001, 43.168911 ], "pop" : 1181, "state" : "MI" }
+{ "_id" : "48857", "city" : "MORRICE", "loc" : [ -84.176771, 42.83851 ], "pop" : 718, "state" : "MI" }
+{ "_id" : "48858", "city" : "MOUNT PLEASANT", "loc" : [ -84.773571, 43.601295 ], "pop" : 33732, "state" : "MI" }
+{ "_id" : "48860", "city" : "MUIR", "loc" : [ -84.93908999999999, 43.043864 ], "pop" : 1885, "state" : "MI" }
+{ "_id" : "48861", "city" : "MULLIKEN", "loc" : [ -84.89791099999999, 42.737657 ], "pop" : 1903, "state" : "MI" }
+{ "_id" : "48864", "city" : "OKEMOS", "loc" : [ -84.418696, 42.705341 ], "pop" : 17587, "state" : "MI" }
+{ "_id" : "48865", "city" : "ORLEANS", "loc" : [ -85.116547, 43.089459 ], "pop" : 1678, "state" : "MI" }
+{ "_id" : "48866", "city" : "OVID", "loc" : [ -84.36493900000001, 42.996927 ], "pop" : 5004, "state" : "MI" }
+{ "_id" : "48867", "city" : "OWOSSO", "loc" : [ -84.159486, 42.993407 ], "pop" : 29958, "state" : "MI" }
+{ "_id" : "48871", "city" : "PERRINTON", "loc" : [ -84.66598399999999, 43.16492 ], "pop" : 1791, "state" : "MI" }
+{ "_id" : "48872", "city" : "PERRY", "loc" : [ -84.231346, 42.820012 ], "pop" : 5746, "state" : "MI" }
+{ "_id" : "48873", "city" : "PEWAMO", "loc" : [ -84.849217, 43.000747 ], "pop" : 654, "state" : "MI" }
+{ "_id" : "48875", "city" : "PORTLAND", "loc" : [ -84.913933, 42.862414 ], "pop" : 8824, "state" : "MI" }
+{ "_id" : "48876", "city" : "POTTERVILLE", "loc" : [ -84.734589, 42.639779 ], "pop" : 2795, "state" : "MI" }
+{ "_id" : "48877", "city" : "RIVERDALE", "loc" : [ -84.826607, 43.409817 ], "pop" : 1211, "state" : "MI" }
+{ "_id" : "48878", "city" : "ROSEBUSH", "loc" : [ -84.783299, 43.68427 ], "pop" : 2025, "state" : "MI" }
+{ "_id" : "48879", "city" : "SAINT JOHNS", "loc" : [ -84.571934, 43.005924 ], "pop" : 16472, "state" : "MI" }
+{ "_id" : "48880", "city" : "SAINT LOUIS", "loc" : [ -84.59523900000001, 43.42777 ], "pop" : 7552, "state" : "MI" }
+{ "_id" : "48881", "city" : "SARANAC", "loc" : [ -85.229938, 42.928534 ], "pop" : 5911, "state" : "MI" }
+{ "_id" : "48883", "city" : "SHEPHERD", "loc" : [ -84.587317, 43.565668 ], "pop" : 17397, "state" : "MI" }
+{ "_id" : "48884", "city" : "SHERIDAN", "loc" : [ -85.04683799999999, 43.212632 ], "pop" : 3030, "state" : "MI" }
+{ "_id" : "48885", "city" : "SIDNEY", "loc" : [ -85.120671, 43.23579 ], "pop" : 642, "state" : "MI" }
+{ "_id" : "48886", "city" : "SIX LAKES", "loc" : [ -85.141569, 43.433714 ], "pop" : 2132, "state" : "MI" }
+{ "_id" : "48888", "city" : "STANTON", "loc" : [ -85.099548, 43.305841 ], "pop" : 6997, "state" : "MI" }
+{ "_id" : "48889", "city" : "SUMNER", "loc" : [ -84.790662, 43.309144 ], "pop" : 2771, "state" : "MI" }
+{ "_id" : "48890", "city" : "SUNFIELD", "loc" : [ -84.98130500000001, 42.769314 ], "pop" : 2282, "state" : "MI" }
+{ "_id" : "48891", "city" : "VESTABURG", "loc" : [ -84.908168, 43.387025 ], "pop" : 3540, "state" : "MI" }
+{ "_id" : "48892", "city" : "WEBBERVILLE", "loc" : [ -84.17013, 42.662981 ], "pop" : 4561, "state" : "MI" }
+{ "_id" : "48893", "city" : "WEIDMAN", "loc" : [ -85.00456699999999, 43.645284 ], "pop" : 708, "state" : "MI" }
+{ "_id" : "48894", "city" : "WESTPHALIA", "loc" : [ -84.785567, 42.912308 ], "pop" : 2099, "state" : "MI" }
+{ "_id" : "48895", "city" : "WILLIAMSTON", "loc" : [ -84.292596, 42.696652 ], "pop" : 9270, "state" : "MI" }
+{ "_id" : "48897", "city" : "WOODLAND", "loc" : [ -85.13261, 42.705654 ], "pop" : 1405, "state" : "MI" }
+{ "_id" : "48906", "city" : "LANSING", "loc" : [ -84.558043, 42.763464 ], "pop" : 28434, "state" : "MI" }
+{ "_id" : "48910", "city" : "LANSING", "loc" : [ -84.54900499999999, 42.700784 ], "pop" : 37654, "state" : "MI" }
+{ "_id" : "48911", "city" : "LANSING", "loc" : [ -84.577168, 42.679727 ], "pop" : 39930, "state" : "MI" }
+{ "_id" : "48912", "city" : "LANSING", "loc" : [ -84.52441399999999, 42.737115 ], "pop" : 19898, "state" : "MI" }
+{ "_id" : "48915", "city" : "LANSING", "loc" : [ -84.570398, 42.739074 ], "pop" : 11703, "state" : "MI" }
+{ "_id" : "48917", "city" : "LANSING", "loc" : [ -84.62439000000001, 42.737621 ], "pop" : 28475, "state" : "MI" }
+{ "_id" : "48933", "city" : "LANSING", "loc" : [ -84.557142, 42.733429 ], "pop" : 2780, "state" : "MI" }
+{ "_id" : "49001", "city" : "KALAMAZOO", "loc" : [ -85.545653, 42.273565 ], "pop" : 45278, "state" : "MI" }
+{ "_id" : "49002", "city" : "KALAMAZOO", "loc" : [ -85.595691, 42.207482 ], "pop" : 40439, "state" : "MI" }
+{ "_id" : "49004", "city" : "PARCHMENT", "loc" : [ -85.54195900000001, 42.326538 ], "pop" : 15968, "state" : "MI" }
+{ "_id" : "49007", "city" : "KALAMAZOO", "loc" : [ -85.613722, 42.295688 ], "pop" : 44854, "state" : "MI" }
+{ "_id" : "49008", "city" : "KALAMAZOO", "loc" : [ -85.609645, 42.262432 ], "pop" : 19435, "state" : "MI" }
+{ "_id" : "49009", "city" : "KALAMAZOO", "loc" : [ -85.686333, 42.280947 ], "pop" : 22218, "state" : "MI" }
+{ "_id" : "49010", "city" : "ALLEGAN", "loc" : [ -85.86608, 42.525609 ], "pop" : 15532, "state" : "MI" }
+{ "_id" : "49011", "city" : "ATHENS", "loc" : [ -85.231742, 42.102962 ], "pop" : 2436, "state" : "MI" }
+{ "_id" : "49012", "city" : "AUGUSTA", "loc" : [ -85.354012, 42.356313 ], "pop" : 2896, "state" : "MI" }
+{ "_id" : "49013", "city" : "BANGOR", "loc" : [ -86.131096, 42.33122 ], "pop" : 8743, "state" : "MI" }
+{ "_id" : "49015", "city" : "BATTLE CREEK", "loc" : [ -85.212825, 42.302806 ], "pop" : 29828, "state" : "MI" }
+{ "_id" : "49017", "city" : "BATTLE CREEK", "loc" : [ -85.181106, 42.332218 ], "pop" : 62035, "state" : "MI" }
+{ "_id" : "49021", "city" : "BELLEVUE", "loc" : [ -85.048867, 42.452474 ], "pop" : 6911, "state" : "MI" }
+{ "_id" : "49022", "city" : "BENTON HARBOR", "loc" : [ -86.423417, 42.108594 ], "pop" : 37550, "state" : "MI" }
+{ "_id" : "49026", "city" : "BLOOMINGDALE", "loc" : [ -85.956757, 42.384232 ], "pop" : 1958, "state" : "MI" }
+{ "_id" : "49028", "city" : "BRONSON", "loc" : [ -85.183767, 41.864316 ], "pop" : 7024, "state" : "MI" }
+{ "_id" : "49029", "city" : "BURLINGTON", "loc" : [ -85.105, 42.123859 ], "pop" : 1898, "state" : "MI" }
+{ "_id" : "49030", "city" : "BURR OAK", "loc" : [ -85.334536, 41.845898 ], "pop" : 3192, "state" : "MI" }
+{ "_id" : "49031", "city" : "CASSOPOLIS", "loc" : [ -85.992273, 41.896805 ], "pop" : 6622, "state" : "MI" }
+{ "_id" : "49032", "city" : "CENTREVILLE", "loc" : [ -85.49629899999999, 41.921685 ], "pop" : 3606, "state" : "MI" }
+{ "_id" : "49033", "city" : "CERESCO", "loc" : [ -85.11284999999999, 42.212741 ], "pop" : 1128, "state" : "MI" }
+{ "_id" : "49034", "city" : "CLIMAX", "loc" : [ -85.323832, 42.233979 ], "pop" : 983, "state" : "MI" }
+{ "_id" : "49036", "city" : "COLDWATER", "loc" : [ -85.00568199999999, 41.925464 ], "pop" : 20278, "state" : "MI" }
+{ "_id" : "49038", "city" : "COLOMA", "loc" : [ -86.32247, 42.202952 ], "pop" : 9987, "state" : "MI" }
+{ "_id" : "49040", "city" : "COLON", "loc" : [ -85.33058800000001, 41.957605 ], "pop" : 2800, "state" : "MI" }
+{ "_id" : "49042", "city" : "CONSTANTINE", "loc" : [ -85.657094, 41.846029 ], "pop" : 5737, "state" : "MI" }
+{ "_id" : "49043", "city" : "COVERT", "loc" : [ -86.274294, 42.291074 ], "pop" : 2544, "state" : "MI" }
+{ "_id" : "49045", "city" : "DECATUR", "loc" : [ -86.03380799999999, 42.101219 ], "pop" : 8320, "state" : "MI" }
+{ "_id" : "49046", "city" : "DELTON", "loc" : [ -85.406706, 42.514102 ], "pop" : 7306, "state" : "MI" }
+{ "_id" : "49047", "city" : "DOWAGIAC", "loc" : [ -86.116766, 41.990965 ], "pop" : 14921, "state" : "MI" }
+{ "_id" : "49050", "city" : "DOWLING", "loc" : [ -85.24945200000001, 42.501478 ], "pop" : 909, "state" : "MI" }
+{ "_id" : "49051", "city" : "EAST LEROY", "loc" : [ -85.231083, 42.196125 ], "pop" : 1915, "state" : "MI" }
+{ "_id" : "49052", "city" : "FULTON", "loc" : [ -85.322659, 42.139086 ], "pop" : 720, "state" : "MI" }
+{ "_id" : "49053", "city" : "GALESBURG", "loc" : [ -85.423665, 42.294843 ], "pop" : 4820, "state" : "MI" }
+{ "_id" : "49055", "city" : "GOBLES", "loc" : [ -85.853649, 42.370182 ], "pop" : 4476, "state" : "MI" }
+{ "_id" : "49056", "city" : "GRAND JUNCTION", "loc" : [ -86.054052, 42.376081 ], "pop" : 2100, "state" : "MI" }
+{ "_id" : "49057", "city" : "HARTFORD", "loc" : [ -86.16870299999999, 42.208807 ], "pop" : 5826, "state" : "MI" }
+{ "_id" : "49058", "city" : "HASTINGS", "loc" : [ -85.29368700000001, 42.643007 ], "pop" : 15043, "state" : "MI" }
+{ "_id" : "49060", "city" : "HICKORY CORNERS", "loc" : [ -85.399784, 42.423682 ], "pop" : 1823, "state" : "MI" }
+{ "_id" : "49061", "city" : "JONES", "loc" : [ -85.83411099999999, 41.912903 ], "pop" : 2121, "state" : "MI" }
+{ "_id" : "49064", "city" : "LAWRENCE", "loc" : [ -86.052543, 42.207635 ], "pop" : 3030, "state" : "MI" }
+{ "_id" : "49065", "city" : "LAWTON", "loc" : [ -85.82896599999999, 42.154462 ], "pop" : 5933, "state" : "MI" }
+{ "_id" : "49066", "city" : "LEONIDAS", "loc" : [ -85.349683, 42.029394 ], "pop" : 765, "state" : "MI" }
+{ "_id" : "49067", "city" : "MARCELLUS", "loc" : [ -85.798776, 42.027461 ], "pop" : 3481, "state" : "MI" }
+{ "_id" : "49068", "city" : "MARSHALL", "loc" : [ -84.95828, 42.272047 ], "pop" : 14844, "state" : "MI" }
+{ "_id" : "49070", "city" : "MARTIN", "loc" : [ -85.610646, 42.548321 ], "pop" : 2366, "state" : "MI" }
+{ "_id" : "49071", "city" : "MATTAWAN", "loc" : [ -85.794281, 42.245069 ], "pop" : 6461, "state" : "MI" }
+{ "_id" : "49072", "city" : "MENDON", "loc" : [ -85.472697, 42.014262 ], "pop" : 3598, "state" : "MI" }
+{ "_id" : "49073", "city" : "NASHVILLE", "loc" : [ -85.122029, 42.593721 ], "pop" : 5517, "state" : "MI" }
+{ "_id" : "49076", "city" : "OLIVET", "loc" : [ -84.897312, 42.445947 ], "pop" : 4084, "state" : "MI" }
+{ "_id" : "49078", "city" : "OTSEGO", "loc" : [ -85.703497, 42.472334 ], "pop" : 10614, "state" : "MI" }
+{ "_id" : "49079", "city" : "PAW PAW", "loc" : [ -85.900488, 42.234931 ], "pop" : 11455, "state" : "MI" }
+{ "_id" : "49080", "city" : "PLAINWELL", "loc" : [ -85.59936, 42.454379 ], "pop" : 15308, "state" : "MI" }
+{ "_id" : "49082", "city" : "QUINCY", "loc" : [ -84.849295, 41.970694 ], "pop" : 8671, "state" : "MI" }
+{ "_id" : "49083", "city" : "RICHLAND", "loc" : [ -85.44465099999999, 42.375689 ], "pop" : 5676, "state" : "MI" }
+{ "_id" : "49085", "city" : "SAINT JOSEPH", "loc" : [ -86.478341, 42.063959 ], "pop" : 22984, "state" : "MI" }
+{ "_id" : "49087", "city" : "SCHOOLCRAFT", "loc" : [ -85.663741, 42.132857 ], "pop" : 5324, "state" : "MI" }
+{ "_id" : "49088", "city" : "SCOTTS", "loc" : [ -85.468492, 42.181892 ], "pop" : 3249, "state" : "MI" }
+{ "_id" : "49089", "city" : "SHERWOOD", "loc" : [ -85.240797, 42.010736 ], "pop" : 2310, "state" : "MI" }
+{ "_id" : "49090", "city" : "SOUTH HAVEN", "loc" : [ -86.25420699999999, 42.404096 ], "pop" : 12604, "state" : "MI" }
+{ "_id" : "49091", "city" : "STURGIS", "loc" : [ -85.426357, 41.808934 ], "pop" : 16597, "state" : "MI" }
+{ "_id" : "49092", "city" : "TEKONSHA", "loc" : [ -84.99260200000001, 42.086326 ], "pop" : 2747, "state" : "MI" }
+{ "_id" : "49093", "city" : "THREE RIVERS", "loc" : [ -85.637125, 41.959598 ], "pop" : 17021, "state" : "MI" }
+{ "_id" : "49094", "city" : "UNION CITY", "loc" : [ -85.135637, 42.055134 ], "pop" : 3600, "state" : "MI" }
+{ "_id" : "49095", "city" : "VANDALIA", "loc" : [ -85.875546, 41.895506 ], "pop" : 1839, "state" : "MI" }
+{ "_id" : "49096", "city" : "VERMONTVILLE", "loc" : [ -85.01098399999999, 42.63921 ], "pop" : 2978, "state" : "MI" }
+{ "_id" : "49097", "city" : "VICKSBURG", "loc" : [ -85.502376, 42.120896 ], "pop" : 8152, "state" : "MI" }
+{ "_id" : "49098", "city" : "WATERVLIET", "loc" : [ -86.26036999999999, 42.193804 ], "pop" : 4793, "state" : "MI" }
+{ "_id" : "49099", "city" : "WHITE PIGEON", "loc" : [ -85.67501, 41.792891 ], "pop" : 6161, "state" : "MI" }
+{ "_id" : "49101", "city" : "BARODA", "loc" : [ -86.491274, 41.948818 ], "pop" : 3030, "state" : "MI" }
+{ "_id" : "49102", "city" : "BERRIEN CENTER", "loc" : [ -86.285039, 41.948439 ], "pop" : 2324, "state" : "MI" }
+{ "_id" : "49103", "city" : "BERRIEN SPRINGS", "loc" : [ -86.35401299999999, 41.948002 ], "pop" : 11600, "state" : "MI" }
+{ "_id" : "49106", "city" : "BRIDGMAN", "loc" : [ -86.554334, 41.936199 ], "pop" : 4073, "state" : "MI" }
+{ "_id" : "49107", "city" : "BUCHANAN", "loc" : [ -86.37084400000001, 41.83269 ], "pop" : 10342, "state" : "MI" }
+{ "_id" : "49111", "city" : "EAU CLAIRE", "loc" : [ -86.29715400000001, 42.015134 ], "pop" : 4007, "state" : "MI" }
+{ "_id" : "49112", "city" : "EDWARDSBURG", "loc" : [ -86.026252, 41.791258 ], "pop" : 8926, "state" : "MI" }
+{ "_id" : "49113", "city" : "GALIEN", "loc" : [ -86.50354400000001, 41.819758 ], "pop" : 2775, "state" : "MI" }
+{ "_id" : "49116", "city" : "LAKESIDE", "loc" : [ -86.669354, 41.848459 ], "pop" : 269, "state" : "MI" }
+{ "_id" : "49117", "city" : "GRAND BEACH", "loc" : [ -86.74663, 41.785591 ], "pop" : 4389, "state" : "MI" }
+{ "_id" : "49120", "city" : "NILES", "loc" : [ -86.236789, 41.820168 ], "pop" : 33750, "state" : "MI" }
+{ "_id" : "49125", "city" : "SAWYER", "loc" : [ -86.588508, 41.882866 ], "pop" : 2704, "state" : "MI" }
+{ "_id" : "49126", "city" : "SODUS", "loc" : [ -86.3921, 42.052082 ], "pop" : 1404, "state" : "MI" }
+{ "_id" : "49127", "city" : "STEVENSVILLE", "loc" : [ -86.51186199999999, 42.021968 ], "pop" : 9354, "state" : "MI" }
+{ "_id" : "49128", "city" : "THREE OAKS", "loc" : [ -86.61541099999999, 41.814976 ], "pop" : 3994, "state" : "MI" }
+{ "_id" : "49129", "city" : "UNION PIER", "loc" : [ -86.691146, 41.82555 ], "pop" : 979, "state" : "MI" }
+{ "_id" : "49130", "city" : "UNION", "loc" : [ -85.85290500000001, 41.782678 ], "pop" : 1617, "state" : "MI" }
+{ "_id" : "49201", "city" : "JACKSON", "loc" : [ -84.38747600000001, 42.254522 ], "pop" : 42076, "state" : "MI" }
+{ "_id" : "49202", "city" : "JACKSON", "loc" : [ -84.408348, 42.263431 ], "pop" : 20387, "state" : "MI" }
+{ "_id" : "49203", "city" : "JACKSON", "loc" : [ -84.41321000000001, 42.228963 ], "pop" : 38466, "state" : "MI" }
+{ "_id" : "49220", "city" : "ADDISON", "loc" : [ -84.312229, 42.003604 ], "pop" : 2506, "state" : "MI" }
+{ "_id" : "49221", "city" : "ADRIAN", "loc" : [ -84.044556, 41.900516 ], "pop" : 33769, "state" : "MI" }
+{ "_id" : "49224", "city" : "ALBION", "loc" : [ -84.756052, 42.258073 ], "pop" : 13514, "state" : "MI" }
+{ "_id" : "49227", "city" : "ALLEN", "loc" : [ -84.76078200000001, 41.926419 ], "pop" : 1953, "state" : "MI" }
+{ "_id" : "49228", "city" : "BLISSFIELD", "loc" : [ -83.877257, 41.827636 ], "pop" : 5635, "state" : "MI" }
+{ "_id" : "49229", "city" : "BRITTON", "loc" : [ -83.837722, 41.988713 ], "pop" : 2553, "state" : "MI" }
+{ "_id" : "49230", "city" : "BROOKLYN", "loc" : [ -84.241353, 42.10436 ], "pop" : 7155, "state" : "MI" }
+{ "_id" : "49232", "city" : "CAMDEN", "loc" : [ -84.724497, 41.736149 ], "pop" : 1500, "state" : "MI" }
+{ "_id" : "49233", "city" : "CEMENT CITY", "loc" : [ -84.325423, 42.060395 ], "pop" : 1313, "state" : "MI" }
+{ "_id" : "49234", "city" : "CLARKLAKE", "loc" : [ -84.352056, 42.123503 ], "pop" : 2418, "state" : "MI" }
+{ "_id" : "49235", "city" : "CLAYTON", "loc" : [ -84.177519, 41.868648 ], "pop" : 2000, "state" : "MI" }
+{ "_id" : "49236", "city" : "CLINTON", "loc" : [ -83.944152, 42.063886 ], "pop" : 5222, "state" : "MI" }
+{ "_id" : "49237", "city" : "CONCORD", "loc" : [ -84.652928, 42.187501 ], "pop" : 3375, "state" : "MI" }
+{ "_id" : "49238", "city" : "DEERFIELD", "loc" : [ -83.784739, 41.890912 ], "pop" : 1427, "state" : "MI" }
+{ "_id" : "49240", "city" : "GRASS LAKE", "loc" : [ -84.194041, 42.271071 ], "pop" : 6321, "state" : "MI" }
+{ "_id" : "49241", "city" : "HANOVER", "loc" : [ -84.58480900000001, 42.102521 ], "pop" : 2809, "state" : "MI" }
+{ "_id" : "49242", "city" : "HILLSDALE", "loc" : [ -84.620812, 41.923954 ], "pop" : 10382, "state" : "MI" }
+{ "_id" : "49245", "city" : "HOMER", "loc" : [ -84.81572, 42.141561 ], "pop" : 4934, "state" : "MI" }
+{ "_id" : "49246", "city" : "HORTON", "loc" : [ -84.49759299999999, 42.119092 ], "pop" : 3099, "state" : "MI" }
+{ "_id" : "49247", "city" : "HUDSON", "loc" : [ -84.338031, 41.858101 ], "pop" : 5953, "state" : "MI" }
+{ "_id" : "49248", "city" : "JASPER", "loc" : [ -83.951549, 41.758956 ], "pop" : 1240, "state" : "MI" }
+{ "_id" : "49249", "city" : "JEROME", "loc" : [ -84.445483, 42.048375 ], "pop" : 2686, "state" : "MI" }
+{ "_id" : "49250", "city" : "JONESVILLE", "loc" : [ -84.645083, 41.979833 ], "pop" : 5671, "state" : "MI" }
+{ "_id" : "49251", "city" : "LESLIE", "loc" : [ -84.420653, 42.460279 ], "pop" : 5493, "state" : "MI" }
+{ "_id" : "49252", "city" : "LITCHFIELD", "loc" : [ -84.636095, 42.054039 ], "pop" : 840, "state" : "MI" }
+{ "_id" : "49253", "city" : "MANITOU BEACH", "loc" : [ -84.276706, 41.967055 ], "pop" : 2714, "state" : "MI" }
+{ "_id" : "49254", "city" : "MICHIGAN CENTER", "loc" : [ -84.321315, 42.226294 ], "pop" : 4013, "state" : "MI" }
+{ "_id" : "49255", "city" : "MONTGOMERY", "loc" : [ -84.84964100000001, 41.792764 ], "pop" : 2260, "state" : "MI" }
+{ "_id" : "49256", "city" : "MORENCI", "loc" : [ -84.219204, 41.738612 ], "pop" : 4699, "state" : "MI" }
+{ "_id" : "49259", "city" : "MUNITH", "loc" : [ -84.248486, 42.370317 ], "pop" : 3078, "state" : "MI" }
+{ "_id" : "49262", "city" : "NORTH ADAMS", "loc" : [ -84.520824, 41.971484 ], "pop" : 750, "state" : "MI" }
+{ "_id" : "49264", "city" : "ONONDAGA", "loc" : [ -84.553501, 42.448726 ], "pop" : 1358, "state" : "MI" }
+{ "_id" : "49265", "city" : "ONSTED", "loc" : [ -84.183892, 42.029533 ], "pop" : 4601, "state" : "MI" }
+{ "_id" : "49266", "city" : "OSSEO", "loc" : [ -84.597388, 41.838413 ], "pop" : 7025, "state" : "MI" }
+{ "_id" : "49267", "city" : "OTTAWA LAKE", "loc" : [ -83.685559, 41.768276 ], "pop" : 4531, "state" : "MI" }
+{ "_id" : "49268", "city" : "PALMYRA", "loc" : [ -83.96567899999999, 41.872976 ], "pop" : 2289, "state" : "MI" }
+{ "_id" : "49269", "city" : "PARMA", "loc" : [ -84.599886, 42.273879 ], "pop" : 6185, "state" : "MI" }
+{ "_id" : "49270", "city" : "PETERSBURG", "loc" : [ -83.687673, 41.875655 ], "pop" : 4832, "state" : "MI" }
+{ "_id" : "49271", "city" : "PITTSFORD", "loc" : [ -84.444016, 41.896262 ], "pop" : 2552, "state" : "MI" }
+{ "_id" : "49272", "city" : "PLEASANT LAKE", "loc" : [ -84.34279100000001, 42.390343 ], "pop" : 1685, "state" : "MI" }
+{ "_id" : "49274", "city" : "READING", "loc" : [ -84.76475000000001, 41.844194 ], "pop" : 2253, "state" : "MI" }
+{ "_id" : "49275", "city" : "RIDGEWAY", "loc" : [ -83.778429, 42.010554 ], "pop" : 23, "state" : "MI" }
+{ "_id" : "49276", "city" : "RIGA", "loc" : [ -83.80114399999999, 41.795309 ], "pop" : 961, "state" : "MI" }
+{ "_id" : "49277", "city" : "RIVES JUNCTION", "loc" : [ -84.458868, 42.38871 ], "pop" : 3676, "state" : "MI" }
+{ "_id" : "49279", "city" : "SAND CREEK", "loc" : [ -84.075502, 41.77928 ], "pop" : 1197, "state" : "MI" }
+{ "_id" : "49281", "city" : "SOMERSET", "loc" : [ -84.39472000000001, 42.044732 ], "pop" : 1556, "state" : "MI" }
+{ "_id" : "49283", "city" : "SPRING ARBOR", "loc" : [ -84.550127, 42.206861 ], "pop" : 2852, "state" : "MI" }
+{ "_id" : "49284", "city" : "SPRINGPORT", "loc" : [ -84.70388800000001, 42.38055 ], "pop" : 3153, "state" : "MI" }
+{ "_id" : "49285", "city" : "STOCKBRIDGE", "loc" : [ -84.175178, 42.460404 ], "pop" : 6047, "state" : "MI" }
+{ "_id" : "49286", "city" : "TECUMSEH", "loc" : [ -83.955485, 41.995297 ], "pop" : 12645, "state" : "MI" }
+{ "_id" : "49287", "city" : "TIPTON", "loc" : [ -84.07684, 42.036911 ], "pop" : 2473, "state" : "MI" }
+{ "_id" : "49288", "city" : "WALDRON", "loc" : [ -84.449636, 41.738608 ], "pop" : 2151, "state" : "MI" }
+{ "_id" : "49301", "city" : "ADA", "loc" : [ -85.480959, 42.95661 ], "pop" : 9568, "state" : "MI" }
+{ "_id" : "49302", "city" : "ALTO", "loc" : [ -85.42555400000001, 42.824312 ], "pop" : 5391, "state" : "MI" }
+{ "_id" : "49303", "city" : "BAILEY", "loc" : [ -85.831318, 43.276768 ], "pop" : 670, "state" : "MI" }
+{ "_id" : "49304", "city" : "BALDWIN", "loc" : [ -85.881874, 43.889409 ], "pop" : 3387, "state" : "MI" }
+{ "_id" : "49305", "city" : "BARRYTON", "loc" : [ -85.15465399999999, 43.750651 ], "pop" : 1824, "state" : "MI" }
+{ "_id" : "49306", "city" : "BELMONT", "loc" : [ -85.586769, 43.077934 ], "pop" : 6782, "state" : "MI" }
+{ "_id" : "49307", "city" : "BIG RAPIDS", "loc" : [ -85.479705, 43.689679 ], "pop" : 18049, "state" : "MI" }
+{ "_id" : "49309", "city" : "BITELY", "loc" : [ -85.877799, 43.732132 ], "pop" : 1828, "state" : "MI" }
+{ "_id" : "49310", "city" : "BLANCHARD", "loc" : [ -85.05885600000001, 43.522778 ], "pop" : 2473, "state" : "MI" }
+{ "_id" : "49315", "city" : "BYRON CENTER", "loc" : [ -85.71360199999999, 42.801614 ], "pop" : 6861, "state" : "MI" }
+{ "_id" : "49316", "city" : "DUTTON", "loc" : [ -85.562167, 42.796395 ], "pop" : 8634, "state" : "MI" }
+{ "_id" : "49318", "city" : "CASNOVIA", "loc" : [ -85.825394, 43.23815 ], "pop" : 1283, "state" : "MI" }
+{ "_id" : "49319", "city" : "CEDAR SPRINGS", "loc" : [ -85.545238, 43.22148 ], "pop" : 9743, "state" : "MI" }
+{ "_id" : "49321", "city" : "COMSTOCK PARK", "loc" : [ -85.684468, 43.057813 ], "pop" : 11913, "state" : "MI" }
+{ "_id" : "49322", "city" : "CORAL", "loc" : [ -85.379245, 43.364458 ], "pop" : 895, "state" : "MI" }
+{ "_id" : "49323", "city" : "DORR", "loc" : [ -85.762798, 42.723113 ], "pop" : 7782, "state" : "MI" }
+{ "_id" : "49325", "city" : "FREEPORT", "loc" : [ -85.279134, 42.729703 ], "pop" : 1546, "state" : "MI" }
+{ "_id" : "49326", "city" : "GOWEN", "loc" : [ -85.315941, 43.223884 ], "pop" : 6144, "state" : "MI" }
+{ "_id" : "49327", "city" : "GRANT", "loc" : [ -85.836827, 43.339197 ], "pop" : 6898, "state" : "MI" }
+{ "_id" : "49328", "city" : "HOPKINS", "loc" : [ -85.732195, 42.64209 ], "pop" : 2350, "state" : "MI" }
+{ "_id" : "49329", "city" : "HOWARD CITY", "loc" : [ -85.485609, 43.408326 ], "pop" : 3028, "state" : "MI" }
+{ "_id" : "49330", "city" : "KENT CITY", "loc" : [ -85.739949, 43.236235 ], "pop" : 3742, "state" : "MI" }
+{ "_id" : "49331", "city" : "LOWELL", "loc" : [ -85.36530500000001, 42.95497 ], "pop" : 12732, "state" : "MI" }
+{ "_id" : "49332", "city" : "MECOSTA", "loc" : [ -85.22803399999999, 43.681317 ], "pop" : 1939, "state" : "MI" }
+{ "_id" : "49333", "city" : "MIDDLEVILLE", "loc" : [ -85.47590099999999, 42.693247 ], "pop" : 8596, "state" : "MI" }
+{ "_id" : "49336", "city" : "MORLEY", "loc" : [ -85.447318, 43.505951 ], "pop" : 2875, "state" : "MI" }
+{ "_id" : "49337", "city" : "NEWAYGO", "loc" : [ -85.759381, 43.419799 ], "pop" : 8091, "state" : "MI" }
+{ "_id" : "49338", "city" : "PARIS", "loc" : [ -85.521348, 43.767704 ], "pop" : 3359, "state" : "MI" }
+{ "_id" : "49339", "city" : "PIERSON", "loc" : [ -85.51335899999999, 43.335514 ], "pop" : 2177, "state" : "MI" }
+{ "_id" : "49340", "city" : "REMUS", "loc" : [ -85.157365, 43.603249 ], "pop" : 4990, "state" : "MI" }
+{ "_id" : "49341", "city" : "ROCKFORD", "loc" : [ -85.513606, 43.115217 ], "pop" : 19778, "state" : "MI" }
+{ "_id" : "49342", "city" : "RODNEY", "loc" : [ -85.321884, 43.73791 ], "pop" : 1202, "state" : "MI" }
+{ "_id" : "49343", "city" : "SAND LAKE", "loc" : [ -85.536655, 43.298109 ], "pop" : 4951, "state" : "MI" }
+{ "_id" : "49344", "city" : "SHELBYVILLE", "loc" : [ -85.62823899999999, 42.593581 ], "pop" : 259, "state" : "MI" }
+{ "_id" : "49345", "city" : "SPARTA", "loc" : [ -85.687668, 43.161867 ], "pop" : 11522, "state" : "MI" }
+{ "_id" : "49346", "city" : "STANWOOD", "loc" : [ -85.444607, 43.601728 ], "pop" : 3068, "state" : "MI" }
+{ "_id" : "49347", "city" : "TRUFANT", "loc" : [ -85.368489, 43.315611 ], "pop" : 1002, "state" : "MI" }
+{ "_id" : "49348", "city" : "WAYLAND", "loc" : [ -85.619112, 42.664268 ], "pop" : 6756, "state" : "MI" }
+{ "_id" : "49349", "city" : "WHITE CLOUD", "loc" : [ -85.75864, 43.539803 ], "pop" : 8668, "state" : "MI" }
+{ "_id" : "49401", "city" : "ALLENDALE", "loc" : [ -85.924913, 42.971066 ], "pop" : 7311, "state" : "MI" }
+{ "_id" : "49402", "city" : "BRANCH", "loc" : [ -86.13136900000001, 43.923296 ], "pop" : 1741, "state" : "MI" }
+{ "_id" : "49403", "city" : "CONKLIN", "loc" : [ -85.853753, 43.149399 ], "pop" : 2720, "state" : "MI" }
+{ "_id" : "49404", "city" : "COOPERSVILLE", "loc" : [ -85.951722, 43.06013 ], "pop" : 5962, "state" : "MI" }
+{ "_id" : "49405", "city" : "CUSTER", "loc" : [ -86.220437, 43.94424 ], "pop" : 1002, "state" : "MI" }
+{ "_id" : "49408", "city" : "FENNVILLE", "loc" : [ -86.124876, 42.577669 ], "pop" : 6486, "state" : "MI" }
+{ "_id" : "49410", "city" : "FOUNTAIN", "loc" : [ -86.21686099999999, 44.036342 ], "pop" : 1030, "state" : "MI" }
+{ "_id" : "49411", "city" : "FREE SOIL", "loc" : [ -86.265158, 44.112036 ], "pop" : 903, "state" : "MI" }
+{ "_id" : "49412", "city" : "FREMONT", "loc" : [ -85.962554, 43.465196 ], "pop" : 7946, "state" : "MI" }
+{ "_id" : "49415", "city" : "FRUITPORT", "loc" : [ -86.13883199999999, 43.144282 ], "pop" : 4183, "state" : "MI" }
+{ "_id" : "49417", "city" : "GRAND HAVEN", "loc" : [ -86.191227, 43.037838 ], "pop" : 24103, "state" : "MI" }
+{ "_id" : "49418", "city" : "GRANDVILLE", "loc" : [ -85.76187400000001, 42.89387 ], "pop" : 19467, "state" : "MI" }
+{ "_id" : "49419", "city" : "HAMILTON", "loc" : [ -85.97473100000001, 42.688097 ], "pop" : 4586, "state" : "MI" }
+{ "_id" : "49420", "city" : "HART", "loc" : [ -86.31415200000001, 43.70676 ], "pop" : 5548, "state" : "MI" }
+{ "_id" : "49421", "city" : "HESPERIA", "loc" : [ -86.060739, 43.596513 ], "pop" : 5102, "state" : "MI" }
+{ "_id" : "49423", "city" : "HOLLAND", "loc" : [ -86.116362, 42.769211 ], "pop" : 40325, "state" : "MI" }
+{ "_id" : "49424", "city" : "HOLLAND", "loc" : [ -86.14263099999999, 42.813514 ], "pop" : 25798, "state" : "MI" }
+{ "_id" : "49425", "city" : "HOLTON", "loc" : [ -86.150853, 43.441454 ], "pop" : 4251, "state" : "MI" }
+{ "_id" : "49426", "city" : "HUDSONVILLE", "loc" : [ -85.8751, 42.874805 ], "pop" : 20122, "state" : "MI" }
+{ "_id" : "49428", "city" : "JENISON", "loc" : [ -85.827603, 42.910423 ], "pop" : 23358, "state" : "MI" }
+{ "_id" : "49431", "city" : "LUDINGTON", "loc" : [ -86.440253, 43.968823 ], "pop" : 13169, "state" : "MI" }
+{ "_id" : "49435", "city" : "MARNE", "loc" : [ -85.84195800000001, 43.053185 ], "pop" : 2715, "state" : "MI" }
+{ "_id" : "49436", "city" : "MEARS", "loc" : [ -86.453307, 43.682494 ], "pop" : 1302, "state" : "MI" }
+{ "_id" : "49437", "city" : "MONTAGUE", "loc" : [ -86.373992, 43.424163 ], "pop" : 4953, "state" : "MI" }
+{ "_id" : "49440", "city" : "MUSKEGON", "loc" : [ -86.249191, 43.232589 ], "pop" : 1033, "state" : "MI" }
+{ "_id" : "49441", "city" : "MUSKEGON", "loc" : [ -86.273819, 43.196184 ], "pop" : 36169, "state" : "MI" }
+{ "_id" : "49442", "city" : "MUSKEGON", "loc" : [ -86.188467, 43.232876 ], "pop" : 39272, "state" : "MI" }
+{ "_id" : "49444", "city" : "MUSKEGON HEIGHTS", "loc" : [ -86.21620799999999, 43.195046 ], "pop" : 29295, "state" : "MI" }
+{ "_id" : "49445", "city" : "NORTH MUSKEGON", "loc" : [ -86.273297, 43.282873 ], "pop" : 18797, "state" : "MI" }
+{ "_id" : "49446", "city" : "NEW ERA", "loc" : [ -86.344803, 43.555578 ], "pop" : 2539, "state" : "MI" }
+{ "_id" : "49447", "city" : "NEW RICHMOND", "loc" : [ -86.03798500000001, 42.662383 ], "pop" : 438, "state" : "MI" }
+{ "_id" : "49448", "city" : "NUNICA", "loc" : [ -86.102768, 43.088306 ], "pop" : 3795, "state" : "MI" }
+{ "_id" : "49449", "city" : "PENTWATER", "loc" : [ -86.38681800000001, 43.823713 ], "pop" : 3915, "state" : "MI" }
+{ "_id" : "49450", "city" : "PULLMAN", "loc" : [ -86.079909, 42.465131 ], "pop" : 2672, "state" : "MI" }
+{ "_id" : "49451", "city" : "RAVENNA", "loc" : [ -85.964816, 43.209128 ], "pop" : 5106, "state" : "MI" }
+{ "_id" : "49452", "city" : "ROTHBURY", "loc" : [ -86.34464, 43.511633 ], "pop" : 1618, "state" : "MI" }
+{ "_id" : "49453", "city" : "SAUGATUCK", "loc" : [ -86.194093, 42.642562 ], "pop" : 3870, "state" : "MI" }
+{ "_id" : "49454", "city" : "SCOTTVILLE", "loc" : [ -86.31561499999999, 43.976692 ], "pop" : 4229, "state" : "MI" }
+{ "_id" : "49455", "city" : "SHELBY", "loc" : [ -86.361503, 43.607942 ], "pop" : 4420, "state" : "MI" }
+{ "_id" : "49456", "city" : "SPRING LAKE", "loc" : [ -86.19150999999999, 43.088741 ], "pop" : 14602, "state" : "MI" }
+{ "_id" : "49457", "city" : "TWIN LAKE", "loc" : [ -86.16331599999999, 43.341378 ], "pop" : 7212, "state" : "MI" }
+{ "_id" : "49459", "city" : "WALKERVILLE", "loc" : [ -86.08299100000001, 43.762559 ], "pop" : 309, "state" : "MI" }
+{ "_id" : "49460", "city" : "WEST OLIVE", "loc" : [ -86.131726, 42.909912 ], "pop" : 6722, "state" : "MI" }
+{ "_id" : "49461", "city" : "WHITEHALL", "loc" : [ -86.331453, 43.390358 ], "pop" : 6925, "state" : "MI" }
+{ "_id" : "49464", "city" : "ZEELAND", "loc" : [ -86.010408, 42.825586 ], "pop" : 15649, "state" : "MI" }
+{ "_id" : "49503", "city" : "GRAND RAPIDS", "loc" : [ -85.65273000000001, 42.965879 ], "pop" : 32876, "state" : "MI" }
+{ "_id" : "49504", "city" : "WALKER", "loc" : [ -85.725543, 42.98392 ], "pop" : 63454, "state" : "MI" }
+{ "_id" : "49505", "city" : "GRAND RAPIDS", "loc" : [ -85.630931, 43.012025 ], "pop" : 52883, "state" : "MI" }
+{ "_id" : "49506", "city" : "GRAND RAPIDS", "loc" : [ -85.621317, 42.943978 ], "pop" : 36668, "state" : "MI" }
+{ "_id" : "49507", "city" : "GRAND RAPIDS", "loc" : [ -85.65416999999999, 42.931788 ], "pop" : 37681, "state" : "MI" }
+{ "_id" : "49508", "city" : "KENTWOOD", "loc" : [ -85.624179, 42.875653 ], "pop" : 32830, "state" : "MI" }
+{ "_id" : "49509", "city" : "WYOMING", "loc" : [ -85.705775, 42.900867 ], "pop" : 57419, "state" : "MI" }
+{ "_id" : "49512", "city" : "KENTWOOD", "loc" : [ -85.57815600000001, 42.89269 ], "pop" : 7823, "state" : "MI" }
+{ "_id" : "49546", "city" : "GRAND RAPIDS", "loc" : [ -85.548346, 42.928029 ], "pop" : 25471, "state" : "MI" }
+{ "_id" : "49548", "city" : "KENTWOOD", "loc" : [ -85.66076700000001, 42.867048 ], "pop" : 32054, "state" : "MI" }
+{ "_id" : "49601", "city" : "CADILLAC", "loc" : [ -85.430046, 44.250447 ], "pop" : 18182, "state" : "MI" }
+{ "_id" : "49612", "city" : "ALDEN", "loc" : [ -85.22410000000001, 44.877887 ], "pop" : 1536, "state" : "MI" }
+{ "_id" : "49613", "city" : "ARCADIA", "loc" : [ -86.206057, 44.523157 ], "pop" : 937, "state" : "MI" }
+{ "_id" : "49614", "city" : "BEAR LAKE", "loc" : [ -86.14249700000001, 44.431125 ], "pop" : 1965, "state" : "MI" }
+{ "_id" : "49615", "city" : "BELLAIRE", "loc" : [ -85.226495, 44.976469 ], "pop" : 2031, "state" : "MI" }
+{ "_id" : "49616", "city" : "BENZONIA", "loc" : [ -86.096091, 44.595502 ], "pop" : 1833, "state" : "MI" }
+{ "_id" : "49617", "city" : "BEULAH", "loc" : [ -86.038346, 44.646002 ], "pop" : 2617, "state" : "MI" }
+{ "_id" : "49618", "city" : "BOON", "loc" : [ -85.614383, 44.291555 ], "pop" : 388, "state" : "MI" }
+{ "_id" : "49619", "city" : "BRETHREN", "loc" : [ -85.996396, 44.296596 ], "pop" : 966, "state" : "MI" }
+{ "_id" : "49620", "city" : "BUCKLEY", "loc" : [ -85.693541, 44.519856 ], "pop" : 1788, "state" : "MI" }
+{ "_id" : "49621", "city" : "CEDAR", "loc" : [ -85.745344, 44.836953 ], "pop" : 2853, "state" : "MI" }
+{ "_id" : "49622", "city" : "CENTRAL LAKE", "loc" : [ -85.267285, 45.074796 ], "pop" : 1970, "state" : "MI" }
+{ "_id" : "49623", "city" : "CHASE", "loc" : [ -85.61963900000001, 43.868172 ], "pop" : 1016, "state" : "MI" }
+{ "_id" : "49625", "city" : "COPEMISH", "loc" : [ -85.88785900000001, 44.450276 ], "pop" : 927, "state" : "MI" }
+{ "_id" : "49629", "city" : "ELK RAPIDS", "loc" : [ -85.408226, 44.895473 ], "pop" : 1493, "state" : "MI" }
+{ "_id" : "49630", "city" : "EMPIRE", "loc" : [ -85.99253299999999, 44.84106 ], "pop" : 609, "state" : "MI" }
+{ "_id" : "49631", "city" : "EVART", "loc" : [ -85.26493499999999, 43.888772 ], "pop" : 4253, "state" : "MI" }
+{ "_id" : "49632", "city" : "FALMOUTH", "loc" : [ -85.01700200000001, 44.252861 ], "pop" : 1891, "state" : "MI" }
+{ "_id" : "49633", "city" : "FIFE LAKE", "loc" : [ -85.253122, 44.572064 ], "pop" : 2566, "state" : "MI" }
+{ "_id" : "49635", "city" : "FRANKFORT", "loc" : [ -86.22120099999999, 44.631122 ], "pop" : 3168, "state" : "MI" }
+{ "_id" : "49636", "city" : "GLEN ARBOR", "loc" : [ -86.03533899999999, 44.842927 ], "pop" : 641, "state" : "MI" }
+{ "_id" : "49637", "city" : "GRAWN", "loc" : [ -85.71129000000001, 44.642779 ], "pop" : 1869, "state" : "MI" }
+{ "_id" : "49638", "city" : "HARRIETTA", "loc" : [ -85.73957299999999, 44.297163 ], "pop" : 651, "state" : "MI" }
+{ "_id" : "49639", "city" : "HERSEY", "loc" : [ -85.40592599999999, 43.84806 ], "pop" : 1915, "state" : "MI" }
+{ "_id" : "49640", "city" : "HONOR", "loc" : [ -86.037582, 44.69539 ], "pop" : 945, "state" : "MI" }
+{ "_id" : "49642", "city" : "IDLEWILD", "loc" : [ -85.716036, 43.912621 ], "pop" : 1132, "state" : "MI" }
+{ "_id" : "49643", "city" : "INTERLOCHEN", "loc" : [ -85.802156, 44.651769 ], "pop" : 3429, "state" : "MI" }
+{ "_id" : "49644", "city" : "IRONS", "loc" : [ -85.939008, 44.096638 ], "pop" : 1245, "state" : "MI" }
+{ "_id" : "49645", "city" : "KALEVA", "loc" : [ -86.04673699999999, 44.369168 ], "pop" : 1533, "state" : "MI" }
+{ "_id" : "49646", "city" : "KALKASKA", "loc" : [ -85.120655, 44.73546 ], "pop" : 7387, "state" : "MI" }
+{ "_id" : "49647", "city" : "KARLIN", "loc" : [ -85.79406, 44.569128 ], "pop" : 80, "state" : "MI" }
+{ "_id" : "49648", "city" : "KEWADIN", "loc" : [ -85.35394100000001, 45.012574 ], "pop" : 1303, "state" : "MI" }
+{ "_id" : "49649", "city" : "KINGSLEY", "loc" : [ -85.526235, 44.575644 ], "pop" : 3823, "state" : "MI" }
+{ "_id" : "49650", "city" : "LAKE ANN", "loc" : [ -85.85284, 44.731736 ], "pop" : 1448, "state" : "MI" }
+{ "_id" : "49651", "city" : "MOORESTOWN", "loc" : [ -85.207352, 44.361932 ], "pop" : 6225, "state" : "MI" }
+{ "_id" : "49653", "city" : "LAKE LEELANAU", "loc" : [ -85.732866, 44.985602 ], "pop" : 2053, "state" : "MI" }
+{ "_id" : "49654", "city" : "LELAND", "loc" : [ -86.092924, 45.010215 ], "pop" : 0, "state" : "MI" }
+{ "_id" : "49655", "city" : "LEROY", "loc" : [ -85.430001, 44.045656 ], "pop" : 3386, "state" : "MI" }
+{ "_id" : "49656", "city" : "LUTHER", "loc" : [ -85.682631, 44.054494 ], "pop" : 1540, "state" : "MI" }
+{ "_id" : "49657", "city" : "MC BAIN", "loc" : [ -85.228252, 44.21718 ], "pop" : 3431, "state" : "MI" }
+{ "_id" : "49659", "city" : "MANCELONA", "loc" : [ -85.063399, 44.911596 ], "pop" : 5447, "state" : "MI" }
+{ "_id" : "49660", "city" : "STRONACH", "loc" : [ -86.28503000000001, 44.228323 ], "pop" : 14319, "state" : "MI" }
+{ "_id" : "49663", "city" : "MANTON", "loc" : [ -85.42017, 44.415222 ], "pop" : 3516, "state" : "MI" }
+{ "_id" : "49664", "city" : "MAPLE CITY", "loc" : [ -85.88139200000001, 44.859035 ], "pop" : 1917, "state" : "MI" }
+{ "_id" : "49665", "city" : "MARION", "loc" : [ -85.15503099999999, 44.046314 ], "pop" : 5710, "state" : "MI" }
+{ "_id" : "49667", "city" : "MERRITT", "loc" : [ -85.015508, 44.36843 ], "pop" : 600, "state" : "MI" }
+{ "_id" : "49668", "city" : "MESICK", "loc" : [ -85.70612199999999, 44.407451 ], "pop" : 2864, "state" : "MI" }
+{ "_id" : "49670", "city" : "NORTHPORT", "loc" : [ -85.617287, 45.115699 ], "pop" : 1663, "state" : "MI" }
+{ "_id" : "49675", "city" : "ONEKAMA", "loc" : [ -86.209959, 44.364576 ], "pop" : 1089, "state" : "MI" }
+{ "_id" : "49676", "city" : "RAPID CITY", "loc" : [ -85.294318, 44.844863 ], "pop" : 2741, "state" : "MI" }
+{ "_id" : "49677", "city" : "REED CITY", "loc" : [ -85.51302800000001, 43.886808 ], "pop" : 5056, "state" : "MI" }
+{ "_id" : "49679", "city" : "SEARS", "loc" : [ -85.18824600000001, 43.901747 ], "pop" : 150, "state" : "MI" }
+{ "_id" : "49680", "city" : "SOUTH BOARDMAN", "loc" : [ -85.24720000000001, 44.640143 ], "pop" : 1427, "state" : "MI" }
+{ "_id" : "49682", "city" : "SUTTONS BAY", "loc" : [ -85.642264, 44.965613 ], "pop" : 3422, "state" : "MI" }
+{ "_id" : "49683", "city" : "THOMPSONVILLE", "loc" : [ -85.945973, 44.519833 ], "pop" : 1231, "state" : "MI" }
+{ "_id" : "49684", "city" : "TRAVERSE CITY", "loc" : [ -85.618869, 44.74365 ], "pop" : 53415, "state" : "MI" }
+{ "_id" : "49688", "city" : "TUSTIN", "loc" : [ -85.490143, 44.107181 ], "pop" : 1213, "state" : "MI" }
+{ "_id" : "49689", "city" : "WELLSTON", "loc" : [ -85.95547500000001, 44.213266 ], "pop" : 1043, "state" : "MI" }
+{ "_id" : "49690", "city" : "WILLIAMSBURG", "loc" : [ -85.434732, 44.801952 ], "pop" : 4987, "state" : "MI" }
+{ "_id" : "49705", "city" : "AFTON", "loc" : [ -84.469453, 45.363684 ], "pop" : 605, "state" : "MI" }
+{ "_id" : "49706", "city" : "ALANSON", "loc" : [ -84.792421, 45.440545 ], "pop" : 3681, "state" : "MI" }
+{ "_id" : "49707", "city" : "ALPENA", "loc" : [ -83.4602, 45.079018 ], "pop" : 23530, "state" : "MI" }
+{ "_id" : "49709", "city" : "ATLANTA", "loc" : [ -84.147982, 44.992371 ], "pop" : 2299, "state" : "MI" }
+{ "_id" : "49710", "city" : "BARBEAU", "loc" : [ -84.217332, 46.284753 ], "pop" : 368, "state" : "MI" }
+{ "_id" : "49712", "city" : "BOYNE CITY", "loc" : [ -85.018294, 45.205203 ], "pop" : 7244, "state" : "MI" }
+{ "_id" : "49713", "city" : "BOYNE FALLS", "loc" : [ -84.89158399999999, 45.211563 ], "pop" : 2009, "state" : "MI" }
+{ "_id" : "49715", "city" : "RACO", "loc" : [ -84.563841, 46.411117 ], "pop" : 871, "state" : "MI" }
+{ "_id" : "49716", "city" : "BRUTUS", "loc" : [ -84.74669299999999, 45.506785 ], "pop" : 586, "state" : "MI" }
+{ "_id" : "49718", "city" : "CARP LAKE", "loc" : [ -84.773453, 45.742364 ], "pop" : 1049, "state" : "MI" }
+{ "_id" : "49719", "city" : "CEDARVILLE", "loc" : [ -84.348823, 46.002449 ], "pop" : 1615, "state" : "MI" }
+{ "_id" : "49720", "city" : "CHARLEVOIX", "loc" : [ -85.24529800000001, 45.29934 ], "pop" : 7690, "state" : "MI" }
+{ "_id" : "49721", "city" : "CHEBOYGAN", "loc" : [ -84.48672000000001, 45.608038 ], "pop" : 13854, "state" : "MI" }
+{ "_id" : "49724", "city" : "DAFTER", "loc" : [ -84.39967900000001, 46.349196 ], "pop" : 2040, "state" : "MI" }
+{ "_id" : "49725", "city" : "DE TOUR VILLAGE", "loc" : [ -83.939628, 45.993852 ], "pop" : 719, "state" : "MI" }
+{ "_id" : "49726", "city" : "DRUMMOND ISLAND", "loc" : [ -83.736706, 46.005521 ], "pop" : 835, "state" : "MI" }
+{ "_id" : "49727", "city" : "EAST JORDAN", "loc" : [ -85.138655, 45.153858 ], "pop" : 5532, "state" : "MI" }
+{ "_id" : "49728", "city" : "ECKERMAN", "loc" : [ -85.162606, 46.346638 ], "pop" : 208, "state" : "MI" }
+{ "_id" : "49729", "city" : "ELLSWORTH", "loc" : [ -85.26329200000001, 45.159929 ], "pop" : 1223, "state" : "MI" }
+{ "_id" : "49730", "city" : "ELMIRA", "loc" : [ -84.830321, 45.034582 ], "pop" : 2807, "state" : "MI" }
+{ "_id" : "49733", "city" : "FREDERIC", "loc" : [ -84.68241, 44.838217 ], "pop" : 3967, "state" : "MI" }
+{ "_id" : "49735", "city" : "GAYLORD", "loc" : [ -84.67228, 45.012523 ], "pop" : 11598, "state" : "MI" }
+{ "_id" : "49736", "city" : "GOETZVILLE", "loc" : [ -84.059271, 46.100976 ], "pop" : 123, "state" : "MI" }
+{ "_id" : "49738", "city" : "GRAYLING", "loc" : [ -84.691321, 44.670959 ], "pop" : 7591, "state" : "MI" }
+{ "_id" : "49740", "city" : "HARBOR POINT", "loc" : [ -84.98030300000001, 45.464535 ], "pop" : 5473, "state" : "MI" }
+{ "_id" : "49743", "city" : "HAWKS", "loc" : [ -83.854219, 45.297467 ], "pop" : 876, "state" : "MI" }
+{ "_id" : "49744", "city" : "HERRON", "loc" : [ -83.65348, 45.012367 ], "pop" : 978, "state" : "MI" }
+{ "_id" : "49746", "city" : "HILLMAN", "loc" : [ -83.946781, 45.069104 ], "pop" : 3902, "state" : "MI" }
+{ "_id" : "49747", "city" : "HUBBARD LAKE", "loc" : [ -83.60590500000001, 44.89467 ], "pop" : 1359, "state" : "MI" }
+{ "_id" : "49749", "city" : "INDIAN RIVER", "loc" : [ -84.595578, 45.426984 ], "pop" : 2965, "state" : "MI" }
+{ "_id" : "49751", "city" : "JOHANNESBURG", "loc" : [ -84.38570799999999, 45.015207 ], "pop" : 2062, "state" : "MI" }
+{ "_id" : "49752", "city" : "KINROSS", "loc" : [ -84.751122, 46.416612 ], "pop" : 1070, "state" : "MI" }
+{ "_id" : "49753", "city" : "LACHINE", "loc" : [ -83.749071, 45.042946 ], "pop" : 1764, "state" : "MI" }
+{ "_id" : "49755", "city" : "LEVERING", "loc" : [ -84.798597, 45.637711 ], "pop" : 1251, "state" : "MI" }
+{ "_id" : "49756", "city" : "LEWISTON", "loc" : [ -84.297281, 44.853758 ], "pop" : 3327, "state" : "MI" }
+{ "_id" : "49757", "city" : "MACKINAC ISLAND", "loc" : [ -84.624527, 45.857837 ], "pop" : 469, "state" : "MI" }
+{ "_id" : "49759", "city" : "MILLERSBURG", "loc" : [ -84.122246, 45.402164 ], "pop" : 2048, "state" : "MI" }
+{ "_id" : "49760", "city" : "MORAN", "loc" : [ -85.007835, 46.044106 ], "pop" : 113, "state" : "MI" }
+{ "_id" : "49762", "city" : "NAUBINWAY", "loc" : [ -85.44619, 46.126021 ], "pop" : 1297, "state" : "MI" }
+{ "_id" : "49765", "city" : "ONAWAY", "loc" : [ -84.212272, 45.33654 ], "pop" : 1926, "state" : "MI" }
+{ "_id" : "49766", "city" : "OSSINEKE", "loc" : [ -83.459186, 44.91038 ], "pop" : 2294, "state" : "MI" }
+{ "_id" : "49768", "city" : "PARADISE", "loc" : [ -85.056247, 46.598321 ], "pop" : 515, "state" : "MI" }
+{ "_id" : "49769", "city" : "PELLSTON", "loc" : [ -84.842502, 45.570285 ], "pop" : 1360, "state" : "MI" }
+{ "_id" : "49770", "city" : "BAY VIEW", "loc" : [ -84.940263, 45.361268 ], "pop" : 12806, "state" : "MI" }
+{ "_id" : "49774", "city" : "PICKFORD", "loc" : [ -84.36631199999999, 46.155858 ], "pop" : 624, "state" : "MI" }
+{ "_id" : "49775", "city" : "POINTE AUX PINS", "loc" : [ -84.447035, 45.754888 ], "pop" : 59, "state" : "MI" }
+{ "_id" : "49776", "city" : "POSEN", "loc" : [ -83.63927099999999, 45.223335 ], "pop" : 3830, "state" : "MI" }
+{ "_id" : "49779", "city" : "ROGERS CITY", "loc" : [ -83.835483, 45.412306 ], "pop" : 5463, "state" : "MI" }
+{ "_id" : "49780", "city" : "FIBRE", "loc" : [ -84.54934299999999, 46.200568 ], "pop" : 3242, "state" : "MI" }
+{ "_id" : "49781", "city" : "SAINT IGNACE", "loc" : [ -84.70940899999999, 45.921527 ], "pop" : 5411, "state" : "MI" }
+{ "_id" : "49782", "city" : "SAINT JAMES", "loc" : [ -85.531581, 45.722061 ], "pop" : 404, "state" : "MI" }
+{ "_id" : "49783", "city" : "SAULT SAINTE MAR", "loc" : [ -84.346746, 46.473932 ], "pop" : 17974, "state" : "MI" }
+{ "_id" : "49788", "city" : "KINCHELOE", "loc" : [ -84.46258400000001, 46.26271 ], "pop" : 6046, "state" : "MI" }
+{ "_id" : "49789", "city" : "STALWART", "loc" : [ -84.155861, 46.138876 ], "pop" : 214, "state" : "MI" }
+{ "_id" : "49792", "city" : "TOWER", "loc" : [ -84.303496, 45.341619 ], "pop" : 929, "state" : "MI" }
+{ "_id" : "49795", "city" : "VANDERBILT", "loc" : [ -84.651134, 45.153247 ], "pop" : 1541, "state" : "MI" }
+{ "_id" : "49799", "city" : "WOLVERINE", "loc" : [ -84.606477, 45.286148 ], "pop" : 1857, "state" : "MI" }
+{ "_id" : "49801", "city" : "IRON MOUNTAIN", "loc" : [ -88.068257, 45.821894 ], "pop" : 18423, "state" : "MI" }
+{ "_id" : "49806", "city" : "AU TRAIN", "loc" : [ -86.77932699999999, 46.428231 ], "pop" : 796, "state" : "MI" }
+{ "_id" : "49807", "city" : "HARDWOOD", "loc" : [ -87.240522, 45.705411 ], "pop" : 4037, "state" : "MI" }
+{ "_id" : "49812", "city" : "CARNEY", "loc" : [ -87.543896, 45.591738 ], "pop" : 1014, "state" : "MI" }
+{ "_id" : "49813", "city" : "CEDAR RIVER", "loc" : [ -87.365994, 45.448475 ], "pop" : 185, "state" : "MI" }
+{ "_id" : "49814", "city" : "CHAMPION", "loc" : [ -87.83058699999999, 46.468497 ], "pop" : 2774, "state" : "MI" }
+{ "_id" : "49815", "city" : "CHANNING", "loc" : [ -88.07722099999999, 46.154562 ], "pop" : 522, "state" : "MI" }
+{ "_id" : "49816", "city" : "LIMESTONE", "loc" : [ -86.758934, 46.294821 ], "pop" : 251, "state" : "MI" }
+{ "_id" : "49817", "city" : "COOKS", "loc" : [ -86.53071799999999, 45.899665 ], "pop" : 2, "state" : "MI" }
+{ "_id" : "49818", "city" : "CORNELL", "loc" : [ -87.223702, 45.910373 ], "pop" : 671, "state" : "MI" }
+{ "_id" : "49820", "city" : "CURTIS", "loc" : [ -85.786466, 46.204763 ], "pop" : 523, "state" : "MI" }
+{ "_id" : "49821", "city" : "DAGGETT", "loc" : [ -87.60785799999999, 45.488738 ], "pop" : 1184, "state" : "MI" }
+{ "_id" : "49822", "city" : "DEERTON", "loc" : [ -87.04064, 46.483979 ], "pop" : 290, "state" : "MI" }
+{ "_id" : "49825", "city" : "EBEN JUNCTION", "loc" : [ -87.032799, 46.351726 ], "pop" : 456, "state" : "MI" }
+{ "_id" : "49826", "city" : "RUMELY", "loc" : [ -86.935068, 46.341867 ], "pop" : 823, "state" : "MI" }
+{ "_id" : "49827", "city" : "ENGADINE", "loc" : [ -85.60046800000001, 46.204009 ], "pop" : 327, "state" : "MI" }
+{ "_id" : "49829", "city" : "ESCANABA", "loc" : [ -87.08898499999999, 45.76587 ], "pop" : 21065, "state" : "MI" }
+{ "_id" : "49833", "city" : "LITTLE LAKE", "loc" : [ -87.41144799999999, 46.053711 ], "pop" : 437, "state" : "MI" }
+{ "_id" : "49834", "city" : "FOSTER CITY", "loc" : [ -87.804768, 46.004769 ], "pop" : 1249, "state" : "MI" }
+{ "_id" : "49835", "city" : "GARDEN", "loc" : [ -86.57757599999999, 45.754867 ], "pop" : 934, "state" : "MI" }
+{ "_id" : "49836", "city" : "GERMFASK", "loc" : [ -85.91589, 46.236261 ], "pop" : 542, "state" : "MI" }
+{ "_id" : "49837", "city" : "BRAMPTON", "loc" : [ -87.02728399999999, 45.856402 ], "pop" : 5707, "state" : "MI" }
+{ "_id" : "49838", "city" : "GOULD CITY", "loc" : [ -85.725889, 46.134544 ], "pop" : 615, "state" : "MI" }
+{ "_id" : "49839", "city" : "GRAND MARAIS", "loc" : [ -85.983633, 46.652916 ], "pop" : 508, "state" : "MI" }
+{ "_id" : "49840", "city" : "GULLIVER", "loc" : [ -86.021433, 46.011491 ], "pop" : 822, "state" : "MI" }
+{ "_id" : "49841", "city" : "PRINCETON", "loc" : [ -87.43016, 46.291938 ], "pop" : 5377, "state" : "MI" }
+{ "_id" : "49843", "city" : "K I SAWYER A F B", "loc" : [ -87.37593, 46.330811 ], "pop" : 5613, "state" : "MI" }
+{ "_id" : "49847", "city" : "HERMANSVILLE", "loc" : [ -87.622659, 45.714902 ], "pop" : 1090, "state" : "MI" }
+{ "_id" : "49848", "city" : "INGALLS", "loc" : [ -87.62060700000001, 45.374774 ], "pop" : 340, "state" : "MI" }
+{ "_id" : "49849", "city" : "NORTH LAKE", "loc" : [ -87.682638, 46.490165 ], "pop" : 11725, "state" : "MI" }
+{ "_id" : "49853", "city" : "MC MILLAN", "loc" : [ -85.730715, 46.297027 ], "pop" : 897, "state" : "MI" }
+{ "_id" : "49854", "city" : "THOMPSON", "loc" : [ -86.275513, 45.982978 ], "pop" : 6753, "state" : "MI" }
+{ "_id" : "49855", "city" : "BEAVER GROVE", "loc" : [ -87.389443, 46.53124 ], "pop" : 32361, "state" : "MI" }
+{ "_id" : "49858", "city" : "MENOMINEE", "loc" : [ -87.621475, 45.13427 ], "pop" : 13149, "state" : "MI" }
+{ "_id" : "49861", "city" : "MICHIGAMME", "loc" : [ -87.892386, 46.668143 ], "pop" : 1230, "state" : "MI" }
+{ "_id" : "49862", "city" : "CHRISTMAS", "loc" : [ -86.626846, 46.413863 ], "pop" : 3762, "state" : "MI" }
+{ "_id" : "49866", "city" : "NEGAUNEE", "loc" : [ -87.582915, 46.500662 ], "pop" : 8204, "state" : "MI" }
+{ "_id" : "49868", "city" : "NEWBERRY", "loc" : [ -85.514951, 46.343763 ], "pop" : 4866, "state" : "MI" }
+{ "_id" : "49870", "city" : "NORWAY", "loc" : [ -87.90469299999999, 45.786186 ], "pop" : 3300, "state" : "MI" }
+{ "_id" : "49873", "city" : "PERRONVILLE", "loc" : [ -87.398903, 45.826409 ], "pop" : 360, "state" : "MI" }
+{ "_id" : "49874", "city" : "POWERS", "loc" : [ -87.531853, 45.679238 ], "pop" : 559, "state" : "MI" }
+{ "_id" : "49876", "city" : "QUINNESEC", "loc" : [ -87.99215100000001, 45.799866 ], "pop" : 1313, "state" : "MI" }
+{ "_id" : "49878", "city" : "RAPID RIVER", "loc" : [ -86.88449, 45.910662 ], "pop" : 3345, "state" : "MI" }
+{ "_id" : "49879", "city" : "REPUBLIC", "loc" : [ -87.99382300000001, 46.368046 ], "pop" : 1192, "state" : "MI" }
+{ "_id" : "49880", "city" : "ROCK", "loc" : [ -87.13306799999999, 46.050262 ], "pop" : 1601, "state" : "MI" }
+{ "_id" : "49881", "city" : "SAGOLA", "loc" : [ -88.067644, 46.081274 ], "pop" : 392, "state" : "MI" }
+{ "_id" : "49883", "city" : "SENEY", "loc" : [ -85.97084700000001, 46.387989 ], "pop" : 185, "state" : "MI" }
+{ "_id" : "49884", "city" : "SHINGLETON", "loc" : [ -86.48226099999999, 46.351202 ], "pop" : 589, "state" : "MI" }
+{ "_id" : "49885", "city" : "SKANDIA", "loc" : [ -87.24809399999999, 46.349049 ], "pop" : 1975, "state" : "MI" }
+{ "_id" : "49886", "city" : "SPALDING", "loc" : [ -87.49639999999999, 45.695747 ], "pop" : 922, "state" : "MI" }
+{ "_id" : "49887", "city" : "STEPHENSON", "loc" : [ -87.62578999999999, 45.416594 ], "pop" : 2202, "state" : "MI" }
+{ "_id" : "49890", "city" : "TRAUNIK", "loc" : [ -86.988891, 46.258534 ], "pop" : 334, "state" : "MI" }
+{ "_id" : "49891", "city" : "TRENARY", "loc" : [ -86.950183, 46.194738 ], "pop" : 563, "state" : "MI" }
+{ "_id" : "49892", "city" : "VULCAN", "loc" : [ -87.816811, 45.762257 ], "pop" : 1841, "state" : "MI" }
+{ "_id" : "49893", "city" : "WALLACE", "loc" : [ -87.580457, 45.301657 ], "pop" : 2103, "state" : "MI" }
+{ "_id" : "49894", "city" : "WELLS", "loc" : [ -87.073443, 45.784866 ], "pop" : 1093, "state" : "MI" }
+{ "_id" : "49895", "city" : "WETMORE", "loc" : [ -86.63453699999999, 46.353518 ], "pop" : 646, "state" : "MI" }
+{ "_id" : "49896", "city" : "WILSON", "loc" : [ -87.399734, 45.664855 ], "pop" : 1112, "state" : "MI" }
+{ "_id" : "49905", "city" : "ATLANTIC MINE", "loc" : [ -88.66131799999999, 47.093663 ], "pop" : 3379, "state" : "MI" }
+{ "_id" : "49908", "city" : "KEWEENAW BAY", "loc" : [ -88.49548900000001, 46.790213 ], "pop" : 1759, "state" : "MI" }
+{ "_id" : "49910", "city" : "BERGLAND", "loc" : [ -89.597296, 46.588124 ], "pop" : 618, "state" : "MI" }
+{ "_id" : "49911", "city" : "BESSEMER", "loc" : [ -90.05154400000001, 46.480188 ], "pop" : 3603, "state" : "MI" }
+{ "_id" : "49912", "city" : "BRUCE CROSSING", "loc" : [ -89.16802800000001, 46.527956 ], "pop" : 1089, "state" : "MI" }
+{ "_id" : "49913", "city" : "LAURIUM", "loc" : [ -88.44271999999999, 47.242721 ], "pop" : 7656, "state" : "MI" }
+{ "_id" : "49916", "city" : "CHASSELL", "loc" : [ -88.554554, 47.002038 ], "pop" : 3096, "state" : "MI" }
+{ "_id" : "49919", "city" : "COVINGTON", "loc" : [ -88.524452, 46.557194 ], "pop" : 260, "state" : "MI" }
+{ "_id" : "49920", "city" : "CRYSTAL FALLS", "loc" : [ -88.350517, 46.109255 ], "pop" : 4804, "state" : "MI" }
+{ "_id" : "49921", "city" : "DODGEVILLE", "loc" : [ -88.58087399999999, 47.091443 ], "pop" : 390, "state" : "MI" }
+{ "_id" : "49925", "city" : "EWEN", "loc" : [ -89.314494, 46.540412 ], "pop" : 772, "state" : "MI" }
+{ "_id" : "49927", "city" : "GAASTRA", "loc" : [ -88.591728, 46.052638 ], "pop" : 489, "state" : "MI" }
+{ "_id" : "49930", "city" : "HANCOCK", "loc" : [ -88.56538500000001, 47.136731 ], "pop" : 7683, "state" : "MI" }
+{ "_id" : "49931", "city" : "HOUGHTON", "loc" : [ -88.558024, 47.115801 ], "pop" : 8639, "state" : "MI" }
+{ "_id" : "49935", "city" : "IRON RIVER", "loc" : [ -88.645974, 46.093017 ], "pop" : 7882, "state" : "MI" }
+{ "_id" : "49938", "city" : "IRONWOOD", "loc" : [ -90.158844, 46.463793 ], "pop" : 9402, "state" : "MI" }
+{ "_id" : "49943", "city" : "KENTON", "loc" : [ -88.812933, 46.491565 ], "pop" : 304, "state" : "MI" }
+{ "_id" : "49945", "city" : "GAY", "loc" : [ -88.411829, 47.171387 ], "pop" : 3365, "state" : "MI" }
+{ "_id" : "49946", "city" : "LANSE", "loc" : [ -88.420959, 46.770407 ], "pop" : 3929, "state" : "MI" }
+{ "_id" : "49947", "city" : "MARENISCO", "loc" : [ -89.67742200000001, 46.355107 ], "pop" : 956, "state" : "MI" }
+{ "_id" : "49948", "city" : "MASS CITY", "loc" : [ -89.064864, 46.747447 ], "pop" : 805, "state" : "MI" }
+{ "_id" : "49950", "city" : "EAGLE HARBOR", "loc" : [ -88.332572, 47.320067 ], "pop" : 1701, "state" : "MI" }
+{ "_id" : "49952", "city" : "NISULA", "loc" : [ -88.83396999999999, 46.76952 ], "pop" : 73, "state" : "MI" }
+{ "_id" : "49953", "city" : "ONTONAGON", "loc" : [ -89.348474, 46.827484 ], "pop" : 5090, "state" : "MI" }
+{ "_id" : "49958", "city" : "PELKIE", "loc" : [ -88.625083, 46.794932 ], "pop" : 1583, "state" : "MI" }
+{ "_id" : "49962", "city" : "SKANEE", "loc" : [ -88.17318899999999, 46.874732 ], "pop" : 310, "state" : "MI" }
+{ "_id" : "49965", "city" : "TOIVOLA", "loc" : [ -88.860657, 46.985447 ], "pop" : 352, "state" : "MI" }
+{ "_id" : "49967", "city" : "TROUT CREEK", "loc" : [ -89.026962, 46.486426 ], "pop" : 480, "state" : "MI" }
+{ "_id" : "49968", "city" : "WAKEFIELD", "loc" : [ -89.942446, 46.475184 ], "pop" : 3043, "state" : "MI" }
+{ "_id" : "49969", "city" : "WATERSMEET", "loc" : [ -89.210836, 46.25416 ], "pop" : 1048, "state" : "MI" }
+{ "_id" : "49970", "city" : "WATTON", "loc" : [ -88.599298, 46.513698 ], "pop" : 391, "state" : "MI" }
+{ "_id" : "50001", "city" : "ACKWORTH", "loc" : [ -93.37671899999999, 41.37372 ], "pop" : 491, "state" : "IA" }
+{ "_id" : "50002", "city" : "ADAIR", "loc" : [ -94.644363, 41.513687 ], "pop" : 1748, "state" : "IA" }
+{ "_id" : "50003", "city" : "ADEL", "loc" : [ -94.037965, 41.62214 ], "pop" : 4884, "state" : "IA" }
+{ "_id" : "50005", "city" : "ALBION", "loc" : [ -92.98821, 42.11427 ], "pop" : 773, "state" : "IA" }
+{ "_id" : "50006", "city" : "ALDEN", "loc" : [ -93.384123, 42.51789 ], "pop" : 1374, "state" : "IA" }
+{ "_id" : "50007", "city" : "ALLEMAN", "loc" : [ -93.60630500000001, 41.815886 ], "pop" : 449, "state" : "IA" }
+{ "_id" : "50008", "city" : "ALLERTON", "loc" : [ -93.37239, 40.702301 ], "pop" : 805, "state" : "IA" }
+{ "_id" : "50009", "city" : "ALTOONA", "loc" : [ -93.472415, 41.647549 ], "pop" : 7546, "state" : "IA" }
+{ "_id" : "50010", "city" : "AMES", "loc" : [ -93.639398, 42.029859 ], "pop" : 52105, "state" : "IA" }
+{ "_id" : "50020", "city" : "ANITA", "loc" : [ -94.77940099999999, 41.449973 ], "pop" : 1529, "state" : "IA" }
+{ "_id" : "50021", "city" : "ANKENY", "loc" : [ -93.602175, 41.72755 ], "pop" : 20465, "state" : "IA" }
+{ "_id" : "50022", "city" : "ATLANTIC", "loc" : [ -95.01012299999999, 41.400279 ], "pop" : 8468, "state" : "IA" }
+{ "_id" : "50025", "city" : "AUDUBON", "loc" : [ -94.91641199999999, 41.730032 ], "pop" : 4034, "state" : "IA" }
+{ "_id" : "50026", "city" : "BAGLEY", "loc" : [ -94.441535, 41.834053 ], "pop" : 568, "state" : "IA" }
+{ "_id" : "50027", "city" : "BARNES CITY", "loc" : [ -92.470338, 41.488269 ], "pop" : 355, "state" : "IA" }
+{ "_id" : "50028", "city" : "BAXTER", "loc" : [ -93.158332, 41.820369 ], "pop" : 1381, "state" : "IA" }
+{ "_id" : "50029", "city" : "BAYARD", "loc" : [ -94.591533, 41.838599 ], "pop" : 971, "state" : "IA" }
+{ "_id" : "50030", "city" : "BEACONSFIELD", "loc" : [ -94.075126, 40.778431 ], "pop" : 195, "state" : "IA" }
+{ "_id" : "50031", "city" : "BEAVER", "loc" : [ -94.103309, 42.039936 ], "pop" : 501, "state" : "IA" }
+{ "_id" : "50033", "city" : "BEVINGTON", "loc" : [ -93.812865, 41.371763 ], "pop" : 273, "state" : "IA" }
+{ "_id" : "50034", "city" : "BLAIRSBURG", "loc" : [ -93.65944399999999, 42.493725 ], "pop" : 458, "state" : "IA" }
+{ "_id" : "50035", "city" : "BONDURANT", "loc" : [ -93.45268900000001, 41.70166 ], "pop" : 2666, "state" : "IA" }
+{ "_id" : "50036", "city" : "BOONE", "loc" : [ -93.878083, 42.069354 ], "pop" : 14773, "state" : "IA" }
+{ "_id" : "50038", "city" : "BOONEVILLE", "loc" : [ -93.88135699999999, 41.533987 ], "pop" : 100, "state" : "IA" }
+{ "_id" : "50039", "city" : "BOUTON", "loc" : [ -93.996286, 41.828432 ], "pop" : 552, "state" : "IA" }
+{ "_id" : "50040", "city" : "BOXHOLM", "loc" : [ -94.10524599999999, 42.170567 ], "pop" : 437, "state" : "IA" }
+{ "_id" : "50041", "city" : "BRADFORD", "loc" : [ -93.218068, 42.610434 ], "pop" : 406, "state" : "IA" }
+{ "_id" : "50042", "city" : "BRAYTON", "loc" : [ -94.974017, 41.55236 ], "pop" : 416, "state" : "IA" }
+{ "_id" : "50044", "city" : "BUSSEY", "loc" : [ -92.896252, 41.209422 ], "pop" : 707, "state" : "IA" }
+{ "_id" : "50046", "city" : "CAMBRIDGE", "loc" : [ -93.53053800000001, 41.90251 ], "pop" : 1103, "state" : "IA" }
+{ "_id" : "50047", "city" : "CARLISLE", "loc" : [ -93.49214000000001, 41.481384 ], "pop" : 5109, "state" : "IA" }
+{ "_id" : "50048", "city" : "CASEY", "loc" : [ -94.414475, 41.496116 ], "pop" : 1822, "state" : "IA" }
+{ "_id" : "50049", "city" : "CHARITON", "loc" : [ -93.30419000000001, 41.022638 ], "pop" : 6836, "state" : "IA" }
+{ "_id" : "50050", "city" : "CHURDAN", "loc" : [ -94.493346, 42.161402 ], "pop" : 797, "state" : "IA" }
+{ "_id" : "50051", "city" : "CLEMONS", "loc" : [ -93.16878, 42.090041 ], "pop" : 557, "state" : "IA" }
+{ "_id" : "50052", "city" : "CLIO", "loc" : [ -93.48644299999999, 40.680261 ], "pop" : 125, "state" : "IA" }
+{ "_id" : "50054", "city" : "COLFAX", "loc" : [ -93.258816, 41.678785 ], "pop" : 3475, "state" : "IA" }
+{ "_id" : "50055", "city" : "COLLINS", "loc" : [ -93.300808, 41.903226 ], "pop" : 764, "state" : "IA" }
+{ "_id" : "50056", "city" : "COLO", "loc" : [ -93.307114, 42.013102 ], "pop" : 1293, "state" : "IA" }
+{ "_id" : "50057", "city" : "COLUMBIA", "loc" : [ -93.15821699999999, 41.183814 ], "pop" : 304, "state" : "IA" }
+{ "_id" : "50058", "city" : "COON RAPIDS", "loc" : [ -94.679979, 41.893957 ], "pop" : 1802, "state" : "IA" }
+{ "_id" : "50059", "city" : "COOPER", "loc" : [ -94.339073, 41.903433 ], "pop" : 170, "state" : "IA" }
+{ "_id" : "50060", "city" : "SEWAL", "loc" : [ -93.322549, 40.76131 ], "pop" : 2617, "state" : "IA" }
+{ "_id" : "50061", "city" : "CUMMING", "loc" : [ -93.75386, 41.484876 ], "pop" : 635, "state" : "IA" }
+{ "_id" : "50062", "city" : "DALLAS", "loc" : [ -93.253525, 41.221332 ], "pop" : 996, "state" : "IA" }
+{ "_id" : "50063", "city" : "DALLAS CENTER", "loc" : [ -93.970657, 41.686248 ], "pop" : 1838, "state" : "IA" }
+{ "_id" : "50064", "city" : "DANA", "loc" : [ -94.232212, 42.10634 ], "pop" : 131, "state" : "IA" }
+{ "_id" : "50065", "city" : "PLEASANTON", "loc" : [ -93.807022, 40.632075 ], "pop" : 762, "state" : "IA" }
+{ "_id" : "50066", "city" : "DAWSON", "loc" : [ -94.217127, 41.832396 ], "pop" : 434, "state" : "IA" }
+{ "_id" : "50067", "city" : "DECATUR", "loc" : [ -93.832598, 40.755258 ], "pop" : 394, "state" : "IA" }
+{ "_id" : "50068", "city" : "DERBY", "loc" : [ -93.47959, 40.935476 ], "pop" : 339, "state" : "IA" }
+{ "_id" : "50069", "city" : "DE SOTO", "loc" : [ -94.027582, 41.533285 ], "pop" : 1535, "state" : "IA" }
+{ "_id" : "50070", "city" : "DEXTER", "loc" : [ -94.2145, 41.519806 ], "pop" : 824, "state" : "IA" }
+{ "_id" : "50071", "city" : "DOWS", "loc" : [ -93.50580100000001, 42.661026 ], "pop" : 1373, "state" : "IA" }
+{ "_id" : "50072", "city" : "EARLHAM", "loc" : [ -94.12944299999999, 41.470916 ], "pop" : 2010, "state" : "IA" }
+{ "_id" : "50073", "city" : "ELKHART", "loc" : [ -93.48545799999999, 41.811384 ], "pop" : 1374, "state" : "IA" }
+{ "_id" : "50074", "city" : "ELLSTON", "loc" : [ -94.08411599999999, 40.850485 ], "pop" : 286, "state" : "IA" }
+{ "_id" : "50075", "city" : "ELLSWORTH", "loc" : [ -93.548979, 42.30086 ], "pop" : 1129, "state" : "IA" }
+{ "_id" : "50076", "city" : "EXIRA", "loc" : [ -94.857145, 41.576771 ], "pop" : 1590, "state" : "IA" }
+{ "_id" : "50101", "city" : "GALT", "loc" : [ -93.60351199999999, 42.691187 ], "pop" : 57, "state" : "IA" }
+{ "_id" : "50102", "city" : "GARDEN CITY", "loc" : [ -93.403068, 42.25266 ], "pop" : 422, "state" : "IA" }
+{ "_id" : "50103", "city" : "GARDEN GROVE", "loc" : [ -93.61166900000001, 40.771078 ], "pop" : 603, "state" : "IA" }
+{ "_id" : "50104", "city" : "GIBSON", "loc" : [ -92.353121, 41.464206 ], "pop" : 458, "state" : "IA" }
+{ "_id" : "50106", "city" : "GILMAN", "loc" : [ -92.810067, 41.901236 ], "pop" : 1221, "state" : "IA" }
+{ "_id" : "50107", "city" : "GRAND JUNCTION", "loc" : [ -94.23362899999999, 42.029578 ], "pop" : 1055, "state" : "IA" }
+{ "_id" : "50108", "city" : "GRAND RIVER", "loc" : [ -93.95437200000001, 40.813704 ], "pop" : 454, "state" : "IA" }
+{ "_id" : "50109", "city" : "GRANGER", "loc" : [ -93.841002, 41.752355 ], "pop" : 1324, "state" : "IA" }
+{ "_id" : "50110", "city" : "GRAY", "loc" : [ -95.02272000000001, 41.82663 ], "pop" : 344, "state" : "IA" }
+{ "_id" : "50111", "city" : "GRIMES", "loc" : [ -93.78210900000001, 41.701838 ], "pop" : 4205, "state" : "IA" }
+{ "_id" : "50112", "city" : "GRINNELL", "loc" : [ -92.734432, 41.742081 ], "pop" : 11530, "state" : "IA" }
+{ "_id" : "50115", "city" : "GUTHRIE CENTER", "loc" : [ -94.48644400000001, 41.683671 ], "pop" : 3398, "state" : "IA" }
+{ "_id" : "50116", "city" : "HAMILTON", "loc" : [ -92.92434900000001, 41.175543 ], "pop" : 314, "state" : "IA" }
+{ "_id" : "50117", "city" : "HAMLIN", "loc" : [ -94.915745, 41.650571 ], "pop" : 336, "state" : "IA" }
+{ "_id" : "50118", "city" : "HARTFORD", "loc" : [ -93.402213, 41.459629 ], "pop" : 1201, "state" : "IA" }
+{ "_id" : "50119", "city" : "HARVEY", "loc" : [ -92.931843, 41.302972 ], "pop" : 683, "state" : "IA" }
+{ "_id" : "50120", "city" : "HAVERHILL", "loc" : [ -92.945857, 41.93196 ], "pop" : 419, "state" : "IA" }
+{ "_id" : "50122", "city" : "HUBBARD", "loc" : [ -93.29392799999999, 42.302208 ], "pop" : 1356, "state" : "IA" }
+{ "_id" : "50123", "city" : "HUMESTON", "loc" : [ -93.51011699999999, 40.846922 ], "pop" : 981, "state" : "IA" }
+{ "_id" : "50124", "city" : "HUXLEY", "loc" : [ -93.60238099999999, 41.899434 ], "pop" : 2417, "state" : "IA" }
+{ "_id" : "50125", "city" : "SPRING HILL", "loc" : [ -93.571502, 41.35617 ], "pop" : 13920, "state" : "IA" }
+{ "_id" : "50126", "city" : "IOWA FALLS", "loc" : [ -93.270943, 42.513756 ], "pop" : 7714, "state" : "IA" }
+{ "_id" : "50127", "city" : "IRA", "loc" : [ -93.16443599999999, 41.731759 ], "pop" : 378, "state" : "IA" }
+{ "_id" : "50128", "city" : "JAMAICA", "loc" : [ -94.320367, 41.841931 ], "pop" : 423, "state" : "IA" }
+{ "_id" : "50129", "city" : "JEFFERSON", "loc" : [ -94.388768, 42.009325 ], "pop" : 5663, "state" : "IA" }
+{ "_id" : "50130", "city" : "JEWELL", "loc" : [ -93.642821, 42.313912 ], "pop" : 1348, "state" : "IA" }
+{ "_id" : "50131", "city" : "JOHNSTON", "loc" : [ -93.702792, 41.673017 ], "pop" : 4945, "state" : "IA" }
+{ "_id" : "50132", "city" : "KAMRAR", "loc" : [ -93.727941, 42.394517 ], "pop" : 246, "state" : "IA" }
+{ "_id" : "50133", "city" : "KELLERTON", "loc" : [ -94.060693, 40.686127 ], "pop" : 601, "state" : "IA" }
+{ "_id" : "50134", "city" : "KELLEY", "loc" : [ -93.664354, 41.948773 ], "pop" : 314, "state" : "IA" }
+{ "_id" : "50135", "city" : "KELLOGG", "loc" : [ -92.911404, 41.718371 ], "pop" : 913, "state" : "IA" }
+{ "_id" : "50136", "city" : "KESWICK", "loc" : [ -92.239547, 41.461251 ], "pop" : 497, "state" : "IA" }
+{ "_id" : "50138", "city" : "KNOXVILLE", "loc" : [ -93.095427, 41.316446 ], "pop" : 11205, "state" : "IA" }
+{ "_id" : "50139", "city" : "LACONA", "loc" : [ -93.38380100000001, 41.198832 ], "pop" : 700, "state" : "IA" }
+{ "_id" : "50140", "city" : "LAMONI", "loc" : [ -93.934899, 40.622852 ], "pop" : 2638, "state" : "IA" }
+{ "_id" : "50141", "city" : "LAUREL", "loc" : [ -92.926294, 41.882904 ], "pop" : 457, "state" : "IA" }
+{ "_id" : "50143", "city" : "LEIGHTON", "loc" : [ -92.808125, 41.364677 ], "pop" : 594, "state" : "IA" }
+{ "_id" : "50144", "city" : "LEON", "loc" : [ -93.742903, 40.737334 ], "pop" : 2556, "state" : "IA" }
+{ "_id" : "50145", "city" : "LIBERTY CENTER", "loc" : [ -93.49739099999999, 41.207668 ], "pop" : 468, "state" : "IA" }
+{ "_id" : "50146", "city" : "LINDEN", "loc" : [ -94.24057999999999, 41.64225 ], "pop" : 585, "state" : "IA" }
+{ "_id" : "50147", "city" : "LINEVILLE", "loc" : [ -93.48620699999999, 40.600373 ], "pop" : 586, "state" : "IA" }
+{ "_id" : "50148", "city" : "LISCOMB", "loc" : [ -92.983279, 42.184 ], "pop" : 512, "state" : "IA" }
+{ "_id" : "50149", "city" : "LORIMOR", "loc" : [ -94.063885, 41.1233 ], "pop" : 619, "state" : "IA" }
+{ "_id" : "50150", "city" : "LOVILIA", "loc" : [ -92.929272, 41.12719 ], "pop" : 1053, "state" : "IA" }
+{ "_id" : "50151", "city" : "LUCAS", "loc" : [ -93.483614, 41.058451 ], "pop" : 617, "state" : "IA" }
+{ "_id" : "50152", "city" : "LUTHER", "loc" : [ -93.855394, 41.991934 ], "pop" : 529, "state" : "IA" }
+{ "_id" : "50153", "city" : "LYNNVILLE", "loc" : [ -92.78771500000001, 41.569766 ], "pop" : 630, "state" : "IA" }
+{ "_id" : "50154", "city" : "MC CALLSBURG", "loc" : [ -93.397757, 42.166475 ], "pop" : 533, "state" : "IA" }
+{ "_id" : "50155", "city" : "MACKSBURG", "loc" : [ -94.18567299999999, 41.202792 ], "pop" : 310, "state" : "IA" }
+{ "_id" : "50156", "city" : "MADRID", "loc" : [ -93.844815, 41.884083 ], "pop" : 4367, "state" : "IA" }
+{ "_id" : "50157", "city" : "MALCOM", "loc" : [ -92.535426, 41.769502 ], "pop" : 1595, "state" : "IA" }
+{ "_id" : "50158", "city" : "MARSHALLTOWN", "loc" : [ -92.91269, 42.040482 ], "pop" : 30857, "state" : "IA" }
+{ "_id" : "50161", "city" : "MAXWELL", "loc" : [ -93.400125, 41.89673 ], "pop" : 1268, "state" : "IA" }
+{ "_id" : "50162", "city" : "MELBOURNE", "loc" : [ -93.085627, 41.932348 ], "pop" : 970, "state" : "IA" }
+{ "_id" : "50163", "city" : "MELCHER-DALLAS", "loc" : [ -93.219404, 41.222912 ], "pop" : 924, "state" : "IA" }
+{ "_id" : "50164", "city" : "MENLO", "loc" : [ -94.409002, 41.534797 ], "pop" : 650, "state" : "IA" }
+{ "_id" : "50165", "city" : "MILLERTON", "loc" : [ -93.27958599999999, 40.854889 ], "pop" : 258, "state" : "IA" }
+{ "_id" : "50166", "city" : "MILO", "loc" : [ -93.445356, 41.29042 ], "pop" : 1705, "state" : "IA" }
+{ "_id" : "50167", "city" : "MINBURN", "loc" : [ -94.01501, 41.756206 ], "pop" : 517, "state" : "IA" }
+{ "_id" : "50168", "city" : "MINGO", "loc" : [ -93.288015, 41.789843 ], "pop" : 725, "state" : "IA" }
+{ "_id" : "50169", "city" : "MITCHELLVILLE", "loc" : [ -93.36995, 41.66089 ], "pop" : 2363, "state" : "IA" }
+{ "_id" : "50170", "city" : "MONROE", "loc" : [ -93.072551, 41.535619 ], "pop" : 2868, "state" : "IA" }
+{ "_id" : "50171", "city" : "MONTEZUMA", "loc" : [ -92.527582, 41.592845 ], "pop" : 3570, "state" : "IA" }
+{ "_id" : "50172", "city" : "GUERNSEY", "loc" : [ -92.333549, 41.662496 ], "pop" : 128, "state" : "IA" }
+{ "_id" : "50173", "city" : "MONTOUR", "loc" : [ -92.700575, 41.970876 ], "pop" : 1137, "state" : "IA" }
+{ "_id" : "50174", "city" : "MURRAY", "loc" : [ -93.952975, 41.037644 ], "pop" : 1357, "state" : "IA" }
+{ "_id" : "50201", "city" : "NEVADA", "loc" : [ -93.446219, 42.018983 ], "pop" : 7381, "state" : "IA" }
+{ "_id" : "50206", "city" : "NEW PROVIDENCE", "loc" : [ -93.175262, 42.269261 ], "pop" : 445, "state" : "IA" }
+{ "_id" : "50207", "city" : "NEW SHARON", "loc" : [ -92.684815, 41.463976 ], "pop" : 2426, "state" : "IA" }
+{ "_id" : "50208", "city" : "NEWTON", "loc" : [ -93.045456, 41.699173 ], "pop" : 19721, "state" : "IA" }
+{ "_id" : "50210", "city" : "NEW VIRGINIA", "loc" : [ -93.71131200000001, 41.160063 ], "pop" : 1593, "state" : "IA" }
+{ "_id" : "50211", "city" : "NORWALK", "loc" : [ -93.657332, 41.486055 ], "pop" : 9512, "state" : "IA" }
+{ "_id" : "50212", "city" : "OGDEN", "loc" : [ -94.006333, 42.035106 ], "pop" : 3115, "state" : "IA" }
+{ "_id" : "50213", "city" : "OSCEOLA", "loc" : [ -93.771236, 41.029503 ], "pop" : 5528, "state" : "IA" }
+{ "_id" : "50214", "city" : "OTLEY", "loc" : [ -93.034778, 41.451806 ], "pop" : 676, "state" : "IA" }
+{ "_id" : "50216", "city" : "PANORA", "loc" : [ -94.360613, 41.696684 ], "pop" : 1847, "state" : "IA" }
+{ "_id" : "50217", "city" : "PATON", "loc" : [ -94.273038, 42.165841 ], "pop" : 621, "state" : "IA" }
+{ "_id" : "50218", "city" : "PATTERSON", "loc" : [ -93.878174, 41.353912 ], "pop" : 258, "state" : "IA" }
+{ "_id" : "50219", "city" : "PELLA", "loc" : [ -92.917207, 41.408175 ], "pop" : 10771, "state" : "IA" }
+{ "_id" : "50220", "city" : "PERRY", "loc" : [ -94.10216699999999, 41.839695 ], "pop" : 7918, "state" : "IA" }
+{ "_id" : "50222", "city" : "PERU", "loc" : [ -93.943729, 41.21454 ], "pop" : 442, "state" : "IA" }
+{ "_id" : "50223", "city" : "PILOT MOUND", "loc" : [ -94.010184, 42.160395 ], "pop" : 380, "state" : "IA" }
+{ "_id" : "50225", "city" : "PLEASANTVILLE", "loc" : [ -93.27120600000001, 41.373836 ], "pop" : 2474, "state" : "IA" }
+{ "_id" : "50226", "city" : "POLK CITY", "loc" : [ -93.689346, 41.754905 ], "pop" : 4203, "state" : "IA" }
+{ "_id" : "50227", "city" : "POPEJOY", "loc" : [ -93.43086700000001, 42.595628 ], "pop" : 298, "state" : "IA" }
+{ "_id" : "50228", "city" : "PRAIRIE CITY", "loc" : [ -93.24098600000001, 41.585425 ], "pop" : 1941, "state" : "IA" }
+{ "_id" : "50229", "city" : "PROLE", "loc" : [ -93.734357, 41.382973 ], "pop" : 1488, "state" : "IA" }
+{ "_id" : "50230", "city" : "RADCLIFFE", "loc" : [ -93.42336400000001, 42.324064 ], "pop" : 804, "state" : "IA" }
+{ "_id" : "50231", "city" : "RANDALL", "loc" : [ -93.62109, 42.247463 ], "pop" : 508, "state" : "IA" }
+{ "_id" : "50232", "city" : "REASNOR", "loc" : [ -93.01982700000001, 41.579802 ], "pop" : 245, "state" : "IA" }
+{ "_id" : "50233", "city" : "REDFIELD", "loc" : [ -94.189733, 41.587349 ], "pop" : 1236, "state" : "IA" }
+{ "_id" : "50234", "city" : "RHODES", "loc" : [ -93.179586, 41.917717 ], "pop" : 564, "state" : "IA" }
+{ "_id" : "50235", "city" : "RIPPEY", "loc" : [ -94.213202, 41.92574 ], "pop" : 563, "state" : "IA" }
+{ "_id" : "50236", "city" : "ROLAND", "loc" : [ -93.50631300000001, 42.164585 ], "pop" : 1452, "state" : "IA" }
+{ "_id" : "50237", "city" : "RUNNELLS", "loc" : [ -93.42025, 41.551549 ], "pop" : 2309, "state" : "IA" }
+{ "_id" : "50238", "city" : "RUSSELL", "loc" : [ -93.178371, 40.945557 ], "pop" : 1018, "state" : "IA" }
+{ "_id" : "50239", "city" : "SAINT ANTHONY", "loc" : [ -93.18243099999999, 42.151974 ], "pop" : 328, "state" : "IA" }
+{ "_id" : "50240", "city" : "SAINT CHARLES", "loc" : [ -93.824195, 41.292443 ], "pop" : 1169, "state" : "IA" }
+{ "_id" : "50241", "city" : "SAINT MARYS", "loc" : [ -93.736107, 41.297826 ], "pop" : 632, "state" : "IA" }
+{ "_id" : "50242", "city" : "SEARSBORO", "loc" : [ -92.69873699999999, 41.56561 ], "pop" : 464, "state" : "IA" }
+{ "_id" : "50244", "city" : "SLATER", "loc" : [ -93.681155, 41.876511 ], "pop" : 2083, "state" : "IA" }
+{ "_id" : "50246", "city" : "STANHOPE", "loc" : [ -93.775081, 42.290407 ], "pop" : 1001, "state" : "IA" }
+{ "_id" : "50247", "city" : "STATE CENTER", "loc" : [ -93.167283, 42.010911 ], "pop" : 1618, "state" : "IA" }
+{ "_id" : "50248", "city" : "STORY CITY", "loc" : [ -93.598811, 42.183487 ], "pop" : 3501, "state" : "IA" }
+{ "_id" : "50249", "city" : "STRATFORD", "loc" : [ -93.90294, 42.284673 ], "pop" : 1215, "state" : "IA" }
+{ "_id" : "50250", "city" : "STUART", "loc" : [ -94.304563, 41.518643 ], "pop" : 1463, "state" : "IA" }
+{ "_id" : "50251", "city" : "SULLY", "loc" : [ -92.845085, 41.573969 ], "pop" : 1096, "state" : "IA" }
+{ "_id" : "50252", "city" : "SWAN", "loc" : [ -93.234165, 41.4717 ], "pop" : 691, "state" : "IA" }
+{ "_id" : "50254", "city" : "THAYER", "loc" : [ -94.068639, 41.00293 ], "pop" : 453, "state" : "IA" }
+{ "_id" : "50256", "city" : "TRACY", "loc" : [ -92.875337, 41.275564 ], "pop" : 256, "state" : "IA" }
+{ "_id" : "50257", "city" : "TRURO", "loc" : [ -93.84097800000001, 41.207622 ], "pop" : 767, "state" : "IA" }
+{ "_id" : "50258", "city" : "UNION", "loc" : [ -93.056192, 42.252074 ], "pop" : 937, "state" : "IA" }
+{ "_id" : "50261", "city" : "VAN METER", "loc" : [ -93.95303, 41.539415 ], "pop" : 1780, "state" : "IA" }
+{ "_id" : "50262", "city" : "VAN WERT", "loc" : [ -93.80732999999999, 40.864451 ], "pop" : 431, "state" : "IA" }
+{ "_id" : "50263", "city" : "WAUKEE", "loc" : [ -93.85916, 41.592959 ], "pop" : 4933, "state" : "IA" }
+{ "_id" : "50264", "city" : "WELDON", "loc" : [ -93.738743, 40.873906 ], "pop" : 388, "state" : "IA" }
+{ "_id" : "50265", "city" : "WEST DES MOINES", "loc" : [ -93.744711, 41.580512 ], "pop" : 31896, "state" : "IA" }
+{ "_id" : "50268", "city" : "WHAT CHEER", "loc" : [ -92.354789, 41.395276 ], "pop" : 1108, "state" : "IA" }
+{ "_id" : "50271", "city" : "WILLIAMS", "loc" : [ -93.56774, 42.461376 ], "pop" : 1036, "state" : "IA" }
+{ "_id" : "50272", "city" : "WILLIAMSON", "loc" : [ -93.26593, 41.102026 ], "pop" : 505, "state" : "IA" }
+{ "_id" : "50273", "city" : "WINTERSET", "loc" : [ -94.008763, 41.339077 ], "pop" : 7254, "state" : "IA" }
+{ "_id" : "50274", "city" : "WIOTA", "loc" : [ -94.840515, 41.384552 ], "pop" : 596, "state" : "IA" }
+{ "_id" : "50275", "city" : "WOODBURN", "loc" : [ -93.608282, 41.00001 ], "pop" : 677, "state" : "IA" }
+{ "_id" : "50276", "city" : "WOODWARD", "loc" : [ -93.90561700000001, 41.845219 ], "pop" : 1749, "state" : "IA" }
+{ "_id" : "50277", "city" : "YALE", "loc" : [ -94.35026000000001, 41.775309 ], "pop" : 414, "state" : "IA" }
+{ "_id" : "50278", "city" : "ZEARING", "loc" : [ -93.292766, 42.15349 ], "pop" : 1032, "state" : "IA" }
+{ "_id" : "50309", "city" : "DES MOINES", "loc" : [ -93.62117499999999, 41.588743 ], "pop" : 4879, "state" : "IA" }
+{ "_id" : "50310", "city" : "DES MOINES", "loc" : [ -93.67361099999999, 41.625475 ], "pop" : 30498, "state" : "IA" }
+{ "_id" : "50311", "city" : "WINDSOR HEIGHTS", "loc" : [ -93.67437099999999, 41.601562 ], "pop" : 19816, "state" : "IA" }
+{ "_id" : "50312", "city" : "DES MOINES", "loc" : [ -93.671908, 41.585453 ], "pop" : 16424, "state" : "IA" }
+{ "_id" : "50313", "city" : "DES MOINES", "loc" : [ -93.620305, 41.638085 ], "pop" : 16175, "state" : "IA" }
+{ "_id" : "50314", "city" : "DES MOINES", "loc" : [ -93.632993, 41.603003 ], "pop" : 11709, "state" : "IA" }
+{ "_id" : "50315", "city" : "DES MOINES", "loc" : [ -93.619226, 41.544394 ], "pop" : 36434, "state" : "IA" }
+{ "_id" : "50316", "city" : "DES MOINES", "loc" : [ -93.59996599999999, 41.609228 ], "pop" : 16359, "state" : "IA" }
+{ "_id" : "50317", "city" : "PLEASANT HILL", "loc" : [ -93.549446, 41.612499 ], "pop" : 39883, "state" : "IA" }
+{ "_id" : "50320", "city" : "DES MOINES", "loc" : [ -93.582674, 41.548693 ], "pop" : 8444, "state" : "IA" }
+{ "_id" : "50321", "city" : "DES MOINES", "loc" : [ -93.661846, 41.547628 ], "pop" : 7233, "state" : "IA" }
+{ "_id" : "50322", "city" : "URBANDALE", "loc" : [ -93.72304200000001, 41.629479 ], "pop" : 28512, "state" : "IA" }
+{ "_id" : "50325", "city" : "CLIVE", "loc" : [ -93.745749, 41.606729 ], "pop" : 7293, "state" : "IA" }
+{ "_id" : "50401", "city" : "MASON CITY", "loc" : [ -93.195379, 43.149869 ], "pop" : 31168, "state" : "IA" }
+{ "_id" : "50420", "city" : "ALEXANDER", "loc" : [ -93.44499999999999, 42.811395 ], "pop" : 664, "state" : "IA" }
+{ "_id" : "50421", "city" : "BELMOND", "loc" : [ -93.620012, 42.851137 ], "pop" : 3306, "state" : "IA" }
+{ "_id" : "50423", "city" : "BRITT", "loc" : [ -93.775175, 43.100582 ], "pop" : 3988, "state" : "IA" }
+{ "_id" : "50424", "city" : "BUFFALO CENTER", "loc" : [ -93.937557, 43.373204 ], "pop" : 1566, "state" : "IA" }
+{ "_id" : "50428", "city" : "CLEAR LAKE", "loc" : [ -93.384978, 43.140607 ], "pop" : 10056, "state" : "IA" }
+{ "_id" : "50430", "city" : "CORWITH", "loc" : [ -93.932303, 42.992736 ], "pop" : 737, "state" : "IA" }
+{ "_id" : "50432", "city" : "CRYSTAL LAKE", "loc" : [ -93.794166, 43.218692 ], "pop" : 543, "state" : "IA" }
+{ "_id" : "50433", "city" : "DOUGHERTY", "loc" : [ -93.068586, 42.941633 ], "pop" : 308, "state" : "IA" }
+{ "_id" : "50434", "city" : "FERTILE", "loc" : [ -93.434485, 43.279514 ], "pop" : 766, "state" : "IA" }
+{ "_id" : "50435", "city" : "FLOYD", "loc" : [ -92.72398800000001, 43.143049 ], "pop" : 1273, "state" : "IA" }
+{ "_id" : "50436", "city" : "FOREST CITY", "loc" : [ -93.635595, 43.269184 ], "pop" : 6010, "state" : "IA" }
+{ "_id" : "50438", "city" : "GARNER", "loc" : [ -93.59439399999999, 43.114395 ], "pop" : 3756, "state" : "IA" }
+{ "_id" : "50439", "city" : "GOODELL", "loc" : [ -93.582426, 42.938298 ], "pop" : 452, "state" : "IA" }
+{ "_id" : "50440", "city" : "GRAFTON", "loc" : [ -93.079718, 43.311016 ], "pop" : 630, "state" : "IA" }
+{ "_id" : "50441", "city" : "HAMPTON", "loc" : [ -93.210954, 42.740531 ], "pop" : 5313, "state" : "IA" }
+{ "_id" : "50444", "city" : "HANLONTOWN", "loc" : [ -93.335065, 43.307234 ], "pop" : 605, "state" : "IA" }
+{ "_id" : "50446", "city" : "JOICE", "loc" : [ -93.44535399999999, 43.376105 ], "pop" : 522, "state" : "IA" }
+{ "_id" : "50447", "city" : "KANAWHA", "loc" : [ -93.772801, 42.94338 ], "pop" : 1181, "state" : "IA" }
+{ "_id" : "50448", "city" : "KENSETT", "loc" : [ -93.172805, 43.37391 ], "pop" : 729, "state" : "IA" }
+{ "_id" : "50449", "city" : "KLEMME", "loc" : [ -93.58794399999999, 43.013643 ], "pop" : 849, "state" : "IA" }
+{ "_id" : "50450", "city" : "LAKE MILLS", "loc" : [ -93.53362799999999, 43.416696 ], "pop" : 2801, "state" : "IA" }
+{ "_id" : "50451", "city" : "LAKOTA", "loc" : [ -94.07055, 43.395283 ], "pop" : 789, "state" : "IA" }
+{ "_id" : "50452", "city" : "LATIMER", "loc" : [ -93.351798, 42.759783 ], "pop" : 966, "state" : "IA" }
+{ "_id" : "50453", "city" : "LELAND", "loc" : [ -93.751496, 43.307043 ], "pop" : 333, "state" : "IA" }
+{ "_id" : "50454", "city" : "LITTLE CEDAR", "loc" : [ -92.734376, 43.391861 ], "pop" : 248, "state" : "IA" }
+{ "_id" : "50455", "city" : "MC INTIRE", "loc" : [ -92.60485, 43.44999 ], "pop" : 382, "state" : "IA" }
+{ "_id" : "50456", "city" : "MANLY", "loc" : [ -93.201802, 43.289116 ], "pop" : 1757, "state" : "IA" }
+{ "_id" : "50457", "city" : "MESERVEY", "loc" : [ -93.477298, 42.913696 ], "pop" : 298, "state" : "IA" }
+{ "_id" : "50458", "city" : "NORA SPRINGS", "loc" : [ -93.000221, 43.147858 ], "pop" : 1849, "state" : "IA" }
+{ "_id" : "50459", "city" : "NORTHWOOD", "loc" : [ -93.24194300000001, 43.450604 ], "pop" : 2982, "state" : "IA" }
+{ "_id" : "50460", "city" : "ORCHARD", "loc" : [ -92.719979, 43.235459 ], "pop" : 442, "state" : "IA" }
+{ "_id" : "50461", "city" : "OSAGE", "loc" : [ -92.814356, 43.28722 ], "pop" : 5790, "state" : "IA" }
+{ "_id" : "50464", "city" : "PLYMOUTH", "loc" : [ -93.12262800000001, 43.246046 ], "pop" : 453, "state" : "IA" }
+{ "_id" : "50465", "city" : "RAKE", "loc" : [ -93.91712800000001, 43.476655 ], "pop" : 435, "state" : "IA" }
+{ "_id" : "50466", "city" : "RICEVILLE", "loc" : [ -92.55537200000001, 43.371899 ], "pop" : 1546, "state" : "IA" }
+{ "_id" : "50467", "city" : "ROCK FALLS", "loc" : [ -93.076402, 43.198014 ], "pop" : 306, "state" : "IA" }
+{ "_id" : "50468", "city" : "ROCKFORD", "loc" : [ -92.952034, 43.057331 ], "pop" : 1258, "state" : "IA" }
+{ "_id" : "50469", "city" : "ROCKWELL", "loc" : [ -93.21673699999999, 43.003167 ], "pop" : 2009, "state" : "IA" }
+{ "_id" : "50470", "city" : "ROWAN", "loc" : [ -93.556966, 42.759644 ], "pop" : 405, "state" : "IA" }
+{ "_id" : "50471", "city" : "RUDD", "loc" : [ -92.88854600000001, 43.141958 ], "pop" : 688, "state" : "IA" }
+{ "_id" : "50472", "city" : "SAINT ANSGAR", "loc" : [ -92.923523, 43.406107 ], "pop" : 2401, "state" : "IA" }
+{ "_id" : "50473", "city" : "SCARVILLE", "loc" : [ -93.64233, 43.467286 ], "pop" : 420, "state" : "IA" }
+{ "_id" : "50475", "city" : "SHEFFIELD", "loc" : [ -93.215583, 42.877881 ], "pop" : 1988, "state" : "IA" }
+{ "_id" : "50476", "city" : "STACYVILLE", "loc" : [ -92.761031, 43.445687 ], "pop" : 798, "state" : "IA" }
+{ "_id" : "50477", "city" : "SWALEDALE", "loc" : [ -93.31152899999999, 42.962167 ], "pop" : 414, "state" : "IA" }
+{ "_id" : "50478", "city" : "THOMPSON", "loc" : [ -93.751671, 43.387497 ], "pop" : 1178, "state" : "IA" }
+{ "_id" : "50479", "city" : "THORNTON", "loc" : [ -93.408787, 42.968405 ], "pop" : 905, "state" : "IA" }
+{ "_id" : "50480", "city" : "TITONKA", "loc" : [ -94.03665599999999, 43.245606 ], "pop" : 1159, "state" : "IA" }
+{ "_id" : "50482", "city" : "VENTURA", "loc" : [ -93.4706, 43.126178 ], "pop" : 816, "state" : "IA" }
+{ "_id" : "50483", "city" : "WESLEY", "loc" : [ -94.003776, 43.09765 ], "pop" : 647, "state" : "IA" }
+{ "_id" : "50484", "city" : "WODEN", "loc" : [ -93.91092500000001, 43.222564 ], "pop" : 511, "state" : "IA" }
+{ "_id" : "50501", "city" : "FORT DODGE", "loc" : [ -94.18073699999999, 42.508817 ], "pop" : 27632, "state" : "IA" }
+{ "_id" : "50510", "city" : "ALBERT CITY", "loc" : [ -94.98238000000001, 42.778403 ], "pop" : 1293, "state" : "IA" }
+{ "_id" : "50511", "city" : "ALGONA", "loc" : [ -94.230638, 43.065976 ], "pop" : 7829, "state" : "IA" }
+{ "_id" : "50514", "city" : "ARMSTRONG", "loc" : [ -94.485305, 43.402423 ], "pop" : 1464, "state" : "IA" }
+{ "_id" : "50515", "city" : "AYRSHIRE", "loc" : [ -94.847804, 43.037001 ], "pop" : 413, "state" : "IA" }
+{ "_id" : "50516", "city" : "BADGER", "loc" : [ -94.162988, 42.599595 ], "pop" : 1270, "state" : "IA" }
+{ "_id" : "50517", "city" : "BANCROFT", "loc" : [ -94.210778, 43.293485 ], "pop" : 1346, "state" : "IA" }
+{ "_id" : "50518", "city" : "BARNUM", "loc" : [ -94.370327, 42.515867 ], "pop" : 481, "state" : "IA" }
+{ "_id" : "50519", "city" : "BODE", "loc" : [ -94.27805499999999, 42.866078 ], "pop" : 555, "state" : "IA" }
+{ "_id" : "50520", "city" : "BRADGATE", "loc" : [ -94.400239, 42.779425 ], "pop" : 359, "state" : "IA" }
+{ "_id" : "50521", "city" : "BURNSIDE", "loc" : [ -94.11425300000001, 42.341318 ], "pop" : 355, "state" : "IA" }
+{ "_id" : "50522", "city" : "BURT", "loc" : [ -94.21223000000001, 43.206167 ], "pop" : 1069, "state" : "IA" }
+{ "_id" : "50523", "city" : "CALLENDER", "loc" : [ -94.281963, 42.349372 ], "pop" : 1009, "state" : "IA" }
+{ "_id" : "50524", "city" : "CLARE", "loc" : [ -94.30802799999999, 42.595397 ], "pop" : 821, "state" : "IA" }
+{ "_id" : "50525", "city" : "CLARION", "loc" : [ -93.727715, 42.727149 ], "pop" : 3849, "state" : "IA" }
+{ "_id" : "50527", "city" : "CURLEW", "loc" : [ -94.797528, 42.963321 ], "pop" : 278, "state" : "IA" }
+{ "_id" : "50528", "city" : "CYLINDER", "loc" : [ -94.510672, 43.150716 ], "pop" : 536, "state" : "IA" }
+{ "_id" : "50530", "city" : "DAYTON", "loc" : [ -94.06104999999999, 42.259438 ], "pop" : 1366, "state" : "IA" }
+{ "_id" : "50531", "city" : "DOLLIVER", "loc" : [ -94.624236, 43.466382 ], "pop" : 260, "state" : "IA" }
+{ "_id" : "50532", "city" : "DUNCOMBE", "loc" : [ -94.059212, 42.449303 ], "pop" : 1561, "state" : "IA" }
+{ "_id" : "50533", "city" : "EAGLE GROVE", "loc" : [ -93.904872, 42.660867 ], "pop" : 4109, "state" : "IA" }
+{ "_id" : "50535", "city" : "EARLY", "loc" : [ -95.172569, 42.448258 ], "pop" : 1195, "state" : "IA" }
+{ "_id" : "50536", "city" : "EMMETSBURG", "loc" : [ -94.682545, 43.108249 ], "pop" : 4794, "state" : "IA" }
+{ "_id" : "50538", "city" : "FARNHAMVILLE", "loc" : [ -94.422623, 42.269234 ], "pop" : 631, "state" : "IA" }
+{ "_id" : "50539", "city" : "FENTON", "loc" : [ -94.404366, 43.242047 ], "pop" : 779, "state" : "IA" }
+{ "_id" : "50540", "city" : "FONDA", "loc" : [ -94.82974, 42.605148 ], "pop" : 1438, "state" : "IA" }
+{ "_id" : "50541", "city" : "GILMORE CITY", "loc" : [ -94.41082400000001, 42.706691 ], "pop" : 604, "state" : "IA" }
+{ "_id" : "50542", "city" : "GOLDFIELD", "loc" : [ -93.91943499999999, 42.758055 ], "pop" : 1148, "state" : "IA" }
+{ "_id" : "50543", "city" : "GOWRIE", "loc" : [ -94.298669, 42.276712 ], "pop" : 1225, "state" : "IA" }
+{ "_id" : "50544", "city" : "HARCOURT", "loc" : [ -94.196095, 42.253052 ], "pop" : 631, "state" : "IA" }
+{ "_id" : "50545", "city" : "HARDY", "loc" : [ -94.030852, 42.782247 ], "pop" : 262, "state" : "IA" }
+{ "_id" : "50546", "city" : "HAVELOCK", "loc" : [ -94.725233, 42.84109 ], "pop" : 586, "state" : "IA" }
+{ "_id" : "50548", "city" : "HUMBOLDT", "loc" : [ -94.213184, 42.719574 ], "pop" : 6493, "state" : "IA" }
+{ "_id" : "50551", "city" : "JOLLEY", "loc" : [ -94.742338, 42.507785 ], "pop" : 296, "state" : "IA" }
+{ "_id" : "50552", "city" : "KNIERIM", "loc" : [ -94.453153, 42.431944 ], "pop" : 295, "state" : "IA" }
+{ "_id" : "50553", "city" : "KNOKE", "loc" : [ -94.85437, 42.520515 ], "pop" : 192, "state" : "IA" }
+{ "_id" : "50554", "city" : "LAURENS", "loc" : [ -94.85081599999999, 42.840938 ], "pop" : 2055, "state" : "IA" }
+{ "_id" : "50556", "city" : "LEDYARD", "loc" : [ -94.15028100000001, 43.434569 ], "pop" : 384, "state" : "IA" }
+{ "_id" : "50557", "city" : "LEHIGH", "loc" : [ -94.03415800000001, 42.352645 ], "pop" : 821, "state" : "IA" }
+{ "_id" : "50558", "city" : "LIVERMORE", "loc" : [ -94.174716, 42.866601 ], "pop" : 645, "state" : "IA" }
+{ "_id" : "50559", "city" : "LONE ROCK", "loc" : [ -94.35857799999999, 43.166645 ], "pop" : 560, "state" : "IA" }
+{ "_id" : "50560", "city" : "LU VERNE", "loc" : [ -94.095912, 42.98684 ], "pop" : 1337, "state" : "IA" }
+{ "_id" : "50561", "city" : "LYTTON", "loc" : [ -94.813991, 42.430375 ], "pop" : 235, "state" : "IA" }
+{ "_id" : "50562", "city" : "MALLARD", "loc" : [ -94.67460800000001, 42.94167 ], "pop" : 721, "state" : "IA" }
+{ "_id" : "50563", "city" : "MANSON", "loc" : [ -94.53038599999999, 42.528503 ], "pop" : 2131, "state" : "IA" }
+{ "_id" : "50565", "city" : "MARATHON", "loc" : [ -94.98355100000001, 42.861233 ], "pop" : 564, "state" : "IA" }
+{ "_id" : "50566", "city" : "MOORLAND", "loc" : [ -94.319886, 42.434005 ], "pop" : 541, "state" : "IA" }
+{ "_id" : "50567", "city" : "NEMAHA", "loc" : [ -95.093914, 42.518027 ], "pop" : 356, "state" : "IA" }
+{ "_id" : "50568", "city" : "NEWELL", "loc" : [ -94.994591, 42.615699 ], "pop" : 1668, "state" : "IA" }
+{ "_id" : "50569", "city" : "OTHO", "loc" : [ -94.170776, 42.432825 ], "pop" : 1910, "state" : "IA" }
+{ "_id" : "50570", "city" : "OTTOSEN", "loc" : [ -94.378648, 42.876443 ], "pop" : 301, "state" : "IA" }
+{ "_id" : "50571", "city" : "PALMER", "loc" : [ -94.543155, 42.641871 ], "pop" : 1119, "state" : "IA" }
+{ "_id" : "50573", "city" : "PLOVER", "loc" : [ -94.622507, 42.869107 ], "pop" : 275, "state" : "IA" }
+{ "_id" : "50574", "city" : "POCAHONTAS", "loc" : [ -94.673675, 42.729602 ], "pop" : 2802, "state" : "IA" }
+{ "_id" : "50575", "city" : "POMEROY", "loc" : [ -94.663758, 42.532565 ], "pop" : 1197, "state" : "IA" }
+{ "_id" : "50576", "city" : "REMBRANDT", "loc" : [ -95.165178, 42.826034 ], "pop" : 236, "state" : "IA" }
+{ "_id" : "50577", "city" : "RENWICK", "loc" : [ -94.007437, 42.849132 ], "pop" : 545, "state" : "IA" }
+{ "_id" : "50578", "city" : "RINGSTED", "loc" : [ -94.52913700000001, 43.297654 ], "pop" : 860, "state" : "IA" }
+{ "_id" : "50579", "city" : "ROCKWELL CITY", "loc" : [ -94.62921900000001, 42.396126 ], "pop" : 2952, "state" : "IA" }
+{ "_id" : "50580", "city" : "RODMAN", "loc" : [ -94.49924300000001, 43.035233 ], "pop" : 286, "state" : "IA" }
+{ "_id" : "50581", "city" : "ROLFE", "loc" : [ -94.516593, 42.808233 ], "pop" : 1250, "state" : "IA" }
+{ "_id" : "50582", "city" : "RUTLAND", "loc" : [ -94.27188200000001, 42.763486 ], "pop" : 529, "state" : "IA" }
+{ "_id" : "50583", "city" : "SAC CITY", "loc" : [ -94.979552, 42.426212 ], "pop" : 3531, "state" : "IA" }
+{ "_id" : "50585", "city" : "SIOUX RAPIDS", "loc" : [ -95.138836, 42.906472 ], "pop" : 1542, "state" : "IA" }
+{ "_id" : "50586", "city" : "SOMERS", "loc" : [ -94.44638999999999, 42.356065 ], "pop" : 425, "state" : "IA" }
+{ "_id" : "50588", "city" : "STORM LAKE", "loc" : [ -95.196079, 42.64738 ], "pop" : 11663, "state" : "IA" }
+{ "_id" : "50590", "city" : "SWEA CITY", "loc" : [ -94.319322, 43.402225 ], "pop" : 1440, "state" : "IA" }
+{ "_id" : "50591", "city" : "THOR", "loc" : [ -94.03895799999999, 42.688923 ], "pop" : 463, "state" : "IA" }
+{ "_id" : "50594", "city" : "VINCENT", "loc" : [ -94.033534, 42.562292 ], "pop" : 719, "state" : "IA" }
+{ "_id" : "50595", "city" : "WEBSTER CITY", "loc" : [ -93.826216, 42.465682 ], "pop" : 9130, "state" : "IA" }
+{ "_id" : "50597", "city" : "WEST BEND", "loc" : [ -94.456402, 42.957415 ], "pop" : 1099, "state" : "IA" }
+{ "_id" : "50598", "city" : "WHITTEMORE", "loc" : [ -94.406395, 43.02608 ], "pop" : 1252, "state" : "IA" }
+{ "_id" : "50599", "city" : "WOOLSTOCK", "loc" : [ -93.82161000000001, 42.584439 ], "pop" : 394, "state" : "IA" }
+{ "_id" : "50601", "city" : "ACKLEY", "loc" : [ -93.060835, 42.552722 ], "pop" : 2316, "state" : "IA" }
+{ "_id" : "50602", "city" : "ALLISON", "loc" : [ -92.78295199999999, 42.761465 ], "pop" : 1458, "state" : "IA" }
+{ "_id" : "50603", "city" : "ALTA VISTA", "loc" : [ -92.423682, 43.148159 ], "pop" : 1356, "state" : "IA" }
+{ "_id" : "50604", "city" : "APLINGTON", "loc" : [ -92.875141, 42.587039 ], "pop" : 1436, "state" : "IA" }
+{ "_id" : "50605", "city" : "AREDALE", "loc" : [ -92.97687999999999, 42.854852 ], "pop" : 317, "state" : "IA" }
+{ "_id" : "50606", "city" : "ARLINGTON", "loc" : [ -91.666814, 42.733827 ], "pop" : 1124, "state" : "IA" }
+{ "_id" : "50607", "city" : "AURORA", "loc" : [ -91.733469, 42.620317 ], "pop" : 344, "state" : "IA" }
+{ "_id" : "50608", "city" : "AUSTINVILLE", "loc" : [ -92.959422, 42.596245 ], "pop" : 363, "state" : "IA" }
+{ "_id" : "50609", "city" : "BEAMAN", "loc" : [ -92.816215, 42.236707 ], "pop" : 395, "state" : "IA" }
+{ "_id" : "50611", "city" : "BRISTOW", "loc" : [ -92.88642400000001, 42.774106 ], "pop" : 465, "state" : "IA" }
+{ "_id" : "50612", "city" : "BUCKINGHAM", "loc" : [ -92.40978800000001, 42.255211 ], "pop" : 694, "state" : "IA" }
+{ "_id" : "50613", "city" : "CEDAR FALLS", "loc" : [ -92.449725, 42.524071 ], "pop" : 36084, "state" : "IA" }
+{ "_id" : "50616", "city" : "CHARLES CITY", "loc" : [ -92.676062, 43.068327 ], "pop" : 10110, "state" : "IA" }
+{ "_id" : "50619", "city" : "CLARKSVILLE", "loc" : [ -92.658833, 42.804079 ], "pop" : 2757, "state" : "IA" }
+{ "_id" : "50621", "city" : "CONRAD", "loc" : [ -92.88652500000001, 42.234188 ], "pop" : 1346, "state" : "IA" }
+{ "_id" : "50622", "city" : "DENVER", "loc" : [ -92.341701, 42.673137 ], "pop" : 2543, "state" : "IA" }
+{ "_id" : "50624", "city" : "DIKE", "loc" : [ -92.612154, 42.47301 ], "pop" : 1860, "state" : "IA" }
+{ "_id" : "50625", "city" : "DUMONT", "loc" : [ -92.967347, 42.736773 ], "pop" : 1302, "state" : "IA" }
+{ "_id" : "50626", "city" : "DUNKERTON", "loc" : [ -92.158826, 42.578028 ], "pop" : 1676, "state" : "IA" }
+{ "_id" : "50627", "city" : "ELDORA", "loc" : [ -93.10369900000001, 42.357158 ], "pop" : 3689, "state" : "IA" }
+{ "_id" : "50628", "city" : "ELMA", "loc" : [ -92.398066, 43.27855 ], "pop" : 2102, "state" : "IA" }
+{ "_id" : "50629", "city" : "FAIRBANK", "loc" : [ -92.032589, 42.616235 ], "pop" : 1770, "state" : "IA" }
+{ "_id" : "50630", "city" : "FREDERICKSBURG", "loc" : [ -92.198334, 42.959299 ], "pop" : 1830, "state" : "IA" }
+{ "_id" : "50632", "city" : "GARWIN", "loc" : [ -92.68935, 42.087228 ], "pop" : 869, "state" : "IA" }
+{ "_id" : "50633", "city" : "GENEVA", "loc" : [ -93.103793, 42.68044 ], "pop" : 382, "state" : "IA" }
+{ "_id" : "50635", "city" : "GLADBROOK", "loc" : [ -92.714112, 42.177432 ], "pop" : 1268, "state" : "IA" }
+{ "_id" : "50636", "city" : "GREENE", "loc" : [ -92.758324, 42.91604 ], "pop" : 2480, "state" : "IA" }
+{ "_id" : "50638", "city" : "GRUNDY CENTER", "loc" : [ -92.777344, 42.3672 ], "pop" : 4130, "state" : "IA" }
+{ "_id" : "50640", "city" : "HANSELL", "loc" : [ -93.090036, 42.771195 ], "pop" : 362, "state" : "IA" }
+{ "_id" : "50641", "city" : "HAZLETON", "loc" : [ -91.910462, 42.607561 ], "pop" : 1480, "state" : "IA" }
+{ "_id" : "50642", "city" : "HOLLAND", "loc" : [ -92.79988400000001, 42.40114 ], "pop" : 222, "state" : "IA" }
+{ "_id" : "50643", "city" : "HUDSON", "loc" : [ -92.45487199999999, 42.390497 ], "pop" : 2641, "state" : "IA" }
+{ "_id" : "50644", "city" : "INDEPENDENCE", "loc" : [ -91.880343, 42.46744 ], "pop" : 8466, "state" : "IA" }
+{ "_id" : "50645", "city" : "IONIA", "loc" : [ -92.486521, 43.040253 ], "pop" : 869, "state" : "IA" }
+{ "_id" : "50647", "city" : "JANESVILLE", "loc" : [ -92.479096, 42.646515 ], "pop" : 2008, "state" : "IA" }
+{ "_id" : "50648", "city" : "JESUP", "loc" : [ -92.045625, 42.482329 ], "pop" : 3505, "state" : "IA" }
+{ "_id" : "50649", "city" : "KESLEY", "loc" : [ -92.853455, 42.685717 ], "pop" : 301, "state" : "IA" }
+{ "_id" : "50650", "city" : "LAMONT", "loc" : [ -91.670078, 42.594552 ], "pop" : 830, "state" : "IA" }
+{ "_id" : "50651", "city" : "LA PORTE CITY", "loc" : [ -92.186155, 42.341618 ], "pop" : 3990, "state" : "IA" }
+{ "_id" : "50652", "city" : "LINCOLN", "loc" : [ -92.70469300000001, 42.256056 ], "pop" : 433, "state" : "IA" }
+{ "_id" : "50653", "city" : "MARBLE ROCK", "loc" : [ -92.89168100000001, 42.964547 ], "pop" : 940, "state" : "IA" }
+{ "_id" : "50654", "city" : "MASONVILLE", "loc" : [ -91.55057600000001, 42.50461 ], "pop" : 557, "state" : "IA" }
+{ "_id" : "50655", "city" : "MAYNARD", "loc" : [ -91.890773, 42.775156 ], "pop" : 899, "state" : "IA" }
+{ "_id" : "50658", "city" : "NASHUA", "loc" : [ -92.529839, 42.952848 ], "pop" : 2007, "state" : "IA" }
+{ "_id" : "50659", "city" : "NEW HAMPTON", "loc" : [ -92.313136, 43.056015 ], "pop" : 5783, "state" : "IA" }
+{ "_id" : "50660", "city" : "NEW HARTFORD", "loc" : [ -92.616359, 42.583128 ], "pop" : 1362, "state" : "IA" }
+{ "_id" : "50662", "city" : "OELWEIN", "loc" : [ -91.913084, 42.681095 ], "pop" : 8426, "state" : "IA" }
+{ "_id" : "50665", "city" : "PARKERSBURG", "loc" : [ -92.76876300000001, 42.571377 ], "pop" : 3544, "state" : "IA" }
+{ "_id" : "50666", "city" : "PLAINFIELD", "loc" : [ -92.51155799999999, 42.850267 ], "pop" : 1030, "state" : "IA" }
+{ "_id" : "50667", "city" : "RAYMOND", "loc" : [ -92.216247, 42.467169 ], "pop" : 367, "state" : "IA" }
+{ "_id" : "50668", "city" : "READLYN", "loc" : [ -92.21543200000001, 42.692869 ], "pop" : 1858, "state" : "IA" }
+{ "_id" : "50669", "city" : "REINBECK", "loc" : [ -92.59483899999999, 42.313078 ], "pop" : 2099, "state" : "IA" }
+{ "_id" : "50670", "city" : "SHELL ROCK", "loc" : [ -92.58878, 42.70611 ], "pop" : 1834, "state" : "IA" }
+{ "_id" : "50671", "city" : "STANLEY", "loc" : [ -91.812673, 42.635623 ], "pop" : 175, "state" : "IA" }
+{ "_id" : "50672", "city" : "STEAMBOAT ROCK", "loc" : [ -93.06291, 42.417841 ], "pop" : 650, "state" : "IA" }
+{ "_id" : "50674", "city" : "SUMNER", "loc" : [ -92.118562, 42.841935 ], "pop" : 3187, "state" : "IA" }
+{ "_id" : "50675", "city" : "TRAER", "loc" : [ -92.482681, 42.184685 ], "pop" : 2064, "state" : "IA" }
+{ "_id" : "50676", "city" : "TRIPOLI", "loc" : [ -92.265934, 42.810538 ], "pop" : 1993, "state" : "IA" }
+{ "_id" : "50677", "city" : "BREMER", "loc" : [ -92.466199, 42.737307 ], "pop" : 10879, "state" : "IA" }
+{ "_id" : "50680", "city" : "WELLSBURG", "loc" : [ -92.939763, 42.449418 ], "pop" : 1353, "state" : "IA" }
+{ "_id" : "50681", "city" : "WESTGATE", "loc" : [ -92.018299, 42.805453 ], "pop" : 1044, "state" : "IA" }
+{ "_id" : "50682", "city" : "WINTHROP", "loc" : [ -91.73146699999999, 42.491163 ], "pop" : 1330, "state" : "IA" }
+{ "_id" : "50701", "city" : "WATERLOO", "loc" : [ -92.36609900000001, 42.477784 ], "pop" : 29194, "state" : "IA" }
+{ "_id" : "50702", "city" : "WATERLOO", "loc" : [ -92.33648599999999, 42.473112 ], "pop" : 18939, "state" : "IA" }
+{ "_id" : "50703", "city" : "WATERLOO", "loc" : [ -92.326919, 42.514875 ], "pop" : 21256, "state" : "IA" }
+{ "_id" : "50706", "city" : "WASHBURN", "loc" : [ -92.2676, 42.407605 ], "pop" : 1010, "state" : "IA" }
+{ "_id" : "50707", "city" : "EVANSDALE", "loc" : [ -92.281158, 42.475453 ], "pop" : 7954, "state" : "IA" }
+{ "_id" : "50801", "city" : "NEVINVILLE", "loc" : [ -94.369151, 41.062384 ], "pop" : 9548, "state" : "IA" }
+{ "_id" : "50830", "city" : "AFTON", "loc" : [ -94.19404400000001, 41.040146 ], "pop" : 1450, "state" : "IA" }
+{ "_id" : "50833", "city" : "BEDFORD", "loc" : [ -94.73244800000001, 40.66829 ], "pop" : 2608, "state" : "IA" }
+{ "_id" : "50835", "city" : "BENTON", "loc" : [ -94.39310399999999, 40.725836 ], "pop" : 203, "state" : "IA" }
+{ "_id" : "50836", "city" : "BLOCKTON", "loc" : [ -94.504901, 40.624242 ], "pop" : 476, "state" : "IA" }
+{ "_id" : "50837", "city" : "BRIDGEWATER", "loc" : [ -94.64101100000001, 41.157084 ], "pop" : 1383, "state" : "IA" }
+{ "_id" : "50840", "city" : "CLEARFIELD", "loc" : [ -94.494439, 40.793534 ], "pop" : 593, "state" : "IA" }
+{ "_id" : "50841", "city" : "CORNING", "loc" : [ -94.735789, 40.987121 ], "pop" : 2660, "state" : "IA" }
+{ "_id" : "50843", "city" : "CUMBERLAND", "loc" : [ -94.87100599999999, 41.263165 ], "pop" : 695, "state" : "IA" }
+{ "_id" : "50844", "city" : "DELPHOS", "loc" : [ -94.316188, 40.661959 ], "pop" : 100, "state" : "IA" }
+{ "_id" : "50845", "city" : "DIAGONAL", "loc" : [ -94.35515599999999, 40.822644 ], "pop" : 793, "state" : "IA" }
+{ "_id" : "50846", "city" : "FONTANELLE", "loc" : [ -94.541904, 41.289568 ], "pop" : 1534, "state" : "IA" }
+{ "_id" : "50847", "city" : "GRANT", "loc" : [ -94.984554, 41.125799 ], "pop" : 315, "state" : "IA" }
+{ "_id" : "50848", "city" : "GRAVITY", "loc" : [ -94.750595, 40.790914 ], "pop" : 617, "state" : "IA" }
+{ "_id" : "50849", "city" : "GREENFIELD", "loc" : [ -94.440757, 41.313311 ], "pop" : 2772, "state" : "IA" }
+{ "_id" : "50850", "city" : "KENT", "loc" : [ -94.421718, 40.944856 ], "pop" : 309, "state" : "IA" }
+{ "_id" : "50851", "city" : "LENOX", "loc" : [ -94.56117, 40.884096 ], "pop" : 1973, "state" : "IA" }
+{ "_id" : "50852", "city" : "MALOY", "loc" : [ -94.40764, 40.673648 ], "pop" : 81, "state" : "IA" }
+{ "_id" : "50853", "city" : "MASSENA", "loc" : [ -94.764872, 41.249867 ], "pop" : 794, "state" : "IA" }
+{ "_id" : "50854", "city" : "MOUNT AYR", "loc" : [ -94.232146, 40.7142 ], "pop" : 2487, "state" : "IA" }
+{ "_id" : "50857", "city" : "NODAWAY", "loc" : [ -94.87309, 40.954034 ], "pop" : 706, "state" : "IA" }
+{ "_id" : "50858", "city" : "ORIENT", "loc" : [ -94.370496, 41.219191 ], "pop" : 1042, "state" : "IA" }
+{ "_id" : "50859", "city" : "PRESCOTT", "loc" : [ -94.524901, 41.024848 ], "pop" : 205, "state" : "IA" }
+{ "_id" : "50860", "city" : "REDDING", "loc" : [ -94.35945100000001, 40.605312 ], "pop" : 327, "state" : "IA" }
+{ "_id" : "50861", "city" : "SHANNON CITY", "loc" : [ -94.250106, 40.936636 ], "pop" : 586, "state" : "IA" }
+{ "_id" : "50862", "city" : "SHARPSBURG", "loc" : [ -94.641633, 40.795042 ], "pop" : 199, "state" : "IA" }
+{ "_id" : "50863", "city" : "TINGLEY", "loc" : [ -94.19082299999999, 40.851597 ], "pop" : 347, "state" : "IA" }
+{ "_id" : "50864", "city" : "VILLISCA", "loc" : [ -94.97958800000001, 40.943718 ], "pop" : 1794, "state" : "IA" }
+{ "_id" : "51001", "city" : "AKRON", "loc" : [ -96.52245000000001, 42.835392 ], "pop" : 2068, "state" : "IA" }
+{ "_id" : "51002", "city" : "ALTA", "loc" : [ -95.3129, 42.677118 ], "pop" : 2757, "state" : "IA" }
+{ "_id" : "51003", "city" : "ALTON", "loc" : [ -96.017268, 42.978175 ], "pop" : 1371, "state" : "IA" }
+{ "_id" : "51004", "city" : "ANTHON", "loc" : [ -95.89476500000001, 42.386967 ], "pop" : 1550, "state" : "IA" }
+{ "_id" : "51005", "city" : "AURELIA", "loc" : [ -95.438086, 42.69122 ], "pop" : 1543, "state" : "IA" }
+{ "_id" : "51006", "city" : "BATTLE CREEK", "loc" : [ -95.604517, 42.332662 ], "pop" : 1552, "state" : "IA" }
+{ "_id" : "51007", "city" : "BRONSON", "loc" : [ -96.19859099999999, 42.429181 ], "pop" : 796, "state" : "IA" }
+{ "_id" : "51009", "city" : "CALUMET", "loc" : [ -95.55487100000001, 42.953272 ], "pop" : 431, "state" : "IA" }
+{ "_id" : "51010", "city" : "CASTANA", "loc" : [ -95.943121, 42.105404 ], "pop" : 533, "state" : "IA" }
+{ "_id" : "51012", "city" : "CHEROKEE", "loc" : [ -95.556842, 42.748187 ], "pop" : 8339, "state" : "IA" }
+{ "_id" : "51014", "city" : "CLEGHORN", "loc" : [ -95.712436, 42.808593 ], "pop" : 541, "state" : "IA" }
+{ "_id" : "51016", "city" : "CORRECTIONVILLE", "loc" : [ -95.780382, 42.474322 ], "pop" : 1432, "state" : "IA" }
+{ "_id" : "51018", "city" : "CUSHING", "loc" : [ -95.67748, 42.464182 ], "pop" : 261, "state" : "IA" }
+{ "_id" : "51019", "city" : "DANBURY", "loc" : [ -95.726259, 42.269337 ], "pop" : 906, "state" : "IA" }
+{ "_id" : "51020", "city" : "GALVA", "loc" : [ -95.429838, 42.510508 ], "pop" : 626, "state" : "IA" }
+{ "_id" : "51022", "city" : "GRANVILLE", "loc" : [ -95.897167, 42.969252 ], "pop" : 592, "state" : "IA" }
+{ "_id" : "51023", "city" : "HAWARDEN", "loc" : [ -96.472992, 43.001333 ], "pop" : 3097, "state" : "IA" }
+{ "_id" : "51024", "city" : "HINTON", "loc" : [ -96.30503299999999, 42.604046 ], "pop" : 2449, "state" : "IA" }
+{ "_id" : "51025", "city" : "HOLSTEIN", "loc" : [ -95.564971, 42.494779 ], "pop" : 1977, "state" : "IA" }
+{ "_id" : "51026", "city" : "HORNICK", "loc" : [ -96.079553, 42.289741 ], "pop" : 894, "state" : "IA" }
+{ "_id" : "51027", "city" : "IRETON", "loc" : [ -96.32322600000001, 42.966566 ], "pop" : 1154, "state" : "IA" }
+{ "_id" : "51028", "city" : "KINGSLEY", "loc" : [ -95.976151, 42.619057 ], "pop" : 2138, "state" : "IA" }
+{ "_id" : "51029", "city" : "LARRABEE", "loc" : [ -95.581228, 42.862758 ], "pop" : 607, "state" : "IA" }
+{ "_id" : "51030", "city" : "LAWTON", "loc" : [ -96.21893, 42.504748 ], "pop" : 1481, "state" : "IA" }
+{ "_id" : "51031", "city" : "LE MARS", "loc" : [ -96.17038599999999, 42.79623 ], "pop" : 11576, "state" : "IA" }
+{ "_id" : "51033", "city" : "LINN GROVE", "loc" : [ -95.251249, 42.874229 ], "pop" : 722, "state" : "IA" }
+{ "_id" : "51034", "city" : "MAPLETON", "loc" : [ -95.79093399999999, 42.158524 ], "pop" : 2038, "state" : "IA" }
+{ "_id" : "51035", "city" : "MARCUS", "loc" : [ -95.803431, 42.819959 ], "pop" : 1654, "state" : "IA" }
+{ "_id" : "51036", "city" : "MAURICE", "loc" : [ -96.165531, 42.962647 ], "pop" : 625, "state" : "IA" }
+{ "_id" : "51037", "city" : "MERIDEN", "loc" : [ -95.64079700000001, 42.787416 ], "pop" : 333, "state" : "IA" }
+{ "_id" : "51038", "city" : "MERRILL", "loc" : [ -96.228324, 42.704737 ], "pop" : 1468, "state" : "IA" }
+{ "_id" : "51039", "city" : "MOVILLE", "loc" : [ -96.065583, 42.481924 ], "pop" : 2064, "state" : "IA" }
+{ "_id" : "51040", "city" : "ONAWA", "loc" : [ -96.107213, 42.036967 ], "pop" : 3867, "state" : "IA" }
+{ "_id" : "51041", "city" : "ORANGE CITY", "loc" : [ -96.05646400000001, 43.01849 ], "pop" : 6126, "state" : "IA" }
+{ "_id" : "51044", "city" : "OTO", "loc" : [ -95.861575, 42.264592 ], "pop" : 340, "state" : "IA" }
+{ "_id" : "51046", "city" : "PAULLINA", "loc" : [ -95.708322, 42.970277 ], "pop" : 1760, "state" : "IA" }
+{ "_id" : "51047", "city" : "PETERSON", "loc" : [ -95.337658, 42.932794 ], "pop" : 640, "state" : "IA" }
+{ "_id" : "51048", "city" : "PIERSON", "loc" : [ -95.89219300000001, 42.533493 ], "pop" : 642, "state" : "IA" }
+{ "_id" : "51049", "city" : "QUIMBY", "loc" : [ -95.681175, 42.628711 ], "pop" : 562, "state" : "IA" }
+{ "_id" : "51050", "city" : "REMSEN", "loc" : [ -95.95437800000001, 42.8149 ], "pop" : 2254, "state" : "IA" }
+{ "_id" : "51051", "city" : "RODNEY", "loc" : [ -95.953456, 42.201541 ], "pop" : 120, "state" : "IA" }
+{ "_id" : "51052", "city" : "SALIX", "loc" : [ -96.28791200000001, 42.330554 ], "pop" : 1210, "state" : "IA" }
+{ "_id" : "51053", "city" : "SCHALLER", "loc" : [ -95.284587, 42.505501 ], "pop" : 1311, "state" : "IA" }
+{ "_id" : "51054", "city" : "SERGEANT BLUFF", "loc" : [ -96.353392, 42.401895 ], "pop" : 2853, "state" : "IA" }
+{ "_id" : "51055", "city" : "SLOAN", "loc" : [ -96.23063399999999, 42.242726 ], "pop" : 1303, "state" : "IA" }
+{ "_id" : "51056", "city" : "SMITHLAND", "loc" : [ -95.94864699999999, 42.24079 ], "pop" : 495, "state" : "IA" }
+{ "_id" : "51058", "city" : "SUTHERLAND", "loc" : [ -95.480665, 42.982623 ], "pop" : 1096, "state" : "IA" }
+{ "_id" : "51059", "city" : "TURIN", "loc" : [ -95.95182800000001, 41.973189 ], "pop" : 387, "state" : "IA" }
+{ "_id" : "51060", "city" : "UTE", "loc" : [ -95.712542, 42.058085 ], "pop" : 567, "state" : "IA" }
+{ "_id" : "51061", "city" : "WASHTA", "loc" : [ -95.72953699999999, 42.578108 ], "pop" : 519, "state" : "IA" }
+{ "_id" : "51062", "city" : "WESTFIELD", "loc" : [ -96.49198699999999, 42.695329 ], "pop" : 1435, "state" : "IA" }
+{ "_id" : "51063", "city" : "WHITING", "loc" : [ -96.182247, 42.15216 ], "pop" : 895, "state" : "IA" }
+{ "_id" : "51101", "city" : "SIOUX CITY", "loc" : [ -96.40291999999999, 42.497223 ], "pop" : 765, "state" : "IA" }
+{ "_id" : "51103", "city" : "SIOUX CITY", "loc" : [ -96.42950999999999, 42.506793 ], "pop" : 16831, "state" : "IA" }
+{ "_id" : "51104", "city" : "SIOUX CITY", "loc" : [ -96.400453, 42.52536 ], "pop" : 20441, "state" : "IA" }
+{ "_id" : "51105", "city" : "SIOUX CITY", "loc" : [ -96.38285500000001, 42.503224 ], "pop" : 10372, "state" : "IA" }
+{ "_id" : "51106", "city" : "SIOUX CITY", "loc" : [ -96.352755, 42.467057 ], "pop" : 25974, "state" : "IA" }
+{ "_id" : "51107", "city" : "SIOUX CITY", "loc" : [ -96.376064, 42.490266 ], "pop" : 258, "state" : "IA" }
+{ "_id" : "51108", "city" : "SIOUX CITY", "loc" : [ -96.361695, 42.546891 ], "pop" : 4615, "state" : "IA" }
+{ "_id" : "51109", "city" : "SIOUX CITY", "loc" : [ -96.480304, 42.517287 ], "pop" : 2592, "state" : "IA" }
+{ "_id" : "51110", "city" : "SIOUX CITY", "loc" : [ -96.372559, 42.400921 ], "pop" : 189, "state" : "IA" }
+{ "_id" : "51111", "city" : "SIOUX CITY", "loc" : [ -96.37129400000001, 42.408912 ], "pop" : 12, "state" : "IA" }
+{ "_id" : "51201", "city" : "SHELDON", "loc" : [ -95.840141, 43.180797 ], "pop" : 5585, "state" : "IA" }
+{ "_id" : "51230", "city" : "ALVORD", "loc" : [ -96.290994, 43.320109 ], "pop" : 494, "state" : "IA" }
+{ "_id" : "51231", "city" : "ARCHER", "loc" : [ -95.74165600000001, 43.117917 ], "pop" : 194, "state" : "IA" }
+{ "_id" : "51232", "city" : "ASHTON", "loc" : [ -95.76550899999999, 43.305259 ], "pop" : 1090, "state" : "IA" }
+{ "_id" : "51234", "city" : "BOYDEN", "loc" : [ -95.982309, 43.20343 ], "pop" : 1652, "state" : "IA" }
+{ "_id" : "51235", "city" : "DOON", "loc" : [ -96.201987, 43.287183 ], "pop" : 957, "state" : "IA" }
+{ "_id" : "51237", "city" : "GEORGE", "loc" : [ -95.989383, 43.343903 ], "pop" : 2326, "state" : "IA" }
+{ "_id" : "51238", "city" : "HOSPERS", "loc" : [ -95.91417199999999, 43.079337 ], "pop" : 1491, "state" : "IA" }
+{ "_id" : "51239", "city" : "HULL", "loc" : [ -96.13924799999999, 43.195201 ], "pop" : 2283, "state" : "IA" }
+{ "_id" : "51240", "city" : "INWOOD", "loc" : [ -96.43629300000001, 43.304747 ], "pop" : 1434, "state" : "IA" }
+{ "_id" : "51241", "city" : "LARCHWOOD", "loc" : [ -96.42522, 43.438673 ], "pop" : 2097, "state" : "IA" }
+{ "_id" : "51243", "city" : "LITTLE ROCK", "loc" : [ -95.892622, 43.449571 ], "pop" : 688, "state" : "IA" }
+{ "_id" : "51245", "city" : "PRIMGHAR", "loc" : [ -95.65330400000001, 43.075892 ], "pop" : 2167, "state" : "IA" }
+{ "_id" : "51246", "city" : "ROCK RAPIDS", "loc" : [ -96.178055, 43.427192 ], "pop" : 3956, "state" : "IA" }
+{ "_id" : "51247", "city" : "ROCK VALLEY", "loc" : [ -96.31034200000001, 43.201356 ], "pop" : 4100, "state" : "IA" }
+{ "_id" : "51248", "city" : "SANBORN", "loc" : [ -95.662227, 43.189002 ], "pop" : 1632, "state" : "IA" }
+{ "_id" : "51249", "city" : "SIBLEY", "loc" : [ -95.7424, 43.406929 ], "pop" : 3853, "state" : "IA" }
+{ "_id" : "51250", "city" : "SIOUX CENTER", "loc" : [ -96.179952, 43.081416 ], "pop" : 7417, "state" : "IA" }
+{ "_id" : "51301", "city" : "SPENCER", "loc" : [ -95.14569, 43.145107 ], "pop" : 12101, "state" : "IA" }
+{ "_id" : "51331", "city" : "ARNOLDS PARK", "loc" : [ -95.13126099999999, 43.36358 ], "pop" : 1109, "state" : "IA" }
+{ "_id" : "51333", "city" : "DICKENS", "loc" : [ -94.985383, 43.154836 ], "pop" : 732, "state" : "IA" }
+{ "_id" : "51334", "city" : "ESTHERVILLE", "loc" : [ -94.818001, 43.401709 ], "pop" : 8614, "state" : "IA" }
+{ "_id" : "51338", "city" : "EVERLY", "loc" : [ -95.322777, 43.160917 ], "pop" : 1153, "state" : "IA" }
+{ "_id" : "51340", "city" : "FOSTORIA", "loc" : [ -95.185042, 43.225857 ], "pop" : 471, "state" : "IA" }
+{ "_id" : "51342", "city" : "GRAETTINGER", "loc" : [ -94.733401, 43.227731 ], "pop" : 1259, "state" : "IA" }
+{ "_id" : "51343", "city" : "GREENVILLE", "loc" : [ -95.058184, 43.033348 ], "pop" : 630, "state" : "IA" }
+{ "_id" : "51345", "city" : "HARRIS", "loc" : [ -95.44260300000001, 43.456793 ], "pop" : 333, "state" : "IA" }
+{ "_id" : "51346", "city" : "HARTLEY", "loc" : [ -95.481696, 43.179984 ], "pop" : 2574, "state" : "IA" }
+{ "_id" : "51347", "city" : "LAKE PARK", "loc" : [ -95.321601, 43.445239 ], "pop" : 1320, "state" : "IA" }
+{ "_id" : "51350", "city" : "MELVIN", "loc" : [ -95.592951, 43.284496 ], "pop" : 395, "state" : "IA" }
+{ "_id" : "51351", "city" : "MILFORD", "loc" : [ -95.161534, 43.31964 ], "pop" : 2964, "state" : "IA" }
+{ "_id" : "51354", "city" : "OCHEYEDAN", "loc" : [ -95.520366, 43.39105 ], "pop" : 1596, "state" : "IA" }
+{ "_id" : "51355", "city" : "OKOBOJI", "loc" : [ -95.153026, 43.37938 ], "pop" : 1637, "state" : "IA" }
+{ "_id" : "51357", "city" : "ROYAL", "loc" : [ -95.26785599999999, 43.048751 ], "pop" : 1035, "state" : "IA" }
+{ "_id" : "51358", "city" : "RUTHVEN", "loc" : [ -94.884214, 43.144845 ], "pop" : 1283, "state" : "IA" }
+{ "_id" : "51360", "city" : "SPIRIT LAKE", "loc" : [ -95.112336, 43.426211 ], "pop" : 6683, "state" : "IA" }
+{ "_id" : "51363", "city" : "SUPERIOR", "loc" : [ -94.964935, 43.450317 ], "pop" : 333, "state" : "IA" }
+{ "_id" : "51364", "city" : "TERRIL", "loc" : [ -94.973725, 43.324073 ], "pop" : 863, "state" : "IA" }
+{ "_id" : "51365", "city" : "WALLINGFORD", "loc" : [ -94.82057, 43.312158 ], "pop" : 371, "state" : "IA" }
+{ "_id" : "51366", "city" : "WEBB", "loc" : [ -94.995124, 42.950189 ], "pop" : 343, "state" : "IA" }
+{ "_id" : "51401", "city" : "CARROLL", "loc" : [ -94.866664, 42.071972 ], "pop" : 11456, "state" : "IA" }
+{ "_id" : "51430", "city" : "ARCADIA", "loc" : [ -95.03713999999999, 42.057279 ], "pop" : 1183, "state" : "IA" }
+{ "_id" : "51431", "city" : "ARTHUR", "loc" : [ -95.367519, 42.336283 ], "pop" : 577, "state" : "IA" }
+{ "_id" : "51432", "city" : "ASPINWALL", "loc" : [ -95.149936, 41.908252 ], "pop" : 367, "state" : "IA" }
+{ "_id" : "51433", "city" : "YETTER", "loc" : [ -94.903447, 42.280895 ], "pop" : 882, "state" : "IA" }
+{ "_id" : "51436", "city" : "BREDA", "loc" : [ -95.00067900000001, 42.175835 ], "pop" : 773, "state" : "IA" }
+{ "_id" : "51439", "city" : "CHARTER OAK", "loc" : [ -95.59924100000001, 42.070735 ], "pop" : 797, "state" : "IA" }
+{ "_id" : "51440", "city" : "DEDHAM", "loc" : [ -94.814896, 41.905539 ], "pop" : 562, "state" : "IA" }
+{ "_id" : "51441", "city" : "DELOIT", "loc" : [ -95.286338, 42.085899 ], "pop" : 618, "state" : "IA" }
+{ "_id" : "51442", "city" : "DENISON", "loc" : [ -95.363572, 42.019626 ], "pop" : 8507, "state" : "IA" }
+{ "_id" : "51443", "city" : "GLIDDEN", "loc" : [ -94.714777, 42.061816 ], "pop" : 1518, "state" : "IA" }
+{ "_id" : "51444", "city" : "HALBUR", "loc" : [ -94.93586000000001, 41.997357 ], "pop" : 720, "state" : "IA" }
+{ "_id" : "51445", "city" : "IDA GROVE", "loc" : [ -95.464488, 42.340026 ], "pop" : 3633, "state" : "IA" }
+{ "_id" : "51446", "city" : "IRWIN", "loc" : [ -95.195842, 41.794094 ], "pop" : 1120, "state" : "IA" }
+{ "_id" : "51447", "city" : "KIRKMAN", "loc" : [ -95.267083, 41.73076 ], "pop" : 395, "state" : "IA" }
+{ "_id" : "51448", "city" : "KIRON", "loc" : [ -95.31146, 42.179359 ], "pop" : 753, "state" : "IA" }
+{ "_id" : "51449", "city" : "LAKE CITY", "loc" : [ -94.74578700000001, 42.270494 ], "pop" : 2539, "state" : "IA" }
+{ "_id" : "51450", "city" : "LAKE VIEW", "loc" : [ -95.048562, 42.315367 ], "pop" : 1792, "state" : "IA" }
+{ "_id" : "51451", "city" : "LANESBORO", "loc" : [ -94.690274, 42.174687 ], "pop" : 396, "state" : "IA" }
+{ "_id" : "51452", "city" : "LIDDERDALE", "loc" : [ -94.79535300000001, 42.152815 ], "pop" : 525, "state" : "IA" }
+{ "_id" : "51453", "city" : "LOHRVILLE", "loc" : [ -94.556605, 42.261923 ], "pop" : 615, "state" : "IA" }
+{ "_id" : "51454", "city" : "MANILLA", "loc" : [ -95.239126, 41.892233 ], "pop" : 1185, "state" : "IA" }
+{ "_id" : "51455", "city" : "MANNING", "loc" : [ -95.055622, 41.907248 ], "pop" : 1807, "state" : "IA" }
+{ "_id" : "51458", "city" : "ODEBOLT", "loc" : [ -95.25005, 42.309514 ], "pop" : 1776, "state" : "IA" }
+{ "_id" : "51459", "city" : "RALSTON", "loc" : [ -94.569779, 42.075655 ], "pop" : 231, "state" : "IA" }
+{ "_id" : "51460", "city" : "RICKETTS", "loc" : [ -95.599547, 42.15406 ], "pop" : 346, "state" : "IA" }
+{ "_id" : "51461", "city" : "SCHLESWIG", "loc" : [ -95.444309, 42.164586 ], "pop" : 1191, "state" : "IA" }
+{ "_id" : "51462", "city" : "SCRANTON", "loc" : [ -94.55176400000001, 42.012381 ], "pop" : 814, "state" : "IA" }
+{ "_id" : "51463", "city" : "TEMPLETON", "loc" : [ -94.93200899999999, 41.912077 ], "pop" : 681, "state" : "IA" }
+{ "_id" : "51465", "city" : "VAIL", "loc" : [ -95.17776600000001, 42.033772 ], "pop" : 790, "state" : "IA" }
+{ "_id" : "51466", "city" : "WALL LAKE", "loc" : [ -95.085156, 42.265252 ], "pop" : 1481, "state" : "IA" }
+{ "_id" : "51467", "city" : "WESTSIDE", "loc" : [ -95.12730000000001, 42.10844 ], "pop" : 714, "state" : "IA" }
+{ "_id" : "51501", "city" : "MANAWA", "loc" : [ -95.88099200000001, 41.252954 ], "pop" : 31614, "state" : "IA" }
+{ "_id" : "51503", "city" : "COUNCIL BLUFFS", "loc" : [ -95.82508300000001, 41.261584 ], "pop" : 30513, "state" : "IA" }
+{ "_id" : "51510", "city" : "CARTER LAKE", "loc" : [ -95.91406000000001, 41.292524 ], "pop" : 3200, "state" : "IA" }
+{ "_id" : "51520", "city" : "ARION", "loc" : [ -95.46232999999999, 41.950406 ], "pop" : 194, "state" : "IA" }
+{ "_id" : "51521", "city" : "AVOCA", "loc" : [ -95.350872, 41.476834 ], "pop" : 2032, "state" : "IA" }
+{ "_id" : "51523", "city" : "BLENCOE", "loc" : [ -96.082663, 41.923662 ], "pop" : 373, "state" : "IA" }
+{ "_id" : "51525", "city" : "CARSON", "loc" : [ -95.36808600000001, 41.225276 ], "pop" : 1398, "state" : "IA" }
+{ "_id" : "51526", "city" : "CRESCENT", "loc" : [ -95.827648, 41.364378 ], "pop" : 1967, "state" : "IA" }
+{ "_id" : "51527", "city" : "EARLING", "loc" : [ -95.340293, 41.827063 ], "pop" : 375, "state" : "IA" }
+{ "_id" : "51528", "city" : "DOW CITY", "loc" : [ -95.4862, 41.913429 ], "pop" : 1313, "state" : "IA" }
+{ "_id" : "51529", "city" : "EARLING", "loc" : [ -95.615709, 41.842301 ], "pop" : 1836, "state" : "IA" }
+{ "_id" : "51530", "city" : "EARLING", "loc" : [ -95.42104500000001, 41.792483 ], "pop" : 1068, "state" : "IA" }
+{ "_id" : "51531", "city" : "ELK HORN", "loc" : [ -95.070015, 41.582871 ], "pop" : 990, "state" : "IA" }
+{ "_id" : "51532", "city" : "ELLIOTT", "loc" : [ -95.160237, 41.130617 ], "pop" : 879, "state" : "IA" }
+{ "_id" : "51533", "city" : "EMERSON", "loc" : [ -95.410624, 41.028439 ], "pop" : 1529, "state" : "IA" }
+{ "_id" : "51534", "city" : "GLENWOOD", "loc" : [ -95.73891999999999, 41.047009 ], "pop" : 6392, "state" : "IA" }
+{ "_id" : "51535", "city" : "GRISWOLD", "loc" : [ -95.098989, 41.223842 ], "pop" : 1678, "state" : "IA" }
+{ "_id" : "51536", "city" : "HANCOCK", "loc" : [ -95.344528, 41.383238 ], "pop" : 427, "state" : "IA" }
+{ "_id" : "51537", "city" : "HARLAN", "loc" : [ -95.31110099999999, 41.64375 ], "pop" : 6934, "state" : "IA" }
+{ "_id" : "51540", "city" : "HASTINGS", "loc" : [ -95.55309699999999, 40.960514 ], "pop" : 267, "state" : "IA" }
+{ "_id" : "51541", "city" : "HENDERSON", "loc" : [ -95.458629, 41.125426 ], "pop" : 564, "state" : "IA" }
+{ "_id" : "51542", "city" : "HONEY CREEK", "loc" : [ -95.8802, 41.463045 ], "pop" : 656, "state" : "IA" }
+{ "_id" : "51543", "city" : "KIMBALLTON", "loc" : [ -95.055324, 41.635214 ], "pop" : 614, "state" : "IA" }
+{ "_id" : "51544", "city" : "LEWIS", "loc" : [ -95.06202399999999, 41.296289 ], "pop" : 980, "state" : "IA" }
+{ "_id" : "51545", "city" : "LITTLE SIOUX", "loc" : [ -96.031357, 41.808267 ], "pop" : 402, "state" : "IA" }
+{ "_id" : "51546", "city" : "LOGAN", "loc" : [ -95.752478, 41.624345 ], "pop" : 2764, "state" : "IA" }
+{ "_id" : "51548", "city" : "MC CLELLAND", "loc" : [ -95.68127800000001, 41.293168 ], "pop" : 714, "state" : "IA" }
+{ "_id" : "51549", "city" : "MACEDONIA", "loc" : [ -95.431386, 41.191627 ], "pop" : 475, "state" : "IA" }
+{ "_id" : "51550", "city" : "MAGNOLIA", "loc" : [ -95.854955, 41.708177 ], "pop" : 631, "state" : "IA" }
+{ "_id" : "51551", "city" : "MALVERN", "loc" : [ -95.58398800000001, 41.007378 ], "pop" : 1409, "state" : "IA" }
+{ "_id" : "51552", "city" : "MARNE", "loc" : [ -95.097308, 41.454681 ], "pop" : 388, "state" : "IA" }
+{ "_id" : "51553", "city" : "MINDEN", "loc" : [ -95.55188699999999, 41.465355 ], "pop" : 917, "state" : "IA" }
+{ "_id" : "51554", "city" : "MINEOLA", "loc" : [ -95.75569900000001, 41.110171 ], "pop" : 1276, "state" : "IA" }
+{ "_id" : "51555", "city" : "MISSOURI VALLEY", "loc" : [ -95.891346, 41.564399 ], "pop" : 4330, "state" : "IA" }
+{ "_id" : "51556", "city" : "MODALE", "loc" : [ -95.985225, 41.637143 ], "pop" : 505, "state" : "IA" }
+{ "_id" : "51557", "city" : "MONDAMIN", "loc" : [ -96.007204, 41.708876 ], "pop" : 793, "state" : "IA" }
+{ "_id" : "51558", "city" : "MOORHEAD", "loc" : [ -95.829031, 41.918601 ], "pop" : 589, "state" : "IA" }
+{ "_id" : "51559", "city" : "NEOLA", "loc" : [ -95.67935799999999, 41.456383 ], "pop" : 1766, "state" : "IA" }
+{ "_id" : "51560", "city" : "OAKLAND", "loc" : [ -95.379034, 41.311964 ], "pop" : 2385, "state" : "IA" }
+{ "_id" : "51561", "city" : "PACIFIC JUNCTION", "loc" : [ -95.80464499999999, 41.027123 ], "pop" : 1228, "state" : "IA" }
+{ "_id" : "51562", "city" : "PANAMA", "loc" : [ -95.48704600000001, 41.728813 ], "pop" : 511, "state" : "IA" }
+{ "_id" : "51563", "city" : "PERSIA", "loc" : [ -95.56577, 41.56473 ], "pop" : 691, "state" : "IA" }
+{ "_id" : "51564", "city" : "PISGAH", "loc" : [ -95.919172, 41.821376 ], "pop" : 673, "state" : "IA" }
+{ "_id" : "51565", "city" : "PORTSMOUTH", "loc" : [ -95.510751, 41.648385 ], "pop" : 476, "state" : "IA" }
+{ "_id" : "51566", "city" : "RED OAK", "loc" : [ -95.226924, 41.007949 ], "pop" : 7395, "state" : "IA" }
+{ "_id" : "51570", "city" : "SHELBY", "loc" : [ -95.446888, 41.533898 ], "pop" : 941, "state" : "IA" }
+{ "_id" : "51571", "city" : "SILVER CITY", "loc" : [ -95.626912, 41.113024 ], "pop" : 483, "state" : "IA" }
+{ "_id" : "51572", "city" : "SOLDIER", "loc" : [ -95.78253100000001, 41.994188 ], "pop" : 665, "state" : "IA" }
+{ "_id" : "51573", "city" : "STANTON", "loc" : [ -95.09876, 40.985924 ], "pop" : 1315, "state" : "IA" }
+{ "_id" : "51575", "city" : "TREYNOR", "loc" : [ -95.617041, 41.220679 ], "pop" : 1619, "state" : "IA" }
+{ "_id" : "51576", "city" : "UNDERWOOD", "loc" : [ -95.626997, 41.360294 ], "pop" : 1652, "state" : "IA" }
+{ "_id" : "51577", "city" : "WALNUT", "loc" : [ -95.217973, 41.462329 ], "pop" : 1293, "state" : "IA" }
+{ "_id" : "51578", "city" : "WESTPHALIA", "loc" : [ -95.386978, 41.718014 ], "pop" : 420, "state" : "IA" }
+{ "_id" : "51579", "city" : "WOODBINE", "loc" : [ -95.700785, 41.737267 ], "pop" : 2105, "state" : "IA" }
+{ "_id" : "51601", "city" : "SHENANDOAH", "loc" : [ -95.36479799999999, 40.758087 ], "pop" : 6226, "state" : "IA" }
+{ "_id" : "51630", "city" : "BLANCHARD", "loc" : [ -95.205377, 40.612156 ], "pop" : 284, "state" : "IA" }
+{ "_id" : "51631", "city" : "BRADDYVILLE", "loc" : [ -94.99557799999999, 40.599081 ], "pop" : 351, "state" : "IA" }
+{ "_id" : "51632", "city" : "CLARINDA", "loc" : [ -95.037976, 40.749084 ], "pop" : 6652, "state" : "IA" }
+{ "_id" : "51636", "city" : "COIN", "loc" : [ -95.221653, 40.668591 ], "pop" : 387, "state" : "IA" }
+{ "_id" : "51637", "city" : "COLLEGE SPRINGS", "loc" : [ -95.099717, 40.617109 ], "pop" : 537, "state" : "IA" }
+{ "_id" : "51638", "city" : "ESSEX", "loc" : [ -95.288777, 40.840359 ], "pop" : 1433, "state" : "IA" }
+{ "_id" : "51639", "city" : "FARRAGUT", "loc" : [ -95.45549800000001, 40.729971 ], "pop" : 1055, "state" : "IA" }
+{ "_id" : "51640", "city" : "HAMBURG", "loc" : [ -95.625789, 40.614902 ], "pop" : 1997, "state" : "IA" }
+{ "_id" : "51645", "city" : "IMOGENE", "loc" : [ -95.435804, 40.863144 ], "pop" : 318, "state" : "IA" }
+{ "_id" : "51646", "city" : "NEW MARKET", "loc" : [ -94.891662, 40.742174 ], "pop" : 702, "state" : "IA" }
+{ "_id" : "51647", "city" : "NORTHBORO", "loc" : [ -95.30959199999999, 40.612737 ], "pop" : 287, "state" : "IA" }
+{ "_id" : "51648", "city" : "PERCIVAL", "loc" : [ -95.809307, 40.740148 ], "pop" : 327, "state" : "IA" }
+{ "_id" : "51649", "city" : "RANDOLPH", "loc" : [ -95.562386, 40.870353 ], "pop" : 419, "state" : "IA" }
+{ "_id" : "51650", "city" : "RIVERTON", "loc" : [ -95.55780300000001, 40.686968 ], "pop" : 447, "state" : "IA" }
+{ "_id" : "51651", "city" : "SHAMBAUGH", "loc" : [ -95.063591, 40.675735 ], "pop" : 456, "state" : "IA" }
+{ "_id" : "51652", "city" : "SIDNEY", "loc" : [ -95.64027, 40.750671 ], "pop" : 1948, "state" : "IA" }
+{ "_id" : "51653", "city" : "TABOR", "loc" : [ -95.672892, 40.900448 ], "pop" : 1626, "state" : "IA" }
+{ "_id" : "51654", "city" : "THURMAN", "loc" : [ -95.760535, 40.84241 ], "pop" : 521, "state" : "IA" }
+{ "_id" : "51656", "city" : "YORKTOWN", "loc" : [ -95.216335, 40.769244 ], "pop" : 257, "state" : "IA" }
+{ "_id" : "52001", "city" : "DUBUQUE", "loc" : [ -90.68191400000001, 42.514977 ], "pop" : 41934, "state" : "IA" }
+{ "_id" : "52002", "city" : "DUBUQUE", "loc" : [ -90.738372, 42.512191 ], "pop" : 12734, "state" : "IA" }
+{ "_id" : "52003", "city" : "DUBUQUE", "loc" : [ -90.682884, 42.464916 ], "pop" : 13104, "state" : "IA" }
+{ "_id" : "52030", "city" : "ANDREW", "loc" : [ -90.60035000000001, 42.158496 ], "pop" : 741, "state" : "IA" }
+{ "_id" : "52031", "city" : "BELLEVUE", "loc" : [ -90.435603, 42.25825 ], "pop" : 2884, "state" : "IA" }
+{ "_id" : "52032", "city" : "BERNARD", "loc" : [ -90.863032, 42.33207 ], "pop" : 861, "state" : "IA" }
+{ "_id" : "52033", "city" : "CASCADE", "loc" : [ -91.01439499999999, 42.286959 ], "pop" : 3155, "state" : "IA" }
+{ "_id" : "52035", "city" : "COLESBURG", "loc" : [ -91.19628, 42.638346 ], "pop" : 1401, "state" : "IA" }
+{ "_id" : "52036", "city" : "DELAWARE", "loc" : [ -91.347176, 42.477713 ], "pop" : 262, "state" : "IA" }
+{ "_id" : "52037", "city" : "DELMAR", "loc" : [ -90.608712, 41.996065 ], "pop" : 927, "state" : "IA" }
+{ "_id" : "52038", "city" : "DUNDEE", "loc" : [ -91.547697, 42.593979 ], "pop" : 618, "state" : "IA" }
+{ "_id" : "52039", "city" : "DURANGO", "loc" : [ -90.860794, 42.552564 ], "pop" : 874, "state" : "IA" }
+{ "_id" : "52040", "city" : "DYERSVILLE", "loc" : [ -91.11826499999999, 42.483332 ], "pop" : 4709, "state" : "IA" }
+{ "_id" : "52041", "city" : "EARLVILLE", "loc" : [ -91.259658, 42.500101 ], "pop" : 1566, "state" : "IA" }
+{ "_id" : "52042", "city" : "EDGEWOOD", "loc" : [ -91.39495100000001, 42.654098 ], "pop" : 2095, "state" : "IA" }
+{ "_id" : "52043", "city" : "ELKADER", "loc" : [ -91.41430800000001, 42.849627 ], "pop" : 2887, "state" : "IA" }
+{ "_id" : "52044", "city" : "ELKPORT", "loc" : [ -91.283934, 42.739892 ], "pop" : 129, "state" : "IA" }
+{ "_id" : "52045", "city" : "EPWORTH", "loc" : [ -90.931331, 42.443928 ], "pop" : 1931, "state" : "IA" }
+{ "_id" : "52046", "city" : "FARLEY", "loc" : [ -91.00826600000001, 42.445059 ], "pop" : 2120, "state" : "IA" }
+{ "_id" : "52047", "city" : "FARMERSBURG", "loc" : [ -91.338984, 42.952205 ], "pop" : 638, "state" : "IA" }
+{ "_id" : "52048", "city" : "GARBER", "loc" : [ -91.259275, 42.74528 ], "pop" : 191, "state" : "IA" }
+{ "_id" : "52049", "city" : "GARNAVILLO", "loc" : [ -91.215609, 42.876188 ], "pop" : 1408, "state" : "IA" }
+{ "_id" : "52050", "city" : "GREELEY", "loc" : [ -91.32331600000001, 42.59389 ], "pop" : 679, "state" : "IA" }
+{ "_id" : "52052", "city" : "GUTTENBERG", "loc" : [ -91.119015, 42.759443 ], "pop" : 4113, "state" : "IA" }
+{ "_id" : "52053", "city" : "HOLY CROSS", "loc" : [ -90.97298600000001, 42.580778 ], "pop" : 1139, "state" : "IA" }
+{ "_id" : "52054", "city" : "LA MOTTE", "loc" : [ -90.617673, 42.304448 ], "pop" : 1132, "state" : "IA" }
+{ "_id" : "52057", "city" : "MANCHESTER", "loc" : [ -91.449001, 42.483418 ], "pop" : 7823, "state" : "IA" }
+{ "_id" : "52060", "city" : "MAQUOKETA", "loc" : [ -90.677075, 42.07782 ], "pop" : 8374, "state" : "IA" }
+{ "_id" : "52064", "city" : "MILES", "loc" : [ -90.336716, 42.100587 ], "pop" : 1083, "state" : "IA" }
+{ "_id" : "52065", "city" : "NEW VIENNA", "loc" : [ -91.09763700000001, 42.567829 ], "pop" : 835, "state" : "IA" }
+{ "_id" : "52066", "city" : "NORTH BUENA VIST", "loc" : [ -90.958772, 42.671103 ], "pop" : 404, "state" : "IA" }
+{ "_id" : "52068", "city" : "PEOSTA", "loc" : [ -90.809372, 42.443535 ], "pop" : 1565, "state" : "IA" }
+{ "_id" : "52069", "city" : "PRESTON", "loc" : [ -90.395382, 42.053854 ], "pop" : 1376, "state" : "IA" }
+{ "_id" : "52070", "city" : "SABULA", "loc" : [ -90.19553000000001, 42.073668 ], "pop" : 1174, "state" : "IA" }
+{ "_id" : "52071", "city" : "SAINT DONATUS", "loc" : [ -90.484514, 42.33119 ], "pop" : 757, "state" : "IA" }
+{ "_id" : "52072", "city" : "SAINT OLAF", "loc" : [ -91.41754899999999, 42.948179 ], "pop" : 466, "state" : "IA" }
+{ "_id" : "52073", "city" : "SHERRILL", "loc" : [ -90.811486, 42.617078 ], "pop" : 1381, "state" : "IA" }
+{ "_id" : "52074", "city" : "SPRAGUEVILLE", "loc" : [ -90.473044, 42.072742 ], "pop" : 492, "state" : "IA" }
+{ "_id" : "52075", "city" : "SPRINGBROOK", "loc" : [ -90.48463700000001, 42.167401 ], "pop" : 497, "state" : "IA" }
+{ "_id" : "52076", "city" : "STRAWBERRY POINT", "loc" : [ -91.540926, 42.683225 ], "pop" : 1825, "state" : "IA" }
+{ "_id" : "52077", "city" : "VOLGA", "loc" : [ -91.542891, 42.790389 ], "pop" : 562, "state" : "IA" }
+{ "_id" : "52078", "city" : "WORTHINGTON", "loc" : [ -91.106919, 42.393001 ], "pop" : 797, "state" : "IA" }
+{ "_id" : "52079", "city" : "ZWINGLE", "loc" : [ -90.750666, 42.277486 ], "pop" : 1320, "state" : "IA" }
+{ "_id" : "52101", "city" : "DECORAH", "loc" : [ -91.793947, 43.322711 ], "pop" : 13593, "state" : "IA" }
+{ "_id" : "52131", "city" : "BURR OAK", "loc" : [ -91.89207399999999, 43.463912 ], "pop" : 484, "state" : "IA" }
+{ "_id" : "52132", "city" : "CALMAR", "loc" : [ -91.91257899999999, 43.197402 ], "pop" : 2218, "state" : "IA" }
+{ "_id" : "52133", "city" : "CASTALIA", "loc" : [ -91.662904, 43.161179 ], "pop" : 1103, "state" : "IA" }
+{ "_id" : "52134", "city" : "CHESTER", "loc" : [ -92.41552799999999, 43.473021 ], "pop" : 571, "state" : "IA" }
+{ "_id" : "52135", "city" : "CLERMONT", "loc" : [ -91.65518400000001, 43.01298 ], "pop" : 817, "state" : "IA" }
+{ "_id" : "52136", "city" : "CRESCO", "loc" : [ -92.12595399999999, 43.363007 ], "pop" : 5785, "state" : "IA" }
+{ "_id" : "52140", "city" : "DORCHESTER", "loc" : [ -91.50765, 43.442136 ], "pop" : 757, "state" : "IA" }
+{ "_id" : "52141", "city" : "ELGIN", "loc" : [ -91.645375, 42.954845 ], "pop" : 963, "state" : "IA" }
+{ "_id" : "52142", "city" : "FAYETTE", "loc" : [ -91.81388699999999, 42.84941 ], "pop" : 1939, "state" : "IA" }
+{ "_id" : "52144", "city" : "FORT ATKINSON", "loc" : [ -91.91336, 43.133932 ], "pop" : 1095, "state" : "IA" }
+{ "_id" : "52146", "city" : "HARPERS FERRY", "loc" : [ -91.218822, 43.16977 ], "pop" : 915, "state" : "IA" }
+{ "_id" : "52147", "city" : "HAWKEYE", "loc" : [ -91.957764, 42.948702 ], "pop" : 1205, "state" : "IA" }
+{ "_id" : "52150", "city" : "JACKSON JUNCTION", "loc" : [ -92.01844699999999, 43.121369 ], "pop" : 369, "state" : "IA" }
+{ "_id" : "52151", "city" : "LANSING", "loc" : [ -91.265979, 43.366126 ], "pop" : 1717, "state" : "IA" }
+{ "_id" : "52154", "city" : "LAWLER", "loc" : [ -92.143974, 43.093247 ], "pop" : 1450, "state" : "IA" }
+{ "_id" : "52155", "city" : "LIME SPRINGS", "loc" : [ -92.273324, 43.45563 ], "pop" : 672, "state" : "IA" }
+{ "_id" : "52156", "city" : "LUANA", "loc" : [ -91.458275, 43.049281 ], "pop" : 388, "state" : "IA" }
+{ "_id" : "52157", "city" : "MC GREGOR", "loc" : [ -91.18872399999999, 43.023719 ], "pop" : 1344, "state" : "IA" }
+{ "_id" : "52158", "city" : "MARQUETTE", "loc" : [ -91.19214100000001, 43.050457 ], "pop" : 276, "state" : "IA" }
+{ "_id" : "52159", "city" : "MONONA", "loc" : [ -91.45867699999999, 43.073485 ], "pop" : 4670, "state" : "IA" }
+{ "_id" : "52160", "city" : "NEW ALBIN", "loc" : [ -91.294166, 43.489877 ], "pop" : 749, "state" : "IA" }
+{ "_id" : "52161", "city" : "OSSIAN", "loc" : [ -91.773431, 43.137858 ], "pop" : 1349, "state" : "IA" }
+{ "_id" : "52162", "city" : "POSTVILLE", "loc" : [ -91.547809, 43.003619 ], "pop" : 885, "state" : "IA" }
+{ "_id" : "52164", "city" : "RANDALIA", "loc" : [ -91.88462800000001, 42.862551 ], "pop" : 159, "state" : "IA" }
+{ "_id" : "52165", "city" : "RIDGEWAY", "loc" : [ -92.00341299999999, 43.297853 ], "pop" : 636, "state" : "IA" }
+{ "_id" : "52166", "city" : "SAINT LUCAS", "loc" : [ -91.91156100000001, 43.047703 ], "pop" : 638, "state" : "IA" }
+{ "_id" : "52169", "city" : "WADENA", "loc" : [ -91.663865, 42.854956 ], "pop" : 551, "state" : "IA" }
+{ "_id" : "52170", "city" : "WATERVILLE", "loc" : [ -91.26304500000001, 43.263608 ], "pop" : 1204, "state" : "IA" }
+{ "_id" : "52171", "city" : "WAUCOMA", "loc" : [ -92.03022, 43.043329 ], "pop" : 727, "state" : "IA" }
+{ "_id" : "52172", "city" : "WAUKON", "loc" : [ -91.479994, 43.263951 ], "pop" : 6134, "state" : "IA" }
+{ "_id" : "52175", "city" : "ELDORADO", "loc" : [ -91.803602, 42.973232 ], "pop" : 3353, "state" : "IA" }
+{ "_id" : "52201", "city" : "AINSWORTH", "loc" : [ -91.547173, 41.320226 ], "pop" : 1265, "state" : "IA" }
+{ "_id" : "52202", "city" : "ALBURNETT", "loc" : [ -91.639245, 42.158322 ], "pop" : 1038, "state" : "IA" }
+{ "_id" : "52203", "city" : "AMANA", "loc" : [ -91.88545000000001, 41.831284 ], "pop" : 450, "state" : "IA" }
+{ "_id" : "52205", "city" : "ANAMOSA", "loc" : [ -91.285115, 42.107763 ], "pop" : 7264, "state" : "IA" }
+{ "_id" : "52206", "city" : "ATKINS", "loc" : [ -91.87596600000001, 41.988103 ], "pop" : 1347, "state" : "IA" }
+{ "_id" : "52207", "city" : "BALDWIN", "loc" : [ -90.819968, 42.073188 ], "pop" : 362, "state" : "IA" }
+{ "_id" : "52208", "city" : "BELLE PLAINE", "loc" : [ -92.257381, 41.899159 ], "pop" : 3562, "state" : "IA" }
+{ "_id" : "52209", "city" : "BLAIRSTOWN", "loc" : [ -92.08286099999999, 41.906338 ], "pop" : 672, "state" : "IA" }
+{ "_id" : "52210", "city" : "BRANDON", "loc" : [ -92.005892, 42.330912 ], "pop" : 717, "state" : "IA" }
+{ "_id" : "52211", "city" : "BROOKLYN", "loc" : [ -92.428462, 41.732147 ], "pop" : 2196, "state" : "IA" }
+{ "_id" : "52212", "city" : "CENTER JUNCTION", "loc" : [ -91.067013, 42.092585 ], "pop" : 647, "state" : "IA" }
+{ "_id" : "52213", "city" : "CENTER POINT", "loc" : [ -91.775764, 42.189844 ], "pop" : 2462, "state" : "IA" }
+{ "_id" : "52214", "city" : "CENTRAL CITY", "loc" : [ -91.491399, 42.198234 ], "pop" : 3478, "state" : "IA" }
+{ "_id" : "52215", "city" : "CHELSEA", "loc" : [ -92.407815, 41.913132 ], "pop" : 906, "state" : "IA" }
+{ "_id" : "52216", "city" : "CLARENCE", "loc" : [ -91.060457, 41.88958 ], "pop" : 1219, "state" : "IA" }
+{ "_id" : "52217", "city" : "CLUTIER", "loc" : [ -92.376347, 42.078892 ], "pop" : 497, "state" : "IA" }
+{ "_id" : "52218", "city" : "COGGON", "loc" : [ -91.541285, 42.279158 ], "pop" : 1053, "state" : "IA" }
+{ "_id" : "52220", "city" : "CONROY", "loc" : [ -91.96947900000001, 41.74255 ], "pop" : 21, "state" : "IA" }
+{ "_id" : "52222", "city" : "DEEP RIVER", "loc" : [ -92.364513, 41.571713 ], "pop" : 596, "state" : "IA" }
+{ "_id" : "52223", "city" : "DELHI", "loc" : [ -91.27022599999999, 42.427082 ], "pop" : 1530, "state" : "IA" }
+{ "_id" : "52224", "city" : "DYSART", "loc" : [ -92.318731, 42.169017 ], "pop" : 1513, "state" : "IA" }
+{ "_id" : "52225", "city" : "ELBERON", "loc" : [ -92.331447, 42.008769 ], "pop" : 337, "state" : "IA" }
+{ "_id" : "52226", "city" : "ELWOOD", "loc" : [ -90.724609, 41.99083 ], "pop" : 413, "state" : "IA" }
+{ "_id" : "52227", "city" : "ELY", "loc" : [ -91.573767, 41.894275 ], "pop" : 1091, "state" : "IA" }
+{ "_id" : "52228", "city" : "FAIRFAX", "loc" : [ -91.780102, 41.915304 ], "pop" : 1392, "state" : "IA" }
+{ "_id" : "52229", "city" : "GARRISON", "loc" : [ -92.16440900000001, 42.158827 ], "pop" : 872, "state" : "IA" }
+{ "_id" : "52231", "city" : "HARPER", "loc" : [ -92.038758, 41.37283 ], "pop" : 324, "state" : "IA" }
+{ "_id" : "52232", "city" : "HARTWICK", "loc" : [ -92.35384500000001, 41.808019 ], "pop" : 376, "state" : "IA" }
+{ "_id" : "52233", "city" : "HIAWATHA", "loc" : [ -91.67695999999999, 42.042455 ], "pop" : 4966, "state" : "IA" }
+{ "_id" : "52236", "city" : "HOMESTEAD", "loc" : [ -91.879471, 41.733858 ], "pop" : 557, "state" : "IA" }
+{ "_id" : "52237", "city" : "HOPKINTON", "loc" : [ -91.24605099999999, 42.342164 ], "pop" : 1547, "state" : "IA" }
+{ "_id" : "52240", "city" : "IOWA CITY", "loc" : [ -91.51119199999999, 41.654899 ], "pop" : 25049, "state" : "IA" }
+{ "_id" : "52241", "city" : "CORALVILLE", "loc" : [ -91.590608, 41.693666 ], "pop" : 12646, "state" : "IA" }
+{ "_id" : "52245", "city" : "IOWA CITY", "loc" : [ -91.51506999999999, 41.664916 ], "pop" : 21140, "state" : "IA" }
+{ "_id" : "52246", "city" : "IOWA CITY", "loc" : [ -91.56688200000001, 41.643813 ], "pop" : 22869, "state" : "IA" }
+{ "_id" : "52247", "city" : "KALONA", "loc" : [ -91.70567800000001, 41.482299 ], "pop" : 3058, "state" : "IA" }
+{ "_id" : "52248", "city" : "KEOTA", "loc" : [ -91.96406399999999, 41.350429 ], "pop" : 1439, "state" : "IA" }
+{ "_id" : "52249", "city" : "KEYSTONE", "loc" : [ -92.217944, 42.015636 ], "pop" : 1110, "state" : "IA" }
+{ "_id" : "52250", "city" : "KINROSS", "loc" : [ -92.001007, 41.460998 ], "pop" : 374, "state" : "IA" }
+{ "_id" : "52251", "city" : "LADORA", "loc" : [ -92.187281, 41.756353 ], "pop" : 304, "state" : "IA" }
+{ "_id" : "52253", "city" : "LISBON", "loc" : [ -91.38613700000001, 41.921169 ], "pop" : 1581, "state" : "IA" }
+{ "_id" : "52254", "city" : "LOST NATION", "loc" : [ -90.82653999999999, 41.974503 ], "pop" : 768, "state" : "IA" }
+{ "_id" : "52255", "city" : "LOWDEN", "loc" : [ -90.93822, 41.859393 ], "pop" : 1488, "state" : "IA" }
+{ "_id" : "52257", "city" : "LUZERNE", "loc" : [ -92.179334, 41.90614 ], "pop" : 110, "state" : "IA" }
+{ "_id" : "52301", "city" : "MARENGO", "loc" : [ -92.07204900000001, 41.786286 ], "pop" : 4856, "state" : "IA" }
+{ "_id" : "52302", "city" : "MARION", "loc" : [ -91.59413499999999, 42.041095 ], "pop" : 23227, "state" : "IA" }
+{ "_id" : "52305", "city" : "MARTELLE", "loc" : [ -91.321703, 42.003512 ], "pop" : 716, "state" : "IA" }
+{ "_id" : "52306", "city" : "MECHANICSVILLE", "loc" : [ -91.27637, 41.903906 ], "pop" : 1516, "state" : "IA" }
+{ "_id" : "52307", "city" : "MIDDLE AMANA", "loc" : [ -91.882696, 41.799737 ], "pop" : 902, "state" : "IA" }
+{ "_id" : "52308", "city" : "MILLERSBURG", "loc" : [ -92.160843, 41.575099 ], "pop" : 223, "state" : "IA" }
+{ "_id" : "52309", "city" : "MONMOUTH", "loc" : [ -90.878551, 42.07716 ], "pop" : 304, "state" : "IA" }
+{ "_id" : "52310", "city" : "MONTICELLO", "loc" : [ -91.19890100000001, 42.232591 ], "pop" : 5549, "state" : "IA" }
+{ "_id" : "52313", "city" : "MOUNT AUBURN", "loc" : [ -92.159485, 42.255395 ], "pop" : 784, "state" : "IA" }
+{ "_id" : "52314", "city" : "MOUNT VERNON", "loc" : [ -91.42737099999999, 41.928741 ], "pop" : 4874, "state" : "IA" }
+{ "_id" : "52315", "city" : "NEWHALL", "loc" : [ -91.97788799999999, 41.992685 ], "pop" : 1216, "state" : "IA" }
+{ "_id" : "52316", "city" : "NORTH ENGLISH", "loc" : [ -92.089291, 41.524128 ], "pop" : 1287, "state" : "IA" }
+{ "_id" : "52317", "city" : "NORTH LIBERTY", "loc" : [ -91.60612, 41.744318 ], "pop" : 3241, "state" : "IA" }
+{ "_id" : "52318", "city" : "NORWAY", "loc" : [ -91.89197, 41.899176 ], "pop" : 1317, "state" : "IA" }
+{ "_id" : "52320", "city" : "OLIN", "loc" : [ -91.14092599999999, 41.995423 ], "pop" : 1427, "state" : "IA" }
+{ "_id" : "52321", "city" : "ONSLOW", "loc" : [ -90.97305, 42.123509 ], "pop" : 322, "state" : "IA" }
+{ "_id" : "52322", "city" : "OXFORD", "loc" : [ -91.772418, 41.650687 ], "pop" : 3141, "state" : "IA" }
+{ "_id" : "52323", "city" : "OXFORD JUNCTION", "loc" : [ -90.954341, 41.985382 ], "pop" : 909, "state" : "IA" }
+{ "_id" : "52324", "city" : "PALO", "loc" : [ -91.78770299999999, 42.036496 ], "pop" : 1528, "state" : "IA" }
+{ "_id" : "52325", "city" : "PARNELL", "loc" : [ -92.00515900000001, 41.570161 ], "pop" : 499, "state" : "IA" }
+{ "_id" : "52326", "city" : "QUASQUETON", "loc" : [ -91.76795, 42.395551 ], "pop" : 834, "state" : "IA" }
+{ "_id" : "52327", "city" : "RIVERSIDE", "loc" : [ -91.57414, 41.475792 ], "pop" : 1514, "state" : "IA" }
+{ "_id" : "52328", "city" : "ROBINS", "loc" : [ -91.664841, 42.073092 ], "pop" : 877, "state" : "IA" }
+{ "_id" : "52329", "city" : "ROWLEY", "loc" : [ -91.787543, 42.343449 ], "pop" : 1393, "state" : "IA" }
+{ "_id" : "52330", "city" : "RYAN", "loc" : [ -91.484838, 42.343643 ], "pop" : 1201, "state" : "IA" }
+{ "_id" : "52331", "city" : "SCOTCH GROVE", "loc" : [ -91.083682, 42.164441 ], "pop" : 447, "state" : "IA" }
+{ "_id" : "52332", "city" : "SHELLSBURG", "loc" : [ -91.874568, 42.084829 ], "pop" : 1463, "state" : "IA" }
+{ "_id" : "52333", "city" : "SOLON", "loc" : [ -91.50860900000001, 41.809913 ], "pop" : 2894, "state" : "IA" }
+{ "_id" : "52334", "city" : "SOUTH AMANA", "loc" : [ -91.92626, 41.757609 ], "pop" : 45, "state" : "IA" }
+{ "_id" : "52335", "city" : "SOUTH ENGLISH", "loc" : [ -92.102557, 41.46214 ], "pop" : 502, "state" : "IA" }
+{ "_id" : "52336", "city" : "SPRINGVILLE", "loc" : [ -91.43935, 42.060741 ], "pop" : 2011, "state" : "IA" }
+{ "_id" : "52337", "city" : "STANWOOD", "loc" : [ -91.166202, 41.896318 ], "pop" : 970, "state" : "IA" }
+{ "_id" : "52338", "city" : "SWISHER", "loc" : [ -91.67391600000001, 41.826843 ], "pop" : 3101, "state" : "IA" }
+{ "_id" : "52339", "city" : "TAMA", "loc" : [ -92.580049, 41.961642 ], "pop" : 3242, "state" : "IA" }
+{ "_id" : "52341", "city" : "TODDVILLE", "loc" : [ -91.728981, 42.103932 ], "pop" : 1337, "state" : "IA" }
+{ "_id" : "52342", "city" : "TOLEDO", "loc" : [ -92.56620599999999, 42.007696 ], "pop" : 3891, "state" : "IA" }
+{ "_id" : "52343", "city" : "TORONTO", "loc" : [ -90.79388899999999, 41.89709 ], "pop" : 660, "state" : "IA" }
+{ "_id" : "52346", "city" : "VAN HORNE", "loc" : [ -92.104617, 42.019394 ], "pop" : 1215, "state" : "IA" }
+{ "_id" : "52347", "city" : "VICTOR", "loc" : [ -92.284172, 41.729004 ], "pop" : 1092, "state" : "IA" }
+{ "_id" : "52348", "city" : "VINING", "loc" : [ -92.369687, 41.979881 ], "pop" : 244, "state" : "IA" }
+{ "_id" : "52349", "city" : "VINTON", "loc" : [ -91.989154, 42.174284 ], "pop" : 8276, "state" : "IA" }
+{ "_id" : "52352", "city" : "WALKER", "loc" : [ -91.73017900000001, 42.272024 ], "pop" : 1706, "state" : "IA" }
+{ "_id" : "52353", "city" : "WASHINGTON", "loc" : [ -91.698671, 41.301453 ], "pop" : 9381, "state" : "IA" }
+{ "_id" : "52354", "city" : "WATKINS", "loc" : [ -91.99646799999999, 41.903993 ], "pop" : 485, "state" : "IA" }
+{ "_id" : "52355", "city" : "WEBSTER", "loc" : [ -92.176525, 41.436408 ], "pop" : 154, "state" : "IA" }
+{ "_id" : "52356", "city" : "WELLMAN", "loc" : [ -91.83995299999999, 41.470032 ], "pop" : 1904, "state" : "IA" }
+{ "_id" : "52357", "city" : "WEST AMANA", "loc" : [ -91.933566, 41.802996 ], "pop" : 90, "state" : "IA" }
+{ "_id" : "52358", "city" : "WEST BRANCH", "loc" : [ -91.3141, 41.672622 ], "pop" : 3533, "state" : "IA" }
+{ "_id" : "52359", "city" : "WEST CHESTER", "loc" : [ -91.861858, 41.361019 ], "pop" : 500, "state" : "IA" }
+{ "_id" : "52361", "city" : "WILLIAMSBURG", "loc" : [ -92.024011, 41.639308 ], "pop" : 4304, "state" : "IA" }
+{ "_id" : "52362", "city" : "WYOMING", "loc" : [ -90.994024, 42.060352 ], "pop" : 884, "state" : "IA" }
+{ "_id" : "52401", "city" : "CEDAR RAPIDS", "loc" : [ -91.655382, 41.9743 ], "pop" : 1924, "state" : "IA" }
+{ "_id" : "52402", "city" : "CEDAR RAPIDS", "loc" : [ -91.661222, 42.018778 ], "pop" : 37211, "state" : "IA" }
+{ "_id" : "52403", "city" : "CEDAR RAPIDS", "loc" : [ -91.625919, 41.984312 ], "pop" : 25064, "state" : "IA" }
+{ "_id" : "52404", "city" : "CEDAR RAPIDS", "loc" : [ -91.685286, 41.952108 ], "pop" : 28262, "state" : "IA" }
+{ "_id" : "52405", "city" : "CEDAR RAPIDS", "loc" : [ -91.709816, 41.980422 ], "pop" : 23685, "state" : "IA" }
+{ "_id" : "52501", "city" : "HIGHLAND CENTER", "loc" : [ -92.413428, 41.015099 ], "pop" : 29462, "state" : "IA" }
+{ "_id" : "52530", "city" : "AGENCY", "loc" : [ -92.316231, 40.995693 ], "pop" : 1233, "state" : "IA" }
+{ "_id" : "52531", "city" : "ALBIA", "loc" : [ -92.794619, 41.028718 ], "pop" : 6397, "state" : "IA" }
+{ "_id" : "52533", "city" : "BATAVIA", "loc" : [ -92.14305899999999, 40.99048 ], "pop" : 1164, "state" : "IA" }
+{ "_id" : "52534", "city" : "BEACON", "loc" : [ -92.72843, 41.287133 ], "pop" : 1559, "state" : "IA" }
+{ "_id" : "52535", "city" : "BIRMINGHAM", "loc" : [ -91.95343099999999, 40.862605 ], "pop" : 1023, "state" : "IA" }
+{ "_id" : "52536", "city" : "BLAKESBURG", "loc" : [ -92.594037, 40.984763 ], "pop" : 1337, "state" : "IA" }
+{ "_id" : "52537", "city" : "BLOOMFIELD", "loc" : [ -92.398712, 40.732368 ], "pop" : 4788, "state" : "IA" }
+{ "_id" : "52538", "city" : "WEST GROVE", "loc" : [ -92.54984899999999, 40.719646 ], "pop" : 419, "state" : "IA" }
+{ "_id" : "52540", "city" : "BRIGHTON", "loc" : [ -91.828351, 41.154331 ], "pop" : 1686, "state" : "IA" }
+{ "_id" : "52542", "city" : "CANTRIL", "loc" : [ -92.046521, 40.654598 ], "pop" : 490, "state" : "IA" }
+{ "_id" : "52543", "city" : "CEDAR", "loc" : [ -92.509021, 41.212054 ], "pop" : 242, "state" : "IA" }
+{ "_id" : "52544", "city" : "CENTERVILLE", "loc" : [ -92.872826, 40.73259 ], "pop" : 7725, "state" : "IA" }
+{ "_id" : "52548", "city" : "CHILLICOTHE", "loc" : [ -92.53276200000001, 41.077041 ], "pop" : 249, "state" : "IA" }
+{ "_id" : "52549", "city" : "CINCINNATI", "loc" : [ -92.921898, 40.634384 ], "pop" : 793, "state" : "IA" }
+{ "_id" : "52550", "city" : "DELTA", "loc" : [ -92.33591199999999, 41.316682 ], "pop" : 614, "state" : "IA" }
+{ "_id" : "52551", "city" : "DOUDS", "loc" : [ -92.045222, 40.803931 ], "pop" : 15, "state" : "IA" }
+{ "_id" : "52552", "city" : "DRAKESVILLE", "loc" : [ -92.505109, 40.825332 ], "pop" : 1576, "state" : "IA" }
+{ "_id" : "52553", "city" : "EDDYVILLE", "loc" : [ -92.622052, 41.153266 ], "pop" : 1474, "state" : "IA" }
+{ "_id" : "52554", "city" : "ELDON", "loc" : [ -92.226754, 40.92613 ], "pop" : 1603, "state" : "IA" }
+{ "_id" : "52555", "city" : "EXLINE", "loc" : [ -92.826999, 40.641399 ], "pop" : 432, "state" : "IA" }
+{ "_id" : "52556", "city" : "FAIRFIELD", "loc" : [ -91.957611, 41.003943 ], "pop" : 12147, "state" : "IA" }
+{ "_id" : "52560", "city" : "FLORIS", "loc" : [ -92.324715, 40.859071 ], "pop" : 1087, "state" : "IA" }
+{ "_id" : "52561", "city" : "FREMONT", "loc" : [ -92.43618600000001, 41.211739 ], "pop" : 835, "state" : "IA" }
+{ "_id" : "52563", "city" : "HEDRICK", "loc" : [ -92.309725, 41.182578 ], "pop" : 1304, "state" : "IA" }
+{ "_id" : "52565", "city" : "KEOSAUQUA", "loc" : [ -91.970434, 40.74235 ], "pop" : 2022, "state" : "IA" }
+{ "_id" : "52566", "city" : "KIRKVILLE", "loc" : [ -92.46989499999999, 41.117927 ], "pop" : 670, "state" : "IA" }
+{ "_id" : "52567", "city" : "LIBERTYVILLE", "loc" : [ -92.024951, 40.949863 ], "pop" : 658, "state" : "IA" }
+{ "_id" : "52569", "city" : "MELROSE", "loc" : [ -93.01451400000001, 40.966466 ], "pop" : 664, "state" : "IA" }
+{ "_id" : "52570", "city" : "MILTON", "loc" : [ -92.143793, 40.672143 ], "pop" : 851, "state" : "IA" }
+{ "_id" : "52571", "city" : "MORAVIA", "loc" : [ -92.853358, 40.882522 ], "pop" : 1143, "state" : "IA" }
+{ "_id" : "52572", "city" : "MOULTON", "loc" : [ -92.683252, 40.686617 ], "pop" : 1073, "state" : "IA" }
+{ "_id" : "52573", "city" : "MOUNT STERLING", "loc" : [ -91.902663, 40.645765 ], "pop" : 249, "state" : "IA" }
+{ "_id" : "52574", "city" : "MYSTIC", "loc" : [ -92.928437, 40.788268 ], "pop" : 1002, "state" : "IA" }
+{ "_id" : "52575", "city" : "NUMA", "loc" : [ -93.013233, 40.674147 ], "pop" : 563, "state" : "IA" }
+{ "_id" : "52576", "city" : "OLLIE", "loc" : [ -92.135366, 41.200134 ], "pop" : 631, "state" : "IA" }
+{ "_id" : "52577", "city" : "OSKALOOSA", "loc" : [ -92.64393, 41.294205 ], "pop" : 14376, "state" : "IA" }
+{ "_id" : "52580", "city" : "PACKWOOD", "loc" : [ -92.066389, 41.122781 ], "pop" : 862, "state" : "IA" }
+{ "_id" : "52581", "city" : "PLANO", "loc" : [ -93.038554, 40.775109 ], "pop" : 414, "state" : "IA" }
+{ "_id" : "52583", "city" : "PROMISE CITY", "loc" : [ -93.152654, 40.758477 ], "pop" : 370, "state" : "IA" }
+{ "_id" : "52584", "city" : "PULASKI", "loc" : [ -92.25797300000001, 40.694081 ], "pop" : 442, "state" : "IA" }
+{ "_id" : "52585", "city" : "RICHLAND", "loc" : [ -91.973921, 41.193905 ], "pop" : 1082, "state" : "IA" }
+{ "_id" : "52586", "city" : "ROSE HILL", "loc" : [ -92.471958, 41.330918 ], "pop" : 795, "state" : "IA" }
+{ "_id" : "52588", "city" : "SELMA", "loc" : [ -92.11067199999999, 40.851936 ], "pop" : 659, "state" : "IA" }
+{ "_id" : "52590", "city" : "SEYMOUR", "loc" : [ -93.136826, 40.672416 ], "pop" : 1192, "state" : "IA" }
+{ "_id" : "52591", "city" : "SIGOURNEY", "loc" : [ -92.201888, 41.330071 ], "pop" : 3402, "state" : "IA" }
+{ "_id" : "52593", "city" : "UDELL", "loc" : [ -92.718512, 40.783573 ], "pop" : 195, "state" : "IA" }
+{ "_id" : "52594", "city" : "UNIONVILLE", "loc" : [ -92.69345199999999, 40.841637 ], "pop" : 403, "state" : "IA" }
+{ "_id" : "52601", "city" : "BURLINGTON", "loc" : [ -91.116972, 40.808665 ], "pop" : 30564, "state" : "IA" }
+{ "_id" : "52619", "city" : "ARGYLE", "loc" : [ -91.563896, 40.565658 ], "pop" : 1899, "state" : "IA" }
+{ "_id" : "52620", "city" : "BONAPARTE", "loc" : [ -91.789734, 40.714825 ], "pop" : 903, "state" : "IA" }
+{ "_id" : "52621", "city" : "CRAWFORDSVILLE", "loc" : [ -91.541444, 41.209257 ], "pop" : 603, "state" : "IA" }
+{ "_id" : "52623", "city" : "DANVILLE", "loc" : [ -91.314027, 40.854046 ], "pop" : 1694, "state" : "IA" }
+{ "_id" : "52624", "city" : "DENMARK", "loc" : [ -91.326593, 40.748693 ], "pop" : 869, "state" : "IA" }
+{ "_id" : "52625", "city" : "DONNELLSON", "loc" : [ -91.574547, 40.661171 ], "pop" : 1823, "state" : "IA" }
+{ "_id" : "52626", "city" : "FARMINGTON", "loc" : [ -91.744719, 40.639715 ], "pop" : 961, "state" : "IA" }
+{ "_id" : "52627", "city" : "FORT MADISON", "loc" : [ -91.33982899999999, 40.633008 ], "pop" : 14472, "state" : "IA" }
+{ "_id" : "52630", "city" : "HILLSBORO", "loc" : [ -91.711938, 40.837211 ], "pop" : 213, "state" : "IA" }
+{ "_id" : "52631", "city" : "HOUGHTON", "loc" : [ -91.63930000000001, 40.775001 ], "pop" : 448, "state" : "IA" }
+{ "_id" : "52632", "city" : "KEOKUK", "loc" : [ -91.398234, 40.409434 ], "pop" : 13995, "state" : "IA" }
+{ "_id" : "52635", "city" : "LOCKRIDGE", "loc" : [ -91.76454, 41.011867 ], "pop" : 693, "state" : "IA" }
+{ "_id" : "52637", "city" : "MEDIAPOLIS", "loc" : [ -91.132142, 41.005932 ], "pop" : 3044, "state" : "IA" }
+{ "_id" : "52638", "city" : "MIDDLETOWN", "loc" : [ -91.26310599999999, 40.82963 ], "pop" : 440, "state" : "IA" }
+{ "_id" : "52639", "city" : "MONTROSE", "loc" : [ -91.423985, 40.513915 ], "pop" : 1857, "state" : "IA" }
+{ "_id" : "52640", "city" : "MORNING SUN", "loc" : [ -91.258146, 41.098424 ], "pop" : 1165, "state" : "IA" }
+{ "_id" : "52641", "city" : "MOUNT PLEASANT", "loc" : [ -91.56142699999999, 40.964573 ], "pop" : 11113, "state" : "IA" }
+{ "_id" : "52644", "city" : "MOUNT UNION", "loc" : [ -91.413831, 41.03735 ], "pop" : 446, "state" : "IA" }
+{ "_id" : "52645", "city" : "NEW LONDON", "loc" : [ -91.39858700000001, 40.916055 ], "pop" : 3627, "state" : "IA" }
+{ "_id" : "52646", "city" : "OAKVILLE", "loc" : [ -91.04392199999999, 41.100326 ], "pop" : 709, "state" : "IA" }
+{ "_id" : "52647", "city" : "OLDS", "loc" : [ -91.548413, 41.12065 ], "pop" : 711, "state" : "IA" }
+{ "_id" : "52649", "city" : "SALEM", "loc" : [ -91.63362100000001, 40.856804 ], "pop" : 786, "state" : "IA" }
+{ "_id" : "52650", "city" : "SPERRY", "loc" : [ -91.185047, 40.941939 ], "pop" : 700, "state" : "IA" }
+{ "_id" : "52651", "city" : "STOCKPORT", "loc" : [ -91.80349699999999, 40.858933 ], "pop" : 503, "state" : "IA" }
+{ "_id" : "52653", "city" : "WAPELLO", "loc" : [ -91.171921, 41.206982 ], "pop" : 4379, "state" : "IA" }
+{ "_id" : "52654", "city" : "WAYLAND", "loc" : [ -91.658946, 41.144919 ], "pop" : 1626, "state" : "IA" }
+{ "_id" : "52655", "city" : "WEST BURLINGTON", "loc" : [ -91.179894, 40.832081 ], "pop" : 5420, "state" : "IA" }
+{ "_id" : "52656", "city" : "WEST POINT", "loc" : [ -91.439733, 40.714986 ], "pop" : 2144, "state" : "IA" }
+{ "_id" : "52657", "city" : "SAINT PAUL", "loc" : [ -91.53754000000001, 40.769306 ], "pop" : 623, "state" : "IA" }
+{ "_id" : "52658", "city" : "WEVER", "loc" : [ -91.226767, 40.706652 ], "pop" : 546, "state" : "IA" }
+{ "_id" : "52659", "city" : "WINFIELD", "loc" : [ -91.43789200000001, 41.125693 ], "pop" : 1349, "state" : "IA" }
+{ "_id" : "52660", "city" : "YARMOUTH", "loc" : [ -91.317548, 41.029687 ], "pop" : 339, "state" : "IA" }
+{ "_id" : "52701", "city" : "ANDOVER", "loc" : [ -90.238584, 41.992552 ], "pop" : 856, "state" : "IA" }
+{ "_id" : "52720", "city" : "ATALISSA", "loc" : [ -91.174764, 41.561443 ], "pop" : 721, "state" : "IA" }
+{ "_id" : "52721", "city" : "BENNETT", "loc" : [ -90.965613, 41.735267 ], "pop" : 824, "state" : "IA" }
+{ "_id" : "52722", "city" : "BETTENDORF", "loc" : [ -90.494201, 41.550865 ], "pop" : 29785, "state" : "IA" }
+{ "_id" : "52726", "city" : "BLUE GRASS", "loc" : [ -90.738015, 41.511168 ], "pop" : 7536, "state" : "IA" }
+{ "_id" : "52727", "city" : "BRYANT", "loc" : [ -90.338767, 41.962932 ], "pop" : 252, "state" : "IA" }
+{ "_id" : "52729", "city" : "CALAMUS", "loc" : [ -90.741553, 41.811122 ], "pop" : 790, "state" : "IA" }
+{ "_id" : "52730", "city" : "CAMANCHE", "loc" : [ -90.270855, 41.788636 ], "pop" : 5013, "state" : "IA" }
+{ "_id" : "52731", "city" : "CHARLOTTE", "loc" : [ -90.47822600000001, 41.977859 ], "pop" : 756, "state" : "IA" }
+{ "_id" : "52732", "city" : "CLINTON", "loc" : [ -90.207784, 41.851684 ], "pop" : 30723, "state" : "IA" }
+{ "_id" : "52738", "city" : "COLUMBUS JUNCTIO", "loc" : [ -91.37419800000001, 41.279911 ], "pop" : 3945, "state" : "IA" }
+{ "_id" : "52739", "city" : "CONESVILLE", "loc" : [ -91.346498, 41.380454 ], "pop" : 497, "state" : "IA" }
+{ "_id" : "52742", "city" : "DE WITT", "loc" : [ -90.523735, 41.826726 ], "pop" : 6560, "state" : "IA" }
+{ "_id" : "52745", "city" : "BIG ROCK", "loc" : [ -90.77833200000001, 41.735013 ], "pop" : 596, "state" : "IA" }
+{ "_id" : "52746", "city" : "DONAHUE", "loc" : [ -90.682908, 41.709316 ], "pop" : 685, "state" : "IA" }
+{ "_id" : "52747", "city" : "DURANT", "loc" : [ -90.909988, 41.614513 ], "pop" : 2416, "state" : "IA" }
+{ "_id" : "52748", "city" : "ELDRIDGE", "loc" : [ -90.563379, 41.663532 ], "pop" : 6947, "state" : "IA" }
+{ "_id" : "52750", "city" : "GOOSE LAKE", "loc" : [ -90.381855, 41.979898 ], "pop" : 542, "state" : "IA" }
+{ "_id" : "52751", "city" : "GRAND MOUND", "loc" : [ -90.63287800000001, 41.823559 ], "pop" : 1149, "state" : "IA" }
+{ "_id" : "52753", "city" : "LE CLAIRE", "loc" : [ -90.36278799999999, 41.608234 ], "pop" : 4176, "state" : "IA" }
+{ "_id" : "52754", "city" : "LETTS", "loc" : [ -91.20399, 41.293027 ], "pop" : 1394, "state" : "IA" }
+{ "_id" : "52755", "city" : "LONE TREE", "loc" : [ -91.436262, 41.498804 ], "pop" : 2038, "state" : "IA" }
+{ "_id" : "52756", "city" : "LONG GROVE", "loc" : [ -90.55343999999999, 41.721327 ], "pop" : 2326, "state" : "IA" }
+{ "_id" : "52760", "city" : "MOSCOW", "loc" : [ -91.085888, 41.564558 ], "pop" : 752, "state" : "IA" }
+{ "_id" : "52761", "city" : "MUSCATINE", "loc" : [ -91.050928, 41.430378 ], "pop" : 29779, "state" : "IA" }
+{ "_id" : "52765", "city" : "NEW LIBERTY", "loc" : [ -90.859922, 41.713229 ], "pop" : 615, "state" : "IA" }
+{ "_id" : "52766", "city" : "NICHOLS", "loc" : [ -91.293116, 41.476634 ], "pop" : 797, "state" : "IA" }
+{ "_id" : "52768", "city" : "PRINCETON", "loc" : [ -90.370574, 41.685753 ], "pop" : 1529, "state" : "IA" }
+{ "_id" : "52769", "city" : "STOCKTON", "loc" : [ -90.84733199999999, 41.558327 ], "pop" : 777, "state" : "IA" }
+{ "_id" : "52772", "city" : "TIPTON", "loc" : [ -91.136163, 41.756276 ], "pop" : 5751, "state" : "IA" }
+{ "_id" : "52773", "city" : "WALCOTT", "loc" : [ -90.72560300000001, 41.645309 ], "pop" : 705, "state" : "IA" }
+{ "_id" : "52774", "city" : "WELTON", "loc" : [ -90.606785, 41.907472 ], "pop" : 539, "state" : "IA" }
+{ "_id" : "52776", "city" : "WEST LIBERTY", "loc" : [ -91.266847, 41.570055 ], "pop" : 3552, "state" : "IA" }
+{ "_id" : "52777", "city" : "WHEATLAND", "loc" : [ -90.84015100000001, 41.82585 ], "pop" : 1092, "state" : "IA" }
+{ "_id" : "52778", "city" : "WILTON", "loc" : [ -91.009958, 41.585801 ], "pop" : 3032, "state" : "IA" }
+{ "_id" : "52802", "city" : "DAVENPORT", "loc" : [ -90.61409, 41.516358 ], "pop" : 12547, "state" : "IA" }
+{ "_id" : "52803", "city" : "DAVENPORT", "loc" : [ -90.561348, 41.538509 ], "pop" : 25514, "state" : "IA" }
+{ "_id" : "52804", "city" : "DAVENPORT", "loc" : [ -90.61147, 41.538603 ], "pop" : 23671, "state" : "IA" }
+{ "_id" : "52806", "city" : "DAVENPORT", "loc" : [ -90.60384500000001, 41.573271 ], "pop" : 25480, "state" : "IA" }
+{ "_id" : "52807", "city" : "DAVENPORT", "loc" : [ -90.540262, 41.561822 ], "pop" : 8531, "state" : "IA" }
+{ "_id" : "53001", "city" : "ADELL", "loc" : [ -88.02539400000001, 43.615071 ], "pop" : 1221, "state" : "WI" }
+{ "_id" : "53002", "city" : "ALLENTON", "loc" : [ -88.35390099999999, 43.468065 ], "pop" : 1449, "state" : "WI" }
+{ "_id" : "53004", "city" : "BELGIUM", "loc" : [ -87.850908, 43.499465 ], "pop" : 2333, "state" : "WI" }
+{ "_id" : "53005", "city" : "BROOKFIELD", "loc" : [ -88.098, 43.062173 ], "pop" : 19793, "state" : "WI" }
+{ "_id" : "53006", "city" : "SOUTH BYRON", "loc" : [ -88.50972899999999, 43.610934 ], "pop" : 1842, "state" : "WI" }
+{ "_id" : "53007", "city" : "BUTLER", "loc" : [ -88.071043, 43.105405 ], "pop" : 2079, "state" : "WI" }
+{ "_id" : "53010", "city" : "CAMPBELLSPORT", "loc" : [ -88.27285500000001, 43.604183 ], "pop" : 6057, "state" : "WI" }
+{ "_id" : "53011", "city" : "CASCADE", "loc" : [ -88.094658, 43.659106 ], "pop" : 632, "state" : "WI" }
+{ "_id" : "53012", "city" : "CEDARBURG", "loc" : [ -88.00286699999999, 43.303413 ], "pop" : 17552, "state" : "WI" }
+{ "_id" : "53013", "city" : "CEDAR GROVE", "loc" : [ -87.840108, 43.575076 ], "pop" : 2656, "state" : "WI" }
+{ "_id" : "53014", "city" : "CHILTON", "loc" : [ -88.182689, 44.024242 ], "pop" : 7495, "state" : "WI" }
+{ "_id" : "53015", "city" : "CLEVELAND", "loc" : [ -87.767314, 43.921732 ], "pop" : 2490, "state" : "WI" }
+{ "_id" : "53017", "city" : "COLGATE", "loc" : [ -88.24061399999999, 43.199767 ], "pop" : 4155, "state" : "WI" }
+{ "_id" : "53018", "city" : "DELAFIELD", "loc" : [ -88.397248, 43.050019 ], "pop" : 4837, "state" : "WI" }
+{ "_id" : "53019", "city" : "EDEN", "loc" : [ -88.326607, 43.695878 ], "pop" : 1874, "state" : "WI" }
+{ "_id" : "53020", "city" : "ELKHART LAKE", "loc" : [ -87.97667, 43.843553 ], "pop" : 4665, "state" : "WI" }
+{ "_id" : "53021", "city" : "WAUBEKA", "loc" : [ -87.982243, 43.484319 ], "pop" : 3942, "state" : "WI" }
+{ "_id" : "53022", "city" : "GERMANTOWN", "loc" : [ -88.116508, 43.218871 ], "pop" : 13053, "state" : "WI" }
+{ "_id" : "53023", "city" : "GLENBEULAH", "loc" : [ -88.10488599999999, 43.766611 ], "pop" : 1965, "state" : "WI" }
+{ "_id" : "53024", "city" : "GRAFTON", "loc" : [ -87.95208700000001, 43.323146 ], "pop" : 12526, "state" : "WI" }
+{ "_id" : "53027", "city" : "HARTFORD", "loc" : [ -88.370727, 43.315749 ], "pop" : 15889, "state" : "WI" }
+{ "_id" : "53029", "city" : "HARTLAND", "loc" : [ -88.344572, 43.117153 ], "pop" : 14530, "state" : "WI" }
+{ "_id" : "53032", "city" : "HORICON", "loc" : [ -88.631049, 43.446859 ], "pop" : 4724, "state" : "WI" }
+{ "_id" : "53033", "city" : "HUBERTUS", "loc" : [ -88.23114700000001, 43.234269 ], "pop" : 4823, "state" : "WI" }
+{ "_id" : "53035", "city" : "IRON RIDGE", "loc" : [ -88.544072, 43.393415 ], "pop" : 2504, "state" : "WI" }
+{ "_id" : "53036", "city" : "IXONIA", "loc" : [ -88.580567, 43.170667 ], "pop" : 2454, "state" : "WI" }
+{ "_id" : "53037", "city" : "JACKSON", "loc" : [ -88.162592, 43.325243 ], "pop" : 3999, "state" : "WI" }
+{ "_id" : "53038", "city" : "JOHNSON CREEK", "loc" : [ -88.783602, 43.075051 ], "pop" : 2469, "state" : "WI" }
+{ "_id" : "53039", "city" : "JUNEAU", "loc" : [ -88.684517, 43.379199 ], "pop" : 5857, "state" : "WI" }
+{ "_id" : "53040", "city" : "KEWASKUM", "loc" : [ -88.19253, 43.521446 ], "pop" : 6394, "state" : "WI" }
+{ "_id" : "53042", "city" : "KIEL", "loc" : [ -87.995644, 43.934105 ], "pop" : 5345, "state" : "WI" }
+{ "_id" : "53044", "city" : "KOHLER", "loc" : [ -87.78673000000001, 43.738096 ], "pop" : 1900, "state" : "WI" }
+{ "_id" : "53045", "city" : "BROOKFIELD", "loc" : [ -88.146946, 43.066791 ], "pop" : 15412, "state" : "WI" }
+{ "_id" : "53046", "city" : "LANNON", "loc" : [ -88.16386300000001, 43.149651 ], "pop" : 924, "state" : "WI" }
+{ "_id" : "53048", "city" : "KNOWLES", "loc" : [ -88.441309, 43.588489 ], "pop" : 2101, "state" : "WI" }
+{ "_id" : "53049", "city" : "MALONE", "loc" : [ -88.307289, 43.869002 ], "pop" : 3453, "state" : "WI" }
+{ "_id" : "53050", "city" : "MAYVILLE", "loc" : [ -88.545084, 43.504496 ], "pop" : 6394, "state" : "WI" }
+{ "_id" : "53051", "city" : "MENOMONEE FALLS", "loc" : [ -88.112774, 43.160174 ], "pop" : 26840, "state" : "WI" }
+{ "_id" : "53057", "city" : "MOUNT CALVARY", "loc" : [ -88.23992200000001, 43.814211 ], "pop" : 1403, "state" : "WI" }
+{ "_id" : "53058", "city" : "NASHOTAH", "loc" : [ -88.408913, 43.111791 ], "pop" : 2996, "state" : "WI" }
+{ "_id" : "53059", "city" : "NEOSHO", "loc" : [ -88.520482, 43.297841 ], "pop" : 2051, "state" : "WI" }
+{ "_id" : "53061", "city" : "NEW HOLSTEIN", "loc" : [ -88.091083, 43.944639 ], "pop" : 5536, "state" : "WI" }
+{ "_id" : "53063", "city" : "NEWTON", "loc" : [ -87.784764, 43.983621 ], "pop" : 1394, "state" : "WI" }
+{ "_id" : "53065", "city" : "OAKFIELD", "loc" : [ -88.55691899999999, 43.686371 ], "pop" : 2377, "state" : "WI" }
+{ "_id" : "53066", "city" : "OCONOMOWOC", "loc" : [ -88.48622899999999, 43.109497 ], "pop" : 24795, "state" : "WI" }
+{ "_id" : "53069", "city" : "OKAUCHEE", "loc" : [ -88.432287, 43.113011 ], "pop" : 848, "state" : "WI" }
+{ "_id" : "53070", "city" : "OOSTBURG", "loc" : [ -87.796955, 43.622939 ], "pop" : 3916, "state" : "WI" }
+{ "_id" : "53072", "city" : "PEWAUKEE", "loc" : [ -88.27292199999999, 43.078777 ], "pop" : 13337, "state" : "WI" }
+{ "_id" : "53073", "city" : "PLYMOUTH", "loc" : [ -87.977906, 43.75258 ], "pop" : 11811, "state" : "WI" }
+{ "_id" : "53074", "city" : "PORT WASHINGTON", "loc" : [ -87.879659, 43.395463 ], "pop" : 10829, "state" : "WI" }
+{ "_id" : "53075", "city" : "RANDOM LAKE", "loc" : [ -87.98155300000001, 43.567206 ], "pop" : 3299, "state" : "WI" }
+{ "_id" : "53076", "city" : "RICHFIELD", "loc" : [ -88.215467, 43.273925 ], "pop" : 2810, "state" : "WI" }
+{ "_id" : "53078", "city" : "RUBICON", "loc" : [ -88.452793, 43.312144 ], "pop" : 1023, "state" : "WI" }
+{ "_id" : "53079", "city" : "SAINT CLOUD", "loc" : [ -88.184482, 43.807431 ], "pop" : 1524, "state" : "WI" }
+{ "_id" : "53080", "city" : "SAUKVILLE", "loc" : [ -87.956765, 43.391265 ], "pop" : 5460, "state" : "WI" }
+{ "_id" : "53081", "city" : "SHEBOYGAN", "loc" : [ -87.724667, 43.740981 ], "pop" : 42246, "state" : "WI" }
+{ "_id" : "53083", "city" : "HOWARDS GROVE", "loc" : [ -87.748552, 43.788609 ], "pop" : 17004, "state" : "WI" }
+{ "_id" : "53085", "city" : "SHEBOYGAN FALLS", "loc" : [ -87.82422800000001, 43.726598 ], "pop" : 9457, "state" : "WI" }
+{ "_id" : "53086", "city" : "SLINGER", "loc" : [ -88.282377, 43.332211 ], "pop" : 4671, "state" : "WI" }
+{ "_id" : "53089", "city" : "SUSSEX", "loc" : [ -88.227064, 43.144059 ], "pop" : 11913, "state" : "WI" }
+{ "_id" : "53091", "city" : "THERESA", "loc" : [ -88.447766, 43.504477 ], "pop" : 1555, "state" : "WI" }
+{ "_id" : "53092", "city" : "MEQUON", "loc" : [ -87.959357, 43.225145 ], "pop" : 22294, "state" : "WI" }
+{ "_id" : "53093", "city" : "WALDO", "loc" : [ -87.97217000000001, 43.657087 ], "pop" : 2471, "state" : "WI" }
+{ "_id" : "53094", "city" : "WATERTOWN", "loc" : [ -88.71850999999999, 43.192971 ], "pop" : 25240, "state" : "WI" }
+{ "_id" : "53095", "city" : "WEST BEND", "loc" : [ -88.184549, 43.422444 ], "pop" : 38743, "state" : "WI" }
+{ "_id" : "53103", "city" : "BIG BEND", "loc" : [ -88.212182, 42.888463 ], "pop" : 4274, "state" : "WI" }
+{ "_id" : "53104", "city" : "BRISTOL", "loc" : [ -88.04777900000001, 42.532525 ], "pop" : 4514, "state" : "WI" }
+{ "_id" : "53105", "city" : "BURLINGTON", "loc" : [ -88.274886, 42.666034 ], "pop" : 23978, "state" : "WI" }
+{ "_id" : "53108", "city" : "CALEDONIA", "loc" : [ -87.92278, 42.829473 ], "pop" : 2453, "state" : "WI" }
+{ "_id" : "53110", "city" : "CUDAHY", "loc" : [ -87.861983, 42.948976 ], "pop" : 18659, "state" : "WI" }
+{ "_id" : "53114", "city" : "DARIEN", "loc" : [ -88.714217, 42.6435 ], "pop" : 3954, "state" : "WI" }
+{ "_id" : "53115", "city" : "DELAVAN", "loc" : [ -88.627717, 42.622715 ], "pop" : 9967, "state" : "WI" }
+{ "_id" : "53118", "city" : "DOUSMAN", "loc" : [ -88.456754, 42.98506 ], "pop" : 5699, "state" : "WI" }
+{ "_id" : "53119", "city" : "EAGLE", "loc" : [ -88.46742, 42.880942 ], "pop" : 3129, "state" : "WI" }
+{ "_id" : "53120", "city" : "EAST TROY", "loc" : [ -88.409215, 42.803531 ], "pop" : 8712, "state" : "WI" }
+{ "_id" : "53121", "city" : "ELKHORN", "loc" : [ -88.546209, 42.700928 ], "pop" : 11680, "state" : "WI" }
+{ "_id" : "53122", "city" : "ELM GROVE", "loc" : [ -88.085374, 43.047943 ], "pop" : 6394, "state" : "WI" }
+{ "_id" : "53125", "city" : "FONTANA", "loc" : [ -88.56842399999999, 42.542928 ], "pop" : 1697, "state" : "WI" }
+{ "_id" : "53126", "city" : "FRANKSVILLE", "loc" : [ -87.987273, 42.785892 ], "pop" : 6685, "state" : "WI" }
+{ "_id" : "53128", "city" : "GENOA CITY", "loc" : [ -88.348456, 42.532276 ], "pop" : 5027, "state" : "WI" }
+{ "_id" : "53129", "city" : "GREENDALE", "loc" : [ -87.994277, 42.937293 ], "pop" : 15109, "state" : "WI" }
+{ "_id" : "53130", "city" : "HALES CORNERS", "loc" : [ -88.05029999999999, 42.941034 ], "pop" : 7643, "state" : "WI" }
+{ "_id" : "53132", "city" : "FRANKLIN", "loc" : [ -88.008582, 42.901728 ], "pop" : 21840, "state" : "WI" }
+{ "_id" : "53137", "city" : "HELENVILLE", "loc" : [ -88.726887, 43.01007 ], "pop" : 1440, "state" : "WI" }
+{ "_id" : "53139", "city" : "KANSASVILLE", "loc" : [ -88.118037, 42.701246 ], "pop" : 2911, "state" : "WI" }
+{ "_id" : "53140", "city" : "KENOSHA", "loc" : [ -87.829945, 42.605228 ], "pop" : 28062, "state" : "WI" }
+{ "_id" : "53142", "city" : "KENOSHA", "loc" : [ -87.870526, 42.556038 ], "pop" : 28495, "state" : "WI" }
+{ "_id" : "53143", "city" : "KENOSHA", "loc" : [ -87.83005300000001, 42.561726 ], "pop" : 26551, "state" : "WI" }
+{ "_id" : "53144", "city" : "KENOSHA", "loc" : [ -87.876171, 42.605788 ], "pop" : 18824, "state" : "WI" }
+{ "_id" : "53146", "city" : "NEW BERLIN", "loc" : [ -88.15527400000001, 42.97397 ], "pop" : 8149, "state" : "WI" }
+{ "_id" : "53147", "city" : "LAKE GENEVA", "loc" : [ -88.45537899999999, 42.588111 ], "pop" : 11183, "state" : "WI" }
+{ "_id" : "53149", "city" : "MUKWONAGO", "loc" : [ -88.345116, 42.882054 ], "pop" : 12846, "state" : "WI" }
+{ "_id" : "53150", "city" : "MUSKEGO", "loc" : [ -88.12141099999999, 42.904651 ], "pop" : 17098, "state" : "WI" }
+{ "_id" : "53151", "city" : "NEW BERLIN", "loc" : [ -88.09464199999999, 42.982151 ], "pop" : 25731, "state" : "WI" }
+{ "_id" : "53153", "city" : "NORTH PRAIRIE", "loc" : [ -88.394988, 42.938501 ], "pop" : 1732, "state" : "WI" }
+{ "_id" : "53154", "city" : "OAK CREEK", "loc" : [ -87.90266099999999, 42.88916 ], "pop" : 19513, "state" : "WI" }
+{ "_id" : "53156", "city" : "PALMYRA", "loc" : [ -88.590255, 42.879263 ], "pop" : 2748, "state" : "WI" }
+{ "_id" : "53168", "city" : "SALEM", "loc" : [ -88.128731, 42.570922 ], "pop" : 8746, "state" : "WI" }
+{ "_id" : "53172", "city" : "SOUTH MILWAUKEE", "loc" : [ -87.864626, 42.910468 ], "pop" : 20958, "state" : "WI" }
+{ "_id" : "53177", "city" : "STURTEVANT", "loc" : [ -87.903082, 42.69673 ], "pop" : 4774, "state" : "WI" }
+{ "_id" : "53178", "city" : "SULLIVAN", "loc" : [ -88.602569, 42.99825 ], "pop" : 3381, "state" : "WI" }
+{ "_id" : "53179", "city" : "TREVOR", "loc" : [ -88.13869, 42.520112 ], "pop" : 3527, "state" : "WI" }
+{ "_id" : "53181", "city" : "TWIN LAKES", "loc" : [ -88.257318, 42.523173 ], "pop" : 6103, "state" : "WI" }
+{ "_id" : "53182", "city" : "UNION GROVE", "loc" : [ -88.03900400000001, 42.689643 ], "pop" : 6233, "state" : "WI" }
+{ "_id" : "53183", "city" : "WALES", "loc" : [ -88.378742, 43.008787 ], "pop" : 3171, "state" : "WI" }
+{ "_id" : "53184", "city" : "WALWORTH", "loc" : [ -88.602738, 42.535005 ], "pop" : 2831, "state" : "WI" }
+{ "_id" : "53185", "city" : "WIND LAKE", "loc" : [ -88.19335, 42.796882 ], "pop" : 11362, "state" : "WI" }
+{ "_id" : "53186", "city" : "WAUKESHA", "loc" : [ -88.219559, 42.999304 ], "pop" : 46445, "state" : "WI" }
+{ "_id" : "53188", "city" : "WAUKESHA", "loc" : [ -88.27048000000001, 43.012848 ], "pop" : 33794, "state" : "WI" }
+{ "_id" : "53190", "city" : "WHITEWATER", "loc" : [ -88.742864, 42.827174 ], "pop" : 16723, "state" : "WI" }
+{ "_id" : "53191", "city" : "WILLIAMS BAY", "loc" : [ -88.54308899999999, 42.576678 ], "pop" : 2208, "state" : "WI" }
+{ "_id" : "53202", "city" : "MILWAUKEE", "loc" : [ -87.896792, 43.050601 ], "pop" : 20178, "state" : "WI" }
+{ "_id" : "53203", "city" : "MILWAUKEE", "loc" : [ -87.915375, 43.040299 ], "pop" : 456, "state" : "WI" }
+{ "_id" : "53204", "city" : "MILWAUKEE", "loc" : [ -87.931685, 43.015778 ], "pop" : 41978, "state" : "WI" }
+{ "_id" : "53205", "city" : "MILWAUKEE", "loc" : [ -87.935332, 43.052841 ], "pop" : 14708, "state" : "WI" }
+{ "_id" : "53206", "city" : "MILWAUKEE", "loc" : [ -87.934714, 43.075324 ], "pop" : 42009, "state" : "WI" }
+{ "_id" : "53207", "city" : "BAY VIEW", "loc" : [ -87.894598, 42.981405 ], "pop" : 49199, "state" : "WI" }
+{ "_id" : "53208", "city" : "MILWAUKEE", "loc" : [ -87.96245399999999, 43.048775 ], "pop" : 42238, "state" : "WI" }
+{ "_id" : "53209", "city" : "MILWAUKEE", "loc" : [ -87.947834, 43.118765 ], "pop" : 51008, "state" : "WI" }
+{ "_id" : "53210", "city" : "MILWAUKEE", "loc" : [ -87.97146600000001, 43.068545 ], "pop" : 32111, "state" : "WI" }
+{ "_id" : "53211", "city" : "SHOREWOOD", "loc" : [ -87.88507799999999, 43.080517 ], "pop" : 37036, "state" : "WI" }
+{ "_id" : "53212", "city" : "MILWAUKEE", "loc" : [ -87.90841500000001, 43.071195 ], "pop" : 37237, "state" : "WI" }
+{ "_id" : "53213", "city" : "WAUWATOSA", "loc" : [ -88.00075699999999, 43.051316 ], "pop" : 27606, "state" : "WI" }
+{ "_id" : "53214", "city" : "WEST ALLIS", "loc" : [ -88.010757, 43.019113 ], "pop" : 38491, "state" : "WI" }
+{ "_id" : "53215", "city" : "WEST MILWAUKEE", "loc" : [ -87.94174, 43.000411 ], "pop" : 48228, "state" : "WI" }
+{ "_id" : "53216", "city" : "MILWAUKEE", "loc" : [ -87.97421799999999, 43.085868 ], "pop" : 34881, "state" : "WI" }
+{ "_id" : "53217", "city" : "MILWAUKEE", "loc" : [ -87.90726100000001, 43.14086 ], "pop" : 30065, "state" : "WI" }
+{ "_id" : "53218", "city" : "MILWAUKEE", "loc" : [ -87.993161, 43.11218 ], "pop" : 40443, "state" : "WI" }
+{ "_id" : "53219", "city" : "MILWAUKEE", "loc" : [ -87.99436799999999, 42.995909 ], "pop" : 35271, "state" : "WI" }
+{ "_id" : "53220", "city" : "GREENFIELD", "loc" : [ -87.992209, 42.968186 ], "pop" : 25819, "state" : "WI" }
+{ "_id" : "53221", "city" : "MILWAUKEE", "loc" : [ -87.944734, 42.954864 ], "pop" : 35767, "state" : "WI" }
+{ "_id" : "53222", "city" : "MILWAUKEE", "loc" : [ -88.02687, 43.08283 ], "pop" : 25406, "state" : "WI" }
+{ "_id" : "53223", "city" : "MILWAUKEE", "loc" : [ -87.989818, 43.162374 ], "pop" : 30272, "state" : "WI" }
+{ "_id" : "53224", "city" : "MILWAUKEE", "loc" : [ -88.03274399999999, 43.159415 ], "pop" : 18182, "state" : "WI" }
+{ "_id" : "53225", "city" : "MILWAUKEE", "loc" : [ -88.03464, 43.115416 ], "pop" : 25395, "state" : "WI" }
+{ "_id" : "53226", "city" : "WAUWATOSA", "loc" : [ -88.041386, 43.050006 ], "pop" : 19216, "state" : "WI" }
+{ "_id" : "53227", "city" : "MILWAUKEE", "loc" : [ -88.036384, 42.994919 ], "pop" : 23150, "state" : "WI" }
+{ "_id" : "53228", "city" : "GREENFIELD", "loc" : [ -88.034638, 42.970251 ], "pop" : 12634, "state" : "WI" }
+{ "_id" : "53233", "city" : "MILWAUKEE", "loc" : [ -87.93566, 43.040738 ], "pop" : 16569, "state" : "WI" }
+{ "_id" : "53402", "city" : "RACINE", "loc" : [ -87.795985, 42.772596 ], "pop" : 31959, "state" : "WI" }
+{ "_id" : "53403", "city" : "RACINE", "loc" : [ -87.80137499999999, 42.706015 ], "pop" : 26329, "state" : "WI" }
+{ "_id" : "53404", "city" : "RACINE", "loc" : [ -87.8053, 42.743348 ], "pop" : 17129, "state" : "WI" }
+{ "_id" : "53405", "city" : "RACINE", "loc" : [ -87.823329, 42.716112 ], "pop" : 26652, "state" : "WI" }
+{ "_id" : "53406", "city" : "RACINE", "loc" : [ -87.855104, 42.724162 ], "pop" : 20925, "state" : "WI" }
+{ "_id" : "53502", "city" : "ALBANY", "loc" : [ -89.435695, 42.715535 ], "pop" : 1886, "state" : "WI" }
+{ "_id" : "53503", "city" : "ARENA", "loc" : [ -89.938614, 43.152111 ], "pop" : 1554, "state" : "WI" }
+{ "_id" : "53504", "city" : "ARGYLE", "loc" : [ -89.85983400000001, 42.695532 ], "pop" : 2048, "state" : "WI" }
+{ "_id" : "53505", "city" : "AVALON", "loc" : [ -88.837142, 42.65979 ], "pop" : 373, "state" : "WI" }
+{ "_id" : "53506", "city" : "AVOCA", "loc" : [ -90.288859, 43.157137 ], "pop" : 1072, "state" : "WI" }
+{ "_id" : "53507", "city" : "BARNEVELD", "loc" : [ -89.904229, 43.015797 ], "pop" : 1301, "state" : "WI" }
+{ "_id" : "53508", "city" : "BELLEVILLE", "loc" : [ -89.53773, 42.866906 ], "pop" : 3500, "state" : "WI" }
+{ "_id" : "53510", "city" : "BELMONT", "loc" : [ -90.335881, 42.730784 ], "pop" : 1477, "state" : "WI" }
+{ "_id" : "53511", "city" : "SHOPIERE", "loc" : [ -89.039897, 42.522871 ], "pop" : 46738, "state" : "WI" }
+{ "_id" : "53515", "city" : "BLACK EARTH", "loc" : [ -89.738974, 43.132213 ], "pop" : 1824, "state" : "WI" }
+{ "_id" : "53516", "city" : "BLANCHARDVILLE", "loc" : [ -89.85551100000001, 42.806186 ], "pop" : 1810, "state" : "WI" }
+{ "_id" : "53517", "city" : "BLUE MOUNDS", "loc" : [ -89.83445500000001, 43.004964 ], "pop" : 639, "state" : "WI" }
+{ "_id" : "53518", "city" : "BLUE RIVER", "loc" : [ -90.587312, 43.236567 ], "pop" : 1520, "state" : "WI" }
+{ "_id" : "53520", "city" : "BRODHEAD", "loc" : [ -89.371409, 42.611074 ], "pop" : 5825, "state" : "WI" }
+{ "_id" : "53521", "city" : "BROOKLYN", "loc" : [ -89.38181400000001, 42.842327 ], "pop" : 2329, "state" : "WI" }
+{ "_id" : "53522", "city" : "BROWNTOWN", "loc" : [ -89.78158000000001, 42.557872 ], "pop" : 1146, "state" : "WI" }
+{ "_id" : "53523", "city" : "CAMBRIDGE", "loc" : [ -89.02090099999999, 42.99176 ], "pop" : 4102, "state" : "WI" }
+{ "_id" : "53525", "city" : "CLINTON", "loc" : [ -88.87047699999999, 42.553481 ], "pop" : 3627, "state" : "WI" }
+{ "_id" : "53526", "city" : "COBB", "loc" : [ -90.332408, 42.966009 ], "pop" : 542, "state" : "WI" }
+{ "_id" : "53527", "city" : "COTTAGE GROVE", "loc" : [ -89.20169199999999, 43.078405 ], "pop" : 4349, "state" : "WI" }
+{ "_id" : "53528", "city" : "CROSS PLAINS", "loc" : [ -89.63966499999999, 43.113214 ], "pop" : 3622, "state" : "WI" }
+{ "_id" : "53529", "city" : "DANE", "loc" : [ -89.51174, 43.242414 ], "pop" : 1572, "state" : "WI" }
+{ "_id" : "53530", "city" : "DARLINGTON", "loc" : [ -90.110648, 42.687816 ], "pop" : 4224, "state" : "WI" }
+{ "_id" : "53531", "city" : "DEERFIELD", "loc" : [ -89.08619899999999, 43.057106 ], "pop" : 2668, "state" : "WI" }
+{ "_id" : "53532", "city" : "DE FOREST", "loc" : [ -89.329652, 43.235748 ], "pop" : 9321, "state" : "WI" }
+{ "_id" : "53533", "city" : "DODGEVILLE", "loc" : [ -90.140433, 42.969779 ], "pop" : 5663, "state" : "WI" }
+{ "_id" : "53534", "city" : "EDGERTON", "loc" : [ -89.06415699999999, 42.838605 ], "pop" : 9749, "state" : "WI" }
+{ "_id" : "53536", "city" : "EVANSVILLE", "loc" : [ -89.287712, 42.773216 ], "pop" : 5986, "state" : "WI" }
+{ "_id" : "53538", "city" : "FORT ATKINSON", "loc" : [ -88.846689, 42.922902 ], "pop" : 15624, "state" : "WI" }
+{ "_id" : "53541", "city" : "GRATIOT", "loc" : [ -90.024344, 42.575852 ], "pop" : 1129, "state" : "WI" }
+{ "_id" : "53543", "city" : "HIGHLAND", "loc" : [ -90.36501, 43.052368 ], "pop" : 1586, "state" : "WI" }
+{ "_id" : "53544", "city" : "HOLLANDALE", "loc" : [ -89.91297299999999, 42.877321 ], "pop" : 591, "state" : "WI" }
+{ "_id" : "53545", "city" : "JANESVILLE", "loc" : [ -89.033124, 42.691542 ], "pop" : 40339, "state" : "WI" }
+{ "_id" : "53546", "city" : "JANESVILLE", "loc" : [ -89.002534, 42.668254 ], "pop" : 22324, "state" : "WI" }
+{ "_id" : "53549", "city" : "JEFFERSON", "loc" : [ -88.807765, 43.000557 ], "pop" : 8540, "state" : "WI" }
+{ "_id" : "53550", "city" : "JUDA", "loc" : [ -89.502608, 42.567874 ], "pop" : 1177, "state" : "WI" }
+{ "_id" : "53551", "city" : "LAKE MILLS", "loc" : [ -88.913335, 43.081576 ], "pop" : 6196, "state" : "WI" }
+{ "_id" : "53553", "city" : "LINDEN", "loc" : [ -90.279726, 42.918419 ], "pop" : 522, "state" : "WI" }
+{ "_id" : "53554", "city" : "LIVINGSTON", "loc" : [ -90.441986, 42.904432 ], "pop" : 964, "state" : "WI" }
+{ "_id" : "53555", "city" : "LODI", "loc" : [ -89.555421, 43.326964 ], "pop" : 5765, "state" : "WI" }
+{ "_id" : "53556", "city" : "LONE ROCK", "loc" : [ -90.235229, 43.220773 ], "pop" : 2367, "state" : "WI" }
+{ "_id" : "53557", "city" : "LOWELL", "loc" : [ -88.787263, 43.342018 ], "pop" : 231, "state" : "WI" }
+{ "_id" : "53558", "city" : "MC FARLAND", "loc" : [ -89.29477300000001, 43.010651 ], "pop" : 8040, "state" : "WI" }
+{ "_id" : "53559", "city" : "MARSHALL", "loc" : [ -89.07533100000001, 43.163639 ], "pop" : 4175, "state" : "WI" }
+{ "_id" : "53560", "city" : "MAZOMANIE", "loc" : [ -89.763616, 43.184746 ], "pop" : 3176, "state" : "WI" }
+{ "_id" : "53561", "city" : "MERRIMAC", "loc" : [ -89.632254, 43.385527 ], "pop" : 1366, "state" : "WI" }
+{ "_id" : "53562", "city" : "MIDDLETON", "loc" : [ -89.50725799999999, 43.105196 ], "pop" : 16575, "state" : "WI" }
+{ "_id" : "53563", "city" : "MILTON", "loc" : [ -88.953087, 42.779087 ], "pop" : 7309, "state" : "WI" }
+{ "_id" : "53565", "city" : "MINERAL POINT", "loc" : [ -90.164556, 42.854696 ], "pop" : 4566, "state" : "WI" }
+{ "_id" : "53566", "city" : "MONROE", "loc" : [ -89.6403, 42.599076 ], "pop" : 13720, "state" : "WI" }
+{ "_id" : "53569", "city" : "MONTFORT", "loc" : [ -90.44473000000001, 42.975745 ], "pop" : 1129, "state" : "WI" }
+{ "_id" : "53570", "city" : "MONTICELLO", "loc" : [ -89.608069, 42.741482 ], "pop" : 2315, "state" : "WI" }
+{ "_id" : "53572", "city" : "MOUNT HOREB", "loc" : [ -89.74144800000001, 43.002022 ], "pop" : 7193, "state" : "WI" }
+{ "_id" : "53573", "city" : "MUSCODA", "loc" : [ -90.456998, 43.207375 ], "pop" : 3774, "state" : "WI" }
+{ "_id" : "53574", "city" : "NEW GLARUS", "loc" : [ -89.643666, 42.814344 ], "pop" : 2540, "state" : "WI" }
+{ "_id" : "53575", "city" : "OREGON", "loc" : [ -89.387002, 42.929485 ], "pop" : 9719, "state" : "WI" }
+{ "_id" : "53576", "city" : "ORFORDVILLE", "loc" : [ -89.253292, 42.627766 ], "pop" : 1923, "state" : "WI" }
+{ "_id" : "53577", "city" : "PLAIN", "loc" : [ -90.055825, 43.292693 ], "pop" : 1292, "state" : "WI" }
+{ "_id" : "53578", "city" : "PRAIRIE DU SAC", "loc" : [ -89.745233, 43.295631 ], "pop" : 4060, "state" : "WI" }
+{ "_id" : "53579", "city" : "REESEVILLE", "loc" : [ -88.857117, 43.301278 ], "pop" : 2027, "state" : "WI" }
+{ "_id" : "53580", "city" : "REWEY", "loc" : [ -90.38036099999999, 42.859393 ], "pop" : 601, "state" : "WI" }
+{ "_id" : "53581", "city" : "GILLINGHAM", "loc" : [ -90.391378, 43.362714 ], "pop" : 10306, "state" : "WI" }
+{ "_id" : "53582", "city" : "RIDGEWAY", "loc" : [ -89.988946, 43.007654 ], "pop" : 924, "state" : "WI" }
+{ "_id" : "53583", "city" : "SAUK CITY", "loc" : [ -89.741777, 43.268558 ], "pop" : 5186, "state" : "WI" }
+{ "_id" : "53585", "city" : "SHARON", "loc" : [ -88.726522, 42.519367 ], "pop" : 2297, "state" : "WI" }
+{ "_id" : "53586", "city" : "SHULLSBURG", "loc" : [ -90.226619, 42.57856 ], "pop" : 2124, "state" : "WI" }
+{ "_id" : "53587", "city" : "SOUTH WAYNE", "loc" : [ -89.88884400000001, 42.582199 ], "pop" : 1444, "state" : "WI" }
+{ "_id" : "53588", "city" : "SPRING GREEN", "loc" : [ -90.06760800000001, 43.18835 ], "pop" : 3439, "state" : "WI" }
+{ "_id" : "53589", "city" : "STOUGHTON", "loc" : [ -89.223989, 42.929007 ], "pop" : 15469, "state" : "WI" }
+{ "_id" : "53590", "city" : "SUN PRAIRIE", "loc" : [ -89.222662, 43.186901 ], "pop" : 18776, "state" : "WI" }
+{ "_id" : "53593", "city" : "VERONA", "loc" : [ -89.55224699999999, 42.999913 ], "pop" : 9932, "state" : "WI" }
+{ "_id" : "53594", "city" : "WATERLOO", "loc" : [ -88.983835, 43.183171 ], "pop" : 4106, "state" : "WI" }
+{ "_id" : "53597", "city" : "WAUNAKEE", "loc" : [ -89.45317, 43.181828 ], "pop" : 9691, "state" : "WI" }
+{ "_id" : "53598", "city" : "WINDSOR", "loc" : [ -89.341469, 43.214121 ], "pop" : 1825, "state" : "WI" }
+{ "_id" : "53703", "city" : "MADISON", "loc" : [ -89.38306799999999, 43.077535 ], "pop" : 25721, "state" : "WI" }
+{ "_id" : "53704", "city" : "MADISON", "loc" : [ -89.352295, 43.120526 ], "pop" : 40639, "state" : "WI" }
+{ "_id" : "53705", "city" : "MADISON", "loc" : [ -89.452823, 43.072999 ], "pop" : 29114, "state" : "WI" }
+{ "_id" : "53706", "city" : "MADISON", "loc" : [ -89.409362, 43.076929 ], "pop" : 3587, "state" : "WI" }
+{ "_id" : "53711", "city" : "MADISON", "loc" : [ -89.452558, 43.035644 ], "pop" : 42198, "state" : "WI" }
+{ "_id" : "53713", "city" : "FITCHBURG", "loc" : [ -89.39000799999999, 43.037381 ], "pop" : 18082, "state" : "WI" }
+{ "_id" : "53714", "city" : "MADISON", "loc" : [ -89.311758, 43.097735 ], "pop" : 17978, "state" : "WI" }
+{ "_id" : "53715", "city" : "MADISON", "loc" : [ -89.40004500000001, 43.065287 ], "pop" : 13545, "state" : "WI" }
+{ "_id" : "53716", "city" : "MONONA", "loc" : [ -89.315921, 43.067413 ], "pop" : 20296, "state" : "WI" }
+{ "_id" : "53717", "city" : "MADISON", "loc" : [ -89.50798399999999, 43.073587 ], "pop" : 7675, "state" : "WI" }
+{ "_id" : "53718", "city" : "MADISON", "loc" : [ -89.40733899999999, 43.152143 ], "pop" : 63, "state" : "WI" }
+{ "_id" : "53719", "city" : "MADISON", "loc" : [ -89.499324, 43.03207 ], "pop" : 9669, "state" : "WI" }
+{ "_id" : "53801", "city" : "BAGLEY", "loc" : [ -91.068502, 42.920734 ], "pop" : 879, "state" : "WI" }
+{ "_id" : "53803", "city" : "BENTON", "loc" : [ -90.33804499999999, 42.534901 ], "pop" : 153, "state" : "WI" }
+{ "_id" : "53804", "city" : "BLOOMINGTON", "loc" : [ -90.90990499999999, 42.872598 ], "pop" : 1485, "state" : "WI" }
+{ "_id" : "53805", "city" : "BOSCOBEL", "loc" : [ -90.706101, 43.139327 ], "pop" : 4755, "state" : "WI" }
+{ "_id" : "53806", "city" : "CASSVILLE", "loc" : [ -90.960751, 42.728791 ], "pop" : 2134, "state" : "WI" }
+{ "_id" : "53807", "city" : "CUBA CITY", "loc" : [ -90.474907, 42.599073 ], "pop" : 6856, "state" : "WI" }
+{ "_id" : "53809", "city" : "FENNIMORE", "loc" : [ -90.65500900000001, 42.988558 ], "pop" : 3668, "state" : "WI" }
+{ "_id" : "53810", "city" : "GLEN HAVEN", "loc" : [ -91.000451, 42.820372 ], "pop" : 614, "state" : "WI" }
+{ "_id" : "53811", "city" : "HAZEL GREEN", "loc" : [ -90.511782, 42.535913 ], "pop" : 3228, "state" : "WI" }
+{ "_id" : "53813", "city" : "LANCASTER", "loc" : [ -90.71090599999999, 42.844469 ], "pop" : 6537, "state" : "WI" }
+{ "_id" : "53816", "city" : "MOUNT HOPE", "loc" : [ -90.86648, 42.968862 ], "pop" : 737, "state" : "WI" }
+{ "_id" : "53818", "city" : "PLATTEVILLE", "loc" : [ -90.485406, 42.73932 ], "pop" : 13067, "state" : "WI" }
+{ "_id" : "53820", "city" : "POTOSI", "loc" : [ -90.700153, 42.6884 ], "pop" : 2845, "state" : "WI" }
+{ "_id" : "53821", "city" : "PRAIRIE DU CHIEN", "loc" : [ -91.119305, 43.042649 ], "pop" : 7950, "state" : "WI" }
+{ "_id" : "53825", "city" : "STITZER", "loc" : [ -90.607924, 42.92142 ], "pop" : 469, "state" : "WI" }
+{ "_id" : "53826", "city" : "WAUZEKA", "loc" : [ -90.923885, 43.114264 ], "pop" : 1455, "state" : "WI" }
+{ "_id" : "53827", "city" : "WOODMAN", "loc" : [ -90.824539, 43.057697 ], "pop" : 412, "state" : "WI" }
+{ "_id" : "53901", "city" : "PORTAGE", "loc" : [ -89.47139, 43.550145 ], "pop" : 11280, "state" : "WI" }
+{ "_id" : "53910", "city" : "ADAMS", "loc" : [ -89.82186900000001, 43.896688 ], "pop" : 2342, "state" : "WI" }
+{ "_id" : "53911", "city" : "ARLINGTON", "loc" : [ -89.36308200000001, 43.326868 ], "pop" : 1329, "state" : "WI" }
+{ "_id" : "53913", "city" : "BARABOO", "loc" : [ -89.746168, 43.482531 ], "pop" : 14955, "state" : "WI" }
+{ "_id" : "53916", "city" : "BEAVER DAM", "loc" : [ -88.840681, 43.461574 ], "pop" : 19539, "state" : "WI" }
+{ "_id" : "53919", "city" : "BRANDON", "loc" : [ -88.784099, 43.72579 ], "pop" : 2953, "state" : "WI" }
+{ "_id" : "53920", "city" : "BRIGGSVILLE", "loc" : [ -89.580259, 43.675865 ], "pop" : 951, "state" : "WI" }
+{ "_id" : "53922", "city" : "BURNETT", "loc" : [ -88.717606, 43.511609 ], "pop" : 909, "state" : "WI" }
+{ "_id" : "53923", "city" : "CAMBRIA", "loc" : [ -89.11561399999999, 43.57239 ], "pop" : 2566, "state" : "WI" }
+{ "_id" : "53924", "city" : "CAZENOVIA", "loc" : [ -90.279572, 43.498715 ], "pop" : 717, "state" : "WI" }
+{ "_id" : "53925", "city" : "COLUMBUS", "loc" : [ -89.027089, 43.331494 ], "pop" : 6847, "state" : "WI" }
+{ "_id" : "53926", "city" : "DALTON", "loc" : [ -89.191768, 43.67178 ], "pop" : 685, "state" : "WI" }
+{ "_id" : "53929", "city" : "ELROY", "loc" : [ -90.28885699999999, 43.751616 ], "pop" : 3270, "state" : "WI" }
+{ "_id" : "53930", "city" : "ENDEAVOR", "loc" : [ -89.461699, 43.696305 ], "pop" : 773, "state" : "WI" }
+{ "_id" : "53932", "city" : "FALL RIVER", "loc" : [ -89.062513, 43.400838 ], "pop" : 1996, "state" : "WI" }
+{ "_id" : "53933", "city" : "FOX LAKE", "loc" : [ -88.90408100000001, 43.581507 ], "pop" : 3233, "state" : "WI" }
+{ "_id" : "53934", "city" : "FRIENDSHIP", "loc" : [ -89.814875, 43.989629 ], "pop" : 4859, "state" : "WI" }
+{ "_id" : "53936", "city" : "GRAND MARSH", "loc" : [ -89.655663, 43.856789 ], "pop" : 1907, "state" : "WI" }
+{ "_id" : "53937", "city" : "HILLPOINT", "loc" : [ -90.15879200000001, 43.395129 ], "pop" : 980, "state" : "WI" }
+{ "_id" : "53939", "city" : "KINGSTON", "loc" : [ -89.131997, 43.69236 ], "pop" : 346, "state" : "WI" }
+{ "_id" : "53941", "city" : "LA VALLE", "loc" : [ -90.127966, 43.569874 ], "pop" : 2383, "state" : "WI" }
+{ "_id" : "53943", "city" : "LOGANVILLE", "loc" : [ -90.033688, 43.405046 ], "pop" : 877, "state" : "WI" }
+{ "_id" : "53944", "city" : "LYNDON STATION", "loc" : [ -89.891543, 43.689875 ], "pop" : 2010, "state" : "WI" }
+{ "_id" : "53946", "city" : "MARKESAN", "loc" : [ -89.00697099999999, 43.714015 ], "pop" : 4015, "state" : "WI" }
+{ "_id" : "53947", "city" : "MARQUETTE", "loc" : [ -89.13965399999999, 43.745886 ], "pop" : 183, "state" : "WI" }
+{ "_id" : "53948", "city" : "MAUSTON", "loc" : [ -90.06408500000001, 43.793383 ], "pop" : 7325, "state" : "WI" }
+{ "_id" : "53949", "city" : "MONTELLO", "loc" : [ -89.35864100000001, 43.768984 ], "pop" : 4392, "state" : "WI" }
+{ "_id" : "53950", "city" : "NEW LISBON", "loc" : [ -90.152407, 43.88775 ], "pop" : 3320, "state" : "WI" }
+{ "_id" : "53951", "city" : "NORTH FREEDOM", "loc" : [ -89.849019, 43.410562 ], "pop" : 1858, "state" : "WI" }
+{ "_id" : "53952", "city" : "OXFORD", "loc" : [ -89.563175, 43.779914 ], "pop" : 1217, "state" : "WI" }
+{ "_id" : "53954", "city" : "PARDEEVILLE", "loc" : [ -89.326514, 43.533975 ], "pop" : 6321, "state" : "WI" }
+{ "_id" : "53955", "city" : "POYNETTE", "loc" : [ -89.418857, 43.401342 ], "pop" : 4264, "state" : "WI" }
+{ "_id" : "53956", "city" : "RANDOLPH", "loc" : [ -89.00299200000001, 43.539696 ], "pop" : 3206, "state" : "WI" }
+{ "_id" : "53959", "city" : "REEDSBURG", "loc" : [ -89.995948, 43.531581 ], "pop" : 9118, "state" : "WI" }
+{ "_id" : "53960", "city" : "RIO", "loc" : [ -89.23536199999999, 43.423053 ], "pop" : 2766, "state" : "WI" }
+{ "_id" : "53961", "city" : "ROCK SPRINGS", "loc" : [ -89.921834, 43.468098 ], "pop" : 735, "state" : "WI" }
+{ "_id" : "53963", "city" : "WAUPUN", "loc" : [ -88.737253, 43.632441 ], "pop" : 11222, "state" : "WI" }
+{ "_id" : "53964", "city" : "WESTFIELD", "loc" : [ -89.502015, 43.896788 ], "pop" : 3309, "state" : "WI" }
+{ "_id" : "53965", "city" : "WISCONSIN DELLS", "loc" : [ -89.76652, 43.650789 ], "pop" : 7650, "state" : "WI" }
+{ "_id" : "53968", "city" : "WONEWOC", "loc" : [ -90.239357, 43.62848 ], "pop" : 3180, "state" : "WI" }
+{ "_id" : "54001", "city" : "DERONDA", "loc" : [ -92.361527, 45.325238 ], "pop" : 4929, "state" : "WI" }
+{ "_id" : "54002", "city" : "BALDWIN", "loc" : [ -92.365498, 44.9657 ], "pop" : 4214, "state" : "WI" }
+{ "_id" : "54003", "city" : "BELDENVILLE", "loc" : [ -92.437202, 44.7721 ], "pop" : 1442, "state" : "WI" }
+{ "_id" : "54004", "city" : "CLAYTON", "loc" : [ -92.13946199999999, 45.306297 ], "pop" : 2414, "state" : "WI" }
+{ "_id" : "54005", "city" : "CLEAR LAKE", "loc" : [ -92.27488, 45.236481 ], "pop" : 3254, "state" : "WI" }
+{ "_id" : "54006", "city" : "CUSHING", "loc" : [ -92.62413599999999, 45.560359 ], "pop" : 2750, "state" : "WI" }
+{ "_id" : "54007", "city" : "DEER PARK", "loc" : [ -92.358464, 45.169046 ], "pop" : 876, "state" : "WI" }
+{ "_id" : "54009", "city" : "DRESSER", "loc" : [ -92.56229999999999, 45.354585 ], "pop" : 4019, "state" : "WI" }
+{ "_id" : "54011", "city" : "ELLSWORTH", "loc" : [ -92.48903799999999, 44.730191 ], "pop" : 4293, "state" : "WI" }
+{ "_id" : "54012", "city" : "EMERALD", "loc" : [ -92.312786, 45.078578 ], "pop" : 630, "state" : "WI" }
+{ "_id" : "54013", "city" : "GLENWOOD CITY", "loc" : [ -92.181588, 45.062339 ], "pop" : 1835, "state" : "WI" }
+{ "_id" : "54014", "city" : "HAGER CITY", "loc" : [ -92.550146, 44.626969 ], "pop" : 2075, "state" : "WI" }
+{ "_id" : "54015", "city" : "HAMMOND", "loc" : [ -92.447215, 44.967004 ], "pop" : 1921, "state" : "WI" }
+{ "_id" : "54016", "city" : "HUDSON", "loc" : [ -92.727062, 44.984187 ], "pop" : 16136, "state" : "WI" }
+{ "_id" : "54017", "city" : "NEW RICHMOND", "loc" : [ -92.551333, 45.159819 ], "pop" : 14190, "state" : "WI" }
+{ "_id" : "54020", "city" : "OSCEOLA", "loc" : [ -92.697108, 45.321757 ], "pop" : 2062, "state" : "WI" }
+{ "_id" : "54021", "city" : "PRESCOTT", "loc" : [ -92.753528, 44.747648 ], "pop" : 4807, "state" : "WI" }
+{ "_id" : "54022", "city" : "RIVER FALLS", "loc" : [ -92.631275, 44.85501 ], "pop" : 16037, "state" : "WI" }
+{ "_id" : "54023", "city" : "ROBERTS", "loc" : [ -92.55977300000001, 44.987356 ], "pop" : 2063, "state" : "WI" }
+{ "_id" : "54024", "city" : "SAINT CROIX FALL", "loc" : [ -92.63837100000001, 45.413215 ], "pop" : 1640, "state" : "WI" }
+{ "_id" : "54025", "city" : "SOMERSET", "loc" : [ -92.686466, 45.133064 ], "pop" : 2937, "state" : "WI" }
+{ "_id" : "54026", "city" : "STAR PRAIRIE", "loc" : [ -92.55135300000001, 45.2013 ], "pop" : 40, "state" : "WI" }
+{ "_id" : "54027", "city" : "WILSON", "loc" : [ -92.196538, 44.94658 ], "pop" : 1415, "state" : "WI" }
+{ "_id" : "54028", "city" : "WOODVILLE", "loc" : [ -92.284803, 44.940806 ], "pop" : 1326, "state" : "WI" }
+{ "_id" : "54082", "city" : "SAINT JOSEPH", "loc" : [ -92.760803, 45.070123 ], "pop" : 987, "state" : "WI" }
+{ "_id" : "54101", "city" : "ABRAMS", "loc" : [ -88.057101, 44.78693 ], "pop" : 1712, "state" : "WI" }
+{ "_id" : "54102", "city" : "AMBERG", "loc" : [ -87.96425600000001, 45.498878 ], "pop" : 917, "state" : "WI" }
+{ "_id" : "54103", "city" : "ARMSTRONG CREEK", "loc" : [ -88.490847, 45.67261 ], "pop" : 460, "state" : "WI" }
+{ "_id" : "54104", "city" : "ATHELSTANE", "loc" : [ -88.175282, 45.422819 ], "pop" : 696, "state" : "WI" }
+{ "_id" : "54106", "city" : "CENTER VALLEY", "loc" : [ -88.444776, 44.485595 ], "pop" : 4859, "state" : "WI" }
+{ "_id" : "54107", "city" : "NAVARINO", "loc" : [ -88.439026, 44.73794 ], "pop" : 2148, "state" : "WI" }
+{ "_id" : "54110", "city" : "BRILLION", "loc" : [ -88.083337, 44.17792 ], "pop" : 4618, "state" : "WI" }
+{ "_id" : "54111", "city" : "CECIL", "loc" : [ -88.41825300000001, 44.811027 ], "pop" : 2966, "state" : "WI" }
+{ "_id" : "54112", "city" : "COLEMAN", "loc" : [ -88.058667, 45.072157 ], "pop" : 2828, "state" : "WI" }
+{ "_id" : "54113", "city" : "COMBINED LOCKS", "loc" : [ -88.313271, 44.266581 ], "pop" : 2190, "state" : "WI" }
+{ "_id" : "54114", "city" : "BEAVER", "loc" : [ -88.06126500000001, 45.254053 ], "pop" : 3395, "state" : "WI" }
+{ "_id" : "54115", "city" : "DE PERE", "loc" : [ -88.080613, 44.438779 ], "pop" : 22430, "state" : "WI" }
+{ "_id" : "54119", "city" : "DUNBAR", "loc" : [ -88.106669, 45.600944 ], "pop" : 838, "state" : "WI" }
+{ "_id" : "54120", "city" : "FENCE", "loc" : [ -88.364873, 45.759652 ], "pop" : 362, "state" : "WI" }
+{ "_id" : "54121", "city" : "FLORENCE", "loc" : [ -88.228921, 45.902724 ], "pop" : 2616, "state" : "WI" }
+{ "_id" : "54123", "city" : "FOREST JUNCTION", "loc" : [ -88.15171599999999, 44.20613 ], "pop" : 395, "state" : "WI" }
+{ "_id" : "54124", "city" : "GILLETT", "loc" : [ -88.32422099999999, 44.901753 ], "pop" : 3317, "state" : "WI" }
+{ "_id" : "54125", "city" : "GOODMAN", "loc" : [ -88.36290099999999, 45.646895 ], "pop" : 758, "state" : "WI" }
+{ "_id" : "54126", "city" : "GREENLEAF", "loc" : [ -88.027519, 44.29373 ], "pop" : 3443, "state" : "WI" }
+{ "_id" : "54128", "city" : "GRESHAM", "loc" : [ -88.78873, 44.852963 ], "pop" : 1689, "state" : "WI" }
+{ "_id" : "54129", "city" : "HILBERT", "loc" : [ -88.20696100000001, 44.127129 ], "pop" : 3938, "state" : "WI" }
+{ "_id" : "54130", "city" : "KAUKAUNA", "loc" : [ -88.271692, 44.29561 ], "pop" : 19823, "state" : "WI" }
+{ "_id" : "54135", "city" : "KESHENA", "loc" : [ -88.63568600000001, 44.914635 ], "pop" : 3588, "state" : "WI" }
+{ "_id" : "54136", "city" : "KIMBERLY", "loc" : [ -88.338374, 44.27008 ], "pop" : 5406, "state" : "WI" }
+{ "_id" : "54137", "city" : "KRAKOW", "loc" : [ -88.25933000000001, 44.763457 ], "pop" : 883, "state" : "WI" }
+{ "_id" : "54138", "city" : "LAKEWOOD", "loc" : [ -88.50318900000001, 45.316285 ], "pop" : 626, "state" : "WI" }
+{ "_id" : "54139", "city" : "STILES", "loc" : [ -88.05430800000001, 44.940494 ], "pop" : 2684, "state" : "WI" }
+{ "_id" : "54140", "city" : "LITTLE CHUTE", "loc" : [ -88.311989, 44.284248 ], "pop" : 7769, "state" : "WI" }
+{ "_id" : "54141", "city" : "LITTLE SUAMICO", "loc" : [ -88.02724499999999, 44.67751 ], "pop" : 3506, "state" : "WI" }
+{ "_id" : "54143", "city" : "MARINETTE", "loc" : [ -87.669684, 45.087403 ], "pop" : 16297, "state" : "WI" }
+{ "_id" : "54149", "city" : "MOUNTAIN", "loc" : [ -88.45828, 45.199127 ], "pop" : 1261, "state" : "WI" }
+{ "_id" : "54150", "city" : "NEOPIT", "loc" : [ -88.861116, 44.987323 ], "pop" : 14, "state" : "WI" }
+{ "_id" : "54151", "city" : "NIAGARA", "loc" : [ -88.03092700000001, 45.765343 ], "pop" : 4123, "state" : "WI" }
+{ "_id" : "54153", "city" : "OCONTO", "loc" : [ -87.891728, 44.891359 ], "pop" : 6710, "state" : "WI" }
+{ "_id" : "54154", "city" : "OCONTO FALLS", "loc" : [ -88.155528, 44.875499 ], "pop" : 4481, "state" : "WI" }
+{ "_id" : "54155", "city" : "ONEIDA", "loc" : [ -88.185851, 44.516641 ], "pop" : 3674, "state" : "WI" }
+{ "_id" : "54156", "city" : "PEMBINE", "loc" : [ -87.97036300000001, 45.607398 ], "pop" : 1443, "state" : "WI" }
+{ "_id" : "54157", "city" : "PESHTIGO", "loc" : [ -87.729795, 45.045778 ], "pop" : 4956, "state" : "WI" }
+{ "_id" : "54159", "city" : "PORTERFIELD", "loc" : [ -87.80624299999999, 45.193399 ], "pop" : 1974, "state" : "WI" }
+{ "_id" : "54161", "city" : "POUND", "loc" : [ -88.13962100000001, 45.127317 ], "pop" : 2084, "state" : "WI" }
+{ "_id" : "54162", "city" : "PULASKI", "loc" : [ -88.263447, 44.66112 ], "pop" : 6933, "state" : "WI" }
+{ "_id" : "54165", "city" : "SEYMOUR", "loc" : [ -88.317243, 44.509096 ], "pop" : 5744, "state" : "WI" }
+{ "_id" : "54166", "city" : "SHAWANO", "loc" : [ -88.603599, 44.785133 ], "pop" : 13367, "state" : "WI" }
+{ "_id" : "54170", "city" : "SHIOCTON", "loc" : [ -88.556236, 44.497202 ], "pop" : 3708, "state" : "WI" }
+{ "_id" : "54171", "city" : "SOBIESKI", "loc" : [ -88.10760500000001, 44.710495 ], "pop" : 1644, "state" : "WI" }
+{ "_id" : "54174", "city" : "SURING", "loc" : [ -88.36276700000001, 45.018551 ], "pop" : 2591, "state" : "WI" }
+{ "_id" : "54175", "city" : "TOWNSEND", "loc" : [ -88.610743, 45.314819 ], "pop" : 729, "state" : "WI" }
+{ "_id" : "54176", "city" : "UNDERHILL", "loc" : [ -88.168898, 44.731836 ], "pop" : 69, "state" : "WI" }
+{ "_id" : "54177", "city" : "WAUSAUKEE", "loc" : [ -87.90987699999999, 45.349507 ], "pop" : 2875, "state" : "WI" }
+{ "_id" : "54180", "city" : "WRIGHTSTOWN", "loc" : [ -88.121769, 44.338377 ], "pop" : 2359, "state" : "WI" }
+{ "_id" : "54201", "city" : "ALGOMA", "loc" : [ -87.457792, 44.610051 ], "pop" : 5387, "state" : "WI" }
+{ "_id" : "54202", "city" : "BAILEYS HARBOR", "loc" : [ -87.167626, 45.056549 ], "pop" : 1167, "state" : "WI" }
+{ "_id" : "54204", "city" : "BRUSSELS", "loc" : [ -87.62251999999999, 44.747558 ], "pop" : 1785, "state" : "WI" }
+{ "_id" : "54205", "city" : "CASCO", "loc" : [ -87.623122, 44.58328 ], "pop" : 2066, "state" : "WI" }
+{ "_id" : "54206", "city" : "CATO", "loc" : [ -87.864688, 44.148521 ], "pop" : 1097, "state" : "WI" }
+{ "_id" : "54208", "city" : "DENMARK", "loc" : [ -87.82703600000001, 44.359392 ], "pop" : 3968, "state" : "WI" }
+{ "_id" : "54209", "city" : "EGG HARBOR", "loc" : [ -87.28052099999999, 45.010039 ], "pop" : 738, "state" : "WI" }
+{ "_id" : "54210", "city" : "ELLISON BAY", "loc" : [ -87.051209, 45.257206 ], "pop" : 804, "state" : "WI" }
+{ "_id" : "54212", "city" : "FISH CREEK", "loc" : [ -87.20643200000001, 45.11554 ], "pop" : 1200, "state" : "WI" }
+{ "_id" : "54213", "city" : "FORESTVILLE", "loc" : [ -87.49283200000001, 44.696863 ], "pop" : 1680, "state" : "WI" }
+{ "_id" : "54214", "city" : "FRANCIS CREEK", "loc" : [ -87.720007, 44.199964 ], "pop" : 562, "state" : "WI" }
+{ "_id" : "54215", "city" : "KELLNERSVILLE", "loc" : [ -87.803596, 44.22493 ], "pop" : 350, "state" : "WI" }
+{ "_id" : "54216", "city" : "KEWAUNEE", "loc" : [ -87.559442, 44.440143 ], "pop" : 6262, "state" : "WI" }
+{ "_id" : "54217", "city" : "LUXEMBURG", "loc" : [ -87.71560599999999, 44.550612 ], "pop" : 5188, "state" : "WI" }
+{ "_id" : "54220", "city" : "MANITOWOC", "loc" : [ -87.682303, 44.097122 ], "pop" : 39178, "state" : "WI" }
+{ "_id" : "54227", "city" : "MARIBEL", "loc" : [ -87.805482, 44.285151 ], "pop" : 2251, "state" : "WI" }
+{ "_id" : "54228", "city" : "MISHICOT", "loc" : [ -87.64470300000001, 44.260942 ], "pop" : 3245, "state" : "WI" }
+{ "_id" : "54229", "city" : "NEW FRANKEN", "loc" : [ -87.823482, 44.559193 ], "pop" : 2640, "state" : "WI" }
+{ "_id" : "54230", "city" : "REEDSVILLE", "loc" : [ -87.96602799999999, 44.157566 ], "pop" : 3073, "state" : "WI" }
+{ "_id" : "54232", "city" : "SAINT NAZIANZ", "loc" : [ -87.922906, 44.006425 ], "pop" : 680, "state" : "WI" }
+{ "_id" : "54234", "city" : "SISTER BAY", "loc" : [ -87.113865, 45.187544 ], "pop" : 1376, "state" : "WI" }
+{ "_id" : "54235", "city" : "STURGEON BAY", "loc" : [ -87.375311, 44.84384 ], "pop" : 16149, "state" : "WI" }
+{ "_id" : "54241", "city" : "TWO RIVERS", "loc" : [ -87.585504, 44.166008 ], "pop" : 16768, "state" : "WI" }
+{ "_id" : "54245", "city" : "VALDERS", "loc" : [ -87.88118299999999, 44.041977 ], "pop" : 2056, "state" : "WI" }
+{ "_id" : "54246", "city" : "WASHINGTON ISLAN", "loc" : [ -86.913664, 45.374042 ], "pop" : 623, "state" : "WI" }
+{ "_id" : "54247", "city" : "WHITELAW", "loc" : [ -87.82669799999999, 44.157269 ], "pop" : 1402, "state" : "WI" }
+{ "_id" : "54301", "city" : "ALLOUEZ", "loc" : [ -88.016868, 44.485313 ], "pop" : 25108, "state" : "WI" }
+{ "_id" : "54302", "city" : "GREEN BAY", "loc" : [ -87.977136, 44.502508 ], "pop" : 27273, "state" : "WI" }
+{ "_id" : "54303", "city" : "HOWARD", "loc" : [ -88.04526199999999, 44.530146 ], "pop" : 27046, "state" : "WI" }
+{ "_id" : "54304", "city" : "ASHWAUBENON", "loc" : [ -88.066799, 44.505525 ], "pop" : 31339, "state" : "WI" }
+{ "_id" : "54311", "city" : "GREEN BAY", "loc" : [ -87.92668500000001, 44.491405 ], "pop" : 19373, "state" : "WI" }
+{ "_id" : "54313", "city" : "GREEN BAY", "loc" : [ -88.102054, 44.546289 ], "pop" : 23360, "state" : "WI" }
+{ "_id" : "54401", "city" : "WAUSAU", "loc" : [ -89.633955, 44.963433 ], "pop" : 51083, "state" : "WI" }
+{ "_id" : "54405", "city" : "ABBOTSFORD", "loc" : [ -90.29943799999999, 44.964057 ], "pop" : 2480, "state" : "WI" }
+{ "_id" : "54406", "city" : "AMHERST", "loc" : [ -89.303482, 44.423052 ], "pop" : 2885, "state" : "WI" }
+{ "_id" : "54407", "city" : "AMHERST JUNCTION", "loc" : [ -89.303754, 44.506458 ], "pop" : 1448, "state" : "WI" }
+{ "_id" : "54408", "city" : "ANIWA", "loc" : [ -89.268254, 45.01039 ], "pop" : 1510, "state" : "WI" }
+{ "_id" : "54409", "city" : "ANTIGO", "loc" : [ -89.14187099999999, 45.131362 ], "pop" : 13087, "state" : "WI" }
+{ "_id" : "54410", "city" : "ARPIN", "loc" : [ -90.037049, 44.54194 ], "pop" : 2301, "state" : "WI" }
+{ "_id" : "54411", "city" : "HAMBURG", "loc" : [ -90.062612, 45.032037 ], "pop" : 4263, "state" : "WI" }
+{ "_id" : "54412", "city" : "AUBURNDALE", "loc" : [ -90.013577, 44.637836 ], "pop" : 1667, "state" : "WI" }
+{ "_id" : "54413", "city" : "BABCOCK", "loc" : [ -90.098574, 44.303064 ], "pop" : 409, "state" : "WI" }
+{ "_id" : "54414", "city" : "BIRNAMWOOD", "loc" : [ -89.212433, 44.926896 ], "pop" : 2464, "state" : "WI" }
+{ "_id" : "54416", "city" : "BOWLER", "loc" : [ -88.976071, 44.933667 ], "pop" : 2777, "state" : "WI" }
+{ "_id" : "54418", "city" : "BRYANT", "loc" : [ -88.99832499999999, 45.202962 ], "pop" : 1029, "state" : "WI" }
+{ "_id" : "54419", "city" : "CHELSEA", "loc" : [ -90.303685, 45.288166 ], "pop" : 122, "state" : "WI" }
+{ "_id" : "54420", "city" : "CHILI", "loc" : [ -90.35995200000001, 44.630135 ], "pop" : 728, "state" : "WI" }
+{ "_id" : "54421", "city" : "COLBY", "loc" : [ -90.314432, 44.911651 ], "pop" : 3621, "state" : "WI" }
+{ "_id" : "54422", "city" : "CURTISS", "loc" : [ -90.45922299999999, 44.960186 ], "pop" : 1111, "state" : "WI" }
+{ "_id" : "54423", "city" : "CUSTER", "loc" : [ -89.41527499999999, 44.56622 ], "pop" : 2010, "state" : "WI" }
+{ "_id" : "54424", "city" : "DEERBROOK", "loc" : [ -89.187257, 45.236791 ], "pop" : 902, "state" : "WI" }
+{ "_id" : "54425", "city" : "DORCHESTER", "loc" : [ -90.35964800000001, 45.004192 ], "pop" : 1860, "state" : "WI" }
+{ "_id" : "54426", "city" : "FENWOOD", "loc" : [ -89.998029, 44.903831 ], "pop" : 3810, "state" : "WI" }
+{ "_id" : "54427", "city" : "ELAND", "loc" : [ -89.246117, 44.830888 ], "pop" : 1278, "state" : "WI" }
+{ "_id" : "54428", "city" : "ELCHO", "loc" : [ -89.15157000000001, 45.440906 ], "pop" : 988, "state" : "WI" }
+{ "_id" : "54430", "city" : "ELTON", "loc" : [ -88.883743, 45.156216 ], "pop" : 135, "state" : "WI" }
+{ "_id" : "54433", "city" : "GILMAN", "loc" : [ -90.825672, 45.18906 ], "pop" : 1780, "state" : "WI" }
+{ "_id" : "54435", "city" : "GLEASON", "loc" : [ -89.475264, 45.338428 ], "pop" : 2347, "state" : "WI" }
+{ "_id" : "54436", "city" : "GRANTON", "loc" : [ -90.44838300000001, 44.560558 ], "pop" : 2072, "state" : "WI" }
+{ "_id" : "54437", "city" : "GREENWOOD", "loc" : [ -90.622913, 44.740373 ], "pop" : 3029, "state" : "WI" }
+{ "_id" : "54440", "city" : "HATLEY", "loc" : [ -89.377728, 44.825638 ], "pop" : 2129, "state" : "WI" }
+{ "_id" : "54441", "city" : "HEWITT", "loc" : [ -90.103054, 44.643651 ], "pop" : 595, "state" : "WI" }
+{ "_id" : "54442", "city" : "IRMA", "loc" : [ -89.66113799999999, 45.348483 ], "pop" : 1006, "state" : "WI" }
+{ "_id" : "54443", "city" : "JUNCTION CITY", "loc" : [ -89.743758, 44.59634 ], "pop" : 2396, "state" : "WI" }
+{ "_id" : "54445", "city" : "LILY", "loc" : [ -88.83845100000001, 45.318723 ], "pop" : 196, "state" : "WI" }
+{ "_id" : "54446", "city" : "LOYAL", "loc" : [ -90.492238, 44.727243 ], "pop" : 3809, "state" : "WI" }
+{ "_id" : "54447", "city" : "LUBLIN", "loc" : [ -90.733678, 45.073933 ], "pop" : 564, "state" : "WI" }
+{ "_id" : "54448", "city" : "MARATHON", "loc" : [ -89.829948, 44.965664 ], "pop" : 5202, "state" : "WI" }
+{ "_id" : "54449", "city" : "MARSHFIELD", "loc" : [ -90.17845, 44.661453 ], "pop" : 25791, "state" : "WI" }
+{ "_id" : "54451", "city" : "MEDFORD", "loc" : [ -90.350306, 45.151185 ], "pop" : 10388, "state" : "WI" }
+{ "_id" : "54452", "city" : "MERRILL", "loc" : [ -89.690696, 45.180924 ], "pop" : 17891, "state" : "WI" }
+{ "_id" : "54454", "city" : "MILLADORE", "loc" : [ -89.88753199999999, 44.604416 ], "pop" : 1347, "state" : "WI" }
+{ "_id" : "54455", "city" : "MOSINEE", "loc" : [ -89.68449099999999, 44.799736 ], "pop" : 13664, "state" : "WI" }
+{ "_id" : "54456", "city" : "NEILLSVILLE", "loc" : [ -90.611197, 44.549429 ], "pop" : 4904, "state" : "WI" }
+{ "_id" : "54457", "city" : "NEKOOSA", "loc" : [ -89.881394, 44.281979 ], "pop" : 7312, "state" : "WI" }
+{ "_id" : "54459", "city" : "OGEMA", "loc" : [ -90.256513, 45.439187 ], "pop" : 1459, "state" : "WI" }
+{ "_id" : "54460", "city" : "OWEN", "loc" : [ -90.54689999999999, 44.957817 ], "pop" : 1759, "state" : "WI" }
+{ "_id" : "54462", "city" : "PEARSON", "loc" : [ -89.075824, 45.388119 ], "pop" : 679, "state" : "WI" }
+{ "_id" : "54463", "city" : "PELICAN LAKE", "loc" : [ -89.181707, 45.504886 ], "pop" : 635, "state" : "WI" }
+{ "_id" : "54465", "city" : "PICKEREL", "loc" : [ -88.91365, 45.356658 ], "pop" : 269, "state" : "WI" }
+{ "_id" : "54466", "city" : "PITTSVILLE", "loc" : [ -90.18917399999999, 44.43747 ], "pop" : 2754, "state" : "WI" }
+{ "_id" : "54467", "city" : "PLOVER", "loc" : [ -89.542805, 44.450673 ], "pop" : 6142, "state" : "WI" }
+{ "_id" : "54469", "city" : "PORT EDWARDS", "loc" : [ -89.865246, 44.349705 ], "pop" : 1828, "state" : "WI" }
+{ "_id" : "54470", "city" : "RIB LAKE", "loc" : [ -90.176322, 45.298376 ], "pop" : 2002, "state" : "WI" }
+{ "_id" : "54471", "city" : "RINGLE", "loc" : [ -89.432845, 44.92383 ], "pop" : 1370, "state" : "WI" }
+{ "_id" : "54473", "city" : "ROSHOLT", "loc" : [ -89.33563700000001, 44.662224 ], "pop" : 3147, "state" : "WI" }
+{ "_id" : "54474", "city" : "ROTHSCHILD", "loc" : [ -89.61926200000001, 44.88429 ], "pop" : 3867, "state" : "WI" }
+{ "_id" : "54475", "city" : "RUDOLPH", "loc" : [ -89.800252, 44.474061 ], "pop" : 1648, "state" : "WI" }
+{ "_id" : "54476", "city" : "SCHOFIELD", "loc" : [ -89.581789, 44.906407 ], "pop" : 12583, "state" : "WI" }
+{ "_id" : "54479", "city" : "SPENCER", "loc" : [ -90.31140600000001, 44.739148 ], "pop" : 2997, "state" : "WI" }
+{ "_id" : "54480", "city" : "STETSONVILLE", "loc" : [ -90.282931, 45.07923 ], "pop" : 1241, "state" : "WI" }
+{ "_id" : "54481", "city" : "STEVENS POINT", "loc" : [ -89.558764, 44.521221 ], "pop" : 38950, "state" : "WI" }
+{ "_id" : "54484", "city" : "STRATFORD", "loc" : [ -90.058317, 44.789878 ], "pop" : 4201, "state" : "WI" }
+{ "_id" : "54485", "city" : "SUMMIT LAKE", "loc" : [ -89.18074300000001, 45.320414 ], "pop" : 616, "state" : "WI" }
+{ "_id" : "54486", "city" : "TIGERTON", "loc" : [ -89.056893, 44.729938 ], "pop" : 3310, "state" : "WI" }
+{ "_id" : "54487", "city" : "TOMAHAWK", "loc" : [ -89.72726900000001, 45.496308 ], "pop" : 8130, "state" : "WI" }
+{ "_id" : "54488", "city" : "UNITY", "loc" : [ -90.322074, 44.822676 ], "pop" : 1797, "state" : "WI" }
+{ "_id" : "54489", "city" : "VESPER", "loc" : [ -89.982553, 44.467656 ], "pop" : 1616, "state" : "WI" }
+{ "_id" : "54490", "city" : "WESTBORO", "loc" : [ -90.307194, 45.344539 ], "pop" : 766, "state" : "WI" }
+{ "_id" : "54491", "city" : "WHITE LAKE", "loc" : [ -88.755489, 45.171465 ], "pop" : 1324, "state" : "WI" }
+{ "_id" : "54493", "city" : "WILLARD", "loc" : [ -90.749897, 44.727378 ], "pop" : 682, "state" : "WI" }
+{ "_id" : "54494", "city" : "WISCONSIN RAPIDS", "loc" : [ -89.806229, 44.375803 ], "pop" : 33296, "state" : "WI" }
+{ "_id" : "54498", "city" : "WITHEE", "loc" : [ -90.604862, 44.975726 ], "pop" : 2286, "state" : "WI" }
+{ "_id" : "54499", "city" : "WITTENBERG", "loc" : [ -89.166479, 44.823247 ], "pop" : 1850, "state" : "WI" }
+{ "_id" : "54501", "city" : "MONICO", "loc" : [ -89.409285, 45.646718 ], "pop" : 19039, "state" : "WI" }
+{ "_id" : "54511", "city" : "CAVOUR", "loc" : [ -88.888566, 45.658309 ], "pop" : 1533, "state" : "WI" }
+{ "_id" : "54512", "city" : "BOULDER JUNCTION", "loc" : [ -89.632454, 46.111183 ], "pop" : 563, "state" : "WI" }
+{ "_id" : "54513", "city" : "BRANTWOOD", "loc" : [ -90.11595199999999, 45.551413 ], "pop" : 540, "state" : "WI" }
+{ "_id" : "54514", "city" : "BUTTERNUT", "loc" : [ -90.482114, 46.018358 ], "pop" : 2054, "state" : "WI" }
+{ "_id" : "54515", "city" : "CATAWBA", "loc" : [ -90.51456399999999, 45.508123 ], "pop" : 616, "state" : "WI" }
+{ "_id" : "54517", "city" : "CLAM LAKE", "loc" : [ -90.884107, 46.245675 ], "pop" : 2, "state" : "WI" }
+{ "_id" : "54519", "city" : "CONOVER", "loc" : [ -89.238919, 46.043968 ], "pop" : 1039, "state" : "WI" }
+{ "_id" : "54520", "city" : "CRANDON", "loc" : [ -88.911619, 45.541553 ], "pop" : 3419, "state" : "WI" }
+{ "_id" : "54521", "city" : "EAGLE RIVER", "loc" : [ -89.253058, 45.916084 ], "pop" : 6726, "state" : "WI" }
+{ "_id" : "54524", "city" : "FIFIELD", "loc" : [ -90.4246, 45.862148 ], "pop" : 496, "state" : "WI" }
+{ "_id" : "54526", "city" : "INGRAM", "loc" : [ -90.855183, 45.488807 ], "pop" : 949, "state" : "WI" }
+{ "_id" : "54527", "city" : "GLIDDEN", "loc" : [ -90.58885600000001, 46.133668 ], "pop" : 1061, "state" : "WI" }
+{ "_id" : "54529", "city" : "HARSHAW", "loc" : [ -89.650346, 45.676244 ], "pop" : 854, "state" : "WI" }
+{ "_id" : "54530", "city" : "HAWKINS", "loc" : [ -90.71137299999999, 45.524129 ], "pop" : 747, "state" : "WI" }
+{ "_id" : "54531", "city" : "HAZELHURST", "loc" : [ -89.74783600000001, 45.77446 ], "pop" : 1057, "state" : "WI" }
+{ "_id" : "54534", "city" : "HURLEY", "loc" : [ -90.19750000000001, 46.44482 ], "pop" : 2658, "state" : "WI" }
+{ "_id" : "54536", "city" : "IRON BELT", "loc" : [ -90.324528, 46.395545 ], "pop" : 265, "state" : "WI" }
+{ "_id" : "54537", "city" : "KENNAN", "loc" : [ -90.590987, 45.53497 ], "pop" : 628, "state" : "WI" }
+{ "_id" : "54538", "city" : "LAC DU FLAMBEAU", "loc" : [ -89.890078, 45.97175 ], "pop" : 2085, "state" : "WI" }
+{ "_id" : "54539", "city" : "LAKE TOMAHAWK", "loc" : [ -89.58560900000001, 45.803455 ], "pop" : 1223, "state" : "WI" }
+{ "_id" : "54540", "city" : "LAND O LAKES", "loc" : [ -89.321787, 46.156305 ], "pop" : 742, "state" : "WI" }
+{ "_id" : "54541", "city" : "LAONA", "loc" : [ -88.671525, 45.553416 ], "pop" : 1823, "state" : "WI" }
+{ "_id" : "54542", "city" : "ALVIN", "loc" : [ -88.695308, 45.921841 ], "pop" : 550, "state" : "WI" }
+{ "_id" : "54545", "city" : "MANITOWISH WATER", "loc" : [ -89.83076699999999, 46.123909 ], "pop" : 901, "state" : "WI" }
+{ "_id" : "54546", "city" : "MELLEN", "loc" : [ -90.655233, 46.300659 ], "pop" : 1752, "state" : "WI" }
+{ "_id" : "54547", "city" : "MERCER", "loc" : [ -90.067914, 46.169594 ], "pop" : 1321, "state" : "WI" }
+{ "_id" : "54548", "city" : "MINOCQUA", "loc" : [ -89.757954, 45.871909 ], "pop" : 3793, "state" : "WI" }
+{ "_id" : "54550", "city" : "PENCE", "loc" : [ -90.244195, 46.425736 ], "pop" : 1019, "state" : "WI" }
+{ "_id" : "54552", "city" : "PARK FALLS", "loc" : [ -90.424648, 45.936345 ], "pop" : 5316, "state" : "WI" }
+{ "_id" : "54554", "city" : "PHELPS", "loc" : [ -89.081547, 46.064481 ], "pop" : 1183, "state" : "WI" }
+{ "_id" : "54555", "city" : "PHILLIPS", "loc" : [ -90.40413100000001, 45.697463 ], "pop" : 5155, "state" : "WI" }
+{ "_id" : "54556", "city" : "PRENTICE", "loc" : [ -90.294217, 45.548201 ], "pop" : 1177, "state" : "WI" }
+{ "_id" : "54557", "city" : "WINCHESTER", "loc" : [ -89.772795, 46.221735 ], "pop" : 735, "state" : "WI" }
+{ "_id" : "54558", "city" : "SAINT GERMAIN", "loc" : [ -89.48655599999999, 45.918315 ], "pop" : 1201, "state" : "WI" }
+{ "_id" : "54559", "city" : "SAXON", "loc" : [ -90.438273, 46.495855 ], "pop" : 478, "state" : "WI" }
+{ "_id" : "54560", "city" : "SAYNER", "loc" : [ -89.519437, 45.986664 ], "pop" : 559, "state" : "WI" }
+{ "_id" : "54562", "city" : "THREE LAKES", "loc" : [ -89.13279199999999, 45.804633 ], "pop" : 1755, "state" : "WI" }
+{ "_id" : "54563", "city" : "TONY", "loc" : [ -90.98693799999999, 45.474082 ], "pop" : 814, "state" : "WI" }
+{ "_id" : "54564", "city" : "TRIPOLI", "loc" : [ -89.985218, 45.581387 ], "pop" : 374, "state" : "WI" }
+{ "_id" : "54565", "city" : "UPSON", "loc" : [ -90.405135, 46.376124 ], "pop" : 69, "state" : "WI" }
+{ "_id" : "54566", "city" : "WABENO", "loc" : [ -88.66245600000001, 45.433172 ], "pop" : 1308, "state" : "WI" }
+{ "_id" : "54568", "city" : "WOODRUFF", "loc" : [ -89.69544999999999, 45.918583 ], "pop" : 4088, "state" : "WI" }
+{ "_id" : "54601", "city" : "LA CROSSE", "loc" : [ -91.217494, 43.798938 ], "pop" : 48348, "state" : "WI" }
+{ "_id" : "54603", "city" : "LA CROSSE", "loc" : [ -91.248439, 43.848675 ], "pop" : 15292, "state" : "WI" }
+{ "_id" : "54610", "city" : "ALMA", "loc" : [ -91.807931, 44.429437 ], "pop" : 3824, "state" : "WI" }
+{ "_id" : "54611", "city" : "ALMA CENTER", "loc" : [ -90.935602, 44.445218 ], "pop" : 989, "state" : "WI" }
+{ "_id" : "54612", "city" : "ARCADIA", "loc" : [ -91.480453, 44.253937 ], "pop" : 4707, "state" : "WI" }
+{ "_id" : "54613", "city" : "ARKDALE", "loc" : [ -89.896215, 44.052886 ], "pop" : 1582, "state" : "WI" }
+{ "_id" : "54614", "city" : "BANGOR", "loc" : [ -90.98088799999999, 43.868697 ], "pop" : 1952, "state" : "WI" }
+{ "_id" : "54615", "city" : "BLACK RIVER FALL", "loc" : [ -90.84795200000001, 44.292101 ], "pop" : 8248, "state" : "WI" }
+{ "_id" : "54616", "city" : "BLAIR", "loc" : [ -91.223501, 44.296843 ], "pop" : 2347, "state" : "WI" }
+{ "_id" : "54617", "city" : "BLOOM CITY", "loc" : [ -90.66645800000001, 43.509034 ], "pop" : 437, "state" : "WI" }
+{ "_id" : "54618", "city" : "CUTLER", "loc" : [ -90.268861, 43.936705 ], "pop" : 1613, "state" : "WI" }
+{ "_id" : "54619", "city" : "CASHTON", "loc" : [ -90.761197, 43.745649 ], "pop" : 1547, "state" : "WI" }
+{ "_id" : "54621", "city" : "CHASEBURG", "loc" : [ -91.07993399999999, 43.679372 ], "pop" : 550, "state" : "WI" }
+{ "_id" : "54622", "city" : "WAUMANDEE", "loc" : [ -91.858677, 44.251591 ], "pop" : 2271, "state" : "WI" }
+{ "_id" : "54623", "city" : "COON VALLEY", "loc" : [ -91.014338, 43.721783 ], "pop" : 1402, "state" : "WI" }
+{ "_id" : "54624", "city" : "VICTORY", "loc" : [ -91.193015, 43.494707 ], "pop" : 1422, "state" : "WI" }
+{ "_id" : "54625", "city" : "DODGE", "loc" : [ -91.52434100000001, 44.12886 ], "pop" : 397, "state" : "WI" }
+{ "_id" : "54626", "city" : "EASTMAN", "loc" : [ -91.01927000000001, 43.19592 ], "pop" : 1064, "state" : "WI" }
+{ "_id" : "54627", "city" : "ETTRICK", "loc" : [ -91.26354600000001, 44.172428 ], "pop" : 1644, "state" : "WI" }
+{ "_id" : "54628", "city" : "FERRYVILLE", "loc" : [ -91.044578, 43.395857 ], "pop" : 1411, "state" : "WI" }
+{ "_id" : "54629", "city" : "FOUNTAIN CITY", "loc" : [ -91.67786099999999, 44.136436 ], "pop" : 2481, "state" : "WI" }
+{ "_id" : "54630", "city" : "GALESVILLE", "loc" : [ -91.358789, 44.088848 ], "pop" : 3111, "state" : "WI" }
+{ "_id" : "54631", "city" : "GAYS MILLS", "loc" : [ -90.867636, 43.293639 ], "pop" : 2577, "state" : "WI" }
+{ "_id" : "54632", "city" : "GENOA", "loc" : [ -91.13499899999999, 43.605134 ], "pop" : 1432, "state" : "WI" }
+{ "_id" : "54634", "city" : "YUBA", "loc" : [ -90.37059499999999, 43.635009 ], "pop" : 2309, "state" : "WI" }
+{ "_id" : "54635", "city" : "NORTHFIELD", "loc" : [ -91.039086, 44.397778 ], "pop" : 1513, "state" : "WI" }
+{ "_id" : "54636", "city" : "HOLMEN", "loc" : [ -91.2497, 43.976125 ], "pop" : 7098, "state" : "WI" }
+{ "_id" : "54638", "city" : "KENDALL", "loc" : [ -90.410691, 43.81614 ], "pop" : 1848, "state" : "WI" }
+{ "_id" : "54639", "city" : "WEST LIMA", "loc" : [ -90.648257, 43.616955 ], "pop" : 3280, "state" : "WI" }
+{ "_id" : "54641", "city" : "MATHER", "loc" : [ -90.295264, 44.147706 ], "pop" : 57, "state" : "WI" }
+{ "_id" : "54642", "city" : "MELROSE", "loc" : [ -91.04446299999999, 44.138156 ], "pop" : 1806, "state" : "WI" }
+{ "_id" : "54644", "city" : "MINDORO", "loc" : [ -91.064181, 44.02873 ], "pop" : 1157, "state" : "WI" }
+{ "_id" : "54646", "city" : "NECEDAH", "loc" : [ -90.05997600000001, 44.034481 ], "pop" : 2741, "state" : "WI" }
+{ "_id" : "54648", "city" : "NORWALK", "loc" : [ -90.680134, 43.812823 ], "pop" : 2360, "state" : "WI" }
+{ "_id" : "54650", "city" : "ONALASKA", "loc" : [ -91.231419, 43.897392 ], "pop" : 16435, "state" : "WI" }
+{ "_id" : "54651", "city" : "ONTARIO", "loc" : [ -90.62053400000001, 43.717197 ], "pop" : 1032, "state" : "WI" }
+{ "_id" : "54652", "city" : "READSTOWN", "loc" : [ -90.75787200000001, 43.450791 ], "pop" : 736, "state" : "WI" }
+{ "_id" : "54653", "city" : "ROCKLAND", "loc" : [ -90.948846, 43.938159 ], "pop" : 1486, "state" : "WI" }
+{ "_id" : "54655", "city" : "SOLDIERS GROVE", "loc" : [ -90.766293, 43.391857 ], "pop" : 1621, "state" : "WI" }
+{ "_id" : "54656", "city" : "SPARTA", "loc" : [ -90.814566, 43.954045 ], "pop" : 14151, "state" : "WI" }
+{ "_id" : "54657", "city" : "STEUBEN", "loc" : [ -90.860878, 43.195464 ], "pop" : 63, "state" : "WI" }
+{ "_id" : "54658", "city" : "STODDARD", "loc" : [ -91.19188, 43.691227 ], "pop" : 2116, "state" : "WI" }
+{ "_id" : "54659", "city" : "TAYLOR", "loc" : [ -91.112752, 44.289855 ], "pop" : 1205, "state" : "WI" }
+{ "_id" : "54660", "city" : "WYEVILLE", "loc" : [ -90.491704, 43.994833 ], "pop" : 14294, "state" : "WI" }
+{ "_id" : "54661", "city" : "TREMPEALEAU", "loc" : [ -91.4282, 44.021843 ], "pop" : 2370, "state" : "WI" }
+{ "_id" : "54664", "city" : "VIOLA", "loc" : [ -90.655416, 43.504758 ], "pop" : 718, "state" : "WI" }
+{ "_id" : "54665", "city" : "VIROQUA", "loc" : [ -90.89386500000001, 43.54419 ], "pop" : 7071, "state" : "WI" }
+{ "_id" : "54666", "city" : "WARRENS", "loc" : [ -90.496692, 44.15697 ], "pop" : 1089, "state" : "WI" }
+{ "_id" : "54667", "city" : "WESTBY", "loc" : [ -90.87403, 43.663123 ], "pop" : 4290, "state" : "WI" }
+{ "_id" : "54669", "city" : "WEST SALEM", "loc" : [ -91.089311, 43.906253 ], "pop" : 5244, "state" : "WI" }
+{ "_id" : "54670", "city" : "WILTON", "loc" : [ -90.51618499999999, 43.832209 ], "pop" : 1188, "state" : "WI" }
+{ "_id" : "54701", "city" : "EAU CLAIRE", "loc" : [ -91.487686, 44.783972 ], "pop" : 31593, "state" : "WI" }
+{ "_id" : "54703", "city" : "EAU CLAIRE", "loc" : [ -91.499701, 44.827122 ], "pop" : 38400, "state" : "WI" }
+{ "_id" : "54720", "city" : "ALTOONA", "loc" : [ -91.43825, 44.802142 ], "pop" : 6065, "state" : "WI" }
+{ "_id" : "54721", "city" : "ARKANSAW", "loc" : [ -92.056646, 44.626659 ], "pop" : 1099, "state" : "WI" }
+{ "_id" : "54722", "city" : "AUGUSTA", "loc" : [ -91.123154, 44.694737 ], "pop" : 3402, "state" : "WI" }
+{ "_id" : "54723", "city" : "BAY CITY", "loc" : [ -92.446889, 44.6166 ], "pop" : 1540, "state" : "WI" }
+{ "_id" : "54724", "city" : "BLOOMER", "loc" : [ -91.489974, 45.102477 ], "pop" : 6410, "state" : "WI" }
+{ "_id" : "54725", "city" : "BOYCEVILLE", "loc" : [ -92.02480300000001, 45.064238 ], "pop" : 2520, "state" : "WI" }
+{ "_id" : "54726", "city" : "BOYD", "loc" : [ -91.029355, 44.943737 ], "pop" : 2549, "state" : "WI" }
+{ "_id" : "54727", "city" : "CADOTT", "loc" : [ -91.169884, 44.963014 ], "pop" : 4397, "state" : "WI" }
+{ "_id" : "54728", "city" : "CHETEK", "loc" : [ -91.65415400000001, 45.317046 ], "pop" : 5453, "state" : "WI" }
+{ "_id" : "54729", "city" : "CHIPPEWA FALLS", "loc" : [ -91.384376, 44.932202 ], "pop" : 25627, "state" : "WI" }
+{ "_id" : "54730", "city" : "COLFAX", "loc" : [ -91.735737, 44.999326 ], "pop" : 4073, "state" : "WI" }
+{ "_id" : "54731", "city" : "CONRATH", "loc" : [ -91.06213200000001, 45.353281 ], "pop" : 758, "state" : "WI" }
+{ "_id" : "54732", "city" : "CORNELL", "loc" : [ -91.17325200000001, 45.16191 ], "pop" : 2799, "state" : "WI" }
+{ "_id" : "54733", "city" : "DALLAS", "loc" : [ -91.836844, 45.254883 ], "pop" : 973, "state" : "WI" }
+{ "_id" : "54734", "city" : "DOWNING", "loc" : [ -92.113384, 45.103032 ], "pop" : 1029, "state" : "WI" }
+{ "_id" : "54736", "city" : "DURAND", "loc" : [ -91.92947599999999, 44.630042 ], "pop" : 3746, "state" : "WI" }
+{ "_id" : "54737", "city" : "EAU GALLE", "loc" : [ -92.04081600000001, 44.721433 ], "pop" : 921, "state" : "WI" }
+{ "_id" : "54738", "city" : "ELEVA", "loc" : [ -91.48036999999999, 44.598493 ], "pop" : 2291, "state" : "WI" }
+{ "_id" : "54739", "city" : "ELK MOUND", "loc" : [ -91.675229, 44.866973 ], "pop" : 3539, "state" : "WI" }
+{ "_id" : "54740", "city" : "ELMWOOD", "loc" : [ -92.202195, 44.756088 ], "pop" : 1759, "state" : "WI" }
+{ "_id" : "54741", "city" : "FAIRCHILD", "loc" : [ -90.990568, 44.596253 ], "pop" : 1319, "state" : "WI" }
+{ "_id" : "54742", "city" : "FALL CREEK", "loc" : [ -91.285631, 44.768385 ], "pop" : 3814, "state" : "WI" }
+{ "_id" : "54744", "city" : "HILLSDALE", "loc" : [ -91.85985700000001, 45.32136 ], "pop" : 560, "state" : "WI" }
+{ "_id" : "54745", "city" : "HOLCOMBE", "loc" : [ -91.132955, 45.251263 ], "pop" : 1752, "state" : "WI" }
+{ "_id" : "54746", "city" : "HUMBIRD", "loc" : [ -90.888257, 44.536676 ], "pop" : 633, "state" : "WI" }
+{ "_id" : "54747", "city" : "INDEPENDENCE", "loc" : [ -91.45351100000001, 44.395926 ], "pop" : 2826, "state" : "WI" }
+{ "_id" : "54748", "city" : "JIM FALLS", "loc" : [ -91.264909, 45.064439 ], "pop" : 974, "state" : "WI" }
+{ "_id" : "54749", "city" : "KNAPP", "loc" : [ -92.07520100000001, 44.954495 ], "pop" : 935, "state" : "WI" }
+{ "_id" : "54750", "city" : "MAIDEN ROCK", "loc" : [ -92.278212, 44.608599 ], "pop" : 1503, "state" : "WI" }
+{ "_id" : "54751", "city" : "MENOMONIE", "loc" : [ -91.92650999999999, 44.87182 ], "pop" : 21211, "state" : "WI" }
+{ "_id" : "54754", "city" : "MERRILLAN", "loc" : [ -90.810496, 44.436938 ], "pop" : 1317, "state" : "WI" }
+{ "_id" : "54755", "city" : "MODENA", "loc" : [ -91.66957600000001, 44.609853 ], "pop" : 4907, "state" : "WI" }
+{ "_id" : "54756", "city" : "NELSON", "loc" : [ -92.000742, 44.42947 ], "pop" : 652, "state" : "WI" }
+{ "_id" : "54757", "city" : "NEW AUBURN", "loc" : [ -91.519747, 45.23562 ], "pop" : 2101, "state" : "WI" }
+{ "_id" : "54758", "city" : "OSSEO", "loc" : [ -91.219148, 44.559923 ], "pop" : 4347, "state" : "WI" }
+{ "_id" : "54759", "city" : "PEPIN", "loc" : [ -92.139353, 44.458687 ], "pop" : 1504, "state" : "WI" }
+{ "_id" : "54761", "city" : "PLUM CITY", "loc" : [ -92.183725, 44.635979 ], "pop" : 1050, "state" : "WI" }
+{ "_id" : "54762", "city" : "PRAIRIE FARM", "loc" : [ -91.974205, 45.246183 ], "pop" : 1061, "state" : "WI" }
+{ "_id" : "54763", "city" : "RIDGELAND", "loc" : [ -91.879024, 45.186773 ], "pop" : 863, "state" : "WI" }
+{ "_id" : "54765", "city" : "SAND CREEK", "loc" : [ -91.701446, 45.170513 ], "pop" : 501, "state" : "WI" }
+{ "_id" : "54766", "city" : "SHELDON", "loc" : [ -90.914148, 45.318171 ], "pop" : 1711, "state" : "WI" }
+{ "_id" : "54767", "city" : "SPRING VALLEY", "loc" : [ -92.290599, 44.835569 ], "pop" : 2746, "state" : "WI" }
+{ "_id" : "54768", "city" : "STANLEY", "loc" : [ -90.938935, 44.968872 ], "pop" : 3157, "state" : "WI" }
+{ "_id" : "54769", "city" : "STOCKHOLM", "loc" : [ -92.22842900000001, 44.500441 ], "pop" : 434, "state" : "WI" }
+{ "_id" : "54770", "city" : "STRUM", "loc" : [ -91.38327099999999, 44.567356 ], "pop" : 1560, "state" : "WI" }
+{ "_id" : "54771", "city" : "THORP", "loc" : [ -90.80286099999999, 44.957319 ], "pop" : 4803, "state" : "WI" }
+{ "_id" : "54772", "city" : "WHEELER", "loc" : [ -91.887055, 45.071856 ], "pop" : 1094, "state" : "WI" }
+{ "_id" : "54773", "city" : "WHITEHALL", "loc" : [ -91.302953, 44.382683 ], "pop" : 3330, "state" : "WI" }
+{ "_id" : "54801", "city" : "SPOONER", "loc" : [ -91.91555, 45.850468 ], "pop" : 5384, "state" : "WI" }
+{ "_id" : "54805", "city" : "ALMENA", "loc" : [ -92.002691, 45.419507 ], "pop" : 3180, "state" : "WI" }
+{ "_id" : "54806", "city" : "MOQUAH", "loc" : [ -90.876712, 46.577948 ], "pop" : 12254, "state" : "WI" }
+{ "_id" : "54810", "city" : "BALSAM LAKE", "loc" : [ -92.41495399999999, 45.458845 ], "pop" : 1765, "state" : "WI" }
+{ "_id" : "54812", "city" : "BARRON", "loc" : [ -91.84996, 45.400535 ], "pop" : 4049, "state" : "WI" }
+{ "_id" : "54813", "city" : "BARRONETT", "loc" : [ -92.019595, 45.618995 ], "pop" : 804, "state" : "WI" }
+{ "_id" : "54814", "city" : "BAYFIELD", "loc" : [ -90.821681, 46.835359 ], "pop" : 2375, "state" : "WI" }
+{ "_id" : "54817", "city" : "BIRCHWOOD", "loc" : [ -91.577564, 45.640296 ], "pop" : 1962, "state" : "WI" }
+{ "_id" : "54819", "city" : "BRUCE", "loc" : [ -91.290622, 45.447923 ], "pop" : 2654, "state" : "WI" }
+{ "_id" : "54820", "city" : "BRULE", "loc" : [ -91.553862, 46.576318 ], "pop" : 902, "state" : "WI" }
+{ "_id" : "54821", "city" : "CABLE", "loc" : [ -91.22443800000001, 46.217155 ], "pop" : 1311, "state" : "WI" }
+{ "_id" : "54822", "city" : "CAMERON", "loc" : [ -91.730992, 45.403836 ], "pop" : 3314, "state" : "WI" }
+{ "_id" : "54824", "city" : "CENTURIA", "loc" : [ -92.547741, 45.448369 ], "pop" : 1791, "state" : "WI" }
+{ "_id" : "54826", "city" : "COMSTOCK", "loc" : [ -92.085961, 45.491114 ], "pop" : 473, "state" : "WI" }
+{ "_id" : "54827", "city" : "CORNUCOPIA", "loc" : [ -91.097421, 46.837171 ], "pop" : 242, "state" : "WI" }
+{ "_id" : "54828", "city" : "NEW POST", "loc" : [ -91.327825, 45.809664 ], "pop" : 377, "state" : "WI" }
+{ "_id" : "54829", "city" : "CUMBERLAND", "loc" : [ -92.029709, 45.5403 ], "pop" : 4229, "state" : "WI" }
+{ "_id" : "54830", "city" : "DAIRYLAND", "loc" : [ -92.265995, 46.029681 ], "pop" : 1855, "state" : "WI" }
+{ "_id" : "54832", "city" : "DRUMMOND", "loc" : [ -91.285569, 46.311896 ], "pop" : 329, "state" : "WI" }
+{ "_id" : "54835", "city" : "EXELAND", "loc" : [ -91.22381900000001, 45.675298 ], "pop" : 939, "state" : "WI" }
+{ "_id" : "54836", "city" : "FOXBORO", "loc" : [ -92.149254, 46.487511 ], "pop" : 1528, "state" : "WI" }
+{ "_id" : "54837", "city" : "CLAM FALLS", "loc" : [ -92.42648199999999, 45.665314 ], "pop" : 4011, "state" : "WI" }
+{ "_id" : "54838", "city" : "GORDON", "loc" : [ -91.803301, 46.233603 ], "pop" : 1088, "state" : "WI" }
+{ "_id" : "54839", "city" : "GRAND VIEW", "loc" : [ -91.107465, 46.357682 ], "pop" : 280, "state" : "WI" }
+{ "_id" : "54840", "city" : "EVERGREEN", "loc" : [ -92.662685, 45.761312 ], "pop" : 4008, "state" : "WI" }
+{ "_id" : "54843", "city" : "NORTH WOODS BEAC", "loc" : [ -91.397659, 46.001404 ], "pop" : 9339, "state" : "WI" }
+{ "_id" : "54844", "city" : "HERBSTER", "loc" : [ -91.233193, 46.82128 ], "pop" : 230, "state" : "WI" }
+{ "_id" : "54845", "city" : "HERTEL", "loc" : [ -92.14041899999999, 45.807561 ], "pop" : 110, "state" : "WI" }
+{ "_id" : "54846", "city" : "HIGH BRIDGE", "loc" : [ -90.73826, 46.379613 ], "pop" : 536, "state" : "WI" }
+{ "_id" : "54847", "city" : "IRON RIVER", "loc" : [ -91.42105599999999, 46.578984 ], "pop" : 1777, "state" : "WI" }
+{ "_id" : "54848", "city" : "LADYSMITH", "loc" : [ -91.10880400000001, 45.471941 ], "pop" : 6737, "state" : "WI" }
+{ "_id" : "54849", "city" : "LAKE NEBAGAMON", "loc" : [ -91.74024300000001, 46.502347 ], "pop" : 1824, "state" : "WI" }
+{ "_id" : "54850", "city" : "LA POINTE", "loc" : [ -90.603622, 46.846675 ], "pop" : 17, "state" : "WI" }
+{ "_id" : "54853", "city" : "LUCK", "loc" : [ -92.416391, 45.556799 ], "pop" : 2131, "state" : "WI" }
+{ "_id" : "54854", "city" : "MAPLE", "loc" : [ -91.702015, 46.620591 ], "pop" : 891, "state" : "WI" }
+{ "_id" : "54855", "city" : "MARENGO", "loc" : [ -90.839991, 46.407112 ], "pop" : 592, "state" : "WI" }
+{ "_id" : "54856", "city" : "DELTA", "loc" : [ -91.05751100000001, 46.457285 ], "pop" : 1519, "state" : "WI" }
+{ "_id" : "54858", "city" : "MILLTOWN", "loc" : [ -92.501739, 45.527082 ], "pop" : 1570, "state" : "WI" }
+{ "_id" : "54859", "city" : "MINONG", "loc" : [ -91.850628, 46.10445 ], "pop" : 1451, "state" : "WI" }
+{ "_id" : "54862", "city" : "OJIBWA", "loc" : [ -91.110922, 45.785351 ], "pop" : 401, "state" : "WI" }
+{ "_id" : "54864", "city" : "POPLAR", "loc" : [ -91.825345, 46.57708 ], "pop" : 1064, "state" : "WI" }
+{ "_id" : "54865", "city" : "PORT WING", "loc" : [ -91.392016, 46.76204 ], "pop" : 544, "state" : "WI" }
+{ "_id" : "54867", "city" : "RADISSON", "loc" : [ -91.22615, 45.773359 ], "pop" : 509, "state" : "WI" }
+{ "_id" : "54868", "city" : "CANTON", "loc" : [ -91.73354399999999, 45.510466 ], "pop" : 13996, "state" : "WI" }
+{ "_id" : "54870", "city" : "SARONA", "loc" : [ -91.762103, 45.708532 ], "pop" : 1201, "state" : "WI" }
+{ "_id" : "54871", "city" : "SHELL LAKE", "loc" : [ -91.960606, 45.753598 ], "pop" : 3450, "state" : "WI" }
+{ "_id" : "54872", "city" : "SIREN", "loc" : [ -92.389151, 45.78214 ], "pop" : 2495, "state" : "WI" }
+{ "_id" : "54873", "city" : "BARNES", "loc" : [ -91.77015400000001, 46.388821 ], "pop" : 2443, "state" : "WI" }
+{ "_id" : "54874", "city" : "WENTWORTH", "loc" : [ -91.94580499999999, 46.588659 ], "pop" : 3029, "state" : "WI" }
+{ "_id" : "54875", "city" : "EARL", "loc" : [ -91.677734, 45.960384 ], "pop" : 970, "state" : "WI" }
+{ "_id" : "54876", "city" : "STONE LAKE", "loc" : [ -91.509291, 45.833733 ], "pop" : 1662, "state" : "WI" }
+{ "_id" : "54880", "city" : "SUPERIOR", "loc" : [ -92.091174, 46.701552 ], "pop" : 29513, "state" : "WI" }
+{ "_id" : "54888", "city" : "TREGO", "loc" : [ -91.858051, 45.951556 ], "pop" : 1037, "state" : "WI" }
+{ "_id" : "54889", "city" : "TURTLE LAKE", "loc" : [ -92.17814199999999, 45.421349 ], "pop" : 2048, "state" : "WI" }
+{ "_id" : "54891", "city" : "WASHBURN", "loc" : [ -90.909516, 46.680595 ], "pop" : 3177, "state" : "WI" }
+{ "_id" : "54893", "city" : "WEBSTER", "loc" : [ -92.322722, 45.874001 ], "pop" : 3012, "state" : "WI" }
+{ "_id" : "54895", "city" : "WEYERHAEUSER", "loc" : [ -91.428944, 45.426347 ], "pop" : 858, "state" : "WI" }
+{ "_id" : "54896", "city" : "LORETTA", "loc" : [ -90.949591, 45.841419 ], "pop" : 1385, "state" : "WI" }
+{ "_id" : "54901", "city" : "OSHKOSH", "loc" : [ -88.54363499999999, 44.021962 ], "pop" : 57187, "state" : "WI" }
+{ "_id" : "54904", "city" : "OSHKOSH", "loc" : [ -88.607015, 44.030356 ], "pop" : 12608, "state" : "WI" }
+{ "_id" : "54909", "city" : "ALMOND", "loc" : [ -89.35836399999999, 44.289832 ], "pop" : 2002, "state" : "WI" }
+{ "_id" : "54911", "city" : "APPLETON", "loc" : [ -88.397649, 44.277325 ], "pop" : 25970, "state" : "WI" }
+{ "_id" : "54914", "city" : "APPLETON", "loc" : [ -88.432608, 44.270992 ], "pop" : 23028, "state" : "WI" }
+{ "_id" : "54915", "city" : "APPLETON", "loc" : [ -88.399902, 44.26351 ], "pop" : 42119, "state" : "WI" }
+{ "_id" : "54921", "city" : "BANCROFT", "loc" : [ -89.530438, 44.30648 ], "pop" : 1368, "state" : "WI" }
+{ "_id" : "54922", "city" : "BEAR CREEK", "loc" : [ -88.740375, 44.5348 ], "pop" : 1488, "state" : "WI" }
+{ "_id" : "54923", "city" : "BERLIN", "loc" : [ -88.949009, 43.976936 ], "pop" : 8132, "state" : "WI" }
+{ "_id" : "54928", "city" : "CAROLINE", "loc" : [ -88.888749, 44.727574 ], "pop" : 293, "state" : "WI" }
+{ "_id" : "54929", "city" : "CLINTONVILLE", "loc" : [ -88.742999, 44.636442 ], "pop" : 8902, "state" : "WI" }
+{ "_id" : "54930", "city" : "COLOMA", "loc" : [ -89.494332, 44.027462 ], "pop" : 1364, "state" : "WI" }
+{ "_id" : "54932", "city" : "ELDORADO", "loc" : [ -88.63882700000001, 43.841471 ], "pop" : 765, "state" : "WI" }
+{ "_id" : "54935", "city" : "TAYCHEEDAH", "loc" : [ -88.429149, 43.770446 ], "pop" : 37093, "state" : "WI" }
+{ "_id" : "54937", "city" : "NORTH FOND DU LA", "loc" : [ -88.481264, 43.792633 ], "pop" : 14665, "state" : "WI" }
+{ "_id" : "54940", "city" : "FREMONT", "loc" : [ -88.844852, 44.237884 ], "pop" : 3211, "state" : "WI" }
+{ "_id" : "54941", "city" : "GREEN LAKE", "loc" : [ -88.96847, 43.844383 ], "pop" : 2504, "state" : "WI" }
+{ "_id" : "54942", "city" : "GREENVILLE", "loc" : [ -88.569579, 44.299747 ], "pop" : 1722, "state" : "WI" }
+{ "_id" : "54943", "city" : "HANCOCK", "loc" : [ -89.534448, 44.129743 ], "pop" : 1214, "state" : "WI" }
+{ "_id" : "54944", "city" : "HORTONVILLE", "loc" : [ -88.62813, 44.327306 ], "pop" : 5602, "state" : "WI" }
+{ "_id" : "54945", "city" : "IOLA", "loc" : [ -89.137311, 44.532183 ], "pop" : 2589, "state" : "WI" }
+{ "_id" : "54946", "city" : "KING", "loc" : [ -89.113739, 44.267332 ], "pop" : 661, "state" : "WI" }
+{ "_id" : "54947", "city" : "LARSEN", "loc" : [ -88.696305, 44.198421 ], "pop" : 1863, "state" : "WI" }
+{ "_id" : "54948", "city" : "LEOPOLIS", "loc" : [ -88.87222300000001, 44.781188 ], "pop" : 403, "state" : "WI" }
+{ "_id" : "54949", "city" : "MANAWA", "loc" : [ -88.916444, 44.470148 ], "pop" : 2749, "state" : "WI" }
+{ "_id" : "54950", "city" : "MARION", "loc" : [ -88.876706, 44.679414 ], "pop" : 3071, "state" : "WI" }
+{ "_id" : "54952", "city" : "MENASHA", "loc" : [ -88.417536, 44.211164 ], "pop" : 22505, "state" : "WI" }
+{ "_id" : "54956", "city" : "NEENAH", "loc" : [ -88.479201, 44.181094 ], "pop" : 34261, "state" : "WI" }
+{ "_id" : "54960", "city" : "NESHKORO", "loc" : [ -89.233572, 43.898943 ], "pop" : 2210, "state" : "WI" }
+{ "_id" : "54961", "city" : "NEW LONDON", "loc" : [ -88.75542799999999, 44.392847 ], "pop" : 13037, "state" : "WI" }
+{ "_id" : "54962", "city" : "OGDENSBURG", "loc" : [ -89.01185099999999, 44.467803 ], "pop" : 1509, "state" : "WI" }
+{ "_id" : "54963", "city" : "OMRO", "loc" : [ -88.75193299999999, 44.035678 ], "pop" : 5678, "state" : "WI" }
+{ "_id" : "54964", "city" : "PICKETT", "loc" : [ -88.71345700000001, 43.900917 ], "pop" : 518, "state" : "WI" }
+{ "_id" : "54965", "city" : "PINE RIVER", "loc" : [ -89.040415, 44.160393 ], "pop" : 2148, "state" : "WI" }
+{ "_id" : "54966", "city" : "PLAINFIELD", "loc" : [ -89.455896, 44.209079 ], "pop" : 2336, "state" : "WI" }
+{ "_id" : "54967", "city" : "POY SIPPI", "loc" : [ -88.926835, 44.110069 ], "pop" : 232, "state" : "WI" }
+{ "_id" : "54968", "city" : "PRINCETON", "loc" : [ -89.12491300000001, 43.843827 ], "pop" : 3101, "state" : "WI" }
+{ "_id" : "54970", "city" : "REDGRANITE", "loc" : [ -89.098125, 44.04381 ], "pop" : 2093, "state" : "WI" }
+{ "_id" : "54971", "city" : "RIPON", "loc" : [ -88.842433, 43.845402 ], "pop" : 10694, "state" : "WI" }
+{ "_id" : "54974", "city" : "ROSENDALE", "loc" : [ -88.641704, 43.788903 ], "pop" : 2012, "state" : "WI" }
+{ "_id" : "54977", "city" : "SCANDINAVIA", "loc" : [ -89.165042, 44.460436 ], "pop" : 1097, "state" : "WI" }
+{ "_id" : "54978", "city" : "TILLEDA", "loc" : [ -88.907498, 44.811812 ], "pop" : 58, "state" : "WI" }
+{ "_id" : "54979", "city" : "VAN DYNE", "loc" : [ -88.510008, 43.873399 ], "pop" : 1403, "state" : "WI" }
+{ "_id" : "54981", "city" : "WAUPACA", "loc" : [ -89.11014299999999, 44.348101 ], "pop" : 11716, "state" : "WI" }
+{ "_id" : "54982", "city" : "WAUTOMA", "loc" : [ -89.26655100000001, 44.065576 ], "pop" : 6318, "state" : "WI" }
+{ "_id" : "54983", "city" : "WEYAUWEGA", "loc" : [ -88.941047, 44.320973 ], "pop" : 3886, "state" : "WI" }
+{ "_id" : "54984", "city" : "WILD ROSE", "loc" : [ -89.195252, 44.183433 ], "pop" : 2127, "state" : "WI" }
+{ "_id" : "54986", "city" : "WINNECONNE", "loc" : [ -88.721384, 44.118704 ], "pop" : 3887, "state" : "WI" }
+{ "_id" : "55001", "city" : "AFTON", "loc" : [ -92.823358, 44.86965 ], "pop" : 4357, "state" : "MN" }
+{ "_id" : "55003", "city" : "BAYPORT", "loc" : [ -92.784375, 45.021405 ], "pop" : 3200, "state" : "MN" }
+{ "_id" : "55005", "city" : "EAST BETHEL", "loc" : [ -93.233088, 45.394114 ], "pop" : 2821, "state" : "MN" }
+{ "_id" : "55006", "city" : "BRAHAM", "loc" : [ -93.203695, 45.717547 ], "pop" : 1944, "state" : "MN" }
+{ "_id" : "55007", "city" : "QUAMBA", "loc" : [ -92.98347, 45.938694 ], "pop" : 1222, "state" : "MN" }
+{ "_id" : "55008", "city" : "CAMBRIDGE", "loc" : [ -93.288935, 45.557591 ], "pop" : 14444, "state" : "MN" }
+{ "_id" : "55009", "city" : "CANNON FALLS", "loc" : [ -92.863995, 44.495985 ], "pop" : 7590, "state" : "MN" }
+{ "_id" : "55010", "city" : "CASTLE ROCK", "loc" : [ -93.109241, 44.594216 ], "pop" : 1480, "state" : "MN" }
+{ "_id" : "55011", "city" : "CEDAR EAST BETHE", "loc" : [ -93.265834, 45.336494 ], "pop" : 6874, "state" : "MN" }
+{ "_id" : "55013", "city" : "CHISAGO CITY", "loc" : [ -92.892134, 45.361144 ], "pop" : 2905, "state" : "MN" }
+{ "_id" : "55014", "city" : "CIRCLE PINES", "loc" : [ -93.143984, 45.152841 ], "pop" : 19791, "state" : "MN" }
+{ "_id" : "55016", "city" : "COTTAGE GROVE", "loc" : [ -92.939283, 44.830824 ], "pop" : 22265, "state" : "MN" }
+{ "_id" : "55017", "city" : "DALBO", "loc" : [ -93.441918, 45.678735 ], "pop" : 616, "state" : "MN" }
+{ "_id" : "55018", "city" : "STANTON", "loc" : [ -92.974779, 44.423884 ], "pop" : 2009, "state" : "MN" }
+{ "_id" : "55019", "city" : "DUNDAS", "loc" : [ -93.20368999999999, 44.395537 ], "pop" : 803, "state" : "MN" }
+{ "_id" : "55020", "city" : "ELKO", "loc" : [ -93.383555, 44.58945 ], "pop" : 4146, "state" : "MN" }
+{ "_id" : "55021", "city" : "FARIBAULT", "loc" : [ -93.28179, 44.294457 ], "pop" : 21450, "state" : "MN" }
+{ "_id" : "55024", "city" : "FARMINGTON", "loc" : [ -93.153891, 44.662799 ], "pop" : 10145, "state" : "MN" }
+{ "_id" : "55025", "city" : "FOREST LAKE", "loc" : [ -92.97489400000001, 45.268499 ], "pop" : 14749, "state" : "MN" }
+{ "_id" : "55026", "city" : "FRONTENAC", "loc" : [ -92.328103, 44.487176 ], "pop" : 1698, "state" : "MN" }
+{ "_id" : "55027", "city" : "GOODHUE", "loc" : [ -92.571743, 44.402178 ], "pop" : 1928, "state" : "MN" }
+{ "_id" : "55030", "city" : "GRASSTON", "loc" : [ -93.196226, 45.772926 ], "pop" : 1007, "state" : "MN" }
+{ "_id" : "55031", "city" : "HAMPTON", "loc" : [ -92.946673, 44.602848 ], "pop" : 1780, "state" : "MN" }
+{ "_id" : "55032", "city" : "HARRIS", "loc" : [ -93.039545, 45.596205 ], "pop" : 2026, "state" : "MN" }
+{ "_id" : "55033", "city" : "WELCH", "loc" : [ -92.862566, 44.718932 ], "pop" : 20769, "state" : "MN" }
+{ "_id" : "55037", "city" : "HINCKLEY", "loc" : [ -92.899333, 46.018876 ], "pop" : 2611, "state" : "MN" }
+{ "_id" : "55038", "city" : "CENTERVILLE", "loc" : [ -93.00349300000001, 45.1628 ], "pop" : 6520, "state" : "MN" }
+{ "_id" : "55040", "city" : "ISANTI", "loc" : [ -93.22656499999999, 45.468212 ], "pop" : 8004, "state" : "MN" }
+{ "_id" : "55041", "city" : "LAKE CITY", "loc" : [ -92.283778, 44.430493 ], "pop" : 5154, "state" : "MN" }
+{ "_id" : "55042", "city" : "LAKE ELMO", "loc" : [ -92.90564999999999, 44.994609 ], "pop" : 5903, "state" : "MN" }
+{ "_id" : "55043", "city" : "LAKELAND", "loc" : [ -92.771592, 44.939384 ], "pop" : 3792, "state" : "MN" }
+{ "_id" : "55044", "city" : "LAKEVILLE", "loc" : [ -93.257802, 44.674865 ], "pop" : 17741, "state" : "MN" }
+{ "_id" : "55045", "city" : "LINDSTROM", "loc" : [ -92.84207600000001, 45.387265 ], "pop" : 5991, "state" : "MN" }
+{ "_id" : "55046", "city" : "VESELI", "loc" : [ -93.42359399999999, 44.462888 ], "pop" : 4020, "state" : "MN" }
+{ "_id" : "55047", "city" : "MARINE ON SAINT", "loc" : [ -92.822952, 45.183119 ], "pop" : 4310, "state" : "MN" }
+{ "_id" : "55049", "city" : "MEDFORD", "loc" : [ -93.24372099999999, 44.17415 ], "pop" : 1305, "state" : "MN" }
+{ "_id" : "55051", "city" : "MORA", "loc" : [ -93.294234, 45.895786 ], "pop" : 10652, "state" : "MN" }
+{ "_id" : "55052", "city" : "MORRISTOWN", "loc" : [ -93.452512, 44.234183 ], "pop" : 1425, "state" : "MN" }
+{ "_id" : "55053", "city" : "NERSTRAND", "loc" : [ -93.0855, 44.353769 ], "pop" : 687, "state" : "MN" }
+{ "_id" : "55055", "city" : "NEWPORT", "loc" : [ -92.998603, 44.872522 ], "pop" : 3720, "state" : "MN" }
+{ "_id" : "55056", "city" : "NORTH BRANCH", "loc" : [ -92.93709699999999, 45.516479 ], "pop" : 6024, "state" : "MN" }
+{ "_id" : "55057", "city" : "NORTHFIELD", "loc" : [ -93.166826, 44.458724 ], "pop" : 17995, "state" : "MN" }
+{ "_id" : "55060", "city" : "OWATONNA", "loc" : [ -93.21914, 44.080478 ], "pop" : 23860, "state" : "MN" }
+{ "_id" : "55063", "city" : "BEROUN", "loc" : [ -92.98260399999999, 45.832273 ], "pop" : 6858, "state" : "MN" }
+{ "_id" : "55065", "city" : "RANDOLPH", "loc" : [ -93.01961900000001, 44.527386 ], "pop" : 370, "state" : "MN" }
+{ "_id" : "55066", "city" : "RED WING", "loc" : [ -92.548559, 44.552779 ], "pop" : 17033, "state" : "MN" }
+{ "_id" : "55067", "city" : "ROCK CREEK", "loc" : [ -92.930826, 45.762404 ], "pop" : 1040, "state" : "MN" }
+{ "_id" : "55068", "city" : "ROSEMOUNT", "loc" : [ -93.158844, 44.728919 ], "pop" : 14747, "state" : "MN" }
+{ "_id" : "55069", "city" : "RUSH CITY", "loc" : [ -92.99787600000001, 45.684496 ], "pop" : 3566, "state" : "MN" }
+{ "_id" : "55070", "city" : "SAINT FRANCIS", "loc" : [ -93.359832, 45.390284 ], "pop" : 2789, "state" : "MN" }
+{ "_id" : "55071", "city" : "SAINT PAUL PARK", "loc" : [ -92.987331, 44.834404 ], "pop" : 5517, "state" : "MN" }
+{ "_id" : "55072", "city" : "MARKVILLE", "loc" : [ -92.87100100000001, 46.121355 ], "pop" : 3299, "state" : "MN" }
+{ "_id" : "55073", "city" : "SCANDIA", "loc" : [ -92.82915800000001, 45.269666 ], "pop" : 2024, "state" : "MN" }
+{ "_id" : "55074", "city" : "SHAFER", "loc" : [ -92.76088900000001, 45.357561 ], "pop" : 1519, "state" : "MN" }
+{ "_id" : "55075", "city" : "SOUTH SAINT PAUL", "loc" : [ -93.046013, 44.888128 ], "pop" : 20027, "state" : "MN" }
+{ "_id" : "55076", "city" : "INVER GROVE HEIG", "loc" : [ -93.034746, 44.841966 ], "pop" : 14444, "state" : "MN" }
+{ "_id" : "55077", "city" : "INVER GROVE HEIG", "loc" : [ -93.073938, 44.850123 ], "pop" : 8309, "state" : "MN" }
+{ "_id" : "55079", "city" : "STACY", "loc" : [ -93.017743, 45.397509 ], "pop" : 5936, "state" : "MN" }
+{ "_id" : "55080", "city" : "STANCHFIELD", "loc" : [ -93.243302, 45.667513 ], "pop" : 913, "state" : "MN" }
+{ "_id" : "55082", "city" : "OAK PARK HEIGHTS", "loc" : [ -92.830032, 45.050007 ], "pop" : 25247, "state" : "MN" }
+{ "_id" : "55084", "city" : "TAYLORS FALLS", "loc" : [ -92.69059300000001, 45.41825 ], "pop" : 1421, "state" : "MN" }
+{ "_id" : "55087", "city" : "WARSAW", "loc" : [ -93.364181, 44.250439 ], "pop" : 1236, "state" : "MN" }
+{ "_id" : "55088", "city" : "WEBSTER", "loc" : [ -93.334418, 44.502633 ], "pop" : 1452, "state" : "MN" }
+{ "_id" : "55089", "city" : "WELCH", "loc" : [ -92.726259, 44.603006 ], "pop" : 678, "state" : "MN" }
+{ "_id" : "55092", "city" : "EAST BETHEL", "loc" : [ -93.06856500000001, 45.324337 ], "pop" : 7514, "state" : "MN" }
+{ "_id" : "55101", "city" : "SAINT PAUL", "loc" : [ -93.083167, 44.969963 ], "pop" : 18352, "state" : "MN" }
+{ "_id" : "55102", "city" : "SAINT PAUL", "loc" : [ -93.120852, 44.937228 ], "pop" : 18585, "state" : "MN" }
+{ "_id" : "55103", "city" : "SAINT PAUL", "loc" : [ -93.121594, 44.960798 ], "pop" : 12169, "state" : "MN" }
+{ "_id" : "55104", "city" : "SAINT PAUL", "loc" : [ -93.15797000000001, 44.953179 ], "pop" : 46396, "state" : "MN" }
+{ "_id" : "55105", "city" : "SAINT PAUL", "loc" : [ -93.165148, 44.934723 ], "pop" : 26216, "state" : "MN" }
+{ "_id" : "55106", "city" : "SAINT PAUL", "loc" : [ -93.048817, 44.968384 ], "pop" : 47905, "state" : "MN" }
+{ "_id" : "55107", "city" : "WEST SAINT PAUL", "loc" : [ -93.086157, 44.927235 ], "pop" : 15825, "state" : "MN" }
+{ "_id" : "55108", "city" : "LAUDERDALE", "loc" : [ -93.17458000000001, 44.982217 ], "pop" : 17285, "state" : "MN" }
+{ "_id" : "55109", "city" : "NORTH SAINT PAUL", "loc" : [ -93.017072, 45.011859 ], "pop" : 28263, "state" : "MN" }
+{ "_id" : "55110", "city" : "WHITE BEAR LAKE", "loc" : [ -93.01129899999999, 45.074527 ], "pop" : 38649, "state" : "MN" }
+{ "_id" : "55111", "city" : "FORT SNELLING", "loc" : [ -93.202579, 44.901548 ], "pop" : 97, "state" : "MN" }
+{ "_id" : "55112", "city" : "NEW BRIGHTON", "loc" : [ -93.199691, 45.074129 ], "pop" : 44128, "state" : "MN" }
+{ "_id" : "55113", "city" : "ROSEVILLE", "loc" : [ -93.14924499999999, 45.012876 ], "pop" : 37302, "state" : "MN" }
+{ "_id" : "55114", "city" : "SAINT PAUL", "loc" : [ -93.19806699999999, 44.967968 ], "pop" : 1402, "state" : "MN" }
+{ "_id" : "55115", "city" : "WHITE BEAR LAKE", "loc" : [ -92.954847, 45.061132 ], "pop" : 6201, "state" : "MN" }
+{ "_id" : "55116", "city" : "SAINT PAUL", "loc" : [ -93.172747, 44.914007 ], "pop" : 23868, "state" : "MN" }
+{ "_id" : "55117", "city" : "LITTLE CANADA", "loc" : [ -93.10365899999999, 44.992165 ], "pop" : 38771, "state" : "MN" }
+{ "_id" : "55118", "city" : "WEST SAINT PAUL", "loc" : [ -93.096435, 44.902691 ], "pop" : 25866, "state" : "MN" }
+{ "_id" : "55119", "city" : "MAPLEWOOD", "loc" : [ -93.008019, 44.955384 ], "pop" : 33887, "state" : "MN" }
+{ "_id" : "55120", "city" : "EAGAN", "loc" : [ -93.12902, 44.873825 ], "pop" : 3113, "state" : "MN" }
+{ "_id" : "55121", "city" : "EAGAN", "loc" : [ -93.16753, 44.843039 ], "pop" : 6047, "state" : "MN" }
+{ "_id" : "55122", "city" : "EAGAN", "loc" : [ -93.19693700000001, 44.803593 ], "pop" : 23875, "state" : "MN" }
+{ "_id" : "55123", "city" : "EAGAN", "loc" : [ -93.14135, 44.809764 ], "pop" : 17487, "state" : "MN" }
+{ "_id" : "55124", "city" : "APPLE VALLEY", "loc" : [ -93.20775999999999, 44.746147 ], "pop" : 34598, "state" : "MN" }
+{ "_id" : "55125", "city" : "WOODBURY", "loc" : [ -92.951413, 44.916195 ], "pop" : 20075, "state" : "MN" }
+{ "_id" : "55126", "city" : "SHOREVIEW", "loc" : [ -93.134367, 45.083334 ], "pop" : 24597, "state" : "MN" }
+{ "_id" : "55127", "city" : "VADNAIS HEIGHTS", "loc" : [ -93.07875, 45.070839 ], "pop" : 14628, "state" : "MN" }
+{ "_id" : "55128", "city" : "OAKDALE", "loc" : [ -92.96812799999999, 44.984648 ], "pop" : 19099, "state" : "MN" }
+{ "_id" : "55150", "city" : "MENDOTA", "loc" : [ -93.161221, 44.885796 ], "pop" : 164, "state" : "MN" }
+{ "_id" : "55301", "city" : "ALBERTVILLE", "loc" : [ -93.646899, 45.253425 ], "pop" : 3132, "state" : "MN" }
+{ "_id" : "55302", "city" : "ANNANDALE", "loc" : [ -94.106072, 45.248272 ], "pop" : 6174, "state" : "MN" }
+{ "_id" : "55303", "city" : "RAMSEY", "loc" : [ -93.407822, 45.238537 ], "pop" : 33161, "state" : "MN" }
+{ "_id" : "55304", "city" : "HAM LAKE", "loc" : [ -93.284531, 45.25068 ], "pop" : 25122, "state" : "MN" }
+{ "_id" : "55307", "city" : "ARLINGTON", "loc" : [ -94.076195, 44.615279 ], "pop" : 2997, "state" : "MN" }
+{ "_id" : "55308", "city" : "BECKER", "loc" : [ -93.84096599999999, 45.436539 ], "pop" : 3589, "state" : "MN" }
+{ "_id" : "55309", "city" : "BIG LAKE", "loc" : [ -93.73991700000001, 45.350648 ], "pop" : 6703, "state" : "MN" }
+{ "_id" : "55310", "city" : "BIRD ISLAND", "loc" : [ -94.871634, 44.750729 ], "pop" : 1885, "state" : "MN" }
+{ "_id" : "55312", "city" : "BROWNTON", "loc" : [ -94.330611, 44.728145 ], "pop" : 1686, "state" : "MN" }
+{ "_id" : "55313", "city" : "BUFFALO", "loc" : [ -93.863479, 45.181371 ], "pop" : 8942, "state" : "MN" }
+{ "_id" : "55314", "city" : "BUFFALO LAKE", "loc" : [ -94.591207, 44.770885 ], "pop" : 1431, "state" : "MN" }
+{ "_id" : "55315", "city" : "CARVER", "loc" : [ -93.687949, 44.716898 ], "pop" : 1181, "state" : "MN" }
+{ "_id" : "55316", "city" : "CHAMPLIN", "loc" : [ -93.381927, 45.170042 ], "pop" : 16849, "state" : "MN" }
+{ "_id" : "55317", "city" : "CHANHASSEN", "loc" : [ -93.535906, 44.867924 ], "pop" : 8499, "state" : "MN" }
+{ "_id" : "55318", "city" : "CHASKA", "loc" : [ -93.60831399999999, 44.806071 ], "pop" : 13907, "state" : "MN" }
+{ "_id" : "55319", "city" : "CLEAR LAKE", "loc" : [ -93.968391, 45.479477 ], "pop" : 3280, "state" : "MN" }
+{ "_id" : "55320", "city" : "CLEARWATER", "loc" : [ -94.04524600000001, 45.387694 ], "pop" : 1752, "state" : "MN" }
+{ "_id" : "55321", "city" : "COKATO", "loc" : [ -94.19105399999999, 45.074761 ], "pop" : 4053, "state" : "MN" }
+{ "_id" : "55322", "city" : "COLOGNE", "loc" : [ -93.798249, 44.764591 ], "pop" : 2298, "state" : "MN" }
+{ "_id" : "55324", "city" : "DARWIN", "loc" : [ -94.424926, 45.102949 ], "pop" : 933, "state" : "MN" }
+{ "_id" : "55325", "city" : "DASSEL", "loc" : [ -94.33047500000001, 45.103208 ], "pop" : 4818, "state" : "MN" }
+{ "_id" : "55327", "city" : "DAYTON", "loc" : [ -93.466795, 45.198164 ], "pop" : 4251, "state" : "MN" }
+{ "_id" : "55328", "city" : "DELANO", "loc" : [ -93.801644, 45.034222 ], "pop" : 5574, "state" : "MN" }
+{ "_id" : "55329", "city" : "EDEN VALLEY", "loc" : [ -94.603911, 45.302006 ], "pop" : 1955, "state" : "MN" }
+{ "_id" : "55330", "city" : "ELK RIVER", "loc" : [ -93.5814, 45.313601 ], "pop" : 17703, "state" : "MN" }
+{ "_id" : "55331", "city" : "EXCELSIOR", "loc" : [ -93.579132, 44.900704 ], "pop" : 15860, "state" : "MN" }
+{ "_id" : "55332", "city" : "FAIRFAX", "loc" : [ -94.72562600000001, 44.532942 ], "pop" : 2250, "state" : "MN" }
+{ "_id" : "55333", "city" : "FRANKLIN", "loc" : [ -94.893094, 44.542132 ], "pop" : 702, "state" : "MN" }
+{ "_id" : "55334", "city" : "GAYLORD", "loc" : [ -94.195543, 44.546298 ], "pop" : 3099, "state" : "MN" }
+{ "_id" : "55335", "city" : "GIBBON", "loc" : [ -94.54667999999999, 44.560587 ], "pop" : 1718, "state" : "MN" }
+{ "_id" : "55336", "city" : "GLENCOE", "loc" : [ -94.161554, 44.778001 ], "pop" : 6275, "state" : "MN" }
+{ "_id" : "55337", "city" : "BURNSVILLE", "loc" : [ -93.275283, 44.76086 ], "pop" : 51421, "state" : "MN" }
+{ "_id" : "55338", "city" : "GREEN ISLE", "loc" : [ -93.932635, 44.668665 ], "pop" : 1353, "state" : "MN" }
+{ "_id" : "55339", "city" : "HAMBURG", "loc" : [ -93.96431699999999, 44.731452 ], "pop" : 696, "state" : "MN" }
+{ "_id" : "55340", "city" : "HAMEL", "loc" : [ -93.575957, 45.079951 ], "pop" : 4930, "state" : "MN" }
+{ "_id" : "55342", "city" : "HECTOR", "loc" : [ -94.70582400000001, 44.748489 ], "pop" : 1896, "state" : "MN" }
+{ "_id" : "55343", "city" : "EDEN PRAIRIE", "loc" : [ -93.41645200000001, 44.933318 ], "pop" : 40067, "state" : "MN" }
+{ "_id" : "55344", "city" : "EDEN PRAIRIE", "loc" : [ -93.437573, 44.857426 ], "pop" : 7901, "state" : "MN" }
+{ "_id" : "55345", "city" : "MINNETONKA", "loc" : [ -93.48499700000001, 44.913808 ], "pop" : 22535, "state" : "MN" }
+{ "_id" : "55346", "city" : "EDEN PRAIRIE", "loc" : [ -93.483028, 44.877106 ], "pop" : 16269, "state" : "MN" }
+{ "_id" : "55347", "city" : "EDEN PRAIRIE", "loc" : [ -93.438934, 44.834217 ], "pop" : 15141, "state" : "MN" }
+{ "_id" : "55349", "city" : "HOWARD LAKE", "loc" : [ -94.069515, 45.061594 ], "pop" : 3443, "state" : "MN" }
+{ "_id" : "55350", "city" : "HUTCHINSON", "loc" : [ -94.384691, 44.894554 ], "pop" : 15549, "state" : "MN" }
+{ "_id" : "55352", "city" : "JORDAN", "loc" : [ -93.61946, 44.671321 ], "pop" : 4679, "state" : "MN" }
+{ "_id" : "55353", "city" : "KIMBALL", "loc" : [ -94.302837, 45.343584 ], "pop" : 2226, "state" : "MN" }
+{ "_id" : "55354", "city" : "LESTER PRAIRIE", "loc" : [ -94.055094, 44.873898 ], "pop" : 2160, "state" : "MN" }
+{ "_id" : "55355", "city" : "LITCHFIELD", "loc" : [ -94.526805, 45.126272 ], "pop" : 8528, "state" : "MN" }
+{ "_id" : "55356", "city" : "LONG LAKE", "loc" : [ -93.58179800000001, 44.991228 ], "pop" : 5700, "state" : "MN" }
+{ "_id" : "55357", "city" : "LORETTO", "loc" : [ -93.66916500000001, 45.106099 ], "pop" : 1492, "state" : "MN" }
+{ "_id" : "55358", "city" : "MAPLE LAKE", "loc" : [ -93.963793, 45.220236 ], "pop" : 4084, "state" : "MN" }
+{ "_id" : "55359", "city" : "MAPLE PLAIN", "loc" : [ -93.700214, 44.978686 ], "pop" : 6885, "state" : "MN" }
+{ "_id" : "55360", "city" : "MAYER", "loc" : [ -93.885925, 44.902231 ], "pop" : 1233, "state" : "MN" }
+{ "_id" : "55362", "city" : "MONTICELLO", "loc" : [ -93.802252, 45.295557 ], "pop" : 8919, "state" : "MN" }
+{ "_id" : "55363", "city" : "MONTROSE", "loc" : [ -93.93176200000001, 45.089737 ], "pop" : 2847, "state" : "MN" }
+{ "_id" : "55364", "city" : "MOUND", "loc" : [ -93.656087, 44.938158 ], "pop" : 13251, "state" : "MN" }
+{ "_id" : "55366", "city" : "NEW AUBURN", "loc" : [ -94.20567, 44.675919 ], "pop" : 784, "state" : "MN" }
+{ "_id" : "55367", "city" : "NEW GERMANY", "loc" : [ -93.97013099999999, 44.899431 ], "pop" : 1136, "state" : "MN" }
+{ "_id" : "55368", "city" : "NORWOOD", "loc" : [ -93.93006699999999, 44.766786 ], "pop" : 1761, "state" : "MN" }
+{ "_id" : "55369", "city" : "MAPLE GROVE", "loc" : [ -93.43987, 45.108636 ], "pop" : 41581, "state" : "MN" }
+{ "_id" : "55370", "city" : "PLATO", "loc" : [ -94.050583, 44.765728 ], "pop" : 990, "state" : "MN" }
+{ "_id" : "55371", "city" : "PRINCETON", "loc" : [ -93.596143, 45.585115 ], "pop" : 8975, "state" : "MN" }
+{ "_id" : "55372", "city" : "PRIOR LAKE", "loc" : [ -93.41005699999999, 44.710694 ], "pop" : 18539, "state" : "MN" }
+{ "_id" : "55373", "city" : "ROCKFORD", "loc" : [ -93.765832, 45.103074 ], "pop" : 6268, "state" : "MN" }
+{ "_id" : "55374", "city" : "ROGERS", "loc" : [ -93.581445, 45.171484 ], "pop" : 4957, "state" : "MN" }
+{ "_id" : "55376", "city" : "SAINT MICHAEL", "loc" : [ -93.65925300000001, 45.206409 ], "pop" : 5441, "state" : "MN" }
+{ "_id" : "55378", "city" : "SAVAGE", "loc" : [ -93.343445, 44.761547 ], "pop" : 7764, "state" : "MN" }
+{ "_id" : "55379", "city" : "SHAKOPEE", "loc" : [ -93.51974800000001, 44.7793 ], "pop" : 14755, "state" : "MN" }
+{ "_id" : "55380", "city" : "SILVER CREEK", "loc" : [ -93.94962200000001, 45.326474 ], "pop" : 1835, "state" : "MN" }
+{ "_id" : "55381", "city" : "SILVER LAKE", "loc" : [ -94.197383, 44.913945 ], "pop" : 2012, "state" : "MN" }
+{ "_id" : "55382", "city" : "SOUTH HAVEN", "loc" : [ -94.162768, 45.346008 ], "pop" : 4377, "state" : "MN" }
+{ "_id" : "55384", "city" : "SPRING PARK", "loc" : [ -93.63410399999999, 44.935566 ], "pop" : 1571, "state" : "MN" }
+{ "_id" : "55385", "city" : "STEWART", "loc" : [ -94.451572, 44.725928 ], "pop" : 1410, "state" : "MN" }
+{ "_id" : "55386", "city" : "VICTORIA", "loc" : [ -93.656094, 44.858223 ], "pop" : 1367, "state" : "MN" }
+{ "_id" : "55387", "city" : "WACONIA", "loc" : [ -93.7784, 44.851029 ], "pop" : 5844, "state" : "MN" }
+{ "_id" : "55388", "city" : "WATERTOWN", "loc" : [ -93.848159, 44.959533 ], "pop" : 3520, "state" : "MN" }
+{ "_id" : "55389", "city" : "WATKINS", "loc" : [ -94.429677, 45.308652 ], "pop" : 1998, "state" : "MN" }
+{ "_id" : "55390", "city" : "WAVERLY", "loc" : [ -93.954538, 45.041265 ], "pop" : 1691, "state" : "MN" }
+{ "_id" : "55391", "city" : "WAYZATA", "loc" : [ -93.52058100000001, 44.958189 ], "pop" : 15196, "state" : "MN" }
+{ "_id" : "55395", "city" : "WINSTED", "loc" : [ -94.05516799999999, 44.958459 ], "pop" : 2548, "state" : "MN" }
+{ "_id" : "55396", "city" : "WINTHROP", "loc" : [ -94.36984699999999, 44.543566 ], "pop" : 2630, "state" : "MN" }
+{ "_id" : "55397", "city" : "YOUNG AMERICA", "loc" : [ -93.918049, 44.792905 ], "pop" : 2527, "state" : "MN" }
+{ "_id" : "55398", "city" : "ZIMMERMAN", "loc" : [ -93.58785899999999, 45.455321 ], "pop" : 5786, "state" : "MN" }
+{ "_id" : "55401", "city" : "MINNEAPOLIS", "loc" : [ -93.26825100000001, 44.983473 ], "pop" : 2716, "state" : "MN" }
+{ "_id" : "55402", "city" : "MINNEAPOLIS", "loc" : [ -93.275871, 44.976184 ], "pop" : 261, "state" : "MN" }
+{ "_id" : "55403", "city" : "MINNEAPOLIS", "loc" : [ -93.282841, 44.967345 ], "pop" : 14098, "state" : "MN" }
+{ "_id" : "55404", "city" : "MINNEAPOLIS", "loc" : [ -93.26416, 44.960891 ], "pop" : 19903, "state" : "MN" }
+{ "_id" : "55405", "city" : "MINNEAPOLIS", "loc" : [ -93.29909600000001, 44.968734 ], "pop" : 16148, "state" : "MN" }
+{ "_id" : "55406", "city" : "MINNEAPOLIS", "loc" : [ -93.221357, 44.938359 ], "pop" : 31760, "state" : "MN" }
+{ "_id" : "55407", "city" : "MINNEAPOLIS", "loc" : [ -93.25449999999999, 44.937787 ], "pop" : 34059, "state" : "MN" }
+{ "_id" : "55408", "city" : "MINNEAPOLIS", "loc" : [ -93.28617300000001, 44.946575 ], "pop" : 29685, "state" : "MN" }
+{ "_id" : "55409", "city" : "MINNEAPOLIS", "loc" : [ -93.28182, 44.926378 ], "pop" : 20415, "state" : "MN" }
+{ "_id" : "55410", "city" : "EDINA", "loc" : [ -93.31818699999999, 44.915366 ], "pop" : 16834, "state" : "MN" }
+{ "_id" : "55411", "city" : "MINNEAPOLIS", "loc" : [ -93.30054800000001, 44.999601 ], "pop" : 30088, "state" : "MN" }
+{ "_id" : "55412", "city" : "MINNEAPOLIS", "loc" : [ -93.30203299999999, 45.024236 ], "pop" : 21329, "state" : "MN" }
+{ "_id" : "55413", "city" : "MINNEAPOLIS", "loc" : [ -93.255194, 44.997994 ], "pop" : 12201, "state" : "MN" }
+{ "_id" : "55414", "city" : "MINNEAPOLIS", "loc" : [ -93.219904, 44.977908 ], "pop" : 10535, "state" : "MN" }
+{ "_id" : "55415", "city" : "MINNEAPOLIS", "loc" : [ -93.264403, 44.971455 ], "pop" : 4401, "state" : "MN" }
+{ "_id" : "55416", "city" : "SAINT LOUIS PARK", "loc" : [ -93.340344, 44.946899 ], "pop" : 26211, "state" : "MN" }
+{ "_id" : "55417", "city" : "MINNEAPOLIS", "loc" : [ -93.23605999999999, 44.905371 ], "pop" : 25445, "state" : "MN" }
+{ "_id" : "55418", "city" : "MINNEAPOLIS", "loc" : [ -93.24010800000001, 45.01923 ], "pop" : 30904, "state" : "MN" }
+{ "_id" : "55419", "city" : "MINNEAPOLIS", "loc" : [ -93.288618, 44.902567 ], "pop" : 19740, "state" : "MN" }
+{ "_id" : "55420", "city" : "BLOOMINGTON", "loc" : [ -93.276034, 44.837284 ], "pop" : 22028, "state" : "MN" }
+{ "_id" : "55421", "city" : "COLUMBIA HEIGHTS", "loc" : [ -93.246095, 45.049582 ], "pop" : 25668, "state" : "MN" }
+{ "_id" : "55422", "city" : "ROBBINSDALE", "loc" : [ -93.339769, 45.016722 ], "pop" : 28922, "state" : "MN" }
+{ "_id" : "55423", "city" : "RICHFIELD", "loc" : [ -93.281351, 44.875731 ], "pop" : 35710, "state" : "MN" }
+{ "_id" : "55424", "city" : "EDINA", "loc" : [ -93.335005, 44.904385 ], "pop" : 12342, "state" : "MN" }
+{ "_id" : "55425", "city" : "BLOOMINGTON", "loc" : [ -93.249413, 44.843198 ], "pop" : 8501, "state" : "MN" }
+{ "_id" : "55426", "city" : "SAINT LOUIS PARK", "loc" : [ -93.379627, 44.954448 ], "pop" : 25951, "state" : "MN" }
+{ "_id" : "55427", "city" : "GOLDEN VALLEY", "loc" : [ -93.381585, 45.010374 ], "pop" : 24406, "state" : "MN" }
+{ "_id" : "55428", "city" : "CRYSTAL", "loc" : [ -93.376908, 45.060299 ], "pop" : 33233, "state" : "MN" }
+{ "_id" : "55429", "city" : "BROOKLYN CENTER", "loc" : [ -93.340203, 45.067667 ], "pop" : 22597, "state" : "MN" }
+{ "_id" : "55430", "city" : "BROOKLYN CENTER", "loc" : [ -93.29906800000001, 45.061106 ], "pop" : 21561, "state" : "MN" }
+{ "_id" : "55431", "city" : "BLOOMINGTON", "loc" : [ -93.31232199999999, 44.827776 ], "pop" : 19428, "state" : "MN" }
+{ "_id" : "55432", "city" : "FRIDLEY", "loc" : [ -93.253905, 45.095695 ], "pop" : 31132, "state" : "MN" }
+{ "_id" : "55433", "city" : "COON RAPIDS", "loc" : [ -93.32625299999999, 45.168192 ], "pop" : 27580, "state" : "MN" }
+{ "_id" : "55434", "city" : "BLAINE", "loc" : [ -93.24255700000001, 45.168083 ], "pop" : 33410, "state" : "MN" }
+{ "_id" : "55435", "city" : "EDINA", "loc" : [ -93.37145200000001, 44.877143 ], "pop" : 8926, "state" : "MN" }
+{ "_id" : "55436", "city" : "EDINA", "loc" : [ -93.370997, 44.902305 ], "pop" : 11750, "state" : "MN" }
+{ "_id" : "55437", "city" : "BLOOMINGTON", "loc" : [ -93.34349899999999, 44.823279 ], "pop" : 19472, "state" : "MN" }
+{ "_id" : "55438", "city" : "BLOOMINGTON", "loc" : [ -93.38014099999999, 44.823924 ], "pop" : 16896, "state" : "MN" }
+{ "_id" : "55439", "city" : "EDINA", "loc" : [ -93.33216899999999, 44.873716 ], "pop" : 10571, "state" : "MN" }
+{ "_id" : "55441", "city" : "PLYMOUTH", "loc" : [ -93.422782, 45.009836 ], "pop" : 16840, "state" : "MN" }
+{ "_id" : "55442", "city" : "PLYMOUTH", "loc" : [ -93.426316, 45.045151 ], "pop" : 9893, "state" : "MN" }
+{ "_id" : "55443", "city" : "BROOKLYN CENTER", "loc" : [ -93.34018399999999, 45.105586 ], "pop" : 20896, "state" : "MN" }
+{ "_id" : "55444", "city" : "BROOKLYN CENTER", "loc" : [ -93.30245499999999, 45.100172 ], "pop" : 12538, "state" : "MN" }
+{ "_id" : "55445", "city" : "BROOKLYN PARK", "loc" : [ -93.37349500000001, 45.103956 ], "pop" : 6398, "state" : "MN" }
+{ "_id" : "55446", "city" : "PLYMOUTH", "loc" : [ -93.472323, 45.032446 ], "pop" : 7704, "state" : "MN" }
+{ "_id" : "55447", "city" : "PLYMOUTH", "loc" : [ -93.49469499999999, 44.998593 ], "pop" : 16668, "state" : "MN" }
+{ "_id" : "55448", "city" : "COON RAPIDS", "loc" : [ -93.289699, 45.180626 ], "pop" : 25234, "state" : "MN" }
+{ "_id" : "55450", "city" : "MINNEAPOLIS", "loc" : [ -93.24741400000001, 44.865883 ], "pop" : 0, "state" : "MN" }
+{ "_id" : "55454", "city" : "MINNEAPOLIS", "loc" : [ -93.242898, 44.968161 ], "pop" : 8815, "state" : "MN" }
+{ "_id" : "55455", "city" : "MINNEAPOLIS", "loc" : [ -93.23927999999999, 44.981562 ], "pop" : 12216, "state" : "MN" }
+{ "_id" : "55599", "city" : "LORETTO", "loc" : [ -93.664534, 45.05604 ], "pop" : 541, "state" : "MN" }
+{ "_id" : "55602", "city" : "BRIMSON", "loc" : [ -91.862521, 47.314162 ], "pop" : 176, "state" : "MN" }
+{ "_id" : "55603", "city" : "FINLAND", "loc" : [ -91.209597, 47.419716 ], "pop" : 565, "state" : "MN" }
+{ "_id" : "55604", "city" : "GRAND MARAIS", "loc" : [ -90.339114, 47.77577 ], "pop" : 2404, "state" : "MN" }
+{ "_id" : "55605", "city" : "GRAND PORTAGE", "loc" : [ -89.69886200000001, 47.959065 ], "pop" : 350, "state" : "MN" }
+{ "_id" : "55606", "city" : "HOVLAND", "loc" : [ -90.04756999999999, 47.83415 ], "pop" : 218, "state" : "MN" }
+{ "_id" : "55607", "city" : "ISABELLA", "loc" : [ -91.51732699999999, 47.626719 ], "pop" : 402, "state" : "MN" }
+{ "_id" : "55612", "city" : "LUTSEN", "loc" : [ -90.638059, 47.683066 ], "pop" : 381, "state" : "MN" }
+{ "_id" : "55613", "city" : "SCHROEDER", "loc" : [ -90.933807, 47.542185 ], "pop" : 174, "state" : "MN" }
+{ "_id" : "55614", "city" : "LITTLE MARAIS", "loc" : [ -91.277753, 47.299905 ], "pop" : 2552, "state" : "MN" }
+{ "_id" : "55615", "city" : "TOFTE", "loc" : [ -90.783135, 47.760792 ], "pop" : 341, "state" : "MN" }
+{ "_id" : "55616", "city" : "TWO HARBORS", "loc" : [ -91.678264, 47.039364 ], "pop" : 6511, "state" : "MN" }
+{ "_id" : "55702", "city" : "ALBORN", "loc" : [ -92.557937, 46.978229 ], "pop" : 601, "state" : "MN" }
+{ "_id" : "55703", "city" : "ANGORA", "loc" : [ -92.64133200000001, 47.757738 ], "pop" : 291, "state" : "MN" }
+{ "_id" : "55704", "city" : "ASKOV", "loc" : [ -92.75281200000001, 46.196408 ], "pop" : 919, "state" : "MN" }
+{ "_id" : "55705", "city" : "AURORA", "loc" : [ -92.24148599999999, 47.495096 ], "pop" : 3674, "state" : "MN" }
+{ "_id" : "55706", "city" : "BABBITT", "loc" : [ -91.956951, 47.709121 ], "pop" : 2014, "state" : "MN" }
+{ "_id" : "55707", "city" : "BARNUM", "loc" : [ -92.629167, 46.519616 ], "pop" : 2028, "state" : "MN" }
+{ "_id" : "55709", "city" : "BOVEY", "loc" : [ -93.372322, 47.286788 ], "pop" : 5077, "state" : "MN" }
+{ "_id" : "55710", "city" : "BRITT", "loc" : [ -92.632062, 47.65496 ], "pop" : 1229, "state" : "MN" }
+{ "_id" : "55711", "city" : "BROOKSTON", "loc" : [ -92.643005, 46.838425 ], "pop" : 621, "state" : "MN" }
+{ "_id" : "55712", "city" : "BRUNO", "loc" : [ -92.618994, 46.284496 ], "pop" : 259, "state" : "MN" }
+{ "_id" : "55717", "city" : "CANYON", "loc" : [ -92.459361, 47.078525 ], "pop" : 230, "state" : "MN" }
+{ "_id" : "55718", "city" : "CARLTON", "loc" : [ -92.470984, 46.6484 ], "pop" : 3401, "state" : "MN" }
+{ "_id" : "55719", "city" : "CHISHOLM", "loc" : [ -92.861693, 47.500744 ], "pop" : 7412, "state" : "MN" }
+{ "_id" : "55720", "city" : "CLOQUET", "loc" : [ -92.45282, 46.726041 ], "pop" : 13503, "state" : "MN" }
+{ "_id" : "55721", "city" : "COHASSET", "loc" : [ -93.639154, 47.269112 ], "pop" : 3694, "state" : "MN" }
+{ "_id" : "55723", "city" : "COOK", "loc" : [ -92.72103799999999, 47.844193 ], "pop" : 2705, "state" : "MN" }
+{ "_id" : "55724", "city" : "KELSEY", "loc" : [ -92.44492099999999, 47.163803 ], "pop" : 430, "state" : "MN" }
+{ "_id" : "55725", "city" : "CRANE LAKE", "loc" : [ -92.48959600000001, 48.259387 ], "pop" : 74, "state" : "MN" }
+{ "_id" : "55726", "city" : "CROMWELL", "loc" : [ -92.873942, 46.671784 ], "pop" : 1048, "state" : "MN" }
+{ "_id" : "55727", "city" : "CULVER", "loc" : [ -92.552403, 46.911886 ], "pop" : 309, "state" : "MN" }
+{ "_id" : "55731", "city" : "ELY", "loc" : [ -91.85704200000001, 47.903435 ], "pop" : 5685, "state" : "MN" }
+{ "_id" : "55732", "city" : "EMBARRASS", "loc" : [ -92.21011, 47.665847 ], "pop" : 1143, "state" : "MN" }
+{ "_id" : "55733", "city" : "ESKO", "loc" : [ -92.35691799999999, 46.712551 ], "pop" : 4102, "state" : "MN" }
+{ "_id" : "55734", "city" : "EVELETH", "loc" : [ -92.528037, 47.451047 ], "pop" : 6135, "state" : "MN" }
+{ "_id" : "55735", "city" : "FINLAYSON", "loc" : [ -92.938924, 46.212111 ], "pop" : 1264, "state" : "MN" }
+{ "_id" : "55736", "city" : "FLOODWOOD", "loc" : [ -92.91668199999999, 46.907589 ], "pop" : 1475, "state" : "MN" }
+{ "_id" : "55740", "city" : "GHEEN", "loc" : [ -92.906892, 47.946475 ], "pop" : 255, "state" : "MN" }
+{ "_id" : "55741", "city" : "GILBERT", "loc" : [ -92.40246399999999, 47.488487 ], "pop" : 4721, "state" : "MN" }
+{ "_id" : "55742", "city" : "GOODLAND", "loc" : [ -93.146914, 47.192426 ], "pop" : 437, "state" : "MN" }
+{ "_id" : "55744", "city" : "LA PRAIRIE", "loc" : [ -93.527672, 47.223472 ], "pop" : 18067, "state" : "MN" }
+{ "_id" : "55746", "city" : "HIBBING", "loc" : [ -92.935582, 47.4156 ], "pop" : 20816, "state" : "MN" }
+{ "_id" : "55748", "city" : "HILL CITY", "loc" : [ -93.599397, 46.996817 ], "pop" : 762, "state" : "MN" }
+{ "_id" : "55749", "city" : "HOLYOKE", "loc" : [ -92.374955, 46.466445 ], "pop" : 160, "state" : "MN" }
+{ "_id" : "55750", "city" : "HOYT LAKES", "loc" : [ -92.140046, 47.514957 ], "pop" : 2348, "state" : "MN" }
+{ "_id" : "55751", "city" : "IRON", "loc" : [ -92.619502, 47.411455 ], "pop" : 1210, "state" : "MN" }
+{ "_id" : "55752", "city" : "JACOBSON", "loc" : [ -93.306359, 46.977187 ], "pop" : 387, "state" : "MN" }
+{ "_id" : "55756", "city" : "KERRICK", "loc" : [ -92.578, 46.379151 ], "pop" : 487, "state" : "MN" }
+{ "_id" : "55757", "city" : "KETTLE RIVER", "loc" : [ -92.904746, 46.502899 ], "pop" : 1136, "state" : "MN" }
+{ "_id" : "55760", "city" : "MC GREGOR", "loc" : [ -93.29562, 46.686424 ], "pop" : 1897, "state" : "MN" }
+{ "_id" : "55762", "city" : "MAHTOWA", "loc" : [ -92.606505, 46.582588 ], "pop" : 833, "state" : "MN" }
+{ "_id" : "55763", "city" : "MAKINEN", "loc" : [ -92.344584, 47.341603 ], "pop" : 1028, "state" : "MN" }
+{ "_id" : "55765", "city" : "MEADOWLANDS", "loc" : [ -92.788357, 47.102064 ], "pop" : 1172, "state" : "MN" }
+{ "_id" : "55766", "city" : "MELRUDE", "loc" : [ -92.42644, 47.242318 ], "pop" : 121, "state" : "MN" }
+{ "_id" : "55767", "city" : "MOOSE LAKE", "loc" : [ -92.74664799999999, 46.44724 ], "pop" : 2699, "state" : "MN" }
+{ "_id" : "55768", "city" : "MOUNTAIN IRON", "loc" : [ -92.624274, 47.513336 ], "pop" : 1790, "state" : "MN" }
+{ "_id" : "55769", "city" : "NASHWAUK", "loc" : [ -93.216818, 47.42003 ], "pop" : 4058, "state" : "MN" }
+{ "_id" : "55771", "city" : "BUYCK", "loc" : [ -92.845555, 47.933881 ], "pop" : 1252, "state" : "MN" }
+{ "_id" : "55773", "city" : "PARKVILLE", "loc" : [ -92.584051, 47.510296 ], "pop" : 1787, "state" : "MN" }
+{ "_id" : "55775", "city" : "PENGILLY", "loc" : [ -93.193667, 47.315089 ], "pop" : 1173, "state" : "MN" }
+{ "_id" : "55779", "city" : "SAGINAW", "loc" : [ -92.391723, 46.879462 ], "pop" : 3185, "state" : "MN" }
+{ "_id" : "55780", "city" : "SAWYER", "loc" : [ -92.609612, 46.711799 ], "pop" : 833, "state" : "MN" }
+{ "_id" : "55783", "city" : "STURGEON LAKE", "loc" : [ -92.818246, 46.383685 ], "pop" : 1883, "state" : "MN" }
+{ "_id" : "55784", "city" : "SWAN RIVER", "loc" : [ -93.19643600000001, 47.07394 ], "pop" : 231, "state" : "MN" }
+{ "_id" : "55785", "city" : "SWATARA", "loc" : [ -93.66848299999999, 46.929871 ], "pop" : 331, "state" : "MN" }
+{ "_id" : "55787", "city" : "TAMARACK", "loc" : [ -93.13420000000001, 46.617873 ], "pop" : 559, "state" : "MN" }
+{ "_id" : "55788", "city" : "TOGO", "loc" : [ -93.201545, 47.76843 ], "pop" : 632, "state" : "MN" }
+{ "_id" : "55790", "city" : "TOWER", "loc" : [ -92.287781, 47.808926 ], "pop" : 2280, "state" : "MN" }
+{ "_id" : "55792", "city" : "VIRGINIA", "loc" : [ -92.528525, 47.537078 ], "pop" : 11153, "state" : "MN" }
+{ "_id" : "55793", "city" : "WARBA", "loc" : [ -93.276417, 47.13611 ], "pop" : 431, "state" : "MN" }
+{ "_id" : "55795", "city" : "WILLOW RIVER", "loc" : [ -92.83093100000001, 46.294883 ], "pop" : 968, "state" : "MN" }
+{ "_id" : "55797", "city" : "WRENSHALL", "loc" : [ -92.37177200000001, 46.592114 ], "pop" : 839, "state" : "MN" }
+{ "_id" : "55798", "city" : "WRIGHT", "loc" : [ -93.002863, 46.675324 ], "pop" : 417, "state" : "MN" }
+{ "_id" : "55799", "city" : "ZIM", "loc" : [ -92.629606, 47.317591 ], "pop" : 507, "state" : "MN" }
+{ "_id" : "55801", "city" : "DULUTH", "loc" : [ -91.84673100000001, 47.094431 ], "pop" : 230, "state" : "MN" }
+{ "_id" : "55802", "city" : "DULUTH", "loc" : [ -92.08649699999999, 46.768475 ], "pop" : 2639, "state" : "MN" }
+{ "_id" : "55803", "city" : "DULUTH", "loc" : [ -92.09405700000001, 46.874913 ], "pop" : 14740, "state" : "MN" }
+{ "_id" : "55804", "city" : "DULUTH", "loc" : [ -92.00743300000001, 46.855131 ], "pop" : 14207, "state" : "MN" }
+{ "_id" : "55805", "city" : "DULUTH", "loc" : [ -92.094553, 46.798733 ], "pop" : 10849, "state" : "MN" }
+{ "_id" : "55806", "city" : "DULUTH", "loc" : [ -92.127871, 46.771457 ], "pop" : 9723, "state" : "MN" }
+{ "_id" : "55807", "city" : "DULUTH", "loc" : [ -92.169821, 46.740783 ], "pop" : 10257, "state" : "MN" }
+{ "_id" : "55808", "city" : "DULUTH", "loc" : [ -92.22261, 46.681002 ], "pop" : 5903, "state" : "MN" }
+{ "_id" : "55810", "city" : "PROCTOR", "loc" : [ -92.232332, 46.74459 ], "pop" : 6881, "state" : "MN" }
+{ "_id" : "55811", "city" : "HERMANTOWN", "loc" : [ -92.16822500000001, 46.81341 ], "pop" : 23478, "state" : "MN" }
+{ "_id" : "55812", "city" : "DULUTH", "loc" : [ -92.07669300000001, 46.810598 ], "pop" : 10296, "state" : "MN" }
+{ "_id" : "55901", "city" : "ROCHESTER", "loc" : [ -92.48962, 44.049572 ], "pop" : 33744, "state" : "MN" }
+{ "_id" : "55902", "city" : "ROCHESTER", "loc" : [ -92.483519, 44.003217 ], "pop" : 13594, "state" : "MN" }
+{ "_id" : "55904", "city" : "ROCHESTER", "loc" : [ -92.39727600000001, 44.010545 ], "pop" : 7854, "state" : "MN" }
+{ "_id" : "55906", "city" : "ROCHESTER", "loc" : [ -92.44687399999999, 44.021001 ], "pop" : 29174, "state" : "MN" }
+{ "_id" : "55909", "city" : "ADAMS", "loc" : [ -92.73049399999999, 43.559119 ], "pop" : 1214, "state" : "MN" }
+{ "_id" : "55910", "city" : "ALTURA", "loc" : [ -91.974474, 44.136114 ], "pop" : 2913, "state" : "MN" }
+{ "_id" : "55912", "city" : "AUSTIN", "loc" : [ -92.978374, 43.669538 ], "pop" : 25655, "state" : "MN" }
+{ "_id" : "55917", "city" : "BLOOMING PRAIRIE", "loc" : [ -93.06081, 43.897732 ], "pop" : 3922, "state" : "MN" }
+{ "_id" : "55918", "city" : "BROWNSDALE", "loc" : [ -92.873752, 43.724761 ], "pop" : 1443, "state" : "MN" }
+{ "_id" : "55919", "city" : "BROWNSVILLE", "loc" : [ -91.301226, 43.670732 ], "pop" : 995, "state" : "MN" }
+{ "_id" : "55920", "city" : "BYRON", "loc" : [ -92.630753, 44.037333 ], "pop" : 7129, "state" : "MN" }
+{ "_id" : "55921", "city" : "CALEDONIA", "loc" : [ -91.48365699999999, 43.622079 ], "pop" : 5049, "state" : "MN" }
+{ "_id" : "55922", "city" : "CANTON", "loc" : [ -91.91295700000001, 43.566687 ], "pop" : 1390, "state" : "MN" }
+{ "_id" : "55923", "city" : "CHATFIELD", "loc" : [ -92.15735100000001, 43.836201 ], "pop" : 3949, "state" : "MN" }
+{ "_id" : "55924", "city" : "CLAREMONT", "loc" : [ -92.988839, 44.05223 ], "pop" : 979, "state" : "MN" }
+{ "_id" : "55925", "city" : "DAKOTA", "loc" : [ -91.39404, 43.914806 ], "pop" : 725, "state" : "MN" }
+{ "_id" : "55926", "city" : "DEXTER", "loc" : [ -92.726764, 43.715962 ], "pop" : 588, "state" : "MN" }
+{ "_id" : "55927", "city" : "DODGE CENTER", "loc" : [ -92.85537600000001, 44.032514 ], "pop" : 3319, "state" : "MN" }
+{ "_id" : "55929", "city" : "DOVER", "loc" : [ -92.14151099999999, 44.001457 ], "pop" : 1265, "state" : "MN" }
+{ "_id" : "55932", "city" : "ELGIN", "loc" : [ -92.25349300000001, 44.135837 ], "pop" : 1494, "state" : "MN" }
+{ "_id" : "55933", "city" : "ELKTON", "loc" : [ -92.710407, 43.634806 ], "pop" : 721, "state" : "MN" }
+{ "_id" : "55934", "city" : "VIOLA", "loc" : [ -92.244068, 44.004294 ], "pop" : 2579, "state" : "MN" }
+{ "_id" : "55935", "city" : "FOUNTAIN", "loc" : [ -92.14228799999999, 43.728404 ], "pop" : 662, "state" : "MN" }
+{ "_id" : "55936", "city" : "GRAND MEADOW", "loc" : [ -92.569203, 43.710065 ], "pop" : 1653, "state" : "MN" }
+{ "_id" : "55937", "city" : "GRANGER", "loc" : [ -92.156115, 43.544873 ], "pop" : 385, "state" : "MN" }
+{ "_id" : "55939", "city" : "HARMONY", "loc" : [ -92.014511, 43.566268 ], "pop" : 1853, "state" : "MN" }
+{ "_id" : "55940", "city" : "HAYFIELD", "loc" : [ -92.81748899999999, 43.892259 ], "pop" : 2254, "state" : "MN" }
+{ "_id" : "55941", "city" : "HOKAH", "loc" : [ -91.345472, 43.750856 ], "pop" : 1289, "state" : "MN" }
+{ "_id" : "55943", "city" : "HOUSTON", "loc" : [ -91.56256500000001, 43.792904 ], "pop" : 3337, "state" : "MN" }
+{ "_id" : "55944", "city" : "KASSON", "loc" : [ -92.74642, 44.024029 ], "pop" : 4420, "state" : "MN" }
+{ "_id" : "55945", "city" : "THEILMAN", "loc" : [ -92.00839000000001, 44.305396 ], "pop" : 738, "state" : "MN" }
+{ "_id" : "55946", "city" : "KENYON", "loc" : [ -93.019661, 44.255237 ], "pop" : 3437, "state" : "MN" }
+{ "_id" : "55947", "city" : "LA CRESCENT", "loc" : [ -91.326325, 43.830686 ], "pop" : 6700, "state" : "MN" }
+{ "_id" : "55949", "city" : "LANESBORO", "loc" : [ -91.987719, 43.717447 ], "pop" : 1191, "state" : "MN" }
+{ "_id" : "55951", "city" : "LE ROY", "loc" : [ -92.50646399999999, 43.531533 ], "pop" : 1478, "state" : "MN" }
+{ "_id" : "55952", "city" : "LEWISTON", "loc" : [ -91.866162, 43.970193 ], "pop" : 2038, "state" : "MN" }
+{ "_id" : "55953", "city" : "LYLE", "loc" : [ -92.932818, 43.530868 ], "pop" : 1314, "state" : "MN" }
+{ "_id" : "55954", "city" : "MABEL", "loc" : [ -91.780636, 43.544611 ], "pop" : 1470, "state" : "MN" }
+{ "_id" : "55955", "city" : "MANTORVILLE", "loc" : [ -92.75796200000001, 44.070195 ], "pop" : 1324, "state" : "MN" }
+{ "_id" : "55956", "city" : "MAZEPPA", "loc" : [ -92.52068300000001, 44.264568 ], "pop" : 1560, "state" : "MN" }
+{ "_id" : "55957", "city" : "MILLVILLE", "loc" : [ -92.267188, 44.235862 ], "pop" : 579, "state" : "MN" }
+{ "_id" : "55959", "city" : "MINNESOTA CITY", "loc" : [ -91.74180800000001, 44.083222 ], "pop" : 1185, "state" : "MN" }
+{ "_id" : "55960", "city" : "ORONOCO", "loc" : [ -92.48496, 44.148861 ], "pop" : 3319, "state" : "MN" }
+{ "_id" : "55961", "city" : "OSTRANDER", "loc" : [ -92.415744, 43.597188 ], "pop" : 654, "state" : "MN" }
+{ "_id" : "55962", "city" : "PETERSON", "loc" : [ -91.84433799999999, 43.77691 ], "pop" : 901, "state" : "MN" }
+{ "_id" : "55963", "city" : "PINE ISLAND", "loc" : [ -92.66134700000001, 44.211009 ], "pop" : 3832, "state" : "MN" }
+{ "_id" : "55964", "city" : "PLAINVIEW", "loc" : [ -92.162125, 44.16373 ], "pop" : 3303, "state" : "MN" }
+{ "_id" : "55965", "city" : "PRESTON", "loc" : [ -92.096039, 43.664132 ], "pop" : 1866, "state" : "MN" }
+{ "_id" : "55967", "city" : "RACINE", "loc" : [ -92.531013, 43.78997 ], "pop" : 1107, "state" : "MN" }
+{ "_id" : "55969", "city" : "ROLLINGSTONE", "loc" : [ -91.81579499999999, 44.102501 ], "pop" : 1085, "state" : "MN" }
+{ "_id" : "55970", "city" : "ROSE CREEK", "loc" : [ -92.862082, 43.627423 ], "pop" : 952, "state" : "MN" }
+{ "_id" : "55971", "city" : "RUSHFORD", "loc" : [ -91.75364999999999, 43.821626 ], "pop" : 2809, "state" : "MN" }
+{ "_id" : "55972", "city" : "SAINT CHARLES", "loc" : [ -92.051738, 43.958481 ], "pop" : 3704, "state" : "MN" }
+{ "_id" : "55973", "city" : "SARGEANT", "loc" : [ -92.759517, 43.808976 ], "pop" : 349, "state" : "MN" }
+{ "_id" : "55974", "city" : "SPRING GROVE", "loc" : [ -91.636788, 43.562339 ], "pop" : 2333, "state" : "MN" }
+{ "_id" : "55975", "city" : "SPRING VALLEY", "loc" : [ -92.367985, 43.682288 ], "pop" : 4506, "state" : "MN" }
+{ "_id" : "55976", "city" : "STEWARTVILLE", "loc" : [ -92.454654, 43.867345 ], "pop" : 6847, "state" : "MN" }
+{ "_id" : "55977", "city" : "TAOPI", "loc" : [ -92.633455, 43.545783 ], "pop" : 350, "state" : "MN" }
+{ "_id" : "55978", "city" : "THEILMAN", "loc" : [ -92.211579, 44.30278 ], "pop" : 402, "state" : "MN" }
+{ "_id" : "55979", "city" : "UTICA", "loc" : [ -91.941737, 43.958727 ], "pop" : 599, "state" : "MN" }
+{ "_id" : "55981", "city" : "WABASHA", "loc" : [ -92.036058, 44.370273 ], "pop" : 3743, "state" : "MN" }
+{ "_id" : "55982", "city" : "WALTHAM", "loc" : [ -92.873446, 43.806958 ], "pop" : 561, "state" : "MN" }
+{ "_id" : "55983", "city" : "WANAMINGO", "loc" : [ -92.810258, 44.31214 ], "pop" : 1319, "state" : "MN" }
+{ "_id" : "55985", "city" : "WEST CONCORD", "loc" : [ -92.88249500000001, 44.151954 ], "pop" : 2040, "state" : "MN" }
+{ "_id" : "55986", "city" : "WHALAN", "loc" : [ -91.918863, 43.716528 ], "pop" : 269, "state" : "MN" }
+{ "_id" : "55987", "city" : "GOODVIEW", "loc" : [ -91.65334799999999, 44.039132 ], "pop" : 34518, "state" : "MN" }
+{ "_id" : "55990", "city" : "WYKOFF", "loc" : [ -92.267921, 43.71464 ], "pop" : 954, "state" : "MN" }
+{ "_id" : "55991", "city" : "HAMMOND", "loc" : [ -92.40396699999999, 44.248812 ], "pop" : 1720, "state" : "MN" }
+{ "_id" : "55992", "city" : "ZUMBROTA", "loc" : [ -92.671863, 44.303179 ], "pop" : 3535, "state" : "MN" }
+{ "_id" : "56001", "city" : "MANKATO", "loc" : [ -93.996044, 44.153809 ], "pop" : 38417, "state" : "MN" }
+{ "_id" : "56003", "city" : "NORTH MANKATO", "loc" : [ -94.031476, 44.177541 ], "pop" : 11629, "state" : "MN" }
+{ "_id" : "56007", "city" : "ALBERT LEA", "loc" : [ -93.370672, 43.653678 ], "pop" : 21186, "state" : "MN" }
+{ "_id" : "56009", "city" : "ALDEN", "loc" : [ -93.582307, 43.646586 ], "pop" : 1660, "state" : "MN" }
+{ "_id" : "56010", "city" : "AMBOY", "loc" : [ -94.177353, 43.890326 ], "pop" : 1449, "state" : "MN" }
+{ "_id" : "56011", "city" : "BELLE PLAINE", "loc" : [ -93.76039400000001, 44.613852 ], "pop" : 4623, "state" : "MN" }
+{ "_id" : "56013", "city" : "BLUE EARTH", "loc" : [ -94.09237899999999, 43.639426 ], "pop" : 5090, "state" : "MN" }
+{ "_id" : "56014", "city" : "BRICELYN", "loc" : [ -93.82108100000001, 43.574628 ], "pop" : 912, "state" : "MN" }
+{ "_id" : "56016", "city" : "CLARKS GROVE", "loc" : [ -93.323222, 43.762971 ], "pop" : 956, "state" : "MN" }
+{ "_id" : "56017", "city" : "CLEVELAND", "loc" : [ -93.828622, 44.32014 ], "pop" : 1258, "state" : "MN" }
+{ "_id" : "56019", "city" : "COMFREY", "loc" : [ -94.91345, 44.111069 ], "pop" : 981, "state" : "MN" }
+{ "_id" : "56020", "city" : "CONGER", "loc" : [ -93.522358, 43.611417 ], "pop" : 277, "state" : "MN" }
+{ "_id" : "56021", "city" : "COURTLAND", "loc" : [ -94.348229, 44.279083 ], "pop" : 1122, "state" : "MN" }
+{ "_id" : "56022", "city" : "DARFUR", "loc" : [ -94.813416, 44.061034 ], "pop" : 331, "state" : "MN" }
+{ "_id" : "56023", "city" : "DELAVAN", "loc" : [ -94.022488, 43.771859 ], "pop" : 310, "state" : "MN" }
+{ "_id" : "56024", "city" : "EAGLE LAKE", "loc" : [ -93.87191199999999, 44.154587 ], "pop" : 2218, "state" : "MN" }
+{ "_id" : "56025", "city" : "EASTON", "loc" : [ -93.933994, 43.758126 ], "pop" : 793, "state" : "MN" }
+{ "_id" : "56026", "city" : "ELLENDALE", "loc" : [ -93.319492, 43.882591 ], "pop" : 1051, "state" : "MN" }
+{ "_id" : "56027", "city" : "ELMORE", "loc" : [ -94.09836799999999, 43.520065 ], "pop" : 1125, "state" : "MN" }
+{ "_id" : "56028", "city" : "ELYSIAN", "loc" : [ -93.69649800000001, 44.22313 ], "pop" : 1303, "state" : "MN" }
+{ "_id" : "56029", "city" : "EMMONS", "loc" : [ -93.48244099999999, 43.508851 ], "pop" : 599, "state" : "MN" }
+{ "_id" : "56030", "city" : "ESSIG", "loc" : [ -94.56823, 44.323754 ], "pop" : 522, "state" : "MN" }
+{ "_id" : "56031", "city" : "FAIRMONT", "loc" : [ -94.45095000000001, 43.637592 ], "pop" : 12732, "state" : "MN" }
+{ "_id" : "56032", "city" : "FREEBORN", "loc" : [ -93.57454300000001, 43.784763 ], "pop" : 632, "state" : "MN" }
+{ "_id" : "56033", "city" : "FROST", "loc" : [ -93.936099, 43.563796 ], "pop" : 388, "state" : "MN" }
+{ "_id" : "56034", "city" : "GARDEN CITY", "loc" : [ -94.179084, 44.046748 ], "pop" : 460, "state" : "MN" }
+{ "_id" : "56035", "city" : "GENEVA", "loc" : [ -93.267096, 43.82354 ], "pop" : 524, "state" : "MN" }
+{ "_id" : "56036", "city" : "GLENVILLE", "loc" : [ -93.26176100000001, 43.557749 ], "pop" : 1254, "state" : "MN" }
+{ "_id" : "56037", "city" : "GOOD THUNDER", "loc" : [ -94.067662, 43.995187 ], "pop" : 941, "state" : "MN" }
+{ "_id" : "56039", "city" : "GRANADA", "loc" : [ -94.330731, 43.706082 ], "pop" : 681, "state" : "MN" }
+{ "_id" : "56041", "city" : "HANSKA", "loc" : [ -94.493267, 44.152678 ], "pop" : 1184, "state" : "MN" }
+{ "_id" : "56042", "city" : "HARTLAND", "loc" : [ -93.47695299999999, 43.803989 ], "pop" : 612, "state" : "MN" }
+{ "_id" : "56043", "city" : "HAYWARD", "loc" : [ -93.23772700000001, 43.63864 ], "pop" : 705, "state" : "MN" }
+{ "_id" : "56044", "city" : "HENDERSON", "loc" : [ -93.934487, 44.534398 ], "pop" : 1785, "state" : "MN" }
+{ "_id" : "56045", "city" : "HOLLANDALE", "loc" : [ -93.16798900000001, 43.752842 ], "pop" : 2346, "state" : "MN" }
+{ "_id" : "56046", "city" : "HOPE", "loc" : [ -93.345823, 43.979723 ], "pop" : 520, "state" : "MN" }
+{ "_id" : "56047", "city" : "HUNTLEY", "loc" : [ -94.201567, 43.723746 ], "pop" : 469, "state" : "MN" }
+{ "_id" : "56048", "city" : "JANESVILLE", "loc" : [ -93.709462, 44.116778 ], "pop" : 2996, "state" : "MN" }
+{ "_id" : "56050", "city" : "KASOTA", "loc" : [ -93.945319, 44.284188 ], "pop" : 1958, "state" : "MN" }
+{ "_id" : "56051", "city" : "KIESTER", "loc" : [ -93.71019099999999, 43.541445 ], "pop" : 923, "state" : "MN" }
+{ "_id" : "56052", "city" : "KILKENNY", "loc" : [ -93.516397, 44.318532 ], "pop" : 1249, "state" : "MN" }
+{ "_id" : "56054", "city" : "LAFAYETTE", "loc" : [ -94.436463, 44.407315 ], "pop" : 2268, "state" : "MN" }
+{ "_id" : "56055", "city" : "LAKE CRYSTAL", "loc" : [ -94.218385, 44.120189 ], "pop" : 3350, "state" : "MN" }
+{ "_id" : "56057", "city" : "LE CENTER", "loc" : [ -93.721428, 44.385348 ], "pop" : 3284, "state" : "MN" }
+{ "_id" : "56058", "city" : "LE SUEUR", "loc" : [ -93.885588, 44.458154 ], "pop" : 5491, "state" : "MN" }
+{ "_id" : "56060", "city" : "LEWISVILLE", "loc" : [ -94.428854, 43.920922 ], "pop" : 568, "state" : "MN" }
+{ "_id" : "56061", "city" : "LONDON", "loc" : [ -93.116527, 43.543455 ], "pop" : 437, "state" : "MN" }
+{ "_id" : "56062", "city" : "MADELIA", "loc" : [ -94.410994, 44.049949 ], "pop" : 3012, "state" : "MN" }
+{ "_id" : "56063", "city" : "MADISON LAKE", "loc" : [ -93.82889299999999, 44.222074 ], "pop" : 2135, "state" : "MN" }
+{ "_id" : "56064", "city" : "MANCHESTER", "loc" : [ -93.46065400000001, 43.716762 ], "pop" : 552, "state" : "MN" }
+{ "_id" : "56065", "city" : "MAPLETON", "loc" : [ -93.954247, 43.933065 ], "pop" : 2299, "state" : "MN" }
+{ "_id" : "56067", "city" : "MERIDEN", "loc" : [ -93.351167, 44.069875 ], "pop" : 693, "state" : "MN" }
+{ "_id" : "56068", "city" : "MINNESOTA LAKE", "loc" : [ -93.82820100000001, 43.829465 ], "pop" : 944, "state" : "MN" }
+{ "_id" : "56069", "city" : "MONTGOMERY", "loc" : [ -93.581024, 44.435591 ], "pop" : 3026, "state" : "MN" }
+{ "_id" : "56071", "city" : "NEW PRAGUE", "loc" : [ -93.580473, 44.540239 ], "pop" : 6601, "state" : "MN" }
+{ "_id" : "56072", "city" : "NEW RICHLAND", "loc" : [ -93.49954099999999, 43.893724 ], "pop" : 1964, "state" : "MN" }
+{ "_id" : "56073", "city" : "NEW ULM", "loc" : [ -94.464421, 44.304378 ], "pop" : 15142, "state" : "MN" }
+{ "_id" : "56074", "city" : "NICOLLET", "loc" : [ -94.186701, 44.272373 ], "pop" : 1654, "state" : "MN" }
+{ "_id" : "56075", "city" : "NORTHROP", "loc" : [ -94.43495, 43.721164 ], "pop" : 724, "state" : "MN" }
+{ "_id" : "56076", "city" : "OAKLAND", "loc" : [ -93.11132499999999, 43.632981 ], "pop" : 394, "state" : "MN" }
+{ "_id" : "56077", "city" : "OTISCO", "loc" : [ -93.474097, 43.981513 ], "pop" : 623, "state" : "MN" }
+{ "_id" : "56078", "city" : "PEMBERTON", "loc" : [ -93.818449, 43.959955 ], "pop" : 880, "state" : "MN" }
+{ "_id" : "56080", "city" : "SAINT CLAIR", "loc" : [ -93.844932, 44.077775 ], "pop" : 1083, "state" : "MN" }
+{ "_id" : "56081", "city" : "SAINT JAMES", "loc" : [ -94.622935, 43.987519 ], "pop" : 6472, "state" : "MN" }
+{ "_id" : "56082", "city" : "SAINT PETER", "loc" : [ -93.981061, 44.335107 ], "pop" : 11277, "state" : "MN" }
+{ "_id" : "56083", "city" : "SANBORN", "loc" : [ -95.13279300000001, 44.218291 ], "pop" : 1030, "state" : "MN" }
+{ "_id" : "56085", "city" : "SLEEPY EYE", "loc" : [ -94.727251, 44.282089 ], "pop" : 6092, "state" : "MN" }
+{ "_id" : "56087", "city" : "SPRINGFIELD", "loc" : [ -94.979204, 44.232905 ], "pop" : 2915, "state" : "MN" }
+{ "_id" : "56088", "city" : "TRUMAN", "loc" : [ -94.431862, 43.820008 ], "pop" : 2319, "state" : "MN" }
+{ "_id" : "56089", "city" : "TWIN LAKES", "loc" : [ -93.388667, 43.553951 ], "pop" : 926, "state" : "MN" }
+{ "_id" : "56090", "city" : "VERNON CENTER", "loc" : [ -94.214212, 43.970557 ], "pop" : 942, "state" : "MN" }
+{ "_id" : "56091", "city" : "WALDORF", "loc" : [ -93.70426399999999, 43.939868 ], "pop" : 962, "state" : "MN" }
+{ "_id" : "56092", "city" : "WALTERS", "loc" : [ -93.70102, 43.623868 ], "pop" : 400, "state" : "MN" }
+{ "_id" : "56093", "city" : "WASECA", "loc" : [ -93.510828, 44.0834 ], "pop" : 11534, "state" : "MN" }
+{ "_id" : "56096", "city" : "WATERVILLE", "loc" : [ -93.575063, 44.223796 ], "pop" : 2390, "state" : "MN" }
+{ "_id" : "56097", "city" : "WELLS", "loc" : [ -93.732069, 43.743396 ], "pop" : 3585, "state" : "MN" }
+{ "_id" : "56098", "city" : "WINNEBAGO", "loc" : [ -94.16324, 43.77549 ], "pop" : 1998, "state" : "MN" }
+{ "_id" : "56101", "city" : "WILDER", "loc" : [ -95.15153100000001, 43.879022 ], "pop" : 6224, "state" : "MN" }
+{ "_id" : "56110", "city" : "ADRIAN", "loc" : [ -95.927261, 43.619683 ], "pop" : 1899, "state" : "MN" }
+{ "_id" : "56111", "city" : "ALPHA", "loc" : [ -94.90508800000001, 43.594594 ], "pop" : 674, "state" : "MN" }
+{ "_id" : "56112", "city" : "AMIRET", "loc" : [ -95.71904600000001, 44.325134 ], "pop" : 556, "state" : "MN" }
+{ "_id" : "56113", "city" : "ARCO", "loc" : [ -96.199913, 44.409147 ], "pop" : 515, "state" : "MN" }
+{ "_id" : "56114", "city" : "AVOCA", "loc" : [ -95.60015199999999, 43.970553 ], "pop" : 572, "state" : "MN" }
+{ "_id" : "56115", "city" : "BALATON", "loc" : [ -95.88377, 44.225253 ], "pop" : 1305, "state" : "MN" }
+{ "_id" : "56116", "city" : "BEAVER CREEK", "loc" : [ -96.369771, 43.622343 ], "pop" : 694, "state" : "MN" }
+{ "_id" : "56117", "city" : "BIGELOW", "loc" : [ -95.651527, 43.533612 ], "pop" : 633, "state" : "MN" }
+{ "_id" : "56118", "city" : "BINGHAM LAKE", "loc" : [ -95.04571, 43.894155 ], "pop" : 432, "state" : "MN" }
+{ "_id" : "56119", "city" : "BREWSTER", "loc" : [ -95.480676, 43.703223 ], "pop" : 800, "state" : "MN" }
+{ "_id" : "56120", "city" : "BUTTERFIELD", "loc" : [ -94.795627, 43.965417 ], "pop" : 894, "state" : "MN" }
+{ "_id" : "56121", "city" : "CEYLON", "loc" : [ -94.614908, 43.538243 ], "pop" : 1051, "state" : "MN" }
+{ "_id" : "56122", "city" : "CHANDLER", "loc" : [ -95.929616, 43.916308 ], "pop" : 808, "state" : "MN" }
+{ "_id" : "56123", "city" : "CURRIE", "loc" : [ -95.695323, 44.094616 ], "pop" : 1254, "state" : "MN" }
+{ "_id" : "56124", "city" : "DELFT", "loc" : [ -95.047234, 43.978502 ], "pop" : 363, "state" : "MN" }
+{ "_id" : "56125", "city" : "DOVRAY", "loc" : [ -95.52708199999999, 44.05967 ], "pop" : 277, "state" : "MN" }
+{ "_id" : "56126", "city" : "DUNDEE", "loc" : [ -95.499286, 43.819052 ], "pop" : 414, "state" : "MN" }
+{ "_id" : "56127", "city" : "DUNNELL", "loc" : [ -94.787558, 43.553052 ], "pop" : 452, "state" : "MN" }
+{ "_id" : "56128", "city" : "EDGERTON", "loc" : [ -96.146333, 43.882419 ], "pop" : 2045, "state" : "MN" }
+{ "_id" : "56129", "city" : "ELLSWORTH", "loc" : [ -96.01124799999999, 43.526539 ], "pop" : 852, "state" : "MN" }
+{ "_id" : "56131", "city" : "FULDA", "loc" : [ -95.597937, 43.875298 ], "pop" : 1792, "state" : "MN" }
+{ "_id" : "56132", "city" : "GARVIN", "loc" : [ -95.76721499999999, 44.229318 ], "pop" : 471, "state" : "MN" }
+{ "_id" : "56133", "city" : "HADLEY", "loc" : [ -95.86902499999999, 44.03105 ], "pop" : 429, "state" : "MN" }
+{ "_id" : "56134", "city" : "HARDWICK", "loc" : [ -96.21607, 43.791072 ], "pop" : 461, "state" : "MN" }
+{ "_id" : "56136", "city" : "HENDRICKS", "loc" : [ -96.407753, 44.499514 ], "pop" : 1305, "state" : "MN" }
+{ "_id" : "56137", "city" : "HERON LAKE", "loc" : [ -95.326736, 43.79788 ], "pop" : 1190, "state" : "MN" }
+{ "_id" : "56138", "city" : "HILLS", "loc" : [ -96.364527, 43.533548 ], "pop" : 1072, "state" : "MN" }
+{ "_id" : "56139", "city" : "HOLLAND", "loc" : [ -96.19027699999999, 44.075904 ], "pop" : 682, "state" : "MN" }
+{ "_id" : "56141", "city" : "IONA", "loc" : [ -95.77176900000001, 43.902631 ], "pop" : 434, "state" : "MN" }
+{ "_id" : "56142", "city" : "IVANHOE", "loc" : [ -96.22605900000001, 44.507119 ], "pop" : 1683, "state" : "MN" }
+{ "_id" : "56143", "city" : "JACKSON", "loc" : [ -94.993827, 43.645732 ], "pop" : 5119, "state" : "MN" }
+{ "_id" : "56144", "city" : "JASPER", "loc" : [ -96.385035, 43.856827 ], "pop" : 1220, "state" : "MN" }
+{ "_id" : "56145", "city" : "JEFFERS", "loc" : [ -95.154664, 44.073678 ], "pop" : 1000, "state" : "MN" }
+{ "_id" : "56146", "city" : "KANARANZI", "loc" : [ -96.111306, 43.54979 ], "pop" : 320, "state" : "MN" }
+{ "_id" : "56147", "city" : "KENNETH", "loc" : [ -96.10886000000001, 43.763738 ], "pop" : 523, "state" : "MN" }
+{ "_id" : "56149", "city" : "LAKE BENTON", "loc" : [ -96.29103499999999, 44.278211 ], "pop" : 1323, "state" : "MN" }
+{ "_id" : "56150", "city" : "LAKEFIELD", "loc" : [ -95.184834, 43.654456 ], "pop" : 3233, "state" : "MN" }
+{ "_id" : "56151", "city" : "LAKE WILSON", "loc" : [ -95.97973, 44.009529 ], "pop" : 749, "state" : "MN" }
+{ "_id" : "56152", "city" : "LAMBERTON", "loc" : [ -95.273946, 44.237776 ], "pop" : 1736, "state" : "MN" }
+{ "_id" : "56153", "city" : "LEOTA", "loc" : [ -96.005392, 43.822628 ], "pop" : 504, "state" : "MN" }
+{ "_id" : "56155", "city" : "LISMORE", "loc" : [ -95.96817799999999, 43.733857 ], "pop" : 494, "state" : "MN" }
+{ "_id" : "56156", "city" : "LUVERNE", "loc" : [ -96.22156200000001, 43.661366 ], "pop" : 5436, "state" : "MN" }
+{ "_id" : "56157", "city" : "LYND", "loc" : [ -95.923284, 44.40322 ], "pop" : 1005, "state" : "MN" }
+{ "_id" : "56158", "city" : "MAGNOLIA", "loc" : [ -96.100825, 43.638211 ], "pop" : 458, "state" : "MN" }
+{ "_id" : "56159", "city" : "MOUNTAIN LAKE", "loc" : [ -94.927313, 43.938998 ], "pop" : 2506, "state" : "MN" }
+{ "_id" : "56160", "city" : "ODIN", "loc" : [ -94.77401999999999, 43.882402 ], "pop" : 382, "state" : "MN" }
+{ "_id" : "56161", "city" : "OKABENA", "loc" : [ -95.338112, 43.72302 ], "pop" : 606, "state" : "MN" }
+{ "_id" : "56162", "city" : "ORMSBY", "loc" : [ -94.68725499999999, 43.861639 ], "pop" : 221, "state" : "MN" }
+{ "_id" : "56164", "city" : "HATFIELD", "loc" : [ -96.322762, 44.009516 ], "pop" : 5923, "state" : "MN" }
+{ "_id" : "56165", "city" : "READING", "loc" : [ -95.738945, 43.713604 ], "pop" : 400, "state" : "MN" }
+{ "_id" : "56166", "city" : "REVERE", "loc" : [ -95.39958799999999, 44.271326 ], "pop" : 459, "state" : "MN" }
+{ "_id" : "56167", "city" : "ROUND LAKE", "loc" : [ -95.45015100000001, 43.562045 ], "pop" : 1236, "state" : "MN" }
+{ "_id" : "56168", "city" : "RUSHMORE", "loc" : [ -95.77672800000001, 43.624011 ], "pop" : 726, "state" : "MN" }
+{ "_id" : "56169", "city" : "RUSSELL", "loc" : [ -95.942564, 44.320129 ], "pop" : 781, "state" : "MN" }
+{ "_id" : "56170", "city" : "FLORENCE", "loc" : [ -96.07902799999999, 44.163836 ], "pop" : 737, "state" : "MN" }
+{ "_id" : "56171", "city" : "SHERBURN", "loc" : [ -94.726877, 43.661089 ], "pop" : 2275, "state" : "MN" }
+{ "_id" : "56172", "city" : "SLAYTON", "loc" : [ -95.755448, 43.985596 ], "pop" : 2535, "state" : "MN" }
+{ "_id" : "56173", "city" : "STEEN", "loc" : [ -96.24386800000001, 43.531728 ], "pop" : 526, "state" : "MN" }
+{ "_id" : "56174", "city" : "STORDEN", "loc" : [ -95.30192599999999, 44.052383 ], "pop" : 537, "state" : "MN" }
+{ "_id" : "56175", "city" : "TRACY", "loc" : [ -95.621301, 44.234201 ], "pop" : 2390, "state" : "MN" }
+{ "_id" : "56176", "city" : "TRIMONT", "loc" : [ -94.71863, 43.782702 ], "pop" : 1349, "state" : "MN" }
+{ "_id" : "56178", "city" : "TYLER", "loc" : [ -96.130235, 44.277342 ], "pop" : 1940, "state" : "MN" }
+{ "_id" : "56179", "city" : "VERDI", "loc" : [ -96.372429, 44.234078 ], "pop" : 234, "state" : "MN" }
+{ "_id" : "56180", "city" : "WALNUT GROVE", "loc" : [ -95.49645099999999, 44.229375 ], "pop" : 1277, "state" : "MN" }
+{ "_id" : "56181", "city" : "WELCOME", "loc" : [ -94.588593, 43.67052 ], "pop" : 1435, "state" : "MN" }
+{ "_id" : "56183", "city" : "WESTBROOK", "loc" : [ -95.423208, 44.065381 ], "pop" : 1362, "state" : "MN" }
+{ "_id" : "56185", "city" : "WILMONT", "loc" : [ -95.832421, 43.7692 ], "pop" : 1101, "state" : "MN" }
+{ "_id" : "56186", "city" : "WOODSTOCK", "loc" : [ -96.119198, 43.987338 ], "pop" : 451, "state" : "MN" }
+{ "_id" : "56187", "city" : "WORTHINGTON", "loc" : [ -95.605907, 43.628626 ], "pop" : 11556, "state" : "MN" }
+{ "_id" : "56201", "city" : "WILLMAR", "loc" : [ -95.05231499999999, 45.139264 ], "pop" : 22069, "state" : "MN" }
+{ "_id" : "56207", "city" : "ALBERTA", "loc" : [ -96.049772, 45.557086 ], "pop" : 296, "state" : "MN" }
+{ "_id" : "56208", "city" : "APPLETON", "loc" : [ -95.994872, 45.20543 ], "pop" : 2294, "state" : "MN" }
+{ "_id" : "56209", "city" : "ATWATER", "loc" : [ -94.793779, 45.111645 ], "pop" : 1841, "state" : "MN" }
+{ "_id" : "56210", "city" : "BARRY", "loc" : [ -96.56052699999999, 45.547446 ], "pop" : 135, "state" : "MN" }
+{ "_id" : "56211", "city" : "BEARDSLEY", "loc" : [ -96.706013, 45.553855 ], "pop" : 494, "state" : "MN" }
+{ "_id" : "56212", "city" : "BELLINGHAM", "loc" : [ -96.32235, 45.155626 ], "pop" : 715, "state" : "MN" }
+{ "_id" : "56214", "city" : "BELVIEW", "loc" : [ -95.317757, 44.605486 ], "pop" : 750, "state" : "MN" }
+{ "_id" : "56215", "city" : "BENSON", "loc" : [ -95.576644, 45.312904 ], "pop" : 5107, "state" : "MN" }
+{ "_id" : "56216", "city" : "SVEA", "loc" : [ -95.06395500000001, 44.939512 ], "pop" : 668, "state" : "MN" }
+{ "_id" : "56218", "city" : "BOYD", "loc" : [ -95.94210200000001, 44.850725 ], "pop" : 668, "state" : "MN" }
+{ "_id" : "56219", "city" : "BROWNS VALLEY", "loc" : [ -96.80625000000001, 45.606934 ], "pop" : 1128, "state" : "MN" }
+{ "_id" : "56220", "city" : "CANBY", "loc" : [ -96.27839400000001, 44.720187 ], "pop" : 3043, "state" : "MN" }
+{ "_id" : "56221", "city" : "CHOKIO", "loc" : [ -96.17331, 45.552369 ], "pop" : 785, "state" : "MN" }
+{ "_id" : "56222", "city" : "CLARA CITY", "loc" : [ -95.349902, 44.963912 ], "pop" : 1879, "state" : "MN" }
+{ "_id" : "56223", "city" : "CLARKFIELD", "loc" : [ -95.830405, 44.774261 ], "pop" : 1623, "state" : "MN" }
+{ "_id" : "56224", "city" : "CLEMENTS", "loc" : [ -95.04744700000001, 44.39432 ], "pop" : 398, "state" : "MN" }
+{ "_id" : "56225", "city" : "CLINTON", "loc" : [ -96.418161, 45.457659 ], "pop" : 843, "state" : "MN" }
+{ "_id" : "56226", "city" : "CLONTARF", "loc" : [ -95.678629, 45.373418 ], "pop" : 279, "state" : "MN" }
+{ "_id" : "56227", "city" : "CORRELL", "loc" : [ -96.17526599999999, 45.290742 ], "pop" : 397, "state" : "MN" }
+{ "_id" : "56228", "city" : "COSMOS", "loc" : [ -94.697827, 44.958969 ], "pop" : 1217, "state" : "MN" }
+{ "_id" : "56229", "city" : "COTTONWOOD", "loc" : [ -95.692508, 44.600251 ], "pop" : 1552, "state" : "MN" }
+{ "_id" : "56230", "city" : "DANUBE", "loc" : [ -95.078366, 44.795567 ], "pop" : 1179, "state" : "MN" }
+{ "_id" : "56231", "city" : "DANVERS", "loc" : [ -95.886194, 45.341853 ], "pop" : 710, "state" : "MN" }
+{ "_id" : "56232", "city" : "DAWSON", "loc" : [ -96.01501399999999, 44.931737 ], "pop" : 2496, "state" : "MN" }
+{ "_id" : "56233", "city" : "DE GRAFF", "loc" : [ -95.44658800000001, 45.270845 ], "pop" : 336, "state" : "MN" }
+{ "_id" : "56235", "city" : "DONNELLY", "loc" : [ -96.064937, 45.70137 ], "pop" : 526, "state" : "MN" }
+{ "_id" : "56236", "city" : "DUMONT", "loc" : [ -96.40612299999999, 45.671742 ], "pop" : 727, "state" : "MN" }
+{ "_id" : "56237", "city" : "ECHO", "loc" : [ -95.418223, 44.631046 ], "pop" : 797, "state" : "MN" }
+{ "_id" : "56238", "city" : "EVAN", "loc" : [ -94.816956, 44.351114 ], "pop" : 222, "state" : "MN" }
+{ "_id" : "56239", "city" : "GHENT", "loc" : [ -95.893642, 44.507843 ], "pop" : 661, "state" : "MN" }
+{ "_id" : "56240", "city" : "GRACEVILLE", "loc" : [ -96.420925, 45.560248 ], "pop" : 1019, "state" : "MN" }
+{ "_id" : "56241", "city" : "GRANITE FALLS", "loc" : [ -95.551557, 44.808749 ], "pop" : 4051, "state" : "MN" }
+{ "_id" : "56243", "city" : "GROVE CITY", "loc" : [ -94.687843, 45.153172 ], "pop" : 1428, "state" : "MN" }
+{ "_id" : "56244", "city" : "HANCOCK", "loc" : [ -95.800775, 45.498464 ], "pop" : 1255, "state" : "MN" }
+{ "_id" : "56245", "city" : "HANLEY FALLS", "loc" : [ -95.682492, 44.678862 ], "pop" : 652, "state" : "MN" }
+{ "_id" : "56246", "city" : "HAWICK", "loc" : [ -94.820762, 45.361775 ], "pop" : 536, "state" : "MN" }
+{ "_id" : "56247", "city" : "HAZEL RUN", "loc" : [ -95.712187, 44.749688 ], "pop" : 328, "state" : "MN" }
+{ "_id" : "56248", "city" : "HERMAN", "loc" : [ -96.099188, 45.807104 ], "pop" : 928, "state" : "MN" }
+{ "_id" : "56249", "city" : "HOLLOWAY", "loc" : [ -95.916374, 45.270805 ], "pop" : 283, "state" : "MN" }
+{ "_id" : "56250", "city" : "JOHNSON", "loc" : [ -96.266277, 45.573007 ], "pop" : 12, "state" : "MN" }
+{ "_id" : "56251", "city" : "KANDIYOHI", "loc" : [ -94.94727399999999, 45.123162 ], "pop" : 1169, "state" : "MN" }
+{ "_id" : "56252", "city" : "KERKHOVEN", "loc" : [ -95.311465, 45.209626 ], "pop" : 1267, "state" : "MN" }
+{ "_id" : "56253", "city" : "LAKE LILLIAN", "loc" : [ -94.901443, 44.96603 ], "pop" : 1106, "state" : "MN" }
+{ "_id" : "56254", "city" : "LOUISBURG", "loc" : [ -96.171539, 45.130556 ], "pop" : 307, "state" : "MN" }
+{ "_id" : "56255", "city" : "LUCAN", "loc" : [ -95.411934, 44.413237 ], "pop" : 487, "state" : "MN" }
+{ "_id" : "56256", "city" : "MADISON", "loc" : [ -96.164507, 44.994618 ], "pop" : 3857, "state" : "MN" }
+{ "_id" : "56257", "city" : "MARIETTA", "loc" : [ -96.409448, 44.963582 ], "pop" : 588, "state" : "MN" }
+{ "_id" : "56258", "city" : "MARSHALL", "loc" : [ -95.779454, 44.448127 ], "pop" : 13489, "state" : "MN" }
+{ "_id" : "56260", "city" : "MAYNARD", "loc" : [ -95.48450800000001, 44.922615 ], "pop" : 1004, "state" : "MN" }
+{ "_id" : "56262", "city" : "MILAN", "loc" : [ -95.869045, 45.114317 ], "pop" : 864, "state" : "MN" }
+{ "_id" : "56263", "city" : "MILROY", "loc" : [ -95.55447100000001, 44.436494 ], "pop" : 907, "state" : "MN" }
+{ "_id" : "56264", "city" : "MINNEOTA", "loc" : [ -95.976714, 44.558732 ], "pop" : 2056, "state" : "MN" }
+{ "_id" : "56265", "city" : "MONTEVIDEO", "loc" : [ -95.676473, 44.968829 ], "pop" : 8405, "state" : "MN" }
+{ "_id" : "56266", "city" : "MORGAN", "loc" : [ -94.921783, 44.392554 ], "pop" : 2257, "state" : "MN" }
+{ "_id" : "56267", "city" : "MORRIS", "loc" : [ -95.91723399999999, 45.592095 ], "pop" : 7772, "state" : "MN" }
+{ "_id" : "56270", "city" : "MORTON", "loc" : [ -95.02681699999999, 44.566189 ], "pop" : 962, "state" : "MN" }
+{ "_id" : "56271", "city" : "MURDOCK", "loc" : [ -95.40489700000001, 45.216147 ], "pop" : 448, "state" : "MN" }
+{ "_id" : "56272", "city" : "NASSAU", "loc" : [ -96.413307, 45.107554 ], "pop" : 293, "state" : "MN" }
+{ "_id" : "56273", "city" : "NEW LONDON", "loc" : [ -94.948008, 45.294936 ], "pop" : 4077, "state" : "MN" }
+{ "_id" : "56274", "city" : "NORCROSS", "loc" : [ -96.134168, 45.885839 ], "pop" : 303, "state" : "MN" }
+{ "_id" : "56276", "city" : "ODESSA", "loc" : [ -96.310154, 45.299766 ], "pop" : 457, "state" : "MN" }
+{ "_id" : "56277", "city" : "OLIVIA", "loc" : [ -94.972747, 44.770627 ], "pop" : 3829, "state" : "MN" }
+{ "_id" : "56278", "city" : "ORTONVILLE", "loc" : [ -96.45965, 45.329621 ], "pop" : 2928, "state" : "MN" }
+{ "_id" : "56279", "city" : "PENNOCK", "loc" : [ -95.17533299999999, 45.131031 ], "pop" : 915, "state" : "MN" }
+{ "_id" : "56280", "city" : "PORTER", "loc" : [ -96.15812, 44.656532 ], "pop" : 425, "state" : "MN" }
+{ "_id" : "56281", "city" : "PRINSBURG", "loc" : [ -95.18653999999999, 44.937088 ], "pop" : 931, "state" : "MN" }
+{ "_id" : "56282", "city" : "RAYMOND", "loc" : [ -95.220788, 45.018097 ], "pop" : 1095, "state" : "MN" }
+{ "_id" : "56283", "city" : "DELHI", "loc" : [ -95.10713, 44.531753 ], "pop" : 6705, "state" : "MN" }
+{ "_id" : "56284", "city" : "RENVILLE", "loc" : [ -95.19887900000001, 44.777609 ], "pop" : 2027, "state" : "MN" }
+{ "_id" : "56285", "city" : "SACRED HEART", "loc" : [ -95.353801, 44.797536 ], "pop" : 1725, "state" : "MN" }
+{ "_id" : "56286", "city" : "SAINT LEO", "loc" : [ -96.042546, 44.711091 ], "pop" : 483, "state" : "MN" }
+{ "_id" : "56287", "city" : "SEAFORTH", "loc" : [ -95.297768, 44.490536 ], "pop" : 327, "state" : "MN" }
+{ "_id" : "56288", "city" : "SPICER", "loc" : [ -94.91157200000001, 45.224112 ], "pop" : 3440, "state" : "MN" }
+{ "_id" : "56289", "city" : "SUNBURG", "loc" : [ -95.204915, 45.358316 ], "pop" : 408, "state" : "MN" }
+{ "_id" : "56291", "city" : "TAUNTON", "loc" : [ -96.052594, 44.595076 ], "pop" : 349, "state" : "MN" }
+{ "_id" : "56292", "city" : "VESTA", "loc" : [ -95.411801, 44.505052 ], "pop" : 525, "state" : "MN" }
+{ "_id" : "56293", "city" : "WABASSO", "loc" : [ -95.2632, 44.405865 ], "pop" : 991, "state" : "MN" }
+{ "_id" : "56294", "city" : "WANDA", "loc" : [ -95.178, 44.32295 ], "pop" : 401, "state" : "MN" }
+{ "_id" : "56295", "city" : "WATSON", "loc" : [ -95.794203, 45.019443 ], "pop" : 436, "state" : "MN" }
+{ "_id" : "56296", "city" : "WHEATON", "loc" : [ -96.486598, 45.811104 ], "pop" : 2338, "state" : "MN" }
+{ "_id" : "56297", "city" : "WOOD LAKE", "loc" : [ -95.540908, 44.637915 ], "pop" : 922, "state" : "MN" }
+{ "_id" : "56301", "city" : "SAINT CLOUD", "loc" : [ -94.18185699999999, 45.540972 ], "pop" : 36182, "state" : "MN" }
+{ "_id" : "56303", "city" : "SAINT CLOUD", "loc" : [ -94.20363399999999, 45.571298 ], "pop" : 14039, "state" : "MN" }
+{ "_id" : "56304", "city" : "SAINT CLOUD", "loc" : [ -94.12844699999999, 45.552113 ], "pop" : 13570, "state" : "MN" }
+{ "_id" : "56307", "city" : "ALBANY", "loc" : [ -94.574022, 45.615114 ], "pop" : 3064, "state" : "MN" }
+{ "_id" : "56308", "city" : "ALEXANDRIA", "loc" : [ -95.38199400000001, 45.881747 ], "pop" : 17548, "state" : "MN" }
+{ "_id" : "56309", "city" : "ASHBY", "loc" : [ -95.821417, 46.078066 ], "pop" : 869, "state" : "MN" }
+{ "_id" : "56310", "city" : "AVON", "loc" : [ -94.436029, 45.612168 ], "pop" : 4355, "state" : "MN" }
+{ "_id" : "56311", "city" : "BARRETT", "loc" : [ -95.87539099999999, 45.899555 ], "pop" : 799, "state" : "MN" }
+{ "_id" : "56312", "city" : "BELGRADE", "loc" : [ -94.969877, 45.486522 ], "pop" : 1661, "state" : "MN" }
+{ "_id" : "56313", "city" : "BOCK", "loc" : [ -93.553658, 45.784427 ], "pop" : 115, "state" : "MN" }
+{ "_id" : "56314", "city" : "BOWLUS", "loc" : [ -94.41753300000001, 45.81212 ], "pop" : 1183, "state" : "MN" }
+{ "_id" : "56315", "city" : "BRANDON", "loc" : [ -95.57876899999999, 46.0039 ], "pop" : 1453, "state" : "MN" }
+{ "_id" : "56316", "city" : "BROOTEN", "loc" : [ -95.09004899999999, 45.493171 ], "pop" : 1287, "state" : "MN" }
+{ "_id" : "56318", "city" : "BURTRUM", "loc" : [ -94.696214, 45.88803 ], "pop" : 854, "state" : "MN" }
+{ "_id" : "56319", "city" : "CARLOS", "loc" : [ -95.310468, 45.972572 ], "pop" : 2136, "state" : "MN" }
+{ "_id" : "56320", "city" : "COLD SPRING", "loc" : [ -94.43782299999999, 45.449976 ], "pop" : 5162, "state" : "MN" }
+{ "_id" : "56323", "city" : "CYRUS", "loc" : [ -95.706965, 45.569483 ], "pop" : 988, "state" : "MN" }
+{ "_id" : "56324", "city" : "DALTON", "loc" : [ -95.85001699999999, 46.154414 ], "pop" : 1305, "state" : "MN" }
+{ "_id" : "56326", "city" : "EVANSVILLE", "loc" : [ -95.69506699999999, 46.01525 ], "pop" : 1149, "state" : "MN" }
+{ "_id" : "56327", "city" : "FARWELL", "loc" : [ -95.665583, 45.724424 ], "pop" : 394, "state" : "MN" }
+{ "_id" : "56328", "city" : "FLENSBURG", "loc" : [ -94.530767, 45.950899 ], "pop" : 213, "state" : "MN" }
+{ "_id" : "56329", "city" : "FOLEY", "loc" : [ -93.868459, 45.708687 ], "pop" : 4078, "state" : "MN" }
+{ "_id" : "56330", "city" : "FORESTON", "loc" : [ -93.69575500000001, 45.702842 ], "pop" : 1353, "state" : "MN" }
+{ "_id" : "56331", "city" : "FREEPORT", "loc" : [ -94.678529, 45.673146 ], "pop" : 3865, "state" : "MN" }
+{ "_id" : "56332", "city" : "GARFIELD", "loc" : [ -95.45004400000001, 45.995309 ], "pop" : 1430, "state" : "MN" }
+{ "_id" : "56333", "city" : "GILMAN", "loc" : [ -93.946876, 45.774178 ], "pop" : 945, "state" : "MN" }
+{ "_id" : "56334", "city" : "GLENWOOD", "loc" : [ -95.38681, 45.642911 ], "pop" : 5272, "state" : "MN" }
+{ "_id" : "56336", "city" : "GREY EAGLE", "loc" : [ -94.832075, 45.81069 ], "pop" : 2188, "state" : "MN" }
+{ "_id" : "56338", "city" : "HILLMAN", "loc" : [ -93.881224, 46.06776 ], "pop" : 724, "state" : "MN" }
+{ "_id" : "56339", "city" : "HOFFMAN", "loc" : [ -95.79548200000001, 45.823292 ], "pop" : 852, "state" : "MN" }
+{ "_id" : "56340", "city" : "HOLDINGFORD", "loc" : [ -94.458091, 45.724924 ], "pop" : 1721, "state" : "MN" }
+{ "_id" : "56341", "city" : "HOLMES CITY", "loc" : [ -95.56464, 45.810706 ], "pop" : 614, "state" : "MN" }
+{ "_id" : "56342", "city" : "ISLE", "loc" : [ -93.474062, 46.169605 ], "pop" : 1109, "state" : "MN" }
+{ "_id" : "56343", "city" : "KENSINGTON", "loc" : [ -95.694452, 45.81761 ], "pop" : 770, "state" : "MN" }
+{ "_id" : "56345", "city" : "LITTLE FALLS", "loc" : [ -94.360428, 45.98108 ], "pop" : 13558, "state" : "MN" }
+{ "_id" : "56347", "city" : "LITTLE SAUK", "loc" : [ -94.89838899999999, 45.962417 ], "pop" : 6436, "state" : "MN" }
+{ "_id" : "56349", "city" : "LOWRY", "loc" : [ -95.53221000000001, 45.710469 ], "pop" : 429, "state" : "MN" }
+{ "_id" : "56350", "city" : "MC GRATH", "loc" : [ -93.241619, 46.244116 ], "pop" : 933, "state" : "MN" }
+{ "_id" : "56352", "city" : "MELROSE", "loc" : [ -94.819768, 45.658183 ], "pop" : 4739, "state" : "MN" }
+{ "_id" : "56353", "city" : "MILACA", "loc" : [ -93.64526600000001, 45.779481 ], "pop" : 4927, "state" : "MN" }
+{ "_id" : "56354", "city" : "MILTONA", "loc" : [ -95.325767, 46.054519 ], "pop" : 866, "state" : "MN" }
+{ "_id" : "56355", "city" : "NELSON", "loc" : [ -95.226032, 45.8516 ], "pop" : 858, "state" : "MN" }
+{ "_id" : "56357", "city" : "OAK PARK", "loc" : [ -93.92141700000001, 45.671403 ], "pop" : 2636, "state" : "MN" }
+{ "_id" : "56358", "city" : "OGILVIE", "loc" : [ -93.43592099999999, 45.847632 ], "pop" : 1143, "state" : "MN" }
+{ "_id" : "56359", "city" : "ONAMIA", "loc" : [ -93.68668, 46.09022 ], "pop" : 3111, "state" : "MN" }
+{ "_id" : "56360", "city" : "OSAKIS", "loc" : [ -95.13317000000001, 45.876836 ], "pop" : 2099, "state" : "MN" }
+{ "_id" : "56361", "city" : "PARKERS PRAIRIE", "loc" : [ -95.360764, 46.176925 ], "pop" : 3067, "state" : "MN" }
+{ "_id" : "56362", "city" : "PAYNESVILLE", "loc" : [ -94.715709, 45.398798 ], "pop" : 4967, "state" : "MN" }
+{ "_id" : "56363", "city" : "PEASE", "loc" : [ -93.649247, 45.697872 ], "pop" : 178, "state" : "MN" }
+{ "_id" : "56364", "city" : "PIERZ", "loc" : [ -94.085306, 46.008059 ], "pop" : 4300, "state" : "MN" }
+{ "_id" : "56367", "city" : "RICE", "loc" : [ -94.165752, 45.736383 ], "pop" : 4560, "state" : "MN" }
+{ "_id" : "56368", "city" : "RICHMOND", "loc" : [ -94.546072, 45.423817 ], "pop" : 3718, "state" : "MN" }
+{ "_id" : "56373", "city" : "ROYALTON", "loc" : [ -94.221063, 45.858928 ], "pop" : 2571, "state" : "MN" }
+{ "_id" : "56374", "city" : "SAINT JOSEPH", "loc" : [ -94.336688, 45.565124 ], "pop" : 9480, "state" : "MN" }
+{ "_id" : "56375", "city" : "SAINT STEPHEN", "loc" : [ -94.281662, 45.711815 ], "pop" : 2868, "state" : "MN" }
+{ "_id" : "56377", "city" : "SARTELL", "loc" : [ -94.21356900000001, 45.631827 ], "pop" : 4966, "state" : "MN" }
+{ "_id" : "56378", "city" : "SAUK CENTRE", "loc" : [ -94.968166, 45.728079 ], "pop" : 6025, "state" : "MN" }
+{ "_id" : "56379", "city" : "SAUK RAPIDS", "loc" : [ -94.159088, 45.604032 ], "pop" : 12505, "state" : "MN" }
+{ "_id" : "56380", "city" : "SEDAN", "loc" : [ -95.263989, 45.51069 ], "pop" : 968, "state" : "MN" }
+{ "_id" : "56381", "city" : "STARBUCK", "loc" : [ -95.542125, 45.592587 ], "pop" : 1964, "state" : "MN" }
+{ "_id" : "56382", "city" : "SWANVILLE", "loc" : [ -94.62892100000001, 45.943148 ], "pop" : 1917, "state" : "MN" }
+{ "_id" : "56384", "city" : "UPSALA", "loc" : [ -94.575531, 45.809723 ], "pop" : 1001, "state" : "MN" }
+{ "_id" : "56385", "city" : "VILLARD", "loc" : [ -95.241439, 45.711823 ], "pop" : 730, "state" : "MN" }
+{ "_id" : "56386", "city" : "WAHKON", "loc" : [ -93.497174, 46.11214 ], "pop" : 656, "state" : "MN" }
+{ "_id" : "56387", "city" : "WAITE PARK", "loc" : [ -94.224481, 45.54972 ], "pop" : 5227, "state" : "MN" }
+{ "_id" : "56389", "city" : "WEST UNION", "loc" : [ -95.08328, 45.798451 ], "pop" : 54, "state" : "MN" }
+{ "_id" : "56401", "city" : "EAST GULL LAKE", "loc" : [ -94.20187300000001, 46.357219 ], "pop" : 23504, "state" : "MN" }
+{ "_id" : "56431", "city" : "AITKIN", "loc" : [ -93.645413, 46.479929 ], "pop" : 6388, "state" : "MN" }
+{ "_id" : "56433", "city" : "AKELEY", "loc" : [ -94.72342999999999, 47.000987 ], "pop" : 1097, "state" : "MN" }
+{ "_id" : "56434", "city" : "ALDRICH", "loc" : [ -94.992017, 46.402538 ], "pop" : 1105, "state" : "MN" }
+{ "_id" : "56435", "city" : "BACKUS", "loc" : [ -94.39591799999999, 46.869905 ], "pop" : 2594, "state" : "MN" }
+{ "_id" : "56437", "city" : "BERTHA", "loc" : [ -95.03573299999999, 46.251457 ], "pop" : 1365, "state" : "MN" }
+{ "_id" : "56438", "city" : "BROWERVILLE", "loc" : [ -94.834581, 46.090525 ], "pop" : 2179, "state" : "MN" }
+{ "_id" : "56440", "city" : "CLARISSA", "loc" : [ -94.95719, 46.137305 ], "pop" : 1222, "state" : "MN" }
+{ "_id" : "56441", "city" : "CROSBY", "loc" : [ -93.987448, 46.509084 ], "pop" : 5601, "state" : "MN" }
+{ "_id" : "56442", "city" : "CROSSLAKE", "loc" : [ -94.114256, 46.678644 ], "pop" : 1132, "state" : "MN" }
+{ "_id" : "56443", "city" : "CUSHING", "loc" : [ -94.618452, 46.202194 ], "pop" : 2122, "state" : "MN" }
+{ "_id" : "56444", "city" : "DEERWOOD", "loc" : [ -93.884863, 46.444571 ], "pop" : 2225, "state" : "MN" }
+{ "_id" : "56446", "city" : "EAGLE BEND", "loc" : [ -95.09606100000001, 46.117017 ], "pop" : 1714, "state" : "MN" }
+{ "_id" : "56447", "city" : "EMILY", "loc" : [ -93.948385, 46.747791 ], "pop" : 699, "state" : "MN" }
+{ "_id" : "56448", "city" : "FIFTY LAKES", "loc" : [ -94.065555, 46.746997 ], "pop" : 289, "state" : "MN" }
+{ "_id" : "56449", "city" : "FORT RIPLEY", "loc" : [ -94.252696, 46.20988 ], "pop" : 1377, "state" : "MN" }
+{ "_id" : "56450", "city" : "GARRISON", "loc" : [ -93.93634299999999, 46.263725 ], "pop" : 1771, "state" : "MN" }
+{ "_id" : "56452", "city" : "HACKENSACK", "loc" : [ -94.50332400000001, 46.988442 ], "pop" : 1382, "state" : "MN" }
+{ "_id" : "56453", "city" : "HEWITT", "loc" : [ -95.050361, 46.32497 ], "pop" : 1213, "state" : "MN" }
+{ "_id" : "56455", "city" : "IRONTON", "loc" : [ -94.043655, 46.464135 ], "pop" : 145, "state" : "MN" }
+{ "_id" : "56456", "city" : "JENKINS", "loc" : [ -94.33248500000001, 46.650983 ], "pop" : 262, "state" : "MN" }
+{ "_id" : "56458", "city" : "LAKE GEORGE", "loc" : [ -95.00214800000001, 47.214992 ], "pop" : 485, "state" : "MN" }
+{ "_id" : "56460", "city" : "LAKE ITASCA", "loc" : [ -95.252149, 47.275725 ], "pop" : 208, "state" : "MN" }
+{ "_id" : "56461", "city" : "LAPORTE", "loc" : [ -94.77716100000001, 47.236752 ], "pop" : 1624, "state" : "MN" }
+{ "_id" : "56463", "city" : "MANHATTAN BEACH", "loc" : [ -94.140068, 46.733563 ], "pop" : 71, "state" : "MN" }
+{ "_id" : "56464", "city" : "MENAHGA", "loc" : [ -95.07142899999999, 46.757233 ], "pop" : 1940, "state" : "MN" }
+{ "_id" : "56465", "city" : "MERRIFIELD", "loc" : [ -94.204268, 46.494309 ], "pop" : 1552, "state" : "MN" }
+{ "_id" : "56466", "city" : "LEADER", "loc" : [ -94.628086, 46.321568 ], "pop" : 943, "state" : "MN" }
+{ "_id" : "56467", "city" : "NEVIS", "loc" : [ -94.84600500000001, 46.931892 ], "pop" : 1252, "state" : "MN" }
+{ "_id" : "56468", "city" : "LAKE SHORE", "loc" : [ -94.29656199999999, 46.484828 ], "pop" : 2184, "state" : "MN" }
+{ "_id" : "56469", "city" : "PALISADE", "loc" : [ -93.562741, 46.689492 ], "pop" : 1168, "state" : "MN" }
+{ "_id" : "56470", "city" : "PARK RAPIDS", "loc" : [ -95.03829899999999, 46.937682 ], "pop" : 8074, "state" : "MN" }
+{ "_id" : "56472", "city" : "PEQUOT LAKES", "loc" : [ -94.26842600000001, 46.62569 ], "pop" : 3437, "state" : "MN" }
+{ "_id" : "56473", "city" : "PILLAGER", "loc" : [ -94.392287, 46.398395 ], "pop" : 3481, "state" : "MN" }
+{ "_id" : "56474", "city" : "PINE RIVER", "loc" : [ -94.44769100000001, 46.693796 ], "pop" : 4095, "state" : "MN" }
+{ "_id" : "56475", "city" : "RANDALL", "loc" : [ -94.50054299999999, 46.073361 ], "pop" : 1621, "state" : "MN" }
+{ "_id" : "56477", "city" : "SEBEKA", "loc" : [ -95.068055, 46.630615 ], "pop" : 3089, "state" : "MN" }
+{ "_id" : "56479", "city" : "STAPLES", "loc" : [ -94.763299, 46.353552 ], "pop" : 5352, "state" : "MN" }
+{ "_id" : "56481", "city" : "VERNDALE", "loc" : [ -94.853268, 46.426995 ], "pop" : 1899, "state" : "MN" }
+{ "_id" : "56482", "city" : "WADENA", "loc" : [ -95.128283, 46.440121 ], "pop" : 5818, "state" : "MN" }
+{ "_id" : "56484", "city" : "WALKER", "loc" : [ -94.584675, 47.08775 ], "pop" : 2431, "state" : "MN" }
+{ "_id" : "56485", "city" : "WHIPHOLT", "loc" : [ -94.35097399999999, 47.040953 ], "pop" : 138, "state" : "MN" }
+{ "_id" : "56501", "city" : "DETROIT LAKES", "loc" : [ -95.800606, 46.834877 ], "pop" : 15501, "state" : "MN" }
+{ "_id" : "56510", "city" : "LOCKHART", "loc" : [ -96.503569, 47.315597 ], "pop" : 2500, "state" : "MN" }
+{ "_id" : "56511", "city" : "AUDUBON", "loc" : [ -95.988136, 46.871887 ], "pop" : 1083, "state" : "MN" }
+{ "_id" : "56513", "city" : "BAKER", "loc" : [ -96.604955, 46.685764 ], "pop" : 267, "state" : "MN" }
+{ "_id" : "56514", "city" : "DOWNER", "loc" : [ -96.37269000000001, 46.677296 ], "pop" : 3357, "state" : "MN" }
+{ "_id" : "56515", "city" : "BATTLE LAKE", "loc" : [ -95.714395, 46.314175 ], "pop" : 2143, "state" : "MN" }
+{ "_id" : "56516", "city" : "BEJOU", "loc" : [ -95.94542300000001, 47.44909 ], "pop" : 358, "state" : "MN" }
+{ "_id" : "56517", "city" : "BELTRAMI", "loc" : [ -96.454864, 47.572118 ], "pop" : 517, "state" : "MN" }
+{ "_id" : "56518", "city" : "BLUFFTON", "loc" : [ -95.223592, 46.491795 ], "pop" : 623, "state" : "MN" }
+{ "_id" : "56519", "city" : "BORUP", "loc" : [ -96.552969, 47.189641 ], "pop" : 329, "state" : "MN" }
+{ "_id" : "56520", "city" : "BRECKENRIDGE", "loc" : [ -96.56222, 46.27966 ], "pop" : 4776, "state" : "MN" }
+{ "_id" : "56521", "city" : "CALLAWAY", "loc" : [ -95.94396399999999, 47.007642 ], "pop" : 761, "state" : "MN" }
+{ "_id" : "56522", "city" : "DORAN", "loc" : [ -96.437169, 46.129645 ], "pop" : 718, "state" : "MN" }
+{ "_id" : "56523", "city" : "ELDRED", "loc" : [ -96.80264699999999, 47.653011 ], "pop" : 731, "state" : "MN" }
+{ "_id" : "56524", "city" : "CLITHERALL", "loc" : [ -95.58582199999999, 46.31693 ], "pop" : 555, "state" : "MN" }
+{ "_id" : "56525", "city" : "COMSTOCK", "loc" : [ -96.739752, 46.666703 ], "pop" : 260, "state" : "MN" }
+{ "_id" : "56527", "city" : "DEER CREEK", "loc" : [ -95.26726499999999, 46.411193 ], "pop" : 1431, "state" : "MN" }
+{ "_id" : "56528", "city" : "DENT", "loc" : [ -95.764357, 46.555417 ], "pop" : 2064, "state" : "MN" }
+{ "_id" : "56529", "city" : "DILWORTH", "loc" : [ -96.70222, 46.878168 ], "pop" : 2546, "state" : "MN" }
+{ "_id" : "56531", "city" : "ELBOW LAKE", "loc" : [ -95.96714900000001, 45.995267 ], "pop" : 2087, "state" : "MN" }
+{ "_id" : "56533", "city" : "ELIZABETH", "loc" : [ -96.085093, 46.406218 ], "pop" : 738, "state" : "MN" }
+{ "_id" : "56534", "city" : "ERHARD", "loc" : [ -96.059264, 46.494817 ], "pop" : 846, "state" : "MN" }
+{ "_id" : "56535", "city" : "ERSKINE", "loc" : [ -96.012173, 47.661817 ], "pop" : 993, "state" : "MN" }
+{ "_id" : "56536", "city" : "FELTON", "loc" : [ -96.505225, 47.070528 ], "pop" : 431, "state" : "MN" }
+{ "_id" : "56537", "city" : "CARLISLE", "loc" : [ -96.06433800000001, 46.289723 ], "pop" : 18010, "state" : "MN" }
+{ "_id" : "56540", "city" : "FERTILE", "loc" : [ -96.237127, 47.521367 ], "pop" : 1933, "state" : "MN" }
+{ "_id" : "56542", "city" : "FOSSTON", "loc" : [ -95.743082, 47.581584 ], "pop" : 2469, "state" : "MN" }
+{ "_id" : "56543", "city" : "FOXHOME", "loc" : [ -96.31757899999999, 46.258366 ], "pop" : 309, "state" : "MN" }
+{ "_id" : "56544", "city" : "FRAZEE", "loc" : [ -95.521159, 46.756469 ], "pop" : 3166, "state" : "MN" }
+{ "_id" : "56545", "city" : "GARY", "loc" : [ -96.215233, 47.367491 ], "pop" : 518, "state" : "MN" }
+{ "_id" : "56546", "city" : "GEORGETOWN", "loc" : [ -96.726996, 47.099865 ], "pop" : 425, "state" : "MN" }
+{ "_id" : "56547", "city" : "GLYNDON", "loc" : [ -96.55833800000001, 46.882023 ], "pop" : 2198, "state" : "MN" }
+{ "_id" : "56548", "city" : "HALSTAD", "loc" : [ -96.79803800000001, 47.355114 ], "pop" : 898, "state" : "MN" }
+{ "_id" : "56549", "city" : "ROLLAG", "loc" : [ -96.31115, 46.884185 ], "pop" : 3105, "state" : "MN" }
+{ "_id" : "56550", "city" : "HENDRUM", "loc" : [ -96.79875, 47.26889 ], "pop" : 467, "state" : "MN" }
+{ "_id" : "56551", "city" : "HENNING", "loc" : [ -95.38516199999999, 46.325606 ], "pop" : 1770, "state" : "MN" }
+{ "_id" : "56552", "city" : "HITTERDAL", "loc" : [ -96.28883999999999, 47.001354 ], "pop" : 613, "state" : "MN" }
+{ "_id" : "56553", "city" : "KENT", "loc" : [ -96.685181, 46.437811 ], "pop" : 168, "state" : "MN" }
+{ "_id" : "56554", "city" : "LAKE PARK", "loc" : [ -96.067047, 46.817623 ], "pop" : 3001, "state" : "MN" }
+{ "_id" : "56556", "city" : "MCINTOSH", "loc" : [ -95.886252, 47.652165 ], "pop" : 1088, "state" : "MN" }
+{ "_id" : "56557", "city" : "MAHNOMEN", "loc" : [ -95.885609, 47.336155 ], "pop" : 2940, "state" : "MN" }
+{ "_id" : "56560", "city" : "MOORHEAD", "loc" : [ -96.75719700000001, 46.867748 ], "pop" : 35056, "state" : "MN" }
+{ "_id" : "56565", "city" : "NASHUA", "loc" : [ -96.31600899999999, 46.053731 ], "pop" : 153, "state" : "MN" }
+{ "_id" : "56566", "city" : "NAYTAHWAUSH", "loc" : [ -95.62832400000001, 47.26007 ], "pop" : 785, "state" : "MN" }
+{ "_id" : "56567", "city" : "NEW YORK MILLS", "loc" : [ -95.40471700000001, 46.555867 ], "pop" : 3681, "state" : "MN" }
+{ "_id" : "56568", "city" : "NIELSVILLE", "loc" : [ -96.75743300000001, 47.537336 ], "pop" : 299, "state" : "MN" }
+{ "_id" : "56569", "city" : "OGEMA", "loc" : [ -95.91512400000001, 47.102865 ], "pop" : 1129, "state" : "MN" }
+{ "_id" : "56570", "city" : "OSAGE", "loc" : [ -95.23528399999999, 46.932896 ], "pop" : 626, "state" : "MN" }
+{ "_id" : "56571", "city" : "OTTERTAIL", "loc" : [ -95.543571, 46.417722 ], "pop" : 1080, "state" : "MN" }
+{ "_id" : "56572", "city" : "PELICAN RAPIDS", "loc" : [ -96.066227, 46.599444 ], "pop" : 4481, "state" : "MN" }
+{ "_id" : "56573", "city" : "PERHAM", "loc" : [ -95.581763, 46.603106 ], "pop" : 3238, "state" : "MN" }
+{ "_id" : "56574", "city" : "PERLEY", "loc" : [ -96.777722, 47.18308 ], "pop" : 303, "state" : "MN" }
+{ "_id" : "56575", "city" : "PONSFORD", "loc" : [ -95.319717, 47.013348 ], "pop" : 1072, "state" : "MN" }
+{ "_id" : "56576", "city" : "RICHVILLE", "loc" : [ -95.59289099999999, 46.500807 ], "pop" : 898, "state" : "MN" }
+{ "_id" : "56577", "city" : "RICHWOOD", "loc" : [ -95.850094, 46.93609 ], "pop" : 594, "state" : "MN" }
+{ "_id" : "56578", "city" : "ROCHERT", "loc" : [ -95.600443, 46.855904 ], "pop" : 688, "state" : "MN" }
+{ "_id" : "56579", "city" : "ROTHSAY", "loc" : [ -96.288726, 46.509412 ], "pop" : 916, "state" : "MN" }
+{ "_id" : "56580", "city" : "SABIN", "loc" : [ -96.59851999999999, 46.770257 ], "pop" : 1225, "state" : "MN" }
+{ "_id" : "56581", "city" : "SHELLY", "loc" : [ -96.78380199999999, 47.455375 ], "pop" : 445, "state" : "MN" }
+{ "_id" : "56583", "city" : "TENNEY", "loc" : [ -96.387049, 45.990196 ], "pop" : 270, "state" : "MN" }
+{ "_id" : "56584", "city" : "TWIN VALLEY", "loc" : [ -96.246382, 47.250905 ], "pop" : 2108, "state" : "MN" }
+{ "_id" : "56585", "city" : "ULEN", "loc" : [ -96.28239000000001, 47.090263 ], "pop" : 939, "state" : "MN" }
+{ "_id" : "56586", "city" : "UNDERWOOD", "loc" : [ -95.84155, 46.32652 ], "pop" : 1932, "state" : "MN" }
+{ "_id" : "56587", "city" : "VERGAS", "loc" : [ -95.79481199999999, 46.670645 ], "pop" : 1338, "state" : "MN" }
+{ "_id" : "56588", "city" : "VINING", "loc" : [ -95.588263, 46.256135 ], "pop" : 463, "state" : "MN" }
+{ "_id" : "56589", "city" : "WAUBUN", "loc" : [ -95.887125, 47.192009 ], "pop" : 961, "state" : "MN" }
+{ "_id" : "56590", "city" : "WENDELL", "loc" : [ -96.114407, 46.056174 ], "pop" : 408, "state" : "MN" }
+{ "_id" : "56592", "city" : "WINGER", "loc" : [ -95.994085, 47.537516 ], "pop" : 406, "state" : "MN" }
+{ "_id" : "56593", "city" : "WOLF LAKE", "loc" : [ -95.36070599999999, 46.833417 ], "pop" : 260, "state" : "MN" }
+{ "_id" : "56594", "city" : "WOLVERTON", "loc" : [ -96.61487, 46.555017 ], "pop" : 834, "state" : "MN" }
+{ "_id" : "56601", "city" : "BEMIDJI", "loc" : [ -94.848809, 47.488071 ], "pop" : 25278, "state" : "MN" }
+{ "_id" : "56621", "city" : "BAGLEY", "loc" : [ -95.41334000000001, 47.487024 ], "pop" : 4063, "state" : "MN" }
+{ "_id" : "56623", "city" : "BAUDETTE", "loc" : [ -94.599479, 48.692724 ], "pop" : 2065, "state" : "MN" }
+{ "_id" : "56626", "city" : "BENA", "loc" : [ -94.251921, 47.347732 ], "pop" : 461, "state" : "MN" }
+{ "_id" : "56627", "city" : "BIG FALLS", "loc" : [ -93.729629, 48.156028 ], "pop" : 652, "state" : "MN" }
+{ "_id" : "56628", "city" : "BIGFORK", "loc" : [ -93.670699, 47.750227 ], "pop" : 819, "state" : "MN" }
+{ "_id" : "56629", "city" : "BIRCHDALE", "loc" : [ -94.167652, 48.624696 ], "pop" : 374, "state" : "MN" }
+{ "_id" : "56630", "city" : "BLACKDUCK", "loc" : [ -94.496072, 47.738136 ], "pop" : 1428, "state" : "MN" }
+{ "_id" : "56632", "city" : "BOY RIVER", "loc" : [ -94.102587, 47.181841 ], "pop" : 132, "state" : "MN" }
+{ "_id" : "56633", "city" : "CASS LAKE", "loc" : [ -94.611896, 47.35155 ], "pop" : 2866, "state" : "MN" }
+{ "_id" : "56634", "city" : "CLEARBROOK", "loc" : [ -95.375185, 47.714581 ], "pop" : 1208, "state" : "MN" }
+{ "_id" : "56636", "city" : "DEER RIVER", "loc" : [ -93.84979, 47.382867 ], "pop" : 3254, "state" : "MN" }
+{ "_id" : "56637", "city" : "TALMOON", "loc" : [ -93.774913, 47.588764 ], "pop" : 155, "state" : "MN" }
+{ "_id" : "56639", "city" : "EFFIE", "loc" : [ -93.579905, 47.847187 ], "pop" : 346, "state" : "MN" }
+{ "_id" : "56641", "city" : "FEDERAL DAM", "loc" : [ -94.257519, 47.206914 ], "pop" : 347, "state" : "MN" }
+{ "_id" : "56644", "city" : "GONVICK", "loc" : [ -95.499014, 47.749009 ], "pop" : 931, "state" : "MN" }
+{ "_id" : "56646", "city" : "GULLY", "loc" : [ -95.641034, 47.769745 ], "pop" : 511, "state" : "MN" }
+{ "_id" : "56647", "city" : "HINES", "loc" : [ -94.647666, 47.732429 ], "pop" : 1083, "state" : "MN" }
+{ "_id" : "56649", "city" : "INTERNATIONAL FA", "loc" : [ -93.40609000000001, 48.583398 ], "pop" : 11124, "state" : "MN" }
+{ "_id" : "56650", "city" : "KELLIHER", "loc" : [ -94.538166, 47.927173 ], "pop" : 1092, "state" : "MN" }
+{ "_id" : "56651", "city" : "LENGBY", "loc" : [ -95.627475, 47.536998 ], "pop" : 514, "state" : "MN" }
+{ "_id" : "56652", "city" : "LEONARD", "loc" : [ -95.37077499999999, 47.628905 ], "pop" : 1022, "state" : "MN" }
+{ "_id" : "56653", "city" : "LITTLEFORK", "loc" : [ -93.53993199999999, 48.385233 ], "pop" : 1769, "state" : "MN" }
+{ "_id" : "56654", "city" : "LOMAN", "loc" : [ -93.840673, 48.516406 ], "pop" : 198, "state" : "MN" }
+{ "_id" : "56655", "city" : "LONGVILLE", "loc" : [ -94.198182, 47.024842 ], "pop" : 757, "state" : "MN" }
+{ "_id" : "56657", "city" : "MARCELL", "loc" : [ -93.678425, 47.634527 ], "pop" : 449, "state" : "MN" }
+{ "_id" : "56659", "city" : "MAX", "loc" : [ -93.972031, 47.628919 ], "pop" : 140, "state" : "MN" }
+{ "_id" : "56660", "city" : "MIZPAH", "loc" : [ -94.146748, 47.949525 ], "pop" : 321, "state" : "MN" }
+{ "_id" : "56661", "city" : "NORTHOME", "loc" : [ -94.204274, 47.844039 ], "pop" : 908, "state" : "MN" }
+{ "_id" : "56662", "city" : "OUTING", "loc" : [ -93.94425200000001, 46.837528 ], "pop" : 348, "state" : "MN" }
+{ "_id" : "56663", "city" : "PENNINGTON", "loc" : [ -94.483361, 47.465121 ], "pop" : 176, "state" : "MN" }
+{ "_id" : "56665", "city" : "PITT", "loc" : [ -94.728252, 48.782986 ], "pop" : 678, "state" : "MN" }
+{ "_id" : "56666", "city" : "PONEMAH", "loc" : [ -94.91704799999999, 48.037168 ], "pop" : 790, "state" : "MN" }
+{ "_id" : "56667", "city" : "PUPOSKY", "loc" : [ -94.980294, 47.7436 ], "pop" : 967, "state" : "MN" }
+{ "_id" : "56668", "city" : "RANIER", "loc" : [ -93.31245699999999, 48.611847 ], "pop" : 1145, "state" : "MN" }
+{ "_id" : "56669", "city" : "RAY", "loc" : [ -93.08954900000001, 48.421834 ], "pop" : 365, "state" : "MN" }
+{ "_id" : "56670", "city" : "REDBY", "loc" : [ -94.940409, 47.868888 ], "pop" : 1394, "state" : "MN" }
+{ "_id" : "56671", "city" : "REDLAKE", "loc" : [ -95.06432, 47.865378 ], "pop" : 1358, "state" : "MN" }
+{ "_id" : "56672", "city" : "REMER", "loc" : [ -93.919647, 47.087422 ], "pop" : 1466, "state" : "MN" }
+{ "_id" : "56673", "city" : "ROOSEVELT", "loc" : [ -95.179389, 48.814807 ], "pop" : 907, "state" : "MN" }
+{ "_id" : "56674", "city" : "SAUM", "loc" : [ -94.651203, 47.974492 ], "pop" : 150, "state" : "MN" }
+{ "_id" : "56676", "city" : "SHEVLIN", "loc" : [ -95.24502099999999, 47.500364 ], "pop" : 879, "state" : "MN" }
+{ "_id" : "56678", "city" : "SOLWAY", "loc" : [ -95.120475, 47.547972 ], "pop" : 971, "state" : "MN" }
+{ "_id" : "56680", "city" : "SPRING LAKE", "loc" : [ -93.83821500000001, 47.588811 ], "pop" : 383, "state" : "MN" }
+{ "_id" : "56681", "city" : "SQUAW LAKE", "loc" : [ -94.14749999999999, 47.636162 ], "pop" : 337, "state" : "MN" }
+{ "_id" : "56682", "city" : "SWIFT", "loc" : [ -95.297499, 48.847573 ], "pop" : 789, "state" : "MN" }
+{ "_id" : "56683", "city" : "TENSTRIKE", "loc" : [ -94.68243200000001, 47.661146 ], "pop" : 184, "state" : "MN" }
+{ "_id" : "56684", "city" : "TRAIL", "loc" : [ -95.760668, 47.747769 ], "pop" : 353, "state" : "MN" }
+{ "_id" : "56685", "city" : "WASKISH", "loc" : [ -94.50370700000001, 48.176971 ], "pop" : 115, "state" : "MN" }
+{ "_id" : "56686", "city" : "WILLIAMS", "loc" : [ -94.955586, 48.802218 ], "pop" : 1257, "state" : "MN" }
+{ "_id" : "56687", "city" : "WILTON", "loc" : [ -94.986238, 47.535254 ], "pop" : 976, "state" : "MN" }
+{ "_id" : "56688", "city" : "WIRT", "loc" : [ -93.98107899999999, 47.716428 ], "pop" : 84, "state" : "MN" }
+{ "_id" : "56701", "city" : "THIEF RIVER FALL", "loc" : [ -96.167019, 48.110391 ], "pop" : 11401, "state" : "MN" }
+{ "_id" : "56710", "city" : "ALVARADO", "loc" : [ -96.991457, 48.201968 ], "pop" : 483, "state" : "MN" }
+{ "_id" : "56711", "city" : "ANGLE INLET", "loc" : [ -95.090248, 49.324924 ], "pop" : 50, "state" : "MN" }
+{ "_id" : "56712", "city" : "ANGUS", "loc" : [ -96.656978, 48.092675 ], "pop" : 336, "state" : "MN" }
+{ "_id" : "56713", "city" : "ARGYLE", "loc" : [ -96.867096, 48.331418 ], "pop" : 989, "state" : "MN" }
+{ "_id" : "56714", "city" : "BADGER", "loc" : [ -96.096523, 48.791294 ], "pop" : 1068, "state" : "MN" }
+{ "_id" : "56715", "city" : "BROOKS", "loc" : [ -96.011663, 47.812942 ], "pop" : 350, "state" : "MN" }
+{ "_id" : "56716", "city" : "CROOKSTON", "loc" : [ -96.59307800000001, 47.779694 ], "pop" : 9976, "state" : "MN" }
+{ "_id" : "56720", "city" : "DONALDSON", "loc" : [ -96.857894, 48.579792 ], "pop" : 117, "state" : "MN" }
+{ "_id" : "56721", "city" : "EAST GRAND FORKS", "loc" : [ -97.02126199999999, 47.931802 ], "pop" : 8830, "state" : "MN" }
+{ "_id" : "56722", "city" : "EUCLID", "loc" : [ -96.921496, 48.033804 ], "pop" : 1483, "state" : "MN" }
+{ "_id" : "56723", "city" : "FISHER", "loc" : [ -96.880312, 47.838145 ], "pop" : 1473, "state" : "MN" }
+{ "_id" : "56724", "city" : "GATZKE", "loc" : [ -95.790305, 48.410416 ], "pop" : 131, "state" : "MN" }
+{ "_id" : "56725", "city" : "GOODRIDGE", "loc" : [ -95.72834400000001, 48.068586 ], "pop" : 923, "state" : "MN" }
+{ "_id" : "56726", "city" : "GREENBUSH", "loc" : [ -96.187091, 48.695667 ], "pop" : 1022, "state" : "MN" }
+{ "_id" : "56727", "city" : "GRYGLA", "loc" : [ -95.639805, 48.307068 ], "pop" : 1315, "state" : "MN" }
+{ "_id" : "56728", "city" : "HALLOCK", "loc" : [ -96.944486, 48.774855 ], "pop" : 1729, "state" : "MN" }
+{ "_id" : "56729", "city" : "HALMA", "loc" : [ -96.59689899999999, 48.666895 ], "pop" : 146, "state" : "MN" }
+{ "_id" : "56732", "city" : "KARLSTAD", "loc" : [ -96.55111599999999, 48.591592 ], "pop" : 1461, "state" : "MN" }
+{ "_id" : "56733", "city" : "KENNEDY", "loc" : [ -96.96140699999999, 48.633686 ], "pop" : 673, "state" : "MN" }
+{ "_id" : "56734", "city" : "LAKE BRONSON", "loc" : [ -96.643145, 48.77868 ], "pop" : 548, "state" : "MN" }
+{ "_id" : "56735", "city" : "ORLEANS", "loc" : [ -96.813729, 48.881968 ], "pop" : 785, "state" : "MN" }
+{ "_id" : "56736", "city" : "MENTOR", "loc" : [ -96.177823, 47.657597 ], "pop" : 993, "state" : "MN" }
+{ "_id" : "56737", "city" : "MIDDLE RIVER", "loc" : [ -96.12325, 48.442593 ], "pop" : 948, "state" : "MN" }
+{ "_id" : "56738", "city" : "NEWFOLDEN", "loc" : [ -96.25501800000001, 48.28945 ], "pop" : 1700, "state" : "MN" }
+{ "_id" : "56740", "city" : "NOYES", "loc" : [ -97.14903200000001, 48.969223 ], "pop" : 67, "state" : "MN" }
+{ "_id" : "56741", "city" : "OAK ISLAND", "loc" : [ -94.849209, 49.313466 ], "pop" : 21, "state" : "MN" }
+{ "_id" : "56742", "city" : "OKLEE", "loc" : [ -95.861693, 47.82861 ], "pop" : 628, "state" : "MN" }
+{ "_id" : "56744", "city" : "OSLO", "loc" : [ -97.116252, 48.20657 ], "pop" : 552, "state" : "MN" }
+{ "_id" : "56748", "city" : "PLUMMER", "loc" : [ -95.964558, 47.911324 ], "pop" : 847, "state" : "MN" }
+{ "_id" : "56750", "city" : "RED LAKE FALLS", "loc" : [ -96.268097, 47.882285 ], "pop" : 2700, "state" : "MN" }
+{ "_id" : "56751", "city" : "PENCER", "loc" : [ -95.756709, 48.826809 ], "pop" : 5473, "state" : "MN" }
+{ "_id" : "56754", "city" : "SAINT HILAIRE", "loc" : [ -96.224914, 48.010871 ], "pop" : 873, "state" : "MN" }
+{ "_id" : "56755", "city" : "SAINT VINCENT", "loc" : [ -97.17030699999999, 48.945825 ], "pop" : 241, "state" : "MN" }
+{ "_id" : "56756", "city" : "SALOL", "loc" : [ -95.535594, 48.852213 ], "pop" : 478, "state" : "MN" }
+{ "_id" : "56757", "city" : "STEPHEN", "loc" : [ -96.867392, 48.452488 ], "pop" : 1340, "state" : "MN" }
+{ "_id" : "56758", "city" : "STRANDQUIST", "loc" : [ -96.472266, 48.45256 ], "pop" : 969, "state" : "MN" }
+{ "_id" : "56759", "city" : "STRATHCONA", "loc" : [ -96.109604, 48.626556 ], "pop" : 860, "state" : "MN" }
+{ "_id" : "56760", "city" : "VIKING", "loc" : [ -96.474926, 48.234881 ], "pop" : 627, "state" : "MN" }
+{ "_id" : "56761", "city" : "WANNASKA", "loc" : [ -95.7072, 48.64515 ], "pop" : 684, "state" : "MN" }
+{ "_id" : "56762", "city" : "RADIUM", "loc" : [ -96.759702, 48.20784 ], "pop" : 2404, "state" : "MN" }
+{ "_id" : "56763", "city" : "WARROAD", "loc" : [ -95.353843, 48.911144 ], "pop" : 3766, "state" : "MN" }
+{ "_id" : "57001", "city" : "ALCESTER", "loc" : [ -96.63324299999999, 43.004726 ], "pop" : 2064, "state" : "SD" }
+{ "_id" : "57002", "city" : "AURORA", "loc" : [ -96.704268, 44.283786 ], "pop" : 1252, "state" : "SD" }
+{ "_id" : "57003", "city" : "BALTIC", "loc" : [ -96.756272, 43.730908 ], "pop" : 1839, "state" : "SD" }
+{ "_id" : "57004", "city" : "BERESFORD", "loc" : [ -96.781256, 43.087409 ], "pop" : 2639, "state" : "SD" }
+{ "_id" : "57005", "city" : "CORSON", "loc" : [ -96.57820100000001, 43.596413 ], "pop" : 4155, "state" : "SD" }
+{ "_id" : "57006", "city" : "BROOKINGS", "loc" : [ -96.791408, 44.305619 ], "pop" : 18164, "state" : "SD" }
+{ "_id" : "57010", "city" : "BURBANK", "loc" : [ -96.846569, 42.763798 ], "pop" : 293, "state" : "SD" }
+{ "_id" : "57012", "city" : "CANISTOTA", "loc" : [ -97.288901, 43.585639 ], "pop" : 1255, "state" : "SD" }
+{ "_id" : "57013", "city" : "CANTON", "loc" : [ -96.593796, 43.303819 ], "pop" : 3210, "state" : "SD" }
+{ "_id" : "57014", "city" : "CENTERVILLE", "loc" : [ -96.96363700000001, 43.117635 ], "pop" : 1048, "state" : "SD" }
+{ "_id" : "57015", "city" : "CHANCELLOR", "loc" : [ -96.98269500000001, 43.407962 ], "pop" : 887, "state" : "SD" }
+{ "_id" : "57016", "city" : "CHESTER", "loc" : [ -96.975883, 43.898077 ], "pop" : 799, "state" : "SD" }
+{ "_id" : "57017", "city" : "COLMAN", "loc" : [ -96.818882, 43.955761 ], "pop" : 1013, "state" : "SD" }
+{ "_id" : "57018", "city" : "COLTON", "loc" : [ -96.957202, 43.795102 ], "pop" : 1242, "state" : "SD" }
+{ "_id" : "57020", "city" : "CROOKS", "loc" : [ -96.818259, 43.64509 ], "pop" : 1262, "state" : "SD" }
+{ "_id" : "57021", "city" : "DAVIS", "loc" : [ -96.979206, 43.286365 ], "pop" : 357, "state" : "SD" }
+{ "_id" : "57022", "city" : "DELL RAPIDS", "loc" : [ -96.72231499999999, 43.822759 ], "pop" : 3128, "state" : "SD" }
+{ "_id" : "57024", "city" : "EGAN", "loc" : [ -96.649252, 43.986592 ], "pop" : 658, "state" : "SD" }
+{ "_id" : "57025", "city" : "ELK POINT", "loc" : [ -96.686954, 42.738219 ], "pop" : 2698, "state" : "SD" }
+{ "_id" : "57026", "city" : "ELKTON", "loc" : [ -96.50109500000001, 44.234984 ], "pop" : 853, "state" : "SD" }
+{ "_id" : "57027", "city" : "FAIRVIEW", "loc" : [ -96.57426100000001, 43.208965 ], "pop" : 472, "state" : "SD" }
+{ "_id" : "57028", "city" : "FLANDREAU", "loc" : [ -96.622184, 44.06578 ], "pop" : 3851, "state" : "SD" }
+{ "_id" : "57029", "city" : "FREEMAN", "loc" : [ -97.46007299999999, 43.360501 ], "pop" : 2190, "state" : "SD" }
+{ "_id" : "57030", "city" : "GARRETSON", "loc" : [ -96.519626, 43.71617 ], "pop" : 1546, "state" : "SD" }
+{ "_id" : "57031", "city" : "GAYVILLE", "loc" : [ -97.18295000000001, 42.883516 ], "pop" : 572, "state" : "SD" }
+{ "_id" : "57032", "city" : "HARRISBURG", "loc" : [ -96.68638900000001, 43.446021 ], "pop" : 3387, "state" : "SD" }
+{ "_id" : "57033", "city" : "HARTFORD", "loc" : [ -96.950052, 43.615472 ], "pop" : 3110, "state" : "SD" }
+{ "_id" : "57034", "city" : "HUDSON", "loc" : [ -96.53063, 43.128357 ], "pop" : 774, "state" : "SD" }
+{ "_id" : "57035", "city" : "HUMBOLDT", "loc" : [ -97.06971, 43.612026 ], "pop" : 1090, "state" : "SD" }
+{ "_id" : "57036", "city" : "HURLEY", "loc" : [ -97.190364, 43.289256 ], "pop" : 1124, "state" : "SD" }
+{ "_id" : "57037", "city" : "IRENE", "loc" : [ -97.255797, 43.102683 ], "pop" : 1320, "state" : "SD" }
+{ "_id" : "57038", "city" : "JEFFERSON", "loc" : [ -96.57839199999999, 42.601341 ], "pop" : 1262, "state" : "SD" }
+{ "_id" : "57039", "city" : "LENNOX", "loc" : [ -96.88206099999999, 43.345066 ], "pop" : 2852, "state" : "SD" }
+{ "_id" : "57040", "city" : "LESTERVILLE", "loc" : [ -97.548282, 43.054976 ], "pop" : 680, "state" : "SD" }
+{ "_id" : "57042", "city" : "MADISON", "loc" : [ -97.11485999999999, 44.005434 ], "pop" : 7745, "state" : "SD" }
+{ "_id" : "57043", "city" : "MARION", "loc" : [ -97.277066, 43.41878 ], "pop" : 1377, "state" : "SD" }
+{ "_id" : "57044", "city" : "MECKLING", "loc" : [ -97.092249, 42.848994 ], "pop" : 228, "state" : "SD" }
+{ "_id" : "57045", "city" : "MENNO", "loc" : [ -97.564986, 43.233968 ], "pop" : 1337, "state" : "SD" }
+{ "_id" : "57046", "city" : "MISSION HILL", "loc" : [ -97.33487700000001, 42.983611 ], "pop" : 546, "state" : "SD" }
+{ "_id" : "57047", "city" : "MONROE", "loc" : [ -97.21816699999999, 43.477883 ], "pop" : 239, "state" : "SD" }
+{ "_id" : "57048", "city" : "MONTROSE", "loc" : [ -97.18849299999999, 43.706262 ], "pop" : 958, "state" : "SD" }
+{ "_id" : "57049", "city" : "DAKOTA DUNES", "loc" : [ -96.50761, 42.532706 ], "pop" : 2491, "state" : "SD" }
+{ "_id" : "57050", "city" : "NUNDA", "loc" : [ -96.994209, 44.152459 ], "pop" : 334, "state" : "SD" }
+{ "_id" : "57051", "city" : "OLDHAM", "loc" : [ -97.269575, 44.245722 ], "pop" : 655, "state" : "SD" }
+{ "_id" : "57052", "city" : "OLIVET", "loc" : [ -97.718355, 43.292811 ], "pop" : 555, "state" : "SD" }
+{ "_id" : "57053", "city" : "PARKER", "loc" : [ -97.133298, 43.40204 ], "pop" : 1494, "state" : "SD" }
+{ "_id" : "57054", "city" : "RAMONA", "loc" : [ -97.234889, 44.122887 ], "pop" : 641, "state" : "SD" }
+{ "_id" : "57055", "city" : "RENNER", "loc" : [ -96.71192499999999, 43.636625 ], "pop" : 1444, "state" : "SD" }
+{ "_id" : "57057", "city" : "RUTLAND", "loc" : [ -96.95185600000001, 44.068282 ], "pop" : 213, "state" : "SD" }
+{ "_id" : "57058", "city" : "SALEM", "loc" : [ -97.379695, 43.735583 ], "pop" : 1963, "state" : "SD" }
+{ "_id" : "57059", "city" : "SCOTLAND", "loc" : [ -97.729596, 43.121208 ], "pop" : 1611, "state" : "SD" }
+{ "_id" : "57060", "city" : "SHERMAN", "loc" : [ -96.54439600000001, 43.798677 ], "pop" : 507, "state" : "SD" }
+{ "_id" : "57061", "city" : "SINAI", "loc" : [ -97.054332, 44.239745 ], "pop" : 296, "state" : "SD" }
+{ "_id" : "57062", "city" : "SPRINGFIELD", "loc" : [ -97.928825, 42.868694 ], "pop" : 2044, "state" : "SD" }
+{ "_id" : "57063", "city" : "TABOR", "loc" : [ -97.69228200000001, 42.938262 ], "pop" : 853, "state" : "SD" }
+{ "_id" : "57064", "city" : "TEA", "loc" : [ -96.817734, 43.471114 ], "pop" : 2885, "state" : "SD" }
+{ "_id" : "57065", "city" : "TRENT", "loc" : [ -96.63257400000001, 43.894159 ], "pop" : 865, "state" : "SD" }
+{ "_id" : "57066", "city" : "TYNDALL", "loc" : [ -97.863285, 42.990043 ], "pop" : 1451, "state" : "SD" }
+{ "_id" : "57067", "city" : "UTICA", "loc" : [ -97.455095, 42.936629 ], "pop" : 1183, "state" : "SD" }
+{ "_id" : "57068", "city" : "VALLEY SPRINGS", "loc" : [ -96.495637, 43.577306 ], "pop" : 1709, "state" : "SD" }
+{ "_id" : "57069", "city" : "VERMILLION", "loc" : [ -96.92578399999999, 42.795109 ], "pop" : 11446, "state" : "SD" }
+{ "_id" : "57070", "city" : "VIBORG", "loc" : [ -97.114048, 43.181497 ], "pop" : 1664, "state" : "SD" }
+{ "_id" : "57071", "city" : "VOLGA", "loc" : [ -96.92514799999999, 44.322354 ], "pop" : 1562, "state" : "SD" }
+{ "_id" : "57072", "city" : "VOLIN", "loc" : [ -97.22823099999999, 42.969617 ], "pop" : 782, "state" : "SD" }
+{ "_id" : "57073", "city" : "WAKONDA", "loc" : [ -97.069374, 42.996001 ], "pop" : 938, "state" : "SD" }
+{ "_id" : "57074", "city" : "WARD", "loc" : [ -96.481325, 44.155883 ], "pop" : 120, "state" : "SD" }
+{ "_id" : "57075", "city" : "WENTWORTH", "loc" : [ -96.961456, 43.985242 ], "pop" : 394, "state" : "SD" }
+{ "_id" : "57076", "city" : "WINFRED", "loc" : [ -97.30926599999999, 43.959511 ], "pop" : 424, "state" : "SD" }
+{ "_id" : "57077", "city" : "WORTHING", "loc" : [ -96.75293499999999, 43.292531 ], "pop" : 882, "state" : "SD" }
+{ "_id" : "57078", "city" : "YANKTON", "loc" : [ -97.398624, 42.882086 ], "pop" : 14765, "state" : "SD" }
+{ "_id" : "57102", "city" : "SIOUX FALLS", "loc" : [ -96.726927, 43.546131 ], "pop" : 530, "state" : "SD" }
+{ "_id" : "57103", "city" : "SIOUX FALLS", "loc" : [ -96.686415, 43.537386 ], "pop" : 32508, "state" : "SD" }
+{ "_id" : "57104", "city" : "SIOUX FALLS", "loc" : [ -96.73753499999999, 43.551355 ], "pop" : 22081, "state" : "SD" }
+{ "_id" : "57105", "city" : "SIOUX FALLS", "loc" : [ -96.73414099999999, 43.523972 ], "pop" : 26347, "state" : "SD" }
+{ "_id" : "57106", "city" : "SIOUX FALLS", "loc" : [ -96.792376, 43.517912 ], "pop" : 16823, "state" : "SD" }
+{ "_id" : "57107", "city" : "SIOUX FALLS", "loc" : [ -96.80281100000001, 43.556628 ], "pop" : 3331, "state" : "SD" }
+{ "_id" : "57115", "city" : "BUFFALO RIDGE", "loc" : [ -96.834165, 43.516936 ], "pop" : 731, "state" : "SD" }
+{ "_id" : "57116", "city" : "SIOUX FALLS", "loc" : [ -96.766199, 43.508535 ], "pop" : 426, "state" : "SD" }
+{ "_id" : "57201", "city" : "WATERTOWN", "loc" : [ -97.123977, 44.904295 ], "pop" : 20148, "state" : "SD" }
+{ "_id" : "57202", "city" : "WAVERLY", "loc" : [ -96.946744, 45.003209 ], "pop" : 163, "state" : "SD" }
+{ "_id" : "57212", "city" : "ARLINGTON", "loc" : [ -97.06873400000001, 44.366769 ], "pop" : 358, "state" : "SD" }
+{ "_id" : "57213", "city" : "ASTORIA", "loc" : [ -96.541634, 44.573515 ], "pop" : 370, "state" : "SD" }
+{ "_id" : "57214", "city" : "BADGER", "loc" : [ -97.218368, 44.491802 ], "pop" : 354, "state" : "SD" }
+{ "_id" : "57216", "city" : "BIG STONE CITY", "loc" : [ -96.56143400000001, 45.28504 ], "pop" : 1568, "state" : "SD" }
+{ "_id" : "57217", "city" : "BRADLEY", "loc" : [ -97.638712, 45.075099 ], "pop" : 399, "state" : "SD" }
+{ "_id" : "57218", "city" : "BRANDT", "loc" : [ -96.643545, 44.67383 ], "pop" : 655, "state" : "SD" }
+{ "_id" : "57219", "city" : "BUTLER", "loc" : [ -97.746573, 45.308982 ], "pop" : 769, "state" : "SD" }
+{ "_id" : "57220", "city" : "BRUCE", "loc" : [ -96.910984, 44.467453 ], "pop" : 929, "state" : "SD" }
+{ "_id" : "57221", "city" : "BRYANT", "loc" : [ -97.453659, 44.598671 ], "pop" : 627, "state" : "SD" }
+{ "_id" : "57223", "city" : "CASTLEWOOD", "loc" : [ -97.020432, 44.731339 ], "pop" : 1083, "state" : "SD" }
+{ "_id" : "57224", "city" : "CLAIRE CITY", "loc" : [ -97.107274, 45.875522 ], "pop" : 394, "state" : "SD" }
+{ "_id" : "57225", "city" : "CLARK", "loc" : [ -97.726536, 44.878 ], "pop" : 2062, "state" : "SD" }
+{ "_id" : "57226", "city" : "ALTAMONT", "loc" : [ -96.700541, 44.763703 ], "pop" : 1786, "state" : "SD" }
+{ "_id" : "57227", "city" : "CORONA", "loc" : [ -96.664897, 45.359483 ], "pop" : 613, "state" : "SD" }
+{ "_id" : "57231", "city" : "DE SMET", "loc" : [ -97.56343200000001, 44.385169 ], "pop" : 1956, "state" : "SD" }
+{ "_id" : "57232", "city" : "EDEN", "loc" : [ -97.37409100000001, 45.621074 ], "pop" : 318, "state" : "SD" }
+{ "_id" : "57233", "city" : "ERWIN", "loc" : [ -97.410291, 44.491484 ], "pop" : 225, "state" : "SD" }
+{ "_id" : "57234", "city" : "DEMPSTER", "loc" : [ -96.923678, 44.576998 ], "pop" : 903, "state" : "SD" }
+{ "_id" : "57235", "city" : "FLORENCE", "loc" : [ -97.286643, 45.055388 ], "pop" : 664, "state" : "SD" }
+{ "_id" : "57236", "city" : "GARDEN CITY", "loc" : [ -97.56802500000001, 44.947413 ], "pop" : 175, "state" : "SD" }
+{ "_id" : "57237", "city" : "GARY", "loc" : [ -96.504362, 44.827022 ], "pop" : 733, "state" : "SD" }
+{ "_id" : "57238", "city" : "BEMIS", "loc" : [ -96.811368, 44.886232 ], "pop" : 509, "state" : "SD" }
+{ "_id" : "57239", "city" : "GRENVILLE", "loc" : [ -97.415457, 45.489673 ], "pop" : 334, "state" : "SD" }
+{ "_id" : "57241", "city" : "HAYTI", "loc" : [ -97.230509, 44.664737 ], "pop" : 720, "state" : "SD" }
+{ "_id" : "57242", "city" : "HAZEL", "loc" : [ -97.30829, 44.75717 ], "pop" : 496, "state" : "SD" }
+{ "_id" : "57243", "city" : "HENRY", "loc" : [ -97.444216, 44.88576 ], "pop" : 435, "state" : "SD" }
+{ "_id" : "57244", "city" : "HETLAND", "loc" : [ -97.141024, 44.367519 ], "pop" : 1069, "state" : "SD" }
+{ "_id" : "57245", "city" : "KRANZBURG", "loc" : [ -96.947013, 44.879264 ], "pop" : 525, "state" : "SD" }
+{ "_id" : "57246", "city" : "LABOLT", "loc" : [ -96.68920900000001, 45.041458 ], "pop" : 188, "state" : "SD" }
+{ "_id" : "57247", "city" : "LAKE CITY", "loc" : [ -97.348131, 45.68991 ], "pop" : 401, "state" : "SD" }
+{ "_id" : "57248", "city" : "LAKE NORDEN", "loc" : [ -97.200867, 44.584351 ], "pop" : 900, "state" : "SD" }
+{ "_id" : "57249", "city" : "LAKE PRESTON", "loc" : [ -97.356283, 44.367298 ], "pop" : 1074, "state" : "SD" }
+{ "_id" : "57251", "city" : "MARVIN", "loc" : [ -96.90996, 45.272651 ], "pop" : 146, "state" : "SD" }
+{ "_id" : "57252", "city" : "MILBANK", "loc" : [ -96.62548, 45.206127 ], "pop" : 5235, "state" : "SD" }
+{ "_id" : "57255", "city" : "NEW EFFINGTON", "loc" : [ -96.91498900000001, 45.865868 ], "pop" : 391, "state" : "SD" }
+{ "_id" : "57256", "city" : "ORTLEY", "loc" : [ -97.176985, 45.340633 ], "pop" : 151, "state" : "SD" }
+{ "_id" : "57257", "city" : "PEEVER", "loc" : [ -97.001205, 45.520647 ], "pop" : 992, "state" : "SD" }
+{ "_id" : "57258", "city" : "RAYMOND", "loc" : [ -97.916781, 44.863651 ], "pop" : 415, "state" : "SD" }
+{ "_id" : "57259", "city" : "ALBEE", "loc" : [ -96.562366, 45.022142 ], "pop" : 357, "state" : "SD" }
+{ "_id" : "57260", "city" : "ROSHOLT", "loc" : [ -96.71741, 45.875315 ], "pop" : 841, "state" : "SD" }
+{ "_id" : "57261", "city" : "ROSLYN", "loc" : [ -97.540105, 45.500564 ], "pop" : 533, "state" : "SD" }
+{ "_id" : "57262", "city" : "AGENCY VILLAGE", "loc" : [ -97.02321999999999, 45.664413 ], "pop" : 4968, "state" : "SD" }
+{ "_id" : "57263", "city" : "SOUTH SHORE", "loc" : [ -96.985885, 45.104919 ], "pop" : 487, "state" : "SD" }
+{ "_id" : "57264", "city" : "STOCKHOLM", "loc" : [ -96.81059, 45.10309 ], "pop" : 213, "state" : "SD" }
+{ "_id" : "57265", "city" : "STRANDBURG", "loc" : [ -96.79012899999999, 45.038872 ], "pop" : 133, "state" : "SD" }
+{ "_id" : "57266", "city" : "SUMMIT", "loc" : [ -97.042654, 45.352128 ], "pop" : 469, "state" : "SD" }
+{ "_id" : "57268", "city" : "TORONTO", "loc" : [ -96.70774, 44.578622 ], "pop" : 469, "state" : "SD" }
+{ "_id" : "57269", "city" : "TWIN BROOKS", "loc" : [ -96.99560099999999, 45.211519 ], "pop" : 532, "state" : "SD" }
+{ "_id" : "57270", "city" : "VEBLEN", "loc" : [ -97.31219299999999, 45.853508 ], "pop" : 765, "state" : "SD" }
+{ "_id" : "57271", "city" : "VIENNA", "loc" : [ -97.545559, 44.690019 ], "pop" : 454, "state" : "SD" }
+{ "_id" : "57272", "city" : "WALLACE", "loc" : [ -97.445751, 45.081542 ], "pop" : 276, "state" : "SD" }
+{ "_id" : "57273", "city" : "WAUBAY", "loc" : [ -97.29498700000001, 45.37837 ], "pop" : 1437, "state" : "SD" }
+{ "_id" : "57274", "city" : "LILY", "loc" : [ -97.515316, 45.322573 ], "pop" : 3194, "state" : "SD" }
+{ "_id" : "57276", "city" : "WHITE", "loc" : [ -96.614963, 44.413237 ], "pop" : 1793, "state" : "SD" }
+{ "_id" : "57278", "city" : "WILLOW LAKE", "loc" : [ -97.674747, 44.627225 ], "pop" : 661, "state" : "SD" }
+{ "_id" : "57279", "city" : "WILMOT", "loc" : [ -96.85600599999999, 45.412487 ], "pop" : 1095, "state" : "SD" }
+{ "_id" : "57301", "city" : "LOOMIS", "loc" : [ -98.02702600000001, 43.710921 ], "pop" : 16187, "state" : "SD" }
+{ "_id" : "57311", "city" : "FARMER", "loc" : [ -97.782087, 43.623847 ], "pop" : 934, "state" : "SD" }
+{ "_id" : "57312", "city" : "ALPENA", "loc" : [ -98.396191, 44.170907 ], "pop" : 414, "state" : "SD" }
+{ "_id" : "57313", "city" : "ARMOUR", "loc" : [ -98.34137200000001, 43.316045 ], "pop" : 1118, "state" : "SD" }
+{ "_id" : "57314", "city" : "FORESTBURG", "loc" : [ -97.953958, 44.035362 ], "pop" : 640, "state" : "SD" }
+{ "_id" : "57315", "city" : "AVON", "loc" : [ -98.028261, 43.039725 ], "pop" : 1130, "state" : "SD" }
+{ "_id" : "57316", "city" : "BANCROFT", "loc" : [ -97.77673299999999, 44.494419 ], "pop" : 200, "state" : "SD" }
+{ "_id" : "57317", "city" : "BONESTEEL", "loc" : [ -98.987959, 43.069536 ], "pop" : 688, "state" : "SD" }
+{ "_id" : "57319", "city" : "DOLTON", "loc" : [ -97.49590999999999, 43.554306 ], "pop" : 1055, "state" : "SD" }
+{ "_id" : "57321", "city" : "CANOVA", "loc" : [ -97.53416300000001, 43.885517 ], "pop" : 506, "state" : "SD" }
+{ "_id" : "57322", "city" : "CARPENTER", "loc" : [ -97.916825, 44.664768 ], "pop" : 101, "state" : "SD" }
+{ "_id" : "57323", "city" : "CARTHAGE", "loc" : [ -97.71163199999999, 44.1496 ], "pop" : 380, "state" : "SD" }
+{ "_id" : "57324", "city" : "CAVOUR", "loc" : [ -98.020797, 44.364951 ], "pop" : 444, "state" : "SD" }
+{ "_id" : "57325", "city" : "CHAMBERLAIN", "loc" : [ -99.311819, 43.795295 ], "pop" : 3218, "state" : "SD" }
+{ "_id" : "57328", "city" : "CORSICA", "loc" : [ -98.356358, 43.421319 ], "pop" : 1569, "state" : "SD" }
+{ "_id" : "57329", "city" : "DANTE", "loc" : [ -98.174637, 42.996661 ], "pop" : 519, "state" : "SD" }
+{ "_id" : "57330", "city" : "DELMONT", "loc" : [ -98.159612, 43.257261 ], "pop" : 468, "state" : "SD" }
+{ "_id" : "57331", "city" : "DIMOCK", "loc" : [ -97.9988, 43.470476 ], "pop" : 426, "state" : "SD" }
+{ "_id" : "57332", "city" : "EMERY", "loc" : [ -97.64748899999999, 43.565647 ], "pop" : 888, "state" : "SD" }
+{ "_id" : "57334", "city" : "ETHAN", "loc" : [ -98.059074, 43.542653 ], "pop" : 975, "state" : "SD" }
+{ "_id" : "57335", "city" : "FAIRFAX", "loc" : [ -98.83075700000001, 43.035103 ], "pop" : 423, "state" : "SD" }
+{ "_id" : "57337", "city" : "FEDORA", "loc" : [ -97.78900299999999, 43.984125 ], "pop" : 288, "state" : "SD" }
+{ "_id" : "57339", "city" : "FORT THOMPSON", "loc" : [ -99.397305, 44.051695 ], "pop" : 1495, "state" : "SD" }
+{ "_id" : "57340", "city" : "FULTON", "loc" : [ -97.871218, 43.758767 ], "pop" : 572, "state" : "SD" }
+{ "_id" : "57341", "city" : "GANN VALLEY", "loc" : [ -99.054334, 44.069303 ], "pop" : 264, "state" : "SD" }
+{ "_id" : "57342", "city" : "GEDDES", "loc" : [ -98.69256, 43.259677 ], "pop" : 725, "state" : "SD" }
+{ "_id" : "57344", "city" : "HARRISON", "loc" : [ -98.523338, 43.454923 ], "pop" : 233, "state" : "SD" }
+{ "_id" : "57345", "city" : "HIGHMORE", "loc" : [ -99.45434899999999, 44.532604 ], "pop" : 1652, "state" : "SD" }
+{ "_id" : "57348", "city" : "HITCHCOCK", "loc" : [ -98.450914, 44.583444 ], "pop" : 501, "state" : "SD" }
+{ "_id" : "57349", "city" : "ROSWELL", "loc" : [ -97.516012, 44.029296 ], "pop" : 2098, "state" : "SD" }
+{ "_id" : "57350", "city" : "HURON", "loc" : [ -98.21629299999999, 44.359022 ], "pop" : 15277, "state" : "SD" }
+{ "_id" : "57353", "city" : "IROQUOIS", "loc" : [ -97.85417200000001, 44.345517 ], "pop" : 576, "state" : "SD" }
+{ "_id" : "57354", "city" : "KAYLOR", "loc" : [ -97.820094, 43.202393 ], "pop" : 223, "state" : "SD" }
+{ "_id" : "57355", "city" : "KIMBALL", "loc" : [ -98.93430499999999, 43.712881 ], "pop" : 1546, "state" : "SD" }
+{ "_id" : "57356", "city" : "LAKE ANDES", "loc" : [ -98.49635499999999, 43.130288 ], "pop" : 2556, "state" : "SD" }
+{ "_id" : "57357", "city" : "RAVINIA", "loc" : [ -98.426413, 43.136123 ], "pop" : 79, "state" : "SD" }
+{ "_id" : "57358", "city" : "LANE", "loc" : [ -98.406496, 44.067383 ], "pop" : 152, "state" : "SD" }
+{ "_id" : "57359", "city" : "LETCHER", "loc" : [ -98.174279, 43.892324 ], "pop" : 912, "state" : "SD" }
+{ "_id" : "57361", "city" : "MARTY", "loc" : [ -98.42242899999999, 42.97639 ], "pop" : 306, "state" : "SD" }
+{ "_id" : "57362", "city" : "MILLER", "loc" : [ -98.989395, 44.496644 ], "pop" : 2938, "state" : "SD" }
+{ "_id" : "57363", "city" : "MOUNT VERNON", "loc" : [ -98.263288, 43.7204 ], "pop" : 731, "state" : "SD" }
+{ "_id" : "57364", "city" : "NEW HOLLAND", "loc" : [ -98.628697, 43.431042 ], "pop" : 358, "state" : "SD" }
+{ "_id" : "57366", "city" : "PARKSTON", "loc" : [ -97.96782399999999, 43.397796 ], "pop" : 2231, "state" : "SD" }
+{ "_id" : "57368", "city" : "PLANKINTON", "loc" : [ -98.46939500000001, 43.737287 ], "pop" : 1129, "state" : "SD" }
+{ "_id" : "57369", "city" : "ACADEMY", "loc" : [ -98.889656, 43.40242 ], "pop" : 2425, "state" : "SD" }
+{ "_id" : "57370", "city" : "PUKWANA", "loc" : [ -99.17788400000001, 43.778326 ], "pop" : 577, "state" : "SD" }
+{ "_id" : "57371", "city" : "REE HEIGHTS", "loc" : [ -99.22864, 44.560275 ], "pop" : 288, "state" : "SD" }
+{ "_id" : "57373", "city" : "SAINT LAWRENCE", "loc" : [ -98.875427, 44.521523 ], "pop" : 425, "state" : "SD" }
+{ "_id" : "57374", "city" : "SPENCER", "loc" : [ -97.59361, 43.755684 ], "pop" : 658, "state" : "SD" }
+{ "_id" : "57375", "city" : "STICKNEY", "loc" : [ -98.508843, 43.58422 ], "pop" : 1099, "state" : "SD" }
+{ "_id" : "57376", "city" : "TRIPP", "loc" : [ -97.97128499999999, 43.240377 ], "pop" : 1128, "state" : "SD" }
+{ "_id" : "57379", "city" : "VIRGIL", "loc" : [ -98.392146, 44.325582 ], "pop" : 167, "state" : "SD" }
+{ "_id" : "57380", "city" : "WAGNER", "loc" : [ -98.281876, 43.081931 ], "pop" : 2665, "state" : "SD" }
+{ "_id" : "57381", "city" : "WESSINGTON", "loc" : [ -98.691982, 44.41285 ], "pop" : 618, "state" : "SD" }
+{ "_id" : "57382", "city" : "WESSINGTON SPRIN", "loc" : [ -98.611625, 44.069935 ], "pop" : 1864, "state" : "SD" }
+{ "_id" : "57383", "city" : "WHITE LAKE", "loc" : [ -98.70761299999999, 43.756441 ], "pop" : 717, "state" : "SD" }
+{ "_id" : "57384", "city" : "WOLSEY", "loc" : [ -98.474251, 44.399072 ], "pop" : 751, "state" : "SD" }
+{ "_id" : "57385", "city" : "WOONSOCKET", "loc" : [ -98.24301699999999, 44.057186 ], "pop" : 1471, "state" : "SD" }
+{ "_id" : "57386", "city" : "YALE", "loc" : [ -97.99324900000001, 44.495591 ], "pop" : 462, "state" : "SD" }
+{ "_id" : "57401", "city" : "ABERDEEN", "loc" : [ -98.485642, 45.466109 ], "pop" : 28786, "state" : "SD" }
+{ "_id" : "57420", "city" : "AKASKA", "loc" : [ -100.118614, 45.332447 ], "pop" : 52, "state" : "SD" }
+{ "_id" : "57421", "city" : "AMHERST", "loc" : [ -97.93007799999999, 45.707426 ], "pop" : 227, "state" : "SD" }
+{ "_id" : "57422", "city" : "ANDOVER", "loc" : [ -97.917497, 45.422171 ], "pop" : 348, "state" : "SD" }
+{ "_id" : "57424", "city" : "ATHOL", "loc" : [ -98.442549, 45.012833 ], "pop" : 306, "state" : "SD" }
+{ "_id" : "57426", "city" : "BARNARD", "loc" : [ -98.55337900000001, 45.720469 ], "pop" : 172, "state" : "SD" }
+{ "_id" : "57427", "city" : "BATH", "loc" : [ -98.355209, 45.456352 ], "pop" : 593, "state" : "SD" }
+{ "_id" : "57428", "city" : "BOWDLE", "loc" : [ -99.63597799999999, 45.432881 ], "pop" : 882, "state" : "SD" }
+{ "_id" : "57429", "city" : "BRENTFORD", "loc" : [ -98.319281, 45.153063 ], "pop" : 257, "state" : "SD" }
+{ "_id" : "57430", "city" : "BRITTON", "loc" : [ -97.74183499999999, 45.802304 ], "pop" : 2507, "state" : "SD" }
+{ "_id" : "57432", "city" : "CLAREMONT", "loc" : [ -98.040367, 45.666149 ], "pop" : 400, "state" : "SD" }
+{ "_id" : "57433", "city" : "COLUMBIA", "loc" : [ -98.295152, 45.671721 ], "pop" : 585, "state" : "SD" }
+{ "_id" : "57434", "city" : "VERDON", "loc" : [ -98.034323, 45.155125 ], "pop" : 611, "state" : "SD" }
+{ "_id" : "57435", "city" : "CRESBARD", "loc" : [ -98.941124, 45.169125 ], "pop" : 312, "state" : "SD" }
+{ "_id" : "57436", "city" : "DOLAND", "loc" : [ -98.09470899999999, 44.81587 ], "pop" : 997, "state" : "SD" }
+{ "_id" : "57437", "city" : "ARTAS", "loc" : [ -99.615926, 45.769768 ], "pop" : 1753, "state" : "SD" }
+{ "_id" : "57438", "city" : "MIRANDA", "loc" : [ -99.13405400000001, 45.06845 ], "pop" : 1593, "state" : "SD" }
+{ "_id" : "57440", "city" : "FRANKFORT", "loc" : [ -98.293496, 44.808416 ], "pop" : 533, "state" : "SD" }
+{ "_id" : "57441", "city" : "FREDERICK", "loc" : [ -98.51756399999999, 45.849332 ], "pop" : 524, "state" : "SD" }
+{ "_id" : "57442", "city" : "GETTYSBURG", "loc" : [ -99.976626, 45.02588 ], "pop" : 2065, "state" : "SD" }
+{ "_id" : "57445", "city" : "GROTON", "loc" : [ -98.105814, 45.450345 ], "pop" : 1814, "state" : "SD" }
+{ "_id" : "57446", "city" : "HECLA", "loc" : [ -98.191774, 45.872515 ], "pop" : 754, "state" : "SD" }
+{ "_id" : "57448", "city" : "HOSMER", "loc" : [ -99.48574499999999, 45.568988 ], "pop" : 454, "state" : "SD" }
+{ "_id" : "57449", "city" : "HOUGHTON", "loc" : [ -98.095186, 45.796746 ], "pop" : 147, "state" : "SD" }
+{ "_id" : "57450", "city" : "HOVEN", "loc" : [ -99.776286, 45.227799 ], "pop" : 677, "state" : "SD" }
+{ "_id" : "57451", "city" : "IPSWICH", "loc" : [ -99.014807, 45.448905 ], "pop" : 1771, "state" : "SD" }
+{ "_id" : "57452", "city" : "JAVA", "loc" : [ -99.83515300000001, 45.413541 ], "pop" : 518, "state" : "SD" }
+{ "_id" : "57454", "city" : "LANGFORD", "loc" : [ -97.792547, 45.617381 ], "pop" : 626, "state" : "SD" }
+{ "_id" : "57455", "city" : "LEBANON", "loc" : [ -99.73657900000001, 45.012318 ], "pop" : 259, "state" : "SD" }
+{ "_id" : "57456", "city" : "LEOLA", "loc" : [ -98.901544, 45.732265 ], "pop" : 1192, "state" : "SD" }
+{ "_id" : "57457", "city" : "LONGLAKE", "loc" : [ -99.250677, 45.796812 ], "pop" : 378, "state" : "SD" }
+{ "_id" : "57460", "city" : "MANSFIELD", "loc" : [ -98.606568, 45.226727 ], "pop" : 92, "state" : "SD" }
+{ "_id" : "57461", "city" : "MELLETTE", "loc" : [ -98.48237, 45.16312 ], "pop" : 362, "state" : "SD" }
+{ "_id" : "57462", "city" : "MINA", "loc" : [ -98.756581, 45.439116 ], "pop" : 515, "state" : "SD" }
+{ "_id" : "57465", "city" : "NORTHVILLE", "loc" : [ -98.65885299999999, 45.161112 ], "pop" : 328, "state" : "SD" }
+{ "_id" : "57466", "city" : "ONAKA", "loc" : [ -99.45505199999999, 45.196527 ], "pop" : 143, "state" : "SD" }
+{ "_id" : "57467", "city" : "ORIENT", "loc" : [ -99.10578700000001, 44.834347 ], "pop" : 441, "state" : "SD" }
+{ "_id" : "57468", "city" : "PIERPONT", "loc" : [ -97.812844, 45.495983 ], "pop" : 328, "state" : "SD" }
+{ "_id" : "57469", "city" : "REDFIELD", "loc" : [ -98.511234, 44.871853 ], "pop" : 4033, "state" : "SD" }
+{ "_id" : "57470", "city" : "ROCKHAM", "loc" : [ -98.768683, 44.971579 ], "pop" : 237, "state" : "SD" }
+{ "_id" : "57471", "city" : "ROSCOE", "loc" : [ -99.33263100000001, 45.427119 ], "pop" : 673, "state" : "SD" }
+{ "_id" : "57472", "city" : "SELBY", "loc" : [ -100.054067, 45.478587 ], "pop" : 1284, "state" : "SD" }
+{ "_id" : "57473", "city" : "SENECA", "loc" : [ -99.46098600000001, 45.026191 ], "pop" : 246, "state" : "SD" }
+{ "_id" : "57474", "city" : "STRATFORD", "loc" : [ -98.27915299999999, 45.286595 ], "pop" : 418, "state" : "SD" }
+{ "_id" : "57475", "city" : "TOLSTOY", "loc" : [ -99.617553, 45.170199 ], "pop" : 189, "state" : "SD" }
+{ "_id" : "57476", "city" : "TULARE", "loc" : [ -98.553926, 44.730489 ], "pop" : 526, "state" : "SD" }
+{ "_id" : "57477", "city" : "TURTON", "loc" : [ -98.09964100000001, 45.037938 ], "pop" : 154, "state" : "SD" }
+{ "_id" : "57479", "city" : "WARNER", "loc" : [ -98.475697, 45.348627 ], "pop" : 1060, "state" : "SD" }
+{ "_id" : "57481", "city" : "WETONKA", "loc" : [ -98.585623, 45.625025 ], "pop" : 337, "state" : "SD" }
+{ "_id" : "57483", "city" : "ZELL", "loc" : [ -98.831746, 44.854624 ], "pop" : 131, "state" : "SD" }
+{ "_id" : "57501", "city" : "PIERRE", "loc" : [ -100.321057, 44.369514 ], "pop" : 14138, "state" : "SD" }
+{ "_id" : "57520", "city" : "AGAR", "loc" : [ -100.071238, 44.839345 ], "pop" : 89, "state" : "SD" }
+{ "_id" : "57521", "city" : "BELVIDERE", "loc" : [ -101.238691, 43.886031 ], "pop" : 177, "state" : "SD" }
+{ "_id" : "57522", "city" : "BLUNT", "loc" : [ -99.94627800000001, 44.502572 ], "pop" : 484, "state" : "SD" }
+{ "_id" : "57523", "city" : "LUCAS", "loc" : [ -99.268963, 43.210602 ], "pop" : 1258, "state" : "SD" }
+{ "_id" : "57526", "city" : "CARTER", "loc" : [ -100.172958, 43.368487 ], "pop" : 118, "state" : "SD" }
+{ "_id" : "57527", "city" : "CEDARBUTTE", "loc" : [ -101.131585, 43.64731 ], "pop" : 208, "state" : "SD" }
+{ "_id" : "57528", "city" : "COLOME", "loc" : [ -99.693273, 43.227334 ], "pop" : 771, "state" : "SD" }
+{ "_id" : "57529", "city" : "DALLAS", "loc" : [ -99.513994, 43.235075 ], "pop" : 167, "state" : "SD" }
+{ "_id" : "57531", "city" : "DRAPER", "loc" : [ -100.508514, 43.926035 ], "pop" : 304, "state" : "SD" }
+{ "_id" : "57532", "city" : "FORT PIERRE", "loc" : [ -100.404323, 44.342587 ], "pop" : 2179, "state" : "SD" }
+{ "_id" : "57533", "city" : "DIXON", "loc" : [ -99.43021400000001, 43.226908 ], "pop" : 2401, "state" : "SD" }
+{ "_id" : "57534", "city" : "HAMILL", "loc" : [ -99.69175199999999, 43.643942 ], "pop" : 78, "state" : "SD" }
+{ "_id" : "57536", "city" : "HARROLD", "loc" : [ -99.73816600000001, 44.521476 ], "pop" : 195, "state" : "SD" }
+{ "_id" : "57537", "city" : "HAYES", "loc" : [ -100.735938, 44.421898 ], "pop" : 191, "state" : "SD" }
+{ "_id" : "57538", "city" : "HERRICK", "loc" : [ -99.21726700000001, 43.101186 ], "pop" : 337, "state" : "SD" }
+{ "_id" : "57540", "city" : "HOLABIRD", "loc" : [ -99.59429900000001, 44.517327 ], "pop" : 44, "state" : "SD" }
+{ "_id" : "57541", "city" : "IDEAL", "loc" : [ -99.927949, 43.559612 ], "pop" : 473, "state" : "SD" }
+{ "_id" : "57542", "city" : "IONA", "loc" : [ -99.488073, 43.575756 ], "pop" : 146, "state" : "SD" }
+{ "_id" : "57543", "city" : "KADOKA", "loc" : [ -101.552272, 43.84457 ], "pop" : 1024, "state" : "SD" }
+{ "_id" : "57544", "city" : "KENNEBEC", "loc" : [ -99.850191, 43.892139 ], "pop" : 495, "state" : "SD" }
+{ "_id" : "57545", "city" : "KEYAPAHA", "loc" : [ -100.163958, 43.073497 ], "pop" : 48, "state" : "SD" }
+{ "_id" : "57547", "city" : "LONG VALLEY", "loc" : [ -101.382145, 43.569784 ], "pop" : 214, "state" : "SD" }
+{ "_id" : "57548", "city" : "LOWER BRULE", "loc" : [ -99.613896, 44.093692 ], "pop" : 1118, "state" : "SD" }
+{ "_id" : "57551", "city" : "VETAL", "loc" : [ -101.740814, 43.178543 ], "pop" : 2159, "state" : "SD" }
+{ "_id" : "57552", "city" : "OTTUMWA", "loc" : [ -101.292442, 44.237443 ], "pop" : 789, "state" : "SD" }
+{ "_id" : "57553", "city" : "MILESVILLE", "loc" : [ -101.752276, 44.428259 ], "pop" : 191, "state" : "SD" }
+{ "_id" : "57555", "city" : "MISSION", "loc" : [ -100.595364, 43.285017 ], "pop" : 3169, "state" : "SD" }
+{ "_id" : "57557", "city" : "MISSION RIDGE", "loc" : [ -100.894553, 44.623851 ], "pop" : 83, "state" : "SD" }
+{ "_id" : "57559", "city" : "MURDO", "loc" : [ -100.712107, 43.896115 ], "pop" : 855, "state" : "SD" }
+{ "_id" : "57560", "city" : "NORRIS", "loc" : [ -101.151664, 43.466176 ], "pop" : 322, "state" : "SD" }
+{ "_id" : "57562", "city" : "OKATON", "loc" : [ -100.935054, 43.934157 ], "pop" : 165, "state" : "SD" }
+{ "_id" : "57564", "city" : "ONIDA", "loc" : [ -100.095667, 44.712543 ], "pop" : 1500, "state" : "SD" }
+{ "_id" : "57566", "city" : "PARMELEE", "loc" : [ -101.008089, 43.311716 ], "pop" : 1272, "state" : "SD" }
+{ "_id" : "57567", "city" : "PHILIP", "loc" : [ -101.687611, 44.055006 ], "pop" : 1644, "state" : "SD" }
+{ "_id" : "57568", "city" : "PRESHO", "loc" : [ -100.074645, 43.899538 ], "pop" : 897, "state" : "SD" }
+{ "_id" : "57569", "city" : "RELIANCE", "loc" : [ -99.485668, 43.830241 ], "pop" : 790, "state" : "SD" }
+{ "_id" : "57571", "city" : "SAINT CHARLES", "loc" : [ -99.090969, 43.108893 ], "pop" : 85, "state" : "SD" }
+{ "_id" : "57572", "city" : "SAINT FRANCIS", "loc" : [ -100.88502, 43.191017 ], "pop" : 3917, "state" : "SD" }
+{ "_id" : "57574", "city" : "TUTHILL", "loc" : [ -101.470116, 43.119623 ], "pop" : 286, "state" : "SD" }
+{ "_id" : "57576", "city" : "VIVIAN", "loc" : [ -100.285989, 43.95352 ], "pop" : 192, "state" : "SD" }
+{ "_id" : "57577", "city" : "WANBLEE", "loc" : [ -101.721856, 43.55893 ], "pop" : 1269, "state" : "SD" }
+{ "_id" : "57578", "city" : "WEWELA", "loc" : [ -99.747317, 43.079352 ], "pop" : 207, "state" : "SD" }
+{ "_id" : "57579", "city" : "WHITE RIVER", "loc" : [ -100.74487, 43.56662 ], "pop" : 1259, "state" : "SD" }
+{ "_id" : "57580", "city" : "CLEARFIELD", "loc" : [ -99.861907, 43.355504 ], "pop" : 5111, "state" : "SD" }
+{ "_id" : "57584", "city" : "WITTEN", "loc" : [ -100.078291, 43.44982 ], "pop" : 118, "state" : "SD" }
+{ "_id" : "57585", "city" : "WOOD", "loc" : [ -100.437929, 43.536599 ], "pop" : 342, "state" : "SD" }
+{ "_id" : "57601", "city" : "MOBRIDGE", "loc" : [ -100.431488, 45.540723 ], "pop" : 4099, "state" : "SD" }
+{ "_id" : "57620", "city" : "BISON", "loc" : [ -102.482707, 45.516126 ], "pop" : 710, "state" : "SD" }
+{ "_id" : "57622", "city" : "CHERRY CREEK", "loc" : [ -101.65178, 44.621018 ], "pop" : 715, "state" : "SD" }
+{ "_id" : "57623", "city" : "DUPREE", "loc" : [ -101.63368, 45.007851 ], "pop" : 1441, "state" : "SD" }
+{ "_id" : "57626", "city" : "FAITH", "loc" : [ -102.054142, 44.992609 ], "pop" : 660, "state" : "SD" }
+{ "_id" : "57628", "city" : "FIRESTEEL", "loc" : [ -101.223461, 45.430736 ], "pop" : 50, "state" : "SD" }
+{ "_id" : "57629", "city" : "GLAD VALLEY", "loc" : [ -101.795168, 45.43696 ], "pop" : 64, "state" : "SD" }
+{ "_id" : "57630", "city" : "GLENCROSS", "loc" : [ -100.894417, 45.450549 ], "pop" : 56, "state" : "SD" }
+{ "_id" : "57631", "city" : "GLENHAM", "loc" : [ -100.27156, 45.53351 ], "pop" : 134, "state" : "SD" }
+{ "_id" : "57632", "city" : "HERREID", "loc" : [ -100.048983, 45.845164 ], "pop" : 829, "state" : "SD" }
+{ "_id" : "57633", "city" : "ISABEL", "loc" : [ -101.273637, 45.064016 ], "pop" : 3606, "state" : "SD" }
+{ "_id" : "57634", "city" : "KELDRON", "loc" : [ -101.939465, 45.902221 ], "pop" : 72, "state" : "SD" }
+{ "_id" : "57638", "city" : "LEMMON", "loc" : [ -102.192772, 45.915892 ], "pop" : 2127, "state" : "SD" }
+{ "_id" : "57640", "city" : "LODGEPOLE", "loc" : [ -102.759917, 45.823193 ], "pop" : 216, "state" : "SD" }
+{ "_id" : "57641", "city" : "MC INTOSH", "loc" : [ -101.500393, 45.81244 ], "pop" : 719, "state" : "SD" }
+{ "_id" : "57642", "city" : "MC LAUGHLIN", "loc" : [ -100.877596, 45.748884 ], "pop" : 2545, "state" : "SD" }
+{ "_id" : "57643", "city" : "MAHTO", "loc" : [ -100.658897, 45.767644 ], "pop" : 31, "state" : "SD" }
+{ "_id" : "57644", "city" : "MEADOW", "loc" : [ -102.284425, 45.353769 ], "pop" : 530, "state" : "SD" }
+{ "_id" : "57645", "city" : "MORRISTOWN", "loc" : [ -101.699838, 45.900642 ], "pop" : 190, "state" : "SD" }
+{ "_id" : "57646", "city" : "MOUND CITY", "loc" : [ -100.047856, 45.678645 ], "pop" : 548, "state" : "SD" }
+{ "_id" : "57647", "city" : "PARADE", "loc" : [ -100.743399, 45.108068 ], "pop" : 819, "state" : "SD" }
+{ "_id" : "57648", "city" : "POLLOCK", "loc" : [ -100.287518, 45.889043 ], "pop" : 493, "state" : "SD" }
+{ "_id" : "57649", "city" : "PRAIRIE CITY", "loc" : [ -102.80847, 45.581342 ], "pop" : 172, "state" : "SD" }
+{ "_id" : "57650", "city" : "RALPH", "loc" : [ -103.035552, 45.855365 ], "pop" : 101, "state" : "SD" }
+{ "_id" : "57651", "city" : "REVA", "loc" : [ -103.069163, 45.527653 ], "pop" : 332, "state" : "SD" }
+{ "_id" : "57653", "city" : "SHADEHILL", "loc" : [ -102.189131, 45.669855 ], "pop" : 49, "state" : "SD" }
+{ "_id" : "57656", "city" : "TIMBER LAKE", "loc" : [ -101.035077, 45.392737 ], "pop" : 939, "state" : "SD" }
+{ "_id" : "57657", "city" : "TRAIL CITY", "loc" : [ -100.682902, 45.440082 ], "pop" : 53, "state" : "SD" }
+{ "_id" : "57658", "city" : "WAKPALA", "loc" : [ -100.533176, 45.700617 ], "pop" : 582, "state" : "SD" }
+{ "_id" : "57660", "city" : "WATAUGA", "loc" : [ -101.512936, 45.927593 ], "pop" : 56, "state" : "SD" }
+{ "_id" : "57701", "city" : "ROCKERVILLE", "loc" : [ -103.200259, 44.077041 ], "pop" : 45328, "state" : "SD" }
+{ "_id" : "57702", "city" : "SILVER CITY", "loc" : [ -103.283406, 44.069796 ], "pop" : 20904, "state" : "SD" }
+{ "_id" : "57706", "city" : "ELLSWORTH AFB", "loc" : [ -103.07591, 44.144655 ], "pop" : 6355, "state" : "SD" }
+{ "_id" : "57708", "city" : "BETHLEHEM", "loc" : [ -103.461246, 44.288967 ], "pop" : 374, "state" : "SD" }
+{ "_id" : "57714", "city" : "ALLEN", "loc" : [ -101.932858, 43.290818 ], "pop" : 761, "state" : "SD" }
+{ "_id" : "57716", "city" : "DENBY", "loc" : [ -102.173776, 43.078962 ], "pop" : 435, "state" : "SD" }
+{ "_id" : "57717", "city" : "BELLE FOURCHE", "loc" : [ -103.839601, 44.672281 ], "pop" : 5841, "state" : "SD" }
+{ "_id" : "57718", "city" : "BLACK HAWK", "loc" : [ -103.348634, 44.151173 ], "pop" : 7418, "state" : "SD" }
+{ "_id" : "57719", "city" : "BOX ELDER", "loc" : [ -103.068237, 44.119858 ], "pop" : 3690, "state" : "SD" }
+{ "_id" : "57720", "city" : "BUFFALO", "loc" : [ -103.582605, 45.574001 ], "pop" : 913, "state" : "SD" }
+{ "_id" : "57722", "city" : "BUFFALO GAP", "loc" : [ -103.315749, 43.495762 ], "pop" : 302, "state" : "SD" }
+{ "_id" : "57724", "city" : "SKY RANCH", "loc" : [ -103.963232, 45.595289 ], "pop" : 258, "state" : "SD" }
+{ "_id" : "57725", "city" : "CAPUTA", "loc" : [ -103.023406, 43.980116 ], "pop" : 578, "state" : "SD" }
+{ "_id" : "57729", "city" : "CREIGHTON", "loc" : [ -102.177043, 44.283087 ], "pop" : 127, "state" : "SD" }
+{ "_id" : "57730", "city" : "CRAZY HORSE", "loc" : [ -103.618465, 43.740886 ], "pop" : 4781, "state" : "SD" }
+{ "_id" : "57732", "city" : "DEADWOOD", "loc" : [ -103.699939, 44.356628 ], "pop" : 2726, "state" : "SD" }
+{ "_id" : "57735", "city" : "EDGEMONT", "loc" : [ -103.811018, 43.287361 ], "pop" : 1264, "state" : "SD" }
+{ "_id" : "57736", "city" : "ELM SPRINGS", "loc" : [ -102.631208, 44.239743 ], "pop" : 222, "state" : "SD" }
+{ "_id" : "57737", "city" : "ENNING", "loc" : [ -102.6208, 44.538884 ], "pop" : 275, "state" : "SD" }
+{ "_id" : "57738", "city" : "FAIRBURN", "loc" : [ -103.213335, 43.66228 ], "pop" : 203, "state" : "SD" }
+{ "_id" : "57741", "city" : "FORT MEADE", "loc" : [ -103.47233, 44.409097 ], "pop" : 124, "state" : "SD" }
+{ "_id" : "57742", "city" : "FRUITDALE", "loc" : [ -103.689568, 44.660039 ], "pop" : 234, "state" : "SD" }
+{ "_id" : "57744", "city" : "HERMOSA", "loc" : [ -103.20596, 43.818845 ], "pop" : 919, "state" : "SD" }
+{ "_id" : "57745", "city" : "HILL CITY", "loc" : [ -103.578158, 43.93768 ], "pop" : 1671, "state" : "SD" }
+{ "_id" : "57747", "city" : "HOT SPRINGS", "loc" : [ -103.476555, 43.422308 ], "pop" : 5467, "state" : "SD" }
+{ "_id" : "57748", "city" : "PLAINVIEW", "loc" : [ -102.215763, 44.534952 ], "pop" : 153, "state" : "SD" }
+{ "_id" : "57750", "city" : "INTERIOR", "loc" : [ -101.964238, 43.731892 ], "pop" : 127, "state" : "SD" }
+{ "_id" : "57751", "city" : "KEYSTONE", "loc" : [ -103.335235, 43.969604 ], "pop" : 2573, "state" : "SD" }
+{ "_id" : "57752", "city" : "KYLE", "loc" : [ -102.212419, 43.439437 ], "pop" : 1424, "state" : "SD" }
+{ "_id" : "57754", "city" : "SPEARFISH CANYON", "loc" : [ -103.769841, 44.349012 ], "pop" : 4626, "state" : "SD" }
+{ "_id" : "57755", "city" : "LUDLOW", "loc" : [ -103.31115, 45.874655 ], "pop" : 142, "state" : "SD" }
+{ "_id" : "57756", "city" : "MANDERSON", "loc" : [ -102.374493, 43.309844 ], "pop" : 1027, "state" : "SD" }
+{ "_id" : "57757", "city" : "MARCUS", "loc" : [ -102.330697, 44.674678 ], "pop" : 28, "state" : "SD" }
+{ "_id" : "57758", "city" : "MUD BUTTE", "loc" : [ -102.803129, 45.031046 ], "pop" : 104, "state" : "SD" }
+{ "_id" : "57759", "city" : "NEMO", "loc" : [ -103.544863, 44.209718 ], "pop" : 393, "state" : "SD" }
+{ "_id" : "57760", "city" : "NEWELL", "loc" : [ -103.391359, 44.740979 ], "pop" : 1223, "state" : "SD" }
+{ "_id" : "57761", "city" : "NEW UNDERWOOD", "loc" : [ -102.813635, 44.087354 ], "pop" : 763, "state" : "SD" }
+{ "_id" : "57762", "city" : "NISLAND", "loc" : [ -103.540176, 44.666539 ], "pop" : 313, "state" : "SD" }
+{ "_id" : "57763", "city" : "OELRICHS", "loc" : [ -103.216181, 43.155063 ], "pop" : 284, "state" : "SD" }
+{ "_id" : "57765", "city" : "OPAL", "loc" : [ -102.477752, 44.867111 ], "pop" : 235, "state" : "SD" }
+{ "_id" : "57766", "city" : "ORAL", "loc" : [ -103.183215, 43.387587 ], "pop" : 265, "state" : "SD" }
+{ "_id" : "57767", "city" : "OWANKA", "loc" : [ -102.562776, 44.063078 ], "pop" : 69, "state" : "SD" }
+{ "_id" : "57769", "city" : "PIEDMONT", "loc" : [ -103.368818, 44.228744 ], "pop" : 1337, "state" : "SD" }
+{ "_id" : "57770", "city" : "PINE RIDGE", "loc" : [ -102.598352, 43.112401 ], "pop" : 5720, "state" : "SD" }
+{ "_id" : "57772", "city" : "PORCUPINE", "loc" : [ -102.223448, 43.293979 ], "pop" : 470, "state" : "SD" }
+{ "_id" : "57774", "city" : "PROVO", "loc" : [ -103.866588, 43.173599 ], "pop" : 32, "state" : "SD" }
+{ "_id" : "57775", "city" : "COTTONWOOD", "loc" : [ -102.069706, 44.07721 ], "pop" : 89, "state" : "SD" }
+{ "_id" : "57777", "city" : "REDOWL", "loc" : [ -102.65923, 44.720224 ], "pop" : 16, "state" : "SD" }
+{ "_id" : "57778", "city" : "ROCHFORD", "loc" : [ -103.657621, 44.072318 ], "pop" : 251, "state" : "SD" }
+{ "_id" : "57779", "city" : "SAINT ONGE", "loc" : [ -103.734426, 44.552225 ], "pop" : 317, "state" : "SD" }
+{ "_id" : "57780", "city" : "SCENIC", "loc" : [ -102.535309, 43.799368 ], "pop" : 128, "state" : "SD" }
+{ "_id" : "57782", "city" : "SMITHWICK", "loc" : [ -103.198826, 43.26837 ], "pop" : 15, "state" : "SD" }
+{ "_id" : "57783", "city" : "SPEARFISH", "loc" : [ -103.864962, 44.494625 ], "pop" : 11088, "state" : "SD" }
+{ "_id" : "57785", "city" : "HEREFORD", "loc" : [ -103.477158, 44.413077 ], "pop" : 8209, "state" : "SD" }
+{ "_id" : "57787", "city" : "STONEVILLE", "loc" : [ -102.79796, 44.638004 ], "pop" : 204, "state" : "SD" }
+{ "_id" : "57788", "city" : "VALE", "loc" : [ -103.379499, 44.622235 ], "pop" : 303, "state" : "SD" }
+{ "_id" : "57790", "city" : "WALL", "loc" : [ -102.224546, 43.981232 ], "pop" : 1070, "state" : "SD" }
+{ "_id" : "57791", "city" : "WASTA", "loc" : [ -102.347077, 44.093707 ], "pop" : 217, "state" : "SD" }
+{ "_id" : "57792", "city" : "WHITE OWL", "loc" : [ -102.445195, 44.618247 ], "pop" : 92, "state" : "SD" }
+{ "_id" : "57793", "city" : "WHITEWOOD", "loc" : [ -103.637039, 44.458855 ], "pop" : 1505, "state" : "SD" }
+{ "_id" : "57794", "city" : "WOUNDED KNEE", "loc" : [ -102.402157, 43.185194 ], "pop" : 826, "state" : "SD" }
+{ "_id" : "57795", "city" : "ZEONA", "loc" : [ -102.7793, 45.251481 ], "pop" : 8, "state" : "SD" }
+{ "_id" : "58002", "city" : "ABSARAKA", "loc" : [ -97.388769, 47.014359 ], "pop" : 124, "state" : "ND" }
+{ "_id" : "58003", "city" : "ALICE", "loc" : [ -97.531819, 46.768892 ], "pop" : 255, "state" : "ND" }
+{ "_id" : "58004", "city" : "AMENIA", "loc" : [ -97.204808, 47.019395 ], "pop" : 321, "state" : "ND" }
+{ "_id" : "58005", "city" : "ARGUSVILLE", "loc" : [ -96.905764, 47.10664 ], "pop" : 353, "state" : "ND" }
+{ "_id" : "58006", "city" : "ARTHUR", "loc" : [ -97.209737, 47.104774 ], "pop" : 543, "state" : "ND" }
+{ "_id" : "58007", "city" : "AYR", "loc" : [ -97.572841, 47.019576 ], "pop" : 187, "state" : "ND" }
+{ "_id" : "58008", "city" : "BARNEY", "loc" : [ -96.970772, 46.249621 ], "pop" : 222, "state" : "ND" }
+{ "_id" : "58009", "city" : "BLANCHARD", "loc" : [ -97.262079, 47.353664 ], "pop" : 144, "state" : "ND" }
+{ "_id" : "58011", "city" : "BUFFALO", "loc" : [ -97.53515899999999, 46.926351 ], "pop" : 281, "state" : "ND" }
+{ "_id" : "58012", "city" : "CASSELTON", "loc" : [ -97.213821, 46.899195 ], "pop" : 1838, "state" : "ND" }
+{ "_id" : "58013", "city" : "CAYUGA", "loc" : [ -97.405941, 46.132589 ], "pop" : 442, "state" : "ND" }
+{ "_id" : "58014", "city" : "CHAFFEE", "loc" : [ -97.357753, 46.766477 ], "pop" : 189, "state" : "ND" }
+{ "_id" : "58015", "city" : "CHRISTINE", "loc" : [ -96.790882, 46.552157 ], "pop" : 377, "state" : "ND" }
+{ "_id" : "58016", "city" : "CLIFFORD", "loc" : [ -97.409961, 47.356946 ], "pop" : 128, "state" : "ND" }
+{ "_id" : "58017", "city" : "BRAMPTON", "loc" : [ -97.80954300000001, 46.089106 ], "pop" : 631, "state" : "ND" }
+{ "_id" : "58018", "city" : "COLFAX", "loc" : [ -96.979001, 46.497153 ], "pop" : 414, "state" : "ND" }
+{ "_id" : "58021", "city" : "DAVENPORT", "loc" : [ -97.087073, 46.696811 ], "pop" : 349, "state" : "ND" }
+{ "_id" : "58027", "city" : "ENDERLIN", "loc" : [ -97.61055399999999, 46.607898 ], "pop" : 1732, "state" : "ND" }
+{ "_id" : "58029", "city" : "ERIE", "loc" : [ -97.384851, 47.112803 ], "pop" : 135, "state" : "ND" }
+{ "_id" : "58030", "city" : "FAIRMOUNT", "loc" : [ -96.63081099999999, 46.042658 ], "pop" : 780, "state" : "ND" }
+{ "_id" : "58031", "city" : "FINGAL", "loc" : [ -97.781198, 46.772754 ], "pop" : 349, "state" : "ND" }
+{ "_id" : "58032", "city" : "FORMAN", "loc" : [ -97.698643, 46.072075 ], "pop" : 72, "state" : "ND" }
+{ "_id" : "58033", "city" : "ENGLEVALE", "loc" : [ -97.90548200000001, 46.478188 ], "pop" : 764, "state" : "ND" }
+{ "_id" : "58035", "city" : "GALESBURG", "loc" : [ -97.374599, 47.27779 ], "pop" : 344, "state" : "ND" }
+{ "_id" : "58036", "city" : "GARDNER", "loc" : [ -96.990116, 47.1252 ], "pop" : 200, "state" : "ND" }
+{ "_id" : "58038", "city" : "GRANDIN", "loc" : [ -97.02067599999999, 47.215769 ], "pop" : 365, "state" : "ND" }
+{ "_id" : "58039", "city" : "GREAT BEND", "loc" : [ -96.817143, 46.154369 ], "pop" : 235, "state" : "ND" }
+{ "_id" : "58040", "city" : "CRETE", "loc" : [ -97.86685300000001, 46.230455 ], "pop" : 243, "state" : "ND" }
+{ "_id" : "58041", "city" : "HANKINSON", "loc" : [ -96.899069, 46.055797 ], "pop" : 1546, "state" : "ND" }
+{ "_id" : "58042", "city" : "PROSPER", "loc" : [ -96.90097299999999, 46.996497 ], "pop" : 1045, "state" : "ND" }
+{ "_id" : "58043", "city" : "HAVANA", "loc" : [ -97.60945, 45.964413 ], "pop" : 272, "state" : "ND" }
+{ "_id" : "58045", "city" : "KELSO", "loc" : [ -97.05602399999999, 47.394168 ], "pop" : 2398, "state" : "ND" }
+{ "_id" : "58046", "city" : "COLGATE", "loc" : [ -97.784865, 47.19995 ], "pop" : 90, "state" : "ND" }
+{ "_id" : "58047", "city" : "HICKSON", "loc" : [ -96.860941, 46.739267 ], "pop" : 2056, "state" : "ND" }
+{ "_id" : "58048", "city" : "HUNTER", "loc" : [ -97.251648, 47.19132 ], "pop" : 512, "state" : "ND" }
+{ "_id" : "58049", "city" : "HASTINGS", "loc" : [ -97.999791, 46.705548 ], "pop" : 355, "state" : "ND" }
+{ "_id" : "58051", "city" : "KINDRED", "loc" : [ -97.004919, 46.654296 ], "pop" : 907, "state" : "ND" }
+{ "_id" : "58052", "city" : "LEONARD", "loc" : [ -97.272488, 46.659324 ], "pop" : 554, "state" : "ND" }
+{ "_id" : "58053", "city" : "GENESEO", "loc" : [ -97.144429, 46.073885 ], "pop" : 1494, "state" : "ND" }
+{ "_id" : "58054", "city" : "ELLIOTT", "loc" : [ -97.658895, 46.420133 ], "pop" : 3078, "state" : "ND" }
+{ "_id" : "58056", "city" : "LUVERNE", "loc" : [ -97.72962200000001, 47.315052 ], "pop" : 893, "state" : "ND" }
+{ "_id" : "58057", "city" : "MCLEOD", "loc" : [ -97.313892, 46.41027 ], "pop" : 70, "state" : "ND" }
+{ "_id" : "58058", "city" : "MANTADOR", "loc" : [ -96.957004, 46.159935 ], "pop" : 239, "state" : "ND" }
+{ "_id" : "58059", "city" : "DURBIN", "loc" : [ -97.051366, 46.867546 ], "pop" : 1665, "state" : "ND" }
+{ "_id" : "58060", "city" : "DELAMERE", "loc" : [ -97.433724, 46.255074 ], "pop" : 927, "state" : "ND" }
+{ "_id" : "58061", "city" : "MOORETON", "loc" : [ -96.85072599999999, 46.261537 ], "pop" : 313, "state" : "ND" }
+{ "_id" : "58062", "city" : "NOME", "loc" : [ -97.791099, 46.674834 ], "pop" : 284, "state" : "ND" }
+{ "_id" : "58063", "city" : "ORISKA", "loc" : [ -97.785331, 46.943251 ], "pop" : 332, "state" : "ND" }
+{ "_id" : "58064", "city" : "PAGE", "loc" : [ -97.596665, 47.151512 ], "pop" : 586, "state" : "ND" }
+{ "_id" : "58067", "city" : "RUTLAND", "loc" : [ -97.548284, 46.073813 ], "pop" : 1166, "state" : "ND" }
+{ "_id" : "58068", "city" : "SHELDON", "loc" : [ -97.454261, 46.554784 ], "pop" : 546, "state" : "ND" }
+{ "_id" : "58069", "city" : "STIRUM", "loc" : [ -97.654233, 46.229891 ], "pop" : 776, "state" : "ND" }
+{ "_id" : "58071", "city" : "TOWER CITY", "loc" : [ -97.659392, 46.911873 ], "pop" : 417, "state" : "ND" }
+{ "_id" : "58072", "city" : "VALLEY CITY", "loc" : [ -98.003316, 46.92681 ], "pop" : 8633, "state" : "ND" }
+{ "_id" : "58075", "city" : "DWIGHT", "loc" : [ -96.633934, 46.279842 ], "pop" : 10683, "state" : "ND" }
+{ "_id" : "58077", "city" : "WALCOTT", "loc" : [ -97.001442, 46.583529 ], "pop" : 740, "state" : "ND" }
+{ "_id" : "58078", "city" : "RIVERSIDE", "loc" : [ -96.89500200000001, 46.869523 ], "pop" : 12422, "state" : "ND" }
+{ "_id" : "58079", "city" : "EMBDEN", "loc" : [ -97.391694, 46.875015 ], "pop" : 367, "state" : "ND" }
+{ "_id" : "58081", "city" : "WYNDMERE", "loc" : [ -97.128912, 46.289137 ], "pop" : 1127, "state" : "ND" }
+{ "_id" : "58102", "city" : "NORTH RIVER", "loc" : [ -96.793577, 46.900878 ], "pop" : 33408, "state" : "ND" }
+{ "_id" : "58103", "city" : "FARGO", "loc" : [ -96.812252, 46.856406 ], "pop" : 38483, "state" : "ND" }
+{ "_id" : "58104", "city" : "BRIARWOOD", "loc" : [ -96.823846, 46.81492 ], "pop" : 5170, "state" : "ND" }
+{ "_id" : "58201", "city" : "GRAND FORKS", "loc" : [ -97.04463, 47.901041 ], "pop" : 31138, "state" : "ND" }
+{ "_id" : "58203", "city" : "GRAND FORKS", "loc" : [ -97.067156, 47.927217 ], "pop" : 19056, "state" : "ND" }
+{ "_id" : "58205", "city" : "GRAND FORKS", "loc" : [ -97.370802, 47.959499 ], "pop" : 9333, "state" : "ND" }
+{ "_id" : "58210", "city" : "ADAMS", "loc" : [ -98.086741, 48.422299 ], "pop" : 312, "state" : "ND" }
+{ "_id" : "58212", "city" : "ANETA", "loc" : [ -97.98140600000001, 47.699262 ], "pop" : 426, "state" : "ND" }
+{ "_id" : "58213", "city" : "ARDOCH", "loc" : [ -97.253534, 48.226911 ], "pop" : 355, "state" : "ND" }
+{ "_id" : "58214", "city" : "ARVILLA", "loc" : [ -97.48712399999999, 47.909292 ], "pop" : 529, "state" : "ND" }
+{ "_id" : "58216", "city" : "BATHGATE", "loc" : [ -97.483215, 48.868632 ], "pop" : 169, "state" : "ND" }
+{ "_id" : "58218", "city" : "BUXTON", "loc" : [ -97.089259, 47.616314 ], "pop" : 952, "state" : "ND" }
+{ "_id" : "58219", "city" : "CALEDONIA", "loc" : [ -96.90847599999999, 47.457645 ], "pop" : 154, "state" : "ND" }
+{ "_id" : "58220", "city" : "CONCRETE", "loc" : [ -97.657191, 48.794341 ], "pop" : 2758, "state" : "ND" }
+{ "_id" : "58222", "city" : "CRYSTAL", "loc" : [ -97.673846, 48.592387 ], "pop" : 384, "state" : "ND" }
+{ "_id" : "58223", "city" : "CUMMINGS", "loc" : [ -96.991287, 47.537023 ], "pop" : 286, "state" : "ND" }
+{ "_id" : "58224", "city" : "DAHLEN", "loc" : [ -97.957269, 48.159896 ], "pop" : 103, "state" : "ND" }
+{ "_id" : "58225", "city" : "BOWESMONT", "loc" : [ -97.19922200000001, 48.578569 ], "pop" : 1233, "state" : "ND" }
+{ "_id" : "58227", "city" : "GARDAR", "loc" : [ -97.89018799999999, 48.490164 ], "pop" : 859, "state" : "ND" }
+{ "_id" : "58228", "city" : "EMERADO", "loc" : [ -97.263012, 47.921376 ], "pop" : 1690, "state" : "ND" }
+{ "_id" : "58229", "city" : "FAIRDALE", "loc" : [ -98.206587, 48.481924 ], "pop" : 274, "state" : "ND" }
+{ "_id" : "58230", "city" : "FINLEY", "loc" : [ -97.744242, 47.530611 ], "pop" : 1403, "state" : "ND" }
+{ "_id" : "58231", "city" : "FORDVILLE", "loc" : [ -97.802238, 48.22119 ], "pop" : 377, "state" : "ND" }
+{ "_id" : "58233", "city" : "FOREST RIVER", "loc" : [ -97.460476, 48.225094 ], "pop" : 284, "state" : "ND" }
+{ "_id" : "58235", "city" : "HONEYFORD", "loc" : [ -97.46329900000001, 48.077082 ], "pop" : 395, "state" : "ND" }
+{ "_id" : "58237", "city" : "NASH", "loc" : [ -97.41589500000001, 48.410783 ], "pop" : 6591, "state" : "ND" }
+{ "_id" : "58238", "city" : "HAMILTON", "loc" : [ -97.469302, 48.794249 ], "pop" : 135, "state" : "ND" }
+{ "_id" : "58239", "city" : "HANNAH", "loc" : [ -98.723693, 48.959446 ], "pop" : 141, "state" : "ND" }
+{ "_id" : "58240", "city" : "HATTON", "loc" : [ -97.432548, 47.638012 ], "pop" : 1081, "state" : "ND" }
+{ "_id" : "58241", "city" : "HENSEL", "loc" : [ -97.59622299999999, 48.673836 ], "pop" : 121, "state" : "ND" }
+{ "_id" : "58243", "city" : "HOOPLE", "loc" : [ -97.61833300000001, 48.51981 ], "pop" : 555, "state" : "ND" }
+{ "_id" : "58244", "city" : "ORR", "loc" : [ -97.681302, 48.118654 ], "pop" : 730, "state" : "ND" }
+{ "_id" : "58249", "city" : "LANGDON", "loc" : [ -98.35662000000001, 48.786562 ], "pop" : 3701, "state" : "ND" }
+{ "_id" : "58250", "city" : "LANKIN", "loc" : [ -98.006997, 48.295233 ], "pop" : 796, "state" : "ND" }
+{ "_id" : "58251", "city" : "MCCANNA", "loc" : [ -97.651792, 47.904048 ], "pop" : 2023, "state" : "ND" }
+{ "_id" : "58254", "city" : "KLOTEN", "loc" : [ -98.162999, 47.778981 ], "pop" : 925, "state" : "ND" }
+{ "_id" : "58255", "city" : "MAIDA", "loc" : [ -98.39482599999999, 48.949043 ], "pop" : 104, "state" : "ND" }
+{ "_id" : "58256", "city" : "MANVEL", "loc" : [ -97.194332, 48.085314 ], "pop" : 1033, "state" : "ND" }
+{ "_id" : "58257", "city" : "MAYVILLE", "loc" : [ -97.317645, 47.50138 ], "pop" : 2378, "state" : "ND" }
+{ "_id" : "58258", "city" : "MEKINOCK", "loc" : [ -97.489593, 47.980909 ], "pop" : 398, "state" : "ND" }
+{ "_id" : "58259", "city" : "WHITMAN", "loc" : [ -98.12424300000001, 48.04144 ], "pop" : 624, "state" : "ND" }
+{ "_id" : "58260", "city" : "MILTON", "loc" : [ -98.01828500000001, 48.616963 ], "pop" : 248, "state" : "ND" }
+{ "_id" : "58261", "city" : "VOSS", "loc" : [ -97.333727, 48.298874 ], "pop" : 851, "state" : "ND" }
+{ "_id" : "58262", "city" : "MOUNTAIN", "loc" : [ -97.807569, 48.677341 ], "pop" : 435, "state" : "ND" }
+{ "_id" : "58265", "city" : "NECHE", "loc" : [ -97.542687, 48.979567 ], "pop" : 500, "state" : "ND" }
+{ "_id" : "58266", "city" : "NIAGARA", "loc" : [ -97.833431, 47.984817 ], "pop" : 164, "state" : "ND" }
+{ "_id" : "58267", "city" : "KEMPTON", "loc" : [ -97.56305399999999, 47.741756 ], "pop" : 1910, "state" : "ND" }
+{ "_id" : "58269", "city" : "OSNABROCK", "loc" : [ -98.23271, 48.641908 ], "pop" : 620, "state" : "ND" }
+{ "_id" : "58270", "city" : "PARK RIVER", "loc" : [ -97.743897, 48.403881 ], "pop" : 2139, "state" : "ND" }
+{ "_id" : "58271", "city" : "JOLIETTE", "loc" : [ -97.275611, 48.936124 ], "pop" : 907, "state" : "ND" }
+{ "_id" : "58272", "city" : "PETERSBURG", "loc" : [ -97.984033, 47.997973 ], "pop" : 404, "state" : "ND" }
+{ "_id" : "58273", "city" : "PISEK", "loc" : [ -97.702894, 48.297096 ], "pop" : 350, "state" : "ND" }
+{ "_id" : "58274", "city" : "PORTLAND", "loc" : [ -97.384303, 47.501542 ], "pop" : 887, "state" : "ND" }
+{ "_id" : "58275", "city" : "REYNOLDS", "loc" : [ -97.209153, 47.706776 ], "pop" : 470, "state" : "ND" }
+{ "_id" : "58276", "city" : "SAINT THOMAS", "loc" : [ -97.454508, 48.625223 ], "pop" : 607, "state" : "ND" }
+{ "_id" : "58277", "city" : "SHARON", "loc" : [ -97.905091, 47.606188 ], "pop" : 163, "state" : "ND" }
+{ "_id" : "58278", "city" : "THOMPSON", "loc" : [ -97.09620099999999, 47.77658 ], "pop" : 1705, "state" : "ND" }
+{ "_id" : "58281", "city" : "WALES", "loc" : [ -98.55964899999999, 48.921647 ], "pop" : 122, "state" : "ND" }
+{ "_id" : "58282", "city" : "BACKOO", "loc" : [ -97.881927, 48.91103 ], "pop" : 1759, "state" : "ND" }
+{ "_id" : "58301", "city" : "DEVILS LAKE", "loc" : [ -98.861588, 48.113162 ], "pop" : 10324, "state" : "ND" }
+{ "_id" : "58311", "city" : "LOMA", "loc" : [ -98.622545, 48.636847 ], "pop" : 272, "state" : "ND" }
+{ "_id" : "58315", "city" : "BARTON", "loc" : [ -100.204429, 48.461084 ], "pop" : 140, "state" : "ND" }
+{ "_id" : "58316", "city" : "BELCOURT", "loc" : [ -99.768754, 48.837862 ], "pop" : 5415, "state" : "ND" }
+{ "_id" : "58317", "city" : "BISBEE", "loc" : [ -99.363592, 48.555196 ], "pop" : 507, "state" : "ND" }
+{ "_id" : "58318", "city" : "BOTTINEAU", "loc" : [ -100.432894, 48.845137 ], "pop" : 4356, "state" : "ND" }
+{ "_id" : "58319", "city" : "BREMEN", "loc" : [ -99.37156400000001, 47.727212 ], "pop" : 108, "state" : "ND" }
+{ "_id" : "58320", "city" : "BRINSMADE", "loc" : [ -99.31238399999999, 48.156805 ], "pop" : 168, "state" : "ND" }
+{ "_id" : "58321", "city" : "BROCKET", "loc" : [ -98.35585399999999, 48.225527 ], "pop" : 131, "state" : "ND" }
+{ "_id" : "58323", "city" : "CALVIN", "loc" : [ -98.92423599999999, 48.80843 ], "pop" : 117, "state" : "ND" }
+{ "_id" : "58324", "city" : "MAZA", "loc" : [ -99.194553, 48.485479 ], "pop" : 1800, "state" : "ND" }
+{ "_id" : "58325", "city" : "CHURCHS FERRY", "loc" : [ -99.141187, 48.286206 ], "pop" : 206, "state" : "ND" }
+{ "_id" : "58327", "city" : "SOUTHAM", "loc" : [ -98.621236, 48.053028 ], "pop" : 272, "state" : "ND" }
+{ "_id" : "58328", "city" : "DOYON", "loc" : [ -98.50675699999999, 48.081067 ], "pop" : 121, "state" : "ND" }
+{ "_id" : "58329", "city" : "SAN HAVEN", "loc" : [ -100.031105, 48.84801 ], "pop" : 3092, "state" : "ND" }
+{ "_id" : "58330", "city" : "EDMORE", "loc" : [ -98.445756, 48.43084 ], "pop" : 572, "state" : "ND" }
+{ "_id" : "58331", "city" : "EGELAND", "loc" : [ -99.111475, 48.635537 ], "pop" : 297, "state" : "ND" }
+{ "_id" : "58332", "city" : "FILLMORE", "loc" : [ -99.703388, 48.072022 ], "pop" : 563, "state" : "ND" }
+{ "_id" : "58337", "city" : "HAMBERG", "loc" : [ -99.46829700000001, 47.779372 ], "pop" : 213, "state" : "ND" }
+{ "_id" : "58338", "city" : "HAMPDEN", "loc" : [ -98.65431599999999, 48.522892 ], "pop" : 148, "state" : "ND" }
+{ "_id" : "58339", "city" : "HANSBORO", "loc" : [ -99.383259, 48.86648 ], "pop" : 390, "state" : "ND" }
+{ "_id" : "58341", "city" : "MANFRED", "loc" : [ -99.932941, 47.768121 ], "pop" : 2769, "state" : "ND" }
+{ "_id" : "58342", "city" : "HEIMDAL", "loc" : [ -99.68914700000001, 47.799918 ], "pop" : 180, "state" : "ND" }
+{ "_id" : "58343", "city" : "KNOX", "loc" : [ -99.671274, 48.338812 ], "pop" : 100, "state" : "ND" }
+{ "_id" : "58344", "city" : "MAPES", "loc" : [ -98.341548, 48.035714 ], "pop" : 1327, "state" : "ND" }
+{ "_id" : "58345", "city" : "LAWTON", "loc" : [ -98.414199, 48.30326 ], "pop" : 178, "state" : "ND" }
+{ "_id" : "58346", "city" : "HARLOW", "loc" : [ -99.440123, 48.26681 ], "pop" : 980, "state" : "ND" }
+{ "_id" : "58348", "city" : "FLORA", "loc" : [ -99.54306099999999, 47.95074 ], "pop" : 1045, "state" : "ND" }
+{ "_id" : "58351", "city" : "MINNEWAUKAN", "loc" : [ -99.274323, 48.069777 ], "pop" : 554, "state" : "ND" }
+{ "_id" : "58352", "city" : "CALIO", "loc" : [ -98.842646, 48.654605 ], "pop" : 572, "state" : "ND" }
+{ "_id" : "58353", "city" : "MYLO", "loc" : [ -99.63287800000001, 48.635981 ], "pop" : 292, "state" : "ND" }
+{ "_id" : "58356", "city" : "BRANTFORD", "loc" : [ -99.078007, 47.679385 ], "pop" : 2309, "state" : "ND" }
+{ "_id" : "58357", "city" : "OBERON", "loc" : [ -99.140129, 47.948744 ], "pop" : 556, "state" : "ND" }
+{ "_id" : "58360", "city" : "OVERLY", "loc" : [ -100.175958, 48.679029 ], "pop" : 61, "state" : "ND" }
+{ "_id" : "58361", "city" : "PEKIN", "loc" : [ -98.326035, 47.769558 ], "pop" : 229, "state" : "ND" }
+{ "_id" : "58362", "city" : "PENN", "loc" : [ -99.06550900000001, 48.227106 ], "pop" : 165, "state" : "ND" }
+{ "_id" : "58363", "city" : "PERTH", "loc" : [ -99.383076, 48.681601 ], "pop" : 125, "state" : "ND" }
+{ "_id" : "58365", "city" : "ROCKLAKE", "loc" : [ -99.17962799999999, 48.821569 ], "pop" : 508, "state" : "ND" }
+{ "_id" : "58366", "city" : "NANSON", "loc" : [ -99.874375, 48.655224 ], "pop" : 1125, "state" : "ND" }
+{ "_id" : "58367", "city" : "ROLLA", "loc" : [ -99.61338600000001, 48.859423 ], "pop" : 1645, "state" : "ND" }
+{ "_id" : "58368", "city" : "PLEASANT LAKE", "loc" : [ -99.998954, 48.317264 ], "pop" : 4592, "state" : "ND" }
+{ "_id" : "58369", "city" : "SAINT JOHN", "loc" : [ -99.76476, 48.936588 ], "pop" : 1203, "state" : "ND" }
+{ "_id" : "58370", "city" : "SAINT MICHAEL", "loc" : [ -98.918058, 47.977363 ], "pop" : 2860, "state" : "ND" }
+{ "_id" : "58372", "city" : "SARLES", "loc" : [ -98.960562, 48.945921 ], "pop" : 172, "state" : "ND" }
+{ "_id" : "58374", "city" : "SHEYENNE", "loc" : [ -99.05832599999999, 47.818386 ], "pop" : 551, "state" : "ND" }
+{ "_id" : "58377", "city" : "STARKWEATHER", "loc" : [ -98.853903, 48.448802 ], "pop" : 456, "state" : "ND" }
+{ "_id" : "58380", "city" : "HAMAR", "loc" : [ -98.475218, 47.802014 ], "pop" : 463, "state" : "ND" }
+{ "_id" : "58381", "city" : "WARWICK", "loc" : [ -98.68095599999999, 47.891285 ], "pop" : 195, "state" : "ND" }
+{ "_id" : "58382", "city" : "WEBSTER", "loc" : [ -98.87394399999999, 48.322852 ], "pop" : 108, "state" : "ND" }
+{ "_id" : "58384", "city" : "WILLOW CITY", "loc" : [ -100.296802, 48.606205 ], "pop" : 453, "state" : "ND" }
+{ "_id" : "58385", "city" : "WOLFORD", "loc" : [ -99.662756, 48.480937 ], "pop" : 326, "state" : "ND" }
+{ "_id" : "58386", "city" : "BAKER", "loc" : [ -99.550489, 48.321709 ], "pop" : 74, "state" : "ND" }
+{ "_id" : "58401", "city" : "ELDRIDGE", "loc" : [ -98.706127, 46.905899 ], "pop" : 18347, "state" : "ND" }
+{ "_id" : "58411", "city" : "ALFRED", "loc" : [ -98.914671, 46.58588 ], "pop" : 121, "state" : "ND" }
+{ "_id" : "58412", "city" : "ARENA", "loc" : [ -100.17651, 47.134934 ], "pop" : 140, "state" : "ND" }
+{ "_id" : "58413", "city" : "ASHLEY", "loc" : [ -99.3164, 46.053677 ], "pop" : 1544, "state" : "ND" }
+{ "_id" : "58415", "city" : "BERLIN", "loc" : [ -98.523342, 46.400834 ], "pop" : 185, "state" : "ND" }
+{ "_id" : "58416", "city" : "BINFORD", "loc" : [ -98.354625, 47.573899 ], "pop" : 506, "state" : "ND" }
+{ "_id" : "58418", "city" : "BOWDON", "loc" : [ -99.701532, 47.434318 ], "pop" : 387, "state" : "ND" }
+{ "_id" : "58420", "city" : "BUCHANAN", "loc" : [ -98.81115800000001, 47.040917 ], "pop" : 162, "state" : "ND" }
+{ "_id" : "58421", "city" : "BORDULAC", "loc" : [ -99.108226, 47.453918 ], "pop" : 3104, "state" : "ND" }
+{ "_id" : "58422", "city" : "EMRICK", "loc" : [ -99.429677, 47.549857 ], "pop" : 115, "state" : "ND" }
+{ "_id" : "58423", "city" : "CHASELEY", "loc" : [ -99.824082, 47.449018 ], "pop" : 68, "state" : "ND" }
+{ "_id" : "58424", "city" : "WINDSOR", "loc" : [ -99.086596, 46.883242 ], "pop" : 378, "state" : "ND" }
+{ "_id" : "58425", "city" : "COOPERSTOWN", "loc" : [ -98.15333200000001, 47.452732 ], "pop" : 2313, "state" : "ND" }
+{ "_id" : "58426", "city" : "COURTENAY", "loc" : [ -98.54885, 47.227195 ], "pop" : 166, "state" : "ND" }
+{ "_id" : "58428", "city" : "DAWSON", "loc" : [ -99.763544, 46.829612 ], "pop" : 298, "state" : "ND" }
+{ "_id" : "58429", "city" : "SIBLEY", "loc" : [ -98.143863, 47.195503 ], "pop" : 376, "state" : "ND" }
+{ "_id" : "58430", "city" : "DENHOFF", "loc" : [ -100.263037, 47.570905 ], "pop" : 177, "state" : "ND" }
+{ "_id" : "58431", "city" : "DICKEY", "loc" : [ -98.46821199999999, 46.542565 ], "pop" : 211, "state" : "ND" }
+{ "_id" : "58432", "city" : "ECKELSON", "loc" : [ -98.366939, 46.916737 ], "pop" : 138, "state" : "ND" }
+{ "_id" : "58433", "city" : "MERRICOURT", "loc" : [ -98.70834600000001, 46.324969 ], "pop" : 1364, "state" : "ND" }
+{ "_id" : "58436", "city" : "ELLENDALE", "loc" : [ -98.51383, 46.007317 ], "pop" : 2446, "state" : "ND" }
+{ "_id" : "58438", "city" : "FESSENDEN", "loc" : [ -99.643361, 47.628644 ], "pop" : 1297, "state" : "ND" }
+{ "_id" : "58439", "city" : "FORBES", "loc" : [ -98.812414, 46.010926 ], "pop" : 287, "state" : "ND" }
+{ "_id" : "58440", "city" : "FREDONIA", "loc" : [ -99.262818, 46.353456 ], "pop" : 453, "state" : "ND" }
+{ "_id" : "58441", "city" : "FULLERTON", "loc" : [ -98.38821900000001, 46.195138 ], "pop" : 375, "state" : "ND" }
+{ "_id" : "58442", "city" : "GACKLE", "loc" : [ -99.21905599999999, 46.591263 ], "pop" : 866, "state" : "ND" }
+{ "_id" : "58443", "city" : "JUANITA", "loc" : [ -98.663951, 47.443185 ], "pop" : 539, "state" : "ND" }
+{ "_id" : "58444", "city" : "GOODRICH", "loc" : [ -100.118979, 47.471048 ], "pop" : 339, "state" : "ND" }
+{ "_id" : "58445", "city" : "GRACE CITY", "loc" : [ -98.809465, 47.55358 ], "pop" : 168, "state" : "ND" }
+{ "_id" : "58448", "city" : "WALUM", "loc" : [ -98.15718, 47.299693 ], "pop" : 374, "state" : "ND" }
+{ "_id" : "58450", "city" : "HEATON", "loc" : [ -99.57848199999999, 47.462249 ], "pop" : 76, "state" : "ND" }
+{ "_id" : "58451", "city" : "HURDSFIELD", "loc" : [ -99.94165, 47.438733 ], "pop" : 194, "state" : "ND" }
+{ "_id" : "58454", "city" : "NORTONVILLE", "loc" : [ -98.807661, 46.500996 ], "pop" : 575, "state" : "ND" }
+{ "_id" : "58455", "city" : "KENSAL", "loc" : [ -98.720579, 47.272609 ], "pop" : 384, "state" : "ND" }
+{ "_id" : "58456", "city" : "KULM", "loc" : [ -98.942724, 46.307274 ], "pop" : 634, "state" : "ND" }
+{ "_id" : "58458", "city" : "GRAND RAPIDS", "loc" : [ -98.30022, 46.361961 ], "pop" : 1493, "state" : "ND" }
+{ "_id" : "58460", "city" : "LEHR", "loc" : [ -99.349136, 46.258638 ], "pop" : 227, "state" : "ND" }
+{ "_id" : "58461", "city" : "LITCHVILLE", "loc" : [ -98.20327, 46.688788 ], "pop" : 421, "state" : "ND" }
+{ "_id" : "58463", "city" : "MCCLUSKY", "loc" : [ -100.451966, 47.489639 ], "pop" : 1002, "state" : "ND" }
+{ "_id" : "58464", "city" : "MCHENRY", "loc" : [ -98.572594, 47.560416 ], "pop" : 172, "state" : "ND" }
+{ "_id" : "58465", "city" : "MANFRED", "loc" : [ -99.764369, 47.711663 ], "pop" : 73, "state" : "ND" }
+{ "_id" : "58466", "city" : "MARION", "loc" : [ -98.253327, 46.571587 ], "pop" : 723, "state" : "ND" }
+{ "_id" : "58467", "city" : "MEDINA", "loc" : [ -99.31055600000001, 46.891951 ], "pop" : 622, "state" : "ND" }
+{ "_id" : "58471", "city" : "MONANGO", "loc" : [ -98.57962000000001, 46.193641 ], "pop" : 172, "state" : "ND" }
+{ "_id" : "58472", "city" : "ADRIAN", "loc" : [ -98.59764699999999, 46.654218 ], "pop" : 419, "state" : "ND" }
+{ "_id" : "58474", "city" : "GUELPH", "loc" : [ -98.099339, 46.128796 ], "pop" : 2569, "state" : "ND" }
+{ "_id" : "58475", "city" : "PETTIBONE", "loc" : [ -99.52789199999999, 47.119973 ], "pop" : 163, "state" : "ND" }
+{ "_id" : "58476", "city" : "EDMUNDS", "loc" : [ -99.00204100000001, 47.165715 ], "pop" : 624, "state" : "ND" }
+{ "_id" : "58477", "city" : "REGAN", "loc" : [ -100.522448, 47.152703 ], "pop" : 274, "state" : "ND" }
+{ "_id" : "58478", "city" : "LAKE WILLIAMS", "loc" : [ -99.70030199999999, 47.150765 ], "pop" : 505, "state" : "ND" }
+{ "_id" : "58479", "city" : "LEAL", "loc" : [ -98.220885, 47.071086 ], "pop" : 395, "state" : "ND" }
+{ "_id" : "58480", "city" : "SANBORN", "loc" : [ -98.233622, 46.927065 ], "pop" : 304, "state" : "ND" }
+{ "_id" : "58481", "city" : "SPIRITWOOD", "loc" : [ -98.64846799999999, 47.101601 ], "pop" : 263, "state" : "ND" }
+{ "_id" : "58482", "city" : "STEELE", "loc" : [ -99.933559, 46.852357 ], "pop" : 1277, "state" : "ND" }
+{ "_id" : "58483", "city" : "STREETER", "loc" : [ -99.29710799999999, 46.694999 ], "pop" : 482, "state" : "ND" }
+{ "_id" : "58484", "city" : "SUTTON", "loc" : [ -98.432044, 47.385355 ], "pop" : 110, "state" : "ND" }
+{ "_id" : "58486", "city" : "SYKESTON", "loc" : [ -99.39751, 47.436938 ], "pop" : 384, "state" : "ND" }
+{ "_id" : "58487", "city" : "TAPPEN", "loc" : [ -99.60189200000001, 46.83362 ], "pop" : 631, "state" : "ND" }
+{ "_id" : "58488", "city" : "TUTTLE", "loc" : [ -99.98728699999999, 47.162583 ], "pop" : 458, "state" : "ND" }
+{ "_id" : "58489", "city" : "VENTURIA", "loc" : [ -99.494253, 46.037075 ], "pop" : 164, "state" : "ND" }
+{ "_id" : "58490", "city" : "VERONA", "loc" : [ -98.089536, 46.371229 ], "pop" : 278, "state" : "ND" }
+{ "_id" : "58492", "city" : "WIMBLEDON", "loc" : [ -98.43291600000001, 47.143837 ], "pop" : 530, "state" : "ND" }
+{ "_id" : "58494", "city" : "WING", "loc" : [ -100.307159, 47.151939 ], "pop" : 376, "state" : "ND" }
+{ "_id" : "58495", "city" : "BURNSTAD", "loc" : [ -99.586005, 46.251617 ], "pop" : 1677, "state" : "ND" }
+{ "_id" : "58496", "city" : "WOODWORTH", "loc" : [ -99.34059999999999, 47.163639 ], "pop" : 340, "state" : "ND" }
+{ "_id" : "58497", "city" : "YPSILANTI", "loc" : [ -98.48763599999999, 46.771949 ], "pop" : 281, "state" : "ND" }
+{ "_id" : "58501", "city" : "BISMARCK", "loc" : [ -100.774755, 46.823448 ], "pop" : 36602, "state" : "ND" }
+{ "_id" : "58504", "city" : "LINCOLN", "loc" : [ -100.774411, 46.782463 ], "pop" : 19990, "state" : "ND" }
+{ "_id" : "58520", "city" : "ALMONT", "loc" : [ -101.522126, 46.704605 ], "pop" : 309, "state" : "ND" }
+{ "_id" : "58521", "city" : "BALDWIN", "loc" : [ -100.761464, 46.954338 ], "pop" : 1218, "state" : "ND" }
+{ "_id" : "58523", "city" : "BEULAH", "loc" : [ -101.807468, 47.270664 ], "pop" : 4363, "state" : "ND" }
+{ "_id" : "58524", "city" : "BRADDOCK", "loc" : [ -100.241577, 46.549885 ], "pop" : 401, "state" : "ND" }
+{ "_id" : "58528", "city" : "CANNON BALL", "loc" : [ -100.59749, 46.387446 ], "pop" : 608, "state" : "ND" }
+{ "_id" : "58529", "city" : "CARSON", "loc" : [ -101.538725, 46.462389 ], "pop" : 713, "state" : "ND" }
+{ "_id" : "58530", "city" : "FORT CLARK", "loc" : [ -101.328643, 47.121912 ], "pop" : 2381, "state" : "ND" }
+{ "_id" : "58531", "city" : "COLEHARBOR", "loc" : [ -101.233198, 47.519559 ], "pop" : 184, "state" : "ND" }
+{ "_id" : "58532", "city" : "DRISCOLL", "loc" : [ -100.144063, 46.851139 ], "pop" : 235, "state" : "ND" }
+{ "_id" : "58533", "city" : "HEIL", "loc" : [ -101.835145, 46.411346 ], "pop" : 1052, "state" : "ND" }
+{ "_id" : "58535", "city" : "LARK", "loc" : [ -101.151681, 46.465133 ], "pop" : 972, "state" : "ND" }
+{ "_id" : "58537", "city" : "HUFF", "loc" : [ -100.693909, 46.563172 ], "pop" : 266, "state" : "ND" }
+{ "_id" : "58538", "city" : "FORT YATES", "loc" : [ -100.651611, 46.09054 ], "pop" : 2096, "state" : "ND" }
+{ "_id" : "58540", "city" : "EMMET", "loc" : [ -101.398325, 47.655219 ], "pop" : 2215, "state" : "ND" }
+{ "_id" : "58541", "city" : "GOLDEN VALLEY", "loc" : [ -102.061229, 47.293754 ], "pop" : 315, "state" : "ND" }
+{ "_id" : "58542", "city" : "HAGUE", "loc" : [ -99.974507, 46.058896 ], "pop" : 252, "state" : "ND" }
+{ "_id" : "58544", "city" : "HAZELTON", "loc" : [ -100.273325, 46.487477 ], "pop" : 323, "state" : "ND" }
+{ "_id" : "58545", "city" : "HAZEN", "loc" : [ -101.610695, 47.327138 ], "pop" : 4072, "state" : "ND" }
+{ "_id" : "58549", "city" : "KINTYRE", "loc" : [ -99.970462, 46.573573 ], "pop" : 83, "state" : "ND" }
+{ "_id" : "58551", "city" : "LEITH", "loc" : [ -101.455531, 46.234873 ], "pop" : 456, "state" : "ND" }
+{ "_id" : "58552", "city" : "TEMVIK", "loc" : [ -100.215832, 46.286924 ], "pop" : 2362, "state" : "ND" }
+{ "_id" : "58553", "city" : "MCKENZIE", "loc" : [ -100.3995, 46.831062 ], "pop" : 163, "state" : "ND" }
+{ "_id" : "58554", "city" : "MANDAN", "loc" : [ -100.909175, 46.830649 ], "pop" : 18098, "state" : "ND" }
+{ "_id" : "58558", "city" : "MENOKEN", "loc" : [ -100.527488, 46.861032 ], "pop" : 176, "state" : "ND" }
+{ "_id" : "58559", "city" : "MERCER", "loc" : [ -100.717079, 47.485792 ], "pop" : 142, "state" : "ND" }
+{ "_id" : "58560", "city" : "MOFFIT", "loc" : [ -100.297538, 46.675725 ], "pop" : 176, "state" : "ND" }
+{ "_id" : "58561", "city" : "NAPOLEON", "loc" : [ -99.77253, 46.486724 ], "pop" : 1440, "state" : "ND" }
+{ "_id" : "58562", "city" : "BENTLEY", "loc" : [ -101.89369, 46.374448 ], "pop" : 1095, "state" : "ND" }
+{ "_id" : "58563", "city" : "HANNOVER", "loc" : [ -101.424453, 46.851248 ], "pop" : 1545, "state" : "ND" }
+{ "_id" : "58564", "city" : "RALEIGH", "loc" : [ -101.282651, 46.335236 ], "pop" : 138, "state" : "ND" }
+{ "_id" : "58565", "city" : "RIVERDALE", "loc" : [ -101.115061, 47.640333 ], "pop" : 86, "state" : "ND" }
+{ "_id" : "58566", "city" : "SAINT ANTHONY", "loc" : [ -100.897237, 46.588831 ], "pop" : 238, "state" : "ND" }
+{ "_id" : "58568", "city" : "SELFRIDGE", "loc" : [ -101.150204, 46.035147 ], "pop" : 647, "state" : "ND" }
+{ "_id" : "58569", "city" : "SHIELDS", "loc" : [ -101.258894, 46.183772 ], "pop" : 76, "state" : "ND" }
+{ "_id" : "58570", "city" : "BREIEN", "loc" : [ -100.81363, 46.294106 ], "pop" : 410, "state" : "ND" }
+{ "_id" : "58571", "city" : "STANTON", "loc" : [ -101.38987, 47.312786 ], "pop" : 720, "state" : "ND" }
+{ "_id" : "58572", "city" : "STERLING", "loc" : [ -100.274392, 46.843583 ], "pop" : 263, "state" : "ND" }
+{ "_id" : "58573", "city" : "STRASBURG", "loc" : [ -100.211869, 46.097938 ], "pop" : 1409, "state" : "ND" }
+{ "_id" : "58575", "city" : "TURTLE LAKE", "loc" : [ -100.881364, 47.541416 ], "pop" : 1059, "state" : "ND" }
+{ "_id" : "58576", "city" : "UNDERWOOD", "loc" : [ -101.189807, 47.460163 ], "pop" : 1629, "state" : "ND" }
+{ "_id" : "58577", "city" : "WASHBURN", "loc" : [ -101.011568, 47.311388 ], "pop" : 2006, "state" : "ND" }
+{ "_id" : "58579", "city" : "WILTON", "loc" : [ -100.794385, 47.170853 ], "pop" : 1335, "state" : "ND" }
+{ "_id" : "58580", "city" : "ZAP", "loc" : [ -101.925649, 47.289711 ], "pop" : 338, "state" : "ND" }
+{ "_id" : "58581", "city" : "ZEELAND", "loc" : [ -99.772543, 46.005476 ], "pop" : 497, "state" : "ND" }
+{ "_id" : "58601", "city" : "NEW HRADEC", "loc" : [ -102.787595, 46.887289 ], "pop" : 18751, "state" : "ND" }
+{ "_id" : "58620", "city" : "AMIDON", "loc" : [ -103.264741, 46.455951 ], "pop" : 673, "state" : "ND" }
+{ "_id" : "58621", "city" : "BEACH", "loc" : [ -103.98429, 46.932381 ], "pop" : 1577, "state" : "ND" }
+{ "_id" : "58622", "city" : "FRYBURG", "loc" : [ -103.179515, 46.887728 ], "pop" : 1290, "state" : "ND" }
+{ "_id" : "58623", "city" : "BOWMAN", "loc" : [ -103.401965, 46.173316 ], "pop" : 2432, "state" : "ND" }
+{ "_id" : "58625", "city" : "DODGE", "loc" : [ -102.198505, 47.304893 ], "pop" : 159, "state" : "ND" }
+{ "_id" : "58626", "city" : "DUNN CENTER", "loc" : [ -102.589198, 47.345265 ], "pop" : 276, "state" : "ND" }
+{ "_id" : "58627", "city" : "GORHAM", "loc" : [ -103.222328, 47.118004 ], "pop" : 729, "state" : "ND" }
+{ "_id" : "58630", "city" : "GLADSTONE", "loc" : [ -102.527379, 46.815162 ], "pop" : 397, "state" : "ND" }
+{ "_id" : "58631", "city" : "GLEN ULLIN", "loc" : [ -101.822293, 46.823301 ], "pop" : 1207, "state" : "ND" }
+{ "_id" : "58632", "city" : "GOLVA", "loc" : [ -103.957545, 46.7075 ], "pop" : 290, "state" : "ND" }
+{ "_id" : "58634", "city" : "GRASSY BUTTE", "loc" : [ -103.294433, 47.443072 ], "pop" : 282, "state" : "ND" }
+{ "_id" : "58636", "city" : "WERNER", "loc" : [ -102.319286, 47.367752 ], "pop" : 973, "state" : "ND" }
+{ "_id" : "58638", "city" : "HEBRON", "loc" : [ -102.036678, 46.893613 ], "pop" : 1133, "state" : "ND" }
+{ "_id" : "58639", "city" : "BUCYRUS", "loc" : [ -102.584516, 46.027869 ], "pop" : 2793, "state" : "ND" }
+{ "_id" : "58640", "city" : "KILLDEER", "loc" : [ -102.776242, 47.410898 ], "pop" : 1564, "state" : "ND" }
+{ "_id" : "58641", "city" : "LEFOR", "loc" : [ -102.764292, 46.725264 ], "pop" : 601, "state" : "ND" }
+{ "_id" : "58642", "city" : "MANNING", "loc" : [ -102.680638, 47.125837 ], "pop" : 733, "state" : "ND" }
+{ "_id" : "58643", "city" : "MARMARTH", "loc" : [ -103.88, 46.325396 ], "pop" : 234, "state" : "ND" }
+{ "_id" : "58645", "city" : "MEDORA", "loc" : [ -103.421011, 46.845771 ], "pop" : 379, "state" : "ND" }
+{ "_id" : "58646", "city" : "BURT", "loc" : [ -102.312935, 46.401095 ], "pop" : 1834, "state" : "ND" }
+{ "_id" : "58647", "city" : "NEW ENGLAND", "loc" : [ -102.835816, 46.512841 ], "pop" : 1183, "state" : "ND" }
+{ "_id" : "58649", "city" : "REEDER", "loc" : [ -102.940519, 46.111577 ], "pop" : 381, "state" : "ND" }
+{ "_id" : "58650", "city" : "REGENT", "loc" : [ -102.568443, 46.423452 ], "pop" : 379, "state" : "ND" }
+{ "_id" : "58651", "city" : "RHAME", "loc" : [ -103.70791, 46.166449 ], "pop" : 467, "state" : "ND" }
+{ "_id" : "58652", "city" : "RICHARDTON", "loc" : [ -102.292004, 46.842614 ], "pop" : 1091, "state" : "ND" }
+{ "_id" : "58653", "city" : "GASCOYNE", "loc" : [ -103.144688, 46.139924 ], "pop" : 697, "state" : "ND" }
+{ "_id" : "58654", "city" : "SENTINEL BUTTE", "loc" : [ -103.800113, 46.830475 ], "pop" : 229, "state" : "ND" }
+{ "_id" : "58655", "city" : "SOUTH HEART", "loc" : [ -103.016241, 46.812701 ], "pop" : 613, "state" : "ND" }
+{ "_id" : "58656", "city" : "TAYLOR", "loc" : [ -102.375626, 46.928372 ], "pop" : 389, "state" : "ND" }
+{ "_id" : "58657", "city" : "TROTTERS", "loc" : [ -103.854704, 47.233008 ], "pop" : 12, "state" : "ND" }
+{ "_id" : "58701", "city" : "MINOT", "loc" : [ -101.298476, 48.22914 ], "pop" : 42195, "state" : "ND" }
+{ "_id" : "58704", "city" : "MINOT AFB", "loc" : [ -101.31678, 48.423217 ], "pop" : 9095, "state" : "ND" }
+{ "_id" : "58710", "city" : "ANAMOOSE", "loc" : [ -100.252941, 47.870307 ], "pop" : 595, "state" : "ND" }
+{ "_id" : "58711", "city" : "ANTLER", "loc" : [ -101.333758, 48.958525 ], "pop" : 222, "state" : "ND" }
+{ "_id" : "58712", "city" : "BALFOUR", "loc" : [ -100.520929, 47.968451 ], "pop" : 82, "state" : "ND" }
+{ "_id" : "58713", "city" : "BANTRY", "loc" : [ -100.789445, 48.511875 ], "pop" : 504, "state" : "ND" }
+{ "_id" : "58716", "city" : "BENEDICT", "loc" : [ -101.057884, 47.786493 ], "pop" : 149, "state" : "ND" }
+{ "_id" : "58718", "city" : "BLAISDELL", "loc" : [ -101.800562, 48.323399 ], "pop" : 677, "state" : "ND" }
+{ "_id" : "58721", "city" : "COTEAU", "loc" : [ -102.247271, 48.796803 ], "pop" : 705, "state" : "ND" }
+{ "_id" : "58722", "city" : "BURLINGTON", "loc" : [ -101.428205, 48.273534 ], "pop" : 1291, "state" : "ND" }
+{ "_id" : "58723", "city" : "BUTTE", "loc" : [ -100.660446, 47.811884 ], "pop" : 241, "state" : "ND" }
+{ "_id" : "58725", "city" : "CARPIO", "loc" : [ -101.711943, 48.432299 ], "pop" : 298, "state" : "ND" }
+{ "_id" : "58727", "city" : "LARSON", "loc" : [ -102.794848, 48.878875 ], "pop" : 484, "state" : "ND" }
+{ "_id" : "58730", "city" : "CROSBY", "loc" : [ -103.274023, 48.883551 ], "pop" : 1881, "state" : "ND" }
+{ "_id" : "58731", "city" : "DEERING", "loc" : [ -101.033685, 48.405693 ], "pop" : 200, "state" : "ND" }
+{ "_id" : "58733", "city" : "DES LACS", "loc" : [ -101.567167, 48.25569 ], "pop" : 306, "state" : "ND" }
+{ "_id" : "58734", "city" : "DONNYBROOK", "loc" : [ -101.896039, 48.490015 ], "pop" : 208, "state" : "ND" }
+{ "_id" : "58735", "city" : "DOUGLAS", "loc" : [ -101.511218, 47.865914 ], "pop" : 135, "state" : "ND" }
+{ "_id" : "58736", "city" : "DRAKE", "loc" : [ -100.378955, 47.902431 ], "pop" : 577, "state" : "ND" }
+{ "_id" : "58737", "city" : "NORTHGATE", "loc" : [ -102.341502, 48.917672 ], "pop" : 240, "state" : "ND" }
+{ "_id" : "58738", "city" : "FOXHOLM", "loc" : [ -101.59072, 48.339193 ], "pop" : 88, "state" : "ND" }
+{ "_id" : "58739", "city" : "GARDENA", "loc" : [ -100.48429, 48.683566 ], "pop" : 82, "state" : "ND" }
+{ "_id" : "58740", "city" : "WOLSETH", "loc" : [ -101.31955, 48.507978 ], "pop" : 783, "state" : "ND" }
+{ "_id" : "58741", "city" : "GRANVILLE", "loc" : [ -100.808193, 48.256575 ], "pop" : 679, "state" : "ND" }
+{ "_id" : "58744", "city" : "KARLSRUHE", "loc" : [ -100.574158, 48.10085 ], "pop" : 682, "state" : "ND" }
+{ "_id" : "58746", "city" : "COULEE", "loc" : [ -102.071745, 48.673149 ], "pop" : 1756, "state" : "ND" }
+{ "_id" : "58747", "city" : "KIEF", "loc" : [ -100.52146, 47.818615 ], "pop" : 204, "state" : "ND" }
+{ "_id" : "58748", "city" : "KRAMER", "loc" : [ -100.671638, 48.686666 ], "pop" : 145, "state" : "ND" }
+{ "_id" : "58750", "city" : "LANSFORD", "loc" : [ -101.385825, 48.625419 ], "pop" : 562, "state" : "ND" }
+{ "_id" : "58752", "city" : "LIGNITE", "loc" : [ -102.554177, 48.848113 ], "pop" : 399, "state" : "ND" }
+{ "_id" : "58755", "city" : "MCGREGOR", "loc" : [ -102.928795, 48.594983 ], "pop" : 94, "state" : "ND" }
+{ "_id" : "58756", "city" : "MAKOTI", "loc" : [ -101.814942, 47.985283 ], "pop" : 247, "state" : "ND" }
+{ "_id" : "58757", "city" : "MANDAREE", "loc" : [ -102.653473, 47.856744 ], "pop" : 886, "state" : "ND" }
+{ "_id" : "58758", "city" : "MARTIN", "loc" : [ -100.122517, 47.778144 ], "pop" : 279, "state" : "ND" }
+{ "_id" : "58759", "city" : "MAX", "loc" : [ -101.293166, 47.815577 ], "pop" : 472, "state" : "ND" }
+{ "_id" : "58760", "city" : "MAXBASS", "loc" : [ -101.256328, 48.772163 ], "pop" : 404, "state" : "ND" }
+{ "_id" : "58761", "city" : "LORAINE", "loc" : [ -101.554512, 48.765814 ], "pop" : 1455, "state" : "ND" }
+{ "_id" : "58762", "city" : "NEWBURG", "loc" : [ -100.968056, 48.698192 ], "pop" : 516, "state" : "ND" }
+{ "_id" : "58763", "city" : "CHARLSON", "loc" : [ -102.485793, 47.977154 ], "pop" : 2033, "state" : "ND" }
+{ "_id" : "58765", "city" : "NOONAN", "loc" : [ -103.009793, 48.885635 ], "pop" : 326, "state" : "ND" }
+{ "_id" : "58768", "city" : "NORWICH", "loc" : [ -100.971165, 48.249115 ], "pop" : 167, "state" : "ND" }
+{ "_id" : "58769", "city" : "PALERMO", "loc" : [ -102.239954, 48.3396 ], "pop" : 133, "state" : "ND" }
+{ "_id" : "58770", "city" : "PARSHALL", "loc" : [ -102.142732, 47.95597 ], "pop" : 1425, "state" : "ND" }
+{ "_id" : "58771", "city" : "PLAZA", "loc" : [ -101.964276, 48.02421 ], "pop" : 309, "state" : "ND" }
+{ "_id" : "58772", "city" : "PORTAL", "loc" : [ -102.548023, 48.975818 ], "pop" : 286, "state" : "ND" }
+{ "_id" : "58773", "city" : "BATTLEVIEW", "loc" : [ -102.644646, 48.589815 ], "pop" : 888, "state" : "ND" }
+{ "_id" : "58775", "city" : "ROSEGLEN", "loc" : [ -101.822041, 47.695967 ], "pop" : 1178, "state" : "ND" }
+{ "_id" : "58776", "city" : "ROSS", "loc" : [ -102.530721, 48.316159 ], "pop" : 104, "state" : "ND" }
+{ "_id" : "58778", "city" : "RUSO", "loc" : [ -100.875432, 47.762224 ], "pop" : 187, "state" : "ND" }
+{ "_id" : "58779", "city" : "RAUB", "loc" : [ -101.765095, 47.868017 ], "pop" : 320, "state" : "ND" }
+{ "_id" : "58781", "city" : "SAWYER", "loc" : [ -101.067396, 48.085837 ], "pop" : 493, "state" : "ND" }
+{ "_id" : "58782", "city" : "SHERWOOD", "loc" : [ -101.697024, 48.957551 ], "pop" : 487, "state" : "ND" }
+{ "_id" : "58783", "city" : "CARBURY", "loc" : [ -100.741324, 48.937378 ], "pop" : 443, "state" : "ND" }
+{ "_id" : "58784", "city" : "BELDEN", "loc" : [ -102.392802, 48.319189 ], "pop" : 2711, "state" : "ND" }
+{ "_id" : "58785", "city" : "SURREY", "loc" : [ -101.121617, 48.236472 ], "pop" : 1109, "state" : "ND" }
+{ "_id" : "58787", "city" : "TOLLEY", "loc" : [ -101.855891, 48.796903 ], "pop" : 270, "state" : "ND" }
+{ "_id" : "58788", "city" : "BERWICK", "loc" : [ -100.412322, 48.377657 ], "pop" : 1251, "state" : "ND" }
+{ "_id" : "58789", "city" : "UPHAM", "loc" : [ -100.732314, 48.581632 ], "pop" : 285, "state" : "ND" }
+{ "_id" : "58790", "city" : "VELVA", "loc" : [ -100.934623, 48.06748 ], "pop" : 1241, "state" : "ND" }
+{ "_id" : "58792", "city" : "BERGEN", "loc" : [ -100.803824, 47.951793 ], "pop" : 418, "state" : "ND" }
+{ "_id" : "58793", "city" : "WESTHOPE", "loc" : [ -101.033809, 48.905074 ], "pop" : 855, "state" : "ND" }
+{ "_id" : "58794", "city" : "WHITE EARTH", "loc" : [ -102.806672, 48.430748 ], "pop" : 172, "state" : "ND" }
+{ "_id" : "58795", "city" : "HAMLET", "loc" : [ -103.184878, 48.621929 ], "pop" : 238, "state" : "ND" }
+{ "_id" : "58801", "city" : "BONETRAILL", "loc" : [ -103.631699, 48.167924 ], "pop" : 16473, "state" : "ND" }
+{ "_id" : "58830", "city" : "APPAM", "loc" : [ -103.422154, 48.585803 ], "pop" : 116, "state" : "ND" }
+{ "_id" : "58831", "city" : "RAWSON", "loc" : [ -103.63961, 47.843517 ], "pop" : 535, "state" : "ND" }
+{ "_id" : "58833", "city" : "AMBROSE", "loc" : [ -103.700676, 48.817195 ], "pop" : 569, "state" : "ND" }
+{ "_id" : "58835", "city" : "ARNEGARD", "loc" : [ -103.453837, 47.808832 ], "pop" : 190, "state" : "ND" }
+{ "_id" : "58838", "city" : "CARTWRIGHT", "loc" : [ -103.948718, 47.79922 ], "pop" : 944, "state" : "ND" }
+{ "_id" : "58843", "city" : "SPRINGBROOK", "loc" : [ -103.372462, 48.260088 ], "pop" : 195, "state" : "ND" }
+{ "_id" : "58844", "city" : "COLGAN", "loc" : [ -103.828955, 48.924646 ], "pop" : 123, "state" : "ND" }
+{ "_id" : "58845", "city" : "ALKABO", "loc" : [ -103.929128, 48.613946 ], "pop" : 313, "state" : "ND" }
+{ "_id" : "58847", "city" : "KEENE", "loc" : [ -102.890567, 47.940516 ], "pop" : 358, "state" : "ND" }
+{ "_id" : "58849", "city" : "WHEELOCK", "loc" : [ -103.18365, 48.3323 ], "pop" : 816, "state" : "ND" }
+{ "_id" : "58852", "city" : "TEMPLE", "loc" : [ -102.961281, 48.392009 ], "pop" : 1984, "state" : "ND" }
+{ "_id" : "58853", "city" : "TRENTON", "loc" : [ -103.861276, 48.056303 ], "pop" : 806, "state" : "ND" }
+{ "_id" : "58854", "city" : "WATFORD CITY", "loc" : [ -103.258205, 47.804258 ], "pop" : 3188, "state" : "ND" }
+{ "_id" : "58856", "city" : "ZAHL", "loc" : [ -103.659926, 48.578747 ], "pop" : 94, "state" : "ND" }
+{ "_id" : "59001", "city" : "ABSAROKEE", "loc" : [ -109.469171, 45.515356 ], "pop" : 1330, "state" : "MT" }
+{ "_id" : "59002", "city" : "ACTON", "loc" : [ -108.680975, 45.936997 ], "pop" : 55, "state" : "MT" }
+{ "_id" : "59003", "city" : "ASHLAND", "loc" : [ -106.279722, 45.58275 ], "pop" : 353, "state" : "MT" }
+{ "_id" : "59006", "city" : "BALLANTINE", "loc" : [ -108.123133, 45.954699 ], "pop" : 730, "state" : "MT" }
+{ "_id" : "59007", "city" : "BEARCREEK", "loc" : [ -109.044704, 45.15226 ], "pop" : 312, "state" : "MT" }
+{ "_id" : "59008", "city" : "BELFRY", "loc" : [ -109.078777, 45.049827 ], "pop" : 64, "state" : "MT" }
+{ "_id" : "59010", "city" : "BIGHORN", "loc" : [ -107.205942, 46.238286 ], "pop" : 573, "state" : "MT" }
+{ "_id" : "59011", "city" : "BIG TIMBER", "loc" : [ -109.963094, 45.82827 ], "pop" : 2296, "state" : "MT" }
+{ "_id" : "59012", "city" : "BIRNEY", "loc" : [ -106.509496, 45.286204 ], "pop" : 138, "state" : "MT" }
+{ "_id" : "59014", "city" : "BRIDGER", "loc" : [ -108.908217, 45.285682 ], "pop" : 1524, "state" : "MT" }
+{ "_id" : "59015", "city" : "BROADVIEW", "loc" : [ -108.809062, 46.082101 ], "pop" : 303, "state" : "MT" }
+{ "_id" : "59016", "city" : "BUSBY", "loc" : [ -106.872311, 45.554139 ], "pop" : 1077, "state" : "MT" }
+{ "_id" : "59017", "city" : "CAT CREEK", "loc" : [ -108.259094, 47.154789 ], "pop" : 155, "state" : "MT" }
+{ "_id" : "59019", "city" : "COLUMBUS", "loc" : [ -109.257126, 45.626171 ], "pop" : 2438, "state" : "MT" }
+{ "_id" : "59022", "city" : "CROW AGENCY", "loc" : [ -107.497251, 45.629594 ], "pop" : 2267, "state" : "MT" }
+{ "_id" : "59024", "city" : "CUSTER", "loc" : [ -107.59585, 46.13019 ], "pop" : 304, "state" : "MT" }
+{ "_id" : "59025", "city" : "DECKER", "loc" : [ -106.87206, 45.179698 ], "pop" : 164, "state" : "MT" }
+{ "_id" : "59027", "city" : "EMIGRANT", "loc" : [ -110.798928, 45.127557 ], "pop" : 2058, "state" : "MT" }
+{ "_id" : "59028", "city" : "FISHTAIL", "loc" : [ -109.582078, 45.400217 ], "pop" : 348, "state" : "MT" }
+{ "_id" : "59029", "city" : "FROMBERG", "loc" : [ -108.905658, 45.40269 ], "pop" : 627, "state" : "MT" }
+{ "_id" : "59030", "city" : "GARDINER", "loc" : [ -110.196258, 45.0493 ], "pop" : 168, "state" : "MT" }
+{ "_id" : "59031", "city" : "GARRYOWEN", "loc" : [ -107.364925, 45.508557 ], "pop" : 428, "state" : "MT" }
+{ "_id" : "59032", "city" : "GRASS RANGE", "loc" : [ -108.827059, 47.025894 ], "pop" : 494, "state" : "MT" }
+{ "_id" : "59033", "city" : "GREYCLIFF", "loc" : [ -109.674601, 45.792631 ], "pop" : 216, "state" : "MT" }
+{ "_id" : "59034", "city" : "HARDIN", "loc" : [ -107.607457, 45.749843 ], "pop" : 3889, "state" : "MT" }
+{ "_id" : "59037", "city" : "HUNTLEY", "loc" : [ -108.284981, 45.89049 ], "pop" : 1006, "state" : "MT" }
+{ "_id" : "59038", "city" : "HYSHAM", "loc" : [ -107.307196, 46.276483 ], "pop" : 301, "state" : "MT" }
+{ "_id" : "59039", "city" : "INGOMAR", "loc" : [ -107.551749, 46.654196 ], "pop" : 118, "state" : "MT" }
+{ "_id" : "59041", "city" : "SILESIA", "loc" : [ -108.94804, 45.498763 ], "pop" : 1739, "state" : "MT" }
+{ "_id" : "59043", "city" : "LAME DEER", "loc" : [ -106.565424, 45.603167 ], "pop" : 2846, "state" : "MT" }
+{ "_id" : "59044", "city" : "LAUREL", "loc" : [ -108.769008, 45.67451 ], "pop" : 8328, "state" : "MT" }
+{ "_id" : "59046", "city" : "LAVINA", "loc" : [ -108.995853, 46.329058 ], "pop" : 410, "state" : "MT" }
+{ "_id" : "59047", "city" : "LIVINGSTON", "loc" : [ -110.560907, 45.654587 ], "pop" : 9980, "state" : "MT" }
+{ "_id" : "59050", "city" : "LODGE GRASS", "loc" : [ -107.734105, 45.33218 ], "pop" : 2938, "state" : "MT" }
+{ "_id" : "59051", "city" : "LUTHER", "loc" : [ -109.475326, 45.279485 ], "pop" : 11, "state" : "MT" }
+{ "_id" : "59052", "city" : "MC LEOD", "loc" : [ -109.935698, 45.596334 ], "pop" : 226, "state" : "MT" }
+{ "_id" : "59053", "city" : "MARTINSDALE", "loc" : [ -110.432397, 46.458149 ], "pop" : 246, "state" : "MT" }
+{ "_id" : "59055", "city" : "MELVILLE", "loc" : [ -109.880885, 46.036446 ], "pop" : 416, "state" : "MT" }
+{ "_id" : "59057", "city" : "MOLT", "loc" : [ -108.973073, 45.861503 ], "pop" : 524, "state" : "MT" }
+{ "_id" : "59058", "city" : "MOSBY", "loc" : [ -107.789149, 46.900453 ], "pop" : 7, "state" : "MT" }
+{ "_id" : "59059", "city" : "MUSSELSHELL", "loc" : [ -108.003122, 46.517125 ], "pop" : 584, "state" : "MT" }
+{ "_id" : "59061", "city" : "NYE", "loc" : [ -109.827137, 45.441022 ], "pop" : 236, "state" : "MT" }
+{ "_id" : "59062", "city" : "OTTER", "loc" : [ -106.008667, 45.445803 ], "pop" : 404, "state" : "MT" }
+{ "_id" : "59063", "city" : "PARK CITY", "loc" : [ -108.929279, 45.632864 ], "pop" : 1398, "state" : "MT" }
+{ "_id" : "59064", "city" : "POMPEYS PILLAR", "loc" : [ -107.915406, 45.983847 ], "pop" : 207, "state" : "MT" }
+{ "_id" : "59065", "city" : "PRAY", "loc" : [ -110.686399, 45.419315 ], "pop" : 1094, "state" : "MT" }
+{ "_id" : "59067", "city" : "RAPELJE", "loc" : [ -109.276093, 45.97948 ], "pop" : 219, "state" : "MT" }
+{ "_id" : "59068", "city" : "RED LODGE", "loc" : [ -109.268812, 45.196522 ], "pop" : 2875, "state" : "MT" }
+{ "_id" : "59069", "city" : "REEDPOINT", "loc" : [ -109.468889, 45.648462 ], "pop" : 301, "state" : "MT" }
+{ "_id" : "59070", "city" : "ROBERTS", "loc" : [ -109.176888, 45.367235 ], "pop" : 652, "state" : "MT" }
+{ "_id" : "59071", "city" : "ROSCOE", "loc" : [ -109.44644, 45.377232 ], "pop" : 159, "state" : "MT" }
+{ "_id" : "59072", "city" : "ROUNDUP", "loc" : [ -108.543846, 46.422487 ], "pop" : 3522, "state" : "MT" }
+{ "_id" : "59074", "city" : "RYEGATE", "loc" : [ -109.276121, 46.272367 ], "pop" : 502, "state" : "MT" }
+{ "_id" : "59075", "city" : "SAINT XAVIER", "loc" : [ -107.709242, 45.488996 ], "pop" : 199, "state" : "MT" }
+{ "_id" : "59077", "city" : "SAND SPRINGS", "loc" : [ -107.288623, 47.032287 ], "pop" : 95, "state" : "MT" }
+{ "_id" : "59078", "city" : "SHAWMUT", "loc" : [ -109.597361, 46.386921 ], "pop" : 249, "state" : "MT" }
+{ "_id" : "59079", "city" : "SHEPHERD", "loc" : [ -108.342634, 45.94608 ], "pop" : 2078, "state" : "MT" }
+{ "_id" : "59085", "city" : "TWODOT", "loc" : [ -109.899483, 46.446513 ], "pop" : 1694, "state" : "MT" }
+{ "_id" : "59086", "city" : "WILSALL", "loc" : [ -110.606147, 45.948351 ], "pop" : 1293, "state" : "MT" }
+{ "_id" : "59087", "city" : "WINNETT", "loc" : [ -108.318373, 46.943788 ], "pop" : 364, "state" : "MT" }
+{ "_id" : "59088", "city" : "WORDEN", "loc" : [ -108.153284, 45.977937 ], "pop" : 1025, "state" : "MT" }
+{ "_id" : "59089", "city" : "WYOLA", "loc" : [ -107.430258, 45.108904 ], "pop" : 375, "state" : "MT" }
+{ "_id" : "59101", "city" : "BILLINGS", "loc" : [ -108.500452, 45.774489 ], "pop" : 33061, "state" : "MT" }
+{ "_id" : "59102", "city" : "BILLINGS", "loc" : [ -108.572662, 45.781265 ], "pop" : 40121, "state" : "MT" }
+{ "_id" : "59105", "city" : "BILLINGS HEIGHTS", "loc" : [ -108.474726, 45.828443 ], "pop" : 20320, "state" : "MT" }
+{ "_id" : "59106", "city" : "BILLINGS", "loc" : [ -108.65191, 45.775306 ], "pop" : 5623, "state" : "MT" }
+{ "_id" : "59201", "city" : "WOLF POINT", "loc" : [ -105.629318, 48.111879 ], "pop" : 4845, "state" : "MT" }
+{ "_id" : "59211", "city" : "ANTELOPE", "loc" : [ -104.452883, 48.696813 ], "pop" : 152, "state" : "MT" }
+{ "_id" : "59212", "city" : "BAINVILLE", "loc" : [ -104.199532, 48.157989 ], "pop" : 354, "state" : "MT" }
+{ "_id" : "59213", "city" : "BROCKTON", "loc" : [ -104.85479, 48.210063 ], "pop" : 959, "state" : "MT" }
+{ "_id" : "59214", "city" : "BROCKWAY", "loc" : [ -105.777649, 47.248497 ], "pop" : 233, "state" : "MT" }
+{ "_id" : "59215", "city" : "CIRCLE", "loc" : [ -105.614771, 47.426389 ], "pop" : 1271, "state" : "MT" }
+{ "_id" : "59218", "city" : "CULBERTSON", "loc" : [ -104.513212, 48.149536 ], "pop" : 949, "state" : "MT" }
+{ "_id" : "59219", "city" : "DAGMAR", "loc" : [ -104.240123, 48.609337 ], "pop" : 317, "state" : "MT" }
+{ "_id" : "59221", "city" : "FAIRVIEW", "loc" : [ -104.230194, 47.891598 ], "pop" : 1668, "state" : "MT" }
+{ "_id" : "59222", "city" : "FLAXVILLE", "loc" : [ -105.163746, 48.747222 ], "pop" : 312, "state" : "MT" }
+{ "_id" : "59223", "city" : "FORT PECK", "loc" : [ -106.516646, 48.053844 ], "pop" : 714, "state" : "MT" }
+{ "_id" : "59225", "city" : "LUSTRE", "loc" : [ -105.991929, 48.161166 ], "pop" : 819, "state" : "MT" }
+{ "_id" : "59226", "city" : "FROID", "loc" : [ -104.451765, 48.320113 ], "pop" : 479, "state" : "MT" }
+{ "_id" : "59230", "city" : "GLASGOW", "loc" : [ -106.609419, 48.203385 ], "pop" : 5192, "state" : "MT" }
+{ "_id" : "59241", "city" : "HINSDALE", "loc" : [ -107.009836, 48.400705 ], "pop" : 704, "state" : "MT" }
+{ "_id" : "59242", "city" : "HOMESTEAD", "loc" : [ -104.591805, 48.429616 ], "pop" : 7, "state" : "MT" }
+{ "_id" : "59243", "city" : "LAMBERT", "loc" : [ -104.598746, 47.745908 ], "pop" : 655, "state" : "MT" }
+{ "_id" : "59244", "city" : "LARSLAN", "loc" : [ -106.283503, 48.58218 ], "pop" : 120, "state" : "MT" }
+{ "_id" : "59247", "city" : "MEDICINE LAKE", "loc" : [ -104.437545, 48.485179 ], "pop" : 629, "state" : "MT" }
+{ "_id" : "59248", "city" : "NASHUA", "loc" : [ -106.24407, 48.18653 ], "pop" : 206, "state" : "MT" }
+{ "_id" : "59250", "city" : "OPHEIM", "loc" : [ -106.365832, 48.87016 ], "pop" : 322, "state" : "MT" }
+{ "_id" : "59252", "city" : "OUTLOOK", "loc" : [ -104.741526, 48.881673 ], "pop" : 241, "state" : "MT" }
+{ "_id" : "59253", "city" : "PEERLESS", "loc" : [ -105.800567, 48.780767 ], "pop" : 395, "state" : "MT" }
+{ "_id" : "59254", "city" : "PLENTYWOOD", "loc" : [ -104.560032, 48.778825 ], "pop" : 2557, "state" : "MT" }
+{ "_id" : "59255", "city" : "POPLAR", "loc" : [ -105.187021, 48.130713 ], "pop" : 3407, "state" : "MT" }
+{ "_id" : "59256", "city" : "RAYMOND", "loc" : [ -104.629763, 48.968612 ], "pop" : 29, "state" : "MT" }
+{ "_id" : "59257", "city" : "REDSTONE", "loc" : [ -104.935259, 48.835511 ], "pop" : 158, "state" : "MT" }
+{ "_id" : "59258", "city" : "RESERVE", "loc" : [ -104.627875, 48.590519 ], "pop" : 127, "state" : "MT" }
+{ "_id" : "59259", "city" : "RICHEY", "loc" : [ -105.017017, 47.622874 ], "pop" : 462, "state" : "MT" }
+{ "_id" : "59260", "city" : "RICHLAND", "loc" : [ -106.223696, 48.727326 ], "pop" : 162, "state" : "MT" }
+{ "_id" : "59261", "city" : "SACO", "loc" : [ -107.429324, 48.638938 ], "pop" : 178, "state" : "MT" }
+{ "_id" : "59262", "city" : "SAVAGE", "loc" : [ -104.284487, 47.519375 ], "pop" : 1170, "state" : "MT" }
+{ "_id" : "59263", "city" : "SCOBEY", "loc" : [ -105.417016, 48.785356 ], "pop" : 1415, "state" : "MT" }
+{ "_id" : "59270", "city" : "SIDNEY", "loc" : [ -104.163445, 47.713017 ], "pop" : 7229, "state" : "MT" }
+{ "_id" : "59274", "city" : "VIDA", "loc" : [ -105.599595, 47.894727 ], "pop" : 772, "state" : "MT" }
+{ "_id" : "59275", "city" : "WESTBY", "loc" : [ -104.124708, 48.858695 ], "pop" : 515, "state" : "MT" }
+{ "_id" : "59276", "city" : "WHITETAIL", "loc" : [ -105.297667, 48.924968 ], "pop" : 144, "state" : "MT" }
+{ "_id" : "59301", "city" : "MILES CITY", "loc" : [ -105.833193, 46.407459 ], "pop" : 10604, "state" : "MT" }
+{ "_id" : "59311", "city" : "ALZADA", "loc" : [ -104.261747, 45.156244 ], "pop" : 101, "state" : "MT" }
+{ "_id" : "59312", "city" : "ANGELA", "loc" : [ -106.315732, 46.771929 ], "pop" : 35, "state" : "MT" }
+{ "_id" : "59313", "city" : "BAKER", "loc" : [ -104.266707, 46.355219 ], "pop" : 2631, "state" : "MT" }
+{ "_id" : "59314", "city" : "BIDDLE", "loc" : [ -105.290138, 45.256977 ], "pop" : 606, "state" : "MT" }
+{ "_id" : "59315", "city" : "BLOOMFIELD", "loc" : [ -104.878235, 47.340813 ], "pop" : 569, "state" : "MT" }
+{ "_id" : "59316", "city" : "BOYES", "loc" : [ -104.884118, 45.490003 ], "pop" : 90, "state" : "MT" }
+{ "_id" : "59317", "city" : "BELLE CREEK", "loc" : [ -105.424968, 45.46057 ], "pop" : 946, "state" : "MT" }
+{ "_id" : "59318", "city" : "BRUSETT", "loc" : [ -107.599864, 47.342341 ], "pop" : 229, "state" : "MT" }
+{ "_id" : "59319", "city" : "CAPITOL", "loc" : [ -104.146212, 45.473162 ], "pop" : 73, "state" : "MT" }
+{ "_id" : "59322", "city" : "COHAGEN", "loc" : [ -106.498065, 47.126296 ], "pop" : 372, "state" : "MT" }
+{ "_id" : "59324", "city" : "EKALAKA", "loc" : [ -104.503958, 45.88054 ], "pop" : 881, "state" : "MT" }
+{ "_id" : "59326", "city" : "FALLON", "loc" : [ -105.116055, 46.786632 ], "pop" : 388, "state" : "MT" }
+{ "_id" : "59327", "city" : "FORSYTH", "loc" : [ -106.699086, 46.2819 ], "pop" : 3148, "state" : "MT" }
+{ "_id" : "59330", "city" : "GLENDIVE", "loc" : [ -104.728716, 47.100813 ], "pop" : 8364, "state" : "MT" }
+{ "_id" : "59332", "city" : "HAMMOND", "loc" : [ -104.615444, 45.291872 ], "pop" : 358, "state" : "MT" }
+{ "_id" : "59336", "city" : "ISMAY", "loc" : [ -105.209064, 46.413223 ], "pop" : 317, "state" : "MT" }
+{ "_id" : "59337", "city" : "JORDAN", "loc" : [ -106.922076, 47.369419 ], "pop" : 886, "state" : "MT" }
+{ "_id" : "59338", "city" : "KINSEY", "loc" : [ -105.74458, 46.577008 ], "pop" : 346, "state" : "MT" }
+{ "_id" : "59339", "city" : "LINDSAY", "loc" : [ -105.208878, 47.202383 ], "pop" : 110, "state" : "MT" }
+{ "_id" : "59341", "city" : "MILDRED", "loc" : [ -104.7891, 46.751671 ], "pop" : 83, "state" : "MT" }
+{ "_id" : "59343", "city" : "OLIVE", "loc" : [ -105.668741, 45.546641 ], "pop" : 59, "state" : "MT" }
+{ "_id" : "59344", "city" : "PLEVNA", "loc" : [ -104.571289, 46.411225 ], "pop" : 433, "state" : "MT" }
+{ "_id" : "59345", "city" : "POWDERVILLE", "loc" : [ -105.276098, 45.739183 ], "pop" : 24, "state" : "MT" }
+{ "_id" : "59347", "city" : "ROSEBUD", "loc" : [ -106.598123, 45.935826 ], "pop" : 3867, "state" : "MT" }
+{ "_id" : "59349", "city" : "TERRY", "loc" : [ -105.37059, 46.828972 ], "pop" : 912, "state" : "MT" }
+{ "_id" : "59351", "city" : "VOLBORG", "loc" : [ -105.721444, 46.073609 ], "pop" : 481, "state" : "MT" }
+{ "_id" : "59353", "city" : "WIBAUX", "loc" : [ -104.189715, 46.964596 ], "pop" : 1191, "state" : "MT" }
+{ "_id" : "59354", "city" : "WILLARD", "loc" : [ -104.446662, 46.114064 ], "pop" : 39, "state" : "MT" }
+{ "_id" : "59401", "city" : "GREAT FALLS", "loc" : [ -111.273397, 47.509812 ], "pop" : 13361, "state" : "MT" }
+{ "_id" : "59404", "city" : "GREAT FALLS", "loc" : [ -111.340496, 47.509755 ], "pop" : 23133, "state" : "MT" }
+{ "_id" : "59405", "city" : "GREAT FALLS", "loc" : [ -111.250227, 47.495016 ], "pop" : 32774, "state" : "MT" }
+{ "_id" : "59410", "city" : "AUGUSTA", "loc" : [ -112.388304, 47.453739 ], "pop" : 839, "state" : "MT" }
+{ "_id" : "59411", "city" : "BABB", "loc" : [ -113.368132, 48.878781 ], "pop" : 224, "state" : "MT" }
+{ "_id" : "59412", "city" : "BELT", "loc" : [ -110.908099, 47.38211 ], "pop" : 1383, "state" : "MT" }
+{ "_id" : "59414", "city" : "BLACK EAGLE", "loc" : [ -111.276366, 47.526197 ], "pop" : 927, "state" : "MT" }
+{ "_id" : "59416", "city" : "BRADY", "loc" : [ -111.755013, 48.031244 ], "pop" : 334, "state" : "MT" }
+{ "_id" : "59417", "city" : "SAINT MARY", "loc" : [ -113.019697, 48.54926 ], "pop" : 6712, "state" : "MT" }
+{ "_id" : "59418", "city" : "BUFFALO", "loc" : [ -109.723122, 46.805593 ], "pop" : 105, "state" : "MT" }
+{ "_id" : "59419", "city" : "BYNUM", "loc" : [ -112.276177, 47.990017 ], "pop" : 130, "state" : "MT" }
+{ "_id" : "59420", "city" : "CARTER", "loc" : [ -110.978593, 47.780964 ], "pop" : 99, "state" : "MT" }
+{ "_id" : "59421", "city" : "CASCADE", "loc" : [ -111.722321, 47.29117 ], "pop" : 2050, "state" : "MT" }
+{ "_id" : "59422", "city" : "CHOTEAU", "loc" : [ -112.202136, 47.837951 ], "pop" : 2846, "state" : "MT" }
+{ "_id" : "59424", "city" : "COFFEE CREEK", "loc" : [ -110.052784, 47.339642 ], "pop" : 175, "state" : "MT" }
+{ "_id" : "59425", "city" : "CONRAD", "loc" : [ -111.939665, 48.178346 ], "pop" : 3843, "state" : "MT" }
+{ "_id" : "59427", "city" : "CUT BANK", "loc" : [ -112.365354, 48.660284 ], "pop" : 5249, "state" : "MT" }
+{ "_id" : "59430", "city" : "DENTON", "loc" : [ -109.878877, 47.319081 ], "pop" : 604, "state" : "MT" }
+{ "_id" : "59433", "city" : "DUTTON", "loc" : [ -111.689967, 47.860082 ], "pop" : 710, "state" : "MT" }
+{ "_id" : "59434", "city" : "EAST GLACIER PAR", "loc" : [ -113.317304, 48.45998 ], "pop" : 35, "state" : "MT" }
+{ "_id" : "59436", "city" : "FAIRFIELD", "loc" : [ -112.001502, 47.614255 ], "pop" : 1598, "state" : "MT" }
+{ "_id" : "59440", "city" : "FLOWEREE", "loc" : [ -111.121384, 47.658441 ], "pop" : 188, "state" : "MT" }
+{ "_id" : "59441", "city" : "FORESTGROVE", "loc" : [ -109.023294, 46.913727 ], "pop" : 143, "state" : "MT" }
+{ "_id" : "59442", "city" : "FORT BENTON", "loc" : [ -110.671487, 47.809406 ], "pop" : 2795, "state" : "MT" }
+{ "_id" : "59443", "city" : "FORT SHAW", "loc" : [ -111.805655, 47.563862 ], "pop" : 531, "state" : "MT" }
+{ "_id" : "59444", "city" : "GALATA", "loc" : [ -111.419772, 48.458657 ], "pop" : 156, "state" : "MT" }
+{ "_id" : "59446", "city" : "GERALDINE", "loc" : [ -110.276537, 47.602365 ], "pop" : 369, "state" : "MT" }
+{ "_id" : "59447", "city" : "GEYSER", "loc" : [ -110.483877, 47.259816 ], "pop" : 289, "state" : "MT" }
+{ "_id" : "59448", "city" : "HEART BUTTE", "loc" : [ -112.845591, 48.277743 ], "pop" : 642, "state" : "MT" }
+{ "_id" : "59450", "city" : "HIGHWOOD", "loc" : [ -110.788656, 47.581587 ], "pop" : 387, "state" : "MT" }
+{ "_id" : "59451", "city" : "HILGER", "loc" : [ -109.456246, 47.269546 ], "pop" : 719, "state" : "MT" }
+{ "_id" : "59452", "city" : "UTICA", "loc" : [ -109.951824, 46.947633 ], "pop" : 632, "state" : "MT" }
+{ "_id" : "59453", "city" : "JUDITH GAP", "loc" : [ -109.675475, 46.662301 ], "pop" : 303, "state" : "MT" }
+{ "_id" : "59454", "city" : "KEVIN", "loc" : [ -111.970829, 48.750786 ], "pop" : 254, "state" : "MT" }
+{ "_id" : "59456", "city" : "LEDGER", "loc" : [ -111.756384, 48.277569 ], "pop" : 42, "state" : "MT" }
+{ "_id" : "59457", "city" : "LEWISTOWN", "loc" : [ -109.420297, 47.056324 ], "pop" : 8545, "state" : "MT" }
+{ "_id" : "59460", "city" : "LOMA", "loc" : [ -110.499487, 47.954576 ], "pop" : 201, "state" : "MT" }
+{ "_id" : "59462", "city" : "MOCCASIN", "loc" : [ -109.890066, 47.09164 ], "pop" : 187, "state" : "MT" }
+{ "_id" : "59463", "city" : "MONARCH", "loc" : [ -110.871027, 47.07223 ], "pop" : 150, "state" : "MT" }
+{ "_id" : "59464", "city" : "MOORE", "loc" : [ -109.653838, 46.989811 ], "pop" : 569, "state" : "MT" }
+{ "_id" : "59465", "city" : "NEIHART", "loc" : [ -110.732827, 46.939086 ], "pop" : 58, "state" : "MT" }
+{ "_id" : "59467", "city" : "PENDROY", "loc" : [ -112.326082, 48.087892 ], "pop" : 214, "state" : "MT" }
+{ "_id" : "59468", "city" : "POWER", "loc" : [ -111.716898, 47.679846 ], "pop" : 862, "state" : "MT" }
+{ "_id" : "59469", "city" : "RAYNESFORD", "loc" : [ -110.704747, 47.260425 ], "pop" : 208, "state" : "MT" }
+{ "_id" : "59471", "city" : "ROY", "loc" : [ -108.863422, 47.367821 ], "pop" : 353, "state" : "MT" }
+{ "_id" : "59472", "city" : "SAND COULEE", "loc" : [ -111.16606, 47.402117 ], "pop" : 583, "state" : "MT" }
+{ "_id" : "59474", "city" : "SHELBY", "loc" : [ -111.839122, 48.503666 ], "pop" : 3375, "state" : "MT" }
+{ "_id" : "59479", "city" : "STANFORD", "loc" : [ -110.196111, 47.14886 ], "pop" : 966, "state" : "MT" }
+{ "_id" : "59480", "city" : "STOCKETT", "loc" : [ -111.12868, 47.321712 ], "pop" : 554, "state" : "MT" }
+{ "_id" : "59482", "city" : "SUNBURST", "loc" : [ -111.744195, 48.851585 ], "pop" : 912, "state" : "MT" }
+{ "_id" : "59483", "city" : "SUN RIVER", "loc" : [ -111.724214, 47.480975 ], "pop" : 1083, "state" : "MT" }
+{ "_id" : "59484", "city" : "SWEETGRASS", "loc" : [ -112.020436, 48.971305 ], "pop" : 349, "state" : "MT" }
+{ "_id" : "59486", "city" : "VALIER", "loc" : [ -112.303275, 48.279504 ], "pop" : 1473, "state" : "MT" }
+{ "_id" : "59487", "city" : "VAUGHN", "loc" : [ -111.576955, 47.562445 ], "pop" : 869, "state" : "MT" }
+{ "_id" : "59489", "city" : "WINIFRED", "loc" : [ -109.340931, 47.589903 ], "pop" : 376, "state" : "MT" }
+{ "_id" : "59501", "city" : "HAVRE", "loc" : [ -109.687974, 48.556121 ], "pop" : 13961, "state" : "MT" }
+{ "_id" : "59520", "city" : "BIG SANDY", "loc" : [ -110.07762, 48.149677 ], "pop" : 1554, "state" : "MT" }
+{ "_id" : "59521", "city" : "BOX ELDER", "loc" : [ -109.820548, 48.284066 ], "pop" : 2012, "state" : "MT" }
+{ "_id" : "59522", "city" : "CHESTER", "loc" : [ -110.97982, 48.454125 ], "pop" : 1530, "state" : "MT" }
+{ "_id" : "59523", "city" : "CHINOOK", "loc" : [ -109.22246, 48.57985 ], "pop" : 2607, "state" : "MT" }
+{ "_id" : "59524", "city" : "DODSON", "loc" : [ -108.629967, 48.207526 ], "pop" : 1870, "state" : "MT" }
+{ "_id" : "59525", "city" : "GILDFORD", "loc" : [ -110.283633, 48.592716 ], "pop" : 330, "state" : "MT" }
+{ "_id" : "59526", "city" : "HARLEM", "loc" : [ -108.769253, 48.539802 ], "pop" : 1177, "state" : "MT" }
+{ "_id" : "59527", "city" : "HAYS", "loc" : [ -108.768422, 48.380374 ], "pop" : 638, "state" : "MT" }
+{ "_id" : "59528", "city" : "HINGHAM", "loc" : [ -110.427548, 48.587029 ], "pop" : 333, "state" : "MT" }
+{ "_id" : "59529", "city" : "HOGELAND", "loc" : [ -108.667704, 48.857071 ], "pop" : 143, "state" : "MT" }
+{ "_id" : "59530", "city" : "INVERNESS", "loc" : [ -110.68796, 48.593009 ], "pop" : 231, "state" : "MT" }
+{ "_id" : "59531", "city" : "JOPLIN", "loc" : [ -110.79145, 48.649795 ], "pop" : 496, "state" : "MT" }
+{ "_id" : "59532", "city" : "KREMLIN", "loc" : [ -110.051315, 48.559955 ], "pop" : 311, "state" : "MT" }
+{ "_id" : "59535", "city" : "LLOYD", "loc" : [ -109.294264, 48.148632 ], "pop" : 212, "state" : "MT" }
+{ "_id" : "59537", "city" : "LORING", "loc" : [ -107.868603, 48.798333 ], "pop" : 243, "state" : "MT" }
+{ "_id" : "59538", "city" : "MALTA", "loc" : [ -107.840784, 48.369167 ], "pop" : 4049, "state" : "MT" }
+{ "_id" : "59540", "city" : "RUDYARD", "loc" : [ -110.555235, 48.586001 ], "pop" : 476, "state" : "MT" }
+{ "_id" : "59542", "city" : "TURNER", "loc" : [ -108.396079, 48.832766 ], "pop" : 270, "state" : "MT" }
+{ "_id" : "59544", "city" : "WHITEWATER", "loc" : [ -107.40543, 48.834909 ], "pop" : 110, "state" : "MT" }
+{ "_id" : "59545", "city" : "WHITLASH", "loc" : [ -111.107512, 48.911037 ], "pop" : 269, "state" : "MT" }
+{ "_id" : "59546", "city" : "ZORTMAN", "loc" : [ -108.349523, 47.874326 ], "pop" : 394, "state" : "MT" }
+{ "_id" : "59601", "city" : "HELENA", "loc" : [ -112.021283, 46.613066 ], "pop" : 40102, "state" : "MT" }
+{ "_id" : "59632", "city" : "BOULDER", "loc" : [ -112.113757, 46.230647 ], "pop" : 1737, "state" : "MT" }
+{ "_id" : "59633", "city" : "CANYON CREEK", "loc" : [ -112.279496, 46.762662 ], "pop" : 648, "state" : "MT" }
+{ "_id" : "59634", "city" : "MONTANA CITY", "loc" : [ -111.992565, 46.474492 ], "pop" : 3496, "state" : "MT" }
+{ "_id" : "59635", "city" : "EAST HELENA", "loc" : [ -111.905089, 46.597324 ], "pop" : 3901, "state" : "MT" }
+{ "_id" : "59639", "city" : "LINCOLN", "loc" : [ -112.66514, 46.957458 ], "pop" : 1015, "state" : "MT" }
+{ "_id" : "59641", "city" : "RADERSBURG", "loc" : [ -111.572186, 46.079317 ], "pop" : 391, "state" : "MT" }
+{ "_id" : "59642", "city" : "RINGLING", "loc" : [ -110.824214, 46.285468 ], "pop" : 97, "state" : "MT" }
+{ "_id" : "59643", "city" : "TOSTON", "loc" : [ -111.425974, 46.20437 ], "pop" : 168, "state" : "MT" }
+{ "_id" : "59644", "city" : "TOWNSEND", "loc" : [ -111.491906, 46.334571 ], "pop" : 2343, "state" : "MT" }
+{ "_id" : "59645", "city" : "WHITE SULPHUR SP", "loc" : [ -110.934413, 46.566323 ], "pop" : 1476, "state" : "MT" }
+{ "_id" : "59647", "city" : "WINSTON", "loc" : [ -111.644671, 46.431485 ], "pop" : 416, "state" : "MT" }
+{ "_id" : "59648", "city" : "WOLF CREEK", "loc" : [ -111.883316, 46.839567 ], "pop" : 995, "state" : "MT" }
+{ "_id" : "59701", "city" : "WALKERVILLE", "loc" : [ -112.517807, 45.991579 ], "pop" : 33096, "state" : "MT" }
+{ "_id" : "59711", "city" : "ANACONDA", "loc" : [ -112.97388, 46.129863 ], "pop" : 8611, "state" : "MT" }
+{ "_id" : "59714", "city" : "BELGRADE", "loc" : [ -111.143927, 45.780126 ], "pop" : 9060, "state" : "MT" }
+{ "_id" : "59715", "city" : "BOZEMAN", "loc" : [ -111.043057, 45.669269 ], "pop" : 31218, "state" : "MT" }
+{ "_id" : "59720", "city" : "CAMERON", "loc" : [ -111.650778, 45.139021 ], "pop" : 269, "state" : "MT" }
+{ "_id" : "59721", "city" : "CARDWELL", "loc" : [ -111.780946, 45.894071 ], "pop" : 109, "state" : "MT" }
+{ "_id" : "59722", "city" : "DEER LODGE", "loc" : [ -112.747589, 46.38807 ], "pop" : 5220, "state" : "MT" }
+{ "_id" : "59724", "city" : "DELL", "loc" : [ -112.950401, 44.95877 ], "pop" : 387, "state" : "MT" }
+{ "_id" : "59725", "city" : "DILLON", "loc" : [ -112.640452, 45.23394 ], "pop" : 6972, "state" : "MT" }
+{ "_id" : "59727", "city" : "DIVIDE", "loc" : [ -112.719551, 45.716055 ], "pop" : 316, "state" : "MT" }
+{ "_id" : "59729", "city" : "ENNIS", "loc" : [ -111.687033, 45.354456 ], "pop" : 1749, "state" : "MT" }
+{ "_id" : "59730", "city" : "GALLATIN GATEWAY", "loc" : [ -111.173407, 45.609963 ], "pop" : 2807, "state" : "MT" }
+{ "_id" : "59731", "city" : "GARRISON", "loc" : [ -112.617322, 46.572363 ], "pop" : 817, "state" : "MT" }
+{ "_id" : "59733", "city" : "GOLD CREEK", "loc" : [ -112.97057, 46.590025 ], "pop" : 66, "state" : "MT" }
+{ "_id" : "59735", "city" : "HARRISON", "loc" : [ -111.846135, 45.742333 ], "pop" : 434, "state" : "MT" }
+{ "_id" : "59736", "city" : "JACKSON", "loc" : [ -113.465862, 45.430725 ], "pop" : 208, "state" : "MT" }
+{ "_id" : "59739", "city" : "LIMA", "loc" : [ -112.562492, 44.644057 ], "pop" : 434, "state" : "MT" }
+{ "_id" : "59741", "city" : "MANHATTAN", "loc" : [ -111.314577, 45.79799 ], "pop" : 3461, "state" : "MT" }
+{ "_id" : "59745", "city" : "NORRIS", "loc" : [ -111.694284, 45.532271 ], "pop" : 148, "state" : "MT" }
+{ "_id" : "59747", "city" : "PONY", "loc" : [ -111.961859, 45.574502 ], "pop" : 252, "state" : "MT" }
+{ "_id" : "59748", "city" : "RAMSAY", "loc" : [ -112.619628, 46.119573 ], "pop" : 89, "state" : "MT" }
+{ "_id" : "59749", "city" : "SHERIDAN", "loc" : [ -112.173543, 45.422968 ], "pop" : 1524, "state" : "MT" }
+{ "_id" : "59750", "city" : "BUTTE", "loc" : [ -112.71586, 46.003281 ], "pop" : 440, "state" : "MT" }
+{ "_id" : "59751", "city" : "SILVER STAR", "loc" : [ -112.177604, 45.757105 ], "pop" : 310, "state" : "MT" }
+{ "_id" : "59752", "city" : "THREE FORKS", "loc" : [ -111.543643, 45.881068 ], "pop" : 1951, "state" : "MT" }
+{ "_id" : "59754", "city" : "TWIN BRIDGES", "loc" : [ -112.349461, 45.531055 ], "pop" : 1041, "state" : "MT" }
+{ "_id" : "59755", "city" : "VIRGINIA CITY", "loc" : [ -112.002619, 45.247216 ], "pop" : 268, "state" : "MT" }
+{ "_id" : "59756", "city" : "WARMSPRINGS", "loc" : [ -112.820041, 46.162593 ], "pop" : 1667, "state" : "MT" }
+{ "_id" : "59758", "city" : "WEST YELLOWSTONE", "loc" : [ -111.18595, 44.912502 ], "pop" : 1987, "state" : "MT" }
+{ "_id" : "59759", "city" : "WHITEHALL", "loc" : [ -112.124535, 45.877146 ], "pop" : 2591, "state" : "MT" }
+{ "_id" : "59761", "city" : "WISDOM", "loc" : [ -113.472926, 45.651915 ], "pop" : 224, "state" : "MT" }
+{ "_id" : "59762", "city" : "WISE RIVER", "loc" : [ -112.996285, 45.742397 ], "pop" : 199, "state" : "MT" }
+{ "_id" : "59801", "city" : "MISSOULA", "loc" : [ -114.025207, 46.856274 ], "pop" : 33811, "state" : "MT" }
+{ "_id" : "59802", "city" : "MISSOULA", "loc" : [ -114.002732, 46.900615 ], "pop" : 22650, "state" : "MT" }
+{ "_id" : "59803", "city" : "MISSOULA", "loc" : [ -114.026528, 46.822362 ], "pop" : 10444, "state" : "MT" }
+{ "_id" : "59820", "city" : "ALBERTON", "loc" : [ -114.492139, 46.98061 ], "pop" : 885, "state" : "MT" }
+{ "_id" : "59821", "city" : "ARLEE", "loc" : [ -114.075978, 47.186035 ], "pop" : 1432, "state" : "MT" }
+{ "_id" : "59823", "city" : "BONNER", "loc" : [ -113.746254, 46.860138 ], "pop" : 1625, "state" : "MT" }
+{ "_id" : "59824", "city" : "MOIESE", "loc" : [ -114.15931, 47.433449 ], "pop" : 1638, "state" : "MT" }
+{ "_id" : "59825", "city" : "CLINTON", "loc" : [ -113.703764, 46.767281 ], "pop" : 829, "state" : "MT" }
+{ "_id" : "59826", "city" : "CONDON", "loc" : [ -113.707477, 47.509696 ], "pop" : 534, "state" : "MT" }
+{ "_id" : "59827", "city" : "CONNER", "loc" : [ -114.179966, 45.912762 ], "pop" : 579, "state" : "MT" }
+{ "_id" : "59828", "city" : "CORVALLIS", "loc" : [ -114.095995, 46.314193 ], "pop" : 2987, "state" : "MT" }
+{ "_id" : "59829", "city" : "DARBY", "loc" : [ -114.193784, 46.028033 ], "pop" : 1657, "state" : "MT" }
+{ "_id" : "59831", "city" : "DIXON", "loc" : [ -114.30557, 47.31313 ], "pop" : 454, "state" : "MT" }
+{ "_id" : "59832", "city" : "DRUMMOND", "loc" : [ -113.242649, 46.664676 ], "pop" : 800, "state" : "MT" }
+{ "_id" : "59833", "city" : "FLORENCE", "loc" : [ -114.094487, 46.63102 ], "pop" : 3184, "state" : "MT" }
+{ "_id" : "59834", "city" : "FRENCHTOWN", "loc" : [ -114.268308, 47.047112 ], "pop" : 1679, "state" : "MT" }
+{ "_id" : "59836", "city" : "GREENOUGH", "loc" : [ -113.427017, 46.943361 ], "pop" : 372, "state" : "MT" }
+{ "_id" : "59837", "city" : "HALL", "loc" : [ -113.208725, 46.582539 ], "pop" : 276, "state" : "MT" }
+{ "_id" : "59840", "city" : "HAMILTON", "loc" : [ -114.167869, 46.23953 ], "pop" : 9548, "state" : "MT" }
+{ "_id" : "59843", "city" : "HELMVILLE", "loc" : [ -112.941296, 46.829968 ], "pop" : 155, "state" : "MT" }
+{ "_id" : "59844", "city" : "HERON", "loc" : [ -115.940668, 48.053668 ], "pop" : 559, "state" : "MT" }
+{ "_id" : "59845", "city" : "HOT SPRINGS", "loc" : [ -114.659712, 47.591408 ], "pop" : 858, "state" : "MT" }
+{ "_id" : "59846", "city" : "HUSON", "loc" : [ -114.421939, 47.065953 ], "pop" : 562, "state" : "MT" }
+{ "_id" : "59847", "city" : "LOLO", "loc" : [ -114.109732, 46.7585 ], "pop" : 3783, "state" : "MT" }
+{ "_id" : "59848", "city" : "LONEPINE", "loc" : [ -114.63718, 47.711209 ], "pop" : 236, "state" : "MT" }
+{ "_id" : "59852", "city" : "NIARADA", "loc" : [ -114.656218, 47.8031 ], "pop" : 58, "state" : "MT" }
+{ "_id" : "59853", "city" : "NOXON", "loc" : [ -115.780658, 48.030166 ], "pop" : 530, "state" : "MT" }
+{ "_id" : "59854", "city" : "OVANDO", "loc" : [ -113.090528, 47.006719 ], "pop" : 362, "state" : "MT" }
+{ "_id" : "59858", "city" : "PHILIPSBURG", "loc" : [ -113.3126, 46.318899 ], "pop" : 1445, "state" : "MT" }
+{ "_id" : "59859", "city" : "PLAINS", "loc" : [ -114.893014, 47.473448 ], "pop" : 2590, "state" : "MT" }
+{ "_id" : "59860", "city" : "POLSON", "loc" : [ -114.140444, 47.687574 ], "pop" : 6294, "state" : "MT" }
+{ "_id" : "59864", "city" : "RONAN", "loc" : [ -114.105385, 47.552457 ], "pop" : 5682, "state" : "MT" }
+{ "_id" : "59865", "city" : "SAINT IGNATIUS", "loc" : [ -114.075822, 47.330014 ], "pop" : 2283, "state" : "MT" }
+{ "_id" : "59866", "city" : "SAINT REGIS", "loc" : [ -115.170323, 47.336899 ], "pop" : 962, "state" : "MT" }
+{ "_id" : "59868", "city" : "SEELEY LAKE", "loc" : [ -113.481019, 47.178928 ], "pop" : 1240, "state" : "MT" }
+{ "_id" : "59870", "city" : "STEVENSVILLE", "loc" : [ -114.047846, 46.526723 ], "pop" : 5250, "state" : "MT" }
+{ "_id" : "59871", "city" : "SULA", "loc" : [ -114.042968, 45.827701 ], "pop" : 422, "state" : "MT" }
+{ "_id" : "59872", "city" : "SUPERIOR", "loc" : [ -114.888483, 47.172103 ], "pop" : 1825, "state" : "MT" }
+{ "_id" : "59873", "city" : "THOMPSON FALLS", "loc" : [ -115.360236, 47.601572 ], "pop" : 2311, "state" : "MT" }
+{ "_id" : "59874", "city" : "TROUT CREEK", "loc" : [ -115.559185, 47.811138 ], "pop" : 1095, "state" : "MT" }
+{ "_id" : "59875", "city" : "VICTOR", "loc" : [ -114.166534, 46.400489 ], "pop" : 2211, "state" : "MT" }
+{ "_id" : "59901", "city" : "EVERGREEN", "loc" : [ -114.289163, 48.220939 ], "pop" : 33469, "state" : "MT" }
+{ "_id" : "59910", "city" : "BIG ARM", "loc" : [ -114.207049, 47.758514 ], "pop" : 1089, "state" : "MT" }
+{ "_id" : "59911", "city" : "SWAN LAKE", "loc" : [ -114.01993, 48.039725 ], "pop" : 5119, "state" : "MT" }
+{ "_id" : "59912", "city" : "COLUMBIA FALLS", "loc" : [ -114.178394, 48.353394 ], "pop" : 9275, "state" : "MT" }
+{ "_id" : "59914", "city" : "DAYTON", "loc" : [ -114.280918, 47.860749 ], "pop" : 226, "state" : "MT" }
+{ "_id" : "59915", "city" : "ELMO", "loc" : [ -114.343938, 47.818541 ], "pop" : 243, "state" : "MT" }
+{ "_id" : "59916", "city" : "ESSEX", "loc" : [ -113.946678, 48.494028 ], "pop" : 98, "state" : "MT" }
+{ "_id" : "59917", "city" : "EUREKA", "loc" : [ -115.004938, 48.842766 ], "pop" : 3747, "state" : "MT" }
+{ "_id" : "59920", "city" : "KILA", "loc" : [ -114.510402, 48.074437 ], "pop" : 578, "state" : "MT" }
+{ "_id" : "59922", "city" : "LAKESIDE", "loc" : [ -114.226562, 48.021469 ], "pop" : 1027, "state" : "MT" }
+{ "_id" : "59923", "city" : "LIBBY", "loc" : [ -115.539101, 48.377311 ], "pop" : 10148, "state" : "MT" }
+{ "_id" : "59925", "city" : "MARION", "loc" : [ -114.744625, 48.083596 ], "pop" : 475, "state" : "MT" }
+{ "_id" : "59928", "city" : "POLEBRIDGE", "loc" : [ -114.383558, 48.820585 ], "pop" : 97, "state" : "MT" }
+{ "_id" : "59929", "city" : "PROCTOR", "loc" : [ -114.383193, 47.940371 ], "pop" : 66, "state" : "MT" }
+{ "_id" : "59930", "city" : "REXFORD", "loc" : [ -115.212859, 48.917947 ], "pop" : 440, "state" : "MT" }
+{ "_id" : "59931", "city" : "ROLLINS", "loc" : [ -114.224986, 47.918207 ], "pop" : 205, "state" : "MT" }
+{ "_id" : "59932", "city" : "SOMERS", "loc" : [ -114.23548, 48.079329 ], "pop" : 1104, "state" : "MT" }
+{ "_id" : "59935", "city" : "TROY", "loc" : [ -115.881684, 48.479119 ], "pop" : 3146, "state" : "MT" }
+{ "_id" : "59937", "city" : "WHITEFISH", "loc" : [ -114.350859, 48.403999 ], "pop" : 9837, "state" : "MT" }
+{ "_id" : "60002", "city" : "ANTIOCH", "loc" : [ -88.117802, 42.464811 ], "pop" : 18058, "state" : "IL" }
+{ "_id" : "60004", "city" : "ARLINGTON HEIGHT", "loc" : [ -87.97909900000001, 42.111619 ], "pop" : 52947, "state" : "IL" }
+{ "_id" : "60005", "city" : "ARLINGTON HEIGHT", "loc" : [ -87.985461, 42.066599 ], "pop" : 26742, "state" : "IL" }
+{ "_id" : "60007", "city" : "ELK GROVE VILLAG", "loc" : [ -88.012775, 42.005613 ], "pop" : 34577, "state" : "IL" }
+{ "_id" : "60008", "city" : "ROLLING MEADOWS", "loc" : [ -88.019075, 42.072979 ], "pop" : 18672, "state" : "IL" }
+{ "_id" : "60010", "city" : "BARRINGTON", "loc" : [ -88.138345, 42.161387 ], "pop" : 37323, "state" : "IL" }
+{ "_id" : "60012", "city" : "CRYSTAL LAKE", "loc" : [ -88.32129399999999, 42.266198 ], "pop" : 6855, "state" : "IL" }
+{ "_id" : "60013", "city" : "CARY", "loc" : [ -88.242594, 42.219599 ], "pop" : 17521, "state" : "IL" }
+{ "_id" : "60014", "city" : "CRYSTAL LAKE", "loc" : [ -88.332364, 42.230755 ], "pop" : 29595, "state" : "IL" }
+{ "_id" : "60015", "city" : "DEERFIELD", "loc" : [ -87.859033, 42.170494 ], "pop" : 22048, "state" : "IL" }
+{ "_id" : "60016", "city" : "DES PLAINES", "loc" : [ -87.88589899999999, 42.046734 ], "pop" : 54734, "state" : "IL" }
+{ "_id" : "60018", "city" : "ROSEMONT", "loc" : [ -87.897882, 42.015116 ], "pop" : 28884, "state" : "IL" }
+{ "_id" : "60020", "city" : "FOX LAKE", "loc" : [ -88.16475199999999, 42.393701 ], "pop" : 10336, "state" : "IL" }
+{ "_id" : "60021", "city" : "FOX RIVER GROVE", "loc" : [ -88.220483, 42.193594 ], "pop" : 4898, "state" : "IL" }
+{ "_id" : "60022", "city" : "GLENCOE", "loc" : [ -87.761486, 42.133339 ], "pop" : 8168, "state" : "IL" }
+{ "_id" : "60025", "city" : "GLENVIEW", "loc" : [ -87.822299, 42.075785 ], "pop" : 45038, "state" : "IL" }
+{ "_id" : "60026", "city" : "GLENVIEW NAS", "loc" : [ -87.824782, 42.09134 ], "pop" : 437, "state" : "IL" }
+{ "_id" : "60030", "city" : "GAGES LAKE", "loc" : [ -88.037789, 42.34848 ], "pop" : 8038, "state" : "IL" }
+{ "_id" : "60031", "city" : "GURNEE", "loc" : [ -87.945232, 42.366906 ], "pop" : 32114, "state" : "IL" }
+{ "_id" : "60033", "city" : "HARVARD", "loc" : [ -88.604812, 42.422727 ], "pop" : 10790, "state" : "IL" }
+{ "_id" : "60034", "city" : "HEBRON", "loc" : [ -88.41758299999999, 42.464173 ], "pop" : 1606, "state" : "IL" }
+{ "_id" : "60035", "city" : "HIGHLAND PARK", "loc" : [ -87.805894, 42.179446 ], "pop" : 29346, "state" : "IL" }
+{ "_id" : "60037", "city" : "FORT SHERIDAN", "loc" : [ -87.805572, 42.209683 ], "pop" : 2598, "state" : "IL" }
+{ "_id" : "60040", "city" : "HIGHWOOD", "loc" : [ -87.81406800000001, 42.203549 ], "pop" : 3956, "state" : "IL" }
+{ "_id" : "60041", "city" : "INGLESIDE", "loc" : [ -88.158749, 42.363093 ], "pop" : 4267, "state" : "IL" }
+{ "_id" : "60042", "city" : "ISLAND LAKE", "loc" : [ -88.19262999999999, 42.274186 ], "pop" : 3919, "state" : "IL" }
+{ "_id" : "60043", "city" : "KENILWORTH", "loc" : [ -87.716463, 42.088444 ], "pop" : 2509, "state" : "IL" }
+{ "_id" : "60044", "city" : "LAKE BLUFF", "loc" : [ -87.85595000000001, 42.28196 ], "pop" : 8031, "state" : "IL" }
+{ "_id" : "60045", "city" : "LAKE FOREST", "loc" : [ -87.84815399999999, 42.237398 ], "pop" : 17948, "state" : "IL" }
+{ "_id" : "60046", "city" : "LINDENHURST", "loc" : [ -88.063318, 42.414796 ], "pop" : 20764, "state" : "IL" }
+{ "_id" : "60047", "city" : "LONG GROVE", "loc" : [ -88.07029900000001, 42.196721 ], "pop" : 26893, "state" : "IL" }
+{ "_id" : "60048", "city" : "LIBERTYVILLE", "loc" : [ -87.949955, 42.281001 ], "pop" : 28573, "state" : "IL" }
+{ "_id" : "60050", "city" : "MC HENRY", "loc" : [ -88.254429, 42.345527 ], "pop" : 39545, "state" : "IL" }
+{ "_id" : "60053", "city" : "MORTON GROVE", "loc" : [ -87.789879, 42.043133 ], "pop" : 22502, "state" : "IL" }
+{ "_id" : "60056", "city" : "MOUNT PROSPECT", "loc" : [ -87.937667, 42.062392 ], "pop" : 54459, "state" : "IL" }
+{ "_id" : "60060", "city" : "MUNDELEIN", "loc" : [ -88.004762, 42.263616 ], "pop" : 22817, "state" : "IL" }
+{ "_id" : "60061", "city" : "VERNON HILLS", "loc" : [ -87.971852, 42.228753 ], "pop" : 19713, "state" : "IL" }
+{ "_id" : "60062", "city" : "NORTHBROOK", "loc" : [ -87.846535, 42.125443 ], "pop" : 40216, "state" : "IL" }
+{ "_id" : "60064", "city" : "ABBOTT PARK", "loc" : [ -87.847819, 42.318901 ], "pop" : 26542, "state" : "IL" }
+{ "_id" : "60067", "city" : "PALATINE", "loc" : [ -88.04293699999999, 42.113888 ], "pop" : 57281, "state" : "IL" }
+{ "_id" : "60068", "city" : "PARK RIDGE", "loc" : [ -87.841675, 42.012171 ], "pop" : 37450, "state" : "IL" }
+{ "_id" : "60069", "city" : "PRAIRIE VIEW", "loc" : [ -87.90482299999999, 42.192872 ], "pop" : 4047, "state" : "IL" }
+{ "_id" : "60070", "city" : "PROSPECT HEIGHTS", "loc" : [ -87.914934, 42.103324 ], "pop" : 14692, "state" : "IL" }
+{ "_id" : "60071", "city" : "RICHMOND", "loc" : [ -88.290024, 42.466863 ], "pop" : 2658, "state" : "IL" }
+{ "_id" : "60072", "city" : "RINGWOOD", "loc" : [ -88.297073, 42.380427 ], "pop" : 1926, "state" : "IL" }
+{ "_id" : "60073", "city" : "ROUND LAKE", "loc" : [ -88.088819, 42.366809 ], "pop" : 28919, "state" : "IL" }
+{ "_id" : "60074", "city" : "PALATINE", "loc" : [ -88.022998, 42.145775 ], "pop" : 11712, "state" : "IL" }
+{ "_id" : "60076", "city" : "SKOKIE", "loc" : [ -87.732828, 42.036168 ], "pop" : 31589, "state" : "IL" }
+{ "_id" : "60077", "city" : "SKOKIE", "loc" : [ -87.75412300000001, 42.034525 ], "pop" : 22680, "state" : "IL" }
+{ "_id" : "60081", "city" : "SPRING GROVE", "loc" : [ -88.22373399999999, 42.441267 ], "pop" : 2783, "state" : "IL" }
+{ "_id" : "60082", "city" : "TECHNY", "loc" : [ -87.80488200000001, 42.121425 ], "pop" : 196, "state" : "IL" }
+{ "_id" : "60083", "city" : "WADSWORTH", "loc" : [ -87.904048, 42.446032 ], "pop" : 5510, "state" : "IL" }
+{ "_id" : "60084", "city" : "WAUCONDA", "loc" : [ -88.133284, 42.263553 ], "pop" : 11142, "state" : "IL" }
+{ "_id" : "60085", "city" : "MC GAW PARK", "loc" : [ -87.852585, 42.361882 ], "pop" : 55778, "state" : "IL" }
+{ "_id" : "60087", "city" : "WAUKEGAN", "loc" : [ -87.85538699999999, 42.398906 ], "pop" : 17816, "state" : "IL" }
+{ "_id" : "60088", "city" : "GREAT LAKES", "loc" : [ -87.864192, 42.303173 ], "pop" : 8831, "state" : "IL" }
+{ "_id" : "60089", "city" : "BUFFALO GROVE", "loc" : [ -87.964364, 42.159843 ], "pop" : 41478, "state" : "IL" }
+{ "_id" : "60090", "city" : "WHEELING", "loc" : [ -87.93409699999999, 42.13404 ], "pop" : 31261, "state" : "IL" }
+{ "_id" : "60091", "city" : "WILMETTE", "loc" : [ -87.72457199999999, 42.076462 ], "pop" : 26657, "state" : "IL" }
+{ "_id" : "60093", "city" : "NORTHFIELD", "loc" : [ -87.752256, 42.103605 ], "pop" : 19317, "state" : "IL" }
+{ "_id" : "60096", "city" : "WINTHROP HARBOR", "loc" : [ -87.831788, 42.479269 ], "pop" : 7433, "state" : "IL" }
+{ "_id" : "60097", "city" : "WONDER LAKE", "loc" : [ -88.353364, 42.384908 ], "pop" : 8401, "state" : "IL" }
+{ "_id" : "60098", "city" : "WOODSTOCK", "loc" : [ -88.447671, 42.319775 ], "pop" : 21770, "state" : "IL" }
+{ "_id" : "60099", "city" : "ZION", "loc" : [ -87.838925, 42.444249 ], "pop" : 24944, "state" : "IL" }
+{ "_id" : "60101", "city" : "ADDISON", "loc" : [ -88.00539999999999, 41.933509 ], "pop" : 35140, "state" : "IL" }
+{ "_id" : "60102", "city" : "LAKE IN THE HILL", "loc" : [ -88.301429, 42.170923 ], "pop" : 22082, "state" : "IL" }
+{ "_id" : "60103", "city" : "HANOVER PARK", "loc" : [ -88.16035599999999, 41.983559 ], "pop" : 51877, "state" : "IL" }
+{ "_id" : "60104", "city" : "BELLWOOD", "loc" : [ -87.878557, 41.882484 ], "pop" : 19336, "state" : "IL" }
+{ "_id" : "60106", "city" : "BENSENVILLE", "loc" : [ -87.944973, 41.950145 ], "pop" : 20080, "state" : "IL" }
+{ "_id" : "60107", "city" : "STREAMWOOD", "loc" : [ -88.168965, 42.022539 ], "pop" : 30513, "state" : "IL" }
+{ "_id" : "60108", "city" : "BLOOMINGDALE", "loc" : [ -88.07823999999999, 41.94827 ], "pop" : 16560, "state" : "IL" }
+{ "_id" : "60110", "city" : "CARPENTERSVILLE", "loc" : [ -88.2606, 42.123004 ], "pop" : 23550, "state" : "IL" }
+{ "_id" : "60111", "city" : "CLARE", "loc" : [ -88.83783200000001, 42.027045 ], "pop" : 373, "state" : "IL" }
+{ "_id" : "60115", "city" : "DE KALB", "loc" : [ -88.760673, 41.934245 ], "pop" : 38360, "state" : "IL" }
+{ "_id" : "60118", "city" : "DUNDEE", "loc" : [ -88.29020199999999, 42.096197 ], "pop" : 11919, "state" : "IL" }
+{ "_id" : "60119", "city" : "ELBURN", "loc" : [ -88.461106, 41.882405 ], "pop" : 6271, "state" : "IL" }
+{ "_id" : "60120", "city" : "ELGIN", "loc" : [ -88.260631, 42.038356 ], "pop" : 42848, "state" : "IL" }
+{ "_id" : "60123", "city" : "ELGIN", "loc" : [ -88.31861499999999, 42.037574 ], "pop" : 43835, "state" : "IL" }
+{ "_id" : "60126", "city" : "ELMHURST", "loc" : [ -87.941025, 41.892661 ], "pop" : 43637, "state" : "IL" }
+{ "_id" : "60129", "city" : "ESMOND", "loc" : [ -88.94386, 42.022458 ], "pop" : 388, "state" : "IL" }
+{ "_id" : "60130", "city" : "FOREST PARK", "loc" : [ -87.810624, 41.874373 ], "pop" : 14882, "state" : "IL" }
+{ "_id" : "60131", "city" : "FRANKLIN PARK", "loc" : [ -87.873423, 41.933878 ], "pop" : 18572, "state" : "IL" }
+{ "_id" : "60134", "city" : "GENEVA", "loc" : [ -88.310954, 41.886013 ], "pop" : 13603, "state" : "IL" }
+{ "_id" : "60135", "city" : "GENOA", "loc" : [ -88.690803, 42.09811 ], "pop" : 4356, "state" : "IL" }
+{ "_id" : "60136", "city" : "GILBERTS", "loc" : [ -88.369089, 42.098377 ], "pop" : 1212, "state" : "IL" }
+{ "_id" : "60137", "city" : "GLEN ELLYN", "loc" : [ -88.064774, 41.866112 ], "pop" : 35643, "state" : "IL" }
+{ "_id" : "60139", "city" : "GLENDALE HEIGHTS", "loc" : [ -88.07928200000001, 41.920523 ], "pop" : 27324, "state" : "IL" }
+{ "_id" : "60140", "city" : "HAMPSHIRE", "loc" : [ -88.517033, 42.080748 ], "pop" : 6255, "state" : "IL" }
+{ "_id" : "60141", "city" : "HINES", "loc" : [ -87.835542, 41.862262 ], "pop" : 200, "state" : "IL" }
+{ "_id" : "60142", "city" : "HUNTLEY", "loc" : [ -88.42684800000001, 42.175555 ], "pop" : 4351, "state" : "IL" }
+{ "_id" : "60143", "city" : "ITASCA", "loc" : [ -88.020247, 41.971967 ], "pop" : 8650, "state" : "IL" }
+{ "_id" : "60145", "city" : "KINGSTON", "loc" : [ -88.769496, 42.105654 ], "pop" : 1555, "state" : "IL" }
+{ "_id" : "60146", "city" : "KIRKLAND", "loc" : [ -88.868522, 42.101406 ], "pop" : 1930, "state" : "IL" }
+{ "_id" : "60148", "city" : "LOMBARD", "loc" : [ -88.01598799999999, 41.872139 ], "pop" : 52289, "state" : "IL" }
+{ "_id" : "60150", "city" : "MALTA", "loc" : [ -88.868818, 41.918332 ], "pop" : 1619, "state" : "IL" }
+{ "_id" : "60151", "city" : "MAPLE PARK", "loc" : [ -88.59985, 41.923217 ], "pop" : 4893, "state" : "IL" }
+{ "_id" : "60152", "city" : "MARENGO", "loc" : [ -88.60736900000001, 42.244189 ], "pop" : 8536, "state" : "IL" }
+{ "_id" : "60153", "city" : "BROADVIEW", "loc" : [ -87.847675, 41.874857 ], "pop" : 37099, "state" : "IL" }
+{ "_id" : "60154", "city" : "WESTCHESTER", "loc" : [ -87.884488, 41.852368 ], "pop" : 16957, "state" : "IL" }
+{ "_id" : "60157", "city" : "MEDINAH", "loc" : [ -88.057507, 41.970545 ], "pop" : 3110, "state" : "IL" }
+{ "_id" : "60160", "city" : "MELROSE PARK", "loc" : [ -87.85806599999999, 41.900347 ], "pop" : 21235, "state" : "IL" }
+{ "_id" : "60162", "city" : "HILLSIDE", "loc" : [ -87.901591, 41.872452 ], "pop" : 7757, "state" : "IL" }
+{ "_id" : "60163", "city" : "HILLSIDE", "loc" : [ -87.910678, 41.886538 ], "pop" : 5079, "state" : "IL" }
+{ "_id" : "60164", "city" : "NORTHLAKE", "loc" : [ -87.89592, 41.917961 ], "pop" : 21306, "state" : "IL" }
+{ "_id" : "60165", "city" : "STONE PARK", "loc" : [ -87.88105299999999, 41.903005 ], "pop" : 4387, "state" : "IL" }
+{ "_id" : "60171", "city" : "RIVER GROVE", "loc" : [ -87.838707, 41.927886 ], "pop" : 9949, "state" : "IL" }
+{ "_id" : "60172", "city" : "ROSELLE", "loc" : [ -88.08569900000001, 41.979834 ], "pop" : 22626, "state" : "IL" }
+{ "_id" : "60173", "city" : "SCHAUMBURG", "loc" : [ -88.04818899999999, 42.05807 ], "pop" : 9314, "state" : "IL" }
+{ "_id" : "60174", "city" : "SAINT CHARLES", "loc" : [ -88.307022, 41.919417 ], "pop" : 27454, "state" : "IL" }
+{ "_id" : "60175", "city" : "SAINT CHARLES", "loc" : [ -88.39179900000001, 41.947842 ], "pop" : 11851, "state" : "IL" }
+{ "_id" : "60176", "city" : "SCHILLER PARK", "loc" : [ -87.869179, 41.956304 ], "pop" : 11189, "state" : "IL" }
+{ "_id" : "60177", "city" : "SOUTH ELGIN", "loc" : [ -88.298558, 41.996868 ], "pop" : 9117, "state" : "IL" }
+{ "_id" : "60178", "city" : "SYCAMORE", "loc" : [ -88.692809, 41.991117 ], "pop" : 13512, "state" : "IL" }
+{ "_id" : "60180", "city" : "UNION", "loc" : [ -88.528295, 42.210274 ], "pop" : 1450, "state" : "IL" }
+{ "_id" : "60181", "city" : "VILLA PARK", "loc" : [ -87.978246, 41.879899 ], "pop" : 27217, "state" : "IL" }
+{ "_id" : "60185", "city" : "WEST CHICAGO", "loc" : [ -88.202168, 41.888558 ], "pop" : 23894, "state" : "IL" }
+{ "_id" : "60187", "city" : "WHEATON", "loc" : [ -88.10763300000001, 41.856592 ], "pop" : 57758, "state" : "IL" }
+{ "_id" : "60188", "city" : "CAROL STREAM", "loc" : [ -88.136962, 41.91784 ], "pop" : 34902, "state" : "IL" }
+{ "_id" : "60190", "city" : "WINFIELD", "loc" : [ -88.15162100000001, 41.874358 ], "pop" : 9255, "state" : "IL" }
+{ "_id" : "60191", "city" : "WOOD DALE", "loc" : [ -87.980971, 41.960171 ], "pop" : 13750, "state" : "IL" }
+{ "_id" : "60193", "city" : "SCHAUMBURG", "loc" : [ -88.093481, 42.014432 ], "pop" : 39438, "state" : "IL" }
+{ "_id" : "60194", "city" : "HOFFMAN ESTATES", "loc" : [ -88.109442, 42.039025 ], "pop" : 37295, "state" : "IL" }
+{ "_id" : "60195", "city" : "HOFFMAN ESTATES", "loc" : [ -88.108709, 42.073865 ], "pop" : 29236, "state" : "IL" }
+{ "_id" : "60201", "city" : "EVANSTON", "loc" : [ -87.69433100000001, 42.054551 ], "pop" : 41692, "state" : "IL" }
+{ "_id" : "60202", "city" : "EVANSTON", "loc" : [ -87.686544, 42.03022 ], "pop" : 31509, "state" : "IL" }
+{ "_id" : "60203", "city" : "EVANSTON", "loc" : [ -87.71759, 42.048487 ], "pop" : 4764, "state" : "IL" }
+{ "_id" : "60301", "city" : "OAK PARK", "loc" : [ -87.798598, 41.888601 ], "pop" : 1673, "state" : "IL" }
+{ "_id" : "60302", "city" : "OAK PARK", "loc" : [ -87.78954299999999, 41.892471 ], "pop" : 33298, "state" : "IL" }
+{ "_id" : "60304", "city" : "OAK PARK", "loc" : [ -87.787712, 41.872458 ], "pop" : 18677, "state" : "IL" }
+{ "_id" : "60305", "city" : "RIVER FOREST", "loc" : [ -87.8159, 41.895064 ], "pop" : 11669, "state" : "IL" }
+{ "_id" : "60401", "city" : "BEECHER", "loc" : [ -87.611538, 41.34437 ], "pop" : 3724, "state" : "IL" }
+{ "_id" : "60402", "city" : "STICKNEY", "loc" : [ -87.79075, 41.841819 ], "pop" : 51541, "state" : "IL" }
+{ "_id" : "60406", "city" : "BLUE ISLAND", "loc" : [ -87.67946499999999, 41.658187 ], "pop" : 23305, "state" : "IL" }
+{ "_id" : "60407", "city" : "BRACEVILLE", "loc" : [ -88.269042, 41.228788 ], "pop" : 1535, "state" : "IL" }
+{ "_id" : "60408", "city" : "BRAIDWOOD", "loc" : [ -88.223124, 41.26574 ], "pop" : 3814, "state" : "IL" }
+{ "_id" : "60409", "city" : "CALUMET CITY", "loc" : [ -87.548328, 41.615257 ], "pop" : 36065, "state" : "IL" }
+{ "_id" : "60410", "city" : "CHANNAHON", "loc" : [ -88.213786, 41.434664 ], "pop" : 3870, "state" : "IL" }
+{ "_id" : "60411", "city" : "SAUK VILLAGE", "loc" : [ -87.613209, 41.506202 ], "pop" : 60738, "state" : "IL" }
+{ "_id" : "60415", "city" : "CHICAGO RIDGE", "loc" : [ -87.77738100000001, 41.70171 ], "pop" : 13472, "state" : "IL" }
+{ "_id" : "60416", "city" : "COAL CITY", "loc" : [ -88.282346, 41.290769 ], "pop" : 6248, "state" : "IL" }
+{ "_id" : "60417", "city" : "CRETE", "loc" : [ -87.602738, 41.438952 ], "pop" : 14372, "state" : "IL" }
+{ "_id" : "60419", "city" : "DOLTON", "loc" : [ -87.59795200000001, 41.625723 ], "pop" : 22705, "state" : "IL" }
+{ "_id" : "60420", "city" : "DWIGHT", "loc" : [ -88.41588400000001, 41.088701 ], "pop" : 4956, "state" : "IL" }
+{ "_id" : "60421", "city" : "ELWOOD", "loc" : [ -88.08642, 41.426018 ], "pop" : 2700, "state" : "IL" }
+{ "_id" : "60422", "city" : "FLOSSMOOR", "loc" : [ -87.68373699999999, 41.540574 ], "pop" : 8627, "state" : "IL" }
+{ "_id" : "60423", "city" : "FRANKFORT", "loc" : [ -87.82477400000001, 41.509361 ], "pop" : 15682, "state" : "IL" }
+{ "_id" : "60424", "city" : "GARDNER", "loc" : [ -88.296543, 41.179321 ], "pop" : 2349, "state" : "IL" }
+{ "_id" : "60425", "city" : "GLENWOOD", "loc" : [ -87.612584, 41.546718 ], "pop" : 10180, "state" : "IL" }
+{ "_id" : "60426", "city" : "MARKHAM", "loc" : [ -87.661115, 41.608536 ], "pop" : 48332, "state" : "IL" }
+{ "_id" : "60429", "city" : "HAZEL CREST", "loc" : [ -87.68488499999999, 41.573803 ], "pop" : 14987, "state" : "IL" }
+{ "_id" : "60430", "city" : "HOMEWOOD", "loc" : [ -87.66157800000001, 41.555579 ], "pop" : 19469, "state" : "IL" }
+{ "_id" : "60431", "city" : "JOLIET", "loc" : [ -88.08241, 41.527154 ], "pop" : 512, "state" : "IL" }
+{ "_id" : "60432", "city" : "JOLIET", "loc" : [ -88.05717799999999, 41.537758 ], "pop" : 20199, "state" : "IL" }
+{ "_id" : "60433", "city" : "JOLIET", "loc" : [ -88.05687, 41.511873 ], "pop" : 18342, "state" : "IL" }
+{ "_id" : "60435", "city" : "SHOREWOOD", "loc" : [ -88.128107, 41.541468 ], "pop" : 56510, "state" : "IL" }
+{ "_id" : "60436", "city" : "ROCKDALE", "loc" : [ -88.135779, 41.508818 ], "pop" : 23888, "state" : "IL" }
+{ "_id" : "60437", "city" : "KINSMAN", "loc" : [ -88.48047699999999, 41.161825 ], "pop" : 687, "state" : "IL" }
+{ "_id" : "60438", "city" : "LANSING", "loc" : [ -87.544634, 41.566045 ], "pop" : 28810, "state" : "IL" }
+{ "_id" : "60439", "city" : "ARGONNE", "loc" : [ -88.02355799999999, 41.695076 ], "pop" : 31018, "state" : "IL" }
+{ "_id" : "60440", "city" : "BOLINGBROOK", "loc" : [ -88.087315, 41.697605 ], "pop" : 23726, "state" : "IL" }
+{ "_id" : "60441", "city" : "ROMEOVILLE", "loc" : [ -88.025581, 41.613481 ], "pop" : 55268, "state" : "IL" }
+{ "_id" : "60442", "city" : "MANHATTAN", "loc" : [ -87.97713299999999, 41.428883 ], "pop" : 3657, "state" : "IL" }
+{ "_id" : "60443", "city" : "MATTESON", "loc" : [ -87.74064799999999, 41.510183 ], "pop" : 13624, "state" : "IL" }
+{ "_id" : "60444", "city" : "MAZON", "loc" : [ -88.409561, 41.297189 ], "pop" : 3909, "state" : "IL" }
+{ "_id" : "60445", "city" : "CRESTWOOD", "loc" : [ -87.732418, 41.634106 ], "pop" : 26378, "state" : "IL" }
+{ "_id" : "60447", "city" : "MINOOKA", "loc" : [ -88.27859599999999, 41.461516 ], "pop" : 6005, "state" : "IL" }
+{ "_id" : "60448", "city" : "MOKENA", "loc" : [ -87.891121, 41.53421 ], "pop" : 12324, "state" : "IL" }
+{ "_id" : "60449", "city" : "MONEE", "loc" : [ -87.77484, 41.419133 ], "pop" : 3537, "state" : "IL" }
+{ "_id" : "60450", "city" : "MORRIS", "loc" : [ -88.41776900000001, 41.367233 ], "pop" : 13423, "state" : "IL" }
+{ "_id" : "60451", "city" : "NEW LENOX", "loc" : [ -87.963083, 41.506701 ], "pop" : 17470, "state" : "IL" }
+{ "_id" : "60452", "city" : "OAK FOREST", "loc" : [ -87.75421900000001, 41.607684 ], "pop" : 26772, "state" : "IL" }
+{ "_id" : "60453", "city" : "OAK LAWN", "loc" : [ -87.751564, 41.714305 ], "pop" : 56039, "state" : "IL" }
+{ "_id" : "60455", "city" : "BRIDGEVIEW", "loc" : [ -87.806572, 41.743128 ], "pop" : 14065, "state" : "IL" }
+{ "_id" : "60456", "city" : "HOMETOWN", "loc" : [ -87.73153600000001, 41.73113 ], "pop" : 4769, "state" : "IL" }
+{ "_id" : "60457", "city" : "HICKORY HILLS", "loc" : [ -87.82889299999999, 41.726228 ], "pop" : 12894, "state" : "IL" }
+{ "_id" : "60458", "city" : "JUSTICE", "loc" : [ -87.834587, 41.744709 ], "pop" : 12773, "state" : "IL" }
+{ "_id" : "60459", "city" : "BURBANK", "loc" : [ -87.769907, 41.744704 ], "pop" : 27870, "state" : "IL" }
+{ "_id" : "60460", "city" : "ODELL", "loc" : [ -88.515641, 41.023773 ], "pop" : 2795, "state" : "IL" }
+{ "_id" : "60461", "city" : "OLYMPIA FIELDS", "loc" : [ -87.68995200000001, 41.51564 ], "pop" : 4253, "state" : "IL" }
+{ "_id" : "60462", "city" : "ORLAND PARK", "loc" : [ -87.84225000000001, 41.619378 ], "pop" : 42564, "state" : "IL" }
+{ "_id" : "60463", "city" : "PALOS HEIGHTS", "loc" : [ -87.792697, 41.662146 ], "pop" : 13509, "state" : "IL" }
+{ "_id" : "60464", "city" : "PALOS PARK", "loc" : [ -87.852146, 41.662352 ], "pop" : 8967, "state" : "IL" }
+{ "_id" : "60465", "city" : "PALOS HILLS", "loc" : [ -87.82627599999999, 41.700389 ], "pop" : 18112, "state" : "IL" }
+{ "_id" : "60466", "city" : "UNIVERSITY PARK", "loc" : [ -87.682867, 41.474064 ], "pop" : 31607, "state" : "IL" }
+{ "_id" : "60468", "city" : "PEOTONE", "loc" : [ -87.78968, 41.33609 ], "pop" : 4936, "state" : "IL" }
+{ "_id" : "60469", "city" : "POSEN", "loc" : [ -87.687213, 41.62766 ], "pop" : 4158, "state" : "IL" }
+{ "_id" : "60470", "city" : "RANSOM", "loc" : [ -88.65021400000001, 41.153048 ], "pop" : 690, "state" : "IL" }
+{ "_id" : "60471", "city" : "RICHTON PARK", "loc" : [ -87.723834, 41.481854 ], "pop" : 10776, "state" : "IL" }
+{ "_id" : "60472", "city" : "ROBBINS", "loc" : [ -87.70890900000001, 41.642289 ], "pop" : 7132, "state" : "IL" }
+{ "_id" : "60473", "city" : "SOUTH HOLLAND", "loc" : [ -87.59381399999999, 41.597916 ], "pop" : 24457, "state" : "IL" }
+{ "_id" : "60475", "city" : "STEGER", "loc" : [ -87.63858500000001, 41.468608 ], "pop" : 8531, "state" : "IL" }
+{ "_id" : "60476", "city" : "THORNTON", "loc" : [ -87.607823, 41.572726 ], "pop" : 2678, "state" : "IL" }
+{ "_id" : "60477", "city" : "TINLEY PARK", "loc" : [ -87.804963, 41.582535 ], "pop" : 45371, "state" : "IL" }
+{ "_id" : "60478", "city" : "COUNTRY CLUB HIL", "loc" : [ -87.718452, 41.559773 ], "pop" : 16225, "state" : "IL" }
+{ "_id" : "60479", "city" : "VERONA", "loc" : [ -88.51701, 41.250094 ], "pop" : 769, "state" : "IL" }
+{ "_id" : "60480", "city" : "WILLOW SPRINGS", "loc" : [ -87.87858799999999, 41.736416 ], "pop" : 4469, "state" : "IL" }
+{ "_id" : "60481", "city" : "CUSTER PARK", "loc" : [ -88.130083, 41.298063 ], "pop" : 11034, "state" : "IL" }
+{ "_id" : "60482", "city" : "WORTH", "loc" : [ -87.786272, 41.689498 ], "pop" : 13081, "state" : "IL" }
+{ "_id" : "60501", "city" : "ARGO", "loc" : [ -87.807468, 41.784245 ], "pop" : 10525, "state" : "IL" }
+{ "_id" : "60504", "city" : "AURORA", "loc" : [ -88.24528100000001, 41.752269 ], "pop" : 15334, "state" : "IL" }
+{ "_id" : "60505", "city" : "AURORA", "loc" : [ -88.297139, 41.758209 ], "pop" : 51422, "state" : "IL" }
+{ "_id" : "60506", "city" : "AURORA", "loc" : [ -88.344582, 41.766414 ], "pop" : 42636, "state" : "IL" }
+{ "_id" : "60510", "city" : "BATAVIA", "loc" : [ -88.30975599999999, 41.848165 ], "pop" : 19299, "state" : "IL" }
+{ "_id" : "60511", "city" : "BIG ROCK", "loc" : [ -88.537617, 41.759308 ], "pop" : 1976, "state" : "IL" }
+{ "_id" : "60512", "city" : "BRISTOL", "loc" : [ -88.401354, 41.707446 ], "pop" : 595, "state" : "IL" }
+{ "_id" : "60513", "city" : "BROOKFIELD", "loc" : [ -87.84924599999999, 41.82167 ], "pop" : 18859, "state" : "IL" }
+{ "_id" : "60514", "city" : "CLARENDON HILLS", "loc" : [ -87.955322, 41.779729 ], "pop" : 17321, "state" : "IL" }
+{ "_id" : "60515", "city" : "DOWNERS GROVE", "loc" : [ -88.01375299999999, 41.803428 ], "pop" : 26971, "state" : "IL" }
+{ "_id" : "60516", "city" : "DOWNERS GROVE", "loc" : [ -88.015873, 41.760157 ], "pop" : 35756, "state" : "IL" }
+{ "_id" : "60517", "city" : "WOODRIDGE", "loc" : [ -88.04885, 41.751755 ], "pop" : 23761, "state" : "IL" }
+{ "_id" : "60518", "city" : "EARLVILLE", "loc" : [ -88.910346, 41.585901 ], "pop" : 2305, "state" : "IL" }
+{ "_id" : "60520", "city" : "HINCKLEY", "loc" : [ -88.644831, 41.769108 ], "pop" : 2387, "state" : "IL" }
+{ "_id" : "60521", "city" : "OAK BROOK", "loc" : [ -87.940089, 41.7891 ], "pop" : 44245, "state" : "IL" }
+{ "_id" : "60525", "city" : "HODGKINS", "loc" : [ -87.875252, 41.801345 ], "pop" : 45424, "state" : "IL" }
+{ "_id" : "60530", "city" : "LEE", "loc" : [ -88.971386, 41.786418 ], "pop" : 825, "state" : "IL" }
+{ "_id" : "60531", "city" : "LELAND", "loc" : [ -88.771574, 41.606591 ], "pop" : 1601, "state" : "IL" }
+{ "_id" : "60532", "city" : "LISLE", "loc" : [ -88.0879, 41.786174 ], "pop" : 24914, "state" : "IL" }
+{ "_id" : "60534", "city" : "LYONS", "loc" : [ -87.823559, 41.813016 ], "pop" : 9828, "state" : "IL" }
+{ "_id" : "60538", "city" : "MONTGOMERY", "loc" : [ -88.331965, 41.717742 ], "pop" : 14146, "state" : "IL" }
+{ "_id" : "60539", "city" : "MOOSEHEART", "loc" : [ -88.331532, 41.824148 ], "pop" : 371, "state" : "IL" }
+{ "_id" : "60540", "city" : "NAPERVILLE", "loc" : [ -88.14103799999999, 41.766198 ], "pop" : 35414, "state" : "IL" }
+{ "_id" : "60541", "city" : "NEWARK", "loc" : [ -88.527006, 41.526679 ], "pop" : 3016, "state" : "IL" }
+{ "_id" : "60542", "city" : "NORTH AURORA", "loc" : [ -88.32742399999999, 41.808932 ], "pop" : 6618, "state" : "IL" }
+{ "_id" : "60543", "city" : "OSWEGO", "loc" : [ -88.345305, 41.684893 ], "pop" : 9649, "state" : "IL" }
+{ "_id" : "60544", "city" : "PLAINFIELD", "loc" : [ -88.19939100000001, 41.600884 ], "pop" : 10416, "state" : "IL" }
+{ "_id" : "60545", "city" : "PLANO", "loc" : [ -88.53838, 41.666987 ], "pop" : 7506, "state" : "IL" }
+{ "_id" : "60546", "city" : "NORTH RIVERSIDE", "loc" : [ -87.82135599999999, 41.837367 ], "pop" : 14899, "state" : "IL" }
+{ "_id" : "60548", "city" : "SANDWICH", "loc" : [ -88.639303, 41.635286 ], "pop" : 10125, "state" : "IL" }
+{ "_id" : "60549", "city" : "SERENA", "loc" : [ -88.75089, 41.499481 ], "pop" : 830, "state" : "IL" }
+{ "_id" : "60550", "city" : "SHABBONA", "loc" : [ -88.875249, 41.763846 ], "pop" : 1180, "state" : "IL" }
+{ "_id" : "60551", "city" : "SHERIDAN", "loc" : [ -88.67063400000001, 41.516428 ], "pop" : 3345, "state" : "IL" }
+{ "_id" : "60552", "city" : "SOMONAUK", "loc" : [ -88.681645, 41.638289 ], "pop" : 1475, "state" : "IL" }
+{ "_id" : "60553", "city" : "STEWARD", "loc" : [ -89.015086, 41.847545 ], "pop" : 661, "state" : "IL" }
+{ "_id" : "60554", "city" : "SUGAR GROVE", "loc" : [ -88.43972100000001, 41.774113 ], "pop" : 4255, "state" : "IL" }
+{ "_id" : "60555", "city" : "WARRENVILLE", "loc" : [ -88.19213000000001, 41.828046 ], "pop" : 12421, "state" : "IL" }
+{ "_id" : "60556", "city" : "WATERMAN", "loc" : [ -88.775381, 41.750365 ], "pop" : 1914, "state" : "IL" }
+{ "_id" : "60558", "city" : "WESTERN SPRINGS", "loc" : [ -87.899485, 41.804864 ], "pop" : 11862, "state" : "IL" }
+{ "_id" : "60559", "city" : "WESTMONT", "loc" : [ -87.975736, 41.772848 ], "pop" : 41903, "state" : "IL" }
+{ "_id" : "60560", "city" : "YORKVILLE", "loc" : [ -88.443794, 41.638725 ], "pop" : 8161, "state" : "IL" }
+{ "_id" : "60563", "city" : "NAPERVILLE", "loc" : [ -88.16901, 41.78955 ], "pop" : 26348, "state" : "IL" }
+{ "_id" : "60564", "city" : "NAPERVILLE", "loc" : [ -88.19524800000001, 41.704022 ], "pop" : 8549, "state" : "IL" }
+{ "_id" : "60565", "city" : "NAPERVILLE", "loc" : [ -88.12824500000001, 41.732833 ], "pop" : 32693, "state" : "IL" }
+{ "_id" : "60601", "city" : "CHICAGO", "loc" : [ -87.618123, 41.885847 ], "pop" : 4585, "state" : "IL" }
+{ "_id" : "60602", "city" : "CHICAGO", "loc" : [ -87.632125, 41.882883 ], "pop" : 59, "state" : "IL" }
+{ "_id" : "60603", "city" : "CHICAGO", "loc" : [ -87.62849900000001, 41.87985 ], "pop" : 0, "state" : "IL" }
+{ "_id" : "60604", "city" : "CHICAGO", "loc" : [ -87.632999, 41.87845 ], "pop" : 3, "state" : "IL" }
+{ "_id" : "60605", "city" : "CHICAGO", "loc" : [ -87.62771499999999, 41.87125 ], "pop" : 7709, "state" : "IL" }
+{ "_id" : "60606", "city" : "CHICAGO", "loc" : [ -87.638648, 41.886822 ], "pop" : 58, "state" : "IL" }
+{ "_id" : "60607", "city" : "CHICAGO", "loc" : [ -87.65784499999999, 41.872075 ], "pop" : 13745, "state" : "IL" }
+{ "_id" : "60608", "city" : "CHICAGO", "loc" : [ -87.669444, 41.851482 ], "pop" : 84518, "state" : "IL" }
+{ "_id" : "60609", "city" : "CHICAGO", "loc" : [ -87.653279, 41.809721 ], "pop" : 89762, "state" : "IL" }
+{ "_id" : "60610", "city" : "CHICAGO", "loc" : [ -87.633565, 41.903294 ], "pop" : 40840, "state" : "IL" }
+{ "_id" : "60611", "city" : "CHICAGO", "loc" : [ -87.62228500000001, 41.897105 ], "pop" : 22264, "state" : "IL" }
+{ "_id" : "60612", "city" : "CHICAGO", "loc" : [ -87.687333, 41.880483 ], "pop" : 44363, "state" : "IL" }
+{ "_id" : "60613", "city" : "CHICAGO", "loc" : [ -87.65749099999999, 41.954341 ], "pop" : 48963, "state" : "IL" }
+{ "_id" : "60614", "city" : "CHICAGO", "loc" : [ -87.648295, 41.92286 ], "pop" : 61350, "state" : "IL" }
+{ "_id" : "60615", "city" : "CHICAGO", "loc" : [ -87.600623, 41.802211 ], "pop" : 44137, "state" : "IL" }
+{ "_id" : "60616", "city" : "CHICAGO", "loc" : [ -87.63055199999999, 41.84258 ], "pop" : 45750, "state" : "IL" }
+{ "_id" : "60617", "city" : "CHICAGO", "loc" : [ -87.556012, 41.725743 ], "pop" : 98612, "state" : "IL" }
+{ "_id" : "60618", "city" : "CHICAGO", "loc" : [ -87.70421399999999, 41.946401 ], "pop" : 88377, "state" : "IL" }
+{ "_id" : "60619", "city" : "CHICAGO", "loc" : [ -87.60539, 41.745765 ], "pop" : 74469, "state" : "IL" }
+{ "_id" : "60620", "city" : "CHICAGO", "loc" : [ -87.654251, 41.741119 ], "pop" : 92005, "state" : "IL" }
+{ "_id" : "60621", "city" : "CHICAGO", "loc" : [ -87.64213599999999, 41.774993 ], "pop" : 56458, "state" : "IL" }
+{ "_id" : "60622", "city" : "CHICAGO", "loc" : [ -87.67785000000001, 41.901923 ], "pop" : 74468, "state" : "IL" }
+{ "_id" : "60623", "city" : "CHICAGO", "loc" : [ -87.7157, 41.849015 ], "pop" : 112047, "state" : "IL" }
+{ "_id" : "60624", "city" : "CHICAGO", "loc" : [ -87.72234899999999, 41.880394 ], "pop" : 50030, "state" : "IL" }
+{ "_id" : "60625", "city" : "CHICAGO", "loc" : [ -87.704157, 41.970325 ], "pop" : 83401, "state" : "IL" }
+{ "_id" : "60626", "city" : "CHICAGO", "loc" : [ -87.668887, 42.009475 ], "pop" : 57320, "state" : "IL" }
+{ "_id" : "60627", "city" : "RIVERDALE", "loc" : [ -87.618213, 41.645918 ], "pop" : 24996, "state" : "IL" }
+{ "_id" : "60628", "city" : "CHICAGO", "loc" : [ -87.62427700000001, 41.693443 ], "pop" : 94317, "state" : "IL" }
+{ "_id" : "60629", "city" : "CHICAGO", "loc" : [ -87.706936, 41.778149 ], "pop" : 91814, "state" : "IL" }
+{ "_id" : "60630", "city" : "CHICAGO", "loc" : [ -87.760273, 41.969862 ], "pop" : 48371, "state" : "IL" }
+{ "_id" : "60631", "city" : "CHICAGO", "loc" : [ -87.808215, 41.995145 ], "pop" : 25175, "state" : "IL" }
+{ "_id" : "60632", "city" : "CHICAGO", "loc" : [ -87.70518, 41.809274 ], "pop" : 62368, "state" : "IL" }
+{ "_id" : "60633", "city" : "BURNHAM", "loc" : [ -87.54948899999999, 41.649791 ], "pop" : 12367, "state" : "IL" }
+{ "_id" : "60634", "city" : "NORRIDGE", "loc" : [ -87.796054, 41.945213 ], "pop" : 69160, "state" : "IL" }
+{ "_id" : "60635", "city" : "ELMWOOD PARK", "loc" : [ -87.808593, 41.922907 ], "pop" : 38056, "state" : "IL" }
+{ "_id" : "60636", "city" : "CHICAGO", "loc" : [ -87.667368, 41.775989 ], "pop" : 58048, "state" : "IL" }
+{ "_id" : "60637", "city" : "CHICAGO", "loc" : [ -87.605097, 41.781312 ], "pop" : 59637, "state" : "IL" }
+{ "_id" : "60638", "city" : "BEDFORD PARK", "loc" : [ -87.77192700000001, 41.789703 ], "pop" : 53145, "state" : "IL" }
+{ "_id" : "60639", "city" : "CHICAGO", "loc" : [ -87.753502, 41.920162 ], "pop" : 74209, "state" : "IL" }
+{ "_id" : "60640", "city" : "CHICAGO", "loc" : [ -87.66240500000001, 41.971928 ], "pop" : 76829, "state" : "IL" }
+{ "_id" : "60641", "city" : "CHICAGO", "loc" : [ -87.747376, 41.945333 ], "pop" : 59870, "state" : "IL" }
+{ "_id" : "60642", "city" : "EVERGREEN PARK", "loc" : [ -87.70172100000001, 41.718765 ], "pop" : 24016, "state" : "IL" }
+{ "_id" : "60643", "city" : "CALUMET PARK", "loc" : [ -87.65944500000001, 41.693243 ], "pop" : 63953, "state" : "IL" }
+{ "_id" : "60644", "city" : "CHICAGO", "loc" : [ -87.758163, 41.882913 ], "pop" : 57376, "state" : "IL" }
+{ "_id" : "60645", "city" : "LINCOLNWOOD", "loc" : [ -87.6962, 42.007718 ], "pop" : 43829, "state" : "IL" }
+{ "_id" : "60646", "city" : "LINCOLNWOOD", "loc" : [ -87.75917200000001, 41.996414 ], "pop" : 32075, "state" : "IL" }
+{ "_id" : "60647", "city" : "CHICAGO", "loc" : [ -87.704322, 41.920903 ], "pop" : 95971, "state" : "IL" }
+{ "_id" : "60648", "city" : "CHICAGO", "loc" : [ -87.81636, 42.031101 ], "pop" : 30924, "state" : "IL" }
+{ "_id" : "60649", "city" : "CHICAGO", "loc" : [ -87.570252, 41.761968 ], "pop" : 54795, "state" : "IL" }
+{ "_id" : "60650", "city" : "CICERO", "loc" : [ -87.76008, 41.84776 ], "pop" : 67670, "state" : "IL" }
+{ "_id" : "60651", "city" : "CHICAGO", "loc" : [ -87.739307, 41.902509 ], "pop" : 78082, "state" : "IL" }
+{ "_id" : "60652", "city" : "CHICAGO", "loc" : [ -87.713516, 41.745393 ], "pop" : 36337, "state" : "IL" }
+{ "_id" : "60653", "city" : "CHICAGO", "loc" : [ -87.612605, 41.819645 ], "pop" : 40091, "state" : "IL" }
+{ "_id" : "60654", "city" : "CHICAGO", "loc" : [ -87.63529200000001, 41.888533 ], "pop" : 0, "state" : "IL" }
+{ "_id" : "60655", "city" : "MERRIONETTE PARK", "loc" : [ -87.70218800000001, 41.693033 ], "pop" : 29847, "state" : "IL" }
+{ "_id" : "60656", "city" : "HARWOOD HEIGHTS", "loc" : [ -87.819981, 41.971844 ], "pop" : 43597, "state" : "IL" }
+{ "_id" : "60657", "city" : "CHICAGO", "loc" : [ -87.652805, 41.93992 ], "pop" : 65533, "state" : "IL" }
+{ "_id" : "60658", "city" : "ALSIP", "loc" : [ -87.729967, 41.671505 ], "pop" : 16461, "state" : "IL" }
+{ "_id" : "60659", "city" : "LINCOLNWOOD", "loc" : [ -87.700823, 41.991687 ], "pop" : 35461, "state" : "IL" }
+{ "_id" : "60660", "city" : "CHICAGO", "loc" : [ -87.662856, 41.990879 ], "pop" : 45106, "state" : "IL" }
+{ "_id" : "60661", "city" : "CHICAGO", "loc" : [ -87.64296899999999, 41.881351 ], "pop" : 2031, "state" : "IL" }
+{ "_id" : "60666", "city" : "AMF OHARE", "loc" : [ -87.906803, 41.9821 ], "pop" : 262, "state" : "IL" }
+{ "_id" : "60901", "city" : "KANKAKEE", "loc" : [ -87.869607, 41.116582 ], "pop" : 35952, "state" : "IL" }
+{ "_id" : "60910", "city" : "AROMA PARK", "loc" : [ -87.77188700000001, 41.094653 ], "pop" : 3151, "state" : "IL" }
+{ "_id" : "60911", "city" : "ASHKUM", "loc" : [ -87.941148, 40.884431 ], "pop" : 1484, "state" : "IL" }
+{ "_id" : "60912", "city" : "BEAVERVILLE", "loc" : [ -87.62171499999999, 40.967164 ], "pop" : 672, "state" : "IL" }
+{ "_id" : "60913", "city" : "BONFIELD", "loc" : [ -88.061854, 41.15731 ], "pop" : 1189, "state" : "IL" }
+{ "_id" : "60914", "city" : "BOURBONNAIS", "loc" : [ -87.879023, 41.166119 ], "pop" : 18311, "state" : "IL" }
+{ "_id" : "60915", "city" : "BRADLEY", "loc" : [ -87.86011499999999, 41.145376 ], "pop" : 10071, "state" : "IL" }
+{ "_id" : "60917", "city" : "BUCKINGHAM", "loc" : [ -88.177156, 41.043316 ], "pop" : 557, "state" : "IL" }
+{ "_id" : "60918", "city" : "BUCKLEY", "loc" : [ -88.036092, 40.601827 ], "pop" : 875, "state" : "IL" }
+{ "_id" : "60919", "city" : "CABERY", "loc" : [ -88.19208500000001, 40.981895 ], "pop" : 510, "state" : "IL" }
+{ "_id" : "60921", "city" : "CHATSWORTH", "loc" : [ -88.293662, 40.748441 ], "pop" : 1703, "state" : "IL" }
+{ "_id" : "60922", "city" : "CHEBANSE", "loc" : [ -87.895917, 41.02541 ], "pop" : 3580, "state" : "IL" }
+{ "_id" : "60924", "city" : "CISSNA PARK", "loc" : [ -87.87588, 40.585814 ], "pop" : 2282, "state" : "IL" }
+{ "_id" : "60927", "city" : "CLIFTON", "loc" : [ -87.920237, 40.939444 ], "pop" : 2033, "state" : "IL" }
+{ "_id" : "60928", "city" : "CRESCENT CITY", "loc" : [ -87.83703, 40.7682 ], "pop" : 1271, "state" : "IL" }
+{ "_id" : "60929", "city" : "CULLOM", "loc" : [ -88.276476, 40.878066 ], "pop" : 782, "state" : "IL" }
+{ "_id" : "60930", "city" : "DANFORTH", "loc" : [ -87.986824, 40.82443 ], "pop" : 959, "state" : "IL" }
+{ "_id" : "60931", "city" : "DONOVAN", "loc" : [ -87.604635, 40.889074 ], "pop" : 613, "state" : "IL" }
+{ "_id" : "60934", "city" : "EMINGTON", "loc" : [ -88.321135, 40.978317 ], "pop" : 330, "state" : "IL" }
+{ "_id" : "60935", "city" : "ESSEX", "loc" : [ -88.184528, 41.167644 ], "pop" : 994, "state" : "IL" }
+{ "_id" : "60936", "city" : "GIBSON CITY", "loc" : [ -88.360873, 40.465932 ], "pop" : 4608, "state" : "IL" }
+{ "_id" : "60938", "city" : "GILMAN", "loc" : [ -87.993336, 40.767987 ], "pop" : 2125, "state" : "IL" }
+{ "_id" : "60940", "city" : "GRANT PARK", "loc" : [ -87.647992, 41.247677 ], "pop" : 3009, "state" : "IL" }
+{ "_id" : "60941", "city" : "HERSCHER", "loc" : [ -88.085801, 41.046441 ], "pop" : 2138, "state" : "IL" }
+{ "_id" : "60942", "city" : "HOOPESTON", "loc" : [ -87.666229, 40.463873 ], "pop" : 6600, "state" : "IL" }
+{ "_id" : "60946", "city" : "KEMPTON", "loc" : [ -88.209013, 40.912604 ], "pop" : 462, "state" : "IL" }
+{ "_id" : "60948", "city" : "LODA", "loc" : [ -88.092675, 40.524097 ], "pop" : 1474, "state" : "IL" }
+{ "_id" : "60949", "city" : "LUDLOW", "loc" : [ -88.13796499999999, 40.374736 ], "pop" : 832, "state" : "IL" }
+{ "_id" : "60950", "city" : "MANTENO", "loc" : [ -87.846761, 41.251439 ], "pop" : 5673, "state" : "IL" }
+{ "_id" : "60951", "city" : "MARTINTON", "loc" : [ -87.744257, 40.905233 ], "pop" : 1004, "state" : "IL" }
+{ "_id" : "60952", "city" : "MELVIN", "loc" : [ -88.255078, 40.571379 ], "pop" : 654, "state" : "IL" }
+{ "_id" : "60953", "city" : "MILFORD", "loc" : [ -87.685332, 40.629253 ], "pop" : 2367, "state" : "IL" }
+{ "_id" : "60954", "city" : "MOMENCE", "loc" : [ -87.657515, 41.159308 ], "pop" : 6804, "state" : "IL" }
+{ "_id" : "60955", "city" : "ONARGA", "loc" : [ -87.995841, 40.712005 ], "pop" : 1678, "state" : "IL" }
+{ "_id" : "60957", "city" : "PAXTON", "loc" : [ -88.098989, 40.456546 ], "pop" : 5226, "state" : "IL" }
+{ "_id" : "60959", "city" : "PIPER CITY", "loc" : [ -88.187347, 40.755615 ], "pop" : 1187, "state" : "IL" }
+{ "_id" : "60960", "city" : "RANKIN", "loc" : [ -87.888355, 40.455911 ], "pop" : 1697, "state" : "IL" }
+{ "_id" : "60961", "city" : "REDDICK", "loc" : [ -88.208928, 41.10053 ], "pop" : 480, "state" : "IL" }
+{ "_id" : "60962", "city" : "ROBERTS", "loc" : [ -88.180414, 40.619333 ], "pop" : 617, "state" : "IL" }
+{ "_id" : "60963", "city" : "ROSSVILLE", "loc" : [ -87.66918099999999, 40.362548 ], "pop" : 2082, "state" : "IL" }
+{ "_id" : "60964", "city" : "SAINT ANNE", "loc" : [ -87.656363, 41.048725 ], "pop" : 6081, "state" : "IL" }
+{ "_id" : "60966", "city" : "SHELDON", "loc" : [ -87.57364, 40.780288 ], "pop" : 1966, "state" : "IL" }
+{ "_id" : "60968", "city" : "THAWVILLE", "loc" : [ -88.09993, 40.684011 ], "pop" : 374, "state" : "IL" }
+{ "_id" : "60970", "city" : "WATSEKA", "loc" : [ -87.730932, 40.773351 ], "pop" : 7072, "state" : "IL" }
+{ "_id" : "60973", "city" : "WELLINGTON", "loc" : [ -87.65607, 40.53394 ], "pop" : 782, "state" : "IL" }
+{ "_id" : "61001", "city" : "APPLE RIVER", "loc" : [ -90.12014499999999, 42.471432 ], "pop" : 1010, "state" : "IL" }
+{ "_id" : "61006", "city" : "ASHTON", "loc" : [ -89.2086, 41.864327 ], "pop" : 1911, "state" : "IL" }
+{ "_id" : "61007", "city" : "BAILEYVILLE", "loc" : [ -89.593937, 42.190465 ], "pop" : 430, "state" : "IL" }
+{ "_id" : "61008", "city" : "BELVIDERE", "loc" : [ -88.850943, 42.259465 ], "pop" : 22199, "state" : "IL" }
+{ "_id" : "61010", "city" : "BYRON", "loc" : [ -89.26588700000001, 42.129236 ], "pop" : 4894, "state" : "IL" }
+{ "_id" : "61011", "city" : "CALEDONIA", "loc" : [ -88.91845600000001, 42.38346 ], "pop" : 2086, "state" : "IL" }
+{ "_id" : "61012", "city" : "CAPRON", "loc" : [ -88.74651799999999, 42.408659 ], "pop" : 1893, "state" : "IL" }
+{ "_id" : "61014", "city" : "CHADWICK", "loc" : [ -89.896278, 41.996205 ], "pop" : 1252, "state" : "IL" }
+{ "_id" : "61015", "city" : "CHANA", "loc" : [ -89.211693, 41.993343 ], "pop" : 1167, "state" : "IL" }
+{ "_id" : "61016", "city" : "CHERRY VALLEY", "loc" : [ -88.961923, 42.220562 ], "pop" : 3768, "state" : "IL" }
+{ "_id" : "61018", "city" : "DAKOTA", "loc" : [ -89.54678199999999, 42.403078 ], "pop" : 1134, "state" : "IL" }
+{ "_id" : "61019", "city" : "DAVIS", "loc" : [ -89.406721, 42.442157 ], "pop" : 2337, "state" : "IL" }
+{ "_id" : "61020", "city" : "DAVIS JUNCTION", "loc" : [ -89.083838, 42.09792 ], "pop" : 1263, "state" : "IL" }
+{ "_id" : "61021", "city" : "DIXON", "loc" : [ -89.48930300000001, 41.847797 ], "pop" : 22293, "state" : "IL" }
+{ "_id" : "61024", "city" : "DURAND", "loc" : [ -89.309378, 42.433653 ], "pop" : 2633, "state" : "IL" }
+{ "_id" : "61025", "city" : "EAST DUBUQUE", "loc" : [ -90.604597, 42.487488 ], "pop" : 4999, "state" : "IL" }
+{ "_id" : "61028", "city" : "ELIZABETH", "loc" : [ -90.19862000000001, 42.308942 ], "pop" : 1951, "state" : "IL" }
+{ "_id" : "61030", "city" : "FORRESTON", "loc" : [ -89.583124, 42.122924 ], "pop" : 2261, "state" : "IL" }
+{ "_id" : "61031", "city" : "FRANKLIN GROVE", "loc" : [ -89.31711199999999, 41.857968 ], "pop" : 2070, "state" : "IL" }
+{ "_id" : "61032", "city" : "FREEPORT", "loc" : [ -89.63452100000001, 42.299148 ], "pop" : 33259, "state" : "IL" }
+{ "_id" : "61036", "city" : "GALENA", "loc" : [ -90.41950900000001, 42.418233 ], "pop" : 5479, "state" : "IL" }
+{ "_id" : "61038", "city" : "GARDEN PRAIRIE", "loc" : [ -88.74366999999999, 42.250983 ], "pop" : 1584, "state" : "IL" }
+{ "_id" : "61039", "city" : "GERMAN VALLEY", "loc" : [ -89.47115100000001, 42.21761 ], "pop" : 1003, "state" : "IL" }
+{ "_id" : "61041", "city" : "HANOVER", "loc" : [ -90.28970700000001, 42.259405 ], "pop" : 1559, "state" : "IL" }
+{ "_id" : "61042", "city" : "HARMON", "loc" : [ -89.569513, 41.697296 ], "pop" : 793, "state" : "IL" }
+{ "_id" : "61044", "city" : "KENT", "loc" : [ -89.919489, 42.315528 ], "pop" : 425, "state" : "IL" }
+{ "_id" : "61045", "city" : "KINGS", "loc" : [ -89.09968499999999, 42.013987 ], "pop" : 377, "state" : "IL" }
+{ "_id" : "61046", "city" : "LANARK", "loc" : [ -89.824732, 42.093534 ], "pop" : 1843, "state" : "IL" }
+{ "_id" : "61047", "city" : "EGAN", "loc" : [ -89.40102400000001, 42.140975 ], "pop" : 1804, "state" : "IL" }
+{ "_id" : "61048", "city" : "LENA", "loc" : [ -89.82525099999999, 42.379054 ], "pop" : 4251, "state" : "IL" }
+{ "_id" : "61049", "city" : "LINDENWOOD", "loc" : [ -89.033979, 42.050741 ], "pop" : 351, "state" : "IL" }
+{ "_id" : "61050", "city" : "MC CONNELL", "loc" : [ -89.741545, 42.439511 ], "pop" : 357, "state" : "IL" }
+{ "_id" : "61051", "city" : "MILLEDGEVILLE", "loc" : [ -89.78012099999999, 41.96737 ], "pop" : 1526, "state" : "IL" }
+{ "_id" : "61052", "city" : "MONROE CENTER", "loc" : [ -89.016946, 42.10501 ], "pop" : 1327, "state" : "IL" }
+{ "_id" : "61053", "city" : "MOUNT CARROLL", "loc" : [ -89.984454, 42.105308 ], "pop" : 3529, "state" : "IL" }
+{ "_id" : "61054", "city" : "MOUNT MORRIS", "loc" : [ -89.434614, 42.047903 ], "pop" : 4169, "state" : "IL" }
+{ "_id" : "61060", "city" : "ORANGEVILLE", "loc" : [ -89.644757, 42.472779 ], "pop" : 1318, "state" : "IL" }
+{ "_id" : "61061", "city" : "OREGON", "loc" : [ -89.344364, 42.009512 ], "pop" : 6482, "state" : "IL" }
+{ "_id" : "61062", "city" : "PEARL CITY", "loc" : [ -89.83932900000001, 42.260972 ], "pop" : 1987, "state" : "IL" }
+{ "_id" : "61063", "city" : "PECATONICA", "loc" : [ -89.34722499999999, 42.305111 ], "pop" : 3554, "state" : "IL" }
+{ "_id" : "61064", "city" : "POLO", "loc" : [ -89.598358, 41.98895 ], "pop" : 4524, "state" : "IL" }
+{ "_id" : "61065", "city" : "POPLAR GROVE", "loc" : [ -88.84277400000001, 42.359365 ], "pop" : 2593, "state" : "IL" }
+{ "_id" : "61067", "city" : "RIDOTT", "loc" : [ -89.462664, 42.299607 ], "pop" : 750, "state" : "IL" }
+{ "_id" : "61068", "city" : "ROCHELLE", "loc" : [ -89.07103499999999, 41.928156 ], "pop" : 12890, "state" : "IL" }
+{ "_id" : "61070", "city" : "ROCK CITY", "loc" : [ -89.47590099999999, 42.410345 ], "pop" : 1420, "state" : "IL" }
+{ "_id" : "61071", "city" : "ROCK FALLS", "loc" : [ -89.69247300000001, 41.766525 ], "pop" : 14548, "state" : "IL" }
+{ "_id" : "61072", "city" : "ROCKTON", "loc" : [ -89.08874400000001, 42.454371 ], "pop" : 6514, "state" : "IL" }
+{ "_id" : "61073", "city" : "ROSCOE", "loc" : [ -88.99433000000001, 42.421659 ], "pop" : 10391, "state" : "IL" }
+{ "_id" : "61074", "city" : "SAVANNA", "loc" : [ -90.140061, 42.095581 ], "pop" : 4943, "state" : "IL" }
+{ "_id" : "61075", "city" : "SCALES MOUND", "loc" : [ -90.258033, 42.471548 ], "pop" : 909, "state" : "IL" }
+{ "_id" : "61078", "city" : "SHANNON", "loc" : [ -89.748075, 42.161049 ], "pop" : 1753, "state" : "IL" }
+{ "_id" : "61080", "city" : "SOUTH BELOIT", "loc" : [ -89.029791, 42.483672 ], "pop" : 6833, "state" : "IL" }
+{ "_id" : "61081", "city" : "STERLING", "loc" : [ -89.70538999999999, 41.805511 ], "pop" : 22261, "state" : "IL" }
+{ "_id" : "61084", "city" : "STILLMAN VALLEY", "loc" : [ -89.189762, 42.11835 ], "pop" : 2772, "state" : "IL" }
+{ "_id" : "61085", "city" : "STOCKTON", "loc" : [ -90.020185, 42.349224 ], "pop" : 3489, "state" : "IL" }
+{ "_id" : "61087", "city" : "WARREN", "loc" : [ -89.985992, 42.489001 ], "pop" : 1967, "state" : "IL" }
+{ "_id" : "61088", "city" : "WINNEBAGO", "loc" : [ -89.23731600000001, 42.272723 ], "pop" : 4059, "state" : "IL" }
+{ "_id" : "61089", "city" : "WINSLOW", "loc" : [ -89.806028, 42.48383 ], "pop" : 887, "state" : "IL" }
+{ "_id" : "61101", "city" : "ROCKFORD", "loc" : [ -89.116118, 42.292233 ], "pop" : 23908, "state" : "IL" }
+{ "_id" : "61102", "city" : "ROCKFORD", "loc" : [ -89.124695, 42.254669 ], "pop" : 19427, "state" : "IL" }
+{ "_id" : "61103", "city" : "ROCKFORD", "loc" : [ -89.083326, 42.300986 ], "pop" : 24143, "state" : "IL" }
+{ "_id" : "61104", "city" : "ROCKFORD", "loc" : [ -89.076779, 42.255355 ], "pop" : 19912, "state" : "IL" }
+{ "_id" : "61107", "city" : "ROCKFORD", "loc" : [ -89.036107, 42.278629 ], "pop" : 28879, "state" : "IL" }
+{ "_id" : "61108", "city" : "ROCKFORD", "loc" : [ -89.02351899999999, 42.251406 ], "pop" : 25501, "state" : "IL" }
+{ "_id" : "61109", "city" : "ROCKFORD", "loc" : [ -89.05118, 42.216581 ], "pop" : 25246, "state" : "IL" }
+{ "_id" : "61111", "city" : "LOVES PARK", "loc" : [ -89.03352099999999, 42.32952 ], "pop" : 47733, "state" : "IL" }
+{ "_id" : "61112", "city" : "ROCKFORD", "loc" : [ -88.970429, 42.245639 ], "pop" : 15, "state" : "IL" }
+{ "_id" : "61201", "city" : "ROCK ISLAND", "loc" : [ -90.564796, 41.491317 ], "pop" : 37799, "state" : "IL" }
+{ "_id" : "61230", "city" : "ALBANY", "loc" : [ -90.208051, 41.765874 ], "pop" : 1287, "state" : "IL" }
+{ "_id" : "61231", "city" : "ALEDO", "loc" : [ -90.741629, 41.20078 ], "pop" : 5189, "state" : "IL" }
+{ "_id" : "61232", "city" : "ANDALUSIA", "loc" : [ -90.728385, 41.435324 ], "pop" : 1899, "state" : "IL" }
+{ "_id" : "61234", "city" : "ANNAWAN", "loc" : [ -89.912949, 41.398022 ], "pop" : 1432, "state" : "IL" }
+{ "_id" : "61235", "city" : "ATKINSON", "loc" : [ -90.022482, 41.41619 ], "pop" : 1619, "state" : "IL" }
+{ "_id" : "61238", "city" : "CAMBRIDGE", "loc" : [ -90.18048, 41.311379 ], "pop" : 3265, "state" : "IL" }
+{ "_id" : "61240", "city" : "COAL VALLEY", "loc" : [ -90.46517900000001, 41.435143 ], "pop" : 5435, "state" : "IL" }
+{ "_id" : "61241", "city" : "GREEN ROCK", "loc" : [ -90.349231, 41.475224 ], "pop" : 7809, "state" : "IL" }
+{ "_id" : "61242", "city" : "CORDOVA", "loc" : [ -90.307121, 41.69278 ], "pop" : 954, "state" : "IL" }
+{ "_id" : "61243", "city" : "DEER GROVE", "loc" : [ -89.6972, 41.631599 ], "pop" : 393, "state" : "IL" }
+{ "_id" : "61244", "city" : "EAST MOLINE", "loc" : [ -90.432118, 41.511804 ], "pop" : 24023, "state" : "IL" }
+{ "_id" : "61250", "city" : "ERIE", "loc" : [ -90.084264, 41.655958 ], "pop" : 2428, "state" : "IL" }
+{ "_id" : "61251", "city" : "FENTON", "loc" : [ -90.04568500000001, 41.728495 ], "pop" : 289, "state" : "IL" }
+{ "_id" : "61252", "city" : "FULTON", "loc" : [ -90.15065300000001, 41.8522 ], "pop" : 5743, "state" : "IL" }
+{ "_id" : "61254", "city" : "GENESEO", "loc" : [ -90.171127, 41.46881 ], "pop" : 10023, "state" : "IL" }
+{ "_id" : "61256", "city" : "HAMPTON", "loc" : [ -90.323037, 41.541805 ], "pop" : 538, "state" : "IL" }
+{ "_id" : "61257", "city" : "HILLSDALE", "loc" : [ -90.22625499999999, 41.592896 ], "pop" : 1807, "state" : "IL" }
+{ "_id" : "61259", "city" : "ILLINOIS CITY", "loc" : [ -90.89250699999999, 41.389236 ], "pop" : 1553, "state" : "IL" }
+{ "_id" : "61260", "city" : "JOY", "loc" : [ -90.85175700000001, 41.226198 ], "pop" : 1185, "state" : "IL" }
+{ "_id" : "61261", "city" : "LYNDON", "loc" : [ -89.916865, 41.719933 ], "pop" : 936, "state" : "IL" }
+{ "_id" : "61262", "city" : "LYNN CENTER", "loc" : [ -90.330444, 41.288761 ], "pop" : 1694, "state" : "IL" }
+{ "_id" : "61263", "city" : "MATHERVILLE", "loc" : [ -90.602343, 41.269075 ], "pop" : 1409, "state" : "IL" }
+{ "_id" : "61264", "city" : "MILAN", "loc" : [ -90.57393500000001, 41.426197 ], "pop" : 14565, "state" : "IL" }
+{ "_id" : "61265", "city" : "MOLINE", "loc" : [ -90.497968, 41.490609 ], "pop" : 45240, "state" : "IL" }
+{ "_id" : "61270", "city" : "MORRISON", "loc" : [ -89.96899500000001, 41.816664 ], "pop" : 7580, "state" : "IL" }
+{ "_id" : "61272", "city" : "NEW BOSTON", "loc" : [ -90.98786, 41.215259 ], "pop" : 1663, "state" : "IL" }
+{ "_id" : "61273", "city" : "ORION", "loc" : [ -90.384929, 41.363367 ], "pop" : 3121, "state" : "IL" }
+{ "_id" : "61274", "city" : "OSCO", "loc" : [ -90.26809299999999, 41.363674 ], "pop" : 538, "state" : "IL" }
+{ "_id" : "61275", "city" : "PORT BYRON", "loc" : [ -90.326291, 41.601346 ], "pop" : 3441, "state" : "IL" }
+{ "_id" : "61277", "city" : "PROPHETSTOWN", "loc" : [ -89.946665, 41.631223 ], "pop" : 3736, "state" : "IL" }
+{ "_id" : "61279", "city" : "REYNOLDS", "loc" : [ -90.638367, 41.327675 ], "pop" : 944, "state" : "IL" }
+{ "_id" : "61281", "city" : "SHERRARD", "loc" : [ -90.493863, 41.302669 ], "pop" : 2192, "state" : "IL" }
+{ "_id" : "61282", "city" : "SILVIS", "loc" : [ -90.412609, 41.500677 ], "pop" : 9832, "state" : "IL" }
+{ "_id" : "61283", "city" : "TAMPICO", "loc" : [ -89.794793, 41.652158 ], "pop" : 1753, "state" : "IL" }
+{ "_id" : "61284", "city" : "TAYLOR RIDGE", "loc" : [ -90.734047, 41.382755 ], "pop" : 1090, "state" : "IL" }
+{ "_id" : "61285", "city" : "THOMSON", "loc" : [ -90.08444299999999, 41.981626 ], "pop" : 1868, "state" : "IL" }
+{ "_id" : "61301", "city" : "LA SALLE", "loc" : [ -89.095468, 41.344221 ], "pop" : 10188, "state" : "IL" }
+{ "_id" : "61310", "city" : "AMBOY", "loc" : [ -89.34716, 41.704181 ], "pop" : 3994, "state" : "IL" }
+{ "_id" : "61311", "city" : "ANCONA", "loc" : [ -88.76603900000001, 41.055118 ], "pop" : 38, "state" : "IL" }
+{ "_id" : "61312", "city" : "ARLINGTON", "loc" : [ -89.221949, 41.443669 ], "pop" : 1044, "state" : "IL" }
+{ "_id" : "61313", "city" : "BLACKSTONE", "loc" : [ -88.649782, 41.071945 ], "pop" : 258, "state" : "IL" }
+{ "_id" : "61314", "city" : "BUDA", "loc" : [ -89.67947599999999, 41.313973 ], "pop" : 931, "state" : "IL" }
+{ "_id" : "61318", "city" : "COMPTON", "loc" : [ -89.08770800000001, 41.684976 ], "pop" : 551, "state" : "IL" }
+{ "_id" : "61319", "city" : "MANVILLE", "loc" : [ -88.742694, 40.985827 ], "pop" : 968, "state" : "IL" }
+{ "_id" : "61320", "city" : "DALZELL", "loc" : [ -89.20326900000001, 41.373077 ], "pop" : 2255, "state" : "IL" }
+{ "_id" : "61321", "city" : "DANA", "loc" : [ -88.962793, 40.954675 ], "pop" : 257, "state" : "IL" }
+{ "_id" : "61325", "city" : "GRAND RIDGE", "loc" : [ -88.816836, 41.238621 ], "pop" : 1179, "state" : "IL" }
+{ "_id" : "61326", "city" : "GRANVILLE", "loc" : [ -89.22502900000001, 41.264212 ], "pop" : 2784, "state" : "IL" }
+{ "_id" : "61327", "city" : "HENNEPIN", "loc" : [ -89.321791, 41.235154 ], "pop" : 1111, "state" : "IL" }
+{ "_id" : "61330", "city" : "LA MOILLE", "loc" : [ -89.29702399999999, 41.537557 ], "pop" : 1315, "state" : "IL" }
+{ "_id" : "61332", "city" : "LEONORE", "loc" : [ -88.99693600000001, 41.166368 ], "pop" : 437, "state" : "IL" }
+{ "_id" : "61333", "city" : "LONG POINT", "loc" : [ -88.881106, 40.989553 ], "pop" : 541, "state" : "IL" }
+{ "_id" : "61334", "city" : "LOSTANT", "loc" : [ -89.075031, 41.145007 ], "pop" : 747, "state" : "IL" }
+{ "_id" : "61335", "city" : "MC NABB", "loc" : [ -89.218664, 41.173026 ], "pop" : 747, "state" : "IL" }
+{ "_id" : "61336", "city" : "MAGNOLIA", "loc" : [ -89.22701000000001, 41.116374 ], "pop" : 519, "state" : "IL" }
+{ "_id" : "61337", "city" : "MALDEN", "loc" : [ -89.36761, 41.437743 ], "pop" : 1109, "state" : "IL" }
+{ "_id" : "61341", "city" : "MARSEILLES", "loc" : [ -88.694678, 41.330201 ], "pop" : 7360, "state" : "IL" }
+{ "_id" : "61342", "city" : "MENDOTA", "loc" : [ -89.10827999999999, 41.544308 ], "pop" : 9660, "state" : "IL" }
+{ "_id" : "61344", "city" : "MINERAL", "loc" : [ -89.820087, 41.403556 ], "pop" : 648, "state" : "IL" }
+{ "_id" : "61345", "city" : "NEPONSET", "loc" : [ -89.794382, 41.290457 ], "pop" : 819, "state" : "IL" }
+{ "_id" : "61346", "city" : "NEW BEDFORD", "loc" : [ -89.778558, 41.540883 ], "pop" : 641, "state" : "IL" }
+{ "_id" : "61348", "city" : "OGLESBY", "loc" : [ -89.055341, 41.292768 ], "pop" : 5323, "state" : "IL" }
+{ "_id" : "61349", "city" : "OHIO", "loc" : [ -89.45741099999999, 41.537149 ], "pop" : 1031, "state" : "IL" }
+{ "_id" : "61350", "city" : "OTTAWA", "loc" : [ -88.841589, 41.352619 ], "pop" : 23727, "state" : "IL" }
+{ "_id" : "61353", "city" : "PAW PAW", "loc" : [ -88.967377, 41.685228 ], "pop" : 1539, "state" : "IL" }
+{ "_id" : "61354", "city" : "PERU", "loc" : [ -89.12647800000001, 41.333021 ], "pop" : 10050, "state" : "IL" }
+{ "_id" : "61356", "city" : "PRINCETON", "loc" : [ -89.42701700000001, 41.362934 ], "pop" : 12333, "state" : "IL" }
+{ "_id" : "61358", "city" : "RUTLAND", "loc" : [ -89.03882900000001, 40.984407 ], "pop" : 629, "state" : "IL" }
+{ "_id" : "61360", "city" : "SENECA", "loc" : [ -88.610013, 41.315248 ], "pop" : 2246, "state" : "IL" }
+{ "_id" : "61361", "city" : "SHEFFIELD", "loc" : [ -89.711502, 41.394876 ], "pop" : 1964, "state" : "IL" }
+{ "_id" : "61362", "city" : "SPRING VALLEY", "loc" : [ -89.20417, 41.327923 ], "pop" : 5541, "state" : "IL" }
+{ "_id" : "61364", "city" : "STREATOR", "loc" : [ -88.83067200000001, 41.12249 ], "pop" : 22239, "state" : "IL" }
+{ "_id" : "61367", "city" : "SUBLETTE", "loc" : [ -89.235409, 41.633144 ], "pop" : 899, "state" : "IL" }
+{ "_id" : "61368", "city" : "TISKILWA", "loc" : [ -89.50796800000001, 41.289055 ], "pop" : 1587, "state" : "IL" }
+{ "_id" : "61369", "city" : "TOLUCA", "loc" : [ -89.13481, 41.004553 ], "pop" : 1755, "state" : "IL" }
+{ "_id" : "61370", "city" : "TONICA", "loc" : [ -89.088993, 41.232741 ], "pop" : 1409, "state" : "IL" }
+{ "_id" : "61373", "city" : "UTICA", "loc" : [ -89.000795, 41.363033 ], "pop" : 1926, "state" : "IL" }
+{ "_id" : "61375", "city" : "VARNA", "loc" : [ -89.24833099999999, 41.032723 ], "pop" : 1527, "state" : "IL" }
+{ "_id" : "61376", "city" : "NORMANDY", "loc" : [ -89.592237, 41.553035 ], "pop" : 2050, "state" : "IL" }
+{ "_id" : "61377", "city" : "WENONA", "loc" : [ -89.04163699999999, 41.054846 ], "pop" : 1410, "state" : "IL" }
+{ "_id" : "61378", "city" : "WEST BROOKLYN", "loc" : [ -89.190917, 41.729156 ], "pop" : 946, "state" : "IL" }
+{ "_id" : "61379", "city" : "WYANET", "loc" : [ -89.574423, 41.378452 ], "pop" : 1799, "state" : "IL" }
+{ "_id" : "61401", "city" : "GALESBURG", "loc" : [ -90.36980699999999, 40.952138 ], "pop" : 36161, "state" : "IL" }
+{ "_id" : "61410", "city" : "ABINGDON", "loc" : [ -90.400898, 40.802312 ], "pop" : 4241, "state" : "IL" }
+{ "_id" : "61411", "city" : "ADAIR", "loc" : [ -90.503742, 40.385197 ], "pop" : 731, "state" : "IL" }
+{ "_id" : "61412", "city" : "ALEXIS", "loc" : [ -90.543576, 41.052146 ], "pop" : 1866, "state" : "IL" }
+{ "_id" : "61413", "city" : "ALPHA", "loc" : [ -90.382081, 41.193029 ], "pop" : 1152, "state" : "IL" }
+{ "_id" : "61414", "city" : "ALTONA", "loc" : [ -90.159826, 41.112828 ], "pop" : 813, "state" : "IL" }
+{ "_id" : "61415", "city" : "AVON", "loc" : [ -90.44605300000001, 40.654947 ], "pop" : 2125, "state" : "IL" }
+{ "_id" : "61416", "city" : "BARDOLPH", "loc" : [ -90.502495, 40.498078 ], "pop" : 365, "state" : "IL" }
+{ "_id" : "61417", "city" : "BERWICK", "loc" : [ -90.50591300000001, 40.779911 ], "pop" : 461, "state" : "IL" }
+{ "_id" : "61418", "city" : "BIGGSVILLE", "loc" : [ -90.85605700000001, 40.853122 ], "pop" : 627, "state" : "IL" }
+{ "_id" : "61420", "city" : "BLANDINSVILLE", "loc" : [ -90.859521, 40.551585 ], "pop" : 1272, "state" : "IL" }
+{ "_id" : "61421", "city" : "BRADFORD", "loc" : [ -89.65207700000001, 41.15323 ], "pop" : 2071, "state" : "IL" }
+{ "_id" : "61422", "city" : "BUSHNELL", "loc" : [ -90.506027, 40.553916 ], "pop" : 3511, "state" : "IL" }
+{ "_id" : "61423", "city" : "CAMERON", "loc" : [ -90.50013, 40.888963 ], "pop" : 969, "state" : "IL" }
+{ "_id" : "61425", "city" : "CARMAN", "loc" : [ -91.05639600000001, 40.755054 ], "pop" : 398, "state" : "IL" }
+{ "_id" : "61427", "city" : "CUBA", "loc" : [ -90.181055, 40.4995 ], "pop" : 2169, "state" : "IL" }
+{ "_id" : "61428", "city" : "DAHINDA", "loc" : [ -90.139808, 40.95508 ], "pop" : 710, "state" : "IL" }
+{ "_id" : "61431", "city" : "ELLISVILLE", "loc" : [ -90.287469, 40.604652 ], "pop" : 565, "state" : "IL" }
+{ "_id" : "61432", "city" : "FAIRVIEW", "loc" : [ -90.16526500000001, 40.64418 ], "pop" : 702, "state" : "IL" }
+{ "_id" : "61433", "city" : "FIATT", "loc" : [ -90.16218600000001, 40.571779 ], "pop" : 495, "state" : "IL" }
+{ "_id" : "61434", "city" : "GALVA", "loc" : [ -90.04809299999999, 41.165627 ], "pop" : 3725, "state" : "IL" }
+{ "_id" : "61435", "city" : "GERLAW", "loc" : [ -90.622765, 40.999519 ], "pop" : 520, "state" : "IL" }
+{ "_id" : "61436", "city" : "GILSON", "loc" : [ -90.174663, 40.876525 ], "pop" : 696, "state" : "IL" }
+{ "_id" : "61437", "city" : "GLADSTONE", "loc" : [ -90.994078, 40.837682 ], "pop" : 1166, "state" : "IL" }
+{ "_id" : "61438", "city" : "GOOD HOPE", "loc" : [ -90.63243199999999, 40.574891 ], "pop" : 499, "state" : "IL" }
+{ "_id" : "61440", "city" : "INDUSTRY", "loc" : [ -90.610524, 40.3256 ], "pop" : 885, "state" : "IL" }
+{ "_id" : "61441", "city" : "IPAVA", "loc" : [ -90.296744, 40.359375 ], "pop" : 1152, "state" : "IL" }
+{ "_id" : "61442", "city" : "KEITHSBURG", "loc" : [ -90.926337, 41.104333 ], "pop" : 1024, "state" : "IL" }
+{ "_id" : "61443", "city" : "KEWANEE", "loc" : [ -89.92739, 41.241116 ], "pop" : 14861, "state" : "IL" }
+{ "_id" : "61447", "city" : "KIRKWOOD", "loc" : [ -90.745659, 40.863849 ], "pop" : 1171, "state" : "IL" }
+{ "_id" : "61448", "city" : "KNOXVILLE", "loc" : [ -90.287116, 40.910672 ], "pop" : 5958, "state" : "IL" }
+{ "_id" : "61449", "city" : "LA FAYETTE", "loc" : [ -89.957466, 41.109535 ], "pop" : 454, "state" : "IL" }
+{ "_id" : "61450", "city" : "LA HARPE", "loc" : [ -90.968746, 40.584586 ], "pop" : 1686, "state" : "IL" }
+{ "_id" : "61451", "city" : "LAURA", "loc" : [ -89.93490799999999, 40.933468 ], "pop" : 500, "state" : "IL" }
+{ "_id" : "61452", "city" : "LITTLETON", "loc" : [ -90.61900799999999, 40.233929 ], "pop" : 386, "state" : "IL" }
+{ "_id" : "61453", "city" : "LITTLE YORK", "loc" : [ -90.736434, 41.01529 ], "pop" : 679, "state" : "IL" }
+{ "_id" : "61454", "city" : "LOMAX", "loc" : [ -91.039096, 40.676143 ], "pop" : 1036, "state" : "IL" }
+{ "_id" : "61455", "city" : "MACOMB", "loc" : [ -90.678674, 40.461674 ], "pop" : 23503, "state" : "IL" }
+{ "_id" : "61458", "city" : "MAQUON", "loc" : [ -90.200841, 40.784863 ], "pop" : 1226, "state" : "IL" }
+{ "_id" : "61459", "city" : "MARIETTA", "loc" : [ -90.38845999999999, 40.497775 ], "pop" : 421, "state" : "IL" }
+{ "_id" : "61460", "city" : "MEDIA", "loc" : [ -90.85696, 40.761775 ], "pop" : 484, "state" : "IL" }
+{ "_id" : "61462", "city" : "MONMOUTH", "loc" : [ -90.644828, 40.910702 ], "pop" : 11245, "state" : "IL" }
+{ "_id" : "61465", "city" : "NEW WINDSOR", "loc" : [ -90.45984199999999, 41.198734 ], "pop" : 1171, "state" : "IL" }
+{ "_id" : "61466", "city" : "NORTH HENDERSON", "loc" : [ -90.47357100000001, 41.100607 ], "pop" : 390, "state" : "IL" }
+{ "_id" : "61467", "city" : "ONEIDA", "loc" : [ -90.239093, 41.083236 ], "pop" : 1122, "state" : "IL" }
+{ "_id" : "61469", "city" : "OQUAWKA", "loc" : [ -90.930199, 40.944174 ], "pop" : 2410, "state" : "IL" }
+{ "_id" : "61470", "city" : "PRAIRIE CITY", "loc" : [ -90.472748, 40.617952 ], "pop" : 651, "state" : "IL" }
+{ "_id" : "61471", "city" : "RARITAN", "loc" : [ -90.831891, 40.687808 ], "pop" : 345, "state" : "IL" }
+{ "_id" : "61472", "city" : "RIO", "loc" : [ -90.389978, 41.110319 ], "pop" : 570, "state" : "IL" }
+{ "_id" : "61473", "city" : "ROSEVILLE", "loc" : [ -90.65145, 40.723821 ], "pop" : 1734, "state" : "IL" }
+{ "_id" : "61474", "city" : "SAINT AUGUSTINE", "loc" : [ -90.37978099999999, 40.7289 ], "pop" : 376, "state" : "IL" }
+{ "_id" : "61475", "city" : "SCIOTA", "loc" : [ -90.707999, 40.567361 ], "pop" : 622, "state" : "IL" }
+{ "_id" : "61476", "city" : "SEATON", "loc" : [ -90.825654, 41.073222 ], "pop" : 704, "state" : "IL" }
+{ "_id" : "61477", "city" : "SMITHFIELD", "loc" : [ -90.285601, 40.48551 ], "pop" : 647, "state" : "IL" }
+{ "_id" : "61478", "city" : "SMITHSHIRE", "loc" : [ -90.739874, 40.740021 ], "pop" : 568, "state" : "IL" }
+{ "_id" : "61479", "city" : "SPEER", "loc" : [ -89.693254, 41.009682 ], "pop" : 398, "state" : "IL" }
+{ "_id" : "61480", "city" : "STRONGHURST", "loc" : [ -90.925702, 40.752265 ], "pop" : 1055, "state" : "IL" }
+{ "_id" : "61482", "city" : "TABLE GROVE", "loc" : [ -90.423901, 40.378441 ], "pop" : 429, "state" : "IL" }
+{ "_id" : "61483", "city" : "TOULON", "loc" : [ -89.860584, 41.100949 ], "pop" : 2378, "state" : "IL" }
+{ "_id" : "61484", "city" : "VERMONT", "loc" : [ -90.422028, 40.30623 ], "pop" : 1112, "state" : "IL" }
+{ "_id" : "61485", "city" : "VICTORIA", "loc" : [ -90.09332499999999, 41.025635 ], "pop" : 669, "state" : "IL" }
+{ "_id" : "61486", "city" : "VIOLA", "loc" : [ -90.593583, 41.202422 ], "pop" : 1651, "state" : "IL" }
+{ "_id" : "61488", "city" : "WATAGA", "loc" : [ -90.27231, 41.022351 ], "pop" : 1197, "state" : "IL" }
+{ "_id" : "61489", "city" : "WILLIAMSFIELD", "loc" : [ -90.026725, 40.927724 ], "pop" : 912, "state" : "IL" }
+{ "_id" : "61490", "city" : "WOODHULL", "loc" : [ -90.283282, 41.184887 ], "pop" : 1390, "state" : "IL" }
+{ "_id" : "61491", "city" : "WYOMING", "loc" : [ -89.778238, 41.059879 ], "pop" : 1818, "state" : "IL" }
+{ "_id" : "61501", "city" : "ASTORIA", "loc" : [ -90.34425400000001, 40.231144 ], "pop" : 2093, "state" : "IL" }
+{ "_id" : "61516", "city" : "BENSON", "loc" : [ -89.116501, 40.83058 ], "pop" : 838, "state" : "IL" }
+{ "_id" : "61517", "city" : "BRIMFIELD", "loc" : [ -89.89703799999999, 40.840654 ], "pop" : 1177, "state" : "IL" }
+{ "_id" : "61518", "city" : "OAK HILL", "loc" : [ -89.83725, 40.786938 ], "pop" : 1007, "state" : "IL" }
+{ "_id" : "61519", "city" : "BRYANT", "loc" : [ -90.06613400000001, 40.483072 ], "pop" : 1017, "state" : "IL" }
+{ "_id" : "61520", "city" : "CANTON", "loc" : [ -90.024151, 40.560137 ], "pop" : 16309, "state" : "IL" }
+{ "_id" : "61523", "city" : "CHILLICOTHE", "loc" : [ -89.506793, 40.901349 ], "pop" : 9929, "state" : "IL" }
+{ "_id" : "61524", "city" : "DUNFERMLINE", "loc" : [ -90.03134900000001, 40.490342 ], "pop" : 319, "state" : "IL" }
+{ "_id" : "61525", "city" : "DUNLAP", "loc" : [ -89.639655, 40.844417 ], "pop" : 4669, "state" : "IL" }
+{ "_id" : "61526", "city" : "EDELSTEIN", "loc" : [ -89.585812, 40.945367 ], "pop" : 1866, "state" : "IL" }
+{ "_id" : "61528", "city" : "EDWARDS", "loc" : [ -89.705344, 40.764362 ], "pop" : 2896, "state" : "IL" }
+{ "_id" : "61529", "city" : "ELMWOOD", "loc" : [ -89.928882, 40.772594 ], "pop" : 2698, "state" : "IL" }
+{ "_id" : "61530", "city" : "EUREKA", "loc" : [ -89.270561, 40.715249 ], "pop" : 5688, "state" : "IL" }
+{ "_id" : "61531", "city" : "MIDDLEGROVE", "loc" : [ -90.013434, 40.690265 ], "pop" : 3569, "state" : "IL" }
+{ "_id" : "61532", "city" : "FOREST CITY", "loc" : [ -89.833426, 40.35942 ], "pop" : 670, "state" : "IL" }
+{ "_id" : "61533", "city" : "GLASFORD", "loc" : [ -89.81132599999999, 40.575976 ], "pop" : 2531, "state" : "IL" }
+{ "_id" : "61534", "city" : "GREEN VALLEY", "loc" : [ -89.65492500000001, 40.41978 ], "pop" : 1800, "state" : "IL" }
+{ "_id" : "61536", "city" : "HANNA CITY", "loc" : [ -89.795242, 40.679776 ], "pop" : 3255, "state" : "IL" }
+{ "_id" : "61537", "city" : "HENRY", "loc" : [ -89.37432800000001, 41.111543 ], "pop" : 3255, "state" : "IL" }
+{ "_id" : "61539", "city" : "KINGSTON MINES", "loc" : [ -89.806791, 40.49028 ], "pop" : 1745, "state" : "IL" }
+{ "_id" : "61540", "city" : "LACON", "loc" : [ -89.400842, 41.021587 ], "pop" : 2809, "state" : "IL" }
+{ "_id" : "61542", "city" : "LEWISTOWN", "loc" : [ -90.15628700000001, 40.383046 ], "pop" : 3849, "state" : "IL" }
+{ "_id" : "61543", "city" : "LIVERPOOL", "loc" : [ -90.038972, 40.411574 ], "pop" : 730, "state" : "IL" }
+{ "_id" : "61544", "city" : "LONDON MILLS", "loc" : [ -90.261594, 40.694954 ], "pop" : 746, "state" : "IL" }
+{ "_id" : "61545", "city" : "CAZENOVIA", "loc" : [ -89.37039900000001, 40.871082 ], "pop" : 1247, "state" : "IL" }
+{ "_id" : "61546", "city" : "MANITO", "loc" : [ -89.78979099999999, 40.415991 ], "pop" : 2593, "state" : "IL" }
+{ "_id" : "61547", "city" : "MAPLETON", "loc" : [ -89.718429, 40.611699 ], "pop" : 2593, "state" : "IL" }
+{ "_id" : "61548", "city" : "METAMORA", "loc" : [ -89.430876, 40.784428 ], "pop" : 9052, "state" : "IL" }
+{ "_id" : "61550", "city" : "MORTON", "loc" : [ -89.46044500000001, 40.614771 ], "pop" : 15207, "state" : "IL" }
+{ "_id" : "61554", "city" : "PEKIN", "loc" : [ -89.624332, 40.567435 ], "pop" : 44902, "state" : "IL" }
+{ "_id" : "61559", "city" : "PRINCEVILLE", "loc" : [ -89.772285, 40.909277 ], "pop" : 3210, "state" : "IL" }
+{ "_id" : "61560", "city" : "PUTNAM", "loc" : [ -89.440901, 41.19486 ], "pop" : 724, "state" : "IL" }
+{ "_id" : "61561", "city" : "ROANOKE", "loc" : [ -89.209334, 40.795601 ], "pop" : 2653, "state" : "IL" }
+{ "_id" : "61563", "city" : "SAINT DAVID", "loc" : [ -90.043739, 40.522571 ], "pop" : 241, "state" : "IL" }
+{ "_id" : "61565", "city" : "SPARLAND", "loc" : [ -89.45711, 41.013366 ], "pop" : 1190, "state" : "IL" }
+{ "_id" : "61567", "city" : "TOPEKA", "loc" : [ -89.93263, 40.38108 ], "pop" : 969, "state" : "IL" }
+{ "_id" : "61568", "city" : "TREMONT", "loc" : [ -89.483316, 40.505337 ], "pop" : 4492, "state" : "IL" }
+{ "_id" : "61569", "city" : "TRIVOLI", "loc" : [ -89.913546, 40.679506 ], "pop" : 1166, "state" : "IL" }
+{ "_id" : "61570", "city" : "WASHBURN", "loc" : [ -89.28304900000001, 40.91413 ], "pop" : 1771, "state" : "IL" }
+{ "_id" : "61571", "city" : "SUNNYLAND", "loc" : [ -89.447926, 40.699364 ], "pop" : 18931, "state" : "IL" }
+{ "_id" : "61572", "city" : "YATES CITY", "loc" : [ -90.026481, 40.787826 ], "pop" : 1402, "state" : "IL" }
+{ "_id" : "61602", "city" : "PEORIA", "loc" : [ -89.601178, 40.687987 ], "pop" : 740, "state" : "IL" }
+{ "_id" : "61603", "city" : "PEORIA HEIGHTS", "loc" : [ -89.58081300000001, 40.713915 ], "pop" : 20163, "state" : "IL" }
+{ "_id" : "61604", "city" : "PEORIA", "loc" : [ -89.63237700000001, 40.711142 ], "pop" : 33171, "state" : "IL" }
+{ "_id" : "61605", "city" : "PEORIA", "loc" : [ -89.62632499999999, 40.677512 ], "pop" : 20320, "state" : "IL" }
+{ "_id" : "61606", "city" : "PEORIA", "loc" : [ -89.612189, 40.698926 ], "pop" : 10299, "state" : "IL" }
+{ "_id" : "61607", "city" : "BARTONVILLE", "loc" : [ -89.67389799999999, 40.652434 ], "pop" : 10389, "state" : "IL" }
+{ "_id" : "61611", "city" : "EAST PEORIA", "loc" : [ -89.55141, 40.673121 ], "pop" : 29630, "state" : "IL" }
+{ "_id" : "61614", "city" : "PEORIA HEIGHTS", "loc" : [ -89.603295, 40.75481 ], "pop" : 35177, "state" : "IL" }
+{ "_id" : "61615", "city" : "PEORIA", "loc" : [ -89.63208299999999, 40.770165 ], "pop" : 15452, "state" : "IL" }
+{ "_id" : "61701", "city" : "BLOOMINGTON", "loc" : [ -88.989318, 40.478295 ], "pop" : 35218, "state" : "IL" }
+{ "_id" : "61704", "city" : "BLOOMINGTON", "loc" : [ -88.96246600000001, 40.471618 ], "pop" : 24135, "state" : "IL" }
+{ "_id" : "61720", "city" : "ANCHOR", "loc" : [ -88.52658099999999, 40.544091 ], "pop" : 393, "state" : "IL" }
+{ "_id" : "61721", "city" : "ARMINGTON", "loc" : [ -89.321775, 40.317046 ], "pop" : 1163, "state" : "IL" }
+{ "_id" : "61722", "city" : "ARROWSMITH", "loc" : [ -88.629648, 40.411966 ], "pop" : 813, "state" : "IL" }
+{ "_id" : "61723", "city" : "ATLANTA", "loc" : [ -89.23002099999999, 40.258624 ], "pop" : 1978, "state" : "IL" }
+{ "_id" : "61724", "city" : "BELLFLOWER", "loc" : [ -88.522702, 40.340091 ], "pop" : 702, "state" : "IL" }
+{ "_id" : "61725", "city" : "CARLOCK", "loc" : [ -89.109779, 40.602898 ], "pop" : 1066, "state" : "IL" }
+{ "_id" : "61726", "city" : "CHENOA", "loc" : [ -88.721853, 40.744633 ], "pop" : 2898, "state" : "IL" }
+{ "_id" : "61727", "city" : "CLINTON", "loc" : [ -88.96266, 40.148708 ], "pop" : 10043, "state" : "IL" }
+{ "_id" : "61728", "city" : "COLFAX", "loc" : [ -88.62001600000001, 40.570377 ], "pop" : 1391, "state" : "IL" }
+{ "_id" : "61729", "city" : "CONGERVILLE", "loc" : [ -89.199397, 40.620762 ], "pop" : 802, "state" : "IL" }
+{ "_id" : "61730", "city" : "COOKSVILLE", "loc" : [ -88.73504699999999, 40.536014 ], "pop" : 478, "state" : "IL" }
+{ "_id" : "61731", "city" : "CROPSEY", "loc" : [ -88.494343, 40.602983 ], "pop" : 240, "state" : "IL" }
+{ "_id" : "61732", "city" : "DANVERS", "loc" : [ -89.18848699999999, 40.536353 ], "pop" : 1825, "state" : "IL" }
+{ "_id" : "61733", "city" : "DEER CREEK", "loc" : [ -89.30029999999999, 40.627992 ], "pop" : 2277, "state" : "IL" }
+{ "_id" : "61734", "city" : "DELAVAN", "loc" : [ -89.532133, 40.369029 ], "pop" : 2285, "state" : "IL" }
+{ "_id" : "61735", "city" : "DEWITT", "loc" : [ -88.763672, 40.184759 ], "pop" : 417, "state" : "IL" }
+{ "_id" : "61736", "city" : "HOLDER", "loc" : [ -88.870814, 40.380858 ], "pop" : 992, "state" : "IL" }
+{ "_id" : "61737", "city" : "ELLSWORTH", "loc" : [ -88.737121, 40.443154 ], "pop" : 660, "state" : "IL" }
+{ "_id" : "61738", "city" : "EL PASO", "loc" : [ -89.01195199999999, 40.738948 ], "pop" : 3338, "state" : "IL" }
+{ "_id" : "61739", "city" : "FAIRBURY", "loc" : [ -88.516486, 40.745033 ], "pop" : 4706, "state" : "IL" }
+{ "_id" : "61740", "city" : "FLANAGAN", "loc" : [ -88.86196, 40.879003 ], "pop" : 1424, "state" : "IL" }
+{ "_id" : "61741", "city" : "FORREST", "loc" : [ -88.411143, 40.751324 ], "pop" : 1809, "state" : "IL" }
+{ "_id" : "61743", "city" : "GRAYMONT", "loc" : [ -88.760299, 40.90663 ], "pop" : 180, "state" : "IL" }
+{ "_id" : "61744", "city" : "GRIDLEY", "loc" : [ -88.884044, 40.74387 ], "pop" : 2142, "state" : "IL" }
+{ "_id" : "61745", "city" : "HEYWORTH", "loc" : [ -88.977608, 40.3307 ], "pop" : 2934, "state" : "IL" }
+{ "_id" : "61747", "city" : "HOPEDALE", "loc" : [ -89.421398, 40.427318 ], "pop" : 1355, "state" : "IL" }
+{ "_id" : "61748", "city" : "HUDSON", "loc" : [ -88.975931, 40.620485 ], "pop" : 1850, "state" : "IL" }
+{ "_id" : "61749", "city" : "KENNEY", "loc" : [ -89.078925, 40.10247 ], "pop" : 789, "state" : "IL" }
+{ "_id" : "61752", "city" : "LE ROY", "loc" : [ -88.75981299999999, 40.346781 ], "pop" : 3379, "state" : "IL" }
+{ "_id" : "61753", "city" : "LEXINGTON", "loc" : [ -88.806203, 40.635685 ], "pop" : 3098, "state" : "IL" }
+{ "_id" : "61754", "city" : "MC LEAN", "loc" : [ -89.164483, 40.328159 ], "pop" : 1432, "state" : "IL" }
+{ "_id" : "61755", "city" : "MACKINAW", "loc" : [ -89.345795, 40.539643 ], "pop" : 2772, "state" : "IL" }
+{ "_id" : "61756", "city" : "MAROA", "loc" : [ -88.957769, 40.034159 ], "pop" : 1883, "state" : "IL" }
+{ "_id" : "61759", "city" : "MINIER", "loc" : [ -89.316484, 40.435889 ], "pop" : 1483, "state" : "IL" }
+{ "_id" : "61760", "city" : "MINONK", "loc" : [ -89.034863, 40.898501 ], "pop" : 2559, "state" : "IL" }
+{ "_id" : "61761", "city" : "NORMAL", "loc" : [ -88.988287, 40.512446 ], "pop" : 40851, "state" : "IL" }
+{ "_id" : "61764", "city" : "PONTIAC", "loc" : [ -88.632775, 40.876404 ], "pop" : 14036, "state" : "IL" }
+{ "_id" : "61769", "city" : "SAUNEMIN", "loc" : [ -88.40936000000001, 40.888516 ], "pop" : 683, "state" : "IL" }
+{ "_id" : "61770", "city" : "SAYBROOK", "loc" : [ -88.52465599999999, 40.432005 ], "pop" : 1051, "state" : "IL" }
+{ "_id" : "61771", "city" : "SECOR", "loc" : [ -89.127065, 40.722402 ], "pop" : 952, "state" : "IL" }
+{ "_id" : "61772", "city" : "SHIRLEY", "loc" : [ -89.08218100000001, 40.417437 ], "pop" : 332, "state" : "IL" }
+{ "_id" : "61773", "city" : "SIBLEY", "loc" : [ -88.38146, 40.582315 ], "pop" : 608, "state" : "IL" }
+{ "_id" : "61774", "city" : "STANFORD", "loc" : [ -89.21643400000001, 40.437575 ], "pop" : 996, "state" : "IL" }
+{ "_id" : "61775", "city" : "STRAWN", "loc" : [ -88.404036, 40.647615 ], "pop" : 322, "state" : "IL" }
+{ "_id" : "61776", "city" : "TOWANDA", "loc" : [ -88.88865, 40.553326 ], "pop" : 1191, "state" : "IL" }
+{ "_id" : "61777", "city" : "WAPELLA", "loc" : [ -88.967264, 40.232305 ], "pop" : 1031, "state" : "IL" }
+{ "_id" : "61778", "city" : "WAYNESVILLE", "loc" : [ -89.114299, 40.243673 ], "pop" : 768, "state" : "IL" }
+{ "_id" : "61801", "city" : "URBANA", "loc" : [ -88.203631, 40.109522 ], "pop" : 46110, "state" : "IL" }
+{ "_id" : "61810", "city" : "ALLERTON", "loc" : [ -87.931235, 39.918818 ], "pop" : 405, "state" : "IL" }
+{ "_id" : "61811", "city" : "ALVIN", "loc" : [ -87.608003, 40.3007 ], "pop" : 817, "state" : "IL" }
+{ "_id" : "61812", "city" : "ARMSTRONG", "loc" : [ -87.894256, 40.217548 ], "pop" : 247, "state" : "IL" }
+{ "_id" : "61813", "city" : "BEMENT", "loc" : [ -88.56877, 39.922207 ], "pop" : 1928, "state" : "IL" }
+{ "_id" : "61814", "city" : "BISMARCK", "loc" : [ -87.613769, 40.255187 ], "pop" : 1476, "state" : "IL" }
+{ "_id" : "61816", "city" : "BROADLANDS", "loc" : [ -87.994831, 39.914247 ], "pop" : 481, "state" : "IL" }
+{ "_id" : "61817", "city" : "CATLIN", "loc" : [ -87.71125499999999, 40.069922 ], "pop" : 3359, "state" : "IL" }
+{ "_id" : "61818", "city" : "CERRO GORDO", "loc" : [ -88.725634, 39.868062 ], "pop" : 2060, "state" : "IL" }
+{ "_id" : "61820", "city" : "CHAMPAIGN", "loc" : [ -88.240747, 40.111017 ], "pop" : 33409, "state" : "IL" }
+{ "_id" : "61821", "city" : "CHAMPAIGN", "loc" : [ -88.278847, 40.107262 ], "pop" : 37547, "state" : "IL" }
+{ "_id" : "61830", "city" : "CISCO", "loc" : [ -88.696153, 39.997164 ], "pop" : 732, "state" : "IL" }
+{ "_id" : "61831", "city" : "COLLISON", "loc" : [ -87.798709, 40.220737 ], "pop" : 421, "state" : "IL" }
+{ "_id" : "61832", "city" : "DANVILLE", "loc" : [ -87.621737, 40.136976 ], "pop" : 49857, "state" : "IL" }
+{ "_id" : "61833", "city" : "TILTON", "loc" : [ -87.644048, 40.096406 ], "pop" : 2945, "state" : "IL" }
+{ "_id" : "61839", "city" : "DE LAND", "loc" : [ -88.63919300000001, 40.110656 ], "pop" : 848, "state" : "IL" }
+{ "_id" : "61840", "city" : "DEWEY", "loc" : [ -88.276966, 40.313055 ], "pop" : 548, "state" : "IL" }
+{ "_id" : "61841", "city" : "FAIRMOUNT", "loc" : [ -87.836456, 40.037329 ], "pop" : 1317, "state" : "IL" }
+{ "_id" : "61842", "city" : "FARMER CITY", "loc" : [ -88.66338500000001, 40.244689 ], "pop" : 2889, "state" : "IL" }
+{ "_id" : "61843", "city" : "FISHER", "loc" : [ -88.355991, 40.299126 ], "pop" : 2823, "state" : "IL" }
+{ "_id" : "61844", "city" : "FITHIAN", "loc" : [ -87.879713, 40.11924 ], "pop" : 673, "state" : "IL" }
+{ "_id" : "61845", "city" : "FOOSLAND", "loc" : [ -88.420177, 40.35537 ], "pop" : 319, "state" : "IL" }
+{ "_id" : "61846", "city" : "GEORGETOWN", "loc" : [ -87.63648000000001, 39.97922 ], "pop" : 4534, "state" : "IL" }
+{ "_id" : "61847", "city" : "GIFFORD", "loc" : [ -88.031705, 40.302755 ], "pop" : 1459, "state" : "IL" }
+{ "_id" : "61849", "city" : "HOMER", "loc" : [ -87.96274200000001, 40.034619 ], "pop" : 1624, "state" : "IL" }
+{ "_id" : "61850", "city" : "INDIANOLA", "loc" : [ -87.73882, 39.926819 ], "pop" : 715, "state" : "IL" }
+{ "_id" : "61851", "city" : "IVESDALE", "loc" : [ -88.44509499999999, 39.950233 ], "pop" : 596, "state" : "IL" }
+{ "_id" : "61852", "city" : "LONGVIEW", "loc" : [ -88.075282, 39.901241 ], "pop" : 555, "state" : "IL" }
+{ "_id" : "61853", "city" : "MAHOMET", "loc" : [ -88.39283, 40.196437 ], "pop" : 8734, "state" : "IL" }
+{ "_id" : "61854", "city" : "MANSFIELD", "loc" : [ -88.517895, 40.214697 ], "pop" : 1407, "state" : "IL" }
+{ "_id" : "61855", "city" : "MILMINE", "loc" : [ -88.648696, 39.900702 ], "pop" : 148, "state" : "IL" }
+{ "_id" : "61856", "city" : "MONTICELLO", "loc" : [ -88.568555, 40.02632 ], "pop" : 5339, "state" : "IL" }
+{ "_id" : "61858", "city" : "OAKWOOD", "loc" : [ -87.7825, 40.116656 ], "pop" : 2852, "state" : "IL" }
+{ "_id" : "61859", "city" : "OGDEN", "loc" : [ -87.966499, 40.140117 ], "pop" : 1397, "state" : "IL" }
+{ "_id" : "61862", "city" : "PENFIELD", "loc" : [ -87.95702, 40.310137 ], "pop" : 601, "state" : "IL" }
+{ "_id" : "61863", "city" : "PESOTUM", "loc" : [ -88.274331, 39.9151 ], "pop" : 774, "state" : "IL" }
+{ "_id" : "61864", "city" : "PHILO", "loc" : [ -88.15950599999999, 40.005156 ], "pop" : 1377, "state" : "IL" }
+{ "_id" : "61865", "city" : "POTOMAC", "loc" : [ -87.82319200000001, 40.309 ], "pop" : 1544, "state" : "IL" }
+{ "_id" : "61866", "city" : "RANTOUL", "loc" : [ -88.146179, 40.310742 ], "pop" : 11146, "state" : "IL" }
+{ "_id" : "61868", "city" : "RANTOUL", "loc" : [ -88.149884, 40.295886 ], "pop" : 7185, "state" : "IL" }
+{ "_id" : "61870", "city" : "RIDGE FARM", "loc" : [ -87.634578, 39.915455 ], "pop" : 2094, "state" : "IL" }
+{ "_id" : "61872", "city" : "SADORUS", "loc" : [ -88.344717, 39.961312 ], "pop" : 1022, "state" : "IL" }
+{ "_id" : "61873", "city" : "SAINT JOSEPH", "loc" : [ -88.04723199999999, 40.120736 ], "pop" : 4168, "state" : "IL" }
+{ "_id" : "61874", "city" : "SAVOY", "loc" : [ -88.252837, 40.065373 ], "pop" : 2972, "state" : "IL" }
+{ "_id" : "61875", "city" : "SEYMOUR", "loc" : [ -88.394431, 40.103471 ], "pop" : 1135, "state" : "IL" }
+{ "_id" : "61876", "city" : "SIDELL", "loc" : [ -87.82480200000001, 39.911018 ], "pop" : 703, "state" : "IL" }
+{ "_id" : "61877", "city" : "SIDNEY", "loc" : [ -88.069029, 40.023206 ], "pop" : 1521, "state" : "IL" }
+{ "_id" : "61878", "city" : "THOMASBORO", "loc" : [ -88.18303299999999, 40.240206 ], "pop" : 1638, "state" : "IL" }
+{ "_id" : "61880", "city" : "TOLONO", "loc" : [ -88.259641, 39.985006 ], "pop" : 2837, "state" : "IL" }
+{ "_id" : "61882", "city" : "WELDON", "loc" : [ -88.753055, 40.117741 ], "pop" : 579, "state" : "IL" }
+{ "_id" : "61883", "city" : "WESTVILLE", "loc" : [ -87.635952, 40.045113 ], "pop" : 4398, "state" : "IL" }
+{ "_id" : "61884", "city" : "WHITE HEATH", "loc" : [ -88.51929699999999, 40.100911 ], "pop" : 1481, "state" : "IL" }
+{ "_id" : "61910", "city" : "ARCOLA", "loc" : [ -88.303679, 39.687001 ], "pop" : 3132, "state" : "IL" }
+{ "_id" : "61911", "city" : "ARTHUR", "loc" : [ -88.45550900000001, 39.707679 ], "pop" : 4951, "state" : "IL" }
+{ "_id" : "61912", "city" : "ASHMORE", "loc" : [ -88.034097, 39.525428 ], "pop" : 1467, "state" : "IL" }
+{ "_id" : "61913", "city" : "ATWOOD", "loc" : [ -88.44944599999999, 39.804368 ], "pop" : 2455, "state" : "IL" }
+{ "_id" : "61914", "city" : "BETHANY", "loc" : [ -88.754301, 39.634754 ], "pop" : 1983, "state" : "IL" }
+{ "_id" : "61917", "city" : "BROCTON", "loc" : [ -87.926258, 39.692311 ], "pop" : 748, "state" : "IL" }
+{ "_id" : "61919", "city" : "CAMARGO", "loc" : [ -88.146815, 39.799955 ], "pop" : 1015, "state" : "IL" }
+{ "_id" : "61920", "city" : "CHARLESTON", "loc" : [ -88.176115, 39.486933 ], "pop" : 22767, "state" : "IL" }
+{ "_id" : "61924", "city" : "CHRISMAN", "loc" : [ -87.655552, 39.799572 ], "pop" : 2269, "state" : "IL" }
+{ "_id" : "61925", "city" : "DALTON CITY", "loc" : [ -88.797459, 39.711943 ], "pop" : 715, "state" : "IL" }
+{ "_id" : "61928", "city" : "GAYS", "loc" : [ -88.524153, 39.479553 ], "pop" : 678, "state" : "IL" }
+{ "_id" : "61929", "city" : "HAMMOND", "loc" : [ -88.57930500000001, 39.79465 ], "pop" : 797, "state" : "IL" }
+{ "_id" : "61930", "city" : "HINDSBORO", "loc" : [ -88.148611, 39.701799 ], "pop" : 811, "state" : "IL" }
+{ "_id" : "61931", "city" : "HUMBOLDT", "loc" : [ -88.314089, 39.60118 ], "pop" : 856, "state" : "IL" }
+{ "_id" : "61932", "city" : "HUME", "loc" : [ -87.87465899999999, 39.800882 ], "pop" : 593, "state" : "IL" }
+{ "_id" : "61933", "city" : "KANSAS", "loc" : [ -87.935238, 39.552533 ], "pop" : 1114, "state" : "IL" }
+{ "_id" : "61937", "city" : "LOVINGTON", "loc" : [ -88.64167500000001, 39.719192 ], "pop" : 1995, "state" : "IL" }
+{ "_id" : "61938", "city" : "MATTOON", "loc" : [ -88.376152, 39.480184 ], "pop" : 23012, "state" : "IL" }
+{ "_id" : "61940", "city" : "METCALF", "loc" : [ -87.795524, 39.800847 ], "pop" : 554, "state" : "IL" }
+{ "_id" : "61942", "city" : "NEWMAN", "loc" : [ -88.000055, 39.784788 ], "pop" : 1591, "state" : "IL" }
+{ "_id" : "61943", "city" : "OAKLAND", "loc" : [ -88.025325, 39.651618 ], "pop" : 1447, "state" : "IL" }
+{ "_id" : "61944", "city" : "PARIS", "loc" : [ -87.697631, 39.613219 ], "pop" : 12509, "state" : "IL" }
+{ "_id" : "61951", "city" : "SULLIVAN", "loc" : [ -88.603767, 39.593431 ], "pop" : 6946, "state" : "IL" }
+{ "_id" : "61953", "city" : "TUSCOLA", "loc" : [ -88.28158500000001, 39.799509 ], "pop" : 5056, "state" : "IL" }
+{ "_id" : "61956", "city" : "VILLA GROVE", "loc" : [ -88.161635, 39.868716 ], "pop" : 3259, "state" : "IL" }
+{ "_id" : "61957", "city" : "WINDSOR", "loc" : [ -88.585747, 39.430198 ], "pop" : 2019, "state" : "IL" }
+{ "_id" : "62001", "city" : "ALHAMBRA", "loc" : [ -89.744123, 38.882211 ], "pop" : 1543, "state" : "IL" }
+{ "_id" : "62002", "city" : "ALTON", "loc" : [ -90.156806, 38.908651 ], "pop" : 37541, "state" : "IL" }
+{ "_id" : "62006", "city" : "BATCHTOWN", "loc" : [ -90.659114, 39.072468 ], "pop" : 579, "state" : "IL" }
+{ "_id" : "62009", "city" : "BENLD", "loc" : [ -89.803057, 39.093903 ], "pop" : 1604, "state" : "IL" }
+{ "_id" : "62010", "city" : "BETHALTO", "loc" : [ -90.034447, 38.907353 ], "pop" : 10587, "state" : "IL" }
+{ "_id" : "62011", "city" : "BINGHAM", "loc" : [ -89.195789, 39.14667 ], "pop" : 565, "state" : "IL" }
+{ "_id" : "62012", "city" : "BRIGHTON", "loc" : [ -90.144312, 39.036098 ], "pop" : 6467, "state" : "IL" }
+{ "_id" : "62013", "city" : "MEPPEN", "loc" : [ -90.59069599999999, 38.937115 ], "pop" : 814, "state" : "IL" }
+{ "_id" : "62014", "city" : "BUNKER HILL", "loc" : [ -89.962379, 39.040827 ], "pop" : 3052, "state" : "IL" }
+{ "_id" : "62015", "city" : "BUTLER", "loc" : [ -89.530535, 39.211419 ], "pop" : 570, "state" : "IL" }
+{ "_id" : "62016", "city" : "CARROLLTON", "loc" : [ -90.409211, 39.300937 ], "pop" : 3079, "state" : "IL" }
+{ "_id" : "62017", "city" : "COFFEEN", "loc" : [ -89.39454000000001, 39.090757 ], "pop" : 1207, "state" : "IL" }
+{ "_id" : "62018", "city" : "COTTAGE HILLS", "loc" : [ -90.082632, 38.912377 ], "pop" : 4437, "state" : "IL" }
+{ "_id" : "62019", "city" : "DONNELLSON", "loc" : [ -89.490858, 39.034422 ], "pop" : 1010, "state" : "IL" }
+{ "_id" : "62021", "city" : "DORSEY", "loc" : [ -89.978635, 38.983237 ], "pop" : 652, "state" : "IL" }
+{ "_id" : "62022", "city" : "DOW", "loc" : [ -90.301059, 39.031198 ], "pop" : 1758, "state" : "IL" }
+{ "_id" : "62024", "city" : "EAST ALTON", "loc" : [ -90.083045, 38.88031 ], "pop" : 13839, "state" : "IL" }
+{ "_id" : "62025", "city" : "EDWARDSVILLE", "loc" : [ -89.963697, 38.804967 ], "pop" : 19241, "state" : "IL" }
+{ "_id" : "62027", "city" : "ELDRED", "loc" : [ -90.53287400000001, 39.283592 ], "pop" : 907, "state" : "IL" }
+{ "_id" : "62028", "city" : "ELSAH", "loc" : [ -90.331913, 38.961297 ], "pop" : 2553, "state" : "IL" }
+{ "_id" : "62030", "city" : "FIDELITY", "loc" : [ -90.198803, 39.132286 ], "pop" : 655, "state" : "IL" }
+{ "_id" : "62031", "city" : "FIELDON", "loc" : [ -90.529742, 39.108608 ], "pop" : 1382, "state" : "IL" }
+{ "_id" : "62032", "city" : "FILLMORE", "loc" : [ -89.294551, 39.103872 ], "pop" : 977, "state" : "IL" }
+{ "_id" : "62033", "city" : "DORCHESTER", "loc" : [ -89.818577, 39.136106 ], "pop" : 6518, "state" : "IL" }
+{ "_id" : "62034", "city" : "GLEN CARBON", "loc" : [ -89.970583, 38.760871 ], "pop" : 9729, "state" : "IL" }
+{ "_id" : "62035", "city" : "GODFREY", "loc" : [ -90.206024, 38.946035 ], "pop" : 13959, "state" : "IL" }
+{ "_id" : "62036", "city" : "GOLDEN EAGLE", "loc" : [ -90.560199, 38.896138 ], "pop" : 266, "state" : "IL" }
+{ "_id" : "62037", "city" : "GRAFTON", "loc" : [ -90.43233499999999, 39.002134 ], "pop" : 2036, "state" : "IL" }
+{ "_id" : "62040", "city" : "MITCHELL", "loc" : [ -90.11582199999999, 38.721572 ], "pop" : 48697, "state" : "IL" }
+{ "_id" : "62044", "city" : "GREENFIELD", "loc" : [ -90.208851, 39.349058 ], "pop" : 1718, "state" : "IL" }
+{ "_id" : "62045", "city" : "HAMBURG", "loc" : [ -90.699546, 39.223488 ], "pop" : 383, "state" : "IL" }
+{ "_id" : "62046", "city" : "HAMEL", "loc" : [ -89.87267799999999, 38.878433 ], "pop" : 1685, "state" : "IL" }
+{ "_id" : "62047", "city" : "HARDIN", "loc" : [ -90.624002, 39.154652 ], "pop" : 1232, "state" : "IL" }
+{ "_id" : "62048", "city" : "HARTFORD", "loc" : [ -90.074533, 38.829852 ], "pop" : 3763, "state" : "IL" }
+{ "_id" : "62049", "city" : "HILLSBORO", "loc" : [ -89.488146, 39.149412 ], "pop" : 7916, "state" : "IL" }
+{ "_id" : "62050", "city" : "HILLVIEW", "loc" : [ -90.512837, 39.467373 ], "pop" : 795, "state" : "IL" }
+{ "_id" : "62051", "city" : "IRVING", "loc" : [ -89.41043000000001, 39.208903 ], "pop" : 909, "state" : "IL" }
+{ "_id" : "62052", "city" : "JERSEYVILLE", "loc" : [ -90.33375700000001, 39.121324 ], "pop" : 9439, "state" : "IL" }
+{ "_id" : "62053", "city" : "KAMPSVILLE", "loc" : [ -90.62693400000001, 39.306388 ], "pop" : 623, "state" : "IL" }
+{ "_id" : "62054", "city" : "KANE", "loc" : [ -90.37188, 39.203688 ], "pop" : 1044, "state" : "IL" }
+{ "_id" : "62056", "city" : "LITCHFIELD", "loc" : [ -89.64991499999999, 39.179345 ], "pop" : 9172, "state" : "IL" }
+{ "_id" : "62060", "city" : "MADISON", "loc" : [ -90.15658500000001, 38.68109 ], "pop" : 7556, "state" : "IL" }
+{ "_id" : "62061", "city" : "MARINE", "loc" : [ -89.821376, 38.785458 ], "pop" : 2020, "state" : "IL" }
+{ "_id" : "62063", "city" : "MEDORA", "loc" : [ -90.154225, 39.198593 ], "pop" : 531, "state" : "IL" }
+{ "_id" : "62065", "city" : "MICHAEL", "loc" : [ -90.633498, 39.21821 ], "pop" : 343, "state" : "IL" }
+{ "_id" : "62067", "city" : "MORO", "loc" : [ -89.961771, 38.931769 ], "pop" : 2775, "state" : "IL" }
+{ "_id" : "62069", "city" : "MOUNT OLIVE", "loc" : [ -89.74484200000001, 39.070504 ], "pop" : 3443, "state" : "IL" }
+{ "_id" : "62070", "city" : "MOZIER", "loc" : [ -90.714978, 39.287719 ], "pop" : 241, "state" : "IL" }
+{ "_id" : "62074", "city" : "NEW DOUGLAS", "loc" : [ -89.73923499999999, 38.967633 ], "pop" : 2464, "state" : "IL" }
+{ "_id" : "62075", "city" : "NOKOMIS", "loc" : [ -89.285297, 39.303642 ], "pop" : 4576, "state" : "IL" }
+{ "_id" : "62079", "city" : "PIASA", "loc" : [ -90.131147, 39.151697 ], "pop" : 863, "state" : "IL" }
+{ "_id" : "62080", "city" : "RAMSEY", "loc" : [ -89.105147, 39.078123 ], "pop" : 4166, "state" : "IL" }
+{ "_id" : "62081", "city" : "ROCKBRIDGE", "loc" : [ -90.255818, 39.283146 ], "pop" : 718, "state" : "IL" }
+{ "_id" : "62082", "city" : "ROODHOUSE", "loc" : [ -90.34981399999999, 39.484646 ], "pop" : 3020, "state" : "IL" }
+{ "_id" : "62083", "city" : "ROSAMOND", "loc" : [ -89.1846, 39.389229 ], "pop" : 443, "state" : "IL" }
+{ "_id" : "62084", "city" : "ROXANA", "loc" : [ -90.07978, 38.848154 ], "pop" : 1513, "state" : "IL" }
+{ "_id" : "62086", "city" : "SORENTO", "loc" : [ -89.565347, 38.969342 ], "pop" : 2127, "state" : "IL" }
+{ "_id" : "62088", "city" : "STAUNTON", "loc" : [ -89.785697, 39.01348 ], "pop" : 5482, "state" : "IL" }
+{ "_id" : "62090", "city" : "VENICE", "loc" : [ -90.16892799999999, 38.67063 ], "pop" : 1559, "state" : "IL" }
+{ "_id" : "62091", "city" : "WALSHVILLE", "loc" : [ -89.634968, 39.047257 ], "pop" : 359, "state" : "IL" }
+{ "_id" : "62092", "city" : "WHITE HALL", "loc" : [ -90.401899, 39.428804 ], "pop" : 3882, "state" : "IL" }
+{ "_id" : "62094", "city" : "WITT", "loc" : [ -89.341426, 39.246919 ], "pop" : 1251, "state" : "IL" }
+{ "_id" : "62095", "city" : "WOOD RIVER", "loc" : [ -90.087507, 38.864279 ], "pop" : 10817, "state" : "IL" }
+{ "_id" : "62097", "city" : "WORDEN", "loc" : [ -89.85321399999999, 38.944895 ], "pop" : 1818, "state" : "IL" }
+{ "_id" : "62201", "city" : "SAUGET", "loc" : [ -90.13806599999999, 38.631538 ], "pop" : 11213, "state" : "IL" }
+{ "_id" : "62203", "city" : "EAST SAINT LOUIS", "loc" : [ -90.074449, 38.599191 ], "pop" : 12435, "state" : "IL" }
+{ "_id" : "62204", "city" : "WASHINGTON PARK", "loc" : [ -90.102008, 38.631335 ], "pop" : 14425, "state" : "IL" }
+{ "_id" : "62205", "city" : "EAST SAINT LOUIS", "loc" : [ -90.12750200000001, 38.614947 ], "pop" : 14488, "state" : "IL" }
+{ "_id" : "62206", "city" : "CAHOKIA", "loc" : [ -90.16587, 38.561899 ], "pop" : 20356, "state" : "IL" }
+{ "_id" : "62207", "city" : "ALORTON", "loc" : [ -90.12829000000001, 38.58734 ], "pop" : 11681, "state" : "IL" }
+{ "_id" : "62208", "city" : "FAIRVIEW HEIGHTS", "loc" : [ -90.007093, 38.596044 ], "pop" : 10882, "state" : "IL" }
+{ "_id" : "62214", "city" : "VENEDY", "loc" : [ -89.52273, 38.360422 ], "pop" : 539, "state" : "IL" }
+{ "_id" : "62215", "city" : "ALBERS", "loc" : [ -89.62015100000001, 38.531955 ], "pop" : 1641, "state" : "IL" }
+{ "_id" : "62217", "city" : "BALDWIN", "loc" : [ -89.841391, 38.175351 ], "pop" : 1093, "state" : "IL" }
+{ "_id" : "62218", "city" : "BARTELSO", "loc" : [ -89.457841, 38.53851 ], "pop" : 1270, "state" : "IL" }
+{ "_id" : "62220", "city" : "BELLEVILLE", "loc" : [ -89.98469299999999, 38.512677 ], "pop" : 23454, "state" : "IL" }
+{ "_id" : "62221", "city" : "BELLEVILLE", "loc" : [ -89.958302, 38.539639 ], "pop" : 29321, "state" : "IL" }
+{ "_id" : "62223", "city" : "BELLEVILLE", "loc" : [ -90.037775, 38.545581 ], "pop" : 34650, "state" : "IL" }
+{ "_id" : "62225", "city" : "SCOTT A F B", "loc" : [ -89.85877499999999, 38.54692 ], "pop" : 7391, "state" : "IL" }
+{ "_id" : "62230", "city" : "BREESE", "loc" : [ -89.52838, 38.618802 ], "pop" : 4882, "state" : "IL" }
+{ "_id" : "62231", "city" : "CARLYLE", "loc" : [ -89.380544, 38.606609 ], "pop" : 6529, "state" : "IL" }
+{ "_id" : "62232", "city" : "CASEYVILLE", "loc" : [ -90.013486, 38.634458 ], "pop" : 7601, "state" : "IL" }
+{ "_id" : "62233", "city" : "CHESTER", "loc" : [ -89.82180700000001, 37.918822 ], "pop" : 9436, "state" : "IL" }
+{ "_id" : "62234", "city" : "COLLINSVILLE", "loc" : [ -89.98529000000001, 38.683545 ], "pop" : 33686, "state" : "IL" }
+{ "_id" : "62236", "city" : "COLUMBIA", "loc" : [ -90.20271700000001, 38.432469 ], "pop" : 8489, "state" : "IL" }
+{ "_id" : "62237", "city" : "SWANWICK", "loc" : [ -89.582064, 38.176401 ], "pop" : 2359, "state" : "IL" }
+{ "_id" : "62238", "city" : "CUTLER", "loc" : [ -89.56612699999999, 38.042663 ], "pop" : 787, "state" : "IL" }
+{ "_id" : "62239", "city" : "DUPO", "loc" : [ -90.194188, 38.514771 ], "pop" : 5663, "state" : "IL" }
+{ "_id" : "62240", "city" : "EAST CARONDELET", "loc" : [ -90.220782, 38.534912 ], "pop" : 1579, "state" : "IL" }
+{ "_id" : "62241", "city" : "ELLIS GROVE", "loc" : [ -89.900847, 38.005358 ], "pop" : 999, "state" : "IL" }
+{ "_id" : "62242", "city" : "EVANSVILLE", "loc" : [ -89.917028, 38.09258 ], "pop" : 1540, "state" : "IL" }
+{ "_id" : "62243", "city" : "FREEBURG", "loc" : [ -89.91806, 38.408016 ], "pop" : 5837, "state" : "IL" }
+{ "_id" : "62244", "city" : "FULTS", "loc" : [ -90.19735300000001, 38.179736 ], "pop" : 635, "state" : "IL" }
+{ "_id" : "62245", "city" : "GERMANTOWN", "loc" : [ -89.54134000000001, 38.548677 ], "pop" : 1773, "state" : "IL" }
+{ "_id" : "62246", "city" : "GREENVILLE", "loc" : [ -89.405185, 38.893338 ], "pop" : 7623, "state" : "IL" }
+{ "_id" : "62248", "city" : "HECKER", "loc" : [ -89.983115, 38.281039 ], "pop" : 1454, "state" : "IL" }
+{ "_id" : "62249", "city" : "HIGHLAND", "loc" : [ -89.678894, 38.763086 ], "pop" : 6772, "state" : "IL" }
+{ "_id" : "62253", "city" : "KEYESPORT", "loc" : [ -89.30632300000001, 38.738773 ], "pop" : 1464, "state" : "IL" }
+{ "_id" : "62254", "city" : "LEBANON", "loc" : [ -89.79921299999999, 38.60528 ], "pop" : 4950, "state" : "IL" }
+{ "_id" : "62255", "city" : "LENZBURG", "loc" : [ -89.792202, 38.295003 ], "pop" : 1316, "state" : "IL" }
+{ "_id" : "62256", "city" : "MAEYSTOWN", "loc" : [ -90.20178, 38.24112 ], "pop" : 592, "state" : "IL" }
+{ "_id" : "62257", "city" : "MARISSA", "loc" : [ -89.750119, 38.245455 ], "pop" : 2634, "state" : "IL" }
+{ "_id" : "62258", "city" : "MASCOUTAH", "loc" : [ -89.787745, 38.474496 ], "pop" : 8151, "state" : "IL" }
+{ "_id" : "62260", "city" : "MILLSTADT", "loc" : [ -90.088818, 38.444264 ], "pop" : 4979, "state" : "IL" }
+{ "_id" : "62261", "city" : "MODOC", "loc" : [ -90.016261, 38.050683 ], "pop" : 381, "state" : "IL" }
+{ "_id" : "62262", "city" : "MULBERRY GROVE", "loc" : [ -89.246297, 38.931082 ], "pop" : 1721, "state" : "IL" }
+{ "_id" : "62263", "city" : "NASHVILLE", "loc" : [ -89.384058, 38.335208 ], "pop" : 4546, "state" : "IL" }
+{ "_id" : "62264", "city" : "NEW ATHENS", "loc" : [ -89.872777, 38.315998 ], "pop" : 2488, "state" : "IL" }
+{ "_id" : "62265", "city" : "NEW BADEN", "loc" : [ -89.692232, 38.531485 ], "pop" : 3455, "state" : "IL" }
+{ "_id" : "62268", "city" : "OAKDALE", "loc" : [ -89.596046, 38.257285 ], "pop" : 1348, "state" : "IL" }
+{ "_id" : "62269", "city" : "SHILOH", "loc" : [ -89.9093, 38.59052 ], "pop" : 21198, "state" : "IL" }
+{ "_id" : "62271", "city" : "OKAWVILLE", "loc" : [ -89.523045, 38.431862 ], "pop" : 2187, "state" : "IL" }
+{ "_id" : "62272", "city" : "PERCY", "loc" : [ -89.616961, 38.01261 ], "pop" : 1241, "state" : "IL" }
+{ "_id" : "62274", "city" : "PINCKNEYVILLE", "loc" : [ -89.38578, 38.090327 ], "pop" : 7013, "state" : "IL" }
+{ "_id" : "62275", "city" : "POCAHONTAS", "loc" : [ -89.52468399999999, 38.78456 ], "pop" : 3279, "state" : "IL" }
+{ "_id" : "62277", "city" : "PRAIRIE DU ROCHE", "loc" : [ -90.090147, 38.085468 ], "pop" : 1017, "state" : "IL" }
+{ "_id" : "62278", "city" : "RED BUD", "loc" : [ -89.988356, 38.190738 ], "pop" : 4923, "state" : "IL" }
+{ "_id" : "62279", "city" : "RENAULT", "loc" : [ -90.095043, 38.170396 ], "pop" : 929, "state" : "IL" }
+{ "_id" : "62280", "city" : "ROCKWOOD", "loc" : [ -89.62144499999999, 37.832201 ], "pop" : 770, "state" : "IL" }
+{ "_id" : "62281", "city" : "SAINT JACOB", "loc" : [ -89.669616, 38.72448 ], "pop" : 5477, "state" : "IL" }
+{ "_id" : "62283", "city" : "SHATTUC", "loc" : [ -89.20543600000001, 38.643533 ], "pop" : 1079, "state" : "IL" }
+{ "_id" : "62284", "city" : "SMITHBORO", "loc" : [ -89.326556, 38.873893 ], "pop" : 771, "state" : "IL" }
+{ "_id" : "62285", "city" : "SMITHTON", "loc" : [ -89.989604, 38.423137 ], "pop" : 2749, "state" : "IL" }
+{ "_id" : "62286", "city" : "SPARTA", "loc" : [ -89.703458, 38.131815 ], "pop" : 8035, "state" : "IL" }
+{ "_id" : "62288", "city" : "STEELEVILLE", "loc" : [ -89.66645800000001, 38.005713 ], "pop" : 2951, "state" : "IL" }
+{ "_id" : "62293", "city" : "TRENTON", "loc" : [ -89.644696, 38.619102 ], "pop" : 5574, "state" : "IL" }
+{ "_id" : "62294", "city" : "TROY", "loc" : [ -89.870848, 38.724275 ], "pop" : 10526, "state" : "IL" }
+{ "_id" : "62295", "city" : "VALMEYER", "loc" : [ -90.309234, 38.295163 ], "pop" : 1841, "state" : "IL" }
+{ "_id" : "62297", "city" : "WALSH", "loc" : [ -89.82965799999999, 38.020286 ], "pop" : 801, "state" : "IL" }
+{ "_id" : "62298", "city" : "WATERLOO", "loc" : [ -90.147773, 38.322273 ], "pop" : 8482, "state" : "IL" }
+{ "_id" : "62301", "city" : "QUINCY", "loc" : [ -91.376284, 39.930701 ], "pop" : 52014, "state" : "IL" }
+{ "_id" : "62311", "city" : "AUGUSTA", "loc" : [ -90.955416, 40.234109 ], "pop" : 867, "state" : "IL" }
+{ "_id" : "62312", "city" : "BARRY", "loc" : [ -91.026482, 39.704662 ], "pop" : 2697, "state" : "IL" }
+{ "_id" : "62313", "city" : "BASCO", "loc" : [ -91.196983, 40.328303 ], "pop" : 399, "state" : "IL" }
+{ "_id" : "62314", "city" : "BAYLIS", "loc" : [ -90.883216, 39.761201 ], "pop" : 628, "state" : "IL" }
+{ "_id" : "62316", "city" : "BOWEN", "loc" : [ -91.070491, 40.234076 ], "pop" : 693, "state" : "IL" }
+{ "_id" : "62318", "city" : "BURNSIDE", "loc" : [ -91.142392, 40.497445 ], "pop" : 770, "state" : "IL" }
+{ "_id" : "62319", "city" : "CAMDEN", "loc" : [ -90.75443300000001, 40.151076 ], "pop" : 317, "state" : "IL" }
+{ "_id" : "62320", "city" : "CAMP POINT", "loc" : [ -91.076926, 40.029285 ], "pop" : 2113, "state" : "IL" }
+{ "_id" : "62321", "city" : "CARTHAGE", "loc" : [ -91.100522, 40.412937 ], "pop" : 4171, "state" : "IL" }
+{ "_id" : "62323", "city" : "CHAMBERSBURG", "loc" : [ -90.663017, 39.807058 ], "pop" : 203, "state" : "IL" }
+{ "_id" : "62324", "city" : "CLAYTON", "loc" : [ -90.955394, 40.013342 ], "pop" : 1354, "state" : "IL" }
+{ "_id" : "62325", "city" : "COATSBURG", "loc" : [ -91.174733, 40.055385 ], "pop" : 446, "state" : "IL" }
+{ "_id" : "62326", "city" : "COLCHESTER", "loc" : [ -90.78456, 40.415643 ], "pop" : 2470, "state" : "IL" }
+{ "_id" : "62330", "city" : "PONTOOSUC", "loc" : [ -91.163454, 40.620062 ], "pop" : 2146, "state" : "IL" }
+{ "_id" : "62332", "city" : "DETROIT", "loc" : [ -90.65449, 39.618307 ], "pop" : 353, "state" : "IL" }
+{ "_id" : "62334", "city" : "ELVASTON", "loc" : [ -91.21642, 40.40662 ], "pop" : 449, "state" : "IL" }
+{ "_id" : "62338", "city" : "FOWLER", "loc" : [ -91.245226, 39.992504 ], "pop" : 508, "state" : "IL" }
+{ "_id" : "62339", "city" : "GOLDEN", "loc" : [ -91.029588, 40.120257 ], "pop" : 938, "state" : "IL" }
+{ "_id" : "62340", "city" : "GRIGGSVILLE", "loc" : [ -90.724891, 39.708378 ], "pop" : 1611, "state" : "IL" }
+{ "_id" : "62341", "city" : "HAMILTON", "loc" : [ -91.344042, 40.439213 ], "pop" : 5574, "state" : "IL" }
+{ "_id" : "62343", "city" : "HULL", "loc" : [ -91.233844, 39.718562 ], "pop" : 892, "state" : "IL" }
+{ "_id" : "62344", "city" : "HUNTSVILLE", "loc" : [ -90.85313600000001, 40.154396 ], "pop" : 189, "state" : "IL" }
+{ "_id" : "62345", "city" : "KINDERHOOK", "loc" : [ -91.16372800000001, 39.695313 ], "pop" : 427, "state" : "IL" }
+{ "_id" : "62346", "city" : "LA PRAIRIE", "loc" : [ -90.984387, 40.157191 ], "pop" : 218, "state" : "IL" }
+{ "_id" : "62347", "city" : "LIBERTY", "loc" : [ -91.08687999999999, 39.889176 ], "pop" : 1331, "state" : "IL" }
+{ "_id" : "62348", "city" : "LIMA", "loc" : [ -91.38675600000001, 40.170098 ], "pop" : 559, "state" : "IL" }
+{ "_id" : "62349", "city" : "LORAINE", "loc" : [ -91.21301, 40.153197 ], "pop" : 634, "state" : "IL" }
+{ "_id" : "62351", "city" : "MENDON", "loc" : [ -91.289923, 40.085658 ], "pop" : 1462, "state" : "IL" }
+{ "_id" : "62352", "city" : "MILTON", "loc" : [ -90.644346, 39.550811 ], "pop" : 548, "state" : "IL" }
+{ "_id" : "62353", "city" : "MOUNT STERLING", "loc" : [ -90.74142399999999, 39.980279 ], "pop" : 4058, "state" : "IL" }
+{ "_id" : "62355", "city" : "NEBO", "loc" : [ -90.7692, 39.420181 ], "pop" : 1011, "state" : "IL" }
+{ "_id" : "62356", "city" : "NEW CANTON", "loc" : [ -91.088556, 39.634242 ], "pop" : 658, "state" : "IL" }
+{ "_id" : "62357", "city" : "NEW SALEM", "loc" : [ -90.843986, 39.699573 ], "pop" : 292, "state" : "IL" }
+{ "_id" : "62358", "city" : "NIOTA", "loc" : [ -91.299136, 40.597753 ], "pop" : 672, "state" : "IL" }
+{ "_id" : "62359", "city" : "PALOMA", "loc" : [ -91.205287, 40.036616 ], "pop" : 254, "state" : "IL" }
+{ "_id" : "62360", "city" : "PAYSON", "loc" : [ -91.262676, 39.815253 ], "pop" : 1939, "state" : "IL" }
+{ "_id" : "62361", "city" : "PEARL", "loc" : [ -90.63795399999999, 39.444072 ], "pop" : 415, "state" : "IL" }
+{ "_id" : "62362", "city" : "PERRY", "loc" : [ -90.746105, 39.787042 ], "pop" : 703, "state" : "IL" }
+{ "_id" : "62363", "city" : "PITTSFIELD", "loc" : [ -90.80726900000001, 39.601306 ], "pop" : 5678, "state" : "IL" }
+{ "_id" : "62365", "city" : "PLAINVILLE", "loc" : [ -91.143598, 39.800448 ], "pop" : 986, "state" : "IL" }
+{ "_id" : "62366", "city" : "PLEASANT HILL", "loc" : [ -90.877011, 39.446697 ], "pop" : 1521, "state" : "IL" }
+{ "_id" : "62367", "city" : "COLMAR", "loc" : [ -90.87381499999999, 40.288493 ], "pop" : 1425, "state" : "IL" }
+{ "_id" : "62370", "city" : "ROCKPORT", "loc" : [ -90.972178, 39.532846 ], "pop" : 641, "state" : "IL" }
+{ "_id" : "62373", "city" : "SUTTER", "loc" : [ -91.37609399999999, 40.309683 ], "pop" : 747, "state" : "IL" }
+{ "_id" : "62374", "city" : "TENNESSEE", "loc" : [ -90.855605, 40.41399 ], "pop" : 414, "state" : "IL" }
+{ "_id" : "62375", "city" : "TIMEWELL", "loc" : [ -90.866067, 40.011658 ], "pop" : 539, "state" : "IL" }
+{ "_id" : "62376", "city" : "URSA", "loc" : [ -91.373341, 40.080918 ], "pop" : 1074, "state" : "IL" }
+{ "_id" : "62378", "city" : "VERSAILLES", "loc" : [ -90.674147, 39.888286 ], "pop" : 1136, "state" : "IL" }
+{ "_id" : "62379", "city" : "WARSAW", "loc" : [ -91.434803, 40.354449 ], "pop" : 1882, "state" : "IL" }
+{ "_id" : "62380", "city" : "WEST POINT", "loc" : [ -91.249568, 40.245184 ], "pop" : 874, "state" : "IL" }
+{ "_id" : "62401", "city" : "EFFINGHAM", "loc" : [ -88.561105, 39.121727 ], "pop" : 15524, "state" : "IL" }
+{ "_id" : "62410", "city" : "ALLENDALE", "loc" : [ -87.721901, 38.523236 ], "pop" : 1051, "state" : "IL" }
+{ "_id" : "62411", "city" : "ALTAMONT", "loc" : [ -88.748092, 39.063449 ], "pop" : 3867, "state" : "IL" }
+{ "_id" : "62413", "city" : "ANNAPOLIS", "loc" : [ -87.802875, 39.117857 ], "pop" : 692, "state" : "IL" }
+{ "_id" : "62414", "city" : "BEECHER CITY", "loc" : [ -88.80385, 39.183515 ], "pop" : 1968, "state" : "IL" }
+{ "_id" : "62415", "city" : "BIRDS", "loc" : [ -87.681545, 38.812059 ], "pop" : 842, "state" : "IL" }
+{ "_id" : "62417", "city" : "BRIDGEPORT", "loc" : [ -87.85492600000001, 38.694506 ], "pop" : 2076, "state" : "IL" }
+{ "_id" : "62418", "city" : "BROWNSTOWN", "loc" : [ -88.949438, 38.989118 ], "pop" : 2434, "state" : "IL" }
+{ "_id" : "62419", "city" : "CALHOUN", "loc" : [ -88.003745, 38.635116 ], "pop" : 715, "state" : "IL" }
+{ "_id" : "62420", "city" : "CASEY", "loc" : [ -87.99130599999999, 39.301716 ], "pop" : 5300, "state" : "IL" }
+{ "_id" : "62421", "city" : "CLAREMONT", "loc" : [ -87.972685, 38.742904 ], "pop" : 1320, "state" : "IL" }
+{ "_id" : "62422", "city" : "COWDEN", "loc" : [ -88.886799, 39.232643 ], "pop" : 1521, "state" : "IL" }
+{ "_id" : "62423", "city" : "DENNISON", "loc" : [ -87.58671, 39.449033 ], "pop" : 753, "state" : "IL" }
+{ "_id" : "62424", "city" : "DIETERICH", "loc" : [ -88.407448, 39.031875 ], "pop" : 1639, "state" : "IL" }
+{ "_id" : "62425", "city" : "DUNDAS", "loc" : [ -88.097309, 38.830572 ], "pop" : 437, "state" : "IL" }
+{ "_id" : "62426", "city" : "LACLEDE", "loc" : [ -88.66386799999999, 38.91318 ], "pop" : 772, "state" : "IL" }
+{ "_id" : "62427", "city" : "FLAT ROCK", "loc" : [ -87.683747, 38.909606 ], "pop" : 2173, "state" : "IL" }
+{ "_id" : "62428", "city" : "HAZEL DELL", "loc" : [ -88.144502, 39.239454 ], "pop" : 2914, "state" : "IL" }
+{ "_id" : "62431", "city" : "HERRICK", "loc" : [ -88.981211, 39.224481 ], "pop" : 628, "state" : "IL" }
+{ "_id" : "62432", "city" : "HIDALGO", "loc" : [ -88.139706, 39.122808 ], "pop" : 820, "state" : "IL" }
+{ "_id" : "62433", "city" : "HUTSONVILLE", "loc" : [ -87.669455, 39.106357 ], "pop" : 1039, "state" : "IL" }
+{ "_id" : "62434", "city" : "INGRAHAM", "loc" : [ -88.320374, 38.828446 ], "pop" : 1077, "state" : "IL" }
+{ "_id" : "62436", "city" : "JEWETT", "loc" : [ -88.24744, 39.207596 ], "pop" : 402, "state" : "IL" }
+{ "_id" : "62438", "city" : "LAKEWOOD", "loc" : [ -88.87147400000001, 39.313358 ], "pop" : 415, "state" : "IL" }
+{ "_id" : "62439", "city" : "LAWRENCEVILLE", "loc" : [ -87.678397, 38.730862 ], "pop" : 7833, "state" : "IL" }
+{ "_id" : "62440", "city" : "LERNA", "loc" : [ -88.25302600000001, 39.39579 ], "pop" : 1289, "state" : "IL" }
+{ "_id" : "62441", "city" : "MARSHALL", "loc" : [ -87.692261, 39.421999 ], "pop" : 8305, "state" : "IL" }
+{ "_id" : "62442", "city" : "MARTINSVILLE", "loc" : [ -87.87073700000001, 39.317443 ], "pop" : 1881, "state" : "IL" }
+{ "_id" : "62443", "city" : "MASON", "loc" : [ -88.623396, 38.964453 ], "pop" : 1774, "state" : "IL" }
+{ "_id" : "62445", "city" : "MONTROSE", "loc" : [ -88.33497, 39.157274 ], "pop" : 1611, "state" : "IL" }
+{ "_id" : "62446", "city" : "MOUNT ERIE", "loc" : [ -88.218521, 38.522151 ], "pop" : 470, "state" : "IL" }
+{ "_id" : "62447", "city" : "NEOGA", "loc" : [ -88.450288, 39.322024 ], "pop" : 3494, "state" : "IL" }
+{ "_id" : "62448", "city" : "NEWTON", "loc" : [ -88.17038599999999, 38.984678 ], "pop" : 5296, "state" : "IL" }
+{ "_id" : "62449", "city" : "OBLONG", "loc" : [ -87.895016, 39.001043 ], "pop" : 3508, "state" : "IL" }
+{ "_id" : "62450", "city" : "OLNEY", "loc" : [ -88.08093599999999, 38.733389 ], "pop" : 11163, "state" : "IL" }
+{ "_id" : "62451", "city" : "PALESTINE", "loc" : [ -87.615695, 39.002823 ], "pop" : 2413, "state" : "IL" }
+{ "_id" : "62452", "city" : "PARKERSBURG", "loc" : [ -88.064722, 38.589998 ], "pop" : 485, "state" : "IL" }
+{ "_id" : "62454", "city" : "ROBINSON", "loc" : [ -87.748352, 39.007034 ], "pop" : 9243, "state" : "IL" }
+{ "_id" : "62458", "city" : "SAINT ELMO", "loc" : [ -88.855181, 39.031544 ], "pop" : 2091, "state" : "IL" }
+{ "_id" : "62460", "city" : "SAINT FRANCISVIL", "loc" : [ -87.67362799999999, 38.612494 ], "pop" : 1806, "state" : "IL" }
+{ "_id" : "62461", "city" : "SHUMWAY", "loc" : [ -88.64182599999999, 39.188138 ], "pop" : 539, "state" : "IL" }
+{ "_id" : "62462", "city" : "SIGEL", "loc" : [ -88.480301, 39.21762 ], "pop" : 2239, "state" : "IL" }
+{ "_id" : "62463", "city" : "STEWARDSON", "loc" : [ -88.63185300000001, 39.27199 ], "pop" : 1219, "state" : "IL" }
+{ "_id" : "62465", "city" : "STRASBURG", "loc" : [ -88.62786199999999, 39.364111 ], "pop" : 758, "state" : "IL" }
+{ "_id" : "62466", "city" : "SUMNER", "loc" : [ -87.780728, 38.734077 ], "pop" : 3517, "state" : "IL" }
+{ "_id" : "62467", "city" : "TEUTOPOLIS", "loc" : [ -88.476741, 39.131978 ], "pop" : 3095, "state" : "IL" }
+{ "_id" : "62468", "city" : "TOLEDO", "loc" : [ -88.246821, 39.277223 ], "pop" : 2046, "state" : "IL" }
+{ "_id" : "62469", "city" : "TRILLA", "loc" : [ -88.345698, 39.385286 ], "pop" : 499, "state" : "IL" }
+{ "_id" : "62471", "city" : "VANDALIA", "loc" : [ -89.104116, 38.94391 ], "pop" : 7894, "state" : "IL" }
+{ "_id" : "62473", "city" : "WATSON", "loc" : [ -88.559876, 39.039488 ], "pop" : 2740, "state" : "IL" }
+{ "_id" : "62474", "city" : "WESTFIELD", "loc" : [ -88.044799, 39.442369 ], "pop" : 1602, "state" : "IL" }
+{ "_id" : "62475", "city" : "WEST LIBERTY", "loc" : [ -88.09792899999999, 38.894989 ], "pop" : 593, "state" : "IL" }
+{ "_id" : "62476", "city" : "WEST SALEM", "loc" : [ -88.032297, 38.518267 ], "pop" : 1994, "state" : "IL" }
+{ "_id" : "62477", "city" : "WEST UNION", "loc" : [ -87.65121499999999, 39.240185 ], "pop" : 993, "state" : "IL" }
+{ "_id" : "62478", "city" : "WEST YORK", "loc" : [ -87.71307299999999, 39.193793 ], "pop" : 665, "state" : "IL" }
+{ "_id" : "62479", "city" : "WHEELER", "loc" : [ -88.317536, 39.018185 ], "pop" : 809, "state" : "IL" }
+{ "_id" : "62480", "city" : "WILLOW HILL", "loc" : [ -88.017156, 38.975654 ], "pop" : 1708, "state" : "IL" }
+{ "_id" : "62481", "city" : "YALE", "loc" : [ -88.01047, 39.129975 ], "pop" : 410, "state" : "IL" }
+{ "_id" : "62501", "city" : "NEWBURG", "loc" : [ -88.821371, 39.991581 ], "pop" : 1444, "state" : "IL" }
+{ "_id" : "62510", "city" : "ASSUMPTION", "loc" : [ -89.039807, 39.509489 ], "pop" : 1949, "state" : "IL" }
+{ "_id" : "62511", "city" : "ATWATER", "loc" : [ -89.763374, 39.310733 ], "pop" : 489, "state" : "IL" }
+{ "_id" : "62512", "city" : "BEASON", "loc" : [ -89.194801, 40.143652 ], "pop" : 467, "state" : "IL" }
+{ "_id" : "62513", "city" : "BLUE MOUND", "loc" : [ -89.113558, 39.697813 ], "pop" : 1488, "state" : "IL" }
+{ "_id" : "62514", "city" : "BOODY", "loc" : [ -89.07206100000001, 39.762824 ], "pop" : 541, "state" : "IL" }
+{ "_id" : "62515", "city" : "BUFFALO HART", "loc" : [ -89.388846, 39.847201 ], "pop" : 797, "state" : "IL" }
+{ "_id" : "62518", "city" : "CHESTNUT", "loc" : [ -89.19001400000001, 40.058202 ], "pop" : 436, "state" : "IL" }
+{ "_id" : "62520", "city" : "DAWSON", "loc" : [ -89.460329, 39.85629 ], "pop" : 558, "state" : "IL" }
+{ "_id" : "62521", "city" : "DECATUR", "loc" : [ -88.925984, 39.827137 ], "pop" : 39666, "state" : "IL" }
+{ "_id" : "62522", "city" : "DECATUR", "loc" : [ -88.98613899999999, 39.843237 ], "pop" : 19224, "state" : "IL" }
+{ "_id" : "62523", "city" : "DECATUR", "loc" : [ -88.953435, 39.841694 ], "pop" : 864, "state" : "IL" }
+{ "_id" : "62526", "city" : "BEARSDALE", "loc" : [ -88.953515, 39.877413 ], "pop" : 39674, "state" : "IL" }
+{ "_id" : "62530", "city" : "CIMIC", "loc" : [ -89.65465399999999, 39.567684 ], "pop" : 1484, "state" : "IL" }
+{ "_id" : "62531", "city" : "EDINBURG", "loc" : [ -89.37788399999999, 39.661223 ], "pop" : 1925, "state" : "IL" }
+{ "_id" : "62533", "city" : "THOMASVILLE", "loc" : [ -89.642718, 39.453048 ], "pop" : 1047, "state" : "IL" }
+{ "_id" : "62534", "city" : "BRUNSWICK", "loc" : [ -88.756208, 39.503253 ], "pop" : 1410, "state" : "IL" }
+{ "_id" : "62536", "city" : "GLENARM", "loc" : [ -89.65814399999999, 39.632713 ], "pop" : 739, "state" : "IL" }
+{ "_id" : "62538", "city" : "HARVEL", "loc" : [ -89.53804, 39.371865 ], "pop" : 374, "state" : "IL" }
+{ "_id" : "62539", "city" : "ILLIOPOLIS", "loc" : [ -89.251319, 39.849929 ], "pop" : 1366, "state" : "IL" }
+{ "_id" : "62543", "city" : "LATHAM", "loc" : [ -89.17249200000001, 39.97111 ], "pop" : 857, "state" : "IL" }
+{ "_id" : "62544", "city" : "MACON", "loc" : [ -88.988026, 39.704093 ], "pop" : 1737, "state" : "IL" }
+{ "_id" : "62545", "city" : "BOLIVIA", "loc" : [ -89.417692, 39.77771 ], "pop" : 2228, "state" : "IL" }
+{ "_id" : "62546", "city" : "MORRISONVILLE", "loc" : [ -89.45407, 39.415336 ], "pop" : 1418, "state" : "IL" }
+{ "_id" : "62547", "city" : "MOUNT AUBURN", "loc" : [ -89.23567199999999, 39.762845 ], "pop" : 1011, "state" : "IL" }
+{ "_id" : "62548", "city" : "MOUNT PULASKI", "loc" : [ -89.293482, 40.004482 ], "pop" : 2500, "state" : "IL" }
+{ "_id" : "62549", "city" : "HERVEY CITY", "loc" : [ -88.87020699999999, 39.778883 ], "pop" : 5691, "state" : "IL" }
+{ "_id" : "62550", "city" : "RADFORD", "loc" : [ -89.012776, 39.616135 ], "pop" : 3112, "state" : "IL" }
+{ "_id" : "62551", "city" : "NIANTIC", "loc" : [ -89.17007099999999, 39.858175 ], "pop" : 850, "state" : "IL" }
+{ "_id" : "62552", "city" : "CASNER", "loc" : [ -88.80559100000001, 39.896897 ], "pop" : 810, "state" : "IL" }
+{ "_id" : "62553", "city" : "OCONEE", "loc" : [ -89.083636, 39.288408 ], "pop" : 796, "state" : "IL" }
+{ "_id" : "62554", "city" : "OREANA", "loc" : [ -88.854675, 39.935135 ], "pop" : 1554, "state" : "IL" }
+{ "_id" : "62555", "city" : "OWANECO", "loc" : [ -89.195071, 39.477508 ], "pop" : 540, "state" : "IL" }
+{ "_id" : "62556", "city" : "CLARKSDALE", "loc" : [ -89.425555, 39.470817 ], "pop" : 689, "state" : "IL" }
+{ "_id" : "62557", "city" : "DUNKEL", "loc" : [ -89.078165, 39.388124 ], "pop" : 7081, "state" : "IL" }
+{ "_id" : "62558", "city" : "SICILY", "loc" : [ -89.57895499999999, 39.590966 ], "pop" : 2822, "state" : "IL" }
+{ "_id" : "62560", "city" : "RAYMOND", "loc" : [ -89.58513499999999, 39.310551 ], "pop" : 1660, "state" : "IL" }
+{ "_id" : "62561", "city" : "SPAULDING", "loc" : [ -89.54190800000001, 39.855239 ], "pop" : 3921, "state" : "IL" }
+{ "_id" : "62563", "city" : "BERRY", "loc" : [ -89.547208, 39.759047 ], "pop" : 8726, "state" : "IL" }
+{ "_id" : "62565", "city" : "CLARKSBURG", "loc" : [ -88.804615, 39.404873 ], "pop" : 7481, "state" : "IL" }
+{ "_id" : "62567", "city" : "STONINGTON", "loc" : [ -89.191328, 39.640482 ], "pop" : 1280, "state" : "IL" }
+{ "_id" : "62568", "city" : "HEWITTSVILLE", "loc" : [ -89.313357, 39.554516 ], "pop" : 17182, "state" : "IL" }
+{ "_id" : "62571", "city" : "DOLLVILLE", "loc" : [ -88.97451700000001, 39.36576 ], "pop" : 1505, "state" : "IL" }
+{ "_id" : "62572", "city" : "WAGGONER", "loc" : [ -89.647429, 39.38383 ], "pop" : 547, "state" : "IL" }
+{ "_id" : "62573", "city" : "HEMAN", "loc" : [ -89.068316, 39.939737 ], "pop" : 1780, "state" : "IL" }
+{ "_id" : "62601", "city" : "ORLEANS", "loc" : [ -90.035304, 39.725935 ], "pop" : 501, "state" : "IL" }
+{ "_id" : "62611", "city" : "ARENZVILLE", "loc" : [ -90.363595, 39.897927 ], "pop" : 1008, "state" : "IL" }
+{ "_id" : "62612", "city" : "NEWMANSVILLE", "loc" : [ -90.028721, 39.89168 ], "pop" : 1904, "state" : "IL" }
+{ "_id" : "62613", "city" : "FANCY PRAIRIE", "loc" : [ -89.72108, 39.964813 ], "pop" : 2696, "state" : "IL" }
+{ "_id" : "62615", "city" : "AUBURN", "loc" : [ -89.744033, 39.591787 ], "pop" : 3934, "state" : "IL" }
+{ "_id" : "62617", "city" : "LYNCHBURG", "loc" : [ -90.148568, 40.161774 ], "pop" : 1118, "state" : "IL" }
+{ "_id" : "62618", "city" : "BEARDSTOWN", "loc" : [ -90.42285099999999, 40.004356 ], "pop" : 7369, "state" : "IL" }
+{ "_id" : "62621", "city" : "EXETER", "loc" : [ -90.53052700000001, 39.744078 ], "pop" : 1101, "state" : "IL" }
+{ "_id" : "62624", "city" : "BADER", "loc" : [ -90.351671, 40.155025 ], "pop" : 766, "state" : "IL" }
+{ "_id" : "62625", "city" : "CANTRALL", "loc" : [ -89.66426, 39.911267 ], "pop" : 1811, "state" : "IL" }
+{ "_id" : "62626", "city" : "COMER", "loc" : [ -89.888935, 39.279821 ], "pop" : 7343, "state" : "IL" }
+{ "_id" : "62627", "city" : "PANTHER CREEK", "loc" : [ -90.147657, 40.038437 ], "pop" : 1283, "state" : "IL" }
+{ "_id" : "62628", "city" : "CHAPIN", "loc" : [ -90.411299, 39.771581 ], "pop" : 879, "state" : "IL" }
+{ "_id" : "62629", "city" : "CHATHAM", "loc" : [ -89.711212, 39.673679 ], "pop" : 4922, "state" : "IL" }
+{ "_id" : "62630", "city" : "HAGAMAN", "loc" : [ -90.076632, 39.270756 ], "pop" : 683, "state" : "IL" }
+{ "_id" : "62631", "city" : "CONCORD", "loc" : [ -90.372175, 39.822958 ], "pop" : 460, "state" : "IL" }
+{ "_id" : "62633", "city" : "BIGGS", "loc" : [ -89.846447, 40.235482 ], "pop" : 1056, "state" : "IL" }
+{ "_id" : "62634", "city" : "BROADWELL", "loc" : [ -89.47493799999999, 40.002394 ], "pop" : 922, "state" : "IL" }
+{ "_id" : "62635", "city" : "EMDEN", "loc" : [ -89.51744100000001, 40.294538 ], "pop" : 1144, "state" : "IL" }
+{ "_id" : "62638", "city" : "CLEMENTS", "loc" : [ -90.048535, 39.608461 ], "pop" : 1280, "state" : "IL" }
+{ "_id" : "62639", "city" : "FREDERICK", "loc" : [ -90.504391, 40.070246 ], "pop" : 690, "state" : "IL" }
+{ "_id" : "62640", "city" : "MCVEY", "loc" : [ -89.780535, 39.447182 ], "pop" : 2454, "state" : "IL" }
+{ "_id" : "62642", "city" : "HUBLY", "loc" : [ -89.711606, 40.079859 ], "pop" : 1499, "state" : "IL" }
+{ "_id" : "62643", "city" : "HARTSBURG", "loc" : [ -89.451944, 40.245073 ], "pop" : 602, "state" : "IL" }
+{ "_id" : "62644", "city" : "ECKARD", "loc" : [ -90.04952, 40.295995 ], "pop" : 5593, "state" : "IL" }
+{ "_id" : "62649", "city" : "HETTICK", "loc" : [ -90.067161, 39.375217 ], "pop" : 518, "state" : "IL" }
+{ "_id" : "62650", "city" : "ARCADIA", "loc" : [ -90.236238, 39.729269 ], "pop" : 28240, "state" : "IL" }
+{ "_id" : "62655", "city" : "KILBOURNE", "loc" : [ -90.004279, 40.158696 ], "pop" : 633, "state" : "IL" }
+{ "_id" : "62656", "city" : "LINCOLN", "loc" : [ -89.368376, 40.14508 ], "pop" : 20130, "state" : "IL" }
+{ "_id" : "62661", "city" : "LOAMI", "loc" : [ -89.858823, 39.670394 ], "pop" : 1286, "state" : "IL" }
+{ "_id" : "62664", "city" : "LUTHER", "loc" : [ -89.69925600000001, 40.199938 ], "pop" : 2968, "state" : "IL" }
+{ "_id" : "62665", "city" : "NAPLES", "loc" : [ -90.549542, 39.797631 ], "pop" : 2215, "state" : "IL" }
+{ "_id" : "62666", "city" : "MIDDLETOWN", "loc" : [ -89.58181999999999, 40.096668 ], "pop" : 586, "state" : "IL" }
+{ "_id" : "62667", "city" : "MODESTO", "loc" : [ -89.97938600000001, 39.475965 ], "pop" : 564, "state" : "IL" }
+{ "_id" : "62668", "city" : "NORTONVILLE", "loc" : [ -90.231189, 39.572952 ], "pop" : 1387, "state" : "IL" }
+{ "_id" : "62670", "city" : "BATES", "loc" : [ -89.905721, 39.736048 ], "pop" : 1470, "state" : "IL" }
+{ "_id" : "62671", "city" : "NEW HOLLAND", "loc" : [ -89.56044, 40.168226 ], "pop" : 663, "state" : "IL" }
+{ "_id" : "62672", "city" : "NILWOOD", "loc" : [ -89.77841100000001, 39.387199 ], "pop" : 633, "state" : "IL" }
+{ "_id" : "62673", "city" : "OAKFORD", "loc" : [ -89.96013499999999, 40.099445 ], "pop" : 493, "state" : "IL" }
+{ "_id" : "62674", "city" : "BARR", "loc" : [ -89.95673600000001, 39.41654 ], "pop" : 1490, "state" : "IL" }
+{ "_id" : "62675", "city" : "ATTERBURY", "loc" : [ -89.847874, 40.011529 ], "pop" : 5049, "state" : "IL" }
+{ "_id" : "62676", "city" : "PLAINVIEW", "loc" : [ -89.97568699999999, 39.128311 ], "pop" : 792, "state" : "IL" }
+{ "_id" : "62677", "city" : "FARMINGDALE", "loc" : [ -89.83836100000001, 39.849767 ], "pop" : 3081, "state" : "IL" }
+{ "_id" : "62681", "city" : "LAYTON", "loc" : [ -90.560883, 40.124189 ], "pop" : 4747, "state" : "IL" }
+{ "_id" : "62682", "city" : "ALLEN", "loc" : [ -89.625029, 40.294466 ], "pop" : 669, "state" : "IL" }
+{ "_id" : "62683", "city" : "SCOTTVILLE", "loc" : [ -90.09692099999999, 39.478167 ], "pop" : 387, "state" : "IL" }
+{ "_id" : "62684", "city" : "BARCLAY", "loc" : [ -89.60251, 39.889456 ], "pop" : 2185, "state" : "IL" }
+{ "_id" : "62685", "city" : "ROYAL LAKES", "loc" : [ -90.048737, 39.124165 ], "pop" : 844, "state" : "IL" }
+{ "_id" : "62688", "city" : "TALLULA", "loc" : [ -89.882274, 39.940188 ], "pop" : 1427, "state" : "IL" }
+{ "_id" : "62690", "city" : "VIRDEN", "loc" : [ -89.77833200000001, 39.506447 ], "pop" : 5939, "state" : "IL" }
+{ "_id" : "62691", "city" : "LITTLE INDIAN", "loc" : [ -90.212681, 39.945475 ], "pop" : 2144, "state" : "IL" }
+{ "_id" : "62692", "city" : "WAVERLY", "loc" : [ -89.944903, 39.586983 ], "pop" : 1968, "state" : "IL" }
+{ "_id" : "62693", "city" : "WILLIAMSVILLE", "loc" : [ -89.534172, 39.930438 ], "pop" : 2320, "state" : "IL" }
+{ "_id" : "62694", "city" : "GLASGOW", "loc" : [ -90.433696, 39.614113 ], "pop" : 3909, "state" : "IL" }
+{ "_id" : "62701", "city" : "SPRINGFIELD", "loc" : [ -89.649531, 39.80004 ], "pop" : 1155, "state" : "IL" }
+{ "_id" : "62702", "city" : "GRANDVIEW", "loc" : [ -89.644147, 39.816768 ], "pop" : 42047, "state" : "IL" }
+{ "_id" : "62703", "city" : "SOUTHERN VIEW", "loc" : [ -89.63333, 39.772401 ], "pop" : 32501, "state" : "IL" }
+{ "_id" : "62704", "city" : "JEROME", "loc" : [ -89.681066, 39.780319 ], "pop" : 41611, "state" : "IL" }
+{ "_id" : "62707", "city" : "ANDREW", "loc" : [ -89.663991, 39.772842 ], "pop" : 16264, "state" : "IL" }
+{ "_id" : "62801", "city" : "CENTRALIA", "loc" : [ -89.136478, 38.524117 ], "pop" : 23956, "state" : "IL" }
+{ "_id" : "62803", "city" : "HOYLETON", "loc" : [ -89.306854, 38.445468 ], "pop" : 1295, "state" : "IL" }
+{ "_id" : "62806", "city" : "ALBION", "loc" : [ -88.063557, 38.374003 ], "pop" : 3162, "state" : "IL" }
+{ "_id" : "62807", "city" : "ALMA", "loc" : [ -88.915695, 38.723089 ], "pop" : 1251, "state" : "IL" }
+{ "_id" : "62808", "city" : "ASHLEY", "loc" : [ -89.231115, 38.306002 ], "pop" : 1260, "state" : "IL" }
+{ "_id" : "62809", "city" : "BARNHILL", "loc" : [ -88.350831, 38.278144 ], "pop" : 165, "state" : "IL" }
+{ "_id" : "62810", "city" : "BELLE RIVE", "loc" : [ -88.75580100000001, 38.215268 ], "pop" : 1149, "state" : "IL" }
+{ "_id" : "62812", "city" : "BENTON", "loc" : [ -88.922659, 37.99998 ], "pop" : 11419, "state" : "IL" }
+{ "_id" : "62814", "city" : "BLUFORD", "loc" : [ -88.75872, 38.353138 ], "pop" : 2622, "state" : "IL" }
+{ "_id" : "62815", "city" : "BONE GAP", "loc" : [ -88.00249100000001, 38.448967 ], "pop" : 496, "state" : "IL" }
+{ "_id" : "62816", "city" : "BONNIE", "loc" : [ -88.922884, 38.198017 ], "pop" : 994, "state" : "IL" }
+{ "_id" : "62817", "city" : "BROUGHTON", "loc" : [ -88.467775, 37.954554 ], "pop" : 732, "state" : "IL" }
+{ "_id" : "62818", "city" : "BROWNS", "loc" : [ -87.992824, 38.376433 ], "pop" : 440, "state" : "IL" }
+{ "_id" : "62819", "city" : "BUCKNER", "loc" : [ -88.977993, 37.966881 ], "pop" : 278, "state" : "IL" }
+{ "_id" : "62820", "city" : "BURNT PRAIRIE", "loc" : [ -88.214719, 38.208151 ], "pop" : 503, "state" : "IL" }
+{ "_id" : "62821", "city" : "CARMI", "loc" : [ -88.16698700000001, 38.080819 ], "pop" : 8234, "state" : "IL" }
+{ "_id" : "62822", "city" : "CHRISTOPHER", "loc" : [ -89.057367, 37.984905 ], "pop" : 5042, "state" : "IL" }
+{ "_id" : "62823", "city" : "CISNE", "loc" : [ -88.40452399999999, 38.513774 ], "pop" : 1403, "state" : "IL" }
+{ "_id" : "62824", "city" : "CLAY CITY", "loc" : [ -88.351641, 38.669501 ], "pop" : 1753, "state" : "IL" }
+{ "_id" : "62827", "city" : "CROSSVILLE", "loc" : [ -88.05947399999999, 38.166029 ], "pop" : 1388, "state" : "IL" }
+{ "_id" : "62828", "city" : "DAHLGREN", "loc" : [ -88.63631100000001, 38.197479 ], "pop" : 1627, "state" : "IL" }
+{ "_id" : "62829", "city" : "DALE", "loc" : [ -88.53423100000001, 37.996585 ], "pop" : 594, "state" : "IL" }
+{ "_id" : "62830", "city" : "DIX", "loc" : [ -88.96569700000001, 38.43329 ], "pop" : 1552, "state" : "IL" }
+{ "_id" : "62831", "city" : "DU BOIS", "loc" : [ -89.204187, 38.252638 ], "pop" : 732, "state" : "IL" }
+{ "_id" : "62832", "city" : "DU QUOIN", "loc" : [ -89.233268, 38.013687 ], "pop" : 10061, "state" : "IL" }
+{ "_id" : "62833", "city" : "ELLERY", "loc" : [ -88.133455, 38.365021 ], "pop" : 141, "state" : "IL" }
+{ "_id" : "62835", "city" : "ENFIELD", "loc" : [ -88.33254599999999, 38.092746 ], "pop" : 1145, "state" : "IL" }
+{ "_id" : "62836", "city" : "EWING", "loc" : [ -88.850441, 38.07021 ], "pop" : 1286, "state" : "IL" }
+{ "_id" : "62837", "city" : "FAIRFIELD", "loc" : [ -88.359323, 38.378214 ], "pop" : 8723, "state" : "IL" }
+{ "_id" : "62838", "city" : "FARINA", "loc" : [ -88.76141200000001, 38.846902 ], "pop" : 925, "state" : "IL" }
+{ "_id" : "62839", "city" : "FLORA", "loc" : [ -88.49186, 38.670337 ], "pop" : 6989, "state" : "IL" }
+{ "_id" : "62840", "city" : "FRANKFORT HEIGHT", "loc" : [ -88.845651, 37.901301 ], "pop" : 778, "state" : "IL" }
+{ "_id" : "62842", "city" : "GEFF", "loc" : [ -88.414428, 38.441326 ], "pop" : 632, "state" : "IL" }
+{ "_id" : "62843", "city" : "GOLDEN GATE", "loc" : [ -88.207466, 38.364514 ], "pop" : 733, "state" : "IL" }
+{ "_id" : "62844", "city" : "GRAYVILLE", "loc" : [ -88.003539, 38.262707 ], "pop" : 2569, "state" : "IL" }
+{ "_id" : "62845", "city" : "HERALD", "loc" : [ -88.21315199999999, 37.967542 ], "pop" : 641, "state" : "IL" }
+{ "_id" : "62846", "city" : "INA", "loc" : [ -88.88936200000001, 38.152743 ], "pop" : 800, "state" : "IL" }
+{ "_id" : "62849", "city" : "IUKA", "loc" : [ -88.768925, 38.613563 ], "pop" : 965, "state" : "IL" }
+{ "_id" : "62850", "city" : "JOHNSONVILLE", "loc" : [ -88.588701, 38.525628 ], "pop" : 1264, "state" : "IL" }
+{ "_id" : "62851", "city" : "KEENES", "loc" : [ -88.64805800000001, 38.369146 ], "pop" : 968, "state" : "IL" }
+{ "_id" : "62853", "city" : "KELL", "loc" : [ -88.84110699999999, 38.513256 ], "pop" : 1261, "state" : "IL" }
+{ "_id" : "62854", "city" : "KINMUNDY", "loc" : [ -88.812999, 38.755857 ], "pop" : 2134, "state" : "IL" }
+{ "_id" : "62855", "city" : "LANCASTER", "loc" : [ -87.871216, 38.537438 ], "pop" : 567, "state" : "IL" }
+{ "_id" : "62858", "city" : "BIBLE GROVE", "loc" : [ -88.510046, 38.811856 ], "pop" : 3688, "state" : "IL" }
+{ "_id" : "62859", "city" : "MC LEANSBORO", "loc" : [ -88.52855599999999, 38.093861 ], "pop" : 4357, "state" : "IL" }
+{ "_id" : "62860", "city" : "MACEDONIA", "loc" : [ -88.696077, 38.013023 ], "pop" : 1505, "state" : "IL" }
+{ "_id" : "62862", "city" : "MILL SHOALS", "loc" : [ -88.333817, 38.244675 ], "pop" : 412, "state" : "IL" }
+{ "_id" : "62863", "city" : "MOUNT CARMEL", "loc" : [ -87.791107, 38.414727 ], "pop" : 11493, "state" : "IL" }
+{ "_id" : "62864", "city" : "MOUNT VERNON", "loc" : [ -88.91052500000001, 38.317014 ], "pop" : 23844, "state" : "IL" }
+{ "_id" : "62865", "city" : "MULKEYTOWN", "loc" : [ -89.1159, 37.968712 ], "pop" : 474, "state" : "IL" }
+{ "_id" : "62866", "city" : "NASON", "loc" : [ -88.968839, 38.173872 ], "pop" : 269, "state" : "IL" }
+{ "_id" : "62867", "city" : "NEW HAVEN", "loc" : [ -88.12845799999999, 37.899907 ], "pop" : 558, "state" : "IL" }
+{ "_id" : "62868", "city" : "NOBLE", "loc" : [ -88.219038, 38.711851 ], "pop" : 2425, "state" : "IL" }
+{ "_id" : "62869", "city" : "NORRIS CITY", "loc" : [ -88.32434000000001, 37.9773 ], "pop" : 2377, "state" : "IL" }
+{ "_id" : "62870", "city" : "ODIN", "loc" : [ -89.055228, 38.608786 ], "pop" : 1758, "state" : "IL" }
+{ "_id" : "62871", "city" : "OMAHA", "loc" : [ -88.286484, 37.890423 ], "pop" : 638, "state" : "IL" }
+{ "_id" : "62872", "city" : "OPDYKE", "loc" : [ -88.77495500000001, 38.274955 ], "pop" : 284, "state" : "IL" }
+{ "_id" : "62875", "city" : "PATOKA", "loc" : [ -89.094188, 38.754852 ], "pop" : 857, "state" : "IL" }
+{ "_id" : "62877", "city" : "RICHVIEW", "loc" : [ -89.175572, 38.408227 ], "pop" : 1087, "state" : "IL" }
+{ "_id" : "62878", "city" : "RINARD", "loc" : [ -88.464094, 38.580596 ], "pop" : 377, "state" : "IL" }
+{ "_id" : "62880", "city" : "SAINT PETER", "loc" : [ -88.855998, 38.869684 ], "pop" : 725, "state" : "IL" }
+{ "_id" : "62881", "city" : "SALEM", "loc" : [ -88.948077, 38.626421 ], "pop" : 11599, "state" : "IL" }
+{ "_id" : "62882", "city" : "SANDOVAL", "loc" : [ -89.11400999999999, 38.613113 ], "pop" : 3145, "state" : "IL" }
+{ "_id" : "62883", "city" : "SCHELLER", "loc" : [ -89.092691, 38.173095 ], "pop" : 528, "state" : "IL" }
+{ "_id" : "62884", "city" : "SESSER", "loc" : [ -89.05740400000001, 38.089422 ], "pop" : 2844, "state" : "IL" }
+{ "_id" : "62885", "city" : "SHOBONIER", "loc" : [ -89.078959, 38.844584 ], "pop" : 219, "state" : "IL" }
+{ "_id" : "62886", "city" : "SIMS", "loc" : [ -88.530642, 38.392318 ], "pop" : 868, "state" : "IL" }
+{ "_id" : "62887", "city" : "SPRINGERTON", "loc" : [ -88.37261100000001, 38.169868 ], "pop" : 737, "state" : "IL" }
+{ "_id" : "62888", "city" : "TAMAROA", "loc" : [ -89.223091, 38.137969 ], "pop" : 1788, "state" : "IL" }
+{ "_id" : "62889", "city" : "TEXICO", "loc" : [ -88.87015100000001, 38.425035 ], "pop" : 1159, "state" : "IL" }
+{ "_id" : "62890", "city" : "THOMPSONVILLE", "loc" : [ -88.768394, 37.880438 ], "pop" : 2413, "state" : "IL" }
+{ "_id" : "62892", "city" : "VERNON", "loc" : [ -89.083001, 38.803328 ], "pop" : 371, "state" : "IL" }
+{ "_id" : "62893", "city" : "WALNUT HILL", "loc" : [ -88.984514, 38.520006 ], "pop" : 1386, "state" : "IL" }
+{ "_id" : "62894", "city" : "WALTONVILLE", "loc" : [ -89.006702, 38.246479 ], "pop" : 1923, "state" : "IL" }
+{ "_id" : "62895", "city" : "WAYNE CITY", "loc" : [ -88.58331699999999, 38.332808 ], "pop" : 1523, "state" : "IL" }
+{ "_id" : "62896", "city" : "WEST FRANKFORT", "loc" : [ -88.930724, 37.897914 ], "pop" : 11800, "state" : "IL" }
+{ "_id" : "62897", "city" : "WHITTINGTON", "loc" : [ -88.863456, 38.098937 ], "pop" : 370, "state" : "IL" }
+{ "_id" : "62898", "city" : "WOODLAWN", "loc" : [ -89.074457, 38.38444 ], "pop" : 1896, "state" : "IL" }
+{ "_id" : "62899", "city" : "XENIA", "loc" : [ -88.63789, 38.669747 ], "pop" : 1252, "state" : "IL" }
+{ "_id" : "62901", "city" : "CARBONDALE", "loc" : [ -89.215762, 37.719994 ], "pop" : 31742, "state" : "IL" }
+{ "_id" : "62905", "city" : "ALTO PASS", "loc" : [ -89.317179, 37.568142 ], "pop" : 912, "state" : "IL" }
+{ "_id" : "62906", "city" : "ANNA", "loc" : [ -89.22068400000001, 37.466777 ], "pop" : 8151, "state" : "IL" }
+{ "_id" : "62907", "city" : "AVA", "loc" : [ -89.465366, 37.879286 ], "pop" : 1806, "state" : "IL" }
+{ "_id" : "62908", "city" : "BELKNAP", "loc" : [ -88.95065200000001, 37.326584 ], "pop" : 188, "state" : "IL" }
+{ "_id" : "62910", "city" : "NEW LIBERTY", "loc" : [ -88.61194399999999, 37.138731 ], "pop" : 2565, "state" : "IL" }
+{ "_id" : "62912", "city" : "BUNCOMBE", "loc" : [ -88.980586, 37.463661 ], "pop" : 696, "state" : "IL" }
+{ "_id" : "62913", "city" : "CACHE", "loc" : [ -89.298018, 37.114131 ], "pop" : 80, "state" : "IL" }
+{ "_id" : "62914", "city" : "CAIRO", "loc" : [ -89.181104, 37.012293 ], "pop" : 5439, "state" : "IL" }
+{ "_id" : "62916", "city" : "CAMPBELL HILL", "loc" : [ -89.57990100000001, 37.922778 ], "pop" : 976, "state" : "IL" }
+{ "_id" : "62917", "city" : "CARRIER MILLS", "loc" : [ -88.612706, 37.678199 ], "pop" : 3355, "state" : "IL" }
+{ "_id" : "62918", "city" : "CARTERVILLE", "loc" : [ -89.097793, 37.774785 ], "pop" : 10457, "state" : "IL" }
+{ "_id" : "62919", "city" : "CAVE IN ROCK", "loc" : [ -88.22196099999999, 37.517947 ], "pop" : 2266, "state" : "IL" }
+{ "_id" : "62920", "city" : "COBDEN", "loc" : [ -89.245741, 37.542358 ], "pop" : 2348, "state" : "IL" }
+{ "_id" : "62922", "city" : "CREAL SPRINGS", "loc" : [ -88.880697, 37.628393 ], "pop" : 2743, "state" : "IL" }
+{ "_id" : "62923", "city" : "CYPRESS", "loc" : [ -89.014414, 37.366223 ], "pop" : 618, "state" : "IL" }
+{ "_id" : "62924", "city" : "DE SOTO", "loc" : [ -89.221834, 37.81473 ], "pop" : 2073, "state" : "IL" }
+{ "_id" : "62926", "city" : "DONGOLA", "loc" : [ -89.134933, 37.371234 ], "pop" : 2361, "state" : "IL" }
+{ "_id" : "62928", "city" : "EDDYVILLE", "loc" : [ -88.594893, 37.52439 ], "pop" : 677, "state" : "IL" }
+{ "_id" : "62930", "city" : "ELDORADO", "loc" : [ -88.443382, 37.813885 ], "pop" : 7036, "state" : "IL" }
+{ "_id" : "62931", "city" : "ELIZABETHTOWN", "loc" : [ -88.28673499999999, 37.466492 ], "pop" : 815, "state" : "IL" }
+{ "_id" : "62932", "city" : "ELKVILLE", "loc" : [ -89.233574, 37.915506 ], "pop" : 2091, "state" : "IL" }
+{ "_id" : "62934", "city" : "EQUALITY", "loc" : [ -88.3445, 37.727786 ], "pop" : 1173, "state" : "IL" }
+{ "_id" : "62935", "city" : "GALATIA", "loc" : [ -88.62348799999999, 37.827444 ], "pop" : 2802, "state" : "IL" }
+{ "_id" : "62938", "city" : "BROWNFIELD", "loc" : [ -88.555148, 37.349984 ], "pop" : 2997, "state" : "IL" }
+{ "_id" : "62939", "city" : "GOREVILLE", "loc" : [ -88.965524, 37.574985 ], "pop" : 2867, "state" : "IL" }
+{ "_id" : "62940", "city" : "GORHAM", "loc" : [ -89.444031, 37.740611 ], "pop" : 982, "state" : "IL" }
+{ "_id" : "62941", "city" : "GRAND CHAIN", "loc" : [ -89.008335, 37.251043 ], "pop" : 603, "state" : "IL" }
+{ "_id" : "62942", "city" : "GRAND TOWER", "loc" : [ -89.49986, 37.63222 ], "pop" : 903, "state" : "IL" }
+{ "_id" : "62943", "city" : "GRANTSBURG", "loc" : [ -88.770489, 37.39672 ], "pop" : 2549, "state" : "IL" }
+{ "_id" : "62946", "city" : "HARRISBURG", "loc" : [ -88.54404, 37.725661 ], "pop" : 12122, "state" : "IL" }
+{ "_id" : "62947", "city" : "HEROD", "loc" : [ -88.458062, 37.469731 ], "pop" : 699, "state" : "IL" }
+{ "_id" : "62948", "city" : "HERRIN", "loc" : [ -89.02316, 37.801884 ], "pop" : 13900, "state" : "IL" }
+{ "_id" : "62950", "city" : "JACOB", "loc" : [ -89.544359, 37.743738 ], "pop" : 257, "state" : "IL" }
+{ "_id" : "62951", "city" : "JOHNSTON CITY", "loc" : [ -88.920858, 37.824477 ], "pop" : 5424, "state" : "IL" }
+{ "_id" : "62952", "city" : "JONESBORO", "loc" : [ -89.291494, 37.446082 ], "pop" : 3383, "state" : "IL" }
+{ "_id" : "62953", "city" : "JOPPA", "loc" : [ -88.84819, 37.247192 ], "pop" : 1687, "state" : "IL" }
+{ "_id" : "62954", "city" : "JUNCTION", "loc" : [ -88.249071, 37.695206 ], "pop" : 581, "state" : "IL" }
+{ "_id" : "62955", "city" : "KARBERS RIDGE", "loc" : [ -88.367893, 37.463071 ], "pop" : 686, "state" : "IL" }
+{ "_id" : "62956", "city" : "KARNAK", "loc" : [ -88.97394300000001, 37.291066 ], "pop" : 710, "state" : "IL" }
+{ "_id" : "62957", "city" : "MC CLURE", "loc" : [ -89.453119, 37.301983 ], "pop" : 1231, "state" : "IL" }
+{ "_id" : "62958", "city" : "MAKANDA", "loc" : [ -89.214232, 37.656396 ], "pop" : 3893, "state" : "IL" }
+{ "_id" : "62959", "city" : "MARION", "loc" : [ -88.929447, 37.725662 ], "pop" : 20722, "state" : "IL" }
+{ "_id" : "62960", "city" : "METROPOLIS", "loc" : [ -88.725179, 37.175348 ], "pop" : 10500, "state" : "IL" }
+{ "_id" : "62961", "city" : "MILLCREEK", "loc" : [ -89.26988900000001, 37.353127 ], "pop" : 356, "state" : "IL" }
+{ "_id" : "62962", "city" : "MILLER CITY", "loc" : [ -89.34944299999999, 37.103359 ], "pop" : 122, "state" : "IL" }
+{ "_id" : "62963", "city" : "MOUND CITY", "loc" : [ -89.163687, 37.086474 ], "pop" : 845, "state" : "IL" }
+{ "_id" : "62964", "city" : "MOUNDS", "loc" : [ -89.200064, 37.11883 ], "pop" : 2064, "state" : "IL" }
+{ "_id" : "62966", "city" : "MURPHYSBORO", "loc" : [ -89.331749, 37.765464 ], "pop" : 15335, "state" : "IL" }
+{ "_id" : "62967", "city" : "NEW BURNSIDE", "loc" : [ -88.771253, 37.580608 ], "pop" : 512, "state" : "IL" }
+{ "_id" : "62970", "city" : "OLMSTED", "loc" : [ -89.093266, 37.193507 ], "pop" : 692, "state" : "IL" }
+{ "_id" : "62972", "city" : "OZARK", "loc" : [ -88.768778, 37.536704 ], "pop" : 463, "state" : "IL" }
+{ "_id" : "62974", "city" : "PITTSBURG", "loc" : [ -88.87039300000001, 37.78387 ], "pop" : 1330, "state" : "IL" }
+{ "_id" : "62975", "city" : "POMONA", "loc" : [ -89.336308, 37.641081 ], "pop" : 769, "state" : "IL" }
+{ "_id" : "62976", "city" : "PULASKI", "loc" : [ -89.19680099999999, 37.214575 ], "pop" : 663, "state" : "IL" }
+{ "_id" : "62977", "city" : "RALEIGH", "loc" : [ -88.53236800000001, 37.825597 ], "pop" : 817, "state" : "IL" }
+{ "_id" : "62979", "city" : "RIDGWAY", "loc" : [ -88.261202, 37.804242 ], "pop" : 1686, "state" : "IL" }
+{ "_id" : "62982", "city" : "ROSICLARE", "loc" : [ -88.346189, 37.423987 ], "pop" : 1422, "state" : "IL" }
+{ "_id" : "62983", "city" : "ROYALTON", "loc" : [ -89.114149, 37.879033 ], "pop" : 1344, "state" : "IL" }
+{ "_id" : "62984", "city" : "SHAWNEETOWN", "loc" : [ -88.17850300000001, 37.713188 ], "pop" : 2400, "state" : "IL" }
+{ "_id" : "62985", "city" : "ROBBS", "loc" : [ -88.76245900000001, 37.463032 ], "pop" : 507, "state" : "IL" }
+{ "_id" : "62987", "city" : "STONEFORT", "loc" : [ -88.742807, 37.62992 ], "pop" : 1255, "state" : "IL" }
+{ "_id" : "62988", "city" : "TAMMS", "loc" : [ -89.276346, 37.234493 ], "pop" : 2020, "state" : "IL" }
+{ "_id" : "62990", "city" : "GALE", "loc" : [ -89.396896, 37.191554 ], "pop" : 1732, "state" : "IL" }
+{ "_id" : "62991", "city" : "TUNNEL HILL", "loc" : [ -88.883459, 37.573676 ], "pop" : 867, "state" : "IL" }
+{ "_id" : "62992", "city" : "ULLIN", "loc" : [ -89.191137, 37.270385 ], "pop" : 787, "state" : "IL" }
+{ "_id" : "62994", "city" : "VERGENNES", "loc" : [ -89.326863, 37.905128 ], "pop" : 681, "state" : "IL" }
+{ "_id" : "62995", "city" : "VIENNA", "loc" : [ -88.88786899999999, 37.420541 ], "pop" : 2767, "state" : "IL" }
+{ "_id" : "62996", "city" : "VILLA RIDGE", "loc" : [ -89.18252200000001, 37.157765 ], "pop" : 736, "state" : "IL" }
+{ "_id" : "62997", "city" : "WILLISVILLE", "loc" : [ -89.578487, 37.982142 ], "pop" : 912, "state" : "IL" }
+{ "_id" : "62998", "city" : "WOLF LAKE", "loc" : [ -89.44076099999999, 37.511985 ], "pop" : 533, "state" : "IL" }
+{ "_id" : "62999", "city" : "ZEIGLER", "loc" : [ -89.06026, 37.906923 ], "pop" : 2502, "state" : "IL" }
+{ "_id" : "63005", "city" : "CHESTERFIELD", "loc" : [ -90.61418500000001, 38.631832 ], "pop" : 7770, "state" : "MO" }
+{ "_id" : "63010", "city" : "ARNOLD", "loc" : [ -90.387046, 38.430484 ], "pop" : 29195, "state" : "MO" }
+{ "_id" : "63011", "city" : "MANCHESTER", "loc" : [ -90.55213000000001, 38.604132 ], "pop" : 36722, "state" : "MO" }
+{ "_id" : "63012", "city" : "BARNHART", "loc" : [ -90.41417, 38.338425 ], "pop" : 7689, "state" : "MO" }
+{ "_id" : "63013", "city" : "BEAUFORT", "loc" : [ -91.170929, 38.429352 ], "pop" : 460, "state" : "MO" }
+{ "_id" : "63014", "city" : "BERGER", "loc" : [ -91.337412, 38.644449 ], "pop" : 1092, "state" : "MO" }
+{ "_id" : "63015", "city" : "CATAWISSA", "loc" : [ -90.761703, 38.436161 ], "pop" : 831, "state" : "MO" }
+{ "_id" : "63016", "city" : "CEDAR HILL", "loc" : [ -90.649777, 38.357319 ], "pop" : 7211, "state" : "MO" }
+{ "_id" : "63017", "city" : "TOWN AND COUNTRY", "loc" : [ -90.53968999999999, 38.647241 ], "pop" : 40848, "state" : "MO" }
+{ "_id" : "63019", "city" : "CRYSTAL CITY", "loc" : [ -90.382525, 38.23002 ], "pop" : 4112, "state" : "MO" }
+{ "_id" : "63020", "city" : "DE SOTO", "loc" : [ -90.554621, 38.120421 ], "pop" : 13331, "state" : "MO" }
+{ "_id" : "63021", "city" : "BALLWIN", "loc" : [ -90.525527, 38.577032 ], "pop" : 46397, "state" : "MO" }
+{ "_id" : "63023", "city" : "DITTMER", "loc" : [ -90.691101, 38.315465 ], "pop" : 2410, "state" : "MO" }
+{ "_id" : "63025", "city" : "CRESCENT", "loc" : [ -90.626277, 38.484832 ], "pop" : 6053, "state" : "MO" }
+{ "_id" : "63026", "city" : "FENTON", "loc" : [ -90.468299, 38.501489 ], "pop" : 38020, "state" : "MO" }
+{ "_id" : "63028", "city" : "FESTUS", "loc" : [ -90.42859, 38.187889 ], "pop" : 22497, "state" : "MO" }
+{ "_id" : "63030", "city" : "FLETCHER", "loc" : [ -90.73445599999999, 38.180141 ], "pop" : 241, "state" : "MO" }
+{ "_id" : "63031", "city" : "FLORISSANT", "loc" : [ -90.340097, 38.806865 ], "pop" : 52659, "state" : "MO" }
+{ "_id" : "63033", "city" : "FLORISSANT", "loc" : [ -90.283062, 38.794711 ], "pop" : 44480, "state" : "MO" }
+{ "_id" : "63034", "city" : "FLORISSANT", "loc" : [ -90.293617, 38.833841 ], "pop" : 13972, "state" : "MO" }
+{ "_id" : "63036", "city" : "FRENCH VILLAGE", "loc" : [ -90.400507, 37.996101 ], "pop" : 697, "state" : "MO" }
+{ "_id" : "63037", "city" : "GERALD", "loc" : [ -91.29306200000001, 38.350719 ], "pop" : 4664, "state" : "MO" }
+{ "_id" : "63038", "city" : "GLENCOE", "loc" : [ -90.64397099999999, 38.5745 ], "pop" : 6093, "state" : "MO" }
+{ "_id" : "63039", "city" : "GRAY SUMMIT", "loc" : [ -90.829184, 38.503044 ], "pop" : 752, "state" : "MO" }
+{ "_id" : "63040", "city" : "GROVER", "loc" : [ -90.646112, 38.573316 ], "pop" : 497, "state" : "MO" }
+{ "_id" : "63042", "city" : "HAZELWOOD", "loc" : [ -90.36692499999999, 38.780875 ], "pop" : 20004, "state" : "MO" }
+{ "_id" : "63043", "city" : "MARYLAND HEIGHTS", "loc" : [ -90.44740299999999, 38.722896 ], "pop" : 21268, "state" : "MO" }
+{ "_id" : "63044", "city" : "BRIDGETON", "loc" : [ -90.416101, 38.750627 ], "pop" : 17695, "state" : "MO" }
+{ "_id" : "63045", "city" : "BRIDGETON", "loc" : [ -90.458062, 38.7561 ], "pop" : 0, "state" : "MO" }
+{ "_id" : "63048", "city" : "HERCULANEUM", "loc" : [ -90.387095, 38.260087 ], "pop" : 2490, "state" : "MO" }
+{ "_id" : "63049", "city" : "HIGH RIDGE", "loc" : [ -90.528127, 38.472783 ], "pop" : 12915, "state" : "MO" }
+{ "_id" : "63050", "city" : "HILLSBORO", "loc" : [ -90.57819600000001, 38.258582 ], "pop" : 14095, "state" : "MO" }
+{ "_id" : "63051", "city" : "HOUSE SPRINGS", "loc" : [ -90.55753900000001, 38.413068 ], "pop" : 10035, "state" : "MO" }
+{ "_id" : "63052", "city" : "ANTONIA", "loc" : [ -90.431134, 38.392733 ], "pop" : 17913, "state" : "MO" }
+{ "_id" : "63055", "city" : "LABADIE", "loc" : [ -90.876966, 38.520031 ], "pop" : 498, "state" : "MO" }
+{ "_id" : "63056", "city" : "LESLIE", "loc" : [ -91.19516400000001, 38.458228 ], "pop" : 1238, "state" : "MO" }
+{ "_id" : "63060", "city" : "LONEDELL", "loc" : [ -90.822216, 38.274982 ], "pop" : 1153, "state" : "MO" }
+{ "_id" : "63061", "city" : "LUEBBERING", "loc" : [ -90.802713, 38.261499 ], "pop" : 224, "state" : "MO" }
+{ "_id" : "63068", "city" : "NEW HAVEN", "loc" : [ -91.22905, 38.573995 ], "pop" : 4353, "state" : "MO" }
+{ "_id" : "63069", "city" : "PACIFIC", "loc" : [ -90.747968, 38.492168 ], "pop" : 12874, "state" : "MO" }
+{ "_id" : "63070", "city" : "PEVELY", "loc" : [ -90.411075, 38.279911 ], "pop" : 5221, "state" : "MO" }
+{ "_id" : "63071", "city" : "RICHWOODS", "loc" : [ -90.83099, 38.149639 ], "pop" : 1079, "state" : "MO" }
+{ "_id" : "63072", "city" : "ROBERTSVILLE", "loc" : [ -90.801619, 38.381602 ], "pop" : 4250, "state" : "MO" }
+{ "_id" : "63074", "city" : "SAINT ANN", "loc" : [ -90.38641800000001, 38.725928 ], "pop" : 16528, "state" : "MO" }
+{ "_id" : "63077", "city" : "SAINT CLAIR", "loc" : [ -90.971346, 38.329927 ], "pop" : 10668, "state" : "MO" }
+{ "_id" : "63080", "city" : "SULLIVAN", "loc" : [ -91.156662, 38.230706 ], "pop" : 7541, "state" : "MO" }
+{ "_id" : "63084", "city" : "UNION", "loc" : [ -91.020596, 38.445629 ], "pop" : 14183, "state" : "MO" }
+{ "_id" : "63088", "city" : "VALLEY PARK", "loc" : [ -90.492422, 38.557619 ], "pop" : 5014, "state" : "MO" }
+{ "_id" : "63089", "city" : "VILLA RIDGE", "loc" : [ -90.882198, 38.460108 ], "pop" : 4954, "state" : "MO" }
+{ "_id" : "63090", "city" : "WASHINGTON", "loc" : [ -91.019346, 38.545851 ], "pop" : 15437, "state" : "MO" }
+{ "_id" : "63091", "city" : "ROSEBUD", "loc" : [ -91.397407, 38.385301 ], "pop" : 607, "state" : "MO" }
+{ "_id" : "63101", "city" : "SAINT LOUIS", "loc" : [ -90.19131299999999, 38.634616 ], "pop" : 931, "state" : "MO" }
+{ "_id" : "63102", "city" : "SAINT LOUIS", "loc" : [ -90.18736, 38.630803 ], "pop" : 731, "state" : "MO" }
+{ "_id" : "63103", "city" : "SAINT LOUIS", "loc" : [ -90.216444, 38.633176 ], "pop" : 6710, "state" : "MO" }
+{ "_id" : "63104", "city" : "SAINT LOUIS", "loc" : [ -90.218512, 38.612819 ], "pop" : 20885, "state" : "MO" }
+{ "_id" : "63105", "city" : "CLAYTON", "loc" : [ -90.324189, 38.642574 ], "pop" : 15732, "state" : "MO" }
+{ "_id" : "63106", "city" : "SAINT LOUIS", "loc" : [ -90.208198, 38.644246 ], "pop" : 15156, "state" : "MO" }
+{ "_id" : "63107", "city" : "SAINT LOUIS", "loc" : [ -90.21249, 38.664522 ], "pop" : 23263, "state" : "MO" }
+{ "_id" : "63108", "city" : "SAINT LOUIS", "loc" : [ -90.254397, 38.644526 ], "pop" : 20993, "state" : "MO" }
+{ "_id" : "63109", "city" : "SAINT LOUIS", "loc" : [ -90.292918, 38.585452 ], "pop" : 30029, "state" : "MO" }
+{ "_id" : "63110", "city" : "SAINT LOUIS", "loc" : [ -90.256381, 38.618534 ], "pop" : 23697, "state" : "MO" }
+{ "_id" : "63111", "city" : "SAINT LOUIS", "loc" : [ -90.24945200000001, 38.563349 ], "pop" : 22733, "state" : "MO" }
+{ "_id" : "63112", "city" : "SAINT LOUIS", "loc" : [ -90.28187, 38.661619 ], "pop" : 28841, "state" : "MO" }
+{ "_id" : "63113", "city" : "SAINT LOUIS", "loc" : [ -90.249633, 38.65896 ], "pop" : 23360, "state" : "MO" }
+{ "_id" : "63114", "city" : "OVERLAND", "loc" : [ -90.363304, 38.704425 ], "pop" : 40522, "state" : "MO" }
+{ "_id" : "63115", "city" : "SAINT LOUIS", "loc" : [ -90.238478, 38.675618 ], "pop" : 30748, "state" : "MO" }
+{ "_id" : "63116", "city" : "SAINT LOUIS", "loc" : [ -90.26254299999999, 38.581356 ], "pop" : 49014, "state" : "MO" }
+{ "_id" : "63117", "city" : "RICHMOND HEIGHTS", "loc" : [ -90.324817, 38.629202 ], "pop" : 10263, "state" : "MO" }
+{ "_id" : "63118", "city" : "SAINT LOUIS", "loc" : [ -90.23091100000001, 38.594265 ], "pop" : 33259, "state" : "MO" }
+{ "_id" : "63119", "city" : "WEBSTER GROVES", "loc" : [ -90.350807, 38.588853 ], "pop" : 33698, "state" : "MO" }
+{ "_id" : "63120", "city" : "SAINT LOUIS", "loc" : [ -90.25945, 38.690914 ], "pop" : 17815, "state" : "MO" }
+{ "_id" : "63121", "city" : "NORMANDY", "loc" : [ -90.296719, 38.705086 ], "pop" : 31649, "state" : "MO" }
+{ "_id" : "63122", "city" : "KIRKWOOD", "loc" : [ -90.410042, 38.58486 ], "pop" : 39452, "state" : "MO" }
+{ "_id" : "63123", "city" : "AFFTON", "loc" : [ -90.325304, 38.550594 ], "pop" : 47127, "state" : "MO" }
+{ "_id" : "63124", "city" : "LADUE", "loc" : [ -90.375468, 38.642383 ], "pop" : 9517, "state" : "MO" }
+{ "_id" : "63125", "city" : "LEMAY", "loc" : [ -90.29590899999999, 38.521899 ], "pop" : 33874, "state" : "MO" }
+{ "_id" : "63126", "city" : "SAPPINGTON", "loc" : [ -90.37867900000001, 38.550349 ], "pop" : 16311, "state" : "MO" }
+{ "_id" : "63127", "city" : "SAPPINGTON", "loc" : [ -90.405967, 38.540369 ], "pop" : 4770, "state" : "MO" }
+{ "_id" : "63128", "city" : "SAPPINGTON", "loc" : [ -90.372275, 38.498285 ], "pop" : 28366, "state" : "MO" }
+{ "_id" : "63129", "city" : "SOUTH COUNTY", "loc" : [ -90.32138999999999, 38.468864 ], "pop" : 45920, "state" : "MO" }
+{ "_id" : "63130", "city" : "UNIVERSITY CITY", "loc" : [ -90.321896, 38.663941 ], "pop" : 33986, "state" : "MO" }
+{ "_id" : "63131", "city" : "DES PERES", "loc" : [ -90.44264, 38.612479 ], "pop" : 16955, "state" : "MO" }
+{ "_id" : "63132", "city" : "OLIVETTE", "loc" : [ -90.369642, 38.672823 ], "pop" : 15193, "state" : "MO" }
+{ "_id" : "63133", "city" : "SAINT LOUIS", "loc" : [ -90.30327200000001, 38.6779 ], "pop" : 11141, "state" : "MO" }
+{ "_id" : "63134", "city" : "BERKELEY", "loc" : [ -90.337834, 38.739614 ], "pop" : 18068, "state" : "MO" }
+{ "_id" : "63135", "city" : "FERGUSON", "loc" : [ -90.302241, 38.748429 ], "pop" : 23173, "state" : "MO" }
+{ "_id" : "63136", "city" : "JENNINGS", "loc" : [ -90.260189, 38.738878 ], "pop" : 54994, "state" : "MO" }
+{ "_id" : "63137", "city" : "NORTH COUNTY", "loc" : [ -90.217778, 38.74885 ], "pop" : 21055, "state" : "MO" }
+{ "_id" : "63138", "city" : "NORTH COUNTY", "loc" : [ -90.21158200000001, 38.787041 ], "pop" : 20801, "state" : "MO" }
+{ "_id" : "63139", "city" : "SAINT LOUIS", "loc" : [ -90.292045, 38.610776 ], "pop" : 25310, "state" : "MO" }
+{ "_id" : "63140", "city" : "BERKELEY", "loc" : [ -90.322846, 38.738482 ], "pop" : 2478, "state" : "MO" }
+{ "_id" : "63141", "city" : "CREVE COEUR", "loc" : [ -90.457072, 38.661741 ], "pop" : 20120, "state" : "MO" }
+{ "_id" : "63143", "city" : "MAPLEWOOD", "loc" : [ -90.31961099999999, 38.613116 ], "pop" : 12025, "state" : "MO" }
+{ "_id" : "63144", "city" : "BRENTWOOD", "loc" : [ -90.350944, 38.620839 ], "pop" : 9770, "state" : "MO" }
+{ "_id" : "63146", "city" : "WEST COUNTY", "loc" : [ -90.448251, 38.688418 ], "pop" : 29946, "state" : "MO" }
+{ "_id" : "63147", "city" : "SAINT LOUIS", "loc" : [ -90.237512, 38.713889 ], "pop" : 13186, "state" : "MO" }
+{ "_id" : "63301", "city" : "SAINT CHARLES", "loc" : [ -90.506503, 38.801424 ], "pop" : 47255, "state" : "MO" }
+{ "_id" : "63303", "city" : "SAINT CHARLES", "loc" : [ -90.547059, 38.762237 ], "pop" : 40675, "state" : "MO" }
+{ "_id" : "63304", "city" : "SAINT CHARLES", "loc" : [ -90.62344299999999, 38.737769 ], "pop" : 27477, "state" : "MO" }
+{ "_id" : "63330", "city" : "ANNADA", "loc" : [ -90.822355, 39.255758 ], "pop" : 199, "state" : "MO" }
+{ "_id" : "63332", "city" : "AUGUSTA", "loc" : [ -90.881471, 38.572767 ], "pop" : 302, "state" : "MO" }
+{ "_id" : "63333", "city" : "BELLFLOWER", "loc" : [ -91.34891500000001, 39.0012 ], "pop" : 689, "state" : "MO" }
+{ "_id" : "63334", "city" : "BOWLING GREEN", "loc" : [ -91.19623199999999, 39.334639 ], "pop" : 5258, "state" : "MO" }
+{ "_id" : "63336", "city" : "CLARKSVILLE", "loc" : [ -90.936205, 39.346477 ], "pop" : 1195, "state" : "MO" }
+{ "_id" : "63339", "city" : "CURRYVILLE", "loc" : [ -91.349301, 39.325702 ], "pop" : 1604, "state" : "MO" }
+{ "_id" : "63341", "city" : "DEFIANCE", "loc" : [ -90.830231, 38.661557 ], "pop" : 2861, "state" : "MO" }
+{ "_id" : "63343", "city" : "ELSBERRY", "loc" : [ -90.815956, 39.158953 ], "pop" : 3739, "state" : "MO" }
+{ "_id" : "63344", "city" : "EOLIA", "loc" : [ -91.009322, 39.243097 ], "pop" : 533, "state" : "MO" }
+{ "_id" : "63345", "city" : "FARBER", "loc" : [ -91.579843, 39.27424 ], "pop" : 546, "state" : "MO" }
+{ "_id" : "63347", "city" : "FOLEY", "loc" : [ -90.777468, 39.053019 ], "pop" : 2518, "state" : "MO" }
+{ "_id" : "63348", "city" : "FORISTELL", "loc" : [ -90.93432799999999, 38.762557 ], "pop" : 2993, "state" : "MO" }
+{ "_id" : "63349", "city" : "HAWK POINT", "loc" : [ -91.121067, 38.976576 ], "pop" : 1550, "state" : "MO" }
+{ "_id" : "63350", "city" : "HIGH HILL", "loc" : [ -91.37147299999999, 38.890238 ], "pop" : 614, "state" : "MO" }
+{ "_id" : "63351", "city" : "JONESBURG", "loc" : [ -91.30193, 38.871658 ], "pop" : 1055, "state" : "MO" }
+{ "_id" : "63352", "city" : "LADDONIA", "loc" : [ -91.689348, 39.259328 ], "pop" : 1023, "state" : "MO" }
+{ "_id" : "63353", "city" : "LOUISIANA", "loc" : [ -91.066385, 39.43359 ], "pop" : 5428, "state" : "MO" }
+{ "_id" : "63357", "city" : "LAKE SHERWOOD", "loc" : [ -91.055459, 38.648619 ], "pop" : 3690, "state" : "MO" }
+{ "_id" : "63359", "city" : "MIDDLETOWN", "loc" : [ -91.38731199999999, 39.105494 ], "pop" : 853, "state" : "MO" }
+{ "_id" : "63361", "city" : "MONTGOMERY CITY", "loc" : [ -91.508486, 38.983949 ], "pop" : 3160, "state" : "MO" }
+{ "_id" : "63362", "city" : "MOSCOW MILLS", "loc" : [ -90.96300100000001, 38.922927 ], "pop" : 3538, "state" : "MO" }
+{ "_id" : "63363", "city" : "NEW FLORENCE", "loc" : [ -91.490861, 38.902309 ], "pop" : 1745, "state" : "MO" }
+{ "_id" : "63364", "city" : "NEW HARTFORD", "loc" : [ -91.292984, 39.188103 ], "pop" : 503, "state" : "MO" }
+{ "_id" : "63366", "city" : "SAINT PAUL", "loc" : [ -90.720159, 38.800101 ], "pop" : 28243, "state" : "MO" }
+{ "_id" : "63367", "city" : "LAKE SAINT LOUIS", "loc" : [ -90.78540700000001, 38.79355 ], "pop" : 7785, "state" : "MO" }
+{ "_id" : "63369", "city" : "OLD MONROE", "loc" : [ -90.77819599999999, 38.934581 ], "pop" : 1591, "state" : "MO" }
+{ "_id" : "63370", "city" : "OLNEY", "loc" : [ -91.211314, 39.087509 ], "pop" : 351, "state" : "MO" }
+{ "_id" : "63371", "city" : "PAYNESVILLE", "loc" : [ -90.907268, 39.258679 ], "pop" : 182, "state" : "MO" }
+{ "_id" : "63373", "city" : "PORTAGE DES SIOU", "loc" : [ -90.353115, 38.927629 ], "pop" : 777, "state" : "MO" }
+{ "_id" : "63376", "city" : "SAINT PETERS", "loc" : [ -90.622765, 38.78024 ], "pop" : 43133, "state" : "MO" }
+{ "_id" : "63377", "city" : "SILEX", "loc" : [ -91.03698799999999, 39.116617 ], "pop" : 2913, "state" : "MO" }
+{ "_id" : "63379", "city" : "TROY", "loc" : [ -90.96244900000001, 39.001212 ], "pop" : 7636, "state" : "MO" }
+{ "_id" : "63381", "city" : "TRUXTON", "loc" : [ -91.21261800000001, 38.967002 ], "pop" : 794, "state" : "MO" }
+{ "_id" : "63382", "city" : "VANDALIA", "loc" : [ -91.488299, 39.294937 ], "pop" : 3441, "state" : "MO" }
+{ "_id" : "63383", "city" : "WARRENTON", "loc" : [ -91.174047, 38.805042 ], "pop" : 9464, "state" : "MO" }
+{ "_id" : "63384", "city" : "WELLSVILLE", "loc" : [ -91.564519, 39.076482 ], "pop" : 1899, "state" : "MO" }
+{ "_id" : "63385", "city" : "WENTZVILLE", "loc" : [ -90.85344000000001, 38.801963 ], "pop" : 10238, "state" : "MO" }
+{ "_id" : "63386", "city" : "WEST ALTON", "loc" : [ -90.23836300000001, 38.875796 ], "pop" : 1172, "state" : "MO" }
+{ "_id" : "63388", "city" : "WILLIAMSBURG", "loc" : [ -91.679188, 38.898143 ], "pop" : 228, "state" : "MO" }
+{ "_id" : "63389", "city" : "WINFIELD", "loc" : [ -90.821319, 38.989727 ], "pop" : 4791, "state" : "MO" }
+{ "_id" : "63390", "city" : "WRIGHT CITY", "loc" : [ -91.03292999999999, 38.809677 ], "pop" : 5852, "state" : "MO" }
+{ "_id" : "63401", "city" : "HANNIBAL", "loc" : [ -91.38387, 39.70636 ], "pop" : 20086, "state" : "MO" }
+{ "_id" : "63430", "city" : "ALEXANDRIA", "loc" : [ -91.51543700000001, 40.344514 ], "pop" : 753, "state" : "MO" }
+{ "_id" : "63431", "city" : "ANABEL", "loc" : [ -92.351142, 39.736793 ], "pop" : 289, "state" : "MO" }
+{ "_id" : "63432", "city" : "ARBELA", "loc" : [ -92.004741, 40.486299 ], "pop" : 564, "state" : "MO" }
+{ "_id" : "63433", "city" : "ASHBURN", "loc" : [ -91.187651, 39.52904 ], "pop" : 235, "state" : "MO" }
+{ "_id" : "63434", "city" : "BETHEL", "loc" : [ -92.03161900000001, 39.892199 ], "pop" : 377, "state" : "MO" }
+{ "_id" : "63435", "city" : "CANTON", "loc" : [ -91.54798700000001, 40.143695 ], "pop" : 3822, "state" : "MO" }
+{ "_id" : "63436", "city" : "CENTER", "loc" : [ -91.53984199999999, 39.515397 ], "pop" : 971, "state" : "MO" }
+{ "_id" : "63437", "city" : "CLARENCE", "loc" : [ -92.25297, 39.736648 ], "pop" : 1600, "state" : "MO" }
+{ "_id" : "63438", "city" : "DURHAM", "loc" : [ -91.67041500000001, 39.962486 ], "pop" : 548, "state" : "MO" }
+{ "_id" : "63439", "city" : "EMDEN", "loc" : [ -91.880926, 39.85013 ], "pop" : 364, "state" : "MO" }
+{ "_id" : "63440", "city" : "EWING", "loc" : [ -91.721627, 39.996237 ], "pop" : 1142, "state" : "MO" }
+{ "_id" : "63441", "city" : "FRANKFORD", "loc" : [ -91.30308599999999, 39.489246 ], "pop" : 831, "state" : "MO" }
+{ "_id" : "63443", "city" : "HUNNEWELL", "loc" : [ -91.88323099999999, 39.701831 ], "pop" : 528, "state" : "MO" }
+{ "_id" : "63445", "city" : "KAHOKA", "loc" : [ -91.725033, 40.426576 ], "pop" : 3922, "state" : "MO" }
+{ "_id" : "63446", "city" : "KNOX CITY", "loc" : [ -92.00770300000001, 40.138357 ], "pop" : 547, "state" : "MO" }
+{ "_id" : "63447", "city" : "LA BELLE", "loc" : [ -91.917125, 40.116383 ], "pop" : 893, "state" : "MO" }
+{ "_id" : "63448", "city" : "LA GRANGE", "loc" : [ -91.518247, 40.039126 ], "pop" : 1715, "state" : "MO" }
+{ "_id" : "63450", "city" : "LENTNER", "loc" : [ -92.148916, 39.712269 ], "pop" : 198, "state" : "MO" }
+{ "_id" : "63451", "city" : "LEONARD", "loc" : [ -92.19467899999999, 39.907577 ], "pop" : 312, "state" : "MO" }
+{ "_id" : "63452", "city" : "LEWISTOWN", "loc" : [ -91.815663, 40.086666 ], "pop" : 824, "state" : "MO" }
+{ "_id" : "63453", "city" : "LURAY", "loc" : [ -91.891227, 40.493096 ], "pop" : 523, "state" : "MO" }
+{ "_id" : "63454", "city" : "MAYWOOD", "loc" : [ -91.614769, 39.933289 ], "pop" : 939, "state" : "MO" }
+{ "_id" : "63456", "city" : "MONROE CITY", "loc" : [ -91.722999, 39.654586 ], "pop" : 4039, "state" : "MO" }
+{ "_id" : "63457", "city" : "MONTICELLO", "loc" : [ -91.712267, 40.10402 ], "pop" : 515, "state" : "MO" }
+{ "_id" : "63458", "city" : "NEWARK", "loc" : [ -91.99236000000001, 39.997428 ], "pop" : 195, "state" : "MO" }
+{ "_id" : "63459", "city" : "NEW LONDON", "loc" : [ -91.39599, 39.591672 ], "pop" : 4801, "state" : "MO" }
+{ "_id" : "63460", "city" : "NOVELTY", "loc" : [ -92.24378299999999, 40.035997 ], "pop" : 542, "state" : "MO" }
+{ "_id" : "63461", "city" : "PALMYRA", "loc" : [ -91.536817, 39.791309 ], "pop" : 5344, "state" : "MO" }
+{ "_id" : "63462", "city" : "PERRY", "loc" : [ -91.664125, 39.420721 ], "pop" : 1268, "state" : "MO" }
+{ "_id" : "63463", "city" : "PHILADELPHIA", "loc" : [ -91.753803, 39.835931 ], "pop" : 674, "state" : "MO" }
+{ "_id" : "63464", "city" : "PLEVNA", "loc" : [ -92.111716, 39.992561 ], "pop" : 149, "state" : "MO" }
+{ "_id" : "63466", "city" : "SAINT PATRICK", "loc" : [ -91.65467700000001, 40.319851 ], "pop" : 455, "state" : "MO" }
+{ "_id" : "63468", "city" : "SHELBINA", "loc" : [ -92.03706, 39.694718 ], "pop" : 2714, "state" : "MO" }
+{ "_id" : "63469", "city" : "SHELBYVILLE", "loc" : [ -92.04978199999999, 39.810792 ], "pop" : 929, "state" : "MO" }
+{ "_id" : "63470", "city" : "STEFFENVILLE", "loc" : [ -91.85945, 39.993976 ], "pop" : 310, "state" : "MO" }
+{ "_id" : "63471", "city" : "TAYLOR", "loc" : [ -91.527834, 39.914486 ], "pop" : 667, "state" : "MO" }
+{ "_id" : "63472", "city" : "WAYLAND", "loc" : [ -91.60786400000001, 40.442574 ], "pop" : 1252, "state" : "MO" }
+{ "_id" : "63473", "city" : "WILLIAMSTOWN", "loc" : [ -91.854809, 40.21559 ], "pop" : 343, "state" : "MO" }
+{ "_id" : "63474", "city" : "WYACONDA", "loc" : [ -91.907077, 40.372083 ], "pop" : 642, "state" : "MO" }
+{ "_id" : "63501", "city" : "KIRKSVILLE", "loc" : [ -92.585634, 40.190765 ], "pop" : 20717, "state" : "MO" }
+{ "_id" : "63530", "city" : "ATLANTA", "loc" : [ -92.475019, 39.914639 ], "pop" : 977, "state" : "MO" }
+{ "_id" : "63531", "city" : "BARING", "loc" : [ -92.23107400000001, 40.250864 ], "pop" : 440, "state" : "MO" }
+{ "_id" : "63532", "city" : "BEVIER", "loc" : [ -92.561925, 39.749707 ], "pop" : 1273, "state" : "MO" }
+{ "_id" : "63533", "city" : "BRASHEAR", "loc" : [ -92.43325299999999, 40.195891 ], "pop" : 1444, "state" : "MO" }
+{ "_id" : "63534", "city" : "CALLAO", "loc" : [ -92.635144, 39.744849 ], "pop" : 878, "state" : "MO" }
+{ "_id" : "63535", "city" : "COATSVILLE", "loc" : [ -92.638801, 40.566473 ], "pop" : 148, "state" : "MO" }
+{ "_id" : "63536", "city" : "DOWNING", "loc" : [ -92.391762, 40.479828 ], "pop" : 953, "state" : "MO" }
+{ "_id" : "63537", "city" : "EDINA", "loc" : [ -92.145549, 40.179452 ], "pop" : 2101, "state" : "MO" }
+{ "_id" : "63538", "city" : "ELMER", "loc" : [ -92.642413, 39.941456 ], "pop" : 308, "state" : "MO" }
+{ "_id" : "63539", "city" : "ETHEL", "loc" : [ -92.766396, 39.914605 ], "pop" : 374, "state" : "MO" }
+{ "_id" : "63540", "city" : "GIBBS", "loc" : [ -92.443495, 40.083962 ], "pop" : 389, "state" : "MO" }
+{ "_id" : "63541", "city" : "GLENWOOD", "loc" : [ -92.58864199999999, 40.514935 ], "pop" : 333, "state" : "MO" }
+{ "_id" : "63543", "city" : "GORIN", "loc" : [ -92.01397, 40.362217 ], "pop" : 428, "state" : "MO" }
+{ "_id" : "63544", "city" : "GREEN CASTLE", "loc" : [ -92.877966, 40.270325 ], "pop" : 335, "state" : "MO" }
+{ "_id" : "63545", "city" : "GREEN CITY", "loc" : [ -92.953244, 40.260125 ], "pop" : 1189, "state" : "MO" }
+{ "_id" : "63546", "city" : "GREENTOP", "loc" : [ -92.55667, 40.344593 ], "pop" : 859, "state" : "MO" }
+{ "_id" : "63547", "city" : "HURDLAND", "loc" : [ -92.279066, 40.160909 ], "pop" : 508, "state" : "MO" }
+{ "_id" : "63548", "city" : "LANCASTER", "loc" : [ -92.526403, 40.525265 ], "pop" : 1060, "state" : "MO" }
+{ "_id" : "63549", "city" : "LA PLATA", "loc" : [ -92.50766900000001, 40.020831 ], "pop" : 2022, "state" : "MO" }
+{ "_id" : "63551", "city" : "LIVONIA", "loc" : [ -92.724084, 40.511237 ], "pop" : 398, "state" : "MO" }
+{ "_id" : "63552", "city" : "MACON", "loc" : [ -92.462163, 39.748089 ], "pop" : 7557, "state" : "MO" }
+{ "_id" : "63555", "city" : "MEMPHIS", "loc" : [ -92.18508300000001, 40.46191 ], "pop" : 3546, "state" : "MO" }
+{ "_id" : "63556", "city" : "MILAN", "loc" : [ -93.136149, 40.184435 ], "pop" : 3171, "state" : "MO" }
+{ "_id" : "63557", "city" : "NEW BOSTON", "loc" : [ -92.91596699999999, 39.933234 ], "pop" : 184, "state" : "MO" }
+{ "_id" : "63558", "city" : "NEW CAMBRIA", "loc" : [ -92.769469, 39.75509 ], "pop" : 953, "state" : "MO" }
+{ "_id" : "63559", "city" : "NOVINGER", "loc" : [ -92.717236, 40.268513 ], "pop" : 1770, "state" : "MO" }
+{ "_id" : "63560", "city" : "POLLOCK", "loc" : [ -93.11150600000001, 40.33852 ], "pop" : 638, "state" : "MO" }
+{ "_id" : "63561", "city" : "QUEEN CITY", "loc" : [ -92.56626300000001, 40.415175 ], "pop" : 1269, "state" : "MO" }
+{ "_id" : "63563", "city" : "RUTLEDGE", "loc" : [ -92.097559, 40.328984 ], "pop" : 284, "state" : "MO" }
+{ "_id" : "63565", "city" : "UNIONVILLE", "loc" : [ -92.99509399999999, 40.481464 ], "pop" : 3515, "state" : "MO" }
+{ "_id" : "63566", "city" : "WINIGAN", "loc" : [ -92.93007, 40.03706 ], "pop" : 335, "state" : "MO" }
+{ "_id" : "63567", "city" : "WORTHINGTON", "loc" : [ -92.740139, 40.424001 ], "pop" : 438, "state" : "MO" }
+{ "_id" : "63601", "city" : "DESLOGE", "loc" : [ -90.52735, 37.85555 ], "pop" : 14716, "state" : "MO" }
+{ "_id" : "63620", "city" : "ANNAPOLIS", "loc" : [ -90.67023500000001, 37.39809 ], "pop" : 1282, "state" : "MO" }
+{ "_id" : "63621", "city" : "ARCADIA", "loc" : [ -90.59276800000001, 37.570054 ], "pop" : 896, "state" : "MO" }
+{ "_id" : "63622", "city" : "BELGRADE", "loc" : [ -90.86130799999999, 37.78886 ], "pop" : 1000, "state" : "MO" }
+{ "_id" : "63623", "city" : "BELLEVIEW", "loc" : [ -90.799075, 37.681981 ], "pop" : 1206, "state" : "MO" }
+{ "_id" : "63624", "city" : "DESLOGE", "loc" : [ -90.620732, 37.769865 ], "pop" : 2282, "state" : "MO" }
+{ "_id" : "63625", "city" : "BLACK", "loc" : [ -90.99173500000001, 37.547275 ], "pop" : 671, "state" : "MO" }
+{ "_id" : "63626", "city" : "BLACKWELL", "loc" : [ -90.70953799999999, 38.071694 ], "pop" : 1012, "state" : "MO" }
+{ "_id" : "63627", "city" : "BLOOMSDALE", "loc" : [ -90.280548, 38.045112 ], "pop" : 3035, "state" : "MO" }
+{ "_id" : "63628", "city" : "BONNE TERRE", "loc" : [ -90.525052, 37.931423 ], "pop" : 10579, "state" : "MO" }
+{ "_id" : "63629", "city" : "BUNKER", "loc" : [ -91.192735, 37.477227 ], "pop" : 882, "state" : "MO" }
+{ "_id" : "63630", "city" : "CADET", "loc" : [ -90.743932, 38.012534 ], "pop" : 3277, "state" : "MO" }
+{ "_id" : "63631", "city" : "CALEDONIA", "loc" : [ -90.740936, 37.763881 ], "pop" : 808, "state" : "MO" }
+{ "_id" : "63633", "city" : "CENTERVILLE", "loc" : [ -90.975657, 37.428537 ], "pop" : 505, "state" : "MO" }
+{ "_id" : "63636", "city" : "DES ARC", "loc" : [ -90.62787, 37.29546 ], "pop" : 640, "state" : "MO" }
+{ "_id" : "63637", "city" : "DOE RUN", "loc" : [ -90.496842, 37.734818 ], "pop" : 1866, "state" : "MO" }
+{ "_id" : "63638", "city" : "ELLINGTON", "loc" : [ -90.958851, 37.239797 ], "pop" : 3329, "state" : "MO" }
+{ "_id" : "63640", "city" : "FARMINGTON", "loc" : [ -90.40937700000001, 37.777299 ], "pop" : 19031, "state" : "MO" }
+{ "_id" : "63645", "city" : "MILLCREEK", "loc" : [ -90.31052699999999, 37.543716 ], "pop" : 10043, "state" : "MO" }
+{ "_id" : "63648", "city" : "IRONDALE", "loc" : [ -90.69838900000001, 37.82962 ], "pop" : 1793, "state" : "MO" }
+{ "_id" : "63650", "city" : "IRON MOUNTAIN", "loc" : [ -90.63563499999999, 37.614702 ], "pop" : 5610, "state" : "MO" }
+{ "_id" : "63653", "city" : "LEADWOOD", "loc" : [ -90.591007, 37.864081 ], "pop" : 1331, "state" : "MO" }
+{ "_id" : "63654", "city" : "LESTERVILLE", "loc" : [ -90.842544, 37.482004 ], "pop" : 733, "state" : "MO" }
+{ "_id" : "63655", "city" : "MARQUAND", "loc" : [ -90.174092, 37.427403 ], "pop" : 1296, "state" : "MO" }
+{ "_id" : "63656", "city" : "MIDDLE BROOK", "loc" : [ -90.67350399999999, 37.670161 ], "pop" : 509, "state" : "MO" }
+{ "_id" : "63660", "city" : "MINERAL POINT", "loc" : [ -90.719324, 37.915555 ], "pop" : 4032, "state" : "MO" }
+{ "_id" : "63662", "city" : "PATTON", "loc" : [ -90.050045, 37.473347 ], "pop" : 1622, "state" : "MO" }
+{ "_id" : "63664", "city" : "POTOSI", "loc" : [ -90.84146699999999, 37.954942 ], "pop" : 7274, "state" : "MO" }
+{ "_id" : "63665", "city" : "REDFORD", "loc" : [ -90.921994, 37.323518 ], "pop" : 407, "state" : "MO" }
+{ "_id" : "63670", "city" : "LAKE FOREST ESTA", "loc" : [ -90.09604, 37.950356 ], "pop" : 9405, "state" : "MO" }
+{ "_id" : "63673", "city" : "SAINT MARY", "loc" : [ -89.92926799999999, 37.914034 ], "pop" : 130, "state" : "IL" }
+{ "_id" : "63675", "city" : "VULCAN", "loc" : [ -90.71060799999999, 37.305963 ], "pop" : 153, "state" : "MO" }
+{ "_id" : "63701", "city" : "CAPE GIRARDEAU", "loc" : [ -89.545861, 37.31685 ], "pop" : 37993, "state" : "MO" }
+{ "_id" : "63730", "city" : "ADVANCE", "loc" : [ -89.910614, 37.092219 ], "pop" : 2448, "state" : "MO" }
+{ "_id" : "63732", "city" : "NEW WELLS", "loc" : [ -89.581453, 37.630633 ], "pop" : 576, "state" : "MO" }
+{ "_id" : "63733", "city" : "ARAB", "loc" : [ -90.080448, 37.064804 ], "pop" : 139, "state" : "MO" }
+{ "_id" : "63735", "city" : "BELL CITY", "loc" : [ -89.798417, 37.011608 ], "pop" : 1219, "state" : "MO" }
+{ "_id" : "63736", "city" : "BENTON", "loc" : [ -89.56640400000001, 37.069674 ], "pop" : 3349, "state" : "MO" }
+{ "_id" : "63739", "city" : "BURFORDVILLE", "loc" : [ -89.820632, 37.363231 ], "pop" : 819, "state" : "MO" }
+{ "_id" : "63740", "city" : "CHAFFEE", "loc" : [ -89.64565, 37.172612 ], "pop" : 4830, "state" : "MO" }
+{ "_id" : "63743", "city" : "DAISY", "loc" : [ -89.821327, 37.515064 ], "pop" : 100, "state" : "MO" }
+{ "_id" : "63744", "city" : "DELTA", "loc" : [ -89.76085999999999, 37.184417 ], "pop" : 1418, "state" : "MO" }
+{ "_id" : "63747", "city" : "FRIEDHEIM", "loc" : [ -89.837552, 37.566904 ], "pop" : 133, "state" : "MO" }
+{ "_id" : "63748", "city" : "FROHNA", "loc" : [ -89.661903, 37.66855 ], "pop" : 1012, "state" : "MO" }
+{ "_id" : "63750", "city" : "GIPSY", "loc" : [ -90.19407699999999, 37.131092 ], "pop" : 92, "state" : "MO" }
+{ "_id" : "63751", "city" : "GLENALLEN", "loc" : [ -90.051495, 37.323119 ], "pop" : 572, "state" : "MO" }
+{ "_id" : "63753", "city" : "GRASSY", "loc" : [ -90.160838, 37.259347 ], "pop" : 375, "state" : "MO" }
+{ "_id" : "63755", "city" : "JACKSON", "loc" : [ -89.651939, 37.387885 ], "pop" : 14335, "state" : "MO" }
+{ "_id" : "63760", "city" : "LEOPOLD", "loc" : [ -89.922735, 37.260903 ], "pop" : 303, "state" : "MO" }
+{ "_id" : "63763", "city" : "MC GEE", "loc" : [ -90.19084700000001, 37.044139 ], "pop" : 308, "state" : "MO" }
+{ "_id" : "63764", "city" : "SCOPUS", "loc" : [ -89.962732, 37.313464 ], "pop" : 5211, "state" : "MO" }
+{ "_id" : "63766", "city" : "MILLERSVILLE", "loc" : [ -89.795035, 37.440138 ], "pop" : 1060, "state" : "MO" }
+{ "_id" : "63769", "city" : "OAK RIDGE", "loc" : [ -89.750818, 37.525787 ], "pop" : 1184, "state" : "MO" }
+{ "_id" : "63770", "city" : "OLD APPLETON", "loc" : [ -89.70709100000001, 37.583014 ], "pop" : 200, "state" : "MO" }
+{ "_id" : "63771", "city" : "ORAN", "loc" : [ -89.67336400000001, 37.086977 ], "pop" : 1827, "state" : "MO" }
+{ "_id" : "63775", "city" : "PERRYVILLE", "loc" : [ -89.87366400000001, 37.717437 ], "pop" : 13296, "state" : "MO" }
+{ "_id" : "63780", "city" : "SCOTT CITY", "loc" : [ -89.518081, 37.20771 ], "pop" : 6340, "state" : "MO" }
+{ "_id" : "63781", "city" : "SEDGEWICKVILLE", "loc" : [ -89.927246, 37.536962 ], "pop" : 772, "state" : "MO" }
+{ "_id" : "63782", "city" : "STURDIVANT", "loc" : [ -90.009215, 37.071011 ], "pop" : 220, "state" : "MO" }
+{ "_id" : "63783", "city" : "UNIONTOWN", "loc" : [ -89.723744, 37.610708 ], "pop" : 440, "state" : "MO" }
+{ "_id" : "63785", "city" : "WHITEWATER", "loc" : [ -89.736338, 37.286495 ], "pop" : 1906, "state" : "MO" }
+{ "_id" : "63786", "city" : "WITTENBERG", "loc" : [ -89.564261, 37.679256 ], "pop" : 140, "state" : "MO" }
+{ "_id" : "63787", "city" : "ZALMA", "loc" : [ -90.075711, 37.13648 ], "pop" : 898, "state" : "MO" }
+{ "_id" : "63801", "city" : "SIKESTON", "loc" : [ -89.58197, 36.891111 ], "pop" : 22618, "state" : "MO" }
+{ "_id" : "63821", "city" : "ARBYRD", "loc" : [ -90.22835499999999, 36.050104 ], "pop" : 891, "state" : "MO" }
+{ "_id" : "63822", "city" : "BERNIE", "loc" : [ -89.987758, 36.672703 ], "pop" : 3200, "state" : "MO" }
+{ "_id" : "63823", "city" : "BERTRAND", "loc" : [ -89.44825899999999, 36.892746 ], "pop" : 1455, "state" : "MO" }
+{ "_id" : "63825", "city" : "BLOOMFIELD", "loc" : [ -89.945564, 36.898892 ], "pop" : 5938, "state" : "MO" }
+{ "_id" : "63827", "city" : "BRAGG CITY", "loc" : [ -89.87362400000001, 36.273236 ], "pop" : 711, "state" : "MO" }
+{ "_id" : "63829", "city" : "CARDWELL", "loc" : [ -90.290696, 36.04345 ], "pop" : 1552, "state" : "MO" }
+{ "_id" : "63830", "city" : "CARUTHERSVILLE", "loc" : [ -89.668306, 36.180237 ], "pop" : 8376, "state" : "MO" }
+{ "_id" : "63833", "city" : "CATRON", "loc" : [ -89.770647, 36.687578 ], "pop" : 174, "state" : "MO" }
+{ "_id" : "63834", "city" : "CHARLESTON", "loc" : [ -89.33420700000001, 36.921341 ], "pop" : 7209, "state" : "MO" }
+{ "_id" : "63837", "city" : "CLARKTON", "loc" : [ -89.972852, 36.447812 ], "pop" : 1672, "state" : "MO" }
+{ "_id" : "63841", "city" : "DEXTER", "loc" : [ -89.963933, 36.788458 ], "pop" : 11641, "state" : "MO" }
+{ "_id" : "63845", "city" : "EAST PRAIRIE", "loc" : [ -89.372629, 36.777609 ], "pop" : 6184, "state" : "MO" }
+{ "_id" : "63846", "city" : "ESSEX", "loc" : [ -89.83664899999999, 36.810859 ], "pop" : 1212, "state" : "MO" }
+{ "_id" : "63848", "city" : "GIDEON", "loc" : [ -89.913546, 36.45378 ], "pop" : 1599, "state" : "MO" }
+{ "_id" : "63849", "city" : "GOBLER", "loc" : [ -89.934907, 36.158987 ], "pop" : 144, "state" : "MO" }
+{ "_id" : "63851", "city" : "HAYTI HEIGHTS", "loc" : [ -89.75160700000001, 36.239475 ], "pop" : 5073, "state" : "MO" }
+{ "_id" : "63852", "city" : "HOLCOMB", "loc" : [ -90.02079500000001, 36.38846 ], "pop" : 1335, "state" : "MO" }
+{ "_id" : "63855", "city" : "HORNERSVILLE", "loc" : [ -90.081643, 36.062694 ], "pop" : 1685, "state" : "MO" }
+{ "_id" : "63857", "city" : "KENNETT", "loc" : [ -90.049057, 36.240656 ], "pop" : 12742, "state" : "MO" }
+{ "_id" : "63862", "city" : "LILBOURN", "loc" : [ -89.61124100000001, 36.585313 ], "pop" : 2258, "state" : "MO" }
+{ "_id" : "63863", "city" : "MALDEN", "loc" : [ -89.973679, 36.567209 ], "pop" : 6735, "state" : "MO" }
+{ "_id" : "63866", "city" : "MARSTON", "loc" : [ -89.62881899999999, 36.508448 ], "pop" : 1160, "state" : "MO" }
+{ "_id" : "63867", "city" : "MATTHEWS", "loc" : [ -89.57683299999999, 36.807528 ], "pop" : 2675, "state" : "MO" }
+{ "_id" : "63868", "city" : "MOREHOUSE", "loc" : [ -89.685191, 36.819041 ], "pop" : 1856, "state" : "MO" }
+{ "_id" : "63869", "city" : "NEW MADRID", "loc" : [ -89.53664499999999, 36.607284 ], "pop" : 4289, "state" : "MO" }
+{ "_id" : "63870", "city" : "PARMA", "loc" : [ -89.818971, 36.585629 ], "pop" : 2308, "state" : "MO" }
+{ "_id" : "63873", "city" : "PORTAGEVILLE", "loc" : [ -89.70023399999999, 36.427945 ], "pop" : 5400, "state" : "MO" }
+{ "_id" : "63876", "city" : "SENATH", "loc" : [ -90.163224, 36.132428 ], "pop" : 2234, "state" : "MO" }
+{ "_id" : "63877", "city" : "STEELE", "loc" : [ -89.834585, 36.091528 ], "pop" : 5905, "state" : "MO" }
+{ "_id" : "63879", "city" : "HOMESTOWN", "loc" : [ -89.816362, 36.347215 ], "pop" : 1003, "state" : "MO" }
+{ "_id" : "63901", "city" : "POPLAR BLUFF", "loc" : [ -90.416647, 36.766235 ], "pop" : 31363, "state" : "MO" }
+{ "_id" : "63931", "city" : "BRIAR", "loc" : [ -90.92777, 36.639115 ], "pop" : 617, "state" : "MO" }
+{ "_id" : "63932", "city" : "BROSELEY", "loc" : [ -90.240472, 36.707553 ], "pop" : 2173, "state" : "MO" }
+{ "_id" : "63933", "city" : "CAMPBELL", "loc" : [ -90.082859, 36.519714 ], "pop" : 4358, "state" : "MO" }
+{ "_id" : "63934", "city" : "CLUBB", "loc" : [ -90.359638, 37.2302 ], "pop" : 88, "state" : "MO" }
+{ "_id" : "63935", "city" : "POYNOR", "loc" : [ -90.81953, 36.621094 ], "pop" : 7690, "state" : "MO" }
+{ "_id" : "63936", "city" : "DUDLEY", "loc" : [ -90.120974, 36.810981 ], "pop" : 1061, "state" : "MO" }
+{ "_id" : "63937", "city" : "ELLSINORE", "loc" : [ -90.74853, 36.945263 ], "pop" : 1573, "state" : "MO" }
+{ "_id" : "63939", "city" : "FAIRDEALING", "loc" : [ -90.633515, 36.670404 ], "pop" : 617, "state" : "MO" }
+{ "_id" : "63940", "city" : "FISK", "loc" : [ -90.216758, 36.783625 ], "pop" : 590, "state" : "MO" }
+{ "_id" : "63941", "city" : "FREMONT", "loc" : [ -91.143984, 36.917164 ], "pop" : 570, "state" : "MO" }
+{ "_id" : "63942", "city" : "GATEWOOD", "loc" : [ -91.07033300000001, 36.562608 ], "pop" : 342, "state" : "MO" }
+{ "_id" : "63943", "city" : "GRANDIN", "loc" : [ -90.794175, 36.827961 ], "pop" : 2228, "state" : "MO" }
+{ "_id" : "63944", "city" : "GREENVILLE", "loc" : [ -90.451362, 37.110838 ], "pop" : 1012, "state" : "MO" }
+{ "_id" : "63945", "city" : "HARVIELL", "loc" : [ -90.55830400000001, 36.672318 ], "pop" : 726, "state" : "MO" }
+{ "_id" : "63947", "city" : "HIRAM", "loc" : [ -90.289556, 37.228158 ], "pop" : 467, "state" : "MO" }
+{ "_id" : "63950", "city" : "LODI", "loc" : [ -90.46322499999999, 37.242046 ], "pop" : 52, "state" : "MO" }
+{ "_id" : "63951", "city" : "LOWNDES", "loc" : [ -90.254437, 37.134318 ], "pop" : 101, "state" : "MO" }
+{ "_id" : "63952", "city" : "MILL SPRING", "loc" : [ -90.67462500000001, 37.067477 ], "pop" : 732, "state" : "MO" }
+{ "_id" : "63953", "city" : "NAYLOR", "loc" : [ -90.612354, 36.584337 ], "pop" : 1390, "state" : "MO" }
+{ "_id" : "63954", "city" : "NEELYVILLE", "loc" : [ -90.49949100000001, 36.571005 ], "pop" : 1556, "state" : "MO" }
+{ "_id" : "63955", "city" : "OXLY", "loc" : [ -90.691973, 36.587385 ], "pop" : 596, "state" : "MO" }
+{ "_id" : "63956", "city" : "PATTERSON", "loc" : [ -90.57717100000001, 37.195992 ], "pop" : 1378, "state" : "MO" }
+{ "_id" : "63957", "city" : "PIEDMONT", "loc" : [ -90.69902, 37.15727 ], "pop" : 3719, "state" : "MO" }
+{ "_id" : "63960", "city" : "PUXICO", "loc" : [ -90.16225799999999, 36.942163 ], "pop" : 2085, "state" : "MO" }
+{ "_id" : "63961", "city" : "QULIN", "loc" : [ -90.261674, 36.581769 ], "pop" : 1646, "state" : "MO" }
+{ "_id" : "63963", "city" : "SHOOK", "loc" : [ -90.30059, 37.076976 ], "pop" : 222, "state" : "MO" }
+{ "_id" : "63964", "city" : "SILVA", "loc" : [ -90.437472, 37.211892 ], "pop" : 933, "state" : "MO" }
+{ "_id" : "63965", "city" : "VAN BUREN", "loc" : [ -91.000681, 37.00153 ], "pop" : 2417, "state" : "MO" }
+{ "_id" : "63966", "city" : "WAPPAPELLO", "loc" : [ -90.28480500000001, 36.976566 ], "pop" : 1353, "state" : "MO" }
+{ "_id" : "63967", "city" : "WILLIAMSVILLE", "loc" : [ -90.48785100000001, 36.963789 ], "pop" : 1657, "state" : "MO" }
+{ "_id" : "64001", "city" : "ALMA", "loc" : [ -93.54285299999999, 39.10484 ], "pop" : 718, "state" : "MO" }
+{ "_id" : "64011", "city" : "BATES CITY", "loc" : [ -94.07984, 39.021887 ], "pop" : 1393, "state" : "MO" }
+{ "_id" : "64012", "city" : "BELTON", "loc" : [ -94.532785, 38.816118 ], "pop" : 20208, "state" : "MO" }
+{ "_id" : "64014", "city" : "BLUE SPRINGS", "loc" : [ -94.260429, 39.015186 ], "pop" : 19140, "state" : "MO" }
+{ "_id" : "64015", "city" : "LAKE TAPAWINGO", "loc" : [ -94.29284800000001, 39.018378 ], "pop" : 23758, "state" : "MO" }
+{ "_id" : "64016", "city" : "BUCKNER", "loc" : [ -94.206219, 39.130328 ], "pop" : 4156, "state" : "MO" }
+{ "_id" : "64017", "city" : "CAMDEN", "loc" : [ -94.025913, 39.204806 ], "pop" : 641, "state" : "MO" }
+{ "_id" : "64018", "city" : "CAMDEN POINT", "loc" : [ -94.744438, 39.451549 ], "pop" : 678, "state" : "MO" }
+{ "_id" : "64019", "city" : "CENTERVIEW", "loc" : [ -93.870234, 38.78971 ], "pop" : 1890, "state" : "MO" }
+{ "_id" : "64020", "city" : "CONCORDIA", "loc" : [ -93.581205, 38.977553 ], "pop" : 3240, "state" : "MO" }
+{ "_id" : "64021", "city" : "CORDER", "loc" : [ -93.639127, 39.102401 ], "pop" : 649, "state" : "MO" }
+{ "_id" : "64022", "city" : "DOVER", "loc" : [ -93.66837700000001, 39.192619 ], "pop" : 512, "state" : "MO" }
+{ "_id" : "64024", "city" : "EXCELSIOR SPRING", "loc" : [ -94.223614, 39.33491 ], "pop" : 18308, "state" : "MO" }
+{ "_id" : "64029", "city" : "GRAIN VALLEY", "loc" : [ -94.20874000000001, 39.027361 ], "pop" : 2865, "state" : "MO" }
+{ "_id" : "64030", "city" : "GRANDVIEW", "loc" : [ -94.52054200000001, 38.881936 ], "pop" : 24926, "state" : "MO" }
+{ "_id" : "64034", "city" : "LAKE WINNEBAGO", "loc" : [ -94.334767, 38.842813 ], "pop" : 5578, "state" : "MO" }
+{ "_id" : "64035", "city" : "HARDIN", "loc" : [ -93.840869, 39.350433 ], "pop" : 2019, "state" : "MO" }
+{ "_id" : "64036", "city" : "HENRIETTA", "loc" : [ -93.93687300000001, 39.236732 ], "pop" : 438, "state" : "MO" }
+{ "_id" : "64037", "city" : "HIGGINSVILLE", "loc" : [ -93.71326500000001, 39.070504 ], "pop" : 5994, "state" : "MO" }
+{ "_id" : "64040", "city" : "HOLDEN", "loc" : [ -93.98557099999999, 38.718595 ], "pop" : 3088, "state" : "MO" }
+{ "_id" : "64048", "city" : "HOLT", "loc" : [ -94.368876, 39.428867 ], "pop" : 1712, "state" : "MO" }
+{ "_id" : "64050", "city" : "INDEPENDENCE", "loc" : [ -94.411072, 39.098288 ], "pop" : 24188, "state" : "MO" }
+{ "_id" : "64052", "city" : "INDEPENDENCE", "loc" : [ -94.449945, 39.074984 ], "pop" : 22793, "state" : "MO" }
+{ "_id" : "64053", "city" : "INDEPENDENCE", "loc" : [ -94.462461, 39.105041 ], "pop" : 6152, "state" : "MO" }
+{ "_id" : "64054", "city" : "SUGAR CREEK", "loc" : [ -94.441496, 39.107234 ], "pop" : 4574, "state" : "MO" }
+{ "_id" : "64055", "city" : "INDEPENDENCE", "loc" : [ -94.403902, 39.054504 ], "pop" : 30654, "state" : "MO" }
+{ "_id" : "64056", "city" : "INDEPENDENCE", "loc" : [ -94.35963700000001, 39.11773 ], "pop" : 14962, "state" : "MO" }
+{ "_id" : "64057", "city" : "INDEPENDENCE", "loc" : [ -94.353284, 39.073099 ], "pop" : 9209, "state" : "MO" }
+{ "_id" : "64058", "city" : "INDEPENDENCE", "loc" : [ -94.35152600000001, 39.141233 ], "pop" : 5752, "state" : "MO" }
+{ "_id" : "64060", "city" : "KEARNEY", "loc" : [ -94.362104, 39.365175 ], "pop" : 4419, "state" : "MO" }
+{ "_id" : "64061", "city" : "KINGSVILLE", "loc" : [ -94.046188, 38.817755 ], "pop" : 3447, "state" : "MO" }
+{ "_id" : "64062", "city" : "LAWSON", "loc" : [ -94.19658800000001, 39.440129 ], "pop" : 4898, "state" : "MO" }
+{ "_id" : "64063", "city" : "LAKE LOTAWANA", "loc" : [ -94.348744, 38.921094 ], "pop" : 30114, "state" : "MO" }
+{ "_id" : "64064", "city" : "LEES SUMMIT", "loc" : [ -94.36519199999999, 38.995336 ], "pop" : 10649, "state" : "MO" }
+{ "_id" : "64067", "city" : "LEXINGTON", "loc" : [ -93.871438, 39.174249 ], "pop" : 6294, "state" : "MO" }
+{ "_id" : "64068", "city" : "PLEASANT VALLEY", "loc" : [ -94.43366399999999, 39.241916 ], "pop" : 25473, "state" : "MO" }
+{ "_id" : "64070", "city" : "LONE JACK", "loc" : [ -94.16145299999999, 38.891837 ], "pop" : 1918, "state" : "MO" }
+{ "_id" : "64071", "city" : "MAYVIEW", "loc" : [ -93.835306, 39.045898 ], "pop" : 746, "state" : "MO" }
+{ "_id" : "64074", "city" : "NAPOLEON", "loc" : [ -94.070911, 39.114034 ], "pop" : 545, "state" : "MO" }
+{ "_id" : "64075", "city" : "OAK GROVE", "loc" : [ -94.13994599999999, 38.998456 ], "pop" : 7851, "state" : "MO" }
+{ "_id" : "64076", "city" : "ODESSA", "loc" : [ -93.975731, 38.982938 ], "pop" : 8790, "state" : "MO" }
+{ "_id" : "64077", "city" : "ORRICK", "loc" : [ -94.123863, 39.211577 ], "pop" : 1186, "state" : "MO" }
+{ "_id" : "64078", "city" : "PECULIAR", "loc" : [ -94.44053, 38.716453 ], "pop" : 5207, "state" : "MO" }
+{ "_id" : "64079", "city" : "PLATTE CITY", "loc" : [ -94.788972, 39.360171 ], "pop" : 4280, "state" : "MO" }
+{ "_id" : "64080", "city" : "PLEASANT HILL", "loc" : [ -94.243961, 38.785856 ], "pop" : 6057, "state" : "MO" }
+{ "_id" : "64081", "city" : "LEES SUMMIT", "loc" : [ -94.407302, 38.914169 ], "pop" : 9637, "state" : "MO" }
+{ "_id" : "64082", "city" : "LEES SUMMIT", "loc" : [ -94.394368, 38.851803 ], "pop" : 2580, "state" : "MO" }
+{ "_id" : "64083", "city" : "RAYMORE", "loc" : [ -94.452893, 38.801896 ], "pop" : 8112, "state" : "MO" }
+{ "_id" : "64084", "city" : "RAYVILLE", "loc" : [ -94.02840999999999, 39.385291 ], "pop" : 1727, "state" : "MO" }
+{ "_id" : "64085", "city" : "RICHMOND", "loc" : [ -93.979163, 39.279298 ], "pop" : 7080, "state" : "MO" }
+{ "_id" : "64088", "city" : "SIBLEY", "loc" : [ -94.19901900000001, 39.162658 ], "pop" : 1527, "state" : "MO" }
+{ "_id" : "64089", "city" : "SMITHVILLE", "loc" : [ -94.55923900000001, 39.391739 ], "pop" : 3469, "state" : "MO" }
+{ "_id" : "64093", "city" : "WARRENSBURG", "loc" : [ -93.727341, 38.766695 ], "pop" : 21993, "state" : "MO" }
+{ "_id" : "64096", "city" : "WAVERLY", "loc" : [ -93.52565199999999, 39.205523 ], "pop" : 1036, "state" : "MO" }
+{ "_id" : "64097", "city" : "WELLINGTON", "loc" : [ -93.985513, 39.125845 ], "pop" : 1167, "state" : "MO" }
+{ "_id" : "64098", "city" : "WESTON", "loc" : [ -94.91445299999999, 39.445294 ], "pop" : 3269, "state" : "MO" }
+{ "_id" : "64101", "city" : "KANSAS CITY", "loc" : [ -94.601849, 39.10005 ], "pop" : 0, "state" : "MO" }
+{ "_id" : "64102", "city" : "KANSAS CITY", "loc" : [ -94.606596, 39.086067 ], "pop" : 0, "state" : "MO" }
+{ "_id" : "64105", "city" : "KANSAS CITY", "loc" : [ -94.590092, 39.102459 ], "pop" : 1733, "state" : "MO" }
+{ "_id" : "64106", "city" : "KANSAS CITY", "loc" : [ -94.569858, 39.105186 ], "pop" : 7323, "state" : "MO" }
+{ "_id" : "64108", "city" : "KANSAS CITY", "loc" : [ -94.586826, 39.0837 ], "pop" : 7167, "state" : "MO" }
+{ "_id" : "64109", "city" : "KANSAS CITY", "loc" : [ -94.56737200000001, 39.066286 ], "pop" : 13553, "state" : "MO" }
+{ "_id" : "64110", "city" : "KANSAS CITY", "loc" : [ -94.57220599999999, 39.036088 ], "pop" : 19532, "state" : "MO" }
+{ "_id" : "64111", "city" : "KANSAS CITY", "loc" : [ -94.59294199999999, 39.056483 ], "pop" : 19929, "state" : "MO" }
+{ "_id" : "64112", "city" : "KANSAS CITY", "loc" : [ -94.592873, 39.038191 ], "pop" : 8891, "state" : "MO" }
+{ "_id" : "64113", "city" : "KANSAS CITY", "loc" : [ -94.593828, 39.01234 ], "pop" : 11744, "state" : "MO" }
+{ "_id" : "64114", "city" : "KANSAS CITY", "loc" : [ -94.595941, 38.962147 ], "pop" : 24416, "state" : "MO" }
+{ "_id" : "64116", "city" : "NORTH KANSAS CIT", "loc" : [ -94.56988200000001, 39.163189 ], "pop" : 14697, "state" : "MO" }
+{ "_id" : "64117", "city" : "RANDOLPH", "loc" : [ -94.527367, 39.168111 ], "pop" : 14295, "state" : "MO" }
+{ "_id" : "64118", "city" : "GLADSTONE", "loc" : [ -94.570448, 39.213842 ], "pop" : 35772, "state" : "MO" }
+{ "_id" : "64119", "city" : "KANSAS CITY", "loc" : [ -94.519873, 39.19785 ], "pop" : 24046, "state" : "MO" }
+{ "_id" : "64120", "city" : "KANSAS CITY", "loc" : [ -94.54873000000001, 39.122206 ], "pop" : 731, "state" : "MO" }
+{ "_id" : "64123", "city" : "KANSAS CITY", "loc" : [ -94.523545, 39.113593 ], "pop" : 9910, "state" : "MO" }
+{ "_id" : "64124", "city" : "KANSAS CITY", "loc" : [ -94.539402, 39.106832 ], "pop" : 11683, "state" : "MO" }
+{ "_id" : "64125", "city" : "KANSAS CITY", "loc" : [ -94.492328, 39.104157 ], "pop" : 2011, "state" : "MO" }
+{ "_id" : "64126", "city" : "KANSAS CITY", "loc" : [ -94.50466, 39.092255 ], "pop" : 6929, "state" : "MO" }
+{ "_id" : "64127", "city" : "KANSAS CITY", "loc" : [ -94.536636, 39.088303 ], "pop" : 22469, "state" : "MO" }
+{ "_id" : "64128", "city" : "KANSAS CITY", "loc" : [ -94.538634, 39.065932 ], "pop" : 18185, "state" : "MO" }
+{ "_id" : "64129", "city" : "KANSAS CITY", "loc" : [ -94.49513, 39.040093 ], "pop" : 12006, "state" : "MO" }
+{ "_id" : "64130", "city" : "KANSAS CITY", "loc" : [ -94.546674, 39.035106 ], "pop" : 30403, "state" : "MO" }
+{ "_id" : "64131", "city" : "KANSAS CITY", "loc" : [ -94.57741, 38.971303 ], "pop" : 24033, "state" : "MO" }
+{ "_id" : "64132", "city" : "KANSAS CITY", "loc" : [ -94.552156, 38.991073 ], "pop" : 17552, "state" : "MO" }
+{ "_id" : "64133", "city" : "RAYTOWN", "loc" : [ -94.45922899999999, 39.014909 ], "pop" : 33484, "state" : "MO" }
+{ "_id" : "64134", "city" : "KANSAS CITY", "loc" : [ -94.500908, 38.929633 ], "pop" : 23346, "state" : "MO" }
+{ "_id" : "64136", "city" : "KANSAS CITY", "loc" : [ -94.400774, 39.018684 ], "pop" : 1033, "state" : "MO" }
+{ "_id" : "64137", "city" : "KANSAS CITY", "loc" : [ -94.540487, 38.92988 ], "pop" : 11216, "state" : "MO" }
+{ "_id" : "64138", "city" : "RAYTOWN", "loc" : [ -94.479361, 38.96871 ], "pop" : 25590, "state" : "MO" }
+{ "_id" : "64139", "city" : "KANSAS CITY", "loc" : [ -94.406086, 38.965891 ], "pop" : 465, "state" : "MO" }
+{ "_id" : "64145", "city" : "KANSAS CITY", "loc" : [ -94.597607, 38.89767 ], "pop" : 4830, "state" : "MO" }
+{ "_id" : "64146", "city" : "KANSAS CITY", "loc" : [ -94.57638, 38.897264 ], "pop" : 1417, "state" : "MO" }
+{ "_id" : "64147", "city" : "MARTIN CITY", "loc" : [ -94.52971700000001, 38.861352 ], "pop" : 600, "state" : "MO" }
+{ "_id" : "64149", "city" : "KANSAS CITY", "loc" : [ -94.463554, 38.860646 ], "pop" : 314, "state" : "MO" }
+{ "_id" : "64150", "city" : "KANSAS CITY", "loc" : [ -94.616669, 39.177927 ], "pop" : 2140, "state" : "MO" }
+{ "_id" : "64151", "city" : "LAKE WAUKOMIS", "loc" : [ -94.63318, 39.213876 ], "pop" : 18196, "state" : "MO" }
+{ "_id" : "64152", "city" : "PARKVILLE", "loc" : [ -94.69131299999999, 39.220954 ], "pop" : 18719, "state" : "MO" }
+{ "_id" : "64153", "city" : "KANSAS CITY", "loc" : [ -94.697008, 39.262746 ], "pop" : 1582, "state" : "MO" }
+{ "_id" : "64154", "city" : "KANSAS CITY", "loc" : [ -94.63544400000001, 39.254728 ], "pop" : 3379, "state" : "MO" }
+{ "_id" : "64155", "city" : "KANSAS CITY", "loc" : [ -94.570401, 39.275831 ], "pop" : 11562, "state" : "MO" }
+{ "_id" : "64156", "city" : "KANSAS CITY", "loc" : [ -94.533614, 39.290052 ], "pop" : 921, "state" : "MO" }
+{ "_id" : "64157", "city" : "KANSAS CITY", "loc" : [ -94.459456, 39.276673 ], "pop" : 1084, "state" : "MO" }
+{ "_id" : "64158", "city" : "KANSAS CITY", "loc" : [ -94.472036, 39.228428 ], "pop" : 158, "state" : "MO" }
+{ "_id" : "64161", "city" : "RANDOLPH", "loc" : [ -94.459829, 39.161506 ], "pop" : 470, "state" : "MO" }
+{ "_id" : "64163", "city" : "FERRELVIEW", "loc" : [ -94.71931499999999, 39.359756 ], "pop" : 1479, "state" : "MO" }
+{ "_id" : "64164", "city" : "KANSAS CITY", "loc" : [ -94.644643, 39.3426 ], "pop" : 1459, "state" : "MO" }
+{ "_id" : "64165", "city" : "KANSAS CITY", "loc" : [ -94.57296599999999, 39.340054 ], "pop" : 320, "state" : "MO" }
+{ "_id" : "64166", "city" : "KANSAS CITY", "loc" : [ -94.519858, 39.329399 ], "pop" : 466, "state" : "MO" }
+{ "_id" : "64167", "city" : "KANSAS CITY", "loc" : [ -94.46529099999999, 39.309643 ], "pop" : 244, "state" : "MO" }
+{ "_id" : "64401", "city" : "AGENCY", "loc" : [ -94.717017, 39.666229 ], "pop" : 1773, "state" : "MO" }
+{ "_id" : "64402", "city" : "ALBANY", "loc" : [ -94.326977, 40.251282 ], "pop" : 2600, "state" : "MO" }
+{ "_id" : "64421", "city" : "AMAZONIA", "loc" : [ -94.911344, 39.909197 ], "pop" : 864, "state" : "MO" }
+{ "_id" : "64422", "city" : "AMITY", "loc" : [ -94.513558, 39.883697 ], "pop" : 651, "state" : "MO" }
+{ "_id" : "64423", "city" : "BARNARD", "loc" : [ -94.805558, 40.186176 ], "pop" : 561, "state" : "MO" }
+{ "_id" : "64424", "city" : "BETHANY", "loc" : [ -94.018863, 40.260055 ], "pop" : 4148, "state" : "MO" }
+{ "_id" : "64426", "city" : "BLYTHEDALE", "loc" : [ -93.895447, 40.502352 ], "pop" : 335, "state" : "MO" }
+{ "_id" : "64427", "city" : "BOLCKOW", "loc" : [ -94.88474100000001, 40.100673 ], "pop" : 684, "state" : "MO" }
+{ "_id" : "64428", "city" : "BURLINGTON JUNCT", "loc" : [ -95.051663, 40.442125 ], "pop" : 922, "state" : "MO" }
+{ "_id" : "64429", "city" : "CAMERON", "loc" : [ -94.243723, 39.730892 ], "pop" : 4660, "state" : "MO" }
+{ "_id" : "64430", "city" : "CLARKSDALE", "loc" : [ -94.54212, 39.813675 ], "pop" : 546, "state" : "MO" }
+{ "_id" : "64431", "city" : "CLEARMONT", "loc" : [ -95.005478, 40.517489 ], "pop" : 524, "state" : "MO" }
+{ "_id" : "64432", "city" : "CLYDE", "loc" : [ -94.654563, 40.264475 ], "pop" : 221, "state" : "MO" }
+{ "_id" : "64433", "city" : "CONCEPTION", "loc" : [ -94.684302, 40.230929 ], "pop" : 281, "state" : "MO" }
+{ "_id" : "64434", "city" : "CONCEPTION JUNCT", "loc" : [ -94.696797, 40.266017 ], "pop" : 334, "state" : "MO" }
+{ "_id" : "64435", "city" : "CORNING", "loc" : [ -95.436128, 40.24463 ], "pop" : 178, "state" : "MO" }
+{ "_id" : "64436", "city" : "COSBY", "loc" : [ -94.697678, 39.855534 ], "pop" : 727, "state" : "MO" }
+{ "_id" : "64437", "city" : "BIGELOW", "loc" : [ -95.377047, 40.193873 ], "pop" : 580, "state" : "MO" }
+{ "_id" : "64438", "city" : "DARLINGTON", "loc" : [ -94.404899, 40.195517 ], "pop" : 184, "state" : "MO" }
+{ "_id" : "64439", "city" : "DEARBORN", "loc" : [ -94.766368, 39.517248 ], "pop" : 1556, "state" : "MO" }
+{ "_id" : "64440", "city" : "DE KALB", "loc" : [ -94.927027, 39.583361 ], "pop" : 584, "state" : "MO" }
+{ "_id" : "64441", "city" : "DENVER", "loc" : [ -94.306624, 40.418074 ], "pop" : 181, "state" : "MO" }
+{ "_id" : "64442", "city" : "EAGLEVILLE", "loc" : [ -93.995058, 40.491197 ], "pop" : 669, "state" : "MO" }
+{ "_id" : "64443", "city" : "EASTON", "loc" : [ -94.65819399999999, 39.751709 ], "pop" : 1189, "state" : "MO" }
+{ "_id" : "64444", "city" : "EDGERTON", "loc" : [ -94.635217, 39.474213 ], "pop" : 1427, "state" : "MO" }
+{ "_id" : "64445", "city" : "ELMO", "loc" : [ -95.123564, 40.518492 ], "pop" : 481, "state" : "MO" }
+{ "_id" : "64446", "city" : "FAIRFAX", "loc" : [ -95.375075, 40.330193 ], "pop" : 1413, "state" : "MO" }
+{ "_id" : "64448", "city" : "FAUCETT", "loc" : [ -94.791276, 39.589124 ], "pop" : 1077, "state" : "MO" }
+{ "_id" : "64449", "city" : "FILLMORE", "loc" : [ -94.955496, 40.014212 ], "pop" : 514, "state" : "MO" }
+{ "_id" : "64451", "city" : "FOREST CITY", "loc" : [ -95.19159399999999, 39.989708 ], "pop" : 450, "state" : "MO" }
+{ "_id" : "64452", "city" : "FORTESCUE", "loc" : [ -95.33158400000001, 40.054712 ], "pop" : 208, "state" : "MO" }
+{ "_id" : "64453", "city" : "GENTRY", "loc" : [ -94.414198, 40.341112 ], "pop" : 256, "state" : "MO" }
+{ "_id" : "64454", "city" : "GOWER", "loc" : [ -94.596526, 39.602009 ], "pop" : 2115, "state" : "MO" }
+{ "_id" : "64455", "city" : "GRAHAM", "loc" : [ -95.012118, 40.201204 ], "pop" : 543, "state" : "MO" }
+{ "_id" : "64456", "city" : "GRANT CITY", "loc" : [ -94.397908, 40.492358 ], "pop" : 1401, "state" : "MO" }
+{ "_id" : "64457", "city" : "GUILFORD", "loc" : [ -94.695076, 40.174614 ], "pop" : 388, "state" : "MO" }
+{ "_id" : "64458", "city" : "HATFIELD", "loc" : [ -94.169059, 40.521853 ], "pop" : 141, "state" : "MO" }
+{ "_id" : "64459", "city" : "HELENA", "loc" : [ -94.69212, 39.925122 ], "pop" : 1218, "state" : "MO" }
+{ "_id" : "64461", "city" : "HOPKINS", "loc" : [ -94.81894800000001, 40.548328 ], "pop" : 869, "state" : "MO" }
+{ "_id" : "64463", "city" : "KING CITY", "loc" : [ -94.52341199999999, 40.065184 ], "pop" : 1382, "state" : "MO" }
+{ "_id" : "64465", "city" : "LATHROP", "loc" : [ -94.309271, 39.517727 ], "pop" : 4461, "state" : "MO" }
+{ "_id" : "64466", "city" : "MAITLAND", "loc" : [ -95.09270600000001, 40.199111 ], "pop" : 582, "state" : "MO" }
+{ "_id" : "64467", "city" : "MARTINSVILLE", "loc" : [ -94.164463, 40.366206 ], "pop" : 271, "state" : "MO" }
+{ "_id" : "64468", "city" : "MARYVILLE", "loc" : [ -94.873479, 40.343399 ], "pop" : 13687, "state" : "MO" }
+{ "_id" : "64469", "city" : "MAYSVILLE", "loc" : [ -94.354821, 39.911189 ], "pop" : 1948, "state" : "MO" }
+{ "_id" : "64470", "city" : "MOUND CITY", "loc" : [ -95.213837, 40.136238 ], "pop" : 2166, "state" : "MO" }
+{ "_id" : "64471", "city" : "NEW HAMPTON", "loc" : [ -94.17856500000001, 40.244439 ], "pop" : 666, "state" : "MO" }
+{ "_id" : "64473", "city" : "OREGON", "loc" : [ -95.123358, 39.980906 ], "pop" : 1601, "state" : "MO" }
+{ "_id" : "64474", "city" : "OSBORN", "loc" : [ -94.247677, 39.768436 ], "pop" : 4084, "state" : "MO" }
+{ "_id" : "64475", "city" : "PARNELL", "loc" : [ -94.659519, 40.472288 ], "pop" : 456, "state" : "MO" }
+{ "_id" : "64476", "city" : "PICKERING", "loc" : [ -94.84111900000001, 40.459073 ], "pop" : 525, "state" : "MO" }
+{ "_id" : "64477", "city" : "PLATTSBURG", "loc" : [ -94.433814, 39.57047 ], "pop" : 3786, "state" : "MO" }
+{ "_id" : "64478", "city" : "QUITMAN", "loc" : [ -95.072909, 40.3701 ], "pop" : 302, "state" : "MO" }
+{ "_id" : "64479", "city" : "RAVENWOOD", "loc" : [ -94.68051, 40.357902 ], "pop" : 942, "state" : "MO" }
+{ "_id" : "64480", "city" : "REA", "loc" : [ -94.70018399999999, 40.059263 ], "pop" : 690, "state" : "MO" }
+{ "_id" : "64481", "city" : "RIDGEWAY", "loc" : [ -93.957527, 40.399896 ], "pop" : 870, "state" : "MO" }
+{ "_id" : "64482", "city" : "ROCK PORT", "loc" : [ -95.52740300000001, 40.430581 ], "pop" : 2704, "state" : "MO" }
+{ "_id" : "64483", "city" : "ROSENDALE", "loc" : [ -94.832808, 40.039853 ], "pop" : 630, "state" : "MO" }
+{ "_id" : "64484", "city" : "RUSHVILLE", "loc" : [ -95.041259, 39.565272 ], "pop" : 1068, "state" : "MO" }
+{ "_id" : "64485", "city" : "SAVANNAH", "loc" : [ -94.826733, 39.916774 ], "pop" : 7599, "state" : "MO" }
+{ "_id" : "64486", "city" : "SHERIDAN", "loc" : [ -94.570149, 40.492822 ], "pop" : 664, "state" : "MO" }
+{ "_id" : "64487", "city" : "SKIDMORE", "loc" : [ -95.079241, 40.28961 ], "pop" : 638, "state" : "MO" }
+{ "_id" : "64489", "city" : "STANBERRY", "loc" : [ -94.538691, 40.229285 ], "pop" : 1879, "state" : "MO" }
+{ "_id" : "64490", "city" : "HEMPLE", "loc" : [ -94.51779000000001, 39.745465 ], "pop" : 2110, "state" : "MO" }
+{ "_id" : "64491", "city" : "TARKIO", "loc" : [ -95.378586, 40.441841 ], "pop" : 2553, "state" : "MO" }
+{ "_id" : "64492", "city" : "TRIMBLE", "loc" : [ -94.55123399999999, 39.487067 ], "pop" : 944, "state" : "MO" }
+{ "_id" : "64493", "city" : "TURNEY", "loc" : [ -94.297241, 39.631772 ], "pop" : 319, "state" : "MO" }
+{ "_id" : "64494", "city" : "UNION STAR", "loc" : [ -94.578732, 39.984645 ], "pop" : 745, "state" : "MO" }
+{ "_id" : "64496", "city" : "WATSON", "loc" : [ -95.61931, 40.477985 ], "pop" : 215, "state" : "MO" }
+{ "_id" : "64497", "city" : "WEATHERBY", "loc" : [ -94.254959, 39.888699 ], "pop" : 584, "state" : "MO" }
+{ "_id" : "64498", "city" : "WESTBORO", "loc" : [ -95.313419, 40.535748 ], "pop" : 572, "state" : "MO" }
+{ "_id" : "64499", "city" : "WORTH", "loc" : [ -94.437084, 40.4173 ], "pop" : 229, "state" : "MO" }
+{ "_id" : "64501", "city" : "SAINT JOSEPH", "loc" : [ -94.838488, 39.768755 ], "pop" : 12978, "state" : "MO" }
+{ "_id" : "64503", "city" : "SAINT JOSEPH", "loc" : [ -94.817125, 39.733987 ], "pop" : 14190, "state" : "MO" }
+{ "_id" : "64504", "city" : "SAINT JOSEPH", "loc" : [ -94.867749, 39.707566 ], "pop" : 11412, "state" : "MO" }
+{ "_id" : "64505", "city" : "SAINT JOSEPH", "loc" : [ -94.844341, 39.796532 ], "pop" : 10627, "state" : "MO" }
+{ "_id" : "64506", "city" : "SAINT JOSEPH", "loc" : [ -94.80431400000001, 39.789292 ], "pop" : 18009, "state" : "MO" }
+{ "_id" : "64507", "city" : "SAINT JOSEPH", "loc" : [ -94.817303, 39.755052 ], "pop" : 11194, "state" : "MO" }
+{ "_id" : "64601", "city" : "CHILLICOTHE", "loc" : [ -93.550887, 39.796569 ], "pop" : 11189, "state" : "MO" }
+{ "_id" : "64620", "city" : "ALTAMONT", "loc" : [ -94.12815500000001, 39.905017 ], "pop" : 533, "state" : "MO" }
+{ "_id" : "64621", "city" : "AVALON", "loc" : [ -93.47288, 39.668183 ], "pop" : 388, "state" : "MO" }
+{ "_id" : "64622", "city" : "BOGARD", "loc" : [ -93.537387, 39.499354 ], "pop" : 831, "state" : "MO" }
+{ "_id" : "64623", "city" : "BOSWORTH", "loc" : [ -93.333521, 39.476692 ], "pop" : 583, "state" : "MO" }
+{ "_id" : "64624", "city" : "BRAYMER", "loc" : [ -93.78868, 39.591454 ], "pop" : 1671, "state" : "MO" }
+{ "_id" : "64625", "city" : "BRECKENRIDGE", "loc" : [ -93.806794, 39.758205 ], "pop" : 608, "state" : "MO" }
+{ "_id" : "64628", "city" : "BROOKFIELD", "loc" : [ -93.07194800000001, 39.784612 ], "pop" : 5564, "state" : "MO" }
+{ "_id" : "64630", "city" : "BROWNING", "loc" : [ -93.160661, 40.028983 ], "pop" : 360, "state" : "MO" }
+{ "_id" : "64631", "city" : "BUCKLIN", "loc" : [ -92.89281, 39.800563 ], "pop" : 969, "state" : "MO" }
+{ "_id" : "64632", "city" : "CAINSVILLE", "loc" : [ -93.759047, 40.457768 ], "pop" : 870, "state" : "MO" }
+{ "_id" : "64633", "city" : "CARROLLTON", "loc" : [ -93.492626, 39.367334 ], "pop" : 5694, "state" : "MO" }
+{ "_id" : "64635", "city" : "CHULA", "loc" : [ -93.484095, 39.922606 ], "pop" : 685, "state" : "MO" }
+{ "_id" : "64636", "city" : "COFFEY", "loc" : [ -94.02515099999999, 40.099928 ], "pop" : 359, "state" : "MO" }
+{ "_id" : "64637", "city" : "COWGILL", "loc" : [ -93.929469, 39.564314 ], "pop" : 532, "state" : "MO" }
+{ "_id" : "64638", "city" : "DAWN", "loc" : [ -93.596405, 39.666506 ], "pop" : 468, "state" : "MO" }
+{ "_id" : "64639", "city" : "DE WITT", "loc" : [ -93.30158299999999, 39.358978 ], "pop" : 592, "state" : "MO" }
+{ "_id" : "64640", "city" : "GALLATIN", "loc" : [ -93.978748, 39.902486 ], "pop" : 3260, "state" : "MO" }
+{ "_id" : "64641", "city" : "GALT", "loc" : [ -93.395261, 40.14398 ], "pop" : 607, "state" : "MO" }
+{ "_id" : "64642", "city" : "GILMAN CITY", "loc" : [ -93.831979, 40.145005 ], "pop" : 680, "state" : "MO" }
+{ "_id" : "64643", "city" : "HALE", "loc" : [ -93.34448, 39.595302 ], "pop" : 771, "state" : "MO" }
+{ "_id" : "64644", "city" : "HAMILTON", "loc" : [ -93.990898, 39.736412 ], "pop" : 2706, "state" : "MO" }
+{ "_id" : "64645", "city" : "HARRIS", "loc" : [ -93.350106, 40.307519 ], "pop" : 127, "state" : "MO" }
+{ "_id" : "64646", "city" : "HUMPHREYS", "loc" : [ -93.301455, 40.114448 ], "pop" : 368, "state" : "MO" }
+{ "_id" : "64647", "city" : "JAMESON", "loc" : [ -93.95974699999999, 40.004615 ], "pop" : 401, "state" : "MO" }
+{ "_id" : "64648", "city" : "JAMESPORT", "loc" : [ -93.78004799999999, 39.983724 ], "pop" : 1933, "state" : "MO" }
+{ "_id" : "64649", "city" : "KIDDER", "loc" : [ -94.130005, 39.757039 ], "pop" : 708, "state" : "MO" }
+{ "_id" : "64650", "city" : "KINGSTON", "loc" : [ -94.082694, 39.6508 ], "pop" : 868, "state" : "MO" }
+{ "_id" : "64651", "city" : "LACLEDE", "loc" : [ -93.16797099999999, 39.7837 ], "pop" : 744, "state" : "MO" }
+{ "_id" : "64652", "city" : "LAREDO", "loc" : [ -93.440676, 40.014397 ], "pop" : 485, "state" : "MO" }
+{ "_id" : "64653", "city" : "LINNEUS", "loc" : [ -93.188529, 39.909945 ], "pop" : 1421, "state" : "MO" }
+{ "_id" : "64654", "city" : "LOCK SPRINGS", "loc" : [ -93.797697, 39.907396 ], "pop" : 576, "state" : "MO" }
+{ "_id" : "64655", "city" : "LUCERNE", "loc" : [ -93.286654, 40.438182 ], "pop" : 206, "state" : "MO" }
+{ "_id" : "64656", "city" : "LUDLOW", "loc" : [ -93.704578, 39.655064 ], "pop" : 355, "state" : "MO" }
+{ "_id" : "64657", "city" : "MC FALL", "loc" : [ -94.300259, 40.105071 ], "pop" : 547, "state" : "MO" }
+{ "_id" : "64658", "city" : "MARCELINE", "loc" : [ -92.945502, 39.712485 ], "pop" : 3517, "state" : "MO" }
+{ "_id" : "64659", "city" : "MEADVILLE", "loc" : [ -93.301389, 39.779468 ], "pop" : 774, "state" : "MO" }
+{ "_id" : "64660", "city" : "MENDON", "loc" : [ -93.089168, 39.582849 ], "pop" : 568, "state" : "MO" }
+{ "_id" : "64661", "city" : "MERCER", "loc" : [ -93.524197, 40.516917 ], "pop" : 975, "state" : "MO" }
+{ "_id" : "64664", "city" : "MOORESVILLE", "loc" : [ -93.71693, 39.74249 ], "pop" : 320, "state" : "MO" }
+{ "_id" : "64665", "city" : "MOUNT MORIAH", "loc" : [ -93.814252, 40.329164 ], "pop" : 247, "state" : "MO" }
+{ "_id" : "64667", "city" : "NEWTOWN", "loc" : [ -93.30727899999999, 40.361227 ], "pop" : 313, "state" : "MO" }
+{ "_id" : "64668", "city" : "NORBORNE", "loc" : [ -93.67609, 39.329903 ], "pop" : 1669, "state" : "MO" }
+{ "_id" : "64670", "city" : "PATTONSBURG", "loc" : [ -94.13429499999999, 40.042756 ], "pop" : 855, "state" : "MO" }
+{ "_id" : "64671", "city" : "POLO", "loc" : [ -94.074303, 39.564697 ], "pop" : 1496, "state" : "MO" }
+{ "_id" : "64672", "city" : "POWERSVILLE", "loc" : [ -93.284436, 40.527155 ], "pop" : 284, "state" : "MO" }
+{ "_id" : "64673", "city" : "PRINCETON", "loc" : [ -93.577394, 40.385533 ], "pop" : 2467, "state" : "MO" }
+{ "_id" : "64674", "city" : "PURDIN", "loc" : [ -93.17001999999999, 39.952948 ], "pop" : 297, "state" : "MO" }
+{ "_id" : "64676", "city" : "ROTHVILLE", "loc" : [ -93.046683, 39.662666 ], "pop" : 440, "state" : "MO" }
+{ "_id" : "64677", "city" : "SAINT CATHARINE", "loc" : [ -92.99294999999999, 39.800017 ], "pop" : 288, "state" : "MO" }
+{ "_id" : "64679", "city" : "SPICKARD", "loc" : [ -93.550291, 40.239985 ], "pop" : 659, "state" : "MO" }
+{ "_id" : "64681", "city" : "SUMNER", "loc" : [ -93.22412799999999, 39.654992 ], "pop" : 307, "state" : "MO" }
+{ "_id" : "64682", "city" : "TINA", "loc" : [ -93.46475, 39.551751 ], "pop" : 399, "state" : "MO" }
+{ "_id" : "64683", "city" : "TRENTON", "loc" : [ -93.608634, 40.082335 ], "pop" : 8465, "state" : "MO" }
+{ "_id" : "64686", "city" : "UTICA", "loc" : [ -93.62889699999999, 39.741742 ], "pop" : 361, "state" : "MO" }
+{ "_id" : "64688", "city" : "WHEELING", "loc" : [ -93.386835, 39.801137 ], "pop" : 481, "state" : "MO" }
+{ "_id" : "64689", "city" : "WINSTON", "loc" : [ -94.148747, 39.84995 ], "pop" : 567, "state" : "MO" }
+{ "_id" : "64701", "city" : "HARRISONVILLE", "loc" : [ -94.32852, 38.64193 ], "pop" : 12242, "state" : "MO" }
+{ "_id" : "64720", "city" : "ADRIAN", "loc" : [ -94.368336, 38.412473 ], "pop" : 2254, "state" : "MO" }
+{ "_id" : "64722", "city" : "AMORET", "loc" : [ -94.57342300000001, 38.260508 ], "pop" : 409, "state" : "MO" }
+{ "_id" : "64723", "city" : "AMSTERDAM", "loc" : [ -94.57628200000001, 38.395385 ], "pop" : 884, "state" : "MO" }
+{ "_id" : "64724", "city" : "APPLETON CITY", "loc" : [ -94.02290000000001, 38.184779 ], "pop" : 1584, "state" : "MO" }
+{ "_id" : "64725", "city" : "ARCHIE", "loc" : [ -94.36299200000001, 38.498612 ], "pop" : 1912, "state" : "MO" }
+{ "_id" : "64726", "city" : "BLAIRSTOWN", "loc" : [ -93.964102, 38.522701 ], "pop" : 803, "state" : "MO" }
+{ "_id" : "64728", "city" : "BRONAUGH", "loc" : [ -94.48603, 37.69 ], "pop" : 493, "state" : "MO" }
+{ "_id" : "64730", "city" : "BUTLER", "loc" : [ -94.31375, 38.271245 ], "pop" : 8449, "state" : "MO" }
+{ "_id" : "64733", "city" : "CHILHOWEE", "loc" : [ -93.865325, 38.612604 ], "pop" : 951, "state" : "MO" }
+{ "_id" : "64734", "city" : "CLEVELAND", "loc" : [ -94.56950000000001, 38.68977 ], "pop" : 2586, "state" : "MO" }
+{ "_id" : "64735", "city" : "TIGHTWAD", "loc" : [ -93.758906, 38.368811 ], "pop" : 12259, "state" : "MO" }
+{ "_id" : "64738", "city" : "COLLINS", "loc" : [ -93.660849, 37.880998 ], "pop" : 844, "state" : "MO" }
+{ "_id" : "64739", "city" : "CREIGHTON", "loc" : [ -94.09260399999999, 38.507754 ], "pop" : 711, "state" : "MO" }
+{ "_id" : "64740", "city" : "DEEPWATER", "loc" : [ -93.73028100000001, 38.243164 ], "pop" : 1233, "state" : "MO" }
+{ "_id" : "64741", "city" : "DEERFIELD", "loc" : [ -94.48484500000001, 37.82109 ], "pop" : 966, "state" : "MO" }
+{ "_id" : "64742", "city" : "DREXEL", "loc" : [ -94.592765, 38.495625 ], "pop" : 1181, "state" : "MO" }
+{ "_id" : "64744", "city" : "EL DORADO SPRING", "loc" : [ -94.030091, 37.858517 ], "pop" : 6787, "state" : "MO" }
+{ "_id" : "64745", "city" : "FOSTER", "loc" : [ -94.53706699999999, 38.17338 ], "pop" : 464, "state" : "MO" }
+{ "_id" : "64746", "city" : "FREEMAN", "loc" : [ -94.495561, 38.624549 ], "pop" : 1509, "state" : "MO" }
+{ "_id" : "64747", "city" : "GARDEN CITY", "loc" : [ -94.18253199999999, 38.568082 ], "pop" : 1837, "state" : "MO" }
+{ "_id" : "64748", "city" : "GOLDEN CITY", "loc" : [ -94.102683, 37.399535 ], "pop" : 1127, "state" : "MO" }
+{ "_id" : "64750", "city" : "HARWOOD", "loc" : [ -94.14019399999999, 37.953028 ], "pop" : 189, "state" : "MO" }
+{ "_id" : "64751", "city" : "HORTON", "loc" : [ -94.396438, 37.995078 ], "pop" : 551, "state" : "MO" }
+{ "_id" : "64752", "city" : "STOTESBURY", "loc" : [ -94.56100000000001, 38.059635 ], "pop" : 728, "state" : "MO" }
+{ "_id" : "64755", "city" : "JASPER", "loc" : [ -94.273126, 37.318224 ], "pop" : 2085, "state" : "MO" }
+{ "_id" : "64756", "city" : "JERICO SPRINGS", "loc" : [ -94.012912, 37.661343 ], "pop" : 966, "state" : "MO" }
+{ "_id" : "64759", "city" : "IANTHA", "loc" : [ -94.270253, 37.500221 ], "pop" : 7847, "state" : "MO" }
+{ "_id" : "64760", "city" : "LATOUR", "loc" : [ -94.045721, 38.634847 ], "pop" : 745, "state" : "MO" }
+{ "_id" : "64761", "city" : "LEETON", "loc" : [ -93.712321, 38.614113 ], "pop" : 1723, "state" : "MO" }
+{ "_id" : "64762", "city" : "LIBERAL", "loc" : [ -94.520377, 37.572453 ], "pop" : 1448, "state" : "MO" }
+{ "_id" : "64763", "city" : "LOWRY CITY", "loc" : [ -93.71135200000001, 38.140443 ], "pop" : 1345, "state" : "MO" }
+{ "_id" : "64767", "city" : "MILO", "loc" : [ -94.304632, 37.744559 ], "pop" : 439, "state" : "MO" }
+{ "_id" : "64769", "city" : "MINDENMINES", "loc" : [ -94.57557300000001, 37.451987 ], "pop" : 544, "state" : "MO" }
+{ "_id" : "64770", "city" : "MONTROSE", "loc" : [ -93.995239, 38.259702 ], "pop" : 643, "state" : "MO" }
+{ "_id" : "64771", "city" : "MOUNDVILLE", "loc" : [ -94.449645, 37.747637 ], "pop" : 478, "state" : "MO" }
+{ "_id" : "64772", "city" : "NEVADA", "loc" : [ -94.35712700000001, 37.840853 ], "pop" : 11918, "state" : "MO" }
+{ "_id" : "64776", "city" : "OSCEOLA", "loc" : [ -93.753621, 38.028553 ], "pop" : 4684, "state" : "MO" }
+{ "_id" : "64778", "city" : "RICHARDS", "loc" : [ -94.55922700000001, 37.906111 ], "pop" : 207, "state" : "MO" }
+{ "_id" : "64779", "city" : "RICH HILL", "loc" : [ -94.363454, 38.09438 ], "pop" : 1630, "state" : "MO" }
+{ "_id" : "64780", "city" : "ROCKVILLE", "loc" : [ -94.129904, 38.076583 ], "pop" : 456, "state" : "MO" }
+{ "_id" : "64783", "city" : "SCHELL CITY", "loc" : [ -94.15791, 38.009403 ], "pop" : 809, "state" : "MO" }
+{ "_id" : "64784", "city" : "SHELDON", "loc" : [ -94.254835, 37.683969 ], "pop" : 1281, "state" : "MO" }
+{ "_id" : "64788", "city" : "URICH", "loc" : [ -93.97847, 38.44489 ], "pop" : 949, "state" : "MO" }
+{ "_id" : "64790", "city" : "WALKER", "loc" : [ -94.22930100000001, 37.893023 ], "pop" : 544, "state" : "MO" }
+{ "_id" : "64801", "city" : "JOPLIN", "loc" : [ -94.505144, 37.096858 ], "pop" : 29617, "state" : "MO" }
+{ "_id" : "64804", "city" : "JOPLIN", "loc" : [ -94.51025199999999, 37.046454 ], "pop" : 30661, "state" : "MO" }
+{ "_id" : "64831", "city" : "ANDERSON", "loc" : [ -94.476648, 36.669224 ], "pop" : 4477, "state" : "MO" }
+{ "_id" : "64832", "city" : "ASBURY", "loc" : [ -94.565484, 37.294168 ], "pop" : 603, "state" : "MO" }
+{ "_id" : "64833", "city" : "AVILLA", "loc" : [ -94.117043, 37.194709 ], "pop" : 678, "state" : "MO" }
+{ "_id" : "64834", "city" : "CARL JUNCTION", "loc" : [ -94.55502, 37.179479 ], "pop" : 4158, "state" : "MO" }
+{ "_id" : "64835", "city" : "CARTERVILLE", "loc" : [ -94.43593799999999, 37.150734 ], "pop" : 2397, "state" : "MO" }
+{ "_id" : "64836", "city" : "CARTHAGE", "loc" : [ -94.311232, 37.159686 ], "pop" : 19516, "state" : "MO" }
+{ "_id" : "64840", "city" : "DIAMOND", "loc" : [ -94.32041, 37.005993 ], "pop" : 2736, "state" : "MO" }
+{ "_id" : "64842", "city" : "FAIRVIEW", "loc" : [ -94.09120299999999, 36.825419 ], "pop" : 568, "state" : "MO" }
+{ "_id" : "64843", "city" : "GOODMAN", "loc" : [ -94.39855, 36.732335 ], "pop" : 2025, "state" : "MO" }
+{ "_id" : "64844", "city" : "GRANBY", "loc" : [ -94.264349, 36.906562 ], "pop" : 3571, "state" : "MO" }
+{ "_id" : "64847", "city" : "LANAGAN", "loc" : [ -94.4551, 36.605956 ], "pop" : 755, "state" : "MO" }
+{ "_id" : "64848", "city" : "LA RUSSELL", "loc" : [ -94.03287400000001, 37.17387 ], "pop" : 817, "state" : "MO" }
+{ "_id" : "64850", "city" : "NEOSHO", "loc" : [ -94.386218, 36.870634 ], "pop" : 15863, "state" : "MO" }
+{ "_id" : "64854", "city" : "NOEL", "loc" : [ -94.490627, 36.541668 ], "pop" : 2239, "state" : "MO" }
+{ "_id" : "64855", "city" : "ORONOGO", "loc" : [ -94.446246, 37.243288 ], "pop" : 3942, "state" : "MO" }
+{ "_id" : "64856", "city" : "JANE", "loc" : [ -94.351461, 36.580243 ], "pop" : 2783, "state" : "MO" }
+{ "_id" : "64859", "city" : "REEDS", "loc" : [ -94.161272, 37.122477 ], "pop" : 222, "state" : "MO" }
+{ "_id" : "64861", "city" : "ROCKY COMFORT", "loc" : [ -94.109066, 36.717546 ], "pop" : 543, "state" : "MO" }
+{ "_id" : "64862", "city" : "SARCOXIE", "loc" : [ -94.11514, 37.072382 ], "pop" : 2133, "state" : "MO" }
+{ "_id" : "64863", "city" : "SOUTH WEST CITY", "loc" : [ -94.596141, 36.531924 ], "pop" : 1201, "state" : "MO" }
+{ "_id" : "64865", "city" : "SENECA", "loc" : [ -94.55936699999999, 36.844169 ], "pop" : 5419, "state" : "MO" }
+{ "_id" : "64866", "city" : "STARK CITY", "loc" : [ -94.154811, 36.878538 ], "pop" : 967, "state" : "MO" }
+{ "_id" : "64867", "city" : "STELLA", "loc" : [ -94.20858, 36.751553 ], "pop" : 2154, "state" : "MO" }
+{ "_id" : "64868", "city" : "TIFF CITY", "loc" : [ -94.59343699999999, 36.664447 ], "pop" : 364, "state" : "MO" }
+{ "_id" : "64870", "city" : "WEBB CITY", "loc" : [ -94.472683, 37.144 ], "pop" : 7474, "state" : "MO" }
+{ "_id" : "64873", "city" : "WENTWORTH", "loc" : [ -94.132169, 36.980702 ], "pop" : 1211, "state" : "MO" }
+{ "_id" : "64874", "city" : "WHEATON", "loc" : [ -94.04916, 36.765145 ], "pop" : 970, "state" : "MO" }
+{ "_id" : "65001", "city" : "ARGYLE", "loc" : [ -92.015456, 38.298619 ], "pop" : 384, "state" : "MO" }
+{ "_id" : "65010", "city" : "ASHLAND", "loc" : [ -92.25366200000001, 38.787771 ], "pop" : 2989, "state" : "MO" }
+{ "_id" : "65011", "city" : "BARNETT", "loc" : [ -92.668594, 38.396696 ], "pop" : 660, "state" : "MO" }
+{ "_id" : "65013", "city" : "BELLE", "loc" : [ -91.730299, 38.271108 ], "pop" : 2874, "state" : "MO" }
+{ "_id" : "65014", "city" : "BLAND", "loc" : [ -91.626334, 38.307383 ], "pop" : 2284, "state" : "MO" }
+{ "_id" : "65016", "city" : "BONNOTS MILL", "loc" : [ -91.92934099999999, 38.553282 ], "pop" : 1373, "state" : "MO" }
+{ "_id" : "65017", "city" : "BRUMLEY", "loc" : [ -92.474732, 38.070914 ], "pop" : 1127, "state" : "MO" }
+{ "_id" : "65018", "city" : "CALIFORNIA", "loc" : [ -92.545558, 38.622369 ], "pop" : 6224, "state" : "MO" }
+{ "_id" : "65020", "city" : "CAMDENTON", "loc" : [ -92.76774399999999, 38.018534 ], "pop" : 8006, "state" : "MO" }
+{ "_id" : "65023", "city" : "CENTERTOWN", "loc" : [ -92.39952099999999, 38.629705 ], "pop" : 1184, "state" : "MO" }
+{ "_id" : "65024", "city" : "CHAMOIS", "loc" : [ -91.76967999999999, 38.652683 ], "pop" : 986, "state" : "MO" }
+{ "_id" : "65025", "city" : "CLARKSBURG", "loc" : [ -92.67292500000001, 38.643156 ], "pop" : 784, "state" : "MO" }
+{ "_id" : "65026", "city" : "ELDON", "loc" : [ -92.57361899999999, 38.340127 ], "pop" : 8673, "state" : "MO" }
+{ "_id" : "65032", "city" : "EUGENE", "loc" : [ -92.368853, 38.359849 ], "pop" : 1181, "state" : "MO" }
+{ "_id" : "65034", "city" : "FORTUNA", "loc" : [ -92.784948, 38.574391 ], "pop" : 310, "state" : "MO" }
+{ "_id" : "65035", "city" : "FREEBURG", "loc" : [ -91.927605, 38.355085 ], "pop" : 1373, "state" : "MO" }
+{ "_id" : "65037", "city" : "GRAVOIS MILLS", "loc" : [ -92.82302900000001, 38.258445 ], "pop" : 5653, "state" : "MO" }
+{ "_id" : "65039", "city" : "HARTSBURG", "loc" : [ -92.286377, 38.715902 ], "pop" : 1945, "state" : "MO" }
+{ "_id" : "65040", "city" : "HENLEY", "loc" : [ -92.312303, 38.388133 ], "pop" : 952, "state" : "MO" }
+{ "_id" : "65041", "city" : "BAY", "loc" : [ -91.46771699999999, 38.668381 ], "pop" : 4842, "state" : "MO" }
+{ "_id" : "65042", "city" : "HIGH POINT", "loc" : [ -92.600514, 38.478237 ], "pop" : 509, "state" : "MO" }
+{ "_id" : "65043", "city" : "HOLTS SUMMIT", "loc" : [ -92.116345, 38.632784 ], "pop" : 6642, "state" : "MO" }
+{ "_id" : "65046", "city" : "JAMESTOWN", "loc" : [ -92.48065099999999, 38.779292 ], "pop" : 1018, "state" : "MO" }
+{ "_id" : "65047", "city" : "KAISER", "loc" : [ -92.579869, 38.163673 ], "pop" : 1213, "state" : "MO" }
+{ "_id" : "65048", "city" : "KOELTZTOWN", "loc" : [ -92.048365, 38.323526 ], "pop" : 185, "state" : "MO" }
+{ "_id" : "65049", "city" : "FOUR SEASONS", "loc" : [ -92.677555, 38.209127 ], "pop" : 4404, "state" : "MO" }
+{ "_id" : "65050", "city" : "LATHAM", "loc" : [ -92.65364700000001, 38.550035 ], "pop" : 937, "state" : "MO" }
+{ "_id" : "65051", "city" : "LINN", "loc" : [ -91.81945, 38.473855 ], "pop" : 3836, "state" : "MO" }
+{ "_id" : "65052", "city" : "LINN CREEK", "loc" : [ -92.683077, 38.060524 ], "pop" : 2308, "state" : "MO" }
+{ "_id" : "65053", "city" : "LOHMAN", "loc" : [ -92.384216, 38.548434 ], "pop" : 356, "state" : "MO" }
+{ "_id" : "65054", "city" : "LOOSE CREEK", "loc" : [ -91.959126, 38.471715 ], "pop" : 1089, "state" : "MO" }
+{ "_id" : "65058", "city" : "META", "loc" : [ -92.135797, 38.250039 ], "pop" : 1003, "state" : "MO" }
+{ "_id" : "65059", "city" : "MOKANE", "loc" : [ -91.886815, 38.699839 ], "pop" : 881, "state" : "MO" }
+{ "_id" : "65061", "city" : "MORRISON", "loc" : [ -91.657972, 38.605967 ], "pop" : 267, "state" : "MO" }
+{ "_id" : "65062", "city" : "MOUNT STERLING", "loc" : [ -91.610315, 38.538786 ], "pop" : 285, "state" : "MO" }
+{ "_id" : "65063", "city" : "NEW BLOOMFIELD", "loc" : [ -92.082983, 38.709996 ], "pop" : 2588, "state" : "MO" }
+{ "_id" : "65064", "city" : "OLEAN", "loc" : [ -92.53031, 38.400059 ], "pop" : 882, "state" : "MO" }
+{ "_id" : "65065", "city" : "OSAGE BEACH", "loc" : [ -92.666427, 38.13805 ], "pop" : 3601, "state" : "MO" }
+{ "_id" : "65066", "city" : "OWENSVILLE", "loc" : [ -91.486679, 38.351119 ], "pop" : 5980, "state" : "MO" }
+{ "_id" : "65067", "city" : "PORTLAND", "loc" : [ -91.70056700000001, 38.784701 ], "pop" : 439, "state" : "MO" }
+{ "_id" : "65068", "city" : "PRAIRIE HOME", "loc" : [ -92.597376, 38.825331 ], "pop" : 533, "state" : "MO" }
+{ "_id" : "65069", "city" : "RHINELAND", "loc" : [ -91.51510500000001, 38.763811 ], "pop" : 1340, "state" : "MO" }
+{ "_id" : "65072", "city" : "ROCKY MOUNT", "loc" : [ -92.705921, 38.291057 ], "pop" : 157, "state" : "MO" }
+{ "_id" : "65074", "city" : "RUSSELLVILLE", "loc" : [ -92.42912200000001, 38.500534 ], "pop" : 2043, "state" : "MO" }
+{ "_id" : "65075", "city" : "SAINT ELIZABETH", "loc" : [ -92.263503, 38.271244 ], "pop" : 701, "state" : "MO" }
+{ "_id" : "65076", "city" : "SAINT THOMAS", "loc" : [ -92.18938199999999, 38.391246 ], "pop" : 1232, "state" : "MO" }
+{ "_id" : "65077", "city" : "STEEDMAN", "loc" : [ -91.788837, 38.756604 ], "pop" : 458, "state" : "MO" }
+{ "_id" : "65078", "city" : "STOVER", "loc" : [ -92.99466700000001, 38.441352 ], "pop" : 1946, "state" : "MO" }
+{ "_id" : "65079", "city" : "SUNRISE BEACH", "loc" : [ -92.78539499999999, 38.155845 ], "pop" : 3635, "state" : "MO" }
+{ "_id" : "65080", "city" : "TEBBETTS", "loc" : [ -91.967316, 38.640193 ], "pop" : 413, "state" : "MO" }
+{ "_id" : "65081", "city" : "TIPTON", "loc" : [ -92.781448, 38.654839 ], "pop" : 2516, "state" : "MO" }
+{ "_id" : "65082", "city" : "TUSCUMBIA", "loc" : [ -92.491739, 38.238881 ], "pop" : 1181, "state" : "MO" }
+{ "_id" : "65083", "city" : "ULMAN", "loc" : [ -92.46397899999999, 38.134141 ], "pop" : 517, "state" : "MO" }
+{ "_id" : "65084", "city" : "VERSAILLES", "loc" : [ -92.825835, 38.436491 ], "pop" : 5581, "state" : "MO" }
+{ "_id" : "65085", "city" : "WESTPHALIA", "loc" : [ -92.039221, 38.426968 ], "pop" : 992, "state" : "MO" }
+{ "_id" : "65101", "city" : "JEFFERSON CITY", "loc" : [ -92.152462, 38.546212 ], "pop" : 25992, "state" : "MO" }
+{ "_id" : "65109", "city" : "JEFFERSON CITY", "loc" : [ -92.244298, 38.577272 ], "pop" : 31418, "state" : "MO" }
+{ "_id" : "65201", "city" : "COLUMBIA", "loc" : [ -92.30486500000001, 38.938176 ], "pop" : 33668, "state" : "MO" }
+{ "_id" : "65202", "city" : "COLUMBIA", "loc" : [ -92.311204, 38.995019 ], "pop" : 27394, "state" : "MO" }
+{ "_id" : "65203", "city" : "COLUMBIA", "loc" : [ -92.363865, 38.93482 ], "pop" : 34914, "state" : "MO" }
+{ "_id" : "65230", "city" : "ARMSTRONG", "loc" : [ -92.70897600000001, 39.256585 ], "pop" : 736, "state" : "MO" }
+{ "_id" : "65231", "city" : "AUXVASSE", "loc" : [ -91.885801, 39.012184 ], "pop" : 2698, "state" : "MO" }
+{ "_id" : "65232", "city" : "BENTON CITY", "loc" : [ -91.766124, 39.120886 ], "pop" : 300, "state" : "MO" }
+{ "_id" : "65233", "city" : "BOONVILLE", "loc" : [ -92.744973, 38.95364 ], "pop" : 9330, "state" : "MO" }
+{ "_id" : "65236", "city" : "BRUNSWICK", "loc" : [ -93.118694, 39.437424 ], "pop" : 1610, "state" : "MO" }
+{ "_id" : "65237", "city" : "BUNCETON", "loc" : [ -92.79269499999999, 38.746754 ], "pop" : 1343, "state" : "MO" }
+{ "_id" : "65239", "city" : "CAIRO", "loc" : [ -92.440027, 39.51141 ], "pop" : 1143, "state" : "MO" }
+{ "_id" : "65240", "city" : "CENTRALIA", "loc" : [ -92.147244, 39.196089 ], "pop" : 5171, "state" : "MO" }
+{ "_id" : "65243", "city" : "CLARK", "loc" : [ -92.382706, 39.315293 ], "pop" : 4672, "state" : "MO" }
+{ "_id" : "65244", "city" : "CLIFTON HILL", "loc" : [ -92.667676, 39.425985 ], "pop" : 341, "state" : "MO" }
+{ "_id" : "65246", "city" : "DALTON", "loc" : [ -92.994366, 39.40346 ], "pop" : 209, "state" : "MO" }
+{ "_id" : "65247", "city" : "EXCELLO", "loc" : [ -92.475705, 39.645543 ], "pop" : 873, "state" : "MO" }
+{ "_id" : "65248", "city" : "FAYETTE", "loc" : [ -92.658287, 39.143041 ], "pop" : 4805, "state" : "MO" }
+{ "_id" : "65250", "city" : "FRANKLIN", "loc" : [ -92.831596, 39.066818 ], "pop" : 680, "state" : "MO" }
+{ "_id" : "65251", "city" : "FULTON", "loc" : [ -91.96055, 38.851821 ], "pop" : 17506, "state" : "MO" }
+{ "_id" : "65254", "city" : "GLASGOW", "loc" : [ -92.831812, 39.225736 ], "pop" : 1757, "state" : "MO" }
+{ "_id" : "65255", "city" : "HALLSVILLE", "loc" : [ -92.223855, 39.105429 ], "pop" : 2476, "state" : "MO" }
+{ "_id" : "65256", "city" : "HARRISBURG", "loc" : [ -92.440955, 39.120312 ], "pop" : 928, "state" : "MO" }
+{ "_id" : "65257", "city" : "HIGBEE", "loc" : [ -92.51630900000001, 39.305521 ], "pop" : 932, "state" : "MO" }
+{ "_id" : "65258", "city" : "HOLLIDAY", "loc" : [ -92.131759, 39.490436 ], "pop" : 286, "state" : "MO" }
+{ "_id" : "65259", "city" : "HUNTSVILLE", "loc" : [ -92.552992, 39.435371 ], "pop" : 3210, "state" : "MO" }
+{ "_id" : "65260", "city" : "JACKSONVILLE", "loc" : [ -92.43153599999999, 39.579076 ], "pop" : 473, "state" : "MO" }
+{ "_id" : "65261", "city" : "KEYTESVILLE", "loc" : [ -92.930187, 39.479388 ], "pop" : 1354, "state" : "MO" }
+{ "_id" : "65262", "city" : "KINGDOM CITY", "loc" : [ -91.95200800000001, 38.95508 ], "pop" : 322, "state" : "MO" }
+{ "_id" : "65263", "city" : "MADISON", "loc" : [ -92.22871499999999, 39.461543 ], "pop" : 2000, "state" : "MO" }
+{ "_id" : "65264", "city" : "MARTINSBURG", "loc" : [ -91.66463, 39.09675 ], "pop" : 644, "state" : "MO" }
+{ "_id" : "65265", "city" : "MEXICO", "loc" : [ -91.889473, 39.171233 ], "pop" : 14785, "state" : "MO" }
+{ "_id" : "65270", "city" : "MOBERLY", "loc" : [ -92.435793, 39.420239 ], "pop" : 14884, "state" : "MO" }
+{ "_id" : "65274", "city" : "NEW FRANKLIN", "loc" : [ -92.738601, 39.020042 ], "pop" : 1595, "state" : "MO" }
+{ "_id" : "65275", "city" : "PARIS", "loc" : [ -92.011323, 39.493219 ], "pop" : 3157, "state" : "MO" }
+{ "_id" : "65276", "city" : "PILOT GROVE", "loc" : [ -92.93046099999999, 38.871168 ], "pop" : 1492, "state" : "MO" }
+{ "_id" : "65279", "city" : "ROCHEPORT", "loc" : [ -92.50785399999999, 38.975578 ], "pop" : 1437, "state" : "MO" }
+{ "_id" : "65280", "city" : "RUSH HILL", "loc" : [ -91.68882499999999, 39.193163 ], "pop" : 646, "state" : "MO" }
+{ "_id" : "65281", "city" : "SALISBURY", "loc" : [ -92.80144, 39.431853 ], "pop" : 4022, "state" : "MO" }
+{ "_id" : "65282", "city" : "SANTA FE", "loc" : [ -91.82937699999999, 39.398929 ], "pop" : 712, "state" : "MO" }
+{ "_id" : "65283", "city" : "STOUTSVILLE", "loc" : [ -91.829661, 39.559425 ], "pop" : 361, "state" : "MO" }
+{ "_id" : "65284", "city" : "STURGEON", "loc" : [ -92.295264, 39.205705 ], "pop" : 1812, "state" : "MO" }
+{ "_id" : "65285", "city" : "THOMPSON", "loc" : [ -92.02594499999999, 39.20258 ], "pop" : 1230, "state" : "MO" }
+{ "_id" : "65286", "city" : "TRIPLETT", "loc" : [ -93.19277099999999, 39.501098 ], "pop" : 192, "state" : "MO" }
+{ "_id" : "65287", "city" : "WOOLDRIDGE", "loc" : [ -92.582584, 38.919475 ], "pop" : 571, "state" : "MO" }
+{ "_id" : "65301", "city" : "SEDALIA", "loc" : [ -93.232268, 38.696076 ], "pop" : 28813, "state" : "MO" }
+{ "_id" : "65305", "city" : "WHITEMAN AFB", "loc" : [ -93.572514, 38.731683 ], "pop" : 4222, "state" : "MO" }
+{ "_id" : "65321", "city" : "BLACKBURN", "loc" : [ -93.428124, 39.098776 ], "pop" : 777, "state" : "MO" }
+{ "_id" : "65322", "city" : "BLACKWATER", "loc" : [ -92.96829099999999, 38.972659 ], "pop" : 713, "state" : "MO" }
+{ "_id" : "65323", "city" : "CALHOUN", "loc" : [ -93.645929, 38.485842 ], "pop" : 795, "state" : "MO" }
+{ "_id" : "65324", "city" : "CLIMAX SPRINGS", "loc" : [ -92.95371, 38.139586 ], "pop" : 1840, "state" : "MO" }
+{ "_id" : "65325", "city" : "COLE CAMP", "loc" : [ -93.191529, 38.453124 ], "pop" : 2570, "state" : "MO" }
+{ "_id" : "65326", "city" : "EDWARDS", "loc" : [ -93.147104, 38.190564 ], "pop" : 1320, "state" : "MO" }
+{ "_id" : "65329", "city" : "FLORENCE", "loc" : [ -92.998606, 38.610056 ], "pop" : 847, "state" : "MO" }
+{ "_id" : "65330", "city" : "GILLIAM", "loc" : [ -92.993222, 39.244708 ], "pop" : 476, "state" : "MO" }
+{ "_id" : "65332", "city" : "GREEN RIDGE", "loc" : [ -93.437395, 38.618983 ], "pop" : 1198, "state" : "MO" }
+{ "_id" : "65333", "city" : "HOUSTONIA", "loc" : [ -93.332531, 38.910581 ], "pop" : 699, "state" : "MO" }
+{ "_id" : "65334", "city" : "HUGHESVILLE", "loc" : [ -93.215895, 38.84944 ], "pop" : 1279, "state" : "MO" }
+{ "_id" : "65335", "city" : "IONIA", "loc" : [ -93.32235799999999, 38.501887 ], "pop" : 175, "state" : "MO" }
+{ "_id" : "65336", "city" : "KNOB NOSTER", "loc" : [ -93.556422, 38.746932 ], "pop" : 4455, "state" : "MO" }
+{ "_id" : "65337", "city" : "LA MONTE", "loc" : [ -93.43126599999999, 38.775256 ], "pop" : 1570, "state" : "MO" }
+{ "_id" : "65338", "city" : "LINCOLN", "loc" : [ -93.3668, 38.407271 ], "pop" : 1810, "state" : "MO" }
+{ "_id" : "65339", "city" : "GRAND PASS", "loc" : [ -93.381325, 39.195108 ], "pop" : 622, "state" : "MO" }
+{ "_id" : "65340", "city" : "NAPTON", "loc" : [ -93.196017, 39.10983 ], "pop" : 15086, "state" : "MO" }
+{ "_id" : "65344", "city" : "MIAMI", "loc" : [ -93.19678, 39.282095 ], "pop" : 569, "state" : "MO" }
+{ "_id" : "65345", "city" : "MORA", "loc" : [ -93.227232, 38.520726 ], "pop" : 132, "state" : "MO" }
+{ "_id" : "65347", "city" : "NELSON", "loc" : [ -93.031102, 39.010447 ], "pop" : 836, "state" : "MO" }
+{ "_id" : "65348", "city" : "OTTERVILLE", "loc" : [ -93.010819, 38.71607 ], "pop" : 853, "state" : "MO" }
+{ "_id" : "65349", "city" : "SLATER", "loc" : [ -93.05467400000001, 39.216273 ], "pop" : 2872, "state" : "MO" }
+{ "_id" : "65350", "city" : "SMITHTON", "loc" : [ -93.10807200000001, 38.649973 ], "pop" : 1669, "state" : "MO" }
+{ "_id" : "65351", "city" : "SWEET SPRINGS", "loc" : [ -93.424683, 38.965953 ], "pop" : 2385, "state" : "MO" }
+{ "_id" : "65354", "city" : "SYRACUSE", "loc" : [ -92.882265, 38.637423 ], "pop" : 730, "state" : "MO" }
+{ "_id" : "65355", "city" : "WARSAW", "loc" : [ -93.337279, 38.250186 ], "pop" : 8108, "state" : "MO" }
+{ "_id" : "65360", "city" : "WINDSOR", "loc" : [ -93.526864, 38.52719 ], "pop" : 3453, "state" : "MO" }
+{ "_id" : "65401", "city" : "ROLLA", "loc" : [ -91.76034799999999, 37.948527 ], "pop" : 24377, "state" : "MO" }
+{ "_id" : "65433", "city" : "BENDAVIS", "loc" : [ -92.228174, 37.246803 ], "pop" : 44, "state" : "MO" }
+{ "_id" : "65436", "city" : "BEULAH", "loc" : [ -91.878714, 37.644469 ], "pop" : 546, "state" : "MO" }
+{ "_id" : "65438", "city" : "BIRCH TREE", "loc" : [ -91.50082, 36.947589 ], "pop" : 2586, "state" : "MO" }
+{ "_id" : "65439", "city" : "BIXBY", "loc" : [ -91.083461, 37.672244 ], "pop" : 464, "state" : "MO" }
+{ "_id" : "65440", "city" : "BOSS", "loc" : [ -91.210905, 37.637282 ], "pop" : 457, "state" : "MO" }
+{ "_id" : "65441", "city" : "BOURBON", "loc" : [ -91.22254, 38.172039 ], "pop" : 4456, "state" : "MO" }
+{ "_id" : "65443", "city" : "BRINKTOWN", "loc" : [ -92.12310600000001, 38.067282 ], "pop" : 946, "state" : "MO" }
+{ "_id" : "65444", "city" : "BUCYRUS", "loc" : [ -92.046536, 37.397197 ], "pop" : 1416, "state" : "MO" }
+{ "_id" : "65446", "city" : "CHERRYVILLE", "loc" : [ -91.234807, 37.806601 ], "pop" : 861, "state" : "MO" }
+{ "_id" : "65449", "city" : "COOK STATION", "loc" : [ -91.461631, 37.855234 ], "pop" : 347, "state" : "MO" }
+{ "_id" : "65452", "city" : "CROCKER", "loc" : [ -92.269998, 37.944611 ], "pop" : 2954, "state" : "MO" }
+{ "_id" : "65453", "city" : "CUBA", "loc" : [ -91.40814, 38.092553 ], "pop" : 7466, "state" : "MO" }
+{ "_id" : "65456", "city" : "DAVISVILLE", "loc" : [ -91.13287200000001, 37.792596 ], "pop" : 286, "state" : "MO" }
+{ "_id" : "65457", "city" : "DEVILS ELBOW", "loc" : [ -92.08569300000001, 37.85026 ], "pop" : 1717, "state" : "MO" }
+{ "_id" : "65459", "city" : "DIXON", "loc" : [ -92.089662, 37.984766 ], "pop" : 4779, "state" : "MO" }
+{ "_id" : "65461", "city" : "DUKE", "loc" : [ -91.99306300000001, 37.655001 ], "pop" : 166, "state" : "MO" }
+{ "_id" : "65462", "city" : "EDGAR SPRINGS", "loc" : [ -91.890579, 37.736505 ], "pop" : 1026, "state" : "MO" }
+{ "_id" : "65463", "city" : "ELDRIDGE", "loc" : [ -92.738202, 37.83456 ], "pop" : 892, "state" : "MO" }
+{ "_id" : "65464", "city" : "ELK CREEK", "loc" : [ -91.998812, 37.217087 ], "pop" : 540, "state" : "MO" }
+{ "_id" : "65466", "city" : "EMINENCE", "loc" : [ -91.451933, 37.162556 ], "pop" : 2450, "state" : "MO" }
+{ "_id" : "65468", "city" : "EUNICE", "loc" : [ -91.723191, 37.212277 ], "pop" : 215, "state" : "MO" }
+{ "_id" : "65470", "city" : "FALCON", "loc" : [ -92.34656200000001, 37.606099 ], "pop" : 561, "state" : "MO" }
+{ "_id" : "65473", "city" : "FORT LEONARD WOO", "loc" : [ -92.126345, 37.759856 ], "pop" : 16140, "state" : "MO" }
+{ "_id" : "65479", "city" : "HARTSHORN", "loc" : [ -91.683418, 37.284306 ], "pop" : 306, "state" : "MO" }
+{ "_id" : "65483", "city" : "HOUSTON", "loc" : [ -91.95298200000001, 37.321829 ], "pop" : 4497, "state" : "MO" }
+{ "_id" : "65484", "city" : "HUGGINS", "loc" : [ -92.148605, 37.266224 ], "pop" : 593, "state" : "MO" }
+{ "_id" : "65486", "city" : "IBERIA", "loc" : [ -92.298897, 38.121926 ], "pop" : 3704, "state" : "MO" }
+{ "_id" : "65501", "city" : "JADWIN", "loc" : [ -91.51588700000001, 37.473619 ], "pop" : 374, "state" : "MO" }
+{ "_id" : "65529", "city" : "JEROME", "loc" : [ -91.99057000000001, 37.92543 ], "pop" : 391, "state" : "MO" }
+{ "_id" : "65534", "city" : "LAQUEY", "loc" : [ -92.337901, 37.749378 ], "pop" : 798, "state" : "MO" }
+{ "_id" : "65535", "city" : "LEASBURG", "loc" : [ -91.2488, 38.081054 ], "pop" : 1061, "state" : "MO" }
+{ "_id" : "65536", "city" : "LEBANON", "loc" : [ -92.655029, 37.685049 ], "pop" : 20859, "state" : "MO" }
+{ "_id" : "65540", "city" : "ANUTT", "loc" : [ -91.715862, 37.743731 ], "pop" : 635, "state" : "MO" }
+{ "_id" : "65541", "city" : "LENOX", "loc" : [ -91.727735, 37.640757 ], "pop" : 640, "state" : "MO" }
+{ "_id" : "65542", "city" : "LICKING", "loc" : [ -91.855585, 37.509082 ], "pop" : 3545, "state" : "MO" }
+{ "_id" : "65543", "city" : "LYNCHBURG", "loc" : [ -92.320196, 37.505357 ], "pop" : 297, "state" : "MO" }
+{ "_id" : "65548", "city" : "MOUNTAIN VIEW", "loc" : [ -91.709937, 36.989197 ], "pop" : 3721, "state" : "MO" }
+{ "_id" : "65550", "city" : "NEWBURG", "loc" : [ -91.880683, 37.900778 ], "pop" : 2972, "state" : "MO" }
+{ "_id" : "65552", "city" : "PLATO", "loc" : [ -92.170913, 37.512231 ], "pop" : 1479, "state" : "MO" }
+{ "_id" : "65555", "city" : "RAYMONDVILLE", "loc" : [ -91.81308900000001, 37.356913 ], "pop" : 1145, "state" : "MO" }
+{ "_id" : "65556", "city" : "RICHLAND", "loc" : [ -92.39624499999999, 37.852752 ], "pop" : 3643, "state" : "MO" }
+{ "_id" : "65557", "city" : "ROBY", "loc" : [ -92.12218799999999, 37.496993 ], "pop" : 184, "state" : "MO" }
+{ "_id" : "65559", "city" : "SAINT JAMES", "loc" : [ -91.60756499999999, 38.005622 ], "pop" : 6315, "state" : "MO" }
+{ "_id" : "65560", "city" : "SALEM", "loc" : [ -91.525809, 37.616952 ], "pop" : 12088, "state" : "MO" }
+{ "_id" : "65564", "city" : "SOLO", "loc" : [ -91.95990500000001, 37.167052 ], "pop" : 309, "state" : "MO" }
+{ "_id" : "65565", "city" : "BERRYMAN", "loc" : [ -91.329337, 37.962998 ], "pop" : 4323, "state" : "MO" }
+{ "_id" : "65566", "city" : "VIBURNUM", "loc" : [ -91.128922, 37.715066 ], "pop" : 844, "state" : "MO" }
+{ "_id" : "65567", "city" : "STOUTLAND", "loc" : [ -92.51137300000001, 37.869338 ], "pop" : 1637, "state" : "MO" }
+{ "_id" : "65570", "city" : "SUCCESS", "loc" : [ -92.003621, 37.480533 ], "pop" : 210, "state" : "MO" }
+{ "_id" : "65571", "city" : "SUMMERSVILLE", "loc" : [ -91.68277, 37.148352 ], "pop" : 1199, "state" : "MO" }
+{ "_id" : "65573", "city" : "TERESITA", "loc" : [ -91.596553, 36.999728 ], "pop" : 573, "state" : "MO" }
+{ "_id" : "65580", "city" : "VICHY", "loc" : [ -91.77875, 38.097958 ], "pop" : 977, "state" : "MO" }
+{ "_id" : "65582", "city" : "VIENNA", "loc" : [ -91.94220799999999, 38.191926 ], "pop" : 1956, "state" : "MO" }
+{ "_id" : "65583", "city" : "SAINT ROBERT", "loc" : [ -92.198944, 37.817515 ], "pop" : 12431, "state" : "MO" }
+{ "_id" : "65586", "city" : "WESCO", "loc" : [ -91.349028, 37.873185 ], "pop" : 460, "state" : "MO" }
+{ "_id" : "65588", "city" : "WINONA", "loc" : [ -91.312059, 37.016869 ], "pop" : 2065, "state" : "MO" }
+{ "_id" : "65589", "city" : "YUKON", "loc" : [ -91.824377, 37.231108 ], "pop" : 476, "state" : "MO" }
+{ "_id" : "65590", "city" : "LONG LANE", "loc" : [ -92.930853, 37.580769 ], "pop" : 1589, "state" : "MO" }
+{ "_id" : "65591", "city" : "MONTREAL", "loc" : [ -92.547031, 37.985108 ], "pop" : 759, "state" : "MO" }
+{ "_id" : "65601", "city" : "ALDRICH", "loc" : [ -93.557642, 37.505667 ], "pop" : 1006, "state" : "MO" }
+{ "_id" : "65603", "city" : "ARCOLA", "loc" : [ -93.858718, 37.531254 ], "pop" : 420, "state" : "MO" }
+{ "_id" : "65604", "city" : "ASH GROVE", "loc" : [ -93.57813, 37.315972 ], "pop" : 1909, "state" : "MO" }
+{ "_id" : "65605", "city" : "JENKINS", "loc" : [ -93.71238, 36.947661 ], "pop" : 10006, "state" : "MO" }
+{ "_id" : "65606", "city" : "RIVERTON", "loc" : [ -91.392743, 36.702543 ], "pop" : 3224, "state" : "MO" }
+{ "_id" : "65608", "city" : "AVA", "loc" : [ -92.67654400000001, 36.940717 ], "pop" : 8246, "state" : "MO" }
+{ "_id" : "65609", "city" : "BAKERSFIELD", "loc" : [ -92.150679, 36.53323 ], "pop" : 560, "state" : "MO" }
+{ "_id" : "65610", "city" : "BILLINGS", "loc" : [ -93.547629, 37.062841 ], "pop" : 2408, "state" : "MO" }
+{ "_id" : "65611", "city" : "BLUE EYE", "loc" : [ -93.42994400000001, 36.54321 ], "pop" : 2148, "state" : "MO" }
+{ "_id" : "65612", "city" : "BOIS D ARC", "loc" : [ -93.54472199999999, 37.221417 ], "pop" : 2410, "state" : "MO" }
+{ "_id" : "65613", "city" : "BOLIVAR", "loc" : [ -93.412631, 37.608502 ], "pop" : 10671, "state" : "MO" }
+{ "_id" : "65614", "city" : "BRADLEYVILLE", "loc" : [ -92.915116, 36.765908 ], "pop" : 428, "state" : "MO" }
+{ "_id" : "65616", "city" : "MARVEL CAVE PARK", "loc" : [ -93.24378900000001, 36.655755 ], "pop" : 7658, "state" : "MO" }
+{ "_id" : "65617", "city" : "BRIGHTON", "loc" : [ -93.36027900000001, 37.472807 ], "pop" : 920, "state" : "MO" }
+{ "_id" : "65618", "city" : "BRIXEY", "loc" : [ -92.40264500000001, 36.758966 ], "pop" : 198, "state" : "MO" }
+{ "_id" : "65619", "city" : "BROOKLINE STATIO", "loc" : [ -93.383467, 37.127184 ], "pop" : 4541, "state" : "MO" }
+{ "_id" : "65620", "city" : "BRUNER", "loc" : [ -92.969241, 36.999002 ], "pop" : 737, "state" : "MO" }
+{ "_id" : "65622", "city" : "BUFFALO", "loc" : [ -93.10422800000001, 37.549842 ], "pop" : 4176, "state" : "MO" }
+{ "_id" : "65623", "city" : "BUTTERFIELD", "loc" : [ -93.912609, 36.745066 ], "pop" : 684, "state" : "MO" }
+{ "_id" : "65624", "city" : "CAPE FAIR", "loc" : [ -93.524255, 36.693776 ], "pop" : 1783, "state" : "MO" }
+{ "_id" : "65625", "city" : "CASSVILLE", "loc" : [ -93.84667, 36.678386 ], "pop" : 5416, "state" : "MO" }
+{ "_id" : "65626", "city" : "CAULFIELD", "loc" : [ -92.067773, 36.60353 ], "pop" : 1941, "state" : "MO" }
+{ "_id" : "65627", "city" : "CEDARCREEK", "loc" : [ -93.017239, 36.571013 ], "pop" : 407, "state" : "MO" }
+{ "_id" : "65629", "city" : "CHADWICK", "loc" : [ -93.04508199999999, 36.922041 ], "pop" : 326, "state" : "MO" }
+{ "_id" : "65630", "city" : "CHESTNUTRIDGE", "loc" : [ -93.10121700000001, 36.835283 ], "pop" : 188, "state" : "MO" }
+{ "_id" : "65631", "city" : "CLEVER", "loc" : [ -93.44747, 37.034796 ], "pop" : 1728, "state" : "MO" }
+{ "_id" : "65632", "city" : "CONWAY", "loc" : [ -92.7891, 37.508472 ], "pop" : 1451, "state" : "MO" }
+{ "_id" : "65633", "city" : "CRANE", "loc" : [ -93.530339, 36.925771 ], "pop" : 2918, "state" : "MO" }
+{ "_id" : "65634", "city" : "CROSS TIMBERS", "loc" : [ -93.19781, 38.023873 ], "pop" : 612, "state" : "MO" }
+{ "_id" : "65635", "city" : "DADEVILLE", "loc" : [ -93.695562, 37.510458 ], "pop" : 774, "state" : "MO" }
+{ "_id" : "65637", "city" : "DORA", "loc" : [ -92.237796, 36.756009 ], "pop" : 1163, "state" : "MO" }
+{ "_id" : "65638", "city" : "DRURY", "loc" : [ -92.36639599999999, 36.93193 ], "pop" : 735, "state" : "MO" }
+{ "_id" : "65640", "city" : "DUNNEGAN", "loc" : [ -93.52160499999999, 37.703137 ], "pop" : 755, "state" : "MO" }
+{ "_id" : "65641", "city" : "EAGLE ROCK", "loc" : [ -93.733609, 36.548035 ], "pop" : 1062, "state" : "MO" }
+{ "_id" : "65644", "city" : "ELKLAND", "loc" : [ -93.020983, 37.433591 ], "pop" : 1136, "state" : "MO" }
+{ "_id" : "65646", "city" : "EVERTON", "loc" : [ -93.68943400000001, 37.235428 ], "pop" : 675, "state" : "MO" }
+{ "_id" : "65647", "city" : "EXETER", "loc" : [ -93.970209, 36.681498 ], "pop" : 2264, "state" : "MO" }
+{ "_id" : "65648", "city" : "FAIR GROVE", "loc" : [ -93.142824, 37.372143 ], "pop" : 2079, "state" : "MO" }
+{ "_id" : "65649", "city" : "FAIR PLAY", "loc" : [ -93.60635499999999, 37.633496 ], "pop" : 1533, "state" : "MO" }
+{ "_id" : "65650", "city" : "FLEMINGTON", "loc" : [ -93.447131, 37.780268 ], "pop" : 642, "state" : "MO" }
+{ "_id" : "65652", "city" : "FORDLAND", "loc" : [ -92.911148, 37.14474 ], "pop" : 2080, "state" : "MO" }
+{ "_id" : "65653", "city" : "FORSYTH", "loc" : [ -93.114968, 36.69548 ], "pop" : 3870, "state" : "MO" }
+{ "_id" : "65654", "city" : "FREISTATT", "loc" : [ -93.89614400000001, 37.017563 ], "pop" : 515, "state" : "MO" }
+{ "_id" : "65655", "city" : "GAINESVILLE", "loc" : [ -92.416151, 36.590101 ], "pop" : 1987, "state" : "MO" }
+{ "_id" : "65656", "city" : "GALENA", "loc" : [ -93.48112999999999, 36.819835 ], "pop" : 2307, "state" : "MO" }
+{ "_id" : "65657", "city" : "GARRISON", "loc" : [ -92.99850000000001, 36.860997 ], "pop" : 362, "state" : "MO" }
+{ "_id" : "65658", "city" : "GOLDEN", "loc" : [ -93.62298800000001, 36.562486 ], "pop" : 1663, "state" : "MO" }
+{ "_id" : "65659", "city" : "GOODSON", "loc" : [ -93.237528, 37.707534 ], "pop" : 379, "state" : "MO" }
+{ "_id" : "65660", "city" : "GRAFF", "loc" : [ -92.264726, 37.326214 ], "pop" : 271, "state" : "MO" }
+{ "_id" : "65661", "city" : "GREENFIELD", "loc" : [ -93.840689, 37.419662 ], "pop" : 2041, "state" : "MO" }
+{ "_id" : "65662", "city" : "GROVESPRING", "loc" : [ -92.60014099999999, 37.494667 ], "pop" : 2121, "state" : "MO" }
+{ "_id" : "65663", "city" : "HALF WAY", "loc" : [ -93.241989, 37.601795 ], "pop" : 1270, "state" : "MO" }
+{ "_id" : "65666", "city" : "HARDENVILLE", "loc" : [ -92.367766, 36.592625 ], "pop" : 267, "state" : "MO" }
+{ "_id" : "65667", "city" : "HARTVILLE", "loc" : [ -92.518058, 37.273453 ], "pop" : 3040, "state" : "MO" }
+{ "_id" : "65668", "city" : "HERMITAGE", "loc" : [ -93.29790199999999, 37.896853 ], "pop" : 2575, "state" : "MO" }
+{ "_id" : "65669", "city" : "HIGHLANDVILLE", "loc" : [ -93.26802000000001, 36.94077 ], "pop" : 2106, "state" : "MO" }
+{ "_id" : "65672", "city" : "HOLLISTER", "loc" : [ -93.228585, 36.610727 ], "pop" : 5515, "state" : "MO" }
+{ "_id" : "65674", "city" : "HUMANSVILLE", "loc" : [ -93.579531, 37.792282 ], "pop" : 1541, "state" : "MO" }
+{ "_id" : "65675", "city" : "HURLEY", "loc" : [ -93.476803, 36.925425 ], "pop" : 766, "state" : "MO" }
+{ "_id" : "65676", "city" : "ISABELLA", "loc" : [ -92.605277, 36.574924 ], "pop" : 563, "state" : "MO" }
+{ "_id" : "65679", "city" : "KIRBYVILLE", "loc" : [ -93.168256, 36.642615 ], "pop" : 1794, "state" : "MO" }
+{ "_id" : "65680", "city" : "KISSEE MILLS", "loc" : [ -93.037733, 36.670446 ], "pop" : 826, "state" : "MO" }
+{ "_id" : "65681", "city" : "LAMPE", "loc" : [ -93.45160199999999, 36.576725 ], "pop" : 1087, "state" : "MO" }
+{ "_id" : "65682", "city" : "LOCKWOOD", "loc" : [ -93.86715, 37.386605 ], "pop" : 4042, "state" : "MO" }
+{ "_id" : "65685", "city" : "LOUISBURG", "loc" : [ -93.10069900000001, 37.682843 ], "pop" : 4530, "state" : "MO" }
+{ "_id" : "65686", "city" : "KIMBERLING CITY", "loc" : [ -93.43720999999999, 36.63928 ], "pop" : 3208, "state" : "MO" }
+{ "_id" : "65688", "city" : "BRANDSVILLE", "loc" : [ -91.735536, 36.584925 ], "pop" : 794, "state" : "MO" }
+{ "_id" : "65689", "city" : "CABOOL", "loc" : [ -92.11440899999999, 37.131366 ], "pop" : 4127, "state" : "MO" }
+{ "_id" : "65690", "city" : "COUCH", "loc" : [ -91.330991, 36.565268 ], "pop" : 995, "state" : "MO" }
+{ "_id" : "65692", "city" : "KOSHKONONG", "loc" : [ -91.630411, 36.605553 ], "pop" : 727, "state" : "MO" }
+{ "_id" : "65701", "city" : "MC CLURG", "loc" : [ -92.818018, 36.751465 ], "pop" : 76, "state" : "MO" }
+{ "_id" : "65702", "city" : "MACOMB", "loc" : [ -92.48206999999999, 37.104947 ], "pop" : 533, "state" : "MO" }
+{ "_id" : "65704", "city" : "MANSFIELD", "loc" : [ -92.593553, 37.1273 ], "pop" : 3368, "state" : "MO" }
+{ "_id" : "65705", "city" : "MARIONVILLE", "loc" : [ -93.641345, 37.000906 ], "pop" : 3305, "state" : "MO" }
+{ "_id" : "65706", "city" : "MARSHFIELD", "loc" : [ -92.925033, 37.331178 ], "pop" : 10026, "state" : "MO" }
+{ "_id" : "65707", "city" : "MILLER", "loc" : [ -93.84218799999999, 37.222454 ], "pop" : 1986, "state" : "MO" }
+{ "_id" : "65708", "city" : "MONETT", "loc" : [ -93.925766, 36.921242 ], "pop" : 9297, "state" : "MO" }
+{ "_id" : "65710", "city" : "MORRISVILLE", "loc" : [ -93.427486, 37.468588 ], "pop" : 689, "state" : "MO" }
+{ "_id" : "65711", "city" : "MOUNTAIN GROVE", "loc" : [ -92.28389300000001, 37.162638 ], "pop" : 7623, "state" : "MO" }
+{ "_id" : "65712", "city" : "MOUNT VERNON", "loc" : [ -93.79763199999999, 37.104466 ], "pop" : 6685, "state" : "MO" }
+{ "_id" : "65713", "city" : "NIANGUA", "loc" : [ -92.776337, 37.398537 ], "pop" : 2628, "state" : "MO" }
+{ "_id" : "65714", "city" : "NIXA", "loc" : [ -93.29717599999999, 37.051154 ], "pop" : 11346, "state" : "MO" }
+{ "_id" : "65715", "city" : "NOBLE", "loc" : [ -92.57686, 36.744052 ], "pop" : 103, "state" : "MO" }
+{ "_id" : "65717", "city" : "NORWOOD", "loc" : [ -92.408209, 37.068696 ], "pop" : 1535, "state" : "MO" }
+{ "_id" : "65720", "city" : "OLDFIELD", "loc" : [ -93.032526, 36.970416 ], "pop" : 409, "state" : "MO" }
+{ "_id" : "65721", "city" : "OZARK", "loc" : [ -93.20221100000001, 37.016926 ], "pop" : 8437, "state" : "MO" }
+{ "_id" : "65722", "city" : "PHILLIPSBURG", "loc" : [ -92.741631, 37.583177 ], "pop" : 1369, "state" : "MO" }
+{ "_id" : "65723", "city" : "PIERCE CITY", "loc" : [ -94.00241, 36.972992 ], "pop" : 2795, "state" : "MO" }
+{ "_id" : "65724", "city" : "PITTSBURG", "loc" : [ -93.335615, 37.8442 ], "pop" : 610, "state" : "MO" }
+{ "_id" : "65725", "city" : "PLEASANT HOPE", "loc" : [ -93.26173300000001, 37.4615 ], "pop" : 2079, "state" : "MO" }
+{ "_id" : "65727", "city" : "POLK", "loc" : [ -93.294065, 37.752928 ], "pop" : 725, "state" : "MO" }
+{ "_id" : "65728", "city" : "PONCE DE LEON", "loc" : [ -93.36705499999999, 36.89054 ], "pop" : 435, "state" : "MO" }
+{ "_id" : "65729", "city" : "PONTIAC", "loc" : [ -92.561221, 36.524804 ], "pop" : 293, "state" : "MO" }
+{ "_id" : "65730", "city" : "POWELL", "loc" : [ -94.167541, 36.556252 ], "pop" : 1681, "state" : "MO" }
+{ "_id" : "65731", "city" : "POWERSITE", "loc" : [ -93.09001499999999, 36.630656 ], "pop" : 742, "state" : "MO" }
+{ "_id" : "65732", "city" : "PRESTON", "loc" : [ -93.171295, 37.939025 ], "pop" : 753, "state" : "MO" }
+{ "_id" : "65733", "city" : "PROTEM", "loc" : [ -92.829689, 36.546336 ], "pop" : 375, "state" : "MO" }
+{ "_id" : "65734", "city" : "PURDY", "loc" : [ -93.916376, 36.806917 ], "pop" : 2906, "state" : "MO" }
+{ "_id" : "65735", "city" : "QUINCY", "loc" : [ -93.471281, 38.002925 ], "pop" : 241, "state" : "MO" }
+{ "_id" : "65737", "city" : "BRANSON WEST", "loc" : [ -93.372182, 36.694658 ], "pop" : 4426, "state" : "MO" }
+{ "_id" : "65738", "city" : "REPUBLIC", "loc" : [ -93.480041, 37.123017 ], "pop" : 8312, "state" : "MO" }
+{ "_id" : "65739", "city" : "RIDGEDALE", "loc" : [ -93.27780799999999, 36.524662 ], "pop" : 809, "state" : "MO" }
+{ "_id" : "65740", "city" : "ROCKAWAY BEACH", "loc" : [ -93.17153500000001, 36.713686 ], "pop" : 1354, "state" : "MO" }
+{ "_id" : "65742", "city" : "ROGERSVILLE", "loc" : [ -93.09644900000001, 37.131047 ], "pop" : 9409, "state" : "MO" }
+{ "_id" : "65744", "city" : "RUETER", "loc" : [ -92.918792, 36.631415 ], "pop" : 180, "state" : "MO" }
+{ "_id" : "65745", "city" : "SELIGMAN", "loc" : [ -93.935851, 36.527593 ], "pop" : 1392, "state" : "MO" }
+{ "_id" : "65746", "city" : "SEYMOUR", "loc" : [ -92.785659, 37.166726 ], "pop" : 5311, "state" : "MO" }
+{ "_id" : "65747", "city" : "SHELL KNOB", "loc" : [ -93.624855, 36.616672 ], "pop" : 821, "state" : "MO" }
+{ "_id" : "65752", "city" : "SOUTH GREENFIELD", "loc" : [ -93.844482, 37.374256 ], "pop" : 248, "state" : "MO" }
+{ "_id" : "65753", "city" : "SPARTA", "loc" : [ -93.106483, 36.977524 ], "pop" : 1879, "state" : "MO" }
+{ "_id" : "65754", "city" : "SPOKANE", "loc" : [ -93.275447, 36.863639 ], "pop" : 968, "state" : "MO" }
+{ "_id" : "65755", "city" : "SQUIRES", "loc" : [ -92.58444299999999, 36.850406 ], "pop" : 536, "state" : "MO" }
+{ "_id" : "65756", "city" : "STOTTS CITY", "loc" : [ -93.954329, 37.103148 ], "pop" : 497, "state" : "MO" }
+{ "_id" : "65757", "city" : "STRAFFORD", "loc" : [ -93.10663, 37.279718 ], "pop" : 3226, "state" : "MO" }
+{ "_id" : "65758", "city" : "SYCAMORE", "loc" : [ -92.354355, 36.67179 ], "pop" : 97, "state" : "MO" }
+{ "_id" : "65759", "city" : "TANEYVILLE", "loc" : [ -93.027951, 36.740497 ], "pop" : 731, "state" : "MO" }
+{ "_id" : "65760", "city" : "TECUMSEH", "loc" : [ -92.259782, 36.58751 ], "pop" : 444, "state" : "MO" }
+{ "_id" : "65761", "city" : "DUGGINSVILLE", "loc" : [ -92.70186099999999, 36.569019 ], "pop" : 962, "state" : "MO" }
+{ "_id" : "65762", "city" : "NOTTINGHILL", "loc" : [ -92.65778899999999, 36.707546 ], "pop" : 617, "state" : "MO" }
+{ "_id" : "65764", "city" : "TUNAS", "loc" : [ -92.980788, 37.839196 ], "pop" : 827, "state" : "MO" }
+{ "_id" : "65766", "city" : "UDALL", "loc" : [ -92.23345, 36.525291 ], "pop" : 184, "state" : "MO" }
+{ "_id" : "65767", "city" : "URBANA", "loc" : [ -93.150972, 37.85233 ], "pop" : 755, "state" : "MO" }
+{ "_id" : "65768", "city" : "VANZANT", "loc" : [ -92.21006800000001, 36.977829 ], "pop" : 1048, "state" : "MO" }
+{ "_id" : "65769", "city" : "VERONA", "loc" : [ -93.800505, 36.936964 ], "pop" : 2021, "state" : "MO" }
+{ "_id" : "65770", "city" : "WALNUT GROVE", "loc" : [ -93.504356, 37.394253 ], "pop" : 2374, "state" : "MO" }
+{ "_id" : "65771", "city" : "WALNUT SHADE", "loc" : [ -93.21482399999999, 36.770395 ], "pop" : 722, "state" : "MO" }
+{ "_id" : "65772", "city" : "WASHBURN", "loc" : [ -93.991974, 36.580703 ], "pop" : 1526, "state" : "MO" }
+{ "_id" : "65773", "city" : "SOUDER", "loc" : [ -92.58991, 36.782631 ], "pop" : 215, "state" : "MO" }
+{ "_id" : "65774", "city" : "WEAUBLEAU", "loc" : [ -93.53435500000001, 37.880393 ], "pop" : 814, "state" : "MO" }
+{ "_id" : "65775", "city" : "WEST PLAINS", "loc" : [ -91.871681, 36.728418 ], "pop" : 16362, "state" : "MO" }
+{ "_id" : "65776", "city" : "SOUTH FORK", "loc" : [ -91.91248400000001, 36.629312 ], "pop" : 194, "state" : "MO" }
+{ "_id" : "65777", "city" : "MOODY", "loc" : [ -91.989756, 36.533018 ], "pop" : 328, "state" : "MO" }
+{ "_id" : "65778", "city" : "MYRTLE", "loc" : [ -91.270584, 36.521697 ], "pop" : 404, "state" : "MO" }
+{ "_id" : "65779", "city" : "WHEATLAND", "loc" : [ -93.398129, 37.910283 ], "pop" : 1730, "state" : "MO" }
+{ "_id" : "65781", "city" : "WILLARD", "loc" : [ -93.425861, 37.296153 ], "pop" : 3690, "state" : "MO" }
+{ "_id" : "65783", "city" : "WINDYVILLE", "loc" : [ -92.93789099999999, 37.718209 ], "pop" : 769, "state" : "MO" }
+{ "_id" : "65784", "city" : "ZANONI", "loc" : [ -92.304677, 36.692518 ], "pop" : 274, "state" : "MO" }
+{ "_id" : "65785", "city" : "STOCKTON", "loc" : [ -93.796013, 37.72408 ], "pop" : 4635, "state" : "MO" }
+{ "_id" : "65786", "city" : "MACKS CREEK", "loc" : [ -92.96034899999999, 37.961563 ], "pop" : 1741, "state" : "MO" }
+{ "_id" : "65787", "city" : "ROACH", "loc" : [ -92.807456, 38.008825 ], "pop" : 1542, "state" : "MO" }
+{ "_id" : "65788", "city" : "PEACE VALLEY", "loc" : [ -91.769598, 36.837974 ], "pop" : 1074, "state" : "MO" }
+{ "_id" : "65789", "city" : "POMONA", "loc" : [ -91.913668, 36.84409 ], "pop" : 1309, "state" : "MO" }
+{ "_id" : "65790", "city" : "POTTERSVILLE", "loc" : [ -92.044044, 36.706822 ], "pop" : 1227, "state" : "MO" }
+{ "_id" : "65791", "city" : "THAYER", "loc" : [ -91.541803, 36.532714 ], "pop" : 3473, "state" : "MO" }
+{ "_id" : "65793", "city" : "WILLOW SPRINGS", "loc" : [ -91.940545, 36.995812 ], "pop" : 5968, "state" : "MO" }
+{ "_id" : "65802", "city" : "SPRINGFIELD", "loc" : [ -93.29903, 37.211663 ], "pop" : 33216, "state" : "MO" }
+{ "_id" : "65803", "city" : "SPRINGFIELD", "loc" : [ -93.29123199999999, 37.259327 ], "pop" : 41361, "state" : "MO" }
+{ "_id" : "65804", "city" : "SPRINGFIELD", "loc" : [ -93.252154, 37.165361 ], "pop" : 33507, "state" : "MO" }
+{ "_id" : "65806", "city" : "SPRINGFIELD", "loc" : [ -93.29710799999999, 37.203057 ], "pop" : 11386, "state" : "MO" }
+{ "_id" : "65807", "city" : "SPRINGFIELD", "loc" : [ -93.308457, 37.166799 ], "pop" : 46691, "state" : "MO" }
+{ "_id" : "65809", "city" : "SPRINGFIELD", "loc" : [ -93.205742, 37.185223 ], "pop" : 5606, "state" : "MO" }
+{ "_id" : "65810", "city" : "SPRINGFIELD", "loc" : [ -93.28959399999999, 37.113647 ], "pop" : 3982, "state" : "MO" }
+{ "_id" : "66002", "city" : "ATCHISON", "loc" : [ -95.130408, 39.559411 ], "pop" : 13463, "state" : "KS" }
+{ "_id" : "66006", "city" : "BALDWIN CITY", "loc" : [ -95.227621, 38.795308 ], "pop" : 6990, "state" : "KS" }
+{ "_id" : "66007", "city" : "BASEHOR", "loc" : [ -94.95703399999999, 39.128137 ], "pop" : 5182, "state" : "KS" }
+{ "_id" : "66008", "city" : "BENDENA", "loc" : [ -95.176458, 39.717379 ], "pop" : 334, "state" : "KS" }
+{ "_id" : "66010", "city" : "BLUE MOUND", "loc" : [ -95.005269, 38.090772 ], "pop" : 484, "state" : "KS" }
+{ "_id" : "66012", "city" : "LAKE OF THE FORE", "loc" : [ -94.886098, 39.068455 ], "pop" : 6315, "state" : "KS" }
+{ "_id" : "66013", "city" : "BUCYRUS", "loc" : [ -94.742947, 38.687017 ], "pop" : 989, "state" : "KS" }
+{ "_id" : "66014", "city" : "CENTERVILLE", "loc" : [ -94.993431, 38.213032 ], "pop" : 381, "state" : "KS" }
+{ "_id" : "66015", "city" : "COLONY", "loc" : [ -95.328705, 38.076147 ], "pop" : 806, "state" : "KS" }
+{ "_id" : "66016", "city" : "CUMMINGS", "loc" : [ -95.286281, 39.482976 ], "pop" : 647, "state" : "KS" }
+{ "_id" : "66017", "city" : "DENTON", "loc" : [ -95.274377, 39.715358 ], "pop" : 378, "state" : "KS" }
+{ "_id" : "66018", "city" : "DE SOTO", "loc" : [ -94.964713, 38.956563 ], "pop" : 4167, "state" : "KS" }
+{ "_id" : "66020", "city" : "EASTON", "loc" : [ -95.05435199999999, 39.362054 ], "pop" : 2801, "state" : "KS" }
+{ "_id" : "66021", "city" : "EDGERTON", "loc" : [ -95.009377, 38.781084 ], "pop" : 2101, "state" : "KS" }
+{ "_id" : "66023", "city" : "EFFINGHAM", "loc" : [ -95.41982, 39.502259 ], "pop" : 1303, "state" : "KS" }
+{ "_id" : "66025", "city" : "EUDORA", "loc" : [ -95.102206, 38.933043 ], "pop" : 4011, "state" : "KS" }
+{ "_id" : "66026", "city" : "FONTANA", "loc" : [ -94.871788, 38.410153 ], "pop" : 774, "state" : "KS" }
+{ "_id" : "66027", "city" : "FORT LEAVENWORTH", "loc" : [ -94.926547, 39.348508 ], "pop" : 12630, "state" : "KS" }
+{ "_id" : "66030", "city" : "GARDNER", "loc" : [ -94.91567499999999, 38.80754 ], "pop" : 5356, "state" : "KS" }
+{ "_id" : "66031", "city" : "INDUSTRIAL AIRPO", "loc" : [ -94.93226300000001, 38.850264 ], "pop" : 723, "state" : "KS" }
+{ "_id" : "66032", "city" : "GARNETT", "loc" : [ -95.25936799999999, 38.285907 ], "pop" : 5081, "state" : "KS" }
+{ "_id" : "66033", "city" : "GREELEY", "loc" : [ -95.11875999999999, 38.352428 ], "pop" : 671, "state" : "KS" }
+{ "_id" : "66035", "city" : "HIGHLAND", "loc" : [ -95.258335, 39.860752 ], "pop" : 1369, "state" : "KS" }
+{ "_id" : "66036", "city" : "HILLSDALE", "loc" : [ -94.85836999999999, 38.684463 ], "pop" : 1969, "state" : "KS" }
+{ "_id" : "66039", "city" : "MILDRED", "loc" : [ -95.145167, 38.091497 ], "pop" : 441, "state" : "KS" }
+{ "_id" : "66040", "city" : "LA CYGNE", "loc" : [ -94.759264, 38.343402 ], "pop" : 1958, "state" : "KS" }
+{ "_id" : "66041", "city" : "HURON", "loc" : [ -95.308902, 39.591202 ], "pop" : 890, "state" : "KS" }
+{ "_id" : "66042", "city" : "LANE", "loc" : [ -95.097886, 38.437499 ], "pop" : 582, "state" : "KS" }
+{ "_id" : "66043", "city" : "LANSING", "loc" : [ -94.899379, 39.250191 ], "pop" : 8145, "state" : "KS" }
+{ "_id" : "66044", "city" : "LAWRENCE", "loc" : [ -95.241789, 38.964402 ], "pop" : 29968, "state" : "KS" }
+{ "_id" : "66046", "city" : "LAWRENCE", "loc" : [ -95.24203, 38.936925 ], "pop" : 16411, "state" : "KS" }
+{ "_id" : "66047", "city" : "LAWRENCE", "loc" : [ -95.27786500000001, 38.940714 ], "pop" : 9234, "state" : "KS" }
+{ "_id" : "66048", "city" : "LEAVENWORTH", "loc" : [ -94.933865, 39.301546 ], "pop" : 28028, "state" : "KS" }
+{ "_id" : "66049", "city" : "LAWRENCE", "loc" : [ -95.27686199999999, 38.970433 ], "pop" : 12600, "state" : "KS" }
+{ "_id" : "66050", "city" : "LECOMPTON", "loc" : [ -95.402519, 39.000125 ], "pop" : 2701, "state" : "KS" }
+{ "_id" : "66052", "city" : "LINWOOD", "loc" : [ -94.991388, 39.020627 ], "pop" : 2036, "state" : "KS" }
+{ "_id" : "66053", "city" : "LOUISBURG", "loc" : [ -94.68290500000001, 38.607341 ], "pop" : 4720, "state" : "KS" }
+{ "_id" : "66054", "city" : "MC LOUTH", "loc" : [ -95.218295, 39.166763 ], "pop" : 2139, "state" : "KS" }
+{ "_id" : "66056", "city" : "MOUND CITY", "loc" : [ -94.81863199999999, 38.155954 ], "pop" : 1644, "state" : "KS" }
+{ "_id" : "66058", "city" : "MUSCOTAH", "loc" : [ -95.49845000000001, 39.588046 ], "pop" : 631, "state" : "KS" }
+{ "_id" : "66060", "city" : "NORTONVILLE", "loc" : [ -95.32357, 39.409532 ], "pop" : 932, "state" : "KS" }
+{ "_id" : "66061", "city" : "OLATHE", "loc" : [ -94.820359, 38.886548 ], "pop" : 31694, "state" : "KS" }
+{ "_id" : "66062", "city" : "OLATHE", "loc" : [ -94.77516799999999, 38.873287 ], "pop" : 32845, "state" : "KS" }
+{ "_id" : "66064", "city" : "OSAWATOMIE", "loc" : [ -94.96199, 38.488803 ], "pop" : 5887, "state" : "KS" }
+{ "_id" : "66066", "city" : "OSKALOOSA", "loc" : [ -95.313546, 39.215183 ], "pop" : 1832, "state" : "KS" }
+{ "_id" : "66067", "city" : "OTTAWA", "loc" : [ -95.274519, 38.614247 ], "pop" : 13830, "state" : "KS" }
+{ "_id" : "66070", "city" : "OZAWKIE", "loc" : [ -95.44038999999999, 39.213648 ], "pop" : 2123, "state" : "KS" }
+{ "_id" : "66071", "city" : "PAOLA", "loc" : [ -94.893694, 38.571999 ], "pop" : 9325, "state" : "KS" }
+{ "_id" : "66072", "city" : "PARKER", "loc" : [ -94.98707400000001, 38.330311 ], "pop" : 830, "state" : "KS" }
+{ "_id" : "66073", "city" : "PERRY", "loc" : [ -95.373122, 39.087524 ], "pop" : 2031, "state" : "KS" }
+{ "_id" : "66075", "city" : "PLEASANTON", "loc" : [ -94.70567, 38.182285 ], "pop" : 2050, "state" : "KS" }
+{ "_id" : "66076", "city" : "POMONA", "loc" : [ -95.448915, 38.615255 ], "pop" : 1680, "state" : "KS" }
+{ "_id" : "66078", "city" : "PRINCETON", "loc" : [ -95.276444, 38.484684 ], "pop" : 650, "state" : "KS" }
+{ "_id" : "66079", "city" : "RANTOUL", "loc" : [ -95.12342099999999, 38.566594 ], "pop" : 1195, "state" : "KS" }
+{ "_id" : "66080", "city" : "RICHMOND", "loc" : [ -95.24887099999999, 38.407434 ], "pop" : 833, "state" : "KS" }
+{ "_id" : "66083", "city" : "SPRING HILL", "loc" : [ -94.82459299999999, 38.763088 ], "pop" : 4024, "state" : "KS" }
+{ "_id" : "66085", "city" : "STILWELL", "loc" : [ -94.664282, 38.790157 ], "pop" : 4836, "state" : "KS" }
+{ "_id" : "66086", "city" : "TONGANOXIE", "loc" : [ -95.10505499999999, 39.102614 ], "pop" : 5556, "state" : "KS" }
+{ "_id" : "66087", "city" : "SEVERANCE", "loc" : [ -95.066345, 39.778746 ], "pop" : 2422, "state" : "KS" }
+{ "_id" : "66088", "city" : "VALLEY FALLS", "loc" : [ -95.46699599999999, 39.34843 ], "pop" : 2000, "state" : "KS" }
+{ "_id" : "66090", "city" : "WATHENA", "loc" : [ -94.92546, 39.762505 ], "pop" : 2825, "state" : "KS" }
+{ "_id" : "66091", "city" : "WELDA", "loc" : [ -95.309606, 38.168615 ], "pop" : 286, "state" : "KS" }
+{ "_id" : "66092", "city" : "WELLSVILLE", "loc" : [ -95.091573, 38.713676 ], "pop" : 2178, "state" : "KS" }
+{ "_id" : "66093", "city" : "WESTPHALIA", "loc" : [ -95.46651199999999, 38.171792 ], "pop" : 518, "state" : "KS" }
+{ "_id" : "66094", "city" : "WHITE CLOUD", "loc" : [ -95.298203, 39.962717 ], "pop" : 379, "state" : "KS" }
+{ "_id" : "66095", "city" : "WILLIAMSBURG", "loc" : [ -95.42261499999999, 38.490166 ], "pop" : 929, "state" : "KS" }
+{ "_id" : "66097", "city" : "WINCHESTER", "loc" : [ -95.26958399999999, 39.324531 ], "pop" : 1191, "state" : "KS" }
+{ "_id" : "66101", "city" : "KANSAS CITY", "loc" : [ -94.627139, 39.115733 ], "pop" : 16147, "state" : "KS" }
+{ "_id" : "66102", "city" : "KANSAS CITY", "loc" : [ -94.669337, 39.113247 ], "pop" : 27909, "state" : "KS" }
+{ "_id" : "66103", "city" : "ROSEDALE", "loc" : [ -94.625105, 39.056193 ], "pop" : 14477, "state" : "KS" }
+{ "_id" : "66104", "city" : "KANSAS CITY", "loc" : [ -94.679158, 39.137512 ], "pop" : 32071, "state" : "KS" }
+{ "_id" : "66105", "city" : "KANSAS CITY", "loc" : [ -94.63564599999999, 39.085025 ], "pop" : 3478, "state" : "KS" }
+{ "_id" : "66106", "city" : "LAKE QUIVIRA", "loc" : [ -94.68739600000001, 39.061187 ], "pop" : 25298, "state" : "KS" }
+{ "_id" : "66109", "city" : "KANSAS CITY", "loc" : [ -94.78559799999999, 39.143376 ], "pop" : 14656, "state" : "KS" }
+{ "_id" : "66111", "city" : "KANSAS CITY", "loc" : [ -94.780593, 39.080332 ], "pop" : 11189, "state" : "KS" }
+{ "_id" : "66112", "city" : "KANSAS CITY", "loc" : [ -94.76402400000001, 39.115999 ], "pop" : 11461, "state" : "KS" }
+{ "_id" : "66115", "city" : "KANSAS CITY", "loc" : [ -94.61464700000001, 39.114534 ], "pop" : 0, "state" : "KS" }
+{ "_id" : "66118", "city" : "KANSAS CITY", "loc" : [ -94.608361, 39.096867 ], "pop" : 0, "state" : "KS" }
+{ "_id" : "66202", "city" : "COUNTRYSIDE", "loc" : [ -94.66699800000001, 39.025376 ], "pop" : 17916, "state" : "KS" }
+{ "_id" : "66203", "city" : "SHAWNEE", "loc" : [ -94.708303, 39.019802 ], "pop" : 20922, "state" : "KS" }
+{ "_id" : "66204", "city" : "OVERLAND PARK", "loc" : [ -94.674769, 38.992488 ], "pop" : 18226, "state" : "KS" }
+{ "_id" : "66205", "city" : "MISSION", "loc" : [ -94.631806, 39.031944 ], "pop" : 14871, "state" : "KS" }
+{ "_id" : "66206", "city" : "LEAWOOD", "loc" : [ -94.61964399999999, 38.960567 ], "pop" : 9797, "state" : "KS" }
+{ "_id" : "66207", "city" : "SHAWNEE MISSION", "loc" : [ -94.64519300000001, 38.957472 ], "pop" : 13863, "state" : "KS" }
+{ "_id" : "66208", "city" : "PRAIRIE VILLAGE", "loc" : [ -94.631513, 38.996812 ], "pop" : 22047, "state" : "KS" }
+{ "_id" : "66209", "city" : "LEAWOOD", "loc" : [ -94.634047, 38.901798 ], "pop" : 12176, "state" : "KS" }
+{ "_id" : "66210", "city" : "LENEXA", "loc" : [ -94.70478799999999, 38.922007 ], "pop" : 17576, "state" : "KS" }
+{ "_id" : "66211", "city" : "LEAWOOD", "loc" : [ -94.637991, 38.925956 ], "pop" : 2155, "state" : "KS" }
+{ "_id" : "66212", "city" : "OVERLAND PARK", "loc" : [ -94.68414, 38.958954 ], "pop" : 36187, "state" : "KS" }
+{ "_id" : "66213", "city" : "OVERLAND PARK", "loc" : [ -94.700344, 38.904899 ], "pop" : 7368, "state" : "KS" }
+{ "_id" : "66214", "city" : "LENEXA", "loc" : [ -94.71326500000001, 38.959929 ], "pop" : 12365, "state" : "KS" }
+{ "_id" : "66215", "city" : "LENEXA", "loc" : [ -94.739947, 38.963028 ], "pop" : 24051, "state" : "KS" }
+{ "_id" : "66216", "city" : "SHAWNEE", "loc" : [ -94.73823400000001, 39.009289 ], "pop" : 19644, "state" : "KS" }
+{ "_id" : "66217", "city" : "SHAWNEE", "loc" : [ -94.779663, 39.004835 ], "pop" : 2261, "state" : "KS" }
+{ "_id" : "66218", "city" : "SHAWNEE", "loc" : [ -94.823913, 39.017431 ], "pop" : 1828, "state" : "KS" }
+{ "_id" : "66219", "city" : "LENEXA", "loc" : [ -94.773145, 38.961896 ], "pop" : 6090, "state" : "KS" }
+{ "_id" : "66220", "city" : "LENEXA", "loc" : [ -94.82999700000001, 38.96884 ], "pop" : 626, "state" : "KS" }
+{ "_id" : "66221", "city" : "STANLEY", "loc" : [ -94.706745, 38.85272 ], "pop" : 1186, "state" : "KS" }
+{ "_id" : "66223", "city" : "STANLEY", "loc" : [ -94.664467, 38.848477 ], "pop" : 3539, "state" : "KS" }
+{ "_id" : "66224", "city" : "STANLEY", "loc" : [ -94.62890299999999, 38.867526 ], "pop" : 713, "state" : "KS" }
+{ "_id" : "66226", "city" : "SHAWNEE", "loc" : [ -94.873017, 38.997764 ], "pop" : 2613, "state" : "KS" }
+{ "_id" : "66227", "city" : "LENEXA", "loc" : [ -94.840082, 38.99416 ], "pop" : 273, "state" : "KS" }
+{ "_id" : "66401", "city" : "ALMA", "loc" : [ -96.292323, 39.009206 ], "pop" : 2186, "state" : "KS" }
+{ "_id" : "66402", "city" : "AUBURN", "loc" : [ -95.81993799999999, 38.916673 ], "pop" : 2157, "state" : "KS" }
+{ "_id" : "66403", "city" : "AXTELL", "loc" : [ -96.26755900000001, 39.870676 ], "pop" : 669, "state" : "KS" }
+{ "_id" : "66404", "city" : "BAILEYVILLE", "loc" : [ -96.180136, 39.881621 ], "pop" : 613, "state" : "KS" }
+{ "_id" : "66406", "city" : "BEATTIE", "loc" : [ -96.428618, 39.89884 ], "pop" : 739, "state" : "KS" }
+{ "_id" : "66407", "city" : "BELVUE", "loc" : [ -96.186635, 39.2273 ], "pop" : 321, "state" : "KS" }
+{ "_id" : "66408", "city" : "BERN", "loc" : [ -95.961028, 39.957051 ], "pop" : 457, "state" : "KS" }
+{ "_id" : "66409", "city" : "BERRYTON", "loc" : [ -95.582487, 38.944182 ], "pop" : 1939, "state" : "KS" }
+{ "_id" : "66411", "city" : "BLUE RAPIDS", "loc" : [ -96.63594999999999, 39.674974 ], "pop" : 1552, "state" : "KS" }
+{ "_id" : "66412", "city" : "BREMEN", "loc" : [ -96.745846, 39.877473 ], "pop" : 347, "state" : "KS" }
+{ "_id" : "66413", "city" : "BURLINGAME", "loc" : [ -95.840017, 38.763395 ], "pop" : 1994, "state" : "KS" }
+{ "_id" : "66414", "city" : "CARBONDALE", "loc" : [ -95.687083, 38.820622 ], "pop" : 2502, "state" : "KS" }
+{ "_id" : "66415", "city" : "CENTRALIA", "loc" : [ -96.14860400000001, 39.738051 ], "pop" : 782, "state" : "KS" }
+{ "_id" : "66416", "city" : "CIRCLEVILLE", "loc" : [ -95.851708, 39.515472 ], "pop" : 466, "state" : "KS" }
+{ "_id" : "66417", "city" : "CORNING", "loc" : [ -96.077589, 39.657015 ], "pop" : 656, "state" : "KS" }
+{ "_id" : "66418", "city" : "DELIA", "loc" : [ -95.96080499999999, 39.265453 ], "pop" : 557, "state" : "KS" }
+{ "_id" : "66419", "city" : "DENISON", "loc" : [ -95.632851, 39.415307 ], "pop" : 604, "state" : "KS" }
+{ "_id" : "66420", "city" : "DOVER", "loc" : [ -95.89854699999999, 39.019223 ], "pop" : 1220, "state" : "KS" }
+{ "_id" : "66422", "city" : "EMMETT", "loc" : [ -96.059325, 39.304819 ], "pop" : 342, "state" : "KS" }
+{ "_id" : "66423", "city" : "ESKRIDGE", "loc" : [ -96.10158300000001, 38.851361 ], "pop" : 771, "state" : "KS" }
+{ "_id" : "66424", "city" : "EVEREST", "loc" : [ -95.413802, 39.687972 ], "pop" : 525, "state" : "KS" }
+{ "_id" : "66425", "city" : "FAIRVIEW", "loc" : [ -95.711012, 39.844504 ], "pop" : 712, "state" : "KS" }
+{ "_id" : "66427", "city" : "WINIFRED", "loc" : [ -96.42832300000001, 39.718996 ], "pop" : 1418, "state" : "KS" }
+{ "_id" : "66428", "city" : "GOFF", "loc" : [ -95.95739399999999, 39.665388 ], "pop" : 537, "state" : "KS" }
+{ "_id" : "66429", "city" : "GRANTVILLE", "loc" : [ -95.539733, 39.097208 ], "pop" : 753, "state" : "KS" }
+{ "_id" : "66431", "city" : "HARVEYVILLE", "loc" : [ -95.996239, 38.857413 ], "pop" : 1065, "state" : "KS" }
+{ "_id" : "66432", "city" : "HAVENSVILLE", "loc" : [ -96.07688400000001, 39.494197 ], "pop" : 417, "state" : "KS" }
+{ "_id" : "66433", "city" : "HERKIMER", "loc" : [ -96.746861, 39.956337 ], "pop" : 270, "state" : "KS" }
+{ "_id" : "66434", "city" : "RESERVE", "loc" : [ -95.52890499999999, 39.871563 ], "pop" : 5297, "state" : "KS" }
+{ "_id" : "66436", "city" : "HOLTON", "loc" : [ -95.752498, 39.443624 ], "pop" : 5625, "state" : "KS" }
+{ "_id" : "66438", "city" : "HOME", "loc" : [ -96.529201, 39.854542 ], "pop" : 362, "state" : "KS" }
+{ "_id" : "66439", "city" : "HORTON", "loc" : [ -95.529858, 39.678883 ], "pop" : 2556, "state" : "KS" }
+{ "_id" : "66440", "city" : "HOYT", "loc" : [ -95.686742, 39.255249 ], "pop" : 1812, "state" : "KS" }
+{ "_id" : "66441", "city" : "JUNCTION CITY", "loc" : [ -96.839553, 39.029913 ], "pop" : 24386, "state" : "KS" }
+{ "_id" : "66442", "city" : "FORT RILEY", "loc" : [ -96.78733800000001, 39.061947 ], "pop" : 5363, "state" : "KS" }
+{ "_id" : "66449", "city" : "LEONARDVILLE", "loc" : [ -96.83122299999999, 39.365151 ], "pop" : 1274, "state" : "KS" }
+{ "_id" : "66450", "city" : "LOUISVILLE", "loc" : [ -96.316954, 39.267048 ], "pop" : 318, "state" : "KS" }
+{ "_id" : "66451", "city" : "LYNDON", "loc" : [ -95.680226, 38.635649 ], "pop" : 1879, "state" : "KS" }
+{ "_id" : "66502", "city" : "MANHATTAN", "loc" : [ -96.585776, 39.193757 ], "pop" : 50178, "state" : "KS" }
+{ "_id" : "66507", "city" : "MAPLE HILL", "loc" : [ -96.018727, 39.069456 ], "pop" : 796, "state" : "KS" }
+{ "_id" : "66508", "city" : "MARYSVILLE", "loc" : [ -96.642183, 39.842827 ], "pop" : 4104, "state" : "KS" }
+{ "_id" : "66509", "city" : "MAYETTA", "loc" : [ -95.692753, 39.348915 ], "pop" : 1132, "state" : "KS" }
+{ "_id" : "66510", "city" : "MELVERN", "loc" : [ -95.628986, 38.50266 ], "pop" : 856, "state" : "KS" }
+{ "_id" : "66512", "city" : "MERIDEN", "loc" : [ -95.54763699999999, 39.203832 ], "pop" : 2299, "state" : "KS" }
+{ "_id" : "66514", "city" : "MILFORD", "loc" : [ -96.91005, 39.169173 ], "pop" : 704, "state" : "KS" }
+{ "_id" : "66515", "city" : "MORRILL", "loc" : [ -95.712048, 39.935592 ], "pop" : 591, "state" : "KS" }
+{ "_id" : "66516", "city" : "NETAWAKA", "loc" : [ -95.72700399999999, 39.606298 ], "pop" : 371, "state" : "KS" }
+{ "_id" : "66517", "city" : "OGDEN", "loc" : [ -96.70007699999999, 39.119219 ], "pop" : 2049, "state" : "KS" }
+{ "_id" : "66518", "city" : "OKETO", "loc" : [ -96.623525, 39.95984 ], "pop" : 318, "state" : "KS" }
+{ "_id" : "66520", "city" : "OLSBURG", "loc" : [ -96.60024900000001, 39.412506 ], "pop" : 581, "state" : "KS" }
+{ "_id" : "66521", "city" : "DULUTH", "loc" : [ -96.17610500000001, 39.472974 ], "pop" : 1358, "state" : "KS" }
+{ "_id" : "66522", "city" : "ONEIDA", "loc" : [ -95.958097, 39.866087 ], "pop" : 247, "state" : "KS" }
+{ "_id" : "66523", "city" : "OSAGE CITY", "loc" : [ -95.830303, 38.626896 ], "pop" : 3627, "state" : "KS" }
+{ "_id" : "66524", "city" : "OVERBROOK", "loc" : [ -95.561632, 38.792173 ], "pop" : 1630, "state" : "KS" }
+{ "_id" : "66526", "city" : "PAXICO", "loc" : [ -96.181777, 39.080285 ], "pop" : 1153, "state" : "KS" }
+{ "_id" : "66527", "city" : "POWHATTAN", "loc" : [ -95.675111, 39.71769 ], "pop" : 913, "state" : "KS" }
+{ "_id" : "66528", "city" : "QUENEMO", "loc" : [ -95.53619, 38.578504 ], "pop" : 500, "state" : "KS" }
+{ "_id" : "66531", "city" : "RILEY", "loc" : [ -96.811824, 39.122421 ], "pop" : 14793, "state" : "KS" }
+{ "_id" : "66532", "city" : "LEONA", "loc" : [ -95.386236, 39.812721 ], "pop" : 671, "state" : "KS" }
+{ "_id" : "66533", "city" : "ROSSVILLE", "loc" : [ -95.95529999999999, 39.145114 ], "pop" : 1583, "state" : "KS" }
+{ "_id" : "66534", "city" : "SABETHA", "loc" : [ -95.811271, 39.89929 ], "pop" : 3242, "state" : "KS" }
+{ "_id" : "66535", "city" : "SAINT GEORGE", "loc" : [ -96.434488, 39.210806 ], "pop" : 1904, "state" : "KS" }
+{ "_id" : "66536", "city" : "SAINT MARYS", "loc" : [ -96.06827699999999, 39.198674 ], "pop" : 2316, "state" : "KS" }
+{ "_id" : "66537", "city" : "SCRANTON", "loc" : [ -95.74799, 38.787998 ], "pop" : 1158, "state" : "KS" }
+{ "_id" : "66538", "city" : "KELLY", "loc" : [ -96.059489, 39.839804 ], "pop" : 3336, "state" : "KS" }
+{ "_id" : "66539", "city" : "SILVER LAKE", "loc" : [ -95.855182, 39.1102 ], "pop" : 2152, "state" : "KS" }
+{ "_id" : "66540", "city" : "SOLDIER", "loc" : [ -95.96517799999999, 39.501254 ], "pop" : 578, "state" : "KS" }
+{ "_id" : "66541", "city" : "SUMMERFIELD", "loc" : [ -96.32790900000001, 39.979847 ], "pop" : 271, "state" : "KS" }
+{ "_id" : "66542", "city" : "TECUMSEH", "loc" : [ -95.537926, 39.021664 ], "pop" : 1059, "state" : "KS" }
+{ "_id" : "66543", "city" : "VASSAR", "loc" : [ -95.581278, 38.669127 ], "pop" : 849, "state" : "KS" }
+{ "_id" : "66544", "city" : "VLIETS", "loc" : [ -96.28164200000001, 39.705044 ], "pop" : 469, "state" : "KS" }
+{ "_id" : "66546", "city" : "WAKARUSA", "loc" : [ -95.701464, 38.904543 ], "pop" : 855, "state" : "KS" }
+{ "_id" : "66547", "city" : "WAMEGO", "loc" : [ -96.315344, 39.210001 ], "pop" : 5200, "state" : "KS" }
+{ "_id" : "66548", "city" : "WATERVILLE", "loc" : [ -96.749781, 39.697088 ], "pop" : 1116, "state" : "KS" }
+{ "_id" : "66549", "city" : "BLAINE", "loc" : [ -96.411402, 39.416545 ], "pop" : 1373, "state" : "KS" }
+{ "_id" : "66550", "city" : "WETMORE", "loc" : [ -95.82311799999999, 39.642761 ], "pop" : 546, "state" : "KS" }
+{ "_id" : "66551", "city" : "ONAGA", "loc" : [ -96.314753, 39.510969 ], "pop" : 238, "state" : "KS" }
+{ "_id" : "66552", "city" : "WHITING", "loc" : [ -95.61584000000001, 39.597396 ], "pop" : 380, "state" : "KS" }
+{ "_id" : "66554", "city" : "RANDOLPH", "loc" : [ -96.782842, 39.487939 ], "pop" : 608, "state" : "KS" }
+{ "_id" : "66603", "city" : "TOPEKA", "loc" : [ -95.680212, 39.055344 ], "pop" : 2250, "state" : "KS" }
+{ "_id" : "66604", "city" : "TOPEKA", "loc" : [ -95.717831, 39.040549 ], "pop" : 23913, "state" : "KS" }
+{ "_id" : "66605", "city" : "TOPEKA", "loc" : [ -95.643894, 39.015076 ], "pop" : 20138, "state" : "KS" }
+{ "_id" : "66606", "city" : "TOPEKA", "loc" : [ -95.709458, 39.058345 ], "pop" : 13053, "state" : "KS" }
+{ "_id" : "66607", "city" : "TOPEKA", "loc" : [ -95.644858, 39.042111 ], "pop" : 9850, "state" : "KS" }
+{ "_id" : "66608", "city" : "TOPEKA", "loc" : [ -95.686651, 39.085812 ], "pop" : 7739, "state" : "KS" }
+{ "_id" : "66609", "city" : "TOPEKA", "loc" : [ -95.668069, 38.991899 ], "pop" : 6252, "state" : "KS" }
+{ "_id" : "66610", "city" : "TOPEKA", "loc" : [ -95.746061, 38.982213 ], "pop" : 4656, "state" : "KS" }
+{ "_id" : "66611", "city" : "TOPEKA", "loc" : [ -95.69815, 39.014152 ], "pop" : 10194, "state" : "KS" }
+{ "_id" : "66612", "city" : "TOPEKA", "loc" : [ -95.68180599999999, 39.042714 ], "pop" : 2949, "state" : "KS" }
+{ "_id" : "66614", "city" : "TOPEKA", "loc" : [ -95.746883, 39.015403 ], "pop" : 26238, "state" : "KS" }
+{ "_id" : "66615", "city" : "TOPEKA", "loc" : [ -95.790561, 39.04458 ], "pop" : 677, "state" : "KS" }
+{ "_id" : "66616", "city" : "TOPEKA", "loc" : [ -95.641302, 39.064479 ], "pop" : 6538, "state" : "KS" }
+{ "_id" : "66617", "city" : "TOPEKA", "loc" : [ -95.63838800000001, 39.127098 ], "pop" : 7779, "state" : "KS" }
+{ "_id" : "66618", "city" : "TOPEKA", "loc" : [ -95.70231, 39.132853 ], "pop" : 5436, "state" : "KS" }
+{ "_id" : "66619", "city" : "PAULINE", "loc" : [ -95.700728, 38.942859 ], "pop" : 2952, "state" : "KS" }
+{ "_id" : "66701", "city" : "HIATTVILLE", "loc" : [ -94.704221, 37.834159 ], "pop" : 11192, "state" : "KS" }
+{ "_id" : "66710", "city" : "ALTOONA", "loc" : [ -95.64833, 37.519669 ], "pop" : 905, "state" : "KS" }
+{ "_id" : "66711", "city" : "ARCADIA", "loc" : [ -94.654782, 37.634113 ], "pop" : 664, "state" : "KS" }
+{ "_id" : "66713", "city" : "BAXTER SPRINGS", "loc" : [ -94.739276, 37.028057 ], "pop" : 5434, "state" : "KS" }
+{ "_id" : "66714", "city" : "BENEDICT", "loc" : [ -95.624213, 37.651401 ], "pop" : 815, "state" : "KS" }
+{ "_id" : "66716", "city" : "BRONSON", "loc" : [ -95.030345, 37.921356 ], "pop" : 702, "state" : "KS" }
+{ "_id" : "66717", "city" : "BUFFALO", "loc" : [ -95.70141700000001, 37.701057 ], "pop" : 455, "state" : "KS" }
+{ "_id" : "66720", "city" : "CHANUTE", "loc" : [ -95.456962, 37.674928 ], "pop" : 10852, "state" : "KS" }
+{ "_id" : "66724", "city" : "CHEROKEE", "loc" : [ -94.842412, 37.369413 ], "pop" : 1397, "state" : "KS" }
+{ "_id" : "66725", "city" : "HALLOWELL", "loc" : [ -94.850227, 37.168992 ], "pop" : 4750, "state" : "KS" }
+{ "_id" : "66727", "city" : "COYVILLE", "loc" : [ -95.917164, 37.659167 ], "pop" : 331, "state" : "KS" }
+{ "_id" : "66728", "city" : "CRESTLINE", "loc" : [ -94.678275, 37.161226 ], "pop" : 478, "state" : "KS" }
+{ "_id" : "66732", "city" : "ELSMORE", "loc" : [ -95.154645, 37.80353 ], "pop" : 293, "state" : "KS" }
+{ "_id" : "66733", "city" : "ERIE", "loc" : [ -95.25138, 37.604395 ], "pop" : 2572, "state" : "KS" }
+{ "_id" : "66734", "city" : "FARLINGTON", "loc" : [ -94.847928, 37.6163 ], "pop" : 519, "state" : "KS" }
+{ "_id" : "66736", "city" : "LAFONTAINE", "loc" : [ -95.822898, 37.525622 ], "pop" : 3747, "state" : "KS" }
+{ "_id" : "66738", "city" : "FULTON", "loc" : [ -94.739591, 37.988279 ], "pop" : 404, "state" : "KS" }
+{ "_id" : "66739", "city" : "GALENA", "loc" : [ -94.655743, 37.063237 ], "pop" : 5961, "state" : "KS" }
+{ "_id" : "66740", "city" : "GALESBURG", "loc" : [ -95.310772, 37.469346 ], "pop" : 932, "state" : "KS" }
+{ "_id" : "66741", "city" : "GARLAND", "loc" : [ -94.672055, 37.717363 ], "pop" : 377, "state" : "KS" }
+{ "_id" : "66743", "city" : "GIRARD", "loc" : [ -94.85691300000001, 37.509129 ], "pop" : 3707, "state" : "KS" }
+{ "_id" : "66746", "city" : "HEPLER", "loc" : [ -94.989225, 37.657558 ], "pop" : 229, "state" : "KS" }
+{ "_id" : "66748", "city" : "HUMBOLDT", "loc" : [ -95.422006, 37.80446 ], "pop" : 3247, "state" : "KS" }
+{ "_id" : "66749", "city" : "CARLYLE", "loc" : [ -95.402146, 37.928244 ], "pop" : 7721, "state" : "KS" }
+{ "_id" : "66751", "city" : "LA HARPE", "loc" : [ -95.32319200000001, 37.92239 ], "pop" : 1966, "state" : "KS" }
+{ "_id" : "66753", "city" : "MC CUNE", "loc" : [ -95.03759100000001, 37.346754 ], "pop" : 1252, "state" : "KS" }
+{ "_id" : "66754", "city" : "MAPLETON", "loc" : [ -94.873519, 38.022821 ], "pop" : 351, "state" : "KS" }
+{ "_id" : "66755", "city" : "MORAN", "loc" : [ -95.164733, 37.934159 ], "pop" : 1214, "state" : "KS" }
+{ "_id" : "66756", "city" : "MULBERRY", "loc" : [ -94.683902, 37.544197 ], "pop" : 3096, "state" : "KS" }
+{ "_id" : "66757", "city" : "NEODESHA", "loc" : [ -95.676478, 37.425709 ], "pop" : 3664, "state" : "KS" }
+{ "_id" : "66758", "city" : "NEOSHO FALLS", "loc" : [ -95.54973200000001, 37.966883 ], "pop" : 392, "state" : "KS" }
+{ "_id" : "66759", "city" : "NEW ALBANY", "loc" : [ -95.912594, 37.544436 ], "pop" : 372, "state" : "KS" }
+{ "_id" : "66761", "city" : "PIQUA", "loc" : [ -95.59002599999999, 37.872847 ], "pop" : 206, "state" : "KS" }
+{ "_id" : "66762", "city" : "RADLEY", "loc" : [ -94.70225000000001, 37.413156 ], "pop" : 24845, "state" : "KS" }
+{ "_id" : "66767", "city" : "PRESCOTT", "loc" : [ -94.700841, 38.071802 ], "pop" : 600, "state" : "KS" }
+{ "_id" : "66769", "city" : "REDFIELD", "loc" : [ -94.828988, 37.856046 ], "pop" : 1224, "state" : "KS" }
+{ "_id" : "66770", "city" : "RIVERTON", "loc" : [ -94.67880100000001, 37.099262 ], "pop" : 564, "state" : "KS" }
+{ "_id" : "66771", "city" : "SAINT PAUL", "loc" : [ -95.168784, 37.518046 ], "pop" : 936, "state" : "KS" }
+{ "_id" : "66772", "city" : "SAVONBURG", "loc" : [ -95.154532, 37.751725 ], "pop" : 197, "state" : "KS" }
+{ "_id" : "66773", "city" : "CARONA", "loc" : [ -94.851961, 37.271102 ], "pop" : 1552, "state" : "KS" }
+{ "_id" : "66775", "city" : "STARK", "loc" : [ -95.138794, 37.681111 ], "pop" : 246, "state" : "KS" }
+{ "_id" : "66776", "city" : "THAYER", "loc" : [ -95.467083, 37.452657 ], "pop" : 1349, "state" : "KS" }
+{ "_id" : "66777", "city" : "TORONTO", "loc" : [ -95.936818, 37.795343 ], "pop" : 659, "state" : "KS" }
+{ "_id" : "66778", "city" : "TREECE", "loc" : [ -94.86904699999999, 37.039883 ], "pop" : 528, "state" : "KS" }
+{ "_id" : "66779", "city" : "UNIONTOWN", "loc" : [ -94.98136599999999, 37.811681 ], "pop" : 825, "state" : "KS" }
+{ "_id" : "66780", "city" : "WALNUT", "loc" : [ -95.045531, 37.59674 ], "pop" : 383, "state" : "KS" }
+{ "_id" : "66781", "city" : "LAWTON", "loc" : [ -94.743909, 37.298173 ], "pop" : 1515, "state" : "KS" }
+{ "_id" : "66783", "city" : "YATES CENTER", "loc" : [ -95.72893999999999, 37.880125 ], "pop" : 2859, "state" : "KS" }
+{ "_id" : "66801", "city" : "EMPORIA", "loc" : [ -96.187145, 38.418405 ], "pop" : 29401, "state" : "KS" }
+{ "_id" : "66830", "city" : "ADMIRE", "loc" : [ -96.101657, 38.639297 ], "pop" : 172, "state" : "KS" }
+{ "_id" : "66833", "city" : "BUSHONG", "loc" : [ -96.249968, 38.637522 ], "pop" : 88, "state" : "KS" }
+{ "_id" : "66834", "city" : "ALTA VISTA", "loc" : [ -96.479983, 38.86357 ], "pop" : 629, "state" : "KS" }
+{ "_id" : "66835", "city" : "AMERICUS", "loc" : [ -96.26075299999999, 38.509803 ], "pop" : 1491, "state" : "KS" }
+{ "_id" : "66838", "city" : "BURDICK", "loc" : [ -96.83963, 38.567369 ], "pop" : 230, "state" : "KS" }
+{ "_id" : "66839", "city" : "STRAWN", "loc" : [ -95.741162, 38.201596 ], "pop" : 4404, "state" : "KS" }
+{ "_id" : "66840", "city" : "BURNS", "loc" : [ -96.863435, 38.12216 ], "pop" : 593, "state" : "KS" }
+{ "_id" : "66842", "city" : "CASSODAY", "loc" : [ -96.674565, 38.029801 ], "pop" : 351, "state" : "KS" }
+{ "_id" : "66843", "city" : "CLEMENTS", "loc" : [ -96.77544399999999, 38.279757 ], "pop" : 200, "state" : "KS" }
+{ "_id" : "66845", "city" : "COTTONWOOD FALLS", "loc" : [ -96.541849, 38.356538 ], "pop" : 1183, "state" : "KS" }
+{ "_id" : "66846", "city" : "DUNLAP", "loc" : [ -96.497294, 38.667657 ], "pop" : 3831, "state" : "KS" }
+{ "_id" : "66849", "city" : "DWIGHT", "loc" : [ -96.580215, 38.838902 ], "pop" : 569, "state" : "KS" }
+{ "_id" : "66850", "city" : "ELMDALE", "loc" : [ -96.667464, 38.377924 ], "pop" : 168, "state" : "KS" }
+{ "_id" : "66851", "city" : "FLORENCE", "loc" : [ -96.934561, 38.241536 ], "pop" : 828, "state" : "KS" }
+{ "_id" : "66852", "city" : "GRIDLEY", "loc" : [ -95.887351, 38.101234 ], "pop" : 638, "state" : "KS" }
+{ "_id" : "66853", "city" : "HAMILTON", "loc" : [ -96.169133, 37.979122 ], "pop" : 600, "state" : "KS" }
+{ "_id" : "66854", "city" : "HARTFORD", "loc" : [ -95.999718, 38.28326 ], "pop" : 1006, "state" : "KS" }
+{ "_id" : "66856", "city" : "LEBO", "loc" : [ -95.822174, 38.416085 ], "pop" : 1708, "state" : "KS" }
+{ "_id" : "66857", "city" : "LE ROY", "loc" : [ -95.62265499999999, 38.087429 ], "pop" : 795, "state" : "KS" }
+{ "_id" : "66858", "city" : "ANTELOPE", "loc" : [ -96.96123, 38.481037 ], "pop" : 562, "state" : "KS" }
+{ "_id" : "66859", "city" : "LOST SPRINGS", "loc" : [ -96.979872, 38.565723 ], "pop" : 241, "state" : "KS" }
+{ "_id" : "66860", "city" : "MADISON", "loc" : [ -96.12128300000001, 38.127755 ], "pop" : 1430, "state" : "KS" }
+{ "_id" : "66861", "city" : "MARION", "loc" : [ -97.02045, 38.355444 ], "pop" : 3196, "state" : "KS" }
+{ "_id" : "66862", "city" : "MATFIELD GREEN", "loc" : [ -96.55410500000001, 38.144768 ], "pop" : 143, "state" : "KS" }
+{ "_id" : "66864", "city" : "NEOSHO RAPIDS", "loc" : [ -96.016824, 38.394762 ], "pop" : 865, "state" : "KS" }
+{ "_id" : "66865", "city" : "OLPE", "loc" : [ -96.18905599999999, 38.257774 ], "pop" : 1156, "state" : "KS" }
+{ "_id" : "66866", "city" : "PEABODY", "loc" : [ -97.118386, 38.173746 ], "pop" : 1927, "state" : "KS" }
+{ "_id" : "66868", "city" : "READING", "loc" : [ -95.98949, 38.529012 ], "pop" : 553, "state" : "KS" }
+{ "_id" : "66869", "city" : "STRONG CITY", "loc" : [ -96.51719199999999, 38.41292 ], "pop" : 1149, "state" : "KS" }
+{ "_id" : "66870", "city" : "VIRGIL", "loc" : [ -96.03293499999999, 37.897594 ], "pop" : 381, "state" : "KS" }
+{ "_id" : "66871", "city" : "WAVERLY", "loc" : [ -95.598201, 38.378214 ], "pop" : 1112, "state" : "KS" }
+{ "_id" : "66872", "city" : "WHITE CITY", "loc" : [ -96.763677, 38.78902 ], "pop" : 983, "state" : "KS" }
+{ "_id" : "66873", "city" : "WILSEY", "loc" : [ -96.670407, 38.633449 ], "pop" : 325, "state" : "KS" }
+{ "_id" : "66901", "city" : "RICE", "loc" : [ -97.662735, 39.559427 ], "pop" : 7733, "state" : "KS" }
+{ "_id" : "66930", "city" : "AGENDA", "loc" : [ -97.42698300000001, 39.702868 ], "pop" : 198, "state" : "KS" }
+{ "_id" : "66931", "city" : "AMES", "loc" : [ -97.538245, 39.533923 ], "pop" : 161, "state" : "KS" }
+{ "_id" : "66932", "city" : "ATHOL", "loc" : [ -98.90773299999999, 39.771872 ], "pop" : 164, "state" : "KS" }
+{ "_id" : "66933", "city" : "BARNES", "loc" : [ -96.867574, 39.684114 ], "pop" : 374, "state" : "KS" }
+{ "_id" : "66935", "city" : "BELLEVILLE", "loc" : [ -97.62901599999999, 39.824054 ], "pop" : 3863, "state" : "KS" }
+{ "_id" : "66936", "city" : "BURR OAK", "loc" : [ -98.34991100000001, 39.893177 ], "pop" : 583, "state" : "KS" }
+{ "_id" : "66937", "city" : "CLIFTON", "loc" : [ -97.261104, 39.620121 ], "pop" : 853, "state" : "KS" }
+{ "_id" : "66938", "city" : "CLYDE", "loc" : [ -97.407999, 39.575842 ], "pop" : 1164, "state" : "KS" }
+{ "_id" : "66939", "city" : "COURTLAND", "loc" : [ -97.889956, 39.78509 ], "pop" : 487, "state" : "KS" }
+{ "_id" : "66940", "city" : "CUBA", "loc" : [ -97.449623, 39.797482 ], "pop" : 342, "state" : "KS" }
+{ "_id" : "66941", "city" : "ESBON", "loc" : [ -98.44622200000001, 39.756186 ], "pop" : 342, "state" : "KS" }
+{ "_id" : "66942", "city" : "FORMOSO", "loc" : [ -97.98890900000001, 39.779467 ], "pop" : 223, "state" : "KS" }
+{ "_id" : "66943", "city" : "GREENLEAF", "loc" : [ -96.977465, 39.706145 ], "pop" : 564, "state" : "KS" }
+{ "_id" : "66944", "city" : "HADDAM", "loc" : [ -97.308142, 39.851969 ], "pop" : 333, "state" : "KS" }
+{ "_id" : "66945", "city" : "HANOVER", "loc" : [ -96.86894700000001, 39.89266 ], "pop" : 1278, "state" : "KS" }
+{ "_id" : "66946", "city" : "HOLLENBERG", "loc" : [ -96.97350900000001, 39.959987 ], "pop" : 146, "state" : "KS" }
+{ "_id" : "66948", "city" : "JAMESTOWN", "loc" : [ -97.86308200000001, 39.602144 ], "pop" : 430, "state" : "KS" }
+{ "_id" : "66949", "city" : "IONIA", "loc" : [ -98.125603, 39.669686 ], "pop" : 752, "state" : "KS" }
+{ "_id" : "66951", "city" : "KENSINGTON", "loc" : [ -99.03084800000001, 39.769179 ], "pop" : 665, "state" : "KS" }
+{ "_id" : "66952", "city" : "BELLAIRE", "loc" : [ -98.558148, 39.812839 ], "pop" : 526, "state" : "KS" }
+{ "_id" : "66953", "city" : "LINN", "loc" : [ -97.08541200000001, 39.684687 ], "pop" : 666, "state" : "KS" }
+{ "_id" : "66955", "city" : "MAHASKA", "loc" : [ -97.34527199999999, 39.984502 ], "pop" : 142, "state" : "KS" }
+{ "_id" : "66956", "city" : "MANKATO", "loc" : [ -98.215227, 39.783259 ], "pop" : 1929, "state" : "KS" }
+{ "_id" : "66958", "city" : "MORROWVILLE", "loc" : [ -97.18252099999999, 39.861551 ], "pop" : 462, "state" : "KS" }
+{ "_id" : "66959", "city" : "MUNDEN", "loc" : [ -97.540302, 39.927219 ], "pop" : 266, "state" : "KS" }
+{ "_id" : "66960", "city" : "NARKA", "loc" : [ -97.42433200000001, 39.958162 ], "pop" : 205, "state" : "KS" }
+{ "_id" : "66961", "city" : "NORWAY", "loc" : [ -97.811926, 39.695305 ], "pop" : 287, "state" : "KS" }
+{ "_id" : "66962", "city" : "PALMER", "loc" : [ -97.11221399999999, 39.619165 ], "pop" : 276, "state" : "KS" }
+{ "_id" : "66963", "city" : "RANDALL", "loc" : [ -98.06605399999999, 39.62859 ], "pop" : 190, "state" : "KS" }
+{ "_id" : "66964", "city" : "REPUBLIC", "loc" : [ -97.843456, 39.937572 ], "pop" : 297, "state" : "KS" }
+{ "_id" : "66966", "city" : "SCANDIA", "loc" : [ -97.778645, 39.793861 ], "pop" : 537, "state" : "KS" }
+{ "_id" : "66967", "city" : "SMITH CENTER", "loc" : [ -98.784243, 39.804217 ], "pop" : 2848, "state" : "KS" }
+{ "_id" : "66968", "city" : "WASHINGTON", "loc" : [ -97.048368, 39.82234 ], "pop" : 1979, "state" : "KS" }
+{ "_id" : "66970", "city" : "WEBBER", "loc" : [ -97.997793, 39.924496 ], "pop" : 232, "state" : "KS" }
+{ "_id" : "67001", "city" : "ANDALE", "loc" : [ -97.64071199999999, 37.782686 ], "pop" : 1251, "state" : "KS" }
+{ "_id" : "67002", "city" : "ANDOVER", "loc" : [ -97.117901, 37.698531 ], "pop" : 5384, "state" : "KS" }
+{ "_id" : "67003", "city" : "ANTHONY", "loc" : [ -98.028499, 37.151206 ], "pop" : 2930, "state" : "KS" }
+{ "_id" : "67004", "city" : "ARGONIA", "loc" : [ -97.755678, 37.283966 ], "pop" : 949, "state" : "KS" }
+{ "_id" : "67005", "city" : "ARKANSAS CITY", "loc" : [ -97.035658, 37.067593 ], "pop" : 17740, "state" : "KS" }
+{ "_id" : "67008", "city" : "ATLANTA", "loc" : [ -96.76613500000001, 37.434309 ], "pop" : 320, "state" : "KS" }
+{ "_id" : "67009", "city" : "ATTICA", "loc" : [ -98.22642500000001, 37.25277 ], "pop" : 1125, "state" : "KS" }
+{ "_id" : "67010", "city" : "AUGUSTA", "loc" : [ -96.964772, 37.683606 ], "pop" : 11306, "state" : "KS" }
+{ "_id" : "67012", "city" : "BEAUMONT", "loc" : [ -96.63864, 37.607871 ], "pop" : 85, "state" : "KS" }
+{ "_id" : "67013", "city" : "BELLE PLAINE", "loc" : [ -97.28522100000001, 37.405155 ], "pop" : 2784, "state" : "KS" }
+{ "_id" : "67016", "city" : "BENTLEY", "loc" : [ -97.516381, 37.879582 ], "pop" : 895, "state" : "KS" }
+{ "_id" : "67017", "city" : "BENTON", "loc" : [ -97.097117, 37.794615 ], "pop" : 2122, "state" : "KS" }
+{ "_id" : "67018", "city" : "BLUFF CITY", "loc" : [ -97.875412, 37.083846 ], "pop" : 216, "state" : "KS" }
+{ "_id" : "67019", "city" : "BURDEN", "loc" : [ -96.75704399999999, 37.320856 ], "pop" : 698, "state" : "KS" }
+{ "_id" : "67020", "city" : "BURRTON", "loc" : [ -97.66664900000001, 38.026128 ], "pop" : 1149, "state" : "KS" }
+{ "_id" : "67021", "city" : "BYERS", "loc" : [ -98.901662, 37.784693 ], "pop" : 208, "state" : "KS" }
+{ "_id" : "67022", "city" : "CALDWELL", "loc" : [ -97.62465899999999, 37.045241 ], "pop" : 1777, "state" : "KS" }
+{ "_id" : "67023", "city" : "CAMBRIDGE", "loc" : [ -96.66388000000001, 37.358348 ], "pop" : 316, "state" : "KS" }
+{ "_id" : "67024", "city" : "CEDAR VALE", "loc" : [ -96.470133, 37.126487 ], "pop" : 1267, "state" : "KS" }
+{ "_id" : "67025", "city" : "CHENEY", "loc" : [ -97.768638, 37.635299 ], "pop" : 2497, "state" : "KS" }
+{ "_id" : "67026", "city" : "CLEARWATER", "loc" : [ -97.508179, 37.507592 ], "pop" : 2453, "state" : "KS" }
+{ "_id" : "67028", "city" : "COATS", "loc" : [ -98.850398, 37.512502 ], "pop" : 190, "state" : "KS" }
+{ "_id" : "67029", "city" : "COLDWATER", "loc" : [ -99.31148399999999, 37.247915 ], "pop" : 1317, "state" : "KS" }
+{ "_id" : "67030", "city" : "COLWICH", "loc" : [ -97.54051800000001, 37.77824 ], "pop" : 1745, "state" : "KS" }
+{ "_id" : "67031", "city" : "CONWAY SPRINGS", "loc" : [ -97.62835800000001, 37.390272 ], "pop" : 2241, "state" : "KS" }
+{ "_id" : "67032", "city" : "CORBIN", "loc" : [ -97.526326, 37.073142 ], "pop" : 193, "state" : "KS" }
+{ "_id" : "67035", "city" : "PENALOSA", "loc" : [ -98.39297000000001, 37.666149 ], "pop" : 497, "state" : "KS" }
+{ "_id" : "67036", "city" : "DANVILLE", "loc" : [ -97.868933, 37.267424 ], "pop" : 168, "state" : "KS" }
+{ "_id" : "67037", "city" : "DERBY", "loc" : [ -97.25488799999999, 37.552976 ], "pop" : 17109, "state" : "KS" }
+{ "_id" : "67038", "city" : "DEXTER", "loc" : [ -96.69170200000001, 37.164087 ], "pop" : 698, "state" : "KS" }
+{ "_id" : "67039", "city" : "DOUGLASS", "loc" : [ -96.994848, 37.51951 ], "pop" : 2388, "state" : "KS" }
+{ "_id" : "67041", "city" : "ELBING", "loc" : [ -97.11276599999999, 38.046208 ], "pop" : 422, "state" : "KS" }
+{ "_id" : "67042", "city" : "EL DORADO", "loc" : [ -96.854297, 37.822649 ], "pop" : 14387, "state" : "KS" }
+{ "_id" : "67045", "city" : "EUREKA", "loc" : [ -96.295877, 37.826471 ], "pop" : 3986, "state" : "KS" }
+{ "_id" : "67047", "city" : "FALL RIVER", "loc" : [ -96.04345600000001, 37.621049 ], "pop" : 527, "state" : "KS" }
+{ "_id" : "67049", "city" : "FREEPORT", "loc" : [ -97.86342, 37.190257 ], "pop" : 52, "state" : "KS" }
+{ "_id" : "67050", "city" : "GARDEN PLAIN", "loc" : [ -97.66002, 37.676712 ], "pop" : 1406, "state" : "KS" }
+{ "_id" : "67051", "city" : "GEUDA SPRINGS", "loc" : [ -97.17950399999999, 37.08093 ], "pop" : 503, "state" : "KS" }
+{ "_id" : "67052", "city" : "GODDARD", "loc" : [ -97.53640799999999, 37.657483 ], "pop" : 6586, "state" : "KS" }
+{ "_id" : "67053", "city" : "GOESSEL", "loc" : [ -97.33628, 38.234259 ], "pop" : 973, "state" : "KS" }
+{ "_id" : "67054", "city" : "GREENSBURG", "loc" : [ -99.301057, 37.608367 ], "pop" : 2073, "state" : "KS" }
+{ "_id" : "67056", "city" : "HALSTEAD", "loc" : [ -97.511792, 38.006391 ], "pop" : 2405, "state" : "KS" }
+{ "_id" : "67057", "city" : "HARDTNER", "loc" : [ -98.654732, 37.030009 ], "pop" : 284, "state" : "KS" }
+{ "_id" : "67058", "city" : "HARPER", "loc" : [ -98.017978, 37.290943 ], "pop" : 2444, "state" : "KS" }
+{ "_id" : "67059", "city" : "HAVILAND", "loc" : [ -99.13396400000001, 37.609615 ], "pop" : 1277, "state" : "KS" }
+{ "_id" : "67060", "city" : "HAYSVILLE", "loc" : [ -97.355323, 37.56467 ], "pop" : 7666, "state" : "KS" }
+{ "_id" : "67061", "city" : "HAZELTON", "loc" : [ -98.400319, 37.098421 ], "pop" : 201, "state" : "KS" }
+{ "_id" : "67062", "city" : "HESSTON", "loc" : [ -97.44945800000001, 38.135951 ], "pop" : 4156, "state" : "KS" }
+{ "_id" : "67063", "city" : "HILLSBORO", "loc" : [ -97.212154, 38.344907 ], "pop" : 3543, "state" : "KS" }
+{ "_id" : "67065", "city" : "ISABEL", "loc" : [ -98.53514, 37.448544 ], "pop" : 198, "state" : "KS" }
+{ "_id" : "67066", "city" : "IUKA", "loc" : [ -98.736103, 37.739725 ], "pop" : 387, "state" : "KS" }
+{ "_id" : "67068", "city" : "BELMONT", "loc" : [ -98.109295, 37.636246 ], "pop" : 6072, "state" : "KS" }
+{ "_id" : "67070", "city" : "KIOWA", "loc" : [ -98.48590799999999, 37.017166 ], "pop" : 1255, "state" : "KS" }
+{ "_id" : "67071", "city" : "LAKE CITY", "loc" : [ -98.809833, 37.356885 ], "pop" : 97, "state" : "KS" }
+{ "_id" : "67072", "city" : "LATHAM", "loc" : [ -96.679148, 37.530983 ], "pop" : 293, "state" : "KS" }
+{ "_id" : "67073", "city" : "LEHIGH", "loc" : [ -97.304315, 38.377106 ], "pop" : 311, "state" : "KS" }
+{ "_id" : "67074", "city" : "LEON", "loc" : [ -96.752634, 37.681268 ], "pop" : 1342, "state" : "KS" }
+{ "_id" : "67101", "city" : "MAIZE", "loc" : [ -97.468874, 37.774727 ], "pop" : 1808, "state" : "KS" }
+{ "_id" : "67102", "city" : "MAPLE CITY", "loc" : [ -96.781387, 37.071295 ], "pop" : 78, "state" : "KS" }
+{ "_id" : "67103", "city" : "MAYFIELD", "loc" : [ -97.54160299999999, 37.251806 ], "pop" : 353, "state" : "KS" }
+{ "_id" : "67104", "city" : "MEDICINE LODGE", "loc" : [ -98.584785, 37.284452 ], "pop" : 3208, "state" : "KS" }
+{ "_id" : "67105", "city" : "MILAN", "loc" : [ -97.65206499999999, 37.257764 ], "pop" : 238, "state" : "KS" }
+{ "_id" : "67106", "city" : "MILTON", "loc" : [ -97.759156, 37.440064 ], "pop" : 353, "state" : "KS" }
+{ "_id" : "67107", "city" : "MOUNDRIDGE", "loc" : [ -97.50876700000001, 38.206029 ], "pop" : 2307, "state" : "KS" }
+{ "_id" : "67108", "city" : "MOUNT HOPE", "loc" : [ -97.659092, 37.868412 ], "pop" : 1060, "state" : "KS" }
+{ "_id" : "67109", "city" : "MULLINVILLE", "loc" : [ -99.46388, 37.571608 ], "pop" : 427, "state" : "KS" }
+{ "_id" : "67110", "city" : "MULVANE", "loc" : [ -97.231954, 37.476433 ], "pop" : 6238, "state" : "KS" }
+{ "_id" : "67111", "city" : "MURDOCK", "loc" : [ -97.95027, 37.609945 ], "pop" : 197, "state" : "KS" }
+{ "_id" : "67112", "city" : "NASHVILLE", "loc" : [ -98.417052, 37.434419 ], "pop" : 220, "state" : "KS" }
+{ "_id" : "67114", "city" : "NEWTON", "loc" : [ -97.343457, 38.045067 ], "pop" : 20273, "state" : "KS" }
+{ "_id" : "67117", "city" : "NORTH NEWTON", "loc" : [ -97.328796, 38.128246 ], "pop" : 408, "state" : "KS" }
+{ "_id" : "67118", "city" : "NORWICH", "loc" : [ -97.866247, 37.4501 ], "pop" : 705, "state" : "KS" }
+{ "_id" : "67119", "city" : "OXFORD", "loc" : [ -97.176131, 37.265303 ], "pop" : 1515, "state" : "KS" }
+{ "_id" : "67120", "city" : "PECK", "loc" : [ -97.311565, 37.472445 ], "pop" : 1023, "state" : "KS" }
+{ "_id" : "67122", "city" : "PIEDMONT", "loc" : [ -96.36950299999999, 37.637169 ], "pop" : 249, "state" : "KS" }
+{ "_id" : "67123", "city" : "POTWIN", "loc" : [ -97.000608, 37.971872 ], "pop" : 900, "state" : "KS" }
+{ "_id" : "67124", "city" : "PRATT", "loc" : [ -98.73003, 37.650219 ], "pop" : 8348, "state" : "KS" }
+{ "_id" : "67127", "city" : "PROTECTION", "loc" : [ -99.481628, 37.196782 ], "pop" : 864, "state" : "KS" }
+{ "_id" : "67128", "city" : "RAGO", "loc" : [ -98.077208, 37.439824 ], "pop" : 127, "state" : "KS" }
+{ "_id" : "67131", "city" : "ROCK", "loc" : [ -96.936468, 37.429435 ], "pop" : 393, "state" : "KS" }
+{ "_id" : "67132", "city" : "ROSALIA", "loc" : [ -96.648161, 37.796041 ], "pop" : 545, "state" : "KS" }
+{ "_id" : "67133", "city" : "ROSE HILL", "loc" : [ -97.117346, 37.578371 ], "pop" : 5598, "state" : "KS" }
+{ "_id" : "67134", "city" : "SAWYER", "loc" : [ -98.66422, 37.51007 ], "pop" : 569, "state" : "KS" }
+{ "_id" : "67135", "city" : "SEDGWICK", "loc" : [ -97.402412, 37.869328 ], "pop" : 7706, "state" : "KS" }
+{ "_id" : "67137", "city" : "CLIMAX", "loc" : [ -96.229777, 37.64985 ], "pop" : 871, "state" : "KS" }
+{ "_id" : "67138", "city" : "SHARON", "loc" : [ -98.414168, 37.249239 ], "pop" : 440, "state" : "KS" }
+{ "_id" : "67140", "city" : "SOUTH HAVEN", "loc" : [ -97.404228, 37.049997 ], "pop" : 710, "state" : "KS" }
+{ "_id" : "67142", "city" : "SPIVEY", "loc" : [ -98.175122, 37.440986 ], "pop" : 169, "state" : "KS" }
+{ "_id" : "67143", "city" : "SUN CITY", "loc" : [ -98.90385999999999, 37.394647 ], "pop" : 191, "state" : "KS" }
+{ "_id" : "67144", "city" : "TOWANDA", "loc" : [ -96.99176900000001, 37.800506 ], "pop" : 2598, "state" : "KS" }
+{ "_id" : "67146", "city" : "UDALL", "loc" : [ -97.110784, 37.393861 ], "pop" : 1714, "state" : "KS" }
+{ "_id" : "67147", "city" : "VALLEY CENTER", "loc" : [ -97.262146, 37.861643 ], "pop" : 1146, "state" : "KS" }
+{ "_id" : "67149", "city" : "VIOLA", "loc" : [ -97.630636, 37.569624 ], "pop" : 1330, "state" : "KS" }
+{ "_id" : "67150", "city" : "WALDRON", "loc" : [ -98.228877, 37.072994 ], "pop" : 189, "state" : "KS" }
+{ "_id" : "67151", "city" : "WALTON", "loc" : [ -97.23607699999999, 38.123909 ], "pop" : 418, "state" : "KS" }
+{ "_id" : "67152", "city" : "WELLINGTON", "loc" : [ -97.39097599999999, 37.27783 ], "pop" : 11149, "state" : "KS" }
+{ "_id" : "67154", "city" : "WHITEWATER", "loc" : [ -97.130816, 37.961231 ], "pop" : 1100, "state" : "KS" }
+{ "_id" : "67155", "city" : "WILMORE", "loc" : [ -99.184577, 37.331794 ], "pop" : 132, "state" : "KS" }
+{ "_id" : "67156", "city" : "WINFIELD", "loc" : [ -96.97998699999999, 37.241621 ], "pop" : 14958, "state" : "KS" }
+{ "_id" : "67159", "city" : "ZENDA", "loc" : [ -98.28736000000001, 37.437253 ], "pop" : 200, "state" : "KS" }
+{ "_id" : "67202", "city" : "WICHITA", "loc" : [ -97.33551, 37.689945 ], "pop" : 1250, "state" : "KS" }
+{ "_id" : "67203", "city" : "WICHITA", "loc" : [ -97.363766, 37.704798 ], "pop" : 30712, "state" : "KS" }
+{ "_id" : "67204", "city" : "WICHITA", "loc" : [ -97.35656299999999, 37.748838 ], "pop" : 20298, "state" : "KS" }
+{ "_id" : "67205", "city" : "WICHITA", "loc" : [ -97.426924, 37.763929 ], "pop" : 1807, "state" : "KS" }
+{ "_id" : "67206", "city" : "EASTBOROUGH", "loc" : [ -97.23925300000001, 37.699622 ], "pop" : 13008, "state" : "KS" }
+{ "_id" : "67207", "city" : "EASTBOROUGH", "loc" : [ -97.238962, 37.667152 ], "pop" : 20116, "state" : "KS" }
+{ "_id" : "67208", "city" : "WICHITA", "loc" : [ -97.28106200000001, 37.702428 ], "pop" : 18195, "state" : "KS" }
+{ "_id" : "67209", "city" : "WICHITA", "loc" : [ -97.42354, 37.677855 ], "pop" : 4135, "state" : "KS" }
+{ "_id" : "67210", "city" : "WICHITA", "loc" : [ -97.26125399999999, 37.637915 ], "pop" : 11414, "state" : "KS" }
+{ "_id" : "67211", "city" : "WICHITA", "loc" : [ -97.316451, 37.666181 ], "pop" : 20182, "state" : "KS" }
+{ "_id" : "67212", "city" : "WICHITA", "loc" : [ -97.438344, 37.700683 ], "pop" : 41349, "state" : "KS" }
+{ "_id" : "67213", "city" : "WICHITA", "loc" : [ -97.35907400000001, 37.667959 ], "pop" : 23607, "state" : "KS" }
+{ "_id" : "67214", "city" : "WICHITA", "loc" : [ -97.313284, 37.705051 ], "pop" : 18651, "state" : "KS" }
+{ "_id" : "67215", "city" : "WICHITA", "loc" : [ -97.42498500000001, 37.633333 ], "pop" : 2930, "state" : "KS" }
+{ "_id" : "67216", "city" : "WICHITA", "loc" : [ -97.313625, 37.622332 ], "pop" : 23031, "state" : "KS" }
+{ "_id" : "67217", "city" : "WICHITA", "loc" : [ -97.35813899999999, 37.626574 ], "pop" : 30680, "state" : "KS" }
+{ "_id" : "67218", "city" : "WICHITA", "loc" : [ -97.280219, 37.669007 ], "pop" : 23491, "state" : "KS" }
+{ "_id" : "67219", "city" : "PARK CITY", "loc" : [ -97.313517, 37.76482 ], "pop" : 10619, "state" : "KS" }
+{ "_id" : "67220", "city" : "BEL AIRE", "loc" : [ -97.275915, 37.74548 ], "pop" : 9802, "state" : "KS" }
+{ "_id" : "67221", "city" : "MC CONNELL A F B", "loc" : [ -97.25402099999999, 37.623687 ], "pop" : 137, "state" : "KS" }
+{ "_id" : "67223", "city" : "WICHITA", "loc" : [ -97.467421, 37.748434 ], "pop" : 318, "state" : "KS" }
+{ "_id" : "67226", "city" : "WICHITA", "loc" : [ -97.24785300000001, 37.737891 ], "pop" : 8884, "state" : "KS" }
+{ "_id" : "67227", "city" : "WICHITA", "loc" : [ -97.460561, 37.588466 ], "pop" : 107, "state" : "KS" }
+{ "_id" : "67228", "city" : "WICHITA", "loc" : [ -97.201404, 37.776061 ], "pop" : 768, "state" : "KS" }
+{ "_id" : "67230", "city" : "WICHITA", "loc" : [ -97.155764, 37.680814 ], "pop" : 4957, "state" : "KS" }
+{ "_id" : "67231", "city" : "WICHITA", "loc" : [ -97.423384, 37.526866 ], "pop" : 855, "state" : "KS" }
+{ "_id" : "67232", "city" : "WICHITA", "loc" : [ -97.164278, 37.642797 ], "pop" : 128, "state" : "KS" }
+{ "_id" : "67233", "city" : "WICHITA", "loc" : [ -97.32237000000001, 37.54434 ], "pop" : 3861, "state" : "KS" }
+{ "_id" : "67235", "city" : "WICHITA", "loc" : [ -97.461145, 37.668631 ], "pop" : 3243, "state" : "KS" }
+{ "_id" : "67236", "city" : "WICHITA", "loc" : [ -97.26821, 37.497943 ], "pop" : 262, "state" : "KS" }
+{ "_id" : "67301", "city" : "INDEPENDENCE", "loc" : [ -95.716528, 37.229247 ], "pop" : 13892, "state" : "KS" }
+{ "_id" : "67330", "city" : "ALTAMONT", "loc" : [ -95.29830200000001, 37.187298 ], "pop" : 1336, "state" : "KS" }
+{ "_id" : "67332", "city" : "BARTLETT", "loc" : [ -95.211512, 37.060096 ], "pop" : 385, "state" : "KS" }
+{ "_id" : "67333", "city" : "CANEY", "loc" : [ -95.909128, 37.022412 ], "pop" : 3302, "state" : "KS" }
+{ "_id" : "67335", "city" : "CHERRYVALE", "loc" : [ -95.55901900000001, 37.266828 ], "pop" : 3490, "state" : "KS" }
+{ "_id" : "67336", "city" : "CHETOPA", "loc" : [ -95.079572, 37.041817 ], "pop" : 2031, "state" : "KS" }
+{ "_id" : "67337", "city" : "COFFEYVILLE", "loc" : [ -95.632756, 37.044056 ], "pop" : 17417, "state" : "KS" }
+{ "_id" : "67341", "city" : "DENNIS", "loc" : [ -95.411602, 37.324324 ], "pop" : 430, "state" : "KS" }
+{ "_id" : "67342", "city" : "EDNA", "loc" : [ -95.344159, 37.056146 ], "pop" : 817, "state" : "KS" }
+{ "_id" : "67344", "city" : "ELK CITY", "loc" : [ -95.913517, 37.314571 ], "pop" : 801, "state" : "KS" }
+{ "_id" : "67345", "city" : "ELK FALLS", "loc" : [ -96.195902, 37.374514 ], "pop" : 206, "state" : "KS" }
+{ "_id" : "67346", "city" : "GRENOLA", "loc" : [ -96.439564, 37.366824 ], "pop" : 389, "state" : "KS" }
+{ "_id" : "67347", "city" : "HAVANA", "loc" : [ -95.941372, 37.091655 ], "pop" : 149, "state" : "KS" }
+{ "_id" : "67349", "city" : "HOWARD", "loc" : [ -96.256298, 37.48089 ], "pop" : 1161, "state" : "KS" }
+{ "_id" : "67351", "city" : "LIBERTY", "loc" : [ -95.601698, 37.157629 ], "pop" : 504, "state" : "KS" }
+{ "_id" : "67352", "city" : "LONGTON", "loc" : [ -96.081379, 37.390455 ], "pop" : 561, "state" : "KS" }
+{ "_id" : "67353", "city" : "MOLINE", "loc" : [ -96.30687500000001, 37.364868 ], "pop" : 681, "state" : "KS" }
+{ "_id" : "67354", "city" : "MOUND VALLEY", "loc" : [ -95.424712, 37.209078 ], "pop" : 807, "state" : "KS" }
+{ "_id" : "67355", "city" : "NIOTAZE", "loc" : [ -96.01922, 37.05133 ], "pop" : 265, "state" : "KS" }
+{ "_id" : "67356", "city" : "OSWEGO", "loc" : [ -95.133458, 37.182254 ], "pop" : 3121, "state" : "KS" }
+{ "_id" : "67357", "city" : "PARSONS", "loc" : [ -95.269288, 37.338888 ], "pop" : 14375, "state" : "KS" }
+{ "_id" : "67360", "city" : "PERU", "loc" : [ -96.140376, 37.056823 ], "pop" : 689, "state" : "KS" }
+{ "_id" : "67361", "city" : "SEDAN", "loc" : [ -96.173248, 37.12968 ], "pop" : 2186, "state" : "KS" }
+{ "_id" : "67401", "city" : "BAVARIA", "loc" : [ -97.60878700000001, 38.823802 ], "pop" : 45208, "state" : "KS" }
+{ "_id" : "67410", "city" : "ABILENE", "loc" : [ -97.20632000000001, 38.937144 ], "pop" : 8249, "state" : "KS" }
+{ "_id" : "67414", "city" : "ADA", "loc" : [ -97.887387, 39.157777 ], "pop" : 179, "state" : "KS" }
+{ "_id" : "67416", "city" : "ASSARIA", "loc" : [ -97.62032000000001, 38.667596 ], "pop" : 761, "state" : "KS" }
+{ "_id" : "67417", "city" : "AURORA", "loc" : [ -97.530411, 39.447188 ], "pop" : 195, "state" : "KS" }
+{ "_id" : "67418", "city" : "BARNARD", "loc" : [ -98.071144, 39.181572 ], "pop" : 302, "state" : "KS" }
+{ "_id" : "67420", "city" : "SCOTTSVILLE", "loc" : [ -98.11171400000001, 39.45446 ], "pop" : 5221, "state" : "KS" }
+{ "_id" : "67422", "city" : "BENNINGTON", "loc" : [ -97.603121, 39.02239 ], "pop" : 844, "state" : "KS" }
+{ "_id" : "67423", "city" : "BEVERLY", "loc" : [ -97.981785, 38.984416 ], "pop" : 389, "state" : "KS" }
+{ "_id" : "67425", "city" : "BROOKVILLE", "loc" : [ -97.86300199999999, 38.785771 ], "pop" : 323, "state" : "KS" }
+{ "_id" : "67427", "city" : "BUSHTON", "loc" : [ -98.401629, 38.501836 ], "pop" : 480, "state" : "KS" }
+{ "_id" : "67428", "city" : "CANTON", "loc" : [ -97.42907200000001, 38.385838 ], "pop" : 1050, "state" : "KS" }
+{ "_id" : "67429", "city" : "CARLTON", "loc" : [ -97.307506, 38.6729 ], "pop" : 121, "state" : "KS" }
+{ "_id" : "67430", "city" : "CAWKER CITY", "loc" : [ -98.433458, 39.511529 ], "pop" : 637, "state" : "KS" }
+{ "_id" : "67431", "city" : "CHAPMAN", "loc" : [ -97.01696099999999, 38.972225 ], "pop" : 1968, "state" : "KS" }
+{ "_id" : "67432", "city" : "CLAY CENTER", "loc" : [ -97.127793, 39.384354 ], "pop" : 6038, "state" : "KS" }
+{ "_id" : "67436", "city" : "DELPHOS", "loc" : [ -97.771692, 39.273122 ], "pop" : 639, "state" : "KS" }
+{ "_id" : "67437", "city" : "DOWNS", "loc" : [ -98.544117, 39.502753 ], "pop" : 1285, "state" : "KS" }
+{ "_id" : "67438", "city" : "DURHAM", "loc" : [ -97.255532, 38.503836 ], "pop" : 444, "state" : "KS" }
+{ "_id" : "67439", "city" : "ELLSWORTH", "loc" : [ -98.20567800000001, 38.731219 ], "pop" : 3728, "state" : "KS" }
+{ "_id" : "67441", "city" : "ENTERPRISE", "loc" : [ -97.112222, 38.906321 ], "pop" : 1286, "state" : "KS" }
+{ "_id" : "67442", "city" : "FALUN", "loc" : [ -97.755411, 38.664794 ], "pop" : 226, "state" : "KS" }
+{ "_id" : "67443", "city" : "GALVA", "loc" : [ -97.53592, 38.382377 ], "pop" : 1151, "state" : "KS" }
+{ "_id" : "67444", "city" : "GENESEO", "loc" : [ -98.185818, 38.503655 ], "pop" : 569, "state" : "KS" }
+{ "_id" : "67445", "city" : "GLASCO", "loc" : [ -97.841829, 39.362092 ], "pop" : 663, "state" : "KS" }
+{ "_id" : "67446", "city" : "GLEN ELDER", "loc" : [ -98.31550799999999, 39.495775 ], "pop" : 632, "state" : "KS" }
+{ "_id" : "67447", "city" : "GREEN", "loc" : [ -96.999424, 39.420056 ], "pop" : 340, "state" : "KS" }
+{ "_id" : "67448", "city" : "GYPSUM", "loc" : [ -97.43384, 38.704744 ], "pop" : 742, "state" : "KS" }
+{ "_id" : "67449", "city" : "DELAVAN", "loc" : [ -97.015491, 38.702306 ], "pop" : 4145, "state" : "KS" }
+{ "_id" : "67450", "city" : "HOLYROOD", "loc" : [ -98.415916, 38.589955 ], "pop" : 678, "state" : "KS" }
+{ "_id" : "67451", "city" : "HOPE", "loc" : [ -97.106126, 38.6776 ], "pop" : 725, "state" : "KS" }
+{ "_id" : "67452", "city" : "HUNTER", "loc" : [ -98.40174500000001, 39.242964 ], "pop" : 181, "state" : "KS" }
+{ "_id" : "67454", "city" : "KANOPOLIS", "loc" : [ -98.15746799999999, 38.709111 ], "pop" : 641, "state" : "KS" }
+{ "_id" : "67455", "city" : "WESTFALL", "loc" : [ -98.14042600000001, 39.028644 ], "pop" : 1986, "state" : "KS" }
+{ "_id" : "67456", "city" : "LINDSBORG", "loc" : [ -97.67389, 38.576058 ], "pop" : 3320, "state" : "KS" }
+{ "_id" : "67457", "city" : "LITTLE RIVER", "loc" : [ -98.01131700000001, 38.407868 ], "pop" : 841, "state" : "KS" }
+{ "_id" : "67458", "city" : "LONGFORD", "loc" : [ -97.208662, 39.174324 ], "pop" : 507, "state" : "KS" }
+{ "_id" : "67459", "city" : "LORRAINE", "loc" : [ -98.28995399999999, 38.565175 ], "pop" : 302, "state" : "KS" }
+{ "_id" : "67460", "city" : "CONWAY", "loc" : [ -97.654989, 38.373732 ], "pop" : 16480, "state" : "KS" }
+{ "_id" : "67463", "city" : "MANCHESTER", "loc" : [ -97.30954699999999, 39.087051 ], "pop" : 203, "state" : "KS" }
+{ "_id" : "67464", "city" : "MARQUETTE", "loc" : [ -97.83807899999999, 38.556028 ], "pop" : 760, "state" : "KS" }
+{ "_id" : "67465", "city" : "MENTOR", "loc" : [ -97.566034, 38.732103 ], "pop" : 791, "state" : "KS" }
+{ "_id" : "67466", "city" : "MILTONVALE", "loc" : [ -97.457911, 39.348078 ], "pop" : 677, "state" : "KS" }
+{ "_id" : "67467", "city" : "MINNEAPOLIS", "loc" : [ -97.668778, 39.129487 ], "pop" : 2985, "state" : "KS" }
+{ "_id" : "67468", "city" : "MORGANVILLE", "loc" : [ -97.249219, 39.509219 ], "pop" : 847, "state" : "KS" }
+{ "_id" : "67469", "city" : "NAVARRE", "loc" : [ -97.105554, 38.81772 ], "pop" : 205, "state" : "KS" }
+{ "_id" : "67470", "city" : "NEW CAMBRIA", "loc" : [ -97.52301199999999, 38.896008 ], "pop" : 390, "state" : "KS" }
+{ "_id" : "67472", "city" : "OAKHILL", "loc" : [ -97.330501, 39.247668 ], "pop" : 96, "state" : "KS" }
+{ "_id" : "67473", "city" : "OSBORNE", "loc" : [ -98.69608100000001, 39.419402 ], "pop" : 2340, "state" : "KS" }
+{ "_id" : "67474", "city" : "PORTIS", "loc" : [ -98.69044599999999, 39.545545 ], "pop" : 255, "state" : "KS" }
+{ "_id" : "67475", "city" : "RAMONA", "loc" : [ -97.075874, 38.577726 ], "pop" : 237, "state" : "KS" }
+{ "_id" : "67476", "city" : "ROXBURY", "loc" : [ -97.42719, 38.474325 ], "pop" : 106, "state" : "KS" }
+{ "_id" : "67478", "city" : "SIMPSON", "loc" : [ -97.948887, 39.373074 ], "pop" : 159, "state" : "KS" }
+{ "_id" : "67479", "city" : "SMOLAN", "loc" : [ -97.71327700000001, 38.76442 ], "pop" : 706, "state" : "KS" }
+{ "_id" : "67480", "city" : "SOLOMON", "loc" : [ -97.351803, 38.919359 ], "pop" : 1626, "state" : "KS" }
+{ "_id" : "67481", "city" : "SYLVAN GROVE", "loc" : [ -98.373031, 39.032443 ], "pop" : 976, "state" : "KS" }
+{ "_id" : "67482", "city" : "TALMAGE", "loc" : [ -97.29736699999999, 39.008594 ], "pop" : 200, "state" : "KS" }
+{ "_id" : "67483", "city" : "TAMPA", "loc" : [ -97.17738799999999, 38.553437 ], "pop" : 211, "state" : "KS" }
+{ "_id" : "67484", "city" : "CULVER", "loc" : [ -97.82837499999999, 38.998318 ], "pop" : 745, "state" : "KS" }
+{ "_id" : "67485", "city" : "TIPTON", "loc" : [ -98.46439100000001, 39.343639 ], "pop" : 373, "state" : "KS" }
+{ "_id" : "67487", "city" : "WAKEFIELD", "loc" : [ -97.022851, 39.224916 ], "pop" : 1330, "state" : "KS" }
+{ "_id" : "67488", "city" : "WELLS", "loc" : [ -97.554636, 39.059224 ], "pop" : 242, "state" : "KS" }
+{ "_id" : "67490", "city" : "WILSON", "loc" : [ -98.44321600000001, 38.813373 ], "pop" : 1237, "state" : "KS" }
+{ "_id" : "67491", "city" : "WINDOM", "loc" : [ -97.89647600000001, 38.384518 ], "pop" : 231, "state" : "KS" }
+{ "_id" : "67492", "city" : "WOODBINE", "loc" : [ -96.961935, 38.813064 ], "pop" : 384, "state" : "KS" }
+{ "_id" : "67501", "city" : "HUTCHINSON", "loc" : [ -97.93105199999999, 38.054995 ], "pop" : 27097, "state" : "KS" }
+{ "_id" : "67502", "city" : "MEDORA", "loc" : [ -97.920517, 38.091483 ], "pop" : 21197, "state" : "KS" }
+{ "_id" : "67505", "city" : "SOUTH HUTCHINSON", "loc" : [ -97.90814, 38.007306 ], "pop" : 4243, "state" : "KS" }
+{ "_id" : "67510", "city" : "ABBYVILLE", "loc" : [ -98.207103, 37.962597 ], "pop" : 267, "state" : "KS" }
+{ "_id" : "67511", "city" : "ALBERT", "loc" : [ -98.98071400000001, 38.475758 ], "pop" : 544, "state" : "KS" }
+{ "_id" : "67512", "city" : "ALDEN", "loc" : [ -98.31120199999999, 38.234303 ], "pop" : 278, "state" : "KS" }
+{ "_id" : "67513", "city" : "ALEXANDER", "loc" : [ -99.537828, 38.456996 ], "pop" : 150, "state" : "KS" }
+{ "_id" : "67514", "city" : "ARLINGTON", "loc" : [ -98.15904500000001, 37.859795 ], "pop" : 930, "state" : "KS" }
+{ "_id" : "67515", "city" : "ARNOLD", "loc" : [ -100.012003, 38.609122 ], "pop" : 0, "state" : "KS" }
+{ "_id" : "67516", "city" : "BAZINE", "loc" : [ -99.701607, 38.456457 ], "pop" : 546, "state" : "KS" }
+{ "_id" : "67517", "city" : "BEAVER", "loc" : [ -98.64832699999999, 38.650055 ], "pop" : 122, "state" : "KS" }
+{ "_id" : "67518", "city" : "BEELER", "loc" : [ -100.170957, 38.48113 ], "pop" : 91, "state" : "KS" }
+{ "_id" : "67519", "city" : "BELPRE", "loc" : [ -99.09357, 37.934655 ], "pop" : 268, "state" : "KS" }
+{ "_id" : "67520", "city" : "BISON", "loc" : [ -99.198634, 38.519332 ], "pop" : 347, "state" : "KS" }
+{ "_id" : "67521", "city" : "BROWNELL", "loc" : [ -99.732806, 38.623854 ], "pop" : 156, "state" : "KS" }
+{ "_id" : "67522", "city" : "BUHLER", "loc" : [ -97.769093, 38.130903 ], "pop" : 1854, "state" : "KS" }
+{ "_id" : "67523", "city" : "BURDETT", "loc" : [ -99.52751499999999, 38.210384 ], "pop" : 340, "state" : "KS" }
+{ "_id" : "67524", "city" : "CHASE", "loc" : [ -98.35563399999999, 38.363515 ], "pop" : 772, "state" : "KS" }
+{ "_id" : "67525", "city" : "CLAFLIN", "loc" : [ -98.53722, 38.540885 ], "pop" : 969, "state" : "KS" }
+{ "_id" : "67526", "city" : "ELLINWOOD", "loc" : [ -98.584872, 38.356498 ], "pop" : 3297, "state" : "KS" }
+{ "_id" : "67529", "city" : "GARFIELD", "loc" : [ -99.237433, 38.064929 ], "pop" : 368, "state" : "KS" }
+{ "_id" : "67530", "city" : "HEIZER", "loc" : [ -98.783103, 38.370937 ], "pop" : 19861, "state" : "KS" }
+{ "_id" : "67543", "city" : "HAVEN", "loc" : [ -97.777244, 37.868593 ], "pop" : 2181, "state" : "KS" }
+{ "_id" : "67544", "city" : "SUSANK", "loc" : [ -98.79104100000001, 38.529246 ], "pop" : 3642, "state" : "KS" }
+{ "_id" : "67545", "city" : "HUDSON", "loc" : [ -98.640815, 38.148493 ], "pop" : 381, "state" : "KS" }
+{ "_id" : "67546", "city" : "INMAN", "loc" : [ -97.795107, 38.223212 ], "pop" : 1863, "state" : "KS" }
+{ "_id" : "67547", "city" : "KINSLEY", "loc" : [ -99.411556, 37.924715 ], "pop" : 2321, "state" : "KS" }
+{ "_id" : "67548", "city" : "LA CROSSE", "loc" : [ -99.30973299999999, 38.531144 ], "pop" : 1545, "state" : "KS" }
+{ "_id" : "67550", "city" : "RADIUM", "loc" : [ -99.112382, 38.179643 ], "pop" : 6572, "state" : "KS" }
+{ "_id" : "67552", "city" : "LEWIS", "loc" : [ -99.24797700000001, 37.906223 ], "pop" : 758, "state" : "KS" }
+{ "_id" : "67553", "city" : "LIEBENTHAL", "loc" : [ -99.282051, 38.646585 ], "pop" : 231, "state" : "KS" }
+{ "_id" : "67554", "city" : "LYONS", "loc" : [ -98.183094, 38.334881 ], "pop" : 4931, "state" : "KS" }
+{ "_id" : "67556", "city" : "MC CRACKEN", "loc" : [ -99.553982, 38.595734 ], "pop" : 317, "state" : "KS" }
+{ "_id" : "67557", "city" : "MACKSVILLE", "loc" : [ -98.948052, 37.943276 ], "pop" : 754, "state" : "KS" }
+{ "_id" : "67559", "city" : "NEKOMA", "loc" : [ -99.42337999999999, 38.437226 ], "pop" : 81, "state" : "KS" }
+{ "_id" : "67560", "city" : "NESS CITY", "loc" : [ -99.90286, 38.438754 ], "pop" : 2256, "state" : "KS" }
+{ "_id" : "67561", "city" : "NICKERSON", "loc" : [ -98.067408, 38.141171 ], "pop" : 1596, "state" : "KS" }
+{ "_id" : "67562", "city" : "ODIN", "loc" : [ -98.626762, 38.55628 ], "pop" : 281, "state" : "KS" }
+{ "_id" : "67563", "city" : "OFFERLE", "loc" : [ -99.549757, 37.882805 ], "pop" : 323, "state" : "KS" }
+{ "_id" : "67564", "city" : "GALATIA", "loc" : [ -98.92899, 38.567045 ], "pop" : 14, "state" : "KS" }
+{ "_id" : "67565", "city" : "GALATIA", "loc" : [ -99.065635, 38.509239 ], "pop" : 711, "state" : "KS" }
+{ "_id" : "67566", "city" : "PARTRIDGE", "loc" : [ -98.07981100000001, 37.967129 ], "pop" : 581, "state" : "KS" }
+{ "_id" : "67567", "city" : "PAWNEE ROCK", "loc" : [ -98.981436, 38.278193 ], "pop" : 515, "state" : "KS" }
+{ "_id" : "67568", "city" : "PLEVNA", "loc" : [ -98.298807, 37.965762 ], "pop" : 270, "state" : "KS" }
+{ "_id" : "67570", "city" : "PRETTY PRAIRIE", "loc" : [ -97.988603, 37.77828 ], "pop" : 959, "state" : "KS" }
+{ "_id" : "67572", "city" : "RANSOM", "loc" : [ -99.92665100000001, 38.640003 ], "pop" : 581, "state" : "KS" }
+{ "_id" : "67573", "city" : "RAYMOND", "loc" : [ -98.411867, 38.287677 ], "pop" : 254, "state" : "KS" }
+{ "_id" : "67574", "city" : "ROZEL", "loc" : [ -99.40484600000001, 38.214823 ], "pop" : 275, "state" : "KS" }
+{ "_id" : "67575", "city" : "RUSH CENTER", "loc" : [ -99.30788099999999, 38.453341 ], "pop" : 275, "state" : "KS" }
+{ "_id" : "67576", "city" : "SAINT JOHN", "loc" : [ -98.764653, 38.030939 ], "pop" : 2292, "state" : "KS" }
+{ "_id" : "67577", "city" : "SEWARD", "loc" : [ -98.76391, 38.206558 ], "pop" : 249, "state" : "KS" }
+{ "_id" : "67578", "city" : "STAFFORD", "loc" : [ -98.592854, 37.955372 ], "pop" : 1689, "state" : "KS" }
+{ "_id" : "67579", "city" : "STERLING", "loc" : [ -98.205474, 38.212621 ], "pop" : 2485, "state" : "KS" }
+{ "_id" : "67581", "city" : "SYLVIA", "loc" : [ -98.40676499999999, 37.955687 ], "pop" : 396, "state" : "KS" }
+{ "_id" : "67582", "city" : "TIMKEN", "loc" : [ -99.19015400000001, 38.445489 ], "pop" : 185, "state" : "KS" }
+{ "_id" : "67583", "city" : "LANGDON", "loc" : [ -98.421798, 37.809593 ], "pop" : 558, "state" : "KS" }
+{ "_id" : "67584", "city" : "UTICA", "loc" : [ -100.137976, 38.641057 ], "pop" : 403, "state" : "KS" }
+{ "_id" : "67601", "city" : "ANTONINO", "loc" : [ -99.320134, 38.878046 ], "pop" : 20703, "state" : "KS" }
+{ "_id" : "67621", "city" : "AGRA", "loc" : [ -99.12554299999999, 39.803701 ], "pop" : 604, "state" : "KS" }
+{ "_id" : "67622", "city" : "ALMENA", "loc" : [ -99.704177, 39.889071 ], "pop" : 574, "state" : "KS" }
+{ "_id" : "67623", "city" : "ALTON", "loc" : [ -98.953875, 39.451422 ], "pop" : 364, "state" : "KS" }
+{ "_id" : "67625", "city" : "BOGUE", "loc" : [ -99.67882, 39.378221 ], "pop" : 416, "state" : "KS" }
+{ "_id" : "67626", "city" : "BUNKER HILL", "loc" : [ -98.678285, 38.835704 ], "pop" : 359, "state" : "KS" }
+{ "_id" : "67627", "city" : "CATHARINE", "loc" : [ -99.215992, 38.96034 ], "pop" : 289, "state" : "KS" }
+{ "_id" : "67628", "city" : "CEDAR", "loc" : [ -98.93692299999999, 39.660242 ], "pop" : 62, "state" : "KS" }
+{ "_id" : "67629", "city" : "CLAYTON", "loc" : [ -100.059623, 39.69985 ], "pop" : 485, "state" : "KS" }
+{ "_id" : "67630", "city" : "CODELL", "loc" : [ -99.15918600000001, 39.206652 ], "pop" : 160, "state" : "KS" }
+{ "_id" : "67631", "city" : "COLLYER", "loc" : [ -100.06921, 38.965231 ], "pop" : 523, "state" : "KS" }
+{ "_id" : "67632", "city" : "DAMAR", "loc" : [ -99.581056, 39.324181 ], "pop" : 214, "state" : "KS" }
+{ "_id" : "67634", "city" : "DORRANCE", "loc" : [ -98.56947099999999, 38.834784 ], "pop" : 316, "state" : "KS" }
+{ "_id" : "67635", "city" : "DRESDEN", "loc" : [ -100.411219, 39.609357 ], "pop" : 158, "state" : "KS" }
+{ "_id" : "67636", "city" : "EDMOND", "loc" : [ -99.78418499999999, 39.661348 ], "pop" : 180, "state" : "KS" }
+{ "_id" : "67637", "city" : "ELLIS", "loc" : [ -99.52851, 38.947128 ], "pop" : 2478, "state" : "KS" }
+{ "_id" : "67638", "city" : "GAYLORD", "loc" : [ -98.801751, 39.659923 ], "pop" : 722, "state" : "KS" }
+{ "_id" : "67639", "city" : "GLADE", "loc" : [ -99.29962999999999, 39.670373 ], "pop" : 320, "state" : "KS" }
+{ "_id" : "67640", "city" : "GORHAM", "loc" : [ -99.01116, 38.872226 ], "pop" : 528, "state" : "KS" }
+{ "_id" : "67641", "city" : "HARLAN", "loc" : [ -98.789796, 39.611345 ], "pop" : 91, "state" : "KS" }
+{ "_id" : "67642", "city" : "HILL CITY", "loc" : [ -99.842921, 39.35657 ], "pop" : 2501, "state" : "KS" }
+{ "_id" : "67643", "city" : "JENNINGS", "loc" : [ -100.283441, 39.676242 ], "pop" : 347, "state" : "KS" }
+{ "_id" : "67644", "city" : "KIRWIN", "loc" : [ -99.120378, 39.671716 ], "pop" : 388, "state" : "KS" }
+{ "_id" : "67645", "city" : "DENSMORE", "loc" : [ -100.001566, 39.609364 ], "pop" : 344, "state" : "KS" }
+{ "_id" : "67646", "city" : "LOGAN", "loc" : [ -99.56869399999999, 39.661096 ], "pop" : 751, "state" : "KS" }
+{ "_id" : "67647", "city" : "LONG ISLAND", "loc" : [ -99.539125, 39.951683 ], "pop" : 260, "state" : "KS" }
+{ "_id" : "67648", "city" : "LUCAS", "loc" : [ -98.535186, 39.058126 ], "pop" : 576, "state" : "KS" }
+{ "_id" : "67649", "city" : "LURAY", "loc" : [ -98.685084, 39.103856 ], "pop" : 339, "state" : "KS" }
+{ "_id" : "67650", "city" : "MORLAND", "loc" : [ -100.07328, 39.322905 ], "pop" : 604, "state" : "KS" }
+{ "_id" : "67651", "city" : "NATOMA", "loc" : [ -98.98286299999999, 39.201341 ], "pop" : 623, "state" : "KS" }
+{ "_id" : "67652", "city" : "NEW ALMELO", "loc" : [ -100.139829, 39.624755 ], "pop" : 2, "state" : "KS" }
+{ "_id" : "67653", "city" : "NORCATUR", "loc" : [ -100.200714, 39.844661 ], "pop" : 304, "state" : "KS" }
+{ "_id" : "67654", "city" : "NORTON", "loc" : [ -99.887832, 39.840706 ], "pop" : 4360, "state" : "KS" }
+{ "_id" : "67656", "city" : "OGALLAH", "loc" : [ -99.681117, 38.932307 ], "pop" : 460, "state" : "KS" }
+{ "_id" : "67657", "city" : "PALCO", "loc" : [ -99.559265, 39.253107 ], "pop" : 384, "state" : "KS" }
+{ "_id" : "67658", "city" : "PARADISE", "loc" : [ -98.920723, 39.075617 ], "pop" : 219, "state" : "KS" }
+{ "_id" : "67659", "city" : "PENOKEE", "loc" : [ -99.919603, 39.391667 ], "pop" : 22, "state" : "KS" }
+{ "_id" : "67660", "city" : "PFEIFER", "loc" : [ -99.14116199999999, 38.729915 ], "pop" : 123, "state" : "KS" }
+{ "_id" : "67661", "city" : "PHILLIPSBURG", "loc" : [ -99.33284, 39.762333 ], "pop" : 3942, "state" : "KS" }
+{ "_id" : "67663", "city" : "PLAINVILLE", "loc" : [ -99.300827, 39.230823 ], "pop" : 2499, "state" : "KS" }
+{ "_id" : "67664", "city" : "PRAIRIE VIEW", "loc" : [ -99.568314, 39.836967 ], "pop" : 325, "state" : "KS" }
+{ "_id" : "67665", "city" : "RUSSELL", "loc" : [ -98.85945100000001, 38.880563 ], "pop" : 5370, "state" : "KS" }
+{ "_id" : "67667", "city" : "SCHOENCHEN", "loc" : [ -99.386872, 38.748087 ], "pop" : 534, "state" : "KS" }
+{ "_id" : "67669", "city" : "STOCKTON", "loc" : [ -99.28710599999999, 39.43761 ], "pop" : 2147, "state" : "KS" }
+{ "_id" : "67671", "city" : "VICTORIA", "loc" : [ -99.13905699999999, 38.858932 ], "pop" : 1877, "state" : "KS" }
+{ "_id" : "67672", "city" : "WA KEENEY", "loc" : [ -99.88182399999999, 39.011415 ], "pop" : 2711, "state" : "KS" }
+{ "_id" : "67673", "city" : "WALDO", "loc" : [ -98.778516, 39.087715 ], "pop" : 128, "state" : "KS" }
+{ "_id" : "67675", "city" : "WOODSTON", "loc" : [ -99.103745, 39.443118 ], "pop" : 317, "state" : "KS" }
+{ "_id" : "67676", "city" : "ZURICH", "loc" : [ -99.44908, 39.218155 ], "pop" : 318, "state" : "KS" }
+{ "_id" : "67701", "city" : "COLBY", "loc" : [ -101.044169, 39.383038 ], "pop" : 7225, "state" : "KS" }
+{ "_id" : "67730", "city" : "ATWOOD", "loc" : [ -101.031766, 39.792607 ], "pop" : 2174, "state" : "KS" }
+{ "_id" : "67731", "city" : "BIRD CITY", "loc" : [ -101.531875, 39.757941 ], "pop" : 794, "state" : "KS" }
+{ "_id" : "67732", "city" : "BREWSTER", "loc" : [ -101.372973, 39.36552 ], "pop" : 374, "state" : "KS" }
+{ "_id" : "67733", "city" : "EDSON", "loc" : [ -101.520999, 39.357873 ], "pop" : 294, "state" : "KS" }
+{ "_id" : "67734", "city" : "GEM", "loc" : [ -100.894781, 39.429587 ], "pop" : 157, "state" : "KS" }
+{ "_id" : "67735", "city" : "GOODLAND", "loc" : [ -101.716396, 39.349099 ], "pop" : 6039, "state" : "KS" }
+{ "_id" : "67736", "city" : "GOVE", "loc" : [ -100.486707, 38.886969 ], "pop" : 379, "state" : "KS" }
+{ "_id" : "67737", "city" : "GRAINFIELD", "loc" : [ -100.468038, 39.103016 ], "pop" : 467, "state" : "KS" }
+{ "_id" : "67738", "city" : "GRINNELL", "loc" : [ -100.662052, 39.085107 ], "pop" : 632, "state" : "KS" }
+{ "_id" : "67739", "city" : "HERNDON", "loc" : [ -100.813935, 39.90356 ], "pop" : 477, "state" : "KS" }
+{ "_id" : "67740", "city" : "HOXIE", "loc" : [ -100.47583, 39.332189 ], "pop" : 2023, "state" : "KS" }
+{ "_id" : "67741", "city" : "KANORADO", "loc" : [ -102.001491, 39.343753 ], "pop" : 593, "state" : "KS" }
+{ "_id" : "67743", "city" : "LEVANT", "loc" : [ -101.209587, 39.384083 ], "pop" : 143, "state" : "KS" }
+{ "_id" : "67744", "city" : "LUDELL", "loc" : [ -100.960352, 39.863037 ], "pop" : 155, "state" : "KS" }
+{ "_id" : "67745", "city" : "MC DONALD", "loc" : [ -101.322697, 39.792304 ], "pop" : 598, "state" : "KS" }
+{ "_id" : "67747", "city" : "MONUMENT", "loc" : [ -101.034952, 39.07896 ], "pop" : 164, "state" : "KS" }
+{ "_id" : "67748", "city" : "OAKLEY", "loc" : [ -100.858048, 39.112102 ], "pop" : 2346, "state" : "KS" }
+{ "_id" : "67749", "city" : "OBERLIN", "loc" : [ -100.531389, 39.827507 ], "pop" : 3046, "state" : "KS" }
+{ "_id" : "67751", "city" : "PARK", "loc" : [ -100.34694, 39.078832 ], "pop" : 316, "state" : "KS" }
+{ "_id" : "67752", "city" : "QUINTER", "loc" : [ -100.233739, 39.036252 ], "pop" : 1437, "state" : "KS" }
+{ "_id" : "67753", "city" : "MENLO", "loc" : [ -100.748982, 39.462185 ], "pop" : 246, "state" : "KS" }
+{ "_id" : "67755", "city" : "RUSSELL SPRINGS", "loc" : [ -101.2759, 38.868374 ], "pop" : 243, "state" : "KS" }
+{ "_id" : "67756", "city" : "WHEELER", "loc" : [ -101.81226, 39.773634 ], "pop" : 2449, "state" : "KS" }
+{ "_id" : "67757", "city" : "SELDEN", "loc" : [ -100.525695, 39.521636 ], "pop" : 872, "state" : "KS" }
+{ "_id" : "67758", "city" : "SHARON SPRINGS", "loc" : [ -101.743118, 38.885661 ], "pop" : 1148, "state" : "KS" }
+{ "_id" : "67759", "city" : "STUDLEY", "loc" : [ -100.281436, 39.261618 ], "pop" : 314, "state" : "KS" }
+{ "_id" : "67761", "city" : "WALLACE", "loc" : [ -101.573474, 38.874675 ], "pop" : 293, "state" : "KS" }
+{ "_id" : "67762", "city" : "WESKAN", "loc" : [ -101.951162, 38.864867 ], "pop" : 380, "state" : "KS" }
+{ "_id" : "67764", "city" : "WINONA", "loc" : [ -101.221569, 39.061038 ], "pop" : 328, "state" : "KS" }
+{ "_id" : "67801", "city" : "DODGE CITY", "loc" : [ -100.024074, 37.756882 ], "pop" : 23098, "state" : "KS" }
+{ "_id" : "67831", "city" : "ASHLAND", "loc" : [ -99.75904, 37.182345 ], "pop" : 1271, "state" : "KS" }
+{ "_id" : "67834", "city" : "BUCKLIN", "loc" : [ -99.632543, 37.552974 ], "pop" : 848, "state" : "KS" }
+{ "_id" : "67835", "city" : "CIMARRON", "loc" : [ -100.343825, 37.812727 ], "pop" : 2249, "state" : "KS" }
+{ "_id" : "67837", "city" : "COPELAND", "loc" : [ -100.614815, 37.567994 ], "pop" : 536, "state" : "KS" }
+{ "_id" : "67838", "city" : "DEERFIELD", "loc" : [ -101.143141, 38.00677 ], "pop" : 1077, "state" : "KS" }
+{ "_id" : "67839", "city" : "ALAMOTA", "loc" : [ -100.458023, 38.474588 ], "pop" : 1666, "state" : "KS" }
+{ "_id" : "67840", "city" : "ENGLEWOOD", "loc" : [ -99.987793, 37.065751 ], "pop" : 148, "state" : "KS" }
+{ "_id" : "67841", "city" : "ENSIGN", "loc" : [ -100.249555, 37.641381 ], "pop" : 373, "state" : "KS" }
+{ "_id" : "67842", "city" : "FORD", "loc" : [ -99.76421999999999, 37.632312 ], "pop" : 403, "state" : "KS" }
+{ "_id" : "67843", "city" : "FORT DODGE", "loc" : [ -99.94563100000001, 37.70652 ], "pop" : 736, "state" : "KS" }
+{ "_id" : "67844", "city" : "FOWLER", "loc" : [ -100.19815, 37.354201 ], "pop" : 881, "state" : "KS" }
+{ "_id" : "67846", "city" : "GARDEN CITY", "loc" : [ -100.862088, 37.97693 ], "pop" : 30189, "state" : "KS" }
+{ "_id" : "67849", "city" : "HANSTON", "loc" : [ -99.69278, 38.108964 ], "pop" : 695, "state" : "KS" }
+{ "_id" : "67850", "city" : "HEALY", "loc" : [ -100.615941, 38.566355 ], "pop" : 476, "state" : "KS" }
+{ "_id" : "67851", "city" : "HOLCOMB", "loc" : [ -100.989323, 37.993105 ], "pop" : 2060, "state" : "KS" }
+{ "_id" : "67853", "city" : "INGALLS", "loc" : [ -100.514253, 37.829339 ], "pop" : 807, "state" : "KS" }
+{ "_id" : "67854", "city" : "JETMORE", "loc" : [ -99.93266800000001, 38.073829 ], "pop" : 1482, "state" : "KS" }
+{ "_id" : "67855", "city" : "JOHNSON", "loc" : [ -101.719354, 37.569424 ], "pop" : 1979, "state" : "KS" }
+{ "_id" : "67856", "city" : "KALVESTA", "loc" : [ -100.443095, 38.102796 ], "pop" : 326, "state" : "KS" }
+{ "_id" : "67857", "city" : "KENDALL", "loc" : [ -101.596883, 37.963657 ], "pop" : 86, "state" : "KS" }
+{ "_id" : "67858", "city" : "KINGSDOWN", "loc" : [ -99.751553, 37.52138 ], "pop" : 124, "state" : "KS" }
+{ "_id" : "67859", "city" : "KISMET", "loc" : [ -100.750645, 37.133601 ], "pop" : 1195, "state" : "KS" }
+{ "_id" : "67860", "city" : "LAKIN", "loc" : [ -101.271297, 37.938197 ], "pop" : 2950, "state" : "KS" }
+{ "_id" : "67861", "city" : "LEOTI", "loc" : [ -101.358851, 38.498726 ], "pop" : 2604, "state" : "KS" }
+{ "_id" : "67862", "city" : "MANTER", "loc" : [ -101.910869, 37.545094 ], "pop" : 354, "state" : "KS" }
+{ "_id" : "67863", "city" : "MODOC", "loc" : [ -101.199231, 38.482523 ], "pop" : 154, "state" : "KS" }
+{ "_id" : "67864", "city" : "MEADE", "loc" : [ -100.336378, 37.282137 ], "pop" : 1949, "state" : "KS" }
+{ "_id" : "67865", "city" : "BLOOM", "loc" : [ -99.960358, 37.42454 ], "pop" : 999, "state" : "KS" }
+{ "_id" : "67867", "city" : "MONTEZUMA", "loc" : [ -100.446127, 37.601638 ], "pop" : 1431, "state" : "KS" }
+{ "_id" : "67868", "city" : "PIERCEVILLE", "loc" : [ -100.71177, 37.907739 ], "pop" : 495, "state" : "KS" }
+{ "_id" : "67869", "city" : "PLAINS", "loc" : [ -100.573174, 37.270106 ], "pop" : 1417, "state" : "KS" }
+{ "_id" : "67870", "city" : "SATANTA", "loc" : [ -100.96908, 37.440916 ], "pop" : 1881, "state" : "KS" }
+{ "_id" : "67871", "city" : "FRIEND", "loc" : [ -100.899331, 38.47994 ], "pop" : 4476, "state" : "KS" }
+{ "_id" : "67874", "city" : "SHIELDS", "loc" : [ -100.417699, 38.620794 ], "pop" : 158, "state" : "KS" }
+{ "_id" : "67876", "city" : "SPEARVILLE", "loc" : [ -99.737041, 37.823473 ], "pop" : 1361, "state" : "KS" }
+{ "_id" : "67877", "city" : "SUBLETTE", "loc" : [ -100.820775, 37.522148 ], "pop" : 2364, "state" : "KS" }
+{ "_id" : "67878", "city" : "SYRACUSE", "loc" : [ -101.768654, 37.982581 ], "pop" : 2302, "state" : "KS" }
+{ "_id" : "67879", "city" : "TRIBUNE", "loc" : [ -101.765584, 38.496219 ], "pop" : 1774, "state" : "KS" }
+{ "_id" : "67880", "city" : "ULYSSES", "loc" : [ -101.348846, 37.579174 ], "pop" : 7159, "state" : "KS" }
+{ "_id" : "67882", "city" : "WRIGHT", "loc" : [ -99.923766, 37.767638 ], "pop" : 759, "state" : "KS" }
+{ "_id" : "67901", "city" : "LIBERAL", "loc" : [ -100.92857, 37.043789 ], "pop" : 17189, "state" : "KS" }
+{ "_id" : "67950", "city" : "ELKHART", "loc" : [ -101.901244, 37.015448 ], "pop" : 2562, "state" : "KS" }
+{ "_id" : "67951", "city" : "HUGOTON", "loc" : [ -101.334614, 37.168226 ], "pop" : 4244, "state" : "KS" }
+{ "_id" : "67952", "city" : "MOSCOW", "loc" : [ -101.242699, 37.317175 ], "pop" : 804, "state" : "KS" }
+{ "_id" : "67953", "city" : "RICHFIELD", "loc" : [ -101.700382, 37.283364 ], "pop" : 269, "state" : "KS" }
+{ "_id" : "67954", "city" : "ROLLA", "loc" : [ -101.644683, 37.108881 ], "pop" : 649, "state" : "KS" }
+{ "_id" : "68001", "city" : "ABIE", "loc" : [ -96.956282, 41.347901 ], "pop" : 282, "state" : "NE" }
+{ "_id" : "68002", "city" : "ARLINGTON", "loc" : [ -96.306974, 41.441654 ], "pop" : 2075, "state" : "NE" }
+{ "_id" : "68003", "city" : "ASHLAND", "loc" : [ -96.39041, 41.05411 ], "pop" : 3296, "state" : "NE" }
+{ "_id" : "68004", "city" : "BANCROFT", "loc" : [ -96.61714600000001, 42.026716 ], "pop" : 913, "state" : "NE" }
+{ "_id" : "68005", "city" : "BELLEVUE", "loc" : [ -95.909932, 41.149663 ], "pop" : 24133, "state" : "NE" }
+{ "_id" : "68007", "city" : "BENNINGTON", "loc" : [ -96.15752500000001, 41.362262 ], "pop" : 1372, "state" : "NE" }
+{ "_id" : "68008", "city" : "BLAIR", "loc" : [ -96.161666, 41.545376 ], "pop" : 9059, "state" : "NE" }
+{ "_id" : "68014", "city" : "BRUNO", "loc" : [ -96.964612, 41.271771 ], "pop" : 366, "state" : "NE" }
+{ "_id" : "68015", "city" : "CEDAR BLUFFS", "loc" : [ -96.569115, 41.383492 ], "pop" : 1911, "state" : "NE" }
+{ "_id" : "68017", "city" : "CERESCO", "loc" : [ -96.639769, 41.06807 ], "pop" : 1237, "state" : "NE" }
+{ "_id" : "68018", "city" : "COLON", "loc" : [ -96.614132, 41.288261 ], "pop" : 290, "state" : "NE" }
+{ "_id" : "68019", "city" : "CRAIG", "loc" : [ -96.392398, 41.771497 ], "pop" : 574, "state" : "NE" }
+{ "_id" : "68020", "city" : "DECATUR", "loc" : [ -96.259456, 41.996553 ], "pop" : 975, "state" : "NE" }
+{ "_id" : "68022", "city" : "ELKHORN", "loc" : [ -96.24308000000001, 41.275647 ], "pop" : 8508, "state" : "NE" }
+{ "_id" : "68023", "city" : "FORT CALHOUN", "loc" : [ -96.032375, 41.437281 ], "pop" : 2833, "state" : "NE" }
+{ "_id" : "68025", "city" : "FREMONT", "loc" : [ -96.494468, 41.441637 ], "pop" : 26498, "state" : "NE" }
+{ "_id" : "68028", "city" : "GRETNA", "loc" : [ -96.24583699999999, 41.134458 ], "pop" : 3236, "state" : "NE" }
+{ "_id" : "68029", "city" : "HERMAN", "loc" : [ -96.286942, 41.652381 ], "pop" : 988, "state" : "NE" }
+{ "_id" : "68031", "city" : "HOOPER", "loc" : [ -96.523231, 41.641371 ], "pop" : 1821, "state" : "NE" }
+{ "_id" : "68033", "city" : "ITHACA", "loc" : [ -96.529785, 41.174849 ], "pop" : 359, "state" : "NE" }
+{ "_id" : "68034", "city" : "KENNARD", "loc" : [ -96.16192700000001, 41.471139 ], "pop" : 1652, "state" : "NE" }
+{ "_id" : "68035", "city" : "LESHARA", "loc" : [ -96.449805, 41.346597 ], "pop" : 492, "state" : "NE" }
+{ "_id" : "68036", "city" : "LINWOOD", "loc" : [ -96.93987300000001, 41.412926 ], "pop" : 175, "state" : "NE" }
+{ "_id" : "68037", "city" : "LOUISVILLE", "loc" : [ -96.194817, 40.996667 ], "pop" : 1998, "state" : "NE" }
+{ "_id" : "68038", "city" : "LYONS", "loc" : [ -96.46613600000001, 41.94416 ], "pop" : 1613, "state" : "NE" }
+{ "_id" : "68039", "city" : "MACY", "loc" : [ -96.35886499999999, 42.117739 ], "pop" : 1464, "state" : "NE" }
+{ "_id" : "68040", "city" : "MALMO", "loc" : [ -96.73271800000001, 41.298424 ], "pop" : 584, "state" : "NE" }
+{ "_id" : "68041", "city" : "MEAD", "loc" : [ -96.49614099999999, 41.23929 ], "pop" : 786, "state" : "NE" }
+{ "_id" : "68044", "city" : "NICKERSON", "loc" : [ -96.49042300000001, 41.523293 ], "pop" : 691, "state" : "NE" }
+{ "_id" : "68045", "city" : "OAKLAND", "loc" : [ -96.46706399999999, 41.838426 ], "pop" : 1855, "state" : "NE" }
+{ "_id" : "68046", "city" : "PAPILLION", "loc" : [ -96.037052, 41.152257 ], "pop" : 7177, "state" : "NE" }
+{ "_id" : "68047", "city" : "PENDER", "loc" : [ -96.718907, 42.117719 ], "pop" : 1818, "state" : "NE" }
+{ "_id" : "68048", "city" : "PLATTSMOUTH", "loc" : [ -95.913933, 40.999194 ], "pop" : 10387, "state" : "NE" }
+{ "_id" : "68050", "city" : "PRAGUE", "loc" : [ -96.830084, 41.303598 ], "pop" : 819, "state" : "NE" }
+{ "_id" : "68054", "city" : "RICHFIELD", "loc" : [ -96.045627, 41.090522 ], "pop" : 822, "state" : "NE" }
+{ "_id" : "68055", "city" : "ROSALIE", "loc" : [ -96.49286600000001, 42.057435 ], "pop" : 424, "state" : "NE" }
+{ "_id" : "68057", "city" : "SCRIBNER", "loc" : [ -96.64409499999999, 41.663035 ], "pop" : 1485, "state" : "NE" }
+{ "_id" : "68059", "city" : "SPRINGFIELD", "loc" : [ -96.143811, 41.07649 ], "pop" : 2961, "state" : "NE" }
+{ "_id" : "68061", "city" : "TEKAMAH", "loc" : [ -96.228144, 41.781898 ], "pop" : 2881, "state" : "NE" }
+{ "_id" : "68062", "city" : "THURSTON", "loc" : [ -96.69035599999999, 42.188161 ], "pop" : 362, "state" : "NE" }
+{ "_id" : "68064", "city" : "VALLEY", "loc" : [ -96.346288, 41.318581 ], "pop" : 3067, "state" : "NE" }
+{ "_id" : "68065", "city" : "VALPARAISO", "loc" : [ -96.80914900000001, 41.084304 ], "pop" : 1095, "state" : "NE" }
+{ "_id" : "68066", "city" : "WAHOO", "loc" : [ -96.62194599999999, 41.211723 ], "pop" : 4258, "state" : "NE" }
+{ "_id" : "68067", "city" : "WALTHILL", "loc" : [ -96.480294, 42.148543 ], "pop" : 1212, "state" : "NE" }
+{ "_id" : "68069", "city" : "WATERLOO", "loc" : [ -96.306318, 41.27024 ], "pop" : 1468, "state" : "NE" }
+{ "_id" : "68070", "city" : "WESTON", "loc" : [ -96.769075, 41.181083 ], "pop" : 834, "state" : "NE" }
+{ "_id" : "68071", "city" : "WINNEBAGO", "loc" : [ -96.468507, 42.233851 ], "pop" : 1449, "state" : "NE" }
+{ "_id" : "68073", "city" : "YUTAN", "loc" : [ -96.393247, 41.23403 ], "pop" : 1838, "state" : "NE" }
+{ "_id" : "68102", "city" : "OMAHA", "loc" : [ -95.940909, 41.258961 ], "pop" : 4963, "state" : "NE" }
+{ "_id" : "68104", "city" : "OMAHA", "loc" : [ -95.999888, 41.29186 ], "pop" : 35325, "state" : "NE" }
+{ "_id" : "68105", "city" : "OMAHA", "loc" : [ -95.96293799999999, 41.243502 ], "pop" : 23007, "state" : "NE" }
+{ "_id" : "68106", "city" : "OMAHA", "loc" : [ -95.997972, 41.240322 ], "pop" : 20622, "state" : "NE" }
+{ "_id" : "68107", "city" : "OMAHA", "loc" : [ -95.955877, 41.206783 ], "pop" : 23890, "state" : "NE" }
+{ "_id" : "68108", "city" : "OMAHA", "loc" : [ -95.93355699999999, 41.238198 ], "pop" : 12721, "state" : "NE" }
+{ "_id" : "68110", "city" : "OMAHA", "loc" : [ -95.936072, 41.293342 ], "pop" : 8718, "state" : "NE" }
+{ "_id" : "68111", "city" : "OMAHA", "loc" : [ -95.965045, 41.296212 ], "pop" : 28453, "state" : "NE" }
+{ "_id" : "68112", "city" : "OMAHA", "loc" : [ -95.959684, 41.329614 ], "pop" : 12075, "state" : "NE" }
+{ "_id" : "68113", "city" : "OFFUTT A F B", "loc" : [ -95.907601, 41.114755 ], "pop" : 2894, "state" : "NE" }
+{ "_id" : "68114", "city" : "OMAHA", "loc" : [ -96.049306, 41.265624 ], "pop" : 16573, "state" : "NE" }
+{ "_id" : "68116", "city" : "OMAHA", "loc" : [ -96.149462, 41.287854 ], "pop" : 875, "state" : "NE" }
+{ "_id" : "68117", "city" : "OMAHA", "loc" : [ -95.995301, 41.206403 ], "pop" : 8347, "state" : "NE" }
+{ "_id" : "68118", "city" : "OMAHA", "loc" : [ -96.166118, 41.260636 ], "pop" : 3593, "state" : "NE" }
+{ "_id" : "68122", "city" : "OMAHA", "loc" : [ -96.045772, 41.333312 ], "pop" : 2556, "state" : "NE" }
+{ "_id" : "68123", "city" : "OMAHA", "loc" : [ -95.95599, 41.122265 ], "pop" : 20362, "state" : "NE" }
+{ "_id" : "68124", "city" : "OMAHA", "loc" : [ -96.049515, 41.233814 ], "pop" : 16340, "state" : "NE" }
+{ "_id" : "68127", "city" : "RALSTON", "loc" : [ -96.055019, 41.201782 ], "pop" : 22434, "state" : "NE" }
+{ "_id" : "68128", "city" : "PAPILLION", "loc" : [ -96.040256, 41.171983 ], "pop" : 15882, "state" : "NE" }
+{ "_id" : "68130", "city" : "OMAHA", "loc" : [ -96.168815, 41.235452 ], "pop" : 7291, "state" : "NE" }
+{ "_id" : "68131", "city" : "OMAHA", "loc" : [ -95.963891, 41.264658 ], "pop" : 14069, "state" : "NE" }
+{ "_id" : "68132", "city" : "OMAHA", "loc" : [ -95.995954, 41.265746 ], "pop" : 13730, "state" : "NE" }
+{ "_id" : "68133", "city" : "PAPILLION", "loc" : [ -96.013076, 41.141564 ], "pop" : 842, "state" : "NE" }
+{ "_id" : "68134", "city" : "OMAHA", "loc" : [ -96.054569, 41.294917 ], "pop" : 27571, "state" : "NE" }
+{ "_id" : "68135", "city" : "OMAHA", "loc" : [ -96.169827, 41.210419 ], "pop" : 2503, "state" : "NE" }
+{ "_id" : "68136", "city" : "OMAHA", "loc" : [ -96.209633, 41.168343 ], "pop" : 226, "state" : "NE" }
+{ "_id" : "68137", "city" : "MILLARD", "loc" : [ -96.12446199999999, 41.201067 ], "pop" : 23894, "state" : "NE" }
+{ "_id" : "68138", "city" : "PAPILLION", "loc" : [ -96.129718, 41.177724 ], "pop" : 8845, "state" : "NE" }
+{ "_id" : "68142", "city" : "OMAHA", "loc" : [ -96.090109, 41.335904 ], "pop" : 1249, "state" : "NE" }
+{ "_id" : "68144", "city" : "MILLARD", "loc" : [ -96.116772, 41.235599 ], "pop" : 26450, "state" : "NE" }
+{ "_id" : "68147", "city" : "OMAHA", "loc" : [ -95.95915599999999, 41.181508 ], "pop" : 9205, "state" : "NE" }
+{ "_id" : "68152", "city" : "OMAHA", "loc" : [ -96.00029499999999, 41.334557 ], "pop" : 6518, "state" : "NE" }
+{ "_id" : "68154", "city" : "OMAHA", "loc" : [ -96.120611, 41.264167 ], "pop" : 21847, "state" : "NE" }
+{ "_id" : "68157", "city" : "PAPILLION", "loc" : [ -95.995378, 41.183423 ], "pop" : 6112, "state" : "NE" }
+{ "_id" : "68164", "city" : "OMAHA", "loc" : [ -96.100793, 41.29552 ], "pop" : 16301, "state" : "NE" }
+{ "_id" : "68301", "city" : "ADAMS", "loc" : [ -96.53955999999999, 40.457571 ], "pop" : 1127, "state" : "NE" }
+{ "_id" : "68303", "city" : "ALEXANDRIA", "loc" : [ -97.40385499999999, 40.261446 ], "pop" : 429, "state" : "NE" }
+{ "_id" : "68304", "city" : "ALVO", "loc" : [ -96.40355700000001, 40.899185 ], "pop" : 447, "state" : "NE" }
+{ "_id" : "68305", "city" : "AUBURN", "loc" : [ -95.85264599999999, 40.378889 ], "pop" : 4296, "state" : "NE" }
+{ "_id" : "68307", "city" : "AVOCA", "loc" : [ -96.095736, 40.815941 ], "pop" : 444, "state" : "NE" }
+{ "_id" : "68310", "city" : "BEATRICE", "loc" : [ -96.743494, 40.270509 ], "pop" : 15528, "state" : "NE" }
+{ "_id" : "68313", "city" : "BEAVER CROSSING", "loc" : [ -97.29135599999999, 40.788658 ], "pop" : 827, "state" : "NE" }
+{ "_id" : "68314", "city" : "BEE", "loc" : [ -97.07446899999999, 41.000675 ], "pop" : 447, "state" : "NE" }
+{ "_id" : "68315", "city" : "BELVIDERE", "loc" : [ -97.55541599999999, 40.25101 ], "pop" : 233, "state" : "NE" }
+{ "_id" : "68316", "city" : "BENEDICT", "loc" : [ -97.60292099999999, 41.003268 ], "pop" : 646, "state" : "NE" }
+{ "_id" : "68317", "city" : "BENNET", "loc" : [ -96.5134, 40.63822 ], "pop" : 1611, "state" : "NE" }
+{ "_id" : "68318", "city" : "BLUE SPRINGS", "loc" : [ -96.659037, 40.140684 ], "pop" : 504, "state" : "NE" }
+{ "_id" : "68319", "city" : "BRADSHAW", "loc" : [ -97.760699, 40.920718 ], "pop" : 716, "state" : "NE" }
+{ "_id" : "68320", "city" : "BROCK", "loc" : [ -95.98014499999999, 40.477227 ], "pop" : 400, "state" : "NE" }
+{ "_id" : "68321", "city" : "BROWNVILLE", "loc" : [ -95.69347999999999, 40.399447 ], "pop" : 475, "state" : "NE" }
+{ "_id" : "68322", "city" : "BRUNING", "loc" : [ -97.557276, 40.330157 ], "pop" : 496, "state" : "NE" }
+{ "_id" : "68323", "city" : "BURCHARD", "loc" : [ -96.348806, 40.105743 ], "pop" : 507, "state" : "NE" }
+{ "_id" : "68324", "city" : "BURR", "loc" : [ -96.238401, 40.560057 ], "pop" : 500, "state" : "NE" }
+{ "_id" : "68325", "city" : "BYRON", "loc" : [ -97.761236, 40.02688 ], "pop" : 357, "state" : "NE" }
+{ "_id" : "68326", "city" : "CARLETON", "loc" : [ -97.671909, 40.300534 ], "pop" : 323, "state" : "NE" }
+{ "_id" : "68327", "city" : "CHESTER", "loc" : [ -97.61969000000001, 40.028954 ], "pop" : 527, "state" : "NE" }
+{ "_id" : "68328", "city" : "CLATONIA", "loc" : [ -96.855513, 40.47236 ], "pop" : 502, "state" : "NE" }
+{ "_id" : "68329", "city" : "COOK", "loc" : [ -96.15262, 40.498628 ], "pop" : 592, "state" : "NE" }
+{ "_id" : "68330", "city" : "CORDOVA", "loc" : [ -97.340721, 40.718477 ], "pop" : 241, "state" : "NE" }
+{ "_id" : "68331", "city" : "CORTLAND", "loc" : [ -96.716627, 40.497599 ], "pop" : 691, "state" : "NE" }
+{ "_id" : "68332", "city" : "CRAB ORCHARD", "loc" : [ -96.411569, 40.316648 ], "pop" : 169, "state" : "NE" }
+{ "_id" : "68333", "city" : "CRETE", "loc" : [ -96.956676, 40.619302 ], "pop" : 6390, "state" : "NE" }
+{ "_id" : "68335", "city" : "DAVENPORT", "loc" : [ -97.80495999999999, 40.310782 ], "pop" : 488, "state" : "NE" }
+{ "_id" : "68336", "city" : "DAVEY", "loc" : [ -96.641379, 41.002543 ], "pop" : 413, "state" : "NE" }
+{ "_id" : "68337", "city" : "DAWSON", "loc" : [ -95.834097, 40.137697 ], "pop" : 359, "state" : "NE" }
+{ "_id" : "68338", "city" : "DAYKIN", "loc" : [ -97.304306, 40.31916 ], "pop" : 324, "state" : "NE" }
+{ "_id" : "68339", "city" : "DENTON", "loc" : [ -96.853157, 40.700905 ], "pop" : 1035, "state" : "NE" }
+{ "_id" : "68340", "city" : "DESHLER", "loc" : [ -97.730007, 40.138668 ], "pop" : 1108, "state" : "NE" }
+{ "_id" : "68341", "city" : "DE WITT", "loc" : [ -96.93376600000001, 40.39438 ], "pop" : 821, "state" : "NE" }
+{ "_id" : "68342", "city" : "DILLER", "loc" : [ -96.949487, 40.119201 ], "pop" : 507, "state" : "NE" }
+{ "_id" : "68343", "city" : "DORCHESTER", "loc" : [ -97.10556200000001, 40.649858 ], "pop" : 832, "state" : "NE" }
+{ "_id" : "68344", "city" : "DOUGLAS", "loc" : [ -96.396958, 40.583824 ], "pop" : 369, "state" : "NE" }
+{ "_id" : "68345", "city" : "DU BOIS", "loc" : [ -96.05747700000001, 40.037486 ], "pop" : 315, "state" : "NE" }
+{ "_id" : "68346", "city" : "DUNBAR", "loc" : [ -96.013575, 40.659156 ], "pop" : 619, "state" : "NE" }
+{ "_id" : "68347", "city" : "EAGLE", "loc" : [ -96.42896500000001, 40.816909 ], "pop" : 1561, "state" : "NE" }
+{ "_id" : "68348", "city" : "ELK CREEK", "loc" : [ -96.142128, 40.2977 ], "pop" : 356, "state" : "NE" }
+{ "_id" : "68349", "city" : "ELMWOOD", "loc" : [ -96.29439499999999, 40.837811 ], "pop" : 879, "state" : "NE" }
+{ "_id" : "68350", "city" : "ENDICOTT", "loc" : [ -97.09378700000001, 40.073407 ], "pop" : 282, "state" : "NE" }
+{ "_id" : "68351", "city" : "EXETER", "loc" : [ -97.44238799999999, 40.634062 ], "pop" : 934, "state" : "NE" }
+{ "_id" : "68352", "city" : "FAIRBURY", "loc" : [ -97.18391800000001, 40.148817 ], "pop" : 5763, "state" : "NE" }
+{ "_id" : "68354", "city" : "FAIRMONT", "loc" : [ -97.58729, 40.6404 ], "pop" : 968, "state" : "NE" }
+{ "_id" : "68355", "city" : "FALLS CITY", "loc" : [ -95.593148, 40.074193 ], "pop" : 6069, "state" : "NE" }
+{ "_id" : "68357", "city" : "FILLEY", "loc" : [ -96.53013199999999, 40.294606 ], "pop" : 352, "state" : "NE" }
+{ "_id" : "68358", "city" : "FIRTH", "loc" : [ -96.614023, 40.558595 ], "pop" : 1095, "state" : "NE" }
+{ "_id" : "68359", "city" : "FRIEND", "loc" : [ -97.273928, 40.636792 ], "pop" : 1707, "state" : "NE" }
+{ "_id" : "68360", "city" : "GARLAND", "loc" : [ -96.97019, 40.941189 ], "pop" : 795, "state" : "NE" }
+{ "_id" : "68361", "city" : "GENEVA", "loc" : [ -97.60962499999999, 40.527731 ], "pop" : 3224, "state" : "NE" }
+{ "_id" : "68362", "city" : "GILEAD", "loc" : [ -97.42713999999999, 40.146986 ], "pop" : 169, "state" : "NE" }
+{ "_id" : "68364", "city" : "GOEHNER", "loc" : [ -97.205456, 40.830208 ], "pop" : 457, "state" : "NE" }
+{ "_id" : "68365", "city" : "GRAFTON", "loc" : [ -97.740263, 40.640193 ], "pop" : 302, "state" : "NE" }
+{ "_id" : "68366", "city" : "GREENWOOD", "loc" : [ -96.42583999999999, 40.97064 ], "pop" : 813, "state" : "NE" }
+{ "_id" : "68367", "city" : "GRESHAM", "loc" : [ -97.407937, 41.020952 ], "pop" : 426, "state" : "NE" }
+{ "_id" : "68368", "city" : "HALLAM", "loc" : [ -96.754518, 40.554734 ], "pop" : 663, "state" : "NE" }
+{ "_id" : "68370", "city" : "HEBRON", "loc" : [ -97.605228, 40.172807 ], "pop" : 2305, "state" : "NE" }
+{ "_id" : "68371", "city" : "HENDERSON", "loc" : [ -97.797865, 40.781374 ], "pop" : 1615, "state" : "NE" }
+{ "_id" : "68372", "city" : "HOLLAND", "loc" : [ -96.62492399999999, 40.624558 ], "pop" : 1495, "state" : "NE" }
+{ "_id" : "68374", "city" : "HOLMESVILLE", "loc" : [ -96.63263499999999, 40.220245 ], "pop" : 353, "state" : "NE" }
+{ "_id" : "68375", "city" : "HUBBELL", "loc" : [ -97.473467, 40.045581 ], "pop" : 200, "state" : "NE" }
+{ "_id" : "68376", "city" : "HUMBOLDT", "loc" : [ -95.931079, 40.156595 ], "pop" : 1806, "state" : "NE" }
+{ "_id" : "68377", "city" : "JANSEN", "loc" : [ -97.02442600000001, 40.207425 ], "pop" : 579, "state" : "NE" }
+{ "_id" : "68378", "city" : "JOHNSON", "loc" : [ -95.988276, 40.401623 ], "pop" : 747, "state" : "NE" }
+{ "_id" : "68379", "city" : "JULIAN", "loc" : [ -95.85046, 40.486056 ], "pop" : 313, "state" : "NE" }
+{ "_id" : "68380", "city" : "LEWISTON", "loc" : [ -96.40494099999999, 40.230879 ], "pop" : 189, "state" : "NE" }
+{ "_id" : "68381", "city" : "LIBERTY", "loc" : [ -96.523668, 40.075286 ], "pop" : 422, "state" : "NE" }
+{ "_id" : "68401", "city" : "MC COOL JUNCTION", "loc" : [ -97.593666, 40.744181 ], "pop" : 820, "state" : "NE" }
+{ "_id" : "68402", "city" : "MALCOLM", "loc" : [ -96.859966, 40.90913 ], "pop" : 954, "state" : "NE" }
+{ "_id" : "68404", "city" : "MARTELL", "loc" : [ -96.744227, 40.651434 ], "pop" : 864, "state" : "NE" }
+{ "_id" : "68405", "city" : "MILFORD", "loc" : [ -97.05763, 40.763153 ], "pop" : 3258, "state" : "NE" }
+{ "_id" : "68406", "city" : "MILLIGAN", "loc" : [ -97.39968399999999, 40.495163 ], "pop" : 477, "state" : "NE" }
+{ "_id" : "68407", "city" : "MURDOCK", "loc" : [ -96.28482700000001, 40.919034 ], "pop" : 622, "state" : "NE" }
+{ "_id" : "68409", "city" : "MURRAY", "loc" : [ -95.922668, 40.91999 ], "pop" : 1145, "state" : "NE" }
+{ "_id" : "68410", "city" : "NEBRASKA CITY", "loc" : [ -95.86190000000001, 40.674746 ], "pop" : 7668, "state" : "NE" }
+{ "_id" : "68413", "city" : "NEHAWKA", "loc" : [ -95.993045, 40.832978 ], "pop" : 423, "state" : "NE" }
+{ "_id" : "68414", "city" : "NEMAHA", "loc" : [ -95.69132999999999, 40.319818 ], "pop" : 428, "state" : "NE" }
+{ "_id" : "68415", "city" : "ODELL", "loc" : [ -96.801924, 40.045128 ], "pop" : 642, "state" : "NE" }
+{ "_id" : "68416", "city" : "OHIOWA", "loc" : [ -97.442712, 40.406507 ], "pop" : 274, "state" : "NE" }
+{ "_id" : "68417", "city" : "OTOE", "loc" : [ -96.132867, 40.735485 ], "pop" : 696, "state" : "NE" }
+{ "_id" : "68418", "city" : "PALMYRA", "loc" : [ -96.39990299999999, 40.704964 ], "pop" : 1012, "state" : "NE" }
+{ "_id" : "68420", "city" : "PAWNEE CITY", "loc" : [ -96.150926, 40.109291 ], "pop" : 1434, "state" : "NE" }
+{ "_id" : "68421", "city" : "PERU", "loc" : [ -95.731166, 40.476643 ], "pop" : 1321, "state" : "NE" }
+{ "_id" : "68422", "city" : "PICKRELL", "loc" : [ -96.734444, 40.382117 ], "pop" : 512, "state" : "NE" }
+{ "_id" : "68423", "city" : "PLEASANT DALE", "loc" : [ -96.95128, 40.813329 ], "pop" : 678, "state" : "NE" }
+{ "_id" : "68424", "city" : "PLYMOUTH", "loc" : [ -97.001169, 40.303896 ], "pop" : 872, "state" : "NE" }
+{ "_id" : "68428", "city" : "AGNEW", "loc" : [ -96.78294200000001, 40.985331 ], "pop" : 1218, "state" : "NE" }
+{ "_id" : "68429", "city" : "REYNOLDS", "loc" : [ -97.318243, 40.059372 ], "pop" : 184, "state" : "NE" }
+{ "_id" : "68430", "city" : "ROCA", "loc" : [ -96.63908499999999, 40.670195 ], "pop" : 517, "state" : "NE" }
+{ "_id" : "68431", "city" : "RULO", "loc" : [ -95.42921800000001, 40.053619 ], "pop" : 312, "state" : "NE" }
+{ "_id" : "68432", "city" : "SAINT MARY", "loc" : [ -96.28997200000001, 40.444756 ], "pop" : 259, "state" : "NE" }
+{ "_id" : "68433", "city" : "SALEM", "loc" : [ -95.727261, 40.061953 ], "pop" : 280, "state" : "NE" }
+{ "_id" : "68434", "city" : "SEWARD", "loc" : [ -97.09661800000001, 40.906609 ], "pop" : 7082, "state" : "NE" }
+{ "_id" : "68436", "city" : "SHICKLEY", "loc" : [ -97.714298, 40.407677 ], "pop" : 722, "state" : "NE" }
+{ "_id" : "68437", "city" : "SHUBERT", "loc" : [ -95.689454, 40.232479 ], "pop" : 320, "state" : "NE" }
+{ "_id" : "68439", "city" : "STAPLEHURST", "loc" : [ -97.18585899999999, 40.984455 ], "pop" : 597, "state" : "NE" }
+{ "_id" : "68440", "city" : "STEELE CITY", "loc" : [ -96.990712, 40.042492 ], "pop" : 248, "state" : "NE" }
+{ "_id" : "68441", "city" : "STEINAUER", "loc" : [ -96.230215, 40.216885 ], "pop" : 378, "state" : "NE" }
+{ "_id" : "68442", "city" : "STELLA", "loc" : [ -95.767989, 40.230345 ], "pop" : 342, "state" : "NE" }
+{ "_id" : "68443", "city" : "STERLING", "loc" : [ -96.386655, 40.463743 ], "pop" : 840, "state" : "NE" }
+{ "_id" : "68444", "city" : "STRANG", "loc" : [ -97.552132, 40.398105 ], "pop" : 202, "state" : "NE" }
+{ "_id" : "68445", "city" : "SWANTON", "loc" : [ -97.08055, 40.384389 ], "pop" : 266, "state" : "NE" }
+{ "_id" : "68446", "city" : "SYRACUSE", "loc" : [ -96.182407, 40.661386 ], "pop" : 1937, "state" : "NE" }
+{ "_id" : "68447", "city" : "TABLE ROCK", "loc" : [ -96.081822, 40.187437 ], "pop" : 494, "state" : "NE" }
+{ "_id" : "68448", "city" : "TALMAGE", "loc" : [ -96.013814, 40.558646 ], "pop" : 731, "state" : "NE" }
+{ "_id" : "68450", "city" : "TECUMSEH", "loc" : [ -96.20495099999999, 40.369702 ], "pop" : 2457, "state" : "NE" }
+{ "_id" : "68452", "city" : "ONG", "loc" : [ -97.861018, 40.396806 ], "pop" : 150, "state" : "NE" }
+{ "_id" : "68453", "city" : "TOBIAS", "loc" : [ -97.318444, 40.426171 ], "pop" : 464, "state" : "NE" }
+{ "_id" : "68454", "city" : "UNADILLA", "loc" : [ -96.282454, 40.691675 ], "pop" : 720, "state" : "NE" }
+{ "_id" : "68455", "city" : "UNION", "loc" : [ -95.903739, 40.824452 ], "pop" : 689, "state" : "NE" }
+{ "_id" : "68456", "city" : "UTICA", "loc" : [ -97.334431, 40.91685 ], "pop" : 1068, "state" : "NE" }
+{ "_id" : "68457", "city" : "VERDON", "loc" : [ -95.716157, 40.142507 ], "pop" : 449, "state" : "NE" }
+{ "_id" : "68458", "city" : "VIRGINIA", "loc" : [ -96.512145, 40.230877 ], "pop" : 226, "state" : "NE" }
+{ "_id" : "68460", "city" : "WACO", "loc" : [ -97.453352, 40.919826 ], "pop" : 613, "state" : "NE" }
+{ "_id" : "68461", "city" : "WALTON", "loc" : [ -96.535943, 40.797467 ], "pop" : 268, "state" : "NE" }
+{ "_id" : "68462", "city" : "WAVERLY", "loc" : [ -96.525988, 40.92224 ], "pop" : 2545, "state" : "NE" }
+{ "_id" : "68463", "city" : "WEEPING WATER", "loc" : [ -96.15282500000001, 40.873096 ], "pop" : 1910, "state" : "NE" }
+{ "_id" : "68464", "city" : "WESTERN", "loc" : [ -97.197649, 40.415157 ], "pop" : 552, "state" : "NE" }
+{ "_id" : "68465", "city" : "WILBER", "loc" : [ -96.975713, 40.482141 ], "pop" : 2016, "state" : "NE" }
+{ "_id" : "68466", "city" : "WYMORE", "loc" : [ -96.661326, 40.112955 ], "pop" : 1935, "state" : "NE" }
+{ "_id" : "68467", "city" : "YORK", "loc" : [ -97.582482, 40.866678 ], "pop" : 9592, "state" : "NE" }
+{ "_id" : "68502", "city" : "LINCOLN", "loc" : [ -96.693763, 40.789282 ], "pop" : 27576, "state" : "NE" }
+{ "_id" : "68503", "city" : "LINCOLN", "loc" : [ -96.67662300000001, 40.823339 ], "pop" : 14093, "state" : "NE" }
+{ "_id" : "68504", "city" : "LINCOLN", "loc" : [ -96.653248, 40.839226 ], "pop" : 12756, "state" : "NE" }
+{ "_id" : "68505", "city" : "LINCOLN", "loc" : [ -96.625193, 40.824674 ], "pop" : 13461, "state" : "NE" }
+{ "_id" : "68506", "city" : "LINCOLN", "loc" : [ -96.643052, 40.784796 ], "pop" : 25903, "state" : "NE" }
+{ "_id" : "68507", "city" : "LINCOLN", "loc" : [ -96.628874, 40.847265 ], "pop" : 12296, "state" : "NE" }
+{ "_id" : "68508", "city" : "LINCOLN", "loc" : [ -96.700907, 40.814503 ], "pop" : 13716, "state" : "NE" }
+{ "_id" : "68510", "city" : "LINCOLN", "loc" : [ -96.65445800000001, 40.806345 ], "pop" : 20948, "state" : "NE" }
+{ "_id" : "68512", "city" : "LINCOLN", "loc" : [ -96.69460599999999, 40.756487 ], "pop" : 6139, "state" : "NE" }
+{ "_id" : "68514", "city" : "LINCOLN", "loc" : [ -96.66108199999999, 40.925792 ], "pop" : 200, "state" : "NE" }
+{ "_id" : "68516", "city" : "LINCOLN", "loc" : [ -96.652304, 40.756807 ], "pop" : 21213, "state" : "NE" }
+{ "_id" : "68517", "city" : "LINCOLN", "loc" : [ -96.60450899999999, 40.931743 ], "pop" : 485, "state" : "NE" }
+{ "_id" : "68520", "city" : "LINCOLN", "loc" : [ -96.56934099999999, 40.774441 ], "pop" : 1460, "state" : "NE" }
+{ "_id" : "68521", "city" : "LINCOLN", "loc" : [ -96.711006, 40.851044 ], "pop" : 16067, "state" : "NE" }
+{ "_id" : "68522", "city" : "LINCOLN", "loc" : [ -96.747871, 40.793407 ], "pop" : 4991, "state" : "NE" }
+{ "_id" : "68523", "city" : "LINCOLN", "loc" : [ -96.75833900000001, 40.740766 ], "pop" : 685, "state" : "NE" }
+{ "_id" : "68524", "city" : "LINCOLN", "loc" : [ -96.79434500000001, 40.852913 ], "pop" : 4321, "state" : "NE" }
+{ "_id" : "68526", "city" : "LINCOLN", "loc" : [ -96.587817, 40.731386 ], "pop" : 526, "state" : "NE" }
+{ "_id" : "68527", "city" : "LINCOLN", "loc" : [ -96.540053, 40.834708 ], "pop" : 617, "state" : "NE" }
+{ "_id" : "68528", "city" : "LINCOLN", "loc" : [ -96.754496, 40.819541 ], "pop" : 2476, "state" : "NE" }
+{ "_id" : "68531", "city" : "LINCOLN", "loc" : [ -96.71557199999999, 40.899397 ], "pop" : 310, "state" : "NE" }
+{ "_id" : "68532", "city" : "LINCOLN", "loc" : [ -96.85509, 40.792159 ], "pop" : 391, "state" : "NE" }
+{ "_id" : "68601", "city" : "RICHLAND", "loc" : [ -97.356469, 41.437225 ], "pop" : 23684, "state" : "NE" }
+{ "_id" : "68620", "city" : "ALBION", "loc" : [ -97.999116, 41.704947 ], "pop" : 3788, "state" : "NE" }
+{ "_id" : "68621", "city" : "AMES", "loc" : [ -96.646344, 41.461253 ], "pop" : 141, "state" : "NE" }
+{ "_id" : "68622", "city" : "BARTLETT", "loc" : [ -98.556668, 41.8697 ], "pop" : 262, "state" : "NE" }
+{ "_id" : "68623", "city" : "BELGRADE", "loc" : [ -98.08663799999999, 41.461077 ], "pop" : 268, "state" : "NE" }
+{ "_id" : "68624", "city" : "BELLWOOD", "loc" : [ -97.274657, 41.347389 ], "pop" : 1199, "state" : "NE" }
+{ "_id" : "68626", "city" : "BRAINARD", "loc" : [ -96.988226, 41.183151 ], "pop" : 570, "state" : "NE" }
+{ "_id" : "68627", "city" : "CEDAR RAPIDS", "loc" : [ -98.15537999999999, 41.556407 ], "pop" : 728, "state" : "NE" }
+{ "_id" : "68628", "city" : "CLARKS", "loc" : [ -97.846143, 41.232797 ], "pop" : 749, "state" : "NE" }
+{ "_id" : "68629", "city" : "CLARKSON", "loc" : [ -97.105059, 41.696064 ], "pop" : 1235, "state" : "NE" }
+{ "_id" : "68631", "city" : "CRESTON", "loc" : [ -97.368692, 41.660695 ], "pop" : 910, "state" : "NE" }
+{ "_id" : "68632", "city" : "GARRISON", "loc" : [ -97.126229, 41.237315 ], "pop" : 3798, "state" : "NE" }
+{ "_id" : "68633", "city" : "DODGE", "loc" : [ -96.818077, 41.681609 ], "pop" : 2151, "state" : "NE" }
+{ "_id" : "68635", "city" : "DWIGHT", "loc" : [ -96.993143, 41.089388 ], "pop" : 462, "state" : "NE" }
+{ "_id" : "68636", "city" : "ELGIN", "loc" : [ -98.07508199999999, 41.973239 ], "pop" : 1367, "state" : "NE" }
+{ "_id" : "68637", "city" : "ERICSON", "loc" : [ -98.645323, 41.782804 ], "pop" : 311, "state" : "NE" }
+{ "_id" : "68638", "city" : "FULLERTON", "loc" : [ -98.00536200000001, 41.366042 ], "pop" : 2087, "state" : "NE" }
+{ "_id" : "68640", "city" : "GENOA", "loc" : [ -97.764011, 41.446776 ], "pop" : 2116, "state" : "NE" }
+{ "_id" : "68641", "city" : "HOWELLS", "loc" : [ -96.985811, 41.696441 ], "pop" : 1122, "state" : "NE" }
+{ "_id" : "68642", "city" : "HUMPHREY", "loc" : [ -97.498649, 41.670184 ], "pop" : 1818, "state" : "NE" }
+{ "_id" : "68643", "city" : "LEIGH", "loc" : [ -97.232001, 41.673877 ], "pop" : 1225, "state" : "NE" }
+{ "_id" : "68644", "city" : "LINDSAY", "loc" : [ -97.671134, 41.692634 ], "pop" : 973, "state" : "NE" }
+{ "_id" : "68647", "city" : "MONROE", "loc" : [ -97.606075, 41.478255 ], "pop" : 799, "state" : "NE" }
+{ "_id" : "68648", "city" : "MORSE BLUFF", "loc" : [ -96.786171, 41.417831 ], "pop" : 486, "state" : "NE" }
+{ "_id" : "68649", "city" : "NORTH BEND", "loc" : [ -96.781328, 41.468924 ], "pop" : 1651, "state" : "NE" }
+{ "_id" : "68650", "city" : "OCTAVIA", "loc" : [ -97.07021, 41.355323 ], "pop" : 361, "state" : "NE" }
+{ "_id" : "68651", "city" : "OSCEOLA", "loc" : [ -97.557079, 41.196565 ], "pop" : 1398, "state" : "NE" }
+{ "_id" : "68652", "city" : "PETERSBURG", "loc" : [ -98.084791, 41.858954 ], "pop" : 784, "state" : "NE" }
+{ "_id" : "68653", "city" : "PLATTE CENTER", "loc" : [ -97.457616, 41.524114 ], "pop" : 1399, "state" : "NE" }
+{ "_id" : "68654", "city" : "POLK", "loc" : [ -97.75237199999999, 41.117671 ], "pop" : 988, "state" : "NE" }
+{ "_id" : "68655", "city" : "PRIMROSE", "loc" : [ -98.235455, 41.64054 ], "pop" : 255, "state" : "NE" }
+{ "_id" : "68658", "city" : "RISING CITY", "loc" : [ -97.303174, 41.208219 ], "pop" : 697, "state" : "NE" }
+{ "_id" : "68659", "city" : "ROGERS", "loc" : [ -96.949735, 41.469536 ], "pop" : 208, "state" : "NE" }
+{ "_id" : "68660", "city" : "SAINT EDWARD", "loc" : [ -97.880116, 41.57076 ], "pop" : 1112, "state" : "NE" }
+{ "_id" : "68661", "city" : "SCHUYLER", "loc" : [ -97.062832, 41.459128 ], "pop" : 5243, "state" : "NE" }
+{ "_id" : "68662", "city" : "SHELBY", "loc" : [ -97.429536, 41.243544 ], "pop" : 1495, "state" : "NE" }
+{ "_id" : "68663", "city" : "SILVER CREEK", "loc" : [ -97.667106, 41.318999 ], "pop" : 627, "state" : "NE" }
+{ "_id" : "68665", "city" : "SPALDING", "loc" : [ -98.37146799999999, 41.687409 ], "pop" : 1053, "state" : "NE" }
+{ "_id" : "68666", "city" : "STROMSBURG", "loc" : [ -97.574183, 41.111834 ], "pop" : 1765, "state" : "NE" }
+{ "_id" : "68667", "city" : "ULYSSES", "loc" : [ -97.30901299999999, 41.089922 ], "pop" : 250, "state" : "NE" }
+{ "_id" : "68669", "city" : "ULYSSES", "loc" : [ -97.19838799999999, 41.079059 ], "pop" : 440, "state" : "NE" }
+{ "_id" : "68701", "city" : "NORFOLK", "loc" : [ -97.422898, 42.032914 ], "pop" : 25728, "state" : "NE" }
+{ "_id" : "68710", "city" : "ALLEN", "loc" : [ -96.8574, 42.443667 ], "pop" : 1007, "state" : "NE" }
+{ "_id" : "68711", "city" : "AMELIA", "loc" : [ -99.008036, 42.18088 ], "pop" : 196, "state" : "NE" }
+{ "_id" : "68713", "city" : "ATKINSON", "loc" : [ -98.97608700000001, 42.548279 ], "pop" : 2321, "state" : "NE" }
+{ "_id" : "68714", "city" : "BASSETT", "loc" : [ -99.538732, 42.576293 ], "pop" : 1344, "state" : "NE" }
+{ "_id" : "68715", "city" : "BATTLE CREEK", "loc" : [ -97.598153, 41.994283 ], "pop" : 1448, "state" : "NE" }
+{ "_id" : "68716", "city" : "BEEMER", "loc" : [ -96.81500800000001, 41.937422 ], "pop" : 948, "state" : "NE" }
+{ "_id" : "68717", "city" : "BELDEN", "loc" : [ -97.195628, 42.402185 ], "pop" : 346, "state" : "NE" }
+{ "_id" : "68718", "city" : "BLOOMFIELD", "loc" : [ -97.654494, 42.597824 ], "pop" : 1873, "state" : "NE" }
+{ "_id" : "68719", "city" : "BRISTOW", "loc" : [ -98.60267, 42.880575 ], "pop" : 355, "state" : "NE" }
+{ "_id" : "68720", "city" : "BRUNSWICK", "loc" : [ -97.944008, 42.351023 ], "pop" : 907, "state" : "NE" }
+{ "_id" : "68722", "city" : "BUTTE", "loc" : [ -98.84590300000001, 42.912377 ], "pop" : 667, "state" : "NE" }
+{ "_id" : "68723", "city" : "CARROLL", "loc" : [ -97.192612, 42.277009 ], "pop" : 576, "state" : "NE" }
+{ "_id" : "68724", "city" : "CENTER", "loc" : [ -97.883567, 42.602451 ], "pop" : 264, "state" : "NE" }
+{ "_id" : "68725", "city" : "CHAMBERS", "loc" : [ -98.737846, 42.191606 ], "pop" : 815, "state" : "NE" }
+{ "_id" : "68726", "city" : "CLEARWATER", "loc" : [ -98.186761, 42.126562 ], "pop" : 919, "state" : "NE" }
+{ "_id" : "68727", "city" : "COLERIDGE", "loc" : [ -97.17856399999999, 42.522992 ], "pop" : 1185, "state" : "NE" }
+{ "_id" : "68728", "city" : "CONCORD", "loc" : [ -96.98103500000001, 42.381982 ], "pop" : 262, "state" : "NE" }
+{ "_id" : "68729", "city" : "CREIGHTON", "loc" : [ -97.89323, 42.468053 ], "pop" : 1604, "state" : "NE" }
+{ "_id" : "68730", "city" : "CROFTON", "loc" : [ -97.540589, 42.737028 ], "pop" : 1717, "state" : "NE" }
+{ "_id" : "68731", "city" : "DAKOTA CITY", "loc" : [ -96.453608, 42.38074 ], "pop" : 3022, "state" : "NE" }
+{ "_id" : "68732", "city" : "DIXON", "loc" : [ -96.97738099999999, 42.41853 ], "pop" : 226, "state" : "NE" }
+{ "_id" : "68733", "city" : "EMERSON", "loc" : [ -96.71587, 42.285247 ], "pop" : 1471, "state" : "NE" }
+{ "_id" : "68734", "city" : "EMMET", "loc" : [ -98.82377700000001, 42.474708 ], "pop" : 190, "state" : "NE" }
+{ "_id" : "68735", "city" : "EWING", "loc" : [ -98.39813700000001, 42.185107 ], "pop" : 1300, "state" : "NE" }
+{ "_id" : "68736", "city" : "FORDYCE", "loc" : [ -97.35666500000001, 42.730889 ], "pop" : 1059, "state" : "NE" }
+{ "_id" : "68737", "city" : "FOSTER", "loc" : [ -97.658038, 42.269932 ], "pop" : 216, "state" : "NE" }
+{ "_id" : "68739", "city" : "HARTINGTON", "loc" : [ -97.28367799999999, 42.623494 ], "pop" : 2806, "state" : "NE" }
+{ "_id" : "68740", "city" : "HOSKINS", "loc" : [ -97.308435, 42.140839 ], "pop" : 784, "state" : "NE" }
+{ "_id" : "68741", "city" : "HUBBARD", "loc" : [ -96.62242500000001, 42.413139 ], "pop" : 705, "state" : "NE" }
+{ "_id" : "68742", "city" : "INMAN", "loc" : [ -98.538366, 42.376149 ], "pop" : 439, "state" : "NE" }
+{ "_id" : "68743", "city" : "JACKSON", "loc" : [ -96.574335, 42.452877 ], "pop" : 406, "state" : "NE" }
+{ "_id" : "68745", "city" : "LAUREL", "loc" : [ -97.08738099999999, 42.427036 ], "pop" : 1519, "state" : "NE" }
+{ "_id" : "68746", "city" : "LYNCH", "loc" : [ -98.450433, 42.837275 ], "pop" : 496, "state" : "NE" }
+{ "_id" : "68747", "city" : "MCLEAN", "loc" : [ -97.47511299999999, 42.392082 ], "pop" : 232, "state" : "NE" }
+{ "_id" : "68748", "city" : "MADISON", "loc" : [ -97.47195000000001, 41.830786 ], "pop" : 3203, "state" : "NE" }
+{ "_id" : "68749", "city" : "MAGNET", "loc" : [ -97.44072199999999, 42.475294 ], "pop" : 218, "state" : "NE" }
+{ "_id" : "68751", "city" : "MASKELL", "loc" : [ -96.966978, 42.670245 ], "pop" : 218, "state" : "NE" }
+{ "_id" : "68752", "city" : "MEADOW GROVE", "loc" : [ -97.73342599999999, 42.010184 ], "pop" : 939, "state" : "NE" }
+{ "_id" : "68753", "city" : "MILLS", "loc" : [ -99.446647, 42.922527 ], "pop" : 329, "state" : "NE" }
+{ "_id" : "68755", "city" : "NAPER", "loc" : [ -99.071027, 42.952091 ], "pop" : 521, "state" : "NE" }
+{ "_id" : "68756", "city" : "NELIGH", "loc" : [ -98.01506999999999, 42.138926 ], "pop" : 2375, "state" : "NE" }
+{ "_id" : "68757", "city" : "NEWCASTLE", "loc" : [ -96.87085, 42.620672 ], "pop" : 763, "state" : "NE" }
+{ "_id" : "68758", "city" : "NEWMAN GROVE", "loc" : [ -97.773966, 41.74977 ], "pop" : 1482, "state" : "NE" }
+{ "_id" : "68759", "city" : "NEWPORT", "loc" : [ -99.335887, 42.600089 ], "pop" : 344, "state" : "NE" }
+{ "_id" : "68760", "city" : "VERDEL", "loc" : [ -97.912734, 42.776942 ], "pop" : 1051, "state" : "NE" }
+{ "_id" : "68761", "city" : "OAKDALE", "loc" : [ -97.918644, 42.053585 ], "pop" : 1016, "state" : "NE" }
+{ "_id" : "68762", "city" : "OBERT", "loc" : [ -97.07070899999999, 42.65767 ], "pop" : 204, "state" : "NE" }
+{ "_id" : "68763", "city" : "ONEILL", "loc" : [ -98.645565, 42.485733 ], "pop" : 5782, "state" : "NE" }
+{ "_id" : "68764", "city" : "ORCHARD", "loc" : [ -98.240853, 42.33987 ], "pop" : 1044, "state" : "NE" }
+{ "_id" : "68765", "city" : "OSMOND", "loc" : [ -97.581998, 42.353936 ], "pop" : 1418, "state" : "NE" }
+{ "_id" : "68766", "city" : "PAGE", "loc" : [ -98.39639, 42.411882 ], "pop" : 544, "state" : "NE" }
+{ "_id" : "68767", "city" : "PIERCE", "loc" : [ -97.525604, 42.194323 ], "pop" : 2942, "state" : "NE" }
+{ "_id" : "68768", "city" : "PILGER", "loc" : [ -97.268472, 42.040413 ], "pop" : 3122, "state" : "NE" }
+{ "_id" : "68769", "city" : "PLAINVIEW", "loc" : [ -97.778615, 42.346701 ], "pop" : 1978, "state" : "NE" }
+{ "_id" : "68770", "city" : "PONCA", "loc" : [ -96.712793, 42.56931 ], "pop" : 1316, "state" : "NE" }
+{ "_id" : "68771", "city" : "RANDOLPH", "loc" : [ -97.34644299999999, 42.379778 ], "pop" : 1826, "state" : "NE" }
+{ "_id" : "68772", "city" : "ROSE", "loc" : [ -99.444755, 42.256782 ], "pop" : 331, "state" : "NE" }
+{ "_id" : "68773", "city" : "ROYAL", "loc" : [ -98.12462600000001, 42.294614 ], "pop" : 479, "state" : "NE" }
+{ "_id" : "68774", "city" : "SAINT HELENA", "loc" : [ -97.358616, 42.818145 ], "pop" : 888, "state" : "NE" }
+{ "_id" : "68776", "city" : "SOUTH SIOUX CITY", "loc" : [ -96.418161, 42.465615 ], "pop" : 12037, "state" : "NE" }
+{ "_id" : "68777", "city" : "SPENCER", "loc" : [ -98.705853, 42.884936 ], "pop" : 796, "state" : "NE" }
+{ "_id" : "68778", "city" : "SPRINGVIEW", "loc" : [ -99.80614799999999, 42.848785 ], "pop" : 700, "state" : "NE" }
+{ "_id" : "68779", "city" : "STANTON", "loc" : [ -97.213955, 41.907559 ], "pop" : 3122, "state" : "NE" }
+{ "_id" : "68780", "city" : "STUART", "loc" : [ -99.139563, 42.571307 ], "pop" : 1331, "state" : "NE" }
+{ "_id" : "68781", "city" : "TILDEN", "loc" : [ -97.82229700000001, 42.049629 ], "pop" : 883, "state" : "NE" }
+{ "_id" : "68783", "city" : "VERDIGRE", "loc" : [ -98.079278, 42.610111 ], "pop" : 1184, "state" : "NE" }
+{ "_id" : "68784", "city" : "WAKEFIELD", "loc" : [ -96.877645, 42.273271 ], "pop" : 1858, "state" : "NE" }
+{ "_id" : "68785", "city" : "WATERBURY", "loc" : [ -96.74478000000001, 42.460431 ], "pop" : 241, "state" : "NE" }
+{ "_id" : "68786", "city" : "WAUSA", "loc" : [ -97.557616, 42.497265 ], "pop" : 1058, "state" : "NE" }
+{ "_id" : "68787", "city" : "WAYNE", "loc" : [ -97.018579, 42.230439 ], "pop" : 6454, "state" : "NE" }
+{ "_id" : "68788", "city" : "WEST POINT", "loc" : [ -96.731763, 41.84503 ], "pop" : 6463, "state" : "NE" }
+{ "_id" : "68789", "city" : "WINNETOON", "loc" : [ -98.025408, 42.494565 ], "pop" : 395, "state" : "NE" }
+{ "_id" : "68790", "city" : "WINSIDE", "loc" : [ -97.18250500000001, 42.167817 ], "pop" : 808, "state" : "NE" }
+{ "_id" : "68791", "city" : "WISNER", "loc" : [ -96.91697499999999, 41.997994 ], "pop" : 1793, "state" : "NE" }
+{ "_id" : "68792", "city" : "WYNOT", "loc" : [ -97.16780900000001, 42.739304 ], "pop" : 609, "state" : "NE" }
+{ "_id" : "68801", "city" : "GRAND ISLAND", "loc" : [ -98.34106199999999, 40.921858 ], "pop" : 24173, "state" : "NE" }
+{ "_id" : "68803", "city" : "GRAND ISLAND", "loc" : [ -98.387271, 40.928608 ], "pop" : 19337, "state" : "NE" }
+{ "_id" : "68810", "city" : "ALDA", "loc" : [ -98.455135, 40.856923 ], "pop" : 872, "state" : "NE" }
+{ "_id" : "68812", "city" : "AMHERST", "loc" : [ -99.260949, 40.849494 ], "pop" : 560, "state" : "NE" }
+{ "_id" : "68813", "city" : "MILBURN", "loc" : [ -99.799149, 41.636214 ], "pop" : 566, "state" : "NE" }
+{ "_id" : "68814", "city" : "ANSLEY", "loc" : [ -99.36452, 41.30193 ], "pop" : 853, "state" : "NE" }
+{ "_id" : "68815", "city" : "ARCADIA", "loc" : [ -99.120468, 41.429305 ], "pop" : 609, "state" : "NE" }
+{ "_id" : "68816", "city" : "ARCHER", "loc" : [ -98.118151, 41.178156 ], "pop" : 237, "state" : "NE" }
+{ "_id" : "68817", "city" : "ASHTON", "loc" : [ -98.803352, 41.267184 ], "pop" : 505, "state" : "NE" }
+{ "_id" : "68818", "city" : "AURORA", "loc" : [ -98.020107, 40.852838 ], "pop" : 5954, "state" : "NE" }
+{ "_id" : "68819", "city" : "BERWYN", "loc" : [ -99.50157299999999, 41.347015 ], "pop" : 318, "state" : "NE" }
+{ "_id" : "68820", "city" : "BOELUS", "loc" : [ -98.697551, 41.100278 ], "pop" : 533, "state" : "NE" }
+{ "_id" : "68821", "city" : "BREWSTER", "loc" : [ -99.829196, 41.946705 ], "pop" : 246, "state" : "NE" }
+{ "_id" : "68822", "city" : "BROKEN BOW", "loc" : [ -99.635452, 41.412586 ], "pop" : 4864, "state" : "NE" }
+{ "_id" : "68823", "city" : "BURWELL", "loc" : [ -99.09952699999999, 41.807982 ], "pop" : 2141, "state" : "NE" }
+{ "_id" : "68824", "city" : "CAIRO", "loc" : [ -98.61653800000001, 41.000183 ], "pop" : 976, "state" : "NE" }
+{ "_id" : "68825", "city" : "CALLAWAY", "loc" : [ -99.993185, 41.248499 ], "pop" : 1100, "state" : "NE" }
+{ "_id" : "68826", "city" : "CENTRAL CITY", "loc" : [ -98.001693, 41.121259 ], "pop" : 3783, "state" : "NE" }
+{ "_id" : "68827", "city" : "CHAPMAN", "loc" : [ -98.221723, 40.985592 ], "pop" : 1503, "state" : "NE" }
+{ "_id" : "68828", "city" : "COMSTOCK", "loc" : [ -99.27528100000001, 41.555254 ], "pop" : 331, "state" : "NE" }
+{ "_id" : "68829", "city" : "COTESFIELD", "loc" : [ -98.655344, 41.34301 ], "pop" : 216, "state" : "NE" }
+{ "_id" : "68831", "city" : "DANNEBROG", "loc" : [ -98.554564, 41.119156 ], "pop" : 890, "state" : "NE" }
+{ "_id" : "68832", "city" : "DONIPHAN", "loc" : [ -98.37900999999999, 40.770031 ], "pop" : 1496, "state" : "NE" }
+{ "_id" : "68833", "city" : "DUNNING", "loc" : [ -100.087271, 41.813107 ], "pop" : 225, "state" : "NE" }
+{ "_id" : "68834", "city" : "EDDYVILLE", "loc" : [ -99.681009, 41.0079 ], "pop" : 229, "state" : "NE" }
+{ "_id" : "68835", "city" : "ELBA", "loc" : [ -98.575622, 41.28644 ], "pop" : 310, "state" : "NE" }
+{ "_id" : "68836", "city" : "ELM CREEK", "loc" : [ -99.372786, 40.730079 ], "pop" : 1256, "state" : "NE" }
+{ "_id" : "68837", "city" : "ELYRIA", "loc" : [ -99.046656, 41.695655 ], "pop" : 305, "state" : "NE" }
+{ "_id" : "68838", "city" : "FARWELL", "loc" : [ -98.648144, 41.220378 ], "pop" : 313, "state" : "NE" }
+{ "_id" : "68840", "city" : "GIBBON", "loc" : [ -98.85435, 40.744445 ], "pop" : 1901, "state" : "NE" }
+{ "_id" : "68841", "city" : "GILTNER", "loc" : [ -98.14344, 40.765402 ], "pop" : 522, "state" : "NE" }
+{ "_id" : "68842", "city" : "GREELEY", "loc" : [ -98.529951, 41.552578 ], "pop" : 832, "state" : "NE" }
+{ "_id" : "68843", "city" : "HAMPTON", "loc" : [ -97.884146, 40.923609 ], "pop" : 897, "state" : "NE" }
+{ "_id" : "68844", "city" : "HAZARD", "loc" : [ -99.071859, 41.093368 ], "pop" : 285, "state" : "NE" }
+{ "_id" : "68846", "city" : "HORDVILLE", "loc" : [ -97.88814499999999, 41.081253 ], "pop" : 405, "state" : "NE" }
+{ "_id" : "68847", "city" : "KEARNEY", "loc" : [ -99.077883, 40.713608 ], "pop" : 28674, "state" : "NE" }
+{ "_id" : "68850", "city" : "LEXINGTON", "loc" : [ -99.751515, 40.785002 ], "pop" : 8970, "state" : "NE" }
+{ "_id" : "68852", "city" : "LITCHFIELD", "loc" : [ -99.141452, 41.168639 ], "pop" : 629, "state" : "NE" }
+{ "_id" : "68853", "city" : "LOUP CITY", "loc" : [ -98.975149, 41.284531 ], "pop" : 1810, "state" : "NE" }
+{ "_id" : "68854", "city" : "MARQUETTE", "loc" : [ -97.999955, 41.010017 ], "pop" : 563, "state" : "NE" }
+{ "_id" : "68855", "city" : "MASON CITY", "loc" : [ -99.304937, 41.185319 ], "pop" : 473, "state" : "NE" }
+{ "_id" : "68856", "city" : "MERNA", "loc" : [ -99.803595, 41.443482 ], "pop" : 913, "state" : "NE" }
+{ "_id" : "68858", "city" : "MILLER", "loc" : [ -99.373987, 40.942236 ], "pop" : 337, "state" : "NE" }
+{ "_id" : "68859", "city" : "NORTH LOUP", "loc" : [ -98.785836, 41.49717 ], "pop" : 626, "state" : "NE" }
+{ "_id" : "68860", "city" : "OCONTO", "loc" : [ -99.69511199999999, 41.138075 ], "pop" : 539, "state" : "NE" }
+{ "_id" : "68861", "city" : "ODESSA", "loc" : [ -99.254082, 40.709726 ], "pop" : 379, "state" : "NE" }
+{ "_id" : "68862", "city" : "ORD", "loc" : [ -98.941783, 41.596187 ], "pop" : 3629, "state" : "NE" }
+{ "_id" : "68863", "city" : "OVERTON", "loc" : [ -99.527824, 40.751875 ], "pop" : 1090, "state" : "NE" }
+{ "_id" : "68864", "city" : "PALMER", "loc" : [ -98.241146, 41.178757 ], "pop" : 1142, "state" : "NE" }
+{ "_id" : "68865", "city" : "PHILLIPS", "loc" : [ -98.21286000000001, 40.898197 ], "pop" : 517, "state" : "NE" }
+{ "_id" : "68866", "city" : "PLEASANTON", "loc" : [ -99.12827799999999, 40.981848 ], "pop" : 654, "state" : "NE" }
+{ "_id" : "68868", "city" : "PROSSER", "loc" : [ -98.559471, 40.659175 ], "pop" : 297, "state" : "NE" }
+{ "_id" : "68869", "city" : "RAVENNA", "loc" : [ -98.904129, 41.023271 ], "pop" : 1646, "state" : "NE" }
+{ "_id" : "68870", "city" : "RIVERDALE", "loc" : [ -99.138147, 40.762684 ], "pop" : 784, "state" : "NE" }
+{ "_id" : "68871", "city" : "ROCKVILLE", "loc" : [ -98.85775700000001, 41.110832 ], "pop" : 489, "state" : "NE" }
+{ "_id" : "68872", "city" : "SAINT LIBORY", "loc" : [ -98.35888, 41.08669 ], "pop" : 705, "state" : "NE" }
+{ "_id" : "68873", "city" : "SAINT PAUL", "loc" : [ -98.44398700000001, 41.224212 ], "pop" : 3088, "state" : "NE" }
+{ "_id" : "68874", "city" : "SARGENT", "loc" : [ -99.381624, 41.650845 ], "pop" : 1042, "state" : "NE" }
+{ "_id" : "68875", "city" : "SCOTIA", "loc" : [ -98.689256, 41.483724 ], "pop" : 711, "state" : "NE" }
+{ "_id" : "68876", "city" : "SHELTON", "loc" : [ -98.743453, 40.771703 ], "pop" : 1256, "state" : "NE" }
+{ "_id" : "68878", "city" : "SUMNER", "loc" : [ -99.51995100000001, 40.950384 ], "pop" : 448, "state" : "NE" }
+{ "_id" : "68879", "city" : "ALMERIA", "loc" : [ -99.415404, 41.822859 ], "pop" : 683, "state" : "NE" }
+{ "_id" : "68881", "city" : "WESTERVILLE", "loc" : [ -99.38436900000001, 41.419282 ], "pop" : 172, "state" : "NE" }
+{ "_id" : "68882", "city" : "WOLBACH", "loc" : [ -98.399456, 41.424373 ], "pop" : 466, "state" : "NE" }
+{ "_id" : "68883", "city" : "WOOD RIVER", "loc" : [ -98.606509, 40.810635 ], "pop" : 2071, "state" : "NE" }
+{ "_id" : "68901", "city" : "HASTINGS", "loc" : [ -98.39114600000001, 40.587654 ], "pop" : 25562, "state" : "NE" }
+{ "_id" : "68920", "city" : "ALMA", "loc" : [ -99.360073, 40.118853 ], "pop" : 1587, "state" : "NE" }
+{ "_id" : "68922", "city" : "ARAPAHOE", "loc" : [ -99.899697, 40.302662 ], "pop" : 1246, "state" : "NE" }
+{ "_id" : "68923", "city" : "ATLANTA", "loc" : [ -99.484354, 40.384901 ], "pop" : 261, "state" : "NE" }
+{ "_id" : "68924", "city" : "AXTELL", "loc" : [ -99.11690299999999, 40.526907 ], "pop" : 1547, "state" : "NE" }
+{ "_id" : "68925", "city" : "AYR", "loc" : [ -98.438982, 40.441054 ], "pop" : 616, "state" : "NE" }
+{ "_id" : "68926", "city" : "BEAVER CITY", "loc" : [ -99.806532, 40.129036 ], "pop" : 959, "state" : "NE" }
+{ "_id" : "68927", "city" : "BERTRAND", "loc" : [ -99.575891, 40.560843 ], "pop" : 1566, "state" : "NE" }
+{ "_id" : "68928", "city" : "BLADEN", "loc" : [ -98.604625, 40.298996 ], "pop" : 579, "state" : "NE" }
+{ "_id" : "68929", "city" : "BLOOMINGTON", "loc" : [ -99.009438, 40.138257 ], "pop" : 431, "state" : "NE" }
+{ "_id" : "68930", "city" : "BLUE HILL", "loc" : [ -98.42695500000001, 40.31102 ], "pop" : 1291, "state" : "NE" }
+{ "_id" : "68932", "city" : "CAMPBELL", "loc" : [ -98.73701199999999, 40.296684 ], "pop" : 525, "state" : "NE" }
+{ "_id" : "68933", "city" : "CLAY CENTER", "loc" : [ -98.03864900000001, 40.511301 ], "pop" : 1115, "state" : "NE" }
+{ "_id" : "68934", "city" : "DEWEESE", "loc" : [ -98.177199, 40.379234 ], "pop" : 342, "state" : "NE" }
+{ "_id" : "68935", "city" : "EDGAR", "loc" : [ -97.972679, 40.365166 ], "pop" : 795, "state" : "NE" }
+{ "_id" : "68936", "city" : "EDISON", "loc" : [ -99.785988, 40.280176 ], "pop" : 246, "state" : "NE" }
+{ "_id" : "68937", "city" : "ELWOOD", "loc" : [ -99.825812, 40.574738 ], "pop" : 956, "state" : "NE" }
+{ "_id" : "68938", "city" : "FAIRFIELD", "loc" : [ -98.106272, 40.428511 ], "pop" : 569, "state" : "NE" }
+{ "_id" : "68939", "city" : "FRANKLIN", "loc" : [ -98.946862, 40.105172 ], "pop" : 1305, "state" : "NE" }
+{ "_id" : "68940", "city" : "FUNK", "loc" : [ -99.244992, 40.502031 ], "pop" : 558, "state" : "NE" }
+{ "_id" : "68941", "city" : "GLENVIL", "loc" : [ -98.246475, 40.493145 ], "pop" : 447, "state" : "NE" }
+{ "_id" : "68942", "city" : "GUIDE ROCK", "loc" : [ -98.33906399999999, 40.081186 ], "pop" : 530, "state" : "NE" }
+{ "_id" : "68943", "city" : "HARDY", "loc" : [ -97.927057, 40.028452 ], "pop" : 462, "state" : "NE" }
+{ "_id" : "68944", "city" : "HARVARD", "loc" : [ -98.084574, 40.626463 ], "pop" : 1400, "state" : "NE" }
+{ "_id" : "68945", "city" : "HEARTWELL", "loc" : [ -98.78514, 40.571601 ], "pop" : 197, "state" : "NE" }
+{ "_id" : "68946", "city" : "HENDLEY", "loc" : [ -99.971537, 40.106312 ], "pop" : 217, "state" : "NE" }
+{ "_id" : "68947", "city" : "HILDRETH", "loc" : [ -99.05712800000001, 40.321743 ], "pop" : 663, "state" : "NE" }
+{ "_id" : "68948", "city" : "HOLBROOK", "loc" : [ -100.013593, 40.301893 ], "pop" : 369, "state" : "NE" }
+{ "_id" : "68949", "city" : "HOLDREGE", "loc" : [ -99.367233, 40.447527 ], "pop" : 6744, "state" : "NE" }
+{ "_id" : "68950", "city" : "HOLSTEIN", "loc" : [ -98.65377700000001, 40.454169 ], "pop" : 413, "state" : "NE" }
+{ "_id" : "68951", "city" : "HUNTLEY", "loc" : [ -99.284786, 40.210254 ], "pop" : 89, "state" : "NE" }
+{ "_id" : "68952", "city" : "INAVALE", "loc" : [ -98.661191, 40.095886 ], "pop" : 249, "state" : "NE" }
+{ "_id" : "68954", "city" : "INLAND", "loc" : [ -98.22337899999999, 40.589934 ], "pop" : 113, "state" : "NE" }
+{ "_id" : "68955", "city" : "JUNIATA", "loc" : [ -98.515017, 40.586652 ], "pop" : 1058, "state" : "NE" }
+{ "_id" : "68956", "city" : "KENESAW", "loc" : [ -98.657241, 40.61645 ], "pop" : 1076, "state" : "NE" }
+{ "_id" : "68957", "city" : "LAWRENCE", "loc" : [ -98.24024300000001, 40.27672 ], "pop" : 594, "state" : "NE" }
+{ "_id" : "68958", "city" : "LOOMIS", "loc" : [ -99.497851, 40.479155 ], "pop" : 586, "state" : "NE" }
+{ "_id" : "68959", "city" : "MINDEN", "loc" : [ -98.93829700000001, 40.509142 ], "pop" : 4365, "state" : "NE" }
+{ "_id" : "68960", "city" : "NAPONEE", "loc" : [ -99.127725, 40.125807 ], "pop" : 361, "state" : "NE" }
+{ "_id" : "68961", "city" : "NORA", "loc" : [ -98.05841700000001, 40.209739 ], "pop" : 1084, "state" : "NE" }
+{ "_id" : "68964", "city" : "OAK", "loc" : [ -97.884114, 40.260489 ], "pop" : 312, "state" : "NE" }
+{ "_id" : "68966", "city" : "ORLEANS", "loc" : [ -99.45718599999999, 40.148435 ], "pop" : 760, "state" : "NE" }
+{ "_id" : "68967", "city" : "OXFORD", "loc" : [ -99.630197, 40.256049 ], "pop" : 1306, "state" : "NE" }
+{ "_id" : "68969", "city" : "RAGAN", "loc" : [ -99.24891, 40.309594 ], "pop" : 148, "state" : "NE" }
+{ "_id" : "68970", "city" : "RED CLOUD", "loc" : [ -98.518655, 40.09516 ], "pop" : 1630, "state" : "NE" }
+{ "_id" : "68971", "city" : "REPUBLICAN CITY", "loc" : [ -99.23218900000001, 40.103401 ], "pop" : 429, "state" : "NE" }
+{ "_id" : "68972", "city" : "RIVERTON", "loc" : [ -98.785819, 40.101626 ], "pop" : 394, "state" : "NE" }
+{ "_id" : "68973", "city" : "ROSELAND", "loc" : [ -98.555059, 40.459058 ], "pop" : 603, "state" : "NE" }
+{ "_id" : "68974", "city" : "RUSKIN", "loc" : [ -97.87203, 40.138318 ], "pop" : 324, "state" : "NE" }
+{ "_id" : "68975", "city" : "SARONVILLE", "loc" : [ -97.87385, 40.600625 ], "pop" : 1704, "state" : "NE" }
+{ "_id" : "68976", "city" : "SMITHFIELD", "loc" : [ -99.82386200000001, 40.583567 ], "pop" : 972, "state" : "NE" }
+{ "_id" : "68977", "city" : "STAMFORD", "loc" : [ -99.581405, 40.11625 ], "pop" : 396, "state" : "NE" }
+{ "_id" : "68978", "city" : "SUPERIOR", "loc" : [ -98.077872, 40.031537 ], "pop" : 2902, "state" : "NE" }
+{ "_id" : "68979", "city" : "SUTTON", "loc" : [ -97.873476, 40.653955 ], "pop" : 215, "state" : "NE" }
+{ "_id" : "68980", "city" : "TRUMBULL", "loc" : [ -98.257414, 40.66918 ], "pop" : 381, "state" : "NE" }
+{ "_id" : "68981", "city" : "UPLAND", "loc" : [ -98.89657699999999, 40.317073 ], "pop" : 259, "state" : "NE" }
+{ "_id" : "68982", "city" : "WILCOX", "loc" : [ -99.153927, 40.373523 ], "pop" : 520, "state" : "NE" }
+{ "_id" : "69001", "city" : "MC COOK", "loc" : [ -100.627948, 40.204905 ], "pop" : 9513, "state" : "NE" }
+{ "_id" : "69020", "city" : "BARTLEY", "loc" : [ -100.29075, 40.258113 ], "pop" : 519, "state" : "NE" }
+{ "_id" : "69021", "city" : "BENKELMAN", "loc" : [ -101.534354, 40.098049 ], "pop" : 1813, "state" : "NE" }
+{ "_id" : "69022", "city" : "CAMBRIDGE", "loc" : [ -100.167579, 40.280767 ], "pop" : 1347, "state" : "NE" }
+{ "_id" : "69023", "city" : "CHAMPION", "loc" : [ -101.74849, 40.460039 ], "pop" : 288, "state" : "NE" }
+{ "_id" : "69024", "city" : "CULBERTSON", "loc" : [ -100.850043, 40.223707 ], "pop" : 1560, "state" : "NE" }
+{ "_id" : "69025", "city" : "CURTIS", "loc" : [ -100.510406, 40.613067 ], "pop" : 1095, "state" : "NE" }
+{ "_id" : "69026", "city" : "DANBURY", "loc" : [ -100.424228, 40.037689 ], "pop" : 283, "state" : "NE" }
+{ "_id" : "69027", "city" : "ENDERS", "loc" : [ -101.522156, 40.465492 ], "pop" : 217, "state" : "NE" }
+{ "_id" : "69028", "city" : "EUSTIS", "loc" : [ -100.054694, 40.626745 ], "pop" : 829, "state" : "NE" }
+{ "_id" : "69029", "city" : "FARNAM", "loc" : [ -100.206878, 40.712881 ], "pop" : 243, "state" : "NE" }
+{ "_id" : "69030", "city" : "HAIGLER", "loc" : [ -101.937106, 40.064179 ], "pop" : 398, "state" : "NE" }
+{ "_id" : "69031", "city" : "HAMLET", "loc" : [ -101.234106, 40.399363 ], "pop" : 222, "state" : "NE" }
+{ "_id" : "69032", "city" : "HAYES CENTER", "loc" : [ -101.025208, 40.517316 ], "pop" : 1000, "state" : "NE" }
+{ "_id" : "69033", "city" : "IMPERIAL", "loc" : [ -101.646775, 40.525124 ], "pop" : 2372, "state" : "NE" }
+{ "_id" : "69034", "city" : "INDIANOLA", "loc" : [ -100.429758, 40.235718 ], "pop" : 1213, "state" : "NE" }
+{ "_id" : "69035", "city" : "LAMAR", "loc" : [ -101.903297, 40.538653 ], "pop" : 613, "state" : "NE" }
+{ "_id" : "69036", "city" : "LEBANON", "loc" : [ -100.26122, 40.07522 ], "pop" : 182, "state" : "NE" }
+{ "_id" : "69037", "city" : "MAX", "loc" : [ -101.391607, 40.106884 ], "pop" : 164, "state" : "NE" }
+{ "_id" : "69038", "city" : "MAYWOOD", "loc" : [ -100.642135, 40.589262 ], "pop" : 689, "state" : "NE" }
+{ "_id" : "69039", "city" : "MOOREFIELD", "loc" : [ -100.310773, 40.57856 ], "pop" : 355, "state" : "NE" }
+{ "_id" : "69040", "city" : "PALISADE", "loc" : [ -101.129464, 40.338668 ], "pop" : 544, "state" : "NE" }
+{ "_id" : "69041", "city" : "PARKS", "loc" : [ -101.739879, 40.139837 ], "pop" : 207, "state" : "NE" }
+{ "_id" : "69042", "city" : "STOCKVILLE", "loc" : [ -100.384886, 40.494834 ], "pop" : 128, "state" : "NE" }
+{ "_id" : "69043", "city" : "STRATTON", "loc" : [ -101.218275, 40.144462 ], "pop" : 776, "state" : "NE" }
+{ "_id" : "69044", "city" : "TRENTON", "loc" : [ -101.020073, 40.168096 ], "pop" : 870, "state" : "NE" }
+{ "_id" : "69045", "city" : "WAUNETA", "loc" : [ -101.381195, 40.440906 ], "pop" : 891, "state" : "NE" }
+{ "_id" : "69046", "city" : "WILSONVILLE", "loc" : [ -100.1211, 40.108895 ], "pop" : 264, "state" : "NE" }
+{ "_id" : "69101", "city" : "NORTH PLATTE", "loc" : [ -100.774631, 41.132595 ], "pop" : 26416, "state" : "NE" }
+{ "_id" : "69120", "city" : "ARNOLD", "loc" : [ -100.156731, 41.445583 ], "pop" : 1099, "state" : "NE" }
+{ "_id" : "69121", "city" : "ARTHUR", "loc" : [ -101.693123, 41.573952 ], "pop" : 462, "state" : "NE" }
+{ "_id" : "69122", "city" : "BIG SPRINGS", "loc" : [ -102.093273, 41.069621 ], "pop" : 792, "state" : "NE" }
+{ "_id" : "69123", "city" : "BRADY", "loc" : [ -100.373649, 41.051525 ], "pop" : 1243, "state" : "NE" }
+{ "_id" : "69125", "city" : "BROADWATER", "loc" : [ -102.822521, 41.582547 ], "pop" : 411, "state" : "NE" }
+{ "_id" : "69127", "city" : "BRULE", "loc" : [ -101.909933, 41.100186 ], "pop" : 792, "state" : "NE" }
+{ "_id" : "69128", "city" : "BUSHNELL", "loc" : [ -103.907494, 41.213876 ], "pop" : 355, "state" : "NE" }
+{ "_id" : "69129", "city" : "CHAPPELL", "loc" : [ -102.452344, 41.096586 ], "pop" : 1445, "state" : "NE" }
+{ "_id" : "69130", "city" : "COZAD", "loc" : [ -99.992091, 40.861934 ], "pop" : 5221, "state" : "NE" }
+{ "_id" : "69131", "city" : "DALTON", "loc" : [ -102.972609, 41.406778 ], "pop" : 511, "state" : "NE" }
+{ "_id" : "69132", "city" : "DICKENS", "loc" : [ -101.01495, 40.804089 ], "pop" : 132, "state" : "NE" }
+{ "_id" : "69133", "city" : "DIX", "loc" : [ -103.479603, 41.226993 ], "pop" : 426, "state" : "NE" }
+{ "_id" : "69134", "city" : "ELSIE", "loc" : [ -101.369994, 40.859647 ], "pop" : 448, "state" : "NE" }
+{ "_id" : "69135", "city" : "ELSMERE", "loc" : [ -100.282412, 42.264974 ], "pop" : 132, "state" : "NE" }
+{ "_id" : "69138", "city" : "GOTHENBURG", "loc" : [ -100.154707, 40.940035 ], "pop" : 3739, "state" : "NE" }
+{ "_id" : "69140", "city" : "GRANT", "loc" : [ -101.719589, 40.851069 ], "pop" : 1896, "state" : "NE" }
+{ "_id" : "69141", "city" : "GURLEY", "loc" : [ -102.982325, 41.28771 ], "pop" : 624, "state" : "NE" }
+{ "_id" : "69142", "city" : "HALSEY", "loc" : [ -100.295515, 41.929095 ], "pop" : 166, "state" : "NE" }
+{ "_id" : "69143", "city" : "HERSHEY", "loc" : [ -101.001157, 41.155303 ], "pop" : 1685, "state" : "NE" }
+{ "_id" : "69144", "city" : "KEYSTONE", "loc" : [ -101.628218, 41.262129 ], "pop" : 247, "state" : "NE" }
+{ "_id" : "69145", "city" : "KIMBALL", "loc" : [ -103.660236, 41.23208 ], "pop" : 3327, "state" : "NE" }
+{ "_id" : "69146", "city" : "LEMOYNE", "loc" : [ -101.894677, 41.304017 ], "pop" : 303, "state" : "NE" }
+{ "_id" : "69147", "city" : "LEWELLEN", "loc" : [ -102.139622, 41.343461 ], "pop" : 612, "state" : "NE" }
+{ "_id" : "69148", "city" : "LISCO", "loc" : [ -102.54983, 41.511398 ], "pop" : 214, "state" : "NE" }
+{ "_id" : "69149", "city" : "LODGEPOLE", "loc" : [ -102.657034, 41.169745 ], "pop" : 642, "state" : "NE" }
+{ "_id" : "69150", "city" : "MADRID", "loc" : [ -101.537067, 40.85443 ], "pop" : 546, "state" : "NE" }
+{ "_id" : "69151", "city" : "MAXWELL", "loc" : [ -100.526993, 41.058831 ], "pop" : 722, "state" : "NE" }
+{ "_id" : "69152", "city" : "MULLEN", "loc" : [ -101.054185, 42.016292 ], "pop" : 793, "state" : "NE" }
+{ "_id" : "69153", "city" : "OGALLALA", "loc" : [ -101.710742, 41.127505 ], "pop" : 6329, "state" : "NE" }
+{ "_id" : "69154", "city" : "OSHKOSH", "loc" : [ -102.345699, 41.445057 ], "pop" : 1634, "state" : "NE" }
+{ "_id" : "69155", "city" : "PAXTON", "loc" : [ -101.358544, 41.126763 ], "pop" : 913, "state" : "NE" }
+{ "_id" : "69156", "city" : "POTTER", "loc" : [ -103.306112, 41.234688 ], "pop" : 658, "state" : "NE" }
+{ "_id" : "69157", "city" : "PURDUM", "loc" : [ -100.15685, 41.966475 ], "pop" : 217, "state" : "NE" }
+{ "_id" : "69161", "city" : "SENECA", "loc" : [ -100.807315, 41.99012 ], "pop" : 169, "state" : "NE" }
+{ "_id" : "69162", "city" : "SIDNEY", "loc" : [ -102.985573, 41.138001 ], "pop" : 7059, "state" : "NE" }
+{ "_id" : "69163", "city" : "STAPLETON", "loc" : [ -100.483105, 41.48877 ], "pop" : 878, "state" : "NE" }
+{ "_id" : "69165", "city" : "SUTHERLAND", "loc" : [ -101.136029, 41.15575 ], "pop" : 1472, "state" : "NE" }
+{ "_id" : "69166", "city" : "BROWNLEE", "loc" : [ -100.573834, 41.973575 ], "pop" : 503, "state" : "NE" }
+{ "_id" : "69167", "city" : "TRYON", "loc" : [ -101.017508, 41.573175 ], "pop" : 546, "state" : "NE" }
+{ "_id" : "69168", "city" : "VENANGO", "loc" : [ -101.983894, 40.807324 ], "pop" : 433, "state" : "NE" }
+{ "_id" : "69169", "city" : "WALLACE", "loc" : [ -101.173767, 40.830423 ], "pop" : 571, "state" : "NE" }
+{ "_id" : "69170", "city" : "WELLFLEET", "loc" : [ -100.711915, 40.798776 ], "pop" : 311, "state" : "NE" }
+{ "_id" : "69201", "city" : "VALENTINE", "loc" : [ -100.621542, 42.806166 ], "pop" : 4504, "state" : "NE" }
+{ "_id" : "69210", "city" : "AINSWORTH", "loc" : [ -99.861491, 42.54027 ], "pop" : 2580, "state" : "NE" }
+{ "_id" : "69211", "city" : "CODY", "loc" : [ -101.379846, 42.614556 ], "pop" : 156, "state" : "NE" }
+{ "_id" : "69212", "city" : "CROOKSTON", "loc" : [ -100.773473, 42.925506 ], "pop" : 229, "state" : "NE" }
+{ "_id" : "69214", "city" : "JOHNSTOWN", "loc" : [ -100.045322, 42.530857 ], "pop" : 371, "state" : "NE" }
+{ "_id" : "69216", "city" : "KILGORE", "loc" : [ -100.988447, 42.914587 ], "pop" : 213, "state" : "NE" }
+{ "_id" : "69217", "city" : "LONG PINE", "loc" : [ -99.72304200000001, 42.533379 ], "pop" : 706, "state" : "NE" }
+{ "_id" : "69218", "city" : "MERRIMAN", "loc" : [ -101.758304, 42.641883 ], "pop" : 873, "state" : "NE" }
+{ "_id" : "69221", "city" : "WOOD LAKE", "loc" : [ -100.287175, 42.626394 ], "pop" : 200, "state" : "NE" }
+{ "_id" : "69301", "city" : "ALLIANCE", "loc" : [ -102.888045, 42.114943 ], "pop" : 11903, "state" : "NE" }
+{ "_id" : "69331", "city" : "ANGORA", "loc" : [ -103.085019, 41.893434 ], "pop" : 84, "state" : "NE" }
+{ "_id" : "69333", "city" : "ASHBY", "loc" : [ -101.963581, 41.977578 ], "pop" : 151, "state" : "NE" }
+{ "_id" : "69334", "city" : "BAYARD", "loc" : [ -103.301887, 41.757923 ], "pop" : 2378, "state" : "NE" }
+{ "_id" : "69335", "city" : "BINGHAM", "loc" : [ -102.133075, 42.260651 ], "pop" : 218, "state" : "NE" }
+{ "_id" : "69336", "city" : "BRIDGEPORT", "loc" : [ -103.070134, 41.676556 ], "pop" : 2550, "state" : "NE" }
+{ "_id" : "69337", "city" : "CHADRON", "loc" : [ -102.995331, 42.819268 ], "pop" : 6661, "state" : "NE" }
+{ "_id" : "69339", "city" : "CRAWFORD", "loc" : [ -103.405336, 42.67584 ], "pop" : 1492, "state" : "NE" }
+{ "_id" : "69340", "city" : "ELLSWORTH", "loc" : [ -102.47245, 42.169717 ], "pop" : 310, "state" : "NE" }
+{ "_id" : "69341", "city" : "GERING", "loc" : [ -103.662896, 41.821993 ], "pop" : 11631, "state" : "NE" }
+{ "_id" : "69343", "city" : "GORDON", "loc" : [ -102.204929, 42.806843 ], "pop" : 2666, "state" : "NE" }
+{ "_id" : "69345", "city" : "HARRISBURG", "loc" : [ -103.711141, 41.55306 ], "pop" : 852, "state" : "NE" }
+{ "_id" : "69346", "city" : "HARRISON", "loc" : [ -103.831803, 42.394594 ], "pop" : 1525, "state" : "NE" }
+{ "_id" : "69347", "city" : "HAY SPRINGS", "loc" : [ -102.675641, 42.640122 ], "pop" : 1570, "state" : "NE" }
+{ "_id" : "69348", "city" : "HEMINGFORD", "loc" : [ -103.064412, 42.33117 ], "pop" : 1280, "state" : "NE" }
+{ "_id" : "69349", "city" : "HENRY", "loc" : [ -104.034933, 41.993392 ], "pop" : 208, "state" : "NE" }
+{ "_id" : "69350", "city" : "HYANNIS", "loc" : [ -101.748296, 42.006967 ], "pop" : 430, "state" : "NE" }
+{ "_id" : "69351", "city" : "LAKESIDE", "loc" : [ -102.443655, 42.049595 ], "pop" : 5, "state" : "NE" }
+{ "_id" : "69352", "city" : "LYMAN", "loc" : [ -104.006569, 41.891765 ], "pop" : 988, "state" : "NE" }
+{ "_id" : "69354", "city" : "MARSLAND", "loc" : [ -103.051857, 42.598842 ], "pop" : 605, "state" : "NE" }
+{ "_id" : "69356", "city" : "MINATARE", "loc" : [ -103.489011, 41.849333 ], "pop" : 2355, "state" : "NE" }
+{ "_id" : "69357", "city" : "MITCHELL", "loc" : [ -103.795996, 41.945851 ], "pop" : 2998, "state" : "NE" }
+{ "_id" : "69358", "city" : "MORRILL", "loc" : [ -103.918216, 41.96807 ], "pop" : 1469, "state" : "NE" }
+{ "_id" : "69360", "city" : "RUSHVILLE", "loc" : [ -102.465738, 42.737934 ], "pop" : 1955, "state" : "NE" }
+{ "_id" : "69361", "city" : "SCOTTSBLUFF", "loc" : [ -103.661914, 41.871975 ], "pop" : 16373, "state" : "NE" }
+{ "_id" : "69366", "city" : "WHITMAN", "loc" : [ -101.521623, 41.958355 ], "pop" : 188, "state" : "NE" }
+{ "_id" : "69367", "city" : "WHITNEY", "loc" : [ -103.239552, 42.755881 ], "pop" : 263, "state" : "NE" }
+{ "_id" : "70001", "city" : "METAIRIE", "loc" : [ -90.16951299999999, 29.987138 ], "pop" : 39554, "state" : "LA" }
+{ "_id" : "70002", "city" : "METAIRIE", "loc" : [ -90.16303000000001, 30.009843 ], "pop" : 19511, "state" : "LA" }
+{ "_id" : "70003", "city" : "METAIRIE", "loc" : [ -90.21456999999999, 29.99746 ], "pop" : 46193, "state" : "LA" }
+{ "_id" : "70005", "city" : "METAIRIE", "loc" : [ -90.13314, 30.000476 ], "pop" : 26512, "state" : "LA" }
+{ "_id" : "70006", "city" : "METAIRIE", "loc" : [ -90.19148300000001, 30.012885 ], "pop" : 16919, "state" : "LA" }
+{ "_id" : "70030", "city" : "DES ALLEMANDS", "loc" : [ -90.44704900000001, 29.821993 ], "pop" : 3322, "state" : "LA" }
+{ "_id" : "70031", "city" : "AMA", "loc" : [ -90.292509, 29.943494 ], "pop" : 1300, "state" : "LA" }
+{ "_id" : "70032", "city" : "ARABI", "loc" : [ -89.99649700000001, 29.961154 ], "pop" : 8954, "state" : "LA" }
+{ "_id" : "70036", "city" : "BARATARIA", "loc" : [ -90.126232, 29.717859 ], "pop" : 334, "state" : "LA" }
+{ "_id" : "70037", "city" : "BELLE CHASSE", "loc" : [ -90.004177, 29.834514 ], "pop" : 9920, "state" : "LA" }
+{ "_id" : "70039", "city" : "BOUTTE", "loc" : [ -90.393396, 29.897319 ], "pop" : 2432, "state" : "LA" }
+{ "_id" : "70040", "city" : "BRAITHWAITE", "loc" : [ -89.885347, 29.673563 ], "pop" : 2303, "state" : "LA" }
+{ "_id" : "70041", "city" : "BURAS", "loc" : [ -89.47568, 29.341056 ], "pop" : 6496, "state" : "LA" }
+{ "_id" : "70043", "city" : "CHALMETTE", "loc" : [ -89.96113699999999, 29.946611 ], "pop" : 31850, "state" : "LA" }
+{ "_id" : "70047", "city" : "NEW SARPY", "loc" : [ -90.373982, 29.96579 ], "pop" : 10472, "state" : "LA" }
+{ "_id" : "70049", "city" : "EDGARD", "loc" : [ -90.581678, 30.031863 ], "pop" : 3702, "state" : "LA" }
+{ "_id" : "70051", "city" : "GARYVILLE", "loc" : [ -90.620113, 30.05352 ], "pop" : 3191, "state" : "LA" }
+{ "_id" : "70052", "city" : "GRAMERCY", "loc" : [ -90.69018199999999, 30.052711 ], "pop" : 2765, "state" : "LA" }
+{ "_id" : "70053", "city" : "GRETNA", "loc" : [ -90.05311500000001, 29.910806 ], "pop" : 16979, "state" : "LA" }
+{ "_id" : "70056", "city" : "TERRYTOWN", "loc" : [ -90.029123, 29.892652 ], "pop" : 37901, "state" : "LA" }
+{ "_id" : "70057", "city" : "HAHNVILLE", "loc" : [ -90.488581, 30.000094 ], "pop" : 745, "state" : "LA" }
+{ "_id" : "70058", "city" : "HARVEY", "loc" : [ -90.06725900000001, 29.872535 ], "pop" : 36824, "state" : "LA" }
+{ "_id" : "70062", "city" : "KENNER", "loc" : [ -90.247901, 29.991203 ], "pop" : 20016, "state" : "LA" }
+{ "_id" : "70065", "city" : "KENNER", "loc" : [ -90.25217499999999, 30.025164 ], "pop" : 54023, "state" : "LA" }
+{ "_id" : "70067", "city" : "LAFITTE", "loc" : [ -90.05663300000001, 29.562194 ], "pop" : 0, "state" : "LA" }
+{ "_id" : "70068", "city" : "LA PLACE", "loc" : [ -90.489544, 30.077718 ], "pop" : 26023, "state" : "LA" }
+{ "_id" : "70070", "city" : "LULING", "loc" : [ -90.36926099999999, 29.925116 ], "pop" : 11956, "state" : "LA" }
+{ "_id" : "70071", "city" : "LUTCHER", "loc" : [ -90.70084, 30.044679 ], "pop" : 3993, "state" : "LA" }
+{ "_id" : "70072", "city" : "MARRERO", "loc" : [ -90.110462, 29.859756 ], "pop" : 58905, "state" : "LA" }
+{ "_id" : "70075", "city" : "MERAUX", "loc" : [ -89.92143299999999, 29.933494 ], "pop" : 7196, "state" : "LA" }
+{ "_id" : "70079", "city" : "NORCO", "loc" : [ -90.41979600000001, 30.005706 ], "pop" : 4931, "state" : "LA" }
+{ "_id" : "70080", "city" : "PARADIS", "loc" : [ -90.43524600000001, 29.877033 ], "pop" : 939, "state" : "LA" }
+{ "_id" : "70083", "city" : "PORT SULPHUR", "loc" : [ -89.68474999999999, 29.470011 ], "pop" : 6398, "state" : "LA" }
+{ "_id" : "70084", "city" : "RESERVE", "loc" : [ -90.551773, 30.060255 ], "pop" : 7080, "state" : "LA" }
+{ "_id" : "70085", "city" : "SAINT BERNARD", "loc" : [ -89.836414, 29.861093 ], "pop" : 8082, "state" : "LA" }
+{ "_id" : "70086", "city" : "SAINT JAMES", "loc" : [ -90.86054900000001, 30.027598 ], "pop" : 2515, "state" : "LA" }
+{ "_id" : "70087", "city" : "SAINT ROSE", "loc" : [ -90.312432, 29.958074 ], "pop" : 6340, "state" : "LA" }
+{ "_id" : "70090", "city" : "VACHERIE", "loc" : [ -90.709699, 29.969372 ], "pop" : 6652, "state" : "LA" }
+{ "_id" : "70091", "city" : "VENICE", "loc" : [ -89.347776, 29.261812 ], "pop" : 458, "state" : "LA" }
+{ "_id" : "70092", "city" : "VIOLET", "loc" : [ -89.89599200000001, 29.904347 ], "pop" : 10549, "state" : "LA" }
+{ "_id" : "70094", "city" : "BRIDGE CITY", "loc" : [ -90.18130499999999, 29.914386 ], "pop" : 35200, "state" : "LA" }
+{ "_id" : "70112", "city" : "NEW ORLEANS", "loc" : [ -90.075301, 29.960484 ], "pop" : 6047, "state" : "LA" }
+{ "_id" : "70113", "city" : "NEW ORLEANS", "loc" : [ -90.084777, 29.940511 ], "pop" : 12177, "state" : "LA" }
+{ "_id" : "70114", "city" : "NEW ORLEANS", "loc" : [ -90.033126, 29.937934 ], "pop" : 29767, "state" : "LA" }
+{ "_id" : "70115", "city" : "NEW ORLEANS", "loc" : [ -90.1005, 29.928863 ], "pop" : 45070, "state" : "LA" }
+{ "_id" : "70116", "city" : "NEW ORLEANS", "loc" : [ -90.06461400000001, 29.968608 ], "pop" : 16592, "state" : "LA" }
+{ "_id" : "70117", "city" : "NEW ORLEANS", "loc" : [ -90.03124, 29.970298 ], "pop" : 56494, "state" : "LA" }
+{ "_id" : "70118", "city" : "NEW ORLEANS", "loc" : [ -90.123598, 29.950352 ], "pop" : 40049, "state" : "LA" }
+{ "_id" : "70119", "city" : "NEW ORLEANS", "loc" : [ -90.085156, 29.974552 ], "pop" : 47894, "state" : "LA" }
+{ "_id" : "70121", "city" : "JEFFERSON", "loc" : [ -90.16095300000001, 29.963071 ], "pop" : 12924, "state" : "LA" }
+{ "_id" : "70122", "city" : "NEW ORLEANS", "loc" : [ -90.064409, 30.005637 ], "pop" : 47077, "state" : "LA" }
+{ "_id" : "70123", "city" : "HARAHAN", "loc" : [ -90.210748, 29.953473 ], "pop" : 25057, "state" : "LA" }
+{ "_id" : "70124", "city" : "NEW ORLEANS", "loc" : [ -90.10938400000001, 30.007081 ], "pop" : 22851, "state" : "LA" }
+{ "_id" : "70125", "city" : "NEW ORLEANS", "loc" : [ -90.102785, 29.951225 ], "pop" : 22734, "state" : "LA" }
+{ "_id" : "70126", "city" : "NEW ORLEANS", "loc" : [ -90.018913, 30.015341 ], "pop" : 45119, "state" : "LA" }
+{ "_id" : "70127", "city" : "NEW ORLEANS", "loc" : [ -89.980688, 30.033811 ], "pop" : 29643, "state" : "LA" }
+{ "_id" : "70128", "city" : "NEW ORLEANS", "loc" : [ -89.95642100000001, 30.052691 ], "pop" : 18844, "state" : "LA" }
+{ "_id" : "70129", "city" : "NEW ORLEANS", "loc" : [ -89.906206, 30.047984 ], "pop" : 14064, "state" : "LA" }
+{ "_id" : "70130", "city" : "NEW ORLEANS", "loc" : [ -90.073949, 29.932438 ], "pop" : 15576, "state" : "LA" }
+{ "_id" : "70131", "city" : "NEW ORLEANS", "loc" : [ -89.996033, 29.916811 ], "pop" : 26939, "state" : "LA" }
+{ "_id" : "70301", "city" : "THIBODAUX", "loc" : [ -90.809605, 29.799213 ], "pop" : 37831, "state" : "LA" }
+{ "_id" : "70339", "city" : "PIERRE PART", "loc" : [ -91.20016699999999, 29.95501 ], "pop" : 5207, "state" : "LA" }
+{ "_id" : "70340", "city" : "AMELIA", "loc" : [ -91.11110499999999, 29.66046 ], "pop" : 656, "state" : "LA" }
+{ "_id" : "70341", "city" : "BELLE ROSE", "loc" : [ -91.04435100000001, 30.025955 ], "pop" : 4842, "state" : "LA" }
+{ "_id" : "70342", "city" : "BERWICK", "loc" : [ -91.205662, 29.698786 ], "pop" : 17631, "state" : "LA" }
+{ "_id" : "70343", "city" : "BOURG", "loc" : [ -90.60866, 29.548489 ], "pop" : 5310, "state" : "LA" }
+{ "_id" : "70344", "city" : "CHAUVIN", "loc" : [ -90.59795200000001, 29.463401 ], "pop" : 6430, "state" : "LA" }
+{ "_id" : "70345", "city" : "CUT OFF", "loc" : [ -90.339298, 29.523188 ], "pop" : 13268, "state" : "LA" }
+{ "_id" : "70346", "city" : "DONALDSONVILLE", "loc" : [ -90.99702499999999, 30.101799 ], "pop" : 11265, "state" : "LA" }
+{ "_id" : "70353", "city" : "DULAC", "loc" : [ -90.655655, 29.359814 ], "pop" : 1683, "state" : "LA" }
+{ "_id" : "70354", "city" : "GALLIANO", "loc" : [ -90.29805399999999, 29.431125 ], "pop" : 3669, "state" : "LA" }
+{ "_id" : "70355", "city" : "GHEENS", "loc" : [ -90.484855, 29.707591 ], "pop" : 452, "state" : "LA" }
+{ "_id" : "70356", "city" : "GIBSON", "loc" : [ -90.977637, 29.662522 ], "pop" : 1642, "state" : "LA" }
+{ "_id" : "70357", "city" : "GOLDEN MEADOW", "loc" : [ -90.263932, 29.382054 ], "pop" : 4075, "state" : "LA" }
+{ "_id" : "70358", "city" : "GRAND ISLE", "loc" : [ -90.00880100000001, 29.22973 ], "pop" : 1455, "state" : "LA" }
+{ "_id" : "70359", "city" : "GRAY", "loc" : [ -90.78071, 29.69034 ], "pop" : 4755, "state" : "LA" }
+{ "_id" : "70360", "city" : "HOUMA", "loc" : [ -90.754808, 29.59433 ], "pop" : 18335, "state" : "LA" }
+{ "_id" : "70363", "city" : "HOUMA", "loc" : [ -90.69166800000001, 29.560137 ], "pop" : 23618, "state" : "LA" }
+{ "_id" : "70364", "city" : "HOUMA", "loc" : [ -90.72680099999999, 29.629887 ], "pop" : 25330, "state" : "LA" }
+{ "_id" : "70372", "city" : "LABADIEVILLE", "loc" : [ -90.961319, 29.834458 ], "pop" : 2856, "state" : "LA" }
+{ "_id" : "70374", "city" : "LOCKPORT", "loc" : [ -90.49061399999999, 29.603493 ], "pop" : 10863, "state" : "LA" }
+{ "_id" : "70375", "city" : "MATHEWS", "loc" : [ -90.49491399999999, 29.681982 ], "pop" : 479, "state" : "LA" }
+{ "_id" : "70377", "city" : "MONTEGUT", "loc" : [ -90.543952, 29.474366 ], "pop" : 3892, "state" : "LA" }
+{ "_id" : "70380", "city" : "MORGAN CITY", "loc" : [ -91.116497, 29.723937 ], "pop" : 5341, "state" : "LA" }
+{ "_id" : "70390", "city" : "NAPOLEONVILLE", "loc" : [ -91.026608, 29.92884 ], "pop" : 7710, "state" : "LA" }
+{ "_id" : "70392", "city" : "PATTERSON", "loc" : [ -91.28123100000001, 29.69671 ], "pop" : 13463, "state" : "LA" }
+{ "_id" : "70394", "city" : "RACELAND", "loc" : [ -90.599908, 29.717835 ], "pop" : 12920, "state" : "LA" }
+{ "_id" : "70395", "city" : "SCHRIEVER", "loc" : [ -90.85134100000001, 29.712276 ], "pop" : 4774, "state" : "LA" }
+{ "_id" : "70397", "city" : "THERIOT", "loc" : [ -90.765146, 29.451587 ], "pop" : 3982, "state" : "LA" }
+{ "_id" : "70401", "city" : "HAMMOND", "loc" : [ -90.48785599999999, 30.51908 ], "pop" : 16101, "state" : "LA" }
+{ "_id" : "70403", "city" : "HAMMOND", "loc" : [ -90.46972, 30.491054 ], "pop" : 15299, "state" : "LA" }
+{ "_id" : "70420", "city" : "ABITA SPRINGS", "loc" : [ -90.00407199999999, 30.483696 ], "pop" : 2659, "state" : "LA" }
+{ "_id" : "70422", "city" : "AMITE", "loc" : [ -90.570493, 30.718208 ], "pop" : 12006, "state" : "LA" }
+{ "_id" : "70426", "city" : "ANGIE", "loc" : [ -89.856714, 30.922406 ], "pop" : 6303, "state" : "LA" }
+{ "_id" : "70427", "city" : "BOGALUSA", "loc" : [ -89.865329, 30.773303 ], "pop" : 18938, "state" : "LA" }
+{ "_id" : "70431", "city" : "BUSH", "loc" : [ -89.955664, 30.613393 ], "pop" : 3906, "state" : "LA" }
+{ "_id" : "70433", "city" : "COVINGTON", "loc" : [ -90.095933, 30.487606 ], "pop" : 26117, "state" : "LA" }
+{ "_id" : "70436", "city" : "FLUKER", "loc" : [ -90.52067, 30.812776 ], "pop" : 186, "state" : "LA" }
+{ "_id" : "70437", "city" : "FOLSOM", "loc" : [ -90.187927, 30.61447 ], "pop" : 4832, "state" : "LA" }
+{ "_id" : "70438", "city" : "FRANKLINTON", "loc" : [ -90.11547899999999, 30.857735 ], "pop" : 16352, "state" : "LA" }
+{ "_id" : "70441", "city" : "GREENSBURG", "loc" : [ -90.725561, 30.864693 ], "pop" : 3833, "state" : "LA" }
+{ "_id" : "70443", "city" : "INDEPENDENCE", "loc" : [ -90.52768500000001, 30.635148 ], "pop" : 4330, "state" : "LA" }
+{ "_id" : "70444", "city" : "KENTWOOD", "loc" : [ -90.472829, 30.889215 ], "pop" : 11244, "state" : "LA" }
+{ "_id" : "70445", "city" : "LACOMBE", "loc" : [ -89.929744, 30.322027 ], "pop" : 7956, "state" : "LA" }
+{ "_id" : "70446", "city" : "LORANGER", "loc" : [ -90.356723, 30.588407 ], "pop" : 8701, "state" : "LA" }
+{ "_id" : "70447", "city" : "MADISONVILLE", "loc" : [ -90.17728200000001, 30.428743 ], "pop" : 3110, "state" : "LA" }
+{ "_id" : "70448", "city" : "MANDEVILLE", "loc" : [ -90.076846, 30.386096 ], "pop" : 22492, "state" : "LA" }
+{ "_id" : "70449", "city" : "MAUREPAS", "loc" : [ -90.704255, 30.271587 ], "pop" : 2489, "state" : "LA" }
+{ "_id" : "70450", "city" : "MOUNT HERMON", "loc" : [ -90.276886, 30.953619 ], "pop" : 1577, "state" : "LA" }
+{ "_id" : "70452", "city" : "PEARL RIVER", "loc" : [ -89.77315, 30.394448 ], "pop" : 9228, "state" : "LA" }
+{ "_id" : "70453", "city" : "PINE GROVE", "loc" : [ -90.767235, 30.703202 ], "pop" : 444, "state" : "LA" }
+{ "_id" : "70454", "city" : "PONCHATOULA", "loc" : [ -90.44224699999999, 30.440644 ], "pop" : 15713, "state" : "LA" }
+{ "_id" : "70455", "city" : "ROBERT", "loc" : [ -90.335171, 30.506327 ], "pop" : 564, "state" : "LA" }
+{ "_id" : "70456", "city" : "ROSELAND", "loc" : [ -90.524277, 30.771711 ], "pop" : 2062, "state" : "LA" }
+{ "_id" : "70458", "city" : "SLIDELL", "loc" : [ -89.771192, 30.278411 ], "pop" : 28918, "state" : "LA" }
+{ "_id" : "70460", "city" : "SLIDELL", "loc" : [ -89.812895, 30.291611 ], "pop" : 18020, "state" : "LA" }
+{ "_id" : "70461", "city" : "SLIDELL", "loc" : [ -89.729027, 30.272615 ], "pop" : 17270, "state" : "LA" }
+{ "_id" : "70462", "city" : "SPRINGFIELD", "loc" : [ -90.577479, 30.415738 ], "pop" : 5597, "state" : "LA" }
+{ "_id" : "70466", "city" : "TICKFAW", "loc" : [ -90.48199700000001, 30.566849 ], "pop" : 5565, "state" : "LA" }
+{ "_id" : "70467", "city" : "VARNADO", "loc" : [ -89.7606, 30.982085 ], "pop" : 15, "state" : "LA" }
+{ "_id" : "70501", "city" : "LAFAYETTE", "loc" : [ -92.008261, 30.236141 ], "pop" : 31717, "state" : "LA" }
+{ "_id" : "70503", "city" : "LAFAYETTE", "loc" : [ -92.049745, 30.184256 ], "pop" : 25109, "state" : "LA" }
+{ "_id" : "70506", "city" : "LAFAYETTE", "loc" : [ -92.065623, 30.207707 ], "pop" : 33970, "state" : "LA" }
+{ "_id" : "70507", "city" : "LAFAYETTE", "loc" : [ -92.015962, 30.281313 ], "pop" : 12074, "state" : "LA" }
+{ "_id" : "70508", "city" : "LAFAYETTE", "loc" : [ -92.023579, 30.158222 ], "pop" : 20568, "state" : "LA" }
+{ "_id" : "70510", "city" : "FORKED ISLAND", "loc" : [ -92.142655, 29.958828 ], "pop" : 21018, "state" : "LA" }
+{ "_id" : "70512", "city" : "ARNAUDVILLE", "loc" : [ -91.92628499999999, 30.398054 ], "pop" : 5676, "state" : "LA" }
+{ "_id" : "70514", "city" : "BALDWIN", "loc" : [ -91.545783, 29.848784 ], "pop" : 4601, "state" : "LA" }
+{ "_id" : "70515", "city" : "BASILE", "loc" : [ -92.57357, 30.497787 ], "pop" : 2733, "state" : "LA" }
+{ "_id" : "70516", "city" : "BRANCH", "loc" : [ -92.33461800000001, 30.328684 ], "pop" : 2695, "state" : "LA" }
+{ "_id" : "70517", "city" : "HENDERSON", "loc" : [ -91.90589900000001, 30.274955 ], "pop" : 9596, "state" : "LA" }
+{ "_id" : "70518", "city" : "BROUSSARD", "loc" : [ -91.950171, 30.12189 ], "pop" : 8159, "state" : "LA" }
+{ "_id" : "70520", "city" : "CARENCRO", "loc" : [ -92.042265, 30.324433 ], "pop" : 12256, "state" : "LA" }
+{ "_id" : "70525", "city" : "CHURCH POINT", "loc" : [ -92.22395400000001, 30.401287 ], "pop" : 11108, "state" : "LA" }
+{ "_id" : "70526", "city" : "CROWLEY", "loc" : [ -92.377709, 30.214753 ], "pop" : 17975, "state" : "LA" }
+{ "_id" : "70528", "city" : "DELCAMBRE", "loc" : [ -91.988938, 29.947414 ], "pop" : 2769, "state" : "LA" }
+{ "_id" : "70529", "city" : "DUSON", "loc" : [ -92.152455, 30.191216 ], "pop" : 7160, "state" : "LA" }
+{ "_id" : "70531", "city" : "EGAN", "loc" : [ -92.500226, 30.250966 ], "pop" : 359, "state" : "LA" }
+{ "_id" : "70532", "city" : "ELTON", "loc" : [ -92.699614, 30.471496 ], "pop" : 1973, "state" : "LA" }
+{ "_id" : "70533", "city" : "ERATH", "loc" : [ -92.034266, 29.952237 ], "pop" : 7280, "state" : "LA" }
+{ "_id" : "70535", "city" : "EUNICE", "loc" : [ -92.39847399999999, 30.51158 ], "pop" : 21409, "state" : "LA" }
+{ "_id" : "70537", "city" : "EVANGELINE", "loc" : [ -92.55324400000001, 30.26829 ], "pop" : 475, "state" : "LA" }
+{ "_id" : "70538", "city" : "FRANKLIN", "loc" : [ -91.50264300000001, 29.785656 ], "pop" : 15334, "state" : "LA" }
+{ "_id" : "70542", "city" : "GUEYDAN", "loc" : [ -92.533779, 30.025541 ], "pop" : 3839, "state" : "LA" }
+{ "_id" : "70543", "city" : "IOTA", "loc" : [ -92.532201, 30.300081 ], "pop" : 5338, "state" : "LA" }
+{ "_id" : "70544", "city" : "JEANERETTE", "loc" : [ -91.654397, 29.90324 ], "pop" : 14068, "state" : "LA" }
+{ "_id" : "70546", "city" : "JENNINGS", "loc" : [ -92.657405, 30.22011 ], "pop" : 11966, "state" : "LA" }
+{ "_id" : "70548", "city" : "KAPLAN", "loc" : [ -92.302463, 29.977096 ], "pop" : 9442, "state" : "LA" }
+{ "_id" : "70549", "city" : "LAKE ARTHUR", "loc" : [ -92.682526, 30.09097 ], "pop" : 5011, "state" : "LA" }
+{ "_id" : "70552", "city" : "LOREAUVILLE", "loc" : [ -91.659571, 30.068276 ], "pop" : 109, "state" : "LA" }
+{ "_id" : "70554", "city" : "MAMOU", "loc" : [ -92.419646, 30.649648 ], "pop" : 6639, "state" : "LA" }
+{ "_id" : "70555", "city" : "MAURICE", "loc" : [ -92.107035, 30.07215 ], "pop" : 3628, "state" : "LA" }
+{ "_id" : "70559", "city" : "MIDLAND", "loc" : [ -92.46315300000001, 30.143437 ], "pop" : 4566, "state" : "LA" }
+{ "_id" : "70560", "city" : "NEW IBERIA", "loc" : [ -91.819959, 30.001027 ], "pop" : 56105, "state" : "LA" }
+{ "_id" : "70570", "city" : "OPELOUSAS", "loc" : [ -92.089668, 30.51442 ], "pop" : 46673, "state" : "LA" }
+{ "_id" : "70577", "city" : "PORT BARRE", "loc" : [ -91.92857600000001, 30.547788 ], "pop" : 4940, "state" : "LA" }
+{ "_id" : "70578", "city" : "RAYNE", "loc" : [ -92.248592, 30.204508 ], "pop" : 15652, "state" : "LA" }
+{ "_id" : "70581", "city" : "ROANOKE", "loc" : [ -92.68697299999999, 30.318167 ], "pop" : 2766, "state" : "LA" }
+{ "_id" : "70582", "city" : "SAINT MARTINVILL", "loc" : [ -91.82596100000001, 30.208282 ], "pop" : 29590, "state" : "LA" }
+{ "_id" : "70583", "city" : "SCOTT", "loc" : [ -92.098079, 30.250401 ], "pop" : 9093, "state" : "LA" }
+{ "_id" : "70584", "city" : "CANKTON", "loc" : [ -92.075681, 30.393741 ], "pop" : 634, "state" : "LA" }
+{ "_id" : "70586", "city" : "VILLE PLATTE", "loc" : [ -92.27370999999999, 30.692376 ], "pop" : 14291, "state" : "LA" }
+{ "_id" : "70589", "city" : "WASHINGTON", "loc" : [ -92.039888, 30.709881 ], "pop" : 3771, "state" : "LA" }
+{ "_id" : "70591", "city" : "WELSH", "loc" : [ -92.818972, 30.236259 ], "pop" : 5587, "state" : "LA" }
+{ "_id" : "70592", "city" : "YOUNGSVILLE", "loc" : [ -92.009629, 30.097498 ], "pop" : 6671, "state" : "LA" }
+{ "_id" : "70601", "city" : "LAKE CHARLES", "loc" : [ -93.187966, 30.228453 ], "pop" : 49710, "state" : "LA" }
+{ "_id" : "70605", "city" : "LAKE CHARLES", "loc" : [ -93.22179800000001, 30.169349 ], "pop" : 42627, "state" : "LA" }
+{ "_id" : "70611", "city" : "LAKE CHARLES", "loc" : [ -93.211082, 30.322031 ], "pop" : 12470, "state" : "LA" }
+{ "_id" : "70630", "city" : "BELL CITY", "loc" : [ -92.94407, 30.114454 ], "pop" : 1365, "state" : "LA" }
+{ "_id" : "70631", "city" : "CAMERON", "loc" : [ -93.27766200000001, 29.86492 ], "pop" : 5677, "state" : "LA" }
+{ "_id" : "70632", "city" : "CREOLE", "loc" : [ -93.034874, 29.797813 ], "pop" : 1023, "state" : "LA" }
+{ "_id" : "70633", "city" : "DEQUINCY", "loc" : [ -93.415053, 30.421113 ], "pop" : 8271, "state" : "LA" }
+{ "_id" : "70634", "city" : "DERIDDER", "loc" : [ -93.268461, 30.828738 ], "pop" : 19304, "state" : "LA" }
+{ "_id" : "70637", "city" : "DRY CREEK", "loc" : [ -92.988849, 30.735356 ], "pop" : 1597, "state" : "LA" }
+{ "_id" : "70639", "city" : "EVANS", "loc" : [ -93.42217100000001, 31.008817 ], "pop" : 2757, "state" : "LA" }
+{ "_id" : "70643", "city" : "GRAND CHENIER", "loc" : [ -92.897997, 29.787535 ], "pop" : 696, "state" : "LA" }
+{ "_id" : "70645", "city" : "HACKBERRY", "loc" : [ -93.374973, 29.982187 ], "pop" : 1668, "state" : "LA" }
+{ "_id" : "70647", "city" : "IOWA", "loc" : [ -93.02585999999999, 30.221937 ], "pop" : 4915, "state" : "LA" }
+{ "_id" : "70648", "city" : "KINDER", "loc" : [ -92.869332, 30.460653 ], "pop" : 6853, "state" : "LA" }
+{ "_id" : "70650", "city" : "LACASSINE", "loc" : [ -92.829262, 30.145587 ], "pop" : 460, "state" : "LA" }
+{ "_id" : "70652", "city" : "LONGVILLE", "loc" : [ -93.254806, 30.579992 ], "pop" : 1324, "state" : "LA" }
+{ "_id" : "70653", "city" : "FIELDS", "loc" : [ -93.530734, 30.770145 ], "pop" : 3273, "state" : "LA" }
+{ "_id" : "70654", "city" : "MITTIE", "loc" : [ -92.932056, 30.678812 ], "pop" : 477, "state" : "LA" }
+{ "_id" : "70655", "city" : "OBERLIN", "loc" : [ -92.752672, 30.6162 ], "pop" : 3121, "state" : "LA" }
+{ "_id" : "70656", "city" : "PITKIN", "loc" : [ -92.954762, 30.932988 ], "pop" : 3603, "state" : "LA" }
+{ "_id" : "70657", "city" : "RAGLEY", "loc" : [ -93.23365200000001, 30.470262 ], "pop" : 2530, "state" : "LA" }
+{ "_id" : "70658", "city" : "REEVES", "loc" : [ -93.03684699999999, 30.496734 ], "pop" : 1718, "state" : "LA" }
+{ "_id" : "70660", "city" : "SINGER", "loc" : [ -93.464986, 30.532906 ], "pop" : 2374, "state" : "LA" }
+{ "_id" : "70661", "city" : "STARKS", "loc" : [ -93.661485, 30.308477 ], "pop" : 2457, "state" : "LA" }
+{ "_id" : "70662", "city" : "SUGARTOWN", "loc" : [ -93.017017, 30.827653 ], "pop" : 319, "state" : "LA" }
+{ "_id" : "70663", "city" : "SULPHUR", "loc" : [ -93.363911, 30.219001 ], "pop" : 29774, "state" : "LA" }
+{ "_id" : "70668", "city" : "VINTON", "loc" : [ -93.57280799999999, 30.201523 ], "pop" : 6584, "state" : "LA" }
+{ "_id" : "70669", "city" : "WESTLAKE", "loc" : [ -93.268837, 30.261274 ], "pop" : 11106, "state" : "LA" }
+{ "_id" : "70710", "city" : "ADDIS", "loc" : [ -91.261348, 30.355699 ], "pop" : 2354, "state" : "LA" }
+{ "_id" : "70711", "city" : "ALBANY", "loc" : [ -90.59641499999999, 30.514872 ], "pop" : 4533, "state" : "LA" }
+{ "_id" : "70712", "city" : "ANGOLA", "loc" : [ -91.597948, 30.96562 ], "pop" : 5382, "state" : "LA" }
+{ "_id" : "70714", "city" : "BAKER", "loc" : [ -91.142893, 30.581395 ], "pop" : 19623, "state" : "LA" }
+{ "_id" : "70715", "city" : "BATCHELOR", "loc" : [ -91.66867499999999, 30.802631 ], "pop" : 1864, "state" : "LA" }
+{ "_id" : "70717", "city" : "BLANKS", "loc" : [ -91.61584499999999, 30.579813 ], "pop" : 1657, "state" : "LA" }
+{ "_id" : "70719", "city" : "BRUSLY", "loc" : [ -91.25264900000001, 30.387692 ], "pop" : 3429, "state" : "LA" }
+{ "_id" : "70720", "city" : "BUECHE", "loc" : [ -91.338303, 30.574894 ], "pop" : 504, "state" : "LA" }
+{ "_id" : "70721", "city" : "POINT CLAIR", "loc" : [ -91.102484, 30.220759 ], "pop" : 1104, "state" : "LA" }
+{ "_id" : "70722", "city" : "CLINTON", "loc" : [ -90.93314100000001, 30.824867 ], "pop" : 3028, "state" : "LA" }
+{ "_id" : "70723", "city" : "CONVENT", "loc" : [ -90.864988, 30.055251 ], "pop" : 2052, "state" : "LA" }
+{ "_id" : "70725", "city" : "DARROW", "loc" : [ -90.965102, 30.12999 ], "pop" : 1090, "state" : "LA" }
+{ "_id" : "70726", "city" : "PORT VINCENT", "loc" : [ -90.932588, 30.484623 ], "pop" : 34574, "state" : "LA" }
+{ "_id" : "70729", "city" : "ERWINVILLE", "loc" : [ -91.399444, 30.551252 ], "pop" : 342, "state" : "LA" }
+{ "_id" : "70730", "city" : "ETHEL", "loc" : [ -91.10997500000001, 30.813124 ], "pop" : 3979, "state" : "LA" }
+{ "_id" : "70732", "city" : "FORDOCHE", "loc" : [ -91.69725800000001, 30.550835 ], "pop" : 0, "state" : "LA" }
+{ "_id" : "70733", "city" : "FRENCH SETTLEMEN", "loc" : [ -90.773225, 30.336394 ], "pop" : 3132, "state" : "LA" }
+{ "_id" : "70734", "city" : "GEISMAR", "loc" : [ -90.975824, 30.236265 ], "pop" : 3622, "state" : "LA" }
+{ "_id" : "70736", "city" : "GLYNN", "loc" : [ -91.342311, 30.637617 ], "pop" : 557, "state" : "LA" }
+{ "_id" : "70737", "city" : "GONZALES", "loc" : [ -90.918012, 30.247306 ], "pop" : 21482, "state" : "LA" }
+{ "_id" : "70739", "city" : "GREENWELL SPRING", "loc" : [ -91.00748400000001, 30.52114 ], "pop" : 8000, "state" : "LA" }
+{ "_id" : "70740", "city" : "GROSSE TETE", "loc" : [ -91.43828999999999, 30.387935 ], "pop" : 956, "state" : "LA" }
+{ "_id" : "70744", "city" : "HOLDEN", "loc" : [ -90.665176, 30.555646 ], "pop" : 2424, "state" : "LA" }
+{ "_id" : "70748", "city" : "THE BLUFFS", "loc" : [ -91.234537, 30.827034 ], "pop" : 7635, "state" : "LA" }
+{ "_id" : "70749", "city" : "JARREAU", "loc" : [ -91.433205, 30.632585 ], "pop" : 1365, "state" : "LA" }
+{ "_id" : "70750", "city" : "KROTZ SPRINGS", "loc" : [ -91.75632899999999, 30.537928 ], "pop" : 935, "state" : "LA" }
+{ "_id" : "70752", "city" : "LAKELAND", "loc" : [ -91.421677, 30.579941 ], "pop" : 839, "state" : "LA" }
+{ "_id" : "70753", "city" : "LETTSWORTH", "loc" : [ -91.740252, 30.932394 ], "pop" : 1589, "state" : "LA" }
+{ "_id" : "70754", "city" : "LIVINGSTON", "loc" : [ -90.76733900000001, 30.474107 ], "pop" : 4653, "state" : "LA" }
+{ "_id" : "70755", "city" : "LIVONIA", "loc" : [ -91.533219, 30.552353 ], "pop" : 2711, "state" : "LA" }
+{ "_id" : "70756", "city" : "LOTTIE", "loc" : [ -91.71053000000001, 30.503947 ], "pop" : 9, "state" : "LA" }
+{ "_id" : "70757", "city" : "RAMAH", "loc" : [ -91.51681600000001, 30.482292 ], "pop" : 2070, "state" : "LA" }
+{ "_id" : "70759", "city" : "MORGANZA", "loc" : [ -91.595935, 30.724491 ], "pop" : 1082, "state" : "LA" }
+{ "_id" : "70760", "city" : "NEW ROADS", "loc" : [ -91.44212400000001, 30.701356 ], "pop" : 7642, "state" : "LA" }
+{ "_id" : "70761", "city" : "NORWOOD", "loc" : [ -91.062871, 30.951772 ], "pop" : 1833, "state" : "LA" }
+{ "_id" : "70762", "city" : "OSCAR", "loc" : [ -91.48457999999999, 30.598759 ], "pop" : 744, "state" : "LA" }
+{ "_id" : "70763", "city" : "PAULINA", "loc" : [ -90.73743899999999, 30.035159 ], "pop" : 2639, "state" : "LA" }
+{ "_id" : "70764", "city" : "PLAQUEMINE", "loc" : [ -91.25236099999999, 30.268414 ], "pop" : 16692, "state" : "LA" }
+{ "_id" : "70767", "city" : "PORT ALLEN", "loc" : [ -91.254088, 30.471983 ], "pop" : 12837, "state" : "LA" }
+{ "_id" : "70769", "city" : "GALVEZ", "loc" : [ -90.92990399999999, 30.315588 ], "pop" : 13275, "state" : "LA" }
+{ "_id" : "70770", "city" : "PRIDE", "loc" : [ -90.99429000000001, 30.613321 ], "pop" : 5260, "state" : "LA" }
+{ "_id" : "70772", "city" : "ROSEDALE", "loc" : [ -91.45616, 30.440776 ], "pop" : 807, "state" : "LA" }
+{ "_id" : "70773", "city" : "ROUGON", "loc" : [ -91.381316, 30.603452 ], "pop" : 542, "state" : "LA" }
+{ "_id" : "70774", "city" : "SAINT AMANT", "loc" : [ -90.84352699999999, 30.23849 ], "pop" : 6177, "state" : "LA" }
+{ "_id" : "70775", "city" : "BAINS", "loc" : [ -91.39226600000001, 30.858658 ], "pop" : 5634, "state" : "LA" }
+{ "_id" : "70776", "city" : "IBERVILLE", "loc" : [ -91.09162000000001, 30.279873 ], "pop" : 3225, "state" : "LA" }
+{ "_id" : "70777", "city" : "SLAUGHTER", "loc" : [ -91.052251, 30.799139 ], "pop" : 4558, "state" : "LA" }
+{ "_id" : "70778", "city" : "SORRENTO", "loc" : [ -90.86314, 30.185388 ], "pop" : 1303, "state" : "LA" }
+{ "_id" : "70780", "city" : "SUNSHINE", "loc" : [ -91.179922, 30.29824 ], "pop" : 395, "state" : "LA" }
+{ "_id" : "70781", "city" : "TORBERT", "loc" : [ -91.421616, 30.538575 ], "pop" : 27, "state" : "LA" }
+{ "_id" : "70783", "city" : "VENTRESS", "loc" : [ -91.403257, 30.681404 ], "pop" : 1926, "state" : "LA" }
+{ "_id" : "70785", "city" : "WALKER", "loc" : [ -90.85570800000001, 30.524748 ], "pop" : 12659, "state" : "LA" }
+{ "_id" : "70788", "city" : "WHITE CASTLE", "loc" : [ -91.17734299999999, 30.15447 ], "pop" : 5739, "state" : "LA" }
+{ "_id" : "70789", "city" : "WILSON", "loc" : [ -91.065511, 30.947325 ], "pop" : 77, "state" : "LA" }
+{ "_id" : "70791", "city" : "ZACHARY", "loc" : [ -91.135841, 30.656129 ], "pop" : 18647, "state" : "LA" }
+{ "_id" : "70792", "city" : "UNCLE SAM", "loc" : [ -90.771879, 30.021679 ], "pop" : 263, "state" : "LA" }
+{ "_id" : "70801", "city" : "BATON ROUGE", "loc" : [ -91.186954, 30.450731 ], "pop" : 62, "state" : "LA" }
+{ "_id" : "70802", "city" : "BATON ROUGE", "loc" : [ -91.169037, 30.444236 ], "pop" : 35116, "state" : "LA" }
+{ "_id" : "70805", "city" : "BATON ROUGE", "loc" : [ -91.148095, 30.48604 ], "pop" : 30584, "state" : "LA" }
+{ "_id" : "70806", "city" : "BATON ROUGE", "loc" : [ -91.13004599999999, 30.448486 ], "pop" : 25893, "state" : "LA" }
+{ "_id" : "70807", "city" : "SCOTLANDVILLE", "loc" : [ -91.17861499999999, 30.533199 ], "pop" : 23234, "state" : "LA" }
+{ "_id" : "70808", "city" : "BATON ROUGE", "loc" : [ -91.146765, 30.406596 ], "pop" : 31189, "state" : "LA" }
+{ "_id" : "70809", "city" : "BATON ROUGE", "loc" : [ -91.08421300000001, 30.408891 ], "pop" : 15623, "state" : "LA" }
+{ "_id" : "70810", "city" : "BATON ROUGE", "loc" : [ -91.091898, 30.363309 ], "pop" : 22331, "state" : "LA" }
+{ "_id" : "70811", "city" : "GREENWOOD", "loc" : [ -91.12653899999999, 30.53046 ], "pop" : 13653, "state" : "LA" }
+{ "_id" : "70812", "city" : "BATON ROUGE", "loc" : [ -91.118111, 30.505159 ], "pop" : 11842, "state" : "LA" }
+{ "_id" : "70814", "city" : "BATON ROUGE", "loc" : [ -91.06893599999999, 30.484808 ], "pop" : 13227, "state" : "LA" }
+{ "_id" : "70815", "city" : "BATON ROUGE", "loc" : [ -91.059558, 30.455809 ], "pop" : 27565, "state" : "LA" }
+{ "_id" : "70816", "city" : "BATON ROUGE", "loc" : [ -91.035645, 30.427289 ], "pop" : 32885, "state" : "LA" }
+{ "_id" : "70817", "city" : "BATON ROUGE", "loc" : [ -91.00212999999999, 30.390404 ], "pop" : 20916, "state" : "LA" }
+{ "_id" : "70818", "city" : "BATON ROUGE", "loc" : [ -91.049964, 30.540832 ], "pop" : 8368, "state" : "LA" }
+{ "_id" : "70819", "city" : "BATON ROUGE", "loc" : [ -91.01564999999999, 30.46679 ], "pop" : 5377, "state" : "LA" }
+{ "_id" : "70820", "city" : "BATON ROUGE", "loc" : [ -91.167064, 30.379523 ], "pop" : 10710, "state" : "LA" }
+{ "_id" : "71001", "city" : "ARCADIA", "loc" : [ -92.92452900000001, 32.555643 ], "pop" : 4367, "state" : "LA" }
+{ "_id" : "71003", "city" : "ATHENS", "loc" : [ -93.023875, 32.645073 ], "pop" : 1336, "state" : "LA" }
+{ "_id" : "71004", "city" : "BELCHER", "loc" : [ -93.85079899999999, 32.754393 ], "pop" : 849, "state" : "LA" }
+{ "_id" : "71006", "city" : "BENTON", "loc" : [ -93.69095, 32.697617 ], "pop" : 7234, "state" : "LA" }
+{ "_id" : "71007", "city" : "BETHANY", "loc" : [ -94.003394, 32.366179 ], "pop" : 404, "state" : "LA" }
+{ "_id" : "71008", "city" : "BIENVILLE", "loc" : [ -92.908402, 32.252323 ], "pop" : 445, "state" : "LA" }
+{ "_id" : "71016", "city" : "CASTOR", "loc" : [ -93.093576, 32.245181 ], "pop" : 2784, "state" : "LA" }
+{ "_id" : "71018", "city" : "COTTON VALLEY", "loc" : [ -93.42588499999999, 32.819011 ], "pop" : 2061, "state" : "LA" }
+{ "_id" : "71019", "city" : "HANNA", "loc" : [ -93.31564400000001, 32.050099 ], "pop" : 9339, "state" : "LA" }
+{ "_id" : "71023", "city" : "DOYLINE", "loc" : [ -93.399585, 32.490023 ], "pop" : 3065, "state" : "LA" }
+{ "_id" : "71024", "city" : "DUBBERLY", "loc" : [ -93.21419, 32.519164 ], "pop" : 1117, "state" : "LA" }
+{ "_id" : "71027", "city" : "FRIERSON", "loc" : [ -93.69148800000001, 32.244968 ], "pop" : 1600, "state" : "LA" }
+{ "_id" : "71028", "city" : "GIBSLAND", "loc" : [ -93.07055800000001, 32.529874 ], "pop" : 2219, "state" : "LA" }
+{ "_id" : "71029", "city" : "GILLIAM", "loc" : [ -93.829268, 32.825055 ], "pop" : 367, "state" : "LA" }
+{ "_id" : "71030", "city" : "GLOSTER", "loc" : [ -93.82930899999999, 32.191705 ], "pop" : 1242, "state" : "LA" }
+{ "_id" : "71031", "city" : "GOLDONNA", "loc" : [ -92.961056, 31.999988 ], "pop" : 1378, "state" : "LA" }
+{ "_id" : "71032", "city" : "GRAND CANE", "loc" : [ -93.79406400000001, 32.105 ], "pop" : 1048, "state" : "LA" }
+{ "_id" : "71033", "city" : "GREENWOOD", "loc" : [ -93.969252, 32.424025 ], "pop" : 3140, "state" : "LA" }
+{ "_id" : "71034", "city" : "HALL SUMMIT", "loc" : [ -93.30475, 32.175249 ], "pop" : 227, "state" : "LA" }
+{ "_id" : "71037", "city" : "HAUGHTON", "loc" : [ -93.565742, 32.550732 ], "pop" : 13876, "state" : "LA" }
+{ "_id" : "71038", "city" : "HAYNESVILLE", "loc" : [ -93.069137, 32.927807 ], "pop" : 7888, "state" : "LA" }
+{ "_id" : "71039", "city" : "HEFLIN", "loc" : [ -93.285192, 32.447008 ], "pop" : 1415, "state" : "LA" }
+{ "_id" : "71040", "city" : "HOMER", "loc" : [ -93.028834, 32.774883 ], "pop" : 6963, "state" : "LA" }
+{ "_id" : "71043", "city" : "HOSSTON", "loc" : [ -93.883425, 32.896653 ], "pop" : 766, "state" : "LA" }
+{ "_id" : "71044", "city" : "IDA", "loc" : [ -93.902186, 32.993393 ], "pop" : 742, "state" : "LA" }
+{ "_id" : "71045", "city" : "JAMESTOWN", "loc" : [ -93.184758, 32.36127 ], "pop" : 380, "state" : "LA" }
+{ "_id" : "71046", "city" : "KEATCHIE", "loc" : [ -93.95104600000001, 32.162173 ], "pop" : 1068, "state" : "LA" }
+{ "_id" : "71047", "city" : "KEITHVILLE", "loc" : [ -93.888138, 32.316059 ], "pop" : 8291, "state" : "LA" }
+{ "_id" : "71048", "city" : "LISBON", "loc" : [ -92.88781, 32.845196 ], "pop" : 427, "state" : "LA" }
+{ "_id" : "71049", "city" : "LOGANSPORT", "loc" : [ -93.962733, 31.994327 ], "pop" : 4130, "state" : "LA" }
+{ "_id" : "71051", "city" : "ELM GROVE", "loc" : [ -93.50261500000001, 32.388628 ], "pop" : 2216, "state" : "LA" }
+{ "_id" : "71052", "city" : "MANSFIELD", "loc" : [ -93.69804499999999, 32.023863 ], "pop" : 12317, "state" : "LA" }
+{ "_id" : "71055", "city" : "MINDEN", "loc" : [ -93.28858700000001, 32.632281 ], "pop" : 21954, "state" : "LA" }
+{ "_id" : "71059", "city" : "MIRA", "loc" : [ -93.918797, 32.922491 ], "pop" : 207, "state" : "LA" }
+{ "_id" : "71060", "city" : "MOORINGSPORT", "loc" : [ -93.973018, 32.66258 ], "pop" : 2838, "state" : "LA" }
+{ "_id" : "71061", "city" : "OIL CITY", "loc" : [ -93.983844, 32.745107 ], "pop" : 1874, "state" : "LA" }
+{ "_id" : "71063", "city" : "PELICAN", "loc" : [ -93.563361, 31.896563 ], "pop" : 998, "state" : "LA" }
+{ "_id" : "71064", "city" : "PLAIN DEALING", "loc" : [ -93.690534, 32.907419 ], "pop" : 4904, "state" : "LA" }
+{ "_id" : "71065", "city" : "PLEASANT HILL", "loc" : [ -93.513594, 31.808577 ], "pop" : 1338, "state" : "LA" }
+{ "_id" : "71067", "city" : "PRINCETON", "loc" : [ -93.522577, 32.579089 ], "pop" : 1914, "state" : "LA" }
+{ "_id" : "71068", "city" : "RINGGOLD", "loc" : [ -93.298241, 32.326302 ], "pop" : 4442, "state" : "LA" }
+{ "_id" : "71069", "city" : "RODESSA", "loc" : [ -93.988474, 32.970079 ], "pop" : 1014, "state" : "LA" }
+{ "_id" : "71070", "city" : "CHESTNUT", "loc" : [ -92.948606, 32.156604 ], "pop" : 1207, "state" : "LA" }
+{ "_id" : "71071", "city" : "SAREPTA", "loc" : [ -93.44040699999999, 32.943361 ], "pop" : 4570, "state" : "LA" }
+{ "_id" : "71072", "city" : "SHONGALOO", "loc" : [ -93.29626399999999, 32.971289 ], "pop" : 752, "state" : "LA" }
+{ "_id" : "71073", "city" : "SIBLEY", "loc" : [ -93.30090199999999, 32.509539 ], "pop" : 1363, "state" : "LA" }
+{ "_id" : "71075", "city" : "SPRINGHILL", "loc" : [ -93.459563, 33.00054 ], "pop" : 6271, "state" : "LA" }
+{ "_id" : "71078", "city" : "STONEWALL", "loc" : [ -93.80027699999999, 32.284758 ], "pop" : 3009, "state" : "LA" }
+{ "_id" : "71079", "city" : "SUMMERFIELD", "loc" : [ -92.821516, 32.923802 ], "pop" : 25, "state" : "LA" }
+{ "_id" : "71082", "city" : "TREES", "loc" : [ -93.987312, 32.866844 ], "pop" : 5880, "state" : "LA" }
+{ "_id" : "71101", "city" : "SHREVEPORT", "loc" : [ -93.748696, 32.503743 ], "pop" : 11355, "state" : "LA" }
+{ "_id" : "71103", "city" : "SHREVEPORT", "loc" : [ -93.772701, 32.494459 ], "pop" : 12908, "state" : "LA" }
+{ "_id" : "71104", "city" : "SHREVEPORT", "loc" : [ -93.73486200000001, 32.482978 ], "pop" : 14181, "state" : "LA" }
+{ "_id" : "71105", "city" : "SHREVEPORT", "loc" : [ -93.714341, 32.458882 ], "pop" : 19053, "state" : "LA" }
+{ "_id" : "71106", "city" : "FORBING", "loc" : [ -93.747922, 32.426251 ], "pop" : 32844, "state" : "LA" }
+{ "_id" : "71107", "city" : "DIXIE", "loc" : [ -93.82878100000001, 32.564652 ], "pop" : 29013, "state" : "LA" }
+{ "_id" : "71108", "city" : "SHREVEPORT", "loc" : [ -93.781378, 32.448596 ], "pop" : 19800, "state" : "LA" }
+{ "_id" : "71109", "city" : "SHREVEPORT", "loc" : [ -93.80129700000001, 32.473994 ], "pop" : 27393, "state" : "LA" }
+{ "_id" : "71110", "city" : "BARKSDALE A F B", "loc" : [ -93.638172, 32.514313 ], "pop" : 3518, "state" : "LA" }
+{ "_id" : "71111", "city" : "BOSSIER CITY", "loc" : [ -93.70382600000001, 32.544924 ], "pop" : 26472, "state" : "LA" }
+{ "_id" : "71112", "city" : "BOSSIER CITY", "loc" : [ -93.676723, 32.486025 ], "pop" : 25299, "state" : "LA" }
+{ "_id" : "71115", "city" : "CASPIANA", "loc" : [ -93.697402, 32.410156 ], "pop" : 8897, "state" : "LA" }
+{ "_id" : "71118", "city" : "SHREVEPORT", "loc" : [ -93.802543, 32.397664 ], "pop" : 23539, "state" : "LA" }
+{ "_id" : "71119", "city" : "SHREVEPORT", "loc" : [ -93.87260999999999, 32.477121 ], "pop" : 10578, "state" : "LA" }
+{ "_id" : "71129", "city" : "SHREVEPORT", "loc" : [ -93.87419199999999, 32.41412 ], "pop" : 12661, "state" : "LA" }
+{ "_id" : "71201", "city" : "MONROE", "loc" : [ -92.106104, 32.528551 ], "pop" : 22419, "state" : "LA" }
+{ "_id" : "71202", "city" : "RICHWOOD", "loc" : [ -92.090231, 32.463327 ], "pop" : 32038, "state" : "LA" }
+{ "_id" : "71203", "city" : "MONROE", "loc" : [ -92.042241, 32.553038 ], "pop" : 35643, "state" : "LA" }
+{ "_id" : "71219", "city" : "BASKIN", "loc" : [ -91.713154, 32.289728 ], "pop" : 1518, "state" : "LA" }
+{ "_id" : "71220", "city" : "BASTROP", "loc" : [ -91.90776, 32.789382 ], "pop" : 26388, "state" : "LA" }
+{ "_id" : "71222", "city" : "BERNICE", "loc" : [ -92.62626899999999, 32.821024 ], "pop" : 3510, "state" : "LA" }
+{ "_id" : "71223", "city" : "BONITA", "loc" : [ -91.682158, 32.912263 ], "pop" : 963, "state" : "LA" }
+{ "_id" : "71225", "city" : "CALHOUN", "loc" : [ -92.32992900000001, 32.524791 ], "pop" : 4082, "state" : "LA" }
+{ "_id" : "71226", "city" : "CHATHAM", "loc" : [ -92.437433, 32.292246 ], "pop" : 1254, "state" : "LA" }
+{ "_id" : "71227", "city" : "CHOUDRANT", "loc" : [ -92.522419, 32.555627 ], "pop" : 5436, "state" : "LA" }
+{ "_id" : "71229", "city" : "COLLINSTON", "loc" : [ -91.86341899999999, 32.697143 ], "pop" : 1128, "state" : "LA" }
+{ "_id" : "71232", "city" : "WARDEN", "loc" : [ -91.51248699999999, 32.450433 ], "pop" : 6657, "state" : "LA" }
+{ "_id" : "71234", "city" : "DOWNSVILLE", "loc" : [ -92.374471, 32.652508 ], "pop" : 4019, "state" : "LA" }
+{ "_id" : "71235", "city" : "DUBACH", "loc" : [ -92.678543, 32.694893 ], "pop" : 2838, "state" : "LA" }
+{ "_id" : "71237", "city" : "EPPS", "loc" : [ -91.49135, 32.616099 ], "pop" : 1586, "state" : "LA" }
+{ "_id" : "71238", "city" : "EROS", "loc" : [ -92.34795, 32.398822 ], "pop" : 2296, "state" : "LA" }
+{ "_id" : "71239", "city" : "EXTENSION", "loc" : [ -91.801091, 31.947065 ], "pop" : 263, "state" : "LA" }
+{ "_id" : "71241", "city" : "FARMERVILLE", "loc" : [ -92.317955, 32.753378 ], "pop" : 7172, "state" : "LA" }
+{ "_id" : "71243", "city" : "FORT NECESSITY", "loc" : [ -91.825694, 32.043412 ], "pop" : 74, "state" : "LA" }
+{ "_id" : "71245", "city" : "GRAMBLING", "loc" : [ -92.715785, 32.524398 ], "pop" : 5740, "state" : "LA" }
+{ "_id" : "71250", "city" : "JONES", "loc" : [ -91.596509, 32.966286 ], "pop" : 386, "state" : "LA" }
+{ "_id" : "71251", "city" : "JONESBORO", "loc" : [ -92.694425, 32.248292 ], "pop" : 11078, "state" : "LA" }
+{ "_id" : "71254", "city" : "LAKE PROVIDENCE", "loc" : [ -91.19056999999999, 32.807067 ], "pop" : 7774, "state" : "LA" }
+{ "_id" : "71256", "city" : "LILLIE", "loc" : [ -92.68576899999999, 32.952931 ], "pop" : 439, "state" : "LA" }
+{ "_id" : "71259", "city" : "MANGHAM", "loc" : [ -91.797607, 32.333114 ], "pop" : 3493, "state" : "LA" }
+{ "_id" : "71260", "city" : "LINVILLE", "loc" : [ -92.25706, 32.888155 ], "pop" : 3761, "state" : "LA" }
+{ "_id" : "71261", "city" : "MER ROUGE", "loc" : [ -91.771643, 32.77176 ], "pop" : 2177, "state" : "LA" }
+{ "_id" : "71263", "city" : "TERRY", "loc" : [ -91.41290499999999, 32.872258 ], "pop" : 9056, "state" : "LA" }
+{ "_id" : "71264", "city" : "OAK RIDGE", "loc" : [ -91.761785, 32.624317 ], "pop" : 913, "state" : "LA" }
+{ "_id" : "71266", "city" : "PIONEER", "loc" : [ -91.464822, 32.715436 ], "pop" : 1451, "state" : "LA" }
+{ "_id" : "71268", "city" : "QUITMAN", "loc" : [ -92.70853200000001, 32.356423 ], "pop" : 2603, "state" : "LA" }
+{ "_id" : "71269", "city" : "ALTO", "loc" : [ -91.76430000000001, 32.468938 ], "pop" : 11441, "state" : "LA" }
+{ "_id" : "71270", "city" : "RUSTON", "loc" : [ -92.64392700000001, 32.530823 ], "pop" : 26114, "state" : "LA" }
+{ "_id" : "71275", "city" : "SIMSBORO", "loc" : [ -92.79948400000001, 32.538388 ], "pop" : 2476, "state" : "LA" }
+{ "_id" : "71276", "city" : "SONDHEIMER", "loc" : [ -91.248197, 32.577216 ], "pop" : 887, "state" : "LA" }
+{ "_id" : "71277", "city" : "SPEARSVILLE", "loc" : [ -92.58698, 32.955022 ], "pop" : 2830, "state" : "LA" }
+{ "_id" : "71280", "city" : "SPENCER", "loc" : [ -92.12134, 32.593268 ], "pop" : 14, "state" : "LA" }
+{ "_id" : "71282", "city" : "MOUND", "loc" : [ -91.190066, 32.402127 ], "pop" : 12354, "state" : "LA" }
+{ "_id" : "71286", "city" : "TRANSYLVANIA", "loc" : [ -91.228813, 32.670529 ], "pop" : 1067, "state" : "LA" }
+{ "_id" : "71291", "city" : "WEST MONROE", "loc" : [ -92.175971, 32.531726 ], "pop" : 27809, "state" : "LA" }
+{ "_id" : "71292", "city" : "WEST MONROE", "loc" : [ -92.185445, 32.456599 ], "pop" : 17851, "state" : "LA" }
+{ "_id" : "71295", "city" : "WINNSBORO", "loc" : [ -91.71084500000001, 32.159229 ], "pop" : 14751, "state" : "LA" }
+{ "_id" : "71301", "city" : "ALEXANDRIA", "loc" : [ -92.46334899999999, 31.288519 ], "pop" : 25040, "state" : "LA" }
+{ "_id" : "71302", "city" : "ALEXANDRIA", "loc" : [ -92.42416900000001, 31.268272 ], "pop" : 16918, "state" : "LA" }
+{ "_id" : "71303", "city" : "ALEXANDRIA", "loc" : [ -92.508892, 31.304838 ], "pop" : 21759, "state" : "LA" }
+{ "_id" : "71316", "city" : "ACME", "loc" : [ -91.821563, 31.301618 ], "pop" : 173, "state" : "LA" }
+{ "_id" : "71318", "city" : "BIG BEND", "loc" : [ -91.84506500000001, 31.079347 ], "pop" : 786, "state" : "LA" }
+{ "_id" : "71322", "city" : "EOLA", "loc" : [ -92.182582, 30.949284 ], "pop" : 6271, "state" : "LA" }
+{ "_id" : "71323", "city" : "CENTER POINT", "loc" : [ -92.18786799999999, 31.263068 ], "pop" : 1720, "state" : "LA" }
+{ "_id" : "71325", "city" : "CHENEYVILLE", "loc" : [ -92.29514399999999, 31.020097 ], "pop" : 1545, "state" : "LA" }
+{ "_id" : "71326", "city" : "CLAYTON", "loc" : [ -91.542547, 31.78857 ], "pop" : 1070, "state" : "LA" }
+{ "_id" : "71327", "city" : "COTTONPORT", "loc" : [ -92.05812400000001, 30.986168 ], "pop" : 3190, "state" : "LA" }
+{ "_id" : "71328", "city" : "BUCKEYE", "loc" : [ -92.202287, 31.354506 ], "pop" : 6080, "state" : "LA" }
+{ "_id" : "71331", "city" : "VICK", "loc" : [ -92.194182, 31.189613 ], "pop" : 447, "state" : "LA" }
+{ "_id" : "71333", "city" : "GOUDEAU", "loc" : [ -92.090039, 30.951089 ], "pop" : 919, "state" : "LA" }
+{ "_id" : "71334", "city" : "FROGMORE", "loc" : [ -91.571958, 31.647944 ], "pop" : 9280, "state" : "LA" }
+{ "_id" : "71336", "city" : "GILBERT", "loc" : [ -91.592026, 32.034943 ], "pop" : 793, "state" : "LA" }
+{ "_id" : "71339", "city" : "HAMBURG", "loc" : [ -91.916177, 31.073269 ], "pop" : 481, "state" : "LA" }
+{ "_id" : "71340", "city" : "HARRISONBURG", "loc" : [ -91.883971, 31.766926 ], "pop" : 2348, "state" : "LA" }
+{ "_id" : "71341", "city" : "HESSMER", "loc" : [ -92.139933, 31.0534 ], "pop" : 3057, "state" : "LA" }
+{ "_id" : "71342", "city" : "JENA", "loc" : [ -92.113677, 31.674817 ], "pop" : 5796, "state" : "LA" }
+{ "_id" : "71343", "city" : "LARTO", "loc" : [ -91.845812, 31.636486 ], "pop" : 5507, "state" : "LA" }
+{ "_id" : "71346", "city" : "LECOMPTE", "loc" : [ -92.389031, 31.106032 ], "pop" : 3056, "state" : "LA" }
+{ "_id" : "71350", "city" : "MANSURA", "loc" : [ -92.054333, 31.061466 ], "pop" : 3239, "state" : "LA" }
+{ "_id" : "71351", "city" : "MARKSVILLE", "loc" : [ -92.083145, 31.139614 ], "pop" : 11217, "state" : "LA" }
+{ "_id" : "71353", "city" : "MELVILLE", "loc" : [ -91.75649, 30.662643 ], "pop" : 2713, "state" : "LA" }
+{ "_id" : "71354", "city" : "MONTEREY", "loc" : [ -91.734455, 31.440287 ], "pop" : 2074, "state" : "LA" }
+{ "_id" : "71355", "city" : "MOREAUVILLE", "loc" : [ -91.981814, 31.036766 ], "pop" : 1914, "state" : "LA" }
+{ "_id" : "71356", "city" : "LE MOYEN", "loc" : [ -92.040781, 30.824887 ], "pop" : 404, "state" : "LA" }
+{ "_id" : "71357", "city" : "NEWELLTON", "loc" : [ -91.25777100000001, 32.065621 ], "pop" : 3235, "state" : "LA" }
+{ "_id" : "71358", "city" : "PALMETTO", "loc" : [ -91.911384, 30.706543 ], "pop" : 621, "state" : "LA" }
+{ "_id" : "71360", "city" : "KOLIN", "loc" : [ -92.399276, 31.34991 ], "pop" : 37069, "state" : "LA" }
+{ "_id" : "71362", "city" : "PLAUCHEVILLE", "loc" : [ -91.984673, 30.936484 ], "pop" : 2517, "state" : "LA" }
+{ "_id" : "71366", "city" : "SAINT JOSEPH", "loc" : [ -91.278432, 31.924805 ], "pop" : 2073, "state" : "LA" }
+{ "_id" : "71367", "city" : "SAINT LANDRY", "loc" : [ -92.393846, 30.83812 ], "pop" : 5679, "state" : "LA" }
+{ "_id" : "71368", "city" : "SICILY ISLAND", "loc" : [ -91.680711, 31.850734 ], "pop" : 1568, "state" : "LA" }
+{ "_id" : "71369", "city" : "SIMMESPORT", "loc" : [ -91.825868, 30.977119 ], "pop" : 3137, "state" : "LA" }
+{ "_id" : "71371", "city" : "TROUT", "loc" : [ -92.19931, 31.653142 ], "pop" : 3624, "state" : "LA" }
+{ "_id" : "71373", "city" : "VIDALIA", "loc" : [ -91.469471, 31.578222 ], "pop" : 9257, "state" : "LA" }
+{ "_id" : "71375", "city" : "WATERPROOF", "loc" : [ -91.387154, 31.807613 ], "pop" : 1245, "state" : "LA" }
+{ "_id" : "71378", "city" : "WISNER", "loc" : [ -91.67679800000001, 31.991252 ], "pop" : 4116, "state" : "LA" }
+{ "_id" : "71401", "city" : "AIMWELL", "loc" : [ -91.992491, 31.761898 ], "pop" : 51, "state" : "LA" }
+{ "_id" : "71403", "city" : "ANACOCO", "loc" : [ -93.358949, 31.221762 ], "pop" : 4978, "state" : "LA" }
+{ "_id" : "71404", "city" : "ATLANTA", "loc" : [ -92.76412500000001, 31.873583 ], "pop" : 2466, "state" : "LA" }
+{ "_id" : "71406", "city" : "BELMONT", "loc" : [ -93.495863, 31.709956 ], "pop" : 616, "state" : "LA" }
+{ "_id" : "71407", "city" : "BENTLEY", "loc" : [ -92.49272999999999, 31.466035 ], "pop" : 2805, "state" : "LA" }
+{ "_id" : "71409", "city" : "BOYCE", "loc" : [ -92.68668099999999, 31.321601 ], "pop" : 4672, "state" : "LA" }
+{ "_id" : "71411", "city" : "CAMPTI", "loc" : [ -93.09357199999999, 31.895851 ], "pop" : 3990, "state" : "LA" }
+{ "_id" : "71412", "city" : "CHOPIN", "loc" : [ -92.94971700000001, 31.541916 ], "pop" : 434, "state" : "LA" }
+{ "_id" : "71416", "city" : "DERRY", "loc" : [ -92.857326, 31.535918 ], "pop" : 802, "state" : "LA" }
+{ "_id" : "71417", "city" : "COLFAX", "loc" : [ -92.656758, 31.507948 ], "pop" : 5520, "state" : "LA" }
+{ "_id" : "71418", "city" : "HEBERT", "loc" : [ -92.10365299999999, 32.114794 ], "pop" : 4785, "state" : "LA" }
+{ "_id" : "71419", "city" : "MITCHELL", "loc" : [ -93.71569, 31.785153 ], "pop" : 1592, "state" : "LA" }
+{ "_id" : "71422", "city" : "DODSON", "loc" : [ -92.678292, 32.070131 ], "pop" : 2198, "state" : "LA" }
+{ "_id" : "71423", "city" : "DRY PRONG", "loc" : [ -92.566479, 31.597921 ], "pop" : 1993, "state" : "LA" }
+{ "_id" : "71424", "city" : "ELMER", "loc" : [ -92.717062, 31.146476 ], "pop" : 1364, "state" : "LA" }
+{ "_id" : "71425", "city" : "ENTERPRISE", "loc" : [ -91.87514899999999, 31.906412 ], "pop" : 124, "state" : "LA" }
+{ "_id" : "71426", "city" : "FISHER", "loc" : [ -93.46019699999999, 31.493655 ], "pop" : 370, "state" : "LA" }
+{ "_id" : "71427", "city" : "FLATWOODS", "loc" : [ -92.881246, 31.384882 ], "pop" : 312, "state" : "LA" }
+{ "_id" : "71429", "city" : "FLORIEN", "loc" : [ -93.517916, 31.427455 ], "pop" : 6006, "state" : "LA" }
+{ "_id" : "71430", "city" : "FOREST HILL", "loc" : [ -92.51079799999999, 31.024304 ], "pop" : 1804, "state" : "LA" }
+{ "_id" : "71432", "city" : "GEORGETOWN", "loc" : [ -92.39518200000001, 31.745006 ], "pop" : 1016, "state" : "LA" }
+{ "_id" : "71433", "city" : "CALCASIEU", "loc" : [ -92.645758, 30.978384 ], "pop" : 4204, "state" : "LA" }
+{ "_id" : "71435", "city" : "GRAYSON", "loc" : [ -91.974615, 32.012108 ], "pop" : 324, "state" : "LA" }
+{ "_id" : "71438", "city" : "LEANDER", "loc" : [ -92.77488, 31.082535 ], "pop" : 854, "state" : "LA" }
+{ "_id" : "71439", "city" : "HORNBECK", "loc" : [ -93.368306, 31.322639 ], "pop" : 1352, "state" : "LA" }
+{ "_id" : "71441", "city" : "KELLY", "loc" : [ -92.12607199999999, 32.028619 ], "pop" : 4042, "state" : "LA" }
+{ "_id" : "71444", "city" : "LACAMP", "loc" : [ -92.89618299999999, 31.160702 ], "pop" : 276, "state" : "LA" }
+{ "_id" : "71446", "city" : "HICKS", "loc" : [ -93.223957, 31.144292 ], "pop" : 21956, "state" : "LA" }
+{ "_id" : "71447", "city" : "CHOPIN", "loc" : [ -92.77185, 31.418481 ], "pop" : 757, "state" : "LA" }
+{ "_id" : "71449", "city" : "MANY", "loc" : [ -93.464113, 31.58508 ], "pop" : 6560, "state" : "LA" }
+{ "_id" : "71450", "city" : "MARTHAVILLE", "loc" : [ -93.395428, 31.772583 ], "pop" : 932, "state" : "LA" }
+{ "_id" : "71451", "city" : "MELDER", "loc" : [ -92.66218600000001, 31.11932 ], "pop" : 377, "state" : "LA" }
+{ "_id" : "71454", "city" : "MONTGOMERY", "loc" : [ -92.841178, 31.667388 ], "pop" : 2263, "state" : "LA" }
+{ "_id" : "71455", "city" : "CLIFTON", "loc" : [ -92.888915, 31.333927 ], "pop" : 443, "state" : "LA" }
+{ "_id" : "71456", "city" : "NATCHEZ", "loc" : [ -93.024117, 31.661502 ], "pop" : 2070, "state" : "LA" }
+{ "_id" : "71457", "city" : "NATCHITOCHES", "loc" : [ -93.091572, 31.761688 ], "pop" : 23878, "state" : "LA" }
+{ "_id" : "71459", "city" : "FORT POLK", "loc" : [ -93.22213000000001, 31.032068 ], "pop" : 27181, "state" : "LA" }
+{ "_id" : "71461", "city" : "NEWLLANO", "loc" : [ -93.287899, 31.069396 ], "pop" : 250, "state" : "LA" }
+{ "_id" : "71462", "city" : "NOBLE", "loc" : [ -93.716679, 31.693849 ], "pop" : 841, "state" : "LA" }
+{ "_id" : "71463", "city" : "OAKDALE", "loc" : [ -92.66396400000001, 30.817173 ], "pop" : 9577, "state" : "LA" }
+{ "_id" : "71465", "city" : "OLLA", "loc" : [ -92.22139, 31.87339 ], "pop" : 3448, "state" : "LA" }
+{ "_id" : "71466", "city" : "OTIS", "loc" : [ -92.744478, 31.226442 ], "pop" : 231, "state" : "LA" }
+{ "_id" : "71467", "city" : "POLLOCK", "loc" : [ -92.400536, 31.499966 ], "pop" : 4328, "state" : "LA" }
+{ "_id" : "71468", "city" : "PROVENCAL", "loc" : [ -93.140089, 31.580117 ], "pop" : 2700, "state" : "LA" }
+{ "_id" : "71469", "city" : "ROBELINE", "loc" : [ -93.320972, 31.771453 ], "pop" : 939, "state" : "LA" }
+{ "_id" : "71472", "city" : "SIEPER", "loc" : [ -92.76981000000001, 31.197034 ], "pop" : 474, "state" : "LA" }
+{ "_id" : "71473", "city" : "SIKES", "loc" : [ -92.442894, 32.068616 ], "pop" : 579, "state" : "LA" }
+{ "_id" : "71477", "city" : "TIOGA", "loc" : [ -92.44711599999999, 31.415732 ], "pop" : 2158, "state" : "LA" }
+{ "_id" : "71479", "city" : "TULLOS", "loc" : [ -92.301254, 31.853088 ], "pop" : 1280, "state" : "LA" }
+{ "_id" : "71483", "city" : "WINNFIELD", "loc" : [ -92.636646, 31.921389 ], "pop" : 9295, "state" : "LA" }
+{ "_id" : "71485", "city" : "WOODWORTH", "loc" : [ -92.49899600000001, 31.132588 ], "pop" : 1932, "state" : "LA" }
+{ "_id" : "71486", "city" : "ZWOLLE", "loc" : [ -93.663569, 31.61379 ], "pop" : 5325, "state" : "LA" }
+{ "_id" : "71601", "city" : "NORTH CEDAR", "loc" : [ -91.995812, 34.215405 ], "pop" : 23095, "state" : "AR" }
+{ "_id" : "71602", "city" : "DOLLARWAY", "loc" : [ -92.089718, 34.257001 ], "pop" : 15547, "state" : "AR" }
+{ "_id" : "71603", "city" : "PINE BLUFF", "loc" : [ -92.044786, 34.189745 ], "pop" : 36473, "state" : "AR" }
+{ "_id" : "71630", "city" : "ARKANSAS CITY", "loc" : [ -91.232529, 33.614328 ], "pop" : 7, "state" : "AR" }
+{ "_id" : "71631", "city" : "BANKS", "loc" : [ -92.260386, 33.549665 ], "pop" : 514, "state" : "AR" }
+{ "_id" : "71635", "city" : "NORTH", "loc" : [ -91.959152, 33.152369 ], "pop" : 14645, "state" : "AR" }
+{ "_id" : "71638", "city" : "DERMOTT", "loc" : [ -91.439391, 33.524054 ], "pop" : 5880, "state" : "AR" }
+{ "_id" : "71639", "city" : "DUMAS", "loc" : [ -91.486056, 33.892102 ], "pop" : 7033, "state" : "AR" }
+{ "_id" : "71640", "city" : "EUDORA", "loc" : [ -91.271552, 33.12135 ], "pop" : 4860, "state" : "AR" }
+{ "_id" : "71642", "city" : "FOUNTAIN HILL", "loc" : [ -91.835627, 33.342951 ], "pop" : 704, "state" : "AR" }
+{ "_id" : "71643", "city" : "GOULD", "loc" : [ -91.576798, 34.034503 ], "pop" : 3765, "state" : "AR" }
+{ "_id" : "71644", "city" : "TAMO", "loc" : [ -91.67082000000001, 34.030484 ], "pop" : 3768, "state" : "AR" }
+{ "_id" : "71646", "city" : "HAMBURG", "loc" : [ -91.80226500000001, 33.2058 ], "pop" : 5422, "state" : "AR" }
+{ "_id" : "71647", "city" : "INGALLS", "loc" : [ -92.127714, 33.422207 ], "pop" : 2150, "state" : "AR" }
+{ "_id" : "71651", "city" : "JERSEY", "loc" : [ -92.29661299999999, 33.388914 ], "pop" : 301, "state" : "AR" }
+{ "_id" : "71652", "city" : "KINGSLAND", "loc" : [ -92.30141500000001, 33.86002 ], "pop" : 993, "state" : "AR" }
+{ "_id" : "71653", "city" : "LAKE VILLAGE", "loc" : [ -91.282487, 33.327408 ], "pop" : 5501, "state" : "AR" }
+{ "_id" : "71654", "city" : "MC GEHEE", "loc" : [ -91.392781, 33.62971 ], "pop" : 6646, "state" : "AR" }
+{ "_id" : "71655", "city" : "MONTICELLO", "loc" : [ -91.794845, 33.624951 ], "pop" : 14127, "state" : "AR" }
+{ "_id" : "71658", "city" : "MONTROSE", "loc" : [ -91.52277599999999, 33.307516 ], "pop" : 948, "state" : "AR" }
+{ "_id" : "71660", "city" : "NEW EDINBURG", "loc" : [ -92.193909, 33.758846 ], "pop" : 1105, "state" : "AR" }
+{ "_id" : "71661", "city" : "PARKDALE", "loc" : [ -91.542793, 33.121267 ], "pop" : 560, "state" : "AR" }
+{ "_id" : "71662", "city" : "PICKENS", "loc" : [ -91.39157, 33.807923 ], "pop" : 1228, "state" : "AR" }
+{ "_id" : "71663", "city" : "PORTLAND", "loc" : [ -91.513935, 33.231773 ], "pop" : 773, "state" : "AR" }
+{ "_id" : "71665", "city" : "RISON", "loc" : [ -92.118762, 33.945325 ], "pop" : 5669, "state" : "AR" }
+{ "_id" : "71666", "city" : "ROHWER", "loc" : [ -91.205124, 33.616003 ], "pop" : 656, "state" : "AR" }
+{ "_id" : "71667", "city" : "STAR CITY", "loc" : [ -91.865343, 33.940528 ], "pop" : 5913, "state" : "AR" }
+{ "_id" : "71670", "city" : "REED", "loc" : [ -91.520287, 33.67479 ], "pop" : 739, "state" : "AR" }
+{ "_id" : "71671", "city" : "WARREN", "loc" : [ -92.07782400000001, 33.613983 ], "pop" : 8828, "state" : "AR" }
+{ "_id" : "71674", "city" : "WATSON", "loc" : [ -91.28145499999999, 33.890737 ], "pop" : 1003, "state" : "AR" }
+{ "_id" : "71675", "city" : "WILMAR", "loc" : [ -91.925697, 33.621296 ], "pop" : 1293, "state" : "AR" }
+{ "_id" : "71676", "city" : "WILMOT", "loc" : [ -91.572283, 33.057557 ], "pop" : 1267, "state" : "AR" }
+{ "_id" : "71677", "city" : "WINCHESTER", "loc" : [ -91.543059, 33.752039 ], "pop" : 687, "state" : "AR" }
+{ "_id" : "71678", "city" : "YORKTOWN", "loc" : [ -91.79647199999999, 34.017166 ], "pop" : 868, "state" : "AR" }
+{ "_id" : "71701", "city" : "EAST CAMDEN", "loc" : [ -92.833386, 33.575866 ], "pop" : 22640, "state" : "AR" }
+{ "_id" : "71720", "city" : "BEARDEN", "loc" : [ -92.61802, 33.729797 ], "pop" : 1945, "state" : "AR" }
+{ "_id" : "71722", "city" : "BLUFF CITY", "loc" : [ -93.18681100000001, 33.698191 ], "pop" : 546, "state" : "AR" }
+{ "_id" : "71725", "city" : "CARTHAGE", "loc" : [ -92.62623000000001, 34.063625 ], "pop" : 1255, "state" : "AR" }
+{ "_id" : "71726", "city" : "READER", "loc" : [ -93.018716, 33.700148 ], "pop" : 1416, "state" : "AR" }
+{ "_id" : "71730", "city" : "EL DORADO", "loc" : [ -92.662856, 33.20735 ], "pop" : 35308, "state" : "AR" }
+{ "_id" : "71740", "city" : "EMERSON", "loc" : [ -93.198699, 33.089054 ], "pop" : 1888, "state" : "AR" }
+{ "_id" : "71742", "city" : "FORDYCE", "loc" : [ -92.42247500000001, 33.817648 ], "pop" : 6001, "state" : "AR" }
+{ "_id" : "71743", "city" : "GURDON", "loc" : [ -93.14169099999999, 33.912493 ], "pop" : 4180, "state" : "AR" }
+{ "_id" : "71744", "city" : "HAMPTON", "loc" : [ -92.52951, 33.537613 ], "pop" : 3505, "state" : "AR" }
+{ "_id" : "71745", "city" : "HARRELL", "loc" : [ -92.391243, 33.510865 ], "pop" : 846, "state" : "AR" }
+{ "_id" : "71747", "city" : "HUTTIG", "loc" : [ -92.194153, 33.045888 ], "pop" : 1287, "state" : "AR" }
+{ "_id" : "71748", "city" : "IVAN", "loc" : [ -92.43940600000001, 33.902984 ], "pop" : 353, "state" : "AR" }
+{ "_id" : "71749", "city" : "JUNCTION CITY", "loc" : [ -92.684254, 33.043965 ], "pop" : 1553, "state" : "AR" }
+{ "_id" : "71751", "city" : "LOUANN", "loc" : [ -92.782759, 33.411744 ], "pop" : 1667, "state" : "AR" }
+{ "_id" : "71752", "city" : "MC NEIL", "loc" : [ -93.193006, 33.36222 ], "pop" : 2020, "state" : "AR" }
+{ "_id" : "71753", "city" : "MAGNOLIA", "loc" : [ -93.239153, 33.264678 ], "pop" : 16379, "state" : "AR" }
+{ "_id" : "71758", "city" : "MOUNT HOLLY", "loc" : [ -92.944265, 33.308534 ], "pop" : 514, "state" : "AR" }
+{ "_id" : "71759", "city" : "NORPHLET", "loc" : [ -92.657619, 33.309619 ], "pop" : 1765, "state" : "AR" }
+{ "_id" : "71762", "city" : "SMACKOVER", "loc" : [ -92.74424999999999, 33.339831 ], "pop" : 3554, "state" : "AR" }
+{ "_id" : "71763", "city" : "MANNING", "loc" : [ -92.810984, 33.902989 ], "pop" : 2005, "state" : "AR" }
+{ "_id" : "71764", "city" : "STEPHENS", "loc" : [ -93.02139099999999, 33.455044 ], "pop" : 2906, "state" : "AR" }
+{ "_id" : "71765", "city" : "STRONG", "loc" : [ -92.362104, 33.119526 ], "pop" : 2738, "state" : "AR" }
+{ "_id" : "71766", "city" : "THORNTON", "loc" : [ -92.468299, 33.767694 ], "pop" : 1272, "state" : "AR" }
+{ "_id" : "71767", "city" : "TINSMAN", "loc" : [ -92.382192, 33.643436 ], "pop" : 203, "state" : "AR" }
+{ "_id" : "71769", "city" : "VILLAGE", "loc" : [ -93.046404, 33.281849 ], "pop" : 882, "state" : "AR" }
+{ "_id" : "71770", "city" : "WALDO", "loc" : [ -93.294915, 33.360017 ], "pop" : 2862, "state" : "AR" }
+{ "_id" : "71801", "city" : "PERRYTOWN", "loc" : [ -93.590305, 33.656645 ], "pop" : 15955, "state" : "AR" }
+{ "_id" : "71822", "city" : "ASHDOWN", "loc" : [ -94.135102, 33.678711 ], "pop" : 8514, "state" : "AR" }
+{ "_id" : "71825", "city" : "BLEVINS", "loc" : [ -93.536035, 33.875468 ], "pop" : 831, "state" : "AR" }
+{ "_id" : "71826", "city" : "BRADLEY", "loc" : [ -93.62749599999999, 33.106963 ], "pop" : 2623, "state" : "AR" }
+{ "_id" : "71827", "city" : "BUCKNER", "loc" : [ -93.44699799999999, 33.375323 ], "pop" : 1364, "state" : "AR" }
+{ "_id" : "71828", "city" : "CALE", "loc" : [ -93.26497000000001, 33.616403 ], "pop" : 230, "state" : "AR" }
+{ "_id" : "71831", "city" : "COLUMBUS", "loc" : [ -93.85588, 33.745108 ], "pop" : 739, "state" : "AR" }
+{ "_id" : "71832", "city" : "DE QUEEN", "loc" : [ -94.338559, 34.044206 ], "pop" : 7593, "state" : "AR" }
+{ "_id" : "71833", "city" : "DIERKS", "loc" : [ -94.015243, 34.13232 ], "pop" : 2284, "state" : "AR" }
+{ "_id" : "71834", "city" : "DODDRIDGE", "loc" : [ -93.954307, 33.105448 ], "pop" : 1435, "state" : "AR" }
+{ "_id" : "71835", "city" : "EMMET", "loc" : [ -93.423242, 33.692896 ], "pop" : 1141, "state" : "AR" }
+{ "_id" : "71836", "city" : "FOREMAN", "loc" : [ -94.388108, 33.71759 ], "pop" : 2740, "state" : "AR" }
+{ "_id" : "71837", "city" : "FOUKE", "loc" : [ -93.900953, 33.302476 ], "pop" : 5895, "state" : "AR" }
+{ "_id" : "71838", "city" : "FULTON", "loc" : [ -93.80856199999999, 33.629876 ], "pop" : 925, "state" : "AR" }
+{ "_id" : "71839", "city" : "GARLAND CITY", "loc" : [ -93.731624, 33.335161 ], "pop" : 666, "state" : "AR" }
+{ "_id" : "71841", "city" : "GILLHAM", "loc" : [ -94.316497, 34.157003 ], "pop" : 853, "state" : "AR" }
+{ "_id" : "71842", "city" : "HORATIO", "loc" : [ -94.295942, 33.939221 ], "pop" : 2952, "state" : "AR" }
+{ "_id" : "71845", "city" : "LEWISVILLE", "loc" : [ -93.595258, 33.373603 ], "pop" : 2550, "state" : "AR" }
+{ "_id" : "71846", "city" : "LOCKESBURG", "loc" : [ -94.127588, 33.930553 ], "pop" : 2239, "state" : "AR" }
+{ "_id" : "71847", "city" : "MC CASKILL", "loc" : [ -93.626605, 33.923042 ], "pop" : 658, "state" : "AR" }
+{ "_id" : "71851", "city" : "MINERAL SPRINGS", "loc" : [ -93.918828, 33.863852 ], "pop" : 2732, "state" : "AR" }
+{ "_id" : "71852", "city" : "NASHVILLE", "loc" : [ -93.87070900000001, 33.957646 ], "pop" : 7625, "state" : "AR" }
+{ "_id" : "71853", "city" : "OGDEN", "loc" : [ -94.027826, 33.585706 ], "pop" : 779, "state" : "AR" }
+{ "_id" : "71855", "city" : "OZAN", "loc" : [ -93.771443, 33.902775 ], "pop" : 1695, "state" : "AR" }
+{ "_id" : "71857", "city" : "PRESCOTT", "loc" : [ -93.372544, 33.804029 ], "pop" : 5732, "state" : "AR" }
+{ "_id" : "71858", "city" : "ROSSTON", "loc" : [ -93.30389099999999, 33.561693 ], "pop" : 1561, "state" : "AR" }
+{ "_id" : "71859", "city" : "SARATOGA", "loc" : [ -93.876723, 33.759883 ], "pop" : 281, "state" : "AR" }
+{ "_id" : "71860", "city" : "STAMPS", "loc" : [ -93.501307, 33.356877 ], "pop" : 3106, "state" : "AR" }
+{ "_id" : "71861", "city" : "TAYLOR", "loc" : [ -93.44601900000001, 33.107957 ], "pop" : 1660, "state" : "AR" }
+{ "_id" : "71862", "city" : "WASHINGTON", "loc" : [ -93.673529, 33.754596 ], "pop" : 821, "state" : "AR" }
+{ "_id" : "71864", "city" : "WILLISVILLE", "loc" : [ -93.31211999999999, 33.484731 ], "pop" : 888, "state" : "AR" }
+{ "_id" : "71865", "city" : "WILTON", "loc" : [ -94.135746, 33.734794 ], "pop" : 983, "state" : "AR" }
+{ "_id" : "71866", "city" : "WINTHROP", "loc" : [ -94.395174, 33.858321 ], "pop" : 950, "state" : "AR" }
+{ "_id" : "71901", "city" : "LAKE CATHERINE", "loc" : [ -93.02602400000001, 34.501475 ], "pop" : 27402, "state" : "AR" }
+{ "_id" : "71909", "city" : "HOT SPRINGS VILL", "loc" : [ -93.00638600000001, 34.65862 ], "pop" : 8268, "state" : "AR" }
+{ "_id" : "71913", "city" : "LAKE HAMILTON", "loc" : [ -93.109177, 34.473304 ], "pop" : 31048, "state" : "AR" }
+{ "_id" : "71921", "city" : "AMITY", "loc" : [ -93.420551, 34.259362 ], "pop" : 1569, "state" : "AR" }
+{ "_id" : "71922", "city" : "ANTOINE", "loc" : [ -93.437169, 34.028296 ], "pop" : 474, "state" : "AR" }
+{ "_id" : "71923", "city" : "ARKADELPHIA", "loc" : [ -93.068989, 34.11525 ], "pop" : 14961, "state" : "AR" }
+{ "_id" : "71929", "city" : "BISMARCK", "loc" : [ -93.187236, 34.311033 ], "pop" : 1291, "state" : "AR" }
+{ "_id" : "71931", "city" : "BLAKELY", "loc" : [ -93.063509, 34.703957 ], "pop" : 271, "state" : "AR" }
+{ "_id" : "71933", "city" : "BONNERDALE", "loc" : [ -93.31941500000001, 34.349751 ], "pop" : 1037, "state" : "AR" }
+{ "_id" : "71935", "city" : "CADDO GAP", "loc" : [ -93.586376, 34.397579 ], "pop" : 2257, "state" : "AR" }
+{ "_id" : "71937", "city" : "COVE", "loc" : [ -94.39234, 34.419159 ], "pop" : 1681, "state" : "AR" }
+{ "_id" : "71940", "city" : "DELIGHT", "loc" : [ -93.524666, 34.023772 ], "pop" : 1529, "state" : "AR" }
+{ "_id" : "71941", "city" : "DONALDSON", "loc" : [ -92.909384, 34.221221 ], "pop" : 748, "state" : "AR" }
+{ "_id" : "71942", "city" : "FRIENDSHIP", "loc" : [ -92.98039300000001, 34.241225 ], "pop" : 626, "state" : "AR" }
+{ "_id" : "71943", "city" : "GLENWOOD", "loc" : [ -93.555881, 34.319207 ], "pop" : 2720, "state" : "AR" }
+{ "_id" : "71944", "city" : "GRANNIS", "loc" : [ -94.32550000000001, 34.237021 ], "pop" : 751, "state" : "AR" }
+{ "_id" : "71945", "city" : "HATFIELD", "loc" : [ -94.371397, 34.487703 ], "pop" : 1048, "state" : "AR" }
+{ "_id" : "71949", "city" : "JESSIEVILLE", "loc" : [ -93.19631800000001, 34.693729 ], "pop" : 931, "state" : "AR" }
+{ "_id" : "71950", "city" : "KIRBY", "loc" : [ -93.616716, 34.255153 ], "pop" : 973, "state" : "AR" }
+{ "_id" : "71952", "city" : "LANGLEY", "loc" : [ -93.850942, 34.314035 ], "pop" : 215, "state" : "AR" }
+{ "_id" : "71953", "city" : "MENA", "loc" : [ -94.220984, 34.581435 ], "pop" : 12505, "state" : "AR" }
+{ "_id" : "71956", "city" : "BUCKVILLE", "loc" : [ -93.16004100000001, 34.577182 ], "pop" : 1857, "state" : "AR" }
+{ "_id" : "71957", "city" : "MOUNT IDA", "loc" : [ -93.574904, 34.561194 ], "pop" : 3052, "state" : "AR" }
+{ "_id" : "71958", "city" : "MURFREESBORO", "loc" : [ -93.710903, 34.101734 ], "pop" : 3775, "state" : "AR" }
+{ "_id" : "71959", "city" : "NEWHOPE", "loc" : [ -93.89048699999999, 34.227347 ], "pop" : 400, "state" : "AR" }
+{ "_id" : "71960", "city" : "NORMAN", "loc" : [ -93.67430400000001, 34.459633 ], "pop" : 688, "state" : "AR" }
+{ "_id" : "71961", "city" : "ODEN", "loc" : [ -93.82110299999999, 34.611292 ], "pop" : 710, "state" : "AR" }
+{ "_id" : "71962", "city" : "OKOLONA", "loc" : [ -93.28967900000001, 34.055138 ], "pop" : 985, "state" : "AR" }
+{ "_id" : "71964", "city" : "PEARCY", "loc" : [ -93.24201499999999, 34.435092 ], "pop" : 3215, "state" : "AR" }
+{ "_id" : "71965", "city" : "PENCIL BLUFF", "loc" : [ -93.742947, 34.639946 ], "pop" : 323, "state" : "AR" }
+{ "_id" : "71968", "city" : "ROYAL", "loc" : [ -93.289734, 34.515049 ], "pop" : 1099, "state" : "AR" }
+{ "_id" : "71969", "city" : "SIMS", "loc" : [ -93.674071, 34.646181 ], "pop" : 461, "state" : "AR" }
+{ "_id" : "71970", "city" : "STORY", "loc" : [ -93.537587, 34.668695 ], "pop" : 350, "state" : "AR" }
+{ "_id" : "71971", "city" : "UMPIRE", "loc" : [ -94.03137700000001, 34.292129 ], "pop" : 647, "state" : "AR" }
+{ "_id" : "71972", "city" : "VANDERVOORT", "loc" : [ -94.369788, 34.379535 ], "pop" : 323, "state" : "AR" }
+{ "_id" : "71973", "city" : "WICKES", "loc" : [ -94.34025699999999, 34.308806 ], "pop" : 1273, "state" : "AR" }
+{ "_id" : "72001", "city" : "ADONA", "loc" : [ -92.903325, 35.046956 ], "pop" : 494, "state" : "AR" }
+{ "_id" : "72002", "city" : "ALEXANDER", "loc" : [ -92.472673, 34.631266 ], "pop" : 7984, "state" : "AR" }
+{ "_id" : "72003", "city" : "ALMYRA", "loc" : [ -91.430992, 34.41459 ], "pop" : 626, "state" : "AR" }
+{ "_id" : "72004", "city" : "ALTHEIMER", "loc" : [ -91.82891600000001, 34.306168 ], "pop" : 1929, "state" : "AR" }
+{ "_id" : "72005", "city" : "AMAGON", "loc" : [ -91.07963599999999, 35.561559 ], "pop" : 457, "state" : "AR" }
+{ "_id" : "72006", "city" : "AUGUSTA", "loc" : [ -91.352653, 35.278806 ], "pop" : 3702, "state" : "AR" }
+{ "_id" : "72007", "city" : "AUSTIN", "loc" : [ -91.95939799999999, 35.028369 ], "pop" : 1741, "state" : "AR" }
+{ "_id" : "72010", "city" : "BALD KNOB", "loc" : [ -91.550197, 35.311331 ], "pop" : 5132, "state" : "AR" }
+{ "_id" : "72011", "city" : "BAUXITE", "loc" : [ -92.36053099999999, 34.545537 ], "pop" : 6956, "state" : "AR" }
+{ "_id" : "72012", "city" : "BEEBE", "loc" : [ -91.907449, 35.093743 ], "pop" : 7862, "state" : "AR" }
+{ "_id" : "72013", "city" : "BEE BRANCH", "loc" : [ -92.408523, 35.423367 ], "pop" : 1344, "state" : "AR" }
+{ "_id" : "72014", "city" : "BEEDEVILLE", "loc" : [ -91.106371, 35.420267 ], "pop" : 518, "state" : "AR" }
+{ "_id" : "72015", "city" : "BENTON", "loc" : [ -92.595241, 34.580087 ], "pop" : 36525, "state" : "AR" }
+{ "_id" : "72016", "city" : "BIGELOW", "loc" : [ -92.630842, 34.984659 ], "pop" : 2001, "state" : "AR" }
+{ "_id" : "72017", "city" : "BISCOE", "loc" : [ -91.490028, 34.833706 ], "pop" : 1348, "state" : "AR" }
+{ "_id" : "72020", "city" : "BRADFORD", "loc" : [ -91.518973, 35.427655 ], "pop" : 3546, "state" : "AR" }
+{ "_id" : "72021", "city" : "BRINKLEY", "loc" : [ -91.188596, 34.878124 ], "pop" : 6313, "state" : "AR" }
+{ "_id" : "72022", "city" : "BRYANT", "loc" : [ -92.49201499999999, 34.606786 ], "pop" : 6065, "state" : "AR" }
+{ "_id" : "72023", "city" : "CABOT", "loc" : [ -92.03177100000001, 34.945724 ], "pop" : 21197, "state" : "AR" }
+{ "_id" : "72024", "city" : "CARLISLE", "loc" : [ -91.745929, 34.793291 ], "pop" : 2904, "state" : "AR" }
+{ "_id" : "72025", "city" : "CASA", "loc" : [ -93.047005, 35.032168 ], "pop" : 649, "state" : "AR" }
+{ "_id" : "72026", "city" : "CASSCOE", "loc" : [ -91.324798, 34.473625 ], "pop" : 1033, "state" : "AR" }
+{ "_id" : "72027", "city" : "CENTER RIDGE", "loc" : [ -92.558167, 35.398063 ], "pop" : 981, "state" : "AR" }
+{ "_id" : "72028", "city" : "CHOCTAW", "loc" : [ -92.426412, 35.523528 ], "pop" : 1091, "state" : "AR" }
+{ "_id" : "72029", "city" : "CLARENDON", "loc" : [ -91.256426, 34.660138 ], "pop" : 3211, "state" : "AR" }
+{ "_id" : "72030", "city" : "CLEVELAND", "loc" : [ -92.71282100000001, 35.358328 ], "pop" : 1244, "state" : "AR" }
+{ "_id" : "72031", "city" : "CLINTON", "loc" : [ -92.475825, 35.604537 ], "pop" : 4098, "state" : "AR" }
+{ "_id" : "72032", "city" : "CONWAY", "loc" : [ -92.423574, 35.084199 ], "pop" : 43236, "state" : "AR" }
+{ "_id" : "72036", "city" : "COTTON PLANT", "loc" : [ -91.229043, 35.017827 ], "pop" : 1789, "state" : "AR" }
+{ "_id" : "72038", "city" : "CROCKETTS BLUFF", "loc" : [ -91.232079, 34.425272 ], "pop" : 132, "state" : "AR" }
+{ "_id" : "72039", "city" : "TWIN GROVES", "loc" : [ -92.432952, 35.291042 ], "pop" : 1605, "state" : "AR" }
+{ "_id" : "72040", "city" : "DES ARC", "loc" : [ -91.511342, 34.97507 ], "pop" : 3446, "state" : "AR" }
+{ "_id" : "72041", "city" : "DE VALLS BLUFF", "loc" : [ -91.49821799999999, 34.744704 ], "pop" : 1854, "state" : "AR" }
+{ "_id" : "72042", "city" : "DE WITT", "loc" : [ -91.33362700000001, 34.285312 ], "pop" : 5320, "state" : "AR" }
+{ "_id" : "72044", "city" : "EDGEMONT", "loc" : [ -92.199471, 35.623006 ], "pop" : 487, "state" : "AR" }
+{ "_id" : "72045", "city" : "EL PASO", "loc" : [ -92.090076, 35.114176 ], "pop" : 580, "state" : "AR" }
+{ "_id" : "72046", "city" : "ENGLAND", "loc" : [ -91.94842199999999, 34.557458 ], "pop" : 5254, "state" : "AR" }
+{ "_id" : "72047", "city" : "ENOLA", "loc" : [ -92.212328, 35.208705 ], "pop" : 500, "state" : "AR" }
+{ "_id" : "72048", "city" : "ETHEL", "loc" : [ -91.13983899999999, 34.243525 ], "pop" : 27, "state" : "AR" }
+{ "_id" : "72051", "city" : "FOX", "loc" : [ -92.304266, 35.768208 ], "pop" : 960, "state" : "AR" }
+{ "_id" : "72052", "city" : "GARNER", "loc" : [ -91.742884, 35.130305 ], "pop" : 618, "state" : "AR" }
+{ "_id" : "72055", "city" : "GILLETT", "loc" : [ -91.380048, 34.121838 ], "pop" : 925, "state" : "AR" }
+{ "_id" : "72057", "city" : "GRAPEVINE", "loc" : [ -92.31094400000001, 34.130893 ], "pop" : 591, "state" : "AR" }
+{ "_id" : "72058", "city" : "GREENBRIER", "loc" : [ -92.357792, 35.229547 ], "pop" : 5532, "state" : "AR" }
+{ "_id" : "72060", "city" : "GRIFFITHVILLE", "loc" : [ -91.624234, 35.114383 ], "pop" : 582, "state" : "AR" }
+{ "_id" : "72061", "city" : "GUY", "loc" : [ -92.33153900000001, 35.318487 ], "pop" : 1026, "state" : "AR" }
+{ "_id" : "72063", "city" : "HATTIEVILLE", "loc" : [ -92.778317, 35.290713 ], "pop" : 360, "state" : "AR" }
+{ "_id" : "72064", "city" : "HAZEN", "loc" : [ -91.576699, 34.783833 ], "pop" : 1841, "state" : "AR" }
+{ "_id" : "72065", "city" : "HENSLEY", "loc" : [ -92.21401899999999, 34.591133 ], "pop" : 3696, "state" : "AR" }
+{ "_id" : "72066", "city" : "HICKORY PLAINS", "loc" : [ -91.750844, 34.978642 ], "pop" : 522, "state" : "AR" }
+{ "_id" : "72067", "city" : "GREERS FERRY", "loc" : [ -92.182284, 35.549812 ], "pop" : 1802, "state" : "AR" }
+{ "_id" : "72068", "city" : "HIGGINSON", "loc" : [ -91.71827999999999, 35.188254 ], "pop" : 786, "state" : "AR" }
+{ "_id" : "72069", "city" : "HOLLY GROVE", "loc" : [ -91.184376, 34.599294 ], "pop" : 1417, "state" : "AR" }
+{ "_id" : "72070", "city" : "HOUSTON", "loc" : [ -92.69131899999999, 35.036209 ], "pop" : 642, "state" : "AR" }
+{ "_id" : "72072", "city" : "HUMNOKE", "loc" : [ -91.75661599999999, 34.541896 ], "pop" : 992, "state" : "AR" }
+{ "_id" : "72073", "city" : "HUMPHREY", "loc" : [ -91.67896, 34.403387 ], "pop" : 851, "state" : "AR" }
+{ "_id" : "72076", "city" : "GRAVEL RIDGE", "loc" : [ -92.13043500000001, 34.881985 ], "pop" : 37428, "state" : "AR" }
+{ "_id" : "72079", "city" : "JEFFERSON", "loc" : [ -92.148574, 34.355285 ], "pop" : 1682, "state" : "AR" }
+{ "_id" : "72080", "city" : "JERUSALEM", "loc" : [ -92.813886, 35.37975 ], "pop" : 765, "state" : "AR" }
+{ "_id" : "72081", "city" : "JUDSONIA", "loc" : [ -91.64908699999999, 35.324954 ], "pop" : 7033, "state" : "AR" }
+{ "_id" : "72082", "city" : "KENSETT", "loc" : [ -91.66967200000001, 35.229939 ], "pop" : 2123, "state" : "AR" }
+{ "_id" : "72083", "city" : "KEO", "loc" : [ -92.00784400000001, 34.604072 ], "pop" : 278, "state" : "AR" }
+{ "_id" : "72084", "city" : "LEOLA", "loc" : [ -92.597865, 34.185605 ], "pop" : 769, "state" : "AR" }
+{ "_id" : "72086", "city" : "LONOKE", "loc" : [ -91.921367, 34.783162 ], "pop" : 6733, "state" : "AR" }
+{ "_id" : "72087", "city" : "LONSDALE", "loc" : [ -92.834034, 34.556203 ], "pop" : 456, "state" : "AR" }
+{ "_id" : "72101", "city" : "MC CRORY", "loc" : [ -91.179327, 35.247292 ], "pop" : 4029, "state" : "AR" }
+{ "_id" : "72102", "city" : "MC RAE", "loc" : [ -91.821551, 35.11322 ], "pop" : 1095, "state" : "AR" }
+{ "_id" : "72103", "city" : "SHANNON HILLS", "loc" : [ -92.384618, 34.621756 ], "pop" : 8853, "state" : "AR" }
+{ "_id" : "72104", "city" : "MALVERN", "loc" : [ -92.829162, 34.355715 ], "pop" : 20257, "state" : "AR" }
+{ "_id" : "72105", "city" : "JONES MILLS", "loc" : [ -92.861975, 34.453624 ], "pop" : 1896, "state" : "AR" }
+{ "_id" : "72106", "city" : "MAYFLOWER", "loc" : [ -92.400102, 34.966853 ], "pop" : 3593, "state" : "AR" }
+{ "_id" : "72110", "city" : "MORRILTON", "loc" : [ -92.73543600000001, 35.169227 ], "pop" : 12976, "state" : "AR" }
+{ "_id" : "72111", "city" : "MOUNT VERNON", "loc" : [ -92.137334, 35.260613 ], "pop" : 534, "state" : "AR" }
+{ "_id" : "72112", "city" : "NEWPORT", "loc" : [ -91.257064, 35.598823 ], "pop" : 13502, "state" : "AR" }
+{ "_id" : "72113", "city" : "MAUMELLE", "loc" : [ -92.40589199999999, 34.849085 ], "pop" : 4806, "state" : "AR" }
+{ "_id" : "72114", "city" : "NORTH LITTLE ROC", "loc" : [ -92.265376, 34.766974 ], "pop" : 15485, "state" : "AR" }
+{ "_id" : "72116", "city" : "SHERWOOD", "loc" : [ -92.237359, 34.807629 ], "pop" : 29871, "state" : "AR" }
+{ "_id" : "72117", "city" : "NORTH LITTLE ROC", "loc" : [ -92.194604, 34.776305 ], "pop" : 12736, "state" : "AR" }
+{ "_id" : "72118", "city" : "CAMP JOSEPH T RO", "loc" : [ -92.307875, 34.821598 ], "pop" : 26442, "state" : "AR" }
+{ "_id" : "72120", "city" : "NORTH LITTLE ROC", "loc" : [ -92.214169, 34.859292 ], "pop" : 15389, "state" : "AR" }
+{ "_id" : "72121", "city" : "PANGBURN", "loc" : [ -91.79597099999999, 35.421583 ], "pop" : 1996, "state" : "AR" }
+{ "_id" : "72122", "city" : "PARON", "loc" : [ -92.748176, 34.785289 ], "pop" : 484, "state" : "AR" }
+{ "_id" : "72125", "city" : "PERRY", "loc" : [ -92.787976, 35.042732 ], "pop" : 648, "state" : "AR" }
+{ "_id" : "72126", "city" : "PERRYVILLE", "loc" : [ -92.847171, 34.970096 ], "pop" : 3851, "state" : "AR" }
+{ "_id" : "72127", "city" : "PLUMERVILLE", "loc" : [ -92.620435, 35.157466 ], "pop" : 1940, "state" : "AR" }
+{ "_id" : "72128", "city" : "POYEN", "loc" : [ -92.599037, 34.350828 ], "pop" : 1753, "state" : "AR" }
+{ "_id" : "72129", "city" : "PRATTSVILLE", "loc" : [ -92.513105, 34.307865 ], "pop" : 860, "state" : "AR" }
+{ "_id" : "72130", "city" : "PRIM", "loc" : [ -92.134596, 35.685733 ], "pop" : 74, "state" : "AR" }
+{ "_id" : "72131", "city" : "QUITMAN", "loc" : [ -92.133334, 35.404988 ], "pop" : 3043, "state" : "AR" }
+{ "_id" : "72132", "city" : "REDFIELD", "loc" : [ -92.17579000000001, 34.452647 ], "pop" : 1888, "state" : "AR" }
+{ "_id" : "72133", "city" : "REYDELL", "loc" : [ -91.55039499999999, 34.143281 ], "pop" : 150, "state" : "AR" }
+{ "_id" : "72134", "city" : "ROE", "loc" : [ -91.37705800000001, 34.628592 ], "pop" : 392, "state" : "AR" }
+{ "_id" : "72135", "city" : "ROLAND", "loc" : [ -92.51915200000001, 34.88287 ], "pop" : 1824, "state" : "AR" }
+{ "_id" : "72136", "city" : "ROMANCE", "loc" : [ -92.06985, 35.215462 ], "pop" : 576, "state" : "AR" }
+{ "_id" : "72137", "city" : "ROSE BUD", "loc" : [ -92.061988, 35.321447 ], "pop" : 891, "state" : "AR" }
+{ "_id" : "72140", "city" : "SAINT CHARLES", "loc" : [ -91.16808, 34.335296 ], "pop" : 607, "state" : "AR" }
+{ "_id" : "72141", "city" : "SCOTLAND", "loc" : [ -92.586652, 35.507956 ], "pop" : 1276, "state" : "AR" }
+{ "_id" : "72142", "city" : "SCOTT", "loc" : [ -92.11566000000001, 34.694215 ], "pop" : 1027, "state" : "AR" }
+{ "_id" : "72143", "city" : "GEORGETOWN", "loc" : [ -91.76293099999999, 35.253512 ], "pop" : 22586, "state" : "AR" }
+{ "_id" : "72150", "city" : "SHERIDAN", "loc" : [ -92.365713, 34.316527 ], "pop" : 9714, "state" : "AR" }
+{ "_id" : "72152", "city" : "SHERRILL", "loc" : [ -91.993285, 34.358148 ], "pop" : 615, "state" : "AR" }
+{ "_id" : "72153", "city" : "SHIRLEY", "loc" : [ -92.29751, 35.573259 ], "pop" : 4841, "state" : "AR" }
+{ "_id" : "72156", "city" : "SOLGOHACHIA", "loc" : [ -92.675387, 35.270056 ], "pop" : 133, "state" : "AR" }
+{ "_id" : "72157", "city" : "SPRINGFIELD", "loc" : [ -92.54567, 35.274879 ], "pop" : 752, "state" : "AR" }
+{ "_id" : "72160", "city" : "STUTTGART", "loc" : [ -91.548742, 34.485358 ], "pop" : 11801, "state" : "AR" }
+{ "_id" : "72165", "city" : "THIDA", "loc" : [ -91.461823, 35.553556 ], "pop" : 616, "state" : "AR" }
+{ "_id" : "72166", "city" : "TICHNOR", "loc" : [ -91.243684, 34.089311 ], "pop" : 331, "state" : "AR" }
+{ "_id" : "72167", "city" : "TRASKWOOD", "loc" : [ -92.654734, 34.450791 ], "pop" : 606, "state" : "AR" }
+{ "_id" : "72168", "city" : "TUCKER", "loc" : [ -91.916265, 34.441442 ], "pop" : 2170, "state" : "AR" }
+{ "_id" : "72170", "city" : "ULM", "loc" : [ -91.51343, 34.579938 ], "pop" : 507, "state" : "AR" }
+{ "_id" : "72173", "city" : "VILONIA", "loc" : [ -92.183235, 35.071895 ], "pop" : 2492, "state" : "AR" }
+{ "_id" : "72175", "city" : "WABBASEKA", "loc" : [ -91.754948, 34.393552 ], "pop" : 1021, "state" : "AR" }
+{ "_id" : "72176", "city" : "WARD", "loc" : [ -91.90038300000001, 34.95316 ], "pop" : 3503, "state" : "AR" }
+{ "_id" : "72179", "city" : "WILBURN", "loc" : [ -91.907248, 35.454547 ], "pop" : 1924, "state" : "AR" }
+{ "_id" : "72181", "city" : "WOOSTER", "loc" : [ -92.450998, 35.197308 ], "pop" : 1264, "state" : "AR" }
+{ "_id" : "72182", "city" : "WRIGHT", "loc" : [ -92.06308, 34.437656 ], "pop" : 302, "state" : "AR" }
+{ "_id" : "72201", "city" : "LITTLE ROCK", "loc" : [ -92.28193899999999, 34.748342 ], "pop" : 539, "state" : "AR" }
+{ "_id" : "72202", "city" : "LITTLE ROCK", "loc" : [ -92.274067, 34.736322 ], "pop" : 11686, "state" : "AR" }
+{ "_id" : "72204", "city" : "LITTLE ROCK", "loc" : [ -92.344041, 34.726904 ], "pop" : 33104, "state" : "AR" }
+{ "_id" : "72205", "city" : "LITTLE ROCK", "loc" : [ -92.345512, 34.750971 ], "pop" : 25156, "state" : "AR" }
+{ "_id" : "72206", "city" : "LITTLE ROCK", "loc" : [ -92.27760600000001, 34.683599 ], "pop" : 27367, "state" : "AR" }
+{ "_id" : "72207", "city" : "LITTLE ROCK", "loc" : [ -92.356481, 34.772121 ], "pop" : 25217, "state" : "AR" }
+{ "_id" : "72208", "city" : "FERNDALE", "loc" : [ -92.585581, 34.781575 ], "pop" : 458, "state" : "AR" }
+{ "_id" : "72209", "city" : "LITTLE ROCK", "loc" : [ -92.352919, 34.672509 ], "pop" : 35211, "state" : "AR" }
+{ "_id" : "72210", "city" : "LITTLE ROCK", "loc" : [ -92.465981, 34.707625 ], "pop" : 4426, "state" : "AR" }
+{ "_id" : "72211", "city" : "LITTLE ROCK", "loc" : [ -92.431485, 34.758819 ], "pop" : 14006, "state" : "AR" }
+{ "_id" : "72212", "city" : "LITTLE ROCK", "loc" : [ -92.42223199999999, 34.787076 ], "pop" : 16183, "state" : "AR" }
+{ "_id" : "72301", "city" : "WEST MEMPHIS", "loc" : [ -90.17792, 35.148442 ], "pop" : 28720, "state" : "AR" }
+{ "_id" : "72310", "city" : "ARMOREL", "loc" : [ -89.758118, 35.942843 ], "pop" : 444, "state" : "AR" }
+{ "_id" : "72311", "city" : "AUBREY", "loc" : [ -90.911331, 34.702727 ], "pop" : 901, "state" : "AR" }
+{ "_id" : "72313", "city" : "BASSETT", "loc" : [ -90.192155, 35.513808 ], "pop" : 1147, "state" : "AR" }
+{ "_id" : "72314", "city" : "BIRDEYE", "loc" : [ -90.67074, 35.409571 ], "pop" : 505, "state" : "AR" }
+{ "_id" : "72315", "city" : "BLYTHEVILLE A F", "loc" : [ -89.92249700000001, 35.934482 ], "pop" : 30944, "state" : "AR" }
+{ "_id" : "72320", "city" : "BRICKEYS", "loc" : [ -90.537738, 34.854814 ], "pop" : 458, "state" : "AR" }
+{ "_id" : "72321", "city" : "BURDETTE", "loc" : [ -89.942312, 35.814769 ], "pop" : 329, "state" : "AR" }
+{ "_id" : "72324", "city" : "CHERRY VALLEY", "loc" : [ -90.761329, 35.399122 ], "pop" : 1273, "state" : "AR" }
+{ "_id" : "72326", "city" : "COLT", "loc" : [ -90.787204, 35.096062 ], "pop" : 3755, "state" : "AR" }
+{ "_id" : "72327", "city" : "CRAWFORDSVILLE", "loc" : [ -90.33510699999999, 35.211873 ], "pop" : 1834, "state" : "AR" }
+{ "_id" : "72328", "city" : "CRUMROD", "loc" : [ -90.949535, 34.216167 ], "pop" : 514, "state" : "AR" }
+{ "_id" : "72329", "city" : "DRIVER", "loc" : [ -89.960526, 35.559714 ], "pop" : 25, "state" : "AR" }
+{ "_id" : "72330", "city" : "DYESS", "loc" : [ -90.215716, 35.595394 ], "pop" : 912, "state" : "AR" }
+{ "_id" : "72331", "city" : "EARLE", "loc" : [ -90.450261, 35.27989 ], "pop" : 5009, "state" : "AR" }
+{ "_id" : "72332", "city" : "EDMONDSON", "loc" : [ -90.328672, 35.022309 ], "pop" : 2435, "state" : "AR" }
+{ "_id" : "72333", "city" : "ELAINE", "loc" : [ -90.873485, 34.308668 ], "pop" : 1366, "state" : "AR" }
+{ "_id" : "72335", "city" : "FORREST CITY", "loc" : [ -90.788572, 35.009129 ], "pop" : 17751, "state" : "AR" }
+{ "_id" : "72338", "city" : "FRENCHMANS BAYOU", "loc" : [ -90.055933, 35.478419 ], "pop" : 34, "state" : "AR" }
+{ "_id" : "72339", "city" : "GILMORE", "loc" : [ -90.264664, 35.386408 ], "pop" : 1852, "state" : "AR" }
+{ "_id" : "72340", "city" : "GOODWIN", "loc" : [ -90.983518, 34.959149 ], "pop" : 597, "state" : "AR" }
+{ "_id" : "72341", "city" : "HAYNES", "loc" : [ -90.766621, 34.883752 ], "pop" : 552, "state" : "AR" }
+{ "_id" : "72342", "city" : "HELENA", "loc" : [ -90.629784, 34.532491 ], "pop" : 9515, "state" : "AR" }
+{ "_id" : "72346", "city" : "HETH", "loc" : [ -90.45855400000001, 35.097335 ], "pop" : 859, "state" : "AR" }
+{ "_id" : "72347", "city" : "HICKORY RIDGE", "loc" : [ -90.982283, 35.399457 ], "pop" : 754, "state" : "AR" }
+{ "_id" : "72348", "city" : "HUGHES", "loc" : [ -90.474142, 34.945416 ], "pop" : 2477, "state" : "AR" }
+{ "_id" : "72350", "city" : "JOINER", "loc" : [ -90.14779, 35.505239 ], "pop" : 986, "state" : "AR" }
+{ "_id" : "72351", "city" : "KEISER", "loc" : [ -90.096171, 35.678626 ], "pop" : 980, "state" : "AR" }
+{ "_id" : "72354", "city" : "LEPANTO", "loc" : [ -90.335883, 35.606909 ], "pop" : 2023, "state" : "AR" }
+{ "_id" : "72355", "city" : "LEXA", "loc" : [ -90.78532, 34.672694 ], "pop" : 903, "state" : "AR" }
+{ "_id" : "72358", "city" : "LUXORA", "loc" : [ -89.92204, 35.760786 ], "pop" : 1593, "state" : "AR" }
+{ "_id" : "72360", "city" : "MARIANNA", "loc" : [ -90.77852, 34.775929 ], "pop" : 8668, "state" : "AR" }
+{ "_id" : "72364", "city" : "MARION", "loc" : [ -90.198908, 35.2077 ], "pop" : 7891, "state" : "AR" }
+{ "_id" : "72365", "city" : "MARKED TREE", "loc" : [ -90.419387, 35.534933 ], "pop" : 5144, "state" : "AR" }
+{ "_id" : "72366", "city" : "MARVELL", "loc" : [ -90.941322, 34.548541 ], "pop" : 2733, "state" : "AR" }
+{ "_id" : "72367", "city" : "MELLWOOD", "loc" : [ -91.008589, 34.220032 ], "pop" : 61, "state" : "AR" }
+{ "_id" : "72368", "city" : "MORO", "loc" : [ -91.00602600000001, 34.802953 ], "pop" : 1571, "state" : "AR" }
+{ "_id" : "72369", "city" : "ONEIDA", "loc" : [ -90.82604499999999, 34.405267 ], "pop" : 918, "state" : "AR" }
+{ "_id" : "72370", "city" : "OSCEOLA", "loc" : [ -89.979764, 35.701864 ], "pop" : 10119, "state" : "AR" }
+{ "_id" : "72372", "city" : "PALESTINE", "loc" : [ -90.904929, 34.966346 ], "pop" : 1371, "state" : "AR" }
+{ "_id" : "72373", "city" : "PARKIN", "loc" : [ -90.556417, 35.258557 ], "pop" : 2437, "state" : "AR" }
+{ "_id" : "72374", "city" : "POPLAR GROVE", "loc" : [ -90.881274, 34.539397 ], "pop" : 1466, "state" : "AR" }
+{ "_id" : "72376", "city" : "PROCTOR", "loc" : [ -90.255026, 35.083396 ], "pop" : 953, "state" : "AR" }
+{ "_id" : "72379", "city" : "SNOW LAKE", "loc" : [ -91.00708299999999, 34.066466 ], "pop" : 225, "state" : "AR" }
+{ "_id" : "72381", "city" : "TOMATO", "loc" : [ -89.787092, 35.806666 ], "pop" : 0, "state" : "AR" }
+{ "_id" : "72384", "city" : "TURRELL", "loc" : [ -90.262979, 35.296936 ], "pop" : 1308, "state" : "AR" }
+{ "_id" : "72386", "city" : "TYRONZA", "loc" : [ -90.351944, 35.486477 ], "pop" : 1230, "state" : "AR" }
+{ "_id" : "72390", "city" : "WEST HELENA", "loc" : [ -90.65453100000001, 34.549635 ], "pop" : 12265, "state" : "AR" }
+{ "_id" : "72392", "city" : "WHEATLEY", "loc" : [ -91.108645, 34.920703 ], "pop" : 542, "state" : "AR" }
+{ "_id" : "72394", "city" : "WIDENER", "loc" : [ -90.629313, 35.059167 ], "pop" : 1145, "state" : "AR" }
+{ "_id" : "72395", "city" : "WILSON", "loc" : [ -90.042749, 35.566004 ], "pop" : 1185, "state" : "AR" }
+{ "_id" : "72396", "city" : "WYNNE", "loc" : [ -90.79303, 35.233036 ], "pop" : 13908, "state" : "AR" }
+{ "_id" : "72397", "city" : "FAIR OAKS", "loc" : [ -91.014304, 35.236817 ], "pop" : 285, "state" : "AR" }
+{ "_id" : "72401", "city" : "JONESBORO", "loc" : [ -90.69652600000001, 35.833016 ], "pop" : 53532, "state" : "AR" }
+{ "_id" : "72410", "city" : "ALICIA", "loc" : [ -91.081003, 35.942327 ], "pop" : 725, "state" : "AR" }
+{ "_id" : "72411", "city" : "BAY", "loc" : [ -90.550658, 35.74559 ], "pop" : 2527, "state" : "AR" }
+{ "_id" : "72412", "city" : "BEECH GROVE", "loc" : [ -90.618084, 36.183172 ], "pop" : 292, "state" : "AR" }
+{ "_id" : "72413", "city" : "BIGGERS", "loc" : [ -90.78446700000001, 36.342978 ], "pop" : 1060, "state" : "AR" }
+{ "_id" : "72414", "city" : "BLACK OAK", "loc" : [ -90.35422699999999, 35.835851 ], "pop" : 518, "state" : "AR" }
+{ "_id" : "72415", "city" : "BLACK ROCK", "loc" : [ -91.11762899999999, 36.114874 ], "pop" : 1190, "state" : "AR" }
+{ "_id" : "72416", "city" : "BONO", "loc" : [ -90.78475299999999, 35.908592 ], "pop" : 3030, "state" : "AR" }
+{ "_id" : "72417", "city" : "BROOKLAND", "loc" : [ -90.576228, 35.91647 ], "pop" : 1896, "state" : "AR" }
+{ "_id" : "72419", "city" : "CARAWAY", "loc" : [ -90.335797, 35.758951 ], "pop" : 2214, "state" : "AR" }
+{ "_id" : "72421", "city" : "CASH", "loc" : [ -90.941007, 35.830145 ], "pop" : 628, "state" : "AR" }
+{ "_id" : "72422", "city" : "CORNING", "loc" : [ -90.58702, 36.415532 ], "pop" : 5469, "state" : "AR" }
+{ "_id" : "72424", "city" : "DATTO", "loc" : [ -90.723117, 36.389685 ], "pop" : 308, "state" : "AR" }
+{ "_id" : "72425", "city" : "DELAPLAINE", "loc" : [ -90.734482, 36.199485 ], "pop" : 719, "state" : "AR" }
+{ "_id" : "72426", "city" : "DELL", "loc" : [ -90.035449, 35.850118 ], "pop" : 832, "state" : "AR" }
+{ "_id" : "72428", "city" : "ETOWAH", "loc" : [ -90.218172, 35.714707 ], "pop" : 1330, "state" : "AR" }
+{ "_id" : "72429", "city" : "FISHER", "loc" : [ -90.955001, 35.513956 ], "pop" : 907, "state" : "AR" }
+{ "_id" : "72430", "city" : "GREENWAY", "loc" : [ -90.225257, 36.334766 ], "pop" : 529, "state" : "AR" }
+{ "_id" : "72432", "city" : "HARRISBURG", "loc" : [ -90.70375199999999, 35.572222 ], "pop" : 5961, "state" : "AR" }
+{ "_id" : "72433", "city" : "HOXIE", "loc" : [ -90.971504, 36.032573 ], "pop" : 3436, "state" : "AR" }
+{ "_id" : "72434", "city" : "IMBODEN", "loc" : [ -91.18544199999999, 36.19763 ], "pop" : 889, "state" : "AR" }
+{ "_id" : "72435", "city" : "KNOBEL", "loc" : [ -90.599048, 36.317647 ], "pop" : 518, "state" : "AR" }
+{ "_id" : "72436", "city" : "LAFE", "loc" : [ -90.506973, 36.21547 ], "pop" : 1007, "state" : "AR" }
+{ "_id" : "72437", "city" : "LAKE CITY", "loc" : [ -90.44232700000001, 35.81715 ], "pop" : 2056, "state" : "AR" }
+{ "_id" : "72438", "city" : "LEACHVILLE", "loc" : [ -90.195488, 35.933216 ], "pop" : 2810, "state" : "AR" }
+{ "_id" : "72440", "city" : "LYNN", "loc" : [ -91.254588, 36.016639 ], "pop" : 1032, "state" : "AR" }
+{ "_id" : "72441", "city" : "MC DOUGAL", "loc" : [ -90.394093, 36.379909 ], "pop" : 1552, "state" : "AR" }
+{ "_id" : "72442", "city" : "ROSELAND", "loc" : [ -90.180252, 35.874885 ], "pop" : 3855, "state" : "AR" }
+{ "_id" : "72443", "city" : "MARMADUKE", "loc" : [ -90.38368, 36.195117 ], "pop" : 2082, "state" : "AR" }
+{ "_id" : "72444", "city" : "MAYNARD", "loc" : [ -90.874921, 36.438563 ], "pop" : 1616, "state" : "AR" }
+{ "_id" : "72445", "city" : "MINTURN", "loc" : [ -91.033704, 35.976096 ], "pop" : 364, "state" : "AR" }
+{ "_id" : "72447", "city" : "MONETTE", "loc" : [ -90.343658, 35.900168 ], "pop" : 2008, "state" : "AR" }
+{ "_id" : "72449", "city" : "O KEAN", "loc" : [ -90.82406899999999, 36.179672 ], "pop" : 420, "state" : "AR" }
+{ "_id" : "72450", "city" : "PARAGOULD", "loc" : [ -90.525093, 36.060033 ], "pop" : 27704, "state" : "AR" }
+{ "_id" : "72453", "city" : "PEACH ORCHARD", "loc" : [ -90.67021699999999, 36.283045 ], "pop" : 332, "state" : "AR" }
+{ "_id" : "72454", "city" : "PIGGOTT", "loc" : [ -90.19261, 36.386993 ], "pop" : 4818, "state" : "AR" }
+{ "_id" : "72455", "city" : "POCAHONTAS", "loc" : [ -90.996782, 36.282876 ], "pop" : 12280, "state" : "AR" }
+{ "_id" : "72456", "city" : "POLLARD", "loc" : [ -90.27512299999999, 36.431725 ], "pop" : 553, "state" : "AR" }
+{ "_id" : "72457", "city" : "PORTIA", "loc" : [ -91.068004, 36.080699 ], "pop" : 646, "state" : "AR" }
+{ "_id" : "72458", "city" : "POWHATAN", "loc" : [ -91.148214, 36.080044 ], "pop" : 476, "state" : "AR" }
+{ "_id" : "72459", "city" : "RAVENDEN", "loc" : [ -91.25933999999999, 36.202863 ], "pop" : 1137, "state" : "AR" }
+{ "_id" : "72460", "city" : "RAVENDEN SPRINGS", "loc" : [ -91.209433, 36.310384 ], "pop" : 944, "state" : "AR" }
+{ "_id" : "72461", "city" : "RECTOR", "loc" : [ -90.270201, 36.267177 ], "pop" : 3515, "state" : "AR" }
+{ "_id" : "72464", "city" : "SAINT FRANCIS", "loc" : [ -90.144991, 36.454771 ], "pop" : 227, "state" : "AR" }
+{ "_id" : "72465", "city" : "SEDGWICK", "loc" : [ -90.880099, 35.985965 ], "pop" : 503, "state" : "AR" }
+{ "_id" : "72466", "city" : "SMITHVILLE", "loc" : [ -91.274456, 36.090815 ], "pop" : 427, "state" : "AR" }
+{ "_id" : "72467", "city" : "STATE UNIVERSITY", "loc" : [ -90.454245, 35.914894 ], "pop" : 544, "state" : "AR" }
+{ "_id" : "72469", "city" : "CALAMINE", "loc" : [ -91.375398, 35.972622 ], "pop" : 1078, "state" : "AR" }
+{ "_id" : "72470", "city" : "SUCCESS", "loc" : [ -90.728128, 36.453615 ], "pop" : 286, "state" : "AR" }
+{ "_id" : "72471", "city" : "SWIFTON", "loc" : [ -91.126358, 35.827366 ], "pop" : 1172, "state" : "AR" }
+{ "_id" : "72472", "city" : "PAYNEWAY", "loc" : [ -90.518738, 35.668914 ], "pop" : 8179, "state" : "AR" }
+{ "_id" : "72473", "city" : "TUCKERMAN", "loc" : [ -91.20034699999999, 35.730678 ], "pop" : 2564, "state" : "AR" }
+{ "_id" : "72476", "city" : "COLLEGE CITY", "loc" : [ -90.952809, 36.077814 ], "pop" : 5794, "state" : "AR" }
+{ "_id" : "72478", "city" : "WARM SPRINGS", "loc" : [ -91.038707, 36.467531 ], "pop" : 238, "state" : "AR" }
+{ "_id" : "72479", "city" : "WEINER", "loc" : [ -90.928928, 35.629052 ], "pop" : 1223, "state" : "AR" }
+{ "_id" : "72482", "city" : "WILLIFORD", "loc" : [ -91.379226, 36.245335 ], "pop" : 349, "state" : "AR" }
+{ "_id" : "72501", "city" : "BATESVILLE", "loc" : [ -91.63518999999999, 35.782614 ], "pop" : 19976, "state" : "AR" }
+{ "_id" : "72512", "city" : "HORSESHOE BEND", "loc" : [ -91.755334, 36.202502 ], "pop" : 3088, "state" : "AR" }
+{ "_id" : "72513", "city" : "AGNOS", "loc" : [ -91.61074600000001, 36.219732 ], "pop" : 1433, "state" : "AR" }
+{ "_id" : "72515", "city" : "BEXAR", "loc" : [ -91.985998, 36.306103 ], "pop" : 325, "state" : "AR" }
+{ "_id" : "72516", "city" : "BOSWELL", "loc" : [ -92.044307, 36.01084 ], "pop" : 321, "state" : "AR" }
+{ "_id" : "72517", "city" : "BROCKWELL", "loc" : [ -91.951308, 36.135755 ], "pop" : 548, "state" : "AR" }
+{ "_id" : "72519", "city" : "JORDAN", "loc" : [ -92.145494, 36.144771 ], "pop" : 2019, "state" : "AR" }
+{ "_id" : "72520", "city" : "CAMP", "loc" : [ -91.72616600000001, 36.402531 ], "pop" : 401, "state" : "AR" }
+{ "_id" : "72521", "city" : "CAVE CITY", "loc" : [ -91.544432, 35.951684 ], "pop" : 2111, "state" : "AR" }
+{ "_id" : "72522", "city" : "CHARLOTTE", "loc" : [ -91.39621699999999, 35.833393 ], "pop" : 797, "state" : "AR" }
+{ "_id" : "72523", "city" : "CONCORD", "loc" : [ -91.833339, 35.641355 ], "pop" : 1168, "state" : "AR" }
+{ "_id" : "72524", "city" : "CORD", "loc" : [ -91.33745500000001, 35.81844 ], "pop" : 205, "state" : "AR" }
+{ "_id" : "72526", "city" : "CUSHMAN", "loc" : [ -91.776455, 35.869663 ], "pop" : 336, "state" : "AR" }
+{ "_id" : "72527", "city" : "DESHA", "loc" : [ -91.678287, 35.731524 ], "pop" : 876, "state" : "AR" }
+{ "_id" : "72528", "city" : "DOLPH", "loc" : [ -92.11766, 36.222878 ], "pop" : 348, "state" : "AR" }
+{ "_id" : "72529", "city" : "CHEROKEE VILLAGE", "loc" : [ -91.528075, 36.30114 ], "pop" : 4523, "state" : "AR" }
+{ "_id" : "72530", "city" : "DRASCO", "loc" : [ -91.939818, 35.661606 ], "pop" : 886, "state" : "AR" }
+{ "_id" : "72531", "city" : "ELIZABETH", "loc" : [ -92.093366, 36.323776 ], "pop" : 390, "state" : "AR" }
+{ "_id" : "72532", "city" : "EVENING SHADE", "loc" : [ -91.59801400000001, 36.085532 ], "pop" : 1356, "state" : "AR" }
+{ "_id" : "72533", "city" : "FIFTY SIX", "loc" : [ -92.218169, 35.991958 ], "pop" : 346, "state" : "AR" }
+{ "_id" : "72534", "city" : "FLORAL", "loc" : [ -91.734101, 35.602337 ], "pop" : 940, "state" : "AR" }
+{ "_id" : "72536", "city" : "FRANKLIN", "loc" : [ -91.80959199999999, 36.129093 ], "pop" : 364, "state" : "AR" }
+{ "_id" : "72537", "city" : "GAMALIEL", "loc" : [ -92.228447, 36.461794 ], "pop" : 301, "state" : "AR" }
+{ "_id" : "72538", "city" : "GEPP", "loc" : [ -92.099507, 36.436443 ], "pop" : 351, "state" : "AR" }
+{ "_id" : "72539", "city" : "GLENCOE", "loc" : [ -91.76948299999999, 36.288962 ], "pop" : 514, "state" : "AR" }
+{ "_id" : "72540", "city" : "GUION", "loc" : [ -91.934287, 35.960135 ], "pop" : 226, "state" : "AR" }
+{ "_id" : "72542", "city" : "HARDY", "loc" : [ -91.411027, 36.322746 ], "pop" : 2473, "state" : "AR" }
+{ "_id" : "72543", "city" : "HEBER SPRINGS", "loc" : [ -92.03921099999999, 35.510278 ], "pop" : 8709, "state" : "AR" }
+{ "_id" : "72544", "city" : "HENDERSON", "loc" : [ -92.26925300000001, 36.356829 ], "pop" : 3441, "state" : "AR" }
+{ "_id" : "72546", "city" : "IDA", "loc" : [ -91.930081, 35.594326 ], "pop" : 539, "state" : "AR" }
+{ "_id" : "72550", "city" : "LOCUST GROVE", "loc" : [ -91.741443, 35.717705 ], "pop" : 750, "state" : "AR" }
+{ "_id" : "72553", "city" : "MAGNESS", "loc" : [ -91.485041, 35.710062 ], "pop" : 413, "state" : "AR" }
+{ "_id" : "72554", "city" : "MAMMOTH SPRING", "loc" : [ -91.575712, 36.407648 ], "pop" : 4075, "state" : "AR" }
+{ "_id" : "72555", "city" : "MARCELLA", "loc" : [ -91.941891, 35.749654 ], "pop" : 535, "state" : "AR" }
+{ "_id" : "72556", "city" : "ZION", "loc" : [ -91.905196, 36.059958 ], "pop" : 1880, "state" : "AR" }
+{ "_id" : "72557", "city" : "MOKO", "loc" : [ -91.85866300000001, 36.468902 ], "pop" : 321, "state" : "AR" }
+{ "_id" : "72560", "city" : "HANOVER", "loc" : [ -92.114762, 35.865769 ], "pop" : 5553, "state" : "AR" }
+{ "_id" : "72561", "city" : "MOUNT PLEASANT", "loc" : [ -91.78501300000001, 35.975909 ], "pop" : 1264, "state" : "AR" }
+{ "_id" : "72562", "city" : "NEWARK", "loc" : [ -91.439395, 35.71183 ], "pop" : 1816, "state" : "AR" }
+{ "_id" : "72564", "city" : "OIL TROUGH", "loc" : [ -91.470305, 35.613147 ], "pop" : 674, "state" : "AR" }
+{ "_id" : "72565", "city" : "OXFORD", "loc" : [ -91.925849, 36.211408 ], "pop" : 738, "state" : "AR" }
+{ "_id" : "72566", "city" : "PINEVILLE", "loc" : [ -92.107299, 36.167704 ], "pop" : 356, "state" : "AR" }
+{ "_id" : "72567", "city" : "PLEASANT GROVE", "loc" : [ -91.931905, 35.842349 ], "pop" : 772, "state" : "AR" }
+{ "_id" : "72568", "city" : "PLEASANT PLAINS", "loc" : [ -91.632043, 35.589301 ], "pop" : 1790, "state" : "AR" }
+{ "_id" : "72569", "city" : "POUGHKEEPSIE", "loc" : [ -91.45157500000001, 36.071526 ], "pop" : 601, "state" : "AR" }
+{ "_id" : "72571", "city" : "ROSIE", "loc" : [ -91.534003, 35.663816 ], "pop" : 438, "state" : "AR" }
+{ "_id" : "72572", "city" : "SAFFELL", "loc" : [ -91.297753, 35.917957 ], "pop" : 379, "state" : "AR" }
+{ "_id" : "72573", "city" : "SAGE", "loc" : [ -91.824569, 36.042476 ], "pop" : 256, "state" : "AR" }
+{ "_id" : "72575", "city" : "SALADO", "loc" : [ -91.59792400000001, 35.703493 ], "pop" : 818, "state" : "AR" }
+{ "_id" : "72576", "city" : "BYRON", "loc" : [ -91.836321, 36.365401 ], "pop" : 2561, "state" : "AR" }
+{ "_id" : "72577", "city" : "SIDNEY", "loc" : [ -91.634593, 35.991554 ], "pop" : 743, "state" : "AR" }
+{ "_id" : "72578", "city" : "STURKIE", "loc" : [ -91.98991700000001, 36.463869 ], "pop" : 168, "state" : "AR" }
+{ "_id" : "72579", "city" : "SULPHUR ROCK", "loc" : [ -91.507333, 35.754466 ], "pop" : 756, "state" : "AR" }
+{ "_id" : "72581", "city" : "TUMBLING SHOALS", "loc" : [ -91.970359, 35.546985 ], "pop" : 768, "state" : "AR" }
+{ "_id" : "72583", "city" : "VIOLA", "loc" : [ -91.99319800000001, 36.392429 ], "pop" : 823, "state" : "AR" }
+{ "_id" : "72584", "city" : "VIOLET HILL", "loc" : [ -91.847064, 36.162966 ], "pop" : 220, "state" : "AR" }
+{ "_id" : "72585", "city" : "WIDEMAN", "loc" : [ -92.001796, 36.198739 ], "pop" : 89, "state" : "AR" }
+{ "_id" : "72587", "city" : "WISEMAN", "loc" : [ -91.84949899999999, 36.228022 ], "pop" : 26, "state" : "AR" }
+{ "_id" : "72601", "city" : "HARRISON", "loc" : [ -93.106162, 36.241707 ], "pop" : 23009, "state" : "AR" }
+{ "_id" : "72610", "city" : "ALCO", "loc" : [ -92.380753, 35.894511 ], "pop" : 172, "state" : "AR" }
+{ "_id" : "72611", "city" : "ALPENA", "loc" : [ -93.2792, 36.299768 ], "pop" : 780, "state" : "AR" }
+{ "_id" : "72612", "city" : "BASS", "loc" : [ -92.999832, 35.892225 ], "pop" : 261, "state" : "AR" }
+{ "_id" : "72616", "city" : "BERRYVILLE", "loc" : [ -93.558725, 36.351908 ], "pop" : 6821, "state" : "AR" }
+{ "_id" : "72617", "city" : "BIG FLAT", "loc" : [ -92.39168100000001, 36.006824 ], "pop" : 244, "state" : "AR" }
+{ "_id" : "72618", "city" : "BRUNO", "loc" : [ -92.763651, 36.124617 ], "pop" : 236, "state" : "AR" }
+{ "_id" : "72619", "city" : "BULL SHOALS", "loc" : [ -92.593765, 36.370958 ], "pop" : 1967, "state" : "AR" }
+{ "_id" : "72623", "city" : "CLARKRIDGE", "loc" : [ -92.35159, 36.443311 ], "pop" : 1031, "state" : "AR" }
+{ "_id" : "72624", "city" : "COMPTON", "loc" : [ -93.30990300000001, 36.097941 ], "pop" : 233, "state" : "AR" }
+{ "_id" : "72626", "city" : "COTTER", "loc" : [ -92.532787, 36.280378 ], "pop" : 1044, "state" : "AR" }
+{ "_id" : "72628", "city" : "DEER", "loc" : [ -93.31738799999999, 35.852982 ], "pop" : 1378, "state" : "AR" }
+{ "_id" : "72629", "city" : "DENNARD", "loc" : [ -92.557456, 35.725236 ], "pop" : 1370, "state" : "AR" }
+{ "_id" : "72632", "city" : "EUREKA SPRINGS", "loc" : [ -93.737915, 36.417465 ], "pop" : 5444, "state" : "AR" }
+{ "_id" : "72633", "city" : "EVERTON", "loc" : [ -92.91498900000001, 36.153366 ], "pop" : 436, "state" : "AR" }
+{ "_id" : "72634", "city" : "FLIPPIN", "loc" : [ -92.577995, 36.268219 ], "pop" : 2784, "state" : "AR" }
+{ "_id" : "72635", "city" : "GASSVILLE", "loc" : [ -92.473637, 36.317525 ], "pop" : 3568, "state" : "AR" }
+{ "_id" : "72638", "city" : "GREEN FOREST", "loc" : [ -93.40587499999999, 36.322408 ], "pop" : 5430, "state" : "AR" }
+{ "_id" : "72639", "city" : "HARRIET", "loc" : [ -92.50055, 35.974187 ], "pop" : 950, "state" : "AR" }
+{ "_id" : "72640", "city" : "HASTY", "loc" : [ -93.04596600000001, 36.015229 ], "pop" : 219, "state" : "AR" }
+{ "_id" : "72641", "city" : "JASPER", "loc" : [ -93.20477099999999, 36.003798 ], "pop" : 1632, "state" : "AR" }
+{ "_id" : "72642", "city" : "LAKEVIEW", "loc" : [ -92.50441600000001, 36.397308 ], "pop" : 2815, "state" : "AR" }
+{ "_id" : "72644", "city" : "LEAD HILL", "loc" : [ -92.930194, 36.430886 ], "pop" : 1818, "state" : "AR" }
+{ "_id" : "72645", "city" : "LESLIE", "loc" : [ -92.566293, 35.82716 ], "pop" : 1768, "state" : "AR" }
+{ "_id" : "72648", "city" : "DOGPATCH", "loc" : [ -93.144822, 36.095121 ], "pop" : 608, "state" : "AR" }
+{ "_id" : "72650", "city" : "MARSHALL", "loc" : [ -92.640203, 35.926697 ], "pop" : 2882, "state" : "AR" }
+{ "_id" : "72651", "city" : "MIDWAY", "loc" : [ -92.431398, 36.290454 ], "pop" : 408, "state" : "AR" }
+{ "_id" : "72653", "city" : "MOUNTAIN HOME", "loc" : [ -92.375337, 36.331153 ], "pop" : 16131, "state" : "AR" }
+{ "_id" : "72655", "city" : "MOUNT JUDEA", "loc" : [ -93.082391, 35.834674 ], "pop" : 665, "state" : "AR" }
+{ "_id" : "72657", "city" : "TIMBO", "loc" : [ -92.25253600000001, 35.896338 ], "pop" : 596, "state" : "AR" }
+{ "_id" : "72658", "city" : "NORFORK", "loc" : [ -92.273011, 36.206571 ], "pop" : 1824, "state" : "AR" }
+{ "_id" : "72660", "city" : "OAK GROVE", "loc" : [ -93.432129, 36.461347 ], "pop" : 956, "state" : "AR" }
+{ "_id" : "72661", "city" : "OAKLAND", "loc" : [ -92.583187, 36.444227 ], "pop" : 544, "state" : "AR" }
+{ "_id" : "72662", "city" : "OMAHA", "loc" : [ -93.18875300000001, 36.46123 ], "pop" : 1251, "state" : "AR" }
+{ "_id" : "72663", "city" : "ONIA", "loc" : [ -92.345859, 35.940339 ], "pop" : 444, "state" : "AR" }
+{ "_id" : "72666", "city" : "PARTHENON", "loc" : [ -93.267776, 35.940836 ], "pop" : 518, "state" : "AR" }
+{ "_id" : "72668", "city" : "PEEL", "loc" : [ -92.776143, 36.444374 ], "pop" : 731, "state" : "AR" }
+{ "_id" : "72669", "city" : "PINDALL", "loc" : [ -92.886409, 36.067479 ], "pop" : 499, "state" : "AR" }
+{ "_id" : "72670", "city" : "PONCA", "loc" : [ -93.401985, 36.066225 ], "pop" : 435, "state" : "AR" }
+{ "_id" : "72675", "city" : "SAINT JOE", "loc" : [ -92.792828, 35.987707 ], "pop" : 1196, "state" : "AR" }
+{ "_id" : "72679", "city" : "TILLY", "loc" : [ -92.84420900000001, 35.6976 ], "pop" : 118, "state" : "AR" }
+{ "_id" : "72680", "city" : "NEWNATA", "loc" : [ -92.337929, 35.855318 ], "pop" : 397, "state" : "AR" }
+{ "_id" : "72682", "city" : "VALLEY SPRINGS", "loc" : [ -92.97993700000001, 36.146823 ], "pop" : 1050, "state" : "AR" }
+{ "_id" : "72683", "city" : "VENDOR", "loc" : [ -93.100815, 35.948062 ], "pop" : 784, "state" : "AR" }
+{ "_id" : "72685", "city" : "WESTERN GROVE", "loc" : [ -92.971649, 36.082994 ], "pop" : 933, "state" : "AR" }
+{ "_id" : "72686", "city" : "WITTS SPRINGS", "loc" : [ -92.815518, 35.785514 ], "pop" : 546, "state" : "AR" }
+{ "_id" : "72687", "city" : "YELLVILLE", "loc" : [ -92.72447200000001, 36.225322 ], "pop" : 5695, "state" : "AR" }
+{ "_id" : "72701", "city" : "FAYETTEVILLE", "loc" : [ -94.153395, 36.052045 ], "pop" : 28372, "state" : "AR" }
+{ "_id" : "72703", "city" : "FAYETTEVILLE", "loc" : [ -94.17162999999999, 36.099183 ], "pop" : 24649, "state" : "AR" }
+{ "_id" : "72712", "city" : "BENTONVILLE", "loc" : [ -94.22242, 36.357703 ], "pop" : 14439, "state" : "AR" }
+{ "_id" : "72714", "city" : "BELLA VISTA", "loc" : [ -94.251969, 36.465086 ], "pop" : 8645, "state" : "AR" }
+{ "_id" : "72716", "city" : "WAL-MART INC", "loc" : [ -94.181483, 36.326554 ], "pop" : 459, "state" : "AR" }
+{ "_id" : "72717", "city" : "CANEHILL", "loc" : [ -94.3862, 35.910992 ], "pop" : 781, "state" : "AR" }
+{ "_id" : "72718", "city" : "CAVE SPRINGS", "loc" : [ -94.207836, 36.266771 ], "pop" : 1629, "state" : "AR" }
+{ "_id" : "72719", "city" : "CENTERTON", "loc" : [ -94.30891, 36.366993 ], "pop" : 1797, "state" : "AR" }
+{ "_id" : "72721", "city" : "COMBS", "loc" : [ -93.82521800000001, 35.848297 ], "pop" : 491, "state" : "AR" }
+{ "_id" : "72722", "city" : "DECATUR", "loc" : [ -94.453411, 36.334749 ], "pop" : 1633, "state" : "AR" }
+{ "_id" : "72727", "city" : "ELKINS", "loc" : [ -94.007323, 36.017719 ], "pop" : 1767, "state" : "AR" }
+{ "_id" : "72729", "city" : "EVANSVILLE", "loc" : [ -94.478936, 35.819345 ], "pop" : 380, "state" : "AR" }
+{ "_id" : "72730", "city" : "FARMINGTON", "loc" : [ -94.253871, 36.043635 ], "pop" : 3495, "state" : "AR" }
+{ "_id" : "72732", "city" : "GARFIELD", "loc" : [ -93.95119699999999, 36.428817 ], "pop" : 1389, "state" : "AR" }
+{ "_id" : "72733", "city" : "GATEWAY", "loc" : [ -93.935016, 36.485751 ], "pop" : 581, "state" : "AR" }
+{ "_id" : "72734", "city" : "GENTRY", "loc" : [ -94.475131, 36.26516 ], "pop" : 5145, "state" : "AR" }
+{ "_id" : "72735", "city" : "GOSHEN", "loc" : [ -93.987262, 36.107523 ], "pop" : 1639, "state" : "AR" }
+{ "_id" : "72736", "city" : "GRAVETTE", "loc" : [ -94.477862, 36.415513 ], "pop" : 3508, "state" : "AR" }
+{ "_id" : "72738", "city" : "HINDSVILLE", "loc" : [ -93.863339, 36.142206 ], "pop" : 1024, "state" : "AR" }
+{ "_id" : "72739", "city" : "HIWASSE", "loc" : [ -94.338993, 36.441589 ], "pop" : 1188, "state" : "AR" }
+{ "_id" : "72740", "city" : "HUNTSVILLE", "loc" : [ -93.72789299999999, 36.104348 ], "pop" : 7021, "state" : "AR" }
+{ "_id" : "72742", "city" : "KINGSTON", "loc" : [ -93.504357, 36.04845 ], "pop" : 566, "state" : "AR" }
+{ "_id" : "72744", "city" : "LINCOLN", "loc" : [ -94.42724, 35.956931 ], "pop" : 3129, "state" : "AR" }
+{ "_id" : "72745", "city" : "LOWELL", "loc" : [ -94.082725, 36.243318 ], "pop" : 5077, "state" : "AR" }
+{ "_id" : "72747", "city" : "MAYSVILLE", "loc" : [ -94.581278, 36.401062 ], "pop" : 214, "state" : "AR" }
+{ "_id" : "72749", "city" : "MORROW", "loc" : [ -94.425793, 35.85373 ], "pop" : 615, "state" : "AR" }
+{ "_id" : "72751", "city" : "PEA RIDGE", "loc" : [ -94.118026, 36.453884 ], "pop" : 3584, "state" : "AR" }
+{ "_id" : "72752", "city" : "PETTIGREW", "loc" : [ -93.61807899999999, 35.834562 ], "pop" : 422, "state" : "AR" }
+{ "_id" : "72753", "city" : "PRAIRIE GROVE", "loc" : [ -94.316861, 35.991809 ], "pop" : 4105, "state" : "AR" }
+{ "_id" : "72756", "city" : "ROGERS", "loc" : [ -94.114784, 36.336316 ], "pop" : 34081, "state" : "AR" }
+{ "_id" : "72760", "city" : "SAINT PAUL", "loc" : [ -93.73474299999999, 35.849576 ], "pop" : 608, "state" : "AR" }
+{ "_id" : "72761", "city" : "SILOAM SPRINGS", "loc" : [ -94.528036, 36.179969 ], "pop" : 11677, "state" : "AR" }
+{ "_id" : "72762", "city" : "SPRINGDALE", "loc" : [ -94.176216, 36.183521 ], "pop" : 20104, "state" : "AR" }
+{ "_id" : "72764", "city" : "BETHEL HEIGHTS", "loc" : [ -94.104682, 36.177918 ], "pop" : 17792, "state" : "AR" }
+{ "_id" : "72768", "city" : "SULPHUR SPRINGS", "loc" : [ -94.45206899999999, 36.479434 ], "pop" : 982, "state" : "AR" }
+{ "_id" : "72769", "city" : "SUMMERS", "loc" : [ -94.500027, 36.013827 ], "pop" : 1013, "state" : "AR" }
+{ "_id" : "72773", "city" : "WESLEY", "loc" : [ -93.911478, 35.957264 ], "pop" : 1307, "state" : "AR" }
+{ "_id" : "72774", "city" : "WEST FORK", "loc" : [ -94.230375, 35.908153 ], "pop" : 4473, "state" : "AR" }
+{ "_id" : "72776", "city" : "WITTER", "loc" : [ -93.621, 35.935583 ], "pop" : 179, "state" : "AR" }
+{ "_id" : "72801", "city" : "RUSSELLVILLE", "loc" : [ -93.13147600000001, 35.284208 ], "pop" : 25169, "state" : "AR" }
+{ "_id" : "72820", "city" : "ALIX", "loc" : [ -93.726416, 35.430767 ], "pop" : 488, "state" : "AR" }
+{ "_id" : "72821", "city" : "ALTUS", "loc" : [ -93.811494, 35.404873 ], "pop" : 2292, "state" : "AR" }
+{ "_id" : "72823", "city" : "ATKINS", "loc" : [ -92.95069599999999, 35.244948 ], "pop" : 4835, "state" : "AR" }
+{ "_id" : "72824", "city" : "BELLEVILLE", "loc" : [ -93.45181700000001, 35.103762 ], "pop" : 988, "state" : "AR" }
+{ "_id" : "72826", "city" : "BLUE MOUNTAIN", "loc" : [ -93.716797, 35.130386 ], "pop" : 200, "state" : "AR" }
+{ "_id" : "72827", "city" : "BLUFFTON", "loc" : [ -93.59194599999999, 34.901635 ], "pop" : 208, "state" : "AR" }
+{ "_id" : "72828", "city" : "BRIGGSVILLE", "loc" : [ -93.515748, 34.916065 ], "pop" : 164, "state" : "AR" }
+{ "_id" : "72830", "city" : "CLARKSVILLE", "loc" : [ -93.491056, 35.490763 ], "pop" : 11304, "state" : "AR" }
+{ "_id" : "72832", "city" : "COAL HILL", "loc" : [ -93.67203000000001, 35.437117 ], "pop" : 1179, "state" : "AR" }
+{ "_id" : "72833", "city" : "DANVILLE", "loc" : [ -93.392933, 35.049541 ], "pop" : 3292, "state" : "AR" }
+{ "_id" : "72834", "city" : "DARDANELLE", "loc" : [ -93.187316, 35.195507 ], "pop" : 8281, "state" : "AR" }
+{ "_id" : "72835", "city" : "DELAWARE", "loc" : [ -93.346152, 35.278005 ], "pop" : 645, "state" : "AR" }
+{ "_id" : "72837", "city" : "DOVER", "loc" : [ -93.135526, 35.407356 ], "pop" : 5687, "state" : "AR" }
+{ "_id" : "72838", "city" : "GRAVELLY", "loc" : [ -93.680249, 34.888123 ], "pop" : 150, "state" : "AR" }
+{ "_id" : "72839", "city" : "HAGARVILLE", "loc" : [ -93.344256, 35.523291 ], "pop" : 584, "state" : "AR" }
+{ "_id" : "72840", "city" : "HARTMAN", "loc" : [ -93.61419600000001, 35.443583 ], "pop" : 846, "state" : "AR" }
+{ "_id" : "72841", "city" : "HARVEY", "loc" : [ -93.752538, 34.867912 ], "pop" : 243, "state" : "AR" }
+{ "_id" : "72842", "city" : "WAVELAND", "loc" : [ -93.576719, 35.111845 ], "pop" : 1294, "state" : "AR" }
+{ "_id" : "72843", "city" : "HECTOR", "loc" : [ -92.965559, 35.40574 ], "pop" : 5067, "state" : "AR" }
+{ "_id" : "72845", "city" : "KNOXVILLE", "loc" : [ -93.361797, 35.374897 ], "pop" : 848, "state" : "AR" }
+{ "_id" : "72846", "city" : "LAMAR", "loc" : [ -93.35515700000001, 35.434868 ], "pop" : 2905, "state" : "AR" }
+{ "_id" : "72847", "city" : "LONDON", "loc" : [ -93.238907, 35.337017 ], "pop" : 2396, "state" : "AR" }
+{ "_id" : "72851", "city" : "NEW BLAINE", "loc" : [ -93.44457, 35.318912 ], "pop" : 891, "state" : "AR" }
+{ "_id" : "72852", "city" : "OARK", "loc" : [ -93.558531, 35.709454 ], "pop" : 221, "state" : "AR" }
+{ "_id" : "72853", "city" : "OLA", "loc" : [ -93.21356, 35.03091 ], "pop" : 1823, "state" : "AR" }
+{ "_id" : "72854", "city" : "OZONE", "loc" : [ -93.43111, 35.657478 ], "pop" : 334, "state" : "AR" }
+{ "_id" : "72855", "city" : "PARIS", "loc" : [ -93.72646899999999, 35.294149 ], "pop" : 5718, "state" : "AR" }
+{ "_id" : "72856", "city" : "PELSOR", "loc" : [ -93.016088, 35.691158 ], "pop" : 117, "state" : "AR" }
+{ "_id" : "72857", "city" : "PLAINVIEW", "loc" : [ -93.30989700000001, 34.966793 ], "pop" : 1260, "state" : "AR" }
+{ "_id" : "72858", "city" : "POTTSVILLE", "loc" : [ -93.056386, 35.239785 ], "pop" : 2494, "state" : "AR" }
+{ "_id" : "72860", "city" : "ROVER", "loc" : [ -93.40172800000001, 34.947522 ], "pop" : 299, "state" : "AR" }
+{ "_id" : "72863", "city" : "SCRANTON", "loc" : [ -93.539362, 35.330816 ], "pop" : 1683, "state" : "AR" }
+{ "_id" : "72865", "city" : "SUBIACO", "loc" : [ -93.63869, 35.31346 ], "pop" : 1190, "state" : "AR" }
+{ "_id" : "72901", "city" : "FORT SMITH", "loc" : [ -94.411035, 35.365272 ], "pop" : 21722, "state" : "AR" }
+{ "_id" : "72903", "city" : "FORT SMITH", "loc" : [ -94.378361, 35.342673 ], "pop" : 32809, "state" : "AR" }
+{ "_id" : "72904", "city" : "FORT SMITH", "loc" : [ -94.38723, 35.405122 ], "pop" : 18559, "state" : "AR" }
+{ "_id" : "72905", "city" : "FORT CHAFFEE", "loc" : [ -94.340521, 35.297366 ], "pop" : 224, "state" : "AR" }
+{ "_id" : "72916", "city" : "FORT SMITH", "loc" : [ -94.37030799999999, 35.250175 ], "pop" : 3494, "state" : "AR" }
+{ "_id" : "72921", "city" : "ALMA", "loc" : [ -94.207337, 35.500043 ], "pop" : 7443, "state" : "AR" }
+{ "_id" : "72923", "city" : "BARLING", "loc" : [ -94.308226, 35.332963 ], "pop" : 3857, "state" : "AR" }
+{ "_id" : "72924", "city" : "BATES", "loc" : [ -94.39315499999999, 34.909295 ], "pop" : 213, "state" : "AR" }
+{ "_id" : "72926", "city" : "BOLES", "loc" : [ -94.062864, 34.765363 ], "pop" : 687, "state" : "AR" }
+{ "_id" : "72927", "city" : "BOONEVILLE", "loc" : [ -93.92743299999999, 35.136385 ], "pop" : 7502, "state" : "AR" }
+{ "_id" : "72928", "city" : "BRANCH", "loc" : [ -93.94537, 35.297055 ], "pop" : 597, "state" : "AR" }
+{ "_id" : "72930", "city" : "CECIL", "loc" : [ -93.942932, 35.434176 ], "pop" : 271, "state" : "AR" }
+{ "_id" : "72932", "city" : "CEDARVILLE", "loc" : [ -94.344618, 35.590231 ], "pop" : 1605, "state" : "AR" }
+{ "_id" : "72933", "city" : "CHARLESTON", "loc" : [ -94.03368, 35.311502 ], "pop" : 3173, "state" : "AR" }
+{ "_id" : "72934", "city" : "CHESTER", "loc" : [ -94.202026, 35.689776 ], "pop" : 1004, "state" : "AR" }
+{ "_id" : "72936", "city" : "GREENWOOD", "loc" : [ -94.253027, 35.195476 ], "pop" : 8385, "state" : "AR" }
+{ "_id" : "72937", "city" : "HACKETT", "loc" : [ -94.39832800000001, 35.194476 ], "pop" : 1587, "state" : "AR" }
+{ "_id" : "72938", "city" : "HARTFORD", "loc" : [ -94.38187600000001, 35.022233 ], "pop" : 1073, "state" : "AR" }
+{ "_id" : "72940", "city" : "HUNTINGTON", "loc" : [ -94.331283, 35.096267 ], "pop" : 2608, "state" : "AR" }
+{ "_id" : "72941", "city" : "CENTRAL CITY", "loc" : [ -94.165637, 35.337513 ], "pop" : 4138, "state" : "AR" }
+{ "_id" : "72943", "city" : "MAGAZINE", "loc" : [ -93.800336, 35.15873 ], "pop" : 1336, "state" : "AR" }
+{ "_id" : "72944", "city" : "MANSFIELD", "loc" : [ -94.22036, 35.0432 ], "pop" : 2607, "state" : "AR" }
+{ "_id" : "72946", "city" : "MOUNTAINBURG", "loc" : [ -94.109094, 35.570027 ], "pop" : 4762, "state" : "AR" }
+{ "_id" : "72947", "city" : "MULBERRY", "loc" : [ -93.988505, 35.517246 ], "pop" : 738, "state" : "AR" }
+{ "_id" : "72948", "city" : "NATURAL DAM", "loc" : [ -94.41237700000001, 35.674259 ], "pop" : 497, "state" : "AR" }
+{ "_id" : "72949", "city" : "OZARK", "loc" : [ -93.837423, 35.524645 ], "pop" : 7338, "state" : "AR" }
+{ "_id" : "72950", "city" : "PARKS", "loc" : [ -93.950913, 34.800333 ], "pop" : 471, "state" : "AR" }
+{ "_id" : "72951", "city" : "RATCLIFF", "loc" : [ -93.84214900000001, 35.276032 ], "pop" : 1392, "state" : "AR" }
+{ "_id" : "72952", "city" : "RUDY", "loc" : [ -94.237376, 35.539805 ], "pop" : 1753, "state" : "AR" }
+{ "_id" : "72955", "city" : "UNIONTOWN", "loc" : [ -94.43487, 35.574822 ], "pop" : 710, "state" : "AR" }
+{ "_id" : "72956", "city" : "VAN BUREN", "loc" : [ -94.32776200000001, 35.453989 ], "pop" : 24719, "state" : "AR" }
+{ "_id" : "72958", "city" : "WALDRON", "loc" : [ -94.077243, 34.902642 ], "pop" : 6884, "state" : "AR" }
+{ "_id" : "72959", "city" : "WINSLOW", "loc" : [ -94.118657, 35.831206 ], "pop" : 2566, "state" : "AR" }
+{ "_id" : "73002", "city" : "ALEX", "loc" : [ -97.75709000000001, 34.961202 ], "pop" : 1976, "state" : "OK" }
+{ "_id" : "73004", "city" : "AMBER", "loc" : [ -97.764566, 35.137691 ], "pop" : 2575, "state" : "OK" }
+{ "_id" : "73005", "city" : "ANADARKO", "loc" : [ -98.24290999999999, 35.072808 ], "pop" : 10332, "state" : "OK" }
+{ "_id" : "73006", "city" : "APACHE", "loc" : [ -98.369483, 34.903376 ], "pop" : 2969, "state" : "OK" }
+{ "_id" : "73007", "city" : "ARCADIA", "loc" : [ -97.32428899999999, 35.6543 ], "pop" : 697, "state" : "OK" }
+{ "_id" : "73008", "city" : "BETHANY", "loc" : [ -97.63985599999999, 35.504315 ], "pop" : 21064, "state" : "OK" }
+{ "_id" : "73009", "city" : "BINGER", "loc" : [ -98.314797, 35.310593 ], "pop" : 1799, "state" : "OK" }
+{ "_id" : "73010", "city" : "BLANCHARD", "loc" : [ -97.640131, 35.119215 ], "pop" : 4511, "state" : "OK" }
+{ "_id" : "73011", "city" : "BRADLEY", "loc" : [ -97.71184100000001, 34.874124 ], "pop" : 416, "state" : "OK" }
+{ "_id" : "73013", "city" : "EDMOND", "loc" : [ -97.473268, 35.621534 ], "pop" : 22802, "state" : "OK" }
+{ "_id" : "73014", "city" : "CALUMET", "loc" : [ -98.18999100000001, 35.594819 ], "pop" : 1507, "state" : "OK" }
+{ "_id" : "73015", "city" : "CARNEGIE", "loc" : [ -98.57545399999999, 35.123484 ], "pop" : 3907, "state" : "OK" }
+{ "_id" : "73016", "city" : "CASHION", "loc" : [ -97.679523, 35.799996 ], "pop" : 408, "state" : "OK" }
+{ "_id" : "73017", "city" : "CEMENT", "loc" : [ -98.14655999999999, 34.932092 ], "pop" : 1641, "state" : "OK" }
+{ "_id" : "73018", "city" : "CHICKASHA", "loc" : [ -97.951847, 35.026751 ], "pop" : 19634, "state" : "OK" }
+{ "_id" : "73020", "city" : "CHOCTAW", "loc" : [ -97.272564, 35.471758 ], "pop" : 13832, "state" : "OK" }
+{ "_id" : "73021", "city" : "COLONY", "loc" : [ -98.67067400000001, 35.344844 ], "pop" : 312, "state" : "OK" }
+{ "_id" : "73024", "city" : "CORN", "loc" : [ -98.806226, 35.399842 ], "pop" : 1156, "state" : "OK" }
+{ "_id" : "73027", "city" : "COYLE", "loc" : [ -97.260683, 35.898496 ], "pop" : 3054, "state" : "OK" }
+{ "_id" : "73028", "city" : "CRESCENT", "loc" : [ -97.59692200000001, 35.942 ], "pop" : 2832, "state" : "OK" }
+{ "_id" : "73029", "city" : "CYRIL", "loc" : [ -98.208269, 34.895854 ], "pop" : 1433, "state" : "OK" }
+{ "_id" : "73030", "city" : "DAVIS", "loc" : [ -97.10843, 34.495301 ], "pop" : 4823, "state" : "OK" }
+{ "_id" : "73034", "city" : "EDMOND", "loc" : [ -97.47983499999999, 35.666483 ], "pop" : 43814, "state" : "OK" }
+{ "_id" : "73035", "city" : "ELMORE CITY", "loc" : [ -97.39003, 34.608516 ], "pop" : 2520, "state" : "OK" }
+{ "_id" : "73036", "city" : "EL RENO", "loc" : [ -97.959091, 35.533468 ], "pop" : 18480, "state" : "OK" }
+{ "_id" : "73038", "city" : "FORT COBB", "loc" : [ -98.430296, 35.116097 ], "pop" : 1847, "state" : "OK" }
+{ "_id" : "73039", "city" : "FOSTER", "loc" : [ -97.533395, 34.627789 ], "pop" : 578, "state" : "OK" }
+{ "_id" : "73040", "city" : "GEARY", "loc" : [ -98.390529, 35.621709 ], "pop" : 2124, "state" : "OK" }
+{ "_id" : "73041", "city" : "GOTEBO", "loc" : [ -98.87597700000001, 35.075891 ], "pop" : 534, "state" : "OK" }
+{ "_id" : "73042", "city" : "GRACEMONT", "loc" : [ -98.283513, 35.187498 ], "pop" : 968, "state" : "OK" }
+{ "_id" : "73043", "city" : "GREENFIELD", "loc" : [ -98.384073, 35.733269 ], "pop" : 270, "state" : "OK" }
+{ "_id" : "73044", "city" : "GUTHRIE", "loc" : [ -97.43599500000001, 35.832955 ], "pop" : 19769, "state" : "OK" }
+{ "_id" : "73045", "city" : "HARRAH", "loc" : [ -97.17343, 35.483258 ], "pop" : 6766, "state" : "OK" }
+{ "_id" : "73046", "city" : "HENNEPIN", "loc" : [ -97.42146700000001, 34.485893 ], "pop" : 656, "state" : "OK" }
+{ "_id" : "73047", "city" : "HINTON", "loc" : [ -98.33134800000001, 35.4675 ], "pop" : 2433, "state" : "OK" }
+{ "_id" : "73048", "city" : "HYDRO", "loc" : [ -98.56044799999999, 35.45201 ], "pop" : 2009, "state" : "OK" }
+{ "_id" : "73049", "city" : "JONES", "loc" : [ -97.28914, 35.575316 ], "pop" : 3059, "state" : "OK" }
+{ "_id" : "73051", "city" : "LEXINGTON", "loc" : [ -97.26094500000001, 35.037661 ], "pop" : 7904, "state" : "OK" }
+{ "_id" : "73052", "city" : "LINDSAY", "loc" : [ -97.599788, 34.821116 ], "pop" : 5597, "state" : "OK" }
+{ "_id" : "73053", "city" : "LOOKEBA", "loc" : [ -98.389833, 35.367946 ], "pop" : 802, "state" : "OK" }
+{ "_id" : "73054", "city" : "LUTHER", "loc" : [ -97.182292, 35.631491 ], "pop" : 2111, "state" : "OK" }
+{ "_id" : "73055", "city" : "MARLOW", "loc" : [ -97.940955, 34.638681 ], "pop" : 7881, "state" : "OK" }
+{ "_id" : "73056", "city" : "MARSHALL", "loc" : [ -97.617052, 36.148455 ], "pop" : 479, "state" : "OK" }
+{ "_id" : "73057", "city" : "MAYSVILLE", "loc" : [ -97.41314300000001, 34.811316 ], "pop" : 2456, "state" : "OK" }
+{ "_id" : "73058", "city" : "MERIDIAN", "loc" : [ -97.24623, 35.8451 ], "pop" : 61, "state" : "OK" }
+{ "_id" : "73059", "city" : "MINCO", "loc" : [ -97.96638, 35.306723 ], "pop" : 2119, "state" : "OK" }
+{ "_id" : "73061", "city" : "MORRISON", "loc" : [ -97.022777, 36.290214 ], "pop" : 1425, "state" : "OK" }
+{ "_id" : "73062", "city" : "MOUNTAIN VIEW", "loc" : [ -98.730694, 35.06535 ], "pop" : 1808, "state" : "OK" }
+{ "_id" : "73063", "city" : "MULHALL", "loc" : [ -97.409809, 36.053678 ], "pop" : 463, "state" : "OK" }
+{ "_id" : "73064", "city" : "MUSTANG", "loc" : [ -97.73088799999999, 35.388498 ], "pop" : 12156, "state" : "OK" }
+{ "_id" : "73065", "city" : "NEWCASTLE", "loc" : [ -97.621573, 35.245269 ], "pop" : 4653, "state" : "OK" }
+{ "_id" : "73067", "city" : "NINNEKAH", "loc" : [ -97.933277, 34.91435 ], "pop" : 1075, "state" : "OK" }
+{ "_id" : "73068", "city" : "NOBLE", "loc" : [ -97.340929, 35.141742 ], "pop" : 8098, "state" : "OK" }
+{ "_id" : "73069", "city" : "NORMAN", "loc" : [ -97.45774299999999, 35.220389 ], "pop" : 21299, "state" : "OK" }
+{ "_id" : "73071", "city" : "NORMAN", "loc" : [ -97.379159, 35.224254 ], "pop" : 32228, "state" : "OK" }
+{ "_id" : "73072", "city" : "NORMAN", "loc" : [ -97.472984, 35.210733 ], "pop" : 27969, "state" : "OK" }
+{ "_id" : "73073", "city" : "ORLANDO", "loc" : [ -97.39599200000001, 36.141973 ], "pop" : 332, "state" : "OK" }
+{ "_id" : "73074", "city" : "PAOLI", "loc" : [ -97.260807, 34.828492 ], "pop" : 989, "state" : "OK" }
+{ "_id" : "73075", "city" : "PAULS VALLEY", "loc" : [ -97.21950099999999, 34.738506 ], "pop" : 8663, "state" : "OK" }
+{ "_id" : "73077", "city" : "PERRY", "loc" : [ -97.284175, 36.287468 ], "pop" : 7231, "state" : "OK" }
+{ "_id" : "73078", "city" : "PIEDMONT", "loc" : [ -97.743109, 35.66946 ], "pop" : 2267, "state" : "OK" }
+{ "_id" : "73079", "city" : "POCASSET", "loc" : [ -97.97904, 35.154437 ], "pop" : 895, "state" : "OK" }
+{ "_id" : "73080", "city" : "PURCELL", "loc" : [ -97.425493, 35.010293 ], "pop" : 8700, "state" : "OK" }
+{ "_id" : "73081", "city" : "RATLIFF CITY", "loc" : [ -97.51442400000001, 34.420719 ], "pop" : 894, "state" : "OK" }
+{ "_id" : "73082", "city" : "RUSH SPRINGS", "loc" : [ -97.943101, 34.770804 ], "pop" : 3537, "state" : "OK" }
+{ "_id" : "73084", "city" : "SPENCER", "loc" : [ -97.348775, 35.518276 ], "pop" : 7675, "state" : "OK" }
+{ "_id" : "73086", "city" : "SULPHUR", "loc" : [ -96.97969500000001, 34.511585 ], "pop" : 7018, "state" : "OK" }
+{ "_id" : "73088", "city" : "TUSSY", "loc" : [ -97.536379, 34.492159 ], "pop" : 90, "state" : "OK" }
+{ "_id" : "73089", "city" : "TUTTLE", "loc" : [ -97.744621, 35.267406 ], "pop" : 8753, "state" : "OK" }
+{ "_id" : "73090", "city" : "UNION CITY", "loc" : [ -97.93979, 35.391333 ], "pop" : 551, "state" : "OK" }
+{ "_id" : "73092", "city" : "VERDEN", "loc" : [ -98.079206, 35.08356 ], "pop" : 734, "state" : "OK" }
+{ "_id" : "73093", "city" : "WASHINGTON", "loc" : [ -97.486969, 35.13235 ], "pop" : 1670, "state" : "OK" }
+{ "_id" : "73095", "city" : "WAYNE", "loc" : [ -97.329014, 34.915353 ], "pop" : 1430, "state" : "OK" }
+{ "_id" : "73096", "city" : "WEATHERFORD", "loc" : [ -98.699603, 35.535046 ], "pop" : 11963, "state" : "OK" }
+{ "_id" : "73098", "city" : "WYNNEWOOD", "loc" : [ -97.176952, 34.63847 ], "pop" : 3762, "state" : "OK" }
+{ "_id" : "73099", "city" : "YUKON", "loc" : [ -97.73230700000001, 35.49772 ], "pop" : 38891, "state" : "OK" }
+{ "_id" : "73102", "city" : "OKLAHOMA CITY", "loc" : [ -97.519926, 35.472601 ], "pop" : 2227, "state" : "OK" }
+{ "_id" : "73103", "city" : "OKLAHOMA CITY", "loc" : [ -97.51959100000001, 35.490957 ], "pop" : 4253, "state" : "OK" }
+{ "_id" : "73104", "city" : "OKLAHOMA CITY", "loc" : [ -97.50171400000001, 35.479388 ], "pop" : 2534, "state" : "OK" }
+{ "_id" : "73105", "city" : "OKLAHOMA CITY", "loc" : [ -97.500291, 35.510811 ], "pop" : 5379, "state" : "OK" }
+{ "_id" : "73106", "city" : "OKLAHOMA CITY", "loc" : [ -97.537228, 35.485328 ], "pop" : 12706, "state" : "OK" }
+{ "_id" : "73107", "city" : "OKLAHOMA CITY", "loc" : [ -97.57397400000001, 35.48736 ], "pop" : 23130, "state" : "OK" }
+{ "_id" : "73108", "city" : "OKLAHOMA CITY", "loc" : [ -97.56192799999999, 35.444485 ], "pop" : 13259, "state" : "OK" }
+{ "_id" : "73109", "city" : "OKLAHOMA CITY", "loc" : [ -97.52613100000001, 35.425944 ], "pop" : 16821, "state" : "OK" }
+{ "_id" : "73110", "city" : "MIDWEST CITY", "loc" : [ -97.397661, 35.461978 ], "pop" : 35101, "state" : "OK" }
+{ "_id" : "73111", "city" : "OKLAHOMA CITY", "loc" : [ -97.48060700000001, 35.504238 ], "pop" : 15332, "state" : "OK" }
+{ "_id" : "73112", "city" : "OKLAHOMA CITY", "loc" : [ -97.574639, 35.518435 ], "pop" : 29057, "state" : "OK" }
+{ "_id" : "73114", "city" : "OKLAHOMA CITY", "loc" : [ -97.52573599999999, 35.570357 ], "pop" : 15126, "state" : "OK" }
+{ "_id" : "73115", "city" : "DEL CITY", "loc" : [ -97.44164499999999, 35.440093 ], "pop" : 23589, "state" : "OK" }
+{ "_id" : "73116", "city" : "NICHOLS HILLS", "loc" : [ -97.56394, 35.542484 ], "pop" : 9559, "state" : "OK" }
+{ "_id" : "73117", "city" : "OKLAHOMA CITY", "loc" : [ -97.472195, 35.479667 ], "pop" : 6489, "state" : "OK" }
+{ "_id" : "73118", "city" : "OKLAHOMA CITY", "loc" : [ -97.531908, 35.513645 ], "pop" : 13826, "state" : "OK" }
+{ "_id" : "73119", "city" : "OKLAHOMA CITY", "loc" : [ -97.561584, 35.421033 ], "pop" : 25150, "state" : "OK" }
+{ "_id" : "73120", "city" : "OKLAHOMA CITY", "loc" : [ -97.563756, 35.583478 ], "pop" : 35879, "state" : "OK" }
+{ "_id" : "73121", "city" : "OKLAHOMA CITY", "loc" : [ -97.445183, 35.506235 ], "pop" : 3134, "state" : "OK" }
+{ "_id" : "73122", "city" : "WARR ACRES", "loc" : [ -97.613305, 35.520239 ], "pop" : 13337, "state" : "OK" }
+{ "_id" : "73127", "city" : "OKLAHOMA CITY", "loc" : [ -97.629927, 35.483371 ], "pop" : 20789, "state" : "OK" }
+{ "_id" : "73128", "city" : "OKLAHOMA CITY", "loc" : [ -97.616362, 35.444358 ], "pop" : 1349, "state" : "OK" }
+{ "_id" : "73129", "city" : "OKLAHOMA CITY", "loc" : [ -97.491309, 35.43119 ], "pop" : 18830, "state" : "OK" }
+{ "_id" : "73130", "city" : "MIDWEST CITY", "loc" : [ -97.351489, 35.460863 ], "pop" : 16223, "state" : "OK" }
+{ "_id" : "73131", "city" : "OKLAHOMA CITY", "loc" : [ -97.469127, 35.579693 ], "pop" : 1460, "state" : "OK" }
+{ "_id" : "73132", "city" : "WARR ACRES", "loc" : [ -97.63633299999999, 35.552783 ], "pop" : 22038, "state" : "OK" }
+{ "_id" : "73134", "city" : "OKLAHOMA CITY", "loc" : [ -97.558342, 35.617397 ], "pop" : 1317, "state" : "OK" }
+{ "_id" : "73135", "city" : "OKLAHOMA CITY", "loc" : [ -97.438762, 35.411037 ], "pop" : 13933, "state" : "OK" }
+{ "_id" : "73139", "city" : "OKLAHOMA CITY", "loc" : [ -97.536205, 35.379193 ], "pop" : 22429, "state" : "OK" }
+{ "_id" : "73141", "city" : "OKLAHOMA CITY", "loc" : [ -97.366606, 35.491848 ], "pop" : 2667, "state" : "OK" }
+{ "_id" : "73142", "city" : "OKLAHOMA CITY", "loc" : [ -97.625067, 35.598994 ], "pop" : 4366, "state" : "OK" }
+{ "_id" : "73145", "city" : "TINKER AFB", "loc" : [ -97.403707, 35.415706 ], "pop" : 3714, "state" : "OK" }
+{ "_id" : "73149", "city" : "OKLAHOMA CITY", "loc" : [ -97.497175, 35.394998 ], "pop" : 5335, "state" : "OK" }
+{ "_id" : "73150", "city" : "OKLAHOMA CITY", "loc" : [ -97.33308, 35.41231 ], "pop" : 4512, "state" : "OK" }
+{ "_id" : "73151", "city" : "OKLAHOMA CITY", "loc" : [ -97.39057, 35.568508 ], "pop" : 1315, "state" : "OK" }
+{ "_id" : "73159", "city" : "OKLAHOMA CITY", "loc" : [ -97.55674, 35.39224 ], "pop" : 21343, "state" : "OK" }
+{ "_id" : "73160", "city" : "MOORE", "loc" : [ -97.487352, 35.342465 ], "pop" : 39935, "state" : "OK" }
+{ "_id" : "73162", "city" : "OKLAHOMA CITY", "loc" : [ -97.64193400000001, 35.580647 ], "pop" : 21084, "state" : "OK" }
+{ "_id" : "73165", "city" : "MOORE", "loc" : [ -97.34979199999999, 35.337086 ], "pop" : 4202, "state" : "OK" }
+{ "_id" : "73169", "city" : "OKLAHOMA CITY", "loc" : [ -97.658683, 35.388233 ], "pop" : 1266, "state" : "OK" }
+{ "_id" : "73170", "city" : "MOORE", "loc" : [ -97.536, 35.341554 ], "pop" : 13250, "state" : "OK" }
+{ "_id" : "73173", "city" : "OKLAHOMA CITY", "loc" : [ -97.63171, 35.342455 ], "pop" : 667, "state" : "OK" }
+{ "_id" : "73179", "city" : "OKLAHOMA CITY", "loc" : [ -97.654729, 35.424157 ], "pop" : 1177, "state" : "OK" }
+{ "_id" : "73401", "city" : "MILO", "loc" : [ -97.134157, 34.176681 ], "pop" : 30328, "state" : "OK" }
+{ "_id" : "73430", "city" : "BURNEYVILLE", "loc" : [ -97.324929, 33.951516 ], "pop" : 740, "state" : "OK" }
+{ "_id" : "73432", "city" : "COLEMAN", "loc" : [ -96.45881799999999, 34.262498 ], "pop" : 1073, "state" : "OK" }
+{ "_id" : "73437", "city" : "GRAHAM", "loc" : [ -97.495435, 34.337379 ], "pop" : 674, "state" : "OK" }
+{ "_id" : "73438", "city" : "HEALDTON", "loc" : [ -97.48890400000001, 34.229017 ], "pop" : 3114, "state" : "OK" }
+{ "_id" : "73439", "city" : "KINGSTON", "loc" : [ -96.711977, 33.951664 ], "pop" : 3808, "state" : "OK" }
+{ "_id" : "73440", "city" : "LEBANON", "loc" : [ -96.86449500000001, 33.961036 ], "pop" : 144, "state" : "OK" }
+{ "_id" : "73441", "city" : "LEON", "loc" : [ -97.447058, 33.924278 ], "pop" : 919, "state" : "OK" }
+{ "_id" : "73442", "city" : "LOCO", "loc" : [ -97.665803, 34.321416 ], "pop" : 338, "state" : "OK" }
+{ "_id" : "73443", "city" : "LONE GROVE", "loc" : [ -97.268523, 34.177373 ], "pop" : 3002, "state" : "OK" }
+{ "_id" : "73446", "city" : "MC MILLAN", "loc" : [ -96.78725799999999, 34.07126 ], "pop" : 6877, "state" : "OK" }
+{ "_id" : "73447", "city" : "MANNSVILLE", "loc" : [ -96.87780100000001, 34.189902 ], "pop" : 888, "state" : "OK" }
+{ "_id" : "73448", "city" : "MARIETTA", "loc" : [ -97.114801, 33.943099 ], "pop" : 5242, "state" : "OK" }
+{ "_id" : "73449", "city" : "MEAD", "loc" : [ -96.529886, 33.994442 ], "pop" : 1520, "state" : "OK" }
+{ "_id" : "73450", "city" : "MILBURN", "loc" : [ -96.54286, 34.195172 ], "pop" : 884, "state" : "OK" }
+{ "_id" : "73453", "city" : "OVERBROOK", "loc" : [ -97.13235299999999, 34.053906 ], "pop" : 283, "state" : "OK" }
+{ "_id" : "73456", "city" : "RINGLING", "loc" : [ -97.602867, 34.167865 ], "pop" : 2215, "state" : "OK" }
+{ "_id" : "73458", "city" : "SPRINGER", "loc" : [ -97.122266, 34.303832 ], "pop" : 1248, "state" : "OK" }
+{ "_id" : "73459", "city" : "THACKERVILLE", "loc" : [ -97.136349, 33.788167 ], "pop" : 973, "state" : "OK" }
+{ "_id" : "73460", "city" : "TISHOMINGO", "loc" : [ -96.667502, 34.264286 ], "pop" : 4958, "state" : "OK" }
+{ "_id" : "73461", "city" : "WAPANUCKA", "loc" : [ -96.45322299999999, 34.386634 ], "pop" : 719, "state" : "OK" }
+{ "_id" : "73463", "city" : "RUBOTTOM", "loc" : [ -97.42487, 34.164206 ], "pop" : 3095, "state" : "OK" }
+{ "_id" : "73501", "city" : "LAWTON", "loc" : [ -98.369783, 34.591467 ], "pop" : 18175, "state" : "OK" }
+{ "_id" : "73503", "city" : "FORT SILL", "loc" : [ -98.40040999999999, 34.659525 ], "pop" : 12228, "state" : "OK" }
+{ "_id" : "73505", "city" : "LAWTON", "loc" : [ -98.455234, 34.617939 ], "pop" : 45542, "state" : "OK" }
+{ "_id" : "73507", "city" : "LAWTON", "loc" : [ -98.389453, 34.624595 ], "pop" : 19244, "state" : "OK" }
+{ "_id" : "73521", "city" : "ALTUS", "loc" : [ -99.320483, 34.648406 ], "pop" : 22957, "state" : "OK" }
+{ "_id" : "73526", "city" : "BLAIR", "loc" : [ -99.333404, 34.778813 ], "pop" : 1147, "state" : "OK" }
+{ "_id" : "73527", "city" : "CACHE", "loc" : [ -98.615351, 34.613072 ], "pop" : 3857, "state" : "OK" }
+{ "_id" : "73528", "city" : "CHATTANOOGA", "loc" : [ -98.651365, 34.426193 ], "pop" : 483, "state" : "OK" }
+{ "_id" : "73529", "city" : "COMANCHE", "loc" : [ -97.979286, 34.376523 ], "pop" : 4998, "state" : "OK" }
+{ "_id" : "73530", "city" : "DAVIDSON", "loc" : [ -99.064031, 34.251423 ], "pop" : 800, "state" : "OK" }
+{ "_id" : "73531", "city" : "DEVOL", "loc" : [ -98.57699100000001, 34.195589 ], "pop" : 311, "state" : "OK" }
+{ "_id" : "73532", "city" : "DUKE", "loc" : [ -99.54817199999999, 34.666769 ], "pop" : 625, "state" : "OK" }
+{ "_id" : "73533", "city" : "DUNCAN", "loc" : [ -97.94032199999999, 34.507277 ], "pop" : 28871, "state" : "OK" }
+{ "_id" : "73537", "city" : "ELDORADO", "loc" : [ -99.645956, 34.472744 ], "pop" : 742, "state" : "OK" }
+{ "_id" : "73538", "city" : "ELGIN", "loc" : [ -98.40732199999999, 34.772018 ], "pop" : 5476, "state" : "OK" }
+{ "_id" : "73539", "city" : "ELMER", "loc" : [ -99.316744, 34.513668 ], "pop" : 569, "state" : "OK" }
+{ "_id" : "73540", "city" : "FAXON", "loc" : [ -98.55771, 34.464521 ], "pop" : 352, "state" : "OK" }
+{ "_id" : "73541", "city" : "FLETCHER", "loc" : [ -98.20024600000001, 34.784657 ], "pop" : 3382, "state" : "OK" }
+{ "_id" : "73542", "city" : "FREDERICK", "loc" : [ -99.011877, 34.401199 ], "pop" : 6196, "state" : "OK" }
+{ "_id" : "73543", "city" : "GERONIMO", "loc" : [ -98.387525, 34.480499 ], "pop" : 1305, "state" : "OK" }
+{ "_id" : "73544", "city" : "GOULD", "loc" : [ -99.78433699999999, 34.664964 ], "pop" : 553, "state" : "OK" }
+{ "_id" : "73546", "city" : "GRANDFIELD", "loc" : [ -98.686654, 34.228247 ], "pop" : 1436, "state" : "OK" }
+{ "_id" : "73547", "city" : "GRANITE", "loc" : [ -99.388139, 34.971184 ], "pop" : 2216, "state" : "OK" }
+{ "_id" : "73548", "city" : "HASTINGS", "loc" : [ -98.107539, 34.225064 ], "pop" : 210, "state" : "OK" }
+{ "_id" : "73549", "city" : "HEADRICK", "loc" : [ -99.23904, 34.72189 ], "pop" : 1903, "state" : "OK" }
+{ "_id" : "73550", "city" : "HOLLIS", "loc" : [ -99.917711, 34.695281 ], "pop" : 3136, "state" : "OK" }
+{ "_id" : "73551", "city" : "HOLLISTER", "loc" : [ -98.881404, 34.352473 ], "pop" : 127, "state" : "OK" }
+{ "_id" : "73552", "city" : "INDIAHOMA", "loc" : [ -98.734864, 34.624226 ], "pop" : 1385, "state" : "OK" }
+{ "_id" : "73553", "city" : "LOVELAND", "loc" : [ -98.72353, 34.391018 ], "pop" : 312, "state" : "OK" }
+{ "_id" : "73554", "city" : "REED", "loc" : [ -99.505769, 34.875473 ], "pop" : 4057, "state" : "OK" }
+{ "_id" : "73559", "city" : "MOUNTAIN PARK", "loc" : [ -98.959136, 34.703158 ], "pop" : 631, "state" : "OK" }
+{ "_id" : "73560", "city" : "OLUSTEE", "loc" : [ -99.428684, 34.549634 ], "pop" : 821, "state" : "OK" }
+{ "_id" : "73561", "city" : "OSCAR", "loc" : [ -97.761359, 33.973237 ], "pop" : 35, "state" : "OK" }
+{ "_id" : "73562", "city" : "RANDLETT", "loc" : [ -98.459974, 34.174045 ], "pop" : 891, "state" : "OK" }
+{ "_id" : "73564", "city" : "ROOSEVELT", "loc" : [ -98.983599, 34.846983 ], "pop" : 666, "state" : "OK" }
+{ "_id" : "73565", "city" : "RYAN", "loc" : [ -97.946141, 34.023787 ], "pop" : 1331, "state" : "OK" }
+{ "_id" : "73566", "city" : "SNYDER", "loc" : [ -98.95075199999999, 34.654779 ], "pop" : 1858, "state" : "OK" }
+{ "_id" : "73568", "city" : "TEMPLE", "loc" : [ -98.23707400000001, 34.260669 ], "pop" : 1588, "state" : "OK" }
+{ "_id" : "73569", "city" : "GRADY", "loc" : [ -97.935045, 33.897162 ], "pop" : 563, "state" : "OK" }
+{ "_id" : "73570", "city" : "TIPTON", "loc" : [ -99.13148200000001, 34.509793 ], "pop" : 1513, "state" : "OK" }
+{ "_id" : "73571", "city" : "VINSON", "loc" : [ -99.833929, 34.906179 ], "pop" : 104, "state" : "OK" }
+{ "_id" : "73572", "city" : "WALTERS", "loc" : [ -98.31398299999999, 34.360526 ], "pop" : 3861, "state" : "OK" }
+{ "_id" : "73573", "city" : "WAURIKA", "loc" : [ -97.99734599999999, 34.174466 ], "pop" : 2656, "state" : "OK" }
+{ "_id" : "73601", "city" : "CLINTON", "loc" : [ -98.979533, 35.511543 ], "pop" : 10287, "state" : "OK" }
+{ "_id" : "73620", "city" : "ARAPAHO", "loc" : [ -98.959508, 35.578864 ], "pop" : 1005, "state" : "OK" }
+{ "_id" : "73622", "city" : "BESSIE", "loc" : [ -98.989638, 35.38545 ], "pop" : 271, "state" : "OK" }
+{ "_id" : "73625", "city" : "BUTLER", "loc" : [ -99.242749, 35.633638 ], "pop" : 1110, "state" : "OK" }
+{ "_id" : "73626", "city" : "CANUTE", "loc" : [ -99.281575, 35.403678 ], "pop" : 1245, "state" : "OK" }
+{ "_id" : "73627", "city" : "CARTER", "loc" : [ -99.48223900000001, 35.220779 ], "pop" : 664, "state" : "OK" }
+{ "_id" : "73628", "city" : "STRONG CITY", "loc" : [ -99.676688, 35.623181 ], "pop" : 1586, "state" : "OK" }
+{ "_id" : "73632", "city" : "CORDELL", "loc" : [ -98.95105599999999, 35.278803 ], "pop" : 4210, "state" : "OK" }
+{ "_id" : "73638", "city" : "CRAWFORD", "loc" : [ -99.80644599999999, 35.836766 ], "pop" : 178, "state" : "OK" }
+{ "_id" : "73639", "city" : "CUSTER CITY", "loc" : [ -98.912013, 35.689371 ], "pop" : 758, "state" : "OK" }
+{ "_id" : "73641", "city" : "DILL CITY", "loc" : [ -99.153738, 35.278704 ], "pop" : 966, "state" : "OK" }
+{ "_id" : "73642", "city" : "DURHAM", "loc" : [ -99.90877399999999, 35.836391 ], "pop" : 173, "state" : "OK" }
+{ "_id" : "73644", "city" : "ELK CITY", "loc" : [ -99.421086, 35.410359 ], "pop" : 12461, "state" : "OK" }
+{ "_id" : "73645", "city" : "ERICK", "loc" : [ -99.863463, 35.228586 ], "pop" : 1638, "state" : "OK" }
+{ "_id" : "73646", "city" : "FAY", "loc" : [ -98.65867799999999, 35.820417 ], "pop" : 136, "state" : "OK" }
+{ "_id" : "73647", "city" : "FOSS", "loc" : [ -99.15259, 35.373645 ], "pop" : 1609, "state" : "OK" }
+{ "_id" : "73650", "city" : "HAMMON", "loc" : [ -99.402683, 35.646131 ], "pop" : 873, "state" : "OK" }
+{ "_id" : "73651", "city" : "HOBART", "loc" : [ -99.094433, 35.025521 ], "pop" : 4844, "state" : "OK" }
+{ "_id" : "73654", "city" : "LEEDEY", "loc" : [ -99.349146, 35.869772 ], "pop" : 906, "state" : "OK" }
+{ "_id" : "73655", "city" : "LONE WOLF", "loc" : [ -99.25016100000001, 34.980584 ], "pop" : 1135, "state" : "OK" }
+{ "_id" : "73658", "city" : "EAGLE CITY", "loc" : [ -98.70805799999999, 35.921429 ], "pop" : 332, "state" : "OK" }
+{ "_id" : "73659", "city" : "PUTNAM", "loc" : [ -98.963765, 35.853851 ], "pop" : 149, "state" : "OK" }
+{ "_id" : "73660", "city" : "REYDON", "loc" : [ -99.916567, 35.657587 ], "pop" : 537, "state" : "OK" }
+{ "_id" : "73661", "city" : "ROCKY", "loc" : [ -99.04803699999999, 35.152636 ], "pop" : 242, "state" : "OK" }
+{ "_id" : "73662", "city" : "SAYRE", "loc" : [ -99.642928, 35.304722 ], "pop" : 4072, "state" : "OK" }
+{ "_id" : "73663", "city" : "SEILING", "loc" : [ -98.88746, 36.127823 ], "pop" : 1847, "state" : "OK" }
+{ "_id" : "73664", "city" : "SENTINEL", "loc" : [ -99.17061099999999, 35.161741 ], "pop" : 1358, "state" : "OK" }
+{ "_id" : "73666", "city" : "SWEETWATER", "loc" : [ -99.90061900000001, 35.448835 ], "pop" : 428, "state" : "OK" }
+{ "_id" : "73667", "city" : "TALOGA", "loc" : [ -98.982473, 35.997242 ], "pop" : 784, "state" : "OK" }
+{ "_id" : "73668", "city" : "TEXOLA", "loc" : [ -99.98218, 35.224977 ], "pop" : 89, "state" : "OK" }
+{ "_id" : "73669", "city" : "THOMAS", "loc" : [ -98.73884200000001, 35.738165 ], "pop" : 1774, "state" : "OK" }
+{ "_id" : "73673", "city" : "WILLOW", "loc" : [ -99.542091, 35.070245 ], "pop" : 376, "state" : "OK" }
+{ "_id" : "73701", "city" : "ENID", "loc" : [ -97.862257, 36.402842 ], "pop" : 22487, "state" : "OK" }
+{ "_id" : "73703", "city" : "ENID", "loc" : [ -97.91569699999999, 36.397509 ], "pop" : 24700, "state" : "OK" }
+{ "_id" : "73716", "city" : "ALINE", "loc" : [ -98.457387, 36.505621 ], "pop" : 526, "state" : "OK" }
+{ "_id" : "73717", "city" : "ALVA", "loc" : [ -98.672162, 36.801564 ], "pop" : 6376, "state" : "OK" }
+{ "_id" : "73718", "city" : "AMES", "loc" : [ -98.181989, 36.242293 ], "pop" : 618, "state" : "OK" }
+{ "_id" : "73719", "city" : "AMORITA", "loc" : [ -98.24582100000001, 36.941221 ], "pop" : 178, "state" : "OK" }
+{ "_id" : "73720", "city" : "BISON", "loc" : [ -97.880484, 36.196222 ], "pop" : 212, "state" : "OK" }
+{ "_id" : "73722", "city" : "BURLINGTON", "loc" : [ -98.42145499999999, 36.903613 ], "pop" : 359, "state" : "OK" }
+{ "_id" : "73723", "city" : "BYRON", "loc" : [ -98.244502, 36.879857 ], "pop" : 172, "state" : "OK" }
+{ "_id" : "73724", "city" : "CANTON", "loc" : [ -98.57781799999999, 36.037194 ], "pop" : 1293, "state" : "OK" }
+{ "_id" : "73725", "city" : "CAPRON", "loc" : [ -98.629891, 36.896812 ], "pop" : 268, "state" : "OK" }
+{ "_id" : "73726", "city" : "CARMEN", "loc" : [ -98.457793, 36.584206 ], "pop" : 642, "state" : "OK" }
+{ "_id" : "73727", "city" : "CARRIER", "loc" : [ -97.99968800000001, 36.518892 ], "pop" : 619, "state" : "OK" }
+{ "_id" : "73728", "city" : "CHEROKEE", "loc" : [ -98.359375, 36.756376 ], "pop" : 2256, "state" : "OK" }
+{ "_id" : "73729", "city" : "CLEO SPRINGS", "loc" : [ -98.442275, 36.408989 ], "pop" : 630, "state" : "OK" }
+{ "_id" : "73730", "city" : "COVINGTON", "loc" : [ -97.575163, 36.309944 ], "pop" : 1017, "state" : "OK" }
+{ "_id" : "73731", "city" : "DACOMA", "loc" : [ -98.594202, 36.660604 ], "pop" : 351, "state" : "OK" }
+{ "_id" : "73733", "city" : "DOUGLAS", "loc" : [ -97.689626, 36.248138 ], "pop" : 314, "state" : "OK" }
+{ "_id" : "73734", "city" : "DOVER", "loc" : [ -97.906677, 35.984761 ], "pop" : 580, "state" : "OK" }
+{ "_id" : "73735", "city" : "DRUMMOND", "loc" : [ -98.03584600000001, 36.284142 ], "pop" : 896, "state" : "OK" }
+{ "_id" : "73736", "city" : "FAIRMONT", "loc" : [ -97.711493, 36.391614 ], "pop" : 701, "state" : "OK" }
+{ "_id" : "73737", "city" : "ORIENTA", "loc" : [ -98.506271, 36.265981 ], "pop" : 3964, "state" : "OK" }
+{ "_id" : "73738", "city" : "GARBER", "loc" : [ -97.57889900000001, 36.439184 ], "pop" : 1296, "state" : "OK" }
+{ "_id" : "73739", "city" : "GOLTRY", "loc" : [ -98.153978, 36.531364 ], "pop" : 436, "state" : "OK" }
+{ "_id" : "73741", "city" : "HELENA", "loc" : [ -98.27781899999999, 36.54375 ], "pop" : 1365, "state" : "OK" }
+{ "_id" : "73742", "city" : "HENNESSEY", "loc" : [ -97.892595, 36.086848 ], "pop" : 4006, "state" : "OK" }
+{ "_id" : "73744", "city" : "HITCHCOCK", "loc" : [ -98.331535, 35.971209 ], "pop" : 231, "state" : "OK" }
+{ "_id" : "73747", "city" : "ISABELLA", "loc" : [ -98.337446, 36.23407 ], "pop" : 416, "state" : "OK" }
+{ "_id" : "73749", "city" : "JET", "loc" : [ -98.172121, 36.692917 ], "pop" : 526, "state" : "OK" }
+{ "_id" : "73750", "city" : "KINGFISHER", "loc" : [ -97.947293, 35.863613 ], "pop" : 6323, "state" : "OK" }
+{ "_id" : "73753", "city" : "KREMLIN", "loc" : [ -97.854186, 36.520735 ], "pop" : 971, "state" : "OK" }
+{ "_id" : "73754", "city" : "LAHOMA", "loc" : [ -98.072738, 36.385005 ], "pop" : 1275, "state" : "OK" }
+{ "_id" : "73755", "city" : "LONGDALE", "loc" : [ -98.549966, 36.121233 ], "pop" : 668, "state" : "OK" }
+{ "_id" : "73756", "city" : "LOYAL", "loc" : [ -98.115516, 35.970529 ], "pop" : 132, "state" : "OK" }
+{ "_id" : "73757", "city" : "LUCIEN", "loc" : [ -97.452574, 36.275327 ], "pop" : 120, "state" : "OK" }
+{ "_id" : "73758", "city" : "MANCHESTER", "loc" : [ -98.03825999999999, 36.9744 ], "pop" : 206, "state" : "OK" }
+{ "_id" : "73759", "city" : "MEDFORD", "loc" : [ -97.720215, 36.814195 ], "pop" : 2027, "state" : "OK" }
+{ "_id" : "73760", "city" : "MENO", "loc" : [ -98.163501, 36.381497 ], "pop" : 455, "state" : "OK" }
+{ "_id" : "73761", "city" : "NASH", "loc" : [ -98.025764, 36.696146 ], "pop" : 647, "state" : "OK" }
+{ "_id" : "73762", "city" : "OKARCHE", "loc" : [ -97.92999, 35.750158 ], "pop" : 1703, "state" : "OK" }
+{ "_id" : "73763", "city" : "OKEENE", "loc" : [ -98.325422, 36.11646 ], "pop" : 1899, "state" : "OK" }
+{ "_id" : "73764", "city" : "OMEGA", "loc" : [ -98.18634400000001, 35.850653 ], "pop" : 60, "state" : "OK" }
+{ "_id" : "73766", "city" : "POND CREEK", "loc" : [ -97.801903, 36.664281 ], "pop" : 1173, "state" : "OK" }
+{ "_id" : "73768", "city" : "RINGWOOD", "loc" : [ -98.270639, 36.375293 ], "pop" : 1362, "state" : "OK" }
+{ "_id" : "73770", "city" : "SOUTHARD", "loc" : [ -98.446456, 36.074706 ], "pop" : 8, "state" : "OK" }
+{ "_id" : "73771", "city" : "WAKITA", "loc" : [ -97.94268700000001, 36.875333 ], "pop" : 684, "state" : "OK" }
+{ "_id" : "73772", "city" : "WATONGA", "loc" : [ -98.41748699999999, 35.853762 ], "pop" : 5042, "state" : "OK" }
+{ "_id" : "73773", "city" : "WAUKOMIS", "loc" : [ -97.89957800000001, 36.278057 ], "pop" : 1704, "state" : "OK" }
+{ "_id" : "73801", "city" : "WOODWARD", "loc" : [ -99.402016, 36.426784 ], "pop" : 14279, "state" : "OK" }
+{ "_id" : "73832", "city" : "HARMON", "loc" : [ -99.73266, 36.120524 ], "pop" : 1353, "state" : "OK" }
+{ "_id" : "73834", "city" : "SELMAN", "loc" : [ -99.604816, 36.835901 ], "pop" : 1957, "state" : "OK" }
+{ "_id" : "73835", "city" : "CAMARGO", "loc" : [ -99.27810100000001, 36.021235 ], "pop" : 233, "state" : "OK" }
+{ "_id" : "73838", "city" : "CHESTER", "loc" : [ -98.884078, 36.252841 ], "pop" : 561, "state" : "OK" }
+{ "_id" : "73840", "city" : "FARGO", "loc" : [ -99.65060200000001, 36.40525 ], "pop" : 692, "state" : "OK" }
+{ "_id" : "73841", "city" : "FORT SUPPLY", "loc" : [ -99.526797, 36.564556 ], "pop" : 1222, "state" : "OK" }
+{ "_id" : "73842", "city" : "FREEDOM", "loc" : [ -99.131922, 36.809036 ], "pop" : 532, "state" : "OK" }
+{ "_id" : "73843", "city" : "GAGE", "loc" : [ -99.760003, 36.317996 ], "pop" : 567, "state" : "OK" }
+{ "_id" : "73844", "city" : "GATE", "loc" : [ -100.073386, 36.875679 ], "pop" : 323, "state" : "OK" }
+{ "_id" : "73847", "city" : "KNOWLES", "loc" : [ -100.217867, 36.839316 ], "pop" : 49, "state" : "OK" }
+{ "_id" : "73848", "city" : "LAVERNE", "loc" : [ -99.891766, 36.70625 ], "pop" : 1747, "state" : "OK" }
+{ "_id" : "73849", "city" : "LOGAN", "loc" : [ -100.167934, 36.635554 ], "pop" : 467, "state" : "OK" }
+{ "_id" : "73851", "city" : "MAY", "loc" : [ -99.72469, 36.62673 ], "pop" : 88, "state" : "OK" }
+{ "_id" : "73852", "city" : "MOORELAND", "loc" : [ -99.18321, 36.442828 ], "pop" : 2047, "state" : "OK" }
+{ "_id" : "73853", "city" : "MUTUAL", "loc" : [ -99.114492, 36.213954 ], "pop" : 262, "state" : "OK" }
+{ "_id" : "73855", "city" : "ROSSTON", "loc" : [ -99.90025300000001, 36.878915 ], "pop" : 271, "state" : "OK" }
+{ "_id" : "73857", "city" : "SHARON", "loc" : [ -99.35873599999999, 36.269872 ], "pop" : 1166, "state" : "OK" }
+{ "_id" : "73858", "city" : "SHATTUCK", "loc" : [ -99.87930299999999, 36.288922 ], "pop" : 1886, "state" : "OK" }
+{ "_id" : "73859", "city" : "VICI", "loc" : [ -99.267004, 36.137168 ], "pop" : 1333, "state" : "OK" }
+{ "_id" : "73860", "city" : "WAYNOKA", "loc" : [ -98.84874600000001, 36.585788 ], "pop" : 1516, "state" : "OK" }
+{ "_id" : "73931", "city" : "BALKO", "loc" : [ -100.710329, 36.599607 ], "pop" : 826, "state" : "OK" }
+{ "_id" : "73932", "city" : "ELMWOOD", "loc" : [ -100.532938, 36.795562 ], "pop" : 2128, "state" : "OK" }
+{ "_id" : "73933", "city" : "BOISE CITY", "loc" : [ -102.535519, 36.728328 ], "pop" : 2064, "state" : "OK" }
+{ "_id" : "73937", "city" : "FELT", "loc" : [ -102.797422, 36.566569 ], "pop" : 210, "state" : "OK" }
+{ "_id" : "73938", "city" : "FORGAN", "loc" : [ -100.540875, 36.908588 ], "pop" : 688, "state" : "OK" }
+{ "_id" : "73939", "city" : "GOODWELL", "loc" : [ -101.71369, 36.674382 ], "pop" : 1857, "state" : "OK" }
+{ "_id" : "73942", "city" : "GUYMON", "loc" : [ -101.47778, 36.696052 ], "pop" : 9387, "state" : "OK" }
+{ "_id" : "73944", "city" : "HARDESTY", "loc" : [ -101.153944, 36.601754 ], "pop" : 450, "state" : "OK" }
+{ "_id" : "73945", "city" : "OPTIMA", "loc" : [ -101.190683, 36.847981 ], "pop" : 2585, "state" : "OK" }
+{ "_id" : "73946", "city" : "KENTON", "loc" : [ -102.912421, 36.855639 ], "pop" : 108, "state" : "OK" }
+{ "_id" : "73947", "city" : "KEYES", "loc" : [ -102.236063, 36.800316 ], "pop" : 781, "state" : "OK" }
+{ "_id" : "73949", "city" : "TEXHOMA", "loc" : [ -101.839351, 36.52529 ], "pop" : 1057, "state" : "OK" }
+{ "_id" : "73950", "city" : "BAKER", "loc" : [ -100.869028, 36.909012 ], "pop" : 1542, "state" : "OK" }
+{ "_id" : "73951", "city" : "TYRONE", "loc" : [ -101.059408, 36.95577 ], "pop" : 1221, "state" : "OK" }
+{ "_id" : "74002", "city" : "BARNSDALL", "loc" : [ -96.131789, 36.542866 ], "pop" : 2936, "state" : "OK" }
+{ "_id" : "74003", "city" : "BARTLESVILLE", "loc" : [ -95.992091, 36.743956 ], "pop" : 14990, "state" : "OK" }
+{ "_id" : "74006", "city" : "BARTLESVILLE", "loc" : [ -95.92513, 36.736646 ], "pop" : 23075, "state" : "OK" }
+{ "_id" : "74008", "city" : "BIXBY", "loc" : [ -95.872895, 35.917291 ], "pop" : 7505, "state" : "OK" }
+{ "_id" : "74010", "city" : "BRISTOW", "loc" : [ -96.375838, 35.820904 ], "pop" : 7361, "state" : "OK" }
+{ "_id" : "74011", "city" : "BROKEN ARROW", "loc" : [ -95.81433199999999, 35.990812 ], "pop" : 23493, "state" : "OK" }
+{ "_id" : "74012", "city" : "BROKEN ARROW", "loc" : [ -95.807863, 36.04466 ], "pop" : 35399, "state" : "OK" }
+{ "_id" : "74014", "city" : "BROKEN ARROW", "loc" : [ -95.722269, 36.054435 ], "pop" : 17246, "state" : "OK" }
+{ "_id" : "74015", "city" : "CATOOSA", "loc" : [ -95.727321, 36.17208 ], "pop" : 7103, "state" : "OK" }
+{ "_id" : "74016", "city" : "CHELSEA", "loc" : [ -95.448871, 36.535586 ], "pop" : 3789, "state" : "OK" }
+{ "_id" : "74017", "city" : "CLAREMORE", "loc" : [ -95.598539, 36.324208 ], "pop" : 29964, "state" : "OK" }
+{ "_id" : "74020", "city" : "CLEVELAND", "loc" : [ -96.42300899999999, 36.255334 ], "pop" : 8636, "state" : "OK" }
+{ "_id" : "74021", "city" : "COLLINSVILLE", "loc" : [ -95.84688, 36.370069 ], "pop" : 8944, "state" : "OK" }
+{ "_id" : "74022", "city" : "COPAN", "loc" : [ -95.912987, 36.906181 ], "pop" : 1965, "state" : "OK" }
+{ "_id" : "74023", "city" : "CUSHING", "loc" : [ -96.752628, 35.982174 ], "pop" : 9961, "state" : "OK" }
+{ "_id" : "74027", "city" : "DELAWARE", "loc" : [ -95.61809599999999, 36.780382 ], "pop" : 1275, "state" : "OK" }
+{ "_id" : "74028", "city" : "DEPEW", "loc" : [ -96.489665, 35.756141 ], "pop" : 2224, "state" : "OK" }
+{ "_id" : "74029", "city" : "DEWEY", "loc" : [ -95.93454, 36.80125 ], "pop" : 5217, "state" : "OK" }
+{ "_id" : "74030", "city" : "DRUMRIGHT", "loc" : [ -96.519789, 35.993136 ], "pop" : 7886, "state" : "OK" }
+{ "_id" : "74032", "city" : "GLENCOE", "loc" : [ -96.91384499999999, 36.215815 ], "pop" : 951, "state" : "OK" }
+{ "_id" : "74033", "city" : "GLENPOOL", "loc" : [ -95.999709, 35.959106 ], "pop" : 6575, "state" : "OK" }
+{ "_id" : "74035", "city" : "HOMINY", "loc" : [ -96.38784800000001, 36.411068 ], "pop" : 3410, "state" : "OK" }
+{ "_id" : "74036", "city" : "INOLA", "loc" : [ -95.520456, 36.150315 ], "pop" : 4268, "state" : "OK" }
+{ "_id" : "74037", "city" : "JENKS", "loc" : [ -95.97971099999999, 36.014834 ], "pop" : 8086, "state" : "OK" }
+{ "_id" : "74038", "city" : "JENNINGS", "loc" : [ -96.573227, 36.186302 ], "pop" : 766, "state" : "OK" }
+{ "_id" : "74039", "city" : "KELLYVILLE", "loc" : [ -96.218009, 35.917075 ], "pop" : 2648, "state" : "OK" }
+{ "_id" : "74042", "city" : "LENAPAH", "loc" : [ -95.623316, 36.880055 ], "pop" : 692, "state" : "OK" }
+{ "_id" : "74044", "city" : "MANNFORD", "loc" : [ -96.357552, 36.092688 ], "pop" : 6963, "state" : "OK" }
+{ "_id" : "74045", "city" : "MARAMEC", "loc" : [ -96.68441, 36.217465 ], "pop" : 290, "state" : "OK" }
+{ "_id" : "74047", "city" : "MOUNDS", "loc" : [ -96.068513, 35.912919 ], "pop" : 5412, "state" : "OK" }
+{ "_id" : "74048", "city" : "NOWATA", "loc" : [ -95.640421, 36.694565 ], "pop" : 5688, "state" : "OK" }
+{ "_id" : "74051", "city" : "OCHELATA", "loc" : [ -95.969143, 36.594655 ], "pop" : 1381, "state" : "OK" }
+{ "_id" : "74053", "city" : "OOLOGAH", "loc" : [ -95.72901, 36.443723 ], "pop" : 3369, "state" : "OK" }
+{ "_id" : "74054", "city" : "OSAGE", "loc" : [ -96.377411, 36.283156 ], "pop" : 633, "state" : "OK" }
+{ "_id" : "74055", "city" : "OWASSO", "loc" : [ -95.82215100000001, 36.286258 ], "pop" : 20281, "state" : "OK" }
+{ "_id" : "74056", "city" : "PAWHUSKA", "loc" : [ -96.31209, 36.690424 ], "pop" : 6039, "state" : "OK" }
+{ "_id" : "74058", "city" : "PAWNEE", "loc" : [ -96.79227, 36.336197 ], "pop" : 4209, "state" : "OK" }
+{ "_id" : "74059", "city" : "PERKINS", "loc" : [ -97.044059, 35.97684 ], "pop" : 3246, "state" : "OK" }
+{ "_id" : "74060", "city" : "PRUE", "loc" : [ -96.27007399999999, 36.250125 ], "pop" : 712, "state" : "OK" }
+{ "_id" : "74061", "city" : "RAMONA", "loc" : [ -95.89622, 36.575245 ], "pop" : 1628, "state" : "OK" }
+{ "_id" : "74062", "city" : "RIPLEY", "loc" : [ -96.89667, 35.998491 ], "pop" : 839, "state" : "OK" }
+{ "_id" : "74063", "city" : "SAND SPRINGS", "loc" : [ -96.142601, 36.13414 ], "pop" : 25745, "state" : "OK" }
+{ "_id" : "74066", "city" : "SAPULPA", "loc" : [ -96.11060999999999, 36.00297 ], "pop" : 24409, "state" : "OK" }
+{ "_id" : "74070", "city" : "SKIATOOK", "loc" : [ -96.012325, 36.372495 ], "pop" : 8619, "state" : "OK" }
+{ "_id" : "74072", "city" : "S COFFEYVILLE", "loc" : [ -95.606509, 36.983684 ], "pop" : 1397, "state" : "OK" }
+{ "_id" : "74073", "city" : "SPERRY", "loc" : [ -95.980368, 36.29547 ], "pop" : 1979, "state" : "OK" }
+{ "_id" : "74074", "city" : "STILLWATER", "loc" : [ -97.060868, 36.104349 ], "pop" : 25259, "state" : "OK" }
+{ "_id" : "74075", "city" : "STILLWATER", "loc" : [ -97.063035, 36.139584 ], "pop" : 18955, "state" : "OK" }
+{ "_id" : "74079", "city" : "KENDRICK", "loc" : [ -96.684377, 35.782389 ], "pop" : 4898, "state" : "OK" }
+{ "_id" : "74080", "city" : "TALALA", "loc" : [ -95.714203, 36.542915 ], "pop" : 883, "state" : "OK" }
+{ "_id" : "74081", "city" : "TERLTON", "loc" : [ -96.48756899999999, 36.188856 ], "pop" : 915, "state" : "OK" }
+{ "_id" : "74083", "city" : "WANN", "loc" : [ -95.776752, 36.940211 ], "pop" : 977, "state" : "OK" }
+{ "_id" : "74084", "city" : "WYNONA", "loc" : [ -96.368891, 36.50847 ], "pop" : 1815, "state" : "OK" }
+{ "_id" : "74085", "city" : "YALE", "loc" : [ -96.702209, 36.110065 ], "pop" : 2296, "state" : "OK" }
+{ "_id" : "74103", "city" : "TULSA", "loc" : [ -95.99542599999999, 36.153858 ], "pop" : 1105, "state" : "OK" }
+{ "_id" : "74104", "city" : "TULSA", "loc" : [ -95.952566, 36.146446 ], "pop" : 13247, "state" : "OK" }
+{ "_id" : "74105", "city" : "TULSA", "loc" : [ -95.96554399999999, 36.094808 ], "pop" : 29466, "state" : "OK" }
+{ "_id" : "74106", "city" : "TULSA", "loc" : [ -95.985956, 36.188296 ], "pop" : 18108, "state" : "OK" }
+{ "_id" : "74107", "city" : "TULSA", "loc" : [ -96.02444800000001, 36.104199 ], "pop" : 18899, "state" : "OK" }
+{ "_id" : "74108", "city" : "TULSA", "loc" : [ -95.792311, 36.149893 ], "pop" : 8018, "state" : "OK" }
+{ "_id" : "74110", "city" : "TULSA", "loc" : [ -95.95249200000001, 36.180296 ], "pop" : 14224, "state" : "OK" }
+{ "_id" : "74112", "city" : "TULSA", "loc" : [ -95.90703600000001, 36.147039 ], "pop" : 21754, "state" : "OK" }
+{ "_id" : "74114", "city" : "TULSA", "loc" : [ -95.94079600000001, 36.126152 ], "pop" : 17190, "state" : "OK" }
+{ "_id" : "74115", "city" : "TULSA", "loc" : [ -95.91118299999999, 36.175408 ], "pop" : 22100, "state" : "OK" }
+{ "_id" : "74116", "city" : "TULSA", "loc" : [ -95.847695, 36.174994 ], "pop" : 2067, "state" : "OK" }
+{ "_id" : "74117", "city" : "TULSA", "loc" : [ -95.910768, 36.27949 ], "pop" : 824, "state" : "OK" }
+{ "_id" : "74119", "city" : "TULSA", "loc" : [ -95.990194, 36.140688 ], "pop" : 4059, "state" : "OK" }
+{ "_id" : "74120", "city" : "TULSA", "loc" : [ -95.973373, 36.144228 ], "pop" : 5612, "state" : "OK" }
+{ "_id" : "74126", "city" : "TULSA", "loc" : [ -95.99311299999999, 36.238288 ], "pop" : 13636, "state" : "OK" }
+{ "_id" : "74127", "city" : "TULSA", "loc" : [ -96.03107, 36.157636 ], "pop" : 17336, "state" : "OK" }
+{ "_id" : "74128", "city" : "TULSA", "loc" : [ -95.851377, 36.145927 ], "pop" : 12260, "state" : "OK" }
+{ "_id" : "74129", "city" : "TULSA", "loc" : [ -95.865354, 36.125928 ], "pop" : 17278, "state" : "OK" }
+{ "_id" : "74130", "city" : "TULSA", "loc" : [ -95.959649, 36.239481 ], "pop" : 2553, "state" : "OK" }
+{ "_id" : "74131", "city" : "TULSA", "loc" : [ -96.06022900000001, 36.05566 ], "pop" : 4057, "state" : "OK" }
+{ "_id" : "74132", "city" : "TULSA", "loc" : [ -96.025104, 36.063971 ], "pop" : 5290, "state" : "OK" }
+{ "_id" : "74133", "city" : "TULSA", "loc" : [ -95.884062, 36.046717 ], "pop" : 30499, "state" : "OK" }
+{ "_id" : "74134", "city" : "TULSA", "loc" : [ -95.822472, 36.116223 ], "pop" : 12607, "state" : "OK" }
+{ "_id" : "74135", "city" : "TULSA", "loc" : [ -95.922805, 36.097603 ], "pop" : 21783, "state" : "OK" }
+{ "_id" : "74136", "city" : "TULSA", "loc" : [ -95.945178, 36.060548 ], "pop" : 29192, "state" : "OK" }
+{ "_id" : "74137", "city" : "TULSA", "loc" : [ -95.93059700000001, 36.028426 ], "pop" : 15434, "state" : "OK" }
+{ "_id" : "74145", "city" : "TULSA", "loc" : [ -95.885576, 36.093433 ], "pop" : 17509, "state" : "OK" }
+{ "_id" : "74146", "city" : "TULSA", "loc" : [ -95.85061, 36.109293 ], "pop" : 12965, "state" : "OK" }
+{ "_id" : "74301", "city" : "VINITA", "loc" : [ -95.138164, 36.633353 ], "pop" : 8987, "state" : "OK" }
+{ "_id" : "74330", "city" : "ADAIR", "loc" : [ -95.27319900000001, 36.411453 ], "pop" : 4938, "state" : "OK" }
+{ "_id" : "74331", "city" : "BERNICE", "loc" : [ -94.90749099999999, 36.630072 ], "pop" : 5352, "state" : "OK" }
+{ "_id" : "74332", "city" : "BIG CABIN", "loc" : [ -95.274736, 36.607931 ], "pop" : 2634, "state" : "OK" }
+{ "_id" : "74333", "city" : "BLUEJACKET", "loc" : [ -95.101844, 36.797453 ], "pop" : 1005, "state" : "OK" }
+{ "_id" : "74337", "city" : "CHOUTEAU", "loc" : [ -95.34157399999999, 36.166924 ], "pop" : 3763, "state" : "OK" }
+{ "_id" : "74338", "city" : "COLCORD", "loc" : [ -94.654675, 36.233349 ], "pop" : 4202, "state" : "OK" }
+{ "_id" : "74339", "city" : "COMMERCE", "loc" : [ -94.872983, 36.933063 ], "pop" : 2624, "state" : "OK" }
+{ "_id" : "74342", "city" : "EUCHA", "loc" : [ -94.92300299999999, 36.398709 ], "pop" : 2935, "state" : "OK" }
+{ "_id" : "74343", "city" : "FAIRLAND", "loc" : [ -94.827934, 36.74178 ], "pop" : 2003, "state" : "OK" }
+{ "_id" : "74344", "city" : "GROVE", "loc" : [ -94.756536, 36.592869 ], "pop" : 8408, "state" : "OK" }
+{ "_id" : "74346", "city" : "JAY", "loc" : [ -94.776309, 36.436343 ], "pop" : 5073, "state" : "OK" }
+{ "_id" : "74347", "city" : "KANSAS", "loc" : [ -94.81141599999999, 36.216114 ], "pop" : 1594, "state" : "OK" }
+{ "_id" : "74352", "city" : "LOCUST GROVE", "loc" : [ -95.168854, 36.181902 ], "pop" : 5856, "state" : "OK" }
+{ "_id" : "74354", "city" : "MIAMI", "loc" : [ -94.87186, 36.876377 ], "pop" : 16679, "state" : "OK" }
+{ "_id" : "74359", "city" : "OAKS", "loc" : [ -94.850206, 36.168663 ], "pop" : 327, "state" : "OK" }
+{ "_id" : "74360", "city" : "PICHER", "loc" : [ -94.817301, 36.979961 ], "pop" : 3019, "state" : "OK" }
+{ "_id" : "74361", "city" : "PRYOR", "loc" : [ -95.31294200000001, 36.292112 ], "pop" : 11669, "state" : "OK" }
+{ "_id" : "74363", "city" : "QUAPAW", "loc" : [ -94.742983, 36.928248 ], "pop" : 2465, "state" : "OK" }
+{ "_id" : "74364", "city" : "LEACH", "loc" : [ -94.993362, 36.211263 ], "pop" : 1222, "state" : "OK" }
+{ "_id" : "74365", "city" : "SALINA", "loc" : [ -95.11577200000001, 36.311597 ], "pop" : 3432, "state" : "OK" }
+{ "_id" : "74366", "city" : "SPAVINAW", "loc" : [ -95.028465, 36.415548 ], "pop" : 1252, "state" : "OK" }
+{ "_id" : "74367", "city" : "STRANG", "loc" : [ -95.070768, 36.463861 ], "pop" : 2240, "state" : "OK" }
+{ "_id" : "74368", "city" : "TWIN OAKS", "loc" : [ -94.854444, 36.191616 ], "pop" : 435, "state" : "OK" }
+{ "_id" : "74369", "city" : "WELCH", "loc" : [ -95.12945499999999, 36.902022 ], "pop" : 1746, "state" : "OK" }
+{ "_id" : "74370", "city" : "WYANDOTTE", "loc" : [ -94.700239, 36.779616 ], "pop" : 2500, "state" : "OK" }
+{ "_id" : "74401", "city" : "MUSKOGEE", "loc" : [ -95.375491, 35.730661 ], "pop" : 21813, "state" : "OK" }
+{ "_id" : "74403", "city" : "MUSKOGEE", "loc" : [ -95.34490700000001, 35.741057 ], "pop" : 24787, "state" : "OK" }
+{ "_id" : "74421", "city" : "BEGGS", "loc" : [ -96.026398, 35.789595 ], "pop" : 4590, "state" : "OK" }
+{ "_id" : "74422", "city" : "BOYNTON", "loc" : [ -95.66003600000001, 35.657652 ], "pop" : 762, "state" : "OK" }
+{ "_id" : "74423", "city" : "BRAGGS", "loc" : [ -95.203326, 35.657395 ], "pop" : 671, "state" : "OK" }
+{ "_id" : "74425", "city" : "CANADIAN", "loc" : [ -95.653042, 35.159258 ], "pop" : 1339, "state" : "OK" }
+{ "_id" : "74426", "city" : "CHECOTAH", "loc" : [ -95.535038, 35.435786 ], "pop" : 9683, "state" : "OK" }
+{ "_id" : "74427", "city" : "COOKSON", "loc" : [ -94.913205, 35.711622 ], "pop" : 1312, "state" : "OK" }
+{ "_id" : "74428", "city" : "COUNCIL HILL", "loc" : [ -95.711326, 35.532175 ], "pop" : 992, "state" : "OK" }
+{ "_id" : "74429", "city" : "COWETA", "loc" : [ -95.652597, 35.957835 ], "pop" : 9873, "state" : "OK" }
+{ "_id" : "74432", "city" : "EUFAULA", "loc" : [ -95.647227, 35.29114 ], "pop" : 5069, "state" : "OK" }
+{ "_id" : "74434", "city" : "FORT GIBSON", "loc" : [ -95.22973399999999, 35.794285 ], "pop" : 5233, "state" : "OK" }
+{ "_id" : "74435", "city" : "GORE", "loc" : [ -95.10947400000001, 35.541772 ], "pop" : 1167, "state" : "OK" }
+{ "_id" : "74436", "city" : "HASKELL", "loc" : [ -95.683981, 35.810752 ], "pop" : 3467, "state" : "OK" }
+{ "_id" : "74437", "city" : "HOFFMAN", "loc" : [ -95.976187, 35.454476 ], "pop" : 10729, "state" : "OK" }
+{ "_id" : "74440", "city" : "HOYT", "loc" : [ -95.29938199999999, 35.268466 ], "pop" : 65, "state" : "OK" }
+{ "_id" : "74441", "city" : "HULBERT", "loc" : [ -95.16509499999999, 35.925415 ], "pop" : 4597, "state" : "OK" }
+{ "_id" : "74442", "city" : "INDIANOLA", "loc" : [ -95.784479, 35.093724 ], "pop" : 2014, "state" : "OK" }
+{ "_id" : "74445", "city" : "MORRIS", "loc" : [ -95.83186000000001, 35.661877 ], "pop" : 3028, "state" : "OK" }
+{ "_id" : "74447", "city" : "OKMULGEE", "loc" : [ -95.96966999999999, 35.628805 ], "pop" : 18109, "state" : "OK" }
+{ "_id" : "74450", "city" : "OKTAHA", "loc" : [ -95.485591, 35.625014 ], "pop" : 2624, "state" : "OK" }
+{ "_id" : "74451", "city" : "PARK HILL", "loc" : [ -94.982173, 35.797686 ], "pop" : 4003, "state" : "OK" }
+{ "_id" : "74452", "city" : "PEGGS", "loc" : [ -94.991928, 36.059061 ], "pop" : 3896, "state" : "OK" }
+{ "_id" : "74454", "city" : "PORTER", "loc" : [ -95.50819300000001, 35.85674 ], "pop" : 2705, "state" : "OK" }
+{ "_id" : "74455", "city" : "PORUM", "loc" : [ -95.260661, 35.363059 ], "pop" : 2976, "state" : "OK" }
+{ "_id" : "74457", "city" : "PROCTOR", "loc" : [ -94.744159, 35.967111 ], "pop" : 443, "state" : "OK" }
+{ "_id" : "74461", "city" : "STIDHAM", "loc" : [ -95.705575, 35.381389 ], "pop" : 286, "state" : "OK" }
+{ "_id" : "74462", "city" : "STIGLER", "loc" : [ -95.10706999999999, 35.268561 ], "pop" : 4932, "state" : "OK" }
+{ "_id" : "74463", "city" : "TAFT", "loc" : [ -95.54935999999999, 35.758059 ], "pop" : 1822, "state" : "OK" }
+{ "_id" : "74464", "city" : "TAHLEQUAH", "loc" : [ -94.97873, 35.909385 ], "pop" : 17092, "state" : "OK" }
+{ "_id" : "74467", "city" : "WAGONER", "loc" : [ -95.353956, 35.954864 ], "pop" : 13813, "state" : "OK" }
+{ "_id" : "74469", "city" : "WARNER", "loc" : [ -95.306434, 35.494546 ], "pop" : 2501, "state" : "OK" }
+{ "_id" : "74470", "city" : "WEBBERS FALLS", "loc" : [ -95.165881, 35.513787 ], "pop" : 1530, "state" : "OK" }
+{ "_id" : "74471", "city" : "WELLING", "loc" : [ -94.865326, 35.881917 ], "pop" : 3149, "state" : "OK" }
+{ "_id" : "74472", "city" : "WHITEFIELD", "loc" : [ -95.237493, 35.25114 ], "pop" : 283, "state" : "OK" }
+{ "_id" : "74501", "city" : "MCALESTER", "loc" : [ -95.759168, 34.926233 ], "pop" : 23786, "state" : "OK" }
+{ "_id" : "74523", "city" : "ANTLERS", "loc" : [ -95.625412, 34.234923 ], "pop" : 5432, "state" : "OK" }
+{ "_id" : "74525", "city" : "ATOKA", "loc" : [ -96.14182700000001, 34.34451 ], "pop" : 7450, "state" : "OK" }
+{ "_id" : "74528", "city" : "BLANCO", "loc" : [ -95.792069, 34.762151 ], "pop" : 289, "state" : "OK" }
+{ "_id" : "74531", "city" : "CALVIN", "loc" : [ -96.270972, 34.877987 ], "pop" : 779, "state" : "OK" }
+{ "_id" : "74533", "city" : "CANEY", "loc" : [ -96.258364, 34.222112 ], "pop" : 1443, "state" : "OK" }
+{ "_id" : "74534", "city" : "CENTRAHOMA", "loc" : [ -96.33858499999999, 34.606642 ], "pop" : 435, "state" : "OK" }
+{ "_id" : "74536", "city" : "CLAYTON", "loc" : [ -95.379981, 34.590591 ], "pop" : 1635, "state" : "OK" }
+{ "_id" : "74538", "city" : "COALGATE", "loc" : [ -96.21672599999999, 34.534408 ], "pop" : 3908, "state" : "OK" }
+{ "_id" : "74540", "city" : "DAISY", "loc" : [ -95.70877299999999, 34.538357 ], "pop" : 147, "state" : "OK" }
+{ "_id" : "74542", "city" : "FARRIS", "loc" : [ -95.841368, 34.255833 ], "pop" : 1226, "state" : "OK" }
+{ "_id" : "74543", "city" : "FINLEY", "loc" : [ -95.53851899999999, 34.340654 ], "pop" : 149, "state" : "OK" }
+{ "_id" : "74547", "city" : "HARTSHORNE", "loc" : [ -95.573972, 34.84517 ], "pop" : 5133, "state" : "OK" }
+{ "_id" : "74548", "city" : "HAYWOOD", "loc" : [ -95.96715399999999, 34.951102 ], "pop" : 2185, "state" : "OK" }
+{ "_id" : "74549", "city" : "HONOBIA", "loc" : [ -94.991557, 34.592604 ], "pop" : 125, "state" : "OK" }
+{ "_id" : "74552", "city" : "KINTA", "loc" : [ -95.317545, 35.197065 ], "pop" : 2676, "state" : "OK" }
+{ "_id" : "74553", "city" : "KIOWA", "loc" : [ -95.93283599999999, 34.727755 ], "pop" : 1390, "state" : "OK" }
+{ "_id" : "74555", "city" : "LANE", "loc" : [ -95.968515, 34.269122 ], "pop" : 1001, "state" : "OK" }
+{ "_id" : "74557", "city" : "MOYERS", "loc" : [ -95.663881, 34.338648 ], "pop" : 280, "state" : "OK" }
+{ "_id" : "74558", "city" : "NASHOBA", "loc" : [ -95.20746699999999, 34.507204 ], "pop" : 534, "state" : "OK" }
+{ "_id" : "74560", "city" : "PITTSBURG", "loc" : [ -95.84390500000001, 34.69748 ], "pop" : 536, "state" : "OK" }
+{ "_id" : "74561", "city" : "QUINTON", "loc" : [ -95.467085, 35.154666 ], "pop" : 3909, "state" : "OK" }
+{ "_id" : "74562", "city" : "RATTAN", "loc" : [ -95.344235, 34.245417 ], "pop" : 1648, "state" : "OK" }
+{ "_id" : "74563", "city" : "RED OAK", "loc" : [ -95.09043200000001, 34.942174 ], "pop" : 2167, "state" : "OK" }
+{ "_id" : "74567", "city" : "SNOW", "loc" : [ -95.42783300000001, 34.377963 ], "pop" : 317, "state" : "OK" }
+{ "_id" : "74569", "city" : "STRINGTOWN", "loc" : [ -96.00024500000001, 34.467597 ], "pop" : 755, "state" : "OK" }
+{ "_id" : "74570", "city" : "STUART", "loc" : [ -96.138105, 34.882581 ], "pop" : 751, "state" : "OK" }
+{ "_id" : "74571", "city" : "TALIHINA", "loc" : [ -94.99781299999999, 34.73812 ], "pop" : 2930, "state" : "OK" }
+{ "_id" : "74572", "city" : "TUPELO", "loc" : [ -96.42736499999999, 34.559809 ], "pop" : 1388, "state" : "OK" }
+{ "_id" : "74574", "city" : "TUSKAHOMA", "loc" : [ -95.220798, 34.734778 ], "pop" : 2491, "state" : "OK" }
+{ "_id" : "74576", "city" : "WARDVILLE", "loc" : [ -96.02095799999999, 34.568791 ], "pop" : 756, "state" : "OK" }
+{ "_id" : "74577", "city" : "WHITESBORO", "loc" : [ -94.86997700000001, 34.684311 ], "pop" : 219, "state" : "OK" }
+{ "_id" : "74578", "city" : "WILBURTON", "loc" : [ -95.33889600000001, 34.912805 ], "pop" : 5866, "state" : "OK" }
+{ "_id" : "74601", "city" : "PONCA CITY", "loc" : [ -97.07840899999999, 36.703104 ], "pop" : 24347, "state" : "OK" }
+{ "_id" : "74604", "city" : "PONCA CITY", "loc" : [ -97.04544300000001, 36.729916 ], "pop" : 9327, "state" : "OK" }
+{ "_id" : "74630", "city" : "BILLINGS", "loc" : [ -97.41888899999999, 36.524609 ], "pop" : 855, "state" : "OK" }
+{ "_id" : "74631", "city" : "BLACKWELL", "loc" : [ -97.28669499999999, 36.800574 ], "pop" : 8480, "state" : "OK" }
+{ "_id" : "74632", "city" : "BRAMAN", "loc" : [ -97.30823100000001, 36.933054 ], "pop" : 746, "state" : "OK" }
+{ "_id" : "74633", "city" : "BURBANK", "loc" : [ -96.786873, 36.696583 ], "pop" : 641, "state" : "OK" }
+{ "_id" : "74636", "city" : "DEER CREEK", "loc" : [ -97.513581, 36.80482 ], "pop" : 260, "state" : "OK" }
+{ "_id" : "74637", "city" : "FAIRFAX", "loc" : [ -96.699691, 36.557687 ], "pop" : 2307, "state" : "OK" }
+{ "_id" : "74640", "city" : "HUNTER", "loc" : [ -97.64250699999999, 36.560342 ], "pop" : 533, "state" : "OK" }
+{ "_id" : "74641", "city" : "KAW CITY", "loc" : [ -96.89886199999999, 36.786663 ], "pop" : 876, "state" : "OK" }
+{ "_id" : "74643", "city" : "LAMONT", "loc" : [ -97.56009299999999, 36.693884 ], "pop" : 650, "state" : "OK" }
+{ "_id" : "74644", "city" : "MARLAND", "loc" : [ -97.09759200000001, 36.559067 ], "pop" : 639, "state" : "OK" }
+{ "_id" : "74646", "city" : "NARDIN", "loc" : [ -97.432458, 36.815517 ], "pop" : 262, "state" : "OK" }
+{ "_id" : "74647", "city" : "PECKHAM", "loc" : [ -97.05132999999999, 36.887425 ], "pop" : 3274, "state" : "OK" }
+{ "_id" : "74650", "city" : "RALSTON", "loc" : [ -96.775481, 36.499228 ], "pop" : 756, "state" : "OK" }
+{ "_id" : "74651", "city" : "RED ROCK", "loc" : [ -97.16402100000001, 36.474754 ], "pop" : 775, "state" : "OK" }
+{ "_id" : "74652", "city" : "FORAKER", "loc" : [ -96.67496199999999, 36.814915 ], "pop" : 1143, "state" : "OK" }
+{ "_id" : "74653", "city" : "TONKAWA", "loc" : [ -97.30634000000001, 36.68062 ], "pop" : 4002, "state" : "OK" }
+{ "_id" : "74701", "city" : "DURANT", "loc" : [ -96.384705, 34.00609 ], "pop" : 17179, "state" : "OK" }
+{ "_id" : "74723", "city" : "BENNINGTON", "loc" : [ -96.01877399999999, 33.977085 ], "pop" : 1411, "state" : "OK" }
+{ "_id" : "74724", "city" : "BETHEL", "loc" : [ -94.87812599999999, 34.358443 ], "pop" : 1468, "state" : "OK" }
+{ "_id" : "74726", "city" : "BOKCHITO", "loc" : [ -96.162097, 33.985913 ], "pop" : 1812, "state" : "OK" }
+{ "_id" : "74727", "city" : "BOSWELL", "loc" : [ -95.84031299999999, 34.024475 ], "pop" : 2162, "state" : "OK" }
+{ "_id" : "74728", "city" : "BROKEN BOW", "loc" : [ -94.76229600000001, 34.026991 ], "pop" : 10436, "state" : "OK" }
+{ "_id" : "74729", "city" : "CADDO", "loc" : [ -96.260017, 34.115688 ], "pop" : 1474, "state" : "OK" }
+{ "_id" : "74730", "city" : "CALERA", "loc" : [ -96.410205, 33.928872 ], "pop" : 2448, "state" : "OK" }
+{ "_id" : "74731", "city" : "CARTWRIGHT", "loc" : [ -96.55190899999999, 33.884552 ], "pop" : 1796, "state" : "OK" }
+{ "_id" : "74733", "city" : "COLBERT", "loc" : [ -96.495345, 33.857516 ], "pop" : 2267, "state" : "OK" }
+{ "_id" : "74734", "city" : "EAGLETOWN", "loc" : [ -94.559557, 34.036358 ], "pop" : 1237, "state" : "OK" }
+{ "_id" : "74735", "city" : "FORT TOWSON", "loc" : [ -95.253015, 34.051968 ], "pop" : 2249, "state" : "OK" }
+{ "_id" : "74736", "city" : "GARVIN", "loc" : [ -94.93230800000001, 33.920512 ], "pop" : 804, "state" : "OK" }
+{ "_id" : "74738", "city" : "GRANT", "loc" : [ -95.489324, 33.930239 ], "pop" : 740, "state" : "OK" }
+{ "_id" : "74740", "city" : "TOM", "loc" : [ -94.58177499999999, 33.787507 ], "pop" : 1861, "state" : "OK" }
+{ "_id" : "74741", "city" : "HENDRIX", "loc" : [ -96.35813400000001, 33.801582 ], "pop" : 1812, "state" : "OK" }
+{ "_id" : "74743", "city" : "HUGO", "loc" : [ -95.513876, 34.011339 ], "pop" : 8804, "state" : "OK" }
+{ "_id" : "74745", "city" : "IDABEL", "loc" : [ -94.802012, 33.88512 ], "pop" : 10294, "state" : "OK" }
+{ "_id" : "74748", "city" : "KENEFIC", "loc" : [ -96.38866299999999, 34.131377 ], "pop" : 370, "state" : "OK" }
+{ "_id" : "74754", "city" : "RINGOLD", "loc" : [ -95.070387, 34.179892 ], "pop" : 97, "state" : "OK" }
+{ "_id" : "74755", "city" : "RUFE", "loc" : [ -95.136011, 34.161684 ], "pop" : 244, "state" : "OK" }
+{ "_id" : "74756", "city" : "SAWYER", "loc" : [ -95.355833, 34.027726 ], "pop" : 421, "state" : "OK" }
+{ "_id" : "74759", "city" : "SOPER", "loc" : [ -95.69156599999999, 34.03659 ], "pop" : 935, "state" : "OK" }
+{ "_id" : "74760", "city" : "SPENCERVILLE", "loc" : [ -95.38346799999999, 34.13263 ], "pop" : 246, "state" : "OK" }
+{ "_id" : "74764", "city" : "VALLIANT", "loc" : [ -95.068625, 34.009056 ], "pop" : 3875, "state" : "OK" }
+{ "_id" : "74766", "city" : "WRIGHT CITY", "loc" : [ -94.99288900000001, 34.079922 ], "pop" : 1879, "state" : "OK" }
+{ "_id" : "74801", "city" : "SHAWNEE", "loc" : [ -96.931321, 35.34907 ], "pop" : 40076, "state" : "OK" }
+{ "_id" : "74820", "city" : "ADA", "loc" : [ -96.69235999999999, 34.780044 ], "pop" : 24967, "state" : "OK" }
+{ "_id" : "74824", "city" : "AGRA", "loc" : [ -96.87794, 35.882548 ], "pop" : 1327, "state" : "OK" }
+{ "_id" : "74825", "city" : "ALLEN", "loc" : [ -96.55846200000001, 34.850176 ], "pop" : 4803, "state" : "OK" }
+{ "_id" : "74826", "city" : "ASHER", "loc" : [ -96.87632600000001, 34.984862 ], "pop" : 970, "state" : "OK" }
+{ "_id" : "74827", "city" : "ATWOOD", "loc" : [ -96.357703, 34.919194 ], "pop" : 723, "state" : "OK" }
+{ "_id" : "74829", "city" : "BOLEY", "loc" : [ -96.470386, 35.491328 ], "pop" : 1437, "state" : "OK" }
+{ "_id" : "74831", "city" : "BYARS", "loc" : [ -97.099723, 34.890397 ], "pop" : 1133, "state" : "OK" }
+{ "_id" : "74832", "city" : "CARNEY", "loc" : [ -97.015942, 35.805381 ], "pop" : 663, "state" : "OK" }
+{ "_id" : "74833", "city" : "CASTLE", "loc" : [ -96.379133, 35.473235 ], "pop" : 168, "state" : "OK" }
+{ "_id" : "74834", "city" : "CHANDLER", "loc" : [ -96.858266, 35.704253 ], "pop" : 6506, "state" : "OK" }
+{ "_id" : "74835", "city" : "CLEARVIEW", "loc" : [ -96.171404, 35.392585 ], "pop" : 227, "state" : "OK" }
+{ "_id" : "74839", "city" : "DUSTIN", "loc" : [ -96.057271, 35.251937 ], "pop" : 893, "state" : "OK" }
+{ "_id" : "74840", "city" : "EARLSBORO", "loc" : [ -96.80409299999999, 35.262792 ], "pop" : 572, "state" : "OK" }
+{ "_id" : "74842", "city" : "FITTSTOWN", "loc" : [ -96.649458, 34.630134 ], "pop" : 759, "state" : "OK" }
+{ "_id" : "74843", "city" : "FITZHUGH", "loc" : [ -96.77448699999999, 34.661545 ], "pop" : 201, "state" : "OK" }
+{ "_id" : "74845", "city" : "VERNON", "loc" : [ -95.89579500000001, 35.208526 ], "pop" : 638, "state" : "OK" }
+{ "_id" : "74848", "city" : "HOLDENVILLE", "loc" : [ -96.37696800000001, 35.083935 ], "pop" : 7471, "state" : "OK" }
+{ "_id" : "74849", "city" : "KONAWA", "loc" : [ -96.734279, 34.970824 ], "pop" : 2800, "state" : "OK" }
+{ "_id" : "74850", "city" : "LAMAR", "loc" : [ -96.114226, 35.083557 ], "pop" : 225, "state" : "OK" }
+{ "_id" : "74851", "city" : "MC LOUD", "loc" : [ -97.105178, 35.41907 ], "pop" : 3334, "state" : "OK" }
+{ "_id" : "74852", "city" : "MACOMB", "loc" : [ -97.033964, 35.12052 ], "pop" : 1005, "state" : "OK" }
+{ "_id" : "74854", "city" : "MAUD", "loc" : [ -96.762686, 35.129224 ], "pop" : 4144, "state" : "OK" }
+{ "_id" : "74855", "city" : "MEEKER", "loc" : [ -96.998052, 35.521111 ], "pop" : 6180, "state" : "OK" }
+{ "_id" : "74856", "city" : "MILL CREEK", "loc" : [ -96.788419, 34.309754 ], "pop" : 1510, "state" : "OK" }
+{ "_id" : "74857", "city" : "NEWALLA", "loc" : [ -97.197123, 35.373415 ], "pop" : 7768, "state" : "OK" }
+{ "_id" : "74859", "city" : "BEARDEN", "loc" : [ -96.306788, 35.447516 ], "pop" : 5792, "state" : "OK" }
+{ "_id" : "74860", "city" : "PADEN", "loc" : [ -96.571921, 35.518171 ], "pop" : 1508, "state" : "OK" }
+{ "_id" : "74864", "city" : "PRAGUE", "loc" : [ -96.700879, 35.510482 ], "pop" : 4504, "state" : "OK" }
+{ "_id" : "74865", "city" : "ROFF", "loc" : [ -96.842313, 34.615294 ], "pop" : 1316, "state" : "OK" }
+{ "_id" : "74867", "city" : "SASAKWA", "loc" : [ -96.538706, 34.950982 ], "pop" : 854, "state" : "OK" }
+{ "_id" : "74868", "city" : "SEMINOLE", "loc" : [ -96.668307, 35.252095 ], "pop" : 11673, "state" : "OK" }
+{ "_id" : "74869", "city" : "SPARKS", "loc" : [ -96.81626900000001, 35.61378 ], "pop" : 330, "state" : "OK" }
+{ "_id" : "74871", "city" : "HARDEN CITY", "loc" : [ -96.54289, 34.666194 ], "pop" : 2317, "state" : "OK" }
+{ "_id" : "74872", "city" : "STRATFORD", "loc" : [ -96.976277, 34.771412 ], "pop" : 2773, "state" : "OK" }
+{ "_id" : "74873", "city" : "TECUMSEH", "loc" : [ -96.966713, 35.25023 ], "pop" : 9203, "state" : "OK" }
+{ "_id" : "74875", "city" : "TRYON", "loc" : [ -96.9984, 35.863151 ], "pop" : 1356, "state" : "OK" }
+{ "_id" : "74878", "city" : "WANETTE", "loc" : [ -97.0419, 34.998313 ], "pop" : 1288, "state" : "OK" }
+{ "_id" : "74880", "city" : "WELEETKA", "loc" : [ -96.113609, 35.341582 ], "pop" : 2133, "state" : "OK" }
+{ "_id" : "74881", "city" : "WELLSTON", "loc" : [ -97.059685, 35.675738 ], "pop" : 3452, "state" : "OK" }
+{ "_id" : "74882", "city" : "WELTY", "loc" : [ -96.42762, 35.610727 ], "pop" : 286, "state" : "OK" }
+{ "_id" : "74883", "city" : "WETUMKA", "loc" : [ -96.242082, 35.239552 ], "pop" : 2181, "state" : "OK" }
+{ "_id" : "74884", "city" : "NEW LIMA", "loc" : [ -96.503793, 35.182893 ], "pop" : 8015, "state" : "OK" }
+{ "_id" : "74901", "city" : "ARKOMA", "loc" : [ -94.44031099999999, 35.343352 ], "pop" : 2764, "state" : "OK" }
+{ "_id" : "74902", "city" : "POCOLA", "loc" : [ -94.476029, 35.243603 ], "pop" : 3575, "state" : "OK" }
+{ "_id" : "74930", "city" : "BOKOSHE", "loc" : [ -94.72215799999999, 35.160925 ], "pop" : 3931, "state" : "OK" }
+{ "_id" : "74931", "city" : "BUNCH", "loc" : [ -94.734154, 35.735691 ], "pop" : 1656, "state" : "OK" }
+{ "_id" : "74932", "city" : "CAMERON", "loc" : [ -94.506015, 35.149355 ], "pop" : 935, "state" : "OK" }
+{ "_id" : "74937", "city" : "HEAVENER", "loc" : [ -94.61848999999999, 34.835267 ], "pop" : 5628, "state" : "OK" }
+{ "_id" : "74939", "city" : "HODGEN", "loc" : [ -94.63908000000001, 34.753757 ], "pop" : 756, "state" : "OK" }
+{ "_id" : "74940", "city" : "HOWE", "loc" : [ -94.657072, 34.929936 ], "pop" : 1352, "state" : "OK" }
+{ "_id" : "74941", "city" : "KEOTA", "loc" : [ -94.902822, 35.264541 ], "pop" : 1878, "state" : "OK" }
+{ "_id" : "74944", "city" : "MCCURTAIN", "loc" : [ -95.012737, 35.140403 ], "pop" : 1106, "state" : "OK" }
+{ "_id" : "74948", "city" : "MULDROW", "loc" : [ -94.633216, 35.401985 ], "pop" : 8185, "state" : "OK" }
+{ "_id" : "74949", "city" : "MUSE", "loc" : [ -94.719007, 34.664124 ], "pop" : 183, "state" : "OK" }
+{ "_id" : "74953", "city" : "POTEAU", "loc" : [ -94.60960300000001, 35.060561 ], "pop" : 9466, "state" : "OK" }
+{ "_id" : "74954", "city" : "ROLAND", "loc" : [ -94.52908499999999, 35.453811 ], "pop" : 7047, "state" : "OK" }
+{ "_id" : "74955", "city" : "SALLISAW", "loc" : [ -94.778998, 35.485191 ], "pop" : 11399, "state" : "OK" }
+{ "_id" : "74956", "city" : "SHADY POINT", "loc" : [ -94.666534, 35.129333 ], "pop" : 937, "state" : "OK" }
+{ "_id" : "74957", "city" : "OCTAVIA", "loc" : [ -94.619117, 34.479056 ], "pop" : 442, "state" : "OK" }
+{ "_id" : "74959", "city" : "SPIRO", "loc" : [ -94.626546, 35.249219 ], "pop" : 7368, "state" : "OK" }
+{ "_id" : "74960", "city" : "STILWELL", "loc" : [ -94.631322, 35.810703 ], "pop" : 10267, "state" : "OK" }
+{ "_id" : "74962", "city" : "VIAN", "loc" : [ -94.988756, 35.540383 ], "pop" : 6030, "state" : "OK" }
+{ "_id" : "74963", "city" : "WATSON", "loc" : [ -94.556217, 34.419252 ], "pop" : 797, "state" : "OK" }
+{ "_id" : "74964", "city" : "WATTS", "loc" : [ -94.634472, 36.115216 ], "pop" : 2156, "state" : "OK" }
+{ "_id" : "74965", "city" : "WESTVILLE", "loc" : [ -94.59262699999999, 35.991226 ], "pop" : 3899, "state" : "OK" }
+{ "_id" : "74966", "city" : "WISTER", "loc" : [ -94.783205, 34.955593 ], "pop" : 3656, "state" : "OK" }
+{ "_id" : "75002", "city" : "ALLEN", "loc" : [ -96.645433, 33.093383 ], "pop" : 24151, "state" : "TX" }
+{ "_id" : "75006", "city" : "CARROLLTON", "loc" : [ -96.882464, 32.965736 ], "pop" : 37699, "state" : "TX" }
+{ "_id" : "75007", "city" : "CARROLLTON", "loc" : [ -96.88198800000001, 33.003294 ], "pop" : 54796, "state" : "TX" }
+{ "_id" : "75008", "city" : "CARROLLTON", "loc" : [ -96.923197, 33.03524 ], "pop" : 1482, "state" : "TX" }
+{ "_id" : "75009", "city" : "CELINA", "loc" : [ -96.767325, 33.310316 ], "pop" : 3373, "state" : "TX" }
+{ "_id" : "75010", "city" : "CARROLLTON", "loc" : [ -96.877746, 33.030414 ], "pop" : 4379, "state" : "TX" }
+{ "_id" : "75019", "city" : "COPPELL", "loc" : [ -96.98051599999999, 32.96727 ], "pop" : 16862, "state" : "TX" }
+{ "_id" : "75020", "city" : "DENISON", "loc" : [ -96.54957400000001, 33.745009 ], "pop" : 27172, "state" : "TX" }
+{ "_id" : "75023", "city" : "PLANO", "loc" : [ -96.73645399999999, 33.054972 ], "pop" : 40832, "state" : "TX" }
+{ "_id" : "75024", "city" : "PLANO", "loc" : [ -96.784307, 33.075211 ], "pop" : 1439, "state" : "TX" }
+{ "_id" : "75025", "city" : "PLANO", "loc" : [ -96.729142, 33.078377 ], "pop" : 8562, "state" : "TX" }
+{ "_id" : "75028", "city" : "FLOWER MOUND", "loc" : [ -97.074501, 33.038268 ], "pop" : 16825, "state" : "TX" }
+{ "_id" : "75034", "city" : "FRISCO", "loc" : [ -96.824105, 33.149901 ], "pop" : 8045, "state" : "TX" }
+{ "_id" : "75038", "city" : "IRVING", "loc" : [ -96.990503, 32.865309 ], "pop" : 20152, "state" : "TX" }
+{ "_id" : "75039", "city" : "IRVING", "loc" : [ -96.93887599999999, 32.869669 ], "pop" : 598, "state" : "TX" }
+{ "_id" : "75040", "city" : "GARLAND", "loc" : [ -96.624804, 32.922744 ], "pop" : 45359, "state" : "TX" }
+{ "_id" : "75041", "city" : "GARLAND", "loc" : [ -96.641115, 32.87937 ], "pop" : 26212, "state" : "TX" }
+{ "_id" : "75042", "city" : "GARLAND", "loc" : [ -96.67754499999999, 32.918486 ], "pop" : 31807, "state" : "TX" }
+{ "_id" : "75043", "city" : "GARLAND", "loc" : [ -96.59988199999999, 32.856502 ], "pop" : 46620, "state" : "TX" }
+{ "_id" : "75044", "city" : "GARLAND", "loc" : [ -96.66538300000001, 32.952228 ], "pop" : 30455, "state" : "TX" }
+{ "_id" : "75048", "city" : "SACHSE", "loc" : [ -96.591472, 32.973576 ], "pop" : 5632, "state" : "TX" }
+{ "_id" : "75050", "city" : "GRAND PRAIRIE", "loc" : [ -97.01121000000001, 32.76488 ], "pop" : 32148, "state" : "TX" }
+{ "_id" : "75051", "city" : "GRAND PRAIRIE", "loc" : [ -97.006916, 32.711471 ], "pop" : 52779, "state" : "TX" }
+{ "_id" : "75052", "city" : "GRAND PRAIRIE", "loc" : [ -97.031142, 32.660475 ], "pop" : 15850, "state" : "TX" }
+{ "_id" : "75056", "city" : "THE COLONY", "loc" : [ -96.883574, 33.094023 ], "pop" : 22549, "state" : "TX" }
+{ "_id" : "75057", "city" : "LEWISVILLE", "loc" : [ -96.999882, 33.053162 ], "pop" : 8052, "state" : "TX" }
+{ "_id" : "75058", "city" : "GUNTER", "loc" : [ -96.734103, 33.449513 ], "pop" : 1410, "state" : "TX" }
+{ "_id" : "75060", "city" : "IRVING", "loc" : [ -96.959665, 32.80231 ], "pop" : 41001, "state" : "TX" }
+{ "_id" : "75061", "city" : "IRVING", "loc" : [ -96.963256, 32.826658 ], "pop" : 42947, "state" : "TX" }
+{ "_id" : "75062", "city" : "IRVING", "loc" : [ -96.97402700000001, 32.847854 ], "pop" : 40234, "state" : "TX" }
+{ "_id" : "75063", "city" : "IRVING", "loc" : [ -96.959817, 32.924686 ], "pop" : 9527, "state" : "TX" }
+{ "_id" : "75065", "city" : "LAKE DALLAS", "loc" : [ -97.023709, 33.121903 ], "pop" : 5452, "state" : "TX" }
+{ "_id" : "75067", "city" : "HIGHLAND VILLAGE", "loc" : [ -97.026815, 33.04503 ], "pop" : 46151, "state" : "TX" }
+{ "_id" : "75068", "city" : "LAKEWOOD VILLAGE", "loc" : [ -96.967811, 33.178319 ], "pop" : 3952, "state" : "TX" }
+{ "_id" : "75069", "city" : "MC KINNEY", "loc" : [ -96.60848799999999, 33.196558 ], "pop" : 20865, "state" : "TX" }
+{ "_id" : "75070", "city" : "MC KINNEY", "loc" : [ -96.66422300000001, 33.195148 ], "pop" : 5573, "state" : "TX" }
+{ "_id" : "75074", "city" : "PLANO", "loc" : [ -96.67771, 33.027722 ], "pop" : 29591, "state" : "TX" }
+{ "_id" : "75075", "city" : "PLANO", "loc" : [ -96.739743, 33.024985 ], "pop" : 33236, "state" : "TX" }
+{ "_id" : "75076", "city" : "POTTSBORO", "loc" : [ -96.690562, 33.809526 ], "pop" : 5458, "state" : "TX" }
+{ "_id" : "75078", "city" : "PROSPER", "loc" : [ -96.795401, 33.236169 ], "pop" : 1103, "state" : "TX" }
+{ "_id" : "75080", "city" : "RICHARDSON", "loc" : [ -96.745249, 32.965986 ], "pop" : 37227, "state" : "TX" }
+{ "_id" : "75081", "city" : "RICHARDSON", "loc" : [ -96.70584100000001, 32.946217 ], "pop" : 30573, "state" : "TX" }
+{ "_id" : "75082", "city" : "RICHARDSON", "loc" : [ -96.685957, 32.986461 ], "pop" : 6678, "state" : "TX" }
+{ "_id" : "75087", "city" : "HEATH", "loc" : [ -96.454497, 32.90456 ], "pop" : 17438, "state" : "TX" }
+{ "_id" : "75088", "city" : "ROWLETT", "loc" : [ -96.547161, 32.90315 ], "pop" : 22057, "state" : "TX" }
+{ "_id" : "75090", "city" : "SHERMAN", "loc" : [ -96.60752100000001, 33.643525 ], "pop" : 35260, "state" : "TX" }
+{ "_id" : "75093", "city" : "PLANO", "loc" : [ -96.788903, 33.029866 ], "pop" : 14376, "state" : "TX" }
+{ "_id" : "75094", "city" : "MURPHY", "loc" : [ -96.609101, 33.004873 ], "pop" : 1722, "state" : "TX" }
+{ "_id" : "75098", "city" : "WYLIE", "loc" : [ -96.539383, 33.004102 ], "pop" : 15418, "state" : "TX" }
+{ "_id" : "75102", "city" : "BARRY", "loc" : [ -96.625141, 32.101356 ], "pop" : 588, "state" : "TX" }
+{ "_id" : "75103", "city" : "CANTON", "loc" : [ -95.904657, 32.514301 ], "pop" : 12281, "state" : "TX" }
+{ "_id" : "75104", "city" : "CEDAR HILL", "loc" : [ -96.94380200000001, 32.58847 ], "pop" : 19503, "state" : "TX" }
+{ "_id" : "75105", "city" : "CHATFIELD", "loc" : [ -96.388668, 32.295416 ], "pop" : 129, "state" : "TX" }
+{ "_id" : "75110", "city" : "CORSICANA", "loc" : [ -96.476151, 32.086776 ], "pop" : 28003, "state" : "TX" }
+{ "_id" : "75114", "city" : "CRANDALL", "loc" : [ -96.46369, 32.597465 ], "pop" : 3720, "state" : "TX" }
+{ "_id" : "75115", "city" : "DE SOTO", "loc" : [ -96.854721, 32.593167 ], "pop" : 33750, "state" : "TX" }
+{ "_id" : "75116", "city" : "DUNCANVILLE", "loc" : [ -96.91139200000001, 32.65873 ], "pop" : 18023, "state" : "TX" }
+{ "_id" : "75117", "city" : "EDGEWOOD", "loc" : [ -95.878011, 32.700326 ], "pop" : 3328, "state" : "TX" }
+{ "_id" : "75119", "city" : "ENNIS", "loc" : [ -96.62236300000001, 32.332102 ], "pop" : 19008, "state" : "TX" }
+{ "_id" : "75124", "city" : "EUSTACE", "loc" : [ -96.013693, 32.296485 ], "pop" : 2192, "state" : "TX" }
+{ "_id" : "75125", "city" : "FERRIS", "loc" : [ -96.664321, 32.52232 ], "pop" : 7592, "state" : "TX" }
+{ "_id" : "75126", "city" : "FORNEY", "loc" : [ -96.45975900000001, 32.749055 ], "pop" : 6803, "state" : "TX" }
+{ "_id" : "75127", "city" : "FRUITVALE", "loc" : [ -95.789903, 32.676981 ], "pop" : 1622, "state" : "TX" }
+{ "_id" : "75134", "city" : "LANCASTER", "loc" : [ -96.78299699999999, 32.616056 ], "pop" : 11306, "state" : "TX" }
+{ "_id" : "75135", "city" : "CADDO MILLS", "loc" : [ -96.239093, 33.068267 ], "pop" : 3148, "state" : "TX" }
+{ "_id" : "75137", "city" : "DUNCANVILLE", "loc" : [ -96.91132500000001, 32.634665 ], "pop" : 16979, "state" : "TX" }
+{ "_id" : "75140", "city" : "GRAND SALINE", "loc" : [ -95.706411, 32.663528 ], "pop" : 4870, "state" : "TX" }
+{ "_id" : "75141", "city" : "HUTCHINS", "loc" : [ -96.707021, 32.639586 ], "pop" : 2716, "state" : "TX" }
+{ "_id" : "75142", "city" : "KAUFMAN", "loc" : [ -96.285239, 32.54599 ], "pop" : 9160, "state" : "TX" }
+{ "_id" : "75143", "city" : "SEVEN POINTS", "loc" : [ -96.257768, 32.369146 ], "pop" : 5268, "state" : "TX" }
+{ "_id" : "75144", "city" : "KERENS", "loc" : [ -96.229828, 32.127463 ], "pop" : 2991, "state" : "TX" }
+{ "_id" : "75146", "city" : "LANCASTER", "loc" : [ -96.77280500000001, 32.591395 ], "pop" : 11762, "state" : "TX" }
+{ "_id" : "75147", "city" : "GUN BARREL CITY", "loc" : [ -96.129524, 32.307513 ], "pop" : 18113, "state" : "TX" }
+{ "_id" : "75148", "city" : "MALAKOFF", "loc" : [ -96.00595199999999, 32.170511 ], "pop" : 4972, "state" : "TX" }
+{ "_id" : "75149", "city" : "MESQUITE", "loc" : [ -96.60821900000001, 32.767821 ], "pop" : 45754, "state" : "TX" }
+{ "_id" : "75150", "city" : "MESQUITE", "loc" : [ -96.630681, 32.815416 ], "pop" : 51494, "state" : "TX" }
+{ "_id" : "75152", "city" : "PALMER", "loc" : [ -96.679429, 32.438714 ], "pop" : 2605, "state" : "TX" }
+{ "_id" : "75153", "city" : "POWELL", "loc" : [ -96.332713, 32.119557 ], "pop" : 127, "state" : "TX" }
+{ "_id" : "75154", "city" : "OVILLA", "loc" : [ -96.82033699999999, 32.516096 ], "pop" : 16882, "state" : "TX" }
+{ "_id" : "75155", "city" : "RICE", "loc" : [ -96.460613, 32.225788 ], "pop" : 1812, "state" : "TX" }
+{ "_id" : "75158", "city" : "SCURRY", "loc" : [ -96.39245099999999, 32.48184 ], "pop" : 2589, "state" : "TX" }
+{ "_id" : "75159", "city" : "SEAGOVILLE", "loc" : [ -96.557967, 32.652522 ], "pop" : 10569, "state" : "TX" }
+{ "_id" : "75160", "city" : "TERRELL", "loc" : [ -96.25134199999999, 32.714292 ], "pop" : 24116, "state" : "TX" }
+{ "_id" : "75163", "city" : "TRINIDAD", "loc" : [ -96.08307000000001, 32.138341 ], "pop" : 1246, "state" : "TX" }
+{ "_id" : "75165", "city" : "WAXAHACHIE", "loc" : [ -96.83739799999999, 32.380796 ], "pop" : 22844, "state" : "TX" }
+{ "_id" : "75169", "city" : "WILLS POINT", "loc" : [ -96.00788, 32.72834 ], "pop" : 7310, "state" : "TX" }
+{ "_id" : "75172", "city" : "WILMER", "loc" : [ -96.68376000000001, 32.598133 ], "pop" : 2407, "state" : "TX" }
+{ "_id" : "75173", "city" : "NEVADA", "loc" : [ -96.387657, 33.05934 ], "pop" : 3149, "state" : "TX" }
+{ "_id" : "75180", "city" : "BALCH SPRINGS", "loc" : [ -96.615278, 32.720216 ], "pop" : 18848, "state" : "TX" }
+{ "_id" : "75181", "city" : "MESQUITE", "loc" : [ -96.566889, 32.727166 ], "pop" : 5005, "state" : "TX" }
+{ "_id" : "75182", "city" : "MESQUITE", "loc" : [ -96.567004, 32.801922 ], "pop" : 1959, "state" : "TX" }
+{ "_id" : "75189", "city" : "ROYSE CITY", "loc" : [ -96.36484, 32.962778 ], "pop" : 5533, "state" : "TX" }
+{ "_id" : "75201", "city" : "DALLAS", "loc" : [ -96.80439, 32.790439 ], "pop" : 1505, "state" : "TX" }
+{ "_id" : "75202", "city" : "DALLAS", "loc" : [ -96.805352, 32.778056 ], "pop" : 3622, "state" : "TX" }
+{ "_id" : "75203", "city" : "DALLAS", "loc" : [ -96.80697600000001, 32.745985 ], "pop" : 18850, "state" : "TX" }
+{ "_id" : "75204", "city" : "DALLAS", "loc" : [ -96.785144, 32.803814 ], "pop" : 16697, "state" : "TX" }
+{ "_id" : "75205", "city" : "VILLAGE", "loc" : [ -96.793828, 32.836878 ], "pop" : 23883, "state" : "TX" }
+{ "_id" : "75206", "city" : "DALLAS", "loc" : [ -96.76921900000001, 32.831029 ], "pop" : 36526, "state" : "TX" }
+{ "_id" : "75207", "city" : "DALLAS", "loc" : [ -96.83187100000001, 32.793897 ], "pop" : 1744, "state" : "TX" }
+{ "_id" : "75208", "city" : "DALLAS", "loc" : [ -96.838898, 32.749208 ], "pop" : 33527, "state" : "TX" }
+{ "_id" : "75209", "city" : "DALLAS", "loc" : [ -96.82598400000001, 32.84564 ], "pop" : 15398, "state" : "TX" }
+{ "_id" : "75210", "city" : "DALLAS", "loc" : [ -96.742974, 32.769919 ], "pop" : 10216, "state" : "TX" }
+{ "_id" : "75211", "city" : "COCKRELL HILL", "loc" : [ -96.88179700000001, 32.736928 ], "pop" : 54691, "state" : "TX" }
+{ "_id" : "75212", "city" : "DALLAS", "loc" : [ -96.871396, 32.782884 ], "pop" : 23556, "state" : "TX" }
+{ "_id" : "75214", "city" : "DALLAS", "loc" : [ -96.749774, 32.824789 ], "pop" : 32618, "state" : "TX" }
+{ "_id" : "75215", "city" : "DALLAS", "loc" : [ -96.76226, 32.758206 ], "pop" : 22120, "state" : "TX" }
+{ "_id" : "75216", "city" : "DALLAS", "loc" : [ -96.79548800000001, 32.708611 ], "pop" : 55166, "state" : "TX" }
+{ "_id" : "75217", "city" : "DALLAS", "loc" : [ -96.675481, 32.724429 ], "pop" : 57605, "state" : "TX" }
+{ "_id" : "75218", "city" : "DALLAS", "loc" : [ -96.69721199999999, 32.846335 ], "pop" : 22646, "state" : "TX" }
+{ "_id" : "75219", "city" : "DALLAS", "loc" : [ -96.814166, 32.813245 ], "pop" : 19178, "state" : "TX" }
+{ "_id" : "75220", "city" : "DALLAS", "loc" : [ -96.862202, 32.868131 ], "pop" : 30241, "state" : "TX" }
+{ "_id" : "75223", "city" : "DALLAS", "loc" : [ -96.74747499999999, 32.794173 ], "pop" : 14700, "state" : "TX" }
+{ "_id" : "75224", "city" : "DALLAS", "loc" : [ -96.838711, 32.711415 ], "pop" : 26734, "state" : "TX" }
+{ "_id" : "75225", "city" : "DALLAS", "loc" : [ -96.791753, 32.862808 ], "pop" : 18255, "state" : "TX" }
+{ "_id" : "75226", "city" : "DALLAS", "loc" : [ -96.76755199999999, 32.78871 ], "pop" : 1561, "state" : "TX" }
+{ "_id" : "75227", "city" : "DALLAS", "loc" : [ -96.68358600000001, 32.767226 ], "pop" : 39631, "state" : "TX" }
+{ "_id" : "75228", "city" : "DALLAS", "loc" : [ -96.678378, 32.824997 ], "pop" : 55010, "state" : "TX" }
+{ "_id" : "75229", "city" : "DALLAS", "loc" : [ -96.8588, 32.8958 ], "pop" : 27621, "state" : "TX" }
+{ "_id" : "75230", "city" : "DALLAS", "loc" : [ -96.78967900000001, 32.89994 ], "pop" : 24281, "state" : "TX" }
+{ "_id" : "75231", "city" : "DALLAS", "loc" : [ -96.74952999999999, 32.875621 ], "pop" : 35407, "state" : "TX" }
+{ "_id" : "75232", "city" : "DALLAS", "loc" : [ -96.838392, 32.664708 ], "pop" : 28289, "state" : "TX" }
+{ "_id" : "75233", "city" : "DALLAS", "loc" : [ -96.872547, 32.704638 ], "pop" : 11206, "state" : "TX" }
+{ "_id" : "75234", "city" : "FARMERS BRANCH", "loc" : [ -96.876848, 32.929803 ], "pop" : 25992, "state" : "TX" }
+{ "_id" : "75235", "city" : "DALLAS", "loc" : [ -96.838843, 32.825213 ], "pop" : 14850, "state" : "TX" }
+{ "_id" : "75236", "city" : "DALLAS", "loc" : [ -96.917737, 32.690002 ], "pop" : 6124, "state" : "TX" }
+{ "_id" : "75237", "city" : "DALLAS", "loc" : [ -96.876453, 32.658972 ], "pop" : 12859, "state" : "TX" }
+{ "_id" : "75238", "city" : "DALLAS", "loc" : [ -96.707982, 32.876976 ], "pop" : 25855, "state" : "TX" }
+{ "_id" : "75239", "city" : "DALLAS", "loc" : [ -96.732769, 32.659974 ], "pop" : 541, "state" : "TX" }
+{ "_id" : "75240", "city" : "DALLAS", "loc" : [ -96.78721400000001, 32.937431 ], "pop" : 37646, "state" : "TX" }
+{ "_id" : "75241", "city" : "DALLAS", "loc" : [ -96.777421, 32.672216 ], "pop" : 26407, "state" : "TX" }
+{ "_id" : "75243", "city" : "DALLAS", "loc" : [ -96.728472, 32.910347 ], "pop" : 48344, "state" : "TX" }
+{ "_id" : "75244", "city" : "FARMERS BRANCH", "loc" : [ -96.842533, 32.925817 ], "pop" : 16870, "state" : "TX" }
+{ "_id" : "75246", "city" : "DALLAS", "loc" : [ -96.769696, 32.79484 ], "pop" : 3129, "state" : "TX" }
+{ "_id" : "75247", "city" : "DALLAS", "loc" : [ -96.887123, 32.801323 ], "pop" : 124, "state" : "TX" }
+{ "_id" : "75248", "city" : "DALLAS", "loc" : [ -96.794242, 32.968199 ], "pop" : 34858, "state" : "TX" }
+{ "_id" : "75249", "city" : "DALLAS", "loc" : [ -96.94926599999999, 32.636024 ], "pop" : 8677, "state" : "TX" }
+{ "_id" : "75251", "city" : "DALLAS", "loc" : [ -96.77183100000001, 32.912203 ], "pop" : 75, "state" : "TX" }
+{ "_id" : "75252", "city" : "DALLAS", "loc" : [ -96.792113, 32.996848 ], "pop" : 15152, "state" : "TX" }
+{ "_id" : "75253", "city" : "DALLAS", "loc" : [ -96.59643, 32.683311 ], "pop" : 10252, "state" : "TX" }
+{ "_id" : "75287", "city" : "DALLAS", "loc" : [ -96.83143, 33.000458 ], "pop" : 11388, "state" : "TX" }
+{ "_id" : "75401", "city" : "GREENVILLE", "loc" : [ -96.10241600000001, 33.117476 ], "pop" : 30183, "state" : "TX" }
+{ "_id" : "75407", "city" : "PRINCETON", "loc" : [ -96.49807300000001, 33.155542 ], "pop" : 7552, "state" : "TX" }
+{ "_id" : "75409", "city" : "ANNA", "loc" : [ -96.563862, 33.344516 ], "pop" : 4413, "state" : "TX" }
+{ "_id" : "75410", "city" : "ALBA", "loc" : [ -95.59710200000001, 32.765235 ], "pop" : 2599, "state" : "TX" }
+{ "_id" : "75411", "city" : "ARTHUR CITY", "loc" : [ -95.49403700000001, 33.840031 ], "pop" : 1583, "state" : "TX" }
+{ "_id" : "75412", "city" : "BAGWELL", "loc" : [ -95.14869, 33.836089 ], "pop" : 979, "state" : "TX" }
+{ "_id" : "75414", "city" : "BELLS", "loc" : [ -96.42366800000001, 33.617817 ], "pop" : 1829, "state" : "TX" }
+{ "_id" : "75415", "city" : "BEN FRANKLIN", "loc" : [ -95.759107, 33.474146 ], "pop" : 151, "state" : "TX" }
+{ "_id" : "75416", "city" : "BLOSSOM", "loc" : [ -95.382341, 33.694547 ], "pop" : 3253, "state" : "TX" }
+{ "_id" : "75417", "city" : "BOGATA", "loc" : [ -95.193725, 33.469862 ], "pop" : 2803, "state" : "TX" }
+{ "_id" : "75418", "city" : "BONHAM", "loc" : [ -96.183566, 33.580559 ], "pop" : 9003, "state" : "TX" }
+{ "_id" : "75420", "city" : "BRASHEAR", "loc" : [ -95.73451, 33.115521 ], "pop" : 272, "state" : "TX" }
+{ "_id" : "75421", "city" : "BROOKSTON", "loc" : [ -95.688812, 33.624555 ], "pop" : 287, "state" : "TX" }
+{ "_id" : "75422", "city" : "CAMPBELL", "loc" : [ -95.94391899999999, 33.151049 ], "pop" : 2029, "state" : "TX" }
+{ "_id" : "75423", "city" : "CELESTE", "loc" : [ -96.207635, 33.264913 ], "pop" : 2697, "state" : "TX" }
+{ "_id" : "75424", "city" : "BLUE RIDGE", "loc" : [ -96.390056, 33.306135 ], "pop" : 2312, "state" : "TX" }
+{ "_id" : "75426", "city" : "CLARKSVILLE", "loc" : [ -95.046094, 33.623563 ], "pop" : 6675, "state" : "TX" }
+{ "_id" : "75428", "city" : "COMMERCE", "loc" : [ -95.90967999999999, 33.2493 ], "pop" : 8421, "state" : "TX" }
+{ "_id" : "75431", "city" : "COMO", "loc" : [ -95.362655, 33.064231 ], "pop" : 1679, "state" : "TX" }
+{ "_id" : "75432", "city" : "COOPER", "loc" : [ -95.662311, 33.381166 ], "pop" : 3438, "state" : "TX" }
+{ "_id" : "75433", "city" : "CUMBY", "loc" : [ -95.79453599999999, 33.111761 ], "pop" : 2894, "state" : "TX" }
+{ "_id" : "75435", "city" : "DEPORT", "loc" : [ -95.365351, 33.522077 ], "pop" : 1927, "state" : "TX" }
+{ "_id" : "75436", "city" : "DETROIT", "loc" : [ -95.23848, 33.662691 ], "pop" : 1594, "state" : "TX" }
+{ "_id" : "75437", "city" : "DIKE", "loc" : [ -95.471125, 33.196485 ], "pop" : 210, "state" : "TX" }
+{ "_id" : "75438", "city" : "DODD CITY", "loc" : [ -96.06194000000001, 33.564704 ], "pop" : 1094, "state" : "TX" }
+{ "_id" : "75439", "city" : "ECTOR", "loc" : [ -96.273533, 33.581913 ], "pop" : 803, "state" : "TX" }
+{ "_id" : "75440", "city" : "EMORY", "loc" : [ -95.741786, 32.875041 ], "pop" : 3919, "state" : "TX" }
+{ "_id" : "75442", "city" : "FARMERSVILLE", "loc" : [ -96.368619, 33.165862 ], "pop" : 4777, "state" : "TX" }
+{ "_id" : "75446", "city" : "HONEY GROVE", "loc" : [ -95.9109, 33.598505 ], "pop" : 2563, "state" : "TX" }
+{ "_id" : "75447", "city" : "IVANHOE", "loc" : [ -96.169811, 33.67364 ], "pop" : 1004, "state" : "TX" }
+{ "_id" : "75448", "city" : "KLONDIKE", "loc" : [ -95.801762, 33.303375 ], "pop" : 729, "state" : "TX" }
+{ "_id" : "75449", "city" : "LADONIA", "loc" : [ -95.94548899999999, 33.424527 ], "pop" : 899, "state" : "TX" }
+{ "_id" : "75450", "city" : "LAKE CREEK", "loc" : [ -95.622131, 33.467493 ], "pop" : 50, "state" : "TX" }
+{ "_id" : "75451", "city" : "LEESBURG", "loc" : [ -95.107924, 32.976275 ], "pop" : 1246, "state" : "TX" }
+{ "_id" : "75452", "city" : "LEONARD", "loc" : [ -96.223772, 33.404363 ], "pop" : 3229, "state" : "TX" }
+{ "_id" : "75453", "city" : "LONE OAK", "loc" : [ -95.943412, 32.991571 ], "pop" : 1822, "state" : "TX" }
+{ "_id" : "75454", "city" : "MELISSA", "loc" : [ -96.574009, 33.284114 ], "pop" : 703, "state" : "TX" }
+{ "_id" : "75455", "city" : "MOUNT PLEASANT", "loc" : [ -94.969461, 33.173309 ], "pop" : 16878, "state" : "TX" }
+{ "_id" : "75457", "city" : "MOUNT VERNON", "loc" : [ -95.21810600000001, 33.170204 ], "pop" : 5948, "state" : "TX" }
+{ "_id" : "75459", "city" : "HOWE", "loc" : [ -96.64072299999999, 33.534867 ], "pop" : 4843, "state" : "TX" }
+{ "_id" : "75460", "city" : "PARIS", "loc" : [ -95.537881, 33.658077 ], "pop" : 30317, "state" : "TX" }
+{ "_id" : "75468", "city" : "PATTONVILLE", "loc" : [ -95.3908, 33.570234 ], "pop" : 194, "state" : "TX" }
+{ "_id" : "75469", "city" : "PECAN GAP", "loc" : [ -95.826196, 33.419641 ], "pop" : 489, "state" : "TX" }
+{ "_id" : "75470", "city" : "PETTY", "loc" : [ -95.789057, 33.609765 ], "pop" : 247, "state" : "TX" }
+{ "_id" : "75471", "city" : "PICKTON", "loc" : [ -95.462979, 33.042401 ], "pop" : 1569, "state" : "TX" }
+{ "_id" : "75472", "city" : "POINT", "loc" : [ -95.89028500000001, 32.900743 ], "pop" : 2796, "state" : "TX" }
+{ "_id" : "75473", "city" : "POWDERLY", "loc" : [ -95.530692, 33.777877 ], "pop" : 1570, "state" : "TX" }
+{ "_id" : "75474", "city" : "QUINLAN", "loc" : [ -96.12608299999999, 32.898347 ], "pop" : 13826, "state" : "TX" }
+{ "_id" : "75476", "city" : "RAVENNA", "loc" : [ -96.145157, 33.709757 ], "pop" : 1635, "state" : "TX" }
+{ "_id" : "75477", "city" : "ROXTON", "loc" : [ -95.74160500000001, 33.542934 ], "pop" : 975, "state" : "TX" }
+{ "_id" : "75478", "city" : "SALTILLO", "loc" : [ -95.343324, 33.176678 ], "pop" : 500, "state" : "TX" }
+{ "_id" : "75479", "city" : "SAVOY", "loc" : [ -96.350156, 33.606571 ], "pop" : 1726, "state" : "TX" }
+{ "_id" : "75480", "city" : "SCROGGINS", "loc" : [ -95.239683, 32.991177 ], "pop" : 2029, "state" : "TX" }
+{ "_id" : "75481", "city" : "SULPHUR BLUFF", "loc" : [ -95.37396, 33.333379 ], "pop" : 228, "state" : "TX" }
+{ "_id" : "75482", "city" : "SULPHUR SPRINGS", "loc" : [ -95.592161, 33.134541 ], "pop" : 21479, "state" : "TX" }
+{ "_id" : "75486", "city" : "SUMNER", "loc" : [ -95.680671, 33.758941 ], "pop" : 3596, "state" : "TX" }
+{ "_id" : "75487", "city" : "TALCO", "loc" : [ -95.049718, 33.33436 ], "pop" : 1932, "state" : "TX" }
+{ "_id" : "75488", "city" : "TELEPHONE", "loc" : [ -96.044945, 33.797854 ], "pop" : 709, "state" : "TX" }
+{ "_id" : "75490", "city" : "TRENTON", "loc" : [ -96.339754, 33.423491 ], "pop" : 1776, "state" : "TX" }
+{ "_id" : "75491", "city" : "WHITEWRIGHT", "loc" : [ -96.451025, 33.519041 ], "pop" : 4327, "state" : "TX" }
+{ "_id" : "75492", "city" : "WINDOM", "loc" : [ -96.002002, 33.563295 ], "pop" : 363, "state" : "TX" }
+{ "_id" : "75493", "city" : "WINFIELD", "loc" : [ -95.07898400000001, 33.161498 ], "pop" : 1956, "state" : "TX" }
+{ "_id" : "75494", "city" : "WINNSBORO", "loc" : [ -95.27265, 32.91462 ], "pop" : 6204, "state" : "TX" }
+{ "_id" : "75495", "city" : "VAN ALSTYNE", "loc" : [ -96.548632, 33.429169 ], "pop" : 4251, "state" : "TX" }
+{ "_id" : "75496", "city" : "WOLFE CITY", "loc" : [ -96.06907, 33.360479 ], "pop" : 2225, "state" : "TX" }
+{ "_id" : "75497", "city" : "YANTIS", "loc" : [ -95.531113, 32.925694 ], "pop" : 1554, "state" : "TX" }
+{ "_id" : "75501", "city" : "WAKE VILLAGE", "loc" : [ -94.118245, 33.407371 ], "pop" : 40273, "state" : "TX" }
+{ "_id" : "75502", "city" : "TEXARKANA", "loc" : [ -94.011281, 33.432644 ], "pop" : 30471, "state" : "AR" }
+{ "_id" : "75503", "city" : "TEXARKANA", "loc" : [ -94.07737400000001, 33.466906 ], "pop" : 16443, "state" : "TX" }
+{ "_id" : "75550", "city" : "ANNONA", "loc" : [ -94.899226, 33.553519 ], "pop" : 949, "state" : "TX" }
+{ "_id" : "75551", "city" : "ATLANTA", "loc" : [ -94.16461700000001, 33.10898 ], "pop" : 9024, "state" : "TX" }
+{ "_id" : "75554", "city" : "AVERY", "loc" : [ -94.786708, 33.533935 ], "pop" : 1317, "state" : "TX" }
+{ "_id" : "75555", "city" : "BIVINS", "loc" : [ -94.140406, 32.96602 ], "pop" : 1758, "state" : "TX" }
+{ "_id" : "75556", "city" : "BLOOMBURG", "loc" : [ -94.064688, 33.133859 ], "pop" : 855, "state" : "TX" }
+{ "_id" : "75558", "city" : "COOKVILLE", "loc" : [ -94.87329099999999, 33.181908 ], "pop" : 2050, "state" : "TX" }
+{ "_id" : "75559", "city" : "DE KALB", "loc" : [ -94.621092, 33.472741 ], "pop" : 3364, "state" : "TX" }
+{ "_id" : "75560", "city" : "DOUGLASSVILLE", "loc" : [ -94.346699, 33.175806 ], "pop" : 1705, "state" : "TX" }
+{ "_id" : "75561", "city" : "LEARY", "loc" : [ -94.269188, 33.477542 ], "pop" : 5815, "state" : "TX" }
+{ "_id" : "75563", "city" : "LINDEN", "loc" : [ -94.36050899999999, 33.004821 ], "pop" : 5727, "state" : "TX" }
+{ "_id" : "75566", "city" : "MARIETTA", "loc" : [ -94.542098, 33.179618 ], "pop" : 1526, "state" : "TX" }
+{ "_id" : "75567", "city" : "MAUD", "loc" : [ -94.48226699999999, 33.35504 ], "pop" : 888, "state" : "TX" }
+{ "_id" : "75568", "city" : "NAPLES", "loc" : [ -94.689061, 33.191186 ], "pop" : 2752, "state" : "TX" }
+{ "_id" : "75569", "city" : "NASH", "loc" : [ -94.14223699999999, 33.439786 ], "pop" : 3464, "state" : "TX" }
+{ "_id" : "75570", "city" : "BOSTON", "loc" : [ -94.433882, 33.462119 ], "pop" : 7801, "state" : "TX" }
+{ "_id" : "75571", "city" : "OMAHA", "loc" : [ -94.763944, 33.180794 ], "pop" : 1791, "state" : "TX" }
+{ "_id" : "75572", "city" : "QUEEN CITY", "loc" : [ -94.154825, 33.18736 ], "pop" : 4376, "state" : "TX" }
+{ "_id" : "75574", "city" : "SIMMS", "loc" : [ -94.60386200000001, 33.498727 ], "pop" : 3617, "state" : "TX" }
+{ "_id" : "75601", "city" : "LONGVIEW", "loc" : [ -94.72328, 32.526854 ], "pop" : 27102, "state" : "TX" }
+{ "_id" : "75602", "city" : "LONGVIEW", "loc" : [ -94.710078, 32.472373 ], "pop" : 17399, "state" : "TX" }
+{ "_id" : "75603", "city" : "LONGVIEW", "loc" : [ -94.711691, 32.426368 ], "pop" : 6737, "state" : "TX" }
+{ "_id" : "75604", "city" : "LONGVIEW", "loc" : [ -94.798957, 32.525139 ], "pop" : 25570, "state" : "TX" }
+{ "_id" : "75605", "city" : "LONGVIEW", "loc" : [ -94.776748, 32.554711 ], "pop" : 9166, "state" : "TX" }
+{ "_id" : "75630", "city" : "AVINGER", "loc" : [ -94.579534, 32.848514 ], "pop" : 2764, "state" : "TX" }
+{ "_id" : "75631", "city" : "BECKVILLE", "loc" : [ -94.455451, 32.245165 ], "pop" : 3114, "state" : "TX" }
+{ "_id" : "75633", "city" : "CARTHAGE", "loc" : [ -94.352721, 32.154379 ], "pop" : 11062, "state" : "TX" }
+{ "_id" : "75638", "city" : "DAINGERFIELD", "loc" : [ -94.735899, 33.031263 ], "pop" : 5614, "state" : "TX" }
+{ "_id" : "75639", "city" : "DE BERRY", "loc" : [ -94.13557, 32.254327 ], "pop" : 4375, "state" : "TX" }
+{ "_id" : "75640", "city" : "NEW DIANA", "loc" : [ -94.698122, 32.704585 ], "pop" : 1930, "state" : "TX" }
+{ "_id" : "75643", "city" : "GARY", "loc" : [ -94.28150100000001, 32.019848 ], "pop" : 1394, "state" : "TX" }
+{ "_id" : "75644", "city" : "GILMER", "loc" : [ -94.971434, 32.724565 ], "pop" : 10141, "state" : "TX" }
+{ "_id" : "75647", "city" : "GLADEWATER", "loc" : [ -94.932001, 32.555858 ], "pop" : 14791, "state" : "TX" }
+{ "_id" : "75650", "city" : "HALLSVILLE", "loc" : [ -94.53330800000001, 32.507283 ], "pop" : 7463, "state" : "TX" }
+{ "_id" : "75651", "city" : "HARLETON", "loc" : [ -94.465165, 32.657858 ], "pop" : 2609, "state" : "TX" }
+{ "_id" : "75652", "city" : "HENDERSON", "loc" : [ -94.791962, 32.152375 ], "pop" : 19836, "state" : "TX" }
+{ "_id" : "75656", "city" : "HUGHES SPRINGS", "loc" : [ -94.622758, 33.016763 ], "pop" : 4564, "state" : "TX" }
+{ "_id" : "75657", "city" : "SMITHLAND", "loc" : [ -94.371217, 32.779863 ], "pop" : 8460, "state" : "TX" }
+{ "_id" : "75661", "city" : "KARNACK", "loc" : [ -94.20005, 32.620508 ], "pop" : 4434, "state" : "TX" }
+{ "_id" : "75662", "city" : "KILGORE", "loc" : [ -94.86527100000001, 32.383557 ], "pop" : 22785, "state" : "TX" }
+{ "_id" : "75667", "city" : "LANEVILLE", "loc" : [ -94.866027, 31.950821 ], "pop" : 3032, "state" : "TX" }
+{ "_id" : "75668", "city" : "LONE STAR", "loc" : [ -94.71830300000001, 32.946982 ], "pop" : 2578, "state" : "TX" }
+{ "_id" : "75669", "city" : "LONG BRANCH", "loc" : [ -94.47202799999999, 32.050224 ], "pop" : 2101, "state" : "TX" }
+{ "_id" : "75670", "city" : "MARSHALL", "loc" : [ -94.36190999999999, 32.53378 ], "pop" : 27482, "state" : "TX" }
+{ "_id" : "75681", "city" : "MOUNT ENTERPRISE", "loc" : [ -94.62350499999999, 31.9125 ], "pop" : 2558, "state" : "TX" }
+{ "_id" : "75683", "city" : "ORE CITY", "loc" : [ -94.751401, 32.785588 ], "pop" : 5129, "state" : "TX" }
+{ "_id" : "75684", "city" : "OVERTON", "loc" : [ -94.95291400000001, 32.269041 ], "pop" : 4776, "state" : "TX" }
+{ "_id" : "75686", "city" : "PITTSBURG", "loc" : [ -94.960337, 32.96231 ], "pop" : 12871, "state" : "TX" }
+{ "_id" : "75687", "city" : "PRICE", "loc" : [ -94.94149400000001, 32.100842 ], "pop" : 945, "state" : "TX" }
+{ "_id" : "75689", "city" : "TURNERTOWN", "loc" : [ -94.950805, 32.18734 ], "pop" : 923, "state" : "TX" }
+{ "_id" : "75691", "city" : "TATUM", "loc" : [ -94.59602700000001, 32.326569 ], "pop" : 4679, "state" : "TX" }
+{ "_id" : "75692", "city" : "WASKOM", "loc" : [ -94.137884, 32.467183 ], "pop" : 6516, "state" : "TX" }
+{ "_id" : "75693", "city" : "CLARKSVILLE CITY", "loc" : [ -94.862115, 32.537232 ], "pop" : 5887, "state" : "TX" }
+{ "_id" : "75701", "city" : "TYLER", "loc" : [ -95.292179, 32.325366 ], "pop" : 30794, "state" : "TX" }
+{ "_id" : "75702", "city" : "TYLER", "loc" : [ -95.311652, 32.361969 ], "pop" : 24885, "state" : "TX" }
+{ "_id" : "75703", "city" : "TYLER", "loc" : [ -95.303147, 32.276827 ], "pop" : 26345, "state" : "TX" }
+{ "_id" : "75704", "city" : "TYLER", "loc" : [ -95.406977, 32.373781 ], "pop" : 6100, "state" : "TX" }
+{ "_id" : "75705", "city" : "TYLER", "loc" : [ -95.125225, 32.376599 ], "pop" : 1539, "state" : "TX" }
+{ "_id" : "75706", "city" : "TYLER", "loc" : [ -95.33099300000001, 32.444148 ], "pop" : 6770, "state" : "TX" }
+{ "_id" : "75707", "city" : "TYLER", "loc" : [ -95.19269199999999, 32.303782 ], "pop" : 9853, "state" : "TX" }
+{ "_id" : "75708", "city" : "EAST TEXAS CENTE", "loc" : [ -95.244354, 32.389193 ], "pop" : 4338, "state" : "TX" }
+{ "_id" : "75709", "city" : "TYLER", "loc" : [ -95.395563, 32.307817 ], "pop" : 1737, "state" : "TX" }
+{ "_id" : "75750", "city" : "ARP", "loc" : [ -95.063908, 32.241758 ], "pop" : 1815, "state" : "TX" }
+{ "_id" : "75751", "city" : "ATHENS", "loc" : [ -95.84318, 32.193499 ], "pop" : 18579, "state" : "TX" }
+{ "_id" : "75754", "city" : "BEN WHEELER", "loc" : [ -95.637085, 32.412588 ], "pop" : 3992, "state" : "TX" }
+{ "_id" : "75755", "city" : "BIG SANDY", "loc" : [ -95.08803399999999, 32.61682 ], "pop" : 3997, "state" : "TX" }
+{ "_id" : "75756", "city" : "EDOM", "loc" : [ -95.62289, 32.290514 ], "pop" : 2868, "state" : "TX" }
+{ "_id" : "75757", "city" : "MOUNT SELMAN", "loc" : [ -95.375045, 32.135745 ], "pop" : 4654, "state" : "TX" }
+{ "_id" : "75758", "city" : "CHANDLER", "loc" : [ -95.502531, 32.270638 ], "pop" : 4835, "state" : "TX" }
+{ "_id" : "75760", "city" : "CUSHING", "loc" : [ -94.853887, 31.797767 ], "pop" : 2068, "state" : "TX" }
+{ "_id" : "75762", "city" : "FLINT", "loc" : [ -95.394848, 32.207927 ], "pop" : 6365, "state" : "TX" }
+{ "_id" : "75763", "city" : "FRANKSTON", "loc" : [ -95.516284, 32.053488 ], "pop" : 5394, "state" : "TX" }
+{ "_id" : "75765", "city" : "HAWKINS", "loc" : [ -95.222015, 32.643901 ], "pop" : 4968, "state" : "TX" }
+{ "_id" : "75766", "city" : "JACKSONVILLE", "loc" : [ -95.27032800000001, 31.96177 ], "pop" : 19652, "state" : "TX" }
+{ "_id" : "75770", "city" : "LARUE", "loc" : [ -95.59266100000001, 32.160758 ], "pop" : 2826, "state" : "TX" }
+{ "_id" : "75771", "city" : "MT SYLVAN", "loc" : [ -95.42993199999999, 32.517152 ], "pop" : 9838, "state" : "TX" }
+{ "_id" : "75773", "city" : "MINEOLA", "loc" : [ -95.487032, 32.666059 ], "pop" : 8904, "state" : "TX" }
+{ "_id" : "75778", "city" : "MURCHISON", "loc" : [ -95.77372, 32.325732 ], "pop" : 1801, "state" : "TX" }
+{ "_id" : "75783", "city" : "QUITMAN", "loc" : [ -95.430161, 32.804862 ], "pop" : 5864, "state" : "TX" }
+{ "_id" : "75784", "city" : "REKLAW", "loc" : [ -95.01183399999999, 31.885858 ], "pop" : 334, "state" : "TX" }
+{ "_id" : "75785", "city" : "DIALVILLE", "loc" : [ -95.17315600000001, 31.80976 ], "pop" : 10527, "state" : "TX" }
+{ "_id" : "75789", "city" : "TROUP", "loc" : [ -95.12265600000001, 32.104003 ], "pop" : 8363, "state" : "TX" }
+{ "_id" : "75790", "city" : "VAN", "loc" : [ -95.654538, 32.528265 ], "pop" : 4019, "state" : "TX" }
+{ "_id" : "75791", "city" : "WHITEHOUSE", "loc" : [ -95.226552, 32.221958 ], "pop" : 8273, "state" : "TX" }
+{ "_id" : "75792", "city" : "WINONA", "loc" : [ -95.124624, 32.466163 ], "pop" : 2825, "state" : "TX" }
+{ "_id" : "75801", "city" : "PALESTINE", "loc" : [ -95.634158, 31.758752 ], "pop" : 26466, "state" : "TX" }
+{ "_id" : "75831", "city" : "FREESTONE", "loc" : [ -96.058516, 31.457151 ], "pop" : 3404, "state" : "TX" }
+{ "_id" : "75833", "city" : "CENTERVILLE", "loc" : [ -95.92128700000001, 31.272025 ], "pop" : 2618, "state" : "TX" }
+{ "_id" : "75835", "city" : "AUSTONIO", "loc" : [ -95.46832999999999, 31.315067 ], "pop" : 11698, "state" : "TX" }
+{ "_id" : "75838", "city" : "DONIE", "loc" : [ -96.238687, 31.487285 ], "pop" : 334, "state" : "TX" }
+{ "_id" : "75839", "city" : "SLOCUM", "loc" : [ -95.55323199999999, 31.635087 ], "pop" : 4767, "state" : "TX" }
+{ "_id" : "75840", "city" : "FAIRFIELD", "loc" : [ -96.15717600000001, 31.736136 ], "pop" : 6331, "state" : "TX" }
+{ "_id" : "75844", "city" : "GRAPELAND", "loc" : [ -95.44471299999999, 31.49721 ], "pop" : 4705, "state" : "TX" }
+{ "_id" : "75845", "city" : "GROVETON", "loc" : [ -95.09689400000001, 31.065142 ], "pop" : 2206, "state" : "TX" }
+{ "_id" : "75846", "city" : "JEWETT", "loc" : [ -96.191841, 31.373925 ], "pop" : 2112, "state" : "TX" }
+{ "_id" : "75847", "city" : "KENNARD", "loc" : [ -95.154118, 31.338449 ], "pop" : 1784, "state" : "TX" }
+{ "_id" : "75850", "city" : "LEONA", "loc" : [ -95.928428, 31.14207 ], "pop" : 475, "state" : "TX" }
+{ "_id" : "75851", "city" : "LOVELADY", "loc" : [ -95.550057, 31.0564 ], "pop" : 3649, "state" : "TX" }
+{ "_id" : "75852", "city" : "MIDWAY", "loc" : [ -95.70894, 30.980579 ], "pop" : 3522, "state" : "TX" }
+{ "_id" : "75853", "city" : "MONTALBA", "loc" : [ -95.75926, 31.922165 ], "pop" : 2070, "state" : "TX" }
+{ "_id" : "75855", "city" : "OAKWOOD", "loc" : [ -95.902151, 31.602312 ], "pop" : 2637, "state" : "TX" }
+{ "_id" : "75856", "city" : "PENNINGTON", "loc" : [ -95.15867799999999, 31.161843 ], "pop" : 565, "state" : "TX" }
+{ "_id" : "75859", "city" : "STREETMAN", "loc" : [ -96.29876299999999, 31.888532 ], "pop" : 488, "state" : "TX" }
+{ "_id" : "75860", "city" : "TEAGUE", "loc" : [ -96.27778000000001, 31.632772 ], "pop" : 5318, "state" : "TX" }
+{ "_id" : "75861", "city" : "TENNESSEE COLONY", "loc" : [ -95.899798, 31.792882 ], "pop" : 11380, "state" : "TX" }
+{ "_id" : "75862", "city" : "TRINITY", "loc" : [ -95.340295, 30.941951 ], "pop" : 7585, "state" : "TX" }
+{ "_id" : "75901", "city" : "KELTYS", "loc" : [ -94.734185, 31.336004 ], "pop" : 46763, "state" : "TX" }
+{ "_id" : "75925", "city" : "FOREST", "loc" : [ -95.079786, 31.647815 ], "pop" : 3203, "state" : "TX" }
+{ "_id" : "75926", "city" : "APPLE SPRINGS", "loc" : [ -94.98115199999999, 31.226923 ], "pop" : 1079, "state" : "TX" }
+{ "_id" : "75928", "city" : "BON WIER", "loc" : [ -93.766465, 30.687557 ], "pop" : 2283, "state" : "TX" }
+{ "_id" : "75929", "city" : "BROADDUS", "loc" : [ -94.215552, 31.295241 ], "pop" : 1786, "state" : "TX" }
+{ "_id" : "75930", "city" : "BRONSON", "loc" : [ -93.999256, 31.339056 ], "pop" : 1922, "state" : "TX" }
+{ "_id" : "75931", "city" : "BROOKELAND", "loc" : [ -94.00356600000001, 31.106273 ], "pop" : 1883, "state" : "TX" }
+{ "_id" : "75932", "city" : "BURKEVILLE", "loc" : [ -93.658517, 31.009934 ], "pop" : 2275, "state" : "TX" }
+{ "_id" : "75933", "city" : "CALL", "loc" : [ -93.833355, 30.574132 ], "pop" : 1813, "state" : "TX" }
+{ "_id" : "75935", "city" : "CENTER", "loc" : [ -94.186947, 31.786468 ], "pop" : 11512, "state" : "TX" }
+{ "_id" : "75936", "city" : "CHESTER", "loc" : [ -94.458099, 30.928532 ], "pop" : 1588, "state" : "TX" }
+{ "_id" : "75937", "city" : "CHIRENO", "loc" : [ -94.430244, 31.511935 ], "pop" : 3983, "state" : "TX" }
+{ "_id" : "75938", "city" : "ROCKLAND", "loc" : [ -94.42181100000001, 30.909226 ], "pop" : 836, "state" : "TX" }
+{ "_id" : "75939", "city" : "BARNUM", "loc" : [ -94.7959, 31.000657 ], "pop" : 3969, "state" : "TX" }
+{ "_id" : "75941", "city" : "DIBOLL", "loc" : [ -94.77291099999999, 31.195028 ], "pop" : 7686, "state" : "TX" }
+{ "_id" : "75943", "city" : "DOUGLASS", "loc" : [ -94.869649, 31.657846 ], "pop" : 1005, "state" : "TX" }
+{ "_id" : "75946", "city" : "GARRISON", "loc" : [ -94.52660400000001, 31.811111 ], "pop" : 2365, "state" : "TX" }
+{ "_id" : "75948", "city" : "HEMPHILL", "loc" : [ -93.79045000000001, 31.316123 ], "pop" : 4180, "state" : "TX" }
+{ "_id" : "75949", "city" : "HUNTINGTON", "loc" : [ -94.566237, 31.283714 ], "pop" : 8415, "state" : "TX" }
+{ "_id" : "75951", "city" : "SAM RAYBURN", "loc" : [ -94.02148099999999, 30.925348 ], "pop" : 14219, "state" : "TX" }
+{ "_id" : "75954", "city" : "JOAQUIN", "loc" : [ -94.060833, 31.943989 ], "pop" : 2754, "state" : "TX" }
+{ "_id" : "75956", "city" : "BON AMI", "loc" : [ -93.92793399999999, 30.688217 ], "pop" : 5772, "state" : "TX" }
+{ "_id" : "75957", "city" : "MAGNOLIA SPRINGS", "loc" : [ -94.070896, 30.762882 ], "pop" : 111, "state" : "TX" }
+{ "_id" : "75959", "city" : "MILAM", "loc" : [ -93.831816, 31.47001 ], "pop" : 2187, "state" : "TX" }
+{ "_id" : "75960", "city" : "MOSCOW", "loc" : [ -94.85437, 30.917902 ], "pop" : 1018, "state" : "TX" }
+{ "_id" : "75961", "city" : "APPLEBY", "loc" : [ -94.651093, 31.618534 ], "pop" : 45332, "state" : "TX" }
+{ "_id" : "75966", "city" : "NEWTON", "loc" : [ -93.7497, 30.835074 ], "pop" : 4184, "state" : "TX" }
+{ "_id" : "75968", "city" : "PINELAND", "loc" : [ -93.97542, 31.241782 ], "pop" : 1279, "state" : "TX" }
+{ "_id" : "75969", "city" : "POLLOK", "loc" : [ -94.82540299999999, 31.429107 ], "pop" : 4725, "state" : "TX" }
+{ "_id" : "75972", "city" : "SAN AUGUSTINE", "loc" : [ -94.132581, 31.515173 ], "pop" : 5916, "state" : "TX" }
+{ "_id" : "75973", "city" : "SHELBYVILLE", "loc" : [ -93.969841, 31.713074 ], "pop" : 2949, "state" : "TX" }
+{ "_id" : "75974", "city" : "TENAHA", "loc" : [ -94.248773, 31.940812 ], "pop" : 1759, "state" : "TX" }
+{ "_id" : "75975", "city" : "TIMPSON", "loc" : [ -94.396733, 31.884089 ], "pop" : 3060, "state" : "TX" }
+{ "_id" : "75976", "city" : "WELLS", "loc" : [ -94.969351, 31.499755 ], "pop" : 1550, "state" : "TX" }
+{ "_id" : "75977", "city" : "WIERGATE", "loc" : [ -93.803854, 31.041417 ], "pop" : 290, "state" : "TX" }
+{ "_id" : "75979", "city" : "DOGWOOD", "loc" : [ -94.425494, 30.775133 ], "pop" : 5942, "state" : "TX" }
+{ "_id" : "75980", "city" : "ZAVALLA", "loc" : [ -94.38711499999999, 31.156863 ], "pop" : 2295, "state" : "TX" }
+{ "_id" : "76006", "city" : "ARLINGTON", "loc" : [ -97.08342500000001, 32.778494 ], "pop" : 18003, "state" : "TX" }
+{ "_id" : "76008", "city" : "ALEDO", "loc" : [ -97.60388500000001, 32.700351 ], "pop" : 5148, "state" : "TX" }
+{ "_id" : "76009", "city" : "ALVARADO", "loc" : [ -97.212971, 32.439499 ], "pop" : 13229, "state" : "TX" }
+{ "_id" : "76010", "city" : "ARLINGTON", "loc" : [ -97.082576, 32.720368 ], "pop" : 42405, "state" : "TX" }
+{ "_id" : "76011", "city" : "ARLINGTON", "loc" : [ -97.100302, 32.758236 ], "pop" : 23943, "state" : "TX" }
+{ "_id" : "76012", "city" : "ARLINGTON", "loc" : [ -97.13480800000001, 32.753962 ], "pop" : 24141, "state" : "TX" }
+{ "_id" : "76013", "city" : "ARLINGTON", "loc" : [ -97.14416, 32.719905 ], "pop" : 30252, "state" : "TX" }
+{ "_id" : "76014", "city" : "ARLINGTON", "loc" : [ -97.08755600000001, 32.695425 ], "pop" : 26087, "state" : "TX" }
+{ "_id" : "76015", "city" : "ARLINGTON", "loc" : [ -97.134685, 32.693125 ], "pop" : 14544, "state" : "TX" }
+{ "_id" : "76016", "city" : "ARLINGTON", "loc" : [ -97.190466, 32.688898 ], "pop" : 28219, "state" : "TX" }
+{ "_id" : "76017", "city" : "ARLINGTON", "loc" : [ -97.159899, 32.65545 ], "pop" : 42829, "state" : "TX" }
+{ "_id" : "76018", "city" : "ARLINGTON", "loc" : [ -97.091987, 32.654752 ], "pop" : 15590, "state" : "TX" }
+{ "_id" : "76020", "city" : "AZLE", "loc" : [ -97.54115299999999, 32.903453 ], "pop" : 18198, "state" : "TX" }
+{ "_id" : "76021", "city" : "BEDFORD", "loc" : [ -97.135797, 32.853579 ], "pop" : 31798, "state" : "TX" }
+{ "_id" : "76022", "city" : "BEDFORD", "loc" : [ -97.14535100000001, 32.829749 ], "pop" : 13186, "state" : "TX" }
+{ "_id" : "76023", "city" : "BOYD", "loc" : [ -97.586797, 33.059367 ], "pop" : 4292, "state" : "TX" }
+{ "_id" : "76028", "city" : "BURLESON", "loc" : [ -97.308959, 32.531624 ], "pop" : 33535, "state" : "TX" }
+{ "_id" : "76031", "city" : "CLEBURNE", "loc" : [ -97.39795700000001, 32.342891 ], "pop" : 25844, "state" : "TX" }
+{ "_id" : "76034", "city" : "COLLEYVILLE", "loc" : [ -97.14602600000001, 32.88721 ], "pop" : 11726, "state" : "TX" }
+{ "_id" : "76035", "city" : "CRESSON", "loc" : [ -97.651931, 32.530714 ], "pop" : 265, "state" : "TX" }
+{ "_id" : "76036", "city" : "CROWLEY", "loc" : [ -97.370306, 32.581398 ], "pop" : 8749, "state" : "TX" }
+{ "_id" : "76039", "city" : "EULESS", "loc" : [ -97.083212, 32.858172 ], "pop" : 22412, "state" : "TX" }
+{ "_id" : "76040", "city" : "EULESS", "loc" : [ -97.09720299999999, 32.826358 ], "pop" : 17220, "state" : "TX" }
+{ "_id" : "76041", "city" : "FORRESTON", "loc" : [ -96.887522, 32.281131 ], "pop" : 106, "state" : "TX" }
+{ "_id" : "76043", "city" : "GLEN ROSE", "loc" : [ -97.762911, 32.229762 ], "pop" : 4432, "state" : "TX" }
+{ "_id" : "76044", "city" : "GODLEY", "loc" : [ -97.534865, 32.428174 ], "pop" : 2595, "state" : "TX" }
+{ "_id" : "76048", "city" : "GRANBURY", "loc" : [ -97.774173, 32.42505 ], "pop" : 13718, "state" : "TX" }
+{ "_id" : "76049", "city" : "GRANBURY", "loc" : [ -97.72848399999999, 32.448811 ], "pop" : 10830, "state" : "TX" }
+{ "_id" : "76050", "city" : "GRANDVIEW", "loc" : [ -97.235069, 32.277856 ], "pop" : 4850, "state" : "TX" }
+{ "_id" : "76051", "city" : "GRAPEVINE", "loc" : [ -97.096203, 32.93143 ], "pop" : 30774, "state" : "TX" }
+{ "_id" : "76052", "city" : "HASLET", "loc" : [ -97.33718500000001, 32.955734 ], "pop" : 866, "state" : "TX" }
+{ "_id" : "76053", "city" : "HURST", "loc" : [ -97.175613, 32.821107 ], "pop" : 24835, "state" : "TX" }
+{ "_id" : "76054", "city" : "HURST", "loc" : [ -97.175521, 32.855832 ], "pop" : 9953, "state" : "TX" }
+{ "_id" : "76055", "city" : "ITASCA", "loc" : [ -97.146034, 32.163589 ], "pop" : 2341, "state" : "TX" }
+{ "_id" : "76058", "city" : "JOSHUA", "loc" : [ -97.401123, 32.466252 ], "pop" : 12544, "state" : "TX" }
+{ "_id" : "76059", "city" : "KEENE", "loc" : [ -97.32868000000001, 32.393659 ], "pop" : 5863, "state" : "TX" }
+{ "_id" : "76060", "city" : "KENNEDALE", "loc" : [ -97.213853, 32.64316 ], "pop" : 5362, "state" : "TX" }
+{ "_id" : "76063", "city" : "MANSFIELD", "loc" : [ -97.14155100000001, 32.577258 ], "pop" : 17381, "state" : "TX" }
+{ "_id" : "76064", "city" : "MAYPEARL", "loc" : [ -96.98802999999999, 32.327878 ], "pop" : 2842, "state" : "TX" }
+{ "_id" : "76065", "city" : "MIDLOTHIAN", "loc" : [ -96.993551, 32.475743 ], "pop" : 10271, "state" : "TX" }
+{ "_id" : "76066", "city" : "MILLSAP", "loc" : [ -97.87838600000001, 32.670019 ], "pop" : 9110, "state" : "TX" }
+{ "_id" : "76067", "city" : "MINERAL WELLS", "loc" : [ -98.063051, 32.810283 ], "pop" : 23617, "state" : "TX" }
+{ "_id" : "76070", "city" : "NEMO", "loc" : [ -97.656668, 32.271312 ], "pop" : 206, "state" : "TX" }
+{ "_id" : "76071", "city" : "NEWARK", "loc" : [ -97.510696, 33.007099 ], "pop" : 2670, "state" : "TX" }
+{ "_id" : "76073", "city" : "PARADISE", "loc" : [ -97.697423, 33.082607 ], "pop" : 3009, "state" : "TX" }
+{ "_id" : "76077", "city" : "RAINBOW", "loc" : [ -97.70652, 32.281216 ], "pop" : 722, "state" : "TX" }
+{ "_id" : "76078", "city" : "RHOME", "loc" : [ -97.48168800000001, 33.054045 ], "pop" : 1771, "state" : "TX" }
+{ "_id" : "76082", "city" : "SPRINGTOWN", "loc" : [ -97.634951, 32.966021 ], "pop" : 7377, "state" : "TX" }
+{ "_id" : "76084", "city" : "VENUS", "loc" : [ -97.108734, 32.432975 ], "pop" : 2726, "state" : "TX" }
+{ "_id" : "76086", "city" : "WEATHERFORD", "loc" : [ -97.738591, 32.784074 ], "pop" : 29937, "state" : "TX" }
+{ "_id" : "76087", "city" : "WEATHERFORD", "loc" : [ -97.68943899999999, 32.749473 ], "pop" : 2502, "state" : "TX" }
+{ "_id" : "76092", "city" : "GRAPEVINE", "loc" : [ -97.148066, 32.956456 ], "pop" : 5638, "state" : "TX" }
+{ "_id" : "76093", "city" : "RIO VISTA", "loc" : [ -97.367825, 32.253168 ], "pop" : 1819, "state" : "TX" }
+{ "_id" : "76102", "city" : "FORT WORTH", "loc" : [ -97.328023, 32.758897 ], "pop" : 8550, "state" : "TX" }
+{ "_id" : "76103", "city" : "FORT WORTH", "loc" : [ -97.26039400000001, 32.747005 ], "pop" : 12611, "state" : "TX" }
+{ "_id" : "76104", "city" : "FORT WORTH", "loc" : [ -97.318409, 32.725551 ], "pop" : 20012, "state" : "TX" }
+{ "_id" : "76105", "city" : "FORT WORTH", "loc" : [ -97.26899, 32.723325 ], "pop" : 20947, "state" : "TX" }
+{ "_id" : "76106", "city" : "FORT WORTH", "loc" : [ -97.356008, 32.796849 ], "pop" : 44367, "state" : "TX" }
+{ "_id" : "76107", "city" : "FORT WORTH", "loc" : [ -97.385248, 32.739175 ], "pop" : 27082, "state" : "TX" }
+{ "_id" : "76108", "city" : "WHITE SETTLEMENT", "loc" : [ -97.474063, 32.759271 ], "pop" : 22510, "state" : "TX" }
+{ "_id" : "76109", "city" : "FORT WORTH", "loc" : [ -97.37887600000001, 32.700246 ], "pop" : 21893, "state" : "TX" }
+{ "_id" : "76110", "city" : "FORT WORTH", "loc" : [ -97.33750499999999, 32.706505 ], "pop" : 27828, "state" : "TX" }
+{ "_id" : "76111", "city" : "FORT WORTH", "loc" : [ -97.300327, 32.782382 ], "pop" : 17740, "state" : "TX" }
+{ "_id" : "76112", "city" : "FORT WORTH", "loc" : [ -97.21812199999999, 32.749297 ], "pop" : 35311, "state" : "TX" }
+{ "_id" : "76114", "city" : "RIVER OAKS", "loc" : [ -97.401526, 32.775379 ], "pop" : 21921, "state" : "TX" }
+{ "_id" : "76115", "city" : "FORT WORTH", "loc" : [ -97.333634, 32.679618 ], "pop" : 16544, "state" : "TX" }
+{ "_id" : "76116", "city" : "FORT WORTH", "loc" : [ -97.448279, 32.723032 ], "pop" : 38210, "state" : "TX" }
+{ "_id" : "76117", "city" : "HALTOM CITY", "loc" : [ -97.27089100000001, 32.808742 ], "pop" : 27312, "state" : "TX" }
+{ "_id" : "76118", "city" : "NORTH RICHLAND H", "loc" : [ -97.222781, 32.808944 ], "pop" : 9764, "state" : "TX" }
+{ "_id" : "76119", "city" : "FORT WORTH", "loc" : [ -97.267492, 32.691379 ], "pop" : 36951, "state" : "TX" }
+{ "_id" : "76120", "city" : "FORT WORTH", "loc" : [ -97.178112, 32.763912 ], "pop" : 8601, "state" : "TX" }
+{ "_id" : "76123", "city" : "FORT WORTH", "loc" : [ -97.365838, 32.625361 ], "pop" : 5314, "state" : "TX" }
+{ "_id" : "76126", "city" : "BENBROOK", "loc" : [ -97.464141, 32.670023 ], "pop" : 14301, "state" : "TX" }
+{ "_id" : "76127", "city" : "CARSWELL AFB", "loc" : [ -97.435453, 32.771846 ], "pop" : 940, "state" : "TX" }
+{ "_id" : "76131", "city" : "FORT WORTH", "loc" : [ -97.337656, 32.863156 ], "pop" : 3738, "state" : "TX" }
+{ "_id" : "76132", "city" : "FORT WORTH", "loc" : [ -97.405626, 32.671092 ], "pop" : 13724, "state" : "TX" }
+{ "_id" : "76133", "city" : "FORT WORTH", "loc" : [ -97.375849, 32.652561 ], "pop" : 44032, "state" : "TX" }
+{ "_id" : "76134", "city" : "FORT WORTH", "loc" : [ -97.33246699999999, 32.646886 ], "pop" : 17442, "state" : "TX" }
+{ "_id" : "76135", "city" : "FORT WORTH", "loc" : [ -97.45191, 32.824844 ], "pop" : 13135, "state" : "TX" }
+{ "_id" : "76137", "city" : "FORT WORTH", "loc" : [ -97.289114, 32.866421 ], "pop" : 15226, "state" : "TX" }
+{ "_id" : "76140", "city" : "EVERMAN", "loc" : [ -97.27040599999999, 32.631332 ], "pop" : 17658, "state" : "TX" }
+{ "_id" : "76148", "city" : "WATAUGA", "loc" : [ -97.24902899999999, 32.8681 ], "pop" : 22794, "state" : "TX" }
+{ "_id" : "76155", "city" : "FORT WORTH", "loc" : [ -97.050285, 32.824742 ], "pop" : 2096, "state" : "TX" }
+{ "_id" : "76177", "city" : "FORT WORTH", "loc" : [ -97.332671, 32.901017 ], "pop" : 61, "state" : "TX" }
+{ "_id" : "76179", "city" : "SAGINAW", "loc" : [ -97.403149, 32.872961 ], "pop" : 15143, "state" : "TX" }
+{ "_id" : "76180", "city" : "NORTH RICHLAND H", "loc" : [ -97.220714, 32.853966 ], "pop" : 44496, "state" : "TX" }
+{ "_id" : "76201", "city" : "DENTON", "loc" : [ -97.13143599999999, 33.22893 ], "pop" : 48643, "state" : "TX" }
+{ "_id" : "76205", "city" : "DENTON", "loc" : [ -97.101833, 33.180106 ], "pop" : 27830, "state" : "TX" }
+{ "_id" : "76225", "city" : "ALVORD", "loc" : [ -97.68848800000001, 33.36982 ], "pop" : 1748, "state" : "TX" }
+{ "_id" : "76226", "city" : "ARGYLE", "loc" : [ -97.159977, 33.106244 ], "pop" : 4420, "state" : "TX" }
+{ "_id" : "76227", "city" : "AUBREY", "loc" : [ -96.987866, 33.291997 ], "pop" : 3089, "state" : "TX" }
+{ "_id" : "76228", "city" : "BELLEVUE", "loc" : [ -98.15737300000001, 33.58789 ], "pop" : 1697, "state" : "TX" }
+{ "_id" : "76230", "city" : "BOWIE", "loc" : [ -97.83733700000001, 33.556796 ], "pop" : 8686, "state" : "TX" }
+{ "_id" : "76233", "city" : "COLLINSVILLE", "loc" : [ -96.901365, 33.558012 ], "pop" : 1681, "state" : "TX" }
+{ "_id" : "76234", "city" : "DECATUR", "loc" : [ -97.573995, 33.235077 ], "pop" : 9323, "state" : "TX" }
+{ "_id" : "76238", "city" : "ERA", "loc" : [ -97.29235799999999, 33.50101 ], "pop" : 264, "state" : "TX" }
+{ "_id" : "76239", "city" : "FORESTBURG", "loc" : [ -97.584774, 33.539778 ], "pop" : 805, "state" : "TX" }
+{ "_id" : "76240", "city" : "LAKE KIOWA", "loc" : [ -97.103208, 33.625943 ], "pop" : 24108, "state" : "TX" }
+{ "_id" : "76245", "city" : "GORDONVILLE", "loc" : [ -96.84027, 33.834283 ], "pop" : 1664, "state" : "TX" }
+{ "_id" : "76247", "city" : "JUSTIN", "loc" : [ -97.309254, 33.073375 ], "pop" : 3422, "state" : "TX" }
+{ "_id" : "76248", "city" : "KELLER", "loc" : [ -97.24888300000001, 32.927556 ], "pop" : 14313, "state" : "TX" }
+{ "_id" : "76249", "city" : "KRUM", "loc" : [ -97.26745200000001, 33.27337 ], "pop" : 3198, "state" : "TX" }
+{ "_id" : "76250", "city" : "LINDSAY", "loc" : [ -97.221436, 33.63601 ], "pop" : 610, "state" : "TX" }
+{ "_id" : "76251", "city" : "MONTAGUE", "loc" : [ -97.72822600000001, 33.663899 ], "pop" : 617, "state" : "TX" }
+{ "_id" : "76252", "city" : "MUENSTER", "loc" : [ -97.362409, 33.659549 ], "pop" : 3042, "state" : "TX" }
+{ "_id" : "76255", "city" : "NOCONA", "loc" : [ -97.72698200000001, 33.798163 ], "pop" : 4365, "state" : "TX" }
+{ "_id" : "76258", "city" : "PILOT POINT", "loc" : [ -96.944554, 33.370983 ], "pop" : 4183, "state" : "TX" }
+{ "_id" : "76259", "city" : "PONDER", "loc" : [ -97.28481499999999, 33.177383 ], "pop" : 1443, "state" : "TX" }
+{ "_id" : "76261", "city" : "RINGGOLD", "loc" : [ -97.94398200000001, 33.816392 ], "pop" : 243, "state" : "TX" }
+{ "_id" : "76262", "city" : "TROPHY CLUB", "loc" : [ -97.20534600000001, 32.98639 ], "pop" : 11484, "state" : "TX" }
+{ "_id" : "76263", "city" : "ROSSTON", "loc" : [ -97.454172, 33.483795 ], "pop" : 30, "state" : "TX" }
+{ "_id" : "76264", "city" : "SADLER", "loc" : [ -96.840017, 33.730989 ], "pop" : 349, "state" : "TX" }
+{ "_id" : "76265", "city" : "SAINT JO", "loc" : [ -97.55675599999999, 33.744024 ], "pop" : 2071, "state" : "TX" }
+{ "_id" : "76266", "city" : "SANGER", "loc" : [ -97.181432, 33.356266 ], "pop" : 7440, "state" : "TX" }
+{ "_id" : "76270", "city" : "SUNSET", "loc" : [ -97.77089100000001, 33.453909 ], "pop" : 487, "state" : "TX" }
+{ "_id" : "76271", "city" : "TIOGA", "loc" : [ -96.909712, 33.467493 ], "pop" : 857, "state" : "TX" }
+{ "_id" : "76272", "city" : "VALLEY VIEW", "loc" : [ -97.231053, 33.502166 ], "pop" : 2754, "state" : "TX" }
+{ "_id" : "76273", "city" : "WHITESBORO", "loc" : [ -96.878984, 33.659021 ], "pop" : 5920, "state" : "TX" }
+{ "_id" : "76301", "city" : "WICHITA FALLS", "loc" : [ -98.49764500000001, 33.905284 ], "pop" : 15309, "state" : "TX" }
+{ "_id" : "76302", "city" : "WICHITA FALLS", "loc" : [ -98.493987, 33.864278 ], "pop" : 10724, "state" : "TX" }
+{ "_id" : "76303", "city" : "WICHITA FALLS", "loc" : [ -98.460812, 33.899837 ], "pop" : 3922, "state" : "TX" }
+{ "_id" : "76304", "city" : "WICHITA FALLS", "loc" : [ -98.500491, 33.930806 ], "pop" : 4529, "state" : "TX" }
+{ "_id" : "76305", "city" : "WICHITA FALLS", "loc" : [ -98.540679, 33.937345 ], "pop" : 8522, "state" : "TX" }
+{ "_id" : "76306", "city" : "WICHITA FALLS", "loc" : [ -98.524835, 33.974595 ], "pop" : 6808, "state" : "TX" }
+{ "_id" : "76308", "city" : "WICHITA FALLS", "loc" : [ -98.53396499999999, 33.863258 ], "pop" : 19151, "state" : "TX" }
+{ "_id" : "76309", "city" : "WICHITA FALLS", "loc" : [ -98.534288, 33.893084 ], "pop" : 12500, "state" : "TX" }
+{ "_id" : "76310", "city" : "WICHITA FALLS", "loc" : [ -98.575548, 33.858122 ], "pop" : 11497, "state" : "TX" }
+{ "_id" : "76311", "city" : "SHEPPARD AFB", "loc" : [ -98.508771, 33.982353 ], "pop" : 7080, "state" : "TX" }
+{ "_id" : "76354", "city" : "BURKBURNETT", "loc" : [ -98.570842, 34.085989 ], "pop" : 10558, "state" : "TX" }
+{ "_id" : "76357", "city" : "BYERS", "loc" : [ -98.18392900000001, 34.072812 ], "pop" : 665, "state" : "TX" }
+{ "_id" : "76359", "city" : "ELBERT", "loc" : [ -99.05521400000001, 33.015687 ], "pop" : 445, "state" : "TX" }
+{ "_id" : "76360", "city" : "ELECTRA", "loc" : [ -98.91545000000001, 34.036234 ], "pop" : 3580, "state" : "TX" }
+{ "_id" : "76363", "city" : "GOREE", "loc" : [ -99.525806, 33.474832 ], "pop" : 523, "state" : "TX" }
+{ "_id" : "76364", "city" : "HARROLD", "loc" : [ -99.03505199999999, 34.097097 ], "pop" : 369, "state" : "TX" }
+{ "_id" : "76365", "city" : "HENRIETTA", "loc" : [ -98.25997599999999, 33.819609 ], "pop" : 6020, "state" : "TX" }
+{ "_id" : "76366", "city" : "HOLLIDAY", "loc" : [ -98.657634, 33.675141 ], "pop" : 5949, "state" : "TX" }
+{ "_id" : "76367", "city" : "IOWA PARK", "loc" : [ -98.674497, 33.94235 ], "pop" : 9443, "state" : "TX" }
+{ "_id" : "76371", "city" : "MUNDAY", "loc" : [ -99.63262400000001, 33.456088 ], "pop" : 2028, "state" : "TX" }
+{ "_id" : "76372", "city" : "NEWCASTLE", "loc" : [ -98.74464399999999, 33.190103 ], "pop" : 905, "state" : "TX" }
+{ "_id" : "76373", "city" : "OKLAUNION", "loc" : [ -99.160234, 34.120372 ], "pop" : 338, "state" : "TX" }
+{ "_id" : "76374", "city" : "OLNEY", "loc" : [ -98.742695, 33.360135 ], "pop" : 4554, "state" : "TX" }
+{ "_id" : "76377", "city" : "PETROLIA", "loc" : [ -98.269223, 34.027331 ], "pop" : 1642, "state" : "TX" }
+{ "_id" : "76379", "city" : "SCOTLAND", "loc" : [ -98.464983, 33.653486 ], "pop" : 398, "state" : "TX" }
+{ "_id" : "76380", "city" : "SEYMOUR", "loc" : [ -99.25872699999999, 33.591445 ], "pop" : 4208, "state" : "TX" }
+{ "_id" : "76383", "city" : "VERA", "loc" : [ -99.75909799999999, 33.615469 ], "pop" : 481, "state" : "TX" }
+{ "_id" : "76384", "city" : "VERNON", "loc" : [ -99.30301, 34.149135 ], "pop" : 14414, "state" : "TX" }
+{ "_id" : "76388", "city" : "WEINERT", "loc" : [ -99.666431, 33.324872 ], "pop" : 301, "state" : "TX" }
+{ "_id" : "76389", "city" : "WINDTHORST", "loc" : [ -98.437589, 33.57957 ], "pop" : 381, "state" : "TX" }
+{ "_id" : "76401", "city" : "STEPHENVILLE", "loc" : [ -98.222407, 32.221372 ], "pop" : 19745, "state" : "TX" }
+{ "_id" : "76424", "city" : "BRECKENRIDGE", "loc" : [ -98.909882, 32.753166 ], "pop" : 8803, "state" : "TX" }
+{ "_id" : "76426", "city" : "BRIDGEPORT", "loc" : [ -97.78098, 33.187027 ], "pop" : 9158, "state" : "TX" }
+{ "_id" : "76427", "city" : "BRYSON", "loc" : [ -98.370256, 33.15947 ], "pop" : 915, "state" : "TX" }
+{ "_id" : "76429", "city" : "CADDO", "loc" : [ -98.65898300000001, 32.688617 ], "pop" : 127, "state" : "TX" }
+{ "_id" : "76430", "city" : "ALBANY", "loc" : [ -99.319581, 32.719005 ], "pop" : 2858, "state" : "TX" }
+{ "_id" : "76431", "city" : "CHICO", "loc" : [ -97.803133, 33.319315 ], "pop" : 2657, "state" : "TX" }
+{ "_id" : "76432", "city" : "BLANKET", "loc" : [ -98.83108900000001, 31.78819 ], "pop" : 1929, "state" : "TX" }
+{ "_id" : "76433", "city" : "BLUFF DALE", "loc" : [ -98.163775, 32.401791 ], "pop" : 1751, "state" : "TX" }
+{ "_id" : "76435", "city" : "CARBON", "loc" : [ -98.83479, 32.270125 ], "pop" : 462, "state" : "TX" }
+{ "_id" : "76436", "city" : "CARLTON", "loc" : [ -98.152519, 31.911438 ], "pop" : 235, "state" : "TX" }
+{ "_id" : "76437", "city" : "CISCO", "loc" : [ -98.986507, 32.380043 ], "pop" : 4906, "state" : "TX" }
+{ "_id" : "76442", "city" : "COMANCHE", "loc" : [ -98.608227, 31.911637 ], "pop" : 7208, "state" : "TX" }
+{ "_id" : "76443", "city" : "CROSS PLAINS", "loc" : [ -99.18718, 32.148159 ], "pop" : 1928, "state" : "TX" }
+{ "_id" : "76444", "city" : "DE LEON", "loc" : [ -98.54894, 32.108742 ], "pop" : 4401, "state" : "TX" }
+{ "_id" : "76445", "city" : "DESDEMONA", "loc" : [ -98.56732700000001, 32.281877 ], "pop" : 366, "state" : "TX" }
+{ "_id" : "76446", "city" : "DUBLIN", "loc" : [ -98.34546899999999, 32.090873 ], "pop" : 5029, "state" : "TX" }
+{ "_id" : "76448", "city" : "EASTLAND", "loc" : [ -98.807101, 32.399418 ], "pop" : 5837, "state" : "TX" }
+{ "_id" : "76449", "city" : "GRAFORD", "loc" : [ -98.337002, 32.924192 ], "pop" : 2235, "state" : "TX" }
+{ "_id" : "76450", "city" : "GRAHAM", "loc" : [ -98.583212, 33.099283 ], "pop" : 12511, "state" : "TX" }
+{ "_id" : "76453", "city" : "GORDON", "loc" : [ -98.36321100000001, 32.547828 ], "pop" : 566, "state" : "TX" }
+{ "_id" : "76454", "city" : "GORMAN", "loc" : [ -98.683408, 32.223441 ], "pop" : 1773, "state" : "TX" }
+{ "_id" : "76455", "city" : "GUSTINE", "loc" : [ -98.383488, 31.872448 ], "pop" : 1680, "state" : "TX" }
+{ "_id" : "76457", "city" : "HICO", "loc" : [ -98.024933, 31.959718 ], "pop" : 1962, "state" : "TX" }
+{ "_id" : "76458", "city" : "JACKSBORO", "loc" : [ -98.168138, 33.234655 ], "pop" : 4664, "state" : "TX" }
+{ "_id" : "76459", "city" : "JERMYN", "loc" : [ -98.39314899999999, 33.263554 ], "pop" : 154, "state" : "TX" }
+{ "_id" : "76460", "city" : "LOVING", "loc" : [ -98.50237, 33.26886 ], "pop" : 156, "state" : "TX" }
+{ "_id" : "76462", "city" : "LIPAN", "loc" : [ -97.953614, 32.507218 ], "pop" : 1582, "state" : "TX" }
+{ "_id" : "76463", "city" : "MINGUS", "loc" : [ -98.42626199999999, 32.562665 ], "pop" : 278, "state" : "TX" }
+{ "_id" : "76464", "city" : "MORAN", "loc" : [ -99.165567, 32.554909 ], "pop" : 458, "state" : "TX" }
+{ "_id" : "76470", "city" : "RANGER", "loc" : [ -98.67465900000001, 32.46809 ], "pop" : 3414, "state" : "TX" }
+{ "_id" : "76471", "city" : "RISING STAR", "loc" : [ -98.98585199999999, 32.127986 ], "pop" : 1810, "state" : "TX" }
+{ "_id" : "76472", "city" : "SANTO", "loc" : [ -98.179675, 32.597935 ], "pop" : 1433, "state" : "TX" }
+{ "_id" : "76474", "city" : "SIDNEY", "loc" : [ -98.767995, 31.932031 ], "pop" : 92, "state" : "TX" }
+{ "_id" : "76475", "city" : "STRAWN", "loc" : [ -98.499467, 32.5945 ], "pop" : 968, "state" : "TX" }
+{ "_id" : "76476", "city" : "TOLAR", "loc" : [ -97.880208, 32.377246 ], "pop" : 2586, "state" : "TX" }
+{ "_id" : "76483", "city" : "THROCKMORTON", "loc" : [ -99.183812, 33.179446 ], "pop" : 1321, "state" : "TX" }
+{ "_id" : "76484", "city" : "PALO PINTO", "loc" : [ -98.270262, 32.725315 ], "pop" : 867, "state" : "TX" }
+{ "_id" : "76486", "city" : "PERRIN", "loc" : [ -98.044006, 33.058453 ], "pop" : 1065, "state" : "TX" }
+{ "_id" : "76487", "city" : "POOLVILLE", "loc" : [ -97.847229, 32.968023 ], "pop" : 1549, "state" : "TX" }
+{ "_id" : "76490", "city" : "WHITT", "loc" : [ -98.02100799999999, 32.955459 ], "pop" : 305, "state" : "TX" }
+{ "_id" : "76491", "city" : "WOODSON", "loc" : [ -99.015953, 33.301972 ], "pop" : 114, "state" : "TX" }
+{ "_id" : "76501", "city" : "TEMPLE", "loc" : [ -97.334264, 31.089518 ], "pop" : 16400, "state" : "TX" }
+{ "_id" : "76502", "city" : "TEMPLE", "loc" : [ -97.389781, 31.071004 ], "pop" : 15632, "state" : "TX" }
+{ "_id" : "76504", "city" : "TEMPLE", "loc" : [ -97.36476399999999, 31.091742 ], "pop" : 20273, "state" : "TX" }
+{ "_id" : "76511", "city" : "BARTLETT", "loc" : [ -97.42630200000001, 30.799056 ], "pop" : 727, "state" : "TX" }
+{ "_id" : "76513", "city" : "BELTON", "loc" : [ -97.472025, 31.072298 ], "pop" : 20331, "state" : "TX" }
+{ "_id" : "76518", "city" : "BUCKHOLTS", "loc" : [ -97.124135, 30.885756 ], "pop" : 1072, "state" : "TX" }
+{ "_id" : "76519", "city" : "BURLINGTON", "loc" : [ -96.88530799999999, 30.945691 ], "pop" : 1312, "state" : "TX" }
+{ "_id" : "76520", "city" : "CAMERON", "loc" : [ -96.976562, 30.852713 ], "pop" : 6965, "state" : "TX" }
+{ "_id" : "76522", "city" : "IZORO", "loc" : [ -97.912132, 31.125799 ], "pop" : 26431, "state" : "TX" }
+{ "_id" : "76523", "city" : "DAVILLA", "loc" : [ -97.20086499999999, 30.767471 ], "pop" : 1079, "state" : "TX" }
+{ "_id" : "76524", "city" : "EDDY", "loc" : [ -97.270926, 31.326724 ], "pop" : 2544, "state" : "TX" }
+{ "_id" : "76525", "city" : "BEE HOUSE", "loc" : [ -98.05517500000001, 31.403967 ], "pop" : 1179, "state" : "TX" }
+{ "_id" : "76526", "city" : "FLAT", "loc" : [ -97.589777, 31.306475 ], "pop" : 774, "state" : "TX" }
+{ "_id" : "76527", "city" : "FLORENCE", "loc" : [ -97.834423, 30.78137 ], "pop" : 3703, "state" : "TX" }
+{ "_id" : "76528", "city" : "TURNERSVILLE", "loc" : [ -97.72428600000001, 31.447646 ], "pop" : 14415, "state" : "TX" }
+{ "_id" : "76530", "city" : "GRANGER", "loc" : [ -97.445065, 30.739813 ], "pop" : 3160, "state" : "TX" }
+{ "_id" : "76531", "city" : "HAMILTON", "loc" : [ -98.113051, 31.678116 ], "pop" : 5260, "state" : "TX" }
+{ "_id" : "76534", "city" : "HOLLAND", "loc" : [ -97.385695, 30.879977 ], "pop" : 2223, "state" : "TX" }
+{ "_id" : "76537", "city" : "JARRELL", "loc" : [ -97.60083299999999, 30.748406 ], "pop" : 3430, "state" : "TX" }
+{ "_id" : "76538", "city" : "JONESBORO", "loc" : [ -97.775155, 31.599601 ], "pop" : 793, "state" : "TX" }
+{ "_id" : "76539", "city" : "KEMPNER", "loc" : [ -97.97206799999999, 31.073051 ], "pop" : 3884, "state" : "TX" }
+{ "_id" : "76541", "city" : "KILLEEN", "loc" : [ -97.727808, 31.116426 ], "pop" : 22853, "state" : "TX" }
+{ "_id" : "76542", "city" : "HARKER HEIGHTS", "loc" : [ -97.746736, 31.075056 ], "pop" : 25829, "state" : "TX" }
+{ "_id" : "76543", "city" : "HARKER HEIGHTS", "loc" : [ -97.67686399999999, 31.100505 ], "pop" : 35052, "state" : "TX" }
+{ "_id" : "76544", "city" : "FORT HOOD", "loc" : [ -97.776404, 31.137953 ], "pop" : 36657, "state" : "TX" }
+{ "_id" : "76550", "city" : "LAMPASAS", "loc" : [ -98.183361, 31.067957 ], "pop" : 7698, "state" : "TX" }
+{ "_id" : "76556", "city" : "MILANO", "loc" : [ -96.803477, 30.736612 ], "pop" : 2187, "state" : "TX" }
+{ "_id" : "76557", "city" : "MOODY", "loc" : [ -97.40995700000001, 31.253321 ], "pop" : 4411, "state" : "TX" }
+{ "_id" : "76559", "city" : "NOLANVILLE", "loc" : [ -97.594109, 31.083271 ], "pop" : 1820, "state" : "TX" }
+{ "_id" : "76561", "city" : "OGLESBY", "loc" : [ -97.550093, 31.443767 ], "pop" : 1221, "state" : "TX" }
+{ "_id" : "76565", "city" : "POTTSVILLE", "loc" : [ -98.356077, 31.68374 ], "pop" : 279, "state" : "TX" }
+{ "_id" : "76566", "city" : "PURMELA", "loc" : [ -97.88894500000001, 31.472647 ], "pop" : 1111, "state" : "TX" }
+{ "_id" : "76567", "city" : "ROCKDALE", "loc" : [ -97.00790000000001, 30.658282 ], "pop" : 8052, "state" : "TX" }
+{ "_id" : "76569", "city" : "ROGERS", "loc" : [ -97.222793, 30.955013 ], "pop" : 2565, "state" : "TX" }
+{ "_id" : "76570", "city" : "ROSEBUD", "loc" : [ -96.975455, 31.092208 ], "pop" : 3093, "state" : "TX" }
+{ "_id" : "76571", "city" : "SALADO", "loc" : [ -97.532999, 30.949388 ], "pop" : 3454, "state" : "TX" }
+{ "_id" : "76574", "city" : "TAYLOR", "loc" : [ -97.44010299999999, 30.58071 ], "pop" : 14135, "state" : "TX" }
+{ "_id" : "76577", "city" : "THORNDALE", "loc" : [ -97.176446, 30.608237 ], "pop" : 2279, "state" : "TX" }
+{ "_id" : "76578", "city" : "THRALL", "loc" : [ -97.289261, 30.591981 ], "pop" : 852, "state" : "TX" }
+{ "_id" : "76579", "city" : "TROY", "loc" : [ -97.285205, 31.175855 ], "pop" : 3791, "state" : "TX" }
+{ "_id" : "76621", "city" : "ABBOTT", "loc" : [ -97.06714599999999, 31.891642 ], "pop" : 577, "state" : "TX" }
+{ "_id" : "76622", "city" : "AQUILLA", "loc" : [ -97.22577, 31.858882 ], "pop" : 1901, "state" : "TX" }
+{ "_id" : "76624", "city" : "AXTELL", "loc" : [ -96.988178, 31.660966 ], "pop" : 3235, "state" : "TX" }
+{ "_id" : "76626", "city" : "BLOOMING GROVE", "loc" : [ -96.700991, 32.075839 ], "pop" : 1594, "state" : "TX" }
+{ "_id" : "76627", "city" : "BLUM", "loc" : [ -97.365183, 32.105183 ], "pop" : 2737, "state" : "TX" }
+{ "_id" : "76629", "city" : "BREMOND", "loc" : [ -96.66974399999999, 31.156007 ], "pop" : 1883, "state" : "TX" }
+{ "_id" : "76630", "city" : "BRUCEVILLE", "loc" : [ -97.234244, 31.326708 ], "pop" : 477, "state" : "TX" }
+{ "_id" : "76631", "city" : "BYNUM", "loc" : [ -96.98370199999999, 31.990668 ], "pop" : 496, "state" : "TX" }
+{ "_id" : "76632", "city" : "CHILTON", "loc" : [ -97.09002, 31.310018 ], "pop" : 2304, "state" : "TX" }
+{ "_id" : "76633", "city" : "CHINA SPRING", "loc" : [ -97.30022099999999, 31.667266 ], "pop" : 3030, "state" : "TX" }
+{ "_id" : "76634", "city" : "LAGUNA PARK", "loc" : [ -97.515282, 31.799689 ], "pop" : 6410, "state" : "TX" }
+{ "_id" : "76635", "city" : "COOLIDGE", "loc" : [ -96.65774399999999, 31.743804 ], "pop" : 1042, "state" : "TX" }
+{ "_id" : "76636", "city" : "COVINGTON", "loc" : [ -97.259091, 32.159538 ], "pop" : 767, "state" : "TX" }
+{ "_id" : "76637", "city" : "CRANFILLS GAP", "loc" : [ -97.78537, 31.781071 ], "pop" : 687, "state" : "TX" }
+{ "_id" : "76638", "city" : "CRAWFORD", "loc" : [ -97.38999200000001, 31.559765 ], "pop" : 3473, "state" : "TX" }
+{ "_id" : "76639", "city" : "DAWSON", "loc" : [ -96.708483, 31.897429 ], "pop" : 1457, "state" : "TX" }
+{ "_id" : "76640", "city" : "ELM MOTT", "loc" : [ -97.113838, 31.672547 ], "pop" : 4183, "state" : "TX" }
+{ "_id" : "76641", "city" : "FROST", "loc" : [ -96.76843700000001, 32.027545 ], "pop" : 1831, "state" : "TX" }
+{ "_id" : "76642", "city" : "GROESBECK", "loc" : [ -96.523381, 31.535667 ], "pop" : 5538, "state" : "TX" }
+{ "_id" : "76643", "city" : "HEWITT", "loc" : [ -97.196556, 31.458166 ], "pop" : 8487, "state" : "TX" }
+{ "_id" : "76645", "city" : "HILLSBORO", "loc" : [ -97.11979100000001, 32.014942 ], "pop" : 8966, "state" : "TX" }
+{ "_id" : "76648", "city" : "HUBBARD", "loc" : [ -96.80001, 31.843559 ], "pop" : 2015, "state" : "TX" }
+{ "_id" : "76649", "city" : "IREDELL", "loc" : [ -97.879283, 31.972197 ], "pop" : 813, "state" : "TX" }
+{ "_id" : "76651", "city" : "ITALY", "loc" : [ -96.88229, 32.178508 ], "pop" : 2321, "state" : "TX" }
+{ "_id" : "76652", "city" : "KOPPERL", "loc" : [ -97.542085, 32.103491 ], "pop" : 820, "state" : "TX" }
+{ "_id" : "76653", "city" : "KOSSE", "loc" : [ -96.61947499999999, 31.314704 ], "pop" : 854, "state" : "TX" }
+{ "_id" : "76655", "city" : "LORENA", "loc" : [ -97.230161, 31.409271 ], "pop" : 4007, "state" : "TX" }
+{ "_id" : "76656", "city" : "LOTT", "loc" : [ -97.058143, 31.192462 ], "pop" : 2005, "state" : "TX" }
+{ "_id" : "76657", "city" : "MC GREGOR", "loc" : [ -97.394318, 31.443099 ], "pop" : 5853, "state" : "TX" }
+{ "_id" : "76660", "city" : "MALONE", "loc" : [ -96.890682, 31.923979 ], "pop" : 491, "state" : "TX" }
+{ "_id" : "76661", "city" : "MARLIN", "loc" : [ -96.888942, 31.303592 ], "pop" : 8810, "state" : "TX" }
+{ "_id" : "76664", "city" : "MART", "loc" : [ -96.838133, 31.545798 ], "pop" : 2588, "state" : "TX" }
+{ "_id" : "76665", "city" : "MERIDIAN", "loc" : [ -97.64433, 31.929022 ], "pop" : 2354, "state" : "TX" }
+{ "_id" : "76666", "city" : "MERTENS", "loc" : [ -96.898128, 32.02753 ], "pop" : 328, "state" : "TX" }
+{ "_id" : "76667", "city" : "MEXIA", "loc" : [ -96.495186, 31.678386 ], "pop" : 10971, "state" : "TX" }
+{ "_id" : "76670", "city" : "MILFORD", "loc" : [ -96.96115, 32.148198 ], "pop" : 1259, "state" : "TX" }
+{ "_id" : "76671", "city" : "MORGAN", "loc" : [ -97.560829, 32.01946 ], "pop" : 1403, "state" : "TX" }
+{ "_id" : "76673", "city" : "MOUNT CALM", "loc" : [ -96.89439299999999, 31.757504 ], "pop" : 612, "state" : "TX" }
+{ "_id" : "76675", "city" : "OTTO", "loc" : [ -96.87590400000001, 31.432733 ], "pop" : 776, "state" : "TX" }
+{ "_id" : "76676", "city" : "PENELOPE", "loc" : [ -96.937164, 31.855148 ], "pop" : 613, "state" : "TX" }
+{ "_id" : "76678", "city" : "PRAIRIE HILL", "loc" : [ -96.809381, 31.659097 ], "pop" : 657, "state" : "TX" }
+{ "_id" : "76679", "city" : "PURDON", "loc" : [ -96.58561899999999, 31.948285 ], "pop" : 752, "state" : "TX" }
+{ "_id" : "76680", "city" : "REAGAN", "loc" : [ -96.74194300000001, 31.229713 ], "pop" : 796, "state" : "TX" }
+{ "_id" : "76681", "city" : "RICHLAND", "loc" : [ -96.437262, 31.901785 ], "pop" : 512, "state" : "TX" }
+{ "_id" : "76682", "city" : "RIESEL", "loc" : [ -96.94764000000001, 31.500247 ], "pop" : 2488, "state" : "TX" }
+{ "_id" : "76687", "city" : "THORNTON", "loc" : [ -96.50237799999999, 31.408326 ], "pop" : 1438, "state" : "TX" }
+{ "_id" : "76689", "city" : "VALLEY MILLS", "loc" : [ -97.493461, 31.659876 ], "pop" : 1796, "state" : "TX" }
+{ "_id" : "76690", "city" : "WALNUT SPRINGS", "loc" : [ -97.751423, 32.059268 ], "pop" : 842, "state" : "TX" }
+{ "_id" : "76691", "city" : "WEST", "loc" : [ -97.125843, 31.775385 ], "pop" : 6222, "state" : "TX" }
+{ "_id" : "76692", "city" : "BONANZA", "loc" : [ -97.33495000000001, 31.959201 ], "pop" : 5302, "state" : "TX" }
+{ "_id" : "76693", "city" : "WORTHAM", "loc" : [ -96.420208, 31.786542 ], "pop" : 1602, "state" : "TX" }
+{ "_id" : "76701", "city" : "WACO", "loc" : [ -97.139608, 31.552452 ], "pop" : 1752, "state" : "TX" }
+{ "_id" : "76704", "city" : "BELLMEAD", "loc" : [ -97.12674199999999, 31.575701 ], "pop" : 8919, "state" : "TX" }
+{ "_id" : "76705", "city" : "BELLMEAD", "loc" : [ -97.09457500000001, 31.610787 ], "pop" : 18763, "state" : "TX" }
+{ "_id" : "76706", "city" : "WACO", "loc" : [ -97.11975200000001, 31.517086 ], "pop" : 31263, "state" : "TX" }
+{ "_id" : "76707", "city" : "WACO", "loc" : [ -97.158824, 31.552709 ], "pop" : 15905, "state" : "TX" }
+{ "_id" : "76708", "city" : "WACO", "loc" : [ -97.178635, 31.576544 ], "pop" : 18436, "state" : "TX" }
+{ "_id" : "76710", "city" : "WACO", "loc" : [ -97.189891, 31.534981 ], "pop" : 22014, "state" : "TX" }
+{ "_id" : "76711", "city" : "BEVERLY HILLS", "loc" : [ -97.150254, 31.519863 ], "pop" : 8736, "state" : "TX" }
+{ "_id" : "76712", "city" : "WOODWAY", "loc" : [ -97.23106199999999, 31.505074 ], "pop" : 14756, "state" : "TX" }
+{ "_id" : "76801", "city" : "EARLY", "loc" : [ -98.97516400000001, 31.704658 ], "pop" : 24634, "state" : "TX" }
+{ "_id" : "76820", "city" : "ART", "loc" : [ -99.093732, 30.775419 ], "pop" : 24, "state" : "TX" }
+{ "_id" : "76821", "city" : "BALLINGER", "loc" : [ -99.958927, 31.746836 ], "pop" : 4957, "state" : "TX" }
+{ "_id" : "76823", "city" : "BANGS", "loc" : [ -99.107657, 31.768388 ], "pop" : 5681, "state" : "TX" }
+{ "_id" : "76824", "city" : "BEND", "loc" : [ -98.482102, 31.11231 ], "pop" : 1, "state" : "TX" }
+{ "_id" : "76825", "city" : "FIFE", "loc" : [ -99.3372, 31.128304 ], "pop" : 7280, "state" : "TX" }
+{ "_id" : "76827", "city" : "BROOKESMITH", "loc" : [ -99.127729, 31.517602 ], "pop" : 240, "state" : "TX" }
+{ "_id" : "76828", "city" : "BURKETT", "loc" : [ -99.255258, 31.998623 ], "pop" : 237, "state" : "TX" }
+{ "_id" : "76831", "city" : "CASTELL", "loc" : [ -98.931859, 30.697429 ], "pop" : 64, "state" : "TX" }
+{ "_id" : "76832", "city" : "CHEROKEE", "loc" : [ -98.66332, 30.980598 ], "pop" : 127, "state" : "TX" }
+{ "_id" : "76834", "city" : "COLEMAN", "loc" : [ -99.427007, 31.828651 ], "pop" : 6300, "state" : "TX" }
+{ "_id" : "76836", "city" : "DOOLE", "loc" : [ -99.550605, 31.415743 ], "pop" : 86, "state" : "TX" }
+{ "_id" : "76837", "city" : "EDEN", "loc" : [ -99.840658, 31.219219 ], "pop" : 2028, "state" : "TX" }
+{ "_id" : "76841", "city" : "FORT MC KAVETT", "loc" : [ -100.080928, 30.82903 ], "pop" : 47, "state" : "TX" }
+{ "_id" : "76842", "city" : "FREDONIA", "loc" : [ -99.12156, 30.921386 ], "pop" : 72, "state" : "TX" }
+{ "_id" : "76844", "city" : "GOLDTHWAITE", "loc" : [ -98.574405, 31.445769 ], "pop" : 2523, "state" : "TX" }
+{ "_id" : "76845", "city" : "GOULDBUSK", "loc" : [ -99.51363000000001, 31.551075 ], "pop" : 159, "state" : "TX" }
+{ "_id" : "76848", "city" : "HEXT", "loc" : [ -99.554008, 30.881632 ], "pop" : 60, "state" : "TX" }
+{ "_id" : "76849", "city" : "JUNCTION", "loc" : [ -99.74731, 30.47544 ], "pop" : 3248, "state" : "TX" }
+{ "_id" : "76852", "city" : "LOHN", "loc" : [ -99.38334, 31.317297 ], "pop" : 233, "state" : "TX" }
+{ "_id" : "76853", "city" : "LOMETA", "loc" : [ -98.400553, 31.216712 ], "pop" : 1215, "state" : "TX" }
+{ "_id" : "76854", "city" : "LONDON", "loc" : [ -99.62552700000001, 30.617101 ], "pop" : 465, "state" : "TX" }
+{ "_id" : "76856", "city" : "MASON", "loc" : [ -99.226117, 30.743392 ], "pop" : 3182, "state" : "TX" }
+{ "_id" : "76857", "city" : "MAY", "loc" : [ -98.96564600000001, 31.957082 ], "pop" : 1454, "state" : "TX" }
+{ "_id" : "76858", "city" : "MELVIN", "loc" : [ -99.54389999999999, 31.185145 ], "pop" : 361, "state" : "TX" }
+{ "_id" : "76859", "city" : "MENARD", "loc" : [ -99.784721, 30.911898 ], "pop" : 2145, "state" : "TX" }
+{ "_id" : "76861", "city" : "MILES", "loc" : [ -100.182292, 31.612052 ], "pop" : 1102, "state" : "TX" }
+{ "_id" : "76862", "city" : "MILLERSVIEW", "loc" : [ -99.71713699999999, 31.416745 ], "pop" : 137, "state" : "TX" }
+{ "_id" : "76864", "city" : "MULLIN", "loc" : [ -98.66354200000001, 31.574829 ], "pop" : 1281, "state" : "TX" }
+{ "_id" : "76865", "city" : "NORTON", "loc" : [ -100.131515, 31.879498 ], "pop" : 244, "state" : "TX" }
+{ "_id" : "76866", "city" : "PAINT ROCK", "loc" : [ -99.91393600000001, 31.504808 ], "pop" : 400, "state" : "TX" }
+{ "_id" : "76867", "city" : "PEAR VALLEY", "loc" : [ -99.494742, 31.297211 ], "pop" : 110, "state" : "TX" }
+{ "_id" : "76869", "city" : "PONTOTOC", "loc" : [ -99.021224, 30.890617 ], "pop" : 113, "state" : "TX" }
+{ "_id" : "76870", "city" : "PRIDDY", "loc" : [ -98.501464, 31.687418 ], "pop" : 122, "state" : "TX" }
+{ "_id" : "76871", "city" : "RICHLAND SPRINGS", "loc" : [ -98.850731, 31.275317 ], "pop" : 1103, "state" : "TX" }
+{ "_id" : "76872", "city" : "ROCHELLE", "loc" : [ -99.157229, 31.300011 ], "pop" : 761, "state" : "TX" }
+{ "_id" : "76873", "city" : "ROCKWOOD", "loc" : [ -99.374579, 31.503677 ], "pop" : 63, "state" : "TX" }
+{ "_id" : "76874", "city" : "ROOSEVELT", "loc" : [ -99.916501, 30.532203 ], "pop" : 382, "state" : "TX" }
+{ "_id" : "76875", "city" : "ROWENA", "loc" : [ -100.019094, 31.64355 ], "pop" : 802, "state" : "TX" }
+{ "_id" : "76877", "city" : "SAN SABA", "loc" : [ -98.730929, 31.162678 ], "pop" : 4023, "state" : "TX" }
+{ "_id" : "76878", "city" : "SANTA ANNA", "loc" : [ -99.321197, 31.721477 ], "pop" : 1835, "state" : "TX" }
+{ "_id" : "76880", "city" : "STAR", "loc" : [ -98.415752, 31.479039 ], "pop" : 605, "state" : "TX" }
+{ "_id" : "76882", "city" : "TALPA", "loc" : [ -99.674679, 31.803424 ], "pop" : 240, "state" : "TX" }
+{ "_id" : "76883", "city" : "TELEGRAPH", "loc" : [ -99.928369, 30.367365 ], "pop" : 27, "state" : "TX" }
+{ "_id" : "76884", "city" : "VALERA", "loc" : [ -99.563962, 31.77314 ], "pop" : 201, "state" : "TX" }
+{ "_id" : "76885", "city" : "VALLEY SPRING", "loc" : [ -98.83254100000001, 30.836862 ], "pop" : 270, "state" : "TX" }
+{ "_id" : "76887", "city" : "VOCA", "loc" : [ -99.16820300000001, 30.995874 ], "pop" : 94, "state" : "TX" }
+{ "_id" : "76888", "city" : "LEADAY", "loc" : [ -99.53853599999999, 31.639194 ], "pop" : 227, "state" : "TX" }
+{ "_id" : "76890", "city" : "ZEPHYR", "loc" : [ -98.81819900000001, 31.669429 ], "pop" : 433, "state" : "TX" }
+{ "_id" : "76901", "city" : "SAN ANGELO", "loc" : [ -100.481752, 31.478165 ], "pop" : 23800, "state" : "TX" }
+{ "_id" : "76903", "city" : "SAN ANGELO", "loc" : [ -100.438586, 31.470735 ], "pop" : 32471, "state" : "TX" }
+{ "_id" : "76904", "city" : "SAN ANGELO", "loc" : [ -100.480036, 31.419411 ], "pop" : 25535, "state" : "TX" }
+{ "_id" : "76905", "city" : "SAN ANGELO", "loc" : [ -100.390005, 31.464738 ], "pop" : 11284, "state" : "TX" }
+{ "_id" : "76930", "city" : "BARNHART", "loc" : [ -101.191752, 31.159647 ], "pop" : 178, "state" : "TX" }
+{ "_id" : "76932", "city" : "BEST", "loc" : [ -101.478776, 31.240592 ], "pop" : 4514, "state" : "TX" }
+{ "_id" : "76933", "city" : "BRONTE", "loc" : [ -100.298765, 31.878939 ], "pop" : 1291, "state" : "TX" }
+{ "_id" : "76934", "city" : "CARLSBAD", "loc" : [ -100.627501, 31.597995 ], "pop" : 1886, "state" : "TX" }
+{ "_id" : "76935", "city" : "CHRISTOVAL", "loc" : [ -100.52031, 31.23461 ], "pop" : 1639, "state" : "TX" }
+{ "_id" : "76936", "city" : "ELDORADO", "loc" : [ -100.58894, 30.86667 ], "pop" : 2990, "state" : "TX" }
+{ "_id" : "76937", "city" : "EOLA", "loc" : [ -100.072892, 31.429812 ], "pop" : 479, "state" : "TX" }
+{ "_id" : "76940", "city" : "MERETA", "loc" : [ -100.183391, 31.48632 ], "pop" : 768, "state" : "TX" }
+{ "_id" : "76941", "city" : "MERTZON", "loc" : [ -100.822101, 31.282884 ], "pop" : 1451, "state" : "TX" }
+{ "_id" : "76943", "city" : "OZONA", "loc" : [ -101.238802, 30.716369 ], "pop" : 4076, "state" : "TX" }
+{ "_id" : "76945", "city" : "ROBERT LEE", "loc" : [ -100.510366, 31.895091 ], "pop" : 1826, "state" : "TX" }
+{ "_id" : "76949", "city" : "SILVER", "loc" : [ -100.692229, 32.048371 ], "pop" : 45, "state" : "TX" }
+{ "_id" : "76950", "city" : "SONORA", "loc" : [ -100.630667, 30.555752 ], "pop" : 4135, "state" : "TX" }
+{ "_id" : "76951", "city" : "STERLING CITY", "loc" : [ -101.001729, 31.835063 ], "pop" : 1438, "state" : "TX" }
+{ "_id" : "76955", "city" : "VANCOURT", "loc" : [ -100.180367, 31.340417 ], "pop" : 256, "state" : "TX" }
+{ "_id" : "76957", "city" : "WALL", "loc" : [ -100.322132, 31.369445 ], "pop" : 819, "state" : "TX" }
+{ "_id" : "77002", "city" : "HOUSTON", "loc" : [ -95.35936100000001, 29.759366 ], "pop" : 7658, "state" : "TX" }
+{ "_id" : "77003", "city" : "HOUSTON", "loc" : [ -95.339108, 29.748903 ], "pop" : 8500, "state" : "TX" }
+{ "_id" : "77004", "city" : "HOUSTON", "loc" : [ -95.36254599999999, 29.724687 ], "pop" : 29940, "state" : "TX" }
+{ "_id" : "77005", "city" : "HOUSTON", "loc" : [ -95.426261, 29.717856 ], "pop" : 21772, "state" : "TX" }
+{ "_id" : "77006", "city" : "HOUSTON", "loc" : [ -95.39225500000001, 29.740899 ], "pop" : 17653, "state" : "TX" }
+{ "_id" : "77007", "city" : "HOUSTON", "loc" : [ -95.40342099999999, 29.773603 ], "pop" : 22511, "state" : "TX" }
+{ "_id" : "77008", "city" : "HOUSTON", "loc" : [ -95.41179700000001, 29.799096 ], "pop" : 29653, "state" : "TX" }
+{ "_id" : "77009", "city" : "HOUSTON", "loc" : [ -95.367481, 29.793558 ], "pop" : 42521, "state" : "TX" }
+{ "_id" : "77010", "city" : "HOUSTON", "loc" : [ -95.356549, 29.75125 ], "pop" : 0, "state" : "TX" }
+{ "_id" : "77011", "city" : "HOUSTON", "loc" : [ -95.30726199999999, 29.741992 ], "pop" : 22311, "state" : "TX" }
+{ "_id" : "77012", "city" : "HOUSTON", "loc" : [ -95.281925, 29.71491 ], "pop" : 23344, "state" : "TX" }
+{ "_id" : "77013", "city" : "HOUSTON", "loc" : [ -95.23013400000001, 29.784169 ], "pop" : 17011, "state" : "TX" }
+{ "_id" : "77014", "city" : "HOUSTON", "loc" : [ -95.462497, 29.979637 ], "pop" : 11970, "state" : "TX" }
+{ "_id" : "77015", "city" : "HOUSTON", "loc" : [ -95.18518899999999, 29.785287 ], "pop" : 42008, "state" : "TX" }
+{ "_id" : "77016", "city" : "HOUSTON", "loc" : [ -95.30319900000001, 29.857855 ], "pop" : 31180, "state" : "TX" }
+{ "_id" : "77017", "city" : "HOUSTON", "loc" : [ -95.25548499999999, 29.686301 ], "pop" : 26502, "state" : "TX" }
+{ "_id" : "77018", "city" : "HOUSTON", "loc" : [ -95.426631, 29.827166 ], "pop" : 25857, "state" : "TX" }
+{ "_id" : "77019", "city" : "HOUSTON", "loc" : [ -95.40539, 29.751651 ], "pop" : 15280, "state" : "TX" }
+{ "_id" : "77020", "city" : "HOUSTON", "loc" : [ -95.312101, 29.775759 ], "pop" : 28011, "state" : "TX" }
+{ "_id" : "77021", "city" : "HOUSTON", "loc" : [ -95.356151, 29.69538 ], "pop" : 23815, "state" : "TX" }
+{ "_id" : "77022", "city" : "HOUSTON", "loc" : [ -95.376862, 29.829862 ], "pop" : 27417, "state" : "TX" }
+{ "_id" : "77023", "city" : "HOUSTON", "loc" : [ -95.31777700000001, 29.724179 ], "pop" : 31983, "state" : "TX" }
+{ "_id" : "77024", "city" : "HOUSTON", "loc" : [ -95.52006299999999, 29.76958 ], "pop" : 30766, "state" : "TX" }
+{ "_id" : "77025", "city" : "HOUSTON", "loc" : [ -95.434107, 29.688897 ], "pop" : 21618, "state" : "TX" }
+{ "_id" : "77026", "city" : "HOUSTON", "loc" : [ -95.32877499999999, 29.797168 ], "pop" : 27744, "state" : "TX" }
+{ "_id" : "77027", "city" : "HOUSTON", "loc" : [ -95.446032, 29.739571 ], "pop" : 11422, "state" : "TX" }
+{ "_id" : "77028", "city" : "HOUSTON", "loc" : [ -95.287886, 29.829657 ], "pop" : 17943, "state" : "TX" }
+{ "_id" : "77029", "city" : "JACINTO CITY", "loc" : [ -95.25486100000001, 29.760326 ], "pop" : 17739, "state" : "TX" }
+{ "_id" : "77030", "city" : "V A HOSPITAL", "loc" : [ -95.40619, 29.70372 ], "pop" : 10462, "state" : "TX" }
+{ "_id" : "77031", "city" : "HOUSTON", "loc" : [ -95.541281, 29.658144 ], "pop" : 14021, "state" : "TX" }
+{ "_id" : "77032", "city" : "HOUSTON", "loc" : [ -95.329883, 29.93676 ], "pop" : 8373, "state" : "TX" }
+{ "_id" : "77033", "city" : "HOUSTON", "loc" : [ -95.338157, 29.668566 ], "pop" : 28295, "state" : "TX" }
+{ "_id" : "77034", "city" : "HOUSTON", "loc" : [ -95.221615, 29.636395 ], "pop" : 21593, "state" : "TX" }
+{ "_id" : "77035", "city" : "HOUSTON", "loc" : [ -95.48536799999999, 29.651833 ], "pop" : 30746, "state" : "TX" }
+{ "_id" : "77036", "city" : "HOUSTON", "loc" : [ -95.540464, 29.698447 ], "pop" : 55414, "state" : "TX" }
+{ "_id" : "77037", "city" : "HOUSTON", "loc" : [ -95.39351499999999, 29.889161 ], "pop" : 14286, "state" : "TX" }
+{ "_id" : "77038", "city" : "HOUSTON", "loc" : [ -95.43860100000001, 29.91956 ], "pop" : 15653, "state" : "TX" }
+{ "_id" : "77039", "city" : "HOUSTON", "loc" : [ -95.33338000000001, 29.906731 ], "pop" : 23839, "state" : "TX" }
+{ "_id" : "77040", "city" : "JERSEY VILLAGE", "loc" : [ -95.52996899999999, 29.879613 ], "pop" : 33052, "state" : "TX" }
+{ "_id" : "77041", "city" : "HOUSTON", "loc" : [ -95.58166300000001, 29.860187 ], "pop" : 14790, "state" : "TX" }
+{ "_id" : "77042", "city" : "HOUSTON", "loc" : [ -95.55889500000001, 29.740446 ], "pop" : 31505, "state" : "TX" }
+{ "_id" : "77043", "city" : "HOUSTON", "loc" : [ -95.560734, 29.805181 ], "pop" : 21752, "state" : "TX" }
+{ "_id" : "77044", "city" : "HOUSTON", "loc" : [ -95.19757, 29.863485 ], "pop" : 10669, "state" : "TX" }
+{ "_id" : "77045", "city" : "HOUSTON", "loc" : [ -95.438166, 29.629717 ], "pop" : 22145, "state" : "TX" }
+{ "_id" : "77046", "city" : "HOUSTON", "loc" : [ -95.431845, 29.73279 ], "pop" : 557, "state" : "TX" }
+{ "_id" : "77047", "city" : "HOUSTON", "loc" : [ -95.374993, 29.625443 ], "pop" : 9588, "state" : "TX" }
+{ "_id" : "77048", "city" : "HOUSTON", "loc" : [ -95.341606, 29.632097 ], "pop" : 13873, "state" : "TX" }
+{ "_id" : "77049", "city" : "HOUSTON", "loc" : [ -95.184815, 29.823471 ], "pop" : 14445, "state" : "TX" }
+{ "_id" : "77050", "city" : "HOUSTON", "loc" : [ -95.284837, 29.901456 ], "pop" : 3709, "state" : "TX" }
+{ "_id" : "77051", "city" : "HOUSTON", "loc" : [ -95.368763, 29.65792 ], "pop" : 13776, "state" : "TX" }
+{ "_id" : "77053", "city" : "HOUSTON", "loc" : [ -95.458709, 29.596156 ], "pop" : 20720, "state" : "TX" }
+{ "_id" : "77054", "city" : "HOUSTON", "loc" : [ -95.40167700000001, 29.685209 ], "pop" : 12399, "state" : "TX" }
+{ "_id" : "77055", "city" : "HOUSTON", "loc" : [ -95.49578700000001, 29.797064 ], "pop" : 36187, "state" : "TX" }
+{ "_id" : "77056", "city" : "HOUSTON", "loc" : [ -95.468282, 29.744584 ], "pop" : 13544, "state" : "TX" }
+{ "_id" : "77057", "city" : "HOUSTON", "loc" : [ -95.490253, 29.74217 ], "pop" : 28217, "state" : "TX" }
+{ "_id" : "77058", "city" : "HOUSTON", "loc" : [ -95.057413, 29.574787 ], "pop" : 5556, "state" : "TX" }
+{ "_id" : "77059", "city" : "HOUSTON", "loc" : [ -95.113354, 29.597493 ], "pop" : 6185, "state" : "TX" }
+{ "_id" : "77060", "city" : "HOUSTON", "loc" : [ -95.398061, 29.933462 ], "pop" : 31443, "state" : "TX" }
+{ "_id" : "77061", "city" : "HOUSTON", "loc" : [ -95.278987, 29.665221 ], "pop" : 20966, "state" : "TX" }
+{ "_id" : "77062", "city" : "HOUSTON", "loc" : [ -95.130292, 29.572084 ], "pop" : 25303, "state" : "TX" }
+{ "_id" : "77063", "city" : "HOUSTON", "loc" : [ -95.52203900000001, 29.734843 ], "pop" : 24156, "state" : "TX" }
+{ "_id" : "77064", "city" : "HOUSTON", "loc" : [ -95.556894, 29.918981 ], "pop" : 21388, "state" : "TX" }
+{ "_id" : "77065", "city" : "HOUSTON", "loc" : [ -95.61063, 29.931933 ], "pop" : 17370, "state" : "TX" }
+{ "_id" : "77066", "city" : "HOUSTON", "loc" : [ -95.49471699999999, 29.961027 ], "pop" : 23310, "state" : "TX" }
+{ "_id" : "77067", "city" : "HOUSTON", "loc" : [ -95.452158, 29.954717 ], "pop" : 18416, "state" : "TX" }
+{ "_id" : "77068", "city" : "HOUSTON", "loc" : [ -95.489661, 30.006867 ], "pop" : 7670, "state" : "TX" }
+{ "_id" : "77069", "city" : "HOUSTON", "loc" : [ -95.520827, 29.986292 ], "pop" : 11617, "state" : "TX" }
+{ "_id" : "77070", "city" : "HOUSTON", "loc" : [ -95.58027, 29.978099 ], "pop" : 25735, "state" : "TX" }
+{ "_id" : "77071", "city" : "HOUSTON", "loc" : [ -95.517554, 29.651838 ], "pop" : 21037, "state" : "TX" }
+{ "_id" : "77072", "city" : "HOUSTON", "loc" : [ -95.58615500000001, 29.699026 ], "pop" : 41808, "state" : "TX" }
+{ "_id" : "77073", "city" : "HOUSTON", "loc" : [ -95.408671, 30.019767 ], "pop" : 10208, "state" : "TX" }
+{ "_id" : "77074", "city" : "HOUSTON", "loc" : [ -95.510588, 29.689601 ], "pop" : 32691, "state" : "TX" }
+{ "_id" : "77075", "city" : "HOUSTON", "loc" : [ -95.25998300000001, 29.622276 ], "pop" : 16943, "state" : "TX" }
+{ "_id" : "77076", "city" : "HOUSTON", "loc" : [ -95.383442, 29.85801 ], "pop" : 23881, "state" : "TX" }
+{ "_id" : "77077", "city" : "HOUSTON", "loc" : [ -95.602991, 29.747656 ], "pop" : 32090, "state" : "TX" }
+{ "_id" : "77078", "city" : "HOUSTON", "loc" : [ -95.258208, 29.849724 ], "pop" : 12300, "state" : "TX" }
+{ "_id" : "77079", "city" : "HOUSTON", "loc" : [ -95.597993, 29.773759 ], "pop" : 29891, "state" : "TX" }
+{ "_id" : "77080", "city" : "HOUSTON", "loc" : [ -95.522986, 29.815854 ], "pop" : 39465, "state" : "TX" }
+{ "_id" : "77081", "city" : "HOUSTON", "loc" : [ -95.484531, 29.711926 ], "pop" : 33787, "state" : "TX" }
+{ "_id" : "77082", "city" : "HOUSTON", "loc" : [ -95.628533, 29.722283 ], "pop" : 23875, "state" : "TX" }
+{ "_id" : "77083", "city" : "HOUSTON", "loc" : [ -95.651098, 29.694709 ], "pop" : 38124, "state" : "TX" }
+{ "_id" : "77084", "city" : "HOUSTON", "loc" : [ -95.662329, 29.844022 ], "pop" : 45204, "state" : "TX" }
+{ "_id" : "77085", "city" : "HOUSTON", "loc" : [ -95.481945, 29.621787 ], "pop" : 6519, "state" : "TX" }
+{ "_id" : "77086", "city" : "HOUSTON", "loc" : [ -95.49386800000001, 29.922667 ], "pop" : 16075, "state" : "TX" }
+{ "_id" : "77087", "city" : "HOUSTON", "loc" : [ -95.301062, 29.687579 ], "pop" : 31112, "state" : "TX" }
+{ "_id" : "77088", "city" : "HOUSTON", "loc" : [ -95.45387700000001, 29.881694 ], "pop" : 44595, "state" : "TX" }
+{ "_id" : "77089", "city" : "HOUSTON", "loc" : [ -95.22178599999999, 29.593978 ], "pop" : 37678, "state" : "TX" }
+{ "_id" : "77090", "city" : "HOUSTON", "loc" : [ -95.447002, 30.016673 ], "pop" : 22054, "state" : "TX" }
+{ "_id" : "77091", "city" : "HOUSTON", "loc" : [ -95.443521, 29.853448 ], "pop" : 21341, "state" : "TX" }
+{ "_id" : "77092", "city" : "HOUSTON", "loc" : [ -95.472031, 29.832391 ], "pop" : 31872, "state" : "TX" }
+{ "_id" : "77093", "city" : "HOUSTON", "loc" : [ -95.34028600000001, 29.861661 ], "pop" : 39118, "state" : "TX" }
+{ "_id" : "77094", "city" : "HOUSTON", "loc" : [ -95.710742, 29.770536 ], "pop" : 1168, "state" : "TX" }
+{ "_id" : "77095", "city" : "HOUSTON", "loc" : [ -95.648082, 29.894115 ], "pop" : 24418, "state" : "TX" }
+{ "_id" : "77096", "city" : "HOUSTON", "loc" : [ -95.48606599999999, 29.672205 ], "pop" : 32124, "state" : "TX" }
+{ "_id" : "77098", "city" : "HOUSTON", "loc" : [ -95.411778, 29.734987 ], "pop" : 10436, "state" : "TX" }
+{ "_id" : "77099", "city" : "HOUSTON", "loc" : [ -95.586613, 29.670869 ], "pop" : 40503, "state" : "TX" }
+{ "_id" : "77301", "city" : "CONROE", "loc" : [ -95.45266700000001, 30.312535 ], "pop" : 20150, "state" : "TX" }
+{ "_id" : "77302", "city" : "GRANGERLAND", "loc" : [ -95.416087, 30.250357 ], "pop" : 5767, "state" : "TX" }
+{ "_id" : "77303", "city" : "CUT AND SHOOT", "loc" : [ -95.369725, 30.344456 ], "pop" : 14683, "state" : "TX" }
+{ "_id" : "77304", "city" : "PANORAMA VILLAGE", "loc" : [ -95.495244, 30.327351 ], "pop" : 9625, "state" : "TX" }
+{ "_id" : "77327", "city" : "CLEVELAND", "loc" : [ -95.020152, 30.329977 ], "pop" : 21298, "state" : "TX" }
+{ "_id" : "77331", "city" : "COLDSPRING", "loc" : [ -95.10858, 30.602661 ], "pop" : 3182, "state" : "TX" }
+{ "_id" : "77335", "city" : "GOODRICH", "loc" : [ -94.95922, 30.607909 ], "pop" : 1441, "state" : "TX" }
+{ "_id" : "77336", "city" : "HUFFMAN", "loc" : [ -95.105069, 30.056491 ], "pop" : 6529, "state" : "TX" }
+{ "_id" : "77338", "city" : "HUMBLE", "loc" : [ -95.282476, 30.004091 ], "pop" : 19090, "state" : "TX" }
+{ "_id" : "77339", "city" : "HUMBLE", "loc" : [ -95.21071600000001, 30.056333 ], "pop" : 28083, "state" : "TX" }
+{ "_id" : "77340", "city" : "HUNTSVILLE", "loc" : [ -95.53418600000001, 30.73435 ], "pop" : 48879, "state" : "TX" }
+{ "_id" : "77345", "city" : "HUMBLE", "loc" : [ -95.170654, 30.056641 ], "pop" : 13004, "state" : "TX" }
+{ "_id" : "77346", "city" : "HUMBLE", "loc" : [ -95.172815, 30.004195 ], "pop" : 15984, "state" : "TX" }
+{ "_id" : "77351", "city" : "SEGNO", "loc" : [ -94.935278, 30.718018 ], "pop" : 24261, "state" : "TX" }
+{ "_id" : "77355", "city" : "MAGNOLIA", "loc" : [ -95.68898900000001, 30.1678 ], "pop" : 15638, "state" : "TX" }
+{ "_id" : "77356", "city" : "MONTGOMERY", "loc" : [ -95.65034199999999, 30.363932 ], "pop" : 12002, "state" : "TX" }
+{ "_id" : "77357", "city" : "NEW CANEY", "loc" : [ -95.197968, 30.157933 ], "pop" : 13214, "state" : "TX" }
+{ "_id" : "77358", "city" : "NEW WAVERLY", "loc" : [ -95.453194, 30.535357 ], "pop" : 1977, "state" : "TX" }
+{ "_id" : "77359", "city" : "OAKHURST", "loc" : [ -95.309478, 30.71262 ], "pop" : 283, "state" : "TX" }
+{ "_id" : "77362", "city" : "PINEHURST", "loc" : [ -95.681406, 30.158052 ], "pop" : 2498, "state" : "TX" }
+{ "_id" : "77363", "city" : "PLANTERSVILLE", "loc" : [ -95.849812, 30.296931 ], "pop" : 1333, "state" : "TX" }
+{ "_id" : "77364", "city" : "POINTBLANK", "loc" : [ -95.229494, 30.75926 ], "pop" : 2911, "state" : "TX" }
+{ "_id" : "77365", "city" : "PORTER", "loc" : [ -95.268613, 30.123731 ], "pop" : 13541, "state" : "TX" }
+{ "_id" : "77371", "city" : "SHEPHERD", "loc" : [ -95.092913, 30.483396 ], "pop" : 9604, "state" : "TX" }
+{ "_id" : "77372", "city" : "SPLENDORA", "loc" : [ -95.199308, 30.232609 ], "pop" : 11287, "state" : "TX" }
+{ "_id" : "77373", "city" : "SPRING", "loc" : [ -95.377329, 30.053241 ], "pop" : 33118, "state" : "TX" }
+{ "_id" : "77375", "city" : "TOMBALL", "loc" : [ -95.62006, 30.073923 ], "pop" : 19801, "state" : "TX" }
+{ "_id" : "77378", "city" : "WILLIS", "loc" : [ -95.49758300000001, 30.432025 ], "pop" : 9988, "state" : "TX" }
+{ "_id" : "77379", "city" : "KLEIN", "loc" : [ -95.528481, 30.023377 ], "pop" : 35275, "state" : "TX" }
+{ "_id" : "77380", "city" : "THE WOODLANDS", "loc" : [ -95.46894399999999, 30.13739 ], "pop" : 16541, "state" : "TX" }
+{ "_id" : "77381", "city" : "THE WOODLANDS", "loc" : [ -95.500743, 30.168887 ], "pop" : 19466, "state" : "TX" }
+{ "_id" : "77384", "city" : "CONROE", "loc" : [ -95.492392, 30.225725 ], "pop" : 1635, "state" : "TX" }
+{ "_id" : "77385", "city" : "CONROE", "loc" : [ -95.42878899999999, 30.187695 ], "pop" : 7311, "state" : "TX" }
+{ "_id" : "77386", "city" : "SPRING", "loc" : [ -95.42394299999999, 30.128805 ], "pop" : 8379, "state" : "TX" }
+{ "_id" : "77388", "city" : "SPRING", "loc" : [ -95.46945599999999, 30.050546 ], "pop" : 21805, "state" : "TX" }
+{ "_id" : "77389", "city" : "SPRING", "loc" : [ -95.506624, 30.104398 ], "pop" : 8540, "state" : "TX" }
+{ "_id" : "77396", "city" : "HUMBLE", "loc" : [ -95.262186, 29.950697 ], "pop" : 16163, "state" : "TX" }
+{ "_id" : "77401", "city" : "BELLAIRE", "loc" : [ -95.461106, 29.702313 ], "pop" : 13913, "state" : "TX" }
+{ "_id" : "77414", "city" : "SARGENT", "loc" : [ -95.92816999999999, 28.96183 ], "pop" : 19305, "state" : "TX" }
+{ "_id" : "77417", "city" : "BEASLEY", "loc" : [ -95.96814500000001, 29.479045 ], "pop" : 2151, "state" : "TX" }
+{ "_id" : "77418", "city" : "BELLVILLE", "loc" : [ -96.253083, 29.96583 ], "pop" : 6771, "state" : "TX" }
+{ "_id" : "77419", "city" : "BLESSING", "loc" : [ -96.217956, 28.864947 ], "pop" : 1285, "state" : "TX" }
+{ "_id" : "77420", "city" : "BOLING", "loc" : [ -95.974045, 29.252874 ], "pop" : 3459, "state" : "TX" }
+{ "_id" : "77422", "city" : "BRAZORIA", "loc" : [ -95.58668299999999, 29.023642 ], "pop" : 12583, "state" : "TX" }
+{ "_id" : "77423", "city" : "BROOKSHIRE", "loc" : [ -95.975537, 29.807168 ], "pop" : 4990, "state" : "TX" }
+{ "_id" : "77426", "city" : "CHAPPELL HILL", "loc" : [ -96.234739, 30.183271 ], "pop" : 2916, "state" : "TX" }
+{ "_id" : "77429", "city" : "CYPRESS", "loc" : [ -95.635778, 29.976608 ], "pop" : 18527, "state" : "TX" }
+{ "_id" : "77430", "city" : "DAMON", "loc" : [ -95.703577, 29.301381 ], "pop" : 1493, "state" : "TX" }
+{ "_id" : "77432", "city" : "DANEVANG", "loc" : [ -96.19765, 29.066969 ], "pop" : 278, "state" : "TX" }
+{ "_id" : "77433", "city" : "CYPRESS", "loc" : [ -95.702456, 29.883633 ], "pop" : 1983, "state" : "TX" }
+{ "_id" : "77434", "city" : "EAGLE LAKE", "loc" : [ -96.33536700000001, 29.584236 ], "pop" : 4543, "state" : "TX" }
+{ "_id" : "77435", "city" : "EAST BERNARD", "loc" : [ -96.121115, 29.470458 ], "pop" : 5773, "state" : "TX" }
+{ "_id" : "77437", "city" : "EL CAMPO", "loc" : [ -96.274266, 29.200776 ], "pop" : 15829, "state" : "TX" }
+{ "_id" : "77440", "city" : "ELMATON", "loc" : [ -96.13351, 28.83209 ], "pop" : 470, "state" : "TX" }
+{ "_id" : "77441", "city" : "FULSHEAR", "loc" : [ -95.897682, 29.721698 ], "pop" : 193, "state" : "TX" }
+{ "_id" : "77442", "city" : "GARWOOD", "loc" : [ -96.49192499999999, 29.476001 ], "pop" : 2231, "state" : "TX" }
+{ "_id" : "77444", "city" : "GUY", "loc" : [ -95.77022700000001, 29.332676 ], "pop" : 343, "state" : "TX" }
+{ "_id" : "77445", "city" : "HEMPSTEAD", "loc" : [ -96.071648, 30.091973 ], "pop" : 5883, "state" : "TX" }
+{ "_id" : "77447", "city" : "HOCKLEY", "loc" : [ -95.810447, 30.072888 ], "pop" : 5040, "state" : "TX" }
+{ "_id" : "77449", "city" : "PARK ROW", "loc" : [ -95.72926699999999, 29.819922 ], "pop" : 22664, "state" : "TX" }
+{ "_id" : "77450", "city" : "PARK ROW", "loc" : [ -95.744506, 29.767632 ], "pop" : 28533, "state" : "TX" }
+{ "_id" : "77455", "city" : "LOUISE", "loc" : [ -96.392374, 29.14908 ], "pop" : 2431, "state" : "TX" }
+{ "_id" : "77456", "city" : "MARKHAM", "loc" : [ -96.09276800000001, 28.954701 ], "pop" : 2015, "state" : "TX" }
+{ "_id" : "77457", "city" : "MATAGORDA", "loc" : [ -95.951891, 28.764926 ], "pop" : 1455, "state" : "TX" }
+{ "_id" : "77458", "city" : "MIDFIELD", "loc" : [ -96.226527, 28.936166 ], "pop" : 286, "state" : "TX" }
+{ "_id" : "77459", "city" : "MISSOURI CITY", "loc" : [ -95.542284, 29.570434 ], "pop" : 16067, "state" : "TX" }
+{ "_id" : "77461", "city" : "NEEDVILLE", "loc" : [ -95.827288, 29.41165 ], "pop" : 7609, "state" : "TX" }
+{ "_id" : "77465", "city" : "PALACIOS", "loc" : [ -96.215439, 28.71504 ], "pop" : 5607, "state" : "TX" }
+{ "_id" : "77468", "city" : "PLEDGER", "loc" : [ -95.898591, 29.179208 ], "pop" : 345, "state" : "TX" }
+{ "_id" : "77469", "city" : "CLODINE", "loc" : [ -95.752122, 29.593226 ], "pop" : 36014, "state" : "TX" }
+{ "_id" : "77471", "city" : "ROSENBERG", "loc" : [ -95.798213, 29.549727 ], "pop" : 22182, "state" : "TX" }
+{ "_id" : "77474", "city" : "SEALY", "loc" : [ -96.159189, 29.782632 ], "pop" : 8680, "state" : "TX" }
+{ "_id" : "77477", "city" : "STAFFORD", "loc" : [ -95.567764, 29.622816 ], "pop" : 18952, "state" : "TX" }
+{ "_id" : "77478", "city" : "SUGAR LAND", "loc" : [ -95.62185599999999, 29.634153 ], "pop" : 36536, "state" : "TX" }
+{ "_id" : "77479", "city" : "SUGAR LAND", "loc" : [ -95.60659099999999, 29.578537 ], "pop" : 20219, "state" : "TX" }
+{ "_id" : "77480", "city" : "SWEENY", "loc" : [ -95.700363, 29.041508 ], "pop" : 5077, "state" : "TX" }
+{ "_id" : "77482", "city" : "VAN VLECK", "loc" : [ -95.938903, 29.013879 ], "pop" : 6011, "state" : "TX" }
+{ "_id" : "77483", "city" : "WADSWORTH", "loc" : [ -95.971307, 28.614288 ], "pop" : 145, "state" : "TX" }
+{ "_id" : "77484", "city" : "WALLER", "loc" : [ -95.961275, 30.086008 ], "pop" : 10513, "state" : "TX" }
+{ "_id" : "77485", "city" : "WALLIS", "loc" : [ -96.045574, 29.63968 ], "pop" : 3380, "state" : "TX" }
+{ "_id" : "77486", "city" : "WEST COLUMBIA", "loc" : [ -95.669388, 29.140823 ], "pop" : 9777, "state" : "TX" }
+{ "_id" : "77488", "city" : "WHARTON", "loc" : [ -96.08582800000001, 29.320488 ], "pop" : 12326, "state" : "TX" }
+{ "_id" : "77489", "city" : "MISSOURI CITY", "loc" : [ -95.511512, 29.596206 ], "pop" : 27760, "state" : "TX" }
+{ "_id" : "77493", "city" : "PARK ROW", "loc" : [ -95.815988, 29.804876 ], "pop" : 10312, "state" : "TX" }
+{ "_id" : "77494", "city" : "PARK ROW", "loc" : [ -95.81167499999999, 29.750893 ], "pop" : 2684, "state" : "TX" }
+{ "_id" : "77502", "city" : "PASADENA", "loc" : [ -95.198193, 29.678945 ], "pop" : 31270, "state" : "TX" }
+{ "_id" : "77503", "city" : "PASADENA", "loc" : [ -95.15721000000001, 29.687696 ], "pop" : 23019, "state" : "TX" }
+{ "_id" : "77504", "city" : "PASADENA", "loc" : [ -95.188478, 29.650133 ], "pop" : 18518, "state" : "TX" }
+{ "_id" : "77505", "city" : "PASADENA", "loc" : [ -95.146388, 29.651753 ], "pop" : 10978, "state" : "TX" }
+{ "_id" : "77506", "city" : "PASADENA", "loc" : [ -95.19895, 29.70087 ], "pop" : 33656, "state" : "TX" }
+{ "_id" : "77507", "city" : "PASADENA", "loc" : [ -95.079365, 29.6055 ], "pop" : 0, "state" : "TX" }
+{ "_id" : "77510", "city" : "ALTA LOMA", "loc" : [ -95.089429, 29.371854 ], "pop" : 11098, "state" : "TX" }
+{ "_id" : "77511", "city" : "ALVIN", "loc" : [ -95.251535, 29.41195 ], "pop" : 30979, "state" : "TX" }
+{ "_id" : "77514", "city" : "MONROE CITY", "loc" : [ -94.55481899999999, 29.780987 ], "pop" : 7969, "state" : "TX" }
+{ "_id" : "77515", "city" : "ANGLETON", "loc" : [ -95.44666100000001, 29.181049 ], "pop" : 29204, "state" : "TX" }
+{ "_id" : "77517", "city" : "ARCADIA", "loc" : [ -95.129003, 29.380259 ], "pop" : 3377, "state" : "TX" }
+{ "_id" : "77518", "city" : "BACLIFF", "loc" : [ -94.989293, 29.505506 ], "pop" : 5465, "state" : "TX" }
+{ "_id" : "77519", "city" : "BATSON", "loc" : [ -94.60959, 30.22502 ], "pop" : 1071, "state" : "TX" }
+{ "_id" : "77520", "city" : "BAYTOWN", "loc" : [ -94.965265, 29.746063 ], "pop" : 43386, "state" : "TX" }
+{ "_id" : "77521", "city" : "BAYTOWN", "loc" : [ -94.969549, 29.770482 ], "pop" : 30277, "state" : "TX" }
+{ "_id" : "77530", "city" : "CHANNELVIEW", "loc" : [ -95.13165499999999, 29.791438 ], "pop" : 23408, "state" : "TX" }
+{ "_id" : "77531", "city" : "CLUTE", "loc" : [ -95.40259500000001, 29.032502 ], "pop" : 13361, "state" : "TX" }
+{ "_id" : "77532", "city" : "BARRETT", "loc" : [ -95.07522, 29.937812 ], "pop" : 13679, "state" : "TX" }
+{ "_id" : "77534", "city" : "DANBURY", "loc" : [ -95.34346499999999, 29.229082 ], "pop" : 2522, "state" : "TX" }
+{ "_id" : "77535", "city" : "DAYTON", "loc" : [ -94.878747, 30.010208 ], "pop" : 16229, "state" : "TX" }
+{ "_id" : "77536", "city" : "DEER PARK", "loc" : [ -95.122192, 29.682571 ], "pop" : 25806, "state" : "TX" }
+{ "_id" : "77538", "city" : "DEVERS", "loc" : [ -94.57461499999999, 29.997835 ], "pop" : 570, "state" : "TX" }
+{ "_id" : "77539", "city" : "SAN LEON", "loc" : [ -95.034496, 29.466033 ], "pop" : 21905, "state" : "TX" }
+{ "_id" : "77541", "city" : "QUINTANA", "loc" : [ -95.37138899999999, 28.96968 ], "pop" : 17049, "state" : "TX" }
+{ "_id" : "77545", "city" : "FRESNO", "loc" : [ -95.462608, 29.52931 ], "pop" : 3144, "state" : "TX" }
+{ "_id" : "77546", "city" : "FRIENDSWOOD", "loc" : [ -95.187888, 29.522399 ], "pop" : 32217, "state" : "TX" }
+{ "_id" : "77547", "city" : "GALENA PARK", "loc" : [ -95.24000100000001, 29.739204 ], "pop" : 9306, "state" : "TX" }
+{ "_id" : "77550", "city" : "GALVESTON", "loc" : [ -94.79297, 29.298272 ], "pop" : 31879, "state" : "TX" }
+{ "_id" : "77551", "city" : "GALVESTON", "loc" : [ -94.83033399999999, 29.276584 ], "pop" : 22680, "state" : "TX" }
+{ "_id" : "77554", "city" : "GALVESTON", "loc" : [ -94.91371599999999, 29.229638 ], "pop" : 5495, "state" : "TX" }
+{ "_id" : "77560", "city" : "HANKAMER", "loc" : [ -94.593846, 29.87524 ], "pop" : 233, "state" : "TX" }
+{ "_id" : "77562", "city" : "HIGHLANDS", "loc" : [ -95.039286, 29.829599 ], "pop" : 17005, "state" : "TX" }
+{ "_id" : "77563", "city" : "HITCHCOCK", "loc" : [ -94.992591, 29.339835 ], "pop" : 8591, "state" : "TX" }
+{ "_id" : "77564", "city" : "HULL", "loc" : [ -94.660382, 30.13337 ], "pop" : 3386, "state" : "TX" }
+{ "_id" : "77565", "city" : "CLEAR LAKE SHORE", "loc" : [ -95.039209, 29.543823 ], "pop" : 4101, "state" : "TX" }
+{ "_id" : "77566", "city" : "LAKE JACKSON", "loc" : [ -95.440119, 29.039275 ], "pop" : 24000, "state" : "TX" }
+{ "_id" : "77568", "city" : "LA MARQUE", "loc" : [ -94.974159, 29.3676 ], "pop" : 13884, "state" : "TX" }
+{ "_id" : "77571", "city" : "SHOREACRES", "loc" : [ -95.05721, 29.660098 ], "pop" : 31556, "state" : "TX" }
+{ "_id" : "77573", "city" : "LEAGUE CITY", "loc" : [ -95.09627399999999, 29.517281 ], "pop" : 41580, "state" : "TX" }
+{ "_id" : "77575", "city" : "AMES", "loc" : [ -94.763819, 30.072794 ], "pop" : 14511, "state" : "TX" }
+{ "_id" : "77577", "city" : "LIVERPOOL", "loc" : [ -95.240754, 29.311457 ], "pop" : 2023, "state" : "TX" }
+{ "_id" : "77578", "city" : "MANVEL", "loc" : [ -95.35033, 29.469381 ], "pop" : 4754, "state" : "TX" }
+{ "_id" : "77581", "city" : "PEARLAND", "loc" : [ -95.272069, 29.561656 ], "pop" : 20807, "state" : "TX" }
+{ "_id" : "77583", "city" : "ROSHARON", "loc" : [ -95.453732, 29.420329 ], "pop" : 8495, "state" : "TX" }
+{ "_id" : "77584", "city" : "PEARLAND", "loc" : [ -95.320778, 29.540479 ], "pop" : 14234, "state" : "TX" }
+{ "_id" : "77585", "city" : "SARATOGA", "loc" : [ -94.571718, 30.339817 ], "pop" : 1921, "state" : "TX" }
+{ "_id" : "77586", "city" : "EL LAGO", "loc" : [ -95.028739, 29.572895 ], "pop" : 9490, "state" : "TX" }
+{ "_id" : "77587", "city" : "SOUTH HOUSTON", "loc" : [ -95.22582, 29.660097 ], "pop" : 16109, "state" : "TX" }
+{ "_id" : "77590", "city" : "TEXAS CITY", "loc" : [ -94.920298, 29.396984 ], "pop" : 30108, "state" : "TX" }
+{ "_id" : "77591", "city" : "TEXAS CITY", "loc" : [ -94.994204, 29.389097 ], "pop" : 10099, "state" : "TX" }
+{ "_id" : "77597", "city" : "WALLISVILLE", "loc" : [ -94.67589599999999, 29.859096 ], "pop" : 1072, "state" : "TX" }
+{ "_id" : "77598", "city" : "WEBSTER", "loc" : [ -95.143985, 29.55641 ], "pop" : 11453, "state" : "TX" }
+{ "_id" : "77611", "city" : "BRIDGE CITY", "loc" : [ -93.84729299999999, 30.04054 ], "pop" : 13688, "state" : "TX" }
+{ "_id" : "77612", "city" : "BUNA", "loc" : [ -93.991263, 30.413209 ], "pop" : 9023, "state" : "TX" }
+{ "_id" : "77614", "city" : "DEWEYVILLE", "loc" : [ -93.77305, 30.289295 ], "pop" : 3133, "state" : "TX" }
+{ "_id" : "77616", "city" : "FRED", "loc" : [ -94.185948, 30.598657 ], "pop" : 1973, "state" : "TX" }
+{ "_id" : "77619", "city" : "GROVES", "loc" : [ -93.915187, 29.944779 ], "pop" : 16865, "state" : "TX" }
+{ "_id" : "77622", "city" : "HAMSHIRE", "loc" : [ -94.31873899999999, 29.866769 ], "pop" : 571, "state" : "TX" }
+{ "_id" : "77624", "city" : "HILLISTER", "loc" : [ -94.407588, 30.689911 ], "pop" : 1326, "state" : "TX" }
+{ "_id" : "77625", "city" : "KOUNTZE", "loc" : [ -94.32590500000001, 30.370316 ], "pop" : 7073, "state" : "TX" }
+{ "_id" : "77627", "city" : "NEDERLAND", "loc" : [ -94.001192, 29.971609 ], "pop" : 22035, "state" : "TX" }
+{ "_id" : "77630", "city" : "WEST ORANGE", "loc" : [ -93.771883, 30.125167 ], "pop" : 39125, "state" : "TX" }
+{ "_id" : "77640", "city" : "PORT ACRES", "loc" : [ -93.96256200000001, 29.882557 ], "pop" : 24605, "state" : "TX" }
+{ "_id" : "77642", "city" : "PORT ARTHUR", "loc" : [ -93.926962, 29.92119 ], "pop" : 33943, "state" : "TX" }
+{ "_id" : "77650", "city" : "CRYSTAL BEACH", "loc" : [ -94.611678, 29.459788 ], "pop" : 2807, "state" : "TX" }
+{ "_id" : "77651", "city" : "PORT NECHES", "loc" : [ -93.96262400000001, 29.976983 ], "pop" : 13009, "state" : "TX" }
+{ "_id" : "77656", "city" : "SILSBEE", "loc" : [ -94.190726, 30.324387 ], "pop" : 27117, "state" : "TX" }
+{ "_id" : "77659", "city" : "SOUR LAKE", "loc" : [ -94.373341, 30.149134 ], "pop" : 4138, "state" : "TX" }
+{ "_id" : "77660", "city" : "SPURGER", "loc" : [ -94.212745, 30.778057 ], "pop" : 2516, "state" : "TX" }
+{ "_id" : "77662", "city" : "VIDOR", "loc" : [ -94.00077899999999, 30.15018 ], "pop" : 27702, "state" : "TX" }
+{ "_id" : "77664", "city" : "WARREN", "loc" : [ -94.411974, 30.597776 ], "pop" : 2465, "state" : "TX" }
+{ "_id" : "77665", "city" : "WINNIE", "loc" : [ -94.339499, 29.815676 ], "pop" : 2716, "state" : "TX" }
+{ "_id" : "77701", "city" : "BEAUMONT", "loc" : [ -94.10389600000001, 30.068805 ], "pop" : 18121, "state" : "TX" }
+{ "_id" : "77702", "city" : "BEAUMONT", "loc" : [ -94.125412, 30.087057 ], "pop" : 4396, "state" : "TX" }
+{ "_id" : "77703", "city" : "BEAUMONT", "loc" : [ -94.119698, 30.113201 ], "pop" : 16003, "state" : "TX" }
+{ "_id" : "77705", "city" : "BEAUMONT", "loc" : [ -94.115673, 30.021128 ], "pop" : 26134, "state" : "TX" }
+{ "_id" : "77706", "city" : "BEAUMONT", "loc" : [ -94.164816, 30.094834 ], "pop" : 25388, "state" : "TX" }
+{ "_id" : "77707", "city" : "BEAUMONT", "loc" : [ -94.175541, 30.068567 ], "pop" : 15366, "state" : "TX" }
+{ "_id" : "77708", "city" : "BEAUMONT", "loc" : [ -94.160357, 30.139957 ], "pop" : 10782, "state" : "TX" }
+{ "_id" : "77713", "city" : "BEAUMONT", "loc" : [ -94.26071899999999, 30.084996 ], "pop" : 10798, "state" : "TX" }
+{ "_id" : "77801", "city" : "BRYAN", "loc" : [ -96.36615999999999, 30.632698 ], "pop" : 12190, "state" : "TX" }
+{ "_id" : "77802", "city" : "BRYAN", "loc" : [ -96.335143, 30.658171 ], "pop" : 19306, "state" : "TX" }
+{ "_id" : "77803", "city" : "BRYAN", "loc" : [ -96.371398, 30.691293 ], "pop" : 32052, "state" : "TX" }
+{ "_id" : "77830", "city" : "ANDERSON", "loc" : [ -96.001822, 30.544291 ], "pop" : 1792, "state" : "TX" }
+{ "_id" : "77831", "city" : "SINGLETON", "loc" : [ -95.93356900000001, 30.764059 ], "pop" : 1079, "state" : "TX" }
+{ "_id" : "77833", "city" : "BRENHAM", "loc" : [ -96.40276900000001, 30.17736 ], "pop" : 20178, "state" : "TX" }
+{ "_id" : "77835", "city" : "BURTON", "loc" : [ -96.59247499999999, 30.176744 ], "pop" : 2444, "state" : "TX" }
+{ "_id" : "77836", "city" : "CALDWELL", "loc" : [ -96.714292, 30.529819 ], "pop" : 7873, "state" : "TX" }
+{ "_id" : "77837", "city" : "CALVERT", "loc" : [ -96.67107, 30.978211 ], "pop" : 1829, "state" : "TX" }
+{ "_id" : "77840", "city" : "COLLEGE STATION", "loc" : [ -96.31227, 30.604476 ], "pop" : 45766, "state" : "TX" }
+{ "_id" : "77843", "city" : "COLLEGE STATION", "loc" : [ -96.340001, 30.614738 ], "pop" : 10425, "state" : "TX" }
+{ "_id" : "77845", "city" : "COLLEGE STATION", "loc" : [ -96.31711300000001, 30.511811 ], "pop" : 1908, "state" : "TX" }
+{ "_id" : "77850", "city" : "CONCORD", "loc" : [ -96.102643, 31.263144 ], "pop" : 143, "state" : "TX" }
+{ "_id" : "77853", "city" : "DIME BOX", "loc" : [ -96.824781, 30.35786 ], "pop" : 699, "state" : "TX" }
+{ "_id" : "77856", "city" : "FRANKLIN", "loc" : [ -96.442643, 31.035013 ], "pop" : 4144, "state" : "TX" }
+{ "_id" : "77859", "city" : "HEARNE", "loc" : [ -96.584256, 30.86686 ], "pop" : 7655, "state" : "TX" }
+{ "_id" : "77861", "city" : "IOLA", "loc" : [ -96.091075, 30.732637 ], "pop" : 1418, "state" : "TX" }
+{ "_id" : "77864", "city" : "MADISONVILLE", "loc" : [ -95.909094, 30.953335 ], "pop" : 5532, "state" : "TX" }
+{ "_id" : "77865", "city" : "MARQUEZ", "loc" : [ -96.237499, 31.230889 ], "pop" : 1047, "state" : "TX" }
+{ "_id" : "77868", "city" : "NAVASOTA", "loc" : [ -96.05935700000001, 30.357645 ], "pop" : 12634, "state" : "TX" }
+{ "_id" : "77871", "city" : "HILLTOP LAKES", "loc" : [ -96.147274, 31.087473 ], "pop" : 2540, "state" : "TX" }
+{ "_id" : "77872", "city" : "NORTH ZULCH", "loc" : [ -96.09248599999999, 30.928531 ], "pop" : 1887, "state" : "TX" }
+{ "_id" : "77873", "city" : "RICHARDS", "loc" : [ -95.861053, 30.538166 ], "pop" : 787, "state" : "TX" }
+{ "_id" : "77879", "city" : "SOMERVILLE", "loc" : [ -96.535825, 30.407585 ], "pop" : 5752, "state" : "TX" }
+{ "_id" : "77880", "city" : "WASHINGTON", "loc" : [ -96.224948, 30.31819 ], "pop" : 616, "state" : "TX" }
+{ "_id" : "77901", "city" : "VICTORIA", "loc" : [ -96.999347, 28.808953 ], "pop" : 50119, "state" : "TX" }
+{ "_id" : "77904", "city" : "VICTORIA", "loc" : [ -96.998993, 28.867482 ], "pop" : 18982, "state" : "TX" }
+{ "_id" : "77951", "city" : "BLOOMINGTON", "loc" : [ -96.88407599999999, 28.68898 ], "pop" : 4452, "state" : "TX" }
+{ "_id" : "77954", "city" : "CUERO", "loc" : [ -97.28124699999999, 29.090969 ], "pop" : 8321, "state" : "TX" }
+{ "_id" : "77957", "city" : "EDNA", "loc" : [ -96.64876599999999, 28.952714 ], "pop" : 8987, "state" : "TX" }
+{ "_id" : "77962", "city" : "GANADO", "loc" : [ -96.503078, 29.03084 ], "pop" : 2876, "state" : "TX" }
+{ "_id" : "77963", "city" : "GOLIAD", "loc" : [ -97.378321, 28.699257 ], "pop" : 5980, "state" : "TX" }
+{ "_id" : "77964", "city" : "HALLETTSVILLE", "loc" : [ -96.923423, 29.442609 ], "pop" : 6905, "state" : "TX" }
+{ "_id" : "77968", "city" : "INEZ", "loc" : [ -96.80029399999999, 28.899416 ], "pop" : 808, "state" : "TX" }
+{ "_id" : "77971", "city" : "LOLITA", "loc" : [ -96.47933, 28.772449 ], "pop" : 2632, "state" : "TX" }
+{ "_id" : "77974", "city" : "MEYERSVILLE", "loc" : [ -97.30416099999999, 28.922921 ], "pop" : 45, "state" : "TX" }
+{ "_id" : "77975", "city" : "MOULTON", "loc" : [ -97.103122, 29.569992 ], "pop" : 2459, "state" : "TX" }
+{ "_id" : "77979", "city" : "PORT LAVACA", "loc" : [ -96.625941, 28.601135 ], "pop" : 15627, "state" : "TX" }
+{ "_id" : "77982", "city" : "PORT O CONNOR", "loc" : [ -96.775131, 28.140032 ], "pop" : 5, "state" : "TX" }
+{ "_id" : "77983", "city" : "SEADRIFT", "loc" : [ -96.702279, 28.410113 ], "pop" : 1965, "state" : "TX" }
+{ "_id" : "77984", "city" : "SHINER", "loc" : [ -97.163955, 29.428038 ], "pop" : 3596, "state" : "TX" }
+{ "_id" : "77990", "city" : "TIVOLI", "loc" : [ -96.88717200000001, 28.440122 ], "pop" : 965, "state" : "TX" }
+{ "_id" : "77994", "city" : "WESTHOFF", "loc" : [ -97.351102, 29.054983 ], "pop" : 2069, "state" : "TX" }
+{ "_id" : "77995", "city" : "YOAKUM", "loc" : [ -97.13063, 29.283954 ], "pop" : 9747, "state" : "TX" }
+{ "_id" : "78002", "city" : "ATASCOSA", "loc" : [ -98.74212, 29.270501 ], "pop" : 2943, "state" : "TX" }
+{ "_id" : "78003", "city" : "BANDERA", "loc" : [ -99.04527899999999, 29.72755 ], "pop" : 5538, "state" : "TX" }
+{ "_id" : "78004", "city" : "BERGHEIM", "loc" : [ -98.59325800000001, 29.839873 ], "pop" : 763, "state" : "TX" }
+{ "_id" : "78005", "city" : "BIGFOOT", "loc" : [ -98.85823000000001, 29.053073 ], "pop" : 328, "state" : "TX" }
+{ "_id" : "78006", "city" : "SISTERDALE", "loc" : [ -98.71340600000001, 29.77774 ], "pop" : 14427, "state" : "TX" }
+{ "_id" : "78007", "city" : "CALLIHAM", "loc" : [ -98.407873, 28.417682 ], "pop" : 230, "state" : "TX" }
+{ "_id" : "78008", "city" : "CAMPBELLTON", "loc" : [ -98.256573, 28.76699 ], "pop" : 475, "state" : "TX" }
+{ "_id" : "78009", "city" : "CASTROVILLE", "loc" : [ -98.882391, 29.35532 ], "pop" : 4262, "state" : "TX" }
+{ "_id" : "78010", "city" : "CAMP VERDE", "loc" : [ -99.00714000000001, 29.939658 ], "pop" : 2704, "state" : "TX" }
+{ "_id" : "78011", "city" : "CHARLOTTE", "loc" : [ -98.70700100000001, 28.864871 ], "pop" : 1990, "state" : "TX" }
+{ "_id" : "78013", "city" : "COMFORT", "loc" : [ -98.843772, 29.979072 ], "pop" : 3253, "state" : "TX" }
+{ "_id" : "78014", "city" : "COTULLA", "loc" : [ -99.23281799999999, 28.439837 ], "pop" : 4369, "state" : "TX" }
+{ "_id" : "78016", "city" : "DEVINE", "loc" : [ -98.90899400000001, 29.152078 ], "pop" : 6887, "state" : "TX" }
+{ "_id" : "78017", "city" : "DILLEY", "loc" : [ -99.174684, 28.678201 ], "pop" : 3396, "state" : "TX" }
+{ "_id" : "78019", "city" : "ENCINAL", "loc" : [ -99.340902, 28.051329 ], "pop" : 821, "state" : "TX" }
+{ "_id" : "78021", "city" : "FOWLERTON", "loc" : [ -98.851821, 28.488666 ], "pop" : 76, "state" : "TX" }
+{ "_id" : "78022", "city" : "GEORGE WEST", "loc" : [ -98.116159, 28.320388 ], "pop" : 4093, "state" : "TX" }
+{ "_id" : "78023", "city" : "GREY FOREST", "loc" : [ -98.703534, 29.592203 ], "pop" : 3552, "state" : "TX" }
+{ "_id" : "78024", "city" : "HUNT", "loc" : [ -99.48232899999999, 30.002694 ], "pop" : 263, "state" : "TX" }
+{ "_id" : "78025", "city" : "INGRAM", "loc" : [ -99.26902200000001, 30.073126 ], "pop" : 7005, "state" : "TX" }
+{ "_id" : "78026", "city" : "JOURDANTON", "loc" : [ -98.544037, 28.902985 ], "pop" : 4615, "state" : "TX" }
+{ "_id" : "78027", "city" : "KENDALIA", "loc" : [ -98.51655599999999, 29.940619 ], "pop" : 251, "state" : "TX" }
+{ "_id" : "78028", "city" : "KERRVILLE", "loc" : [ -99.140817, 30.041647 ], "pop" : 26128, "state" : "TX" }
+{ "_id" : "78039", "city" : "LA COSTE", "loc" : [ -98.812466, 29.308178 ], "pop" : 1320, "state" : "TX" }
+{ "_id" : "78040", "city" : "LAREDO", "loc" : [ -99.49857900000001, 27.515538 ], "pop" : 43486, "state" : "TX" }
+{ "_id" : "78041", "city" : "LAREDO", "loc" : [ -99.49065299999999, 27.556933 ], "pop" : 46156, "state" : "TX" }
+{ "_id" : "78043", "city" : "RIO BRAVO", "loc" : [ -99.46548799999999, 27.481537 ], "pop" : 42505, "state" : "TX" }
+{ "_id" : "78052", "city" : "LYTLE", "loc" : [ -98.794489, 29.236568 ], "pop" : 2078, "state" : "TX" }
+{ "_id" : "78053", "city" : "MC COY", "loc" : [ -98.371565, 28.792661 ], "pop" : 34, "state" : "TX" }
+{ "_id" : "78055", "city" : "MEDINA", "loc" : [ -99.306431, 29.790689 ], "pop" : 1590, "state" : "TX" }
+{ "_id" : "78056", "city" : "MICO", "loc" : [ -98.88210599999999, 29.59105 ], "pop" : 230, "state" : "TX" }
+{ "_id" : "78057", "city" : "MOORE", "loc" : [ -98.987403, 29.035377 ], "pop" : 767, "state" : "TX" }
+{ "_id" : "78058", "city" : "MOUNTAIN HOME", "loc" : [ -99.318607, 30.213249 ], "pop" : 207, "state" : "TX" }
+{ "_id" : "78059", "city" : "NATALIA", "loc" : [ -98.855158, 29.211669 ], "pop" : 4136, "state" : "TX" }
+{ "_id" : "78060", "city" : "OAKVILLE", "loc" : [ -98.055392, 28.464402 ], "pop" : 261, "state" : "TX" }
+{ "_id" : "78061", "city" : "PEARSALL", "loc" : [ -99.09436100000001, 28.892317 ], "pop" : 8981, "state" : "TX" }
+{ "_id" : "78063", "city" : "LAKEHILLS", "loc" : [ -98.922118, 29.631513 ], "pop" : 3187, "state" : "TX" }
+{ "_id" : "78064", "city" : "PLEASANTON", "loc" : [ -98.48306100000001, 28.992368 ], "pop" : 11977, "state" : "TX" }
+{ "_id" : "78065", "city" : "POTEET", "loc" : [ -98.624071, 29.099405 ], "pop" : 9523, "state" : "TX" }
+{ "_id" : "78066", "city" : "RIOMEDINA", "loc" : [ -98.866865, 29.490395 ], "pop" : 687, "state" : "TX" }
+{ "_id" : "78067", "city" : "SAN YGNACIO", "loc" : [ -99.427148, 27.062523 ], "pop" : 871, "state" : "TX" }
+{ "_id" : "78069", "city" : "SOMERSET", "loc" : [ -98.62140100000001, 29.211561 ], "pop" : 3477, "state" : "TX" }
+{ "_id" : "78070", "city" : "SPRING BRANCH", "loc" : [ -98.37878600000001, 29.923815 ], "pop" : 1544, "state" : "TX" }
+{ "_id" : "78071", "city" : "THREE RIVERS", "loc" : [ -98.178162, 28.475646 ], "pop" : 3190, "state" : "TX" }
+{ "_id" : "78072", "city" : "TILDEN", "loc" : [ -98.569322, 28.419755 ], "pop" : 575, "state" : "TX" }
+{ "_id" : "78073", "city" : "VON ORMY", "loc" : [ -98.66774100000001, 29.274979 ], "pop" : 2911, "state" : "TX" }
+{ "_id" : "78075", "city" : "WHITSETT", "loc" : [ -98.256484, 28.637316 ], "pop" : 135, "state" : "TX" }
+{ "_id" : "78076", "city" : "ZAPATA", "loc" : [ -99.250625, 26.88966 ], "pop" : 8408, "state" : "TX" }
+{ "_id" : "78101", "city" : "ADKINS", "loc" : [ -98.26504, 29.380542 ], "pop" : 3611, "state" : "TX" }
+{ "_id" : "78102", "city" : "BEEVILLE", "loc" : [ -97.761571, 28.422246 ], "pop" : 23211, "state" : "TX" }
+{ "_id" : "78108", "city" : "CIBOLO", "loc" : [ -98.22798299999999, 29.574971 ], "pop" : 6062, "state" : "TX" }
+{ "_id" : "78109", "city" : "CONVERSE", "loc" : [ -98.321673, 29.517331 ], "pop" : 13291, "state" : "TX" }
+{ "_id" : "78111", "city" : "ECLETO", "loc" : [ -97.741185, 29.020128 ], "pop" : 0, "state" : "TX" }
+{ "_id" : "78112", "city" : "ELMENDORF", "loc" : [ -98.371982, 29.230793 ], "pop" : 2251, "state" : "TX" }
+{ "_id" : "78113", "city" : "FALLS CITY", "loc" : [ -98.015632, 28.981413 ], "pop" : 964, "state" : "TX" }
+{ "_id" : "78114", "city" : "FLORESVILLE", "loc" : [ -98.193589, 29.169338 ], "pop" : 11510, "state" : "TX" }
+{ "_id" : "78116", "city" : "GILLETT", "loc" : [ -97.83432500000001, 29.051353 ], "pop" : 641, "state" : "TX" }
+{ "_id" : "78117", "city" : "HOBSON", "loc" : [ -97.970743, 28.944499 ], "pop" : 302, "state" : "TX" }
+{ "_id" : "78118", "city" : "KARNES CITY", "loc" : [ -97.90707, 28.882757 ], "pop" : 3827, "state" : "TX" }
+{ "_id" : "78119", "city" : "KENEDY", "loc" : [ -97.845601, 28.804584 ], "pop" : 5118, "state" : "TX" }
+{ "_id" : "78121", "city" : "LA VERNIA", "loc" : [ -98.112971, 29.350905 ], "pop" : 4529, "state" : "TX" }
+{ "_id" : "78122", "city" : "LEESVILLE", "loc" : [ -97.75662199999999, 29.396142 ], "pop" : 206, "state" : "TX" }
+{ "_id" : "78123", "city" : "MC QUEENEY", "loc" : [ -98.03759100000001, 29.605655 ], "pop" : 2055, "state" : "TX" }
+{ "_id" : "78124", "city" : "MARION", "loc" : [ -98.151709, 29.56835 ], "pop" : 4167, "state" : "TX" }
+{ "_id" : "78130", "city" : "CANYON LAKE", "loc" : [ -98.113041, 29.694733 ], "pop" : 32975, "state" : "TX" }
+{ "_id" : "78132", "city" : "CANYON LAKE", "loc" : [ -98.16721200000001, 29.72939 ], "pop" : 6412, "state" : "TX" }
+{ "_id" : "78133", "city" : "CANYON LAKE", "loc" : [ -98.24941200000001, 29.870984 ], "pop" : 8428, "state" : "TX" }
+{ "_id" : "78140", "city" : "NIXON", "loc" : [ -97.752898, 29.301649 ], "pop" : 2953, "state" : "TX" }
+{ "_id" : "78141", "city" : "NORDHEIM", "loc" : [ -97.594579, 28.914225 ], "pop" : 655, "state" : "TX" }
+{ "_id" : "78147", "city" : "POTH", "loc" : [ -98.08247, 29.06191 ], "pop" : 3000, "state" : "TX" }
+{ "_id" : "78148", "city" : "RANDOLPH A F B", "loc" : [ -98.306742, 29.551608 ], "pop" : 13215, "state" : "TX" }
+{ "_id" : "78150", "city" : "RANDOLPH A F B", "loc" : [ -98.27919300000001, 29.53021 ], "pop" : 4079, "state" : "TX" }
+{ "_id" : "78151", "city" : "RUNGE", "loc" : [ -97.713824, 28.887556 ], "pop" : 1603, "state" : "TX" }
+{ "_id" : "78152", "city" : "SAINT HEDWIG", "loc" : [ -98.195223, 29.435284 ], "pop" : 1685, "state" : "TX" }
+{ "_id" : "78154", "city" : "SELMA", "loc" : [ -98.27221400000001, 29.568159 ], "pop" : 10332, "state" : "TX" }
+{ "_id" : "78155", "city" : "SEGUIN", "loc" : [ -97.962801, 29.561316 ], "pop" : 32348, "state" : "TX" }
+{ "_id" : "78159", "city" : "SMILEY", "loc" : [ -97.62271200000001, 29.265529 ], "pop" : 972, "state" : "TX" }
+{ "_id" : "78160", "city" : "STOCKDALE", "loc" : [ -97.93508199999999, 29.231907 ], "pop" : 3085, "state" : "TX" }
+{ "_id" : "78161", "city" : "SUTHERLAND SPRIN", "loc" : [ -98.07079400000001, 29.277831 ], "pop" : 1051, "state" : "TX" }
+{ "_id" : "78163", "city" : "WETMORE", "loc" : [ -98.43784599999999, 29.780175 ], "pop" : 5491, "state" : "TX" }
+{ "_id" : "78164", "city" : "YORKTOWN", "loc" : [ -97.512056, 28.989191 ], "pop" : 3733, "state" : "TX" }
+{ "_id" : "78201", "city" : "BALCONES HEIGHTS", "loc" : [ -98.526352, 29.468525 ], "pop" : 43037, "state" : "TX" }
+{ "_id" : "78202", "city" : "SAN ANTONIO", "loc" : [ -98.460112, 29.427462 ], "pop" : 12043, "state" : "TX" }
+{ "_id" : "78203", "city" : "SAN ANTONIO", "loc" : [ -98.460127, 29.414799 ], "pop" : 7261, "state" : "TX" }
+{ "_id" : "78204", "city" : "SAN ANTONIO", "loc" : [ -98.5063, 29.400217 ], "pop" : 11526, "state" : "TX" }
+{ "_id" : "78205", "city" : "SAN ANTONIO", "loc" : [ -98.492509, 29.423711 ], "pop" : 1714, "state" : "TX" }
+{ "_id" : "78207", "city" : "SAN ANTONIO", "loc" : [ -98.52596699999999, 29.422855 ], "pop" : 58355, "state" : "TX" }
+{ "_id" : "78208", "city" : "SAN ANTONIO", "loc" : [ -98.458983, 29.440039 ], "pop" : 5007, "state" : "TX" }
+{ "_id" : "78209", "city" : "ALAMO HEIGHTS", "loc" : [ -98.45577400000001, 29.488623 ], "pop" : 34701, "state" : "TX" }
+{ "_id" : "78210", "city" : "SAN ANTONIO", "loc" : [ -98.465796, 29.397718 ], "pop" : 39300, "state" : "TX" }
+{ "_id" : "78211", "city" : "SAN ANTONIO", "loc" : [ -98.545219, 29.358366 ], "pop" : 30417, "state" : "TX" }
+{ "_id" : "78212", "city" : "OLMOS PARK", "loc" : [ -98.49581499999999, 29.461181 ], "pop" : 29762, "state" : "TX" }
+{ "_id" : "78213", "city" : "CASTLE HILLS", "loc" : [ -98.522679, 29.513406 ], "pop" : 36060, "state" : "TX" }
+{ "_id" : "78214", "city" : "SAN ANTONIO", "loc" : [ -98.492436, 29.364115 ], "pop" : 23338, "state" : "TX" }
+{ "_id" : "78215", "city" : "SAN ANTONIO", "loc" : [ -98.479338, 29.441338 ], "pop" : 1264, "state" : "TX" }
+{ "_id" : "78216", "city" : "SAN ANTONIO", "loc" : [ -98.497511, 29.533387 ], "pop" : 30435, "state" : "TX" }
+{ "_id" : "78217", "city" : "SAN ANTONIO", "loc" : [ -98.419444, 29.539525 ], "pop" : 27925, "state" : "TX" }
+{ "_id" : "78218", "city" : "SAN ANTONIO", "loc" : [ -98.403184, 29.496852 ], "pop" : 29276, "state" : "TX" }
+{ "_id" : "78219", "city" : "KIRBY", "loc" : [ -98.39731500000001, 29.448794 ], "pop" : 14249, "state" : "TX" }
+{ "_id" : "78220", "city" : "SAN ANTONIO", "loc" : [ -98.412791, 29.410641 ], "pop" : 17035, "state" : "TX" }
+{ "_id" : "78221", "city" : "SAN ANTONIO", "loc" : [ -98.50541699999999, 29.330913 ], "pop" : 35392, "state" : "TX" }
+{ "_id" : "78222", "city" : "SAN ANTONIO", "loc" : [ -98.396005, 29.383113 ], "pop" : 12729, "state" : "TX" }
+{ "_id" : "78223", "city" : "SAN ANTONIO", "loc" : [ -98.43562799999999, 29.357869 ], "pop" : 38381, "state" : "TX" }
+{ "_id" : "78224", "city" : "SAN ANTONIO", "loc" : [ -98.53933499999999, 29.337432 ], "pop" : 14894, "state" : "TX" }
+{ "_id" : "78225", "city" : "SAN ANTONIO", "loc" : [ -98.524494, 29.387497 ], "pop" : 13803, "state" : "TX" }
+{ "_id" : "78226", "city" : "SAN ANTONIO", "loc" : [ -98.551095, 29.393001 ], "pop" : 7141, "state" : "TX" }
+{ "_id" : "78227", "city" : "SAN ANTONIO", "loc" : [ -98.643311, 29.402687 ], "pop" : 42329, "state" : "TX" }
+{ "_id" : "78228", "city" : "SAN ANTONIO", "loc" : [ -98.56987100000001, 29.458937 ], "pop" : 58136, "state" : "TX" }
+{ "_id" : "78229", "city" : "SAN ANTONIO", "loc" : [ -98.569726, 29.504228 ], "pop" : 22681, "state" : "TX" }
+{ "_id" : "78230", "city" : "SAN ANTONIO", "loc" : [ -98.552117, 29.540738 ], "pop" : 30253, "state" : "TX" }
+{ "_id" : "78231", "city" : "SHAVANO PARK", "loc" : [ -98.536817, 29.571434 ], "pop" : 7504, "state" : "TX" }
+{ "_id" : "78232", "city" : "HOLLYWOOD PARK", "loc" : [ -98.46729999999999, 29.582833 ], "pop" : 27332, "state" : "TX" }
+{ "_id" : "78233", "city" : "LIVE OAK", "loc" : [ -98.369128, 29.554741 ], "pop" : 36334, "state" : "TX" }
+{ "_id" : "78234", "city" : "FORT SAM HOUSTON", "loc" : [ -98.43540400000001, 29.461961 ], "pop" : 8258, "state" : "TX" }
+{ "_id" : "78235", "city" : "BROOKS A F B", "loc" : [ -98.43944399999999, 29.341733 ], "pop" : 885, "state" : "TX" }
+{ "_id" : "78236", "city" : "WILFORD HALL U S", "loc" : [ -98.613367, 29.394267 ], "pop" : 8707, "state" : "TX" }
+{ "_id" : "78237", "city" : "SAN ANTONIO", "loc" : [ -98.56454600000001, 29.420758 ], "pop" : 38900, "state" : "TX" }
+{ "_id" : "78238", "city" : "LEON VALLEY", "loc" : [ -98.61545099999999, 29.476833 ], "pop" : 20840, "state" : "TX" }
+{ "_id" : "78239", "city" : "WINDCREST", "loc" : [ -98.361604, 29.515686 ], "pop" : 21781, "state" : "TX" }
+{ "_id" : "78240", "city" : "SAN ANTONIO", "loc" : [ -98.600566, 29.518896 ], "pop" : 33776, "state" : "TX" }
+{ "_id" : "78241", "city" : "KELLY A F B", "loc" : [ -98.578063, 29.392432 ], "pop" : 1784, "state" : "TX" }
+{ "_id" : "78242", "city" : "SAN ANTONIO", "loc" : [ -98.610927, 29.350905 ], "pop" : 24343, "state" : "TX" }
+{ "_id" : "78244", "city" : "SAN ANTONIO", "loc" : [ -98.347585, 29.479264 ], "pop" : 13798, "state" : "TX" }
+{ "_id" : "78245", "city" : "SAN ANTONIO", "loc" : [ -98.689494, 29.418927 ], "pop" : 20410, "state" : "TX" }
+{ "_id" : "78247", "city" : "WETMORE", "loc" : [ -98.409783, 29.577604 ], "pop" : 25572, "state" : "TX" }
+{ "_id" : "78248", "city" : "SAN ANTONIO", "loc" : [ -98.520105, 29.58936 ], "pop" : 4469, "state" : "TX" }
+{ "_id" : "78249", "city" : "SAN ANTONIO", "loc" : [ -98.611666, 29.561245 ], "pop" : 19127, "state" : "TX" }
+{ "_id" : "78250", "city" : "SAN ANTONIO", "loc" : [ -98.66876499999999, 29.505394 ], "pop" : 43845, "state" : "TX" }
+{ "_id" : "78251", "city" : "SAN ANTONIO", "loc" : [ -98.655472, 29.459743 ], "pop" : 15297, "state" : "TX" }
+{ "_id" : "78252", "city" : "SAN ANTONIO", "loc" : [ -98.646395, 29.346015 ], "pop" : 1378, "state" : "TX" }
+{ "_id" : "78253", "city" : "SAN ANTONIO", "loc" : [ -98.74793099999999, 29.459923 ], "pop" : 3861, "state" : "TX" }
+{ "_id" : "78254", "city" : "SAN ANTONIO", "loc" : [ -98.724841, 29.54091 ], "pop" : 1340, "state" : "TX" }
+{ "_id" : "78255", "city" : "SAN ANTONIO", "loc" : [ -98.65557200000001, 29.636875 ], "pop" : 2544, "state" : "TX" }
+{ "_id" : "78256", "city" : "SAN ANTONIO", "loc" : [ -98.625215, 29.616946 ], "pop" : 1237, "state" : "TX" }
+{ "_id" : "78257", "city" : "SAN ANTONIO", "loc" : [ -98.61370100000001, 29.64953 ], "pop" : 1360, "state" : "TX" }
+{ "_id" : "78258", "city" : "SAN ANTONIO", "loc" : [ -98.49669900000001, 29.65624 ], "pop" : 2877, "state" : "TX" }
+{ "_id" : "78259", "city" : "SAN ANTONIO", "loc" : [ -98.444495, 29.628331 ], "pop" : 3865, "state" : "TX" }
+{ "_id" : "78260", "city" : "SAN ANTONIO", "loc" : [ -98.475908, 29.702578 ], "pop" : 1684, "state" : "TX" }
+{ "_id" : "78261", "city" : "SAN ANTONIO", "loc" : [ -98.41909200000001, 29.705463 ], "pop" : 487, "state" : "TX" }
+{ "_id" : "78263", "city" : "SAN ANTONIO", "loc" : [ -98.317386, 29.36143 ], "pop" : 2836, "state" : "TX" }
+{ "_id" : "78264", "city" : "SAN ANTONIO", "loc" : [ -98.472272, 29.173345 ], "pop" : 3723, "state" : "TX" }
+{ "_id" : "78266", "city" : "GARDEN RIDGE", "loc" : [ -98.312774, 29.644226 ], "pop" : 2016, "state" : "TX" }
+{ "_id" : "78332", "city" : "ALICE", "loc" : [ -98.08362200000001, 27.743171 ], "pop" : 28292, "state" : "TX" }
+{ "_id" : "78336", "city" : "ARANSAS PASS", "loc" : [ -97.159091, 27.909498 ], "pop" : 9087, "state" : "TX" }
+{ "_id" : "78338", "city" : "ARMSTRONG", "loc" : [ -97.70929099999999, 26.738706 ], "pop" : 148, "state" : "TX" }
+{ "_id" : "78340", "city" : "BAYSIDE", "loc" : [ -97.210643, 28.096758 ], "pop" : 454, "state" : "TX" }
+{ "_id" : "78343", "city" : "BISHOP", "loc" : [ -97.78303099999999, 27.588564 ], "pop" : 4608, "state" : "TX" }
+{ "_id" : "78344", "city" : "BRUNI", "loc" : [ -98.85010800000001, 27.435329 ], "pop" : 508, "state" : "TX" }
+{ "_id" : "78349", "city" : "CONCEPCION", "loc" : [ -98.381489, 27.544266 ], "pop" : 3458, "state" : "TX" }
+{ "_id" : "78353", "city" : "ENCINO", "loc" : [ -98.192168, 26.924862 ], "pop" : 703, "state" : "TX" }
+{ "_id" : "78355", "city" : "FALFURRIAS", "loc" : [ -98.140844, 27.22416 ], "pop" : 7501, "state" : "TX" }
+{ "_id" : "78357", "city" : "FREER", "loc" : [ -98.606129, 27.879984 ], "pop" : 3922, "state" : "TX" }
+{ "_id" : "78358", "city" : "FULTON", "loc" : [ -96.80837699999999, 28.223448 ], "pop" : 0, "state" : "TX" }
+{ "_id" : "78360", "city" : "GUERRA", "loc" : [ -98.918886, 26.912753 ], "pop" : 34, "state" : "TX" }
+{ "_id" : "78361", "city" : "HEBBRONVILLE", "loc" : [ -98.68288800000001, 27.2997 ], "pop" : 5078, "state" : "TX" }
+{ "_id" : "78362", "city" : "INGLESIDE", "loc" : [ -97.206906, 27.868238 ], "pop" : 5871, "state" : "TX" }
+{ "_id" : "78363", "city" : "KINGSVILLE NAVAL", "loc" : [ -97.85959800000001, 27.507418 ], "pop" : 28435, "state" : "TX" }
+{ "_id" : "78368", "city" : "MATHIS", "loc" : [ -97.809659, 28.080208 ], "pop" : 11068, "state" : "TX" }
+{ "_id" : "78369", "city" : "MIRANDO CITY", "loc" : [ -99.00111699999999, 27.445038 ], "pop" : 584, "state" : "TX" }
+{ "_id" : "78370", "city" : "ODEM", "loc" : [ -97.583752, 27.940306 ], "pop" : 3299, "state" : "TX" }
+{ "_id" : "78372", "city" : "ORANGE GROVE", "loc" : [ -97.983835, 27.948659 ], "pop" : 4339, "state" : "TX" }
+{ "_id" : "78374", "city" : "PORTLAND", "loc" : [ -97.316931, 27.893547 ], "pop" : 15830, "state" : "TX" }
+{ "_id" : "78375", "city" : "PREMONT", "loc" : [ -98.13301800000001, 27.354444 ], "pop" : 4051, "state" : "TX" }
+{ "_id" : "78376", "city" : "REALITOS", "loc" : [ -98.535493, 27.416283 ], "pop" : 520, "state" : "TX" }
+{ "_id" : "78377", "city" : "REFUGIO", "loc" : [ -97.27666499999999, 28.316944 ], "pop" : 4004, "state" : "TX" }
+{ "_id" : "78379", "city" : "RIVIERA", "loc" : [ -97.778707, 27.321735 ], "pop" : 1839, "state" : "TX" }
+{ "_id" : "78380", "city" : "ROBSTOWN", "loc" : [ -97.699523, 27.798395 ], "pop" : 24903, "state" : "TX" }
+{ "_id" : "78382", "city" : "ROCKPORT", "loc" : [ -97.06877299999999, 28.030778 ], "pop" : 16944, "state" : "TX" }
+{ "_id" : "78383", "city" : "SANDIA", "loc" : [ -97.89784899999999, 28.070879 ], "pop" : 2053, "state" : "TX" }
+{ "_id" : "78384", "city" : "SAN DIEGO", "loc" : [ -98.250297, 27.76535 ], "pop" : 5018, "state" : "TX" }
+{ "_id" : "78385", "city" : "SARITA", "loc" : [ -97.85762699999999, 27.149622 ], "pop" : 312, "state" : "TX" }
+{ "_id" : "78387", "city" : "SINTON", "loc" : [ -97.519582, 28.033895 ], "pop" : 9051, "state" : "TX" }
+{ "_id" : "78389", "city" : "SKIDMORE", "loc" : [ -97.666071, 28.230577 ], "pop" : 1785, "state" : "TX" }
+{ "_id" : "78390", "city" : "TAFT", "loc" : [ -97.39662300000001, 27.976517 ], "pop" : 6140, "state" : "TX" }
+{ "_id" : "78391", "city" : "TYNAN", "loc" : [ -97.754881, 28.169341 ], "pop" : 327, "state" : "TX" }
+{ "_id" : "78393", "city" : "WOODSBORO", "loc" : [ -97.31921, 28.223222 ], "pop" : 2559, "state" : "TX" }
+{ "_id" : "78401", "city" : "CORPUS CHRISTI", "loc" : [ -97.40299400000001, 27.794086 ], "pop" : 5811, "state" : "TX" }
+{ "_id" : "78402", "city" : "CORPUS CHRISTI", "loc" : [ -97.385659, 27.82621 ], "pop" : 451, "state" : "TX" }
+{ "_id" : "78404", "city" : "CORPUS CHRISTI", "loc" : [ -97.40125500000001, 27.768329 ], "pop" : 17395, "state" : "TX" }
+{ "_id" : "78405", "city" : "CORPUS CHRISTI", "loc" : [ -97.427132, 27.776234 ], "pop" : 17437, "state" : "TX" }
+{ "_id" : "78406", "city" : "CORPUS CHRISTI", "loc" : [ -97.51445, 27.768412 ], "pop" : 1556, "state" : "TX" }
+{ "_id" : "78407", "city" : "CORPUS CHRISTI", "loc" : [ -97.435597, 27.804195 ], "pop" : 6334, "state" : "TX" }
+{ "_id" : "78408", "city" : "CORPUS CHRISTI", "loc" : [ -97.43814999999999, 27.794477 ], "pop" : 10071, "state" : "TX" }
+{ "_id" : "78409", "city" : "CORPUS CHRISTI", "loc" : [ -97.527034, 27.814555 ], "pop" : 2655, "state" : "TX" }
+{ "_id" : "78410", "city" : "CORPUS CHRISTI", "loc" : [ -97.596002, 27.84585 ], "pop" : 20860, "state" : "TX" }
+{ "_id" : "78411", "city" : "CORPUS CHRISTI", "loc" : [ -97.387732, 27.731139 ], "pop" : 27625, "state" : "TX" }
+{ "_id" : "78412", "city" : "CORPUS CHRISTI", "loc" : [ -97.353694, 27.70608 ], "pop" : 33510, "state" : "TX" }
+{ "_id" : "78413", "city" : "CORPUS CHRISTI", "loc" : [ -97.39832, 27.691041 ], "pop" : 27278, "state" : "TX" }
+{ "_id" : "78414", "city" : "CORPUS CHRISTI", "loc" : [ -97.365016, 27.677016 ], "pop" : 8600, "state" : "TX" }
+{ "_id" : "78415", "city" : "CORPUS CHRISTI", "loc" : [ -97.40778, 27.726204 ], "pop" : 39998, "state" : "TX" }
+{ "_id" : "78416", "city" : "CORPUS CHRISTI", "loc" : [ -97.43468, 27.753593 ], "pop" : 16634, "state" : "TX" }
+{ "_id" : "78417", "city" : "CORPUS CHRISTI", "loc" : [ -97.44942899999999, 27.728964 ], "pop" : 3075, "state" : "TX" }
+{ "_id" : "78418", "city" : "CORPUS CHRISTI", "loc" : [ -97.266558, 27.668531 ], "pop" : 20449, "state" : "TX" }
+{ "_id" : "78419", "city" : "CORPUS CHRISTI", "loc" : [ -97.27636, 27.692502 ], "pop" : 1873, "state" : "TX" }
+{ "_id" : "78473", "city" : "CORPUS CHRISTI", "loc" : [ -97.396624, 27.79515 ], "pop" : 0, "state" : "TX" }
+{ "_id" : "78501", "city" : "MCALLEN", "loc" : [ -98.235871, 26.21544 ], "pop" : 53932, "state" : "TX" }
+{ "_id" : "78503", "city" : "MCALLEN", "loc" : [ -98.251974, 26.177115 ], "pop" : 14820, "state" : "TX" }
+{ "_id" : "78504", "city" : "MCALLEN", "loc" : [ -98.230253, 26.255645 ], "pop" : 15182, "state" : "TX" }
+{ "_id" : "78516", "city" : "ALAMO", "loc" : [ -98.116445, 26.190578 ], "pop" : 16555, "state" : "TX" }
+{ "_id" : "78520", "city" : "BROWNSVILLE", "loc" : [ -97.517413, 25.933743 ], "pop" : 50091, "state" : "TX" }
+{ "_id" : "78521", "city" : "BROWNSVILLE", "loc" : [ -97.461236, 25.922103 ], "pop" : 79463, "state" : "TX" }
+{ "_id" : "78536", "city" : "DELMITA", "loc" : [ -98.396553, 26.656571 ], "pop" : 55, "state" : "TX" }
+{ "_id" : "78537", "city" : "DONNA", "loc" : [ -98.052925, 26.167138 ], "pop" : 20909, "state" : "TX" }
+{ "_id" : "78538", "city" : "MONTE ALTO", "loc" : [ -97.97547299999999, 26.304208 ], "pop" : 16225, "state" : "TX" }
+{ "_id" : "78539", "city" : "EDINBURG", "loc" : [ -98.15692199999999, 26.304221 ], "pop" : 52534, "state" : "TX" }
+{ "_id" : "78547", "city" : "GARCIASVILLE", "loc" : [ -98.669112, 26.312894 ], "pop" : 5741, "state" : "TX" }
+{ "_id" : "78548", "city" : "GRULLA", "loc" : [ -98.596041, 26.293714 ], "pop" : 303, "state" : "TX" }
+{ "_id" : "78549", "city" : "HARGILL", "loc" : [ -97.99933, 26.433812 ], "pop" : 1294, "state" : "TX" }
+{ "_id" : "78550", "city" : "HARLINGEN", "loc" : [ -97.688981, 26.195142 ], "pop" : 43292, "state" : "TX" }
+{ "_id" : "78552", "city" : "HARLINGEN", "loc" : [ -97.746771, 26.183069 ], "pop" : 21672, "state" : "TX" }
+{ "_id" : "78557", "city" : "HIDALGO", "loc" : [ -98.253641, 26.102832 ], "pop" : 3300, "state" : "TX" }
+{ "_id" : "78559", "city" : "LA FERIA", "loc" : [ -97.826115, 26.166556 ], "pop" : 8446, "state" : "TX" }
+{ "_id" : "78563", "city" : "LINN", "loc" : [ -98.17986999999999, 26.542054 ], "pop" : 1244, "state" : "TX" }
+{ "_id" : "78566", "city" : "BAYVIEW", "loc" : [ -97.490402, 26.091068 ], "pop" : 9033, "state" : "TX" }
+{ "_id" : "78569", "city" : "LYFORD", "loc" : [ -97.78165300000001, 26.408926 ], "pop" : 2757, "state" : "TX" }
+{ "_id" : "78570", "city" : "MERCEDES", "loc" : [ -97.918503, 26.15133 ], "pop" : 21450, "state" : "TX" }
+{ "_id" : "78572", "city" : "ALTON", "loc" : [ -98.342647, 26.24153 ], "pop" : 67604, "state" : "TX" }
+{ "_id" : "78577", "city" : "PHARR", "loc" : [ -98.187022, 26.177053 ], "pop" : 36070, "state" : "TX" }
+{ "_id" : "78578", "city" : "PORT ISABEL", "loc" : [ -97.254389, 26.08764 ], "pop" : 9335, "state" : "TX" }
+{ "_id" : "78580", "city" : "RAYMONDVILLE", "loc" : [ -97.79666, 26.479243 ], "pop" : 11642, "state" : "TX" }
+{ "_id" : "78582", "city" : "RIO GRANDE CITY", "loc" : [ -98.810444, 26.394194 ], "pop" : 19113, "state" : "TX" }
+{ "_id" : "78583", "city" : "RIO HONDO", "loc" : [ -97.551311, 26.233855 ], "pop" : 4990, "state" : "TX" }
+{ "_id" : "78584", "city" : "ROMA", "loc" : [ -99.00247899999999, 26.421545 ], "pop" : 14612, "state" : "TX" }
+{ "_id" : "78586", "city" : "SAN BENITO", "loc" : [ -97.64474800000001, 26.133659 ], "pop" : 28609, "state" : "TX" }
+{ "_id" : "78588", "city" : "SAN ISIDRO", "loc" : [ -98.416147, 26.721404 ], "pop" : 468, "state" : "TX" }
+{ "_id" : "78589", "city" : "SAN JUAN", "loc" : [ -98.153729, 26.204375 ], "pop" : 18419, "state" : "TX" }
+{ "_id" : "78590", "city" : "SAN PERLITA", "loc" : [ -97.61569900000001, 26.483156 ], "pop" : 886, "state" : "TX" }
+{ "_id" : "78591", "city" : "SANTA ELENA", "loc" : [ -98.519412, 26.73364 ], "pop" : 223, "state" : "TX" }
+{ "_id" : "78593", "city" : "SANTA ROSA", "loc" : [ -97.82566300000001, 26.255508 ], "pop" : 3393, "state" : "TX" }
+{ "_id" : "78594", "city" : "SEBASTIAN", "loc" : [ -97.774728, 26.34524 ], "pop" : 2137, "state" : "TX" }
+{ "_id" : "78595", "city" : "SULLIVAN CITY", "loc" : [ -98.562713, 26.27197 ], "pop" : 3351, "state" : "TX" }
+{ "_id" : "78596", "city" : "WESLACO", "loc" : [ -97.988714, 26.169444 ], "pop" : 40652, "state" : "TX" }
+{ "_id" : "78597", "city" : "SOUTH PADRE ISLA", "loc" : [ -97.167294, 26.111105 ], "pop" : 1796, "state" : "TX" }
+{ "_id" : "78598", "city" : "PORT MANSFIELD", "loc" : [ -97.427982, 26.555237 ], "pop" : 287, "state" : "TX" }
+{ "_id" : "78602", "city" : "BASTROP", "loc" : [ -97.292101, 30.13883 ], "pop" : 10588, "state" : "TX" }
+{ "_id" : "78603", "city" : "BEBE", "loc" : [ -97.626594, 29.422211 ], "pop" : 82, "state" : "TX" }
+{ "_id" : "78605", "city" : "BERTRAM", "loc" : [ -98.052932, 30.741082 ], "pop" : 1622, "state" : "TX" }
+{ "_id" : "78606", "city" : "BLANCO", "loc" : [ -98.410663, 30.087359 ], "pop" : 3152, "state" : "TX" }
+{ "_id" : "78607", "city" : "BLUFFTON", "loc" : [ -98.51503, 30.825633 ], "pop" : 31, "state" : "TX" }
+{ "_id" : "78608", "city" : "BRIGGS", "loc" : [ -97.97022800000001, 30.932546 ], "pop" : 715, "state" : "TX" }
+{ "_id" : "78609", "city" : "BUCHANAN DAM", "loc" : [ -98.453226, 30.759765 ], "pop" : 1457, "state" : "TX" }
+{ "_id" : "78610", "city" : "BUDA", "loc" : [ -97.85342199999999, 30.091758 ], "pop" : 7487, "state" : "TX" }
+{ "_id" : "78611", "city" : "BURNET", "loc" : [ -98.26424, 30.776597 ], "pop" : 8460, "state" : "TX" }
+{ "_id" : "78612", "city" : "CEDAR CREEK", "loc" : [ -97.497602, 30.096636 ], "pop" : 8026, "state" : "TX" }
+{ "_id" : "78613", "city" : "CEDAR PARK", "loc" : [ -97.817571, 30.477165 ], "pop" : 22192, "state" : "TX" }
+{ "_id" : "78614", "city" : "COST", "loc" : [ -97.553124, 29.432098 ], "pop" : 286, "state" : "TX" }
+{ "_id" : "78615", "city" : "COUPLAND", "loc" : [ -97.330364, 30.532357 ], "pop" : 2311, "state" : "TX" }
+{ "_id" : "78616", "city" : "DALE", "loc" : [ -97.580968, 29.952785 ], "pop" : 2666, "state" : "TX" }
+{ "_id" : "78617", "city" : "DEL VALLE", "loc" : [ -97.613443, 30.174492 ], "pop" : 5635, "state" : "TX" }
+{ "_id" : "78618", "city" : "DOSS", "loc" : [ -99.17072, 30.461319 ], "pop" : 54, "state" : "TX" }
+{ "_id" : "78619", "city" : "DRIFTWOOD", "loc" : [ -98.05237200000001, 30.159351 ], "pop" : 1064, "state" : "TX" }
+{ "_id" : "78620", "city" : "DRIPPING SPRINGS", "loc" : [ -98.102947, 30.226768 ], "pop" : 3453, "state" : "TX" }
+{ "_id" : "78621", "city" : "ELGIN", "loc" : [ -97.37374800000001, 30.323136 ], "pop" : 9852, "state" : "TX" }
+{ "_id" : "78623", "city" : "FISCHER", "loc" : [ -98.25828300000001, 29.969588 ], "pop" : 459, "state" : "TX" }
+{ "_id" : "78624", "city" : "FREDERICKSBURG", "loc" : [ -98.87992800000001, 30.281658 ], "pop" : 15125, "state" : "TX" }
+{ "_id" : "78626", "city" : "GEORGETOWN", "loc" : [ -97.670704, 30.633038 ], "pop" : 8153, "state" : "TX" }
+{ "_id" : "78628", "city" : "ANDICE", "loc" : [ -97.70093900000001, 30.659364 ], "pop" : 14100, "state" : "TX" }
+{ "_id" : "78629", "city" : "GONZALES", "loc" : [ -97.449456, 29.50857 ], "pop" : 11297, "state" : "TX" }
+{ "_id" : "78631", "city" : "HARPER", "loc" : [ -99.24104800000001, 30.281637 ], "pop" : 1144, "state" : "TX" }
+{ "_id" : "78632", "city" : "HARWOOD", "loc" : [ -97.490622, 29.666108 ], "pop" : 295, "state" : "TX" }
+{ "_id" : "78634", "city" : "HUTTO", "loc" : [ -97.56720300000001, 30.525725 ], "pop" : 2314, "state" : "TX" }
+{ "_id" : "78635", "city" : "HYE", "loc" : [ -98.539607, 30.226866 ], "pop" : 341, "state" : "TX" }
+{ "_id" : "78636", "city" : "JOHNSON CITY", "loc" : [ -98.36908200000001, 30.294806 ], "pop" : 2219, "state" : "TX" }
+{ "_id" : "78638", "city" : "KINGSBURY", "loc" : [ -97.830634, 29.672566 ], "pop" : 1073, "state" : "TX" }
+{ "_id" : "78639", "city" : "KINGSLAND", "loc" : [ -98.447492, 30.666212 ], "pop" : 2797, "state" : "TX" }
+{ "_id" : "78640", "city" : "UHLAND", "loc" : [ -97.83710600000001, 30.0043 ], "pop" : 8770, "state" : "TX" }
+{ "_id" : "78641", "city" : "LEANDER", "loc" : [ -97.87516599999999, 30.552888 ], "pop" : 10882, "state" : "TX" }
+{ "_id" : "78642", "city" : "LIBERTY HILL", "loc" : [ -97.93159799999999, 30.662953 ], "pop" : 2028, "state" : "TX" }
+{ "_id" : "78643", "city" : "SUNRISE BEACH", "loc" : [ -98.652727, 30.722533 ], "pop" : 4802, "state" : "TX" }
+{ "_id" : "78644", "city" : "LOCKHART", "loc" : [ -97.676922, 29.886759 ], "pop" : 11690, "state" : "TX" }
+{ "_id" : "78645", "city" : "JONESTOWN", "loc" : [ -97.97023, 30.459796 ], "pop" : 4060, "state" : "TX" }
+{ "_id" : "78648", "city" : "LULING", "loc" : [ -97.649947, 29.682621 ], "pop" : 6587, "state" : "TX" }
+{ "_id" : "78650", "city" : "MC DADE", "loc" : [ -97.238556, 30.296816 ], "pop" : 721, "state" : "TX" }
+{ "_id" : "78652", "city" : "MANCHACA", "loc" : [ -97.853793, 30.127267 ], "pop" : 4049, "state" : "TX" }
+{ "_id" : "78653", "city" : "MANOR", "loc" : [ -97.532295, 30.338817 ], "pop" : 5359, "state" : "TX" }
+{ "_id" : "78654", "city" : "CYPRESS MILL", "loc" : [ -98.30699199999999, 30.57228 ], "pop" : 13422, "state" : "TX" }
+{ "_id" : "78655", "city" : "MARTINDALE", "loc" : [ -97.79331999999999, 29.793328 ], "pop" : 2081, "state" : "TX" }
+{ "_id" : "78656", "city" : "MAXWELL", "loc" : [ -97.852852, 29.878628 ], "pop" : 3974, "state" : "TX" }
+{ "_id" : "78659", "city" : "PAIGE", "loc" : [ -97.119771, 30.185799 ], "pop" : 1294, "state" : "TX" }
+{ "_id" : "78660", "city" : "PFLUGERVILLE", "loc" : [ -97.629895, 30.442133 ], "pop" : 12297, "state" : "TX" }
+{ "_id" : "78662", "city" : "RED ROCK", "loc" : [ -97.408058, 29.990616 ], "pop" : 1963, "state" : "TX" }
+{ "_id" : "78663", "city" : "ROUND MOUNTAIN", "loc" : [ -98.436514, 30.442879 ], "pop" : 169, "state" : "TX" }
+{ "_id" : "78664", "city" : "ROUND ROCK", "loc" : [ -97.66802800000001, 30.51452 ], "pop" : 20142, "state" : "TX" }
+{ "_id" : "78665", "city" : "SANDY", "loc" : [ -98.509846, 30.339127 ], "pop" : 91, "state" : "TX" }
+{ "_id" : "78666", "city" : "SAN MARCOS", "loc" : [ -97.94041799999999, 29.875359 ], "pop" : 39087, "state" : "TX" }
+{ "_id" : "78669", "city" : "SPICEWOOD", "loc" : [ -98.05392000000001, 30.389945 ], "pop" : 2235, "state" : "TX" }
+{ "_id" : "78671", "city" : "ALBERT", "loc" : [ -98.655468, 30.224921 ], "pop" : 777, "state" : "TX" }
+{ "_id" : "78672", "city" : "TOW", "loc" : [ -98.459647, 30.860867 ], "pop" : 874, "state" : "TX" }
+{ "_id" : "78675", "city" : "WILLOW CITY", "loc" : [ -98.66458900000001, 30.454889 ], "pop" : 104, "state" : "TX" }
+{ "_id" : "78676", "city" : "WIMBERLEY", "loc" : [ -98.11230999999999, 30.026471 ], "pop" : 7004, "state" : "TX" }
+{ "_id" : "78677", "city" : "WRIGHTSBORO", "loc" : [ -97.503531, 29.357772 ], "pop" : 26, "state" : "TX" }
+{ "_id" : "78681", "city" : "ROUND ROCK", "loc" : [ -97.706171, 30.508431 ], "pop" : 17196, "state" : "TX" }
+{ "_id" : "78701", "city" : "AUSTIN", "loc" : [ -97.742559, 30.271289 ], "pop" : 3857, "state" : "TX" }
+{ "_id" : "78702", "city" : "AUSTIN", "loc" : [ -97.716589, 30.263817 ], "pop" : 21432, "state" : "TX" }
+{ "_id" : "78703", "city" : "AUSTIN", "loc" : [ -97.764809, 30.290671 ], "pop" : 18253, "state" : "TX" }
+{ "_id" : "78704", "city" : "AUSTIN", "loc" : [ -97.765788, 30.242831 ], "pop" : 39211, "state" : "TX" }
+{ "_id" : "78705", "city" : "AUSTIN", "loc" : [ -97.739627, 30.289619 ], "pop" : 23679, "state" : "TX" }
+{ "_id" : "78717", "city" : "AUSTIN", "loc" : [ -97.747187, 30.505972 ], "pop" : 2516, "state" : "TX" }
+{ "_id" : "78719", "city" : "AUSTIN", "loc" : [ -97.666701, 30.180243 ], "pop" : 5368, "state" : "TX" }
+{ "_id" : "78721", "city" : "AUSTIN", "loc" : [ -97.686798, 30.272144 ], "pop" : 9091, "state" : "TX" }
+{ "_id" : "78722", "city" : "AUSTIN", "loc" : [ -97.71495, 30.289305 ], "pop" : 5588, "state" : "TX" }
+{ "_id" : "78723", "city" : "AUSTIN", "loc" : [ -97.68494099999999, 30.308515 ], "pop" : 22972, "state" : "TX" }
+{ "_id" : "78724", "city" : "AUSTIN", "loc" : [ -97.63958700000001, 30.295982 ], "pop" : 6465, "state" : "TX" }
+{ "_id" : "78725", "city" : "AUSTIN", "loc" : [ -97.624301, 30.256186 ], "pop" : 2764, "state" : "TX" }
+{ "_id" : "78726", "city" : "AUSTIN", "loc" : [ -97.832649, 30.43 ], "pop" : 871, "state" : "TX" }
+{ "_id" : "78727", "city" : "AUSTIN", "loc" : [ -97.719488, 30.425422 ], "pop" : 14276, "state" : "TX" }
+{ "_id" : "78728", "city" : "AUSTIN", "loc" : [ -97.681123, 30.441679 ], "pop" : 8051, "state" : "TX" }
+{ "_id" : "78729", "city" : "AUSTIN", "loc" : [ -97.768787, 30.45206 ], "pop" : 16611, "state" : "TX" }
+{ "_id" : "78730", "city" : "AUSTIN", "loc" : [ -97.824062, 30.360745 ], "pop" : 1021, "state" : "TX" }
+{ "_id" : "78731", "city" : "AUSTIN", "loc" : [ -97.760887, 30.347129 ], "pop" : 23276, "state" : "TX" }
+{ "_id" : "78732", "city" : "AUSTIN", "loc" : [ -97.900685, 30.375233 ], "pop" : 919, "state" : "TX" }
+{ "_id" : "78733", "city" : "AUSTIN", "loc" : [ -97.86663299999999, 30.331355 ], "pop" : 4083, "state" : "TX" }
+{ "_id" : "78734", "city" : "LAKEWAY", "loc" : [ -97.95755800000001, 30.377404 ], "pop" : 7495, "state" : "TX" }
+{ "_id" : "78735", "city" : "AUSTIN", "loc" : [ -97.84142300000001, 30.248978 ], "pop" : 3463, "state" : "TX" }
+{ "_id" : "78736", "city" : "AUSTIN", "loc" : [ -97.91596800000001, 30.244433 ], "pop" : 5812, "state" : "TX" }
+{ "_id" : "78737", "city" : "AUSTIN", "loc" : [ -97.94274900000001, 30.210692 ], "pop" : 4135, "state" : "TX" }
+{ "_id" : "78738", "city" : "AUSTIN", "loc" : [ -97.982367, 30.333708 ], "pop" : 606, "state" : "TX" }
+{ "_id" : "78739", "city" : "AUSTIN", "loc" : [ -97.878433, 30.172026 ], "pop" : 3104, "state" : "TX" }
+{ "_id" : "78741", "city" : "AUSTIN", "loc" : [ -97.722317, 30.231513 ], "pop" : 25424, "state" : "TX" }
+{ "_id" : "78742", "city" : "AUSTIN", "loc" : [ -97.670349, 30.231296 ], "pop" : 1653, "state" : "TX" }
+{ "_id" : "78744", "city" : "AUSTIN", "loc" : [ -97.74723, 30.18764 ], "pop" : 23418, "state" : "TX" }
+{ "_id" : "78745", "city" : "AUSTIN", "loc" : [ -97.795599, 30.206298 ], "pop" : 48151, "state" : "TX" }
+{ "_id" : "78746", "city" : "WEST LAKE HILLS", "loc" : [ -97.80812899999999, 30.285009 ], "pop" : 18855, "state" : "TX" }
+{ "_id" : "78747", "city" : "CREEDMOOR", "loc" : [ -97.76212700000001, 30.130235 ], "pop" : 3070, "state" : "TX" }
+{ "_id" : "78748", "city" : "AUSTIN", "loc" : [ -97.822474, 30.174311 ], "pop" : 16288, "state" : "TX" }
+{ "_id" : "78749", "city" : "AUSTIN", "loc" : [ -97.85075500000001, 30.216641 ], "pop" : 13674, "state" : "TX" }
+{ "_id" : "78750", "city" : "AUSTIN", "loc" : [ -97.79667600000001, 30.422401 ], "pop" : 8867, "state" : "TX" }
+{ "_id" : "78751", "city" : "AUSTIN", "loc" : [ -97.724163, 30.309288 ], "pop" : 12715, "state" : "TX" }
+{ "_id" : "78752", "city" : "AUSTIN", "loc" : [ -97.700394, 30.331562 ], "pop" : 13311, "state" : "TX" }
+{ "_id" : "78753", "city" : "AUSTIN", "loc" : [ -97.682658, 30.36485 ], "pop" : 26823, "state" : "TX" }
+{ "_id" : "78754", "city" : "AUSTIN", "loc" : [ -97.667267, 30.342331 ], "pop" : 2328, "state" : "TX" }
+{ "_id" : "78756", "city" : "AUSTIN", "loc" : [ -97.73903199999999, 30.322312 ], "pop" : 7525, "state" : "TX" }
+{ "_id" : "78757", "city" : "AUSTIN", "loc" : [ -97.731617, 30.343732 ], "pop" : 11723, "state" : "TX" }
+{ "_id" : "78758", "city" : "AUSTIN", "loc" : [ -97.707758, 30.376431 ], "pop" : 43246, "state" : "TX" }
+{ "_id" : "78759", "city" : "AUSTIN", "loc" : [ -97.752602, 30.403614 ], "pop" : 27479, "state" : "TX" }
+{ "_id" : "78801", "city" : "UVALDE", "loc" : [ -99.793074, 29.217238 ], "pop" : 19725, "state" : "TX" }
+{ "_id" : "78827", "city" : "ASHERTON", "loc" : [ -99.748611, 28.436421 ], "pop" : 1869, "state" : "TX" }
+{ "_id" : "78828", "city" : "BARKSDALE", "loc" : [ -100.070983, 29.708488 ], "pop" : 353, "state" : "TX" }
+{ "_id" : "78829", "city" : "BATESVILLE", "loc" : [ -99.611457, 28.928648 ], "pop" : 1512, "state" : "TX" }
+{ "_id" : "78830", "city" : "BIG WELLS", "loc" : [ -99.57808300000001, 28.569344 ], "pop" : 882, "state" : "TX" }
+{ "_id" : "78832", "city" : "BRACKETTVILLE", "loc" : [ -100.415495, 29.30963 ], "pop" : 3119, "state" : "TX" }
+{ "_id" : "78833", "city" : "CAMP WOOD", "loc" : [ -100.00838, 29.679491 ], "pop" : 1017, "state" : "TX" }
+{ "_id" : "78834", "city" : "CARRIZO SPRINGS", "loc" : [ -99.863513, 28.52779 ], "pop" : 7682, "state" : "TX" }
+{ "_id" : "78837", "city" : "COMSTOCK", "loc" : [ -101.262755, 29.74842 ], "pop" : 497, "state" : "TX" }
+{ "_id" : "78838", "city" : "CONCAN", "loc" : [ -99.68424400000001, 29.524057 ], "pop" : 201, "state" : "TX" }
+{ "_id" : "78839", "city" : "CRYSTAL CITY", "loc" : [ -99.826412, 28.686953 ], "pop" : 9130, "state" : "TX" }
+{ "_id" : "78840", "city" : "LAUGHLIN A F B", "loc" : [ -100.891555, 29.373881 ], "pop" : 38233, "state" : "TX" }
+{ "_id" : "78850", "city" : "D HANIS", "loc" : [ -99.28348800000001, 29.3398 ], "pop" : 1337, "state" : "TX" }
+{ "_id" : "78851", "city" : "DRYDEN", "loc" : [ -102.33207, 30.165108 ], "pop" : 1410, "state" : "TX" }
+{ "_id" : "78852", "city" : "EAGLE PASS", "loc" : [ -100.48176, 28.702786 ], "pop" : 35136, "state" : "TX" }
+{ "_id" : "78861", "city" : "DUNLAY", "loc" : [ -99.12763699999999, 29.356065 ], "pop" : 8114, "state" : "TX" }
+{ "_id" : "78870", "city" : "KNIPPA", "loc" : [ -99.637171, 29.291119 ], "pop" : 618, "state" : "TX" }
+{ "_id" : "78872", "city" : "LA PRYOR", "loc" : [ -99.85074, 28.948848 ], "pop" : 1520, "state" : "TX" }
+{ "_id" : "78873", "city" : "LEAKEY", "loc" : [ -99.747913, 29.768951 ], "pop" : 1142, "state" : "TX" }
+{ "_id" : "78877", "city" : "SPOFFORD", "loc" : [ -100.574181, 28.942688 ], "pop" : 1242, "state" : "TX" }
+{ "_id" : "78879", "city" : "RIO FRIO", "loc" : [ -99.77233699999999, 29.658295 ], "pop" : 253, "state" : "TX" }
+{ "_id" : "78880", "city" : "ROCKSPRINGS", "loc" : [ -100.231029, 30.018756 ], "pop" : 1904, "state" : "TX" }
+{ "_id" : "78881", "city" : "SABINAL", "loc" : [ -99.478109, 29.326668 ], "pop" : 2203, "state" : "TX" }
+{ "_id" : "78883", "city" : "TARPLEY", "loc" : [ -99.24687400000001, 29.645494 ], "pop" : 20, "state" : "TX" }
+{ "_id" : "78884", "city" : "UTOPIA", "loc" : [ -99.558454, 29.597197 ], "pop" : 593, "state" : "TX" }
+{ "_id" : "78885", "city" : "VANDERPOOL", "loc" : [ -99.555542, 29.741779 ], "pop" : 227, "state" : "TX" }
+{ "_id" : "78886", "city" : "YANCEY", "loc" : [ -99.14277, 29.140398 ], "pop" : 368, "state" : "TX" }
+{ "_id" : "78931", "city" : "BLEIBLERVILLE", "loc" : [ -96.418719, 29.967572 ], "pop" : 1226, "state" : "TX" }
+{ "_id" : "78932", "city" : "CARMINE", "loc" : [ -96.686077, 30.140351 ], "pop" : 356, "state" : "TX" }
+{ "_id" : "78933", "city" : "CAT SPRING", "loc" : [ -96.390029, 29.751204 ], "pop" : 658, "state" : "TX" }
+{ "_id" : "78934", "city" : "COLUMBUS", "loc" : [ -96.5527, 29.703247 ], "pop" : 5234, "state" : "TX" }
+{ "_id" : "78935", "city" : "ALLEYTON", "loc" : [ -96.46312, 29.745286 ], "pop" : 273, "state" : "TX" }
+{ "_id" : "78938", "city" : "ELLINGER", "loc" : [ -96.69663, 29.845915 ], "pop" : 374, "state" : "TX" }
+{ "_id" : "78940", "city" : "FAYETTEVILLE", "loc" : [ -96.646317, 29.886789 ], "pop" : 2290, "state" : "TX" }
+{ "_id" : "78941", "city" : "FLATONIA", "loc" : [ -97.098685, 29.709493 ], "pop" : 2934, "state" : "TX" }
+{ "_id" : "78942", "city" : "GIDDINGS", "loc" : [ -96.93322000000001, 30.177725 ], "pop" : 6799, "state" : "TX" }
+{ "_id" : "78944", "city" : "INDUSTRY", "loc" : [ -96.518849, 29.971789 ], "pop" : 1258, "state" : "TX" }
+{ "_id" : "78945", "city" : "LA GRANGE", "loc" : [ -96.885988, 29.903978 ], "pop" : 10019, "state" : "TX" }
+{ "_id" : "78946", "city" : "LEDBETTER", "loc" : [ -96.761276, 30.238307 ], "pop" : 806, "state" : "TX" }
+{ "_id" : "78947", "city" : "LEXINGTON", "loc" : [ -97.052387, 30.419144 ], "pop" : 3138, "state" : "TX" }
+{ "_id" : "78948", "city" : "LINCOLN", "loc" : [ -96.970159, 30.317693 ], "pop" : 1228, "state" : "TX" }
+{ "_id" : "78949", "city" : "MULDOON", "loc" : [ -97.100562, 29.799305 ], "pop" : 8, "state" : "TX" }
+{ "_id" : "78950", "city" : "NEW ULM", "loc" : [ -96.537963, 29.814248 ], "pop" : 689, "state" : "TX" }
+{ "_id" : "78953", "city" : "ROSANKY", "loc" : [ -97.311875, 29.924122 ], "pop" : 1345, "state" : "TX" }
+{ "_id" : "78954", "city" : "ROUND TOP", "loc" : [ -96.734058, 30.041131 ], "pop" : 1127, "state" : "TX" }
+{ "_id" : "78956", "city" : "SCHULENBURG", "loc" : [ -96.91056399999999, 29.688247 ], "pop" : 3703, "state" : "TX" }
+{ "_id" : "78957", "city" : "SMITHVILLE", "loc" : [ -97.149396, 30.017813 ], "pop" : 5244, "state" : "TX" }
+{ "_id" : "78959", "city" : "WAELDER", "loc" : [ -97.295798, 29.6868 ], "pop" : 1105, "state" : "TX" }
+{ "_id" : "78962", "city" : "WEIMAR", "loc" : [ -96.755045, 29.678707 ], "pop" : 3854, "state" : "TX" }
+{ "_id" : "78963", "city" : "WEST POINT", "loc" : [ -97.036129, 29.95235 ], "pop" : 58, "state" : "TX" }
+{ "_id" : "79001", "city" : "ADRIAN", "loc" : [ -102.69699, 35.275807 ], "pop" : 307, "state" : "TX" }
+{ "_id" : "79005", "city" : "BOOKER", "loc" : [ -100.523791, 36.442948 ], "pop" : 1454, "state" : "TX" }
+{ "_id" : "79007", "city" : "PHILLIPS", "loc" : [ -101.403245, 35.664299 ], "pop" : 17339, "state" : "TX" }
+{ "_id" : "79009", "city" : "BOVINA", "loc" : [ -102.806115, 34.481504 ], "pop" : 2805, "state" : "TX" }
+{ "_id" : "79011", "city" : "BRISCOE", "loc" : [ -100.167923, 35.58547 ], "pop" : 469, "state" : "TX" }
+{ "_id" : "79014", "city" : "GLAZIER", "loc" : [ -100.353875, 35.885906 ], "pop" : 3720, "state" : "TX" }
+{ "_id" : "79015", "city" : "CANYON", "loc" : [ -101.924705, 34.977222 ], "pop" : 14389, "state" : "TX" }
+{ "_id" : "79018", "city" : "CHANNING", "loc" : [ -102.334269, 35.782572 ], "pop" : 648, "state" : "TX" }
+{ "_id" : "79019", "city" : "CLAUDE", "loc" : [ -101.381271, 35.096715 ], "pop" : 1903, "state" : "TX" }
+{ "_id" : "79022", "city" : "DALHART", "loc" : [ -102.517658, 36.073183 ], "pop" : 7051, "state" : "TX" }
+{ "_id" : "79027", "city" : "DIMMITT", "loc" : [ -102.304634, 34.534089 ], "pop" : 7088, "state" : "TX" }
+{ "_id" : "79029", "city" : "DUMAS", "loc" : [ -101.967984, 35.882315 ], "pop" : 15902, "state" : "TX" }
+{ "_id" : "79031", "city" : "EARTH", "loc" : [ -102.421284, 34.241521 ], "pop" : 1704, "state" : "TX" }
+{ "_id" : "79034", "city" : "FOLLETT", "loc" : [ -100.206776, 36.430923 ], "pop" : 983, "state" : "TX" }
+{ "_id" : "79035", "city" : "BLACK", "loc" : [ -102.719139, 34.640298 ], "pop" : 4788, "state" : "TX" }
+{ "_id" : "79036", "city" : "FRITCH", "loc" : [ -101.584482, 35.644121 ], "pop" : 5073, "state" : "TX" }
+{ "_id" : "79039", "city" : "GROOM", "loc" : [ -101.12846, 35.216761 ], "pop" : 827, "state" : "TX" }
+{ "_id" : "79040", "city" : "GRUVER", "loc" : [ -101.408906, 36.286805 ], "pop" : 2053, "state" : "TX" }
+{ "_id" : "79041", "city" : "HALE CENTER", "loc" : [ -101.873623, 34.066943 ], "pop" : 3139, "state" : "TX" }
+{ "_id" : "79042", "city" : "HAPPY", "loc" : [ -101.825632, 34.721899 ], "pop" : 839, "state" : "TX" }
+{ "_id" : "79043", "city" : "HART", "loc" : [ -102.115534, 34.387838 ], "pop" : 1430, "state" : "TX" }
+{ "_id" : "79044", "city" : "HARTLEY", "loc" : [ -102.52213, 35.931122 ], "pop" : 724, "state" : "TX" }
+{ "_id" : "79045", "city" : "HEREFORD", "loc" : [ -102.40503, 34.837037 ], "pop" : 19090, "state" : "TX" }
+{ "_id" : "79046", "city" : "HIGGINS", "loc" : [ -100.095191, 36.136504 ], "pop" : 672, "state" : "TX" }
+{ "_id" : "79052", "city" : "KRESS", "loc" : [ -101.73705, 34.373703 ], "pop" : 1643, "state" : "TX" }
+{ "_id" : "79056", "city" : "LIPSCOMB", "loc" : [ -100.270164, 36.223031 ], "pop" : 34, "state" : "TX" }
+{ "_id" : "79057", "city" : "KELLERVILLE", "loc" : [ -100.611303, 35.234051 ], "pop" : 1151, "state" : "TX" }
+{ "_id" : "79059", "city" : "MIAMI", "loc" : [ -100.702715, 35.719301 ], "pop" : 1025, "state" : "TX" }
+{ "_id" : "79061", "city" : "MOBEETIE", "loc" : [ -100.424158, 35.529717 ], "pop" : 421, "state" : "TX" }
+{ "_id" : "79062", "city" : "MORSE", "loc" : [ -101.47288, 36.059579 ], "pop" : 169, "state" : "TX" }
+{ "_id" : "79063", "city" : "NAZARETH", "loc" : [ -102.106914, 34.544356 ], "pop" : 443, "state" : "TX" }
+{ "_id" : "79064", "city" : "OLTON", "loc" : [ -102.141415, 34.184418 ], "pop" : 2747, "state" : "TX" }
+{ "_id" : "79065", "city" : "PAMPA", "loc" : [ -100.957885, 35.538043 ], "pop" : 22816, "state" : "TX" }
+{ "_id" : "79068", "city" : "PANHANDLE", "loc" : [ -101.43037, 35.380841 ], "pop" : 3669, "state" : "TX" }
+{ "_id" : "79070", "city" : "PERRYTON", "loc" : [ -100.815558, 36.374825 ], "pop" : 9128, "state" : "TX" }
+{ "_id" : "79072", "city" : "PLAINVIEW", "loc" : [ -101.725896, 34.196194 ], "pop" : 27037, "state" : "TX" }
+{ "_id" : "79079", "city" : "TWITTY", "loc" : [ -100.262152, 35.220596 ], "pop" : 2927, "state" : "TX" }
+{ "_id" : "79080", "city" : "SKELLYTOWN", "loc" : [ -101.172134, 35.568489 ], "pop" : 739, "state" : "TX" }
+{ "_id" : "79081", "city" : "SPEARMAN", "loc" : [ -101.195234, 36.192689 ], "pop" : 3626, "state" : "TX" }
+{ "_id" : "79082", "city" : "SPRINGLAKE", "loc" : [ -102.308999, 34.23932 ], "pop" : 331, "state" : "TX" }
+{ "_id" : "79083", "city" : "STINNETT", "loc" : [ -101.450011, 35.837661 ], "pop" : 3277, "state" : "TX" }
+{ "_id" : "79084", "city" : "STRATFORD", "loc" : [ -101.988568, 36.33349 ], "pop" : 2858, "state" : "TX" }
+{ "_id" : "79085", "city" : "SUMMERFIELD", "loc" : [ -102.49919, 34.727244 ], "pop" : 109, "state" : "TX" }
+{ "_id" : "79086", "city" : "SUNRAY", "loc" : [ -101.812334, 36.009707 ], "pop" : 1963, "state" : "TX" }
+{ "_id" : "79087", "city" : "TEXLINE", "loc" : [ -102.984516, 36.374034 ], "pop" : 672, "state" : "TX" }
+{ "_id" : "79088", "city" : "VIGO PARK", "loc" : [ -101.762864, 34.540258 ], "pop" : 5651, "state" : "TX" }
+{ "_id" : "79092", "city" : "VEGA", "loc" : [ -102.356572, 35.373212 ], "pop" : 1738, "state" : "TX" }
+{ "_id" : "79094", "city" : "WAYSIDE", "loc" : [ -101.545434, 34.803353 ], "pop" : 118, "state" : "TX" }
+{ "_id" : "79095", "city" : "WELLINGTON", "loc" : [ -100.220721, 34.871726 ], "pop" : 3324, "state" : "TX" }
+{ "_id" : "79096", "city" : "WHEELER", "loc" : [ -100.256824, 35.431852 ], "pop" : 2062, "state" : "TX" }
+{ "_id" : "79097", "city" : "WHITE DEER", "loc" : [ -101.173993, 35.42781 ], "pop" : 1341, "state" : "TX" }
+{ "_id" : "79098", "city" : "WILDORADO", "loc" : [ -102.211754, 35.19156 ], "pop" : 296, "state" : "TX" }
+{ "_id" : "79101", "city" : "AMARILLO", "loc" : [ -101.842052, 35.203238 ], "pop" : 2355, "state" : "TX" }
+{ "_id" : "79102", "city" : "AMARILLO", "loc" : [ -101.84963, 35.199854 ], "pop" : 9091, "state" : "TX" }
+{ "_id" : "79103", "city" : "AMARILLO", "loc" : [ -101.797587, 35.175134 ], "pop" : 5336, "state" : "TX" }
+{ "_id" : "79104", "city" : "AMARILLO", "loc" : [ -101.797503, 35.193918 ], "pop" : 12468, "state" : "TX" }
+{ "_id" : "79106", "city" : "AMARILLO", "loc" : [ -101.894918, 35.197741 ], "pop" : 29728, "state" : "TX" }
+{ "_id" : "79107", "city" : "AMARILLO", "loc" : [ -101.805962, 35.230866 ], "pop" : 29593, "state" : "TX" }
+{ "_id" : "79108", "city" : "AMARILLO", "loc" : [ -101.830025, 35.277866 ], "pop" : 8461, "state" : "TX" }
+{ "_id" : "79109", "city" : "AMARILLO", "loc" : [ -101.886764, 35.166332 ], "pop" : 41676, "state" : "TX" }
+{ "_id" : "79110", "city" : "AMARILLO", "loc" : [ -101.864063, 35.154468 ], "pop" : 17159, "state" : "TX" }
+{ "_id" : "79111", "city" : "AMARILLO", "loc" : [ -101.670342, 35.228619 ], "pop" : 2194, "state" : "TX" }
+{ "_id" : "79118", "city" : "AMARILLO", "loc" : [ -101.834936, 35.07629 ], "pop" : 6981, "state" : "TX" }
+{ "_id" : "79119", "city" : "AMARILLO", "loc" : [ -101.97432, 35.064214 ], "pop" : 968, "state" : "TX" }
+{ "_id" : "79121", "city" : "AMARILLO", "loc" : [ -101.926594, 35.169689 ], "pop" : 3454, "state" : "TX" }
+{ "_id" : "79124", "city" : "AMARILLO", "loc" : [ -101.942952, 35.270269 ], "pop" : 3694, "state" : "TX" }
+{ "_id" : "79201", "city" : "KIRKLAND", "loc" : [ -100.21017, 34.428124 ], "pop" : 5862, "state" : "TX" }
+{ "_id" : "79220", "city" : "AFTON", "loc" : [ -100.802131, 33.771837 ], "pop" : 132, "state" : "TX" }
+{ "_id" : "79225", "city" : "CHILLICOTHE", "loc" : [ -99.515669, 34.243946 ], "pop" : 1186, "state" : "TX" }
+{ "_id" : "79226", "city" : "CLARENDON", "loc" : [ -100.895157, 34.952878 ], "pop" : 2884, "state" : "TX" }
+{ "_id" : "79227", "city" : "CROWELL", "loc" : [ -99.698345, 33.991208 ], "pop" : 1794, "state" : "TX" }
+{ "_id" : "79229", "city" : "DICKENS", "loc" : [ -100.819695, 33.627996 ], "pop" : 569, "state" : "TX" }
+{ "_id" : "79230", "city" : "DODSON", "loc" : [ -100.028593, 34.764354 ], "pop" : 197, "state" : "TX" }
+{ "_id" : "79232", "city" : "DUMONT", "loc" : [ -100.319829, 33.656735 ], "pop" : 344, "state" : "TX" }
+{ "_id" : "79234", "city" : "FLOMOT", "loc" : [ -101.003824, 34.232076 ], "pop" : 38, "state" : "TX" }
+{ "_id" : "79235", "city" : "FLOYDADA", "loc" : [ -101.334564, 33.974296 ], "pop" : 5075, "state" : "TX" }
+{ "_id" : "79237", "city" : "HEDLEY", "loc" : [ -100.680632, 34.869787 ], "pop" : 812, "state" : "TX" }
+{ "_id" : "79239", "city" : "LAKEVIEW", "loc" : [ -100.725921, 34.672437 ], "pop" : 358, "state" : "TX" }
+{ "_id" : "79241", "city" : "LOCKNEY", "loc" : [ -101.425934, 34.145827 ], "pop" : 3422, "state" : "TX" }
+{ "_id" : "79243", "city" : "MCADOO", "loc" : [ -100.983293, 33.741265 ], "pop" : 149, "state" : "TX" }
+{ "_id" : "79244", "city" : "MATADOR", "loc" : [ -100.836138, 34.052507 ], "pop" : 1173, "state" : "TX" }
+{ "_id" : "79245", "city" : "MEMPHIS", "loc" : [ -100.534653, 34.712237 ], "pop" : 2843, "state" : "TX" }
+{ "_id" : "79248", "city" : "CHALK", "loc" : [ -100.305917, 34.019154 ], "pop" : 2260, "state" : "TX" }
+{ "_id" : "79250", "city" : "PETERSBURG", "loc" : [ -101.604591, 33.876806 ], "pop" : 1608, "state" : "TX" }
+{ "_id" : "79251", "city" : "QUAIL", "loc" : [ -100.425243, 34.917969 ], "pop" : 73, "state" : "TX" }
+{ "_id" : "79252", "city" : "QUANAH", "loc" : [ -99.749438, 34.29555 ], "pop" : 4097, "state" : "TX" }
+{ "_id" : "79255", "city" : "QUITAQUE", "loc" : [ -101.046458, 34.379605 ], "pop" : 674, "state" : "TX" }
+{ "_id" : "79256", "city" : "ROARING SPRINGS", "loc" : [ -100.852818, 33.897669 ], "pop" : 321, "state" : "TX" }
+{ "_id" : "79257", "city" : "SILVERTON", "loc" : [ -101.316899, 34.464089 ], "pop" : 1297, "state" : "TX" }
+{ "_id" : "79259", "city" : "TELL", "loc" : [ -100.396482, 34.378164 ], "pop" : 70, "state" : "TX" }
+{ "_id" : "79260", "city" : "TRUSCOTT", "loc" : [ -99.66245499999999, 33.75323 ], "pop" : 54, "state" : "TX" }
+{ "_id" : "79261", "city" : "TURKEY", "loc" : [ -100.844875, 34.403644 ], "pop" : 704, "state" : "TX" }
+{ "_id" : "79311", "city" : "ABERNATHY", "loc" : [ -101.861111, 33.849961 ], "pop" : 3482, "state" : "TX" }
+{ "_id" : "79312", "city" : "AMHERST", "loc" : [ -102.441614, 33.997608 ], "pop" : 1266, "state" : "TX" }
+{ "_id" : "79313", "city" : "ANTON", "loc" : [ -102.165165, 33.804278 ], "pop" : 1625, "state" : "TX" }
+{ "_id" : "79316", "city" : "BROWNFIELD", "loc" : [ -102.276157, 33.169801 ], "pop" : 11954, "state" : "TX" }
+{ "_id" : "79320", "city" : "BULA", "loc" : [ -102.656426, 33.89696 ], "pop" : 113, "state" : "TX" }
+{ "_id" : "79322", "city" : "CROSBYTON", "loc" : [ -101.228733, 33.656159 ], "pop" : 2711, "state" : "TX" }
+{ "_id" : "79323", "city" : "DENVER CITY", "loc" : [ -102.831251, 32.971114 ], "pop" : 6697, "state" : "TX" }
+{ "_id" : "79324", "city" : "ENOCHS", "loc" : [ -102.764107, 33.850225 ], "pop" : 53, "state" : "TX" }
+{ "_id" : "79325", "city" : "FARWELL", "loc" : [ -102.990064, 34.386025 ], "pop" : 2270, "state" : "TX" }
+{ "_id" : "79326", "city" : "FIELDTON", "loc" : [ -102.269692, 34.091878 ], "pop" : 48, "state" : "TX" }
+{ "_id" : "79329", "city" : "IDALOU", "loc" : [ -101.678579, 33.650376 ], "pop" : 4632, "state" : "TX" }
+{ "_id" : "79331", "city" : "LAMESA", "loc" : [ -101.956914, 32.736677 ], "pop" : 12989, "state" : "TX" }
+{ "_id" : "79336", "city" : "LEVELLAND", "loc" : [ -102.367591, 33.578778 ], "pop" : 20952, "state" : "TX" }
+{ "_id" : "79339", "city" : "LITTLEFIELD", "loc" : [ -102.320697, 33.921195 ], "pop" : 7766, "state" : "TX" }
+{ "_id" : "79342", "city" : "LOOP", "loc" : [ -102.422084, 32.916169 ], "pop" : 393, "state" : "TX" }
+{ "_id" : "79343", "city" : "LORENZO", "loc" : [ -101.527736, 33.666626 ], "pop" : 1753, "state" : "TX" }
+{ "_id" : "79344", "city" : "MAPLE", "loc" : [ -102.926588, 33.8622 ], "pop" : 234, "state" : "TX" }
+{ "_id" : "79345", "city" : "MEADOW", "loc" : [ -102.249196, 33.332098 ], "pop" : 1234, "state" : "TX" }
+{ "_id" : "79346", "city" : "MORTON", "loc" : [ -102.779619, 33.715718 ], "pop" : 3569, "state" : "TX" }
+{ "_id" : "79347", "city" : "MULESHOE", "loc" : [ -102.749631, 34.219308 ], "pop" : 6664, "state" : "TX" }
+{ "_id" : "79351", "city" : "ODONNELL", "loc" : [ -101.827099, 32.977331 ], "pop" : 1381, "state" : "TX" }
+{ "_id" : "79353", "city" : "PEP", "loc" : [ -102.56558, 33.810434 ], "pop" : 66, "state" : "TX" }
+{ "_id" : "79355", "city" : "PLAINS", "loc" : [ -102.829367, 33.189354 ], "pop" : 2089, "state" : "TX" }
+{ "_id" : "79356", "city" : "POST", "loc" : [ -101.39216, 33.201695 ], "pop" : 5143, "state" : "TX" }
+{ "_id" : "79357", "city" : "CONE", "loc" : [ -101.382738, 33.678977 ], "pop" : 2840, "state" : "TX" }
+{ "_id" : "79358", "city" : "ROPESVILLE", "loc" : [ -102.15841, 33.457499 ], "pop" : 1556, "state" : "TX" }
+{ "_id" : "79359", "city" : "SEAGRAVES", "loc" : [ -102.578075, 32.93172 ], "pop" : 3307, "state" : "TX" }
+{ "_id" : "79360", "city" : "SEMINOLE", "loc" : [ -102.682761, 32.721045 ], "pop" : 10423, "state" : "TX" }
+{ "_id" : "79363", "city" : "SHALLOWATER", "loc" : [ -101.983626, 33.691859 ], "pop" : 4342, "state" : "TX" }
+{ "_id" : "79364", "city" : "RANSOM CANYON", "loc" : [ -101.65192, 33.436795 ], "pop" : 7118, "state" : "TX" }
+{ "_id" : "79366", "city" : "RANSOM CANYON", "loc" : [ -101.690805, 33.533019 ], "pop" : 1248, "state" : "TX" }
+{ "_id" : "79370", "city" : "SPUR", "loc" : [ -100.857116, 33.479016 ], "pop" : 1718, "state" : "TX" }
+{ "_id" : "79371", "city" : "SUDAN", "loc" : [ -102.525525, 34.069661 ], "pop" : 1210, "state" : "TX" }
+{ "_id" : "79373", "city" : "TAHOKA", "loc" : [ -101.821976, 33.198803 ], "pop" : 4309, "state" : "TX" }
+{ "_id" : "79376", "city" : "TOKIO", "loc" : [ -102.576753, 33.18259 ], "pop" : 30, "state" : "TX" }
+{ "_id" : "79377", "city" : "WELCH", "loc" : [ -102.106792, 32.893827 ], "pop" : 575, "state" : "TX" }
+{ "_id" : "79379", "city" : "WHITEFACE", "loc" : [ -102.638941, 33.586575 ], "pop" : 808, "state" : "TX" }
+{ "_id" : "79381", "city" : "WILSON", "loc" : [ -101.712231, 33.329862 ], "pop" : 1068, "state" : "TX" }
+{ "_id" : "79382", "city" : "WOLFFORTH", "loc" : [ -102.026101, 33.530381 ], "pop" : 3101, "state" : "TX" }
+{ "_id" : "79401", "city" : "LUBBOCK", "loc" : [ -101.860634, 33.586527 ], "pop" : 10240, "state" : "TX" }
+{ "_id" : "79403", "city" : "LUBBOCK", "loc" : [ -101.80982, 33.619573 ], "pop" : 17237, "state" : "TX" }
+{ "_id" : "79404", "city" : "LUBBOCK", "loc" : [ -101.833263, 33.525979 ], "pop" : 12158, "state" : "TX" }
+{ "_id" : "79405", "city" : "LUBBOCK", "loc" : [ -101.850655, 33.570972 ], "pop" : 2903, "state" : "TX" }
+{ "_id" : "79406", "city" : "LUBBOCK", "loc" : [ -101.877828, 33.581934 ], "pop" : 5582, "state" : "TX" }
+{ "_id" : "79407", "city" : "LUBBOCK", "loc" : [ -101.942333, 33.568369 ], "pop" : 12783, "state" : "TX" }
+{ "_id" : "79410", "city" : "LUBBOCK", "loc" : [ -101.890377, 33.56931 ], "pop" : 9955, "state" : "TX" }
+{ "_id" : "79411", "city" : "LUBBOCK", "loc" : [ -101.862593, 33.570393 ], "pop" : 4715, "state" : "TX" }
+{ "_id" : "79412", "city" : "LUBBOCK", "loc" : [ -101.857737, 33.546313 ], "pop" : 14245, "state" : "TX" }
+{ "_id" : "79413", "city" : "LUBBOCK", "loc" : [ -101.887142, 33.546597 ], "pop" : 20238, "state" : "TX" }
+{ "_id" : "79414", "city" : "LUBBOCK", "loc" : [ -101.918666, 33.549728 ], "pop" : 16893, "state" : "TX" }
+{ "_id" : "79415", "city" : "LUBBOCK", "loc" : [ -101.876015, 33.602117 ], "pop" : 13384, "state" : "TX" }
+{ "_id" : "79416", "city" : "LUBBOCK", "loc" : [ -101.936705, 33.592397 ], "pop" : 20774, "state" : "TX" }
+{ "_id" : "79423", "city" : "LUBBOCK", "loc" : [ -101.87946, 33.514604 ], "pop" : 17308, "state" : "TX" }
+{ "_id" : "79424", "city" : "LUBBOCK", "loc" : [ -101.93439, 33.515866 ], "pop" : 22873, "state" : "TX" }
+{ "_id" : "79489", "city" : "REESE AIR FORCE", "loc" : [ -102.028792, 33.594344 ], "pop" : 312, "state" : "TX" }
+{ "_id" : "79501", "city" : "ANSON", "loc" : [ -99.895301, 32.748894 ], "pop" : 3724, "state" : "TX" }
+{ "_id" : "79502", "city" : "ASPERMONT", "loc" : [ -100.234372, 33.130059 ], "pop" : 1424, "state" : "TX" }
+{ "_id" : "79503", "city" : "AVOCA", "loc" : [ -99.69642, 32.883225 ], "pop" : 248, "state" : "TX" }
+{ "_id" : "79504", "city" : "BAIRD", "loc" : [ -99.37766000000001, 32.391557 ], "pop" : 2267, "state" : "TX" }
+{ "_id" : "79506", "city" : "BLACKWELL", "loc" : [ -100.311078, 32.082044 ], "pop" : 697, "state" : "TX" }
+{ "_id" : "79510", "city" : "CLYDE", "loc" : [ -99.518445, 32.380289 ], "pop" : 7664, "state" : "TX" }
+{ "_id" : "79511", "city" : "COAHOMA", "loc" : [ -101.319681, 32.294215 ], "pop" : 2365, "state" : "TX" }
+{ "_id" : "79512", "city" : "COLORADO CITY", "loc" : [ -100.860948, 32.398736 ], "pop" : 5874, "state" : "TX" }
+{ "_id" : "79517", "city" : "FLUVANNA", "loc" : [ -101.041966, 32.781022 ], "pop" : 707, "state" : "TX" }
+{ "_id" : "79518", "city" : "GIRARD", "loc" : [ -100.693688, 33.363202 ], "pop" : 132, "state" : "TX" }
+{ "_id" : "79519", "city" : "GOLDSBORO", "loc" : [ -99.677457, 32.048213 ], "pop" : 27, "state" : "TX" }
+{ "_id" : "79520", "city" : "HAMLIN", "loc" : [ -100.128014, 32.879893 ], "pop" : 3271, "state" : "TX" }
+{ "_id" : "79521", "city" : "HASKELL", "loc" : [ -99.730923, 33.157993 ], "pop" : 3917, "state" : "TX" }
+{ "_id" : "79525", "city" : "HAWLEY", "loc" : [ -99.79599399999999, 32.594965 ], "pop" : 4405, "state" : "TX" }
+{ "_id" : "79526", "city" : "HERMLEIGH", "loc" : [ -100.754714, 32.629441 ], "pop" : 942, "state" : "TX" }
+{ "_id" : "79527", "city" : "IRA", "loc" : [ -101.025419, 32.621274 ], "pop" : 949, "state" : "TX" }
+{ "_id" : "79528", "city" : "JAYTON", "loc" : [ -100.582482, 33.251774 ], "pop" : 708, "state" : "TX" }
+{ "_id" : "79529", "city" : "KNOX CITY", "loc" : [ -99.8137, 33.418294 ], "pop" : 1751, "state" : "TX" }
+{ "_id" : "79530", "city" : "LAWN", "loc" : [ -99.73508099999999, 32.136012 ], "pop" : 619, "state" : "TX" }
+{ "_id" : "79532", "city" : "LORAINE", "loc" : [ -100.72851, 32.385047 ], "pop" : 1300, "state" : "TX" }
+{ "_id" : "79533", "city" : "LUEDERS", "loc" : [ -99.672792, 32.762339 ], "pop" : 839, "state" : "TX" }
+{ "_id" : "79534", "city" : "MC CAULLEY", "loc" : [ -100.216784, 32.778654 ], "pop" : 272, "state" : "TX" }
+{ "_id" : "79535", "city" : "MARYNEAL", "loc" : [ -100.497178, 32.202639 ], "pop" : 123, "state" : "TX" }
+{ "_id" : "79536", "city" : "MERKEL", "loc" : [ -99.99244299999999, 32.444371 ], "pop" : 4906, "state" : "TX" }
+{ "_id" : "79537", "city" : "NOLAN", "loc" : [ -100.267053, 32.279333 ], "pop" : 254, "state" : "TX" }
+{ "_id" : "79538", "city" : "NOVICE", "loc" : [ -99.59353, 32.000927 ], "pop" : 421, "state" : "TX" }
+{ "_id" : "79539", "city" : "O BRIEN", "loc" : [ -99.847303, 33.374869 ], "pop" : 314, "state" : "TX" }
+{ "_id" : "79540", "city" : "OLD GLORY", "loc" : [ -100.153155, 33.184162 ], "pop" : 431, "state" : "TX" }
+{ "_id" : "79541", "city" : "OVALO", "loc" : [ -99.822873, 32.155257 ], "pop" : 326, "state" : "TX" }
+{ "_id" : "79543", "city" : "ROBY", "loc" : [ -100.400766, 32.722016 ], "pop" : 1333, "state" : "TX" }
+{ "_id" : "79544", "city" : "ROCHESTER", "loc" : [ -99.85936599999999, 33.310457 ], "pop" : 707, "state" : "TX" }
+{ "_id" : "79545", "city" : "ROSCOE", "loc" : [ -100.539088, 32.427558 ], "pop" : 2168, "state" : "TX" }
+{ "_id" : "79546", "city" : "ROTAN", "loc" : [ -100.470489, 32.855521 ], "pop" : 2449, "state" : "TX" }
+{ "_id" : "79547", "city" : "RULE", "loc" : [ -99.889354, 33.184163 ], "pop" : 993, "state" : "TX" }
+{ "_id" : "79548", "city" : "SAGERTON", "loc" : [ -99.892329, 33.051321 ], "pop" : 351, "state" : "TX" }
+{ "_id" : "79549", "city" : "DERMOTT", "loc" : [ -100.907485, 32.715105 ], "pop" : 16206, "state" : "TX" }
+{ "_id" : "79553", "city" : "STAMFORD", "loc" : [ -99.78592999999999, 32.945323 ], "pop" : 4338, "state" : "TX" }
+{ "_id" : "79556", "city" : "SWEETWATER", "loc" : [ -100.397908, 32.472589 ], "pop" : 14064, "state" : "TX" }
+{ "_id" : "79560", "city" : "SYLVESTER", "loc" : [ -100.242497, 32.717909 ], "pop" : 240, "state" : "TX" }
+{ "_id" : "79561", "city" : "TRENT", "loc" : [ -100.119488, 32.489752 ], "pop" : 494, "state" : "TX" }
+{ "_id" : "79562", "city" : "TUSCOLA", "loc" : [ -99.82438999999999, 32.234955 ], "pop" : 2980, "state" : "TX" }
+{ "_id" : "79563", "city" : "TYE", "loc" : [ -99.86843399999999, 32.447728 ], "pop" : 903, "state" : "TX" }
+{ "_id" : "79565", "city" : "WESTBROOK", "loc" : [ -100.990719, 32.353195 ], "pop" : 842, "state" : "TX" }
+{ "_id" : "79566", "city" : "WINGATE", "loc" : [ -100.118311, 32.031777 ], "pop" : 313, "state" : "TX" }
+{ "_id" : "79567", "city" : "WINTERS", "loc" : [ -99.95511399999999, 31.962028 ], "pop" : 3876, "state" : "TX" }
+{ "_id" : "79601", "city" : "ABILENE", "loc" : [ -99.718208, 32.468155 ], "pop" : 16713, "state" : "TX" }
+{ "_id" : "79602", "city" : "ABILENE", "loc" : [ -99.721448, 32.41783 ], "pop" : 16432, "state" : "TX" }
+{ "_id" : "79603", "city" : "ABILENE", "loc" : [ -99.761916, 32.467852 ], "pop" : 24123, "state" : "TX" }
+{ "_id" : "79605", "city" : "ABILENE", "loc" : [ -99.772374, 32.431987 ], "pop" : 29862, "state" : "TX" }
+{ "_id" : "79606", "city" : "ABILENE", "loc" : [ -99.77457800000001, 32.392038 ], "pop" : 17332, "state" : "TX" }
+{ "_id" : "79607", "city" : "DYESS AFB", "loc" : [ -99.82214, 32.418956 ], "pop" : 4965, "state" : "TX" }
+{ "_id" : "79701", "city" : "MIDLAND", "loc" : [ -102.06261, 31.989636 ], "pop" : 32926, "state" : "TX" }
+{ "_id" : "79703", "city" : "MIDLAND", "loc" : [ -102.136854, 31.972106 ], "pop" : 23167, "state" : "TX" }
+{ "_id" : "79705", "city" : "MIDLAND", "loc" : [ -102.091483, 32.029473 ], "pop" : 27708, "state" : "TX" }
+{ "_id" : "79707", "city" : "MIDLAND", "loc" : [ -102.147599, 32.019911 ], "pop" : 22810, "state" : "TX" }
+{ "_id" : "79713", "city" : "ACKERLY", "loc" : [ -101.795132, 32.609085 ], "pop" : 793, "state" : "TX" }
+{ "_id" : "79714", "city" : "ANDREWS", "loc" : [ -102.540926, 32.320125 ], "pop" : 14338, "state" : "TX" }
+{ "_id" : "79718", "city" : "BALMORHEA", "loc" : [ -103.693316, 31.012361 ], "pop" : 1655, "state" : "TX" }
+{ "_id" : "79719", "city" : "BARSTOW", "loc" : [ -103.397086, 31.463908 ], "pop" : 701, "state" : "TX" }
+{ "_id" : "79720", "city" : "VEALMOOR", "loc" : [ -101.467517, 32.241767 ], "pop" : 29733, "state" : "TX" }
+{ "_id" : "79730", "city" : "COYANOSA", "loc" : [ -103.053815, 31.229547 ], "pop" : 341, "state" : "TX" }
+{ "_id" : "79731", "city" : "CRANE", "loc" : [ -102.354382, 31.396949 ], "pop" : 4652, "state" : "TX" }
+{ "_id" : "79734", "city" : "FORT DAVIS", "loc" : [ -103.936434, 30.613144 ], "pop" : 1607, "state" : "TX" }
+{ "_id" : "79735", "city" : "FORT STOCKTON", "loc" : [ -102.879942, 30.890785 ], "pop" : 11755, "state" : "TX" }
+{ "_id" : "79738", "city" : "GAIL", "loc" : [ -101.450032, 32.752334 ], "pop" : 799, "state" : "TX" }
+{ "_id" : "79739", "city" : "GARDEN CITY", "loc" : [ -101.526912, 31.849078 ], "pop" : 1447, "state" : "TX" }
+{ "_id" : "79741", "city" : "GOLDSMITH", "loc" : [ -102.625047, 31.95412 ], "pop" : 442, "state" : "TX" }
+{ "_id" : "79742", "city" : "GRANDFALLS", "loc" : [ -102.856778, 31.345856 ], "pop" : 748, "state" : "TX" }
+{ "_id" : "79743", "city" : "IMPERIAL", "loc" : [ -102.710918, 31.237264 ], "pop" : 557, "state" : "TX" }
+{ "_id" : "79744", "city" : "IRAAN", "loc" : [ -101.915175, 30.915564 ], "pop" : 1596, "state" : "TX" }
+{ "_id" : "79745", "city" : "KERMIT", "loc" : [ -103.091269, 31.85496 ], "pop" : 7370, "state" : "TX" }
+{ "_id" : "79748", "city" : "KNOTT", "loc" : [ -101.651731, 32.412489 ], "pop" : 245, "state" : "TX" }
+{ "_id" : "79749", "city" : "LENORAH", "loc" : [ -101.761137, 32.439157 ], "pop" : 529, "state" : "TX" }
+{ "_id" : "79752", "city" : "MC CAMEY", "loc" : [ -102.215325, 31.131894 ], "pop" : 2950, "state" : "TX" }
+{ "_id" : "79754", "city" : "MENTONE", "loc" : [ -103.550316, 31.738374 ], "pop" : 107, "state" : "TX" }
+{ "_id" : "79755", "city" : "MIDKIFF", "loc" : [ -101.926913, 31.306761 ], "pop" : 1497, "state" : "TX" }
+{ "_id" : "79756", "city" : "MONAHANS", "loc" : [ -102.900273, 31.581294 ], "pop" : 11296, "state" : "TX" }
+{ "_id" : "79758", "city" : "GARDENDALE", "loc" : [ -102.357237, 32.024476 ], "pop" : 1536, "state" : "TX" }
+{ "_id" : "79761", "city" : "ODESSA", "loc" : [ -102.352252, 31.857945 ], "pop" : 30126, "state" : "TX" }
+{ "_id" : "79762", "city" : "ODESSA", "loc" : [ -102.354806, 31.889029 ], "pop" : 34327, "state" : "TX" }
+{ "_id" : "79763", "city" : "ODESSA", "loc" : [ -102.416179, 31.834085 ], "pop" : 30550, "state" : "TX" }
+{ "_id" : "79764", "city" : "ODESSA", "loc" : [ -102.437465, 31.876683 ], "pop" : 17919, "state" : "TX" }
+{ "_id" : "79765", "city" : "ODESSA", "loc" : [ -102.394403, 31.937548 ], "pop" : 2240, "state" : "TX" }
+{ "_id" : "79766", "city" : "ODESSA", "loc" : [ -102.344863, 31.782683 ], "pop" : 1794, "state" : "TX" }
+{ "_id" : "79772", "city" : "VERHALEN", "loc" : [ -103.508129, 31.414384 ], "pop" : 14197, "state" : "TX" }
+{ "_id" : "79777", "city" : "PYOTE", "loc" : [ -103.139676, 31.539491 ], "pop" : 370, "state" : "TX" }
+{ "_id" : "79781", "city" : "SHEFFIELD", "loc" : [ -101.859963, 30.693549 ], "pop" : 428, "state" : "TX" }
+{ "_id" : "79782", "city" : "STANTON", "loc" : [ -101.809887, 32.139992 ], "pop" : 3776, "state" : "TX" }
+{ "_id" : "79783", "city" : "TARZAN", "loc" : [ -101.960723, 32.357523 ], "pop" : 643, "state" : "TX" }
+{ "_id" : "79789", "city" : "WINK", "loc" : [ -103.156084, 31.752673 ], "pop" : 1256, "state" : "TX" }
+{ "_id" : "79821", "city" : "ANTHONY", "loc" : [ -106.597625, 31.990718 ], "pop" : 3341, "state" : "TX" }
+{ "_id" : "79830", "city" : "ALPINE", "loc" : [ -103.654089, 30.263111 ], "pop" : 7648, "state" : "TX" }
+{ "_id" : "79834", "city" : "BIG BEND NATIONA", "loc" : [ -103.330626, 29.147657 ], "pop" : 249, "state" : "TX" }
+{ "_id" : "79835", "city" : "CANUTILLO", "loc" : [ -106.592888, 31.934379 ], "pop" : 8585, "state" : "TX" }
+{ "_id" : "79836", "city" : "CLINT", "loc" : [ -106.20383, 31.549418 ], "pop" : 17337, "state" : "TX" }
+{ "_id" : "79837", "city" : "DELL CITY", "loc" : [ -105.209902, 31.923975 ], "pop" : 915, "state" : "TX" }
+{ "_id" : "79839", "city" : "FORT HANCOCK", "loc" : [ -105.823448, 31.296887 ], "pop" : 1108, "state" : "TX" }
+{ "_id" : "79842", "city" : "MARATHON", "loc" : [ -103.221397, 30.18858 ], "pop" : 725, "state" : "TX" }
+{ "_id" : "79843", "city" : "MARFA", "loc" : [ -104.084835, 30.292982 ], "pop" : 3155, "state" : "TX" }
+{ "_id" : "79845", "city" : "PRESIDIO", "loc" : [ -104.35511, 29.557302 ], "pop" : 3482, "state" : "TX" }
+{ "_id" : "79847", "city" : "SALT FLAT", "loc" : [ -104.611467, 31.359027 ], "pop" : 317, "state" : "TX" }
+{ "_id" : "79851", "city" : "SIERRA BLANCA", "loc" : [ -105.321874, 31.193821 ], "pop" : 892, "state" : "TX" }
+{ "_id" : "79852", "city" : "TERLINGUA", "loc" : [ -103.559671, 29.31648 ], "pop" : 59, "state" : "TX" }
+{ "_id" : "79854", "city" : "VALENTINE", "loc" : [ -104.481096, 30.620043 ], "pop" : 339, "state" : "TX" }
+{ "_id" : "79855", "city" : "KENT", "loc" : [ -104.832249, 31.042879 ], "pop" : 3090, "state" : "TX" }
+{ "_id" : "79901", "city" : "EL PASO", "loc" : [ -106.478311, 31.758411 ], "pop" : 17467, "state" : "TX" }
+{ "_id" : "79902", "city" : "EL PASO", "loc" : [ -106.493165, 31.776317 ], "pop" : 26404, "state" : "TX" }
+{ "_id" : "79903", "city" : "EL PASO", "loc" : [ -106.440569, 31.786213 ], "pop" : 20768, "state" : "TX" }
+{ "_id" : "79904", "city" : "EL PASO", "loc" : [ -106.438135, 31.853334 ], "pop" : 35732, "state" : "TX" }
+{ "_id" : "79905", "city" : "EL PASO", "loc" : [ -106.430445, 31.767447 ], "pop" : 32865, "state" : "TX" }
+{ "_id" : "79906", "city" : "FORT BLISS", "loc" : [ -106.421611, 31.807631 ], "pop" : 11364, "state" : "TX" }
+{ "_id" : "79907", "city" : "EL PASO", "loc" : [ -106.329281, 31.708908 ], "pop" : 58052, "state" : "TX" }
+{ "_id" : "79908", "city" : "FORT BLISS", "loc" : [ -106.386711, 31.82753 ], "pop" : 2918, "state" : "TX" }
+{ "_id" : "79912", "city" : "EL PASO", "loc" : [ -106.536433, 31.838309 ], "pop" : 46537, "state" : "TX" }
+{ "_id" : "79915", "city" : "EL PASO", "loc" : [ -106.368605, 31.743234 ], "pop" : 46356, "state" : "TX" }
+{ "_id" : "79916", "city" : "FORT BLISS", "loc" : [ -106.159157, 31.794873 ], "pop" : 6703, "state" : "TX" }
+{ "_id" : "79922", "city" : "EL PASO", "loc" : [ -106.573176, 31.821767 ], "pop" : 8540, "state" : "TX" }
+{ "_id" : "79924", "city" : "EL PASO", "loc" : [ -106.414857, 31.902098 ], "pop" : 57215, "state" : "TX" }
+{ "_id" : "79925", "city" : "EL PASO", "loc" : [ -106.361317, 31.781402 ], "pop" : 41235, "state" : "TX" }
+{ "_id" : "79927", "city" : "HORIZON CITY", "loc" : [ -106.273064, 31.653014 ], "pop" : 30011, "state" : "TX" }
+{ "_id" : "79930", "city" : "EL PASO", "loc" : [ -106.456754, 31.804795 ], "pop" : 29792, "state" : "TX" }
+{ "_id" : "79932", "city" : "EL PASO", "loc" : [ -106.593186, 31.862334 ], "pop" : 14909, "state" : "TX" }
+{ "_id" : "79934", "city" : "EL PASO", "loc" : [ -106.407328, 31.938585 ], "pop" : 2983, "state" : "TX" }
+{ "_id" : "79935", "city" : "EL PASO", "loc" : [ -106.330258, 31.771847 ], "pop" : 20465, "state" : "TX" }
+{ "_id" : "79936", "city" : "EL PASO", "loc" : [ -106.30159, 31.767655 ], "pop" : 52031, "state" : "TX" }
+{ "_id" : "80002", "city" : "ARVADA", "loc" : [ -105.098402, 39.794533 ], "pop" : 12065, "state" : "CO" }
+{ "_id" : "80003", "city" : "ARVADA", "loc" : [ -105.065549, 39.828572 ], "pop" : 32980, "state" : "CO" }
+{ "_id" : "80004", "city" : "ARVADA", "loc" : [ -105.11771, 39.814066 ], "pop" : 33260, "state" : "CO" }
+{ "_id" : "80005", "city" : "ARVADA", "loc" : [ -105.109719, 39.842189 ], "pop" : 22613, "state" : "CO" }
+{ "_id" : "80010", "city" : "AURORA", "loc" : [ -104.864618, 39.736788 ], "pop" : 27090, "state" : "CO" }
+{ "_id" : "80011", "city" : "AURORA", "loc" : [ -104.815233, 39.737809 ], "pop" : 36021, "state" : "CO" }
+{ "_id" : "80012", "city" : "AURORA", "loc" : [ -104.837693, 39.698672 ], "pop" : 37711, "state" : "CO" }
+{ "_id" : "80013", "city" : "AURORA", "loc" : [ -104.784566, 39.657457 ], "pop" : 45335, "state" : "CO" }
+{ "_id" : "80014", "city" : "AURORA", "loc" : [ -104.834954, 39.666171 ], "pop" : 31059, "state" : "CO" }
+{ "_id" : "80015", "city" : "AURORA", "loc" : [ -104.787438, 39.62552 ], "pop" : 28161, "state" : "CO" }
+{ "_id" : "80016", "city" : "AURORA", "loc" : [ -104.741734, 39.618713 ], "pop" : 4085, "state" : "CO" }
+{ "_id" : "80017", "city" : "AURORA", "loc" : [ -104.788093, 39.694827 ], "pop" : 25910, "state" : "CO" }
+{ "_id" : "80018", "city" : "AURORA", "loc" : [ -104.707102, 39.710179 ], "pop" : 321, "state" : "CO" }
+{ "_id" : "80019", "city" : "AURORA", "loc" : [ -104.706906, 39.765608 ], "pop" : 46, "state" : "CO" }
+{ "_id" : "80020", "city" : "BROOMFIELD", "loc" : [ -105.060902, 39.924513 ], "pop" : 31533, "state" : "CO" }
+{ "_id" : "80021", "city" : "WESTMINSTER", "loc" : [ -105.102837, 39.875996 ], "pop" : 20461, "state" : "CO" }
+{ "_id" : "80022", "city" : "COMMERCE CITY", "loc" : [ -104.911349, 39.825875 ], "pop" : 23205, "state" : "CO" }
+{ "_id" : "80026", "city" : "LAFAYETTE", "loc" : [ -105.096346, 39.997964 ], "pop" : 17111, "state" : "CO" }
+{ "_id" : "80027", "city" : "LOUISVILLE", "loc" : [ -105.145557, 39.978942 ], "pop" : 12612, "state" : "CO" }
+{ "_id" : "80030", "city" : "WESTMINSTER", "loc" : [ -105.037086, 39.854238 ], "pop" : 43235, "state" : "CO" }
+{ "_id" : "80033", "city" : "WHEAT RIDGE", "loc" : [ -105.096195, 39.774036 ], "pop" : 23040, "state" : "CO" }
+{ "_id" : "80045", "city" : "AURORA", "loc" : [ -104.837954, 39.748014 ], "pop" : 1715, "state" : "CO" }
+{ "_id" : "80101", "city" : "AGATE", "loc" : [ -103.984575, 39.420256 ], "pop" : 230, "state" : "CO" }
+{ "_id" : "80102", "city" : "BENNETT", "loc" : [ -104.427284, 39.725398 ], "pop" : 3885, "state" : "CO" }
+{ "_id" : "80103", "city" : "BYERS", "loc" : [ -104.201872, 39.698454 ], "pop" : 1448, "state" : "CO" }
+{ "_id" : "80104", "city" : "CASTLE ROCK", "loc" : [ -104.860187, 39.39256 ], "pop" : 11763, "state" : "CO" }
+{ "_id" : "80105", "city" : "DEER TRAIL", "loc" : [ -104.068003, 39.593121 ], "pop" : 634, "state" : "CO" }
+{ "_id" : "80106", "city" : "ELBERT", "loc" : [ -104.574631, 39.096892 ], "pop" : 1808, "state" : "CO" }
+{ "_id" : "80107", "city" : "ELIZABETH", "loc" : [ -104.591961, 39.383618 ], "pop" : 4973, "state" : "CO" }
+{ "_id" : "80110", "city" : "CHERRY HILLS VIL", "loc" : [ -104.990022, 39.646027 ], "pop" : 40226, "state" : "CO" }
+{ "_id" : "80111", "city" : "CHERRY HILLS VIL", "loc" : [ -104.882832, 39.610327 ], "pop" : 20230, "state" : "CO" }
+{ "_id" : "80112", "city" : "ENGLEWOOD", "loc" : [ -104.901115, 39.58051 ], "pop" : 20210, "state" : "CO" }
+{ "_id" : "80116", "city" : "FRANKTOWN", "loc" : [ -104.725569, 39.372841 ], "pop" : 3742, "state" : "CO" }
+{ "_id" : "80117", "city" : "KIOWA", "loc" : [ -104.452263, 39.323972 ], "pop" : 680, "state" : "CO" }
+{ "_id" : "80118", "city" : "LARKSPUR", "loc" : [ -104.854587, 39.201079 ], "pop" : 1424, "state" : "CO" }
+{ "_id" : "80120", "city" : "LITTLETON", "loc" : [ -105.0044, 39.599426 ], "pop" : 24992, "state" : "CO" }
+{ "_id" : "80121", "city" : "GREENWOOD VILLAG", "loc" : [ -104.957285, 39.605835 ], "pop" : 17238, "state" : "CO" }
+{ "_id" : "80122", "city" : "LITTLETON", "loc" : [ -104.955673, 39.581418 ], "pop" : 31135, "state" : "CO" }
+{ "_id" : "80123", "city" : "BOW MAR", "loc" : [ -105.07766, 39.596854 ], "pop" : 59418, "state" : "CO" }
+{ "_id" : "80124", "city" : "LITTLETON", "loc" : [ -104.897204, 39.55061 ], "pop" : 5393, "state" : "CO" }
+{ "_id" : "80125", "city" : "LITTLETON", "loc" : [ -105.056098, 39.484466 ], "pop" : 3230, "state" : "CO" }
+{ "_id" : "80126", "city" : "HIGHLANDS RANCH", "loc" : [ -104.963751, 39.55134 ], "pop" : 13649, "state" : "CO" }
+{ "_id" : "80127", "city" : "LITTLETON", "loc" : [ -105.132811, 39.591968 ], "pop" : 23204, "state" : "CO" }
+{ "_id" : "80132", "city" : "MONUMENT", "loc" : [ -104.85416, 39.100726 ], "pop" : 7411, "state" : "CO" }
+{ "_id" : "80133", "city" : "PALMER LAKE", "loc" : [ -104.914795, 39.120498 ], "pop" : 1237, "state" : "CO" }
+{ "_id" : "80134", "city" : "PARKER", "loc" : [ -104.734904, 39.505466 ], "pop" : 19466, "state" : "CO" }
+{ "_id" : "80135", "city" : "DECKERS", "loc" : [ -105.008305, 39.330109 ], "pop" : 3257, "state" : "CO" }
+{ "_id" : "80136", "city" : "STRASBURG", "loc" : [ -104.268258, 39.781359 ], "pop" : 1197, "state" : "CO" }
+{ "_id" : "80137", "city" : "WATKINS", "loc" : [ -104.583391, 39.762317 ], "pop" : 406, "state" : "CO" }
+{ "_id" : "80202", "city" : "DENVER", "loc" : [ -104.994591, 39.749107 ], "pop" : 2816, "state" : "CO" }
+{ "_id" : "80203", "city" : "DENVER", "loc" : [ -104.981111, 39.731285 ], "pop" : 15775, "state" : "CO" }
+{ "_id" : "80204", "city" : "DENVER", "loc" : [ -105.025854, 39.734022 ], "pop" : 27439, "state" : "CO" }
+{ "_id" : "80205", "city" : "DENVER", "loc" : [ -104.966141, 39.758993 ], "pop" : 24169, "state" : "CO" }
+{ "_id" : "80206", "city" : "DENVER", "loc" : [ -104.9524, 39.733109 ], "pop" : 19145, "state" : "CO" }
+{ "_id" : "80207", "city" : "DENVER", "loc" : [ -104.91771, 39.758425 ], "pop" : 20955, "state" : "CO" }
+{ "_id" : "80209", "city" : "DENVER", "loc" : [ -104.968587, 39.707437 ], "pop" : 19691, "state" : "CO" }
+{ "_id" : "80210", "city" : "DENVER", "loc" : [ -104.963124, 39.679003 ], "pop" : 30868, "state" : "CO" }
+{ "_id" : "80211", "city" : "DENVER", "loc" : [ -105.020377, 39.766515 ], "pop" : 34679, "state" : "CO" }
+{ "_id" : "80212", "city" : "MOUNTAIN VIEW", "loc" : [ -105.046979, 39.772396 ], "pop" : 17745, "state" : "CO" }
+{ "_id" : "80214", "city" : "EDGEWATER", "loc" : [ -105.062036, 39.746931 ], "pop" : 13154, "state" : "CO" }
+{ "_id" : "80215", "city" : "LAKEWOOD", "loc" : [ -105.102329, 39.744033 ], "pop" : 27556, "state" : "CO" }
+{ "_id" : "80216", "city" : "DENVER", "loc" : [ -104.966946, 39.783469 ], "pop" : 9113, "state" : "CO" }
+{ "_id" : "80218", "city" : "DENVER", "loc" : [ -104.971652, 39.732747 ], "pop" : 14916, "state" : "CO" }
+{ "_id" : "80219", "city" : "DENVER", "loc" : [ -105.034134, 39.695624 ], "pop" : 48234, "state" : "CO" }
+{ "_id" : "80220", "city" : "DENVER", "loc" : [ -104.912866, 39.7312 ], "pop" : 35520, "state" : "CO" }
+{ "_id" : "80221", "city" : "FEDERAL HEIGHTS", "loc" : [ -105.007985, 39.840562 ], "pop" : 54069, "state" : "CO" }
+{ "_id" : "80222", "city" : "GLENDALE", "loc" : [ -104.927992, 39.682803 ], "pop" : 28373, "state" : "CO" }
+{ "_id" : "80223", "city" : "DENVER", "loc" : [ -105.002799, 39.700239 ], "pop" : 16692, "state" : "CO" }
+{ "_id" : "80224", "city" : "DENVER", "loc" : [ -104.910778, 39.687995 ], "pop" : 14918, "state" : "CO" }
+{ "_id" : "80226", "city" : "LAKEWOOD", "loc" : [ -105.066703, 39.712186 ], "pop" : 13675, "state" : "CO" }
+{ "_id" : "80227", "city" : "DENVER", "loc" : [ -105.085359, 39.666746 ], "pop" : 26932, "state" : "CO" }
+{ "_id" : "80228", "city" : "LAKEWOOD", "loc" : [ -105.143009, 39.696898 ], "pop" : 25008, "state" : "CO" }
+{ "_id" : "80229", "city" : "THORNTON", "loc" : [ -104.961749, 39.860998 ], "pop" : 33512, "state" : "CO" }
+{ "_id" : "80231", "city" : "DENVER", "loc" : [ -104.884326, 39.679324 ], "pop" : 35985, "state" : "CO" }
+{ "_id" : "80232", "city" : "LAKEWOOD", "loc" : [ -105.094524, 39.697282 ], "pop" : 35087, "state" : "CO" }
+{ "_id" : "80233", "city" : "NORTHGLENN", "loc" : [ -104.958257, 39.901222 ], "pop" : 30749, "state" : "CO" }
+{ "_id" : "80234", "city" : "NORTHGLENN", "loc" : [ -105.004474, 39.905479 ], "pop" : 13350, "state" : "CO" }
+{ "_id" : "80235", "city" : "DENVER", "loc" : [ -105.079466, 39.647175 ], "pop" : 5783, "state" : "CO" }
+{ "_id" : "80236", "city" : "DENVER", "loc" : [ -105.037595, 39.653535 ], "pop" : 12979, "state" : "CO" }
+{ "_id" : "80237", "city" : "DENVER", "loc" : [ -104.89866, 39.64314 ], "pop" : 14211, "state" : "CO" }
+{ "_id" : "80239", "city" : "DENVER", "loc" : [ -104.828837, 39.787757 ], "pop" : 17622, "state" : "CO" }
+{ "_id" : "80241", "city" : "NORTHGLENN", "loc" : [ -104.941809, 39.927792 ], "pop" : 10108, "state" : "CO" }
+{ "_id" : "80249", "city" : "DENVER", "loc" : [ -104.75565, 39.778264 ], "pop" : 2740, "state" : "CO" }
+{ "_id" : "80301", "city" : "BOULDER", "loc" : [ -105.21426, 40.049733 ], "pop" : 18174, "state" : "CO" }
+{ "_id" : "80302", "city" : "BOULDER", "loc" : [ -105.285131, 40.017235 ], "pop" : 29384, "state" : "CO" }
+{ "_id" : "80303", "city" : "BOULDER", "loc" : [ -105.239178, 39.991381 ], "pop" : 39860, "state" : "CO" }
+{ "_id" : "80304", "city" : "BOULDER", "loc" : [ -105.277073, 40.037482 ], "pop" : 21550, "state" : "CO" }
+{ "_id" : "80401", "city" : "GOLDEN", "loc" : [ -105.191528, 39.730548 ], "pop" : 32876, "state" : "CO" }
+{ "_id" : "80403", "city" : "GOLDEN", "loc" : [ -105.282516, 39.823219 ], "pop" : 13159, "state" : "CO" }
+{ "_id" : "80421", "city" : "BAILEY", "loc" : [ -105.469282, 39.448233 ], "pop" : 4448, "state" : "CO" }
+{ "_id" : "80422", "city" : "BLACK HAWK", "loc" : [ -105.503991, 39.801105 ], "pop" : 551, "state" : "CO" }
+{ "_id" : "80423", "city" : "BOND", "loc" : [ -106.676273, 39.869119 ], "pop" : 149, "state" : "CO" }
+{ "_id" : "80428", "city" : "CLARK", "loc" : [ -106.921482, 40.726783 ], "pop" : 455, "state" : "CO" }
+{ "_id" : "80429", "city" : "CLIMAX", "loc" : [ -106.258027, 39.298804 ], "pop" : 346, "state" : "CO" }
+{ "_id" : "80430", "city" : "COALMONT", "loc" : [ -106.532134, 40.538252 ], "pop" : 88, "state" : "CO" }
+{ "_id" : "80433", "city" : "CONIFER", "loc" : [ -105.316873, 39.519735 ], "pop" : 5919, "state" : "CO" }
+{ "_id" : "80435", "city" : "KEYSTONE", "loc" : [ -106.057345, 39.574827 ], "pop" : 12881, "state" : "CO" }
+{ "_id" : "80439", "city" : "EVERGREEN", "loc" : [ -105.340248, 39.637405 ], "pop" : 19250, "state" : "CO" }
+{ "_id" : "80440", "city" : "FAIRPLAY", "loc" : [ -105.999416, 39.225617 ], "pop" : 1030, "state" : "CO" }
+{ "_id" : "80441", "city" : "FOXTON", "loc" : [ -105.24815, 39.372056 ], "pop" : 127, "state" : "CO" }
+{ "_id" : "80446", "city" : "GRANBY", "loc" : [ -105.889916, 40.012834 ], "pop" : 4839, "state" : "CO" }
+{ "_id" : "80447", "city" : "GRAND LAKE", "loc" : [ -105.860488, 40.228862 ], "pop" : 1202, "state" : "CO" }
+{ "_id" : "80452", "city" : "IDAHO SPRINGS", "loc" : [ -105.598261, 39.740192 ], "pop" : 5113, "state" : "CO" }
+{ "_id" : "80455", "city" : "JAMESTOWN", "loc" : [ -105.418971, 40.10056 ], "pop" : 654, "state" : "CO" }
+{ "_id" : "80456", "city" : "JEFFERSON", "loc" : [ -105.78633, 39.300926 ], "pop" : 157, "state" : "CO" }
+{ "_id" : "80459", "city" : "KREMMLING", "loc" : [ -106.395472, 40.063224 ], "pop" : 1580, "state" : "CO" }
+{ "_id" : "80461", "city" : "LEADVILLE", "loc" : [ -106.301545, 39.249742 ], "pop" : 5544, "state" : "CO" }
+{ "_id" : "80463", "city" : "MC COY", "loc" : [ -106.730906, 39.913377 ], "pop" : 61, "state" : "CO" }
+{ "_id" : "80465", "city" : "MORRISON", "loc" : [ -105.174641, 39.612452 ], "pop" : 13657, "state" : "CO" }
+{ "_id" : "80466", "city" : "NEDERLAND", "loc" : [ -105.481265, 39.970259 ], "pop" : 2621, "state" : "CO" }
+{ "_id" : "80467", "city" : "OAK CREEK", "loc" : [ -106.929621, 40.256733 ], "pop" : 1135, "state" : "CO" }
+{ "_id" : "80468", "city" : "PARSHALL", "loc" : [ -106.225492, 40.053765 ], "pop" : 345, "state" : "CO" }
+{ "_id" : "80470", "city" : "PINE", "loc" : [ -105.374116, 39.46667 ], "pop" : 2827, "state" : "CO" }
+{ "_id" : "80471", "city" : "PINECLIFFE", "loc" : [ -105.354004, 39.942898 ], "pop" : 225, "state" : "CO" }
+{ "_id" : "80474", "city" : "ROLLINSVILLE", "loc" : [ -105.472596, 39.910757 ], "pop" : 343, "state" : "CO" }
+{ "_id" : "80479", "city" : "TOPONAS", "loc" : [ -106.908172, 40.119601 ], "pop" : 697, "state" : "CO" }
+{ "_id" : "80480", "city" : "WALDEN", "loc" : [ -106.276728, 40.709978 ], "pop" : 1517, "state" : "CO" }
+{ "_id" : "80481", "city" : "WARD", "loc" : [ -105.508023, 40.072572 ], "pop" : 159, "state" : "CO" }
+{ "_id" : "80487", "city" : "STEAMBOAT SPRING", "loc" : [ -106.8457, 40.474124 ], "pop" : 9773, "state" : "CO" }
+{ "_id" : "80501", "city" : "LONGMONT", "loc" : [ -105.10095, 40.177921 ], "pop" : 47166, "state" : "CO" }
+{ "_id" : "80503", "city" : "LONGMONT", "loc" : [ -105.162432, 40.15588 ], "pop" : 16814, "state" : "CO" }
+{ "_id" : "80504", "city" : "LONGMONT", "loc" : [ -104.950446, 40.130615 ], "pop" : 3716, "state" : "CO" }
+{ "_id" : "80510", "city" : "ALLENSPARK", "loc" : [ -105.520064, 40.226775 ], "pop" : 183, "state" : "CO" }
+{ "_id" : "80512", "city" : "BELLVUE", "loc" : [ -105.260977, 40.626528 ], "pop" : 1982, "state" : "CO" }
+{ "_id" : "80513", "city" : "BERTHOUD", "loc" : [ -105.105459, 40.299333 ], "pop" : 6886, "state" : "CO" }
+{ "_id" : "80514", "city" : "DACONO", "loc" : [ -104.929705, 40.08361 ], "pop" : 2223, "state" : "CO" }
+{ "_id" : "80515", "city" : "DRAKE", "loc" : [ -105.296925, 40.443257 ], "pop" : 721, "state" : "CO" }
+{ "_id" : "80516", "city" : "ERIE", "loc" : [ -105.068583, 40.059746 ], "pop" : 304, "state" : "CO" }
+{ "_id" : "80517", "city" : "ESTES PARK", "loc" : [ -105.514163, 40.365761 ], "pop" : 6428, "state" : "CO" }
+{ "_id" : "80521", "city" : "FORT COLLINS", "loc" : [ -105.103884, 40.581293 ], "pop" : 30059, "state" : "CO" }
+{ "_id" : "80524", "city" : "FORT COLLINS", "loc" : [ -105.05811, 40.59865 ], "pop" : 21204, "state" : "CO" }
+{ "_id" : "80525", "city" : "FORT COLLINS", "loc" : [ -105.054715, 40.538354 ], "pop" : 31263, "state" : "CO" }
+{ "_id" : "80526", "city" : "FORT COLLINS", "loc" : [ -105.107646, 40.547294 ], "pop" : 29180, "state" : "CO" }
+{ "_id" : "80534", "city" : "JOHNSTOWN", "loc" : [ -104.923558, 40.335526 ], "pop" : 2601, "state" : "CO" }
+{ "_id" : "80535", "city" : "LAPORTE", "loc" : [ -105.148757, 40.634683 ], "pop" : 2300, "state" : "CO" }
+{ "_id" : "80536", "city" : "VIRGINIA DALE", "loc" : [ -105.367745, 40.779878 ], "pop" : 513, "state" : "CO" }
+{ "_id" : "80537", "city" : "LOVELAND", "loc" : [ -105.09164, 40.384917 ], "pop" : 24502, "state" : "CO" }
+{ "_id" : "80538", "city" : "LOVELAND", "loc" : [ -105.089985, 40.426239 ], "pop" : 26449, "state" : "CO" }
+{ "_id" : "80540", "city" : "LYONS", "loc" : [ -105.323071, 40.235715 ], "pop" : 3696, "state" : "CO" }
+{ "_id" : "80543", "city" : "MILLIKEN", "loc" : [ -104.876137, 40.310656 ], "pop" : 2632, "state" : "CO" }
+{ "_id" : "80545", "city" : "RED FEATHER LAKE", "loc" : [ -105.624455, 40.796451 ], "pop" : 440, "state" : "CO" }
+{ "_id" : "80549", "city" : "WELLINGTON", "loc" : [ -105.031844, 40.725525 ], "pop" : 3309, "state" : "CO" }
+{ "_id" : "80550", "city" : "WINDSOR", "loc" : [ -104.899442, 40.483663 ], "pop" : 6724, "state" : "CO" }
+{ "_id" : "80601", "city" : "LOCHBUI", "loc" : [ -104.810278, 39.980553 ], "pop" : 20533, "state" : "CO" }
+{ "_id" : "80610", "city" : "AULT", "loc" : [ -104.735629, 40.593772 ], "pop" : 2684, "state" : "CO" }
+{ "_id" : "80611", "city" : "BRIGGSDALE", "loc" : [ -104.28707, 40.639192 ], "pop" : 259, "state" : "CO" }
+{ "_id" : "80612", "city" : "CARR", "loc" : [ -104.885865, 40.866551 ], "pop" : 94, "state" : "CO" }
+{ "_id" : "80615", "city" : "EATON", "loc" : [ -104.714559, 40.527272 ], "pop" : 2902, "state" : "CO" }
+{ "_id" : "80620", "city" : "EVANS", "loc" : [ -104.697095, 40.380255 ], "pop" : 6262, "state" : "CO" }
+{ "_id" : "80621", "city" : "WATTENBURG", "loc" : [ -104.865639, 40.078876 ], "pop" : 12913, "state" : "CO" }
+{ "_id" : "80622", "city" : "GALETON", "loc" : [ -104.597254, 40.515034 ], "pop" : 360, "state" : "CO" }
+{ "_id" : "80624", "city" : "GILL", "loc" : [ -104.499995, 40.469586 ], "pop" : 130, "state" : "CO" }
+{ "_id" : "80631", "city" : "GARDEN CITY", "loc" : [ -104.704756, 40.413968 ], "pop" : 53905, "state" : "CO" }
+{ "_id" : "80634", "city" : "GREELEY", "loc" : [ -104.754113, 40.410947 ], "pop" : 14100, "state" : "CO" }
+{ "_id" : "80640", "city" : "HENDERSON", "loc" : [ -104.871834, 39.898304 ], "pop" : 1388, "state" : "CO" }
+{ "_id" : "80642", "city" : "HUDSON", "loc" : [ -104.653208, 40.060555 ], "pop" : 2369, "state" : "CO" }
+{ "_id" : "80643", "city" : "KEENESBURG", "loc" : [ -104.446366, 40.095847 ], "pop" : 1979, "state" : "CO" }
+{ "_id" : "80644", "city" : "KERSEY", "loc" : [ -104.528768, 40.396305 ], "pop" : 2843, "state" : "CO" }
+{ "_id" : "80645", "city" : "LA SALLE", "loc" : [ -104.726784, 40.321138 ], "pop" : 4455, "state" : "CO" }
+{ "_id" : "80648", "city" : "NUNN", "loc" : [ -104.785012, 40.726483 ], "pop" : 505, "state" : "CO" }
+{ "_id" : "80649", "city" : "ORCHARD", "loc" : [ -104.097325, 40.363946 ], "pop" : 277, "state" : "CO" }
+{ "_id" : "80650", "city" : "PIERCE", "loc" : [ -104.763764, 40.635911 ], "pop" : 1020, "state" : "CO" }
+{ "_id" : "80651", "city" : "PLATTEVILLE", "loc" : [ -104.802776, 40.213121 ], "pop" : 2577, "state" : "CO" }
+{ "_id" : "80652", "city" : "ROGGEN", "loc" : [ -104.315747, 40.207445 ], "pop" : 150, "state" : "CO" }
+{ "_id" : "80653", "city" : "WELDONA", "loc" : [ -103.967755, 40.368093 ], "pop" : 328, "state" : "CO" }
+{ "_id" : "80654", "city" : "HOYT", "loc" : [ -104.052814, 40.205651 ], "pop" : 1746, "state" : "CO" }
+{ "_id" : "80701", "city" : "FORT MORGAN", "loc" : [ -103.803119, 40.254084 ], "pop" : 13263, "state" : "CO" }
+{ "_id" : "80720", "city" : "AKRON", "loc" : [ -103.225885, 40.180315 ], "pop" : 2559, "state" : "CO" }
+{ "_id" : "80721", "city" : "AMHERST", "loc" : [ -102.170567, 40.682386 ], "pop" : 86, "state" : "CO" }
+{ "_id" : "80722", "city" : "ATWOOD", "loc" : [ -103.039301, 40.517432 ], "pop" : 140, "state" : "CO" }
+{ "_id" : "80723", "city" : "BRUSH", "loc" : [ -103.62788, 40.260255 ], "pop" : 5603, "state" : "CO" }
+{ "_id" : "80726", "city" : "CROOK", "loc" : [ -102.847174, 40.874743 ], "pop" : 638, "state" : "CO" }
+{ "_id" : "80727", "city" : "ECKLEY", "loc" : [ -102.482776, 40.113775 ], "pop" : 242, "state" : "CO" }
+{ "_id" : "80728", "city" : "FLEMING", "loc" : [ -102.868821, 40.637019 ], "pop" : 853, "state" : "CO" }
+{ "_id" : "80729", "city" : "GROVER", "loc" : [ -104.234613, 40.871635 ], "pop" : 492, "state" : "CO" }
+{ "_id" : "80731", "city" : "HAXTUN", "loc" : [ -102.605175, 40.640587 ], "pop" : 1569, "state" : "CO" }
+{ "_id" : "80733", "city" : "HILLROSE", "loc" : [ -103.541816, 40.307186 ], "pop" : 516, "state" : "CO" }
+{ "_id" : "80734", "city" : "HOLYOKE", "loc" : [ -102.282545, 40.582542 ], "pop" : 2642, "state" : "CO" }
+{ "_id" : "80735", "city" : "HALE", "loc" : [ -102.211563, 39.733147 ], "pop" : 393, "state" : "CO" }
+{ "_id" : "80736", "city" : "ILIFF", "loc" : [ -103.096808, 40.769174 ], "pop" : 778, "state" : "CO" }
+{ "_id" : "80737", "city" : "JULESBURG", "loc" : [ -102.257501, 40.97083 ], "pop" : 1712, "state" : "CO" }
+{ "_id" : "80740", "city" : "LINDON", "loc" : [ -103.314471, 39.830849 ], "pop" : 136, "state" : "CO" }
+{ "_id" : "80741", "city" : "WILLARD", "loc" : [ -103.34471, 40.511548 ], "pop" : 959, "state" : "CO" }
+{ "_id" : "80742", "city" : "NEW RAYMER", "loc" : [ -103.838982, 40.685079 ], "pop" : 310, "state" : "CO" }
+{ "_id" : "80743", "city" : "OTIS", "loc" : [ -102.939219, 40.202989 ], "pop" : 1102, "state" : "CO" }
+{ "_id" : "80744", "city" : "OVID", "loc" : [ -102.387396, 40.945865 ], "pop" : 563, "state" : "CO" }
+{ "_id" : "80745", "city" : "PADRONI", "loc" : [ -103.358163, 40.954911 ], "pop" : 72, "state" : "CO" }
+{ "_id" : "80747", "city" : "PEETZ", "loc" : [ -103.116606, 40.95195 ], "pop" : 451, "state" : "CO" }
+{ "_id" : "80749", "city" : "SEDGWICK", "loc" : [ -102.529122, 40.910317 ], "pop" : 415, "state" : "CO" }
+{ "_id" : "80750", "city" : "SNYDER", "loc" : [ -103.597134, 40.330655 ], "pop" : 134, "state" : "CO" }
+{ "_id" : "80751", "city" : "STERLING", "loc" : [ -103.221183, 40.63062 ], "pop" : 13524, "state" : "CO" }
+{ "_id" : "80754", "city" : "STONEHAM", "loc" : [ -103.638687, 40.686994 ], "pop" : 141, "state" : "CO" }
+{ "_id" : "80755", "city" : "VERNON", "loc" : [ -102.319343, 39.933127 ], "pop" : 318, "state" : "CO" }
+{ "_id" : "80757", "city" : "LAST CHANCE", "loc" : [ -103.578033, 39.938105 ], "pop" : 265, "state" : "CO" }
+{ "_id" : "80758", "city" : "LAIRD", "loc" : [ -102.233751, 40.104917 ], "pop" : 3396, "state" : "CO" }
+{ "_id" : "80759", "city" : "YUMA", "loc" : [ -102.707174, 40.130063 ], "pop" : 3811, "state" : "CO" }
+{ "_id" : "80801", "city" : "ANTON", "loc" : [ -103.434296, 39.686527 ], "pop" : 240, "state" : "CO" }
+{ "_id" : "80802", "city" : "ARAPAHOE", "loc" : [ -102.19401, 38.841716 ], "pop" : 335, "state" : "CO" }
+{ "_id" : "80804", "city" : "ARRIBA", "loc" : [ -103.270968, 39.30253 ], "pop" : 388, "state" : "CO" }
+{ "_id" : "80805", "city" : "BETHUNE", "loc" : [ -102.428142, 39.344771 ], "pop" : 543, "state" : "CO" }
+{ "_id" : "80807", "city" : "BURLINGTON", "loc" : [ -102.258281, 39.310649 ], "pop" : 3982, "state" : "CO" }
+{ "_id" : "80808", "city" : "CALHAN", "loc" : [ -104.355274, 38.964773 ], "pop" : 2955, "state" : "CO" }
+{ "_id" : "80809", "city" : "NORTH POLE", "loc" : [ -104.993684, 38.921314 ], "pop" : 2259, "state" : "CO" }
+{ "_id" : "80810", "city" : "CHEYENNE WELLS", "loc" : [ -102.358173, 38.819762 ], "pop" : 1364, "state" : "CO" }
+{ "_id" : "80812", "city" : "COPE", "loc" : [ -102.988098, 39.746227 ], "pop" : 626, "state" : "CO" }
+{ "_id" : "80814", "city" : "DIVIDE", "loc" : [ -105.19937, 38.957622 ], "pop" : 1675, "state" : "CO" }
+{ "_id" : "80815", "city" : "FLAGLER", "loc" : [ -103.062395, 39.312654 ], "pop" : 854, "state" : "CO" }
+{ "_id" : "80816", "city" : "FLORISSANT", "loc" : [ -105.226106, 38.827669 ], "pop" : 2480, "state" : "CO" }
+{ "_id" : "80817", "city" : "FOUNTAIN", "loc" : [ -104.700469, 38.699563 ], "pop" : 11570, "state" : "CO" }
+{ "_id" : "80818", "city" : "GENOA", "loc" : [ -103.460689, 39.338328 ], "pop" : 320, "state" : "CO" }
+{ "_id" : "80820", "city" : "GUFFEY", "loc" : [ -105.57835, 38.814584 ], "pop" : 300, "state" : "CO" }
+{ "_id" : "80821", "city" : "HUGO", "loc" : [ -103.498971, 39.084318 ], "pop" : 1064, "state" : "CO" }
+{ "_id" : "80822", "city" : "JOES", "loc" : [ -102.615134, 39.672771 ], "pop" : 315, "state" : "CO" }
+{ "_id" : "80823", "city" : "KARVAL", "loc" : [ -103.500613, 38.71194 ], "pop" : 339, "state" : "CO" }
+{ "_id" : "80824", "city" : "KIRK", "loc" : [ -102.477554, 39.617072 ], "pop" : 479, "state" : "CO" }
+{ "_id" : "80825", "city" : "KIT CARSON", "loc" : [ -102.819842, 38.803984 ], "pop" : 698, "state" : "CO" }
+{ "_id" : "80827", "city" : "LAKE GEORGE", "loc" : [ -105.434654, 39.034233 ], "pop" : 587, "state" : "CO" }
+{ "_id" : "80828", "city" : "LIMON", "loc" : [ -103.685572, 39.27126 ], "pop" : 2244, "state" : "CO" }
+{ "_id" : "80829", "city" : "MANITOU SPRINGS", "loc" : [ -104.905839, 38.854994 ], "pop" : 4989, "state" : "CO" }
+{ "_id" : "80830", "city" : "MATHESON", "loc" : [ -103.913165, 39.132044 ], "pop" : 439, "state" : "CO" }
+{ "_id" : "80831", "city" : "PEYTON", "loc" : [ -104.54722, 38.954097 ], "pop" : 3707, "state" : "CO" }
+{ "_id" : "80832", "city" : "RAMAH", "loc" : [ -104.124733, 39.073571 ], "pop" : 561, "state" : "CO" }
+{ "_id" : "80833", "city" : "RUSH", "loc" : [ -104.024065, 38.764248 ], "pop" : 408, "state" : "CO" }
+{ "_id" : "80834", "city" : "SEIBERT", "loc" : [ -102.882184, 39.318329 ], "pop" : 364, "state" : "CO" }
+{ "_id" : "80835", "city" : "SIMLA", "loc" : [ -104.086236, 39.146457 ], "pop" : 580, "state" : "CO" }
+{ "_id" : "80836", "city" : "STRATTON", "loc" : [ -102.597928, 39.308733 ], "pop" : 1102, "state" : "CO" }
+{ "_id" : "80840", "city" : "UNITED STATES AI", "loc" : [ -104.860139, 38.990448 ], "pop" : 9062, "state" : "CO" }
+{ "_id" : "80861", "city" : "VONA", "loc" : [ -102.739287, 39.323564 ], "pop" : 295, "state" : "CO" }
+{ "_id" : "80863", "city" : "WOODLAND PARK", "loc" : [ -105.062292, 38.996929 ], "pop" : 8272, "state" : "CO" }
+{ "_id" : "80864", "city" : "YODER", "loc" : [ -104.218353, 38.775252 ], "pop" : 511, "state" : "CO" }
+{ "_id" : "80903", "city" : "COLORADO SPRINGS", "loc" : [ -104.814466, 38.838832 ], "pop" : 13972, "state" : "CO" }
+{ "_id" : "80904", "city" : "COLORADO SPRINGS", "loc" : [ -104.859513, 38.853318 ], "pop" : 17366, "state" : "CO" }
+{ "_id" : "80905", "city" : "COLORADO SPRINGS", "loc" : [ -104.836997, 38.837692 ], "pop" : 3435, "state" : "CO" }
+{ "_id" : "80906", "city" : "COLORADO SPRINGS", "loc" : [ -104.819893, 38.790164 ], "pop" : 38856, "state" : "CO" }
+{ "_id" : "80907", "city" : "COLORADO SPRINGS", "loc" : [ -104.817034, 38.876001 ], "pop" : 25123, "state" : "CO" }
+{ "_id" : "80908", "city" : "COLORADO SPRINGS", "loc" : [ -104.693331, 39.023745 ], "pop" : 6803, "state" : "CO" }
+{ "_id" : "80909", "city" : "COLORADO SPRINGS", "loc" : [ -104.773483, 38.852038 ], "pop" : 34887, "state" : "CO" }
+{ "_id" : "80910", "city" : "COLORADO SPRINGS", "loc" : [ -104.770299, 38.815164 ], "pop" : 24867, "state" : "CO" }
+{ "_id" : "80911", "city" : "COLORADO SPRINGS", "loc" : [ -104.722322, 38.745665 ], "pop" : 22116, "state" : "CO" }
+{ "_id" : "80913", "city" : "FORT CARSON", "loc" : [ -104.782218, 38.741967 ], "pop" : 11309, "state" : "CO" }
+{ "_id" : "80914", "city" : "CHEYENNE MTN AFB", "loc" : [ -104.719052, 38.784241 ], "pop" : 0, "state" : "CO" }
+{ "_id" : "80915", "city" : "COLORADO SPRINGS", "loc" : [ -104.713422, 38.855845 ], "pop" : 18209, "state" : "CO" }
+{ "_id" : "80916", "city" : "COLORADO SPRINGS", "loc" : [ -104.74034, 38.807619 ], "pop" : 26402, "state" : "CO" }
+{ "_id" : "80917", "city" : "COLORADO SPRINGS", "loc" : [ -104.739904, 38.886027 ], "pop" : 27664, "state" : "CO" }
+{ "_id" : "80918", "city" : "COLORADO SPRINGS", "loc" : [ -104.773444, 38.912924 ], "pop" : 36410, "state" : "CO" }
+{ "_id" : "80919", "city" : "COLORADO SPRINGS", "loc" : [ -104.84642, 38.926795 ], "pop" : 17468, "state" : "CO" }
+{ "_id" : "80920", "city" : "COLORADO SPRINGS", "loc" : [ -104.766951, 38.949732 ], "pop" : 16907, "state" : "CO" }
+{ "_id" : "80921", "city" : "COLORADO SPRINGS", "loc" : [ -104.814042, 39.048674 ], "pop" : 3539, "state" : "CO" }
+{ "_id" : "80922", "city" : "COLORADO SPRINGS", "loc" : [ -104.698161, 38.90503 ], "pop" : 1836, "state" : "CO" }
+{ "_id" : "80925", "city" : "COLORADO SPRINGS", "loc" : [ -104.660087, 38.731329 ], "pop" : 2550, "state" : "CO" }
+{ "_id" : "80926", "city" : "COLORADO SPRINGS", "loc" : [ -104.85051, 38.698073 ], "pop" : 1040, "state" : "CO" }
+{ "_id" : "80928", "city" : "COLORADO SPRINGS", "loc" : [ -104.457043, 38.623261 ], "pop" : 273, "state" : "CO" }
+{ "_id" : "80929", "city" : "COLORADO SPRINGS", "loc" : [ -104.607857, 38.796837 ], "pop" : 197, "state" : "CO" }
+{ "_id" : "80930", "city" : "COLORADO SPRINGS", "loc" : [ -104.526924, 38.828926 ], "pop" : 484, "state" : "CO" }
+{ "_id" : "81001", "city" : "PUEBLO", "loc" : [ -104.584828, 38.287876 ], "pop" : 28837, "state" : "CO" }
+{ "_id" : "81003", "city" : "PUEBLO", "loc" : [ -104.62337, 38.284277 ], "pop" : 13461, "state" : "CO" }
+{ "_id" : "81004", "city" : "PUEBLO", "loc" : [ -104.627829, 38.244063 ], "pop" : 25748, "state" : "CO" }
+{ "_id" : "81005", "city" : "PUEBLO", "loc" : [ -104.660031, 38.235157 ], "pop" : 26273, "state" : "CO" }
+{ "_id" : "81006", "city" : "PUEBLO", "loc" : [ -104.531834, 38.24465 ], "pop" : 12277, "state" : "CO" }
+{ "_id" : "81007", "city" : "PUEBLO WEST", "loc" : [ -104.743264, 38.319975 ], "pop" : 4592, "state" : "CO" }
+{ "_id" : "81008", "city" : "PUEBLO", "loc" : [ -104.628433, 38.313251 ], "pop" : 5953, "state" : "CO" }
+{ "_id" : "81020", "city" : "AGUILAR", "loc" : [ -104.676926, 37.393304 ], "pop" : 928, "state" : "CO" }
+{ "_id" : "81021", "city" : "ARLINGTON", "loc" : [ -103.369741, 38.40677 ], "pop" : 28, "state" : "CO" }
+{ "_id" : "81022", "city" : "NORTH AVONDALE", "loc" : [ -104.359686, 38.211603 ], "pop" : 1483, "state" : "CO" }
+{ "_id" : "81023", "city" : "BEULAH", "loc" : [ -104.97245, 38.083712 ], "pop" : 867, "state" : "CO" }
+{ "_id" : "81025", "city" : "BOONE", "loc" : [ -104.25851, 38.264614 ], "pop" : 976, "state" : "CO" }
+{ "_id" : "81026", "city" : "BRANDON", "loc" : [ -102.781906, 38.485133 ], "pop" : 1094, "state" : "CO" }
+{ "_id" : "81027", "city" : "BRANSON", "loc" : [ -103.874115, 37.051775 ], "pop" : 140, "state" : "CO" }
+{ "_id" : "81028", "city" : "BRISTOL", "loc" : [ -102.342642, 38.133184 ], "pop" : 256, "state" : "CO" }
+{ "_id" : "81029", "city" : "CAMPO", "loc" : [ -102.546423, 37.119547 ], "pop" : 487, "state" : "CO" }
+{ "_id" : "81036", "city" : "CHIVINGTON", "loc" : [ -102.50536, 38.444141 ], "pop" : 123, "state" : "CO" }
+{ "_id" : "81039", "city" : "FOWLER", "loc" : [ -104.029908, 38.123071 ], "pop" : 1877, "state" : "CO" }
+{ "_id" : "81040", "city" : "FARISITA", "loc" : [ -105.237397, 37.763753 ], "pop" : 428, "state" : "CO" }
+{ "_id" : "81041", "city" : "GRANADA", "loc" : [ -102.32712, 38.054485 ], "pop" : 741, "state" : "CO" }
+{ "_id" : "81043", "city" : "HARTMAN", "loc" : [ -102.186609, 38.145291 ], "pop" : 256, "state" : "CO" }
+{ "_id" : "81044", "city" : "CADDOA", "loc" : [ -102.933145, 38.107347 ], "pop" : 263, "state" : "CO" }
+{ "_id" : "81045", "city" : "HASWELL", "loc" : [ -103.150543, 38.447431 ], "pop" : 109, "state" : "CO" }
+{ "_id" : "81047", "city" : "HOLLY", "loc" : [ -102.141466, 38.0205 ], "pop" : 1480, "state" : "CO" }
+{ "_id" : "81049", "city" : "VILLEGREEN", "loc" : [ -103.358348, 37.331189 ], "pop" : 389, "state" : "CO" }
+{ "_id" : "81050", "city" : "TIMPAS", "loc" : [ -103.549068, 37.991552 ], "pop" : 11742, "state" : "CO" }
+{ "_id" : "81052", "city" : "LAMAR", "loc" : [ -102.619195, 38.084136 ], "pop" : 9903, "state" : "CO" }
+{ "_id" : "81054", "city" : "DEORA", "loc" : [ -103.208492, 38.065514 ], "pop" : 4217, "state" : "CO" }
+{ "_id" : "81055", "city" : "CUCHARA", "loc" : [ -105.012994, 37.498292 ], "pop" : 1234, "state" : "CO" }
+{ "_id" : "81057", "city" : "MC CLAVE", "loc" : [ -102.816934, 38.150484 ], "pop" : 568, "state" : "CO" }
+{ "_id" : "81058", "city" : "MANZANOLA", "loc" : [ -103.876602, 38.110861 ], "pop" : 961, "state" : "CO" }
+{ "_id" : "81059", "city" : "DELHI", "loc" : [ -104.13074, 37.478533 ], "pop" : 237, "state" : "CO" }
+{ "_id" : "81062", "city" : "OLNEY SPRINGS", "loc" : [ -103.941033, 38.201877 ], "pop" : 706, "state" : "CO" }
+{ "_id" : "81063", "city" : "ORDWAY", "loc" : [ -103.800277, 38.209546 ], "pop" : 2692, "state" : "CO" }
+{ "_id" : "81064", "city" : "UTLEYVILLE", "loc" : [ -102.893106, 37.355885 ], "pop" : 383, "state" : "CO" }
+{ "_id" : "81067", "city" : "ROCKY FORD", "loc" : [ -103.725143, 38.049016 ], "pop" : 5946, "state" : "CO" }
+{ "_id" : "81069", "city" : "RYE", "loc" : [ -104.886257, 37.937145 ], "pop" : 2369, "state" : "CO" }
+{ "_id" : "81071", "city" : "TOWNER", "loc" : [ -102.295367, 38.462172 ], "pop" : 162, "state" : "CO" }
+{ "_id" : "81073", "city" : "SPRINGFIELD", "loc" : [ -102.617322, 37.406727 ], "pop" : 1992, "state" : "CO" }
+{ "_id" : "81076", "city" : "SUGAR CITY", "loc" : [ -103.655557, 38.244368 ], "pop" : 400, "state" : "CO" }
+{ "_id" : "81081", "city" : "TRINCHERA", "loc" : [ -104.118354, 37.075662 ], "pop" : 21, "state" : "CO" }
+{ "_id" : "81082", "city" : "JANSEN", "loc" : [ -104.500715, 37.175475 ], "pop" : 10978, "state" : "CO" }
+{ "_id" : "81084", "city" : "LYCAN", "loc" : [ -102.320128, 37.57476 ], "pop" : 183, "state" : "CO" }
+{ "_id" : "81087", "city" : "VILAS", "loc" : [ -102.44374, 37.373043 ], "pop" : 145, "state" : "CO" }
+{ "_id" : "81089", "city" : "FARISTA", "loc" : [ -104.804301, 37.638159 ], "pop" : 4347, "state" : "CO" }
+{ "_id" : "81090", "city" : "WALSH", "loc" : [ -102.253716, 37.352057 ], "pop" : 1366, "state" : "CO" }
+{ "_id" : "81091", "city" : "WESTON", "loc" : [ -104.824749, 37.170211 ], "pop" : 1094, "state" : "CO" }
+{ "_id" : "81092", "city" : "WILEY", "loc" : [ -102.714734, 38.158978 ], "pop" : 711, "state" : "CO" }
+{ "_id" : "81101", "city" : "ALAMOSA", "loc" : [ -105.878602, 37.470274 ], "pop" : 12580, "state" : "CO" }
+{ "_id" : "81120", "city" : "ANTONITO", "loc" : [ -106.037946, 37.085473 ], "pop" : 2246, "state" : "CO" }
+{ "_id" : "81121", "city" : "ARBOLES", "loc" : [ -107.390749, 37.101633 ], "pop" : 587, "state" : "CO" }
+{ "_id" : "81122", "city" : "BAYFIELD", "loc" : [ -107.613728, 37.260328 ], "pop" : 3866, "state" : "CO" }
+{ "_id" : "81123", "city" : "BLANCA", "loc" : [ -105.517784, 37.431702 ], "pop" : 429, "state" : "CO" }
+{ "_id" : "81125", "city" : "CENTER", "loc" : [ -106.090628, 37.734295 ], "pop" : 4419, "state" : "CO" }
+{ "_id" : "81130", "city" : "CREEDE", "loc" : [ -106.927679, 37.816367 ], "pop" : 558, "state" : "CO" }
+{ "_id" : "81132", "city" : "LA GARITA", "loc" : [ -106.350502, 37.671346 ], "pop" : 2791, "state" : "CO" }
+{ "_id" : "81133", "city" : "FORT GARLAND", "loc" : [ -105.404879, 37.426978 ], "pop" : 725, "state" : "CO" }
+{ "_id" : "81136", "city" : "HOOPER", "loc" : [ -105.871193, 37.723203 ], "pop" : 265, "state" : "CO" }
+{ "_id" : "81137", "city" : "IGNACIO", "loc" : [ -107.639465, 37.126412 ], "pop" : 3494, "state" : "CO" }
+{ "_id" : "81140", "city" : "LA JARA", "loc" : [ -106.005427, 37.290726 ], "pop" : 2274, "state" : "CO" }
+{ "_id" : "81143", "city" : "MOFFAT", "loc" : [ -105.841051, 38.045195 ], "pop" : 737, "state" : "CO" }
+{ "_id" : "81144", "city" : "MONTE VISTA", "loc" : [ -106.140833, 37.573095 ], "pop" : 6041, "state" : "CO" }
+{ "_id" : "81146", "city" : "MOSCA", "loc" : [ -105.806866, 37.635796 ], "pop" : 399, "state" : "CO" }
+{ "_id" : "81147", "city" : "PAGOSA SPRINGS", "loc" : [ -107.038497, 37.252345 ], "pop" : 4758, "state" : "CO" }
+{ "_id" : "81149", "city" : "SAGUACHE", "loc" : [ -106.187592, 38.09775 ], "pop" : 895, "state" : "CO" }
+{ "_id" : "81150", "city" : "SAN ACACIO", "loc" : [ -105.439949, 37.201347 ], "pop" : 1146, "state" : "CO" }
+{ "_id" : "81151", "city" : "SANFORD", "loc" : [ -105.928588, 37.208724 ], "pop" : 3037, "state" : "CO" }
+{ "_id" : "81152", "city" : "MESITA", "loc" : [ -105.575625, 37.05057 ], "pop" : 252, "state" : "CO" }
+{ "_id" : "81153", "city" : "SAN PABLO", "loc" : [ -105.346196, 37.134872 ], "pop" : 638, "state" : "CO" }
+{ "_id" : "81154", "city" : "SOUTH FORK", "loc" : [ -106.612451, 37.67248 ], "pop" : 722, "state" : "CO" }
+{ "_id" : "81155", "city" : "VILLA GROVE", "loc" : [ -106.110183, 38.2952 ], "pop" : 53, "state" : "CO" }
+{ "_id" : "81201", "city" : "SALIDA", "loc" : [ -105.997818, 38.525909 ], "pop" : 7658, "state" : "CO" }
+{ "_id" : "81210", "city" : "ALMONT", "loc" : [ -106.627099, 38.64997 ], "pop" : 150, "state" : "CO" }
+{ "_id" : "81211", "city" : "BUENA VISTA", "loc" : [ -106.147121, 38.838003 ], "pop" : 5220, "state" : "CO" }
+{ "_id" : "81212", "city" : "CANON CITY", "loc" : [ -105.217829, 38.445074 ], "pop" : 23049, "state" : "CO" }
+{ "_id" : "81220", "city" : "CIMARRON", "loc" : [ -107.482366, 38.387633 ], "pop" : 84, "state" : "CO" }
+{ "_id" : "81224", "city" : "CRESTED BUTTE", "loc" : [ -106.961899, 38.869081 ], "pop" : 1750, "state" : "CO" }
+{ "_id" : "81226", "city" : "FLORENCE", "loc" : [ -105.123233, 38.385016 ], "pop" : 4461, "state" : "CO" }
+{ "_id" : "81228", "city" : "GRANITE", "loc" : [ -106.311417, 39.095294 ], "pop" : 79, "state" : "CO" }
+{ "_id" : "81230", "city" : "GUNNISON", "loc" : [ -106.931013, 38.551056 ], "pop" : 7814, "state" : "CO" }
+{ "_id" : "81233", "city" : "HOWARD", "loc" : [ -105.747124, 38.388519 ], "pop" : 485, "state" : "CO" }
+{ "_id" : "81235", "city" : "LAKE CITY", "loc" : [ -107.302037, 37.986769 ], "pop" : 467, "state" : "CO" }
+{ "_id" : "81236", "city" : "NATHROP", "loc" : [ -106.116576, 38.710343 ], "pop" : 440, "state" : "CO" }
+{ "_id" : "81239", "city" : "PARLIN", "loc" : [ -106.677995, 38.508762 ], "pop" : 67, "state" : "CO" }
+{ "_id" : "81240", "city" : "PENROSE", "loc" : [ -105.011325, 38.433622 ], "pop" : 3166, "state" : "CO" }
+{ "_id" : "81241", "city" : "PITKIN", "loc" : [ -106.516774, 38.608542 ], "pop" : 53, "state" : "CO" }
+{ "_id" : "81243", "city" : "POWDERHORN", "loc" : [ -107.108449, 38.282165 ], "pop" : 11, "state" : "CO" }
+{ "_id" : "81251", "city" : "TWIN LAKES", "loc" : [ -106.435079, 39.090231 ], "pop" : 49, "state" : "CO" }
+{ "_id" : "81252", "city" : "WESTCLIFFE", "loc" : [ -105.433154, 38.123023 ], "pop" : 1569, "state" : "CO" }
+{ "_id" : "81253", "city" : "WETMORE", "loc" : [ -105.106441, 38.189857 ], "pop" : 357, "state" : "CO" }
+{ "_id" : "81301", "city" : "DURANGO", "loc" : [ -107.861684, 37.287388 ], "pop" : 23506, "state" : "CO" }
+{ "_id" : "81320", "city" : "CAHONE", "loc" : [ -108.579442, 37.69163 ], "pop" : 384, "state" : "CO" }
+{ "_id" : "81321", "city" : "CORTEZ", "loc" : [ -108.583726, 37.354949 ], "pop" : 11937, "state" : "CO" }
+{ "_id" : "81323", "city" : "DOLORES", "loc" : [ -108.471748, 37.466571 ], "pop" : 1770, "state" : "CO" }
+{ "_id" : "81324", "city" : "DOVE CREEK", "loc" : [ -108.918147, 37.763199 ], "pop" : 1120, "state" : "CO" }
+{ "_id" : "81325", "city" : "EGNAR", "loc" : [ -108.929889, 37.934448 ], "pop" : 119, "state" : "CO" }
+{ "_id" : "81326", "city" : "HESPERUS", "loc" : [ -108.121917, 37.165368 ], "pop" : 1303, "state" : "CO" }
+{ "_id" : "81327", "city" : "LEWIS", "loc" : [ -108.61891, 37.47101 ], "pop" : 1455, "state" : "CO" }
+{ "_id" : "81328", "city" : "MANCOS", "loc" : [ -108.298242, 37.347133 ], "pop" : 2141, "state" : "CO" }
+{ "_id" : "81331", "city" : "PLEASANT VIEW", "loc" : [ -108.809487, 37.588763 ], "pop" : 223, "state" : "CO" }
+{ "_id" : "81334", "city" : "TOWAOC", "loc" : [ -108.719993, 37.208408 ], "pop" : 1135, "state" : "CO" }
+{ "_id" : "81335", "city" : "YELLOW JACKET", "loc" : [ -108.785167, 37.499526 ], "pop" : 126, "state" : "CO" }
+{ "_id" : "81401", "city" : "MONTROSE", "loc" : [ -107.875182, 38.46783 ], "pop" : 17834, "state" : "CO" }
+{ "_id" : "81410", "city" : "AUSTIN", "loc" : [ -107.97384, 38.797544 ], "pop" : 1258, "state" : "CO" }
+{ "_id" : "81411", "city" : "BEDROCK", "loc" : [ -108.953224, 38.384352 ], "pop" : 191, "state" : "CO" }
+{ "_id" : "81413", "city" : "CEDAREDGE", "loc" : [ -107.926786, 38.911878 ], "pop" : 3254, "state" : "CO" }
+{ "_id" : "81415", "city" : "CRAWFORD", "loc" : [ -107.614864, 38.69408 ], "pop" : 882, "state" : "CO" }
+{ "_id" : "81416", "city" : "DELTA", "loc" : [ -108.060421, 38.734891 ], "pop" : 8644, "state" : "CO" }
+{ "_id" : "81418", "city" : "ECKERT", "loc" : [ -107.962452, 38.844982 ], "pop" : 1211, "state" : "CO" }
+{ "_id" : "81419", "city" : "HOTCHKISS", "loc" : [ -107.747173, 38.812417 ], "pop" : 2735, "state" : "CO" }
+{ "_id" : "81422", "city" : "NATURITA", "loc" : [ -108.572836, 38.222559 ], "pop" : 554, "state" : "CO" }
+{ "_id" : "81423", "city" : "NORWOOD", "loc" : [ -108.284472, 38.110406 ], "pop" : 1079, "state" : "CO" }
+{ "_id" : "81424", "city" : "NUCLA", "loc" : [ -108.547644, 38.268219 ], "pop" : 1135, "state" : "CO" }
+{ "_id" : "81425", "city" : "OLATHE", "loc" : [ -107.992118, 38.597575 ], "pop" : 4246, "state" : "CO" }
+{ "_id" : "81426", "city" : "OPHIR", "loc" : [ -107.851961, 37.856197 ], "pop" : 138, "state" : "CO" }
+{ "_id" : "81427", "city" : "OURAY", "loc" : [ -107.67261, 38.02576 ], "pop" : 686, "state" : "CO" }
+{ "_id" : "81428", "city" : "PAONIA", "loc" : [ -107.598483, 38.864978 ], "pop" : 3314, "state" : "CO" }
+{ "_id" : "81430", "city" : "PLACERVILLE", "loc" : [ -108.024775, 38.008759 ], "pop" : 467, "state" : "CO" }
+{ "_id" : "81431", "city" : "REDVALE", "loc" : [ -108.389536, 38.186452 ], "pop" : 409, "state" : "CO" }
+{ "_id" : "81432", "city" : "RIDGWAY", "loc" : [ -107.753341, 38.138074 ], "pop" : 1299, "state" : "CO" }
+{ "_id" : "81433", "city" : "SILVERTON", "loc" : [ -107.666686, 37.808995 ], "pop" : 745, "state" : "CO" }
+{ "_id" : "81434", "city" : "SOMERSET", "loc" : [ -107.378145, 38.946801 ], "pop" : 180, "state" : "CO" }
+{ "_id" : "81435", "city" : "TELLURIDE", "loc" : [ -107.821371, 37.940028 ], "pop" : 1850, "state" : "CO" }
+{ "_id" : "81501", "city" : "GRAND JUNCTION", "loc" : [ -108.545692, 39.078326 ], "pop" : 19665, "state" : "CO" }
+{ "_id" : "81503", "city" : "GRAND JUNCTION", "loc" : [ -108.575609, 39.056777 ], "pop" : 20467, "state" : "CO" }
+{ "_id" : "81504", "city" : "FRUITVALE", "loc" : [ -108.489094, 39.083136 ], "pop" : 16754, "state" : "CO" }
+{ "_id" : "81505", "city" : "GRAND JUNCTION", "loc" : [ -108.596834, 39.107097 ], "pop" : 4877, "state" : "CO" }
+{ "_id" : "81506", "city" : "GRAND JUNCTION", "loc" : [ -108.54911, 39.103209 ], "pop" : 7471, "state" : "CO" }
+{ "_id" : "81520", "city" : "CLIFTON", "loc" : [ -108.449628, 39.0805 ], "pop" : 8408, "state" : "CO" }
+{ "_id" : "81521", "city" : "FRUITA", "loc" : [ -108.721757, 39.163656 ], "pop" : 6230, "state" : "CO" }
+{ "_id" : "81522", "city" : "GATEWAY", "loc" : [ -108.791344, 38.915136 ], "pop" : 752, "state" : "CO" }
+{ "_id" : "81524", "city" : "LOMA", "loc" : [ -108.814902, 39.227896 ], "pop" : 1067, "state" : "CO" }
+{ "_id" : "81525", "city" : "MACK", "loc" : [ -108.929597, 39.255367 ], "pop" : 176, "state" : "CO" }
+{ "_id" : "81526", "city" : "PALISADE", "loc" : [ -108.367977, 39.103178 ], "pop" : 4366, "state" : "CO" }
+{ "_id" : "81527", "city" : "WHITEWATER", "loc" : [ -108.399042, 38.974422 ], "pop" : 664, "state" : "CO" }
+{ "_id" : "81601", "city" : "GLENWOOD SPRINGS", "loc" : [ -107.325188, 39.529607 ], "pop" : 9606, "state" : "CO" }
+{ "_id" : "81610", "city" : "DINOSAUR", "loc" : [ -108.965184, 40.256609 ], "pop" : 498, "state" : "CO" }
+{ "_id" : "81611", "city" : "ASPEN", "loc" : [ -106.823593, 39.195139 ], "pop" : 7431, "state" : "CO" }
+{ "_id" : "81621", "city" : "BASALT", "loc" : [ -106.998752, 39.353466 ], "pop" : 3248, "state" : "CO" }
+{ "_id" : "81623", "city" : "MARBLE", "loc" : [ -107.171012, 39.385431 ], "pop" : 9406, "state" : "CO" }
+{ "_id" : "81624", "city" : "COLLBRAN", "loc" : [ -107.924945, 39.245267 ], "pop" : 1043, "state" : "CO" }
+{ "_id" : "81625", "city" : "CRAIG", "loc" : [ -107.561458, 40.522351 ], "pop" : 10242, "state" : "CO" }
+{ "_id" : "81630", "city" : "DE BEQUE", "loc" : [ -108.230405, 39.311764 ], "pop" : 464, "state" : "CO" }
+{ "_id" : "81631", "city" : "EAGLE", "loc" : [ -106.75884, 39.634138 ], "pop" : 3368, "state" : "CO" }
+{ "_id" : "81633", "city" : "ELK SPRINGS", "loc" : [ -108.419729, 40.414588 ], "pop" : 10, "state" : "CO" }
+{ "_id" : "81635", "city" : "BATTLEMENT MESA", "loc" : [ -108.038038, 39.440729 ], "pop" : 2602, "state" : "CO" }
+{ "_id" : "81637", "city" : "GYPSUM", "loc" : [ -106.967083, 39.661848 ], "pop" : 2593, "state" : "CO" }
+{ "_id" : "81638", "city" : "HAMILTON", "loc" : [ -107.584089, 40.32504 ], "pop" : 191, "state" : "CO" }
+{ "_id" : "81639", "city" : "HAYDEN", "loc" : [ -107.257055, 40.494487 ], "pop" : 2028, "state" : "CO" }
+{ "_id" : "81640", "city" : "MAYBELL", "loc" : [ -108.272264, 40.650649 ], "pop" : 351, "state" : "CO" }
+{ "_id" : "81641", "city" : "MEEKER", "loc" : [ -107.892498, 40.038726 ], "pop" : 3094, "state" : "CO" }
+{ "_id" : "81642", "city" : "MEREDITH", "loc" : [ -106.67823, 39.335348 ], "pop" : 76, "state" : "CO" }
+{ "_id" : "81643", "city" : "MESA", "loc" : [ -108.104401, 39.161161 ], "pop" : 741, "state" : "CO" }
+{ "_id" : "81647", "city" : "NEW CASTLE", "loc" : [ -107.542758, 39.570922 ], "pop" : 2719, "state" : "CO" }
+{ "_id" : "81648", "city" : "RANGELY", "loc" : [ -108.799148, 40.082844 ], "pop" : 2740, "state" : "CO" }
+{ "_id" : "81650", "city" : "RIFLE", "loc" : [ -107.789804, 39.549073 ], "pop" : 7146, "state" : "CO" }
+{ "_id" : "81652", "city" : "SILT", "loc" : [ -107.657411, 39.541464 ], "pop" : 2430, "state" : "CO" }
+{ "_id" : "81653", "city" : "SLATER", "loc" : [ -107.497178, 40.947985 ], "pop" : 65, "state" : "CO" }
+{ "_id" : "81654", "city" : "SNOWMASS", "loc" : [ -106.950839, 39.250059 ], "pop" : 2627, "state" : "CO" }
+{ "_id" : "81657", "city" : "VAIL", "loc" : [ -106.463454, 39.623793 ], "pop" : 11449, "state" : "CO" }
+{ "_id" : "82001", "city" : "CHEYENNE", "loc" : [ -104.796234, 41.143719 ], "pop" : 33107, "state" : "WY" }
+{ "_id" : "82007", "city" : "CHEYENNE", "loc" : [ -104.810745, 41.108433 ], "pop" : 15050, "state" : "WY" }
+{ "_id" : "82009", "city" : "CHEYENNE", "loc" : [ -104.802328, 41.183566 ], "pop" : 22028, "state" : "WY" }
+{ "_id" : "82050", "city" : "ALBIN", "loc" : [ -104.150542, 41.434237 ], "pop" : 310, "state" : "WY" }
+{ "_id" : "82051", "city" : "LARAMIE", "loc" : [ -105.819708, 41.562721 ], "pop" : 22, "state" : "WY" }
+{ "_id" : "82052", "city" : "BUFORD", "loc" : [ -105.469697, 41.142115 ], "pop" : 97, "state" : "WY" }
+{ "_id" : "82053", "city" : "BURNS", "loc" : [ -104.315521, 41.200297 ], "pop" : 1303, "state" : "WY" }
+{ "_id" : "82054", "city" : "CARPENTER", "loc" : [ -104.276514, 41.042819 ], "pop" : 222, "state" : "WY" }
+{ "_id" : "82055", "city" : "CENTENNIAL", "loc" : [ -105.99451, 41.339149 ], "pop" : 446, "state" : "WY" }
+{ "_id" : "82058", "city" : "GARRETT", "loc" : [ -105.550534, 42.142015 ], "pop" : 120, "state" : "WY" }
+{ "_id" : "82063", "city" : "JELM", "loc" : [ -105.925727, 41.145723 ], "pop" : 470, "state" : "WY" }
+{ "_id" : "82070", "city" : "LARAMIE", "loc" : [ -105.581146, 41.312907 ], "pop" : 29327, "state" : "WY" }
+{ "_id" : "82080", "city" : "MC FADDEN", "loc" : [ -106.137861, 41.6327 ], "pop" : 79, "state" : "WY" }
+{ "_id" : "82081", "city" : "MERIDEN", "loc" : [ -104.286606, 41.54236 ], "pop" : 40, "state" : "WY" }
+{ "_id" : "82082", "city" : "PINE BLUFFS", "loc" : [ -104.066591, 41.178799 ], "pop" : 1082, "state" : "WY" }
+{ "_id" : "82083", "city" : "ROCK RIVER", "loc" : [ -105.974629, 41.746073 ], "pop" : 236, "state" : "WY" }
+{ "_id" : "82084", "city" : "TIE SIDING", "loc" : [ -105.446222, 41.052785 ], "pop" : 19, "state" : "WY" }
+{ "_id" : "82190", "city" : "FISHING BRIDGE", "loc" : [ -110.674366, 44.853913 ], "pop" : 443, "state" : "WY" }
+{ "_id" : "82201", "city" : "WHEATLAND", "loc" : [ -104.967852, 42.049467 ], "pop" : 5952, "state" : "WY" }
+{ "_id" : "82210", "city" : "CHUGWATER", "loc" : [ -104.817916, 41.748668 ], "pop" : 295, "state" : "WY" }
+{ "_id" : "82212", "city" : "FORT LARAMIE", "loc" : [ -104.522595, 42.213314 ], "pop" : 325, "state" : "WY" }
+{ "_id" : "82213", "city" : "GLENDO", "loc" : [ -105.000013, 42.500352 ], "pop" : 471, "state" : "WY" }
+{ "_id" : "82214", "city" : "GUERNSEY", "loc" : [ -104.751164, 42.265513 ], "pop" : 1319, "state" : "WY" }
+{ "_id" : "82215", "city" : "HARTVILLE", "loc" : [ -104.729564, 42.33339 ], "pop" : 108, "state" : "WY" }
+{ "_id" : "82217", "city" : "HAWK SPRINGS", "loc" : [ -104.329498, 41.741481 ], "pop" : 125, "state" : "WY" }
+{ "_id" : "82219", "city" : "JAY EM", "loc" : [ -104.311437, 42.357399 ], "pop" : 399, "state" : "WY" }
+{ "_id" : "82220", "city" : "KEELINE", "loc" : [ -104.720277, 42.839062 ], "pop" : 209, "state" : "WY" }
+{ "_id" : "82221", "city" : "LAGRANGE", "loc" : [ -104.19738, 41.642311 ], "pop" : 413, "state" : "WY" }
+{ "_id" : "82222", "city" : "LANCE CREEK", "loc" : [ -104.544958, 43.231636 ], "pop" : 181, "state" : "WY" }
+{ "_id" : "82223", "city" : "LINGLE", "loc" : [ -104.331992, 42.134624 ], "pop" : 714, "state" : "WY" }
+{ "_id" : "82224", "city" : "LOST SPRINGS", "loc" : [ -104.920901, 42.729835 ], "pop" : 6, "state" : "WY" }
+{ "_id" : "82225", "city" : "LUSK", "loc" : [ -104.465076, 42.765953 ], "pop" : 1724, "state" : "WY" }
+{ "_id" : "82229", "city" : "SHAWNEE", "loc" : [ -105.032447, 42.839464 ], "pop" : 137, "state" : "WY" }
+{ "_id" : "82240", "city" : "TORRINGTON", "loc" : [ -104.191662, 42.062377 ], "pop" : 9575, "state" : "WY" }
+{ "_id" : "82242", "city" : "VAN TASSELL", "loc" : [ -104.315073, 42.830004 ], "pop" : 385, "state" : "WY" }
+{ "_id" : "82243", "city" : "VETERAN", "loc" : [ -104.370899, 41.982091 ], "pop" : 148, "state" : "WY" }
+{ "_id" : "82244", "city" : "YODER", "loc" : [ -104.353507, 41.912018 ], "pop" : 674, "state" : "WY" }
+{ "_id" : "82301", "city" : "RAWLINS", "loc" : [ -107.234883, 41.795131 ], "pop" : 9914, "state" : "WY" }
+{ "_id" : "82310", "city" : "JEFFREY CITY", "loc" : [ -107.872422, 42.540201 ], "pop" : 253, "state" : "WY" }
+{ "_id" : "82321", "city" : "BAGGS", "loc" : [ -107.668733, 41.031191 ], "pop" : 384, "state" : "WY" }
+{ "_id" : "82322", "city" : "BAIROIL", "loc" : [ -107.563288, 42.232721 ], "pop" : 236, "state" : "WY" }
+{ "_id" : "82323", "city" : "DIXON", "loc" : [ -107.560354, 41.044631 ], "pop" : 253, "state" : "WY" }
+{ "_id" : "82325", "city" : "ENCAMPMENT", "loc" : [ -106.780285, 41.205353 ], "pop" : 946, "state" : "WY" }
+{ "_id" : "82327", "city" : "HANNA", "loc" : [ -106.528283, 41.87264 ], "pop" : 1585, "state" : "WY" }
+{ "_id" : "82329", "city" : "MEDICINE BOW", "loc" : [ -106.201228, 41.903002 ], "pop" : 409, "state" : "WY" }
+{ "_id" : "82331", "city" : "RYAN PARK", "loc" : [ -106.797538, 41.446293 ], "pop" : 2462, "state" : "WY" }
+{ "_id" : "82332", "city" : "SAVERY", "loc" : [ -107.42338, 41.039485 ], "pop" : 97, "state" : "WY" }
+{ "_id" : "82334", "city" : "SINCLAIR", "loc" : [ -107.109083, 41.779741 ], "pop" : 530, "state" : "WY" }
+{ "_id" : "82336", "city" : "WAMSUTTER", "loc" : [ -108.151674, 41.658278 ], "pop" : 516, "state" : "WY" }
+{ "_id" : "82401", "city" : "WORLAND", "loc" : [ -107.95626, 44.013796 ], "pop" : 7693, "state" : "WY" }
+{ "_id" : "82410", "city" : "BASIN", "loc" : [ -108.043787, 44.378765 ], "pop" : 1580, "state" : "WY" }
+{ "_id" : "82411", "city" : "BURLINGTON", "loc" : [ -108.432669, 44.444218 ], "pop" : 435, "state" : "WY" }
+{ "_id" : "82414", "city" : "CODY", "loc" : [ -109.075611, 44.523135 ], "pop" : 11985, "state" : "WY" }
+{ "_id" : "82421", "city" : "DEAVER", "loc" : [ -108.597948, 44.925695 ], "pop" : 499, "state" : "WY" }
+{ "_id" : "82426", "city" : "GREYBULL", "loc" : [ -108.079503, 44.491881 ], "pop" : 2460, "state" : "WY" }
+{ "_id" : "82428", "city" : "HYATTVILLE", "loc" : [ -107.605318, 44.250693 ], "pop" : 97, "state" : "WY" }
+{ "_id" : "82431", "city" : "LOVELL", "loc" : [ -108.414107, 44.833637 ], "pop" : 4322, "state" : "WY" }
+{ "_id" : "82432", "city" : "MANDERSON", "loc" : [ -107.953423, 44.311931 ], "pop" : 657, "state" : "WY" }
+{ "_id" : "82433", "city" : "MEETEETSE", "loc" : [ -108.950045, 44.196202 ], "pop" : 1010, "state" : "WY" }
+{ "_id" : "82434", "city" : "OTTO", "loc" : [ -108.304673, 44.405644 ], "pop" : 120, "state" : "WY" }
+{ "_id" : "82435", "city" : "POWELL", "loc" : [ -108.777322, 44.756077 ], "pop" : 9608, "state" : "WY" }
+{ "_id" : "82441", "city" : "SHELL", "loc" : [ -107.824333, 44.563649 ], "pop" : 355, "state" : "WY" }
+{ "_id" : "82442", "city" : "TEN SLEEP", "loc" : [ -107.415305, 43.997848 ], "pop" : 695, "state" : "WY" }
+{ "_id" : "82443", "city" : "GRASS CREEK", "loc" : [ -108.231297, 43.662152 ], "pop" : 4809, "state" : "WY" }
+{ "_id" : "82450", "city" : "WAPITI", "loc" : [ -109.432629, 44.47967 ], "pop" : 214, "state" : "WY" }
+{ "_id" : "82501", "city" : "GAS HILLS", "loc" : [ -108.411335, 43.045786 ], "pop" : 15471, "state" : "WY" }
+{ "_id" : "82510", "city" : "ARAPAHOE", "loc" : [ -108.494134, 42.967936 ], "pop" : 605, "state" : "WY" }
+{ "_id" : "82512", "city" : "CROWHEART", "loc" : [ -109.296043, 43.371569 ], "pop" : 157, "state" : "WY" }
+{ "_id" : "82513", "city" : "DUBOIS", "loc" : [ -109.649175, 43.545136 ], "pop" : 1493, "state" : "WY" }
+{ "_id" : "82514", "city" : "FORT WASHAKIE", "loc" : [ -108.896445, 43.004761 ], "pop" : 1131, "state" : "WY" }
+{ "_id" : "82516", "city" : "KINNEAR", "loc" : [ -108.615428, 43.131777 ], "pop" : 420, "state" : "WY" }
+{ "_id" : "82520", "city" : "ETHETE", "loc" : [ -108.738288, 42.859678 ], "pop" : 11770, "state" : "WY" }
+{ "_id" : "82523", "city" : "PAVILLION", "loc" : [ -108.604394, 43.198515 ], "pop" : 1681, "state" : "WY" }
+{ "_id" : "82601", "city" : "CASPER", "loc" : [ -106.316571, 42.845763 ], "pop" : 21224, "state" : "WY" }
+{ "_id" : "82604", "city" : "CASPER", "loc" : [ -106.389634, 42.826073 ], "pop" : 24812, "state" : "WY" }
+{ "_id" : "82609", "city" : "CASPER", "loc" : [ -106.280649, 42.840629 ], "pop" : 12789, "state" : "WY" }
+{ "_id" : "82620", "city" : "ALCOVA", "loc" : [ -106.610199, 42.568383 ], "pop" : 10, "state" : "WY" }
+{ "_id" : "82630", "city" : "ARMINTO", "loc" : [ -107.343611, 43.120883 ], "pop" : 14, "state" : "WY" }
+{ "_id" : "82633", "city" : "DOUGLAS", "loc" : [ -105.385484, 42.762558 ], "pop" : 7502, "state" : "WY" }
+{ "_id" : "82636", "city" : "EVANSVILLE", "loc" : [ -106.263886, 42.861384 ], "pop" : 1621, "state" : "WY" }
+{ "_id" : "82637", "city" : "GLENROCK", "loc" : [ -105.857911, 42.867495 ], "pop" : 3483, "state" : "WY" }
+{ "_id" : "82639", "city" : "KAYCEE", "loc" : [ -106.56323, 43.723625 ], "pop" : 876, "state" : "WY" }
+{ "_id" : "82642", "city" : "LYSITE", "loc" : [ -107.648781, 43.328417 ], "pop" : 81, "state" : "WY" }
+{ "_id" : "82643", "city" : "MIDWEST", "loc" : [ -106.266818, 43.410829 ], "pop" : 756, "state" : "WY" }
+{ "_id" : "82649", "city" : "SHOSHONI", "loc" : [ -108.100667, 43.245707 ], "pop" : 600, "state" : "WY" }
+{ "_id" : "82701", "city" : "NEWCASTLE", "loc" : [ -104.226205, 43.851098 ], "pop" : 4833, "state" : "WY" }
+{ "_id" : "82710", "city" : "ALADDIN", "loc" : [ -104.19314, 44.747331 ], "pop" : 230, "state" : "WY" }
+{ "_id" : "82712", "city" : "BEULAH", "loc" : [ -104.153095, 44.573575 ], "pop" : 187, "state" : "WY" }
+{ "_id" : "82714", "city" : "DEVILS TOWER", "loc" : [ -104.793638, 44.617067 ], "pop" : 119, "state" : "WY" }
+{ "_id" : "82715", "city" : "FOUR CORNERS", "loc" : [ -104.122897, 44.100747 ], "pop" : 38, "state" : "WY" }
+{ "_id" : "82716", "city" : "GILLETTE", "loc" : [ -105.497442, 44.282009 ], "pop" : 25968, "state" : "WY" }
+{ "_id" : "82720", "city" : "HULETT", "loc" : [ -104.617367, 44.735222 ], "pop" : 1054, "state" : "WY" }
+{ "_id" : "82721", "city" : "PINE HAVEN", "loc" : [ -104.905904, 44.299932 ], "pop" : 1820, "state" : "WY" }
+{ "_id" : "82723", "city" : "OSAGE", "loc" : [ -104.4226, 43.998982 ], "pop" : 292, "state" : "WY" }
+{ "_id" : "82724", "city" : "OSHOTO", "loc" : [ -104.937659, 44.583023 ], "pop" : 57, "state" : "WY" }
+{ "_id" : "82725", "city" : "RECLUSE", "loc" : [ -105.776005, 44.786149 ], "pop" : 183, "state" : "WY" }
+{ "_id" : "82727", "city" : "ROZET", "loc" : [ -105.245875, 44.305825 ], "pop" : 900, "state" : "WY" }
+{ "_id" : "82729", "city" : "SUNDANCE", "loc" : [ -104.383696, 44.405755 ], "pop" : 1827, "state" : "WY" }
+{ "_id" : "82730", "city" : "UPTON", "loc" : [ -104.635159, 44.089271 ], "pop" : 1355, "state" : "WY" }
+{ "_id" : "82731", "city" : "GILLETTE", "loc" : [ -105.373236, 44.835689 ], "pop" : 187, "state" : "WY" }
+{ "_id" : "82732", "city" : "WRIGHT", "loc" : [ -105.532327, 43.829349 ], "pop" : 2132, "state" : "WY" }
+{ "_id" : "82801", "city" : "SHERIDAN", "loc" : [ -106.964795, 44.78486 ], "pop" : 20025, "state" : "WY" }
+{ "_id" : "82831", "city" : "ARVADA", "loc" : [ -106.109191, 44.689876 ], "pop" : 107, "state" : "WY" }
+{ "_id" : "82832", "city" : "BANNER", "loc" : [ -106.87331, 44.590804 ], "pop" : 983, "state" : "WY" }
+{ "_id" : "82834", "city" : "BUFFALO", "loc" : [ -106.70726, 44.34847 ], "pop" : 5269, "state" : "WY" }
+{ "_id" : "82835", "city" : "CLEARMONT", "loc" : [ -106.458071, 44.66101 ], "pop" : 350, "state" : "WY" }
+{ "_id" : "82836", "city" : "DAYTON", "loc" : [ -107.302605, 44.877958 ], "pop" : 986, "state" : "WY" }
+{ "_id" : "82838", "city" : "PARKMAN", "loc" : [ -107.325393, 44.964965 ], "pop" : 148, "state" : "WY" }
+{ "_id" : "82839", "city" : "ACME", "loc" : [ -107.159833, 44.904789 ], "pop" : 868, "state" : "WY" }
+{ "_id" : "82842", "city" : "STORY", "loc" : [ -107.049229, 44.607169 ], "pop" : 63, "state" : "WY" }
+{ "_id" : "82844", "city" : "RANCHESTER", "loc" : [ -107.303429, 44.768228 ], "pop" : 32, "state" : "WY" }
+{ "_id" : "82901", "city" : "ROCK SPRINGS", "loc" : [ -109.230047, 41.605957 ], "pop" : 23927, "state" : "WY" }
+{ "_id" : "82922", "city" : "BONDURANT", "loc" : [ -110.335287, 43.223798 ], "pop" : 116, "state" : "WY" }
+{ "_id" : "82923", "city" : "BOULDER", "loc" : [ -109.540105, 42.688146 ], "pop" : 112, "state" : "WY" }
+{ "_id" : "82925", "city" : "CORA", "loc" : [ -109.915351, 43.139921 ], "pop" : 30, "state" : "WY" }
+{ "_id" : "82930", "city" : "EVANSTON", "loc" : [ -110.963067, 41.260947 ], "pop" : 12577, "state" : "WY" }
+{ "_id" : "82933", "city" : "FORT BRIDGER", "loc" : [ -110.347428, 41.28282 ], "pop" : 3777, "state" : "WY" }
+{ "_id" : "82935", "city" : "GREEN RIVER", "loc" : [ -109.471445, 41.51959 ], "pop" : 13956, "state" : "WY" }
+{ "_id" : "82936", "city" : "LONETREE", "loc" : [ -110.172862, 41.049144 ], "pop" : 24, "state" : "WY" }
+{ "_id" : "82937", "city" : "LYMAN", "loc" : [ -110.292629, 41.329136 ], "pop" : 2327, "state" : "WY" }
+{ "_id" : "82938", "city" : "MC KINNON", "loc" : [ -109.874536, 41.040898 ], "pop" : 188, "state" : "WY" }
+{ "_id" : "82941", "city" : "PINEDALE", "loc" : [ -109.856088, 42.854331 ], "pop" : 2326, "state" : "WY" }
+{ "_id" : "83001", "city" : "COLTER BAY", "loc" : [ -110.766277, 43.460734 ], "pop" : 9078, "state" : "WY" }
+{ "_id" : "83011", "city" : "KELLY", "loc" : [ -110.544186, 43.609361 ], "pop" : 203, "state" : "WY" }
+{ "_id" : "83012", "city" : "MOOSE", "loc" : [ -110.857493, 43.771201 ], "pop" : 519, "state" : "WY" }
+{ "_id" : "83013", "city" : "MORAN", "loc" : [ -110.329429, 43.881635 ], "pop" : 191, "state" : "WY" }
+{ "_id" : "83014", "city" : "WILSON", "loc" : [ -110.874199, 43.49922 ], "pop" : 1099, "state" : "WY" }
+{ "_id" : "83101", "city" : "KEMMERER", "loc" : [ -110.52834, 41.788661 ], "pop" : 4258, "state" : "WY" }
+{ "_id" : "83110", "city" : "AFTON", "loc" : [ -110.941976, 42.712829 ], "pop" : 3201, "state" : "WY" }
+{ "_id" : "83111", "city" : "AUBURN", "loc" : [ -110.994415, 42.805114 ], "pop" : 488, "state" : "WY" }
+{ "_id" : "83112", "city" : "BEDFORD", "loc" : [ -110.95556, 42.932336 ], "pop" : 1177, "state" : "WY" }
+{ "_id" : "83113", "city" : "MARBLETON", "loc" : [ -110.132954, 42.552059 ], "pop" : 1861, "state" : "WY" }
+{ "_id" : "83114", "city" : "COKEVILLE", "loc" : [ -110.916419, 42.057983 ], "pop" : 905, "state" : "WY" }
+{ "_id" : "83115", "city" : "DANIEL", "loc" : [ -110.133624, 42.917629 ], "pop" : 398, "state" : "WY" }
+{ "_id" : "83118", "city" : "ETNA", "loc" : [ -111.015996, 43.138606 ], "pop" : 524, "state" : "WY" }
+{ "_id" : "83120", "city" : "FREEDOM", "loc" : [ -111.029178, 43.017167 ], "pop" : 212, "state" : "WY" }
+{ "_id" : "83122", "city" : "GROVER", "loc" : [ -110.924392, 42.796472 ], "pop" : 335, "state" : "WY" }
+{ "_id" : "83123", "city" : "LA BARGE", "loc" : [ -110.210865, 42.24734 ], "pop" : 606, "state" : "WY" }
+{ "_id" : "83126", "city" : "SMOOT", "loc" : [ -110.922351, 42.619238 ], "pop" : 414, "state" : "WY" }
+{ "_id" : "83127", "city" : "THAYNE", "loc" : [ -111.011354, 42.933026 ], "pop" : 505, "state" : "WY" }
+{ "_id" : "83201", "city" : "POCATELLO", "loc" : [ -112.438142, 42.887592 ], "pop" : 33282, "state" : "ID" }
+{ "_id" : "83202", "city" : "CHUBBUCK", "loc" : [ -112.474873, 42.926548 ], "pop" : 11385, "state" : "ID" }
+{ "_id" : "83203", "city" : "FORT HALL", "loc" : [ -112.459854, 42.988717 ], "pop" : 1566, "state" : "ID" }
+{ "_id" : "83204", "city" : "POCATELLO", "loc" : [ -112.443352, 42.846463 ], "pop" : 15605, "state" : "ID" }
+{ "_id" : "83210", "city" : "STERLING", "loc" : [ -112.818124, 42.976717 ], "pop" : 2653, "state" : "ID" }
+{ "_id" : "83211", "city" : "AMERICAN FALLS", "loc" : [ -112.870714, 42.789876 ], "pop" : 5867, "state" : "ID" }
+{ "_id" : "83212", "city" : "ARBON", "loc" : [ -112.558481, 42.502634 ], "pop" : 121, "state" : "ID" }
+{ "_id" : "83213", "city" : "ARCO", "loc" : [ -113.317559, 43.635521 ], "pop" : 1823, "state" : "ID" }
+{ "_id" : "83214", "city" : "ARIMO", "loc" : [ -112.174649, 42.559953 ], "pop" : 333, "state" : "ID" }
+{ "_id" : "83217", "city" : "BANCROFT", "loc" : [ -111.842944, 42.720463 ], "pop" : 988, "state" : "ID" }
+{ "_id" : "83220", "city" : "BERN", "loc" : [ -111.392595, 42.319144 ], "pop" : 261, "state" : "ID" }
+{ "_id" : "83221", "city" : "BLACKFOOT", "loc" : [ -112.361545, 43.194327 ], "pop" : 18202, "state" : "ID" }
+{ "_id" : "83226", "city" : "CHALLIS", "loc" : [ -114.19463, 44.496912 ], "pop" : 2426, "state" : "ID" }
+{ "_id" : "83227", "city" : "CLAYTON", "loc" : [ -114.410189, 44.273289 ], "pop" : 41, "state" : "ID" }
+{ "_id" : "83228", "city" : "CLIFTON", "loc" : [ -111.995737, 42.215972 ], "pop" : 538, "state" : "ID" }
+{ "_id" : "83230", "city" : "CONDA", "loc" : [ -111.54023, 42.717126 ], "pop" : 21, "state" : "ID" }
+{ "_id" : "83231", "city" : "DARLINGTON", "loc" : [ -113.380284, 43.7715 ], "pop" : 12, "state" : "ID" }
+{ "_id" : "83232", "city" : "DAYTON", "loc" : [ -111.985836, 42.11836 ], "pop" : 659, "state" : "ID" }
+{ "_id" : "83234", "city" : "DOWNEY", "loc" : [ -112.109019, 42.418127 ], "pop" : 939, "state" : "ID" }
+{ "_id" : "83235", "city" : "ELLIS", "loc" : [ -114.001594, 44.878829 ], "pop" : 192, "state" : "ID" }
+{ "_id" : "83236", "city" : "FIRTH", "loc" : [ -112.158819, 43.302066 ], "pop" : 2878, "state" : "ID" }
+{ "_id" : "83237", "city" : "FRANKLIN", "loc" : [ -111.822862, 42.030389 ], "pop" : 1699, "state" : "ID" }
+{ "_id" : "83238", "city" : "GENEVA", "loc" : [ -111.072185, 42.313585 ], "pop" : 125, "state" : "ID" }
+{ "_id" : "83241", "city" : "GRACE", "loc" : [ -111.739981, 42.549978 ], "pop" : 2050, "state" : "ID" }
+{ "_id" : "83243", "city" : "HOLBROOK", "loc" : [ -112.693404, 42.222148 ], "pop" : 213, "state" : "ID" }
+{ "_id" : "83245", "city" : "INKOM", "loc" : [ -112.246474, 42.796379 ], "pop" : 823, "state" : "ID" }
+{ "_id" : "83246", "city" : "LAVA HOT SPRINGS", "loc" : [ -112.017644, 42.618474 ], "pop" : 512, "state" : "ID" }
+{ "_id" : "83250", "city" : "MC CAMMON", "loc" : [ -112.175758, 42.63362 ], "pop" : 2603, "state" : "ID" }
+{ "_id" : "83251", "city" : "MACKAY", "loc" : [ -113.611984, 43.91106 ], "pop" : 1207, "state" : "ID" }
+{ "_id" : "83252", "city" : "MALAD CITY", "loc" : [ -112.262045, 42.180783 ], "pop" : 3110, "state" : "ID" }
+{ "_id" : "83253", "city" : "PATTERSON", "loc" : [ -113.916039, 44.701745 ], "pop" : 210, "state" : "ID" }
+{ "_id" : "83254", "city" : "MONTPELIER", "loc" : [ -111.31946, 42.35199 ], "pop" : 4292, "state" : "ID" }
+{ "_id" : "83255", "city" : "MOORE", "loc" : [ -113.260349, 43.782094 ], "pop" : 1083, "state" : "ID" }
+{ "_id" : "83260", "city" : "OVID", "loc" : [ -111.451109, 42.311423 ], "pop" : 290, "state" : "ID" }
+{ "_id" : "83261", "city" : "PARIS", "loc" : [ -111.402938, 42.207065 ], "pop" : 852, "state" : "ID" }
+{ "_id" : "83262", "city" : "PINGREE", "loc" : [ -112.449035, 43.195618 ], "pop" : 7340, "state" : "ID" }
+{ "_id" : "83263", "city" : "PRESTON", "loc" : [ -111.856516, 42.110917 ], "pop" : 5402, "state" : "ID" }
+{ "_id" : "83271", "city" : "ROCKLAND", "loc" : [ -112.853982, 42.555582 ], "pop" : 478, "state" : "ID" }
+{ "_id" : "83272", "city" : "SAINT CHARLES", "loc" : [ -111.389744, 42.112812 ], "pop" : 199, "state" : "ID" }
+{ "_id" : "83274", "city" : "SHELLEY", "loc" : [ -112.107549, 43.376901 ], "pop" : 6164, "state" : "ID" }
+{ "_id" : "83276", "city" : "SODA SPRINGS", "loc" : [ -111.569896, 42.671819 ], "pop" : 3871, "state" : "ID" }
+{ "_id" : "83278", "city" : "STANLEY", "loc" : [ -114.725414, 44.22908 ], "pop" : 444, "state" : "ID" }
+{ "_id" : "83280", "city" : "STONE", "loc" : [ -112.711473, 42.038983 ], "pop" : 169, "state" : "ID" }
+{ "_id" : "83283", "city" : "THATCHER", "loc" : [ -111.78899, 42.331959 ], "pop" : 207, "state" : "ID" }
+{ "_id" : "83285", "city" : "WAYAN", "loc" : [ -111.254056, 43.02691 ], "pop" : 117, "state" : "ID" }
+{ "_id" : "83286", "city" : "WESTON", "loc" : [ -111.97154, 42.044621 ], "pop" : 727, "state" : "ID" }
+{ "_id" : "83287", "city" : "FISH HAVEN", "loc" : [ -111.463323, 42.045926 ], "pop" : 65, "state" : "ID" }
+{ "_id" : "83301", "city" : "TWIN FALLS", "loc" : [ -114.469265, 42.556495 ], "pop" : 34539, "state" : "ID" }
+{ "_id" : "83302", "city" : "ROGERSON", "loc" : [ -114.603794, 42.219567 ], "pop" : 92, "state" : "ID" }
+{ "_id" : "83313", "city" : "BELLEVUE", "loc" : [ -114.249804, 43.439694 ], "pop" : 2150, "state" : "ID" }
+{ "_id" : "83314", "city" : "BLISS", "loc" : [ -114.910387, 42.944859 ], "pop" : 845, "state" : "ID" }
+{ "_id" : "83316", "city" : "BUHL", "loc" : [ -114.782545, 42.600763 ], "pop" : 8014, "state" : "ID" }
+{ "_id" : "83318", "city" : "BURLEY", "loc" : [ -113.793081, 42.524442 ], "pop" : 12406, "state" : "ID" }
+{ "_id" : "83320", "city" : "CAREY", "loc" : [ -113.892567, 43.274443 ], "pop" : 820, "state" : "ID" }
+{ "_id" : "83321", "city" : "CASTLEFORD", "loc" : [ -114.873433, 42.521015 ], "pop" : 365, "state" : "ID" }
+{ "_id" : "83322", "city" : "CORRAL", "loc" : [ -115.00871, 43.307127 ], "pop" : 59, "state" : "ID" }
+{ "_id" : "83323", "city" : "DECLO", "loc" : [ -113.644794, 42.524005 ], "pop" : 2592, "state" : "ID" }
+{ "_id" : "83324", "city" : "DIETRICH", "loc" : [ -114.266408, 42.91254 ], "pop" : 178, "state" : "ID" }
+{ "_id" : "83325", "city" : "EDEN", "loc" : [ -114.162762, 42.580374 ], "pop" : 1762, "state" : "ID" }
+{ "_id" : "83326", "city" : "ELBA", "loc" : [ -113.663559, 42.180865 ], "pop" : 163, "state" : "ID" }
+{ "_id" : "83327", "city" : "FAIRFIELD", "loc" : [ -114.790845, 43.367504 ], "pop" : 668, "state" : "ID" }
+{ "_id" : "83328", "city" : "FILER", "loc" : [ -114.614047, 42.565269 ], "pop" : 4176, "state" : "ID" }
+{ "_id" : "83330", "city" : "GOODING", "loc" : [ -114.711966, 42.937345 ], "pop" : 4846, "state" : "ID" }
+{ "_id" : "83332", "city" : "HAGERMAN", "loc" : [ -114.88697, 42.814205 ], "pop" : 1613, "state" : "ID" }
+{ "_id" : "83333", "city" : "HAILEY", "loc" : [ -114.306398, 43.523861 ], "pop" : 4683, "state" : "ID" }
+{ "_id" : "83334", "city" : "HANSEN", "loc" : [ -114.299364, 42.524895 ], "pop" : 1525, "state" : "ID" }
+{ "_id" : "83335", "city" : "HAZELTON", "loc" : [ -114.134984, 42.595462 ], "pop" : 705, "state" : "ID" }
+{ "_id" : "83336", "city" : "HEYBURN", "loc" : [ -113.770885, 42.559922 ], "pop" : 4757, "state" : "ID" }
+{ "_id" : "83338", "city" : "JEROME", "loc" : [ -114.501244, 42.71784 ], "pop" : 12671, "state" : "ID" }
+{ "_id" : "83340", "city" : "OBSIDIAN", "loc" : [ -114.373664, 43.675459 ], "pop" : 5823, "state" : "ID" }
+{ "_id" : "83341", "city" : "KIMBERLY", "loc" : [ -114.365725, 42.528656 ], "pop" : 3779, "state" : "ID" }
+{ "_id" : "83342", "city" : "NAF", "loc" : [ -113.448656, 42.364652 ], "pop" : 2315, "state" : "ID" }
+{ "_id" : "83343", "city" : "MINIDOKA", "loc" : [ -113.620033, 42.759784 ], "pop" : 1379, "state" : "ID" }
+{ "_id" : "83344", "city" : "MURTAUGH", "loc" : [ -114.160641, 42.477597 ], "pop" : 1019, "state" : "ID" }
+{ "_id" : "83346", "city" : "OAKLEY", "loc" : [ -113.906945, 42.347561 ], "pop" : 2056, "state" : "ID" }
+{ "_id" : "83347", "city" : "PAUL", "loc" : [ -113.797125, 42.623999 ], "pop" : 3464, "state" : "ID" }
+{ "_id" : "83348", "city" : "PICABO", "loc" : [ -114.086065, 43.310149 ], "pop" : 76, "state" : "ID" }
+{ "_id" : "83349", "city" : "RICHFIELD", "loc" : [ -114.15079, 43.058839 ], "pop" : 789, "state" : "ID" }
+{ "_id" : "83350", "city" : "ACEQUIA", "loc" : [ -113.66699, 42.621467 ], "pop" : 9761, "state" : "ID" }
+{ "_id" : "83352", "city" : "SHOSHONE", "loc" : [ -114.382176, 42.947353 ], "pop" : 2341, "state" : "ID" }
+{ "_id" : "83355", "city" : "WENDELL", "loc" : [ -114.715391, 42.757868 ], "pop" : 4400, "state" : "ID" }
+{ "_id" : "83401", "city" : "AMMON", "loc" : [ -111.990626, 43.517679 ], "pop" : 27974, "state" : "ID" }
+{ "_id" : "83402", "city" : "IDAHO FALLS", "loc" : [ -112.057762, 43.493373 ], "pop" : 20716, "state" : "ID" }
+{ "_id" : "83404", "city" : "IDAHO FALLS", "loc" : [ -112.012449, 43.475043 ], "pop" : 14962, "state" : "ID" }
+{ "_id" : "83406", "city" : "IDAHO FALLS", "loc" : [ -111.966052, 43.473233 ], "pop" : 5935, "state" : "ID" }
+{ "_id" : "83420", "city" : "ASHTON", "loc" : [ -111.619526, 43.988078 ], "pop" : 8639, "state" : "ID" }
+{ "_id" : "83422", "city" : "DRIGGS", "loc" : [ -111.119896, 43.726291 ], "pop" : 1495, "state" : "ID" }
+{ "_id" : "83423", "city" : "DUBOIS", "loc" : [ -112.325852, 44.185769 ], "pop" : 650, "state" : "ID" }
+{ "_id" : "83424", "city" : "FELT", "loc" : [ -111.189496, 43.872407 ], "pop" : 40, "state" : "ID" }
+{ "_id" : "83425", "city" : "HAMER", "loc" : [ -112.187189, 43.930751 ], "pop" : 396, "state" : "ID" }
+{ "_id" : "83427", "city" : "IONA", "loc" : [ -111.928356, 43.525946 ], "pop" : 1491, "state" : "ID" }
+{ "_id" : "83429", "city" : "ISLAND PARK", "loc" : [ -111.367914, 44.446606 ], "pop" : 35, "state" : "ID" }
+{ "_id" : "83431", "city" : "LEWISVILLE", "loc" : [ -112.018884, 43.672476 ], "pop" : 1565, "state" : "ID" }
+{ "_id" : "83434", "city" : "MENAN", "loc" : [ -111.983702, 43.726576 ], "pop" : 1789, "state" : "ID" }
+{ "_id" : "83435", "city" : "MONTEVIEW", "loc" : [ -112.578321, 43.986242 ], "pop" : 441, "state" : "ID" }
+{ "_id" : "83436", "city" : "NEWDALE", "loc" : [ -111.604192, 43.888078 ], "pop" : 430, "state" : "ID" }
+{ "_id" : "83440", "city" : "REXBURG", "loc" : [ -111.789022, 43.809968 ], "pop" : 19157, "state" : "ID" }
+{ "_id" : "83442", "city" : "RIGBY", "loc" : [ -111.900481, 43.671462 ], "pop" : 8178, "state" : "ID" }
+{ "_id" : "83443", "city" : "RIRIE", "loc" : [ -111.760692, 43.631961 ], "pop" : 1749, "state" : "ID" }
+{ "_id" : "83444", "city" : "ROBERTS", "loc" : [ -112.119591, 43.7116 ], "pop" : 1436, "state" : "ID" }
+{ "_id" : "83445", "city" : "SAINT ANTHONY", "loc" : [ -111.523156, 44.274499 ], "pop" : 747, "state" : "ID" }
+{ "_id" : "83446", "city" : "SPENCER", "loc" : [ -112.098821, 44.281444 ], "pop" : 112, "state" : "ID" }
+{ "_id" : "83448", "city" : "SUGAR CITY", "loc" : [ -111.79004, 43.866852 ], "pop" : 4517, "state" : "ID" }
+{ "_id" : "83449", "city" : "SWAN VALLEY", "loc" : [ -111.279358, 43.405826 ], "pop" : 441, "state" : "ID" }
+{ "_id" : "83450", "city" : "TERRETON", "loc" : [ -112.420041, 43.858635 ], "pop" : 1537, "state" : "ID" }
+{ "_id" : "83451", "city" : "TETON", "loc" : [ -111.668145, 43.898751 ], "pop" : 1086, "state" : "ID" }
+{ "_id" : "83452", "city" : "TETONIA", "loc" : [ -111.186997, 43.843713 ], "pop" : 820, "state" : "ID" }
+{ "_id" : "83455", "city" : "VICTOR", "loc" : [ -111.125934, 43.614827 ], "pop" : 1084, "state" : "ID" }
+{ "_id" : "83462", "city" : "CARMEN", "loc" : [ -113.857267, 45.255016 ], "pop" : 195, "state" : "ID" }
+{ "_id" : "83463", "city" : "GIBBONSVILLE", "loc" : [ -113.956466, 45.484608 ], "pop" : 230, "state" : "ID" }
+{ "_id" : "83464", "city" : "LEADORE", "loc" : [ -113.492586, 44.738909 ], "pop" : 594, "state" : "ID" }
+{ "_id" : "83466", "city" : "NORTH FORK", "loc" : [ -113.857287, 45.377605 ], "pop" : 267, "state" : "ID" }
+{ "_id" : "83467", "city" : "SALMON", "loc" : [ -113.878356, 45.157142 ], "pop" : 5159, "state" : "ID" }
+{ "_id" : "83469", "city" : "SHOUP", "loc" : [ -114.405987, 45.18514 ], "pop" : 67, "state" : "ID" }
+{ "_id" : "83501", "city" : "SOUTH GATE PLAZA", "loc" : [ -116.987714, 46.389457 ], "pop" : 29650, "state" : "ID" }
+{ "_id" : "83520", "city" : "AHSAHKA", "loc" : [ -116.371537, 46.510318 ], "pop" : 335, "state" : "ID" }
+{ "_id" : "83522", "city" : "COTTONWOOD", "loc" : [ -116.373306, 46.044789 ], "pop" : 1791, "state" : "ID" }
+{ "_id" : "83523", "city" : "CRAIGMONT", "loc" : [ -116.467655, 46.245292 ], "pop" : 820, "state" : "ID" }
+{ "_id" : "83524", "city" : "CULDESAC", "loc" : [ -116.653579, 46.378012 ], "pop" : 1161, "state" : "ID" }
+{ "_id" : "83525", "city" : "DIXIE", "loc" : [ -115.359158, 45.888897 ], "pop" : 755, "state" : "ID" }
+{ "_id" : "83526", "city" : "FERDINAND", "loc" : [ -116.39817, 46.134877 ], "pop" : 323, "state" : "ID" }
+{ "_id" : "83530", "city" : "GRANGEVILLE", "loc" : [ -116.107639, 45.927239 ], "pop" : 4791, "state" : "ID" }
+{ "_id" : "83533", "city" : "GREENCREEK", "loc" : [ -116.27239, 46.115523 ], "pop" : 269, "state" : "ID" }
+{ "_id" : "83535", "city" : "JULIAETTA", "loc" : [ -116.718849, 46.575376 ], "pop" : 1014, "state" : "ID" }
+{ "_id" : "83536", "city" : "KAMIAH", "loc" : [ -116.034742, 46.21856 ], "pop" : 2970, "state" : "ID" }
+{ "_id" : "83537", "city" : "KENDRICK", "loc" : [ -116.604895, 46.628628 ], "pop" : 970, "state" : "ID" }
+{ "_id" : "83538", "city" : "KEUTERVILLE", "loc" : [ -116.535583, 45.929443 ], "pop" : 0, "state" : "ID" }
+{ "_id" : "83539", "city" : "CLEARWATER", "loc" : [ -115.92396, 46.125859 ], "pop" : 2704, "state" : "ID" }
+{ "_id" : "83540", "city" : "LAPWAI", "loc" : [ -116.790225, 46.412403 ], "pop" : 1784, "state" : "ID" }
+{ "_id" : "83541", "city" : "LENORE", "loc" : [ -116.513015, 46.535408 ], "pop" : 473, "state" : "ID" }
+{ "_id" : "83542", "city" : "LUCILE", "loc" : [ -116.266899, 45.556963 ], "pop" : 216, "state" : "ID" }
+{ "_id" : "83543", "city" : "NEZPERCE", "loc" : [ -116.239281, 46.247533 ], "pop" : 650, "state" : "ID" }
+{ "_id" : "83544", "city" : "OROFINO", "loc" : [ -116.240417, 46.495197 ], "pop" : 5738, "state" : "ID" }
+{ "_id" : "83545", "city" : "PECK", "loc" : [ -116.411394, 46.480661 ], "pop" : 295, "state" : "ID" }
+{ "_id" : "83546", "city" : "PIERCE", "loc" : [ -115.807071, 46.492424 ], "pop" : 900, "state" : "ID" }
+{ "_id" : "83547", "city" : "POLLOCK", "loc" : [ -116.351742, 45.306754 ], "pop" : 274, "state" : "ID" }
+{ "_id" : "83548", "city" : "REUBENS", "loc" : [ -116.533334, 46.336112 ], "pop" : 121, "state" : "ID" }
+{ "_id" : "83549", "city" : "RIGGINS", "loc" : [ -116.300553, 45.397006 ], "pop" : 818, "state" : "ID" }
+{ "_id" : "83553", "city" : "WEIPPE", "loc" : [ -115.938593, 46.38069 ], "pop" : 1193, "state" : "ID" }
+{ "_id" : "83554", "city" : "WHITE BIRD", "loc" : [ -116.2889, 45.752096 ], "pop" : 393, "state" : "ID" }
+{ "_id" : "83555", "city" : "WINCHESTER", "loc" : [ -116.620382, 46.238334 ], "pop" : 380, "state" : "ID" }
+{ "_id" : "83601", "city" : "ATLANTA", "loc" : [ -115.357042, 43.567436 ], "pop" : 208, "state" : "ID" }
+{ "_id" : "83602", "city" : "BANKS", "loc" : [ -115.983737, 44.149152 ], "pop" : 494, "state" : "ID" }
+{ "_id" : "83604", "city" : "GRASMERE", "loc" : [ -115.677259, 42.76006 ], "pop" : 609, "state" : "ID" }
+{ "_id" : "83605", "city" : "CALDWELL", "loc" : [ -116.700038, 43.662719 ], "pop" : 32407, "state" : "ID" }
+{ "_id" : "83610", "city" : "CAMBRIDGE", "loc" : [ -116.675717, 44.59216 ], "pop" : 962, "state" : "ID" }
+{ "_id" : "83611", "city" : "WEST MOUNTAIN", "loc" : [ -116.027676, 44.493273 ], "pop" : 1681, "state" : "ID" }
+{ "_id" : "83612", "city" : "COUNCIL", "loc" : [ -116.451833, 44.762754 ], "pop" : 1606, "state" : "ID" }
+{ "_id" : "83615", "city" : "DONNELLY", "loc" : [ -116.08578, 44.74937 ], "pop" : 681, "state" : "ID" }
+{ "_id" : "83616", "city" : "EAGLE", "loc" : [ -116.361966, 43.706879 ], "pop" : 6874, "state" : "ID" }
+{ "_id" : "83617", "city" : "MONTOUR", "loc" : [ -116.511459, 43.879152 ], "pop" : 11189, "state" : "ID" }
+{ "_id" : "83619", "city" : "FRUITLAND", "loc" : [ -116.914259, 44.002658 ], "pop" : 4611, "state" : "ID" }
+{ "_id" : "83622", "city" : "GARDEN VALLEY", "loc" : [ -115.824311, 44.090932 ], "pop" : 513, "state" : "ID" }
+{ "_id" : "83623", "city" : "GLENNS FERRY", "loc" : [ -115.315973, 42.962202 ], "pop" : 2040, "state" : "ID" }
+{ "_id" : "83624", "city" : "GRAND VIEW", "loc" : [ -116.08187, 42.810101 ], "pop" : 1449, "state" : "ID" }
+{ "_id" : "83627", "city" : "HAMMETT", "loc" : [ -115.565839, 42.981755 ], "pop" : 73, "state" : "ID" }
+{ "_id" : "83628", "city" : "HOMEDALE", "loc" : [ -116.947228, 43.613844 ], "pop" : 3079, "state" : "ID" }
+{ "_id" : "83629", "city" : "HORSESHOE BEND", "loc" : [ -116.180898, 43.922882 ], "pop" : 1111, "state" : "ID" }
+{ "_id" : "83631", "city" : "IDAHO CITY", "loc" : [ -115.918436, 43.758601 ], "pop" : 1324, "state" : "ID" }
+{ "_id" : "83632", "city" : "INDIAN VALLEY", "loc" : [ -116.442969, 44.549134 ], "pop" : 188, "state" : "ID" }
+{ "_id" : "83633", "city" : "KING HILL", "loc" : [ -115.269098, 42.936104 ], "pop" : 357, "state" : "ID" }
+{ "_id" : "83634", "city" : "KUNA", "loc" : [ -116.381859, 43.487034 ], "pop" : 8141, "state" : "ID" }
+{ "_id" : "83636", "city" : "LETHA", "loc" : [ -116.585004, 43.840306 ], "pop" : 29, "state" : "ID" }
+{ "_id" : "83637", "city" : "LOWMAN", "loc" : [ -115.528488, 44.110616 ], "pop" : 63, "state" : "ID" }
+{ "_id" : "83638", "city" : "MC CALL", "loc" : [ -116.078873, 44.891784 ], "pop" : 3681, "state" : "ID" }
+{ "_id" : "83639", "city" : "MARSING", "loc" : [ -116.823968, 43.539866 ], "pop" : 2281, "state" : "ID" }
+{ "_id" : "83641", "city" : "MELBA", "loc" : [ -116.548875, 43.37842 ], "pop" : 1116, "state" : "ID" }
+{ "_id" : "83642", "city" : "MERIDIAN", "loc" : [ -116.397538, 43.614963 ], "pop" : 19033, "state" : "ID" }
+{ "_id" : "83643", "city" : "MESA", "loc" : [ -116.42113, 44.657747 ], "pop" : 279, "state" : "ID" }
+{ "_id" : "83644", "city" : "MIDDLETON", "loc" : [ -116.61122, 43.719052 ], "pop" : 3898, "state" : "ID" }
+{ "_id" : "83645", "city" : "MIDVALE", "loc" : [ -116.703838, 44.441979 ], "pop" : 621, "state" : "ID" }
+{ "_id" : "83647", "city" : "MOUNTAIN HOME", "loc" : [ -115.696334, 43.139223 ], "pop" : 12235, "state" : "ID" }
+{ "_id" : "83648", "city" : "MOUNTAIN HOME A", "loc" : [ -115.873609, 43.049315 ], "pop" : 6304, "state" : "ID" }
+{ "_id" : "83650", "city" : "OREANA", "loc" : [ -116.605379, 43.207296 ], "pop" : 1156, "state" : "ID" }
+{ "_id" : "83651", "city" : "NAMPA", "loc" : [ -116.584818, 43.58342 ], "pop" : 16068, "state" : "ID" }
+{ "_id" : "83654", "city" : "NEW MEADOWS", "loc" : [ -116.287438, 44.993969 ], "pop" : 1179, "state" : "ID" }
+{ "_id" : "83655", "city" : "NEW PLYMOUTH", "loc" : [ -116.804818, 43.959021 ], "pop" : 3165, "state" : "ID" }
+{ "_id" : "83657", "city" : "OLA", "loc" : [ -116.290915, 44.235026 ], "pop" : 159, "state" : "ID" }
+{ "_id" : "83660", "city" : "PARMA", "loc" : [ -116.940066, 43.789576 ], "pop" : 4477, "state" : "ID" }
+{ "_id" : "83661", "city" : "PAYETTE", "loc" : [ -116.920277, 44.07818 ], "pop" : 7913, "state" : "ID" }
+{ "_id" : "83669", "city" : "STAR", "loc" : [ -116.496735, 43.701296 ], "pop" : 1579, "state" : "ID" }
+{ "_id" : "83670", "city" : "SWEET", "loc" : [ -116.323215, 43.99475 ], "pop" : 344, "state" : "ID" }
+{ "_id" : "83672", "city" : "WEISER", "loc" : [ -116.96507, 44.25222 ], "pop" : 6967, "state" : "ID" }
+{ "_id" : "83676", "city" : "WILDER", "loc" : [ -116.912199, 43.657851 ], "pop" : 3042, "state" : "ID" }
+{ "_id" : "83677", "city" : "YELLOW PINE", "loc" : [ -115.49634, 44.969809 ], "pop" : 68, "state" : "ID" }
+{ "_id" : "83686", "city" : "NAMPA", "loc" : [ -116.565962, 43.544125 ], "pop" : 17886, "state" : "ID" }
+{ "_id" : "83687", "city" : "NAMPA", "loc" : [ -116.536024, 43.593657 ], "pop" : 10589, "state" : "ID" }
+{ "_id" : "83702", "city" : "BOISE", "loc" : [ -116.205192, 43.632237 ], "pop" : 19423, "state" : "ID" }
+{ "_id" : "83703", "city" : "BOISE", "loc" : [ -116.252396, 43.660051 ], "pop" : 17005, "state" : "ID" }
+{ "_id" : "83704", "city" : "BOISE", "loc" : [ -116.295099, 43.633001 ], "pop" : 40912, "state" : "ID" }
+{ "_id" : "83705", "city" : "BOISE", "loc" : [ -116.219104, 43.585077 ], "pop" : 25402, "state" : "ID" }
+{ "_id" : "83706", "city" : "BOISE", "loc" : [ -116.191006, 43.588495 ], "pop" : 24826, "state" : "ID" }
+{ "_id" : "83709", "city" : "BOISE", "loc" : [ -116.29407, 43.574085 ], "pop" : 30382, "state" : "ID" }
+{ "_id" : "83712", "city" : "BOISE", "loc" : [ -116.164924, 43.602311 ], "pop" : 7572, "state" : "ID" }
+{ "_id" : "83714", "city" : "GARDEN CITY", "loc" : [ -116.265751, 43.643036 ], "pop" : 5897, "state" : "ID" }
+{ "_id" : "83801", "city" : "ATHOL", "loc" : [ -116.731821, 47.92674 ], "pop" : 2520, "state" : "ID" }
+{ "_id" : "83802", "city" : "AVERY", "loc" : [ -115.866012, 47.271431 ], "pop" : 113, "state" : "ID" }
+{ "_id" : "83803", "city" : "BAYVIEW", "loc" : [ -116.568745, 47.96535 ], "pop" : 722, "state" : "ID" }
+{ "_id" : "83804", "city" : "BLANCHARD", "loc" : [ -116.990865, 48.022344 ], "pop" : 507, "state" : "ID" }
+{ "_id" : "83805", "city" : "BONNERS FERRY", "loc" : [ -116.332178, 48.730642 ], "pop" : 5219, "state" : "ID" }
+{ "_id" : "83808", "city" : "CALDER", "loc" : [ -116.222793, 47.274135 ], "pop" : 77, "state" : "ID" }
+{ "_id" : "83809", "city" : "CAREYWOOD", "loc" : [ -116.598761, 48.062494 ], "pop" : 361, "state" : "ID" }
+{ "_id" : "83810", "city" : "CATALDO", "loc" : [ -116.443138, 47.552169 ], "pop" : 982, "state" : "ID" }
+{ "_id" : "83811", "city" : "CLARK FORK", "loc" : [ -116.169865, 48.140457 ], "pop" : 971, "state" : "ID" }
+{ "_id" : "83812", "city" : "CLARKIA", "loc" : [ -116.277408, 47.044477 ], "pop" : 85, "state" : "ID" }
+{ "_id" : "83813", "city" : "COCOLALLA", "loc" : [ -116.657051, 48.124828 ], "pop" : 715, "state" : "ID" }
+{ "_id" : "83814", "city" : "COEUR D ALENE", "loc" : [ -116.784976, 47.692841 ], "pop" : 33589, "state" : "ID" }
+{ "_id" : "83821", "city" : "COOLIN", "loc" : [ -116.840823, 48.522754 ], "pop" : 194, "state" : "ID" }
+{ "_id" : "83822", "city" : "OLD TOWN", "loc" : [ -116.927382, 48.187988 ], "pop" : 2229, "state" : "ID" }
+{ "_id" : "83823", "city" : "DEARY", "loc" : [ -116.523782, 46.806062 ], "pop" : 1483, "state" : "ID" }
+{ "_id" : "83824", "city" : "DESMET", "loc" : [ -116.893746, 47.125954 ], "pop" : 265, "state" : "ID" }
+{ "_id" : "83827", "city" : "ELK RIVER", "loc" : [ -116.179943, 46.782972 ], "pop" : 154, "state" : "ID" }
+{ "_id" : "83830", "city" : "FERNWOOD", "loc" : [ -116.383126, 47.116027 ], "pop" : 372, "state" : "ID" }
+{ "_id" : "83832", "city" : "GENESEE", "loc" : [ -116.928991, 46.571394 ], "pop" : 1241, "state" : "ID" }
+{ "_id" : "83833", "city" : "HARRISON", "loc" : [ -116.744607, 47.501692 ], "pop" : 1077, "state" : "ID" }
+{ "_id" : "83834", "city" : "HARVARD", "loc" : [ -116.702524, 46.937647 ], "pop" : 226, "state" : "ID" }
+{ "_id" : "83835", "city" : "HAYDEN LAKE", "loc" : [ -116.776821, 47.773853 ], "pop" : 9287, "state" : "ID" }
+{ "_id" : "83836", "city" : "HOPE", "loc" : [ -116.279504, 48.244402 ], "pop" : 687, "state" : "ID" }
+{ "_id" : "83837", "city" : "KELLOGG", "loc" : [ -116.125281, 47.543069 ], "pop" : 4640, "state" : "ID" }
+{ "_id" : "83839", "city" : "KINGSTON", "loc" : [ -116.288722, 47.550881 ], "pop" : 690, "state" : "ID" }
+{ "_id" : "83842", "city" : "MEDIMONT", "loc" : [ -116.568291, 47.462482 ], "pop" : 32, "state" : "ID" }
+{ "_id" : "83843", "city" : "MOSCOW", "loc" : [ -116.989683, 46.730921 ], "pop" : 21714, "state" : "ID" }
+{ "_id" : "83845", "city" : "MOYIE SPRINGS", "loc" : [ -116.179603, 48.746434 ], "pop" : 1496, "state" : "ID" }
+{ "_id" : "83846", "city" : "MULLAN", "loc" : [ -115.792603, 47.470906 ], "pop" : 995, "state" : "ID" }
+{ "_id" : "83847", "city" : "NAPLES", "loc" : [ -116.319636, 48.60491 ], "pop" : 1556, "state" : "ID" }
+{ "_id" : "83848", "city" : "NORDMAN", "loc" : [ -116.92126, 48.566944 ], "pop" : 446, "state" : "ID" }
+{ "_id" : "83850", "city" : "PINEHURST", "loc" : [ -116.264679, 47.501823 ], "pop" : 371, "state" : "ID" }
+{ "_id" : "83851", "city" : "PLUMMER", "loc" : [ -116.866161, 47.327782 ], "pop" : 1439, "state" : "ID" }
+{ "_id" : "83853", "city" : "PORTHILL", "loc" : [ -116.477517, 48.992037 ], "pop" : 61, "state" : "ID" }
+{ "_id" : "83854", "city" : "POST FALLS", "loc" : [ -116.935349, 47.720475 ], "pop" : 14952, "state" : "ID" }
+{ "_id" : "83855", "city" : "POTLATCH", "loc" : [ -116.914101, 46.944833 ], "pop" : 1836, "state" : "ID" }
+{ "_id" : "83856", "city" : "PRIEST RIVER", "loc" : [ -116.906617, 48.16637 ], "pop" : 4345, "state" : "ID" }
+{ "_id" : "83857", "city" : "PRINCETON", "loc" : [ -116.828728, 46.899556 ], "pop" : 733, "state" : "ID" }
+{ "_id" : "83858", "city" : "RATHDRUM", "loc" : [ -116.887294, 47.824107 ], "pop" : 4798, "state" : "ID" }
+{ "_id" : "83860", "city" : "SAGLE", "loc" : [ -116.5455, 48.2035 ], "pop" : 3512, "state" : "ID" }
+{ "_id" : "83861", "city" : "SAINT MARIES", "loc" : [ -116.568107, 47.297727 ], "pop" : 5894, "state" : "ID" }
+{ "_id" : "83864", "city" : "SANDPOINT", "loc" : [ -116.533249, 48.311989 ], "pop" : 12421, "state" : "ID" }
+{ "_id" : "83868", "city" : "SMELTERVILLE", "loc" : [ -116.240113, 47.537096 ], "pop" : 2272, "state" : "ID" }
+{ "_id" : "83869", "city" : "SPIRIT LAKE", "loc" : [ -116.868046, 47.965652 ], "pop" : 860, "state" : "ID" }
+{ "_id" : "83870", "city" : "TENSED", "loc" : [ -116.902716, 47.170735 ], "pop" : 332, "state" : "ID" }
+{ "_id" : "83871", "city" : "TROY", "loc" : [ -116.768105, 46.742648 ], "pop" : 1481, "state" : "ID" }
+{ "_id" : "83872", "city" : "VIOLA", "loc" : [ -116.97319, 46.858293 ], "pop" : 519, "state" : "ID" }
+{ "_id" : "83873", "city" : "WALLACE", "loc" : [ -115.962001, 47.490842 ], "pop" : 4688, "state" : "ID" }
+{ "_id" : "83876", "city" : "WORLEY", "loc" : [ -116.905634, 47.429213 ], "pop" : 845, "state" : "ID" }
+{ "_id" : "84001", "city" : "ALTAMONT", "loc" : [ -110.446356, 40.370225 ], "pop" : 146, "state" : "UT" }
+{ "_id" : "84002", "city" : "ALTONAH", "loc" : [ -110.438499, 40.441894 ], "pop" : 10, "state" : "UT" }
+{ "_id" : "84003", "city" : "AMERICAN FORK", "loc" : [ -111.794107, 40.392784 ], "pop" : 21864, "state" : "UT" }
+{ "_id" : "84004", "city" : "ALPINE", "loc" : [ -111.768861, 40.461591 ], "pop" : 3665, "state" : "UT" }
+{ "_id" : "84006", "city" : "BINGHAM CANYON", "loc" : [ -112.097718, 40.564614 ], "pop" : 631, "state" : "UT" }
+{ "_id" : "84007", "city" : "BLUEBELL", "loc" : [ -110.294122, 40.351728 ], "pop" : 1443, "state" : "UT" }
+{ "_id" : "84010", "city" : "BOUNTIFUL", "loc" : [ -111.872658, 40.877513 ], "pop" : 41077, "state" : "UT" }
+{ "_id" : "84012", "city" : "BRIDGELAND", "loc" : [ -110.160264, 40.230411 ], "pop" : 849, "state" : "UT" }
+{ "_id" : "84013", "city" : "CEDAR VALLEY", "loc" : [ -111.968985, 40.142516 ], "pop" : 1836, "state" : "UT" }
+{ "_id" : "84014", "city" : "CENTERVILLE", "loc" : [ -111.87701, 40.926772 ], "pop" : 11989, "state" : "UT" }
+{ "_id" : "84015", "city" : "CLEARFIELD", "loc" : [ -112.048224, 41.129388 ], "pop" : 25972, "state" : "UT" }
+{ "_id" : "84017", "city" : "COALVILLE", "loc" : [ -111.407108, 40.924385 ], "pop" : 3217, "state" : "UT" }
+{ "_id" : "84018", "city" : "CROYDON", "loc" : [ -111.523092, 41.068915 ], "pop" : 117, "state" : "UT" }
+{ "_id" : "84020", "city" : "DRAPER", "loc" : [ -111.88096, 40.504599 ], "pop" : 5602, "state" : "UT" }
+{ "_id" : "84021", "city" : "DUCHESNE", "loc" : [ -110.618094, 39.95398 ], "pop" : 38, "state" : "UT" }
+{ "_id" : "84022", "city" : "DUGWAY", "loc" : [ -112.872905, 40.526892 ], "pop" : 79, "state" : "UT" }
+{ "_id" : "84023", "city" : "DUTCH JOHN", "loc" : [ -109.354255, 40.932244 ], "pop" : 174, "state" : "UT" }
+{ "_id" : "84025", "city" : "FARMINGTON", "loc" : [ -111.893785, 40.988913 ], "pop" : 10307, "state" : "UT" }
+{ "_id" : "84026", "city" : "FORT DUCHESNE", "loc" : [ -109.863726, 40.301411 ], "pop" : 1649, "state" : "UT" }
+{ "_id" : "84028", "city" : "GARDEN CITY", "loc" : [ -111.407033, 41.93764 ], "pop" : 254, "state" : "UT" }
+{ "_id" : "84029", "city" : "GRANTSVILLE", "loc" : [ -112.461766, 40.60054 ], "pop" : 4741, "state" : "UT" }
+{ "_id" : "84031", "city" : "HANNA", "loc" : [ -110.809748, 40.450135 ], "pop" : 54, "state" : "UT" }
+{ "_id" : "84032", "city" : "HEBER CITY", "loc" : [ -111.405088, 40.494703 ], "pop" : 7913, "state" : "UT" }
+{ "_id" : "84035", "city" : "JENSEN", "loc" : [ -109.350982, 40.378715 ], "pop" : 471, "state" : "UT" }
+{ "_id" : "84036", "city" : "KAMAS", "loc" : [ -111.261877, 40.641432 ], "pop" : 2433, "state" : "UT" }
+{ "_id" : "84037", "city" : "KAYSVILLE", "loc" : [ -111.932607, 41.037527 ], "pop" : 21132, "state" : "UT" }
+{ "_id" : "84038", "city" : "LAKETOWN", "loc" : [ -111.268853, 41.81068 ], "pop" : 430, "state" : "UT" }
+{ "_id" : "84039", "city" : "LAPOINT", "loc" : [ -109.804102, 40.400285 ], "pop" : 362, "state" : "UT" }
+{ "_id" : "84040", "city" : "LAYTON", "loc" : [ -111.927365, 41.084576 ], "pop" : 13289, "state" : "UT" }
+{ "_id" : "84041", "city" : "LAYTON", "loc" : [ -111.970354, 41.087905 ], "pop" : 33600, "state" : "UT" }
+{ "_id" : "84042", "city" : "LINDON", "loc" : [ -111.714358, 40.34119 ], "pop" : 3819, "state" : "UT" }
+{ "_id" : "84043", "city" : "LEHI", "loc" : [ -111.850606, 40.395845 ], "pop" : 9188, "state" : "UT" }
+{ "_id" : "84044", "city" : "MAGNA", "loc" : [ -112.080867, 40.700879 ], "pop" : 17841, "state" : "UT" }
+{ "_id" : "84046", "city" : "MANILA", "loc" : [ -109.723503, 40.968494 ], "pop" : 516, "state" : "UT" }
+{ "_id" : "84047", "city" : "MIDVALE", "loc" : [ -111.885066, 40.615178 ], "pop" : 25001, "state" : "UT" }
+{ "_id" : "84049", "city" : "MIDWAY", "loc" : [ -111.477575, 40.50934 ], "pop" : 1837, "state" : "UT" }
+{ "_id" : "84050", "city" : "MORGAN", "loc" : [ -111.716339, 41.067832 ], "pop" : 5411, "state" : "UT" }
+{ "_id" : "84051", "city" : "MOUNTAIN HOME", "loc" : [ -110.767018, 40.191999 ], "pop" : 236, "state" : "UT" }
+{ "_id" : "84052", "city" : "MYTON", "loc" : [ -110.048056, 40.194049 ], "pop" : 940, "state" : "UT" }
+{ "_id" : "84053", "city" : "NEOLA", "loc" : [ -110.037221, 40.449149 ], "pop" : 810, "state" : "UT" }
+{ "_id" : "84054", "city" : "NORTH SALT LAKE", "loc" : [ -111.904116, 40.844064 ], "pop" : 7216, "state" : "UT" }
+{ "_id" : "84056", "city" : "HILL AIR FORCE B", "loc" : [ -111.995565, 41.116962 ], "pop" : 5432, "state" : "UT" }
+{ "_id" : "84057", "city" : "OREM", "loc" : [ -111.695293, 40.313407 ], "pop" : 38292, "state" : "UT" }
+{ "_id" : "84058", "city" : "VINEYARD", "loc" : [ -111.694301, 40.280761 ], "pop" : 29323, "state" : "UT" }
+{ "_id" : "84060", "city" : "PARK CITY", "loc" : [ -111.528021, 40.695724 ], "pop" : 8976, "state" : "UT" }
+{ "_id" : "84061", "city" : "PEOA", "loc" : [ -111.302467, 40.720937 ], "pop" : 892, "state" : "UT" }
+{ "_id" : "84062", "city" : "PLEASANT GROVE", "loc" : [ -111.733284, 40.371986 ], "pop" : 15703, "state" : "UT" }
+{ "_id" : "84063", "city" : "RANDLETT", "loc" : [ -109.730102, 40.21865 ], "pop" : 78, "state" : "UT" }
+{ "_id" : "84064", "city" : "RANDOLPH", "loc" : [ -111.185578, 41.656328 ], "pop" : 682, "state" : "UT" }
+{ "_id" : "84065", "city" : "LARK", "loc" : [ -111.954661, 40.53789 ], "pop" : 28444, "state" : "UT" }
+{ "_id" : "84066", "city" : "ROOSEVELT", "loc" : [ -110.010782, 40.310229 ], "pop" : 6725, "state" : "UT" }
+{ "_id" : "84067", "city" : "ROY", "loc" : [ -112.038177, 41.172365 ], "pop" : 22166, "state" : "UT" }
+{ "_id" : "84069", "city" : "RUSH VALLEY", "loc" : [ -112.744033, 40.233625 ], "pop" : 1893, "state" : "UT" }
+{ "_id" : "84070", "city" : "SANDY", "loc" : [ -111.881625, 40.579379 ], "pop" : 19422, "state" : "UT" }
+{ "_id" : "84071", "city" : "STOCKTON", "loc" : [ -112.425214, 40.350451 ], "pop" : 490, "state" : "UT" }
+{ "_id" : "84072", "city" : "TABIONA", "loc" : [ -110.702108, 40.382691 ], "pop" : 440, "state" : "UT" }
+{ "_id" : "84073", "city" : "TALMAGE", "loc" : [ -110.396529, 40.174569 ], "pop" : 1743, "state" : "UT" }
+{ "_id" : "84074", "city" : "TOOELE", "loc" : [ -112.300214, 40.545445 ], "pop" : 17588, "state" : "UT" }
+{ "_id" : "84075", "city" : "SYRACUSE", "loc" : [ -112.0451, 41.086423 ], "pop" : 9737, "state" : "UT" }
+{ "_id" : "84076", "city" : "TRIDELL", "loc" : [ -109.835906, 40.443593 ], "pop" : 363, "state" : "UT" }
+{ "_id" : "84078", "city" : "VERNAL", "loc" : [ -109.546883, 40.440613 ], "pop" : 17641, "state" : "UT" }
+{ "_id" : "84080", "city" : "VERNON", "loc" : [ -112.425961, 40.082609 ], "pop" : 200, "state" : "UT" }
+{ "_id" : "84082", "city" : "WALLSBURG", "loc" : [ -111.464934, 40.365697 ], "pop" : 649, "state" : "UT" }
+{ "_id" : "84083", "city" : "TROUT CREEK", "loc" : [ -113.993573, 40.597396 ], "pop" : 1801, "state" : "UT" }
+{ "_id" : "84084", "city" : "WEST JORDAN", "loc" : [ -111.967662, 40.625429 ], "pop" : 36145, "state" : "UT" }
+{ "_id" : "84085", "city" : "WHITEROCKS", "loc" : [ -109.917244, 40.452771 ], "pop" : 858, "state" : "UT" }
+{ "_id" : "84086", "city" : "WOODRUFF", "loc" : [ -111.186848, 41.488783 ], "pop" : 359, "state" : "UT" }
+{ "_id" : "84087", "city" : "WOODS CROSS", "loc" : [ -111.902712, 40.887447 ], "pop" : 8170, "state" : "UT" }
+{ "_id" : "84088", "city" : "WEST JORDAN", "loc" : [ -111.964385, 40.595913 ], "pop" : 18592, "state" : "UT" }
+{ "_id" : "84092", "city" : "ALTA", "loc" : [ -111.82736, 40.560245 ], "pop" : 25465, "state" : "UT" }
+{ "_id" : "84093", "city" : "SANDY", "loc" : [ -111.830989, 40.592651 ], "pop" : 26702, "state" : "UT" }
+{ "_id" : "84094", "city" : "SANDY", "loc" : [ -111.861716, 40.568757 ], "pop" : 26375, "state" : "UT" }
+{ "_id" : "84101", "city" : "SALT LAKE CITY", "loc" : [ -111.896657, 40.755851 ], "pop" : 2449, "state" : "UT" }
+{ "_id" : "84102", "city" : "SALT LAKE CITY", "loc" : [ -111.862721, 40.760034 ], "pop" : 15367, "state" : "UT" }
+{ "_id" : "84103", "city" : "SALT LAKE CITY", "loc" : [ -111.874891, 40.777584 ], "pop" : 21427, "state" : "UT" }
+{ "_id" : "84104", "city" : "SALT LAKE CITY", "loc" : [ -111.925979, 40.74985 ], "pop" : 16951, "state" : "UT" }
+{ "_id" : "84105", "city" : "SALT LAKE CITY", "loc" : [ -111.858087, 40.737236 ], "pop" : 22228, "state" : "UT" }
+{ "_id" : "84106", "city" : "SALT LAKE CITY", "loc" : [ -111.854841, 40.705597 ], "pop" : 30496, "state" : "UT" }
+{ "_id" : "84107", "city" : "MURRAY", "loc" : [ -111.878383, 40.659014 ], "pop" : 28403, "state" : "UT" }
+{ "_id" : "84108", "city" : "SALT LAKE CITY", "loc" : [ -111.825822, 40.737136 ], "pop" : 16873, "state" : "UT" }
+{ "_id" : "84109", "city" : "SALT LAKE CITY", "loc" : [ -111.814218, 40.704251 ], "pop" : 24049, "state" : "UT" }
+{ "_id" : "84111", "city" : "SALT LAKE CITY", "loc" : [ -111.881, 40.754834 ], "pop" : 8978, "state" : "UT" }
+{ "_id" : "84112", "city" : "SALT LAKE CITY", "loc" : [ -111.827827, 40.752372 ], "pop" : 2555, "state" : "UT" }
+{ "_id" : "84113", "city" : "SALT LAKE CITY", "loc" : [ -111.841825, 40.763057 ], "pop" : 1093, "state" : "UT" }
+{ "_id" : "84115", "city" : "SOUTH SALT LAKE", "loc" : [ -111.883828, 40.715797 ], "pop" : 21776, "state" : "UT" }
+{ "_id" : "84116", "city" : "SALT LAKE CITY", "loc" : [ -111.929054, 40.785697 ], "pop" : 23880, "state" : "UT" }
+{ "_id" : "84117", "city" : "HOLLADAY", "loc" : [ -111.832943, 40.666302 ], "pop" : 23063, "state" : "UT" }
+{ "_id" : "84118", "city" : "KEARNS", "loc" : [ -111.98521, 40.652759 ], "pop" : 55999, "state" : "UT" }
+{ "_id" : "84119", "city" : "WEST VALLEY CITY", "loc" : [ -111.952964, 40.690977 ], "pop" : 38892, "state" : "UT" }
+{ "_id" : "84120", "city" : "WEST VALLEY CITY", "loc" : [ -112.009783, 40.68708 ], "pop" : 52854, "state" : "UT" }
+{ "_id" : "84121", "city" : "COTTONWOOD", "loc" : [ -111.82468, 40.623247 ], "pop" : 40235, "state" : "UT" }
+{ "_id" : "84123", "city" : "MURRAY", "loc" : [ -111.919483, 40.660479 ], "pop" : 27766, "state" : "UT" }
+{ "_id" : "84124", "city" : "HOLLADAY", "loc" : [ -111.820833, 40.67966 ], "pop" : 20402, "state" : "UT" }
+{ "_id" : "84302", "city" : "BRIGHAM CITY", "loc" : [ -112.015177, 41.507921 ], "pop" : 17119, "state" : "UT" }
+{ "_id" : "84305", "city" : "CLARKSTON", "loc" : [ -112.04859, 41.91877 ], "pop" : 665, "state" : "UT" }
+{ "_id" : "84306", "city" : "COLLINSTON", "loc" : [ -112.124219, 41.78777 ], "pop" : 952, "state" : "UT" }
+{ "_id" : "84307", "city" : "CORINNE", "loc" : [ -112.151388, 41.544986 ], "pop" : 1201, "state" : "UT" }
+{ "_id" : "84308", "city" : "CORNISH", "loc" : [ -111.954241, 41.970178 ], "pop" : 250, "state" : "UT" }
+{ "_id" : "84309", "city" : "DEWEYVILLE", "loc" : [ -112.094717, 41.697226 ], "pop" : 491, "state" : "UT" }
+{ "_id" : "84310", "city" : "EDEN", "loc" : [ -111.855765, 41.330279 ], "pop" : 1707, "state" : "UT" }
+{ "_id" : "84311", "city" : "FIELDING", "loc" : [ -112.118978, 41.811817 ], "pop" : 703, "state" : "UT" }
+{ "_id" : "84312", "city" : "GARLAND", "loc" : [ -112.151635, 41.741319 ], "pop" : 2208, "state" : "UT" }
+{ "_id" : "84313", "city" : "GROUSE CREEK", "loc" : [ -113.854043, 41.629727 ], "pop" : 124, "state" : "UT" }
+{ "_id" : "84314", "city" : "HONEYVILLE", "loc" : [ -112.097425, 41.623754 ], "pop" : 2236, "state" : "UT" }
+{ "_id" : "84315", "city" : "HOOPER", "loc" : [ -112.090371, 41.18267 ], "pop" : 10540, "state" : "UT" }
+{ "_id" : "84317", "city" : "HUNTSVILLE", "loc" : [ -111.761821, 41.272139 ], "pop" : 2247, "state" : "UT" }
+{ "_id" : "84319", "city" : "HYRUM", "loc" : [ -111.849, 41.631096 ], "pop" : 5352, "state" : "UT" }
+{ "_id" : "84320", "city" : "LEWISTON", "loc" : [ -111.876814, 41.970087 ], "pop" : 1418, "state" : "UT" }
+{ "_id" : "84321", "city" : "LOGAN", "loc" : [ -111.822613, 41.747025 ], "pop" : 40074, "state" : "UT" }
+{ "_id" : "84324", "city" : "MANTUA", "loc" : [ -111.941646, 41.497496 ], "pop" : 715, "state" : "UT" }
+{ "_id" : "84325", "city" : "MENDON", "loc" : [ -111.981692, 41.709989 ], "pop" : 1015, "state" : "UT" }
+{ "_id" : "84328", "city" : "PARADISE", "loc" : [ -111.829665, 41.560009 ], "pop" : 916, "state" : "UT" }
+{ "_id" : "84329", "city" : "PARK VALLEY", "loc" : [ -113.34776, 41.855125 ], "pop" : 281, "state" : "UT" }
+{ "_id" : "84332", "city" : "PROVIDENCE", "loc" : [ -111.824389, 41.69522 ], "pop" : 7650, "state" : "UT" }
+{ "_id" : "84333", "city" : "RICHMOND", "loc" : [ -111.806922, 41.928223 ], "pop" : 2556, "state" : "UT" }
+{ "_id" : "84335", "city" : "SMITHFIELD", "loc" : [ -111.852813, 41.840328 ], "pop" : 7376, "state" : "UT" }
+{ "_id" : "84336", "city" : "SNOWVILLE", "loc" : [ -112.353391, 41.840321 ], "pop" : 1982, "state" : "UT" }
+{ "_id" : "84337", "city" : "TREMONTON", "loc" : [ -112.181293, 41.701564 ], "pop" : 6439, "state" : "UT" }
+{ "_id" : "84338", "city" : "TRENTON", "loc" : [ -111.934033, 41.910453 ], "pop" : 450, "state" : "UT" }
+{ "_id" : "84339", "city" : "WELLSVILLE", "loc" : [ -111.931676, 41.634302 ], "pop" : 2461, "state" : "UT" }
+{ "_id" : "84340", "city" : "WILLARD", "loc" : [ -112.031653, 41.398944 ], "pop" : 2034, "state" : "UT" }
+{ "_id" : "84401", "city" : "OGDEN", "loc" : [ -111.962121, 41.22148 ], "pop" : 21276, "state" : "UT" }
+{ "_id" : "84403", "city" : "OGDEN", "loc" : [ -111.948927, 41.189412 ], "pop" : 28751, "state" : "UT" }
+{ "_id" : "84404", "city" : "OGDEN", "loc" : [ -111.983686, 41.262727 ], "pop" : 35790, "state" : "UT" }
+{ "_id" : "84405", "city" : "OGDEN", "loc" : [ -111.980945, 41.173928 ], "pop" : 18982, "state" : "UT" }
+{ "_id" : "84414", "city" : "OGDEN", "loc" : [ -111.968924, 41.311201 ], "pop" : 16891, "state" : "UT" }
+{ "_id" : "84501", "city" : "PRICE", "loc" : [ -110.808117, 39.602013 ], "pop" : 11741, "state" : "UT" }
+{ "_id" : "84510", "city" : "ANETH", "loc" : [ -109.298281, 37.214671 ], "pop" : 3442, "state" : "UT" }
+{ "_id" : "84511", "city" : "BLANDING", "loc" : [ -109.486599, 37.586342 ], "pop" : 4469, "state" : "UT" }
+{ "_id" : "84520", "city" : "EAST CARBON", "loc" : [ -110.411308, 39.546088 ], "pop" : 1628, "state" : "UT" }
+{ "_id" : "84523", "city" : "FERRON", "loc" : [ -111.146698, 39.069196 ], "pop" : 2349, "state" : "UT" }
+{ "_id" : "84525", "city" : "GREEN RIVER", "loc" : [ -110.159817, 39.000243 ], "pop" : 919, "state" : "UT" }
+{ "_id" : "84526", "city" : "HELPER", "loc" : [ -110.856, 39.673684 ], "pop" : 4005, "state" : "UT" }
+{ "_id" : "84528", "city" : "HUNTINGTON", "loc" : [ -110.974094, 39.29202 ], "pop" : 7137, "state" : "UT" }
+{ "_id" : "84531", "city" : "MEXICAN HAT", "loc" : [ -109.991865, 37.118429 ], "pop" : 647, "state" : "UT" }
+{ "_id" : "84532", "city" : "MOAB", "loc" : [ -109.527087, 38.567674 ], "pop" : 6337, "state" : "UT" }
+{ "_id" : "84533", "city" : "BULLFROG", "loc" : [ -110.506917, 37.459898 ], "pop" : 125, "state" : "UT" }
+{ "_id" : "84535", "city" : "MONTICELLO", "loc" : [ -109.315289, 37.921709 ], "pop" : 2527, "state" : "UT" }
+{ "_id" : "84536", "city" : "MONUMENT VALLEY", "loc" : [ -110.427335, 37.061425 ], "pop" : 1411, "state" : "UT" }
+{ "_id" : "84540", "city" : "THOMPSON", "loc" : [ -109.794482, 38.988065 ], "pop" : 210, "state" : "UT" }
+{ "_id" : "84542", "city" : "WELLINGTON", "loc" : [ -110.736954, 39.537257 ], "pop" : 2854, "state" : "UT" }
+{ "_id" : "84601", "city" : "PROVO", "loc" : [ -111.675504, 40.231949 ], "pop" : 20121, "state" : "UT" }
+{ "_id" : "84604", "city" : "PROVO", "loc" : [ -111.654906, 40.260681 ], "pop" : 43841, "state" : "UT" }
+{ "_id" : "84606", "city" : "PROVO", "loc" : [ -111.644724, 40.234675 ], "pop" : 23536, "state" : "UT" }
+{ "_id" : "84621", "city" : "AXTELL", "loc" : [ -111.824303, 39.053248 ], "pop" : 167, "state" : "UT" }
+{ "_id" : "84622", "city" : "CENTERFIELD", "loc" : [ -111.818516, 39.125083 ], "pop" : 945, "state" : "UT" }
+{ "_id" : "84624", "city" : "DELTA", "loc" : [ -112.531892, 39.375534 ], "pop" : 5673, "state" : "UT" }
+{ "_id" : "84627", "city" : "EPHRAIM", "loc" : [ -111.582301, 39.359983 ], "pop" : 3492, "state" : "UT" }
+{ "_id" : "84628", "city" : "EUREKA", "loc" : [ -112.117448, 39.954094 ], "pop" : 600, "state" : "UT" }
+{ "_id" : "84629", "city" : "FAIRVIEW", "loc" : [ -111.495287, 39.645318 ], "pop" : 2089, "state" : "UT" }
+{ "_id" : "84630", "city" : "FAYETTE", "loc" : [ -111.849712, 39.231533 ], "pop" : 207, "state" : "UT" }
+{ "_id" : "84631", "city" : "FILLMORE", "loc" : [ -112.331321, 38.980539 ], "pop" : 3930, "state" : "UT" }
+{ "_id" : "84634", "city" : "GUNNISON", "loc" : [ -111.816701, 39.154464 ], "pop" : 1330, "state" : "UT" }
+{ "_id" : "84635", "city" : "HINCKLEY", "loc" : [ -112.671577, 39.330842 ], "pop" : 983, "state" : "UT" }
+{ "_id" : "84642", "city" : "MANTI", "loc" : [ -111.651372, 39.235389 ], "pop" : 3088, "state" : "UT" }
+{ "_id" : "84645", "city" : "MONA", "loc" : [ -111.848001, 39.838165 ], "pop" : 826, "state" : "UT" }
+{ "_id" : "84647", "city" : "MOUNT PLEASANT", "loc" : [ -111.503854, 39.523227 ], "pop" : 4979, "state" : "UT" }
+{ "_id" : "84648", "city" : "NEPHI", "loc" : [ -111.8359, 39.692275 ], "pop" : 4200, "state" : "UT" }
+{ "_id" : "84650", "city" : "OASIS", "loc" : [ -112.648079, 39.27067 ], "pop" : 500, "state" : "UT" }
+{ "_id" : "84651", "city" : "PAYSON", "loc" : [ -111.732138, 40.044866 ], "pop" : 13960, "state" : "UT" }
+{ "_id" : "84653", "city" : "WOODLAND HILLS", "loc" : [ -111.65906, 40.042702 ], "pop" : 3766, "state" : "UT" }
+{ "_id" : "84654", "city" : "SALINA", "loc" : [ -111.881072, 38.956028 ], "pop" : 3716, "state" : "UT" }
+{ "_id" : "84655", "city" : "GENOLA", "loc" : [ -111.793819, 39.980356 ], "pop" : 3647, "state" : "UT" }
+{ "_id" : "84660", "city" : "SPANISH FORK", "loc" : [ -111.646246, 40.10991 ], "pop" : 12851, "state" : "UT" }
+{ "_id" : "84663", "city" : "SPRINGVILLE", "loc" : [ -111.598664, 40.162528 ], "pop" : 14403, "state" : "UT" }
+{ "_id" : "84664", "city" : "MAPLETON", "loc" : [ -111.580122, 40.133711 ], "pop" : 3427, "state" : "UT" }
+{ "_id" : "84701", "city" : "VENICE", "loc" : [ -112.062253, 38.757075 ], "pop" : 8412, "state" : "UT" }
+{ "_id" : "84710", "city" : "ALTON", "loc" : [ -112.548389, 37.469905 ], "pop" : 159, "state" : "UT" }
+{ "_id" : "84712", "city" : "ANTIMONY", "loc" : [ -111.993029, 38.1015 ], "pop" : 90, "state" : "UT" }
+{ "_id" : "84713", "city" : "BEAVER", "loc" : [ -112.629916, 38.28071 ], "pop" : 2560, "state" : "UT" }
+{ "_id" : "84714", "city" : "BERYL", "loc" : [ -113.619586, 37.96005 ], "pop" : 12, "state" : "UT" }
+{ "_id" : "84716", "city" : "BOULDER", "loc" : [ -111.426646, 37.916606 ], "pop" : 131, "state" : "UT" }
+{ "_id" : "84717", "city" : "BRYCE CANYON", "loc" : [ -112.074311, 37.608427 ], "pop" : 958, "state" : "UT" }
+{ "_id" : "84719", "city" : "BRIAN HEAD", "loc" : [ -112.843698, 37.698465 ], "pop" : 111, "state" : "UT" }
+{ "_id" : "84720", "city" : "PINTURA", "loc" : [ -113.074513, 37.689544 ], "pop" : 17392, "state" : "UT" }
+{ "_id" : "84722", "city" : "CENTRAL", "loc" : [ -113.717199, 37.567734 ], "pop" : 1127, "state" : "UT" }
+{ "_id" : "84726", "city" : "ESCALANTE", "loc" : [ -111.603695, 37.769839 ], "pop" : 955, "state" : "UT" }
+{ "_id" : "84728", "city" : "GARRISON", "loc" : [ -113.894858, 39.074382 ], "pop" : 247, "state" : "UT" }
+{ "_id" : "84729", "city" : "GLENDALE", "loc" : [ -112.603491, 37.321897 ], "pop" : 287, "state" : "UT" }
+{ "_id" : "84731", "city" : "GREENVILLE", "loc" : [ -112.708404, 38.263582 ], "pop" : 116, "state" : "UT" }
+{ "_id" : "84734", "city" : "HANKSVILLE", "loc" : [ -110.813744, 38.252051 ], "pop" : 373, "state" : "UT" }
+{ "_id" : "84737", "city" : "HURRICANE", "loc" : [ -113.224706, 37.169098 ], "pop" : 9174, "state" : "UT" }
+{ "_id" : "84739", "city" : "JOSEPH", "loc" : [ -112.225119, 38.622092 ], "pop" : 289, "state" : "UT" }
+{ "_id" : "84741", "city" : "BIG WATER", "loc" : [ -112.345374, 37.072085 ], "pop" : 4174, "state" : "UT" }
+{ "_id" : "84743", "city" : "KINGSTON", "loc" : [ -112.204864, 38.215772 ], "pop" : 825, "state" : "UT" }
+{ "_id" : "84747", "city" : "FREMONT", "loc" : [ -111.629233, 38.417266 ], "pop" : 987, "state" : "UT" }
+{ "_id" : "84750", "city" : "MARYSVALE", "loc" : [ -112.251848, 38.444924 ], "pop" : 452, "state" : "UT" }
+{ "_id" : "84751", "city" : "MILFORD", "loc" : [ -112.993377, 38.331071 ], "pop" : 2089, "state" : "UT" }
+{ "_id" : "84753", "city" : "MODENA", "loc" : [ -113.919282, 37.799452 ], "pop" : 9, "state" : "UT" }
+{ "_id" : "84754", "city" : "AUSTIN", "loc" : [ -112.132434, 38.645305 ], "pop" : 2995, "state" : "UT" }
+{ "_id" : "84755", "city" : "MOUNT CARMEL", "loc" : [ -112.670034, 37.237821 ], "pop" : 43, "state" : "UT" }
+{ "_id" : "84756", "city" : "NEWCASTLE", "loc" : [ -113.661479, 37.736049 ], "pop" : 758, "state" : "UT" }
+{ "_id" : "84758", "city" : "ORDERVILLE", "loc" : [ -112.642045, 37.274419 ], "pop" : 506, "state" : "UT" }
+{ "_id" : "84759", "city" : "PANGUITCH", "loc" : [ -112.436886, 37.80777 ], "pop" : 1797, "state" : "UT" }
+{ "_id" : "84760", "city" : "PARAGONAH", "loc" : [ -112.773972, 37.89172 ], "pop" : 334, "state" : "UT" }
+{ "_id" : "84761", "city" : "PAROWAN", "loc" : [ -112.832251, 37.844861 ], "pop" : 1988, "state" : "UT" }
+{ "_id" : "84766", "city" : "SEVIER", "loc" : [ -112.392126, 38.590709 ], "pop" : 19, "state" : "UT" }
+{ "_id" : "84770", "city" : "ST GEORGE", "loc" : [ -113.595261, 37.106651 ], "pop" : 33146, "state" : "UT" }
+{ "_id" : "84772", "city" : "SUMMIT", "loc" : [ -112.913407, 37.803397 ], "pop" : 185, "state" : "UT" }
+{ "_id" : "84773", "city" : "TEASDALE", "loc" : [ -111.43346, 38.285334 ], "pop" : 430, "state" : "UT" }
+{ "_id" : "84775", "city" : "TORREY", "loc" : [ -111.547439, 38.334993 ], "pop" : 436, "state" : "UT" }
+{ "_id" : "84780", "city" : "WASHINGTON", "loc" : [ -113.505043, 37.136379 ], "pop" : 4134, "state" : "UT" }
+{ "_id" : "84781", "city" : "PINE VALLEY", "loc" : [ -113.517708, 37.389772 ], "pop" : 31, "state" : "UT" }
+{ "_id" : "84782", "city" : "VEYO", "loc" : [ -113.666758, 37.35896 ], "pop" : 449, "state" : "UT" }
+{ "_id" : "84783", "city" : "DAMMERON VALLEY", "loc" : [ -113.658553, 37.284899 ], "pop" : 499, "state" : "UT" }
+{ "_id" : "85003", "city" : "PHOENIX", "loc" : [ -112.077428, 33.451095 ], "pop" : 10633, "state" : "AZ" }
+{ "_id" : "85004", "city" : "PHOENIX", "loc" : [ -112.068584, 33.455708 ], "pop" : 4491, "state" : "AZ" }
+{ "_id" : "85006", "city" : "PHOENIX", "loc" : [ -112.047357, 33.465016 ], "pop" : 26747, "state" : "AZ" }
+{ "_id" : "85007", "city" : "PHOENIX", "loc" : [ -112.089326, 33.452298 ], "pop" : 13650, "state" : "AZ" }
+{ "_id" : "85008", "city" : "PHOENIX", "loc" : [ -111.998381, 33.466457 ], "pop" : 41733, "state" : "AZ" }
+{ "_id" : "85009", "city" : "PHOENIX", "loc" : [ -112.128368, 33.456373 ], "pop" : 41512, "state" : "AZ" }
+{ "_id" : "85012", "city" : "PHOENIX", "loc" : [ -112.067816, 33.509744 ], "pop" : 6141, "state" : "AZ" }
+{ "_id" : "85013", "city" : "PHOENIX", "loc" : [ -112.082657, 33.508493 ], "pop" : 18467, "state" : "AZ" }
+{ "_id" : "85014", "city" : "PHOENIX", "loc" : [ -112.05557, 33.510263 ], "pop" : 22646, "state" : "AZ" }
+{ "_id" : "85015", "city" : "PHOENIX", "loc" : [ -112.101064, 33.508164 ], "pop" : 32497, "state" : "AZ" }
+{ "_id" : "85016", "city" : "PHOENIX", "loc" : [ -112.030496, 33.502117 ], "pop" : 29527, "state" : "AZ" }
+{ "_id" : "85017", "city" : "PHOENIX", "loc" : [ -112.121232, 33.515263 ], "pop" : 27741, "state" : "AZ" }
+{ "_id" : "85018", "city" : "PHOENIX", "loc" : [ -111.988259, 33.495796 ], "pop" : 32926, "state" : "AZ" }
+{ "_id" : "85019", "city" : "PHOENIX", "loc" : [ -112.141681, 33.512284 ], "pop" : 21879, "state" : "AZ" }
+{ "_id" : "85020", "city" : "PHOENIX", "loc" : [ -112.055888, 33.562281 ], "pop" : 29043, "state" : "AZ" }
+{ "_id" : "85021", "city" : "PHOENIX", "loc" : [ -112.092686, 33.559965 ], "pop" : 31201, "state" : "AZ" }
+{ "_id" : "85022", "city" : "PHOENIX", "loc" : [ -112.052008, 33.631513 ], "pop" : 33573, "state" : "AZ" }
+{ "_id" : "85023", "city" : "PHOENIX", "loc" : [ -112.111838, 33.632383 ], "pop" : 54668, "state" : "AZ" }
+{ "_id" : "85024", "city" : "PHOENIX", "loc" : [ -112.036956, 33.661664 ], "pop" : 14090, "state" : "AZ" }
+{ "_id" : "85027", "city" : "NEW RIVER STAGE", "loc" : [ -112.102723, 33.667157 ], "pop" : 24843, "state" : "AZ" }
+{ "_id" : "85028", "city" : "PHOENIX", "loc" : [ -112.008724, 33.585115 ], "pop" : 22662, "state" : "AZ" }
+{ "_id" : "85029", "city" : "PHOENIX", "loc" : [ -112.119913, 33.596133 ], "pop" : 40764, "state" : "AZ" }
+{ "_id" : "85031", "city" : "PHOENIX", "loc" : [ -112.16963, 33.493909 ], "pop" : 21088, "state" : "AZ" }
+{ "_id" : "85032", "city" : "PHOENIX", "loc" : [ -112.004369, 33.623807 ], "pop" : 53113, "state" : "AZ" }
+{ "_id" : "85033", "city" : "PHOENIX", "loc" : [ -112.213185, 33.494426 ], "pop" : 41367, "state" : "AZ" }
+{ "_id" : "85034", "city" : "PHOENIX", "loc" : [ -112.042135, 33.441251 ], "pop" : 9824, "state" : "AZ" }
+{ "_id" : "85035", "city" : "PHOENIX", "loc" : [ -112.183177, 33.472353 ], "pop" : 35384, "state" : "AZ" }
+{ "_id" : "85037", "city" : "PHOENIX", "loc" : [ -112.246763, 33.491278 ], "pop" : 13924, "state" : "AZ" }
+{ "_id" : "85039", "city" : "PHOENIX", "loc" : [ -112.288573, 33.495362 ], "pop" : 7914, "state" : "AZ" }
+{ "_id" : "85040", "city" : "PHOENIX", "loc" : [ -112.03126, 33.390475 ], "pop" : 47527, "state" : "AZ" }
+{ "_id" : "85041", "city" : "PHOENIX", "loc" : [ -112.095437, 33.388882 ], "pop" : 29343, "state" : "AZ" }
+{ "_id" : "85043", "city" : "PHOENIX", "loc" : [ -112.197245, 33.449056 ], "pop" : 7054, "state" : "AZ" }
+{ "_id" : "85044", "city" : "PHOENIX", "loc" : [ -111.9943, 33.329124 ], "pop" : 32053, "state" : "AZ" }
+{ "_id" : "85051", "city" : "PHOENIX", "loc" : [ -112.133168, 33.559113 ], "pop" : 35671, "state" : "AZ" }
+{ "_id" : "85201", "city" : "MESA", "loc" : [ -111.846931, 33.43174 ], "pop" : 40017, "state" : "AZ" }
+{ "_id" : "85202", "city" : "MESA", "loc" : [ -111.872429, 33.385095 ], "pop" : 40729, "state" : "AZ" }
+{ "_id" : "85203", "city" : "MESA", "loc" : [ -111.805697, 33.436952 ], "pop" : 32853, "state" : "AZ" }
+{ "_id" : "85204", "city" : "MESA", "loc" : [ -111.789554, 33.399168 ], "pop" : 55180, "state" : "AZ" }
+{ "_id" : "85205", "city" : "MESA", "loc" : [ -111.712939, 33.43685 ], "pop" : 35676, "state" : "AZ" }
+{ "_id" : "85206", "city" : "MESA", "loc" : [ -111.724223, 33.402603 ], "pop" : 21274, "state" : "AZ" }
+{ "_id" : "85207", "city" : "MESA", "loc" : [ -111.64256, 33.432073 ], "pop" : 12547, "state" : "AZ" }
+{ "_id" : "85208", "city" : "MESA", "loc" : [ -111.651297, 33.398416 ], "pop" : 22113, "state" : "AZ" }
+{ "_id" : "85210", "city" : "MESA", "loc" : [ -111.842757, 33.38867 ], "pop" : 32467, "state" : "AZ" }
+{ "_id" : "85213", "city" : "MESA", "loc" : [ -111.773114, 33.436688 ], "pop" : 23500, "state" : "AZ" }
+{ "_id" : "85219", "city" : "GOLD CANYON", "loc" : [ -111.51331, 33.360787 ], "pop" : 14112, "state" : "AZ" }
+{ "_id" : "85220", "city" : "APACHE JUNCTION", "loc" : [ -111.571818, 33.415211 ], "pop" : 19342, "state" : "AZ" }
+{ "_id" : "85222", "city" : "ELEVEN MILE CORN", "loc" : [ -111.756093, 32.892667 ], "pop" : 26134, "state" : "AZ" }
+{ "_id" : "85224", "city" : "CHANDLER", "loc" : [ -111.863156, 33.330091 ], "pop" : 54023, "state" : "AZ" }
+{ "_id" : "85225", "city" : "CHANDLER", "loc" : [ -111.823881, 33.310505 ], "pop" : 15678, "state" : "AZ" }
+{ "_id" : "85226", "city" : "CHANDLER", "loc" : [ -111.919827, 33.30917 ], "pop" : 17639, "state" : "AZ" }
+{ "_id" : "85228", "city" : "COOLIDGE", "loc" : [ -111.534378, 32.957399 ], "pop" : 10698, "state" : "AZ" }
+{ "_id" : "85231", "city" : "ELOY", "loc" : [ -111.583275, 32.750929 ], "pop" : 10670, "state" : "AZ" }
+{ "_id" : "85232", "city" : "FLORENCE", "loc" : [ -111.361234, 32.996881 ], "pop" : 9888, "state" : "AZ" }
+{ "_id" : "85234", "city" : "GILBERT", "loc" : [ -111.780876, 33.352746 ], "pop" : 32606, "state" : "AZ" }
+{ "_id" : "85236", "city" : "HIGLEY", "loc" : [ -111.696926, 33.302382 ], "pop" : 3583, "state" : "AZ" }
+{ "_id" : "85237", "city" : "KEARNY", "loc" : [ -110.91227, 33.059443 ], "pop" : 2736, "state" : "AZ" }
+{ "_id" : "85239", "city" : "MOBILE", "loc" : [ -112.075228, 32.987379 ], "pop" : 5026, "state" : "AZ" }
+{ "_id" : "85240", "city" : "WILLIAMS AFB", "loc" : [ -111.668801, 33.310289 ], "pop" : 2574, "state" : "AZ" }
+{ "_id" : "85242", "city" : "ARIZONA BOYS RAN", "loc" : [ -111.643596, 33.238577 ], "pop" : 2569, "state" : "AZ" }
+{ "_id" : "85247", "city" : "SACATON", "loc" : [ -111.775162, 33.097699 ], "pop" : 6792, "state" : "AZ" }
+{ "_id" : "85248", "city" : "SUN LAKES", "loc" : [ -111.866899, 33.223056 ], "pop" : 9399, "state" : "AZ" }
+{ "_id" : "85249", "city" : "CHANDLER", "loc" : [ -111.774486, 33.241384 ], "pop" : 3871, "state" : "AZ" }
+{ "_id" : "85250", "city" : "SCOTTSDALE", "loc" : [ -111.904926, 33.521767 ], "pop" : 16133, "state" : "AZ" }
+{ "_id" : "85251", "city" : "SCOTTSDALE", "loc" : [ -111.916697, 33.493559 ], "pop" : 30869, "state" : "AZ" }
+{ "_id" : "85253", "city" : "PARADISE VALLEY", "loc" : [ -111.956546, 33.549439 ], "pop" : 15289, "state" : "AZ" }
+{ "_id" : "85254", "city" : "SCOTTSDALE", "loc" : [ -111.955422, 33.616476 ], "pop" : 37414, "state" : "AZ" }
+{ "_id" : "85255", "city" : "SCOTTSDALE", "loc" : [ -111.889213, 33.696801 ], "pop" : 2927, "state" : "AZ" }
+{ "_id" : "85256", "city" : "SCOTTSDALE", "loc" : [ -111.85333, 33.485793 ], "pop" : 3367, "state" : "AZ" }
+{ "_id" : "85257", "city" : "SCOTTSDALE", "loc" : [ -111.915129, 33.46693 ], "pop" : 30182, "state" : "AZ" }
+{ "_id" : "85258", "city" : "SCOTTSDALE", "loc" : [ -111.893067, 33.564747 ], "pop" : 20867, "state" : "AZ" }
+{ "_id" : "85259", "city" : "SCOTTSDALE", "loc" : [ -111.840438, 33.587943 ], "pop" : 7802, "state" : "AZ" }
+{ "_id" : "85260", "city" : "SCOTTSDALE", "loc" : [ -111.88671, 33.601323 ], "pop" : 17908, "state" : "AZ" }
+{ "_id" : "85262", "city" : "SCOTTSDALE", "loc" : [ -111.779135, 33.77524 ], "pop" : 1614, "state" : "AZ" }
+{ "_id" : "85264", "city" : "FORT MCDOWELL", "loc" : [ -111.68062, 33.611807 ], "pop" : 619, "state" : "AZ" }
+{ "_id" : "85268", "city" : "FOUNTAIN HILLS", "loc" : [ -111.723685, 33.608489 ], "pop" : 10030, "state" : "AZ" }
+{ "_id" : "85272", "city" : "STANFIELD", "loc" : [ -111.965987, 32.882321 ], "pop" : 644, "state" : "AZ" }
+{ "_id" : "85273", "city" : "SUPERIOR", "loc" : [ -111.09846, 33.288716 ], "pop" : 3901, "state" : "AZ" }
+{ "_id" : "85281", "city" : "TEMPE", "loc" : [ -111.926144, 33.422675 ], "pop" : 49218, "state" : "AZ" }
+{ "_id" : "85282", "city" : "TEMPE", "loc" : [ -111.924896, 33.391669 ], "pop" : 47890, "state" : "AZ" }
+{ "_id" : "85283", "city" : "TEMPE", "loc" : [ -111.93122, 33.366524 ], "pop" : 38332, "state" : "AZ" }
+{ "_id" : "85284", "city" : "TEMPE", "loc" : [ -111.919696, 33.336302 ], "pop" : 12320, "state" : "AZ" }
+{ "_id" : "85292", "city" : "WINKELMAN", "loc" : [ -110.772682, 33.00572 ], "pop" : 1977, "state" : "AZ" }
+{ "_id" : "85301", "city" : "GLENDALE", "loc" : [ -112.176703, 33.531122 ], "pop" : 46331, "state" : "AZ" }
+{ "_id" : "85302", "city" : "GLENDALE", "loc" : [ -112.175289, 33.567487 ], "pop" : 32094, "state" : "AZ" }
+{ "_id" : "85303", "city" : "GLENDALE", "loc" : [ -112.214937, 33.526215 ], "pop" : 16045, "state" : "AZ" }
+{ "_id" : "85304", "city" : "GLENDALE", "loc" : [ -112.174575, 33.594289 ], "pop" : 26463, "state" : "AZ" }
+{ "_id" : "85305", "city" : "GLENDALE", "loc" : [ -112.248232, 33.529103 ], "pop" : 1424, "state" : "AZ" }
+{ "_id" : "85306", "city" : "GLENDALE", "loc" : [ -112.177563, 33.623882 ], "pop" : 23493, "state" : "AZ" }
+{ "_id" : "85307", "city" : "LUKE AFB", "loc" : [ -112.326735, 33.534879 ], "pop" : 4120, "state" : "AZ" }
+{ "_id" : "85308", "city" : "GLENDALE", "loc" : [ -112.169391, 33.653924 ], "pop" : 31532, "state" : "AZ" }
+{ "_id" : "85309", "city" : "LUKE AFB", "loc" : [ -112.356186, 33.539993 ], "pop" : 3601, "state" : "AZ" }
+{ "_id" : "85310", "city" : "GLENDALE", "loc" : [ -112.164131, 33.704726 ], "pop" : 5369, "state" : "AZ" }
+{ "_id" : "85321", "city" : "WHY", "loc" : [ -112.858681, 32.373485 ], "pop" : 3288, "state" : "AZ" }
+{ "_id" : "85322", "city" : "ARLINGTON", "loc" : [ -112.789058, 33.313317 ], "pop" : 329, "state" : "AZ" }
+{ "_id" : "85323", "city" : "AVONDALE", "loc" : [ -112.343754, 33.432114 ], "pop" : 12321, "state" : "AZ" }
+{ "_id" : "85324", "city" : "ROCK SPRINGS", "loc" : [ -112.130956, 34.073197 ], "pop" : 1819, "state" : "AZ" }
+{ "_id" : "85326", "city" : "BUCKEYE", "loc" : [ -112.607728, 33.38896 ], "pop" : 13086, "state" : "AZ" }
+{ "_id" : "85328", "city" : "CIBOLA", "loc" : [ -114.512204, 33.614886 ], "pop" : 1285, "state" : "AZ" }
+{ "_id" : "85331", "city" : "CAVE CREEK", "loc" : [ -112.015106, 33.821896 ], "pop" : 13654, "state" : "AZ" }
+{ "_id" : "85332", "city" : "CONGRESS", "loc" : [ -112.76801, 34.176425 ], "pop" : 2314, "state" : "AZ" }
+{ "_id" : "85333", "city" : "DATELAND", "loc" : [ -113.463126, 32.867886 ], "pop" : 659, "state" : "AZ" }
+{ "_id" : "85335", "city" : "EL MIRAGE", "loc" : [ -112.324147, 33.608153 ], "pop" : 5234, "state" : "AZ" }
+{ "_id" : "85337", "city" : "GILA BEND", "loc" : [ -112.746832, 32.93059 ], "pop" : 2898, "state" : "AZ" }
+{ "_id" : "85338", "city" : "GOODYEAR", "loc" : [ -112.383385, 33.436809 ], "pop" : 5819, "state" : "AZ" }
+{ "_id" : "85339", "city" : "LAVEEN", "loc" : [ -112.171618, 33.343572 ], "pop" : 6187, "state" : "AZ" }
+{ "_id" : "85340", "city" : "LITCHFIELD PARK", "loc" : [ -112.380497, 33.494127 ], "pop" : 6349, "state" : "AZ" }
+{ "_id" : "85342", "city" : "MORRISTOWN", "loc" : [ -112.548331, 33.772993 ], "pop" : 2878, "state" : "AZ" }
+{ "_id" : "85343", "city" : "PALO VERDE", "loc" : [ -112.646662, 33.34848 ], "pop" : 669, "state" : "AZ" }
+{ "_id" : "85344", "city" : "EMPIRE LANDING", "loc" : [ -114.266342, 34.0254 ], "pop" : 11143, "state" : "AZ" }
+{ "_id" : "85345", "city" : "PEORIA", "loc" : [ -112.234424, 33.576135 ], "pop" : 37607, "state" : "AZ" }
+{ "_id" : "85347", "city" : "ROLL", "loc" : [ -113.564287, 32.936635 ], "pop" : 959, "state" : "AZ" }
+{ "_id" : "85348", "city" : "SALOME", "loc" : [ -113.571459, 33.748141 ], "pop" : 1279, "state" : "AZ" }
+{ "_id" : "85350", "city" : "SOMERTON", "loc" : [ -114.7127, 32.563398 ], "pop" : 15339, "state" : "AZ" }
+{ "_id" : "85351", "city" : "SUN CITY", "loc" : [ -112.279701, 33.606104 ], "pop" : 31102, "state" : "AZ" }
+{ "_id" : "85353", "city" : "TOLLESON", "loc" : [ -112.277444, 33.434686 ], "pop" : 9485, "state" : "AZ" }
+{ "_id" : "85354", "city" : "TONOPAH", "loc" : [ -112.952785, 33.422797 ], "pop" : 95, "state" : "AZ" }
+{ "_id" : "85355", "city" : "WADDELL", "loc" : [ -112.43869, 33.567285 ], "pop" : 2125, "state" : "AZ" }
+{ "_id" : "85356", "city" : "WELLTON", "loc" : [ -114.176616, 32.749251 ], "pop" : 4778, "state" : "AZ" }
+{ "_id" : "85361", "city" : "WITTMANN", "loc" : [ -112.446578, 33.726425 ], "pop" : 789, "state" : "AZ" }
+{ "_id" : "85362", "city" : "YARNELL", "loc" : [ -112.62166, 34.414076 ], "pop" : 455, "state" : "AZ" }
+{ "_id" : "85363", "city" : "YOUNGTOWN", "loc" : [ -112.301305, 33.590751 ], "pop" : 2351, "state" : "AZ" }
+{ "_id" : "85364", "city" : "YUMA", "loc" : [ -114.642362, 32.701507 ], "pop" : 57131, "state" : "AZ" }
+{ "_id" : "85365", "city" : "YUMA PROVING GRO", "loc" : [ -114.548633, 32.671352 ], "pop" : 28179, "state" : "AZ" }
+{ "_id" : "85373", "city" : "SUN CITY", "loc" : [ -112.321397, 33.658756 ], "pop" : 25878, "state" : "AZ" }
+{ "_id" : "85374", "city" : "SURPRISE", "loc" : [ -112.33143, 33.630028 ], "pop" : 5042, "state" : "AZ" }
+{ "_id" : "85375", "city" : "SUN CITY WEST", "loc" : [ -112.255434, 33.662576 ], "pop" : 5702, "state" : "AZ" }
+{ "_id" : "85381", "city" : "PEORIA", "loc" : [ -112.223723, 33.604761 ], "pop" : 9624, "state" : "AZ" }
+{ "_id" : "85382", "city" : "PEORIA", "loc" : [ -112.207177, 33.63083 ], "pop" : 1738, "state" : "AZ" }
+{ "_id" : "85390", "city" : "WICKENBURG", "loc" : [ -112.738973, 33.911282 ], "pop" : 7994, "state" : "AZ" }
+{ "_id" : "85501", "city" : "GLOBE", "loc" : [ -110.789247, 33.402426 ], "pop" : 13240, "state" : "AZ" }
+{ "_id" : "85530", "city" : "BYLAS", "loc" : [ -110.11702, 33.126549 ], "pop" : 1371, "state" : "AZ" }
+{ "_id" : "85533", "city" : "CLIFTON", "loc" : [ -109.246199, 33.132343 ], "pop" : 376, "state" : "AZ" }
+{ "_id" : "85534", "city" : "FRANKLIN", "loc" : [ -109.129575, 32.793976 ], "pop" : 2395, "state" : "AZ" }
+{ "_id" : "85535", "city" : "EDEN", "loc" : [ -109.953682, 33.028629 ], "pop" : 55, "state" : "AZ" }
+{ "_id" : "85539", "city" : "MIAMI", "loc" : [ -110.881182, 33.431928 ], "pop" : 4866, "state" : "AZ" }
+{ "_id" : "85540", "city" : "MORENCI", "loc" : [ -109.311517, 33.043593 ], "pop" : 5223, "state" : "AZ" }
+{ "_id" : "85541", "city" : "PAYSON", "loc" : [ -111.287774, 34.219779 ], "pop" : 13456, "state" : "AZ" }
+{ "_id" : "85542", "city" : "PERIDOT", "loc" : [ -110.37252, 33.478874 ], "pop" : 4878, "state" : "AZ" }
+{ "_id" : "85543", "city" : "PIMA", "loc" : [ -109.856009, 32.909661 ], "pop" : 2881, "state" : "AZ" }
+{ "_id" : "85544", "city" : "STRAWBERRY", "loc" : [ -111.473483, 34.390915 ], "pop" : 1903, "state" : "AZ" }
+{ "_id" : "85545", "city" : "ROOSEVELT", "loc" : [ -110.974884, 33.635753 ], "pop" : 65, "state" : "AZ" }
+{ "_id" : "85546", "city" : "SAFFORD", "loc" : [ -109.626641, 32.829491 ], "pop" : 2676, "state" : "AZ" }
+{ "_id" : "85550", "city" : "SAN CARLOS", "loc" : [ -110.395323, 33.310643 ], "pop" : 2307, "state" : "AZ" }
+{ "_id" : "85552", "city" : "THATCHER", "loc" : [ -109.730245, 32.819902 ], "pop" : 15375, "state" : "AZ" }
+{ "_id" : "85602", "city" : "BENSON", "loc" : [ -110.294113, 31.98826 ], "pop" : 6141, "state" : "AZ" }
+{ "_id" : "85603", "city" : "BISBEE", "loc" : [ -109.911736, 31.408557 ], "pop" : 8471, "state" : "AZ" }
+{ "_id" : "85606", "city" : "COCHISE", "loc" : [ -109.92393, 32.097891 ], "pop" : 290, "state" : "AZ" }
+{ "_id" : "85607", "city" : "DOUGLAS", "loc" : [ -109.544698, 31.35111 ], "pop" : 17350, "state" : "AZ" }
+{ "_id" : "85610", "city" : "ELFRIDA", "loc" : [ -109.619277, 31.713891 ], "pop" : 1655, "state" : "AZ" }
+{ "_id" : "85611", "city" : "ELGIN", "loc" : [ -110.611403, 31.66002 ], "pop" : 638, "state" : "AZ" }
+{ "_id" : "85613", "city" : "FORT HUACHUCA", "loc" : [ -110.344131, 31.558735 ], "pop" : 8710, "state" : "AZ" }
+{ "_id" : "85614", "city" : "GREEN VALLEY", "loc" : [ -111.000253, 31.854271 ], "pop" : 15530, "state" : "AZ" }
+{ "_id" : "85615", "city" : "HEREFORD", "loc" : [ -110.204728, 31.403545 ], "pop" : 1762, "state" : "AZ" }
+{ "_id" : "85616", "city" : "HUACHUCA CITY", "loc" : [ -110.333414, 31.663896 ], "pop" : 3639, "state" : "AZ" }
+{ "_id" : "85617", "city" : "MC NEAL", "loc" : [ -109.630971, 31.502969 ], "pop" : 3135, "state" : "AZ" }
+{ "_id" : "85618", "city" : "MAMMOTH", "loc" : [ -110.643961, 32.723875 ], "pop" : 1876, "state" : "AZ" }
+{ "_id" : "85621", "city" : "NOGALES", "loc" : [ -110.943508, 31.376969 ], "pop" : 25506, "state" : "AZ" }
+{ "_id" : "85623", "city" : "ORACLE", "loc" : [ -110.796126, 32.600506 ], "pop" : 3833, "state" : "AZ" }
+{ "_id" : "85624", "city" : "PATAGONIA", "loc" : [ -110.696774, 31.535317 ], "pop" : 1430, "state" : "AZ" }
+{ "_id" : "85625", "city" : "PEARCE", "loc" : [ -109.795032, 31.966608 ], "pop" : 2421, "state" : "AZ" }
+{ "_id" : "85629", "city" : "SAHUARITA", "loc" : [ -111.000154, 31.945169 ], "pop" : 2973, "state" : "AZ" }
+{ "_id" : "85630", "city" : "SAINT DAVID", "loc" : [ -110.215377, 31.897251 ], "pop" : 1928, "state" : "AZ" }
+{ "_id" : "85631", "city" : "SAN MANUEL", "loc" : [ -110.656788, 32.695831 ], "pop" : 6253, "state" : "AZ" }
+{ "_id" : "85632", "city" : "PORTAL", "loc" : [ -109.367152, 32.208167 ], "pop" : 1485, "state" : "AZ" }
+{ "_id" : "85634", "city" : "PISINEMO", "loc" : [ -111.922207, 32.031572 ], "pop" : 9003, "state" : "AZ" }
+{ "_id" : "85635", "city" : "SIERRA VISTA", "loc" : [ -110.266565, 31.536467 ], "pop" : 33700, "state" : "AZ" }
+{ "_id" : "85637", "city" : "SONOITA", "loc" : [ -110.724418, 31.866154 ], "pop" : 1399, "state" : "AZ" }
+{ "_id" : "85638", "city" : "TOMBSTONE", "loc" : [ -110.058449, 31.721598 ], "pop" : 1556, "state" : "AZ" }
+{ "_id" : "85640", "city" : "AMADO", "loc" : [ -111.039693, 31.594194 ], "pop" : 813, "state" : "AZ" }
+{ "_id" : "85641", "city" : "VAIL", "loc" : [ -110.88375, 32.035926 ], "pop" : 2843, "state" : "AZ" }
+{ "_id" : "85643", "city" : "WILLCOX", "loc" : [ -109.863111, 32.372977 ], "pop" : 7297, "state" : "AZ" }
+{ "_id" : "85645", "city" : "AMADO", "loc" : [ -111.072233, 31.643759 ], "pop" : 1157, "state" : "AZ" }
+{ "_id" : "85653", "city" : "MARANA", "loc" : [ -111.273621, 32.404749 ], "pop" : 7562, "state" : "AZ" }
+{ "_id" : "85701", "city" : "TUCSON", "loc" : [ -110.969445, 32.213873 ], "pop" : 5191, "state" : "AZ" }
+{ "_id" : "85704", "city" : "CASAS ADOBES", "loc" : [ -110.984593, 32.329175 ], "pop" : 24039, "state" : "AZ" }
+{ "_id" : "85705", "city" : "TUCSON", "loc" : [ -110.984536, 32.269088 ], "pop" : 52751, "state" : "AZ" }
+{ "_id" : "85706", "city" : "TUCSON", "loc" : [ -110.945127, 32.139172 ], "pop" : 52458, "state" : "AZ" }
+{ "_id" : "85708", "city" : "TUCSON", "loc" : [ -110.869283, 32.179989 ], "pop" : 6191, "state" : "AZ" }
+{ "_id" : "85710", "city" : "TUCSON", "loc" : [ -110.824046, 32.213813 ], "pop" : 52679, "state" : "AZ" }
+{ "_id" : "85711", "city" : "TUCSON", "loc" : [ -110.882892, 32.212729 ], "pop" : 40024, "state" : "AZ" }
+{ "_id" : "85712", "city" : "TUCSON", "loc" : [ -110.886919, 32.250043 ], "pop" : 28813, "state" : "AZ" }
+{ "_id" : "85713", "city" : "TUCSON", "loc" : [ -110.973896, 32.194065 ], "pop" : 40625, "state" : "AZ" }
+{ "_id" : "85714", "city" : "TUCSON", "loc" : [ -110.971891, 32.170657 ], "pop" : 16488, "state" : "AZ" }
+{ "_id" : "85715", "city" : "TUCSON", "loc" : [ -110.834837, 32.269213 ], "pop" : 33197, "state" : "AZ" }
+{ "_id" : "85716", "city" : "TUCSON", "loc" : [ -110.922176, 32.246815 ], "pop" : 32258, "state" : "AZ" }
+{ "_id" : "85718", "city" : "TUCSON", "loc" : [ -110.917882, 32.311154 ], "pop" : 22441, "state" : "AZ" }
+{ "_id" : "85719", "city" : "TUCSON", "loc" : [ -110.949142, 32.247426 ], "pop" : 39019, "state" : "AZ" }
+{ "_id" : "85730", "city" : "TUCSON", "loc" : [ -110.81904, 32.180951 ], "pop" : 33251, "state" : "AZ" }
+{ "_id" : "85735", "city" : "TUCSON", "loc" : [ -111.260758, 32.057796 ], "pop" : 2987, "state" : "AZ" }
+{ "_id" : "85736", "city" : "TUCSON", "loc" : [ -111.317842, 31.667909 ], "pop" : 1130, "state" : "AZ" }
+{ "_id" : "85737", "city" : "ORO VALLEY", "loc" : [ -110.954463, 32.431679 ], "pop" : 14077, "state" : "AZ" }
+{ "_id" : "85741", "city" : "TUCSON", "loc" : [ -111.041873, 32.347215 ], "pop" : 36400, "state" : "AZ" }
+{ "_id" : "85743", "city" : "TUCSON", "loc" : [ -111.177071, 32.33655 ], "pop" : 4507, "state" : "AZ" }
+{ "_id" : "85745", "city" : "TUCSON", "loc" : [ -111.017907, 32.243359 ], "pop" : 25143, "state" : "AZ" }
+{ "_id" : "85746", "city" : "TUCSON", "loc" : [ -111.050569, 32.142244 ], "pop" : 34683, "state" : "AZ" }
+{ "_id" : "85747", "city" : "TUCSON", "loc" : [ -110.667337, 32.071142 ], "pop" : 2286, "state" : "AZ" }
+{ "_id" : "85748", "city" : "TUCSON", "loc" : [ -110.775765, 32.214981 ], "pop" : 9675, "state" : "AZ" }
+{ "_id" : "85749", "city" : "TUCSON", "loc" : [ -110.765829, 32.273285 ], "pop" : 14254, "state" : "AZ" }
+{ "_id" : "85901", "city" : "SHOW LOW", "loc" : [ -110.054633, 34.060117 ], "pop" : 16493, "state" : "AZ" }
+{ "_id" : "85920", "city" : "ALPINE", "loc" : [ -109.12829, 33.827878 ], "pop" : 243, "state" : "AZ" }
+{ "_id" : "85922", "city" : "BLUE", "loc" : [ -109.06849, 33.651245 ], "pop" : 14, "state" : "AZ" }
+{ "_id" : "85924", "city" : "CONCHO", "loc" : [ -109.674096, 34.445787 ], "pop" : 949, "state" : "AZ" }
+{ "_id" : "85925", "city" : "EAGAR", "loc" : [ -109.246933, 33.954571 ], "pop" : 482, "state" : "AZ" }
+{ "_id" : "85928", "city" : "HEBER", "loc" : [ -110.568647, 34.4163 ], "pop" : 1856, "state" : "AZ" }
+{ "_id" : "85929", "city" : "LAKESIDE", "loc" : [ -109.986878, 34.166224 ], "pop" : 5350, "state" : "AZ" }
+{ "_id" : "85935", "city" : "PINETOP", "loc" : [ -109.919668, 34.117459 ], "pop" : 1938, "state" : "AZ" }
+{ "_id" : "85936", "city" : "SAINT JOHNS", "loc" : [ -109.379617, 34.501008 ], "pop" : 3844, "state" : "AZ" }
+{ "_id" : "85937", "city" : "SNOWFLAKE", "loc" : [ -110.080742, 34.495859 ], "pop" : 6678, "state" : "AZ" }
+{ "_id" : "85938", "city" : "SPRINGERVILLE", "loc" : [ -109.304066, 34.119333 ], "pop" : 6560, "state" : "AZ" }
+{ "_id" : "86001", "city" : "FLAGSTAFF", "loc" : [ -111.661979, 35.185911 ], "pop" : 30174, "state" : "AZ" }
+{ "_id" : "86004", "city" : "FLAGSTAFF", "loc" : [ -111.574109, 35.225736 ], "pop" : 26878, "state" : "AZ" }
+{ "_id" : "86021", "city" : "COLORADO CITY", "loc" : [ -112.952427, 36.976266 ], "pop" : 3065, "state" : "AZ" }
+{ "_id" : "86022", "city" : "FREDONIA", "loc" : [ -112.497864, 36.904397 ], "pop" : 1393, "state" : "AZ" }
+{ "_id" : "86025", "city" : "HOLBROOK", "loc" : [ -110.143412, 34.908451 ], "pop" : 5567, "state" : "AZ" }
+{ "_id" : "86030", "city" : "HOTEVILLA", "loc" : [ -110.566107, 36.211141 ], "pop" : 271, "state" : "AZ" }
+{ "_id" : "86033", "city" : "KAYENTA", "loc" : [ -110.265229, 36.688327 ], "pop" : 7549, "state" : "AZ" }
+{ "_id" : "86034", "city" : "KEAMS CANYON", "loc" : [ -110.284461, 35.808206 ], "pop" : 3240, "state" : "AZ" }
+{ "_id" : "86035", "city" : "LEUPP", "loc" : [ -110.992651, 35.336528 ], "pop" : 2396, "state" : "AZ" }
+{ "_id" : "86036", "city" : "MARBLE CANYON", "loc" : [ -111.558166, 36.956943 ], "pop" : 564, "state" : "AZ" }
+{ "_id" : "86038", "city" : "MORMON LAKE", "loc" : [ -111.454914, 34.916896 ], "pop" : 55, "state" : "AZ" }
+{ "_id" : "86039", "city" : "KYKOTSMOVI VILLA", "loc" : [ -110.368805, 35.579084 ], "pop" : 167, "state" : "AZ" }
+{ "_id" : "86040", "city" : "GREENEHAVEN", "loc" : [ -111.43847, 36.896625 ], "pop" : 8428, "state" : "AZ" }
+{ "_id" : "86042", "city" : "POLACCA", "loc" : [ -110.51114, 35.811812 ], "pop" : 1723, "state" : "AZ" }
+{ "_id" : "86043", "city" : "SECOND MESA", "loc" : [ -110.6472, 35.903782 ], "pop" : 1653, "state" : "AZ" }
+{ "_id" : "86044", "city" : "TONALEA", "loc" : [ -110.882042, 35.934555 ], "pop" : 158, "state" : "AZ" }
+{ "_id" : "86045", "city" : "TUBA CITY", "loc" : [ -111.268566, 36.103729 ], "pop" : 10514, "state" : "AZ" }
+{ "_id" : "86046", "city" : "WILLIAMS", "loc" : [ -112.17075, 35.543398 ], "pop" : 6117, "state" : "AZ" }
+{ "_id" : "86047", "city" : "WINSLOW", "loc" : [ -110.511382, 35.16078 ], "pop" : 17429, "state" : "AZ" }
+{ "_id" : "86053", "city" : "KAIBITO", "loc" : [ -111.136973, 36.484798 ], "pop" : 6098, "state" : "AZ" }
+{ "_id" : "86054", "city" : "SHONTO", "loc" : [ -110.647743, 36.61594 ], "pop" : 2049, "state" : "AZ" }
+{ "_id" : "86301", "city" : "PRESCOTT", "loc" : [ -113.022459, 34.629909 ], "pop" : 915, "state" : "AZ" }
+{ "_id" : "86303", "city" : "GROOM CREEK", "loc" : [ -112.473459, 34.558577 ], "pop" : 36617, "state" : "AZ" }
+{ "_id" : "86314", "city" : "PRESCOTT VALLEY", "loc" : [ -112.326378, 34.601934 ], "pop" : 11396, "state" : "AZ" }
+{ "_id" : "86320", "city" : "ASH FORK", "loc" : [ -112.502681, 35.214998 ], "pop" : 563, "state" : "AZ" }
+{ "_id" : "86321", "city" : "BAGDAD", "loc" : [ -113.175535, 34.578484 ], "pop" : 1596, "state" : "AZ" }
+{ "_id" : "86322", "city" : "CAMP VERDE", "loc" : [ -111.855131, 34.569733 ], "pop" : 6250, "state" : "AZ" }
+{ "_id" : "86323", "city" : "CHINO VALLEY", "loc" : [ -112.473099, 34.775739 ], "pop" : 7285, "state" : "AZ" }
+{ "_id" : "86324", "city" : "CLARKDALE", "loc" : [ -112.033417, 34.747793 ], "pop" : 7574, "state" : "AZ" }
+{ "_id" : "86325", "city" : "CORNVILLE", "loc" : [ -111.908556, 34.725593 ], "pop" : 2612, "state" : "AZ" }
+{ "_id" : "86326", "city" : "COTTONWOOD", "loc" : [ -112.009099, 34.705547 ], "pop" : 8530, "state" : "AZ" }
+{ "_id" : "86327", "city" : "DEWEY", "loc" : [ -112.256665, 34.536753 ], "pop" : 3965, "state" : "AZ" }
+{ "_id" : "86332", "city" : "KIRKLAND", "loc" : [ -112.896641, 34.454149 ], "pop" : 186, "state" : "AZ" }
+{ "_id" : "86333", "city" : "MAYER", "loc" : [ -112.129551, 34.365535 ], "pop" : 3248, "state" : "AZ" }
+{ "_id" : "86334", "city" : "PAULDEN", "loc" : [ -112.544105, 35.03129 ], "pop" : 24, "state" : "AZ" }
+{ "_id" : "86335", "city" : "RIMROCK", "loc" : [ -111.784222, 34.63799 ], "pop" : 1743, "state" : "AZ" }
+{ "_id" : "86336", "city" : "SEDONA", "loc" : [ -111.750627, 34.826645 ], "pop" : 13225, "state" : "AZ" }
+{ "_id" : "86337", "city" : "SELIGMAN", "loc" : [ -112.954805, 35.321246 ], "pop" : 693, "state" : "AZ" }
+{ "_id" : "86343", "city" : "CROWN KING", "loc" : [ -112.333971, 34.224062 ], "pop" : 105, "state" : "AZ" }
+{ "_id" : "86401", "city" : "KINGMAN", "loc" : [ -114.05689, 35.258379 ], "pop" : 32002, "state" : "AZ" }
+{ "_id" : "86403", "city" : "DESERT HILLS", "loc" : [ -114.308083, 34.492879 ], "pop" : 26718, "state" : "AZ" }
+{ "_id" : "86412", "city" : "HUALAPAI", "loc" : [ -113.295324, 35.540732 ], "pop" : 2, "state" : "AZ" }
+{ "_id" : "86430", "city" : "BULLHEAD CITY", "loc" : [ -114.588816, 35.014832 ], "pop" : 3196, "state" : "AZ" }
+{ "_id" : "86432", "city" : "LITTLEFIELD", "loc" : [ -113.913693, 36.866524 ], "pop" : 87, "state" : "AZ" }
+{ "_id" : "86434", "city" : "PEACH SPRINGS", "loc" : [ -113.420199, 35.537795 ], "pop" : 798, "state" : "AZ" }
+{ "_id" : "86435", "city" : "SUPAI", "loc" : [ -112.693212, 36.224157 ], "pop" : 423, "state" : "AZ" }
+{ "_id" : "86436", "city" : "TOPOCK", "loc" : [ -114.481666, 34.778388 ], "pop" : 912, "state" : "AZ" }
+{ "_id" : "86440", "city" : "MOHAVE VALLEY", "loc" : [ -114.595115, 34.892942 ], "pop" : 4139, "state" : "AZ" }
+{ "_id" : "86441", "city" : "DOLAN SPRINGS", "loc" : [ -114.547771, 35.774789 ], "pop" : 68, "state" : "AZ" }
+{ "_id" : "86442", "city" : "BULLHEAD CITY", "loc" : [ -114.594737, 35.106001 ], "pop" : 22394, "state" : "AZ" }
+{ "_id" : "86444", "city" : "MEADVIEW", "loc" : [ -114.327696, 35.813733 ], "pop" : 118, "state" : "AZ" }
+{ "_id" : "86502", "city" : "CHAMBERS", "loc" : [ -109.37389, 35.143044 ], "pop" : 1085, "state" : "AZ" }
+{ "_id" : "86503", "city" : "CHINLE", "loc" : [ -109.603693, 36.130367 ], "pop" : 10679, "state" : "AZ" }
+{ "_id" : "86505", "city" : "GANADO", "loc" : [ -109.283168, 35.651844 ], "pop" : 23428, "state" : "AZ" }
+{ "_id" : "86507", "city" : "LUKACHUKAI", "loc" : [ -109.244614, 36.418111 ], "pop" : 1665, "state" : "AZ" }
+{ "_id" : "86509", "city" : "NAVAJO", "loc" : [ -109.396217, 34.817202 ], "pop" : 41, "state" : "AZ" }
+{ "_id" : "86510", "city" : "PINON", "loc" : [ -110.221077, 36.100243 ], "pop" : 5911, "state" : "AZ" }
+{ "_id" : "86514", "city" : "TEEC NOS POS", "loc" : [ -109.359039, 36.779694 ], "pop" : 4941, "state" : "AZ" }
+{ "_id" : "86535", "city" : "DENNEHOTSO", "loc" : [ -109.861001, 36.777286 ], "pop" : 1693, "state" : "AZ" }
+{ "_id" : "86538", "city" : "MANY FARMS", "loc" : [ -109.634021, 36.408259 ], "pop" : 4172, "state" : "AZ" }
+{ "_id" : "86556", "city" : "TSAILE", "loc" : [ -109.217627, 36.307075 ], "pop" : 1593, "state" : "AZ" }
+{ "_id" : "87001", "city" : "ALGODONES", "loc" : [ -106.616589, 35.428527 ], "pop" : 0, "state" : "NM" }
+{ "_id" : "87002", "city" : "BOYS RANCH", "loc" : [ -106.761215, 34.645562 ], "pop" : 14826, "state" : "NM" }
+{ "_id" : "87004", "city" : "BERNALILLO", "loc" : [ -106.530873, 35.328506 ], "pop" : 7113, "state" : "NM" }
+{ "_id" : "87005", "city" : "BLUEWATER", "loc" : [ -108.191663, 35.164724 ], "pop" : 1611, "state" : "NM" }
+{ "_id" : "87006", "city" : "BOSQUE", "loc" : [ -106.8038, 34.49956 ], "pop" : 276, "state" : "NM" }
+{ "_id" : "87007", "city" : "CASA BLANCA", "loc" : [ -107.433907, 35.035222 ], "pop" : 2986, "state" : "NM" }
+{ "_id" : "87008", "city" : "CEDAR CREST", "loc" : [ -106.361737, 35.128506 ], "pop" : 1860, "state" : "NM" }
+{ "_id" : "87009", "city" : "CEDARVALE", "loc" : [ -105.734516, 34.388028 ], "pop" : 66, "state" : "NM" }
+{ "_id" : "87010", "city" : "CERRILLOS", "loc" : [ -106.131683, 35.422965 ], "pop" : 788, "state" : "NM" }
+{ "_id" : "87013", "city" : "CUBA", "loc" : [ -107.188462, 36.048201 ], "pop" : 2764, "state" : "NM" }
+{ "_id" : "87014", "city" : "CUBERO", "loc" : [ -107.856722, 35.117372 ], "pop" : 16704, "state" : "NM" }
+{ "_id" : "87015", "city" : "EDGEWOOD", "loc" : [ -106.187207, 35.077603 ], "pop" : 3032, "state" : "NM" }
+{ "_id" : "87016", "city" : "ESTANCIA", "loc" : [ -106.135024, 34.769983 ], "pop" : 2634, "state" : "NM" }
+{ "_id" : "87017", "city" : "GALLINA", "loc" : [ -106.661388, 36.171429 ], "pop" : 1003, "state" : "NM" }
+{ "_id" : "87018", "city" : "COUNSELOR", "loc" : [ -106.949789, 36.118386 ], "pop" : 566, "state" : "NM" }
+{ "_id" : "87020", "city" : "GRANTS", "loc" : [ -107.935662, 35.359802 ], "pop" : 428, "state" : "NM" }
+{ "_id" : "87023", "city" : "JARALES", "loc" : [ -107.029912, 34.648156 ], "pop" : 9, "state" : "NM" }
+{ "_id" : "87024", "city" : "JEMEZ PUEBLO", "loc" : [ -106.721894, 35.624315 ], "pop" : 2256, "state" : "NM" }
+{ "_id" : "87025", "city" : "JEMEZ SPRINGS", "loc" : [ -106.771393, 35.892689 ], "pop" : 1, "state" : "NM" }
+{ "_id" : "87026", "city" : "CANONCITO", "loc" : [ -107.105843, 35.085305 ], "pop" : 1272, "state" : "NM" }
+{ "_id" : "87027", "city" : "LA JARA", "loc" : [ -106.992335, 36.119383 ], "pop" : 5, "state" : "NM" }
+{ "_id" : "87028", "city" : "LAJOYA", "loc" : [ -106.84279, 34.343444 ], "pop" : 74, "state" : "NM" }
+{ "_id" : "87029", "city" : "LINDRITH", "loc" : [ -106.925352, 36.336141 ], "pop" : 574, "state" : "NM" }
+{ "_id" : "87031", "city" : "LOS LUNAS", "loc" : [ -106.711537, 34.780607 ], "pop" : 23560, "state" : "NM" }
+{ "_id" : "87035", "city" : "MORIARTY", "loc" : [ -106.060871, 34.988878 ], "pop" : 5570, "state" : "NM" }
+{ "_id" : "87036", "city" : "MOUNTAINAIR", "loc" : [ -106.257738, 34.515775 ], "pop" : 1442, "state" : "NM" }
+{ "_id" : "87041", "city" : "COCHITI PUEBLO", "loc" : [ -106.343472, 35.603104 ], "pop" : 1527, "state" : "NM" }
+{ "_id" : "87042", "city" : "PERALTA", "loc" : [ -106.687159, 34.833188 ], "pop" : 2672, "state" : "NM" }
+{ "_id" : "87043", "city" : "PLACITAS", "loc" : [ -106.529279, 35.309175 ], "pop" : 8357, "state" : "NM" }
+{ "_id" : "87044", "city" : "PONDEROSA", "loc" : [ -106.654421, 35.797576 ], "pop" : 1092, "state" : "NM" }
+{ "_id" : "87045", "city" : "PREWITT", "loc" : [ -108.103798, 35.35466 ], "pop" : 1114, "state" : "NM" }
+{ "_id" : "87046", "city" : "REGINA", "loc" : [ -107.071932, 36.20283 ], "pop" : 0, "state" : "NM" }
+{ "_id" : "87047", "city" : "SANDIA PARK", "loc" : [ -106.323846, 35.168275 ], "pop" : 2672, "state" : "NM" }
+{ "_id" : "87048", "city" : "CORRALES", "loc" : [ -106.620034, 35.233888 ], "pop" : 4900, "state" : "NM" }
+{ "_id" : "87050", "city" : "SAN MATEO", "loc" : [ -107.70498, 35.222614 ], "pop" : 912, "state" : "NM" }
+{ "_id" : "87052", "city" : "SANTO DOMINGO PU", "loc" : [ -106.361275, 35.513892 ], "pop" : 3030, "state" : "NM" }
+{ "_id" : "87053", "city" : "ZIA PUEBLO", "loc" : [ -106.737467, 35.524241 ], "pop" : 877, "state" : "NM" }
+{ "_id" : "87055", "city" : "SEBOYETA", "loc" : [ -107.382281, 35.149322 ], "pop" : 1356, "state" : "NM" }
+{ "_id" : "87056", "city" : "STANLEY", "loc" : [ -106.028299, 35.12948 ], "pop" : 552, "state" : "NM" }
+{ "_id" : "87059", "city" : "TIJERAS", "loc" : [ -106.306226, 35.044563 ], "pop" : 6861, "state" : "NM" }
+{ "_id" : "87062", "city" : "VEGUITA", "loc" : [ -106.759148, 34.485032 ], "pop" : 817, "state" : "NM" }
+{ "_id" : "87063", "city" : "WILLARD", "loc" : [ -106.030706, 34.57543 ], "pop" : 276, "state" : "NM" }
+{ "_id" : "87068", "city" : "BOSQUE FARMS", "loc" : [ -106.697506, 34.876366 ], "pop" : 6286, "state" : "NM" }
+{ "_id" : "87102", "city" : "ALBUQUERQUE", "loc" : [ -106.648171, 35.081831 ], "pop" : 20645, "state" : "NM" }
+{ "_id" : "87104", "city" : "ALBUQUERQUE", "loc" : [ -106.671215, 35.103822 ], "pop" : 11889, "state" : "NM" }
+{ "_id" : "87105", "city" : "ALBUQUERQUE", "loc" : [ -106.689341, 35.044761 ], "pop" : 50233, "state" : "NM" }
+{ "_id" : "87106", "city" : "ALBUQUERQUE", "loc" : [ -106.616917, 35.079011 ], "pop" : 26482, "state" : "NM" }
+{ "_id" : "87107", "city" : "ALBUQUERQUE", "loc" : [ -106.642747, 35.134742 ], "pop" : 30302, "state" : "NM" }
+{ "_id" : "87108", "city" : "ALBUQUERQUE", "loc" : [ -106.574864, 35.072586 ], "pop" : 36704, "state" : "NM" }
+{ "_id" : "87109", "city" : "ALBUQUERQUE", "loc" : [ -106.569004, 35.15058 ], "pop" : 39310, "state" : "NM" }
+{ "_id" : "87110", "city" : "ALBUQUERQUE", "loc" : [ -106.578052, 35.110417 ], "pop" : 42652, "state" : "NM" }
+{ "_id" : "87111", "city" : "ALBUQUERQUE", "loc" : [ -106.522164, 35.134724 ], "pop" : 47455, "state" : "NM" }
+{ "_id" : "87112", "city" : "ALBUQUERQUE", "loc" : [ -106.518338, 35.101026 ], "pop" : 45478, "state" : "NM" }
+{ "_id" : "87113", "city" : "ALBUQUERQUE", "loc" : [ -106.601467, 35.175906 ], "pop" : 3622, "state" : "NM" }
+{ "_id" : "87114", "city" : "ALAMEDA", "loc" : [ -106.659138, 35.195612 ], "pop" : 16352, "state" : "NM" }
+{ "_id" : "87115", "city" : "KIRTLAND A F B E", "loc" : [ -106.513896, 34.904876 ], "pop" : 0, "state" : "NM" }
+{ "_id" : "87116", "city" : "ALBUQUERQUE", "loc" : [ -106.550605, 35.056116 ], "pop" : 5761, "state" : "NM" }
+{ "_id" : "87118", "city" : "ALBUQUERQUE", "loc" : [ -106.595802, 35.055443 ], "pop" : 3067, "state" : "NM" }
+{ "_id" : "87120", "city" : "ALBUQUERQUE", "loc" : [ -106.704137, 35.142146 ], "pop" : 23796, "state" : "NM" }
+{ "_id" : "87121", "city" : "ALBUQUERQUE", "loc" : [ -106.726861, 35.051209 ], "pop" : 22253, "state" : "NM" }
+{ "_id" : "87122", "city" : "ALBUQUERQUE", "loc" : [ -106.510176, 35.178715 ], "pop" : 6127, "state" : "NM" }
+{ "_id" : "87123", "city" : "ALBUQUERQUE", "loc" : [ -106.509003, 35.07166 ], "pop" : 33808, "state" : "NM" }
+{ "_id" : "87124", "city" : "RIO RANCHO", "loc" : [ -106.681756, 35.249347 ], "pop" : 29586, "state" : "NM" }
+{ "_id" : "87301", "city" : "GALLUP", "loc" : [ -108.741352, 35.506475 ], "pop" : 32311, "state" : "NM" }
+{ "_id" : "87310", "city" : "BRIMHALL", "loc" : [ -108.581469, 35.800503 ], "pop" : 119, "state" : "NM" }
+{ "_id" : "87312", "city" : "CONTINENTAL DIVI", "loc" : [ -108.469256, 35.504295 ], "pop" : 704, "state" : "NM" }
+{ "_id" : "87313", "city" : "CROWNPOINT", "loc" : [ -108.02709, 35.720557 ], "pop" : 6400, "state" : "NM" }
+{ "_id" : "87315", "city" : "FENCE LAKE", "loc" : [ -108.693392, 34.734385 ], "pop" : 112, "state" : "NM" }
+{ "_id" : "87320", "city" : "MEXICAN SPRINGS", "loc" : [ -108.818964, 35.783727 ], "pop" : 562, "state" : "NM" }
+{ "_id" : "87321", "city" : "RAMAH", "loc" : [ -108.491951, 35.132375 ], "pop" : 517, "state" : "NM" }
+{ "_id" : "87323", "city" : "THOREAU", "loc" : [ -107.830218, 35.57869 ], "pop" : 4254, "state" : "NM" }
+{ "_id" : "87324", "city" : "TOADLENA", "loc" : [ -108.750647, 36.073202 ], "pop" : 2097, "state" : "NM" }
+{ "_id" : "87325", "city" : "TOHATCHI", "loc" : [ -108.687818, 35.768609 ], "pop" : 5648, "state" : "NM" }
+{ "_id" : "87327", "city" : "ZUNI", "loc" : [ -108.833611, 35.06845 ], "pop" : 7382, "state" : "NM" }
+{ "_id" : "87328", "city" : "NAVAJO", "loc" : [ -109.022621, 35.894193 ], "pop" : 2715, "state" : "NM" }
+{ "_id" : "87401", "city" : "FARMINGTON", "loc" : [ -108.199531, 36.706514 ], "pop" : 36782, "state" : "NM" }
+{ "_id" : "87402", "city" : "FARMINGTON", "loc" : [ -108.147766, 36.768503 ], "pop" : 7238, "state" : "NM" }
+{ "_id" : "87410", "city" : "AZTEC", "loc" : [ -108.010982, 36.820499 ], "pop" : 10951, "state" : "NM" }
+{ "_id" : "87412", "city" : "BLANCO", "loc" : [ -107.795276, 36.725612 ], "pop" : 1007, "state" : "NM" }
+{ "_id" : "87413", "city" : "BLOOMFIELD", "loc" : [ -107.978437, 36.695475 ], "pop" : 9612, "state" : "NM" }
+{ "_id" : "87415", "city" : "FLORA VISTA", "loc" : [ -108.082683, 36.802771 ], "pop" : 2634, "state" : "NM" }
+{ "_id" : "87416", "city" : "FRUITLAND", "loc" : [ -108.45339, 36.76323 ], "pop" : 819, "state" : "NM" }
+{ "_id" : "87417", "city" : "KIRTLAND", "loc" : [ -108.350956, 36.740953 ], "pop" : 5087, "state" : "NM" }
+{ "_id" : "87418", "city" : "LA PLATA", "loc" : [ -108.179243, 36.957632 ], "pop" : 163, "state" : "NM" }
+{ "_id" : "87419", "city" : "NAVAJO DAM", "loc" : [ -107.670991, 36.833838 ], "pop" : 32, "state" : "NM" }
+{ "_id" : "87420", "city" : "SHIPROCK", "loc" : [ -108.735479, 36.655981 ], "pop" : 14805, "state" : "NM" }
+{ "_id" : "87421", "city" : "WATERFLOW", "loc" : [ -108.431083, 36.780092 ], "pop" : 378, "state" : "NM" }
+{ "_id" : "87501", "city" : "POJOAQUE VALLEY", "loc" : [ -105.974818, 35.702472 ], "pop" : 51715, "state" : "NM" }
+{ "_id" : "87505", "city" : "SANTA FE", "loc" : [ -105.981994, 35.619623 ], "pop" : 34054, "state" : "NM" }
+{ "_id" : "87510", "city" : "ABIQUIU", "loc" : [ -106.244859, 36.176923 ], "pop" : 1538, "state" : "NM" }
+{ "_id" : "87513", "city" : "ARROYO HONDO", "loc" : [ -105.621998, 36.531848 ], "pop" : 1333, "state" : "NM" }
+{ "_id" : "87514", "city" : "ARROYO SECO", "loc" : [ -105.594609, 36.504568 ], "pop" : 782, "state" : "NM" }
+{ "_id" : "87520", "city" : "CHAMA", "loc" : [ -106.582928, 36.896214 ], "pop" : 1103, "state" : "NM" }
+{ "_id" : "87521", "city" : "CHAMISAL", "loc" : [ -105.68461, 36.160411 ], "pop" : 2147, "state" : "NM" }
+{ "_id" : "87522", "city" : "CUNDIYO", "loc" : [ -105.911441, 36.011906 ], "pop" : 4380, "state" : "NM" }
+{ "_id" : "87524", "city" : "COSTILLA", "loc" : [ -105.501586, 36.952556 ], "pop" : 495, "state" : "NM" }
+{ "_id" : "87527", "city" : "DIXON", "loc" : [ -105.86148, 36.179 ], "pop" : 1320, "state" : "NM" }
+{ "_id" : "87528", "city" : "DULCE", "loc" : [ -107.060179, 36.859808 ], "pop" : 2936, "state" : "NM" }
+{ "_id" : "87530", "city" : "EL RITO", "loc" : [ -106.21917, 36.364694 ], "pop" : 928, "state" : "NM" }
+{ "_id" : "87531", "city" : "EMBUDO", "loc" : [ -106.024187, 36.137028 ], "pop" : 3377, "state" : "NM" }
+{ "_id" : "87532", "city" : "ESPANOLA", "loc" : [ -106.071697, 35.987157 ], "pop" : 9437, "state" : "NM" }
+{ "_id" : "87535", "city" : "GLORIETA", "loc" : [ -105.790316, 35.566645 ], "pop" : 1246, "state" : "NM" }
+{ "_id" : "87537", "city" : "HERNANDEZ", "loc" : [ -106.139579, 36.073811 ], "pop" : 832, "state" : "NM" }
+{ "_id" : "87539", "city" : "LA MADERA", "loc" : [ -106.13443, 36.246387 ], "pop" : 75, "state" : "NM" }
+{ "_id" : "87540", "city" : "LAMY", "loc" : [ -105.940906, 35.431057 ], "pop" : 516, "state" : "NM" }
+{ "_id" : "87544", "city" : "LOS ALAMOS", "loc" : [ -106.267624, 35.866321 ], "pop" : 18122, "state" : "NM" }
+{ "_id" : "87549", "city" : "OJO CALIENTE", "loc" : [ -105.915507, 36.40991 ], "pop" : 453, "state" : "NM" }
+{ "_id" : "87552", "city" : "PECOS", "loc" : [ -105.670104, 35.571011 ], "pop" : 2534, "state" : "NM" }
+{ "_id" : "87553", "city" : "PENASCO", "loc" : [ -105.734245, 36.176023 ], "pop" : 632, "state" : "NM" }
+{ "_id" : "87556", "city" : "QUESTA", "loc" : [ -105.560984, 36.72572 ], "pop" : 2881, "state" : "NM" }
+{ "_id" : "87557", "city" : "RANCHOS DE TAOS", "loc" : [ -105.608576, 36.335692 ], "pop" : 174, "state" : "NM" }
+{ "_id" : "87560", "city" : "RIBERA", "loc" : [ -105.465228, 35.334448 ], "pop" : 1619, "state" : "NM" }
+{ "_id" : "87563", "city" : "RUTHERON", "loc" : [ -106.685267, 36.647146 ], "pop" : 38, "state" : "NM" }
+{ "_id" : "87564", "city" : "SAN CRISTOBAL", "loc" : [ -105.635968, 36.611638 ], "pop" : 326, "state" : "NM" }
+{ "_id" : "87565", "city" : "SAN JOSE", "loc" : [ -105.438341, 35.456949 ], "pop" : 844, "state" : "NM" }
+{ "_id" : "87566", "city" : "SAN JUAN PUEBLO", "loc" : [ -106.079267, 36.048886 ], "pop" : 5209, "state" : "NM" }
+{ "_id" : "87567", "city" : "SANTA CRUZ", "loc" : [ -106.031839, 35.986011 ], "pop" : 5947, "state" : "NM" }
+{ "_id" : "87571", "city" : "TAOS", "loc" : [ -105.584732, 36.395288 ], "pop" : 13297, "state" : "NM" }
+{ "_id" : "87573", "city" : "TERERRO", "loc" : [ -105.645725, 35.736881 ], "pop" : 99, "state" : "NM" }
+{ "_id" : "87575", "city" : "TIERRA AMARILLA", "loc" : [ -106.556972, 36.680481 ], "pop" : 1865, "state" : "NM" }
+{ "_id" : "87579", "city" : "VADITO", "loc" : [ -105.67818, 36.191305 ], "pop" : 360, "state" : "NM" }
+{ "_id" : "87580", "city" : "VALDEZ", "loc" : [ -105.506971, 36.569699 ], "pop" : 238, "state" : "NM" }
+{ "_id" : "87581", "city" : "VALLECITOS", "loc" : [ -106.085942, 36.516284 ], "pop" : 576, "state" : "NM" }
+{ "_id" : "87701", "city" : "LAS VEGAS", "loc" : [ -105.227162, 35.594862 ], "pop" : 19567, "state" : "NM" }
+{ "_id" : "87711", "city" : "ANTON CHICO", "loc" : [ -105.141041, 35.159262 ], "pop" : 296, "state" : "NM" }
+{ "_id" : "87713", "city" : "CHACON", "loc" : [ -105.385411, 36.138805 ], "pop" : 180, "state" : "NM" }
+{ "_id" : "87714", "city" : "CIMARRON", "loc" : [ -105.069694, 36.457424 ], "pop" : 1582, "state" : "NM" }
+{ "_id" : "87715", "city" : "CLEVELAND", "loc" : [ -105.43262, 35.989831 ], "pop" : 228, "state" : "NM" }
+{ "_id" : "87718", "city" : "EAGLE NEST", "loc" : [ -105.275561, 36.53255 ], "pop" : 463, "state" : "NM" }
+{ "_id" : "87722", "city" : "GUADALUPITA", "loc" : [ -105.127814, 36.113046 ], "pop" : 52, "state" : "NM" }
+{ "_id" : "87724", "city" : "LA LOMA", "loc" : [ -105.096864, 35.191562 ], "pop" : 233, "state" : "NM" }
+{ "_id" : "87725", "city" : "LEDOUX", "loc" : [ -105.421555, 35.919118 ], "pop" : 179, "state" : "NM" }
+{ "_id" : "87728", "city" : "MAXWELL", "loc" : [ -104.56395, 36.543393 ], "pop" : 390, "state" : "NM" }
+{ "_id" : "87729", "city" : "MIAMI", "loc" : [ -104.811769, 36.28955 ], "pop" : 65, "state" : "NM" }
+{ "_id" : "87730", "city" : "MILLS", "loc" : [ -104.227743, 36.128144 ], "pop" : 21, "state" : "NM" }
+{ "_id" : "87731", "city" : "MONTEZUMA", "loc" : [ -105.409729, 35.682959 ], "pop" : 62, "state" : "NM" }
+{ "_id" : "87732", "city" : "MORA", "loc" : [ -105.312837, 36.00405 ], "pop" : 2636, "state" : "NM" }
+{ "_id" : "87733", "city" : "ALBERT", "loc" : [ -103.746132, 35.715938 ], "pop" : 373, "state" : "NM" }
+{ "_id" : "87734", "city" : "OCATE", "loc" : [ -105.06595, 36.10366 ], "pop" : 327, "state" : "NM" }
+{ "_id" : "87740", "city" : "RATON", "loc" : [ -104.434881, 36.895187 ], "pop" : 8449, "state" : "NM" }
+{ "_id" : "87742", "city" : "ROCIADA", "loc" : [ -105.314716, 35.822648 ], "pop" : 480, "state" : "NM" }
+{ "_id" : "87743", "city" : "ROY", "loc" : [ -104.149698, 35.952248 ], "pop" : 499, "state" : "NM" }
+{ "_id" : "87745", "city" : "SAPELLO", "loc" : [ -105.107735, 35.762012 ], "pop" : 2, "state" : "NM" }
+{ "_id" : "87746", "city" : "SOLANO", "loc" : [ -104.1221, 35.837828 ], "pop" : 87, "state" : "NM" }
+{ "_id" : "87747", "city" : "SPRINGER", "loc" : [ -104.592705, 36.37672 ], "pop" : 1976, "state" : "NM" }
+{ "_id" : "87750", "city" : "VALMORA", "loc" : [ -104.911587, 35.794033 ], "pop" : 138, "state" : "NM" }
+{ "_id" : "87752", "city" : "WAGON MOUND", "loc" : [ -104.691, 35.981361 ], "pop" : 524, "state" : "NM" }
+{ "_id" : "87801", "city" : "SOCORRO", "loc" : [ -106.890659, 34.047853 ], "pop" : 9663, "state" : "NM" }
+{ "_id" : "87815", "city" : "BINGHAM", "loc" : [ -106.021163, 34.043864 ], "pop" : 33, "state" : "NM" }
+{ "_id" : "87820", "city" : "ARAGON", "loc" : [ -108.546589, 33.88592 ], "pop" : 149, "state" : "NM" }
+{ "_id" : "87821", "city" : "DATIL", "loc" : [ -108.018284, 34.04269 ], "pop" : 340, "state" : "NM" }
+{ "_id" : "87823", "city" : "LEMITAR", "loc" : [ -106.904381, 34.155999 ], "pop" : 439, "state" : "NM" }
+{ "_id" : "87825", "city" : "ALAMO", "loc" : [ -107.340647, 34.241178 ], "pop" : 2715, "state" : "NM" }
+{ "_id" : "87827", "city" : "PIE TOWN", "loc" : [ -108.368187, 34.324282 ], "pop" : 396, "state" : "NM" }
+{ "_id" : "87828", "city" : "POLVADERA", "loc" : [ -106.897505, 34.134672 ], "pop" : 225, "state" : "NM" }
+{ "_id" : "87829", "city" : "QUEMADO", "loc" : [ -108.757835, 34.265158 ], "pop" : 188, "state" : "NM" }
+{ "_id" : "87830", "city" : "RESERVE", "loc" : [ -108.800918, 33.688074 ], "pop" : 1172, "state" : "NM" }
+{ "_id" : "87831", "city" : "SAN ACACIA", "loc" : [ -106.904884, 34.228328 ], "pop" : 522, "state" : "NM" }
+{ "_id" : "87901", "city" : "TRUTH OR CONSEQU", "loc" : [ -107.248794, 33.139478 ], "pop" : 7794, "state" : "NM" }
+{ "_id" : "87930", "city" : "ARREY", "loc" : [ -107.354368, 32.802057 ], "pop" : 555, "state" : "NM" }
+{ "_id" : "87931", "city" : "CABALLO", "loc" : [ -107.347113, 33.013452 ], "pop" : 860, "state" : "NM" }
+{ "_id" : "87932", "city" : "CUCHILLO", "loc" : [ -107.456536, 33.370269 ], "pop" : 125, "state" : "NM" }
+{ "_id" : "87933", "city" : "DERRY", "loc" : [ -107.284271, 32.808561 ], "pop" : 118, "state" : "NM" }
+{ "_id" : "87936", "city" : "GARFIELD", "loc" : [ -107.270409, 32.755749 ], "pop" : 432, "state" : "NM" }
+{ "_id" : "87937", "city" : "HATCH", "loc" : [ -107.159028, 32.658335 ], "pop" : 2314, "state" : "NM" }
+{ "_id" : "87940", "city" : "RINCON", "loc" : [ -107.064343, 32.65969 ], "pop" : 394, "state" : "NM" }
+{ "_id" : "87941", "city" : "SALEM", "loc" : [ -107.215689, 32.709322 ], "pop" : 709, "state" : "NM" }
+{ "_id" : "87942", "city" : "WILLIAMSBURG", "loc" : [ -107.337583, 33.226498 ], "pop" : 58, "state" : "NM" }
+{ "_id" : "87943", "city" : "WINSTON", "loc" : [ -107.667456, 33.306089 ], "pop" : 97, "state" : "NM" }
+{ "_id" : "88001", "city" : "LAS CRUCES", "loc" : [ -106.746034, 32.321641 ], "pop" : 57502, "state" : "NM" }
+{ "_id" : "88002", "city" : "WHITE SANDS MISS", "loc" : [ -106.49236, 32.382669 ], "pop" : 2616, "state" : "NM" }
+{ "_id" : "88005", "city" : "LAS CRUCES", "loc" : [ -106.79908, 32.316076 ], "pop" : 40042, "state" : "NM" }
+{ "_id" : "88020", "city" : "ANIMAS", "loc" : [ -108.585695, 31.793696 ], "pop" : 1291, "state" : "NM" }
+{ "_id" : "88021", "city" : "CHAPARRAL", "loc" : [ -106.573452, 31.934505 ], "pop" : 24480, "state" : "NM" }
+{ "_id" : "88023", "city" : "VANADIUM", "loc" : [ -108.107667, 32.756334 ], "pop" : 3694, "state" : "NM" }
+{ "_id" : "88025", "city" : "BUCKHORN", "loc" : [ -108.477951, 32.813466 ], "pop" : 1822, "state" : "NM" }
+{ "_id" : "88026", "city" : "CENTRAL", "loc" : [ -108.162698, 32.779767 ], "pop" : 3161, "state" : "NM" }
+{ "_id" : "88030", "city" : "DEMING", "loc" : [ -107.746559, 32.231808 ], "pop" : 18110, "state" : "NM" }
+{ "_id" : "88039", "city" : "GLENWOOD", "loc" : [ -108.774282, 33.304789 ], "pop" : 318, "state" : "NM" }
+{ "_id" : "88041", "city" : "SAN LORENZO", "loc" : [ -108.082185, 32.853311 ], "pop" : 271, "state" : "NM" }
+{ "_id" : "88042", "city" : "HILLSBORO", "loc" : [ -107.6276, 32.923913 ], "pop" : 305, "state" : "NM" }
+{ "_id" : "88043", "city" : "HURLEY", "loc" : [ -108.15162, 32.64799 ], "pop" : 1775, "state" : "NM" }
+{ "_id" : "88044", "city" : "LA MESA", "loc" : [ -106.701103, 32.082312 ], "pop" : 3370, "state" : "NM" }
+{ "_id" : "88045", "city" : "ROAD FORKS", "loc" : [ -108.754657, 32.314032 ], "pop" : 4667, "state" : "NM" }
+{ "_id" : "88047", "city" : "MESILLA PARK", "loc" : [ -106.637016, 32.297725 ], "pop" : 83, "state" : "NM" }
+{ "_id" : "88048", "city" : "MESQUITE", "loc" : [ -106.667626, 32.145958 ], "pop" : 3568, "state" : "NM" }
+{ "_id" : "88049", "city" : "MIMBRES", "loc" : [ -107.942326, 32.860936 ], "pop" : 818, "state" : "NM" }
+{ "_id" : "88061", "city" : "SILVER CITY", "loc" : [ -108.274916, 32.789986 ], "pop" : 16135, "state" : "NM" }
+{ "_id" : "88101", "city" : "CLOVIS", "loc" : [ -103.221391, 34.412585 ], "pop" : 39152, "state" : "NM" }
+{ "_id" : "88112", "city" : "BROADVIEW", "loc" : [ -103.129235, 34.803956 ], "pop" : 175, "state" : "NM" }
+{ "_id" : "88113", "city" : "CAUSEY", "loc" : [ -103.150201, 33.892926 ], "pop" : 229, "state" : "NM" }
+{ "_id" : "88114", "city" : "CROSSROADS", "loc" : [ -103.356387, 33.527186 ], "pop" : 17, "state" : "NM" }
+{ "_id" : "88116", "city" : "ELIDA", "loc" : [ -103.632341, 33.940468 ], "pop" : 503, "state" : "NM" }
+{ "_id" : "88118", "city" : "FLOYD", "loc" : [ -103.582707, 34.251951 ], "pop" : 681, "state" : "NM" }
+{ "_id" : "88119", "city" : "FORT SUMNER", "loc" : [ -104.231689, 34.460018 ], "pop" : 1934, "state" : "NM" }
+{ "_id" : "88120", "city" : "GRADY", "loc" : [ -103.298043, 34.810697 ], "pop" : 265, "state" : "NM" }
+{ "_id" : "88121", "city" : "HOUSE", "loc" : [ -103.920256, 34.695156 ], "pop" : 235, "state" : "NM" }
+{ "_id" : "88123", "city" : "LINGO", "loc" : [ -103.208161, 33.696291 ], "pop" : 52, "state" : "NM" }
+{ "_id" : "88124", "city" : "MELROSE", "loc" : [ -103.632507, 34.44787 ], "pop" : 976, "state" : "NM" }
+{ "_id" : "88125", "city" : "MILNESAND", "loc" : [ -103.278189, 33.60501 ], "pop" : 10, "state" : "NM" }
+{ "_id" : "88126", "city" : "PEP", "loc" : [ -103.327208, 33.897032 ], "pop" : 369, "state" : "NM" }
+{ "_id" : "88130", "city" : "PORTALES", "loc" : [ -103.336311, 34.179915 ], "pop" : 14828, "state" : "NM" }
+{ "_id" : "88132", "city" : "ROGERS", "loc" : [ -103.127527, 34.024759 ], "pop" : 30, "state" : "NM" }
+{ "_id" : "88133", "city" : "SAINT VRAIN", "loc" : [ -103.453239, 34.465205 ], "pop" : 188, "state" : "NM" }
+{ "_id" : "88134", "city" : "TAIBAN", "loc" : [ -104.032899, 34.424829 ], "pop" : 94, "state" : "NM" }
+{ "_id" : "88135", "city" : "TEXICO", "loc" : [ -103.061544, 34.395795 ], "pop" : 1451, "state" : "NM" }
+{ "_id" : "88136", "city" : "YESO", "loc" : [ -104.527582, 34.474962 ], "pop" : 224, "state" : "NM" }
+{ "_id" : "88201", "city" : "ROSWELL", "loc" : [ -104.525857, 33.388504 ], "pop" : 53644, "state" : "NM" }
+{ "_id" : "88210", "city" : "ARTESIA", "loc" : [ -104.407401, 32.838355 ], "pop" : 14689, "state" : "NM" }
+{ "_id" : "88213", "city" : "CAPROCK", "loc" : [ -103.639009, 33.393855 ], "pop" : 19, "state" : "NM" }
+{ "_id" : "88220", "city" : "CARLSBAD", "loc" : [ -104.239539, 32.411867 ], "pop" : 31888, "state" : "NM" }
+{ "_id" : "88230", "city" : "DEXTER", "loc" : [ -104.383285, 33.191006 ], "pop" : 2056, "state" : "NM" }
+{ "_id" : "88231", "city" : "EUNICE", "loc" : [ -103.159407, 32.439225 ], "pop" : 3014, "state" : "NM" }
+{ "_id" : "88232", "city" : "HAGERMAN", "loc" : [ -104.329778, 33.107643 ], "pop" : 1409, "state" : "NM" }
+{ "_id" : "88240", "city" : "HOBBS", "loc" : [ -103.137246, 32.72217 ], "pop" : 36880, "state" : "NM" }
+{ "_id" : "88250", "city" : "HOPE", "loc" : [ -104.729921, 32.81561 ], "pop" : 177, "state" : "NM" }
+{ "_id" : "88252", "city" : "JAL", "loc" : [ -103.199724, 32.112816 ], "pop" : 2335, "state" : "NM" }
+{ "_id" : "88253", "city" : "LAKE ARTHUR", "loc" : [ -104.406412, 33.017106 ], "pop" : 740, "state" : "NM" }
+{ "_id" : "88256", "city" : "LOVING", "loc" : [ -104.091376, 32.274034 ], "pop" : 1851, "state" : "NM" }
+{ "_id" : "88260", "city" : "LOVINGTON", "loc" : [ -103.348849, 32.951166 ], "pop" : 12046, "state" : "NM" }
+{ "_id" : "88264", "city" : "MALJAMAR", "loc" : [ -103.723401, 32.842281 ], "pop" : 61, "state" : "NM" }
+{ "_id" : "88265", "city" : "MONUMENT", "loc" : [ -103.270256, 32.587405 ], "pop" : 0, "state" : "NM" }
+{ "_id" : "88266", "city" : "OIL CENTER", "loc" : [ -103.301915, 32.490383 ], "pop" : 0, "state" : "NM" }
+{ "_id" : "88267", "city" : "TATUM", "loc" : [ -103.314, 33.260018 ], "pop" : 1393, "state" : "NM" }
+{ "_id" : "88301", "city" : "CARRIZOZO", "loc" : [ -105.869617, 33.64962 ], "pop" : 1288, "state" : "NM" }
+{ "_id" : "88310", "city" : "ALAMOGORDO", "loc" : [ -105.948544, 32.893186 ], "pop" : 31204, "state" : "NM" }
+{ "_id" : "88314", "city" : "BENT", "loc" : [ -105.863472, 33.148014 ], "pop" : 172, "state" : "NM" }
+{ "_id" : "88316", "city" : "CAPITAN", "loc" : [ -105.526906, 33.560232 ], "pop" : 1760, "state" : "NM" }
+{ "_id" : "88317", "city" : "CLOUDCROFT", "loc" : [ -105.939028, 32.574067 ], "pop" : 4482, "state" : "NM" }
+{ "_id" : "88318", "city" : "CORONA", "loc" : [ -105.533873, 34.169259 ], "pop" : 496, "state" : "NM" }
+{ "_id" : "88321", "city" : "ENCINO", "loc" : [ -105.483914, 34.61496 ], "pop" : 290, "state" : "NM" }
+{ "_id" : "88324", "city" : "GLENCOE", "loc" : [ -105.502991, 33.386738 ], "pop" : 68, "state" : "NM" }
+{ "_id" : "88330", "city" : "HOLLOMAN AIR FOR", "loc" : [ -106.07845, 32.862093 ], "pop" : 5896, "state" : "NM" }
+{ "_id" : "88336", "city" : "HONDO", "loc" : [ -105.388854, 33.462518 ], "pop" : 160, "state" : "NM" }
+{ "_id" : "88337", "city" : "LA LUZ", "loc" : [ -105.953397, 32.977449 ], "pop" : 2302, "state" : "NM" }
+{ "_id" : "88338", "city" : "LINCOLN", "loc" : [ -105.528427, 33.492912 ], "pop" : 150, "state" : "NM" }
+{ "_id" : "88339", "city" : "MAYHILL", "loc" : [ -105.518056, 32.907048 ], "pop" : 237, "state" : "NM" }
+{ "_id" : "88340", "city" : "MESCALERO", "loc" : [ -105.774293, 33.216436 ], "pop" : 2695, "state" : "NM" }
+{ "_id" : "88341", "city" : "NOGAL", "loc" : [ -105.703631, 33.499552 ], "pop" : 312, "state" : "NM" }
+{ "_id" : "88343", "city" : "PICACHO", "loc" : [ -105.083382, 33.345642 ], "pop" : 38, "state" : "NM" }
+{ "_id" : "88344", "city" : "PINON", "loc" : [ -105.415708, 32.639584 ], "pop" : 92, "state" : "NM" }
+{ "_id" : "88345", "city" : "RUIDOSO", "loc" : [ -105.650994, 33.347406 ], "pop" : 6883, "state" : "NM" }
+{ "_id" : "88346", "city" : "RUIDOSO DOWNS", "loc" : [ -105.538306, 33.357718 ], "pop" : 367, "state" : "NM" }
+{ "_id" : "88347", "city" : "SACRAMENTO", "loc" : [ -105.621128, 32.805221 ], "pop" : 69, "state" : "NM" }
+{ "_id" : "88348", "city" : "SAN PATRICIO", "loc" : [ -105.349798, 33.38775 ], "pop" : 532, "state" : "NM" }
+{ "_id" : "88351", "city" : "TINNIE", "loc" : [ -105.202681, 33.337308 ], "pop" : 165, "state" : "NM" }
+{ "_id" : "88352", "city" : "TULAROSA", "loc" : [ -106.010789, 33.065049 ], "pop" : 4583, "state" : "NM" }
+{ "_id" : "88353", "city" : "VAUGHN", "loc" : [ -105.192558, 34.624074 ], "pop" : 741, "state" : "NM" }
+{ "_id" : "88354", "city" : "WEED", "loc" : [ -105.506296, 32.80519 ], "pop" : 196, "state" : "NM" }
+{ "_id" : "88401", "city" : "TUCUMCARI", "loc" : [ -103.717935, 35.168003 ], "pop" : 8634, "state" : "NM" }
+{ "_id" : "88410", "city" : "AMISTAD", "loc" : [ -103.212954, 35.898276 ], "pop" : 170, "state" : "NM" }
+{ "_id" : "88411", "city" : "BARD", "loc" : [ -103.317778, 35.115364 ], "pop" : 358, "state" : "NM" }
+{ "_id" : "88412", "city" : "BUEYEROS", "loc" : [ -103.666894, 36.013541 ], "pop" : 7, "state" : "NM" }
+{ "_id" : "88414", "city" : "CAPULIN", "loc" : [ -103.993599, 36.747453 ], "pop" : 62, "state" : "NM" }
+{ "_id" : "88415", "city" : "CLAYTON", "loc" : [ -103.188823, 36.441378 ], "pop" : 2886, "state" : "NM" }
+{ "_id" : "88416", "city" : "CONCHAS DAM", "loc" : [ -104.205231, 35.378561 ], "pop" : 218, "state" : "NM" }
+{ "_id" : "88417", "city" : "CUERVO", "loc" : [ -104.399867, 35.01013 ], "pop" : 66, "state" : "NM" }
+{ "_id" : "88418", "city" : "DES MOINES", "loc" : [ -103.873853, 36.729069 ], "pop" : 278, "state" : "NM" }
+{ "_id" : "88419", "city" : "FOLSOM", "loc" : [ -103.839925, 36.86896 ], "pop" : 172, "state" : "NM" }
+{ "_id" : "88421", "city" : "GARITA", "loc" : [ -104.441911, 35.350182 ], "pop" : 113, "state" : "NM" }
+{ "_id" : "88422", "city" : "GLADSTONE", "loc" : [ -103.893081, 36.307741 ], "pop" : 45, "state" : "NM" }
+{ "_id" : "88424", "city" : "GRENVILLE", "loc" : [ -103.415521, 36.725396 ], "pop" : 185, "state" : "NM" }
+{ "_id" : "88426", "city" : "LOGAN", "loc" : [ -103.438339, 35.368051 ], "pop" : 962, "state" : "NM" }
+{ "_id" : "88427", "city" : "MC ALISTER", "loc" : [ -103.657169, 34.749206 ], "pop" : 171, "state" : "NM" }
+{ "_id" : "88429", "city" : "MOUNT DORA", "loc" : [ -103.416667, 36.498795 ], "pop" : 27, "state" : "NM" }
+{ "_id" : "88430", "city" : "NARA VISA", "loc" : [ -103.131738, 35.617963 ], "pop" : 170, "state" : "NM" }
+{ "_id" : "88431", "city" : "NEWKIRK", "loc" : [ -104.243323, 35.084746 ], "pop" : 40, "state" : "NM" }
+{ "_id" : "88432", "city" : "PUERTO DE LUNA", "loc" : [ -104.619645, 34.847826 ], "pop" : 66, "state" : "NM" }
+{ "_id" : "88433", "city" : "QUAY", "loc" : [ -103.78176, 34.929916 ], "pop" : 10, "state" : "NM" }
+{ "_id" : "88434", "city" : "SAN JON", "loc" : [ -103.284599, 35.119848 ], "pop" : 283, "state" : "NM" }
+{ "_id" : "88435", "city" : "PASTURA", "loc" : [ -104.682155, 34.933276 ], "pop" : 2714, "state" : "NM" }
+{ "_id" : "88436", "city" : "SEDAN", "loc" : [ -103.14488, 36.226027 ], "pop" : 105, "state" : "NM" }
+{ "_id" : "88437", "city" : "SENECA", "loc" : [ -103.089394, 36.6279 ], "pop" : 54, "state" : "NM" }
+{ "_id" : "88438", "city" : "STEAD", "loc" : [ -103.121117, 36.12359 ], "pop" : 140, "state" : "NM" }
+{ "_id" : "88439", "city" : "TREMENTINA", "loc" : [ -104.616341, 35.584945 ], "pop" : 125, "state" : "NM" }
+{ "_id" : "88441", "city" : "BELL RANCH", "loc" : [ -104.111991, 35.638425 ], "pop" : 80, "state" : "NM" }
+{ "_id" : "89001", "city" : "ALAMO", "loc" : [ -115.308032, 37.325866 ], "pop" : 926, "state" : "NV" }
+{ "_id" : "89005", "city" : "BOULDER CITY", "loc" : [ -114.834413, 35.972711 ], "pop" : 12920, "state" : "NV" }
+{ "_id" : "89008", "city" : "CALIENTE", "loc" : [ -114.509727, 37.612817 ], "pop" : 1214, "state" : "NV" }
+{ "_id" : "89013", "city" : "GOLDFIELD", "loc" : [ -117.269379, 37.834364 ], "pop" : 712, "state" : "NV" }
+{ "_id" : "89014", "city" : "HENDERSON", "loc" : [ -115.077968, 36.056435 ], "pop" : 27761, "state" : "NV" }
+{ "_id" : "89015", "city" : "HENDERSON", "loc" : [ -114.971809, 36.035705 ], "pop" : 35694, "state" : "NV" }
+{ "_id" : "89017", "city" : "HIKO", "loc" : [ -115.177158, 37.651695 ], "pop" : 97, "state" : "NV" }
+{ "_id" : "89018", "city" : "INDIAN SPRINGS", "loc" : [ -115.581067, 36.407223 ], "pop" : 4114, "state" : "NV" }
+{ "_id" : "89019", "city" : "GOODSPRINGS", "loc" : [ -115.469154, 35.854839 ], "pop" : 1344, "state" : "NV" }
+{ "_id" : "89020", "city" : "AMARGOSA VALLEY", "loc" : [ -116.57755, 36.944007 ], "pop" : 3506, "state" : "NV" }
+{ "_id" : "89029", "city" : "LAUGHLIN", "loc" : [ -114.636769, 35.132138 ], "pop" : 4801, "state" : "NV" }
+{ "_id" : "89030", "city" : "NORTH LAS VEGAS", "loc" : [ -114.851389, 36.4475 ], "pop" : 16, "state" : "NV" }
+{ "_id" : "89031", "city" : "NORTH LAS VEGAS", "loc" : [ -115.124832, 36.206228 ], "pop" : 48113, "state" : "NV" }
+{ "_id" : "89040", "city" : "OVERTON", "loc" : [ -114.378202, 36.637236 ], "pop" : 8191, "state" : "NV" }
+{ "_id" : "89041", "city" : "PAHRUMP", "loc" : [ -116.014661, 36.204039 ], "pop" : 7440, "state" : "NV" }
+{ "_id" : "89043", "city" : "PIOCHE", "loc" : [ -114.396824, 37.898097 ], "pop" : 1538, "state" : "NV" }
+{ "_id" : "89045", "city" : "ROUND MOUNTAIN", "loc" : [ -117.127989, 38.682886 ], "pop" : 1302, "state" : "NV" }
+{ "_id" : "89046", "city" : "COTTONWOOD COVE", "loc" : [ -114.924182, 35.447601 ], "pop" : 948, "state" : "NV" }
+{ "_id" : "89047", "city" : "SILVERPEAK", "loc" : [ -117.94592, 37.76444 ], "pop" : 632, "state" : "NV" }
+{ "_id" : "89049", "city" : "TONOPAH", "loc" : [ -117.089886, 38.204273 ], "pop" : 4724, "state" : "NV" }
+{ "_id" : "89101", "city" : "LAS VEGAS", "loc" : [ -115.122366, 36.172082 ], "pop" : 40270, "state" : "NV" }
+{ "_id" : "89102", "city" : "LAS VEGAS", "loc" : [ -115.200351, 36.143303 ], "pop" : 48070, "state" : "NV" }
+{ "_id" : "89103", "city" : "LAS VEGAS", "loc" : [ -115.216072, 36.114865 ], "pop" : 33258, "state" : "NV" }
+{ "_id" : "89104", "city" : "LAS VEGAS", "loc" : [ -115.109195, 36.15197 ], "pop" : 26805, "state" : "NV" }
+{ "_id" : "89106", "city" : "LAS VEGAS", "loc" : [ -115.161703, 36.184673 ], "pop" : 21458, "state" : "NV" }
+{ "_id" : "89107", "city" : "LAS VEGAS", "loc" : [ -115.217638, 36.170457 ], "pop" : 32628, "state" : "NV" }
+{ "_id" : "89108", "city" : "LAS VEGAS", "loc" : [ -115.223259, 36.204399 ], "pop" : 46924, "state" : "NV" }
+{ "_id" : "89109", "city" : "LAS VEGAS", "loc" : [ -115.145378, 36.125991 ], "pop" : 35139, "state" : "NV" }
+{ "_id" : "89110", "city" : "LAS VEGAS", "loc" : [ -115.066892, 36.173031 ], "pop" : 43396, "state" : "NV" }
+{ "_id" : "89113", "city" : "LAS VEGAS", "loc" : [ -115.256614, 36.085366 ], "pop" : 1801, "state" : "NV" }
+{ "_id" : "89115", "city" : "LAS VEGAS", "loc" : [ -115.067062, 36.215818 ], "pop" : 51532, "state" : "NV" }
+{ "_id" : "89117", "city" : "LAS VEGAS", "loc" : [ -115.275518, 36.130196 ], "pop" : 30271, "state" : "NV" }
+{ "_id" : "89118", "city" : "LAS VEGAS", "loc" : [ -115.216856, 36.081052 ], "pop" : 9932, "state" : "NV" }
+{ "_id" : "89119", "city" : "LAS VEGAS", "loc" : [ -115.136463, 36.100836 ], "pop" : 38719, "state" : "NV" }
+{ "_id" : "89120", "city" : "LAS VEGAS", "loc" : [ -115.088485, 36.091423 ], "pop" : 16191, "state" : "NV" }
+{ "_id" : "89121", "city" : "LAS VEGAS", "loc" : [ -115.090219, 36.12318 ], "pop" : 50168, "state" : "NV" }
+{ "_id" : "89122", "city" : "LAS VEGAS", "loc" : [ -115.052322, 36.120501 ], "pop" : 27409, "state" : "NV" }
+{ "_id" : "89123", "city" : "LAS VEGAS", "loc" : [ -115.146182, 36.038273 ], "pop" : 6706, "state" : "NV" }
+{ "_id" : "89124", "city" : "LAS VEGAS", "loc" : [ -115.095067, 35.963391 ], "pop" : 2580, "state" : "NV" }
+{ "_id" : "89128", "city" : "LAS VEGAS", "loc" : [ -115.256252, 36.175992 ], "pop" : 18956, "state" : "NV" }
+{ "_id" : "89129", "city" : "LAS VEGAS", "loc" : [ -115.274254, 36.245004 ], "pop" : 5610, "state" : "NV" }
+{ "_id" : "89130", "city" : "LAS VEGAS", "loc" : [ -115.221032, 36.247137 ], "pop" : 4383, "state" : "NV" }
+{ "_id" : "89131", "city" : "LAS VEGAS", "loc" : [ -115.241942, 36.295604 ], "pop" : 1721, "state" : "NV" }
+{ "_id" : "89134", "city" : "LAS VEGAS", "loc" : [ -115.294123, 36.209234 ], "pop" : 3630, "state" : "NV" }
+{ "_id" : "89301", "city" : "ELY", "loc" : [ -114.878011, 39.309356 ], "pop" : 8558, "state" : "NV" }
+{ "_id" : "89310", "city" : "AUSTIN", "loc" : [ -117.081063, 39.507986 ], "pop" : 1026, "state" : "NV" }
+{ "_id" : "89311", "city" : "BAKER", "loc" : [ -114.246165, 39.065996 ], "pop" : 269, "state" : "NV" }
+{ "_id" : "89316", "city" : "EUREKA", "loc" : [ -115.994308, 39.589661 ], "pop" : 1118, "state" : "NV" }
+{ "_id" : "89317", "city" : "LUND", "loc" : [ -115.044026, 38.904633 ], "pop" : 437, "state" : "NV" }
+{ "_id" : "89403", "city" : "DAYTON", "loc" : [ -119.52872, 39.280594 ], "pop" : 2183, "state" : "NV" }
+{ "_id" : "89404", "city" : "DENIO", "loc" : [ -118.731962, 41.704263 ], "pop" : 199, "state" : "NV" }
+{ "_id" : "89405", "city" : "EMPIRE", "loc" : [ -119.655265, 40.357703 ], "pop" : 246, "state" : "NV" }
+{ "_id" : "89406", "city" : "FALLON", "loc" : [ -118.786112, 39.470254 ], "pop" : 17938, "state" : "NV" }
+{ "_id" : "89408", "city" : "FERNLEY", "loc" : [ -119.235044, 39.601888 ], "pop" : 5188, "state" : "NV" }
+{ "_id" : "89409", "city" : "GABBS", "loc" : [ -117.868556, 38.880226 ], "pop" : 809, "state" : "NV" }
+{ "_id" : "89410", "city" : "GARDNERVILLE", "loc" : [ -119.726902, 38.898268 ], "pop" : 15778, "state" : "NV" }
+{ "_id" : "89412", "city" : "GERLACH", "loc" : [ -119.377441, 40.674645 ], "pop" : 469, "state" : "NV" }
+{ "_id" : "89413", "city" : "GLENBROOK", "loc" : [ -119.927776, 38.993752 ], "pop" : 5705, "state" : "NV" }
+{ "_id" : "89414", "city" : "GOLCONDA", "loc" : [ -117.334929, 40.968325 ], "pop" : 411, "state" : "NV" }
+{ "_id" : "89415", "city" : "HAWTHORNE", "loc" : [ -118.641143, 38.534658 ], "pop" : 5172, "state" : "NV" }
+{ "_id" : "89418", "city" : "UNIONVILLE", "loc" : [ -118.02115, 40.652217 ], "pop" : 1060, "state" : "NV" }
+{ "_id" : "89419", "city" : "LOVELOCK", "loc" : [ -118.468915, 40.1819 ], "pop" : 3276, "state" : "NV" }
+{ "_id" : "89420", "city" : "LUNING", "loc" : [ -118.157114, 38.406072 ], "pop" : 501, "state" : "NV" }
+{ "_id" : "89423", "city" : "MINDEN", "loc" : [ -119.731363, 39.021766 ], "pop" : 3385, "state" : "NV" }
+{ "_id" : "89424", "city" : "NIXON", "loc" : [ -119.464262, 39.885388 ], "pop" : 610, "state" : "NV" }
+{ "_id" : "89425", "city" : "OROVADA", "loc" : [ -117.775458, 41.822001 ], "pop" : 1039, "state" : "NV" }
+{ "_id" : "89426", "city" : "PARADISE VALLEY", "loc" : [ -117.572848, 41.505726 ], "pop" : 244, "state" : "NV" }
+{ "_id" : "89427", "city" : "SCHURZ", "loc" : [ -118.775578, 38.957527 ], "pop" : 802, "state" : "NV" }
+{ "_id" : "89429", "city" : "SILVER SPRINGS", "loc" : [ -119.270503, 39.380045 ], "pop" : 3261, "state" : "NV" }
+{ "_id" : "89430", "city" : "SMITH", "loc" : [ -119.389005, 38.917166 ], "pop" : 70, "state" : "NV" }
+{ "_id" : "89431", "city" : "SPARKS", "loc" : [ -119.755588, 39.547254 ], "pop" : 33923, "state" : "NV" }
+{ "_id" : "89433", "city" : "SUN VALLEY", "loc" : [ -119.775363, 39.595477 ], "pop" : 11261, "state" : "NV" }
+{ "_id" : "89434", "city" : "SPARKS", "loc" : [ -119.717754, 39.550229 ], "pop" : 20249, "state" : "NV" }
+{ "_id" : "89436", "city" : "SPARKS", "loc" : [ -119.708125, 39.626861 ], "pop" : 4228, "state" : "NV" }
+{ "_id" : "89440", "city" : "VIRGINIA CITY", "loc" : [ -119.596063, 39.387282 ], "pop" : 2526, "state" : "NV" }
+{ "_id" : "89442", "city" : "WADSWORTH", "loc" : [ -119.291778, 39.648069 ], "pop" : 757, "state" : "NV" }
+{ "_id" : "89444", "city" : "WELLINGTON", "loc" : [ -119.344901, 38.78762 ], "pop" : 1004, "state" : "NV" }
+{ "_id" : "89445", "city" : "WINNEMUCCA", "loc" : [ -117.746693, 40.966418 ], "pop" : 10951, "state" : "NV" }
+{ "_id" : "89447", "city" : "YERINGTON", "loc" : [ -119.159558, 38.986567 ], "pop" : 6157, "state" : "NV" }
+{ "_id" : "89451", "city" : "INCLINE VILLAGE", "loc" : [ -119.95206, 39.256352 ], "pop" : 7807, "state" : "NV" }
+{ "_id" : "89501", "city" : "RENO", "loc" : [ -119.811275, 39.526812 ], "pop" : 2664, "state" : "NV" }
+{ "_id" : "89502", "city" : "RENO", "loc" : [ -119.776395, 39.497239 ], "pop" : 38332, "state" : "NV" }
+{ "_id" : "89503", "city" : "RENO", "loc" : [ -119.837409, 39.5354 ], "pop" : 23955, "state" : "NV" }
+{ "_id" : "89506", "city" : "RENO", "loc" : [ -119.873505, 39.641168 ], "pop" : 24254, "state" : "NV" }
+{ "_id" : "89509", "city" : "RENO", "loc" : [ -119.823932, 39.498042 ], "pop" : 36606, "state" : "NV" }
+{ "_id" : "89510", "city" : "RENO", "loc" : [ -119.602678, 39.769919 ], "pop" : 613, "state" : "NV" }
+{ "_id" : "89511", "city" : "RENO", "loc" : [ -119.766846, 39.41512 ], "pop" : 16412, "state" : "NV" }
+{ "_id" : "89512", "city" : "RENO", "loc" : [ -119.795699, 39.548312 ], "pop" : 21009, "state" : "NV" }
+{ "_id" : "89523", "city" : "RENO", "loc" : [ -119.903065, 39.524917 ], "pop" : 7697, "state" : "NV" }
+{ "_id" : "89701", "city" : "CARSON CITY", "loc" : [ -119.745904, 39.150746 ], "pop" : 18817, "state" : "NV" }
+{ "_id" : "89703", "city" : "CARSON CITY", "loc" : [ -119.778242, 39.17036 ], "pop" : 8047, "state" : "NV" }
+{ "_id" : "89704", "city" : "CARSON CITY", "loc" : [ -119.828624, 39.089756 ], "pop" : 82, "state" : "NV" }
+{ "_id" : "89705", "city" : "CARSON CITY", "loc" : [ -119.782899, 39.089147 ], "pop" : 2703, "state" : "NV" }
+{ "_id" : "89706", "city" : "MOUNDHOUSE", "loc" : [ -119.742912, 39.210876 ], "pop" : 19276, "state" : "NV" }
+{ "_id" : "89801", "city" : "JIGGS", "loc" : [ -115.724679, 40.826247 ], "pop" : 24461, "state" : "NV" }
+{ "_id" : "89820", "city" : "BATTLE MOUNTAIN", "loc" : [ -116.955439, 40.621985 ], "pop" : 5240, "state" : "NV" }
+{ "_id" : "89821", "city" : "BEOWAWE", "loc" : [ -116.477387, 40.462398 ], "pop" : 429, "state" : "NV" }
+{ "_id" : "89822", "city" : "CARLIN", "loc" : [ -116.108208, 40.717216 ], "pop" : 2272, "state" : "NV" }
+{ "_id" : "89823", "city" : "DEETH", "loc" : [ -115.371729, 41.431033 ], "pop" : 69, "state" : "NV" }
+{ "_id" : "89825", "city" : "JACKPOT", "loc" : [ -115.112886, 41.839591 ], "pop" : 95, "state" : "NV" }
+{ "_id" : "89831", "city" : "MOUNTAIN CITY", "loc" : [ -116.113801, 41.870781 ], "pop" : 1259, "state" : "NV" }
+{ "_id" : "89833", "city" : "RUBY VALLEY", "loc" : [ -115.231219, 40.399514 ], "pop" : 37, "state" : "NV" }
+{ "_id" : "89834", "city" : "TUSCARORA", "loc" : [ -116.931141, 41.171527 ], "pop" : 1, "state" : "NV" }
+{ "_id" : "89835", "city" : "OASIS", "loc" : [ -114.532752, 41.129798 ], "pop" : 5336, "state" : "NV" }
+{ "_id" : "90001", "city" : "LOS ANGELES", "loc" : [ -118.247896, 33.973093 ], "pop" : 51841, "state" : "CA" }
+{ "_id" : "90002", "city" : "LOS ANGELES", "loc" : [ -118.246213, 33.94969 ], "pop" : 40629, "state" : "CA" }
+{ "_id" : "90003", "city" : "LOS ANGELES", "loc" : [ -118.272739, 33.965335 ], "pop" : 53938, "state" : "CA" }
+{ "_id" : "90004", "city" : "LOS ANGELES", "loc" : [ -118.302863, 34.076163 ], "pop" : 64062, "state" : "CA" }
+{ "_id" : "90005", "city" : "LOS ANGELES", "loc" : [ -118.301197, 34.058508 ], "pop" : 35864, "state" : "CA" }
+{ "_id" : "90006", "city" : "LOS ANGELES", "loc" : [ -118.291687, 34.049323 ], "pop" : 63389, "state" : "CA" }
+{ "_id" : "90007", "city" : "LOS ANGELES", "loc" : [ -118.287095, 34.029442 ], "pop" : 46985, "state" : "CA" }
+{ "_id" : "90008", "city" : "LOS ANGELES", "loc" : [ -118.341123, 34.011643 ], "pop" : 33073, "state" : "CA" }
+{ "_id" : "90010", "city" : "LOS ANGELES", "loc" : [ -118.302664, 34.060633 ], "pop" : 5335, "state" : "CA" }
+{ "_id" : "90011", "city" : "LOS ANGELES", "loc" : [ -118.258189, 34.007856 ], "pop" : 96074, "state" : "CA" }
+{ "_id" : "90012", "city" : "LOS ANGELES", "loc" : [ -118.238479, 34.061396 ], "pop" : 28518, "state" : "CA" }
+{ "_id" : "90013", "city" : "LOS ANGELES", "loc" : [ -118.243366, 34.044841 ], "pop" : 5653, "state" : "CA" }
+{ "_id" : "90014", "city" : "LOS ANGELES", "loc" : [ -118.250937, 34.044272 ], "pop" : 2715, "state" : "CA" }
+{ "_id" : "90015", "city" : "LOS ANGELES", "loc" : [ -118.271613, 34.043439 ], "pop" : 18880, "state" : "CA" }
+{ "_id" : "90016", "city" : "LOS ANGELES", "loc" : [ -118.352787, 34.029826 ], "pop" : 43669, "state" : "CA" }
+{ "_id" : "90017", "city" : "LOS ANGELES", "loc" : [ -118.266582, 34.055864 ], "pop" : 21790, "state" : "CA" }
+{ "_id" : "90018", "city" : "LOS ANGELES", "loc" : [ -118.315173, 34.028972 ], "pop" : 48267, "state" : "CA" }
+{ "_id" : "90019", "city" : "LOS ANGELES", "loc" : [ -118.33426, 34.048158 ], "pop" : 64996, "state" : "CA" }
+{ "_id" : "90020", "city" : "LOS ANGELES", "loc" : [ -118.302211, 34.066535 ], "pop" : 34926, "state" : "CA" }
+{ "_id" : "90021", "city" : "LOS ANGELES", "loc" : [ -118.244698, 34.033303 ], "pop" : 2869, "state" : "CA" }
+{ "_id" : "90022", "city" : "EAST LOS ANGELES", "loc" : [ -118.155319, 34.023638 ], "pop" : 65065, "state" : "CA" }
+{ "_id" : "90023", "city" : "LOS ANGELES", "loc" : [ -118.197498, 34.024478 ], "pop" : 47136, "state" : "CA" }
+{ "_id" : "90024", "city" : "LOS ANGELES", "loc" : [ -118.440796, 34.063691 ], "pop" : 38370, "state" : "CA" }
+{ "_id" : "90025", "city" : "LOS ANGELES", "loc" : [ -118.448717, 34.044662 ], "pop" : 37746, "state" : "CA" }
+{ "_id" : "90026", "city" : "LOS ANGELES", "loc" : [ -118.264641, 34.076629 ], "pop" : 74751, "state" : "CA" }
+{ "_id" : "90027", "city" : "LOS ANGELES", "loc" : [ -118.292516, 34.104031 ], "pop" : 50484, "state" : "CA" }
+{ "_id" : "90028", "city" : "LOS ANGELES", "loc" : [ -118.325363, 34.100549 ], "pop" : 30152, "state" : "CA" }
+{ "_id" : "90029", "city" : "LOS ANGELES", "loc" : [ -118.294393, 34.089982 ], "pop" : 41120, "state" : "CA" }
+{ "_id" : "90031", "city" : "LOS ANGELES", "loc" : [ -118.211279, 34.078349 ], "pop" : 39706, "state" : "CA" }
+{ "_id" : "90032", "city" : "LOS ANGELES", "loc" : [ -118.175323, 34.081785 ], "pop" : 46602, "state" : "CA" }
+{ "_id" : "90033", "city" : "LOS ANGELES", "loc" : [ -118.208442, 34.048676 ], "pop" : 57469, "state" : "CA" }
+{ "_id" : "90034", "city" : "LOS ANGELES", "loc" : [ -118.400482, 34.028977 ], "pop" : 53930, "state" : "CA" }
+{ "_id" : "90035", "city" : "LOS ANGELES", "loc" : [ -118.380615, 34.053096 ], "pop" : 25723, "state" : "CA" }
+{ "_id" : "90036", "city" : "LOS ANGELES", "loc" : [ -118.349175, 34.069888 ], "pop" : 29887, "state" : "CA" }
+{ "_id" : "90037", "city" : "LOS ANGELES", "loc" : [ -118.286284, 34.002982 ], "pop" : 56922, "state" : "CA" }
+{ "_id" : "90038", "city" : "LOS ANGELES", "loc" : [ -118.321489, 34.089769 ], "pop" : 33001, "state" : "CA" }
+{ "_id" : "90039", "city" : "LOS ANGELES", "loc" : [ -118.259428, 34.112089 ], "pop" : 29189, "state" : "CA" }
+{ "_id" : "90040", "city" : "CITY OF COMMERCE", "loc" : [ -118.151352, 33.99471 ], "pop" : 9689, "state" : "CA" }
+{ "_id" : "90041", "city" : "LOS ANGELES", "loc" : [ -118.208205, 34.133932 ], "pop" : 26864, "state" : "CA" }
+{ "_id" : "90042", "city" : "LOS ANGELES", "loc" : [ -118.192902, 34.114527 ], "pop" : 60003, "state" : "CA" }
+{ "_id" : "90043", "city" : "LOS ANGELES", "loc" : [ -118.33211, 33.987099 ], "pop" : 45397, "state" : "CA" }
+{ "_id" : "90044", "city" : "LOS ANGELES", "loc" : [ -118.290119, 33.955089 ], "pop" : 83958, "state" : "CA" }
+{ "_id" : "90045", "city" : "LOS ANGELES", "loc" : [ -118.394128, 33.963075 ], "pop" : 36480, "state" : "CA" }
+{ "_id" : "90046", "city" : "COLE", "loc" : [ -118.357979, 34.09743 ], "pop" : 48423, "state" : "CA" }
+{ "_id" : "90047", "city" : "LOS ANGELES", "loc" : [ -118.307304, 33.956896 ], "pop" : 47975, "state" : "CA" }
+{ "_id" : "90048", "city" : "LOS ANGELES", "loc" : [ -118.371969, 34.073656 ], "pop" : 20863, "state" : "CA" }
+{ "_id" : "90049", "city" : "LOS ANGELES", "loc" : [ -118.473967, 34.066 ], "pop" : 35507, "state" : "CA" }
+{ "_id" : "90056", "city" : "LOS ANGELES", "loc" : [ -118.370703, 33.985329 ], "pop" : 8108, "state" : "CA" }
+{ "_id" : "90057", "city" : "LOS ANGELES", "loc" : [ -118.276262, 34.062172 ], "pop" : 39017, "state" : "CA" }
+{ "_id" : "90058", "city" : "VERNON", "loc" : [ -118.235365, 33.997344 ], "pop" : 4090, "state" : "CA" }
+{ "_id" : "90059", "city" : "LOS ANGELES", "loc" : [ -118.24628, 33.929331 ], "pop" : 34536, "state" : "CA" }
+{ "_id" : "90061", "city" : "LOS ANGELES", "loc" : [ -118.271638, 33.924493 ], "pop" : 21856, "state" : "CA" }
+{ "_id" : "90062", "city" : "LOS ANGELES", "loc" : [ -118.307277, 34.00324 ], "pop" : 27517, "state" : "CA" }
+{ "_id" : "90063", "city" : "HAZARD", "loc" : [ -118.185432, 34.044017 ], "pop" : 61123, "state" : "CA" }
+{ "_id" : "90064", "city" : "LOS ANGELES", "loc" : [ -118.425911, 34.035279 ], "pop" : 23530, "state" : "CA" }
+{ "_id" : "90065", "city" : "LOS ANGELES", "loc" : [ -118.226637, 34.107307 ], "pop" : 45578, "state" : "CA" }
+{ "_id" : "90066", "city" : "LOS ANGELES", "loc" : [ -118.429769, 34.002956 ], "pop" : 53095, "state" : "CA" }
+{ "_id" : "90067", "city" : "LOS ANGELES", "loc" : [ -118.409479, 34.055146 ], "pop" : 2731, "state" : "CA" }
+{ "_id" : "90068", "city" : "LOS ANGELES", "loc" : [ -118.330476, 34.115625 ], "pop" : 25615, "state" : "CA" }
+{ "_id" : "90069", "city" : "WEST HOLLYWOOD", "loc" : [ -118.378753, 34.090573 ], "pop" : 20587, "state" : "CA" }
+{ "_id" : "90071", "city" : "LOS ANGELES", "loc" : [ -118.257127, 34.052043 ], "pop" : 15, "state" : "CA" }
+{ "_id" : "90077", "city" : "LOS ANGELES", "loc" : [ -118.450155, 34.111245 ], "pop" : 7989, "state" : "CA" }
+{ "_id" : "90201", "city" : "BELL GARDENS", "loc" : [ -118.17205, 33.969177 ], "pop" : 99568, "state" : "CA" }
+{ "_id" : "90210", "city" : "BEVERLY HILLS", "loc" : [ -118.406477, 34.090107 ], "pop" : 20700, "state" : "CA" }
+{ "_id" : "90211", "city" : "BEVERLY HILLS", "loc" : [ -118.383007, 34.065217 ], "pop" : 7746, "state" : "CA" }
+{ "_id" : "90212", "city" : "BEVERLY HILLS", "loc" : [ -118.399544, 34.061855 ], "pop" : 10725, "state" : "CA" }
+{ "_id" : "90220", "city" : "RANCHO DOMINGUEZ", "loc" : [ -118.239044, 33.890654 ], "pop" : 47631, "state" : "CA" }
+{ "_id" : "90221", "city" : "EAST RANCHO DOMI", "loc" : [ -118.203724, 33.897324 ], "pop" : 47844, "state" : "CA" }
+{ "_id" : "90222", "city" : "ROSEWOOD", "loc" : [ -118.234034, 33.911535 ], "pop" : 28754, "state" : "CA" }
+{ "_id" : "90230", "city" : "CULVER CITY", "loc" : [ -118.399115, 33.994927 ], "pop" : 32207, "state" : "CA" }
+{ "_id" : "90232", "city" : "CULVER CITY", "loc" : [ -118.397332, 34.016809 ], "pop" : 16138, "state" : "CA" }
+{ "_id" : "90240", "city" : "DOWNEY", "loc" : [ -118.117381, 33.958135 ], "pop" : 20273, "state" : "CA" }
+{ "_id" : "90241", "city" : "DOWNEY", "loc" : [ -118.13062, 33.941612 ], "pop" : 34348, "state" : "CA" }
+{ "_id" : "90242", "city" : "DOWNEY", "loc" : [ -118.139465, 33.921789 ], "pop" : 36988, "state" : "CA" }
+{ "_id" : "90245", "city" : "EL SEGUNDO", "loc" : [ -118.411924, 33.924275 ], "pop" : 15162, "state" : "CA" }
+{ "_id" : "90247", "city" : "GARDENA", "loc" : [ -118.296122, 33.892463 ], "pop" : 42072, "state" : "CA" }
+{ "_id" : "90248", "city" : "GARDENA", "loc" : [ -118.289312, 33.874506 ], "pop" : 9529, "state" : "CA" }
+{ "_id" : "90249", "city" : "GARDENA", "loc" : [ -118.319854, 33.899762 ], "pop" : 25806, "state" : "CA" }
+{ "_id" : "90250", "city" : "HOLLY PARK", "loc" : [ -118.346978, 33.913214 ], "pop" : 78511, "state" : "CA" }
+{ "_id" : "90254", "city" : "HERMOSA BEACH", "loc" : [ -118.395511, 33.864309 ], "pop" : 18289, "state" : "CA" }
+{ "_id" : "90255", "city" : "HUNTINGTON PARK", "loc" : [ -118.216053, 33.976879 ], "pop" : 72139, "state" : "CA" }
+{ "_id" : "90260", "city" : "LAWNDALE", "loc" : [ -118.351014, 33.887908 ], "pop" : 29576, "state" : "CA" }
+{ "_id" : "90262", "city" : "LYNWOOD", "loc" : [ -118.201289, 33.924076 ], "pop" : 61606, "state" : "CA" }
+{ "_id" : "90265", "city" : "MALIBU", "loc" : [ -118.735149, 34.040184 ], "pop" : 17850, "state" : "CA" }
+{ "_id" : "90266", "city" : "MANHATTAN BEACH", "loc" : [ -118.399562, 33.889594 ], "pop" : 31984, "state" : "CA" }
+{ "_id" : "90270", "city" : "MAYWOOD", "loc" : [ -118.187685, 33.988992 ], "pop" : 27801, "state" : "CA" }
+{ "_id" : "90272", "city" : "PACIFIC PALISADE", "loc" : [ -118.536874, 34.054097 ], "pop" : 20984, "state" : "CA" }
+{ "_id" : "90274", "city" : "PALOS VERDES EST", "loc" : [ -118.374763, 33.770094 ], "pop" : 60381, "state" : "CA" }
+{ "_id" : "90277", "city" : "REDONDO BEACH", "loc" : [ -118.383221, 33.830656 ], "pop" : 33102, "state" : "CA" }
+{ "_id" : "90278", "city" : "REDONDO BEACH", "loc" : [ -118.371459, 33.870654 ], "pop" : 34873, "state" : "CA" }
+{ "_id" : "90280", "city" : "SOUTH GATE", "loc" : [ -118.201349, 33.94617 ], "pop" : 87026, "state" : "CA" }
+{ "_id" : "90290", "city" : "TOPANGA", "loc" : [ -118.602268, 34.10759 ], "pop" : 5430, "state" : "CA" }
+{ "_id" : "90291", "city" : "VENICE", "loc" : [ -118.463463, 33.993772 ], "pop" : 32987, "state" : "CA" }
+{ "_id" : "90292", "city" : "MARINA DEL REY", "loc" : [ -118.452475, 33.977876 ], "pop" : 16572, "state" : "CA" }
+{ "_id" : "90293", "city" : "PLAYA DEL REY", "loc" : [ -118.437314, 33.957745 ], "pop" : 11477, "state" : "CA" }
+{ "_id" : "90301", "city" : "INGLEWOOD", "loc" : [ -118.355575, 33.955048 ], "pop" : 36481, "state" : "CA" }
+{ "_id" : "90302", "city" : "INGLEWOOD", "loc" : [ -118.354805, 33.974496 ], "pop" : 28681, "state" : "CA" }
+{ "_id" : "90303", "city" : "INGLEWOOD", "loc" : [ -118.332058, 33.937691 ], "pop" : 26418, "state" : "CA" }
+{ "_id" : "90304", "city" : "LENNOX", "loc" : [ -118.355562, 33.938514 ], "pop" : 28216, "state" : "CA" }
+{ "_id" : "90305", "city" : "INGLEWOOD", "loc" : [ -118.32585, 33.958304 ], "pop" : 14370, "state" : "CA" }
+{ "_id" : "90401", "city" : "SANTA MONICA", "loc" : [ -118.490708, 34.017628 ], "pop" : 4813, "state" : "CA" }
+{ "_id" : "90402", "city" : "SANTA MONICA", "loc" : [ -118.503011, 34.034875 ], "pop" : 14628, "state" : "CA" }
+{ "_id" : "90403", "city" : "SANTA MONICA", "loc" : [ -118.49241, 34.028658 ], "pop" : 22303, "state" : "CA" }
+{ "_id" : "90404", "city" : "SANTA MONICA", "loc" : [ -118.4733, 34.026828 ], "pop" : 22480, "state" : "CA" }
+{ "_id" : "90405", "city" : "SANTA MONICA", "loc" : [ -118.471708, 34.01001 ], "pop" : 26081, "state" : "CA" }
+{ "_id" : "90501", "city" : "TORRANCE", "loc" : [ -118.31183, 33.826817 ], "pop" : 37691, "state" : "CA" }
+{ "_id" : "90502", "city" : "TORRANCE", "loc" : [ -118.292039, 33.828555 ], "pop" : 15963, "state" : "CA" }
+{ "_id" : "90503", "city" : "TORRANCE", "loc" : [ -118.354236, 33.839709 ], "pop" : 40351, "state" : "CA" }
+{ "_id" : "90504", "city" : "TORRANCE", "loc" : [ -118.329517, 33.870815 ], "pop" : 30245, "state" : "CA" }
+{ "_id" : "90505", "city" : "TORRANCE", "loc" : [ -118.350733, 33.810635 ], "pop" : 33933, "state" : "CA" }
+{ "_id" : "90506", "city" : "TORRANCE", "loc" : [ -118.329543, 33.885367 ], "pop" : 0, "state" : "CA" }
+{ "_id" : "90601", "city" : "WHITTIER", "loc" : [ -118.037139, 34.001119 ], "pop" : 30501, "state" : "CA" }
+{ "_id" : "90602", "city" : "WHITTIER", "loc" : [ -118.033703, 33.96931 ], "pop" : 23508, "state" : "CA" }
+{ "_id" : "90603", "city" : "WHITTIER", "loc" : [ -117.992685, 33.943199 ], "pop" : 18063, "state" : "CA" }
+{ "_id" : "90604", "city" : "WHITTIER", "loc" : [ -118.012075, 33.929931 ], "pop" : 36371, "state" : "CA" }
+{ "_id" : "90605", "city" : "WHITTIER", "loc" : [ -118.035568, 33.941338 ], "pop" : 34035, "state" : "CA" }
+{ "_id" : "90606", "city" : "LOS NIETOS", "loc" : [ -118.065639, 33.977019 ], "pop" : 30185, "state" : "CA" }
+{ "_id" : "90620", "city" : "BUENA PARK", "loc" : [ -118.011359, 33.840607 ], "pop" : 42966, "state" : "CA" }
+{ "_id" : "90621", "city" : "BUENA PARK", "loc" : [ -117.994257, 33.873136 ], "pop" : 27502, "state" : "CA" }
+{ "_id" : "90623", "city" : "CERRITOS", "loc" : [ -118.040618, 33.849017 ], "pop" : 15066, "state" : "CA" }
+{ "_id" : "90630", "city" : "CYPRESS", "loc" : [ -118.038696, 33.818613 ], "pop" : 43055, "state" : "CA" }
+{ "_id" : "90631", "city" : "LA HABRA HEIGHTS", "loc" : [ -117.949703, 33.932173 ], "pop" : 59113, "state" : "CA" }
+{ "_id" : "90638", "city" : "LA MIRADA", "loc" : [ -118.010081, 33.906681 ], "pop" : 40452, "state" : "CA" }
+{ "_id" : "90640", "city" : "MONTEBELLO", "loc" : [ -118.112986, 34.013342 ], "pop" : 59068, "state" : "CA" }
+{ "_id" : "90650", "city" : "NORWALK", "loc" : [ -118.081767, 33.90564 ], "pop" : 94188, "state" : "CA" }
+{ "_id" : "90660", "city" : "PICO RIVERA", "loc" : [ -118.088269, 33.98857 ], "pop" : 58891, "state" : "CA" }
+{ "_id" : "90670", "city" : "SANTA FE SPRINGS", "loc" : [ -118.083801, 33.946407 ], "pop" : 14417, "state" : "CA" }
+{ "_id" : "90680", "city" : "STANTON", "loc" : [ -117.994709, 33.803029 ], "pop" : 25160, "state" : "CA" }
+{ "_id" : "90701", "city" : "CERRITOS", "loc" : [ -118.068046, 33.866568 ], "pop" : 69130, "state" : "CA" }
+{ "_id" : "90704", "city" : "AVALON", "loc" : [ -118.343706, 33.331963 ], "pop" : 3445, "state" : "CA" }
+{ "_id" : "90706", "city" : "BELLFLOWER", "loc" : [ -118.126527, 33.886676 ], "pop" : 61650, "state" : "CA" }
+{ "_id" : "90710", "city" : "HARBOR CITY", "loc" : [ -118.299114, 33.797006 ], "pop" : 24418, "state" : "CA" }
+{ "_id" : "90712", "city" : "LAKEWOOD", "loc" : [ -118.145727, 33.851201 ], "pop" : 28992, "state" : "CA" }
+{ "_id" : "90713", "city" : "LAKEWOOD", "loc" : [ -118.111464, 33.847302 ], "pop" : 26646, "state" : "CA" }
+{ "_id" : "90715", "city" : "LAKEWOOD", "loc" : [ -118.076707, 33.840453 ], "pop" : 17983, "state" : "CA" }
+{ "_id" : "90716", "city" : "HAWAIIAN GARDENS", "loc" : [ -118.072964, 33.82958 ], "pop" : 13921, "state" : "CA" }
+{ "_id" : "90717", "city" : "RANCHO PALOS VER", "loc" : [ -118.31693, 33.793339 ], "pop" : 19635, "state" : "CA" }
+{ "_id" : "90720", "city" : "ROSSMOOR", "loc" : [ -118.069891, 33.795291 ], "pop" : 21695, "state" : "CA" }
+{ "_id" : "90723", "city" : "PARAMOUNT", "loc" : [ -118.163152, 33.896867 ], "pop" : 46679, "state" : "CA" }
+{ "_id" : "90731", "city" : "SAN PEDRO", "loc" : [ -118.291425, 33.733894 ], "pop" : 58821, "state" : "CA" }
+{ "_id" : "90732", "city" : "RANCHO PALOS VER", "loc" : [ -118.310597, 33.744947 ], "pop" : 26244, "state" : "CA" }
+{ "_id" : "90740", "city" : "SEAL BEACH", "loc" : [ -118.08428, 33.760971 ], "pop" : 24537, "state" : "CA" }
+{ "_id" : "90744", "city" : "WILMINGTON", "loc" : [ -118.264451, 33.785475 ], "pop" : 49178, "state" : "CA" }
+{ "_id" : "90745", "city" : "CARSON", "loc" : [ -118.268352, 33.822968 ], "pop" : 50251, "state" : "CA" }
+{ "_id" : "90746", "city" : "CARSON", "loc" : [ -118.255449, 33.858444 ], "pop" : 25970, "state" : "CA" }
+{ "_id" : "90802", "city" : "LONG BEACH", "loc" : [ -118.182025, 33.770553 ], "pop" : 33906, "state" : "CA" }
+{ "_id" : "90803", "city" : "LONG BEACH", "loc" : [ -118.134073, 33.761932 ], "pop" : 32492, "state" : "CA" }
+{ "_id" : "90804", "city" : "SIGNAL HILL", "loc" : [ -118.155187, 33.782993 ], "pop" : 36092, "state" : "CA" }
+{ "_id" : "90805", "city" : "LONG BEACH", "loc" : [ -118.180102, 33.863457 ], "pop" : 74011, "state" : "CA" }
+{ "_id" : "90806", "city" : "SIGNAL HILL", "loc" : [ -118.187443, 33.799319 ], "pop" : 44982, "state" : "CA" }
+{ "_id" : "90807", "city" : "SIGNAL HILL", "loc" : [ -118.18092, 33.830712 ], "pop" : 28037, "state" : "CA" }
+{ "_id" : "90808", "city" : "LONG BEACH", "loc" : [ -118.110299, 33.824145 ], "pop" : 37809, "state" : "CA" }
+{ "_id" : "90810", "city" : "CARSON", "loc" : [ -118.215006, 33.810985 ], "pop" : 36694, "state" : "CA" }
+{ "_id" : "90813", "city" : "LONG BEACH", "loc" : [ -118.183488, 33.78202 ], "pop" : 58109, "state" : "CA" }
+{ "_id" : "90814", "city" : "LONG BEACH", "loc" : [ -118.147988, 33.771576 ], "pop" : 17359, "state" : "CA" }
+{ "_id" : "90815", "city" : "LONG BEACH", "loc" : [ -118.119249, 33.793908 ], "pop" : 38603, "state" : "CA" }
+{ "_id" : "90822", "city" : "LONG BEACH", "loc" : [ -118.239257, 33.744415 ], "pop" : 7362, "state" : "CA" }
+{ "_id" : "91001", "city" : "ALTADENA", "loc" : [ -118.13919, 34.191187 ], "pop" : 36013, "state" : "CA" }
+{ "_id" : "91006", "city" : "ARCADIA", "loc" : [ -118.026374, 34.132389 ], "pop" : 30550, "state" : "CA" }
+{ "_id" : "91007", "city" : "ARCADIA", "loc" : [ -118.051483, 34.124271 ], "pop" : 25675, "state" : "CA" }
+{ "_id" : "91010", "city" : "BRADBURY", "loc" : [ -117.967005, 34.137445 ], "pop" : 26462, "state" : "CA" }
+{ "_id" : "91011", "city" : "FLINTRIDGE", "loc" : [ -118.199008, 34.209282 ], "pop" : 19699, "state" : "CA" }
+{ "_id" : "91016", "city" : "MONROVIA", "loc" : [ -118.001376, 34.143959 ], "pop" : 39015, "state" : "CA" }
+{ "_id" : "91020", "city" : "MONTROSE", "loc" : [ -118.230529, 34.211425 ], "pop" : 6536, "state" : "CA" }
+{ "_id" : "91024", "city" : "SIERRA MADRE", "loc" : [ -118.051916, 34.165101 ], "pop" : 10560, "state" : "CA" }
+{ "_id" : "91030", "city" : "SOUTH PASADENA", "loc" : [ -118.154696, 34.110939 ], "pop" : 23936, "state" : "CA" }
+{ "_id" : "91040", "city" : "SHADOW HILLS", "loc" : [ -118.321359, 34.261025 ], "pop" : 18303, "state" : "CA" }
+{ "_id" : "91042", "city" : "TUJUNGA", "loc" : [ -118.284856, 34.254389 ], "pop" : 24853, "state" : "CA" }
+{ "_id" : "91101", "city" : "PASADENA", "loc" : [ -118.139119, 34.146762 ], "pop" : 16045, "state" : "CA" }
+{ "_id" : "91103", "city" : "PASADENA", "loc" : [ -118.155119, 34.166906 ], "pop" : 26641, "state" : "CA" }
+{ "_id" : "91104", "city" : "PASADENA", "loc" : [ -118.12609, 34.167776 ], "pop" : 37973, "state" : "CA" }
+{ "_id" : "91105", "city" : "PASADENA", "loc" : [ -118.163577, 34.135455 ], "pop" : 11165, "state" : "CA" }
+{ "_id" : "91106", "city" : "PASADENA", "loc" : [ -118.126647, 34.143527 ], "pop" : 23854, "state" : "CA" }
+{ "_id" : "91107", "city" : "PASADENA", "loc" : [ -118.088905, 34.150997 ], "pop" : 31390, "state" : "CA" }
+{ "_id" : "91108", "city" : "SAN MARINO", "loc" : [ -118.111745, 34.120698 ], "pop" : 12953, "state" : "CA" }
+{ "_id" : "91201", "city" : "GLENDALE", "loc" : [ -118.289892, 34.171606 ], "pop" : 22495, "state" : "CA" }
+{ "_id" : "91202", "city" : "GLENDALE", "loc" : [ -118.265649, 34.165235 ], "pop" : 20331, "state" : "CA" }
+{ "_id" : "91203", "city" : "GLENDALE", "loc" : [ -118.263614, 34.151718 ], "pop" : 12714, "state" : "CA" }
+{ "_id" : "91204", "city" : "GLENDALE", "loc" : [ -118.259947, 34.137871 ], "pop" : 15541, "state" : "CA" }
+{ "_id" : "91205", "city" : "GLENDALE", "loc" : [ -118.24245, 34.137798 ], "pop" : 38428, "state" : "CA" }
+{ "_id" : "91206", "city" : "GLENDALE", "loc" : [ -118.232217, 34.155605 ], "pop" : 30415, "state" : "CA" }
+{ "_id" : "91207", "city" : "GLENDALE", "loc" : [ -118.245086, 34.164856 ], "pop" : 8911, "state" : "CA" }
+{ "_id" : "91208", "city" : "GLENDALE", "loc" : [ -118.234966, 34.19212 ], "pop" : 14831, "state" : "CA" }
+{ "_id" : "91214", "city" : "LA CRESCENTA", "loc" : [ -118.245687, 34.231619 ], "pop" : 27249, "state" : "CA" }
+{ "_id" : "91301", "city" : "OAK PARK", "loc" : [ -118.75718, 34.157163 ], "pop" : 35520, "state" : "CA" }
+{ "_id" : "91302", "city" : "CALABASAS", "loc" : [ -118.664103, 34.141854 ], "pop" : 12690, "state" : "CA" }
+{ "_id" : "91303", "city" : "CANOGA PARK", "loc" : [ -118.59828, 34.199257 ], "pop" : 19656, "state" : "CA" }
+{ "_id" : "91304", "city" : "CANOGA PARK", "loc" : [ -118.611059, 34.219671 ], "pop" : 43675, "state" : "CA" }
+{ "_id" : "91306", "city" : "WINNETKA", "loc" : [ -118.57492, 34.2092 ], "pop" : 39261, "state" : "CA" }
+{ "_id" : "91307", "city" : "WEST HILLS", "loc" : [ -118.638892, 34.196343 ], "pop" : 22049, "state" : "CA" }
+{ "_id" : "91311", "city" : "CHATSWORTH", "loc" : [ -118.591357, 34.258253 ], "pop" : 37225, "state" : "CA" }
+{ "_id" : "91316", "city" : "ENCINO", "loc" : [ -118.517542, 34.165479 ], "pop" : 24538, "state" : "CA" }
+{ "_id" : "91320", "city" : "NEWBURY PARK", "loc" : [ -118.935798, 34.177393 ], "pop" : 31941, "state" : "CA" }
+{ "_id" : "91321", "city" : "NEWHALL", "loc" : [ -118.523005, 34.379519 ], "pop" : 23520, "state" : "CA" }
+{ "_id" : "91324", "city" : "NORTHRIDGE", "loc" : [ -118.546595, 34.236743 ], "pop" : 23252, "state" : "CA" }
+{ "_id" : "91325", "city" : "NORTHRIDGE", "loc" : [ -118.51884, 34.235332 ], "pop" : 28071, "state" : "CA" }
+{ "_id" : "91326", "city" : "PORTER RANCH", "loc" : [ -118.541235, 34.274191 ], "pop" : 23466, "state" : "CA" }
+{ "_id" : "91330", "city" : "CALIFORNIA STATE", "loc" : [ -118.528634, 34.23805 ], "pop" : 1604, "state" : "CA" }
+{ "_id" : "91331", "city" : "ARLETA", "loc" : [ -118.420692, 34.258081 ], "pop" : 88114, "state" : "CA" }
+{ "_id" : "91335", "city" : "RESEDA", "loc" : [ -118.539071, 34.200663 ], "pop" : 62117, "state" : "CA" }
+{ "_id" : "91340", "city" : "SAN FERNANDO", "loc" : [ -118.435242, 34.287509 ], "pop" : 33379, "state" : "CA" }
+{ "_id" : "91342", "city" : "SYLMAR", "loc" : [ -118.432181, 34.30538 ], "pop" : 68612, "state" : "CA" }
+{ "_id" : "91343", "city" : "NORTH HILLS", "loc" : [ -118.47582, 34.236636 ], "pop" : 48751, "state" : "CA" }
+{ "_id" : "91344", "city" : "GRANADA HILLS", "loc" : [ -118.4992, 34.277068 ], "pop" : 45729, "state" : "CA" }
+{ "_id" : "91345", "city" : "MISSION HILLS", "loc" : [ -118.458659, 34.261873 ], "pop" : 14886, "state" : "CA" }
+{ "_id" : "91350", "city" : "AGUA DULCE", "loc" : [ -118.488955, 34.459742 ], "pop" : 31741, "state" : "CA" }
+{ "_id" : "91351", "city" : "CANYON COUNTRY", "loc" : [ -118.449011, 34.426203 ], "pop" : 47273, "state" : "CA" }
+{ "_id" : "91352", "city" : "SUN VALLEY", "loc" : [ -118.369853, 34.220907 ], "pop" : 43722, "state" : "CA" }
+{ "_id" : "91354", "city" : "VALENCIA", "loc" : [ -118.537437, 34.446608 ], "pop" : 7918, "state" : "CA" }
+{ "_id" : "91355", "city" : "VALENCIA", "loc" : [ -118.55352, 34.398456 ], "pop" : 23550, "state" : "CA" }
+{ "_id" : "91356", "city" : "TARZANA", "loc" : [ -118.541354, 34.16708 ], "pop" : 25316, "state" : "CA" }
+{ "_id" : "91360", "city" : "THOUSAND OAKS", "loc" : [ -118.873908, 34.209179 ], "pop" : 41654, "state" : "CA" }
+{ "_id" : "91361", "city" : "WESTLAKE VILLAGE", "loc" : [ -118.83832, 34.147233 ], "pop" : 18608, "state" : "CA" }
+{ "_id" : "91362", "city" : "WESTLAKE VILLAGE", "loc" : [ -118.830601, 34.191884 ], "pop" : 26572, "state" : "CA" }
+{ "_id" : "91364", "city" : "WOODLAND HILLS", "loc" : [ -118.600019, 34.155652 ], "pop" : 25638, "state" : "CA" }
+{ "_id" : "91367", "city" : "WOODLAND HILLS", "loc" : [ -118.615891, 34.176689 ], "pop" : 34253, "state" : "CA" }
+{ "_id" : "91381", "city" : "NEWHALL", "loc" : [ -118.582134, 34.381067 ], "pop" : 1677, "state" : "CA" }
+{ "_id" : "91384", "city" : "CASTAIC", "loc" : [ -118.62537, 34.482695 ], "pop" : 19440, "state" : "CA" }
+{ "_id" : "91401", "city" : "VAN NUYS", "loc" : [ -118.432375, 34.180152 ], "pop" : 35990, "state" : "CA" }
+{ "_id" : "91402", "city" : "PANORAMA CITY", "loc" : [ -118.447009, 34.226158 ], "pop" : 52577, "state" : "CA" }
+{ "_id" : "91403", "city" : "SHERMAN OAKS", "loc" : [ -118.460325, 34.151407 ], "pop" : 20046, "state" : "CA" }
+{ "_id" : "91405", "city" : "VAN NUYS", "loc" : [ -118.445636, 34.200068 ], "pop" : 39669, "state" : "CA" }
+{ "_id" : "91406", "city" : "VAN NUYS", "loc" : [ -118.486821, 34.200568 ], "pop" : 46124, "state" : "CA" }
+{ "_id" : "91411", "city" : "VAN NUYS", "loc" : [ -118.457396, 34.178133 ], "pop" : 21616, "state" : "CA" }
+{ "_id" : "91423", "city" : "SHERMAN OAKS", "loc" : [ -118.432208, 34.152565 ], "pop" : 27747, "state" : "CA" }
+{ "_id" : "91436", "city" : "ENCINO", "loc" : [ -118.488238, 34.15098 ], "pop" : 13605, "state" : "CA" }
+{ "_id" : "91501", "city" : "BURBANK", "loc" : [ -118.300898, 34.186238 ], "pop" : 15991, "state" : "CA" }
+{ "_id" : "91502", "city" : "BURBANK", "loc" : [ -118.305912, 34.174487 ], "pop" : 9833, "state" : "CA" }
+{ "_id" : "91504", "city" : "BURBANK", "loc" : [ -118.326401, 34.200097 ], "pop" : 22656, "state" : "CA" }
+{ "_id" : "91505", "city" : "BURBANK", "loc" : [ -118.344175, 34.168998 ], "pop" : 27676, "state" : "CA" }
+{ "_id" : "91506", "city" : "BURBANK", "loc" : [ -118.323148, 34.171746 ], "pop" : 18336, "state" : "CA" }
+{ "_id" : "91601", "city" : "NORTH HOLLYWOOD", "loc" : [ -118.371274, 34.16867 ], "pop" : 33882, "state" : "CA" }
+{ "_id" : "91602", "city" : "TOLUCA LAKE", "loc" : [ -118.367606, 34.151095 ], "pop" : 14301, "state" : "CA" }
+{ "_id" : "91604", "city" : "STUDIO CITY", "loc" : [ -118.391311, 34.143025 ], "pop" : 24354, "state" : "CA" }
+{ "_id" : "91605", "city" : "NORTH HOLLYWOOD", "loc" : [ -118.400069, 34.205747 ], "pop" : 50050, "state" : "CA" }
+{ "_id" : "91606", "city" : "NORTH HOLLYWOOD", "loc" : [ -118.386538, 34.187182 ], "pop" : 39737, "state" : "CA" }
+{ "_id" : "91607", "city" : "VALLEY VILLAGE", "loc" : [ -118.398905, 34.167217 ], "pop" : 28021, "state" : "CA" }
+{ "_id" : "91701", "city" : "ALTA LOMA", "loc" : [ -117.599149, 34.133922 ], "pop" : 31633, "state" : "CA" }
+{ "_id" : "91702", "city" : "AZUSA", "loc" : [ -117.903083, 34.12476 ], "pop" : 52261, "state" : "CA" }
+{ "_id" : "91706", "city" : "IRWINDALE", "loc" : [ -117.969539, 34.084245 ], "pop" : 69464, "state" : "CA" }
+{ "_id" : "91709", "city" : "CHINO HILLS", "loc" : [ -117.730791, 33.979735 ], "pop" : 37965, "state" : "CA" }
+{ "_id" : "91710", "city" : "CHINO", "loc" : [ -117.684401, 34.012532 ], "pop" : 69244, "state" : "CA" }
+{ "_id" : "91711", "city" : "CLAREMONT", "loc" : [ -117.718293, 34.109167 ], "pop" : 34096, "state" : "CA" }
+{ "_id" : "91719", "city" : "CORONA", "loc" : [ -117.531916, 33.861839 ], "pop" : 42717, "state" : "CA" }
+{ "_id" : "91720", "city" : "CORONA", "loc" : [ -117.594288, 33.876995 ], "pop" : 55741, "state" : "CA" }
+{ "_id" : "91722", "city" : "COVINA", "loc" : [ -117.906544, 34.097162 ], "pop" : 31703, "state" : "CA" }
+{ "_id" : "91723", "city" : "COVINA", "loc" : [ -117.884285, 34.08596 ], "pop" : 15590, "state" : "CA" }
+{ "_id" : "91724", "city" : "COVINA", "loc" : [ -117.855982, 34.093752 ], "pop" : 23462, "state" : "CA" }
+{ "_id" : "91730", "city" : "RANCHO CUCAMONGA", "loc" : [ -117.59408, 34.107039 ], "pop" : 41087, "state" : "CA" }
+{ "_id" : "91731", "city" : "EL MONTE", "loc" : [ -118.037108, 34.079142 ], "pop" : 26178, "state" : "CA" }
+{ "_id" : "91732", "city" : "EL MONTE", "loc" : [ -118.01492, 34.070533 ], "pop" : 58059, "state" : "CA" }
+{ "_id" : "91733", "city" : "SOUTH EL MONTE", "loc" : [ -118.044381, 34.055676 ], "pop" : 43691, "state" : "CA" }
+{ "_id" : "91737", "city" : "ALTA LOMA", "loc" : [ -117.579295, 34.144883 ], "pop" : 19708, "state" : "CA" }
+{ "_id" : "91739", "city" : "ETIWANDA", "loc" : [ -117.519329, 34.119873 ], "pop" : 13553, "state" : "CA" }
+{ "_id" : "91740", "city" : "GLENDORA", "loc" : [ -117.855155, 34.128663 ], "pop" : 48836, "state" : "CA" }
+{ "_id" : "91744", "city" : "INDUSTRY", "loc" : [ -117.934098, 34.029428 ], "pop" : 77114, "state" : "CA" }
+{ "_id" : "91745", "city" : "HACIENDA HEIGHTS", "loc" : [ -117.965205, 33.997741 ], "pop" : 52182, "state" : "CA" }
+{ "_id" : "91746", "city" : "BASSETT", "loc" : [ -117.980026, 34.050963 ], "pop" : 30330, "state" : "CA" }
+{ "_id" : "91748", "city" : "ROWLAND HEIGHTS", "loc" : [ -117.896946, 33.981777 ], "pop" : 40511, "state" : "CA" }
+{ "_id" : "91750", "city" : "LA VERNE", "loc" : [ -117.77077, 34.115905 ], "pop" : 33621, "state" : "CA" }
+{ "_id" : "91752", "city" : "MIRA LOMA", "loc" : [ -117.523574, 33.993845 ], "pop" : 17368, "state" : "CA" }
+{ "_id" : "91754", "city" : "MONTEREY PARK", "loc" : [ -118.127144, 34.053409 ], "pop" : 62133, "state" : "CA" }
+{ "_id" : "91759", "city" : "MT BALDY", "loc" : [ -117.580219, 34.218082 ], "pop" : 430, "state" : "CA" }
+{ "_id" : "91760", "city" : "NORCO", "loc" : [ -117.557866, 33.927983 ], "pop" : 23585, "state" : "CA" }
+{ "_id" : "91761", "city" : "ONTARIO", "loc" : [ -117.618662, 34.031647 ], "pop" : 47921, "state" : "CA" }
+{ "_id" : "91762", "city" : "ONTARIO", "loc" : [ -117.66647, 34.058415 ], "pop" : 47653, "state" : "CA" }
+{ "_id" : "91763", "city" : "MONTCLAIR", "loc" : [ -117.698669, 34.073298 ], "pop" : 25862, "state" : "CA" }
+{ "_id" : "91764", "city" : "ONTARIO", "loc" : [ -117.625402, 34.076308 ], "pop" : 41958, "state" : "CA" }
+{ "_id" : "91765", "city" : "DIAMOND BAR", "loc" : [ -117.809822, 34.006585 ], "pop" : 41920, "state" : "CA" }
+{ "_id" : "91766", "city" : "PHILLIPS RANCH", "loc" : [ -117.752086, 34.043268 ], "pop" : 64056, "state" : "CA" }
+{ "_id" : "91767", "city" : "POMONA", "loc" : [ -117.736171, 34.081187 ], "pop" : 41420, "state" : "CA" }
+{ "_id" : "91768", "city" : "POMONA", "loc" : [ -117.776312, 34.066168 ], "pop" : 31007, "state" : "CA" }
+{ "_id" : "91770", "city" : "ROSEMEAD", "loc" : [ -118.08529, 34.065767 ], "pop" : 59898, "state" : "CA" }
+{ "_id" : "91773", "city" : "SAN DIMAS", "loc" : [ -117.81694, 34.102263 ], "pop" : 32453, "state" : "CA" }
+{ "_id" : "91775", "city" : "SAN GABRIEL", "loc" : [ -118.085658, 34.115486 ], "pop" : 21426, "state" : "CA" }
+{ "_id" : "91776", "city" : "SAN GABRIEL", "loc" : [ -118.095471, 34.089027 ], "pop" : 34995, "state" : "CA" }
+{ "_id" : "91780", "city" : "TEMPLE CITY", "loc" : [ -118.053652, 34.101586 ], "pop" : 31297, "state" : "CA" }
+{ "_id" : "91786", "city" : "UPLAND", "loc" : [ -117.658336, 34.114432 ], "pop" : 66548, "state" : "CA" }
+{ "_id" : "91789", "city" : "DIAMOND BAR", "loc" : [ -117.857828, 34.016625 ], "pop" : 42206, "state" : "CA" }
+{ "_id" : "91790", "city" : "WEST COVINA", "loc" : [ -117.936643, 34.067336 ], "pop" : 38113, "state" : "CA" }
+{ "_id" : "91791", "city" : "WEST COVINA", "loc" : [ -117.897767, 34.065267 ], "pop" : 25685, "state" : "CA" }
+{ "_id" : "91792", "city" : "WEST COVINA", "loc" : [ -117.897459, 34.022852 ], "pop" : 30496, "state" : "CA" }
+{ "_id" : "91801", "city" : "ALHAMBRA", "loc" : [ -118.129288, 34.091436 ], "pop" : 51148, "state" : "CA" }
+{ "_id" : "91803", "city" : "ALHAMBRA", "loc" : [ -118.143354, 34.074514 ], "pop" : 30228, "state" : "CA" }
+{ "_id" : "91901", "city" : "ALPINE", "loc" : [ -116.754328, 32.828161 ], "pop" : 12566, "state" : "CA" }
+{ "_id" : "91902", "city" : "BONITA", "loc" : [ -117.022065, 32.667143 ], "pop" : 16579, "state" : "CA" }
+{ "_id" : "91905", "city" : "BOULEVARD", "loc" : [ -116.319982, 32.671934 ], "pop" : 1163, "state" : "CA" }
+{ "_id" : "91906", "city" : "CAMPO", "loc" : [ -116.490459, 32.660491 ], "pop" : 2657, "state" : "CA" }
+{ "_id" : "91910", "city" : "CHULA VISTA", "loc" : [ -117.06756, 32.637139 ], "pop" : 56320, "state" : "CA" }
+{ "_id" : "91911", "city" : "CHULA VISTA", "loc" : [ -117.056459, 32.608428 ], "pop" : 65952, "state" : "CA" }
+{ "_id" : "91913", "city" : "CHULA VISTA", "loc" : [ -116.985237, 32.651296 ], "pop" : 10079, "state" : "CA" }
+{ "_id" : "91914", "city" : "CHULA VISTA", "loc" : [ -116.96517, 32.65875 ], "pop" : 0, "state" : "CA" }
+{ "_id" : "91915", "city" : "CHULA VISTA", "loc" : [ -116.940807, 32.631513 ], "pop" : 12, "state" : "CA" }
+{ "_id" : "91916", "city" : "DESCANSO", "loc" : [ -116.602732, 32.872971 ], "pop" : 1826, "state" : "CA" }
+{ "_id" : "91917", "city" : "DULZURA", "loc" : [ -116.728523, 32.615172 ], "pop" : 352, "state" : "CA" }
+{ "_id" : "91932", "city" : "IMPERIAL BEACH", "loc" : [ -117.11478, 32.578289 ], "pop" : 26567, "state" : "CA" }
+{ "_id" : "91934", "city" : "JACUMBA", "loc" : [ -116.195184, 32.624934 ], "pop" : 599, "state" : "CA" }
+{ "_id" : "91935", "city" : "JAMUL", "loc" : [ -116.832332, 32.716289 ], "pop" : 7879, "state" : "CA" }
+{ "_id" : "91941", "city" : "LA MESA", "loc" : [ -117.011541, 32.760431 ], "pop" : 42536, "state" : "CA" }
+{ "_id" : "91942", "city" : "LA MESA", "loc" : [ -117.018879, 32.783506 ], "pop" : 23944, "state" : "CA" }
+{ "_id" : "91945", "city" : "LEMON GROVE", "loc" : [ -117.032646, 32.73323 ], "pop" : 24268, "state" : "CA" }
+{ "_id" : "91950", "city" : "NATIONAL CITY", "loc" : [ -117.089747, 32.674916 ], "pop" : 52005, "state" : "CA" }
+{ "_id" : "91962", "city" : "PINE VALLEY", "loc" : [ -116.512733, 32.835047 ], "pop" : 1801, "state" : "CA" }
+{ "_id" : "91963", "city" : "POTRERO", "loc" : [ -116.603748, 32.620477 ], "pop" : 638, "state" : "CA" }
+{ "_id" : "91977", "city" : "SPRING VALLEY", "loc" : [ -116.997644, 32.724014 ], "pop" : 52403, "state" : "CA" }
+{ "_id" : "91978", "city" : "SPRING VALLEY", "loc" : [ -116.959551, 32.732892 ], "pop" : 7601, "state" : "CA" }
+{ "_id" : "91980", "city" : "TECATE", "loc" : [ -116.606397, 32.592205 ], "pop" : 230, "state" : "CA" }
+{ "_id" : "92003", "city" : "BONSALL", "loc" : [ -117.18969, 33.294033 ], "pop" : 2910, "state" : "CA" }
+{ "_id" : "92004", "city" : "BORREGO SPRINGS", "loc" : [ -116.351394, 33.238649 ], "pop" : 2633, "state" : "CA" }
+{ "_id" : "92007", "city" : "CARDIFF BY THE S", "loc" : [ -117.274371, 33.025265 ], "pop" : 10236, "state" : "CA" }
+{ "_id" : "92008", "city" : "CARLSBAD", "loc" : [ -117.324998, 33.160241 ], "pop" : 35651, "state" : "CA" }
+{ "_id" : "92009", "city" : "CARLSBAD", "loc" : [ -117.261888, 33.095407 ], "pop" : 27019, "state" : "CA" }
+{ "_id" : "92014", "city" : "DEL MAR", "loc" : [ -117.237314, 32.971474 ], "pop" : 19885, "state" : "CA" }
+{ "_id" : "92019", "city" : "EL CAJON", "loc" : [ -116.919055, 32.777726 ], "pop" : 35425, "state" : "CA" }
+{ "_id" : "92020", "city" : "EL CAJON", "loc" : [ -116.966504, 32.792765 ], "pop" : 55176, "state" : "CA" }
+{ "_id" : "92021", "city" : "EL CAJON", "loc" : [ -116.922336, 32.817847 ], "pop" : 51773, "state" : "CA" }
+{ "_id" : "92024", "city" : "ENCINITAS", "loc" : [ -117.26891, 33.053469 ], "pop" : 45995, "state" : "CA" }
+{ "_id" : "92025", "city" : "ESCONDIDO", "loc" : [ -117.069987, 33.110117 ], "pop" : 39345, "state" : "CA" }
+{ "_id" : "92026", "city" : "ESCONDIDO", "loc" : [ -117.097808, 33.160513 ], "pop" : 37176, "state" : "CA" }
+{ "_id" : "92027", "city" : "ESCONDIDO", "loc" : [ -117.051966, 33.138824 ], "pop" : 39305, "state" : "CA" }
+{ "_id" : "92028", "city" : "FALLBROOK", "loc" : [ -117.228952, 33.369015 ], "pop" : 35232, "state" : "CA" }
+{ "_id" : "92029", "city" : "ESCONDIDO", "loc" : [ -117.112793, 33.089497 ], "pop" : 18174, "state" : "CA" }
+{ "_id" : "92036", "city" : "JULIAN", "loc" : [ -116.565812, 33.053355 ], "pop" : 2552, "state" : "CA" }
+{ "_id" : "92037", "city" : "LA JOLLA", "loc" : [ -117.25208, 32.845488 ], "pop" : 40399, "state" : "CA" }
+{ "_id" : "92040", "city" : "LAKESIDE", "loc" : [ -116.920089, 32.856181 ], "pop" : 41054, "state" : "CA" }
+{ "_id" : "92054", "city" : "OCEANSIDE", "loc" : [ -117.357294, 33.20723 ], "pop" : 61760, "state" : "CA" }
+{ "_id" : "92055", "city" : "MARINE CORP BASE", "loc" : [ -117.409452, 33.327929 ], "pop" : 13643, "state" : "CA" }
+{ "_id" : "92056", "city" : "OCEANSIDE", "loc" : [ -117.283089, 33.196784 ], "pop" : 40161, "state" : "CA" }
+{ "_id" : "92057", "city" : "OCEANSIDE", "loc" : [ -117.302484, 33.240654 ], "pop" : 33178, "state" : "CA" }
+{ "_id" : "92059", "city" : "PALA", "loc" : [ -117.071725, 33.377662 ], "pop" : 1064, "state" : "CA" }
+{ "_id" : "92061", "city" : "PAUMA VALLEY", "loc" : [ -116.959552, 33.306285 ], "pop" : 1929, "state" : "CA" }
+{ "_id" : "92064", "city" : "POWAY", "loc" : [ -117.040223, 32.975619 ], "pop" : 43490, "state" : "CA" }
+{ "_id" : "92065", "city" : "RAMONA", "loc" : [ -116.853548, 33.029349 ], "pop" : 27744, "state" : "CA" }
+{ "_id" : "92066", "city" : "RANCHITA", "loc" : [ -116.539121, 33.24055 ], "pop" : 389, "state" : "CA" }
+{ "_id" : "92068", "city" : "SAN LUIS REY", "loc" : [ -117.306403, 33.294367 ], "pop" : 9471, "state" : "CA" }
+{ "_id" : "92069", "city" : "SAN MARCOS", "loc" : [ -117.169716, 33.144386 ], "pop" : 45382, "state" : "CA" }
+{ "_id" : "92070", "city" : "SANTA YSABEL", "loc" : [ -116.69635, 33.147579 ], "pop" : 1263, "state" : "CA" }
+{ "_id" : "92071", "city" : "SANTEE", "loc" : [ -116.986154, 32.848636 ], "pop" : 52816, "state" : "CA" }
+{ "_id" : "92075", "city" : "SOLANA BEACH", "loc" : [ -117.2598, 32.993739 ], "pop" : 12259, "state" : "CA" }
+{ "_id" : "92082", "city" : "VALLEY CENTER", "loc" : [ -117.012232, 33.249046 ], "pop" : 13196, "state" : "CA" }
+{ "_id" : "92083", "city" : "VISTA", "loc" : [ -117.245854, 33.187296 ], "pop" : 50641, "state" : "CA" }
+{ "_id" : "92084", "city" : "VISTA", "loc" : [ -117.224285, 33.213118 ], "pop" : 38088, "state" : "CA" }
+{ "_id" : "92086", "city" : "WARNER SPRINGS", "loc" : [ -116.721385, 33.303666 ], "pop" : 780, "state" : "CA" }
+{ "_id" : "92101", "city" : "SAN DIEGO", "loc" : [ -117.159316, 32.71852 ], "pop" : 20265, "state" : "CA" }
+{ "_id" : "92102", "city" : "SAN DIEGO", "loc" : [ -117.121858, 32.713893 ], "pop" : 45265, "state" : "CA" }
+{ "_id" : "92103", "city" : "SAN DIEGO", "loc" : [ -117.163552, 32.746638 ], "pop" : 31123, "state" : "CA" }
+{ "_id" : "92104", "city" : "SAN DIEGO", "loc" : [ -117.127189, 32.745425 ], "pop" : 44032, "state" : "CA" }
+{ "_id" : "92105", "city" : "SAN DIEGO", "loc" : [ -117.094681, 32.7423 ], "pop" : 63344, "state" : "CA" }
+{ "_id" : "92106", "city" : "SAN DIEGO", "loc" : [ -117.226829, 32.72725 ], "pop" : 27640, "state" : "CA" }
+{ "_id" : "92107", "city" : "SAN DIEGO", "loc" : [ -117.243307, 32.742531 ], "pop" : 25913, "state" : "CA" }
+{ "_id" : "92108", "city" : "SAN DIEGO", "loc" : [ -117.133525, 32.778327 ], "pop" : 8860, "state" : "CA" }
+{ "_id" : "92109", "city" : "SAN DIEGO", "loc" : [ -117.240534, 32.796923 ], "pop" : 44804, "state" : "CA" }
+{ "_id" : "92110", "city" : "SAN DIEGO", "loc" : [ -117.202847, 32.763476 ], "pop" : 26787, "state" : "CA" }
+{ "_id" : "92111", "city" : "SAN DIEGO", "loc" : [ -117.17081, 32.797185 ], "pop" : 45487, "state" : "CA" }
+{ "_id" : "92113", "city" : "SAN DIEGO", "loc" : [ -117.115257, 32.697047 ], "pop" : 44741, "state" : "CA" }
+{ "_id" : "92114", "city" : "SAN DIEGO", "loc" : [ -117.05235, 32.705923 ], "pop" : 62258, "state" : "CA" }
+{ "_id" : "92115", "city" : "SAN DIEGO", "loc" : [ -117.072056, 32.760742 ], "pop" : 51418, "state" : "CA" }
+{ "_id" : "92116", "city" : "SAN DIEGO", "loc" : [ -117.124166, 32.762446 ], "pop" : 32279, "state" : "CA" }
+{ "_id" : "92117", "city" : "SAN DIEGO", "loc" : [ -117.196536, 32.823948 ], "pop" : 49737, "state" : "CA" }
+{ "_id" : "92118", "city" : "CORONADO", "loc" : [ -117.169823, 32.68069 ], "pop" : 16670, "state" : "CA" }
+{ "_id" : "92119", "city" : "SAN DIEGO", "loc" : [ -117.026065, 32.803587 ], "pop" : 24135, "state" : "CA" }
+{ "_id" : "92120", "city" : "SAN DIEGO", "loc" : [ -117.070708, 32.79581 ], "pop" : 25375, "state" : "CA" }
+{ "_id" : "92121", "city" : "SAN DIEGO", "loc" : [ -117.203503, 32.891894 ], "pop" : 2286, "state" : "CA" }
+{ "_id" : "92122", "city" : "SAN DIEGO", "loc" : [ -117.211507, 32.857736 ], "pop" : 30192, "state" : "CA" }
+{ "_id" : "92123", "city" : "SAN DIEGO", "loc" : [ -117.139248, 32.797297 ], "pop" : 23541, "state" : "CA" }
+{ "_id" : "92124", "city" : "SAN DIEGO", "loc" : [ -117.098613, 32.820113 ], "pop" : 29171, "state" : "CA" }
+{ "_id" : "92126", "city" : "SAN DIEGO", "loc" : [ -117.140227, 32.916136 ], "pop" : 56676, "state" : "CA" }
+{ "_id" : "92127", "city" : "SAN DIEGO", "loc" : [ -117.085596, 33.027854 ], "pop" : 11077, "state" : "CA" }
+{ "_id" : "92128", "city" : "SAN DIEGO", "loc" : [ -117.068982, 33.00666 ], "pop" : 30437, "state" : "CA" }
+{ "_id" : "92129", "city" : "SAN DIEGO", "loc" : [ -117.121308, 32.965185 ], "pop" : 43092, "state" : "CA" }
+{ "_id" : "92130", "city" : "SAN DIEGO", "loc" : [ -117.225201, 32.955533 ], "pop" : 12681, "state" : "CA" }
+{ "_id" : "92131", "city" : "SAN DIEGO", "loc" : [ -117.089758, 32.912343 ], "pop" : 16649, "state" : "CA" }
+{ "_id" : "92135", "city" : "SAN DIEGO", "loc" : [ -117.19202, 32.702482 ], "pop" : 8122, "state" : "CA" }
+{ "_id" : "92136", "city" : "SAN DIEGO", "loc" : [ -117.124678, 32.681585 ], "pop" : 11750, "state" : "CA" }
+{ "_id" : "92139", "city" : "SAN DIEGO", "loc" : [ -117.047375, 32.680612 ], "pop" : 35577, "state" : "CA" }
+{ "_id" : "92145", "city" : "SAN DIEGO", "loc" : [ -117.116518, 32.870365 ], "pop" : 3089, "state" : "CA" }
+{ "_id" : "92154", "city" : "SAN DIEGO", "loc" : [ -117.070725, 32.575276 ], "pop" : 59925, "state" : "CA" }
+{ "_id" : "92155", "city" : "SAN DIEGO", "loc" : [ -117.160335, 32.676144 ], "pop" : 1570, "state" : "CA" }
+{ "_id" : "92173", "city" : "SAN YSIDRO", "loc" : [ -117.042976, 32.562567 ], "pop" : 30131, "state" : "CA" }
+{ "_id" : "92201", "city" : "CHIRIACO SUMMIT", "loc" : [ -116.235729, 33.721899 ], "pop" : 47118, "state" : "CA" }
+{ "_id" : "92210", "city" : "INDIAN WELLS", "loc" : [ -116.338129, 33.716334 ], "pop" : 2599, "state" : "CA" }
+{ "_id" : "92220", "city" : "BANNING", "loc" : [ -116.889928, 33.92816 ], "pop" : 22545, "state" : "CA" }
+{ "_id" : "92223", "city" : "BEAUMONT", "loc" : [ -116.970079, 33.950429 ], "pop" : 16176, "state" : "CA" }
+{ "_id" : "92225", "city" : "LOST LAKE", "loc" : [ -114.597131, 33.605715 ], "pop" : 13852, "state" : "CA" }
+{ "_id" : "92227", "city" : "BRAWLEY", "loc" : [ -115.529613, 32.979181 ], "pop" : 20199, "state" : "CA" }
+{ "_id" : "92230", "city" : "CABAZON", "loc" : [ -116.773948, 33.908583 ], "pop" : 1697, "state" : "CA" }
+{ "_id" : "92231", "city" : "CALEXICO", "loc" : [ -115.502815, 32.683227 ], "pop" : 22345, "state" : "CA" }
+{ "_id" : "92233", "city" : "CALIPATRIA", "loc" : [ -115.511402, 33.166956 ], "pop" : 4847, "state" : "CA" }
+{ "_id" : "92234", "city" : "CATHEDRAL CITY", "loc" : [ -116.466497, 33.809839 ], "pop" : 29640, "state" : "CA" }
+{ "_id" : "92236", "city" : "COACHELLA", "loc" : [ -116.177231, 33.674965 ], "pop" : 17147, "state" : "CA" }
+{ "_id" : "92239", "city" : "EAGLE MOUNTAIN", "loc" : [ -115.052603, 33.604941 ], "pop" : 4499, "state" : "CA" }
+{ "_id" : "92240", "city" : "DESERT HOT SPRIN", "loc" : [ -116.366222, 33.904973 ], "pop" : 686, "state" : "CA" }
+{ "_id" : "92242", "city" : "BIG RIVER", "loc" : [ -114.33928, 34.149142 ], "pop" : 976, "state" : "CA" }
+{ "_id" : "92243", "city" : "EL CENTRO", "loc" : [ -115.566508, 32.789332 ], "pop" : 39246, "state" : "CA" }
+{ "_id" : "92249", "city" : "HEBER", "loc" : [ -115.428281, 32.698918 ], "pop" : 206, "state" : "CA" }
+{ "_id" : "92250", "city" : "HOLTVILLE", "loc" : [ -115.377456, 32.810387 ], "pop" : 7060, "state" : "CA" }
+{ "_id" : "92251", "city" : "IMPERIAL", "loc" : [ -115.572984, 32.846954 ], "pop" : 6092, "state" : "CA" }
+{ "_id" : "92252", "city" : "JOSHUA TREE", "loc" : [ -116.303763, 34.150163 ], "pop" : 8227, "state" : "CA" }
+{ "_id" : "92253", "city" : "LA QUINTA", "loc" : [ -116.308081, 33.668474 ], "pop" : 9392, "state" : "CA" }
+{ "_id" : "92256", "city" : "MORONGO VALLEY", "loc" : [ -116.565641, 34.060646 ], "pop" : 2721, "state" : "CA" }
+{ "_id" : "92257", "city" : "NILAND", "loc" : [ -115.696455, 33.378373 ], "pop" : 875, "state" : "CA" }
+{ "_id" : "92260", "city" : "PALM CITY", "loc" : [ -116.366442, 33.730842 ], "pop" : 31975, "state" : "CA" }
+{ "_id" : "92262", "city" : "PALM SPRINGS", "loc" : [ -116.53466, 33.841406 ], "pop" : 22808, "state" : "CA" }
+{ "_id" : "92264", "city" : "PALM SPRINGS", "loc" : [ -116.516958, 33.801828 ], "pop" : 18733, "state" : "CA" }
+{ "_id" : "92267", "city" : "PARKER DAM", "loc" : [ -114.155969, 34.297977 ], "pop" : 141, "state" : "CA" }
+{ "_id" : "92270", "city" : "RANCHO MIRAGE", "loc" : [ -116.422451, 33.764284 ], "pop" : 9737, "state" : "CA" }
+{ "_id" : "92272", "city" : "BLYTHE", "loc" : [ -116.495855, 33.951256 ], "pop" : 18605, "state" : "CA" }
+{ "_id" : "92274", "city" : "SALTON CITY", "loc" : [ -116.11584, 33.543418 ], "pop" : 19112, "state" : "CA" }
+{ "_id" : "92276", "city" : "THOUSAND PALMS", "loc" : [ -116.371305, 33.808158 ], "pop" : 5557, "state" : "CA" }
+{ "_id" : "92277", "city" : "TWENTYNINE PALMS", "loc" : [ -116.060133, 34.145509 ], "pop" : 13371, "state" : "CA" }
+{ "_id" : "92278", "city" : "TWENTYNINE PALMS", "loc" : [ -116.06041, 34.237969 ], "pop" : 11412, "state" : "CA" }
+{ "_id" : "92280", "city" : "VIDAL", "loc" : [ -114.565602, 34.156109 ], "pop" : 40, "state" : "CA" }
+{ "_id" : "92281", "city" : "WESTMORLAND", "loc" : [ -115.630723, 33.041058 ], "pop" : 1902, "state" : "CA" }
+{ "_id" : "92282", "city" : "WHITE WATER", "loc" : [ -116.693154, 33.927591 ], "pop" : 420, "state" : "CA" }
+{ "_id" : "92283", "city" : "FELICITY", "loc" : [ -114.636634, 32.832922 ], "pop" : 3867, "state" : "CA" }
+{ "_id" : "92284", "city" : "YUCCA VALLEY", "loc" : [ -116.431313, 34.155936 ], "pop" : 22131, "state" : "CA" }
+{ "_id" : "92301", "city" : "ADELANTO", "loc" : [ -117.424189, 34.584128 ], "pop" : 7176, "state" : "CA" }
+{ "_id" : "92304", "city" : "AMBOY", "loc" : [ -115.774907, 34.599012 ], "pop" : 29, "state" : "CA" }
+{ "_id" : "92305", "city" : "ANGELUS OAKS", "loc" : [ -116.948482, 34.153149 ], "pop" : 238, "state" : "CA" }
+{ "_id" : "92307", "city" : "APPLE VALLEY", "loc" : [ -117.2132, 34.529081 ], "pop" : 26066, "state" : "CA" }
+{ "_id" : "92308", "city" : "APPLE VALLEY", "loc" : [ -117.192684, 34.469814 ], "pop" : 24973, "state" : "CA" }
+{ "_id" : "92309", "city" : "BAKER", "loc" : [ -116.063754, 35.360573 ], "pop" : 606, "state" : "CA" }
+{ "_id" : "92310", "city" : "FORT IRWIN", "loc" : [ -116.644759, 35.40148 ], "pop" : 6735, "state" : "CA" }
+{ "_id" : "92311", "city" : "BARSTOW", "loc" : [ -117.038702, 34.89145 ], "pop" : 33076, "state" : "CA" }
+{ "_id" : "92314", "city" : "BIG BEAR CITY", "loc" : [ -116.920412, 34.242233 ], "pop" : 18959, "state" : "CA" }
+{ "_id" : "92316", "city" : "BLOOMINGTON", "loc" : [ -117.399295, 34.066198 ], "pop" : 22916, "state" : "CA" }
+{ "_id" : "92320", "city" : "CALIMESA", "loc" : [ -117.04304, 33.994586 ], "pop" : 6345, "state" : "CA" }
+{ "_id" : "92324", "city" : "GRAND TERRACE", "loc" : [ -117.318577, 34.057964 ], "pop" : 53822, "state" : "CA" }
+{ "_id" : "92327", "city" : "DAGGETT", "loc" : [ -116.887555, 34.86677 ], "pop" : 701, "state" : "CA" }
+{ "_id" : "92328", "city" : "DEATH VALLEY", "loc" : [ -116.893682, 36.467165 ], "pop" : 440, "state" : "CA" }
+{ "_id" : "92332", "city" : "ESSEX", "loc" : [ -115.280344, 34.560626 ], "pop" : 214, "state" : "CA" }
+{ "_id" : "92335", "city" : "FONTANA", "loc" : [ -117.455114, 34.079351 ], "pop" : 81255, "state" : "CA" }
+{ "_id" : "92336", "city" : "FONTANA", "loc" : [ -117.437759, 34.117276 ], "pop" : 27957, "state" : "CA" }
+{ "_id" : "92338", "city" : "LUDLOW", "loc" : [ -116.386202, 34.901779 ], "pop" : 383, "state" : "CA" }
+{ "_id" : "92339", "city" : "FOREST FALLS", "loc" : [ -116.914147, 34.08805 ], "pop" : 842, "state" : "CA" }
+{ "_id" : "92342", "city" : "HELENDALE", "loc" : [ -117.33666, 34.749859 ], "pop" : 3612, "state" : "CA" }
+{ "_id" : "92345", "city" : "HESPERIA", "loc" : [ -117.302527, 34.422215 ], "pop" : 52170, "state" : "CA" }
+{ "_id" : "92346", "city" : "EAST HIGHLAND", "loc" : [ -117.208717, 34.126969 ], "pop" : 37484, "state" : "CA" }
+{ "_id" : "92347", "city" : "HINKLEY", "loc" : [ -117.180867, 34.92788 ], "pop" : 1905, "state" : "CA" }
+{ "_id" : "92351", "city" : "KELSO", "loc" : [ -115.577574, 34.9678 ], "pop" : 30, "state" : "CA" }
+{ "_id" : "92354", "city" : "LOMA LINDA", "loc" : [ -117.251286, 34.052833 ], "pop" : 17855, "state" : "CA" }
+{ "_id" : "92356", "city" : "LUCERNE VALLEY", "loc" : [ -116.918857, 34.44695 ], "pop" : 4353, "state" : "CA" }
+{ "_id" : "92358", "city" : "LYTLE CREEK", "loc" : [ -117.518613, 34.255755 ], "pop" : 625, "state" : "CA" }
+{ "_id" : "92359", "city" : "MENTONE", "loc" : [ -117.112581, 34.077372 ], "pop" : 5832, "state" : "CA" }
+{ "_id" : "92363", "city" : "NEEDLES", "loc" : [ -114.587134, 34.782369 ], "pop" : 6316, "state" : "CA" }
+{ "_id" : "92364", "city" : "NIPTON", "loc" : [ -115.481436, 35.46761 ], "pop" : 390, "state" : "CA" }
+{ "_id" : "92365", "city" : "NEWBERRY SPRINGS", "loc" : [ -116.746373, 34.885001 ], "pop" : 4296, "state" : "CA" }
+{ "_id" : "92368", "city" : "ORO GRANDE", "loc" : [ -117.332733, 34.617832 ], "pop" : 852, "state" : "CA" }
+{ "_id" : "92371", "city" : "PHELAN", "loc" : [ -117.519604, 34.444901 ], "pop" : 13508, "state" : "CA" }
+{ "_id" : "92372", "city" : "PINON HILLS", "loc" : [ -117.640262, 34.442937 ], "pop" : 1741, "state" : "CA" }
+{ "_id" : "92373", "city" : "REDLANDS", "loc" : [ -117.180352, 34.039659 ], "pop" : 29784, "state" : "CA" }
+{ "_id" : "92374", "city" : "REDLANDS", "loc" : [ -117.167182, 34.064989 ], "pop" : 36952, "state" : "CA" }
+{ "_id" : "92376", "city" : "RIALTO", "loc" : [ -117.377133, 34.113155 ], "pop" : 75341, "state" : "CA" }
+{ "_id" : "92384", "city" : "SHOSHONE", "loc" : [ -116.264476, 35.899239 ], "pop" : 353, "state" : "CA" }
+{ "_id" : "92389", "city" : "TECOPA", "loc" : [ -115.829824, 35.897925 ], "pop" : 48, "state" : "CA" }
+{ "_id" : "92392", "city" : "SPRING VALLEY LA", "loc" : [ -117.319235, 34.503917 ], "pop" : 51968, "state" : "CA" }
+{ "_id" : "92394", "city" : "GEORGE AFB", "loc" : [ -117.363516, 34.577325 ], "pop" : 6815, "state" : "CA" }
+{ "_id" : "92397", "city" : "WRIGHTWOOD", "loc" : [ -117.6249, 34.362839 ], "pop" : 4148, "state" : "CA" }
+{ "_id" : "92399", "city" : "YUCAIPA", "loc" : [ -117.048925, 34.028197 ], "pop" : 33298, "state" : "CA" }
+{ "_id" : "92401", "city" : "SAN BERNARDINO", "loc" : [ -117.289753, 34.110521 ], "pop" : 1193, "state" : "CA" }
+{ "_id" : "92404", "city" : "SAN BERNARDINO", "loc" : [ -117.260572, 34.142577 ], "pop" : 50792, "state" : "CA" }
+{ "_id" : "92405", "city" : "MUSCOY", "loc" : [ -117.310765, 34.144101 ], "pop" : 35583, "state" : "CA" }
+{ "_id" : "92407", "city" : "SAN BERNARDINO", "loc" : [ -117.293697, 34.20928 ], "pop" : 44927, "state" : "CA" }
+{ "_id" : "92408", "city" : "SAN BERNARDINO", "loc" : [ -117.271059, 34.083127 ], "pop" : 13378, "state" : "CA" }
+{ "_id" : "92409", "city" : "SAN BERNARDINO", "loc" : [ -117.241291, 34.103685 ], "pop" : 1746, "state" : "CA" }
+{ "_id" : "92410", "city" : "SAN BERNARDINO", "loc" : [ -117.296789, 34.107729 ], "pop" : 42522, "state" : "CA" }
+{ "_id" : "92411", "city" : "SAN BERNARDINO", "loc" : [ -117.317158, 34.121414 ], "pop" : 22994, "state" : "CA" }
+{ "_id" : "92501", "city" : "RIVERSIDE", "loc" : [ -117.369421, 33.9924 ], "pop" : 18478, "state" : "CA" }
+{ "_id" : "92503", "city" : "RIVERSIDE", "loc" : [ -117.458862, 33.920808 ], "pop" : 55552, "state" : "CA" }
+{ "_id" : "92504", "city" : "RIVERSIDE", "loc" : [ -117.411948, 33.931458 ], "pop" : 45308, "state" : "CA" }
+{ "_id" : "92505", "city" : "RIVERSIDE", "loc" : [ -117.486687, 33.922769 ], "pop" : 37420, "state" : "CA" }
+{ "_id" : "92506", "city" : "RIVERSIDE", "loc" : [ -117.375696, 33.945485 ], "pop" : 37294, "state" : "CA" }
+{ "_id" : "92507", "city" : "RIVERSIDE", "loc" : [ -117.338874, 33.976086 ], "pop" : 45844, "state" : "CA" }
+{ "_id" : "92508", "city" : "RIVERSIDE", "loc" : [ -117.304264, 33.889676 ], "pop" : 13582, "state" : "CA" }
+{ "_id" : "92509", "city" : "RUBIDOUX", "loc" : [ -117.444896, 33.997355 ], "pop" : 52456, "state" : "CA" }
+{ "_id" : "92530", "city" : "LAKE ELSINORE", "loc" : [ -117.348535, 33.659816 ], "pop" : 34619, "state" : "CA" }
+{ "_id" : "92532", "city" : "LAKE ELSINORE", "loc" : [ -117.271278, 33.651662 ], "pop" : 6796, "state" : "CA" }
+{ "_id" : "92536", "city" : "AGUANGA", "loc" : [ -116.799693, 33.447306 ], "pop" : 2309, "state" : "CA" }
+{ "_id" : "92539", "city" : "ANZA", "loc" : [ -116.71355, 33.568812 ], "pop" : 1860, "state" : "CA" }
+{ "_id" : "92543", "city" : "HEMET", "loc" : [ -116.972974, 33.741613 ], "pop" : 26985, "state" : "CA" }
+{ "_id" : "92544", "city" : "HEMET", "loc" : [ -116.924306, 33.738978 ], "pop" : 34483, "state" : "CA" }
+{ "_id" : "92545", "city" : "HEMET", "loc" : [ -117.015078, 33.739857 ], "pop" : 19513, "state" : "CA" }
+{ "_id" : "92548", "city" : "HOMELAND", "loc" : [ -117.111845, 33.74528 ], "pop" : 4290, "state" : "CA" }
+{ "_id" : "92549", "city" : "IDYLLWILD", "loc" : [ -116.710665, 33.730433 ], "pop" : 3975, "state" : "CA" }
+{ "_id" : "92553", "city" : "MORENO VALLEY", "loc" : [ -117.235066, 33.915719 ], "pop" : 71314, "state" : "CA" }
+{ "_id" : "92555", "city" : "MORENO VALLEY", "loc" : [ -117.185105, 33.937659 ], "pop" : 9784, "state" : "CA" }
+{ "_id" : "92557", "city" : "MORENO VALLEY", "loc" : [ -117.245682, 33.955257 ], "pop" : 37853, "state" : "CA" }
+{ "_id" : "92561", "city" : "MOUNTAIN CENTER", "loc" : [ -116.581954, 33.531667 ], "pop" : 1896, "state" : "CA" }
+{ "_id" : "92562", "city" : "MURRIETA", "loc" : [ -117.273838, 33.563071 ], "pop" : 1988, "state" : "CA" }
+{ "_id" : "92563", "city" : "MURRIETA", "loc" : [ -117.178298, 33.56903 ], "pop" : 22649, "state" : "CA" }
+{ "_id" : "92567", "city" : "LAKEVIEW", "loc" : [ -117.118704, 33.807712 ], "pop" : 6480, "state" : "CA" }
+{ "_id" : "92570", "city" : "MEAD VALLEY", "loc" : [ -117.280005, 33.797535 ], "pop" : 31870, "state" : "CA" }
+{ "_id" : "92571", "city" : "PERRIS", "loc" : [ -117.217968, 33.810979 ], "pop" : 12436, "state" : "CA" }
+{ "_id" : "92582", "city" : "SAN JACINTO", "loc" : [ -116.981911, 33.788281 ], "pop" : 3233, "state" : "CA" }
+{ "_id" : "92583", "city" : "GILMAN HOT SPRIN", "loc" : [ -116.955201, 33.78604 ], "pop" : 15506, "state" : "CA" }
+{ "_id" : "92584", "city" : "MENIFEE", "loc" : [ -117.1743, 33.664744 ], "pop" : 8347, "state" : "CA" }
+{ "_id" : "92585", "city" : "ROMOLAND", "loc" : [ -117.171899, 33.744518 ], "pop" : 5231, "state" : "CA" }
+{ "_id" : "92586", "city" : "SUN CITY", "loc" : [ -117.196942, 33.704373 ], "pop" : 15225, "state" : "CA" }
+{ "_id" : "92587", "city" : "CANYON LAKE", "loc" : [ -117.252653, 33.688756 ], "pop" : 12522, "state" : "CA" }
+{ "_id" : "92590", "city" : "TEMECULA", "loc" : [ -117.182437, 33.490269 ], "pop" : 2128, "state" : "CA" }
+{ "_id" : "92591", "city" : "TEMECULA", "loc" : [ -117.128571, 33.521687 ], "pop" : 13480, "state" : "CA" }
+{ "_id" : "92592", "city" : "TEMECULA", "loc" : [ -117.095774, 33.498314 ], "pop" : 15567, "state" : "CA" }
+{ "_id" : "92595", "city" : "WILDOMAR", "loc" : [ -117.263953, 33.602115 ], "pop" : 4758, "state" : "CA" }
+{ "_id" : "92596", "city" : "WINCHESTER", "loc" : [ -117.088518, 33.624269 ], "pop" : 1195, "state" : "CA" }
+{ "_id" : "92610", "city" : "FOOTHILL RANCH", "loc" : [ -117.664995, 33.666822 ], "pop" : 3294, "state" : "CA" }
+{ "_id" : "92621", "city" : "BREA", "loc" : [ -117.886742, 33.922897 ], "pop" : 45577, "state" : "CA" }
+{ "_id" : "92624", "city" : "CAPISTRANO BEACH", "loc" : [ -117.662657, 33.459115 ], "pop" : 7498, "state" : "CA" }
+{ "_id" : "92625", "city" : "CORONA DEL MAR", "loc" : [ -117.874331, 33.602066 ], "pop" : 5166, "state" : "CA" }
+{ "_id" : "92626", "city" : "COSTA MESA", "loc" : [ -117.909623, 33.677711 ], "pop" : 45411, "state" : "CA" }
+{ "_id" : "92627", "city" : "COSTA MESA", "loc" : [ -117.917667, 33.647793 ], "pop" : 52357, "state" : "CA" }
+{ "_id" : "92629", "city" : "MONARCH BAY", "loc" : [ -117.700483, 33.476964 ], "pop" : 25618, "state" : "CA" }
+{ "_id" : "92630", "city" : "LAKE FOREST", "loc" : [ -117.68819, 33.640015 ], "pop" : 51666, "state" : "CA" }
+{ "_id" : "92631", "city" : "FULLERTON", "loc" : [ -117.89157, 33.880519 ], "pop" : 28902, "state" : "CA" }
+{ "_id" : "92632", "city" : "FULLERTON", "loc" : [ -117.928376, 33.865848 ], "pop" : 21680, "state" : "CA" }
+{ "_id" : "92633", "city" : "FULLERTON", "loc" : [ -117.961043, 33.873913 ], "pop" : 42033, "state" : "CA" }
+{ "_id" : "92635", "city" : "FULLERTON", "loc" : [ -117.927801, 33.901181 ], "pop" : 10531, "state" : "CA" }
+{ "_id" : "92640", "city" : "GARDEN GROVE", "loc" : [ -117.92906, 33.785826 ], "pop" : 43908, "state" : "CA" }
+{ "_id" : "92641", "city" : "GARDEN GROVE", "loc" : [ -117.975526, 33.786651 ], "pop" : 29308, "state" : "CA" }
+{ "_id" : "92643", "city" : "GARDEN GROVE", "loc" : [ -117.930193, 33.762641 ], "pop" : 39473, "state" : "CA" }
+{ "_id" : "92644", "city" : "GARDEN GROVE", "loc" : [ -117.96935, 33.765532 ], "pop" : 20467, "state" : "CA" }
+{ "_id" : "92645", "city" : "GARDEN GROVE", "loc" : [ -118.02639, 33.78324 ], "pop" : 16398, "state" : "CA" }
+{ "_id" : "92646", "city" : "HUNTINGTON BEACH", "loc" : [ -117.967771, 33.668448 ], "pop" : 57915, "state" : "CA" }
+{ "_id" : "92647", "city" : "HUNTINGTON BEACH", "loc" : [ -118.003035, 33.721018 ], "pop" : 56565, "state" : "CA" }
+{ "_id" : "92648", "city" : "HUNTINGTON BEACH", "loc" : [ -117.999012, 33.674577 ], "pop" : 34997, "state" : "CA" }
+{ "_id" : "92649", "city" : "HUNTINGTON BEACH", "loc" : [ -118.045142, 33.719111 ], "pop" : 34065, "state" : "CA" }
+{ "_id" : "92651", "city" : "LAGUNA NIGUEL", "loc" : [ -117.772351, 33.542927 ], "pop" : 20315, "state" : "CA" }
+{ "_id" : "92653", "city" : "LAGUNA HILLS", "loc" : [ -117.70854, 33.60028 ], "pop" : 45283, "state" : "CA" }
+{ "_id" : "92655", "city" : "MIDWAY CITY", "loc" : [ -117.983539, 33.744794 ], "pop" : 6224, "state" : "CA" }
+{ "_id" : "92656", "city" : "ALISO VIEJO", "loc" : [ -117.708906, 33.572367 ], "pop" : 16455, "state" : "CA" }
+{ "_id" : "92657", "city" : "NEWPORT BEACH", "loc" : [ -117.855317, 33.596382 ], "pop" : 8254, "state" : "CA" }
+{ "_id" : "92660", "city" : "NEWPORT BEACH", "loc" : [ -117.8757, 33.630027 ], "pop" : 25390, "state" : "CA" }
+{ "_id" : "92661", "city" : "NEWPORT BEACH", "loc" : [ -117.906237, 33.604429 ], "pop" : 6123, "state" : "CA" }
+{ "_id" : "92662", "city" : "NEWPORT BEACH", "loc" : [ -117.891732, 33.606459 ], "pop" : 3472, "state" : "CA" }
+{ "_id" : "92663", "city" : "NEWPORT BEACH", "loc" : [ -117.92788, 33.623084 ], "pop" : 19826, "state" : "CA" }
+{ "_id" : "92665", "city" : "ORANGE", "loc" : [ -117.844903, 33.83096 ], "pop" : 16566, "state" : "CA" }
+{ "_id" : "92666", "city" : "ORANGE", "loc" : [ -117.845461, 33.785258 ], "pop" : 13811, "state" : "CA" }
+{ "_id" : "92667", "city" : "VILLA PARK", "loc" : [ -117.828421, 33.81036 ], "pop" : 40937, "state" : "CA" }
+{ "_id" : "92668", "city" : "ORANGE", "loc" : [ -117.87532, 33.786481 ], "pop" : 20139, "state" : "CA" }
+{ "_id" : "92669", "city" : "ORANGE", "loc" : [ -117.800285, 33.791672 ], "pop" : 31583, "state" : "CA" }
+{ "_id" : "92670", "city" : "PLACENTIA", "loc" : [ -117.859837, 33.880323 ], "pop" : 47174, "state" : "CA" }
+{ "_id" : "92672", "city" : "SAN CLEMENTE", "loc" : [ -117.610139, 33.430809 ], "pop" : 46719, "state" : "CA" }
+{ "_id" : "92675", "city" : "MISSION VIEJO", "loc" : [ -117.657409, 33.511714 ], "pop" : 28121, "state" : "CA" }
+{ "_id" : "92677", "city" : "LAGUNA NIGUEL", "loc" : [ -117.705154, 33.522871 ], "pop" : 40072, "state" : "CA" }
+{ "_id" : "92679", "city" : "COTO DE CAZA", "loc" : [ -117.577709, 33.634576 ], "pop" : 6067, "state" : "CA" }
+{ "_id" : "92680", "city" : "TUSTIN", "loc" : [ -117.819193, 33.73713 ], "pop" : 51150, "state" : "CA" }
+{ "_id" : "92683", "city" : "WESTMINSTER", "loc" : [ -117.991312, 33.752756 ], "pop" : 77965, "state" : "CA" }
+{ "_id" : "92686", "city" : "YORBA LINDA", "loc" : [ -117.799619, 33.888361 ], "pop" : 41141, "state" : "CA" }
+{ "_id" : "92687", "city" : "YORBA LINDA", "loc" : [ -117.731162, 33.88238 ], "pop" : 14429, "state" : "CA" }
+{ "_id" : "92688", "city" : "RANCHO SANTA MAR", "loc" : [ -117.588388, 33.651822 ], "pop" : 9489, "state" : "CA" }
+{ "_id" : "92691", "city" : "MISSION VIEJO", "loc" : [ -117.664119, 33.617155 ], "pop" : 48832, "state" : "CA" }
+{ "_id" : "92692", "city" : "MISSION VIEJO", "loc" : [ -117.64245, 33.610872 ], "pop" : 30777, "state" : "CA" }
+{ "_id" : "92701", "city" : "SANTA ANA", "loc" : [ -117.857665, 33.75016 ], "pop" : 63544, "state" : "CA" }
+{ "_id" : "92703", "city" : "SANTA ANA", "loc" : [ -117.899589, 33.746613 ], "pop" : 63104, "state" : "CA" }
+{ "_id" : "92704", "city" : "SANTA ANA", "loc" : [ -117.904683, 33.726513 ], "pop" : 77151, "state" : "CA" }
+{ "_id" : "92705", "city" : "COWAN HEIGHTS", "loc" : [ -117.768902, 33.74866 ], "pop" : 37045, "state" : "CA" }
+{ "_id" : "92706", "city" : "SANTA ANA", "loc" : [ -117.881791, 33.764434 ], "pop" : 30673, "state" : "CA" }
+{ "_id" : "92707", "city" : "SANTA ANA HEIGHT", "loc" : [ -117.870346, 33.715938 ], "pop" : 56450, "state" : "CA" }
+{ "_id" : "92708", "city" : "FOUNTAIN VALLEY", "loc" : [ -117.952318, 33.710762 ], "pop" : 54803, "state" : "CA" }
+{ "_id" : "92709", "city" : "EL TORO MARINE C", "loc" : [ -117.715018, 33.681287 ], "pop" : 8078, "state" : "CA" }
+{ "_id" : "92714", "city" : "IRVINE", "loc" : [ -117.798928, 33.68764 ], "pop" : 60654, "state" : "CA" }
+{ "_id" : "92715", "city" : "IRVINE", "loc" : [ -117.821251, 33.650884 ], "pop" : 30690, "state" : "CA" }
+{ "_id" : "92718", "city" : "IRVINE", "loc" : [ -117.711476, 33.658179 ], "pop" : 1, "state" : "CA" }
+{ "_id" : "92720", "city" : "IRVINE", "loc" : [ -117.765533, 33.707495 ], "pop" : 23474, "state" : "CA" }
+{ "_id" : "92801", "city" : "ANAHEIM", "loc" : [ -117.954035, 33.842679 ], "pop" : 47392, "state" : "CA" }
+{ "_id" : "92802", "city" : "ANAHEIM", "loc" : [ -117.92219, 33.806909 ], "pop" : 36262, "state" : "CA" }
+{ "_id" : "92804", "city" : "ANAHEIM", "loc" : [ -117.974985, 33.81908 ], "pop" : 63622, "state" : "CA" }
+{ "_id" : "92805", "city" : "ANAHEIM", "loc" : [ -117.906263, 33.835332 ], "pop" : 55489, "state" : "CA" }
+{ "_id" : "92806", "city" : "ANAHEIM", "loc" : [ -117.875928, 33.837344 ], "pop" : 27945, "state" : "CA" }
+{ "_id" : "92807", "city" : "ANAHEIM", "loc" : [ -117.787657, 33.851583 ], "pop" : 35411, "state" : "CA" }
+{ "_id" : "92808", "city" : "ANAHEIM", "loc" : [ -117.748445, 33.857569 ], "pop" : 6206, "state" : "CA" }
+{ "_id" : "93001", "city" : "SAN BUENAVENTURA", "loc" : [ -119.28882, 34.290531 ], "pop" : 31453, "state" : "CA" }
+{ "_id" : "93003", "city" : "SAN BUENAVENTURA", "loc" : [ -119.2214, 34.270568 ], "pop" : 44627, "state" : "CA" }
+{ "_id" : "93004", "city" : "SAN BUENAVENTURA", "loc" : [ -119.168727, 34.278091 ], "pop" : 23430, "state" : "CA" }
+{ "_id" : "93010", "city" : "CAMARILLO", "loc" : [ -119.046361, 34.231328 ], "pop" : 40173, "state" : "CA" }
+{ "_id" : "93012", "city" : "CAMARILLO", "loc" : [ -118.986648, 34.22179 ], "pop" : 23489, "state" : "CA" }
+{ "_id" : "93013", "city" : "CARPINTERIA", "loc" : [ -119.518257, 34.403589 ], "pop" : 16591, "state" : "CA" }
+{ "_id" : "93015", "city" : "BARDSDALE", "loc" : [ -118.904071, 34.402557 ], "pop" : 15311, "state" : "CA" }
+{ "_id" : "93021", "city" : "MOORPARK", "loc" : [ -118.877139, 34.278421 ], "pop" : 27011, "state" : "CA" }
+{ "_id" : "93022", "city" : "OAK VIEW", "loc" : [ -119.298168, 34.402021 ], "pop" : 5611, "state" : "CA" }
+{ "_id" : "93023", "city" : "OJAI", "loc" : [ -119.256477, 34.44512 ], "pop" : 22778, "state" : "CA" }
+{ "_id" : "93030", "city" : "OXNARD", "loc" : [ -119.174952, 34.214142 ], "pop" : 66240, "state" : "CA" }
+{ "_id" : "93033", "city" : "OXNARD", "loc" : [ -119.171732, 34.168505 ], "pop" : 66043, "state" : "CA" }
+{ "_id" : "93035", "city" : "OXNARD", "loc" : [ -119.215975, 34.182177 ], "pop" : 23778, "state" : "CA" }
+{ "_id" : "93041", "city" : "PORT HUENEME", "loc" : [ -119.197317, 34.162572 ], "pop" : 17337, "state" : "CA" }
+{ "_id" : "93042", "city" : "POINT MUGU NAWC", "loc" : [ -119.09931, 34.123432 ], "pop" : 1707, "state" : "CA" }
+{ "_id" : "93043", "city" : "PORT HUENEME CBC", "loc" : [ -119.206008, 34.16212 ], "pop" : 3389, "state" : "CA" }
+{ "_id" : "93060", "city" : "SANTA PAULA", "loc" : [ -119.071328, 34.354718 ], "pop" : 28319, "state" : "CA" }
+{ "_id" : "93063", "city" : "SANTA SUSANA", "loc" : [ -118.699229, 34.279202 ], "pop" : 47637, "state" : "CA" }
+{ "_id" : "93065", "city" : "SIMI VALLEY", "loc" : [ -118.765349, 34.265589 ], "pop" : 55528, "state" : "CA" }
+{ "_id" : "93066", "city" : "SOMIS", "loc" : [ -119.011537, 34.279753 ], "pop" : 3025, "state" : "CA" }
+{ "_id" : "93067", "city" : "SUMMERLAND", "loc" : [ -119.596016, 34.424541 ], "pop" : 1330, "state" : "CA" }
+{ "_id" : "93101", "city" : "SANTA BARBARA", "loc" : [ -119.70782, 34.419668 ], "pop" : 29235, "state" : "CA" }
+{ "_id" : "93103", "city" : "SANTA BARBARA", "loc" : [ -119.683275, 34.429065 ], "pop" : 18199, "state" : "CA" }
+{ "_id" : "93105", "city" : "SANTA BARBARA", "loc" : [ -119.728538, 34.436915 ], "pop" : 23284, "state" : "CA" }
+{ "_id" : "93108", "city" : "MONTECITO", "loc" : [ -119.64255, 34.434258 ], "pop" : 12923, "state" : "CA" }
+{ "_id" : "93109", "city" : "SANTA BARBARA", "loc" : [ -119.7194, 34.403848 ], "pop" : 11089, "state" : "CA" }
+{ "_id" : "93110", "city" : "SANTA BARBARA", "loc" : [ -119.764668, 34.441814 ], "pop" : 15352, "state" : "CA" }
+{ "_id" : "93111", "city" : "SANTA BARBARA", "loc" : [ -119.802509, 34.445262 ], "pop" : 17689, "state" : "CA" }
+{ "_id" : "93117", "city" : "GOLETA", "loc" : [ -119.861245, 34.429631 ], "pop" : 45988, "state" : "CA" }
+{ "_id" : "93202", "city" : "ARMONA", "loc" : [ -119.705279, 36.309459 ], "pop" : 752, "state" : "CA" }
+{ "_id" : "93203", "city" : "ARVIN", "loc" : [ -118.8336, 35.196629 ], "pop" : 10613, "state" : "CA" }
+{ "_id" : "93204", "city" : "AVENAL", "loc" : [ -120.122716, 35.987667 ], "pop" : 9882, "state" : "CA" }
+{ "_id" : "93205", "city" : "BODFISH", "loc" : [ -118.484656, 35.587046 ], "pop" : 1407, "state" : "CA" }
+{ "_id" : "93206", "city" : "BUTTONWILLOW", "loc" : [ -119.465926, 35.403268 ], "pop" : 1975, "state" : "CA" }
+{ "_id" : "93207", "city" : "CALIFORNIA HOT S", "loc" : [ -118.646317, 35.892422 ], "pop" : 436, "state" : "CA" }
+{ "_id" : "93210", "city" : "COALINGA", "loc" : [ -120.348928, 36.162435 ], "pop" : 9579, "state" : "CA" }
+{ "_id" : "93212", "city" : "CORCORAN", "loc" : [ -119.560665, 36.086455 ], "pop" : 16228, "state" : "CA" }
+{ "_id" : "93214", "city" : "CUYAMA", "loc" : [ -119.661339, 34.933694 ], "pop" : 808, "state" : "CA" }
+{ "_id" : "93215", "city" : "DELANO", "loc" : [ -119.24594, 35.771511 ], "pop" : 23803, "state" : "CA" }
+{ "_id" : "93217", "city" : "DI GIORGIO", "loc" : [ -118.846755, 35.247604 ], "pop" : 258, "state" : "CA" }
+{ "_id" : "93219", "city" : "EARLIMART", "loc" : [ -119.253406, 35.854195 ], "pop" : 11963, "state" : "CA" }
+{ "_id" : "93221", "city" : "EXETER", "loc" : [ -119.12928, 36.304055 ], "pop" : 11088, "state" : "CA" }
+{ "_id" : "93223", "city" : "FARMERSVILLE", "loc" : [ -119.205357, 36.300169 ], "pop" : 6432, "state" : "CA" }
+{ "_id" : "93224", "city" : "FELLOWS", "loc" : [ -119.564757, 35.202579 ], "pop" : 521, "state" : "CA" }
+{ "_id" : "93225", "city" : "FRAZIER PARK", "loc" : [ -119.035488, 34.826463 ], "pop" : 5257, "state" : "CA" }
+{ "_id" : "93226", "city" : "GLENNVILLE", "loc" : [ -118.71693, 35.737677 ], "pop" : 346, "state" : "CA" }
+{ "_id" : "93230", "city" : "HANFORD", "loc" : [ -119.649094, 36.331419 ], "pop" : 44686, "state" : "CA" }
+{ "_id" : "93234", "city" : "HURON", "loc" : [ -120.101964, 36.237144 ], "pop" : 7050, "state" : "CA" }
+{ "_id" : "93235", "city" : "IVANHOE", "loc" : [ -119.218884, 36.385622 ], "pop" : 3326, "state" : "CA" }
+{ "_id" : "93238", "city" : "KERNVILLE", "loc" : [ -118.404723, 35.755005 ], "pop" : 812, "state" : "CA" }
+{ "_id" : "93239", "city" : "KETTLEMAN CITY", "loc" : [ -119.964361, 36.021501 ], "pop" : 1762, "state" : "CA" }
+{ "_id" : "93240", "city" : "MOUNTAIN MESA", "loc" : [ -118.441256, 35.617889 ], "pop" : 6285, "state" : "CA" }
+{ "_id" : "93241", "city" : "LAMONT", "loc" : [ -118.912419, 35.257059 ], "pop" : 13471, "state" : "CA" }
+{ "_id" : "93242", "city" : "LATON", "loc" : [ -119.715565, 36.437834 ], "pop" : 2860, "state" : "CA" }
+{ "_id" : "93243", "city" : "GORMAN", "loc" : [ -118.879126, 34.828862 ], "pop" : 1103, "state" : "CA" }
+{ "_id" : "93244", "city" : "LEMONCOVE", "loc" : [ -119.004986, 36.396084 ], "pop" : 64, "state" : "CA" }
+{ "_id" : "93245", "city" : "LEMOORE NAVAL AI", "loc" : [ -119.831017, 36.309535 ], "pop" : 26170, "state" : "CA" }
+{ "_id" : "93247", "city" : "LINDSAY", "loc" : [ -119.088427, 36.209551 ], "pop" : 12983, "state" : "CA" }
+{ "_id" : "93249", "city" : "LOST HILLS", "loc" : [ -119.721573, 35.613111 ], "pop" : 2373, "state" : "CA" }
+{ "_id" : "93250", "city" : "MC FARLAND", "loc" : [ -119.227156, 35.675779 ], "pop" : 8494, "state" : "CA" }
+{ "_id" : "93251", "city" : "MC KITTRICK", "loc" : [ -119.636627, 35.303097 ], "pop" : 616, "state" : "CA" }
+{ "_id" : "93252", "city" : "MARICOPA", "loc" : [ -119.407661, 35.038353 ], "pop" : 1571, "state" : "CA" }
+{ "_id" : "93254", "city" : "NEW CUYAMA", "loc" : [ -119.823806, 34.996709 ], "pop" : 80, "state" : "CA" }
+{ "_id" : "93255", "city" : "ONYX", "loc" : [ -118.190227, 35.713584 ], "pop" : 380, "state" : "CA" }
+{ "_id" : "93256", "city" : "PIXLEY", "loc" : [ -119.256427, 35.955286 ], "pop" : 4768, "state" : "CA" }
+{ "_id" : "93257", "city" : "PORTERVILLE", "loc" : [ -119.031549, 36.068636 ], "pop" : 54599, "state" : "CA" }
+{ "_id" : "93260", "city" : "POSEY", "loc" : [ -118.664286, 35.813496 ], "pop" : 253, "state" : "CA" }
+{ "_id" : "93262", "city" : "GIANT FOREST", "loc" : [ -118.772271, 36.573878 ], "pop" : 132, "state" : "CA" }
+{ "_id" : "93263", "city" : "SHAFTER", "loc" : [ -119.280075, 35.496994 ], "pop" : 12270, "state" : "CA" }
+{ "_id" : "93265", "city" : "SPRINGVILLE", "loc" : [ -118.796059, 36.136314 ], "pop" : 3374, "state" : "CA" }
+{ "_id" : "93266", "city" : "STRATFORD", "loc" : [ -119.823564, 36.178976 ], "pop" : 1135, "state" : "CA" }
+{ "_id" : "93267", "city" : "STRATHMORE", "loc" : [ -119.079163, 36.147237 ], "pop" : 4774, "state" : "CA" }
+{ "_id" : "93268", "city" : "TAFT", "loc" : [ -119.455674, 35.148164 ], "pop" : 15046, "state" : "CA" }
+{ "_id" : "93270", "city" : "TERRA BELLA", "loc" : [ -119.031239, 35.95698 ], "pop" : 5066, "state" : "CA" }
+{ "_id" : "93271", "city" : "THREE RIVERS", "loc" : [ -118.88754, 36.437686 ], "pop" : 2245, "state" : "CA" }
+{ "_id" : "93272", "city" : "TIPTON", "loc" : [ -119.30781, 36.054567 ], "pop" : 2365, "state" : "CA" }
+{ "_id" : "93274", "city" : "TULARE", "loc" : [ -119.33802, 36.202155 ], "pop" : 45567, "state" : "CA" }
+{ "_id" : "93276", "city" : "TUPMAN", "loc" : [ -119.341994, 35.288547 ], "pop" : 280, "state" : "CA" }
+{ "_id" : "93277", "city" : "VISALIA", "loc" : [ -119.306471, 36.311379 ], "pop" : 51620, "state" : "CA" }
+{ "_id" : "93280", "city" : "POND", "loc" : [ -119.344728, 35.593375 ], "pop" : 13589, "state" : "CA" }
+{ "_id" : "93283", "city" : "WELDON", "loc" : [ -118.285856, 35.639076 ], "pop" : 2049, "state" : "CA" }
+{ "_id" : "93285", "city" : "WOFFORD HEIGHTS", "loc" : [ -118.455877, 35.724556 ], "pop" : 3480, "state" : "CA" }
+{ "_id" : "93286", "city" : "WOODLAKE", "loc" : [ -119.091764, 36.431334 ], "pop" : 8421, "state" : "CA" }
+{ "_id" : "93287", "city" : "WOODY", "loc" : [ -118.843872, 35.70681 ], "pop" : 72, "state" : "CA" }
+{ "_id" : "93291", "city" : "VISALIA", "loc" : [ -119.301029, 36.355108 ], "pop" : 46656, "state" : "CA" }
+{ "_id" : "93301", "city" : "BAKERSFIELD", "loc" : [ -119.017063, 35.386611 ], "pop" : 12822, "state" : "CA" }
+{ "_id" : "93304", "city" : "BAKERSFIELD", "loc" : [ -119.021793, 35.339581 ], "pop" : 41870, "state" : "CA" }
+{ "_id" : "93305", "city" : "COLLEGE HEIGHTS", "loc" : [ -118.982042, 35.387772 ], "pop" : 34046, "state" : "CA" }
+{ "_id" : "93306", "city" : "BAKERSFIELD", "loc" : [ -118.939104, 35.386697 ], "pop" : 46699, "state" : "CA" }
+{ "_id" : "93307", "city" : "BAKERSFIELD", "loc" : [ -118.983851, 35.327484 ], "pop" : 50585, "state" : "CA" }
+{ "_id" : "93308", "city" : "BAKERSFIELD", "loc" : [ -119.043319, 35.424395 ], "pop" : 39454, "state" : "CA" }
+{ "_id" : "93309", "city" : "BAKERSFIELD", "loc" : [ -119.062713, 35.33839 ], "pop" : 58179, "state" : "CA" }
+{ "_id" : "93311", "city" : "BAKERSFIELD", "loc" : [ -119.105647, 35.303891 ], "pop" : 10321, "state" : "CA" }
+{ "_id" : "93312", "city" : "GREENACRES", "loc" : [ -119.15014, 35.382082 ], "pop" : 15935, "state" : "CA" }
+{ "_id" : "93313", "city" : "BAKERSFIELD", "loc" : [ -119.050936, 35.297391 ], "pop" : 11417, "state" : "CA" }
+{ "_id" : "93401", "city" : "SAN LUIS OBISPO", "loc" : [ -120.650933, 35.263453 ], "pop" : 24638, "state" : "CA" }
+{ "_id" : "93402", "city" : "LOS OSOS", "loc" : [ -120.833261, 35.317203 ], "pop" : 14648, "state" : "CA" }
+{ "_id" : "93405", "city" : "SAN LUIS OBISPO", "loc" : [ -120.681724, 35.290058 ], "pop" : 31976, "state" : "CA" }
+{ "_id" : "93420", "city" : "HALCYON", "loc" : [ -120.57289, 35.11449 ], "pop" : 21992, "state" : "CA" }
+{ "_id" : "93422", "city" : "ATASCADERO", "loc" : [ -120.663838, 35.475439 ], "pop" : 27720, "state" : "CA" }
+{ "_id" : "93426", "city" : "BRADLEY", "loc" : [ -120.972793, 35.809255 ], "pop" : 862, "state" : "CA" }
+{ "_id" : "93427", "city" : "BUELLTON", "loc" : [ -120.192233, 34.62093 ], "pop" : 3883, "state" : "CA" }
+{ "_id" : "93428", "city" : "CAMBRIA", "loc" : [ -121.084029, 35.556568 ], "pop" : 5635, "state" : "CA" }
+{ "_id" : "93430", "city" : "CAYUCOS", "loc" : [ -120.890791, 35.444606 ], "pop" : 3384, "state" : "CA" }
+{ "_id" : "93431", "city" : "CHOLAME", "loc" : [ -120.194827, 35.543847 ], "pop" : 206, "state" : "CA" }
+{ "_id" : "93432", "city" : "CRESTON", "loc" : [ -120.554238, 35.491543 ], "pop" : 726, "state" : "CA" }
+{ "_id" : "93433", "city" : "GROVER BEACH", "loc" : [ -120.617348, 35.120969 ], "pop" : 11790, "state" : "CA" }
+{ "_id" : "93434", "city" : "GUADALUPE", "loc" : [ -120.570329, 34.959989 ], "pop" : 6064, "state" : "CA" }
+{ "_id" : "93436", "city" : "LOMPOC", "loc" : [ -120.450605, 34.658349 ], "pop" : 49960, "state" : "CA" }
+{ "_id" : "93437", "city" : "LOMPOC", "loc" : [ -120.517096, 34.753215 ], "pop" : 9846, "state" : "CA" }
+{ "_id" : "93442", "city" : "MORRO BAY", "loc" : [ -120.844745, 35.37953 ], "pop" : 10475, "state" : "CA" }
+{ "_id" : "93444", "city" : "NIPOMO", "loc" : [ -120.489413, 35.029806 ], "pop" : 11070, "state" : "CA" }
+{ "_id" : "93445", "city" : "OCEANO", "loc" : [ -120.608044, 35.10187 ], "pop" : 6249, "state" : "CA" }
+{ "_id" : "93446", "city" : "ADELAIDE", "loc" : [ -120.670676, 35.635248 ], "pop" : 29255, "state" : "CA" }
+{ "_id" : "93449", "city" : "SHELL BEACH", "loc" : [ -120.651788, 35.149212 ], "pop" : 7474, "state" : "CA" }
+{ "_id" : "93450", "city" : "SAN ARDO", "loc" : [ -120.861191, 35.985685 ], "pop" : 1684, "state" : "CA" }
+{ "_id" : "93451", "city" : "PARKFIELD", "loc" : [ -120.696532, 35.753209 ], "pop" : 1218, "state" : "CA" }
+{ "_id" : "93452", "city" : "SAN SIMEON", "loc" : [ -121.144033, 35.666815 ], "pop" : 500, "state" : "CA" }
+{ "_id" : "93453", "city" : "CALIFORNIA VALLE", "loc" : [ -120.3202, 35.341254 ], "pop" : 1237, "state" : "CA" }
+{ "_id" : "93454", "city" : "SANTA MARIA", "loc" : [ -120.43245, 34.954538 ], "pop" : 60187, "state" : "CA" }
+{ "_id" : "93455", "city" : "ORCUTT", "loc" : [ -120.429128, 34.879786 ], "pop" : 32891, "state" : "CA" }
+{ "_id" : "93460", "city" : "SANTA YNEZ", "loc" : [ -120.071332, 34.623966 ], "pop" : 5659, "state" : "CA" }
+{ "_id" : "93461", "city" : "SHANDON", "loc" : [ -120.372047, 35.651273 ], "pop" : 908, "state" : "CA" }
+{ "_id" : "93463", "city" : "BALLARD", "loc" : [ -120.129286, 34.609931 ], "pop" : 8327, "state" : "CA" }
+{ "_id" : "93465", "city" : "TEMPLETON", "loc" : [ -120.710737, 35.555082 ], "pop" : 5795, "state" : "CA" }
+{ "_id" : "93501", "city" : "MOJAVE", "loc" : [ -118.173475, 35.047767 ], "pop" : 4774, "state" : "CA" }
+{ "_id" : "93505", "city" : "CALIFORNIA CITY", "loc" : [ -117.965142, 35.127783 ], "pop" : 6086, "state" : "CA" }
+{ "_id" : "93510", "city" : "ACTON", "loc" : [ -118.195929, 34.483541 ], "pop" : 6139, "state" : "CA" }
+{ "_id" : "93512", "city" : "BENTON", "loc" : [ -118.498526, 37.798099 ], "pop" : 241, "state" : "CA" }
+{ "_id" : "93513", "city" : "BIG PINE", "loc" : [ -118.291597, 37.167857 ], "pop" : 1642, "state" : "CA" }
+{ "_id" : "93514", "city" : "TOMS PLACE", "loc" : [ -118.44156, 37.386301 ], "pop" : 14072, "state" : "CA" }
+{ "_id" : "93516", "city" : "BORON", "loc" : [ -117.662921, 35.003748 ], "pop" : 2904, "state" : "CA" }
+{ "_id" : "93517", "city" : "BRIDGEPORT", "loc" : [ -119.208025, 38.256601 ], "pop" : 697, "state" : "CA" }
+{ "_id" : "93518", "city" : "HAVILAH", "loc" : [ -118.410264, 35.356798 ], "pop" : 899, "state" : "CA" }
+{ "_id" : "93519", "city" : "CANTIL", "loc" : [ -117.993868, 35.282558 ], "pop" : 222, "state" : "CA" }
+{ "_id" : "93523", "city" : "NORTH EDWARDS", "loc" : [ -117.915384, 34.930507 ], "pop" : 8996, "state" : "CA" }
+{ "_id" : "93526", "city" : "INDEPENDENCE", "loc" : [ -118.204808, 36.839578 ], "pop" : 889, "state" : "CA" }
+{ "_id" : "93527", "city" : "PEARSONVILLE", "loc" : [ -117.834844, 35.674498 ], "pop" : 2633, "state" : "CA" }
+{ "_id" : "93528", "city" : "JOHANNESBURG", "loc" : [ -117.637325, 35.370655 ], "pop" : 306, "state" : "CA" }
+{ "_id" : "93529", "city" : "JUNE LAKE", "loc" : [ -119.082492, 37.777324 ], "pop" : 609, "state" : "CA" }
+{ "_id" : "93531", "city" : "KEENE", "loc" : [ -118.607563, 35.237502 ], "pop" : 455, "state" : "CA" }
+{ "_id" : "93532", "city" : "ELIZABETH LAKE", "loc" : [ -118.444719, 34.668297 ], "pop" : 2337, "state" : "CA" }
+{ "_id" : "93534", "city" : "LANCASTER", "loc" : [ -118.149129, 34.690888 ], "pop" : 32929, "state" : "CA" }
+{ "_id" : "93535", "city" : "HI VISTA", "loc" : [ -118.063245, 34.684751 ], "pop" : 49751, "state" : "CA" }
+{ "_id" : "93536", "city" : "QUARTZ HILL", "loc" : [ -118.213336, 34.673619 ], "pop" : 39987, "state" : "CA" }
+{ "_id" : "93541", "city" : "LEE VINING", "loc" : [ -119.123413, 37.988988 ], "pop" : 415, "state" : "CA" }
+{ "_id" : "93543", "city" : "JUNIPER HILLS", "loc" : [ -117.957405, 34.547372 ], "pop" : 10046, "state" : "CA" }
+{ "_id" : "93544", "city" : "CRYSTALAIRE", "loc" : [ -117.798841, 34.495914 ], "pop" : 1204, "state" : "CA" }
+{ "_id" : "93545", "city" : "LONE PINE", "loc" : [ -118.057824, 36.579781 ], "pop" : 2257, "state" : "CA" }
+{ "_id" : "93546", "city" : "CROWLEY LAKE", "loc" : [ -118.976383, 37.642361 ], "pop" : 4832, "state" : "CA" }
+{ "_id" : "93550", "city" : "LAKE LOS ANGELES", "loc" : [ -118.061306, 34.571483 ], "pop" : 71024, "state" : "CA" }
+{ "_id" : "93551", "city" : "LEONA VALLEY", "loc" : [ -118.181207, 34.601404 ], "pop" : 20768, "state" : "CA" }
+{ "_id" : "93553", "city" : "JUNIPER HILLS", "loc" : [ -117.902893, 34.491124 ], "pop" : 1106, "state" : "CA" }
+{ "_id" : "93554", "city" : "RANDSBURG", "loc" : [ -117.726396, 35.352176 ], "pop" : 190, "state" : "CA" }
+{ "_id" : "93555", "city" : "CHINA LAKE NWC", "loc" : [ -117.679733, 35.631376 ], "pop" : 34246, "state" : "CA" }
+{ "_id" : "93560", "city" : "WILLOW SPRINGS", "loc" : [ -118.19636, 34.863117 ], "pop" : 9898, "state" : "CA" }
+{ "_id" : "93561", "city" : "BEAR VALLEY SPRI", "loc" : [ -118.522227, 35.129776 ], "pop" : 24466, "state" : "CA" }
+{ "_id" : "93562", "city" : "ARGUS", "loc" : [ -117.382992, 35.760817 ], "pop" : 3189, "state" : "CA" }
+{ "_id" : "93563", "city" : "VALYERMO", "loc" : [ -117.8271, 34.339014 ], "pop" : 1456, "state" : "CA" }
+{ "_id" : "93601", "city" : "AHWAHNEE", "loc" : [ -119.723251, 37.407631 ], "pop" : 327, "state" : "CA" }
+{ "_id" : "93602", "city" : "AUBERRY", "loc" : [ -119.457202, 37.072635 ], "pop" : 3179, "state" : "CA" }
+{ "_id" : "93604", "city" : "BASS LAKE", "loc" : [ -119.556839, 37.324359 ], "pop" : 628, "state" : "CA" }
+{ "_id" : "93608", "city" : "CANTUA CREEK", "loc" : [ -120.335252, 36.492123 ], "pop" : 1622, "state" : "CA" }
+{ "_id" : "93609", "city" : "CARUTHERS", "loc" : [ -119.844581, 36.535847 ], "pop" : 4558, "state" : "CA" }
+{ "_id" : "93610", "city" : "CHOWCHILLA", "loc" : [ -120.269077, 37.101371 ], "pop" : 10745, "state" : "CA" }
+{ "_id" : "93612", "city" : "CLOVIS", "loc" : [ -119.689757, 36.823146 ], "pop" : 59963, "state" : "CA" }
+{ "_id" : "93614", "city" : "COARSEGOLD", "loc" : [ -119.745545, 37.221378 ], "pop" : 6950, "state" : "CA" }
+{ "_id" : "93615", "city" : "CUTLER", "loc" : [ -119.287023, 36.524266 ], "pop" : 4901, "state" : "CA" }
+{ "_id" : "93616", "city" : "DEL REY", "loc" : [ -119.59291, 36.654306 ], "pop" : 1923, "state" : "CA" }
+{ "_id" : "93618", "city" : "DINUBA", "loc" : [ -119.39087, 36.534931 ], "pop" : 20012, "state" : "CA" }
+{ "_id" : "93620", "city" : "DOS PALOS", "loc" : [ -120.633348, 37.00253 ], "pop" : 9311, "state" : "CA" }
+{ "_id" : "93621", "city" : "DUNLAP", "loc" : [ -119.089931, 36.744635 ], "pop" : 94, "state" : "CA" }
+{ "_id" : "93622", "city" : "FIREBAUGH", "loc" : [ -120.470048, 36.8651 ], "pop" : 7435, "state" : "CA" }
+{ "_id" : "93623", "city" : "FISH CAMP", "loc" : [ -119.642005, 37.51692 ], "pop" : 132, "state" : "CA" }
+{ "_id" : "93625", "city" : "FOWLER", "loc" : [ -119.671025, 36.628153 ], "pop" : 5290, "state" : "CA" }
+{ "_id" : "93626", "city" : "FRIANT", "loc" : [ -119.696501, 37.002416 ], "pop" : 871, "state" : "CA" }
+{ "_id" : "93627", "city" : "HELM", "loc" : [ -120.093598, 36.499231 ], "pop" : 832, "state" : "CA" }
+{ "_id" : "93630", "city" : "KERMAN", "loc" : [ -120.072444, 36.730576 ], "pop" : 11224, "state" : "CA" }
+{ "_id" : "93631", "city" : "KINGSBURG", "loc" : [ -119.543298, 36.508047 ], "pop" : 12263, "state" : "CA" }
+{ "_id" : "93633", "city" : "KINGS CANYON NAT", "loc" : [ -119.068201, 36.780601 ], "pop" : 472, "state" : "CA" }
+{ "_id" : "93635", "city" : "LOS BANOS", "loc" : [ -120.854387, 37.06266 ], "pop" : 18199, "state" : "CA" }
+{ "_id" : "93637", "city" : "MADERA", "loc" : [ -120.081966, 36.94026 ], "pop" : 20440, "state" : "CA" }
+{ "_id" : "93638", "city" : "MADERA", "loc" : [ -120.012778, 36.968726 ], "pop" : 36525, "state" : "CA" }
+{ "_id" : "93640", "city" : "MENDOTA", "loc" : [ -120.409287, 36.742365 ], "pop" : 8839, "state" : "CA" }
+{ "_id" : "93641", "city" : "MIRAMONTE", "loc" : [ -119.047718, 36.68938 ], "pop" : 607, "state" : "CA" }
+{ "_id" : "93643", "city" : "NORTH FORK", "loc" : [ -119.514324, 37.212531 ], "pop" : 2541, "state" : "CA" }
+{ "_id" : "93644", "city" : "OAKHURST", "loc" : [ -119.644854, 37.347561 ], "pop" : 8190, "state" : "CA" }
+{ "_id" : "93645", "city" : "O NEALS", "loc" : [ -119.745369, 37.086874 ], "pop" : 24, "state" : "CA" }
+{ "_id" : "93646", "city" : "ORANGE COVE", "loc" : [ -119.313502, 36.624283 ], "pop" : 6374, "state" : "CA" }
+{ "_id" : "93647", "city" : "OROSI", "loc" : [ -119.281522, 36.546368 ], "pop" : 7545, "state" : "CA" }
+{ "_id" : "93648", "city" : "PARLIER", "loc" : [ -119.537482, 36.610265 ], "pop" : 9076, "state" : "CA" }
+{ "_id" : "93650", "city" : "PINEDALE", "loc" : [ -119.800359, 36.841107 ], "pop" : 4164, "state" : "CA" }
+{ "_id" : "93651", "city" : "PRATHER", "loc" : [ -119.526771, 36.993799 ], "pop" : 1446, "state" : "CA" }
+{ "_id" : "93652", "city" : "RAISIN", "loc" : [ -119.903158, 36.598928 ], "pop" : 381, "state" : "CA" }
+{ "_id" : "93653", "city" : "RAYMOND", "loc" : [ -119.876567, 37.27898 ], "pop" : 491, "state" : "CA" }
+{ "_id" : "93654", "city" : "REEDLEY", "loc" : [ -119.437785, 36.604406 ], "pop" : 22370, "state" : "CA" }
+{ "_id" : "93656", "city" : "RIVERDALE", "loc" : [ -119.871953, 36.429525 ], "pop" : 4386, "state" : "CA" }
+{ "_id" : "93657", "city" : "SANGER", "loc" : [ -119.547796, 36.7243 ], "pop" : 27201, "state" : "CA" }
+{ "_id" : "93660", "city" : "SAN JOAQUIN", "loc" : [ -120.188934, 36.605869 ], "pop" : 2727, "state" : "CA" }
+{ "_id" : "93662", "city" : "SELMA", "loc" : [ -119.617026, 36.569524 ], "pop" : 21798, "state" : "CA" }
+{ "_id" : "93664", "city" : "SHAVER LAKE", "loc" : [ -119.273031, 37.139695 ], "pop" : 925, "state" : "CA" }
+{ "_id" : "93667", "city" : "TOLLHOUSE", "loc" : [ -119.391415, 36.99434 ], "pop" : 1820, "state" : "CA" }
+{ "_id" : "93668", "city" : "TRANQUILLITY", "loc" : [ -120.261655, 36.658376 ], "pop" : 1297, "state" : "CA" }
+{ "_id" : "93669", "city" : "WISHON", "loc" : [ -119.557014, 37.281028 ], "pop" : 474, "state" : "CA" }
+{ "_id" : "93675", "city" : "SQUAW VALLEY", "loc" : [ -119.181449, 36.707146 ], "pop" : 2731, "state" : "CA" }
+{ "_id" : "93701", "city" : "FRESNO", "loc" : [ -119.786705, 36.748727 ], "pop" : 15024, "state" : "CA" }
+{ "_id" : "93702", "city" : "FRESNO", "loc" : [ -119.753215, 36.739954 ], "pop" : 44477, "state" : "CA" }
+{ "_id" : "93703", "city" : "FRESNO", "loc" : [ -119.759401, 36.768445 ], "pop" : 30457, "state" : "CA" }
+{ "_id" : "93704", "city" : "FIG GARDEN VILLA", "loc" : [ -119.799745, 36.798781 ], "pop" : 26496, "state" : "CA" }
+{ "_id" : "93705", "city" : "FRESNO", "loc" : [ -119.828617, 36.786285 ], "pop" : 34114, "state" : "CA" }
+{ "_id" : "93706", "city" : "EASTON", "loc" : [ -119.820408, 36.700589 ], "pop" : 33682, "state" : "CA" }
+{ "_id" : "93710", "city" : "FRESNO", "loc" : [ -119.76205, 36.823643 ], "pop" : 29719, "state" : "CA" }
+{ "_id" : "93711", "city" : "FRESNO", "loc" : [ -119.831896, 36.830297 ], "pop" : 29809, "state" : "CA" }
+{ "_id" : "93720", "city" : "FRESNO", "loc" : [ -119.765522, 36.857944 ], "pop" : 21498, "state" : "CA" }
+{ "_id" : "93721", "city" : "FRESNO", "loc" : [ -119.784273, 36.737714 ], "pop" : 6156, "state" : "CA" }
+{ "_id" : "93722", "city" : "FRESNO", "loc" : [ -119.880119, 36.791779 ], "pop" : 33523, "state" : "CA" }
+{ "_id" : "93725", "city" : "CALWA", "loc" : [ -119.742477, 36.675312 ], "pop" : 19698, "state" : "CA" }
+{ "_id" : "93726", "city" : "FRESNO", "loc" : [ -119.760445, 36.794943 ], "pop" : 36325, "state" : "CA" }
+{ "_id" : "93727", "city" : "FRESNO", "loc" : [ -119.706055, 36.752796 ], "pop" : 51417, "state" : "CA" }
+{ "_id" : "93728", "city" : "FRESNO", "loc" : [ -119.811314, 36.758095 ], "pop" : 15386, "state" : "CA" }
+{ "_id" : "93901", "city" : "SALINAS", "loc" : [ -121.659589, 36.667693 ], "pop" : 25605, "state" : "CA" }
+{ "_id" : "93905", "city" : "SALINAS", "loc" : [ -121.617606, 36.681143 ], "pop" : 41956, "state" : "CA" }
+{ "_id" : "93906", "city" : "SALINAS", "loc" : [ -121.643805, 36.710339 ], "pop" : 39534, "state" : "CA" }
+{ "_id" : "93907", "city" : "PRUNEDALE", "loc" : [ -121.665588, 36.765385 ], "pop" : 21061, "state" : "CA" }
+{ "_id" : "93908", "city" : "SALINAS", "loc" : [ -121.672861, 36.601122 ], "pop" : 15610, "state" : "CA" }
+{ "_id" : "93920", "city" : "BIG SUR", "loc" : [ -121.700897, 36.245798 ], "pop" : 1669, "state" : "CA" }
+{ "_id" : "93923", "city" : "CARMEL", "loc" : [ -121.894875, 36.545693 ], "pop" : 15293, "state" : "CA" }
+{ "_id" : "93924", "city" : "CARMEL VALLEY", "loc" : [ -121.724356, 36.478709 ], "pop" : 6066, "state" : "CA" }
+{ "_id" : "93925", "city" : "CHUALAR", "loc" : [ -121.431964, 36.595042 ], "pop" : 12, "state" : "CA" }
+{ "_id" : "93926", "city" : "GONZALES", "loc" : [ -121.410347, 36.490038 ], "pop" : 12842, "state" : "CA" }
+{ "_id" : "93927", "city" : "GREENFIELD", "loc" : [ -121.24507, 36.320178 ], "pop" : 8728, "state" : "CA" }
+{ "_id" : "93930", "city" : "KING CITY", "loc" : [ -121.127329, 36.202776 ], "pop" : 11299, "state" : "CA" }
+{ "_id" : "93932", "city" : "LOCKWOOD", "loc" : [ -121.205946, 35.989287 ], "pop" : 939, "state" : "CA" }
+{ "_id" : "93933", "city" : "MARINA", "loc" : [ -121.793383, 36.684922 ], "pop" : 16973, "state" : "CA" }
+{ "_id" : "93940", "city" : "DEL REY OAKS", "loc" : [ -121.8848, 36.595642 ], "pop" : 35326, "state" : "CA" }
+{ "_id" : "93941", "city" : "FORT ORD", "loc" : [ -121.804999, 36.644627 ], "pop" : 25009, "state" : "CA" }
+{ "_id" : "93950", "city" : "PACIFIC GROVE", "loc" : [ -121.921957, 36.616737 ], "pop" : 16040, "state" : "CA" }
+{ "_id" : "93953", "city" : "PEBBLE BEACH", "loc" : [ -121.942044, 36.590735 ], "pop" : 5061, "state" : "CA" }
+{ "_id" : "93955", "city" : "SAND CITY", "loc" : [ -121.835724, 36.609208 ], "pop" : 23514, "state" : "CA" }
+{ "_id" : "93960", "city" : "SOLEDAD", "loc" : [ -121.324286, 36.41964 ], "pop" : 9046, "state" : "CA" }
+{ "_id" : "94002", "city" : "BELMONT", "loc" : [ -122.292671, 37.517433 ], "pop" : 24960, "state" : "CA" }
+{ "_id" : "94005", "city" : "BRISBANE", "loc" : [ -122.400118, 37.681104 ], "pop" : 2952, "state" : "CA" }
+{ "_id" : "94010", "city" : "HILLSBOROUGH", "loc" : [ -122.362952, 37.575884 ], "pop" : 38444, "state" : "CA" }
+{ "_id" : "94014", "city" : "COLMA", "loc" : [ -122.452679, 37.698187 ], "pop" : 40406, "state" : "CA" }
+{ "_id" : "94015", "city" : "DALY CITY", "loc" : [ -122.478015, 37.678696 ], "pop" : 57354, "state" : "CA" }
+{ "_id" : "94019", "city" : "HALF MOON BAY", "loc" : [ -122.445929, 37.479057 ], "pop" : 14073, "state" : "CA" }
+{ "_id" : "94020", "city" : "LA HONDA", "loc" : [ -122.293889, 37.272285 ], "pop" : 1557, "state" : "CA" }
+{ "_id" : "94021", "city" : "LOMA MAR", "loc" : [ -122.281996, 37.254437 ], "pop" : 237, "state" : "CA" }
+{ "_id" : "94022", "city" : "LOS ALTOS", "loc" : [ -122.125754, 37.381432 ], "pop" : 17366, "state" : "CA" }
+{ "_id" : "94024", "city" : "LOS ALTOS", "loc" : [ -122.086205, 37.354745 ], "pop" : 20795, "state" : "CA" }
+{ "_id" : "94025", "city" : "WEST MENLO PARK", "loc" : [ -122.179136, 37.453401 ], "pop" : 38383, "state" : "CA" }
+{ "_id" : "94027", "city" : "ATHERTON", "loc" : [ -122.200198, 37.456255 ], "pop" : 7312, "state" : "CA" }
+{ "_id" : "94028", "city" : "LADERA", "loc" : [ -122.208131, 37.378859 ], "pop" : 6379, "state" : "CA" }
+{ "_id" : "94030", "city" : "MILLBRAE", "loc" : [ -122.401985, 37.600382 ], "pop" : 20508, "state" : "CA" }
+{ "_id" : "94035", "city" : "MOFFETT FIELD", "loc" : [ -122.051944, 37.41001 ], "pop" : 790, "state" : "CA" }
+{ "_id" : "94038", "city" : "MOSS BEACH", "loc" : [ -122.50683, 37.531039 ], "pop" : 5415, "state" : "CA" }
+{ "_id" : "94040", "city" : "MOUNTAIN VIEW", "loc" : [ -122.087983, 37.385532 ], "pop" : 26969, "state" : "CA" }
+{ "_id" : "94041", "city" : "MOUNTAIN VIEW", "loc" : [ -122.078341, 37.389347 ], "pop" : 13438, "state" : "CA" }
+{ "_id" : "94043", "city" : "MOUNTAIN VIEW", "loc" : [ -122.077468, 37.405567 ], "pop" : 28592, "state" : "CA" }
+{ "_id" : "94044", "city" : "PACIFICA", "loc" : [ -122.481607, 37.619559 ], "pop" : 37596, "state" : "CA" }
+{ "_id" : "94060", "city" : "PESCADERO", "loc" : [ -122.364876, 37.206518 ], "pop" : 670, "state" : "CA" }
+{ "_id" : "94061", "city" : "REDWOOD CITY", "loc" : [ -122.230406, 37.464661 ], "pop" : 33316, "state" : "CA" }
+{ "_id" : "94062", "city" : "WOODSIDE", "loc" : [ -122.255879, 37.452119 ], "pop" : 24947, "state" : "CA" }
+{ "_id" : "94063", "city" : "REDWOOD CITY", "loc" : [ -122.209134, 37.481544 ], "pop" : 28251, "state" : "CA" }
+{ "_id" : "94065", "city" : "REDWOOD CITY", "loc" : [ -122.248564, 37.533128 ], "pop" : 2285, "state" : "CA" }
+{ "_id" : "94066", "city" : "SAN BRUNO", "loc" : [ -122.429021, 37.624742 ], "pop" : 38678, "state" : "CA" }
+{ "_id" : "94070", "city" : "SAN CARLOS", "loc" : [ -122.267356, 37.496859 ], "pop" : 27599, "state" : "CA" }
+{ "_id" : "94074", "city" : "SAN GREGORIO", "loc" : [ -122.355552, 37.325513 ], "pop" : 312, "state" : "CA" }
+{ "_id" : "94080", "city" : "SOUTH SAN FRANCI", "loc" : [ -122.4347, 37.65382 ], "pop" : 54610, "state" : "CA" }
+{ "_id" : "94086", "city" : "SUNNYVALE", "loc" : [ -122.023771, 37.376407 ], "pop" : 56215, "state" : "CA" }
+{ "_id" : "94087", "city" : "SUNNYVALE", "loc" : [ -122.034859, 37.350214 ], "pop" : 47813, "state" : "CA" }
+{ "_id" : "94089", "city" : "SUNNYVALE", "loc" : [ -122.000637, 37.398255 ], "pop" : 13522, "state" : "CA" }
+{ "_id" : "94102", "city" : "SAN FRANCISCO", "loc" : [ -122.416728, 37.781334 ], "pop" : 26908, "state" : "CA" }
+{ "_id" : "94103", "city" : "SAN FRANCISCO", "loc" : [ -122.414664, 37.77254 ], "pop" : 17867, "state" : "CA" }
+{ "_id" : "94104", "city" : "SAN FRANCISCO", "loc" : [ -122.401826, 37.791487 ], "pop" : 760, "state" : "CA" }
+{ "_id" : "94105", "city" : "SAN FRANCISCO", "loc" : [ -122.389229, 37.786427 ], "pop" : 2054, "state" : "CA" }
+{ "_id" : "94107", "city" : "SAN FRANCISCO", "loc" : [ -122.397099, 37.762147 ], "pop" : 12143, "state" : "CA" }
+{ "_id" : "94108", "city" : "SAN FRANCISCO", "loc" : [ -122.40791, 37.792931 ], "pop" : 14143, "state" : "CA" }
+{ "_id" : "94109", "city" : "SAN FRANCISCO", "loc" : [ -122.418579, 37.791687 ], "pop" : 49396, "state" : "CA" }
+{ "_id" : "94110", "city" : "SAN FRANCISCO", "loc" : [ -122.415344, 37.750858 ], "pop" : 70770, "state" : "CA" }
+{ "_id" : "94111", "city" : "SAN FRANCISCO", "loc" : [ -122.400147, 37.797376 ], "pop" : 3122, "state" : "CA" }
+{ "_id" : "94112", "city" : "SAN FRANCISCO", "loc" : [ -122.441081, 37.71954 ], "pop" : 64320, "state" : "CA" }
+{ "_id" : "94114", "city" : "SAN FRANCISCO", "loc" : [ -122.432977, 37.758716 ], "pop" : 30698, "state" : "CA" }
+{ "_id" : "94115", "city" : "SAN FRANCISCO", "loc" : [ -122.435835, 37.785607 ], "pop" : 28859, "state" : "CA" }
+{ "_id" : "94116", "city" : "SAN FRANCISCO", "loc" : [ -122.486296, 37.744144 ], "pop" : 39970, "state" : "CA" }
+{ "_id" : "94117", "city" : "SAN FRANCISCO", "loc" : [ -122.441272, 37.771234 ], "pop" : 38127, "state" : "CA" }
+{ "_id" : "94118", "city" : "SAN FRANCISCO", "loc" : [ -122.461414, 37.781174 ], "pop" : 38499, "state" : "CA" }
+{ "_id" : "94121", "city" : "SAN FRANCISCO", "loc" : [ -122.489178, 37.778616 ], "pop" : 40430, "state" : "CA" }
+{ "_id" : "94122", "city" : "SAN FRANCISCO", "loc" : [ -122.483647, 37.759326 ], "pop" : 52318, "state" : "CA" }
+{ "_id" : "94123", "city" : "SAN FRANCISCO", "loc" : [ -122.434163, 37.799865 ], "pop" : 23280, "state" : "CA" }
+{ "_id" : "94124", "city" : "SAN FRANCISCO", "loc" : [ -122.388649, 37.730888 ], "pop" : 27239, "state" : "CA" }
+{ "_id" : "94127", "city" : "SAN FRANCISCO", "loc" : [ -122.457116, 37.735385 ], "pop" : 17906, "state" : "CA" }
+{ "_id" : "94129", "city" : "SAN FRANCISCO", "loc" : [ -122.464958, 37.800507 ], "pop" : 4715, "state" : "CA" }
+{ "_id" : "94130", "city" : "SAN FRANCISCO", "loc" : [ -122.369319, 37.823128 ], "pop" : 4533, "state" : "CA" }
+{ "_id" : "94131", "city" : "SAN FRANCISCO", "loc" : [ -122.438335, 37.745032 ], "pop" : 30521, "state" : "CA" }
+{ "_id" : "94132", "city" : "SAN FRANCISCO", "loc" : [ -122.47545, 37.721118 ], "pop" : 23632, "state" : "CA" }
+{ "_id" : "94133", "city" : "SAN FRANCISCO", "loc" : [ -122.409081, 37.800175 ], "pop" : 27148, "state" : "CA" }
+{ "_id" : "94134", "city" : "SAN FRANCISCO", "loc" : [ -122.409577, 37.718968 ], "pop" : 34635, "state" : "CA" }
+{ "_id" : "94301", "city" : "PALO ALTO", "loc" : [ -122.149685, 37.444324 ], "pop" : 15965, "state" : "CA" }
+{ "_id" : "94303", "city" : "EAST PALO ALTO", "loc" : [ -122.131902, 37.455641 ], "pop" : 35680, "state" : "CA" }
+{ "_id" : "94304", "city" : "PALO ALTO", "loc" : [ -122.184234, 37.433424 ], "pop" : 1835, "state" : "CA" }
+{ "_id" : "94305", "city" : "STANFORD", "loc" : [ -122.161867, 37.423573 ], "pop" : 18097, "state" : "CA" }
+{ "_id" : "94306", "city" : "PALO ALTO", "loc" : [ -122.127375, 37.418009 ], "pop" : 24309, "state" : "CA" }
+{ "_id" : "94401", "city" : "RUSSIAN RIVER", "loc" : [ -122.320262, 37.572271 ], "pop" : 28190, "state" : "CA" }
+{ "_id" : "94402", "city" : "SAN MATEO", "loc" : [ -122.32762, 37.550685 ], "pop" : 23838, "state" : "CA" }
+{ "_id" : "94403", "city" : "SAN MATEO", "loc" : [ -122.299796, 37.539495 ], "pop" : 35630, "state" : "CA" }
+{ "_id" : "94404", "city" : "FOSTER CITY", "loc" : [ -122.263577, 37.551614 ], "pop" : 33745, "state" : "CA" }
+{ "_id" : "94501", "city" : "COAST GUARD ISLA", "loc" : [ -122.260516, 37.764783 ], "pop" : 76110, "state" : "CA" }
+{ "_id" : "94507", "city" : "ALAMO", "loc" : [ -122.022868, 37.853695 ], "pop" : 8569, "state" : "CA" }
+{ "_id" : "94508", "city" : "ANGWIN", "loc" : [ -122.447732, 38.576906 ], "pop" : 4067, "state" : "CA" }
+{ "_id" : "94509", "city" : "ANTIOCH", "loc" : [ -121.808906, 37.993917 ], "pop" : 62830, "state" : "CA" }
+{ "_id" : "94510", "city" : "BENICIA", "loc" : [ -122.161392, 38.068459 ], "pop" : 24545, "state" : "CA" }
+{ "_id" : "94512", "city" : "BIRDS LANDING", "loc" : [ -121.844318, 38.150402 ], "pop" : 32, "state" : "CA" }
+{ "_id" : "94513", "city" : "BRENTWOOD", "loc" : [ -121.689427, 37.932415 ], "pop" : 12372, "state" : "CA" }
+{ "_id" : "94514", "city" : "BYRON", "loc" : [ -121.602211, 37.902616 ], "pop" : 5745, "state" : "CA" }
+{ "_id" : "94515", "city" : "CALISTOGA", "loc" : [ -122.581384, 38.582305 ], "pop" : 5758, "state" : "CA" }
+{ "_id" : "94517", "city" : "CLAYTON", "loc" : [ -121.909967, 37.915442 ], "pop" : 10353, "state" : "CA" }
+{ "_id" : "94518", "city" : "CONCORD", "loc" : [ -122.026296, 37.950434 ], "pop" : 25516, "state" : "CA" }
+{ "_id" : "94519", "city" : "CONCORD", "loc" : [ -122.011948, 37.984082 ], "pop" : 19032, "state" : "CA" }
+{ "_id" : "94520", "city" : "CONCORD", "loc" : [ -122.036178, 37.982259 ], "pop" : 31474, "state" : "CA" }
+{ "_id" : "94521", "city" : "CONCORD", "loc" : [ -121.974955, 37.957503 ], "pop" : 39005, "state" : "CA" }
+{ "_id" : "94523", "city" : "PLEASANT HILL", "loc" : [ -122.07371, 37.954002 ], "pop" : 31046, "state" : "CA" }
+{ "_id" : "94525", "city" : "CROCKETT", "loc" : [ -122.217659, 38.051865 ], "pop" : 3228, "state" : "CA" }
+{ "_id" : "94526", "city" : "DANVILLE", "loc" : [ -121.96598, 37.813985 ], "pop" : 40613, "state" : "CA" }
+{ "_id" : "94528", "city" : "DIABLO", "loc" : [ -121.960951, 37.83883 ], "pop" : 791, "state" : "CA" }
+{ "_id" : "94530", "city" : "EL CERRITO", "loc" : [ -122.298521, 37.915633 ], "pop" : 28146, "state" : "CA" }
+{ "_id" : "94533", "city" : "FAIRFIELD", "loc" : [ -122.03565, 38.267084 ], "pop" : 65455, "state" : "CA" }
+{ "_id" : "94535", "city" : "TRAVIS AFB", "loc" : [ -121.946317, 38.274313 ], "pop" : 9874, "state" : "CA" }
+{ "_id" : "94536", "city" : "FREMONT", "loc" : [ -121.999935, 37.560493 ], "pop" : 58580, "state" : "CA" }
+{ "_id" : "94538", "city" : "FREMONT", "loc" : [ -121.971215, 37.530815 ], "pop" : 45430, "state" : "CA" }
+{ "_id" : "94539", "city" : "FREMONT", "loc" : [ -121.928733, 37.517579 ], "pop" : 39927, "state" : "CA" }
+{ "_id" : "94541", "city" : "HAYWARD", "loc" : [ -122.089418, 37.674048 ], "pop" : 48964, "state" : "CA" }
+{ "_id" : "94542", "city" : "HAYWARD", "loc" : [ -122.047236, 37.658566 ], "pop" : 11165, "state" : "CA" }
+{ "_id" : "94544", "city" : "HAYWARD", "loc" : [ -122.067029, 37.637443 ], "pop" : 58348, "state" : "CA" }
+{ "_id" : "94545", "city" : "HAYWARD", "loc" : [ -122.0971, 37.633245 ], "pop" : 23760, "state" : "CA" }
+{ "_id" : "94546", "city" : "CASTRO VALLEY", "loc" : [ -122.078183, 37.701527 ], "pop" : 37808, "state" : "CA" }
+{ "_id" : "94547", "city" : "HERCULES", "loc" : [ -122.263702, 38.006649 ], "pop" : 16376, "state" : "CA" }
+{ "_id" : "94548", "city" : "KNIGHTSEN", "loc" : [ -121.672149, 37.9818 ], "pop" : 118, "state" : "CA" }
+{ "_id" : "94549", "city" : "LAFAYETTE", "loc" : [ -122.11194, 37.896105 ], "pop" : 25979, "state" : "CA" }
+{ "_id" : "94550", "city" : "LIVERMORE", "loc" : [ -121.762983, 37.68299 ], "pop" : 59709, "state" : "CA" }
+{ "_id" : "94552", "city" : "CASTRO VALLEY", "loc" : [ -122.038113, 37.713107 ], "pop" : 7936, "state" : "CA" }
+{ "_id" : "94553", "city" : "PACHECO", "loc" : [ -122.111693, 37.993246 ], "pop" : 45532, "state" : "CA" }
+{ "_id" : "94555", "city" : "FREMONT", "loc" : [ -122.046925, 37.573458 ], "pop" : 29437, "state" : "CA" }
+{ "_id" : "94556", "city" : "MORAGA", "loc" : [ -122.124185, 37.843653 ], "pop" : 15988, "state" : "CA" }
+{ "_id" : "94558", "city" : "SPANISH FLAT", "loc" : [ -122.305518, 38.328137 ], "pop" : 57901, "state" : "CA" }
+{ "_id" : "94559", "city" : "NAPA", "loc" : [ -122.284086, 38.290362 ], "pop" : 23606, "state" : "CA" }
+{ "_id" : "94560", "city" : "NEWARK", "loc" : [ -122.031956, 37.536812 ], "pop" : 37861, "state" : "CA" }
+{ "_id" : "94561", "city" : "OAKLEY", "loc" : [ -121.703623, 37.994034 ], "pop" : 20920, "state" : "CA" }
+{ "_id" : "94563", "city" : "ORINDA", "loc" : [ -122.172848, 37.878659 ], "pop" : 16883, "state" : "CA" }
+{ "_id" : "94564", "city" : "PINOLE", "loc" : [ -122.287477, 37.996903 ], "pop" : 16920, "state" : "CA" }
+{ "_id" : "94565", "city" : "SHORE ACRES", "loc" : [ -121.908178, 38.016887 ], "pop" : 64053, "state" : "CA" }
+{ "_id" : "94566", "city" : "PLEASANTON", "loc" : [ -121.8755, 37.665804 ], "pop" : 32953, "state" : "CA" }
+{ "_id" : "94567", "city" : "POPE VALLEY", "loc" : [ -122.472244, 38.678192 ], "pop" : 286, "state" : "CA" }
+{ "_id" : "94568", "city" : "DUBLIN", "loc" : [ -121.922589, 37.716597 ], "pop" : 23275, "state" : "CA" }
+{ "_id" : "94569", "city" : "PORT COSTA", "loc" : [ -122.186649, 38.046013 ], "pop" : 228, "state" : "CA" }
+{ "_id" : "94571", "city" : "RIO VISTA", "loc" : [ -121.701635, 38.163734 ], "pop" : 4516, "state" : "CA" }
+{ "_id" : "94572", "city" : "RODEO", "loc" : [ -122.258139, 38.03069 ], "pop" : 7827, "state" : "CA" }
+{ "_id" : "94574", "city" : "SAINT HELENA", "loc" : [ -122.461921, 38.513776 ], "pop" : 9388, "state" : "CA" }
+{ "_id" : "94577", "city" : "SAN LEANDRO", "loc" : [ -122.158705, 37.720467 ], "pop" : 36779, "state" : "CA" }
+{ "_id" : "94578", "city" : "SAN LEANDRO", "loc" : [ -122.123969, 37.702377 ], "pop" : 31780, "state" : "CA" }
+{ "_id" : "94579", "city" : "SAN LEANDRO", "loc" : [ -122.150659, 37.689209 ], "pop" : 15754, "state" : "CA" }
+{ "_id" : "94580", "city" : "SAN LORENZO", "loc" : [ -122.129547, 37.678671 ], "pop" : 23010, "state" : "CA" }
+{ "_id" : "94583", "city" : "SAN RAMON", "loc" : [ -121.952224, 37.756188 ], "pop" : 35449, "state" : "CA" }
+{ "_id" : "94585", "city" : "SUISUN CITY", "loc" : [ -122.042003, 38.240834 ], "pop" : 31081, "state" : "CA" }
+{ "_id" : "94586", "city" : "SUNOL", "loc" : [ -121.898636, 37.609403 ], "pop" : 953, "state" : "CA" }
+{ "_id" : "94587", "city" : "UNION CITY", "loc" : [ -122.049702, 37.589458 ], "pop" : 52869, "state" : "CA" }
+{ "_id" : "94588", "city" : "PLEASANTON", "loc" : [ -121.8957, 37.687311 ], "pop" : 19032, "state" : "CA" }
+{ "_id" : "94589", "city" : "AMERICAN CANYON", "loc" : [ -122.249333, 38.148345 ], "pop" : 37599, "state" : "CA" }
+{ "_id" : "94590", "city" : "VALLEJO", "loc" : [ -122.247367, 38.105302 ], "pop" : 35516, "state" : "CA" }
+{ "_id" : "94591", "city" : "VALLEJO", "loc" : [ -122.212354, 38.09853 ], "pop" : 43336, "state" : "CA" }
+{ "_id" : "94592", "city" : "MARE ISLAND", "loc" : [ -122.27273, 38.094654 ], "pop" : 3589, "state" : "CA" }
+{ "_id" : "94595", "city" : "WALNUT CREEK", "loc" : [ -122.070259, 37.875317 ], "pop" : 16346, "state" : "CA" }
+{ "_id" : "94596", "city" : "WALNUT CREEK", "loc" : [ -122.054909, 37.905279 ], "pop" : 38092, "state" : "CA" }
+{ "_id" : "94598", "city" : "WALNUT CREEK", "loc" : [ -122.025879, 37.919424 ], "pop" : 24174, "state" : "CA" }
+{ "_id" : "94599", "city" : "YOUNTVILLE", "loc" : [ -122.358506, 38.403813 ], "pop" : 1876, "state" : "CA" }
+{ "_id" : "94601", "city" : "OAKLAND", "loc" : [ -122.216587, 37.780595 ], "pop" : 47715, "state" : "CA" }
+{ "_id" : "94602", "city" : "OAKLAND", "loc" : [ -122.210368, 37.801133 ], "pop" : 28629, "state" : "CA" }
+{ "_id" : "94603", "city" : "OAKLAND", "loc" : [ -122.171017, 37.740239 ], "pop" : 27303, "state" : "CA" }
+{ "_id" : "94605", "city" : "OAKLAND", "loc" : [ -122.163326, 37.764132 ], "pop" : 38511, "state" : "CA" }
+{ "_id" : "94606", "city" : "OAKLAND", "loc" : [ -122.24292, 37.79565 ], "pop" : 38555, "state" : "CA" }
+{ "_id" : "94607", "city" : "OAKLAND", "loc" : [ -122.285051, 37.807084 ], "pop" : 21294, "state" : "CA" }
+{ "_id" : "94608", "city" : "EMERYVILLE", "loc" : [ -122.280363, 37.836466 ], "pop" : 22318, "state" : "CA" }
+{ "_id" : "94609", "city" : "OAKLAND", "loc" : [ -122.26367, 37.836096 ], "pop" : 20263, "state" : "CA" }
+{ "_id" : "94610", "city" : "OAKLAND", "loc" : [ -122.244322, 37.812636 ], "pop" : 29637, "state" : "CA" }
+{ "_id" : "94611", "city" : "PIEDMONT", "loc" : [ -122.22683, 37.828157 ], "pop" : 34238, "state" : "CA" }
+{ "_id" : "94612", "city" : "OAKLAND", "loc" : [ -122.266774, 37.808473 ], "pop" : 10763, "state" : "CA" }
+{ "_id" : "94613", "city" : "OAKLAND", "loc" : [ -122.181585, 37.782427 ], "pop" : 627, "state" : "CA" }
+{ "_id" : "94618", "city" : "PIEDMONT", "loc" : [ -122.24191, 37.84368 ], "pop" : 15763, "state" : "CA" }
+{ "_id" : "94619", "city" : "OAKLAND", "loc" : [ -122.18838, 37.787786 ], "pop" : 24501, "state" : "CA" }
+{ "_id" : "94621", "city" : "OAKLAND", "loc" : [ -122.185335, 37.758924 ], "pop" : 26689, "state" : "CA" }
+{ "_id" : "94702", "city" : "BERKELEY", "loc" : [ -122.285126, 37.865611 ], "pop" : 15004, "state" : "CA" }
+{ "_id" : "94703", "city" : "BERKELEY", "loc" : [ -122.274914, 37.863028 ], "pop" : 18554, "state" : "CA" }
+{ "_id" : "94704", "city" : "BERKELEY", "loc" : [ -122.257048, 37.866428 ], "pop" : 23551, "state" : "CA" }
+{ "_id" : "94705", "city" : "BERKELEY", "loc" : [ -122.249964, 37.85711 ], "pop" : 11833, "state" : "CA" }
+{ "_id" : "94706", "city" : "ALBANY", "loc" : [ -122.295394, 37.890045 ], "pop" : 17333, "state" : "CA" }
+{ "_id" : "94707", "city" : "KENSINGTON", "loc" : [ -122.276517, 37.893118 ], "pop" : 9152, "state" : "CA" }
+{ "_id" : "94708", "city" : "KENSINGTON", "loc" : [ -122.25976, 37.890829 ], "pop" : 8874, "state" : "CA" }
+{ "_id" : "94709", "city" : "BERKELEY", "loc" : [ -122.265461, 37.878397 ], "pop" : 9927, "state" : "CA" }
+{ "_id" : "94710", "city" : "BERKELEY", "loc" : [ -122.295929, 37.869603 ], "pop" : 6891, "state" : "CA" }
+{ "_id" : "94801", "city" : "RICHMOND", "loc" : [ -122.36201, 37.940039 ], "pop" : 23948, "state" : "CA" }
+{ "_id" : "94803", "city" : "EL SOBRANTE", "loc" : [ -122.290092, 37.969287 ], "pop" : 22238, "state" : "CA" }
+{ "_id" : "94804", "city" : "RICHMOND", "loc" : [ -122.33421, 37.926523 ], "pop" : 33990, "state" : "CA" }
+{ "_id" : "94805", "city" : "RICHMOND", "loc" : [ -122.323756, 37.941719 ], "pop" : 12342, "state" : "CA" }
+{ "_id" : "94806", "city" : "SAN PABLO", "loc" : [ -122.336929, 37.972374 ], "pop" : 47668, "state" : "CA" }
+{ "_id" : "94901", "city" : "SAN RAFAEL", "loc" : [ -122.510502, 37.969144 ], "pop" : 41550, "state" : "CA" }
+{ "_id" : "94903", "city" : "CIVIC CENTER", "loc" : [ -122.54521, 38.015044 ], "pop" : 25563, "state" : "CA" }
+{ "_id" : "94904", "city" : "KENTFIELD", "loc" : [ -122.535501, 37.950599 ], "pop" : 11820, "state" : "CA" }
+{ "_id" : "94920", "city" : "BELVEDERE", "loc" : [ -122.472627, 37.889885 ], "pop" : 10993, "state" : "CA" }
+{ "_id" : "94922", "city" : "BODEGA", "loc" : [ -122.951364, 38.339264 ], "pop" : 93, "state" : "CA" }
+{ "_id" : "94923", "city" : "BODEGA BAY", "loc" : [ -123.037308, 38.330921 ], "pop" : 1427, "state" : "CA" }
+{ "_id" : "94924", "city" : "BOLINAS", "loc" : [ -122.694655, 37.907875 ], "pop" : 1555, "state" : "CA" }
+{ "_id" : "94925", "city" : "CORTE MADERA", "loc" : [ -122.513202, 37.922256 ], "pop" : 7974, "state" : "CA" }
+{ "_id" : "94928", "city" : "ROHNERT PARK", "loc" : [ -122.69408, 38.347027 ], "pop" : 35730, "state" : "CA" }
+{ "_id" : "94930", "city" : "FAIRFAX", "loc" : [ -122.593711, 37.988289 ], "pop" : 8051, "state" : "CA" }
+{ "_id" : "94931", "city" : "COTATI", "loc" : [ -122.704831, 38.325918 ], "pop" : 6849, "state" : "CA" }
+{ "_id" : "94933", "city" : "FOREST KNOLLS", "loc" : [ -122.69074, 38.012178 ], "pop" : 732, "state" : "CA" }
+{ "_id" : "94937", "city" : "INVERNESS", "loc" : [ -122.856774, 38.083514 ], "pop" : 1716, "state" : "CA" }
+{ "_id" : "94938", "city" : "LAGUNITAS", "loc" : [ -122.701576, 38.013929 ], "pop" : 276, "state" : "CA" }
+{ "_id" : "94939", "city" : "LARKSPUR", "loc" : [ -122.536202, 37.936743 ], "pop" : 5884, "state" : "CA" }
+{ "_id" : "94940", "city" : "MARSHALL", "loc" : [ -122.890011, 38.176221 ], "pop" : 55, "state" : "CA" }
+{ "_id" : "94941", "city" : "MILL VALLEY", "loc" : [ -122.533885, 37.895757 ], "pop" : 27746, "state" : "CA" }
+{ "_id" : "94945", "city" : "NOVATO", "loc" : [ -122.571416, 38.1163 ], "pop" : 15535, "state" : "CA" }
+{ "_id" : "94946", "city" : "NICASIO", "loc" : [ -122.696402, 38.054622 ], "pop" : 665, "state" : "CA" }
+{ "_id" : "94947", "city" : "NOVATO", "loc" : [ -122.583691, 38.097258 ], "pop" : 22759, "state" : "CA" }
+{ "_id" : "94949", "city" : "NOVATO", "loc" : [ -122.540408, 38.061837 ], "pop" : 16219, "state" : "CA" }
+{ "_id" : "94951", "city" : "PENNGROVE", "loc" : [ -122.671772, 38.315948 ], "pop" : 3886, "state" : "CA" }
+{ "_id" : "94952", "city" : "PETALUMA", "loc" : [ -122.677727, 38.240349 ], "pop" : 29724, "state" : "CA" }
+{ "_id" : "94954", "city" : "PETALUMA", "loc" : [ -122.615536, 38.250739 ], "pop" : 27667, "state" : "CA" }
+{ "_id" : "94956", "city" : "POINT REYES STAT", "loc" : [ -122.81621, 38.064794 ], "pop" : 951, "state" : "CA" }
+{ "_id" : "94960", "city" : "SAN ANSELMO", "loc" : [ -122.571062, 37.984579 ], "pop" : 15178, "state" : "CA" }
+{ "_id" : "94963", "city" : "SAN GERONIMO", "loc" : [ -122.67784, 38.017155 ], "pop" : 802, "state" : "CA" }
+{ "_id" : "94965", "city" : "SAUSALITO", "loc" : [ -122.494555, 37.860147 ], "pop" : 10032, "state" : "CA" }
+{ "_id" : "94970", "city" : "STINSON BEACH", "loc" : [ -122.639305, 37.901992 ], "pop" : 630, "state" : "CA" }
+{ "_id" : "94972", "city" : "VALLEY FORD", "loc" : [ -122.924457, 38.315729 ], "pop" : 114, "state" : "CA" }
+{ "_id" : "94973", "city" : "WOODACRE", "loc" : [ -122.638247, 38.006933 ], "pop" : 1524, "state" : "CA" }
+{ "_id" : "95002", "city" : "ALVISO", "loc" : [ -121.968597, 37.427659 ], "pop" : 2179, "state" : "CA" }
+{ "_id" : "95003", "city" : "APTOS", "loc" : [ -121.891979, 36.978477 ], "pop" : 23964, "state" : "CA" }
+{ "_id" : "95004", "city" : "AROMAS", "loc" : [ -121.639781, 36.878522 ], "pop" : 2713, "state" : "CA" }
+{ "_id" : "95005", "city" : "BEN LOMOND", "loc" : [ -122.083869, 37.086183 ], "pop" : 7702, "state" : "CA" }
+{ "_id" : "95006", "city" : "BOULDER CREEK", "loc" : [ -122.133053, 37.149934 ], "pop" : 9434, "state" : "CA" }
+{ "_id" : "95008", "city" : "CAMPBELL", "loc" : [ -121.95539, 37.280007 ], "pop" : 41821, "state" : "CA" }
+{ "_id" : "95010", "city" : "CAPITOLA", "loc" : [ -121.952145, 36.977359 ], "pop" : 9337, "state" : "CA" }
+{ "_id" : "95012", "city" : "CASTROVILLE", "loc" : [ -121.747368, 36.77142 ], "pop" : 7168, "state" : "CA" }
+{ "_id" : "95013", "city" : "COYOTE", "loc" : [ -121.746021, 37.216721 ], "pop" : 316, "state" : "CA" }
+{ "_id" : "95014", "city" : "MONTE VISTA", "loc" : [ -122.038604, 37.317363 ], "pop" : 47598, "state" : "CA" }
+{ "_id" : "95017", "city" : "DAVENPORT", "loc" : [ -122.225735, 37.06306 ], "pop" : 42, "state" : "CA" }
+{ "_id" : "95018", "city" : "FELTON", "loc" : [ -122.062162, 37.063124 ], "pop" : 8194, "state" : "CA" }
+{ "_id" : "95019", "city" : "FREEDOM", "loc" : [ -121.776761, 36.936483 ], "pop" : 5075, "state" : "CA" }
+{ "_id" : "95020", "city" : "GILROY", "loc" : [ -121.57825, 37.016005 ], "pop" : 39878, "state" : "CA" }
+{ "_id" : "95023", "city" : "HOLLISTER", "loc" : [ -121.387101, 36.848404 ], "pop" : 31243, "state" : "CA" }
+{ "_id" : "95030", "city" : "MONTE SERENO", "loc" : [ -121.978684, 37.211677 ], "pop" : 25881, "state" : "CA" }
+{ "_id" : "95032", "city" : "LOS GATOS", "loc" : [ -121.950088, 37.231571 ], "pop" : 18189, "state" : "CA" }
+{ "_id" : "95035", "city" : "MILPITAS", "loc" : [ -121.892885, 37.436491 ], "pop" : 50907, "state" : "CA" }
+{ "_id" : "95037", "city" : "MORGAN HILL", "loc" : [ -121.64636, 37.129171 ], "pop" : 31309, "state" : "CA" }
+{ "_id" : "95043", "city" : "PAICINES", "loc" : [ -121.032853, 36.49478 ], "pop" : 636, "state" : "CA" }
+{ "_id" : "95045", "city" : "SAN JUAN BAUTIST", "loc" : [ -121.532721, 36.849856 ], "pop" : 3657, "state" : "CA" }
+{ "_id" : "95046", "city" : "SAN MARTIN", "loc" : [ -121.599901, 37.091118 ], "pop" : 5563, "state" : "CA" }
+{ "_id" : "95050", "city" : "SANTA CLARA", "loc" : [ -121.954079, 37.34732 ], "pop" : 33310, "state" : "CA" }
+{ "_id" : "95051", "city" : "SANTA CLARA", "loc" : [ -121.983848, 37.346992 ], "pop" : 49570, "state" : "CA" }
+{ "_id" : "95054", "city" : "SANTA CLARA", "loc" : [ -121.95394, 37.394673 ], "pop" : 10370, "state" : "CA" }
+{ "_id" : "95060", "city" : "SCOTTS VALLEY", "loc" : [ -122.043612, 36.982946 ], "pop" : 40334, "state" : "CA" }
+{ "_id" : "95062", "city" : "SANTA CRUZ", "loc" : [ -121.988055, 36.972101 ], "pop" : 34287, "state" : "CA" }
+{ "_id" : "95064", "city" : "SANTA CRUZ", "loc" : [ -122.057803, 36.995851 ], "pop" : 4658, "state" : "CA" }
+{ "_id" : "95065", "city" : "SANTA CRUZ", "loc" : [ -121.982557, 37.003319 ], "pop" : 8130, "state" : "CA" }
+{ "_id" : "95066", "city" : "SCOTTS VALLEY", "loc" : [ -122.014961, 37.057841 ], "pop" : 10636, "state" : "CA" }
+{ "_id" : "95070", "city" : "SARATOGA", "loc" : [ -122.018238, 37.272871 ], "pop" : 28909, "state" : "CA" }
+{ "_id" : "95073", "city" : "SOQUEL", "loc" : [ -121.950255, 37.003525 ], "pop" : 8143, "state" : "CA" }
+{ "_id" : "95076", "city" : "LA SELVA BEACH", "loc" : [ -121.763437, 36.920515 ], "pop" : 68295, "state" : "CA" }
+{ "_id" : "95110", "city" : "SAN JOSE", "loc" : [ -121.890299, 37.32966 ], "pop" : 17437, "state" : "CA" }
+{ "_id" : "95111", "city" : "SAN JOSE", "loc" : [ -121.824038, 37.282276 ], "pop" : 48286, "state" : "CA" }
+{ "_id" : "95112", "city" : "SAN JOSE", "loc" : [ -121.880414, 37.341388 ], "pop" : 46470, "state" : "CA" }
+{ "_id" : "95113", "city" : "SAN JOSE", "loc" : [ -121.887227, 37.335188 ], "pop" : 1265, "state" : "CA" }
+{ "_id" : "95116", "city" : "SAN JOSE", "loc" : [ -121.850221, 37.351342 ], "pop" : 46754, "state" : "CA" }
+{ "_id" : "95117", "city" : "SAN JOSE", "loc" : [ -121.962126, 37.308896 ], "pop" : 27414, "state" : "CA" }
+{ "_id" : "95118", "city" : "SAN JOSE", "loc" : [ -121.889845, 37.256162 ], "pop" : 30591, "state" : "CA" }
+{ "_id" : "95119", "city" : "SAN JOSE", "loc" : [ -121.790067, 37.230135 ], "pop" : 9823, "state" : "CA" }
+{ "_id" : "95120", "city" : "SAN JOSE", "loc" : [ -121.861547, 37.217538 ], "pop" : 34577, "state" : "CA" }
+{ "_id" : "95121", "city" : "SAN JOSE", "loc" : [ -121.811939, 37.30593 ], "pop" : 32572, "state" : "CA" }
+{ "_id" : "95122", "city" : "SAN JOSE", "loc" : [ -121.833949, 37.329313 ], "pop" : 52543, "state" : "CA" }
+{ "_id" : "95123", "city" : "SAN JOSE", "loc" : [ -121.830502, 37.244594 ], "pop" : 55146, "state" : "CA" }
+{ "_id" : "95124", "city" : "SAN JOSE", "loc" : [ -121.920831, 37.256844 ], "pop" : 44595, "state" : "CA" }
+{ "_id" : "95125", "city" : "SAN JOSE", "loc" : [ -121.895476, 37.296187 ], "pop" : 42573, "state" : "CA" }
+{ "_id" : "95126", "city" : "SAN JOSE", "loc" : [ -121.917398, 37.322482 ], "pop" : 24778, "state" : "CA" }
+{ "_id" : "95127", "city" : "SAN JOSE", "loc" : [ -121.819516, 37.3664 ], "pop" : 50371, "state" : "CA" }
+{ "_id" : "95128", "city" : "SAN JOSE", "loc" : [ -121.934364, 37.314657 ], "pop" : 28275, "state" : "CA" }
+{ "_id" : "95129", "city" : "SAN JOSE", "loc" : [ -122.000494, 37.306537 ], "pop" : 33953, "state" : "CA" }
+{ "_id" : "95130", "city" : "SAN JOSE", "loc" : [ -121.979182, 37.288628 ], "pop" : 13765, "state" : "CA" }
+{ "_id" : "95131", "city" : "SAN JOSE", "loc" : [ -121.879977, 37.386368 ], "pop" : 18425, "state" : "CA" }
+{ "_id" : "95132", "city" : "SAN JOSE", "loc" : [ -121.860336, 37.40408 ], "pop" : 37995, "state" : "CA" }
+{ "_id" : "95133", "city" : "SAN JOSE", "loc" : [ -121.855959, 37.372875 ], "pop" : 24136, "state" : "CA" }
+{ "_id" : "95134", "city" : "SAN JOSE", "loc" : [ -121.943399, 37.413999 ], "pop" : 4324, "state" : "CA" }
+{ "_id" : "95135", "city" : "SAN JOSE", "loc" : [ -121.757228, 37.297539 ], "pop" : 9104, "state" : "CA" }
+{ "_id" : "95136", "city" : "SAN JOSE", "loc" : [ -121.847625, 37.268423 ], "pop" : 31200, "state" : "CA" }
+{ "_id" : "95138", "city" : "SAN JOSE", "loc" : [ -121.778641, 37.246259 ], "pop" : 5956, "state" : "CA" }
+{ "_id" : "95139", "city" : "SAN JOSE", "loc" : [ -121.766867, 37.225162 ], "pop" : 6912, "state" : "CA" }
+{ "_id" : "95140", "city" : "MOUNT HAMILTON", "loc" : [ -121.639948, 37.316087 ], "pop" : 37, "state" : "CA" }
+{ "_id" : "95141", "city" : "SAN JOSE", "loc" : [ -121.755808, 37.169912 ], "pop" : 0, "state" : "CA" }
+{ "_id" : "95148", "city" : "SAN JOSE", "loc" : [ -121.792111, 37.329765 ], "pop" : 37413, "state" : "CA" }
+{ "_id" : "95202", "city" : "STOCKTON", "loc" : [ -121.287087, 37.960632 ], "pop" : 7753, "state" : "CA" }
+{ "_id" : "95203", "city" : "STOCKTON", "loc" : [ -121.307688, 37.956515 ], "pop" : 17847, "state" : "CA" }
+{ "_id" : "95204", "city" : "STOCKTON", "loc" : [ -121.315364, 37.974302 ], "pop" : 28860, "state" : "CA" }
+{ "_id" : "95205", "city" : "STOCKTON", "loc" : [ -121.259241, 37.960986 ], "pop" : 31314, "state" : "CA" }
+{ "_id" : "95206", "city" : "STOCKTON", "loc" : [ -121.287169, 37.931643 ], "pop" : 33154, "state" : "CA" }
+{ "_id" : "95207", "city" : "STOCKTON", "loc" : [ -121.32056, 38.002025 ], "pop" : 50167, "state" : "CA" }
+{ "_id" : "95209", "city" : "STOCKTON", "loc" : [ -121.343292, 38.033105 ], "pop" : 26289, "state" : "CA" }
+{ "_id" : "95210", "city" : "STOCKTON", "loc" : [ -121.297229, 38.024997 ], "pop" : 33763, "state" : "CA" }
+{ "_id" : "95211", "city" : "UNIV OF THE PACI", "loc" : [ -121.310336, 37.980364 ], "pop" : 1722, "state" : "CA" }
+{ "_id" : "95212", "city" : "STOCKTON", "loc" : [ -121.246018, 38.034428 ], "pop" : 5584, "state" : "CA" }
+{ "_id" : "95215", "city" : "STOCKTON", "loc" : [ -121.215295, 37.968545 ], "pop" : 18533, "state" : "CA" }
+{ "_id" : "95219", "city" : "STOCKTON", "loc" : [ -121.363712, 38.010233 ], "pop" : 13994, "state" : "CA" }
+{ "_id" : "95220", "city" : "ACAMPO", "loc" : [ -121.218576, 38.200413 ], "pop" : 7734, "state" : "CA" }
+{ "_id" : "95222", "city" : "ANGELS CAMP", "loc" : [ -120.55437, 38.064011 ], "pop" : 3530, "state" : "CA" }
+{ "_id" : "95223", "city" : "BEAR VALLEY", "loc" : [ -120.342231, 38.24175 ], "pop" : 6205, "state" : "CA" }
+{ "_id" : "95228", "city" : "COPPEROPOLIS", "loc" : [ -120.638374, 37.937246 ], "pop" : 1336, "state" : "CA" }
+{ "_id" : "95230", "city" : "FARMINGTON", "loc" : [ -120.852343, 37.944771 ], "pop" : 141, "state" : "CA" }
+{ "_id" : "95231", "city" : "FRENCH CAMP", "loc" : [ -121.282704, 37.877982 ], "pop" : 3673, "state" : "CA" }
+{ "_id" : "95232", "city" : "GLENCOE", "loc" : [ -120.594546, 38.351557 ], "pop" : 189, "state" : "CA" }
+{ "_id" : "95236", "city" : "LINDEN", "loc" : [ -121.074442, 38.021869 ], "pop" : 3656, "state" : "CA" }
+{ "_id" : "95237", "city" : "LOCKEFORD", "loc" : [ -121.135611, 38.162436 ], "pop" : 2847, "state" : "CA" }
+{ "_id" : "95240", "city" : "LODI", "loc" : [ -121.263034, 38.123579 ], "pop" : 42726, "state" : "CA" }
+{ "_id" : "95242", "city" : "LODI", "loc" : [ -121.311814, 38.132989 ], "pop" : 20669, "state" : "CA" }
+{ "_id" : "95245", "city" : "MOKELUMNE HILL", "loc" : [ -120.567705, 38.328918 ], "pop" : 3507, "state" : "CA" }
+{ "_id" : "95246", "city" : "MOUNTAIN RANCH", "loc" : [ -120.548137, 38.220363 ], "pop" : 2323, "state" : "CA" }
+{ "_id" : "95247", "city" : "MURPHYS", "loc" : [ -120.461772, 38.126896 ], "pop" : 2691, "state" : "CA" }
+{ "_id" : "95249", "city" : "SAN ANDREAS", "loc" : [ -120.668703, 38.186732 ], "pop" : 3081, "state" : "CA" }
+{ "_id" : "95251", "city" : "VALLECITO", "loc" : [ -120.467879, 38.101472 ], "pop" : 200, "state" : "CA" }
+{ "_id" : "95252", "city" : "VALLEY SPRINGS", "loc" : [ -120.859742, 38.154355 ], "pop" : 7592, "state" : "CA" }
+{ "_id" : "95255", "city" : "WEST POINT", "loc" : [ -120.515862, 38.406201 ], "pop" : 1513, "state" : "CA" }
+{ "_id" : "95257", "city" : "WILSEYVILLE", "loc" : [ -120.442356, 38.384566 ], "pop" : 32, "state" : "CA" }
+{ "_id" : "95258", "city" : "WOODBRIDGE", "loc" : [ -121.308632, 38.155124 ], "pop" : 2241, "state" : "CA" }
+{ "_id" : "95301", "city" : "ATWATER", "loc" : [ -120.600837, 37.353154 ], "pop" : 24928, "state" : "CA" }
+{ "_id" : "95303", "city" : "BALLICO", "loc" : [ -120.700152, 37.452455 ], "pop" : 1296, "state" : "CA" }
+{ "_id" : "95306", "city" : "CATHEYS VALLEY", "loc" : [ -120.069017, 37.441409 ], "pop" : 1033, "state" : "CA" }
+{ "_id" : "95307", "city" : "CERES", "loc" : [ -120.949936, 37.588097 ], "pop" : 29037, "state" : "CA" }
+{ "_id" : "95309", "city" : "CHINESE CAMP", "loc" : [ -120.406673, 37.856829 ], "pop" : 15, "state" : "CA" }
+{ "_id" : "95310", "city" : "COLUMBIA", "loc" : [ -120.405552, 38.03975 ], "pop" : 1512, "state" : "CA" }
+{ "_id" : "95311", "city" : "COULTERVILLE", "loc" : [ -119.985813, 37.738642 ], "pop" : 2384, "state" : "CA" }
+{ "_id" : "95313", "city" : "CROWS LANDING", "loc" : [ -121.019893, 37.438956 ], "pop" : 1896, "state" : "CA" }
+{ "_id" : "95315", "city" : "DELHI", "loc" : [ -120.775489, 37.428629 ], "pop" : 6151, "state" : "CA" }
+{ "_id" : "95316", "city" : "DENAIR", "loc" : [ -120.796474, 37.538419 ], "pop" : 5878, "state" : "CA" }
+{ "_id" : "95317", "city" : "EL NIDO", "loc" : [ -120.483235, 37.13452 ], "pop" : 1024, "state" : "CA" }
+{ "_id" : "95320", "city" : "ESCALON", "loc" : [ -120.990044, 37.804428 ], "pop" : 9405, "state" : "CA" }
+{ "_id" : "95321", "city" : "GROVELAND", "loc" : [ -120.191809, 37.840899 ], "pop" : 3616, "state" : "CA" }
+{ "_id" : "95322", "city" : "GUSTINE", "loc" : [ -121.003965, 37.242456 ], "pop" : 6083, "state" : "CA" }
+{ "_id" : "95323", "city" : "HICKMAN", "loc" : [ -120.71722, 37.619989 ], "pop" : 1405, "state" : "CA" }
+{ "_id" : "95324", "city" : "HILMAR", "loc" : [ -120.856144, 37.408377 ], "pop" : 6676, "state" : "CA" }
+{ "_id" : "95325", "city" : "HORNITOS", "loc" : [ -120.226443, 37.492226 ], "pop" : 49, "state" : "CA" }
+{ "_id" : "95326", "city" : "HUGHSON", "loc" : [ -120.865281, 37.594364 ], "pop" : 6383, "state" : "CA" }
+{ "_id" : "95327", "city" : "JAMESTOWN", "loc" : [ -120.494567, 37.906544 ], "pop" : 8359, "state" : "CA" }
+{ "_id" : "95329", "city" : "LA GRANGE", "loc" : [ -120.358131, 37.678915 ], "pop" : 1305, "state" : "CA" }
+{ "_id" : "95330", "city" : "LATHROP", "loc" : [ -121.282652, 37.820897 ], "pop" : 8426, "state" : "CA" }
+{ "_id" : "95333", "city" : "LE GRAND", "loc" : [ -120.251737, 37.234175 ], "pop" : 1810, "state" : "CA" }
+{ "_id" : "95334", "city" : "LIVINGSTON", "loc" : [ -120.716156, 37.376168 ], "pop" : 10994, "state" : "CA" }
+{ "_id" : "95335", "city" : "COLD SPRINGS", "loc" : [ -120.001159, 38.20336 ], "pop" : 201, "state" : "CA" }
+{ "_id" : "95336", "city" : "MANTECA", "loc" : [ -121.21856, 37.80875 ], "pop" : 51728, "state" : "CA" }
+{ "_id" : "95338", "city" : "MARIPOSA", "loc" : [ -119.892496, 37.503918 ], "pop" : 9323, "state" : "CA" }
+{ "_id" : "95340", "city" : "RED TOP", "loc" : [ -120.461668, 37.300724 ], "pop" : 59918, "state" : "CA" }
+{ "_id" : "95345", "city" : "MIDPINES", "loc" : [ -119.946548, 37.571009 ], "pop" : 388, "state" : "CA" }
+{ "_id" : "95346", "city" : "MI WUK VILLAGE", "loc" : [ -120.131762, 38.105576 ], "pop" : 701, "state" : "CA" }
+{ "_id" : "95348", "city" : "MERCED", "loc" : [ -120.500897, 37.326964 ], "pop" : 19719, "state" : "CA" }
+{ "_id" : "95350", "city" : "MODESTO", "loc" : [ -121.011303, 37.674649 ], "pop" : 50618, "state" : "CA" }
+{ "_id" : "95351", "city" : "MODESTO", "loc" : [ -121.006033, 37.625022 ], "pop" : 69275, "state" : "CA" }
+{ "_id" : "95354", "city" : "MODESTO", "loc" : [ -120.968323, 37.644526 ], "pop" : 26630, "state" : "CA" }
+{ "_id" : "95355", "city" : "MODESTO", "loc" : [ -120.954658, 37.673515 ], "pop" : 43734, "state" : "CA" }
+{ "_id" : "95356", "city" : "MODESTO", "loc" : [ -121.027051, 37.699431 ], "pop" : 26202, "state" : "CA" }
+{ "_id" : "95360", "city" : "NEWMAN", "loc" : [ -121.025943, 37.317591 ], "pop" : 5313, "state" : "CA" }
+{ "_id" : "95361", "city" : "KNIGHTS FERRY", "loc" : [ -120.849474, 37.775323 ], "pop" : 20919, "state" : "CA" }
+{ "_id" : "95363", "city" : "PATTERSON", "loc" : [ -121.140732, 37.490592 ], "pop" : 13437, "state" : "CA" }
+{ "_id" : "95364", "city" : "PINECREST", "loc" : [ -119.865195, 38.341062 ], "pop" : 13, "state" : "CA" }
+{ "_id" : "95366", "city" : "RIPON", "loc" : [ -121.122909, 37.753286 ], "pop" : 10879, "state" : "CA" }
+{ "_id" : "95367", "city" : "RIVERBANK", "loc" : [ -120.943019, 37.732809 ], "pop" : 9732, "state" : "CA" }
+{ "_id" : "95368", "city" : "SALIDA", "loc" : [ -121.090484, 37.70713 ], "pop" : 3255, "state" : "CA" }
+{ "_id" : "95369", "city" : "SNELLING", "loc" : [ -120.481615, 37.514359 ], "pop" : 1335, "state" : "CA" }
+{ "_id" : "95370", "city" : "SONORA", "loc" : [ -120.338498, 37.995692 ], "pop" : 23398, "state" : "CA" }
+{ "_id" : "95372", "city" : "SOULSBYVILLE", "loc" : [ -120.259892, 37.992794 ], "pop" : 1566, "state" : "CA" }
+{ "_id" : "95374", "city" : "STEVINSON", "loc" : [ -120.869856, 37.32575 ], "pop" : 1564, "state" : "CA" }
+{ "_id" : "95376", "city" : "TRACY", "loc" : [ -121.419723, 37.742116 ], "pop" : 47291, "state" : "CA" }
+{ "_id" : "95379", "city" : "TUOLUMNE", "loc" : [ -120.237496, 37.971339 ], "pop" : 3402, "state" : "CA" }
+{ "_id" : "95380", "city" : "TURLOCK", "loc" : [ -120.850511, 37.503605 ], "pop" : 50025, "state" : "CA" }
+{ "_id" : "95383", "city" : "TWAIN HARTE", "loc" : [ -120.2155, 38.044722 ], "pop" : 5133, "state" : "CA" }
+{ "_id" : "95386", "city" : "WATERFORD", "loc" : [ -120.753862, 37.650988 ], "pop" : 6505, "state" : "CA" }
+{ "_id" : "95388", "city" : "WINTON", "loc" : [ -120.6132, 37.39233 ], "pop" : 10362, "state" : "CA" }
+{ "_id" : "95401", "city" : "SANTA ROSA", "loc" : [ -122.751722, 38.443123 ], "pop" : 30549, "state" : "CA" }
+{ "_id" : "95403", "city" : "SANTA ROSA", "loc" : [ -122.748528, 38.477273 ], "pop" : 30874, "state" : "CA" }
+{ "_id" : "95404", "city" : "SANTA ROSA", "loc" : [ -122.689524, 38.449556 ], "pop" : 31216, "state" : "CA" }
+{ "_id" : "95405", "city" : "SANTA ROSA", "loc" : [ -122.66988, 38.438279 ], "pop" : 20776, "state" : "CA" }
+{ "_id" : "95407", "city" : "SANTA ROSA", "loc" : [ -122.727896, 38.410462 ], "pop" : 22086, "state" : "CA" }
+{ "_id" : "95409", "city" : "SANTA ROSA", "loc" : [ -122.642125, 38.461242 ], "pop" : 22897, "state" : "CA" }
+{ "_id" : "95410", "city" : "ALBION", "loc" : [ -123.721366, 39.215934 ], "pop" : 869, "state" : "CA" }
+{ "_id" : "95412", "city" : "ANNAPOLIS", "loc" : [ -123.314214, 38.714485 ], "pop" : 24, "state" : "CA" }
+{ "_id" : "95415", "city" : "BOONVILLE", "loc" : [ -123.401954, 39.035007 ], "pop" : 1744, "state" : "CA" }
+{ "_id" : "95417", "city" : "BRANSCOMB", "loc" : [ -123.554982, 39.700531 ], "pop" : 708, "state" : "CA" }
+{ "_id" : "95420", "city" : "CASPAR", "loc" : [ -123.798489, 39.365102 ], "pop" : 349, "state" : "CA" }
+{ "_id" : "95421", "city" : "CAZADERO", "loc" : [ -123.182896, 38.566335 ], "pop" : 2367, "state" : "CA" }
+{ "_id" : "95422", "city" : "CLEARLAKE", "loc" : [ -122.636089, 38.957138 ], "pop" : 12157, "state" : "CA" }
+{ "_id" : "95423", "city" : "CLEARLAKE OAKS", "loc" : [ -122.66873, 39.034838 ], "pop" : 3400, "state" : "CA" }
+{ "_id" : "95425", "city" : "CLOVERDALE", "loc" : [ -123.011725, 38.799396 ], "pop" : 7695, "state" : "CA" }
+{ "_id" : "95427", "city" : "COMPTCHE", "loc" : [ -123.585652, 39.249919 ], "pop" : 538, "state" : "CA" }
+{ "_id" : "95428", "city" : "COVELO", "loc" : [ -123.215015, 39.801864 ], "pop" : 2182, "state" : "CA" }
+{ "_id" : "95429", "city" : "DOS RIOS", "loc" : [ -123.298294, 39.709298 ], "pop" : 14, "state" : "CA" }
+{ "_id" : "95432", "city" : "ELK", "loc" : [ -123.723961, 39.160402 ], "pop" : 199, "state" : "CA" }
+{ "_id" : "95436", "city" : "FORESTVILLE", "loc" : [ -122.896683, 38.489442 ], "pop" : 7252, "state" : "CA" }
+{ "_id" : "95437", "city" : "FORT BRAGG", "loc" : [ -123.78835, 39.437452 ], "pop" : 13535, "state" : "CA" }
+{ "_id" : "95439", "city" : "FULTON", "loc" : [ -122.77608, 38.494732 ], "pop" : 569, "state" : "CA" }
+{ "_id" : "95441", "city" : "GEYSERVILLE", "loc" : [ -122.888921, 38.700398 ], "pop" : 2716, "state" : "CA" }
+{ "_id" : "95442", "city" : "GLEN ELLEN", "loc" : [ -122.521002, 38.362538 ], "pop" : 5055, "state" : "CA" }
+{ "_id" : "95443", "city" : "GLENHAVEN", "loc" : [ -122.522035, 38.99008 ], "pop" : 94, "state" : "CA" }
+{ "_id" : "95444", "city" : "GRATON", "loc" : [ -122.866766, 38.434971 ], "pop" : 259, "state" : "CA" }
+{ "_id" : "95445", "city" : "GUALALA", "loc" : [ -123.553975, 38.803619 ], "pop" : 1806, "state" : "CA" }
+{ "_id" : "95446", "city" : "GUERNEVILLE", "loc" : [ -122.994416, 38.509573 ], "pop" : 5060, "state" : "CA" }
+{ "_id" : "95448", "city" : "HEALDSBURG", "loc" : [ -122.856529, 38.61553 ], "pop" : 16884, "state" : "CA" }
+{ "_id" : "95449", "city" : "HOPLAND", "loc" : [ -123.116956, 38.972056 ], "pop" : 1648, "state" : "CA" }
+{ "_id" : "95450", "city" : "JENNER", "loc" : [ -123.135379, 38.474093 ], "pop" : 156, "state" : "CA" }
+{ "_id" : "95451", "city" : "KELSEYVILLE", "loc" : [ -122.781707, 38.946164 ], "pop" : 10064, "state" : "CA" }
+{ "_id" : "95452", "city" : "KENWOOD", "loc" : [ -122.554679, 38.416794 ], "pop" : 1411, "state" : "CA" }
+{ "_id" : "95453", "city" : "LAKEPORT", "loc" : [ -122.915082, 39.055147 ], "pop" : 10351, "state" : "CA" }
+{ "_id" : "95454", "city" : "LAYTONVILLE", "loc" : [ -123.486862, 39.667811 ], "pop" : 1815, "state" : "CA" }
+{ "_id" : "95456", "city" : "LITTLERIVER", "loc" : [ -123.753089, 39.271042 ], "pop" : 1119, "state" : "CA" }
+{ "_id" : "95457", "city" : "LOWER LAKE", "loc" : [ -122.575426, 38.860682 ], "pop" : 4880, "state" : "CA" }
+{ "_id" : "95458", "city" : "LUCERNE", "loc" : [ -122.785125, 39.083393 ], "pop" : 2330, "state" : "CA" }
+{ "_id" : "95459", "city" : "MANCHESTER", "loc" : [ -123.670962, 38.992088 ], "pop" : 453, "state" : "CA" }
+{ "_id" : "95460", "city" : "MENDOCINO", "loc" : [ -123.78846, 39.323212 ], "pop" : 1876, "state" : "CA" }
+{ "_id" : "95461", "city" : "MIDDLETOWN", "loc" : [ -122.64352, 38.782504 ], "pop" : 2863, "state" : "CA" }
+{ "_id" : "95462", "city" : "RUSSIAN RIVER MD", "loc" : [ -123.00447, 38.462668 ], "pop" : 1999, "state" : "CA" }
+{ "_id" : "95464", "city" : "NICE", "loc" : [ -122.842409, 39.122341 ], "pop" : 2374, "state" : "CA" }
+{ "_id" : "95465", "city" : "OCCIDENTAL", "loc" : [ -122.988194, 38.396911 ], "pop" : 2094, "state" : "CA" }
+{ "_id" : "95466", "city" : "PHILO", "loc" : [ -123.538218, 39.120005 ], "pop" : 498, "state" : "CA" }
+{ "_id" : "95468", "city" : "POINT ARENA", "loc" : [ -123.660756, 38.915264 ], "pop" : 1129, "state" : "CA" }
+{ "_id" : "95469", "city" : "POTTER VALLEY", "loc" : [ -123.104181, 39.329639 ], "pop" : 1970, "state" : "CA" }
+{ "_id" : "95470", "city" : "REDWOOD VALLEY", "loc" : [ -123.213289, 39.269446 ], "pop" : 5328, "state" : "CA" }
+{ "_id" : "95472", "city" : "FREESTONE", "loc" : [ -122.838503, 38.391543 ], "pop" : 27943, "state" : "CA" }
+{ "_id" : "95476", "city" : "SONOMA", "loc" : [ -122.472843, 38.295659 ], "pop" : 30443, "state" : "CA" }
+{ "_id" : "95482", "city" : "UKIAH", "loc" : [ -123.200692, 39.151917 ], "pop" : 28165, "state" : "CA" }
+{ "_id" : "95485", "city" : "UPPER LAKE", "loc" : [ -122.896114, 39.160829 ], "pop" : 1771, "state" : "CA" }
+{ "_id" : "95488", "city" : "WESTPORT", "loc" : [ -123.76426, 39.644059 ], "pop" : 369, "state" : "CA" }
+{ "_id" : "95490", "city" : "WILLITS", "loc" : [ -123.350271, 39.411426 ], "pop" : 12864, "state" : "CA" }
+{ "_id" : "95492", "city" : "WINDSOR", "loc" : [ -122.804375, 38.543182 ], "pop" : 13717, "state" : "CA" }
+{ "_id" : "95493", "city" : "WITTER SPRINGS", "loc" : [ -122.97105, 39.182118 ], "pop" : 300, "state" : "CA" }
+{ "_id" : "95494", "city" : "YORKVILLE", "loc" : [ -123.233867, 38.908945 ], "pop" : 173, "state" : "CA" }
+{ "_id" : "95497", "city" : "THE SEA RANCH", "loc" : [ -123.467486, 38.725627 ], "pop" : 576, "state" : "CA" }
+{ "_id" : "95501", "city" : "EUREKA", "loc" : [ -124.155892, 40.776237 ], "pop" : 45720, "state" : "CA" }
+{ "_id" : "95521", "city" : "MC KINLEYVILLE", "loc" : [ -124.081069, 40.904901 ], "pop" : 32283, "state" : "CA" }
+{ "_id" : "95524", "city" : "BAYSIDE", "loc" : [ -124.027305, 40.822381 ], "pop" : 1744, "state" : "CA" }
+{ "_id" : "95525", "city" : "BLUE LAKE", "loc" : [ -123.896696, 40.928701 ], "pop" : 328, "state" : "CA" }
+{ "_id" : "95526", "city" : "RUTH", "loc" : [ -123.549351, 40.468566 ], "pop" : 1076, "state" : "CA" }
+{ "_id" : "95527", "city" : "BURNT RANCH", "loc" : [ -123.461248, 40.772238 ], "pop" : 478, "state" : "CA" }
+{ "_id" : "95528", "city" : "CARLOTTA", "loc" : [ -123.974287, 40.507027 ], "pop" : 1054, "state" : "CA" }
+{ "_id" : "95531", "city" : "CRESCENT CITY", "loc" : [ -124.178448, 41.785402 ], "pop" : 19400, "state" : "CA" }
+{ "_id" : "95536", "city" : "FERNDALE", "loc" : [ -124.252268, 40.574488 ], "pop" : 2942, "state" : "CA" }
+{ "_id" : "95540", "city" : "FORTUNA", "loc" : [ -124.140654, 40.584931 ], "pop" : 10727, "state" : "CA" }
+{ "_id" : "95543", "city" : "GASQUET", "loc" : [ -123.912467, 41.862768 ], "pop" : 658, "state" : "CA" }
+{ "_id" : "95546", "city" : "HOOPA", "loc" : [ -123.692754, 41.105937 ], "pop" : 2702, "state" : "CA" }
+{ "_id" : "95547", "city" : "HYDESVILLE", "loc" : [ -124.084489, 40.549576 ], "pop" : 919, "state" : "CA" }
+{ "_id" : "95548", "city" : "KLAMATH", "loc" : [ -124.033907, 41.542075 ], "pop" : 1390, "state" : "CA" }
+{ "_id" : "95549", "city" : "KNEELAND", "loc" : [ -123.946421, 40.71262 ], "pop" : 265, "state" : "CA" }
+{ "_id" : "95550", "city" : "KORBEL", "loc" : [ -123.859413, 40.824369 ], "pop" : 187, "state" : "CA" }
+{ "_id" : "95551", "city" : "LOLETA", "loc" : [ -124.228826, 40.6531 ], "pop" : 1244, "state" : "CA" }
+{ "_id" : "95552", "city" : "MAD RIVER", "loc" : [ -123.413994, 40.352352 ], "pop" : 6, "state" : "CA" }
+{ "_id" : "95554", "city" : "MYERS FLAT", "loc" : [ -123.822713, 40.194758 ], "pop" : 3791, "state" : "CA" }
+{ "_id" : "95555", "city" : "ORICK", "loc" : [ -124.050319, 41.30724 ], "pop" : 314, "state" : "CA" }
+{ "_id" : "95556", "city" : "ORLEANS", "loc" : [ -123.529564, 41.318092 ], "pop" : 619, "state" : "CA" }
+{ "_id" : "95558", "city" : "PETROLIA", "loc" : [ -124.251236, 40.300558 ], "pop" : 347, "state" : "CA" }
+{ "_id" : "95560", "city" : "REDWAY", "loc" : [ -123.844194, 40.110081 ], "pop" : 148, "state" : "CA" }
+{ "_id" : "95562", "city" : "RIO DELL", "loc" : [ -124.104386, 40.495147 ], "pop" : 4066, "state" : "CA" }
+{ "_id" : "95563", "city" : "SALYER", "loc" : [ -123.547833, 40.89095 ], "pop" : 903, "state" : "CA" }
+{ "_id" : "95564", "city" : "SAMOA", "loc" : [ -124.193571, 40.803712 ], "pop" : 527, "state" : "CA" }
+{ "_id" : "95565", "city" : "SCOTIA", "loc" : [ -124.039074, 40.454665 ], "pop" : 321, "state" : "CA" }
+{ "_id" : "95567", "city" : "SMITH RIVER", "loc" : [ -124.166115, 41.936218 ], "pop" : 2012, "state" : "CA" }
+{ "_id" : "95568", "city" : "SOMES BAR", "loc" : [ -123.475928, 41.43304 ], "pop" : 195, "state" : "CA" }
+{ "_id" : "95569", "city" : "REDCREST", "loc" : [ -123.94205, 40.406458 ], "pop" : 208, "state" : "CA" }
+{ "_id" : "95570", "city" : "WESTHAVEN", "loc" : [ -124.101253, 41.087949 ], "pop" : 3143, "state" : "CA" }
+{ "_id" : "95573", "city" : "WILLOW CREEK", "loc" : [ -123.631062, 40.938894 ], "pop" : 1503, "state" : "CA" }
+{ "_id" : "95603", "city" : "AUBURN", "loc" : [ -121.084347, 38.928311 ], "pop" : 32535, "state" : "CA" }
+{ "_id" : "95605", "city" : "BRYTE", "loc" : [ -121.526377, 38.592424 ], "pop" : 11611, "state" : "CA" }
+{ "_id" : "95606", "city" : "BROOKS", "loc" : [ -122.133391, 38.739277 ], "pop" : 162, "state" : "CA" }
+{ "_id" : "95607", "city" : "CAPAY", "loc" : [ -122.100993, 38.696964 ], "pop" : 175, "state" : "CA" }
+{ "_id" : "95608", "city" : "CARMICHAEL", "loc" : [ -121.328683, 38.628393 ], "pop" : 55815, "state" : "CA" }
+{ "_id" : "95610", "city" : "CITRUS HEIGHTS", "loc" : [ -121.269211, 38.694571 ], "pop" : 41476, "state" : "CA" }
+{ "_id" : "95612", "city" : "CLARKSBURG", "loc" : [ -121.556853, 38.395963 ], "pop" : 1501, "state" : "CA" }
+{ "_id" : "95614", "city" : "COOL", "loc" : [ -120.972963, 38.903633 ], "pop" : 2325, "state" : "CA" }
+{ "_id" : "95615", "city" : "COURTLAND", "loc" : [ -121.554297, 38.305756 ], "pop" : 958, "state" : "CA" }
+{ "_id" : "95616", "city" : "DAVIS", "loc" : [ -121.748495, 38.554817 ], "pop" : 52224, "state" : "CA" }
+{ "_id" : "95618", "city" : "EL MACERO", "loc" : [ -121.676722, 38.542151 ], "pop" : 1126, "state" : "CA" }
+{ "_id" : "95619", "city" : "DIAMOND SPRINGS", "loc" : [ -120.836071, 38.66302 ], "pop" : 6747, "state" : "CA" }
+{ "_id" : "95620", "city" : "LIBERTY FARMS", "loc" : [ -121.815825, 38.458691 ], "pop" : 14536, "state" : "CA" }
+{ "_id" : "95621", "city" : "CITRUS HEIGHTS", "loc" : [ -121.307501, 38.695155 ], "pop" : 40540, "state" : "CA" }
+{ "_id" : "95624", "city" : "ELK GROVE", "loc" : [ -121.359914, 38.412744 ], "pop" : 23492, "state" : "CA" }
+{ "_id" : "95626", "city" : "ELVERTA", "loc" : [ -121.431038, 38.716424 ], "pop" : 6154, "state" : "CA" }
+{ "_id" : "95627", "city" : "ESPARTO", "loc" : [ -122.021391, 38.694191 ], "pop" : 2118, "state" : "CA" }
+{ "_id" : "95628", "city" : "FAIR OAKS", "loc" : [ -121.261065, 38.655408 ], "pop" : 40502, "state" : "CA" }
+{ "_id" : "95629", "city" : "FIDDLETOWN", "loc" : [ -120.715926, 38.53141 ], "pop" : 1147, "state" : "CA" }
+{ "_id" : "95630", "city" : "EL DORADO HILLS", "loc" : [ -121.140927, 38.687885 ], "pop" : 38587, "state" : "CA" }
+{ "_id" : "95631", "city" : "FORESTHILL", "loc" : [ -120.861127, 39.00229 ], "pop" : 4626, "state" : "CA" }
+{ "_id" : "95632", "city" : "GALT", "loc" : [ -121.29383, 38.269846 ], "pop" : 14173, "state" : "CA" }
+{ "_id" : "95633", "city" : "GARDEN VALLEY", "loc" : [ -120.856672, 38.866495 ], "pop" : 3628, "state" : "CA" }
+{ "_id" : "95634", "city" : "GEORGETOWN", "loc" : [ -120.793388, 38.919892 ], "pop" : 1634, "state" : "CA" }
+{ "_id" : "95635", "city" : "GREENWOOD", "loc" : [ -120.916589, 38.936234 ], "pop" : 226, "state" : "CA" }
+{ "_id" : "95636", "city" : "GRIZZLY FLATS", "loc" : [ -120.542508, 38.628665 ], "pop" : 237, "state" : "CA" }
+{ "_id" : "95637", "city" : "GUINDA", "loc" : [ -122.189659, 38.816568 ], "pop" : 198, "state" : "CA" }
+{ "_id" : "95638", "city" : "HERALD", "loc" : [ -121.158898, 38.31282 ], "pop" : 1009, "state" : "CA" }
+{ "_id" : "95640", "city" : "IONE", "loc" : [ -120.943265, 38.351882 ], "pop" : 8440, "state" : "CA" }
+{ "_id" : "95641", "city" : "ISLETON", "loc" : [ -121.604858, 38.155392 ], "pop" : 2273, "state" : "CA" }
+{ "_id" : "95642", "city" : "JACKSON", "loc" : [ -120.754877, 38.357514 ], "pop" : 5335, "state" : "CA" }
+{ "_id" : "95643", "city" : "KELSEY", "loc" : [ -120.824056, 38.797636 ], "pop" : 531, "state" : "CA" }
+{ "_id" : "95645", "city" : "KNIGHTS LANDING", "loc" : [ -121.720003, 38.822032 ], "pop" : 1907, "state" : "CA" }
+{ "_id" : "95648", "city" : "LINCOLN", "loc" : [ -121.295541, 38.904035 ], "pop" : 11935, "state" : "CA" }
+{ "_id" : "95650", "city" : "LOOMIS", "loc" : [ -121.169826, 38.80711 ], "pop" : 12973, "state" : "CA" }
+{ "_id" : "95651", "city" : "LOTUS", "loc" : [ -120.928864, 38.801712 ], "pop" : 1832, "state" : "CA" }
+{ "_id" : "95652", "city" : "MCCLELLAN AFB", "loc" : [ -121.40311, 38.655416 ], "pop" : 541, "state" : "CA" }
+{ "_id" : "95653", "city" : "MADISON", "loc" : [ -121.972129, 38.680164 ], "pop" : 523, "state" : "CA" }
+{ "_id" : "95655", "city" : "MATHER AFB", "loc" : [ -121.282394, 38.549224 ], "pop" : 4880, "state" : "CA" }
+{ "_id" : "95658", "city" : "NEWCASTLE", "loc" : [ -121.142616, 38.872467 ], "pop" : 5998, "state" : "CA" }
+{ "_id" : "95659", "city" : "TROWBRIDGE", "loc" : [ -121.553043, 38.882726 ], "pop" : 802, "state" : "CA" }
+{ "_id" : "95660", "city" : "NORTH HIGHLANDS", "loc" : [ -121.374913, 38.68855 ], "pop" : 42271, "state" : "CA" }
+{ "_id" : "95661", "city" : "ROSEVILLE", "loc" : [ -121.233968, 38.734612 ], "pop" : 29157, "state" : "CA" }
+{ "_id" : "95662", "city" : "ORANGEVALE", "loc" : [ -121.222902, 38.682384 ], "pop" : 31361, "state" : "CA" }
+{ "_id" : "95663", "city" : "PENRYN", "loc" : [ -121.179149, 38.856654 ], "pop" : 2048, "state" : "CA" }
+{ "_id" : "95664", "city" : "PILOT HILL", "loc" : [ -121.029765, 38.826312 ], "pop" : 1152, "state" : "CA" }
+{ "_id" : "95665", "city" : "PINE GROVE", "loc" : [ -120.643713, 38.396783 ], "pop" : 3066, "state" : "CA" }
+{ "_id" : "95666", "city" : "PIONEER", "loc" : [ -120.531815, 38.460271 ], "pop" : 4797, "state" : "CA" }
+{ "_id" : "95667", "city" : "PLACERVILLE", "loc" : [ -120.804564, 38.719479 ], "pop" : 30563, "state" : "CA" }
+{ "_id" : "95668", "city" : "PLEASANT GROVE", "loc" : [ -121.507967, 38.787773 ], "pop" : 1034, "state" : "CA" }
+{ "_id" : "95669", "city" : "PLYMOUTH", "loc" : [ -120.870258, 38.48811 ], "pop" : 969, "state" : "CA" }
+{ "_id" : "95670", "city" : "GOLD RIVER", "loc" : [ -121.289434, 38.601897 ], "pop" : 42461, "state" : "CA" }
+{ "_id" : "95672", "city" : "RESCUE", "loc" : [ -120.994526, 38.719353 ], "pop" : 2987, "state" : "CA" }
+{ "_id" : "95673", "city" : "RIO LINDA", "loc" : [ -121.445152, 38.689311 ], "pop" : 12756, "state" : "CA" }
+{ "_id" : "95674", "city" : "RIO OSO", "loc" : [ -121.505305, 38.960998 ], "pop" : 1102, "state" : "CA" }
+{ "_id" : "95677", "city" : "ROCKLIN", "loc" : [ -121.243406, 38.791898 ], "pop" : 19125, "state" : "CA" }
+{ "_id" : "95678", "city" : "ROSEVILLE", "loc" : [ -121.302801, 38.750895 ], "pop" : 28285, "state" : "CA" }
+{ "_id" : "95679", "city" : "RUMSEY", "loc" : [ -122.253738, 38.8762 ], "pop" : 228, "state" : "CA" }
+{ "_id" : "95681", "city" : "SHERIDAN", "loc" : [ -121.362062, 38.99153 ], "pop" : 1169, "state" : "CA" }
+{ "_id" : "95682", "city" : "CAMERON PARK", "loc" : [ -120.975925, 38.665616 ], "pop" : 20139, "state" : "CA" }
+{ "_id" : "95683", "city" : "RANCHO MURIETA", "loc" : [ -121.094089, 38.507475 ], "pop" : 3035, "state" : "CA" }
+{ "_id" : "95684", "city" : "SOMERSET", "loc" : [ -120.666306, 38.607414 ], "pop" : 2892, "state" : "CA" }
+{ "_id" : "95685", "city" : "SUTTER CREEK", "loc" : [ -120.785454, 38.418569 ], "pop" : 5677, "state" : "CA" }
+{ "_id" : "95687", "city" : "VACAVILLE", "loc" : [ -121.962285, 38.341915 ], "pop" : 50280, "state" : "CA" }
+{ "_id" : "95688", "city" : "VACAVILLE", "loc" : [ -121.989912, 38.3812 ], "pop" : 29052, "state" : "CA" }
+{ "_id" : "95689", "city" : "VOLCANO", "loc" : [ -120.617761, 38.477319 ], "pop" : 1004, "state" : "CA" }
+{ "_id" : "95690", "city" : "WALNUT GROVE", "loc" : [ -121.524849, 38.236362 ], "pop" : 1839, "state" : "CA" }
+{ "_id" : "95691", "city" : "WEST SACRAMENTO", "loc" : [ -121.539671, 38.567979 ], "pop" : 17301, "state" : "CA" }
+{ "_id" : "95692", "city" : "WHEATLAND", "loc" : [ -121.422126, 39.019197 ], "pop" : 2532, "state" : "CA" }
+{ "_id" : "95693", "city" : "WILTON", "loc" : [ -121.225656, 38.412069 ], "pop" : 4082, "state" : "CA" }
+{ "_id" : "95694", "city" : "WINTERS", "loc" : [ -121.974544, 38.529462 ], "pop" : 6253, "state" : "CA" }
+{ "_id" : "95695", "city" : "WOODLAND", "loc" : [ -121.77932, 38.674294 ], "pop" : 44587, "state" : "CA" }
+{ "_id" : "95698", "city" : "ZAMORA", "loc" : [ -121.90654, 38.799896 ], "pop" : 317, "state" : "CA" }
+{ "_id" : "95701", "city" : "ALTA", "loc" : [ -120.773165, 39.228032 ], "pop" : 751, "state" : "CA" }
+{ "_id" : "95703", "city" : "APPLEGATE", "loc" : [ -120.990511, 38.995487 ], "pop" : 1898, "state" : "CA" }
+{ "_id" : "95709", "city" : "CAMINO", "loc" : [ -120.671979, 38.744938 ], "pop" : 4394, "state" : "CA" }
+{ "_id" : "95713", "city" : "IOWA HILL", "loc" : [ -120.960163, 39.076936 ], "pop" : 7344, "state" : "CA" }
+{ "_id" : "95714", "city" : "DUTCH FLAT", "loc" : [ -120.826224, 39.197788 ], "pop" : 533, "state" : "CA" }
+{ "_id" : "95715", "city" : "EMIGRANT GAP", "loc" : [ -120.662902, 39.286907 ], "pop" : 36, "state" : "CA" }
+{ "_id" : "95717", "city" : "GOLD RUN", "loc" : [ -120.856909, 39.175102 ], "pop" : 79, "state" : "CA" }
+{ "_id" : "95720", "city" : "KYBURZ", "loc" : [ -120.25529, 38.780036 ], "pop" : 159, "state" : "CA" }
+{ "_id" : "95721", "city" : "ECHO LAKE", "loc" : [ -120.070498, 38.810254 ], "pop" : 17, "state" : "CA" }
+{ "_id" : "95722", "city" : "MEADOW VISTA", "loc" : [ -121.029155, 39.003101 ], "pop" : 3314, "state" : "CA" }
+{ "_id" : "95724", "city" : "NORDEN", "loc" : [ -120.400876, 39.319566 ], "pop" : 316, "state" : "CA" }
+{ "_id" : "95726", "city" : "PACIFIC HOUSE", "loc" : [ -120.585114, 38.745581 ], "pop" : 7722, "state" : "CA" }
+{ "_id" : "95728", "city" : "SODA SPRINGS", "loc" : [ -120.465493, 39.338467 ], "pop" : 96, "state" : "CA" }
+{ "_id" : "95735", "city" : "TWIN BRIDGES", "loc" : [ -120.128851, 38.808615 ], "pop" : 0, "state" : "CA" }
+{ "_id" : "95742", "city" : "RANCHO CORDOVA", "loc" : [ -121.204019, 38.604313 ], "pop" : 186, "state" : "CA" }
+{ "_id" : "95758", "city" : "ELK GROVE", "loc" : [ -121.430706, 38.404238 ], "pop" : 13455, "state" : "CA" }
+{ "_id" : "95814", "city" : "SACRAMENTO", "loc" : [ -121.489404, 38.579792 ], "pop" : 16414, "state" : "CA" }
+{ "_id" : "95815", "city" : "SACRAMENTO", "loc" : [ -121.443543, 38.613303 ], "pop" : 23491, "state" : "CA" }
+{ "_id" : "95816", "city" : "SACRAMENTO", "loc" : [ -121.46753, 38.572788 ], "pop" : 16211, "state" : "CA" }
+{ "_id" : "95817", "city" : "SACRAMENTO", "loc" : [ -121.458324, 38.549785 ], "pop" : 15767, "state" : "CA" }
+{ "_id" : "95818", "city" : "SACRAMENTO", "loc" : [ -121.492884, 38.556778 ], "pop" : 22214, "state" : "CA" }
+{ "_id" : "95819", "city" : "SACRAMENTO", "loc" : [ -121.436634, 38.568293 ], "pop" : 18333, "state" : "CA" }
+{ "_id" : "95820", "city" : "SACRAMENTO", "loc" : [ -121.445139, 38.534694 ], "pop" : 35354, "state" : "CA" }
+{ "_id" : "95821", "city" : "SACRAMENTO", "loc" : [ -121.383807, 38.623889 ], "pop" : 33040, "state" : "CA" }
+{ "_id" : "95822", "city" : "SACRAMENTO", "loc" : [ -121.493541, 38.509139 ], "pop" : 43943, "state" : "CA" }
+{ "_id" : "95823", "city" : "SACRAMENTO", "loc" : [ -121.443846, 38.479711 ], "pop" : 55103, "state" : "CA" }
+{ "_id" : "95824", "city" : "SACRAMENTO", "loc" : [ -121.441883, 38.517843 ], "pop" : 26507, "state" : "CA" }
+{ "_id" : "95825", "city" : "SACRAMENTO", "loc" : [ -121.405677, 38.589226 ], "pop" : 27116, "state" : "CA" }
+{ "_id" : "95826", "city" : "SACRAMENTO", "loc" : [ -121.369265, 38.553868 ], "pop" : 38107, "state" : "CA" }
+{ "_id" : "95827", "city" : "SACRAMENTO", "loc" : [ -121.328593, 38.56623 ], "pop" : 19471, "state" : "CA" }
+{ "_id" : "95828", "city" : "SACRAMENTO", "loc" : [ -121.401504, 38.483718 ], "pop" : 43489, "state" : "CA" }
+{ "_id" : "95829", "city" : "SACRAMENTO", "loc" : [ -121.346631, 38.472564 ], "pop" : 4610, "state" : "CA" }
+{ "_id" : "95830", "city" : "SACRAMENTO", "loc" : [ -121.281453, 38.476556 ], "pop" : 420, "state" : "CA" }
+{ "_id" : "95831", "city" : "SACRAMENTO", "loc" : [ -121.529661, 38.496226 ], "pop" : 39369, "state" : "CA" }
+{ "_id" : "95832", "city" : "SACRAMENTO", "loc" : [ -121.482967, 38.475387 ], "pop" : 7724, "state" : "CA" }
+{ "_id" : "95833", "city" : "SACRAMENTO", "loc" : [ -121.494487, 38.616993 ], "pop" : 29150, "state" : "CA" }
+{ "_id" : "95834", "city" : "SACRAMENTO", "loc" : [ -121.492052, 38.633418 ], "pop" : 6375, "state" : "CA" }
+{ "_id" : "95835", "city" : "SACRAMENTO", "loc" : [ -121.483444, 38.662595 ], "pop" : 373, "state" : "CA" }
+{ "_id" : "95836", "city" : "SACRAMENTO", "loc" : [ -121.532259, 38.707346 ], "pop" : 8, "state" : "CA" }
+{ "_id" : "95837", "city" : "SACRAMENTO", "loc" : [ -121.60297, 38.681726 ], "pop" : 259, "state" : "CA" }
+{ "_id" : "95838", "city" : "SACRAMENTO", "loc" : [ -121.44396, 38.640566 ], "pop" : 26996, "state" : "CA" }
+{ "_id" : "95841", "city" : "SACRAMENTO", "loc" : [ -121.340608, 38.662699 ], "pop" : 21161, "state" : "CA" }
+{ "_id" : "95842", "city" : "SACRAMENTO", "loc" : [ -121.35046, 38.687385 ], "pop" : 32169, "state" : "CA" }
+{ "_id" : "95864", "city" : "SACRAMENTO", "loc" : [ -121.376889, 38.587768 ], "pop" : 25105, "state" : "CA" }
+{ "_id" : "95901", "city" : "MARYSVILLE", "loc" : [ -121.522467, 39.141653 ], "pop" : 43785, "state" : "CA" }
+{ "_id" : "95910", "city" : "ALLEGHANY", "loc" : [ -120.727176, 39.512698 ], "pop" : 0, "state" : "CA" }
+{ "_id" : "95912", "city" : "ARBUCKLE", "loc" : [ -122.027405, 39.013787 ], "pop" : 3851, "state" : "CA" }
+{ "_id" : "95914", "city" : "BANGOR", "loc" : [ -121.350499, 39.424862 ], "pop" : 110, "state" : "CA" }
+{ "_id" : "95915", "city" : "BELDEN", "loc" : [ -121.325924, 39.921746 ], "pop" : 32, "state" : "CA" }
+{ "_id" : "95916", "city" : "BERRY CREEK", "loc" : [ -121.385467, 39.638394 ], "pop" : 1285, "state" : "CA" }
+{ "_id" : "95917", "city" : "BIGGS", "loc" : [ -121.695873, 39.414918 ], "pop" : 2784, "state" : "CA" }
+{ "_id" : "95918", "city" : "BROWNS VALLEY", "loc" : [ -121.346482, 39.284428 ], "pop" : 1297, "state" : "CA" }
+{ "_id" : "95919", "city" : "BROWNSVILLE", "loc" : [ -121.261179, 39.452534 ], "pop" : 1013, "state" : "CA" }
+{ "_id" : "95920", "city" : "BUTTE CITY", "loc" : [ -121.978046, 39.456348 ], "pop" : 548, "state" : "CA" }
+{ "_id" : "95922", "city" : "CAMPTONVILLE", "loc" : [ -121.023066, 39.450784 ], "pop" : 1090, "state" : "CA" }
+{ "_id" : "95923", "city" : "CANYONDAM", "loc" : [ -121.156324, 40.207958 ], "pop" : 39, "state" : "CA" }
+{ "_id" : "95926", "city" : "COHASSET", "loc" : [ -121.851806, 39.756466 ], "pop" : 55269, "state" : "CA" }
+{ "_id" : "95928", "city" : "CHICO", "loc" : [ -121.81555, 39.729523 ], "pop" : 27452, "state" : "CA" }
+{ "_id" : "95932", "city" : "COLUSA", "loc" : [ -122.011563, 39.21311 ], "pop" : 7042, "state" : "CA" }
+{ "_id" : "95934", "city" : "CRESCENT MILLS", "loc" : [ -120.881993, 40.081915 ], "pop" : 189, "state" : "CA" }
+{ "_id" : "95935", "city" : "DOBBINS", "loc" : [ -121.234386, 39.371469 ], "pop" : 1502, "state" : "CA" }
+{ "_id" : "95936", "city" : "DOWNIEVILLE", "loc" : [ -120.677767, 39.570265 ], "pop" : 46, "state" : "CA" }
+{ "_id" : "95937", "city" : "DUNNIGAN", "loc" : [ -121.996577, 38.893671 ], "pop" : 850, "state" : "CA" }
+{ "_id" : "95938", "city" : "DURHAM", "loc" : [ -121.791983, 39.641599 ], "pop" : 3327, "state" : "CA" }
+{ "_id" : "95939", "city" : "ELK CREEK", "loc" : [ -122.557244, 39.598914 ], "pop" : 497, "state" : "CA" }
+{ "_id" : "95941", "city" : "FORBESTOWN", "loc" : [ -121.213443, 39.541712 ], "pop" : 517, "state" : "CA" }
+{ "_id" : "95942", "city" : "BUTTE MEADOWS", "loc" : [ -121.500205, 40.129931 ], "pop" : 91, "state" : "CA" }
+{ "_id" : "95943", "city" : "GLENN", "loc" : [ -122.038443, 39.606871 ], "pop" : 1090, "state" : "CA" }
+{ "_id" : "95944", "city" : "GOODYEARS BAR", "loc" : [ -120.820698, 39.572891 ], "pop" : 377, "state" : "CA" }
+{ "_id" : "95945", "city" : "GRASS VALLEY", "loc" : [ -121.037401, 39.207617 ], "pop" : 21263, "state" : "CA" }
+{ "_id" : "95946", "city" : "PENN VALLEY", "loc" : [ -121.193519, 39.218778 ], "pop" : 7603, "state" : "CA" }
+{ "_id" : "95947", "city" : "GREENVILLE", "loc" : [ -120.927299, 40.142404 ], "pop" : 2690, "state" : "CA" }
+{ "_id" : "95948", "city" : "GRIDLEY", "loc" : [ -121.689777, 39.358855 ], "pop" : 9499, "state" : "CA" }
+{ "_id" : "95949", "city" : "GRASS VALLEY", "loc" : [ -121.069357, 39.1029 ], "pop" : 20973, "state" : "CA" }
+{ "_id" : "95953", "city" : "LIVE OAK", "loc" : [ -121.66393, 39.266904 ], "pop" : 6800, "state" : "CA" }
+{ "_id" : "95954", "city" : "MAGALIA", "loc" : [ -121.597455, 39.831728 ], "pop" : 10009, "state" : "CA" }
+{ "_id" : "95955", "city" : "MAXWELL", "loc" : [ -122.195161, 39.292494 ], "pop" : 1410, "state" : "CA" }
+{ "_id" : "95956", "city" : "MEADOW VALLEY", "loc" : [ -121.05629, 39.918488 ], "pop" : 91, "state" : "CA" }
+{ "_id" : "95957", "city" : "MERIDIAN", "loc" : [ -121.88138, 39.116812 ], "pop" : 907, "state" : "CA" }
+{ "_id" : "95959", "city" : "NEVADA CITY", "loc" : [ -121.019634, 39.275395 ], "pop" : 16670, "state" : "CA" }
+{ "_id" : "95960", "city" : "NORTH SAN JUAN", "loc" : [ -121.13498, 39.354037 ], "pop" : 228, "state" : "CA" }
+{ "_id" : "95961", "city" : "OLIVEHURST", "loc" : [ -121.550059, 39.089483 ], "pop" : 6418, "state" : "CA" }
+{ "_id" : "95962", "city" : "OREGON HOUSE", "loc" : [ -121.209229, 39.314388 ], "pop" : 0, "state" : "CA" }
+{ "_id" : "95963", "city" : "ORLAND", "loc" : [ -122.157885, 39.744578 ], "pop" : 14720, "state" : "CA" }
+{ "_id" : "95965", "city" : "PULGA", "loc" : [ -121.578396, 39.532967 ], "pop" : 16712, "state" : "CA" }
+{ "_id" : "95966", "city" : "OROVILLE", "loc" : [ -121.502029, 39.491448 ], "pop" : 27286, "state" : "CA" }
+{ "_id" : "95968", "city" : "PALERMO", "loc" : [ -121.545389, 39.436148 ], "pop" : 1843, "state" : "CA" }
+{ "_id" : "95969", "city" : "PARADISE", "loc" : [ -121.603097, 39.759804 ], "pop" : 26327, "state" : "CA" }
+{ "_id" : "95970", "city" : "PRINCETON", "loc" : [ -122.030181, 39.428313 ], "pop" : 563, "state" : "CA" }
+{ "_id" : "95971", "city" : "QUINCY", "loc" : [ -120.928493, 39.940504 ], "pop" : 6303, "state" : "CA" }
+{ "_id" : "95972", "city" : "RACKERBY", "loc" : [ -121.336192, 39.4059 ], "pop" : 260, "state" : "CA" }
+{ "_id" : "95975", "city" : "ROUGH AND READY", "loc" : [ -121.150856, 39.228585 ], "pop" : 1811, "state" : "CA" }
+{ "_id" : "95977", "city" : "SMARTVILLE", "loc" : [ -121.266716, 39.204305 ], "pop" : 807, "state" : "CA" }
+{ "_id" : "95979", "city" : "STONYFORD", "loc" : [ -122.517811, 39.333652 ], "pop" : 683, "state" : "CA" }
+{ "_id" : "95981", "city" : "LA PORTE", "loc" : [ -121.074566, 39.604136 ], "pop" : 242, "state" : "CA" }
+{ "_id" : "95982", "city" : "SUTTER", "loc" : [ -121.756527, 39.168114 ], "pop" : 3090, "state" : "CA" }
+{ "_id" : "95983", "city" : "TAYLORSVILLE", "loc" : [ -120.801797, 40.064911 ], "pop" : 177, "state" : "CA" }
+{ "_id" : "95984", "city" : "TWAIN", "loc" : [ -121.150729, 40.002769 ], "pop" : 211, "state" : "CA" }
+{ "_id" : "95987", "city" : "WILLIAMS", "loc" : [ -122.162375, 39.148855 ], "pop" : 3094, "state" : "CA" }
+{ "_id" : "95988", "city" : "WILLOWS", "loc" : [ -122.199204, 39.523751 ], "pop" : 8034, "state" : "CA" }
+{ "_id" : "95991", "city" : "YUBA CITY", "loc" : [ -121.621599, 39.128619 ], "pop" : 30201, "state" : "CA" }
+{ "_id" : "95993", "city" : "YUBA CITY", "loc" : [ -121.655168, 39.128193 ], "pop" : 19635, "state" : "CA" }
+{ "_id" : "96001", "city" : "REDDING", "loc" : [ -122.411627, 40.560493 ], "pop" : 30690, "state" : "CA" }
+{ "_id" : "96002", "city" : "REDDING", "loc" : [ -122.333932, 40.548586 ], "pop" : 29008, "state" : "CA" }
+{ "_id" : "96003", "city" : "REDDING", "loc" : [ -122.352962, 40.627751 ], "pop" : 30889, "state" : "CA" }
+{ "_id" : "96006", "city" : "ADIN", "loc" : [ -120.943193, 41.21751 ], "pop" : 355, "state" : "CA" }
+{ "_id" : "96007", "city" : "ANDERSON", "loc" : [ -122.328218, 40.457432 ], "pop" : 20309, "state" : "CA" }
+{ "_id" : "96008", "city" : "BELLA VISTA", "loc" : [ -122.07245, 40.740945 ], "pop" : 1218, "state" : "CA" }
+{ "_id" : "96010", "city" : "BIG BAR", "loc" : [ -123.229006, 40.74796 ], "pop" : 344, "state" : "CA" }
+{ "_id" : "96013", "city" : "BURNEY", "loc" : [ -121.655036, 40.894927 ], "pop" : 4666, "state" : "CA" }
+{ "_id" : "96014", "city" : "CALLAHAN", "loc" : [ -122.764046, 41.383257 ], "pop" : 196, "state" : "CA" }
+{ "_id" : "96015", "city" : "CANBY", "loc" : [ -120.921769, 41.466358 ], "pop" : 424, "state" : "CA" }
+{ "_id" : "96016", "city" : "CASSEL", "loc" : [ -121.524497, 40.907832 ], "pop" : 566, "state" : "CA" }
+{ "_id" : "96019", "city" : "SHASTA LAKE", "loc" : [ -122.365395, 40.680262 ], "pop" : 6405, "state" : "CA" }
+{ "_id" : "96020", "city" : "CHESTER", "loc" : [ -121.227338, 40.297457 ], "pop" : 2361, "state" : "CA" }
+{ "_id" : "96021", "city" : "CORNING", "loc" : [ -122.195991, 39.929566 ], "pop" : 12436, "state" : "CA" }
+{ "_id" : "96022", "city" : "COTTONWOOD", "loc" : [ -122.337463, 40.369072 ], "pop" : 9579, "state" : "CA" }
+{ "_id" : "96024", "city" : "DOUGLAS CITY", "loc" : [ -122.923867, 40.634151 ], "pop" : 727, "state" : "CA" }
+{ "_id" : "96025", "city" : "DUNSMUIR", "loc" : [ -122.273397, 41.212439 ], "pop" : 2683, "state" : "CA" }
+{ "_id" : "96027", "city" : "SAWYERS BAR", "loc" : [ -122.914189, 41.468303 ], "pop" : 2326, "state" : "CA" }
+{ "_id" : "96028", "city" : "FALL RIVER MILLS", "loc" : [ -121.460562, 41.03931 ], "pop" : 1843, "state" : "CA" }
+{ "_id" : "96031", "city" : "FORKS OF SALMON", "loc" : [ -123.09781, 41.256978 ], "pop" : 469, "state" : "CA" }
+{ "_id" : "96032", "city" : "FORT JONES", "loc" : [ -122.883207, 41.617027 ], "pop" : 2363, "state" : "CA" }
+{ "_id" : "96033", "city" : "FRENCH GULCH", "loc" : [ -122.622868, 40.703517 ], "pop" : 640, "state" : "CA" }
+{ "_id" : "96034", "city" : "GAZELLE", "loc" : [ -122.537122, 41.510485 ], "pop" : 162, "state" : "CA" }
+{ "_id" : "96035", "city" : "GERBER", "loc" : [ -122.164937, 40.042997 ], "pop" : 3337, "state" : "CA" }
+{ "_id" : "96038", "city" : "GRENADA", "loc" : [ -122.525829, 41.612512 ], "pop" : 703, "state" : "CA" }
+{ "_id" : "96039", "city" : "HAPPY CAMP", "loc" : [ -123.388045, 41.801802 ], "pop" : 1885, "state" : "CA" }
+{ "_id" : "96040", "city" : "HAT CREEK", "loc" : [ -121.463687, 40.767673 ], "pop" : 150, "state" : "CA" }
+{ "_id" : "96041", "city" : "HAYFORK", "loc" : [ -123.163416, 40.550431 ], "pop" : 2671, "state" : "CA" }
+{ "_id" : "96044", "city" : "HORNBROOK", "loc" : [ -122.526528, 41.907738 ], "pop" : 905, "state" : "CA" }
+{ "_id" : "96045", "city" : "HORSE CREEK", "loc" : [ -123.013919, 41.833732 ], "pop" : 379, "state" : "CA" }
+{ "_id" : "96047", "city" : "IGO", "loc" : [ -122.654023, 40.431795 ], "pop" : 205, "state" : "CA" }
+{ "_id" : "96048", "city" : "HELENA", "loc" : [ -123.062671, 40.768187 ], "pop" : 606, "state" : "CA" }
+{ "_id" : "96050", "city" : "KLAMATH RIVER", "loc" : [ -122.819693, 41.863699 ], "pop" : 174, "state" : "CA" }
+{ "_id" : "96051", "city" : "LAKEHEAD", "loc" : [ -122.359281, 40.958775 ], "pop" : 1709, "state" : "CA" }
+{ "_id" : "96052", "city" : "LEWISTON", "loc" : [ -122.842591, 40.745986 ], "pop" : 2461, "state" : "CA" }
+{ "_id" : "96055", "city" : "LOS MOLINOS", "loc" : [ -122.099175, 40.049735 ], "pop" : 3363, "state" : "CA" }
+{ "_id" : "96056", "city" : "MCARTHUR", "loc" : [ -121.214896, 41.111407 ], "pop" : 2797, "state" : "CA" }
+{ "_id" : "96057", "city" : "MCCLOUD", "loc" : [ -122.13562, 41.252108 ], "pop" : 1743, "state" : "CA" }
+{ "_id" : "96058", "city" : "MACDOEL", "loc" : [ -121.944472, 41.883028 ], "pop" : 1945, "state" : "CA" }
+{ "_id" : "96059", "city" : "MANTON", "loc" : [ -121.836521, 40.433125 ], "pop" : 344, "state" : "CA" }
+{ "_id" : "96062", "city" : "MILLVILLE", "loc" : [ -122.111088, 40.565316 ], "pop" : 1281, "state" : "CA" }
+{ "_id" : "96063", "city" : "MINERAL", "loc" : [ -121.524807, 40.328826 ], "pop" : 172, "state" : "CA" }
+{ "_id" : "96064", "city" : "MONTAGUE", "loc" : [ -122.463799, 41.724294 ], "pop" : 4246, "state" : "CA" }
+{ "_id" : "96065", "city" : "MONTGOMERY CREEK", "loc" : [ -121.923313, 40.912378 ], "pop" : 823, "state" : "CA" }
+{ "_id" : "96067", "city" : "MOUNT SHASTA", "loc" : [ -122.324017, 41.317435 ], "pop" : 6719, "state" : "CA" }
+{ "_id" : "96069", "city" : "OAK RUN", "loc" : [ -122.040932, 40.68631 ], "pop" : 1160, "state" : "CA" }
+{ "_id" : "96071", "city" : "OLD STATION", "loc" : [ -121.458476, 40.62557 ], "pop" : 213, "state" : "CA" }
+{ "_id" : "96073", "city" : "PALO CEDRO", "loc" : [ -122.239805, 40.576661 ], "pop" : 3905, "state" : "CA" }
+{ "_id" : "96075", "city" : "PAYNES CREEK", "loc" : [ -121.764952, 40.351415 ], "pop" : 773, "state" : "CA" }
+{ "_id" : "96076", "city" : "WILDWOOD", "loc" : [ -122.918013, 40.316528 ], "pop" : 119, "state" : "CA" }
+{ "_id" : "96080", "city" : "RED BLUFF", "loc" : [ -122.238281, 40.179535 ], "pop" : 25180, "state" : "CA" }
+{ "_id" : "96085", "city" : "SCOTT BAR", "loc" : [ -122.988183, 41.77364 ], "pop" : 21, "state" : "CA" }
+{ "_id" : "96086", "city" : "SEIAD VALLEY", "loc" : [ -123.243762, 41.886589 ], "pop" : 311, "state" : "CA" }
+{ "_id" : "96087", "city" : "SHASTA", "loc" : [ -122.49685, 40.610896 ], "pop" : 294, "state" : "CA" }
+{ "_id" : "96088", "city" : "SHINGLETOWN", "loc" : [ -121.885668, 40.504959 ], "pop" : 3681, "state" : "CA" }
+{ "_id" : "96091", "city" : "TRINITY CENTER", "loc" : [ -122.723919, 41.061548 ], "pop" : 362, "state" : "CA" }
+{ "_id" : "96093", "city" : "WEAVERVILLE", "loc" : [ -122.935303, 40.731701 ], "pop" : 3188, "state" : "CA" }
+{ "_id" : "96094", "city" : "EDGEWOOD", "loc" : [ -122.384803, 41.439466 ], "pop" : 5506, "state" : "CA" }
+{ "_id" : "96096", "city" : "WHITMORE", "loc" : [ -121.877076, 40.65255 ], "pop" : 593, "state" : "CA" }
+{ "_id" : "96097", "city" : "YREKA", "loc" : [ -122.637604, 41.720558 ], "pop" : 9151, "state" : "CA" }
+{ "_id" : "96101", "city" : "ALTURAS", "loc" : [ -120.545584, 41.476742 ], "pop" : 5566, "state" : "CA" }
+{ "_id" : "96103", "city" : "CROMBERG", "loc" : [ -120.627397, 39.784745 ], "pop" : 1774, "state" : "CA" }
+{ "_id" : "96104", "city" : "CEDARVILLE", "loc" : [ -120.151551, 41.475871 ], "pop" : 991, "state" : "CA" }
+{ "_id" : "96105", "city" : "CHILCOOT", "loc" : [ -120.175212, 39.805683 ], "pop" : 470, "state" : "CA" }
+{ "_id" : "96106", "city" : "CLIO", "loc" : [ -120.560458, 39.74326 ], "pop" : 84, "state" : "CA" }
+{ "_id" : "96107", "city" : "COLEVILLE", "loc" : [ -119.482784, 38.502903 ], "pop" : 1370, "state" : "CA" }
+{ "_id" : "96108", "city" : "DAVIS CREEK", "loc" : [ -120.323549, 41.862555 ], "pop" : 285, "state" : "CA" }
+{ "_id" : "96109", "city" : "DOYLE", "loc" : [ -120.107693, 40.000799 ], "pop" : 985, "state" : "CA" }
+{ "_id" : "96111", "city" : "FLORISTON", "loc" : [ -120.025421, 39.445746 ], "pop" : 169, "state" : "CA" }
+{ "_id" : "96112", "city" : "FORT BIDWELL", "loc" : [ -120.161983, 41.864441 ], "pop" : 226, "state" : "CA" }
+{ "_id" : "96113", "city" : "HERLONG", "loc" : [ -120.171271, 40.148492 ], "pop" : 1518, "state" : "CA" }
+{ "_id" : "96114", "city" : "JANESVILLE", "loc" : [ -120.50982, 40.296325 ], "pop" : 2655, "state" : "CA" }
+{ "_id" : "96115", "city" : "LAKE CITY", "loc" : [ -120.181424, 41.668208 ], "pop" : 234, "state" : "CA" }
+{ "_id" : "96117", "city" : "LITCHFIELD", "loc" : [ -120.253975, 40.362788 ], "pop" : 23, "state" : "CA" }
+{ "_id" : "96118", "city" : "LOYALTON", "loc" : [ -120.229662, 39.662974 ], "pop" : 1500, "state" : "CA" }
+{ "_id" : "96120", "city" : "HOPE VALLEY", "loc" : [ -119.807275, 38.76473 ], "pop" : 850, "state" : "CA" }
+{ "_id" : "96121", "city" : "MILFORD", "loc" : [ -120.389508, 40.182763 ], "pop" : 376, "state" : "CA" }
+{ "_id" : "96122", "city" : "PORTOLA", "loc" : [ -120.466858, 39.810883 ], "pop" : 3685, "state" : "CA" }
+{ "_id" : "96123", "city" : "RAVENDALE", "loc" : [ -120.16001, 40.831705 ], "pop" : 89, "state" : "CA" }
+{ "_id" : "96124", "city" : "CALPINE", "loc" : [ -120.4442, 39.651699 ], "pop" : 286, "state" : "CA" }
+{ "_id" : "96125", "city" : "SIERRA CITY", "loc" : [ -120.624135, 39.559248 ], "pop" : 311, "state" : "CA" }
+{ "_id" : "96126", "city" : "SIERRAVILLE", "loc" : [ -120.347789, 39.594294 ], "pop" : 355, "state" : "CA" }
+{ "_id" : "96128", "city" : "STANDISH", "loc" : [ -120.406847, 40.350863 ], "pop" : 340, "state" : "CA" }
+{ "_id" : "96130", "city" : "SUSANVILLE", "loc" : [ -120.646442, 40.398282 ], "pop" : 19347, "state" : "CA" }
+{ "_id" : "96132", "city" : "TERMO", "loc" : [ -120.517378, 40.946667 ], "pop" : 199, "state" : "CA" }
+{ "_id" : "96133", "city" : "TOPAZ", "loc" : [ -119.512164, 38.64151 ], "pop" : 87, "state" : "CA" }
+{ "_id" : "96134", "city" : "TULELAKE", "loc" : [ -121.434688, 41.931621 ], "pop" : 2613, "state" : "CA" }
+{ "_id" : "96135", "city" : "VINTON", "loc" : [ -120.204994, 39.720719 ], "pop" : 0, "state" : "CA" }
+{ "_id" : "96136", "city" : "WENDEL", "loc" : [ -120.352156, 40.346233 ], "pop" : 148, "state" : "CA" }
+{ "_id" : "96137", "city" : "PENINSULA VILLAG", "loc" : [ -121.109224, 40.270359 ], "pop" : 1843, "state" : "CA" }
+{ "_id" : "96140", "city" : "CARNELIAN BAY", "loc" : [ -120.075328, 39.231937 ], "pop" : 620, "state" : "CA" }
+{ "_id" : "96141", "city" : "HOMEWOOD", "loc" : [ -120.179035, 39.078157 ], "pop" : 283, "state" : "CA" }
+{ "_id" : "96142", "city" : "TAHOMA", "loc" : [ -120.135747, 39.064406 ], "pop" : 1029, "state" : "CA" }
+{ "_id" : "96143", "city" : "KINGS BEACH", "loc" : [ -120.023287, 39.240119 ], "pop" : 3247, "state" : "CA" }
+{ "_id" : "96145", "city" : "TAHOE CITY", "loc" : [ -120.144532, 39.180618 ], "pop" : 4944, "state" : "CA" }
+{ "_id" : "96148", "city" : "TAHOE VISTA", "loc" : [ -120.052128, 39.24475 ], "pop" : 717, "state" : "CA" }
+{ "_id" : "96150", "city" : "SOUTH LAKE TAHOE", "loc" : [ -119.986469, 38.916976 ], "pop" : 28975, "state" : "CA" }
+{ "_id" : "96161", "city" : "TRUCKEE", "loc" : [ -120.172942, 39.338546 ], "pop" : 9544, "state" : "CA" }
+{ "_id" : "96162", "city" : "TRUCKEE", "loc" : [ -120.295031, 39.319321 ], "pop" : 199, "state" : "CA" }
+{ "_id" : "96701", "city" : "AIEA", "loc" : [ -157.933237, 21.390795 ], "pop" : 43273, "state" : "HI" }
+{ "_id" : "96704", "city" : "CAPTAIN COOK", "loc" : [ -155.887463, 19.438604 ], "pop" : 5338, "state" : "HI" }
+{ "_id" : "96705", "city" : "ELEELE", "loc" : [ -159.538115, 21.923017 ], "pop" : 6466, "state" : "HI" }
+{ "_id" : "96706", "city" : "EWA BEACH", "loc" : [ -158.010307, 21.327418 ], "pop" : 26089, "state" : "HI" }
+{ "_id" : "96707", "city" : "KAPOLEI", "loc" : [ -158.087007, 21.345284 ], "pop" : 15891, "state" : "HI" }
+{ "_id" : "96708", "city" : "HAIKU", "loc" : [ -156.299983, 20.907097 ], "pop" : 5695, "state" : "HI" }
+{ "_id" : "96710", "city" : "HAKALAU", "loc" : [ -155.133335, 19.888217 ], "pop" : 198, "state" : "HI" }
+{ "_id" : "96712", "city" : "HALEIWA", "loc" : [ -158.069315, 21.631151 ], "pop" : 7870, "state" : "HI" }
+{ "_id" : "96713", "city" : "HANA", "loc" : [ -156.039659, 20.761635 ], "pop" : 1895, "state" : "HI" }
+{ "_id" : "96716", "city" : "HANAPEPE", "loc" : [ -159.592022, 21.915644 ], "pop" : 1523, "state" : "HI" }
+{ "_id" : "96717", "city" : "HAUULA", "loc" : [ -157.915704, 21.61395 ], "pop" : 3477, "state" : "HI" }
+{ "_id" : "96718", "city" : "HAWAII NATIONAL", "loc" : [ -155.284015, 19.431103 ], "pop" : 91, "state" : "HI" }
+{ "_id" : "96719", "city" : "HAWI", "loc" : [ -155.838007, 20.238021 ], "pop" : 1741, "state" : "HI" }
+{ "_id" : "96720", "city" : "HILO", "loc" : [ -155.093921, 19.702522 ], "pop" : 40158, "state" : "HI" }
+{ "_id" : "96722", "city" : "PRINCEVILLE", "loc" : [ -159.462587, 22.215948 ], "pop" : 4631, "state" : "HI" }
+{ "_id" : "96725", "city" : "HOLUALOA", "loc" : [ -155.917639, 19.610316 ], "pop" : 2096, "state" : "HI" }
+{ "_id" : "96726", "city" : "HONAUNAU", "loc" : [ -155.893356, 19.44845 ], "pop" : 1583, "state" : "HI" }
+{ "_id" : "96727", "city" : "HONOKAA", "loc" : [ -155.488026, 20.08266 ], "pop" : 3681, "state" : "HI" }
+{ "_id" : "96728", "city" : "HONOMU", "loc" : [ -155.11766, 19.872767 ], "pop" : 548, "state" : "HI" }
+{ "_id" : "96729", "city" : "HOOLEHUA", "loc" : [ -157.079138, 21.173025 ], "pop" : 853, "state" : "HI" }
+{ "_id" : "96730", "city" : "KAAAWA", "loc" : [ -157.873734, 21.56737 ], "pop" : 2305, "state" : "HI" }
+{ "_id" : "96732", "city" : "KAHULUI", "loc" : [ -156.478327, 20.881388 ], "pop" : 17289, "state" : "HI" }
+{ "_id" : "96734", "city" : "KAILUA", "loc" : [ -157.744781, 21.406262 ], "pop" : 53403, "state" : "HI" }
+{ "_id" : "96740", "city" : "KAILUA KONA", "loc" : [ -155.979809, 19.653053 ], "pop" : 19616, "state" : "HI" }
+{ "_id" : "96742", "city" : "KALAUPAPA", "loc" : [ -156.983453, 21.19289 ], "pop" : 130, "state" : "HI" }
+{ "_id" : "96743", "city" : "KAMUELA", "loc" : [ -155.705189, 20.008128 ], "pop" : 9140, "state" : "HI" }
+{ "_id" : "96744", "city" : "KANEOHE", "loc" : [ -157.811543, 21.422819 ], "pop" : 55236, "state" : "HI" }
+{ "_id" : "96746", "city" : "KAPAA", "loc" : [ -159.344842, 22.086798 ], "pop" : 15627, "state" : "HI" }
+{ "_id" : "96747", "city" : "KAUMAKANI", "loc" : [ -159.62413, 21.921329 ], "pop" : 819, "state" : "HI" }
+{ "_id" : "96748", "city" : "KAUNAKAKAI", "loc" : [ -156.969015, 21.090504 ], "pop" : 4419, "state" : "HI" }
+{ "_id" : "96749", "city" : "KEAAU", "loc" : [ -154.992644, 19.589277 ], "pop" : 4297, "state" : "HI" }
+{ "_id" : "96750", "city" : "KEALAKEKUA", "loc" : [ -155.930025, 19.526149 ], "pop" : 1309, "state" : "HI" }
+{ "_id" : "96752", "city" : "KEKAHA", "loc" : [ -159.71988, 21.973509 ], "pop" : 3785, "state" : "HI" }
+{ "_id" : "96753", "city" : "KIHEI", "loc" : [ -156.447543, 20.744124 ], "pop" : 14759, "state" : "HI" }
+{ "_id" : "96755", "city" : "KAPAAU", "loc" : [ -155.798981, 20.218323 ], "pop" : 2550, "state" : "HI" }
+{ "_id" : "96756", "city" : "KOLOA", "loc" : [ -159.474927, 21.908293 ], "pop" : 4906, "state" : "HI" }
+{ "_id" : "96757", "city" : "KUALAPUU", "loc" : [ -157.027669, 21.160097 ], "pop" : 818, "state" : "HI" }
+{ "_id" : "96760", "city" : "KURTISTOWN", "loc" : [ -155.020659, 19.570637 ], "pop" : 3975, "state" : "HI" }
+{ "_id" : "96761", "city" : "LAHAINA", "loc" : [ -156.677162, 20.917432 ], "pop" : 14508, "state" : "HI" }
+{ "_id" : "96762", "city" : "LAIE", "loc" : [ -157.939377, 21.659513 ], "pop" : 8481, "state" : "HI" }
+{ "_id" : "96763", "city" : "LANAI CITY", "loc" : [ -156.921027, 20.829323 ], "pop" : 2426, "state" : "HI" }
+{ "_id" : "96764", "city" : "LAUPAHOEHOE", "loc" : [ -155.232263, 19.980194 ], "pop" : 1015, "state" : "HI" }
+{ "_id" : "96766", "city" : "LIHUE", "loc" : [ -159.368258, 21.981618 ], "pop" : 10663, "state" : "HI" }
+{ "_id" : "96768", "city" : "MAKAWAO", "loc" : [ -156.332735, 20.846932 ], "pop" : 13389, "state" : "HI" }
+{ "_id" : "96769", "city" : "MAKAWELI", "loc" : [ -159.790721, 21.927639 ], "pop" : 797, "state" : "HI" }
+{ "_id" : "96770", "city" : "MAUNALOA", "loc" : [ -157.219277, 21.142202 ], "pop" : 497, "state" : "HI" }
+{ "_id" : "96771", "city" : "MOUNTAIN VIEW", "loc" : [ -155.086436, 19.550587 ], "pop" : 3170, "state" : "HI" }
+{ "_id" : "96772", "city" : "NAALEHU", "loc" : [ -155.657474, 19.066844 ], "pop" : 2729, "state" : "HI" }
+{ "_id" : "96773", "city" : "NINOLE", "loc" : [ -155.159923, 19.904436 ], "pop" : 0, "state" : "HI" }
+{ "_id" : "96774", "city" : "OOKALA", "loc" : [ -155.274666, 20.011887 ], "pop" : 315, "state" : "HI" }
+{ "_id" : "96775", "city" : "PAAUHAU", "loc" : [ -155.449088, 20.027748 ], "pop" : 917, "state" : "HI" }
+{ "_id" : "96776", "city" : "PAAUILO", "loc" : [ -155.369728, 20.027119 ], "pop" : 947, "state" : "HI" }
+{ "_id" : "96777", "city" : "PAHALA", "loc" : [ -155.481506, 19.207898 ], "pop" : 1616, "state" : "HI" }
+{ "_id" : "96778", "city" : "PAHOA", "loc" : [ -154.923135, 19.508901 ], "pop" : 6702, "state" : "HI" }
+{ "_id" : "96779", "city" : "PAIA", "loc" : [ -156.38017, 20.91539 ], "pop" : 2311, "state" : "HI" }
+{ "_id" : "96780", "city" : "PAPAALOA", "loc" : [ -155.218402, 19.904835 ], "pop" : 208, "state" : "HI" }
+{ "_id" : "96781", "city" : "PAPAIKOU", "loc" : [ -155.098442, 19.791643 ], "pop" : 1700, "state" : "HI" }
+{ "_id" : "96782", "city" : "PEARL CITY", "loc" : [ -157.965164, 21.408393 ], "pop" : 38207, "state" : "HI" }
+{ "_id" : "96783", "city" : "PEPEEKEO", "loc" : [ -155.112994, 19.835283 ], "pop" : 2038, "state" : "HI" }
+{ "_id" : "96785", "city" : "VOLCANO", "loc" : [ -155.19743, 19.480066 ], "pop" : 2639, "state" : "HI" }
+{ "_id" : "96786", "city" : "WAHIAWA", "loc" : [ -158.043527, 21.500596 ], "pop" : 43663, "state" : "HI" }
+{ "_id" : "96789", "city" : "MILILANI", "loc" : [ -158.017379, 21.45311 ], "pop" : 34734, "state" : "HI" }
+{ "_id" : "96790", "city" : "KULA", "loc" : [ -156.326026, 20.753353 ], "pop" : 5697, "state" : "HI" }
+{ "_id" : "96791", "city" : "WAIALUA", "loc" : [ -158.126673, 21.576623 ], "pop" : 7975, "state" : "HI" }
+{ "_id" : "96792", "city" : "WAIANAE", "loc" : [ -158.178071, 21.435192 ], "pop" : 37518, "state" : "HI" }
+{ "_id" : "96793", "city" : "WAILUKU", "loc" : [ -156.503612, 20.896586 ], "pop" : 15818, "state" : "HI" }
+{ "_id" : "96795", "city" : "WAIMANALO", "loc" : [ -157.713094, 21.341786 ], "pop" : 9055, "state" : "HI" }
+{ "_id" : "96796", "city" : "WAIMEA", "loc" : [ -159.669429, 21.968487 ], "pop" : 1960, "state" : "HI" }
+{ "_id" : "96797", "city" : "WAIPAHU", "loc" : [ -158.012418, 21.398203 ], "pop" : 52411, "state" : "HI" }
+{ "_id" : "96813", "city" : "HONOLULU", "loc" : [ -157.852072, 21.317905 ], "pop" : 23082, "state" : "HI" }
+{ "_id" : "96814", "city" : "HONOLULU", "loc" : [ -157.843876, 21.299846 ], "pop" : 14182, "state" : "HI" }
+{ "_id" : "96815", "city" : "HONOLULU", "loc" : [ -157.826616, 21.281084 ], "pop" : 28650, "state" : "HI" }
+{ "_id" : "96816", "city" : "HONOLULU", "loc" : [ -157.800626, 21.288677 ], "pop" : 49208, "state" : "HI" }
+{ "_id" : "96817", "city" : "HONOLULU", "loc" : [ -157.861469, 21.329452 ], "pop" : 48920, "state" : "HI" }
+{ "_id" : "96818", "city" : "HONOLULU", "loc" : [ -157.926925, 21.353173 ], "pop" : 62915, "state" : "HI" }
+{ "_id" : "96819", "city" : "HONOLULU", "loc" : [ -157.875947, 21.34877 ], "pop" : 50584, "state" : "HI" }
+{ "_id" : "96821", "city" : "HONOLULU", "loc" : [ -157.755242, 21.292811 ], "pop" : 18366, "state" : "HI" }
+{ "_id" : "96822", "city" : "HONOLULU", "loc" : [ -157.829819, 21.311704 ], "pop" : 39632, "state" : "HI" }
+{ "_id" : "96825", "city" : "HONOLULU", "loc" : [ -157.698523, 21.298684 ], "pop" : 27432, "state" : "HI" }
+{ "_id" : "96826", "city" : "HONOLULU", "loc" : [ -157.828388, 21.294139 ], "pop" : 33672, "state" : "HI" }
+{ "_id" : "97001", "city" : "ANTELOPE", "loc" : [ -120.791384, 44.889196 ], "pop" : 129, "state" : "OR" }
+{ "_id" : "97002", "city" : "AURORA", "loc" : [ -122.803881, 45.228432 ], "pop" : 4638, "state" : "OR" }
+{ "_id" : "97004", "city" : "BEAVERCREEK", "loc" : [ -122.475122, 45.259723 ], "pop" : 4253, "state" : "OR" }
+{ "_id" : "97005", "city" : "BEAVERTON", "loc" : [ -122.805395, 45.475035 ], "pop" : 46660, "state" : "OR" }
+{ "_id" : "97006", "city" : "ALOHA", "loc" : [ -122.859209, 45.517675 ], "pop" : 31650, "state" : "OR" }
+{ "_id" : "97007", "city" : "ALOHA", "loc" : [ -122.859473, 45.472985 ], "pop" : 35583, "state" : "OR" }
+{ "_id" : "97009", "city" : "BORING", "loc" : [ -122.380713, 45.429704 ], "pop" : 11406, "state" : "OR" }
+{ "_id" : "97010", "city" : "BRIDAL VEIL", "loc" : [ -122.176587, 45.557904 ], "pop" : 8, "state" : "OR" }
+{ "_id" : "97011", "city" : "BRIGHTWOOD", "loc" : [ -122.003621, 45.365218 ], "pop" : 788, "state" : "OR" }
+{ "_id" : "97013", "city" : "CANBY", "loc" : [ -122.68322, 45.251425 ], "pop" : 15801, "state" : "OR" }
+{ "_id" : "97014", "city" : "BONNEVILLE", "loc" : [ -121.882411, 45.671447 ], "pop" : 951, "state" : "OR" }
+{ "_id" : "97015", "city" : "CLACKAMAS", "loc" : [ -122.52005, 45.414992 ], "pop" : 12352, "state" : "OR" }
+{ "_id" : "97016", "city" : "WESTPORT", "loc" : [ -123.2124, 46.09978 ], "pop" : 6361, "state" : "OR" }
+{ "_id" : "97017", "city" : "COLTON", "loc" : [ -122.424753, 45.157291 ], "pop" : 4223, "state" : "OR" }
+{ "_id" : "97018", "city" : "COLUMBIA CITY", "loc" : [ -122.812174, 45.892474 ], "pop" : 1003, "state" : "OR" }
+{ "_id" : "97019", "city" : "CORBETT", "loc" : [ -122.241746, 45.522116 ], "pop" : 2355, "state" : "OR" }
+{ "_id" : "97021", "city" : "FRIEND", "loc" : [ -121.146797, 45.429099 ], "pop" : 1111, "state" : "OR" }
+{ "_id" : "97022", "city" : "EAGLE CREEK", "loc" : [ -122.338053, 45.358205 ], "pop" : 3285, "state" : "OR" }
+{ "_id" : "97023", "city" : "ESTACADA", "loc" : [ -122.325858, 45.287177 ], "pop" : 8703, "state" : "OR" }
+{ "_id" : "97026", "city" : "GERVAIS", "loc" : [ -122.896185, 45.108645 ], "pop" : 992, "state" : "OR" }
+{ "_id" : "97027", "city" : "GLADSTONE", "loc" : [ -122.590197, 45.389882 ], "pop" : 10148, "state" : "OR" }
+{ "_id" : "97028", "city" : "TIMBERLINE LODGE", "loc" : [ -121.785426, 45.318366 ], "pop" : 268, "state" : "OR" }
+{ "_id" : "97029", "city" : "GRASS VALLEY", "loc" : [ -120.747795, 45.301333 ], "pop" : 415, "state" : "OR" }
+{ "_id" : "97030", "city" : "GRESHAM", "loc" : [ -122.420258, 45.515397 ], "pop" : 35728, "state" : "OR" }
+{ "_id" : "97031", "city" : "HOOD RIVER", "loc" : [ -121.539104, 45.671058 ], "pop" : 13718, "state" : "OR" }
+{ "_id" : "97032", "city" : "HUBBARD", "loc" : [ -122.754115, 45.160422 ], "pop" : 6393, "state" : "OR" }
+{ "_id" : "97033", "city" : "KENT", "loc" : [ -120.664895, 45.083789 ], "pop" : 0, "state" : "OR" }
+{ "_id" : "97034", "city" : "LAKE OSWEGO", "loc" : [ -122.684721, 45.409263 ], "pop" : 18063, "state" : "OR" }
+{ "_id" : "97035", "city" : "LAKE OSWEGO", "loc" : [ -122.722709, 45.414666 ], "pop" : 19305, "state" : "OR" }
+{ "_id" : "97037", "city" : "MAUPIN", "loc" : [ -121.228164, 45.074247 ], "pop" : 1758, "state" : "OR" }
+{ "_id" : "97038", "city" : "MOLALLA", "loc" : [ -122.575574, 45.122256 ], "pop" : 7829, "state" : "OR" }
+{ "_id" : "97039", "city" : "MORO", "loc" : [ -120.695666, 45.485332 ], "pop" : 550, "state" : "OR" }
+{ "_id" : "97040", "city" : "MOSIER", "loc" : [ -121.324532, 45.66167 ], "pop" : 1573, "state" : "OR" }
+{ "_id" : "97041", "city" : "MOUNT HOOD PARKD", "loc" : [ -121.588485, 45.521584 ], "pop" : 2236, "state" : "OR" }
+{ "_id" : "97042", "city" : "MULINO", "loc" : [ -122.535068, 45.212973 ], "pop" : 2935, "state" : "OR" }
+{ "_id" : "97044", "city" : "ODELL", "loc" : [ -121.440131, 45.623245 ], "pop" : 0, "state" : "OR" }
+{ "_id" : "97045", "city" : "OREGON CITY", "loc" : [ -122.569991, 45.337718 ], "pop" : 36753, "state" : "OR" }
+{ "_id" : "97048", "city" : "RAINIER", "loc" : [ -122.967067, 46.064552 ], "pop" : 6357, "state" : "OR" }
+{ "_id" : "97049", "city" : "ZIGZAG", "loc" : [ -121.953691, 45.355201 ], "pop" : 1325, "state" : "OR" }
+{ "_id" : "97050", "city" : "RUFUS", "loc" : [ -120.726777, 45.68515 ], "pop" : 389, "state" : "OR" }
+{ "_id" : "97051", "city" : "SAINT HELENS", "loc" : [ -122.828177, 45.860825 ], "pop" : 10355, "state" : "OR" }
+{ "_id" : "97053", "city" : "WARREN", "loc" : [ -122.863445, 45.826043 ], "pop" : 2378, "state" : "OR" }
+{ "_id" : "97054", "city" : "DEER ISLAND", "loc" : [ -122.898458, 45.935553 ], "pop" : 1317, "state" : "OR" }
+{ "_id" : "97055", "city" : "SANDY", "loc" : [ -122.223049, 45.378954 ], "pop" : 12936, "state" : "OR" }
+{ "_id" : "97056", "city" : "SCAPPOOSE", "loc" : [ -122.892771, 45.765451 ], "pop" : 7812, "state" : "OR" }
+{ "_id" : "97057", "city" : "SHANIKO", "loc" : [ -120.806953, 45.047231 ], "pop" : 81, "state" : "OR" }
+{ "_id" : "97058", "city" : "THE DALLES", "loc" : [ -121.190493, 45.599504 ], "pop" : 16319, "state" : "OR" }
+{ "_id" : "97060", "city" : "TROUTDALE", "loc" : [ -122.373866, 45.525398 ], "pop" : 4849, "state" : "OR" }
+{ "_id" : "97062", "city" : "TUALATIN", "loc" : [ -122.763132, 45.372688 ], "pop" : 16371, "state" : "OR" }
+{ "_id" : "97063", "city" : "WAMIC", "loc" : [ -121.296517, 45.231789 ], "pop" : 712, "state" : "OR" }
+{ "_id" : "97064", "city" : "VERNONIA", "loc" : [ -123.196662, 45.857298 ], "pop" : 2931, "state" : "OR" }
+{ "_id" : "97065", "city" : "WASCO", "loc" : [ -120.730356, 45.597447 ], "pop" : 564, "state" : "OR" }
+{ "_id" : "97067", "city" : "WELCHES", "loc" : [ -121.959826, 45.339862 ], "pop" : 802, "state" : "OR" }
+{ "_id" : "97068", "city" : "WEST LINN", "loc" : [ -122.647952, 45.366874 ], "pop" : 19962, "state" : "OR" }
+{ "_id" : "97070", "city" : "WILSONVILLE", "loc" : [ -122.769886, 45.298646 ], "pop" : 9397, "state" : "OR" }
+{ "_id" : "97071", "city" : "WOODBURN", "loc" : [ -122.858342, 45.144617 ], "pop" : 17482, "state" : "OR" }
+{ "_id" : "97080", "city" : "GRESHAM", "loc" : [ -122.415645, 45.481699 ], "pop" : 25232, "state" : "OR" }
+{ "_id" : "97101", "city" : "AMITY", "loc" : [ -123.174402, 45.115704 ], "pop" : 2810, "state" : "OR" }
+{ "_id" : "97103", "city" : "ASTORIA", "loc" : [ -123.79798, 46.155802 ], "pop" : 19140, "state" : "OR" }
+{ "_id" : "97106", "city" : "BANKS", "loc" : [ -123.120982, 45.653476 ], "pop" : 3316, "state" : "OR" }
+{ "_id" : "97107", "city" : "BAY CITY", "loc" : [ -123.876075, 45.519658 ], "pop" : 1483, "state" : "OR" }
+{ "_id" : "97108", "city" : "BEAVER", "loc" : [ -123.823417, 45.276746 ], "pop" : 133, "state" : "OR" }
+{ "_id" : "97109", "city" : "BUXTON", "loc" : [ -123.214555, 45.736983 ], "pop" : 420, "state" : "OR" }
+{ "_id" : "97111", "city" : "CARLTON", "loc" : [ -123.152346, 45.28593 ], "pop" : 1555, "state" : "OR" }
+{ "_id" : "97112", "city" : "CLOVERDALE", "loc" : [ -123.835628, 45.285821 ], "pop" : 1269, "state" : "OR" }
+{ "_id" : "97113", "city" : "CORNELIUS", "loc" : [ -123.041536, 45.529034 ], "pop" : 13173, "state" : "OR" }
+{ "_id" : "97114", "city" : "DAYTON", "loc" : [ -123.075332, 45.197722 ], "pop" : 3640, "state" : "OR" }
+{ "_id" : "97115", "city" : "DUNDEE", "loc" : [ -123.01523, 45.27761 ], "pop" : 2382, "state" : "OR" }
+{ "_id" : "97116", "city" : "GLENWOOD", "loc" : [ -123.115152, 45.532835 ], "pop" : 17626, "state" : "OR" }
+{ "_id" : "97117", "city" : "GALES CREEK", "loc" : [ -123.233967, 45.595747 ], "pop" : 374, "state" : "OR" }
+{ "_id" : "97119", "city" : "GASTON", "loc" : [ -123.16657, 45.442738 ], "pop" : 3844, "state" : "OR" }
+{ "_id" : "97121", "city" : "HAMMOND", "loc" : [ -123.952726, 46.198028 ], "pop" : 627, "state" : "OR" }
+{ "_id" : "97122", "city" : "HEBO", "loc" : [ -123.871433, 45.212016 ], "pop" : 366, "state" : "OR" }
+{ "_id" : "97123", "city" : "HILLSBORO", "loc" : [ -122.956998, 45.498401 ], "pop" : 24201, "state" : "OR" }
+{ "_id" : "97124", "city" : "HILLSBORO", "loc" : [ -122.963608, 45.53868 ], "pop" : 20503, "state" : "OR" }
+{ "_id" : "97125", "city" : "MANNING", "loc" : [ -123.186113, 45.652468 ], "pop" : 549, "state" : "OR" }
+{ "_id" : "97127", "city" : "LAFAYETTE", "loc" : [ -123.111362, 45.246638 ], "pop" : 1315, "state" : "OR" }
+{ "_id" : "97128", "city" : "MCMINNVILLE", "loc" : [ -123.204342, 45.209677 ], "pop" : 21848, "state" : "OR" }
+{ "_id" : "97131", "city" : "NEHALEM", "loc" : [ -123.904943, 45.72159 ], "pop" : 2118, "state" : "OR" }
+{ "_id" : "97132", "city" : "NEWBERG", "loc" : [ -122.968503, 45.309901 ], "pop" : 18911, "state" : "OR" }
+{ "_id" : "97136", "city" : "ROCKAWAY", "loc" : [ -123.907834, 45.608511 ], "pop" : 3164, "state" : "OR" }
+{ "_id" : "97137", "city" : "SAINT PAUL", "loc" : [ -122.96737, 45.195996 ], "pop" : 1623, "state" : "OR" }
+{ "_id" : "97138", "city" : "GEARHART", "loc" : [ -123.878837, 45.969506 ], "pop" : 7239, "state" : "OR" }
+{ "_id" : "97140", "city" : "SHERWOOD", "loc" : [ -122.856724, 45.351419 ], "pop" : 7623, "state" : "OR" }
+{ "_id" : "97141", "city" : "TILLAMOOK", "loc" : [ -123.818851, 45.449185 ], "pop" : 11010, "state" : "OR" }
+{ "_id" : "97144", "city" : "TIMBER", "loc" : [ -123.311852, 45.727033 ], "pop" : 124, "state" : "OR" }
+{ "_id" : "97145", "city" : "TOLOVANA PARK", "loc" : [ -123.95887, 45.886172 ], "pop" : 1114, "state" : "OR" }
+{ "_id" : "97146", "city" : "WARRENTON", "loc" : [ -123.925366, 46.145017 ], "pop" : 4224, "state" : "OR" }
+{ "_id" : "97148", "city" : "YAMHILL", "loc" : [ -123.203639, 45.335049 ], "pop" : 4276, "state" : "OR" }
+{ "_id" : "97149", "city" : "NESKOWIN", "loc" : [ -123.926344, 45.178165 ], "pop" : 2027, "state" : "OR" }
+{ "_id" : "97201", "city" : "PORTLAND", "loc" : [ -122.690258, 45.498819 ], "pop" : 22763, "state" : "OR" }
+{ "_id" : "97202", "city" : "PORTLAND", "loc" : [ -122.636534, 45.484007 ], "pop" : 37147, "state" : "OR" }
+{ "_id" : "97203", "city" : "PORTLAND", "loc" : [ -122.734699, 45.588872 ], "pop" : 24789, "state" : "OR" }
+{ "_id" : "97204", "city" : "PORTLAND", "loc" : [ -122.674498, 45.51807 ], "pop" : 1094, "state" : "OR" }
+{ "_id" : "97205", "city" : "PORTLAND", "loc" : [ -122.688846, 45.52072 ], "pop" : 5804, "state" : "OR" }
+{ "_id" : "97206", "city" : "PORTLAND", "loc" : [ -122.59727, 45.483995 ], "pop" : 43134, "state" : "OR" }
+{ "_id" : "97209", "city" : "PORTLAND", "loc" : [ -122.685447, 45.526962 ], "pop" : 5810, "state" : "OR" }
+{ "_id" : "97210", "city" : "PORTLAND", "loc" : [ -122.703348, 45.530318 ], "pop" : 9284, "state" : "OR" }
+{ "_id" : "97211", "city" : "PORTLAND", "loc" : [ -122.644815, 45.565259 ], "pop" : 28736, "state" : "OR" }
+{ "_id" : "97212", "city" : "PORTLAND", "loc" : [ -122.642319, 45.544127 ], "pop" : 23898, "state" : "OR" }
+{ "_id" : "97213", "city" : "PORTLAND", "loc" : [ -122.59867, 45.537292 ], "pop" : 29400, "state" : "OR" }
+{ "_id" : "97214", "city" : "PORTLAND", "loc" : [ -122.636397, 45.514207 ], "pop" : 23413, "state" : "OR" }
+{ "_id" : "97215", "city" : "PORTLAND", "loc" : [ -122.599001, 45.514282 ], "pop" : 16563, "state" : "OR" }
+{ "_id" : "97216", "city" : "PORTLAND", "loc" : [ -122.55688, 45.513746 ], "pop" : 11436, "state" : "OR" }
+{ "_id" : "97217", "city" : "PORTLAND", "loc" : [ -122.684196, 45.57424 ], "pop" : 29086, "state" : "OR" }
+{ "_id" : "97218", "city" : "PORTLAND", "loc" : [ -122.600131, 45.560032 ], "pop" : 12305, "state" : "OR" }
+{ "_id" : "97219", "city" : "PORTLAND", "loc" : [ -122.70738, 45.457956 ], "pop" : 34992, "state" : "OR" }
+{ "_id" : "97220", "city" : "PORTLAND", "loc" : [ -122.556586, 45.541109 ], "pop" : 25679, "state" : "OR" }
+{ "_id" : "97221", "city" : "PORTLAND", "loc" : [ -122.726723, 45.491829 ], "pop" : 10834, "state" : "OR" }
+{ "_id" : "97222", "city" : "MILWAUKIE", "loc" : [ -122.615092, 45.442919 ], "pop" : 30905, "state" : "OR" }
+{ "_id" : "97223", "city" : "GARDEN HOME", "loc" : [ -122.775974, 45.443343 ], "pop" : 33529, "state" : "OR" }
+{ "_id" : "97224", "city" : "TIGARD", "loc" : [ -122.788379, 45.407292 ], "pop" : 17149, "state" : "OR" }
+{ "_id" : "97225", "city" : "CEDAR HILLS", "loc" : [ -122.768344, 45.500449 ], "pop" : 20934, "state" : "OR" }
+{ "_id" : "97227", "city" : "PORTLAND", "loc" : [ -122.674257, 45.549564 ], "pop" : 3171, "state" : "OR" }
+{ "_id" : "97229", "city" : "PORTLAND", "loc" : [ -122.829924, 45.541087 ], "pop" : 23490, "state" : "OR" }
+{ "_id" : "97230", "city" : "ROCKWOOD CORNERS", "loc" : [ -122.500343, 45.535753 ], "pop" : 30643, "state" : "OR" }
+{ "_id" : "97231", "city" : "PORTLAND", "loc" : [ -122.838032, 45.640124 ], "pop" : 3760, "state" : "OR" }
+{ "_id" : "97232", "city" : "PORTLAND", "loc" : [ -122.63631, 45.528712 ], "pop" : 10323, "state" : "OR" }
+{ "_id" : "97233", "city" : "PORTLAND", "loc" : [ -122.498493, 45.514206 ], "pop" : 27274, "state" : "OR" }
+{ "_id" : "97236", "city" : "PORTLAND", "loc" : [ -122.509091, 45.488748 ], "pop" : 24710, "state" : "OR" }
+{ "_id" : "97266", "city" : "PORTLAND", "loc" : [ -122.559607, 45.476207 ], "pop" : 29648, "state" : "OR" }
+{ "_id" : "97267", "city" : "OAK GROVE", "loc" : [ -122.610631, 45.407494 ], "pop" : 29597, "state" : "OR" }
+{ "_id" : "97301", "city" : "SALEM", "loc" : [ -122.979692, 44.926039 ], "pop" : 48007, "state" : "OR" }
+{ "_id" : "97302", "city" : "SALEM", "loc" : [ -123.044514, 44.903899 ], "pop" : 34814, "state" : "OR" }
+{ "_id" : "97303", "city" : "KEIZER", "loc" : [ -123.019015, 44.985794 ], "pop" : 35826, "state" : "OR" }
+{ "_id" : "97304", "city" : "SALEM", "loc" : [ -123.075323, 44.958846 ], "pop" : 16986, "state" : "OR" }
+{ "_id" : "97305", "city" : "BROOKS", "loc" : [ -122.966892, 44.982502 ], "pop" : 28239, "state" : "OR" }
+{ "_id" : "97306", "city" : "SALEM", "loc" : [ -123.043789, 44.8685 ], "pop" : 14770, "state" : "OR" }
+{ "_id" : "97321", "city" : "ALBANY", "loc" : [ -123.094409, 44.627722 ], "pop" : 42908, "state" : "OR" }
+{ "_id" : "97324", "city" : "ALSEA", "loc" : [ -123.60892, 44.369068 ], "pop" : 1008, "state" : "OR" }
+{ "_id" : "97325", "city" : "WEST STAYTON", "loc" : [ -122.878575, 44.817817 ], "pop" : 4185, "state" : "OR" }
+{ "_id" : "97326", "city" : "BLODGETT", "loc" : [ -123.606715, 44.628141 ], "pop" : 657, "state" : "OR" }
+{ "_id" : "97327", "city" : "BROWNSVILLE", "loc" : [ -122.948491, 44.376974 ], "pop" : 3249, "state" : "OR" }
+{ "_id" : "97329", "city" : "CASCADIA", "loc" : [ -122.464214, 44.392239 ], "pop" : 163, "state" : "OR" }
+{ "_id" : "97330", "city" : "CORVALLIS", "loc" : [ -123.272171, 44.590411 ], "pop" : 38801, "state" : "OR" }
+{ "_id" : "97331", "city" : "CORVALLIS", "loc" : [ -123.277889, 44.563783 ], "pop" : 2528, "state" : "OR" }
+{ "_id" : "97333", "city" : "CORVALLIS", "loc" : [ -123.279908, 44.539281 ], "pop" : 13009, "state" : "OR" }
+{ "_id" : "97338", "city" : "DALLAS", "loc" : [ -123.319991, 44.922534 ], "pop" : 14447, "state" : "OR" }
+{ "_id" : "97341", "city" : "DEPOE BAY", "loc" : [ -124.03234, 44.851445 ], "pop" : 3022, "state" : "OR" }
+{ "_id" : "97342", "city" : "DETROIT", "loc" : [ -122.18447, 44.776619 ], "pop" : 589, "state" : "OR" }
+{ "_id" : "97343", "city" : "EDDYVILLE", "loc" : [ -123.753096, 44.637139 ], "pop" : 599, "state" : "OR" }
+{ "_id" : "97344", "city" : "FALLS CITY", "loc" : [ -123.446149, 44.870597 ], "pop" : 957, "state" : "OR" }
+{ "_id" : "97345", "city" : "FOSTER", "loc" : [ -122.544898, 44.383556 ], "pop" : 192, "state" : "OR" }
+{ "_id" : "97346", "city" : "GATES", "loc" : [ -122.399498, 44.752716 ], "pop" : 697, "state" : "OR" }
+{ "_id" : "97347", "city" : "GRAND RONDE", "loc" : [ -123.633518, 45.074973 ], "pop" : 1151, "state" : "OR" }
+{ "_id" : "97348", "city" : "HALSEY", "loc" : [ -123.125103, 44.386151 ], "pop" : 1159, "state" : "OR" }
+{ "_id" : "97350", "city" : "IDANHA", "loc" : [ -122.047574, 44.701484 ], "pop" : 340, "state" : "OR" }
+{ "_id" : "97351", "city" : "INDEPENDENCE", "loc" : [ -123.187913, 44.848098 ], "pop" : 5955, "state" : "OR" }
+{ "_id" : "97352", "city" : "JEFFERSON", "loc" : [ -123.00596, 44.749452 ], "pop" : 5829, "state" : "OR" }
+{ "_id" : "97355", "city" : "LEBANON", "loc" : [ -122.882064, 44.531558 ], "pop" : 23147, "state" : "OR" }
+{ "_id" : "97357", "city" : "LOGSDEN", "loc" : [ -123.773645, 44.747514 ], "pop" : 234, "state" : "OR" }
+{ "_id" : "97358", "city" : "LYONS", "loc" : [ -122.820083, 44.776792 ], "pop" : 0, "state" : "OR" }
+{ "_id" : "97360", "city" : "MILL CITY", "loc" : [ -122.476825, 44.751566 ], "pop" : 2340, "state" : "OR" }
+{ "_id" : "97361", "city" : "MONMOUTH", "loc" : [ -123.251233, 44.837706 ], "pop" : 8071, "state" : "OR" }
+{ "_id" : "97362", "city" : "MOUNT ANGEL", "loc" : [ -122.785611, 45.073727 ], "pop" : 4747, "state" : "OR" }
+{ "_id" : "97364", "city" : "NEOTSU", "loc" : [ -123.984337, 44.998801 ], "pop" : 347, "state" : "OR" }
+{ "_id" : "97365", "city" : "NEWPORT", "loc" : [ -124.050903, 44.648653 ], "pop" : 9239, "state" : "OR" }
+{ "_id" : "97366", "city" : "SOUTH BEACH", "loc" : [ -124.059968, 44.57122 ], "pop" : 1423, "state" : "OR" }
+{ "_id" : "97367", "city" : "LINCOLN CITY", "loc" : [ -123.99556, 44.968139 ], "pop" : 6786, "state" : "OR" }
+{ "_id" : "97368", "city" : "OTIS", "loc" : [ -123.933244, 45.013755 ], "pop" : 2506, "state" : "OR" }
+{ "_id" : "97370", "city" : "PHILOMATH", "loc" : [ -123.392271, 44.548817 ], "pop" : 6879, "state" : "OR" }
+{ "_id" : "97371", "city" : "RICKREALL", "loc" : [ -123.206424, 45.020032 ], "pop" : 266, "state" : "OR" }
+{ "_id" : "97374", "city" : "SCIO", "loc" : [ -122.768356, 44.716792 ], "pop" : 7170, "state" : "OR" }
+{ "_id" : "97375", "city" : "SCOTTS MILLS", "loc" : [ -122.665418, 45.022 ], "pop" : 1326, "state" : "OR" }
+{ "_id" : "97376", "city" : "SEAL ROCK", "loc" : [ -124.060708, 44.477749 ], "pop" : 1845, "state" : "OR" }
+{ "_id" : "97377", "city" : "SHEDD", "loc" : [ -123.106462, 44.452951 ], "pop" : 1067, "state" : "OR" }
+{ "_id" : "97378", "city" : "SHERIDAN", "loc" : [ -123.400335, 45.089703 ], "pop" : 6591, "state" : "OR" }
+{ "_id" : "97380", "city" : "SILETZ", "loc" : [ -123.906239, 44.731333 ], "pop" : 1869, "state" : "OR" }
+{ "_id" : "97381", "city" : "SILVERTON", "loc" : [ -122.762724, 44.991041 ], "pop" : 10399, "state" : "OR" }
+{ "_id" : "97383", "city" : "STAYTON", "loc" : [ -122.76241, 44.80211 ], "pop" : 6808, "state" : "OR" }
+{ "_id" : "97385", "city" : "SUBLIMITY", "loc" : [ -122.800718, 44.842523 ], "pop" : 2881, "state" : "OR" }
+{ "_id" : "97386", "city" : "SWEET HOME", "loc" : [ -122.728561, 44.398111 ], "pop" : 11237, "state" : "OR" }
+{ "_id" : "97389", "city" : "TANGENT", "loc" : [ -123.110815, 44.54973 ], "pop" : 1257, "state" : "OR" }
+{ "_id" : "97390", "city" : "TIDEWATER", "loc" : [ -123.914861, 44.405538 ], "pop" : 523, "state" : "OR" }
+{ "_id" : "97391", "city" : "TOLEDO", "loc" : [ -123.930119, 44.627082 ], "pop" : 5609, "state" : "OR" }
+{ "_id" : "97392", "city" : "TURNER", "loc" : [ -122.950117, 44.847607 ], "pop" : 1243, "state" : "OR" }
+{ "_id" : "97394", "city" : "WALDPORT", "loc" : [ -124.035053, 44.408497 ], "pop" : 3302, "state" : "OR" }
+{ "_id" : "97396", "city" : "WILLAMINA", "loc" : [ -123.504708, 45.082605 ], "pop" : 2697, "state" : "OR" }
+{ "_id" : "97401", "city" : "COBURG", "loc" : [ -123.078757, 44.073677 ], "pop" : 36277, "state" : "OR" }
+{ "_id" : "97402", "city" : "EUGENE", "loc" : [ -123.155525, 44.061243 ], "pop" : 37830, "state" : "OR" }
+{ "_id" : "97403", "city" : "EUGENE", "loc" : [ -123.061422, 44.038534 ], "pop" : 11073, "state" : "OR" }
+{ "_id" : "97404", "city" : "EUGENE", "loc" : [ -123.13336, 44.100536 ], "pop" : 23778, "state" : "OR" }
+{ "_id" : "97405", "city" : "EUGENE", "loc" : [ -123.099769, 44.018497 ], "pop" : 40921, "state" : "OR" }
+{ "_id" : "97406", "city" : "AGNESS", "loc" : [ -124.064769, 42.574788 ], "pop" : 126, "state" : "OR" }
+{ "_id" : "97410", "city" : "AZALEA", "loc" : [ -123.155017, 42.844992 ], "pop" : 1111, "state" : "OR" }
+{ "_id" : "97411", "city" : "BANDON", "loc" : [ -124.40367, 43.096806 ], "pop" : 4852, "state" : "OR" }
+{ "_id" : "97412", "city" : "BLACHLY", "loc" : [ -123.534816, 44.196597 ], "pop" : 495, "state" : "OR" }
+{ "_id" : "97413", "city" : "MC KENZIE BRIDGE", "loc" : [ -122.222951, 44.177809 ], "pop" : 1139, "state" : "OR" }
+{ "_id" : "97414", "city" : "BROADBENT", "loc" : [ -124.118924, 42.985048 ], "pop" : 121, "state" : "OR" }
+{ "_id" : "97415", "city" : "HARBOR", "loc" : [ -124.267811, 42.064004 ], "pop" : 11673, "state" : "OR" }
+{ "_id" : "97416", "city" : "CAMAS VALLEY", "loc" : [ -123.665465, 43.05566 ], "pop" : 972, "state" : "OR" }
+{ "_id" : "97417", "city" : "CANYONVILLE", "loc" : [ -123.278015, 42.930683 ], "pop" : 1670, "state" : "OR" }
+{ "_id" : "97419", "city" : "CHESHIRE", "loc" : [ -123.371516, 44.178206 ], "pop" : 1050, "state" : "OR" }
+{ "_id" : "97420", "city" : "CHARLESTON", "loc" : [ -124.233101, 43.362812 ], "pop" : 24343, "state" : "OR" }
+{ "_id" : "97423", "city" : "COQUILLE", "loc" : [ -124.201386, 43.188413 ], "pop" : 8374, "state" : "OR" }
+{ "_id" : "97424", "city" : "COTTAGE GROVE", "loc" : [ -123.05291, 43.783934 ], "pop" : 15067, "state" : "OR" }
+{ "_id" : "97426", "city" : "CRESWELL", "loc" : [ -123.02838, 43.90583 ], "pop" : 6332, "state" : "OR" }
+{ "_id" : "97427", "city" : "CULP CREEK", "loc" : [ -122.752417, 43.684534 ], "pop" : 317, "state" : "OR" }
+{ "_id" : "97429", "city" : "DAYS CREEK", "loc" : [ -123.14387, 42.981946 ], "pop" : 392, "state" : "OR" }
+{ "_id" : "97430", "city" : "GREENLEAF", "loc" : [ -123.688328, 44.145131 ], "pop" : 492, "state" : "OR" }
+{ "_id" : "97431", "city" : "DEXTER", "loc" : [ -122.842351, 43.921691 ], "pop" : 2980, "state" : "OR" }
+{ "_id" : "97434", "city" : "DORENA", "loc" : [ -122.885796, 43.758655 ], "pop" : 225, "state" : "OR" }
+{ "_id" : "97435", "city" : "DRAIN", "loc" : [ -123.292922, 43.687659 ], "pop" : 2331, "state" : "OR" }
+{ "_id" : "97436", "city" : "ELKTON", "loc" : [ -123.590014, 43.637761 ], "pop" : 878, "state" : "OR" }
+{ "_id" : "97437", "city" : "ELMIRA", "loc" : [ -123.367051, 44.08726 ], "pop" : 2424, "state" : "OR" }
+{ "_id" : "97438", "city" : "FALL CREEK", "loc" : [ -122.785904, 43.95616 ], "pop" : 1581, "state" : "OR" }
+{ "_id" : "97439", "city" : "FLORENCE", "loc" : [ -124.099303, 43.988099 ], "pop" : 10063, "state" : "OR" }
+{ "_id" : "97441", "city" : "GARDINER", "loc" : [ -124.143695, 43.785736 ], "pop" : 14, "state" : "OR" }
+{ "_id" : "97442", "city" : "GLENDALE", "loc" : [ -123.394302, 42.751751 ], "pop" : 2050, "state" : "OR" }
+{ "_id" : "97443", "city" : "GLIDE", "loc" : [ -122.963846, 43.277395 ], "pop" : 2905, "state" : "OR" }
+{ "_id" : "97444", "city" : "PISTOL RIVER", "loc" : [ -124.396072, 42.434818 ], "pop" : 4760, "state" : "OR" }
+{ "_id" : "97446", "city" : "HARRISBURG", "loc" : [ -123.143165, 44.271656 ], "pop" : 3272, "state" : "OR" }
+{ "_id" : "97447", "city" : "IDLEYLD PARK", "loc" : [ -122.901789, 43.371571 ], "pop" : 222, "state" : "OR" }
+{ "_id" : "97448", "city" : "JUNCTION CITY", "loc" : [ -123.230014, 44.198792 ], "pop" : 10456, "state" : "OR" }
+{ "_id" : "97449", "city" : "LAKESIDE", "loc" : [ -124.162364, 43.583306 ], "pop" : 994, "state" : "OR" }
+{ "_id" : "97450", "city" : "LANGLOIS", "loc" : [ -124.441322, 42.915386 ], "pop" : 557, "state" : "OR" }
+{ "_id" : "97451", "city" : "LORANE", "loc" : [ -123.247679, 43.829044 ], "pop" : 499, "state" : "OR" }
+{ "_id" : "97452", "city" : "LOWELL", "loc" : [ -122.780627, 43.920993 ], "pop" : 792, "state" : "OR" }
+{ "_id" : "97453", "city" : "MAPLETON", "loc" : [ -123.865735, 44.031189 ], "pop" : 1104, "state" : "OR" }
+{ "_id" : "97454", "city" : "MARCOLA", "loc" : [ -122.82464, 44.206439 ], "pop" : 1442, "state" : "OR" }
+{ "_id" : "97455", "city" : "PLEASANT HILL", "loc" : [ -122.928487, 43.945816 ], "pop" : 2218, "state" : "OR" }
+{ "_id" : "97456", "city" : "MONROE", "loc" : [ -123.32033, 44.32446 ], "pop" : 2478, "state" : "OR" }
+{ "_id" : "97457", "city" : "MYRTLE CREEK", "loc" : [ -123.285054, 43.016161 ], "pop" : 9453, "state" : "OR" }
+{ "_id" : "97458", "city" : "MYRTLE POINT", "loc" : [ -124.121327, 43.066694 ], "pop" : 5246, "state" : "OR" }
+{ "_id" : "97459", "city" : "NORTH BEND", "loc" : [ -124.213103, 43.432665 ], "pop" : 15269, "state" : "OR" }
+{ "_id" : "97461", "city" : "NOTI", "loc" : [ -123.456962, 44.119509 ], "pop" : 1189, "state" : "OR" }
+{ "_id" : "97462", "city" : "OAKLAND", "loc" : [ -123.355774, 43.452968 ], "pop" : 3315, "state" : "OR" }
+{ "_id" : "97463", "city" : "OAKRIDGE", "loc" : [ -122.457711, 43.749767 ], "pop" : 4058, "state" : "OR" }
+{ "_id" : "97465", "city" : "PORT ORFORD", "loc" : [ -124.491283, 42.757194 ], "pop" : 1799, "state" : "OR" }
+{ "_id" : "97466", "city" : "POWERS", "loc" : [ -124.066441, 42.891006 ], "pop" : 953, "state" : "OR" }
+{ "_id" : "97467", "city" : "WINCHESTER BAY", "loc" : [ -124.105476, 43.695701 ], "pop" : 6723, "state" : "OR" }
+{ "_id" : "97468", "city" : "REMOTE", "loc" : [ -123.89149, 43.007909 ], "pop" : 121, "state" : "OR" }
+{ "_id" : "97469", "city" : "RIDDLE", "loc" : [ -123.361247, 42.938867 ], "pop" : 2698, "state" : "OR" }
+{ "_id" : "97470", "city" : "ROSEBURG", "loc" : [ -123.366437, 43.222726 ], "pop" : 41697, "state" : "OR" }
+{ "_id" : "97473", "city" : "SCOTTSBURG", "loc" : [ -123.804065, 43.676481 ], "pop" : 329, "state" : "OR" }
+{ "_id" : "97476", "city" : "SIXES", "loc" : [ -124.44093, 42.824984 ], "pop" : 412, "state" : "OR" }
+{ "_id" : "97477", "city" : "SPRINGFIELD", "loc" : [ -123.015259, 44.06106 ], "pop" : 32384, "state" : "OR" }
+{ "_id" : "97478", "city" : "SPRINGFIELD", "loc" : [ -122.917108, 44.056056 ], "pop" : 27521, "state" : "OR" }
+{ "_id" : "97479", "city" : "SUTHERLIN", "loc" : [ -123.297425, 43.390404 ], "pop" : 7304, "state" : "OR" }
+{ "_id" : "97480", "city" : "SWISSHOME", "loc" : [ -123.827899, 44.089903 ], "pop" : 641, "state" : "OR" }
+{ "_id" : "97481", "city" : "TENMILE", "loc" : [ -123.530104, 43.137116 ], "pop" : 1231, "state" : "OR" }
+{ "_id" : "97484", "city" : "TILLER", "loc" : [ -122.908088, 42.985896 ], "pop" : 534, "state" : "OR" }
+{ "_id" : "97486", "city" : "UMPQUA", "loc" : [ -123.535771, 43.374537 ], "pop" : 587, "state" : "OR" }
+{ "_id" : "97487", "city" : "VENETA", "loc" : [ -123.35159, 44.038235 ], "pop" : 6004, "state" : "OR" }
+{ "_id" : "97488", "city" : "VIDA", "loc" : [ -122.504429, 44.130041 ], "pop" : 1040, "state" : "OR" }
+{ "_id" : "97489", "city" : "LEABURG", "loc" : [ -122.629064, 44.135163 ], "pop" : 432, "state" : "OR" }
+{ "_id" : "97490", "city" : "WALTON", "loc" : [ -123.589304, 44.028194 ], "pop" : 298, "state" : "OR" }
+{ "_id" : "97492", "city" : "WESTFIR", "loc" : [ -122.514095, 43.756636 ], "pop" : 514, "state" : "OR" }
+{ "_id" : "97493", "city" : "WESTLAKE", "loc" : [ -124.033364, 43.914017 ], "pop" : 272, "state" : "OR" }
+{ "_id" : "97496", "city" : "WINSTON", "loc" : [ -123.432481, 43.104855 ], "pop" : 5971, "state" : "OR" }
+{ "_id" : "97497", "city" : "SUNNY VALLEY", "loc" : [ -123.351538, 42.655128 ], "pop" : 1253, "state" : "OR" }
+{ "_id" : "97498", "city" : "YACHATS", "loc" : [ -124.086262, 44.325563 ], "pop" : 1235, "state" : "OR" }
+{ "_id" : "97499", "city" : "YONCALLA", "loc" : [ -123.292562, 43.60434 ], "pop" : 2261, "state" : "OR" }
+{ "_id" : "97501", "city" : "WEST MAIN", "loc" : [ -122.887011, 42.319293 ], "pop" : 28708, "state" : "OR" }
+{ "_id" : "97502", "city" : "CENTRAL POINT", "loc" : [ -122.922235, 42.389914 ], "pop" : 17293, "state" : "OR" }
+{ "_id" : "97503", "city" : "WHITE CITY", "loc" : [ -122.82962, 42.431919 ], "pop" : 7024, "state" : "OR" }
+{ "_id" : "97504", "city" : "MEDFORD", "loc" : [ -122.839801, 42.336251 ], "pop" : 30933, "state" : "OR" }
+{ "_id" : "97520", "city" : "ASHLAND", "loc" : [ -122.693033, 42.188509 ], "pop" : 19579, "state" : "OR" }
+{ "_id" : "97522", "city" : "BUTTE FALLS", "loc" : [ -122.563801, 42.549243 ], "pop" : 1115, "state" : "OR" }
+{ "_id" : "97523", "city" : "CAVE JUNCTION", "loc" : [ -123.627199, 42.134789 ], "pop" : 5500, "state" : "OR" }
+{ "_id" : "97524", "city" : "EAGLE POINT", "loc" : [ -122.808802, 42.493467 ], "pop" : 7468, "state" : "OR" }
+{ "_id" : "97525", "city" : "GOLD HILL", "loc" : [ -123.08543, 42.424436 ], "pop" : 6650, "state" : "OR" }
+{ "_id" : "97526", "city" : "GRANTS PASS", "loc" : [ -123.345727, 42.463758 ], "pop" : 27145, "state" : "OR" }
+{ "_id" : "97527", "city" : "GRANTS PASS", "loc" : [ -123.353799, 42.398913 ], "pop" : 21774, "state" : "OR" }
+{ "_id" : "97530", "city" : "APPLEGATE", "loc" : [ -123.028098, 42.254894 ], "pop" : 5723, "state" : "OR" }
+{ "_id" : "97531", "city" : "KERBY", "loc" : [ -123.657302, 42.209343 ], "pop" : 78, "state" : "OR" }
+{ "_id" : "97532", "city" : "MERLIN", "loc" : [ -123.439256, 42.529654 ], "pop" : 1806, "state" : "OR" }
+{ "_id" : "97534", "city" : "O BRIEN", "loc" : [ -123.720898, 42.068816 ], "pop" : 247, "state" : "OR" }
+{ "_id" : "97535", "city" : "PHOENIX", "loc" : [ -122.822694, 42.276555 ], "pop" : 6054, "state" : "OR" }
+{ "_id" : "97536", "city" : "PROSPECT", "loc" : [ -122.50898, 42.754394 ], "pop" : 869, "state" : "OR" }
+{ "_id" : "97537", "city" : "ROGUE RIVER", "loc" : [ -123.158726, 42.488889 ], "pop" : 6131, "state" : "OR" }
+{ "_id" : "97538", "city" : "SELMA", "loc" : [ -123.568394, 42.296358 ], "pop" : 2065, "state" : "OR" }
+{ "_id" : "97539", "city" : "SHADY COVE", "loc" : [ -122.812191, 42.607575 ], "pop" : 2364, "state" : "OR" }
+{ "_id" : "97540", "city" : "TALENT", "loc" : [ -122.78605, 42.236252 ], "pop" : 5288, "state" : "OR" }
+{ "_id" : "97541", "city" : "TRAIL", "loc" : [ -122.816029, 42.686358 ], "pop" : 1028, "state" : "OR" }
+{ "_id" : "97543", "city" : "WILDERVILLE", "loc" : [ -123.513861, 42.392483 ], "pop" : 927, "state" : "OR" }
+{ "_id" : "97544", "city" : "WILLIAMS", "loc" : [ -123.282877, 42.223049 ], "pop" : 1854, "state" : "OR" }
+{ "_id" : "97601", "city" : "ORETECH", "loc" : [ -121.786969, 42.229601 ], "pop" : 18626, "state" : "OR" }
+{ "_id" : "97603", "city" : "KLAMATH FALLS", "loc" : [ -121.724124, 42.191915 ], "pop" : 24894, "state" : "OR" }
+{ "_id" : "97620", "city" : "ADEL", "loc" : [ -119.883291, 42.148697 ], "pop" : 190, "state" : "OR" }
+{ "_id" : "97621", "city" : "BEATTY", "loc" : [ -121.219962, 42.436942 ], "pop" : 95, "state" : "OR" }
+{ "_id" : "97623", "city" : "BONANZA", "loc" : [ -121.333558, 42.246268 ], "pop" : 2753, "state" : "OR" }
+{ "_id" : "97624", "city" : "CHILOQUIN", "loc" : [ -121.744959, 42.546293 ], "pop" : 3608, "state" : "OR" }
+{ "_id" : "97625", "city" : "DAIRY", "loc" : [ -121.642453, 42.258141 ], "pop" : 8, "state" : "OR" }
+{ "_id" : "97627", "city" : "KENO", "loc" : [ -121.972427, 42.175472 ], "pop" : 2696, "state" : "OR" }
+{ "_id" : "97630", "city" : "LAKEVIEW", "loc" : [ -120.377533, 42.185443 ], "pop" : 4890, "state" : "OR" }
+{ "_id" : "97632", "city" : "MALIN", "loc" : [ -121.422121, 42.019502 ], "pop" : 1456, "state" : "OR" }
+{ "_id" : "97633", "city" : "MERRILL", "loc" : [ -121.598545, 42.029516 ], "pop" : 1344, "state" : "OR" }
+{ "_id" : "97635", "city" : "NEW PINE CREEK", "loc" : [ -120.28939, 42.027759 ], "pop" : 198, "state" : "OR" }
+{ "_id" : "97636", "city" : "PAISLEY", "loc" : [ -120.553208, 42.703089 ], "pop" : 619, "state" : "OR" }
+{ "_id" : "97637", "city" : "PLUSH", "loc" : [ -119.894722, 42.503493 ], "pop" : 126, "state" : "OR" }
+{ "_id" : "97638", "city" : "SILVER LAKE", "loc" : [ -120.780109, 43.258164 ], "pop" : 1127, "state" : "OR" }
+{ "_id" : "97640", "city" : "SUMMER LAKE", "loc" : [ -121.063254, 42.831302 ], "pop" : 1, "state" : "OR" }
+{ "_id" : "97701", "city" : "BEND", "loc" : [ -121.293632, 44.092788 ], "pop" : 29432, "state" : "OR" }
+{ "_id" : "97702", "city" : "BEND", "loc" : [ -121.298543, 44.022332 ], "pop" : 20214, "state" : "OR" }
+{ "_id" : "97707", "city" : "SUNRIVER", "loc" : [ -121.457871, 43.850336 ], "pop" : 2881, "state" : "OR" }
+{ "_id" : "97711", "city" : "ASHWOOD", "loc" : [ -120.719161, 44.719479 ], "pop" : 114, "state" : "OR" }
+{ "_id" : "97712", "city" : "BROTHERS", "loc" : [ -120.477035, 43.778877 ], "pop" : 41, "state" : "OR" }
+{ "_id" : "97720", "city" : "BURNS", "loc" : [ -119.050398, 43.51451 ], "pop" : 5844, "state" : "OR" }
+{ "_id" : "97730", "city" : "CAMP SHERMAN", "loc" : [ -121.639363, 44.454997 ], "pop" : 378, "state" : "OR" }
+{ "_id" : "97731", "city" : "DIAMOND LAKE", "loc" : [ -121.8447, 43.124669 ], "pop" : 388, "state" : "OR" }
+{ "_id" : "97732", "city" : "CRANE", "loc" : [ -118.4642, 43.426219 ], "pop" : 280, "state" : "OR" }
+{ "_id" : "97733", "city" : "CRESCENT", "loc" : [ -121.664813, 43.497226 ], "pop" : 1848, "state" : "OR" }
+{ "_id" : "97734", "city" : "CULVER", "loc" : [ -121.234353, 44.481796 ], "pop" : 2517, "state" : "OR" }
+{ "_id" : "97735", "city" : "FORT ROCK", "loc" : [ -121.08243, 43.44615 ], "pop" : 35, "state" : "OR" }
+{ "_id" : "97737", "city" : "GILCHRIST", "loc" : [ -121.886596, 43.30759 ], "pop" : 148, "state" : "OR" }
+{ "_id" : "97739", "city" : "LA PINE", "loc" : [ -121.519445, 43.709125 ], "pop" : 4815, "state" : "OR" }
+{ "_id" : "97740", "city" : "LAWEN", "loc" : [ -118.8418, 43.561816 ], "pop" : 708, "state" : "OR" }
+{ "_id" : "97741", "city" : "MADRAS", "loc" : [ -121.134924, 44.637579 ], "pop" : 8294, "state" : "OR" }
+{ "_id" : "97750", "city" : "MITCHELL", "loc" : [ -120.145579, 44.565734 ], "pop" : 394, "state" : "OR" }
+{ "_id" : "97751", "city" : "PAULINA", "loc" : [ -119.782768, 44.210243 ], "pop" : 98, "state" : "OR" }
+{ "_id" : "97752", "city" : "POST", "loc" : [ -120.299781, 44.079273 ], "pop" : 252, "state" : "OR" }
+{ "_id" : "97753", "city" : "POWELL BUTTE", "loc" : [ -121.011326, 44.241512 ], "pop" : 1056, "state" : "OR" }
+{ "_id" : "97754", "city" : "PRINEVILLE", "loc" : [ -120.833616, 44.30445 ], "pop" : 12484, "state" : "OR" }
+{ "_id" : "97756", "city" : "REDMOND", "loc" : [ -121.189604, 44.27669 ], "pop" : 12161, "state" : "OR" }
+{ "_id" : "97758", "city" : "RILEY", "loc" : [ -116.900621, 44.930529 ], "pop" : 157, "state" : "OR" }
+{ "_id" : "97759", "city" : "BLACK BUTTE RANC", "loc" : [ -121.524133, 44.307329 ], "pop" : 3534, "state" : "OR" }
+{ "_id" : "97760", "city" : "CROOKED RIVER RA", "loc" : [ -121.167565, 44.355505 ], "pop" : 2101, "state" : "OR" }
+{ "_id" : "97761", "city" : "WARM SPRINGS", "loc" : [ -121.290941, 44.746826 ], "pop" : 2400, "state" : "OR" }
+{ "_id" : "97801", "city" : "PENDLETON", "loc" : [ -118.783104, 45.660535 ], "pop" : 20225, "state" : "OR" }
+{ "_id" : "97810", "city" : "ADAMS", "loc" : [ -118.617582, 45.749678 ], "pop" : 609, "state" : "OR" }
+{ "_id" : "97812", "city" : "ARLINGTON", "loc" : [ -120.197148, 45.666417 ], "pop" : 708, "state" : "OR" }
+{ "_id" : "97813", "city" : "ATHENA", "loc" : [ -118.497147, 45.828893 ], "pop" : 1334, "state" : "OR" }
+{ "_id" : "97814", "city" : "MEDICAL SPRINGS", "loc" : [ -117.828631, 44.780102 ], "pop" : 10024, "state" : "OR" }
+{ "_id" : "97818", "city" : "BOARDMAN", "loc" : [ -119.72057, 45.827165 ], "pop" : 2143, "state" : "OR" }
+{ "_id" : "97820", "city" : "CANYON CITY", "loc" : [ -118.950155, 44.410005 ], "pop" : 2806, "state" : "OR" }
+{ "_id" : "97823", "city" : "CONDON", "loc" : [ -120.189834, 45.230587 ], "pop" : 1009, "state" : "OR" }
+{ "_id" : "97824", "city" : "COVE", "loc" : [ -117.814741, 45.319902 ], "pop" : 1280, "state" : "OR" }
+{ "_id" : "97825", "city" : "DAYVILLE", "loc" : [ -119.531178, 44.466307 ], "pop" : 144, "state" : "OR" }
+{ "_id" : "97826", "city" : "ECHO", "loc" : [ -119.194904, 45.74109 ], "pop" : 648, "state" : "OR" }
+{ "_id" : "97827", "city" : "ELGIN", "loc" : [ -117.91119, 45.594101 ], "pop" : 2549, "state" : "OR" }
+{ "_id" : "97828", "city" : "ENTERPRISE", "loc" : [ -117.288808, 45.437037 ], "pop" : 3201, "state" : "OR" }
+{ "_id" : "97830", "city" : "KINZUA", "loc" : [ -120.206699, 44.985289 ], "pop" : 564, "state" : "OR" }
+{ "_id" : "97831", "city" : "FOX", "loc" : [ -119.291646, 44.660681 ], "pop" : 47, "state" : "OR" }
+{ "_id" : "97833", "city" : "HAINES", "loc" : [ -117.97556, 44.877622 ], "pop" : 1642, "state" : "OR" }
+{ "_id" : "97834", "city" : "HALFWAY", "loc" : [ -117.113152, 44.895272 ], "pop" : 1020, "state" : "OR" }
+{ "_id" : "97835", "city" : "HELIX", "loc" : [ -118.722219, 45.866541 ], "pop" : 383, "state" : "OR" }
+{ "_id" : "97836", "city" : "HEPPNER", "loc" : [ -119.536897, 45.348577 ], "pop" : 2127, "state" : "OR" }
+{ "_id" : "97837", "city" : "HEREFORD", "loc" : [ -117.98896, 44.641048 ], "pop" : 287, "state" : "OR" }
+{ "_id" : "97838", "city" : "HERMISTON", "loc" : [ -119.284876, 45.844992 ], "pop" : 16982, "state" : "OR" }
+{ "_id" : "97839", "city" : "LEXINGTON", "loc" : [ -119.74636, 45.426362 ], "pop" : 519, "state" : "OR" }
+{ "_id" : "97841", "city" : "IMBLER", "loc" : [ -117.954377, 45.459908 ], "pop" : 561, "state" : "OR" }
+{ "_id" : "97842", "city" : "IMNAHA", "loc" : [ -116.825741, 45.513733 ], "pop" : 255, "state" : "OR" }
+{ "_id" : "97843", "city" : "IONE", "loc" : [ -119.769034, 45.54033 ], "pop" : 535, "state" : "OR" }
+{ "_id" : "97844", "city" : "IRRIGON", "loc" : [ -119.507016, 45.88768 ], "pop" : 2301, "state" : "OR" }
+{ "_id" : "97845", "city" : "JOHN DAY", "loc" : [ -119.105157, 44.409977 ], "pop" : 1367, "state" : "OR" }
+{ "_id" : "97846", "city" : "JOSEPH", "loc" : [ -117.212805, 45.349432 ], "pop" : 1749, "state" : "OR" }
+{ "_id" : "97848", "city" : "KIMBERLY", "loc" : [ -119.596497, 44.72263 ], "pop" : 62, "state" : "OR" }
+{ "_id" : "97850", "city" : "LA GRANDE", "loc" : [ -118.085228, 45.330435 ], "pop" : 15401, "state" : "OR" }
+{ "_id" : "97856", "city" : "LONG CREEK", "loc" : [ -119.09702, 44.755416 ], "pop" : 442, "state" : "OR" }
+{ "_id" : "97857", "city" : "LOSTINE", "loc" : [ -117.435909, 45.493861 ], "pop" : 456, "state" : "OR" }
+{ "_id" : "97862", "city" : "MILTON FREEWATER", "loc" : [ -118.391172, 45.948581 ], "pop" : 9723, "state" : "OR" }
+{ "_id" : "97864", "city" : "MONUMENT", "loc" : [ -119.430164, 44.818451 ], "pop" : 410, "state" : "OR" }
+{ "_id" : "97865", "city" : "MOUNT VERNON", "loc" : [ -119.112142, 44.417095 ], "pop" : 538, "state" : "OR" }
+{ "_id" : "97867", "city" : "NORTH POWDER", "loc" : [ -117.933666, 45.031667 ], "pop" : 571, "state" : "OR" }
+{ "_id" : "97868", "city" : "PILOT ROCK", "loc" : [ -118.848331, 45.422724 ], "pop" : 2298, "state" : "OR" }
+{ "_id" : "97869", "city" : "PRAIRIE CITY", "loc" : [ -118.695199, 44.456977 ], "pop" : 1614, "state" : "OR" }
+{ "_id" : "97870", "city" : "RICHLAND", "loc" : [ -117.301825, 44.797013 ], "pop" : 927, "state" : "OR" }
+{ "_id" : "97872", "city" : "RITTER", "loc" : [ -118.941818, 44.95404 ], "pop" : 71, "state" : "OR" }
+{ "_id" : "97873", "city" : "SENECA", "loc" : [ -119.057797, 44.127704 ], "pop" : 352, "state" : "OR" }
+{ "_id" : "97874", "city" : "SPRAY", "loc" : [ -119.830318, 44.824186 ], "pop" : 438, "state" : "OR" }
+{ "_id" : "97875", "city" : "STANFIELD", "loc" : [ -119.211602, 45.785988 ], "pop" : 2031, "state" : "OR" }
+{ "_id" : "97876", "city" : "SUMMERVILLE", "loc" : [ -118.026978, 45.507687 ], "pop" : 773, "state" : "OR" }
+{ "_id" : "97877", "city" : "SUMPTER", "loc" : [ -118.190604, 44.73164 ], "pop" : 251, "state" : "OR" }
+{ "_id" : "97882", "city" : "MCNARY", "loc" : [ -119.313715, 45.915725 ], "pop" : 4009, "state" : "OR" }
+{ "_id" : "97883", "city" : "UNION", "loc" : [ -117.853554, 45.201939 ], "pop" : 2463, "state" : "OR" }
+{ "_id" : "97884", "city" : "UNITY", "loc" : [ -118.16273, 44.449063 ], "pop" : 315, "state" : "OR" }
+{ "_id" : "97885", "city" : "WALLOWA", "loc" : [ -117.535727, 45.571722 ], "pop" : 1250, "state" : "OR" }
+{ "_id" : "97886", "city" : "WESTON", "loc" : [ -118.373279, 45.807365 ], "pop" : 1007, "state" : "OR" }
+{ "_id" : "97901", "city" : "ADRIAN", "loc" : [ -117.060193, 43.653712 ], "pop" : 568, "state" : "OR" }
+{ "_id" : "97902", "city" : "AROCK", "loc" : [ -117.034189, 43.970896 ], "pop" : 846, "state" : "OR" }
+{ "_id" : "97903", "city" : "BROGAN", "loc" : [ -117.590371, 44.199396 ], "pop" : 205, "state" : "OR" }
+{ "_id" : "97904", "city" : "DREWSEY", "loc" : [ -118.47066, 43.864277 ], "pop" : 228, "state" : "OR" }
+{ "_id" : "97906", "city" : "HARPER", "loc" : [ -117.528433, 43.873363 ], "pop" : 326, "state" : "OR" }
+{ "_id" : "97907", "city" : "HUNTINGTON", "loc" : [ -117.309691, 44.381113 ], "pop" : 694, "state" : "OR" }
+{ "_id" : "97908", "city" : "IRONSIDE", "loc" : [ -117.944435, 44.300913 ], "pop" : 79, "state" : "OR" }
+{ "_id" : "97909", "city" : "JAMIESON", "loc" : [ -117.437269, 44.181873 ], "pop" : 53, "state" : "OR" }
+{ "_id" : "97910", "city" : "JORDAN VALLEY", "loc" : [ -117.280984, 42.880139 ], "pop" : 879, "state" : "OR" }
+{ "_id" : "97911", "city" : "JUNTURA", "loc" : [ -118.092118, 43.825277 ], "pop" : 83, "state" : "OR" }
+{ "_id" : "97913", "city" : "NYSSA", "loc" : [ -117.025113, 43.860386 ], "pop" : 5288, "state" : "OR" }
+{ "_id" : "97914", "city" : "ONTARIO", "loc" : [ -116.978268, 44.04156 ], "pop" : 13665, "state" : "OR" }
+{ "_id" : "97917", "city" : "RIVERSIDE", "loc" : [ -118.095769, 43.467415 ], "pop" : 65, "state" : "OR" }
+{ "_id" : "97918", "city" : "VALE", "loc" : [ -117.267412, 44.003902 ], "pop" : 3940, "state" : "OR" }
+{ "_id" : "97920", "city" : "WESTFALL", "loc" : [ -117.687673, 43.992246 ], "pop" : 41, "state" : "OR" }
+{ "_id" : "98001", "city" : "ALGONA", "loc" : [ -122.270057, 47.316339 ], "pop" : 22846, "state" : "WA" }
+{ "_id" : "98002", "city" : "AUBURN", "loc" : [ -122.206741, 47.30503 ], "pop" : 38163, "state" : "WA" }
+{ "_id" : "98003", "city" : "FEDERAL WAY", "loc" : [ -122.311726, 47.3203 ], "pop" : 34573, "state" : "WA" }
+{ "_id" : "98004", "city" : "BEAUX ARTS", "loc" : [ -122.207371, 47.619899 ], "pop" : 23724, "state" : "WA" }
+{ "_id" : "98005", "city" : "BELLEVUE", "loc" : [ -122.166288, 47.614961 ], "pop" : 14297, "state" : "WA" }
+{ "_id" : "98006", "city" : "BELLEVUE", "loc" : [ -122.155179, 47.561425 ], "pop" : 26775, "state" : "WA" }
+{ "_id" : "98007", "city" : "BELLEVUE", "loc" : [ -122.142572, 47.617443 ], "pop" : 21887, "state" : "WA" }
+{ "_id" : "98008", "city" : "BELLEVUE", "loc" : [ -122.116173, 47.611468 ], "pop" : 24046, "state" : "WA" }
+{ "_id" : "98010", "city" : "BLACK DIAMOND", "loc" : [ -122.005265, 47.311372 ], "pop" : 1817, "state" : "WA" }
+{ "_id" : "98011", "city" : "BOTHELL", "loc" : [ -122.2159, 47.749692 ], "pop" : 32985, "state" : "WA" }
+{ "_id" : "98012", "city" : "MILL CREEK", "loc" : [ -122.206981, 47.848941 ], "pop" : 19247, "state" : "WA" }
+{ "_id" : "98014", "city" : "CARNATION", "loc" : [ -121.911095, 47.638007 ], "pop" : 2808, "state" : "WA" }
+{ "_id" : "98019", "city" : "DUVALL", "loc" : [ -121.936906, 47.724987 ], "pop" : 7866, "state" : "WA" }
+{ "_id" : "98020", "city" : "WOODWAY", "loc" : [ -122.366949, 47.800693 ], "pop" : 17396, "state" : "WA" }
+{ "_id" : "98021", "city" : "BOTHELL", "loc" : [ -122.224339, 47.791806 ], "pop" : 18013, "state" : "WA" }
+{ "_id" : "98022", "city" : "ENUMCLAW", "loc" : [ -122.031429, 47.266545 ], "pop" : 34850, "state" : "WA" }
+{ "_id" : "98023", "city" : "FEDERAL WAY", "loc" : [ -122.36123, 47.310358 ], "pop" : 38292, "state" : "WA" }
+{ "_id" : "98024", "city" : "FALL CITY", "loc" : [ -121.889646, 47.568233 ], "pop" : 3213, "state" : "WA" }
+{ "_id" : "98026", "city" : "EDMONDS", "loc" : [ -122.334463, 47.823324 ], "pop" : 33385, "state" : "WA" }
+{ "_id" : "98027", "city" : "ISSAQUAH", "loc" : [ -122.033517, 47.550911 ], "pop" : 37255, "state" : "WA" }
+{ "_id" : "98031", "city" : "KENT", "loc" : [ -122.193184, 47.388004 ], "pop" : 50515, "state" : "WA" }
+{ "_id" : "98032", "city" : "KENT", "loc" : [ -122.285362, 47.377633 ], "pop" : 31379, "state" : "WA" }
+{ "_id" : "98033", "city" : "KIRKLAND", "loc" : [ -122.189442, 47.678597 ], "pop" : 28211, "state" : "WA" }
+{ "_id" : "98034", "city" : "KIRKLAND", "loc" : [ -122.196571, 47.718777 ], "pop" : 38266, "state" : "WA" }
+{ "_id" : "98036", "city" : "BRIER", "loc" : [ -122.287789, 47.811825 ], "pop" : 28602, "state" : "WA" }
+{ "_id" : "98037", "city" : "LYNNWOOD", "loc" : [ -122.282139, 47.850532 ], "pop" : 36995, "state" : "WA" }
+{ "_id" : "98038", "city" : "MAPLE VALLEY", "loc" : [ -122.057413, 47.384526 ], "pop" : 13768, "state" : "WA" }
+{ "_id" : "98040", "city" : "MERCER ISLAND", "loc" : [ -122.226562, 47.563149 ], "pop" : 20816, "state" : "WA" }
+{ "_id" : "98042", "city" : "KENT", "loc" : [ -122.120615, 47.368044 ], "pop" : 22576, "state" : "WA" }
+{ "_id" : "98043", "city" : "MOUNTLAKE TERRAC", "loc" : [ -122.304036, 47.793061 ], "pop" : 20059, "state" : "WA" }
+{ "_id" : "98045", "city" : "NORTH BEND", "loc" : [ -121.757142, 47.475546 ], "pop" : 10083, "state" : "WA" }
+{ "_id" : "98047", "city" : "PACIFIC", "loc" : [ -122.243481, 47.266605 ], "pop" : 3902, "state" : "WA" }
+{ "_id" : "98051", "city" : "RAVENSDALE", "loc" : [ -121.987897, 47.415476 ], "pop" : 3778, "state" : "WA" }
+{ "_id" : "98052", "city" : "REDMOND", "loc" : [ -122.123242, 47.671796 ], "pop" : 37639, "state" : "WA" }
+{ "_id" : "98053", "city" : "REDMOND", "loc" : [ -122.038578, 47.646238 ], "pop" : 22112, "state" : "WA" }
+{ "_id" : "98055", "city" : "RENTON", "loc" : [ -122.207484, 47.464759 ], "pop" : 17902, "state" : "WA" }
+{ "_id" : "98056", "city" : "RENTON", "loc" : [ -122.181942, 47.507336 ], "pop" : 23790, "state" : "WA" }
+{ "_id" : "98058", "city" : "RENTON", "loc" : [ -122.121586, 47.446507 ], "pop" : 10153, "state" : "WA" }
+{ "_id" : "98059", "city" : "RENTON", "loc" : [ -122.151178, 47.467383 ], "pop" : 48197, "state" : "WA" }
+{ "_id" : "98065", "city" : "SNOQUALMIE", "loc" : [ -121.822533, 47.529286 ], "pop" : 3913, "state" : "WA" }
+{ "_id" : "98070", "city" : "VASHON", "loc" : [ -122.464415, 47.425949 ], "pop" : 9309, "state" : "WA" }
+{ "_id" : "98072", "city" : "WOODINVILLE", "loc" : [ -122.127087, 47.768384 ], "pop" : 40666, "state" : "WA" }
+{ "_id" : "98101", "city" : "SEATTLE", "loc" : [ -122.330456, 47.611435 ], "pop" : 5801, "state" : "WA" }
+{ "_id" : "98102", "city" : "SEATTLE", "loc" : [ -122.320993, 47.63025 ], "pop" : 19000, "state" : "WA" }
+{ "_id" : "98103", "city" : "SEATTLE", "loc" : [ -122.342621, 47.67335 ], "pop" : 39491, "state" : "WA" }
+{ "_id" : "98104", "city" : "SEATTLE", "loc" : [ -122.325644, 47.603631 ], "pop" : 9680, "state" : "WA" }
+{ "_id" : "98105", "city" : "SEATTLE", "loc" : [ -122.302236, 47.663266 ], "pop" : 37120, "state" : "WA" }
+{ "_id" : "98106", "city" : "SEATTLE", "loc" : [ -122.354688, 47.534362 ], "pop" : 17510, "state" : "WA" }
+{ "_id" : "98107", "city" : "SEATTLE", "loc" : [ -122.37626, 47.67012 ], "pop" : 18288, "state" : "WA" }
+{ "_id" : "98108", "city" : "TUKWILA", "loc" : [ -122.306823, 47.547448 ], "pop" : 18776, "state" : "WA" }
+{ "_id" : "98109", "city" : "SEATTLE", "loc" : [ -122.347615, 47.633875 ], "pop" : 13401, "state" : "WA" }
+{ "_id" : "98110", "city" : "BAINBRIDGE ISLAN", "loc" : [ -122.531297, 47.645048 ], "pop" : 15846, "state" : "WA" }
+{ "_id" : "98112", "city" : "SEATTLE", "loc" : [ -122.297157, 47.630115 ], "pop" : 19760, "state" : "WA" }
+{ "_id" : "98115", "city" : "SEATTLE", "loc" : [ -122.296828, 47.684918 ], "pop" : 40454, "state" : "WA" }
+{ "_id" : "98116", "city" : "SEATTLE", "loc" : [ -122.393445, 47.574591 ], "pop" : 20408, "state" : "WA" }
+{ "_id" : "98117", "city" : "SEATTLE", "loc" : [ -122.377223, 47.687263 ], "pop" : 28572, "state" : "WA" }
+{ "_id" : "98118", "city" : "SEATTLE", "loc" : [ -122.275021, 47.541234 ], "pop" : 36684, "state" : "WA" }
+{ "_id" : "98119", "city" : "SEATTLE", "loc" : [ -122.364272, 47.637917 ], "pop" : 19064, "state" : "WA" }
+{ "_id" : "98121", "city" : "SEATTLE", "loc" : [ -122.344696, 47.615135 ], "pop" : 4091, "state" : "WA" }
+{ "_id" : "98122", "city" : "SEATTLE", "loc" : [ -122.305608, 47.611633 ], "pop" : 25105, "state" : "WA" }
+{ "_id" : "98125", "city" : "SEATTLE", "loc" : [ -122.301546, 47.717002 ], "pop" : 31928, "state" : "WA" }
+{ "_id" : "98126", "city" : "SEATTLE", "loc" : [ -122.373458, 47.544361 ], "pop" : 18627, "state" : "WA" }
+{ "_id" : "98133", "city" : "SEATTLE", "loc" : [ -122.343132, 47.737717 ], "pop" : 39634, "state" : "WA" }
+{ "_id" : "98134", "city" : "SEATTLE", "loc" : [ -122.326346, 47.590276 ], "pop" : 1437, "state" : "WA" }
+{ "_id" : "98136", "city" : "SEATTLE", "loc" : [ -122.387768, 47.539769 ], "pop" : 13816, "state" : "WA" }
+{ "_id" : "98144", "city" : "SEATTLE", "loc" : [ -122.300457, 47.584624 ], "pop" : 23333, "state" : "WA" }
+{ "_id" : "98146", "city" : "BURIEN", "loc" : [ -122.353989, 47.501069 ], "pop" : 25963, "state" : "WA" }
+{ "_id" : "98148", "city" : "NORMANDY PARK", "loc" : [ -122.326112, 47.450209 ], "pop" : 8818, "state" : "WA" }
+{ "_id" : "98155", "city" : "LK FOREST PARK", "loc" : [ -122.296305, 47.758161 ], "pop" : 38296, "state" : "WA" }
+{ "_id" : "98158", "city" : "SEATAC", "loc" : [ -122.318454, 47.442739 ], "pop" : 97, "state" : "WA" }
+{ "_id" : "98166", "city" : "NORMANDY PARK", "loc" : [ -122.347392, 47.455052 ], "pop" : 19331, "state" : "WA" }
+{ "_id" : "98168", "city" : "TUKWILA", "loc" : [ -122.302376, 47.48851 ], "pop" : 27990, "state" : "WA" }
+{ "_id" : "98177", "city" : "SEATTLE", "loc" : [ -122.368585, 47.746678 ], "pop" : 18532, "state" : "WA" }
+{ "_id" : "98178", "city" : "TUKWILA", "loc" : [ -122.247366, 47.499489 ], "pop" : 19522, "state" : "WA" }
+{ "_id" : "98188", "city" : "TUKWILA", "loc" : [ -122.281159, 47.449808 ], "pop" : 18001, "state" : "WA" }
+{ "_id" : "98198", "city" : "DES MOINES", "loc" : [ -122.309559, 47.407286 ], "pop" : 20550, "state" : "WA" }
+{ "_id" : "98199", "city" : "SEATTLE", "loc" : [ -122.396357, 47.648845 ], "pop" : 18360, "state" : "WA" }
+{ "_id" : "98201", "city" : "EVERETT", "loc" : [ -122.200571, 47.988431 ], "pop" : 26440, "state" : "WA" }
+{ "_id" : "98203", "city" : "EVERETT", "loc" : [ -122.221846, 47.941937 ], "pop" : 26506, "state" : "WA" }
+{ "_id" : "98204", "city" : "EVERETT", "loc" : [ -122.247217, 47.901659 ], "pop" : 20496, "state" : "WA" }
+{ "_id" : "98205", "city" : "EVERETT", "loc" : [ -122.115759, 47.990065 ], "pop" : 10083, "state" : "WA" }
+{ "_id" : "98208", "city" : "EVERETT", "loc" : [ -122.198722, 47.894822 ], "pop" : 32818, "state" : "WA" }
+{ "_id" : "98220", "city" : "ACME", "loc" : [ -122.191391, 48.675248 ], "pop" : 471, "state" : "WA" }
+{ "_id" : "98221", "city" : "ANACORTES", "loc" : [ -122.630873, 48.500438 ], "pop" : 12986, "state" : "WA" }
+{ "_id" : "98223", "city" : "ARLINGTON", "loc" : [ -122.112126, 48.18293 ], "pop" : 24435, "state" : "WA" }
+{ "_id" : "98224", "city" : "BARING", "loc" : [ -121.44757, 47.757787 ], "pop" : 210, "state" : "WA" }
+{ "_id" : "98225", "city" : "BELLINGHAM", "loc" : [ -122.488676, 48.748957 ], "pop" : 38415, "state" : "WA" }
+{ "_id" : "98226", "city" : "BELLINGHAM", "loc" : [ -122.441457, 48.762763 ], "pop" : 38518, "state" : "WA" }
+{ "_id" : "98230", "city" : "BLAINE", "loc" : [ -122.732327, 48.963572 ], "pop" : 7057, "state" : "WA" }
+{ "_id" : "98232", "city" : "BOW", "loc" : [ -122.413438, 48.562037 ], "pop" : 3245, "state" : "WA" }
+{ "_id" : "98233", "city" : "BURLINGTON", "loc" : [ -122.33449, 48.478577 ], "pop" : 9113, "state" : "WA" }
+{ "_id" : "98236", "city" : "CLINTON", "loc" : [ -122.391588, 47.950845 ], "pop" : 3242, "state" : "WA" }
+{ "_id" : "98237", "city" : "CONCRETE", "loc" : [ -121.664294, 48.530962 ], "pop" : 3217, "state" : "WA" }
+{ "_id" : "98239", "city" : "COUPEVILLE", "loc" : [ -122.682346, 48.218911 ], "pop" : 5753, "state" : "WA" }
+{ "_id" : "98240", "city" : "CUSTER", "loc" : [ -122.622571, 48.937412 ], "pop" : 2791, "state" : "WA" }
+{ "_id" : "98241", "city" : "DARRINGTON", "loc" : [ -121.591807, 48.249285 ], "pop" : 1761, "state" : "WA" }
+{ "_id" : "98244", "city" : "GLACIER", "loc" : [ -122.153957, 48.803366 ], "pop" : 2110, "state" : "WA" }
+{ "_id" : "98245", "city" : "EASTSOUND", "loc" : [ -122.937045, 48.665554 ], "pop" : 2259, "state" : "WA" }
+{ "_id" : "98247", "city" : "EVERSON", "loc" : [ -122.332474, 48.90447 ], "pop" : 6986, "state" : "WA" }
+{ "_id" : "98248", "city" : "FERNDALE", "loc" : [ -122.595293, 48.862531 ], "pop" : 13697, "state" : "WA" }
+{ "_id" : "98249", "city" : "FREELAND", "loc" : [ -122.564086, 48.03417 ], "pop" : 2321, "state" : "WA" }
+{ "_id" : "98250", "city" : "FRIDAY HARBOR", "loc" : [ -123.094717, 48.545416 ], "pop" : 2508, "state" : "WA" }
+{ "_id" : "98252", "city" : "GRANITE FALLS", "loc" : [ -121.942752, 48.078977 ], "pop" : 3634, "state" : "WA" }
+{ "_id" : "98253", "city" : "GREENBANK", "loc" : [ -122.587086, 48.124432 ], "pop" : 926, "state" : "WA" }
+{ "_id" : "98257", "city" : "LA CONNER", "loc" : [ -122.53134, 48.409306 ], "pop" : 3154, "state" : "WA" }
+{ "_id" : "98258", "city" : "LAKE STEVENS", "loc" : [ -122.067153, 48.017103 ], "pop" : 12728, "state" : "WA" }
+{ "_id" : "98260", "city" : "LANGLEY", "loc" : [ -122.452992, 48.018672 ], "pop" : 6036, "state" : "WA" }
+{ "_id" : "98261", "city" : "LOPEZ", "loc" : [ -122.967434, 48.520804 ], "pop" : 4147, "state" : "WA" }
+{ "_id" : "98262", "city" : "LUMMI ISLAND", "loc" : [ -122.682285, 48.712765 ], "pop" : 628, "state" : "WA" }
+{ "_id" : "98263", "city" : "LYMAN", "loc" : [ -122.016183, 48.525744 ], "pop" : 1887, "state" : "WA" }
+{ "_id" : "98264", "city" : "LYNDEN", "loc" : [ -122.459153, 48.937225 ], "pop" : 12896, "state" : "WA" }
+{ "_id" : "98270", "city" : "MARYSVILLE", "loc" : [ -122.156168, 48.065639 ], "pop" : 19966, "state" : "WA" }
+{ "_id" : "98271", "city" : "MARYSVILLE", "loc" : [ -122.197956, 48.096572 ], "pop" : 19743, "state" : "WA" }
+{ "_id" : "98272", "city" : "MONROE", "loc" : [ -121.947376, 47.85853 ], "pop" : 14143, "state" : "WA" }
+{ "_id" : "98273", "city" : "MOUNT VERNON", "loc" : [ -122.326548, 48.416427 ], "pop" : 30295, "state" : "WA" }
+{ "_id" : "98275", "city" : "MUKILTEO", "loc" : [ -122.301906, 47.919896 ], "pop" : 10373, "state" : "WA" }
+{ "_id" : "98277", "city" : "OAK HARBOR", "loc" : [ -122.637439, 48.315096 ], "pop" : 32450, "state" : "WA" }
+{ "_id" : "98278", "city" : "WHIDBEY ISLAND N", "loc" : [ -122.69005, 48.295271 ], "pop" : 3434, "state" : "WA" }
+{ "_id" : "98279", "city" : "OLGA", "loc" : [ -122.836224, 48.655526 ], "pop" : 1029, "state" : "WA" }
+{ "_id" : "98281", "city" : "POINT ROBERTS", "loc" : [ -123.055474, 48.987876 ], "pop" : 923, "state" : "WA" }
+{ "_id" : "98283", "city" : "ROCKPORT", "loc" : [ -121.555352, 48.470388 ], "pop" : 157, "state" : "WA" }
+{ "_id" : "98284", "city" : "SEDRO WOOLLEY", "loc" : [ -122.232943, 48.527405 ], "pop" : 14902, "state" : "WA" }
+{ "_id" : "98288", "city" : "SKYKOMISH", "loc" : [ -121.371297, 47.692158 ], "pop" : 388, "state" : "WA" }
+{ "_id" : "98290", "city" : "SNOHOMISH", "loc" : [ -122.071562, 47.895381 ], "pop" : 37327, "state" : "WA" }
+{ "_id" : "98292", "city" : "STANWOOD", "loc" : [ -122.377978, 48.201067 ], "pop" : 19288, "state" : "WA" }
+{ "_id" : "98294", "city" : "SULTAN", "loc" : [ -121.736869, 47.858942 ], "pop" : 7010, "state" : "WA" }
+{ "_id" : "98295", "city" : "SUMAS", "loc" : [ -122.207425, 48.970763 ], "pop" : 2537, "state" : "WA" }
+{ "_id" : "98303", "city" : "ANDERSON ISLAND", "loc" : [ -122.696025, 47.15872 ], "pop" : 548, "state" : "WA" }
+{ "_id" : "98304", "city" : "ASHFORD", "loc" : [ -121.989791, 46.753121 ], "pop" : 339, "state" : "WA" }
+{ "_id" : "98305", "city" : "BEAVER", "loc" : [ -124.305424, 48.067263 ], "pop" : 695, "state" : "WA" }
+{ "_id" : "98310", "city" : "BREMERTON", "loc" : [ -122.629913, 47.601916 ], "pop" : 49057, "state" : "WA" }
+{ "_id" : "98312", "city" : "BREMERTON", "loc" : [ -122.695786, 47.575424 ], "pop" : 28858, "state" : "WA" }
+{ "_id" : "98314", "city" : "PUGET SOUND NAVA", "loc" : [ -122.724354, 47.746255 ], "pop" : 708, "state" : "WA" }
+{ "_id" : "98315", "city" : "SILVERDALE", "loc" : [ -122.716106, 47.692017 ], "pop" : 3702, "state" : "WA" }
+{ "_id" : "98320", "city" : "BRINNON", "loc" : [ -122.937509, 47.677596 ], "pop" : 1049, "state" : "WA" }
+{ "_id" : "98321", "city" : "BUCKLEY", "loc" : [ -122.062098, 47.152449 ], "pop" : 10153, "state" : "WA" }
+{ "_id" : "98323", "city" : "CARBONADO", "loc" : [ -122.051339, 47.080242 ], "pop" : 495, "state" : "WA" }
+{ "_id" : "98325", "city" : "CHIMACUM", "loc" : [ -122.788323, 47.98607 ], "pop" : 1191, "state" : "WA" }
+{ "_id" : "98326", "city" : "CLALLAM BAY", "loc" : [ -124.201512, 48.225486 ], "pop" : 384, "state" : "WA" }
+{ "_id" : "98328", "city" : "EATONVILLE", "loc" : [ -122.269626, 46.870778 ], "pop" : 3972, "state" : "WA" }
+{ "_id" : "98329", "city" : "GIG HARBOR", "loc" : [ -122.7, 47.378579 ], "pop" : 6678, "state" : "WA" }
+{ "_id" : "98330", "city" : "ELBE", "loc" : [ -122.150344, 46.766607 ], "pop" : 103, "state" : "WA" }
+{ "_id" : "98331", "city" : "FORKS", "loc" : [ -124.398949, 47.928732 ], "pop" : 6657, "state" : "WA" }
+{ "_id" : "98332", "city" : "GIG HARBOR", "loc" : [ -122.600144, 47.3607 ], "pop" : 9138, "state" : "WA" }
+{ "_id" : "98333", "city" : "FOX ISLAND", "loc" : [ -122.628579, 47.25238 ], "pop" : 2017, "state" : "WA" }
+{ "_id" : "98335", "city" : "GIG HARBOR", "loc" : [ -122.608377, 47.300154 ], "pop" : 17299, "state" : "WA" }
+{ "_id" : "98336", "city" : "GLENOMA", "loc" : [ -122.099014, 46.528266 ], "pop" : 657, "state" : "WA" }
+{ "_id" : "98338", "city" : "GRAHAM", "loc" : [ -122.293648, 47.024575 ], "pop" : 11136, "state" : "WA" }
+{ "_id" : "98339", "city" : "PORT HADLOCK", "loc" : [ -122.768151, 48.034531 ], "pop" : 2574, "state" : "WA" }
+{ "_id" : "98340", "city" : "HANSVILLE", "loc" : [ -122.565509, 47.906143 ], "pop" : 1256, "state" : "WA" }
+{ "_id" : "98346", "city" : "KINGSTON", "loc" : [ -122.525503, 47.810844 ], "pop" : 5507, "state" : "WA" }
+{ "_id" : "98349", "city" : "HOME", "loc" : [ -122.74273, 47.247366 ], "pop" : 3373, "state" : "WA" }
+{ "_id" : "98351", "city" : "LONGBRANCH", "loc" : [ -122.756126, 47.200737 ], "pop" : 733, "state" : "WA" }
+{ "_id" : "98354", "city" : "MILTON", "loc" : [ -122.315514, 47.24827 ], "pop" : 3562, "state" : "WA" }
+{ "_id" : "98355", "city" : "MINERAL", "loc" : [ -122.186056, 46.709635 ], "pop" : 814, "state" : "WA" }
+{ "_id" : "98356", "city" : "MORTON", "loc" : [ -122.249573, 46.558056 ], "pop" : 2530, "state" : "WA" }
+{ "_id" : "98358", "city" : "NORDLAND", "loc" : [ -122.692553, 48.04321 ], "pop" : 738, "state" : "WA" }
+{ "_id" : "98359", "city" : "OLALLA", "loc" : [ -122.574512, 47.424088 ], "pop" : 3173, "state" : "WA" }
+{ "_id" : "98360", "city" : "ORTING", "loc" : [ -122.185978, 47.082206 ], "pop" : 4493, "state" : "WA" }
+{ "_id" : "98361", "city" : "PACKWOOD", "loc" : [ -121.655254, 46.650038 ], "pop" : 495, "state" : "WA" }
+{ "_id" : "98362", "city" : "PORT ANGELES", "loc" : [ -123.438442, 48.106489 ], "pop" : 30373, "state" : "WA" }
+{ "_id" : "98365", "city" : "PORT LUDLOW", "loc" : [ -122.689615, 47.922192 ], "pop" : 2229, "state" : "WA" }
+{ "_id" : "98366", "city" : "SOUTH PARK VILLA", "loc" : [ -122.615276, 47.504838 ], "pop" : 44359, "state" : "WA" }
+{ "_id" : "98368", "city" : "PORT TOWNSEND", "loc" : [ -122.794457, 48.104012 ], "pop" : 9870, "state" : "WA" }
+{ "_id" : "98370", "city" : "POULSBO", "loc" : [ -122.627721, 47.742278 ], "pop" : 20554, "state" : "WA" }
+{ "_id" : "98371", "city" : "PUYALLUP", "loc" : [ -122.315097, 47.199123 ], "pop" : 18207, "state" : "WA" }
+{ "_id" : "98372", "city" : "PUYALLUP", "loc" : [ -122.273415, 47.204202 ], "pop" : 17053, "state" : "WA" }
+{ "_id" : "98373", "city" : "PUYALLUP", "loc" : [ -122.321868, 47.128363 ], "pop" : 23219, "state" : "WA" }
+{ "_id" : "98374", "city" : "PUYALLUP", "loc" : [ -122.265248, 47.142427 ], "pop" : 21982, "state" : "WA" }
+{ "_id" : "98376", "city" : "QUILCENE", "loc" : [ -122.858304, 47.832429 ], "pop" : 1592, "state" : "WA" }
+{ "_id" : "98377", "city" : "RANDLE", "loc" : [ -121.855533, 46.549195 ], "pop" : 2620, "state" : "WA" }
+{ "_id" : "98380", "city" : "SEABECK", "loc" : [ -122.822685, 47.625497 ], "pop" : 2555, "state" : "WA" }
+{ "_id" : "98381", "city" : "SEKIU", "loc" : [ -124.468467, 48.303166 ], "pop" : 2582, "state" : "WA" }
+{ "_id" : "98382", "city" : "SEQUIM", "loc" : [ -123.119814, 48.088136 ], "pop" : 16523, "state" : "WA" }
+{ "_id" : "98383", "city" : "SILVERDALE", "loc" : [ -122.698054, 47.662139 ], "pop" : 12276, "state" : "WA" }
+{ "_id" : "98387", "city" : "SPANAWAY", "loc" : [ -122.394336, 47.073218 ], "pop" : 24035, "state" : "WA" }
+{ "_id" : "98388", "city" : "STEILACOOM", "loc" : [ -122.588837, 47.170369 ], "pop" : 6099, "state" : "WA" }
+{ "_id" : "98390", "city" : "BONNEY LAKE", "loc" : [ -122.180275, 47.188801 ], "pop" : 35436, "state" : "WA" }
+{ "_id" : "98392", "city" : "SUQUAMISH", "loc" : [ -122.557295, 47.734303 ], "pop" : 1880, "state" : "WA" }
+{ "_id" : "98394", "city" : "VAUGHN", "loc" : [ -122.773598, 47.330921 ], "pop" : 804, "state" : "WA" }
+{ "_id" : "98402", "city" : "TACOMA", "loc" : [ -122.440536, 47.254508 ], "pop" : 2994, "state" : "WA" }
+{ "_id" : "98403", "city" : "TACOMA", "loc" : [ -122.457538, 47.26428 ], "pop" : 7493, "state" : "WA" }
+{ "_id" : "98404", "city" : "TACOMA", "loc" : [ -122.412625, 47.211312 ], "pop" : 27135, "state" : "WA" }
+{ "_id" : "98405", "city" : "TACOMA", "loc" : [ -122.46435, 47.248351 ], "pop" : 23918, "state" : "WA" }
+{ "_id" : "98406", "city" : "TACOMA", "loc" : [ -122.499349, 47.26325 ], "pop" : 22971, "state" : "WA" }
+{ "_id" : "98407", "city" : "TACOMA", "loc" : [ -122.503881, 47.282479 ], "pop" : 19881, "state" : "WA" }
+{ "_id" : "98408", "city" : "TACOMA", "loc" : [ -122.444381, 47.207267 ], "pop" : 28753, "state" : "WA" }
+{ "_id" : "98409", "city" : "TACOMA", "loc" : [ -122.482503, 47.20381 ], "pop" : 25045, "state" : "WA" }
+{ "_id" : "98421", "city" : "TACOMA", "loc" : [ -122.401457, 47.266373 ], "pop" : 508, "state" : "WA" }
+{ "_id" : "98422", "city" : "TACOMA", "loc" : [ -122.398349, 47.294805 ], "pop" : 10385, "state" : "WA" }
+{ "_id" : "98424", "city" : "FIFE", "loc" : [ -122.350962, 47.243632 ], "pop" : 5626, "state" : "WA" }
+{ "_id" : "98433", "city" : "FORT LEWIS", "loc" : [ -122.583486, 47.100864 ], "pop" : 27463, "state" : "WA" }
+{ "_id" : "98439", "city" : "LAKEWOOD CENTER", "loc" : [ -122.529326, 47.122905 ], "pop" : 3064, "state" : "WA" }
+{ "_id" : "98443", "city" : "TACOMA", "loc" : [ -122.372815, 47.204369 ], "pop" : 5457, "state" : "WA" }
+{ "_id" : "98444", "city" : "PARKLAND", "loc" : [ -122.448842, 47.156553 ], "pop" : 27406, "state" : "WA" }
+{ "_id" : "98445", "city" : "PARKLAND", "loc" : [ -122.411614, 47.133967 ], "pop" : 20298, "state" : "WA" }
+{ "_id" : "98446", "city" : "PARKLAND", "loc" : [ -122.37189, 47.14041 ], "pop" : 7156, "state" : "WA" }
+{ "_id" : "98465", "city" : "TACOMA", "loc" : [ -122.527272, 47.249139 ], "pop" : 6919, "state" : "WA" }
+{ "_id" : "98466", "city" : "FIRCREST", "loc" : [ -122.53503, 47.22788 ], "pop" : 22719, "state" : "WA" }
+{ "_id" : "98467", "city" : "TACOMA", "loc" : [ -122.533562, 47.205395 ], "pop" : 12823, "state" : "WA" }
+{ "_id" : "98498", "city" : "LAKEWOOD CENTER", "loc" : [ -122.555357, 47.164269 ], "pop" : 28193, "state" : "WA" }
+{ "_id" : "98499", "city" : "LAKEWOOD CENTER", "loc" : [ -122.509074, 47.160786 ], "pop" : 20970, "state" : "WA" }
+{ "_id" : "98501", "city" : "OLYMPIA", "loc" : [ -122.876311, 47.012906 ], "pop" : 25979, "state" : "WA" }
+{ "_id" : "98502", "city" : "OLYMPIA", "loc" : [ -122.95214, 47.029828 ], "pop" : 40246, "state" : "WA" }
+{ "_id" : "98503", "city" : "LACEY", "loc" : [ -122.782665, 47.023967 ], "pop" : 43492, "state" : "WA" }
+{ "_id" : "98506", "city" : "LACEY", "loc" : [ -122.832844, 47.076259 ], "pop" : 24889, "state" : "WA" }
+{ "_id" : "98520", "city" : "ABERDEEN", "loc" : [ -123.79629, 46.984293 ], "pop" : 22346, "state" : "WA" }
+{ "_id" : "98524", "city" : "ALLYN", "loc" : [ -122.853571, 47.385004 ], "pop" : 2049, "state" : "WA" }
+{ "_id" : "98526", "city" : "AMANDA PARK", "loc" : [ -123.907375, 47.470579 ], "pop" : 470, "state" : "WA" }
+{ "_id" : "98528", "city" : "BEAR CREEK", "loc" : [ -122.822381, 47.454956 ], "pop" : 2351, "state" : "WA" }
+{ "_id" : "98531", "city" : "CENTRALIA", "loc" : [ -122.967068, 46.724635 ], "pop" : 17633, "state" : "WA" }
+{ "_id" : "98532", "city" : "CHEHALIS", "loc" : [ -122.965764, 46.638193 ], "pop" : 18065, "state" : "WA" }
+{ "_id" : "98533", "city" : "CINEBAR", "loc" : [ -122.566005, 46.567131 ], "pop" : 796, "state" : "WA" }
+{ "_id" : "98535", "city" : "COPALIS BEACH", "loc" : [ -124.135881, 47.065044 ], "pop" : 703, "state" : "WA" }
+{ "_id" : "98536", "city" : "COPALIS CROSSING", "loc" : [ -124.13471, 47.12535 ], "pop" : 685, "state" : "WA" }
+{ "_id" : "98537", "city" : "COSMOPOLIS", "loc" : [ -123.77394, 46.953789 ], "pop" : 1424, "state" : "WA" }
+{ "_id" : "98538", "city" : "CURTIS", "loc" : [ -123.156974, 46.558372 ], "pop" : 449, "state" : "WA" }
+{ "_id" : "98541", "city" : "ELMA", "loc" : [ -123.39969, 47.005813 ], "pop" : 7356, "state" : "WA" }
+{ "_id" : "98542", "city" : "ETHEL", "loc" : [ -122.776009, 46.53581 ], "pop" : 320, "state" : "WA" }
+{ "_id" : "98546", "city" : "GRAPEVIEW", "loc" : [ -122.949742, 47.305783 ], "pop" : 3234, "state" : "WA" }
+{ "_id" : "98547", "city" : "GRAYLAND", "loc" : [ -124.056194, 46.853201 ], "pop" : 1677, "state" : "WA" }
+{ "_id" : "98548", "city" : "HOODSPORT", "loc" : [ -123.173932, 47.423526 ], "pop" : 1165, "state" : "WA" }
+{ "_id" : "98550", "city" : "HOQUIAM", "loc" : [ -123.884169, 46.982269 ], "pop" : 9597, "state" : "WA" }
+{ "_id" : "98552", "city" : "HUMPTULIPS", "loc" : [ -123.971695, 47.135632 ], "pop" : 1301, "state" : "WA" }
+{ "_id" : "98555", "city" : "LILLIWAUP", "loc" : [ -123.063119, 47.512773 ], "pop" : 635, "state" : "WA" }
+{ "_id" : "98557", "city" : "MC CLEARY", "loc" : [ -123.273301, 47.053987 ], "pop" : 2644, "state" : "WA" }
+{ "_id" : "98560", "city" : "MATLOCK", "loc" : [ -123.337638, 47.177545 ], "pop" : 1716, "state" : "WA" }
+{ "_id" : "98562", "city" : "MOCLIPS", "loc" : [ -124.20438, 47.222619 ], "pop" : 574, "state" : "WA" }
+{ "_id" : "98563", "city" : "MONTESANO", "loc" : [ -123.500584, 47.09013 ], "pop" : 10079, "state" : "WA" }
+{ "_id" : "98564", "city" : "MOSSYROCK", "loc" : [ -122.478935, 46.513136 ], "pop" : 1390, "state" : "WA" }
+{ "_id" : "98568", "city" : "OAKVILLE", "loc" : [ -123.249329, 46.843366 ], "pop" : 1915, "state" : "WA" }
+{ "_id" : "98569", "city" : "OCEAN CITY", "loc" : [ -124.15323, 46.982905 ], "pop" : 2307, "state" : "WA" }
+{ "_id" : "98570", "city" : "ONALASKA", "loc" : [ -122.707503, 46.573016 ], "pop" : 3077, "state" : "WA" }
+{ "_id" : "98571", "city" : "PACIFIC BEACH", "loc" : [ -124.158833, 47.198144 ], "pop" : 122, "state" : "WA" }
+{ "_id" : "98572", "city" : "PE ELL", "loc" : [ -123.285244, 46.56558 ], "pop" : 921, "state" : "WA" }
+{ "_id" : "98575", "city" : "QUINAULT", "loc" : [ -123.803744, 47.448505 ], "pop" : 545, "state" : "WA" }
+{ "_id" : "98576", "city" : "RAINIER", "loc" : [ -122.679468, 46.882942 ], "pop" : 2397, "state" : "WA" }
+{ "_id" : "98577", "city" : "RAYMOND", "loc" : [ -123.692889, 46.671046 ], "pop" : 6144, "state" : "WA" }
+{ "_id" : "98579", "city" : "ROCHESTER", "loc" : [ -123.040634, 46.819295 ], "pop" : 8231, "state" : "WA" }
+{ "_id" : "98580", "city" : "ROY", "loc" : [ -122.448271, 46.956048 ], "pop" : 7730, "state" : "WA" }
+{ "_id" : "98581", "city" : "RYDERWOOD", "loc" : [ -123.043134, 46.375176 ], "pop" : 330, "state" : "WA" }
+{ "_id" : "98582", "city" : "SALKUM", "loc" : [ -122.645364, 46.515059 ], "pop" : 336, "state" : "WA" }
+{ "_id" : "98584", "city" : "SHELTON", "loc" : [ -123.072862, 47.20863 ], "pop" : 19074, "state" : "WA" }
+{ "_id" : "98585", "city" : "SILVER CREEK", "loc" : [ -122.475716, 46.549077 ], "pop" : 697, "state" : "WA" }
+{ "_id" : "98586", "city" : "SOUTH BEND", "loc" : [ -123.820315, 46.6544 ], "pop" : 2575, "state" : "WA" }
+{ "_id" : "98587", "city" : "TAHOLAH", "loc" : [ -124.2827, 47.340711 ], "pop" : 851, "state" : "WA" }
+{ "_id" : "98588", "city" : "TAHUYA", "loc" : [ -122.921126, 47.435618 ], "pop" : 3794, "state" : "WA" }
+{ "_id" : "98589", "city" : "TENINO", "loc" : [ -122.849269, 46.864119 ], "pop" : 6451, "state" : "WA" }
+{ "_id" : "98590", "city" : "TOKELAND", "loc" : [ -124.046008, 46.746874 ], "pop" : 891, "state" : "WA" }
+{ "_id" : "98591", "city" : "TOLEDO", "loc" : [ -122.826559, 46.439552 ], "pop" : 2829, "state" : "WA" }
+{ "_id" : "98592", "city" : "UNION", "loc" : [ -123.034364, 47.351305 ], "pop" : 1592, "state" : "WA" }
+{ "_id" : "98593", "city" : "VADER", "loc" : [ -122.958493, 46.398505 ], "pop" : 523, "state" : "WA" }
+{ "_id" : "98595", "city" : "WESTPORT", "loc" : [ -124.106055, 46.883619 ], "pop" : 2463, "state" : "WA" }
+{ "_id" : "98596", "city" : "WINLOCK", "loc" : [ -122.915806, 46.494014 ], "pop" : 5206, "state" : "WA" }
+{ "_id" : "98597", "city" : "YELM", "loc" : [ -122.588049, 46.920589 ], "pop" : 9553, "state" : "WA" }
+{ "_id" : "98601", "city" : "AMBOY", "loc" : [ -122.457418, 45.9195 ], "pop" : 1910, "state" : "WA" }
+{ "_id" : "98602", "city" : "APPLETON", "loc" : [ -121.148618, 45.909041 ], "pop" : 13, "state" : "WA" }
+{ "_id" : "98603", "city" : "ARIEL", "loc" : [ -122.46769, 45.995154 ], "pop" : 735, "state" : "WA" }
+{ "_id" : "98604", "city" : "BATTLE GROUND", "loc" : [ -122.531845, 45.790667 ], "pop" : 16072, "state" : "WA" }
+{ "_id" : "98605", "city" : "COOK", "loc" : [ -121.175778, 45.6341 ], "pop" : 954, "state" : "WA" }
+{ "_id" : "98606", "city" : "BRUSH PRAIRIE", "loc" : [ -122.484342, 45.730432 ], "pop" : 6663, "state" : "WA" }
+{ "_id" : "98607", "city" : "CAMAS", "loc" : [ -122.414231, 45.605772 ], "pop" : 12058, "state" : "WA" }
+{ "_id" : "98610", "city" : "CARSON", "loc" : [ -121.835138, 45.749332 ], "pop" : 2009, "state" : "WA" }
+{ "_id" : "98611", "city" : "CASTLE ROCK", "loc" : [ -122.9139, 46.278291 ], "pop" : 8455, "state" : "WA" }
+{ "_id" : "98612", "city" : "CATHLAMET", "loc" : [ -123.362716, 46.195383 ], "pop" : 2114, "state" : "WA" }
+{ "_id" : "98613", "city" : "CENTERVILLE", "loc" : [ -120.945973, 45.703183 ], "pop" : 681, "state" : "WA" }
+{ "_id" : "98616", "city" : "COUGAR", "loc" : [ -122.294186, 46.069012 ], "pop" : 122, "state" : "WA" }
+{ "_id" : "98619", "city" : "GLENWOOD", "loc" : [ -121.28849, 46.007104 ], "pop" : 549, "state" : "WA" }
+{ "_id" : "98620", "city" : "GOLDENDALE", "loc" : [ -120.812981, 45.832021 ], "pop" : 5761, "state" : "WA" }
+{ "_id" : "98621", "city" : "GRAYS RIVER", "loc" : [ -123.588845, 46.353481 ], "pop" : 209, "state" : "WA" }
+{ "_id" : "98624", "city" : "ILWACO", "loc" : [ -124.02822, 46.314214 ], "pop" : 1210, "state" : "WA" }
+{ "_id" : "98625", "city" : "KALAMA", "loc" : [ -122.816588, 46.011229 ], "pop" : 3627, "state" : "WA" }
+{ "_id" : "98626", "city" : "KELSO", "loc" : [ -122.886994, 46.148491 ], "pop" : 20593, "state" : "WA" }
+{ "_id" : "98628", "city" : "KLICKITAT", "loc" : [ -121.229231, 45.751534 ], "pop" : 23, "state" : "WA" }
+{ "_id" : "98629", "city" : "LA CENTER", "loc" : [ -122.623972, 45.880587 ], "pop" : 3969, "state" : "WA" }
+{ "_id" : "98631", "city" : "LONG BEACH", "loc" : [ -124.047041, 46.377369 ], "pop" : 3648, "state" : "WA" }
+{ "_id" : "98632", "city" : "LONGVIEW", "loc" : [ -122.963421, 46.151354 ], "pop" : 42028, "state" : "WA" }
+{ "_id" : "98635", "city" : "LYLE", "loc" : [ -121.250112, 45.74495 ], "pop" : 1583, "state" : "WA" }
+{ "_id" : "98638", "city" : "NASELLE", "loc" : [ -123.804381, 46.352758 ], "pop" : 2177, "state" : "WA" }
+{ "_id" : "98640", "city" : "OCEAN PARK", "loc" : [ -124.043582, 46.502867 ], "pop" : 2601, "state" : "WA" }
+{ "_id" : "98642", "city" : "RIDGEFIELD", "loc" : [ -122.693354, 45.784634 ], "pop" : 7845, "state" : "WA" }
+{ "_id" : "98643", "city" : "ROSBURG", "loc" : [ -123.657105, 46.307076 ], "pop" : 279, "state" : "WA" }
+{ "_id" : "98645", "city" : "SILVERLAKE", "loc" : [ -122.764886, 46.316322 ], "pop" : 927, "state" : "WA" }
+{ "_id" : "98647", "city" : "SKAMOKAWA", "loc" : [ -123.43316, 46.295186 ], "pop" : 361, "state" : "WA" }
+{ "_id" : "98648", "city" : "STEVENSON", "loc" : [ -121.909346, 45.688173 ], "pop" : 3203, "state" : "WA" }
+{ "_id" : "98649", "city" : "TOUTLE", "loc" : [ -122.647696, 46.295605 ], "pop" : 599, "state" : "WA" }
+{ "_id" : "98650", "city" : "TROUT LAKE", "loc" : [ -121.516272, 45.982789 ], "pop" : 766, "state" : "WA" }
+{ "_id" : "98651", "city" : "UNDERWOOD", "loc" : [ -121.597408, 45.740872 ], "pop" : 1161, "state" : "WA" }
+{ "_id" : "98660", "city" : "VANCOUVER", "loc" : [ -122.68014, 45.64183 ], "pop" : 10432, "state" : "WA" }
+{ "_id" : "98661", "city" : "VANCOUVER", "loc" : [ -122.625146, 45.641807 ], "pop" : 28837, "state" : "WA" }
+{ "_id" : "98662", "city" : "ORCHARDS", "loc" : [ -122.576182, 45.674519 ], "pop" : 17842, "state" : "WA" }
+{ "_id" : "98663", "city" : "VANCOUVER", "loc" : [ -122.660385, 45.6514 ], "pop" : 13198, "state" : "WA" }
+{ "_id" : "98664", "city" : "VANCOUVER", "loc" : [ -122.576741, 45.623086 ], "pop" : 17179, "state" : "WA" }
+{ "_id" : "98665", "city" : "HAZEL DELL", "loc" : [ -122.664223, 45.68217 ], "pop" : 16488, "state" : "WA" }
+{ "_id" : "98670", "city" : "WAHKIACUS", "loc" : [ -121.148586, 45.815567 ], "pop" : 442, "state" : "WA" }
+{ "_id" : "98671", "city" : "WASHOUGAL", "loc" : [ -122.310396, 45.595921 ], "pop" : 10873, "state" : "WA" }
+{ "_id" : "98672", "city" : "WHITE SALMON", "loc" : [ -121.479459, 45.755142 ], "pop" : 5396, "state" : "WA" }
+{ "_id" : "98674", "city" : "WOODLAND", "loc" : [ -122.71256, 45.921859 ], "pop" : 6266, "state" : "WA" }
+{ "_id" : "98675", "city" : "YACOLT", "loc" : [ -122.427545, 45.862247 ], "pop" : 3295, "state" : "WA" }
+{ "_id" : "98682", "city" : "VANCOUVER", "loc" : [ -122.521224, 45.664399 ], "pop" : 21359, "state" : "WA" }
+{ "_id" : "98684", "city" : "CASCADE PARK", "loc" : [ -122.524969, 45.617522 ], "pop" : 26400, "state" : "WA" }
+{ "_id" : "98685", "city" : "FELIDA", "loc" : [ -122.682474, 45.707313 ], "pop" : 13972, "state" : "WA" }
+{ "_id" : "98686", "city" : "VANCOUVER", "loc" : [ -122.632226, 45.712017 ], "pop" : 9966, "state" : "WA" }
+{ "_id" : "98801", "city" : "WENATCHEE", "loc" : [ -120.327345, 47.425269 ], "pop" : 28906, "state" : "WA" }
+{ "_id" : "98802", "city" : "EAST WENATCHEE", "loc" : [ -120.273136, 47.418596 ], "pop" : 17975, "state" : "WA" }
+{ "_id" : "98812", "city" : "BREWSTER", "loc" : [ -119.771999, 48.120641 ], "pop" : 3177, "state" : "WA" }
+{ "_id" : "98813", "city" : "BRIDGEPORT", "loc" : [ -119.702772, 48.016083 ], "pop" : 2757, "state" : "WA" }
+{ "_id" : "98814", "city" : "CARLTON", "loc" : [ -120.10551, 48.252615 ], "pop" : 332, "state" : "WA" }
+{ "_id" : "98815", "city" : "CASHMERE", "loc" : [ -120.503274, 47.517293 ], "pop" : 7504, "state" : "WA" }
+{ "_id" : "98816", "city" : "CHELAN", "loc" : [ -120.027306, 47.848263 ], "pop" : 4949, "state" : "WA" }
+{ "_id" : "98822", "city" : "ENTIAT", "loc" : [ -120.276031, 47.705653 ], "pop" : 1507, "state" : "WA" }
+{ "_id" : "98823", "city" : "EPHRATA", "loc" : [ -119.533582, 47.277051 ], "pop" : 8779, "state" : "WA" }
+{ "_id" : "98826", "city" : "LEAVENWORTH", "loc" : [ -120.674792, 47.6438 ], "pop" : 4288, "state" : "WA" }
+{ "_id" : "98827", "city" : "LOOMIS", "loc" : [ -119.642675, 48.869627 ], "pop" : 329, "state" : "WA" }
+{ "_id" : "98828", "city" : "MALAGA", "loc" : [ -120.208562, 47.355306 ], "pop" : 1633, "state" : "WA" }
+{ "_id" : "98830", "city" : "MANSFIELD", "loc" : [ -119.405315, 47.902136 ], "pop" : 960, "state" : "WA" }
+{ "_id" : "98831", "city" : "MANSON", "loc" : [ -120.148963, 47.895764 ], "pop" : 2309, "state" : "WA" }
+{ "_id" : "98832", "city" : "MARLIN", "loc" : [ -119.090897, 47.320929 ], "pop" : 856, "state" : "WA" }
+{ "_id" : "98833", "city" : "MAZAMA", "loc" : [ -120.38796, 48.597728 ], "pop" : 115, "state" : "WA" }
+{ "_id" : "98834", "city" : "METHOW", "loc" : [ -120.0059, 48.09001 ], "pop" : 623, "state" : "WA" }
+{ "_id" : "98837", "city" : "MOSES LAKE", "loc" : [ -119.289149, 47.137363 ], "pop" : 22935, "state" : "WA" }
+{ "_id" : "98840", "city" : "OKANOGAN", "loc" : [ -119.604563, 48.351328 ], "pop" : 3782, "state" : "WA" }
+{ "_id" : "98841", "city" : "OMAK", "loc" : [ -119.527156, 48.414347 ], "pop" : 6059, "state" : "WA" }
+{ "_id" : "98843", "city" : "ORONDO", "loc" : [ -120.172143, 47.696928 ], "pop" : 1424, "state" : "WA" }
+{ "_id" : "98844", "city" : "OROVILLE", "loc" : [ -119.403236, 48.939681 ], "pop" : 3283, "state" : "WA" }
+{ "_id" : "98845", "city" : "PALISADES", "loc" : [ -119.802264, 47.469367 ], "pop" : 36, "state" : "WA" }
+{ "_id" : "98846", "city" : "PATEROS", "loc" : [ -119.913322, 48.059147 ], "pop" : 696, "state" : "WA" }
+{ "_id" : "98847", "city" : "PESHASTIN", "loc" : [ -120.613928, 47.581294 ], "pop" : 1030, "state" : "WA" }
+{ "_id" : "98848", "city" : "QUINCY", "loc" : [ -119.845922, 47.197574 ], "pop" : 7429, "state" : "WA" }
+{ "_id" : "98849", "city" : "RIVERSIDE", "loc" : [ -119.580316, 48.487567 ], "pop" : 1871, "state" : "WA" }
+{ "_id" : "98850", "city" : "ROCK ISLAND", "loc" : [ -120.137794, 47.370558 ], "pop" : 1336, "state" : "WA" }
+{ "_id" : "98851", "city" : "SOAP LAKE", "loc" : [ -119.485962, 47.383034 ], "pop" : 2482, "state" : "WA" }
+{ "_id" : "98852", "city" : "STEHEKIN", "loc" : [ -120.755185, 48.298034 ], "pop" : 124, "state" : "WA" }
+{ "_id" : "98855", "city" : "TONASKET", "loc" : [ -119.394252, 48.71944 ], "pop" : 4921, "state" : "WA" }
+{ "_id" : "98856", "city" : "TWISP", "loc" : [ -120.135035, 48.363231 ], "pop" : 1938, "state" : "WA" }
+{ "_id" : "98857", "city" : "WARDEN", "loc" : [ -119.053932, 46.97697 ], "pop" : 2678, "state" : "WA" }
+{ "_id" : "98858", "city" : "WATERVILLE", "loc" : [ -119.988743, 47.62951 ], "pop" : 1717, "state" : "WA" }
+{ "_id" : "98859", "city" : "WAUCONDA", "loc" : [ -118.946947, 48.822449 ], "pop" : 325, "state" : "WA" }
+{ "_id" : "98862", "city" : "WINTHROP", "loc" : [ -120.180468, 48.475607 ], "pop" : 1263, "state" : "WA" }
+{ "_id" : "98901", "city" : "TERRACE HEIGHTS", "loc" : [ -120.477336, 46.606991 ], "pop" : 22057, "state" : "WA" }
+{ "_id" : "98902", "city" : "YAKIMA", "loc" : [ -120.531084, 46.593393 ], "pop" : 39091, "state" : "WA" }
+{ "_id" : "98903", "city" : "UNION GAP", "loc" : [ -120.556587, 46.5572 ], "pop" : 10498, "state" : "WA" }
+{ "_id" : "98908", "city" : "WIDE HOLLOW", "loc" : [ -120.605175, 46.605865 ], "pop" : 27078, "state" : "WA" }
+{ "_id" : "98922", "city" : "CLE ELUM", "loc" : [ -120.968505, 47.206319 ], "pop" : 5299, "state" : "WA" }
+{ "_id" : "98923", "city" : "COWICHE", "loc" : [ -120.714893, 46.66611 ], "pop" : 920, "state" : "WA" }
+{ "_id" : "98926", "city" : "ELLENSBURG", "loc" : [ -120.516274, 46.999632 ], "pop" : 20344, "state" : "WA" }
+{ "_id" : "98930", "city" : "GRANDVIEW", "loc" : [ -119.915734, 46.253846 ], "pop" : 10558, "state" : "WA" }
+{ "_id" : "98932", "city" : "GRANGER", "loc" : [ -120.181848, 46.348045 ], "pop" : 3562, "state" : "WA" }
+{ "_id" : "98933", "city" : "HARRAH", "loc" : [ -120.573606, 46.410383 ], "pop" : 2643, "state" : "WA" }
+{ "_id" : "98935", "city" : "MABTON", "loc" : [ -120.015141, 46.212082 ], "pop" : 3586, "state" : "WA" }
+{ "_id" : "98936", "city" : "MOXEE", "loc" : [ -120.368463, 46.554205 ], "pop" : 4194, "state" : "WA" }
+{ "_id" : "98937", "city" : "WHITE PASS", "loc" : [ -120.826699, 46.735335 ], "pop" : 2996, "state" : "WA" }
+{ "_id" : "98938", "city" : "OUTLOOK", "loc" : [ -120.097005, 46.352497 ], "pop" : 1705, "state" : "WA" }
+{ "_id" : "98942", "city" : "SELAH", "loc" : [ -120.540813, 46.67671 ], "pop" : 12507, "state" : "WA" }
+{ "_id" : "98944", "city" : "SUNNYSIDE", "loc" : [ -120.012631, 46.321273 ], "pop" : 16774, "state" : "WA" }
+{ "_id" : "98946", "city" : "THORP", "loc" : [ -120.678557, 47.017785 ], "pop" : 1082, "state" : "WA" }
+{ "_id" : "98947", "city" : "TIETON", "loc" : [ -120.747275, 46.706331 ], "pop" : 2079, "state" : "WA" }
+{ "_id" : "98948", "city" : "TOPPENISH", "loc" : [ -120.330534, 46.375123 ], "pop" : 11101, "state" : "WA" }
+{ "_id" : "98951", "city" : "WAPATO", "loc" : [ -120.426484, 46.45066 ], "pop" : 10262, "state" : "WA" }
+{ "_id" : "98952", "city" : "WHITE SWAN", "loc" : [ -120.745317, 46.371558 ], "pop" : 1941, "state" : "WA" }
+{ "_id" : "98953", "city" : "ZILLAH", "loc" : [ -120.266161, 46.415777 ], "pop" : 5266, "state" : "WA" }
+{ "_id" : "99003", "city" : "CHATTAROY", "loc" : [ -117.29209, 47.919178 ], "pop" : 1991, "state" : "WA" }
+{ "_id" : "99004", "city" : "CHENEY", "loc" : [ -117.583372, 47.494257 ], "pop" : 12257, "state" : "WA" }
+{ "_id" : "99005", "city" : "COLBERT", "loc" : [ -117.375895, 47.841093 ], "pop" : 3926, "state" : "WA" }
+{ "_id" : "99006", "city" : "DEER PARK", "loc" : [ -117.443559, 47.948615 ], "pop" : 7287, "state" : "WA" }
+{ "_id" : "99008", "city" : "EDWALL", "loc" : [ -117.907095, 47.537896 ], "pop" : 379, "state" : "WA" }
+{ "_id" : "99009", "city" : "ELK", "loc" : [ -117.296253, 48.020523 ], "pop" : 2386, "state" : "WA" }
+{ "_id" : "99011", "city" : "FAIRCHILD AIR FO", "loc" : [ -117.643746, 47.613068 ], "pop" : 4854, "state" : "WA" }
+{ "_id" : "99012", "city" : "FAIRFIELD", "loc" : [ -117.192054, 47.398726 ], "pop" : 641, "state" : "WA" }
+{ "_id" : "99013", "city" : "FORD", "loc" : [ -117.811858, 47.916873 ], "pop" : 790, "state" : "WA" }
+{ "_id" : "99016", "city" : "GREENACRES", "loc" : [ -117.156801, 47.658357 ], "pop" : 5312, "state" : "WA" }
+{ "_id" : "99017", "city" : "LAMONT", "loc" : [ -117.830239, 47.17304 ], "pop" : 317, "state" : "WA" }
+{ "_id" : "99018", "city" : "LATAH", "loc" : [ -117.16884, 47.303815 ], "pop" : 477, "state" : "WA" }
+{ "_id" : "99019", "city" : "LIBERTY LAKE", "loc" : [ -117.083808, 47.651672 ], "pop" : 2372, "state" : "WA" }
+{ "_id" : "99021", "city" : "MEAD", "loc" : [ -117.311716, 47.793268 ], "pop" : 5903, "state" : "WA" }
+{ "_id" : "99022", "city" : "ESPANOLA", "loc" : [ -117.679351, 47.583696 ], "pop" : 6436, "state" : "WA" }
+{ "_id" : "99023", "city" : "MICA", "loc" : [ -117.163711, 47.553814 ], "pop" : 921, "state" : "WA" }
+{ "_id" : "99025", "city" : "NEWMAN LAKE", "loc" : [ -117.064041, 47.727371 ], "pop" : 3092, "state" : "WA" }
+{ "_id" : "99026", "city" : "NINE MILE FALLS", "loc" : [ -117.589359, 47.801945 ], "pop" : 4872, "state" : "WA" }
+{ "_id" : "99027", "city" : "OTIS ORCHARDS", "loc" : [ -117.11209, 47.70273 ], "pop" : 5922, "state" : "WA" }
+{ "_id" : "99029", "city" : "REARDAN", "loc" : [ -117.866264, 47.705407 ], "pop" : 1072, "state" : "WA" }
+{ "_id" : "99030", "city" : "ROCKFORD", "loc" : [ -117.131842, 47.452804 ], "pop" : 844, "state" : "WA" }
+{ "_id" : "99031", "city" : "SPANGLE", "loc" : [ -117.382696, 47.4338 ], "pop" : 1434, "state" : "WA" }
+{ "_id" : "99032", "city" : "SPRAGUE", "loc" : [ -117.989684, 47.324725 ], "pop" : 672, "state" : "WA" }
+{ "_id" : "99033", "city" : "TEKOA", "loc" : [ -117.081919, 47.227081 ], "pop" : 950, "state" : "WA" }
+{ "_id" : "99034", "city" : "TUMTUM", "loc" : [ -117.698996, 47.898173 ], "pop" : 312, "state" : "WA" }
+{ "_id" : "99036", "city" : "VALLEYFORD", "loc" : [ -117.268601, 47.529176 ], "pop" : 698, "state" : "WA" }
+{ "_id" : "99037", "city" : "VERADALE", "loc" : [ -117.197706, 47.642103 ], "pop" : 8397, "state" : "WA" }
+{ "_id" : "99039", "city" : "WAVERLY", "loc" : [ -117.233108, 47.335393 ], "pop" : 166, "state" : "WA" }
+{ "_id" : "99040", "city" : "WELLPINIT", "loc" : [ -117.985646, 47.86974 ], "pop" : 488, "state" : "WA" }
+{ "_id" : "99101", "city" : "ADDY", "loc" : [ -117.892383, 48.44769 ], "pop" : 1226, "state" : "WA" }
+{ "_id" : "99103", "city" : "ALMIRA", "loc" : [ -118.91225, 47.763175 ], "pop" : 646, "state" : "WA" }
+{ "_id" : "99105", "city" : "BENGE", "loc" : [ -117.969895, 46.867636 ], "pop" : 2, "state" : "WA" }
+{ "_id" : "99107", "city" : "BOYDS", "loc" : [ -118.19906, 48.691919 ], "pop" : 782, "state" : "WA" }
+{ "_id" : "99109", "city" : "CHEWELAH", "loc" : [ -117.77539, 48.287585 ], "pop" : 5239, "state" : "WA" }
+{ "_id" : "99110", "city" : "CLAYTON", "loc" : [ -117.574021, 47.955206 ], "pop" : 1621, "state" : "WA" }
+{ "_id" : "99111", "city" : "COLFAX", "loc" : [ -117.366975, 46.879996 ], "pop" : 3592, "state" : "WA" }
+{ "_id" : "99113", "city" : "COLTON", "loc" : [ -117.169243, 46.590098 ], "pop" : 650, "state" : "WA" }
+{ "_id" : "99114", "city" : "COLVILLE", "loc" : [ -117.864463, 48.57799 ], "pop" : 8805, "state" : "WA" }
+{ "_id" : "99115", "city" : "COULEE CITY", "loc" : [ -119.27582, 47.596571 ], "pop" : 1013, "state" : "WA" }
+{ "_id" : "99116", "city" : "COULEE DAM", "loc" : [ -119.180907, 48.173861 ], "pop" : 4636, "state" : "WA" }
+{ "_id" : "99117", "city" : "CRESTON", "loc" : [ -118.530656, 47.797681 ], "pop" : 527, "state" : "WA" }
+{ "_id" : "99118", "city" : "CURLEW", "loc" : [ -118.645182, 48.910775 ], "pop" : 986, "state" : "WA" }
+{ "_id" : "99119", "city" : "CUSICK", "loc" : [ -117.329464, 48.391513 ], "pop" : 439, "state" : "WA" }
+{ "_id" : "99121", "city" : "DANVILLE", "loc" : [ -118.488408, 48.972524 ], "pop" : 48, "state" : "WA" }
+{ "_id" : "99122", "city" : "DAVENPORT", "loc" : [ -118.166657, 47.680855 ], "pop" : 2383, "state" : "WA" }
+{ "_id" : "99123", "city" : "ELECTRIC CITY", "loc" : [ -119.036728, 47.926446 ], "pop" : 1152, "state" : "WA" }
+{ "_id" : "99125", "city" : "ENDICOTT", "loc" : [ -117.723005, 46.936407 ], "pop" : 673, "state" : "WA" }
+{ "_id" : "99126", "city" : "EVANS", "loc" : [ -118.00012, 48.745787 ], "pop" : 350, "state" : "WA" }
+{ "_id" : "99128", "city" : "FARMINGTON", "loc" : [ -117.076327, 47.084742 ], "pop" : 355, "state" : "WA" }
+{ "_id" : "99129", "city" : "FRUITLAND", "loc" : [ -118.215906, 47.979746 ], "pop" : 515, "state" : "WA" }
+{ "_id" : "99130", "city" : "GARFIELD", "loc" : [ -117.152293, 46.994639 ], "pop" : 795, "state" : "WA" }
+{ "_id" : "99131", "city" : "GIFFORD", "loc" : [ -118.12989, 48.22287 ], "pop" : 60, "state" : "WA" }
+{ "_id" : "99133", "city" : "GRAND COULEE", "loc" : [ -118.997835, 47.938511 ], "pop" : 1073, "state" : "WA" }
+{ "_id" : "99134", "city" : "HARRINGTON", "loc" : [ -118.277793, 47.4555 ], "pop" : 786, "state" : "WA" }
+{ "_id" : "99135", "city" : "HARTLINE", "loc" : [ -119.104467, 47.725631 ], "pop" : 315, "state" : "WA" }
+{ "_id" : "99137", "city" : "HUNTERS", "loc" : [ -118.152491, 48.133261 ], "pop" : 349, "state" : "WA" }
+{ "_id" : "99138", "city" : "INCHELIUM", "loc" : [ -118.355166, 48.292411 ], "pop" : 1297, "state" : "WA" }
+{ "_id" : "99139", "city" : "IONE", "loc" : [ -117.404859, 48.713023 ], "pop" : 1204, "state" : "WA" }
+{ "_id" : "99140", "city" : "KELLER", "loc" : [ -118.654731, 48.023594 ], "pop" : 255, "state" : "WA" }
+{ "_id" : "99141", "city" : "KETTLE FALLS", "loc" : [ -118.054801, 48.636375 ], "pop" : 3668, "state" : "WA" }
+{ "_id" : "99143", "city" : "LACROSSE", "loc" : [ -117.770277, 46.771684 ], "pop" : 1066, "state" : "WA" }
+{ "_id" : "99147", "city" : "LINCOLN", "loc" : [ -118.481012, 47.78204 ], "pop" : 31, "state" : "WA" }
+{ "_id" : "99148", "city" : "LOON LAKE", "loc" : [ -117.632496, 48.078393 ], "pop" : 1885, "state" : "WA" }
+{ "_id" : "99150", "city" : "MALO", "loc" : [ -118.623712, 48.81862 ], "pop" : 396, "state" : "WA" }
+{ "_id" : "99153", "city" : "METALINE FALLS", "loc" : [ -117.36332, 48.859747 ], "pop" : 729, "state" : "WA" }
+{ "_id" : "99156", "city" : "NEWPORT", "loc" : [ -117.150784, 48.169465 ], "pop" : 5881, "state" : "WA" }
+{ "_id" : "99157", "city" : "NORTHPORT", "loc" : [ -117.793052, 48.924663 ], "pop" : 462, "state" : "WA" }
+{ "_id" : "99158", "city" : "OAKESDALE", "loc" : [ -117.280326, 47.080556 ], "pop" : 764, "state" : "WA" }
+{ "_id" : "99159", "city" : "ODESSA", "loc" : [ -118.698316, 47.339491 ], "pop" : 1324, "state" : "WA" }
+{ "_id" : "99161", "city" : "PALOUSE", "loc" : [ -117.085475, 46.907555 ], "pop" : 1270, "state" : "WA" }
+{ "_id" : "99163", "city" : "PULLMAN", "loc" : [ -117.172936, 46.735247 ], "pop" : 25909, "state" : "WA" }
+{ "_id" : "99166", "city" : "REPUBLIC", "loc" : [ -118.699942, 48.670366 ], "pop" : 2531, "state" : "WA" }
+{ "_id" : "99167", "city" : "RICE", "loc" : [ -118.124865, 48.406169 ], "pop" : 615, "state" : "WA" }
+{ "_id" : "99169", "city" : "RITZVILLE", "loc" : [ -118.395812, 47.131528 ], "pop" : 2472, "state" : "WA" }
+{ "_id" : "99170", "city" : "ROSALIA", "loc" : [ -117.41468, 47.221777 ], "pop" : 1081, "state" : "WA" }
+{ "_id" : "99171", "city" : "SAINT JOHN", "loc" : [ -117.573002, 47.075539 ], "pop" : 765, "state" : "WA" }
+{ "_id" : "99173", "city" : "SPRINGDALE", "loc" : [ -117.873273, 47.992737 ], "pop" : 361, "state" : "WA" }
+{ "_id" : "99176", "city" : "THORNTON", "loc" : [ -117.386416, 47.12525 ], "pop" : 186, "state" : "WA" }
+{ "_id" : "99179", "city" : "UNIONTOWN", "loc" : [ -117.090756, 46.525818 ], "pop" : 433, "state" : "WA" }
+{ "_id" : "99180", "city" : "USK", "loc" : [ -117.318947, 48.295969 ], "pop" : 501, "state" : "WA" }
+{ "_id" : "99181", "city" : "VALLEY", "loc" : [ -117.760967, 48.135114 ], "pop" : 1328, "state" : "WA" }
+{ "_id" : "99185", "city" : "WILBUR", "loc" : [ -118.706271, 47.741012 ], "pop" : 1238, "state" : "WA" }
+{ "_id" : "99201", "city" : "SPOKANE", "loc" : [ -117.436527, 47.666485 ], "pop" : 9599, "state" : "WA" }
+{ "_id" : "99202", "city" : "SPOKANE", "loc" : [ -117.380972, 47.654741 ], "pop" : 17424, "state" : "WA" }
+{ "_id" : "99203", "city" : "SPOKANE", "loc" : [ -117.404121, 47.629443 ], "pop" : 20454, "state" : "WA" }
+{ "_id" : "99204", "city" : "SPOKANE", "loc" : [ -117.471896, 47.640682 ], "pop" : 24611, "state" : "WA" }
+{ "_id" : "99205", "city" : "SPOKANE", "loc" : [ -117.439912, 47.69641 ], "pop" : 42032, "state" : "WA" }
+{ "_id" : "99206", "city" : "SPOKANE", "loc" : [ -117.258126, 47.649588 ], "pop" : 29077, "state" : "WA" }
+{ "_id" : "99207", "city" : "SPOKANE", "loc" : [ -117.374565, 47.697712 ], "pop" : 46237, "state" : "WA" }
+{ "_id" : "99208", "city" : "SPOKANE", "loc" : [ -117.435207, 47.737434 ], "pop" : 27989, "state" : "WA" }
+{ "_id" : "99212", "city" : "SPOKANE", "loc" : [ -117.304853, 47.668598 ], "pop" : 16771, "state" : "WA" }
+{ "_id" : "99216", "city" : "SPOKANE", "loc" : [ -117.219307, 47.663389 ], "pop" : 18834, "state" : "WA" }
+{ "_id" : "99218", "city" : "SPOKANE", "loc" : [ -117.4146, 47.755648 ], "pop" : 11902, "state" : "WA" }
+{ "_id" : "99223", "city" : "SPOKANE", "loc" : [ -117.362215, 47.61558 ], "pop" : 19056, "state" : "WA" }
+{ "_id" : "99301", "city" : "PASCO", "loc" : [ -119.104387, 46.249183 ], "pop" : 33988, "state" : "WA" }
+{ "_id" : "99320", "city" : "BENTON CITY", "loc" : [ -119.491349, 46.280624 ], "pop" : 5047, "state" : "WA" }
+{ "_id" : "99321", "city" : "BEVERLY", "loc" : [ -119.912074, 46.848429 ], "pop" : 315, "state" : "WA" }
+{ "_id" : "99322", "city" : "BICKLETON", "loc" : [ -120.104223, 45.959687 ], "pop" : 329, "state" : "WA" }
+{ "_id" : "99324", "city" : "COLLEGE PLACE", "loc" : [ -118.385338, 46.045723 ], "pop" : 6904, "state" : "WA" }
+{ "_id" : "99326", "city" : "CONNELL", "loc" : [ -118.85454, 46.66426 ], "pop" : 2699, "state" : "WA" }
+{ "_id" : "99327", "city" : "CUNNINGHAM", "loc" : [ -119.107604, 46.757333 ], "pop" : 511, "state" : "WA" }
+{ "_id" : "99328", "city" : "DAYTON", "loc" : [ -117.973791, 46.307459 ], "pop" : 3373, "state" : "WA" }
+{ "_id" : "99330", "city" : "ELTOPIA", "loc" : [ -119.101333, 46.474996 ], "pop" : 758, "state" : "WA" }
+{ "_id" : "99336", "city" : "KENNEWICK", "loc" : [ -119.167951, 46.210913 ], "pop" : 33860, "state" : "WA" }
+{ "_id" : "99337", "city" : "KENNEWICK", "loc" : [ -119.138289, 46.181387 ], "pop" : 25962, "state" : "WA" }
+{ "_id" : "99341", "city" : "LIND", "loc" : [ -118.706057, 46.955954 ], "pop" : 1134, "state" : "WA" }
+{ "_id" : "99343", "city" : "MESA", "loc" : [ -119.137324, 46.578223 ], "pop" : 2382, "state" : "WA" }
+{ "_id" : "99344", "city" : "MATTAWA", "loc" : [ -119.316405, 46.792518 ], "pop" : 11812, "state" : "WA" }
+{ "_id" : "99345", "city" : "PATERSON", "loc" : [ -119.755873, 45.991139 ], "pop" : 94, "state" : "WA" }
+{ "_id" : "99346", "city" : "PLYMOUTH", "loc" : [ -119.502998, 46.038184 ], "pop" : 219, "state" : "WA" }
+{ "_id" : "99347", "city" : "POMEROY", "loc" : [ -117.599282, 46.469838 ], "pop" : 2467, "state" : "WA" }
+{ "_id" : "99348", "city" : "PRESCOTT", "loc" : [ -118.409663, 46.353879 ], "pop" : 638, "state" : "WA" }
+{ "_id" : "99350", "city" : "PROSSER", "loc" : [ -119.771014, 46.223183 ], "pop" : 9714, "state" : "WA" }
+{ "_id" : "99352", "city" : "RICHLAND", "loc" : [ -119.289201, 46.283265 ], "pop" : 37664, "state" : "WA" }
+{ "_id" : "99356", "city" : "ROOSEVELT", "loc" : [ -120.356611, 45.82962 ], "pop" : 172, "state" : "WA" }
+{ "_id" : "99357", "city" : "ROYAL CITY", "loc" : [ -119.581473, 46.91557 ], "pop" : 3388, "state" : "WA" }
+{ "_id" : "99360", "city" : "LOWDEN", "loc" : [ -118.655411, 46.04851 ], "pop" : 1234, "state" : "WA" }
+{ "_id" : "99361", "city" : "WAITSBURG", "loc" : [ -118.144734, 46.269092 ], "pop" : 2138, "state" : "WA" }
+{ "_id" : "99362", "city" : "WALLA WALLA", "loc" : [ -118.331544, 46.061373 ], "pop" : 34993, "state" : "WA" }
+{ "_id" : "99371", "city" : "WASHTUCNA", "loc" : [ -118.286203, 46.820912 ], "pop" : 625, "state" : "WA" }
+{ "_id" : "99401", "city" : "ANATONE", "loc" : [ -117.088316, 46.128466 ], "pop" : 141, "state" : "WA" }
+{ "_id" : "99402", "city" : "ASOTIN", "loc" : [ -117.001548, 46.134318 ], "pop" : 89, "state" : "WA" }
+{ "_id" : "99403", "city" : "CLARKSTON", "loc" : [ -117.064457, 46.394622 ], "pop" : 17375, "state" : "WA" }
+{ "_id" : "99501", "city" : "ANCHORAGE", "loc" : [ -149.876077, 61.211571 ], "pop" : 14436, "state" : "AK" }
+{ "_id" : "99502", "city" : "ANCHORAGE", "loc" : [ -150.093943, 61.096163 ], "pop" : 15891, "state" : "AK" }
+{ "_id" : "99503", "city" : "ANCHORAGE", "loc" : [ -149.893844, 61.189953 ], "pop" : 12534, "state" : "AK" }
+{ "_id" : "99504", "city" : "ANCHORAGE", "loc" : [ -149.74467, 61.203696 ], "pop" : 32383, "state" : "AK" }
+{ "_id" : "99505", "city" : "FORT RICHARDSON", "loc" : [ -149.675454, 61.275256 ], "pop" : 7979, "state" : "AK" }
+{ "_id" : "99506", "city" : "ELMENDORF AFB", "loc" : [ -149.812667, 61.251531 ], "pop" : 7907, "state" : "AK" }
+{ "_id" : "99507", "city" : "ANCHORAGE", "loc" : [ -149.828912, 61.153543 ], "pop" : 20128, "state" : "AK" }
+{ "_id" : "99508", "city" : "ANCHORAGE", "loc" : [ -149.810085, 61.205959 ], "pop" : 29857, "state" : "AK" }
+{ "_id" : "99515", "city" : "ANCHORAGE", "loc" : [ -149.897401, 61.119381 ], "pop" : 17094, "state" : "AK" }
+{ "_id" : "99516", "city" : "ANCHORAGE", "loc" : [ -149.779998, 61.10541 ], "pop" : 18356, "state" : "AK" }
+{ "_id" : "99517", "city" : "ANCHORAGE", "loc" : [ -149.936111, 61.190136 ], "pop" : 15192, "state" : "AK" }
+{ "_id" : "99518", "city" : "ANCHORAGE", "loc" : [ -149.886571, 61.154862 ], "pop" : 8116, "state" : "AK" }
+{ "_id" : "99549", "city" : "PORT HEIDEN", "loc" : [ -158.566367, 56.964333 ], "pop" : 119, "state" : "AK" }
+{ "_id" : "99551", "city" : "AKIACHAK", "loc" : [ -161.39233, 60.891854 ], "pop" : 481, "state" : "AK" }
+{ "_id" : "99552", "city" : "AKIAK", "loc" : [ -161.199325, 60.890632 ], "pop" : 285, "state" : "AK" }
+{ "_id" : "99553", "city" : "AKUTAN", "loc" : [ -165.785368, 54.143012 ], "pop" : 589, "state" : "AK" }
+{ "_id" : "99554", "city" : "ALAKANUK", "loc" : [ -164.60228, 62.746967 ], "pop" : 1186, "state" : "AK" }
+{ "_id" : "99555", "city" : "ALEKNAGIK", "loc" : [ -158.619882, 59.269688 ], "pop" : 185, "state" : "AK" }
+{ "_id" : "99556", "city" : "NIKOLAEVSK", "loc" : [ -151.732933, 59.788818 ], "pop" : 1698, "state" : "AK" }
+{ "_id" : "99557", "city" : "CHUATHBALUK", "loc" : [ -157.758502, 61.691648 ], "pop" : 352, "state" : "AK" }
+{ "_id" : "99558", "city" : "ANVIK", "loc" : [ -160.130441, 62.830913 ], "pop" : 296, "state" : "AK" }
+{ "_id" : "99559", "city" : "ATMAUTLUAK", "loc" : [ -161.824053, 60.832389 ], "pop" : 7188, "state" : "AK" }
+{ "_id" : "99561", "city" : "CHEFORNAK", "loc" : [ -164.210294, 60.153746 ], "pop" : 320, "state" : "AK" }
+{ "_id" : "99563", "city" : "CHEVAK", "loc" : [ -164.776457, 61.583982 ], "pop" : 0, "state" : "AK" }
+{ "_id" : "99564", "city" : "CHIGNIK", "loc" : [ -158.415696, 56.301639 ], "pop" : 188, "state" : "AK" }
+{ "_id" : "99565", "city" : "CHIGNIK LAGOON", "loc" : [ -158.673528, 56.251277 ], "pop" : 186, "state" : "AK" }
+{ "_id" : "99567", "city" : "CHUGIAK", "loc" : [ -149.453736, 61.409802 ], "pop" : 6910, "state" : "AK" }
+{ "_id" : "99568", "city" : "CLAM GULCH", "loc" : [ -151.422628, 60.201603 ], "pop" : 133, "state" : "AK" }
+{ "_id" : "99569", "city" : "CLARKS POINT", "loc" : [ -158.451241, 58.84921 ], "pop" : 68, "state" : "AK" }
+{ "_id" : "99571", "city" : "NELSON LAGOON", "loc" : [ -161.942941, 55.610952 ], "pop" : 475, "state" : "AK" }
+{ "_id" : "99572", "city" : "COOPER LANDING", "loc" : [ -149.823514, 60.476692 ], "pop" : 252, "state" : "AK" }
+{ "_id" : "99573", "city" : "COPPER CENTER", "loc" : [ -144.97793, 61.91581 ], "pop" : 1389, "state" : "AK" }
+{ "_id" : "99574", "city" : "CHENEGA BAY", "loc" : [ -147.943316, 60.102558 ], "pop" : 96, "state" : "AK" }
+{ "_id" : "99575", "city" : "CROOKED CREEK", "loc" : [ -158.002483, 61.818072 ], "pop" : 1, "state" : "AK" }
+{ "_id" : "99576", "city" : "KOLIGANEK", "loc" : [ -158.973533, 59.059279 ], "pop" : 2711, "state" : "AK" }
+{ "_id" : "99577", "city" : "EAGLE RIVER", "loc" : [ -149.508515, 61.311357 ], "pop" : 18429, "state" : "AK" }
+{ "_id" : "99578", "city" : "EEK", "loc" : [ -162.032341, 60.215058 ], "pop" : 254, "state" : "AK" }
+{ "_id" : "99579", "city" : "EGEGIK", "loc" : [ -157.342202, 58.206174 ], "pop" : 122, "state" : "AK" }
+{ "_id" : "99580", "city" : "EKWOK", "loc" : [ -157.478211, 59.362792 ], "pop" : 77, "state" : "AK" }
+{ "_id" : "99581", "city" : "EMMONAK", "loc" : [ -164.131298, 62.827404 ], "pop" : 0, "state" : "AK" }
+{ "_id" : "99583", "city" : "FALSE PASS", "loc" : [ -163.436845, 54.841028 ], "pop" : 68, "state" : "AK" }
+{ "_id" : "99585", "city" : "MARSHALL", "loc" : [ -161.7394, 61.837087 ], "pop" : 530, "state" : "AK" }
+{ "_id" : "99586", "city" : "SLANA", "loc" : [ -143.568393, 62.654744 ], "pop" : 394, "state" : "AK" }
+{ "_id" : "99588", "city" : "GLENNALLEN", "loc" : [ -145.661684, 62.103895 ], "pop" : 1024, "state" : "AK" }
+{ "_id" : "99589", "city" : "GOODNEWS BAY", "loc" : [ -161.587146, 59.085008 ], "pop" : 305, "state" : "AK" }
+{ "_id" : "99590", "city" : "GRAYLING", "loc" : [ -159.404907, 63.372013 ], "pop" : 0, "state" : "AK" }
+{ "_id" : "99591", "city" : "SAINT GEORGE ISL", "loc" : [ -169.547257, 56.60324 ], "pop" : 138, "state" : "AK" }
+{ "_id" : "99602", "city" : "HOLY CROSS", "loc" : [ -159.825092, 62.192584 ], "pop" : 277, "state" : "AK" }
+{ "_id" : "99603", "city" : "PORT GRAHAM", "loc" : [ -151.462644, 59.665495 ], "pop" : 8186, "state" : "AK" }
+{ "_id" : "99604", "city" : "HOOPER BAY", "loc" : [ -165.891045, 61.537157 ], "pop" : 1443, "state" : "AK" }
+{ "_id" : "99606", "city" : "KOKHANOK", "loc" : [ -155.462556, 59.564836 ], "pop" : 362, "state" : "AK" }
+{ "_id" : "99607", "city" : "KALSKAG", "loc" : [ -160.3261, 61.541006 ], "pop" : 172, "state" : "AK" }
+{ "_id" : "99610", "city" : "KASILOF", "loc" : [ -151.28958, 60.316365 ], "pop" : 963, "state" : "AK" }
+{ "_id" : "99611", "city" : "KENAI", "loc" : [ -151.254556, 60.614467 ], "pop" : 10508, "state" : "AK" }
+{ "_id" : "99612", "city" : "KING COVE", "loc" : [ -162.305561, 55.062848 ], "pop" : 451, "state" : "AK" }
+{ "_id" : "99613", "city" : "IGIUGIG", "loc" : [ -156.641603, 58.724264 ], "pop" : 480, "state" : "AK" }
+{ "_id" : "99614", "city" : "KIPNUK", "loc" : [ -164.101013, 59.923204 ], "pop" : 470, "state" : "AK" }
+{ "_id" : "99615", "city" : "AKHIOK", "loc" : [ -152.500169, 57.781967 ], "pop" : 13309, "state" : "AK" }
+{ "_id" : "99620", "city" : "KOTLIK", "loc" : [ -163.554153, 63.029471 ], "pop" : 462, "state" : "AK" }
+{ "_id" : "99621", "city" : "KWETHLUK", "loc" : [ -161.38849, 60.771814 ], "pop" : 558, "state" : "AK" }
+{ "_id" : "99622", "city" : "KWIGILLINGOK", "loc" : [ -162.984938, 59.881022 ], "pop" : 572, "state" : "AK" }
+{ "_id" : "99625", "city" : "LEVELOCK", "loc" : [ -154.976815, 59.371395 ], "pop" : 204, "state" : "AK" }
+{ "_id" : "99626", "city" : "LOWER KALSKAG", "loc" : [ -160.359966, 61.51377 ], "pop" : 291, "state" : "AK" }
+{ "_id" : "99627", "city" : "MC GRATH", "loc" : [ -155.585153, 62.967153 ], "pop" : 618, "state" : "AK" }
+{ "_id" : "99628", "city" : "MANOKOTAK", "loc" : [ -158.989699, 59.009559 ], "pop" : 385, "state" : "AK" }
+{ "_id" : "99630", "city" : "MEKORYUK", "loc" : [ -166.283583, 60.365679 ], "pop" : 177, "state" : "AK" }
+{ "_id" : "99631", "city" : "MOOSE PASS", "loc" : [ -149.255911, 60.85852 ], "pop" : 1649, "state" : "AK" }
+{ "_id" : "99632", "city" : "MOUNTAIN VILLAGE", "loc" : [ -163.883822, 62.158913 ], "pop" : 788, "state" : "AK" }
+{ "_id" : "99633", "city" : "NAKNEK", "loc" : [ -156.705405, 58.885699 ], "pop" : 0, "state" : "AK" }
+{ "_id" : "99634", "city" : "NAPAKIAK", "loc" : [ -161.738144, 60.663758 ], "pop" : 328, "state" : "AK" }
+{ "_id" : "99636", "city" : "NEW STUYAHOK", "loc" : [ -157.297205, 59.593533 ], "pop" : 586, "state" : "AK" }
+{ "_id" : "99638", "city" : "NIKOLSKI", "loc" : [ -168.788427, 52.988337 ], "pop" : 42, "state" : "AK" }
+{ "_id" : "99639", "city" : "NINILCHIK", "loc" : [ -151.639604, 60.010833 ], "pop" : 767, "state" : "AK" }
+{ "_id" : "99640", "city" : "NONDALTON", "loc" : [ -154.731675, 60.030837 ], "pop" : 233, "state" : "AK" }
+{ "_id" : "99645", "city" : "BUTTE", "loc" : [ -149.065323, 61.613814 ], "pop" : 12358, "state" : "AK" }
+{ "_id" : "99647", "city" : "PEDRO BAY", "loc" : [ -153.821856, 59.92238 ], "pop" : 59, "state" : "AK" }
+{ "_id" : "99648", "city" : "PERRYVILLE", "loc" : [ -159.259333, 55.945289 ], "pop" : 143, "state" : "AK" }
+{ "_id" : "99649", "city" : "PILOT POINT", "loc" : [ -157.449272, 57.595193 ], "pop" : 63, "state" : "AK" }
+{ "_id" : "99650", "city" : "PILOT STATION", "loc" : [ -162.874716, 61.946159 ], "pop" : 463, "state" : "AK" }
+{ "_id" : "99651", "city" : "PLATINUM", "loc" : [ -162.043201, 58.63364 ], "pop" : 4, "state" : "AK" }
+{ "_id" : "99653", "city" : "PORT ALSWORTH", "loc" : [ -154.433803, 60.636416 ], "pop" : 7, "state" : "AK" }
+{ "_id" : "99654", "city" : "WASILLA", "loc" : [ -149.395875, 61.592349 ], "pop" : 10404, "state" : "AK" }
+{ "_id" : "99655", "city" : "QUINHAGAK", "loc" : [ -161.874938, 59.738057 ], "pop" : 501, "state" : "AK" }
+{ "_id" : "99656", "city" : "RED DEVIL", "loc" : [ -157.195969, 61.735389 ], "pop" : 159, "state" : "AK" }
+{ "_id" : "99657", "city" : "RUSSIAN MISSION", "loc" : [ -161.558413, 61.591302 ], "pop" : 0, "state" : "AK" }
+{ "_id" : "99658", "city" : "SAINT MARYS", "loc" : [ -163.205263, 62.054106 ], "pop" : 576, "state" : "AK" }
+{ "_id" : "99659", "city" : "SAINT MICHAEL", "loc" : [ -162.109141, 63.47759 ], "pop" : 295, "state" : "AK" }
+{ "_id" : "99660", "city" : "SAINT PAUL ISLAN", "loc" : [ -170.293408, 57.178697 ], "pop" : 763, "state" : "AK" }
+{ "_id" : "99661", "city" : "SAND POINT", "loc" : [ -160.491435, 55.319236 ], "pop" : 881, "state" : "AK" }
+{ "_id" : "99662", "city" : "SCAMMON BAY", "loc" : [ -165.581945, 61.845019 ], "pop" : 343, "state" : "AK" }
+{ "_id" : "99664", "city" : "SEWARD", "loc" : [ -149.39849, 60.132874 ], "pop" : 3937, "state" : "AK" }
+{ "_id" : "99665", "city" : "SHAGELUK", "loc" : [ -159.52816, 62.661092 ], "pop" : 139, "state" : "AK" }
+{ "_id" : "99668", "city" : "SLEETMUTE", "loc" : [ -157.118284, 61.634555 ], "pop" : 0, "state" : "AK" }
+{ "_id" : "99669", "city" : "SOLDOTNA", "loc" : [ -151.13582, 60.481778 ], "pop" : 9825, "state" : "AK" }
+{ "_id" : "99670", "city" : "SOUTH NAKNEK", "loc" : [ -156.850289, 58.736221 ], "pop" : 929, "state" : "AK" }
+{ "_id" : "99671", "city" : "STEBBINS", "loc" : [ -162.227355, 63.478468 ], "pop" : 400, "state" : "AK" }
+{ "_id" : "99672", "city" : "STERLING", "loc" : [ -150.849792, 60.520373 ], "pop" : 3814, "state" : "AK" }
+{ "_id" : "99676", "city" : "TALKEETNA", "loc" : [ -150.110097, 62.260516 ], "pop" : 1420, "state" : "AK" }
+{ "_id" : "99679", "city" : "TULUKSAK", "loc" : [ -160.938924, 61.108848 ], "pop" : 358, "state" : "AK" }
+{ "_id" : "99681", "city" : "TUNUNAK", "loc" : [ -165.097464, 60.539322 ], "pop" : 889, "state" : "AK" }
+{ "_id" : "99682", "city" : "TYONEK", "loc" : [ -151.348495, 61.117929 ], "pop" : 277, "state" : "AK" }
+{ "_id" : "99683", "city" : "TRAPPER CREEK", "loc" : [ -150.284455, 61.441361 ], "pop" : 20, "state" : "AK" }
+{ "_id" : "99684", "city" : "UNALAKLEET", "loc" : [ -160.788365, 63.883478 ], "pop" : 716, "state" : "AK" }
+{ "_id" : "99685", "city" : "UNALASKA", "loc" : [ -166.519855, 53.887114 ], "pop" : 3089, "state" : "AK" }
+{ "_id" : "99686", "city" : "VALDEZ", "loc" : [ -146.195628, 60.895044 ], "pop" : 7049, "state" : "AK" }
+{ "_id" : "99687", "city" : "WASILLA", "loc" : [ -149.533003, 61.578032 ], "pop" : 14215, "state" : "AK" }
+{ "_id" : "99688", "city" : "WILLOW", "loc" : [ -150.188891, 61.771511 ], "pop" : 1237, "state" : "AK" }
+{ "_id" : "99689", "city" : "YAKUTAT", "loc" : [ -139.778858, 59.620211 ], "pop" : 705, "state" : "AK" }
+{ "_id" : "99691", "city" : "NIKOLAI", "loc" : [ -154.381247, 63.001603 ], "pop" : 109, "state" : "AK" }
+{ "_id" : "99692", "city" : "DUTCH HARBOR", "loc" : [ -167.510656, 53.362757 ], "pop" : 3, "state" : "AK" }
+{ "_id" : "99701", "city" : "COLDFOOT", "loc" : [ -147.710431, 64.840238 ], "pop" : 19316, "state" : "AK" }
+{ "_id" : "99702", "city" : "EIELSON AFB", "loc" : [ -147.08051, 64.67352 ], "pop" : 5266, "state" : "AK" }
+{ "_id" : "99703", "city" : "FORT WAINWRIGHT", "loc" : [ -147.655673, 64.82830300000001 ], "pop" : 6238, "state" : "AK" }
+{ "_id" : "99704", "city" : "CLEAR", "loc" : [ -149.139885, 64.418121 ], "pop" : 440, "state" : "AK" }
+{ "_id" : "99705", "city" : "NORTH POLE", "loc" : [ -147.369353, 64.78049 ], "pop" : 14672, "state" : "AK" }
+{ "_id" : "99709", "city" : "FAIRBANKS", "loc" : [ -147.846917, 64.85437 ], "pop" : 23238, "state" : "AK" }
+{ "_id" : "99712", "city" : "FAIRBANKS", "loc" : [ -147.510479, 64.91087899999999 ], "pop" : 8141, "state" : "AK" }
+{ "_id" : "99714", "city" : "SALCHA", "loc" : [ -146.952974, 64.50905 ], "pop" : 890, "state" : "AK" }
+{ "_id" : "99720", "city" : "ALLAKAKET", "loc" : [ -152.712155, 66.54319700000001 ], "pop" : 170, "state" : "AK" }
+{ "_id" : "99721", "city" : "ANAKTUVUK PASS", "loc" : [ -151.679005, 68.11878 ], "pop" : 260, "state" : "AK" }
+{ "_id" : "99722", "city" : "ARCTIC VILLAGE", "loc" : [ -145.423115, 68.077395 ], "pop" : 107, "state" : "AK" }
+{ "_id" : "99723", "city" : "BARROW", "loc" : [ -156.817409, 71.23463700000001 ], "pop" : 3696, "state" : "AK" }
+{ "_id" : "99724", "city" : "BEAVER", "loc" : [ -147.279803, 66.33883 ], "pop" : 103, "state" : "AK" }
+{ "_id" : "99726", "city" : "BETTLES FIELD", "loc" : [ -151.062414, 67.100495 ], "pop" : 156, "state" : "AK" }
+{ "_id" : "99727", "city" : "BUCKLAND", "loc" : [ -161.131676, 65.98105200000001 ], "pop" : 318, "state" : "AK" }
+{ "_id" : "99729", "city" : "CANTWELL", "loc" : [ -148.89735, 63.395458 ], "pop" : 210, "state" : "AK" }
+{ "_id" : "99730", "city" : "CENTRAL", "loc" : [ -144.74886, 65.468058 ], "pop" : 107, "state" : "AK" }
+{ "_id" : "99733", "city" : "CIRCLE", "loc" : [ -144.08262, 65.82454199999999 ], "pop" : 73, "state" : "AK" }
+{ "_id" : "99734", "city" : "PRUDHOE BAY", "loc" : [ -148.559636, 70.07005700000001 ], "pop" : 153, "state" : "AK" }
+{ "_id" : "99736", "city" : "DEERING", "loc" : [ -162.711951, 66.062265 ], "pop" : 167, "state" : "AK" }
+{ "_id" : "99737", "city" : "DOT LAKE", "loc" : [ -145.613611, 64.005426 ], "pop" : 4111, "state" : "AK" }
+{ "_id" : "99739", "city" : "ELIM", "loc" : [ -162.260371, 64.621662 ], "pop" : 264, "state" : "AK" }
+{ "_id" : "99740", "city" : "FORT YUKON", "loc" : [ -145.306439, 66.52074399999999 ], "pop" : 662, "state" : "AK" }
+{ "_id" : "99741", "city" : "GALENA", "loc" : [ -156.797701, 64.760784 ], "pop" : 847, "state" : "AK" }
+{ "_id" : "99742", "city" : "GAMBELL", "loc" : [ -171.701685, 63.776555 ], "pop" : 525, "state" : "AK" }
+{ "_id" : "99743", "city" : "HEALY", "loc" : [ -149.011128, 63.917123 ], "pop" : 1057, "state" : "AK" }
+{ "_id" : "99744", "city" : "ANDERSON", "loc" : [ -149.1718, 64.300693 ], "pop" : 300, "state" : "AK" }
+{ "_id" : "99745", "city" : "HUGHES", "loc" : [ -154.26443, 66.038246 ], "pop" : 64, "state" : "AK" }
+{ "_id" : "99746", "city" : "HUSLIA", "loc" : [ -156.291976, 65.68991800000001 ], "pop" : 207, "state" : "AK" }
+{ "_id" : "99747", "city" : "KAKTOVIK", "loc" : [ -143.631329, 70.042889 ], "pop" : 245, "state" : "AK" }
+{ "_id" : "99748", "city" : "KALTAG", "loc" : [ -158.724251, 64.33045199999999 ], "pop" : 240, "state" : "AK" }
+{ "_id" : "99749", "city" : "KIANA", "loc" : [ -158.152204, 67.18026 ], "pop" : 349, "state" : "AK" }
+{ "_id" : "99750", "city" : "KIVALINA", "loc" : [ -163.733617, 67.665859 ], "pop" : 689, "state" : "AK" }
+{ "_id" : "99751", "city" : "KOBUK", "loc" : [ -157.066864, 66.91225300000001 ], "pop" : 306, "state" : "AK" }
+{ "_id" : "99752", "city" : "KOTZEBUE", "loc" : [ -162.126493, 66.846459 ], "pop" : 3347, "state" : "AK" }
+{ "_id" : "99753", "city" : "KOYUK", "loc" : [ -161.149957, 64.931668 ], "pop" : 231, "state" : "AK" }
+{ "_id" : "99755", "city" : "DENALI NATIONAL", "loc" : [ -149.539532, 63.516075 ], "pop" : 27, "state" : "AK" }
+{ "_id" : "99756", "city" : "MANLEY HOT SPRIN", "loc" : [ -150.573267, 65.02058 ], "pop" : 122, "state" : "AK" }
+{ "_id" : "99757", "city" : "LAKE MINCHUMINA", "loc" : [ -152.430081, 63.903884 ], "pop" : 32, "state" : "AK" }
+{ "_id" : "99758", "city" : "MINTO", "loc" : [ -149.691186, 65.05839899999999 ], "pop" : 228, "state" : "AK" }
+{ "_id" : "99759", "city" : "POINT LAY", "loc" : [ -162.906148, 69.705626 ], "pop" : 139, "state" : "AK" }
+{ "_id" : "99760", "city" : "NENANA", "loc" : [ -149.086744, 64.55765599999999 ], "pop" : 393, "state" : "AK" }
+{ "_id" : "99761", "city" : "NOATAK", "loc" : [ -160.509453, 66.97553000000001 ], "pop" : 395, "state" : "AK" }
+{ "_id" : "99762", "city" : "GOLOVIN", "loc" : [ -165.310667, 64.505775 ], "pop" : 3706, "state" : "AK" }
+{ "_id" : "99763", "city" : "NOORVIK", "loc" : [ -161.044132, 66.836353 ], "pop" : 534, "state" : "AK" }
+{ "_id" : "99765", "city" : "NULATO", "loc" : [ -157.991353, 64.778024 ], "pop" : 492, "state" : "AK" }
+{ "_id" : "99766", "city" : "POINT HOPE", "loc" : [ -166.72618, 68.31205799999999 ], "pop" : 640, "state" : "AK" }
+{ "_id" : "99767", "city" : "RAMPART", "loc" : [ -150.011201, 65.383627 ], "pop" : 68, "state" : "AK" }
+{ "_id" : "99768", "city" : "RUBY", "loc" : [ -155.503872, 64.720062 ], "pop" : 172, "state" : "AK" }
+{ "_id" : "99769", "city" : "SAVOONGA", "loc" : [ -170.470908, 63.679737 ], "pop" : 519, "state" : "AK" }
+{ "_id" : "99770", "city" : "SELAWIK", "loc" : [ -158.534287, 65.713537 ], "pop" : 0, "state" : "AK" }
+{ "_id" : "99771", "city" : "SHAKTOOLIK", "loc" : [ -161.174589, 64.37549799999999 ], "pop" : 183, "state" : "AK" }
+{ "_id" : "99772", "city" : "SHISHMAREF", "loc" : [ -166.137276, 66.23056200000001 ], "pop" : 456, "state" : "AK" }
+{ "_id" : "99773", "city" : "SHUNGNAK", "loc" : [ -157.613496, 66.958141 ], "pop" : 0, "state" : "AK" }
+{ "_id" : "99774", "city" : "STEVENS VILLAGE", "loc" : [ -149.118286, 65.99589400000001 ], "pop" : 110, "state" : "AK" }
+{ "_id" : "99777", "city" : "TANANA", "loc" : [ -152.103747, 65.15648299999999 ], "pop" : 345, "state" : "AK" }
+{ "_id" : "99778", "city" : "TELLER", "loc" : [ -166.3833, 65.24016399999999 ], "pop" : 260, "state" : "AK" }
+{ "_id" : "99780", "city" : "BORDER", "loc" : [ -142.523046, 63.435022 ], "pop" : 1805, "state" : "AK" }
+{ "_id" : "99781", "city" : "VENETIE", "loc" : [ -146.413723, 67.010446 ], "pop" : 184, "state" : "AK" }
+{ "_id" : "99782", "city" : "WAINWRIGHT", "loc" : [ -160.012532, 70.620064 ], "pop" : 492, "state" : "AK" }
+{ "_id" : "99783", "city" : "WALES", "loc" : [ -168.520521, 65.68821199999999 ], "pop" : 341, "state" : "AK" }
+{ "_id" : "99784", "city" : "WHITE MOUNTAIN", "loc" : [ -163.42185, 64.702791 ], "pop" : 194, "state" : "AK" }
+{ "_id" : "99785", "city" : "BREVIG MISSION", "loc" : [ -166.478578, 65.334187 ], "pop" : 198, "state" : "AK" }
+{ "_id" : "99786", "city" : "AMBLER", "loc" : [ -156.455652, 67.46951 ], "pop" : 8, "state" : "AK" }
+{ "_id" : "99788", "city" : "CHALKYITSIK", "loc" : [ -143.638121, 66.71899999999999 ], "pop" : 99, "state" : "AK" }
+{ "_id" : "99789", "city" : "NUIQSUT", "loc" : [ -150.997119, 70.19273699999999 ], "pop" : 354, "state" : "AK" }
+{ "_id" : "99801", "city" : "JUNEAU", "loc" : [ -134.529429, 58.362767 ], "pop" : 24947, "state" : "AK" }
+{ "_id" : "99820", "city" : "ANGOON", "loc" : [ -134.371052, 57.569832 ], "pop" : 1002, "state" : "AK" }
+{ "_id" : "99824", "city" : "DOUGLAS", "loc" : [ -134.395041, 58.275597 ], "pop" : 1802, "state" : "AK" }
+{ "_id" : "99826", "city" : "GUSTAVUS", "loc" : [ -135.761542, 58.42835 ], "pop" : 258, "state" : "AK" }
+{ "_id" : "99827", "city" : "HAINES", "loc" : [ -135.542032, 59.251886 ], "pop" : 2246, "state" : "AK" }
+{ "_id" : "99829", "city" : "HOONAH", "loc" : [ -135.558435, 58.032237 ], "pop" : 1670, "state" : "AK" }
+{ "_id" : "99833", "city" : "PETERSBURG", "loc" : [ -133.160683, 56.827134 ], "pop" : 4253, "state" : "AK" }
+{ "_id" : "99835", "city" : "SITKA", "loc" : [ -135.316569, 57.051436 ], "pop" : 8638, "state" : "AK" }
+{ "_id" : "99840", "city" : "SKAGWAY", "loc" : [ -135.301794, 59.468471 ], "pop" : 692, "state" : "AK" }
+{ "_id" : "99901", "city" : "KETCHIKAN", "loc" : [ -131.683175, 55.372028 ], "pop" : 13886, "state" : "AK" }
+{ "_id" : "99919", "city" : "THORNE BAY", "loc" : [ -132.513815, 55.66086 ], "pop" : 744, "state" : "AK" }
+{ "_id" : "99921", "city" : "CRAIG", "loc" : [ -133.117081, 55.47317 ], "pop" : 1398, "state" : "AK" }
+{ "_id" : "99922", "city" : "HYDABURG", "loc" : [ -132.633175, 55.137406 ], "pop" : 891, "state" : "AK" }
+{ "_id" : "99923", "city" : "HYDER", "loc" : [ -130.124915, 55.925867 ], "pop" : 116, "state" : "AK" }
+{ "_id" : "99925", "city" : "KLAWOCK", "loc" : [ -133.055503, 55.552611 ], "pop" : 851, "state" : "AK" }
+{ "_id" : "99926", "city" : "METLAKATLA", "loc" : [ -131.579001, 55.121491 ], "pop" : 1469, "state" : "AK" }
+{ "_id" : "99927", "city" : "POINT BAKER", "loc" : [ -133.376372, 56.307858 ], "pop" : 426, "state" : "AK" }
+{ "_id" : "99929", "city" : "WRANGELL", "loc" : [ -132.352918, 56.433524 ], "pop" : 2573, "state" : "AK" }
+{ "_id" : "99950", "city" : "KETCHIKAN", "loc" : [ -133.18479, 55.942471 ], "pop" : 422, "state" : "AK" }
diff --git a/storage/connect/mysql-test/connect/std_data/coffee.htm b/storage/connect/mysql-test/connect/std_data/coffee.htm
new file mode 100644
index 00000000..95a23d5c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/coffee.htm
@@ -0,0 +1,24 @@
+<TABLE summary="This table charts the number of cups of coffe
+ consumed by each senator, the type of coffee (decaf
+ or regular), and whether taken with sugar.">
+ <CAPTION>Cups of coffee consumed by each senator</CAPTION>
+ <TR>
+ <TH>Name</TH>
+ <TH>Cups</TH>
+ <TH>Type of Coffee</TH>
+ <TH>Sugar?</TH>
+ </TR>
+ <TR>
+ <TD>T. Sexton</TD>
+ <TD>10</TD>
+ <TD>Espresso</TD>
+ <TD>No</TD>
+ </TR>
+ <TR>
+ <TD>J. Dinnen</TD>
+ <TD>5</TD>
+ <TD>Decaf</TD>
+ <TD>Yes</TD>
+ </TR>
+</TABLE>
+
diff --git a/storage/connect/mysql-test/connect/std_data/contact.ini b/storage/connect/mysql-test/connect/std_data/contact.ini
new file mode 100644
index 00000000..6d11e738
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/contact.ini
@@ -0,0 +1,23 @@
+[BER]
+name=Bertrand
+forename=Olivier
+address=21 rue Ferdinand Buisson
+city=Issy-les-Mlx
+zipcode=92130
+tel=09.54.36.29.60
+cell=06.70.06.04.16
+[WEL]
+name=Schmitt
+forename=Bernard
+hired=19/02/1985
+address=64 tiergarten strasse
+city=Berlin
+zipcode=95013
+tel=03.43.377.360
+[UK1]
+name=Smith
+forename=Henry
+hired=08/11/2003
+address=143 Blum Rd.
+city=London
+zipcode=NW1 2BP
diff --git a/storage/connect/mysql-test/connect/std_data/contacts.xls b/storage/connect/mysql-test/connect/std_data/contacts.xls
new file mode 100644
index 00000000..77a97bef
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/contacts.xls
Binary files differ
diff --git a/storage/connect/mysql-test/connect/std_data/cp1251.xml b/storage/connect/mysql-test/connect/std_data/cp1251.xml
new file mode 100644
index 00000000..af15d5f8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/cp1251.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="cp1251"?>
+<a><b><c>ÁÂÃÄÅÆÇ</c></b></a>
diff --git a/storage/connect/mysql-test/connect/std_data/dept.dat b/storage/connect/mysql-test/connect/std_data/dept.dat
new file mode 100644
index 00000000..2cf0ba8c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/dept.dat
@@ -0,0 +1,4 @@
+0318 KINGSTON 70012 SALES Bank/Insurance
+0021 ARMONK 87777 CHQ Corporate headquarter
+0319 HARRISON 40567 SALES Federal Administration
+2452 POUGHKEEPSIE 31416 DEVELOPMENT Research & development
diff --git a/storage/connect/mysql-test/connect/std_data/emp.txt b/storage/connect/mysql-test/connect/std_data/emp.txt
new file mode 100644
index 00000000..08cafdb8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/emp.txt
@@ -0,0 +1,4545 @@
+5745ESCOURCHE BENEDICTE 21935 71962121994051834514275.50 0MTECHN
+9692VICENTE LAURENCE 21941 81967101989011621213032.80 0MANGL
+9146NICOLAS ROGER 11941 61964071995023417325098.65 0MSANS
+2985TESSEREAU MARIE HELENE 21941 91967011990011932314933.78 0VSANS
+3368MOGADOR ALAIN 11941 11961091993114330331420.55 0CSANS
+7394CHAUSSEE ERIC DENIS 11944 91965111983123200223583.86 0MANGL
+4655MAILLOT GEORGES 11945 51970091986122470018541.64 0CANGL
+2825CAMILLE NADINE 21956 91994011993011949415050.45 0MSANS
+1460BRUYERES JEAN MARC 11958 81984081988052090215980.07 0MSANS
+4974LONES GERARD 11959101979011994121608112916.70 0MSANS
+8811CROISILLES DOMINIQUE 11961101983051991011868714507.13 0MSANS
+4682MUY CHRISTINE 21962101986051985051288210745.30 0MANGL
+2974SEYSSAUD GERARD 11963 91984101989051949415050.55 0MALLEM
+3185QUINET OLIVIER 11966 71985061993111868714507.94 0MSANS
+9543KOMITAS YVES 11967 21993011992011330611017.70 0MTECHN
+3493COUDET ERIC CHRISTIAN 11935101955041992063417325097.97 1MTECHN
+9039CHAMBOURCY JEAN PAUL 11936 21965031995033417325098.51 1MALLEM
+3731CLERE BRIGITTE 21936111963091995082666519900.77 1CSANS
+2935BONVIN ROBERT 11937 71960121985042273717261.66 1MANGL
+4278VALBOSQUET VERONIQUE SIMONE 21939 21972071992021932314933.54 1MSANS
+1653LIEGE LAURENCE 2193912198901198605 8656 8145.57 1.SANS
+4477LECOURBE DIDIER 11939121965051993011663613342.67 1MSANS
+1400AVENE ANDRE 11940111969121993041557012568.44 1MALLEM
+9742YZENGREMER MICHEL 11941121968011995042201216756.19 1MVENTE
+7255PEYRESTORTES MARIE CHRISTINE 21941 11962041988072470018541.83 1MANGL
+1725EPEND MARIE AGNES 21941 41973071989011621213033.65 1VSANS
+4647PERADONNERIE JACQUES 11941121974071992071369311287.41 1MSANS
+7633SCHEFFER CLAUDE 11944 11969031991011433211714.46 1MSANS
+9793SABLONS MARIE FRANCE 21945 5199408199308 9126 8456.87 1VSANS
+6057EAU BRUNO 11947 91972041991071433211715.33 1MSANS
+6465JADES CATHERINE 21947121970011995042137316331.60 1MINFOR
+8298BERGERS BERNARD 11947101975091993011369311287.29 1MSANS
+9254LEGROS SUZANNE 21947 41971111995111684813422.57 1MESP
+7761KAMAL ALAIN 11948 91977041993111471512024.08 1MCOMPT
+5772GAUTHIER SABINE 21948 61977071994041471512025.34 1MTECHN
+9643BARTHELEMY DOMINIQUE 11949 519871019901111131 9657.16 1LSANS
+3906ROUYRE LAURE 21949 31973071972071326611016.21 1MSANS
+8707SICILE JEAN PIERRE 11950 11976071993011369311286.56 1MANGL
+0091THIVERNAL DIDIER JEAN 11951101980051991101471512024.71 1MSANS
+5757CLOPERIE FABIENNE 21951 71972051995071684813423.26 1MSANS
+7795LATOUR CATHERINE 21952 4199406199306 8359 7953.72 1MSANS
+4879EGUILLES GILLES 11952 61972121990071621213032.51 1MANGL
+8311VINS JEAN PIERRE 11952 119930919920910407 9272.06 1MTECHN
+5964JUST STEPHANE BERNARD 11952 51974061993011369311286.48 1MSANS
+2822NEMAN ELISABETH 21952 7199304199204 9597 8728.14 1MSANS
+1340ABBE MICHELE 21953101973071991041578112722.60 1MSANS
+5357ZOLA BERNARD 11954 41980061992011471512024.35 1MSANS
+8456DHUYS CORINNE ANNE 21954 71979031993041471512025.50 1MINFOR
+4618FERRY BRUNO 11954 41977041995011578112722.24 1MSANS
+8212CIRCLE BERNARD 11955111975041991071578112722.42 1MSANS
+8015BACHELET DOMINIQUE 11956121977031994072644919744.10 1MTECHN
+4320SUPERI MONIQUE 21956 319940519920111389 9852.00 1MSANS
+0442CONTOUR ALAIN 11957 91977031995062201216757.70 1MSANS
+1034PROLONGEE MICHELINE 21957 61980051994071471512024.15 1MSANS
+2106BARDE JEAN CLAUDE 11958 219840719830711131 9659.17 1MANGL
+1977FOCH BERNADETTE 21958 3199202199102 8656 8145.03 1.SANS
+3620BAGNOLET ANDRE 11958 11978061992051471512024.33 1MSANS
+3344PEUPLIERS JOSIANE 21959 8199207199201 8656 8146.16 1DSANS
+9038MALVILLE ETHEL LINKA 21959 31993091992011202810240.59 1MTECHN
+0475PIERREFONTAINE BERNARD 11959 61984081987112090215979.62 1MSANS
+4077MONTMELIAN NOELLE 21960 21984031983031288210743.92 1MSANS
+1421FONTCHANDON PATRICE 11961 71984081989052090215980.97 1MALLEM
+7043MOULERON MARTINE 21962 5199303199203 8656 8145.83 1.SANS
+7239EPARGNE PASCALE 21962 91983011982011608112915.57 1MSANS
+0361BRUANT LAURENCE 21962 31983041994091894014661.48 1CSANS
+1988MIGNARD ANNE 21962 51993081992011249910473.36 1MSANS
+8159GOLFE JEAN CLAUDE 11963 81985101992071288210745.49 1MANGL
+7227BLEU MICHELE 21963 21994071992011249910472.61 1MTECHN
+2721SATGE SOPHIE JULIE 21963 6199503199403 8656 8146.07 1MESP
+1514PANNES JOEL ETIENNE 11964 11984101983101288210743.81 1MSANS
+1595SEPTEMBRE PATRICE 11964 11988031987031527112373.40 1MSANS
+5702CONCORDE PAUL 11965 71994051994011288210744.94 1MMARKT
+3500DRIONNE JEAN XAVIER 119651119860119850110791 9501.81 1MSANS
+3597PIERAM DOMINIQUE 11966 31991101990101381911366.72 1MINFOR
+3537JEAN ANNE MARIE 2196610199610199510 9894 8921.90 1MSANS
+0036CHATEAUBRIAND FRANCOISE 21967 8199307199207 7803 7681.42 1.SANS
+2501GASTA PIERRE 11967101987091988071949415051.95 1CESP
+5621KERGUILLE PASCAL 11967 71988071994061381911364.83 1MALLEM
+5823BRIAC MONIQUE 21968 51994011993011360611210.93 1MSANS
+3717FRADINIERE DANIEL 11968 51988041991041249910472.01 1MTECHN
+2374PETITS SYLVIE FRANCOISE 21969 91992091991091330611018.24 1MSANS
+8139POMPE ERIC 11969 21989041995031249910472.21 1MESP
+3293GUSTAVIA MICHEL 11969 11993021992021420611637.74 1CINFOR
+6848IMPASSE CLIVE 11969 71988071994011249910471.88 1MSANS
+2857ERMITE DOMINIQUE 11969 319910719900710407 9271.86 1MTECHN
+9167PARENT JEAN CLAUDE 11969 919930419920411389 9850.61 1CTECHN
+6582OR MARYSE 21970 419920719910710024 8998.62 1MSANS
+3685ANNEAU CORINNE JEANNE 21970 919920819910811389 9852.27 1MSANS
+4890CIMIEZ PHILIPPE 11971121994101993101360611209.89 1MSANS
+7740MARCEAU AGNES 21971 119920919910911389 9852.45 1MANGL
+5934RANCHO DOMINIQUE 11971 91992071991071420611637.60 1CANGL
+6784WEST JEAN LOUIS 11971 71995011994031202810241.57 1CSANS
+0502ARRALLES GILLES 11971121993121994011249910473.27 1CSANS
+5900LESIGNY OLIVIER 11972 6199606199506 8656 8145.74 1CVENTE
+9357EGLISE ROGER 11972 5199207199312 9597 8728.89 1CINFOR
+2647MONASTERE PHILIPPE JEAN 11972 919940619930610363 9233.31 1CSANS
+7752RANCE GERARD 11973 2199607199507 7803 7680.14 1CINFOR
+2565AQUITAINE GENEVIEVE 21973 119940619920111389 9852.22 1CALLEM
+6946ORBAY CHRISTIANE 2197311199207199101 8656 8146.88 1MSANS
+3358SALONINA ETIENNE 11973 419930919920911389 9852.36 1CANGL
+7527BOULEYGUE PATRICK PIERRE 119741219940419930410668 9426.72 1CSANS
+4780VALMORE ALBERT 11974 81995011994011206910241.16 1CSANS
+6139PALMAROLE BERNADETTE 21975 1199504199404 8359 7952.78 1CSANS
+2461CHAFFARD FREDERIC 11975 1199408199308 7803 7680.62 1CANGL
+4422KAZ ELISABETH 2197612199607199507 7803 7681.11 1CSANS
+3477CABRINE SYLVIE 21978 7199608199508 7803 7679.51 1CTECHN
+6323FABIA RENE 11935 31960121990082273717260.44 2MSANS
+5986ANNA DANIEL 11935 41970041991011433211714.88 2DSANS
+1512FONTAIN HENRY 1193511198901198801 9894 8922.57 2VESP
+6902BLANCS BRUNO 11935 61958071993052470018541.64 2MSANS
+1158CORNEBARRIEU JEAN FRANCOIS MARCEL11936121964011994011557012566.45 2CTECHN
+8277PRIEURE CORINNE 21936 51963011991072273717260.26 2CANGL
+3981TERME FREDERIC 11937 71959021989013844228044.89 2MSANS
+1713DANVILLE DANIEL 11937 51961101985022470018540.87 2MANGL
+9871CAZALIS THIERRY 11938 61966121989062947921840.15 2MANGL
+0383CRESSELY JOELLE 21938111962091990012273717260.55 2VANGL
+3742PYRENEES CHRISTIAN 11938121971101995011663613342.85 2MESP
+6595BAGUIERE FRANCOIS 11938121964081983102022115556.35 2MALLEM
+6543PIERRON PATRICK 11939 7198901198801 9894 8921.33 2CSANS
+8167CLAUX MARTINE 21939 21967011992021932314934.48 2CSANS
+4406LESBACHES COLETTE 21940111973071994041894014662.43 2MSANS
+8258HARTMANN MARC 11940 31968061995011663613343.06 2MVENTE
+3848BARAUDIERE JEAN CLAUDE 11940 11964101990042739020404.83 2MANGL
+1529PICOURENC ANNY 21940 71967011989062470018541.86 2DVENTE
+3069PERIER MICHELE 2194010199601199501 7803 7681.25 2MSANS
+8473COLONIE PIERRETTE 21941 31968041991041932314933.58 2MINFOR
+0084NIEMEN ODILE 21941 51970071991101932314933.73 2CSANS
+6401ALLERAY ARLETTE 21941 21972121993071894014662.64 2CSANS
+8343LEDION FRANCOIS RENE 11941 71972031991071663613344.41 2MALLEM
+9940LAUNES LILIANE 2194210199005198606 8656 8145.83 2.SANS
+7584MARSAT SERGE 11942101964081994011557012567.26 2MSANS
+1051ROSAN STEPHANE 11942 51962041991072273717261.13 2MANGL
+8928POINCARE ANNE MARIE 21942 41965021994051834514275.50 2MANGL
+0874FRANCS KATHERIN 21942 61968031992021932314934.00 2MSANS
+3411CORDELIERS ELISABETH 219421119931119921110152 9116.90 2MSANS
+8736PERTUADE DIDIER 11943 31973071992041403411520.93 2MANGL
+5553OLIVIER CHANTAL 21943 71964071992102137316331.97 2MTECHN
+8502AUGUSTE JOCELYNE 21943101962121991072273717261.16 2CTECHN
+7314DRAIO TOMOKO 21943111969111991072273717260.71 2MSANS
+7892HAUTIL MARIE AGNES NICOLE 2194312199201199101 7803 7681.35 2.SANS
+1146RUES LAURENT 11943 51970041990032022115556.13 2MSANS
+5013POURNAY STEPHANE 11943 71969101991011433211714.01 2MMARKT
+1970SARREBOURG CHRISTOPHE 11943 91962121988122470018540.20 2MTECHN
+2665SAVOIE HELENE 21944 91968091986062470018540.53 2MSANS
+9470KALISTE SUZANNE 21944 31970071991041578112722.12 2DSANS
+7109PEREIRA JOSIANE 21944 71965011982102470018541.72 2CSANS
+0293COURDIMANCHE JEAN CLAUDE 11944 41967011991012273717260.50 2MSANS
+6308BASQUES ERIC WILLEM 11944 71970051988042273717261.30 2MSANS
+9758ROSSA ROBERT 11944 21976051991101369311286.71 2MSANS
+0368GEROFOSSE JOELLE 21944 5198810198306 8656 8146.34 2.ANGL
+3899SALIVE JACQUES 11945 81971051991071433211713.67 2MTECHN
+4807RONDINELLE NOELLE 21945 81968091993062470018540.42 2MSANS
+1251CAP CLAUDE 1194510198907198903 8656 8146.20 2.ANGL
+8624FREVILLE ALAIN 119451119820119810111389 9852.74 2MSANS
+2995ROI JEAN 11946 91972011990101433211715.50 2MANGL
+2130POMPE JEAN MARIE 11946 11972081991071578112722.03 2MSANS
+1524ANTARES CHRISTIAN 11946 41972011990011433211714.43 2MTECHN
+2651AUBE YVES 11946 71971071987041932314934.48 2MALLEM
+5389YVON CAROLE 21946101969031993031834514275.34 2CSANS
+5055BERTHIER CAROLE SIMONE 21947 319931019921010024 8999.31 2MINFOR
+9623LAGER NORMA 21947 61982071992121471512024.51 2MSANS
+9198CAGEAC MICHEL 11947101971031991011433211715.45 2MTECHN
+1117MONS JOELLE 21948 41970081986052334017609.84 2MSANS
+3883BELFORT FLORENCE 21948 2199503199403 8359 7952.96 2MINFOR
+1886CHERCHE CHRISTIANE 21948 3199412199312 9597 8729.72 2MSANS
+9452MORGANE ISABELLE HELENE 21948 61971061989011621213032.70 2MVENTE
+1240POSTEL JOHN 11948111974071992011403411520.33 2MTECHN
+2793DALHIAS EUGENE 11948 71974041992031518612336.02 2MSANS
+1264TRESSERVE EVELYNE 21948 71969081991012990722149.03 2MTECHN
+2964PUJADE ROBERT 11949 81974071992041403411521.74 2MANGL
+9832COUTURIER PATRICK 11949 11972031988102273717260.76 2MSANS
+7619ETIGNY FLORENCE 21949 21970111995042137316332.59 2DVENTE
+3262FABRONITA ANNE 21949 11969091993061834514274.66 2MSANS
+2312SENONCHES ERIK 11949111977041993041369311287.23 2MALLEM
+8743GALLA DANIEL 11949 31970081991012137316331.79 2MALLEM
+0857RAYNOUARD JEAN PIERRE 11950 91982061993111369311287.65 2MSANS
+2136DEROISIN JEAN MARIE 11950 11979061992011608112916.74 2CSANS
+4603LEPURDIE PHILIPPE 11950 91977101990101684813422.12 2MSANS
+2694JOSEPH ERIC 11950 31979021992011249910471.62 2SANGL
+0601SAOUVES PATRICIA 21950 51971021990101834514275.83 2MTECHN
+7409RENE DANIEL 11950 11973051990122470018541.83 2MANGL
+0950SENNELY JEAN PIERRE 11950 51977081986091621213033.28 2MANGL
+1214LOTHIERS ALAIN 11951 51976101993011608112915.65 2MSANS
+6388LAGRANGE ANDRE 11951 81976031984112470018541.20 2MSANS
+2773MORGON ALBAN 11951 91974051988122334017610.33 2MANGL
+7718PIEDS PASCAL BRUNO 11951 61981061993011471512025.91 2CSANS
+8483MEDITERRANEE FREDERIC 11951101970101991112334017610.56 2MSANS
+6772TRARIEUX GUY 11952 91976041992121932314933.54 2MTECHN
+3860MONTABO GHYSLAIN 21952121972041979101684813421.64 2MMICRO
+4868SEVRIER BERNARD 11952 31981041992121369311287.50 2MANGL
+5715CHEVREUSE CATHERINE 21953 11974081991092175716600.56 2MSANS
+3702CALIFO BEATRICE 21953 21973021993012017815517.91 2MESP
+4778LABORDE SHOKO 21953 61973041990101578112723.50 2MSANS
+4134GABONNAISE GHISLAINE 21953 61980071979071202810241.30 2DESP
+4174GAGNEUR JEAN FRANCIS 11953 81979011991101369311288.22 2CSANS
+6892NOLET JEAN LOUIS 11953 81982051992041369311287.41 2MSANS
+5817SERPENTINE CLAUDE 11954 11973111989122175716601.28 2MSANS
+9960GASSIN PASCAL 11954 81974121991012334017610.60 2MSANS
+4935ANNE EVELYNE 21954101975021986101684813423.38 2CANGL
+7050LUBECK MARIE CHRISTINE 21954 81975101993091608112915.33 2DESP
+4537ANNECY ROBERT 11954 91974061992011578112721.89 2MANGL
+1403CHAUVETS CHRISTINE 21954 31977031992011471512025.55 2MINFOR
+3733JAUSSERANNE MASAYO 21955 41978011981091834514274.29 2MSANS
+3799VAILLANT ANNE MARIE 2195558199606199506 7803 7679.58 2MSANS
+1112CHAUMINE RUTH 21956 71985091984091288210745.99 2MSANS
+8102AUSSOU MARCELINE 21956 91985061984061288210744.53 2MMICRO
+3321GABRIE JEAN LOUIS 11956101976031993041471512024.75 2MSANS
+6037SENART JEAN PIERRE 11956 419810319921011389 9852.47 2MSANS
+2073CHAUFOURNIERS FRANCOIS 11956 61976111994041471512026.24 2MSANS
+3246LAMANON VERONIQUE 21956111980041995101527112374.97 2MTECHN
+5182MA PIERRE 11957 41978121994071911114779.14 2MALLEM
+1023GIONO PATRICK 11957 91989011995011249910472.21 2MSANS
+6811GENERAL ALAIN 11957 219930719940111302 9775.56 2MSANS
+9879FOUJU PATRICK 11958 91983051987052090215979.70 2MSANS
+9605ATLANTIQUE CATHERINE 21958 4199510199410 7803 7681.20 2MSANS
+4610COLMAR YVES 11958111982021981021608112916.50 2MSANS
+1905INGRANDES GILLES 11958 11978061993041471512024.03 2MSANS
+6585VERON PHILIPPE 11958 41990091989111450311831.69 2MINFOR
+1508DOBROPOL ERIC JEAN 11958 71978071995041249910473.33 2MTECHN
+9616AIGUELONGUE JEAN PIERRE 11958 71979101994051783213884.92 2MTECHN
+5207GANDOUX PATRICK 11958 11980081985112256617145.24 2MSANS
+5107FABRON CLAUDE 21959101982021981021326611016.48 2MTECHN
+6821ARCADIE RAPHAEL 11959 519810119800111389 9851.34 2MSANS
+9011TUTELLE CLAUDINE 21959 3199201199101 7803 7680.57 2.INFOR
+9117TOURISTIQUE AGNES 21959 31983111982111326611016.24 2MSANS
+2719CRECH DOMINIQUE 11959 81983101991012781920673.39 2MSANS
+9688BAUME BRIAC 11960 1198901198801 9894 8921.36 2MVENTE
+0734CIPRES DOMINIQUE MAURICE 11960 21984111993041527112374.40 2MSANS
+2402VALBOIS DOMINIQUE 11960 419880419870410407 9271.77 2MSANS
+4887ARBAUD JACQUES 11961 61985101993011168610047.18 2MSANS
+3196ARCADES YVES 11961 619910819900810024 8999.88 2MSANS
+0090SENLIS COLETTE 21961 7199610199510 8656 8147.17 2MSANS
+1096BOULOGNE AIME 11961111982061981061326611016.53 2MTECHN
+2728ABOUT CATHERINE MARIE 21961 219841019831011389 9851.55 2DSANS
+9891EXELMANS PATRICK 11961 61992061991061249910472.97 2DSANS
+4344SANTA MARYLENE 21962 91993081992011249910472.41 2DSANS
+6050PROSPER JOELLE 21962 41982051981051326611018.19 2MESP
+1207CAUSSADE MONIQUE ESTELLE 21962 91982111995011450311831.07 2DTECHN
+0864MIOLLIS FRANCOISE 21962 6199501199401 8656 8146.41 2MANGL
+0149MONVALLON BRIGITTE 21962 41983011982011326611016.29 2CSANS
+2375ALIZE CAROLE 21962 91983011982011215710280.24 2MANGL
+8618RESID CHRISTIANE 21962101996111995111202810241.90 2MSANS
+2736PAPIN GERARD 11962 51982051993091949415052.11 2MSANS
+3073JONCS PATRICK FRANCOIS 11962 919890519880510407 9270.62 2MANGL
+6231ENFER PHILIPPE 11962 61988031993041288210744.28 2CALLEM
+5886CHANAZ RENE CHARLES 11962 41992091991091839014312.94 2MSANS
+7276ORGEMONT DANIEL 11962 119830719910711131 9658.28 2MINFOR
+8307GUILLAUME BRIGITTE 21963 21986051985051288210744.10 2MALLEM
+6242ESCLIMONT MARC 11963121986071993051288210745.94 2MMARKT
+2593CARNOT JEROME HENRI 11963 719890619880610407 9271.23 2MSANS
+9494TAILLANDERIE JOSETTE 21963 41985101984101249910472.84 2MANGL
+6039BOURRIER ODILE 21963121984051992011288210745.88 2DSANS
+8408MARINE JEAN PHILIPPE 11963 419850619840610791 9502.46 2MSANS
+3121DOMAINES MICHEL 11963121983061983081326611016.74 2CALLEM
+3716LANDES DANIEL 11963 919851019841010791 9503.30 2MCOMPT
+7915LAMBALLE CHRISTIAN 11963 7199009199510 8656 8145.48 2.SANS
+9027RUGBY NICOLAS PHILIPPE 11964111993051992051249910472.12 2MSANS
+2392MAXIME FRANCIS 119641219850419840410791 9501.95 2MCOMPT
+3798BORNEL PATRICE 11964 51984061993071527112374.31 2MANGL
+8092DOURNAZAC MARIE CLAUDE 21964 71988031995091450311831.39 2DTECHN
+9707FEUILLANTS STEPHANE 11964 91985041984041288210744.95 2MSANS
+1926ESCLAPON JEAN PIERRE 11964101987071990011288210744.14 2MSANS
+9268DOCKS CATHERINE 21965 81985101984101288210745.97 2MALLEM
+6133MOULYN JEAN NOEL 11965 519950119940110024 8999.58 2MANGL
+2064GABRIELLE CLAUDE 119651119940419940110363 9232.71 2MANGL
+3515ARZENS JEAN MICHEL 11966121987061994101249910473.45 2CSANS
+1327LEVALLOIS CHRISTIAN HENRI 11966 419870119860110407 9270.96 2MALLEM
+4538VALLEE PATRICK 11966111987091986091527112373.35 2MSANS
+3705TOLLARE GUY 11966 319900219890210407 9271.28 2MANGL
+2150SUD FREDERIC 11966 819891119881110407 9271.41 2MANGL
+0295WEBER PATRICK 11966121989041994071249910471.94 2MANGL
+8904ARMAGNAC BRIGITTE 21966 21993011992011839014312.78 2MSANS
+0895ABORD CHANTAL 21966 31992021991011202810241.94 2MINFOR
+3361MONTMORENCY LUC 11967 119891219890411302 9775.47 2MANGL
+5793CHANEZ OLIVIER 11967 61989021988021539912452.16 2MTECHN
+9149AUBEPINES JEAN CLAUDE 11967 919950619920110024 8999.72 2MSANS
+6376MYANS DIDIER 11967 419900919890910024 8998.71 2CINFOR
+7437KERILIS CHRISTINE LUCIENNE 21967 219950519940510668 9426.77 2MMARKT
+5688TALLOIRES DOMINIQUE LOUISETTE 21968 81992121991121949415052.16 2MINFOR
+3037GRANADOS BRIGITTE 219681119921119911111389 9851.33 2MSANS
+0075CROUESTY PIERRE G 119681119900619890610407 9271.65 2MTECHN
+7531UCHA GERARD 11968 319880619870610407 9270.24 2MALLEM
+7464MORLET CHARLES 11968 319890419880410024 8999.79 2CVENTE
+0214BLAZY CECILE MARIE NOELLE 2196812199405199305 9894 8922.34 2MMARKT
+4596BONHEUR PHILIPPE 11969 81990011992061202810240.46 2MTECHN
+3345ERESTE ERIC 119691219900919890910024 8999.72 2CSANS
+2283MONTS PIERRE 11969 3199606199506 7803 7681.34 2CALLEM
+5377ROGER FRANCK ANTOINE 1196912199306199206 8656 8147.19 2.SANS
+2310PANORAMA JEAN PIERRE 11969 1199407199307 8656 8146.86 2MSANS
+5201LINCON ALAIN 11969 11990101989101202810240.66 2MSANS
+0199ROLAND ERIC JOSE 11969 119890719880710407 9270.29 2MSANS
+9200FABREGAS LIONEL 11970 419940219940310024 8999.90 2MTECHN
+7648PEPINIERES JEAN PAUL 11970 119920419910410024 8999.90 2MANGL
+0531FALAISE PATRICK 11970111993101994051450311831.87 2MTECHN
+0234TERTRE GILLES 11970 419940419930510363 9233.63 2CALLEM
+4680FREIGNEAUX TORBEN 119711119910519931110024 8999.31 2MANGL
+6897BRIGAND MAGGUY 21972 719910719900710024 8998.62 2MSANS
+3962VIMANEY DOMINIQUE 219721119940719930411389 9852.18 2MSANS
+3186VALLAURIS STEPHANE DENIS 119721119931219921211389 9851.57 2CSANS
+8810GRENELLE BERTRAND 11972 219931219921211389 9851.21 2CSANS
+4405ROBIAC FLORENT 11972 41992121993021420611638.14 2CTECHN
+1562PORTO DENIS 11972 31992021994011249910471.76 2CSANS
+9401VIEILLE DOMINIQUE PIERRE 11972 119940619930610363 9232.37 2CSANS
+6240ROMARINS MAURICE 11973 61993031994011202810241.12 2CTECHN
+7717INDRE GEORGES 11973 7199306199201 9597 8728.41 2CTECHN
+4476AUGUSTIN CHRISTIAN 11974 419941119931110668 9425.55 2CSANS
+1784LOIN MARTINE 21975 3199607199507 7803 7680.09 2CSANS
+3218FLORENCE PIERRE 11977 1199606199506 7803 7681.25 2CESP
+2085HEOL GUY PAUL 11977 5199410199502 8359 7951.66 2CSANS
+0871BOUCHE MICHELE 21934 9199201199409 7803 7680.72 3.SANS
+6519INGRES CLOTILDE 2193511199202199102 8656 8146.47 3.ALLEM
+4038ADAM JANICK 21936111960061980062470018542.10 3MSANS
+5872MURES MARYSE 2193610199210199110 9085 8417.54 3VSANS
+1672LECOIN MIREILLE 21938 7199505199405 7590 7562.85 3MANGL
+7357DETRIE MARIE PIERRE 21939 61962071983032470018540.96 3MSANS
+6152LAVA MICHEL 11939 71962111991013844228045.78 3MSANS
+3943SOUPANE MARIE HELENE 21940 31967011990011932314934.18 3MANGL
+3325REVIREE ALAIN 11941 21973071992011403411521.25 3MANGL
+2673HENNER LILIANE 21942 6199501199401 8656 8145.91 3CSANS
+1755THEBAIDE MICHELE 21942 71966061995011834514275.86 3CSANS
+7360DUCHEMIN VALERIE 21942 61970051991091932314933.73 3MANGL
+1599CHALETS ALAIN 11943121988031993011215710279.23 3MSANS
+9946AULNAY LAURENT 11945111972061995072470018540.87 3MVENTE
+2412GILLES ANNE 21946101969081990012137316330.83 3MSANS
+0843EPICEAS COLETTE 21947111971011994051834514274.26 3MANGL
+6293TERRAS ERIC 11949 41976021992012470018542.13 3MSANS
+0336AMOUR MARC 11949 31978081993121471512024.17 3MSANS
+5125BASTIDES GUY 11949 91975091990011684813422.12 3DESP
+7428LEGENDRE ELISABETH 21950 91979121978121249910472.15 3MSANS
+5015GERARD VALERIE 2195112199307199207 8656 8146.11 3.ALLEM
+4029SUISSE HERVE 11951 41970101990101932314935.08 3MTECHN
+3802BARTHELEMY JEAN 11951 11976051994041471512025.77 3MESP
+1871FELIX JEAN CLAUDE 11951 419811119870411131 9657.08 3SSANS
+0467MALMAISON HENRI 11952 81976041992011578112722.66 3MANGL
+4342PEYRE ANDRE 11953 519820419810411389 9851.64 3MESP
+4047DORDOGNE GERARD 11954 11984081993011471512025.01 3MANGL
+0870CHARBONNIERE HERVE MICHEL 119541219860119850111131 9658.11 3MANGL
+5403CLEMENT RICHARD 1195511198103198910 2079 1.27 3MANGL
+2799LOUBET HENRI 11955111980051995041249910473.33 3MANGL
+8532LEDRU GERARD 11956 41975061992081868714506.76 3MCOMPT
+6909NICOLAS SYLVIE MARIE FRANCOI21956 91977041992021471512026.04 3MALLEM
+4518CLAUDE BRIGITTE 21956 21978041992021471512025.74 3CSANS
+9477MERE MARIE LAURE 2195612199201199101 7803 7679.73 3.SANS
+5508BATHIE PAUL 11957 31979051995041249910473.65 3MSANS
+8413MARRONIERS ROBERT 11957111979121992011471512025.46 3MANGL
+4314MAUGARNY VERONIQUE 21958 11978071992121471512026.22 3MTECHN
+4329MAREUIL JEAN PAUL 11958 21981051994011471512025.56 3MVENTE
+8123CANADA FRANCOIS 119581219940719930711389 9852.20 3MCOMPT
+8870NEUVE JEAN FRANCOIS 11959 81978071992091471512025.02 3MTECHN
+8119RAMPART PIERRE 11961121981061993051527112374.76 3MALLEM
+7639ASSAS ERIC 119611019850119840111131 9657.96 3MANGL
+7720SIFFRET PATRICK 11961 719870319870410791 9502.58 3MVENTE
+5003PUYBERNARD DANIEL 119611119930419920410024 8999.03 3MSANS
+8713VAGNE FREDERIQUE JOSEE 21961111982021981091608112916.97 3MANGL
+1064CASSANYES JACQUES 11962121988061995011373711327.43 3MSANS
+6331CORMIER MIREILLE 21962 51985091984091249910472.33 3MSANS
+8037FARRERE JEAN LOUIS 11962 91987071992052529918967.97 3MVENTE
+2186JOZON CLAUDINE 21963111984091992011949415051.54 3MSANS
+6036VERQUIERES YVON 119641119880719911010407 9271.97 3MSANS
+7970FOIRAIL MARC 119641119850319840310791 9502.86 3MALLEM
+1484VICTORET NICOLE 21965 5199610199510 8359 7952.10 3MANGL
+7412FLERS GUY 11965 219880219870210407 9270.06 3MSANS
+3857DENIS BRIGITTE 21965 91993091992011202810240.55 3MESP
+5856ILIZ THIERRY 119651119860519850510791 9503.61 3CALLEM
+0008CESAR ERIC 11966 91987081986081249910472.87 3CANGL
+8742MONTANT CATHERINE 21966 91993101992011202810240.28 3MALLEM
+9552LACOMBE FRANCK 11966 51989021991121450311832.47 3MSANS
+4423ROC CLAUDE 119671019931119930110024 8998.17 3MSANS
+2631MORIZET SERGE 11967 51988041992051450311830.88 3CSANS
+2963BEAUMONT PASCAL 11968 2199306199301 9597 8728.13 3MINFOR
+1467OTTO JEAN 11968111991111990111467711987.67 3MANGL
+9461BARREAU PHILIPPE 11968 11990011989011202810240.08 3MSANS
+8108ARCANG PATRICK 11969 51990021989021381911365.41 3MSANS
+7093HERAULTS DANIEL 1196911199408199308 9597 8728.82 3CSANS
+3952LEDOUX VERONIQUE 21969 919910919900911389 9851.84 3MSANS
+7563SUPER THI VIET 11971 21990081994011249910473.67 3MSANS
+4441MIRAPOL DOMINIQUE 21971 819930619920611389 9851.34 3MSANS
+2892LOTS THIERRY 11971 2199303199510 9597 8728.23 3MSANS
+5535HOULGATES PASCAL 11971 6199607199507 7803 7681.13 3CSANS
+2838PLAGE JEAN LUC ANDRE 11972 11992071991071420611638.68 3MTECHN
+9036MERCEDES YVES 11972 51993101992101420611639.01 3CSANS
+2537MONTSOURIS PATRICK EMILE 1197211199505199505 9597 8727.87 3MALLEM
+0228AUBERTS JACQUES YVES 11972 6199404199201 9597 8729.43 3CVENTE
+5626VERNEDE ROGER CL 11973 41994101993091450311831.06 3CSANS
+6525AVES SYLVIANE 21973 2199204199104 8656 8145.93 3.TECHN
+9781OLLIER ANNE MARIE 21973 619931119921111389 9850.97 3CSANS
+1379ROSTAND PIERRE 11974 4199507199504 9126 8457.54 3MSANS
+5204CRAVANT DOMINIQUE 11974 1199601199501 7803 7681.40 3CSANS
+6619HORIZON JEAN MICHEL 1197410199606199506 7803 7681.44 3CANGL
+5826VALBONNE ANTOINE 11974 71993091994081202810240.77 3CMICRO
+0256GRANG DOMINIQUE 21974 5199508199408 7590 7563.95 3MTECHN
+4230FAISANDERIE ANNE MARIE 21974 819930819920811389 9852.69 3MALLEM
+4212ORME HERVE 11976 8199606199506 7803 7681.44 3CSANS
+6753PINTADES HERVE 11977 9199608199508 7803 7679.99 3CANGL
+7715VAILLANT CHANTAL 2193111198801199302 7677 7603.76 4.ALLEM
+8632CLAIRETTES JACQUES 11935 51964081994011557012566.54 4MSANS
+3535CASANOVA THIERRY 11936 91963081995112022115555.22 4MESP
+1574AVENUE PIERRE ALAIN 11936 719890119920811131 9657.20 4MINFOR
+4591VINCIN NICOLE 21939121966071993012137316332.68 4CSANS
+3788POTERIE MICHEL 11939 81972061990011403411520.75 4MALLEM
+0118BRETHON GUY 11939 419871119950310407 9270.03 4MSANS
+2869LIMERGUE BRIGITTE 21939 91963041991072273717260.91 4CANGL
+8403BOSQUET FABRICE 11939 81966071990011433211714.79 4MSANS
+3617VATA JEAN 119401019930819910110407 9270.62 4MSANS
+4772SAENS BERNARD 11940 719900519890510024 8999.04 4MSANS
+3869MARIUS MIREILLE 21941 81961101995072137316330.70 4VESP
+3900PERDONNET PHILIPPE 11941 119921219911210407 9270.44 4MSANS
+7958CARDINALE ROSELYNE 21942 21963101992072137316331.25 4MSANS
+9381LOTOS CAROLINE FREDERIQUE 21942 11968011990011932314934.90 4MESP
+1020FLORIDE KATIA 21942 71972071993111834514276.10 4DSANS
+9843MEON GERARD 11943 41973101991011621213032.20 4MSANS
+0204GAILLARD CHRISTIANE 21944 71964071993012137316331.82 4MSANS
+1733VUE CATHERINE 21944 61963111992072137316331.78 4MVENTE
+6248AYGUESVIVES MICHELE 21944 41970071991071684813421.33 4MANGL
+4598FEUILLERAIE JEAN MARIE 11945 219890119910610791 9502.23 4CSANS
+3077SAPIAC ALAIN 11945 71971111991012470018542.09 4MANGL
+2431RENAUDES NADINE 21946 61968111990012137316330.56 4CSANS
+1120SATUR JOSIANE 21946 51969031990012137316331.03 4CSANS
+0145ITALIENS EDITH 21946 81968111984062470018540.30 4CSANS
+4624COURDIMANCHE JEAN LOUIS 11947 81968121989102273717259.95 4MTECHN
+8599LONGCHAMP JOSETTE 21948 7199201199101 7803 7679.49 4.ANGL
+3219SERNAGLIA FREDERIQUE 21948 51969031968031326611016.35 4MMICRO
+7793ANATOLE ERIC 11948 519910119941010024 8998.50 4MSANS
+4753VENT JEAN MARC 11948 61970011988012273717261.76 4MSANS
+5892CHARLEROI MARTINE 21949101968111992091834514275.70 4DSANS
+8687GOELETTES JEAN LOUIS 11950 91975041995011578112721.71 4MSANS
+5669ADRIENNE CATHERINE 21950 61972101991072017815517.59 4CESP
+2743CLAIR MARC 11950 11978031994011369311286.26 4MANGL
+1234DAMPIERRE MICHELLE 21950111969081995042334017608.88 4MSANS
+9403LECLERC CLAIRE 21951 71971071991042137316331.51 4MSANS
+0934ENCLAVE JEAN CLAUDE 11951 21981051990041621213033.38 4MALLEM
+9416BLEU JEAN CLAUDE 11951 21976051991011369311286.78 4MSANS
+9196PYANDIERE MARIE NOELLE 21951 41982021981021326611016.03 4MSANS
+3568MOISSAN JEAN PAUL 11952111976071991071578112723.29 4MALLEM
+7750TONNELIERS MARIE 21952111973011993071471512024.35 4MINFOR
+2095MARS BRIGITTE 21952 81984011992011288210744.49 4DMARKT
+4777GORBIO MARIE DENISE 21953 61973061991011578112723.74 4MALLEM
+8945VASSY MICHELLE 21953 11973051993041471512025.88 4MSANS
+3712MAURUCHES PHILIPPE 11953 819860119850111131 9658.99 4MALLEM
+6740EUZKADI JOEL 11953 11973031990071578112722.87 4MANGL
+7024BRUSC EVELYNE 21953 71976041991121578112723.36 4MMICRO
+8219INFIRMERIE JEAN PAUL 11954 91980051990101608112916.59 4MANGL
+5540BRUAND DANIEL 11954 51974031993031684813422.75 4MANGL
+7460MATISSE MARGIE 21954 61975041991101578112723.42 4MANGL
+2655THEZAN MONIQUE 21954 91975081991091578112722.28 4MSANS
+9672BORON ERIC 11955 51975081992102017815516.74 4MSANS
+8145BOULETS DOMINIQUE 21956 1199105199005 9894 8921.63 4MSANS
+3110CERF VALERIE 21956111993081992011249910472.37 4MTECHN
+7652BAY PATRICK 11956 71976071992011578112722.47 4MCOMPT
+4074FRANK DANIELLE 21957101992111991011202810241.17 4MSANS
+4741ESCOUTADOU FRANCOISE MARIE 21957 2198901198505 8656 8145.06 4.ANGL
+0933SOUCARRADE BEATRICE 21957 5199312199212 9894 8922.21 4MALLEM
+7852CAILLOTS CLAUDINE 21958 71978091992091471512025.14 4MSANS
+5344THEODORE CHRISTINE 2195811199310199210 7803 7680.44 4.SANS
+8813MILLIERE BEATRICE FRANCOISE 21959 51981071980071202810241.36 4MSANS
+5426NATIONS ISABELLE 21959101981111980111463211946.14 4MSANS
+4656TILLET FRANCOISE 21960 71983041982041608112916.59 4CANGL
+8524ALLIER ANNE MARIE 21960 1199209199109 8656 8146.28 4.SANS
+0380MARAINVILLERS NATHALIE 21961 2199410199310 8656 8147.15 4CSANS
+1404FAISANS ERIC 119611219830319830811131 9658.86 4CSANS
+6501MERICOURT FRANCOISE 21961 519951119941110668 9426.09 4MANGL
+4607CHAPPEL CHANTAL 21961 41982091981091330611017.46 4MANGL
+1959PEY JOSIANE 21961111982111981111608112916.95 4MALLEM
+8843TIMSIT HUBERT 11961 61982041988011326611017.25 4MSANS
+1688BENOITE JEAN CLAUDE 11961 91987071992121249910472.51 4MTECHN
+5712FOUENT VINCENT EMILE 11961101983071982071326611016.03 4MSANS
+7184FRANCE RAYMOND 11961 419880319870310024 8998.35 4MINFOR
+5235HAUTS YANNICK CLAUDE 11961 819871019861010791 9503.90 4MVENTE
+6310PEYRIGOUE PATRICK 11962 81982031989071326611016.78 4MALLEM
+5397COURCELLES MIREILLE 21962 9198810198505 8656 8145.89 4.SANS
+4469PASSELEU CHRISTIANE 21962 41984011983011381911366.72 4MANGL
+8234MAIAUX BRIGITTE 21963111991071991011249910473.22 4DANGL
+9770JARD MINELLE ODILE 21963 91988111987111249910471.84 4MSANS
+5324CERF CLAUDE 11964 419870719920510791 9503.34 4MSANS
+9061ROMAGUE MARTINE 21964 71983111982111326611016.12 4CANGL
+8920PORQUIER DANIELLE 21964 41987021986021527112374.66 4CALLEM
+7098CHATENAY ANDRE 119641119841019831010791 9503.94 4CVENTE
+8128PRECONIL YVES 11965 71988021987031527112373.94 4MSANS
+6719KEFYSSIA CHANTAL 21965 319940619920111389 9851.03 4MSANS
+6244MANGEON MICHELINE 21965 8199402199304 7803 7680.34 4MINFOR
+3461LUCIA CHRISTIANE 2196610199308199208 8656 8145.56 4.ANGL
+9241ROTOURS PIERRE 119661119900819890810024 8999.13 4CSANS
+6268TOURING GENEVIEVE 21966 1199403199303 8359 7952.46 4MSANS
+4829COLLES EMILE 11966 419910719900710024 8998.31 4MESP
+0750CADET YVES 11966 919860419850410791 9503.79 4MTECHN
+0057ESCALE THIERRY 11967 71989021988021450311831.93 4MSANS
+9924CHINON BRIGITTE 21968 8199207199107 8656 8146.65 4.SANS
+7821AILES CECILE 21968 41991051992111202810239.81 4CSANS
+7114LANCIER WILMA 21968111994031992011202810241.07 4CESP
+4765TILLEULS JEAN 11969 51992041994011249910472.59 4MINFOR
+4429EDOUARD FRANCOIS 11969 319890419921010407 9272.09 4MINFOR
+1431GIORDAN SONIA 21970 5199201199101 8656 8145.51 4MANGL
+9920BOUIN CATHERINE 21970 919900419890410876 9502.28 4MSANS
+5522AURELIA MARIE CHRISTINE 21971 31993031993051267210590.24 4MSANS
+7479TRINITE NOEL 11971 3199604199504 7803 7680.36 4MSANS
+3516GASPARDES KUMIKO 21971 41993061992061267210590.05 4MSANS
+5784BOITE REMY 11972 819910619900610024 8998.26 4CANGL
+1143MACORNAY ROGER 11972 6199212199112 9597 8728.58 4MSANS
+0244FEUQUIERES CLAUDINE 21972 719921019911011389 9851.57 4MSANS
+0161LONGAGES FREDERIC 11973 119920819910811389 9852.02 4MSANS
+5206TISSOUS ELIANE 2197311199405199305 8359 7951.97 4CESP
+6992FOUGERAIE JEAN YVES 119731119931219921211389 9852.45 4CSANS
+3522REST ANNICK 21974 9199306199206 7803 7680.08 4.TECHN
+9573FONTAINE CATHERINE JEANNE 21975 2199407199307 7803 7679.87 4CSANS
+5048HAUTES JEAN RENE 11975 619961219951211389 9850.74 4CSANS
+1152QUARTIER MARTINE 21975 6199408199308 9894 8921.41 4CSANS
+0049LAUNAY NOUARA 21976 6199607199507 7803 7679.85 4CSANS
+4557ROBARESSES HELENE 2197611199507199407 7803 7680.53 4CANGL
+4244GEMEAUX DANIELE 21977 9199608199508 7803 7679.33 4CALLEM
+0257PUNAAVIA GUY 11935 219930119920110407 9271.82 5MSANS
+4173ALPINS FRANCOIS 1193510198811198505 8827 8263.65 5.SANS
+5358CHEVRY JEAN DENIS 11936 9199503199201 9085 8418.03 5MCOMPT
+4903WILSON SERGE 119361119890119930210791 9503.49 5CMANAG
+2411BINEAU RENE 11937 41970081991011433211713.71 5MSANS
+5097OURS MADELEINE 2193910198810198506 8656 8145.20 5.SANS
+1099VILLAINE YAN CLAUDE 11939101968061990011433211713.58 5MINFOR
+0060ATTAMRK CORINNE 21939 41962061983102470018542.06 5MSANS
+7199LECONTE EDMOND 11940 51972061995012201216757.94 5MSANS
+7870PIA PHILIPPE 11940 71967071991101433211715.00 5MSANS
+4990ROSSAYS SERGE 11940 21963091988012273717260.31 5MSANS
+3381BUSSEROLLES ISABELLE 21940 8199505199201 9085 8418.09 5DSANS
+0099RAHAL PHILIPPE 11940 11961051984062470018541.16 5MSANS
+5909TOURRETTES LILIANE 21940 91961101983102470018540.93 5MTECHN
+8941BEZIERS CLAUDE 21941 11961051992102137316332.72 5MSANS
+7223CHARMETTES MARCO 11941 41972091991011433211714.06 5MSANS
+8980LARMINAT FRANCOISE 21941 4198910198512 8656 8146.16 5.INFOR
+1164PROVENCAL NICOLE ALIX 21942 91968101991072273717260.89 5CSANS
+7010DELOISON SYLVIA 21942 51968121991101932314934.72 5MSANS
+3304ROSES MARIE THERESE 21942 81968091993111834514275.11 5MSANS
+7469BUTTE MARIE FRANCE 21943 21962121991072273717261.13 5MSANS
+8184VANNES MARC 11943 11971051994011621213032.96 5MSANS
+1647CLAIRES CEDRIC 11944121969011991011433211713.67 5MTECHN
+0926BEACH CLAUDE 21944 41970041991101932314934.45 5MANGL
+3781COULANGES CHRISTINE 21944 61965021992091932314934.21 5VSANS
+7004GUILBAUD MARTINE 21944 41966061995042137316330.61 5MSANS
+5511CAPUCINS JACQUELINE 21944 41965121990082470018540.74 5MSANS
+0535OLLIERES MARIE JOSE 21944111964071993072137316331.95 5DALLEM
+6700DOLET FREDERIC 11944 91973041992011403411521.64 5MSANS
+9005SUCE LYDIE 21945111977061992011471512025.50 5MTECHN
+2933PEGOMAS MONIQUE 21945 81982061981061326611016.62 5VALLEM
+1543GATTIERES MICHEL 11945 81970091991041433211715.59 5MSANS
+0725AUBIERS PHILIPPE 11945 91976051993011369311286.75 5MANGL
+2098ENTREES ANNY 21945101968061994102666519899.56 5MSANS
+8761WAGRAM JEAN FRANCOIS 11946 21971101988061932314935.35 5MTECHN
+2003PAULINE AGNES 21947 2199303199203 8656 8146.59 5.SANS
+1732RELAIS GILLES 11948 31970031993111834514274.96 5MSANS
+6970THIERS MICHEL 11948 71970101994071834514274.42 5MALLEM
+4216HUGO FRANK 11948 21971031991012990722149.47 5DALLEM
+6627ABBAYE GERALD 11948 619810319800311389 9850.65 5MANGL
+5230DUNANT PHILIPPE 11948121983101993041326611016.87 5MANGL
+2460POINTE DENIS 11949 51975081992011578112722.47 5MANGL
+7858ARBONNE FRANCIS 11949 71974081992012470018541.70 5MSANS
+3903CHAMPAUBERT PIERRE J 11949 41976101992011369311286.24 5MANGL
+8857DIVE MYRIAM 2195012199311199211 8656 8146.88 5.SANS
+0497KARINE JEANNINE 21950 5199311199211 7677 7604.39 5.SANS
+3876SANGUINAIRES FLORENCE 21950111970021991091834514275.86 5MTECHN
+3265PAVILLON PHILIPPE OLIVIER 11950111970041987102470018542.13 5MSANS
+2421VERDIER MARTINE 21950 41970071994031834514274.80 5MANGL
+8685PROVENCALES JEAN MICHEL 11950 11978061992121471512026.06 5CANGL
+6880CHARONNE GISELLE 21950 21971031994071834514275.47 5MCOMPT
+3995BELLEVUE CHANTAL 21950101977011992011471512024.48 5MSANS
+1936MANHASSET JULES 11951 31970101991021834514276.22 5MVENTE
+8771MAURIN JEAN MICHEL 119511119930819910110791 9503.74 5CSANS
+8918MORON DANIEL 11951101971031986072470018541.02 5MCOMPT
+7486HAUTACAM JEAN PIERRE 11951 11979061992011249910472.78 5MSANS
+8979PARE LUCIEN 11952 41973071991041578112723.72 5MSANS
+8316MOUSLIM PASCAL 11952 31972051990071621213032.39 5CSANS
+0252AUNES CLAUDINE 21952 71972051992111684813421.69 5MALLEM
+4525CHAVONNES FRANCOIS 11952 31976111992071578112721.79 5CANGL
+2153CROULEBARBE JEAN JACQUES 11952111972121994011684813423.34 5MSANS
+4523PITARD JACQUES 11952 91973081990123417325097.24 5MSANS
+0877MILLION CLAUDE 11952 31974121992012017815516.65 5MALLEM
+0553CRABERE HERVE 11953 91979051992121471512025.97 5DANGL
+4593COLLINES FRANCOISE 21953 81973051994031911114779.59 5CSANS
+5525MILLY JEAN HUGUES 11953 11976091991012022115555.39 5MSANS
+8419CREMIEUX CHRISTIAN 11953 71972071991072137316332.68 5MSANS
+5466CHENEY JOSE 11953101977031994011578112723.31 5MALLEM
+8647MOTHE DOMINIQUE 11953 21984071992051326611017.10 5MVENTE
+7550BORDEAUX GILBERT 11953 8199006198709 8656 8146.61 5.VENTE
+5317SIMAREGRE MARION 21954 21975081993071608112916.88 5MSANS
+7895BEAULIEU ALAIN 11954 41982031994011471512025.55 5MSANS
+7110BRUNES MICHELINE 21954 91977011994011471512024.69 5MSANS
+9833MOULINS FLORENCE 21954 3197505197405 8530 8066.58 5MSANS
+9346RIVIERE BRIAN 11955 31980081992011249910473.42 5MESP
+3155ALAUDA CATHERINE 21955 51977051993071471512025.55 5MSANS
+4303MARJORIS PATRICK 11955121980041992121369311286.96 5MSANS
+8955LACRETELLE ANNE 21955 419960719950710668 9426.57 5DSANS
+0292ENCLOS CHANTAL 21956101977071977041834514275.97 5MVENTE
+7044ENGHIEN GERARD 11956 11978061992041369311286.93 5DESP
+3352LOZERE SERGE 11957 81983021991092529918968.46 5MANGL
+7626HENIN PHILIPPE 11957101986081993011168610046.99 5MALLEM
+1198MARTYRS WILLIAM RENE 11957121977031991052043315671.24 5CSANS
+4601CEYZERIEU PHILIPPE 11958101979121987111684813421.72 5MSANS
+6850BEAUSOLEIL BRIGITTE 21958 81981031986021527112374.79 5MANGL
+0505CLAPIERS MARIE CLAUDE 2195810199403199303 9126 8456.57 5MSANS
+6127MONTEE CHRISTINE 21958 31980091994071471512024.15 5MSANS
+4080FOCH SERGE 11959 319810319810511131 9658.24 5MSANS
+8151ECUREUIL OLIVIER 11959 21989071996012815620945.31 5.TECHN
+2121BOURDAILLERIE SIMONE 21959 11979071993041471512024.56 5MSANS
+5078FERNAND ANNE MARIE 2195912199110198510 8656 8146.61 5.SANS
+2667BERGERE PIERRE 11959 51978061985041684813422.48 5MANGL
+2407SOLEIL NADIA INGRID 21959 61989061988061249910472.73 5MTECHN
+2235VILLEMARECHAL GERARD 11959 61983061989121326611017.72 5CINFOR
+0110ANDRE NADIA 21959 319930519920510363 9233.61 5MANGL
+4644AVIGNON CHARLES 11959 519830319920611131 9657.56 5MANGL
+7070MONGE HONORINE 21960111980051985061608112916.23 5MSANS
+8043EGAL LIVIA 21960 11985101984101288210744.85 5CTECHN
+5249THEODULE REMY 11960 41987051991041949415052.11 5MALLEM
+7737CLUB ISABELLE ANDREE 21960111980061994011471512025.77 5MANGL
+3853DZOANH CHRISTOPHE 11960 61988101994041288210744.58 5MANGL
+2653MARSACQ CLAUDE 11960 31985111984112256617146.01 5MTECHN
+6452POSTFACH ALAIN 11961 31985081984081288210744.98 5MTECHN
+0681LOGE PASCAL 11961 11985031991021527112372.86 5MSANS
+9537JEAN MICHEL 11961 31988061991121249910471.84 5MVENTE
+6327NOUES ANTOINE 11961121982101981101608112916.14 5MSANS
+6682VATONNE BRIGITTE 21961 71982011981011608112916.65 5MSANS
+9847GAMBADES JOCELYNE 21961101982011981011288210744.17 5MANGL
+6375GAUTIER CLAUDUNE 21961101984071994011450311832.63 5CINFOR
+6651RIVA PIERRE 11961 919830619820611131 9657.62 5MSANS
+1485REUILLY JOSETTE 2196212198901198603 8656 8146.41 5.ALLEM
+9501BETHUME MICHEL 11962 81985031993041326611016.65 5MSANS
+9435PROVENCE JEAN MARC ROBERT 11962 919940919920110024 8999.30 5CSANS
+6492VENDELAIS DANIEL 11963 119830419820411131 9657.66 5CINFOR
+9242REVELLATA BRUNO 11963111987071993041288210744.41 5MSANS
+4454ETANG BEATRICE 21963 31983081982081326611017.61 5MESP
+7265AMPHYTRION JOEL 11963 31990091993041249910472.78 5CSANS
+2299ADRIAN ALAIN 11963121988101987101288210745.70 5MESP
+8642ALE MYRIAM 219631219940719930411389 9851.34 5MALLEM
+9850BOULOURIS CHARLY BERTRAND 11963121987091986092090215980.25 5MINFOR
+3445COLOMBE SYLVIE 21964 319870619860611389 9850.74 5MSANS
+1844GUY PAUL 11964121985121994011433211715.27 5MANGL
+7102QUINQUENAIS MICHEL 11964101984091994041574112685.17 5MSANS
+1584KERVENEL JEAN CLAUDE 11964 71984061987121288210745.76 5MANGL
+2604LIBERATION FRANCOIS DANIEL 11964 819841019840810791 9503.36 5MSANS
+0403HERMITTE PHILIPPE 11964 61983051993051527112374.04 5MSANS
+5722CHATAIGNERAIE LIONEL 11964 91983121992061527112373.67 5MSANS
+3237HUYMANS MICHEL 11964 21984021990011527112372.81 5MALLEM
+5398TASSIGNY CHANTAL 21964 51988111987112090215981.24 5MSANS
+1027VRAUX PHILIPPE CLAUDE 11965 91993091993031202810240.76 5MSANS
+3198BERIN DENIS 11965 81987011994091693613499.07 5MANGL
+1036MADAME EDOUARD 11965 81986091985091288210744.77 5CSANS
+6124ABELIAS DELIA 21965 519940919930411389 9850.65 5MSANS
+1462BLANCHE MARIE FRANCE 219651219940319930311389 9852.60 5MTECHN
+0587ORMEAU GENEVIEVE 21965 51990011989011249910471.76 5CSANS
+8260BROSSAY JEAN PIERRE 11965 319931119911010407 9270.24 5MESP
+8146BROC ANDRE PAUL 11966 319940219920110024 8998.37 5MANGL
+8310HOTTINGUER ISABELLE MADELEINE 21966 1198906198512 8656 8145.98 5.INFOR
+6654TAHITI MARIE LOUISE 21966 6199501199401 9597 8729.13 5MSANS
+5470LAGARDELLE XAVIER 119661119900719890710407 9271.97 5MSANS
+8823ROUCHERETS EVELYNE 21966 61985101984101249910472.06 5MTECHN
+8327BARRELLET PASCAL 11966 41987021993121288210743.92 5MTECHN
+8879GROULT ANNE MARIE 21966 41993011991011202810241.70 5CANGL
+5928DREZERY ALAIN 11966 91989081988081539912453.11 5MSANS
+3229THOMAS SABINE DOMINIQUE 219671019940519920111389 9852.59 5MTECHN
+1136BRECHE MARIE AGNE 21967 3199601199501 9126 8456.70 5MANGL
+5446POMMERAIE GUY 11967 8199606199506 8656 8145.80 5MSANS
+0654CARAVELLES ROBERT AH 11967 81989071989021450311831.55 5MANGL
+0015TAVANNES LOAN 21967 419930619920610024 8999.72 5MINFOR
+8197NETTER GILBERT 11967 61987051994041249910472.06 5MSANS
+5236PASSERO MARC 11967 8199309199209 9085 8418.26 5CSANS
+3054WILSON GERARD 11967 119870919860910407 9272.09 5MSANS
+9725GUILHEM DANIEL 11967111990021989021539912451.67 5MSANS
+6092CLEME MARIE CHANTAL 21968 3199201199101 8656 8146.46 5.SANS
+2456HOLBERN FREDERIC 11968 2198902198802 7207 7448.96 5.ANGL
+6716VILLERSEXEL TANGI FRANCOIS 11968 2199306199206 9597 8727.78 5MSANS
+6119RAVAS ANNE MARIE 21968 6199502199402 8656 8146.19 5MSANS
+2294VILLAGE SYLVAINE 21968 91992041991041202810240.68 5MINFOR
+8140CAMIN JEAN MARCEL 11968 51988121993121249910473.45 5CANGL
+7302MERIDIEN MAURICE 11968 219880519910210407 9271.32 5MANGL
+7914JOLI MAURICE 11969 31989041992121249910472.06 5MANGL
+2148ESPAGNE BRUNO 11969 819920319910310024 8999.36 5MSANS
+1823BOUCICAULT NICOLE 21969 519941019930411389 9851.82 5MSANS
+9657MAGESCQ EMMANUEL 119691119920519941010024 8999.97 5CSANS
+9896MIO JEAN 11969 11991101990101330611017.19 5MTECHN
+8478SOURCE SIDNEY 11969 61989041988101249910473.49 5LSANS
+6336HASARD ERIC 11969 4199305199205 9597 8729.63 5CANGL
+5471LEVAINVILLE LAURENT 1197011199301199201 9597 8729.97 5MVENTE
+5314HALLES JACQUES 11970121991101990101467711985.86 5MSANS
+1685NORMANDIE MICHEL 11970 319900719890710024 8999.40 5CANGL
+6830LAOUADIE GWENAELLE 21970 2199608199508 8359 7953.65 5MTECHN
+1727CAUVETS MARTIAL 11970 7199311199409 9597 8728.99 5CSANS
+5830BRIOLLAY JEAN PAUL 11970 21991011994011249910473.24 5MINFOR
+8526CAMPION FRANCOISE 21970101991111990111202810240.91 5MANGL
+6622TANANARIVE GILBERT 11971 51992071992091330611016.75 5CSANS
+7788JOCELYN CHRISTIAN 11971 6199302199202 9597 8728.05 5CESP
+2781SAFRENIER PIERRE 11971 8199301199201 9597 8729.63 5CSANS
+6277PAULEL HERVE 1197112199403199201 9597 8729.54 5MANGL
+6618NOTRE PIERRE 11972 519930919920910363 9232.44 5MSANS
+6648SAKAKINI BERNARD 11972 319920419910911389 9851.24 5MANGL
+8593JULLIEN JEAN PIERRE 11972 8199604199504 9894 8922.45 5CVENTE
+8229CHANTELOUP CHANTAL 21972 11992101991101420611637.21 5MSANS
+8361OUCHES FRANOISE 21972 4199508199408 7803 7680.80 5CSANS
+3075LUMIO JEAN LUC 11972 41991111994011249910472.52 5LSANS
+5865FERROLLES MARIE CECILE 2197210199403199303 7803 7680.27 5MCOMPT
+0134SEVRES DOMINIQUE 11973 5199507199407 7803 7679.72 5CTECHN
+4254HENIN SERGE 11973 3199409199510 9597 8728.17 5CSANS
+8695AMBASSADE MARIE BEATRICE 21973 8199605199505 7803 7680.62 5CALLEM
+4411DAVOUST FRANCIS ALAIN 11973 719930419940711389 9851.73 5CCOMPT
+3332COUST JEAN PIERRE FLORENT 11973 2199507199407 7803 7679.46 5CSANS
+4946SAUVAGE PATRICIA 21974 5199604199504 7803 7680.77 5MSANS
+1918BABY DOMINIQUE 21974 519941019950810668 9425.45 5MINFOR
+6316CORENTIN MARTINE RENEE 21974 119930919920911389 9851.84 5CANGL
+3700PROSPER MARTINE 21974 4199508199408 7464 7524.42 5CANGL
+2405COUDUN WALID 1197411199605199505 7803 7679.55 5CALLEM
+7545DELEY MARTINE 21975 2199606199506 7803 7679.91 5MSANS
+3372HARRETCHEVERRIA FRANCISCO 11975 3199506199406 9894 8921.49 5CALLEM
+4733SIMON CATHERINE 21975 9199608199508 7464 7525.73 5CESP
+3419LAVIROTTE MICHELE 2197510199507199407 7803 7679.76 5CALLEM
+3469VASNIER CORINNE 21976 6199607199507 7803 7679.73 5CSANS
+7472VERLAI JEAN MARIE 11977 3199606199506 7803 7680.84 5CSANS
+5601PEYNIBLOU ROBERT 11977 1199606199506 7803 7680.44 5CANGL
+3668NARCISSES MARIE FRANCE 21977 9199606199506 7803 7681.07 5CSANS
+9202GARE BRIGITTE MARIE MADEL21977 3199507199407 7803 7679.58 5CTECHN
+4110KEROUAL FABRICE 1197711199607199507 7803 7679.54 5CSANS
+3531OUCHE ALAIN 11935 31965081995011557012568.13 6MSANS
+3428DAUPHINS NOUNA 21935 81967011990071578112723.50 6MSANS
+8594BAIE JACQUES 11936 51962021994033844228045.97 6MALLEM
+1267ORGE GERARD 11938 41964041994011557012567.81 6MSANS
+7513PINSONS PATRICK 11938 41963071995082947921839.78 6MSANS
+4234DORMANT CHANTAL 21939 71970011991011932314934.66 6CINFOR
+4904PANORAMIC LAURENCE 21940 9198901198610 8656 8146.50 6.SANS
+3727GUYNEMER VERONIQUE 21940 51972051989101621213032.21 6CSANS
+8364COUDERC ANNICK 21941111973101990071621213033.61 6CANGL
+1743VALLEES GERARD 11941 71970041995062470018540.61 6MANGL
+5058LIBERATION THIERRY 11941111973101991011403411521.37 6MSANS
+8875BRAILLE CLAUDE 11941 71974041989101834514274.74 6MSANS
+5325HESPERIDES JACQUES 11942 81963041991072273717260.64 6MANGL
+9083PONS JEANNE 21942111972101994041894014662.64 6MSANS
+3082SIROIS JEAN 11942 11965111989071663613342.67 6MANGL
+0164ENCRABE DOMINIQUE MARIE 21942 8198810198410 8656 8145.03 6.ANGL
+5264PARLY MARIE HELENE 21943 61963031993032922321685.16 6MANGL
+3102GRDE GERARD 11943 11966061991012470018540.24 6MANGL
+6225GRAVAS GILBERT 119431219750819881211389 9852.47 6MINFOR
+0486TOCQUEVILLE MICHEL 11943 71965061990012470018541.72 6MSANS
+6103DAUDIN MICHEL 11943 31971081991071433211713.97 6MANGL
+9562JULES MARYSE 21943 71962091984062470018540.75 6VANGL
+1659EVANS MARIE NOELLE 21944 21963121994072137316331.91 6MSANS
+5753SAXE BERNARD 11944 51964111985063200223582.85 6MSANS
+5551AMBROISE GILES 11944 21972081991012470018541.97 6MSANS
+2734FELICE PHILIPPE 11945 91970051991011433211715.24 6MSANS
+2627SAVIGNY ANDRE AUGUSTE 11945 71964121990052470018542.04 6MSANS
+2707VAUGIRARD HELENE 21945 8199407199307 7590 7562.63 6MSANS
+0420DARDOUNELLES DANIEL 11945 21971021990011433211714.52 6MINFOR
+0574JAURES MARC 11946101972081994011663613343.70 6MANGL
+4658BORA JEAN PIERRE 11946 31973091992011403411520.69 6MMARKT
+2852BERLIOZ PASCAL ALAIN 11946121969111991012273717260.45 6MSANS
+9183STATION BERNARD 11947 61976101991011283810705.62 6MSANS
+7225BONSECOURS ANNE 21947 51976071993111471512024.74 6DSANS
+5915ANTILLES ISABELLE 21948 61969081995101433211714.47 6MSANS
+7173GIOTERAIE ROBERT 11948 61967111986042470018541.91 6MANGL
+7940NICOT ERIC 11949121974041992011403411520.15 6MSANS
+6066CLEMENCEAU YVES 11949 31971041995012201216756.31 6MSANS
+8113VITRY DOMINIQUE 21949 7199311199211 9597 8728.28 6DVENTE
+6047TASSIGNY THIERRY 11950 41973081994122470018541.72 6MTECHN
+9002BERRAT BRUNO 11950 51977051993041369311286.29 6CANGL
+8038AUDIBERT PATRICK 11950 719770119931211389 9850.58 6MINFOR
+4759BLANCHE MAYAKO 21950 51970101991071578112723.11 6MSANS
+6982CYRANO DANIELLE 21950 51974111991071578112723.74 6CANGL
+9782BARRAGE CLAUDINE 21950 3199109198902 8656 8146.01 6.ANGL
+4552ABBADIE MONIQUE 21950 61976011991101578112722.87 6MANGL
+3112AGENT DANIELLE 21950 11993121992011202810240.31 6MESP
+4893GRANDE ISABELLE 2195012199507199301 7677 7604.70 6MINFOR
+6863FERTE MARIE JOSE 21950 71970101991012137316330.65 6MINFOR
+3487TALARIC MICHELINE 21950 21973101991071578112722.51 6MANGL
+7125FERRAYONN JEAN MICHEL SERGE 11951101977101994041249910473.47 6MVENTE
+5445RON DOMINIQUE 11951121971101991013200223582.31 6MSANS
+0070PLASCASSIER DANIEL 11951121975051991011369311286.30 6MSANS
+0688PARGAMINIERE JEAN 11951101976061993011369311286.15 6MSANS
+0032FOUR CLAUDE 11951 61975111991011684813421.95 6MCOMPT
+2442BOULOC MARIE FRANCOISE 21951 31974051986052334017609.66 6MALLEM
+3898KENNEDY YVES 11951121977101991011369311287.25 6MANGL
+8228LEFRANC JEAN LOUIS 119521219931119910110791 9502.26 6MSANS
+7142LEGER VINCENT 11952 81976051991011684813421.99 6MANGL
+0571DOMINICAINES JERZY 11952 31971101991013200223582.94 6MSANS
+0382KERHAM CATHERINE 21952 21974041991071578112722.07 6MSANS
+8150BEARN FRANCK 11952 21982091993011527112372.87 6MSANS
+7995BAUDIN DANIEL 11953 91975051994011369311287.19 6MSANS
+4159CHASSENARD JEAN BERNARD 11953 519870619860610791 9503.21 6MSANS
+3964FAREMOUTIERS LAURENCE 21953 6199311199211 8656 8145.08 6MSANS
+0454CHERBOURG ISABELLE 21953 6199610199510 7803 7679.81 6MVENTE
+5111CROIZAT CHRISTOPHE 11953111973031990071578112722.69 6MALLEM
+2014LISIERE XAVIER 11953 8198911199501 9894 8923.22 6MSANS
+9741PARIS PASCAL ELIE 11954101978081991012022115555.53 6MTECHN
+0737YERRES GERARD 11954 61976091995042529918968.84 6MTECHN
+3053TORRE PAULE 21955 91976061995101881314585.97 6MVENTE
+2120CORMEILLE JEAN LUC 11955 5199610199510 8656 8146.74 6MSANS
+1540PIJOUNIE ANGELE 21956 51977021981091834514274.87 6MANGL
+6259VICQ CATHERINE COLETTE 21956 219780719770710668 9425.82 6MSANS
+8345DAGOBERT DJARN 11956 719820919871111131 9658.24 6MINFOR
+3734GARNIER PASCAL FRANCOIS 11956101977081994042201216756.71 6MSANS
+4365ESSO ANTOINE 11956121976061994011369311288.10 6MSANS
+0262ROLLAT HERVE 11956111979081991012175716601.93 6MSANS
+7989RHONE YVES 11956 71977051994041249910472.06 6MANGL
+4035ISLIP ANNIE CLAUDE 21957 41993101992011249910472.06 6MINFOR
+8638DUNOIS JACQUES 11957 51981031995062273717260.50 6MINFOR
+6417ALBI RENE 11957111980091993121369311288.04 6MANGL
+7559MARIENTHAL MONIQUE 21958 319940919930411389 9852.59 6MSANS
+1621CAMBRIDGE ALAIN 11958 8199312199212 9597 8729.04 6MINFOR
+3476CREPY ALICE 2195811198711198611 9511 8688.22 6MSANS
+2482CHORON EVELYNE 21958 7199110199409 8656 8145.42 6.SANS
+4165BALZAC MICHEL 11958 71985121995011433211713.76 6MSANS
+9040FERDINAND CHARLES 119581219781019771011389 9852.24 6MANGL
+6858CUVRAY MARTINE 21959 71980041994011471512025.82 6MMARKT
+2723PAPARA FRANCOISE 21959 61980051994011471512025.70 6MTECHN
+1222FOSSES MONIQUE 21959 21980041993121804514081.78 6MTECHN
+8741BOULEVARD MICHEL JACQUES 11959 91979021993041471512024.62 6MTECHN
+5441ZOLA BRIGITTE 21959111979081993071471512025.82 6MINFOR
+9947ERMITA CATHERINE 21959 81982081981081326611017.38 6MSANS
+2563FLORISSANT PHILIPPE 11959 51981071989052256617145.21 6MMANAG
+3583MOLLAY JEROME 11959 81981031993051608112916.41 6MALLEM
+6466ORMES ANNIE 21961 21981081995071433211713.85 6MALLEM
+1432AGRIANT ROBERT 11961 31984031991091527112372.83 6MCOMPT
+3657NOVEMBRE SERGE 11961 51986071992101527112374.36 6MSANS
+5054FRANCK HUGUES 11961111984031983031608112915.87 6MALLEM
+7313CRESTET JEAN PIERRE 11961 41984091994091326611017.55 6MSANS
+1383ORIOL ANNE 21961 61983021982021288210744.01 6DSANS
+9235DANTE JEAN MARIE 11962 71984031993081527112374.13 6MANGL
+1924MALVEZIN MARTINE 21962111984071983071608112915.47 6MSANS
+0722MUSSE JOELLE 21962101982081981081608112916.65 6MMICRO
+2536BEAUSOLEIL DOMINIQUE 11962 219830419851210791 9502.17 6MSANS
+3286DEEPFIELD GERALD 11962 319930819921210876 9502.09 6CSANS
+9760CHAMPET MARTINE 21962121988101987101202810241.67 6DTECHN
+0459FERRAILLONS NICOLAS 11962 819850919840910791 9501.95 6MSANS
+9070ROUGUETS JEAN RENAUD 11962 919920519910510024 8999.54 6MSANS
+5609MONNEGER GEORGES 11962 61984101993051527112374.00 6MALLEM
+8699COLMAR CATHERINE 21962 21988061987061202810241.09 6MINFOR
+0121PARAY JEAN FRANCOIS 11963 219830419920311131 9658.07 6MVENTE
+9033TIMBAL FRANCOIS 11963 91991021991022529918969.60 6MSANS
+0477HORTENSE ALAIN 11963 51984021992101527112374.84 6CSANS
+9565CARRETIER JOSE 11963 81986121992121450311830.53 6MINFOR
+5210BARTHOU PASCAL 11963 319850419850511131 9657.21 6MANGL
+7365GALLAIS PATRICE 11963101984031983081288210745.79 6MSANS
+3436TADJOURAH PATRICK 11964 51984061991011288210744.35 6MTECHN
+0043HILLS JEAN MARC 11964 719840619830610791 9503.67 6SSANS
+6646ROOSEVELT FLORENCE ANNICK 21964 51989111988111249910472.39 6MESP
+5680PORSMORIC MARIE MADELEINE 21964 31983041982041326611017.97 6MANGL
+6503MONCEY JEAN PAUL 11964 319940219930110024 8998.77 6MALLEM
+9162BROSSOLETTE MARYVONNE 21964 91984111983111288210744.28 6MSANS
+5895QUATRE DANIEL 11964 31984101993011616712994.89 6MSANS
+3689ETOILE ALAIN 11965 31985051992011527112374.54 6MSANS
+6754MAXIMIN JEROME 119651119930819920811389 9851.10 6MANGL
+1818BOYARDVILLE KINEO 11965 919850519840510791 9501.83 6MALLEM
+6998HONORE PATRICIA 21965 31989051994011381911366.18 6DSANS
+0086COLLETTE SERGE 11965 41985091991121288210744.14 6MALLEM
+2914ESPAGNET ERWAN 11965 21984051983051288210744.17 6MSANS
+9284COLIBRIS JEAN JACQUES 11965 41993101992101330611018.00 6MTECHN
+5732LEUTHREAU ALAIN CHRISTIAN 11965 11987081992011450311831.39 6MSANS
+7234MARDELLE ROGER 11965 81986041993051450311832.14 6MALLEM
+2688TILLEUL FREDERIC 11965 619930719940110876 9503.04 6MSANS
+6325MIGNEAUX FRANCOIS 11965 419940119920110407 9270.44 6MANGL
+0520PIBRAC STEPHANE 11965 219850819840810791 9503.76 6MSANS
+5142HUBIES BRIGITTE NOELLE 21966 41991071990071202810241.79 6MCOMPT
+2662PEYLONG GHISLAINE 21966 9199201199101 7803 7680.36 6.SANS
+5787PRADIER PHILIPPE 11966 11987051994091693613499.34 6MALLEM
+0594PARK GILLES 11967 11989101988101249910472.52 6MSANS
+9155VIADIEU DIDIER 119671219940419920110024 8998.50 6MSANS
+9944STRASBOURG ROBERT 11967121993061992061267210590.24 6MALLEM
+0751MONTDAUPHIN CLAUDE 11967 819910319950610024 8998.80 6CANGL
+6596INFROIT STEPHEN 11967 41990011994011249910473.45 6MSANS
+2539CARTHY ANNICK 21967 41994071992011202810241.09 6MSANS
+9966ENFERT BRIGITTE 21967 919930719920711389 9851.37 6MALLEM
+8934REGNIER ANNICK 219671019950319930411389 9851.96 6MALLEM
+1654LEADER MICHEL 11967101995101994101839014312.60 6CANGL
+7794ANEMONES EVELYNE FRANCOISE 21968 11993031991011202810241.66 6MTECHN
+5095BLAIRE MARIE JOSE 21968111989101988101539912453.06 6CSANS
+3446RICHOIN JEAN PIERRE 11968121990091994121450311832.51 6MINFOR
+0591FERON CHRISTINE 21968101994031992011202810240.76 6CSANS
+6142SORBIERS ROSWITHA 21968 81993061992061267210589.60 6CSANS
+4698JEAN GERARD 11969 51989101991091249910472.96 6MTECHN
+9192SAVIGNE ALAIN 11969 31991011990011202810240.26 6MESP
+0014NANTAUX ETIENNE 11969121994061992011202810240.46 6MANGL
+6632JULLIAN FREDERIC 11969 9199102199002 8656 8145.20 6.SANS
+1053MORTIER GUY 11969111992121991121330611016.35 6CALLEM
+3261SUCHET MARIE THERESE 21969111994031992011202810239.91 6MSANS
+4711BLANCHE ALAIN 11969121992121993031267210589.55 6MCOMPT
+5942FLOREAL JEAN PAUL 11969 11990111989111381911366.49 6CVENTE
+1744ESPAGNE JEAN PAUL 11969 119900219890210024 8998.41 6MESP
+7503TOUCHARD ANNE MARIE 21970 21990111989111202810241.57 6MSANS
+2585ESTIENNES JEAN 11970111993111992111330611018.18 6MANGL
+8805CHENIER ROBERT 11970 71992071991071420611638.05 6MSANS
+7438ROSELINES SYLVIE 21970101994031992011202810240.72 6CSANS
+6724POTHONNIER MARIE JEANNE 2197011199206199106 8656 8146.42 6.SANS
+5056POINCARRE KARINE 21970111994031992011202810241.45 6MINFOR
+2915REILLE MICHEL 11970 7199602199502 9256 8533.59 6CANGL
+3988ATALANTE BRUNO YVES 1197012199402199302 9597 8728.68 6CANGL
+3548JOURDAN GUY 11970101994061992011202810240.35 6CALLEM
+1071CHAROLLES JACQUES 11970 1199306199206 9597 8728.82 6CINFOR
+7830BOCH BERNARD 11970 3199304199308 9597 8729.09 6CINFOR
+7543REIN PIERRE 11970 9199501199401 8656 8146.05 6MSANS
+0754ELANS EVELYNE 21970 5199010198910 8656 8146.07 6.SANS
+0414CHARDON HERVE 119711019931019921011389 9852.65 6MESP
+3628VILLACOUBLAY PHILIPPE 11971 919930319920311389 9851.12 6MALLEM
+0150ADDAX MICHEL 119711219940719920110024 8999.70 6CVENTE
+9176CAHEN HUGUES JEAN LUC 11971 219921019911011389 9852.24 6CSANS
+2846COOLE SERGE 11971 1199403199201 9597 8729.70 6CSANS
+2967LANCIERS KLAUS 11972 819930319920311389 9851.59 6CANGL
+5218EXELMANS JEAN JACQUES 11972 1199210199101 9597 8727.83 6MMICRO
+5276ALLEE JEAN JACQUES 11972 519931219921210363 9233.79 6MALLEM
+7650FARLED DANIEL 119721119941219931210363 9232.28 6MTECHN
+1760COURTILLE FLORENCE CLAUDE 21972 419940819920111389 9851.61 6MSANS
+0061FLORIDA CLAUDE 21972 719930519920511389 9851.24 6CANGL
+4799DUBAN REMY 11973121993011994011202810240.82 6CSANS
+5516LUZAC BERNARD 11973 5199606199506 7803 7680.27 6CMICRO
+2886KERINEL PATRICK 1197311199309199209 9126 8456.47 6CALLEM
+2318BURNOL MICHEL 11973 6199310199210 9597 8729.58 6CALLEM
+2243BASCH GEORGETTE 21973 319930919920911389 9852.41 6MSANS
+9674JAUNE SANDRINE 219731219951219941210668 9426.66 6MVENTE
+3507CAMPANULES GERALDINE 21973111994031993031267210590.14 6CTECHN
+8457ROAD MARTINE 21974 719940619930610668 9426.03 6MSANS
+5644PERROQUETS PHILIPPE ANDRE 11974 3199407199307 9126 8455.98 6MANGL
+5222PASTEUR CLAUDE 11974 3199606199304 9126 8456.34 6CTECHN
+2362GORBELLA ANNIE 21974 21994091994071450311830.61 6CANGL
+3214NELSON JEAN YVES 11974 2199412199312 8359 7953.60 6CINFOR
+2883CHEIRON MICHEL 1197511199611199511 9256 8532.96 6CSANS
+3892LENNON NICOLE 21975 3199207199307 7803 7681.02 6.INFOR
+2980ROASSAL JEAN MARC 11975 7199507199407 7803 7680.67 6CTECHN
+3954BARONNETTE FRANCOISE 2197612199610199510 7803 7680.59 6CANGL
+8734MARGUERITE ANNIE 21977 6199606199506 7803 7679.49 6CSANS
+2986ROURE CLAUDE 11977 8199608199508 7803 7679.40 6CSANS
+2812FABIEN CATHERINE SYLVIE 21930 1198905199501 8827 8264.04 7.SANS
+4059LECOURBE FREDERIQUE 21935 41961101982052470018540.38 7VSANS
+3810LACS ELIANE 21935 51961111987012273717261.07 7MANGL
+1179VIES FRANCOISE 21935 1199306199501 8656 8146.82 7.TECHN
+4536CAPUCINS JEAN PIERRE 11936 61958121993103200223584.44 7MSANS
+5665CAMOIN MARIE CLAUDE 21936 8198910198511 8656 8145.15 7.SANS
+5858BONODIERE MARIE CECILE 21937 41962071985102273717261.25 7MALLEM
+3737MAREY ANDRE 11937101973071992011403411520.80 7MALLEM
+3343ECLUSE SERGE 11939 21970081995062201216755.92 7MMARKT
+7410MONNETIER MARIE JOSEPH GEORGE 21939 51963051991072273717260.50 7MANGL
+9145ULI MARC 11940 31969061991011433211714.60 7MALLEM
+4704MANOLA MICHELLE 21941 11961081987032572519241.16 7CALLEM
+6915PLERGUER JOSE 11941 81973071992041403411521.34 7MSANS
+1437DIGUE GEORGES 11942 11973071992011403411521.70 7DSANS
+7658DOYENNES PATRICIA 21942 51964101992072273717261.07 7MSANS
+3938DOMINE OLIVIER 11943 51971041991011433211714.10 7MALLEM
+4424CORBEIL JEAN PIERRE 11943 81974051993011369311287.59 7MSANS
+7614PHILIPPE MICHEL 11943 31963091986012273717260.13 7MSANS
+3959RONCIERE MARIE CLAUDE 21943 21973071990041621213033.19 7MSANS
+9296THABAS ANITA 21944 51964071990102273717261.39 7CALLEM
+9017DELAPORTE ANNE PATRICIA 2194511199201199101 7803 7679.64 7.SANS
+3629RAMBUTEAU JEAN PIERRE 11945121972061991071433211715.51 7MANGL
+3070ETIOLLES MICHEL 11946 21975031994121471512025.95 7MANGL
+3212CYCLADES BEATRICE 21946 31966121995072017815517.38 7MSANS
+8064ARCANGUES MARIE CHRISTINE 21946 71969031984062470018542.19 7CSANS
+4281GAURBETS CHRISTIAN 11946 319890119941110791 9502.01 7MANGL
+0562BLANQUET ANNE 21946 6198810198511 8656 8145.21 7.SANS
+2853MESTE MARYSE 21946 1199301199201 9085 8417.91 7MTECHN
+4550CHEVRY CLAIRE 21947 71968041993111834514275.06 7MVENTE
+2513EUDES SABINE 21948 11970041993121834514276.18 7MTECHN
+2928HEYRAULT FRANCOIS 11948 21972041991012137316331.56 7MESP
+8846LIGNIERES JEAN CLAUDE 11948 41975061991011369311287.77 7MSANS
+0470POTEL PHILIPPE 11949 21974051991112043315669.51 7MCOMPT
+7926OUSTAOU CATHERINE 21949 31970111988042334017610.69 7CVENTE
+1398NOUVEAU MARIE PIERRE 21949111969101990012137316331.39 7CSANS
+7196THIERS PASCAL 119501019800619790611389 9852.33 7MSANS
+8076DELANNE COLETTE EMMANUELLE 21951 71971061990011621213033.43 7MSANS
+8525VOISIN PIERRE 11951 61976051991071578112723.68 7MTECHN
+7965DELESTRAINT MARIE CLAIRE 21952111973021992102017815517.91 7MALLEM
+2553CONVENTION MONIQUE 21952 91978061992121471512025.64 7MTECHN
+3819SOLEMAR ANNE 21952 81979061979021684813422.18 7CTECHN
+3540SAISSY DANIEL 11953 81980081989041684813422.77 7MALLEM
+1880GOUFFE JEAN CLAUDE 11953 71983061995011578112722.61 7MSANS
+7620MOIRAX REINE 2195310199307199207 9894 8923.11 7MSANS
+2953TOMBE PATRICIA GABRIELLE 21953 41975101991091578112723.06 7MTECHN
+5507ALEXIS JOCELYNE 21954 41975011974011288210745.40 7MSANS
+4941FONVAL MAX 11954 41978051994011369311286.83 7MSANS
+4394BRIAND JOSETTE 21954 71975051995011881314584.61 7MALLEM
+6207FOINS CLARISSE 21954121976071992011578112723.18 7CSANS
+9748CHARVE MARIE CLAUDE 21954 1199103198801 9894 8921.67 7MSANS
+9682TIPHAINE JEAN CLAUDE 11955101978091994041471512026.06 7MINFOR
+1788NAJY ALAIN 11955 11975031991071578112721.89 7MINFOR
+7956NOTAIRE FRANCOISE MADELEINE 21955 31977011981041684813422.41 7MSANS
+3415PRAIRIE PASCALE 21956 719911219901210024 8999.63 7MSANS
+9208ESCADENIERES JEAN FRANCOIS 11956 61984081993011471512026.22 7MSANS
+0945MAISON HEIKE 21956121977021992011471512024.30 7MSANS
+2271LANDE MICHEL 11957 41982021994011471512025.56 7MSANS
+3201BANGKOKNOI CATHERINE MONIQUE 21957 41978081977081834514275.41 7MANGL
+6914BANCHEREAUX JOSETTE 21957 31981051995041433211714.15 7MANGL
+8957LAFFON BENOIT 11958111977091994011621213033.05 7MSANS
+4169FOUBERT AUGUST 11959 819820519871011131 9658.59 7MANGL
+7880DIV JOELLE 21959111982041981041330611017.86 7MMICRO
+7448ORSAY SYLVIE 21959 11984111983111608112917.15 7MSANS
+6126SAUVEUR ANNICK 21961 21981051980051288210745.75 7MSANS
+7782PETRO CHRISTIANE 21961 4199004198706 8656 8145.57 7.SANS
+3730PEREIRE FABIENNE 21962 51982091981091608112916.37 7MTECHN
+4013TROUIN ETIENNE 11962 21987061993091839014312.81 7MTECHN
+1602VINCENT MICHEL 11963 51986111985112090215979.83 7MSANS
+1113AVENYE PASCALE 21963 8199407199307 7803 7680.81 7MSANS
+5901GIORDAN JACK 119641119840219830210791 9503.99 7MTECHN
+5007CASTEBELLE PATRICE 11964 41984061993121288210745.40 7MVENTE
+5706QUIOU SUMIYO 21965121986091985091288210745.79 7MSANS
+8009COULOMMIERES FRANCIS 11965 119880819870810407 9271.16 7CSANS
+4505VERGNE IRENE 21966 61991031990031381911366.63 7MSANS
+2764BALAN GABRIEL 11967 21988051992121249910472.84 7MSANS
+5527CHAMIER BLAISE 11968 81992011991011381911366.84 7MSANS
+9559OUSTALET JACQUES 11970 2199207199402 8656 8146.28 7.ANGL
+9156GUILHERMY YUKO 21972 8199208199108 7803 7679.37 7.SANS
+2342LAJARRIGE MARIE JOSE 219721219920719910710363 9233.39 7.SANS
+0358MERINDOL JEAN PIERRE 11974 81995051994071288210745.57 7CALLEM
+7473MERMOZ JACQUELINE 21931 7198810199501 8656 8147.15 8.SANS
+7635DERAIN NATHALIE 21933 4198903199501 8656 8145.62 8.COMPT
+2535TREVISE PHILIPPE 11935 61963081994122666519901.15 8MSANS
+4757GERMINY MARIE LOUISE 21935 81954091982072273717260.53 8MANGL
+5975FAVORITE MICHEL SERGE 11935121963041981052470018541.88 8MSANS
+3758CALANDRELLES YVES 11935 51968021993011663613344.05 8MVENTE
+3094TARN ANNICK 21935 61959081982052470018541.01 8MSANS
+7689COURONNE MICHEL 11936 91958091995012666519900.32 8MSANS
+0853COLLEDEBOEUF PIERRE 11936 71973031992041403411520.30 8MSANS
+5252COSSIGNY PASCAL PAUL 11936 21964121989072947921839.52 8VSANS
+2084HARET COLETTE 21937 5199605199505 7803 7680.09 8MSANS
+8285MASSENET MARIE FRANCE 21937 81963091991072273717260.26 8CANGL
+7176ROBESPIERRE PATRICK 11938111962121985072273717260.68 8MANGL
+1151QUERCIOLO ABDELAZIZ 11938 31965111995011834514274.24 8CSANS
+1464SANE CLAUDE 11938 9198801198604 8656 8145.80 8.INFOR
+6980MARTIN CHRISTIAN 11938 71972101990011433211714.42 8MSANS
+7189CUERS JEAN BAPTISTE 11939 81966071993011663613344.45 8MSANS
+7123BOISSIER MARIE JOSEE 21939 61962121990102273717260.22 8CINFOR
+7519VACHET CATHERINE 21939 11983081992011326611016.12 8MANGL
+2640BARBERAZ MARYSE 21939 61967011989091932314933.85 8MSANS
+1630GRACAY ISABELLE 21939 71966071991101932314933.67 8MSANS
+6303DOUBLE YVELINE 21939 51964071994102666519901.01 8DANGL
+8547BEAU SOPHIE 21939 71967071990071578112722.87 8VSANS
+7642ROCHEREAU ANNICK 21939 41966061994072137316330.94 8MSANS
+4913LAURICESQUE JEAN FRANCOIS 11939 619900719920710407 9271.92 8MSANS
+0289CARIBOU ELISABETH 21940 21959051992091932314934.03 8MSANS
+5838MAUPERTHUIS CLAUDE 11940111961061994053417325097.60 8MVENTE
+1874GRANGES CATHERINE 21940 819940919920110024 8999.72 8MSANS
+1504FONTENAY GERARD 11940 51963121988113200223582.58 8MSANS
+9111MONTILS DENIS 11940 31973031992071369311287.46 8MSANS
+8171VIVES FRANCOIS 11940101966071989071433211715.65 8MSANS
+5585COLLEGE REMY 11941111971121991052022115556.35 8MSANS
+6338ANSE FRANCIS 11941 11963071992041557012568.02 8MVENTE
+9521ARBOUSIERS ANNY 21941 71963031993122334017609.66 8DSANS
+5504HONORE MARC 11941101966071990011433211715.68 8MSANS
+0434ROUGET ELIANE 21941 41961051994101684813421.91 8MINFOR
+8697ROCHEFORT MARIE CLAIRE 21941 81963031991072273717259.86 8CANGL
+5183NID BRIGITTE 21941111969011992121834514274.42 8MANGL
+4171LAFFITTE ODILE 21941 6199201199101 7803 7679.41 8.ALLEM
+9168OISANS DOMINIQUE 11942 61976101992011578112723.00 8MSANS
+0577REDERSKAAI ANNE 21942 41971011994071834514275.68 8VSANS
+4455LORREZ ERIC 11942 4198810198604 8656 8146.28 8.ESP
+1456ALESIA LIONEL 11942 41963041984102470018541.64 8MANGL
+6360QUESSINE PATRICK 11942 51962111993123200223584.16 8MSANS
+9206RAVAGERS LUC 11942 71967011994121557012567.18 8MSANS
+5506ORA MARCK WITOLD 11942 81964071992012470018540.60 8MANGL
+0645MALOUET MYRIAM 21942 81962101991072273717261.18 8MSANS
+2325LONGUERAIE GUY 11943 61975031990011433211713.61 8MSANS
+6153LUNAIN LINETTE 21943 9198810198604 8656 8147.06 8.SANS
+8628ANCIENS PATRICK 11943 21963041992032739020403.89 8MVENTE
+7345FLORENT FREDERIQUE 21943 41962121987082470018541.61 8CTECHN
+9650GODARD GERARD JEAN 11943121975021993011369311286.71 8CANGL
+0047BEUNE YANNICK MARIE 11943 71962121984092470018540.80 8MSANS
+9696RAFFET CHRISTOPHE 11943121993041992041642313188.35 8.ESP
+2868MONTREAL SABINE PASQUA 2194312199401199301 8656 8146.11 8MSANS
+9052ORANGE JACQUES 11943 61972071992011433211714.46 8MANGL
+0622GEOFFROY MARTINE 21943111970091991101932314934.93 8VVENTE
+5329VILETTE GUY 11944 21967121990041433211714.75 8MSANS
+7979BORDS MAEVA 21944121964071993061834514275.97 8MSANS
+0046GREENS BRIGITTE 21944 4199009198909 8656 8147.19 8.SANS
+7861LAGACHE CAROLINE 21944121963111991072273717260.85 8MSANS
+6041MAIRIE MICHEL 11944 61969101989056400345693.48 8MSANS
+6790VAUX ARIANE ELIANE 21944 31964071993102137316332.47 8MANGL
+7706NICOLE CHRISTIAN 11945 31966041995072137316330.79 8CSANS
+3032VOIE CLAUDE 2194510199501199401 7803 7680.95 8CSANS
+4678GASCOGNE LYDIA 21945 51966121993011471512025.37 8MTECHN
+6211LEFEVRE MIREILLE 21945 61966021995042137316330.58 8MSANS
+4373CHENAIE FRANCOIS 11945 419940919930910363 9232.55 8MSANS
+6516SABLONS ROBERT 11946 91982011992101249910472.66 8CSANS
+3672CORVETTE JOELLE 21946101968111992121834514274.53 8DALLEM
+6368ALPES ANNE CLAIRE 21946 31965121993031834514276.15 8DTECHN
+9883MATRUT NICOLE 21946121973041993041471512025.11 8MSANS
+1004DUNOIS GERARD 11946111973071992121518612335.69 8MSANS
+5302REMUSAT ALAIN 11946 11975051991011578112723.33 8MSANS
+0673VASES DANIEL 11946 41969051995032666519900.02 8MINFOR
+5739COUR CLAUDE 21946 3199512199412 8656 8146.09 8MSANS
+0992EVENOS GERARD 11947 819941119920110407 9271.52 8MCOMPT
+2791BERTHELOT ANNIE 21947 51977071991101578112723.00 8CSANS
+7501GOUBET FRANCOIS PIERRE 11947121972121991071621213032.53 8MTECHN
+8208PIERRAILLES MICHELINE 21947 91971011995011834514275.91 8MSANS
+2702BLAQUE JEAN JACQUES 11947 11970061991102739020405.01 8MTECHN
+8704COLLINE JEAN PIERRE 11947 119890119880110152 9116.67 8MSANS
+4666HELLEN PIERRE 11947 61979021993041471512024.60 8MSANS
+8568AQUILON ISABELLE 21947 11969011991012137316332.22 8MANGL
+7824REVA JOSIANE 21948 6199003198608 8656 8146.61 8.SANS
+9576MONTET LIONEL 11948 61969121994072470018541.95 8MSANS
+3165HAUTS MYRIAM 21948 51970121991022022115555.81 8MANGL
+9783THOMAS MARIE PAULE 21948 51971101990072022115555.44 8CMANAG
+0892EPARGNE PIERRE 11948121973051990011684813423.29 8MSANS
+8463GIMONT MARIE LAURE 21948111970011991071834514274.30 8MSANS
+3612GLENAN ALAIN 11948 11973071990011834514276.06 8MSANS
+3989AVENIR HERVE 11948 41979071992011249910472.66 8MSANS
+1849GRASSE JEAN MARIE 11948 51974111992041403411521.97 8MSANS
+5860GRANGES MARLENE 21949121969031989011621213032.26 8MSANS
+0021ECOLES MARTIAL 11949 91981091992011249910472.37 8MSANS
+5620BLANC MARIE SABINE 21949 1199107198704 8656 8146.01 8.SANS
+9485MONT PHILIPPE 1194911198704198604 8656 8146.68 8.SANS
+5814TERMES YVES 11949 41978021993121369311286.03 8MSANS
+7863YESILKOY DOMINIQUE 11949 71969031990012137316330.92 8MANGL
+0579HILARION ETIENNE 11949 31968121989021932314934.09 8MSANS
+4379FORGERONS JEAN FRANCOIS 11949 11977041993011369311287.16 8CANGL
+3965BOISGELOUP ANNE ANDREE 21949 81971011984082470018542.24 8MINFOR
+8322FLAYAT RICHARD 11949 119800919860911389 9851.64 8MSANS
+3220PLASCASSIER CATHERINE 21950 91974051991071578112721.53 8CSANS
+2062NOIRAY GUY 11950 31993111992111642313189.25 8.SANS
+1017COROT MICHEL 11950 11977021993041369311286.53 8CANGL
+5913CITEAUX YVES 11950 61978031995082000715437.49 8MTECHN
+4766COLOMBE GUY 11950 81972041989101621213033.97 8CANGL
+8829CARCE ANNICK 21950 51970111991071578112723.22 8MSANS
+5482ENTREPIERRES DOMINIQUE 21950 81974081991081578112723.00 8MMARKT
+6118THEOPHILE PHILIPPE 11950 21970041995102666519900.36 8MSANS
+6158PUYGARD PHILIPPE 11950121971041993103916628549.82 8MSANS
+7664FRANCOIS HUBERT 11950 41974071993011369311287.46 8MANGL
+3674HOP VINATIER ANNE ODETTE 2195010199507199407 8359 7952.07 8MINFOR
+8401STADE YVES 11951121972051990011621213032.80 8MINFOR
+4992SOLEIL MURIEL NICOLE 21951101972021991072137316330.58 8MANGL
+4163FRESNAIE PHILIPPE 11951121977051991011684813423.49 8MALLEM
+6140VERTE ICHIKO 21951 51972071993042017815516.20 8MANGL
+7521SILLAT JOELLE 21951 71973081991021684813421.81 8MSANS
+8682HUYSMANS DANIEL 11951 61977051993011471512025.47 8CSANS
+4383JAVELOT CLAIRE 21952 21975041995101881314584.67 8MANGL
+3010CARLA ANNE 21952 21972081980102470018540.07 8MSANS
+5234BELLEGARDE GHISLAINE 21952 51972021991121608112916.45 8MSANS
+4958NAPOULE ANDREE 21952 71974011973011288210743.90 8MSANS
+8132ALDE PATRICK 11952 61971121989071621213032.29 8MSANS
+6296ALEXANDRIE CATHERINE 21952 11973051994041450311832.36 8MALLEM
+2851FEDERATION JACKY BRUNO 11952 419830419820411389 9851.21 8MSANS
+2922TRIERE JEAN PIERRE 11952 21972041989101621213032.87 8MESP
+4520BARONNETTES MICHEL 11952 51975121993011369311287.43 8MSANS
+7884LEPINE YAN MICH 11952 11986061995071288210745.04 8MSANS
+2916GRENADIERS LAURENT 11952 71977101991041578112721.89 8CSANS
+6995CIVRY MARILYN 21953111975041993041471512025.05 8MVENTE
+8042BERTHE DANIEL 11953 11976071993011369311286.57 8MSANS
+4389CARPATODE JACQUELINE 21953 31974051993012017815517.95 8MSANS
+4164THENIOUX THIERRY MICHEL 11953 31972071992072175716602.09 8DTECHN
+9986ARS DOMINIQUE 21953111974051991071578112721.65 8MMARKT
+2077VELETA CHRISTIAN 11953 81977121991071684813421.55 8MANGL
+7207VICT MICHEL 11954 71979091994041249910472.66 8CSANS
+0617ARBOUSIERS MARC 11954111981041991011608112915.62 8MANGL
+6266PALOMBES ALEXIS 11954121978061994011578112723.22 8MSANS
+3336REPUBLIQUE LOIC PIERRE 11954121986031991121288210745.67 8MTECHN
+6034LAMOTHE ROBERT 11955 71976081994011369311286.38 8MSANS
+8420COULEUVRE DIDIER BERNARD 11955 21978061994011369311286.30 8MVENTE
+7021INVILLE JEAN MICHEL 11955 11975051994012397418037.86 8MSANS
+2224EGALITE ISABELLE 21955121978031992021471512025.97 8MALLEM
+3309HELENE ISABELLE 21955 41986041992011288210745.22 8MSANS
+2341LANGUEDOC ANDRE 11955 61980081979081684813421.33 8MTECHN
+5599KOETZINGUE MARTINE 2195512199402199302 7803 7679.49 8MSANS
+1570ORB NATHALIE 21955 21976061992072043315669.60 8CTECHN
+0095DUNOISE DANIELLE 21955 21977041981011608112915.51 8MTECHN
+5288CHELLAH MARIE HELENE 21955 91976071991121578112721.88 8CALLEM
+9228CARDINALE PATRICK 11955 81979071994101249910472.03 8MSANS
+5668FOY MARC LAURENT 11955 419840319830710791 9503.63 8MSANS
+2007NEUVILLE PHILIPPE 11956 31976091991011578112721.79 8MSANS
+8560MAI DANIEL 11956121983041995101433211715.69 8MSANS
+6777PALAIS ANNE MARIE 21956 21977071976071834514274.96 8MSANS
+0514GRENIER MARIE CLAUDE 21956111978061992051471512025.43 8MANGL
+2450MEYRAN CHRISTOPHE 11956 91978081990052022115554.36 8MSANS
+0738CHATEAU SYLVIE 2195611199310199210 9894 8921.99 8MVENTE
+4115MIROIRS LINE 21957 71977071981091834514275.11 8MCOMPT
+2843BERRIERE THIERRY 11957 319930819940110876 9503.70 8MSANS
+1706KERDANIOU FREDERIQUE YVELINE 21957111979081993051608112916.01 8MTECHN
+3794MAL GERARD 11957 71989061993011326611016.03 8CANGL
+4102ZOUAVES ALAIN 11957 51980051986112256617145.74 8MMARKT
+6349GALLEU LAURENCE 21957101977021992011471512024.60 8MSANS
+1461BORGHESE TEVA 11957 91977081995041249910472.91 8MSANS
+1587CALIFO ROLAND 11958 6199305199201 9597 8729.39 8MSANS
+1182GRANCEY VALERIE 21958 11978031992021471512024.17 8CALLEM
+9993VALLON JEAN FRANCOIS 11958 21982031994011471512024.97 8MCOMPT
+3559OR CAROLINE 21959111979081993071471512025.77 8MSANS
+8859BERENGUIER MARTINE 21959 81980051993071527112373.49 8DSANS
+9596SINGER MARIE ODILE 21959111981081980081326611016.26 8MALLEM
+1614PIED JOCELYNE 21959101979081993071471512025.56 8MSANS
+7872CASTELET CATHERINE 21959 31980101979101684813422.12 8MSANS
+3066SCHWEITZER JEAN JACQUES MARIE 11959101984091993121326611016.80 8MSANS
+6764EGEOIRES DIDIER PIERRE 11959 519890819880810407 9271.56 8CANGL
+0114EGLISE ANDRE 11959121981101992101608112917.19 8MANGL
+8832ISOLA ERIC 11959121981061993121471512025.47 8MSANS
+0083BRUZETTES JEAN PAUL 11959 31984081991061326611016.78 8MSANS
+9690MAUPERTUIS GEORGES 11959 61981011989111608112915.03 8MANGL
+5294GIRONNETS MURIEL 21959 31981041980041684813421.54 8CSANS
+2982HORACE SATO 21959 7198609198507 9511 8689.07 8MSANS
+1765ARGE PHILIPPE 119591019930519920510024 8998.08 8CALLEM
+9648MOLENE HEYMAN 11960 21984111991092529918968.43 8MSANS
+2260BOULAZAC FRANCOISE 21960 11980101979101684813423.35 8MSANS
+0614RENOIR JEAN ADRIEN 11960 31983081993011215710279.72 8MSANS
+5022CARTOUCHERIE JACQUES 11960111984121994011578112723.60 8MSANS
+7019AULNES BETTY 21960121980091988051527112374.16 8MTECHN
+1225GRANIER DIDIER 11960121982091993011527112374.09 8MSANS
+0305CANTARON JACQUELINE ANNE 21960 21979111993101471512025.92 8MANGL
+9818ULBACH NATHALIE 21960 81982011981011326611018.09 8MALLEM
+6769TOURENNE MARIE HELENE 21960 81993081992011249910471.66 8MSANS
+4168CAILLE NELLY 21960 11980101979101684813423.35 8MSANS
+2371PILATTE PHILIPPE 11960121984071991061326611018.09 8MSANS
+1380SALLE BRUNO GEORGES 11960 31982011988112090215980.82 8MSANS
+1410REPUBLIQU ROZENN 21960 51983041982041608112915.17 8MSANS
+1668VALESCURE GILBERT 11961 619880319930111302 9775.91 8CESP
+4486CHANZY GILBERT 11961 81984061988052090215979.76 8MSANS
+4667CLAIR ANNICK 21961 51982071981071326611017.91 8MSANS
+3248CAMPANELLES MARTINE 21961 51982081989112090215981.29 8CSANS
+6422BARBELET THIERRY 11961 319810119800111131 9657.47 8MSANS
+5543JUMIN HENRY 1196111199405199201 9597 8729.85 8MANGL
+2561SAURSON MICHEL 11961 319820419900111131 9658.72 8MANGL
+3290CHARBONNEL PATRICIA 21961 7199607199507 8359 7952.19 8MSANS
+4075ORSAY JEAN MARC 11961 919890619950910407 9272.24 8MINFOR
+3928DAVID BERNARD 11961 51981091993121326611016.78 8MALLEM
+3502MONTGOINS ODILE 21961 91984091983091288210744.01 8CSANS
+2628MANET MICHELE 21961 51984091983091288210745.57 8MSANS
+3679LAY CAROLE 21961 81982101993071527112374.70 8CTECHN
+9476FERREOL PATRICE 11961 51985101993011168610047.54 8CALLEM
+6300VALLIER NICOLE 21961 3199207199107 8656 8146.11 8.ANGL
+2306RAHO BERNARD 11961 919900319890510407 9270.44 8MSANS
+7612VIEUX PASCAL CHRISTOPHE 11961101983051982051326611017.92 8MCOMPT
+9056CRAPONNE PHILIPPE 11961121985031989112090215981.60 8MSANS
+5891PRESIDENT ROBERT 11961 21992121993122401918074.91 8MSANS
+4133AIR PIERRE 11961 71981071991091326611016.35 8MSANS
+9028OUSTALET JEAN 11961 819821219811211131 9658.52 8MTECHN
+3462MONTEIL JACKY 11962 819820619810611131 9657.15 8MSANS
+7126JUSTICE MARIE PIERRE 2196211199504199404 7803 7680.66 8MSANS
+2705VILLA MIREILLE 21962 2199201199101 7803 7681.04 8.VENTE
+6788EXTE DOMINIQUE 21962101984111991091527112373.05 8MSANS
+6035AUMALE SYLVAIN 11962 619840319830311131 9658.70 8MSANS
+3359CERNOY PHILIPPE 11962121988061989091527112374.58 8CSANS
+8236CANAULET LOIC 11962 919870219870110407 9271.16 8MSANS
+2285FAURE NICOLE 21962101982071981071326611016.83 8MSANS
+6765PICARD AXEL 11963 61992121991121330611016.03 8CSANS
+6602COUDREE LAURENT MARCEL 11963111986051994111693613498.86 8MSANS
+6537BOTZARIS MANUEL 11963 91984031991091288210744.23 8MSANS
+9865CARDELINO ELISABETH 21963121986061985061288210744.19 8MSANS
+7936GAMBARDELLA MONIQUE 21963101984111983111288210743.92 8CSANS
+1490PAUTEL PATRICIA 21963 21993091992011202810241.21 8MSANS
+8828CAMP JEAN FRANCIS 11963 31983101993011949415050.78 8MSANS
+6652SURESNES BRIGITTE 21963121989081988081249910472.82 8DSANS
+9991PROF CHANTAL 21963 819950319940311389 9850.74 8MSANS
+4136ONDINE LAURENCE 21963 61984111983111608112915.66 8MTECHN
+2731DRIVE MICHEL 11963 81983051982051326611017.83 8MSANS
+7391SOIE BEATRICE MARIE 21964 11986101985101168610048.22 8CALLEM
+7157CEDEX GERARD 11964111991121990121330611016.53 8MSANS
+1010ARCES ELISABETH ANNE 2196412198811198606 8656 8145.62 8.ANGL
+7723GRATENTOUR FRANCOIS 11964121991051995081202810240.84 8MSANS
+7515JARUNSANITWONG PIERRE JEAN 11964 3199612199401 9597 8729.36 8CSANS
+7251ISIDRO DANIEL 11964 91988051987052090215980.28 8MSANS
+4749AVERTIN CLAUDE 11964101986071993041288210744.26 8MTECHN
+2395LOGNES HEDWIGE 21964 61984091983091288210744.23 8MSANS
+1171DELMAS DANIEL 11965 11988051992041249910473.45 8MTECHN
+8804MAHON FRANCINE 21965 51993061992061202810240.46 8MANGL
+0367DANTZIG JEAN 119651219940619930610363 9232.62 8CANGL
+4984SOULT ERIC ANDRE 11965 219931119921110024 8999.21 8CANGL
+5821POMPIDOU GINETTE 21965 51985061985061347711131.13 8MSANS
+6382LABOURD CATHERINE 21965 71989071995091249910472.66 8VTECHN
+0635WILLOWCREST JEAN CLAUDE 11965 71985071992121288210745.13 8MSANS
+0760PENIL PASCAL 119651019870119860110791 9501.81 8MTECHN
+6467HAVRE ANDREE 21965101987051986101527112374.07 8MSANS
+9897ONGUI PATRICE 11965 619940119930111389 9851.07 8CSANS
+5429HINODE FRANCOISE 21965 2199304199204 9126 8456.10 8MESP
+6900MANTEAUX GERARD 11966 719910219930610024 8997.99 8MSANS
+0370CASTELL MONIQUE 21966 41989031988031249910473.24 8MALLEM
+8517WASHINGTON BERNARD 119661219890119860410407 9272.17 8.ANGL
+9967TREMEUR HERVE MARIE 11966 81989081988081249910472.59 8SCOMPT
+6163MOLLARD JACQUES 11966 21993021992011249910473.00 8MANGL
+7120SOGNES HELENE 21966 31989031988031249910472.73 8MINFOR
+6709KERIMEL MICHEL 11966101988011987011539912453.47 8MANGL
+5303HETROLLIER MARIE LAURE 21966 119940919930411389 9852.11 8MANGL
+7075CEZAIRE JEAN LOUIS 11966 61985041992061527112374.63 8MTECHN
+5072SAUVETAT ALAIN 11966 919910519900510024 8999.27 8MANGL
+6154CALME MICHEL 11967 91988041991061249910472.82 8MANGL
+3329DOME PATRICE 119671219921119931110024 8999.31 8MSANS
+6319CALVAIRE YANICK 11967 119920819910810024 8998.01 8MSANS
+4968LYCEE MICHEL 11967 31991101990101467711987.34 8CSANS
+0009LOS JEROME 11967 2199611199511 8656 8146.86 8CSANS
+1878BEAUVILLE ERIK 11967 91990031994011249910473.09 8MSANS
+9800DORET CAROLINE LILIANE 21967 719930619920611389 9851.28 8MTECHN
+4797PORTOI MIVA 21967 61989111989111839014313.36 8MSANS
+7931LABERTRANNE SYLVETTE 21967 81994051992011202810241.97 8MTECHN
+8940BARRES MICHAELLE 21967 81990021993071330611016.66 8MSANS
+3164CROUY ANDRE 11967 71992091991091839014314.38 8MSANS
+1556CAMP VERONIQUE 21967 9199302199202 8656 8145.66 8.SANS
+2245FRINGANE VINCENT 11968 419940219920110024 8999.94 8CTECHN
+0888CURIE JEAN BERNARD 11968 91988091993121249910471.74 8MSANS
+3431BOUEL BERNARD 119681019880919870910407 9270.97 8MSANS
+3147ROCHERS ISABELLE 21968 51994071992011202810239.96 8CTECHN
+7236SIMENTAL BERNARD 11968 219910719910510407 9270.44 8MCOMPT
+9853YAN DAMIENNE 21968 71994011992011202810241.16 8CSANS
+3267LONG BRIGITTE 21968 11992091991091330611016.93 8MSANS
+8141EXUPERY GERALD 11968 51994011993011267210590.11 8CSANS
+3839MINIMES JEAN PIERRE 11968 71989011988011450311831.78 8MESP
+6386PAUCOURT SALOLOM 11969 91994011993011420611639.24 8MTECHN
+5948CARRERE JOCELYNE 21969 6199205199105 8656 8145.60 8.SANS
+1726ASQUES SYLVIE 21969101994021992011202810240.50 8MANGL
+3067CHEVRAINVILLIER BERTRAND 11969 119940119920110024 8999.90 8MSANS
+5762WINSTON JEAN 11969 11989101988101450311832.69 8MSANS
+6200MONTGOMERY DANIEL 11969 91990041995011330611016.47 8MSANS
+9177RIEUX BERNARD 119691119920619910611389 9852.27 8MINFOR
+6151CANTAGALLO EDDY FELIX 11969 71994011993011202810240.23 8MSANS
+8371MOUTHON HERMINE 21969 919950319930411389 9852.29 8MTECHN
+5982LONGWOOD MARIE NOELLE 21969 71991091991051330611016.84 8MVENTE
+3924ANGELES MARYSE 21970 219940719920111389 9850.74 8MSANS
+5000MARCHAND ANDRE 11970 8199306199206 9597 8727.91 8MSANS
+6053EXINCOURT DOMINIQUE 11970 419940619920110024 8999.43 8CESP
+6405ORMILLES ALAIN 119701119910819900810024 8999.57 8MSANS
+4367OURCHES AGNES 21970 1199506199406 7803 7680.36 8CSANS
+6055LACATE DENIS 11970 9199308199208 9597 8729.66 8CTECHN
+4701DUCA ANDRE 11970 71991051990051467711985.86 8CESP
+6470ALLEES YVON 11970 71991021990021467711987.75 8MALLEM
+6121RIVAGE FRANCOIS MARCEL 11970 419950119950110363 9233.88 8CSANS
+0867FOURS CHRISTINE 21970 3199409199309 8359 7952.10 8MTECHN
+9075SEMBAT FREDERIC 11970 3198912198812 8656 8145.26 8.ALLEM
+9637JUAN MURIEL 21970 5199310199210 8656 8146.70 8.TECHN
+6609GAYE NICOLE 21970 8199607199507 7803 7680.41 8MSANS
+5493LAUZES MICHEL 11970 11991071990071202810241.09 8MSANS
+6491BRAS BEATRICE 21971 619921019950410668 9425.45 8MSANS
+7556YOLA PHILIPPE 11971121994041993041360611209.94 8CTECHN
+7031ECOLE CHRISTINE EMILIE 21971 419910219920111389 9851.19 8MSANS
+5834ORANGERIE SERGE 11971 8199302199202 9597 8728.46 8CSANS
+4526LOT PHILIPPE 1197110199407199307 9597 8729.27 8CSANS
+4363QUART VINCENT 11971 4199404199201 9597 8728.44 8CSANS
+7702MONTARNAUD PIERRE 11971121992111991111420611638.97 8MVENTE
+8710GAULTIER ISABELLE 21971 31994011993011267210589.57 8CSANS
+5198ROUILLON CLAIRE LUCIE 21971 819940519920111389 9851.97 8CANGL
+6286WATTEAU JEAN CLAUDE 11971 81994071993071360611211.56 8MSANS
+3787TAUDE JACQUES 11971121993121994011202810241.40 8MSANS
+3968CAPRI MARIE CHRISTINE 21972 8199607199507 7803 7681.22 8CESP
+5435BERRE JOELLE 21972 21994091993091360611211.42 8CSANS
+2682VINGT GENEVIEVE 21972 7199406199306 7803 7681.40 8CSANS
+5935ORVEAU FRANCK 1197212199609199509 8656 8146.25 8MTECHN
+5312LUCE GUY 11972 81994041993041420611637.47 8MSANS
+5416ESSARTS FRANCOIS 11972 819931019930711389 9850.62 8CSANS
+5534ISLE MICHEL 1197210199312199212 9597 8728.58 8MSANS
+3974DEVIN FRANCOIS 1197212199605199505 8656 8145.57 8CSANS
+6877COUPERIN PHILIPPE 11972 5199310199210 9597 8727.95 8CSANS
+4740PLAISANCE SERGE 11972 219950119930410024 8998.82 8CSANS
+3393MANAU EDITH 21972 219941019930411389 9851.88 8MTECHN
+9615BOL JEAN CLAUDE 11972 21991071994011249910471.79 8MSANS
+4599GUYAU MAUD SOPHIE 21972 519940719920111389 9852.47 8MANGL
+8612HAMELIN JEAN MARC 11972 8199310199401 9597 8728.98 8CSANS
+8541RESIDENCE MICHEL 11972 319951219941210668 9426.89 8CTECHN
+3801NASTRINGUES SABINE 21973 8199606199506 7803 7679.46 8CTECHN
+2827OREE JOSEPH JEAN JACQUES 11973 6199502199402 9126 8456.78 8CANGL
+7660ESTIENNE JACQUES 11973 1199406199306 9126 8455.56 8MSANS
+5260JACQUES ERIC BERNARD 11973 319931119921111389 9851.61 8CSANS
+3671GARCHES GEORGES 11973 31992021991011202810240.68 8CANGL
+4348ROQUEFORT JEAN PIERRE 11973 819930319920311389 9850.74 8CINFOR
+6630LAGRANGE THIERRY 11973 9199302199505 9597 8729.63 8CTECHN
+9712EMPIRE CHRISTIANE 21973 6199606199506 7803 7680.67 8CSANS
+3751OASIS JACQUELINE 21973 219930319920711389 9851.25 8MSANS
+3830DRECHO JEAN 11973 61993051994011202810240.55 8CSANS
+4561DANNEMOIS JEROME 11973 5199612199601 7803 7679.91 8CSANS
+3191JAVEL CHRISTIAN 11973 5199311199211 8656 8147.13 8.SANS
+1618CHASLES CORINE 219731219940719930710668 9427.08 8MSANS
+4268SENE LUC 1197312199306199206 9597 8728.23 8CSANS
+8421ROCBARON JOEL 11974 1199510199410 7803 7680.36 8CSANS
+0930ESTANOVE ALAIN 1197411199606199506 7803 7679.99 8CMICRO
+6807TOURDRES MANUEL 11974121994051993051360611210.28 8CSANS
+4488CHAUVEAU CECILE 2197412199601199501 7803 7679.51 8CSANS
+8315COUVENT PIERRE 11974121995121994121450311831.06 8CSANS
+6605EDMOND SYLVIE 21974 8199504199404 7803 7679.78 8CTECHN
+9778ONS MARIE SIMONE 21974 7199405199406 7803 7679.96 8MSANS
+3816AURIC PASCAL 11974 6199502199402 9894 8922.63 8CSANS
+2018FOUR PATRICIA MICHELE 219741219940719930710668 9427.40 8CALLEM
+7643SEGUIER PATRICK 11974 5199406199306 7803 7679.67 8CSANS
+5610SAGET HENRY 11974 9199407199307 9126 8456.47 8CALLEM
+6425FINLAY PHILIPPE 11974 81993121994011202810241.74 8CANGL
+8616PAEA MICHEL 11975 5199407199406 7803 7681.40 8CSANS
+9958DULUD GILLES 11975 6199612199512 8656 8146.52 8.TECHN
+8573PIBONSON CHRISTOPHE FREDERIC 11975 6199607199507 7803 7680.81 8CSANS
+7803INCAPIS PASCALE NANCY 21975 7199604199504 7803 7680.34 8CALLEM
+7514VIENOT ANDRE 11975 3199508199408 7803 7679.78 8CSANS
+7507FAISANDERIE JEAN PIERRE 1197512199607199507 7803 7679.99 8CSANS
+3865MICHEL PATRICK 11976 3199507199407 7803 7680.12 8CSANS
+4755OCTAVE MARC 1197612199608199508 7803 7679.99 8CSANS
+0542TORREILLES ALAIN 11976 5199510199410 8656 8145.80 8CSANS
+9647DELORME DOMINIQUE PIERRETTE 2197612199407199307 7803 7679.69 8CSANS
+4725TACONNAZ BEATRICE 21976 4199508199408 7803 7681.17 8CALLEM
+9564CESSOLE FRANCIS 11976 4199607199507 7803 7681.20 8CSANS
+8087CHUTES GUY 11976 3199407199307 7803 7680.62 8CANGL
+5480LOUIS JACQUES 11977 9199607199507 7803 7680.59 8CSANS
+1361BANVILLE PATRICK 11977 4199607199507 7803 7680.34 8CSANS
+6209BEAURECUEI CATHERINE 21977 4199607199507 7803 7680.57 8CSANS
+3656FLIREY JEAN CLAUDE 1197711199606199506 7803 7679.59 8CANGL
+9051SUANE ALINE 21929 919680919870111389 9851.91 9VSANS
+2724DEL PIERRE 11930 21989021995023455825330.03 9.SANS
+7341GRATECA PIERRE 11933 21966071993012273717260.26 9MSANS
+6774BARRAU AGNES 21933 8199512199412 8656 8145.06 9MANGL
+0536FIRMAMENT SCHEHRAZAD 21934121962101982052470018541.72 9DSANS
+7368RESSAC RICHARD JOSEPH 11934 11967011994011557012567.09 9LANGL
+7599ANNE JEAN FRANCOIS 11935 11974031994011578112722.84 9VSANS
+1083COUCOURDE DOMINIQUE 11935101973061991011433211715.02 9MSANS
+2946ROLLAND OLIVIER 11936 51962111984122470018541.29 9MSANS
+7241THERMALE MARGUERITE 21936 7199306199206 9511 8688.67 9MESP
+1695LOUVEL CHRISTIAN 11937 519820219920311389 9852.69 9MSANS
+9744SALENGRO SYLVIAN ERIC 11937101961071991083417325097.15 9MESP
+7083OLIVETTE CATHERINE 21937101966071989031932314934.86 9MALLEM
+0151DUCHEMIN JEAN JACQUES 11938 41962061991012470018541.29 9MINFOR
+8395FRANCO ANNIE 21939101984011991091288210745.34 9MANGL
+9978BARBERAZ MARIE CLAUDE 21939 71972071989011621213034.09 9VANGL
+2131ARGENT CATHERINE 21939 71963121994042137316332.05 9MALLEM
+3235THUI HUGUES 11939 61967071995041557012566.37 9MSANS
+7994THIBAULT PATRICK 11939 31962051983032470018542.10 9MTECHN
+5783DOMATS MICHELE 21939121963031992021932314934.12 9MANGL
+6426PORTAIL JEAN FRANCOIS 11939 11969121995041557012567.53 9MESP
+6856JULIE JEAN MARIE 11940 319950219940211131 9657.83 9MANGL
+4024LEBRUN ALAIN 11940111965041995041557012567.77 9MESP
+9739NOCETA YVES 11940 21972041991011663613343.82 9MSANS
+9045MURET RENEE 21940101964091993072137316332.29 9CSANS
+4987UNIVERSITE CATHERINE 21940 41967011990011932314935.20 9MESP
+1530CYRILLE ANNICK 219401219741019881011131 9659.19 9VSANS
+1447HAMEAU OLIVIER 11940 61964081988092947921838.88 9MTECHN
+8268ANNEES PATRICK 11941 51961081992042022115555.75 9SANGL
+9303SCIOTOT ALICE 21941 61973071991101578112722.75 9MSANS
+0509PIECE ROBERT 11941 51963121994073844228045.38 9MSANS
+3288ISERE EMMANUEL 11941 51965081990011433211714.24 9MSANS
+9898CHANTEGRIVE JEAN MARC 11941 91964091992082470018540.12 9MSANS
+0163DAUTHEVILLE MARCELLO 11941111964121992072137316332.45 9MANGL
+0652VAUTHIER MARIE ALICE 21941 41971021991101932314933.60 9MINFOR
+7932VAUX DANIEL 11942 51969031991011433211713.80 9MSANS
+0197MAURENS CLAUDE 11942 91962081984123200223582.94 9MTECHN
+3251RUELLE JEAN 11942111976041992011403411520.12 9MALLEM
+8289OLYMPE NADINE 21942 51964121993102137316331.37 9MSANS
+9503GLORIETTE ALDO 119421019951219941210024 8999.12 9MSANS
+4563CERTAIN LOUIS 11942 31965071995011557012567.22 9MANGL
+6383DESGRANGES JEAN CLAUDE 11942 71983051993011249910473.49 9MSANS
+8658VALLONGUE BERNARD 11942 71963041995102666519899.30 9MESP
+4745RUCHERS GILLES 11942 21980051979051249910473.56 9MSANS
+8824PEYBERT JOCELYNE 21942 31963031994012137316332.51 9MSANS
+7242CORMEIL PATRICK 11942 81970041990011433211714.79 9MANGL
+0065ANGES XAVIER 11943101966101990011663613343.16 9VSANS
+4531SENART JEAN LOUIS 11943 21967111987012273717261.13 9MSANS
+7154MUIDS THIERRY 11943 31962121990013844228044.24 9MINFOR
+5345ORATOIRE ALAIN 11943121970081989011932314934.36 9MSANS
+3282SOUGERES JEAN LOUIS 11943 11968051990011433211715.33 9MSANS
+6215JOFFRE PASCALE 21943 81986021991071249910473.24 9MINFOR
+7867BASTIDE HIROKO 21943 51964071993072334017610.06 9MCOMPT
+6194STEPHAN KARIM 11943 81966051995041557012567.45 9MANGL
+4570MONDENARD JACQUES 11944 61965051994012137316331.93 9MINFOR
+3691CAORCHES MICHELE 21944101965081995042137316331.97 9MINFOR
+8595PRAD BENOIT PIERRE 11944111965031984123200223582.37 9MALLEM
+6617LONDRES PATRICK 11944 41972041991011621213032.39 9MSANS
+9701CAPUCINES ALAIN 11944 119820119830511389 9851.24 9MSANS
+7661ROSERAIE FRANCOIS 11944 31973071992011403411521.88 9MANGL
+0274FROMAGERIE ALAIN 11944121971011991101433211714.28 9CSANS
+9427GROULES MARIE FRANCOISE 21944 81963111993082334017609.06 9MANGL
+9749HEROLD ISABELLE 21944 31973071991071578112722.97 9DSANS
+5120MONTBY PIERRE 11945 81978041994011663613343.91 9MINFOR
+7337MAGINOT PHILIPPE 11945 61965031994012137316330.71 9MANGL
+2937PAYEN JEAN PAUL 11945 81973051992011403411520.53 9CANGL
+3034SCHUMANN GEORGES 11945 81970041991011433211715.11 9MSANS
+4582PETENATI MARIE CHRISTINE 21945 11974121993032043315669.65 9MALLEM
+2430TOURNELLES ALAIN 11945 91975031993011369311287.38 9MSANS
+4782CHENAY MARIE LAURENCE 21945121968091989012273717259.78 9MSANS
+1091RENNES MARIE ANGE 21945 61974071990071621213033.56 9MSANS
+2494ONA FRANCOISE 21946 51969081993121834514275.25 9MESP
+2170VIENNE MARIANNE 21946 81970021991102137316330.67 9VSANS
+2830FONTAINE ANNETTE 21946 41968041991091932314935.20 9MSANS
+8673ABEL JEAN PIERRE 11946 2198810198510 8656 8145.21 9.SANS
+9142ORSAY MICHEL 11946121970121991041663613343.28 9MSANS
+6458FOYER JEAN LUC JACKY 11946 71969111986012470018540.12 9MSANS
+8418RIVERIN ALAIN 11946 11979091992011249910473.05 9CCOMPT
+2785PONT ANDRE 11947 41968041990102739020403.33 9MANGL
+3079MOISE YVES 11947121972071991101433211714.69 9MTECHN
+6994CHEMINEES SOPHIE 21947 11976061981091834514276.09 9MANGL
+0913ROCHER BRIGITTE 21947101971041990102334017609.66 9MSANS
+3030LUZIADES ANTONINA 21947 519940619920111389 9851.64 9MSANS
+2592CLOUZIT NATHALIE 21947 7199208199108 8656 8145.20 9.SANS
+2816BAULE VERONIQUE 21948 51973031972031236910396.01 9MANGL
+0561DELAUNE JEAN NOEL 11948 11975041993011369311287.82 9MSANS
+4506DIDEROT JEAN PAUL 11948 619790519880411131 9657.51 9MTECHN
+5103CORNETIERE FRANCOISE 21948 21983061990041288210744.22 9DSANS
+0785RUDLOFF MICHEL 11949121971121993122547019086.15 9CSANS
+7465DEVORAH MICHEL 11949 91980041990091608112915.38 9MSANS
+6601LAS CLAUDE 11949 61969051990043417325096.67 9MTECHN
+5921SAINTPIERRE CAROLE 21950 31974021991071578112722.12 9CSANS
+4717BERARD DENIS 11950101983081987011283810705.67 9DTECHN
+6138DUCERIS COLETTE 21950 81992051991011202810241.85 9SVENTE
+1254ESQUIROL JEAN CHRISTIAN 11950 81975081992101369311286.84 9MANGL
+3226BOX CHRISTINE 21950 41970041990101834514275.65 9MSANS
+4683MAUNE PASCALE 21950 61974051995072175716601.42 9MSANS
+3496FROIDE JEAN JACQUES 11950111972101991012137316331.69 9MANGL
+2173BERNARD CHRISTIAN 11950 41972051991042137316331.34 9MANGL
+2204VIA STEPHAN 11951121972101991072017815517.05 9MSANS
+5528HORIZONA JEAN PAUL 11951 219931019940510407 9270.34 9MANGL
+2181CHAPUIS ALLAN 11951 1198810198603 8656 8145.89 9.SANS
+8003COMPREIGNAC JEAN RENE 11951 81973101994082201216756.14 9MALLEM
+4444HOTELS ANDRE 11951 41981111992011249910471.71 9CTECHN
+3137GARIDECH MICHELINE 21951121993051993041249910473.47 9MANGL
+5824LONGCHAMPS SYLVIE 21951 51972011990071578112722.42 9MANGL
+8477MENEZMEUR NORIKO 21951 51973071991041578112722.69 9MESP
+1336RANELAGH PIERRETTE 21952 21972041995011881314585.46 9MALLEM
+6782LAVACHET ALAIN 11952 11978091994011369311287.77 9MINFOR
+6451MONTPARNASSE AURIC 11952121973031987112470018540.56 9MESP
+9132BOUVELARD ALAIN 11952 619930819910110407 9271.74 9CSANS
+9726VIGIER GABRIEL 11952 419930819920811389 9852.47 9MSANS
+4608DESPAGNE ANNIE 21952 3199503199403 8656 8146.05 9MSANS
+2221LYANES YANN 11953121973071995041881314586.14 9MVENTE
+1575PELURES MICHEL 11953111975011991012781920674.59 9MSANS
+4898BLANCHET ODILE 21953101973071984051834514275.11 9MSANS
+2339ODES MICHEL 11953 31976121993041471512025.77 9MSANS
+4008BETHANCOURT MARIE ANNE 21953111981121980121202810241.36 9MSANS
+1590CIVRAC PHILIPPE 11953 91977051993041369311286.83 9MTECHN
+6109PEIRE GERARD ANDRE 11953 31972071991082175716602.51 9MCOMPT
+7232CHAMP MICHELINE 21953 7199001198801 8656 8145.87 9.SANS
+4789TOURACHE ALAIN 11954 71974081993011369311286.53 9MTECHN
+8709QUIETUDE MONIQUE 21954101977011994101471512025.14 9CSANS
+1712BIR ALAIN 11954 31975011991091684813421.42 9MSANS
+7069TUBY ROBERT 11954 71975061991071578112722.30 9MSANS
+4017BLEURY BRIGITTE 21954101977011992011471512025.20 9CSANS
+4255BEAUSEJOUR FRANCOISE 21955101981031995071433211714.70 9MSANS
+3435VENTS PHILIPPE 11955 71978041991011471512025.16 9MTECHN
+3130CIGALONS PHILIPPE PIERRE YVES11955121978111995021608112916.95 9MALLEM
+9170ALMA ANTOINE 11955111978101992011578112722.61 9MANGL
+9114CASTEL LILIANE 21955 51976071991121578112722.52 9MVENTE
+4844CHER JOELLE 21956 31993091995111202810240.94 9MINFOR
+1241GOUVERNEUR JEAN PAUL 11956 31976031990101684813422.68 9MSANS
+9766FRAYSSE CHRISTIAN 11956 819800719821211389 9850.88 9MSANS
+6781CHANTEREINE JEAN LUC 11956 91979011992012175716602.36 9MSANS
+6220PUYRAVEAU MICHEL 11956101985041988061326611017.52 9MSANS
+5187BOLIVAR DANIELE MARIE 21956 81981081995071433211714.30 9MSANS
+8283VICINAL MARCEL 11956 91977111992012175716600.94 9MSANS
+0990CORMERY EYT 11956111979121995041249910472.84 9MSANS
+9255SERRES MARY ANNE 21956 71981011980011684813421.58 9DANGL
+9968TRAILLES JEAN 11956 919870419860910407 9271.59 9MSANS
+6046RONDE JACQUES 11957101976121992011608112915.20 9MSANS
+4312DUROC KETTY 21957111980041979041684813421.51 9CANGL
+1998MADELEINE CATHERINE 21957 21980061994041471512025.70 9MSANS
+0810TROMPETTES LAURENCE GISELE 21957 91994021992011202810240.40 9SSANS
+1103JOURDANS JEAN MARIE 119571019900419910410791 9502.58 9MANGL
+3941SOUGRAIGNE MICHELINE 21957 71980071979071684813423.49 9CSANS
+1971BORDINAS GENEVIEVE 21957111980011993111471512024.89 9MSANS
+5459VORS ANNE 21957 5199006198906 8656 8146.61 9.SANS
+5423FLOQUET FABRICE 11957 3199408199308 8359 7953.59 9MSANS
+0905CARREL KARIN 21957101980101979101684813423.47 9MANGL
+4069JUZET JEAN FRANCOIS 11957101976071993062043315669.89 9MSANS
+4527MANIGUETS PIERRE 11958 819820619810611131 9658.16 9MSANS
+2372FONTANGE EMILIENNE 21958111981041980041381911366.00 9MANGL
+4357RAYOL PATRICIA 21958 41994031992011202810240.40 9MSANS
+5408BLANCHE GERARD 11958 41981021985112256617147.10 9MANGL
+3006FOULQUES JOELLE 21958 51979031993041471512026.00 9MINFOR
+6430PERIGORD PIERRE 11958 219790519780511389 9852.09 9CSANS
+6468PLANTADE BEATRICE 21958101981041980041684813422.18 9MALLEM
+0044MONTBRUN PIERRE 11959 51983061993121326611017.97 9MANGL
+2272GRANGE JEAN MICHEL 11959 519790319820111389 9851.46 9MSANS
+8185TONNER CHANTAL MARIE 21959 3199606199506 7803 7681.35 9MSANS
+8317DAMESME JOELLE 21959 919940219930211389 9851.73 9MSANS
+3554FRONTONAS MICHELINE 21959 61979101978101202810241.66 9MESP
+3926TARNES NELL 11959 11980101993041471512024.20 9MVENTE
+9173BLIGNY MARIE MADELEINE 21959 1198810198510 8656 8146.64 9.TECHN
+9704DEMMLER ANDREE 21959101979101993071471512024.66 9MANGL
+1648RENAULT MARIE ODILE 21959111986121991071249910472.96 9MSANS
+1803HONORE ISABELLE 21959111982041981041202810240.26 9MALLEM
+5795SUQUETTE SYLVIE 21959121980031995021527112374.40 9MANGL
+9158ALDERBURCHS PATRICE 11959 719790619811011389 9852.67 9MSANS
+8333PONCHETTES VIRGINIE 21959 7198801198510 8656 8145.83 9.SANS
+5238BOURRE CLAUDE 11960 51981031984091684813423.35 9CSANS
+7478ERDRE ANNE 21960 81993111992011202810240.71 9MANGL
+2036SALENGRO SYLVIANE 21960 31985121984121288210744.62 9CINFOR
+7716GOLF BERTRAND 11960121982071989021608112916.95 9MANGL
+4057MILTAT HERVE 11960 719810419800411131 9657.84 9MANGL
+2635BIGNAN MARTINE 21960 51981041992092090215980.88 9MSANS
+7613PIERRE JACQUES 11961121986041990031527112374.84 9MSANS
+0365CLICHY BERNARD 11961 419830519830511131 9658.07 9MSANS
+2806GOIZ DIDIER 11961 119840419830411131 9658.46 9MSANS
+4103BRUSC CATHERINE 21961 319940919930411389 9852.47 9MSANS
+1349MAUROIR ERIC 11961 819900119870310407 9270.29 9.SANS
+0451RENARD JEAN MICHEL 11961 1198810198604 8656 8145.78 9.SANS
+8494CYGNE SYLVIANE 21961111983021982021326611016.71 9CSANS
+9150GAY JEAN CLAUDE 119611119880719870810407 9271.52 9MSANS
+3221SURCOUF GUY 11961 91984081992121527112374.97 9MSANS
+3083CANADA ALAIN 11961 11982051982111326611017.29 9CSANS
+0448LAVANDES GILLES 11962 319930819920811389 9850.79 9MALLEM
+3439VERSAILLES MARC 11962 319840419830411131 9657.57 9MALLEM
+5360VEZELAY THIERRY 11962 119880919870910791 9502.46 9MSANS
+8567PRE FRANCOIS 11962 519910119940810407 9271.42 9MINFOR
+0702LACOSTE PHILIPPE 11962 61985091984091608112916.14 9MESP
+3016CARDELINE ELISE 21962 11993091992011202810241.27 9MSANS
+7387BELLERIVE EVELINE 21962 91992111992061330611016.03 9MSANS
+3882RETHACKER JEAN LOUIS 11962 719930819921210407 9272.17 9MSANS
+5174SEILLANS NICOLE 21962 71983081982081608112915.08 9MTECHN
+2800VILLETTE JEAN PIERRE 11962 51985041991091288210744.28 9MANGL
+9420ROURES YANNICK 119621019820319810311131 9658.82 9MSANS
+4001ASNIERES JEAN PIERRE 11962121987071994091693613499.67 9MSANS
+8856CANALS GILLES 11962 219911219901210024 8999.16 9MANGL
+9775MOUETTES FRANCOIS 119621219900219890210407 9270.91 9CVENTE
+7097BROUENOU JEAN PIERRE 11962 619860319850310791 9502.82 9MSANS
+8917CHANCELIER PATRICK 11962 31995021994021202810240.53 9MSANS
+8358CREBILLON NICOLE 21962 61983011982011608112916.37 9VSANS
+1296BERARD MICHELE 21962 119941019931011389 9850.89 9MSANS
+3188CONCY MICHELE 21962 31987091986092090215979.80 9MALLEM
+6829SEINE DANIELE 21962111994061993061202810240.23 9MALLEM
+7876VIELLA HERVE 11963 619930119920110407 9272.09 9CESP
+7396SANAJO BRUNO 11963 91987081991091249910473.60 9LSANS
+7380MARINA ANNE JACQUELINE 21963 119910919900910024 8999.61 9CANGL
+5941SIFFLETERIE GILLES 11963 519940219910710407 9270.56 9MTECHN
+5364BOUSSY GENEVIEVE 21963 519940519920111389 9850.61 9MANGL
+9502MONTOLIEU JEAN CLAUDE 11963 41985051994061527112374.72 9MSANS
+8964DOUJAT MICHEL 11963 619841119831110791 9503.92 9MSANS
+3405AMANDIERS PHILIPPE 11963 81984031992111527112372.90 9MSANS
+1868COUPE JEAN 11963 61993031995081381911366.16 9MSANS
+2984GOUSTAN JEAN MARC 11963101987111994091693613499.09 9CSANS
+7572CHARONNE DANIELLE 21964 41995011994011206910240.19 9MALLEM
+9668EDELWEISS JEAN BERNARD 11964 31984071991121288210745.70 9MSANS
+3335CANTEPERDRIX MARIE CHRISTINE 21964 41983061982061326611017.52 9MSANS
+2509FINO JEAN MICHEL 1196410199311199211 9085 8417.90 9CVENTE
+1812LLORCA PIERRE 11964 21986031993091527112374.72 9MTECHN
+5943BERGERIE JEAN 11964 31987021995011373711327.16 9MSANS
+5136VALERIEN ANDRE PASCAL 11964 71987081986081527112373.86 9MANGL
+6432ECUREUILS PATRICK 11964 3199202199102 8656 8147.19 9.SANS
+2610DUVERGIER MARC 11964 91984031992031527112374.88 9MTECHN
+5455CEZANNE PASCAL LUC 11965 31988091993031450311831.19 9CALLEM
+7204PICCINI CAROLINE 21965121992091991091839014314.08 9CSANS
+0125HUNTINGTON YVONNE 21965 91994011992011202810240.77 9MSANS
+3791BOUISSETTE PHILIPPE 119651119940119950810024 8998.95 9CSANS
+2711ROSETTE PHILIPPE 11965 41990101994011288210744.86 9CALLEM
+4882LOZERE ERIC 11965 31988021992061450311831.91 9MANGL
+4855BELLEVUE PATRICK 11965 11990101989101249910473.69 9MALLEM
+3048PIERRE PIERRE 11965 7199110199010 8656 8146.61 9.ANGL
+2278LOGT NORBERT 119651019900619890610407 9270.24 9MSANS
+5557LAUZADEL GERARD 11965 91992071994072256617145.75 9MSANS
+6129ROZ GISELE 2196510198805198510 8656 8145.20 9.ALLEM
+3979RIVES YVES 1196511199609199509 9126 8455.98 9MTECHN
+8688FASSUN HUGUETTE 21965 4199511199411 7803 7680.23 9MSANS
+9402PARMENTIER PATRICK 11966 819880319870310407 9270.16 9MCOMPT
+8428BARJAQUETS THIERRY ABEL 119661119920319910310024 8999.07 9CALLEM
+8348CLERMONT ANNE MARIE 21966 11989051988051202810241.40 9MVENTE
+3723COURCELLE GENEVIEVE 21966 2199506199406 7803 7680.93 9MANGL
+3173CHAL ARMAND 11966101986051988061288210745.88 9MSANS
+9965VENETES YOLANDE 21966 519930719920711389 9851.21 9MTECHN
+6306ANJOU ALINE SIMONE 2196612199004198707 8656 8147.13 9.ANGL
+5448FILHOS JEAN CHARLES HERVE 1196612199212199112 7677 7604.70 9MSANS
+7571GORRE SYLVIE 21966101988121987121249910472.03 9MSANS
+8890LAMORLAYE FREDERIC 11966 41986041992011450311832.68 9MVENTE
+2287DORMOY GENEVIEVE 21966 31988111987111450311830.80 9MSANS
+0092ALCANAL JEAN LUC 11966 61987041992121249910472.03 9CSANS
+2554ROULOTTE OLIVIER 11966 419940219920110024 8999.03 9MANGL
+9801GRAPPONS NATHALIE 21966 919940819930411389 9851.57 9MTECHN
+1541ALDES JEAN MICHEL 11967121994051992011202810240.26 9MSANS
+9290PLOEMEL YVES 11967121991051990051467711986.91 9MSANS
+8169CHAUVIN FRANCOIS 11967 21994011994011202810240.53 9MSANS
+6269GOLF ROLAND 11967 919940219940710024 8999.47 9MALLEM
+2878RICHART ERIC JEAN MARIE 11967 819891219950410407 9271.91 9MSANS
+9098OR DANIEL 11967 719880919870910407 9272.01 9CSANS
+4331MONIER DIDIER 11967 719881019871010407 9270.12 9CSANS
+0261ROUQUET RENE 11967 41989051988051539912452.78 9MSANS
+1507FLACHAT PIERRE 11967 41994011993011420611639.09 9CSANS
+7887TENDRE CLAUDE ANNE 21967121994051992011202810241.72 9DSANS
+0525SERRES LAURENCE MAGALI 21967 11994011992011202810240.50 9MSANS
+9421ASNIERES MARIE CHRISTINE 21967 319951119930411389 9852.22 9MSANS
+3624LAPEYRE THIERRY 11967 519870119940110407 9270.12 9MSANS
+0344GABRIEL JEAN PIERRE 11967 419940119920110024 8999.57 9MINFOR
+7208GAZAN ERIC JEAN 11967 219940119950810024 8998.94 9MTECHN
+4335GLACIERE KEIKO 21967 21994041992011202810240.89 9MINFOR
+9851TOUCANS MICHEL 11968 219910119900110407 9272.01 9MTECHN
+9263ROSSINI ALAIN 11968111991011995021330611018.13 9MSANS
+9662DEPORT PHILIPPE GEORGES 11968 3199607199507 8656 8145.38 9MANGL
+2814ALFRED VERONIQUE 21968 6199202199102 8656 8146.65 9.COMPT
+3291LACUEE REMI 11968 91989021988021450311831.34 9MANGL
+3557KERHOUET REGIS 119681019930319920310024 8997.86 9MSANS
+6204ESCA BRIGITTE 21968 9199404199201 9597 8729.22 9CESP
+1678HADRIEN PHILIPPE 11968 819931219921210363 9231.95 9CSANS
+0299MONICA DOMINIQUE 21968 51994021992011202810241.70 9MTECHN
+6960PRES COLETTE 21968 2199108199008 8656 8147.15 9.SANS
+4443BENOIT JOSIANE 21968 81988011992011249910473.05 9MTECHN
+5697QUILICHINI ROBERT 11968 31993121992011202810241.92 9MINFOR
+9315PAVE LEON 11968 21988111987111539912452.39 9CTECHN
+7230BOUCHE FRANCOISE 21969 3199304199204 9126 8457.67 9MSANS
+8237DENEB WALTER 11969 419890919910710407 9271.47 9CSANS
+3459ALISCAMPS LEONIE 2196912199610199510 8656 8146.02 9MANGL
+4247ARISTIDE CHRISTIAN 11969 5199501199401 9894 8921.55 9MSANS
+0137VILLEMENT ANNE MARIE 21969 81994051992011202810239.81 9MSANS
+9445STREET DANIELLE 21969 7199204199104 8656 8146.74 9MSANS
+9019VALLIERES JEAN 11969121990111989111381911366.90 9MALLEM
+4031COLVERTS LAURENCE 21969 11993121992011202810240.89 9MSANS
+4000CUENANT THEOPHILE 11969 219890619880610024 8998.09 9CSANS
+7496GRASS FRANCOIS 11969 81989051992121249910472.43 9CSANS
+4671GRASSET ROGER 11969111992061995121330611018.09 9CSANS
+0067RESTAURANT MICHEL 11970 7199407199307 9597 8728.26 9MANGL
+0824FIGARES JACQUES 11970121993101992101360611210.03 9CESP
+0143MACONNERIE MICHEL 1197010199511199411 7803 7679.87 9MSANS
+2934FUZELIER SYLVIANE 21970 5198906198806 8656 8146.56 9MSANS
+2663TOULOUSE PATRICK 119701219930819920811389 9850.66 9CSANS
+0038LANGRUNE FRANCOIS 119711119940619951010024 8998.32 9CANGL
+8414VILLE NOEL 11971 41990051989051202810241.49 9CANGL
+5333SQUARE JEAN LUC 11971 81995051994071450311832.45 9CSANS
+3680LAUTREC CALIXTE 21971 9199602199502 7803 7680.84 9MINFOR
+9370CAMELIAS CHRISTIAN 11971 5199307199207 9597 8729.90 9MTECHN
+6026NADAILLAC JEAN LOUIS 119711019910219900210024 8998.44 9CANGL
+4310VICTORIA ERIC 1197110199607199507 7803 7680.44 9CSANS
+2394CLAVIERS MICHELE RENEE 219711019910919900910024 8998.26 9CANGL
+4996GUILLAUME FREDERIC HENRI 11971 41993031992031330611016.30 9CSANS
+6930ROYAL EVELYNE 219711219940119930110668 9426.26 9MSANS
+1006CRAU MARIE CLAIRE 21971 21994051992011202810241.04 9MSANS
+0817ATHEE MAITE 21971 81993011992011267210590.11 9MSANS
+5245VAL XAVIER 11971 3199306199206 8656 8146.79 9MESP
+7249CLARS ALFRED 1197110199306199206 7803 7679.41 9.ALLEM
+9895JUVANTE JACQUES 11971 61995051994051450311832.69 9MSANS
+4769BORDERIE OLIVIER JEAN 11972 219940719930711389 9852.20 9MTECHN
+4620VERDEILLE FRANCIS 11972 619930419940910363 9232.32 9CSANS
+3812BLAINS DIDIER 11972 9199302199202 9597 8729.94 9MANGL
+9910FORET JEAN CLAUDE 11972 119930719921011389 9851.30 9CSANS
+5930CHATEAU SERGE 11972 9199205199105 9597 8728.49 9CMICRO
+3132SAGONE EMMANUEL 21972 4199601199501 7803 7679.46 9MSANS
+2171BERGERONNETTES STEPHANE 11972121995111994111450311832.22 9MSANS
+5929CARRIEREBLANCHE OLIVIER 11973 6199410199310 9597 8728.98 9CINFOR
+6111ROCHETTE JACQUES 1197310199307199207 7803 7680.93 9.ANGL
+1480CREYSSAC VANESSA 21973 4199511199411 7803 7679.33 9CSANS
+9433BIS NICOLE 21973 6199407199307 8359 7951.65 9MALLEM
+5673ROLLIN JEAN 11973 6199304199204 9597 8728.28 9CESP
+8786MIMOSAS ALAIN 11973 21993031993061420611637.51 9CANGL
+3099MAUR ANDRE 11973 41996051995051450311830.65 9CANGL
+1278ENTASSI VERONIQUE 21973 7199606199506 7803 7679.67 9CSANS
+6956PRIEURE FRANCOISE 21973 819930919920911389 9851.28 9CSANS
+7084AVNEUE JACQUELINE 21974 7199606199506 7803 7679.99 9MANGL
+9484DOUMER JOEL 11974 519930819940910363 9232.98 9CESP
+9483VILLEBON REMY 11974 8199606199506 7803 7679.78 9CSANS
+4120SURBAIX FRANCOIS 11974 719940819930810668 9425.81 9CSANS
+6136PASSERO JEAN PAUL 11974 4199606199506 7803 7679.78 9CANGL
+9119SERVAN VERONIQUE 21975 7199505199405 7803 7680.00 9CANGL
+0958RENDEZVOUS BARBARA 21975 6199307199207 7803 7679.87 9.TECHN
+0221ANDALUCIA SERGE 11975 1199606199506 4264 5818.98 9CANGL
+1770MARIGOT DIDIER 11975 9199407199307 7803 7679.94 9CCOMPT
+2889MANE JACQUES 11975 5199606199506 7803 7680.21 9CINFOR
+8800CHEZ JEAN 11975 5199408199308 7803 7680.98 9CANGL
+6217MURE GREGOIRE ROBERT 11976 5199607199507 7803 7679.28 9CANGL
+9488HARMAS JOSE 11976 8199607199507 7803 7680.27 9CANGL
+9074MILIERE ELIANE 21976 6199607199507 7803 7681.26 9CSANS
+8755BOITRON MICHEL 11976 4199606199506 7803 7679.67 9CSANS
+5066LOGES PATRICK 11976 2199401199301 7803 7680.72 9CSANS
+7767CAVOK CATHERINE 21976 4199506199406 7803 7679.49 9CANGL
+4014DELAMBRE ALAIN 11976 4199507199407 7803 7680.71 9CSANS
+7434CHAMPCEVINEL MICHELINE 2197612199606199506 7803 7681.25 9CSANS
+3520CATALINA CATHERINE MARIE HELE21976 9199506199406 7803 7681.34 9CVENTE
+6859BILLET JEAN LOUIS 11977 7199606199506 7803 7680.36 9CALLEM
+3181NADAUDS JEAN MARC 11977 2199506199507 7803 7679.51 9CANGL
+0928DELACROIX CATHERINE 21977 6199607199507 7803 7681.13 9CALLEM
+5100BREVAINVILLE GERALD 11977 8199607199507 7803 7679.45 9CSANS
+2336ROCAMADOUR GILLES RENE 119331219861119901011131 9658.9910MINFOR
+3692ALBIZZIAS DOMINIQUE 11935121965031994011557012566.3610MSANS
+1060SEDS ANNE MARIE 21935 61970071991071578112722.8210VANGL
+1596OPERA JEAN LUC 11935 31971101991041433211714.3910MSANS
+2633SOULEYRAS MONIQUE 21935111958071993012470018540.4410MINFOR
+0658LOURMEL BERNARD 11936 51967051994011932314934.8010MTECHN
+1362LAC YUMIKO 21937 41965061994012137316332.6910MSANS
+7201ILE JEAN PASCAL 1193711198810198309 8656 8145.1210.SANS
+7674CASTE PIERRE 11937121971061993072547019086.2710MVENTE
+9244LIVRY EDITH 21937 1198901198306 8656 8145.3810.INFOR
+4790FRANCIS LYSIANE 21937 2199001198903 8656 8146.5210.SANS
+7950CHARBONNIERE STEPHAN 11938 61972051991011433211714.5510MSANS
+1814IRMA MARIE 21938101967011989091932314935.3810CANGL
+0599FAUBOURG BERNARD 11938 71961011986012273717261.9010MSANS
+0425PLUVIERS JEAN PIERRE 11939121971071995081557012567.3610MSANS
+7312EST THIERRY 11939111971071992011433211715.4510MANGL
+2010CAMP LAURENT 11939 319890119931211389 9852.1510CTECHN
+3770COSTES ELIANE 21939 91980071992121471512024.9610CSANS
+3046CRIMEE JACQUES 11939 719890619880610494 9309.0810MANGL
+5231BONNETERIE VERONIQUE 21940 61962021988042273717260.8010VINFOR
+1917CENTRE FREDERICK HENRI 11940 31961091990012739020404.0510MALLEM
+0890MIEGESOLLES BERNARD 11940 21960041995043200223583.4110MESP
+5720SAULX JACQUES 11941 71971071990071663613343.3310MSANS
+4881DESFOSSEZ JULIETTE 21941121976051991051684813422.8110MSANS
+5085ALBERIC PHILIPPE 11941 919900719950310407 9271.7010MANGL
+0632BESSE PASCAL 11941 51966021989071663613343.7310MSANS
+5114SHARON MICHEL 11941 21968081984062022115555.3510MSANS
+4229TERRASSE BERNARD 11942 11964111993102137316332.4710MSANS
+2811BROSSOLETTE GEORGES 11942 11967121990011663613343.0610MSANS
+0937TILLEULS BRUNO 11942 81972061992011433211714.9110MANGL
+6193ROOSEVELT CHRISTIAN 11942 71972061991011663613344.1510DTECHN
+2942PETEL GEORGES 11942 21974051992071369311287.8610MTECHN
+9989TASSIGNY JEAN PATRICK 11942 91971071992011403411520.6610MANGL
+1548BARBIER RENAUD JEAN 11942 81961081986042273717260.1910VINFOR
+9612LAURAGAIS PHILIP 11943111972031995042547019084.9710MCOMPT
+0194FOUQUEVILLE BRIGITTE 21943 51963041991072273717261.1310MSANS
+2327GAVOTTE JEAN MARC 11943 11974051993011369311287.1010MSANS
+9716HENRI JACQUES 11943 31963041993032922321685.2910MANGL
+2720LOCMIQUEL BERNARD 11943 6199301199201 8656 8145.4410.SANS
+1736OLIVERAIE VERONIQUE MICHELLE 21943111971071991071578112723.5010DANGL
+5205PIOCH VERONIQUE 2194412199302199202 8656 8145.2610.SANS
+3085TRASTOUR GERARD 11944 61972041990011433211714.0710DSANS
+0317MOUETTE THERESE 21944 51972051988101621213032.5110MSANS
+5694PIERRELAIS ERIC 11945 81972091976082022115555.4410CANGL
+1116BOISSISE ANNE MARIE 21945 1198901198606 8359 7952.1210.ANGL
+4722BRIMONT MARTINE 21945 5199007198907 8656 8147.1710.INFOR
+3958CRAMCHABAN MICHEL 11945121969011990101433211714.5110MSANS
+7673SURESNES JEAN PIERRE 11945 61982011992101249910472.1010DSANS
+7687VALET JACQUES 11945 61972071989011621213032.1710MANGL
+8152TAILLIS FRANCOIS 21946 91976021991101578112722.6610MCOMPT
+0924BONAVENTURE REIKO 21946 91971011993042547019086.4510MVENTE
+8336MASSUGAS MICHELLE 21946111968111992091834514274.3910MSANS
+8834LEMENC DIDIER 11946 11974031992102334017609.9510MSANS
+6052DURAND LAURENT 11946 21972121988061932314934.9910MSANS
+8405GAULLE JACQUES FRANCOIS 11946 31969051989012273717261.7510MSANS
+7901VIOLAINE JACQUES 11946 419840719900711131 9659.1710MALLEM
+9538SUEDE JEAN MICHEL 11946101971021991011433211715.6910MSANS
+7317MARMONT ALAIN 11947 91973051991071621213032.1210MSANS
+8240ASSOMPTION JACQUES 11947 11973011991072837121100.6710MALLEM
+8104FRERE DOMINIQUE 11947 11975041993011369311286.0310MVENTE
+6906VILLEFRANQUE FRANCOISE 2194810199107199007 8656 8145.4410.MARKT
+4316DOMDES NOELLE 21948 51971011989082022115554.9910MSANS
+8058RANGE MARIE CLAUDE 21949111973061991071578112722.2410MSANS
+6117WILSON MICHELINE 21949 21970011993111834514274.5310CSANS
+2977CERISAIE CAROLE PAULETTE 21949 81972051993111471512025.8210MCOMPT
+3294PLOUER MICHEL 11949101969101989042022115555.4110MCOMPT
+4908GIRONDE PATRICK 11949 41981091992011249910472.6910MSANS
+2440AJAC FRANCOIS 11949121974081990011684813423.2610MSANS
+6866MUSTAPHA VALERIE 21949 71970111994071834514275.3810MALLEM
+9238CHOISY JACQUES 11950101976081992042022115555.4810MSANS
+5421NATIONALE FRANCOISE JEANNE 21950 21971061995121684813422.3610MSANS
+7441ROCHE CLAUDE 11950121977051993041369311288.0110MINFOR
+2053LOIR MONIQUE 21951121972061990011621213032.0610MANGL
+6550BELLEVUE FREDERIC DAVID 11951121970111990122470018540.4210MANGL
+0900PAT VICENTE 11952 61977071991011369311287.7710MINFOR
+9719BERAL YVON 11952101986101994011433211714.3710MVENTE
+8718VIENNO DOMINIQUE 11952121976101991011369311287.8310MSANS
+5348CRIKET JEAN 11953121979051995041471512024.2110MSANS
+7442DETAILLE JOEL 11953 81973031991012334017608.5310MSANS
+7704MARTILLE CATHERINE 21953 21973041991072137316330.5310CANGL
+3122MADELEINE CLAUDE 11953 31978061995041471512024.7810MANGL
+7454AURAY MARC 11953121972121992122175716601.7510MSANS
+2338LAMARTINE DOMINIQUE 11953 81981051992011471512025.4710MSANS
+5898ITALIE DENIS 11955 419941119920110791 9502.4110MSANS
+2818ENTREPRENEURS BRIGITTE 2195610199506199406 8359 7951.8010MSANS
+4736MONTBRIEUX LAURENT 11956 11982051991071471512024.9210MSANS
+5607ORBAY GILBERT 11956121976071994011369311288.0110MTECHN
+6044BRONZE CHANTAL 21956 31978031990101911114779.0510CESP
+2949AIGREFEUILLE HERVE 119561119810119840811389 9851.9210MTECHN
+1891POSTALE DIDIER 119561019820319810611131 9658.0110MSANS
+6887ESTADOU MARC 1195712199311199211 8656 8146.8810.COMPT
+3156FLACQ PHILIPPE 11957 11980081992011608112915.1510MINFOR
+0665MIRAGE HERVE 11957 41978031995041249910471.8810MSANS
+9619SOLEIL SYLVIE 2195811199406199507 9126 8456.9610MTECHN
+7598COTES MARC 11958 41978041995041249910471.9410MINFOR
+1289SOUCI ANNE 21958101980071979071194310202.5910MSANS
+5278SEYSSUEL ROSELYNE 21958 51979021993071608112917.1010MSANS
+5065INDUSTRIE JEAN PIERRE 11958 81978071995041249910473.1510CSANS
+6257PLESSIS JEAN YVES 11959 51983041994011433211714.2810MVENTE
+5018CHAUX JEAN 11959 91979061993041471512026.1810MTECHN
+4009PLEIN ANTHONY 11959 719810119800511389 9850.5610MTECHN
+9730PRINCE JEAN JACQUES 11960 31982051991091326611017.5010CSANS
+1357TAMNIES FRANCOISE 21960 11980031979031215710279.3810MSANS
+8601VALMY PIERRE M 119601019820319810311131 9657.9610MTECHN
+5371ARC GILBERT 11960111988101996012773220636.1610.INFOR
+0267OLIVIERS DIDIER 11960 7199312199212 9597 8728.6410MSANS
+3866FLEURIS JEAN MICHEL 11960 41986021993041288210744.6410MTECHN
+4485ALLEMANE PHILIPPE 11960 71983011989041608112915.2410MSANS
+1801CAUTEGRIL CORINNE 21961 11981031992061527112372.9010CTECHN
+0557BENEFIAT MARTINE 2196111199412199312 7803 7680.7710MSANS
+2605MATHURIN PIERRE 119611019830419820411131 9658.4710MINFOR
+8035BASSETTE BERTRAND 11961 31987081986081288210743.8610MANGL
+4026GAJAC KARIN 21962 81983011982011608112916.3210MSANS
+8790TREDREZ LEONIE 21962 71986061985061288210745.2210MSANS
+0932BASTIDON MARYLENE MARTHE 21962 7199301199201 8656 8146.4210.SANS
+1052MARJOLAINE PHILIPPE 11962 11984111991071868714507.4710MSANS
+3917FONSORBES JOEL YVES 11962111982061988051326611016.6210MALLEM
+6770ROUBIN FREDERIC MARC 11962 719840419870211131 9658.4110CSANS
+9591BAS EDOUARD 11963 319850419841210791 9503.5810MSANS
+0126LALA MICHEL 11963 219830619820611131 9658.7410CESP
+0547GAUMERIE EDGAR 11963121985011994011433211714.2510MANGL
+5064LOISIRS GEORGES 119631019851219860510791 9503.6610MALLEM
+6975BOUCHET YANNICK 11964 61985111985112090215981.0610MESP
+2365TERNES ERIC 11964 51983081994011433211714.4310VVENTE
+1287OIDE MARIE LOUISE 2196412199201198703 8656 8146.9710.SANS
+1746MICHELETTE GERARD 11964 619840719830710791 9503.7410MSANS
+4496COLONEL MONIQUE 21964 41984091983091288210744.8610CSANS
+6420MERCURE MICHEL 11965 61985121993121288210745.0010MSANS
+2452FEUDON ANNICK 21965 81989061988061249910471.8910MANGL
+3490DION ALEXANDRA YVETTE 21965 6199504199404 7803 7680.5910MVENTE
+9441GALLET JEAN CLAUDE 11965 11991021994022256617147.1310MSANS
+8588JARRES GERARD 11966 919880319870310407 9271.5610MSANS
+1291HERMITAGE XAVIER 11966111991101990101330611016.3310CSANS
+6530ETRUN PATRICK 11966 31989111988111539912452.4210MANGL
+1352PLAIS JUAN CARLOS 11967 419870719860710407 9270.9110MSANS
+7277REY MICHEL 11967 21995081996012559919162.3610CSANS
+1793BARBE VALERIE ANNE 21967 5199201199101 7803 7680.5910.INFOR
+3158KERIOLET FRANCOIS CHRISTOPHE 11967 41990051992121381911365.8510CSANS
+0027DANS JEAN PIERRE 11967 719920119910110024 8999.9910MSANS
+6374PUISEAU THUY LAN 11967 61987041991121249910472.2410MESP
+9025BEUVRON PATRICK 1196711199606199506 7803 7679.4610CANGL
+9820CHARLES CATHERINE 2196710199507199407 8656 8146.4610MALLEM
+6484VIGNAUD PATRICK 11969 91990071992031381911365.6710MSANS
+1414BRUNE SYLVIE 21969 619890219880211302 9775.1910MSANS
+4633MICHELET JOHAN FR 11970 619901219891210024 8999.7210MINFOR
+2182PLANTIER PHILIPPE 11971101995091994091450311831.5510CSANS
+8157LILAS PIERRE 1197210199207199107 8656 8146.5510.SANS
+5454LOIR MARIA 21973 5199406199306 7803 7680.1410CANGL
+9209CARREFOUR SERGE 11974 6199505199404 9126 8455.7410MALLEM
+3395ADAM JEAN CLAUDE 11974111993091994011202810241.5810CSANS
+8662REIGNIER JEAN MICHEL 11975 9199607199507 7803 7681.4710CSANS
+8679MOUTONNE MARIANNE 21935 9199408199201 9085 8419.1611DCOMPT
+9359RASPAIL ALAIN 11935 91963121994103200223582.5411MTECHN
+0977DELBESSOU JEAN CLAUDE 11935 91958051992013844228044.4211MANGL
+5628REPUBLIQUE PHILIPPE 11935111967011995041557012567.7211MALLEM
+5361CHAUMIERE CHANTAL 21937 91967011992011471512024.5111MANGL
+8814KIKOCHI CHRISTINE 21939 819880519870510407 9271.4611MTECHN
+3550CONCLUE PAULETTE 21941 21973081991071578112723.7211MTECHN
+3525PAU CLAIRE 21942 81965021991122334017609.2411DSANS
+6963CEZANNE CAROLE 2194310199411199311 8656 8146.7911MALLEM
+1837FRIZAC PETER 11943 81976041995011578112721.6711MINFOR
+5658SOLANGIERE JEAN 11944121969121990041433211715.0511MSANS
+7261MONTGERMONT SOPHIE JEANNINE 21945111971111995041834514274.5111MANGL
+4785LODI PHILIPPE 11945 21980071994011471512024.5611MESP
+5841PORT JACQUELINE 21946 41970021969021300910822.2611MANGL
+0606BAGEN MARIE JEANNE 21946 11970121993032022115555.6811MSANS
+5640GALLIA BENEDICTE 21946101973101993121911114780.1311MINFOR
+0298BRETIGNY MICHELINE 21946 5199208199108 8656 8145.8011.TECHN
+3925PELLETIER MARTINE 21946111968111993012137316332.0911MSANS
+7692BARBIN MARIE NOELLE 21948 21968111990012137316331.0611CINFOR
+3739JUIN MARCEL 11948111981091992011249910472.7411MSANS
+7300URANIES CHRISTIAN 11948 91973021992011433211714.6011MTECHN
+6456TUBLERIE CAROLE 21949 81968111992032470018540.0611MANGL
+3324TAMANACO MARTIAL 11949 21974061993011369311288.2211MSANS
+8400LOIRE MURIEL 21949 41969031991091834514275.4511MSANS
+9140RENAITRIE CLAUDE 11949101980071995041249910473.7211MSANS
+5589SITE PATRICIA 21949 7199508199408 7803 7679.4611MVENTE
+5386MEDECIN JACKY 11950 21975051992101369311286.8711MSANS
+2377VOLTAIRE CHRISTIAN 11951111976101993041471512025.2511MSANS
+4340BAUDRIMONT JEAN FRANCOIS 11951 41984071993121326611017.5511MINFOR
+0397PAREAGE JEAN YVES 11951 81979071994101249910472.9611MANGL
+9259PEYRAS CHANTAL 21951 4199608199508 7803 7679.6411MVENTE
+1711ESTAGNOL BRUNO CLAUDE 11951121983051992071578112722.6611MINFOR
+4351CHARRON ANNICK DENISE 2195210199408199308 8359 7952.4311MALLEM
+2396CHAPELLE JOCELYNE 21952 41976061975061288210745.0911MANGL
+3571OBSERVATOIR NICOLE 2195211199610199510 7803 7679.9911MSANS
+2219LISA MARIE LOUISE 21952 11973061991041578112722.4211MSANS
+7029VIERGE DANIEL 11953 51976091994112547019086.5111MSANS
+6315EPSOM LAURENCE SONIA 219531119961019951010668 9425.3111MSANS
+8330GUISE VERONIQUE 21954 91975071974071215710279.3211MTECHN
+4963GUILLOTIERE ROBERT 11954 21977071992072350617727.3311MSANS
+9223MARCHAUX JEAN PATRICK 11955 91975031991071578112722.0711MINFOR
+8081JAMBLES BERNARD 11955101980061995041249910472.1211MSANS
+2906DOUGLAS ERIC JEAN MARIE 11955 21978051994011369311287.7711MSANS
+3749MAGNAN PIERRE 11956 7197910199111 4134 0.8911MESP
+8176THENOT DIDIER 11956 71980021982102470018541.8311MSANS
+3392SIMON PIERRE 11956 61979021994041249910472.7011MSANS
+6393BERGERS LYDIE 2195611198901198604 8656 8146.4111.VENTE
+7181CABAUDRAN FREDERIC MICHEL 11957 21978061991102529918969.2211MSANS
+6568LANDEDA THIERRY PATRICE 11958 31979071993071471512025.9511MSANS
+0333DAPHNE CHRISTOPHE 11958 719820619810611131 9657.6211MSANS
+2504TREICH JACQUES 11959 51982051994081638413149.5711MALLEM
+3534KHRAIEF CHRISTIAN ANTONIN 11959 61981031995021433211714.7011MSANS
+9601PECLET GENEVIEVE 21959 119791019781010024 8999.7411MSANS
+2575BELLEVUE FRANCIS 11959101980051991091369311287.1611MSANS
+1679GRIGNAN GERALD 11959 71981081993081804514082.7211MANGL
+4039GOULAINE EDWIGE MARCELLE 21959 51979081993071471512024.9611MSANS
+3106YABBOQ CHRISTINE 21960 119910619900610024 8999.7011MANGL
+5771GONDS JACQUES 11960 21983051995011433211713.8911MSANS
+3478ATHOS FRANCOIS 11960 21983081989112090215980.7311MSANS
+3217MOINES FRANCE 21961 51982111981111326611017.1611MTECHN
+3318EPINAY DIDIER 11961 51982111995091450311832.0011MVENTE
+0241PROVENCALE CHRISTINE 21961 11984021983021249910472.6111MSANS
+7712JANVRY CHRISTIAN 11962 41986081995011373711328.3211MTECHN
+8426FILET GLORIA 21962 1199607199507 8656 8146.2911MSANS
+2991BOIRARGUES MARC 11962121982061990091326611016.1711CSANS
+4250FOREST ANGEL 11962 219830819950911131 9657.3911MINFOR
+0642GOGH ANNICK 21962 719960219930410668 9427.0711MSANS
+3978FONDETTES YUKIKO 21963 71984081983081527112374.5211MANGL
+1989BRANCION MARIE JOSEPHE 21963 51990041993081330611017.2911MSANS
+7919CERFS BRIGITTE 2196310199310199210 9597 8729.1711MALLEM
+6531DORMELLES PIERRE JACQUES 11963 41983041982041326611016.5111MSANS
+0104SALETTES FREDERIC 11963 219860519850511131 9658.8611MMICRO
+3391LAURISTON JEAN CLAUDE 11963 41983061991091326611017.6511MINFOR
+9918BOULEAUX DANIELLE 21964 8199505199405 8656 8146.1111MSANS
+9860MOREAS LOIC 11964 2199303199203 9597 8728.9811MSANS
+4629LEMBRAS MARC 11964 31988041989011527112374.8411MSANS
+8531SIGNORE CHANTAL 21965 4199607199507 7803 7680.8911MSANS
+5775GRANDS LINDA 21965 41988061987061249910473.6311MESP
+0548VALERIEN PHILIPPE 11965 71986041995041710713577.0111MSANS
+5728MUCHARISTA GILLES 11965 81985071991121288210744.9511MSANS
+0495ALIZES JEAN MICHEL 11965 61986071993111288210745.2211CTECHN
+3119GAMBETTA JEAN PIERRE 11965 519851119841110791 9502.2311MANGL
+7770NOTTET CHANTAL 21966 31985101984101288210744.2611MALLEM
+7186ILLIERS FRANCK 119661219921119911210024 8998.3111CANGL
+5800COLOMBIERES VERONIQUE 21966 71992081991081202810240.8611MSANS
+8549ROMAI PATRICK 11967 81987041993081450311830.5811MANGL
+2557CHAI CATHERINE 21967 9199201199101 7803 7680.9811.INFOR
+5044ROUSSILLON HIOU SHU 21967 51987111993031381911365.1911CSANS
+3101MARECHAL JACQUES 11967 91988071993011839014313.7211MANGL
+9282LEOPOLD ALAIN 119671119880519890910407 9271.9711MSANS
+1201PEYRERE PASCAL 11968 919881219871210407 9270.4211MALLEM
+7061TEICH PAUL 11968111994031993031267210588.7411MSANS
+5746HARRIAGUE GERARD 119681119900919890910407 9271.1911MANGL
+6486MAR ALAIN 11968 1199404199304 7590 7564.3511MSANS
+0773VICTOR JEAN CHRISTOPHE 11968 71994081993082107316096.7111MALLEM
+3494VILLARCEAU ISABELLE MARIE 21969 7199609199509 9894 8921.5911MSANS
+1068AMOUR DIDIER 11969111991051990051467711987.6711MINFOR
+1796ROCQUENCOURT FRANCK 11970121991091990091202810241.7011MANGL
+6197WRIGHT ANNE 21971 919930319920311389 9850.7011MSANS
+9660CYPRES GERARD 119711019900719890710024 8997.9011MALLEM
+8022ARCAY CLAUDE 11971 51992111991111202810240.1311MSANS
+3764CHEMIN FABIENNE 21971 219951119941110668 9425.6411MVENTE
+2448PINCHINADES JEAN CLAUDE 11972 21995051994051450311831.0111CALLEM
+1927VALESCURE PHILIPPE 11972 4199501199304 9597 8728.7711CSANS
+2074AZUR DIDIER 11972 51993111992111267210588.5311CTECHN
+9842BASTIDE ERIC 11972 5199312199212 9597 8727.9111CSANS
+5954SABLES ROCCO 1197212199305199205 9597 8728.1911CSANS
+0278PAIXENT JEAN MICHEL 11972121994101993101360611210.6011CSANS
+1572DAGNY BRUNO 11972 11993101992101360611210.2811MSANS
+4298AIZIER NICOLE 21972 219940719920111389 9852.4211MALLEM
+2321DESIRADE EVELYNE 21972 119910719900710024 8998.1311MTECHN
+6794CHEUVRY PHILIPPE 11973 9199207199107 9597 8729.9211CSANS
+8383ETIOLLES ANNE MARIE 21974 5199607199507 9894 8922.2111CSANS
+3562PORSCAVE GEORGES PASCAL 11974 1199508199408 7803 7679.9911CANGL
+6773GERANDO NICOLE 21974 51995051994071450311831.9711CANGL
+4226APPY BERTRAND GEORGES 11975 2199606199506 9256 8532.5611CTECHN
+1343SANS FRANCOIS 1197510199410199310 9126 8456.3911CSANS
+6979ANGLAIS NADINE 21975 7199304199302 8656 8145.5711.SANS
+5254BERLIOZ DANIELE 2197610199607199507 7803 7680.5011CTECHN
+0275FRIARD GERARD 1197610199608199508 7803 7681.4711CSANS
+3929CHATEAU VERONIQUE 21935 2199301199201 9085 8417.4612VANGL
+2917PASTEUR NICOLE 21935 31967071990011932314933.6012MSANS
+4491FALLIERE CATHERINE 21935 7199109199507 7677 7603.7312.ANGL
+4190CHRISTOPHE DOMINIQUE AUGUSTE 11935 31977111992101369311287.1912MANGL
+3826RAYON BERNARD 11935 319830819820811389 9851.7412DESP
+2841SEVERINE PHILIPPE 11936 6199409199309 8656 8146.7412MANGL
+6337FREDERIC CATHERINE 2193812199201199101 9085 8417.6312SSANS
+7355ANTOVAL JEAN FRANCOIS 11938101961021995043200223582.3212MANGL
+8990DETALOUX CLAUDIE 21938 71962071984102273717260.0812CSANS
+7576SEBASTIEN BERNARD 11939 51971121991071663613343.3712MCOMPT
+3808CABRIES ANNE LOUISE 21939 31973071985041834514275.9512VSANS
+3333BOSQUE JEAN YVES 119391219900919920310791 9503.1612CTECHN
+0851ORANGERS CHRISTIAN 11939 11973071992011433211715.2212MALLEM
+7226ROYA FRANCOISE 21939121962121983122470018541.7912MSANS
+4767DOMITIA VINCENT 11939 6198912198504 8656 8145.1112.VENTE
+1932LEROY FRANCK 11939101968101991011433211714.2112MTECHN
+4220GUERINIERE MICHEL 11940 11971041991011663613343.9712MSANS
+5021MONTLANDON RENE 11940 61973041993011369311286.6612MSANS
+3088ALTAIR NICOLE 21941101962031994122470018540.1712MSANS
+2222MILLET JACQUELINE 21941 21970051992072137316331.7812MALLEM
+6726HURONNERIE CHRISTIAN 11941101980031992011403411521.2912MANGL
+1951ROSIERE GILBERT 11941 91971031990011433211715.5412MSANS
+4436CHAVANNES MARIA LUIZ 21942 51968111991072137316332.6012MSANS
+9151CHATONNAY PAUL 11942 21969021990071433211715.6312MTECHN
+2643SOUSBOIS DOMINIQUE 21942 31962041988122470018540.2412MSANS
+6554SARCELLES JEAN MARIE 11943111963071993083200223584.0712MTECHN
+6672RENDEZVOUS FRANCOIS 11943 11969091990101663613343.6012MSANS
+3579RUISSEAU DANIEL 11943 31965011994011557012567.1812MANGL
+0484PAUL CORINNA 21943 61965121988062470018540.6612MSANS
+3880ROUVRES ERIC 11943 819931119950610407 9271.7412MSANS
+4665MONTEE JOSETTE 21943111968041991052470018540.5712MSANS
+3302VERS JEAN 11944111970061991011433211714.8712MANGL
+6749AUCUN JEAN CLAUDE 11945 11974071992041471512025.0212MINFOR
+6957RESIDENCE EVELYNE 21945 61971071991101578112723.4212CSANS
+1669CHEZY PIERRE 11946111976051993011369311286.0612MSANS
+1674AVENIDA SYLVIE 2194611198806198706 9511 8688.4112DINFOR
+6741FONDS GEORGES 11948 11977041994011249910472.1012MSANS
+4859ZORI CATHERINE 21948 81968111991021834514274.7012MSANS
+1314MINES JEAN MARIE 11948 31975061993071369311288.1812MALLEM
+5393PROVEN ANNICK 21948 9199309199209 8656 8145.0612.ALLEM
+9886FLAUBERT YOLANDE 21948 41968041995111684813422.3612MANGL
+8118JUGY JACQUELINE 2194912199504199404 8656 8146.6412MTECHN
+3693RETRAITE MARYSE ARMANDE 21949 9199201199101 7803 7681.4712.SANS
+7335PETITES MICHELLE 21949 71970101990112043315671.1512MSANS
+6896MERIMEE PATRICK 11949 11972031995011834514274.2412MANGL
+0173RESIDENCE HARRY 11949 71973061992101369311287.1412MVENTE
+7211LAVIGNAC MARIE ANNE 21950 6199307199207 7803 7680.0912.SANS
+6258DEAUVILLE SALIM PHILIPPE 11950 61975101993011684813423.4912MSANS
+6945BERANGER AGNES 21950 11970011989011621213034.1012MSANS
+6072LAZUEL CHANTAL 21951 11971051995041834514274.4412MSANS
+3233GRETZ PATRICK 11951 61981041993011608112917.2412MSANS
+3090VERTS THERESE 21951 21972101987072334017610.2012CALLEM
+4522POISY BRIGITTE 21951 41973051991011578112722.7012MSANS
+1211SAINTE PIERRE 11951 219940119940110407 9272.1312MSANS
+9697RUE NADINE NICOLE 21951 11977071991051608112915.7412CTECHN
+7336GRURY ANTOINE 11951111977051993041369311286.9212MTECHN
+4900BENARD JEAN LOUIS 11951 71973081992032470018540.1512MSANS
+0543BARETY JACQUES 11951 71977031993011369311286.8012MSANS
+4195GRENIER THIERRY HENRI 11951 71979011994111403411522.0912MALLEM
+6636BERANGER JEAN PIERRE 11951 619831219821211131 9659.0112MALLEM
+1282PALOMBES OLIVIER 11952 81979061995011621213033.3712MESP
+7146VENERIE YANN MAR 11952101981031992011249910473.4712MSANS
+8503GIRELLES MARTINE 21952 41993111992011202810240.1312MANGL
+9767ROUBLOT FREDERIC 11952 71976121991071578112722.3712MSANS
+1506BELLES SERGE 11952 1199301199201 8656 8146.7012.SANS
+5411MERMOZ BRIGITTE 21953 419910919900910024 8997.8112SSANS
+8001PANORAMAS JACQUES 11953111980031992101369311287.3212MALLEM
+8972NOGUES JEAN 11953121981091992011249910472.0112MSANS
+6536MARX EVELYNE 21953 7199201199101 9511 8688.8912MANGL
+3768LAMBRIGOT PHILIPPE 11954 51976071991012022115554.5412MSANS
+0662BRACQ GEORGES 11954121975111993121369311286.4712MSANS
+5304BETOUILLERE NORIKO 21954 71979061993041433211713.9212MALLEM
+4215PARA KARIN 21954 91979071992111608112915.5312DSANS
+2037FORGE LUCIEN 11955 21984021992111578112723.2412MSANS
+2945ABBEVILLE PASCAL 11955101983101993011471512025.4612MANGL
+2849NERTHE MARTINE 21955 21978091993101471512025.9212MSANS
+3488REVOL ANNE 21955111977071992011471512024.0612MSANS
+4431LAUNAY LOIC 11955101984091993011215710278.6912MSANS
+8724CASSIFLORE ROGER 11956 11976071985102397418036.3812MANGL
+0629FRANCOIS SANDRINE 21956 91977071995101881314586.0612MSANS
+4823RENARDIERE JEAN LOUIS 11956 41977031992111608112915.2912MSANS
+8808ENGHIEN MAX 11956 91977061992011471512025.6512MVENTE
+2432MICHELE ISABELLE 2195710199611199511 7803 7679.4512CINFOR
+7158CAPITAINE DOMINIQUE 21957 91978061993031608112917.0412MSANS
+6317COURLIS GUY 11957 21980051992121369311286.7412MSANS
+7608DESSUS SABINE NICOLE 21957121979031993041471512025.2812MSANS
+3637PEYRIERE FRANCOIS 11957 81979111995101911114778.2412MSANS
+9600HAKEIM THIERRY 11957 51981031986092256617146.6812MANGL
+1537RESISTANCE SERGE 11958 81986031991101868714506.0112MSANS
+3033PIERREDON JEAN LUC 11958 51980041992121471512024.7812MSANS
+9058ROYALES ALAIN 11958 31982081994041326611016.6912MSANS
+1074PONTILLARD JACQUELINE 21958 51981111980111608112915.8412MALLEM
+0339VERNOCE THIERRY 11958 81982041994041471512025.3212MSANS
+1325ZOLA CHRISTINE 21958 81978121993041471512024.9312MSANS
+6083HAIG MICHELE 21959 419791119781110876 9502.3712MSANS
+9351QUIHOU STEPHANE 11959 41988061992091450311831.2512MSANS
+9582LAENNEC COLETTE 21959 41983071982071326611016.0812MSANS
+5220RECOLLETS YVES 11959 51981011994011471512026.1512MSANS
+5140DAILLON DOMINIQUE JEAN 11960 31984071995081527112374.5812MANGL
+4446ELPHEGE PIERRE YVES 11960 419840319830811131 9657.2612MANGL
+0969BOUNIN PHILIPPE 11960 71983031991111616712995.2012MSANS
+2335CAILLOUP CHRISTINE 21960 11980091994071471512025.0212DSANS
+8339MER ISABELLE 21960111980101979101684813422.5712MANGL
+6061ESCALES JEAN MARIE 11960 51982051995121804514082.6512CSANS
+0818GATTIERES PATRICE 11961121983121989031527112373.0812MTECHN
+5053LARUE KARINE 21961 8199407199307 8359 7952.0712MSANS
+9219OPALINE EVELYNE 21961 61983111982111202810240.8412MALLEM
+6160LAURENT ANNICK 21961 51982091981091527112373.7112MANGL
+9514GARGAS NICOLE 21961 31981041980041684813421.4912MSANS
+2936KIPLING ERIC 11961 419830419830711131 9659.2212MTECHN
+3023BOREL PHILIPPE GILLES 11961 51982041981081608112915.8912MSANS
+5767BORGHERE PASCAL EMILE 11961 51985061989112090215981.0912MSANS
+9519SUISSES PHILIPPE 11961121985031984031608112916.4312MSANS
+7271BOUEL JEAN LUC 11962 21982071990101527112374.1612MSANS
+1969BIERE SIMONE 21962 3199404199304 8359 7953.2412MESP
+1388MOLIERE GERARD 11962 71987081988011527112374.2012MSANS
+5714NICOLO DIDIER 11962 11983071984121608112916.8112MCOMPT
+1039ATTILL ERIC 11962 91983081984091608112916.6412MALLEM
+4474SAUSSAYE MICHEL 11962101989011992121249910471.9712CANGL
+0108ORBESSON MIREILLE 21962 81983041989112090215981.4112MSANS
+8464DIJON JEAN LUC 119621219860219850210791 9503.7012MINFOR
+0217MAGDEBOURG PIERRE 11962 51986071995011373711327.8712MANGL
+5259VANOEL SERGE 11963 81984021991011868714507.8512CSANS
+6176GOETHE GILLES RAYMOND 11963 41983051993121326611016.5712MSANS
+3711SIGNAL KARIN 21963 6199407199307 9126 8456.8212MCOMPT
+5792ARCACHON SERGE 11963 519931019910710407 9271.9712MCOMPT
+2491OSSOLA ANNIE 21963 51993101992011202810240.2612CSANS
+5463PERE JEAN LUC 11963 819860319850310791 9503.8812MSANS
+0572ALSACE MICHEL 11963 219830619920111131 9658.0212MANGL
+5197LATECOERE BERNADETTE 2196411199201199101 7803 7680.2312.SANS
+3820SAUSSES MICHEL LOUIS 11964 31986061985061288210743.8312CINFOR
+3831CRESP BRIGITTE 21964 6199109199009 8656 8145.8412.TECHN
+7862GUILLEMARD GERARD 11964 619870419880910791 9503.2712MSANS
+3863TREMOILLE LAURENT 11965111989011991051249910473.0012MTECHN
+2269VERDUN DIDIER 119651019870219910110407 9271.4212MSANS
+4817VAUCLUSIENS JEAN PIERRE 11965101986051991091288210743.8612MVENTE
+8120BUSSIERE LYNDA 21965101988041994121450311832.2912MSANS
+9872ROTTEMBOURG PHILIPPE 11965 71985071991091288210745.6112CALLEM
+3157GEORGES MARC 11965 119870219860210791 9502.1412MVENTE
+5375GRAFFIANE ROBERT 11965 119870419861210791 9502.8912MSANS
+9838SELLE XAVIER 11966101992011991011202810240.9512MSANS
+4716BEG PASCAL 11966 61987061992041249910473.4212CANGL
+8142FONTENIL MADELEINE 21967 91990051993051723313653.6012VESP
+4631ROBINS ISABELLE CAMILLE 21967 61993111992011202810241.8112MSANS
+0875RESISTANTE ALAIN 11967 61988041994011249910473.1812MSANS
+7618JUANE JOSEPH 11967 919880919910210407 9270.4812MSANS
+6297QUINT MARIE CHRISTINE 21967 11989121988121202810240.8412MINFOR
+9234SAINTRY FRANCK JEAN 11967 619891019881010791 9502.8912MSANS
+0878MERIMEE GUY 11967 81990011989011467711986.9112MSANS
+7463VALETTE BERTRAND 11967 91987051994051381911366.9312MSANS
+1043RAMBOUILLET JEAN FRANCOIS 11968 81990071989071381911364.8712MANGL
+2350PANPYC CLAUDE 11968 91990111989111467711985.8712MSANS
+9468GUEPIN EVA 21968 41989051988071949415051.6812MSANS
+4690VERLIN YVES 11968101989111994011249910473.4712MINFOR
+4832BAYARD CORINNE 21968 21990111989111202810239.8312MSANS
+2141CHATAIGNIER CATHERINE 21968 519940919930411389 9852.2212MMANAG
+2439AIGUILLE CATHERINE 21968 9199407199307 8359 7952.2512MVENTE
+2895PASSAGE PHILIPPE 11968111990031989081381911366.2212CSANS
+6720ANTHEOR VINCENT 11968 21988051993041249910472.6412MSANS
+4877AUBIN PATRICK 11968 71990011989011202810239.7812CSANS
+7975GUITTARD ISABELLE 21968121993121992011202810240.1912MSANS
+3884DESMOULINS ANNIE 21969 2199510199410 7803 7680.5012MSANS
+4326CASSIOPEE JEAN PIERRE 11969 21989031988031249910473.5612MSANS
+9844DAUDET ROBERT 11969121993101992101330611016.3012MALLEM
+1235TRANSIT CHRISTINE 21969101992031991031420611639.2212CINFOR
+9148CARTIGNY TONY PIERRE 11969 81994091993091450311830.6212CMANAG
+1898VEUVE BERNARD 11969 119891019881010407 9270.6912CALLEM
+4856BELIER JEROME 11970 11990111992011381911365.6212MSANS
+3215BASTILLE GILBERT 11970 219921019911010024 8997.8612CSANS
+1681VAUCHAMPS THIERRY 11970 319940419930111389 9852.2412CVENTE
+0330GIRAUD DIDIER 11970 319940319920110024 8998.7112MALLEM
+2920FONZERI PAUL 11970 81993061992061267210590.0212MTECHN
+3390CLANS LOUIS 11970 51989111988111539912451.9712CSANS
+7148OISEAUX FRANCE 2197011199004198904 8656 8145.6612.MANAG
+2817GAIRANT MONIQUE 21970 319910719900710024 8997.9112CSANS
+8162VOLONTAIRES MONIQUE 21970 5199410199310 7590 7564.3812MSANS
+9567LEGUMES CHRISTINE 219711119950419940110668 9426.0312MANGL
+2435BRESSON SYLVIE 2197112199007199101 8656 8145.9312MSANS
+0955BEAUGENCY LAURENCE 21971 1199206199106 9597 8729.9712CSANS
+4021VICOMTE ROLAND 11971 119900619890610024 8998.0112MINFOR
+7963MONTESQUIEU HENRI 11971 51993081994011249910473.0512MVENTE
+9955WAY JEAN MARC 11971 1199305199205 9597 8728.0112CSANS
+1833INKERMANN LAURE 21972 919930519920511389 9851.3912MANGL
+4630CHEVREUILS CHRISTINE 2197312199306199206 8359 7952.0112.TECHN
+3273MIREILLE ALAIN 11973 819931119921111389 9851.5512CMARKT
+6842DARONNE ALAIN 1197311199307199503 9597 8729.2212CINFOR
+5953BOURGEOIS BRUNO 11973 21993081994011202810241.9212MSANS
+3467PONTIER ALAIN 11973 619930919920911389 9850.5612MSANS
+6507MAYVILLE CHANTAL 21974 1199208199302 8656 8146.4112MANGL
+4060HALLEGUEN MICHEL 11974 11993121994011202810241.7012CSANS
+8760RAGUINOT GHISLAINE ROBERTE 21975 1199507199407 7803 7681.4412CSANS
+1454NEUF GILLES 11977 9199606199506 7803 7681.3512CSANS
+2092BRASSAURIS MICHEL 11931 91956101978013327724477.6013VSANS
+8552VIOLET DIDIER 11933 4198810199501 8827 8263.5613.SANS
+6589DEVENCON BERNARD 11934111955111993103417325098.4513MSANS
+7036PERNETY FREDERIC 11934101961111987102273717260.4013MINFOR
+7079CHARDONNERETS LAURIS 11935 31978071992011403411520.5313CINFOR
+9868JAURES MICHEL 11935 51970051992011403411521.2013MSANS
+8365HELIOTROPES LISE 21935 11963021991072273717259.8613CSANS
+7450POISSON CHANTAL 21936 91968111989011621213033.5613MINFOR
+9779CONSOLACAO NATHALIE 21937 3199401199201 9085 8417.3613VSANS
+8202DIANE JACQUELINE SUZANNE 21937 61972041989101621213032.8713VESP
+5521LAZURE RAOUL 11937 31966021995011557012567.6313MTECHN
+7843NOM ETIENNE 11938 1199001198510 8656 8145.6213.SANS
+7282IRISASCO ERIC STANIS 11938121958081988013844228045.3713MSANS
+3124VIVIER GEORGES 11939121967011994011663613342.8513MSANS
+1445GAUSSADE FRANCINE 21939 11967121992012137316332.1113MSANS
+5399GROSSETI JACQUES 11940111969011990011433211714.7913MSANS
+7177MONTSEGUR DOMINIQUE 11940 2199206199106 8656 8146.8313.ALLEM
+4475SOLEIL JEAN CHARLES 11940111962041993043417325097.6413MINFOR
+6615GRAVELLE CLAUDE 11940 419880319870810407 9270.3013MESP
+5880OR LILIANE 21940 8199301199201 8656 8147.0113.ANGL
+0756RENARD PATRICK 11941 71960041991013327724477.7213MSANS
+9016SIMON JACQUES 11941 81973061992101369311288.1813MANGL
+4931AIGNAN SALOMON 11941121972111992011403411520.2913MSANS
+7676ROUX DOMINIQUE 11941 81969121990011433211715.5413MSANS
+3434NOUVELLE GUILLAUME 11941 31970061991011433211715.4713MSANS
+1569MOULINS CATHERINE 21941 31993051993101249910472.9113MSANS
+4399SOLDATS ANNE 21941 71963091994011932314934.0013VSANS
+4929MANOUCHIAN RICHARD 11943 41979011992011249910473.3213MALLEM
+5101CLOT PATRICK 11943101977041995011578112723.1813MSANS
+1399PLANTES MEDERIC 11943 61962111991072273717261.5413MTECHN
+4835LECHIAGAT MAURICE 11944111963121993082922321683.6013MSANS
+2862CASTELROC PHILIPPE 11944 81968091988062947921840.0613MTECHN
+5852PUGET JEAN LEO 11944101971011990032022115554.8113MSANS
+4369BOUCHER LUCIEN 11944 51976051991012022115555.3913MALLEM
+6206VERANE COLETTE 21945 11975101987031684813422.3113MSANS
+2842ROND THIERRY PIERRE 11946 11967121993013844228045.1613MANGL
+8250JULIEN MARIE PAULE 21947 4199409199309 7803 7680.0013MINFOR
+4160ALLUES DANNY 21947101978071993012529918968.6013MSANS
+8190BUT CLAUDE 11947 71982041994011471512024.0813MANGL
+9979FLORALE STEVEN 11947 21975041992101369311286.7813MANGL
+5458BEYNAC PIERRE 11947111972031994011663613343.8813MESP
+5735CONDE THIERRY HENRI 11947 51976041995011578112722.5213MSANS
+6972BIRAC DANIELLE 21948 41973071991071578112722.1913MSANS
+8328MAC LAURENT ROLAND 11948121977031993011369311287.1013MSANS
+8020COMMODORE JACKY 11949 21977031993071369311287.0713MSANS
+9492BOURGADE FREDERIC NICOLAS 11949 91972081986092470018540.6013MANGL
+7494HAM JEAN BAPTISTE 11949111979041993081369311287.1913MSANS
+2684LANTERNE JEAN PIERRE 11950121975041991071578112723.1813MSANS
+8110LACOUSSIERE MONIQUE 21950 71993101992011202810240.4013MANGL
+4050HERBILLON FRANCOIS 11950111971051991012470018540.6113MSANS
+0115ACHILLE JACQUES 11951 41976021992091834514274.9313MSANS
+6913MADAGASCAR FRANCOISE 21951 81977101993041471512024.8713MANGL
+9541FARGE FRANCOIS 11952 91984031994011433211714.8813MANGL
+1147VERTES GEORGES 11952111979041991011608112917.2413MANGL
+3720FRESNE PASCAL 11952 91973021992082022115554.4213MALLEM
+3427LYAUTEY SOPHIE 21952 91973051991011578112723.4213MALLEM
+6348TOURELLE BEATRICE 21952 51972061990011621213034.1513MANGL
+6291MONTMERY MICHEL 11952111978091995011578112723.5413MSANS
+9048VILL YANN 11953 51981021993011369311286.6913MSANS
+2556GAGNEUR MARTINE 21954 3199611199511 8359 7952.9113MTECHN
+5041GALAND MICHELE 21954121981071995071433211714.0113MSANS
+6421OUERRE CHARLEY 11956111982071993011249910473.1113MESP
+8090BALISE JOEL 11956 61986011995011373711326.7113MSANS
+6312RASPAIL CAROLINE 21956 619940619920111389 9852.5113MSANS
+6598RUBENS JEAN MICHEL 11957121976121992011578112721.6513MMARKT
+7944MAUBEUGE JEAN ALAIN 11957 11982031981031326611016.2913MMARKT
+8793MOREAU BERNARD 11957111985051988031288210745.0413MANGL
+8404CHEVERNY OLIVIER 11957 51983081995011578112722.8713MSANS
+1860CHAMPIGNY JEAN HUGUES 11957121978031993051608112916.7213MSANS
+9938CHARENTON PASCAL 11957 21981061993011471512025.2513MSANS
+0001TASSIG ARMELLE 21957 71982031981031288210743.8113MSANS
+6966GARE MARIE THERESE 21957 41979101993071471512025.8213MINFOR
+5849ELOI FRANCIS 11958 21983051993011215710279.9913MALLEM
+0222GERTWILLER ROLF MIC 11958 61983061995061894014661.1213MINFOR
+9106MAISON JEAN CLAUDE 11958 11978021992051471512025.5613MSANS
+3045BATISSE PHILIPPE 11958 51977121992012175716600.9413MVENTE
+6087HUCHA ANNE NATHALIE 21959121981011988112090215981.6313MSANS
+7732GENETS JEAN DENIS 11959121986061985061288210745.3913MSANS
+8156BRASLES BRUNO ROGER 11959 81984041995071433211714.0613MSANS
+4809GENEVOIX ALAIN 11960 219810919810111389 9851.6613MTECHN
+2618BOCOUMYAJOUR PHILIPPE 11960 41980061992092090215981.1813MSANS
+1786TREVARESSE FRANCIS 11960 21981091994011471512025.5013MSANS
+7909CHARITE CATHERINE 21961 11985041984041527112373.8513CESP
+7849BUCHES COLETTE 21961121985051984051527112373.8513MSANS
+7624JOUVENES CATHERINE 21961 1199504199404 8359 7953.5113MANGL
+2428DUCOS FRANCE 21961 1199309199209 8656 8146.1613.ALLEM
+4640FINLAY JEAN PAUL 11961 319830419841011131 9658.3413MSANS
+0498MONET ANDREE 21961111983081982081608112917.0013MSANS
+3902ISTANBUL DENIS 11962 519840619830611131 9657.5313MINFOR
+8720LOU ALBERT 119621119880819870810407 9271.3413MALLEM
+9086CARNOT HENRI 11962101990111989111450311830.9813MSANS
+4105CHAMINY YVES 11962 21982051987041608112917.1013MVENTE
+7566SAINS CHRISTIAN 11962 31983091993051527112372.8113MSANS
+2552FOCH FRANCK 11962121986061990111288210745.8113MSANS
+5248VERONESE PATRICE 11962 219890119880210407 9271.9913MSANS
+0127GRENETA BEATRICE GENEVIEVE 21962101984071983071288210743.8613MANGL
+6150MAUREL DOMINIQUE 21962 11984071983111608112915.0813MVENTE
+7881CHAILLEY ISABELLE 21963101985091984091288210744.4413CSANS
+3227POINT COLETTE 21963 31989031988031249910471.5813CANGL
+1094FERRAT ANNE LORRAINE 21963 91983061982061326611017.8313MSANS
+0209MONTALEAU PASCAL JEAN 11963101983061986111326611017.3413MTECHN
+6991COLOMBIER MARCEL 119631119870519880210791 9502.8913MSANS
+8764PALMAS MARTINE 21963 81994051993051267210590.2913MTECHN
+2275FANGADE ELISABETH 21963 51984021983021288210744.8513MTECHN
+0866SECRET MIREILLE 21963 71991111990111249910472.0313MSANS
+0133TORREPORTO CHRISTIANE THERESE 21963 6199302199202 7803 7680.4513.SANS
+1651VALERE VINCENT 11963101987081991071288210745.9413MANGL
+0332FRER CATHERINE 21964 7199407199307 7803 7681.2913MINFOR
+1313ARPHY FREDERIC PASCAL 119641019870319860310791 9502.9813MSANS
+7694BANNIERE GERARD 11964101987041992111288210745.9913MSANS
+2808BOULIE ISABELLE 21964 41985051984051450311832.6913MSANS
+9520ERMONT VERONIQUE 21964101993111992011202810241.1313MSANS
+7726BUTIN JEAN YVES 11964 6198810198707 8656 8145.0313.COMPT
+9487MARECHAUX ERIC JACQUES 11964 21988051987051450311830.9813CSANS
+7195ARENE CHRISTINE 21964 71994101993101249910471.7613MINFOR
+3536HAIE NATHALIE LUCE 21965 71985121984121249910472.4713MSANS
+0845CHARLEMENTINE DOMINIQUE 21965 519940419920111389 9852.7413CTECHN
+8486CANADEL SUZANNE 21965 41985121984121288210744.4113MALLEM
+5385ROZOY TRISTAN 11965 31987071992031450311830.8313MANGL
+7086BEAUME ALAIN 119651019860619850610791 9502.5313MSANS
+2621LOTISSEMENT STANISLAW 11965 51986051990111616712995.9313MSANS
+9449POSTE MARIE CLAUDE 21965111989031988031202810241.5713MSANS
+1109PERRAULT CHRISTIAN 11966 81986041994041450311831.3713MSANS
+4280BEGUDE MARTINE 21966 91986041985041288210744.1913MSANS
+1973ESPRAT JEAN BAPTISTE 11966 919900119900510024 8997.9113MTECHN
+6164UNIVERSITE VERONIQUE 21966 41985121984121288210744.1313MSANS
+9407THIERRY GUENAELL 21966 91990091989091638413150.7913CALLEM
+6809PERCEY PHILIPPE 11967 519930819920811389 9850.5313MTECHN
+9633GILANDIERE ANDRE 11968 61993081994082256617146.7213CSANS
+7128PERSPECTIVE PHILIPPE 11968101991101990101467711987.3613MSANS
+0709AMYOT ISABELLE 2196810199603199503 7803 7680.2113MSANS
+9931CIVADE PIERRE 11969 51991111990111467711986.6213MSANS
+1496FERME STEPHANE 11969 519890919880910407 9271.7913CTECHN
+4802JAURES MARIE CLAUDE 21969 21994011992011202810240.8213MALLEM
+5721VIEUX ERIC 11969 41989061991021249910473.5413MSANS
+4763PINTA ALAIN GEORGES 11969 919921019930210407 9270.6513MSANS
+9618PASTOUR CHRISTINE 21969 11994081993081206910240.4613CSANS
+3207PAQUERETTES MARIE CHRISTINE 21969 619940619930410668 9426.0813CSANS
+0667FOURCHES SYLVIE 21969 719920719930411389 9850.6213MSANS
+8437ORANGERI DANIEL 11969 31989041992121249910473.1513CSANS
+4233LEBLANC CHRISTIAN 11970 419910119900110024 8999.3113MANGL
+2043RAVEL FRANCOISE 2197010199301199201 9597 8728.8913MSANS
+4748REDONDO CHRISTINE 21970111994081993081206910241.3013CINFOR
+6379ROUGE CATHERINE 21970 11994011992011202810241.7213MALLEM
+4507ALBAN CATHERINE 21970 91993011991011202810240.9813MSANS
+8424FRANCE JEAN PIERRE 11970111992081991081202810240.9913CANGL
+3409FLEURUS BRIGITTE 21970 9199009198909 8656 8146.6813.ALLEM
+8040ROY PATRICK 11970 41991111990111839014313.7013MSANS
+4985CUTTE MICHELE 21970 419940519920111389 9852.6013CANGL
+0589MARTIN FABRICE 11971 11990091992021202810241.9013CANGL
+2531ROI MICHEL 11971 41994011992011202810240.4413LSANS
+0686RENAUDIN JEAN FRANCOIS 11971 51990091993121202810241.1213CSANS
+1223ROUDIL CECILE MARIE 219711019921019911011389 9852.5913MVENTE
+0603THORETON GUY 11971 7199605199505 7803 7681.0813MSANS
+4480WAGNER YVES 11972 31991091994011249910473.6313CSANS
+7873VALERY NORBERT 11972 319921019911011389 9852.0613MSANS
+0068LAC CATHERINE 21972 419940519920111389 9852.2713MSANS
+6496BEL CATHERINE EMILIENNE 219721119920219910211389 9851.3413MESP
+4096XAVIER THIERRY 11973 31995121995101288210745.8513CSANS
+0302FRANCH WILLIAM 11973 8199502199402 9894 8922.8613CSANS
+1195GUILBERT ELISABETH 21973 819930319920311389 9851.4113CSANS
+8888LEGER BERNADETTE 21973 7199409199309 9126 8455.9813CSANS
+9415FONTANEY MARIE PAULE 21973 4199404199304 9894 8922.4113MSANS
+8921ROSA SUZANNE 219741019940819930810668 9426.3413CVENTE
+1867BASSE JOCELYNE 21974 6199404199304 9894 8923.1713MSANS
+1798RUSSE THIERRY 11974 4199401199301 9894 8923.3113CANGL
+8684CHEM BERTRAND 11975 6199407199307 7803 7680.3913CSANS
+3841UTRILLO JACQUES 1197611199506199406 7803 7681.1613CSANS
+6399ABEILLES RENE 11934 7199207199107 9511 8687.5114MSANS
+1983PETUNIAS MICHELLE 21935 1199208199501 7803 7680.2614.SANS
+0006DOMONT YVES 1193511198810198509 8656 8145.3914.ALLEM
+6326JATELIER CHRISTIAN 1193511199107198509 8656 8146.0914.ANGL
+5224MAGNOLIAS MICHELE 21936 31962111991072273717260.2614MSANS
+1839ANSELME REMY 11937 21963121994011557012567.7714MSANS
+6250ASPREMONT JEAN LUC 11937 91968081990071433211715.6514MALLEM
+2328AGE MARIE HELENE 21937 81966071995102017815518.0914MSANS
+1178NAPOLEON HELENE 21938 61967071990071578112723.2714CANGL
+9417SOUTRANO MICHELE 21938 11963021963051288210744.3714MVENTE
+9022GATINES CHRISTIAN 11938 11973071992011403411520.0814MINFOR
+6359LANCHY SOPHIE 21938 8198811198511 8656 8146.3414.ALLEM
+4141JASMINS PIERRE 11938 81976071992041403411521.0714MANGL
+7981NOUVELLES PHILIPPE 11939111968011993011557012566.8214MTECHN
+1626VEUR LOIC 11939 11982011993011215710279.2314MANGL
+4677ORMEAUX CHRISTIAN 11939 91963121994011557012567.6614MSANS
+0263ASPHODELE STEPHANIE 2194010198807198707 8656 8146.5514.ANGL
+8254CONNETABLE JOELLE 21940 8199509199409 8656 8147.1714MINFOR
+9870RESISTANCE PHILIPPE 11940 61967071993061834514274.5714MSANS
+4388ORBAY PATRICK 11941 41965051994011557012568.1314MINFOR
+0023ROUVIGNARGUES CATHERINE 21941101963011994042666519900.9114MMARKT
+9628BROOKE ROGER 11942 11962021991072273717261.4714MMARKT
+4240NUMANCE ANNIE 21942 71963031992012273717261.0014MANGL
+3342ROMPU FRANCIS 11942 61962031994113200223583.9014MSANS
+4773HA DIDIER 11942101961091994033200223583.1214MANGL
+2795ECHO BRIGITTE 21944 419941019930411389 9852.4114MSANS
+4188VISONNIERE MARIE CHANTAL 21945121972101971101249910473.7414MINFOR
+0739VALLES JEAN FRANCOIS 11945 71966081995042666519900.3614MSANS
+4899COURBANIERE DIDIER PIERRE 11945 31972061991011663613343.1614MESP
+7972FORET MARC 11947 41971071991011433211714.9114MESP
+1272CIGALES JEAN DOMINIQUE 11947101976101991011369311286.2114MTECHN
+6191HUGO MARLENE 21948 91973101991071578112722.6114MSANS
+1802CAVALIER PHILIPPE 11949111972021992092256617145.2914MALLEM
+3695JEANNE CHRISTOPHE 11949121977081992101471512024.1514MESP
+9900ANTOUNE FRANCE DOMINIQUE 21949 31972121992012017815516.8314MSANS
+0012MAUREILLAS RAPHAELE 21951 51971071988052334017609.1514DSANS
+9378VERDIERS CLAUDE 11951 41980031992061369311287.0114MSANS
+8265POUSSIEU DOMINIQUE 21951 81980061988052090215979.7614CSANS
+3423MORIGNY LUC 11952111979061992011608112916.7214MSANS
+7925FOURNIER JEAN PIERRE 11952 21976021995061608112916.2814MSANS
+2966ANTIBES JOEL 11952 41975101994041894014661.7814MANGL
+7905BOISSONADE FRANCOIS 11952 51990031989031288210744.1914MINFOR
+2700LERINS MURIEL 21953 91974011973011288210745.5214MTECHN
+6213TOISON JACQUELINE 21954 21974081982041527112373.3514MSANS
+1204TRIANON ANNICK 21954 3198801198511 8656 8146.6514.SANS
+7183CABRIER MARIE FRANCE 21954111974071979112470018541.1114MSANS
+0005BOILEAU FRANCOIS 11954 61974051990052175716601.9514MSANS
+7845LARGADES NOELLE FRANCOISE 21955101977021992011471512024.8714MSANS
+3059BLEUETS MAURICE 11956 81980071995011471512025.7014MSANS
+3868IORANA PATRICIA 21957 2199201199101 7803 7680.0314.SANS
+4327MARTILLE CATHERINE 21957101984091983091288210744.6414CSANS
+3448FAREL MICHELINE 2195712198805198603 8656 8145.9314.SANS
+6045AIGUELONGUE MICHEL 11958 71983081992061527112374.8114MANGL
+3104GAIRAUT JACQUES 11959121987021989051288210743.9914MSANS
+6864SCHMITT DENISE 21959 3199201199101 7803 7680.3414.ALLEM
+3805OUEN GERARD 11959 91980061994011471512024.5714MANGL
+7188SOL FRANCOIS 11960101981051991011868714507.4514MTECHN
+7952CABRO MARIE CLAUDE 21960 4199504199304 9126 8456.3314MTECHN
+3834JEANPIERRE FRANCK 11960 21981091987011684813421.4614MSANS
+2909BLERE PHILIPPE 11960 31983041993121326611017.6114MSANS
+8259VALOIS NATHALIE THERESE 21961 2198810198603 8656 8147.0114.SANS
+9506FORESTIERE ANTOINE REMI 11961 719821119811111131 9658.0714MSANS
+5269BIZET JEROME 11961111985041993021433211714.1514MESP
+5031CORBIERES PASCAL 11961 21982121993041326611016.6214MSANS
+0735MONTAIGUET ANNE MARIE 21962 819960619940111389 9850.5614MANGL
+0633BULLY LOUISE 21962 91991121994061202810241.5214MANGL
+7250SERMET XAVIER 11962 41985061986011527112373.0414MANGL
+9656SARRAMEA ANDRE 11962101983081994091868714507.1614MALLEM
+8263MAISONNEUVE MURIEL SOPHIE 2196212199404199301 9597 8727.8714MSANS
+8851BERGES MARTINE 21964 2199406199306 8359 7952.5514MSANS
+7351NUNGESSER PHILIPPE 11964 71988111987112188616680.9314MSANS
+3681LOOZE BRITTA 21964 21993121992011202810240.9114MESP
+1581VALLAGON MURIEL 21964 31986041987091527112374.1214MANGL
+0821BRANLY YVES MARIE 11965 51986011993041288210743.8714CVENTE
+3591MANNA CATHERINE MARGUERITE21965 7199407199307 8359 7952.4314MSANS
+7792INSTIT PHILIPPE 11965 619870719870410407 9271.4114MSANS
+5791RADEGONDE MARIE LOUISE 21966101986041985041168610048.4714MSANS
+0301ESTERELLA ANTOINE PAUL 11967121989021988021450311832.0014CSANS
+1872TOUL FRANCIS 11967 919900419900910407 9271.3814MTECHN
+5651MURIERS CHRISTOPHE 11967 31989101995071249910472.7414CANGL
+0527REMPART DENIS 11967111992071991071330611016.9614MALLEM
+8590TOURNEFORT CHRISTIAN 11968 6199410199508 9126 8456.6614MANGL
+5968PRESBYTERE DOMINIQUE 21968 21992011991011202810241.8414MSANS
+8374AUMALE JACQUES 11968 819890419880410407 9270.6614MSANS
+7416BREGUET DANIEL 11968 21987061993051381911365.2614MSANS
+0198MARINES MARTINE 219691119920419910411389 9852.0214MANGL
+8772GORGE MARC VITTORIO 11969121989091994011249910472.7814MSANS
+9157LEON JEAN CLAUDE 11969 81989061995101249910472.6114MSANS
+3588LUCIEN DANIEL 1196912199403199303 9597 8727.9914MSANS
+5266COUTANT DOMINIQUE 21969 2199502199402 7803 7680.0914MINFOR
+6967CONTI GILLES 11969 9199612199512 7803 7680.6614CSANS
+4277COLLONGES MARTINE 21969 2199112199012 8656 8146.3814.ALLEM
+6780ERIK SABINE 21970 819910619910411389 9850.6214MSANS
+9400LONGCHAMPS MARIE CLAUDE 21970 71990041989041202810241.6714MSANS
+0861ROUMEGONS GERARD 11973 81996101995101288210744.8514CANGL
+1149MOULIN MYRIAM ELISABETH 21974 9199501199401 7803 7681.2514CINFOR
+8134AJOUPA PHILIPPE 11974 3199508199408 7803 7680.5314CANGL
+5009LEVIS FRANCOISE 21974 6199506199406 7803 7679.6914CCOMPT
+5993FROBERT ARN 11975 7199503199403 8359 7951.9414CANGL
+7536ORNE BEATRICE 21976 3199602199511 7803 7680.3214CSANS
+0584LISON PATRICK 1197611199610199510 7803 7679.2814CSANS
+9645TESTE ALAIN YVES 11935 31964091994011557012567.6215MANGL
+4415CROIX GUY 11936 61966081981072022115555.5015MANGL
+2212BAC JEAN PHILIPPE ANDRE 11937 41972051992011433211715.3215MSANS
+9432ULYSSE JEAN MARC 11938 91960121988062947921840.2015MINFOR
+8124CHAMIGNY STEPHANE 11938 2199001198604 8656 8145.1215.SANS
+7324MOLITOR ROMAIN 11938 41962111992032572519240.6415MTECHN
+8862CONDAMINES NICOLE 21938 41960111976012470018540.4715MSANS
+2089ALLEN DIDIER 11939 81972041990011403411520.5715MSANS
+3194COUTURIER DENIS 11939 11963101994011557012568.2615MVENTE
+0835VALMANTE DENIS 11939 21959051991113327724475.7015MINFOR
+8646MESNAY ANNE GENEVIEVE 21939 51967011994091834514275.5215MANGL
+3426GAMBETTA ISABELLE CECILE 21940 7198912198603 8656 8146.0515.COMPT
+0422VAUGAILLERES CHRISTIAN 11940101963111988011663613343.0315MSANS
+0838ORVANNE PATRICK 11940 31962061993082922321683.8515MSANS
+4067OUTREMONT PATRICK 11940 31962031987012022115555.6215MSANS
+0744GRANAGHIU DIDIER 11940 81972021995041834514276.1015MVENTE
+9034TREILLE MARIE JOSE 21940 11962051984062470018540.8215CSANS
+5214BART MICHEL 11940 21964071991072273717261.7615MALLEM
+3460SERENA MARTINE 2194011198810198604 8656 8146.0515.ANGL
+3601MONTJEAN DOMINIQUE 21941 6198805198610 8656 8146.2015.SANS
+9277ELNE LAURENCE COLETTE 21941 31968071990011621213033.3215MSANS
+0325PLATANES CHRISTINE 21942121966081995091834514275.8315DSANS
+9878GAUTIER MARYVONNE 21942121972101989011621213033.2915VCOMPT
+9699GERVAIS JACQUES 11942 11966101992011663613343.4715CSANS
+6148GATINAIS FRANCIS 11943101969101992082470018541.2815MSANS
+4347MONTFRAY CLAUDE 21943 71962121991072273717260.0115MANGL
+4710VIRY GUY 11943 51970051991011433211714.3715MALLEM
+0354BENIGUET MARIE PASCALE 21944 41965021993111471512024.3315MINFOR
+6561LEBAS HELENE 21944 21964071994011932314934.2715SSANS
+1882BARBES JEAN MARC 11945 9199309199209 8656 8145.8915.SANS
+0226FERRIE CLAIRE 21945 4199207199107 8656 8146.7315.SANS
+6166BARGUE FRANCOIS 11946 61972071991101433211715.4515MESP
+9007CLAYE PHILIPPE GERARD 11946 21970041991011433211715.0915MALLEM
+9314GRILLONS MARTINE MONIQUE 21947121969031981122470018542.1015MSANS
+2474RODIN ERIC JACQUES 11947121972121991071621213034.1315MSANS
+0379ARGENSON BERNARD 11947 61971121991082470018541.2915MSANS
+1358SEILLE JEAN PAUL 11947 31971021993061834514274.8915MTECHN
+0628GOURGAUD PHILIPPE 11948 11969051993082666519901.0015MTECHN
+1939DISQUE ERIC 11948 41977031991011578112723.4215CTECHN
+1605FRESNES ALAIN 11948 51975061991011684813422.8115MSANS
+9214CHAMPS BRUNO 11948111973081991013417325098.6515MSANS
+5666NOVEMBRE JEAN PHILIPPE 11949 41971101994013417325097.9315MSANS
+0720MOINES GUY 11950121978011994031471512025.3415MSANS
+8674IMPERIAL JEAN CHRISTIAS 11950 21970041989111932314935.4315MINFOR
+8739HUGO MICHEL 11950 21974041992011578112721.8015MSANS
+9090CYR CATHERINE 21950 7198908198808 8656 8145.3915.SANS
+8528EMERAUDES BERTRAND 11951 61979061992011249910472.0615MSANS
+0912ALBERES MARTHE 21951 41974051991072137316331.3315MTECHN
+1664BENASY DOMINIQUE 2195210197206197106 7252 7486.2815MSANS
+5853ROI CHANTAL 2195210199112199012 8656 8147.0615.SANS
+6634DUMAS BRIGITTE 2195210199509199409 7590 7562.6315MESP
+9376LOUVRE SABINE MARIE 21952 51975051995021433211713.5315MSANS
+8735BYRON MARTINE 21952 51973071991071578112722.0715MALLEM
+1663PLANESTEL CATHERINE 21953 11974101993042017815517.2015CANGL
+5646ALEXANDRE MARIE CLAUDE 21953 11975071991091578112723.4215VSANS
+6614GLYCINES PIERRE 11953 71978101994031471512025.7215MSANS
+8773CLEMENCEAU ROLAND 11953 81974031991012334017609.3715CTECHN
+2191HEBERT PIERRE 11953 21972081992072043315669.2915MSANS
+7378THOMAS PATRICK 11954111982051994011433211715.6315MSANS
+6161HASTIGNAN ANNICK 21954 31980071994041471512025.0115VVENTE
+6895VALETTES ANORE 11955 31979061993121369311288.2415MALLEM
+8499ATHIS JEAN PAUL 11955 11977081976081834514274.8015MSANS
+8271SPORTS PAQUITA 2195612199112199012 8656 8147.0115.ANGL
+3980RAPHAEL MARLENE 21957 61980041979041684813421.6715MINFOR
+9964MUGEL PATRICK 119571119821219820311131 9658.4715MSANS
+0593GRACE JEAN MARC 11957 41977121992021471512024.5615CSANS
+2905EXEMPT PATRICIA 21957 3199201199101 7803 7680.5915.ANGL
+5492PERRIERE PASCAL LUC 11957 11983121994041894014662.7215MSANS
+7685SURMELIN JACQUES 11957 5198109198812 4864 2.1915MSANS
+3608ROOSEVELT FLORENCE 21957121980111994071471512024.5315MTECHN
+5451TULEU JEAN LOUIS 11957111977121994011621213033.1015CSANS
+4681VERIGNON JACQUES 11957 51984051995071433211714.1615CSANS
+1478RESIDENCE CLAUDE GUSTAVE 11958101982091995011433211715.7415MSANS
+0355ROSAIS MICHELINE 21958 81978061992051471512024.1515MANGL
+4981CHRISTOL BRUNO 11958 11978061995041249910473.5415MSANS
+6921MATRA FERNAND 11958 11978051993011471512024.4215MESP
+2956LAPEYRERE PHILIPPE 11958 11977071985102397418037.4715MANGL
+8126CYPRES JACQUES 11958 41983081982081608112917.1515CALLEM
+5587BERENGUIER JEAN PASCAL ROGER 11959 81981061993031894014662.0615MSANS
+2962CAYES CAROLINE 21959 61981051995041433211713.9215MESP
+5994GRASSE PHILIPPE 11959 819820419811211389 9851.6915MALLEM
+0767SOUCHET MARTINE 21959 91983011982011249910471.9215MTECHN
+1353AGEN JEAN MARC 11960 319810319800311131 9657.6515MANGL
+9232GROULLES ANTOINE JEAN 11961 31993101992011249910472.5715MALLEM
+3855BAUMES JEAN LUC 11961 41982111994031527112373.1015MANGL
+9369HELBRONNER VERONIQUE 21961111994031993031202810241.5715MINFOR
+4341OLIVIER CHANTAL 21961 31981101980101684813422.3515MSANS
+5305DAME ANNIE 21961 51981071995071433211715.5915MSANS
+6569GAULLE JEAN CLAUDE 11962 91989041992121249910472.3015MSANS
+6715SEINE KARL 11962 719840219830211131 9657.1215MSANS
+3136GOBELINS JEAN PIERRE 11962 21993091992011249910472.3015MSANS
+5291LAMBERTIANAS MARIE CLAUDE 21962 7199506199406 9126 8457.5615DSANS
+6342MISSECLE DIDIER 11963 41989111988111539912453.6015MSANS
+3447VIAL GEORGES 11963 51985041984111527112374.3415MALLEM
+5045GRAZAILLES LAURE 21963 8199108199008 8656 8146.9715.INFOR
+7974CHAUSSEE PAUL 11963 61985071991121288210743.9215MSANS
+2189PEYBERT DIDIER 11963 81983081988112090215980.4615MSANS
+7262JOZE PATRICK JEAN 11963 91983111982111326611017.4115MSANS
+8222ETANG LIONEL 11963 71985011993031693613497.9015MSANS
+6881OUEST OLIVIER 119631219840419840210791 9502.0815MSANS
+8121MADELEINE JEAN 11964101984071983121288210745.1815CESP
+6828CONCY JEAN MICHEL 11964 91988041994091693613499.2215MALLEM
+3939CHURCHILL BRIGITTE 21964101992021991021330611016.6015MSANS
+5116PEREIRE DIDIER PAUL 11964 21986071992121288210745.9915MSANS
+2174TEISSEIRE ELFRIEDE 21964 4199212199112 8656 8145.5615.ANGL
+0585CRETS LAURENCE 21965 3199306199209 9597 8728.8415MSANS
+7988DOMAINE PASCAL 11965 61984051993071527112372.8715MSANS
+1646PERDRIX MARCELINE 21965 51985101984101288210745.7015MSANS
+7090KERAVEL GILBERT 11965 11988041994091693613498.2215MSANS
+3100BARILLERIE BRUNO 11965121988111987112188616679.7215MALLEM
+8075ESCALE YOKO 21965 61991061990061381911365.3215MSANS
+1009CHARRIERE SYLVAIN 11965101993021993121249910473.1115MSANS
+8542MOLIERE PIERRE 11965 51987111995021450311830.6215MSANS
+8729ROSTAND PIERRE 119661219860419850410791 9503.7015MANGL
+8802DOUMER JEAN LOUIS 11966 619860319930110791 9502.8415MINFOR
+8596ABEBERRY PATRICK 11966 619891119910910407 9270.2415MALLEM
+6485CHALEUTRE GILBERT 119661219870719860710407 9271.9715MTECHN
+9054FAURE FRANCIS 11966 519860719890710791 9503.7915MALLEM
+6168CHENEAUX COLETTE 21966 61994021992011202810240.1915MSANS
+9809PESSOT JEAN JACQUES 11966 11992011991011202810241.3015CALLEM
+8041BIGUE THIERRY ALAIN 11966 619860419850410791 9503.8515CCOMPT
+7730CALIANES STEPHANE JEAN 11967 3199404199304 9894 8921.6315CSANS
+2161TOUCH MICHELE 21967 11989111988111949415052.4015MSANS
+1999LISLE GILLES 11967111990021989021539912451.6115MMICRO
+2038GRANDES ROGER 11968 2199312199212 9597 8728.0115CSANS
+4888BELMONTET ANN 21968 619960419950410668 9426.5315MSANS
+5809ROUSSIER DENIS 11968111990011989011467711987.1615CSANS
+0146ROSESCERNY MIREILLE 21968 5199602199502 8656 8145.5715MANGL
+3432GARCIA PHILIPPE 11968 51990121992041249910471.8915CSANS
+3058SANGRIA CAROLINE 219691119910519900510024 8998.6815MANGL
+7679BLEU CHRISTIANE 2196911199207199107 8656 8146.3815.SANS
+0602VAUGINES GILBERT CHRISTIAN 11969 91991061994011249910471.7615CCOMPT
+5226BOULEE PHILIPPE 11969 819900419890410407 9271.7215CSANS
+5904ORANGERIE MARIE CHRISTINE 21969 1199001198712 8656 8146.0115.ALLEM
+8131NICE CHANTAL 21969 41989031990011450311831.6615CTECHN
+8570SOULAGE MICHEL 11969 41989091994031330611016.4415MVENTE
+5857ALLEE JACQUES 11969 7199304199206 9597 8728.9515MANGL
+6920LOTI YVES 11969 919911219901210024 8999.3115CVENTE
+3599PLANA JEAN PIERRE 11970 61991051990051467711987.6115MALLEM
+7579BERGUEROLLES MARIE CLAIRE 219701219910919900911389 9852.4115MSANS
+0494DESBORDES BERNARD 1197012199101199001 8656 8145.1215.SANS
+9496MONTBAURON ERIC 11970 61991051990051467711986.2215MSANS
+8603DESCENTE FRANCOISE 21971 5199607199507 7803 7680.9915MSANS
+2449TAHITIAA MIE 21971 619940919930810668 9425.5515MSANS
+7786LOUP ISABELLE 21971 61991121993041202810240.8915MANGL
+6100MARNE JOEL 119711219940719940111389 9851.4615MSANS
+8569ASPIRAN ANDRE 11971 61991121994011249910472.8415MSANS
+0626ODET PAULE 21971 2199611199511 7803 7681.0415MSANS
+7006ARGENCE PHILIPPE 1197212199308199208 9597 8728.2215CANGL
+2516MAILHEAUX LAURENT 11972 41991121991061202810241.5215CSANS
+4928COLLEDEBOEUF ANNE MARIE THERESE 21973 51994071993071206910240.6415MANGL
+1718HACHETTE ERIC 11974 7199606199506 7803 7679.4615CALLEM
+5240MUSES JEAN BERNARD 11974 9199507199407 9894 8922.4415CANGL
+3654MAIRIE MARIE 2197412199507199407 7803 7680.6315CSANS
+3017BAUCHAT MICHELE 21975 8199505199405 8359 7952.4615MSANS
+1395BROSSOLETTE MARIANNE 21975 4199609199509 7803 7679.7615CESP
+9154REYNARDE FREDERIC JEAN 11975 8199406199306 7803 7680.3415CANGL
+3041BOYER ERIC 11975 3199406199306 7803 7679.3315CSANS
+8817FILOURIE FRANCOISE RENEE 21976 8199506199406 7803 7679.3615CANGL
+3408BRIE BRUNO 1197611199508199408 7803 7679.4515CSANS
+6446WYLLIE PATRICK 11976 1199507199407 7803 7679.4915CSANS
+7476SOMME BEATRICE 21976 4199606199506 7803 7680.8615CSANS
+8951BARNIER MARTINE 2197612199506199406 7803 7679.4915CTECHN
+5707FOCH DENIS 11977 7199607199507 7803 7679.3615CCOMPT
+9331PEYPIN MICHEL 11977 3199506199406 7803 7681.2015CALLEM
+2044RENAN BERNARD 11977 7199607199507 7803 7679.9915CSANS
+0991GUTENBERG BERNADETTE MARCELLE 21930 6199207199107 9894 8922.1616MANGL
+4650NORD PASCALE 21930 6199001199506 8827 8262.8016.SANS
+7670BOURG ERIC 11935 11967071994011433211713.8816MCOMPT
+1067ITALIE SVETLANA 11935 81973071991011433211713.6116MSANS
+7446BELMONT MARIE JEANNE 21936 4199010198910 8656 8145.0316.ANGL
+4567VICTORET DOMINIQUE 11936 2198812198511 8656 8146.6116.ALLEM
+1382ARIES DOMINIQUE 11936 11970081991041433211713.8816MANGL
+7727TERRASSES BERNARD JACQUES 11936 91957051994123417325096.9816MALLEM
+2304MERCUES JACQUES ANDRE 11936101955061992113327724476.7316MSANS
+1717FEUILLETS EDITH 21936 51971091992021932314935.3116MSANS
+5274VALLEES PASCALE 21937 8198901198511 8656 8145.6216.INFOR
+1751BESSE WILLIAM 11937101959021994065760041273.7516MSANS
+7544TRAIL PATRICK 11938 41971081991101433211714.7916MINFOR
+0247VIARD CHRISTIAN 11938 11962121984073200223583.9016MTECHN
+9383CHALONNIERE MARIA 21938 4199009198909 8656 8147.1916.SANS
+1762EMERAUDE BRIGITTE 21938 11975051995011369311288.0616VESP
+8379MAGNIOUX NADINE CHRISTINE 21938 81966071990071578112723.4716CTECHN
+4635CYTHERE CORINNE CHARLINE 21939 4199201199101 9085 8418.3916MANGL
+2414PILATTE MARIE JEANNE 21939 11962051983032470018540.4716CSANS
+9003MOULIN DIDIER PAUL 11939 51980021995121471512025.3716MINFOR
+6102MARINVILLE ERIC ANDRE 11939 21971031991101433211714.6416VANGL
+9945ELANCOURT AGNES 219401119841019810111131 9658.0916CVENTE
+5615THORELLE FRANCOIS BERNARD 11940 219840119840311131 9658.6416MALLEM
+9231HERBILLON MADELEINE 21941 11968071990071578112722.1216MSANS
+9547REMY CATHERINE 21941 31965121990012273717261.0916MTECHN
+8538DAMPMART THIERRY 11941 41964071994013200223582.7616MSANS
+4432ECOLE CLAUDE 11941121966071995041557012566.5416MALLEM
+7122SORRIERES JACKY 11941111975031992011403411520.6216MSANS
+5855CESARI PHILIPPE 11941 41972081992011433211715.6916MSANS
+4569BELTCAGUY JEAN PIERRE 11941 31974041991011369311288.0016MSANS
+0119BAUMETTES VONICK 21942 7199309199209 8656 8146.7316.SANS
+5799ICARD JACQUELINE 21942 31968071994031834514275.4316VTECHN
+3230NIBELLE PHILIPPE 11942101963011990042273717261.8816MTECHN
+1160PLAY JEAN DANIEL 11942 81975091993041369311287.9716MSANS
+8701ORRIANES DIDIER 11942 81964101989122470018540.0616MTECHN
+9211ANJOU JEAN CLAUDE 11943 81969101991011433211715.4716MSANS
+2069CHURCHILL ANDREA 11943 61970061995042201216756.8916MINFOR
+4457ARBAUD JEAN CLAUDE 11944 61971011992102137316332.3116MSANS
+9480SABLONNIERES CAROLINE 21944 11962121991072273717261.7616MALLEM
+1573HOCHET HELENE 2194410199208199108 8656 8145.3416.ESP
+8504ANDRE FRANCOISE 2194510199301199201 8656 8145.4216.SANS
+2608THIRD ALFRED 11945 91971041990012137316331.6616CSANS
+0698CEDRES BRUNEL 11945 91968061990071433211714.3916MSANS
+8224CLOSERIE MARTINE 21945 61971061991101932314935.2616VTECHN
+6798MONTESPAN JEAN NOEL 11946 21983121993011215710278.5716MTECHN
+4449TRAW ALAIN 11946 21976091993041369311287.8216MSANS
+1458BOIZEAU PHILIPPE 11947 11973071993041518612334.9216MANGL
+8853OUF HENRIETTE 21948 91970011994062201216756.8016MALLEM
+0743GEORGE BERNARD ALAIN 11948111973021991011433211714.9316DALLEM
+2218GEMEAUX GUILLAUME 11949 51970101992072739020404.5916MSANS
+3154MONTAGNE SERGE 11949 31973061992011403411522.1316MSANS
+2871VILLERMONT EVELYNE 21949111970061993102175716601.0116MINFOR
+8174SARDAN PATRICK 11950 61978051990091966515206.0716MANGL
+5180LONE ALAIN 11950 31978021994011369311287.4616MANGL
+7155COSSON DOMINIQUE 11950 41970101991012990722150.5216MANGL
+7616QUAI FRANCOISE 21951 51973101991071578112723.5116MSANS
+1943VAUGIRARD DANIELLE 21951 7198810198709 8656 8145.3916.SANS
+8270LOUPS CHRISTIAN 11951111979031993011471512024.3816MALLEM
+2654PRESSENS ANNE MARIE 21951 31973011976011288210745.5416MINFOR
+8175COUDOURON LUC 11952 21978061995011249910472.6616MSANS
+9368DOLMENS CLAUDE 11953 81977081991071578112723.3816MSANS
+3828ESTIENNE PATRICK XUAN VINH 11953 71984071992041326611016.1116MINFOR
+8961APPART JEAN LUC 11953101973021992102017815516.1216MSANS
+9113PERIGUEUX JOELLE 21953 21973101991071578112723.0616MINFOR
+7735FLEZ PIERRE 11953 11978071994011403411521.0216MINFOR
+4018FONTMERLE MICHELINE 21953 8199311199211 8656 8146.9516.SANS
+5157GREZ FRANCIS 11953111974051992082350617725.9216MTECHN
+5311SUFFREN MARIA 21953 41973021990101578112722.9116MANGL
+7764BRON CLAUDE 11953 91979081994011249910472.9216MINFOR
+0120POSTAL CHRISTIAN 11954 31976071994011369311288.1516MSANS
+5265HUGO JEAN 11954 51975021993092256617146.9116MSANS
+5590SOPHIE SUZEL 219541119960119940110668 9425.3116VSANS
+5401LARREY MONIQUE 21954 31975041995101881314585.7316MSANS
+6562LANTERNE CLAUDE 11955121980061995041471512024.3516MANGL
+1519GOURDON SYLVAIN 11955 51980051995011249910472.9716MVENTE
+3963RUISSATEL MICHEL 11955 51979051994011249910473.2216MSANS
+3870COMMANDERIE BERNARD 119561219850419870910791 9503.3616MANGL
+6506SUPERIEUR JEAN CLAUDE 11956 31979011994011249910472.3016MINFOR
+0863FIGUIERES JEAN PIERRE 119561219890919881210407 9270.6216MSANS
+1566GROS ANDRE 11956 419950119950110363 9232.9816MSANS
+2124CHASSEURS AUDE 21957 219920619930110024 8997.9516MINFOR
+5594VAAGGASSE CLAUDE 11958 71978051992011471512024.3916MALLEM
+7033TITAN ERIC 11958 41978011992021471512025.2516MSANS
+5186CEYRESTE JEAN 11958 91980091993041471512024.7116MSANS
+7174SEPTEMBRE PIERRE 11958121978081995071369311286.1516MSANS
+4207REGARD GINA 21958 1199107199007 8656 8146.5216.SANS
+0723GARDONNE SIMONE 21958 21989081991101249910473.2416MALLEM
+3190MONTAUROUX FRANCINE 21959 61989011991071249910473.4116MINFOR
+7379SUD PHILIPPE 11959 81982051992011527112374.2216MALLEM
+0598FERBER GUILLAUME 11959101981051995082256617146.9116MINFOR
+6321CEZANNE ALAIN 11960 41984041993041326611016.0616MSANS
+6273FONVERT MARC 11961 619901019891010407 9271.5916MSANS
+6867GENEVE ANNE MARIE 21961 31983011982011608112916.2516MSANS
+7828PUISEAUX BERNARD 11961 5199403199303 9597 8728.1416MSANS
+7252CHEM MARC 11962 41986091992041949415052.0616MSANS
+0052TEMPLIERS CATHERINE 21962 61982021989041608112916.9716MSANS
+4660HAROUSTA PHILIPPE 119621119900119890110024 8998.9516MVENTE
+3619MURAT PIERRE 1196212199406199306 9126 8455.9716MINFOR
+1366REINE GEORGES 11962 5199606199506 9126 8456.6416LSANS
+6020YVART ELISABETH 21962121994051992011202810241.1616MANGL
+9740SEJOUR DANIEL 11962 81982121992041326611017.0516MSANS
+3790BEAURONNE PAUL 11963 419840619830610791 9502.6816DSANS
+0831VICTOR MICHELE 21963 11985121984121288210744.4116MSANS
+5171NEIGE DANY 21963 21985051984051527112372.9916CSANS
+4834CROIX CLAUDINE 2196310199101198807 8656 8145.0616.SANS
+9575HILL DOMINIQUE 21963 319951219941211389 9852.5416MSANS
+1494FECAMP DANIEL 11963 31991041990041381911366.6116MSANS
+2944MONCET THIERRY 11963 91991081992051249910471.9416MCOMPT
+8018DRAGON XAVIER 119631019830519820510791 9503.5216CCOMPT
+7258CASTELLAS LAURENT MARC 11964 31984091992121288210745.9316MSANS
+3956CORDIERS PHILIP 11964 219861019851010791 9503.0416MSANS
+1434TRESPOEY HENRI NICOLA 11964101987041991091450311831.5216MTECHN
+7725MASSANE LAURENT ALEXANDRE 11964 819850919840910791 9503.9916MALLEM
+5509FLAMANTS OLIVIER 11964 219890519880510407 9271.8216CSANS
+9732VENT THIERRY 11964 91987071988121288210744.9116MALLEM
+8053CAUSSINIERO ANNY 21965 8199610199510 7803 7680.3216MANGL
+8933CHOPIN VERONIQUE 21965101986061994091288210744.0816MANGL
+4294GRAVIER PHILIPPE ARTHUR 11965 61994041992011202810240.0416MTECHN
+7996LOUPIATS CATHERINE 21965 3199312199212 9597 8728.5816CSANS
+5751DIMANCHES JEAN FRANCOIS ROLAND1196511199404199201 9597 8727.9916CSANS
+3314COPERNIC NATHALIE 11965 91993111992011202810239.8316MALLEM
+8095MALIKA ESMERALDA 21966111994051992011202810241.6116MINFOR
+2514CANGINA MARIE CLAUDE 21966 519951219941210668 9426.3416MANGL
+8137BARBE SOPHIE 21966 61985061984061202810241.6116MSANS
+2086FELIBIEN GILBERT PIERRE 11966 619860919850910407 9270.8916MINFOR
+5743FOUESNAN PHILIPPE 11966101987021991071288210745.4316MANGL
+7755ALGLAIS BERNARD 11966 81989031988031249910473.3616MVENTE
+4183NEUVICQ MARIE CLAUDE 219661119950119930411389 9851.0116MSANS
+5854BINEAU BRUNO DANIEL 11967 51991081990082107316097.0316MSANS
+1015HUSSON MICHEL 11967 31990041989041467711985.8116MINFOR
+8894VEGA YANNICK 11967 1199311199211 9597 8729.4016CSANS
+2165POMONE EVELYNE 21967111989031993071381911366.4716CSANS
+3736LYS DIDIER 11968 919950119950110363 9232.6616CSANS
+9047PUITS VINCENT 11968 21990081989081539912453.7216CSANS
+6745COMMANDANT DOMINIQUE 21968 6199403199303 8656 8146.3216MANGL
+2664JAMES CHANTAL 21968 719940419920111389 9851.5216CSANS
+2387LECLERC BERNARD 11968 819950119950110363 9233.9016MSANS
+8096PAROISSE DOMINIQUE 21969 61991091991021330611016.5116MTECHN
+8708BOISSY BERNADETTE 21969 7199006198708 8656 8145.2116.SANS
+7358CUQUERON MARTINE 21969121994031992011202810240.4616CSANS
+5192BESSOU ROSINE 21969101991111990111839014314.0816MSANS
+1422LAVAUX DOMINIQUE 21969 11992061991061202810240.9816CSANS
+4798IDOLE MARIE CHRISTINE 21969 219930419920411389 9852.1516MSANS
+7101NOGENTAIS CHRISTINE 21969 91989111988111202810240.5916MSANS
+3573MIRBEL ANTONIO 119691019900519890510024 8999.4916CSANS
+8187NORD ROBERT 11969101991101990101467711987.9716MVENTE
+2888CASTELS YVONNE 21970 419960619940110668 9426.8916MSANS
+5902GARRIGUE MICHELE 21970 21994021992011202810241.7616MSANS
+7139BRUANT ISABELLE 21970 919940619920111389 9852.0916MSANS
+8561FREGATE DOMINIQUE 11970 81993041995091267210590.1516LSANS
+8391ESCOURADIERES CHRISTOPHE 11970111991111990111467711986.0816CSANS
+7113FLAVIEN MICHEL 11970 91992121991121467711987.9416MSANS
+1139CHAMPIGNY LIONEL 11970 11995031993041202810241.7416MANGL
+3774FAHNESTOCK MAX 11970 11992101991101467711987.9016MSANS
+3115MAGATIS PIERRE 11971 119960219950211389 9851.0316CSANS
+7606ITALIE JACQUES 11971 4199407199307 7803 7679.4516CVENTE
+2804JOYEUX FRANCIS 11971 21990061992121202810241.0416CSANS
+5659HOULE PATRICK 11971 21993121992121420611637.3316MESP
+9687LANCIERS DANIEL PHILIPPE 11971 8199311199211 9597 8727.9016CANGL
+5871LACOURTADE PHILIPPE 11972 11991121994011249910472.6116CVENTE
+4676LUPINO ATSUKO 21972 6199501199401 8656 8146.1416MTECHN
+2981VIREBELLE FRANCOISE 21972 219940819930810668 9426.5716CSANS
+1979LOMBARDS JEAN DIDIE 11973 6199309199209 9597 8729.0716CSANS
+7372BOIS MONIQUE 21973 1199407199307 7803 7681.1116CSANS
+3844PERIGORD NICOLE 21973 319930919920911389 9850.5616CSANS
+0819THOBIE DANIELLE 21974 1199409199309 8359 7952.6116CALLEM
+8257SEVIN CLAUDINE 21974 4199409199309 8359 7951.8816CSANS
+5832DELAGRANGE MICHELE 21974 3199309199209 9597 8728.8216MSANS
+6357MORTARIEU MARIE JEANNE 21974 8199607199507 9894 8921.8516CSANS
+7800TOURNELLES FLORENCE JACQUELINE 21974 519950119940110668 9426.0016MSANS
+1978CENIS ALAIN 11974 71994091994011202810240.8616CSANS
+4208BEAU OLIVIER 11975 8199510199502 8359 7951.6616CTECHN
+2472TOWERS CORINNE 2197511199410199310 8359 7953.1116CTECHN
+8054QUINTA PASCAL 11975 4199606199506 7803 7680.5016CSANS
+5910JARRY CLAIRE 21976 1199608199508 7803 7680.6616CVENTE
+9513GENISSIEUX HERVE 1197612199607199507 7803 7680.0016CSANS
+6334MUSSET MARIE PIERRE 21977 3199607199507 7803 7681.4716CSANS
+3177VILLEFRANCHE NICOLE 21977 7199607199507 7803 7680.4416CESP
+3707PREVOST CLAUDIA 11934 81963071994011663613343.7817MANGL
+7266OUCHE JEAN LOUIS 119351019930919910110407 9272.2217CSANS
+5677VIRGINIE JEAN PHILIPPE 11938 51963111989071663613342.9817MESP
+0564PEYREBELLE JOELLE 21939 11967011989091932314934.5317MSANS
+6752SILLERY PIERRE 11941 41962061985072273717260.5917MSANS
+7389BILLOUX NATHALIE 21941 3199012198912 8656 8145.3317.SANS
+0440MALASSIS EVELYNE 21942 11993101992011202810240.7217DSANS
+6527CURSON JEAN LOUIS 11946 71974121991011369311287.1017MANGL
+4166EVIAN FRANCOIS 11946 31969101986012470018540.6117MSANS
+6635ROSAY FABRICE EUGENE 11946 71970031989122334017609.4317MANGL
+3999MUSARDIERE CLAIRE 21946 81968111983042470018540.9317VALLEM
+9845YVETTE MARTINE 21947 71972101990071621213032.1717MANGL
+1439FIEF EVELYNE 21947 91974071991071578112723.1817MSANS
+2404ROME BRUNO 11947 91988031995011433211715.0917CSANS
+8776ROME THIERRY 11948 61974011995031911114779.7717MSANS
+5946TERRA MARIE CHRISTINE 21950 91970011991071578112723.6817MSANS
+5232DEBUSSY CATHERINE 21951 81973051991021684813421.7217MTECHN
+0869CARAMEL ELIANE 2195211199207199107 8656 8146.0917.SANS
+1911PLASSAN THIERRY 11954 41980031992031608112916.5917MTECHN
+1670LORETOHOHE MARIE EDITH 21954 11974071993101911114780.0617MANGL
+9187BINGER DOMINIQUE 21955121986091991041249910471.9217DESP
+2614COLLONGUE MARCEL 119561019810319820611389 9852.2917MANGL
+9658BEAUREPAIRE MICHELE 21957 81977071992011471512025.4717MSANS
+1305HOPITAL DOMINIQUE 21957121979071980041684813421.6717CSANS
+2762PELUT PIERRE YVES 11958 119881219871210407 9271.4117MALLEM
+4217ALEXANDRA JEAN MICHEL 11958 71983031993081326611017.7417CTECHN
+8469CRETES PAULETTE 21959 619910719900710024 8999.3117MANGL
+1495RIBAUTE PIERRE LAURENT 11959 119801019820611389 9850.8817MINFOR
+1650BRIAND SYLVIE 21959 91980041992121608112915.9217MSANS
+8360JOUY CLAUDIE MARIE 21959 319940419920111389 9852.7417MSANS
+5653ROLL ROBERT 11959111988061991091450311830.5617MINFOR
+4042TANE PHILIPPE 119591019870719890410791 9503.7017MANGL
+0940YVETTE MICHEL 11959 31978071991032022115555.5017CTECHN
+9875DANREMONT THIERRY 11961 41982091995041433211714.5117MTECHN
+9667CASITA JEAN LUC 11961 81982081995121638413150.9717MSANS
+1371ROME MAURICE 11962 21984051995081710713577.9317MSANS
+6755AUBAIS BRIGITTE 21962121983011993051527112374.0017MTECHN
+2907BRETEUIL FREDERIC VALERY 11962 41993021993081202810241.7217MSANS
+4530MICHAUDES CHRISTINE 21963 11982071981071326611017.7417CSANS
+9935TAZARKA BERNARD 11963 91992111991111330611016.2617MSANS
+1813PLOUGUIE DANIEL 11964 21985081989051288210745.8117MTECHN
+2666DAUX JACQUES ANTOINE 119641219840119830110791 9503.3917CANGL
+4498LOUVEAUCOURT MICHEL 11965 81985061988061288210744.9117MSANS
+6274BRIE PIERRE 11965 21984071983071288210745.4317MANGL
+8475PATHE LOUIS 11966 91987111993091839014314.3417MSANS
+2923LACLOTTE NADINE 2196610199501199304 9597 8728.7217CTECHN
+5049CROZES CAROLE 21966 71987021992011450311832.6817CMANAG
+9666RABINES MICHEL 11966 81986071995121450311832.3617MTECHN
+1503LESTRADE GILLES 11967 119870119860110407 9272.1917MINFOR
+2577JONCQUIERES MARCUS 11967 61987041990091249910471.6517MANGL
+6372VILLARS LYDIE 21967 3199411199311 7803 7680.5917MANGL
+8399HAMEAUX BERNARD 11968 61990071991081249910473.2417MSANS
+0624BLOY MICHELINE 219681219940619930610668 9427.0217MANGL
+0069ARTHUR CLAUDE 11968 71989021993041249910472.5717MTECHN
+9429MATIN FRANCOIS 11969 919890419890410407 9271.0217MANGL
+6364LEONIE SERGE 11969 919900319890310024 8998.4117MSANS
+3990SALANGANE CATHERINE 21970 619950919940110668 9426.0017CALLEM
+9447AYGULF CHANTAL 21970 419950219930411389 9851.1617MSANS
+5807CIMES ODILE 21970 1199404199304 9126 8457.6317MINFOR
+6551FOUCHER CHRISTIAN 11970 81990081989081202810240.2617MSANS
+9323SAUVAGERIE MARCEL 11970 7199512199412 9126 8457.5917MSANS
+0265PEYRIERE YVES 11970 91990111989111381911366.7217CTECHN
+8683BRUSE VERONIQUE MARIE PAUL21971 119960119950111389 9851.9717CCOMPT
+4051CHANTILLY PATRICK 11971 8199602199502 7803 7681.2017CINFOR
+5145ETHORRI BERNARD 11971 9199309199209 9597 8729.2517MSANS
+2756CADDESI THIERRY SERGE 11971 919910719900710024 8998.0117MSANS
+5810HAUT CAROLE 2197212199610199510 8656 8146.9517MESP
+1266GAUTIER VIRGINIE SOPHIE 21972 1199603199503 9894 8923.0217MSANS
+8948CLOUD RICHARD 11972 81991071992041202810239.8317CSANS
+4395DELIBES ERIC 11972 619940219930211389 9852.6917MESP
+9450DAMMARTIN YVES 11972 6199404199304 9597 8729.4517MSANS
+4403MORTIERS BERNARD 11972 219910919900910024 8999.0917MANGL
+1227ROSSAT MICHEL RENE 1197212199407199201 9597 8728.3517CINFOR
+8746VERGER JACQUES 11972 519940219930211389 9851.0117MCOMPT
+9344ECHEZ CLAUDE 11973 9199505199405 9126 8456.2417CSANS
+4420CASA ALAIN JEAN CLAUDE 11973 319930719941111389 9851.8417CSANS
+2752BEAUTE PATRICK 119731219930419920411389 9851.7417MSANS
+0850MULON GERARD 11974 619940919940110668 9425.6717MCOMPT
+2641ESCURIAL JEAN FRANCOIS 11974 3199606199506 7803 7679.5117CTECHN
+2955MALETACHE GENEVIEVE 21974 9199508199408 7803 7680.9817MSANS
+5801COSTES NOEL 11975 8199609199509 9894 8921.3117CSANS
+2146DAUMIER IGINIO 11975 4199310199210 8359 7951.7917.ALLEM
+3984OR GISELE 21975 9199607199507 7803 7679.6717CANGL
+9050GIRAULT LILIANE 21975 5199406199306 8359 7952.9617MSANS
+3948SEIN FREDERIC 1197511199410199310 8359 7953.3217CSANS
+4265MIGNET BERNARD 11976 5199507199407 7803 7679.7817CANGL
+0351RIMBAUD JEAN PAUL 11976 619961219951211389 9852.3617CSANS
+1931BERGERAC DIDIER 11933 3198810199501 8656 8146.3218.SANS
+9698SCHUMAN DOMINIQUE JEAN 11935 71968101995041557012568.3518MANGL
+2020JOLY PIERRE 11935 119870719900710791 9503.6618CSANS
+7058BARGE REMI 11935121955021980013327724475.6718MTECHN
+3747MARIES RENE 11935 51955021988013844228044.8418MSANS
+3141VALLONGUE GUY 11936101976071991011433211715.2418MINFOR
+1098CACTU CATHERINE 21936 41962111991072273717261.7218MINFOR
+9199PLOUHARNEL BERNADETTE 21936 21967011989102273717261.0418DINFOR
+9270ABBE SOPHIE 21937 71968061991041932314934.4118MSANS
+2969BEDOYERE GUY 11937 7199001198412 8656 8146.6418.TECHN
+1219HOCHE JEAN MAURICE 11938 51969051990011433211714.1218MANGL
+1887TOURNON GILLES 11938 51967051990011433211714.1918MANGL
+5417AMBREVILLE FRANCE 21938 51973071990071578112721.7618VSANS
+1954SOPROCOM PATRICK 11938 71973101992011403411522.1318MSANS
+0028ROLE PHILIPPE 11939 81963111994011557012567.1418MSANS
+6857KERPADIRAC EMMANUEL CLAUDE 11939 71965051990011433211714.6418MANGL
+3697PEYRUIS BRIGITTE 21939 81962061991021834514276.0918MSANS
+5636SAVE RENE 11940 21969061991101433211714.1918MSANS
+5290VIALE PHILIPPE 11940 11974071991011369311286.8418CINFOR
+2591COLLE FLORENCE 21940 3199207199107 8656 8146.5218.SANS
+7651GOZLAN XAVIER JEAN 11940 41960031993033200223582.7318MSANS
+8388MONTROUGE LOIK 11940121974071992011403411520.2018MTECHN
+3384LIVRON FRANCOISE 21940 71964071992072273717261.1818VSANS
+7291MARLY MARTINE 2194010199206199106 8656 8145.8318.INFOR
+2644EAU FRANCIS 11941 11968121990011433211713.5818MSANS
+0515WRIGHT PHILIPPE 11941 21973061992041403411520.2118MSANS
+1243SEMAPHORE ANDRE 11941 71969111986072470018540.5618MTECHN
+1791PASTEUR BRIGITTE 21941 61974101992011578112722.8818MTECHN
+1226SAUD JEAN PIERRE 11941 91973081995011621213034.1018MANGL
+3874PASSERINES DOMINIQUE 21941 61966021992042273717260.5318MANGL
+5394QUAY YVES 11941 91973041990101684813421.4518MANGL
+0308BELLIVIER MICHEL 11941 21963091988043417325098.6318MSANS
+8445HEROS SYLVIE 21942121963091991082470018540.5318MSANS
+7703CERF NICOLE 21942 51978071992121471512025.6118MSANS
+3807REBAIS FRANCOISE MICHELE 21942 31972041989011621213032.7018CSANS
+5173TARCO MARC 11943 51973051993011369311286.4718MSANS
+3544RESTANQUES SERGE 11943111971121990011433211713.8018MVENTE
+7289FRAMBOISIERE DANIELE 21943 51969071991011578112721.6718CALLEM
+2761WYLLIE ANNIE 21944 41963121985051932314935.2918MSANS
+7593AMPHORE BERNARD 11944 71964101989062922321684.7218MANGL
+7373PAMPERIGOUSTE MICHEL 11944 21972101992011403411521.3418MSANS
+1159PATIOS ELISABETH 21944 91970101991101932314935.2618MSANS
+6999BEL ALAIN 11945121969101990011433211714.7918MSANS
+7962VIGIE MICHEL 11945 91971071994122295317300.3718MTECHN
+3123GAULLE ERIC NOEL 11945 51973121991082470018540.6918MMARKT
+9943DOUMER PATRICK 11945 51968041990071433211715.1118MSANS
+3765IMPERATORS GHALIA 21945 61965021993102137316332.1118MSANS
+6688COULOUNIEIX HERVE JEAN MARIE 11945 61971031991062273717260.7718MSANS
+0965JUDITH BERNARD 11945 51966051987122470018542.2418MINFOR
+3763MERMOLLOD DANIEL 11945 21972071992011433211713.5318MSANS
+0042POUTGE PHILIPPE 11945 81968081990101433211715.7218MSANS
+2250JACQUIN JOEL 11946 41971071991102022115556.3818MSANS
+7112REDOURTIERE VERONIQUE 21947 3199303199203 7677 7603.7718.ANGL
+5217SARRAZINIERE MICHELE 21947 51968111991102137316330.6718MINFOR
+1448MAUPASSANT PHILIPPE 11947111968121988102273717260.8118MSANS
+7506CLAP JEAN JACQUES 11947101968061986042470018540.8918MSANS
+5237JAS MICHEL 11948 21975101993121369311287.1918MSANS
+0341MAKILA NICOLE 21948 2198901198510 8656 8145.1118.ESP
+3475REMISE MARIE CLAUDE 21948 41968041989042273717260.3218CSANS
+3575DONAT JEAN MARC 11948 51972121991011621213033.6418MINFOR
+0433CAROUBIER PHILIPPE GABRIEL 11948 5198801198306 8656 8146.1618.ANGL
+9184PINEUILH CATHERINE JEANNE 21948 11968091967091493112142.5618MSANS
+1377KERCOLIN ALAIN 11948 91972061992112137316331.4718MSANS
+7248MERCIER FRANCOIS 21948 71970071993121834514275.1418MSANS
+9014FELOUQUE JEAN LOUP 11948101972121994011621213032.9718MCOMPT
+1756FREMICOURT DOMINIQUE 11949 81969121989111932314933.9918MANGL
+7383BLAISON FRANCOISE MARIE 21949111970071994031834514275.1618MALLEM
+6290TILLEULS BERNARD 11949 61971041990123417325098.1518MINFOR
+2226VIVO DOMINIQUE 21949 41971101995041834514275.6118MTECHN
+8441SARGIS CLAUDE 21949 11973061993082175716601.4318MINFOR
+1520PIC JEAN JACQUES 11949 11975041992041403411521.8618MSANS
+5696DRUGEON PATRICE 11949 81980071995041249910473.1818MANGL
+1048MORIZET ANNE 21950 11970121994051834514274.8318MSANS
+4058FRANCE ALAIN 11950101974091991071578112722.6118MMANAG
+0512MARBO JOSIANE 21950 71972011992102017815517.3818MANGL
+2797GUY LIONEL GILLES 11951 51976051993071894014662.5918MSANS
+9267SAUSSIERE MARC 11951111972041992102017815516.2418MSANS
+6865EMMANUELLA ALAIN 11951 51982041993011369311287.7418MSANS
+0116GALICIE FRANCOISE GEORGETTE 21951 41971101992011471512024.0618MANGL
+6144ROSERAIE DOMINIQUE THIERRY 11951 91972081992112739020404.7018MANGL
+9941JULIETTE CHRISTIANE 21952 71976091992011578112721.6518MANGL
+1879CLAIRVAUX JEAN SYLVAIN 11952 31976041993011369311287.4318MALLEM
+9577PECHEURS DOMINIQUE 11953 31978031995011578112723.3318MSANS
+4352BAR REGIS 11953 71979061994011249910473.4518CSANS
+2194EVIAN DANIEL 11953 81977061992011608112915.1218MANGL
+0566PARADISIER DIDIER 11953 11983111993011215710278.3018MANGL
+8627CHARRIERES PHILIPPE 11954 61974111982102470018540.8018MSANS
+5729BRECHET PHILIPPE EMMANUEL 11954 41974081991012137316331.2818MINFOR
+3643RONSARD PATRICIA 21954121976011982052256617146.4518MSANS
+1486AGEN CAROLE 21954 91977071984112256617147.1818MANGL
+4779CALIFORNIE PATRICE 11955 31975051991101578112723.3318MSANS
+0975BIEVRES ALAIN 11955 61978101993011471512024.4718MSANS
+8614DUSENBACH ALAIN 11956 61979031992011471512024.3918MSANS
+4428SAUZON ISABELLE 21956111977051992011471512024.2618MSANS
+1720EOLE PATRICK 11956 41987111986112090215980.5518MALLEM
+8905JANVIER MARLENE 21957 11979071993041471512024.3018MSANS
+7774GAL PHILIPPE 11957 81977061982041834514275.7218MESP
+3204SAGINAW EDITH 21957 319790719780711302 9774.2018MANGL
+5409LEUN CLAUDE 119581019800719821011389 9852.4518MANGL
+4971CHANTEGRELET FRANCOIS NICOLAS 11958101978061987112256617146.9518CSANS
+5691ALTIPORT ANNE 21958121979101993111471512024.9618DTECHN
+1005FLEURS PIERRE 11958 81981041985041684813421.4218MSANS
+6295WINTER JACQUES 11959 81982081988052090215980.7318MINFOR
+3634CELY JOELLE 21959 31979101995021433211713.6518MSANS
+8425SOPITENIA BERNARD 11959 919790619831111389 9851.2118MANGL
+2714AGNEAUX VINCENT 11959 21980091979091684813422.7218MSANS
+3908SAN CATHERINE 21959111980031989112090215980.7318MSANS
+9522ALLERAY EUSEBE 11959 81982041989052090215979.8918MANGL
+4818CARNOT GENEVIEVE 21960 61981031995021433211714.8218MSANS
+2809VAUCRISES FLORENCE 21960 1199205199105 8656 8146.4618.SANS
+6703LAFONT CAROLE 21960 31993081992011249910472.3918MSANS
+4781RUSSIE FRANCK 11960 1199006198906 8656 8146.2818.ESP
+0025OYANA AYALA 21960 31981011980011202810241.2518MANGL
+4606GARNET CHRISTOPHE HUBERT 11960 41983011993041326611017.3218MSANS
+3285CASTAGNIERS BRIGITTE 21960 61980061986101684813422.5318SSANS
+9855HEBERT GABRIEL 11960 11988091992041249910472.9618MALLEM
+7538RUSTICANA JACQUELINE 21960111981011980011326611017.7018MANGL
+7245HAVRE ALESSANDRA 11961121985031984031608112917.1018MSANS
+2845ROSNE ANNE NOELLE 21961 6199507199407 7803 7681.3818MESP
+4993NOIR GUY 11961 81982031995101638413149.8318MINFOR
+0352NOTAIRES PHILIPPE SERGE 11961121986111993072397418036.8018MSANS
+6114LAMPAUL ROSELYNE 21961 61994021992011202810240.8618CSANS
+8947GUE JEAN PIERRE 11961 41981071995071433211713.7018MSANS
+6115NICOLAS DOMINIQUE 21961121983011982011608112916.0218MSANS
+0276ESQUIERE YVES 11961 81988081992061450311832.1518MSANS
+5271BARGEMON SERGE MAURICE 11962 51992111991011249910471.6518MSANS
+3485SOURCES MARTINE 21962 1199201199101 7803 7680.9818.SANS
+1542BOCAGE MARYVONNE 21962 5199203199103 9597 8728.5818CSANS
+8004CARDINAL MARIE JOSEE 21962 21983051982051527112373.2318MSANS
+7577VIE KAVERIO 11962121982061987111608112917.1318MSANS
+1474RABIAC CLAUDINE 21962 81984061983061249910472.0718MSANS
+7742CAZILHAC DOMINIQUE 21962 51983011982011608112915.6518MALLEM
+1316BRIAND FRANCOISE 21963 21983041982041608112915.7518MCOMPT
+5967MASCREE YVES 11963 91983071988011608112915.3918MSANS
+8262PENSEES FRANCOIS 11963 71985081991091288210745.3018CALLEM
+9624JOFFRE FRANCOISE 21964 71988041987041202810240.7718DALLEM
+1583MONTGOLFIER BERNARD 11964 11984071993041288210745.2718MSANS
+8539GILBERTIN MOISE 11964 11985041986081288210745.4318MSANS
+9414YVELINES JEAN PIERRE 11964111985071984071288210745.6618CANGL
+2500PROVOST DANUTA HALINA 21964 51985051984051381911365.9518MESP
+4860AUBEPINES THIERRY 11964 31993081993082401918075.8118MANGL
+1591CALADE ALAIN 11964 21984071990091288210745.7518MSANS
+8611DUGUESCLIN MARIE NOELLE 219651219880619870610876 9503.9018MANGL
+1890DUC PATRICK 11965 21985091989111527112373.2218MANGL
+8780ANTANANARIVO JEAN PIERRE 11965 219860619931210791 9502.9918MINFOR
+9489CALMETTE JOEL 11965 31991121992122401918075.5718MANGL
+0389VICTORET YOLANDE 21965 1198810198707 8656 8146.2818.SANS
+8865VERDIE CHRISTINE 21965 51990111989111949415051.6818MSANS
+3552LOGEM ISABELLE 21965 3199408199308 8359 7951.8018MSANS
+2210MANCHOULAS PHILIPPE 11965 31994021993021420611638.9518MTECHN
+6427LAUTIN JEAN DANIEL 11966 719890619880610791 9502.0518MINFOR
+9413KERAVILOU HUBERT 11966 51989061993111249910472.6918MANGL
+0446CHENEUSE JACQUES 11967 419931119950910363 9232.5318MVENTE
+8752ALPILLES PATRICE 11967 6199105199005 8656 8146.2318.ALLEM
+8347AICARD BERNARD 11968 219880619880110407 9271.1118MANGL
+2090ALICE JEAN MICHEL 11968 61993041992041202810240.9118MSANS
+8583EPINETTES DENIS 11968 31988041994101249910472.6618CINFOR
+2122SEE PHILIPPE 11968 9199205199105 9597 8728.6418CANGL
+2399ROQUEPAVA PAUL 11968 81988071993111249910472.9118MSANS
+8130FRATERNITE JEAN FRANCOIS 11969 91992061994011288210745.7218MSANS
+7498CARROUGES JEAN MARC 11969 31989041993121249910473.0618MANGL
+3505CHEVREUL JEAN JACQUES 11969 61990091989091467711987.2218MSANS
+2473MAJOR THIERRY 11969 3199406199306 7677 7604.8418CSANS
+7707AYGOSI CORINNE 2197010199502199402 8359 7953.4218MSANS
+6442BERGER NATHALIE 21970 5199607199507 7803 7679.4518MANGL
+5162CHANDELIERS JOEL 11970 7199501199301 9085 8419.1118CSANS
+1417BILLETS WADY 11971 119931019921011389 9851.2118MANGL
+1522PARAME COLETTE 21971 3199606199506 8359 7952.5518MSANS
+2322BARRE JACQUELINE 21971 91991011990011202810239.7818MANGL
+8136TASSIGNY JEAN PAUL 11972 31992061991061249910472.4618MSANS
+2240LOUP VERONIQUE 21973 21994031993031267210589.1018MSANS
+2489VELLEDER MARC 11974 7199506199406 7803 7679.7818CTECHN
+8166GUERRIAS CLAUDE 1197710199610199510 7803 7680.5718CSANS
+6073ALLENDE DOMINIQUE 11977 1199606199506 7803 7680.9018CSANS
+6606FROIDEVAUX FRANCOIS JEAN 11934111958051993013844228045.6538MESP
+5822DITTE NAGUIBA 11937 61966091991072273717260.5038MSANS
+1148KERVENNEC JEAN JACQUES 11938 31971051991011663613342.7438MANGL
+8491ROCHEBRUN MAURICE 11939 51967011992021932314935.2938MCOMPT
+5749GILBERT JACQUES 11939 61968031992102334017610.6938MTECHN
+3667PERGOLETTE JACQUES 11939 31963051988011663613344.6938CSANS
+6409PLACE JOSYANE 21940 71984011991091288210745.1338MSANS
+2498GASNIER CLAUDE 11940 119810719890511131 9657.9738MSANS
+2100BRASSIOUX BRUNO 11942 41973061991011621213032.2438MSANS
+1118HOUMEAU ANDRE 11943 51962111991072273717260.3538MSANS
+4519CAGOU JEAN CLAUDE 11943 41972071991011663613343.2038MSANS
+6013REMO JEAN MARC 11943 91966121990011663613343.0138MANGL
+8050YAN BERNARD 11944111963121992042273717261.8138MSANS
+3614EGUILLON SERGE 11944 31978041992011471512025.5638MSANS
+5430CHARPENTIER JEAN PIERRE 11944 91966061994072137316332.5038MSANS
+8523PARIS PHILIPPE LOUIS 11945101969071992062334017610.6538MANGL
+2111TOUL ROLAND 11947 51972021992012017815518.0638MINFOR
+0683GEORGES RICHARD EMILE 11948 91976091994012000715439.1738MANGL
+7517GRAND PHILIPPE 11950111971041995072470018540.9738MSANS
+4909AIX JACQUES 11950 11970041993121834514276.0138DCOMPT
+3400NOUAN PIERRE 11951 41971041992122739020403.8938MSANS
+7319BERGERONNERIE MICHEL 11951 21979031993011578112723.3338CSANS
+2615PATURES DANIEL 11952 91972081993122547019085.9538MALLEM
+1673MIRAMAR PHILIPPE 11952121973071983112470018541.3438MSANS
+4747LOLIVE FREDERIC 11953 81978111993011608112915.9738MSANS
+9613BORD JEAN MARC 11953 41978051995041249910473.2038MSANS
+9161CHANTE PATRICK 1195311199603199505 8656 8147.0938MTECHN
+1511COLBERT PIERRE MARIE HENRI 11953121973031993042017815517.9138MSANS
+0700BRAGELOGNE ALAIN 11954 91974021989052256617146.1638CSANS
+4590BERRY CHRISTINE 21954 5199302199201 9085 8419.4938DMANAG
+7017LASPLANES DOMINIQUE 11955 41984061993041326611016.6238MCOMPT
+4869ROUMANILLE CLAUDE 1195512199306199206 9126 8457.4938CTECHN
+2931PYRAMIDE ANDRE 11956 61979031992011471512026.0638MSANS
+0636COTEAUX MICHEL 11956 31976011992011608112915.2138MANGL
+9829EUROPE JACK 11957 11980061985011684813422.6838DSANS
+7001FORET MARC 11957 41977011994011249910471.5638MTECHN
+7136OCEAN HENRI 11957121977061992011471512024.5338CSANS
+3955VIGNES PATRICK 11959 51981011993031608112916.1438MANGL
+9568ARNOCHE GERARD 11959 71981061993121471512025.8338CTECHN
+4979AIMEE PASCAL 11959 519860219880110791 9503.5238MSANS
+2891SCHLOSSER BRUNO 11960 51982111995071433211713.6738MSANS
+8194CABIRAUX JEAN LUC 11960 219930119910110407 9272.1338SANGL
+2865LEIGNE ANNE MARIE 21960 71980091993051527112374.8538MSANS
+4343GERMIGNY YVES 11961121983041982041326611017.7438MSANS
+2039ROUTE JEAN CHARLES 11961 21982031981031326611017.8838MANGL
+8887CUTTE HUBERT 119611019820619810611131 9657.5738CANGL
+5692LAC FREDERIC 11961121981051994011433211715.2438MTECHN
+9404COMBES HUBERT 11961 9199308199208 9597 8729.7438MCOMPT
+7675CHEVRIER JEAN HERVE 11962 41984021991071527112374.2538MINFOR
+8147PROMENADE CHRISTIAN 11962 3199405199201 9597 8729.7238MANGL
+8550RASCAS JEAN 11963 119850219900610791 9503.9738MSANS
+8387JEROME PIERRE 11963111985041992011949415051.6838MALLEM
+7757FAVIERE PATRICK ANDRE 11963 51984081991021527112373.3138MSANS
+2903GLADIATEURS MICHEL 11963 31984121983121326611016.0338MSANS
+5686BEDFORDALE THIERRY 11963 819831219821210791 9502.0438CINFOR
+5983TANNERON JEAN FRANCOIS 11964 61987111995042256617147.2238MTECHN
+5469CIGALIERE JEAN FRANCOIS LOUIS 11964 31988081988021450311832.6838MSANS
+2425BOUVREUILS MICHEL 11964 11988011995121381911366.9938MMANAG
+7826EAU ARNAUD 11964 81987021986021249910473.4938LSANS
+4783TESSIER MICHEL 11964 61990011991011249910472.1238MALLEM
+4053ARPENTS PHILIPPE 11965 219901019891010407 9271.1138CESP
+5354COMBELONGE PHILIPPE 11965 41985041984041288210745.9338CESP
+0915TUILLIERE JEAN LOUIS 11965 51989031991011249910471.5838MCOMPT
+3732MALABRY FREDERIC 11965 219940119910110407 9271.7938CSANS
+8032VIRO PASCAL 11966 319921119911110024 8998.3738MSANS
+0237TORRICELLI ERIC 11966 61988101986051288210744.7638.SANS
+9815LAPLACE PHILIPPE 11966 5198912198812 8656 8146.1438.SANS
+0253TALLOIRES ERIC 11966 61989121993071381911366.0338CSANS
+7893BOURBOTTES JOEL 11966 8199404199201 9597 8729.0338MANGL
+2674SET OLIVIER 11966 619891119881110407 9270.5638MSANS
+8321LONGS FREDERIC 11966 219950319940110668 9427.0238CSANS
+6369DOURBIES PATRICE 11966 319920319910310024 8999.3438CSANS
+1563TURBINE JACQUES 11966 91987031994091693613498.1438MTECHN
+6038COLLINE RICHARD 11966 5198912198812 8656 8147.2238.ANGL
+8370BONSON THIERRY 11967 5199011198911 8656 8145.3838.MANAG
+1538FAUVETTES HUGUES 11967 6199609199509 7803 7681.3138MANGL
+5092DJINNS MICHEL 11967 1199111199011 9597 8728.9938CSANS
+3468GARDES FARID 11967 119880319870310407 9270.4238MSANS
+7303DENY JEAN CLAUDE 11967 51993021992021202810240.7738CESP
+1319PLOUGONVELIN JEAN FRANCOIS 11967 919880919870910407 9270.1638MTECHN
+7182BEAUMARCHAIS ALAIN 11967 11990111993071381911365.9838MSANS
+5432ROMAIN JEAN PIERRE 11968 519940519920110024 8998.1738CANGL
+8756PEGUIERE PHILIPPE 11968 919940319930310668 9426.6338MTECHN
+0590MONTROSIER DIDIER 11968 419940419920111389 9851.6438MSANS
+3773FIORI MICHEL 11968 61990051990051381911364.9938MSANS
+9060CHAMBORD AGOSTINI 11968 9199406199306 7803 7679.9138CSANS
+7693DIZIER THIERRY 11968 319920519911111389 9851.7338CSANS
+7838CECILE PATRICK 11968101988071991011249910473.6738CSANS
+6964GOYRANS GABRIELLE 21969 91990031992011202810239.9638MSANS
+0784COSQUER COLIN 11969 719940619930611389 9851.9638MINFOR
+8622COURTAIS JOSE 11970 619960719950710668 9426.6238MSANS
+2794BERGERET CHRISTOPHE 11970 61992051993041202810240.5938MINFOR
+4688RABELAIS FREDERIC 119701219940619930411389 9850.7138MANGL
+9681POUSSEAUX RICHARD 11970 61991041990041202810241.4538MINFOR
+0530BRANCOLAR PIERRE 11970 619900619890610024 8998.3538CANGL
+9957LENTILLY LAHOUARI 11971 7199607199507 7803 7680.6638CSANS
+7210CHAMPERRET ANDRE JEAN 1197111199406199201 9597 8728.6838CTECHN
+7549BRAMO JEAN 11971 2199612199401 9597 8727.9638CSANS
+1719TELEMLY JEAN 1197110199612199512 9894 8922.8038CINFOR
+7574MOUQUET PIERRE 11971 3199304199204 9597 8728.7738CANGL
+1471ETOILE PHILIPPE 11971 3199501199304 9597 8729.9038MANGL
+1536MAISTRE LOUIS 11971 51990121989121202810241.5238MINFOR
+7328BLAMONT BRUNO 11971 31991021990021202810240.4038CSANS
+4093TOLOSANE JEAN 11971 51991071990071202810240.7638CANGL
+8648RAPHAEL GERARD 1197210199408199201 9597 8728.4938CMICRO
+2769GOULET ERIC 11972 119950419940111389 9852.5938MSANS
+9108CRETEIL MICHEL 11972 4199606199506 8656 8145.6638CSANS
+5284POMPONNE ALEXIS 119721219920519911211389 9851.7938CTECHN
+8876LAIGNEAU ALAIN 11972 3199202199102 8656 8146.4138.ANGL
+6070REVOULUN CONOR 11972 2199608199508 7803 7681.4038CMARKT
+8083CLEYRAC JACQUES 11972 5199403199201 9597 8727.9138CANGL
+8314PARIS GERARD 119731119940819930810668 9426.0338MANGL
+4108SEGURET GUY 11973 9199207199107 9597 8728.4638CSANS
+4139PRESSENSE PATRICK 11973 9199608199508 8656 8145.6938CALLEM
+2465CHATEAUDOUBLE DIDIER 119731019950219940210668 9426.4838CSANS
+5213MARTINIERE GERARD 11973 8199608199508 7803 7679.2838CSANS
+0769POUR PHILIPPE 11973 719940919930910668 9425.8538CSANS
+2580BESON MARC 11973 7199307199207 9126 8457.0238CALLEM
+4770LIEUTENANT JEAN OLIVIER 11973 8199607199507 8656 8145.6638CINFOR
+1963SENGA CLAUDE 11973 6199412199201 9126 8457.2238MCOMPT
+2932SOULT CAMILLE 11974 5199604199504 8656 8145.8338CESP
+5177CLOS GILLES 11974 4199506199406 9126 8456.6138CALLEM
+0619MEUR BRUNO 11974 2199607199507 9894 8921.6938CANGL
+3202RUBEU DOMINIQUE 1197411199610199511 9894 8922.0838CINFOR
+1263PONTILLOU DIDIER ERNEST 11974 1199309199209 9597 8728.1738CSANS
+3833NEUVE JACQUES 11974 2199508199408 9894 8921.6438CANGL
+6528NIMES ROBERT 11974 1199410199310 9597 8729.3638MSANS
+9312CHAT ANDRE 11974 7199307199207 9597 8729.6338CANGL
+0437SAUVAGEONNE RICHARD 11974 4199301199201 9597 8728.8238MSANS
+5387PLEHEDEL JEAN RENAUD 11974 8199309199209 9597 8728.9938CVENTE
+5835MAROLLES DENIS 11974 7199609199509 7803 7679.9438CSANS
+5277BURON STEPHANE 11975 4199410199310 9126 8457.5938CALLEM
+0147URSULES PATRICK 1197510199512199412 8656 8147.1738CSANS
+6637DEVANT PATRICK 11975 7199610199510 8656 8146.2938CSANS
+7462BARBICAJA STEPHANE 11975 9199609199509 7803 7679.3138CSANS
+9096HELENA PHILIPPE 11975 81994111994011202810241.8538CINFOR
+7777ENGOULEVANT JEAN CLAUDE 1197511199612199512 9894 8922.0838CSANS
+7823BRENNUS JEAN PIERRE 11975 2199606199506 7803 7681.2038CINFOR
+7353LOOVAS FREDERIC 11976 6199612199512 9894 8922.8938CANGL
+5381BRIAND JACQUES 11976 1199507199506 7803 7681.4038CSANS
+8880LECLERC FRANCOIS 11977 2199506199406 7803 7679.8738CMICRO
+1576MONTMELIAN CLAUDE 11977 9199607199507 7803 7679.3138CANGL
+6203GUECH RENE 11977 1199507199407 7803 7680.2638CCOMPT
+2768MERIBEL RICHARD 11977 7199607199507 7803 7681.2938CSANS
+7366FERNANDEZ OLIVIER 1197712199607199507 7803 7681.0238CANGL
+7525LONJUEUIL SYLVIE 2193011198901199511 8656 8145.9141.INFOR
+8410CAIXA JEAN PIERRE 11935 31956051979013327724476.3741MSANS
+4687FURSTENBERG NADIA 21936 31972041994101881314585.6641MSANS
+9030AMIRAL JEAN RENE 11936 61961081993011663613343.8441MSANS
+0747SURREY TOMOE 2193611199201199101 7803 7680.6241.INFOR
+6230LIGURES JEAN PAUL 11937 81962021994042666519900.8141MALLEM
+5598FONTENELLES CLAUDIE 21937 31962031995102666519899.2941MANGL
+7964AUMONT JOSE 11938 31968121991011433211715.7241CSANS
+1865HUBERT CHRISTIAN 11938121962111982112470018542.1041MSANS
+0974ROMAINE JEAN MARIE 11939 91962111989071663613342.9741MALLEM
+8959BILLEHOU DENIS 11940 41962011993011663613343.2041MSANS
+3134RESISTANCE CHRISTIAN 11941 61970051987012022115555.5741MANGL
+2829MARCIGNY ANNETTE 21941 8198901198711 8656 8146.6141.SANS
+9621AIR MONIQUE 21941111968071990071578112723.4141MTECHN
+2532MIMOSE JEAN 11941 31979031994011369311287.2541CANGL
+6822BERLIOZ MICHELE 21942 81965021992051932314934.6841MSANS
+8381REGRATTIER FRANCOISE 21942 41963101991072273717261.0341MSANS
+1877GASTON APOLLINA 11943 41972061995011663613343.5241MANGL
+9764NORTH CATHERINE 21943101992051995121330611017.8841MVENTE
+0051FABRON GILLES 11943111972121992041403411522.2441MSANS
+2826DESTEY RICHARD 11943101965121990011433211713.6541MSANS
+4901GANDHI FRANCOISE 21943 31969031991011932314935.1641MSANS
+2788ENSOLEILLADE CHRISTIAN 11943 81966011991043844228044.1541MINFOR
+2725SAROIS CORINNE 21943 71972081994051804514081.9541MANGL
+4033GRIVES PHILIPPE 11944 31966101990011433211714.0341MSANS
+0306LUTECE CATHERINE 21944 91977061992011471512026.2241VSANS
+6413TURALURE LOUIS 11945 11967121990041433211715.1541MALLEM
+6065BUARD JEAN JACQUES 11945111969061991011433211714.6441MTECHN
+0713CLAUVEL MARIE CHRISTINE 21945121993101992011202810241.7441MSANS
+2016BENGALIS HENRIETTE 2194510199103199003 7677 7603.0141.SANS
+5741SAUVAGERE ALAIN 11945 91972021989011621213034.1541MSANS
+5896GAILLARD ERIC 11946 31973021995011663613344.4541MANGL
+4390PAROUQUINE MARTINE 21946 81973041995101911114778.4441MESP
+4358MAYE CHRISTOPHE 11946 81970111994051834514276.1841MSANS
+3228PERRET JEAN PIERRE 11946 419800719790711389 9852.6741MESP
+2070COMMERCE MARTINE 21946 11965101995042739020405.2241MMARKT
+2112COT CHANTAL 21947 5199104199004 8656 8147.0141.ANGL
+5488MONTAIGNE ERNEST 11947 81972061989041621213032.6541MTECHN
+4615JAURES PASCAL 11947 319850219840211389 9852.1441MSANS
+3975BENAT MARTINE 21947 9197204197104 8103 7796.4541MTECHN
+5422LAUGIER FREDERIQUE 21948 719850419880110791 9502.2841CANGL
+7269TORTE DENIS 11948 71969081994083916628548.6641MSANS
+9916MARNES JEAN CLAUDE 11948 719931019910710407 9270.0341MCOMPT
+7840GRIGNON CHRISTIAN 11949 51969121989122470018541.4341CVENTE
+5255VERNY ARLETTE 21949 81971061990071621213033.7041MALLEM
+4729SALONINA PATRICK 11949 91974041992011608112916.6141MCOMPT
+5121KISS THIERRY 11949101976041994011369311288.2241MTECHN
+3042FERIC MARIE CLAIRE 21949 51984071994031288210744.1741VTECHN
+3660PLAINES FLORENCE 2194912199303199306 9597 8728.0841MANGL
+6514EPINIERE JANY 21950101972011990102175716601.3041MSANS
+4692HUNTZIGER BERNADETTE 21951 71992101991101202810241.0741MSANS
+6747CHAMPERRET LAURENT 11951 819870719870810407 9270.9741MSANS
+5984JAMET DANIELLE 21952 9199203199103 7677 7603.0441.SANS
+8680SERRALONGUE ANDRE 11952 31977071981102470018541.9541MSANS
+1345LENTILLAC ALAIN 11952 919940119920110407 9272.0141CALLEM
+9942AUSSEL MURIELLE 21953 4199406199306 9597 8729.5841MINFOR
+6512SCIPION CLAIRE 21953121974081992032175716602.2441MSANS
+2634FOCH JOCELYNE 21953 31996011995011249910473.0941MINFOR
+5957CYPRIERE CHARLES 11953 81977091993071369311288.1041MANGL
+7817EMILE SYLVIE 21953121973041994011527112373.0441MSANS
+8678HUNG HUGUES 11954 819810519850611389 9852.6041MSANS
+7968LUBONIS MICHEL 11955 71980041992021471512025.5241MSANS
+3688EBAT ANNE MARIE 21955 31977071995071433211714.0341LSANS
+0140GIRARD CLAUDE 11955 71978111991041578112722.8741MTECHN
+6583EUGENE CHRISTINE 21955 71978051992111608112916.2541MINFOR
+3771CUQUES ELISABETH 21955 11993101992011202810241.6641MSANS
+9329CARRIERO JOSE 11955 719830419820411131 9658.8341MSANS
+6210MACHIEL ROGER 11956 71977031993041471512024.0841MSANS
+7407QUENU PATRICK 11956 71980051995041249910473.3241MALLEM
+7722CARNOT GENEVIEVE 21956 51977051993031608112915.4241MALLEM
+7051PALMIERS EVELYNE 21957 41980041994011471512025.1141MSANS
+6978JACARANDAS ALAIN 11957 11985081993041288210744.7741MANGL
+5352VANTAGE GERALD 11957 91978071992091471512024.5341MTECHN
+9337CHALONS MICHELE 21958 3199609199509 4342 5820.2441MSANS
+6534HERRET VIVIEN 11958 919861119860710791 9502.8041MSANS
+3402RUVEI LINDA 21958 71981051995041433211713.6241MSANS
+5959SERLIANE HERVE 119581119851219841210791 9503.3141CANGL
+2613ROSIERS RICHARD 11958 3199601199507 9894 8921.8141MSANS
+3289ALLEGRES GERARD 11959121981071994011471512025.9141MSANS
+6523ROCCA GUY 119591219850119860411131 9659.1541MMARKT
+8881CHATEAUBRIAND GILLES 11959 51981011993071471512025.3241MSANS
+5781HELSINKI DANIELLE 21959 81981011995011433211715.7441MANGL
+4147SIAGNE CORINNE 21960 61981041980041450311832.2441MSANS
+1606POIL MARIE THERESE 21960 919941119920110024 8999.5241CANGL
+1752ROUGUIERE GUY 11960 319940819951011389 9851.1041CSANS
+5961CHALAIS MICHEL 11960 919930819910110407 9271.4641MSANS
+1601DURUY ANNE MARIE 21960 21989071988071249910473.2741MALLEM
+3631ESPARIAT MIREILLE 21960 4199511199411 9126 8457.4941MESP
+2747TENSE MARCEL 11960 11982021995042256617145.7841MSANS
+6989JACQU YANNICK JEAN LOUIS 119601219831119850111131 9657.0641CSANS
+4612BOURNET LAURENT LOUIS 11960 119900519891110407 9271.2441MSANS
+3236PIOL DOMINIQUE 11960 51984051991011326611017.7741MSANS
+6475VILLETTE PHILIPPE 11961 21984081983081608112915.6641CANGL
+8207MESNIL REGIS 11961 21982101990112090215979.7941MSANS
+0526AGUESSEAU DARA STEFANE 21961 91986041985041288210745.7541MSANS
+3092MONTFLEURY JACQUES 11961 11983041994011433211713.9441MSANS
+7762BUCHERIE ANNIE 21961 91986101985101288210744.6741MSANS
+9535MADONA CHRISTIAN 11961 719931019910110407 9270.8041CSANS
+4953GARE HIROMI 21961121984031994011527112374.4941DSANS
+6431CORNEBARRIEU JEAN PIERRE 11962121985101991021527112373.6241MANGL
+3878ANLHIAC MICHEL 11962 7199602199502 8656 8145.9641MSANS
+6464ESTEREL GASTON 11962 619860319880310791 9503.7641MANGL
+2255MAUVALLAT ANNE 21962 71982081981081326611016.1541VANGL
+8438CHANTACO MARIE NOELLE 2196211199307199207 8656 8147.1541.SANS
+4202FENOUA MARC 11962 3199212199112 9597 8728.5041MTECHN
+3836PAUL PHILIPPE 11962 31982011993041326611016.2141MSANS
+0418CHANET NICOLE 21962121982041981041608112917.1541MSANS
+2005ROCHES MARIE HELENE 21963 31984071983071608112915.2141MINFOR
+7305RASPAIL YANN 11963 719850919840910791 9501.7841MSANS
+4264SCHOENFELD PHILIPPE 11963 619830419841111131 9658.4241MANGL
+4951LAUVE JEAN PIERRE 119631119840319860610791 9502.5941MSANS
+7632VALLOIS FREDERIC 11963101986011990111288210744.6741MSANS
+6021ANTOINE JACQUES 11963 4199406199306 9597 8729.3441LANGL
+1193SAUT YANNICK 11963 51987061992121450311830.7941MSANS
+5840VIRARD JEAN PAUL XAVIER 11963121995011994011206910241.4941MTECHN
+0346CASATORRA BERNARD 11963 419910619900610024 8998.1741MSANS
+0082BAURECH HENRI 11963 41991101990101381911365.5041CSANS
+3466TULIPES ANNEE 21963121984111983111450311830.8541MTECHN
+3635FUSTEL BRIGITTE 21963101983041991091527112373.6441MALLEM
+3776THUITSIGNOL ANDRE 11963 91983071986081326611016.7441MSANS
+7941PINS MICHEL HENRI 11963 81983081993041288210745.4341CSANS
+8903CHARTRES MARIE ODILE 2196412199412199312 8656 8147.2441MANGL
+6455GIANOTTI FRANCOIS 11964 219870119860110791 9501.8341MSANS
+3178PABU PATRICE 1196412199606199506 8656 8145.9641MANGL
+1683TOKI GILBERT 11964101994051993051267210589.2541CTECHN
+1069COUTURES ERWIN 11964 6199504199404 8359 7952.6641CSANS
+7668PALISSY ALAIN 11964 2199310199210 9597 8729.2741MSANS
+4934AIGUES JEAN MARIE 119651019860719860310791 9503.9741MTECHN
+5099LARRALDIA REMY 11965 11987021993091949415052.3541CANGL
+8301BOUCHAREL FABIENNE 21965 81993091992091839014312.4041CSANS
+7214VOUTE CHRISTIAN 11965 419870719870610407 9270.9741CTECHN
+7913MOULINS YVES 119651219890519880510407 9271.8641DCOMPT
+1180REPENTANCE MICHEL 11965101993111992011249910472.8741MALLEM
+1457SAUVETTE GERARD 1196512199301199201 9597 8729.3041MSANS
+4206LONGERE ISABELLE MARIE ALICE21965 8199610199510 8656 8146.1141CANGL
+2030TONELIER MARC 11965 719860419880510791 9502.5541CSANS
+2828DERRIEN JEAN JACQUES 11966 71991011990041202810241.6141MSANS
+5283COULLET OLIVIER 11966 519880619870610407 9272.1341MANGL
+8198COUPANCES CHRISTINE 2196610199403199303 9126 8456.3041CSANS
+4478NOSTRADAMUS GREGOIRE 11966 719860419900210791 9503.9741MSANS
+7215HILAIRE FRANCOIS 119661019860319850310791 9503.9741CSANS
+8745MONTREUIL GUY ROBERT 119661019910419900410024 8999.0741CTECHN
+3647DELESTRAINT JEAN CLAUDE 11966 11989061994011381911366.2741MSANS
+7458LISERB JEAN LUC 11966121991061992031381911366.0941MALLEM
+6758BIGOCHETS FREDERIC 11966 119911119901210407 9270.8341MSANS
+0098JARDINIERS MYRIAM 21966 51986061993071450311830.9441MVENTE
+0882BRUXELLES CAROLINE 219661019940319920111389 9851.8241MALLEM
+5390VEYRE NATHALIE 21966 419941119930411389 9851.9741MALLEM
+4046CHAMBERTE BERNARD 11966 31987091988071949415052.4441CSANS
+4837BONNAMOUR MICHELE 21966 21994031993011723313654.5941MSANS
+0532MORE LOUIS 11967 919870819930410407 9270.2441MTECHN
+4906LELIWA DANIEL 11967 219870619860610407 9271.2041MSANS
+5362MAGNOLIAS JACQUES 11967 6199609199511 7464 7525.6141CSANS
+8779SORQUES GUY 11967 61988041990011249910472.9741MANGL
+1022ETANG GERARD 11967 3199506199304 9597 8729.5841LANGL
+8535DELACROIX JEAN PAUL 11967 619940519930511389 9851.5141MSANS
+4910ARANDELYS HERVE 11967 71990101989101202810241.0941MANGL
+4304EURE ALAIN GEORGES 11967 51991101990101330611017.7941CESP
+0132DJILLALI ALAIN 119671119931119920110407 9271.1941MSANS
+9907BON THIERRY 11967 91987091992111450311830.6141MSANS
+5376REGNAULT DANIEL 11968 51990111991021381911366.7941MALLEM
+0903SUR BRUNO 11968121992051994121330611017.0541CSANS
+7066RENAN FRANCOIS 119681219890619910510024 8999.7441CVENTE
+9334ALL ADELE 21968 9199310199210 9597 8728.9841MSANS
+1100MONTFORT ANNE MARIE 21968 519950219930411389 9851.7441MSANS
+7153PINSON GENEVIEVE 21968 31989111993071381911366.3041MSANS
+4338MABO MICHELE 21968 7199602199502 8656 8147.1541MSANS
+2568GODEAUX GEORGES 11968 61994051993051267210590.4141MSANS
+9355MEUNIER MARIE HELENE 219681219940919930411389 9851.1041MINFOR
+4462CACTUS MICHEL 11968 51993091992091839014312.7641CTECHN
+2155REINOTS DENIS 11968 1199406199201 9597 8729.6641CMARKT
+1708QUEUILLES ALAIN 11968 91991111991111723313654.7041MANGL
+9411MANDRAGORE ALAIN JEAN 11968 81995041994041206910241.6641CSANS
+4930ELVIRE PATRICE 11968 41995121993041202810241.7441CALLEM
+8112PAVOIS LUC 11969121992021991021381911366.7941CSANS
+8181UNIVERSITE OLIVIER 1196912199408199308 9126 8456.6941LVENTE
+6245CAIRE ANNICK 2196911199405199301 9085 8419.1641CSANS
+2166PRETY CORINNE 21969 7199612199512 9894 8922.5341.SANS
+4325COTTAGES YVAN 1196911199407199307 9126 8456.9741MCOMPT
+0898SYLCO ALAIN JACQUES 11969 91989091988091249910472.9641MSANS
+4572DARTHE DIDIER GEORGES 11969 4199503199304 9126 8456.5541CSANS
+9418AUREVILLE PHILIPPE 11969 519900719890710024 8998.2841CSANS
+7504MAROT ALAIN 11969 119910319951110024 8997.8341CANGL
+4672TRUCQUES JACQUES 11969 2199606199506 8656 8145.6041MANGL
+5588POUTILS ALAIN 1197012199405199305 9597 8728.2241MALLEM
+8965SAUCES JEAN PAUL 11970 71992021991021381911366.2541CSANS
+1934PRESSES LUCIEN 11970 11991091990091467711987.9041CSANS
+5600LAROIN LAURENT 11970 91991061990061202810240.6841CTECHN
+8935REINE JEAN PAUL 11970 119920819910810024 8998.7141CSANS
+9304MARCQ MARCEL 11970 719940119930111389 9851.4341CANGL
+5444CHEM LOUISIANE ALAIN 11970 11991021990021202810240.2241MSANS
+7850HUBERT BERTRAND 119701219920619920410024 8998.1441CSANS
+0638FLEUZY PHILIPPE 119701119900419890410024 8998.7141MVENTE
+0729MUETTE CLAUDINE 21970 5199204199104 9597 8729.8541MALLEM
+5723MARCHE LAURENCE YVONNE 21970 919940619930411389 9852.3641CANGL
+1904CHENE JEAN GABRIEL 1197010199501199304 9597 8729.2141MSANS
+1861CREOUNE MARIE THERESE 21970111991101990101330611018.1541MSANS
+5885LONGUET MICHELINE 21970 619950319940110668 9426.5941MSANS
+9271SEINE LIONEL 11971 81993121992121267210589.8241MSANS
+6056CHE FREDERIC 11971 219901019891010024 8999.8541MSANS
+8822BOUSSOLE ERIC 11971 819910419900410024 8998.7641CSANS
+1433COMBE ALAIN 11971 5199308199208 9597 8729.3941CSANS
+5251GRELLOU DOMINIQUE 11971 91992091991091330611018.2441MESP
+6795EMMANUEL MARYSE 219711119920719920811389 9851.3041MANGL
+6104AUDE CATHERINE JOELLE 21971 7199309199209 9126 8456.4741MSANS
+3946PLEUMER CATHERINE 21971 6199301199201 9597 8728.1941MANGL
+9614BOUE FRANCOISE 21971 519921219951011389 9850.7641CSANS
+5568TASSY DANIELLE 2197111199605199505 8656 8146.4141SSANS
+5159CHATEAU GUY 11971 619910419900410024 8998.9541CSANS
+3722VERE ALAIN 119711219930919920911389 9852.6941CVENTE
+8496ORANGINI PATRICK 11971 31994051993051267210590.4241CSANS
+4662CANTE WINNI 21971 9199206199106 9597 8728.7141MSANS
+5032CHATAIGNIER MARIE LOUISE 21971 81991121991091330611017.6441MSANS
+1771PICHOLINES JOELLE 21971101991121990121202810240.9441MALLEM
+8900BOULAINVILLIERS MARTINE 21971 719940619920111389 9852.0041MSANS
+8306GUERRE FRANCOIS 1197112199103199003 8656 8146.2941.ALLEM
+9088LAROQUE MARIE FRANCE 21971121993091992091723313654.6141CALLEM
+6520LIEU JEAN PIERRE 1197112199201199101 9597 8728.2341CESP
+2579HERANDIERE PIERRE 11971 6199606199506 8656 8146.4641CTECHN
+8999JARDINS PIERRE 11971 819910119900110024 8999.3041MSANS
+8513PERRIERES PHILIPPE 1197211199205199412 9597 8728.0941CTECHN
+5836GIRARDON SYLVIANE 21972 119911019901010024 8998.5041MTECHN
+9465DAN FRANCOIS 11972 31994031993031267210590.0541CALLEM
+3970BREGUI GERARD 11972 5199311199210 9597 8729.5241CALLEM
+8911RIVIERE MARTINE 21972 5199310199210 9597 8728.8441CANGL
+8506RIBOT JEAN PIERRE 11972 3199403199303 9597 8728.1341CANGL
+4988CHATILLON DIMITRY 1197210199303199203 9597 8729.2541MANGL
+3678GRES CLAUDE 21972 8199608199508 7803 7680.6241CSANS
+9757CADENELLE PAUL 11972 219951219940110668 9425.8141MINFOR
+8910RENAISSANCE RENAUD 119721019931119921111389 9851.5541CSANS
+4973SAL EMMANUELLE 21972 719920119910111389 9851.3941MANGL
+8099TURENNE MARTINE 21972 8199407199407 9126 8457.5641DANGL
+6683HIRONDELLES MARGUETITE 219721219930919920910668 9425.4541MANGL
+3610BERTRAND DIDIER 11972 8199403199201 9597 8727.9941CSANS
+7709MORINERIE YVES 11972 7199206199409 9597 8729.5241CSANS
+6549BOISSERAIE HERVE 11972 41995041994041206910240.7641CTECHN
+8170MALHEUREUX PATRICK 11972 21991111990111202810241.4041CSANS
+0105CRONSTADT CHRISTOPHE 11972 6199209199109 9597 8729.1741CALLEM
+3953CHARBERYS NICOLE 219721019930819920811389 9850.9841CALLEM
+7071BARBINIERE PHILIPPE 11972 71993031992031267210590.4741CSANS
+4851LETRIMAN CLAUDE 11973 5199602199502 9894 8921.9641CANGL
+0165VAUGRENIER JACQUES 11973 119930919920911389 9852.3841CINFOR
+7080BANCHE ANTOINE 11973 3199306199206 9597 8729.6741CSANS
+1252VINCENNES ANDRE 11973 6199410199310 9126 8457.3641CSANS
+1299SERIGNE LOUIS 11973 4199310199210 9597 8728.2641MSANS
+7759WILDERTON LUC 1197311199410199310 9126 8457.3241CSANS
+8844LORGUE SYLVIE 21973 119930319920311389 9852.3841MSANS
+8332BRANLY BRIGITTE 21973 7199509199409 7803 7680.7241CSANS
+8767DEMOISELLES LUC JACQUES 1197310199301199201 9597 8729.7441CANGL
+6481MANCEY RENE PAU 1197311199411199506 9597 8727.8341CSANS
+9685HERRIOT MARIE CHRISTINE 21973 6199408199308 9126 8456.8241CESP
+5412JANVIER KATY 21973 6199210199110 8359 7953.4241.VENTE
+3049VICOMTAL ANNE FRANCE 21973 2199305199205 9597 8728.1741MANGL
+8606DIDIER MARC 11973 3199308199508 9597 8728.5041MSANS
+5438MOREL JEAN JACQUES 11973 91994031993031267210589.0641MSANS
+1333CERET ISABELLE 21973 3199608199508 9894 8922.4141CALLEM
+8656COUBARD FREDERIC 11973 9199305199205 9597 8729.6641CTECHN
+7939MONOD SYLVAIN 11973 5199301199201 9597 8729.2541CSANS
+2807BOTTERO PATRICK 11973 4199403199303 9597 8728.5341CSANS
+1950VAROISES ELISABETH 21973 619930919920911389 9850.8341MSANS
+0981MARCILLY JEAN RENE 11973111992101994011249910472.1941CTECHN
+7067ROSES PASCALE ISABELLE 21974 3199406199306 8359 7952.7941CSANS
+5670DEVLOO RICHARD 11974 5199512199304 9126 8456.9141MALLEM
+0896CHEVAL CHANTAL 2197411199603199503 7803 7681.1141CVENTE
+7374BAUX MARTINE 21974 6199607199507 7803 7679.6441CALLEM
+2343PANSEROT BRIGITTE 21974 7199406199306 9126 8456.5741CSANS
+8458ARMANDY CLARA 21974 419940719930810668 9427.4041CTECHN
+5573TAKAOA MARTINE 2197412199306199206 8359 7953.1141.ANGL
+1351ROYAN MICHEL 11974 8199606199506 8656 8145.8741CSANS
+2308COAT MARIELLE 21974 21994091993091206910240.3741CANGL
+1077BARBY HERVE 11974 3199609199509 8656 8146.8341MSANS
+8863JUNOT JEAN GILLES 11974 7199610199510 8656 8145.4441CSANS
+3894CIEL JACQUES 11974 119940919930910668 9425.6741CINFOR
+5086FABRE GEORGES 11974 7199407199307 7803 7680.7141CSANS
+3050CROISON RICHARD 11974 9199409199309 9126 8457.3341CSANS
+9319CHAT DIDIER 119751119941219931210668 9426.9341CINFOR
+2636MONTJUSTIN BERNADETTE 21975 8199609199509 7803 7680.8141CSANS
+1156MER JEAN MARIE 1197512199603199503 8656 8145.2141CSANS
+2790RAGEUL SERGE REYNALD 11975 5199603199503 8656 8146.7941CSANS
+4387BRETEUIL ERIC 11975 1199606199506 8656 8146.2941CALLEM
+7191COCHET HUGUES 1197511199609199509 7803 7680.7541CSANS
+7798LARGE DOMINIQUE 21975 8199609199509 7803 7680.8641CSANS
+1442CANDEOU ARMAND 11975 3199603199503 8656 8147.1041CSANS
+6969CHAIGNEAU CHRISTOPHE 1197512199610199510 8656 8146.0241MALLEM
+5660HOULET MARIE ELISE 21975 5199603199503 8656 8147.0441MANGL
+9225TOURNON MARIE ELISABETH 2197612199607199507 7803 7680.8641CSANS
+3312GURGY FRANCK KLEBER 11976 6199606199506 7803 7679.6741CESP
+2078CEDRES JACQUES 1197612199509199409 7803 7681.4941CSANS
+1381ALPHONSE MARIA ISABELLE 21976 3199607199507 7803 7679.6341CSANS
+2376POMPADOUR HELENE 21976 7199606199506 7803 7681.2941CINFOR
+2713RUILLE PATRICK 1197612199507199509 7803 7680.1241CALLEM
+2134FRANCOEUR ELISABETH 21977 6199610199510 7803 7680.3241CINFOR
+7879EGLISE LAURA 21977 8199608199508 7803 7680.6241CCOMPT
+6841GEAUNE GILLES 11978 2199507199407 7803 7680.3041CANGL
+8261LOC PHILIPPE 11935 11955021990084330331421.1942MSANS
+0031DEFEND JEAN YVES 11935 51961081987042273717261.5642MINFOR
+7162PIOT YUMIKO 21935 41969041991051932314933.5575CSANS
+6005DESIDERATO ASSUNTA 21935111962101994012137316332.6342MSANS
+1346NIZON JEAN LOUIS 11936 51971021994011663613343.9542MSANS
+6423CHARTIF ANNIE 21937111962081987082572519241.9042MANGL
+3151EUBAS DIDIER 11938 81963021981053327724476.0342MSANS
+0345KOCK CLAUDINE 21939 91968051995041834514275.4142MSANS
+4204POSTILLON NICOLE 21939 31963121992102137316332.0042MSANS
+1286BERTIN BERNADETTE 21939101967011990011932314935.1342CTECHN
+0588ONZE BERNADETTE 21939 41962101990072273717260.7142MTECHN
+0552ARENE PASCAL JACQUES 11939 21963071988101663613342.9742MSANS
+8335DRAGON BERNARD 11939111963031987012022115555.3642MSANS
+5819CORNEYRETTE MICHEL 11939 41963041983123200223583.0542MSANS
+6812MONADE ANNIE 21940 11961121994072137316330.5642MSANS
+5797PLATEAU ROGER 11941 71964041993113844228045.2942MSANS
+0254FONTAINE DOMINIQUE 11941 41963071992041557012567.5042MANGL
+8521PRELLAVICA JEAN 11941101966061989071663613344.4542MSANS
+1509MOINE JEAN PIERRE 11941 21960031984102273717260.4542MTECHN
+9780LETELLIER JEAN CLAUDE 11941111975071991011369311286.0842SALLEM
+0995HECTOR MICHELINE 21941 91971011991071578112722.3742MALLEM
+0917PUISAGE JANNIE 21941 81962041992042273717260.7242MSANS
+0311LIEVRES ELISABETH 21941111968031990011932314934.1442CTECHN
+2094NOTRE JEROME MARIE AUGUSTE11942101970061993071557012567.0042MSANS
+3489EGALITE SYLVIE 21942 81962041981112470018541.3642DSANS
+2303BUSSY PASCALE 21942101968121991011932314933.8242MMICRO
+2502MEAUX JOSEPHINE 21943 41966061994102137316332.2942MSANS
+9316DANTON ANNE HELENE 21943 91969091991051932314933.6942MSANS
+0398ABREUVOIR JEAN LUC 11943 41962111986012470018540.7542MSANS
+6448FORCET VALERIE SYLVIANE 21944 81964091994072137316331.2842MANGL
+9339TOULON DENIS 11944 91970121994011663613343.1042MSANS
+1107OUZOUER ANNE 21945 11966061992021932314935.2242DTECHN
+1368ALIVOU MICHELE 21945101971101989102273717260.0542CSANS
+9954LANFRIERE JOSIANE 21945 41996011994011202810240.4142DANGL
+1709LUXEMBOURG FABIENNE 21945111972071991101578112721.5342MSANS
+5979DESNOUETTES PASCAL ROBERT 11945 31975061990011684813422.8442MSANS
+3473AULX OLIVIER 11945 61971081991012334017610.4742MSANS
+3451MANEBIT MARIE MADELEINE 21947101972041993121471512025.3442MSANS
+7163GIGNAC MYRIAM 21947 11969081989042334017610.2042MSANS
+8839CORINA DOUGLAS 11947101967041995042137316332.5642MSANS
+7647COCTEAU YVAN 11947 21973051995072547019086.4742CSANS
+9097APARTADO BRIGITTE 21948111974101994011621213033.6142CANGL
+9822VERONIQUES PATRICIA 21949 419791119920111389 9851.0342MSANS
+5016SYLVAFLOR BRIGITTE 21949 51970021994032334017609.4642MSANS
+5933BROUILLARD SYLVIE 21949 31969011991072137316331.1542MSANS
+1734PLAGE LUDWIKA 21950 61971081991012137316331.0742DSANS
+8533LIBERTE PATRICIA 21950121970011995041834514276.1042DANGL
+7399FONTVERT ISABELLE 21950 41970121994051834514275.5542MTECHN
+7055MONTGIVRAY PIERRE 11951 41972081994062547019085.7942MVENTE
+4158CHARTON DANIEL 11951 91980041993041608112915.2642MANGL
+7325NIEL RICHARD 11951 71973081989053417325098.0042MANGL
+7367BRIAND MICHELE 21951 41973061991011578112722.0142MSANS
+0279HEURES PHILIPPE 11951111980041993011527112373.3542MSANS
+5487TOURAINE CLAUDE 21951 41972081991012137316332.7242MALLEM
+1239JALMOUTIERS CLAUDE 11952 31983031991031693613499.3442CINFOR
+4152CHEMST ELISABETH 21952 91972031971031258210512.6242MANGL
+7961ABBE KATIA 21952 51986071991041249910472.5942MANGL
+9227LEPELLETIER MARIE FRANCE 21952 81973051992102017815518.1942CSANS
+2603ESCALE DANIELE 21952101972071990011621213034.0142MANGL
+9280SISLEY BRIGITTE 21953 319740719730711515 9931.0742MESP
+6356ROZIER MONIQUE 21953 51972081990041621213032.3542MSANS
+6175CHENNEVIERES MARIE THERESE 21953111980101991011249910473.1542DSANS
+0679FONT EMMANUEL 11953 81984081993081326611018.0942MESP
+2032VIALA DANIEL 11954 71973061991011578112723.0642MSANS
+7857MASSEL GILLES MARCEL 11954 81976011995072256617145.4842MTECHN
+4251CLINCHAMPS ANITA 21954111977101976101279810668.5342MALLEM
+4945COURS ERIC 11955 71988101992044121428006.7742.SANS
+1834FUBLAINES BRUNO 11956 91976041995042000715438.5042MSANS
+3825KRIMAHER JEAN CLAUDE 11956 91984081992061326611017.8242MSANS
+9642MORILLOT CATHERINE 21956 319950419940411389 9851.7942MINFOR
+7414DUVEEM FRANCOIS 11956 51988041992011168610047.2742MSANS
+8488BOUGAINVILLIERS PATRICIA 21957 31978071977071224010317.3642MSANS
+3611COURSEGOUL DOMINIQUE 11957 21984081993011215710278.5342MSANS
+5494LABROUSTE AINA 21958 81980011993111471512025.4142MTECHN
+9526FLEURY MARIE CLAUDE 21958 319880719890710407 9270.6042MSANS
+2858LABBE FRANCK 11958121980111994051450311831.3442MMANAG
+3479NOISETIERS MONIQUE 21959 31989011991101249910473.6742MCOMPT
+0868ODET CORINNE 21959111989031988031249910471.6542MSANS
+3022TORSE PATRICK 11959 31978121993012022115555.8642MSANS
+3375ORLAMONDE MICHELE 21959121986091993051450311832.4142MTECHN
+5711PASTEUR CHARLOTTE 21959 71980051994011471512024.9242MSANS
+1466PERRIERE MAUD 21959101979081993071471512025.7442CSANS
+9464ROS ANDRE 119601019900419940110024 8998.4042MSANS
+9586TRAVERSIERE ALAIN 11960 11984121993041527112373.3742MINFOR
+4466GATTIERE BRUNO 11960 41982081992081215710280.1042MSANS
+4368GALIGNES GENEVIEVE 21960 61982091988031326611016.2442MSANS
+2690CHERBOURG HENRI 11960 91983111992091326611017.5542MSANS
+2470LEPLESSIS JEAN FRANCOIS 11961 31984041994011578112722.3742MSANS
+7595GLOIRE MARIE LAURE 21961 519940219920111389 9850.6542MTECHN
+1338SCAMARONI PATRICIA 21961111981111980111608112916.9742MANGL
+2208PLAINES MICHELLE 21961 21982021981021326611017.4742MSANS
+2517REMENIER MARTINE 21961 7199409199309 9126 8457.3642CTECHN
+9410BARRELET GENEVIEVE 21961 41983021982021326611016.3542CSANS
+2551POLIENAS MARCEL 11962 419870319860310791 9502.4942CCOMPT
+7760DANG YVES 11962121982011993091949415051.2742MSANS
+2116CEZEROU PHILIPPE 11962 71983051992022529918968.4642CMICRO
+8052PECH CHRISTIAN 11962 31986021993091839014314.4942MSANS
+0931SALSIBURY ANNE MARIE 21962 31982071981071326611018.0142MSANS
+8826SAUCERRE ELODIE 21962 81986041985041288210743.9942CSANS
+0716BEAU IRMGARD 21962 5198607198507 9085 8417.9142MANGL
+1742VERSEAU MICHELINE 21962 71982111981111527112373.3542MALLEM
+8835EXPERT FRANCOISE 21962 11983041982041608112917.0042MALLEM
+4580TIGNES GHISLAINE 21962 619921019920711389 9851.6442MINFOR
+7561SCIEZ MICHEL 11963 71991111990111467711986.1942MANGL
+4437OEILLETS JEAN FRANCOIS 11963 619930219920210024 8999.8142CTECHN
+9877LIEUDIT RICHARD 11963 51984101993071527112374.6742MSANS
+9511KERNEVEL VINCENT 11963 91985051995101450311831.2142MALLEM
+7509TARN ERIC 11963 619890219930110407 9271.8242MANGL
+1089BERE CHRISTOPHE ALEXANDRE11963 51985071992011288210745.8442CSANS
+7426MONTIGNY CHANTAL 21964 11985021984021527112373.3742MSANS
+6738BLOC FRANCOIS 11964 61989071993071381911365.6242MANGL
+4323RIAS CHRISTIAN PAUL 11964 91985091990111949415051.8942MALLEM
+1244CAMBEIRON JEAN RICHARD 11964 41985051993011693613498.3742MSANS
+5905CHISSEAUX HUGUES 11964 119910719920710024 8998.6442MSANS
+5258LAMBROSCHINI OLIVIER MAURICE 11964121989051995082256617145.0642MSANS
+1452IMAM CHRISTIAN 11964 51993111993011723313653.5142CSANS
+6093DEVAUX FARID 11964 91988061994011249910473.0242CSANS
+3662MIDI JEAN MICHEL 11964 71985021992091616712994.0842MANGL
+6965PENNE ERIC 11964 619850419840410791 9503.7242MSANS
+0024FLEURS VALERIE 21965 81986101992121450311832.2042CSANS
+3927PARC CORINNE 21965 81993111992011202810240.9542MALLEM
+9121NAUSSANNES JEAN FRANCIS 11965 81988051992071616712994.4542MANGL
+6670GENIE PIERRE 11965101994051993051420611638.9242MESP
+9153DESMOULINS PATRICE 11965 11989111994092401918074.6042MSANS
+2680CHOUETTES JEAN LOUIS 11965 519891219921211302 9776.1742CANGL
+5006ESPERANCE CORINNE 21966 619940919930411389 9852.3842MCOMPT
+9852ADOUE DIDIER 1196611199401199301 7590 7564.3542CSANS
+4760MURAT CHRISTOPHE BERNARD 11966 81991041992061381911365.1342MALLEM
+4744LESCAR ERIC CLAUDE 11966 31989021988021450311830.8542MSANS
+9188HULOT MAURICE 11966 11990021991101249910472.7942MANGL
+3718SOU ANDRE 11966111991111994011249910472.9642MANGL
+1189GROSSO XAVIER 11966111995081994081868714506.1342CSANS
+7659METRA MARYSE 21966 91989051988051450311832.4142MALLEM
+1281CRIPE GISELE 21966 91987021986021527112374.7042MSANS
+7796AMIRAL ELIANE 21966 21994011992011202810239.9642CSANS
+6977NOHANT MONIQUE 21966 91986061990111949415051.2242MSANS
+7731VERGERS MARIE GENEVIEVE 21966 219941219930411389 9851.6442CSANS
+4652LAFAYETTE MICHELINE 21967 31987061988031450311831.8742MSANS
+7993CHILPERIC BRIGITTE 21967 619940519920111389 9851.0742CTECHN
+2195VELASQUEZ DENISE 219671219940519920111389 9852.2042MSANS
+5536TIFFANY CATHERINE 21967 81988051987051450311832.2042MSANS
+9529CLAIREFONTAINE CLAUDINE 21967 81991081992061267210588.8542MSANS
+1639VILLENEUVE GUY 11967 41994101993041202810241.8542CANGL
+1238BOURBESNEUR DIDIER 11967 41991091990092611219510.6742CSANS
+9384CORALLINES PATRICK 11967 31990011993031249910471.9242CSANS
+4464PICHI PIERRE 11967 2199507199407 7464 7525.8642CANGL
+6931VOL MICHEL 11967 61994051993041360611211.0642CANGL
+0488DOREE DOMINIQUE 21967 21991111990111723313653.8442MSANS
+0529RELUYEN JOELLE 21967101987101988051467711986.0142MSANS
+9178PART CHRISTIAN 11967101993061993091267210588.8942CANGL
+8565KENNEDY JOCELYNE 21968 11991011990011381911366.3442CSANS
+2088ROUSSEL LILIANE 21968 719930819920811389 9850.8342CSANS
+6684BRUN CHRISTIAN 11968 11987051992091839014313.2142CANGL
+7111VENIZY JACQUES 11968 519940319930310363 9232.9842MANGL
+9217POUTIS ALAIN 11968 21989041995071249910473.5942DMICRO
+4714MARINA FREDERIQUE 21968 21988121992011249910471.8942MSANS
+8715AULDE BRIGITTE 21968 71994051992011202810240.9142CSANS
+9713ESCUDIER PIERRE 11968 61988121993041467711986.5342MTECHN
+6341SELLEBIED MICHEL 11968 81988011994011249910473.4242MSANS
+8663JASSERON ANDRE 11968 21995081994081450311832.7242CESP
+5734ODENAS SYLVIE 21969 81991041990041381911366.0742CESP
+2288CENSIER MARTINE DANIELLE 21969 4199408199308 8359 7952.9642CINFOR
+4540PERS RENE 11969 71991111990111949415051.9742MANGL
+5166VERAN BRUNO 11969 319930719920711389 9852.3642CINFOR
+3740CLOSEAUX PHILIPPE 11969 6199312199212 9597 8729.9742CESP
+5076BELLONTE JOSIANE 2196910199312199212 7590 7562.4942.SANS
+6280MAGENTA LAURENCE ANNE 219691019930519920511389 9852.2442MSANS
+4916MONTMERLE NELLY 21969121991101992061330611017.1642MESP
+1013SEILLAN MIREILLE 21970101994021993021360611211.0942CALLEM
+3949GRUN PATRICK 11970 41993111992111330611017.1942MANGL
+0280RICHELIEU ROLAND 11970121991111992061202810241.0942MSANS
+7899FRERES CHRISTIANE 21970 71994031992011202810239.8342MESP
+5404VIARMES ROBERT 11970 41993051994011202810240.0842MINFOR
+6508CALEU FREDERIC 11970101992111991111420611637.7842CSANS
+6706VILLEMER GERARD YVES 11970 91992051991051202810240.0142CSANS
+9352WAUTHIER CHRISTIANE 21970 919921019911010668 9426.2742MSANS
+7483ARAGO REGINE 21970 11993061992101420611637.1242CTECHN
+8430BRUEYS ROSELYNE 21970 5199302199202 8359 7952.7942MSANS
+2207CAMBEFERRIS MARIE ODILE 21970 919940719930411389 9852.0642MANGL
+7014CATHERINE ANNE MARIE 21970 519930519920511389 9851.3442CSANS
+2499MONTALEMBERT FRANCOISE 219701119921219911211389 9852.4742MANGL
+0607CORBERES ISABELLE REGINE 2197011199511199411 9894 8922.7742MSANS
+8631MOUSTERIAN MICHEL 11970 519940619930511389 9852.7242CVENTE
+4299PAIX MICHEL 11970 31994011993011420611637.1142MSANS
+1722ALBERT GEORGES 11970 71990061992091202810240.8242MSANS
+7839LORRAINE DANIEL 11970 81993121992121420611639.2242MTECHN
+2390VENISE JEROME 11970 6199406199306 9597 8728.5342CSANS
+4622BOUTON SERGE 11970 71992111991111420611638.5042MALLEM
+8468MONTALEIGNE FRANCK 11970 61993031992031420611637.8042CSANS
+4926LEZARDIERE JEAN CHRISTIAN 11970 819930119920111389 9852.3842MSANS
+0318MISSIONNAI FRANCOIS 11970101994021993021420611639.2442MSANS
+2478CENAC ANNE MARIE 21971 11992071991071420611637.4442MESP
+9531FLEURIES PATRICIA ODILE 21971 6199612199512 9894 8921.9442CSANS
+2370ARTOIS MARIE MADELEINE 21971 919930219920211389 9851.2442CSANS
+9824CLAOU JANINE 219711019941019931010668 9425.7342CANGL
+0436BUISSON JOELLE 21971 519950119940110668 9426.4142CSANS
+6968RABELAIS CHANTAL 21971 619951219940110668 9426.3242CSANS
+6232CASE CHRISTIANE 21971 61994051993051267210588.8542MANGL
+5473GERANIUMS JEAN 11971 11990051994011249910472.9242CSANS
+1033ISLE JEAN PIERRE 11971 51992081994011249910473.6342CTECHN
+6691MONTAGN PIERRE 11971 91991091994011249910472.5942CSANS
+3613TRONGET FREDERIC 11971 219940419940110363 9232.4642MSANS
+5033GENELLES PASCAL 11971 81991121993061330611018.0142CSANS
+5241KENNEDY PHILIPPE ANDRE 11971 219930619920611389 9850.5642CSANS
+2276MESANGES JEAN PIERRE 11971 11991081991091202810241.0342MCOMPT
+4273HOLLYWOOD THOMAS 11971 41993021992021420611639.1042MANGL
+9172PITCHOUM JEAN CLAUDE 11971 119921019930410876 9502.9942CSANS
+2512GACHE JEAN CLAUDE 11971 81994091994011202810240.6442CSANS
+4896CHILHAC GUY 11971 219930119920111389 9850.7642CANGL
+3539MAS JEAN FRANCOIS 11971101992071991071420611637.6042CSANS
+4359GAULLE LOIC 11971 419930219920211389 9852.0542CSANS
+0794SOCLATE ALAIN 11972101994051993041360611211.0542CSANS
+6685CONSOLAT JEAN PAUL 1197211199503199304 9597 8729.5842CSANS
+3658BACON STEPHEN 119721119930219920210363 9231.8642MSANS
+5829RAINIER YVES HENRI 119721219930119920110363 9231.9642MTECHN
+5038ROSE JOCELYN 11972 41994011993011420611638.5042CTECHN
+1479NOEL JEAN PIERRE 11972 219931119921111389 9850.8342CSANS
+3997RICARD SYLVAIN 11972 61992051991051420611637.5642CANGL
+6600LOUP KAZUKO 21972 519931019920811389 9852.2042CSANS
+9876VOUZON CHRISTINE 21972 11993101992101723313654.7242CINFOR
+2373RAPAILLOU THIERRY 11972101992121994011202810240.0542CSANS
+1153RIBERA FRANCOIS 11972 3199406199306 7590 7563.9942CANGL
+0976AIR FREDERIC 119721119940219930211389 9850.6242MSANS
+1075COLOMBIER JACK 11972 6199401199301 7590 7562.5442CINFOR
+3036SOISSONS THIERRY 11972 71992021991091420611637.7442CSANS
+7541HIER MONIQUE 21972 11993101994111288210743.9942CSANS
+8819RHIN JOSIANNE 2197212199407199307 7803 7679.9442CANGL
+4699LENTISQUES FLORENCE 21972 6199501199401 9894 8923.2942CSANS
+5011CIGOGNES MARIE FRANCOISE 21972 3199605199505 7803 7681.0242CSANS
+7216FARRERE CHRISTIANE 2197212199408199308 8359 7953.2942CSANS
+9971SALVADOR REMY 119731219951219941210668 9425.9942CSANS
+6878BIGUET YVES 119731219940219930210668 9425.5842CANGL
+9980LACHAMP CHANTAL 2197312199306199206 8359 7953.7242MSANS
+3279ROITELET CHRISTINE 21973 819941219930411389 9851.8742CESP
+9903PROVENCE VINCIANNE 21973 2199411199311 8359 7953.6342CVENTE
+6941MAT SYLVIE 21973 919930719920711389 9850.7042CMARKT
+2424PLAINE ELIZABETH 21973 419950419940110668 9427.4942MANGL
+4221SOLOGNE ERIC 11973 619940619930610668 9427.2442CTECHN
+8519ERABLES DANIELLE 21973 419931019921011389 9852.6742MANGL
+7323SAUME ISABELLE ANNE 21973 919950319940310668 9426.6242CANGL
+2143CUQUES HELENE 21973 6199612199512 9894 8922.0042MESP
+5163SOULELHAT CORINNE THERESE 21973 9199407199307 8359 7953.0642CANGL
+9032PETILLAT PIERRE 11973 41992091994011249910471.7442CSANS
+9059DARONNE JACQUES 11973 419940619930610668 9426.4142CANGL
+6626DEVESSOUS JEAN CHARLES 11973 91994071993071206910241.5842CSANS
+7108BUISSONNETS HENRI 11973 419930419920711389 9851.6142CSANS
+0443FONTAINE YAN 11973 9199406199306 7464 7524.2142CESP
+3078CHARBONNIERE JEAN PIERRE 119741019931019920711389 9852.2942CSANS
+5301REYNAL JEAN LUC 11974 6199401199212 9597 8729.6742MINFOR
+7425RAFFAELLI PHILIPPE 11974 319940719940111389 9851.8842MINFOR
+9638SYLPHES PAUL 1197410199407199307 9894 8922.5742CMICRO
+9287ROSSAYS MARIE CHRISTINE 219741019960419950411389 9851.3443MANGL
+9554PILGRIMS JEAN PIERRE 11974 219931219921111389 9852.0242MSANS
+0960BOCAGE JACQUES 11974121993091994011202810240.9442CSANS
+7246PEYRIERE MARIE CARMEN 21974 419940719930710668 9426.2242CANGL
+3039COMBRAY MARC 11975 4199607199507 7803 7680.7542CSANS
+5779SAENS ANNIE 2197510199608199508 7803 7680.8942CANGL
+8044FERRY ROSINE 21975 9199507199407 7803 7679.8742CCOMPT
+0191KER MARIE HELENE 21975 3199611199511 9256 8533.0242MSANS
+6974MANCINI JEANNINE 2197511199408199308 7803 7679.7642CANGL
+0518VICTOIRE PATRICIA 21975 3199608199508 7803 7680.8042CSANS
+1262TRAUD JACQUES 11975 819940519930510668 9425.9642CMARKT
+7772MOZART SOLANGE THERESE 2197610199608199508 7803 7679.4142CALLEM
+9670GRESSETS LAUREEN 21977 8199607199507 7803 7681.0442CSANS
+8996ADRET CELINE 21977 3199608199508 7803 7680.6242CANGL
+3676MENEZ MARC MAXIMILIEN 11933 91966071994011932314935.3843MALLEM
+9549BOURGOGNE ANNICK 21936 41968051991102137316331.4643MSANS
+9677BROQUERIE CLAUDY 219381219780719910611131 9658.3743VSANS
+4456LAC PATRICIA 21938 81962041985062470018542.2243MANGL
+6693FENELON VALERIE 21939 61959121986012273717261.0743MTECHN
+0887NASTRINGUES BERNARD 11939 81962091992032137316331.2443MESP
+7338AMBROISE RENE 11940 91968041995011557012566.9943MSANS
+0858TURNEGOUET DIDIER 11942 71982011993011249910473.0043MSANS
+8537VERT PATRICK 11942 61976121993011578112722.9343MSANS
+3521HOUEL PATRICK 11942111970091995011557012568.2243MSANS
+2105ROCAL JEANINE 21944 51970071991071578112723.3343MANGL
+6696PLAIDEURS JEAN PIERRE 11945 91972121990011403411520.4243MANGL
+1309BELLE MARIE MARTINE 21945 31965011988042470018541.9743MSANS
+9127PENFOULIC EMMANUEL 11946 5198901198801 9894 8921.9943MESP
+2831CHAMAS MIREILLE 21947 21969031993031834514274.8443MINFOR
+1888BONJOUR GUY 11947 91980101993101471512024.6243MANGL
+1642POURTEL FRANCOISE 21948121974111994041471512026.1543MANGL
+5118QUINTANA NADINE 21948 6199406199304 9126 8457.3343MSANS
+7220LANDON JACQUELINE 21948 91970071994092529918967.9843CSANS
+5846ROI PATRICIA 21948 11971051991102043315669.5743MINFOR
+6443JUIN DAVID 11948 11975061991012137316331.7043MSANS
+1072BELLY THIERRY 11949 91979041992011249910472.6143MANGL
+3513GAMA VALERIA 21949121969021990071578112722.3343MANGL
+8936MARGUERITE MICHELE 21951 41973021993012017815516.0843MSANS
+9731GILLES NICOLE 21951 319961119951110668 9426.2743MSANS
+3374ROBESPIERRE CORINE 21952121973021991012781920675.1943MSANS
+9500EDELWEISS GERARD 11952 21978011992111684813422.4443MANGL
+9602PARADOU MICHELE 21952 51975051981091684813422.6843MSANS
+4313BERNEDE AGNES 21954111975041991071578112723.7243MANGL
+9347LAUZES MICHELE FRANCOISE 21956 91978061992051471512025.7043MANGL
+9922BELLA MARIE THERESE 21956 61982041981041326611018.1043MINFOR
+9508ROBERT PATRICIA 21957121979071994121911114778.0643MSANS
+9342GALLERANDS PAULETTE 21957 419950219930411389 9850.7043MTECHN
+8765ELANCOURT BERNARD 11957 71980081993061369311286.1743MSANS
+8497RIBOT JOELLE JACQUELINE 21957 21977071992121527112373.0443MSANS
+6373RENE CLAUDINE 21958121978041992021471512024.3543MANGL
+1513FRANLAINE BLANDINE 21958 91984101985041527112373.9543MSANS
+1684CHALEIL MICHELINE 21958 31978061993101471512025.3243MANGL
+2983LAVIE JACQUES 11959111988031994011249910471.9743LALLEM
+3412CORTIJO AGNES 21959 31983011982011608112915.7843MSANS
+4467VADEL JEAN MARIE 11959 51991041994011202810241.3943MSANS
+9453CAVILLON MAURICE 11960 61985111992071288210744.4643MALLEM
+7623MALESHERBES BRUNO 11961 81984081991061326611016.7443MTECHN
+1600BLANCHES MARIE CHARLOTTE 21961121990031993061249910472.0143MALLEM
+7714POMMIERS VALERIE 21962 41993081992011249910471.6143MESP
+7193CAMBARRAS PHILIPPE 119621119930119920110876 9503.2743MALLEM
+0639TANQUEUX FREDERIQUE 21962 61982081989112090215980.8243CSANS
+8276LACROIX DIDIER 11962 61991101993041467711986.8943MSANS
+5057CINO GERARD 11963 61983111995091693613498.3143MINFOR
+0238SARRAZINE MARC 11963 619941119931010363 9233.5743MSANS
+7129NIVERT THIERRY MICHEL 11963 519910419940111302 9775.7943MSANS
+8602PYRENEES DANIELLE 21964121993091992011202810240.5943DESP
+6662PUERTO SYLVIE 21964121985101984101249910473.5643MSANS
+7625SCHWEITZER LAURENCE 21964111991091990091202810240.4643DANGL
+7052CARREAUX SYLVIE 21964 61985021984021288210744.6743MALLEM
+9218SALIS ARMELLE 21965 3198801198601 8656 8146.6143.SANS
+3260JABLINES JEAN JACQUES 11965 41990091995092256617145.3043MSANS
+9721LAVOIR YVES 11965 619930119921011389 9852.1443DALLEM
+3429CAM BERNARD 11965 61987021993051839014313.5743MSANS
+1856FLAUBERT PASCAL 11965101985061994111693613498.5543MSANS
+0790JARDIN SERGE 11966101987091992101539912453.0643MSANS
+2445VIESCAMPS YANNICK 11966 11991111991101381911365.5343MSANS
+5684SARRASIN PATRICK 11966 51994101993101267210589.3943CSANS
+4794DIAZ PHILIPPE PIERRE 11966 21987111993111693613499.4543MSANS
+5479THIREUIL GILLES 11966 31992041992011202810241.0343CSANS
+6199HELEN MARTIAL 11967 91987081995011373711326.7043MSANS
+9298FOUQUET RAYMOND 11967 419960619950611389 9852.2943DINFOR
+7535COURTELINE PHILIPPE 11967 11991021994011249910471.6143MTECHN
+4595PANSEROT JEAN JACQUES 11967121989091989061539912452.5143MINFOR
+4584SANGUI PHILIPPE 11968 219950119950110363 9231.9543MSANS
+1356BERTIN MARYVONNE 21968 41993061992061267210589.6943MMICRO
+3761GARD HENRI 11968101989071993091723313654.6543MSANS
+6649GUILLAUMET LAURENCE 21968 71994021992011202810240.3543CSANS
+2548LYCEE ALAIN 11968 51993121994011202810240.1743CSANS
+0307ABBAYE ANNICK 21968 919920919910911389 9850.7443MSANS
+0524PEYRILLES YOLANDE 21969 119940719930411389 9852.5943MSANS
+3086FABRE JEAN YVES 11969 71989121994041249910473.2443MSANS
+2273BREUIL SERGE 11970 719891119920811302 9774.3843MALLEM
+5532NIRVANA FRANCIS 11970 419920219920810876 9502.1443MTECHN
+0282TOURISSE BERNARD 11970 41994081993081360611211.4743CANGL
+8554BOUVIER OLIVIER 11970 81993061992061267210590.5443CANGL
+3126PONTAROUX JOCELYNE 21970 619930619930411389 9851.1943MSANS
+0208ENCLOS DIDIER 11970 219941019950110363 9233.5443CSANS
+5629VENEUX JEAN 11970 319930919920911389 9851.7443CINFOR
+9569CASCADES MARYVONNE 21970 91991101990101202810239.7843CSANS
+4663DAUBERIE DOMINIQUE 21970 919941019930411389 9851.1543MSANS
+3912FOURNAS MARIE 21970 119930819920711389 9850.8343CTECHN
+2317CALDANA ODILE 219711019940519920111389 9850.7943MANGL
+4841MARIDOR CLAUDIA 21971 4198907199101 8656 8146.1643.SANS
+3038FERRARI FRANCOISE 21971 2199206199106 7803 7681.2543.ANGL
+3547KERA MICHEL 11971101994101993101360611209.9243CSANS
+8801ORRES JEAN JACQUES 11972 91994061993061420611638.1043CINFOR
+8995CRUCITA PHILIPPE 11972 11993041994011249910472.5743CINFOR
+1636NORVIL BERNARD 119721119930919920911389 9850.9243CSANS
+7758AURES JACK 11972 5199309199209 9597 8728.6443CSANS
+9063SATIE OLIVIER 11972111994061993061420611639.0643CSANS
+9116BREVIAIRES LAURENCE 21972 119930419920411389 9852.3343CINFOR
+3743SORALY ALAIN 11972 4199407199307 9126 8455.8443CANGL
+9641ASTARAC CATHERINE MONIQUE 219721019940619920111389 9851.6943CALLEM
+1350RAMBUTEAU RENEE 21972 61993091992091360611209.6543CSANS
+0615ROBERT REMI 11973 51994011993071267210589.9343CTECHN
+2872KERPETIT ALAIN 11973121994041993041420611637.8043CSANS
+9594BENEDICTINES JACQUES 119731219931119921111389 9851.1543LSANS
+5147TERRESROUGES DIDIER 119731119930319930311389 9852.2443CSANS
+3464CASTERAN EVELYNE 21973 519950219940210668 9426.1843MSANS
+1330INFERIEUR CHRISTIAN 1197411199607199507 7803 7680.0543CSANS
+0129DEGANNE WILLIAM 11974 91994071993071206910241.9743CMARKT
+9626STENDHAL CLAUDE 11974 51994081994121202810240.0543CSANS
+8520COUPERIN JEAN 119741119940519930510668 9425.5843CSANS
+7404PERGOLESE RICHARD 11974 31994051993041360611211.5143CANGL
+2352ECLUSE BEATRICE 2197411199608199508 7803 7680.6243CCOMPT
+6779PERRONET PASCAL 11974 91994061993061360611210.9143CANGL
+9456REVOIRS MARC 1197512199507199407 7803 7680.9943CINFOR
+9467CONCORDE CLAUDE 11975 919941019931010668 9427.4443CSANS
+7348GENOUILLY FREDERIQUE 21975 7199407199307 7803 7680.4443CANGL
+8390CEILA DOMINIQUE 11975 9199409199309 9894 8922.7243CSANS
+3308BOULANGER RENE 11975 6199410199310 9894 8922.0043CALLEM
+8061DENFERT VALERIE FRANCOISE 21975 11995041994041206910241.1243MSANS
+9867ROCHOPT MARIE PIERRE 21976 8199609199509 7803 7680.2343CCOMPT
+0466MIMOSAS CHRISTIAN 11976 1199408199308 7803 7679.3143CSANS
+6069BATIGNOLLES MARTINE 2197710199608199508 7803 7679.2843CSANS
+7049CRENON DANIEL 11947 81973041994011621213032.3044MSANS
+1304PERI VERONIQUE 2194912199310199210 9597 8729.0944MSANS
+3258DARMONT VERONIQUE 21961 21986061992021168610047.0344MSANS
+1840COQUART LUCILE 21964 41984101993051381911365.0544MANGL
+2897PERCHE ALAIN 11967101990061995011318010939.1344LSANS
+6181BIZET MIYUKI 21968 2199302199202 9597 8727.9944MSANS
+6750EDGAR HERVE 11971 21992011991011202810240.5844LSANS
+0175MARQUIS COLETTE 21974 5199606199506 7803 7680.2744CSANS
+1275FRIGOULET YVES 1197410199506199406 9894 8921.6944CSANS
+8305BEZENAC FRANCOISE 21953 2199404199304 9126 8455.7045MSANS
+4858DUPLEIX MARC RENE 11954111978121982102470018541.8845MANGL
+6314ABERDEN EVELYNE 21958 61979111978111684813423.0845MSANS
+0464PETIGNONS DOMINIQUE 11961 91984061993031527112374.9745MSANS
+3847GUICHARD PHILIPPE 11961 11983081988112090215980.9745MTECHN
+8173HOPITAL ANSENIA 21964 319950419940110668 9425.3645MSANS
+4339VILLE DOMINIQUE 11971 91994111993111267210589.1245CSANS
+1142SPITALIERI FREDERIC 11933111953121993014121428007.2246MALLEM
+6086SOEUR JEAN JACQUES 11935 91955061991053417325097.9646MSANS
+0246OREE PATRICK 11937 71965101986012470018541.1946MANGL
+7398MOUNET CLAUDE 11937 919960119950510024 8999.3946MSANS
+2438VISITATION CLAUDE 11938 31964111986012470018542.2446MSANS
+3413ETIENNE JEAN MARIE 11940121969051986072470018541.1146MSANS
+9044GUEN PAUL 11941 11973051993011518612335.2846MINFOR
+4544MONEGLIA ABDELKAD 11941121965101989072947921838.8046MINFOR
+5661BELLON PHILIPPE 11943 91965111994013200223584.4346MSANS
+4296VENDARGUES YVES 11943 31964111991012273717260.1446MSANS
+2281TRIMARAN OLIVIER 11944 81973051990011403411521.4646MINFOR
+9015IRIS YVES 11945121973011990011403411522.1346MESP
+7856BELLEVILLE GERARD 11946 31965101986012470018540.2946MSANS
+9041SADI PIERRE 11946 61977121995062000715437.9146CINFOR
+2976BLANQUI GIANCARLO 11946 51968091986072273717261.9446DSANS
+4370GROUPE PHILIPPE 11947 21974071990011403411522.0946MTECHN
+7697SEYSSINS BERNARD 11948 51968071991012470018541.8646MALLEM
+9305SEINE GUY 11949 91970041987012273717259.9046MANGL
+5926BOILEAU BERNARD 11951 61972051989012273717261.9046MALLEM
+3592PETIT GILLES 11951101974011995032547019085.7046MANGL
+7590PLAYA JEAN YVES 11954101977091982102470018541.4746MSANS
+8144DARIE JEAN PIERRE 11954 21995011994011420611638.9246MSANS
+8637GUILDFORD PHILIPPE 11955 21974061995082547019085.8646MINFOR
+7809CEYRESTE FRANCIS 11955 31975021993081608112916.2546MSANS
+9226MONDONVILLE MICHEL 11956 51979011992011471512025.1146MTECHN
+8675BLANCHISSEURS ANNIE 21958 11979071993041471512024.3346MSANS
+0338BARBUSSE ROSELYNE 21958 1198902199209 9597 8729.2546MSANS
+4849SANZILLON MARIE NOELLE 21958 81979101978101288210743.8346MSANS
+7791PRA BRIGITTE 21958 81981041980041684813422.0846MSANS
+3255LENOTRE BERTRAND MARIE 11959 81980111991012022115555.6246MESP
+3148EOLIENNE GUILLAUME 11959 11983031991011868714507.9446MSANS
+1942CAUSSES MICHEL 11960121987081991061288210745.4746MSANS
+8983RAYMOND JEAN LOUIS 11961 11985031991011868714506.7246MSANS
+5296BRETAGNE PHILIPPE 11961 41983081991011868714507.7246MSANS
+0323QUONIAM GILLES 11961121983051993091450311831.5746MSANS
+3231MOULIN HUGUES MARIE 11961111985091995011373711328.2246CSANS
+9926PIN PATRICIA 21962 41984051983051288210745.7546MSANS
+0400HARAS PHILIPPE 1196312199407199411 9597 8728.1746MANGL
+8313ROUILLAC BERNARD 11964 31991021991022529918968.4746MSANS
+1947CORNEILLE DOMINIQUE 11965111987021994091693613499.4346MANGL
+1364KERSAUX JACQUES 11965 41987091986092090215981.4746CANGL
+4571CAILLOU ERIC 11965 91985041992071616712995.9946CSANS
+5043BAC MONIQUE 21965 61988081987081539912452.4646CSANS
+5037CALLE PHILIPPE ROGER 11966 81994091993091839014312.4546LSANS
+3072PONTHION ALAIN 11966 21990091989091467711987.1346MANGL
+3441ARMAINVILLIERS YANNICK 11966 11987021994091693613498.8546MANGL
+2298PLESSIER ANNE MARIE 21967 2199004199111 8656 8146.6146.ANGL
+3281ALBAN ELIANE 21967 21986111992011288210744.0846MSANS
+1984ROCH GERARD 11968111992031992041467711986.7246MSANS
+6981TROQUEREAU JEAN JACQUES 11968 91992081991081467711986.2646MALLEM
+4384LAMORLAYE MICHELE 21968 31993121992011202810240.1746MSANS
+4391JUGE BERTRAND 11969101992091993072397418036.9346MSANS
+4122CAULAINCOURT YVES 11969101988081987081539912452.1646MINFOR
+5356LACAPELLE ALAIN 119691119930419920411389 9852.0246MTECHN
+8278CHANTEMERLE GERARD 11969 919920619940710876 9503.4546MSANS
+2596DESSUS GUILLAUME 11969 11991091990091467711986.4946MSANS
+7596MEYERBEER EDOUARD 11970 11992111992111330611018.1046CMARKT
+5724HOCQUETTES AUDE 21971 31991071990071467711986.3146MSANS
+1372AUBEPINS CHRISTIAN 11971 21994101993101360611209.8846MALLEM
+8783BAUDOIN JEAN FRANCOIS 11971121993081994011202810240.4146CSANS
+3416MIREFLEURS NORIKO 21972121994021993021360611211.5646MCOMPT
+0948TIERRAINE MARC CAMILLE 11972 319930719920711389 9851.5946MTECHN
+0904FOUGERES JEAN MARIE 11972 919920119920311389 9850.8946CTECHN
+4010QUARTRAVEL CATHERINE 2197211199501199401 9894 8921.7246MSANS
+1528FARMINGTON RENEE 21973 119940419940111389 9851.0346MSANS
+8402TREZEE GILLES 11973 919930719920711389 9850.8846CSANS
+7279CORNE GUY 11973 71994011993011360611210.3746CSANS
+0232PIN JEAN CLAUDE 11973 519960619940110668 9425.4546CTECHN
+9635MAGALI CHRISTIAN 11974 4199607199507 8656 8147.2246CALLEM
+7035ANGLAS LUCIENNE 21932 21963011988102273717260.1448VSANS
+7818HERZOG DOMINIQUE 21937121972101993041557012567.0848DSANS
+6478MAREYE JEAN PHILIPPE 11940 21959101983102273717260.8048MSANS
+1661VAN EDITH 21940 81974091990012137316330.9748MSANS
+1597MATRAT CATHERINE 21940 61967071992121834514275.5948MTECHN
+1046MAUNY JEAN CHRISTOPHE 11941 81979021994011471512025.4748MSANS
+8249FILLES MICHEL 11942 51962081993093417325097.1948MSANS
+0711PICCINI JEAN JACQUES 11943 81963041995072470018542.0048MSANS
+0378HALLIERS JEAN PHILIPPE 11943 3199501199401 9597 8729.3648CALLEM
+9597VOLTE MARIE THERESE 21946 71968041990012273717260.9448MCOMPT
+4768PICAUD BRIGITTE 21947101973101995102043315670.9248DSANS
+0554ROLAND ANNE 219471019920719910710024 8998.7748DSANS
+3349SERRE PIERRE MARC 11948 61969021991012470018542.1048MALLEM
+3355KURFURSTEN PAULE MARIE ODILE 21948 7199501199301 8656 8145.6648MSANS
+6449IRUENA DOMINIQUE 11949 71969031990051932314934.2748MESP
+3922LAVERSINE YVES 11949 81975101986103634926571.4148CSANS
+7286JOUVENET HENRI 11951121981021994011621213032.6548MANGL
+2199CABOTS CHRISTIAN 11953121988121995011373711326.7148MINFOR
+8300CHARPENTIER CHANTAL 21955 61992011993041249910472.4148MSANS
+2397FAMILIAL JANY 11955 61982101994041471512024.3348MANGL
+9021BIED CLAUDE 11957 51980061992111911114779.6848MSANS
+4703COZ JEAN 11957 41979081993121911114779.7748MSANS
+3297STALINGRAD BERTRAND 11959 31981081992102090215980.9748MANGL
+2319FRANCOEUR HENRI FELIX 11959 11980081993121804514081.0148MSANS
+8833MONTLHERY ELIANE 21960111983041989041527112373.6848MANGL
+1084MAGNARD JEAN PIERRE 11960 91984021992012022115556.0248MSANS
+4562HAUTE ANNIE 21961 61984061983061249910472.8748MTECHN
+4907FRANC BERTRAND 11964 21984081986072090215980.5648CSANS
+2492ETANG PASCAL VINCENT 11968121990111989111467711986.6248MANGL
+3754RAOUL FRANCOISE 21968 91994031993091450311831.8448MTECHN
+7902CELARD BERNARD 11969 31990041989041467711987.9048MANGL
+0316FLORENTIN TYRONE 11969111989081989021450311832.4148MANGL
+1981DEPARTEMENTALE PIERRE 11970111993041992041420611639.0148CSANS
+4735BEL SKEVOS 11970 61991021994011249910473.5448MSANS
+0999CONNE DENIS 11971101993041992041420611638.8848CSANS
+3832BEACH SERGE 11973 41994121994011202810241.1248MTECHN
+4697PURPAN FRANCK 11935 51976041994011578112723.1550MTECHN
+1565NEMOURS ANDRE BERTIN 11939101967071990091932314934.3150MANGL
+8977MAHATMA HERVE 11942 41981051994011621213032.0650MANGL
+8738ZILINA JEAN LOUIS 11942101980061990031249910473.4750MTECHN
+6415ECUREUILS ERIC WILLIAM 11942 61969081994011932314934.7050MSANS
+9332FRIRION GEORGES 11945 5199409199309 9597 8729.4950MSANS
+5001YVES PHILIPPE 11945 41975111988071578112722.8750MSANS
+2290ENSOLEIADO JEAN MICHEL 11946 21988051994011288210745.5250MSANS
+8492LAGRIVE LAURENT 11947 81982011993011369311287.2950MANGL
+3609GUESDE ERIC 11949 11989061992031249910472.1950MSANS
+8482TOUT ANDRE 11949 71980041995011621213034.2250MANGL
+8866PERCENEIGE PASCAL 11950 41976071995011578112723.7450MSANS
+3195VIVE CLAUDE 11950 21981081995011621213032.2050MSANS
+2538AICARD SABINE 21954121976061993031608112915.5150MTECHN
+5185LUTHEZIEU PATRICK 11955 51988021994011288210744.2650MANGL
+3135EDER DIDIER 11957 819880119930310791 9502.9150MTECHN
+9006MAURETTES JACQUES 11958 11985041993011369311286.6950MINFOR
+8049COLLIERES CHANTAL 21961 11984031983031288210745.2250MTECHN
+8766TERROIR GILLES 11963101987121989091450311832.4150CALLEM
+2924LAC BRUNO 11963121989051988052090215981.1450MSANS
+5549DUMONT MICHEL 11964 51988051991081450311832.4250MALLEM
+8382MONSEIGNEUR CHRISTIAN 11964111992011994011249910471.8950MSANS
+8129STATION BRUNO 11966 41994051993051202810239.8750MANGL
+3420EMERIAU JOSE 1196711199306199206 9597 8729.8450MANGL
+9831CLAMOUR YVES 11967 819950919940910668 9427.4950MANGL
+9072MENDON GUY 11968 1199605199505 8656 8146.8850MSANS
+4669FAURE ERIC 11968 3199505199405 9126 8455.8850CTECHN
+4319MOURISCOT PATRICK 11970 9199306199206 9597 8729.2750LSANS
+1731FRANKLIN MICHEL 11970 4199401199301 9597 8729.4050CSANS
+0510PILOT DANIEL 11972 519961219951211389 9851.5250CSANS
+5973LECLERC MAURICE 11974 3199606199506 8656 8146.3750CSANS
+9358MONBEL HENRI 11933 91959031993011557012567.1251MVENTE
+7641BRETONNE CHANTAL 21936 51962081990012273717260.9451CSANS
+7048CASTELNAU LAURENCE 21937 91962031991042273717259.7851CMICRO
+5481PASCAL GILLES EMILE 11937101958051979013327724476.1651MSANS
+6723SARRAZA FRANCOIS 11938 21962031989082572519240.3551MSANS
+6355REPOS JEAN MARC 11938 41960011980013327724476.5251MSANS
+1644ACARDIE BEATE 21939 31963091991072273717260.2251CTECHN
+5030LOGELBACH ASTRIDE 21940 11962031991042137316332.4551MVENTE
+5298GARDE MARIE FRANCE 21940 91969011989011621213034.1951MALLEM
+6400SIONIE CATHERINE 21941 3196206196106 4894 6128.0051MTECHN
+5537CAPEOU LUCE 21942 519931219920110024 8999.7951DINFOR
+7143DEO NOBUKO 21942 41969091991102137316331.9751MSANS
+9555CAMBRONNE DANIELE 21943111962051984122572519240.2851CSANS
+3792EAUX JEAN 11944 81966031995072137316330.9751MSANS
+6932PAULIN ISABELLE 21945 41972041989011621213033.2851MALLEM
+1308CHRISTOL MARTINE 21945111968121993061834514274.8451MSANS
+2877DANIELLE GERARD 11946111970051992011471512025.1151MSANS
+5367ILE FRANCOISE 2194712199010198910 8656 8146.1451.SANS
+3253VERG BIRGIT AGNES 21948101969071985042470018540.3951DANGL
+5806FRED CATHERINE 21948 41968041990042572519239.8251MANGL
+6174BANQUIER CATHERINE 21950111971061989011621213033.7051MSANS
+8732FOUNSUT PIERRE ANDRE 11950 11978071995041249910472.1051MCOMPT
+4803ALASSEUR AGNES 21950 71974051992091471512026.1051MSANS
+9024CHATARDS CAROLINE SOPHIE 21951 31972081987052334017609.4651MALLEM
+1259SOUFFLOT FRANCOISE 21952 81981011983091326611017.2551CSANS
+7009PARADIS LUDWIKA 21952 71974011973011215710279.1951MSANS
+9186LESPIAT EVELYNE 21952111973041990101578112722.1551MSANS
+6834FLEMING JOCELYNE 21953 41973021993012017815517.2851MMARKT
+5164BEAUVILLAGE COLETTE 21953 91986081985081684813421.4051MSANS
+4947ESCALUS CHANTAL 21954 219810519800510024 8998.4151MSANS
+8461MARGUERITES CATHERINE 21955111976061994051471512025.0151DSANS
+5391FOURCAULT ANITA 21956 61978061992091471512024.4451MSANS
+2777ALMUNECAR CHRISTINE 21958 41993071992011249910471.6251MINFOR
+9747DROPT MONIQUE 21958 31979031993041471512024.0851MANGL
+2758CRAYS KIM LEE TAMARA 21959 11992031991011202810240.1951MSANS
+8238SERGENT ISABELLE 21959111983061982061326611016.0351CSANS
+4402DIVISION SABINE 21959 71979101993071471512025.1651MALLEM
+1231FACE HUBERT 11959 319950319940111389 9852.6751LTECHN
+3907ESBLY GUNDA 21960 81980071979071288210745.3451MANGL
+4821TAMEYE MERCEDES 21960 119820919810910668 9426.6651MANGL
+1175CRESY CHRISTIANE 21961 21990111989111249910471.6651SSANS
+6825FEUILLES DENISE 21961 51982051981051326611016.0651MANGL
+5368FLANDRE SUZANNE 21962 71983111982111249910472.3351MANGL
+0947LORRAINS CHRISTINE 21962101985041984041288210745.1651MALLEM
+5318CLAMART ANNE 21962 51982081981081326611018.0051MSANS
+8693FILLIETTE JEANNINE 21962 31982091981091194310201.7051MANGL
+5069GRAVELLE ILSE BERTI 21962 81992061991011202810241.9051CSANS
+5908VERTS CATHERINE MARIE 21962121984111983111608112915.9651MSANS
+3068DUNKERQUE ELIANE 21962 31986101985101202810240.4051MSANS
+5894CARESTIER MARYSE 21963 41985091984091288210745.1351MALLEM
+1739HILARION LAURENCE 21963 61982091981091497412179.3651MSANS
+8326MASSAY MARTINE 21963 41984091983091608112915.6951CANGL
+6923GUYONNE NATHALIE 21963 81983101982101608112915.7551CVENTE
+3533SAVIGNAC SERGE 11963 319890319880310407 9271.2351MSANS
+9590GARIBALDI FLORENCE 21963 519940619920111389 9852.0051CANGL
+5287HORIZONS MARIE ODILE 21963 21983021982021249910471.5651MSANS
+9152PARRERE PHILIPPE ANDRE 11963 61992021991021381911366.2151CSANS
+4730CROISETTE MARC 11963 61987111992012529918968.2051MANGL
+7896LONGUE MARTINE 21964 91986041985041288210745.7251MSANS
+0156CHTANOU YVES 11964 71993011992011839014314.0851MANGL
+3013CELLIER REGINE SYLVIANE 21964 719870619860610668 9426.4151MANGL
+1040HAUTI MARTINE 21964 11984101983101288210745.3951MINFOR
+0730COURBET CHRISTINE 21964101984101983101202810241.7051MSANS
+2393ROTONDE ELISABETH 21964 71984071983071202810241.8451MANGL
+6940LELIEVRE RYOKO 21964 21985051984051527112373.2351CSANS
+5571MARCEAUX ANDREE 21965 31993091992011202810240.2251MSANS
+9937MANDARINE GHISLAINE 21965 11994031992011202810240.9151MANGL
+6185HERMITTE FRANCOIS 11965 91990051989051949415051.5051CSANS
+5405ARTZAMENDI MICHELE 21965 71989081988111949415050.6751MANGL
+4260MIROMESNIL MARTINE 21965 71988031987031450311830.5351CSANS
+9396BARBUSSE MICHELLE 21966 91986061993011839014313.0951MSANS
+8592PLANTIERS MARTINE 21966 71994031993031267210589.5751CSANS
+6905HAVRE PATRICK 11967 61988111987112090215981.2251MSANS
+0499BEAUMARCHES JEAN PIERRE 11967111990021994051839014313.9551MSANS
+9812PECHERIE FLORENCE 21967 219940419920111389 9852.2251CESP
+6177RIQUET JANINE 21968 51994031993031267210589.6651CTECHN
+1459FRANCE ANNE MARIE 21968 21988091993011381911366.4951CTECHN
+9340EPINE RENAUD 11969 11994081993081206910239.8651MSANS
+7293OBERKAMPF JEAN JACQUES 11969 81989041993041249910471.7051CCOMPT
+0852GUERARD MARIE SOPHIE 2196911199308199208 9894 8923.1651MESP
+8275DELZONS MICHELE 219691119930319920311389 9852.7251CALLEM
+5873MARCHE MARIE LAURENCE CHRIS2197011199205199105 9597 8729.3051MSANS
+8465BERNASSE ISABELLE 219701119920319910311389 9852.6551MANGL
+2444BOUGNON MARIE JEANNE 21970 81993111992111267210590.7451CSANS
+3440BAZOCHES MICHELE 21970111993101995041206910240.4151MSANS
+2864GOAS SERGE 11970 51992101993081267210590.4151CESP
+5499CLOHARS GERARD 11970 819900819890810024 8998.8451CSANS
+6120MARVIVO EVELYNE 21971 519950219940210668 9426.5351MSANS
+5419BEZANLEU CATHERINE 21971 51994031993031267210590.2951MTECHN
+0309TUILERIE SOPHIE 21971 21994051993051267210590.6951CSANS
+6131CAGNES NICOLE 21971 519940619930610668 9426.5351CCOMPT
+8518VILLOUE JOELLE 21971 61992041993051267210590.0951CSANS
+8453JONCHERE DOMINIQUE 11971 319940619920110024 8998.7651MSANS
+5604NEUILLY AGNES 21972 119920419910410668 9425.8151MSANS
+7047ALOUETTES MARIE ANDREE 21972 419920119910111389 9850.9451CSANS
+5306BOPENIAN MONIQUE 219721019920919910911389 9851.9151MSANS
+9169FLEURIS LILIANE 21972 71993121992121267210588.9251CANGL
+8308BUZENVAL VERONIQUE THERESE 21972 5199607199507 7803 7679.4151CALLEM
+1210NAUGAIRE MARIE ANTOINETTE 21973 61993081993091267210589.5252MSANS
+5105HUGO CATHERINE 2197311199607199507 9894 8921.4651CANGL
+3726LIVRYS BRIGITTE 21973121995071995051288210745.4751CSANS
+5859MUZY PASCALE 21973 619930719920711389 9850.6151CVENTE
+1436SAUVE DOMINIQUE 21973 61994101994121206910241.1351MSANS
+2239CHALIGNY KYOKO 21973 31994091993091206910239.8651CSANS
+0183LAURIERS PAULE 21974 81995111994121206910241.2551CSANS
+9366PINET LAURENCE 21974 819940819930810668 9425.3651MESP
+6833VIGNY EVELYNE 21974 51994081995121206910239.9952CVENTE
+1571SEINE GUY 11974 3199609199509 7803 7680.8951CANGL
+8078LAMARCK JOSIANE 21974 3199602199502 9894 8922.4151CTECHN
+0018LOUVERSEY CATHERINE GINETTE 2197510199611199511 9894 8922.1451CSANS
+7419VEROCE MICHELLE 21975 3199406199306 7803 7680.1451CSANS
+8512ASSOMPTION CHRISTIANE 21975 3199608199508 7803 7680.5951CVENTE
+6365EDENFLORE BRIGITTE 21975 1199308199208 7803 7681.4251.ALLEM
+2274LOTUS ISABELLE 21975 7199612199512 9894 8923.1351CSANS
+5674MAUBLANC NICOLE 21975 9199602199502 9894 8922.8051CSANS
+0762GIORDAN ANNE MARIE 21975 1199607199507 9894 8921.3151MINFOR
+0696PICAUD JEANNINE 21976 2199607199507 7464 7525.7451CSANS
+6681MARCEL FRANCOISE 21976 3199608199508 7803 7680.6251CSANS
+0740CHESNAIE PHILIPPE 11977 1199507199407 7803 7681.2551CINFOR
+4654CANNES FRANCIS 11977 3199609199509 7803 7679.5851CANGL
+7430MULLERON FRANCOIS 11978 5199607199507 7803 7680.8451CSANS
+3935LISSAND ISABELLE 21978 4199607199507 7803 7680.6351CSANS
+5586SCHUMAN NANCIE 21931111974111991071578112723.0552VSANS
+1401RENAUDOT MARYSE 21933 51968071990071621213033.8152MSANS
+1061AMBOISE DENIS 11934 11964041993011663613344.2752MSANS
+9799GUILLEMETTE JEAN CLAUDE 11935 31955021991082470018540.7552MSANS
+3145SABLES PHILIPPE 11936 11959021993073417325098.3651MANGL
+3589FOURMONT PASCAL 11936 71959031982063327724477.0651MSANS
+2996PAUL MARIE PIERRE 21936 51972121989011621213033.9152MSANS
+2578PISY YVES 11938 71962111981102470018542.2252MSANS
+1257LAMARK PATRICK 11939 71963121992052470018541.5052MINFOR
+6677BRETHENCOURT NOEL 11939 21972111991011578112722.7052MSANS
+9734FIGOURNAS DENIS 11940111971041989101932314934.7252MANGL
+6502POMMERY ROBERT 11941 81963121993011663613344.0552MSANS
+2718CHENES HAFID 11941 11964081994011557012567.3952MSANS
+4104LANCY LIONEL 11942121988011995013587826261.1652.SANS
+8284MERY PAUL EMILE 11942 61968021994012137316331.8752MCOMPT
+3992BOUTICOURT EUGENIO GIOVANNI 11943 51964071987042273717261.8452MALLEM
+9819LATTRE GUY 11945 31974071992071369311286.1252MESP
+1150CAILLOUX JOSIANE 21945 11965021985042470018541.4752CANGL
+6760HAUTINS BRIGITTE 21945 719781219900711131 9659.0652MSANS
+2900FOS BERNARD GUY 11946 91974051993091168610046.6952CINFOR
+3096CASTELLAR JACQUES 11946 71972041991112137316331.0352MINFOR
+3983FLEURIE ISABELLE 11948111973111994011663613343.3052MANGL
+9627CITROEN SILVIE 21948 31970041991012990722150.2852CALLEM
+2626BUFFON BRUNO PIERRE 11948 51974051993011621213032.8352MANGL
+1995GRENELLE PASCAL 11949 81975041991071578112721.7152MSANS
+6675EMAN BERNARD 11950 71973081991012739020403.1152VSANS
+1203JACOB JEAN PIERRE 11950 619790819780811389 9852.0052MSANS
+1502COUBERTIN MICHEL 11951121979031992121608112916.4752MCOMPT
+9762APPOLINAIRE JEAN CLAUDE 11951 51971101992112175716600.9252MANGL
+6014MAURICE JOEL 11952 419910319900310024 8999.7952CSANS
+8272BESANCON CHRISTIANE 21953 2199304199204 9597 8728.9452SSANS
+4121VOLTAIRE PHILIPPE 11953 51972071995122043315671.2452CALLEM
+3385CARNOT HENERE 11953121978061993051864214469.1452MANGL
+9459SAUVETERRE OLIVIER MICHEL LOUIS11954101982061990011608112916.2352MANGL
+0260MOURILLON JOELLE 21955 21984011992011249910473.0952MSANS
+6808ROBERT PIERRE 11956 61979061992021471512025.3752DVENTE
+1754CITADELLE PHILIPPE 119561019830619910311131 9658.9152MANGL
+3114PINCES FREDERIC 11956 61976031988011684813422.5952CSANS
+2401PAPE MARIE ANNE 21956 31978061992121471512025.9552MSANS
+3724AGNOS ERIC 11956 71976041993111578112721.7052CSANS
+1438KERLIBOUZEC EVELYNE 21956 71981111980111527112373.3252MINFOR
+8247VERSAILLES LAURENT 11956 61980081995091249910472.5552MSANS
+0939FLAMBERTINS ALAIN 11957 819950619920110024 8999.0752CSANS
+5765FOCH ROBERT 11957 11981031993031608112916.3252MALLEM
+9301GARDETTES DOMINIQUE 21957 1199505199405 9126 8456.6952MSANS
+8571TIRE ROBERT 11958 11984051992041326611017.9752MSANS
+7487THORNTON JEAN LOUIS 11958 31981041994051804514081.0752MANGL
+3406AVEL PAULE 21958 419780619770611515 9930.5352MSANS
+0124DESPORTES STEPHANE 11959 21979021995091471512025.7252MSANS
+6928ASSIER PIERRETTE 21959111993101992011202810241.1352CTECHN
+0989FEROLLES WILLIAM 11959 81983041982041326611016.3052MSANS
+9802ORGE JEAN CLAUDE 11959 11980081987112256617145.8752MSANS
+8376FOUQUE ERIC 11959 2198801198502 8656 8145.6552.SANS
+8925COURBET YVES 11960 71987031989112090215980.8752MALLEM
+3897ANDELU ALAIN 11960 81991011994011249910471.7452DSANS
+3323BOSQUETS CLAUDE 11960 41983031995121433211715.6952CANGL
+7089COULOUBRIER DENIS 11960 7199303199203 9126 8455.6552CVENTE
+3026AGUILLON LUC 11961 2199601199501 8656 8145.6652MANGL
+9585EGLISE ANDRE ROGER 11961101988111993092401918076.1152MSANS
+0634MAINE JOSEPH 11961111986011992121288210745.7052CSANS
+7284FORTES ANDREE 21961 51991111990111949415051.2152MSANS
+3518VIELLE GEORGES 11961101988091992121249910473.6752MSANS
+3969FERIGOULAS SYLVIE 21962 71983011982011288210743.9052MALLEM
+1749ARCADIA PASCAL 1196210199305199209 9597 8727.8352CANGL
+5023PAVIS YVON 11962 4199512199501 9126 8455.5352MALLEM
+6853PLAGNE ROBERT 11962 819840619830611131 9657.1252CINFOR
+0421HARAVILLIERS MAX 11962 819850819840810791 9502.9852CINFOR
+8436PLEIN ROGER 11962 51984081989112090215981.3652CESP
+2433SARTRE SERGE 119621219850719920910791 9502.6652CSANS
+4413WALDTEUFEL FRANCINE 21962121982051988051608112916.0252MANGL
+2214MONTEZE FRANCOISE 21962 3199302199202 9597 8728.3752MALLEM
+0233COMMUNE ANNE 21963 2199312199212 9085 8419.4452STECHN
+0441SOLARIUM ELISABETH MARIE PIER21963 21993071992011202810240.9952MTECHN
+4510LETELLIER HUBERT 11963 31986111986031527112374.5852CSANS
+1778EVEQUE BERNARD 11963 51986111992011949415051.3952MSANS
+1339SEGUR SERGE 11963 91985091992121527112374.1252MTECHN
+4092HEURSAULT AGNES 21963 51982031981031326611016.7552MSANS
+9379GOJA MARIE THERESE 21963 71983041982041288210744.2652MINFOR
+1533BODIN ISABELLE 21963 419831219821210024 8998.9152MSANS
+9862FOSSE BETTINA 21963 91990111989111949415051.9552MSANS
+6255VIGNE NICOLE 21963101984111983111608112916.9152MSANS
+6101VAUGRENIER CATHERINE 21963101984051989041527112374.9452MINFOR
+8653SEQUOIA HENRI 11964 51988031994011249910473.2052MSANS
+9919BILY PATRICK GUY 11964 91985091992091949415050.6352MSANS
+7059VALLEROY BEATRIX 21964 2199204199104 9597 8729.0752MSANS
+5440PORS ANNE MARIE 21965 21986061985061527112373.1752MSANS
+2587VICOMTE PATRICIA 21965 11991111992011202810239.8652CESP
+9598SULLY CHRISTIAN 11965 91994051992011202810240.1452MANGL
+0899MANU JEAN PAUL 11965 519880519870510407 9270.2952MTECHN
+0493POET JEAN PAUL 11965 119891219881210407 9270.5652MINFOR
+7853LILAS JEAN CLAUDE 11966 31986051985051288210744.5052MANGL
+4637LONGCHAMP CATHERINE 21966 91988051993091839014313.0952MSANS
+5141LINDFIELD GERARD 119661119870119860110407 9272.2452MANGL
+3945PESSOT VERONIQUE 21966 119910719900710024 8998.8952MINFOR
+6408PUJOLS CHRISTINE 21966 71987061986061249910473.0952MSANS
+5883AUREA JEAN 11966101988061991011249910471.9452CESP
+6385CHAILLY LAURENCE 21967 419910719900710024 8998.4152MANGL
+8609CEINTURE ANNE MARIE 21967 21991121995071202810240.1452MANGL
+1367NOIRES ANNIE 21967 61991101990101330611017.1952MSANS
+6827NOISY FRANCIS 11967101988011987011450311831.9752CESP
+3823RESISTANCE CHRISTIAN HENRI 119671119890319880610407 9270.8452MSANS
+5716CYRAN PATRICK 11967 11987071994111450311832.6852MANGL
+2307ARBELLARA NADINE 21967 61988091990111839014313.9352CSANS
+0224VEBRET VIRGINIE 21967 9199406199305 9126 8456.1652CANGL
+3639BERGERON CHRISTINE 21967 619951219940110668 9426.1852DSANS
+5292CREGY MAURICE 11967 719940819930411389 9852.4952MANGL
+8369BRENS COLETTE 21968 81991101990101330611017.4152CANGL
+2447REBEYROLIE ANNIE 21968 619900319900911389 9851.0352MALLEM
+0478MES CHRISTINE 21968 4199309199209 9597 8728.7152CSANS
+2875CLION MARIE FRANCE 21968 319930519920511389 9852.4552CSANS
+8148CROS FRANCOIS 11968 41988111987111249910472.7352MSANS
+9990VERCINGETORIX CHRISTINE 21968 119950419930411389 9851.2852MSANS
+2796BLONC JEAN PIERRE 11968 4199301199511 9597 8727.8152MSANS
+9996GUIS LUCIEN 119681219931119920110024 8998.5352CSANS
+7769NERVAL MICHELE 21968 41990051994011330611017.8352CSANS
+6262RACINE ALAIN 11969 719890419880410407 9271.9552CSANS
+9102SAUGES BENOIT 11969 11989071993081381911364.8152MSANS
+4448NARON PASCAL LOUIS 11969 2199605199505 8656 8145.6952LSANS
+3197CHAUMES GUY 11969 819930619920610024 8998.9452MSANS
+2201LUYNES SOPHIE JOELLE 21969 5199311199211 9597 8728.2352CANGL
+3000PLAINES JEAN MARC 1196910199204199312 7677 7604.9052CINFOR
+7547BREGUIERES THERESE 21969 719920419910411389 9851.3352MANGL
+9804CADOT MARIE JOSE 21969 81991101990101330611018.2252MSANS
+5321JAUNAC SOPHIE 219691019910719900710024 8998.5852MSANS
+3824LAVISSE DANIELLE 2196912199405199305 8359 7952.9252CSANS
+6505LOUISE PIERRE 11969 419910119900110024 8999.8152CSANS
+9873BOULOURI JEAN MICHEL 11969 71990021992091202810241.3652MSANS
+9771BREUILHSUD THIERRY 11969 419910719900710024 8997.9652CCOMPT
+8931ELVARD CLAUDE 11970 81994031993032107316096.9852MANGL
+2755GEROME MAURICE 11970 8199311199212 9597 8728.9552MTECHN
+8557CYRNOS BERNARD 11970 5199404199201 9597 8729.9052MSANS
+3651COCTEAU GABRIEL 11970 41994011993011267210588.5352CSANS
+4459VITALIS ALAIN 1197010199612199512 9894 8921.9152LSANS
+9388COURTENAY JEAN JACQUES 11970 91990031995071202810241.1252MVENTE
+1310CAILLADE ADRIEN 11970101996111995111616712994.7752CALLEM
+5461GOMETZ CHRISTIANE 21970 61994071993071407611559.6252CSANS
+0669MAUVALAT DANIELE 21970 6199209199109 9597 8728.7652MSANS
+0103TAILLEFER MICHELINE 2197010199608199508 7803 7680.0552CSANS
+5577MOUGINS CHANTAL 21970 619940919930411389 9852.6952CSANS
+0340LAMBESC MARIE CHRISTINE 21970 3199607199507 7803 7680.6252CSANS
+1328PIERRE PATRICE PAUL 1197111199106199006 8656 8145.0352.SANS
+3172DENOUVAL DANIEL 11971 419940319920110024 8999.1652MSANS
+9639ESPAON MARC 11971 7199407199307 9597 8727.7852CTECHN
+6612FONTMERLE JOELLE 21971 919930419920411389 9850.8452CSANS
+1855MAILLOL PIERRE 1197110199303199203 9597 8728.0452MSANS
+8791RASTINES PHILIP 11971 81993011992011267210589.2852CSANS
+2880FLORALIES MARIE THERESE 219711219930919920911389 9852.3352CINFOR
+9921SERPENTINE FRANCOISE 21971 419920219910211389 9851.1652CVENTE
+6761KING JACQUES 11971 5199606199401 9597 8729.9952CALLEM
+8677BREANCON VERONIQUE 21971 919940819930810668 9425.7252MANGL
+0030SUVERET PATRICK 1197110199501199304 9597 8728.6652MSANS
+4284REGNAULT JEAN MARC 11971 719900619890610024 8999.3652CSANS
+3275POMPIDOU DIDIER 11971 6199610199510 8656 8145.3352MSANS
+7270BONNEUIL MARC 1197110199107199007 8656 8145.3052.SANS
+2988DEREURE BRIGITTE 21971 8199606199506 8656 8145.8752CINFOR
+0334GRAVESONN JEAN 119711119911019901010024 8997.7852CANGL
+5425PONT FRANCOIS 11971111995041994041267210588.8852CSANS
+7132MIDI JEAN PIERRE 11971 5199608199509 8656 8145.4852CANGL
+5172BLOMET JEAN PIERRE 11971 81993061992061267210589.5252CSANS
+1753QUIETA DOMINIQUE 11971 41991061995101202810241.7652MSANS
+8062DOMINO MARC 11971 719910819900810024 8999.4052MSANS
+8636ECLUZELLES MICHELE 21971 9199609199509 9894 8921.5952CSANS
+5812REPUBLIQUE VERONIQUE 21972 31995101994101206910240.4052CSANS
+0712TEYSSIERES MARTINE 21972 6199607199507 7803 7680.8952CSANS
+3543DUNETTE LAURENCE 21972 4199608199508 8656 8145.9152MSANS
+7967FOUCANCOURT ASTRID 21972 219930619951011389 9850.8852CSANS
+6876THERESE MISAKO 21972 719940819930710668 9427.2652MSANS
+9406GALLIEN MICHEL 11972 219910719900710024 8997.9052MSANS
+7605BAUMES ALEXANDRA 11972 7199501199304 9597 8728.1952MALLEM
+1625ARTHUISIERE JACQUES 11972 61995011994011206910240.6652CSANS
+6717DOUMER PHILIPPE 1197212199611199401 9597 8728.8052CESP
+1677CHABRIER LAURENT JEAN CLAUDE 1197211199504199404 9126 8456.3952CSANS
+8299PUY JEAN 119721119931219940111389 9852.6352CANGL
+8443COUSTERES MICHEL 11972 2199107199012 8656 8145.4452.SANS
+7741NANT FREDERIC 11972 31991061994111202810240.7652MSANS
+0657TAUDE FABRICE HENRI 11972 319940219930211389 9851.3752CANGL
+9630GOELETTE JEAN LOUIS THIERRY 11972 4199407199307 9597 8728.1352CSANS
+1127EXUPERY SIMONE 21972 5199602199502 9894 8921.4152CTECHN
+6944LIBERTE CORINNE MARIE 21972 41993071993051267210589.5253CSANS
+3755ARNAUD MARIE PIERRE 21972 6199307199207 9597 8729.3052MALLEM
+2437CLAUSONNES MARTINE 2197212199411199311 9126 8457.1152MSANS
+2896LUNA NADINE MARIE 21972 8199308199208 9597 8728.3252CTECHN
+1758KARU LILIANE 21972 3199207199107 9597 8729.7452CINFOR
+5392FER RADHIA 21972 3199210199106 8359 7952.9152.SANS
+9857EGLISE CLAIRE 21972 7199402199302 9126 8457.1152CSANS
+6707INKERMANN GERARD 119731219951119941110668 9426.5952CSANS
+4728ESTANISLAO ERIC 11973 1199608199508 7803 7680.7752CSANS
+6566GOULAIN BRIGITTE 21973121994121993121206910240.7753CESP
+0727PUY THERESE 2197311199610199510 8656 8145.6552LTECHN
+0980ARGENTIERE GILLES 1197311199406199306 9126 8456.1552CANGL
+4718DOMOY MICHEL 11973 219940819930811389 9852.0052CSANS
+0216CALAIS FREDERIQUE 21973 219930919920911389 9850.6152MVENTE
+2997FOIRAIL COLAS JEAN LOUP 11973 1199604199504 8656 8145.4852CINFOR
+5877EPI LUC 11973 5199308199208 9597 8729.3052CANGL
+0287CARTIER JEAN LUC 11973 7199511199411 9894 8923.3852CTECHN
+7891MOUSTRAN PAUL 11973 2199303199203 9597 8729.8452CSANS
+3815ELYSEE LOUIS 1197311199304199204 9597 8728.6652CSANS
+0959REPUBLIQUE ERICK 11973 619930719951111389 9852.2752CESP
+2490GLENANS PHILIPPE 11973 41995101994101206910241.8452CSANS
+6935PAYRAC JEAN JACQUES 11973 9199310199210 9597 8729.2252MSANS
+8784JACQUET FREDERICK 11973 319930919920911389 9852.2452CINFOR
+7986COUCHANT YOLANDE 2197312199608199508 7803 7679.4652CALLEM
+1549DRYADES PIERRE G 11973 9199408199307 9126 8456.7052CSANS
+0968OPIO SYLVIE 21974 6199606199506 8656 8145.3852CSANS
+0353DELATTRE FREDERIQUE 21974 9199603199503 8656 8145.8052CINFOR
+1122ACACIAS SERGE 11974101995101994101206910240.9452CTECHN
+9008MANOIR DANIEL R 11974 9199606199506 9894 8921.4052CSANS
+3650AIRES FERNANDO 11974 7199407199307 8656 8146.2552CSANS
+7799TOUR JEAN PIERRE 11974 3199508199408 9126 8456.3752CSANS
+4614VILLERS CHRISTIAN 11974 119951119941110668 9427.4752CSANS
+6384SEURAT JEAN JACQUES 11974 1199504199404 9126 8457.4952CSANS
+0504MEYRIN MICHEL 11974 8199607199507 7803 7679.3752CTECHN
+3076TAMARIS THIERRY 1197411199405199305 9126 8457.7452CALLEM
+5273CAYES PHILIPPE NICOLAS 11974 2199308199208 9597 8729.3452CALLEM
+9558BATOUCH PAUL 11974 6199606199506 8656 8145.2452CSANS
+6082PEDRO GERARD 11974 6199607199507 7803 7680.3252CSANS
+4712CIDEX NICOLE 21974 9199607199507 7803 7680.0052CALLEM
+7982VILAR MICHELINE 21974 9199604199504 9894 8921.4052CALLEM
+0377RIBE MARTINE 2197411199609199509 8656 8146.6152CVENTE
+1910AUBE DOMINIQUE 21974 3199610199510 8656 8146.0152CANGL
+1632COURTAU MARIE JOSEE 21974 8199609199509 7803 7679.6352CSANS
+0616HIIS BEATRICE 21974 919930919920911389 9850.9852MSANS
+5825TIREUSES MARIE FRANCOISE 2197512199609199509 7803 7680.7152CANGL
+8598SAND CHRISTIANE 2197511199607199507 9894 8922.0552CSANS
+9425VISA GILLES 11975 319951119950211389 9851.7452CALLEM
+8440EYGAUX LAURENT 11975 6199603199507 9894 8922.1652CSANS
+3240BARBUSSE JEAN PIERRE 11975 6199510199410 8656 8146.2552CANGL
+7022LOUPS DOMINIQUE 11975 3199605199505 8656 8146.7752CSANS
+3687SULTZER MARYLINE 21975 8199607199507 7803 7681.1752CTECHN
+3649TROIS ANGELICA 2197511199608199508 8656 8147.0652CSANS
+8797BELHAITRE RENE 11975 4199409199309 9126 8455.7652CSANS
+3401SOURCE PAUL 11975 2199612199512 9894 8921.4152CANGL
+0533JOUFFROY LUCIENNE 2197511199608199508 9894 8922.0052CTECHN
+4412CAPEAU MONIQUE 21976 1199607199507 7803 7680.6252CINFOR
+9518COCULOT HELENE 21976 8199508199408 7803 7681.2952CSANS
+1220VALLOIS ALAIN 11976 7199607199507 7803 7680.1852CANGL
+7054DANGALYS MARTINE 2197712199607199507 7803 7680.7752CSANS
+5515MARNE GHISLAINE 21977 6199607199507 7803 7680.0552CSANS
+2958CLAIR GISELE 21977 8199608199508 7803 7680.6352CANGL
+5379CONCHES DOMINIQUE 21977 6199607199507 7803 7679.4652CANGL
+9250DECHAMBRE MICHEL 11977 8199607199507 7803 7679.4552CSANS
+7969SALEON ALAIN 11977 8199607199507 7803 7679.3652CANGL
+0131EOLE ROXANE RENEE 2197710199607199507 7803 7679.2852CANGL
+9710OUEST HENRIE MARCEL 11979 2199607199507 7464 7525.1452CINFOR
+0487PRIEUR JEAN FRANCOIS 11956 81983041982041684813423.3153MSANS
+7696BELVEDERE XAVIER 11962 81982071995091450311830.6753MINFOR
+2063LIOURA PASCAL JEAN 11964 41986111995082256617145.7853MANGL
+7927TRAVERSIERE JEAN PIERRE 11965111986081995091450311832.1553MCOMPT
+2549VASCO DANIEL 11968 51990091995111450311832.1453MANGL
+2675RESIDENCE JEAN MARC 11969 21995111994111450311831.3453CANGL
+8649VIGIER OLIVIER 11969 8199612199512 4638 5819.0153MSANS
+7524BEDOK STEPHANE AUGUSTE 11969 51995121994121450311832.5653CSANS
+3056FRANCE MARION 21971 61996091995091450311831.7553CSANS
+9905CORNICHE DANIEL 11972 31996091995091450311832.2057CSANS
+4894PORTE RONAN JEAN PIERRE 11972121993091992091450311831.9353CSANS
+6471SUCCURSALE LAURE MARIE 21972 71996091995091450311832.1854CALLEM
+8530TOURS ANNE YVONNE 21973 31995121994121450311832.3854CSANS
+4004MORTON JEAN CLAUDE 11965 81992031991031965617846.6854CANGL
+4099MONTELIER DENIS 11971 519940819930811389 9851.1257MSANS
+9423CHATEAU CARL 11956 51980091992121471512024.3958MSANS
+2026BERT CLAUDE 21957 51979031986021497412181.1158MALLEM
+0951MERAY MARIE HELENE 21964 61990051989051249910472.7058MTECHN
+5282PINEL LILIANE 21948 71977031992011471512024.4859MINFOR
+5545DOM ANNIE 21960121982091995061638413150.2959DSANS
+4161BOIS ANNICK 21960 81983021982021326611016.2459MSANS
+1624LORRAINE CHRISTIAN 11961 41983081991012781920674.8359MSANS
+0982VEYANS MICHEL 11961 21982091991092529918968.7059MINFOR
+0123LOCARNO ANNE MARIE 2197411199402199302 8359 7953.1159MSANS
+7957AVAUX PHILIPPE 11942 51963041991072273717261.4960CCOMPT
+0611SAUVAN JEAN FRANCOIS 11946 71980111994011471512025.0260MTECHN
+8634MONTGAZIN ANDRE 11950121974061991012137316331.7560MALLEM
+3872AZUR JEAN CLAUDE 11951101970101990101932314935.1760MMICRO
+7401PARC PIERRE 11952 91989011994011288210745.9360MSANS
+8111STADE BERNARD 11953 21983021984051249910473.4960MANGL
+8795MOTU JEAN LUC 11959 81979101994011578112722.8260MSANS
+2118BAUDETS MARIE CHRISTINE 21961 31983011982011608112915.3560MTECHN
+8422WIEHN BRUNO 11963121988061992021249910472.6660MANGL
+3871SOLE MARTINE 219661019910919950510876 9503.4760MINFOR
+6169CUOQ CORINNE BRIGITTE 21967 21989121995071249910472.2560MANGL
+2571BARAT MARTINE 21968 81994061996012303517377.3560CSANS
+4114HOURTINS DOMINIQUE 11977 1199608199508 7803 7680.5960CANGL
+1079GUEN HELENE 219391219820419810411131 9657.7561MSANS
+0830EGLY DANIELLE 21950 1199406199306 9126 8457.4261MSANS
+1903GENEVIEVE HARDY 11953 91978111989112256617146.1661MINFOR
+9550INGERSHEIM PHILIPPE 11961 61982041987041608112917.1961MANGL
+3284BELLETRUD JEAN 11950 61977101993121369311287.2363MALLEM
+2911SOUBISE IVAN 11958 71982031992112529918967.7663MTECHN
+5851CREACH FRANCOIS 21963 9199608199508 7803 7680.0863MSANS
+6333DUPARCHY LILIANE 21973 3199406199306 9894 8921.6763CSANS
+1729CURAT ROBERT 11935 91958051994123417325098.2464MSANS
+7436CHALLONNIERE VALERIE 21941 41962041989012137316332.3664MSANS
+6301BLUM CHANTAL 21943 71969071991051932314935.2664MSANS
+7026SARRETTE MICHEL 11946 21991011990013200223583.2364.ANGL
+0646MARIE BRIGITTE 21950111971011992061834514275.6164DMANAG
+1101ENFANTS ANTOINETTE 21955 61981011995011527112373.9164MANGL
+8770RACHERET LAURENCE 21956 71978061993051608112916.8864MANGL
+4751LIONS DAVID 11958 91980071993092090215981.1464MANGL
+9291SOULEYAS DOMINIQUE 11958 11980011992101911114779.7764MANGL
+2505LUCHON JACQUELINE 21958 21989011993041249910473.4964MSANS
+8607VOLVESTRE ELISABETH 21958 11991111990111249910472.9764SALLEM
+1586PESSAC JEAN YVES 11961 21989051988051949415050.2864CSANS
+5341RIOU ROBERT 11962 61985091993011949415052.4365MCOMPT
+8946MOULINET ANNE 21962 81983041982041608112915.6064MSANS
+5619MARCQ MONIQUE 21963101995101994101206910241.3064MSANS
+8989JUZAN CLAUDE 11965101990091994092401918075.4464CANGL
+0763PERAULT CHANTAL 21965 21986041985041527112373.5364MSANS
+1526JEREZ NICOLE 21967 519911219920111389 9851.6164.ALLEM
+2211KELLERMANN FREDERIQUE 21967 91991111990111202810241.9764MSANS
+4302KERCADORET DOMINIQUE 11971 81994071993071206910240.2364CSANS
+1236PALETTE ROSE MAY 21971 91994031993031267210588.9264CSANS
+8225SEROT MARTINE 21972 11992061992031330611017.7065CALLEM
+5326DRAGUIGNAN FRANCOISE 21972 519930619920611389 9852.0564MTECHN
+5970DANUBE PHILIPPE 11974 11994071993071206910240.4965CSANS
+6556BROUILLET ANTOINE 11937 11986101986012687820055.0565.SANS
+1186AOUT JEAN JACQUES 11937 21987011986012431618272.0165.COMPT
+7999PIERREFONDS STEPHANE 11938 31964051994011663613342.7665MINFOR
+1312GRENOUILLERE PHILIPPE 11939 71964101987016400345693.2465MALLEM
+0460MARRONNIERS GERARD 11942 41961061994113587826261.7965MINFOR
+4154LOUIS PHILIPPE 11942121965101993012739020403.3065MVENTE
+3603MUETTE GEORGES CHARLES 11942 41968071992013844228044.8465MANGL
+8992COUDREE PASCAL 11943 91968031988072273717260.3265MSANS
+9382CONSTANCE MADELEINE 21944 519830619860211131 9657.1265VSANS
+0255MARTINIQUE GERARD 11946 31994121993123882428316.7365MSANS
+8195EXELMANS BERNARD 11946 91984051984111215710278.1665MVENTE
+3879GOUT JACQUES 11947 51968121992122470018540.5765MSANS
+9678HETRES VIANNEY 11947 91968091994094121428006.1765MALLEM
+6027STRASBOURD JEAN CLAUDE 11951 21972101987052470018540.1565MALLEM
+7805BESSIERES JEAN 11952 51973031988112334017609.4265MSANS
+7152REUILLY ANNE 21953 91974071993121471512024.5665MINFOR
+4995BERCHET FRANCOISE 2195412199306199206 8656 8145.6065MMANAG
+1933ERMITAGE JEAN CLAUDE 11955 11991031994021249910471.6165MSANS
+0728VOISEMBERT ISABELLE 21955 61976011991011471512024.2165MSANS
+0718CERNAY MARC JEAN MARIE 11959 11988011987013669126843.7365.SANS
+2726ORDENER MARIE FRANCOISE 21959 21980071991101369311287.9765MSANS
+0225PLELO PHILIPPE 119591119800319790311389 9851.3365MSANS
+0630GOBELINS BERNARD 11959 71981031991012781920674.6165MTECHN
+1138ISARDS ELIANE 21960 21988101990042581519316.5865.SANS
+8716TOURELLES JOSETTE 21961 81983041989112090215980.4365DANGL
+3837CONTAMINES ANNIE 21961 81984121992061527112373.2265MANGL
+0223FOUSSEAU DOMINIQUE 21961 21996071995082005015476.6165DINFOR
+8553OUSTALADO PIERRE 11962 61984011993121326611017.7265MSANS
+1723HIGH MURIEL 21962 71983011982011608112917.1865MSANS
+2779PLAT MICHEL 11963121984051993102401918074.6765CANGL
+7160BOILEAU DENIS 11964111985031990111949415051.9565MANGL
+1054MARINET CRISTOFORO 11964101985091993092401918076.4465MALLEM
+0034ANGELY JEAN PIERRE 11965 31988081991121249910473.3265MINFOR
+0684DIEUDONNE CORINNE 21965101988121987121249910473.7465MSANS
+4943SICARD DOMINIQUE 21966 919931019921010363 9233.2765MINFOR
+8211CARLE PATRICK 11966 31994011993011621213033.5665MALLEM
+1276GREFFIER SERGE 11967 119930619940110024 8999.1365CSANS
+5313BIARRITZ CHRISTINE 21967 91990111991012602319433.9065.ALLEM
+5161DUBOC NICOLE 219671219880119870111302 9774.4865MANGL
+1515SABLEAUX REGINE 21969 71993011992011839014313.2665MSANS
+7518LANORVILLE JEAN DAVID ALBERT 119701219960519950511389 9851.7065CSANS
+6488CATALAGNE PHILIPPE 11970 71996101995101706413577.4365CSANS
+8039LAURENS PATRICIA 21971111993031995011557012567.4165.SANS
+7894PEPINIERE MARIE ANNE 21971 41991111991111723313653.7565MSANS
+9988MEN JACQUES 11972 71994061993061420611638.1665CANGL
+0742TOUTES JEAN FRANCOIS 11972 71993031992031420611637.6665CANGL
+3618FREDISANE BRUNO 119751019960619950611389 9852.5465CANGL
+7403AUGUSTINES ERICK 11937 61988031987024330331419.2172.ALLEM
+7418PATRICIA JEAN CLAUDE 11944 71990071993011369311286.2072.SANS
+9902CORSE MARIE JOSE 21958 41988101983101326611018.1872.INFOR
+1972FLANDRIN CATHERINE 21963121988101983101288210744.3772.SANS
+6223BEAR MICHELINE 21963 51989061992031450311831.6972.SANS
+1899CHEVILLY ISABELLE 21963 71989011992061450311832.7272MTECHN
+1131BLAISE MIHOKO 21963101990011991061450311831.0372.SANS
+7170AIGUEBONNE MARIE 21971 11995101994101206910241.9972CSANS
+0384LAMBESC ALBERT 11973 119901019920110024 8999.7672.TECHN
+4786VIGEN EVELYNE 21939121962121990102273717261.1873MINFOR
+5969COTE MIDORI 21946121994101993102334017610.5973MSANS
+6378MYOSOTIS YVES 11949 31992011994113844228045.8873.SANS
+3664MAREUIL NADINE 21966 21989061989111288210744.8673.SANS
+8858EANOLIAS JACQUELINE 21949 51977071991121911114778.7075CSANS
+1090LORETTE YVES ANDRE 11950 61971081995013587826261.5875MSANS
+3800KOUTIO ALAIN 11961 91982121989052090215980.3975MINFOR
+5591PALALDA MARC 11965 81995061994061267210590.3275MSANS
diff --git a/storage/connect/mysql-test/connect/std_data/employee.dat b/storage/connect/mysql-test/connect/std_data/employee.dat
new file mode 100644
index 00000000..c571667f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/employee.dat
@@ -0,0 +1,27 @@
+74200 BANCROFT 2 SALESMAN 70012 0318 24888 9600.00
+02345 SMITH 1 ENGINEER 31416 2452 11111 9000.00
+78943 MERCHANT 1 SALESMAN 70012 0318 24888 8700.00
+07654 FUNNIGUY 1 ADMINISTRATOR 40567 0319 33333 8500.00
+45678 BUGHAPPY 1 PROGRAMMER 40567 0319 12345 8500.00
+34567 BIGHEAD 1 SCIENTIST 31416 2452 11111 8000.00
+77777 SHRINKY 2 ADMINISTRATOR 70012 0318 27845 7500.00
+74234 WALTER 1 ENGINEER 70012 0318 24888 7400.00
+56789 FODDERMAN 1 SALESMAN 40567 0319 12345 7000.00
+73452 TONGHO 1 ENGINEER 70012 0318 24888 6800.00
+22222 SHORTSIGHT 2 SECRETARY 87777 0021 5500.00
+55555 MESSIFUL 2 SECRETARY 40567 0319 12345 5000.50
+27845 HONEY 2 SECRETARY 70012 0318 24888 4900.00
+98765 GOOSEPEN 1 ADMINISTRATOR 07654 0319 33333 4700.00
+11111 CHERRY 2 SECRETARY 31416 2452 4500.00
+33333 MONAPENNY 2 SECRETARY 07654 0319 3800.00
+12345 KITTY 2 TYPIST 40567 0319 3000.45
+24888 PLUMHEAD 2 TYPIST 27845 0318 2800.00
+87777 STRONG 1 DIRECTOR 0021 22222 23000.00
+76543 BULLOZER 1 SALESMAN 40567 0319 12345 14800.00
+70012 WERTHER 1 DIRECTOR 87777 0318 27845 14500.00
+40567 QUINN 1 DIRECTOR 87777 0319 55555 14000.00
+31416 ORELLY 1 ENGINEER 87777 2452 11111 13400.00
+36666 BIGHORN 1 SCIENTIST 31416 2452 11111 11000.00
+00137 BROWNY 1 ENGINEER 40567 0319 12345 10500.00
+73111 WHEELFOR 1 SALESMAN 70012 0318 24888 10030.00
+00023 MARTIN 1 ENGINEER 40567 0319 12345 10000.00
diff --git a/storage/connect/mysql-test/connect/std_data/expense.json b/storage/connect/mysql-test/connect/std_data/expense.json
new file mode 100644
index 00000000..f9373ef1
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/expense.json
@@ -0,0 +1,158 @@
+[
+ {
+ "WHO": "Joe",
+ "WEEK": [
+ {
+ "NUMBER": 3,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 18.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 12.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 19.00
+ },
+ {
+ "WHAT": "Car",
+ "AMOUNT": 20.00
+ }
+ ]
+ },
+ {
+ "NUMBER": 4,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 19.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 16.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 17.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 17.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 14.00
+ }
+ ]
+ },
+ {
+ "NUMBER": 5,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 14.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 12.00
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "WHO": "Beth",
+ "WEEK": [
+ {
+ "NUMBER": 3,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 16.00
+ }
+ ]
+ },
+ {
+ "NUMBER": 4,
+ "EXPENSE": [
+ {
+ "WHAT": "Food",
+ "AMOUNT": 17.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 15.00
+ }
+ ]
+ },
+ {
+ "NUMBER": 5,
+ "EXPENSE": [
+ {
+ "WHAT": "Food",
+ "AMOUNT": 12.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 20.00
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "WHO": "Janet",
+ "WEEK": [
+ {
+ "NUMBER": 3,
+ "EXPENSE": [
+ {
+ "WHAT": "Car",
+ "AMOUNT": 19.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 18.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 18.00
+ }
+ ]
+ },
+ {
+ "NUMBER": 4,
+ "EXPENSE": [
+ {
+ "WHAT": "Car",
+ "AMOUNT": 17.00
+ }
+ ]
+ },
+ {
+ "NUMBER": 5,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 14.00
+ },
+ {
+ "WHAT": "Car",
+ "AMOUNT": 12.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 19.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 12.00
+ }
+ ]
+ }
+ ]
+ }
+]
diff --git a/storage/connect/mysql-test/connect/std_data/expenses.txt b/storage/connect/mysql-test/connect/std_data/expenses.txt
new file mode 100644
index 00000000..66a94edb
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/expenses.txt
@@ -0,0 +1,24 @@
+Joe 3Beer 18.00
+Beth 4Food 17.00
+Janet 5Beer 14.00
+Joe 3Food 12.00
+Joe 4Beer 19.00
+Janet 5Car 12.00
+Joe 3Food 19.00
+Beth 4Beer 15.00
+Janet 5Beer 19.00
+Joe 3Car 20.00
+Joe 4Beer 16.00
+Beth 5Food 12.00
+Beth 3Beer 16.00
+Joe 4Food 17.00
+Joe 5Beer 14.00
+Janet 3Car 19.00
+Joe 4Food 17.00
+Beth 5Beer 20.00
+Janet 3Food 18.00
+Joe 4Beer 14.00
+Joe 5Food 12.00
+Janet 3Beer 18.00
+Janet 4Car 17.00
+Janet 5Food 12.00
diff --git a/storage/connect/mysql-test/connect/std_data/funny.txt b/storage/connect/mysql-test/connect/std_data/funny.txt
new file mode 100644
index 00000000..e69cd7db
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/funny.txt
@@ -0,0 +1,3 @@
+12345,'BERTRAND',#200;5009.13
+56, 'POIROT-DELMOTTE' ,#4256 ;18009
+345 ,'TRUCMUCHE' , #67; 19000.25
diff --git a/storage/connect/mysql-test/connect/std_data/funny2.txt b/storage/connect/mysql-test/connect/std_data/funny2.txt
new file mode 100644
index 00000000..f9080e74
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/funny2.txt
@@ -0,0 +1,3 @@
+12345,'BERTRAND',#200;5009.13
+56, 'POIROT-DELMOTTE' ,# ;18009
+345 ,'' , #67; 19000.25
diff --git a/storage/connect/mysql-test/connect/std_data/girls.txt b/storage/connect/mysql-test/connect/std_data/girls.txt
new file mode 100644
index 00000000..12ce8bab
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/girls.txt
@@ -0,0 +1,5 @@
+Mary Boston 25
+Nancy Palo Alto 23
+Susan Chicago 18
+Betty Chicago 32
+Anne Denver 23
diff --git a/storage/connect/mysql-test/connect/std_data/gloss.json b/storage/connect/mysql-test/connect/std_data/gloss.json
new file mode 100644
index 00000000..cfe3476c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/gloss.json
@@ -0,0 +1,22 @@
+{
+ "glossary": {
+ "title": "example glossary",
+ "GlossDiv": {
+ "title": "S",
+ "GlossList": {
+ "GlossEntry": {
+ "ID": "SGML",
+ "SortAs": "SGML",
+ "GlossTerm": "Standard Generalized Markup Language",
+ "Acronym": "SGML",
+ "Abbrev": "ISO 8879:1986",
+ "GlossDef": {
+ "para": "A meta-markup language, used to create markup languages such as DocBook.",
+ "GlossSeeAlso": ["GML", "XML"]
+ },
+ "GlossSee": "markup"
+ }
+ }
+ }
+ }
+}
diff --git a/storage/connect/mysql-test/connect/std_data/latin1.xml b/storage/connect/mysql-test/connect/std_data/latin1.xml
new file mode 100644
index 00000000..c6f1f2c8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/latin1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<a><b><c>ÁÂÃÄÅÆÇ</c></b></a>
diff --git a/storage/connect/mysql-test/connect/std_data/mdev9949.frm b/storage/connect/mysql-test/connect/std_data/mdev9949.frm
new file mode 100644
index 00000000..56bb9a71
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/mdev9949.frm
Binary files differ
diff --git a/storage/connect/mysql-test/connect/std_data/mulexp3.json b/storage/connect/mysql-test/connect/std_data/mulexp3.json
new file mode 100644
index 00000000..5edd2ab1
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/mulexp3.json
@@ -0,0 +1,52 @@
+[
+ {
+ "WHO": "Joe",
+ "WEEK": 3,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 18.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 12.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 19.00
+ },
+ {
+ "WHAT": "Car",
+ "AMOUNT": 20.00
+ }
+ ]
+ },
+ {
+ "WHO": "Beth",
+ "WEEK": 3,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 16.00
+ }
+ ]
+ },
+ {
+ "WHO": "Janet",
+ "WEEK": 3,
+ "EXPENSE": [
+ {
+ "WHAT": "Car",
+ "AMOUNT": 19.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 18.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 18.00
+ }
+ ]
+ }
+]
diff --git a/storage/connect/mysql-test/connect/std_data/mulexp4.json b/storage/connect/mysql-test/connect/std_data/mulexp4.json
new file mode 100644
index 00000000..7f7b88d6
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/mulexp4.json
@@ -0,0 +1,52 @@
+[
+ {
+ "WHO": "Joe",
+ "WEEK": 4,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 19.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 16.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 17.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 17.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 14.00
+ }
+ ]
+ },
+ {
+ "WHO": "Beth",
+ "WEEK": 4,
+ "EXPENSE": [
+ {
+ "WHAT": "Food",
+ "AMOUNT": 17.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 15.00
+ }
+ ]
+ },
+ {
+ "WHO": "Janet",
+ "WEEK": 4,
+ "EXPENSE": [
+ {
+ "WHAT": "Car",
+ "AMOUNT": 17.00
+ }
+ ]
+ }
+]
diff --git a/storage/connect/mysql-test/connect/std_data/mulexp5.json b/storage/connect/mysql-test/connect/std_data/mulexp5.json
new file mode 100644
index 00000000..b1713040
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/mulexp5.json
@@ -0,0 +1,52 @@
+[
+ {
+ "WHO": "Joe",
+ "WEEK": 5,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 14.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 12.00
+ }
+ ]
+ },
+ {
+ "WHO": "Beth",
+ "WEEK": 5,
+ "EXPENSE": [
+ {
+ "WHAT": "Food",
+ "AMOUNT": 12.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 20.00
+ }
+ ]
+ },
+ {
+ "WHO": "Janet",
+ "WEEK": 5,
+ "EXPENSE": [
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 14.00
+ },
+ {
+ "WHAT": "Car",
+ "AMOUNT": 12.00
+ },
+ {
+ "WHAT": "Beer",
+ "AMOUNT": 19.00
+ },
+ {
+ "WHAT": "Food",
+ "AMOUNT": 12.00
+ }
+ ]
+ }
+]
diff --git a/storage/connect/mysql-test/connect/std_data/nocs.xml b/storage/connect/mysql-test/connect/std_data/nocs.xml
new file mode 100644
index 00000000..b2f11085
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/nocs.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<a><b><c>ÁÂÃÄÅÆÇ</c></b></a>
diff --git a/storage/connect/mysql-test/connect/std_data/people.csv b/storage/connect/mysql-test/connect/std_data/people.csv
new file mode 100644
index 00000000..64567aec
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/people.csv
@@ -0,0 +1,3 @@
+Name;birth;children
+"Archibald";17/05/01;3
+"Nabucho";12/08/03;2
diff --git a/storage/connect/mysql-test/connect/std_data/sexe.csv b/storage/connect/mysql-test/connect/std_data/sexe.csv
new file mode 100644
index 00000000..7e5d3ec9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/sexe.csv
@@ -0,0 +1,3 @@
+0;Inconnu
+1;Masculin
+2;Feminin
diff --git a/storage/connect/mysql-test/connect/std_data/sitmat.csv b/storage/connect/mysql-test/connect/std_data/sitmat.csv
new file mode 100644
index 00000000..a5178ed2
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/sitmat.csv
@@ -0,0 +1,7 @@
+.;Inconnu
+C;Celibataire
+D;Divorce
+L;Union libre
+M;Marie
+S;Separe
+V;Veuf
diff --git a/storage/connect/mysql-test/connect/std_data/test.sqlite3 b/storage/connect/mysql-test/connect/std_data/test.sqlite3
new file mode 100644
index 00000000..a3574c44
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/test.sqlite3
Binary files differ
diff --git a/storage/connect/mysql-test/connect/std_data/xsample.xml b/storage/connect/mysql-test/connect/std_data/xsample.xml
new file mode 100644
index 00000000..20c67fe1
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/xsample.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BIBLIO SUBJECT="XML">
+ <BOOK ISBN="9782212090819" LANG="fr" SUBJECT="applications">
+ <AUTHOR>
+ <FIRSTNAME>Jean-Christophe</FIRSTNAME>
+ <LASTNAME>Bernadac</LASTNAME>
+ </AUTHOR>
+ <AUTHOR>
+ <FIRSTNAME>François</FIRSTNAME>
+ <LASTNAME>Knab</LASTNAME>
+ </AUTHOR>
+ <TITLE>Construire une application XML</TITLE>
+ <PUBLISHER>
+ <NAME>Eyrolles</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>1999</DATEPUB>
+ </BOOK>
+ <BOOK ISBN="9782840825685" LANG="fr" SUBJECT="applications">
+ <AUTHOR>
+ <FIRSTNAME>William J.</FIRSTNAME>
+ <LASTNAME>Pardi</LASTNAME>
+ </AUTHOR>
+ <TRANSLATOR PREFIX="adapté de l'anglais par">
+ <FIRSTNAME>James</FIRSTNAME>
+ <LASTNAME>Guerin</LASTNAME>
+ </TRANSLATOR>
+ <TITLE>XML en Action</TITLE>
+ <PUBLISHER>
+ <NAME>Microsoft Press</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>1999</DATEPUB>
+ </BOOK>
+</BIBLIO>
diff --git a/storage/connect/mysql-test/connect/std_data/xsample2.xml b/storage/connect/mysql-test/connect/std_data/xsample2.xml
new file mode 100644
index 00000000..35295844
--- /dev/null
+++ b/storage/connect/mysql-test/connect/std_data/xsample2.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BIBLIO SUBJECT="XML">
+ <BOOK ISBN="9782212090819" LANG="fr" SUBJECT="applications">
+ <AUTHOR>
+ <FIRSTNAME>Jean-Christophe</FIRSTNAME>
+ <LASTNAME>Bernadac</LASTNAME>
+ </AUTHOR>
+ <AUTHOR>
+ <FIRSTNAME>François</FIRSTNAME>
+ <LASTNAME>Knab</LASTNAME>
+ </AUTHOR>
+ <TITLE>Construire une application XML</TITLE>
+ <PUBLISHER>
+ <NAME>Eyrolles</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>1999</DATEPUB>
+ </BOOK>
+ <BOOK ISBN="9782840825685" LANG="fr" SUBJECT="applications">
+ <AUTHOR>
+ <FIRSTNAME>William J.</FIRSTNAME>
+ <LASTNAME>Pardi</LASTNAME>
+ </AUTHOR>
+ <TRANSLATOR PREFIX="adapté de l'anglais par">
+ <FIRSTNAME>James</FIRSTNAME>
+ <LASTNAME>Guerin</LASTNAME>
+ </TRANSLATOR>
+ <TITLE>XML en Action</TITLE>
+ <PUBLISHER>
+ <NAME>Microsoft Press</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>1999</DATEPUB>
+ </BOOK>
+ <BOOK ISBN="9782212090529" LANG="fr" SUBJECT="général">
+ <AUTHOR>
+ <FIRSTNAME>Alain</FIRSTNAME>
+ <LASTNAME>Michard</LASTNAME>
+ </AUTHOR>
+ <TITLE>XML, Langage et Applications</TITLE>
+ <PUBLISHER>
+ <NAME>Eyrolles</NAME>
+ <PLACE>Paris</PLACE>
+ </PUBLISHER>
+ <DATEPUB>2003</DATEPUB>
+ </BOOK>
+</BIBLIO>
diff --git a/storage/connect/mysql-test/connect/suite.opt b/storage/connect/mysql-test/connect/suite.opt
new file mode 100644
index 00000000..a67571f5
--- /dev/null
+++ b/storage/connect/mysql-test/connect/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$HA_CONNECT_SO --plugin-connect=ON
diff --git a/storage/connect/mysql-test/connect/suite.pm b/storage/connect/mysql-test/connect/suite.pm
new file mode 100644
index 00000000..2dabbc82
--- /dev/null
+++ b/storage/connect/mysql-test/connect/suite.pm
@@ -0,0 +1,16 @@
+package My::Suite::Connect;
+
+@ISA = qw(My::Suite);
+
+return "No CONNECT engine" unless $ENV{HA_CONNECT_SO} or
+ $::mysqld_variables{'connect'} eq "ON";
+
+# RECOMPILE_FOR_EMBEDDED also means that a plugin
+# cannot be dynamically loaded into embedded
+return "Not run for embedded server" if $::opt_embedded_server and
+ $ENV{HA_CONNECT_SO};
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/storage/connect/mysql-test/connect/t/alter.test b/storage/connect/mysql-test/connect/t/alter.test
new file mode 100644
index 00000000..0eda6355
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/alter.test
@@ -0,0 +1,139 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # Testing indexing with ALTER on inward table (in-place)
+--echo #
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT;
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+SELECT * FROM t1;
+CREATE INDEX xc ON t1(c);
+DESCRIBE SELECT * FROM t1 WHERE c = 2;
+DROP INDEX xc ON t1;
+CREATE INDEX xd ON t1(d);
+DROP INDEX xd ON t1;
+ALTER TABLE t1 ADD INDEX xc (c), ADD INDEX xd (d);
+SHOW INDEX FROM t1;
+ALTER TABLE t1 DROP INDEX xc, DROP INDEX xd;
+SHOW INDEX FROM t1;
+
+--echo #
+--echo # Testing modifying columns inward table (not in-place)
+--echo #
+ALTER TABLE t1 MODIFY COLUMN c CHAR(5) NOT NULL;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+ALTER TABLE t1 MODIFY COLUMN c INT NOT NULL;
+
+--echo #
+--echo # Fails because indexing must be in-place
+--echo #
+--error ER_ALTER_OPERATION_NOT_SUPPORTED
+ALTER TABLE t1 MODIFY COLUMN c CHAR(10) NOT NULL, ADD INDEX xd (d);
+
+--echo #
+--echo # Testing changing table type (not in-place)
+--echo #
+ALTER TABLE t1 TABLE_TYPE=CSV HEADER=1 QUOTED=1;
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+
+--echo # create an outward table used to see the t1 file
+CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.csv';
+SELECT * FROM t2;
+
+--echo #
+--echo # Testing changing engine
+--echo #
+DROP TABLE t1;
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT;
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+ALTER TABLE t1 ADD INDEX xc (c), ADD INDEX xd (d);
+ALTER TABLE t1 ENGINE = MYISAM;
+SHOW CREATE TABLE t1;
+SHOW INDEX FROM t1;
+SELECT * FROM t1;
+ALTER TABLE t1 ENGINE = CONNECT TABLE_TYPE=DBF;
+SHOW CREATE TABLE t1;
+SHOW INDEX FROM t1;
+SELECT * FROM t1;
+DROP TABLE t1, t2;
+
+--echo #
+--echo # Testing ALTER on outward tables
+--echo #
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='tf1.txt' ENDING=1;
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+SELECT * FROM t1;
+CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='tf1.txt';
+SELECT * FROM t2;
+
+--echo #
+--echo # Indexing works the same
+--echo #
+ALTER TABLE t1 ADD INDEX xc (c), ADD INDEX xd (d);
+SHOW INDEX FROM t1;
+SELECT d FROM t1 WHERE c = 2;
+ALTER TABLE t1 DROP INDEX xc, DROP INDEX xd;
+SHOW INDEX FROM t1;
+
+--echo #
+--echo # Other alterations do not modify the file
+--echo #
+ALTER TABLE t1 MODIFY COLUMN c CHAR(5) NOT NULL;
+SELECT * FROM t2;
+SHOW CREATE TABLE t1;
+#Wrong result
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+ALTER TABLE t1 MODIFY COLUMN c INT NOT NULL;
+
+--echo #
+--echo # Changing column order
+--echo #
+ALTER TABLE t1 MODIFY COLUMN c INT NOT NULL AFTER d;
+SELECT * FROM t2;
+SHOW CREATE TABLE t1;
+--echo # Wrong result
+SELECT * FROM t1;
+ALTER TABLE t1 MODIFY COLUMN c INT NOT NULL FIRST;
+--echo # What should have been done
+ALTER TABLE t1 MODIFY c INT NOT NULL FLAG=0 AFTER d, MODIFY d CHAR(10) NOT NULL FLAG=11;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+
+--echo #
+--echo # Changing to another engine is Ok
+--echo # However, the data file is not deleted.
+--echo #
+ALTER TABLE t1 ENGINE=ARIA;
+SHOW CREATE TABLE t1;
+set @old_sql_mode=@@sql_mode;
+set sql_mode=ignore_bad_table_options;
+SHOW CREATE TABLE t1;
+set sql_mode=@old_sql_mode;
+SELECT * from t1;
+SELECT * from t2;
+
+--echo #
+--echo # Changing back to CONNECT fails
+--echo # Sure enough, the data file was not deleted.
+--echo #
+--error ER_UNKNOWN_ERROR
+ALTER TABLE t1 ENGINE=CONNECT;
+
+--echo #
+--echo # But changing back to CONNECT succeed
+--echo # if the data file does not exist.
+--echo #
+--remove_file $MYSQLD_DATADIR/test/tf1.txt
+ALTER TABLE t1 ENGINE=CONNECT;
+SHOW CREATE TABLE t1;
+SELECT * from t1;
+SELECT * from t2;
+
+DROP TABLE t1, t2;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/tf1.txt
diff --git a/storage/connect/mysql-test/connect/t/alter_engine.test b/storage/connect/mysql-test/connect/t/alter_engine.test
new file mode 100644
index 00000000..789a0955
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/alter_engine.test
@@ -0,0 +1,11 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # MDEV-24422 Server crashes in GetTypeID / ha_connect::GetRealType upon
+--echo # altering table engine
+--echo #
+
+CREATE TABLE t1 (f INT) ENGINE=CONNECT;
+ALTER TABLE t1 ENGINE InnoDB;
+ALTER TABLE t1 ENGINE CONNECT;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/alter_xml.test b/storage/connect/mysql-test/connect/t/alter_xml.test
new file mode 100644
index 00000000..4c2e1670
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/alter_xml.test
@@ -0,0 +1,29 @@
+--source windows.inc
+
+--echo #
+--echo # Testing changing table type (not in-place)
+--echo #
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV HEADER=1 QUOTED=1;
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+SELECT * FROM t1;
+
+--echo # This would fail if the top node name is not specified.
+--echo # This is because the XML top node name defaults to the table name.
+--echo # Sure enough the temporary table name begins with '#' and is rejected by XML.
+--echo # Therefore the top node name must be specified (along with the row nodes name).
+ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='xmlsup=domdoc,rownode=row';
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+
+--echo # Let us see the XML file
+CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.xml';
+SELECT * FROM t2;
+--echo # NOTE: The first (ignored) row is due to the remaining HEADER=1 option.
+
+--echo # Testing field option modification
+ALTER TABLE t1 MODIFY d CHAR(10) NOT NULL XPATH='@', HEADER=0;
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+SELECT * FROM t2;
+
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/t/alter_xml2.test b/storage/connect/mysql-test/connect/t/alter_xml2.test
new file mode 100644
index 00000000..ec4065ba
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/alter_xml2.test
@@ -0,0 +1,29 @@
+--source have_libxml2.inc
+
+--echo #
+--echo # Testing changing table type (not in-place)
+--echo #
+CREATE TABLE t1 (c INT NOT NULL, d CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=CSV HEADER=1 QUOTED=1;
+INSERT INTO t1 VALUES (1,'One'), (2,'Two'), (3,'Three');
+SELECT * FROM t1;
+
+--echo # This would fail if the top node name is not specified.
+--echo # This is because the XML top node name defaults to the table name.
+--echo # Sure enough the temporary table name begins with '#' and is rejected by XML.
+--echo # Therefore the top node name must be specified (along with the row nodes name).
+ALTER TABLE t1 TABLE_TYPE=XML TABNAME=t1 OPTION_LIST='xmlsup=libxml2,rownode=row';
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+
+--echo # Let us see the XML file
+CREATE TABLE t2 (line VARCHAR(100) NOT NULL) ENGINE=CONNECT FILE_NAME='t1.xml';
+SELECT * FROM t2;
+--echo # NOTE: The first (ignored) row is due to the remaining HEADER=1 option.
+
+--echo # Testing field option modification
+ALTER TABLE t1 MODIFY d CHAR(10) NOT NULL XPATH='@', HEADER=0;
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+SELECT * FROM t2;
+
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/t/bin.test b/storage/connect/mysql-test/connect/t/bin.test
new file mode 100644
index 00000000..1e45bcaf
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/bin.test
@@ -0,0 +1,77 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=BIN FILE_NAME='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+SET time_zone='+00:00';
+CREATE TABLE t1
+(
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL,
+ id CHAR(5) NOT NULL FIELD_FORMAT='S',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+ dept INT(4) NOT NULL FIELD_FORMAT='S'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
+SELECT * FROM t1;
+
+--error ER_GET_ERRMSG
+INSERT INTO t1 VALUES (55555,'RONALD','1980-02-26','3333',4444.44,555);
+INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1
+(
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL,
+ id CHAR(5) NOT NULL FIELD_FORMAT='S',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+ dept INT(4) NOT NULL FIELD_FORMAT='S'
+) ENGINE=CONNECT TABLE_TYPE=BIN READONLY=Yes FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+ALTER TABLE t1 READONLY=NO;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=YES;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (7777,'BILL','1973-06-30',4444,5555.555,777);
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that the underlying file is created
+--echo #
+CREATE TABLE t1
+(
+ c CHAR(4) NOT NULL FIELD_FORMAT='C'
+) ENGINE=CONNECT TABLE_TYPE=BIN FILE_NAME='bin2.dat';
+INSERT INTO t1 VALUES (10),(20),(300),(4000);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/Testbal.dat
+--remove_file $MYSQLD_DATADIR/test/bin2.dat
diff --git a/storage/connect/mysql-test/connect/t/bson.test b/storage/connect/mysql-test/connect/t/bson.test
new file mode 100644
index 00000000..ab38cab7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/bson.test
@@ -0,0 +1,294 @@
+--source include/not_embedded.inc
+--source include/have_partition.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/biblio.json $MYSQLD_DATADIR/test/biblio.json
+--copy_file $MTR_SUITE_DIR/std_data/bib0.json $MYSQLD_DATADIR/test/bib0.json
+--copy_file $MTR_SUITE_DIR/std_data/expense.json $MYSQLD_DATADIR/test/expense.json
+--copy_file $MTR_SUITE_DIR/std_data/mulexp3.json $MYSQLD_DATADIR/test/mulexp3.json
+--copy_file $MTR_SUITE_DIR/std_data/mulexp4.json $MYSQLD_DATADIR/test/mulexp4.json
+--copy_file $MTR_SUITE_DIR/std_data/mulexp5.json $MYSQLD_DATADIR/test/mulexp5.json
+
+--echo #
+--echo # Testing doc samples
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15),
+ LANG CHAR(2),
+ SUBJECT CHAR(32),
+ AUTHOR CHAR(64),
+ TITLE CHAR(32),
+ TRANSLATION CHAR(32),
+ TRANSLATOR CHAR(80),
+ PUBLISHER CHAR(32),
+ DATEPUB int(4)
+) ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing Jpath. Get the number of authors
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15),
+ Language CHAR(2) JPATH='$.LANG',
+ Subject CHAR(32) JPATH='$.SUBJECT',
+ Authors INT(2) JPATH='$.AUTHOR[#]',
+ Title CHAR(32) JPATH='$.TITLE',
+ Translation CHAR(32) JPATH='$.TRANSLATION',
+ Translator CHAR(80) JPATH='$.TRANSLATOR',
+ Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+ Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+ Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Concatenates the authors
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15),
+ Language CHAR(2) JPATH='$.LANG',
+ Subject CHAR(32) JPATH='$.SUBJECT',
+ AuthorFN CHAR(128) JPATH='$.AUTHOR[" and "].FIRSTNAME',
+ AuthorLN CHAR(128) JPATH='$.AUTHOR[" and "].LASTNAME',
+ Title CHAR(32) JPATH='$.TITLE',
+ Translation CHAR(32) JPATH='$.TRANSLATION',
+ Translator CHAR(80) JPATH='$.TRANSLATOR',
+ Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+ Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+ Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing expanding authors
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15),
+ Language CHAR(2) JPATH='$.LANG',
+ Subject CHAR(32) JPATH='$.SUBJECT',
+ AuthorFN CHAR(128) JPATH='$.AUTHOR[*].FIRSTNAME',
+ AuthorLN CHAR(128) JPATH='$.AUTHOR[*].LASTNAME',
+ Title CHAR(32) JPATH='$.TITLE',
+ Translation CHAR(32) JPATH='$.TRANSLATION',
+ Translator CHAR(80) JPATH='$.TRANSLATOR',
+ Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+ Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+ Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+UPDATE t1 SET AuthorFN = 'Philippe' WHERE AuthorLN = 'Knab';
+SELECT * FROM t1 WHERE ISBN = '9782212090819';
+
+--echo #
+--echo # To add an author a new table must be created
+--echo #
+CREATE TABLE t2 (
+FIRSTNAME CHAR(32),
+LASTNAME CHAR(32))
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json' OPTION_LIST='Object=$[1].AUTHOR';
+SELECT * FROM t2;
+INSERT INTO t2 VALUES('Charles','Dickens');
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP TABLE t2;
+
+--echo #
+--echo # Check the biblio file has the good format
+--echo #
+CREATE TABLE t1
+(
+ line char(255)
+)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='biblio.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing a pretty=0 file
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15) NOT NULL,
+ Language CHAR(2) JPATH='$.LANG',
+ Subject CHAR(32) JPATH='$.SUBJECT',
+ AuthorFN CHAR(128) JPATH='$.AUTHOR[*].FIRSTNAME',
+ AuthorLN CHAR(128) JPATH='$.AUTHOR[*].LASTNAME',
+ Title CHAR(32) JPATH='$.TITLE',
+ Translation CHAR(32) JPATH='$.TRANSLATED.PREFIX',
+ TranslatorFN CHAR(80) JPATH='$.TRANSLATED.TRANSLATOR.FIRSTNAME',
+ TranslatorLN CHAR(80) JPATH='$.TRANSLATED.TRANSLATOR.LASTNAME',
+ Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+ Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+ Year int(4) JPATH='$.DATEPUB',
+ INDEX IX(ISBN)
+)
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='bib0.json' LRECL=320 OPTION_LIST='Pretty=0';
+SHOW INDEX FROM t1;
+SELECT * FROM t1;
+DESCRIBE SELECT * FROM t1 WHERE ISBN = '9782212090819';
+--error ER_GET_ERRMSG
+UPDATE t1 SET AuthorFN = 'Philippe' WHERE ISBN = '9782212090819';
+DROP TABLE t1;
+
+--echo #
+--echo # A file with 2 arrays
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[*].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[].EXPENSE["+"].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[].EXPENSE[+].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Now it can be fully expanded
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[*].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[*].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[*].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+#--error ER_GET_ERRMSG
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # A table showing many calculated results
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12) NOT NULL,
+WEEKS CHAR(12) NOT NULL JPATH='$.WEEK[", "].NUMBER',
+SUMS CHAR(64) NOT NULL JPATH='$.WEEK["+"].EXPENSE[+].AMOUNT',
+SUM DOUBLE(8,2) NOT NULL JPATH='$.WEEK[+].EXPENSE[+].AMOUNT',
+AVGS CHAR(64) NOT NULL JPATH='$.WEEK["+"].EXPENSE[!].AMOUNT',
+SUMAVG DOUBLE(8,2) NOT NULL JPATH='$.WEEK[+].EXPENSE[!].AMOUNT',
+AVGSUM DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[+].AMOUNT',
+AVGAVG DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[!].AMOUNT',
+AVERAGE DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Expand expense in 3 one week tables
+--echo #
+CREATE TABLE t2 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[0].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[0].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[0].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t2;
+
+CREATE TABLE t3 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[1].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[1].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[1].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t3;
+
+CREATE TABLE t4 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[2].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[2].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[2].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='expense.json';
+SELECT * FROM t4;
+
+--echo #
+--echo # The expanded table is made as a TBL table
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32),
+AMOUNT DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t2,t3,t4';
+SELECT * FROM t1;
+DROP TABLE t1, t2, t3, t4;
+
+--echo #
+--echo # Three partial JSON tables
+--echo #
+CREATE TABLE t2 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp3.json';
+SELECT * FROM t2;
+
+CREATE TABLE t3 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp4.json';
+SELECT * FROM t3;
+
+CREATE TABLE t4 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp5.json';
+SELECT * FROM t4;
+
+--echo #
+--echo # The complete table can be a multiple JSON table
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp*.json' MULTIPLE=1;
+SELECT * FROM t1 ORDER BY WHO, WEEK, WHAT, AMOUNT;
+DROP TABLE t1;
+
+--echo #
+--echo # Or also a partition JSON table
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='mulexp%s.json';
+ALTER TABLE t1
+PARTITION BY LIST COLUMNS(WEEK) (
+PARTITION `3` VALUES IN(3),
+PARTITION `4` VALUES IN(4),
+PARTITION `5` VALUES IN(5));
+SHOW WARNINGS;
+SELECT * FROM t1;
+SELECT * FROM t1 WHERE WEEK = 4;
+DROP TABLE t1, t2, t3, t4;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/biblio.json
+--remove_file $MYSQLD_DATADIR/test/bib0.dnx
+--remove_file $MYSQLD_DATADIR/test/bib0.json
+--remove_file $MYSQLD_DATADIR/test/expense.json
+--remove_file $MYSQLD_DATADIR/test/mulexp3.json
+--remove_file $MYSQLD_DATADIR/test/mulexp4.json
+--remove_file $MYSQLD_DATADIR/test/mulexp5.json
diff --git a/storage/connect/mysql-test/connect/t/bson_java_2.test b/storage/connect/mysql-test/connect/t/bson_java_2.test
new file mode 100644
index 00000000..2188d9c2
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/bson_java_2.test
@@ -0,0 +1,14 @@
+-- source jdbconn.inc
+-- source mongo.inc
+
+--disable_query_log
+eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/Mongo2.jar';
+set connect_json_all_path=0;
+--enable_query_log
+let $DRV= Java;
+let $VERS= 2;
+let $TYPE= BSON;
+let $CONN= CONNECTION='mongodb://localhost:27017' LRECL=4096;
+
+-- source mongo_test.inc
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/bson_java_3.test b/storage/connect/mysql-test/connect/t/bson_java_3.test
new file mode 100644
index 00000000..e7dd90b3
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/bson_java_3.test
@@ -0,0 +1,14 @@
+-- source jdbconn.inc
+-- source mongo.inc
+
+--disable_query_log
+eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/Mongo3.jar';
+set connect_json_all_path=0;
+--enable_query_log
+let $DRV= Java;
+let $VERS= 3;
+let $TYPE= BSON;
+let $CONN= CONNECTION='mongodb://localhost:27017' LRECL=4096;
+
+-- source mongo_test.inc
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/bson_mongo_c.test b/storage/connect/mysql-test/connect/t/bson_mongo_c.test
new file mode 100644
index 00000000..938d77c7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/bson_mongo_c.test
@@ -0,0 +1,10 @@
+-- source mongo.inc
+
+let $DRV= C;
+let $VERS= 0;
+let $PROJ= {"projection":;
+let $ENDP= };
+let $TYPE= BSON;
+let $CONN= CONNECTION='mongodb://localhost:27017' LRECL=1024;
+
+-- source mongo_test.inc
diff --git a/storage/connect/mysql-test/connect/t/bson_udf.inc b/storage/connect/mysql-test/connect/t/bson_udf.inc
new file mode 100644
index 00000000..c4722722
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/bson_udf.inc
@@ -0,0 +1,72 @@
+--disable_query_log
+#
+# Check if server has support for loading plugins
+#
+if (`SELECT @@have_dynamic_loading != 'YES'`) {
+ --skip UDF requires dynamic loading
+}
+if (!$HA_CONNECT_SO) {
+ --skip Needs a dynamically built ha_connect.so
+}
+
+--eval CREATE FUNCTION bson_test RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonvalue RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_make_array RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_array_add_values RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_array_add RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_array_delete RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_make_object RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_object_nonull RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_object_key RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_object_add RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_object_delete RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_object_list RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_object_values RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonset_def_prec RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonget_def_prec RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonset_grp_size RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonget_grp_size RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE AGGREGATE FUNCTION bson_array_grp RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE AGGREGATE FUNCTION bson_object_grp RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonlocate RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_locate_all RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_contains RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsoncontains_path RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_item_merge RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_get_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_delete_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonget_string RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonget_int RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bsonget_real RETURNS REAL SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_set_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_insert_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_update_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_file RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bson_serialize RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bfile_make RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bfile_convert RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bfile_bjson RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_make_array RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_array_add RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_array_add_values RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_array_delete RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE AGGREGATE FUNCTION bbin_array_grp RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE AGGREGATE FUNCTION bbin_object_grp RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_make_object RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_object_nonull RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_object_key RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_object_add RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_object_delete RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_object_list RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_object_values RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_get_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_item_merge RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_set_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_insert_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_update_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_delete_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_locate_all RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION bbin_file RETURNS STRING SONAME '$HA_CONNECT_SO';
+
+--enable_query_log
+
diff --git a/storage/connect/mysql-test/connect/t/bson_udf.test b/storage/connect/mysql-test/connect/t/bson_udf.test
new file mode 100644
index 00000000..0da2de38
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/bson_udf.test
@@ -0,0 +1,282 @@
+--source bson_udf.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/biblio.json $MYSQLD_DATADIR/test/biblio.json
+--copy_file $MTR_SUITE_DIR/std_data/employee.dat $MYSQLD_DATADIR/test/employee.dat
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=VIR BLOCK_SIZE=5;
+
+--echo #
+--echo # Test UDF's with constant arguments
+--echo #
+--error ER_CANT_INITIALIZE_UDF
+SELECT BsonValue(56, 3.1416, 'foo', NULL);
+SELECT BsonValue(3.1416);
+SELECT BsonValue(-80);
+SELECT BsonValue('foo');
+SELECT BsonValue(9223372036854775807);
+SELECT BsonValue(NULL);
+SELECT BsonValue(TRUE);
+SELECT BsonValue(FALSE);
+SELECT BsonValue();
+SELECT BsonValue('[11, 22, 33]' json_) FROM t1;
+#
+SELECT Bson_Make_Array();
+SELECT Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL);
+SELECT Bson_Make_Array(Bson_Make_Array(56, 3.1416, 'foo'), TRUE);
+#
+--error ER_CANT_INITIALIZE_UDF
+SELECT Bson_Array_Add(Bson_Make_Array(56, 3.1416, 'foo', NULL)) Array;
+SELECT Bson_Array_Add(Bson_Make_Array(56, 3.1416, 'foo', NULL), 'One more') Array;
+#--error ER_CANT_INITIALIZE_UDF
+SELECT Bson_Array_Add(BsonValue('one value'), 'One more');
+#--error ER_CANT_INITIALIZE_UDF
+SELECT Bson_Array_Add('one value', 'One more');
+SELECT Bson_Array_Add('one value' json_, 'One more');
+#--error ER_CANT_INITIALIZE_UDF
+SELECT Bson_Array_Add(5 json_, 'One more');
+SELECT Bson_Array_Add('[5,3,8,7,9]' json_, 4, 0);
+SELECT Bson_Array_Add('[5,3,8,7,9]' json_, 4, 2) Array;
+SELECT Bson_Array_Add('[5,3,8,7,9]' json_, 4, 9);
+SELECT Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), '[2]', 33, 1);
+SELECT Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), 33, '[2]', 1);
+SELECT Bson_Array_Add(Bson_Make_Array(1, 2, Bson_Make_Array(11, 22)), 33, 1, '[2]');
+#
+SELECT Bson_Array_Add_Values(Bson_Make_Array(56, 3.1416, 'machin', NULL), 'One more', 'Two more') Array;
+SELECT Bson_Array_Add_Values(Bson_Make_Array(56, 3.1416, 'machin'), 'One more', 'Two more') Array FROM t1;
+SELECT Bson_Array_Add_Values(Bson_Make_Array(56, 3.1416, 'machin'), n) Array FROM t1;
+SELECT Bson_Array_Add_Values(Bson_Make_Array(n, 3.1416, 'machin'), n) Array FROM t1;
+SELECT Bson_Array_Add_Values('[56]', 3.1416, 'machin') Array;
+#
+SELECT Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0);
+SELECT Bson_Array_Delete(Bson_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2);
+SELECT Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2');
+SELECT Bson_Array_Delete(Bson_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2); /* WARNING VOID */
+#
+SELECT Bson_Make_Object(56, 3.1416, 'foo', NULL);
+SELECT Bson_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty);
+SELECT Bson_Make_Object();
+SELECT Bson_Make_Object(Bson_Make_Array(56, 3.1416, 'foo'), NULL);
+SELECT Bson_Make_Array(Bson_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL);
+SELECT Bson_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL);
+--error ER_CANT_INITIALIZE_UDF
+SELECT Bson_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty');
+#
+SELECT Bson_Object_Add(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color);
+SELECT Bson_Object_Add(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price);
+SELECT Bson_Object_Add(Bson_File('notexist.json'), 'cheese' item, '[1]', 1);
+#
+SELECT Bson_Object_Delete(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc');
+SELECT Bson_Object_Delete(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose');
+#
+SELECT Bson_Object_List(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty)) "Key List";
+SELECT Bson_Object_List('{"qty":56, "price":3.1416, "truc":"machin", "garanty":null}') "Key List";
+SELECT Bson_Object_Values('{"One":1,"Two":2,"Three":3}') "Value List";
+
+--echo #
+--echo # Test UDF's with column arguments
+--echo #
+SELECT Bsonset_Def_Prec(2);
+CREATE TABLE t2
+(
+ ISBN CHAR(15),
+ LANG CHAR(2),
+ SUBJECT CHAR(32),
+ AUTHOR CHAR(64),
+ TITLE CHAR(32),
+ TRANSLATION CHAR(32),
+ TRANSLATOR CHAR(80),
+ PUBLISHER CHAR(32),
+ DATEPUB int(4)
+) ENGINE=CONNECT TABLE_TYPE=BSON FILE_NAME='biblio.json';
+
+SELECT Bson_Make_Array(AUTHOR, TITLE, DATEPUB) FROM t2;
+SELECT Bson_Make_Object(AUTHOR, TITLE, DATEPUB) FROM t2;
+--error ER_CANT_INITIALIZE_UDF
+SELECT Bson_Array_Grp(TITLE, DATEPUB) FROM t2;
+SELECT Bson_Array_Grp(TITLE) FROM t2;
+
+CREATE TABLE t3 (
+ SERIALNO CHAR(5) NOT NULL,
+ NAME VARCHAR(12) NOT NULL FLAG=6,
+ SEX SMALLINT(1) NOT NULL,
+ TITLE VARCHAR(15) NOT NULL FLAG=20,
+ MANAGER CHAR(5) DEFAULT NULL,
+ DEPARTMENT CHAr(4) NOT NULL FLAG=41,
+ SECRETARY CHAR(5) DEFAULT NULL FLAG=46,
+ SALARY DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=8 FILE_NAME='employee.dat' ENDING=1;
+
+SELECT Bson_Make_Object(SERIALNO, NAME, TITLE, SALARY) FROM t3 WHERE NAME = 'MERCHANT';
+SELECT DEPARTMENT, Bson_Array_Grp(NAME) FROM t3 GROUP BY DEPARTMENT;
+#SET connect_json_grp_size=30; Deprecated
+SELECT BsonSet_Grp_Size(30);
+SELECT Bson_Make_Object(title, Bson_Array_Grp(name) `json_names`) from t3 GROUP BY title;
+SELECT Bson_Make_Array(DEPARTMENT, Bson_Array_Grp(NAME)) FROM t3 GROUP BY DEPARTMENT;
+SELECT Bson_Make_Object(DEPARTMENT, Bson_Array_Grp(NAME) json_NAMES) FROM t3 GROUP BY DEPARTMENT;
+SELECT Bson_Make_Object(DEPARTMENT, Bson_Array_Grp(Bson_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT;
+SELECT Bson_Make_Object(DEPARTMENT, TITLE, Bson_Array_Grp(Bson_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT, TITLE;
+--error ER_CANT_INITIALIZE_UDF
+SELECT Bson_Object_Grp(SALARY) FROM t3;
+SELECT Bson_Object_Grp(NAME, SALARY) FROM t3;
+SELECT Bson_Make_Object(DEPARTMENT, Bson_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT;
+SELECT Bson_Array_Grp(NAME) FROM t3;
+#
+SELECT Bson_Object_Key(name, title) FROM t3 WHERE DEPARTMENT = 318;
+SELECT Bson_Object_Grp(name, title) FROM t3 WHERE DEPARTMENT = 318;
+
+--echo #
+--echo # Test value getting UDF's
+--echo #
+SELECT BsonGet_String(Bson_Array_Grp(name),'[#]') FROM t3;
+SELECT BsonGet_String(Bson_Array_Grp(name),'[","]') FROM t3;
+SELECT BsonGet_String(Bson_Array_Grp(name),'[>]') FROM t3;
+SET @j1 = '[45,28,36,45,89]';
+SELECT BsonGet_String(@j1,'1');
+SELECT BsonGet_String(@j1 json_,'3');
+SELECT BsonGet_String(Bson_Make_Array(45,28,36,45,89),'3');
+SELECT BsonGet_String(Bson_Make_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",BsonGet_String(Bson_Make_Array(45,28,36,45,89),'[+]') "sum";
+SELECT BsonGet_String(Bson_Make_Array(Bson_Make_Array(45,28),Bson_Make_Array(36,45,89)),'1.0');
+SELECT BsonGet_String(Bson_Make_Array(Bson_Make_Array(45,28),Bson_Make_Array(36,45,89)),'1.*');
+SELECT BsonGet_String(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc');
+SET @j2 = '{"qty":56,"price":3.141600,"truc":"machin","garanty":null}';
+SELECT BsonGet_String(@j2 json_,'truc');
+SELECT BsonGet_String(@j2,'truc');
+SELECT BsonGet_String(@j2,'chose');
+SELECT BsonGet_String(NULL json_, NULL); /* NULL WARNING */
+SELECT department, BsonGet_String(Bson_Make_Object(department, Bson_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+#
+SELECT BsonGet_Int(@j1, '4');
+SELECT BsonGet_Int(@j1, '[#]');
+SELECT BsonGet_Int(@j1, '[+]');
+SELECT BsonGet_Int(@j1 json_, '3');
+SELECT BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '3');
+SELECT BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '["+"]');
+SELECT BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '[+]');
+SELECT BsonGet_Int(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '1.0');
+SELECT BsonGet_Int(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '0.1');
+SELECT BsonGet_Int(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty');
+SELECT BsonGet_Int(@j2 json_, 'price');
+SELECT BsonGet_Int(@j2, 'qty');
+SELECT BsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose');
+SELECT BsonGet_Int(BsonGet_String(Bson_Make_Array(Bson_Make_Array(45,28),Bson_Make_Array(36,45,89)), '1.*'), '[+]') sum;
+SELECT department, BsonGet_Int(Bson_Make_Object(department, Bson_Array_Grp(salary) "Json_salaries"), 'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+#
+SELECT BsonGet_Real(@j1, '2');
+SELECT BsonGet_Real(@j1 json_, '3', 2);
+SELECT BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '3');
+SELECT BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '["+"]');
+SELECT BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '[+]');
+SELECT BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '[!]');
+SELECT BsonGet_Real(Bson_Make_Array(Bson_Make_Array(45,28), Bson_Make_Array(36,45,89)), '1.0');
+SELECT BsonGet_Real(Bson_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price');
+SELECT BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty');
+SELECT BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price');
+SELECT BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price', 4);
+SELECT BsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose');
+SELECT department, BsonGet_Real(Bson_Make_Object(department, Bson_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+
+--echo #
+--echo # Documentation examples
+--echo #
+SELECT
+ BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '4') "Rank",
+ BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '[#]') "Number",
+ BsonGet_String(Bson_Make_Array(45,28,36,45,89), '[","]') "Concat",
+ BsonGet_Int(Bson_Make_Array(45,28,36,45,89), '[+]') "Sum",
+ BsonGet_Real(Bson_Make_Array(45,28,36,45,89), '[!]', 2) "Avg";
+SELECT
+ BsonGet_String('{"qty":7,"price":29.50,"garanty":null}', 'price') "String",
+ BsonGet_Int('{"qty":7,"price":29.50,"garanty":null}', 'price') "Int",
+ BsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price') "Real";
+SELECT BsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price', 3) "Real";
+
+--echo #
+--echo # Testing Locate
+--echo #
+SELECT BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin');
+SELECT BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56);
+SELECT BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416);
+SELECT BsonLocate(Bson_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose');
+SELECT BsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'Jack') Path;
+SELECT BsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'jack' ci) Path;
+SELECT BsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"Jack", "LN":"London"}' json_) Path;
+SELECT BsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"jack", "LN":"London"}' json_) Path;
+SELECT BsonLocate('[45,28,36,45,89]',36);
+SELECT BsonLocate('[45,28,36,45,89]' json_,28.0);
+SELECT Bson_Locate_All('[45,28,36,45,89]',10);
+SELECT Bson_Locate_All('[45,28,36,45,89]',45);
+SELECT Bson_Locate_All('[[45,28],36,45,89]',45);
+SELECT Bson_Locate_All('[[45,28,45],36,45,89]',45);
+SELECT Bson_Locate_All('[[45,28,45],36,45,89]',BsonGet_Int('[3,45]','[1]'));
+SELECT BsonLocate('[[45,28,45],36,45,89]',45,n) from t1;
+SELECT BsonGet_String(Bson_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) FROM t1;
+SELECT BsonGet_String(Bson_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) AS `Path` FROM t1 GROUP BY n HAVING `Path` IS NOT NULL;
+SELECT Bson_Locate_All('[45,28,[36,45,89]]',45);
+SELECT Bson_Locate_All('[[45,28],[36,45.0,89]]',BsonValue(45.0));
+SELECT Bson_Locate_All('[[45,28],[36,45.0,89]]',45.0);
+SELECT BsonLocate('[[45,28],[36,45,89]]','[36,45,89]' json_);
+SELECT BsonLocate('[[45,28],[36,45,89]]','[45,28]' json_);
+SELECT Bson_Locate_All('[[45,28],[[36,45],89]]','45') "All paths";
+SELECT Bson_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_);
+SELECT BsonGet_Int(Bson_Locate_All('[[45,28],[[36,45],89]]',45), '[#]') "Nb of occurs";
+SELECT Bson_Locate_All('[[45,28],[[36,45],89]]',45,2);
+SELECT BsonGet_String(Bson_Locate_All('[45,28,36,45,89]',45),'0');
+SELECT BsonLocate(Bson_File('test/biblio.json'), 'Knab');
+SELECT Bson_Locate_All('test/biblio.json' jfile_, 'Knab');
+
+--echo #
+--echo # Testing json files
+--echo #
+SELECT Bfile_Make('[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},
+{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},
+{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]', 'test/fx.json', 0) AS NewFile;
+SELECT Bfile_Make('test/fx.json', 1);
+SELECT Bfile_Make('test/fx.json' jfile_);
+SELECT Bfile_Make(Bbin_File('test/fx.json'), 0);
+SELECT Bson_File('test/fx.json', 1);
+SELECT Bson_File('test/fx.json', 2);
+SELECT Bson_File('test/fx.json', 0);
+SELECT Bson_File('test/fx.json', '0');
+SELECT Bson_File('test/fx.json', '[?]');
+SELECT BsonGet_String(Bson_File('test/fx.json'), '1.*');
+SELECT BsonGet_String(Bson_File('test/fx.json'), '1');
+SELECT BsonGet_Int(Bson_File('test/fx.json'), '1.mileage') AS Mileage;
+SELECT BsonGet_Real(Bson_File('test/fx.json'), '0.price', 2) AS Price;
+SELECT Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 'ratings');
+SELECT Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 1, 'ratings');
+SELECT Bson_Array_Add(Bson_File('test/fx.json', '2'), 6, 'ratings', 1);
+SELECT Bson_Array_Add(Bson_File('test/fx.json', '2.ratings'), 6, 0);
+SELECT Bson_Array_Delete(Bson_File('test/fx.json', '2'), 'ratings', 1);
+SELECT Bson_Object_Add(Bson_File('test/fx.json', '2'), 'france' origin);
+SELECT Bson_Object_Add(Bson_File('test/fx.json', '2'), 70 H, 'size');
+SELECT Bson_Object_Add(Bson_File('test/fx.json', '3'), 70 H, 'size');
+SELECT Bson_Object_List(Bson_File('test/fx.json', '3.size'));
+
+--echo #
+--echo # Testing new functions
+--echo #
+SELECT Bson_Item_Merge('["a","b","c"]','["d","e","f"]') as "Result";
+SELECT Bson_Item_Merge(Bson_Make_Array('a','b','c'), Bson_Make_Array('d','e','f')) as "Result";
+SELECT
+Bson_Set_Item('[1,2,3,{"quatre":4}]', 'foo', '$[1]', 5, '$[3].cinq') as "Set",
+Bson_Insert_Item('[1,2,3,{"quatre":4}]', 'foo', '$[1]', 5, '$[3].cinq') as "Insert",
+Bson_Update_Item(Bson_Make_Array(1,2,3,Bson_Object_Key('quatre',4)),'foo','$[1]',5,'$[3].cinq') "Update";
+SELECT bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','1','[2].Deux');
+SELECT bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','["[1]","[3].Deux"]');
+SELECT bson_delete_item('[1,2,3,{"quatre":4,"Deux":2}]','$.[3].Deux');
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+SELECT BsonSet_Grp_Size(10);
+
+#
+# Clean up
+#
+--source bson_udf2.inc
+--remove_file $MYSQLD_DATADIR/test/biblio.json
+--remove_file $MYSQLD_DATADIR/test/employee.dat
+--remove_file $MYSQLD_DATADIR/test/fx.json
+
diff --git a/storage/connect/mysql-test/connect/t/bson_udf2.inc b/storage/connect/mysql-test/connect/t/bson_udf2.inc
new file mode 100644
index 00000000..d06d7fac
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/bson_udf2.inc
@@ -0,0 +1,63 @@
+--disable_query_log
+
+DROP FUNCTION bson_test;
+DROP FUNCTION bsonvalue;
+DROP FUNCTION bson_make_array;
+DROP FUNCTION bson_array_add_values;
+DROP FUNCTION bson_array_add;
+DROP FUNCTION bson_array_delete;
+DROP FUNCTION bson_make_object;
+DROP FUNCTION bson_object_nonull;
+DROP FUNCTION bson_object_key;
+DROP FUNCTION bson_object_add;
+DROP FUNCTION bson_object_delete;
+DROP FUNCTION bson_object_list;
+DROP FUNCTION bson_object_values;
+DROP FUNCTION bsonset_def_prec;
+DROP FUNCTION bsonget_def_prec;
+DROP FUNCTION bsonset_grp_size;
+DROP FUNCTION bsonget_grp_size;
+DROP FUNCTION bson_array_grp;
+DROP FUNCTION bson_object_grp;
+DROP FUNCTION bsonlocate;
+DROP FUNCTION bson_locate_all;
+DROP FUNCTION bson_contains;
+DROP FUNCTION bsoncontains_path;
+DROP FUNCTION bson_item_merge;
+DROP FUNCTION bson_get_item;
+DROP FUNCTION bson_delete_item;
+DROP FUNCTION bsonget_string;
+DROP FUNCTION bsonget_int;
+DROP FUNCTION bsonget_real;
+DROP FUNCTION bson_set_item;
+DROP FUNCTION bson_insert_item;
+DROP FUNCTION bson_update_item;
+DROP FUNCTION bson_serialize;
+DROP FUNCTION bson_file;
+DROP FUNCTION bfile_make;
+DROP FUNCTION bfile_convert;
+DROP FUNCTION bfile_bjson;
+DROP FUNCTION bbin_make_array;
+DROP FUNCTION bbin_array_add;
+DROP FUNCTION bbin_array_add_values;
+DROP FUNCTION bbin_array_delete;
+DROP FUNCTION bbin_array_grp;
+DROP FUNCTION bbin_object_grp;
+DROP FUNCTION bbin_make_object;
+DROP FUNCTION bbin_object_nonull;
+DROP FUNCTION bbin_object_key;
+DROP FUNCTION bbin_object_add;
+DROP FUNCTION bbin_object_delete;
+DROP FUNCTION bbin_object_list;
+DROP FUNCTION bbin_object_values;
+DROP FUNCTION bbin_get_item;
+DROP FUNCTION bbin_set_item;
+DROP FUNCTION bbin_insert_item;
+DROP FUNCTION bbin_update_item;
+DROP FUNCTION bbin_item_merge;
+DROP FUNCTION bbin_delete_item;
+DROP FUNCTION bbin_locate_all;
+DROP FUNCTION bbin_file;
+
+--enable_query_log
+
diff --git a/storage/connect/mysql-test/connect/t/csv.test b/storage/connect/mysql-test/connect/t/csv.test
new file mode 100644
index 00000000..5662fdb7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/csv.test
@@ -0,0 +1,185 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/people.csv $MYSQLD_DATADIR/test/people.csv
+
+SET NAMES utf8;
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=CSV FILE_NAME='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing examples from the manual
+--echo #
+CREATE TABLE t1
+(
+ name CHAR(12) NOT NULL,
+ birth DATE NOT NULL DATE_FORMAT='DD/MM/YY',
+ children SMALLINT(2) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
+ HEADER=1 SEP_CHAR=';' QUOTED=1;
+SELECT * FROM t1;
+INSERT INTO t1 VALUES ('RONALD','1980-02-26',4);
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/people.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/people.csv'),'\r\n','\n');
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1
+(
+ name CHAR(12) NOT NULL,
+ birth DATE NOT NULL DATE_FORMAT='DD/MM/YY',
+ children SMALLINT(2) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='people.csv'
+ HEADER=1 SEP_CHAR=';' QUOTED=1 READONLY=yes;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+--error ER_GET_ERRMSG
+UPDATE t1 SET children=6 WHERE name='BILL';
+--error ER_GET_ERRMSG
+DELETE FROM t1 WHERE name='BILL';
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=no;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES ('BILL','1973-06-30',5);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that the underlying file is created
+--echo #
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL,
+ c2 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='tmp.csv'
+ HEADER=1 SEP_CHAR=',' QUOTED=1;
+INSERT INTO t1 VALUES (10,10),(20,20),(300,300),(4000,4000), ('a b','c d');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/tmp.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/tmp.csv'),'\r\n','\n');
+
+--echo #
+--echo # Creating a CSV table from a MyISAM table
+--echo #
+CREATE TABLE t1 (a VARCHAR(10) NOT NULL, b INT NOT NULL) ENGINE=MyISAM;
+INSERT INTO t1 VALUES ('test1',1), ('test2',2);
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t2.csv'
+ AS SELECT * FROM t1;
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t2.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t2.csv'),'\r\n','\n');
+--remove_file $MYSQLD_DATADIR/test/t2.csv
+
+--echo #
+--echo # Testing international data
+--echo #
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=utf8;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=utf8 DATA_CHARSET=latin1;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv';
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=latin1;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv'
+ CHARSET=latin1 DATA_CHARSET=utf8;
+INSERT INTO t1 VALUES ('á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+CREATE TABLE t1
+(
+ c1 CHAR(12) CHARACTER SET latin1 NOT NULL,
+ c2 CHAR(12) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='t1.csv';
+INSERT INTO t1 VALUES ('á','á');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.csv
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT HEX(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.csv'),'\r\n','\n'));
+--remove_file $MYSQLD_DATADIR/test/t1.csv
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/people.csv
+--remove_file $MYSQLD_DATADIR/test/tmp.csv
diff --git a/storage/connect/mysql-test/connect/t/datest.test b/storage/connect/mysql-test/connect/t/datest.test
new file mode 100644
index 00000000..e9ee28ed
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/datest.test
@@ -0,0 +1,28 @@
+--echo #
+--echo # Testing out of range dates as (var)char
+--echo #
+CREATE TABLE t1 (
+id INT NOT NULL,
+dat CHAR(10) NOT NULL,
+tim CHAR(8) DEFAULT '09:35:08',
+datim CHAR(19) DEFAULT '1789-08-10 14:20:30')
+ENGINE=CONNECT TABLE_TYPE=FIX;
+INSERT INTO t1(id,dat) VALUES(1,'1515-04-01'),(2,'2014-07-26'),(3,'2118-11-02');
+SELECT * FROM t1;
+SELECT id, DATE(datim) FROM t1 LIMIT 1;
+SELECT id, DAYNAME(dat) FROM t1;
+SELECT id, DAYNAME(datim) FROM t1 LIMIT 1;
+SELECT id, TIME(tim) FROM t1 LIMIT 1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing use of dates in where clause (MDEV-8926)
+--echo #
+CREATE TABLE t1 (col1 DATE) ENGINE=CONNECT TABLE_TYPE=CSV;
+INSERT INTO t1 VALUES('2015-01-01'),('2015-02-01'),('2015-03-01'),('2015-04-01');
+SELECT * FROM t1 WHERE col1 = '2015-02-01';
+SELECT * FROM t1 WHERE col1 > '2015-02-01';
+SELECT * FROM t1 WHERE col1 >= '2015-02-01';
+SELECT * FROM t1 WHERE col1 < '2015-02-01';
+SELECT * FROM t1 WHERE col1 <= '2015-02-01';
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/dbf.test b/storage/connect/mysql-test/connect/t/dbf.test
new file mode 100644
index 00000000..b798b1a2
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/dbf.test
@@ -0,0 +1,511 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+SHOW CREATE TABLE t1;
+--replace_regex /on .*test.t1.dbf/on DATADIR\/test\/t1.dbf/
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--replace_regex /Cannot open .*test.t1.dbf/Cannot open DATADIR\/test\/t1.dbf/
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--replace_regex /Cannot open .*test.t1.dbf/Cannot open DATADIR\/test\/t1.dbf/
+SHOW WARNINGS;
+
+
+DELIMITER //;
+CREATE PROCEDURE test.dbf_field(in fieldno INT, in content BLOB) DETERMINISTIC
+BEGIN
+ SELECT '---';
+ SELECT fieldno AS `FieldN`;
+ SELECT TRIM(TRAILING 0x00 FROM LEFT(content, 10)) AS `Name`;
+ SELECT SUBSTRING(content, 12, 1) AS `Type`;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,13,4))),16,10) AS `Offset`;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,17,1))),16,10) AS `Length`;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,18,1))),16,10) AS `Dec`;
+ SELECT HEX(REVERSE(SUBSTRING(content,19,1))) AS `Flags`;
+-- SELECT CONV(HEX(REVERSE(SUBSTRING(content,20,4))),16,10) AS `Next`;
+-- SELECT CONV(HEX(REVERSE(SUBSTRING(content,24,4))),16,10) AS `Step`;
+END//
+
+CREATE PROCEDURE test.dbf_header(in fname VARCHAR(1024)) DETERMINISTIC
+BEGIN
+ DECLARE content BLOB;
+ DECLARE offset INT;
+ DECLARE fieldno INT;
+ SELECT '--------';
+ SELECT LOAD_FILE(fname) INTO content;
+ SELECT LENGTH(content) AS FileSize;
+ SELECT HEX(LEFT(content, 1)) AS DBF_Version;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,5,4))),16,10) AS NRecords;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,9,2))),16,10) AS FirstRecPos;
+ SELECT CONV(HEX(REVERSE(SUBSTRING(content,11,2))),16,10) AS RecLength;
+ SELECT HEX(REVERSE(SUBSTRING(content,29,2))) AS TableFlags;
+ SELECT HEX(REVERSE(SUBSTRING(content,30,1))) AS CodePageMark;
+ SET offset=33;
+ SET fieldno=0;
+ WHILE SUBSTR(content, offset, 1) <> 0x0D AND offset + 32 < LENGTH(content) DO
+ CALL dbf_field(fieldno, SUBSTRING(content, offset, 32));
+ SET offset=offset + 32;
+ SET fieldno=fieldno + 1;
+ END WHILE;
+ SELECT '--------';
+END//
+DELIMITER ;//
+
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (10),(20);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=Yes;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (30);
+--error ER_GET_ERRMSG
+UPDATE t1 SET a=30 WHERE a=10;
+--error ER_GET_ERRMSG
+DELETE FROM t1 WHERE a=10;
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+ALTER TABLE t1 READONLY=NO;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (30);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # This SQL script crashed (dbf01.sql)
+--echo #
+CREATE TABLE t1
+(
+ a int(11) NOT NULL,
+ b char(10) NOT NULL,
+ c varchar(10) NOT NULL
+) ENGINE=CONNECT table_type=DBF file_name='t1.dbf';
+INSERT INTO t1 VALUES (1,'1','1');
+INSERT INTO t1 VALUES (2,'2','2');
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing that table options in lower case and mixed case are understood:
+--echo #
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT table_type=dbf file_name='t1.dbf';
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+CREATE TABLE t1 (a CHAR(10) NOT NULL) ENGINE=CONNECT Table_Type=dbf File_Name='t1.dbf';
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES ('test');
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+#
+# TODO: this creates DBF record with length=32, which looks wrong
+#
+--echo #
+--echo # Testing multiple columns
+--echo #
+CREATE TABLE t1
+(
+ a INT NOT NULL,
+ b CHAR(10) NOT NULL,
+ c VARCHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (1,'1','1');
+INSERT INTO t1 VALUES (2,'2','2');
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing long column name
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a012345678901234567890123456789 INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+
+--echo #
+--echo # Testing 2 columns with long names (12)
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a0123456789a INT NOT NULL,
+ b0123456789b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x11.dbf';
+
+--echo #
+--echo # Testing 2 columns with long names (11)
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a012345678a INT NOT NULL,
+ b012345678b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x12.dbf';
+
+--echo #
+--echo # Testing 2 columns name length 10 (maximum possible length)
+--echo #
+CREATE TABLE t1
+(
+ a01234567a INT NOT NULL,
+ b01234567b INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t02x13.dbf';
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (1,2);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t02x13.dbf
+
+
+--echo #
+--echo # Testing BIGINT
+--echo #
+CREATE TABLE t1
+(
+ a bigint NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (0x7FFFFFFFFFFFFFFF);
+INSERT INTO t1 VALUES (-0x8000000000000000);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing TINYINT
+--echo #
+CREATE TABLE t1
+(
+ a TINYINT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing SMALLINT
+--echo #
+CREATE TABLE t1
+(
+ a SMALLINT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (0x7FFF);
+INSERT INTO t1 VALUES (-0x8000);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing VARCHAR
+--echo #
+CREATE TABLE t1
+(
+ a VARCHAR(255) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (REPEAT('a',255));
+SELECT LENGTH(a) FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing too long CHAR
+--echo # All columns longer than 255 bytes should be rejected
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a CHAR(86) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+
+
+--echo #
+--echo # Testing too long VARCHAR
+--echo # All columns longer than 255 bytes should be rejected
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a VARCHAR(256) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a VARCHAR(86) CHARACTER SET utf8 NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ a VARCHAR(64000) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+
+
+--echo #
+--echo # Testing BLOB
+--echo #
+--error ER_TABLE_CANT_HANDLE_BLOB
+CREATE TABLE t1
+(
+ a BLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_TABLE_CANT_HANDLE_BLOB
+CREATE TABLE t1
+(
+ a TINYBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_TABLE_CANT_HANDLE_BLOB
+CREATE TABLE t1
+(
+ a MEDIUMBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+--error ER_TABLE_CANT_HANDLE_BLOB
+CREATE TABLE t1
+(
+ a LONGBLOB
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+
+
+# TODO: utf8 does not work
+#--echo #
+#--echo # Testing varchar with utf8
+#--echo #
+#SET NAMES utf8;
+#CREATE TABLE t1
+#(
+# a VARCHAR(10) CHARACTER SET utf8
+#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+#INSERT INTO t1 VALUES (REPEAT(_ucs2 0x00DF,10));
+#SELECT * FROM t1;
+#DROP TABLE IF EXISTS t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing DATE
+--echo #
+CREATE TABLE t1
+(
+ a DATE NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES ('2001-01-01');
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+
+--echo #
+--echo # Testing FLOAT
+--echo #
+CREATE TABLE t1
+(
+ a FLOAT(12,4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+#
+# TODO: this return error:
+# Got error 122 'Value 123.0000000000 too long for column a of length 12'
+# from CONNECT
+#
+#CREATE TABLE t1
+#(
+# a FLOAT NOT NULL
+#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+#--error ER_GET_ERRMSG - why this error?
+#INSERT INTO t1 VALUES (123);
+#SELECT * FROM t1;
+#DROP TABLE IF EXISTS t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+#
+# TODO: this creates a column of type 'D' (date), which is wrong
+#
+#--echo #
+#--echo # Testing DATETIME
+#--echo #
+#CREATE TABLE t1
+#(
+# a DATETIME NOT NULL
+#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+#INSERT INTO t1 VALUES ('2013-02-01');
+#SELECT * FROM t1;
+#DROP TABLE t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+#
+# TODO: this creates a column of type 'D' (date), which is wrong
+#
+#--echo #
+#--echo # Testing TIMESTAMP
+#--echo #
+#CREATE TABLE t1
+#(
+# a TIMESTAMP
+#) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+#INSERT INTO t1 VALUES ('2013-02-01');
+#SELECT * FROM t1;
+#DROP TABLE t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+--echo #
+--echo # Testing double
+--echo #
+CREATE TABLE t1
+(
+ a DOUBLE(20,5) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES (123);
+INSERT INTO t1 VALUES (123456789.12345);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE IF EXISTS t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+
+# TODO:
+# Testing with no FILE_NAME specified
+# Currently it returns:
+# ERROR 1296 (HY000): Got error 174 'Open(a+) error 21
+# on /opt/mariadb-5.5/data/: Is a directory' from CONNECT
+#CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=DBF;
+
+--echo #
+--echo # Testing ALTER
+--echo #
+# Temporarily change the file name because ALTER that are not executed not in place
+# delete the data file when it has the same path/name than the default file name.
+CREATE TABLE t1
+(
+ a VARCHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1c.dbf';
+INSERT INTO t1 VALUES ('10');
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1c.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1c.dbf');
+--horizontal_results
+ALTER TABLE t1 MODIFY a VARCHAR(10) NOT NULL;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1c.dbf');
+--horizontal_results
+ALTER TABLE t1 MODIFY a INT(10) NOT NULL;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1c.dbf');
+--horizontal_results
+
+# TODO: this does not work on Windows
+#ALTER TABLE t1 MODIFY a INT(8) NOT NULL;
+#SHOW CREATE TABLE t1;
+#--error ER_GET_ERRMSG
+#SELECT * FROM t1;
+#--vertical_results
+#--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+#eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+#--horizontal_results
+DROP TABLE IF EXISTS t1;
+--remove_file $MYSQLD_DATADIR/test/t1c.dbf
+
+
+--echo #
+--echo # Testing NULL
+--echo #
+# TODO: NULLs should probably change to DEFAULT and produce a warning
+CREATE TABLE t1
+(
+ c1 VARCHAR(10) NOT NULL,
+ c2 VARCHAR(10) NOT NULL DEFAULT 'def',
+ i1 INT NOT NULL,
+ i2 INT NOT NULL DEFAULT 123
+) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='t1.dbf';
+INSERT INTO t1 VALUES ('10','10',10,10);
+#INSERT INTO t1 VALUES (NULL,NULL,NULL,NULL);
+INSERT INTO t1(c1,i1) VALUES ('20',20);
+INSERT INTO t1 VALUES ('30',DEFAULT,30,DEFAULT);
+SELECT * FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.dbf
+--vertical_results
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+eval CALL dbf_header('$MYSQLD_DATADIR/test/t1.dbf');
+--horizontal_results
+DROP TABLE IF EXISTS t1;
+--remove_file $MYSQLD_DATADIR/test/t1.dbf
+
+DROP PROCEDURE test.dbf_field;
+DROP PROCEDURE test.dbf_header;
diff --git a/storage/connect/mysql-test/connect/t/dir.test b/storage/connect/mysql-test/connect/t/dir.test
new file mode 100644
index 00000000..684b5522
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/dir.test
@@ -0,0 +1,53 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+
+CREATE TABLE t1 (
+ path VARCHAR(256) NOT NULL flag=1,
+ fname VARCHAR(256) NOT NULL,
+ ftype CHAR(4) NOT NULL,
+ size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.txt'
+ OPTION_LIST='subdir=1';
+
+--replace_result $MYSQLD_DATADIR DATADIR/
+SELECT * FROM t1;
+
+--copy_file $MTR_SUITE_DIR/std_data/boys.txt $MYSQLD_DATADIR/test/boys.txt
+--copy_file $MTR_SUITE_DIR/std_data/boyswin.txt $MYSQLD_DATADIR/test/boyswin.txt
+
+--mkdir $MYSQLD_DATADIR/test/subdir/
+--copy_file $MYSQLD_DATADIR/test/boys.txt $MYSQLD_DATADIR/test/subdir/boys2.txt
+--replace_result $MYSQLD_DATADIR DATADIR/
+SELECT fname, ftype, size FROM t1 ORDER BY fname, ftype, size;
+ALTER TABLE t1 OPTION_LIST='subdir=0';
+SHOW CREATE TABLE t1;
+--replace_result $MYSQLD_DATADIR DATADIR/
+SELECT fname, ftype, size FROM t1 ORDER BY fname, ftype, size;
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+INSERT INTO t1 VALUES ('','','','');
+
+DROP TABLE t1;
+
+# TODO: automatically add columns
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.txt';
+
+
+#
+# TODO: this fails on Linux
+#
+#CREATE TABLE t1 t1 (
+# DRIVE CHAR(2),
+# PATH VARCHAR(256),
+# FNAME VARCHAR(256),
+# FTYPE CHAR(4),
+# SIZE DOUBLE(12,0) flag=5,
+# MODIFIED datetime
+#) engine=CONNECT table_type=DIR file_name='*.txt';
+#SELECT * FROM t1;
+#DROP TABLE t1;
+
+--remove_file $MYSQLD_DATADIR/test/subdir/boys2.txt
+--rmdir $MYSQLD_DATADIR/test/subdir/
+--remove_file $MYSQLD_DATADIR/test/boys.txt
+--remove_file $MYSQLD_DATADIR/test/boyswin.txt
diff --git a/storage/connect/mysql-test/connect/t/drop-open-error.opt b/storage/connect/mysql-test/connect/t/drop-open-error.opt
new file mode 100644
index 00000000..22520f0a
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/drop-open-error.opt
@@ -0,0 +1 @@
+--secure-file-priv=""
diff --git a/storage/connect/mysql-test/connect/t/drop-open-error.test b/storage/connect/mysql-test/connect/t/drop-open-error.test
new file mode 100644
index 00000000..0b73ac98
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/drop-open-error.test
@@ -0,0 +1,29 @@
+#
+# tests for the case when open_table_def() fails from inside
+# ha_connect::delete_or_rename_table()
+#
+#
+# MDEV-9949 Connect Engine: long SRCDEF leads to broken table
+#
+let $datadir=`select @@datadir`;
+
+create table t1 (c varchar(8));
+error ER_VALUE_TOO_LONG;
+# 34K SRCDEF line:
+create table tcon engine=connect table_type=mysql CONNECTION='mysql://root@localhost/test/t1' SRCDEF='select c from t1 where c in ("foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar", "foo", "bar", "qux", "foobar")';
+
+# copy the invalid frm (as created by the statement above before the MDEV-9949 fix)
+copy_file $MTR_SUITE_DIR/std_data/mdev9949.frm $datadir/test/mdev9949.frm;
+drop table mdev9949;
+drop table t1;
+
+#
+# MDEV-7935 CREATE TABLE ... AS SELECT ... can cause a Server crash (Assertion `0' in Protocol::end_statement)
+#
+select @@secure_file_priv 'must be NULL'; # otherwise foo/bar.txt won't be allowed
+create table t1 (a char(16)) engine=myisam;
+insert into t1 values('Hello World!');
+replace_regex @on .*/foo/@on foo/@;
+error ER_GET_ERRMSG;
+create table t2 engine=connect file_name='foo/bar.txt' as select * from t1;
+drop table t1;
diff --git a/storage/connect/mysql-test/connect/t/endian.test b/storage/connect/mysql-test/connect/t/endian.test
new file mode 100644
index 00000000..e5f4a24f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/endian.test
@@ -0,0 +1,88 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/Testbal.dat $MYSQLD_DATADIR/test/Testbal.dat
+
+SET time_zone='+00:00';
+
+--echo #
+--echo # Testing little endian table
+--echo #
+CREATE TABLE t1
+(
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL FIELD_FORMAT='L',
+ id CHAR(5) NOT NULL FIELD_FORMAT='L2',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='LF',
+ dept INT(4) NOT NULL FIELD_FORMAT='L2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat';
+SELECT * FROM t1;
+INSERT INTO t1 VALUES (5555,'RONALD','1980-02-26','3333',4444.44,555);
+SELECT * FROM t1;
+
+DROP TABLE t1;
+CREATE TABLE t1
+(
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL,
+ id CHAR(5) NOT NULL FIELD_FORMAT='S',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+ dept INT(4) NOT NULL FIELD_FORMAT='S'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.dat' OPTION_LIST='Endian=Little';
+SELECT * FROM t1;
+
+--echo #
+--echo # Testing big endian table
+--echo #
+CREATE TABLE t2 (
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL FIELD_FORMAT='B',
+ id CHAR(5) NOT NULL FIELD_FORMAT='BS',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
+ dept INT(4) NOT NULL FIELD_FORMAT='B2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
+INSERT INTO t2 SELECT * FROM t1;
+SELECT * FROM t2;
+
+DROP TABLE t2;
+CREATE TABLE t2 (
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL,
+ id CHAR(5) NOT NULL FIELD_FORMAT='S',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+ dept INT(4) NOT NULL FIELD_FORMAT='2'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
+SELECT * FROM t2;
+
+DROP TABLE t2;
+CREATE TABLE t2 (
+ fig CHAR(4) NOT NULL,
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL,
+ id SMALLINT(5) NOT NULL,
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='F',
+ dept SMALLINT(4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin' OPTION_LIST='Endian=Big';
+SELECT * FROM t2;
+
+DROP TABLE t2;
+CREATE TABLE t2 (
+ fig INT(4) NOT NULL FIELD_FORMAT='C',
+ name CHAR(10) NOT NULL,
+ birth DATE NOT NULL FIELD_FORMAT='B',
+ id CHAR(5) NOT NULL FIELD_FORMAT='BS',
+ salary DOUBLE(9,2) NOT NULL DEFAULT 0.00 FIELD_FORMAT='BF',
+ dept SMALLINT(4) NOT NULL FIELD_FORMAT='B'
+) ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=5 FILE_NAME='Testbal.bin';
+SELECT * FROM t2;
+
+DROP TABLE t1, t2;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/Testbal.dat
+--remove_file $MYSQLD_DATADIR/test/Testbal.bin
diff --git a/storage/connect/mysql-test/connect/t/fix.test b/storage/connect/mysql-test/connect/t/fix.test
new file mode 100644
index 00000000..f05abbb9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/fix.test
@@ -0,0 +1,108 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/dept.dat $MYSQLD_DATADIR/test/dept.dat
+--copy_file $MTR_SUITE_DIR/std_data/boys.txt $MYSQLD_DATADIR/test/boys.txt
+--copy_file $MTR_SUITE_DIR/std_data/boyswin.txt $MYSQLD_DATADIR/test/boyswin.txt
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL
+) Engine=CONNECT TABLE_TYPE=DOS FILE_NAME='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='t1.txt';
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (20);
+--error ER_GET_ERRMSG
+UPDATE t1 SET id=20 WHERE id=10;
+--error ER_GET_ERRMSG
+DELETE FROM t1 WHERE id=10;
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+ALTER TABLE t1 READONLY=0;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (20);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.txt
+
+
+--echo #
+--echo # Testing manual examples
+--echo #
+CREATE TABLE t1
+(
+ number CHAR(4) not null,
+ location CHAR(15) NOT NULL flag=5,
+ director CHAR(5) NOT NULL flag=20,
+ function CHAR(12) NOT NULL flag=26,
+ name CHAR(22) NOT NULL flag=38
+) ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='dept.dat';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ name char(12) not null,
+ city char(11) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' ENDING=1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ name char(12) not null,
+ city char(11) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' LRECL=47 ENDING=1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1
+(
+ name char(12) not null,
+ city char(11) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boyswin.txt' ENDING=2;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ name char(12) not null,
+ city char(11) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boyswin.txt' LRECL=47 ENDING=2;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/dept.dat
+--remove_file $MYSQLD_DATADIR/test/boys.txt
+--remove_file $MYSQLD_DATADIR/test/boyswin.txt
diff --git a/storage/connect/mysql-test/connect/t/fmt.test b/storage/connect/mysql-test/connect/t/fmt.test
new file mode 100644
index 00000000..2cea2dba
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/fmt.test
@@ -0,0 +1,85 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/funny.txt $MYSQLD_DATADIR/test/funny.txt
+--copy_file $MTR_SUITE_DIR/std_data/funny2.txt $MYSQLD_DATADIR/test/funny2.txt
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT NOT NULL field_format=' %n%d%n'
+) Engine=CONNECT table_type=FMT file_name='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing update on FMT tables
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL field_format=' %n%d%n'
+) ENGINE=CONNECT TABLE_TYPE=FMT FILE_NAME='t1.txt';
+--error ER_GET_ERRMSG
+INSERT INTO t1 VALUES (10),(20);
+# TODO:
+#--error ER_GET_ERRMSG
+#UPDATE t1 SET id=20;
+#TRUNCATE TABLE t1;
+#DELETE FROM t1 WHERE id=10;
+#SELECT * FROM t1;
+DROP TABLE t1;
+#--remove_file $MYSQLD_DATADIR/test/t1.txt
+
+
+--echo #
+--echo # Testing manual examples
+--echo #
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=" , '%n%[^']%n'",
+ DEPNO Integer(4) not null field_format=' , #%n%d%n',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny.txt';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# TODO: shoudn't a warning instead of error be returned on bad format?
+#
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=" , '%n%[^']%n'",
+ DEPNO Integer(4) not null field_format=' , #%n%d%n',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny2.txt';
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ ID Integer(5) not null field_format=' %n%d%n',
+ NAME Char(16) not null field_format=' , ''%n%[^'']%m',
+ DEPNO Integer(4) not null field_format=''' , #%n%d%m',
+ SALARY Double(12,2) not null field_format=' ; %n%f%n'
+) Engine=CONNECT table_type=FMT file_name='funny2.txt';
+SELECT * FROM t1;
+--error ER_GET_ERRMSG
+UPDATE t1 SET SALARY=1234;
+# TODO: this query crashes
+# UPDATE t1 SET SALARY=1234 WHERE ID=56;
+DELETE FROM t1 WHERE ID=56;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/funny.txt
+--remove_file $MYSQLD_DATADIR/test/funny2.txt
diff --git a/storage/connect/mysql-test/connect/t/general.test b/storage/connect/mysql-test/connect/t/general.test
new file mode 100644
index 00000000..34e5d4c7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/general.test
@@ -0,0 +1,16 @@
+--echo #
+--echo # Testing features not specific to any TABLE_TYPE
+--echo #
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=NON_EXISTING;
+#SHOW CREATE TABLE t1;
+#DROP TABLE t1;
+
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=FIX;
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+#--error ER_GET_ERRMSG
+--error ER_UNKNOWN_ERROR
+ALTER TABLE t1 TABLE_TYPE=NON_EXISTING;
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/grant.inc b/storage/connect/mysql-test/connect/t/grant.inc
new file mode 100644
index 00000000..ef6e0cec
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/grant.inc
@@ -0,0 +1,86 @@
+--echo #
+--echo # Beginning of grant.inc
+--echo #
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+--connect(user,localhost,user,,)
+--connection user
+SELECT user();
+--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT $TABLE_OPTIONS
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+UPDATE t1 SET a=20;
+SELECT * FROM t1;
+DELETE FROM t1;
+SELECT * FROM t1;
+INSERT INTO t1 VALUES(10);
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+# TODO: LOCK, UNLOCK, REFERENCES, INDEX
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+# Making sure DROP erased the data file
+--error 1
+--remove_file $MYSQLD_DATADIR/test/t1.$FILE_EXT
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT $TABLE_OPTIONS FILE_NAME='t1.EXT'
+--connection default
+SELECT user();
+--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT $TABLE_OPTIONS FILE_NAME='t1.EXT'
+INSERT INTO t1 VALUES (10);
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES (10);
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 SET a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+TRUNCATE TABLE t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 READONLY=1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 FILE_NAME='t2.EXT';
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DROP TABLE t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE VIEW v1 AS SELECT * FROM t1;
+--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
+--connection default
+SELECT user();
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM v1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1 VALUES (2);
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1 SET a=123;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM v1;
+--connection default
+SELECT user();
+DROP VIEW v1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.EXT
+--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT $TABLE_OPTIONS
+INSERT INTO t1 VALUES (10);
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 FILE_NAME='t1.EXT';
+--connection default
+DROP TABLE t1;
+--disconnect user
+DROP USER user@localhost;
+
+--echo #
+--echo # End of grant.inc
+--echo #
diff --git a/storage/connect/mysql-test/connect/t/grant.test b/storage/connect/mysql-test/connect/t/grant.test
new file mode 100644
index 00000000..afe55026
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/grant.test
@@ -0,0 +1,96 @@
+-- source include/not_embedded.inc
+set sql_mode="";
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # Testing FILE privilege
+--echo #
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+--connect(user,localhost,user,,)
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE TABLE t1 (
+ path VARCHAR(256) NOT NULL flag=1,
+ fname VARCHAR(256) NOT NULL,
+ ftype CHAR(4) NOT NULL,
+ size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.*';
+--connection default
+SELECT user();
+CREATE TABLE t1 (
+ path VARCHAR(256) NOT NULL flag=1,
+ fname VARCHAR(256) NOT NULL,
+ ftype CHAR(4) NOT NULL,
+ size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*.*';
+# "size>0" to skip directory names on Windows
+--replace_result $MYSQLD_DATADIR DATADIR/
+SELECT fname, ftype, size FROM t1 WHERE size>0 AND ftype!='.opt';
+
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES ();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM t1 WHERE path='xxx';
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 SET path='yyy' WHERE path='xxx';
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+TRUNCATE TABLE t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 READONLY=1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
+--connection default
+SELECT user();
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM v1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1 VALUES (1,1,1,1);
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1 SET path=123;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM v1;
+
+--disconnect user
+--connection default
+SELECT user();
+DROP VIEW v1;
+DROP TABLE t1;
+DROP USER user@localhost;
+--echo #
+--echo # Testing FILE privileges done
+--echo #
+
+
+let $TABLE_OPTIONS=TABLE_TYPE=BIN;
+let $FILE_EXT=BIN;
+--source grant.inc
+
+let $TABLE_OPTIONS=TABLE_TYPE=CSV;
+let $FILE_EXT=CSV;
+--source grant.inc
+
+let $TABLE_OPTIONS=TABLE_TYPE=DBF;
+let $FILE_EXT=DBF;
+--source grant.inc
+
+let $TABLE_OPTIONS=TABLE_TYPE=FIX;
+let $FILE_EXT=FIX;
+--source grant.inc
+
+let $TABLE_OPTIONS=TABLE_TYPE=VEC MAX_ROWS=100;
+let $FILE_EXT=VEC;
+--source grant.inc
+
+set sql_mode=default;
diff --git a/storage/connect/mysql-test/connect/t/grant2.test b/storage/connect/mysql-test/connect/t/grant2.test
new file mode 100644
index 00000000..351eb97f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/grant2.test
@@ -0,0 +1,869 @@
+-- source include/not_embedded.inc
+
+# Tests that involve SQL SECURITY DEFINER (e.g. in VIEWs)
+# TODO: add test with stored routines eventually.
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # MDEV-7574 Security definer views don't work with CONNECT ODBC tables
+--echo #
+
+CREATE USER user@localhost;
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+
+--echo # Testing SQLCOM_SELECT
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE DEFINER=user@localhost SQL SECURITY DEFINER VIEW v1_baddefiner AS SELECT * FROM t1;
+SELECT * FROM t1;
+SELECT * FROM v1_invoker;
+SELECT * FROM v1_definer;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM v1_baddefiner;
+
+--connect(user,localhost,user,,)
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM v1_invoker;
+SELECT * FROM v1_definer;
+--connection default
+DROP VIEW v1_invoker, v1_definer, v1_baddefiner;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_UPDATE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+UPDATE t1 SET a=11;
+UPDATE v1_invoker SET a=12;
+UPDATE v1_definer SET a=13;
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 SET a=21;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_invoker SET a=22;
+UPDATE v1_definer SET a=23;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_INSERT
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+INSERT INTO t1 VALUES (11);
+INSERT INTO v1_invoker VALUES (12);
+INSERT INTO v1_definer VALUES (13);
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES (21);
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1_invoker VALUES (22);
+INSERT INTO v1_definer VALUES (23);
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_REPLACE
+# REPLACE is not supported by ConnectSE, so we're testing the difference
+# between ER_SPECIFIC_ACCESS_DENIED_ERROR vs ER_NOT_ALLOWED_COMMAND
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO t1 VALUES (11);
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_invoker VALUES (12);
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer VALUES (13);
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+REPLACE INTO t1 VALUES (21);
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+REPLACE INTO v1_invoker VALUES (22);
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer VALUES (23);
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_DELETE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10),(11),(12),(13),(21),(22),(23);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DELETE FROM t1 WHERE a=11;
+DELETE FROM v1_invoker WHERE a=12;
+DELETE FROM v1_definer WHERE a=13;
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM t1 WHERE a=21;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM v1_invoker WHERE a=22;
+DELETE FROM v1_definer WHERE a=23;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_LOAD
+--connection default
+CREATE TABLE t1 (a VARCHAR(128)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer
+--connection user
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE t1
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_invoker
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval LOAD DATA LOCAL INFILE '$MTR_SUITE_DIR/std_data/boys.txt' INTO TABLE v1_definer
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_TRUNCATE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (11);
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+TRUNCATE TABLE t1;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+# TODO: Perhaps FILE_ACL is not needed for DROP TABLE. Discuss with Olivier.
+--echo # Testing SQLCOM_DROP_TABLE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DROP TABLE t1;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_DROP_VIEW
+--echo # DROP VIEW does not need FILE_ACL.
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10),(11),(12),(13),(21),(22),(23);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+DROP VIEW v1_invoker, v1_definer;
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+--connection user
+DROP VIEW v1_invoker;
+DROP VIEW v1_definer;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_CREATE_TABLE
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+--connection default
+
+--echo # Testing SQLCOM_LOCK_TABLES
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+LOCK TABLE t1 READ;
+UNLOCK TABLES;
+LOCK TABLE t1 WRITE;
+UNLOCK TABLES;
+LOCK TABLE v1_invoker READ;
+UNLOCK TABLES;
+LOCK TABLE v1_invoker WRITE;
+UNLOCK TABLES;
+LOCK TABLE v1_definer READ;
+UNLOCK TABLES;
+LOCK TABLE v1_definer WRITE;
+UNLOCK TABLES;
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+LOCK TABLE t1 READ;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+LOCK TABLE t1 WRITE;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+LOCK TABLE v1_invoker READ;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+LOCK TABLE v1_invoker WRITE;
+LOCK TABLE v1_definer READ;
+UNLOCK TABLES;
+LOCK TABLE v1_definer WRITE;
+UNLOCK TABLES;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_UPDATE_MULTI
+--connection default
+# t1 and t2 require FILE_ACL, t3 does not
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE TABLE t2 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t2.fix';
+CREATE TABLE t3 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES (20);
+INSERT INTO t3 VALUES (30);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v2_invoker AS SELECT * FROM t2;
+CREATE SQL SECURITY DEFINER VIEW v2_definer AS SELECT * FROM t2;
+UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+--connection user
+
+# All queries with t1 should fail
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# All queries with t2 should fail
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t2 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t2 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t2 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t2 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t2 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t2 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t2 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# t3 does not need FILE_ALC
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t3 a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t3 a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+# This is OK:
+UPDATE t3 a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t3 a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+# This is OK:
+UPDATE t3 a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t3 a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+# This is OK:
+UPDATE t3 a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# All queries with v1_invoker should fail
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# v1_definer does not need FILE_ACL from the invoker
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v1_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# All queries with v2_invoker should fail
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_invoker a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+# v2_definer does not need FILE_ACL from the invoker
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_definer a1,t1 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_definer a1,t2 a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,t3 a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_definer a1,v1_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v1_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v2_definer a1,v2_invoker a2 SET a1.a=50 WHERE a1.a=a2.a;
+UPDATE v2_definer a1,v2_definer a2 SET a1.a=50 WHERE a1.a=a2.a;
+
+--connection default
+DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer;
+DROP TABLE t1, t2, t3;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t2.fix
+
+--echo # Testing SQLCOM_DELETE_MULTI
+--connection default
+# t1 and t2 require FILE_ACL, t3 does not
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE TABLE t2 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t2.fix';
+CREATE TABLE t3 (a INT);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES (20);
+INSERT INTO t3 VALUES (30);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE SQL SECURITY INVOKER VIEW v2_invoker AS SELECT * FROM t2;
+CREATE SQL SECURITY DEFINER VIEW v2_definer AS SELECT * FROM t2;
+DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+
+--connection user
+
+# All queries with t1 should fail
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,t2 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,v1_invoker a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,v2_invoker a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t1 a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# All queries with t2 should fail
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,t2 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,v1_invoker a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,v2_invoker a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t2 a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# t3 does not need FILE_ALC
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t3 a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t3 a1,t2 a2 WHERE a1.a=a2.a;
+# This is OK:
+DELETE a1 FROM t3 a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t3 a1,v1_invoker a2 WHERE a1.a=a2.a;
+# This is OK:
+DELETE a1 FROM t3 a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM t3 a1,v2_invoker a2 WHERE a1.a=a2.a;
+# This is OK:
+DELETE a1 FROM t3 a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# All queries with v1_invoker should fail
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,t2 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# v1_definer does not need FILE_ACL from the invoker
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_definer a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v1_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v1_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# All queries with v2_invoker should fail
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,t2 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,v1_invoker a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,v2_invoker a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_invoker a1,v2_definer a2 WHERE a1.a=a2.a;
+
+# v2_definer does not need FILE_ACL from the invoker
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_definer a1,t1 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_definer a1,t2 a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,t3 a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_definer a1,v1_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v1_definer a2 WHERE a1.a=a2.a;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE a1 FROM v2_definer a1,v2_invoker a2 WHERE a1.a=a2.a;
+DELETE a1 FROM v2_definer a1,v2_definer a2 WHERE a1.a=a2.a;
+
+--connection default
+DROP VIEW v1_invoker, v1_definer, v2_invoker, v2_definer;
+DROP TABLE t1, t2, t3;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t2.fix
+
+--echo # Testing SQLCOM_CREATE_VIEW
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+CREATE VIEW v2 AS SELECT * FROM v1_invoker;
+DROP VIEW v2;
+CREATE VIEW v2 AS SELECT * FROM v1_definer;
+DROP VIEW v2;
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE VIEW v2 AS SELECT * FROM t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE VIEW v2 AS SELECT * FROM v1_invoker;
+CREATE VIEW v2 AS SELECT * FROM v1_definer;
+DROP VIEW v2;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_INSERT_SELECT
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1 WHERE a=20;
+INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 SELECT * FROM t1 WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 SELECT * FROM v1_definer WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1_definer SELECT * FROM t1 WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+# This is OK:
+INSERT INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_REPLACE_SELECT
+# REPLACE is not supported by CONNECT
+# so we're testing ER_NOT_ALLOWED_COMMAND vs ER_SPECIFIC_ACCESS_DENIED_ERROR here
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+CREATE SQL SECURITY INVOKER VIEW v1_invoker AS SELECT * FROM t1;
+CREATE SQL SECURITY DEFINER VIEW v1_definer AS SELECT * FROM t1;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO t1 SELECT * FROM t1 WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+REPLACE INTO t1 SELECT * FROM t1 WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+REPLACE INTO t1 SELECT * FROM v1_invoker WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+REPLACE INTO t1 SELECT * FROM v1_definer WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+REPLACE INTO v1_invoker SELECT * FROM t1 WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+REPLACE INTO v1_invoker SELECT * FROM v1_invoker WHERE a=20;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+REPLACE INTO v1_invoker SELECT * FROM v1_definer WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM t1 WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM v1_invoker WHERE a=20;
+--error ER_NOT_ALLOWED_COMMAND
+REPLACE INTO v1_definer SELECT * FROM v1_definer WHERE a=20;
+--connection default
+DROP VIEW v1_invoker, v1_definer;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_RENAME_TABLE
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+RENAME TABLE t1 TO t2;
+SHOW CREATE TABLE t2;
+RENAME TABLE t2 TO t1;
+--connection user
+# TODO: Perhaps FILE_ACL is needed for RENAME. Discuss with Oliver.
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+RENAME TABLE t1 TO t2;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (for ALTER..RENAME)
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 RENAME TO t2;
+SHOW CREATE TABLE t2;
+ALTER TABLE t2 RENAME TO t1;
+--connection user
+# TODO: Perhaps FILE_ACL is not needed for ALTER..RENAME. Discuss with Olivier.
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 RENAME TO t2;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (changing ENGINE to non-CONNECT)
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ENGINE=MyISAM;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 ENGINE=MyISAM;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (changing ENGINE to CONNECT)
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+# This should succeed, as 't1.fix' does not exists.
+ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+DROP TABLE t1;
+CREATE TABLE t1 (a INT) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (10);
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+--connection default
+DROP TABLE t1;
+
+--echo # Testing SQLCOM_OPTIMIZE
+--connection default
+CREATE TABLE t1 (a INT NOT NULL, KEY(a)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+OPTIMIZE TABLE t1;
+--connection user
+# This command succeeds, but reports "Access denied" in the "Msg_text" column.
+OPTIMIZE TABLE t1;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (adding columns)
+--connection default
+CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10);
+ALTER TABLE t1 ADD b INT;
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 ADD c INT;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (removing columns)
+--connection default
+CREATE TABLE t1 (a INT,b INT,c INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10,10);
+ALTER TABLE t1 DROP b;
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 DROP c;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+
+--echo # Testing SQLCOM_ALTER_TABLE (adding keys)
+--connection default
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+ALTER TABLE t1 ADD KEY(a);
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 ADD KEY(b);
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t1.fnx
+
+--echo # Testing SQLCOM_ALTER_TABLE (removing keys)
+--connection default
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL, KEY a(a), KEY b(b)) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+ALTER TABLE t1 DROP KEY a;
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 DROP KEY b;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t1.fnx
+
+--echo # Testing SQLCOM_CREATE_INDEX and SQLCOM_DROP_INDEX
+--connection default
+CREATE TABLE t1 (a INT NOT NULL,b INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+INSERT INTO t1 VALUES (10,10);
+CREATE INDEX a ON t1 (a);
+DROP INDEX a ON t1;
+CREATE INDEX a ON t1 (a);
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE INDEX b ON t1 (b);
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DROP INDEX a ON t1;
+--connection default
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.fix
+--remove_file $MYSQLD_DATADIR/test/t1.fnx
+
+--echo # Testing stored procedures
+CREATE PROCEDURE p_definer() SQL SECURITY DEFINER
+ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE PROCEDURE p_invoker() SQL SECURITY INVOKER
+ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+CREATE DEFINER=user@localhost PROCEDURE p_baddefiner() SQL SECURITY DEFINER
+ CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=fix FILE_NAME='t1.fix';
+
+CALL p_definer();
+DROP TABLE t1;
+CALL p_invoker();
+DROP TABLE t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CALL p_baddefiner();
+
+--connection user
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CALL p_invoker();
+CALL p_definer();
+
+--connection default
+DROP TABLE t1;
+DROP PROCEDURE p_definer;
+DROP PROCEDURE p_invoker;
+DROP PROCEDURE p_baddefiner;
+
+DROP USER user@localhost;
diff --git a/storage/connect/mysql-test/connect/t/grant3.test b/storage/connect/mysql-test/connect/t/grant3.test
new file mode 100644
index 00000000..9f05ca79
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/grant3.test
@@ -0,0 +1,11 @@
+#
+# MDEV-9610 Trigger on normal table can't insert into CONNECT engine table - Access Denied
+#
+create table tcon (i int) engine=Connect table_type=DOS file_name='tcon.dos';
+create table tin (i int);
+create trigger tr after insert on tin for each row insert into tcon values (new.i);
+insert into tin values (1);
+drop table tin,tcon;
+
+let datadir=`select @@datadir`;
+remove_file $datadir/test/tcon.dos;
diff --git a/storage/connect/mysql-test/connect/t/have_libxml2.inc b/storage/connect/mysql-test/connect/t/have_libxml2.inc
new file mode 100644
index 00000000..fc16265a
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/have_libxml2.inc
@@ -0,0 +1,17 @@
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1 (a VARCHAR(10))
+ENGINE=CONNECT TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2';
+if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+ AND ENGINE='CONNECT'
+ AND CREATE_OPTIONS LIKE '%`table_type`=XML%'
+ AND CREATE_OPTIONS LIKE '%xmlsup=libxml2%'`)
+{
+ DROP TABLE IF EXISTS t1;
+ Skip Need LIBXML2;
+}
+DROP TABLE t1;
+--enable_query_log
+
+
diff --git a/storage/connect/mysql-test/connect/t/have_odbc.inc b/storage/connect/mysql-test/connect/t/have_odbc.inc
new file mode 100644
index 00000000..437fad82
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/have_odbc.inc
@@ -0,0 +1,9 @@
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
+if ($mysql_errno)
+{
+ Skip No ODBC support;
+}
+DROP TABLE t1;
+--enable_query_log
diff --git a/storage/connect/mysql-test/connect/t/have_odbc_oracle.inc b/storage/connect/mysql-test/connect/t/have_odbc_oracle.inc
new file mode 100644
index 00000000..b89522ef
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/have_odbc_oracle.inc
@@ -0,0 +1,15 @@
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+if ($mysql_errno)
+{
+ Skip No ODBC support;
+}
+if (!`SELECT count(*) FROM t1 WHERE Name='ConnectEngineOracle'`)
+{
+ DROP TABLE t1;
+ Skip Need ODBC data source ConnectEngineOracle;
+}
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+--enable_query_log
diff --git a/storage/connect/mysql-test/connect/t/have_odbc_postgresql.inc b/storage/connect/mysql-test/connect/t/have_odbc_postgresql.inc
new file mode 100644
index 00000000..b4d2ec64
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/have_odbc_postgresql.inc
@@ -0,0 +1,15 @@
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+if ($mysql_errno)
+{
+ Skip No ODBC support;
+}
+if (!`SELECT count(*) FROM t1 WHERE Name='ConnectEnginePostgresql'`)
+{
+ DROP TABLE t1;
+ Skip Need ODBC data source ConnectEnginePostgresql;
+}
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+--enable_query_log
diff --git a/storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc b/storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc
new file mode 100644
index 00000000..9528e00f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/have_odbc_sqlite3.inc
@@ -0,0 +1,15 @@
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
+if ($mysql_errno)
+{
+ Skip No ODBC support;
+}
+if (!`SELECT count(*) FROM t1 WHERE Description='SQLite3 ODBC Driver'`)
+{
+ DROP TABLE t1;
+ Skip Need SQLite3 ODBC Driver;
+}
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+--enable_query_log
diff --git a/storage/connect/mysql-test/connect/t/have_zip.inc b/storage/connect/mysql-test/connect/t/have_zip.inc
new file mode 100644
index 00000000..d1283fc1
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/have_zip.inc
@@ -0,0 +1,19 @@
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1 (a CHAR(10)) ENGINE=CONNECT TABLE_TYPE=ZIP FILE_NAME='test.zip';
+if ($mysql_errno)
+{
+ Skip No ZIP support;
+}
+#if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+# WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+# AND ENGINE='CONNECT'
+# AND CREATE_OPTIONS LIKE '%`table_type`=ZIP%'
+# AND CREATE OPTIONS LIKE "%`file_name`='test.zip'%"`)
+#{
+# DROP TABLE IF EXISTS t1;
+# Skip Need ZIP support;
+#}
+DROP TABLE t1;
+--enable_query_log
+
diff --git a/storage/connect/mysql-test/connect/t/index.test b/storage/connect/mysql-test/connect/t/index.test
new file mode 100644
index 00000000..5e913582
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/index.test
@@ -0,0 +1,86 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/emp.txt $MYSQLD_DATADIR/test/emp.txt
+--copy_file $MTR_SUITE_DIR/std_data/sexe.csv $MYSQLD_DATADIR/test/sexe.csv
+--copy_file $MTR_SUITE_DIR/std_data/sitmat.csv $MYSQLD_DATADIR/test/sitmat.csv
+
+--echo #
+--echo # Testing indexing
+--echo #
+CREATE TABLE t1
+(
+ matricule INT(4) KEY NOT NULL field_format='Z',
+ nom VARCHAR(16) NOT NULL,
+ prenom VARCHAR(20) NOT NULL,
+ sexe SMALLINT(1) NOT NULL COMMENT 'sexe 1:M 2:F',
+ aanais INT(4) NOT NULL,
+ mmnais INT(2) NOT NULL,
+ ddentree DATE NOT NULL date_format='YYYYMM',
+ ddnom DATE NOT NULL date_format='YYYYMM',
+ brut INT(5) NOT NULL,
+ net DOUBLE(8,2) NOT NULL,
+ service INT(2) NOT NULL,
+ sitmat CHAR(1) NOT NULL,
+ formation CHAR(5) NOT NULL,
+ INDEX NP(nom,prenom)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='emp.txt' ENDING=2;
+SELECT * FROM t1 LIMIT 10;
+SELECT SUM(brut) from t1;
+
+--echo #
+--echo # Testing file mapping
+--echo #
+ALTER TABLE t1 MAPPED=yes;
+SELECT * FROM t1 LIMIT 10;
+SELECT SUM(brut) FROM t1;
+
+--echo #
+--echo # Test the indexes (made when creating the table)
+--echo #
+SELECT * FROM t1 WHERE matricule = '0091';
+SELECT * FROM t1 WHERE nom = 'FOCH';
+SELECT * FROM t1 WHERE nom = 'FOCH' and prenom = 'DENIS';
+
+--echo #
+--echo # Testing UPDATE
+--echo #
+UPDATE t1 SET aanais = aanais + 16;
+UPDATE t1 SET ddentree = adddate(ddentree, interval 16 year);
+UPDATE t1 SET ddnom = adddate(ddnom, interval 16 year);
+SELECT * FROM t1 WHERE nom = 'FOCH';
+
+--echo #
+--echo # Testing JOIN
+--echo #
+create table t2
+(
+ sexe INT(1) KEY,
+ genre CHAR(8) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='sexe.csv' SEP_CHAR=';' ENDING=2;
+SELECT * FROM t2;
+SELECT nom, prenom, genre FROM t1 NATURAL JOIN t2 LIMIT 10;
+
+--echo #
+--echo # Another table
+--echo #
+CREATE TABLE t3 (
+ sitmat CHAR(1) KEY,
+ situation CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='sitmat.csv' SEP_CHAR=';' ENDING=2;
+SELECT * FROM t3;
+SELECT nom, prenom, genre, situation FROM t1 NATURAL JOIN t2 NATURAL JOIN t3 WHERE nom = 'FOCH';
+
+--echo #
+--echo # Testing DELETE
+--echo #
+DELETE FROM t1;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/emp.txt
+--remove_file $MYSQLD_DATADIR/test/sexe.csv
+--remove_file $MYSQLD_DATADIR/test/sitmat.csv
diff --git a/storage/connect/mysql-test/connect/t/infoschema-9739.test b/storage/connect/mysql-test/connect/t/infoschema-9739.test
new file mode 100644
index 00000000..16f837ca
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/infoschema-9739.test
@@ -0,0 +1,9 @@
+#
+# MDEV-9739 Assertion `m_status == DA_ERROR || m_status == DA_OK' failed in Diagnostics_area::message() ; connect.xml* tests fail in buildbot
+#
+
+--source windows.inc
+
+create table t1 (i int) engine=Connect table_type=XML option_list='xmlsup=domdoc';
+select * from information_schema.tables where table_schema='test' and create_options like '%table_type=XML%';
+drop table t1;
diff --git a/storage/connect/mysql-test/connect/t/infoschema2-9739.test b/storage/connect/mysql-test/connect/t/infoschema2-9739.test
new file mode 100644
index 00000000..76681bc9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/infoschema2-9739.test
@@ -0,0 +1,9 @@
+#
+# MDEV-9739 Assertion `m_status == DA_ERROR || m_status == DA_OK' failed in Diagnostics_area::message() ; connect.xml* tests fail in buildbot
+#
+
+--source have_libxml2.inc
+
+create table t1 (i int) engine=Connect table_type=XML option_list='xmlsup=libxml2';
+select * from information_schema.tables where table_schema='test' and create_options like '%table_type=XML%';
+drop table t1;
diff --git a/storage/connect/mysql-test/connect/t/ini.test b/storage/connect/mysql-test/connect/t/ini.test
new file mode 100644
index 00000000..449b9720
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/ini.test
@@ -0,0 +1,156 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/contact.ini $MYSQLD_DATADIR/test/contact.ini
+
+--echo #
+--echo # Testing errors
+--echo #
+CREATE TABLE t1
+(
+ ID INT
+) Engine=CONNECT TABLE_TYPE=INI FILE_NAME='nonexistent.txt';
+--replace_regex /on .*test.nonexistent.txt/on DATADIR\/test\/nonexistent.txt/
+# TODO: check why this is needed for Windows
+--replace_result Open(rt) Open(rb)
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing examples from the manual
+--echo #
+
+CREATE TABLE t1
+(
+ contact CHAR(16) flag=1,
+ name CHAR(20),
+ forename CHAR(32),
+ hired date date_format='DD/MM/YYYY',
+ address CHAR(64),
+ city CHAR(20),
+ zipcode CHAR(8),
+ tel CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='contact.ini';
+SELECT contact, name, hired, city, tel FROM t1;
+
+UPDATE t1 SET forename= 'Harry' where contact='UK1';
+SELECT * FROM t1 WHERE contact='UK1';
+INSERT INTO t1 (contact,forename) VALUES ('UK1','Harrison');
+SELECT * FROM t1 WHERE contact='UK1';
+INSERT INTO t1 (contact,forename) VALUES ('UK2','John');
+SELECT * FROM t1 WHERE contact='UK2';
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/contact.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n');
+
+CREATE TABLE t1
+(
+ section CHAR(16) flag=1,
+ keyname CHAR(16) flag=2,
+ value CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='contact.ini'
+ OPTION_LIST='Layout=Row';
+UPDATE t1 SET value='Paul' WHERE section='UK2' AND keyname='forename';
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/contact.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/contact.ini'),'\r\n','\n'),'\n\n','\n');
+
+
+--echo #
+--echo # Testing that the underlying file is created
+--echo #
+CREATE TABLE t1
+(
+ contact CHAR(12) NOT NULL flag=1,
+ c2 CHAR(12) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='tmp.ini';
+INSERT INTO t1 VALUES (10,10),(20,20),(300,300),(4000,4000), ('a b','c d');
+SELECT * FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/tmp.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/tmp.ini'),'\r\n','\n'),'\n\n','\n');
+
+
+--echo #
+--echo # Testing bad table
+--echo #
+CREATE TABLE t1
+(
+ id INT
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.ini';
+--error ER_GET_ERRMSG
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing READONLY tables
+--echo #
+CREATE TABLE t1
+(
+ contact CHAR(10) flag=1,
+ c2 CHAR(60)
+) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.ini';
+INSERT INTO t1 VALUES ('UK',10),('FR',20),('RU',30);
+SELECT * FROM t1;
+ALTER TABLE t1 READONLY=1;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES ('US',40);
+--error ER_GET_ERRMSG
+UPDATE t1 SET c2=20 WHERE c2=10;
+--error ER_GET_ERRMSG
+DELETE FROM t1 WHERE c2=10;
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+ALTER TABLE t1 READONLY=0;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES ('US',40);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.ini
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/contact.ini
+--remove_file $MYSQLD_DATADIR/test/tmp.ini
+
+
+--echo #
+--echo # Bug: TABLE_TYPE=ini does not clear memory between CREATE TABLEs
+--echo #
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+INSERT INTO t1 VALUES ('sec1','val1'),('sec2','val2');
+SELECT sec AS s, val AS v FROM t1;
+DROP TABLE t1;
+CREATE TABLE t1 (sec2 CHAR(10) NOT NULL FLAG=1, val2 CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+INSERT INTO t1 VALUES ('sec1','val11'),('sec2','val22');
+SELECT sec2 AS s, val2 AS v FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n');
+DROP TABLE t1;
+
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+CREATE TABLE t2 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=INI;
+INSERT INTO t1 VALUES('1sec1','1val1'),('1sec2','1val2');
+INSERT INTO t2 VALUES('2sec1','2val1'),('2sec2','2val2');
+SELECT sec AS s, val AS v FROM t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t1.ini'),'\r\n','\n'),'\n\n','\n');
+SELECT sec AS s, val AS v FROM t2;
+--chmod 0777 $MYSQLD_DATADIR/test/t2.ini
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval SELECT REPLACE(REPLACE(LOAD_FILE('$MYSQLD_DATADIR/test/t2.ini'),'\r\n','\n'),'\n\n','\n');
+DROP TABLE t1, t2;
diff --git a/storage/connect/mysql-test/connect/t/ini_grant.test b/storage/connect/mysql-test/connect/t/ini_grant.test
new file mode 100644
index 00000000..bbf85e5f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/ini_grant.test
@@ -0,0 +1,81 @@
+-- source include/not_embedded.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # Checking FILE privileges
+--echo #
+set sql_mode="";
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+set sql_mode=default;
+--connect(user,localhost,user,,)
+--connection user
+SELECT user();
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI;
+INSERT INTO t1 VALUES ('sec1','val1');
+SELECT * FROM t1;
+UPDATE t1 SET val='val11';
+SELECT * FROM t1;
+DELETE FROM t1;
+SELECT * FROM t1;
+INSERT INTO t1 VALUES('sec2','val2');
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+# Making sure DROP erased the data file
+--error 1
+--remove_file $MYSQLD_DATADIR/test/t1.ini
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT';
+--connection default
+SELECT user();
+CREATE TABLE t1 (sec CHAR(10) NOT NULL FLAG=1, val CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=INI FILE_NAME='t1.EXT';
+INSERT INTO t1 VALUES ('sec1','val1');
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES ('sec2','val2');
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 SET val='val11';
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+TRUNCATE TABLE t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 READONLY=1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DROP TABLE t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE VIEW v1 AS SELECT * FROM t1;
+--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
+--connection default
+SELECT user();
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM v1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1 VALUES ('sec3','val3');
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1 SET val='val11';
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM v1;
+--disconnect user
+--connection default
+DROP VIEW v1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1.EXT
+DROP USER user@localhost;
+
+--echo #
+--echo # Checking FILE privileges: done
+--echo #
+
+
diff --git a/storage/connect/mysql-test/connect/t/jdbc.test b/storage/connect/mysql-test/connect/t/jdbc.test
new file mode 100644
index 00000000..79809f4e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/jdbc.test
@@ -0,0 +1,150 @@
+-- source windows.inc
+-- source jdbconn.inc
+SET GLOBAL time_zone='+0:00';
+SET time_zone='+0:00';
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/girls.txt $MYSQLD_DATADIR/test/girls.txt
+
+let $PORT= `select @@port`;
+
+#
+# This test is run against a local MariaDB server
+#
+CREATE DATABASE connect;
+USE connect;
+CREATE TABLE t2 (
+ id bigint not null,
+ msg varchar(500),
+ tm time,
+ dt date,
+ dtm datetime,
+ ts timestamp);
+INSERT INTO t2 VALUES(455000000000, 'A very big number', '18:10:25', '2016-03-16', '1999-12-11 23:01:52', '2015-07-24 09:32:45');
+SELECT * FROM t2;
+
+--echo #
+--echo # Testing JDBC connection to MySQL driver
+--echo #
+USE test;
+--replace_result $PORT PORT
+--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME=t2 CONNECTION='jdbc:mysql://localhost:$PORT/connect?user=root&useSSL=false'
+SELECT * FROM t1;
+INSERT INTO t1 VALUES(786325481247, 'Hello!', '19:45:03', '1933-08-10', '1985-11-12 09:02:44', '2014-06-17 10:32:01');
+SELECT * FROM t1;
+DELETE FROM t1 WHERE msg = 'Hello!';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing JDBC view
+--echo #
+--replace_result $PORT PORT
+--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC SRCDEF='select id, msg, tm, dt from t2' CONNECTION='jdbc:mysql://localhost:$PORT/connect?user=root&useSSL=false'
+SELECT * FROM t1;
+SELECT msg, dt FROM t1;
+DROP TABLE t1, connect.t2;
+
+--echo #
+--echo # Testing JDBC write operations
+--echo #
+USE connect;
+--copy_file $MTR_SUITE_DIR/std_data/boys.txt $MYSQLD_DATADIR/connect/boys.txt
+CREATE TABLE boys (
+ name CHAR(12) NOT NULL,
+ city CHAR(11),
+ birth DATE DATE_FORMAT='DD/MM/YYYY',
+ hired DATE DATE_FORMAT='DD/MM/YYYY' flag=36)
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='boys.txt' ENDING=1;
+SELECT * FROM boys;
+
+USE test;
+CREATE TABLE t3 (
+ name CHAR(12) NOT NULL,
+ city CHAR(12),
+ birth DATE,
+ hired DATE);
+INSERT INTO t3 VALUES('Donald','Atlanta','1999-04-01','2016-03-31'),('Mick','New York','1980-01-20','2002-09-11');
+SELECT * FROM t3;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME=boys CONNECTION='jdbc:mysql://localhost:$PORT/connect?user=root&useSSL=false' OPTION_LIST='scrollable=1'
+SELECT * FROM t1;
+UPDATE t1 SET city = 'Phoenix' WHERE name = 'Henry';
+INSERT INTO t1 SELECT * FROM t3;
+INSERT INTO t1 VALUES('Tom','Seatle','2002-03-15',NULL);
+SELECT * FROM t1;
+DROP TABLE t3;
+
+--echo #
+--echo # Testing JDBC join operations
+--echo #
+CREATE TABLE t3 (
+ name CHAR(9) NOT NULL,
+ city CHAR(12) NOT NULL,
+ age INT(2))
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='girls.txt' ENDING=1;
+SELECT g.name, b.name, g.city FROM t3 g STRAIGHT_JOIN connect.boys b where g.city = b.city;
+SELECT g.name, b.name, g.city FROM t3 g STRAIGHT_JOIN t1 b where g.city = b.city;
+DROP TABLE t1, t3, connect.boys;
+
+--echo #
+--echo # Testing MariaDB JDBC driver
+--echo #
+USE connect;
+--copy_file $MTR_SUITE_DIR/std_data/employee.dat $MYSQLD_DATADIR/connect/employee.dat
+CREATE TABLE emp (
+ serialno CHAR(5) NOT NULL,
+ name VARCHAR(12) NOT NULL FLAG=6,
+ sex TINYINT(1) NOT NULL,
+ title VARCHAR(15) NOT NULL FLAG=20,
+ manager CHAR(5) NOT NULL,
+ department CHAR(4) NOT NULL FLAG=41,
+ secretary CHAR(5) NOT NULL FLAG=46,
+ salary DOUBLE(8,2) NOT NULL FLAG=52)
+ENGINE=connect TABLE_TYPE=fix FILE_NAME='employee.dat' ENDING=1;
+SELECT * FROM emp;
+
+--echo #
+--echo # Option Driver is required to find the Driver class inside the executable jar file
+--echo #
+USE test;
+--replace_result $PORT PORT
+--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME=emp CONNECTION='jdbc:mariadb://localhost:$PORT/connect?user=root' OPTION_LIST='Driver=org.mariadb.jdbc.Driver'
+--replace_result $PORT PORT
+--eval SHOW CREATE TABLE t1
+SELECT * FROM t1;
+SELECT name, title, salary FROM t1 WHERE sex = 1;
+
+DROP TABLE t1, connect.emp;
+
+#
+# Testing remote command execution (Driver option is no more necessary)
+#
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 (command varchar(128) not null,number int(5) not null flag=1,message varchar(255) flag=2) ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:mariadb://localhost:$PORT/connect' OPTION_LIST='User=root,Execsrc=1'
+SELECT * FROM t2 WHERE command='drop table tx1';
+SELECT * FROM t2 WHERE command = 'create table tx1 (a int not null, b char(32), c double(8,2))';
+SELECT * FROM t2 WHERE command in ('insert into tx1 values(1,''The number one'',456.12)',"insert into tx1(a,b) values(2,'The number two'),(3,'The number three')");
+SELECT * FROM t2 WHERE command='update tx1 set c = 3.1416 where a = 2';
+SELECT * FROM t2 WHERE command='select * from tx1';
+SELECT * FROM t2 WHERE command='delete from tx1 where a = 2';
+SELECT * FROM connect.tx1;
+DROP TABLE t2;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=tables CONNECTION='jdbc:mariadb://localhost:$PORT/connect' option_list='User=root,Maxres=50'
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP TABLE connect.tx1;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/connect/boys.txt
+--remove_file $MYSQLD_DATADIR/connect/employee.dat
+DROP DATABASE connect;
+--remove_file $MYSQLD_DATADIR/test/girls.txt
+SET GLOBAL time_zone=SYSTEM;
+SET time_zone=SYSTEM;
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/jdbc_new.test b/storage/connect/mysql-test/connect/t/jdbc_new.test
new file mode 100644
index 00000000..1eaafdfb
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/jdbc_new.test
@@ -0,0 +1,187 @@
+#
+# This test is run against a remote MySQL server
+#
+connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
+connection master;
+
+-- source windows.inc
+-- source jdbconn.inc
+
+connection slave;
+SET GLOBAL time_zone='+0:00';
+SET time_zone='+0:00';
+
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+
+--echo #
+--echo # Testing errors
+--echo #
+connection master;
+SET GLOBAL time_zone='+0:00';
+SET time_zone='+0:00';
+
+# Bad user name
+# Suppress "mysql_real_connect failed:" (printed in _DEBUG build)
+--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=unknown&useSSL=false';
+
+# Bad database name
+--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/unknown?user=root&useSSL=false';
+
+# Bad table name
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME='unknown'
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t1;
+
+# Bad column name
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# The remote table disappeared
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+
+connection slave;
+ALTER TABLE t1 RENAME t1backup;
+
+connection master;
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+
+connection slave;
+ALTER TABLE t1backup RENAME t1;
+
+connection master;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing SELECT, etc.
+--echo #
+
+# Automatic table structure
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME='t1'
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure: remote NULL, local NOT NULL
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure with wrong column types
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing numeric data types
+--echo #
+
+# TODO: mediumint is converted to int, float is converted to double, decimal is converted to double
+CREATE TABLE t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float, g double, h decimal(20,5));
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265);
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing character data types
+--echo #
+
+CREATE TABLE t1 (a char(12), b varchar(12));
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES('Welcome','Hello, World');
+SELECT * FROM t1;
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing temporal data types
+--echo #
+
+CREATE TABLE t1 (a date, b datetime, c time, d timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, e year);
+SHOW CREATE TABLE t1;
+INSERT IGNORE INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23');
+SELECT * FROM t1;
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+ CONNECTION='jdbc:mysql://127.0.0.1:$SLAVE_MYPORT/test?user=root&useSSL=false';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+SET GLOBAL time_zone=SYSTEM;
+SET time_zone=SYSTEM;
+
+connection master;
+SET GLOBAL time_zone=SYSTEM;
+SET time_zone=SYSTEM;
+-- source jdbconn_cleanup.inc
+
diff --git a/storage/connect/mysql-test/connect/t/jdbc_oracle.test b/storage/connect/mysql-test/connect/t/jdbc_oracle.test
new file mode 100644
index 00000000..0a475102
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/jdbc_oracle.test
@@ -0,0 +1,56 @@
+-- source jdbconn.inc
+
+#
+# This test is run against Oracle driver
+#
+CREATE TABLE t2 (
+ command varchar(128) not null,
+ number int(5) not null flag=1,
+ message varchar(255) flag=2)
+ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='jdbc:oracle:thin:@localhost:1521:xe'
+OPTION_LIST='User=system,Password=Biscote01,Execsrc=1';
+SELECT * FROM t2 WHERE command = 'drop table employee';
+SELECT * FROM t2 WHERE command = 'create table employee (id int not null, name varchar(32), title char(16), salary number(8,2))';
+SELECT * FROM t2 WHERE command = "insert into employee values(4567,'Johnson', 'Engineer', 12560.50)";
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=tables
+CONNECTION='jdbc:oracle:thin:@localhost:1521:xe'
+OPTION_LIST='User=system,Password=Biscote01';
+SELECT * FROM t1 WHERE table_name='employee';
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC TABNAME='EMPLOYEE' CATFUNC=columns
+CONNECTION='jdbc:oracle:thin:@localhost:1521:xe'
+OPTION_LIST='User=system,Password=Biscote01';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Test connecting via a Federated server
+#
+CREATE SERVER 'oracle' FOREIGN DATA WRAPPER 'oracle.jdbc.driver.OracleDriver' OPTIONS (
+HOST 'jdbc:oracle:thin:@localhost:1521:xe',
+DATABASE 'SYSTEM',
+USER 'system',
+PASSWORD 'Biscote01',
+PORT 0,
+SOCKET '',
+OWNER 'SYSTEM');
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CONNECTION='oracle' tabname='EMPLOYEE';
+SELECT * FROM t1;
+INSERT INTO t1 VALUES(6214, 'Clinton', 'Retired', NULL);
+UPDATE t1 set name='Trump' WHERE id = 4567;
+SELECT * FROM t1;
+DELETE FROM t1 WHERE id = 6214;
+SELECT * FROM t1;
+DROP TABLE t1;
+SELECT * FROM t2 WHERE command = 'drop table employee';
+DROP TABLE t2;
+DROP SERVER 'oracle';
+
+#
+# Clean up
+#
+
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/jdbc_postgresql.test b/storage/connect/mysql-test/connect/t/jdbc_postgresql.test
new file mode 100644
index 00000000..8036f710
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/jdbc_postgresql.test
@@ -0,0 +1,64 @@
+-- source jdbconn.inc
+
+#
+# This test is run against Postgresql driver
+#
+eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/JavaWrappers.jar;C:/Jconnectors/postgresql-42.2.1.jar';
+CREATE TABLE t2 (
+ command varchar(128) not null,
+ number int(5) not null flag=1,
+ message varchar(255) flag=2)
+ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono'
+OPTION_LIST='Execsrc=1';
+#CONNECTION='jdbc:postgresql://localhost/mtr'
+#OPTION_LIST='User=mtr,Password=mtr,Schema=public,Execsrc=1';
+SELECT * FROM t2 WHERE command='drop table employee';
+SELECT * FROM t2 WHERE command = 'create table employee (id int not null, name varchar(32), title char(16), salary decimal(8,2))';
+SELECT * FROM t2 WHERE command = "insert into employee values(4567,'Johnson', 'Engineer', 12560.50)";
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=tables
+CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono'
+OPTION_LIST='Tabtype=TABLE,Maxres=10';
+#CONNECTION='jdbc:postgresql://localhost/mtr'
+#OPTION_LIST='User=mtr,Password=mtr,Schema=public,Tabtype=TABLE,Maxres=10';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC tabname=employee CATFUNC=columns
+CONNECTION='jdbc:postgresql://localhost/test?user=postgres&password=tinono';
+#CONNECTION='jdbc:postgresql://localhost/mtr' tabname=employee;
+#OPTION_LIST='User=mtr,Password=mtr,Maxres=10';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Test connecting via a Federated server
+#
+CREATE SERVER 'postgresql' FOREIGN DATA WRAPPER 'postgresql' OPTIONS (
+HOST 'localhost',
+DATABASE 'test',
+USER 'postgres',
+PASSWORD 'tinono',
+PORT 0,
+SOCKET '',
+OWNER 'root');
+#DATABASE 'mtr',
+#USER 'mtr',
+#PASSWORD 'mtr',
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC
+CONNECTION='postgresql/public.employee';
+SELECT * FROM t1;
+INSERT INTO t1 VALUES(3126,'Smith', 'Clerk', 5230.00);
+UPDATE t1 SET salary = salary + 100.00;
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP SERVER 'postgresql';
+SELECT * FROM t2 WHERE command='drop table employee';
+DROP TABLE t2;
+
+#
+# Clean up
+#
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/jdbconn.inc b/storage/connect/mysql-test/connect/t/jdbconn.inc
new file mode 100644
index 00000000..81ec80c1
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/jdbconn.inc
@@ -0,0 +1,33 @@
+--source include/not_embedded.inc
+
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=JDBC CATFUNC=drivers;
+if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+ AND ENGINE='CONNECT'
+ AND (CREATE_OPTIONS LIKE "%`table_type`='JDBC'%" OR CREATE_OPTIONS LIKE '%`table_type`=JDBC%')`)
+{
+ Skip Need Java support;
+}
+DROP TABLE t1;
+
+# You cand edit this file to reflect what is the required files location on your machine.
+# This is the path to the JVM library (dll or so)
+# If not set CONNECT will try to use the JAVA_HOME environment variable
+# and if not found try to find it in the registers (Windows only)
+#SET GLOBAL connect_jvm_path='C:\\Program Files\\Java\\jdk1.8.0_77\\jre\\bin\\client';
+
+# The complete class path send when creating the Java Virtual Machine is, in that order:
+# 1 - The current directory.
+# 2 - The paths of the connect_class_path global variable.
+# 3 - The paths of the CLASSPATH environment variable.
+# In this test we use an executable jar file that contains all the eisting wrappers.
+#eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/JdbcMariaDB.jar';
+eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/JavaWrappers.jar';
+
+# Paths to the JDK classes and to the JDBC drivers should be defined in the CLASSPATH environment variable
+#CREATE FUNCTION envar RETURNS STRING SONAME 'ha_connect.dll';
+#SELECT envar('CLASSPATH');
+
+--enable_query_log
diff --git a/storage/connect/mysql-test/connect/t/jdbconn_cleanup.inc b/storage/connect/mysql-test/connect/t/jdbconn_cleanup.inc
new file mode 100644
index 00000000..d70e594d
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/jdbconn_cleanup.inc
@@ -0,0 +1,8 @@
+--disable_query_log
+--disable_warnings
+#DROP FUNCTION envar;
+SET GLOBAL connect_jvm_path=NULL;
+SET GLOBAL connect_class_path=NULL;
+SET GLOBAL time_zone = SYSTEM;
+--enable_warnings
+--enable_query_log
diff --git a/storage/connect/mysql-test/connect/t/json.test b/storage/connect/mysql-test/connect/t/json.test
new file mode 100644
index 00000000..8b42ef9c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/json.test
@@ -0,0 +1,294 @@
+--source include/not_embedded.inc
+--source include/have_partition.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/biblio.json $MYSQLD_DATADIR/test/biblio.json
+--copy_file $MTR_SUITE_DIR/std_data/bib0.json $MYSQLD_DATADIR/test/bib0.json
+--copy_file $MTR_SUITE_DIR/std_data/expense.json $MYSQLD_DATADIR/test/expense.json
+--copy_file $MTR_SUITE_DIR/std_data/mulexp3.json $MYSQLD_DATADIR/test/mulexp3.json
+--copy_file $MTR_SUITE_DIR/std_data/mulexp4.json $MYSQLD_DATADIR/test/mulexp4.json
+--copy_file $MTR_SUITE_DIR/std_data/mulexp5.json $MYSQLD_DATADIR/test/mulexp5.json
+
+--echo #
+--echo # Testing doc samples
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15),
+ LANG CHAR(2),
+ SUBJECT CHAR(32),
+ AUTHOR CHAR(64),
+ TITLE CHAR(32),
+ TRANSLATION CHAR(32),
+ TRANSLATOR CHAR(80),
+ PUBLISHER CHAR(32),
+ DATEPUB int(4)
+) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing Jpath. Get the number of authors
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15),
+ Language CHAR(2) JPATH='$.LANG',
+ Subject CHAR(32) JPATH='$.SUBJECT',
+ Authors INT(2) JPATH='$.AUTHOR[#]',
+ Title CHAR(32) JPATH='$.TITLE',
+ Translation CHAR(32) JPATH='$.TRANSLATION',
+ Translator CHAR(80) JPATH='$.TRANSLATOR',
+ Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+ Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+ Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Concatenates the authors
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15),
+ Language CHAR(2) JPATH='$.LANG',
+ Subject CHAR(32) JPATH='$.SUBJECT',
+ AuthorFN CHAR(128) JPATH='$.AUTHOR[" and "].FIRSTNAME',
+ AuthorLN CHAR(128) JPATH='$.AUTHOR[" and "].LASTNAME',
+ Title CHAR(32) JPATH='$.TITLE',
+ Translation CHAR(32) JPATH='$.TRANSLATION',
+ Translator CHAR(80) JPATH='$.TRANSLATOR',
+ Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+ Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+ Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing expanding authors
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15),
+ Language CHAR(2) JPATH='$.LANG',
+ Subject CHAR(32) JPATH='$.SUBJECT',
+ AuthorFN CHAR(128) JPATH='$.AUTHOR[*].FIRSTNAME',
+ AuthorLN CHAR(128) JPATH='$.AUTHOR[*].LASTNAME',
+ Title CHAR(32) JPATH='$.TITLE',
+ Translation CHAR(32) JPATH='$.TRANSLATION',
+ Translator CHAR(80) JPATH='$.TRANSLATOR',
+ Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+ Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+ Year int(4) JPATH='$.DATEPUB'
+)
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+SELECT * FROM t1;
+UPDATE t1 SET AuthorFN = 'Philippe' WHERE AuthorLN = 'Knab';
+SELECT * FROM t1 WHERE ISBN = '9782212090819';
+
+--echo #
+--echo # To add an author a new table must be created
+--echo #
+CREATE TABLE t2 (
+FIRSTNAME CHAR(32),
+LASTNAME CHAR(32))
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json' OPTION_LIST='Object=$[1].AUTHOR';
+SELECT * FROM t2;
+INSERT INTO t2 VALUES('Charles','Dickens');
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP TABLE t2;
+
+--echo #
+--echo # Check the biblio file has the good format
+--echo #
+CREATE TABLE t1
+(
+ line char(255)
+)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='biblio.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing a pretty=0 file
+--echo #
+CREATE TABLE t1
+(
+ ISBN CHAR(15) NOT NULL,
+ Language CHAR(2) JPATH='$.LANG',
+ Subject CHAR(32) JPATH='$.SUBJECT',
+ AuthorFN CHAR(128) JPATH='$.AUTHOR[*].FIRSTNAME',
+ AuthorLN CHAR(128) JPATH='$.AUTHOR[*].LASTNAME',
+ Title CHAR(32) JPATH='$.TITLE',
+ Translation CHAR(32) JPATH='$.TRANSLATED.PREFIX',
+ TranslatorFN CHAR(80) JPATH='$.TRANSLATED.TRANSLATOR.FIRSTNAME',
+ TranslatorLN CHAR(80) JPATH='$.TRANSLATED.TRANSLATOR.LASTNAME',
+ Publisher CHAR(20) JPATH='$.PUBLISHER.NAME',
+ Location CHAR(16) JPATH='$.PUBLISHER.PLACE',
+ Year int(4) JPATH='$.DATEPUB',
+ INDEX IX(ISBN)
+)
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bib0.json' LRECL=320 OPTION_LIST='Pretty=0';
+SHOW INDEX FROM t1;
+SELECT * FROM t1;
+DESCRIBE SELECT * FROM t1 WHERE ISBN = '9782212090819';
+--error ER_GET_ERRMSG
+UPDATE t1 SET AuthorFN = 'Philippe' WHERE ISBN = '9782212090819';
+DROP TABLE t1;
+
+--echo #
+--echo # A file with 2 arrays
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[*].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[].EXPENSE["+"].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[].EXPENSE[+].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Now it can be fully expanded
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[*].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[*].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[*].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+#--error ER_GET_ERRMSG
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # A table showing many calculated results
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12) NOT NULL,
+WEEKS CHAR(12) NOT NULL JPATH='$.WEEK[", "].NUMBER',
+SUMS CHAR(64) NOT NULL JPATH='$.WEEK["+"].EXPENSE[+].AMOUNT',
+SUM DOUBLE(8,2) NOT NULL JPATH='$.WEEK[+].EXPENSE[+].AMOUNT',
+AVGS CHAR(64) NOT NULL JPATH='$.WEEK["+"].EXPENSE[!].AMOUNT',
+SUMAVG DOUBLE(8,2) NOT NULL JPATH='$.WEEK[+].EXPENSE[!].AMOUNT',
+AVGSUM DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[+].AMOUNT',
+AVGAVG DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[!].AMOUNT',
+AVERAGE DOUBLE(8,2) NOT NULL JPATH='$.WEEK[!].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Expand expense in 3 one week tables
+--echo #
+CREATE TABLE t2 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[0].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[0].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[0].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t2;
+
+CREATE TABLE t3 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[1].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[1].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[1].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t3;
+
+CREATE TABLE t4 (
+WHO CHAR(12),
+WEEK INT(2) JPATH='$.WEEK[2].NUMBER',
+WHAT CHAR(32) JPATH='$.WEEK[2].EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.WEEK[2].EXPENSE[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.json';
+SELECT * FROM t4;
+
+--echo #
+--echo # The expanded table is made as a TBL table
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32),
+AMOUNT DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t2,t3,t4';
+SELECT * FROM t1;
+DROP TABLE t1, t2, t3, t4;
+
+--echo #
+--echo # Three partial JSON tables
+--echo #
+CREATE TABLE t2 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp3.json';
+SELECT * FROM t2;
+
+CREATE TABLE t3 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp4.json';
+SELECT * FROM t3;
+
+CREATE TABLE t4 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp5.json';
+SELECT * FROM t4;
+
+--echo #
+--echo # The complete table can be a multiple JSON table
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp*.json' MULTIPLE=1;
+SELECT * FROM t1 ORDER BY WHO, WEEK, WHAT, AMOUNT;
+DROP TABLE t1;
+
+--echo #
+--echo # Or also a partition JSON table
+--echo #
+CREATE TABLE t1 (
+WHO CHAR(12),
+WEEK INT(2),
+WHAT CHAR(32) JPATH='$.EXPENSE[*].WHAT',
+AMOUNT DOUBLE(8,2) JPATH='$.EXPENSE.[*].AMOUNT')
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='mulexp%s.json';
+ALTER TABLE t1
+PARTITION BY LIST COLUMNS(WEEK) (
+PARTITION `3` VALUES IN(3),
+PARTITION `4` VALUES IN(4),
+PARTITION `5` VALUES IN(5));
+SHOW WARNINGS;
+SELECT * FROM t1;
+SELECT * FROM t1 WHERE WEEK = 4;
+DROP TABLE t1, t2, t3, t4;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/biblio.json
+--remove_file $MYSQLD_DATADIR/test/bib0.dnx
+--remove_file $MYSQLD_DATADIR/test/bib0.json
+--remove_file $MYSQLD_DATADIR/test/expense.json
+--remove_file $MYSQLD_DATADIR/test/mulexp3.json
+--remove_file $MYSQLD_DATADIR/test/mulexp4.json
+--remove_file $MYSQLD_DATADIR/test/mulexp5.json
diff --git a/storage/connect/mysql-test/connect/t/json_java_2.test b/storage/connect/mysql-test/connect/t/json_java_2.test
new file mode 100644
index 00000000..03202828
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/json_java_2.test
@@ -0,0 +1,14 @@
+-- source jdbconn.inc
+-- source mongo.inc
+
+--disable_query_log
+eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/Mongo2.jar';
+set connect_json_all_path=0;
+--enable_query_log
+let $DRV= Java;
+let $VERS= 2;
+let $TYPE= JSON;
+let $CONN= CONNECTION='mongodb://localhost:27017' LRECL=4096;
+
+-- source mongo_test.inc
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/json_java_3.test b/storage/connect/mysql-test/connect/t/json_java_3.test
new file mode 100644
index 00000000..238808a8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/json_java_3.test
@@ -0,0 +1,14 @@
+-- source jdbconn.inc
+-- source mongo.inc
+
+--disable_query_log
+eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/Mongo3.jar';
+set connect_json_all_path=0;
+--enable_query_log
+let $DRV= Java;
+let $VERS= 3;
+let $TYPE= JSON;
+let $CONN= CONNECTION='mongodb://localhost:27017' LRECL=4096;
+
+-- source mongo_test.inc
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/json_mongo_c.test b/storage/connect/mysql-test/connect/t/json_mongo_c.test
new file mode 100644
index 00000000..b2148124
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/json_mongo_c.test
@@ -0,0 +1,10 @@
+-- source mongo.inc
+
+let $DRV= C;
+let $VERS= 0;
+let $PROJ= {"projection":;
+let $ENDP= };
+let $TYPE= JSON;
+let $CONN= CONNECTION='mongodb://localhost:27017' LRECL=1024;
+
+-- source mongo_test.inc
diff --git a/storage/connect/mysql-test/connect/t/json_udf.inc b/storage/connect/mysql-test/connect/t/json_udf.inc
new file mode 100644
index 00000000..4f675023
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/json_udf.inc
@@ -0,0 +1,60 @@
+--disable_query_log
+#
+# Check if server has support for loading plugins
+#
+if (`SELECT @@have_dynamic_loading != 'YES'`) {
+ --skip UDF requires dynamic loading
+}
+if (!$HA_CONNECT_SO) {
+ --skip Needs a dynamically built ha_connect.so
+}
+
+--eval CREATE FUNCTION json_make_array RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_array_add RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_array_add_values RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_array_delete RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_make_object RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_object_nonull RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_object_key RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_object_add RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_object_delete RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_object_list RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsonvalue RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsonset_grp_size RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsonget_grp_size RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE AGGREGATE FUNCTION json_array_grp RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE AGGREGATE FUNCTION json_object_grp RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsonget_string RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsonget_int RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsonget_real RETURNS REAL SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsonlocate RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_locate_all RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_file RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jfile_make RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsoncontains RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jsoncontains_path RETURNS INTEGER SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_get_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_set_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_insert_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_update_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_item_merge RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION json_serialize RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_array RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_array_add_values RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_array_add RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_array_delete RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_object RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_object_nonull RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_object_key RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_object_add RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_object_delete RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_object_list RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_get_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_item_merge RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_set_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_insert_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_update_item RETURNS STRING SONAME '$HA_CONNECT_SO';
+--eval CREATE FUNCTION jbin_file RETURNS STRING SONAME '$HA_CONNECT_SO';
+
+--enable_query_log
+
diff --git a/storage/connect/mysql-test/connect/t/json_udf.test b/storage/connect/mysql-test/connect/t/json_udf.test
new file mode 100644
index 00000000..d45131f3
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/json_udf.test
@@ -0,0 +1,268 @@
+--source json_udf.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/biblio.json $MYSQLD_DATADIR/test/biblio.json
+--copy_file $MTR_SUITE_DIR/std_data/employee.dat $MYSQLD_DATADIR/test/employee.dat
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=VIR BLOCK_SIZE=5;
+
+--echo #
+--echo # Test UDF's with constant arguments
+--echo #
+--error ER_CANT_INITIALIZE_UDF
+SELECT JsonValue(56, 3.1416, 'foo', NULL);
+SELECT JsonValue(3.1416);
+SELECT JsonValue(-80);
+SELECT JsonValue('foo');
+SELECT JsonValue(9223372036854775807);
+SELECT JsonValue(NULL);
+SELECT JsonValue(TRUE);
+SELECT JsonValue(FALSE);
+SELECT JsonValue();
+SELECT JsonValue('[11, 22, 33]' json_) FROM t1;
+#
+SELECT Json_Make_Array();
+SELECT Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL);
+SELECT Json_Make_Array(Json_Make_Array(56, 3.1416, 'foo'), TRUE);
+#
+--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL)) Array;
+SELECT Json_Array_Add(Json_Make_Array(56, 3.1416, 'foo', NULL), 'One more') Array;
+#--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Array_Add(JsonValue('one value'), 'One more');
+#--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Array_Add('one value', 'One more');
+SELECT Json_Array_Add('one value' json_, 'One more');
+#--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Array_Add(5 json_, 'One more');
+SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 0);
+SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 2) Array;
+SELECT Json_Array_Add('[5,3,8,7,9]' json_, 4, 9);
+SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), '[2]', 33, 1);
+SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, '[2]', 1);
+SELECT Json_Array_Add(Json_Make_Array(1, 2, Json_Make_Array(11, 22)), 33, 1, '[2]');
+#
+SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin', NULL), 'One more', 'Two more') Array;
+SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin'), 'One more', 'Two more') Array FROM t1;
+SELECT Json_Array_Add_Values(Json_Make_Array(56, 3.1416, 'machin'), n) Array FROM t1;
+SELECT Json_Array_Add_Values(Json_Make_Array(n, 3.1416, 'machin'), n) Array FROM t1;
+SELECT Json_Array_Add_Values('[56]', 3.1416, 'machin') Array;
+#
+SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), 0);
+SELECT Json_Array_Delete(Json_Make_Object(56, 3.1416, 'My name is Foo', NULL), 2);
+SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2');
+SELECT Json_Array_Delete(Json_Make_Array(56, 3.1416, 'My name is "Foo"', NULL), '2', 2);
+#
+SELECT Json_Make_Object(56, 3.1416, 'foo', NULL);
+SELECT Json_Make_Object(56 qty, 3.1416 price, 'foo' truc, NULL garanty);
+SELECT Json_Make_Object();
+SELECT Json_Make_Object(Json_Make_Array(56, 3.1416, 'foo'), NULL);
+SELECT Json_Make_Array(Json_Make_Object(56 "qty", 3.1416 "price", 'foo') ,NULL);
+SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL);
+--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty');
+#
+SELECT Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color);
+SELECT Json_Object_Add(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price);
+SELECT Json_Object_Add(Json_File('notexist.json'), 'cheese' item, '[1]', 1);
+#
+SELECT Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'truc');
+SELECT Json_Object_Delete(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'chose');
+#
+SELECT Json_Object_List(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty)) "Key List";
+SELECT Json_Object_List('{"qty":56, "price":3.1416, "truc":"machin", "garanty":null}') "Key List";
+
+--echo #
+--echo # Test UDF's with column arguments
+--echo #
+CREATE TABLE t2
+(
+ ISBN CHAR(15),
+ LANG CHAR(2),
+ SUBJECT CHAR(32),
+ AUTHOR CHAR(64),
+ TITLE CHAR(32),
+ TRANSLATION CHAR(32),
+ TRANSLATOR CHAR(80),
+ PUBLISHER CHAR(32),
+ DATEPUB int(4)
+) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='biblio.json';
+
+SELECT Json_Make_Array(AUTHOR, TITLE, DATEPUB) FROM t2;
+SELECT Json_Make_Object(AUTHOR, TITLE, DATEPUB) FROM t2;
+--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Array_Grp(TITLE, DATEPUB) FROM t2;
+SELECT Json_Array_Grp(TITLE) FROM t2;
+
+CREATE TABLE t3 (
+ SERIALNO CHAR(5) NOT NULL,
+ NAME VARCHAR(12) NOT NULL FLAG=6,
+ SEX SMALLINT(1) NOT NULL,
+ TITLE VARCHAR(15) NOT NULL FLAG=20,
+ MANAGER CHAR(5) DEFAULT NULL,
+ DEPARTMENT CHAr(4) NOT NULL FLAG=41,
+ SECRETARY CHAR(5) DEFAULT NULL FLAG=46,
+ SALARY DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=8 FILE_NAME='employee.dat' ENDING=1;
+
+SELECT Json_Make_Object(SERIALNO, NAME, TITLE, SALARY) FROM t3 WHERE NAME = 'MERCHANT';
+SELECT DEPARTMENT, Json_Array_Grp(NAME) FROM t3 GROUP BY DEPARTMENT;
+#SET connect_json_grp_size=30; Deprecated
+SELECT JsonSet_Grp_Size(30);
+SELECT Json_Make_Object(title, Json_Array_Grp(name) `json_names`) from t3 GROUP BY title;
+SELECT Json_Make_Array(DEPARTMENT, Json_Array_Grp(NAME)) FROM t3 GROUP BY DEPARTMENT;
+SELECT Json_Make_Object(DEPARTMENT, Json_Array_Grp(NAME) json_NAMES) FROM t3 GROUP BY DEPARTMENT;
+SELECT Json_Make_Object(DEPARTMENT, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, TITLE, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT;
+SELECT Json_Make_Object(DEPARTMENT, TITLE, Json_Array_Grp(Json_Make_Object(SERIALNO, NAME, SALARY)) json_EMPLOYES) FROM t3 GROUP BY DEPARTMENT, TITLE;
+--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Object_Grp(SALARY) FROM t3;
+SELECT Json_Object_Grp(NAME, SALARY) FROM t3;
+SELECT Json_Make_Object(DEPARTMENT, Json_Object_Grp(NAME, SALARY) "Json_SALARIES") FROM t3 GROUP BY DEPARTMENT;
+SELECT Json_Array_Grp(NAME) FROM t3;
+#
+SELECT Json_Object_Key(name, title) FROM t3 WHERE DEPARTMENT = 318;
+SELECT Json_Object_Grp(name, title) FROM t3 WHERE DEPARTMENT = 318;
+
+--echo #
+--echo # Test value getting UDF's
+--echo #
+SELECT JsonGet_String(Json_Array_Grp(name),'[#]') FROM t3;
+SELECT JsonGet_String(Json_Array_Grp(name),'[","]') FROM t3;
+SELECT JsonGet_String(Json_Array_Grp(name),'[>]') FROM t3;
+SET @j1 = '[45,28,36,45,89]';
+SELECT JsonGet_String(@j1,'1');
+SELECT JsonGet_String(@j1 json_,'3');
+SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'3');
+SELECT JsonGet_String(Json_Make_Array(45,28,36,45,89),'["+"]') "list",'=' as "egal",JsonGet_String(Json_Make_Array(45,28,36,45,89),'[+]') "sum";
+SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.0');
+SELECT JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)),'1.*');
+SELECT JsonGet_String(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'truc');
+SET @j2 = '{"qty":56,"price":3.141600,"truc":"machin","garanty":null}';
+SELECT JsonGet_String(@j2 json_,'truc');
+SELECT JsonGet_String(@j2,'truc');
+SELECT JsonGet_String(@j2,'chose');
+SELECT JsonGet_String(NULL json_, NULL);
+SELECT department, JsonGet_String(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+#
+SELECT JsonGet_Int(@j1, '4');
+SELECT JsonGet_Int(@j1, '[#]');
+SELECT JsonGet_Int(@j1, '[+]');
+SELECT JsonGet_Int(@j1 json_, '3');
+SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '3');
+SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '["+"]');
+SELECT JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]');
+SELECT JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0');
+SELECT JsonGet_Int(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '0.1');
+SELECT JsonGet_Int(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'qty');
+SELECT JsonGet_Int(@j2 json_, 'price');
+SELECT JsonGet_Int(@j2, 'qty');
+SELECT JsonGet_Int('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose');
+SELECT JsonGet_Int(JsonGet_String(Json_Make_Array(Json_Make_Array(45,28),Json_Make_Array(36,45,89)), '1.*'), '[+]') sum;
+SELECT department, JsonGet_Int(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"), 'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+#
+SELECT JsonGet_Real(@j1, '2');
+SELECT JsonGet_Real(@j1 json_, '3', 2);
+SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '3');
+SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '["+"]');
+SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[+]');
+SELECT JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]');
+SELECT JsonGet_Real(Json_Make_Array(Json_Make_Array(45,28), Json_Make_Array(36,45,89)), '1.0');
+SELECT JsonGet_Real(Json_Make_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'price');
+SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}' json_, 'qty');
+SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price');
+SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'price', 4);
+SELECT JsonGet_Real('{"qty":56,"price":3.141600,"truc":"machin","garanty":null}', 'chose');
+SELECT department, JsonGet_Real(Json_Make_Object(department, Json_Array_Grp(salary) "Json_salaries"),'salaries.[+]') Sumsal FROM t3 GROUP BY department;
+
+--echo #
+--echo # Documentation examples
+--echo #
+SELECT
+ JsonGet_Int(Json_Make_Array(45,28,36,45,89), '4') "Rank",
+ JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[#]') "Number",
+ JsonGet_String(Json_Make_Array(45,28,36,45,89), '[","]') "Concat",
+ JsonGet_Int(Json_Make_Array(45,28,36,45,89), '[+]') "Sum",
+ JsonGet_Real(Json_Make_Array(45,28,36,45,89), '[!]', 2) "Avg";
+SELECT
+ JsonGet_String('{"qty":7,"price":29.50,"garanty":null}', 'price') "String",
+ JsonGet_Int('{"qty":7,"price":29.50,"garanty":null}', 'price') "Int",
+ JsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price') "Real";
+SELECT JsonGet_Real('{"qty":7,"price":29.50,"garanty":null}', 'price', 3) "Real";
+
+--echo #
+--echo # Testing Locate
+--echo #
+SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'machin');
+SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),56);
+SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),3.1416);
+SELECT JsonLocate(Json_Make_Object(56 qty,3.1416 price,'machin' truc, NULL garanty),'chose');
+SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'Jack') Path;
+SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, 'jack' ci) Path;
+SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"Jack", "LN":"London"}' json_) Path;
+SELECT JsonLocate('{"AUTHORS":[{"FN":"Jules", "LN":"Verne"}, {"FN":"Jack", "LN":"London"}]}' json_, '{"FN":"jack", "LN":"London"}' json_) Path;
+SELECT JsonLocate('[45,28,36,45,89]',36);
+SELECT JsonLocate('[45,28,36,45,89]' json_,28.0);
+SELECT Json_Locate_All('[45,28,36,45,89]',10);
+SELECT Json_Locate_All('[45,28,36,45,89]',45);
+SELECT Json_Locate_All('[[45,28],36,45,89]',45);
+SELECT Json_Locate_All('[[45,28,45],36,45,89]',45);
+SELECT Json_Locate_All('[[45,28,45],36,45,89]',JsonGet_Int('[3,45]','[1]'));
+SELECT JsonLocate('[[45,28,45],36,45,89]',45,n) from t1;
+SELECT JsonGet_String(Json_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) FROM t1;
+SELECT JsonGet_String(Json_Locate_All('[[45,28,45],36,45,89]',45),concat('[',n-1,']')) AS `Path` FROM t1 GROUP BY n HAVING `Path` IS NOT NULL;
+SELECT Json_Locate_All('[45,28,[36,45,89]]',45);
+SELECT Json_Locate_All('[[45,28],[36,45.0,89]]',JsonValue(45.0));
+SELECT Json_Locate_All('[[45,28],[36,45.0,89]]',45.0);
+SELECT JsonLocate('[[45,28],[36,45,89]]','[36,45,89]' json_);
+SELECT JsonLocate('[[45,28],[36,45,89]]','[45,28]' json_);
+SELECT Json_Locate_All('[[45,28],[[36,45],89]]','45') "All paths";
+SELECT Json_Locate_All('[[45,28],[[36,45],89]]','[36,45]' json_);
+SELECT JsonGet_Int(Json_Locate_All('[[45,28],[[36,45],89]]',45), '[#]') "Nb of occurs";
+SELECT Json_Locate_All('[[45,28],[[36,45],89]]',45,2);
+SELECT JsonGet_String(Json_Locate_All('[45,28,36,45,89]',45),'0');
+SELECT JsonLocate(Json_File('test/biblio.json'), 'Knab');
+SELECT Json_Locate_All('test/biblio.json' jfile_, 'Knab');
+
+--echo #
+--echo # Testing json files
+--echo #
+SELECT Jfile_Make('[{"_id":5,"type":"food","item":"beer","taste":"light","price":5.65,"ratings":[5,8,9]},
+{"_id":6,"type":"car","item":"roadster","mileage":56000,"ratings":[6,9]},
+{"_id":7,"type":"food","item":"meat","origin":"argentina","ratings":[2,4]},
+{"_id":8,"type":"furniture","item":"table","size":{"W":60,"L":80,"H":40},"ratings":[5,8,7]}]', 'test/fx.json', 0) AS NewFile;
+SELECT Jfile_Make('test/fx.json', 1);
+SELECT Jfile_Make('test/fx.json' jfile_);
+SELECT Jfile_Make(Jbin_File('test/fx.json'), 0);
+SELECT Json_File('test/fx.json', 1);
+SELECT Json_File('test/fx.json', 2);
+SELECT Json_File('test/fx.json', 0);
+SELECT Json_File('test/fx.json', '0');
+SELECT Json_File('test/fx.json', '[?]');
+SELECT JsonGet_String(Json_File('test/fx.json'), '1.*');
+SELECT JsonGet_String(Json_File('test/fx.json'), '1');
+SELECT JsonGet_Int(Json_File('test/fx.json'), '1.mileage') AS Mileage;
+SELECT JsonGet_Real(Json_File('test/fx.json'), '0.price', 2) AS Price;
+SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings');
+SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 1, 'ratings');
+SELECT Json_Array_Add(Json_File('test/fx.json', '2'), 6, 'ratings', 1);
+SELECT Json_Array_Add(Json_File('test/fx.json', '2.ratings'), 6, 0);
+SELECT Json_Array_Delete(Json_File('test/fx.json', '2'), 'ratings', 1);
+SELECT Json_Object_Add(Json_File('test/fx.json', '2'), 'france' origin);
+SELECT Json_Object_Add(Json_File('test/fx.json', '2'), 70 H, 'size');
+SELECT Json_Object_Add(Json_File('test/fx.json', '3'), 70 H, 'size');
+SELECT Json_Object_List(Json_File('test/fx.json', '3.size'));
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+
+#
+# Clean up
+#
+--source json_udf2.inc
+--remove_file $MYSQLD_DATADIR/test/biblio.json
+--remove_file $MYSQLD_DATADIR/test/employee.dat
+--remove_file $MYSQLD_DATADIR/test/fx.json
+
+
diff --git a/storage/connect/mysql-test/connect/t/json_udf2.inc b/storage/connect/mysql-test/connect/t/json_udf2.inc
new file mode 100644
index 00000000..fe23692a
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/json_udf2.inc
@@ -0,0 +1,51 @@
+--disable_query_log
+
+DROP FUNCTION json_make_array;
+DROP FUNCTION json_array_add;
+DROP FUNCTION json_array_add_values;
+DROP FUNCTION json_array_delete;
+DROP FUNCTION json_make_object;
+DROP FUNCTION json_object_nonull;
+DROP FUNCTION json_object_key;
+DROP FUNCTION json_object_add;
+DROP FUNCTION json_object_delete;
+DROP FUNCTION json_object_list;
+DROP FUNCTION jsonvalue;
+DROP FUNCTION jsonset_grp_size;
+DROP FUNCTION jsonget_grp_size;
+DROP FUNCTION json_array_grp;
+DROP FUNCTION json_object_grp;
+DROP FUNCTION jsonget_string;
+DROP FUNCTION jsonget_int;
+DROP FUNCTION jsonget_real;
+DROP FUNCTION jsonlocate;
+DROP FUNCTION json_locate_all;
+DROP FUNCTION json_file;
+DROP FUNCTION jfile_make;
+DROP FUNCTION json_get_item;
+DROP FUNCTION json_item_merge;
+DROP FUNCTION jsoncontains;
+DROP FUNCTION jsoncontains_path;
+DROP FUNCTION json_set_item;
+DROP FUNCTION json_insert_item;
+DROP FUNCTION json_update_item;
+DROP FUNCTION json_serialize;
+DROP FUNCTION jbin_array;
+DROP FUNCTION jbin_array_add_values;
+DROP FUNCTION jbin_array_add;
+DROP FUNCTION jbin_array_delete;
+DROP FUNCTION jbin_object;
+DROP FUNCTION jbin_object_nonull;
+DROP FUNCTION jbin_object_key;
+DROP FUNCTION jbin_object_add;
+DROP FUNCTION jbin_object_delete;
+DROP FUNCTION jbin_object_list;
+DROP FUNCTION jbin_get_item;
+DROP FUNCTION jbin_item_merge;
+DROP FUNCTION jbin_set_item;
+DROP FUNCTION jbin_insert_item;
+DROP FUNCTION jbin_update_item;
+DROP FUNCTION jbin_file;
+
+--enable_query_log
+
diff --git a/storage/connect/mysql-test/connect/t/json_udf_bin.test b/storage/connect/mysql-test/connect/t/json_udf_bin.test
new file mode 100644
index 00000000..cbbfca9d
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/json_udf_bin.test
@@ -0,0 +1,213 @@
+--source json_udf.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/gloss.json $MYSQLD_DATADIR/gloss.json
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=VIR BLOCK_SIZE=3;
+
+--echo #
+--echo # Test Jbin UDF's
+--echo #
+SELECT Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), n) from t1;
+SELECT Json_Array_Add(Jbin_Array(n, 3.1416, 'My name is "Foo"', NULL), n) from t1;
+SELECT Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), Jbin_Array('a','b',n)) from t1;
+SELECT Json_Array_Add(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), JsonGet_String(Jbin_Array('a','b','c'), '[1]'));
+SELECT Json_Array_Delete(Jbin_Array_Add_Values(Jbin_Array(56, 3.1416, 'My name is "Foo"', NULL), "One more", 2), 4);
+SELECT Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), NULL), '[1]', 1);
+SELECT Json_Array_Delete(Jbin_Array(56, Jbin_Array(3.1416, 'My name is "Foo"'), TRUE), 1, '[1]');
+SELECT Json_Make_Array(1, TRUE, 0, FALSE);
+SELECT Json_Serialize(Jbin_Array(TRUE, FALSE));
+#
+SELECT Json_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL);
+SELECT Json_Serialize(Jbin_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty', NULL));
+--error ER_CANT_INITIALIZE_UDF
+SELECT Jbin_Object_Key('qty', 56, 'price', 3.1416, 'truc', 'machin', 'garanty');
+SELECT Json_Object_Add(Jbin_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color);
+SELECT Json_Object_Add(Jbin_Object(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price);
+SELECT Json_Object_Add(Jbin_Object_Nonull(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 'blue' color);
+SELECT Json_Object_Add(Jbin_Object_Nonull(56 qty, 3.1416 price, 'machin' truc, NULL garanty), 45.99 price);
+
+--echo #
+--echo # Test Jbin file UDF's
+--echo #
+SELECT Json_Serialize(Jbin_File('gloss.json'));
+SELECT JsonLocate(Jbin_File('gloss.json'),'XML');
+#
+SELECT Json_Object_Key('first', 'foo', 'second', Jbin_Array('a', 33));
+SELECT Json_Get_Item(Json_Make_Array('a','b','c'), '$[1]');
+SELECT Json_Get_Item(Json_Make_Object('foo' AS "first", Json_Make_Array('a', 33) AS "json_second"), '$.second') AS "item";
+SELECT Json_Get_Item(Jbin_Object('foo' first, Jbin_Array('a', 33) jbin_second), '$.second') item;
+SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv');
+SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv'));
+SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv');
+SELECT JsonGet_String(Json_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso') lang;
+SELECT Json_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso') "See also";
+SELECT Json_Serialize(Jbin_Get_Item(Jbin_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso')) "See also";
+SELECT JsonGet_String(Json_Get_Item(Json_File('gloss.json'),'$.glossary.GlossDiv.GlossList.GlossEntry.GlossDef.GlossSeeAlso'),'$[0]') lang;
+
+--echo #
+--echo # Test Item Get/Set/Insert/Update UDF's
+--echo #
+SELECT Json_Get_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[]');
+SELECT Json_Get_Item(Jbin_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), '$[1]');
+SELECT Json_Get_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$[1]');
+#
+SELECT Json_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)));
+--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), '$.foo');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 7, '$[1]');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 7, '$[1]');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Json_Make_Array(7, 8, 9), '$[1]');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2]');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[2].*');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 3.1416, '$.foo');
+SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 'toto', '$[1][2]');
+SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 300, '$[2].nxt.total[]');
+SELECT Json_Set_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 300, '$[2].nxt.total[]');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), Jbin_Array(7, 8, 9), '$[1]', 5, '$[2].cinq', 10, '$[1][]');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 44, '$[2].quatre');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, 'truc');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '');
+SELECT Json_Set_Item(Jbin_Array(1, 2, Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '*');
+SELECT Json_Serialize(Jbin_Set_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq'));
+#
+SELECT Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq');
+SELECT Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq');
+SELECT Json_Insert_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre');
+SELECT Json_Update_Item(Jbin_Array(1, Jbin_Array(7, 8, 9), Jbin_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][]', 44, '$[2].quatre');
+SELECT Json_Insert_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]');
+SELECT Json_Update_Item(Json_Make_Array(1, Json_Make_Array(7, 8, 9), Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[2].cinq', 10, '$[1][1]', 300, '$[2].nxt.total[]');
+SELECT Json_Insert_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]');
+SELECT Json_Update_Item(Json_Make_Array(1, 2, Json_Object_Key('trois', 3, 'quatre', 4)), 5, '$[]');
+
+--echo #
+--echo # Test merging items UDF's
+--echo #
+SELECT Json_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f'));
+SELECT Json_Item_Merge(Json_Make_Array('a','b','c'), Json_Make_Array('d','e','f')) AS "Result";
+SELECT Json_Array_Add(Jbin_Item_Merge(Jbin_Array('a','b','c'), Jbin_Array('d','e','f')), 'and', 3);
+SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d",5 "e",6 "f"));
+SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",2 "c"), Jbin_Array('d','e','f'));
+SELECT Json_Object_Add(Jbin_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "d",5 "e",6 "f")), 'x' AS "and");
+SELECT Json_Item_Merge(Jbin_Object(1 "a",2 "b",3 "c"), Jbin_Object(4 "a",5 "e",6 "f"));
+--error ER_CANT_INITIALIZE_UDF
+SELECT Json_Item_Merge('foo', Json_Make_Array('d','e','f'));
+
+--echo #
+--echo # Test making file UDF's
+--echo #
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+SELECT Json_File('bt1.json');
+SELECT Json_File(Jfile_Make(Jbin_File('bt1.json'), 0));
+SELECT Json_File(Jfile_Make(Jbin_File('bt1.json'), 1));
+SELECT Json_File(Jfile_Make(Jbin_File('bt1.json'), 2));
+SELECT Json_File('bt1.json', 0);
+SELECT Json_File('bt1.json', 1);
+SELECT Json_File('bt1.json', 2);
+SELECT Json_Serialize(Jbin_Array('a','b','c'));
+SELECT Json_Serialize(Jbin_Array_Add(Jbin_File('not_exist.json'), 'd'));
+--echo # This does not modify the file
+SELECT Json_Serialize(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'));
+SELECT Json_File('bt1.json', 2);
+--echo # This does modify the file
+SELECT Json_Array_Add(Jbin_File('bt1.json'), 'd');
+SELECT Json_File('bt1.json', 2);
+--echo # Back to the original file
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+SELECT Json_Make_Object(Jbin_Array_Add(Jbin_Array('a','b','c'), 'd') "Jbin_foo") AS "Result";
+SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd')) AS "Result";
+SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1") AS "Result";
+--echo # This does modify the file
+SELECT Json_Make_Object(Json_Array_Add(Jbin_File('bt1.json'), 'd') "Jfile_bt1") AS "Result";
+SELECT Json_File('bt1.json');
+SELECT Json_File(Json_Array_Delete(Jbin_File('bt1.json'), 3), 2);
+SELECT Json_Make_Object(Jbin_Array_Add(Jbin_File('bt1.json'), 'd') "Jbin_bt1", n "t1") AS "Result" from t1;
+SELECT Json_File(Json_Array_Add(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'), 'e')) AS "Result";
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+SELECT Json_File(Json_Array_Add(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'), 'e')) AS "Result" from t1;
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+SELECT Json_Array_Add(Jbin_Array_Add(Jbin_File('bt1.json'), 'd'), n) AS "Result" from t1;
+--echo # Show modified file
+SELECT Json_File('bt1.json');
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+SELECT Json_Array_Add(Jbin_File('bt1.json'), n) AS "Result" from t1;
+--echo # Show modified file
+SELECT Json_File('bt1.json');
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+SELECT Json_File(Jbin_Item_Merge(Jbin_File('bt1.json'), Jbin_Array('d','e','f')));
+SELECT Json_File(Json_Item_Merge(Jbin_File('bt1.json'), Jbin_Array('d','e','f')));
+SELECT Jfile_Make(Jbin_Array('a','b','c'), 'bt1.json');
+--echo # Test DELETE from file
+SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 1)) AS "Result";
+SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 2) "Jbin_bt1") AS "Result";
+SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 0) "Jbin_bt1", n "t1") AS "Result" from t1;
+SELECT Json_Make_Object(Jbin_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1;
+SELECT Json_Make_Object(Json_Array_Delete(Jbin_File('bt1.json'), 3 - n) "Jbin_bt1") AS "Result" from t1;
+--echo # Show modified file
+SELECT Json_File('bt1.json');
+--echo # Object file
+SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0);
+SELECT Json_File('bt2.json', 0);
+SELECT Json_File('bt2.json');
+SELECT Json_Serialize(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"));
+--echo # First query (file not modified)
+SELECT Json_Make_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jbin_new") AS "Result";
+--echo # First query (file modified)
+SELECT Json_Make_Object(Json_Object_Add(Jbin_File('bt2.json'), 4 AS "d") AS "Jfile_new") AS "Result";
+SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0);
+SELECT Json_Make_Object(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d") "Jbin_new", n "t1") AS "Result" from t1;
+SELECT Json_File(Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), 5 "e")) AS "Result";
+SELECT Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), 5 "e") AS "Result" from t1;
+SELECT Json_Object_Add(Jbin_Object_Add(Jbin_File('bt2.json'), 4 "d"), n "n") AS "Result" from t1;
+SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0);
+SELECT Json_Object_Add(Jbin_File('bt2.json'), n) AS "Result" from t1;
+SELECT Json_File('bt2.json');
+SELECT Jfile_Make(Jbin_Object(1 "a", 2 "b", 3 "c"), 'bt2.json', 0);
+SELECT Json_Serialize(Jbin_Item_Merge(Jbin_File('bt2.json'), Jbin_Object(4 "d",5 "e",6 "f"))) AS "Result";
+SELECT Json_File(Json_Item_Merge(Jbin_File('bt2.json'), Jbin_Object(4 "d",5 "e",6 "f"))) AS "Result";
+SELECT Json_Item_Merge(Json_Make_Object(1 "a", 2 "b", 3 "c"), Json_Make_Object(4 "d",5 "b",6 "f")) AS "Result";
+#
+SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'b')) AS "Result";
+SELECT Json_Make_Object(Jbin_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result";
+SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jbin_bt1") AS "Result";
+SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'c') "Jfile_bt1") AS "Result";
+SELECT Json_Make_Object(Json_Object_Delete(Jbin_File('bt2.json'), 'a') "Jbin_bt1", n "t1") AS "Result" from t1;
+#
+SELECT Json_Serialize(Jbin_Object_List(Jbin_File('bt2.json'))) "Key list";
+
+#
+# Test documentation examples
+#
+SELECT Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0);
+SELECT Json_Array_Add(Json_File('bt3.json', '$.b'), 66);
+SELECT Json_Array_Add(Json_File('bt3.json'), 66, '$.b');
+SELECT Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66);
+SELECT Json_File('bt3.json', 3);
+SELECT Jfile_Make('{"a":1, "b":[44, 55]}' json_, 'bt3.json', 0);
+#
+CREATE TABLE t2 (
+ n INT KEY,
+ jfile_cols CHAR(12) NOT NULL)
+ENGINE= MYISAM;
+INSERT INTO t2 VALUES(1,'bt3.json');
+--echo # In this table, the jfile_cols column just contains a file name
+UPDATE t2 SET jfile_cols = Json_Array_Add(Jbin_File('bt3.json', '$.b'), 66) WHERE n = 1;
+SELECT JsonGet_String(jfile_cols, '*') FROM t2;
+UPDATE t2 SET jfile_cols = Json_Insert_Item(jfile_cols, 77, '$.b[]') WHERE n = 1;
+SELECT JsonGet_String(jfile_cols, '$.b.*') FROM t2;
+UPDATE t2 SET jfile_cols = Json_Insert_Item(Jbin_Insert_Item(jfile_cols, 88, '$.b[]') , 99, '$.b[]') WHERE n = 1;
+SELECT JsonGet_String(jfile_cols, '*') FROM t2;
+
+DROP TABLE t1, t2;
+
+#
+# Clean up
+#
+--source json_udf2.inc
+--remove_file $MYSQLD_DATADIR/gloss.json
+--remove_file $MYSQLD_DATADIR/bt1.json
+--remove_file $MYSQLD_DATADIR/bt2.json
+--remove_file $MYSQLD_DATADIR/bt3.json
+
diff --git a/storage/connect/mysql-test/connect/t/mongo.inc b/storage/connect/mysql-test/connect/t/mongo.inc
new file mode 100644
index 00000000..fab2ca84
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mongo.inc
@@ -0,0 +1,3 @@
+let $MONGO= C:/Applic/MongoDB/Server/3.6/bin/mongo;
+let $MONGOIMPORT= C:/Applic/MongoDB/Server/3.6/bin/mongoimport;
+
diff --git a/storage/connect/mysql-test/connect/t/mongo_c.test b/storage/connect/mysql-test/connect/t/mongo_c.test
new file mode 100644
index 00000000..1c4930e9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mongo_c.test
@@ -0,0 +1,9 @@
+-- source mongo.inc
+
+let $DRV= C;
+let $VERS= 0;
+let $PROJ= {"projection":;
+let $ENDP= };
+let $TYPE= MONGO;
+
+-- source mongo_test.inc
diff --git a/storage/connect/mysql-test/connect/t/mongo_java_2.test b/storage/connect/mysql-test/connect/t/mongo_java_2.test
new file mode 100644
index 00000000..7dcd0281
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mongo_java_2.test
@@ -0,0 +1,12 @@
+-- source jdbconn.inc
+-- source mongo.inc
+
+--disable_query_log
+eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/Mongo2.jar';
+--enable_query_log
+let $DRV= Java;
+let $VERS= 2;
+let $TYPE= MONGO;
+
+-- source mongo_test.inc
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/mongo_java_3.test b/storage/connect/mysql-test/connect/t/mongo_java_3.test
new file mode 100644
index 00000000..aab16d5e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mongo_java_3.test
@@ -0,0 +1,12 @@
+-- source jdbconn.inc
+-- source mongo.inc
+
+--disable_query_log
+eval SET GLOBAL connect_class_path='$MTR_SUITE_DIR/std_data/Mongo3.jar';
+--enable_query_log
+let $DRV= Java;
+let $VERS= 3;
+let $TYPE= MONGO;
+
+-- source mongo_test.inc
+-- source jdbconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/mongo_test.inc b/storage/connect/mysql-test/connect/t/mongo_test.inc
new file mode 100644
index 00000000..6e7c78e8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mongo_test.inc
@@ -0,0 +1,216 @@
+set connect_enable_mongo=1;
+set connect_json_all_path=0;
+
+--echo #
+--echo # Test the MONGO table type
+--echo #
+eval CREATE TABLE t1 (Document varchar(1024) JPATH='*')
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME=restaurants $CONN
+OPTION_LIST='Driver=$DRV,Version=$VERS' DATA_CHARSET=utf8;
+SELECT * from t1 limit 3;
+DROP TABLE t1;
+
+--echo #
+--echo # Test catfunc
+--echo #
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME=restaurants CATFUNC=columns
+OPTION_LIST='Depth=1,Driver=$DRV,Version=$VERS' DATA_CHARSET=utf8 $CONN;
+SELECT * from t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Explicit columns
+--echo #
+eval CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(255) NOT NULL,
+cuisine VARCHAR(255) NOT NULL,
+borough VARCHAR(255) NOT NULL,
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME=restaurants
+CONNECTION='mongodb://localhost:27017' LRECL=1024 DATA_CHARSET=utf8
+OPTION_LIST='Driver=$DRV,Version=$VERS';
+SELECT * FROM t1 LIMIT 10;
+DROP TABLE t1;
+
+--echo #
+--echo # Test discovery
+--echo #
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME=restaurants
+OPTION_LIST='Depth=1,Driver=$DRV,Version=$VERS' $CONN DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1 LIMIT 5;
+DROP TABLE t1;
+
+--echo #
+--echo # Dropping a column
+--echo #
+let $COLIST= $PROJ{"grades":0}$ENDP;
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME=restaurants DATA_CHARSET=utf8
+COLIST='$COLIST' OPTION_LIST='Driver=$DRV,Version=$VERS,level=0' $CONN;
+SELECT * FROM t1 LIMIT 10;
+DROP TABLE t1;
+
+--echo #
+--echo # Specifying Jpath
+--echo #
+eval CREATE TABLE t1 (
+_id VARCHAR(24) NOT NULL,
+name VARCHAR(64) NOT NULL,
+cuisine CHAR(200) NOT NULL,
+borough CHAR(16) NOT NULL,
+street VARCHAR(65) JPATH='address.street',
+building CHAR(16) JPATH='address.building',
+zipcode CHAR(5) JPATH='address.zipcode',
+grade CHAR(1) JPATH='grades.0.grade',
+score INT(4) NOT NULL JPATH='grades.0.score',
+`date` DATE JPATH='grades.0.date',
+restaurant_id VARCHAR(255) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME='restaurants' DATA_CHARSET=utf8
+OPTION_LIST='Driver=$DRV,Version=$VERS' $CONN;
+--vertical_results
+SELECT * FROM t1 LIMIT 1;
+--horizontal_results
+SELECT name, street, score, date FROM t1 LIMIT 5;
+SELECT name, cuisine, borough FROM t1 WHERE grade = 'A' LIMIT 10;
+SELECT COUNT(*) FROM t1 WHERE grade = 'A';
+SELECT * FROM t1 WHERE cuisine = 'English';
+SELECT * FROM t1 WHERE score = building;
+DROP TABLE t1;
+
+--echo #
+--echo # Specifying Filter
+--echo #
+eval CREATE TABLE t1 (
+_id CHAR(24) NOT NULL,
+name CHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+restaurant_id CHAR(8) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME=restaurants DATA_CHARSET=utf8
+FILTER='{"cuisine":"French","borough":{"\$ne":"Manhattan"}}'
+OPTION_LIST='Driver=$DRV,Version=$VERS' $CONN;
+SELECT name FROM t1 WHERE borough = 'Queens';
+DROP TABLE t1;
+
+--echo #
+--echo # Testing pipeline
+--echo #
+eval CREATE TABLE t1 (
+name VARCHAR(64) NOT NULL,
+borough CHAR(16) NOT NULL,
+date DATETIME NOT NULL,
+grade CHAR(1) NOT NULL,
+score INT(4) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME='restaurants' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"\$match":{"cuisine":"French"}},{"\$unwind":"\$grades"},{"\$project":{"_id":0,"name":1,"borough":1,"date":"\$grades.date","grade":"\$grades.grade","score":"\$grades.score"}}]}'
+OPTION_LIST='Driver=$DRV,Version=$VERS,Pipeline=1' $CONN;
+SELECT * FROM t1 LIMIT 10;
+SELECT name, grade, score, date FROM t1 WHERE borough = 'Bronx';
+DROP TABLE t1;
+
+--echo #
+--echo # try level 2 discovery
+--echo #
+let $COLIST= $PROJ{"cuisine":0}$ENDP;
+eval CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME=restaurants
+FILTER='{"cuisine":"French","borough":{"\$ne":"Manhattan"}}'
+COLIST='$COLIST' $CONN
+OPTION_LIST='Driver=$DRV,level=2,version=$VERS';
+SHOW CREATE TABLE t1;
+IF ($TYPE == MONGO)
+{
+SELECT name, borough, address_street, grades_0_score AS score FROM t1 WHERE grades_0_grade = 'B';
+}
+IF ($TYPE == JSON)
+{
+SELECT name, borough, address_street, grades_score AS score FROM t1 WHERE grades_grade = 'B';
+}
+IF ($TYPE == BSON)
+{
+SELECT name, borough, address_street, grades_score AS score FROM t1 WHERE grades_grade = 'B';
+}
+DROP TABLE t1;
+
+--echo #
+--echo # try CRUD operations
+--echo #
+--disable_query_log
+--exec $MONGO --eval "db.testcoll.drop()" --quiet
+--enable_query_log
+eval CREATE TABLE t1 (_id INT(4) NOT NULL, msg CHAR(64))
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME='testcoll'
+OPTION_LIST='Driver=$DRV,Version=$VERS' $CONN;
+DELETE FROM t1;
+INSERT INTO t1 VALUES(0,NULL),(1,'One'),(2,'Two'),(3,'Three');
+SELECT * FROM t1;
+UPDATE t1 SET msg = 'Deux' WHERE _id = 2;
+DELETE FROM t1 WHERE msg IS NULL;
+SELECT * FROM t1;
+DELETE FROM t1;
+DROP TABLE t1;
+--exec $MONGO --eval "db.testcoll.drop()" --quiet
+
+--echo #
+--echo # List states whose population is equal or more than 10 millions
+--echo #
+--disable_query_log
+--exec $MONGO --eval "db.cities.drop()" --quiet
+--enable_query_log
+--exec $MONGOIMPORT --quiet $MTR_SUITE_DIR/std_data/cities.json
+eval CREATE TABLE t1 (
+ _id char(5) NOT NULL,
+ city char(16) NOT NULL,
+ loc_0 double(12,6) NOT NULL `JPATH`='loc.0',
+ loc_1 char(12) NOT NULL `JPATH`='loc.1',
+ pop int(11) NOT NULL,
+ state char(2) NOT NULL)
+ENGINE=CONNECT CONNECTION='mongodb://localhost:27017' TABLE_TYPE=$TYPE TABNAME='cities'
+OPTION_LIST='Driver=$DRV,Version=$VERS' $CONN DATA_CHARSET='utf8';
+--echo # Using SQL for grouping
+SELECT state, sum(pop) AS totalPop FROM t1 GROUP BY state HAVING totalPop >= 10000000 ORDER BY totalPop DESC;
+DROP TABLE t1;
+
+--echo # Using a pipeline for grouping
+eval CREATE TABLE t1 (_id CHAR(2) NOT NULL, totalPop INT(11) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME='cities' DATA_CHARSET=utf8
+COLIST='{"pipeline":[{"\$group":{"_id":"\$state","totalPop":{"\$sum":"\$pop"}}},{"\$match":{"totalPop":{"\$gte":10000000}}},{"\$sort":{"totalPop":-1}}]}'
+OPTION_LIST='Driver=$DRV,Version=$VERS,Pipeline=1' $CONN;
+SELECT * FROM t1;
+DROP TABLE t1;
+--exec $MONGO --eval "db.cities.drop()" --quiet
+
+--echo #
+--echo # Test making array
+--echo #
+eval CREATE TABLE t1 (
+ _id int(4) NOT NULL,
+ item CHAR(8) NOT NULL,
+ prices_0 INT(6) JPATH='prices.0',
+ prices_1 INT(6) JPATH='prices.1',
+ prices_2 INT(6) JPATH='prices.2',
+ prices_3 INT(6) JPATH='prices.3',
+ prices_4 INT(6) JPATH='prices.4')
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME='testcoll' DATA_CHARSET=utf8
+OPTION_LIST='Driver=$DRV,Version=$VERS' $CONN;
+INSERT INTO t1 VALUES
+(1,'journal',87,45,63,12,78),
+(2,'notebook',123,456,789,NULL,NULL),
+(3,'paper',5,7,3,8,NULL),
+(4,'planner',25,71,NULL,44,27),
+(5,'postcard',5,7,3,8,NULL);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Test array aggregation
+--echo #
+eval CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=$TYPE TABNAME='testcoll'
+COLIST='{"pipeline":[{"\$project":{"_id":0,"item":1,"total":{"\$sum":"\$prices"},"average":{"\$avg":"\$prices"}}}]}'
+OPTION_LIST='Driver=$DRV,Version=$VERS,Pipeline=YES' $CONN;
+SELECT * FROM t1;
+DROP TABLE t1;
+--exec $MONGO --eval "db.testcoll.drop()" --quiet
+
+set connect_enable_mongo=0;
diff --git a/storage/connect/mysql-test/connect/t/mrr.test b/storage/connect/mysql-test/connect/t/mrr.test
new file mode 100644
index 00000000..4b9e64bd
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mrr.test
@@ -0,0 +1,66 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/emp.txt $MYSQLD_DATADIR/test/emp.txt
+
+--echo #
+--echo # Show MRR setting. The way it is done is because the t3 table cannot be directly based on
+--echo # the information_schema.session_variables table. Not being a CONNECT table, it would be
+--echo # read using an intermediate MYSQL table using the MySQL API and could not reflect the
+--echo # current session variable change (the call would create another session) This would be
+--echo # correct only for querying GLOBAL variables but is not what we want to do here.
+--echo #
+CREATE TABLE t2 (
+name VARCHAR(64) NOT NULL,
+value VARCHAR(1024) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=DOS;
+INSERT INTO t2 SELECT * FROM information_schema.session_variables WHERE variable_name = 'OPTIMIZER_SWITCH';
+# Check that MRR is OFF by default
+create table t3 (
+name CHAR(32) NOT NULL,
+value CHAR(64) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=XCOL TABNAME=t2 OPTION_LIST='Colname=value';
+SELECT value FROM t3 WHERE value LIKE 'mrr%';
+
+--echo #
+--echo # Testing indexing with MRR OFF
+--echo #
+CREATE TABLE t1
+(
+ matricule INT(4) KEY NOT NULL field_format='Z',
+ nom VARCHAR(16) NOT NULL,
+ prenom VARCHAR(20) NOT NULL,
+ sexe SMALLINT(1) NOT NULL COMMENT 'sexe 1:M 2:F',
+ aanais INT(4) NOT NULL,
+ mmnais INT(2) NOT NULL,
+ ddentree DATE NOT NULL date_format='YYYYMM',
+ ddnom DATE NOT NULL date_format='YYYYMM',
+ brut INT(5) NOT NULL,
+ net DOUBLE(8,2) NOT NULL,
+ service INT(2) NOT NULL,
+ sitmat CHAR(1) NOT NULL,
+ formation CHAR(5) NOT NULL,
+ INDEX NP(nom,prenom)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='emp.txt' ENDING=2;
+SELECT * FROM t1 LIMIT 10;
+--echo # Without MRR, the rows are retrieved sorted by name
+SELECT matricule, nom, prenom, sitmat, net FROM t1 WHERE nom IN ('ETANG','FOCH','CERF','ITALIE','ROI');
+
+--echo #
+--echo # Testing indexing with MRR ON
+--echo #
+SET @@LOCAL.OPTIMIZER_SWITCH='mrr=on';
+--echo # Refresh the t2 table to reflect the change
+UPDATE t2, information_schema.session_variables SET value = variable_value WHERE variable_name = 'OPTIMIZER_SWITCH';
+--echo # Check that MRR is ON for the session
+SELECT value FROM t3 WHERE value LIKE 'mrr%';
+--echo # With MRR, the rows are retrieved sorted by their position in the table
+SELECT matricule, nom, prenom, sitmat, net FROM t1 WHERE nom IN ('ETANG','FOCH','CERF','ITALIE','ROI');
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+
+#
+# Clean up
+#
+SET @@LOCAL.OPTIMIZER_SWITCH='mrr=off';
+--remove_file $MYSQLD_DATADIR/test/emp.txt
diff --git a/storage/connect/mysql-test/connect/t/mul.test b/storage/connect/mysql-test/connect/t/mul.test
new file mode 100644
index 00000000..97caba02
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mul.test
@@ -0,0 +1,43 @@
+--echo #
+--echo # Testing multiple 1
+--echo #
+CREATE TABLE `t1` (
+ `a` char(10) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=CSV `sep_char`=';';
+INSERT INTO t1 VALUES('test1','bla');
+SELECT * FROM t1;
+
+CREATE TABLE `t2` (
+ `a` char(10) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=CSV `sep_char`=';';
+INSERT INTO t2 VALUES('test2','blub');
+SELECT * FROM t2;
+
+CREATE TABLE `t_all` (
+ `a` char(10) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=CSV `file_name`='t*.csv' `sep_char`=';' `multiple`=1;
+SELECT * FROM t_all order by `a`;
+
+--echo #
+--echo # Testing multiple 2
+--echo #
+CREATE table fnlist (
+fn char(8) not null
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 table_type=DOS;
+INSERT INTO fnlist VALUES('t1.csv'),('t2.csv');
+SELECT fn FROM fnlist;
+
+CREATE TABLE `tblist` (
+ `a` char(10) DEFAULT NULL,
+ `b` char(10) DEFAULT NULL
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 `table_type`=CSV `file_name`='fnlist.dos' `sep_char`=';' `multiple`=2;
+SELECT * FROM tblist;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t_all;
+DROP TABLE fnlist;
+DROP TABLE tblist;
diff --git a/storage/connect/mysql-test/connect/t/mul_new.test b/storage/connect/mysql-test/connect/t/mul_new.test
new file mode 100644
index 00000000..33011f6c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mul_new.test
@@ -0,0 +1,67 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+--mkdir $MYSQLD_DATADIR/test/subdir/
+
+--echo #
+--echo # Testing multiple 1
+--echo #
+CREATE TABLE t1 (
+ Chiffre int(3) NOT NULL,
+ Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='num1.csv' LRECL=20 HEADER=1;
+INSERT INTO t1 VALUES(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five'),(6,'Six');
+SELECT * FROM t1;
+
+CREATE TABLE t2 (
+ Chiffre int(3) NOT NULL,
+ Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='subdir/num2.csv' LRECL=20 HEADER=1;
+INSERT INTO t2 VALUES(7,'Seven'),(8,'Eight'),(9,'Nine'),(10,'Ten'),(11,'Eleven'),(12,'Twelve');
+SELECT * FROM t2;
+
+CREATE TABLE t3 (
+ Chiffre int(3) NOT NULL,
+ Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='num3.csv' LRECL=20 HEADER=1;
+INSERT INTO t3 VALUES(13,'Thirteen'),(14,'Fourteen'),(15,'Fifteen'),(16,'Sixteen'),(17,'Seventeen'),(18,'Eighteen');
+SELECT * FROM t3;
+
+CREATE TABLE t4 (
+ Chiffre int(3) NOT NULL,
+ Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='subdir/num4.csv' LRECL=20 HEADER=1;
+INSERT INTO t4 VALUES(19,'Nineteen'),(20,'Twenty'),(21,'Twenty one'),(22,'Twenty two'),(23,'Tenty three'),(24,'Twenty four');
+SELECT * FROM t4;
+
+CREATE TABLE t5 (
+ Chiffre int(3) NOT NULL,
+ Lettre char(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE='CSV' FILE_NAME='num5.csv' LRECL=20 HEADER=1;
+INSERT INTO t5 VALUES(25,'Twenty five'),(26,'Twenty six'),(27,'Twenty seven'),(28,'Twenty eight'),(29,'Tenty eight'),(30,'Thirty');
+SELECT * FROM t5;
+
+CREATE TABLE t_all (
+ Chiffre int(3) not null,
+ Lettre char(16) not null)
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='num?.csv' HEADER=1 LRECL=20 MULTIPLE=1;
+SELECT * FROM t_all ORDER BY Chiffre;
+
+--echo #
+--echo # Testing multiple 3
+--echo #
+ALTER TABLE t_all MULTIPLE=3;
+SELECT * FROM t_all ORDER BY Chiffre;
+
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
+DROP TABLE t5;
+DROP TABLE t_all;
+
+--remove_file $MYSQLD_DATADIR/test/subdir/num2.csv
+--remove_file $MYSQLD_DATADIR/test/subdir/num4.csv
+--rmdir $MYSQLD_DATADIR/test/subdir/
+--remove_file $MYSQLD_DATADIR/test/num1.csv
+--remove_file $MYSQLD_DATADIR/test/num3.csv
+--remove_file $MYSQLD_DATADIR/test/num5.csv
+
diff --git a/storage/connect/mysql-test/connect/t/myconn.inc b/storage/connect/mysql-test/connect/t/myconn.inc
new file mode 100644
index 00000000..54c698e7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/myconn.inc
@@ -0,0 +1,27 @@
+--source include/not_embedded.inc
+
+let $PORT= `select @@port`;
+
+--disable_query_log
+--replace_result $PORT PORT
+--error 0,ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/tx1';
+if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+ AND ENGINE='CONNECT'
+ AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
+{
+ Skip Need MySQL support;
+}
+DROP TABLE t1;
+--enable_query_log
+
+connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,);
+
+connection master;
+CREATE DATABASE connect;
+
+connection slave;
+CREATE DATABASE connect;
diff --git a/storage/connect/mysql-test/connect/t/myconn_cleanup.inc b/storage/connect/mysql-test/connect/t/myconn_cleanup.inc
new file mode 100644
index 00000000..db473e51
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/myconn_cleanup.inc
@@ -0,0 +1,9 @@
+connection master;
+--disable_warnings
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+
+connection slave;
+DROP TABLE IF EXISTS connect.t1;
+DROP DATABASE IF EXISTS connect;
+--enable_warnings
diff --git a/storage/connect/mysql-test/connect/t/mysql.test b/storage/connect/mysql-test/connect/t/mysql.test
new file mode 100644
index 00000000..7585c202
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql.test
@@ -0,0 +1,472 @@
+-- source include/not_embedded.inc
+
+#
+# TODO: consider a possibility to run this test
+# against some remote MySQL server
+#
+
+let $PORT= `select @@port`;
+
+--disable_query_log
+--replace_result $PORT PORT
+--error 0,ER_UNKNOWN_ERROR
+--eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='tx1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+ AND ENGINE='CONNECT'
+ AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
+{
+ Skip Need MySQL support;
+}
+DROP TABLE t1;
+--enable_query_log
+
+# TODO: remote VARCHAR is displayed as CHAR
+
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+
+--echo #
+--echo # Testing errors
+--echo #
+
+# Bad user name
+# Suppress "mysql_real_connect failed:" (printed in _DEBUG build)
+--replace_result $PORT PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root1,port=$PORT'
+
+# Bad database name
+--replace_result $PORT PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL DBNAME='unknown' TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+
+# Bad database name, with OPTION_LIST going first.
+--replace_result $PORT PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL OPTION_LIST='host=localhost,user=root,port=$PORT' DBNAME='unknown' TABNAME='t1'
+
+# Bad table name
+--replace_result $PORT PORT
+--error ER_UNKNOWN_ERROR
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='unknown' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t2;
+
+# Bad column name
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+--error ER_GET_ERRMSG
+SELECT * FROM t2;
+DROP TABLE t2;
+
+# The remote table disappeared
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+ALTER TABLE t1 RENAME t1backup;
+--error ER_GET_ERRMSG
+SELECT * FROM t2;
+ALTER TABLE t1backup RENAME t1;
+DROP TABLE t2;
+
+
+--echo #
+--echo # Testing SELECT, etc.
+--echo #
+
+# Automatic table structure
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+
+# Explicit table structure
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+
+# Explicit table structure: remote NULL, local NOT NULL
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+
+# Explicit table structure with wrong column types
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+DROP TABLE t1;
+
+--echo #
+--echo # Testing numeric data types
+--echo #
+
+# TODO: tinyint is mapped to smallint
+#CREATE TABLE t1 (a tinyint);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: unsigned does not work
+#CREATE TABLE t1 (a tinyint unsigned);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+CREATE TABLE t1 (a smallint);
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t1;
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2, t1;
+
+CREATE TABLE t1 (a mediumint);
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t1;
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2, t1;
+
+CREATE TABLE t1 (a int);
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t1;
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2, t1;
+
+
+# TODO: bigint is mapped to double(20,0)
+CREATE TABLE t1 (a bigint);
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t1;
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2, t1;
+
+
+# TODO: ERROR 1439: Display width out of range for 'a' (max = 255)
+#CREATE TABLE t1 (a float);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: ERROR 1439: Display width out of range for 'a' (max = 255)
+#CREATE TABLE t1 (a double);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: decimal is converted to double
+#CREATE TABLE t1 (a decimal(20,5));
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: add test for BIT
+
+--echo #
+--echo # Testing character data types
+--echo #
+
+# TODO: char is mapped to varchar
+CREATE TABLE t1 (a char(10));
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t1;
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2, t1;
+
+CREATE TABLE t1 (a varchar(10));
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t1;
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2, t1;
+
+# TODO: ERROR 1105: Unsupported column type tinytext
+#CREATE TABLE t1 (a tinytext);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: ERROR 1105: Unsupported column type mediumtext
+#CREATE TABLE t1 (a mediumtext);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: text is converted to varchar(256)
+#CREATE TABLE t1 (a text);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: ERROR 1105: Unsupported column type longtext
+#CREATE TABLE t1 (a longtext);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+#TODO: add tests for ENUM
+#TODO: add tests for SET
+
+--echo #
+--echo # Testing binary data types
+--echo #
+
+# TODO: ERROR 1105: Unsupported column type binary
+#CREATE TABLE t1 (a binary(10));
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: ERROR 1105: Unsupported column type varbinary
+#CREATE TABLE t1 (a varbinary(10));
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: ERROR 1105: Unsupported column type tinyblob
+#CREATE TABLE t1 (a tinyblob);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: ERROR 1105: Unsupported column type mediumblob
+#CREATE TABLE t1 (a mediumblob);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: blob is converted to varchar(256)
+#CREATE TABLE t1 (a blob);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: ERROR 1105: Unsupported column type longblob
+#CREATE TABLE t1 (a longblob);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: ERROR 1105: Unsupported column type geometry
+#CREATE TABLE t1 (a geometry);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+--echo #
+--echo # Testing temporal data types
+--echo #
+
+# TODO: time is converted to date
+#CREATE TABLE t1 (a time);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+CREATE TABLE t1 (a date);
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+--replace_result $PORT PORT
+SHOW CREATE TABLE t1;
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2, t1;
+
+# TODO: datetime is converted to date
+#CREATE TABLE t1 (a datetime);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: timestamp is converted to date
+#CREATE TABLE t1 (a timestamp);
+#--replace_result $PORT PORT
+#--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $PORT PORT
+#SHOW CREATE TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t2, t1;
+
+# TODO: add test for YEAR
+# TODO: add tests for fractional seconds
+
+--echo #
+--echo # MDEV-4877 mysqldump dumps all data from a connect table
+--echo #
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20),(30);
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:$PORT/test/t1'
+SELECT * FROM t2;
+--echo # Start of mysqldump ------
+--replace_result $PORT PORT
+--exec $MYSQL_DUMP --compact test t2
+--echo # End of mysqldump ------
+DROP TABLE t2;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing getting unsigned types
+--echo #
+CREATE TABLE t1 (
+a TINYINT UNSIGNED NOT NULL,
+b SMALLINT ZEROFILL NOT NULL,
+c INT UNSIGNED NOT NULL,
+d BIGINT UNSIGNED NOT NULL,
+e CHAR(32) NOT NULL DEFAULT 'Hello') ENGINE=CONNECT TABLE_TYPE=FIX;
+DESCRIBE t1;
+INSERT INTO t1(a,b,c,d) VALUES(255,65535,4294967295,18446744073709551615);
+SELECT * FROM t1;
+
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME=t1;
+DESCRIBE t2;
+SELECT * FROM t2;
+
+DROP TABLE t2;
+DROP TABLE t1;
+
+#
+# MDEV-6085 ALTER TABLE looses the connection string
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (10),(20),(30);
+--replace_result $PORT PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@localhost:$PORT/test/t1'
+SELECT * FROM t2;
+ALTER TABLE t2 MODIFY a TINYINT;
+--replace_result $PORT PORT
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
diff --git a/storage/connect/mysql-test/connect/t/mysql_discovery.test b/storage/connect/mysql-test/connect/t/mysql_discovery.test
new file mode 100644
index 00000000..cd266750
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_discovery.test
@@ -0,0 +1,33 @@
+-- source myconn.inc
+
+connection slave;
+
+CREATE TABLE t1 (
+ `id` int(20) primary key,
+ `group` int NOT NULL default 1,
+ `a\\b` int NOT NULL default 2,
+ `a\\` int unsigned,
+ `name` varchar(32) default 'name')
+ DEFAULT CHARSET=latin1;
+
+connection master;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+INSERT INTO t1 (id, name) VALUES (1, 'foo');
+INSERT INTO t1 (id, name) VALUES (2, 'fee');
+--sorted_result
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+--sorted_result
+SELECT * FROM t1;
+DROP TABLE t1;
+
+-- source myconn_cleanup.inc
+
diff --git a/storage/connect/mysql-test/connect/t/mysql_exec.test b/storage/connect/mysql-test/connect/t/mysql_exec.test
new file mode 100644
index 00000000..4aad23cd
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_exec.test
@@ -0,0 +1,45 @@
+-- source myconn.inc
+
+--echo #
+--echo # Checking Sending Commands
+--echo #
+connection master;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (
+ command VARCHAR(128) NOT NULL,
+ warnings INT(4) NOT NULL FLAG=3,
+ number INT(5) NOT NULL FLAG=1,
+ message VARCHAR(255) FLAG=2)
+ ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test' OPTION_LIST='Execsrc=1,maxerr=2';
+
+SELECT * FROM t1 WHERE command IN ('Warning','Note',
+ 'drop table if exists t1',
+ 'create table t1 (id int key auto_increment, msg varchar(32) not null)',
+ "insert into t1(msg) values('One'),(NULL),('Three')",
+ "insert into t1 values(2,'Deux') on duplicate key update msg = 'Two'",
+ "insert into t1(message) values('Four'),('Five'),('Six')",
+ 'insert ignore into t1(id) values(NULL)',
+ "update t1 set msg = 'Four' where id = 4",
+ 'select * from t1');
+
+--echo #
+--echo # Checking Using Procedure
+--echo #
+DROP PROCEDURE IF EXISTS p1;
+CREATE PROCEDURE p1(cmd varchar(512))
+ READS SQL DATA
+ SELECT * FROM t1 WHERE command IN ('Warning','Note',cmd);
+
+CALL p1('insert ignore into t1(id) values(NULL)');
+CALL p1('update t1 set msg = "Five" where id = 5');
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+connection slave;
+--sorted_result
+SELECT * FROM t1;
+DROP TABLE t1;
+
+-- source myconn_cleanup.inc
+
diff --git a/storage/connect/mysql-test/connect/t/mysql_grant.test b/storage/connect/mysql-test/connect/t/mysql_grant.test
new file mode 100644
index 00000000..30737258
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_grant.test
@@ -0,0 +1,80 @@
+-- source include/not_embedded.inc
+
+let $PORT= `select @@port`;
+
+--disable_query_log
+--replace_result $PORT PORT
+--error 0,ER_UNKNOWN_ERROR
+--eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='tx1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+ AND ENGINE='CONNECT'
+ AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
+{
+ Skip Need MySQL support;
+}
+DROP TABLE t1;
+--enable_query_log
+
+--echo #
+--echo # Testing FILE privilege
+--echo #
+set sql_mode="";
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+set sql_mode=default;
+--connect(user,localhost,user,,)
+--connection user
+SELECT user();
+--replace_result $PORT PORT
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL OPTION_LIST='host=localhost,user=root1,port=$PORT'
+--connection default
+SELECT user();
+CREATE TABLE t1remote (a INT NOT NULL);
+INSERT INTO t1remote VALUES (10),(20),(30);
+--replace_result $PORT PORT
+--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=MySQL TABNAME=t1remote OPTION_LIST='host=localhost,user=root,port=$PORT'
+SELECT * FROM t1;
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES ('xxx');
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM t1 WHERE a='xxx';
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE t1 SET a='yyy' WHERE a='xxx';
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+TRUNCATE TABLE t1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+ALTER TABLE t1 READONLY=1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
+--connection default
+SELECT user();
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+--connection user
+SELECT user();
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SELECT * FROM v1;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+INSERT INTO v1 VALUES (2);
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+UPDATE v1 SET a=123;
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+DELETE FROM v1;
+
+--disconnect user
+--connection default
+SELECT user();
+DROP VIEW v1;
+DROP TABLE t1, t1remote;
+DROP USER user@localhost;
+--echo #
+--echo # Testing FILE privileges done
+--echo #
+
diff --git a/storage/connect/mysql-test/connect/t/mysql_index.test b/storage/connect/mysql-test/connect/t/mysql_index.test
new file mode 100644
index 00000000..cb4a332c
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_index.test
@@ -0,0 +1,145 @@
+-- source include/not_embedded.inc
+
+#
+# TODO: consider a possibility to run this test
+# against some remote MySQL server
+#
+
+let $PORT= `select @@port`;
+
+--disable_query_log
+--replace_result $PORT PORT
+--error 0,ER_UNKNOWN_ERROR
+--eval CREATE TABLE t1 (a INT) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='tx1' OPTION_LIST='host=localhost,user=root,port=$PORT'
+if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+ AND ENGINE='CONNECT'
+ AND CREATE_OPTIONS LIKE '%`table_type`=MySQL%'`)
+{
+ Skip Need MySQL support;
+}
+DROP TABLE t1;
+--enable_query_log
+
+--echo #
+--echo # Make remote table
+--echo #
+CREATE TABLE t1 (
+ id int(11) NOT NULL,
+ msg char(100) DEFAULT NULL,
+ PRIMARY KEY (id)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES(1,'Un'),(3,'Trois'),(5,'Cinq');
+INSERT INTO t1 VALUES(2,'Two'),(4,'Four'),(6,'Six');
+SELECT * FROM t1;
+
+--echo #
+--echo # Make local MYSQL table with indexed id column
+--echo #
+CREATE TABLE t2 (
+ id int(11) NOT NULL,
+ msg char(100) DEFAULT NULL,
+ PRIMARY KEY (id)
+) ENGINE=CONNECT DEFAULT CHARSET=latin1 TABLE_TYPE=MYSQL TABNAME=t1;
+
+--echo #
+--echo # Testing SELECT, etc.
+--echo #
+SELECT * FROM t2;
+SELECT * FROM t2 WHERE id = 3;
+SELECT * FROM t2 WHERE id IN (2,4);
+SELECT * FROM t2 WHERE id IN (2,4) AND msg = 'Two';
+SELECT * FROM t2 WHERE id > 4;
+--sorted_result
+SELECT * FROM t2 WHERE id >= 3;
+SELECT * FROM t2 WHERE id < 3;
+SELECT * FROM t2 WHERE id < 2 OR id > 4;
+SELECT * FROM t2 WHERE id <= 3;
+SELECT * FROM t2 WHERE id BETWEEN 3 AND 5;
+SELECT * FROM t2 WHERE id > 2 AND id < 6;
+SELECT * FROM t2 ORDER BY id;
+UPDATE t2 SET msg = 'Five' WHERE id = 5;
+SELECT * FROM t2;
+DELETE FROM t2 WHERE id = 4;
+SELECT * FROM t2;
+
+DROP TABLE t2;
+DROP TABLE t1;
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/emp.txt $MYSQLD_DATADIR/test/emp.txt
+
+--echo #
+--echo # Make local FIX table with indices matricule and nom/prenom
+--echo #
+CREATE TABLE t1
+(
+ matricule INT(4) KEY NOT NULL field_format='Z',
+ nom VARCHAR(16) NOT NULL,
+ prenom VARCHAR(20) NOT NULL,
+ sexe SMALLINT(1) NOT NULL COMMENT 'sexe 1:M 2:F',
+ aanais INT(4) NOT NULL,
+ mmnais INT(2) NOT NULL,
+ ddentree DATE NOT NULL date_format='YYYYMM',
+ ddnom DATE NOT NULL date_format='YYYYMM',
+ brut INT(5) NOT NULL,
+ net DOUBLE(8,2) NOT NULL,
+ service INT(2) NOT NULL,
+ sitmat CHAR(1) NOT NULL,
+ formation CHAR(5) NOT NULL,
+ INDEX NP(nom,prenom)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='emp.txt' ENDING=2;
+
+--echo #
+--echo # Make MYSQL table with same indices
+--echo #
+CREATE TABLE t2
+(
+ matricule INT(4) KEY NOT NULL,
+ nom VARCHAR(16) NOT NULL,
+ prenom VARCHAR(20) NOT NULL,
+ sexe SMALLINT(1) NOT NULL,
+ aanais INT(4) NOT NULL,
+ mmnais INT(2) NOT NULL,
+ ddentree DATE NOT NULL date_format='YYYYMM',
+ ddnom DATE NOT NULL date_format='YYYYMM',
+ brut INT(5) NOT NULL,
+ net DOUBLE(8,2) NOT NULL,
+ service INT(2) NOT NULL,
+ sitmat CHAR(1) NOT NULL,
+ formation CHAR(5) NOT NULL,
+ INDEX NP(nom,prenom)
+) ENGINE=CONNECT TABLE_TYPE=MYSQL CONNECTIOn='mysql://root@localhost/test/t1';
+SELECT * FROM t2 limit 10;
+SELECT matricule, nom, prenom FROM t2 WHERE nom IN ('FOCH','MOGADOR');
+--sorted_result
+explain SELECT matricule, nom, prenom FROM t2 WHERE nom IN ('FOCH','MOGADOR');
+SELECT matricule, nom, prenom FROM t2 WHERE nom = 'FOCH' OR nom = 'MOGADOR';
+--sorted_result
+SELECT matricule, nom, prenom FROM t2 WHERE nom < 'ADDAX';
+--sorted_result
+SELECT matricule, nom, prenom FROM t2 WHERE nom <= 'ABEL';
+--sorted_result
+SELECT matricule, nom, prenom FROM t2 WHERE nom > 'YVON';
+--sorted_result
+SELECT matricule, nom, prenom FROM t2 WHERE nom >= 'YVON';
+--sorted_result
+SELECT matricule, nom, prenom FROM t2 WHERE nom <= 'ABEL' OR nom > 'YVON';
+--sorted_result
+SELECT matricule, nom, prenom FROM t2 WHERE nom > 'HELEN' AND nom < 'HEROS';
+--sorted_result
+SELECT matricule, nom, prenom FROM t2 WHERE nom BETWEEN 'HELEN' AND 'HEROS';
+--sorted_result
+SELECT matricule, nom, prenom FROM t2 WHERE nom BETWEEN 'HELEN' AND 'HEROS' AND prenom = 'PHILIPPE';
+SELECT matricule, nom, prenom FROM t2 ORDER BY nom,prenom LIMIT 10;
+--sorted_result
+SELECT a.nom, a.prenom, b.nom FROM t1 a STRAIGHT_JOIN t2 b ON a.prenom = b.prenom WHERE a.nom = 'FOCH' AND a.nom != b.nom;
+
+DROP TABLE t2;
+DROP TABLE t1;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/emp.txt
+--remove_file $MYSQLD_DATADIR/test/emp.fnx
diff --git a/storage/connect/mysql-test/connect/t/mysql_new.test b/storage/connect/mysql-test/connect/t/mysql_new.test
new file mode 100644
index 00000000..db9b1b70
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/mysql_new.test
@@ -0,0 +1,325 @@
+-- source myconn.inc
+
+#
+# This test is run against a remote MySQL server
+#
+
+connection slave;
+
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (NULL,NULL),(0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+
+--echo #
+--echo # Testing errors
+--echo #
+connection master;
+
+# Bad user name
+# Suppress "mysql_real_connect failed:" (printed in _DEBUG build)
+--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://unknown@127.0.0.1:$SLAVE_MYPORT/test/t1';
+
+# Bad database name
+--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/unknown/t1';
+
+# Bad database name, with OPTION_LIST going first.
+--replace_result $SLAVE_MYPORT SLAVE_PORT "mysql_real_connect failed: " ""
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT' DBNAME='unknown' TABNAME='t1';
+
+# Bad table name
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+--error ER_UNKNOWN_ERROR
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/unknown';
+--error ER_NO_SUCH_TABLE
+SHOW CREATE TABLE t1;
+
+# Bad column name
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (x int, y char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# The remote table disappeared
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+
+connection slave;
+ALTER TABLE t1 RENAME t1backup;
+
+connection master;
+--error ER_GET_ERRMSG
+SELECT * FROM t1;
+
+connection slave;
+ALTER TABLE t1backup RENAME t1;
+
+connection master;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing SELECT, etc.
+--echo #
+
+# Automatic table structure
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a int, b char(10)) ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1'
+ OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure: remote NULL, local NOT NULL
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a INT NOT NULL, b CHAR(10) NOT NULL) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+# Explicit table structure with wrong column types
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 (a char(10), b int) ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing numeric data types
+--echo #
+
+# TODO: mediumint is converted to int, float is converted to double, decimal is converted to double
+CREATE TABLE t1 (a tinyint, b smallint, c mediumint, d int, e bigint, f float, g double, h decimal(20,5));
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES(100,3333,41235,1234567890,235000000000,3.14159265,3.14159265,3141.59265);
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+# TODO: unsigned does not work
+#CREATE TABLE t1 (a tinyint unsigned);
+#SHOW CREATE TABLE t1;
+
+#connection master;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT';
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1;
+
+#connection slave;
+#DROP TABLE t1;
+
+# TODO: add test for BIT
+
+--echo #
+--echo # Testing character data types
+--echo #
+
+CREATE TABLE t1 (a char(12), b varchar(12));
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES('Welcome','Hello, World');
+SELECT * FROM t1;
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+# TODO: ERROR 1105: Unsupported column type tinytext
+#CREATE TABLE t1 (a tinytext);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type mediumtext
+#CREATE TABLE t1 (a mediumtext);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: text is converted to varchar(256)
+#CREATE TABLE t1 (a text);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type longtext
+#CREATE TABLE t1 (a longtext);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+#TODO: add tests for ENUM
+#TODO: add tests for SET
+
+#--echo #
+#--echo # Testing binary data types
+#--echo #
+
+# TODO: ERROR 1105: Unsupported column type binary
+#CREATE TABLE t1 (a binary(10));
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type varbinary
+#CREATE TABLE t1 (a varbinary(10));
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type tinyblob
+#CREATE TABLE t1 (a tinyblob);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type mediumblob
+#CREATE TABLE t1 (a mediumblob);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: blob is converted to varchar(256)
+#CREATE TABLE t1 (a blob);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type longblob
+#CREATE TABLE t1 (a longblob);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+# TODO: ERROR 1105: Unsupported column type geometry
+#CREATE TABLE t1 (a geometry);
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='t1' OPTION_LIST='host=127.0.0.1,user=root,port=$SLAVE_MYPORT'
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#--replace_result $SLAVE_MYPORT SLAVE_PORT
+#SHOW CREATE TABLE t1;
+#SELECT * FROM t1;
+#DROP TABLE t1, t1;
+
+--echo #
+--echo # Testing temporal data types
+--echo #
+
+CREATE TABLE t1 (a date, b datetime, c time, d timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, e year);
+SHOW CREATE TABLE t1;
+INSERT IGNORE INTO t1 VALUES('2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23','2003-05-27 10:45:23');
+SELECT * FROM t1;
+
+connection master;
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL
+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT';
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+connection slave;
+DROP TABLE t1;
+
+-- source myconn_cleanup.inc
+
diff --git a/storage/connect/mysql-test/connect/t/null.test b/storage/connect/mysql-test/connect/t/null.test
new file mode 100644
index 00000000..d2c78414
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/null.test
@@ -0,0 +1,87 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # Testing FIX null columns
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL,
+ nb INT,
+ msg VARCHAR(12)
+) ENGINE=CONNECT TABLE_TYPE=FIX;
+--error ER_BAD_NULL_ERROR
+INSERT INTO t1 values(NULL,1,'Hello');
+INSERT INTO t1 values(10,4,NULL),(20,2,'Hello'),(0,0,'Zero');
+SELECT * FROM t1;
+SELECT* FROM t1 WHERE id IS NULL;
+SELECT * FROM t1 WHERE nb IS NULL;
+SELECT * FROM t1 WHERE msg IS NOT NULL;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing CSV null columns
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL,
+ nb INT,
+ msg VARCHAR(12)
+) ENGINE=CONNECT TABLE_TYPE=CSV HEADER=1;
+--error ER_BAD_NULL_ERROR
+INSERT INTO t1 values(NULL,1,'Hello');
+INSERT INTO t1 values(10,4,NULL),(20,2,'Hello'),(0,0,'Zero');
+SELECT * FROM t1;
+SELECT* FROM t1 WHERE id IS NULL;
+SELECT * FROM t1 WHERE nb IS NULL;
+SELECT * FROM t1 WHERE msg IS NOT NULL;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing BIN null columns
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL,
+ nb INT,
+ msg VARCHAR(12)
+) ENGINE=CONNECT TABLE_TYPE=BIN;
+--error ER_BAD_NULL_ERROR
+INSERT INTO t1 values(NULL,1,'Hello');
+INSERT INTO t1 values(10,4,NULL),(20,2,'Hello'),(0,0,'Zero');
+SELECT * FROM t1;
+SELECT* FROM t1 WHERE id IS NULL;
+SELECT * FROM t1 WHERE nb IS NULL;
+SELECT * FROM t1 WHERE msg IS NOT NULL;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing DBF null columns
+--echo #
+CREATE TABLE t1
+(
+ id INT NOT NULL,
+ nb INT,
+ msg VARCHAR(12)
+) ENGINE=CONNECT TABLE_TYPE=DBF;
+--error ER_BAD_NULL_ERROR
+INSERT INTO t1 values(NULL,1,'Hello');
+INSERT INTO t1 values(10,4,NULL),(20,2,'Hello'),(0,0,'Zero');
+SELECT * FROM t1;
+SELECT* FROM t1 WHERE id IS NULL;
+SELECT * FROM t1 WHERE nb IS NULL;
+SELECT * FROM t1 WHERE msg IS NOT NULL;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing INI null columns
+--echo #
+CREATE TABLE t1
+(
+ `sec` char(8) NOT NULL flag=1,
+ `key` char(12)
+) ENGINE=CONNECT TABLE_TYPE=INI;
+INSERT INTO t1(sec) values('S1');
+SELECT * FROM t1;
+INSERT INTO t1 values('S1','Newval');
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/occur.test b/storage/connect/mysql-test/connect/t/occur.test
new file mode 100644
index 00000000..7d7bca87
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/occur.test
@@ -0,0 +1,61 @@
+-- source include/not_embedded.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $PORT= `select @@port`;
+--copy_file $MTR_SUITE_DIR/std_data/employee.dat $MYSQLD_DATADIR/test/employee.dat
+
+CREATE TABLE employee (
+serialno CHAR(5) NOT NULL,
+name VARCHAR(12) NOT NULL FLAG=6,
+sex TINYINT(1) NOT NULL,
+title VARCHAR(15) NOT NULL FLAG=20,
+manager CHAR(5) DEFAULT NULL,
+department CHAR(4) NOT NULL FLAG=41,
+secretary CHAR(5) DEFAULT NULL FLAG=46,
+salary DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=connect TABLE_TYPE=fix FILE_NAME='employee.dat' ENDING=1;
+SELECT * FROM employee;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE occurs (name CHAR(12), sex CHAR(1), title CHAR(15), department CHAR(4), salary DOUBLE(8,2), id_of CHAR(12), id CHAR(5) NOT NULL) ENGINE=CONNECT TABLE_TYPE=OCCUR TABNAME=employee OPTION_LIST='OccurCol=ID,RankCol=ID_OF,Colist=serialno;manager;secretary,port=$PORT';
+SELECT * FROM occurs;
+
+DROP TABLE occurs;
+DROP TABLE employee;
+
+CREATE TABLE pets (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0,
+cat INT NOT NULL DEFAULT 0,
+rabbit INT NOT NULL DEFAULT 0,
+bird INT NOT NULL DEFAULT 0,
+fish INT NOT NULL DEFAULT 0) ENGINE=MYISAM;
+INSERT INTO pets(name,dog) VALUES('John',2);
+INSERT INTO pets(name,cat) VALUES('Bill',1);
+INSERT INTO pets(name,dog,cat) VALUES('Mary',1,1);
+INSERT INTO pets(name,rabbit) VALUES('Lisbeth',2);
+INSERT INTO pets(name,cat,bird) VALUES('Kevin',2,6);
+INSERT INTO pets(name,dog,fish) VALUES('Donald',1,3);
+SELECT * FROM pets;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE xpet (name VARCHAR(12) NOT NULL, race CHAR(6) NOT NULL, number INT) ENGINE=CONNECT TABLE_TYPE=OCCUR TABNAME=pets OPTION_LIST='OccurCol=number,RankCol=race,Colist=dog;cat;rabbit;bird;fish,port=$PORT'
+
+SELECT * FROM xpet;
+SELECT name FROM xpet;
+SELECT name FROM xpet WHERE race = 'cat' AND number = 0;
+SELECT name, SUM(number) pets FROM xpet GROUP BY name;
+
+ALTER TABLE xpet MODIFY number INT NOT NULL;
+
+SELECT * FROM xpet;
+SELECT * FROM xpet WHERE number > 1;
+SELECT DISTINCT name FROM xpet WHERE number > 1;
+SELECT name FROM xpet;
+SELECT name, race FROM xpet;
+SELECT name, count(*) FROM xpet GROUP BY name, LEAST(number,1);
+SELECT name, number, count(*) FROM xpet GROUP BY name, number;
+
+DROP TABLE xpet;
+DROP TABLE pets;
+--remove_file $MYSQLD_DATADIR/test/employee.dat
diff --git a/storage/connect/mysql-test/connect/t/odbc.test b/storage/connect/mysql-test/connect/t/odbc.test
new file mode 100644
index 00000000..fc297040
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc.test
@@ -0,0 +1,25 @@
+--source have_odbc.inc
+
+SET NAMES utf8;
+
+# MS ODBC and unixODBC return different error message text,
+# so disable displaying error messages
+--disable_result_log ONCE
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Bad connection string';
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Tables CONNECTION='Not important';
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Columns CONNECTION='Not important';
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/odbc_firebird.test b/storage/connect/mysql-test/connect/t/odbc_firebird.test
new file mode 100644
index 00000000..c9279eec
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc_firebird.test
@@ -0,0 +1,35 @@
+--source have_odbc.inc
+
+SET NAMES utf8;
+
+# MS ODBC and unixODBC return different error message text,
+# so disable displaying error messages
+--disable_result_log ONCE
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Bad connection string';
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+if (`select count(*)=0 from t1 where name='firebird'`) {
+ DROP TABLE t1;
+ skip No Firebird;
+}
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Tables CONNECTION='Not important';
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Columns CONNECTION='Not important';
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC TABNAME='EMPLOYEE' CONNECTION='DSN=Firebird;UID=SYSDBA;PWD=masterkey';
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/odbc_oracle.sql b/storage/connect/mysql-test/connect/t/odbc_oracle.sql
new file mode 100644
index 00000000..50ba824b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc_oracle.sql
@@ -0,0 +1,16 @@
+DROP USER mtr CASCADE;
+CREATE USER mtr IDENTIFIED BY mtr
+DEFAULT TABLESPACE users
+TEMPORARY TABLESPACE temp;
+GRANT CREATE SESSION TO mtr;
+GRANT CREATE TABLE TO mtr;
+GRANT CREATE VIEW TO mtr;
+ALTER USER mtr QUOTA UNLIMITED ON USERS;
+CONNECT mtr/mtr;
+CREATE TABLE t1 (a INT,b NUMBER);
+INSERT INTO t1 VALUES (10,1000*1000*1000);
+INSERT INTO t1 VALUES (20,1000*1000*1000*1000);
+INSERT INTO t1 VALUES (30,1000*1000*1000*1000*1000);
+CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE TABLE t2 (a VARCHAR(64));
+INSERT INTO t2 VALUES ('test');
diff --git a/storage/connect/mysql-test/connect/t/odbc_oracle.test b/storage/connect/mysql-test/connect/t/odbc_oracle.test
new file mode 100644
index 00000000..2a6eb5b7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc_oracle.test
@@ -0,0 +1,230 @@
+--source have_odbc_oracle.inc
+
+#
+# To configure your system to be able to run this test,
+# follow through the following steps:
+#
+# 1. Install and configure Oracle database to start on the system startup.
+#
+# 2. Create user, database, schema and tables to be used by mtr:
+# sqlplus system/manager < odbc_oracle.sql
+#
+# 3. Configure Oracle ODBC Driver for unixODBC (skip this step on Windows):
+# Add these lines into /etc/odbcinst.ini:
+# (the exact paths can vary)
+#
+#[Oracle11g]
+#Description=Oracle ODBC driver for Oracle 11g
+#Driver=/u01/app/oracle/product/11.2.0/xe/lib/libsqora.so.11.1
+#Setup=
+#FileUsage=
+#CPTimeout=
+#CPReuse=
+#
+# 4. Create a data source with the name "ConnectEngineOracle"
+# - On Windows: use odbcadm.exe
+# - On Linux: put these lines into /etc/odbc.ini
+#
+#[ConnectEngineOracle]
+#Application Attributes=T
+#Attributes=W
+#BatchAutocommitMode=IfAllSuccessful
+#CloseCursor=F
+#DisableDPM=F
+#DisableMTS=T
+#Driver=Oracle11g
+#DSN=ConnectEngineOracle
+#EXECSchemaOpt=
+#EXECSyntax=T
+#Failover=T
+#FailoverDelay=10
+#FailoverRetryCount=10
+#FetchBufferSize=64000
+#ForceWCHAR=F
+#Lobs=T
+#Longs=T
+#MetadataIdDefault=F
+#QueryTimeout=T
+#ResultSets=T
+#ServerName=
+#SQLGetData extensions=F
+#Translation DLL=
+#Translation Option=0
+#UserID=
+
+
+SET NAMES utf8;
+
+#
+# Oracle does not support the third (catalog) level
+# in SQLTables() and SQLColumns(), e.g.: CATFUNC=Tables TABNAME='%.%.%'.
+# It returns a "Driver not capable" error on attept to use non-NULL catalog.
+#
+# But it works fine with the second (schema) level:
+# CATFUNC=Tables TABNAME='%.%'
+# Note, if schema level is not specified, or schema level is '%',
+# tables for *all* schemas are returned
+# (not only for the schema associated with the user.
+#
+# Note, schema and table names must be in upper case.
+#
+
+
+
+--echo #
+--echo # Checking CATFUNC=Tables
+--echo #
+--echo
+
+--echo # All tables in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables;
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='%.%';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables "T1" in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='%.T1';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables "T1" in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='T1';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # Table "T1" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='MTR.T1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Tables TABNAME='MTR.%';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Checking CATFUNC=Columns
+--echo #
+--echo
+
+
+--echo # All columns in all schemas (limited with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Columns;
+# Disable warnings to avoid "Result limited to 20000 lines"
+--disable_warnings
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+--enable_warnings
+DROP TABLE t1;
+
+--echo # All columns in all schemas (limited with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Columns TABNAME='%.%';
+# Disable warnings to avoid "Result limited to 20000 lines"
+--disable_warnings
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+--enable_warnings
+DROP TABLE t1;
+
+--echo # All tables "T1" in all schemas (limited with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew' CATFUNC=Columns TABNAME='%.T1';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # Table "T1" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Columns TABNAME='MTR.T1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables "T1" in all schemas (filtered with WHERE)
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+CATFUNC=Columns TABNAME='%.T1';
+SELECT * FROM t1 WHERE Table_Schema='MTR' ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Checking tables
+--echo #
+--echo
+
+--echo # Table "T1" in the default schema ("MTR")
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+TABNAME='T1';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1 ORDER BY A;
+
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo # Table "T1" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+TABNAME='MTR.T1';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo # View "V1" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+TABNAME='MTR.V1';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo # Table "T2" in the schema "MTR"
+CREATE TABLE t1 ENGINE=CONNECT
+TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineOracle;UID=mtr;PWD=mtrnew'
+TABNAME='MTR.T2';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/odbc_postgresql.sql b/storage/connect/mysql-test/connect/t/odbc_postgresql.sql
new file mode 100644
index 00000000..1c302294
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc_postgresql.sql
@@ -0,0 +1,27 @@
+--
+-- The SQL script to create PostgreSQL data for odbc_postgresql.test
+--
+-- Run this script as a admin user:
+-- psql -U postgres < odbc_postgresql.sql
+
+SET NAMES 'UTF8';
+
+DROP DATABASE IF EXISTS mtr;
+DROP USER IF EXISTS mtr;
+
+CREATE USER mtr WITH PASSWORD 'mtr';
+CREATE DATABASE mtr OWNER=mtr ENCODING='UTF8';
+GRANT ALL ON DATABASE mtr TO mtr;
+\c mtr
+SET role mtr;
+CREATE TABLE t1 (a INT NOT NULL);
+INSERT INTO t1 VALUES (10),(20),(30);
+CREATE VIEW v1 AS SELECT * FROM t1;
+CREATE TABLE t2 (a INT NOT NULL);
+INSERT INTO t2 VALUES (40),(50),(60);
+CREATE SCHEMA schema1 AUTHORIZATION mtr;
+CREATE TABLE schema1.t1 (a CHAR(10) NOT NULL);
+INSERT INTO schema1.t1 VALUES ('aaa'),('bbb'),('ccc'),('ÑÑÑ');
+CREATE VIEW schema1.v1 AS SELECT * FROM schema1.t1;
+CREATE TABLE schema1.t2 (a CHAR(10) NOT NULL);
+INSERT INTO schema1.t2 VALUES ('xxx'),('yyy'),('zzz'),('ÄÖÜ');
diff --git a/storage/connect/mysql-test/connect/t/odbc_postgresql.test b/storage/connect/mysql-test/connect/t/odbc_postgresql.test
new file mode 100644
index 00000000..7fc16130
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc_postgresql.test
@@ -0,0 +1,207 @@
+--source have_odbc_postgresql.inc
+#--source include/not_embedded.inc
+
+#
+# To configure your system to be able to run this test,
+# follow through the following steps:
+#
+# 1. Install and configure PostgreSQL database to stat on the system startup
+#
+# 2. Create user, database, schema and tables to be used by mtr:
+# psql -U postgres < odbc_postgresql.sql
+#
+# 3. Install PostgreSQL ODBC Driver.
+# - On CentOS, Fedora:
+# sudo yum install postgresql-odbc
+# - On Ubuntu, Debian:
+# sudo apt-get install odbc-postgresql
+#
+# 4. Create a data source with the name "ConnectEnginePostgresql"
+# - On Windows: use odbcadm.exe
+# - On Linux: put these lines into /etc/odbc.ini
+#
+#[ConnectEnginePostgresql]
+#Description=PostgreSQL DSN for ConnectSE
+#Driver=PostgreSQL (should the path to the driver so file)
+#Database=mtr
+#Servername=localhost
+#Port=5432
+#
+# 5. Allow user "mtr" to connect to the database "mtr"
+# Add this line into the begginning of pg_hba.conf
+# (usually /var/lib/pgsql/data/pg_hba.conf on Linux):
+#host mtr mtr 127.0.0.1/32 password
+#
+# 6. Restart the server:
+# sudo service postgresql restart
+#
+#
+
+SET NAMES utf8;
+
+--echo #
+--echo # Checking CATFUNC=Tables
+--echo #
+--echo
+--echo # All tables in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables;
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.%.%';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.%';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables in the default schema ("public")
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables "t1" in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables "t1" in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # Table "t1" in the default schema ("public")
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # Table "t1" in the schema "public"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.public.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # Table "t1" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='%.schema1.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables "t1" in all schemas (Catalog name is ignored by PostgreSQL)
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Tables TABNAME='xxx.%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo #
+--echo # Checking CATFUNC=Columns
+--echo #
+--echo
+
+#
+# For some reasons SQLColumn (unlike SQLTables) include columns of system
+# tables from the schemas like "information_schema", "pg_catalog", "pg_toast".
+# So we add the "Table_Schema IN ('public','schema1')" clause into some queries.
+#
+
+--echo # All columns in the schemas "public" and "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns;
+SELECT * FROM t1 WHERE Table_Schema IN ('public','schema1') ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All columns in the schemas "public" and "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.%.%';
+SELECT * FROM t1 WHERE Table_Schema IN ('public','schema1') ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables "t1" in all schemas
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # Table "t1" in the schema "public"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.public.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # Table "t1" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='%.schema1.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+--echo # All tables "t1" in all schemas (Catalog name is ignored by PostgreSQL)
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' CATFUNC=Columns TABNAME='xxx.%.t1';
+SELECT * FROM t1 ORDER BY Table_Schema, Table_Name;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Checking tables
+--echo #
+--echo
+
+--echo # Table "t1" in the default schema ("public")
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo # Table "t1" in the schema "public"
+CREATE TABLE t1 ENGINE=CONNECT TABNAME='public.t1' TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo # Table "t1" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABNAME='schema1.t1' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo # View "v1" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABNAME='schema1.v1' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo # Table "t2" in the schema "schema1"
+CREATE TABLE t1 ENGINE=CONNECT TABNAME='schema1.t2' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr';
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+DROP VIEW v1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/odbc_sqlite3.test b/storage/connect/mysql-test/connect/t/odbc_sqlite3.test
new file mode 100644
index 00000000..a22fa3a7
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc_sqlite3.test
@@ -0,0 +1,90 @@
+--source have_odbc_sqlite3.inc
+
+#
+# To run this test, install SQLite3 ODBC Driver from
+# http://www.ch-werner.de/sqliteodbc/
+#
+# Note, the test does not need a DSN to be created
+# (only the driver is required)
+#
+#
+# On Windows:
+# -----------
+# Download and run the installer file sqliteodbc.exe
+# Version sqliteodbc-0.991 is known to Work.
+# After running the installer the test should start working automatically.
+#
+# On Linux:
+# --------
+# 1. Download the source tarball, e.g.: sqliteodbc-0.993.tar.gz
+# 2. Unpack the sources:
+# tar -zxf sqliteodbc-0.993.tar.gz
+# 3. Compile the source and install:
+# cd sqliteodbc-0.993
+# ./configure --prefix=/opt/sqliteodbc
+# make
+# sudo make install
+#
+# (you can use a different --prefix, according to your preferences)
+#
+# 4. Add these lines into /etc/odbcinst.ini
+#
+#[SQLite3 ODBC Driver]
+#Description=SQLite3 ODBC Driver
+#Driver=/opt/sqliteodbc/libsqlite3odbc.so
+#Setup=/opt/sqliteodbc/libsqlite3odbc.so
+#
+# Adjust the directory "/opt/sqliteodbc/" according to --prefix
+# that you chose on step #3.
+#
+#
+
+SET NAMES utf8;
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+
+#
+# For some reasons Windows does not allow to remove the data base
+# file after "DROP TABLE t1". So unlike in odbc_xls.test we won't copy
+# the data file, we'll use directly the file in std_data.
+# As we do not do any modifications in the database, this should be OK.
+#
+let $Database=$MTR_SUITE_DIR/std_data/test.sqlite3;
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+CREATE VIEW v1 AS SELECT * FROM t1;
+SELECT * FROM v1;
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABNAME='t1' TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8
+SELECT * FROM t1 ORDER BY Table_name;
+DROP TABLE t1;
+
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8
+SELECT * FROM t1 ORDER BY Table_name;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test b/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test
new file mode 100644
index 00000000..887385af
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc_sqlite3_grant.test
@@ -0,0 +1,91 @@
+-- source include/not_embedded.inc
+-- source have_odbc_sqlite3.inc
+
+#
+# For the instructions on how to setup SQLite3 ODBC DSN,
+# please see odbc_sqlite3.test
+#
+
+SET NAMES utf8;
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+
+GRANT ALL PRIVILEGES ON *.* TO user@localhost;
+REVOKE FILE ON *.* FROM user@localhost;
+--connect(user,localhost,user,,)
+--connection user
+SELECT user();
+--error ER_ACCESS_DENIED_ERROR
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC;
+--error ER_ACCESS_DENIED_ERROR
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Drivers;
+--error ER_ACCESS_DENIED_ERROR
+CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+--connection default
+SELECT user();
+
+
+#
+# For some reasons Windows does not allow to remove the data base
+# file after "DROP TABLE t1". So unlike in odbc_xls.test we won't copy
+# the data file, we'll use directly the file in std_data.
+# As we do not do any modifications in the database, this should be OK.
+#
+let $Database=$MTR_SUITE_DIR/std_data/test.sqlite3;
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='Driver=SQLite3 ODBC Driver;Database=$Database;NoWCHAR=yes' CHARSET=utf8 DATA_CHARSET=utf8;
+--replace_result $MTR_SUITE_DIR MTR_SUITE_DIR
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+--connection user
+SELECT user();
+--error ER_ACCESS_DENIED_ERROR
+SELECT * FROM t1;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO t1 VALUES ('xxx');
+--error ER_ACCESS_DENIED_ERROR
+DELETE FROM t1 WHERE a='xxx';
+--error ER_ACCESS_DENIED_ERROR
+UPDATE t1 SET a='yyy' WHERE a='xxx';
+--error ER_ACCESS_DENIED_ERROR
+TRUNCATE TABLE t1;
+--error ER_ACCESS_DENIED_ERROR
+ALTER TABLE t1 READONLY=1;
+--error ER_ACCESS_DENIED_ERROR
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
+--echo # using SQL SECIRITY INVOKER
+--connection default
+SELECT user();
+CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT * FROM t1;
+--connection user
+SELECT user();
+--error ER_ACCESS_DENIED_ERROR
+SELECT * FROM v1;
+--error ER_ACCESS_DENIED_ERROR
+INSERT INTO v1 VALUES (2);
+--error ER_ACCESS_DENIED_ERROR
+UPDATE v1 SET a=123;
+--error ER_ACCESS_DENIED_ERROR
+DELETE FROM v1;
+
+--echo # Testing a VIEW created with FILE privileges but accessed with no FILE
+--echo # using SQL SECIRITY DEFINER
+--connection default
+DROP VIEW v1;
+SELECT user();
+CREATE SQL SECURITY DEFINER VIEW v1 AS SELECT * FROM t1;
+--connection user
+SELECT user();
+SELECT * FROM v1 WHERE a='test1';
+
+
+--disconnect user
+--connection default
+SELECT user();
+DROP VIEW v1;
+DROP TABLE t1;
+
+DROP USER user@localhost;
diff --git a/storage/connect/mysql-test/connect/t/odbc_xls.test b/storage/connect/mysql-test/connect/t/odbc_xls.test
new file mode 100644
index 00000000..1ae1382b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/odbc_xls.test
@@ -0,0 +1,39 @@
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=ODBC CATFUNC=Sources;
+if ($mysql_errno)
+{
+ Skip No ODBC support;
+}
+if (!`SELECT count(*) FROM t1 WHERE Name='ConnectEngineXLS'`)
+{
+ DROP TABLE t1;
+ Skip Need ODBC data source ConnectEngineXLS;
+}
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+--enable_query_log
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/contacts.xls $MYSQLD_DATADIR/test/contacts.xls
+
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval CREATE TABLE contact (Nom VARCHAR(128), Fonction VARCHAR(128), Company VARCHAR(128), Repertoire VARCHAR(30)) ENGINE=CONNECT TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=$MYSQLD_DATADIR/test/contacts.xls';
+SELECT Nom, Fonction FROM contact WHERE Repertoire='ascii';
+DROP TABLE contact;
+
+
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Tables TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=$MYSQLD_DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;
+--replace_result $MYSQLD_DATADIR DATADIR
+SELECT * FROM t1 WHERE Table_name='CONTACT';
+DROP TABLE t1;
+
+--replace_result $MYSQLD_DATADIR DATADIR
+--eval CREATE TABLE t1 ENGINE=CONNECT CATFUNC=Columns TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEngineXLS;DBQ=$MYSQLD_DATADIR/test/contacts.xls' CHARSET=utf8 DATA_CHARSET=latin1;
+--replace_result $MYSQLD_DATADIR DATADIR
+SELECT * FROM t1 WHERE Table_name='CONTACT' AND Column_name IN ('Nom','Fonction');
+DROP TABLE t1;
+
+--remove_file $MYSQLD_DATADIR/test/contacts.xls
diff --git a/storage/connect/mysql-test/connect/t/part_file.test b/storage/connect/mysql-test/connect/t/part_file.test
new file mode 100644
index 00000000..2e5127f0
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/part_file.test
@@ -0,0 +1,166 @@
+--source include/have_partition.inc
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+set @@global.connect_exact_info=ON;
+
+--echo # This will be used to see what data files are created
+CREATE TABLE dr1 (
+ fname VARCHAR(256) NOT NULL FLAG=2,
+ ftype CHAR(8) NOT NULL FLAG=3
+# ,FSIZE INT(6) NOT NULL FLAG=5 removed because Unix size != Windows size
+) engine=CONNECT table_type=DIR file_name='t1#P#*.*';
+
+--echo #
+--echo # Testing partitioning on inward table
+--echo #
+CREATE TABLE t1 (
+ id INT NOT NULL,
+ msg VARCHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=CSV AVG_ROW_LENGTH=10
+PARTITION BY RANGE(id) (
+PARTITION first VALUES LESS THAN(10),
+PARTITION middle VALUES LESS THAN(50),
+PARTITION last VALUES LESS THAN(MAXVALUE));
+INSERT INTO t1 VALUES(4, 'four'),(24, 'twenty four');
+INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one');
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM t1;
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id > 50;
+SELECT * FROM t1 WHERE id > 50;
+#TODO: Differences between Linux and Windows
+#SHOW TABLE STATUS LIKE 't1';
+--error ER_GET_ERRMSG
+UPDATE t1 set id = 41 WHERE msg = 'four';
+UPDATE t1 set msg = 'quatre' WHERE id = 4;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+--echo #
+--echo # Altering partitioning on inward table
+--echo #
+ALTER TABLE t1
+PARTITION by range(id) (
+PARTITION first VALUES LESS THAN(11),
+PARTITION middle VALUES LESS THAN(50),
+PARTITION last VALUES LESS THAN(MAXVALUE));
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM dr1 ORDER BY fname, ftype;
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id=10;
+SELECT * FROM t1 WHERE id=10;
+DELETE FROM t1 WHERE id in (4,60);
+SELECT * FROM t1;
+DROP TABLE t1;
+# TODO: this fails on Linux
+#SELECT * FROM dr1;
+
+--echo #
+--echo # Testing partitioning on a void outward table
+--echo #
+ALTER TABLE dr1 FILE_NAME='part*.*';
+CREATE TABLE t1 (
+ rwid INT(6) DEFAULT 0 SPECIAL=ROWID,
+ rnum INT(6) DEFAULT 0 SPECIAL=ROWNUM,
+ prtn VARCHAR(64) DEFAULT '' SPECIAL=PARTID,
+ tbn VARCHAR(64) DEFAULT '' SPECIAL=TABID,
+ fid VARCHAR(256) DEFAULT '' SPECIAL=FNAME,
+ id INT KEY NOT NULL,
+ msg VARCHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='part%s.txt';
+--replace_result $MYSQLD_DATADIR "DATADIR/"
+ALTER TABLE t1
+PARTITION by range columns(id) (
+PARTITION `1` VALUES LESS THAN(10),
+PARTITION `2` VALUES LESS THAN(50),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+SHOW INDEX FROM t1;
+# TODO: this fails on Linux
+#SELECT * FROM dr1 ORDER BY fname, ftype;
+INSERT INTO t1(id,msg) VALUES(4, 'four');
+SELECT * FROM dr1 ORDER BY fname, ftype;
+INSERT INTO t1(id,msg) VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one');
+INSERT INTO t1(id,msg) VALUES(72,'seventy two'),(20,'twenty'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM t1;
+SELECT * FROM t1 order by id;
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10;
+SELECT * FROM t1 WHERE id = 10;
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id >= 40;
+SELECT * FROM t1 WHERE id >= 40;
+SELECT count(*) FROM t1 WHERE id < 10;
+SELECT case when id < 10 then 1 when id < 50 then 2 else 3 end as pn, count(*) FROM t1 group by pn;
+SELECT prtn, count(*) FROM t1 group by prtn;
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id > 50;
+SELECT * FROM t1 WHERE id = 35;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+--echo # This does not change the partition file data and is WRONG
+ALTER TABLE t1
+PARTITION by range columns(id) (
+PARTITION `1` VALUES LESS THAN(11),
+PARTITION `2` VALUES LESS THAN(70),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+SELECT CASE WHEN id < 11 THEN 1 WHEN id < 70 THEN 2 ELSE 3 END AS pn, COUNT(*) FROM t1 GROUP BY pn;
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM dr1 ORDER BY fname, ftype;
+--echo #
+--echo # This is the correct way to change partitioning:
+--echo # Save table values, erase the table, then re-insert saved values in modified table
+--echo #
+CREATE TABLE t2 (
+ id INT NOT NULL,
+ msg VARCHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=FIX;
+INSERT INTO t2 SELECT id, msg FROM t1;
+DELETE FROM t1;
+INSERT INTO t1(id,msg) SELECT * FROM t2;
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM t1;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+DROP TABLE t2;
+DROP TABLE t1;
+
+--echo #
+--echo # Testing partitioning on a populated outward table
+--echo #
+CREATE TABLE t1 (
+ id INT NOT NULL,
+ msg VARCHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='part%s.txt'
+PARTITION by range columns(id) (
+PARTITION `1` VALUES LESS THAN(11),
+PARTITION `2` VALUES LESS THAN(70),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM t1 WHERE id < 11;
+SELECT * FROM t1 WHERE id >= 70;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+
+--echo #
+--echo # Testing indexing on a partitioned table
+--echo #
+CREATE INDEX XID ON t1(id);
+SHOW INDEX FROM t1;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10;
+DROP INDEX XID ON t1;
+SHOW INDEX FROM t1;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+ALTER TABLE t1 ADD PRIMARY KEY (id);
+SHOW INDEX FROM t1;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 10;
+ALTER TABLE t1 DROP PRIMARY KEY;
+SHOW INDEX FROM t1;
+SELECT * FROM dr1 ORDER BY fname, ftype;
+DROP TABLE t1;
+DROP TABLE dr1;
+
+#
+# Clean up
+#
+set @@global.connect_exact_info=OFF;
+
+--remove_file $MYSQLD_DATADIR/test/part1.txt
+--remove_file $MYSQLD_DATADIR/test/part2.txt
+--remove_file $MYSQLD_DATADIR/test/part3.txt
+#--remove_file $MYSQLD_DATADIR/test/part%s.fnx
+#--remove_file $MYSQLD_DATADIR/test/part1.fnx
+#--remove_file $MYSQLD_DATADIR/test/part2.fnx
+#--remove_file $MYSQLD_DATADIR/test/part3.fnx
diff --git a/storage/connect/mysql-test/connect/t/part_table.test b/storage/connect/mysql-test/connect/t/part_table.test
new file mode 100644
index 00000000..0fb2a11f
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/part_table.test
@@ -0,0 +1,107 @@
+--source include/not_embedded.inc
+--source include/have_partition.inc
+
+set @@global.connect_exact_info=ON;
+
+#
+# These will be used by the t1 table partition table
+#
+CREATE TABLE xt1 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=MyISAM;
+INSERT INTO xt1 VALUES(4, 'four'),(7,'seven'),(1,'one'),(8,'eight');
+SELECT * FROM xt1;
+
+CREATE TABLE xt2 (
+id INT KEY NOT NULL,
+msg VARCHAR(32));
+INSERT INTO xt2 VALUES(10,'ten'),(40,'forty'),(11,'eleven'),(35,'thirty five');
+SELECT * FROM xt2;
+
+CREATE TABLE xt3 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=CSV AVG_ROW_LENGTH=6;
+INSERT INTO xt3 VALUES(60,'sixty'),(81,'eighty one'),(72,'seventy two');
+SELECT * FROM xt3;
+
+#
+# Based on PROXY the table is not indexable
+#
+CREATE TABLE t1 (
+id INT NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=PROXY TABNAME='xt%s'
+PARTITION BY RANGE COLUMNS(id) (
+PARTITION `1` VALUES LESS THAN(10),
+PARTITION `2` VALUES LESS THAN(50),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM t1;
+DELETE FROM t1;
+--error ER_UNKNOWN_ERROR
+ALTER TABLE t1 ADD INDEX XID(id);
+INSERT INTO t1 VALUES(4, 'four');
+INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one');
+INSERT INTO t1 VALUES(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM t1;
+EXPLAIN PARTITIONS
+SELECT * FROM t1 WHERE id = 81;
+DELETE FROM t1;
+DROP TABLE t1;
+
+#
+# Based on MYSQL the table is indexable
+#
+CREATE TABLE t1 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME='xt%s'
+PARTITION BY RANGE COLUMNS(id) (
+PARTITION `1` VALUES LESS THAN(10),
+PARTITION `2` VALUES LESS THAN(50),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+SHOW INDEX FROM t1;
+INSERT INTO t1 VALUES(4, 'four');
+INSERT INTO t1 VALUES(40, 'forty');
+INSERT INTO t1 VALUES(72,'seventy two');
+INSERT INTO t1 VALUES(7,'seven'),(10,'ten'),(60,'sixty'),(81,'eighty one'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT partition_name, table_rows FROM information_schema.partitions WHERE table_name = 't1';
+SELECT * FROM t1;
+EXPLAIN PARTITIONS SELECT * FROM t1 WHERE id = 81;
+SELECT * FROM t1 WHERE id = 7;
+SELECT * FROM t1 WHERE id = 35;
+UPDATE t1 SET msg = 'number' WHERE id in (60,72);
+UPDATE t1 SET msg = 'soixante' WHERE id = 60;
+SELECT * FROM t1 WHERE id > 50;
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+UPDATE t1 SET msg = 'sept' WHERE id = 7;
+SELECT * FROM t1;
+DELETE FROM t1 WHERE id in (60,72);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Using a connection string
+#
+CREATE TABLE t1 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=MYSQL
+OPTION_LIST='connect=mysql://root@localhost/test/xt%s'
+PARTITION BY RANGE COLUMNS(id) (
+PARTITION `1` VALUES LESS THAN(10),
+PARTITION `2` VALUES LESS THAN(50),
+PARTITION `3` VALUES LESS THAN(MAXVALUE));
+SELECT * FROM t1;
+DROP TABLE t1;
+DROP TABLE xt1;
+DROP TABLE xt2;
+DROP TABLE xt3;
+
+#
+# Clean up
+#
+set @@global.connect_exact_info=OFF;
diff --git a/storage/connect/mysql-test/connect/t/pivot.test b/storage/connect/mysql-test/connect/t/pivot.test
new file mode 100644
index 00000000..09544f27
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/pivot.test
@@ -0,0 +1,163 @@
+-- source include/not_embedded.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $PORT= `select @@port`;
+--copy_file $MTR_SUITE_DIR/std_data/expenses.txt $MYSQLD_DATADIR/test/expenses.txt
+
+--echo #
+--echo # Testing the PIVOT table type
+--echo #
+CREATE TABLE expenses (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+What CHAR(12) NOT NULL,
+Amount DOUBLE(8,2))
+ENGINE=CONNECT TABLE_TYPE=FIX FILE_NAME='expenses.txt' ENDING=2;
+SELECT * FROM expenses;
+
+--echo #
+--echo # Pivoting from What
+--echo #
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Restricting the columns in a Pivot Table
+--echo #
+ALTER TABLE pivex DROP COLUMN week;
+SELECT * FROM pivex;
+
+--echo #
+--echo # Using a source definition
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+Week INT(2) NOT NULL,
+Beer DOUBLE(8,2) FLAG=1,
+Car DOUBLE(8,2) FLAG=1,
+Food DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, week, what, sum(amount) as amount from expenses where week in (4,5) group by who, week, what';
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=what,FncCol=amount,port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Pivoting from Week
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+`3` DOUBLE(8,2) FLAG=1,
+`4` DOUBLE(8,2) FLAG=1,
+`5` DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=expenses;
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=Week,port=$PORT'
+SELECT * FROM pivex;
+
+--echo #
+--echo # Using scalar functions and expresssions
+--echo #
+DROP TABLE pivex;
+CREATE TABLE pivex (
+Who CHAR(10) NOT NULL,
+What CHAR(12) NOT NULL,
+First DOUBLE(8,2) FLAG=1,
+Middle DOUBLE(8,2) FLAG=1,
+Last DOUBLE(8,2) FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT
+SRCDEF='select who, what, case when week=3 then ''First'' when week=5 then ''Last'' else ''Middle'' end as wk, sum(amount) * 6.56 as amnt from expenses group by who, what, wk';
+--replace_result $PORT PORT
+--eval ALTER TABLE pivex OPTION_LIST='PivotCol=wk,FncCol=amnt,port=$PORT'
+SELECT * FROM pivex;
+DROP TABLE pivex;
+DROP TABLE expenses;
+
+--echo #
+--echo # Make the PETS table
+--echo #
+CREATE TABLE pets (
+Name VARCHAR(12) NOT NULL,
+Race CHAR(6) NOT NULL,
+Number INT NOT NULL) ENGINE=MYISAM;
+INSERT INTO pets VALUES('John','dog',2);
+INSERT INTO pets VALUES('Bill','cat',1);
+INSERT INTO pets VALUES('Mary','dog',1);
+INSERT INTO pets VALUES('Mary','cat',1);
+INSERT INTO pets VALUES('Lisbeth','rabbit',2);
+INSERT INTO pets VALUES('Kevin','cat',2);
+INSERT INTO pets VALUES('Kevin','bird',6);
+INSERT INTO pets VALUES('Donald','dog',1);
+INSERT INTO pets VALUES('Donald','fish',3);
+SELECT * FROM pets;
+
+--echo #
+--echo # Pivot the PETS table
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+rabbit INT NOT NULL DEFAULT 0 FLAG=1,
+bird INT NOT NULL DEFAULT 0 FLAG=1,
+fish INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+DROP TABLE pivet;
+
+--echo #
+--echo # Testing the "data" column list
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+--error ER_GET_ERRMSG
+SELECT * FROM pivet;
+ALTER TABLE pivet OPTION_LIST='PivotCol=race,groupby=1,accept=1';
+SELECT * FROM pivet;
+DROP TABLE pivet;
+
+--echo #
+--echo # Adding a "dump" column
+--echo #
+CREATE TABLE pivet (
+name VARCHAR(12) NOT NULL,
+dog INT NOT NULL DEFAULT 0 FLAG=1,
+cat INT NOT NULL DEFAULT 0 FLAG=1,
+other INT NOT NULL DEFAULT 0 FLAG=2)
+ENGINE=CONNECT TABLE_TYPE=PIVOT TABNAME=pets OPTION_LIST='PivotCol=race,groupby=1';
+SELECT * FROM pivet;
+
+DROP TABLE pivet;
+DROP TABLE pets;
+
+--echo #
+--echo # MDEV-5734
+--echo #
+CREATE TABLE fruit (
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(32) NOT NULL,
+ `cnt` int(11) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
+INSERT INTO fruit VALUES (1,'apple',1),(2,'banana',1),(3,'apple',2),(4,'cherry',4),(5,'durazno',2);
+SELECT * FROM fruit;
+CREATE TABLE fruit_pivot ENGINE=CONNECT TABLE_TYPE=pivot TABNAME=fruit;
+SELECT * FROM fruit_pivot;
+
+DROP TABLE fruit_pivot;
+DROP TABLE fruit;
+--remove_file $MYSQLD_DATADIR/test/expenses.txt
diff --git a/storage/connect/mysql-test/connect/t/rest.inc b/storage/connect/mysql-test/connect/t/rest.inc
new file mode 100644
index 00000000..6848e4b6
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/rest.inc
@@ -0,0 +1,17 @@
+--disable_query_log
+--error 0,ER_UNKNOWN_ERROR
+CREATE TABLE t1
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='users.json'
+HTTP='http://jsonplaceholder.typicode.com/users';
+
+if (!`SELECT count(*) FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1'
+ AND ENGINE='CONNECT'
+ AND CREATE_OPTIONS LIKE "%`table_type`='JSON'%"`)
+{
+ DROP TABLE IF EXISTS t1;
+ Skip Need Curl or Casablanca;
+}
+DROP TABLE t1;
+--enable_query_log
+
diff --git a/storage/connect/mysql-test/connect/t/rest.test b/storage/connect/mysql-test/connect/t/rest.test
new file mode 100644
index 00000000..67066ed4
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/rest.test
@@ -0,0 +1,17 @@
+--source rest.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # Testing REST query
+--echo #
+CREATE TABLE t1
+ENGINE=CONNECT DATA_CHARSET=utf8 TABLE_TYPE=JSON FILE_NAME='users.json'
+HTTP='http://jsonplaceholder.typicode.com/users';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/users.json
diff --git a/storage/connect/mysql-test/connect/t/secure_file_priv-master.opt b/storage/connect/mysql-test/connect/t/secure_file_priv-master.opt
new file mode 100644
index 00000000..e9a43a55
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/secure_file_priv-master.opt
@@ -0,0 +1 @@
+--secure_file_priv=$MYSQL_TMP_DIR
diff --git a/storage/connect/mysql-test/connect/t/secure_file_priv.test b/storage/connect/mysql-test/connect/t/secure_file_priv.test
new file mode 100644
index 00000000..f7792536
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/secure_file_priv.test
@@ -0,0 +1,13 @@
+let $DATADIR= `select @@datadir`;
+let $SECUREDIR= `select @@secure_file_priv`;
+
+--replace_result $DATADIR DATADIR
+--error ER_OPTION_PREVENTS_STATEMENT
+--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='$DATADIR/t1.dbf'
+
+--replace_result $SECUREDIR SECUREDATADIR
+--eval CREATE TABLE t1 (a INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=DBF FILE_NAME='$SECUREDIR/t1.dbf'
+INSERT INTO t1 VALUES (10);
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQL_TMP_DIR/t1.dbf
diff --git a/storage/connect/mysql-test/connect/t/tbl.test b/storage/connect/mysql-test/connect/t/tbl.test
new file mode 100644
index 00000000..4f8497d4
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/tbl.test
@@ -0,0 +1,53 @@
+--source include/not_embedded.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $PORT= `select @@port`;
+
+--echo #
+--echo # Checking TBL tables
+--echo #
+CREATE TABLE t1 (
+a INT NOT NULL,
+message CHAR(10)) ENGINE=connect;
+INSERT INTO t1 VALUES (1,'Testing'),(2,'dos table'),(3,'t1');
+SELECT * FROM t1;
+
+CREATE TABLE t2 (
+a INT NOT NULL,
+message CHAR(10)) ENGINE=connect TABLE_TYPE=BIN;
+INSERT INTO t2 VALUES (1,'Testing'),(2,NULL),(3,'t2');
+SELECT * FROM t2;
+
+CREATE TABLE t3 (
+a INT NOT NULL,
+message CHAR(10)) ENGINE=connect TABLE_TYPE=CSV;
+INSERT INTO t3 VALUES (1,'Testing'),(2,'csv table'),(3,'t3');
+SELECT * FROM t3;
+
+CREATE TABLE t4 (
+ta INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
+message CHAR(20)) ENGINE=MyISAM;
+INSERT INTO t4 (message) VALUES ('Testing'),('myisam table'),('t4');
+SELECT * FROM t4;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE total (tabname CHAR(8) NOT NULL SPECIAL='TABID', ta TINYINT NOT NULL FLAG=1, message CHAR(20)) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2,t3,t4' OPTION_LIST='port=$PORT'
+
+SELECT * FROM total;
+SELECT * FROM total WHERE tabname = 't2';
+SELECT * FROM total WHERE tabname = 't2' AND ta = 3;
+SELECT * FROM total WHERE tabname IN ('t1','t4');
+SELECT * FROM total WHERE ta = 3 AND tabname IN ('t1','t2');
+SELECT * FROM total WHERE tabname <> 't2';
+SELECT * FROM total WHERE tabname != 't2' AND ta = 3;
+SELECT * FROM total WHERE tabname NOT IN ('t2','t3');
+SELECT * FROM total WHERE ta = 3 AND tabname IN ('t2','t3');
+SELECT * FROM total WHERE ta = 3 OR tabname IN ('t2','t4');
+SELECT * FROM total WHERE NOT tabname = 't2';
+SELECT * FROM total WHERE tabname = 't2' OR tabname = 't1';
+
+DROP TABLE total;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE t4;
diff --git a/storage/connect/mysql-test/connect/t/tbl_thread.test b/storage/connect/mysql-test/connect/t/tbl_thread.test
new file mode 100644
index 00000000..05409c69
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/tbl_thread.test
@@ -0,0 +1,112 @@
+-- source myconn.inc
+
+connection default;
+
+--echo #
+--echo # Checking thread TBL tables
+--echo #
+CREATE TABLE t1 (a int, b char(10));
+INSERT INTO t1 VALUES (0,'test00'),(1,'test01'),(2,'test02'),(3,'test03');
+SELECT * FROM t1;
+
+connection master;
+
+CREATE TABLE rt2 (a int, b char(10));
+INSERT INTO rt2 VALUES (4,'test04'),(5,'test05'),(6,'test06'),(7,'test07');
+SELECT * FROM rt2;
+
+connection slave;
+
+USE test;
+CREATE TABLE rt3 (a int, b char(10));
+INSERT INTO rt3 VALUES (8,'test08'),(9,'test09'),(10,'test10'),(11,'test11');
+SELECT * FROM rt3;
+
+CREATE TABLE rt4 (a int, b char(10));
+INSERT INTO rt4 VALUES (12,'test12'),(13,'test13'),(14,'test14'),(15,'test15');
+SELECT * FROM rt4;
+
+CREATE TABLE rt5 (a int, b char(10));
+INSERT INTO rt5 VALUES (16,'test16'),(17,'test17'),(18,'test18'),(19,'test19');
+SELECT * FROM rt5;
+
+connection default;
+
+--replace_result $MASTER_MYPORT MASTER_PORT
+eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:$MASTER_MYPORT/test/rt2';
+SELECT * FROM t2;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t3 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/rt3';
+SELECT * FROM t3;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t4 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/rt4';
+SELECT * FROM t4;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+eval CREATE TABLE t5 ENGINE=CONNECT TABLE_TYPE=MYSQL
+CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/rt5';
+SELECT * FROM t5;
+
+--replace_result $PORT PORT
+eval CREATE TABLE total (a int, b char(10))
+ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2,t3,t4,t5'
+OPTION_LIST='thread=yes,port=$PORT';
+set connect_xtrace=96;
+SELECT * FROM total order by a desc;
+set connect_xtrace=0;
+
+connection master;
+
+DROP TABLE rt2;
+
+connection slave;
+
+DROP TABLE rt3,rt4,rt5;
+
+connection default;
+
+DROP TABLE t1,t2,t3,t4,t5,total;
+
+--echo #
+--echo # Old thread TBL tables test modified
+--echo #
+--replace_result $MASTER_MYPORT MASTER_PORT
+--eval CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL SRCDEF='select 11 as v' OPTION_LIST='port=$MASTER_MYPORT'
+SELECT * FROM t1;
+
+--replace_result $SLAVE_MYPORT SLAVE_PORT
+--eval CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL SRCDEF='select 22 as v' OPTION_LIST='port=$SLAVE_MYPORT'
+SELECT * FROM t2;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE total (v BIGINT(20) UNSIGNED NOT NULL) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2' OPTION_LIST='thread=yes,port=$PORT';
+set connect_xtrace=96;
+SELECT * FROM total order by v desc;
+set connect_xtrace=0;
+DROP TABLE t1,t2,total;
+
+--echo #
+--echo # Old thread TBL tables test not modified (suppressed until MDEV-10179 is fixed)
+--echo #
+CREATE TABLE t1 ENGINE=CONNECT TABLE_TYPE=MYSQL SRCDEF='select 11 as v';
+SELECT * FROM t1;
+
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL SRCDEF='select 22 as v';
+SELECT * FROM t2;
+
+--replace_result $PORT PORT
+--eval CREATE TABLE total (v BIGINT(20) UNSIGNED NOT NULL) ENGINE=CONNECT TABLE_TYPE=TBL TABLE_LIST='t1,t2' OPTION_LIST='thread=yes,port=$PORT';
+set connect_xtrace=96;
+SELECT * FROM total order by v desc;
+set connect_xtrace=0;
+
+DROP TABLE total;
+DROP TABLE t1;
+DROP TABLE t2;
+
+-- source myconn_cleanup.inc
diff --git a/storage/connect/mysql-test/connect/t/temporary.test b/storage/connect/mysql-test/connect/t/temporary.test
new file mode 100644
index 00000000..dda066c8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/temporary.test
@@ -0,0 +1,13 @@
+#
+# CONNECT tables cannot be TEMPORARY
+#
+
+--error ER_ILLEGAL_HA_CREATE_OPTION
+CREATE TEMPORARY TABLE t1 (a int not null)
+ ENGINE=CONNECT table_type=MYSQL CONNECTION='mysql://root@127.0.0.1/test/t2';
+
+# also with assisted discovery
+--error ER_ILLEGAL_HA_CREATE_OPTION
+CREATE TEMPORARY TABLE t1
+ ENGINE=CONNECT table_type=MYSQL CONNECTION='mysql://root@127.0.0.1/test/t2';
+
diff --git a/storage/connect/mysql-test/connect/t/type_inet6.test b/storage/connect/mysql-test/connect/t/type_inet6.test
new file mode 100644
index 00000000..19f5c13e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/type_inet6.test
@@ -0,0 +1,10 @@
+--echo #
+--echo # MDEV-21764 CONNECT table with INET6 field produces warnings upon SELECT
+--echo #
+
+CREATE TABLE t1 (a INET6) ENGINE=CONNECT TABLE_TYPE=DOS;
+INSERT INTO t1 VALUES ('::');
+INSERT INTO t1 VALUES ('::ffff');
+INSERT INTO t1 VALUES ('ffff::ffff');
+SELECT * FROM t1;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/unsigned.test b/storage/connect/mysql-test/connect/t/unsigned.test
new file mode 100644
index 00000000..48f6bdc8
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/unsigned.test
@@ -0,0 +1,35 @@
+--echo #
+--echo # Testing unsigned types
+--echo #
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+a TINYINT UNSIGNED NOT NULL,
+b SMALLINT ZEROFILL NOT NULL,
+c INT UNSIGNED NOT NULL,
+d BIGINT UNSIGNED NOT NULL,
+e CHAR(32) NOT NULL DEFAULT '???') ENGINE=CONNECT TABLE_TYPE=FIX;
+DESCRIBE t1;
+INSERT INTO t1(a,b,c,d) VALUES(255,65535,4294967295,18446744073709551615);
+SELECT * FROM t1;
+UPDATE t1 SET e = d;
+SELECT * FROM t1;
+UPDATE IGNORE t1 SET c = d;
+SELECT * FROM t1;
+UPDATE IGNORE t1 SET c = e;
+SELECT * FROM t1;
+UPDATE t1 SET d = e;
+SELECT * FROM t1;
+
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=PROXY TABNAME=t1;
+DESCRIBE t2;
+SELECT * FROM t2;
+
+# Moved to mysql.test (cannot be executed if embedded)
+#DROP TABLE t2;
+#CREATE TABLE t2 ENGINE=CONNECT TABLE_TYPE=MYSQL TABNAME=t1;
+#DESCRIBE t2;
+#SELECT * FROM t2;
+
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/upd.test b/storage/connect/mysql-test/connect/t/upd.test
new file mode 100644
index 00000000..28b566b5
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/upd.test
@@ -0,0 +1,157 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/employee.dat $MYSQLD_DATADIR/test/employee.dat
+
+SET sql_mode = 'NO_ENGINE_SUBSTITUTION';
+
+CREATE TABLE employee
+(
+serialno CHAR(5) NOT NULL,
+name VARCHAR(12) NOT NULL FLAG=6,
+sex TINYINT(1) NOT NULL,
+title VARCHAR(15) NOT NULL FLAG=20,
+manager CHAR(5) NOT NULL,
+department CHAR(4) NOT NULL FLAG=41,
+secretary CHAR(5) NOT NULL FLAG=46,
+salary DOUBLE(8,2) NOT NULL FLAG=52
+) ENGINE=connect TABLE_TYPE=fix FILE_NAME='employee.dat' ENDING=1;
+SELECT * FROM employee;
+
+DELIMITER //;
+CREATE PROCEDURE test.tst_up() DETERMINISTIC
+BEGIN
+SELECT * FROM t1;
+UPDATE t1 SET salary = salary + 1, title = 'RESEARCH' WHERE title = 'SCIENTIST';
+UPDATE t1 SET salary = salary + 1, title = 'TECHNICIAN' WHERE title = 'ENGINEER';
+UPDATE t1 SET title = 'PUPPET' WHERE name = 'TONGHO';
+UPDATE t1 SET salary = 0. WHERE title = 'XXX';
+SELECT * FROM t1;
+DELETE FROM t1 WHERE title = 'SECRETARY';
+DELETE FROM t1 WHERE title = 'DIRECTOR';
+DELETE FROM t1 WHERE title = 'TYPIST';
+SELECT * FROM t1;
+DELETE FROM t1 LIMIT 3;
+INSERT INTO t1(serialno, name, title, salary) VALUES('66666','NEWMAN','ENGINEER',10000.80);
+SELECT * FROM t1;
+DROP TABLE t1;
+END//
+DELIMITER ;//
+
+--echo #
+--echo # Testing DOS table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing DOS table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect mapped=yes AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing FIX table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=fix AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing FIX table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=fix mapped=yes AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing FIX table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=fix huge=yes AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing CSV table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=csv AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing CSV table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=csv mapped=yes AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing DBF table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=dbf AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing DBF table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=dbf mapped=yes AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing BIN table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=bin AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing BIN table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=bin mapped=yes AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing BIN table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=bin huge=yes AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing VEC table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=vec MAX_ROWS=30 AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing VEC table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=vec mapped=yes MAX_ROWS=30 AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing VEC table changes
+--echo #
+CREATE TABLE t1 ENGINE=connect TABLE_TYPE=vec huge=yes MAX_ROWS=30 AS SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing INI table changes
+--echo #
+CREATE TABLE t1
+(
+serialno CHAR(5) NOT NULL FLAG=1,
+name VARCHAR(12) NOT NULL,
+sex TINYINT(1),
+title VARCHAR(15) NOT NULL,
+manager CHAR(5),
+department CHAR(4),
+secretary CHAR(5),
+salary DOUBLE(8,2) NOT NULL
+) ENGINE=connect TABLE_TYPE=ini;
+INSERT INTO t1 SELECT * FROM employee;
+CALL test.tst_up();
+
+--echo #
+--echo # Testing XML table changes (must be in a separate test)
+--echo #
+#CREATE TABLE t1 ENGINE=connect TABLE_TYPE=xml option_list='rownode=dd' AS SELECT * FROM employee;
+#CALL test.tst_up();
+
+DROP PROCEDURE test.tst_up;
+DROP TABLE employee;
+
+SET sql_mode = DEFAULT;
+
+--remove_file $MYSQLD_DATADIR/test/employee.dat
diff --git a/storage/connect/mysql-test/connect/t/updelx.inc b/storage/connect/mysql-test/connect/t/updelx.inc
new file mode 100644
index 00000000..f38a59b9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/updelx.inc
@@ -0,0 +1,25 @@
+DELETE FROM t1;
+INSERT INTO t1 VALUES(4, 'four'),(7,'seven'),(10,'ten'),(40,'forty'),(60,'sixty'),(81,'eighty one'),(72,'seventy two'),(11,'eleven'),(1,'one'),(35,'thirty five'),(8,'eight');
+SELECT * FROM t1;
+UPDATE t1 SET msg = 'bof' WHERE id = 35;
+SELECT * FROM t1;
+UPDATE t1 SET msg = 'big' WHERE id > 50;
+SELECT * FROM t1;
+UPDATE t1 SET msg = 'updated' WHERE id IN (8,35,60,72);
+SELECT * FROM t1;
+UPDATE t1 SET msg = 'twin' WHERE id IN (81,10);
+SELECT * FROM t1;
+UPDATE t1 SET msg = 'sixty' WHERE id = 60;
+SELECT * FROM t1 WHERE id = 60;
+DELETE FROM t1 WHERE id = 4;
+SELECT * FROM t1;
+DELETE FROM t1 WHERE id IN (40,11,35);
+SELECT * FROM t1;
+DELETE FROM t1 WHERE id IN (4,60,1);
+SELECT msg FROM t1;
+DELETE FROM t1 WHERE id IN (81,72);
+SELECT id FROM t1;
+DELETE FROM t1 WHERE id IN (7,10);
+SELECT * FROM t1;
+DELETE FROM t1 WHERE id = 8;
+SELECT * FROM t1;
diff --git a/storage/connect/mysql-test/connect/t/updelx.test b/storage/connect/mysql-test/connect/t/updelx.test
new file mode 100644
index 00000000..f6291432
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/updelx.test
@@ -0,0 +1,96 @@
+-- source include/not_embedded.inc
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--echo #
+--echo # Testing indexed UPDATE and DELETE for all table types
+--echo #
+
+--echo # CSV table
+CREATE TABLE t1 (
+id INT KEY NOT NULL,
+msg VARCHAR(32))
+ENGINE=CONNECT TABLE_TYPE=CSV AVG_ROW_LENGTH=6;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=NO BLOCK_SIZE=6;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+DROP TABLE t1;
+
+--echo # DOS table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16))
+ENGINE=CONNECT TABLE_TYPE=DOS;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=NO BLOCK_SIZE=4;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+DROP TABLE t1;
+
+--echo # FIX table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16) DISTRIB=CLUSTERED)
+ENGINE=CONNECT TABLE_TYPE=FIX BLOCK_SIZE=4;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=NO HUGE=YES;
+-- source updelx.inc
+DROP TABLE t1;
+
+--echo # BIN table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16) DISTRIB=CLUSTERED)
+ENGINE=CONNECT TABLE_TYPE=BIN BLOCK_SIZE=8;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=NO HUGE=YES;
+-- source updelx.inc
+DROP TABLE t1;
+
+--echo # DBF table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16))
+ENGINE=CONNECT TABLE_TYPE=DBF BLOCK_SIZE=12;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+#ALTER TABLE t1 MAPPED=NO HUGE=YES;
+#-- source updelx.inc
+DROP TABLE t1;
+
+--echo # VEC table
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16))
+ENGINE=CONNECT TABLE_TYPE=VEC BLOCK_SIZE=6 MAX_ROWS=16;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=NO HUGE=YES;
+-- source updelx.inc
+DROP TABLE t1;
+
+--echo # Split VEC table (outward)
+CREATE TABLE t1 (
+id INT(4) KEY NOT NULL,
+msg VARCHAR(16))
+ENGINE=CONNECT TABLE_TYPE=VEC BLOCK_SIZE=6 FILE_NAME='tx.vec';
+-- source updelx.inc
+ALTER TABLE t1 MAPPED=YES;
+-- source updelx.inc
+DROP TABLE t1;
+
+# Cleanup
+--remove_file $MYSQLD_DATADIR/test/tx1.vec
+--remove_file $MYSQLD_DATADIR/test/tx2.vec
diff --git a/storage/connect/mysql-test/connect/t/updelx2.test b/storage/connect/mysql-test/connect/t/updelx2.test
new file mode 100644
index 00000000..8b90851a
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/updelx2.test
@@ -0,0 +1,22 @@
+-- source include/not_embedded.inc
+
+--echo #
+--echo # Testing multiple indexed UPDATE and DELETE
+--echo #
+CREATE TABLE t1 (
+id INT(4) NOT NULL,
+msg VARCHAR(16) NOT NULL,
+INDEX IDM(id,msg))
+ENGINE=CONNECT TABLE_TYPE=DOS;
+INSERT INTO t1 VALUES(1,'one'),(4, 'four'),(7,'seven'),(8,'eight'),(10,'ten'),(11,'eleven'),(40,'forty'),(35,'thirty five'),(60,'sixty'),(72,'seventy two'),(81,'eighty one');
+INSERT INTO t1 VALUES(1,'un'),(4, 'quatre'),(7,'sept'),(8,'huit'),(10,'dix'),(11,'onze'),(40,'quarante'),(35,'trente cinq'),(60,'soixante'),(72,'soixante douze'),(81,'quatrevingt un');
+SELECT * FROM t1 IGNORE INDEX (IDM);
+UPDATE t1 SET msg = 'dieci' WHERE id = 10;
+SELECT * FROM t1 IGNORE INDEX (IDM);
+UPDATE t1 SET msg = 'septante deux' WHERE id = 72;
+SELECT * FROM t1 IGNORE INDEX (IDM);
+UPDATE t1 SET id=2, msg='deux' WHERE id=4 AND msg='quatre';
+SELECT * FROM t1 IGNORE INDEX (IDM);
+DELETE FROM t1 WHERE id IN (8,40);
+SELECT * FROM t1 IGNORE INDEX (IDM);
+DROP TABLE t1;
diff --git a/storage/connect/mysql-test/connect/t/vcol.test b/storage/connect/mysql-test/connect/t/vcol.test
new file mode 100644
index 00000000..cdf37175
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/vcol.test
@@ -0,0 +1,31 @@
+let datadir= `select @@datadir`;
+--copy_file $MTR_SUITE_DIR/std_data/boys.txt $datadir/test/boys.txt
+
+create table t1 (
+ #linenum int(6) not null default 0 special=rowid,
+ name char(12) not null,
+ city char(11) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36,
+ agehired int(3) as (floor(datediff(hired,birth)/365.25))
+ )
+engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47 ending=1;
+select * from t1;
+drop table t1;
+
+--error ER_NULL_COLUMN_IN_INDEX
+create table t1 (
+ #linenum int(6) not null default 0 special=rowid,
+ name char(12) not null,
+ city char(11) not null,
+ birth date not null date_format='DD/MM/YYYY',
+ hired date not null date_format='DD/MM/YYYY' flag=36,
+ agehired int(3) as (floor(datediff(hired,birth)/365.25)),
+ index (agehired)
+ )
+engine=CONNECT table_type=FIX file_name='boys.txt' mapped=YES lrecl=47 ending=1;
+
+#
+# Clean up
+#
+--remove_file $datadir/test/boys.txt
diff --git a/storage/connect/mysql-test/connect/t/vec.test b/storage/connect/mysql-test/connect/t/vec.test
new file mode 100644
index 00000000..c88a8577
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/vec.test
@@ -0,0 +1,80 @@
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+CREATE TABLE dir1 (
+ spath VARCHAR(256) NOT NULL flag=1,
+ fname VARCHAR(256) NOT NULL,
+ ftype CHAR(4) NOT NULL,
+ size DOUBLE(12,0) NOT NULL flag=5
+) ENGINE=CONNECT TABLE_TYPE=DIR FILE_NAME='*vec*';
+
+
+CREATE TABLE t1
+(
+ a INT NOT NULL,
+ b CHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=VEC FILE_NAME='t1vec';
+SHOW CREATE TABLE t1;
+# Testing SELECT on empty file
+--replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
+SELECT * FROM t1;
+INSERT INTO t1 VALUES (0,'test01'), (1,'test01'), (2,'test02'), (3,'test03');
+SELECT * FROM t1;
+SELECT a FROM t1;
+SELECT b FROM t1;
+--replace_result $MYSQLD_DATADIR DATADIR/
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1vec1
+--remove_file $MYSQLD_DATADIR/test/t1vec2
+
+
+CREATE TABLE t1
+(
+ a INT NOT NULL,
+ b CHAR(10) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=VEC FILE_NAME='t1vec' MAX_ROWS=10;
+SHOW CREATE TABLE t1;
+# Testing SELECTs on empty file
+--replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
+SELECT * FROM t1;
+--replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
+SELECT a FROM t1;
+--replace_regex /Open.rb. error 2 on .*\/test\/t1vec/Open(rb) error 2 on DATADIR\/test\/t1vec/
+SELECT b FROM t1;
+INSERT INTO t1 VALUES (0,'test01'), (1,'test01'), (2,'test02'), (3,'test03');
+SELECT * FROM t1;
+SELECT a FROM t1;
+SELECT b FROM t1;
+--replace_result $MYSQLD_DATADIR DATADIR/
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+--echo #
+--echo # Testing READONLY
+--echo #
+ALTER TABLE t1 READONLY=yes;
+SHOW CREATE TABLE t1;
+--error ER_OPEN_AS_READONLY
+INSERT INTO t1 VALUES (4,'test04');
+--error ER_GET_ERRMSG
+UPDATE t1 SET b='test04' WHERE a=3;
+--error ER_GET_ERRMSG
+DELETE FROM t1 WHERE a=3;
+--error ER_OPEN_AS_READONLY
+TRUNCATE TABLE t1;
+ALTER TABLE t1 READONLY=no;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES (4,'test04');
+UPDATE t1 SET b='test04a' WHERE a=4;
+DELETE FROM t1 WHERE a=0;
+SELECT * FROM t1;
+TRUNCATE TABLE t1;
+SELECT fname, ftype, size FROM dir1 ORDER BY fname, ftype;
+SELECT * FROM t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/t1vec
+--remove_file $MYSQLD_DATADIR/test/t1vec.blk
+
+
+--echo #
+--echo # Clean up
+--echo #
+DROP TABLE dir1;
diff --git a/storage/connect/mysql-test/connect/t/windows.inc b/storage/connect/mysql-test/connect/t/windows.inc
new file mode 100644
index 00000000..88553d8a
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/windows.inc
@@ -0,0 +1,5 @@
+if (`select convert(@@version_compile_os using latin1) IN ("Win32","Win64","Windows") = 0`)
+{
+ skip Need windows;
+}
+
diff --git a/storage/connect/mysql-test/connect/t/xcol.test b/storage/connect/mysql-test/connect/t/xcol.test
new file mode 100644
index 00000000..e0183f01
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xcol.test
@@ -0,0 +1,41 @@
+--echo #
+--echo # Make the children list table
+--echo #
+CREATE TABLE chlist (
+mother char(12) NOT NULL COMMENT 'The mother of the listed children',
+children varchar(30) DEFAULT NULL COMMENT 'The comma separated list of children'
+) ENGINE=CONNECT;
+INSERT INTO chlist VALUES('Sophia','Vivian, Antony');
+INSERT INTO chlist VALUES('Lisbeth','Lucy,Charles,Diana');
+INSERT INTO chlist VALUES('Corinne',NULL);
+INSERT INTO chlist VALUES('Claude','Marc');
+INSERT INTO chlist VALUES('Janet','Arthur,Sandra,Peter,John');
+SELECT * FROM chlist;
+
+--echo #
+--echo # Checking XCOL tables
+--echo #
+CREATE TABLE child ENGINE=CONNECT TABLE_TYPE=XCOL TABNAME=chlist OPTION_LIST='colname=children';
+SELECT * FROM child;
+SELECT * FROM child ORDER BY mother;
+SELECT * FROM child ORDER BY children;
+SELECT mother FROM child;
+SELECT mother, COUNT(*) FROM child GROUP BY mother;
+SELECT mother, COUNT(children) FROM child GROUP BY mother;
+
+--echo #
+--echo # Test using special columns
+--echo #
+CREATE TABLE `child2` (
+ `row` int NOT NULL SPECIAL=ROWID,
+ `num` int NOT NULL SPECIAL=ROWNUM,
+ `mother` varchar(12) NOT NULL COMMENT 'The mother of the children',
+ `child` varchar(12) NOT NULL COMMENT 'The child name' FLAG=2
+) ENGINE=CONNECT TABLE_TYPE=XCOL TABNAME=chlist `OPTION_LIST`='colname=child';
+SELECT * FROM child2;
+--echo # List only first child
+SELECT mother, child FROM child2 where num = 1;
+
+DROP TABLE child;
+DROP TABLE chlist;
+DROP TABLE child2;
diff --git a/storage/connect/mysql-test/connect/t/xml.test b/storage/connect/mysql-test/connect/t/xml.test
new file mode 100644
index 00000000..e837ec79
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml.test
@@ -0,0 +1,321 @@
+--source windows.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+SET NAMES utf8;
+
+--vertical_results
+
+--copy_file $MTR_SUITE_DIR/std_data/xsample.xml $MYSQLD_DATADIR/test/xsample.xml
+--copy_file $MTR_SUITE_DIR/std_data/latin1.xml $MYSQLD_DATADIR/test/latin1.xml
+--copy_file $MTR_SUITE_DIR/std_data/cp1251.xml $MYSQLD_DATADIR/test/cp1251.xml
+
+#--echo $MYSQL_TEST_DIR
+#--exec pwd
+#SELECT LOAD_FILE('test/xsample.xml');
+
+
+--echo #
+--echo # Testing tag values
+--echo #
+CREATE TABLE t1
+(
+ AUTHOR CHAR(50),
+ TITLE CHAR(32),
+ TRANSLATOR CHAR(40),
+ PUBLISHER CHAR(40),
+ DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that tag names are case sensitive
+--echo #
+CREATE TABLE t1
+(
+ author CHAR(50),
+ TITLE CHAR(32),
+ TRANSLATOR CHAR(40),
+ PUBLISHER CHAR(40),
+ DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing attribute values
+--echo #
+CREATE TABLE t1 (
+ ISBN CHAR(15),
+ LANG CHAR(2),
+ SUBJECT CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='Coltype=@,xmlsup=domdoc';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that attribute names are case sensitive
+--echo #
+CREATE TABLE t1 (
+ isbn CHAR(15),
+ LANG CHAR(2),
+ SUBJECT CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='Coltype=@,xmlsup=domdoc';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing mixed tag and attribute values
+--echo #
+CREATE TABLE t1 (
+ ISBN CHAR(15) FIELD_FORMAT='@',
+ LANG CHAR(2) FIELD_FORMAT='@',
+ SUBJECT CHAR(32) FIELD_FORMAT='@',
+ AUTHOR CHAR(50),
+ TITLE CHAR(32),
+ TRANSLATOR CHAR(40),
+ PUBLISHER CHAR(40),
+ DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing INSERT on mixed tag and attribute values
+--echo #
+--copy_file $MTR_SUITE_DIR/std_data/xsample.xml $MYSQLD_DATADIR/test/xsample2.xml
+--chmod 0644 $MYSQLD_DATADIR/test/xsample2.xml
+CREATE TABLE t1 (
+ ISBN CHAR(15) FIELD_FORMAT='@',
+ LANG CHAR(2) FIELD_FORMAT='@',
+ SUBJECT CHAR(32) FIELD_FORMAT='@',
+ AUTHOR CHAR(50),
+ TITLE CHAR(32),
+ TRANSLATOR CHAR(40),
+ PUBLISHER CHAR(40),
+ DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.xml'
+ TABNAME='BIBLIO'
+ OPTION_LIST='rownode=BOOK,xmlsup=domdoc';
+INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB)
+VALUES('9782212090529','fr','général','Alain Michard',
+'XML, Langage et Applications','Eyrolles Paris',1998);
+SELECT * FROM t1;
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--eval SELECT LOAD_FILE('$MYSQLD_DATADIR/test/xsample2.xml') AS xml
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/xsample2.xml
+
+
+--echo #
+--echo # Testing XPath
+--echo #
+CREATE TABLE t1 (
+ isbn CHAR(15) FIELD_FORMAT='@ISBN',
+ language CHAR(2) FIELD_FORMAT='@LANG',
+ subject CHAR(32) FIELD_FORMAT='@SUBJECT',
+ authorfn CHAR(20) FIELD_FORMAT='AUTHOR/FIRSTNAME',
+ authorln CHAR(20) FIELD_FORMAT='AUTHOR/LASTNAME',
+ title CHAR(32) FIELD_FORMAT='TITLE',
+ translated CHAR(32) FIELD_FORMAT='TRANSLATOR/@PREFIX',
+ tranfn CHAR(20) FIELD_FORMAT='TRANSLATOR/FIRSTNAME',
+ tranln CHAR(20) FIELD_FORMAT='TRANSLATOR/LASTNAME',
+ publisher CHAR(20) FIELD_FORMAT='PUBLISHER/NAME',
+ location CHAR(20) FIELD_FORMAT='PUBLISHER/PLACE',
+ year INT(4) FIELD_FORMAT='DATEPUB'
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=domdoc';
+SELECT * FROM t1;
+SELECT isbn, title, translated, tranfn, tranln, location FROM t1
+WHERE translated <> '';
+DROP TABLE t1;
+
+
+#
+# TODO: Connect.pdf says nodes with variable depth are not supported
+#
+#--echo #
+#--echo # Relative paths are not supported
+#--echo #
+#CREATE TABLE t1 (
+# authorfn CHAR(20) FIELD_FORMAT='//FIRSTNAME',
+# authorln CHAR(20) FIELD_FORMAT='//LASTNAME'
+#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+# TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1';
+#SELECT * FROM t1;
+#DROP TABLE t1;
+
+
+#
+# TODO: Connect.pdf says absolute paths are not supported
+#
+#--echo #
+#--echo # Absolute path is not supported
+#--echo #
+#CREATE TABLE t1 (
+# authorfn CHAR(20) FIELD_FORMAT='/BIBLIO/BOOK/AUTHOR/FIRSTNAME',
+# authorln CHAR(20) FIELD_FORMAT='/BIBLIO/BOOK/AUTHOR/LASTNAME'
+#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+# TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1';
+#SELECT * FROM t1;
+#DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that XPath is case sensitive
+--echo #
+CREATE TABLE t1
+(
+ isbn CHAR(15) FIELD_FORMAT='@isbn'
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=domdoc';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing character sets
+--echo #
+
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc'
+ DATA_CHARSET=latin1;
+
+CREATE TABLE t1
+(
+ c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc'
+ DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+SELECT c, HEX(c) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT c, HEX(c) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ c CHAR(16) CHARACTER SET utf8
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT c, HEX(c) FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Conversion from latin1 to cp1251 produces a warning.
+--echo # Question marks are returned.
+--echo #
+CREATE TABLE t1
+(
+ c CHAR(16) CHARACTER SET cp1251
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=domdoc';
+SELECT c, HEX(c) FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing Cyrillic
+--echo #
+#CREATE TABLE t1
+#(
+# c CHAR(16) CHARACTER SET utf8
+#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml'
+# OPTION_LIST='xmlsup=domdoc,rownode=b';
+#SELECT * FROM t1;
+#INSERT INTO t1 VALUES ('ИКЛМÐ');
+#SELECT c, HEX(c) FROM t1;
+#DROP TABLE t1;
+#CREATE TABLE t1
+#(
+# c CHAR(16) CHARACTER SET cp1251
+#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml'
+# OPTION_LIST='xmlsup=domdoc,rownode=b';
+#SELECT * FROM t1;
+#INSERT INTO t1 VALUES ('ОПРСТ');
+#SELECT c, HEX(c) FROM t1;
+#DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that the underlying file is created with a proper Encoding
+--echo #
+CREATE TABLE t1 (node VARCHAR(50))
+ CHARACTER SET latin1
+ ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=utf-8';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+SELECT node, hex(node) FROM t1;
+DROP TABLE t1;
+#--chmod 0777 $MYSQLD_DATADIR/test/t1.xml
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml')
+SELECT LEFT(@a,38);
+SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node'));
+--remove_file $MYSQLD_DATADIR/test/t1.xml
+
+CREATE TABLE t1 (node VARCHAR(50))
+ CHARACTER SET latin1
+ ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=iso-8859-1';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+SELECT node, hex(node) FROM t1;
+DROP TABLE t1;
+#--chmod 0777 $MYSQLD_DATADIR/test/t1.xml
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml')
+SELECT LEFT(@a,43);
+SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node'));
+--remove_file $MYSQLD_DATADIR/test/t1.xml
+
+
+--echo #
+--echo # Testing XML entities
+--echo #
+CREATE TABLE t1 (node VARCHAR(50))
+ CHARACTER SET utf8
+ ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=domdoc,rownode=line,encoding=iso-8859-1';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+--replace_regex /.*iso-8859-1.*/warning about characters outside of iso-8859-1/
+INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3);
+INSERT INTO t1 VALUES ('&<>"\'');
+SELECT node, hex(node) FROM t1;
+DROP TABLE t1;
+#--chmod 0777 $MYSQLD_DATADIR/test/t1.xml
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml')
+SELECT CAST(@a AS CHAR CHARACTER SET latin1);
+--remove_file $MYSQLD_DATADIR/test/t1.xml
+
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/xsample.xml
+--remove_file $MYSQLD_DATADIR/test/latin1.xml
+--remove_file $MYSQLD_DATADIR/test/cp1251.xml
diff --git a/storage/connect/mysql-test/connect/t/xml2.test b/storage/connect/mysql-test/connect/t/xml2.test
new file mode 100644
index 00000000..9c5f685d
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml2.test
@@ -0,0 +1,320 @@
+--source have_libxml2.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+SET NAMES utf8;
+
+--vertical_results
+
+--copy_file $MTR_SUITE_DIR/std_data/xsample.xml $MYSQLD_DATADIR/test/xsample.xml
+--copy_file $MTR_SUITE_DIR/std_data/latin1.xml $MYSQLD_DATADIR/test/latin1.xml
+--copy_file $MTR_SUITE_DIR/std_data/cp1251.xml $MYSQLD_DATADIR/test/cp1251.xml
+
+#--echo $MYSQL_TEST_DIR
+#--exec pwd
+#SELECT LOAD_FILE('test/xsample.xml');
+
+
+--echo #
+--echo # Testing tag values
+--echo #
+CREATE TABLE t1
+(
+ AUTHOR CHAR(50),
+ TITLE CHAR(32),
+ TRANSLATOR CHAR(40),
+ PUBLISHER CHAR(40),
+ DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that tag names are case sensitive
+--echo #
+CREATE TABLE t1
+(
+ author CHAR(50),
+ TITLE CHAR(32),
+ TRANSLATOR CHAR(40),
+ PUBLISHER CHAR(40),
+ DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing attribute values
+--echo #
+CREATE TABLE t1 (
+ ISBN CHAR(15),
+ LANG CHAR(2),
+ SUBJECT CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='Coltype=@,xmlsup=libxml2';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that attribute names are case sensitive
+--echo #
+CREATE TABLE t1 (
+ isbn CHAR(15),
+ LANG CHAR(2),
+ SUBJECT CHAR(32)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ OPTION_LIST='Coltype=@,xmlsup=libxml2';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing mixed tag and attribute values
+--echo #
+CREATE TABLE t1 (
+ ISBN CHAR(15) XPATH='@',
+ LANG CHAR(2) XPATH='@',
+ SUBJECT CHAR(32) XPATH='@',
+ AUTHOR CHAR(50),
+ TITLE CHAR(32),
+ TRANSLATOR CHAR(40),
+ PUBLISHER CHAR(40),
+ DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing INSERT on mixed tag and attribute values
+--echo #
+--copy_file $MTR_SUITE_DIR/std_data/xsample.xml $MYSQLD_DATADIR/test/xsample2.xml
+--chmod 0644 $MYSQLD_DATADIR/test/xsample2.xml
+CREATE TABLE t1 (
+ ISBN CHAR(15) XPATH='@',
+ LANG CHAR(2) XPATH='@',
+ SUBJECT CHAR(32) XPATH='@',
+ AUTHOR CHAR(50),
+ TITLE CHAR(32),
+ TRANSLATOR CHAR(40),
+ PUBLISHER CHAR(40),
+ DATEPUB INT(4)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.xml'
+ TABNAME='BIBLIO'
+ OPTION_LIST='rownode=BOOK,xmlsup=libxml2';
+INSERT INTO t1 (ISBN, LANG, SUBJECT, AUTHOR, TITLE, PUBLISHEr, DATEPUB)
+VALUES('9782212090529','fr','général','Alain Michard',
+'XML, Langage et Applications','Eyrolles Paris',1998);
+SELECT * FROM t1;
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--eval SELECT LOAD_FILE('$MYSQLD_DATADIR/test/xsample2.xml') AS xml
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/xsample2.xml
+
+
+--echo #
+--echo # Testing XPath
+--echo #
+CREATE TABLE t1 (
+ isbn CHAR(15) XPATH='@ISBN',
+ language CHAR(2) XPATH='@LANG',
+ subject CHAR(32) XPATH='@SUBJECT',
+ authorfn CHAR(20) XPATH='AUTHOR/FIRSTNAME',
+ authorln CHAR(20) XPATH='AUTHOR/LASTNAME',
+ title CHAR(32) XPATH='TITLE',
+ translated CHAR(32) XPATH='TRANSLATOR/@PREFIX',
+ tranfn CHAR(20) XPATH='TRANSLATOR/FIRSTNAME',
+ tranln CHAR(20) XPATH='TRANSLATOR/LASTNAME',
+ publisher CHAR(20) XPATH='PUBLISHER/NAME',
+ location CHAR(20) XPATH='PUBLISHER/PLACE',
+ year INT(4) XPATH='DATEPUB'
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2';
+SELECT * FROM t1;
+SELECT isbn, title, translated, tranfn, tranln, location FROM t1
+WHERE translated <> '';
+DROP TABLE t1;
+
+
+#
+# TODO: Connect.pdf says nodes with variable depth are not supported
+#
+#--echo #
+#--echo # Relative paths are not supported
+#--echo #
+#CREATE TABLE t1 (
+# authorfn CHAR(20) XPATH='//FIRSTNAME',
+# authorln CHAR(20) XPATH='//LASTNAME'
+#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+# TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1';
+#SELECT * FROM t1;
+#DROP TABLE t1;
+
+
+#
+# TODO: Connect.pdf says absolute paths are not supported
+#
+#--echo #
+#--echo # Absolute path is not supported
+#--echo #
+#CREATE TABLE t1 (
+# authorfn CHAR(20) XPATH='/BIBLIO/BOOK/AUTHOR/FIRSTNAME',
+# authorln CHAR(20) XPATH='/BIBLIO/BOOK/AUTHOR/LASTNAME'
+#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+# TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1';
+#SELECT * FROM t1;
+#DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that XPath is case sensitive
+--echo #
+CREATE TABLE t1
+(
+ isbn CHAR(15) XPATH='@isbn'
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample.xml'
+ TABNAME='BIBLIO' OPTION_LIST='rownode=BOOK,skipnull=1,xmlsup=libxml2';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing character sets
+--echo #
+
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1
+(
+ c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2'
+ DATA_CHARSET=latin1;
+
+CREATE TABLE t1
+(
+ c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2'
+ DATA_CHARSET=utf8;
+SHOW CREATE TABLE t1;
+SELECT c, HEX(c) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ c CHAR(16)
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT c, HEX(c) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1
+(
+ c CHAR(16) CHARACTER SET utf8
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT c, HEX(c) FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Conversion from latin1 to cp1251 produces a warning.
+--echo # Question marks are returned.
+--echo #
+CREATE TABLE t1
+(
+ c CHAR(16) CHARACTER SET cp1251
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='latin1.xml'
+ OPTION_LIST='xmlsup=libxml2';
+SELECT c, HEX(c) FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Testing Cyrillic
+--echo #
+#CREATE TABLE t1
+#(
+# c CHAR(16) CHARACTER SET utf8
+#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml'
+# OPTION_LIST='xmlsup=libxml2,rownode=b';
+#SELECT * FROM t1;
+#INSERT INTO t1 VALUES ('ИКЛМÐ');
+#SELECT c, HEX(c) FROM t1;
+#DROP TABLE t1;
+#CREATE TABLE t1
+#(
+# c CHAR(16) CHARACTER SET cp1251
+#) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='cp1251.xml'
+# OPTION_LIST='xmlsup=libxml2,rownode=b';
+#SELECT * FROM t1;
+#INSERT INTO t1 VALUES ('ОПРСТ');
+#SELECT c, HEX(c) FROM t1;
+#DROP TABLE t1;
+
+
+--echo #
+--echo # Testing that the underlying file is created with a proper Encoding
+--echo #
+CREATE TABLE t1 (node VARCHAR(50))
+ CHARACTER SET latin1
+ ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=utf-8';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+SELECT node, hex(node) FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.xml
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml')
+SELECT LEFT(@a,38);
+SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node'));
+--remove_file $MYSQLD_DATADIR/test/t1.xml
+
+CREATE TABLE t1 (node VARCHAR(50))
+ CHARACTER SET latin1
+ ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+SELECT node, hex(node) FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.xml
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml')
+SELECT LEFT(@a,43);
+SELECT HEX(EXTRACTVALUE(@a,'/t1/line/node'));
+--remove_file $MYSQLD_DATADIR/test/t1.xml
+
+
+--echo #
+--echo # Testing XML entities
+--echo #
+CREATE TABLE t1 (node VARCHAR(50))
+ CHARACTER SET utf8
+ ENGINE=connect TABLE_TYPE=xml FILE_NAME='t1.xml'
+ OPTION_LIST='xmlsup=libxml2,rownode=line,encoding=iso-8859-1';
+INSERT INTO t1 VALUES (_latin1 0xC0C1C2C3);
+INSERT INTO t1 VALUES (_cp1251 0xC0C1C2C3);
+INSERT INTO t1 VALUES ('&<>"\'');
+SELECT node, hex(node) FROM t1;
+DROP TABLE t1;
+--chmod 0777 $MYSQLD_DATADIR/test/t1.xml
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--eval SET @a=LOAD_FILE('$MYSQLD_DATADIR/test/t1.xml')
+SELECT CAST(@a AS CHAR CHARACTER SET latin1);
+--remove_file $MYSQLD_DATADIR/test/t1.xml
+
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/xsample.xml
+--remove_file $MYSQLD_DATADIR/test/latin1.xml
+--remove_file $MYSQLD_DATADIR/test/cp1251.xml
diff --git a/storage/connect/mysql-test/connect/t/xml2_grant.test b/storage/connect/mysql-test/connect/t/xml2_grant.test
new file mode 100644
index 00000000..26753c96
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml2_grant.test
@@ -0,0 +1,8 @@
+-- source include/not_embedded.inc
+-- source have_libxml2.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+let $TABLE_OPTIONS=TABLE_TYPE=XML OPTION_LIST='xmlsup=libxml2,rownode=row';
+let $FILE_EXT=XML;
+--source grant.inc
diff --git a/storage/connect/mysql-test/connect/t/xml2_html.test b/storage/connect/mysql-test/connect/t/xml2_html.test
new file mode 100644
index 00000000..2f4fc50e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml2_html.test
@@ -0,0 +1,39 @@
+--source have_libxml2.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+SET NAMES utf8;
+
+--copy_file $MTR_SUITE_DIR/std_data/beers.xml $MYSQLD_DATADIR/test/beers.xml
+--copy_file $MTR_SUITE_DIR/std_data/coffee.htm $MYSQLD_DATADIR/test/coffee.htm
+
+--echo #
+--echo # Testing HTML like XML file
+--echo #
+CREATE TABLE beers (
+`Name` CHAR(16) XPATH='brandName',
+`Origin` CHAR(16) XPATH='origin',
+`Description` CHAR(32) XPATH='details')
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='beers.xml'
+TABNAME='table' OPTION_LIST='xmlsup=libxml2,rownode=tr,colnode=td';
+SELECT * FROM beers;
+DROP TABLE beers;
+
+--echo #
+--echo # Testing HTML file
+--echo #
+CREATE TABLE coffee (
+`Name` CHAR(16),
+`Cups` INT(8),
+`Type` CHAR(16),
+`Sugar` CHAR(4))
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='coffee.htm'
+TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=libxml2,Coltype=HTML';
+SELECT * FROM coffee;
+DROP TABLE coffee;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/beers.xml
+--remove_file $MYSQLD_DATADIR/test/coffee.htm
diff --git a/storage/connect/mysql-test/connect/t/xml2_mdev5261.test b/storage/connect/mysql-test/connect/t/xml2_mdev5261.test
new file mode 100644
index 00000000..16640c8b
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml2_mdev5261.test
@@ -0,0 +1,27 @@
+--source have_libxml2.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+SET NAMES utf8;
+
+#
+#--echo Testing indexing on not indexable table type
+#
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=libxml2,Rownode=N';
+CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=libxml2,Rownode=N';
+DESCRIBE t1;
+# one could *add* an index to an existing table
+--error ER_UNKNOWN_ERROR
+ALTER TABLE t1 ADD UNIQUE(i);
+--error ER_UNKNOWN_ERROR
+CREATE UNIQUE INDEX i ON t1(i);
+DESCRIBE t1;
+INSERT INTO t1 VALUES(2),(5),(7);
+SELECT * FROM t1 WHERE i = 5;
+--error ER_CANT_DROP_FIELD_OR_KEY
+ALTER TABLE t1 DROP INDEX i;
+--error ER_CANT_DROP_FIELD_OR_KEY
+DROP INDEX i ON t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/xt1.xml
diff --git a/storage/connect/mysql-test/connect/t/xml2_mult.test b/storage/connect/mysql-test/connect/t/xml2_mult.test
new file mode 100644
index 00000000..e9914c71
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml2_mult.test
@@ -0,0 +1,64 @@
+--source have_libxml2.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+SET NAMES utf8;
+
+--copy_file $MTR_SUITE_DIR/std_data/bookstore.xml $MYSQLD_DATADIR/test/bookstore.xml
+
+#--echo $MYSQL_TEST_DIR
+#--exec pwd
+#SELECT LOAD_FILE('test/bookstore.xml');
+
+
+--echo #
+--echo # Testing expanded values
+--echo #
+CREATE TABLE `bookstore` (
+ `category` CHAR(16) NOT NULL XPATH='@',
+ `title` VARCHAR(50) NOT NULL,
+ `lang` char(2) NOT NULL XPATH='title/@',
+ `author` VARCHAR(24) NOT NULL,
+ `year` INT(4) NOT NULL,
+ `price` DOUBLE(8,2) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=libxml2';
+SELECT * FROM bookstore;
+SELECT category, title, price FROM bookstore;
+SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%';
+SELECT category, title, price FROM bookstore WHERE author LIKE 'J%';
+
+
+--echo #
+--echo # Limiting expanded values
+--echo #
+ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=libxml2';
+SELECT * FROM bookstore;
+--echo # One line lost because the where clause is applied only on the first 3 rows
+SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
+
+
+--echo #
+--echo # Testing concatenated values
+--echo #
+ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=libxml2';
+--echo # truncated
+SELECT * FROM bookstore;
+--echo # increase author size
+ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL;
+SELECT * FROM bookstore;
+
+
+--echo #
+--echo # Limiting concatenated values
+--echo #
+ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=libxml2';
+SELECT * FROM bookstore;
+--echo # The where clause is applied on the concatenated column result
+SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
+DROP TABLE bookstore;
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/bookstore.xml
diff --git a/storage/connect/mysql-test/connect/t/xml2_zip.test b/storage/connect/mysql-test/connect/t/xml2_zip.test
new file mode 100644
index 00000000..df69f9da
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml2_zip.test
@@ -0,0 +1,41 @@
+--source have_zip.inc
+--source have_libxml2.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--vertical_results
+
+--copy_file $MTR_SUITE_DIR/std_data/xsample2.xml $MYSQLD_DATADIR/test/xsample2.xml
+
+--echo #
+--echo # Testing zipped XML tables
+--echo #
+CREATE TABLE t1 (
+ISBN CHAR(13) NOT NULL XPATH='@',
+LANG CHAR(2) NOT NULL XPATH='@',
+SUBJECT CHAR(12) NOT NULL XPATH='@',
+AUTHOR_FIRSTNAME CHAR(15) NOT NULL XPATH='AUTHOR/FIRSTNAME',
+AUTHOR_LASTNAME CHAR(8) NOT NULL XPATH='AUTHOR/LASTNAME',
+TRANSLATOR_PREFIX CHAR(24) DEFAULT NULL XPATH='TRANSLATOR/@PREFIX',
+TRANSLATOR_FIRSTNAME CHAR(6) DEFAULT NULL XPATH='TRANSLATOR/FIRSTNAME',
+TRANSLATOR_LASTNAME CHAR(6) DEFAULT NULL XPATH='TRANSLATOR/LASTNAME',
+TITLE CHAR(30) NOT NULL,
+PUBLISHER_NAME CHAR(15) NOT NULL XPATH='PUBLISHER/NAME',
+PUBLISHER_PLACE CHAR(5) NOT NULL XPATH='PUBLISHER/PLACE',
+DATEPUB CHAR(4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES
+OPTION_LIST='depth=0,entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=libxml2,expand=1,mulnode=AUTHOR';
+SELECT * FROM t1;
+
+#testing discovery
+CREATE TABLE t2
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES
+OPTION_LIST='depth=0,xmlsup=libxml2';
+SELECT * FROM t2;
+DROP TABLE t1,t2;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/xsample2.xml
+--remove_file $MYSQLD_DATADIR/test/xsample2.zip
diff --git a/storage/connect/mysql-test/connect/t/xml_grant.test b/storage/connect/mysql-test/connect/t/xml_grant.test
new file mode 100644
index 00000000..94f640b9
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml_grant.test
@@ -0,0 +1,8 @@
+-- source include/not_embedded.inc
+-- source windows.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+let $TABLE_OPTIONS=TABLE_TYPE=XML OPTION_LIST='xmlsup=domdoc,rownode=row';
+let $FILE_EXT=XML;
+--source grant.inc
diff --git a/storage/connect/mysql-test/connect/t/xml_html.test b/storage/connect/mysql-test/connect/t/xml_html.test
new file mode 100644
index 00000000..1430f68d
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml_html.test
@@ -0,0 +1,39 @@
+--source windows.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+SET NAMES utf8;
+
+--copy_file $MTR_SUITE_DIR/std_data/beers.xml $MYSQLD_DATADIR/test/beers.xml
+--copy_file $MTR_SUITE_DIR/std_data/coffee.htm $MYSQLD_DATADIR/test/coffee.htm
+
+--echo #
+--echo # Testing HTML like XML file
+--echo #
+CREATE TABLE beers (
+`Name` CHAR(16) XPATH='brandName',
+`Origin` CHAR(16) XPATH='origin',
+`Description` CHAR(32) XPATH='details')
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='beers.xml'
+TABNAME='table' OPTION_LIST='xmlsup=domdoc,rownode=tr,colnode=td';
+SELECT * FROM beers;
+DROP TABLE beers;
+
+--echo #
+--echo # Testing HTML file
+--echo #
+CREATE TABLE coffee (
+`Name` CHAR(16),
+`Cups` INT(8),
+`Type` CHAR(16),
+`Sugar` CHAR(4))
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='coffee.htm'
+TABNAME='TABLE' HEADER=1 OPTION_LIST='xmlsup=domdoc,Coltype=HTML';
+SELECT * FROM coffee;
+DROP TABLE coffee;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/beers.xml
+--remove_file $MYSQLD_DATADIR/test/coffee.htm
diff --git a/storage/connect/mysql-test/connect/t/xml_mdev5261.test b/storage/connect/mysql-test/connect/t/xml_mdev5261.test
new file mode 100644
index 00000000..25cace50
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml_mdev5261.test
@@ -0,0 +1,27 @@
+--source windows.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+SET NAMES utf8;
+
+#
+#--echo Testing indexing on not indexable table type
+#
+--error ER_UNKNOWN_ERROR
+CREATE TABLE t1 (i INT UNIQUE NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=domdoc,Rownode=N';
+CREATE TABLE t1 (i INT NOT NULL) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xt1.xml' OPTION_LIST='xmlsup=domdoc,Rownode=N';
+DESCRIBE t1;
+# one could *add* an index to an existing table
+--error ER_UNKNOWN_ERROR
+ALTER TABLE t1 ADD UNIQUE(i);
+--error ER_UNKNOWN_ERROR
+CREATE UNIQUE INDEX i ON t1(i);
+DESCRIBE t1;
+INSERT INTO t1 VALUES(2),(5),(7);
+SELECT * FROM t1 WHERE i = 5;
+--error ER_CANT_DROP_FIELD_OR_KEY
+ALTER TABLE t1 DROP INDEX i;
+--error ER_CANT_DROP_FIELD_OR_KEY
+DROP INDEX i ON t1;
+DROP TABLE t1;
+--remove_file $MYSQLD_DATADIR/test/xt1.xml
diff --git a/storage/connect/mysql-test/connect/t/xml_mult.test b/storage/connect/mysql-test/connect/t/xml_mult.test
new file mode 100644
index 00000000..221d6734
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml_mult.test
@@ -0,0 +1,64 @@
+--source windows.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+SET NAMES utf8;
+
+--copy_file $MTR_SUITE_DIR/std_data/bookstore.xml $MYSQLD_DATADIR/test/bookstore.xml
+
+#--echo $MYSQL_TEST_DIR
+#--exec pwd
+#SELECT LOAD_FILE('test/bookstore.xml');
+
+
+--echo #
+--echo # Testing expanded values
+--echo #
+CREATE TABLE `bookstore` (
+ `category` CHAR(16) NOT NULL XPATH='@',
+ `title` VARCHAR(50) NOT NULL,
+ `lang` char(2) NOT NULL XPATH='title/@',
+ `author` VARCHAR(24) NOT NULL,
+ `year` INT(4) NOT NULL,
+ `price` DOUBLE(8,2) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='bookstore.xml' OPTION_LIST='expand=1,mulnode=author,limit=6,xmlsup=domdoc';
+SELECT * FROM bookstore;
+SELECT category, title, price FROM bookstore;
+SELECT category, title, author, price FROM bookstore WHERE author LIKE '%K%';
+SELECT category, title, price FROM bookstore WHERE author LIKE 'J%';
+
+
+--echo #
+--echo # Limiting expanded values
+--echo #
+ALTER TABLE bookstore OPTION_LIST='expand=1,mulnode=author,limit=3,xmlsup=domdoc';
+SELECT * FROM bookstore;
+--echo # One line lost because the where clause is applied only on the first 3 rows
+SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
+
+
+--echo #
+--echo # Testing concatenated values
+--echo #
+ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=6,xmlsup=domdoc';
+--echo # truncated
+SELECT * FROM bookstore;
+--echo # increase author size
+ALTER TABLE bookstore MODIFY `author` VARCHAR(128) NOT NULL;
+SELECT * FROM bookstore;
+
+
+--echo #
+--echo # Limiting concatenated values
+--echo #
+ALTER TABLE bookstore OPTION_LIST='mulnode=author,limit=4,xmlsup=domdoc';
+SELECT * FROM bookstore;
+--echo # The where clause is applied on the concatenated column result
+SELECT category, title, author, price FROM bookstore WHERE author LIKE 'J%';
+DROP TABLE bookstore;
+
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/bookstore.xml
diff --git a/storage/connect/mysql-test/connect/t/xml_zip.test b/storage/connect/mysql-test/connect/t/xml_zip.test
new file mode 100644
index 00000000..29ee2e0e
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/xml_zip.test
@@ -0,0 +1,41 @@
+--source have_zip.inc
+--source windows.inc
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--vertical_results
+
+--copy_file $MTR_SUITE_DIR/std_data/xsample2.xml $MYSQLD_DATADIR/test/xsample2.xml
+
+--echo #
+--echo # Testing zipped XML tables
+--echo #
+CREATE TABLE t1 (
+ISBN CHAR(13) NOT NULL XPATH='@',
+LANG CHAR(2) NOT NULL XPATH='@',
+SUBJECT CHAR(12) NOT NULL XPATH='@',
+AUTHOR_FIRSTNAME CHAR(15) NOT NULL XPATH='AUTHOR/FIRSTNAME',
+AUTHOR_LASTNAME CHAR(8) NOT NULL XPATH='AUTHOR/LASTNAME',
+TRANSLATOR_PREFIX CHAR(24) DEFAULT NULL XPATH='TRANSLATOR/@PREFIX',
+TRANSLATOR_FIRSTNAME CHAR(6) DEFAULT NULL XPATH='TRANSLATOR/FIRSTNAME',
+TRANSLATOR_LASTNAME CHAR(6) DEFAULT NULL XPATH='TRANSLATOR/LASTNAME',
+TITLE CHAR(30) NOT NULL,
+PUBLISHER_NAME CHAR(15) NOT NULL XPATH='PUBLISHER/NAME',
+PUBLISHER_PLACE CHAR(5) NOT NULL XPATH='PUBLISHER/PLACE',
+DATEPUB CHAR(4) NOT NULL
+) ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES
+OPTION_LIST='depth=0,entry=xsample2.xml,load=xsample2.xml,rownode=BOOK,xmlsup=domdoc,expand=1,mulnode=AUTHOR';
+SELECT * FROM t1;
+
+#testing discovery
+CREATE TABLE t2
+ENGINE=CONNECT TABLE_TYPE=XML FILE_NAME='xsample2.zip' ZIPPED=YES
+OPTION_LIST='depth=0,xmlsup=domdoc';
+SELECT * FROM t2;
+DROP TABLE t1,t2;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/xsample2.xml
+--remove_file $MYSQLD_DATADIR/test/xsample2.zip
diff --git a/storage/connect/mysql-test/connect/t/zip.test b/storage/connect/mysql-test/connect/t/zip.test
new file mode 100644
index 00000000..1f0a4eed
--- /dev/null
+++ b/storage/connect/mysql-test/connect/t/zip.test
@@ -0,0 +1,136 @@
+--source have_zip.inc
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+--copy_file $MTR_SUITE_DIR/std_data/bios.json $MYSQLD_DATADIR/test/bios.json
+
+--echo #
+--echo # Testing zipped DOS tables
+--echo #
+CREATE TABLE t1 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='newdos.zip'
+OPTION_LIST='ENTRY=new1.dos' ZIPPED=1;
+INSERT INTO t1 VALUES(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five'),(6,'Six'),(7,'Seven'),(8,'Eight'),(9,'Nine'),(10,'Ten');
+SELECT * FROM t1;
+
+CREATE TABLE t2 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='newdos.zip'
+OPTION_LIST='ENTRY=new2.dos,APPEND=1' ZIPPED=1;
+INSERT INTO t2 VALUES(11,'Eleven'),(12,'Twelve'),(13,'Thirteen'),(14,'Fourteen'),(15,'Fiften'),(16,'Sixteen'),(17,'Seventeen'),(18,'Eighteen'),(19,'Nineteen'),(20,'Twenty');
+SELECT * FROM t2;
+
+CREATE TABLE t3 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=DOS FILE_NAME='newdos.zip'
+OPTION_LIST='MULENTRIES=1' ZIPPED=1;
+SELECT * FROM t3;
+
+CREATE TABLE t4 (
+fn VARCHAR(256)NOT NULL,
+cmpsize BIGINT NOT NULL FLAG=1,
+uncsize BIGINT NOT NULL FLAG=2,
+method INT NOT NULL FLAG=3)
+ENGINE=CONNECT TABLE_TYPE=ZIP FILE_NAME='newdos.zip';
+SELECT * FROM t4;
+DROP TABLE t1,t2,t3,t4;
+
+--echo #
+--echo # Testing zipped CSV tables
+--echo #
+CREATE TABLE t1 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='newcsv.zip'
+OPTION_LIST='ENTRY=new1.csv' HEADER=1 ZIPPED=1;
+INSERT INTO t1 VALUES(1,'One'),(2,'Two'),(3,'Three'),(4,'Four'),(5,'Five'),(6,'Six'),(7,'Seven'),(8,'Eight'),(9,'Nine'),(10,'Ten');
+SELECT * FROM t1;
+
+# Test discovery
+CREATE TABLE td1
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='newcsv.zip'
+OPTION_LIST='ENTRY=new1.csv' HEADER=1 ZIPPED=1;
+SELECT * FROM td1;
+DROP TABLE td1;
+
+CREATE TABLE t2 (
+digit INT(3) NOT NULL,
+letter CHAR(16) NOT NULL)
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='newcsv.zip'
+OPTION_LIST='ENTRY=new2.csv,APPEND=1' HEADER=1 ZIPPED=1;
+INSERT INTO t2 VALUES(11,'Eleven'),(12,'Twelve'),(13,'Thirteen'),(14,'Fourteen'),(15,'Fiften'),(16,'Sixteen'),(17,'Seventeen'),(18,'Eighteen'),(19,'Nineteen'),(20,'Twenty');
+SELECT * FROM t2;
+
+CREATE TABLE t3
+ENGINE=CONNECT TABLE_TYPE=CSV FILE_NAME='newcsv.zip'
+OPTION_LIST='MULENTRIES=1' HEADER=1 ZIPPED=1;
+SELECT * FROM t3;
+
+CREATE TABLE t4 (
+fn VARCHAR(256)NOT NULL,
+cmpsize BIGINT NOT NULL FLAG=1,
+uncsize BIGINT NOT NULL FLAG=2,
+method INT NOT NULL FLAG=3)
+ENGINE=CONNECT TABLE_TYPE=ZIP FILE_NAME='newcsv.zip';
+SELECT * FROM t4;
+DROP TABLE t1,t2,t3,t4;
+
+--echo #
+--echo # Testing zipped JSON tables
+--echo #
+CREATE TABLE t1 (
+_id INT(2) NOT NULL,
+name_first CHAR(9) NOT NULL JPATH='$.name.first',
+name_aka CHAR(4) DEFAULT NULL JPATH='$.name.aka',
+name_last CHAR(10) NOT NULL JPATH='$.name.last',
+title CHAR(12) DEFAULT NULL,
+birth CHAR(20) DEFAULT NULL,
+death CHAR(20) DEFAULT NULL,
+contribs CHAR(50) NOT NULL JPATH='$.contribs',
+awards_award CHAR(42) DEFAULT NULL JPATH='$.awards.award',
+awards_year CHAR(4) DEFAULT NULL JPATH='$.awards.year',
+awards_by CHAR(38) DEFAULT NULL JPATH='$.awards.by'
+) ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bios.zip' OPTION_LIST='ENTRY=bios.json,LOAD=bios.json' ZIPPED=YES;
+SELECT * FROM t1;
+
+# Test discovery
+CREATE TABLE t2
+ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='bios.zip' ZIPPED=1
+OPTION_LIST='DEPTH=5';
+SELECT * FROM t2;
+
+CREATE TABLE t3 (
+_id INT(2) NOT NULL,
+firstname CHAR(9) NOT NULL JPATH='$.name.first',
+aka CHAR(4) DEFAULT NULL JPATH='$.name.aka',
+lastname CHAR(10) NOT NULL JPATH='$.name.last',
+title CHAR(12) DEFAULT NULL,
+birth date DEFAULT NULL date_format="YYYY-DD-MM'T'hh:mm:ss'Z'",
+death date DEFAULT NULL date_format="YYYY-DD-MM'T'hh:mm:ss'Z'",
+contribs CHAR(64) NOT NULL JPATH='$.contribs.[", "]',
+award CHAR(42) DEFAULT NULL JPATH='$.awards[*].award',
+year CHAR(4) DEFAULT NULL JPATH='$.awards[*].year',
+`by` CHAR(38) DEFAULT NULL JPATH='$.awards[*].by'
+) ENGINE=CONNECT TABLE_TYPE='json' FILE_NAME='bios.zip' ZIPPED=YES;
+SELECT * FROM t3 WHERE _id = 1;
+
+CREATE TABLE t4 (
+fn VARCHAR(256)NOT NULL,
+cmpsize BIGINT NOT NULL FLAG=1,
+uncsize BIGINT NOT NULL FLAG=2,
+method INT NOT NULL FLAG=3)
+ENGINE=CONNECT TABLE_TYPE=ZIP FILE_NAME='bios.zip';
+SELECT * FROM t4;
+DROP TABLE t1,t2,t3,t4;
+
+#
+# Clean up
+#
+--remove_file $MYSQLD_DATADIR/test/newdos.zip
+--remove_file $MYSQLD_DATADIR/test/newcsv.zip
+--remove_file $MYSQLD_DATADIR/test/bios.zip
+--remove_file $MYSQLD_DATADIR/test/bios.json
+
diff --git a/storage/connect/myutil.cpp b/storage/connect/myutil.cpp
new file mode 100644
index 00000000..c49db48b
--- /dev/null
+++ b/storage/connect/myutil.cpp
@@ -0,0 +1,318 @@
+/************** MyUtil C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: MYUTIL */
+/* ------------- */
+/* Version 1.2 */
+/* */
+/* Author Olivier BERTRAND 2014 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* It contains utility functions to convert data types. */
+/* It can optionally use the embedded MySQL library. */
+/* */
+/************************************************************************/
+#include "my_global.h"
+#include <mysql.h>
+#if defined(_WIN32)
+//#include <windows.h>
+#else // !_WIN32
+#include "osutil.h"
+#endif // !_WIN32
+
+#include "global.h"
+#include "plgdbsem.h"
+//#include "value.h"
+//#include "valblk.h"
+#include "myutil.h"
+#define DLL_EXPORT // Items are exported from this DLL
+
+//extern "C" int xconv;
+TYPCONV GetTypeConv(void);
+
+/************************************************************************/
+/* Convert from MySQL type name to PlugDB type number */
+/************************************************************************/
+int MYSQLtoPLG(char *typname, char *var)
+ {
+ int type;
+ TYPCONV xconv = GetTypeConv();
+
+ if (!stricmp(typname, "int") || !stricmp(typname, "mediumint") ||
+ !stricmp(typname, "integer"))
+ type = TYPE_INT;
+ else if (!stricmp(typname, "smallint"))
+ type = TYPE_SHORT;
+ else if (!stricmp(typname, "char") || !stricmp(typname, "varchar") ||
+ !stricmp(typname, "enum") || !stricmp(typname, "set"))
+ type = TYPE_STRING;
+ else if (!stricmp(typname, "double") || !stricmp(typname, "float") ||
+ !stricmp(typname, "real"))
+ type = TYPE_DOUBLE;
+ else if (!stricmp(typname, "decimal") || !stricmp(typname, "numeric"))
+ type = TYPE_DECIM;
+ else if (!stricmp(typname, "date") || !stricmp(typname, "datetime") ||
+ !stricmp(typname, "time") || !stricmp(typname, "timestamp") ||
+ !stricmp(typname, "year"))
+ type = TYPE_DATE;
+ else if (!stricmp(typname, "bigint") || !stricmp(typname, "longlong"))
+ type = TYPE_BIGINT;
+ else if (!stricmp(typname, "tinyint"))
+ type = TYPE_TINY;
+ else if (!stricmp(typname, "text") && var) {
+ switch (xconv) {
+ case TPC_YES:
+ type = TYPE_STRING;
+ *var = 'X';
+ break;
+ case TPC_SKIP:
+ *var = 'K';
+ /* falls through */
+ default: // TPC_NO
+ type = TYPE_ERROR;
+ } // endswitch xconv
+
+ return type;
+ } else
+ type = TYPE_ERROR;
+
+ if (var) {
+ if (type == TYPE_DATE) {
+ // This is to make the difference between temporal values
+ if (!stricmp(typname, "date"))
+ *var = 'D';
+ else if (!stricmp(typname, "datetime"))
+ *var = 'A';
+ else if (!stricmp(typname, "timestamp"))
+ *var = 'S';
+ else if (!stricmp(typname, "time"))
+ *var = 'T';
+ else if (!stricmp(typname, "year"))
+ *var = 'Y';
+
+ } else if (type == TYPE_STRING) {
+ if (!stricmp(typname, "varchar"))
+ // This is to make the difference between CHAR and VARCHAR
+ *var = 'V';
+
+ } else if (type == TYPE_ERROR && xconv == TPC_SKIP)
+ *var = 'K';
+ else
+ *var = 0;
+
+ } // endif var
+
+ return type;
+ } // end of MYSQLtoPLG
+
+/************************************************************************/
+/* Convert from PlugDB type to MySQL type number */
+/************************************************************************/
+enum enum_field_types PLGtoMYSQL(int type, bool dbf, char v)
+ {
+ enum enum_field_types mytype;
+
+ switch (type) {
+ case TYPE_INT:
+ mytype = MYSQL_TYPE_LONG;
+ break;
+ case TYPE_SHORT:
+ mytype = MYSQL_TYPE_SHORT;
+ break;
+ case TYPE_DOUBLE:
+ mytype = MYSQL_TYPE_DOUBLE;
+ break;
+ case TYPE_DATE:
+ mytype = (dbf) ? MYSQL_TYPE_DATE :
+ (v == 'S') ? MYSQL_TYPE_TIMESTAMP :
+ (v == 'D') ? MYSQL_TYPE_NEWDATE :
+ (v == 'T') ? MYSQL_TYPE_TIME :
+ (v == 'Y') ? MYSQL_TYPE_YEAR : MYSQL_TYPE_DATETIME;
+ break;
+ case TYPE_STRING:
+ mytype = (v) ? MYSQL_TYPE_VARCHAR : MYSQL_TYPE_STRING;
+ break;
+ case TYPE_BIGINT:
+ mytype = MYSQL_TYPE_LONGLONG;
+ break;
+ case TYPE_TINY:
+ mytype = MYSQL_TYPE_TINY;
+ break;
+ case TYPE_DECIM:
+#if !defined(ALPHA)
+ mytype = MYSQL_TYPE_NEWDECIMAL;
+#else // ALPHA
+ mytype = MYSQL_TYPE_DECIMAL;
+#endif // ALPHA
+ break;
+ default:
+ mytype = MYSQL_TYPE_NULL;
+ } // endswitch mytype
+
+ return mytype;
+ } // end of PLGtoMYSQL
+
+/************************************************************************/
+/* Convert from PlugDB type to MySQL type name */
+/************************************************************************/
+const char *PLGtoMYSQLtype(int type, bool dbf, char v)
+ {
+ switch (type) {
+ case TYPE_INT: return "INT";
+ case TYPE_SHORT: return "SMALLINT";
+ case TYPE_DOUBLE: return "DOUBLE";
+ case TYPE_DATE: return dbf ? "DATE" :
+ (v == 'S') ? "TIMESTAMP" :
+ (v == 'D') ? "DATE" :
+ (v == 'T') ? "TIME" :
+ (v == 'Y') ? "YEAR" : "DATETIME";
+ case TYPE_STRING: return v ? "VARCHAR" : "CHAR";
+ case TYPE_BIGINT: return "BIGINT";
+ case TYPE_TINY: return "TINYINT";
+ case TYPE_DECIM: return "DECIMAL";
+ default: return (v) ? "VARCHAR" : "CHAR";
+ } // endswitch mytype
+
+ } // end of PLGtoMYSQLtype
+
+/************************************************************************/
+/* Convert from MySQL type to PlugDB type number */
+/************************************************************************/
+int MYSQLtoPLG(int mytype, char *var)
+ {
+ int type, xconv = GetTypeConv();
+
+ switch (mytype) {
+ case MYSQL_TYPE_SHORT:
+ type = TYPE_SHORT;
+ break;
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_ENUM: // ???
+ type = TYPE_INT;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ type = TYPE_BIGINT;
+ break;
+ case MYSQL_TYPE_TINY:
+ type = TYPE_TINY;
+ break;
+ case MYSQL_TYPE_DECIMAL:
+#if !defined(ALPHA)
+ case MYSQL_TYPE_NEWDECIMAL:
+#endif // !ALPHA)
+ type = TYPE_DECIM;
+ break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ type = TYPE_DOUBLE;
+ break;
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_YEAR:
+ case MYSQL_TYPE_TIME:
+ type = TYPE_DATE;
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+#if !defined(ALPHA)
+ case MYSQL_TYPE_VARCHAR:
+#endif // !ALPHA)
+ case MYSQL_TYPE_STRING:
+ type = (*var == 'B') ? TYPE_BIN : TYPE_STRING;
+ break;
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ if (var) {
+ switch (xconv) {
+ case TPC_YES:
+ if (*var != 'B') {
+ // This is a TEXT column
+ type = TYPE_STRING;
+ *var = 'X';
+ } else
+ type = TYPE_BIN;
+
+ break;
+ case TPC_SKIP:
+ *var = 'K'; // Skip
+ /* falls through */
+ default: // TPC_NO
+ type = TYPE_ERROR;
+ } // endswitch xconv
+
+ return type;
+ } // endif var
+ /* falls through */
+ default:
+ type = TYPE_ERROR;
+ } // endswitch mytype
+
+ if (var) switch (mytype) {
+ // This is to make the difference between CHAR and VARCHAR
+#if !defined(ALPHA)
+ case MYSQL_TYPE_VARCHAR:
+#endif // !ALPHA)
+ case MYSQL_TYPE_VAR_STRING: *var = 'V'; break;
+ // This is to make the difference between temporal values
+ case MYSQL_TYPE_TIMESTAMP: *var = 'S'; break;
+ case MYSQL_TYPE_DATE: *var = 'D'; break;
+ case MYSQL_TYPE_DATETIME: *var = 'A'; break;
+ case MYSQL_TYPE_YEAR: *var = 'Y'; break;
+ case MYSQL_TYPE_TIME: *var = 'T'; break;
+ default: *var = 0;
+ } // endswitch mytype
+
+ return type;
+ } // end of MYSQLtoPLG
+
+/************************************************************************/
+/* Returns the format corresponding to a MySQL date type number. */
+/************************************************************************/
+PCSZ MyDateFmt(int mytype)
+ {
+ PCSZ fmt;
+
+ switch (mytype) {
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ fmt = "YYYY-MM-DD hh:mm:ss";
+ break;
+ case MYSQL_TYPE_DATE:
+ fmt = "YYYY-MM-DD";
+ break;
+ case MYSQL_TYPE_YEAR:
+ fmt = "YYYY";
+ break;
+ case MYSQL_TYPE_TIME:
+ fmt = "hh:mm:ss";
+ break;
+ default:
+ fmt = NULL;
+ } // endswitch mytype
+
+ return fmt;
+ } // end of MyDateFmt
+
+/************************************************************************/
+/* Returns the format corresponding to a MySQL date type name. */
+/************************************************************************/
+PCSZ MyDateFmt(char *typname)
+ {
+ PCSZ fmt;
+
+ if (!stricmp(typname, "datetime") || !stricmp(typname, "timestamp"))
+ fmt = "YYYY-MM-DD hh:mm:ss";
+ else if (!stricmp(typname, "date"))
+ fmt = "YYYY-MM-DD";
+ else if (!stricmp(typname, "year"))
+ fmt = "YYYY";
+ else if (!stricmp(typname, "time"))
+ fmt = "hh:mm:ss";
+ else
+ fmt = NULL;
+
+ return fmt;
+ } // end of MyDateFmt
+
diff --git a/storage/connect/myutil.h b/storage/connect/myutil.h
new file mode 100644
index 00000000..fa41fa47
--- /dev/null
+++ b/storage/connect/myutil.h
@@ -0,0 +1,14 @@
+/***********************************************************************/
+/* Prototypes of Functions used externally. */
+/***********************************************************************/
+#ifndef __MYUTIL__H
+#define __MYUTIL__H
+
+enum enum_field_types PLGtoMYSQL(int type, bool dbf, char var = 0);
+const char *PLGtoMYSQLtype(int type, bool dbf, char var = 0);
+int MYSQLtoPLG(char *typname, char *var);
+int MYSQLtoPLG(int mytype, char *var);
+PCSZ MyDateFmt(int mytype);
+PCSZ MyDateFmt(char *typname);
+
+#endif // __MYUTIL__H
diff --git a/storage/connect/noconst.c b/storage/connect/noconst.c
new file mode 100644
index 00000000..043eae7c
--- /dev/null
+++ b/storage/connect/noconst.c
@@ -0,0 +1,38 @@
+/***********************************************************************/
+/* (C) Copyright to the author Olivier BERTRAND 2015 */
+/***********************************************************************/
+#include <my_global.h>
+#include <mysqld.h>
+#include <string.h>
+
+#if defined(__WIN__)
+#define DllExport __declspec( dllexport )
+#else // !__WIN__
+#define DllExport
+#endif // !__WIN__
+
+extern "C" {
+ DllExport my_bool noconst_init(UDF_INIT*, UDF_ARGS*, char*);
+ DllExport char *noconst(UDF_INIT*, UDF_ARGS*, char*, unsigned long*, char*, char*);
+} // extern "C"
+
+/***********************************************************************/
+/* Returns its argument saying it is not a constant. */
+/***********************************************************************/
+my_bool noconst_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "noconst unique argument must be a string");
+ return true;
+ } // endif arg
+
+ initid->const_item = false; // The trick!
+ return false;
+} // end of noconst_init
+
+char *noconst(UDF_INIT *initid, UDF_ARGS *args, char *result,
+ unsigned long *res_length, char *, char *)
+{
+ return args->args[0];
+} // end of noconst
+
diff --git a/storage/connect/odbccat.h b/storage/connect/odbccat.h
new file mode 100644
index 00000000..05b82e49
--- /dev/null
+++ b/storage/connect/odbccat.h
@@ -0,0 +1,25 @@
+// Timeout and net wait defaults
+#define DEFAULT_LOGIN_TIMEOUT -1 // means do not set
+#define DEFAULT_QUERY_TIMEOUT -1 // means do not set
+
+typedef struct odbc_parms {
+ PCSZ User; // User connect info
+ PCSZ Pwd; // Password connect info
+ int Cto; // Connect timeout
+ int Qto; // Query timeout
+ bool UseCnc; // Use SQLConnect (!SQLDriverConnect)
+ } ODBCPARM, *POPARM;
+
+/***********************************************************************/
+/* ODBC catalog function prototypes. */
+/***********************************************************************/
+#if defined(PROMPT_OK)
+char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop);
+#endif // PROMPT_OK
+PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info);
+PQRYRES ODBCColumns(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ table,
+ PCSZ colpat, int maxres, bool info, POPARM sop);
+PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, POPARM sop);
+PQRYRES ODBCTables(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ tabpat,
+ PCSZ tabtyp, int maxres, bool info, POPARM sop);
+PQRYRES ODBCDrivers(PGLOBAL g, int maxres, bool info);
diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp
new file mode 100644
index 00000000..d7a7bf19
--- /dev/null
+++ b/storage/connect/odbconn.cpp
@@ -0,0 +1,2639 @@
+/***********************************************************************/
+/* Name: ODBCONN.CPP Version 2.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2017 */
+/* */
+/* This file contains the ODBC connection classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+#include <m_string.h>
+#if defined(_WIN32)
+//nclude <io.h>
+//nclude <fcntl.h>
+#include <direct.h> // for getcwd
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else
+#if defined(UNIX)
+#include <errno.h>
+#else
+//nclude <io.h>
+#endif
+//nclude <fcntl.h>
+#define NODW
+#endif
+
+/***********************************************************************/
+/* Required objects includes. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xobject.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "odbccat.h"
+#include "tabodbc.h"
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+#include "valblk.h"
+#include "osutil.h"
+
+
+#if defined(_WIN32)
+/***********************************************************************/
+/* For dynamic load of ODBC32.DLL */
+/***********************************************************************/
+#pragma comment(lib, "odbc32.lib")
+extern "C" HINSTANCE s_hModule; // Saved module handle
+#endif // _WIN32
+
+TYPCONV GetTypeConv();
+int GetConvSize();
+void OdbcClose(PGLOBAL g, PFBLOCK fp);
+
+/***********************************************************************/
+/* Some macro's (should be defined elsewhere to be more accessible) */
+/***********************************************************************/
+#if defined(_DEBUG)
+#define ASSERT(f) assert(f)
+#define DEBUG_ONLY(f) (f)
+#else // !_DEBUG
+#define ASSERT(f) ((void)0)
+#define DEBUG_ONLY(f) ((void)0)
+#endif // !_DEBUG
+
+/***********************************************************************/
+/* GetSQLType: returns the SQL_TYPE corresponding to a PLG type. */
+/***********************************************************************/
+static short GetSQLType(int type)
+ {
+ short tp = SQL_TYPE_NULL;
+
+ switch (type) {
+ case TYPE_STRING: tp = SQL_CHAR; break;
+ case TYPE_SHORT: tp = SQL_SMALLINT; break;
+ case TYPE_INT: tp = SQL_INTEGER; break;
+ case TYPE_DATE: tp = SQL_TIMESTAMP; break;
+ case TYPE_BIGINT: tp = SQL_BIGINT; break; // (-5)
+ case TYPE_DOUBLE: tp = SQL_DOUBLE; break;
+ case TYPE_TINY: tp = SQL_TINYINT; break;
+ case TYPE_DECIM: tp = SQL_DECIMAL; break;
+ } // endswitch type
+
+ return tp;
+ } // end of GetSQLType
+
+/***********************************************************************/
+/* GetSQLCType: returns the SQL_C_TYPE corresponding to a PLG type. */
+/***********************************************************************/
+static int GetSQLCType(int type)
+ {
+ int tp = SQL_TYPE_NULL;
+
+ switch (type) {
+ case TYPE_STRING: tp = SQL_C_CHAR; break;
+ case TYPE_SHORT: tp = SQL_C_SHORT; break;
+ case TYPE_INT: tp = SQL_C_LONG; break;
+ case TYPE_DATE: tp = SQL_C_TIMESTAMP; break;
+ case TYPE_BIGINT: tp = SQL_C_SBIGINT; break;
+ case TYPE_DOUBLE: tp = SQL_C_DOUBLE; break;
+ case TYPE_TINY : tp = SQL_C_TINYINT; break;
+//#if (ODBCVER >= 0x0300)
+// case TYPE_DECIM: tp = SQL_C_NUMERIC; break; (CRASH!!!)
+//#else
+ case TYPE_DECIM: tp = SQL_C_CHAR; break;
+//#endif
+
+ } // endswitch type
+
+ return tp;
+ } // end of GetSQLCType
+
+/***********************************************************************/
+/* TranslateSQLType: translate a SQL Type to a PLG type. */
+/***********************************************************************/
+int TranslateSQLType(int stp, int prec, int& len, char& v, bool& w)
+ {
+ int type;
+
+ switch (stp) {
+ case SQL_WVARCHAR: // (-9)
+ w = true;
+ case SQL_VARCHAR: // 12
+ v = 'V';
+ type = TYPE_STRING;
+ break;
+ case SQL_WCHAR: // (-8)
+ w = true;
+ case SQL_CHAR: // 1
+ type = TYPE_STRING;
+ break;
+ case SQL_WLONGVARCHAR: // (-10)
+ w = true;
+ case SQL_LONGVARCHAR: // (-1)
+ if (GetTypeConv() == TPC_YES || GetTypeConv() == TPC_FORCE) {
+ v = 'V';
+ type = TYPE_STRING;
+ len = (len) ? MY_MIN(abs(len), GetConvSize()) : GetConvSize();
+ } else
+ type = TYPE_ERROR;
+
+ break;
+ case SQL_NUMERIC: // 2
+ case SQL_DECIMAL: // 3
+// type = (prec || len > 20) ? TYPE_DOUBLE
+// : (len > 10) ? TYPE_BIGINT : TYPE_INT;
+ type = TYPE_DECIM;
+ break;
+ case SQL_INTEGER: // 4
+ type = TYPE_INT;
+ break;
+ case SQL_SMALLINT: // 5
+ type = TYPE_SHORT;
+ break;
+ case SQL_TINYINT: // (-6)
+ case SQL_BIT: // (-7)
+ type = TYPE_TINY;
+ break;
+ case SQL_FLOAT: // 6
+ case SQL_REAL: // 7
+ case SQL_DOUBLE: // 8
+ type = TYPE_DOUBLE;
+ break;
+ case SQL_DATETIME: // 9
+ type = TYPE_DATE;
+ len = 19;
+ break;
+ case SQL_TYPE_DATE: // 91
+ type = TYPE_DATE;
+ len = 10;
+ v = 'D';
+ break;
+ case SQL_INTERVAL: // 10
+ case SQL_TYPE_TIME: // 92
+ type = TYPE_STRING;
+ len = 8 + ((prec) ? (prec+1) : 0);
+ v = 'T';
+ break;
+ case SQL_TIMESTAMP: // 11
+ case SQL_TYPE_TIMESTAMP: // 93
+ type = TYPE_DATE;
+ len = 19 + ((prec) ? (prec+1) : 0);
+ v = 'S';
+ break;
+ case SQL_BIGINT: // (-5)
+ type = TYPE_BIGINT;
+ break;
+ case SQL_BINARY: // (-2)
+ case SQL_VARBINARY: // (-3)
+ case SQL_LONGVARBINARY: // (-4)
+ if (GetTypeConv() == TPC_FORCE) {
+ v = 'V';
+ type = TYPE_STRING;
+ len = (len) ? MY_MIN(abs(len), GetConvSize()) : GetConvSize();
+ } else
+ type = TYPE_ERROR;
+
+ break;
+ case SQL_GUID: // (-11)
+ type = TYPE_STRING;
+ len = 36;
+ break;
+ case SQL_UNKNOWN_TYPE: // 0
+ default:
+ type = TYPE_ERROR;
+ len = 0;
+ } // endswitch type
+
+ return type;
+ } // end of TranslateSQLType
+
+#if defined(PROMPT_OK)
+/***********************************************************************/
+/* ODBCCheckConnection: Check completeness of connection string. */
+/***********************************************************************/
+char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop)
+ {
+ char *newdsn, dir[_MAX_PATH], buf[_MAX_PATH];
+ int rc;
+ DWORD options = ODBConn::openReadOnly;
+ ODBConn *ocp = new(g) ODBConn(g, NULL);
+
+ (void) getcwd(dir, sizeof(dir) - 1);
+
+ switch (cop) {
+ case 1: options |= ODBConn::forceOdbcDialog; break;
+ case 2: options |= ODBConn::noOdbcDialog; break;
+ } // endswitch cop
+
+ if (ocp->Open(dsn, options) < 1)
+ newdsn = NULL;
+ else
+ newdsn = ocp->GetConnect();
+
+ (void) getcwd(buf, sizeof(buf) - 1);
+
+ // Some data sources change the current directory
+ if (strcmp(dir, buf))
+ rc = chdir(dir);
+
+ ocp->Close();
+ return newdsn; // Return complete connection string
+ } // end of ODBCCheckConnection
+#endif // PROMPT_OK
+
+/***********************************************************************/
+/* Allocate the structure used to refer to the result set. */
+/***********************************************************************/
+static CATPARM *AllocCatInfo(PGLOBAL g, CATINFO fid, PCSZ db,
+ PCSZ tab, PQRYRES qrp)
+{
+ size_t i, m, n;
+ CATPARM *cap;
+
+#if defined(_DEBUG)
+ assert(qrp);
+#endif
+
+ try {
+ m = (size_t)qrp->Maxres;
+ n = (size_t)qrp->Nbcol;
+ cap = (CATPARM *)PlugSubAlloc(g, NULL, sizeof(CATPARM));
+ memset(cap, 0, sizeof(CATPARM));
+ cap->Id = fid;
+ cap->Qrp = qrp;
+ cap->DB = db;
+ cap->Tab = tab;
+ cap->Vlen = (SQLLEN* *)PlugSubAlloc(g, NULL, n * sizeof(SQLLEN *));
+
+ for (i = 0; i < n; i++)
+ cap->Vlen[i] = (SQLLEN *)PlugSubAlloc(g, NULL, m * sizeof(SQLLEN));
+
+ cap->Status = (UWORD *)PlugSubAlloc(g, NULL, m * sizeof(UWORD));
+
+ } catch (int n) {
+ htrc("Exeption %d: %s\n", n, g->Message);
+ cap = NULL;
+ } catch (const char *msg) {
+ htrc(g->Message, msg);
+ printf("%s\n", g->Message);
+ cap = NULL;
+ } // end catch
+
+ return cap;
+} // end of AllocCatInfo
+
+#if 0
+/***********************************************************************/
+/* Check for nulls and reset them to Null (?) values. */
+/***********************************************************************/
+static void ResetNullValues(CATPARM *cap)
+ {
+ int i, n, ncol;
+ PCOLRES crp;
+ PQRYRES qrp = cap->Qrp;
+
+#if defined(_DEBUG)
+ assert(qrp);
+#endif
+
+ ncol = qrp->Nbcol;
+
+ for (i = 0, crp = qrp->Colresp; i < ncol && crp; i++, crp = crp->Next)
+ for (n = 0; n < qrp->Nblin; n++)
+ if (cap->Vlen[i][n] == SQL_NULL_DATA)
+ crp->Kdata->Reset(n);
+
+ } // end of ResetNullValues
+#endif
+
+/***********************************************************************/
+/* Close an ODBC table after a thrown error (called by PlugCloseFile) */
+/***********************************************************************/
+void OdbcClose(PGLOBAL g, PFBLOCK fp) {
+ ((ODBConn*)fp->File)->Close();
+} // end of OdbcClose
+
+/***********************************************************************/
+/* ODBCColumns: constructs the result blocks containing all columns */
+/* of an ODBC table that will be retrieved by GetData commands. */
+/***********************************************************************/
+PQRYRES ODBCColumns(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ table,
+ PCSZ colpat, int maxres, bool info, POPARM sop)
+ {
+ int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
+ TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT,
+ TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
+ XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_TABNAME, FLD_NAME,
+ FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH,
+ FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM};
+ unsigned int length[] = {0, 0, 0, 0, 6, 0, 10, 10, 6, 6, 6, 0};
+ bool b[] = {true,true,false,false,false,false,false,false,true,true,false,true};
+ int i, n, ncol = 12;
+ PCOLRES crp;
+ PQRYRES qrp;
+ CATPARM *cap;
+ ODBConn *ocp = NULL;
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ if (!info) {
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, sop, 10) < 1) // openReadOnly + noODBCdialog
+ return NULL;
+
+ if (table && !strchr(table, '%')) {
+ // We fix a MySQL limit because some data sources return 32767
+ n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
+ maxres = (n) ? MY_MIN(n, 4096) : 4096;
+ } else if (!maxres)
+ maxres = 20000;
+
+// n = ocp->GetMaxValue(SQL_MAX_CATALOG_NAME_LEN);
+// length[0] = (n) ? (n + 1) : 0;
+// n = ocp->GetMaxValue(SQL_MAX_SCHEMA_NAME_LEN);
+// length[1] = (n) ? (n + 1) : 0;
+// n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
+// length[2] = (n) ? (n + 1) : 0;
+ n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
+ length[3] = (n) ? (n + 1) : 128;
+ } else { // Info table
+ maxres = 0;
+ length[0] = 128;
+ length[1] = 128;
+ length[2] = 128;
+ length[3] = 128;
+ length[5] = 30;
+ length[11] = 255;
+ } // endif ocp
+
+ if (trace(1))
+ htrc("ODBCColumns: max=%d len=%d,%d,%d,%d\n",
+ maxres, length[0], length[1], length[2], length[3]);
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS,
+ buftyp, fldtyp, length, false, true);
+
+ for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
+ if (b[i])
+ crp->Kdata->SetNullable(true);
+
+ if (info || !qrp) // Info table
+ return qrp;
+
+ if (trace(1))
+ htrc("Getting col results ncol=%d\n", qrp->Nbcol);
+
+ if (!(cap = AllocCatInfo(g, CAT_COL, db, table, qrp)))
+ return NULL;
+
+ cap->Pat = colpat;
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = ocp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+// ResetNullValues(cap);
+
+ if (trace(1))
+ htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
+
+ } else
+ qrp = NULL;
+
+ /* Cleanup */
+ ocp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCColumns
+
+/**************************************************************************/
+/* ODBCSrcCols: constructs the result blocks containing the */
+/* description of all the columns of a Srcdef option. */
+/**************************************************************************/
+PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, POPARM sop)
+ {
+ char *sqry;
+ ODBConn *ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, sop, 10) < 1) // openReadOnly + noOdbcDialog
+ return NULL;
+
+ if (strstr(src, "%s")) {
+ // Place holder for an eventual where clause
+ sqry = (char*)PlugSubAlloc(g, NULL, strlen(src) + 3);
+ sprintf(sqry, src, "1=1", "1=1"); // dummy where clause
+ } else
+ sqry = src;
+
+ return ocp->GetMetaData(g, dsn, sqry);
+ } // end of ODBCSrcCols
+
+#if 0
+/**************************************************************************/
+/* MyODBCCols: returns column info as required by ha_connect::pre_create. */
+/**************************************************************************/
+PQRYRES MyODBCCols(PGLOBAL g, char *dsn, char *tab, bool info)
+ {
+// int i, type, len, prec;
+ bool w = false;
+// PCOLRES crp, crpt, crpl, crpp;
+ PQRYRES qrp;
+ ODBConn *ocp;
+
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ if (!info) {
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ } else
+ ocp = NULL;
+
+ /**********************************************************************/
+ /* Get the information about the ODBC table columns. */
+ /**********************************************************************/
+ if ((qrp = ODBCColumns(g, ocp, dsn, NULL, tab, 0, NULL)) && ocp)
+ dsn = ocp->GetConnect(); // Complete connect string
+
+ /************************************************************************/
+ /* Close the local connection. */
+ /************************************************************************/
+ if (ocp)
+ ocp->Close();
+
+ if (!qrp)
+ return NULL; // Error in ODBCColumns
+
+ /************************************************************************/
+ /* Keep only the info used by ha_connect::pre_create. */
+ /************************************************************************/
+ qrp->Colresp = qrp->Colresp->Next->Next; // Skip Schema and Table names
+
+ crpt = qrp->Colresp->Next; // SQL type
+ crpl = crpt->Next->Next; // Length
+ crpp = crpl->Next->Next; // Decimals
+
+ for (int i = 0; i < qrp->Nblin; i++) {
+ // Types must be PLG types, not SQL types
+ type = crpt->Kdata->GetIntValue(i);
+ len = crpl->Kdata->GetIntValue(i);
+ prec = crpp->Kdata->GetIntValue(i);
+ type = TranslateSQLType(type, prec, len, w);
+ crpt->Kdata->SetValue(type, i);
+
+ // Some data sources do not count prec in length
+ if (type == TYPE_DOUBLE)
+ len += (prec + 2); // To be safe
+
+ // Could have been changed for blobs or numeric
+ crpl->Kdata->SetValue(len, i);
+ } // endfor i
+
+ crpp->Next = crpp->Next->Next->Next; // Should be Remark
+
+ // Renumber crp's for flag comparison
+ for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
+ crp->Ncol = ++i;
+
+ qrp->Nbcol = i; // Should be 7; was 11, skipped 4
+ return qrp;
+ } // end of MyODBCCols
+#endif // 0
+
+/*************************************************************************/
+/* ODBCDrivers: constructs the result blocks containing all ODBC */
+/* drivers available on the local host. */
+/* Called with info=true to have result column names. */
+/*************************************************************************/
+PQRYRES ODBCDrivers(PGLOBAL g, int maxres, bool info)
+ {
+ int buftyp[] = {TYPE_STRING, TYPE_STRING};
+ XFLD fldtyp[] = {FLD_NAME, FLD_REM};
+ unsigned int length[] = {128, 256};
+ bool b[] = {false, true};
+ int i, ncol = 2;
+ PCOLRES crp;
+ PQRYRES qrp;
+ ODBConn *ocp = NULL;
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ if (!info) {
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (!maxres)
+ maxres = 256; // Estimated max number of drivers
+
+ } else
+ maxres = 0;
+
+ if (trace(1))
+ htrc("ODBCDrivers: max=%d len=%d\n", maxres, length[0]);
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_DRIVER,
+ buftyp, fldtyp, length, false, true);
+
+ for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
+ if (b[i])
+ crp->Kdata->SetNullable(true);
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if (!info && qrp && ocp->GetDrivers(qrp))
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCDrivers
+
+/*************************************************************************/
+/* ODBCDataSources: constructs the result blocks containing all ODBC */
+/* data sources available on the local host. */
+/* Called with info=true to have result column names. */
+/*************************************************************************/
+PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info)
+ {
+ int buftyp[] = {TYPE_STRING, TYPE_STRING};
+ XFLD fldtyp[] = {FLD_NAME, FLD_REM};
+ unsigned int length[] = {0, 256};
+ bool b[] = {false, true};
+ int i, n = 0, ncol = 2;
+ PCOLRES crp;
+ PQRYRES qrp;
+ ODBConn *ocp = NULL;
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ if (!info) {
+ ocp = new(g) ODBConn(g, NULL);
+ n = ocp->GetMaxValue(SQL_MAX_DSN_LENGTH);
+ length[0] = (n) ? (n + 1) : 256;
+
+ if (!maxres)
+ maxres = 512; // Estimated max number of data sources
+
+ } else {
+ length[0] = 256;
+ maxres = 0;
+ } // endif info
+
+ if (trace(1))
+ htrc("ODBCDataSources: max=%d len=%d\n", maxres, length[0]);
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_DSRC,
+ buftyp, fldtyp, length, false, true);
+
+ for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
+ if (b[i])
+ crp->Kdata->SetNullable(true);
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if (!info && qrp && ocp->GetDataSources(qrp))
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCDataSources
+
+/**************************************************************************/
+/* ODBCTables: constructs the result blocks containing all tables in */
+/* an ODBC database that will be retrieved by GetData commands. */
+/**************************************************************************/
+PQRYRES ODBCTables(PGLOBAL g, PCSZ dsn, PCSZ db, PCSZ tabpat, PCSZ tabtyp,
+ int maxres, bool info, POPARM sop)
+ {
+ int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
+ TYPE_STRING, TYPE_STRING};
+ XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_NAME,
+ FLD_TYPE, FLD_REM};
+ unsigned int length[] = {0, 0, 0, 16, 0};
+ bool b[] ={ true, true, false, false, true };
+ int i, n, ncol = 5;
+ PCOLRES crp;
+ PQRYRES qrp;
+ CATPARM *cap;
+ ODBConn *ocp = NULL;
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ if (!info) {
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, sop, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ if (!maxres)
+ maxres = 10000; // This is completely arbitrary
+
+// n = ocp->GetMaxValue(SQL_MAX_CATALOG_NAME_LEN);
+// length[0] = (n) ? (n + 1) : 0;
+// n = ocp->GetMaxValue(SQL_MAX_SCHEMA_NAME_LEN);
+// length[1] = (n) ? (n + 1) : 0;
+ n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
+ length[2] = (n) ? (n + 1) : 128;
+ } else {
+ maxres = 0;
+ length[0] = 128;
+ length[1] = 128;
+ length[2] = 128;
+ length[4] = 255;
+ } // endif info
+
+ if (trace(1))
+ htrc("ODBCTables: max=%d len=%d,%d\n", maxres, length[0], length[1]);
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES, buftyp,
+ fldtyp, length, false, true);
+
+ for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
+ if (b[i])
+ crp->Kdata->SetNullable(true);
+
+ if (info || !qrp)
+ return qrp;
+
+ if (!(cap = AllocCatInfo(g, CAT_TAB, db, tabpat, qrp)))
+ return NULL;
+
+ cap->Pat = tabtyp;
+
+ if (trace(1))
+ htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol);
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = ocp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+// ResetNullValues(cap);
+
+ if (trace(1))
+ htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
+
+ } else
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Close any local connection. */
+ /************************************************************************/
+ ocp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCTables
+
+#if 0 // Currently not used by CONNECT
+/**************************************************************************/
+/* PrimaryKeys: constructs the result blocks containing all the */
+/* ODBC catalog information concerning primary keys. */
+/**************************************************************************/
+PQRYRES ODBCPrimaryKeys(PGLOBAL g, ODBConn *op, char *dsn, char *table)
+ {
+ static int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
+ TYPE_STRING, TYPE_SHORT, TYPE_STRING};
+ static unsigned int length[] = {0, 0, 0, 0, 6, 128};
+ int n, ncol = 5;
+ int maxres;
+ PQRYRES qrp;
+ CATPARM *cap;
+ ODBConn *ocp = op;
+
+ if (!op) {
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ } // endif op
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ n = ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_TABLE);
+ maxres = (n) ? (int)n : 250;
+ n = ocp->GetMaxValue(SQL_MAX_CATALOG_NAME_LEN);
+ length[0] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_SCHEMA_NAME_LEN);
+ length[1] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
+ length[2] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
+ length[3] = (n) ? (n + 1) : 128;
+
+ if (trace(1))
+ htrc("ODBCPrimaryKeys: max=%d len=%d,%d,%d\n",
+ maxres, length[0], length[1], length[2]);
+
+ /************************************************************************/
+ /* Allocate the structure used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_PKEY,
+ buftyp, NULL, length, false, true);
+
+ if (trace(1))
+ htrc("Getting pkey results ncol=%d\n", qrp->Nbcol);
+
+ cap = AllocCatInfo(g, CAT_KEY, NULL, table, qrp);
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = ocp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+// ResetNullValues(cap);
+
+ if (trace(1))
+ htrc("PrimaryKeys: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
+
+ } else
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Close any local connection. */
+ /************************************************************************/
+ if (!op)
+ ocp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of ODBCPrimaryKeys
+
+/**************************************************************************/
+/* Statistics: constructs the result blocks containing statistics */
+/* about one or several tables to be retrieved by GetData commands. */
+/**************************************************************************/
+PQRYRES ODBCStatistics(PGLOBAL g, ODBConn *op, char *dsn, char *pat,
+ int un, int acc)
+ {
+ static int buftyp[] = {TYPE_STRING,
+ TYPE_STRING, TYPE_STRING, TYPE_SHORT, TYPE_STRING,
+ TYPE_STRING, TYPE_SHORT, TYPE_SHORT, TYPE_STRING,
+ TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_STRING};
+ static unsigned int length[] = {0, 0, 0 ,6 ,0 ,0 ,6 ,6 ,0 ,2 ,10 ,10 ,128};
+ int n, ncol = 13;
+ int maxres;
+ PQRYRES qrp;
+ CATPARM *cap;
+ ODBConn *ocp = op;
+
+ if (!op) {
+ /**********************************************************************/
+ /* Open the connection with the ODBC data source. */
+ /**********************************************************************/
+ ocp = new(g) ODBConn(g, NULL);
+
+ if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly
+ return NULL;
+
+ } // endif op
+
+ /************************************************************************/
+ /* Do an evaluation of the result size. */
+ /************************************************************************/
+ n = 1 + ocp->GetMaxValue(SQL_MAX_COLUMNS_IN_INDEX);
+ maxres = (n) ? (int)n : 32;
+ n = ocp->GetMaxValue(SQL_MAX_SCHEMA_NAME_LEN);
+ length[1] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_TABLE_NAME_LEN);
+ length[2] = length[5] = (n) ? (n + 1) : 128;
+ n = ocp->GetMaxValue(SQL_MAX_CATALOG_NAME_LEN);
+ length[0] = length[4] = (n) ? (n + 1) : length[2];
+ n = ocp->GetMaxValue(SQL_MAX_COLUMN_NAME_LEN);
+ length[7] = (n) ? (n + 1) : 128;
+
+ if (trace(1))
+ htrc("SemStatistics: max=%d pat=%s\n", maxres, SVP(pat));
+
+ /************************************************************************/
+ /* Allocate the structure used to refer to the result set. */
+ /************************************************************************/
+ qrp = PlgAllocResult(g, ncol, maxres, IDS_STAT,
+ buftyp, NULL, length, false, true);
+
+ if (trace(1))
+ htrc("Getting stat results ncol=%d\n", qrp->Nbcol);
+
+ cap = AllocCatInfo(g, CAT_STAT, NULL, pat, qrp);
+ cap->Unique = (un < 0) ? SQL_INDEX_UNIQUE : (UWORD)un;
+ cap->Accuracy = (acc < 0) ? SQL_QUICK : (UWORD)acc;
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ if ((n = ocp->GetCatInfo(cap)) >= 0) {
+ qrp->Nblin = n;
+// ResetNullValues(cap);
+
+ if (trace(1))
+ htrc("Statistics: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
+
+ } else
+ qrp = NULL;
+
+ /************************************************************************/
+ /* Close any local connection. */
+ /************************************************************************/
+ if (!op)
+ ocp->Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of Statistics
+#endif // 0
+
+/***********************************************************************/
+/* Implementation of DBX class. */
+/***********************************************************************/
+DBX::DBX(RETCODE rc, PCSZ msg)
+ {
+ m_RC = rc;
+ m_Msg = msg;
+
+ for (int i = 0; i < MAX_NUM_OF_MSG; i++)
+ m_ErrMsg[i] = NULL;
+
+ } // end of DBX constructor
+
+/***********************************************************************/
+/* This function is called by ThrowDBX. */
+/***********************************************************************/
+bool DBX::BuildErrorMessage(ODBConn* pdb, HSTMT hstmt)
+ {
+ if (pdb) {
+ SWORD len;
+ RETCODE rc;
+ UCHAR msg[SQL_MAX_MESSAGE_LENGTH + 1];
+ UCHAR state[SQL_SQLSTATE_SIZE + 1];
+ SDWORD native;
+ PGLOBAL g = pdb->m_G;
+
+ rc = SQLError(pdb->m_henv, pdb->m_hdbc, hstmt, state,
+ &native, msg, SQL_MAX_MESSAGE_LENGTH - 1, &len);
+
+ if (rc == SQL_NO_DATA_FOUND)
+ return false;
+ else if (rc != SQL_INVALID_HANDLE) {
+ // Skip non-errors
+ for (int i = 0; i < MAX_NUM_OF_MSG
+ && (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
+ && strcmp((char*)state, "00000"); i++) {
+ m_ErrMsg[i] = (PSZ)PlugDup(g, (char*)msg);
+
+ if (trace(1))
+ htrc("%s: %s, Native=%d\n", state, msg, native);
+
+ rc = SQLError(pdb->m_henv, pdb->m_hdbc, hstmt, state,
+ &native, msg, SQL_MAX_MESSAGE_LENGTH - 1, &len);
+
+ } // endfor i
+
+ return true;
+ } else {
+ snprintf((char*)msg, SQL_MAX_MESSAGE_LENGTH + 1, "%s: %s", m_Msg,
+ MSG(BAD_HANDLE_VAL));
+ m_ErrMsg[0] = (PSZ)PlugDup(g, (char*)msg);
+
+ if (trace(1))
+ htrc("%s: rc=%hd\n", SVP(m_ErrMsg[0]), m_RC);
+
+ return true;
+ } // endif rc
+
+ } else
+ m_ErrMsg[0] = "No connexion address provided";
+
+ if (trace(1))
+ htrc("%s: rc=%hd (%s)\n", SVP(m_Msg), m_RC, SVP(m_ErrMsg[0]));
+
+ return true;
+ } // end of BuildErrorMessage
+
+const char *DBX::GetErrorMessage(int i)
+ {
+ if (i < 0 || i >= MAX_NUM_OF_MSG)
+ return "No ODBC error";
+ else if (m_ErrMsg[i])
+ return m_ErrMsg[i];
+ else
+ return (m_Msg) ? m_Msg : "Unknown error";
+
+ } // end of GetErrorMessage
+
+/***********************************************************************/
+/* ODBConn construction/destruction. */
+/***********************************************************************/
+ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
+ {
+ m_G = g;
+ m_Tdb = tdbp;
+ m_henv = SQL_NULL_HENV;
+ m_hdbc = SQL_NULL_HDBC;
+//m_Recset = NULL
+ m_hstmt = SQL_NULL_HSTMT;
+ m_LoginTimeout = DEFAULT_LOGIN_TIMEOUT;
+ m_QueryTimeout = DEFAULT_QUERY_TIMEOUT;
+ m_UpdateOptions = 0;
+ m_RowsetSize = (DWORD)((tdbp) ? tdbp->Rows : 10);
+ m_Catver = (tdbp) ? tdbp->Catver : 0;
+ m_Rows = 0;
+ m_Fetch = 0;
+ m_Fp = NULL;
+ m_Connect = NULL;
+ m_User = NULL;
+ m_Pwd = NULL;
+ m_Updatable = true;
+ m_Transact = false;
+ m_Scrollable = (tdbp) ? tdbp->Scrollable : false;
+ m_Full = false;
+ m_UseCnc = false;
+ m_IDQuoteChar[0] = '"';
+ m_IDQuoteChar[1] = 0;
+//*m_ErrMsg = '\0';
+ } // end of ODBConn
+
+//ODBConn::~ODBConn()
+// {
+//if (Connected())
+// EndCom();
+
+// } // end of ~ODBConn
+
+/***********************************************************************/
+/* Screen for errors. */
+/***********************************************************************/
+bool ODBConn::Check(RETCODE rc)
+ {
+ switch (rc) {
+ case SQL_SUCCESS_WITH_INFO:
+ if (trace(1)) {
+ DBX x(rc);
+
+ if (x.BuildErrorMessage(this, m_hstmt))
+ htrc("ODBC Success With Info, hstmt=%p %s\n",
+ m_hstmt, x.GetErrorMessage(0));
+
+ } // endif trace
+
+ // Fall through
+ case SQL_SUCCESS:
+ case SQL_NO_DATA_FOUND:
+ return true;
+ } // endswitch rc
+
+ return false;
+ } // end of Check
+
+/***********************************************************************/
+/* DB exception throw routines. */
+/***********************************************************************/
+void ODBConn::ThrowDBX(RETCODE rc, PCSZ msg, HSTMT hstmt)
+ {
+ DBX* xp = new(m_G) DBX(rc, msg);
+
+ // Don't throw if no error
+ if (xp->BuildErrorMessage(this, hstmt))
+ throw xp;
+
+ } // end of ThrowDBX
+
+void ODBConn::ThrowDBX(PCSZ msg)
+ {
+ DBX* xp = new(m_G) DBX(0, "Error");
+
+ xp->m_ErrMsg[0] = msg;
+ throw xp;
+ } // end of ThrowDBX
+
+/***********************************************************************/
+/* Utility routine. */
+/***********************************************************************/
+PSZ ODBConn::GetStringInfo(ushort infotype)
+ {
+//ASSERT(m_hdbc != SQL_NULL_HDBC);
+ char *p, buffer[MAX_STRING_INFO];
+ SWORD result;
+ RETCODE rc;
+
+ rc = SQLGetInfo(m_hdbc, infotype, buffer, sizeof(buffer), &result);
+
+ if (!Check(rc)) {
+ ThrowDBX(rc, "SQLGetInfo"); // Temporary
+// *buffer = '\0';
+ } // endif rc
+
+ p = PlugDup(m_G, buffer);
+ return p;
+ } // end of GetStringInfo
+
+/***********************************************************************/
+/* Utility routine. */
+/***********************************************************************/
+int ODBConn::GetMaxValue(ushort infotype)
+ {
+//ASSERT(m_hdbc != SQL_NULL_HDBC);
+ ushort maxval;
+ RETCODE rc;
+
+ rc = SQLGetInfo(m_hdbc, infotype, &maxval, 0, NULL);
+
+ if (!Check(rc))
+ maxval = 0;
+
+ return (int)maxval;
+ } // end of GetMaxValue
+
+/***********************************************************************/
+/* Utility routines. */
+/***********************************************************************/
+void ODBConn::OnSetOptions(HSTMT hstmt)
+ {
+ RETCODE rc;
+ ASSERT(m_hdbc != SQL_NULL_HDBC);
+
+ if ((signed)m_QueryTimeout != -1) {
+ // Attempt to set query timeout. Ignore failure
+ rc = SQLSetStmtOption(hstmt, SQL_QUERY_TIMEOUT, m_QueryTimeout);
+
+ if (!Check(rc))
+ // don't attempt it again
+ m_QueryTimeout = (DWORD)-1;
+
+ } // endif m_QueryTimeout
+
+ if (m_RowsetSize > 0) {
+ // Attempt to set rowset size.
+ // In case of failure reset it to 0 to use Fetch.
+ rc = SQLSetStmtOption(hstmt, SQL_ROWSET_SIZE, m_RowsetSize);
+
+ if (!Check(rc))
+ // don't attempt it again
+ m_RowsetSize = 0;
+
+ } // endif m_RowsetSize
+
+ } // end of OnSetOptions
+
+/***********************************************************************/
+/* Open: connect to a data source. */
+/***********************************************************************/
+int ODBConn::Open(PCSZ ConnectString, POPARM sop, DWORD options)
+ {
+ PGLOBAL& g = m_G;
+//ASSERT_VALID(this);
+//ASSERT(ConnectString == NULL || AfxIsValidString(ConnectString));
+ ASSERT(!(options & noOdbcDialog && options & forceOdbcDialog));
+
+ m_Updatable = !(options & openReadOnly);
+ m_Connect = ConnectString;
+ m_User = sop->User;
+ m_Pwd = sop->Pwd;
+ m_LoginTimeout = sop->Cto;
+ m_QueryTimeout = sop->Qto;
+ m_UseCnc = sop->UseCnc;
+
+ // Allocate the HDBC and make connection
+ try {
+ /*PSZ ver;*/
+
+ AllocConnect(options);
+ /*ver = GetStringInfo(SQL_ODBC_VER);*/
+
+ if (!m_UseCnc) {
+ if (DriverConnect(options)) {
+ strcpy(g->Message, MSG(CONNECT_CANCEL));
+ return 0;
+ } // endif
+
+ } else // Connect using SQLConnect
+ Connect();
+
+ /*********************************************************************/
+ /* Link a Fblock. This make possible to automatically close it */
+ /* in case of error (throw). */
+ /*********************************************************************/
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ m_Fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+ m_Fp->Type = TYPE_FB_ODBC;
+ m_Fp->Fname = NULL;
+ m_Fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = m_Fp;
+ m_Fp->Count = 1;
+ m_Fp->Length = 0;
+ m_Fp->Memory = NULL;
+ m_Fp->Mode = MODE_ANY;
+ m_Fp->File = this;
+ m_Fp->Handle = 0;
+
+ /*ver = GetStringInfo(SQL_DRIVER_ODBC_VER);*/
+ // Verify support for required functionality and cache info
+// VerifyConnect(); Deprecated
+ GetConnectInfo();
+ } catch(DBX *xp) {
+ sprintf(g->Message, "%s: %s", xp->m_Msg, xp->GetErrorMessage(0));
+ Close();
+// Free();
+ return -1;
+ } // end try-catch
+
+ return 1;
+ } // end of Open
+
+/***********************************************************************/
+/* Allocate an henv (first time called) and hdbc. */
+/***********************************************************************/
+void ODBConn::AllocConnect(DWORD Options)
+ {
+ if (m_hdbc != SQL_NULL_HDBC)
+ return;
+
+ RETCODE rc;
+//AfxLockGlobals(CRIT_ODBC);
+
+ // Need to allocate an environment for first connection
+ if (m_henv == SQL_NULL_HENV) {
+// ASSERT(m_nAlloc == 0);
+
+ rc = SQLAllocEnv(&m_henv);
+
+ if (!Check(rc)) {
+// AfxUnlockGlobals(CRIT_ODBC);
+ ThrowDBX(rc, "SQLAllocEnv"); // Fatal
+ } // endif rc
+
+ } // endif m_henv
+
+ // Do the real thing, allocating connection data
+ rc = SQLAllocConnect(m_henv, &m_hdbc);
+
+ if (!Check(rc)) {
+// AfxUnlockGlobals(CRIT_ODBC);
+ ThrowDBX(rc, "SQLAllocConnect"); // Fatal
+ } // endif rc
+
+//m_nAlloc++; // allocated at last
+//AfxUnlockGlobals(CRIT_ODBC);
+
+#if defined(_DEBUG)
+ if (Options & traceSQL) {
+ SQLSetConnectOption(m_hdbc, SQL_OPT_TRACEFILE, (SQLULEN)"xodbc.out");
+ SQLSetConnectOption(m_hdbc, SQL_OPT_TRACE, 1);
+ } // endif
+#endif // _DEBUG
+
+ if ((signed)m_LoginTimeout >= 0) {
+ rc = SQLSetConnectOption(m_hdbc, SQL_LOGIN_TIMEOUT, m_LoginTimeout);
+
+ if (trace(1) && rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
+ htrc("Warning: Failure setting login timeout\n");
+
+ } // endif Timeout
+
+ if (!m_Updatable) {
+ rc = SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE, SQL_MODE_READ_ONLY);
+
+ if (trace(1) && rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
+ htrc("Warning: Failure setting read only access mode\n");
+
+ } // endif
+
+ // Turn on cursor lib support
+ if (Options & useCursorLib)
+ rc = SQLSetConnectOption(m_hdbc, SQL_ODBC_CURSORS, SQL_CUR_USE_DRIVER);
+
+ return;
+ } // end of AllocConnect
+
+/***********************************************************************/
+/* Connect to data source using SQLConnect. */
+/***********************************************************************/
+void ODBConn::Connect(void)
+ {
+ SQLRETURN rc;
+ SQLSMALLINT ul = (m_User ? SQL_NTS : 0);
+ SQLSMALLINT pl = (m_Pwd ? SQL_NTS : 0);
+
+ rc = SQLConnect(m_hdbc, (SQLCHAR*)m_Connect, SQL_NTS,
+ (SQLCHAR*)m_User, ul, (SQLCHAR*)m_Pwd, pl);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLConnect");
+
+ } // end of Connect
+
+/***********************************************************************/
+/* Connect to data source using SQLDriverConnect. */
+/***********************************************************************/
+bool ODBConn::DriverConnect(DWORD Options)
+ {
+ RETCODE rc;
+ SWORD nResult;
+ PUCHAR ConnOut = (PUCHAR)PlugSubAlloc(m_G, NULL, MAX_CONNECT_LEN);
+ UWORD wConnectOption = SQL_DRIVER_COMPLETE;
+#if defined(_WIN32)
+ HWND hWndTop = GetForegroundWindow();
+ HWND hWnd = GetParent(hWndTop);
+
+ if (hWnd == NULL)
+ hWnd = GetDesktopWindow();
+#else // !_WIN32
+ HWND hWnd = (HWND)1;
+#endif // !_WIN32
+
+ wConnectOption = SQL_DRIVER_NOPROMPT;
+//else if (Options & forceOdbcDialog)
+// wConnectOption = SQL_DRIVER_PROMPT;
+
+ rc = SQLDriverConnect(m_hdbc, hWnd, (PUCHAR)m_Connect,
+ SQL_NTS, ConnOut, MAX_CONNECT_LEN,
+ &nResult, wConnectOption);
+
+#if defined(_WIN32)
+ if (hWndTop)
+ EnableWindow(hWndTop, true);
+#endif // _WIN32
+
+ // If user hit 'Cancel'
+ if (rc == SQL_NO_DATA_FOUND) {
+ Close();
+// Free();
+ return true;
+ } // endif rc
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLDriverConnect");
+
+ // Save connect string returned from ODBC
+ m_Connect = (PSZ)ConnOut;
+
+ // All done
+ return false;
+ } // end of DriverConnect
+
+void ODBConn::VerifyConnect()
+ {
+#if defined(NEWMSG) || defined(XMSG)
+ PGLOBAL& g = m_G;
+#endif // NEWMSG || XMSG
+ RETCODE rc;
+ SWORD result;
+ SWORD conformance;
+
+ rc = SQLGetInfo(m_hdbc, SQL_ODBC_API_CONFORMANCE,
+ &conformance, sizeof(conformance), &result);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLGetInfo");
+
+ if (conformance < SQL_OAC_LEVEL1)
+ ThrowDBX(MSG(API_CONF_ERROR));
+
+ rc = SQLGetInfo(m_hdbc, SQL_ODBC_SQL_CONFORMANCE,
+ &conformance, sizeof(conformance), &result);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLGetInfo");
+
+ if (conformance < SQL_OSC_MINIMUM)
+ ThrowDBX(MSG(SQL_CONF_ERROR));
+
+ } // end of VerifyConnect
+
+void ODBConn::GetConnectInfo()
+ {
+ RETCODE rc;
+ SWORD nResult;
+#if 0 // Update not implemented yet
+ UDWORD DrvPosOp;
+
+ // Reset the database update options
+ m_UpdateOptions = 0;
+
+ // Check for SQLSetPos support
+ rc = SQLGetInfo(m_hdbc, SQL_POS_OPERATIONS,
+ &DrvPosOp, sizeof(DrvPosOp), &nResult);
+
+ if (Check(rc) &&
+ (DrvPosOp & SQL_POS_UPDATE) &&
+ (DrvPosOp & SQL_POS_DELETE) &&
+ (DrvPosOp & SQL_POS_ADD))
+ m_UpdateOptions = SQL_SETPOSUPDATES;
+
+ // Check for positioned update SQL support
+ UDWORD PosStatements;
+
+ rc = SQLGetInfo(m_hdbc, SQL_POSITIONED_STATEMENTS,
+ &PosStatements, sizeof(PosStatements),
+ &nResult);
+
+ if (Check(rc) &&
+ (PosStatements & SQL_PS_POSITIONED_DELETE) &&
+ (PosStatements & SQL_PS_POSITIONED_UPDATE))
+ m_UpdateOptions |= SQL_POSITIONEDSQL;
+
+ if (m_Updatable) {
+ // Make sure data source is Updatable
+ char ReadOnly[10];
+
+ rc = SQLGetInfo(m_hdbc, SQL_DATA_SOURCE_READ_ONLY,
+ ReadOnly, sizeof(ReadOnly), &nResult);
+
+ if (Check(rc) && nResult == 1)
+ m_Updatable = !!strcmp(ReadOnly, "Y");
+ else
+ m_Updatable = false;
+
+ if (trace(1))
+ htrc("Warning: data source is readonly\n");
+
+ } else // Make data source is !Updatable
+ rc = SQLSetConnectOption(m_hdbc, SQL_ACCESS_MODE,
+ SQL_MODE_READ_ONLY);
+#endif // 0
+
+ // Get the quote char to use when constructing SQL
+ rc = SQLGetInfo(m_hdbc, SQL_IDENTIFIER_QUOTE_CHAR,
+ m_IDQuoteChar, sizeof(m_IDQuoteChar), &nResult);
+
+ if (trace(1))
+ htrc("DBMS: %s, Version: %s, rc=%d\n",
+ GetStringInfo(SQL_DBMS_NAME), GetStringInfo(SQL_DBMS_VER), rc);
+
+ } // end of GetConnectInfo
+
+/***********************************************************************/
+/* Allocate record set and execute an SQL query. */
+/***********************************************************************/
+int ODBConn::ExecDirectSQL(char *sql, ODBCCOL *tocols)
+ {
+ PGLOBAL& g = m_G;
+ void *buffer;
+ bool b;
+ UWORD n;
+ SWORD len, tp, ncol = 0;
+ ODBCCOL *colp;
+ RETCODE rc;
+ HSTMT hstmt;
+
+ try {
+ b = false;
+
+ if (m_hstmt) {
+ // This is a Requery
+ rc = SQLFreeStmt(m_hstmt, SQL_CLOSE);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLFreeStmt", m_hstmt);
+
+ m_hstmt = NULL;
+ } // endif m_hstmt
+
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLAllocStmt");
+
+ if (m_Scrollable) {
+ rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_SCROLLABLE,
+ (void*)SQL_SCROLLABLE, 0);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "Scrollable", hstmt);
+
+ } // endif m_Scrollable
+
+ OnSetOptions(hstmt);
+ b = true;
+
+ if (trace(1))
+ htrc("ExecDirect hstmt=%p %.256s\n", hstmt, sql);
+
+ if (m_Tdb->Srcdef) {
+ // Be sure this is a query returning a result set
+ do {
+ rc = SQLPrepare(hstmt, (PUCHAR)sql, SQL_NTS);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLPrepare", hstmt);
+
+ if (!Check(rc = SQLNumResultCols(hstmt, &ncol)))
+ ThrowDBX(rc, "SQLNumResultCols", hstmt);
+
+ if (ncol == 0) {
+ strcpy(g->Message, "This Srcdef does not return a result set");
+ return -1;
+ } // endif ncol
+
+ // Ok, now we can proceed
+ do {
+ rc = SQLExecute(hstmt);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLExecute", hstmt);
+
+ } else {
+ do {
+ rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLExecDirect", hstmt);
+
+ do {
+ rc = SQLNumResultCols(hstmt, &ncol);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ } // endif Srcdef
+
+ for (n = 0, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
+ if (!colp->IsSpecial())
+ n++;
+
+ // n can be 0 for query such as Select count(*) from table
+ if (n && n > (UWORD)ncol)
+ ThrowDBX(MSG(COL_NUM_MISM));
+
+ // Now bind the column buffers
+ for (n = 1, colp = tocols; colp; colp = (PODBCCOL)colp->GetNext())
+ if (!colp->IsSpecial()) {
+ buffer = colp->GetBuffer(m_RowsetSize);
+ len = colp->GetBuflen();
+ tp = GetSQLCType(colp->GetResultType());
+
+ if (tp == SQL_TYPE_NULL) {
+ sprintf(m_G->Message, MSG(INV_COLUMN_TYPE),
+ colp->GetResultType(), SVP(colp->GetName()));
+ ThrowDBX(m_G->Message);
+ } // endif tp
+
+ if (trace(1))
+ htrc("Binding col=%u type=%d buf=%p len=%d slen=%p\n",
+ n, tp, buffer, len, colp->GetStrLen());
+
+ rc = SQLBindCol(hstmt, n, tp, buffer, len, colp->GetStrLen());
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLBindCol", hstmt);
+
+ n++;
+ } // endif pcol
+
+ } catch(DBX *x) {
+ if (trace(1))
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+
+ if (b)
+ SQLCancel(hstmt);
+
+ rc = SQLFreeStmt(hstmt, SQL_DROP);
+ m_hstmt = NULL;
+ return -1;
+ } // end try/catch
+
+ m_hstmt = hstmt;
+ return (int)m_RowsetSize; // May have been reset in OnSetOptions
+ } // end of ExecDirectSQL
+
+/***********************************************************************/
+/* Get the number of lines of the result set. */
+/***********************************************************************/
+int ODBConn::GetResultSize(char *sql, ODBCCOL *colp)
+ {
+ int n = 0;
+ RETCODE rc;
+
+ if (ExecDirectSQL(sql, colp) < 0)
+ return -1;
+
+ try {
+ for (n = 0; ; n++) {
+ do {
+ rc = SQLFetch(m_hstmt);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLFetch", m_hstmt);
+
+ if (rc == SQL_NO_DATA_FOUND)
+ break;
+
+ } // endfor n
+
+ } catch(DBX *x) {
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+
+ if (trace(1))
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ SQLCancel(m_hstmt);
+ n = -2;
+ } // end try/catch
+
+ rc = SQLFreeStmt(m_hstmt, SQL_DROP);
+ m_hstmt = NULL;
+
+ if (n != 1)
+ return -3;
+ else
+ return colp->GetIntValue();
+
+ } // end of GetResultSize
+
+/***********************************************************************/
+/* Fetch next row. */
+/***********************************************************************/
+int ODBConn::Fetch(int pos)
+ {
+ ASSERT(m_hstmt);
+ int irc;
+ SQLULEN crow;
+ RETCODE rc;
+ PGLOBAL& g = m_G;
+
+ try {
+// do {
+ if (pos) {
+ rc = SQLExtendedFetch(m_hstmt, SQL_FETCH_ABSOLUTE, pos, &crow, NULL);
+ } else if (m_RowsetSize) {
+ rc = SQLExtendedFetch(m_hstmt, SQL_FETCH_NEXT, 1, &crow, NULL);
+ } else {
+ rc = SQLFetch(m_hstmt);
+ crow = 1;
+ } // endif m_RowsetSize
+// } while (rc == SQL_STILL_EXECUTING);
+
+ if (trace(2))
+ htrc("Fetch: hstmt=%p RowseSize=%d rc=%d\n",
+ m_hstmt, m_RowsetSize, rc);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "Fetching", m_hstmt);
+
+ if (rc == SQL_NO_DATA_FOUND) {
+ m_Full = (m_Fetch == 1);
+ irc = 0;
+ } else
+ irc = (int)crow;
+
+ m_Fetch++;
+ m_Rows += irc;
+ } catch(DBX *x) {
+ if (trace(1))
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ sprintf(g->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ irc = -1;
+ } // end try/catch
+
+ return irc;
+ } // end of Fetch
+
+/***********************************************************************/
+/* Prepare an SQL statement for insert. */
+/***********************************************************************/
+int ODBConn::PrepareSQL(char *sql)
+ {
+ PGLOBAL& g = m_G;
+ bool b;
+ UINT txn = 0;
+ SWORD nparm;
+ RETCODE rc;
+ HSTMT hstmt;
+
+ if (m_Tdb->GetMode() != MODE_READ) {
+ // Does the data source support transactions
+ rc = SQLGetInfo(m_hdbc, SQL_TXN_CAPABLE, &txn, 0, NULL);
+
+ if (Check(rc) && txn != SQL_TC_NONE) try {
+ rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
+ SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLSetConnectAttr");
+
+ m_Transact = true;
+ } catch(DBX *x) {
+ if (trace(1))
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ sprintf(g->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ } // end try/catch
+
+ } // endif Mode
+
+ try {
+ b = false;
+
+ if (m_hstmt) {
+ SQLFreeStmt(m_hstmt, SQL_CLOSE);
+
+ hstmt = m_hstmt;
+ m_hstmt = NULL;
+
+ if (m_Tdb->GetAmType() != TYPE_AM_XDBC)
+ ThrowDBX(MSG(SEQUENCE_ERROR));
+
+ } // endif m_hstmt
+
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
+
+ OnSetOptions(hstmt);
+ b = true;
+
+ if (trace(1))
+ htrc("Prepare hstmt=%p %.64s\n", hstmt, sql);
+
+ do {
+ rc = SQLPrepare(hstmt, (PUCHAR)sql, SQL_NTS);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLPrepare", hstmt);
+
+ do {
+ rc = SQLNumParams(hstmt, &nparm);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ } catch(DBX *x) {
+ if (trace(1))
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ sprintf(g->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+
+ if (b)
+ SQLCancel(hstmt);
+
+ rc = SQLFreeStmt(hstmt, SQL_DROP);
+ m_hstmt = NULL;
+
+ if (m_Transact) {
+ rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK);
+ m_Transact = false;
+ } // endif m_Transact
+
+ return -1;
+ } // end try/catch
+
+ m_hstmt = hstmt;
+ return (int)nparm;
+ } // end of PrepareSQL
+
+/***********************************************************************/
+/* Execute a prepared statement. */
+/***********************************************************************/
+int ODBConn::ExecuteSQL(void)
+ {
+ PGLOBAL& g = m_G;
+ SWORD ncol = 0;
+ RETCODE rc;
+ SQLLEN afrw = -1;
+
+ try {
+ do {
+ rc = SQLExecute(m_hstmt);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLExecute", m_hstmt);
+
+ if (!Check(rc = SQLNumResultCols(m_hstmt, &ncol)))
+ ThrowDBX(rc, "SQLNumResultCols", m_hstmt);
+
+ if (ncol) {
+ // This should never happen while inserting
+ strcpy(g->Message, "Logical error while inserting");
+ } else {
+ // Insert, Update or Delete statement
+ if (!Check(rc = SQLRowCount(m_hstmt, &afrw)))
+ ThrowDBX(rc, "SQLRowCount", m_hstmt);
+
+ } // endif ncol
+
+ } catch(DBX *x) {
+ sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ SQLCancel(m_hstmt);
+ rc = SQLFreeStmt(m_hstmt, SQL_DROP);
+ m_hstmt = NULL;
+
+ if (m_Transact) {
+ rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_ROLLBACK);
+ m_Transact = false;
+ } // endif m_Transact
+
+ afrw = -1;
+ } // end try/catch
+
+ return (int)afrw;
+ } // end of ExecuteSQL
+
+/***********************************************************************/
+/* Bind a parameter for inserting. */
+/***********************************************************************/
+bool ODBConn::BindParam(ODBCCOL *colp)
+ {
+ void *buf;
+ int buftype = colp->GetResultType();
+ SQLUSMALLINT n = colp->GetRank();
+ SQLSMALLINT ct, sqlt, dec, nul __attribute__((unused));
+ SQLULEN colsize;
+ SQLLEN len;
+ SQLLEN *strlen = colp->GetStrLen();
+ SQLRETURN rc;
+
+#if 0
+ try {
+ // This function is often not or badly implemented by data sources
+ rc = SQLDescribeParam(m_hstmt, n, &sqlt, &colsize, &dec, &nul);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLDescribeParam", m_hstmt);
+
+ } catch(DBX *x) {
+ sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+#endif // 0
+ colsize = colp->GetPrecision();
+ sqlt = GetSQLType(buftype);
+ dec = IsTypeNum(buftype) ? colp->GetScale() : 0;
+ nul = colp->IsNullable() ? SQL_NULLABLE : SQL_NO_NULLS;
+//} // end try/catch
+
+ buf = colp->GetBuffer(0);
+ len = IsTypeChar(buftype) ? colp->GetBuflen() : 0;
+ ct = GetSQLCType(buftype);
+ *strlen = IsTypeChar(buftype) ? SQL_NTS : 0;
+
+ try {
+ rc = SQLBindParameter(m_hstmt, n, SQL_PARAM_INPUT, ct, sqlt,
+ colsize, dec, buf, len, strlen);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLBindParameter", m_hstmt);
+
+ } catch(DBX *x) {
+ strcpy(m_G->Message, x->GetErrorMessage(0));
+ SQLCancel(m_hstmt);
+ rc = SQLFreeStmt(m_hstmt, SQL_DROP);
+ m_hstmt = NULL;
+ return true;
+ } // end try/catch
+
+ return false;
+ } // end of BindParam
+
+/***********************************************************************/
+/* Execute an SQL command. */
+/***********************************************************************/
+bool ODBConn::ExecSQLcommand(char *sql)
+ {
+ char cmd[16];
+ bool b, rcd = false;
+ UINT txn = 0;
+ PGLOBAL& g = m_G;
+ SWORD ncol = 0;
+ SQLLEN afrw;
+ RETCODE rc;
+ HSTMT hstmt;
+
+ try {
+ b = FALSE;
+
+ // Check whether we should use transaction
+ if (sscanf(sql, " %15s ", cmd) == 1) {
+ if (!stricmp(cmd, "INSERT") || !stricmp(cmd, "UPDATE") ||
+ !stricmp(cmd, "DELETE") || !stricmp(cmd, "REPLACE")) {
+ // Does the data source support transactions
+ rc = SQLGetInfo(m_hdbc, SQL_TXN_CAPABLE, &txn, 0, NULL);
+
+ if (Check(rc) && txn != SQL_TC_NONE) {
+ rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
+ SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLSetConnectAttr");
+
+ m_Transact = TRUE;
+ } // endif txn
+
+ } // endif cmd
+
+ } // endif sql
+
+ // Allocate the statement handle
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
+
+ OnSetOptions(hstmt);
+ b = true;
+
+ if (trace(1))
+ htrc("ExecSQLcommand hstmt=%p %.64s\n", hstmt, sql);
+
+ // Proceed with command execution
+ do {
+ rc = SQLExecDirect(hstmt, (PUCHAR)sql, SQL_NTS);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLExecDirect", hstmt);
+
+ // Check whether this is a query returning a result set
+ if (!Check(rc = SQLNumResultCols(hstmt, &ncol)))
+ ThrowDBX(rc, "SQLNumResultCols", hstmt);
+
+ if (!ncol) {
+ if (!Check(SQLRowCount(hstmt, &afrw)))
+ ThrowDBX(rc, "SQLRowCount", hstmt);
+
+ m_Tdb->AftRows = (int)afrw;
+ strcpy(g->Message, "Affected rows");
+ } else {
+ m_Tdb->AftRows = (int)ncol;
+ strcpy(g->Message, "Result set column number");
+ } // endif ncol
+
+ } catch(DBX *x) {
+ if (trace(1))
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ sprintf(g->Message, "Remote %s: %s", x->m_Msg, x->GetErrorMessage(0));
+
+ if (b)
+ SQLCancel(hstmt);
+
+ m_Tdb->AftRows = -1;
+ rcd = true;
+ } // end try/catch
+
+ if (!Check(rc = SQLFreeStmt(hstmt, SQL_CLOSE)))
+ sprintf(g->Message, "SQLFreeStmt: rc=%d", rc);
+
+ if (m_Transact) {
+ // Terminate the transaction
+ if (!Check(rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc,
+ (rcd) ? SQL_ROLLBACK : SQL_COMMIT)))
+ sprintf(g->Message, "SQLEndTran: rc=%d", rc);
+
+ if (!Check(rc = SQLSetConnectAttr(m_hdbc, SQL_ATTR_AUTOCOMMIT,
+ (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER)))
+ sprintf(g->Message, "SQLSetConnectAttr: rc=%d", rc);
+
+ m_Transact = false;
+ } // endif m_Transact
+
+ return rcd;
+ } // end of ExecSQLcommand
+
+/**************************************************************************/
+/* GetMetaData: constructs the result blocks containing the */
+/* description of all the columns of an SQL command. */
+/**************************************************************************/
+PQRYRES ODBConn::GetMetaData(PGLOBAL g, PCSZ dsn, PCSZ src)
+ {
+ static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_INT,
+ TYPE_SHORT, TYPE_SHORT};
+ static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_PREC,
+ FLD_SCALE, FLD_NULL};
+ static unsigned int length[] = {0, 6, 10, 6, 6};
+ unsigned char cn[60];
+ int qcol = 5;
+ short nl, type, prec, nul, cns = (short)sizeof(cn);
+ PQRYRES qrp = NULL;
+ PCOLRES crp;
+ USHORT i;
+ SQLULEN n;
+ SWORD ncol;
+ RETCODE rc;
+ HSTMT hstmt;
+
+ try {
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
+
+ OnSetOptions(hstmt);
+
+ do {
+ rc = SQLPrepare(hstmt, (PUCHAR)src, SQL_NTS);
+// rc = SQLExecDirect(hstmt, (PUCHAR)src, SQL_NTS);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLExecDirect", hstmt);
+
+ do {
+ rc = SQLNumResultCols(hstmt, &ncol);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLNumResultCols", hstmt);
+
+ if (ncol) for (i = 1; i <= ncol; i++) {
+ do {
+ rc = SQLDescribeCol(hstmt, i, NULL, 0, &nl, NULL, NULL, NULL, NULL);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLDescribeCol", hstmt);
+
+ length[0] = MY_MAX(length[0], (UINT)nl);
+ } // endfor i
+
+ } catch(DBX *x) {
+ sprintf(g->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ goto err;
+ } // end try/catch
+
+ if (!ncol) {
+ strcpy(g->Message, "Invalid Srcdef");
+ goto err;
+ } // endif ncol
+
+ /************************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /************************************************************************/
+ if (!(qrp = PlgAllocResult(g, qcol, ncol, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, true)))
+ return NULL;
+
+ // Some columns must be renamed
+ for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
+ switch (++i) {
+ case 3: crp->Name = "Precision"; break;
+ case 4: crp->Name = "Scale"; break;
+ case 5: crp->Name = "Nullable"; break;
+ } // endswitch i
+
+ /************************************************************************/
+ /* Now get the results into blocks. */
+ /************************************************************************/
+ try {
+ for (i = 0; i < ncol; i++) {
+ do {
+ rc = SQLDescribeCol(hstmt, i+1, cn, cns, &nl, &type, &n, &prec, &nul);
+ } while (rc == SQL_STILL_EXECUTING);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLDescribeCol", hstmt);
+ else
+ qrp->Nblin++;
+
+ crp = qrp->Colresp; // Column_Name
+ crp->Kdata->SetValue((char*)cn, i);
+ crp = crp->Next; // Data_Type
+ crp->Kdata->SetValue(type, i);
+ crp = crp->Next; // Precision (length)
+ crp->Kdata->SetValue((int)n, i);
+ crp = crp->Next; // Scale
+ crp->Kdata->SetValue(prec, i);
+ crp = crp->Next; // Nullable
+ crp->Kdata->SetValue(nul, i);
+ } // endfor i
+
+ } catch(DBX *x) {
+ sprintf(g->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ qrp = NULL;
+ } // end try/catch
+
+ /* Cleanup */
+ err:
+ SQLCancel(hstmt);
+ rc = SQLFreeStmt(hstmt, SQL_DROP);
+ Close();
+
+ /************************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /************************************************************************/
+ return qrp;
+ } // end of GetMetaData
+
+/***********************************************************************/
+/* Get the list of Data Sources and set it in qrp. */
+/***********************************************************************/
+bool ODBConn::GetDataSources(PQRYRES qrp)
+ {
+ bool rv = false;
+ UCHAR *dsn, *des;
+ UWORD dir = SQL_FETCH_FIRST;
+ SWORD n1, n2, p1, p2;
+ PCOLRES crp1 = qrp->Colresp, crp2 = qrp->Colresp->Next;
+ RETCODE rc;
+
+ n1 = crp1->Clen;
+ n2 = crp2->Clen;
+
+ try {
+ rc = SQLAllocEnv(&m_henv);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLAllocEnv"); // Fatal
+
+ for (int i = 0; i < qrp->Maxres; i++) {
+ dsn = (UCHAR*)crp1->Kdata->GetValPtr(i);
+ des = (UCHAR*)crp2->Kdata->GetValPtr(i);
+ rc = SQLDataSources(m_henv, dir, dsn, n1, &p1, des, n2, &p2);
+
+ if (rc == SQL_NO_DATA_FOUND)
+ break;
+ else if (!Check(rc))
+ ThrowDBX(rc, "SQLDataSources");
+
+ qrp->Nblin++;
+ dir = SQL_FETCH_NEXT;
+ } // endfor i
+
+ } catch(DBX *x) {
+ sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ rv = true;
+ } // end try/catch
+
+ Close();
+ return rv;
+ } // end of GetDataSources
+
+/***********************************************************************/
+/* Get the list of Drivers and set it in qrp. */
+/***********************************************************************/
+bool ODBConn::GetDrivers(PQRYRES qrp)
+ {
+ int i, n;
+ bool rv = false;
+ UCHAR *des, *att;
+ UWORD dir = SQL_FETCH_FIRST;
+ SWORD n1, n2, p1, p2;
+ PCOLRES crp1 = qrp->Colresp, crp2 = qrp->Colresp->Next;
+ RETCODE rc;
+
+ n1 = crp1->Clen;
+ n2 = crp2->Clen;
+
+ try {
+ rc = SQLAllocEnv(&m_henv);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLAllocEnv"); // Fatal
+
+ for (n = 0; n < qrp->Maxres; n++) {
+ des = (UCHAR*)crp1->Kdata->GetValPtr(n);
+ att = (UCHAR*)crp2->Kdata->GetValPtr(n);
+ rc = SQLDrivers(m_henv, dir, des, n1, &p1, att, n2, &p2);
+
+ if (rc == SQL_NO_DATA_FOUND)
+ break;
+ else if (!Check(rc))
+ ThrowDBX(rc, "SQLDrivers");
+
+
+ // The attributes being separated by '\0', set them to ';'
+ for (i = 0; i < p2; i++)
+ if (!att[i])
+ att[i] = ';';
+
+ qrp->Nblin++;
+ dir = SQL_FETCH_NEXT;
+ } // endfor n
+
+ } catch(DBX *x) {
+ sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ rv = true;
+ } // end try/catch
+
+ Close();
+ return rv;
+ } // end of GetDrivers
+
+/***********************************************************************/
+/* A helper class to split an optionally qualified table name into */
+/* components. */
+/* These formats are understood: */
+/* "CatalogName.SchemaName.TableName" */
+/* "SchemaName.TableName" */
+/* "TableName" */
+/***********************************************************************/
+class SQLQualifiedName
+{
+ static const uint max_parts= 3; // Catalog.Schema.Table
+ MYSQL_LEX_STRING m_part[max_parts];
+ char m_buf[512];
+
+ void lex_string_set(MYSQL_LEX_STRING *S, char *str, size_t length)
+ {
+ S->str= str;
+ S->length= length;
+ } // end of lex_string_set
+
+ void lex_string_shorten_down(MYSQL_LEX_STRING *S, size_t offs)
+ {
+ DBUG_ASSERT(offs <= S->length);
+ S->str+= offs;
+ S->length-= offs;
+ } // end of lex_string_shorten_down
+
+ /*********************************************************************/
+ /* Find the rightmost '.' delimiter and return the length */
+ /* of the qualifier, including the rightmost '.' delimier. */
+ /* For example, for the string {"a.b.c",5} it will return 4, */
+ /* which is the length of the qualifier "a.b." */
+ /*********************************************************************/
+ size_t lex_string_find_qualifier(MYSQL_LEX_STRING *S)
+ {
+ size_t i;
+ for (i= S->length; i > 0; i--)
+ {
+ if (S->str[i - 1] == '.')
+ {
+ S->str[i - 1]= '\0';
+ return i;
+ }
+ }
+ return 0;
+ } // end of lex_string_find_qualifier
+
+public:
+ /*********************************************************************/
+ /* Initialize to the given optionally qualified name. */
+ /* NULL pointer in "name" is supported. */
+ /* name qualifier has precedence over schema. */
+ /*********************************************************************/
+ SQLQualifiedName(CATPARM *cap)
+ {
+ const char *name = (const char *)cap->Tab;
+ char *db = (char *)cap->DB;
+ size_t len, i;
+
+ // Initialize the parts
+ for (i = 0 ; i < max_parts; i++)
+ lex_string_set(&m_part[i], NULL, 0);
+
+ if (name) {
+ // Initialize the first (rightmost) part
+ lex_string_set(&m_part[0], m_buf,
+ strmake(m_buf, name, sizeof(m_buf) - 1) - m_buf);
+
+ // Initialize the other parts, if exist.
+ for (i= 1; i < max_parts; i++) {
+ if (!(len= lex_string_find_qualifier(&m_part[i - 1])))
+ break;
+
+ lex_string_set(&m_part[i], m_part[i - 1].str, len - 1);
+ lex_string_shorten_down(&m_part[i - 1], len);
+ } // endfor i
+
+ } // endif name
+
+ // If it was not specified, set schema as the passed db name
+ if (db && !m_part[1].length)
+ lex_string_set(&m_part[1], db, strlen(db));
+
+ } // end of SQLQualifiedName
+
+ SQLCHAR *ptr(uint i)
+ {
+ DBUG_ASSERT(i < max_parts);
+ return (SQLCHAR *) (m_part[i].length ? m_part[i].str : NULL);
+ } // end of ptr
+
+ SQLSMALLINT length(uint i)
+ {
+ DBUG_ASSERT(i < max_parts);
+ return (SQLSMALLINT)m_part[i].length;
+ } // end of length
+
+}; // end of class SQLQualifiedName
+
+/***********************************************************************/
+/* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */
+/***********************************************************************/
+int ODBConn::GetCatInfo(CATPARM *cap)
+ {
+ PGLOBAL& g = m_G;
+ void *buffer;
+ int i, irc;
+ bool b;
+ PCSZ fnc = "Unknown";
+ UWORD n = 0;
+ SWORD ncol, len, tp;
+ SQLULEN crow = 0;
+ PQRYRES qrp = cap->Qrp;
+ PCOLRES crp;
+ RETCODE rc = 0;
+ HSTMT hstmt = NULL;
+ SQLLEN *vl, *vlen = NULL;
+ PVAL *pval = NULL;
+ char* *pbuf = NULL;
+
+ try {
+ b = false;
+
+ if (!m_hstmt) {
+ rc = SQLAllocStmt(m_hdbc, &hstmt);
+
+ if (!Check(rc))
+ ThrowDBX(SQL_INVALID_HANDLE, "SQLAllocStmt");
+
+ } else
+ ThrowDBX(MSG(SEQUENCE_ERROR));
+
+ b = true;
+
+ // Currently m_Catver should be always 0 here
+ assert(!m_Catver); // This may be temporary
+
+ if (qrp->Maxres > 0)
+ m_RowsetSize = 1;
+ else
+ ThrowDBX("0-sized result");
+
+ SQLQualifiedName name(cap);
+
+ // Now do call the proper ODBC API
+ switch (cap->Id) {
+ case CAT_TAB:
+ fnc = "SQLTables";
+ rc = SQLTables(hstmt, name.ptr(2), name.length(2),
+ name.ptr(1), name.length(1),
+ name.ptr(0), name.length(0),
+ (SQLCHAR *)cap->Pat,
+ cap->Pat ? SQL_NTS : 0);
+ break;
+ case CAT_COL:
+ fnc = "SQLColumns";
+ rc = SQLColumns(hstmt, name.ptr(2), name.length(2),
+ name.ptr(1), name.length(1),
+ name.ptr(0), name.length(0),
+ (SQLCHAR *)cap->Pat,
+ cap->Pat ? SQL_NTS : 0);
+ break;
+ case CAT_KEY:
+ fnc = "SQLPrimaryKeys";
+ rc = SQLPrimaryKeys(hstmt, name.ptr(2), name.length(2),
+ name.ptr(1), name.length(1),
+ name.ptr(0), name.length(0));
+ break;
+ case CAT_STAT:
+ fnc = "SQLStatistics";
+ rc = SQLStatistics(hstmt, name.ptr(2), name.length(2),
+ name.ptr(1), name.length(1),
+ name.ptr(0), name.length(0),
+ cap->Unique, cap->Accuracy);
+ break;
+ case CAT_SPC:
+ ThrowDBX("SQLSpecialColumns not available yet");
+ default:
+ ThrowDBX("Invalid SQL function id");
+ } // endswitch infotype
+
+ if (!Check(rc))
+ ThrowDBX(rc, fnc, hstmt);
+
+ // Some data source do not implement SQLNumResultCols
+ if (Check(SQLNumResultCols(hstmt, &ncol)))
+ // n because we no more ignore the first column
+ if ((n = (UWORD)qrp->Nbcol) > (UWORD)ncol)
+ ThrowDBX(MSG(COL_NUM_MISM));
+
+ // Unconditional to handle STRBLK's
+ pval = (PVAL *)PlugSubAlloc(g, NULL, n * sizeof(PVAL));
+ vlen = (SQLLEN *)PlugSubAlloc(g, NULL, n * sizeof(SQLLEN));
+ pbuf = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
+
+ // Now bind the column buffers
+ for (n = 0, crp = qrp->Colresp; crp; crp = crp->Next) {
+ if ((tp = GetSQLCType(crp->Type)) == SQL_TYPE_NULL) {
+ sprintf(g->Message, MSG(INV_COLUMN_TYPE), crp->Type, crp->Name);
+ ThrowDBX(g->Message);
+ } // endif tp
+
+ if (!(len = GetTypeSize(crp->Type, crp->Length))) {
+ len = 255; // for STRBLK's
+ ((STRBLK*)crp->Kdata)->SetSorted(true);
+ } // endif len
+
+ pval[n] = AllocateValue(g, crp->Type, len);
+ pval[n]->SetNullable(true);
+
+ if (crp->Type == TYPE_STRING) {
+ pbuf[n] = (char*)PlugSubAlloc(g, NULL, len);
+ buffer = pbuf[n];
+ } else
+ buffer = pval[n]->GetTo_Val();
+
+ vl = vlen + n;
+
+ // n + 1 because column numbers begin with 1
+ rc = SQLBindCol(hstmt, n + 1, tp, buffer, len, vl);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLBindCol", hstmt);
+
+ n++;
+ } // endfor crp
+
+ fnc = "SQLFetch";
+
+ // Now fetch the result
+ // Extended fetch cannot be used because of STRBLK's
+ for (i = 0; i < qrp->Maxres; i++) {
+ if ((rc = SQLFetch(hstmt)) == SQL_NO_DATA_FOUND)
+ break;
+ else if (rc != SQL_SUCCESS) {
+ if (trace(2) || (trace(1) && rc != SQL_SUCCESS_WITH_INFO)) {
+ UCHAR msg[SQL_MAX_MESSAGE_LENGTH + 1];
+ UCHAR state[SQL_SQLSTATE_SIZE + 1];
+ RETCODE erc;
+ SDWORD native;
+
+ htrc("SQLFetch: row %d rc=%d\n", i+1, rc);
+ erc = SQLError(m_henv, m_hdbc, hstmt, state, &native, msg,
+ SQL_MAX_MESSAGE_LENGTH - 1, &len);
+
+ if (rc != SQL_INVALID_HANDLE)
+ // Skip non-errors
+ for (n = 0; n < MAX_NUM_OF_MSG
+ && (erc == SQL_SUCCESS || erc == SQL_SUCCESS_WITH_INFO)
+ && strcmp((char*)state, "00000"); n++) {
+ htrc("%s: %s, Native=%d\n", state, msg, native);
+ erc = SQLError(m_henv, m_hdbc, hstmt, state, &native,
+ msg, SQL_MAX_MESSAGE_LENGTH - 1, &len);
+ } // endfor n
+
+ } // endif trace
+
+ if (rc != SQL_SUCCESS_WITH_INFO)
+ qrp->BadLines++;
+
+ } // endif rc
+
+ for (n = 0, crp = qrp->Colresp; crp; n++, crp = crp->Next) {
+ if (vlen[n] == SQL_NO_TOTAL)
+ ThrowDBX("Unexpected SQL_NO_TOTAL returned from SQLFetch");
+ else if (vlen[n] == SQL_NULL_DATA)
+ pval[n]->SetNull(true);
+ else if (crp->Type == TYPE_STRING/* && vlen[n] != SQL_NULL_DATA*/)
+ pval[n]->SetValue_char(pbuf[n], (int)vlen[n]);
+ else
+ pval[n]->SetNull(false);
+
+ crp->Kdata->SetValue(pval[n], i);
+ cap->Vlen[n][i] = vlen[n];
+ } // endfor crp
+
+ } // endfor i
+
+#if 0
+ if ((crow = i) && (rc == SQL_NO_DATA || rc == SQL_SUCCESS_WITH_INFO))
+ rc = SQL_SUCCESS;
+
+ if (rc == SQL_NO_DATA_FOUND) {
+ if (cap->Pat)
+ sprintf(g->Message, MSG(NO_TABCOL_DATA), cap->Tab, cap->Pat);
+ else
+ sprintf(g->Message, MSG(NO_TAB_DATA), cap->Tab);
+
+ ThrowDBX(g->Message);
+ } else if (rc == SQL_SUCCESS) {
+ if ((rc = SQLFetch(hstmt)) != SQL_NO_DATA_FOUND)
+ qrp->Truncated = true;
+
+ } else
+ ThrowDBX(rc, fnc, hstmt);
+#endif // 0
+
+ if (!rc || rc == SQL_NO_DATA || rc == SQL_SUCCESS_WITH_INFO) {
+ if ((rc = SQLFetch(hstmt)) != SQL_NO_DATA_FOUND)
+ qrp->Truncated = true;
+
+ crow = i;
+ } else
+ ThrowDBX(rc, fnc, hstmt);
+
+ irc = (int)crow;
+ } catch(DBX *x) {
+ if (trace(1))
+ for (int i = 0; i < MAX_NUM_OF_MSG && x->m_ErrMsg[i]; i++)
+ htrc(x->m_ErrMsg[i]);
+
+ sprintf(g->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ irc = -1;
+ } // end try/catch
+
+ if (b)
+ SQLCancel(hstmt);
+
+ // All this (hstmt vs> m_hstmt) to be revisited
+ if (hstmt)
+ rc = SQLFreeStmt(hstmt, SQL_DROP);
+
+ return irc;
+ } // end of GetCatInfo
+
+/***********************************************************************/
+/* Allocate a CONNECT result structure from the ODBC result. */
+/***********************************************************************/
+PQRYRES ODBConn::AllocateResult(PGLOBAL g)
+ {
+ bool uns;
+ PODBCCOL colp;
+ PCOLRES *pcrp, crp;
+ PQRYRES qrp;
+
+ if (!m_Rows) {
+ strcpy(g->Message, "Void result");
+ return NULL;
+ } // endif m_Res
+
+ /*********************************************************************/
+ /* Allocate the result storage for future retrieval. */
+ /*********************************************************************/
+ qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
+ pcrp = &qrp->Colresp;
+ qrp->Continued = FALSE;
+ qrp->Truncated = FALSE;
+ qrp->Info = FALSE;
+ qrp->Suball = TRUE;
+ qrp->BadLines = 0;
+ qrp->Maxsize = m_Rows;
+ qrp->Maxres = m_Rows;
+ qrp->Nbcol = 0;
+ qrp->Nblin = 0;
+ qrp->Cursor = 0;
+
+ for (colp = (PODBCCOL)m_Tdb->Columns; colp;
+ colp = (PODBCCOL)colp->GetNext())
+ if (!colp->IsSpecial()) {
+ *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
+ crp = *pcrp;
+ pcrp = &crp->Next;
+ memset(crp, 0, sizeof(COLRES));
+ crp->Ncol = ++qrp->Nbcol;
+ crp->Name = colp->GetName();
+ crp->Type = colp->GetResultType();
+ crp->Prec = colp->GetScale();
+ crp->Length = colp->GetLength();
+ crp->Clen = colp->GetBuflen();
+ uns = colp->IsUnsigned();
+
+ if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
+ crp->Clen, 0, FALSE, TRUE, uns))) {
+ sprintf(g->Message, MSG(INV_RESULT_TYPE),
+ GetFormatType(crp->Type));
+ return NULL;
+ } // endif Kdata
+
+ if (!colp->IsNullable())
+ crp->Nulls = NULL;
+ else {
+ crp->Nulls = (char*)PlugSubAlloc(g, NULL, m_Rows);
+ memset(crp->Nulls, ' ', m_Rows);
+ } // endelse Nullable
+
+ colp->SetCrp(crp);
+ } // endif colp
+
+ *pcrp = NULL;
+//qrp->Nblin = n;
+ return qrp;
+ } // end of AllocateResult
+
+/***********************************************************************/
+/* Restart from beginning of result set */
+/***********************************************************************/
+int ODBConn::Rewind(char *sql, ODBCCOL *tocols)
+ {
+ int rc, rbuf = -1;
+
+ if (!m_hstmt)
+ rbuf = -1;
+ else if (m_Full)
+ rbuf = m_Rows; // No need to "rewind"
+ else if (m_Scrollable) {
+ SQLULEN crow;
+
+ try {
+ rc = SQLExtendedFetch(m_hstmt, SQL_FETCH_FIRST, 1, &crow, NULL);
+
+ if (!Check(rc))
+ ThrowDBX(rc, "SQLExtendedFetch", m_hstmt);
+
+ rbuf = (int)crow;
+ } catch(DBX *x) {
+ sprintf(m_G->Message, "%s: %s", x->m_Msg, x->GetErrorMessage(0));
+ rbuf = -1;
+ } // end try/catch
+
+ } else if (ExecDirectSQL(sql, tocols) >= 0)
+ rbuf = 0;
+
+ return rbuf;
+ } // end of Rewind
+
+/***********************************************************************/
+/* Disconnect connection */
+/***********************************************************************/
+void ODBConn::Close()
+ {
+ RETCODE rc;
+
+ if (m_hstmt) {
+ // Is required for multiple tables
+ rc = SQLFreeStmt(m_hstmt, SQL_DROP);
+ m_hstmt = NULL;
+ } // endif m_hstmt
+
+ if (m_hdbc != SQL_NULL_HDBC) {
+ if (m_Transact) {
+ rc = SQLEndTran(SQL_HANDLE_DBC, m_hdbc, SQL_COMMIT);
+ m_Transact = false;
+ } // endif m_Transact
+
+ rc = SQLDisconnect(m_hdbc);
+
+ if (trace(1) && rc != SQL_SUCCESS)
+ htrc("Error: SQLDisconnect rc=%d\n", rc);
+
+ rc = SQLFreeConnect(m_hdbc);
+
+ if (trace(1) && rc != SQL_SUCCESS)
+ htrc("Error: SQLFreeConnect rc=%d\n", rc);
+
+ m_hdbc = SQL_NULL_HDBC;
+ } // endif m_hdbc
+
+ if (m_henv != SQL_NULL_HENV) {
+ rc = SQLFreeEnv(m_henv);
+
+ if (trace(1) && rc != SQL_SUCCESS) // Nothing we can do
+ htrc("Error: SQLFreeEnv failure ignored in Close\n");
+
+ m_henv = SQL_NULL_HENV;
+ } // endif m_henv
+
+ if (m_Fp)
+ m_Fp->Count = 0;
+
+ } // end of Close
diff --git a/storage/connect/odbconn.h b/storage/connect/odbconn.h
new file mode 100644
index 00000000..7038f06e
--- /dev/null
+++ b/storage/connect/odbconn.h
@@ -0,0 +1,202 @@
+/***********************************************************************/
+/* ODBConn.h : header file for the ODBC connection classes. */
+/***********************************************************************/
+//nclude <windows.h> /* Windows include file */
+//nclude <windowsx.h> /* Message crackers */
+
+/***********************************************************************/
+/* Included C-definition files required by the interface. */
+/***********************************************************************/
+#include "block.h"
+
+/***********************************************************************/
+/* ODBC interface. */
+/***********************************************************************/
+#include <sql.h>
+#include <sqlext.h>
+
+/***********************************************************************/
+/* Constants and defines. */
+/***********************************************************************/
+// Miscellaneous sizing info
+#define MAX_NUM_OF_MSG 10 // Max number of error messages
+//efine MAX_CURRENCY 30 // Max size of Currency($) string
+#define MAX_TNAME_LEN 32 // Max size of table names
+//efine MAX_FNAME_LEN 256 // Max size of field names
+#define MAX_STRING_INFO 256 // Max size of string from SQLGetInfo
+//efine MAX_DNAME_LEN 256 // Max size of Recordset names
+#define MAX_CONNECT_LEN 1024 // Max size of Connect string
+//efine MAX_CURSOR_NAME 18 // Max size of a cursor name
+//efine DEFAULT_FIELD_TYPE SQL_TYPE_NULL // pick "C" data type to match SQL data type
+
+#if !defined(_WIN32)
+typedef unsigned char *PUCHAR;
+#endif // !_WIN32
+
+// Field Flags, used to indicate status of fields
+//efine SQL_FIELD_FLAG_DIRTY 0x1
+//efine SQL_FIELD_FLAG_NULL 0x2
+
+// Update options flags
+#define SQL_SETPOSUPDATES 0x0001
+#define SQL_POSITIONEDSQL 0x0002
+//efine SQL_GDBOUND 0x0004
+
+enum CATINFO {CAT_TAB = 1, /* SQLTables */
+ CAT_COL = 2, /* SQLColumns */
+ CAT_KEY = 3, /* SQLPrimaryKeys */
+ CAT_STAT = 4, /* SQLStatistics */
+ CAT_SPC = 5}; /* SQLSpecialColumns */
+
+/***********************************************************************/
+/* This structure is used to control the catalog functions. */
+/***********************************************************************/
+typedef struct tagCATPARM {
+ CATINFO Id; // Id to indicate function
+ PQRYRES Qrp; // Result set pointer
+ PCSZ DB; // Database (Schema)
+ PCSZ Tab; // Table name or pattern
+ PCSZ Pat; // Table type or column pattern
+ SQLLEN* *Vlen; // To array of indicator values
+ UWORD *Status; // To status block
+ // For SQLStatistics
+ UWORD Unique; // Index type
+ UWORD Accuracy; // For Cardinality and Pages
+ // For SQLSpecialColumns
+ UWORD ColType;
+ UWORD Scope;
+ UWORD Nullable;
+ } CATPARM;
+
+// ODBC connection to a data source
+class TDBODBC;
+class ODBCCOL;
+class ODBConn;
+
+/***********************************************************************/
+/* Class DBX (ODBC exception). */
+/***********************************************************************/
+class DBX : public BLOCK {
+ friend class ODBConn;
+ // Construction (by ThrowDBX only) -- destruction
+ protected:
+ DBX(RETCODE rc, PCSZ msg = NULL);
+ public:
+//virtual ~DBX() {}
+//void operator delete(void*, PGLOBAL, void*) {};
+
+ // Implementation (use ThrowDBX to create)
+ RETCODE GetRC(void) {return m_RC;}
+ PCSZ GetMsg(void) {return m_Msg;}
+ PCSZ GetErrorMessage(int i);
+
+ protected:
+ bool BuildErrorMessage(ODBConn* pdb, HSTMT hstmt = SQL_NULL_HSTMT);
+
+ // Attributes
+ RETCODE m_RC;
+ PCSZ m_Msg;
+ PCSZ m_ErrMsg[MAX_NUM_OF_MSG];
+ }; // end of DBX class definition
+
+/***********************************************************************/
+/* ODBConn class. */
+/***********************************************************************/
+class ODBConn : public BLOCK {
+ friend class TDBODBC;
+ friend class DBX;
+//friend PQRYRES GetColumnInfo(PGLOBAL, char*&, char *, int, PVBLK&);
+ private:
+ ODBConn(); // Standard (unused) constructor
+
+ public:
+ ODBConn(PGLOBAL g, TDBODBC *tdbp);
+
+ enum DOP { // Db Open oPtions
+ traceSQL = 0x0001, // Trace SQL calls
+ openReadOnly = 0x0002, // Open database read only
+ useCursorLib = 0x0004, // Use ODBC cursor lib
+ noOdbcDialog = 0x0008, // Don't display ODBC Connect dialog
+ forceOdbcDialog = 0x0010}; // Always display ODBC connect dialog
+
+ int Open(PCSZ ConnectString, POPARM sop, DWORD Options = 0);
+ int Rewind(char *sql, ODBCCOL *tocols);
+ void Close(void);
+ PQRYRES AllocateResult(PGLOBAL g);
+
+ // Attributes
+ public:
+ char *GetQuoteChar(void) {return m_IDQuoteChar;}
+ // Database successfully opened?
+ bool IsOpen(void) {return m_hdbc != SQL_NULL_HDBC;}
+ PSZ GetStringInfo(ushort infotype);
+ int GetMaxValue(ushort infotype);
+ PCSZ GetConnect(void) {return m_Connect;}
+
+ public:
+ // Operations
+//void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;}
+//void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;}
+//void SetUserName(PSZ user) {m_User = user;}
+//void SetUserPwd(PSZ pwd) {m_Pwd = pwd;}
+ int GetResultSize(char *sql, ODBCCOL *colp);
+ int ExecDirectSQL(char *sql, ODBCCOL *tocols);
+ int Fetch(int pos = 0);
+ int PrepareSQL(char *sql);
+ int ExecuteSQL(void);
+ bool BindParam(ODBCCOL *colp);
+ bool ExecSQLcommand(char *sql);
+ int GetCatInfo(CATPARM *cap);
+ bool GetDataSources(PQRYRES qrp);
+ bool GetDrivers(PQRYRES qrp);
+ PQRYRES GetMetaData(PGLOBAL g, PCSZ dsn, PCSZ src);
+
+ public:
+ // Set special options
+ void OnSetOptions(HSTMT hstmt);
+
+ // Implementation
+ public:
+//virtual ~ODBConn();
+
+ // ODBC operations
+ protected:
+ bool Check(RETCODE rc);
+ void ThrowDBX(RETCODE rc, PCSZ msg, HSTMT hstmt = SQL_NULL_HSTMT);
+ void ThrowDBX(PCSZ msg);
+ void AllocConnect(DWORD dwOptions);
+ void Connect(void);
+ bool DriverConnect(DWORD Options);
+ void VerifyConnect(void);
+ void GetConnectInfo(void);
+//void Free(void);
+
+ protected:
+ // Static members
+//static HENV m_henv;
+//static int m_nAlloc; // per-Appl reference to HENV above
+
+ // Members
+ PGLOBAL m_G;
+ TDBODBC *m_Tdb;
+ HENV m_henv;
+ HDBC m_hdbc;
+ HSTMT m_hstmt;
+ DWORD m_LoginTimeout;
+ DWORD m_QueryTimeout;
+ DWORD m_UpdateOptions;
+ DWORD m_RowsetSize;
+ char m_IDQuoteChar[2];
+ PFBLOCK m_Fp;
+ PCSZ m_Connect;
+ PCSZ m_User;
+ PCSZ m_Pwd;
+ int m_Catver;
+ int m_Rows;
+ int m_Fetch;
+ bool m_Updatable;
+ bool m_Transact;
+ bool m_Scrollable;
+ bool m_UseCnc;
+ bool m_Full;
+ }; // end of ODBConn class definition
diff --git a/storage/connect/os.h b/storage/connect/os.h
new file mode 100644
index 00000000..7d0d5cab
--- /dev/null
+++ b/storage/connect/os.h
@@ -0,0 +1,70 @@
+/* Copyright (C) MariaDB Corporation Ab */
+#ifndef _OS_H_INCLUDED
+#define _OS_H_INCLUDED
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
+typedef off_t off64_t;
+#define lseek64(fd, offset, whence) lseek((fd), (offset), (whence))
+#define open64(path, flags, mode) open((path), (flags), (mode))
+#define ftruncate64(fd, length) ftruncate((fd), (length))
+#define O_LARGEFILE 0
+#endif
+
+#ifdef _AIX
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0
+#endif
+#endif
+
+#if defined(_WIN32)
+typedef __int64 BIGINT;
+typedef _Null_terminated_ const char *PCSZ;
+#else // !_WIN32
+typedef longlong BIGINT;
+#define FILE_BEGIN SEEK_SET
+#define FILE_CURRENT SEEK_CUR
+#define FILE_END SEEK_END
+typedef const char *PCSZ;
+#endif // !_WIN32
+
+
+#if !defined(_WIN32)
+typedef const void *LPCVOID;
+typedef const char *LPCTSTR;
+typedef const char *LPCSTR;
+typedef unsigned char BYTE;
+typedef char *LPSTR;
+typedef char *LPTSTR;
+typedef char *PSZ;
+typedef long BOOL;
+typedef int INT;
+#if !defined(NODW)
+/*
+ sqltypes.h from unixODBC incorrectly defines
+ DWORD as "unsigned int" instead of "unsigned long" on 64-bit platforms.
+ Add "#define NODW" into all files including this file that include
+ sqltypes.h (through sql.h or sqlext.h).
+*/
+typedef unsigned long DWORD;
+#endif // !NODW
+#undef HANDLE
+typedef int HANDLE;
+
+#define stricmp strcasecmp
+#define _stricmp strcasecmp
+#define strnicmp strncasecmp
+#define _strnicmp strncasecmp
+#ifdef PATH_MAX
+#define _MAX_PATH PATH_MAX
+#else
+#define _MAX_PATH FN_REFLEN
+#endif
+#define _MAX_DRIVE 3
+#define _MAX_DIR FN_REFLEN
+#define _MAX_FNAME FN_HEADLEN
+#define _MAX_EXT FN_EXTLEN
+#define INVALID_HANDLE_VALUE (-1)
+#define __stdcall
+#endif /* !_WIN32 */
+
+#endif /* _OS_H_INCLUDED */
diff --git a/storage/connect/osutil.c b/storage/connect/osutil.c
new file mode 100644
index 00000000..278023f5
--- /dev/null
+++ b/storage/connect/osutil.c
@@ -0,0 +1,179 @@
+/* Copyright (C) MariaDB Corporation Ab */
+#include "my_global.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "osutil.h"
+
+#ifdef _WIN32
+my_bool CloseFileHandle(HANDLE h)
+ {
+ return !CloseHandle(h);
+ } /* end of CloseFileHandle */
+
+#else /* UNIX */
+/* code to handle Linux and Solaris */
+#include <unistd.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+extern FILE *debug;
+
+/***********************************************************************/
+/* Define some functions not existing in the UNIX library. */
+/***********************************************************************/
+PSZ strupr(PSZ p)
+ {
+ register int i;
+
+ for (i = 0; p[i]; i++)
+ p[i] = toupper(p[i]);
+
+ return (p);
+ } /* end of strupr */
+
+PSZ strlwr(PSZ p)
+ {
+ register int i;
+
+ for (i = 0; p[i]; i++)
+ p[i] = tolower(p[i]);
+
+ return (p);
+ } /* end of strlwr */
+
+/***********************************************************************/
+/* Define the splitpath function not existing in the UNIX library. */
+/***********************************************************************/
+void _splitpath(LPCSTR name, LPSTR drive, LPSTR dir, LPSTR fn, LPSTR ft)
+ {
+ LPCSTR p2, p = name;
+
+#ifdef DEBTRACE
+ htrc("SplitPath: name=%s [%s (%d)]\n",
+ XSTR(name), XSTR(__FILE__), __LINE__);
+#endif
+
+ if (drive) *drive = '\0';
+ if (dir) *dir = '\0';
+ if (fn) *fn = '\0';
+ if (ft) *ft = '\0';
+
+ if ((p2 = strrchr(p, '/'))) {
+ p2++;
+ if (dir) strncat(dir, p, p2 - p);
+ p = p2;
+ } /* endif p2 */
+
+ if ((p2 = strrchr(p, '.'))) {
+ if (fn) strncat(fn, p, p2 - p);
+ if (ft) strcpy(ft, p2);
+ } else
+ if (fn) strcpy(fn, p);
+
+#ifdef DEBTRACE
+ htrc("SplitPath: name=%s drive=%s dir=%s filename=%s type=%s [%s(%d)]\n",
+ XSTR(name), XSTR(drive), XSTR(dir), XSTR(fn), XSTR(ft), __FILE__, __LINE__);
+#endif
+ } /* end of _splitpath */
+
+/***********************************************************************/
+/* Define the makepath function not existing in the UNIX library. */
+/***********************************************************************/
+void _makepath(LPSTR name, LPCSTR drive __attribute__((unused)), LPCSTR dir, LPCSTR fn, LPCSTR ft)
+ {
+ int n;
+
+ if (!name)
+ return;
+ else
+ *name = '\0';
+
+ if (dir && (n = strlen(dir)) > 0) {
+ strcpy(name, dir);
+
+ if (name[n-1] != '/')
+ strcat(name, "/");
+
+ } /* endif dir */
+
+ if (fn)
+ strcat(name, fn);
+
+ if (ft && strlen(ft)) {
+ if (*ft != '.')
+ strcat(name, ".");
+
+ strcat(name, ft);
+ } /* endif ft */
+
+ } /* end of _makepath */
+
+my_bool CloseFileHandle(HANDLE h)
+ {
+ return (close(h)) ? TRUE : FALSE;
+ } /* end of CloseFileHandle */
+
+int GetLastError()
+ {
+ return errno;
+ } /* end of GetLastError */
+
+unsigned long _filelength(int fd)
+ {
+ struct stat st;
+
+ if (fd == -1)
+ return 0;
+
+ if (fstat(fd, &st) != 0)
+ return 0;
+
+ return st.st_size;
+ } /* end of _filelength */
+
+char *_fullpath(char *absPath, const char *relPath, size_t maxLength)
+ {
+ // Fixme
+ char *p;
+
+ if ( *relPath == '\\' || *relPath == '/' ) {
+ strncpy(absPath, relPath, maxLength);
+ } else if (*relPath == '~') {
+ // get the path to the home directory
+ struct passwd *pw = getpwuid(getuid());
+ const char *homedir = pw->pw_dir;
+
+ if (homedir)
+ strcat(strncpy(absPath, homedir, maxLength), relPath + 1);
+ else
+ strncpy(absPath, relPath, maxLength);
+
+ } else {
+ char buff[2*_MAX_PATH];
+
+ p= getcwd(buff, _MAX_PATH);
+ assert(p);
+ strcat(buff,"/");
+ strcat(buff, relPath);
+ strncpy(absPath, buff, maxLength);
+ } /* endif's relPath */
+
+ p = absPath;
+
+ for(; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+
+ return absPath;
+ } /* end of _fullpath */
+
+BOOL MessageBeep(uint i __attribute__((unused)))
+ {
+ // Fixme
+ return TRUE;
+ } /* end of MessageBeep */
+
+#endif // UNIX
diff --git a/storage/connect/osutil.h b/storage/connect/osutil.h
new file mode 100644
index 00000000..380e7beb
--- /dev/null
+++ b/storage/connect/osutil.h
@@ -0,0 +1,58 @@
+/* Copyright (C) MariaDB Corporation Ab */
+#ifndef __OSUTIL_H__
+#define __OSUTIL_H__
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#if defined(MARIADB)
+#include "my_global.h"
+#else
+#include "mini-global.h"
+#endif
+#include <errno.h>
+#include <stddef.h>
+#include "os.h"
+
+#define MB_OK 0x00000000
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int GetLastError();
+void _splitpath(const char*, char*, char*, char*, char*);
+void _makepath(char*, const char*, const char*, const char*, const char*);
+char *_fullpath(char *absPath, const char *relPath, size_t maxLength);
+BOOL MessageBeep(uint);
+unsigned long _filelength(int fd);
+
+PSZ strupr(PSZ s);
+PSZ strlwr(PSZ s);
+
+typedef size_t FILEPOS;
+//pedef int FILEHANDLE; // UNIX
+
+#ifdef __cplusplus
+}
+#endif
+
+#else /* WINDOWS */
+#include <windows.h>
+
+typedef __int64 FILEPOS;
+//pedef HANDLE FILEHANDLE; // Win32
+
+#endif /* WINDOWS */
+
+#define XSTR(x) ((x)?(x):"<null>")
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+my_bool CloseFileHandle(HANDLE h);
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __OSUTIL_H__ */
diff --git a/storage/connect/plgcnx.h b/storage/connect/plgcnx.h
new file mode 100644
index 00000000..1b341bc5
--- /dev/null
+++ b/storage/connect/plgcnx.h
@@ -0,0 +1,67 @@
+/**************************************************************************/
+/* PLGCNX.H */
+/* Copyright to the author: Olivier Bertrand 2000-2014 */
+/* */
+/* This is the connection DLL's declares. */
+/**************************************************************************/
+#if !defined(_PLGCNX_H)
+#define _PLGCNX_H
+
+#define MAXMSGLEN 65512 /* Default max length of cnx message */
+#define MAXERRMSG 512 /* Max length of error messages */
+#define MAXMESSAGE 256 /* Max length of returned messages */
+#define MAXDBNAME 128 /* Max length of DB related names */
+
+/**************************************************************************/
+/* API Function return codes. */
+/**************************************************************************/
+enum FNRC {RC_LICENSE = 7, /* PLGConnect prompt for license key */
+ RC_PASSWD = 6, /* PLGConnect prompt for User/Pwd */
+ RC_SUCWINFO = 5, /* Succes With Info return code */
+ RC_SOCKET = 4, /* RC from PLGConnect to socket DLL */
+ RC_PROMPT = 3, /* Intermediate prompt return */
+ RC_CANCEL = 2, /* Command was cancelled by user */
+ RC_PROGRESS = 1, /* Intermediate progress info */
+ RC_SUCCESS = 0, /* Successful function (must be 0) */
+ RC_MEMORY = -1, /* Storage allocation error */
+ RC_TRUNCATED = -2, /* Result has been truncated */
+ RC_TIMEOUT = -3, /* Connection timeout occurred */
+ RC_TOOBIG = -4, /* Data is too big for connection */
+ RC_KEY = -5, /* Null ptr to key in Connect */
+ /* or bad key in other functions */
+ RC_MAXCONN = -6, /* Too many conn's for one process */
+ RC_MAXCLIENT = -7, /* Too many clients for one system */
+ RC_SYNCHRO = -8, /* Synchronization error */
+ RC_SERVER = -9, /* Error related to the server */
+ RC_MAXCOL = -10, /* Result has too many columns */
+ RC_LAST = -10}; /* Other error codes are < this and */
+ /* are system errors. */
+
+/**************************************************************************/
+/* Standard function return codes. */
+/**************************************************************************/
+#if !defined(RC_OK_DEFINED)
+#define RC_OK_DEFINED
+enum RCODE {RC_OK = 0, /* No error return code */
+ RC_NF = 1, /* Not found return code */
+ RC_EF = 2, /* End of file return code */
+ RC_FX = 3, /* Error return code */
+ RC_INFO = 4}; /* Success with info */
+#endif // !RC_OK_DEFINED
+
+/**************************************************************************/
+/* Index of info values within the info int integer array. */
+/**************************************************************************/
+enum INFO {INDX_RC, /* Index of PlugDB return code field */
+ INDX_TIME, /* Index of elapsed time in millisec */
+ INDX_CHG, /* Index of Language or DB changed */
+ INDX_RSAV, /* Index of Result Set availability */
+ INDX_TYPE, /* Index of returned data type field */
+ INDX_LINE, /* Index of number of lines field */
+ INDX_LEN, /* Index of line length field */
+ INDX_SIZE, /* Index of returned data size field */
+ INDX_MAX}; /* Size of info array */
+
+#endif /* !_PLGCNX_H */
+
+/* ------------------------- End of Plgcnx.h ---------------------------- */
diff --git a/storage/connect/plgdbsem.h b/storage/connect/plgdbsem.h
new file mode 100644
index 00000000..370bf69f
--- /dev/null
+++ b/storage/connect/plgdbsem.h
@@ -0,0 +1,651 @@
+/************** PlgDBSem H Declares Source Code File (.H) **************/
+/* Name: PLGDBSEM.H Version 3.8 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2019 */
+/* */
+/* This file contains the CONNECT storage engine definitions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include required application header files */
+/***********************************************************************/
+#include "checklvl.h"
+
+/***********************************************************************/
+/* DB Constant definitions. */
+/***********************************************************************/
+#if defined(FRENCH)
+#define DEFAULT_LOCALE "French"
+#else // !FRENCH
+#define DEFAULT_LOCALE "English"
+#endif // !FRENCH
+
+#define DOS_MAX_PATH 144 /* Must be the same across systems */
+#define DOS_BUFF_LEN 100 /* Number of lines in binary file buffer */
+#undef DOMAIN /* For Unix version */
+
+enum BLKTYP {TYPE_TABLE = 50, /* Table Name/Srcdef/... Block */
+ TYPE_COLUMN = 51, /* Column Name/Qualifier Block */
+ TYPE_TDB = 53, /* Table Description Block */
+ TYPE_COLBLK = 54, /* Column Description Block */
+ TYPE_FILTER = 55, /* Filter Description Block */
+ TYPE_ARRAY = 63, /* General array type */
+ TYPE_PSZ = 64, /* Pointer to String ended by 0 */
+ TYPE_SQL = 65, /* Pointer to SQL block */
+ TYPE_XOBJECT = 69, /* Extended DB object */
+ TYPE_COLCRT = 71, /* Column creation block */
+ TYPE_CONST = 72, /* Constant */
+
+/*-------------------- additional values used by LNA ------------------*/
+ TYPE_COLIST = 14, /* Column list */
+ TYPE_COL = 41, /* Column */
+/*-------------------- types used by scalar functions -----------------*/
+ TYPE_NUM = 12,
+ TYPE_UNDEF = 13,
+/*-------------------- file blocks used when closing ------------------*/
+ TYPE_FB_FILE = 22, /* File block (stream) */
+ TYPE_FB_MAP = 23, /* Mapped file block (storage) */
+ TYPE_FB_HANDLE = 24, /* File block (handle) */
+ TYPE_FB_XML = 21, /* DOM XML file block */
+ TYPE_FB_XML2 = 27, /* libxml2 XML file block */
+ TYPE_FB_ODBC = 25, /* ODBC file block */
+ TYPE_FB_ZIP = 28, /* ZIP file block */
+ TYPE_FB_JAVA = 29, /* JAVA file block */
+ TYPE_FB_MONGO = 30}; /* MONGO file block */
+
+enum TABTYPE {TAB_UNDEF = 0, /* Table of undefined type */
+ TAB_DOS = 1, /* Fixed column offset, variable LRECL */
+ TAB_FIX = 2, /* Fixed column offset, fixed LRECL */
+ TAB_BIN = 3, /* Like FIX but can have binary fields */
+ TAB_CSV = 4, /* DOS files with CSV records */
+ TAB_FMT = 5, /* DOS files with formatted records */
+ TAB_DBF = 6, /* DBF Dbase or Foxpro files */
+ TAB_XML = 7, /* XML or HTML files */
+ TAB_INI = 8, /* INI or CFG files */
+ TAB_VEC = 9, /* Vector column arrangement */
+ TAB_ODBC = 10, /* Table accessed via (unix)ODBC */
+ TAB_MYSQL = 11, /* MySQL table accessed via MySQL API */
+ TAB_DIR = 12, /* Returns a list of files */
+ TAB_MAC = 13, /* MAC address (Windows only) */
+ TAB_WMI = 14, /* WMI tables (Windows only) */
+ TAB_TBL = 15, /* Collection of CONNECT tables */
+ TAB_OEM = 16, /* OEM implemented table */
+ TAB_XCL = 17, /* XCL table */
+ TAB_OCCUR = 18, /* OCCUR table */
+ TAB_PRX = 19, /* Proxy (catalog) table */
+ TAB_PLG = 20, /* PLG NIY */
+ TAB_PIVOT = 21, /* PIVOT table */
+ TAB_VIR = 22, /* Virtual tables */
+ TAB_JSON = 23, /* JSON tables */
+ TAB_JCT = 24, /* Junction tables NIY */
+ TAB_DMY = 25, /* DMY Dummy tables NIY */
+ TAB_JDBC = 26, /* Table accessed via JDBC */
+ TAB_ZIP = 27, /* ZIP file info table */
+ TAB_MONGO = 28, /* Table retrieved from MongoDB */
+ TAB_REST = 29, /* Table retrieved from Rest */
+ TAB_BSON = 30, /* BSON Table (development) */
+ TAB_NIY = 31}; /* Table not implemented yet */
+
+enum AMT {TYPE_AM_ERROR = 0, /* Type not defined */
+ TYPE_AM_ROWID = 1, /* ROWID type (special column) */
+ TYPE_AM_FILID = 2, /* FILEID type (special column) */
+ TYPE_AM_TAB = 3, /* Table (any type) */
+ TYPE_AM_VIEW = 4, /* VIEW (any type) */
+ TYPE_AM_SRVID = 5, /* SERVID type (special column) */
+ TYPE_AM_TABID = 6, /* TABID type (special column) */
+ TYPE_AM_CNSID = 7, /* CONSTID type (special column) */
+ TYPE_AM_PRTID = 8, /* PARTID type (special column) */
+ TYPE_AM_COUNT = 10, /* CPT AM type no (count table) */
+ TYPE_AM_DCD = 20, /* Decode access method type no */
+ TYPE_AM_CMS = 30, /* CMS access method type no */
+ TYPE_AM_MAP = 32, /* MAP access method type no */
+ TYPE_AM_FMT = 33, /* DOS files with formatted recs */
+ TYPE_AM_CSV = 34, /* DOS files with CSV records */
+ TYPE_AM_MCV = 35, /* MAP files with CSV records */
+ TYPE_AM_DOS = 36, /* DOS am with Lrecl = V */
+ TYPE_AM_FIX = 38, /* DOS am with Lrecl = F */
+ TYPE_AM_BIN = 39, /* DOS am with Lrecl = B */
+ TYPE_AM_VCT = 40, /* VCT access method type no */
+ TYPE_AM_VMP = 43, /* VMP access method type no */
+ TYPE_AM_QRY = 50, /* QRY access method type no */
+ TYPE_AM_QRS = 51, /* QRYRES access method type no */
+ TYPE_AM_SQL = 60, /* SQL VIEW access method type */
+ TYPE_AM_PLG = 70, /* PLG access method type no */
+ TYPE_AM_PLM = 71, /* PDM access method type no */
+ TYPE_AM_DOM = 80, /* DOM access method type no */
+ TYPE_AM_DIR = 90, /* DIR access method type no */
+ TYPE_AM_ODBC = 100, /* ODBC access method type no */
+ TYPE_AM_XDBC = 101, /* XDBC access method type no */
+ TYPE_AM_JDBC = 102, /* JDBC access method type no */
+ TYPE_AM_XJDC = 103, /* XJDC access method type no */
+ TYPE_AM_OEM = 110, /* OEM access method type no */
+ TYPE_AM_TBL = 115, /* TBL access method type no */
+ TYPE_AM_PIVOT = 120, /* PIVOT access method type no */
+ TYPE_AM_SRC = 121, /* PIVOT multiple column type no */
+ TYPE_AM_FNC = 122, /* PIVOT source column type no */
+ TYPE_AM_XCOL = 124, /* XCOL access method type no */
+ TYPE_AM_XML = 127, /* XML access method type no */
+ TYPE_AM_OCCUR = 128, /* OCCUR access method type no */
+ TYPE_AM_PRX = 129, /* PROXY access method type no */
+ TYPE_AM_XTB = 130, /* SYS table access method type */
+ TYPE_AM_BLK = 131, /* BLK access method type no */
+ TYPE_AM_GZ = 132, /* GZ access method type no */
+ TYPE_AM_ZLIB = 133, /* ZLIB access method type no */
+ TYPE_AM_JSON = 134, /* JSON access method type no */
+ TYPE_AM_JSN = 135, /* JSN access method type no */
+ TYPE_AM_MAC = 137, /* MAC table access method type */
+ TYPE_AM_WMI = 139, /* WMI table access method type */
+ TYPE_AM_XCL = 140, /* SYS column access method type */
+ TYPE_AM_INI = 150, /* INI files access method */
+ TYPE_AM_TFC = 155, /* TFC (Circa) (Fuzzy compare) */
+ TYPE_AM_DBF = 160, /* DBF Dbase files am type no */
+ TYPE_AM_JCT = 170, /* Junction tables am type no */
+ TYPE_AM_VIR = 171, /* Virtual tables am type no */
+ TYPE_AM_DMY = 172, /* DMY Dummy tables am type no */
+ TYPE_AM_SET = 180, /* SET Set tables am type no */
+ TYPE_AM_MYSQL = 190, /* MYSQL access method type no */
+ TYPE_AM_MYX = 191, /* MYSQL EXEC access method type */
+ TYPE_AM_CAT = 192, /* Catalog access method type no */
+ TYPE_AM_ZIP = 193, /* ZIP access method type no */
+ TYPE_AM_MGO = 194, /* MGO access method type no */
+ TYPE_AM_OUT = 200}; /* Output relations (storage) */
+
+enum RECFM {RECFM_DFLT = 0, /* Default table type */
+ RECFM_NAF = 1, /* Not a file table */
+ RECFM_OEM = 2, /* OEM table */
+ RECFM_VAR = 3, /* Varying length DOS files */
+ RECFM_FIX = 4, /* Fixed length DOS files */
+ RECFM_BIN = 5, /* Binary DOS files (also fixed) */
+ RECFM_DBF = 6, /* DBase formatted file */
+ RECFM_CSV = 7, /* CSV file */
+ RECFM_FMT = 8, /* FMT formatted file */
+ RECFM_VCT = 9, /* VCT formatted files */
+ RECFM_XML = 10, /* XML formatted files */
+ RECFM_JSON = 11, /* JSON formatted files */
+ RECFM_DIR = 12, /* DIR table */
+ RECFM_ODBC = 13, /* Table accessed via ODBC */
+ RECFM_JDBC = 14, /* Table accessed via JDBC */
+ RECFM_PLG = 15}; /* Table accessed via PLGconn */
+
+enum MISC {DB_TABNO = 1, /* DB routines in Utility Table */
+ MAX_MULT_KEY = 10, /* Max multiple key number */
+ NAM_LEN = 128, /* Length of col and tab names */
+ ARRAY_SIZE = 50, /* Default array block size */
+// MAXRES = 500, /* Default maximum result lines */
+// MAXLIN = 10000, /* Default maximum data lines */
+ MAXBMP = 32}; /* Default XDB2 max bitmap size */
+
+#if 0
+enum ALGMOD {AMOD_AUTO = 0, /* PLG chooses best algorithm */
+ AMOD_SQL = 1, /* Use SQL algorithm */
+ AMOD_QRY = 2}; /* Use QUERY algorithm */
+#endif // 0
+
+enum MODE {MODE_ERROR = -1, /* Invalid mode */
+ MODE_ANY = 0, /* Unspecified mode */
+ MODE_READ = 10, /* Input/Output mode */
+ MODE_READX = 11, /* Read indexed mode */
+ MODE_WRITE = 20, /* Input/Output mode */
+ MODE_UPDATE = 30, /* Input/Output mode */
+ MODE_INSERT = 40, /* Input/Output mode */
+ MODE_DELETE = 50, /* Input/Output mode */
+ MODE_ALTER = 60}; /* alter mode */
+
+#if !defined(RC_OK_DEFINED)
+#define RC_OK_DEFINED
+enum RCODE {RC_OK = 0, /* No error return code */
+ RC_NF = 1, /* Not found return code */
+ RC_EF = 2, /* End of file return code */
+ RC_FX = 3, /* Error return code */
+ RC_INFO = 4}; /* Success with info */
+#endif // !RC_OK_DEFINED
+
+enum OPVAL {OP_EQ = 1, /* Filtering operator = */
+ OP_NE = 2, /* Filtering operator != */
+ OP_GT = 3, /* Filtering operator > */
+ OP_GE = 4, /* Filtering operator >= */
+ OP_LT = 5, /* Filtering operator < */
+ OP_LE = 6, /* Filtering operator <= */
+ OP_IN = 7, /* Filtering operator IN */
+ OP_NULL = 8, /* Filtering operator IS NULL */
+ OP_EXIST = 9, /* Filtering operator EXISTS */
+ OP_LIKE = 10, /* Filtering operator LIKE */
+ OP_LOJ = -1, /* Filter op LEFT OUTER JOIN */
+ OP_ROJ = -2, /* Filter op RIGHT OUTER JOIN */
+ OP_DTJ = -3, /* Filter op DISTINCT JOIN */
+ OP_XX = 11, /* Filtering operator unknown */
+ OP_AND = 12, /* Filtering operator AND */
+ OP_OR = 13, /* Filtering operator OR */
+ OP_CNC = 14, /* Expression Concat operator */
+ OP_NOT = 15, /* Filtering operator NOT */
+ OP_SEP = 20, /* Filtering separator */
+ OP_ADD = 16, /* Expression Add operator */
+ OP_SUB = 17, /* Expression Substract operator */
+ OP_MULT = 18, /* Expression Multiply operator */
+ OP_DIV = 19, /* Expression Divide operator */
+ OP_NUM = 22, /* Scalar function Op Num */
+ OP_MAX = 24, /* Scalar function Op Max */
+ OP_MIN = 25, /* Scalar function Op Min */
+ OP_EXP = 36, /* Scalar function Op Exp */
+ OP_FDISK = 94, /* Operator Disk of fileid */
+ OP_FPATH = 95, /* Operator Path of fileid */
+ OP_FNAME = 96, /* Operator Name of fileid */
+ OP_FTYPE = 97, /* Operator Type of fileid */
+ OP_LAST = 82, /* Index operator Find Last */
+ OP_FIRST = 106, /* Index operator Find First */
+ OP_NEXT = 107, /* Index operator Find Next */
+ OP_SAME = 108, /* Index operator Find Next Same */
+ OP_FSTDIF = 109, /* Index operator Find First dif */
+ OP_NXTDIF = 110, /* Index operator Find Next dif */
+ OP_PREV = 116}; /* Index operator Find Previous */
+#if 0
+ OP_NOP = 21, /* Scalar function is nopped */
+ OP_ABS = 23, /* Scalar function Op Abs */
+ OP_CEIL = 26, /* Scalar function Op Ceil */
+ OP_FLOOR = 27, /* Scalar function Op Floor */
+ OP_MOD = 28, /* Scalar function Op Mod */
+ OP_ROUND = 29, /* Scalar function Op Round */
+ OP_SIGN = 30, /* Scalar function Op Sign */
+ OP_LEN = 31, /* Scalar function Op Len */
+ OP_INSTR = 32, /* Scalar function Op Instr */
+ OP_LEFT = 33, /* Scalar function Op Left */
+ OP_RIGHT = 34, /* Scalar function Op Right */
+ OP_ASCII = 35, /* Scalar function Op Ascii */
+ OP_EXP = 36, /* Scalar function Op Exp */
+ OP_LN = 37, /* Scalar function Op Ln */
+ OP_LOG = 38, /* Scalar function Op Log */
+ OP_POWER = 39, /* Scalar function Op Power */
+ OP_SQRT = 40, /* Scalar function Op Sqrt */
+ OP_COS = 41, /* Scalar function Op Cos */
+ OP_COSH = 42, /* Scalar function Op Cosh */
+ OP_SIN = 43, /* Scalar function Op Sin */
+ OP_SINH = 44, /* Scalar function Op Sinh */
+ OP_TAN = 45, /* Scalar function Op Tan */
+ OP_TANH = 46, /* Scalar function Op Tanh */
+ OP_USER = 47, /* Scalar function Op User */
+ OP_CHAR = 48, /* Scalar function Op Char */
+ OP_UPPER = 49, /* Scalar function Op Upper */
+ OP_LOWER = 50, /* Scalar function Op Lower */
+ OP_RPAD = 51, /* Scalar function Op Rpad */
+ OP_LPAD = 52, /* Scalar function Op Lpad */
+ OP_LTRIM = 53, /* Scalar function Op Ltrim */
+ OP_RTRIM = 54, /* Scalar function Op Rtrim */
+ OP_REPL = 55, /* Scalar function Op Replace */
+ OP_SUBST = 56, /* Scalar function Op Substr */
+ OP_LJUST = 57, /* Scalar function Op Ljustify */
+ OP_RJUST = 58, /* Scalar function Op Rjustify */
+ OP_CJUST = 59, /* Scalar function Op Cjustify */
+ OP_ENCODE = 60, /* Scalar function Op Encode */
+ OP_DECODE = 61, /* Scalar function Op Decode */
+ OP_SEQU = 62, /* Scalar function Op Sequence */
+ OP_IF = 63, /* Scalar function Op If */
+ OP_STRING = 64, /* Scalar function Op String */
+ OP_TOKEN = 65, /* Scalar function Op Token */
+ OP_SNDX = 66, /* Scalar function Op Soundex */
+ OP_DATE = 67, /* Scalar function Op Date */
+ OP_MDAY = 68, /* Scalar function Op Month Day */
+ OP_MONTH = 69, /* Scalar function Op Month of */
+ OP_YEAR = 70, /* Scalar function Op Year of */
+ OP_WDAY = 71, /* Scalar function Op Week Day */
+ OP_YDAY = 72, /* Scalar function Op Year Day */
+ OP_DBTWN = 73, /* Scalar function Op Days betwn */
+ OP_MBTWN = 74, /* Scalar function Op Months btw */
+ OP_YBTWN = 75, /* Scalar function Op Years btwn */
+ OP_ADDAY = 76, /* Scalar function Op Add Days */
+ OP_ADDMTH = 77, /* Scalar function Op Add Months */
+ OP_ADDYR = 78, /* Scalar function Op Add Years */
+ OP_NXTDAY = 79, /* Scalar function Op Next Day */
+ OP_SYSDT = 80, /* Scalar function Op SysDate */
+ OP_DELTA = 81, /* Scalar function Op Delta */
+ OP_LAST = 82, /* Scalar function Op Last */
+ OP_IFF = 83, /* Scalar function Op Iff */
+ OP_MAVG = 84, /* Scalar function Op Moving Avg */
+ OP_VWAP = 85, /* Scalar function Op VWAP */
+ OP_TIME = 86, /* Scalar function Op TIME */
+ OP_SETLEN = 87, /* Scalar function Op Set Length */
+ OP_TRANSL = 88, /* Scalar function Op Translate */
+ OP_BITAND = 89, /* Expression BitAnd operator */
+ OP_BITOR = 90, /* Expression BitOr operator */
+ OP_BITXOR = 91, /* Expression XOR operator */
+ OP_BITNOT = 92, /* Expression Complement operator*/
+ OP_CNTIN = 93, /* Scalar function Count In */
+ OP_FDISK = 94, /* Scalar function Disk of fileid*/
+ OP_FPATH = 95, /* Scalar function Path of fileid*/
+ OP_FNAME = 96, /* Scalar function Name of fileid*/
+ OP_FTYPE = 97, /* Scalar function Type of fileid*/
+ OP_XDATE = 98, /* Scalar function Op Fmt Date */
+ OP_SWITCH = 99, /* Scalar function Op Switch */
+ OP_EXIT = 100, /* Scalar function Op Exit */
+ OP_LIT = 101, /* Scalar function Op Literal */
+ OP_LOCALE = 102, /* Scalar function Op Locale */
+ OP_FRNCH = 103, /* Scalar function Op French */
+ OP_ENGLSH = 104, /* Scalar function Op English */
+ OP_RAND = 105, /* Scalar function Op Rand(om) */
+ OP_FIRST = 106, /* Index operator Find First */
+ OP_NEXT = 107, /* Index operator Find Next */
+ OP_SAME = 108, /* Index operator Find Next Same */
+ OP_FSTDIF = 109, /* Index operator Find First dif */
+ OP_NXTDIF = 110, /* Index operator Find Next dif */
+ OP_VAL = 111, /* Scalar function Op Valist */
+ OP_QUART = 112, /* Scalar function Op QUARTER */
+ OP_CURDT = 113, /* Scalar function Op CurDate */
+ OP_NWEEK = 114, /* Scalar function Op Week number*/
+ OP_ROW = 115, /* Scalar function Op Row */
+ OP_PREV = 116, /* Index operator Find Previous */
+ OP_SYSTEM = 200, /* Scalar function Op System */
+ OP_REMOVE = 201, /* Scalar function Op Remove */
+ OP_RENAME = 202, /* Scalar function Op Rename */
+ OP_FCOMP = 203}; /* Scalar function Op Compare */
+#endif // 0
+
+enum TUSE {USE_NO = 0, /* Table is not yet linearized */
+ USE_LIN = 1, /* Table is linearized */
+ USE_READY = 2, /* Column buffers are allocated */
+ USE_OPEN = 3, /* Table is open */
+ USE_CNT = 4, /* Specific to LNA */
+ USE_NOKEY = 5}; /* Specific to SqlToHql */
+
+/***********************************************************************/
+/* Following definitions are used to indicate the status of a column. */
+/***********************************************************************/
+enum STATUS {BUF_NO = 0x00, /* Column buffer not allocated */
+ BUF_EMPTY = 0x01, /* Column buffer is empty */
+ BUF_READY = 0x02, /* Column buffer is ready */
+ BUF_READ = 0x04, /* Column buffer has read value */
+ BUF_MAPPED = 0x08}; /* Used by the VMPFAM class */
+
+/***********************************************************************/
+/* Following definitions are used to indicate how a column is used. */
+/* Corresponding bits are ON if the column is used in: */
+/***********************************************************************/
+enum COLUSE {U_P = 0x01, /* the projection list. */
+ U_J_EXT = 0x02, /* a join filter. */
+ U_J_INT = 0x04, /* a join after linearisation. */
+/*-- Such a column have a constant value throughout a subquery eval. --*/
+ U_CORREL = 0x08, /* a correlated sub-query */
+/*-------------------- additional values used by CONNECT --------------*/
+ U_VAR = 0x10, /* a VARCHAR column */
+ U_VIRTUAL = 0x20, /* a VIRTUAL column */
+ U_NULLS = 0x40, /* The column may have nulls */
+ U_IS_NULL = 0x80, /* The column has a null value */
+ U_SPECIAL = 0x100, /* The column is special */
+ U_UNSIGNED = 0x200, /* The column type is unsigned */
+ U_ZEROFILL = 0x400, /* The column is zero filled */
+ U_UUID = 0x800}; /* The column is a UUID */
+
+/***********************************************************************/
+/* DB description class and block pointer definitions. */
+/***********************************************************************/
+typedef class XTAB *PTABLE;
+typedef class COLUMN *PCOLUMN;
+typedef class XOBJECT *PXOB;
+typedef class COLBLK *PCOL;
+typedef class TDB *PTDB;
+typedef class TDBASE *PTDBASE;
+typedef class TDBEXT *PTDBEXT;
+typedef class TDBDOS *PTDBDOS;
+typedef class TDBFIX *PTDBFIX;
+typedef class TDBFMT *PTDBFMT;
+typedef class TDBCSV *PTDBCSV;
+typedef class TDBDOM *PTDBDOM;
+typedef class TDBDIR *PTDBDIR;
+typedef class DOSCOL *PDOSCOL;
+typedef class CSVCOL *PCSVCOL;
+typedef class MAPCOL *PMAPCOL;
+typedef class TDBMFT *PTDBMFT;
+typedef class TDBMCV *PTDBMCV;
+typedef class MCVCOL *PMCVCOL;
+typedef class RESCOL *PRESCOL;
+typedef class XXBASE *PKXBASE;
+typedef class KXYCOL *PXCOL;
+typedef class CATALOG *PCATLG;
+typedef class RELDEF *PRELDEF;
+typedef class TABDEF *PTABDEF;
+typedef class EXTDEF *PEXTBDEF;
+typedef class DOSDEF *PDOSDEF;
+typedef class CSVDEF *PCSVDEF;
+typedef class VCTDEF *PVCTDEF;
+typedef class PIVOTDEF *PPIVOTDEF;
+typedef class DOMDEF *PDOMDEF;
+typedef class DIRDEF *PDIRDEF;
+typedef class RESTDEF *PRESTDEF;
+typedef class OEMDEF *POEMDEF;
+typedef class COLCRT *PCOLCRT;
+typedef class COLDEF *PCOLDEF;
+typedef class CONSTANT *PCONST;
+typedef class VALUE *PVAL;
+typedef class VALBLK *PVBLK;
+typedef class FILTER *PFIL;
+
+typedef struct _fblock *PFBLOCK;
+typedef struct _mblock *PMBLOCK;
+typedef struct _cblock *PCBLOCK;
+typedef struct _tabs *PTABS;
+typedef struct _qryres *PQRYRES;
+typedef struct _colres *PCOLRES;
+typedef struct _datpar *PDTP;
+typedef struct indx_used *PXUSED;
+typedef struct ha_table_option_struct TOS, *PTOS;
+
+/***********************************************************************/
+/* Utility blocks for file and storage. */
+/***********************************************************************/
+typedef struct _fblock { /* Opened (mapped) file block */
+ struct _fblock *Next;
+ LPCSTR Fname; /* Point on file name */
+ size_t Length; /* File length (<4GB) */
+ short Count; /* Nb of times map is used */
+ short Type; /* TYPE_FB_FILE or TYPE_FB_MAP */
+ MODE Mode; /* Open mode */
+ char *Memory; /* Pointer to file mapping view */
+ void *File; /* FILE pointer */
+ HANDLE Handle; /* File handle */
+ } FBLOCK;
+
+typedef struct _mblock { /* Memory block */
+ PMBLOCK Next;
+ bool Inlist; /* True if in mblock list */
+ size_t Size; /* Size of allocation */
+ bool Sub; /* True if suballocated */
+ void *Memp; /* Memory pointer */
+ } MBLOCK;
+
+/***********************************************************************/
+/* The QUERY application User Block. */
+/***********************************************************************/
+typedef struct { /* User application block */
+ NAME Name; /* User application name */
+ char Server[17]; /* Server name */
+ char DBName[17]; /* Current database name */
+ PCATLG Catalog; /* To CATALOG class */
+ PQRYRES Result; /* To query result blocks */
+ PFBLOCK Openlist; /* To file/map open list */
+ PMBLOCK Memlist; /* To memory block list */
+ PXUSED Xlist; /* To used index list */
+ int Maxbmp; /* Maximum XDB2 bitmap size */
+ int Check; /* General level of checking */
+ int Numlines; /* Number of lines involved */
+//USETEMP UseTemp; /* Use temporary file */
+ int Vtdbno; /* Used for TDB number setting */
+ bool Remote; /* true: if remotely called */
+ bool Proginfo; /* true: return progress info */
+ bool Subcor; /* Used for Progress info */
+ size_t ProgMax; /* Used for Progress info */
+ size_t ProgCur; /* Used for Progress info */
+ size_t ProgSav; /* Used for Progress info */
+ LPCSTR Step; /* Execution step name */
+ } DBUSERBLK, *PDBUSER;
+
+/***********************************************************************/
+/* Column output format. */
+/***********************************************************************/
+typedef struct _format { /* Format descriptor block */
+ char Type[2]; /* C:char, F:double, N:int, Dx: date */
+ ushort Length; /* Output length */
+ short Prec; /* Output precision */
+ } FORMAT, *PFORMAT;
+
+/***********************************************************************/
+/* Definition of blocks used in type and copy routines. */
+/***********************************************************************/
+typedef struct _tabptr { /* start=P1 */
+ struct _tabptr *Next;
+ int Num; /* alignement */
+ void *Old[50];
+ void *New[50]; /* old and new values of copied ptrs */
+ } TABPTR, *PTABPTR;
+
+typedef struct _tabadr { /* start=P3 */
+ struct _tabadr *Next;
+ int Num;
+ void *Adx[50]; /* addr of pointers to be reset */
+ } TABADR, *PTABADR;
+
+typedef struct _tabs {
+ PGLOBAL G;
+ PTABPTR P1;
+ PTABADR P3;
+ } TABS;
+
+/***********************************************************************/
+/* Argument of expression, function, filter etc. (Xobject) */
+/***********************************************************************/
+typedef struct _arg { /* Argument */
+ PXOB To_Obj; /* To the argument object */
+ PVAL Value; /* Argument value */
+ bool Conv; /* TRUE if conversion is required */
+ } ARGBLK, *PARG;
+
+typedef struct _oper { /* Operator */
+ PSZ Name; /* The input/output operator name */
+ OPVAL Val; /* Operator numeric value */
+ int Mod; /* The modificator */
+ } OPER, *POPER;
+
+/***********************************************************************/
+/* Following definitions are used to define table fields (columns). */
+/***********************************************************************/
+enum XFLD {FLD_NO = 0, /* Not a field definition item */
+ FLD_NAME = 1, /* Item name */
+ FLD_TYPE = 2, /* Field type */
+ FLD_TYPENAME = 3, /* Field type name */
+ FLD_PREC = 4, /* Field precision (length?) */
+ FLD_LENGTH = 5, /* Field length (?) */
+ FLD_SCALE = 6, /* Field scale (precision) */
+ FLD_RADIX = 7, /* Field radix */
+ FLD_NULL = 8, /* Field nullable property */
+ FLD_REM = 9, /* Field comment (remark) */
+ FLD_CHARSET = 10, /* Field collation */
+ FLD_KEY = 11, /* Field key property */
+ FLD_DEFAULT = 12, /* Field default value */
+ FLD_EXTRA = 13, /* Field extra info */
+ FLD_PRIV = 14, /* Field priviledges */
+ FLD_DATEFMT = 15, /* Field date format */
+ FLD_FORMAT = 16, /* Field format */
+ FLD_CAT = 17, /* Table catalog */
+ FLD_SCHEM = 18, /* Table schema */
+ FLD_TABNAME = 19, /* Column Table name */
+ FLD_FLAG = 20}; /* Field flag (CONNECT specific) */
+
+/***********************************************************************/
+/* Result of last SQL noconv query. */
+/***********************************************************************/
+typedef struct _qryres {
+ PCOLRES Colresp; /* Points to columns of result */
+ bool Continued; /* true when more rows to fetch */
+ bool Truncated; /* true when truncated by maxres */
+ bool Suball; /* true when entirely suballocated */
+ bool Info; /* true when info msg generated */
+ int Maxsize; /* Max query number of lines */
+ int Maxres; /* Allocation size */
+ int Nblin; /* Number of rows in result set */
+ int Nbcol; /* Number of columns in result set */
+ int Cursor; /* Starting position to get data */
+ int BadLines; /* Skipped bad lines in table file */
+ } QRYRES, *PQRYRES;
+
+typedef struct _colres {
+ PCOLRES Next; /* To next result column */
+ PCOL Colp; /* To matching column block */
+ PCSZ Name; /* Column header */
+ PVBLK Kdata; /* Column block of values */
+ char *Nulls; /* Column null value array */
+ int Type; /* Internal type */
+ int Datasize; /* Overall data size */
+ int Ncol; /* Column number */
+ int Clen; /* Data individual internal size */
+ int Length; /* Data individual print length */
+ int Prec; /* Precision */
+ int Flag; /* Flag option value */
+ XFLD Fld; /* Type of field info */
+ char Var; /* Type added information */
+ } COLRES;
+
+#if defined(_WIN32) && !defined(NOEX)
+#define DllExport __declspec( dllexport )
+#else // !_WIN32
+#define DllExport
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Utility routines. */
+/***********************************************************************/
+PPARM Vcolist(PGLOBAL, PTDB, PSZ, bool);
+void PlugPutOut(PGLOBAL, FILE *, short, void *, uint);
+void PlugLineDB(PGLOBAL, PSZ, short, void *, uint);
+//ar *PlgGetDataPath(PGLOBAL g);
+char *SetPath(PGLOBAL g, const char *path);
+char *ExtractFromPath(PGLOBAL, char *, char *, OPVAL);
+void AddPointer(PTABS, void *);
+PDTP MakeDateFormat(PGLOBAL, PCSZ, bool, bool, int);
+int ExtractDate(char *, PDTP, int, int val[6]);
+
+/**************************************************************************/
+/* Allocate the result structure that will contain result data. */
+/**************************************************************************/
+DllExport PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
+ int *buftyp, XFLD *fldtyp,
+ unsigned int *length,
+ bool blank, bool nonull);
+
+/***********************************************************************/
+/* Exported utility routines. */
+/***********************************************************************/
+DllExport FILE *PlugOpenFile(PGLOBAL, LPCSTR, LPCSTR);
+DllExport FILE *PlugReopenFile(PGLOBAL, PFBLOCK, LPCSTR);
+DllExport int PlugCloseFile(PGLOBAL, PFBLOCK, bool all = false);
+DllExport void PlugCleanup(PGLOBAL, bool);
+DllExport bool GetPromptAnswer(PGLOBAL, char *);
+DllExport char *GetAmName(PGLOBAL g, AMT am, void *memp = NULL);
+DllExport PDBUSER PlgMakeUser(PGLOBAL g);
+DllExport PDBUSER PlgGetUser(PGLOBAL g);
+DllExport PCATLG PlgGetCatalog(PGLOBAL g, bool jump = true);
+DllExport bool PlgSetXdbPath(PGLOBAL g, PSZ, PSZ, char *, int, char *, int);
+DllExport void PlgDBfree(MBLOCK&);
+DllExport void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size);
+DllExport char *PlgDBDup(PGLOBAL g, const char *str);
+DllExport void *PlgDBalloc(PGLOBAL, void *, MBLOCK&);
+DllExport void *PlgDBrealloc(PGLOBAL, void *, MBLOCK&, size_t);
+DllExport void NewPointer(PTABS, void *, void *);
+//lExport char *GetIni(int n= 0); // Not used anymore
+DllExport void SetTrc(void);
+DllExport PCSZ GetListOption(PGLOBAL, PCSZ, PCSZ, PCSZ def=NULL);
+DllExport PCSZ GetStringTableOption(PGLOBAL, PTOS, PCSZ, PCSZ);
+DllExport bool GetBooleanTableOption(PGLOBAL, PTOS, PCSZ, bool);
+DllExport int GetIntegerTableOption(PGLOBAL, PTOS, PCSZ, int);
+
+#define MSGID_NONE 0
+#define MSGID_CANNOT_OPEN 1
+#define MSGID_OPEN_MODE_ERROR 2
+#define MSGID_OPEN_STRERROR 3
+#define MSGID_OPEN_ERROR_AND_STRERROR 4
+#define MSGID_OPEN_MODE_STRERROR 5
+#define MSGID_OPEN_EMPTY_FILE 6
+
+FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode);
+int global_open(GLOBAL *g, int msgid, const char *filename, int flags);
+int global_open(GLOBAL *g, int msgid, const char *filename, int flags, int mode);
+DllExport LPCSTR PlugSetPath(LPSTR to, LPCSTR name, LPCSTR dir);
+char *MakeEscape(PGLOBAL g, char* str, char q);
+
+DllExport bool PushWarning(PGLOBAL, PTDB, int level = 1);
diff --git a/storage/connect/plgdbutl.cpp b/storage/connect/plgdbutl.cpp
new file mode 100644
index 00000000..55c7b811
--- /dev/null
+++ b/storage/connect/plgdbutl.cpp
@@ -0,0 +1,1614 @@
+/********** PlgDBUtl Fpe C++ Program Source Code File (.CPP) ***********/
+/* PROGRAM NAME: PLGDBUTL */
+/* ------------- */
+/* Version 4.1 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* Utility functions used by DB semantic routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* See Readme.C for a list and description of required SYSTEM files. */
+/* */
+/* PLGDBUTL.C - Source code */
+/* GLOBAL.H - Global declaration file */
+/* PLGDBSEM.H - DB application declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* OS2.LIB - OS2 libray */
+/* LLIBCE.LIB - Protect mode/standard combined large model C */
+/* library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, MS, Borland or GNU C++ Compiler */
+/* IBM, MS, Borland or GNU Linker */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#include "my_pthread.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#include <errno.h>
+#define BIGMEM 1048576 // 1 Megabyte
+#else // !_WIN32
+#include <unistd.h>
+#include <fcntl.h>
+//#if defined(THREAD)
+#include <pthread.h>
+//#endif // THREAD
+#include <stdarg.h>
+#define BIGMEM 2147483647 // Max int value
+#endif // !_WIN32
+#include <locale.h>
+
+/***********************************************************************/
+/* Include application header files */
+/***********************************************************************/
+#include "global.h" // header containing all global declarations.
+#include "plgdbsem.h" // header containing the DB applic. declarations.
+#include "preparse.h" // For DATPAR
+#include "osutil.h"
+#include "maputil.h"
+#include "catalog.h"
+#include "colblk.h"
+#include "xtable.h" // header of TBX, TDB and TDBASE classes
+#include "tabcol.h" // header of XTAB and COLUMN classes
+#include "valblk.h"
+#include "rcmsg.h"
+#ifdef ZIP_SUPPORT
+#include "filamzip.h"
+#endif // ZIP_SUPPORT
+#ifdef JAVA_SUPPORT
+#include "javaconn.h"
+#endif // JAVA_SUPPORT
+#ifdef CMGO_SUPPORT
+#include "cmgoconn.h"
+#endif // JAVA_SUPPORT
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+bool Initdone = false;
+bool plugin = false; // True when called by the XDB plugin handler
+
+extern "C" {
+extern char version[];
+} // extern "C"
+
+//#if defined(_WIN32)
+//extern CRITICAL_SECTION parsec; // Used calling the Flex parser
+//#else // !_WIN32
+extern pthread_mutex_t parmut;
+//#endif // !_WIN32
+
+// The debug trace used by the main thread
+FILE *pfile = NULL;
+
+MBLOCK Nmblk = {NULL, false, 0, false, NULL}; // Used to init MBLOCK's
+
+/***********************************************************************/
+/* Routines called externally and internally by utility routines. */
+/***********************************************************************/
+bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
+bool EvalLikePattern(LPCSTR, LPCSTR);
+void PlugConvertConstant(PGLOBAL, void* &, short&);
+
+#ifdef DOMDOC_SUPPORT
+void CloseXMLFile(PGLOBAL, PFBLOCK, bool);
+#endif // DOMDOC_SUPPORT
+
+#ifdef LIBXML2_SUPPORT
+#include "libdoc.h"
+#endif // LIBXML2_SUPPORT
+
+#ifdef ODBC_SUPPORT
+void OdbcClose(PGLOBAL g, PFBLOCK fp);
+#endif // ODBC_SUPPORT
+
+/***********************************************************************/
+/* Routines for file IO with error reporting to g->Message */
+/* Note: errno and strerror must be called before the message file */
+/* is read in the case of XMSG compile. */
+/***********************************************************************/
+static void global_open_error_msg(GLOBAL *g, int msgid, const char *path,
+ const char *mode)
+{
+ int len, rno= (int)errno;
+ char errmsg[256]= "";
+
+ strncat(errmsg, strerror(errno), 255);
+
+ switch (msgid)
+ {
+ case MSGID_CANNOT_OPEN:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(CANNOT_OPEN), // Cannot open %s
+ path);
+ break;
+
+ case MSGID_OPEN_MODE_ERROR:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(OPEN_MODE_ERROR), // "Open(%s) error %d on %s"
+ mode, rno, path);
+ break;
+
+ case MSGID_OPEN_MODE_STRERROR:
+ {char fmt[256];
+ strcat(strcpy(fmt, MSG(OPEN_MODE_ERROR)), ": %s");
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ fmt, // Open(%s) error %d on %s: %s
+ mode, rno, path, errmsg);
+ }break;
+
+ case MSGID_OPEN_STRERROR:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(OPEN_STRERROR), // "open error: %s"
+ errmsg);
+ break;
+
+ case MSGID_OPEN_ERROR_AND_STRERROR:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ //OPEN_ERROR does not work, as it wants mode %d (not %s)
+ //MSG(OPEN_ERROR) "%s",// "Open error %d in mode %d on %s: %s"
+ "Open error %d in mode %s on %s: %s",
+ rno, mode, path, errmsg);
+ break;
+
+ case MSGID_OPEN_EMPTY_FILE:
+ len= snprintf(g->Message, sizeof(g->Message) - 1,
+ MSG(OPEN_EMPTY_FILE), // "Opening empty file %s: %s"
+ path, errmsg);
+ break;
+
+ default:
+ DBUG_ASSERT(0);
+ /* Fall through*/
+ case 0:
+ len= 0;
+ }
+ g->Message[len]= '\0';
+}
+
+
+FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode)
+{
+ FILE *f;
+ if (!(f= fopen(path, mode)))
+ global_open_error_msg(g, msgid, path, mode);
+ return f;
+}
+
+
+int global_open(GLOBAL *g, int msgid, const char *path, int flags)
+{
+ int h;
+ if ((h= open(path, flags)) <= 0)
+ global_open_error_msg(g, msgid, path, "");
+ return h;
+}
+
+
+int global_open(GLOBAL *g, int msgid, const char *path, int flags, int mode)
+{
+ int h;
+ if ((h= open(path, flags, mode)) <= 0)
+ {
+ char modestr[64];
+ snprintf(modestr, sizeof(modestr), "%d", mode);
+ global_open_error_msg(g, msgid, path, modestr);
+ }
+ return h;
+}
+
+DllExport void SetTrc(void)
+{
+ // If tracing is on, debug must be initialized.
+ debug = pfile;
+} // end of SetTrc
+
+/**************************************************************************/
+/* SubAllocate the result structure that will contain result data. */
+/**************************************************************************/
+PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
+ int *buftyp, XFLD *fldtyp,
+ unsigned int *length, bool blank, bool nonull)
+{
+ char cname[NAM_LEN+1];
+ int i;
+ PCOLRES *pcrp, crp;
+ PQRYRES qrp;
+
+ try {
+ /**********************************************************************/
+ /* Allocate the structure used to contain the result set. */
+ /**********************************************************************/
+ qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
+ pcrp = &qrp->Colresp;
+ qrp->Continued = false;
+ qrp->Truncated = false;
+ qrp->Info = false;
+ qrp->Suball = true;
+ qrp->Maxres = maxres;
+ qrp->Maxsize = 0;
+ qrp->Nblin = 0;
+ qrp->Nbcol = 0; // will be ncol
+ qrp->Cursor = 0;
+ qrp->BadLines = 0;
+
+ for (i = 0; i < ncol; i++) {
+ *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
+ crp = *pcrp;
+ pcrp = &crp->Next;
+ memset(crp, 0, sizeof(COLRES));
+ crp->Colp = NULL;
+ crp->Ncol = ++qrp->Nbcol;
+ crp->Type = buftyp[i];
+ crp->Length = length[i];
+ crp->Clen = GetTypeSize(crp->Type, length[i]);
+ crp->Prec = 0;
+
+ if (ids > 0) {
+#if defined(XMSG)
+ // Get header from message file
+ strncpy(cname, PlugReadMessage(g, ids + crp->Ncol, NULL), NAM_LEN);
+ cname[NAM_LEN] = 0; // for truncated long names
+#else // !XMSG
+ GetRcString(ids + crp->Ncol, cname, sizeof(cname));
+#endif // !XMSG
+ crp->Name = (PSZ)PlugDup(g, cname);
+ } else
+ crp->Name = NULL; // Will be set by caller
+
+ if (fldtyp)
+ crp->Fld = fldtyp[i];
+ else
+ crp->Fld = FLD_NO;
+
+ // Allocate the Value Block that will contain data
+ if (crp->Length || nonull)
+ crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
+ crp->Length, 0, true, blank, false);
+ else
+ crp->Kdata = NULL;
+
+ if (trace(1))
+ htrc("Column(%d) %s type=%d len=%d value=%p\n",
+ crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata);
+
+ } // endfor i
+
+ *pcrp = NULL;
+
+ } catch (int n) {
+ htrc("Exception %d: %s\n", n, g->Message);
+ qrp = NULL;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ htrc("%s\n", g->Message);
+ qrp = NULL;
+ } // end catch
+
+ return qrp;
+} // end of PlgAllocResult
+
+/***********************************************************************/
+/* Allocate and initialize the new DB User Block. */
+/***********************************************************************/
+PDBUSER PlgMakeUser(PGLOBAL g)
+ {
+ PDBUSER dbuserp;
+
+ if (!(dbuserp = (PDBUSER)malloc(sizeof(DBUSERBLK)))) {
+ sprintf(g->Message, MSG(MALLOC_ERROR), "PlgMakeUser");
+ return NULL;
+ } // endif dbuserp
+
+ memset(dbuserp, 0, sizeof(DBUSERBLK));
+ dbuserp->Maxbmp = MAXBMP;
+//dbuserp->UseTemp = TMP_AUTO;
+ dbuserp->Check = CHK_ALL;
+ strcpy(dbuserp->Server, "CONNECT");
+ return dbuserp;
+ } // end of PlgMakeUser
+
+/***********************************************************************/
+/* PlgGetUser: returns DBUSER block pointer. */
+/***********************************************************************/
+PDBUSER PlgGetUser(PGLOBAL g)
+ {
+ PDBUSER dup = (PDBUSER)((g->Activityp) ? g->Activityp->Aptr : NULL);
+
+ if (!dup)
+ strcpy(g->Message, MSG(APPL_NOT_INIT));
+
+ return dup;
+ } // end of PlgGetUser
+
+/***********************************************************************/
+/* PlgGetCatalog: returns CATALOG class pointer. */
+/***********************************************************************/
+PCATLG PlgGetCatalog(PGLOBAL g, bool jump)
+ {
+ PDBUSER dbuserp = PlgGetUser(g);
+ PCATLG cat = (dbuserp) ? dbuserp->Catalog : NULL;
+
+ if (!cat && jump) {
+ // Raise exception so caller doesn't have to check return value
+ strcpy(g->Message, MSG(NO_ACTIVE_DB));
+ throw 1;
+ } // endif cat
+
+ return cat;
+ } // end of PlgGetCatalog
+
+#if 0
+/***********************************************************************/
+/* PlgGetDataPath: returns the default data path. */
+/***********************************************************************/
+char *PlgGetDataPath(PGLOBAL g)
+ {
+ PCATLG cat = PlgGetCatalog(g, false);
+
+ return (cat) ? cat->GetDataPath() : NULL;
+ } // end of PlgGetDataPath
+#endif // 0
+
+/***********************************************************************/
+/* This function returns a database path. */
+/***********************************************************************/
+char *SetPath(PGLOBAL g, const char *path)
+{
+ char *buf= NULL;
+
+ if (path) {
+ size_t len = strlen(path) + (*path != '.' ? 4 : 1);
+
+ if (!(buf = (char*)PlgDBSubAlloc(g, NULL, len)))
+ return NULL;
+
+ if (PlugIsAbsolutePath(path)) {
+ strcpy(buf, path);
+ return buf;
+ } // endif path
+
+ if (*path != '.') {
+#if defined(_WIN32)
+ const char *s = "\\";
+#else // !_WIN32
+ const char *s = "/";
+#endif // !_WIN32
+ strcat(strcat(strcat(strcpy(buf, "."), s), path), s);
+ } else
+ strcpy(buf, path);
+
+ } // endif path
+
+ return buf;
+} // end of SetPath
+
+/***********************************************************************/
+/* Extract from a path name the required component. */
+/* This function assumes there is enough space in the buffer. */
+/***********************************************************************/
+char *ExtractFromPath(PGLOBAL g, char *pBuff, char *FileName, OPVAL op)
+ {
+ char *drive = NULL, *direc = NULL, *fname = NULL, *ftype = NULL;
+
+ switch (op) { // Determine which part to extract
+#if defined(_WIN32)
+ case OP_FDISK: drive = pBuff; break;
+#endif // !UNIX
+ case OP_FPATH: direc = pBuff; break;
+ case OP_FNAME: fname = pBuff; break;
+ case OP_FTYPE: ftype = pBuff; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_OPER), op, "ExtractFromPath");
+ return NULL;
+ } // endswitch op
+
+ // Now do the extraction
+ _splitpath(FileName, drive, direc, fname, ftype);
+ return pBuff;
+ } // end of PlgExtractFromPath
+
+
+#ifdef NOT_USED
+/***********************************************************************/
+/* Check the occurrence and matching of a pattern against a string. */
+/* Because this function is only used for catalog name checking, */
+/* it must be case insensitive. */
+/***********************************************************************/
+static bool PlugCheckPattern(PGLOBAL g, LPCSTR string, LPCSTR pat)
+ {
+ if (pat && strlen(pat)) {
+ // This leaves 2048 bytes (MAX_STR / 2) for each components
+ LPSTR name = g->Message + MAX_STR / 2;
+
+ strlwr(strcpy(name, string));
+ strlwr(strcpy(g->Message, pat)); // Can be modified by Eval
+ return EvalLikePattern(name, g->Message);
+ } else
+ return true;
+
+ } // end of PlugCheckPattern
+#endif /* NOT_USED */
+
+/***********************************************************************/
+/* PlugEvalLike: evaluates a LIKE clause. */
+/* Syntaxe: M like P escape C. strg->M, pat->P, C not implemented yet */
+/***********************************************************************/
+bool PlugEvalLike(PGLOBAL g, LPCSTR strg, LPCSTR pat, bool ci)
+ {
+ char *tp, *sp;
+ bool b;
+
+ if (trace(2))
+ htrc("LIKE: strg='%s' pattern='%s'\n", strg, pat);
+
+ if (ci) { /* Case insensitive test */
+ if (strlen(pat) + strlen(strg) + 1 < MAX_STR)
+ tp = g->Message;
+ else if (!(tp = new char[strlen(pat) + strlen(strg) + 2])) {
+ strcpy(g->Message, MSG(NEW_RETURN_NULL));
+ throw (int)OP_LIKE;
+ } /* endif tp */
+
+ sp = tp + strlen(pat) + 1;
+ strlwr(strcpy(tp, pat)); /* Make a lower case copy of pat */
+ strlwr(strcpy(sp, strg)); /* Make a lower case copy of strg */
+ } else { /* Case sensitive test */
+ if (strlen(pat) < MAX_STR) /* In most of the case for small pat */
+ tp = g->Message; /* Use this as temporary work space. */
+ else if (!(tp = new char[strlen(pat) + 1])) {
+ strcpy(g->Message, MSG(NEW_RETURN_NULL));
+ throw (int)OP_LIKE;
+ } /* endif tp */
+
+ strcpy(tp, pat); /* Make a copy to be worked into */
+ sp = (char*)strg;
+ } /* endif ci */
+
+ b = EvalLikePattern(sp, tp);
+
+ if (tp != g->Message) /* If working space was obtained */
+ delete [] tp; /* by the use of new, delete it. */
+
+ return (b);
+ } /* end of PlugEvalLike */
+
+/***********************************************************************/
+/* M and P are variable length character string. If M and P are zero */
+/* length strings then the Like predicate is true. */
+/* */
+/* The Like predicate is true if: */
+/* */
+/* 1- A subtring of M is a sequence of 0 or more contiguous <CR> of M */
+/* and each <CR> of M is part of exactly one substring. */
+/* */
+/* 2- If the i-th <subtring-specifyer> of P is an <arbitrary-char- */
+/* specifier>, the i-th subtring of M is any single <CR>. */
+/* */
+/* 3- If the i-th <subtring-specifyer> of P is an <arbitrary-string- */
+/* specifier>, then the i-th subtring of M is any sequence of zero */
+/* or more <CR>. */
+/* */
+/* 4- If the i-th <subtring-specifyer> of P is neither an <arbitrary- */
+/* character-specifier> nor an <arbitrary-string-specifier>, then */
+/* the i-th substring of M is equal to that <substring-specifier> */
+/* according to the collating sequence of the <like-predicate>, */
+/* without the appending of <space-character>, and has the same */
+/* length as that <substring-specifier>. */
+/* */
+/* 5- The number of substrings of M is equal to the number of */
+/* <subtring-specifiers> of P. */
+/* */
+/* Otherwise M like P is false. */
+/***********************************************************************/
+bool EvalLikePattern(LPCSTR sp, LPCSTR tp)
+ {
+ LPSTR p;
+ char c;
+ ssize_t n;
+ bool b, t = false;
+
+ if (trace(2))
+ htrc("Eval Like: sp=%s tp=%s\n",
+ (sp) ? sp : "Null", (tp) ? tp : "Null");
+
+ /********************************************************************/
+ /* If pattern is void, Like is true only if string is also void. */
+ /********************************************************************/
+ if (!*tp)
+ return (!*sp);
+
+ /********************************************************************/
+ /* Analyse eventual arbitrary specifications ahead of pattern. */
+ /********************************************************************/
+ for (p = (LPSTR)tp; p;)
+ switch (*p) { /* it can contain % and/or _ */
+ case '%': /* An % has been found */
+ t = true; /* Note eventual character skip */
+ p++;
+ break;
+ case '_': /* An _ has been found */
+ if (*sp) { /* If more character in string */
+ sp++; /* skip it */
+ p++;
+ } else
+ return false; /* Like condition is not met */
+
+ break;
+ default:
+ tp = p; /* Point to rest of template */
+ p = NULL; /* To stop For loop */
+ break;
+ } /* endswitch */
+
+ if ((p = (LPSTR)strpbrk(tp, "%_"))) /* Get position of next % or _ */
+ n = p - tp;
+ else
+ n = strlen(tp); /* Get length of pattern head */
+
+ if (trace(2))
+ htrc(" testing: t=%d sp=%s tp=%s p=%p\n", t, sp, tp, p);
+
+ if (n > (signed)strlen(sp)) /* If head is longer than strg */
+ b = false; /* Like condition is not met */
+ else if (n == 0) /* If void <substring-specifier> */
+ b = (t || !*sp); /* true if % or void strg. */
+ else if (!t) {
+ /*******************************************************************/
+ /* No character to skip, check occurrence of <subtring-specifier> */
+ /* at the very beginning of remaining string. */
+ /*******************************************************************/
+ if (p) {
+ if ((b = !strncmp(sp, tp, n)))
+ b = EvalLikePattern(sp + n, p);
+
+ } else
+ b = !strcmp(sp, tp); /* strg and tmp heads match */
+
+ } else
+ if (p)
+ /*****************************************************************/
+ /* Here is the case explaining why we need a recursive routine. */
+ /* The test must be done not only against the first occurrence */
+ /* of the <substring-specifier> in the remaining string, */
+ /* but also with all eventual succeeding ones. */
+ /*****************************************************************/
+ for (b = false, c = *p; !b && (signed)strlen(sp) >= n; sp++) {
+ *p = '\0'; /* Separate pattern header */
+
+ if ((sp = strstr(sp, tp))) {
+ *p = c;
+ b = EvalLikePattern(sp + n, p);
+ } else {
+ *p = c;
+ b = false;
+ break;
+ } /* endif s */
+
+ } /* endfor b, sp */
+
+ else {
+ sp += (strlen(sp) - n);
+ b = !strcmp(sp, tp);
+ } /* endif p */
+
+ if (trace(2))
+ htrc(" done: b=%d n=%d sp=%s tp=%s\n",
+ b, n, (sp) ? sp : "Null", tp);
+
+ return (b);
+ } /* end of EvalLikePattern */
+
+/***********************************************************************/
+/* MakeEscape: Escape some characters in a string. */
+/***********************************************************************/
+char *MakeEscape(PGLOBAL g, char* str, char q)
+ {
+ char *bufp;
+ int i, k, n = 0, len = (int)strlen(str);
+
+ for (i = 0; i < len; i++)
+ if (str[i] == q || str[i] == '\\')
+ n++;
+
+ if (!n)
+ return str;
+ else
+ bufp = (char*)PlugSubAlloc(g, NULL, len + n + 1);
+
+ for (i = k = 0; i < len; i++) {
+ if (str[i] == q || str[i] == '\\')
+ bufp[k++] = '\\';
+
+ bufp[k++] = str[i];
+ } // endfor i
+
+ bufp[k] = 0;
+ return bufp;
+ } /* end of MakeEscape */
+
+/***********************************************************************/
+/* PlugConvertConstant: convert a Plug constant to an Xobject. */
+/***********************************************************************/
+void PlugConvertConstant(PGLOBAL g, void* & value, short& type)
+ {
+ if (trace(1))
+ htrc("PlugConvertConstant: value=%p type=%hd\n", value, type);
+
+ if (type != TYPE_XOBJECT) {
+ value = new(g) CONSTANT(g, value, type);
+ type = TYPE_XOBJECT;
+ } // endif type
+
+ } // end of PlugConvertConstant
+
+/***********************************************************************/
+/* Call the Flex preparser to convert a date format to a sscanf input */
+/* format and a Strftime output format. Flag if not 0 indicates that */
+/* non quoted blanks are not included in the output format. */
+/***********************************************************************/
+PDTP MakeDateFormat(PGLOBAL g, PCSZ dfmt, bool in, bool out, int flag)
+{
+ int rc;
+ PDTP pdp = (PDTP)PlugSubAlloc(g, NULL, sizeof(DATPAR));
+
+ if (trace(1))
+ htrc("MakeDateFormat: dfmt=%s\n", dfmt);
+
+ memset(pdp, 0, sizeof(DATPAR));
+ pdp->Format = pdp->Curp = PlugDup(g, dfmt);
+ pdp->Outsize = 2 * strlen(dfmt) + 1;
+
+ if (in)
+ pdp->InFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
+
+ if (out)
+ pdp->OutFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
+
+ pdp->Flag = flag;
+
+ /*********************************************************************/
+ /* Call the FLEX generated parser. In multi-threading mode the next */
+ /* instruction is protected by mutex fmdflex using static variables. */
+ /*********************************************************************/
+ pthread_mutex_lock(&parmut);
+ rc = fmdflex(pdp);
+ pthread_mutex_unlock(&parmut);
+
+ if (trace(1))
+ htrc("Done: in=%s out=%s rc=%d\n", SVP(pdp->InFmt), SVP(pdp->OutFmt), rc);
+
+ return pdp;
+} // end of MakeDateFormat
+
+/***********************************************************************/
+/* Extract the date from a formatted string according to format. */
+/***********************************************************************/
+int ExtractDate(char *dts, PDTP pdp, int defy, int val[6])
+ {
+ PCSZ fmt;
+ char c, d, e, W[8][12];
+ int i, k, m, numval;
+ int n, y = 30;
+ bool b = true; // true for null dates
+
+ if (pdp)
+ fmt = pdp->InFmt;
+ else // assume standard MySQL date format
+ fmt = "%4d-%2d-%2d %2d:%2d:%2d";
+
+ if (trace(2))
+ htrc("ExtractDate: dts=%s fmt=%s defy=%d\n", dts, fmt, defy);
+
+ // Set default values for time only use
+ if (defy) {
+ // This may be a default value for year
+ y = defy;
+ val[0] = y;
+ y = (y < 100) ? y : 30;
+ } else
+ val[0] = 70;
+
+ val[1] = 1;
+ val[2] = 1;
+
+ for (i = 3; i < 6; i++)
+ val[i] = 0;
+
+ numval = 0;
+
+ // Get the date field parse it with derived input format
+ m = sscanf(dts, fmt, W[0], W[1], W[2], W[3], W[4], W[5], W[6], W[7]);
+
+ if (m > pdp->Num)
+ m = pdp->Num;
+
+ for (i = 0; i < m; i++) {
+ if ((n = *(int*)W[i]))
+ b = false;
+
+ switch (k = pdp->Index[i]) {
+ case 0:
+ if (n < y)
+ n += 100;
+
+ val[0] = n;
+ numval = MY_MAX(numval, 1);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ val[k] = n;
+ numval = MY_MAX(numval, k + 1);
+ break;
+ case -1:
+ c = toupper(W[i][0]);
+ d = toupper(W[i][1]);
+ e = toupper(W[i][2]);
+
+ switch (c) {
+ case 'J':
+ n = (d == 'A') ? 1
+ : (e == 'N') ? 6 : 7; break;
+ case 'F': n = 2; break;
+ case 'M':
+ n = (e == 'R') ? 3 : 5; break;
+ case 'A':
+ n = (d == 'P') ? 4 : 8; break;
+ break;
+ case 'S': n = 9; break;
+ case 'O': n = 10; break;
+ case 'N': n = 11; break;
+ case 'D': n = 12; break;
+ } /* endswitch c */
+
+ val[1] = n;
+ numval = MY_MAX(numval, 2);
+ break;
+ case -6:
+ c = toupper(W[i][0]);
+ n = val[3] % 12;
+
+ if (c == 'P')
+ n += 12;
+
+ val[3] = n;
+ break;
+ } // endswitch Plugpar
+
+ } // endfor i
+
+ if (trace(2))
+ htrc("numval=%d val=(%d,%d,%d,%d,%d,%d)\n",
+ numval, val[0], val[1], val[2], val[3], val[4], val[5]);
+
+ return (b) ? 0 : numval;
+ } // end of ExtractDate
+
+/***********************************************************************/
+/* Open file routine: the purpose of this routine is to make a list */
+/* of all open file so they can be closed in SQLINIT on error jump. */
+/***********************************************************************/
+FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype)
+ {
+ FILE *fop;
+ PFBLOCK fp;
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ if (trace(1)) {
+ htrc("PlugOpenFile: fname=%s ftype=%s\n", fname, ftype);
+ htrc("dbuserp=%p\n", dbuserp);
+ } // endif trace
+
+ if ((fop= global_fopen(g, MSGID_OPEN_MODE_STRERROR, fname, ftype)) != NULL) {
+ if (trace(1))
+ htrc(" fop=%p\n", fop);
+
+ fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
+
+ if (trace(1))
+ htrc(" fp=%p\n", fp);
+
+ // fname may be in volatile memory such as stack
+ fp->Fname = PlugDup(g, fname);
+ fp->Count = 1;
+ fp->Type = TYPE_FB_FILE;
+ fp->File = fop;
+ fp->Mode = MODE_ANY; // ???
+ fp->Next = dbuserp->Openlist;
+ dbuserp->Openlist = fp;
+ } /* endif fop */
+
+ if (trace(1))
+ htrc(" returning fop=%p\n", fop);
+
+ return (fop);
+ } // end of PlugOpenFile
+
+/***********************************************************************/
+/* Close file routine: the purpose of this routine is to avoid */
+/* double closing that freeze the system on some Unix platforms. */
+/***********************************************************************/
+FILE *PlugReopenFile(PGLOBAL g, PFBLOCK fp, LPCSTR md)
+ {
+ FILE *fop;
+
+ if ((fop = global_fopen(g, MSGID_OPEN_MODE_STRERROR, fp->Fname, md))) {
+ fp->Count = 1;
+ fp->Type = TYPE_FB_FILE;
+ fp->File = fop;
+ } /* endif fop */
+
+ return (fop);
+ } // end of PlugOpenFile
+
+/***********************************************************************/
+/* Close file routine: the purpose of this routine is to avoid */
+/* double closing that freeze the system on some Unix platforms. */
+/***********************************************************************/
+int PlugCloseFile(PGLOBAL g, PFBLOCK fp, bool all)
+ {
+ int rc = 0;
+
+ if (trace(1))
+ htrc("PlugCloseFile: fp=%p count=%hd type=%hd\n",
+ fp, ((fp) ? fp->Count : 0), ((fp) ? fp->Type : 0));
+
+ if (!fp || !fp->Count)
+ return rc;
+
+ switch (fp->Type) {
+ case TYPE_FB_FILE:
+ if (fclose((FILE *)fp->File) == EOF)
+ rc = errno;
+
+ fp->File = NULL;
+ fp->Mode = MODE_ANY;
+ fp->Count = 0;
+ break;
+ case TYPE_FB_MAP:
+ if ((fp->Count = (all) ? 0 : fp->Count - 1))
+ break;
+
+ if (CloseMemMap(fp->Memory, fp->Length))
+ rc = (int)GetLastError();
+
+ fp->Memory = NULL;
+ fp->Mode = MODE_ANY;
+ // fall through
+ case TYPE_FB_HANDLE:
+ if (fp->Handle && fp->Handle != INVALID_HANDLE_VALUE)
+ if (CloseFileHandle(fp->Handle))
+ rc = (rc) ? rc : (int)GetLastError();
+
+ fp->Handle = INVALID_HANDLE_VALUE;
+ fp->Mode = MODE_ANY;
+ fp->Count = 0;
+ break;
+#ifdef DOMDOC_SUPPORT
+ case TYPE_FB_XML:
+ CloseXMLFile(g, fp, all);
+ break;
+#endif // DOMDOC_SUPPORT
+#ifdef LIBXML2_SUPPORT
+ case TYPE_FB_XML2:
+ CloseXML2File(g, fp, all);
+ break;
+#endif // LIBXML2_SUPPORT
+#ifdef ODBC_SUPPORT
+ case TYPE_FB_ODBC:
+ OdbcClose(g, fp);
+ fp->Count = 0;
+ fp->File = NULL;
+ break;
+#endif // ODBC_SUPPORT
+#ifdef ZIP_SUPPORT
+ case TYPE_FB_ZIP:
+ if (fp->Mode == MODE_INSERT)
+ ((ZIPUTIL*)fp->File)->close();
+ else
+ ((UNZIPUTL*)fp->File)->close();
+
+ fp->Memory = NULL;
+ fp->Mode = MODE_ANY;
+ fp->Count = 0;
+ fp->File = NULL;
+ break;
+#endif // ZIP_SUPPORT
+#ifdef JAVA_SUPPORT
+ case TYPE_FB_JAVA:
+ ((JAVAConn*)fp->File)->Close();
+ fp->Count = 0;
+ fp->File = NULL;
+ break;
+#endif // JAVA_SUPPORT
+#ifdef CMGO_SUPPORT
+ case TYPE_FB_MONGO:
+ ((CMgoConn*)fp->File)->Close();
+ fp->Count = 0;
+ fp->File = NULL;
+ break;
+#endif // JAVA_SUPPORT
+ default:
+ rc = RC_FX;
+ } // endswitch Type
+
+ return rc;
+ } // end of PlugCloseFile
+
+/***********************************************************************/
+/* PlugCleanup: Cleanup remaining items of a SQL query. */
+/***********************************************************************/
+void PlugCleanup(PGLOBAL g, bool dofree)
+ {
+ PCATLG cat;
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ // The test on Catalog is to avoid a Windows bug that can make
+ // LoadString in PlugGetMessage to fail in some case
+ if (!dbuserp || !(cat = dbuserp->Catalog))
+ return;
+
+ /*********************************************************************/
+ /* Close eventually still open/mapped files. */
+ /*********************************************************************/
+ for (PFBLOCK fp = dbuserp->Openlist; fp; fp = fp->Next)
+ PlugCloseFile(g, fp, true);
+
+ dbuserp->Openlist = NULL;
+
+ if (dofree) {
+ /*******************************************************************/
+ /* Cleanup any non suballocated memory still not freed. */
+ /*******************************************************************/
+ for (PMBLOCK mp = dbuserp->Memlist; mp; mp = mp->Next)
+ PlgDBfree(*mp);
+
+ dbuserp->Memlist = NULL;
+
+ /*******************************************************************/
+ /* If not using permanent storage catalog, reset volatile values. */
+ /*******************************************************************/
+ cat->Reset();
+
+ /*******************************************************************/
+ /* This is the place to reset the pointer on domains. */
+ /*******************************************************************/
+ dbuserp->Subcor = false;
+ dbuserp->Step = "New query"; // was STEP(PARSING_QUERY);
+ dbuserp->ProgMax = dbuserp->ProgCur = dbuserp->ProgSav = 0;
+ } // endif dofree
+
+ } // end of PlugCleanup
+
+#if 0
+/***********************************************************************/
+/* That stupid Windows 98 does not provide this function. */
+/***********************************************************************/
+bool WritePrivateProfileInt(LPCSTR sec, LPCSTR key, int n, LPCSTR ini)
+ {
+ char buf[12];
+
+ sprintf(buf, "%d", n);
+ return WritePrivateProfileString(sec, key, buf, ini);
+ } // end of WritePrivateProfileInt
+
+/***********************************************************************/
+/* Retrieve a size from an INI file with eventual K or M following. */
+/***********************************************************************/
+int GetIniSize(char *section, char *key, char *def, char *ini)
+ {
+ char c, buff[32];
+ int i;
+ int n = 0;
+
+ GetPrivateProfileString(section, key, def, buff, sizeof(buff), ini);
+
+ if ((i = sscanf(buff, " %d %c ", &n, &c)) == 2)
+ switch (toupper(c)) {
+ case 'M':
+ n *= 1024;
+ case 'K':
+ n *= 1024;
+ } // endswitch c
+
+ if (trace(1))
+ htrc("GetIniSize: key=%s buff=%s i=%d n=%d\n", key, buff, i, n);
+
+ return n;
+ } // end of GetIniSize
+
+/***********************************************************************/
+/* Allocate a string retrieved from an INI file and return its address */
+/***********************************************************************/
+DllExport PSZ GetIniString(PGLOBAL g, void *mp, LPCSTR sec, LPCSTR key,
+ LPCSTR def, LPCSTR ini)
+ {
+ char buff[_MAX_PATH];
+ PSZ p;
+ int n, m = sizeof(buff);
+ char *buf = buff;
+
+#if defined(_DEBUG)
+ assert (sec && key);
+#endif
+
+ again:
+ n = GetPrivateProfileString(sec, key, def, buf, m, ini);
+
+ if (n == m - 1) {
+ // String may have been truncated, make sure to have all
+ if (buf != buff)
+ delete [] buf;
+
+ m *= 2;
+ buf = new char[m];
+ goto again;
+ } // endif n
+
+ p = (PSZ)PlugSubAlloc(g, mp, n + 1);
+
+ if (trace(1))
+ htrc("GetIniString: sec=%s key=%s buf=%s\n", sec, key, buf);
+
+ strcpy(p, buf);
+
+ if (buf != buff)
+ delete [] buf;
+
+ return p;
+ } // end of GetIniString
+#endif // 0
+
+/***********************************************************************/
+/* GetAmName: return the name correponding to an AM code. */
+/***********************************************************************/
+char *GetAmName(PGLOBAL g, AMT am, void *memp)
+ {
+ char *amn= (char*)PlugSubAlloc(g, memp, 16);
+
+ switch (am) {
+ case TYPE_AM_ERROR: strcpy(amn, "ERROR"); break;
+ case TYPE_AM_ROWID: strcpy(amn, "ROWID"); break;
+ case TYPE_AM_FILID: strcpy(amn, "FILID"); break;
+ case TYPE_AM_VIEW: strcpy(amn, "VIEW"); break;
+ case TYPE_AM_COUNT: strcpy(amn, "COUNT"); break;
+ case TYPE_AM_DCD: strcpy(amn, "DCD"); break;
+ case TYPE_AM_CMS: strcpy(amn, "CMS"); break;
+ case TYPE_AM_MAP: strcpy(amn, "MAP"); break;
+ case TYPE_AM_FMT: strcpy(amn, "FMT"); break;
+ case TYPE_AM_CSV: strcpy(amn, "CSV"); break;
+ case TYPE_AM_MCV: strcpy(amn, "MCV"); break;
+ case TYPE_AM_DOS: strcpy(amn, "DOS"); break;
+ case TYPE_AM_FIX: strcpy(amn, "FIX"); break;
+ case TYPE_AM_BIN: strcpy(amn, "BIN"); break;
+ case TYPE_AM_VCT: strcpy(amn, "VEC"); break;
+ case TYPE_AM_VMP: strcpy(amn, "VMP"); break;
+ case TYPE_AM_DBF: strcpy(amn, "DBF"); break;
+ case TYPE_AM_QRY: strcpy(amn, "QRY"); break;
+ case TYPE_AM_SQL: strcpy(amn, "SQL"); break;
+ case TYPE_AM_PLG: strcpy(amn, "PLG"); break;
+ case TYPE_AM_PLM: strcpy(amn, "PLM"); break;
+ case TYPE_AM_DOM: strcpy(amn, "DOM"); break;
+ case TYPE_AM_DIR: strcpy(amn, "DIR"); break;
+ case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break;
+ case TYPE_AM_JDBC: strcpy(amn, "JDBC"); break;
+ case TYPE_AM_MAC: strcpy(amn, "MAC"); break;
+ case TYPE_AM_OEM: strcpy(amn, "OEM"); break;
+ case TYPE_AM_OUT: strcpy(amn, "OUT"); break;
+ default: sprintf(amn, "OEM(%d)", am);
+ } // endswitch am
+
+ return amn;
+ } // end of GetAmName
+
+#if defined(SE_CATCH)
+/***********************************************************************/
+/* GetExceptionDesc: return the description of an exception code. */
+/***********************************************************************/
+char *GetExceptionDesc(PGLOBAL g, unsigned int e)
+ {
+ char *p;
+
+ switch (e) {
+ case EXCEPTION_GUARD_PAGE:
+ p = MSG(GUARD_PAGE);
+ break;
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ p = MSG(DATA_MISALIGN);
+ break;
+ case EXCEPTION_BREAKPOINT:
+ p = MSG(BREAKPOINT);
+ break;
+ case EXCEPTION_SINGLE_STEP:
+ p = MSG(SINGLE_STEP);
+ break;
+ case EXCEPTION_ACCESS_VIOLATION:
+ p = MSG(ACCESS_VIOLATN);
+ break;
+ case EXCEPTION_IN_PAGE_ERROR:
+ p = MSG(PAGE_ERROR);
+ break;
+ case EXCEPTION_INVALID_HANDLE:
+ p = MSG(INVALID_HANDLE);
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ p = MSG(ILLEGAL_INSTR);
+ break;
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ p = MSG(NONCONT_EXCEPT);
+ break;
+ case EXCEPTION_INVALID_DISPOSITION:
+ p = MSG(INVALID_DISP);
+ break;
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ p = MSG(ARRAY_BNDS_EXCD);
+ break;
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ p = MSG(FLT_DENORMAL_OP);
+ break;
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ p = MSG(FLT_ZERO_DIVIDE);
+ break;
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ p = MSG(FLT_BAD_RESULT);
+ break;
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ p = MSG(FLT_INVALID_OP);
+ break;
+ case EXCEPTION_FLT_OVERFLOW:
+ p = MSG(FLT_OVERFLOW);
+ break;
+ case EXCEPTION_FLT_STACK_CHECK:
+ p = MSG(FLT_STACK_CHECK);
+ break;
+ case EXCEPTION_FLT_UNDERFLOW:
+ p = MSG(FLT_UNDERFLOW);
+ break;
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ p = MSG(INT_ZERO_DIVIDE);
+ break;
+ case EXCEPTION_INT_OVERFLOW:
+ p = MSG(INT_OVERFLOW);
+ break;
+ case EXCEPTION_PRIV_INSTRUCTION:
+ p = MSG(PRIV_INSTR);
+ break;
+ case EXCEPTION_STACK_OVERFLOW:
+ p = MSG(STACK_OVERFLOW);
+ break;
+ case CONTROL_C_EXIT:
+ p = MSG(CONTROL_C_EXIT);
+ break;
+ case STATUS_NO_MEMORY:
+ p = MSG(NO_MEMORY);
+ break;
+ default:
+ p = MSG(UNKNOWN_EXCPT);
+ break;
+ } // endswitch nSE
+
+ return p;
+ } // end of GetExceptionDesc
+#endif // SE_CATCH
+
+/***********************************************************************/
+/* PlgDBalloc: allocates or suballocates memory conditionally. */
+/* If mp.Sub is true at entry, this forces suballocation. */
+/* If the memory is allocated, makes an entry in an allocation list */
+/* so it can be freed at the normal or error query completion. */
+/***********************************************************************/
+void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp)
+{
+//bool b;
+ size_t maxsub, minsub;
+ void *arp = (area) ? area : g->Sarea;
+ PPOOLHEADER pph = (PPOOLHEADER)arp;
+
+ if (mp.Memp) {
+ // This is a reallocation. If this block is not suballocated, it
+ // was already placed in the chain of memory blocks and we must
+ // not do it again as it can trigger a loop when freeing them.
+ // Note: this works if blocks can be reallocated only once.
+ // Otherwise a new boolean must be added to the block that
+ // indicate that it is chained, or a test on the whole chain be
+ // done to check whether the block is already there.
+// b = mp.Sub;
+ mp.Sub = false; // Restrict suballocation to one quarter
+ } // endif Memp
+
+ // Suballoc when possible if mp.Sub is initially true, but leaving
+ // a minimum amount of storage for future operations such as the
+ // optimize recalculation after insert; otherwise
+ // suballoc only if size is smaller than one quarter of free mem.
+ minsub = (pph->FreeBlk + pph->To_Free + 524248) >> 2;
+ maxsub = (pph->FreeBlk < minsub) ? 0 : pph->FreeBlk - minsub;
+ mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2));
+
+ if (trace(2))
+ htrc("PlgDBalloc: in %p size=%zd used=%zd free=%zd sub=%d\n",
+ arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub);
+
+ if (!mp.Sub) {
+ // For allocations greater than one fourth of remaining storage
+ // in the area, do allocate from virtual storage.
+ const char*v = "malloc";
+#if defined(_WIN32)
+ if (mp.Size >= BIGMEM) {
+ v = "VirtualAlloc";
+ mp.Memp = VirtualAlloc(NULL, mp.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ } else
+#endif
+ mp.Memp = malloc(mp.Size);
+
+ if (trace(8))
+ htrc("PlgDBalloc: %s(%zd) at %p\n", v, mp.Size, mp.Memp);
+
+ if (!mp.Inlist && mp.Memp) {
+ // New allocated block, put it in the memory block chain.
+ PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
+
+ mp.Next = dbuserp->Memlist;
+ dbuserp->Memlist = &mp;
+ mp.Inlist = true;
+ } // endif mp
+
+ } else
+ // Suballocating is Ok.
+ mp.Memp = PlugSubAlloc(g, area, mp.Size);
+
+ return mp.Memp;
+} // end of PlgDBalloc
+
+/***********************************************************************/
+/* PlgDBrealloc: reallocates memory conditionally. */
+/* Note that this routine can fail only when block size is increased */
+/* because otherwise we keep the old storage on failure. */
+/***********************************************************************/
+void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize)
+ {
+ MBLOCK m;
+
+#if defined(_DEBUG)
+// assert (mp.Memp != NULL);
+#endif
+
+ if (trace(2))
+ htrc("PlgDBrealloc: %p size=%zd sub=%d\n", mp.Memp, mp.Size, mp.Sub);
+
+ if (newsize == mp.Size)
+ return mp.Memp; // Nothing to do
+ else
+ m = mp;
+
+ if (!mp.Sub && mp.Size < BIGMEM && newsize < BIGMEM) {
+ // Allocation was done by malloc, try to use realloc but
+ // suballoc if newsize is smaller than one quarter of free mem.
+ size_t maxsub;
+ PPOOLHEADER pph = (PPOOLHEADER)((area) ? area : g->Sarea);
+
+ maxsub = (pph->FreeBlk < 131072) ? 0 : pph->FreeBlk - 131072;
+
+ if ((mp.Sub = (newsize <= (maxsub >> 2)))) {
+ mp.Memp = PlugSubAlloc(g, area, newsize);
+ memcpy(mp.Memp, m.Memp, MY_MIN(m.Size, newsize));
+ PlgDBfree(m); // Free the old block
+ } else {
+ if (!(mp.Memp = realloc(mp.Memp, newsize))) {
+ mp = m; // Possible only if newsize > Size
+ return NULL; // Failed
+ } else if (trace(8))
+ htrc("PlgDBrealloc: realloc(%ld) at %p\n", newsize, mp.Memp);
+
+ } // endif's
+
+ mp.Size = newsize;
+ } else if (!mp.Sub || newsize > mp.Size) {
+ // Was suballocated or Allocation was done by VirtualAlloc
+ // Make a new allocation and copy the useful part
+ // Note: DO NOT reset Memp and Sub so we know that this
+ // is a reallocation in PlgDBalloc
+ mp.Size = newsize;
+
+ if (PlgDBalloc(g, area, mp)) {
+ memcpy(mp.Memp, m.Memp, MY_MIN(m.Size, newsize));
+ PlgDBfree(m); // Free the old block
+ } else {
+ mp = m; // No space to realloc, do nothing
+
+ if (newsize > m.Size)
+ return NULL; // Failed
+
+ } // endif PlgDBalloc
+
+ } // endif's
+
+ if (trace(8))
+ htrc(" newsize=%zd newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub);
+
+ return mp.Memp;
+ } // end of PlgDBrealloc
+
+/***********************************************************************/
+/* PlgDBfree: free memory if not suballocated. */
+/***********************************************************************/
+void PlgDBfree(MBLOCK& mp)
+ {
+ if (!mp.Sub && mp.Memp) {
+ const char*v = "free";
+#if defined(_WIN32)
+ if (mp.Size >= BIGMEM) {
+ v = "VirtualFree";
+ VirtualFree(mp.Memp, 0, MEM_RELEASE);
+ } else
+#endif
+ free(mp.Memp);
+
+ if (trace(8))
+ htrc("PlgDBfree: %s(%p) size=%d\n", v, mp.Memp, mp.Size);
+
+ } // endif mp
+
+ // Do not reset Next to avoid cutting the Mblock chain
+ mp.Memp = NULL;
+ mp.Sub = false;
+ mp.Size = 0;
+ } // end of PlgDBfree
+
+/***********************************************************************/
+/* Program for sub-allocating one item in a storage area. */
+/* Note: This function is equivalent to PlugSubAlloc except that in */
+/* case of insufficient memory, it returns NULL instead of doing a */
+/* throw. The caller must test the return value for error. */
+/***********************************************************************/
+void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size)
+ {
+ PPOOLHEADER pph; // Points on area header.
+
+ if (!memp)
+ /*******************************************************************/
+ /* Allocation is to be done in the Sarea. */
+ /*******************************************************************/
+ memp = g->Sarea;
+
+//size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */
+ size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */
+ pph = (PPOOLHEADER)memp;
+
+ if (trace(16))
+ htrc("PlgDBSubAlloc: memp=%p size=%zd used=%zd free=%zd\n",
+ memp, size, pph->To_Free, pph->FreeBlk);
+
+ if (size > pph->FreeBlk) { /* Not enough memory left in pool */
+ sprintf(g->Message,
+ "Not enough memory in Work area for request of %zd (used=%zd free=%zd)",
+ size, pph->To_Free, pph->FreeBlk);
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return NULL;
+ } // endif size
+
+ /*********************************************************************/
+ /* Do the suballocation the simplest way. */
+ /*********************************************************************/
+ memp = MakePtr(memp, pph->To_Free); // Points to suballocated block
+ pph->To_Free += size; // New offset of pool free block
+ pph->FreeBlk -= size; // New size of pool free block
+
+ if (trace(16))
+ htrc("Done memp=%p used=%zd free=%zd\n",
+ memp, pph->To_Free, pph->FreeBlk);
+
+ return (memp);
+ } // end of PlgDBSubAlloc
+
+/***********************************************************************/
+/* Program for sub-allocating and copying a string in a storage area. */
+/***********************************************************************/
+char *PlgDBDup(PGLOBAL g, const char *str)
+ {
+ if (str) {
+ char *sm = (char*)PlgDBSubAlloc(g, NULL, strlen(str) + 1);
+
+ if (sm)
+ strcpy(sm, str);
+
+ return sm;
+ } else
+ return NULL;
+
+ } // end of PlgDBDup
+
+/***********************************************************************/
+/* PUTOUT: Plug DB object typing routine. */
+/***********************************************************************/
+void PlugPutOut(PGLOBAL g, FILE *f, short t, void *v, uint n)
+ {
+ char m[64];
+
+ if (trace(1))
+ htrc("PUTOUT: f=%p t=%d v=%p n=%d\n", f, t, v, n);
+
+ if (!v)
+ return;
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+ n += 2; /* Increase margin */
+
+ switch (t) {
+ case TYPE_ERROR:
+ fprintf(f, "--> %s\n", (PSZ)v);
+ break;
+
+ case TYPE_STRING:
+ case TYPE_PSZ:
+ fprintf(f, "%s%s\n", m, (PSZ)v);
+ break;
+
+ case TYPE_DOUBLE:
+ fprintf(f, "%s%lf\n", m, *(double *)v);
+ break;
+
+ case TYPE_LIST:
+ case TYPE_COLIST:
+ case TYPE_COL:
+ {PPARM p;
+
+ if (t == TYPE_LIST)
+ fprintf(f, "%s%s\n", m, MSG(LIST));
+ else
+ fprintf(f, "%s%s\n", m, "Colist:");
+
+ for (p = (PPARM)v; p; p = p->Next)
+ PlugPutOut(g, f, p->Type, p->Value, n);
+
+ } break;
+
+ case TYPE_INT:
+ fprintf(f, "%s%d\n", m, *(int *)v);
+ break;
+
+ case TYPE_SHORT:
+ fprintf(f, "%s%hd\n", m, *(short *)v);
+ break;
+
+ case TYPE_TINY:
+ fprintf(f, "%s%d\n", m, (int)*(char *)v);
+ break;
+
+ case TYPE_VOID:
+ break;
+
+ case TYPE_SQL:
+ case TYPE_TABLE:
+ case TYPE_TDB:
+ case TYPE_XOBJECT:
+ ((PBLOCK)v)->Printf(g, f, n-2);
+ break;
+
+ default:
+ fprintf(f, "%s%s %d\n", m, MSG(ANSWER_TYPE), t);
+ } /* endswitch */
+
+ return;
+ } /* end of PlugPutOut */
+
+/***********************************************************************/
+/* NewPointer: makes a table of pointer values to be changed later. */
+/***********************************************************************/
+DllExport void NewPointer(PTABS t, void *oldv, void *newv)
+ {
+ PTABPTR tp;
+
+ if (!oldv) /* error ?????????? */
+ return;
+
+ if (!t->P1 || t->P1->Num == 50)
+ {
+ if (!(tp = new TABPTR)) {
+ PGLOBAL g = t->G;
+
+ sprintf(g->Message, "NewPointer: %s", MSG(MEM_ALLOC_ERROR));
+ throw 3;
+ } else {
+ tp->Next = t->P1;
+ tp->Num = 0;
+ t->P1 = tp;
+ } /* endif tp */
+ }
+
+ t->P1->Old[t->P1->Num] = oldv;
+ t->P1->New[t->P1->Num++] = newv;
+ } /* end of NewPointer */
+
+#if 0
+/***********************************************************************/
+/* Compare two files and return 0 if they are identical, else 1. */
+/***********************************************************************/
+int FileComp(PGLOBAL g, char *file1, char *file2)
+ {
+ char *fn[2], *bp[2], buff1[4096], buff2[4096];
+ int i, k, n[2], h[2] = {-1,-1};
+ int len[2], rc = -1;
+
+ fn[0] = file1; fn[1] = file2;
+ bp[0] = buff1; bp[1] = buff2;
+
+ for (i = 0; i < 2; i++) {
+#if defined(_WIN32)
+ h[i]= global_open(g, MSGID_NONE, fn[i], _O_RDONLY | _O_BINARY);
+#else // !_WIN32
+ h[i]= global_open(g, MSGOD_NONE, fn[i], O_RDONLY);
+#endif // !_WIN32
+
+ if (h[i] == -1) {
+// if (errno != ENOENT) {
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "rb", (int)errno, fn[i]);
+ strcat(strcat(g->Message, ": "), strerror(errno));
+ throw 666;
+ // } else
+// len[i] = 0; // File does not exist yet
+
+ } else {
+ if ((len[i] = _filelength(h[i])) < 0) {
+ sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", fn[i]);
+ throw 666;
+ } // endif len
+
+ } // endif h
+
+ } // endfor i
+
+ if (len[0] != len[1])
+ rc = 1;
+
+ while (rc == -1) {
+ for (i = 0; i < 2; i++)
+ if ((n[i] = read(h[i], bp[i], 4096)) < 0) {
+ sprintf(g->Message, MSG(READ_ERROR), fn[i], strerror(errno));
+ goto fin;
+ } // endif n
+
+ if (n[0] != n[1])
+ rc = 1;
+ else if (*n == 0)
+ rc = 0;
+ else for (k = 0; k < *n; k++)
+ if (*(bp[0] + k) != *(bp[1] + k)) {
+ rc = 1;
+ goto fin;
+ } // endif bp
+
+ } // endwhile
+
+ fin:
+ for (i = 0; i < 2; i++)
+ if (h[i] != -1)
+ close(h[i]);
+
+ return rc;
+ } // end of FileComp
+#endif // 0
diff --git a/storage/connect/plgodbc.h b/storage/connect/plgodbc.h
new file mode 100644
index 00000000..46bc41ad
--- /dev/null
+++ b/storage/connect/plgodbc.h
@@ -0,0 +1,230 @@
+/***********************************************************************/
+/* PLGODBC.H - This is the ODBC PlugDB driver include file. */
+/***********************************************************************/
+//efine WINVER 0x0300 // prevent Windows 3.1 feature usage
+#include <windows.h> /* Windows include file */
+#include <windowsx.h> /* Message crackers */
+#include <commctrl.h>
+
+/***********************************************************************/
+/* Included C-definition files required by the interface. */
+/***********************************************************************/
+#include <string.h> /* String manipulation declares */
+#include <stdlib.h> /* C standard library */
+#include <ctype.h> /* C language specific types */
+#include <stdio.h> /* FOPEN_MAX declaration */
+#include <time.h> /* time_t type declaration */
+
+/***********************************************************************/
+/* ODBC interface of PlugDB driver declares. */
+/***********************************************************************/
+#include "podbcerr.h" /* Resource ID for PlugDB Driver */
+#if !defined(WIN32)
+#include "w16macro.h"
+#endif
+
+#define ODBCVER 0x0300
+
+#include "sqltypes.h"
+#include "sql.h"
+#include "sqlext.h"
+
+/***********************************************************************/
+/* Definitions to be used in function prototypes. */
+/* The SQL_API is to be used only for those functions exported for */
+/* driver manager use. */
+/* The EXPFUNC is to be used only for those functions exported but */
+/* used internally, ie, dialog procs. */
+/* The INTFUNC is to be used for all other functions. */
+/***********************************************************************/
+#if defined(WIN32)
+#define INTFUNC __stdcall
+#define EXPFUNC __stdcall
+#else
+#define INTFUNC FAR PASCAL
+#define EXPFUNC __export CALLBACK
+#endif
+
+/***********************************************************************/
+/* External variables. */
+/***********************************************************************/
+extern HINSTANCE NEAR s_hModule; // DLL handle.
+#ifdef DEBTRACE
+extern FILE *debug;
+#endif
+extern bool clearerror;
+
+/***********************************************************************/
+/* Additional values used by PlugDB for ODBC. */
+/***********************************************************************/
+#define RES_TYPE_PREPARE 1 /* Result from SQLPrepare */
+#define RES_TYPE_CATALOG 2 /* Result from catalog funcs */
+#define MAXPATHLEN _MAX_PATH /* Max path length */
+#define MAXKEYLEN 16 /* Max keyword length */
+#define MAXDESC 256 /* Max description length */
+#define MAXDSNAME 33 /* Max data source name length */
+#define MAXCRNAME 18 /* Max stmt cursor name length */
+#define DEFMAXRES 6300 /* Default MaxRes value */
+#define NAM_LEN 128 /* Length of col and tab names */
+
+#define MAXRESULT 1000 /* ? */
+#define MAXCOMMAND 200 /* ? */
+#define RC_ERROR RC_LAST-1
+#define RC_FREE 3
+
+#if !defined(NOLIB)
+#define CNXKEY uint /* C Key returned by Conn DLL */
+#else
+typedef struct _conninfo *PCONN;
+#endif /* !NOLIB */
+
+#if defined(DEBTRACE)
+#define TRACE0(X) fprintf(debug,X);
+#define TRACE1(X,A) fprintf(debug,X,A);
+#define TRACE2(X,A,B) fprintf(debug,X,A,B);
+#define TRACE3(X,A,B,C) fprintf(debug,X,A,B,C);
+#define TRACE4(X,A,B,C,D) fprintf(debug,X,A,B,C,D);
+#define TRACE5(X,A,B,C,D,E) fprintf(debug,X,A,B,C,D,E);
+#define TRACE6(X,A,B,C,D,E,F) fprintf(debug,X,A,B,C,D,E,F);
+#else /* !DEBTRACE*/
+#define TRACE0(X)
+#define TRACE1(X,A)
+#define TRACE2(X,A,B)
+#define TRACE3(X,A,B,C)
+#define TRACE4(X,A,B,C,D)
+#define TRACE5(X,A,B,C,D,E)
+#define TRACE6(X,A,B,C,D,E,F)
+#endif /* !DEBTRACE*/
+
+// This definition MUST be identical to the value in plgdbsem.h
+#define XMOD_PREPARE 1
+
+/***********************************************************************/
+/* ODBC.INI keywords (use extern definition in SETUP.C) */
+/***********************************************************************/
+extern char const *EMPTYSTR; /* Empty String */
+extern char const *OPTIONON;
+extern char const *OPTIONOFF;
+extern char const *INI_SDEFAULT; /* Default data source name */
+extern char const *ODBC_INI; /* ODBC initialization file */
+extern char const *INI_KDEFL; /* Is SQL to use by default? */
+extern char const *INI_KLANG; /* Application language */
+extern char const *INI_KDATA; /* Data description file */
+extern char const *INI_KSVR; /* PLG Server */
+
+/************************************************************************/
+/* Attribute key indexes (into an array of Attr structs, see below) */
+/************************************************************************/
+#define KEY_DSN 0
+#define KEY_DEFL 1
+#define KEY_LANG 2
+#define KEY_DATA 3
+#define KEY_SERVER 4
+#define LAST_KEY 5 /* Number of keys in TAG's */
+#define KEY_DESC 5
+#define KEY_TRANSNAME 6
+#define KEY_TRANSOPTION 7
+#define KEY_TRANSDLL 8
+#define NUMOFKEYS 9 /* Number of keys supported */
+
+#define FOURYEARS 126230400 // Four years in seconds (1 leap)
+
+/***********************************************************************/
+/* This is used when an "out of memory" error happens, because this */
+/* error recording system allocates memory when it logs an error, */
+/* and it would be bad if it tried to allocate memory when it got an */
+/* out of memory error. */
+/***********************************************************************/
+typedef enum _ERRSTAT {
+ errstatOK,
+ errstatNO_MEMORY,
+ } ERRSTAT;
+
+/***********************************************************************/
+/* Types */
+/***********************************************************************/
+typedef struct TagAttr {
+ bool fSupplied;
+ char Attr[MAXPATHLEN];
+ } TAG, *PTAG;
+
+typedef struct _parscons { /* Parse constants */
+ int Slen; /* String length */
+ int Ntag; /* Number of entries in tags */
+ int Nlook; /* Number of entries in lookup */
+ char Sep; /* Separator */
+ } PARC, *PPARC;
+
+/***********************************************************************/
+/* Attribute string look-up table (maps keys to associated indexes) */
+/***********************************************************************/
+typedef struct _Look {
+ const char *szKey;
+ int iKey;
+ } LOOK, *PLOOK;
+
+/***********************************************************************/
+/* This is info about a single error. */
+/***********************************************************************/
+typedef struct _ERRBLK *PERRBLK;
+
+typedef struct _ERRBLK {
+ PERRBLK Next; /* Next block in linked list of error blocks */
+ DWORD Native_Error; /* Native error */
+ DWORD Stderr; /* SQLC error code */
+ PSZ Message; /* Points to text of message */
+ } ERRBLK;
+
+/***********************************************************************/
+/* This is a header block, it records information about a list of */
+/* errors (ERRBLOCK's). */
+/***********************************************************************/
+typedef struct _ERRINFO {
+ PERRBLK First; /* First block in linked list of error blocks. */
+ PERRBLK Last; /* Last block in above list. */
+ ERRSTAT Errstat; /* Status for special condition out of memory */
+ } ERRINFO, *PERRINFO;
+
+/***********************************************************************/
+/* Environment information. */
+/***********************************************************************/
+typedef struct _env {
+ ERRINFO Errinfo; /* Error list */
+ UDWORD ODBCver;
+ UDWORD ODBCdateformat;
+ } ENV, *PENV;
+
+/***********************************************************************/
+/* Classes used in the PlugDB ODBC Driver. */
+/***********************************************************************/
+typedef class DBC *PDBC;
+typedef class STMT *PSTMT;
+typedef class CURSOR *PCURSOR;
+typedef class RESULT *PRESULT;
+typedef class BINDDATA *PBIND;
+typedef class BINDPARM *PBDPARM;
+typedef class CPLGdrv *PSCDRV;
+typedef class DESCRIPTOR *PDSC;
+
+/***********************************************************************/
+/* ODBC Prototypes. */
+/***********************************************************************/
+void PostSQLError(HENV, HDBC, HSTMT, DWORD, DWORD, PSZ);
+void ClearSQLError(HENV, HDBC, HSTMT);
+short LoadRcString(UWORD, LPSTR, short);
+RETCODE RetcodeCopyBytes(HDBC, HSTMT, UCHAR FAR *, SWORD,
+ SWORD FAR *, UCHAR FAR *, SWORD, bool);
+
+/***********************************************************************/
+/* Private functions used by the driver. */
+/***********************************************************************/
+bool EXPFUNC FDriverConnectProc(HWND, WORD, WPARAM, LPARAM);
+extern void ParseAttrString(PLOOK, PTAG, UCHAR FAR *, PPARC);
+RETCODE PASCAL StringCopy(HDBC, HSTMT, PTR, SWORD, SWORD FAR *,
+ char FAR *);
+RETCODE PASCAL ShortCopy(HDBC, HSTMT, PTR, SWORD, SWORD FAR *, short);
+RETCODE PASCAL LongCopy(HDBC, HSTMT, PTR, SWORD, SWORD FAR *, int);
+RETCODE PASCAL GeneralCopy(HDBC, HSTMT, PTR, SWORD,
+ SWORD FAR *, PTR, SWORD);
+
+/* --------------------- End of PLGODBC.H ---------------------------- */
diff --git a/storage/connect/plgxml.cpp b/storage/connect/plgxml.cpp
new file mode 100644
index 00000000..8c5cc261
--- /dev/null
+++ b/storage/connect/plgxml.cpp
@@ -0,0 +1,185 @@
+/******************************************************************/
+/* Implementation of XML document processing using PdbXML. */
+/* Author: Olivier Bertrand 2007-2017 */
+/******************************************************************/
+#include "my_global.h"
+#include "global.h"
+#include "plgdbsem.h"
+#include "block.h"
+#include "plgxml.h"
+
+#if !defined(DOMDOC_SUPPORT)
+PXDOC GetDomDoc(PGLOBAL g, char *nsl, char *nsdf,
+ char *enc, PFBLOCK fp)
+ {
+ strcpy(g->Message, MSG(DOM_NOT_SUPP));
+ return NULL;
+ } // end of GetDomDoc
+#endif // !DOMDOC_SUPPORT
+
+#ifndef LIBXML2_SUPPORT
+PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf,
+ char *enc, PFBLOCK fp)
+ {
+ strcpy(g->Message, "libxml2 not supported");
+ return NULL;
+ } // end of GetLibxmlDoc
+#endif // LIBXML2_SUPPORT
+
+/******************************************************************/
+/* XMLDOCUMENT constructor. */
+/******************************************************************/
+XMLDOCUMENT::XMLDOCUMENT(char *nsl, char *nsdf, char *enc)
+{
+#if defined(ZIP_SUPPORT)
+ zip = NULL;
+#else // !ZIP_SUPPORT
+ zip = false;
+#endif // !ZIP_SUPPORT
+ Namespaces = NULL;
+ Encoding = enc;
+ Nslist = nsl;
+ DefNs = nsdf;
+} // end of XMLDOCUMENT constructor
+
+/******************************************************************/
+/* Initialize zipped file processing. */
+/******************************************************************/
+bool XMLDOCUMENT::InitZip(PGLOBAL g, PCSZ entry)
+{
+#if defined(ZIP_SUPPORT)
+ bool mul = (entry) ? strchr(entry, '*') || strchr(entry, '?') : false;
+ zip = new(g) UNZIPUTL(entry, NULL, mul);
+ return zip == NULL;
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return true;
+#endif // !ZIP_SUPPORT
+} // end of InitZip
+
+/******************************************************************/
+/* Make the namespace structure list. */
+/******************************************************************/
+char* XMLDOCUMENT::GetMemDoc(PGLOBAL g, char *fn)
+{
+#if defined(ZIP_SUPPORT)
+ return (zip->OpenTable(g, MODE_ANY, fn)) ? NULL : zip->memory;
+#else // !ZIP_SUPPORT
+ return NULL;
+#endif // !ZIP_SUPPORT
+} // end of GetMemDoc
+
+/******************************************************************/
+/* Make the namespace structure list. */
+/******************************************************************/
+bool XMLDOCUMENT::MakeNSlist(PGLOBAL g)
+{
+ char *prefix, *href, *next = Nslist;
+ PNS nsp, *ppns = &Namespaces;
+
+ while (next) {
+ // Skip spaces
+ while ((*next) == ' ')
+ next++;
+
+ if ((*next) == '\0')
+ break;
+
+ // Find prefix
+ prefix = next;
+ next = strchr(next, '=');
+
+ if (next == NULL) {
+ strcpy(g->Message, MSG(BAS_NS_LIST));
+ return true;
+ } // endif next
+
+ *(next++) = '\0';
+
+ // Find href
+ href = next;
+ next = strchr(next, ' ');
+
+ if (next != NULL)
+ *(next++) = '\0';
+
+ // Allocate and link NS structure
+ nsp = (PNS)PlugSubAlloc(g, NULL, sizeof(NS));
+ nsp->Next = NULL;
+ nsp->Prefix = prefix;
+ nsp->Uri = href;
+ *ppns = nsp;
+ ppns = &nsp->Next;
+ } // endwhile next
+
+ return false;
+ } // end of MakeNSlist
+
+/******************************************************************/
+/* Close ZIP file. */
+/******************************************************************/
+void XMLDOCUMENT::CloseZip(void)
+{
+#if defined(ZIP_SUPPORT)
+ if (zip) {
+ zip->close();
+ zip = NULL;
+ } // endif zip
+#endif // ZIP_SUPPORT
+} // end of CloseZip
+
+/******************************************************************/
+/* XMLNODE constructor. */
+/******************************************************************/
+XMLNODE::XMLNODE(PXDOC dp)
+ {
+ Doc = dp;
+ Next = NULL;
+ Children = NULL;
+ Buf = NULL;
+ Len = -1;
+ } // end of XMLNODE constructor
+
+/******************************************************************/
+/* Attach new node at the end of this node children list. */
+/******************************************************************/
+PXNODE XMLNODE::NewChild(PXNODE ncp)
+{
+ PXNODE np, *pnp = &Children;
+
+ for (np = *pnp; np; np = np->Next)
+ pnp = &np->Next;
+
+ *pnp = np;
+ return ncp;
+} // end of NewChild
+
+/******************************************************************/
+/* Delete a node from this node children list. */
+/******************************************************************/
+void XMLNODE::Delete(PXNODE dnp)
+ {
+ PXNODE *pnp = &Children;
+
+ for (PXNODE np = *pnp; np; np = np->Next)
+ if (np == dnp) {
+ *pnp = dnp->Next;
+ break;
+ } else
+ pnp = &np->Next;
+
+ } // end of Delete
+
+/******************************************************************/
+/* Store a string in Buf, enventually reallocating it. */
+/******************************************************************/
+char *XMLNODE::BufAlloc(PGLOBAL g, const char *p, int n)
+ {
+ if (Len < n) {
+ Len = n;
+ Buf = (char*)PlugSubAlloc(g, NULL, n + 1);
+ } // endif Len
+
+ *Buf = '\0';
+ return strncat(Buf, p, n);
+ } // end of BufAlloc
diff --git a/storage/connect/plgxml.h b/storage/connect/plgxml.h
new file mode 100644
index 00000000..82629e4c
--- /dev/null
+++ b/storage/connect/plgxml.h
@@ -0,0 +1,194 @@
+#if defined(ZIP_SUPPORT)
+#include "filamzip.h"
+#endif // ZIP_SUPPORT
+
+/******************************************************************/
+/* Dual XML implementation base classes defines. */
+/******************************************************************/
+#if !defined(BASE_BUFFER_SIZE)
+enum ElementType { // libxml2
+ XML_ELEMENT_NODE = 1,
+ XML_ATTRIBUTE_NODE = 2,
+ XML_TEXT_NODE = 3,
+ XML_CDATA_SECTION_NODE = 4,
+ XML_ENTITY_REF_NODE = 5,
+ XML_ENTITY_NODE = 6,
+ XML_PI_NODE = 7,
+ XML_COMMENT_NODE = 8,
+ XML_DOCUMENT_NODE = 9,
+ XML_DOCUMENT_TYPE_NODE = 10,
+ XML_DOCUMENT_FRAG_NODE = 11,
+ XML_NOTATION_NODE = 12,
+ XML_HTML_DOCUMENT_NODE = 13,
+ XML_DTD_NODE = 14,
+ XML_ELEMENT_DECL = 15,
+ XML_ATTRIBUTE_DECL = 16,
+ XML_ENTITY_DECL = 17,
+ XML_NAMESPACE_DECL = 18,
+ XML_XINCLUDE_START = 19,
+ XML_XINCLUDE_END = 20,
+ XML_DOCB_DOCUMENT_NODE = 21};
+#endif // !BASE_BUFFER_SIZE
+
+//#if !defined(NODE_TYPE_LIST)
+#ifdef NOT_USED
+enum NodeType { // MS DOM
+ NODE_ELEMENT = 1,
+ NODE_ATTRIBUTE = 2,
+ NODE_TEXT = 3,
+ NODE_CDATA_SECTION = 4,
+ NODE_ENTITY_REFERENCE = 5,
+ NODE_ENTITY = 6,
+ NODE_PROCESSING_INSTRUCTION = 7,
+ NODE_COMMENT = 8,
+ NODE_DOCUMENT = 9,
+ NODE_DOCUMENT_TYPE = 10,
+ NODE_DOCUMENT_FRAGMENT = 11,
+ NODE_NOTATION = 12};
+#endif // !NODE_TYPE_LIST
+
+typedef class XMLDOCUMENT *PXDOC; // Document
+typedef class XMLNODE *PXNODE; // Node (Element)
+typedef class XMLNODELIST *PXLIST; // Node list
+typedef class XMLATTRIBUTE *PXATTR; // Attribute
+
+typedef struct _ns {
+ struct _ns *Next;
+ char *Prefix;
+ char *Uri;
+ } NS, *PNS;
+
+PXDOC GetLibxmlDoc(PGLOBAL g, char *nsl, char *nsdf,
+ char *enc, PFBLOCK fp = NULL);
+PXDOC GetDomDoc(PGLOBAL g, char *nsl, char *nsdf,
+ char *enc, PFBLOCK fp = NULL);
+
+/******************************************************************/
+/* Declaration of XML document. */
+/******************************************************************/
+class XMLDOCUMENT : public BLOCK {
+ friend class XML2NODE;
+ friend class DOMNODE;
+ public:
+ // Properties
+ virtual short GetDocType(void) = 0;
+ virtual void *GetDocPtr(void) = 0;
+ virtual void SetNofree(bool b) = 0;
+
+ // Methods
+ virtual bool Initialize(PGLOBAL, PCSZ, bool) = 0;
+ virtual bool ParseFile(PGLOBAL, char *) = 0;
+ virtual bool NewDoc(PGLOBAL, PCSZ) = 0;
+ virtual void AddComment(PGLOBAL, char *) = 0;
+ virtual PXNODE GetRoot(PGLOBAL) = 0;
+ virtual PXNODE NewRoot(PGLOBAL, char *) = 0;
+ virtual PXNODE NewPnode(PGLOBAL, char * = NULL) = 0;
+ virtual PXATTR NewPattr(PGLOBAL) = 0;
+ virtual PXLIST NewPlist(PGLOBAL) = 0;
+ virtual int DumpDoc(PGLOBAL, char *) = 0;
+ virtual void CloseDoc(PGLOBAL, PFBLOCK) = 0;
+ virtual PFBLOCK LinkXblock(PGLOBAL, MODE, int, char *) = 0;
+
+ protected:
+ // Constructor
+ XMLDOCUMENT(char *nsl, char *nsdf, char *enc);
+
+ // Utility
+ bool MakeNSlist(PGLOBAL g);
+ bool InitZip(PGLOBAL g, PCSZ entry);
+ char *GetMemDoc(PGLOBAL g, char *fn);
+ void CloseZip(void);
+
+ // Members
+#if defined(ZIP_SUPPORT)
+ UNZIPUTL *zip; /* Used for zipped file */
+#else // !ZIP_SUPPORT
+ bool zip; /* Always false */
+#endif // !ZIP_SUPPORT
+ PNS Namespaces; /* To the namespaces */
+ char *Encoding; /* The document encoding */
+ char *Nslist; /* Namespace list */
+ char *DefNs; /* Default namespace */
+}; // end of class XMLDOCUMENT
+
+/******************************************************************/
+/* Declaration of XML node. */
+/******************************************************************/
+class XMLNODE : public BLOCK {
+ public:
+ // Properties
+ virtual char *GetName(PGLOBAL) = 0;
+ virtual int GetType(void) = 0;
+ virtual PXNODE GetNext(PGLOBAL) = 0;
+ virtual PXNODE GetChild(PGLOBAL) = 0;
+ virtual int GetLen(void) {return Len;}
+
+ // Methods
+ virtual RCODE GetContent(PGLOBAL, char *, int) = 0;
+ virtual bool SetContent(PGLOBAL, char *, int) = 0;
+ virtual PXNODE Clone(PGLOBAL, PXNODE) = 0;
+ virtual PXLIST GetChildElements(PGLOBAL, char * = NULL, PXLIST = NULL) = 0;
+ virtual PXLIST SelectNodes(PGLOBAL, char *, PXLIST = NULL) = 0;
+ virtual PXNODE SelectSingleNode(PGLOBAL, char *, PXNODE = NULL) = 0;
+ virtual PXATTR GetAttribute(PGLOBAL, char *, PXATTR = NULL) = 0;
+ virtual PXNODE AddChildNode(PGLOBAL, PCSZ, PXNODE = NULL) = 0;
+ virtual PXATTR AddProperty(PGLOBAL, char *, PXATTR = NULL) = 0;
+ virtual void AddText(PGLOBAL, PCSZ) = 0;
+ virtual void DeleteChild(PGLOBAL, PXNODE) = 0;
+
+ protected:
+ PXNODE NewChild(PXNODE ncp);
+ void Delete(PXNODE dnp);
+ char *BufAlloc(PGLOBAL g, const char *p, int n);
+
+ // Constructor
+ XMLNODE(PXDOC dp);
+
+ // Members
+ PXDOC Doc;
+ PXNODE Next;
+ PXNODE Children;
+ char *Buf;
+ int Len;
+}; // end of class XMLNODE
+
+/******************************************************************/
+/* Declaration of XML node list. */
+/******************************************************************/
+class XMLNODELIST : public BLOCK {
+ public:
+ // Properties
+ virtual int GetLength(void) = 0;
+ virtual PXNODE GetItem(PGLOBAL, int, PXNODE = NULL) = 0;
+ virtual bool DropItem(PGLOBAL, int) = 0;
+
+ protected:
+ // Constructor
+ XMLNODELIST(PXDOC dp) {Doc = dp;}
+
+ // Members
+ PXDOC Doc;
+}; // end of class XMLNODELIST
+
+/******************************************************************/
+/* Declaration of XML attribute. */
+/******************************************************************/
+class XMLATTRIBUTE : public BLOCK {
+ public:
+ // Properties
+ virtual char *GetName(PGLOBAL) = 0;
+ virtual PXATTR GetNext(PGLOBAL) = 0;
+
+ // Methods
+ virtual RCODE GetText(PGLOBAL, char *, int) = 0;
+ virtual bool SetText(PGLOBAL, char *, int) = 0;
+
+ protected:
+ // Constructor
+ XMLATTRIBUTE(PXDOC dp) {Doc = dp;}
+
+ // Members
+ PXDOC Doc;
+}; // end of class XMLATTRIBUTE
+
+
diff --git a/storage/connect/plugutil.cpp b/storage/connect/plugutil.cpp
new file mode 100644
index 00000000..a63eee75
--- /dev/null
+++ b/storage/connect/plugutil.cpp
@@ -0,0 +1,637 @@
+/************** PlugUtil C Program Source Code File (.C) ***************/
+/* */
+/* PROGRAM NAME: PLUGUTIL */
+/* ------------- */
+/* Version 3.1 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 1993-2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are initialization and utility Plug routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* See Readme.C for a list and description of required SYSTEM files. */
+/* */
+/* PLUG.C - Source code */
+/* GLOBAL.H - Global declaration file */
+/* OPTION.H - Option declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* */
+/* OS2.LIB - OS2 libray */
+/* LLIBCE.LIB - Protect mode/standard combined large model C */
+/* library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* */
+/* IBM C Compiler */
+/* IBM Linker */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* */
+/* Include relevant MariaDB header file. */
+/* */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+//#include <windows.h>
+#else
+#if defined(UNIX) || defined(UNIV_LINUX)
+#include <errno.h>
+#include <unistd.h>
+//#define __stdcall
+#else
+#include <dir.h>
+#endif
+#include <stdarg.h>
+#endif
+
+#if defined(WIN)
+#include <alloc.h>
+#endif
+#include <errno.h> /* definitions of ERANGE ENOMEM */
+#if !defined(UNIX) && !defined(UNIV_LINUX)
+#include <direct.h> /* Directory management library */
+#endif
+
+/***********************************************************************/
+/* */
+/* Include application header files */
+/* */
+/* global.h is header containing all global declarations. */
+/* */
+/***********************************************************************/
+#define STORAGE /* Initialize global variables */
+
+#include "osutil.h"
+#include "global.h"
+#include "plgdbsem.h"
+#if defined(NEWMSG)
+#include "rcmsg.h"
+#endif // NEWMSG
+
+#if defined(_WIN32)
+extern HINSTANCE s_hModule; /* Saved module handle */
+#endif // _WIN32
+
+#if defined(XMSG)
+extern char *msg_path;
+char *msglang(void);
+#endif // XMSG
+
+/***********************************************************************/
+/* Local Definitions and static variables */
+/***********************************************************************/
+typedef struct {
+ ushort Segsize;
+ ushort Size;
+} AREASIZE;
+
+ACTIVITY defActivity = { /* Describes activity and language */
+ NULL, /* Points to user work area(s) */
+ "Unknown"}; /* Application name */
+
+#if defined(XMSG) || defined(NEWMSG)
+ static char stmsg[200];
+#endif // XMSG || NEWMSG
+
+#if defined(UNIX) || defined(UNIV_LINUX)
+#include "rcmsg.h"
+#endif // UNIX
+
+/**************************************************************************/
+/* Conditional tracing output function. */
+/**************************************************************************/
+void xtrc(uint x, char const *fmt, ...)
+{
+ if (GetTraceValue() & x) {
+ va_list ap;
+ va_start(ap, fmt);
+
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ } // endif x
+
+} // end of xtrc
+
+/**************************************************************************/
+/* Tracing output function. */
+/**************************************************************************/
+void htrc(char const* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+} // end of htrc
+
+/***********************************************************************/
+/* Plug initialization routine. */
+/* Language points on initial language name and eventual path. */
+/* Return value is the pointer to the Global structure. */
+/***********************************************************************/
+PGLOBAL PlugInit(LPCSTR Language, size_t worksize)
+{
+ PGLOBAL g;
+
+ if (trace(2))
+ htrc("PlugInit: Language='%-.256s'\n",
+ ((!Language) ? "Null" : (char*)Language));
+
+ try {
+ g = new GLOBAL;
+ } catch (...) {
+ fprintf(stderr, MSG(GLOBAL_ERROR), (int)sizeof(GLOBAL));
+ return NULL;
+ } // end try/catch
+
+ g->Sarea = NULL;
+ g->Createas = false;
+ g->Alchecked = 0;
+ g->Mrr = 0;
+ g->Activityp = NULL;
+ g->Xchk = NULL;
+ g->N = 0;
+ g->More = 0;
+ g->Saved_Size = 0;
+ strcpy(g->Message, "");
+
+ /*******************************************************************/
+ /* Allocate the main work segment. */
+ /*******************************************************************/
+ if (worksize && AllocSarea(g, worksize)) {
+ char errmsg[MAX_STR];
+ snprintf(errmsg, sizeof(errmsg) - 1, MSG(WORK_AREA), g->Message);
+ strcpy(g->Message, errmsg);
+ } // endif Sarea
+
+ g->jump_level = -1; /* New setting to allow recursive call of Plug */
+ return(g);
+} /* end of PlugInit */
+
+/***********************************************************************/
+/* PlugExit: Terminate Plug operations. */
+/***********************************************************************/
+PGLOBAL PlugExit(PGLOBAL g)
+{
+ if (g) {
+ PDBUSER dup = PlgGetUser(g);
+
+ if (dup)
+ free(dup);
+
+ FreeSarea(g);
+ delete g;
+ } // endif g
+
+ return NULL;
+} // end of PlugExit
+
+/***********************************************************************/
+/* Remove the file type from a file name. */
+/* Note: this routine is not really implemented for Unix. */
+/***********************************************************************/
+LPSTR PlugRemoveType(LPSTR pBuff, LPCSTR FileName)
+{
+#if defined(_WIN32)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ftype[_MAX_EXT];
+
+ _splitpath(FileName, drive, direc, fname, ftype);
+
+ if (trace(2)) {
+ htrc("after _splitpath: FileName=%-.256s\n", FileName);
+ htrc("drive=%-.256s dir=%-.256s fname=%-.256s ext=%-.256s\n",
+ SVP(drive), direc, fname, ftype);
+ } // endif trace
+
+ _makepath(pBuff, drive, direc, fname, "");
+
+ if (trace(2))
+ htrc("buff='%-.256s'\n", pBuff);
+
+ return pBuff;
+} // end of PlugRemoveType
+
+BOOL PlugIsAbsolutePath(LPCSTR path)
+{
+#if defined(_WIN32)
+ return ((path[0] >= 'a' && path[0] <= 'z') ||
+ (path[0] >= 'A' && path[0] <= 'Z')) && path[1] == ':';
+#else
+ return path[0] == '/';
+#endif
+}
+
+/***********************************************************************/
+/* Set the full path of a file relatively to a given path. */
+/* Note: this routine is not really implemented for Unix. */
+/***********************************************************************/
+LPCSTR PlugSetPath(LPSTR pBuff, LPCSTR prefix, LPCSTR FileName, LPCSTR defpath)
+{
+ char newname[_MAX_PATH];
+ char direc[_MAX_DIR], defdir[_MAX_DIR], tmpdir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ftype[_MAX_EXT];
+#if defined(_WIN32)
+ char drive[_MAX_DRIVE], defdrv[_MAX_DRIVE];
+#else
+ char *drive = NULL, *defdrv = NULL;
+#endif
+
+ if (trace(2))
+ htrc("prefix=%-.256s fn=%-.256s path=%-.256s\n", prefix, FileName, defpath);
+
+ if (!strncmp(FileName, "//", 2) || !strncmp(FileName, "\\\\", 2)) {
+ strcpy(pBuff, FileName); // Remote file
+ return pBuff;
+ } // endif
+
+ if (PlugIsAbsolutePath(FileName))
+ {
+ strcpy(pBuff, FileName); // FileName includes absolute path
+ return pBuff;
+ } // endif
+
+#if !defined(_WIN32)
+ if (*FileName == '~') {
+ if (_fullpath(pBuff, FileName, _MAX_PATH)) {
+ if (trace(2))
+ htrc("pbuff='%-.256s'\n", pBuff);
+
+ return pBuff;
+ } else
+ return FileName; // Error, return unchanged name
+
+ } // endif FileName
+#endif // !_WIN32
+
+ if (prefix && strcmp(prefix, ".") && !PlugIsAbsolutePath(defpath))
+ {
+ char tmp[_MAX_PATH];
+ int len= snprintf(tmp, sizeof(tmp) - 1, "%s%s%s",
+ prefix, defpath, FileName);
+ memcpy(pBuff, tmp, (size_t) len);
+ pBuff[len]= '\0';
+ return pBuff;
+ }
+
+ _splitpath(FileName, drive, direc, fname, ftype);
+
+ if (defpath) {
+ char c = defpath[strlen(defpath) - 1];
+
+ strcpy(tmpdir, defpath);
+
+ if (c != '/' && c != '\\')
+ strcat(tmpdir, "/");
+
+ } else
+ strcpy(tmpdir, "./");
+
+ _splitpath(tmpdir, defdrv, defdir, NULL, NULL);
+
+ if (trace(2)) {
+ htrc("after _splitpath: FileName=%-.256s\n", FileName);
+#if defined(_WIN32)
+ htrc("drive=%-.256s dir=%-.256s fname=%-.256s ext=%-.256s\n", drive, direc, fname, ftype);
+ htrc("defdrv=%-.256s defdir=%-.256s\n", defdrv, defdir);
+#else
+ htrc("dir=%-.256s fname=%-.256s ext=%-.256s\n", direc, fname, ftype);
+#endif
+ } // endif trace
+
+ if (drive && !*drive)
+ strcpy(drive, defdrv);
+
+ switch (*direc) {
+ case '\0':
+ strcpy(direc, defdir);
+ break;
+ case '\\':
+ case '/':
+ break;
+ default:
+ // This supposes that defdir ends with a SLASH
+ strcpy(direc, strcat(defdir, direc));
+ } // endswitch
+
+ _makepath(newname, drive, direc, fname, ftype);
+
+ if (trace(2))
+ htrc("newname='%-.256s'\n", newname);
+
+ if (_fullpath(pBuff, newname, _MAX_PATH)) {
+ if (trace(2))
+ htrc("pbuff='%-.256s'\n", pBuff);
+
+ return pBuff;
+ } else
+ return FileName; // Error, return unchanged name
+
+} // end of PlugSetPath
+
+#if defined(XMSG)
+/***********************************************************************/
+/* PlugGetMessage: get a message from the message file. */
+/***********************************************************************/
+char *PlugReadMessage(PGLOBAL g, int mid, char *m)
+{
+ char msgfile[_MAX_PATH], msgid[32], buff[256];
+ char *msg;
+ FILE *mfile = NULL;
+
+//GetPrivateProfileString("Message", msglang, "Message\\english.msg",
+// msgfile, _MAX_PATH, plgini);
+//strcat(strcat(strcpy(msgfile, msg_path), msglang()), ".msg");
+ strcat(strcpy(buff, msglang()), ".msg");
+ PlugSetPath(msgfile, NULL, buff, msg_path);
+
+ if (!(mfile = fopen(msgfile, "rt"))) {
+ sprintf(stmsg, "Fail to open message file %-.256s", msgfile);
+ goto err;
+ } // endif mfile
+
+ for (;;)
+ if (!fgets(buff, 256, mfile)) {
+ sprintf(stmsg, "Cannot get message %d %-.256s", mid, SVP(m));
+ goto fin;
+ } else
+ if (atoi(buff) == mid)
+ break;
+
+ if (sscanf(buff, " %*d %.31s \"%.255[^\"]", msgid, stmsg) < 2) {
+ // Old message file
+ if (!sscanf(buff, " %*d \"%.255[^\"]", stmsg)) {
+ sprintf(stmsg, "Bad message file for %d %-.256s", mid, SVP(m));
+ goto fin;
+ } else
+ m = NULL;
+
+ } // endif sscanf
+
+ if (m && strcmp(m, msgid)) {
+ // Message file is out of date
+ strcpy(stmsg, m);
+ goto fin;
+ } // endif m
+
+ fin:
+ fclose(mfile);
+
+ err:
+ if (g) {
+ // Called by STEP
+ msg = PlugDup(g, stmsg);
+ } else // Called by MSG or PlgGetErrorMsg
+ msg = stmsg;
+
+ return msg;
+} // end of PlugReadMessage
+
+#elif defined(NEWMSG)
+/***********************************************************************/
+/* PlugGetMessage: get a message from the resource string table. */
+/***********************************************************************/
+char *PlugGetMessage(PGLOBAL g, int mid)
+{
+ char *msg;
+
+#if 0 // was !defined(UNIX) && !defined(UNIV_LINUX)
+ int n = LoadString(s_hModule, (uint)mid, (LPTSTR)stmsg, 200);
+
+ if (n == 0) {
+ DWORD rc = GetLastError();
+ msg = (char*)PlugSubAlloc(g, NULL, 512); // Extend buf allocation
+ n = sprintf(msg, "Message %d, rc=%d: ", mid, rc);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)(msg + n), 512 - n, NULL);
+ return msg;
+ } // endif n
+
+#else // ALL
+ if (!GetRcString(mid, stmsg, 200))
+ sprintf(stmsg, "Message %d not found", mid);
+#endif // ALL
+
+ if (g) {
+ // Called by STEP
+ msg = PlugDup(g, stmsg);
+ } else // Called by MSG or PlgGetErrorMsg
+ msg = stmsg;
+
+ return msg;
+} // end of PlugGetMessage
+#endif // NEWMSG
+
+#if defined(_WIN32)
+/***********************************************************************/
+/* Return the line length of the console screen buffer. */
+/***********************************************************************/
+short GetLineLength(PGLOBAL g)
+{
+ CONSOLE_SCREEN_BUFFER_INFO coninfo;
+ HANDLE hcons = GetStdHandle(STD_OUTPUT_HANDLE);
+ BOOL b = GetConsoleScreenBufferInfo(hcons, &coninfo);
+
+ return (b) ? coninfo.dwSize.X : 0;
+} // end of GetLineLength
+#endif // _WIN32
+
+/***********************************************************************/
+/* Program for memory allocation of work and language areas. */
+/***********************************************************************/
+bool AllocSarea(PGLOBAL g, size_t size)
+{
+ /*********************************************************************/
+ /* This is the allocation routine for the WIN32/UNIX/AIX version. */
+ /*********************************************************************/
+#if defined(_WIN32)
+ if (size >= 1048576) // 1M
+ g->Sarea = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ else
+#endif
+ g->Sarea = malloc(size);
+
+ if (!g->Sarea) {
+ sprintf(g->Message, MSG(MALLOC_ERROR), "malloc");
+ g->Sarea_Size = 0;
+ } else {
+ g->Sarea_Size = size;
+ PlugSubSet(g->Sarea, size);
+ } // endif Sarea
+
+#if defined(DEVELOPMENT)
+ if (true) {
+#else
+ if (trace(8)) {
+#endif
+ if (g->Sarea) {
+ htrc("Work area of %zd allocated at %p\n", size, g->Sarea);
+ } else
+ htrc("SareaAlloc: %-.256s\n", g->Message);
+
+ } // endif trace
+
+ return (!g->Sarea);
+} // end of AllocSarea
+
+/***********************************************************************/
+/* Program for memory freeing the work area. */
+/***********************************************************************/
+void FreeSarea(PGLOBAL g)
+{
+ if (g->Sarea) {
+#if defined(_WIN32)
+ if (g->Sarea_Size >= 1048576) // 1M
+ VirtualFree(g->Sarea, 0, MEM_RELEASE);
+ else
+#endif
+ free(g->Sarea);
+
+#if defined(DEVELOPMENT)
+ if (true)
+#else
+ if (trace(8))
+#endif
+ htrc("Freeing Sarea at %p size = %zd\n", g->Sarea, g->Sarea_Size);
+
+ g->Sarea = NULL;
+ g->Sarea_Size = 0;
+ } // endif Sarea
+
+ return;
+} // end of FreeSarea
+
+/***********************************************************************/
+/* Program for SubSet initialization of memory pools. */
+/* Here there should be some verification done such as validity of */
+/* the address and size not larger than memory size. */
+/***********************************************************************/
+BOOL PlugSubSet(void *memp, size_t size)
+{
+ PPOOLHEADER pph = (PPOOLHEADER)memp;
+
+ pph->To_Free = (size_t)sizeof(POOLHEADER);
+ pph->FreeBlk = size - pph->To_Free;
+ return FALSE;
+} /* end of PlugSubSet */
+
+/***********************************************************************/
+/* Use it to export a function that do throwing. */
+/***********************************************************************/
+static void *DoThrow(int n)
+{
+ throw n;
+} /* end of DoThrow */
+
+/***********************************************************************/
+/* Program for sub-allocating one item in a storage area. */
+/* The simple way things are done here is based on the fact */
+/* that no freeing of suballocated blocks is permitted in CONNECT. */
+/***********************************************************************/
+void *PlugSubAlloc(PGLOBAL g, void *memp, size_t size)
+{
+ PPOOLHEADER pph; /* Points on area header. */
+
+ if (!memp)
+ /*******************************************************************/
+ /* Allocation is to be done in the Sarea. */
+ /*******************************************************************/
+ memp = g->Sarea;
+
+ size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */
+ pph = (PPOOLHEADER)memp;
+
+ if (trace(16))
+ htrc("SubAlloc in %p size=%zd used=%zd free=%zd\n",
+ memp, size, pph->To_Free, pph->FreeBlk);
+
+ if (size > pph->FreeBlk) { /* Not enough memory left in pool */
+ PCSZ pname = "Work";
+
+ sprintf(g->Message,
+ "Not enough memory in %-.256s area for request of %zu (used=%zu free=%zu)",
+ pname, size, pph->To_Free, pph->FreeBlk);
+
+ if (trace(1))
+ htrc("PlugSubAlloc: %-.256s\n", g->Message);
+
+ DoThrow(1234);
+ } /* endif size OS32 code */
+
+ /*********************************************************************/
+ /* Do the suballocation the simplest way. */
+ /*********************************************************************/
+ memp = MakePtr(memp, pph->To_Free); /* Points to suballocated block */
+ pph->To_Free += size; /* New offset of pool free block */
+ pph->FreeBlk -= size; /* New size of pool free block */
+
+ if (trace(16))
+ htrc("Done memp=%p used=%zd free=%zd\n",
+ memp, pph->To_Free, pph->FreeBlk);
+
+ return (memp);
+} /* end of PlugSubAlloc */
+
+/***********************************************************************/
+/* Program for sub-allocating and copying a string in a storage area. */
+/***********************************************************************/
+char *PlugDup(PGLOBAL g, const char *str)
+{
+ if (str) {
+ char *sm = (char*)PlugSubAlloc(g, NULL, strlen(str) + 1);
+
+ strcpy(sm, str);
+ return sm;
+ } else
+ return NULL;
+
+} // end of PlugDup
+
+/*************************************************************************/
+/* This routine makes a pointer from an offset to a memory pointer. */
+/*************************************************************************/
+void* MakePtr(void* memp, size_t offset)
+{
+ // return ((offset == 0) ? NULL : &((char*)memp)[offset]);
+ return (!offset) ? NULL : (char *)memp + offset;
+} /* end of MakePtr */
+
+/*************************************************************************/
+/* This routine makes an offset from a pointer new format. */
+/*************************************************************************/
+size_t MakeOff(void* memp, void* ptr)
+{
+ if (ptr) {
+#if defined(_DEBUG) || defined(DEVELOPMENT)
+ if (ptr <= memp) {
+ fprintf(stderr, "ptr %p <= memp %p", ptr, memp);
+ DoThrow(999);
+ } // endif ptr
+#endif // _DEBUG || DEVELOPMENT
+ return (size_t)(((char*)ptr) - ((char*)memp));
+ } else
+ return 0;
+
+} /* end of MakeOff */
+
+/*---------------------- End of PLUGUTIL program ------------------------*/
diff --git a/storage/connect/preparse.h b/storage/connect/preparse.h
new file mode 100644
index 00000000..3db7a2af
--- /dev/null
+++ b/storage/connect/preparse.h
@@ -0,0 +1,34 @@
+#if !defined(PREPARSE_DEFINED)
+#define PREPARSE_DEFINED
+
+#include "checklvl.h"
+
+/***********************************************************************/
+/* Struct of variables used by the date format pre-parser. */
+/***********************************************************************/
+typedef struct _datpar {
+ const char *Format; // Points to format to decode
+ const char *Curp; // Points to current parsing position
+ char *InFmt; // Start of input format
+ char *OutFmt; // Start of output format
+ int Index[8]; // Indexes of date values
+ int Num; // Number of values to retrieve
+ int Flag; // 1: Input, 2: Output, 4: no output blank
+ int Outsize; // Size of output buffers
+ } DATPAR, *PDTP;
+
+/***********************************************************************/
+/* Preparsers used by SQL language. */
+/***********************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int fmdflex(PDTP pp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // PREPARSE_DEFINED
+
diff --git a/storage/connect/rcmsg.c b/storage/connect/rcmsg.c
new file mode 100644
index 00000000..4cd443d8
--- /dev/null
+++ b/storage/connect/rcmsg.c
@@ -0,0 +1,69 @@
+/**************** RCMsg C Program Source Code File (.C) ****************/
+/* PROGRAM NAME: RCMSG */
+/* ------------- */
+/* Version 1.3 */
+/* */
+/* COPYRIGHT */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND: 2005 - 2014 */
+/* */
+/* WHAT THIS PROGRAM DOES */
+/* ----------------------- */
+/* This program simulates LoadString. */
+/* */
+/***********************************************************************/
+#if !defined(XMSG)
+#include <stdio.h>
+#include <string.h>
+#include "resource.h"
+#include "rcmsg.h"
+#if defined(NEWMSG)
+#include "msgid.h"
+#endif // NEWMSG
+
+#if !defined(_WIN32)
+#define stricmp strcasecmp
+#endif // !_WIN32
+
+char *msglang(void);
+
+const char *GetMsgid(int id)
+ {
+ const char *p = NULL;
+
+ // This conditional until a real fix is found for MDEV-7304
+#if defined(FRENCH)
+ if (!stricmp(msglang(), "french"))
+ switch (id) {
+#include "frids.h"
+#if defined(NEWMSG)
+#include "frcas.h"
+#endif // NEWMSG
+ } // endswitch(id)
+
+ else // English
+#endif // FRENCH
+ switch (id) {
+#include "enids.h"
+#if defined(NEWMSG)
+#include "encas.h"
+#endif // NEWMSG
+ } // endswitch(id)
+
+ return p;
+ } // end of GetMsgid
+
+int GetRcString(int id, char *buf, int bufsize)
+ {
+ const char *p = NULL;
+ char msg[32];
+
+ if (!(p = GetMsgid(id))) {
+ sprintf(msg, "ID=%d unknown", id);
+ p = msg;
+ } // endif p
+
+ return sprintf(buf, "%.*s", bufsize-1, p);
+ } // end of GetRcString
+
+#endif // !XMSG
diff --git a/storage/connect/rcmsg.h b/storage/connect/rcmsg.h
new file mode 100644
index 00000000..499ca3b2
--- /dev/null
+++ b/storage/connect/rcmsg.h
@@ -0,0 +1,15 @@
+#ifndef __RCMSG_H__
+#define __RCMSG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *GetMsgid(int id);
+int GetRcString(int id, char *buf, int bufsize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RCMSG_H__ */
diff --git a/storage/connect/reldef.cpp b/storage/connect/reldef.cpp
new file mode 100644
index 00000000..39761fc2
--- /dev/null
+++ b/storage/connect/reldef.cpp
@@ -0,0 +1,949 @@
+/************* RelDef CPP Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: RELDEF */
+/* ------------- */
+/* Version 1.7 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2004-2019 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the DB definition related routines. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <sqlext.h>
+#else
+//#include <dlfcn.h> // dlopen(), dlclose(), dlsym() ...
+#include "osutil.h"
+//#include "sqlext.h"
+#endif
+#include "handler.h"
+
+/***********************************************************************/
+/* Include application header files */
+/* */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing DB application declarations. */
+/* catalog.h is header containing DB description declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "reldef.h"
+#include "colblk.h"
+#include "tabcol.h"
+#include "filamap.h"
+#include "filamfix.h"
+#if defined(VCT_SUPPORT)
+#include "filamvct.h"
+#endif // VCT_SUPPORT
+#if defined(GZ_SUPPORT)
+#include "filamgz.h"
+#endif // GZ_SUPPORT
+#include "tabdos.h"
+#include "valblk.h"
+#include "tabmul.h"
+#include "ha_connect.h"
+#include "mycat.h"
+
+#if !defined(_WIN32)
+extern handlerton *connect_hton;
+#endif // !_WIN32
+
+/***********************************************************************/
+/* External function. */
+/***********************************************************************/
+USETEMP UseTemp(void);
+char *GetPluginDir(void);
+PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char* tab, char* db, bool info);
+
+/***********************************************************************/
+/* OEMColumns: Get table column info for an OEM table. */
+/***********************************************************************/
+PQRYRES OEMColumns(PGLOBAL g, PTOS topt, char* tab, char* db, bool info)
+{
+ typedef PQRYRES(__stdcall* XCOLDEF) (PGLOBAL, void*, char*, char*, bool);
+ const char* module, * subtype;
+ char c, soname[_MAX_PATH], getname[40] = "Col";
+#if defined(_WIN32)
+ HANDLE hdll; /* Handle to the external DLL */
+#else // !_WIN32
+ void* hdll; /* Handle for the loaded shared library */
+#endif // !_WIN32
+ XCOLDEF coldef = NULL;
+ PQRYRES qrp = NULL;
+
+ module = topt->module;
+ subtype = topt->subtype;
+
+ if (!module || !subtype)
+ return NULL;
+
+ /*********************************************************************/
+ /* Ensure that the .dll doesn't have a path. */
+ /* This is done to ensure that only approved dll from the system */
+ /* directories are used (to make this even remotely secure). */
+ /*********************************************************************/
+ if (check_valid_path(module, strlen(module))) {
+ strcpy(g->Message, "Module cannot contain a path");
+ return NULL;
+ } else
+ PlugSetPath(soname, module, GetPluginDir());
+
+ // The exported name is always in uppercase
+ for (int i = 0; ; i++) {
+ c = subtype[i];
+ getname[i + 3] = toupper(c);
+ if (!c) break;
+ } // endfor i
+
+#if defined(_WIN32)
+ // Load the Dll implementing the table
+ if (!(hdll = LoadLibrary(soname))) {
+ char buf[256];
+ DWORD rc = GetLastError();
+
+ sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, soname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ strcat(strcat(g->Message, ": "), buf);
+ return NULL;
+ } // endif hDll
+
+// Get the function returning an instance of the external DEF class
+ if (!(coldef = (XCOLDEF)GetProcAddress((HINSTANCE)hdll, getname))) {
+ sprintf(g->Message, MSG(PROCADD_ERROR), GetLastError(), getname);
+ FreeLibrary((HMODULE)hdll);
+ return NULL;
+ } // endif coldef
+#else // !_WIN32
+ const char* error = NULL;
+
+ // Load the desired shared library
+ if (!(hdll = dlopen(soname, RTLD_LAZY))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error));
+ return NULL;
+ } // endif Hdll
+
+// Get the function returning an instance of the external DEF class
+ if (!(coldef = (XCOLDEF)dlsym(hdll, getname))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(GET_FUNC_ERR), getname, SVP(error));
+ dlclose(hdll);
+ return NULL;
+ } // endif coldef
+#endif // !_WIN32
+
+ // Just in case the external Get function does not set error messages
+ sprintf(g->Message, "Error getting column info from %s", subtype);
+
+ // Get the table column definition
+ qrp = coldef(g, topt, tab, db, info);
+
+#if defined(_WIN32)
+ FreeLibrary((HMODULE)hdll);
+#else // !_WIN32
+ dlclose(hdll);
+#endif // !_WIN32
+
+ return qrp;
+} // end of OEMColumns
+
+/* --------------------------- Class RELDEF -------------------------- */
+
+/***********************************************************************/
+/* RELDEF Constructor. */
+/***********************************************************************/
+RELDEF::RELDEF(void)
+ {
+ Next = NULL;
+ To_Cols = NULL;
+ Name = NULL;
+ Database = NULL;
+ Cat = NULL;
+ Hc = NULL;
+ } // end of RELDEF constructor
+
+/***********************************************************************/
+/* This function return a pointer to the Table Option Struct. */
+/***********************************************************************/
+PTOS RELDEF::GetTopt(void)
+ {
+ return Hc->GetTableOptionStruct();
+ } // end of GetTopt
+
+/***********************************************************************/
+/* This function sets an integer table information. */
+/***********************************************************************/
+bool RELDEF::SetIntCatInfo(PCSZ what, int n)
+ {
+ return Hc->SetIntegerOption(what, n);
+ } // end of SetIntCatInfo
+
+/***********************************************************************/
+/* This function returns integer table information. */
+/***********************************************************************/
+int RELDEF::GetIntCatInfo(PCSZ what, int idef)
+ {
+ int n= Hc->GetIntegerOption(what);
+
+ return (n == NO_IVAL) ? idef : n;
+ } // end of GetIntCatInfo
+
+/***********************************************************************/
+/* This function returns Boolean table information. */
+/***********************************************************************/
+bool RELDEF::GetBoolCatInfo(PCSZ what, bool bdef)
+ {
+ bool b= Hc->GetBooleanOption(what, bdef);
+
+ return b;
+ } // end of GetBoolCatInfo
+
+/***********************************************************************/
+/* This function returns size catalog information. */
+/***********************************************************************/
+int RELDEF::GetSizeCatInfo(PCSZ what, PCSZ sdef)
+ {
+ char c;
+ PCSZ s;
+ int i, n= 0;
+
+ if (!(s= Hc->GetStringOption(what)))
+ s= sdef;
+
+ if ((i= sscanf(s, " %d %c ", &n, &c)) == 2)
+ switch (toupper(c)) {
+ case 'M':
+ n *= 1024;
+ // fall through
+ case 'K':
+ n *= 1024;
+ } // endswitch c
+
+ return n;
+} // end of GetSizeCatInfo
+
+/***********************************************************************/
+/* This function sets char table information in buf. */
+/***********************************************************************/
+int RELDEF::GetCharCatInfo(PCSZ what, PCSZ sdef, char *buf, int size)
+ {
+ PCSZ s= Hc->GetStringOption(what);
+
+ strncpy(buf, ((s) ? s : sdef), size);
+ return size;
+ } // end of GetCharCatInfo
+
+/***********************************************************************/
+/* To be used by any TDB's. */
+/***********************************************************************/
+bool RELDEF::Partitioned(void)
+ {
+ return Hc->IsPartitioned();
+ } // end of Partitioned
+
+/***********************************************************************/
+/* This function returns string table information. */
+/* Default parameter is "*" to get the handler default. */
+/***********************************************************************/
+char *RELDEF::GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef)
+ {
+ char *sval = NULL;
+ PCSZ name, s= Hc->GetStringOption(what, sdef);
+
+ if (s) {
+ if (!Hc->IsPartitioned() ||
+ (stricmp(what, "filename") && stricmp(what, "tabname")
+ && stricmp(what, "connect")))
+ sval= PlugDup(g, s);
+ else
+ sval= (char*)s;
+
+ } else if (!stricmp(what, "filename")) {
+ // Return default file name
+ PCSZ ftype= Hc->GetStringOption("Type", "*");
+ int i, n;
+
+ if (IsFileType(GetTypeID(ftype))) {
+ name= Hc->GetPartName();
+ sval= (char*)PlugSubAlloc(g, NULL, strlen(name) + 12);
+ strcat(strcpy(sval, name), ".");
+ n= strlen(sval);
+
+ // Fold ftype to lower case
+ for (i= 0; i < 12; i++)
+ if (!ftype[i]) {
+ sval[n+i]= 0;
+ break;
+ } else
+ sval[n+i]= tolower(ftype[i]);
+
+ } // endif FileType
+
+ } // endif s
+
+ return sval;
+ } // end of GetStringCatInfo
+
+/* --------------------------- Class TABDEF -------------------------- */
+
+/***********************************************************************/
+/* TABDEF Constructor. */
+/***********************************************************************/
+TABDEF::TABDEF(void)
+ {
+ Schema = NULL;
+ Desc = NULL;
+ Recfm = RECFM_DFLT;
+ Catfunc = FNC_NO;
+ Card = 0;
+ Elemt = 0;
+ Sort = 0;
+ Multiple = 0;
+ Degree = 0;
+ Pseudo = 0;
+ Read_Only = false;
+ m_data_charset = NULL;
+ csname = NULL;
+ } // end of TABDEF constructor
+
+/***********************************************************************/
+/* Return the table format. */
+/***********************************************************************/
+RECFM TABDEF::GetTableFormat(const char* type)
+{
+ RECFM recfm = Recfm;
+
+ if (Catfunc != FNC_NO)
+ recfm = RECFM_NAF;
+ else if (recfm == RECFM_DFLT)
+ // Default format depends on the table type
+ switch (GetTypeID(type)) {
+ case TAB_DOS: recfm = RECFM_VAR; break;
+ case TAB_CSV: recfm = RECFM_CSV; break;
+ case TAB_FMT: recfm = RECFM_FMT; break;
+ case TAB_FIX: recfm = RECFM_FIX; break;
+ case TAB_BIN: recfm = RECFM_BIN; break;
+ case TAB_VEC: recfm = RECFM_VCT; break;
+ case TAB_DBF: recfm = RECFM_DBF; break;
+ case TAB_XML: recfm = RECFM_XML; break;
+ case TAB_DIR: recfm = RECFM_DIR; break;
+ default: recfm = RECFM_NAF; break;
+ } // endswitch type
+
+ return recfm;
+} // end of GetTableFormat
+
+/***********************************************************************/
+/* Define: initialize the table definition block from XDB file. */
+/***********************************************************************/
+bool TABDEF::Define(PGLOBAL g, PCATLG cat,
+ LPCSTR name, LPCSTR schema, LPCSTR am)
+{
+ Hc = ((MYCAT*)cat)->GetHandler();
+ Name = (PSZ)name;
+ Schema = (PSZ)Hc->GetDBName(schema);
+ Cat = cat;
+ Catfunc = GetFuncID(GetStringCatInfo(g, "Catfunc", NULL));
+ Elemt = GetIntCatInfo("Elements", 0);
+ Multiple = GetIntCatInfo("Multiple", 0);
+ Degree = GetIntCatInfo("Degree", 0);
+ Read_Only = GetBoolCatInfo("ReadOnly", false);
+ const char *data_charset_name= GetStringCatInfo(g, "Data_charset", NULL);
+ m_data_charset= data_charset_name ?
+ get_charset_by_csname(data_charset_name, MY_CS_PRIMARY, 0):
+ NULL;
+ csname = GetStringCatInfo(g, "Table_charset", NULL);
+
+ // Do the definition of AM specific fields
+ if (DefineAM(g, am, 0))
+ return true;
+
+ // Get The column definitions
+ if (stricmp(am, "OEM") && GetColCatInfo(g) < 0)
+ return true;
+
+ Hc->tshp = NULL; // TO BE CHECKED
+ return false;
+} // end of Define
+
+/***********************************************************************/
+/* This function returns the database data path. */
+/***********************************************************************/
+PCSZ TABDEF::GetPath(void)
+ {
+ return (Database) ? Database : (Hc) ? Hc->GetDataPath() : NULL;
+ } // end of GetPath
+
+/***********************************************************************/
+/* This function returns column table information. */
+/***********************************************************************/
+int TABDEF::GetColCatInfo(PGLOBAL g)
+ {
+ char *type = GetStringCatInfo(g, "Type", "*");
+ char c, fty, eds;
+ int i, n, loff, poff, nof, nlg;
+ void *field = NULL;
+ RECFM trf;
+ PCOLDEF cdp, lcdp = NULL, tocols= NULL;
+ PCOLINFO pcf= (PCOLINFO)PlugSubAlloc(g, NULL, sizeof(COLINFO));
+
+ memset(pcf, 0, sizeof(COLINFO));
+
+ // Get the table format
+ trf = GetTableFormat(type);
+
+ // Take care of the column definitions
+ i= poff= nof= nlg= 0;
+
+#if defined(_WIN32)
+ // Offsets of HTML and DIR tables start from 0, DBF at 1
+ loff= (trf == RECFM_DBF) ? 1 : (trf == RECFM_XML || trf == RECFM_DIR) ? -1 : 0;
+#else // !_WIN32
+ // Offsets of HTML tables start from 0, DIR and DBF at 1
+ loff = (trf == RECFM_DBF || trf == RECFM_DIR) ? 1 : (trf == RECFM_XML) ? -1 : 0;
+#endif // !_WIN32
+
+ while (true) {
+ // Default Offset depends on table format
+ switch (trf ) {
+ case RECFM_VAR:
+ case RECFM_FIX:
+ case RECFM_BIN:
+ case RECFM_VCT:
+ case RECFM_DBF:
+ poff= loff + nof; // Default next offset
+ nlg= MY_MAX(nlg, poff); // Default lrecl
+ break;
+ case RECFM_CSV:
+ case RECFM_FMT:
+ nlg+= nof;
+ /* falls through */
+ case RECFM_DIR:
+ case RECFM_XML:
+ poff= loff + (pcf->Flags & U_VIRTUAL ? 0 : 1);
+ break;
+ //case RECFM_INI:
+ //case RECFM_MAC:
+ //case RECFM_TBL:
+ //case RECFM_XCL:
+ //case RECFM_OCCUR:
+ //case RECFM_PRX:
+ case RECFM_OEM:
+ poff = 0; // Offset represents an independant flag
+ break;
+ default: // PLG ODBC JDBC MYSQL WMI...
+ poff = 0; // NA
+ break;
+ } // endswitch trf
+
+// do {
+ field= Hc->GetColumnOption(g, field, pcf);
+// } while (field && (*pcf->Name =='*' /*|| pcf->Flags & U_VIRTUAL*/));
+
+ if (trf == RECFM_DBF && pcf->Type == TYPE_DATE && !pcf->Datefmt) {
+ // DBF date format defaults to 'YYYMMDD'
+ pcf->Datefmt= "YYYYMMDD";
+ pcf->Length= 8;
+ } // endif trf
+
+ if (!field)
+ break;
+
+ // Allocate the column description block
+ cdp= new(g) COLDEF;
+
+ if ((nof= cdp->Define(g, NULL, pcf, poff)) < 0)
+ return -1; // Error, probably unhandled type
+ else
+ loff= cdp->GetOffset();
+
+ switch (trf ) {
+ case RECFM_VCT:
+ cdp->SetOffset(0); // Not to have shift
+ /* falls through */
+ case RECFM_BIN:
+ // BIN/VEC are packed by default
+ if (nof) {
+ // Field width is the internal representation width
+ // that can also depend on the column format
+ fty = cdp->Decode ? 'C' : 'X';
+ eds = 0;
+ n = 0;
+
+ if (cdp->Fmt && !cdp->Decode) {
+ for (i = 0; cdp->Fmt[i]; i++) {
+ c = toupper(cdp->Fmt[i]);
+
+ if (isdigit(c))
+ n = (n * 10 + (c - '0'));
+ else if (c == 'L' || c == 'B' || c == 'H')
+ eds = c;
+ else
+ fty = c;
+
+ } // endfor i
+
+ } // endif Fmt
+
+ if (n)
+ nof = n;
+ else switch (fty) {
+ case 'X':
+ if (eds && IsTypeChar(cdp->Buf_Type))
+ nof = sizeof(longlong);
+ else
+ nof= cdp->Clen;
+
+ break;
+ case 'C': break;
+ case 'R':
+ case 'F': nof = sizeof(float); break;
+ case 'I': nof = sizeof(int); break;
+ case 'D': nof = sizeof(double); break;
+ case 'S': nof = sizeof(short); break;
+ case 'T': nof = sizeof(char); break;
+ case 'G': nof = sizeof(longlong); break;
+ default: /* Wrong format */
+ sprintf(g->Message, "Invalid format %c", fty);
+ return -1;
+ } // endswitch fty
+
+ } // endif nof
+
+ default:
+ break;
+ } // endswitch trf
+
+ if (lcdp)
+ lcdp->SetNext(cdp);
+ else
+ tocols= cdp;
+
+ lcdp= cdp;
+ i++;
+ } // endwhile
+
+ // Degree is the the number of defined columns (informational)
+ if (i != GetDegree())
+ SetDegree(i);
+
+ if (GetDefType() == TYPE_AM_DOS) {
+ int ending, recln= 0;
+
+ ending = Hc->GetIntegerOption("Ending");
+
+ // Calculate the default record size
+ switch (trf ) {
+ case RECFM_FIX:
+ case RECFM_BIN:
+ recln= nlg + ending; // + length of line ending
+ break;
+ case RECFM_VCT:
+ recln= nlg;
+
+// if ((k= (pak < 0) ? 8 : pak) > 1)
+ // See above for detailed comment
+ // Round up lrecl to multiple of 8 or pak
+// recln= ((recln + k - 1) / k) * k;
+
+ break;
+ case RECFM_VAR:
+ case RECFM_DBF:
+ recln= nlg;
+ break;
+ case RECFM_CSV:
+ case RECFM_FMT:
+ // The number of separators (assuming an extra one can exist)
+// recln= poff * ((qotd) ? 3 : 1); to be investigated
+ recln= nlg + poff * 3; // To be safe
+ default:
+ break;
+ } // endswitch trf
+
+ // lrecl must be at least recln to avoid buffer overflow
+ if (trace(1))
+ htrc("Lrecl: Calculated=%d defined=%d\n",
+ recln, Hc->GetIntegerOption("Lrecl"));
+
+ recln = MY_MAX(recln, Hc->GetIntegerOption("Lrecl"));
+ Hc->SetIntegerOption("Lrecl", recln);
+ ((PDOSDEF)this)->SetLrecl(recln);
+
+ if (trace(1))
+ htrc("Lrecl set to %d\n", recln);
+
+ } // endif TYPE
+
+ // Attach the column definition to the tabdef
+ SetCols(tocols);
+ return poff;
+ } // end of GetColCatInfo
+
+/***********************************************************************/
+/* SetIndexInfo: retrieve index description from the table structure. */
+/***********************************************************************/
+void TABDEF::SetIndexInfo(void)
+ {
+ // Attach new index(es)
+ SetIndx(Hc->GetIndexInfo());
+ } // end of SetIndexInfo
+
+/* --------------------------- Class OEMDEF -------------------------- */
+
+/***********************************************************************/
+/* GetXdef: get the external TABDEF from OEM module. */
+/***********************************************************************/
+PTABDEF OEMDEF::GetXdef(PGLOBAL g)
+ {
+ typedef PTABDEF (__stdcall *XGETDEF) (PGLOBAL, void *);
+ char c, soname[_MAX_PATH], getname[40] = "Get";
+ PTABDEF xdefp;
+ XGETDEF getdef = NULL;
+ PCATLG cat = Cat;
+
+ /*********************************************************************/
+ /* Ensure that the module name doesn't have a path. */
+ /* This is done to ensure that only approved libs from the system */
+ /* directories are used (to make this even remotely secure). */
+ /*********************************************************************/
+ if (check_valid_path(Module, strlen(Module))) {
+ strcpy(g->Message, "Module cannot contain a path");
+ return NULL;
+ } else
+// PlugSetPath(soname, Module, GetPluginDir()); // Crashes on Fedora
+ strncat(strcpy(soname, GetPluginDir()), Module,
+ sizeof(soname) - strlen(soname) - 1);
+
+#if defined(_WIN32)
+ // Is the DLL already loaded?
+ if (!Hdll && !(Hdll = GetModuleHandle(soname)))
+ // No, load the Dll implementing the function
+ if (!(Hdll = LoadLibrary(soname))) {
+ char buf[256];
+ DWORD rc = GetLastError();
+
+ sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, soname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ strcat(strcat(g->Message, ": "), buf);
+ return NULL;
+ } // endif hDll
+
+ // The exported name is always in uppercase
+ for (int i = 0; ; i++) {
+ c = Subtype[i];
+ getname[i + 3] = toupper(c);
+ if (!c) break;
+ } // endfor i
+
+ // Get the function returning an instance of the external DEF class
+ if (!(getdef = (XGETDEF)GetProcAddress((HINSTANCE)Hdll, getname))) {
+ char buf[256];
+ DWORD rc = GetLastError();
+
+ sprintf(g->Message, MSG(PROCADD_ERROR), rc, getname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ strcat(strcat(g->Message, ": "), buf);
+ FreeLibrary((HMODULE)Hdll);
+ return NULL;
+ } // endif getdef
+#else // !_WIN32
+ const char *error = NULL;
+
+#if 0 // Don't know what all this stuff does
+ Dl_info dl_info;
+
+ // The OEM lib must retrieve exported CONNECT variables
+ if (dladdr(&connect_hton, &dl_info)) {
+ if (dlopen(dl_info.dli_fname, RTLD_NOLOAD | RTLD_NOW | RTLD_GLOBAL) == 0) {
+ error = dlerror();
+ sprintf(g->Message, "dlopen failed: %s, OEM not supported", SVP(error));
+ return NULL;
+ } // endif dlopen
+
+ } else {
+ error = dlerror();
+ sprintf(g->Message, "dladdr failed: %s, OEM not supported", SVP(error));
+ return NULL;
+ } // endif dladdr
+#endif // 0
+
+ // Load the desired shared library
+ if (!Hdll && !(Hdll = dlopen(soname, RTLD_LAZY))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error));
+ return NULL;
+ } // endif Hdll
+
+ // The exported name is always in uppercase
+ for (int i = 0; ; i++) {
+ c = Subtype[i];
+ getname[i + 3] = toupper(c);
+ if (!c) break;
+ } // endfor i
+
+ // Get the function returning an instance of the external DEF class
+ if (!(getdef = (XGETDEF)dlsym(Hdll, getname))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(GET_FUNC_ERR), getname, SVP(error));
+ dlclose(Hdll);
+ return NULL;
+ } // endif getdef
+#endif // !_WIN32
+
+ // Just in case the external Get function does not set error messages
+ sprintf(g->Message, MSG(DEF_ALLOC_ERROR), Subtype);
+
+ // Get the table definition block
+ if (!(xdefp = getdef(g, NULL)))
+ return NULL;
+
+ // Have the external class do its complete definition
+ if (!cat->Cbuf) {
+ // Suballocate a temporary buffer for the entire column section
+ cat->Cblen = GetSizeCatInfo("Colsize", "8K");
+ cat->Cbuf = (char*)PlugSubAlloc(g, NULL, cat->Cblen);
+ } // endif Cbuf
+
+ // Ok, return external block
+ return xdefp;
+ } // end of GetXdef
+
+#if 0
+/***********************************************************************/
+/* DeleteTableFile: Delete an OEM table file if applicable. */
+/***********************************************************************/
+bool OEMDEF::DeleteTableFile(PGLOBAL g)
+ {
+ if (!Pxdef)
+ Pxdef = GetXdef(g);
+
+ return (Pxdef) ? Pxdef->DeleteTableFile(g) : true;
+ } // end of DeleteTableFile
+#endif // 0
+
+/***********************************************************************/
+/* Define: initialize the table definition block from XDB file. */
+/***********************************************************************/
+bool OEMDEF::DefineAM(PGLOBAL g, LPCSTR, int)
+ {
+ Module = GetStringCatInfo(g, "Module", "");
+ Subtype = GetStringCatInfo(g, "Subtype", Module);
+
+ if (!*Module)
+ Module = Subtype;
+
+ char *desc = (char*)PlugSubAlloc(g, NULL, strlen(Module)
+ + strlen(Subtype) + 3);
+ sprintf(desc, "%s(%s)", Module, Subtype);
+ Desc = desc;
+
+ // If define block not here yet, get it now
+ if (!Pxdef && !(Pxdef = GetXdef(g)))
+ return true; // Error
+
+ // Here "OEM" should be replace by a more useful value
+ return Pxdef->Define(g, Cat, Name, Schema, Subtype);
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB OEMDEF::GetTable(PGLOBAL g, MODE mode)
+ {
+ PTDB tdbp = NULL;
+
+ // If define block not here yet, get it now
+ if (!Pxdef && !(Pxdef = GetXdef(g)))
+ return NULL; // Error
+
+ /*********************************************************************/
+ /* Allocate a TDB of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*********************************************************************/
+ if (!(tdbp = Pxdef->GetTable(g, mode)))
+ return NULL;
+ else if (Multiple && tdbp->GetFtype() == RECFM_OEM)
+ tdbp = new(g) TDBMUL(tdbp); // No block optimization yet
+
+#if 0
+ /*********************************************************************/
+ /* The OEM table is based on a file type (currently DOS+ only) */
+ /*********************************************************************/
+ assert (rfm == RECFM_VAR || rfm == RECFM_FIX ||
+ rfm == RECFM_BIN || rfm == RECFM_VCT);
+
+ PTXF txfp = NULL;
+ PDOSDEF defp = (PDOSDEF)Pxdef;
+ bool map = defp->Mapped && mode != MODE_INSERT &&
+ !(UseTemp() == TMP_FORCE &&
+ (mode == MODE_UPDATE || mode == MODE_DELETE));
+ int cmpr = defp->Compressed;
+
+ /*********************************************************************/
+ /* Allocate table and file processing class of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*********************************************************************/
+ if (!((PTDBDOS)tdbp)->GetTxfp()) {
+ if (cmpr) {
+#if defined(GZ_SUPPORT)
+ if (cmpr == 1)
+ txfp = new(g) GZFAM(defp);
+ else
+ txfp = new(g) ZLBFAM(defp);
+#else // !GZ_SUPPORT
+ strcpy(g->Message, "Compress not supported");
+ return NULL;
+#endif // !GZ_SUPPORT
+ } else if (rfm == RECFM_VAR) {
+ if (map)
+ txfp = new(g) MAPFAM(defp);
+ else
+ txfp = new(g) DOSFAM(defp);
+
+ } else if (rfm == RECFM_FIX || rfm == RECFM_BIN) {
+ if (map)
+ txfp = new(g) MPXFAM(defp);
+ else
+ txfp = new(g) FIXFAM(defp);
+ } else if (rfm == RECFM_VCT) {
+#if defined(VCT_SUPPORT)
+ assert(Pxdef->GetDefType() == TYPE_AM_VCT);
+
+ if (map)
+ txfp = new(g) VCMFAM((PVCTDEF)defp);
+ else
+ txfp = new(g) VCTFAM((PVCTDEF)defp);
+#else // !VCT_SUPPORT
+ strcpy(g->Message, "VCT no more supported");
+ return NULL;
+#endif // !VCT_SUPPORT
+ } // endif's
+
+ ((PTDBDOS)tdbp)->SetTxfp(txfp);
+ } // endif Txfp
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+#endif // 0
+ return tdbp;
+ } // end of GetTable
+
+/* --------------------------- Class COLCRT -------------------------- */
+
+/***********************************************************************/
+/* COLCRT Constructors. */
+/***********************************************************************/
+COLCRT::COLCRT(PSZ name)
+ {
+ Next = NULL;
+ Name = name;
+ Desc = NULL;
+ Decode = NULL;
+ Fmt = NULL;
+ Offset = -1;
+ Long = -1;
+ Precision = -1;
+ Freq = -1;
+ Key = -1;
+ Scale = -1;
+ Opt = -1;
+ DataType = '*';
+ } // end of COLCRT constructor for table creation
+
+COLCRT::COLCRT(void)
+ {
+ Next = NULL;
+ Name = NULL;
+ Desc = NULL;
+ Decode = NULL;
+ Fmt = NULL;
+ Offset = 0;
+ Long = 0;
+ Precision = 0;
+ Freq = 0;
+ Key = 0;
+ Scale = 0;
+ Opt = 0;
+ DataType = '*';
+ } // end of COLCRT constructor for table & view definition
+
+/* --------------------------- Class COLDEF -------------------------- */
+
+/***********************************************************************/
+/* COLDEF Constructor. */
+/***********************************************************************/
+COLDEF::COLDEF(void) : COLCRT()
+ {
+ To_Min = NULL;
+ To_Max = NULL;
+ To_Pos = NULL;
+ Xdb2 = FALSE;
+ To_Bmap = NULL;
+ To_Dval = NULL;
+ Ndv = 0;
+ Nbm = 0;
+ Buf_Type = TYPE_ERROR;
+ Clen = 0;
+ Poff = 0;
+ memset(&F, 0, sizeof(FORMAT));
+ Flags = 0;
+ } // end of COLDEF constructor
+
+/***********************************************************************/
+/* Define: initialize a column definition from a COLINFO structure. */
+/***********************************************************************/
+int COLDEF::Define(PGLOBAL g, void *, PCOLINFO cfp, int poff)
+ {
+ Name = (PSZ)PlugDup(g, cfp->Name);
+
+ if (!(cfp->Flags & U_SPECIAL)) {
+ Poff = poff;
+ Buf_Type = cfp->Type;
+
+ if ((Clen = GetTypeSize(Buf_Type, cfp->Length)) < 0) {
+ sprintf(g->Message, MSG(BAD_COL_TYPE), GetTypeName(Buf_Type), Name);
+ return -1;
+ } // endswitch
+
+ strcpy(F.Type, GetFormatType(Buf_Type));
+ F.Length = cfp->Length;
+ F.Prec = cfp->Scale;
+ Offset = (cfp->Offset < 0) ? poff : cfp->Offset;
+ Precision = cfp->Precision;
+ Scale = cfp->Scale;
+ Long = cfp->Length;
+ Opt = cfp->Opt;
+ Key = cfp->Key;
+ Freq = cfp->Freq;
+
+ if (cfp->Remark && *cfp->Remark)
+ Desc = (PSZ)PlugDup(g, cfp->Remark);
+
+ if (cfp->Datefmt)
+ Decode = (PSZ)PlugDup(g, cfp->Datefmt);
+
+ } else
+ Offset = poff;
+
+ if (cfp->Fieldfmt)
+ Fmt = (PSZ)PlugDup(g, cfp->Fieldfmt);
+
+ Flags = cfp->Flags;
+ return (Flags & (U_VIRTUAL|U_SPECIAL)) ? 0 : Long;
+ } // end of Define
+
+/* ------------------------- End of RelDef --------------------------- */
diff --git a/storage/connect/reldef.h b/storage/connect/reldef.h
new file mode 100644
index 00000000..1b81ae9e
--- /dev/null
+++ b/storage/connect/reldef.h
@@ -0,0 +1,251 @@
+/*************** RelDef H Declares Source Code File (.H) ***************/
+/* Name: RELDEF.H Version 1.6 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2004-2016 */
+/* */
+/* This file contains the DEF classes definitions. */
+/***********************************************************************/
+
+#ifndef __RELDEF_H
+#define __RELDEF_H
+
+#include "block.h"
+#include "catalog.h"
+//#include "my_sys.h"
+#include "mycat.h"
+
+typedef class INDEXDEF *PIXDEF;
+typedef class ha_connect *PHC;
+
+/***********************************************************************/
+/* Table or View (relation) definition block. */
+/***********************************************************************/
+class DllExport RELDEF : public BLOCK { // Relation definition block
+ friend class CATALOG;
+ friend class PLUGCAT;
+ friend class MYCAT;
+ public:
+ RELDEF(void); // Constructor
+
+ // Implementation
+ PRELDEF GetNext(void) {return Next;}
+ PSZ GetName(void) {return Name;}
+ PSZ GetDB(void) {return (PSZ)Database;}
+ PCOLDEF GetCols(void) {return To_Cols;}
+ PHC GetHandler(void) {return Hc;}
+ void SetCols(PCOLDEF pcd) {To_Cols = pcd;}
+ PCATLG GetCat(void) {return Cat;}
+ virtual const char *GetType(void) = 0;
+ virtual AMT GetDefType(void) = 0;
+ void SetName(const char *str) { Name=(char*)str; }
+ void SetCat(PCATLG cat) { Cat=cat; }
+
+ // Methods
+ PTOS GetTopt(void);
+ bool GetBoolCatInfo(PCSZ what, bool bdef);
+ bool SetIntCatInfo(PCSZ what, int ival);
+ bool Partitioned(void);
+ int GetIntCatInfo(PCSZ what, int idef);
+ int GetSizeCatInfo(PCSZ what, PCSZ sdef);
+ int GetCharCatInfo(PCSZ what, PCSZ sdef, char *buf, int size);
+ char *GetStringCatInfo(PGLOBAL g, PCSZ what, PCSZ sdef);
+ virtual int Indexable(void) {return 0;}
+ virtual bool Define(PGLOBAL g, PCATLG cat,
+ LPCSTR name, LPCSTR schema, LPCSTR am) = 0;
+ virtual PTDB GetTable(PGLOBAL g, MODE mode) = 0;
+
+ protected:
+ PRELDEF Next; /* To next definition block */
+ PSZ Name; /* Name of the view */
+ LPCSTR Database; /* Table database */
+ PCOLDEF To_Cols; /* To a list of column desc */
+ PCATLG Cat; /* To DB catalog info */
+ PHC Hc; /* The Connect handler */
+ }; // end of RELDEF
+
+/***********************************************************************/
+/* This class corresponds to the data base description for tables */
+/* of type DOS, FIX, CSV, DBF, BIN, VCT, JSON, XML... */
+/***********************************************************************/
+class DllExport TABDEF : public RELDEF { /* Logical table descriptor */
+ friend class CATALOG;
+ friend class PLUGCAT;
+ friend class MYCAT;
+ friend class TDB;
+ friend class TDBEXT;
+public:
+ // Constructor
+ TABDEF(void); // Constructor
+
+ // Implementation
+ int GetDegree(void) {return Degree;}
+ void SetDegree(int d) {Degree = d;}
+ int GetElemt(void) {return Elemt;}
+ void SetNext(PTABDEF tdfp) {Next = tdfp;}
+ int GetMultiple(void) {return Multiple;}
+ int GetPseudo(void) {return Pseudo;}
+ RECFM GetRecfm(void) {return Recfm;}
+ PCSZ GetPath(void);
+//PSZ GetPath(void)
+// {return (Database) ? (PSZ)Database : Cat->GetDataPath();}
+ RECFM GetTableFormat(const char* type);
+ bool SepIndex(void) {return GetBoolCatInfo("SepIndex", false);}
+ bool IsReadOnly(void) {return Read_Only;}
+ virtual AMT GetDefType(void) {return TYPE_AM_TAB;}
+ virtual PIXDEF GetIndx(void) {return NULL;}
+ virtual void SetIndx(PIXDEF) {}
+ virtual bool IsHuge(void) {return false;}
+ const CHARSET_INFO *data_charset() {return m_data_charset;}
+ const char *GetCsName(void) {return csname;}
+
+ // Methods
+ int GetColCatInfo(PGLOBAL g);
+ void SetIndexInfo(void);
+ bool DropTable(PGLOBAL g, PSZ name);
+ virtual bool Define(PGLOBAL g, PCATLG cat,
+ LPCSTR name, LPCSTR schema, LPCSTR am);
+ virtual bool DefineAM(PGLOBAL, LPCSTR, int) = 0;
+
+ protected:
+ // Members
+ PCSZ Schema; /* Table schema (for ODBC) */
+ PCSZ Desc; /* Table description */
+ RECFM Recfm; /* File or table format */
+ uint Catfunc; /* Catalog function ID */
+ int Card; /* (max) number of rows in table */
+ int Elemt; /* Number of rows in blocks or rowset */
+ int Sort; /* Table already sorted ??? */
+ int Multiple; /* 0: No 1: DIR 2: Section 3: filelist */
+ int Degree; /* Number of columns in the table */
+ int Pseudo; /* Bit: 1 ROWID }Ok, 2 FILEID Ok */
+ bool Read_Only; /* true for read only tables */
+ const CHARSET_INFO *m_data_charset;
+ const char *csname; /* Table charset name */
+}; // end of TABDEF
+
+/***********************************************************************/
+/* Externally defined OEM tables. */
+/***********************************************************************/
+class DllExport OEMDEF : public TABDEF { /* OEM table */
+ friend class CATALOG;
+ friend class PLUGCAT;
+ friend class MYCAT;
+ public:
+ // Constructor
+ OEMDEF(void) {Hdll = NULL; Pxdef = NULL; Module = Subtype = NULL;}
+
+ // Implementation
+ virtual const char *GetType(void) {return "OEM";}
+ virtual AMT GetDefType(void) {return TYPE_AM_OEM;}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE mode);
+
+ protected:
+ PTABDEF GetXdef(PGLOBAL g);
+
+ // Members
+#if defined(_WIN32)
+ HANDLE Hdll; /* Handle to the external DLL */
+#else // !_WIN32
+ void *Hdll; /* Handle for the loaded shared library */
+#endif // !_WIN32
+ PTABDEF Pxdef; /* Pointer to the external TABDEF class */
+ char *Module; /* Path/Name of the DLL implenting it */
+ char *Subtype; /* The name of the OEM table sub type */
+ }; // end of OEMDEF
+
+/***********************************************************************/
+/* Column definition block used during creation. */
+/***********************************************************************/
+class DllExport COLCRT : public BLOCK { /* Column description block */
+ friend class TABDEF;
+ public:
+ COLCRT(PSZ name); // Constructor
+ COLCRT(void); // Constructor (for views)
+
+ // Implementation
+ PSZ GetName(void) {return Name;}
+ PSZ GetDecode(void) {return Decode;}
+ PSZ GetFmt(void) {return Fmt;}
+ int GetOpt(void) {return Opt;}
+ int GetFreq(void) {return Freq;}
+ int GetLong(void) {return Long;}
+ int GetPrecision(void) {return Precision;}
+ int GetOffset(void) {return Offset;}
+ void SetOffset(int offset) {Offset = offset;}
+
+ protected:
+ PCOLCRT Next; /* To next block */
+ PSZ Name; /* Column name */
+ PSZ Desc; /* Column description */
+ PSZ Decode; /* Date format */
+ PSZ Fmt; /* Input format for formatted files */
+ int Offset; /* Offset of field within record */
+ int Long; /* Length of field in file record (!BIN) */
+ int Key; /* Key (greater than 1 if multiple) */
+ int Precision; /* Logical column length */
+ int Scale; /* Decimals for float/decimal values */
+ int Opt; /* 0:Not 1:clustered 2:sorted-asc 3:desc */
+ int Freq; /* Estimated number of different values */
+ char DataType; /* Internal data type (C, N, F, T) */
+ }; // end of COLCRT
+
+/***********************************************************************/
+/* Column definition block. */
+/***********************************************************************/
+class DllExport COLDEF : public COLCRT { /* Column description block */
+ friend class TABDEF;
+ friend class COLBLK;
+ friend class DBFFAM;
+ friend class TDB;
+ friend class TDBASE;
+ friend class TDBDOS;
+public:
+ COLDEF(void); // Constructor
+
+ // Implementation
+ PCOLDEF GetNext(void) {return (PCOLDEF)Next;}
+ void SetNext(PCOLDEF pcdf) {Next = pcdf;}
+ int GetLength(void) {return (int)F.Length;}
+ int GetClen(void) {return Clen;}
+ int GetType(void) {return Buf_Type;}
+ int GetPoff(void) {return Poff;}
+ void *GetMin(void) {return To_Min;}
+ void SetMin(void *minp) {To_Min = minp;}
+ void *GetMax(void) {return To_Max;}
+ void SetMax(void *maxp) {To_Max = maxp;}
+ bool GetXdb2(void) {return Xdb2;}
+ void SetXdb2(bool b) {Xdb2 = b;}
+ void *GetBmap(void) {return To_Bmap;}
+ void SetBmap(void *bmp) {To_Bmap = bmp;}
+ void *GetDval(void) {return To_Dval;}
+ void SetDval(void *dvp) {To_Dval = dvp;}
+ int GetNdv(void) {return Ndv;}
+ void SetNdv(int ndv) {Ndv = ndv;}
+ int GetNbm(void) {return Nbm;}
+ void SetNbm(int nbm) {Nbm = nbm;}
+ int Define(PGLOBAL g, void *memp, PCOLINFO cfp, int poff);
+ void Define(PGLOBAL g, PCOL colp);
+ bool IsSpecial(void) {return (Flags & U_SPECIAL) ? true : false;}
+ bool IsVirtual(void) {return (Flags & U_VIRTUAL) ? true : false;}
+
+ protected:
+ void *To_Min; /* Point to array of block min values */
+ void *To_Max; /* Point to array of block max values */
+ int *To_Pos; /* Point to array of block positions */
+ bool Xdb2; /* TRUE if to be optimized by XDB2 */
+ void *To_Bmap; /* To array of block bitmap values */
+ void *To_Dval; /* To array of column distinct values */
+ int Ndv; /* Number of distinct values */
+ int Nbm; /* Number of ULONG in bitmap (XDB2) */
+ int Buf_Type; /* Internal data type */
+ int Clen; /* Internal data size in chars (bytes) */
+ int Poff; /* Calculated offset for Packed tables */
+ FORMAT F; /* Output format (should be in COLCRT) */
+ ushort Flags; /* Used by MariaDB CONNECT handler */
+ }; // end of COLDEF
+
+#endif // __RELDEF_H
+
diff --git a/storage/connect/resource.h b/storage/connect/resource.h
new file mode 100644
index 00000000..1c3e1ee3
--- /dev/null
+++ b/storage/connect/resource.h
@@ -0,0 +1,46 @@
+#define IDS_TABLES 100
+#define IDS_TAB_01 101
+#define IDS_TAB_02 102
+#define IDS_TAB_03 103
+#define IDS_TAB_04 104
+#define IDS_TAB_05 105
+#define IDS_COLUMNS 106
+#define IDS_COL_01 107
+#define IDS_COL_02 108
+#define IDS_COL_03 109
+#define IDS_COL_04 110
+#define IDS_COL_05 111
+#define IDS_COL_06 112
+#define IDS_COL_07 113
+#define IDS_COL_08 114
+#define IDS_COL_09 115
+#define IDS_COL_10 116
+#define IDS_COL_11 117
+#define IDS_COL_12 118
+#define IDS_PKEY 119
+#define IDS_PKY_01 120
+#define IDS_PKY_02 121
+#define IDS_PKY_03 122
+#define IDS_PKY_04 123
+#define IDS_PKY_05 124
+#define IDS_PKY_06 125
+#define IDS_STAT 126
+#define IDS_STA_01 127
+#define IDS_STA_02 128
+#define IDS_STA_03 129
+#define IDS_STA_04 130
+#define IDS_STA_05 131
+#define IDS_STA_06 132
+#define IDS_STA_07 133
+#define IDS_STA_08 134
+#define IDS_STA_09 135
+#define IDS_STA_10 136
+#define IDS_STA_11 137
+#define IDS_STA_12 138
+#define IDS_STA_13 139
+#define IDS_DRIVER 140
+#define IDS_DRV_01 141
+#define IDS_DRV_02 142
+#define IDS_DSRC 143
+#define IDS_DSC_01 144
+#define IDS_DSC_02 145
diff --git a/storage/connect/rest.def b/storage/connect/rest.def
new file mode 100644
index 00000000..71c76740
--- /dev/null
+++ b/storage/connect/rest.def
@@ -0,0 +1,4 @@
+LIBRARY REST2
+EXPORTS
+ GetREST @1
+ ColREST @2
diff --git a/storage/connect/restget.cpp b/storage/connect/restget.cpp
new file mode 100644
index 00000000..29dae230
--- /dev/null
+++ b/storage/connect/restget.cpp
@@ -0,0 +1,90 @@
+/************* Restget C++ Program Source Code File (.CPP) *************/
+/* Adapted from the sample program of the Casablanca tutorial. */
+/* Copyright Olivier Bertrand 2019. */
+/***********************************************************************/
+#include <cpprest/filestream.h>
+#include <cpprest/http_client.h>
+
+using namespace utility::conversions; // String conversions utilities
+using namespace web; // Common features like URIs.
+using namespace web::http; // Common HTTP functionality
+using namespace web::http::client; // HTTP client features
+using namespace concurrency::streams; // Asynchronous streams
+
+typedef const char* PCSZ;
+
+extern "C" int restGetFile(char* m, bool xt, PCSZ http, PCSZ uri, PCSZ fn);
+
+/***********************************************************************/
+/* Make a local copy of the requested file. */
+/***********************************************************************/
+int restGetFile(char *m, bool xt, PCSZ http, PCSZ uri, PCSZ fn)
+{
+ int rc = 0;
+ auto fileStream = std::make_shared<ostream>();
+
+ if (!http || !fn) {
+ //strcpy(g->Message, "Missing http or filename");
+ strcpy(m, "Missing http or filename");
+ return 2;
+ } // endif
+
+ if (xt)
+ fprintf(stderr, "restGetFile: fn=%s\n", fn);
+
+ // Open stream to output file.
+ pplx::task<void> requestTask = fstream::open_ostream(to_string_t(fn))
+ .then([=](ostream outFile) {
+ *fileStream= outFile;
+
+ if (xt)
+ fprintf(stderr, "Outfile isopen=%d\n", outFile.is_open());
+
+ // Create http_client to send the request.
+ http_client client(to_string_t(http));
+
+ if (uri) {
+ // Build request URI and start the request.
+ uri_builder builder(to_string_t(uri));
+ return client.request(methods::GET, builder.to_string());
+ } else
+ return client.request(methods::GET);
+ })
+
+ // Handle response headers arriving.
+ .then([=](http_response response) {
+ if (xt)
+ fprintf(stderr, "Received response status code:%u\n",
+ response.status_code());
+
+ // Write response body into the file.
+ return response.body().read_to_end(fileStream->streambuf());
+ })
+
+ // Close the file stream.
+ .then([=](size_t n) {
+ if (xt)
+ fprintf(stderr, "Return size=%zu\n", n);
+
+ return fileStream->close();
+ });
+
+ // Wait for all the outstanding I/O to complete and handle any exceptions
+ try {
+ if (xt)
+ fprintf(stderr, "Waiting\n");
+
+ requestTask.wait();
+ } catch (const std::exception &e) {
+ if (xt)
+ fprintf(stderr, "Error exception: %s\n", e.what());
+
+ sprintf(m, "Error exception: %s", e.what());
+ rc= 1;
+ } // end try/catch
+
+ if (xt)
+ fprintf(stderr, "restget done: rc=%d\n", rc);
+
+ return rc;
+} // end of restGetFile
diff --git a/storage/connect/tabbson.cpp b/storage/connect/tabbson.cpp
new file mode 100644
index 00000000..de272798
--- /dev/null
+++ b/storage/connect/tabbson.cpp
@@ -0,0 +1,2627 @@
+/************* tabbson C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: tabbson Version 1.2 */
+/* (C) Copyright to the author Olivier BERTRAND 2020 - 2021 */
+/* This program are the BSON class DB execution routines. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tdbdos.h is header containing the TDBDOS declarations. */
+/* json.h is header containing the JSON classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "maputil.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#include "tabbson.h"
+#include "filamap.h"
+#if defined(GZ_SUPPORT)
+#include "filamgz.h"
+#endif // GZ_SUPPORT
+#if defined(ZIP_SUPPORT)
+#include "filamzip.h"
+#endif // ZIP_SUPPORT
+#if defined(JAVA_SUPPORT)
+#include "jmgfam.h"
+#endif // JAVA_SUPPORT
+#if defined(CMGO_SUPPORT)
+#include "cmgfam.h"
+#endif // CMGO_SUPPORT
+#include "tabmul.h"
+#include "checklvl.h"
+#include "resource.h"
+#include "mycat.h" // for FNC_COL
+
+/***********************************************************************/
+/* This should be an option. */
+/***********************************************************************/
+#define MAXCOL 200 /* Default max column nb in result */
+//#define TYPE_UNKNOWN 12 /* Must be greater than other types */
+
+/***********************************************************************/
+/* External functions. */
+/***********************************************************************/
+USETEMP UseTemp(void);
+bool JsonAllPath(void);
+int GetDefaultDepth(void);
+char *GetJsonNull(void);
+bool Stringified(PCSZ, char*);
+
+/***********************************************************************/
+/* BSONColumns: construct the result blocks containing the description */
+/* of all the columns of a table contained inside a JSON file. */
+/***********************************************************************/
+PQRYRES BSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
+{
+ static int buftyp[] = { TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
+ TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING };
+ static XFLD fldtyp[] = { FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
+ FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT };
+ static unsigned int length[] = { 0, 6, 8, 10, 10, 6, 6, 0 };
+ int i, n = 0;
+ int ncol = sizeof(buftyp) / sizeof(int);
+ PJCL jcp;
+ BSONDISC* pjdc = NULL;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ if (info) {
+ length[0] = 128;
+ length[7] = 256;
+ goto skipit;
+ } // endif info
+
+ if (GetIntegerTableOption(g, topt, "Multiple", 0)) {
+ strcpy(g->Message, "Cannot find column definition for multiple table");
+ return NULL;
+ } // endif Multiple
+
+ pjdc = new(g) BSONDISC(g, length);
+
+ if (!(n = pjdc->GetColumns(g, db, dsn, topt)))
+ return NULL;
+
+skipit:
+ if (trace(1))
+ htrc("BSONColumns: n=%d len=%d\n", n, length[0]);
+
+ /*********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /*********************************************************************/
+ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, false);
+
+ crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
+ crp->Name = PlugDup(g, "Nullable");
+ crp->Next->Name = PlugDup(g, "Jpath");
+
+ if (info || !qrp)
+ return qrp;
+
+ qrp->Nblin = n;
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ for (i = 0, jcp = pjdc->fjcp; jcp; i++, jcp = jcp->Next) {
+ if (jcp->Type == TYPE_UNKNOWN)
+ jcp->Type = TYPE_STRG; // Void column
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(jcp->Name, i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(jcp->Type, i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(jcp->Type), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(jcp->Len, i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(jcp->Len, i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(jcp->Scale, i);
+ crp = crp->Next; // Nullable
+ crp->Kdata->SetValue(jcp->Cbn ? 1 : 0, i);
+ crp = crp->Next; // Field format
+
+ if (crp->Kdata)
+ crp->Kdata->SetValue(jcp->Fmt, i);
+
+ } // endfor i
+
+/*********************************************************************/
+/* Return the result pointer. */
+/*********************************************************************/
+ return qrp;
+} // end of BSONColumns
+
+/* -------------------------- Class BSONDISC ------------------------- */
+
+/***********************************************************************/
+/* Class used to get the columns of a JSON table. */
+/***********************************************************************/
+BSONDISC::BSONDISC(PGLOBAL g, uint* lg)
+{
+ length = lg;
+ jcp = fjcp = pjcp = NULL;
+ tdp = NULL;
+ tjnp = NULL;
+ jpp = NULL;
+ tjsp = NULL;
+ jsp = NULL;
+ bp = NULL;
+ row = NULL;
+ sep = NULL;
+ strfy = NULL;
+ i = n = bf = ncol = lvl = sz = limit = 0;
+ all = false;
+} // end of BSONDISC constructor
+
+int BSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
+{
+ char filename[_MAX_PATH];
+ bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
+ PBVAL bdp = NULL;
+
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
+ sep = GetStringTableOption(g, topt, "Separator", ".");
+ sz = GetIntegerTableOption(g, topt, "Jsize", 1024);
+ limit = GetIntegerTableOption(g, topt, "Limit", 50);
+ strfy = GetStringTableOption(g, topt, "Stringify", NULL);
+
+ /*********************************************************************/
+ /* Open the input file. */
+ /*********************************************************************/
+ tdp = new(g) BSONDEF;
+ tdp->G = NULL;
+#if defined(ZIP_SUPPORT)
+ tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
+ tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false);
+#endif // ZIP_SUPPORT
+ tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL);
+
+ if (!tdp->Fn && topt->http)
+ tdp->Fn = GetStringTableOption(g, topt, "Subtype", NULL);
+
+ if (!(tdp->Database = SetPath(g, db)))
+ return 0;
+
+ if ((tdp->Objname = GetStringTableOption(g, topt, "Object", NULL))) {
+ if (*tdp->Objname == '$') tdp->Objname++;
+ if (*tdp->Objname == '.') tdp->Objname++;
+ } // endif Objname
+
+ tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0;
+ tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2);
+ tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL);
+ tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false);
+ tdp->Uri = (dsn && *dsn ? dsn : NULL);
+
+ if (!tdp->Fn && !tdp->Uri) {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return 0;
+ } else
+ topt->subtype = NULL;
+
+ if (tdp->Fn) {
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, tdp->Fn, tdp->GetPath());
+ tdp->Fn = PlugDup(g, filename);
+ } // endif Fn
+
+ if (trace(1))
+ htrc("File %s objname=%s pretty=%d lvl=%d\n",
+ tdp->Fn, tdp->Objname, tdp->Pretty, lvl);
+
+ if (tdp->Uri) {
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+ tdp->Collname = GetStringTableOption(g, topt, "Tabname", NULL);
+ tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test");
+ tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all");
+ tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false);
+ tdp->Driver = (PSZ)GetStringTableOption(g, topt, "Driver", NULL);
+ tdp->Version = GetIntegerTableOption(g, topt, "Version", 3);
+ tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper",
+ (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface");
+ tdp->Pretty = 0;
+#else // !MONGO_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return 0;
+#endif // !MONGO_SUPPORT
+ } // endif Uri
+
+ if (tdp->Pretty == 2) {
+ tdp->G = g;
+
+ if (tdp->Zipped) {
+#if defined(ZIP_SUPPORT)
+ tjsp = new(g) TDBBSON(g, tdp, new(g) UNZFAM(tdp));
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return 0;
+#endif // !ZIP_SUPPORT
+ } else
+ tjsp = new(g) TDBBSON(g, tdp, new(g) MAPFAM(tdp));
+
+ if (tjsp->MakeDocument(g))
+ return 0;
+
+ bp = tjsp->Bp;
+// bdp = tjsp->GetDoc() ? bp->GetBson(tjsp->GetDoc()) : NULL;
+ bdp = tjsp->GetDoc();
+ jsp = bdp ? bp->GetArrayValue(bdp, 0) : NULL;
+ } else {
+ if (!((tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))) {
+ if (!mgo) {
+ sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty);
+ return 0;
+ } else
+ tdp->Lrecl = 8192; // Should be enough
+
+ } // endif Lrecl
+
+ // Allocate the parse work memory
+ tdp->G = PlugInit(NULL, (size_t)tdp->Lrecl * (tdp->Pretty >= 0 ? 4 : 2));
+ tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF);
+
+ if (tdp->Zipped) {
+#if defined(ZIP_SUPPORT)
+ tjnp = new(g)TDBBSN(g, tdp, new(g) UNZFAM(tdp));
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } else if (tdp->Uri) {
+ if (tdp->Driver && toupper(*tdp->Driver) == 'C') {
+#if defined(CMGO_SUPPORT)
+ tjnp = new(g) TDBBSN(g, tdp, new(g) CMGFAM(tdp));
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "C");
+ return 0;
+#endif
+ } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') {
+#if defined(JAVA_SUPPORT)
+ tjnp = new(g) TDBBSN(g, tdp, new(g) JMGFAM(tdp));
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "Java");
+ return 0;
+#endif
+ } else { // Driver not specified
+#if defined(CMGO_SUPPORT)
+ tjnp = new(g) TDBBSN(g, tdp, new(g) CMGFAM(tdp));
+#elif defined(JAVA_SUPPORT)
+ tjnp = new(g) TDBBSN(g, tdp, new(g) JMGFAM(tdp));
+#else
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return 0;
+#endif
+ } // endif Driver
+
+ } else if (tdp->Pretty >= 0)
+ tjnp = new(g) TDBBSN(g, tdp, new(g) DOSFAM(tdp));
+ else
+ tjnp = new(g) TDBBSN(g, tdp, new(g) BINFAM(tdp));
+
+ tjnp->SetMode(MODE_READ);
+ bp = tjnp->Bp;
+
+ if (tjnp->OpenDB(g))
+ return 0;
+
+ switch (tjnp->ReadDB(g)) {
+ case RC_EF:
+ strcpy(g->Message, "Void json table");
+ case RC_FX:
+ goto err;
+ default:
+ jsp = tjnp->Row;
+ } // endswitch ReadDB
+
+ } // endif pretty
+
+ if (!(row = (jsp) ? bp->GetObject(jsp) : NULL)) {
+ strcpy(g->Message, "Can only retrieve columns from object rows");
+ goto err;
+ } // endif row
+
+ all = GetBooleanTableOption(g, topt, "Fullarray", false);
+ jcol.Name = jcol.Fmt = NULL;
+ jcol.Next = NULL;
+ jcol.Found = true;
+ colname[0] = 0;
+
+ if (!tdp->Uri) {
+ fmt[0] = '$';
+ fmt[1] = '.';
+ bf = 2;
+ } // endif Uri
+
+ /*********************************************************************/
+ /* Analyse the JSON tree and define columns. */
+ /*********************************************************************/
+ for (i = 1; ; i++) {
+ for (jpp = row; jpp; jpp = bp->GetNext(jpp)) {
+ strncpy(colname, bp->GetKey(jpp), 64);
+ fmt[bf] = 0;
+
+ if (Find(g, bp->GetVlp(jpp), colname, MY_MIN(lvl, 0)))
+ goto err;
+
+ } // endfor jpp
+
+ // Missing column can be null
+ for (jcp = fjcp; jcp; jcp = jcp->Next) {
+ jcp->Cbn |= !jcp->Found;
+ jcp->Found = false;
+ } // endfor jcp
+
+ if (tdp->Pretty != 2) {
+ // Read next record
+ switch (tjnp->ReadDB(g)) {
+ case RC_EF:
+ jsp = NULL;
+ break;
+ case RC_FX:
+ goto err;
+ default:
+ jsp = tjnp->Row;
+ } // endswitch ReadDB
+
+ } else
+ jsp = bp->GetArrayValue(bdp, i);
+
+ if (!(row = (jsp) ? bp->GetObject(jsp) : NULL))
+ break;
+
+ } // endfor i
+
+ if (tdp->Pretty != 2)
+ tjnp->CloseDB(g);
+
+ return n;
+
+err:
+ if (tdp->Pretty != 2)
+ tjnp->CloseDB(g);
+
+ return 0;
+} // end of GetColumns
+
+bool BSONDISC::Find(PGLOBAL g, PBVAL jvp, PCSZ key, int j)
+{
+ char *p, *pc = colname + strlen(colname), buf[32];
+ int ars;
+ size_t n;
+ PBVAL job;
+ PBVAL jar;
+
+ if (jvp && !bp->IsJson(jvp)) {
+ if (JsonAllPath() && !fmt[bf])
+ strcat(fmt, colname);
+
+ jcol.Type = (JTYP)jvp->Type;
+
+ switch (jvp->Type) {
+ case TYPE_STRG:
+ case TYPE_DTM:
+ jcol.Len = (int)strlen(bp->GetString(jvp));
+ break;
+ case TYPE_INTG:
+ case TYPE_BINT:
+ jcol.Len = (int)strlen(bp->GetString(jvp, buf));
+ break;
+ case TYPE_DBL:
+ case TYPE_FLOAT:
+ jcol.Len = (int)strlen(bp->GetString(jvp, buf));
+ jcol.Scale = jvp->Nd;
+ break;
+ case TYPE_BOOL:
+ jcol.Len = 1;
+ break;
+ default:
+ jcol.Len = 0;
+ break;
+ } // endswitch Type
+
+ jcol.Scale = jvp->Nd;
+ jcol.Cbn = jvp->Type == TYPE_NULL;
+ } else if (!jvp || bp->IsValueNull(jvp)) {
+ jcol.Type = TYPE_UNKNOWN;
+ jcol.Len = jcol.Scale = 0;
+ jcol.Cbn = true;
+ } else if (j < lvl && !Stringified(strfy, colname)) {
+ if (!fmt[bf])
+ strcat(fmt, colname);
+
+ p = fmt + strlen(fmt);
+ jsp = jvp;
+
+ switch (jsp->Type) {
+ case TYPE_JOB:
+ job = jsp;
+
+ for (PBPR jrp = bp->GetObject(job); jrp; jrp = bp->GetNext(jrp)) {
+ PCSZ k = bp->GetKey(jrp);
+
+ if (*k != '$') {
+ n = sizeof(fmt) - strlen(fmt) - 1;
+ strncat(strncat(fmt, sep, n), k, n - strlen(sep));
+ n = sizeof(colname) - strlen(colname) - 1;
+ strncat(strncat(colname, "_", n), k, n - 1);
+ } // endif Key
+
+ if (Find(g, bp->GetVlp(jrp), k, j + 1))
+ return true;
+
+ *p = *pc = 0;
+ } // endfor jrp
+
+ return false;
+ case TYPE_JAR:
+ jar = jsp;
+
+ if (all || (tdp->Xcol && !stricmp(tdp->Xcol, key)))
+ ars = MY_MIN(bp->GetArraySize(jar), limit);
+ else
+ ars = MY_MIN(bp->GetArraySize(jar), 1);
+
+ for (int k = 0; k < ars; k++) {
+ n = sizeof(fmt) - (strlen(fmt) + 1);
+
+ if (!tdp->Xcol || stricmp(tdp->Xcol, key)) {
+ sprintf(buf, "%d", k);
+
+ if (tdp->Uri) {
+ strncat(strncat(fmt, sep, n), buf, n - strlen(sep));
+ } else {
+ strncat(strncat(fmt, "[", n), buf, n - 1);
+ strncat(fmt, "]", n - (strlen(buf) + 1));
+ } // endif uri
+
+ if (all) {
+ n = sizeof(colname) - (strlen(colname) + 1);
+ strncat(strncat(colname, "_", n), buf, n - 1);
+ } // endif all
+
+ } else {
+ strncat(fmt, (tdp->Uri ? sep : "[*]"), n);
+ }
+
+ if (Find(g, bp->GetArrayValue(jar, k), "", j))
+ return true;
+
+ *p = *pc = 0;
+ } // endfor k
+
+ return false;
+ default:
+ sprintf(g->Message, "Logical error after %s", fmt);
+ return true;
+ } // endswitch Type
+
+ } else if (lvl >= 0) {
+ if (Stringified(strfy, colname)) {
+ if (!fmt[bf])
+ strcat(fmt, colname);
+
+ strcat(fmt, ".*");
+ } else if (JsonAllPath() && !fmt[bf])
+ strcat(fmt, colname);
+
+ jcol.Type = TYPE_STRG;
+ jcol.Len = sz;
+ jcol.Scale = 0;
+ jcol.Cbn = true;
+ } else
+ return false;
+
+ AddColumn(g);
+ return false;
+} // end of Find
+
+void BSONDISC::AddColumn(PGLOBAL g)
+{
+ bool b = fmt[bf] != 0; // True if formatted
+
+ // Check whether this column was already found
+ for (jcp = fjcp; jcp; jcp = jcp->Next)
+ if (!strcmp(colname, jcp->Name))
+ break;
+
+ if (jcp) {
+ if (jcp->Type != jcol.Type) {
+ if (jcp->Type == TYPE_UNKNOWN || jcp->Type == TYPE_NULL)
+ jcp->Type = jcol.Type;
+ // else if (jcol.Type != TYPE_UNKNOWN && jcol.Type != TYPE_VOID)
+ // jcp->Type = TYPE_STRING;
+ else if (jcp->Type != TYPE_STRG)
+ switch (jcol.Type) {
+ case TYPE_STRG:
+ case TYPE_DBL:
+ jcp->Type = jcol.Type;
+ break;
+ case TYPE_BINT:
+ if (jcp->Type == TYPE_INTG || jcp->Type == TYPE_BOOL)
+ jcp->Type = jcol.Type;
+
+ break;
+ case TYPE_INTG:
+ if (jcp->Type == TYPE_BOOL)
+ jcp->Type = jcol.Type;
+
+ break;
+ default:
+ break;
+ } // endswith Type
+
+ } // endif Type
+
+ if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) {
+ jcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], strlen(fmt));
+ } // endif fmt
+
+ jcp->Len = MY_MAX(jcp->Len, jcol.Len);
+ jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale);
+ jcp->Cbn |= jcol.Cbn;
+ jcp->Found = true;
+ } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) {
+ // New column
+ jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL));
+ *jcp = jcol;
+ jcp->Cbn |= (i > 1);
+ jcp->Name = PlugDup(g, colname);
+ length[0] = MY_MAX(length[0], strlen(colname));
+
+ if (b) {
+ jcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], strlen(fmt));
+ } else
+ jcp->Fmt = NULL;
+
+ if (pjcp) {
+ jcp->Next = pjcp->Next;
+ pjcp->Next = jcp;
+ } else
+ fjcp = jcp;
+
+ n++;
+ } // endif jcp
+
+ if (jcp)
+ pjcp = jcp;
+
+} // end of AddColumn
+
+/* -------------------------- Class BTUTIL --------------------------- */
+
+/***********************************************************************/
+/* Find the row in the tree structure. */
+/***********************************************************************/
+PBVAL BTUTIL::FindRow(PGLOBAL g)
+{
+ char *p, *objpath = PlugDup(g, Tp->Objname);
+ char *sep = (char*)(Tp->Sep == ':' ? ":[" : ".[");
+ bool bp = false, b = false;
+ PBVAL jsp = Tp->Row;
+ PBVAL val = NULL;
+
+ for (; jsp && objpath; objpath = p, bp = b) {
+ if ((p = strpbrk(objpath + 1, sep))) {
+ b = (*p == '[');
+ *p++ = 0;
+ } // endif p
+
+ if (!bp && *objpath != '[' && !IsNum(objpath)) { // objpass is a key
+ val = (jsp->Type == TYPE_JOB) ?
+ GetKeyValue(jsp, objpath) : NULL;
+ } else {
+ if (bp || *objpath == '[') { // Old style
+ if (objpath[strlen(objpath) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path %s", Tp->Objname);
+ return NULL;
+ } else if (!bp)
+ objpath++;
+
+ } // endif bp
+
+ val = (jsp->Type == TYPE_JAR) ?
+ GetArrayValue(jsp, atoi(objpath) - Tp->B) : NULL;
+ } // endif objpath
+
+ // jsp = (val) ? val->GetJson() : NULL;
+ jsp = val;
+ } // endfor objpath
+
+ if (jsp && jsp->Type != TYPE_JOB) {
+ if (jsp->Type == TYPE_JAR) {
+ jsp = GetArrayValue(jsp, Tp->B);
+
+ if (jsp->Type != TYPE_JOB)
+ jsp = NULL;
+
+ } else
+ jsp = NULL;
+
+ } // endif Type
+
+ return jsp;
+} // end of FindRow
+
+/***********************************************************************/
+/* Parse the read line. */
+/***********************************************************************/
+PBVAL BTUTIL::ParseLine(PGLOBAL g, int prty, bool cma)
+{
+ pretty = prty;
+ comma = cma;
+ return ParseJson(g, Tp->To_Line, strlen(Tp->To_Line));
+} // end of ParseLine
+
+/***********************************************************************/
+/* Make the top tree from the object path. */
+/***********************************************************************/
+PBVAL BTUTIL::MakeTopTree(PGLOBAL g, int type)
+{
+ PBVAL top = NULL, val = NULL;
+
+ if (Tp->Objname) {
+ if (!Tp->Row) {
+ // Parse and allocate Objpath item(s)
+ char *p, *objpath = PlugDup(g, Tp->Objname);
+ char *sep = (char*)(Tp->Sep == ':' ? ":[" : ".[");
+ int i;
+ bool bp = false, b = false;
+ PBVAL objp = NULL;
+ PBVAL arp = NULL;
+
+ for (; objpath; objpath = p, bp = b) {
+ if ((p = strpbrk(objpath + 1, sep))) {
+ b = (*p == '[');
+ *p++ = 0;
+ } // endif p
+
+
+ if (!bp && *objpath != '[' && !IsNum(objpath)) {
+ // objpass is a key
+ objp = NewVal(TYPE_JOB);
+
+ if (!top)
+ top = objp;
+
+ if (val)
+ SetValueObj(val, objp);
+
+ val = NewVal();
+ SetKeyValue(objp, MOF(val), objpath);
+ } else {
+ if (bp || *objpath == '[') {
+ // Old style
+ if (objpath[strlen(objpath) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path %s", Tp->Objname);
+ return NULL;
+ } else if (!bp)
+ objpath++;
+
+ } // endif bp
+
+ if (!top)
+ top = NewVal(TYPE_JAR);
+
+ if (val)
+ SetValueArr(val, arp);
+
+ val = NewVal();
+ i = atoi(objpath) - Tp->B;
+ SetArrayValue(arp, val, i);
+ } // endif objpath
+
+ } // endfor p
+
+ } // endif Val
+
+ Tp->Row = val;
+ if (Tp->Row) Tp->Row->Type = type;
+ } else
+ top = Tp->Row = NewVal(type);
+
+ return top;
+} // end of MakeTopTree
+
+PSZ BTUTIL::SerialVal(PGLOBAL g, PBVAL vlp, int pretty)
+{
+ return Serialize(g, vlp, NULL, pretty);
+} // en of SerialTop
+
+/* -------------------------- Class BCUTIL --------------------------- */
+
+/***********************************************************************/
+/* SetValue: Set a value from a BVALUE contains. */
+/***********************************************************************/
+void BCUTIL::SetJsonValue(PGLOBAL g, PVAL vp, PBVAL jvp)
+{
+ if (jvp) {
+ vp->SetNull(false);
+
+ if (Jb) {
+ vp->SetValue_psz(Serialize(g, jvp, NULL, 0));
+ Jb = false;
+ } else switch (jvp->Type) {
+ case TYPE_STRG:
+ case TYPE_INTG:
+ case TYPE_BINT:
+ case TYPE_DBL:
+ case TYPE_DTM:
+ case TYPE_FLOAT:
+ switch (vp->GetType()) {
+ case TYPE_STRING:
+ case TYPE_DECIM:
+ vp->SetValue_psz(GetString(jvp));
+ break;
+ case TYPE_INT:
+ case TYPE_SHORT:
+ case TYPE_TINY:
+ vp->SetValue(GetInteger(jvp));
+ break;
+ case TYPE_BIGINT:
+ vp->SetValue(GetBigint(jvp));
+ break;
+ case TYPE_DOUBLE:
+ vp->SetValue(GetDouble(jvp));
+
+ if (jvp->Type == TYPE_DBL || jvp->Type == TYPE_FLOAT)
+ vp->SetPrec(jvp->Nd);
+
+ break;
+ case TYPE_DATE:
+ if (jvp->Type == TYPE_STRG) {
+ PSZ dat = GetString(jvp);
+
+ if (!IsNum(dat)) {
+ if (!((DTVAL*)vp)->IsFormatted())
+ ((DTVAL*)vp)->SetFormat(g, "YYYY-MM-DDThh:mm:ssZ", 20, 0);
+
+ vp->SetValue_psz(dat);
+ } else
+ vp->SetValue(atoi(dat));
+
+ } else
+ vp->SetValue(GetInteger(jvp));
+
+ break;
+ default:
+ sprintf(G->Message, "Unsupported column type %d", vp->GetType());
+ throw 888;
+ } // endswitch Type
+
+ break;
+ case TYPE_BOOL:
+ if (vp->IsTypeNum())
+ vp->SetValue(GetInteger(jvp) ? 1 : 0);
+ else
+ vp->SetValue_psz((PSZ)(GetInteger(jvp) ? "true" : "false"));
+
+ break;
+ case TYPE_JAR:
+ case TYPE_JOB:
+ // SetJsonValue(g, vp, val->GetArray()->GetValue(0));
+ vp->SetValue_psz(GetValueText(g, jvp, NULL));
+ break;
+ default:
+ vp->Reset();
+ vp->SetNull(true);
+ } // endswitch Type
+
+ } else {
+ vp->Reset();
+ vp->SetNull(true);
+ } // endif val
+
+} // end of SetJsonValue
+
+/***********************************************************************/
+/* MakeJson: Serialize the json item and set value to it. */
+/***********************************************************************/
+PBVAL BCUTIL::MakeBson(PGLOBAL g, PBVAL jsp, int n)
+{
+ PBVAL vlp, jvp = jsp;
+
+ if (n < Cp->Nod - 1) {
+ if (jsp->Type == TYPE_JAR) {
+ int ars = GetArraySize(jsp);
+ PJNODE jnp = &Cp->Nodes[n];
+
+ jvp = NewVal(TYPE_JAR);
+ jnp->Op = OP_EQ;
+
+ for (int i = 0; i < ars; i++) {
+ jnp->Rank = i;
+ vlp = GetRowValue(g, jsp, n);
+ AddArrayValue(jvp,DupVal(vlp));
+ } // endfor i
+
+ jnp->Op = OP_XX;
+ jnp->Rank = 0;
+ } else if (jsp->Type == TYPE_JOB) {
+ jvp = NewVal(TYPE_JOB);
+
+ for (PBPR prp = GetObject(jsp); prp; prp = GetNext(prp)) {
+ vlp = GetRowValue(g, GetVlp(prp), n + 1);
+ SetKeyValue(jvp, vlp, MZP(prp->Key));
+ } // endfor prp
+
+ } // endif Type
+
+ } // endif's
+
+ Jb = true;
+ return jvp;
+} // end of MakeBson
+
+/***********************************************************************/
+/* GetRowValue: */
+/***********************************************************************/
+PBVAL BCUTIL::GetRowValue(PGLOBAL g, PBVAL row, int i)
+{
+ int nod = Cp->Nod;
+ JNODE *nodes = Cp->Nodes;
+ PBVAL arp;
+ PBVAL bvp = NULL;
+
+ for (; i < nod && row; i++) {
+ if (nodes[i].Op == OP_NUM) {
+ bvp = NewVal(TYPE_INT);
+ bvp->N = (row->Type == TYPE_JAR) ? GetSize(row) : 1;
+ return(bvp);
+ } else if (nodes[i].Op == OP_XX) {
+ return MakeBson(g, row, i);
+ } else switch (row->Type) {
+ case TYPE_JOB:
+ if (!nodes[i].Key) {
+ // Expected Array was not there, wrap the value
+ if (i < nod - 1)
+ continue;
+ else
+ bvp = row;
+
+ } else
+ bvp = GetKeyValue(row, nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ arp = row;
+
+ if (!nodes[i].Key) {
+ if (nodes[i].Op == OP_EQ)
+ bvp = GetArrayValue(arp, nodes[i].Rank);
+ else if (nodes[i].Op == OP_EXP)
+ return NewVal(ExpandArray(g, arp, i));
+ else
+ return NewVal(CalculateArray(g, arp, i));
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ bvp = GetArrayValue(arp, 0);
+ i--;
+ } // endif's
+
+ break;
+ case TYPE_JVAL:
+ bvp = row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->Type);
+ bvp = NULL;
+ } // endswitch Type
+
+ if (i < nod - 1)
+ row = bvp;
+
+ } // endfor i
+
+ return bvp;
+} // end of GetRowValue
+
+/***********************************************************************/
+/* GetColumnValue: */
+/***********************************************************************/
+PVAL BCUTIL::GetColumnValue(PGLOBAL g, PBVAL row, int i)
+{
+ PVAL value = Cp->Value;
+ PBVAL bvp = GetRowValue(g, row, i);
+
+ SetJsonValue(g, value, bvp);
+ return value;
+} // end of GetColumnValue
+
+/***********************************************************************/
+/* ExpandArray: */
+/***********************************************************************/
+PVAL BCUTIL::ExpandArray(PGLOBAL g, PBVAL arp, int n)
+{
+ int nod = Cp->Nod, ars = MY_MIN(Tp->Limit, GetArraySize(arp));
+ JNODE *nodes = Cp->Nodes;
+ PVAL value = Cp->Value;
+ PBVAL bvp;
+ BVAL bval;
+
+ if (!ars) {
+ value->Reset();
+ value->SetNull(true);
+ Tp->NextSame = 0;
+ return value;
+ } // endif ars
+
+ if (!(bvp = GetArrayValue(arp, (nodes[n].Rx = nodes[n].Nx)))) {
+ strcpy(g->Message, "Logical error expanding array");
+ throw 666;
+ } // endif jvp
+
+ if (n < nod - 1 && IsJson(bvp)) {
+ SetValue(&bval, GetColumnValue(g, bvp, n + 1));
+ bvp = &bval;
+ } // endif n
+
+ if (n >= Tp->NextSame) {
+ if (++nodes[n].Nx == ars) {
+ nodes[n].Nx = 0;
+ Cp->Xnod = 0;
+ } else
+ Cp->Xnod = n;
+
+ Tp->NextSame = Cp->Xnod;
+ } // endif NextSame
+
+ SetJsonValue(g, value, bvp);
+ return value;
+} // end of ExpandArray
+
+/***********************************************************************/
+/* CalculateArray: */
+/***********************************************************************/
+PVAL BCUTIL::CalculateArray(PGLOBAL g, PBVAL arp, int n)
+{
+ int i, ars, nv = 0, nextsame = Tp->NextSame;
+ bool err;
+ int nod = Cp->Nod;
+ JNODE *nodes = Cp->Nodes;
+ OPVAL op = nodes[n].Op;
+ PVAL val[2], vp = nodes[n].Valp, mulval = Cp->MulVal;
+ PBVAL jvrp, jvp;
+ BVAL jval;
+
+ vp->Reset();
+ ars = MY_MIN(Tp->Limit, GetArraySize(arp));
+ xtrc(1,"CalculateArray: size=%d op=%d nextsame=%d\n", ars, op, nextsame);
+
+ for (i = 0; i < ars; i++) {
+ jvrp = GetArrayValue(arp, i);
+ xtrc(1, "i=%d nv=%d\n", i, nv);
+
+ if (!IsValueNull(jvrp) || (op == OP_CNC && GetJsonNull())) do {
+ if (IsValueNull(jvrp)) {
+ SetString(jvrp, PlugDup(G, GetJsonNull()));
+ jvp = jvrp;
+ } else if (n < nod - 1 && IsJson(jvrp)) {
+ Tp->NextSame = nextsame;
+ SetValue(&jval, GetColumnValue(g, jvrp, n + 1));
+ jvp = &jval;
+ } else
+ jvp = jvrp;
+
+ xtrc(1, "jvp=%s null=%d\n", GetString(jvp), IsValueNull(jvp) ? 1 : 0);
+
+ if (!nv++) {
+ SetJsonValue(g, vp, jvp);
+ continue;
+ } else
+ SetJsonValue(g, mulval, jvp);
+
+ if (!mulval->IsNull()) {
+ switch (op) {
+ case OP_CNC:
+ if (nodes[n].CncVal) {
+ val[0] = nodes[n].CncVal;
+ err = vp->Compute(g, val, 1, op);
+ } // endif CncVal
+
+ val[0] = mulval;
+ err = vp->Compute(g, val, 1, op);
+ break;
+ // case OP_NUM:
+ case OP_SEP:
+ val[0] = nodes[n].Valp;
+ val[1] = mulval;
+ err = vp->Compute(g, val, 2, OP_ADD);
+ break;
+ default:
+ val[0] = nodes[n].Valp;
+ val[1] = mulval;
+ err = vp->Compute(g, val, 2, op);
+ } // endswitch Op
+
+ if (err)
+ vp->Reset();
+
+ if (trace(1)) {
+ char buf(32);
+
+ htrc("vp='%s' err=%d\n",
+ vp->GetCharString(&buf), err ? 1 : 0);
+
+ } // endif trace
+
+ } // endif Null
+
+ } while (Tp->NextSame > nextsame);
+
+ } // endfor i
+
+ if (op == OP_SEP) {
+ // Calculate average
+ mulval->SetValue(nv);
+ val[0] = vp;
+ val[1] = mulval;
+
+ if (vp->Compute(g, val, 2, OP_DIV))
+ vp->Reset();
+
+ } // endif Op
+
+ Tp->NextSame = nextsame;
+ return vp;
+} // end of CalculateArray
+
+/***********************************************************************/
+/* GetRow: Get the object containing this column. */
+/***********************************************************************/
+PBVAL BCUTIL::GetRow(PGLOBAL g)
+{
+ int nod = Cp->Nod;
+ JNODE *nodes = Cp->Nodes;
+ PBVAL val = NULL;
+ PBVAL arp;
+ PBVAL nwr, row = Tp->Row;
+
+ for (int i = 0; i < nod && row; i++) {
+ if (i < nod-1 && nodes[i+1].Op == OP_XX)
+ break;
+ else switch (row->Type) {
+ case TYPE_JOB:
+ if (!nodes[i].Key)
+ // Expected Array was not there, wrap the value
+ continue;
+
+ val = GetKeyValue(row, nodes[i].Key);
+ break;
+ case TYPE_JAR:
+ arp = row;
+
+ if (!nodes[i].Key) {
+ if (nodes[i].Op == OP_EQ)
+ val = GetArrayValue(arp, nodes[i].Rank);
+ else
+ val = GetArrayValue(arp, nodes[i].Rx);
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ val = GetArrayValue(arp, 0);
+ i--;
+ } // endif Nodes
+
+ break;
+ case TYPE_JVAL:
+ val = row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->Type);
+ val = NULL;
+ } // endswitch Type
+
+ if (val) {
+ row = val;
+ } else {
+ // Construct missing objects
+ for (i++; row && i < nod; i++) {
+ int type;
+
+ if (nodes[i].Op == OP_XX)
+ break;
+ else if (!nodes[i].Key)
+ // Construct intermediate array
+ type = TYPE_JAR;
+ else
+ type = TYPE_JOB;
+
+ if (row->Type == TYPE_JOB) {
+ nwr = AddPair(row, nodes[i - 1].Key, type);
+ } else if (row->Type == TYPE_JAR) {
+ AddArrayValue(row, (nwr = NewVal(type)));
+ } else {
+ strcpy(g->Message, "Wrong type when writing new row");
+ nwr = NULL;
+ } // endif's
+
+ row = nwr;
+ } // endfor i
+
+ break;
+ } // endelse
+
+ } // endfor i
+
+ return row;
+} // end of GetRow
+
+
+/* -------------------------- Class BSONDEF -------------------------- */
+
+BSONDEF::BSONDEF(void)
+{
+ Jmode = MODE_OBJECT;
+ Objname = NULL;
+ Xcol = NULL;
+ Pretty = 2;
+ Limit = 1;
+ Base = 0;
+ Strict = false;
+ Sep = '.';
+ Uri = NULL;
+ Collname = Options = Filter = NULL;
+ Pipe = false;
+ Driver = NULL;
+ Version = 0;
+ Wrapname = NULL;
+} // end of BSONDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values. */
+/***********************************************************************/
+bool BSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ G = g;
+ Schema = GetStringCatInfo(g, "DBname", Schema);
+ Jmode = (JMODE)GetIntCatInfo("Jmode", MODE_OBJECT);
+
+ if ((Objname = GetStringCatInfo(g, "Object", NULL))) {
+ if (*Objname == '$') Objname++;
+ if (*Objname == '.') Objname++;
+ } // endif Objname
+
+ Xcol = GetStringCatInfo(g, "Expand", NULL);
+ Pretty = GetIntCatInfo("Pretty", 2);
+ Limit = GetIntCatInfo("Limit", 50);
+ Base = GetIntCatInfo("Base", 0) ? 1 : 0;
+ Sep = *GetStringCatInfo(g, "Separator", ".");
+ Accept = GetBoolCatInfo("Accept", false);
+
+ // Don't use url as MONGO uri when called from REST
+ if (stricmp(am, "REST") && (Uri = GetStringCatInfo(g, "Connect", NULL))) {
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+ Collname = GetStringCatInfo(g, "Name",
+ (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
+ Collname = GetStringCatInfo(g, "Tabname", Collname);
+ Options = GetStringCatInfo(g, "Colist", Xcol ? "all" : NULL);
+ Filter = GetStringCatInfo(g, "Filter", NULL);
+ Pipe = GetBoolCatInfo("Pipeline", false);
+ Driver = GetStringCatInfo(g, "Driver", NULL);
+ Version = GetIntCatInfo("Version", 3);
+ Pretty = 0;
+#if defined(JAVA_SUPPORT)
+ if (Version == 2)
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface");
+ else
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface");
+#endif // JAVA_SUPPORT
+#else // !MONGO_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return true;
+#endif // !MONGO_SUPPORT
+ } // endif Uri
+
+ return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff);
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB BSONDEF::GetTable(PGLOBAL g, MODE m)
+{
+ if (trace(1))
+ htrc("BSON GetTable Pretty=%d Uri=%s\n", Pretty, SVP(Uri));
+
+ if (Catfunc == FNC_COL)
+ return new(g)TDBBCL(this);
+
+ PTDBASE tdbp;
+ PTXF txfp = NULL;
+
+ // JSN not used for pretty=1 for insert or delete
+ if (Pretty <= 0 || (Pretty == 1 && (m == MODE_READ || m == MODE_UPDATE))) {
+ USETEMP tmp = UseTemp();
+ bool map = Mapped && Pretty >= 0 && m != MODE_INSERT &&
+ !(tmp != TMP_NO && m == MODE_UPDATE) &&
+ !(tmp == TMP_FORCE && (m == MODE_UPDATE || m == MODE_DELETE));
+
+ if (Lrecl) {
+ // Allocate the parse work memory
+ G = PlugInit(NULL, (size_t)Lrecl * (Pretty < 0 ? 3 : 5));
+ } else {
+ strcpy(g->Message, "LRECL is not defined");
+ return NULL;
+ } // endif Lrecl
+
+ if (Pretty < 0) { // BJsonfile
+ txfp = new(g) BINFAM(this);
+ } else if (Uri) {
+ if (Driver && toupper(*Driver) == 'C') {
+#if defined(CMGO_SUPPORT)
+ txfp = new(g) CMGFAM(this);
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "C");
+ return NULL;
+#endif
+ } else if (Driver && toupper(*Driver) == 'J') {
+#if defined(JAVA_SUPPORT)
+ txfp = new(g) JMGFAM(this);
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "Java");
+ return NULL;
+#endif
+ } else { // Driver not specified
+#if defined(CMGO_SUPPORT)
+ txfp = new(g) CMGFAM(this);
+#elif defined(JAVA_SUPPORT)
+ txfp = new(g) JMGFAM(this);
+#else // !MONGO_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return NULL;
+#endif // !MONGO_SUPPORT
+ } // endif Driver
+
+ Pretty = 4; // Not a file
+ } else if (Zipped) {
+#if defined(ZIP_SUPPORT)
+ if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
+ txfp = new(g) UNZFAM(this);
+ } else if (m == MODE_INSERT) {
+ txfp = new(g) ZIPFAM(this);
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's m
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } else if (Compressed) {
+#if defined(GZ_SUPPORT)
+ if (Compressed == 1)
+ txfp = new(g) GZFAM(this);
+ else
+ txfp = new(g) ZLBFAM(this);
+#else // !GZ_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ");
+ return NULL;
+#endif // !GZ_SUPPORT
+ } else if (map) {
+ txfp = new(g) MAPFAM(this);
+ } else
+ txfp = new(g) DOSFAM(this);
+
+ // Txfp must be set for TDBBSN
+ tdbp = new(g) TDBBSN(g, this, txfp);
+ } else {
+ if (Zipped) {
+#if defined(ZIP_SUPPORT)
+ if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
+ txfp = new(g) UNZFAM(this);
+ } else if (m == MODE_INSERT) {
+ strcpy(g->Message, "INSERT supported only for zipped JSON when pretty=0");
+ return NULL;
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's m
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } else
+ txfp = new(g) MAPFAM(this);
+
+ tdbp = new(g) TDBBSON(g, this, txfp);
+ } // endif Pretty
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+
+ return tdbp;
+} // end of GetTable
+
+/* --------------------------- Class TDBBSN -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBBSN class (Pretty < 2) */
+/***********************************************************************/
+TDBBSN::TDBBSN(PGLOBAL g, PBDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
+{
+ Bp = new(g) BTUTIL(tdp->G, this);
+ Top = NULL;
+ Row = NULL;
+ Colp = NULL;
+
+ if (tdp) {
+ Jmode = tdp->Jmode;
+ Objname = tdp->Objname;
+ Xcol = tdp->Xcol;
+ Limit = tdp->Limit;
+ Pretty = tdp->Pretty;
+ B = tdp->Base ? 1 : 0;
+ Sep = tdp->Sep;
+ Strict = tdp->Strict;
+ } else {
+ Jmode = MODE_OBJECT;
+ Objname = NULL;
+ Xcol = NULL;
+ Limit = 1;
+ Pretty = 0;
+ B = 0;
+ Sep = '.';
+ Strict = false;
+ } // endif tdp
+
+ Fpos = -1;
+ N = M = 0;
+ NextSame = 0;
+ SameRow = 0;
+ Xval = -1;
+ Comma = false;
+ Bp->SetPretty(Pretty);
+} // end of TDBBSN standard constructor
+
+TDBBSN::TDBBSN(TDBBSN* tdbp) : TDBDOS(NULL, tdbp)
+{
+ Bp = tdbp->Bp;
+ Top = tdbp->Top;
+ Row = tdbp->Row;
+ Colp = tdbp->Colp;
+ Jmode = tdbp->Jmode;
+ Objname = tdbp->Objname;
+ Xcol = tdbp->Xcol;
+ Fpos = tdbp->Fpos;
+ N = tdbp->N;
+ M = tdbp->M;
+ Limit = tdbp->Limit;
+ NextSame = tdbp->NextSame;
+ SameRow = tdbp->SameRow;
+ Xval = tdbp->Xval;
+ B = tdbp->B;
+ Sep = tdbp->Sep;
+ Pretty = tdbp->Pretty;
+ Strict = tdbp->Strict;
+ Comma = tdbp->Comma;
+} // end of TDBBSN copy constructor
+
+// Used for update
+PTDB TDBBSN::Clone(PTABS t)
+{
+ PTDB tp;
+ PBSCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBBSN(this);
+
+ for (cp1 = (PBSCOL)Columns; cp1; cp1 = (PBSCOL)cp1->GetNext()) {
+ cp2 = new(g) BSONCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+} // end of Clone
+
+/***********************************************************************/
+/* Allocate JSN column description block. */
+/***********************************************************************/
+PCOL TDBBSN::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ PBSCOL colp = new(g) BSONCOL(g, cdp, this, cprec, n);
+
+ return (colp->ParseJpath(g)) ? NULL : colp;
+} // end of MakeCol
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBBSN::InsertSpecialColumn(PCOL colp)
+{
+ if (!colp->IsSpecial())
+ return NULL;
+
+ //if (Xcol && ((SPCBLK*)colp)->GetRnm())
+ // colp->SetKey(0); // Rownum is no more a key
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+} // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* JSON Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBBSN::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 0;
+ else if (Cardinal < 0) {
+ Cardinal = TDBDOS::Cardinality(g);
+
+ } // endif Cardinal
+
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* JSON GetMaxSize: returns file size estimate in number of lines. */
+/***********************************************************************/
+int TDBBSN::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = TDBDOS::GetMaxSize(g) * ((Xcol) ? Limit : 1);
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* JSON EstimatedLength. Returns an estimated minimum line length. */
+/***********************************************************************/
+int TDBBSN::EstimatedLength(void)
+{
+ if (AvgLen <= 0)
+ return (Lrecl ? Lrecl : 1024) / 8; // TODO: make it better
+ else
+ return AvgLen;
+
+} // end of Estimated Length
+
+/***********************************************************************/
+/* OpenDB: Data Base open routine for BSN access method. */
+/***********************************************************************/
+bool TDBBSN::OpenDB(PGLOBAL g)
+{
+ TUSE use = Use;
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open replace it at its beginning. ??? */
+ /*******************************************************************/
+ Fpos = -1;
+ NextSame = 0;
+ SameRow = 0;
+ } // endif Use
+
+ /*********************************************************************/
+ /* Open according to logical input/output mode required. */
+ /*********************************************************************/
+ if (TDBDOS::OpenDB(g))
+ return true;
+
+ if (use == USE_OPEN)
+ return false;
+
+ if (Pretty < 0) {
+ /*********************************************************************/
+ /* Binary BJSON table. */
+ /*********************************************************************/
+ xtrc(1, "JSN OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ // Lrecl is Ok
+ size_t linelen = Lrecl;
+ MODE mode = Mode;
+
+ // Buffer must be allocated in G->Sarea
+ Mode = MODE_ANY;
+ Txfp->AllocateBuffer(Bp->G);
+ Mode = mode;
+
+ if (Mode == MODE_INSERT)
+ Bp->SubSet(true);
+ else
+ Bp->MemSave();
+
+ To_Line = Txfp->GetBuf();
+ memset(To_Line, 0, linelen);
+ xtrc(1, "OpenJSN: R%hd mode=%d To_Line=%p\n", Tdb_No, Mode, To_Line);
+ } // endif Pretty
+
+ /***********************************************************************/
+ /* First opening. */
+ /***********************************************************************/
+ if (Mode == MODE_INSERT) {
+ int type;
+
+ switch (Jmode) {
+ case MODE_OBJECT: type = TYPE_JOB; break;
+ case MODE_ARRAY: type = TYPE_JAR; break;
+ case MODE_VALUE: type = TYPE_JVAL; break;
+ default:
+ sprintf(g->Message, "Invalid Jmode %d", Jmode);
+ return true;
+ } // endswitch Jmode
+
+ Top = Bp->MakeTopTree(g, type);
+ Bp->MemSave();
+ } // endif Mode
+
+ if (Xcol)
+ To_Filter = NULL; // Not compatible
+
+ return false;
+} // end of OpenDB
+
+/***********************************************************************/
+/* SkipHeader: Physically skip first header line if applicable. */
+/* This is called from TDBDOS::OpenDB and must be executed before */
+/* Kindex construction if the file is accessed using an index. */
+/***********************************************************************/
+bool TDBBSN::SkipHeader(PGLOBAL g)
+{
+ int len = GetFileLength(g);
+ bool rc = false;
+
+#if defined(_DEBUG)
+ if (len < 0)
+ return true;
+#endif // _DEBUG
+
+ if (Pretty == 1) {
+ if (Mode == MODE_INSERT || Mode == MODE_DELETE) {
+ // Mode Insert and delete are no more handled here
+ DBUG_ASSERT(false);
+ } else if (len > 0) // !Insert && !Delete
+ rc = (Txfp->SkipRecord(g, false) == RC_FX || Txfp->RecordPos(g));
+
+ } // endif Pretty
+
+ return rc;
+} // end of SkipHeader
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for JSN access method. */
+/***********************************************************************/
+int TDBBSN::ReadDB(PGLOBAL g)
+{
+ int rc;
+
+ N++;
+
+ if (NextSame) {
+ SameRow = NextSame;
+ NextSame = 0;
+ M++;
+ return RC_OK;
+ } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK) {
+ if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK))
+ return rc; // Deferred reading failed
+
+ if (Pretty >= 0) {
+ // Recover the memory used for parsing
+ Bp->SubSet();
+
+ if ((Row = Bp->ParseLine(g, Pretty, Comma))) {
+ Top = Row;
+ Row = Bp->FindRow(g);
+ SameRow = 0;
+ Fpos++;
+ M = 1;
+ rc = RC_OK;
+ } else if (Pretty != 1 || strcmp(To_Line, "]")) {
+ Bp->GetMsg(g);
+ rc = RC_FX;
+ } else
+ rc = RC_EF;
+
+ } else { // Here we get a movable Json binary tree
+ Bp->MemSet(((BINFAM*)Txfp)->Recsize); // Useful when updating
+ Row = Top = (PBVAL)To_Line;
+ Row = Bp->FindRow(g);
+ SameRow = 0;
+ Fpos++;
+ M = 1;
+ rc = RC_OK;
+ } // endif Pretty
+
+ } // endif ReadDB
+
+ return rc;
+} // end of ReadDB
+
+/***********************************************************************/
+/* PrepareWriting: Prepare the line for WriteDB. */
+/***********************************************************************/
+bool TDBBSN::PrepareWriting(PGLOBAL g)
+{
+ if (Pretty >= 0) {
+ PSZ s;
+
+// if (!(Top = Bp->MakeTopTree(g, Row->Type)))
+// return true;
+
+ if ((s = Bp->SerialVal(g, Top, Pretty))) {
+ if (Comma)
+ strcat(s, ",");
+
+ if ((signed)strlen(s) > Lrecl) {
+ strncpy(To_Line, s, Lrecl);
+ sprintf(g->Message, "Line truncated (lrecl=%d)", Lrecl);
+ return PushWarning(g, this);
+ } else
+ strcpy(To_Line, s);
+
+ return false;
+ } else
+ return true;
+ } else
+ ((BINFAM*)Txfp)->Recsize = ((size_t)PlugSubAlloc(Bp->G, NULL, 0)
+ - (size_t)To_Line);
+ return false;
+} // end of PrepareWriting
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for JSON access method. */
+/***********************************************************************/
+int TDBBSN::WriteDB(PGLOBAL g) {
+ int rc = TDBDOS::WriteDB(g);
+
+ Bp->SubSet();
+ Bp->Clear(Row);
+ return rc;
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base close routine for JSON access method. */
+/***********************************************************************/
+void TDBBSN::CloseDB(PGLOBAL g)
+{
+ TDBDOS::CloseDB(g);
+ Bp->G = PlugExit(Bp->G);
+} // end of CloseDB
+
+/* ---------------------------- BSONCOL ------------------------------ */
+
+/***********************************************************************/
+/* BSONCOL public constructor. */
+/***********************************************************************/
+BSONCOL::BSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : DOSCOL(g, cdp, tdbp, cprec, i, "DOS")
+{
+ Tbp = (TDBBSN*)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
+ Cp = new(g) BCUTIL(((PBDEF)Tbp->To_Def)->G, this, Tbp);
+ Jpath = cdp->GetFmt();
+ MulVal = NULL;
+ Nodes = NULL;
+ Nod = 0;
+ Sep = Tbp->Sep;
+ Xnod = -1;
+ Xpd = false;
+ Parsed = false;
+ Warned = false;
+ Sgfy = false;
+} // end of BSONCOL constructor
+
+/***********************************************************************/
+/* BSONCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+BSONCOL::BSONCOL(BSONCOL* col1, PTDB tdbp) : DOSCOL(col1, tdbp)
+{
+ Tbp = col1->Tbp;
+ Cp = col1->Cp;
+ Jpath = col1->Jpath;
+ MulVal = col1->MulVal;
+ Nodes = col1->Nodes;
+ Nod = col1->Nod;
+ Sep = col1->Sep;
+ Xnod = col1->Xnod;
+ Xpd = col1->Xpd;
+ Parsed = col1->Parsed;
+ Warned = col1->Warned;
+ Sgfy = col1->Sgfy;
+} // end of BSONCOL copy constructor
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool BSONCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+{
+ if (DOSCOL::SetBuffer(g, value, ok, check))
+ return true;
+
+ // Parse the json path
+ if (ParseJpath(g))
+ return true;
+
+ Tbp = (TDBBSN*)To_Tdb;
+ return false;
+} // end of SetBuffer
+
+/***********************************************************************/
+/* Check whether this object is expanded. */
+/***********************************************************************/
+bool BSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b)
+{
+ if ((Tbp->Xcol && nm && !strcmp(nm, Tbp->Xcol) &&
+ (Tbp->Xval < 0 || Tbp->Xval == i)) || Xpd) {
+ Xpd = true; // Expandable object
+ Nodes[i].Op = OP_EXP;
+ } else if (b) {
+ strcpy(g->Message, "Cannot expand more than one branch");
+ return true;
+ } // endif Xcol
+
+ return false;
+} // end of CheckExpand
+
+/***********************************************************************/
+/* Analyse array processing options. */
+/***********************************************************************/
+bool BSONCOL::SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm)
+{
+ int n;
+ bool dg = true, b = false;
+ PJNODE jnp = &Nodes[i];
+
+ //if (*p == '[') p++; // Old syntax .[ or :[
+ n = (int)strlen(p);
+
+ if (*p) {
+ if (p[n - 1] == ']') {
+ p[--n] = 0;
+ } else if (!IsNum(p)) {
+ // Wrong array specification
+ sprintf(g->Message, "Invalid array specification %s for %s", p, Name);
+ return true;
+ } // endif p
+
+ } else
+ b = true;
+
+ // To check whether a numeric Rank was specified
+ dg = IsNum(p);
+
+ if (!n) {
+ // Default specifications
+ if (CheckExpand(g, i, nm, false))
+ return true;
+ else if (jnp->Op != OP_EXP) {
+ if (b) {
+ // Return 1st value (B is the index base)
+ jnp->Rank = Tbp->B;
+ jnp->Op = OP_EQ;
+ } else if (!Value->IsTypeNum()) {
+ jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING);
+ jnp->Op = OP_CNC;
+ } else
+ jnp->Op = OP_ADD;
+
+ } // endif OP
+
+ } else if (dg) {
+ // Return nth value
+ jnp->Rank = atoi(p) - Tbp->B;
+ jnp->Op = OP_EQ;
+ } else if (n == 1) {
+ // Set the Op value;
+ if (Sep == ':')
+ switch (*p) {
+ case '*': *p = 'x'; break;
+ case 'x':
+ case 'X': *p = '*'; break; // Expand this array
+ default: break;
+ } // endswitch p
+
+ switch (*p) {
+ case '+': jnp->Op = OP_ADD; break;
+ case 'x': jnp->Op = OP_MULT; break;
+ case '>': jnp->Op = OP_MAX; break;
+ case '<': jnp->Op = OP_MIN; break;
+ case '!': jnp->Op = OP_SEP; break; // Average
+ case '#': jnp->Op = OP_NUM; break;
+ case '*': // Expand this array
+ if (!Tbp->Xcol && nm) {
+ Xpd = true;
+ jnp->Op = OP_EXP;
+ Tbp->Xval = i;
+ Tbp->Xcol = nm;
+ } else if (CheckExpand(g, i, nm, true))
+ return true;
+
+ break;
+ default:
+ sprintf(g->Message,
+ "Invalid function specification %c for %s", *p, Name);
+ return true;
+ } // endswitch *p
+
+ } else if (*p == '"' && p[n - 1] == '"') {
+ // This is a concat specification
+ jnp->Op = OP_CNC;
+
+ if (n > 2) {
+ // Set concat intermediate string
+ p[n - 1] = 0;
+ jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
+ } // endif n
+
+ } else {
+ sprintf(g->Message, "Wrong array specification for %s", Name);
+ return true;
+ } // endif's
+
+ // For calculated arrays, a local Value must be used
+ switch (jnp->Op) {
+ case OP_NUM:
+ jnp->Valp = AllocateValue(g, TYPE_INT);
+ break;
+ case OP_ADD:
+ case OP_MULT:
+ case OP_SEP:
+ if (!IsTypeChar(Buf_Type))
+ jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
+ else
+ jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
+
+ break;
+ case OP_MIN:
+ case OP_MAX:
+ jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
+ break;
+ case OP_CNC:
+ if (IsTypeChar(Buf_Type))
+ jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
+ else
+ jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
+
+ break;
+ default:
+ break;
+ } // endswitch Op
+
+ if (jnp->Valp)
+ MulVal = AllocateValue(g, jnp->Valp);
+
+ return false;
+} // end of SetArrayOptions
+
+/***********************************************************************/
+/* Parse the eventual passed Jpath information. */
+/* This information can be specified in the Fieldfmt column option */
+/* when creating the table. It permits to indicate the position of */
+/* the node corresponding to that column. */
+/***********************************************************************/
+bool BSONCOL::ParseJpath(PGLOBAL g)
+{
+ char* p, * p1 = NULL, * p2 = NULL, * pbuf = NULL;
+ int i;
+ bool a;
+
+ if (Parsed)
+ return false; // Already done
+ else if (InitValue(g))
+ return true;
+ else if (!Jpath)
+ Jpath = Name;
+
+ if (To_Tdb->GetOrig()) {
+ // This is an updated column, get nodes from origin
+ for (PBSCOL colp = (PBSCOL)Tbp->GetColumns(); colp;
+ colp = (PBSCOL)colp->GetNext())
+ if (!stricmp(Name, colp->GetName())) {
+ Nod = colp->Nod;
+ Nodes = colp->Nodes;
+ Xpd = colp->Xpd;
+ goto fin;
+ } // endif Name
+
+ sprintf(g->Message, "Cannot parse updated column %s", Name);
+ return true;
+ } // endif To_Orig
+
+ pbuf = PlugDup(g, Jpath);
+ if (*pbuf == '$') pbuf++;
+ if (*pbuf == Sep) pbuf++;
+ if (*pbuf == '[') p1 = pbuf++;
+
+ // Estimate the required number of nodes
+ for (i = 0, p = pbuf; (p = NextChr(p, Sep)); i++, p++)
+ Nod++; // One path node found
+
+ Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE));
+ memset(Nodes, 0, (Nod) * sizeof(JNODE));
+
+ // Analyze the Jpath for this column
+ for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
+ a = (p1 != NULL);
+ p1 = strchr(p, '[');
+ p2 = strchr(p, Sep);
+
+ if (!p2)
+ p2 = p1;
+ else if (p1) {
+ if (p1 < p2)
+ p2 = p1;
+ else if (p1 == p2 + 1)
+ *p2++ = 0; // Old syntax .[ or :[
+ else
+ p1 = NULL;
+
+ } // endif p1
+
+ if (p2)
+ *p2++ = 0;
+
+ // Jpath must be explicit
+ if (a || *p == 0 || *p == '[' || IsNum(p)) {
+ // Analyse intermediate array processing
+ if (SetArrayOptions(g, p, i, Nodes[i - 1].Key))
+ return true;
+ else if (Xpd && Tbp->Mode == MODE_DELETE) {
+ strcpy(g->Message, "Cannot delete expanded columns");
+ return true;
+ } // endif Xpd
+
+ } else if (*p == '*') {
+ // Return JSON
+ Nodes[i].Op = OP_XX;
+ } else {
+ Nodes[i].Key = p;
+ Nodes[i].Op = OP_EXIST;
+ } // endif's
+
+ } // endfor i, p
+
+ Nod = i;
+
+fin:
+ MulVal = AllocateValue(g, Value);
+ Parsed = true;
+ return false;
+} // end of ParseJpath
+
+/***********************************************************************/
+/* Get Jpath converted to Mongo path. */
+/***********************************************************************/
+PSZ BSONCOL::GetJpath(PGLOBAL g, bool proj)
+{
+ if (Jpath) {
+ char* p1, * p2, * mgopath;
+ int i = 0;
+
+ if (strcmp(Jpath, "*")) {
+ p1 = Jpath;
+ if (*p1 == '$') p1++;
+ if (*p1 == '.') p1++;
+ mgopath = PlugDup(g, p1);
+ } else {
+ Sgfy = true;
+ return NULL;
+ } // endif
+
+ for (p1 = p2 = mgopath; *p1; p1++)
+ {
+ if (i) { // Inside []
+ if (isdigit(*p1)) {
+ if (!proj)
+ *p2++ = *p1;
+
+ } else if (*p1 == ']' && i == 1) {
+ if (proj && p1[1] == '.')
+ p1++;
+
+ i = 0;
+ } else if (*p1 == '.' && i == 2) {
+ if (!proj)
+ *p2++ = '.';
+
+ i = 0;
+ } else if (!proj)
+ return NULL;
+
+ } else switch (*p1) {
+ case ':':
+ case '.':
+ if (isdigit(p1[1]))
+ i = 2;
+
+ *p2++ = '.';
+ break;
+ case '[':
+ if (*(p2 - 1) != '.')
+ *p2++ = '.';
+
+ i = 1;
+ break;
+ case '*':
+ if (*(p2 - 1) == '.' && !*(p1 + 1)) {
+ p2--; // Suppress last :*
+ Sgfy = true;
+ break;
+ } // endif p2
+ /* fall through */
+ default:
+ *p2++ = *p1;
+ break;
+ } // endswitch p1;
+ }
+
+ if (*(p2 - 1) == '.')
+ p2--;
+
+ *p2 = 0;
+ return mgopath;
+ } else
+ return NULL;
+
+} // end of GetJpath
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void BSONCOL::ReadColumn(PGLOBAL g)
+{
+ if (!Tbp->SameRow || Xnod >= Tbp->SameRow)
+ Value->SetValue_pval(Cp->GetColumnValue(g, Tbp->Row, 0));
+
+#if defined(DEVELOPMENT)
+ if (Xpd && Value->IsNull() && !((PBDEF)Tbp->To_Def)->Accept)
+ htrc("Null expandable JSON value for column %s\n", Name);
+#endif // DEVELOPMENT
+
+ // Set null when applicable
+ if (!Nullable)
+ Value->SetNull(false);
+
+} // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: */
+/***********************************************************************/
+void BSONCOL::WriteColumn(PGLOBAL g)
+{
+ if (Xpd && Tbp->Pretty < 2) {
+ strcpy(g->Message, "Cannot write expanded column when Pretty is not 2");
+ throw 666;
+ } // endif Xpd
+
+ /*********************************************************************/
+ /* Check whether this node must be written. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, FALSE); // Convert the updated value
+
+ /*********************************************************************/
+ /* On INSERT Null values are represented by no node. */
+ /*********************************************************************/
+ if (Value->IsNull() && Tbp->Mode == MODE_INSERT)
+ return;
+
+ PBVAL jsp, row = Cp->GetRow(g);
+
+ if (row) switch (Buf_Type) {
+ case TYPE_STRING:
+ case TYPE_DATE:
+ case TYPE_INT:
+ case TYPE_TINY:
+ case TYPE_SHORT:
+ case TYPE_BIGINT:
+ case TYPE_DOUBLE:
+ if (Buf_Type == TYPE_STRING && Nodes[Nod - 1].Op == OP_XX) {
+ char *s = Value->GetCharValue();
+
+ if (!(jsp = Cp->ParseJson(g, s, strlen(s)))) {
+ strcpy(g->Message, s);
+ throw 666;
+ } // endif jsp
+
+ switch (row->Type) {
+ case TYPE_JAR:
+ if (Nod > 1 && Nodes[Nod - 2].Op == OP_EQ)
+ Cp->SetArrayValue(row, jsp, Nodes[Nod - 2].Rank);
+ else
+ Cp->AddArrayValue(row, jsp);
+
+ break;
+ case TYPE_JOB:
+ if (Nod > 1 && Nodes[Nod - 2].Key)
+ Cp->SetKeyValue(row, jsp, Nodes[Nod - 2].Key);
+
+ break;
+ case TYPE_JVAL:
+ default:
+ Cp->SetValueVal(row, jsp);
+ } // endswitch Type
+
+ break;
+ } else
+ jsp = Cp->NewVal(Value);
+
+ switch (row->Type) {
+ case TYPE_JAR:
+ if (Nodes[Nod - 1].Op == OP_EQ)
+ Cp->SetArrayValue(row, jsp, Nodes[Nod - 1].Rank);
+ else
+ Cp->AddArrayValue(row, jsp);
+
+ break;
+ case TYPE_JOB:
+ if (Nodes[Nod - 1].Key)
+ Cp->SetKeyValue(row, jsp, Nodes[Nod - 1].Key);
+
+ break;
+ case TYPE_JVAL:
+ default:
+ Cp->SetValueVal(row, jsp);
+ } // endswitch Type
+
+ break;
+ default: // ??????????
+ sprintf(g->Message, "Invalid column type %d", Buf_Type);
+ } // endswitch Type
+
+} // end of WriteColumn
+
+/* -------------------------- Class TDBBSON -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBBSON class. */
+/***********************************************************************/
+TDBBSON::TDBBSON(PGLOBAL g, PBDEF tdp, PTXF txfp) : TDBBSN(g, tdp, txfp)
+{
+ Docp = NULL;
+ Multiple = tdp->Multiple;
+ Done = Changed = false;
+ Bp->SetPretty(2);
+} // end of TDBBSON standard constructor
+
+TDBBSON::TDBBSON(PBTDB tdbp) : TDBBSN(tdbp)
+{
+ Docp = tdbp->Docp;
+ Multiple = tdbp->Multiple;
+ Done = tdbp->Done;
+ Changed = tdbp->Changed;
+} // end of TDBBSON copy constructor
+
+// Used for update
+PTDB TDBBSON::Clone(PTABS t)
+{
+ PTDB tp;
+ PBSCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBBSON(this);
+
+ for (cp1 = (PBSCOL)Columns; cp1; cp1 = (PBSCOL)cp1->GetNext()) {
+ cp2 = new(g) BSONCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+} // end of Clone
+
+/***********************************************************************/
+/* Make the document tree from the object path. */
+/***********************************************************************/
+int TDBBSON::MakeNewDoc(PGLOBAL g)
+{
+ // Create a void table that will be populated
+ Docp = Bp->NewVal(TYPE_JAR);
+
+ if (!(Top = Bp->MakeTopTree(g, TYPE_JAR)))
+ return RC_FX;
+
+ Docp = Row;
+ Done = true;
+ return RC_OK;
+} // end of MakeNewDoc
+
+/***********************************************************************/
+/* Make the document tree from a file. */
+/***********************************************************************/
+int TDBBSON::MakeDocument(PGLOBAL g)
+{
+ char *p, *p1, *p2, *memory, *objpath, *key = NULL;
+ int i = 0;
+ size_t len;
+ my_bool a;
+ MODE mode = Mode;
+ PBVAL jsp;
+ PBVAL objp = NULL;
+ PBVAL arp = NULL;
+ PBVAL val = NULL;
+
+ if (Done)
+ return RC_OK;
+
+ /*********************************************************************/
+ /* Create the mapping file object in mode read. */
+ /*********************************************************************/
+ Mode = MODE_READ;
+
+ if (!Txfp->OpenTableFile(g)) {
+ PFBLOCK fp = Txfp->GetTo_Fb();
+
+ if (fp) {
+ len = fp->Length;
+ memory = fp->Memory;
+ } else {
+ Mode = mode; // Restore saved Mode
+ return MakeNewDoc(g);
+ } // endif fp
+
+ } else
+ return RC_FX;
+
+ /*********************************************************************/
+ /* Parse the json file and allocate its tree structure. */
+ /*********************************************************************/
+ g->Message[0] = 0;
+ jsp = Top = Bp->ParseJson(g, memory, len);
+ Txfp->CloseTableFile(g, false);
+ Mode = mode; // Restore saved Mode
+
+ if (!jsp && g->Message[0])
+ return RC_FX;
+
+ if ((objpath = PlugDup(g, Objname))) {
+ p1 = (*objpath == '[') ? objpath++ : NULL;
+
+ /*********************************************************************/
+ /* Find the table in the tree structure. */
+ /*********************************************************************/
+ for (p = objpath; jsp && p; p = (p2 ? p2 : NULL)) {
+ a = (p1 != NULL);
+ p1 = strchr(p, '[');
+ p2 = strchr(p, '.');
+
+ if (!p2)
+ p2 = p1;
+ else if (p1) {
+ if (p1 < p2)
+ p2 = p1;
+ else if (p1 == p2 + 1)
+ *p2++ = 0; // Old syntax .[
+ else
+ p1 = NULL;
+
+ } // endif p1
+
+ if (p2)
+ *p2++ = 0;
+
+ if (!a && *p && *p != '[' && !IsNum(p)) {
+ // obj is a key
+ if (jsp->Type != TYPE_JOB) {
+ strcpy(g->Message, "Table path does not match the json file");
+ return RC_FX;
+ } // endif Type
+
+ key = p;
+ objp = jsp;
+ arp = NULL;
+ val = Bp->GetKeyValue(objp, key);
+
+ if (!val || !(jsp = Bp->GetBson(val))) {
+ sprintf(g->Message, "Cannot find object key %s", key);
+ return RC_FX;
+ } // endif val
+
+ } else {
+ if (*p == '[') {
+ // Old style
+ if (p[strlen(p) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path near %s", p);
+ return RC_FX;
+ } else
+ p++;
+
+ } // endif p
+
+ if (jsp->Type != TYPE_JAR) {
+ strcpy(g->Message, "Table path does not match the json file");
+ return RC_FX;
+ } // endif Type
+
+ arp = jsp;
+ objp = NULL;
+ i = atoi(p) - B;
+ val = Bp->GetArrayValue(arp, i);
+
+ if (!val) {
+ sprintf(g->Message, "Cannot find array value %d", i);
+ return RC_FX;
+ } // endif val
+
+ } // endif
+
+ jsp = val;
+ } // endfor p
+
+ } // endif objpath
+
+ if (jsp && jsp->Type == TYPE_JAR)
+ Docp = jsp;
+ else {
+ // The table is void or is just one object or one value
+ if (objp) {
+ Docp = Bp->GetKeyValue(objp, key);
+ Docp->To_Val = Bp->MOF(Bp->DupVal(Docp));
+ Docp->Type = TYPE_JAR;
+ } else if (arp) {
+ Docp = Bp->NewVal(TYPE_JAR);
+ Bp->AddArrayValue(Docp, jsp);
+ Bp->SetArrayValue(arp, Docp, i);
+ } else {
+ Top = Docp = Bp->NewVal(TYPE_JAR);
+ Bp->AddArrayValue(Docp, jsp);
+ } // endif's
+
+ } // endif jsp
+
+ Done = true;
+ return RC_OK;
+} // end of MakeDocument
+
+/***********************************************************************/
+/* JSON Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBBSON::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return (Xcol || Multiple) ? 0 : 1;
+ else if (Cardinal < 0) {
+ if (!Multiple) {
+ if (MakeDocument(g) == RC_OK)
+ Cardinal = Bp->GetSize(Docp);
+
+ } else
+ return 10;
+
+ } // endif Cardinal
+
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* JSON GetMaxSize: returns table size estimate in number of rows. */
+/***********************************************************************/
+int TDBBSON::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = Cardinality(g) * ((Xcol) ? Limit : 1);
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* ResetSize: call by TDBMUL when calculating size estimate. */
+/***********************************************************************/
+void TDBBSON::ResetSize(void)
+{
+ MaxSize = Cardinal = -1;
+ Fpos = -1;
+ N = 0;
+ Done = false;
+} // end of ResetSize
+
+/***********************************************************************/
+/* TDBBSON is not indexable. */
+/***********************************************************************/
+int TDBBSON::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool)
+{
+ if (pxdf) {
+ strcpy(g->Message, "JSON not indexable when pretty = 2");
+ return RC_FX;
+ } else
+ return RC_OK;
+
+} // end of MakeIndex
+
+/***********************************************************************/
+/* Return the position in the table. */
+/***********************************************************************/
+int TDBBSON::GetRecpos(void)
+{
+#if 0
+ union {
+ uint Rpos;
+ BYTE Spos[4];
+ };
+
+ Rpos = htonl(Fpos);
+ Spos[0] = (BYTE)NextSame;
+ return Rpos;
+#endif // 0
+ return Fpos;
+} // end of GetRecpos
+
+/***********************************************************************/
+/* Set the position in the table. */
+/***********************************************************************/
+bool TDBBSON::SetRecpos(PGLOBAL, int recpos)
+{
+#if 0
+ union {
+ uint Rpos;
+ BYTE Spos[4];
+ };
+
+ Rpos = recpos;
+ NextSame = Spos[0];
+ Spos[0] = 0;
+ Fpos = (signed)ntohl(Rpos);
+
+ //if (Fpos != (signed)ntohl(Rpos)) {
+ // Fpos = ntohl(Rpos);
+ // same = false;
+ //} else
+ // same = true;
+#endif // 0
+
+ Fpos = recpos - 1;
+ return false;
+} // end of SetRecpos
+
+/***********************************************************************/
+/* JSON Access Method opening routine. */
+/***********************************************************************/
+bool TDBBSON::OpenDB(PGLOBAL g)
+{
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open replace it at its beginning. */
+ /*******************************************************************/
+ Fpos = -1;
+ NextSame = false;
+ SameRow = 0;
+ return false;
+ } // endif use
+
+/*********************************************************************/
+/* OpenDB: initialize the JSON file processing. */
+/*********************************************************************/
+ if (MakeDocument(g) != RC_OK)
+ return true;
+
+ if (Mode == MODE_INSERT)
+ switch (Jmode) {
+ case MODE_OBJECT: Row = Bp->NewVal(TYPE_JOB); break;
+ case MODE_ARRAY: Row = Bp->NewVal(TYPE_JAR); break;
+ case MODE_VALUE: Row = Bp->NewVal(TYPE_JVAL); break;
+ default:
+ sprintf(g->Message, "Invalid Jmode %d", Jmode);
+ return true;
+ } // endswitch Jmode
+
+ if (Xcol)
+ To_Filter = NULL; // Imcompatible
+
+ Use = USE_OPEN;
+ return false;
+} // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for JSON access method. */
+/***********************************************************************/
+int TDBBSON::ReadDB(PGLOBAL)
+{
+ int rc;
+
+ N++;
+
+ if (NextSame) {
+ SameRow = NextSame;
+ NextSame = false;
+ M++;
+ rc = RC_OK;
+ } else if (++Fpos < (signed)Bp->GetSize(Docp)) {
+ Row = Bp->GetArrayValue(Docp, Fpos);
+
+ if (Row->Type == TYPE_JVAL)
+ Row = Bp->GetBson(Row);
+
+ SameRow = 0;
+ M = 1;
+ rc = RC_OK;
+ } else
+ rc = RC_EF;
+
+ return rc;
+} // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for JSON access method. */
+/***********************************************************************/
+int TDBBSON::WriteDB(PGLOBAL g)
+{
+ if (Mode == MODE_INSERT) {
+ Bp->AddArrayValue(Docp, Row);
+
+ switch(Jmode) {
+ case MODE_OBJECT: Row = Bp->NewVal(TYPE_JOB); break;
+ case MODE_ARRAY: Row = Bp->NewVal(TYPE_JAR); break;
+ default: Row = Bp->NewVal(); break;
+ } // endswitch Jmode
+
+ } else
+ Bp->SetArrayValue(Docp, Row, Fpos);
+
+ Changed = true;
+ return RC_OK;
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for JSON access method. */
+/***********************************************************************/
+int TDBBSON::DeleteDB(PGLOBAL g, int irc)
+{
+ if (irc == RC_OK)
+ // Deleted current row
+ Bp->DeleteValue(Docp, Fpos);
+ else if (irc == RC_FX)
+ // Delete all
+ Docp->To_Val = 0;
+
+ Changed = true;
+ return RC_OK;
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for JSON access methods. */
+/***********************************************************************/
+void TDBBSON::CloseDB(PGLOBAL g)
+{
+ if (!Changed)
+ return;
+
+ // Save the modified document
+ char filename[_MAX_PATH];
+
+//Docp->InitArray(g);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, ((PBDEF)To_Def)->Fn, GetPath());
+
+ // Serialize the modified table
+ if (!Bp->Serialize(g, Top, filename, Pretty))
+ puts(g->Message);
+
+} // end of CloseDB
+
+/* ---------------------------TDBBCL class --------------------------- */
+
+/***********************************************************************/
+/* TDBBCL class constructor. */
+/***********************************************************************/
+TDBBCL::TDBBCL(PBDEF tdp) : TDBCAT(tdp) {
+ Topt = tdp->GetTopt();
+ Db = tdp->Schema;
+ Dsn = tdp->Uri;
+} // end of TDBBCL constructor
+
+/***********************************************************************/
+/* GetResult: Get the list the JSON file columns. */
+/***********************************************************************/
+PQRYRES TDBBCL::GetResult(PGLOBAL g) {
+ return BSONColumns(g, Db, Dsn, Topt, false);
+} // end of GetResult
+
+/* --------------------------- End of json --------------------------- */
diff --git a/storage/connect/tabbson.h b/storage/connect/tabbson.h
new file mode 100644
index 00000000..7f41bba6
--- /dev/null
+++ b/storage/connect/tabbson.h
@@ -0,0 +1,342 @@
+/*************** tabbson H Declares Source Code File (.H) **************/
+/* Name: tabbson.h Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2020 - 2021 */
+/* */
+/* This file contains the BSON classes declares. */
+/***********************************************************************/
+#pragma once
+#include "block.h"
+#include "colblk.h"
+#include "bson.h"
+#include "tabjson.h"
+
+typedef class BTUTIL* PBTUT;
+typedef class BCUTIL* PBCUT;
+typedef class BSONDEF* PBDEF;
+typedef class TDBBSON* PBTDB;
+typedef class BSONCOL* PBSCOL;
+class TDBBSN;
+DllExport PQRYRES BSONColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool);
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+class BSONDISC : public BLOCK {
+public:
+ // Constructor
+ BSONDISC(PGLOBAL g, uint* lg);
+
+ // Functions
+ int GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt);
+ bool Find(PGLOBAL g, PBVAL jvp, PCSZ key, int j);
+ void AddColumn(PGLOBAL g);
+
+ // Members
+ JCOL jcol;
+ PJCL jcp, fjcp, pjcp;
+ //PVL vlp;
+ PBDEF tdp;
+ TDBBSN *tjnp;
+ PBTDB tjsp;
+ PBPR jpp;
+ PBVAL jsp;
+ PBPR row;
+ PBTUT bp;
+ PCSZ sep;
+ PCSZ strfy;
+ char colname[65], fmt[129], buf[16];
+ uint *length;
+ int i, n, bf, ncol, lvl, sz, limit;
+ bool all;
+}; // end of BSONDISC
+
+/***********************************************************************/
+/* JSON table. */
+/***********************************************************************/
+class DllExport BSONDEF : public DOSDEF { /* Table description */
+ friend class TDBBSON;
+ friend class TDBBSN;
+ friend class TDBBCL;
+ friend class BSONDISC;
+ friend class BSONCOL;
+#if defined(CMGO_SUPPORT)
+ friend class CMGFAM;
+#endif // CMGO_SUPPORT
+#if defined(JAVA_SUPPORT)
+ friend class JMGFAM;
+#endif // JAVA_SUPPORT
+public:
+ // Constructor
+ BSONDEF(void);
+
+ // Implementation
+ virtual const char* GetType(void) { return "BSON"; }
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+protected:
+ // Members
+ PGLOBAL G; /* Bson utility memory */
+ JMODE Jmode; /* MODE_OBJECT by default */
+ PCSZ Objname; /* Name of first level object */
+ PCSZ Xcol; /* Name of expandable column */
+ int Limit; /* Limit of multiple values */
+ int Pretty; /* Depends on file structure */
+ int Base; /* The array index base */
+ bool Strict; /* Strict syntax checking */
+ char Sep; /* The Jpath separator */
+ const char* Uri; /* MongoDB connection URI */
+ PCSZ Collname; /* External collection name */
+ PSZ Options; /* Colist ; Pipe */
+ PSZ Filter; /* Filter */
+ PSZ Driver; /* MongoDB Driver (C or JAVA) */
+ bool Pipe; /* True if Colist is a pipeline */
+ int Version; /* Driver version */
+ PSZ Wrapname; /* MongoDB java wrapper name */
+}; // end of BSONDEF
+
+
+/* -------------------------- BTUTIL class --------------------------- */
+
+/***********************************************************************/
+/* Handles all BJSON actions for a BSON table. */
+/***********************************************************************/
+class BTUTIL : public BDOC {
+public:
+ // Constructor
+ BTUTIL(PGLOBAL G, TDBBSN* tp) : BDOC(G) { Tp = tp; }
+
+ // Utility functions
+ PBVAL FindRow(PGLOBAL g);
+ PBVAL ParseLine(PGLOBAL g, int prty, bool cma);
+ PBVAL MakeTopTree(PGLOBAL g, int type);
+ PSZ SerialVal(PGLOBAL g, PBVAL top, int pretty);
+
+protected:
+ // Members
+ TDBBSN* Tp;
+}; // end of class BTUTIL
+
+/* -------------------------- BCUTIL class --------------------------- */
+
+/***********************************************************************/
+/* Handles all BJSON actions for a BSON columns. */
+/***********************************************************************/
+class BCUTIL : public BTUTIL {
+public:
+ // Constructor
+ BCUTIL(PGLOBAL G, PBSCOL cp, TDBBSN* tp) : BTUTIL(G, tp)
+ { Cp = cp; Jb = false; }
+
+ // Utility functions
+ void SetJsonValue(PGLOBAL g, PVAL vp, PBVAL jvp);
+ PBVAL MakeBson(PGLOBAL g, PBVAL jsp, int n);
+ PBVAL GetRowValue(PGLOBAL g, PBVAL row, int i);
+ PVAL GetColumnValue(PGLOBAL g, PBVAL row, int i);
+ PVAL ExpandArray(PGLOBAL g, PBVAL arp, int n);
+ PVAL CalculateArray(PGLOBAL g, PBVAL arp, int n);
+ PBVAL GetRow(PGLOBAL g);
+
+protected:
+ // Member
+ PBSCOL Cp;
+ bool Jb;
+}; // end of class BCUTIL
+
+ /* -------------------------- TDBBSN class --------------------------- */
+
+/***********************************************************************/
+/* This is the BSN Access Method class declaration. */
+/* The table is a DOS file, each record being a JSON object. */
+/***********************************************************************/
+class DllExport TDBBSN : public TDBDOS {
+ friend class BSONCOL;
+ friend class BSONDEF;
+ friend class BTUTIL;
+ friend class BCUTIL;
+ friend class BSONDISC;
+#if defined(CMGO_SUPPORT)
+ friend class CMGFAM;
+#endif // CMGO_SUPPORT
+#if defined(JAVA_SUPPORT)
+ friend class JMGFAM;
+#endif // JAVA_SUPPORT
+public:
+ // Constructor
+ TDBBSN(PGLOBAL g, PBDEF tdp, PTXF txfp);
+ TDBBSN(TDBBSN* tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) { return TYPE_AM_JSN; }
+ virtual bool SkipHeader(PGLOBAL g);
+ virtual PTDB Duplicate(PGLOBAL g) { return (PTDB)new(g) TDBBSN(this); }
+ PBVAL GetRow(void) { return Row; }
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual PCOL InsertSpecialColumn(PCOL colp);
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE) {return (b) ? M : N;}
+ virtual bool CanBeFiltered(void)
+ {return Txfp->GetAmType() == TYPE_AM_MGO || !Xcol;}
+
+ // Database routines
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual bool PrepareWriting(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual void CloseDB(PGLOBAL g);
+
+ // Specific routine
+ virtual int EstimatedLength(void);
+
+protected:
+ PBVAL FindRow(PGLOBAL g);
+//int MakeTopTree(PGLOBAL g, PBVAL jsp);
+
+ // Members
+ PBTUT Bp; // The BSUTIL handling class
+ PBVAL Top; // The top JSON tree
+ PBVAL Row; // The current row
+ PBSCOL Colp; // The multiple column
+ JMODE Jmode; // MODE_OBJECT by default
+ PCSZ Objname; // The table object name
+ PCSZ Xcol; // Name of expandable column
+ int Fpos; // The current row index
+ int N; // The current Rownum
+ int M; // Index of multiple value
+ int Limit; // Limit of multiple values
+ int Pretty; // Depends on file structure
+ int NextSame; // Same next row
+ int SameRow; // Same row nb
+ int Xval; // Index of expandable array
+ int B; // Array index base
+ char Sep; // The Jpath separator
+ bool Strict; // Strict syntax checking
+ bool Comma; // Row has final comma
+}; // end of class TDBBSN
+
+/* -------------------------- BSONCOL class -------------------------- */
+
+/***********************************************************************/
+/* Class BSONCOL: JSON access method column descriptor. */
+/***********************************************************************/
+class DllExport BSONCOL : public DOSCOL {
+ friend class TDBBSN;
+ friend class TDBBSON;
+ friend class BCUTIL;
+#if defined(CMGO_SUPPORT)
+ friend class CMGFAM;
+#endif // CMGO_SUPPORT
+#if defined(JAVA_SUPPORT)
+ friend class JMGFAM;
+#endif // JAVA_SUPPORT
+public:
+ // Constructors
+ BSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
+ BSONCOL(BSONCOL* colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) { return Tbp->GetAmType(); }
+ virtual bool Stringify(void) { return Sgfy; }
+
+ // Methods
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ bool ParseJpath(PGLOBAL g);
+ virtual PSZ GetJpath(PGLOBAL g, bool proj);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+protected:
+ bool CheckExpand(PGLOBAL g, int i, PSZ nm, bool b);
+ bool SetArrayOptions(PGLOBAL g, char* p, int i, PSZ nm);
+
+ // Default constructor not to be used
+ BSONCOL(void) {}
+
+ // Members
+ TDBBSN *Tbp; // To the JSN table block
+ PBCUT Cp; // To the BCUTIL handling class
+ PVAL MulVal; // To value used by multiple column
+ char *Jpath; // The json path
+ JNODE *Nodes; // The intermediate objects
+ int Nod; // The number of intermediate objects
+ int Xnod; // Index of multiple values
+ char Sep; // The Jpath separator
+ bool Xpd; // True for expandable column
+ bool Parsed; // True when parsed
+ bool Warned; // True when warning issued
+ bool Sgfy; // True if stringified
+}; // end of class BSONCOL
+
+/* -------------------------- TDBBSON class -------------------------- */
+
+/***********************************************************************/
+/* This is the JSON Access Method class declaration. */
+/***********************************************************************/
+class DllExport TDBBSON : public TDBBSN {
+ friend class BSONDEF;
+ friend class BSONCOL;
+public:
+ // Constructor
+ TDBBSON(PGLOBAL g, PBDEF tdp, PTXF txfp);
+ TDBBSON(PBTDB tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) { return TYPE_AM_JSON; }
+ virtual PTDB Duplicate(PGLOBAL g) { return (PTDB)new(g) TDBBSON(this); }
+ PBVAL GetDoc(void) { return Docp; }
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+
+ // Database routines
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual void ResetSize(void);
+ virtual int GetProgCur(void) { return N; }
+ virtual int GetRecpos(void);
+ virtual bool SetRecpos(PGLOBAL g, int recpos);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual bool PrepareWriting(PGLOBAL g) { return false; }
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ int MakeDocument(PGLOBAL g);
+
+ // Optimization routines
+ virtual int MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add);
+
+protected:
+ int MakeNewDoc(PGLOBAL g);
+
+ // Members
+ PBVAL Docp; // The document array
+ int Multiple; // 0: No 1: DIR 2: Section 3: filelist
+ bool Done; // True when document parsing is done
+ bool Changed; // After Update, Insert or Delete
+}; // end of class TDBBSON
+
+/***********************************************************************/
+/* This is the class declaration for the JSON catalog table. */
+/***********************************************************************/
+class DllExport TDBBCL : public TDBCAT {
+public:
+ // Constructor
+ TDBBCL(PBDEF tdp);
+
+protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PTOS Topt;
+ PCSZ Db;
+ PCSZ Dsn;
+}; // end of class TDBBCL
diff --git a/storage/connect/tabcmg.cpp b/storage/connect/tabcmg.cpp
new file mode 100644
index 00000000..56d705f4
--- /dev/null
+++ b/storage/connect/tabcmg.cpp
@@ -0,0 +1,506 @@
+/************** tabcmg C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: tabcmg Version 1.3 */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
+/* This program are the C MongoDB class DB execution routines. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tdbdos.h is header containing the TDBDOS declarations. */
+/* json.h is header containing the JSON classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "maputil.h"
+#include "filamtxt.h"
+#include "tabext.h"
+#include "tabcmg.h"
+#include "tabmul.h"
+#include "filter.h"
+
+PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info);
+bool Stringified(PCSZ, char*);
+
+/* -------------------------- Class CMGDISC -------------------------- */
+
+/***********************************************************************/
+/* Get document. */
+/***********************************************************************/
+void CMGDISC::GetDoc(void)
+{
+ doc = ((TDBCMG*)tmgp)->Cmgp->Document;
+} // end of GetDoc
+
+/***********************************************************************/
+/* Analyse passed document. */
+/***********************************************************************/
+//bool CMGDISC::Find(PGLOBAL g, int i, int k, bool b)
+bool CMGDISC::Find(PGLOBAL g)
+{
+ return FindInDoc(g, &iter, doc, NULL, NULL, 0, false);
+} // end of Find
+
+/***********************************************************************/
+/* Analyse passed document. */
+/***********************************************************************/
+bool CMGDISC::FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc,
+ char *pcn, char *pfmt, int k, bool b)
+{
+ if (!doc || bson_iter_init(iter, doc)) {
+ const char *key;
+ char colname[65];
+ char fmt[129];
+ bool newcol;
+ size_t n;
+
+ while (bson_iter_next(iter)) {
+ key = bson_iter_key(iter);
+ newcol = true;
+
+ if (pcn) {
+ n = sizeof(colname) - 1;
+ strncpy(colname, pcn, n);
+ colname[n] = 0;
+ n -= strlen(colname);
+ strncat(strncat(colname, "_", n), key, n - 1);
+ } else
+ strcpy(colname, key);
+
+ if (pfmt) {
+ n = sizeof(fmt) - 1;
+ strncpy(fmt, pfmt, n);
+ fmt[n] = 0;
+ n -= strlen(fmt);
+ strncat(strncat(fmt, ".", n), key, n - 1);
+ } else
+ strcpy(fmt, key);
+
+ bcol.Cbn = false;
+
+ switch (bson_iter_type(iter)) {
+ case BSON_TYPE_UTF8:
+ bcol.Type = TYPE_STRING;
+ bcol.Len = strlen(bson_iter_utf8(iter, NULL));
+ break;
+ case BSON_TYPE_INT32:
+ bcol.Type = TYPE_INT;
+ bcol.Len = 11; // bson_iter_int32(iter)
+ break;
+ case BSON_TYPE_INT64:
+ bcol.Type = TYPE_BIGINT;
+ bcol.Len = 22; // bson_iter_int64(iter)
+ break;
+ case BSON_TYPE_DOUBLE:
+ bcol.Type = TYPE_DOUBLE;
+ bcol.Len = 12;
+ bcol.Scale = 6; // bson_iter_double(iter)
+ break;
+ case BSON_TYPE_DATE_TIME:
+ bcol.Type = TYPE_DATE;
+ bcol.Len = 19; // bson_iter_date_time(iter)
+ break;
+ case BSON_TYPE_BOOL:
+ bcol.Type = TYPE_TINY;
+ bcol.Len = 1;
+ break;
+ case BSON_TYPE_OID:
+ bcol.Type = TYPE_STRING;
+ bcol.Len = 24; // bson_iter_oid(iter)
+ break;
+ case BSON_TYPE_DECIMAL128:
+ bcol.Type = TYPE_DECIM;
+ bcol.Len = 32; // bson_iter_decimal128(iter, &dec)
+ break;
+ case BSON_TYPE_DOCUMENT:
+ if (lvl < 0)
+ continue;
+ else if (lvl <= k) {
+ bcol.Type = TYPE_STRING;
+ bcol.Len = 512;
+ } else {
+ bson_iter_t child;
+
+ if (bson_iter_recurse(iter, &child))
+ if (FindInDoc(g, &child, NULL, colname, fmt, k + 1, false))
+ return true;
+
+ newcol = false;
+ } // endif lvl
+
+ break;
+ case BSON_TYPE_ARRAY:
+ if (lvl < 0)
+ continue;
+ else if (lvl <= k) {
+ bcol.Type = TYPE_STRING;
+ bcol.Len = 512;
+ } else {
+ bson_t* arr;
+ bson_iter_t itar;
+ const uint8_t* data = NULL;
+ uint32_t len = 0;
+
+ bson_iter_array(iter, &len, &data);
+ arr = bson_new_from_data(data, len);
+
+ if (FindInDoc(g, &itar, arr, colname, fmt, k + 1, !all))
+ return true;
+
+ newcol = false;
+ } // endif lvl
+
+ break;
+ } // endswitch iter
+
+ if (newcol)
+ AddColumn(g, colname, fmt, k);
+
+ if (b)
+ break; // Test only first element of arrays
+
+ } // endwhile iter
+
+ } // endif doc
+
+ return false;
+} // end of FindInDoc
+
+/* --------------------------- Class TDBCMG -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBCMG class. */
+/***********************************************************************/
+TDBCMG::TDBCMG(MGODEF *tdp) : TDBEXT(tdp)
+{
+ Cmgp = NULL;
+ Cnd = NULL;
+ Pcg.Tdbp = this;
+
+ if (tdp) {
+ Pcg.Uristr = tdp->Uri;
+ Pcg.Db_name = tdp->Tabschema;
+ Pcg.Coll_name = tdp->Tabname;
+ Pcg.Options = tdp->Colist;
+ Pcg.Filter = tdp->Filter;
+ Pcg.Line = NULL;
+ Pcg.Pipe = tdp->Pipe && tdp->Colist != NULL;
+ B = tdp->Base ? 1 : 0;
+ Strfy = tdp->Strfy;
+ } else {
+ Pcg.Uristr = NULL;
+ Pcg.Db_name = NULL;
+ Pcg.Coll_name = NULL;
+ Pcg.Options = NULL;
+ Pcg.Filter = NULL;
+ Pcg.Line = NULL;
+ Pcg.Pipe = false;
+ Strfy = NULL;
+ B = 0;
+ } // endif tdp
+
+ Fpos = -1;
+ N = 0;
+ Done = false;
+} // end of TDBCMG standard constructor
+
+TDBCMG::TDBCMG(TDBCMG *tdbp) : TDBEXT(tdbp)
+{
+ Cmgp = tdbp->Cmgp;
+ Cnd = tdbp->Cnd;
+ Pcg = tdbp->Pcg;
+ Strfy = tdbp->Strfy;
+ B = tdbp->B;
+ Fpos = tdbp->Fpos;
+ N = tdbp->N;
+ Done = tdbp->Done;
+} // end of TDBCMG copy constructor
+
+// Used for update
+PTDB TDBCMG::Clone(PTABS t)
+{
+ PTDB tp;
+ PMGOCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBCMG(this);
+
+ for (cp1 = (PMGOCOL)Columns; cp1; cp1 = (PMGOCOL)cp1->GetNext())
+ if (!cp1->IsSpecial()) {
+ cp2 = new(g) MGOCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endif cp1
+
+ return tp;
+} // end of Clone
+
+/***********************************************************************/
+/* Allocate JSN column description block. */
+/***********************************************************************/
+PCOL TDBCMG::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ PMGOCOL colp = new(g) MGOCOL(g, cdp, this, cprec, n);
+
+ return colp;
+} // end of MakeCol
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBCMG::InsertSpecialColumn(PCOL colp)
+{
+ if (!colp->IsSpecial())
+ return NULL;
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+} // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* Init: initialize MongoDB processing. */
+/***********************************************************************/
+bool TDBCMG::Init(PGLOBAL g)
+{
+ if (Done)
+ return false;
+
+ /*********************************************************************/
+ /* Open an C connection for this table. */
+ /*********************************************************************/
+ if (!Cmgp)
+ Cmgp = new(g) CMgoConn(g, &Pcg);
+ else if (Cmgp->IsConnected())
+ Cmgp->Close();
+
+ if (Cmgp->Connect(g))
+ return true;
+
+ Done = true;
+ return false;
+} // end of Init
+
+/***********************************************************************/
+/* MONGO Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBCMG::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 1;
+ else if (Cardinal < 0)
+ Cardinal = (!Init(g)) ? Cmgp->CollSize(g) : 0;
+
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* MONGO GetMaxSize: returns collection size estimate. */
+/***********************************************************************/
+int TDBCMG::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = Cardinality(g);
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* OpenDB: Data Base open routine for MONGO access method. */
+/***********************************************************************/
+bool TDBCMG::OpenDB(PGLOBAL g)
+{
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open replace it at its beginning. */
+ /*******************************************************************/
+ Cmgp->Rewind();
+ Fpos = -1;
+ return false;
+ } // endif Use
+
+ /*********************************************************************/
+ /* First opening. */
+ /*********************************************************************/
+ if (Pcg.Pipe && Mode != MODE_READ) {
+ strcpy(g->Message, "Pipeline tables are read only");
+ return true;
+ } // endif Pipe
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ if (Init(g))
+ return true;
+
+ if (Mode == MODE_DELETE && !Next)
+ // Delete all documents
+ return Cmgp->DocDelete(g);
+ else if (Mode == MODE_INSERT)
+ Cmgp->MakeColumnGroups(g);
+
+ return false;
+} // end of OpenDB
+
+/***********************************************************************/
+/* Data Base indexed read routine for ODBC access method. */
+/***********************************************************************/
+bool TDBCMG::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
+{
+ strcpy(g->Message, "MONGO tables are not indexable");
+ return true;
+} // end of ReadKey
+
+/***********************************************************************/
+/* ReadDB: Get next document from a collection. */
+/***********************************************************************/
+int TDBCMG::ReadDB(PGLOBAL g)
+{
+ return Cmgp->ReadNext(g);
+} // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for MGO access method. */
+/***********************************************************************/
+int TDBCMG::WriteDB(PGLOBAL g)
+{
+ return Cmgp->Write(g);
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for MGO access method. */
+/***********************************************************************/
+int TDBCMG::DeleteDB(PGLOBAL g, int irc)
+{
+ return (irc == RC_OK) ? WriteDB(g) : RC_OK;
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Table close routine for MONGO tables. */
+/***********************************************************************/
+void TDBCMG::CloseDB(PGLOBAL g)
+{
+ Cmgp->Close();
+ Done = false;
+} // end of CloseDB
+
+/* ----------------------------- MGOCOL ------------------------------ */
+
+/***********************************************************************/
+/* MGOCOL public constructor. */
+/***********************************************************************/
+MGOCOL::MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : EXTCOL(cdp, tdbp, cprec, i, "MGO")
+{
+ Tmgp = (PTDBCMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
+ Sgfy = Stringified(Tmgp->Strfy, Name);
+
+ if ((Jpath = cdp->GetFmt())) {
+ int n = strlen(Jpath) - 1;
+
+ if (Jpath[n] == '*') {
+ Jpath = PlugDup(g, cdp->GetFmt());
+ if (Jpath[n - 1] == '.') n--;
+ Jpath[n] = 0;
+ Sgfy = true;
+ } // endif Jpath
+
+ } else
+ Jpath = cdp->GetName();
+
+} // end of MGOCOL constructor
+
+/***********************************************************************/
+/* MGOCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+MGOCOL::MGOCOL(MGOCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
+{
+ Tmgp = col1->Tmgp;
+ Jpath = col1->Jpath;
+ Sgfy = col1->Sgfy;
+} // end of MGOCOL copy constructor
+
+/***********************************************************************/
+/* Get path when proj is false or projection path when proj is true. */
+/***********************************************************************/
+PSZ MGOCOL::GetJpath(PGLOBAL g, bool proj)
+{
+ if (Jpath) {
+ if (proj) {
+ char *p1, *p2, *projpath = PlugDup(g, Jpath);
+ int i = 0;
+
+ for (p1 = p2 = projpath; *p1; p1++)
+ if (*p1 == '.') {
+ if (!i)
+ *p2++ = *p1;
+
+ i = 1;
+ } else if (i) {
+ if (!isdigit(*p1)) {
+ *p2++ = *p1;
+ i = 0;
+ } // endif p1
+
+ } else
+ *p2++ = *p1;
+
+ if (*(p2 - 1) == '.')
+ p2--;
+
+ *p2 = 0;
+ return projpath;
+ } else
+ return Jpath;
+
+ } else
+ return Name;
+
+} // end of GetJpath
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void MGOCOL::ReadColumn(PGLOBAL g)
+{
+ Tmgp->Cmgp->GetColumnValue(g, this);
+} // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: */
+/***********************************************************************/
+void MGOCOL::WriteColumn(PGLOBAL g)
+{
+ // Check whether this node must be written
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, FALSE); // Convert the updated value
+
+} // end of WriteColumn
+
+/* ---------------------------TDBGOL class --------------------------- */
+
+/***********************************************************************/
+/* TDBGOL class constructor. */
+/***********************************************************************/
+TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp)
+{
+ Topt = tdp->GetTopt();
+ Uri = tdp->Uri;
+ Db = tdp->GetTabschema();
+} // end of TDBJCL constructor
+
+/***********************************************************************/
+/* GetResult: Get the list the JSON file columns. */
+/***********************************************************************/
+PQRYRES TDBGOL::GetResult(PGLOBAL g)
+{
+ return MGOColumns(g, Db, Uri, Topt, false);
+} // end of GetResult
+
+/* -------------------------- End of mongo --------------------------- */
diff --git a/storage/connect/tabcmg.h b/storage/connect/tabcmg.h
new file mode 100644
index 00000000..9effe714
--- /dev/null
+++ b/storage/connect/tabcmg.h
@@ -0,0 +1,133 @@
+/**************** tabcmg H Declares Source Code File (.H) **************/
+/* Name: tabcmg.h Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
+/* */
+/* This file contains the MongoDB classes declares. */
+/***********************************************************************/
+#include "mongo.h"
+#include "cmgoconn.h"
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+class CMGDISC : public MGODISC {
+public:
+ // Constructor
+ CMGDISC(PGLOBAL g, int *lg) : MGODISC(g, lg) { drv = "C"; }
+
+ // Methods
+ virtual void GetDoc(void);
+//virtual bool Find(PGLOBAL g, int i, int k, bool b);
+ virtual bool Find(PGLOBAL g);
+
+ // BSON Function
+//bool FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc,
+// char *pcn, char *pfmt, int i, int k, bool b);
+ bool FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc,
+ char *pcn, char *pfmt, int k, bool b);
+
+ // Members
+ bson_iter_t iter;
+ const bson_t *doc;
+}; // end of CMGDISC
+
+/* -------------------------- TDBCMG class --------------------------- */
+
+/***********************************************************************/
+/* This is the MongoDB Table Type class declaration. */
+/* The table is a collection, each record being a document. */
+/***********************************************************************/
+class DllExport TDBCMG : public TDBEXT {
+ friend class MGOCOL;
+ friend class MGODEF;
+ friend class CMGDISC;
+ friend PQRYRES MGOColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool);
+public:
+ // Constructor
+ TDBCMG(MGODEF *tdp);
+ TDBCMG(TDBCMG *tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_MGO;}
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBCMG(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual PCOL InsertSpecialColumn(PCOL colp);
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE) {return N;}
+
+ // Database routines
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr);
+
+protected:
+ bool Init(PGLOBAL g);
+
+ // Members
+ CMgoConn *Cmgp; // Points to a C Mongo connection class
+ CMGOPARM Pcg; // Parms passed to Cmgp
+ const Item *Cnd; // The first condition
+ PCSZ Strfy; // The stringified columns
+ int Fpos; // The current row index
+ int N; // The current Rownum
+ int B; // Array index base
+ bool Done; // Init done
+}; // end of class TDBCMG
+
+/* --------------------------- MGOCOL class -------------------------- */
+
+/***********************************************************************/
+/* Class MGOCOL: MongoDB access method column descriptor. */
+/***********************************************************************/
+class DllExport MGOCOL : public EXTCOL {
+ friend class TDBCMG;
+ friend class FILTER;
+public:
+ // Constructors
+ MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
+ MGOCOL(MGOCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) { return Tmgp->GetAmType(); }
+ virtual bool Stringify(void) { return Sgfy; }
+
+ // Methods
+ virtual PSZ GetJpath(PGLOBAL g, bool proj);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+protected:
+ // Default constructor not to be used
+ MGOCOL(void) {}
+
+ // Members
+ TDBCMG *Tmgp; // To the MGO table block
+ char *Jpath; // The json path
+ bool Sgfy; // True if stringified
+}; // end of class MGOCOL
+
+/***********************************************************************/
+/* This is the class declaration for the MONGO catalog table. */
+/***********************************************************************/
+class DllExport TDBGOL : public TDBCAT {
+public:
+ // Constructor
+ TDBGOL(PMGODEF tdp);
+
+protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PTOS Topt;
+ PCSZ Uri;
+ PCSZ Db;
+}; // end of class TDBGOL
diff --git a/storage/connect/tabcol.cpp b/storage/connect/tabcol.cpp
new file mode 100644
index 00000000..93de0598
--- /dev/null
+++ b/storage/connect/tabcol.cpp
@@ -0,0 +1,169 @@
+/************* TabCol C++ Functions Source Code File (.CPP) ************/
+/* Name: TABCOL.CPP Version 2.7 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2015 */
+/* */
+/* This file contains the PlugDB++ XTAB, COLUMN and XORDER methods. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* tabcol.h is header containing XTAB, and XORDER declares. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabcol.h"
+
+/***********************************************************************/
+/* XTAB public constructor. */
+/***********************************************************************/
+XTAB::XTAB(LPCSTR name, LPCSTR srcdef) : Name(name)
+ {
+ Next = NULL;
+ To_Tdb = NULL;
+ Srcdef = srcdef;
+ Schema = NULL;
+ Qualifier = NULL;
+
+ if (trace(1))
+ htrc("XTAB: making new TABLE %s %s\n", Name, Srcdef);
+
+ } // end of XTAB constructor
+
+/***********************************************************************/
+/* XTAB public constructor as a copy of another table. */
+/***********************************************************************/
+XTAB::XTAB(PTABLE tp) : Name(tp->Name)
+ {
+ Next = NULL;
+ To_Tdb = NULL;
+ Srcdef = tp->Srcdef;
+ Schema = tp->Schema;
+ Qualifier = tp->Qualifier;
+
+ if (trace(1))
+ htrc(" making copy TABLE %s %s\n", Name, SVP(Srcdef));
+
+ } // end of XTAB constructor
+
+/***********************************************************************/
+/* Link the tab2 tables to the tab1(this) table chain. */
+/***********************************************************************/
+PTABLE XTAB::Link(PTABLE tab2)
+ {
+ PTABLE tabp;
+
+ if (trace(1))
+ htrc("Linking tables %s... to %s\n", Name, tab2->Name);
+
+ for (tabp = this; tabp->Next; tabp = tabp->Next) ;
+
+ tabp->Next = tab2;
+ return (this);
+ } /* end of Link */
+
+/***********************************************************************/
+/* Make file output of XTAB contents. */
+/***********************************************************************/
+void XTAB::Printf(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+
+ for (PTABLE tp = this; tp; tp = tp->Next) {
+ fprintf(f, "%sTABLE: %s.%s %s\n",
+ m, SVP(tp->Schema), tp->Name, SVP(tp->Srcdef));
+ PlugPutOut(g, f, TYPE_TDB, tp->To_Tdb, n + 2);
+ } /* endfor tp */
+
+ } /* end of Printf */
+
+/***********************************************************************/
+/* Make string output of XTAB contents. */
+/***********************************************************************/
+void XTAB::Prints(PGLOBAL, char *ps, uint z)
+ {
+ char buf[128];
+ int i, n = (int)z - 1;
+
+ *ps = '\0';
+
+ for (PTABLE tp = this; tp && n > 0; tp = tp->Next) {
+ i = sprintf(buf, "TABLE: %s.%s %s To_Tdb=%p ",
+ SVP(tp->Schema), tp->Name, SVP(tp->Srcdef), tp->To_Tdb);
+ strncat(ps, buf, n);
+ n -= i;
+ } // endif tp
+
+ } /* end of Prints */
+
+
+/***********************************************************************/
+/* COLUMN public constructor. */
+/***********************************************************************/
+COLUMN::COLUMN(LPCSTR name) : Name(name)
+ {
+ To_Table = NULL;
+ To_Col = NULL;
+ Qualifier = NULL;
+
+ if (trace(1))
+ htrc(" making new COLUMN %s\n", Name);
+
+ } // end of COLUMN constructor
+
+/***********************************************************************/
+/* COLUMN SetFormat: should never be called. */
+/***********************************************************************/
+bool COLUMN::SetFormat(PGLOBAL g, FORMAT&)
+ {
+ strcpy(g->Message, MSG(NO_FORMAT_COL));
+ return true;
+ } // end of SetFormat
+
+/***********************************************************************/
+/* Make file output of COLUMN contents. */
+/***********************************************************************/
+void COLUMN::Printf(PGLOBAL g, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+
+ if (Name)
+ fprintf(f, "%sCOLUMN: %s.%s\n", m,
+ ((!Qualifier) ? (PSZ)"?" : Qualifier), Name);
+ else // LNA
+ fprintf(f, "%sC%d\n", m, (!Qualifier) ? 0 : *(int *)Qualifier);
+
+ PlugPutOut(g, f, TYPE_TABLE, To_Table, n + 2);
+ PlugPutOut(g, f, TYPE_XOBJECT, To_Col, n + 2);
+ } /* end of Printf */
+
+/***********************************************************************/
+/* Make string output of COLUMN contents. */
+/***********************************************************************/
+void COLUMN::Prints(PGLOBAL, char *ps, uint z)
+ {
+ char buf[80];
+
+ if (Name)
+ sprintf(buf, "COLUMN: %s.%s table=%p col=%p",
+ ((!Qualifier) ? (PSZ)"?" : Qualifier), Name, To_Table, To_Col);
+ else // LNA
+ sprintf(buf, "C%d", (!Qualifier) ? 0 : *(int *)Qualifier);
+
+ strncpy(ps, buf, z);
+ ps[z - 1] = '\0';
+ } /* end of Prints */
diff --git a/storage/connect/tabcol.h b/storage/connect/tabcol.h
new file mode 100644
index 00000000..e4657e2f
--- /dev/null
+++ b/storage/connect/tabcol.h
@@ -0,0 +1,109 @@
+/*************** TabCol H Declares Source Code File (.H) ***************/
+/* Name: TABCOL.H Version 2.8 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2013 */
+/* */
+/* This file contains the XTAB, COLUMN and XORDER class definitions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include required application header files */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#include "xobject.h"
+
+/***********************************************************************/
+/* Definition of class XTAB with all its method functions. */
+/***********************************************************************/
+class DllExport XTAB: public BLOCK { // Table Name-Schema-Srcdef block.
+ friend class TDBPRX;
+ friend class TDBTBM;
+ public:
+ // Constructors
+ XTAB(LPCSTR name, LPCSTR srcdef = NULL);
+ XTAB(PTABLE tp);
+
+ // Implementation
+ PTABLE GetNext(void) {return Next;}
+ PTDB GetTo_Tdb(void) {return To_Tdb;}
+ LPCSTR GetName(void) {return Name;}
+ LPCSTR GetSrc(void) {return Srcdef;}
+ LPCSTR GetSchema(void) {return Schema;}
+ LPCSTR GetQualifier(void) {return Qualifier;}
+ void SetTo_Tdb(PTDB tdbp) {To_Tdb = tdbp;}
+ void SetName(LPCSTR name) {Name = name;}
+ void SetSrc(LPCSTR srcdef) {Srcdef = srcdef;}
+ void SetSchema(LPCSTR schname) {Schema = schname;}
+ void SetQualifier(LPCSTR qname) {Qualifier = qname;}
+
+ // Methods
+ PTABLE Link(PTABLE);
+ void Printf(PGLOBAL g, FILE *f, uint n);
+ void Prints(PGLOBAL g, char *ps, uint z);
+
+ protected:
+ // Members
+ PTABLE Next; // Points to next table in chain
+ PTDB To_Tdb; // Points to Table description Block
+ LPCSTR Name; // Table name
+ LPCSTR Srcdef; // Table Source definition
+ LPCSTR Schema; // Schema name
+ LPCSTR Qualifier; // Qualifier name
+ }; // end of class XTAB
+
+
+/***********************************************************************/
+/* Definition of class COLUMN with all its method functions. */
+/* Note: because of LNA routines, the constantness of Name was */
+/* removed and constructing a COLUMN with null name was allowed. */
+/* Perhaps this should be replaced by the use of a specific class. */
+/***********************************************************************/
+class DllExport COLUMN: public XOBJECT { // Column Name/Qualifier block.
+ public:
+ // Constructor
+ COLUMN(LPCSTR name);
+
+ // Implementation
+ virtual int GetType(void) {return TYPE_COLUMN;}
+ virtual int GetResultType(void) {assert(false); return TYPE_VOID;}
+ virtual int GetLength(void) {assert(false); return 0;}
+ virtual int GetLengthEx(void) {assert(false); return 0;}
+ virtual int GetScale() {assert(false); return 0;};
+ LPCSTR GetName(void) {return Name;}
+ LPCSTR GetQualifier(void) {return Qualifier;}
+ PTABLE GetTo_Table(void) {return To_Table;}
+ PCOL GetTo_Col(void) {return To_Col;}
+ void SetQualifier(LPCSTR qualif) {Qualifier = qualif;}
+ void SetTo_Table(PTABLE tablep) {To_Table = tablep;}
+ void SetTo_Col(PCOL colp) {To_Col = colp;}
+
+ // Methods
+ virtual void Printf(PGLOBAL g, FILE *f, uint n);
+ virtual void Prints(PGLOBAL g, char *ps, uint z);
+ // All methods below should never be used for COLUMN's
+ virtual void Reset(void) {assert(false);}
+ virtual bool Compare(PXOB) {assert(false); return false;}
+ virtual bool SetFormat(PGLOBAL, FORMAT&);
+ virtual bool Eval(PGLOBAL) {assert(false); return true;}
+
+ private:
+ // Members
+ PTABLE To_Table; // Point to Table Name Block
+ PCOL To_Col; // Points to Column Description Block
+ LPCSTR const Name; // Column name
+ LPCSTR Qualifier; // Qualifier name
+ }; // end of class COLUMN
+
+/***********************************************************************/
+/* Definition of class SPCCOL with all its method functions. */
+/* Note: Currently the special columns are ROWID, ROWNUM, FILEID, */
+/* SERVID, TABID, PARTID, and CONID. */
+/***********************************************************************/
+class SPCCOL: public COLUMN { // Special Column Name/Qualifier block.
+ public:
+ // Constructor
+ SPCCOL(LPCSTR name) : COLUMN(name) {}
+
+ private:
+ // Members
+ }; // end of class SPCCOL
diff --git a/storage/connect/tabdos.cpp b/storage/connect/tabdos.cpp
new file mode 100644
index 00000000..2e70fdfc
--- /dev/null
+++ b/storage/connect/tabdos.cpp
@@ -0,0 +1,2921 @@
+/************* TabDos C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABDOS */
+/* ------------- */
+/* Version 4.9.5 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2020 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the DOS tables classes. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <sys\timeb.h> // For testing only
+#include <fcntl.h>
+#include <errno.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* filamtxt.h is header containing the file AM classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "osutil.h"
+#include "plgdbsem.h"
+//#include "catalog.h"
+#include "mycat.h"
+#include "xindex.h"
+#include "filamap.h"
+#include "filamfix.h"
+#include "filamdbf.h"
+#if defined(GZ_SUPPORT)
+#include "filamgz.h"
+#endif // GZ_SUPPORT
+#if defined(ZIP_SUPPORT)
+#include "filamzip.h"
+#endif // ZIP_SUPPORT
+#include "tabdos.h"
+#include "tabfix.h"
+#include "tabmul.h"
+#include "array.h"
+#include "blkfil.h"
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+int num_read, num_there, num_eq[2]; // Statistics
+
+/***********************************************************************/
+/* Size of optimize file header. */
+/***********************************************************************/
+#define NZ 4
+
+/***********************************************************************/
+/* External function. */
+/***********************************************************************/
+bool ExactInfo(void);
+USETEMP UseTemp(void);
+
+/***********************************************************************/
+/* Min and Max blocks contains zero ended fields (blank = false). */
+/* No conversion of block values (check = true). */
+/***********************************************************************/
+PVBLK AllocValBlock(PGLOBAL, void *, int, int, int len= 0, int prec= 0,
+ bool check= true, bool blank= false, bool un= false);
+
+/* --------------------------- Class DOSDEF -------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+DOSDEF::DOSDEF(void)
+ {
+ Pseudo = 3;
+ Fn = NULL;
+ Ofn = NULL;
+ Entry = NULL;
+ To_Indx = NULL;
+ Pwd = NULL;
+ Recfm = RECFM_VAR;
+ Mapped = false;
+ Zipped = false;
+ Mulentries = false;
+ Append = false;
+ Padded = false;
+ Huge = false;
+ Accept = false;
+ Eof = false;
+ To_Pos = NULL;
+ Optimized = 0;
+ AllocBlks = 0;
+ Compressed = 0;
+ Lrecl = 0;
+ AvgLen = 0;
+ Block = 0;
+ Last = 0;
+ Blksize = 0;
+ Maxerr = 0;
+ ReadMode = 0;
+ Ending = 0;
+ Teds = 0;
+ } // end of DOSDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool DOSDEF::DefineAM(PGLOBAL g, LPCSTR am, int)
+ {
+ char buf[8];
+ bool map = (am && (*am == 'M' || *am == 'm'));
+ LPCSTR dfm = (am && (*am == 'F' || *am == 'f')) ? "F"
+ : (am && (*am == 'B' || *am == 'b')) ? "B"
+ : (am && (*am == 'X' || *am == 'x')) ? "X"
+ : (am && !stricmp(am, "DBF")) ? "D" : "V";
+
+ if ((Zipped = GetBoolCatInfo("Zipped", false))) {
+ Entry = GetStringCatInfo(g, "Entry", NULL);
+ Mulentries = (Entry && *Entry) ? strchr(Entry, '*') || strchr(Entry, '?')
+ : false;
+ Mulentries = GetBoolCatInfo("Mulentries", Mulentries);
+ Append = GetBoolCatInfo("Append", false);
+ Pwd = GetStringCatInfo(g, "Password", NULL);
+ } // endif Zipped
+
+ Desc = Fn = GetStringCatInfo(g, "Filename", NULL);
+ Ofn = GetStringCatInfo(g, "Optname", Fn);
+ GetCharCatInfo("Recfm", (PSZ)dfm, buf, sizeof(buf));
+ Recfm = (toupper(*buf) == 'F') ? RECFM_FIX :
+ (toupper(*buf) == 'B') ? RECFM_BIN :
+ (toupper(*buf) == 'X') ? RECFM_NAF : // MGO
+ (toupper(*buf) == 'D') ? RECFM_DBF : RECFM_VAR;
+ Lrecl = GetIntCatInfo("Lrecl", 0);
+
+ if (Recfm != RECFM_DBF)
+ Compressed = GetIntCatInfo("Compressed", 0);
+
+ Mapped = GetBoolCatInfo("Mapped", map);
+//Block = GetIntCatInfo("Blocks", 0);
+//Last = GetIntCatInfo("Last", 0);
+ Ending = GetIntCatInfo("Ending", CRLF);
+
+ if (Ending <= 0) {
+ Ending = (Recfm == RECFM_BIN || Recfm == RECFM_VCT) ? 0 : CRLF;
+ SetIntCatInfo("Ending", Ending);
+ } // endif ending
+
+ if (Recfm == RECFM_FIX || Recfm == RECFM_BIN) {
+ Huge = GetBoolCatInfo("Huge", Cat->GetDefHuge());
+ Padded = GetBoolCatInfo("Padded", false);
+ Blksize = GetIntCatInfo("Blksize", 0);
+ Eof = (GetIntCatInfo("EOF", 0) != 0);
+ Teds = toupper(*GetStringCatInfo(g, "Endian", ""));
+ } else if (Recfm == RECFM_DBF) {
+ Maxerr = GetIntCatInfo("Maxerr", 0);
+ Accept = GetBoolCatInfo("Accept", false);
+ ReadMode = GetIntCatInfo("Readmode", 0);
+ } else // (Recfm == RECFM_VAR)
+ AvgLen = GetIntCatInfo("Avglen", 0);
+
+ // Ignore wrong Index definitions for catalog commands
+ SetIndexInfo();
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* Get the full path/name of the optization file. */
+/***********************************************************************/
+bool DOSDEF::GetOptFileName(PGLOBAL g, char *filename)
+ {
+ PCSZ ftype;
+
+ switch (Recfm) {
+ case RECFM_VAR: ftype = ".dop"; break;
+ case RECFM_FIX: ftype = ".fop"; break;
+ case RECFM_BIN: ftype = ".bop"; break;
+ case RECFM_VCT: ftype = ".vop"; break;
+ case RECFM_CSV: ftype = ".cop"; break;
+ case RECFM_DBF: ftype = ".dbp"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Recfm);
+ return true;
+ } // endswitch Ftype
+
+ PlugSetPath(filename, Ofn, GetPath());
+ strcat(PlugRemoveType(filename, filename), ftype);
+ return false;
+ } // end of GetOptFileName
+
+/***********************************************************************/
+/* After an optimize error occurred, remove all set optimize values. */
+/***********************************************************************/
+void DOSDEF::RemoveOptValues(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ PCOLDEF cdp;
+
+ // Delete settings of optimized columns
+ for (cdp = To_Cols; cdp; cdp = cdp->GetNext())
+ if (cdp->GetOpt()) {
+ cdp->SetMin(NULL);
+ cdp->SetMax(NULL);
+ cdp->SetNdv(0);
+ cdp->SetNbm(0);
+ cdp->SetDval(NULL);
+ cdp->SetBmap(NULL);
+ } // endif Opt
+
+ // Delete block position setting for not fixed tables
+ To_Pos = NULL;
+ AllocBlks = 0;
+
+ // Delete any eventually ill formed non matching optimization file
+ if (!GetOptFileName(g, filename))
+#if defined(_WIN32)
+ DeleteFile(filename);
+#else // UNIX
+ remove(filename);
+#endif // _WIN32
+
+ Optimized = 0;
+ } // end of RemoveOptValues
+
+/***********************************************************************/
+/* DeleteIndexFile: Delete DOS/UNIX index file(s) using platform API. */
+/***********************************************************************/
+bool DOSDEF::DeleteIndexFile(PGLOBAL g, PIXDEF pxdf)
+ {
+ PCSZ ftype;
+ char filename[_MAX_PATH];
+ bool sep, rc = false;
+
+ if (!To_Indx)
+ return false; // No index
+
+ // If true indexes are in separate files
+ sep = GetBoolCatInfo("SepIndex", false);
+
+ if (!sep && pxdf) {
+ strcpy(g->Message, MSG(NO_RECOV_SPACE));
+ return true;
+ } // endif sep
+
+ switch (Recfm) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_CSV: ftype = ".cnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(BAD_RECFM_VAL), Recfm);
+ return true;
+ } // endswitch Ftype
+
+ /*********************************************************************/
+ /* Check for existence of an index file. */
+ /*********************************************************************/
+ if (sep) {
+ // Indexes are save in separate files
+#if defined(_WIN32)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ bool all = !pxdf;
+
+ if (all)
+ pxdf = To_Indx;
+
+ for (; pxdf; pxdf = pxdf->GetNext()) {
+ _splitpath(Ofn, drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), pxdf->GetName());
+ _makepath(filename, drive, direc, fname, ftype);
+ PlugSetPath(filename, filename, GetPath());
+#if defined(_WIN32)
+ if (!DeleteFile(filename))
+ rc |= (GetLastError() != ERROR_FILE_NOT_FOUND);
+#else // UNIX
+ if (remove(filename))
+ rc |= (errno != ENOENT);
+#endif // UNIX
+
+ if (!all)
+ break;
+
+ } // endfor pxdf
+
+ } else { // !sep
+ // Drop all indexes, delete the common file
+ PlugSetPath(filename, Ofn, GetPath());
+ strcat(PlugRemoveType(filename, filename), ftype);
+#if defined(_WIN32)
+ if (!DeleteFile(filename))
+ rc = (GetLastError() != ERROR_FILE_NOT_FOUND);
+#else // UNIX
+ if (remove(filename))
+ rc = (errno != ENOENT);
+#endif // UNIX
+ } // endif sep
+
+ if (rc)
+ sprintf(g->Message, MSG(DEL_FILE_ERR), filename);
+
+ return rc; // Return true if error
+ } // end of DeleteIndexFile
+
+/***********************************************************************/
+/* InvalidateIndex: mark all indexes as invalid. */
+/***********************************************************************/
+bool DOSDEF::InvalidateIndex(PGLOBAL)
+ {
+ if (To_Indx)
+ for (PIXDEF xp = To_Indx; xp; xp = xp->Next)
+ xp->Invalid = true;
+
+ return false;
+ } // end of InvalidateIndex
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB DOSDEF::GetTable(PGLOBAL g, MODE mode)
+ {
+ // Mapping not used for insert
+ USETEMP tmp = UseTemp();
+ bool map = Mapped && mode != MODE_INSERT &&
+ !(tmp != TMP_NO && Recfm == RECFM_VAR
+ && mode == MODE_UPDATE) &&
+ !(tmp == TMP_FORCE &&
+ (mode == MODE_UPDATE || mode == MODE_DELETE));
+ PTXF txfp = NULL;
+ PTDBASE tdbp;
+
+ /*********************************************************************/
+ /* Allocate table and file processing class of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*********************************************************************/
+ if (Recfm == RECFM_DBF) {
+ if (Catfunc == FNC_NO) {
+ if (Zipped) {
+ if (mode == MODE_READ || mode == MODE_ANY || mode == MODE_ALTER) {
+ txfp = new(g) UZDFAM(this);
+ } else {
+ strcpy(g->Message, "Zipped DBF tables are read only");
+ return NULL;
+ } // endif's mode
+
+ } else if (map)
+ txfp = new(g) DBMFAM(this);
+ else
+ txfp = new(g) DBFFAM(this);
+
+ tdbp = new(g) TDBFIX(this, txfp);
+ } else
+ tdbp = new(g) TDBDCL(this); // Catfunc should be 'C'
+
+ } else if (Zipped) {
+#if defined(ZIP_SUPPORT)
+ if (Recfm == RECFM_VAR) {
+ if (mode == MODE_READ || mode == MODE_ANY || mode == MODE_ALTER) {
+ txfp = new(g) UNZFAM(this);
+ } else if (mode == MODE_INSERT) {
+ txfp = new(g) ZIPFAM(this);
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's mode
+
+ tdbp = new(g) TDBDOS(this, txfp);
+ } else {
+ if (mode == MODE_READ || mode == MODE_ANY || mode == MODE_ALTER) {
+ txfp = new(g) UZXFAM(this);
+ } else if (mode == MODE_INSERT) {
+ txfp = new(g) ZPXFAM(this);
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's mode
+
+ tdbp = new(g)TDBFIX(this, txfp);
+ } // endif Recfm
+
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } else if (Recfm != RECFM_VAR && Compressed < 2) {
+ if (Huge)
+ txfp = new(g) BGXFAM(this);
+ else if (map)
+ txfp = new(g) MPXFAM(this);
+ else if (Compressed) {
+#if defined(GZ_SUPPORT)
+ txfp = new(g) GZXFAM(this);
+#else // !GZ_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ");
+ return NULL;
+#endif // !GZ_SUPPORT
+ } else
+ txfp = new(g) FIXFAM(this);
+
+ tdbp = new(g) TDBFIX(this, txfp);
+ } else {
+ if (Compressed) {
+#if defined(GZ_SUPPORT)
+ if (Compressed == 1)
+ txfp = new(g) GZFAM(this);
+ else
+ txfp = new(g) ZLBFAM(this);
+
+#else // !GZ_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ");
+ return NULL;
+#endif // !GZ_SUPPORT
+ } else if (map)
+ txfp = new(g) MAPFAM(this);
+ else
+ txfp = new(g) DOSFAM(this);
+
+ // Txfp must be set even for not multiple tables because
+ // it is needed when calling Cardinality in GetBlockValues.
+ tdbp = new(g) TDBDOS(this, txfp);
+ } // endif Recfm
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+ else
+ /*******************************************************************/
+ /* For block tables, get eventually saved optimization values. */
+ /*******************************************************************/
+ if (tdbp->GetBlockValues(g)) {
+ PushWarning(g, tdbp);
+// return NULL; // causes a crash when deleting index
+ } else if (Recfm == RECFM_VAR || Compressed > 1) {
+ if (IsOptimized()) {
+ if (map) {
+ txfp = new(g) MBKFAM(this);
+ } else if (Compressed) {
+#if defined(GZ_SUPPORT)
+ if (Compressed == 1)
+ txfp = new(g) ZBKFAM(this);
+ else {
+ txfp->SetBlkPos(To_Pos);
+ ((PZLBFAM)txfp)->SetOptimized(To_Pos != NULL);
+ } // endelse
+#else
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ");
+ return NULL;
+#endif
+ } else
+ txfp = new(g) BLKFAM(this);
+
+ ((PTDBDOS)tdbp)->SetTxfp(txfp);
+ } // endif Optimized
+
+ } // endif Recfm
+
+ return tdbp;
+ } // end of GetTable
+
+/* ------------------------ Class TDBDOS ----------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBDOS class. This is the common class that */
+/* contain all that is common between the TDBDOS and TDBMAP classes. */
+/***********************************************************************/
+TDBDOS::TDBDOS(PDOSDEF tdp, PTXF txfp) : TDBASE(tdp)
+ {
+ if ((Txfp = txfp))
+ Txfp->SetTdbp(this);
+
+ Lrecl = tdp->Lrecl;
+ AvgLen = tdp->AvgLen;
+ Ftype = tdp->Recfm;
+ To_Line = NULL;
+//To_BlkIdx = NULL;
+ To_BlkFil = NULL;
+ SavFil = NULL;
+//Xeval = 0;
+ Beval = 0;
+ Abort = false;
+ Indxd = false;
+ } // end of TDBDOS standard constructor
+
+TDBDOS::TDBDOS(PGLOBAL g, PTDBDOS tdbp) : TDBASE(tdbp)
+ {
+ Txfp = (g) ? tdbp->Txfp->Duplicate(g) : tdbp->Txfp;
+ Lrecl = tdbp->Lrecl;
+ AvgLen = tdbp->AvgLen;
+ Ftype = tdbp->Ftype;
+ To_Line = tdbp->To_Line;
+//To_BlkIdx = tdbp->To_BlkIdx;
+ To_BlkFil = tdbp->To_BlkFil;
+ SavFil = tdbp->SavFil;
+//Xeval = tdbp->Xeval;
+ Beval = tdbp->Beval;
+ Abort = tdbp->Abort;
+ Indxd = tdbp->Indxd;
+ } // end of TDBDOS copy constructor
+
+// Method
+PTDB TDBDOS::Clone(PTABS t)
+ {
+ PTDB tp;
+ PDOSCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBDOS(g, this);
+
+ for (cp1 = (PDOSCOL)Columns; cp1; cp1 = (PDOSCOL)cp1->GetNext()) {
+ cp2 = new(g) DOSCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Allocate DOS column description block. */
+/***********************************************************************/
+PCOL TDBDOS::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) DOSCOL(g, cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Print debug information. */
+/***********************************************************************/
+void TDBDOS::PrintAM(FILE *f, char *m)
+ {
+ fprintf(f, "%s AM(%d): mode=%d\n", m, GetAmType(), Mode);
+
+ if (Txfp->To_File)
+ fprintf(f, "%s File: %s\n", m, Txfp->To_File);
+
+ } // end of PrintAM
+
+/***********************************************************************/
+/* Remake the indexes after the table was modified. */
+/***********************************************************************/
+int TDBDOS::ResetTableOpt(PGLOBAL g, bool dop, bool dox)
+ {
+ int prc = RC_OK, rc = RC_OK;
+
+ if (!GetFileLength(g)) {
+ // Void table, delete all opt and index files
+ PDOSDEF defp = (PDOSDEF)To_Def;
+
+ defp->RemoveOptValues(g);
+ return (defp->DeleteIndexFile(g, NULL)) ? RC_INFO : RC_OK;
+ } // endif GetFileLength
+
+ MaxSize = -1; // Size must be recalculated
+ Cardinal = -1; // as well as Cardinality
+
+ To_Filter = NULL; // Disable filtering
+//To_BlkIdx = NULL; // and index filtering
+ To_BlkFil = NULL; // and block filtering
+
+ // After the table was modified the indexes
+ // are invalid and we should mark them as such...
+ (void)((PDOSDEF)To_Def)->InvalidateIndex(g);
+
+ if (dop) {
+ Columns = NULL; // Not used anymore
+
+ if (Txfp->Blocked) {
+ // MakeBlockValues must be executed in non blocked mode
+ // except for ZLIB access method.
+ if (Txfp->GetAmType() == TYPE_AM_MAP) {
+ Txfp = new(g) MAPFAM((PDOSDEF)To_Def);
+#if defined(GZ_SUPPORT)
+ } else if (Txfp->GetAmType() == TYPE_AM_GZ) {
+ Txfp = new(g) GZFAM((PDOSDEF)To_Def);
+ } else if (Txfp->GetAmType() == TYPE_AM_ZLIB) {
+ Txfp->Reset();
+ ((PZLBFAM)Txfp)->SetOptimized(false);
+#endif // GZ_SUPPORT
+ } else if (Txfp->GetAmType() == TYPE_AM_BLK)
+ Txfp = new(g) DOSFAM((PDOSDEF)To_Def);
+
+ Txfp->SetTdbp(this);
+ } else
+ Txfp->Reset();
+
+ Use = USE_READY; // So the table can be reopened
+ Mode = MODE_ANY; // Just to be clean
+ rc = MakeBlockValues(g); // Redo optimization
+ } // endif dop
+
+ if (dox && (rc == RC_OK || rc == RC_INFO)) {
+ // Remake eventual indexes
+// if (Mode != MODE_UPDATE)
+ To_SetCols = NULL; // Positions are changed
+
+ Columns = NULL; // Not used anymore
+ Txfp->Reset(); // New start
+ Use = USE_READY; // So the table can be reopened
+ Mode = MODE_READ; // New mode
+ prc = rc;
+
+ if (PlgGetUser(g)->Check & CHK_OPT)
+ // We must remake all indexes.
+ rc = MakeIndex(g, NULL, false);
+
+ rc = (rc == RC_INFO) ? prc : rc;
+ } // endif dox
+
+ return rc;
+ } // end of ResetTableOpt
+
+/***********************************************************************/
+/* Calculate the block sizes so block I/O can be used and also the */
+/* Min/Max values for clustered/sorted table columns. */
+/***********************************************************************/
+int TDBDOS::MakeBlockValues(PGLOBAL g)
+ {
+ int i, lg, nrec, rc, n = 0;
+ int curnum, curblk, block, savndv, savnbm;
+ void *savmin, *savmax;
+ bool blocked, xdb2 = false;
+//POOLHEADER save;
+ PCOLDEF cdp;
+ PDOSDEF defp = (PDOSDEF)To_Def;
+ PDOSCOL colp = NULL;
+ PDBUSER dup = PlgGetUser(g);
+//void *memp = cat->GetDescp();
+ (void) defp->GetCat(); // XXX Should be removed?
+
+
+ if ((nrec = defp->GetElemt()) < 2) {
+ if (!To_Def->Partitioned()) {
+ // This may be wrong to do in some cases
+ strcpy(g->Message, MSG(TABLE_NOT_OPT));
+ return RC_INFO; // Not to be optimized
+ } else
+ return RC_OK;
+
+ } else if (GetMaxSize(g) == 0 || !(dup->Check & CHK_OPT)) {
+ // Suppress the opt file firstly if the table is void,
+ // secondly when it was modified with OPTIMIZATION unchecked
+ // because it is no more valid.
+ defp->RemoveOptValues(g); // Erase opt file
+ return RC_OK; // void table
+ } else if (MaxSize < 0)
+ return RC_FX;
+
+ defp->SetOptimized(0);
+
+ // Estimate the number of needed blocks
+ if ((block = (int)((MaxSize + (int)nrec - 1) / (int)nrec)) < 2) {
+ // This may be wrong to do in some cases
+ defp->RemoveOptValues(g);
+ strcpy(g->Message, MSG(TABLE_NOT_OPT));
+ return RC_INFO; // Not to be optimized
+ } // endif block
+
+ // We have to use local variables because Txfp->CurBlk is set
+ // to Rows+1 by unblocked variable length table access methods.
+ curblk = -1;
+ curnum = nrec - 1;
+//last = 0;
+ Txfp->Block = block; // This is useful mainly for
+ Txfp->CurBlk = curblk; // blocked tables (ZLBFAM), for
+ Txfp->CurNum = curnum; // others it is just to be clean.
+
+ /*********************************************************************/
+ /* Allocate the array of block starting positions. */
+ /*********************************************************************/
+//if (memp)
+// save = *(PPOOLHEADER)memp;
+
+ Txfp->BlkPos = (int*)PlugSubAlloc(g, NULL, (block + 1) * sizeof(int));
+
+ /*********************************************************************/
+ /* Allocate the blocks for clustered columns. */
+ /*********************************************************************/
+ blocked = Txfp->Blocked; // Save
+ Txfp->Blocked = true; // So column block can be allocated
+
+ for (cdp = defp->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++)
+ if (cdp->GetOpt()) {
+ lg = cdp->GetClen();
+
+ if (cdp->GetFreq() && cdp->GetFreq() <= dup->Maxbmp) {
+ cdp->SetXdb2(true);
+ savndv = cdp->GetNdv();
+ cdp->SetNdv(0); // Reset Dval number of values
+ xdb2 = true;
+ savmax = cdp->GetDval();
+ cdp->SetDval(PlugSubAlloc(g, NULL, cdp->GetFreq() * lg));
+ savnbm = cdp->GetNbm();
+ cdp->SetNbm(0); // Prevent Bmap allocation
+// savmin = cdp->GetBmap();
+// cdp->SetBmap(PlugSubAlloc(g, NULL, block * sizeof(int)));
+
+ if (trace(1))
+ htrc("Dval(%p) Bmap(%p) col(%d) %s Block=%d lg=%d\n",
+ cdp->GetDval(), cdp->GetBmap(), i, cdp->GetName(), block, lg);
+
+ // colp will be initialized with proper Dval VALBLK
+ colp = (PDOSCOL)MakeCol(g, cdp, colp, i);
+ colp->InitValue(g); // Allocate column value buffer
+ cdp->SetNbm(savnbm);
+// cdp->SetBmap(savmin); // Can be reused if the new size
+ cdp->SetDval(savmax); // is not greater than this one.
+ cdp->SetNdv(savndv);
+ } else {
+ cdp->SetXdb2(false); // Maxbmp may have been reset
+ savmin = cdp->GetMin();
+ savmax = cdp->GetMax();
+ cdp->SetMin(PlugSubAlloc(g, NULL, block * lg));
+ cdp->SetMax(PlugSubAlloc(g, NULL, block * lg));
+
+ // Valgrind complains if there are uninitialised bytes
+ // after the null character ending
+ if (IsTypeChar(cdp->GetType())) {
+ memset(cdp->GetMin(), 0, block * lg);
+ memset(cdp->GetMax(), 0, block * lg);
+ } // endif Type
+
+ if (trace(1))
+ htrc("min(%p) max(%p) col(%d) %s Block=%d lg=%d\n",
+ cdp->GetMin(), cdp->GetMax(), i, cdp->GetName(), block, lg);
+
+ // colp will be initialized with proper opt VALBLK's
+ colp = (PDOSCOL)MakeCol(g, cdp, colp, i);
+ colp->InitValue(g); // Allocate column value buffer
+ cdp->SetMin(savmin); // Can be reused if the number
+ cdp->SetMax(savmax); // of blocks does not change.
+ } // endif Freq
+
+ } // endif Clustered
+
+ // No optimised columns. Still useful for blocked variable tables.
+ if (!colp && defp->Recfm != RECFM_VAR) {
+ strcpy(g->Message, "No optimised columns");
+ return RC_INFO;
+ } // endif colp
+
+ Txfp->Blocked = blocked;
+
+ /*********************************************************************/
+ /* Now do calculate the optimization values. */
+ /*********************************************************************/
+ Mode = MODE_READ;
+
+ if (OpenDB(g))
+ return RC_FX;
+
+ if (xdb2) {
+ /*********************************************************************/
+ /* Retrieve the distinct values of XDB2 columns. */
+ /*********************************************************************/
+ if (GetDistinctColumnValues(g, nrec))
+ return RC_FX;
+
+ OpenDB(g); // Rewind the table file
+ } // endif xdb2
+
+#if defined(PROG_INFO)
+ /*********************************************************************/
+ /* Initialize progress information */
+ /*********************************************************************/
+ char *p = (char *)PlugSubAlloc(g, NULL, 24 + strlen(Name));
+
+ dup->Step = strcat(strcpy(p, MSG(OPTIMIZING)), Name);
+ dup->ProgMax = GetProgMax(g);
+ dup->ProgCur = 0;
+#endif // SOCKET_MODE || THREAD
+
+ /*********************************************************************/
+ /* Make block starting pos and min/max values of cluster columns. */
+ /*********************************************************************/
+ while ((rc = ReadDB(g)) == RC_OK) {
+ if (blocked) {
+ // A blocked FAM class handles CurNum and CurBlk (ZLBFAM)
+ if (!Txfp->CurNum)
+ Txfp->BlkPos[Txfp->CurBlk] = Txfp->GetPos();
+
+ } else {
+ if (++curnum >= nrec) {
+ if (++curblk >= block) {
+ strcpy(g->Message, MSG(BAD_BLK_ESTIM));
+ goto err;
+ } else
+ curnum = 0;
+
+ // Get block starting position
+ Txfp->BlkPos[curblk] = Txfp->GetPos();
+ } // endif CurNum
+
+// last = curnum + 1; // curnum is zero based
+ Txfp->CurBlk = curblk; // Used in COLDOS::SetMinMax
+ Txfp->CurNum = curnum; // Used in COLDOS::SetMinMax
+ } // endif blocked
+
+ /*******************************************************************/
+ /* Now calculate the min and max values for the cluster columns. */
+ /*******************************************************************/
+ for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->GetNext())
+ if (colp->Clustered == 2) {
+ if (colp->SetBitMap(g))
+ goto err;
+
+ } else
+ if (colp->SetMinMax(g))
+ goto err; // Currently: column is not sorted
+
+#if defined(PROG_INFO)
+ if (!dup->Step) {
+ strcpy(g->Message, MSG(OPT_CANCELLED));
+ goto err;
+ } else
+ dup->ProgCur = GetProgCur();
+#endif // PROG_INFO
+
+ n++; // Used to calculate block and last
+ } // endwhile
+
+ if (rc == RC_EF) {
+ Txfp->Nrec = nrec;
+
+#if 0 // No good because Curblk and CurNum after EOF are different
+ // depending on whether the file is mapped or not mapped.
+ if (blocked) {
+// Txfp->Block = Txfp->CurBlk + 1;
+ Txfp->Last = (Txfp->CurNum) ? Txfp->CurNum : nrec;
+// Txfp->Last = (Txfp->CurNum) ? Txfp->CurNum + 1 : nrec;
+ Txfp->Block = Txfp->CurBlk + (Txfp->Last == nrec ? 0 : 1);
+ } else {
+ Txfp->Block = curblk + 1;
+ Txfp->Last = last;
+ } // endif blocked
+#endif // 0
+
+ // New values of Block and Last
+ Txfp->Block = (n + nrec - 1) / nrec;
+ Txfp->Last = (n % nrec) ? (n % nrec) : nrec;
+
+ // This is needed to be able to calculate the last block size
+ Txfp->BlkPos[Txfp->Block] = Txfp->GetNextPos();
+ } else
+ goto err;
+
+ /*********************************************************************/
+ /* Save the optimization values for this table. */
+ /*********************************************************************/
+ if (!SaveBlockValues(g)) {
+ defp->Block = Txfp->Block;
+ defp->Last = Txfp->Last;
+ CloseDB(g);
+ defp->SetIntCatInfo("Blocks", Txfp->Block);
+ defp->SetIntCatInfo("Last", Txfp->Last);
+ return RC_OK;
+ } // endif SaveBlockValues
+
+ err:
+ // Restore Desc memory suballocation
+//if (memp)
+// *(PPOOLHEADER)memp = save;
+
+ defp->RemoveOptValues(g);
+ CloseDB(g);
+ return RC_FX;
+ } // end of MakeBlockValues
+
+/***********************************************************************/
+/* Save the block and Min/Max values for this table. */
+/* The problem here is to avoid name duplication, because more than */
+/* one data file can have the same name (but different types) and/or */
+/* the same data file can be used with different block sizes. This is */
+/* why we use Ofn that defaults to the file name but can be set to a */
+/* different name if necessary. */
+/***********************************************************************/
+bool TDBDOS::SaveBlockValues(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int lg, n[NZ + 2];
+ size_t nbk, ndv, nbm, block = Txfp->Block;
+ bool rc = false;
+ FILE *opfile;
+ PDOSCOL colp;
+ PDOSDEF defp = (PDOSDEF)To_Def;
+
+ if (defp->GetOptFileName(g, filename))
+ return true;
+
+ if (!(opfile = fopen(filename, "wb"))) {
+ sprintf(g->Message, MSG(OPEN_MODE_ERROR),
+ "wb", (int)errno, filename);
+ strcat(strcat(g->Message, ": "), strerror(errno));
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ return true;
+ } // endif opfile
+
+ memset(n, 0, sizeof(n)); // To avoid valgrind warning
+
+ if (Ftype == RECFM_VAR || defp->Compressed == 2) {
+ /*******************************************************************/
+ /* Write block starting positions into the opt file. */
+ /*******************************************************************/
+ block++;
+ lg = sizeof(int);
+ n[0] = Txfp->Last; n[1] = lg; n[2] = Txfp->Nrec; n[3] = Txfp->Block;
+
+ if (fwrite(n, sizeof(int), NZ, opfile) != NZ) {
+ sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ if (fwrite(Txfp->BlkPos, lg, block, opfile) != block) {
+ sprintf(g->Message, MSG(OPTBLK_WR_ERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ block--; // = Txfp->Block;
+ } // endif Ftype
+
+ /*********************************************************************/
+ /* Write the Min/Max values into the opt file. */
+ /*********************************************************************/
+ for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->Next) {
+ lg = colp->Value->GetClen();
+
+ // Now start the writing process
+ if (colp->Clustered == 2) {
+ // New XDB2 block optimization. Will be recognized when reading
+ // because the column index is negated.
+ ndv = colp->Ndv; nbm = colp->Nbm;
+ nbk = nbm * block;
+ n[0] = -colp->Index; n[1] = lg; n[2] = Txfp->Nrec; n[3] = block;
+ n[4] = ndv; n[5] = nbm;
+
+ if (fwrite(n, sizeof(int), NZ + 2, opfile) != NZ + 2) {
+ sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ if (fwrite(colp->Dval->GetValPointer(), lg, ndv, opfile) != ndv) {
+ sprintf(g->Message, MSG(OPT_DVAL_WR_ERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ if (fwrite(colp->Bmap->GetValPointer(), sizeof(int), nbk, opfile) != nbk) {
+ sprintf(g->Message, MSG(OPT_BMAP_WR_ERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ } else {
+ n[0] = colp->Index; n[1] = lg; n[2] = Txfp->Nrec; n[3] = block;
+
+ if (fwrite(n, sizeof(int), NZ, opfile) != NZ) {
+ sprintf(g->Message, MSG(OPT_HEAD_WR_ERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ if (fwrite(colp->Min->GetValPointer(), lg, block, opfile) != block) {
+ sprintf(g->Message, MSG(OPT_MIN_WR_ERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ if (fwrite(colp->Max->GetValPointer(), lg, block, opfile) != block) {
+ sprintf(g->Message, MSG(OPT_MAX_WR_ERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ } // endif Clustered
+
+ } // endfor colp
+
+ fclose(opfile);
+ return rc;
+ } // end of SaveBlockValues
+
+/***********************************************************************/
+/* Read the Min/Max values for this table. */
+/* The problem here is to avoid name duplication, because more than */
+/* one data file can have the same name (but different types) and/or */
+/* the same data file can be used with different block sizes. This is */
+/* why we use Ofn that defaults to the file name but can be set to a */
+/* different name if necessary. */
+/***********************************************************************/
+bool TDBDOS::GetBlockValues(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ int i, lg, n[NZ];
+ int nrec, block = 0, last = 0;
+ int len;
+ bool newblk = false;
+ size_t ndv, nbm, nbk, blk;
+ FILE *opfile;
+ PCOLDEF cdp;
+ PDOSDEF defp = (PDOSDEF)To_Def;
+ PDBUSER dup = PlgGetUser(g);
+
+ (void) defp->GetCat(); // XXX Should be removed?
+
+
+#if 0
+ if (Mode == MODE_INSERT && Txfp->GetAmType() == TYPE_AM_DOS)
+ return false;
+#endif // _WIN32
+
+ if (defp->Optimized || !(dup->Check & CHK_OPT))
+ return false; // Already done or to be redone
+
+ if (Ftype == RECFM_VAR || defp->Compressed == 2) {
+ /*******************************************************************/
+ /* Variable length file that can be read by block. */
+ /*******************************************************************/
+ nrec = (defp->GetElemt()) ? defp->GetElemt() : 1;
+
+ if (nrec > 1) {
+ // The table can be declared optimized if it is void.
+ // This is useful to handle Insert in optimized mode.
+ char filename[_MAX_PATH];
+ int h;
+ int flen = -1;
+
+ PlugSetPath(filename, defp->Fn, GetPath());
+ h = open(filename, O_RDONLY);
+ flen = (h == -1 && errno == ENOENT) ? 0 : _filelength(h);
+
+ if (h != -1)
+ close(h);
+
+ if (!flen) {
+ defp->SetOptimized(1);
+ return false;
+ } // endif flen
+
+ } else
+ return false; // Not optimisable
+
+ cdp = defp->GetCols();
+ i = 1;
+ } else {
+ /*******************************************************************/
+ /* Fixed length file. Opt file exists only for clustered columns. */
+ /*******************************************************************/
+ // Check for existence of clustered columns
+ for (cdp = defp->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++)
+ if (cdp->GetOpt())
+ break;
+
+ if (!cdp)
+ return false; // No optimization needed
+
+ if ((len = Cardinality(g)) < 0)
+ return true; // Table error
+ else if (!len)
+ return false; // File does not exist yet
+
+ block = Txfp->Block; // Was set in Cardinality
+ nrec = Txfp->Nrec;
+ } // endif Ftype
+
+ if (defp->GetOptFileName(g, filename))
+ return true;
+
+ if (!(opfile = fopen(filename, "rb")))
+ return false; // No saved values
+
+ if (Ftype == RECFM_VAR || defp->Compressed == 2) {
+ /*******************************************************************/
+ /* Read block starting positions from the opt file. */
+ /*******************************************************************/
+ lg = sizeof(int);
+
+ if (fread(n, sizeof(int), NZ, opfile) != NZ) {
+ sprintf(g->Message, MSG(OPT_HEAD_RD_ERR), strerror(errno));
+ goto err;
+ } // endif size
+
+ if (n[1] != lg || n[2] != nrec) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), filename);
+ goto err;
+ } // endif
+
+ last = n[0];
+ block = n[3];
+ blk = block + 1;
+
+ defp->To_Pos = (int*)PlugSubAlloc(g, NULL, blk * lg);
+
+ if (fread(defp->To_Pos, lg, blk, opfile) != blk) {
+ sprintf(g->Message, MSG(OPTBLK_RD_ERR), strerror(errno));
+ goto err;
+ } // endif size
+
+ } // endif Ftype
+
+ /*********************************************************************/
+ /* Read the Min/Max values from the opt file. */
+ /*********************************************************************/
+ for (; cdp; cdp = cdp->GetNext(), i++)
+ if (cdp->GetOpt()) {
+ lg = cdp->GetClen();
+ blk = block;
+
+ // Now start the reading process.
+ if (fread(n, sizeof(int), NZ, opfile) != NZ) {
+ sprintf(g->Message, MSG(OPT_HEAD_RD_ERR), strerror(errno));
+ goto err;
+ } // endif size
+
+ if (n[0] == -i) {
+ // Read the XDB2 opt values from the opt file
+ if (n[1] != lg || n[2] != nrec || n[3] != block) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), filename);
+ goto err;
+ } // endif
+
+ if (fread(n, sizeof(int), 2, opfile) != 2) {
+ sprintf(g->Message, MSG(OPT_HEAD_RD_ERR), strerror(errno));
+ goto err;
+ } // endif fread
+
+ ndv = n[0]; nbm = n[1]; nbk = nbm * blk;
+
+ if (cdp->GetNdv() < (int)ndv || !cdp->GetDval())
+ cdp->SetDval(PlugSubAlloc(g, NULL, ndv * lg));
+
+ cdp->SetNdv((int)ndv);
+
+ if (fread(cdp->GetDval(), lg, ndv, opfile) != ndv) {
+ sprintf(g->Message, MSG(OPT_DVAL_RD_ERR), strerror(errno));
+ goto err;
+ } // endif size
+
+ if (newblk || cdp->GetNbm() < (int)nbm || !cdp->GetBmap())
+ cdp->SetBmap(PlugSubAlloc(g, NULL, nbk * sizeof(int)));
+
+ cdp->SetNbm((int)nbm);
+
+ if (fread(cdp->GetBmap(), sizeof(int), nbk, opfile) != nbk) {
+ sprintf(g->Message, MSG(OPT_BMAP_RD_ERR), strerror(errno));
+ goto err;
+ } // endif size
+
+ cdp->SetXdb2(true);
+ } else {
+ // Read the Min/Max values from the opt file
+ if (n[0] != i || n[1] != lg || n[2] != nrec || n[3] != block) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), filename);
+ goto err;
+ } // endif
+
+ if (newblk || !cdp->GetMin())
+ cdp->SetMin(PlugSubAlloc(g, NULL, blk * lg));
+
+ if (fread(cdp->GetMin(), lg, blk, opfile) != blk) {
+ sprintf(g->Message, MSG(OPT_MIN_RD_ERR), strerror(errno));
+ goto err;
+ } // endif size
+
+ if (newblk || !cdp->GetMax())
+ cdp->SetMax(PlugSubAlloc(g, NULL, blk * lg));
+
+ if (fread(cdp->GetMax(), lg, blk, opfile) != blk) {
+ sprintf(g->Message, MSG(OPT_MAX_RD_ERR), strerror(errno));
+ goto err;
+ } // endif size
+
+ cdp->SetXdb2(false);
+ } // endif n[0] (XDB2)
+
+ } // endif Clustered
+
+ defp->SetBlock(block);
+ defp->Last = last; // For Cardinality
+ defp->SetAllocBlks(block);
+ defp->SetOptimized(1);
+ fclose(opfile);
+ MaxSize = -1; // Can be refined later
+ return false;
+
+ err:
+ defp->RemoveOptValues(g);
+ fclose(opfile);
+
+ // Ignore error if not in mode CHK_OPT
+ return (PlgGetUser(g)->Check & CHK_OPT) != 0;
+ } // end of GetBlockValues
+
+/***********************************************************************/
+/* This fonction is used while making XDB2 block optimization. */
+/* It constructs for each elligible columns, the sorted list of the */
+/* distinct values existing in the column. This function uses an */
+/* algorithm that permit to get several sets of distinct values by */
+/* reading the table only once, which cannot be done using a standard */
+/* SQL query. */
+/***********************************************************************/
+bool TDBDOS::GetDistinctColumnValues(PGLOBAL g, int nrec)
+ {
+ char *p;
+ int rc, blk, n = 0;
+ PDOSCOL colp;
+ PDBUSER dup = PlgGetUser(g);
+
+ /*********************************************************************/
+ /* Initialize progress information */
+ /*********************************************************************/
+ p = (char *)PlugSubAlloc(g, NULL, 48 + strlen(Name));
+ dup->Step = strcat(strcpy(p, MSG(GET_DIST_VALS)), Name);
+ dup->ProgMax = GetProgMax(g);
+ dup->ProgCur = 0;
+
+ while ((rc = ReadDB(g)) == RC_OK) {
+ for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->Next)
+ if (colp->Clustered == 2)
+ if (colp->AddDistinctValue(g))
+ return true; // Too many distinct values
+
+#if defined(SOCKET_MODE)
+ if (SendProgress(dup)) {
+ strcpy(g->Message, MSG(OPT_CANCELLED));
+ return true;
+ } else
+#elif defined(THREAD)
+ if (!dup->Step) {
+ strcpy(g->Message, MSG(OPT_CANCELLED));
+ return true;
+ } else
+#endif // THREAD
+ dup->ProgCur = GetProgCur();
+
+ n++;
+ } // endwhile
+
+ if (rc != RC_EF)
+ return true;
+
+ // Reset the number of table blocks
+//nrec = ((PDOSDEF)To_Def)->GetElemt(); (or default value)
+ blk = (n + nrec - 1) / nrec;
+ Txfp->Block = blk; // Useful mainly for ZLBFAM ???
+
+ // Set Nbm, Bmap for XDB2 columns
+ for (colp = (PDOSCOL)Columns; colp; colp = (PDOSCOL)colp->Next)
+ if (colp->Clustered == 2) {
+// colp->Cdp->SetNdv(colp->Ndv);
+ colp->Nbm = (colp->Ndv + MAXBMP - 1) / MAXBMP;
+ colp->Bmap = AllocValBlock(g, NULL, TYPE_INT, colp->Nbm * blk);
+ } // endif Clustered
+
+ return false;
+ } // end of GetDistinctColumnValues
+
+/***********************************************************************/
+/* Analyze the filter and construct the Block Evaluation Filter. */
+/* This is possible when a filter contains predicates implying a */
+/* column marked as "clustered" or "sorted" matched to a constant */
+/* argument. It is then possible by comparison against the smallest */
+/* and largest column values in each block to determine whether the */
+/* filter condition will be always true or always false for the block.*/
+/***********************************************************************/
+PBF TDBDOS::InitBlockFilter(PGLOBAL g, PFIL filp)
+ {
+ bool blk = Txfp->Blocked;
+
+ if (To_BlkFil)
+ return To_BlkFil; // Already done
+ else if (!filp)
+ return NULL;
+ else if (blk) {
+ if (Txfp->GetAmType() == TYPE_AM_DBF)
+ /*****************************************************************/
+ /* If RowID is used in this query, block optimization cannot be */
+ /* used because currently the file must be read sequentially. */
+ /*****************************************************************/
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_ROWID && !((RIDBLK*)cp)->GetRnm())
+ return NULL;
+
+ } // endif blk
+
+ int i, op = filp->GetOpc(), opm = filp->GetOpm();
+ bool cnv[2];
+ PCOL colp;
+ PXOB arg[2] = {NULL,NULL};
+ PBF *fp = NULL, bfp = NULL;
+
+ switch (op) {
+ case OP_EQ:
+ case OP_NE:
+ case OP_GT:
+ case OP_GE:
+ case OP_LT:
+ case OP_LE:
+ if (! opm) {
+ for (i = 0; i < 2; i++) {
+ arg[i] = filp->Arg(i);
+ cnv[i] = filp->Conv(i);
+ } // endfor i
+
+ bfp = CheckBlockFilari(g, arg, op, cnv);
+ break;
+ } // endif !opm
+
+ // if opm, pass thru
+ // fall through
+ case OP_IN:
+ if (filp->GetArgType(0) == TYPE_COLBLK &&
+ filp->GetArgType(1) == TYPE_ARRAY) {
+ arg[0] = filp->Arg(0);
+ arg[1] = filp->Arg(1);
+ colp = (PCOL)arg[0];
+
+ if (colp->GetTo_Tdb() == this) {
+ // Block evaluation is possible for...
+ if (colp->GetAmType() == TYPE_AM_ROWID) {
+ // Special column ROWID and constant array, but
+ // currently we don't know how to retrieve a RowID
+ // from a DBF table that is not sequentially read.
+// if (Txfp->GetAmType() != TYPE_AM_DBF ||
+// ((RIDBLK*)arg[0])->GetRnm())
+ bfp = new(g) BLKSPCIN(g, this, op, opm, arg, Txfp->Nrec);
+
+ } else if (blk && Txfp->Nrec > 1 && colp->IsClustered())
+ {
+ // Clustered column and constant array
+ if (colp->GetClustered() == 2)
+ bfp = new(g) BLKFILIN2(g, this, op, opm, arg);
+ else
+ bfp = new(g) BLKFILIN(g, this, op, opm, arg);
+ }
+ } // endif this
+
+#if 0
+ } else if (filp->GetArgType(0) == TYPE_SCALF &&
+ filp->GetArgType(1) == TYPE_ARRAY) {
+ arg[0] = filp->Arg(0);
+ arg[1] = filp->Arg(1);
+
+ if (((PSCALF)arg[0])->GetOp() == OP_ROW &&
+ arg[1]->GetResultType() == TYPE_LIST) {
+ PARRAY par = (PARRAY)arg[1];
+ LSTVAL *vlp = (LSTVAL*)par->GetValue();
+
+ ((SFROW*)arg[0])->GetParms(n);
+
+ if (n != vlp->GetN())
+ return NULL;
+ else
+ n = par->GetNval();
+
+ arg[1] = new(g) CONSTANT(vlp);
+ fp = (PBF*)PlugSubAlloc(g, NULL, n * sizeof(PBF));
+ cnv[0] = cnv[1] = false;
+
+ if (op == OP_IN)
+ op = OP_EQ;
+
+ for (i = 0; i < n; i++) {
+ par->GetNthValue(vlp, i);
+
+ if (!(fp[i] = CheckBlockFilari(g, arg, op, cnv)))
+ return NULL;
+
+ } // endfor i
+
+ bfp = new(g) BLKFILLOG(this, (opm == 2 ? OP_AND : OP_OR), fp, n);
+ } // endif ROW
+#endif // 0
+
+ } // endif Type
+
+ break;
+ case OP_AND:
+ case OP_OR:
+ fp = (PBF*)PlugSubAlloc(g, NULL, 2 * sizeof(PBF));
+ fp[0] = InitBlockFilter(g, (PFIL)(filp->Arg(0)));
+ fp[1] = InitBlockFilter(g, (PFIL)(filp->Arg(1)));
+
+ if (fp[0] || fp[1])
+ bfp = new(g) BLKFILLOG(this, op, fp, 2);
+
+ break;
+ case OP_NOT:
+ fp = (PBF*)PlugSubAlloc(g, NULL, sizeof(PBF));
+
+ if ((*fp = InitBlockFilter(g, (PFIL)(filp->Arg(0)))))
+ bfp = new(g) BLKFILLOG(this, op, fp, 1);
+
+ break;
+ case OP_LIKE:
+ default:
+ break;
+ } // endswitch op
+
+ return bfp;
+ } // end of InitBlockFilter
+
+/***********************************************************************/
+/* Analyze the passed arguments and construct the Block Filter. */
+/***********************************************************************/
+PBF TDBDOS::CheckBlockFilari(PGLOBAL g, PXOB *arg, int op, bool *cnv)
+ {
+//int i, n1, n2, ctype = TYPE_ERROR, n = 0, type[2] = {0,0};
+//bool conv = false, xdb2 = false, ok = false, b[2];
+//PXOB *xarg1, *xarg2 = NULL, xp[2];
+ int i, n = 0, type[2] = {0,0};
+ bool conv = false, xdb2 = false;
+ PXOB xp[2];
+ PCOL colp;
+ PBF bfp = NULL;
+
+ for (i = 0; i < 2; i++) {
+ switch (arg[i]->GetType()) {
+ case TYPE_CONST:
+ type[i] = 1;
+ // ctype = arg[i]->GetResultType();
+ break;
+ case TYPE_COLBLK:
+ conv = cnv[i];
+ colp = (PCOL)arg[i];
+
+ if (colp->GetTo_Tdb() == this) {
+ if (colp->GetAmType() == TYPE_AM_ROWID) {
+ // Currently we don't know how to retrieve a RowID
+ // from a DBF table that is not sequentially read.
+// if (Txfp->GetAmType() != TYPE_AM_DBF ||
+// ((RIDBLK*)arg[i])->GetRnm())
+ type[i] = 5;
+
+ } else if (Txfp->Blocked && Txfp->Nrec > 1 &&
+ colp->IsClustered()) {
+ type[i] = 2;
+ xdb2 = colp->GetClustered() == 2;
+ } // endif Clustered
+
+ } else if (colp->GetColUse(U_CORREL)) {
+ // This is a column pointing to the outer query of a
+ // correlated subquery, it has a constant value during
+ // each execution of the subquery.
+ type[i] = 1;
+// ctype = arg[i]->GetResultType();
+ } // endif this
+
+ break;
+// case TYPE_SCALF:
+// if (((PSCALF)arg[i])->GetOp() == OP_ROW) {
+// sfr[i] = (SFROW*)arg[i];
+// type[i] = 7;
+// } // endif Op
+
+// break;
+ default:
+ break;
+ } // endswitch ArgType
+
+ if (!type[i])
+ break;
+
+ n += type[i];
+ } // endfor i
+
+ if (n == 3 || n == 6) {
+ if (conv) {
+ // The constant has not the good type and will not match
+ // the block min/max values. Warn and abort.
+ sprintf(g->Message, "Block opt: %s", MSG(VALTYPE_NOMATCH));
+ PushWarning(g, this);
+ return NULL;
+ } // endif Conv
+
+ if (type[0] == 1) {
+ // Make it always as Column-op-Value
+ *xp = arg[0];
+ arg[0] = arg[1];
+ arg[1] = *xp;
+
+ switch (op) {
+ case OP_GT: op = OP_LT; break;
+ case OP_GE: op = OP_LE; break;
+ case OP_LT: op = OP_GT; break;
+ case OP_LE: op = OP_GE; break;
+ } // endswitch op
+
+ } // endif
+
+#if defined(_DEBUG)
+// assert(arg[0]->GetResultType() == ctype);
+#endif
+
+ if (n == 3) {
+ if (xdb2) {
+ if (((PDOSCOL)arg[0])->GetNbm() == 1)
+ bfp = new(g) BLKFILAR2(g, this, op, arg);
+ else // Multiple bitmap made of several ULONG's
+ bfp = new(g) BLKFILMR2(g, this, op, arg);
+ } else
+ bfp = new(g) BLKFILARI(g, this, op, arg);
+
+ } else // n = 6
+ bfp = new(g) BLKSPCARI(this, op, arg, Txfp->Nrec);
+
+#if 0
+ } else if (n == 8 || n == 14) {
+ if (n == 8 && ctype != TYPE_LIST) {
+ // Should never happen
+ strcpy(g->Message, "Block opt: bad constant");
+ throw 99;
+ } // endif Conv
+
+ if (type[0] == 1) {
+ // Make it always as Column-op-Value
+ sfr[0] = sfr[1];
+ arg[1] = arg[0];
+
+ switch (op) {
+ case OP_GT: op = OP_LT; break;
+ case OP_GE: op = OP_LE; break;
+ case OP_LT: op = OP_GT; break;
+ case OP_LE: op = OP_GE; break;
+ } // endswitch op
+
+ } // endif
+
+ xarg1 = sfr[0]->GetParms(n1);
+
+ if (n == 8) {
+ vlp = (LSTVAL*)arg[1]->GetValue();
+ n2 = vlp->GetN();
+ xp[1] = new(g) CONSTANT((PVAL)NULL);
+ } else
+ xarg2 = sfr[1]->GetParms(n2);
+
+ if (n1 != n2)
+ return NULL; // Should we flag an error ?
+
+ fp = (PBF*)PlugSubAlloc(g, NULL, n1 * sizeof(PBF));
+
+ for (i = 0; i < n1; i++) {
+ xp[0] = xarg1[i];
+
+ if (n == 8)
+ ((CONSTANT*)xp[1])->SetValue(vlp->GetSubVal(i));
+ else
+ xp[1] = xarg2[i];
+
+ b[0] = b[1] = (xp[0]->GetResultType() != xp[1]->GetResultType());
+ ok |= ((fp[i] = CheckBlockFilari(g, xp, op, b)) != NULL);
+ } // endfor i
+
+ if (ok)
+ bfp = new(g) BLKFILLOG(this, OP_AND, fp, n1);
+#endif // 0
+
+ } // endif n
+
+ return bfp;
+ } // end of CheckBlockFilari
+
+/***********************************************************************/
+/* ResetBlkFil: reset the block filter and restore filtering, or make */
+/* the block filter if To_Filter was not set when opening the table. */
+/***********************************************************************/
+void TDBDOS::ResetBlockFilter(PGLOBAL g)
+ {
+ if (!To_BlkFil) {
+ if (To_Filter)
+ if ((To_BlkFil = InitBlockFilter(g, To_Filter))) {
+ htrc("BlkFil=%p\n", To_BlkFil);
+ MaxSize = -1; // To be recalculated
+ } // endif To_BlkFil
+
+ return;
+ } // endif To_BlkFil
+
+ To_BlkFil->Reset(g);
+
+ if (SavFil && !To_Filter) {
+ // Restore filter if it was disabled by optimization
+ To_Filter = SavFil;
+ SavFil = NULL;
+ } // endif
+
+ Beval = 0;
+ } // end of ResetBlockFilter
+
+/***********************************************************************/
+/* Block optimization: evaluate the block index filter against */
+/* the min and max values of this block and return: */
+/* RC_OK: if some records in the block can meet filter criteria. */
+/* RC_NF: if no record in the block can meet filter criteria. */
+/* RC_EF: if no record in the remaining file can meet filter criteria.*/
+/* In addition, temporarily supress filtering if all the records in */
+/* the block meet filter criteria. */
+/***********************************************************************/
+int TDBDOS::TestBlock(PGLOBAL g)
+ {
+ int rc = RC_OK;
+
+ if (To_BlkFil && Beval != 2) {
+ // Check for block filtering evaluation
+ if (Beval == 1) {
+ // Filter was removed for last block, restore it
+ To_Filter = SavFil;
+ SavFil = NULL;
+ } // endif Beval
+
+ // Check for valid records in new block
+ switch (Beval = To_BlkFil->BlockEval(g)) {
+ case -2: // No more valid values in file
+ rc = RC_EF;
+ break;
+ case -1: // No valid values in block
+ rc = RC_NF;
+ break;
+ case 1: // All block values are valid
+ case 2: // All subsequent file values are Ok
+ // Before suppressing the filter for the block(s) it is
+ // necessary to reset the filtered columns to NOT_READ
+ // so their new values are retrieved by the SELECT list.
+ if (To_Filter) // Can be NULL when externally called (XDB)
+ To_Filter->Reset();
+
+ SavFil = To_Filter;
+ To_Filter = NULL; // So remove filter
+ } // endswitch Beval
+
+ if (trace(1))
+ htrc("BF Eval Beval=%d\n", Beval);
+
+ } // endif To_BlkFil
+
+ return rc;
+ } // end of TestBlock
+
+/***********************************************************************/
+/* Check whether we have to create/update permanent indexes. */
+/***********************************************************************/
+int TDBDOS::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add)
+ {
+ int k, n, rc = RC_OK;
+ bool fixed, doit, sep;
+ PCOL *keycols, colp;
+ PIXDEF xdp, sxp = NULL;
+ PKPDEF kdp;
+ PDOSDEF dfp;
+//PCOLDEF cdp;
+ PXINDEX x;
+ PXLOAD pxp;
+
+ Mode = MODE_READ;
+ Use = USE_READY;
+ dfp = (PDOSDEF)To_Def;
+
+ if (!Cardinality(g)) {
+ // Void table erase eventual index file(s)
+ (void)dfp->DeleteIndexFile(g, NULL);
+ return RC_OK;
+ } else
+ fixed = Ftype != RECFM_VAR;
+
+ // Are we are called from CreateTable or CreateIndex?
+ if (pxdf) {
+ if (!add && dfp->GetIndx()) {
+ strcpy(g->Message, MSG(INDX_EXIST_YET));
+ return RC_FX;
+ } // endif To_Indx
+
+ if (add && dfp->GetIndx()) {
+ for (sxp = dfp->GetIndx(); sxp; sxp = sxp->GetNext())
+ if (!stricmp(sxp->GetName(), pxdf->GetName())) {
+ sprintf(g->Message, MSG(INDEX_YET_ON), pxdf->GetName(), Name);
+ return RC_FX;
+ } else if (!sxp->GetNext())
+ break;
+
+ sxp->SetNext(pxdf);
+// first = false;
+ } else
+ dfp->SetIndx(pxdf);
+
+// pxdf->SetDef(dfp);
+ } else if (!(pxdf = dfp->GetIndx()))
+ return RC_INFO; // No index to make
+
+ try {
+ // Allocate all columns that will be used by indexes.
+ // This must be done before opening the table so specific
+ // column initialization can be done (in particular by TDBVCT)
+ for (n = 0, xdp = pxdf; xdp; xdp = xdp->GetNext())
+ for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext()) {
+ if (!(colp = ColDB(g, kdp->GetName(), 0))) {
+ sprintf(g->Message, MSG(INDX_COL_NOTIN), kdp->GetName(), Name);
+ goto err;
+ } else if (colp->GetResultType() == TYPE_DECIM) {
+ sprintf(g->Message, "Decimal columns are not indexable yet");
+ goto err;
+ } // endif Type
+
+ colp->InitValue(g);
+ n = MY_MAX(n, xdp->GetNparts());
+ } // endfor kdp
+
+ keycols = (PCOL*)PlugSubAlloc(g, NULL, n * sizeof(PCOL));
+ sep = dfp->GetBoolCatInfo("SepIndex", false);
+
+ /*********************************************************************/
+ /* Construct and save the defined indexes. */
+ /*********************************************************************/
+ for (xdp = pxdf; xdp; xdp = xdp->GetNext())
+ if (!OpenDB(g)) {
+ if (xdp->IsAuto() && fixed)
+ // Auto increment key and fixed file: use an XXROW index
+ continue; // XXROW index doesn't need to be made
+
+ // On Update, redo only indexes that are modified
+ doit = !To_SetCols;
+ n = 0;
+
+ if (sxp)
+ xdp->SetID(sxp->GetID() + 1);
+
+ for (kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext()) {
+ // Check whether this column was updated
+ for (colp = To_SetCols; !doit && colp; colp = colp->GetNext())
+ if (!stricmp(kdp->GetName(), colp->GetName()))
+ doit = true;
+
+ keycols[n++] = ColDB(g, kdp->GetName(), 0);
+ } // endfor kdp
+
+ // If no indexed columns were updated, don't remake the index
+ // if indexes are in separate files.
+ if (!doit && sep)
+ continue;
+
+ k = xdp->GetNparts();
+
+ // Make the index and save it
+ if (dfp->Huge)
+ pxp = new(g) XHUGE;
+ else
+ pxp = new(g) XFILE;
+
+ if (k == 1) // Simple index
+ x = new(g) XINDXS(this, xdp, pxp, keycols);
+ else // Multi-Column index
+ x = new(g) XINDEX(this, xdp, pxp, keycols);
+
+ if (!x->Make(g, sxp)) {
+ // Retreive define values from the index
+ xdp->SetMaxSame(x->GetMaxSame());
+ // xdp->SetSize(x->GetSize());
+
+ // store KXYCOL Mxs in KPARTDEF Mxsame
+ xdp->SetMxsame(x);
+
+#if defined(TRACE)
+ printf("Make done...\n");
+#endif // TRACE
+
+ // if (x->GetSize() > 0)
+ sxp = xdp;
+
+ xdp->SetInvalid(false);
+ } else
+ goto err;
+
+ } else
+ return RC_INFO; // Error or Physical table does not exist
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ rc = RC_FX;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ rc = RC_FX;
+ } // end catch
+
+ if (Use == USE_OPEN)
+ CloseDB(g);
+
+ return rc;
+
+err:
+ if (sxp)
+ sxp->SetNext(NULL);
+ else
+ dfp->SetIndx(NULL);
+
+ return RC_FX;
+ } // end of MakeIndex
+
+/***********************************************************************/
+/* Make a dynamic index. */
+/***********************************************************************/
+bool TDBDOS::InitialyzeIndex(PGLOBAL g, volatile PIXDEF xdp, bool sorted)
+{
+ int k;
+ volatile bool dynamic;
+ bool brc;
+ PCOL colp;
+ PCOLDEF cdp;
+ PVAL valp;
+ PXLOAD pxp;
+ volatile PKXBASE kxp;
+ PKPDEF kdp;
+
+ if (!xdp && !(xdp = To_Xdp)) {
+ strcpy(g->Message, "NULL dynamic index");
+ return true;
+ } else
+ dynamic = To_Filter && xdp->IsUnique() && xdp->IsDynamic();
+// dynamic = To_Filter && xdp->IsDynamic(); NIY
+
+ // Allocate the key columns definition block
+ Knum = xdp->GetNparts();
+ To_Key_Col = (PCOL*)PlugSubAlloc(g, NULL, Knum * sizeof(PCOL));
+
+ // Get the key column description list
+ for (k = 0, kdp = xdp->GetToKeyParts(); kdp; kdp = kdp->GetNext())
+ if (!(colp = ColDB(g, kdp->GetName(), 0)) || colp->InitValue(g)) {
+ sprintf(g->Message, "Wrong column %s", kdp->GetName());
+ return true;
+ } else
+ To_Key_Col[k++] = colp;
+
+#if defined(_DEBUG)
+ if (k != Knum) {
+ sprintf(g->Message, "Key part number mismatch for %s",
+ xdp->GetName());
+ return 0;
+ } // endif k
+#endif // _DEBUG
+
+ // Allocate the pseudo constants that will contain the key values
+ To_Link = (PXOB*)PlugSubAlloc(g, NULL, Knum * sizeof(PXOB));
+
+ for (k = 0, kdp = xdp->GetToKeyParts(); kdp; k++, kdp = kdp->GetNext()) {
+ if ((cdp = Key(k)->GetCdp()))
+ valp = AllocateValue(g, cdp->GetType(), cdp->GetLength());
+ else { // Special column ?
+ colp = Key(k);
+ valp = AllocateValue(g, colp->GetResultType(), colp->GetLength());
+ } // endif cdp
+
+ To_Link[k]= new(g) CONSTANT(valp);
+ } // endfor k
+
+ // Make the index on xdp
+ if (!xdp->IsAuto()) {
+ if (!dynamic) {
+ if (((PDOSDEF)To_Def)->Huge)
+ pxp = new(g) XHUGE;
+ else
+ pxp = new(g) XFILE;
+
+ } else
+ pxp = NULL;
+
+ if (Knum == 1) // Single index
+ kxp = new(g) XINDXS(this, xdp, pxp, To_Key_Col, To_Link);
+ else // Multi-Column index
+ kxp = new(g) XINDEX(this, xdp, pxp, To_Key_Col, To_Link);
+
+ } else // Column contains same values as ROWID
+ kxp = new(g) XXROW(this);
+
+ try {
+ if (dynamic) {
+ ResetBlockFilter(g);
+ kxp->SetDynamic(dynamic);
+ brc = kxp->Make(g, xdp);
+ } else
+ brc = kxp->Init(g);
+
+ if (!brc) {
+ if (Txfp->GetAmType() == TYPE_AM_BLK) {
+ // Cannot use indexing in DOS block mode
+ Txfp = new(g) DOSFAM((PBLKFAM)Txfp, (PDOSDEF)To_Def);
+ Txfp->AllocateBuffer(g);
+ To_BlkFil = NULL;
+ } // endif AmType
+
+ To_Kindex= kxp;
+
+ if (!(sorted && To_Kindex->IsSorted()) &&
+ ((Mode == MODE_UPDATE && IsUsingTemp(g)) ||
+ (Mode == MODE_DELETE && Txfp->GetAmType() != TYPE_AM_DBF)))
+ Indxd = true;
+
+ } // endif brc
+
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ brc = true;
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ brc = true;
+ } // end catch
+
+ return brc;
+} // end of InitialyzeIndex
+
+/***********************************************************************/
+/* DOS GetProgMax: get the max value for progress information. */
+/***********************************************************************/
+int TDBDOS::GetProgMax(PGLOBAL g)
+ {
+ return (To_Kindex) ? GetMaxSize(g) : GetFileLength(g);
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* DOS GetProgCur: get the current value for progress information. */
+/***********************************************************************/
+int TDBDOS::GetProgCur(void)
+ {
+ return (To_Kindex) ? To_Kindex->GetCur_K() + 1 : GetRecpos();
+ } // end of GetProgCur
+
+/***********************************************************************/
+/* RowNumber: return the ordinal number of the current row. */
+/***********************************************************************/
+int TDBDOS::RowNumber(PGLOBAL g, bool)
+ {
+ if (To_Kindex) {
+ /*******************************************************************/
+ /* Don't know how to retrieve RowID from file address. */
+ /*******************************************************************/
+ sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
+ GetAmName(g, Txfp->GetAmType()));
+ return 0;
+ } else
+ return Txfp->GetRowID();
+
+ } // end of RowNumber
+
+/***********************************************************************/
+/* DOS Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int TDBDOS::Cardinality(PGLOBAL g)
+ {
+ int n = Txfp->Cardinality(NULL);
+
+ if (!g)
+ return (Mode == MODE_ANY) ? 1 : n;
+
+ if (Cardinal < 0) {
+ if (!Txfp->Blocked && n == 0) {
+ // Info command, we try to return exact row number
+ PDOSDEF dfp = (PDOSDEF)To_Def;
+ PIXDEF xdp = dfp->To_Indx;
+
+ if (xdp && xdp->IsValid()) {
+ // Cardinality can be retreived from one index
+ PXLOAD pxp;
+
+ if (dfp->Huge)
+ pxp = new(g) XHUGE;
+ else
+ pxp = new(g) XFILE;
+
+ PXINDEX kxp = new(g) XINDEX(this, xdp, pxp, NULL, NULL);
+
+ if (!(kxp->GetAllSizes(g, Cardinal)))
+ return Cardinal;
+
+ } // endif Mode
+
+ if (Mode == MODE_ANY && ExactInfo()) {
+ // Using index impossible or failed, do it the hard way
+ Mode = MODE_READ;
+ To_Line = (char*)PlugSubAlloc(g, NULL, (size_t)Lrecl + 1);
+
+ if (Txfp->OpenTableFile(g))
+ return (Cardinal = Txfp->Cardinality(g));
+
+ for (Cardinal = 0; n != RC_EF;)
+ if (!(n = Txfp->ReadBuffer(g)))
+ Cardinal++;
+
+ Txfp->CloseTableFile(g, false);
+ Mode = MODE_ANY;
+ } else {
+ // Return the best estimate
+ int len = GetFileLength(g);
+
+ if (len >= 0) {
+ int rec;
+
+ if (trace(1))
+ htrc("Estimating lines len=%d ending=%d/n",
+ len, ((PDOSDEF)To_Def)->Ending);
+
+ /*************************************************************/
+ /* Estimate the number of lines in the table (if not known) */
+ /* by dividing the file length by the average record length. */
+ /*************************************************************/
+ rec = ((PDOSDEF)To_Def)->Ending;
+
+ if (AvgLen <= 0) // No given average estimate
+ rec += EstimatedLength();
+ else // An estimate was given for the average record length
+ rec += AvgLen;
+
+ Cardinal = (len + rec - 1) / rec;
+
+ if (trace(1))
+ htrc("avglen=%d MaxSize%d\n", rec, Cardinal);
+
+ } // endif len
+
+ } // endif Mode
+
+ } else
+ Cardinal = Txfp->Cardinality(g);
+
+ } // endif Cardinal
+
+ return Cardinal;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* DOS GetMaxSize: returns file size estimate in number of lines. */
+/* This function covers variable record length files. */
+/***********************************************************************/
+int TDBDOS::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize >= 0)
+ return MaxSize;
+
+ if (!Cardinality(NULL)) {
+ int len = GetFileLength(g);
+
+ if (len >= 0) {
+ int rec;
+
+ if (trace(1))
+ htrc("Estimating lines len=%d ending=%d/n",
+ len, ((PDOSDEF)To_Def)->Ending);
+
+ /*****************************************************************/
+ /* Estimate the number of lines in the table (if not known) by */
+ /* dividing the file length by minimum record length. */
+ /*****************************************************************/
+ rec = EstimatedLength() + ((PDOSDEF)To_Def)->Ending;
+ MaxSize = (len + rec - 1) / rec;
+
+ if (trace(1))
+ htrc("avglen=%d MaxSize%d\n", rec, MaxSize);
+
+ } // endif len
+
+ } else
+ MaxSize = Cardinality(g);
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* DOS EstimatedLength. Returns an estimated minimum line length. */
+/***********************************************************************/
+int TDBDOS::EstimatedLength(void)
+ {
+ int dep = 0;
+ PCOLDEF cdp = To_Def->GetCols();
+
+ if (!cdp->GetNext()) {
+ // One column table, we are going to return a ridiculous
+ // result if we set dep to 1
+ dep = 1 + cdp->GetLong() / 20; // Why 20 ?????
+ } else for (; cdp; cdp = cdp->GetNext())
+ if (!(cdp->Flags & (U_VIRTUAL|U_SPECIAL)))
+ dep = MY_MAX(dep, cdp->GetOffset());
+
+ return (int)dep;
+ } // end of Estimated Length
+
+/***********************************************************************/
+/* DOS tables favor the use temporary files for Update. */
+/***********************************************************************/
+bool TDBDOS::IsUsingTemp(PGLOBAL)
+ {
+ USETEMP utp = UseTemp();
+
+ return (utp == TMP_YES || utp == TMP_FORCE ||
+ (utp == TMP_AUTO && Mode == MODE_UPDATE));
+ } // end of IsUsingTemp
+
+/***********************************************************************/
+/* DOS Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool TDBDOS::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("DOS OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ if (!To_Kindex) {
+ Txfp->Rewind(); // see comment in Work.log
+
+ if (SkipHeader(g))
+ return true;
+
+ } else
+ /*****************************************************************/
+ /* Table is to be accessed through a sorted index table. */
+ /*****************************************************************/
+ To_Kindex->Reset();
+
+ ResetBlockFilter(g);
+ return false;
+ } // endif use
+
+ if (Mode == MODE_DELETE && !Next && Txfp->GetAmType() != TYPE_AM_DOS
+#if defined(BSON_SUPPORT)
+ && Txfp->GetAmType() != TYPE_AM_BIN
+#endif // BSON_SUPPORT
+ && Txfp->GetAmType() != TYPE_AM_MGO) {
+ // Delete all lines. Not handled in MAP or block mode
+ Txfp = new(g) DOSFAM((PDOSDEF)To_Def);
+ Txfp->SetTdbp(this);
+ } else if (Txfp->Blocked && (Mode == MODE_DELETE ||
+ (Mode == MODE_UPDATE && UseTemp() != TMP_NO))) {
+ /*******************************************************************/
+ /* Delete is not currently handled in block mode neither Update */
+ /* when using a temporary file. */
+ /*******************************************************************/
+ if (Txfp->GetAmType() == TYPE_AM_MAP && Mode == MODE_DELETE)
+ Txfp = new(g) MAPFAM((PDOSDEF)To_Def);
+#if defined(GZ_SUPPORT)
+ else if (Txfp->GetAmType() == TYPE_AM_GZ)
+ Txfp = new(g) GZFAM((PDOSDEF)To_Def);
+#endif // GZ_SUPPORT
+ else // if (Txfp->GetAmType() != TYPE_AM_DOS) ???
+ Txfp = new(g) DOSFAM((PDOSDEF)To_Def);
+
+ Txfp->SetTdbp(this);
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Open according to logical input/output mode required. */
+ /* Use conventionnal input/output functions. */
+ /* Treat files as binary in Delete mode (for line moving) */
+ /*********************************************************************/
+ if (Txfp->OpenTableFile(g))
+ return true;
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Allocate the block filter tree if evaluation is possible. */
+ /*********************************************************************/
+ To_BlkFil = InitBlockFilter(g, To_Filter);
+
+ /*********************************************************************/
+ /* Lrecl does not include line ending */
+ /*********************************************************************/
+ size_t linelen = Lrecl + ((PDOSDEF)To_Def)->Ending + 1;
+
+ To_Line = (char*)PlugSubAlloc(g, NULL, linelen);
+
+ if (Mode == MODE_INSERT) {
+ // Spaces between fields must be filled with blanks
+ memset(To_Line, ' ', Lrecl);
+ To_Line[Lrecl] = '\0';
+ } else
+ memset(To_Line, 0, linelen);
+
+ if (trace(1))
+ htrc("OpenDos: R%hd mode=%d To_Line=%p\n", Tdb_No, Mode, To_Line);
+
+ if (SkipHeader(g)) // When called from CSV/FMT files
+ return true;
+
+ /*********************************************************************/
+ /* Reset statistics values. */
+ /*********************************************************************/
+ num_read = num_there = num_eq[0] = num_eq[1] = 0;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for DOS access method. */
+/***********************************************************************/
+int TDBDOS::ReadDB(PGLOBAL g)
+ {
+ if (trace(2))
+ htrc("DOS ReadDB: R%d Mode=%d key=%p link=%p Kindex=%p To_Line=%p\n",
+ GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex, To_Line);
+
+ if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ int recpos = To_Kindex->Fetch(g);
+
+ switch (recpos) {
+ case -1: // End of file reached
+ return RC_EF;
+ case -2: // No match for join
+ return RC_NF;
+ case -3: // Same record as non null last one
+ num_there++;
+ return RC_OK;
+ default:
+ /***************************************************************/
+ /* Set the file position according to record to read. */
+ /***************************************************************/
+ if (SetRecpos(g, recpos))
+ return RC_FX;
+
+ if (trace(2))
+ htrc("File position is now %d\n", GetRecpos());
+
+ if (Mode == MODE_READ)
+ /*************************************************************/
+ /* Defer physical reading until one column setting needs it */
+ /* as it can be a big saving on joins where no other column */
+ /* than the keys are used, so reading is unnecessary. */
+ /*************************************************************/
+ if (Txfp->DeferReading())
+ return RC_OK;
+
+ } // endswitch recpos
+
+ } // endif To_Kindex
+
+ if (trace(2))
+ htrc(" ReadDB: this=%p To_Line=%p\n", this, To_Line);
+
+ /*********************************************************************/
+ /* Now start the reading process. */
+ /*********************************************************************/
+ return ReadBuffer(g);
+ } // end of ReadDB
+
+/***********************************************************************/
+/* PrepareWriting: Prepare the line to write. */
+/***********************************************************************/
+bool TDBDOS::PrepareWriting(PGLOBAL)
+ {
+ if (Ftype == RECFM_VAR && (Mode == MODE_INSERT || Txfp->GetUseTemp())) {
+ char *p;
+
+ /*******************************************************************/
+ /* Suppress trailing blanks. */
+ /* Also suppress eventual null from last line. */
+ /*******************************************************************/
+ for (p = To_Line + Lrecl -1; p >= To_Line; p--)
+ if (*p && *p != ' ')
+ break;
+
+ *(++p) = '\0';
+ } // endif Mode
+
+ return false;
+ } // end of PrepareWriting
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for DOS access method. */
+/***********************************************************************/
+int TDBDOS::WriteDB(PGLOBAL g)
+ {
+ if (trace(2))
+ htrc("DOS WriteDB: R%d Mode=%d \n", Tdb_No, Mode);
+
+ // Make the line to write
+ if (PrepareWriting(g))
+ return RC_FX;
+
+ if (trace(2))
+ htrc("Write: line is='%s'\n", To_Line);
+
+ // Now start the writing process
+ return Txfp->WriteBuffer(g);
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for DOS (and FIX) access method. */
+/* RC_FX means delete all. Nothing to do here (was done at open). */
+/***********************************************************************/
+int TDBDOS::DeleteDB(PGLOBAL g, int irc)
+ {
+ return (irc == RC_FX) ? RC_OK : Txfp->DeleteRecords(g, irc);
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for DOS access method. */
+/***********************************************************************/
+void TDBDOS::CloseDB(PGLOBAL g)
+ {
+ if (To_Kindex) {
+ To_Kindex->Close();
+ To_Kindex = NULL;
+ } // endif
+
+ Txfp->CloseTableFile(g, Abort);
+ RestoreNrec();
+ } // end of CloseDB
+
+// ------------------------ DOSCOL functions ----------------------------
+
+/***********************************************************************/
+/* DOSCOL public constructor (also called by MAPCOL). */
+/***********************************************************************/
+DOSCOL::DOSCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PCSZ am)
+ : COLBLK(cdp, tp, i)
+ {
+ char *p;
+ int prec = Format.Prec;
+ PTXF txfp = ((PTDBDOS)tp)->Txfp;
+
+ assert(cdp);
+
+ if (cp) {
+ Next = cp->GetNext();
+ cp->SetNext(this);
+ } else {
+ Next = tp->GetColumns();
+ tp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional Dos access method information for column.
+ Deplac = cdp->GetOffset();
+ Long = cdp->GetLong();
+ To_Val = NULL;
+ Clustered = cdp->GetOpt();
+ Sorted = (cdp->GetOpt() == 2) ? 1 : 0;
+ Ndv = 0; // Currently used only for XDB2
+ Nbm = 0; // Currently used only for XDB2
+ Min = NULL;
+ Max = NULL;
+ Bmap = NULL;
+ Dval = NULL;
+ Buf = NULL;
+
+ if (txfp && txfp->Blocked && Opt && (cdp->GetMin() || cdp->GetDval())) {
+ int nblk = txfp->GetBlock();
+
+ Clustered = (cdp->GetXdb2()) ? 2 : 1;
+ Sorted = (cdp->GetOpt() > 1) ? 1 : 0; // Currently ascending only
+
+ if (Clustered == 1) {
+ Min = AllocValBlock(g, cdp->GetMin(), Buf_Type, nblk, Long, prec);
+ Max = AllocValBlock(g, cdp->GetMax(), Buf_Type, nblk, Long, prec);
+ } else { // Clustered == 2
+ // Ndv is the number of distinct values in Dval. Ndv and Nbm
+ // may be 0 when optimizing because Ndval is not filled yet,
+ // but the size of the passed Dval memory block is Ok.
+ Ndv = cdp->GetNdv();
+ Dval = AllocValBlock(g, cdp->GetDval(), Buf_Type, Ndv, Long, prec);
+
+ // Bmap cannot be allocated when optimizing, we must know Nbm first
+ if ((Nbm = cdp->GetNbm()))
+ Bmap = AllocValBlock(g, cdp->GetBmap(), TYPE_INT, Nbm * nblk);
+
+ } // endif Clustered
+
+ } // endif Opt
+
+ OldVal = NULL; // Currently used only in MinMax
+ Dsp = 0;
+ Ldz = false;
+ Nod = false;
+ Dcm = -1;
+ p = cdp->GetFmt();
+ Buf = NULL;
+
+ if (p && IsTypeNum(Buf_Type)) {
+ // Formatted numeric value
+ for (; p && *p && isalpha(*p); p++)
+ switch (toupper(*p)) {
+ case 'Z': // Have leading zeros
+ Ldz = true;
+ break;
+ case 'N': // Have no decimal point
+ Nod = true;
+ break;
+ case 'D': // Decimal separator
+ Dsp = *(++p);
+ break;
+ } // endswitch p
+
+ // Set number of decimal digits
+ Dcm = (*p) ? atoi(p) : GetScale();
+ } // endif fmt
+
+ if (trace(1))
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ } // end of DOSCOL constructor
+
+/***********************************************************************/
+/* DOSCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+DOSCOL::DOSCOL(DOSCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Deplac = col1->Deplac;
+ Long = col1->Long;
+ To_Val = col1->To_Val;
+ Ldz = col1->Ldz;
+ Dsp = col1->Dsp;
+ Nod = col1->Nod;
+ Dcm = col1->Dcm;
+ OldVal = col1->OldVal;
+ Buf = col1->Buf;
+ Clustered = col1->Clustered;
+ Sorted = col1->Sorted;
+ Min = col1->Min;
+ Max = col1->Max;
+ Bmap = col1->Bmap;
+ Dval = col1->Dval;
+ Ndv = col1->Ndv;
+ Nbm = col1->Nbm;
+ } // end of DOSCOL copy constructor
+
+/***********************************************************************/
+/* VarSize: This function tells UpdateDB whether or not the block */
+/* optimization file must be redone if this column is updated, even */
+/* it is not sorted or clustered. This applies to the last column of */
+/* a variable length table that is blocked, because if it is updated */
+/* using a temporary file, the block size may be modified. */
+/***********************************************************************/
+bool DOSCOL::VarSize(void)
+ {
+ PTDBDOS tdbp = (PTDBDOS)To_Tdb;
+ PTXF txfp = tdbp->Txfp;
+
+ if (Cdp && !Cdp->GetNext() // Must be the last column
+ && tdbp->Ftype == RECFM_VAR // of a DOS variable length
+ && txfp->Blocked // blocked table
+ && txfp->GetUseTemp()) // using a temporary file.
+ return true;
+ else
+ return false;
+
+ } // end VarSize
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool DOSCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+ {
+ if (!(To_Val = value)) {
+ sprintf(g->Message, MSG(VALUE_ERROR), Name);
+ return true;
+ } else if (Buf_Type == value->GetType()) {
+ // Values are of the (good) column type
+ if (Buf_Type == TYPE_DATE) {
+ // If any of the date values is formatted
+ // output format must be set for the receiving table
+ if (GetDomain() || ((DTVAL *)value)->IsFormatted())
+ goto newval; // This will make a new value;
+
+ } else if (Buf_Type == TYPE_DOUBLE)
+ // Float values must be written with the correct (column) precision
+ // Note: maybe this should be forced by ShowValue instead of this ?
+ value->SetPrec(GetScale());
+
+ Value = value; // Directly access the external value
+ } else {
+ // Values are not of the (good) column type
+ if (check) {
+ sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
+ GetTypeName(Buf_Type), GetTypeName(value->GetType()));
+ return true;
+ } // endif check
+
+ newval:
+ if (InitValue(g)) // Allocate the matching value block
+ return true;
+
+ } // endif's Value, Buf_Type
+
+ // Allocate the buffer used in WriteColumn for numeric columns
+ if (!Buf && IsTypeNum(Buf_Type))
+ Buf = (char*)PlugSubAlloc(g, NULL, MY_MAX(64, Long + 1));
+ else // Text columns do not need additional buffer
+ Buf = (char*)Value->GetTo_Val();
+
+ // Because Colblk's have been made from a copy of the original TDB in
+ // case of Update, we must reset them to point to the original one.
+ if (To_Tdb->GetOrig())
+ To_Tdb = (PTDB)To_Tdb->GetOrig();
+
+ // Set the Column
+ Status = (ok) ? BUF_EMPTY : BUF_NO;
+ return false;
+ } // end of SetBuffer
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the last line */
+/* read from the corresponding table, extract from it the field */
+/* corresponding to this column and convert it to buffer type. */
+/***********************************************************************/
+void DOSCOL::ReadColumn(PGLOBAL g)
+ {
+ char *p = NULL;
+ int i, rc;
+ int field;
+ bool err = false;
+ double dval;
+ PTDBDOS tdbp = (PTDBDOS)To_Tdb;
+
+ if (trace(2))
+ htrc(
+ "DOS ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type);
+
+ /*********************************************************************/
+ /* If physical reading of the line was deferred, do it now. */
+ /*********************************************************************/
+ if (!tdbp->IsRead())
+ if ((rc = tdbp->ReadBuffer(g)) != RC_OK) {
+ if (rc == RC_EF)
+ sprintf(g->Message, MSG(INV_DEF_READ), rc);
+
+ throw 11;
+ } // endif
+
+ p = tdbp->To_Line + Deplac;
+ field = Long;
+
+ /*********************************************************************/
+ /* For a variable length file, check if the field exists. */
+ /*********************************************************************/
+ if ((tdbp->Ftype == RECFM_VAR || tdbp->Ftype == RECFM_CSV)
+ && strlen(tdbp->To_Line) < (unsigned)Deplac)
+ field = 0;
+ else if (Dsp)
+ for(i = 0; i < field; i++)
+ if (p[i] == Dsp)
+ p[i] = '.';
+
+ switch (tdbp->Ftype) {
+ case RECFM_VAR:
+ case RECFM_FIX: // Fixed length text file
+ case RECFM_CSV: // Variable length CSV or FMT file
+ case RECFM_DBF: // Fixed length DBase file
+ if (Nod) switch (Buf_Type) {
+ case TYPE_INT:
+ case TYPE_SHORT:
+ case TYPE_TINY:
+ case TYPE_BIGINT:
+ err = Value->SetValue_char(p, field - Dcm);
+ break;
+ case TYPE_DOUBLE:
+ if (!(err = Value->SetValue_char(p, field))) {
+ dval = Value->GetFloatValue();
+
+ for (i = 0; i < Dcm; i++)
+ dval /= 10.0;
+
+ Value->SetValue(dval);
+ } // endif err
+
+ break;
+ default:
+ err = Value->SetValue_char(p, field);
+
+ if (!err && Buf_Type == TYPE_DECIM) {
+ char* s = Value->GetCharValue();
+
+ if (!(err = ((i = strlen(s)) >= Value->GetClen()))) {
+ for (int d = Dcm + 1; d; i--, d--)
+ s[i + 1] = s[i];
+
+ s[i + 1] = '.';
+ } // endif err
+
+ } // endif DECIM
+
+ break;
+ } // endswitch Buf_Type
+
+ else
+ err = Value->SetValue_char(p, field);
+
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_RECFM), tdbp->Ftype);
+ throw 34;
+ } // endswitch Ftype
+
+ if (err) {
+ sprintf(g->Message, "Out of range value for column %s at row %d",
+ Name, tdbp->RowNumber(g));
+ PushWarning(g, tdbp);
+ } // endif err
+
+ // Set null when applicable
+ if (Nullable)
+ Value->SetNull(Value->IsZero());
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last line */
+/* read from the corresponding table, and rewrite the field */
+/* corresponding to this column from the column buffer and type. */
+/***********************************************************************/
+void DOSCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, fmt[32];
+ int i, k, n, len, field;
+ PTDBDOS tdbp = (PTDBDOS)To_Tdb;
+
+ if (trace(2))
+ htrc("DOS WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status);
+
+ p = tdbp->To_Line + Deplac;
+
+ if (trace(2))
+ htrc("Lrecl=%d deplac=%d int=%d\n", tdbp->Lrecl, Deplac, Long);
+
+ field = Long;
+
+ if (tdbp->Ftype == RECFM_VAR && tdbp->Mode == MODE_UPDATE) {
+ len = (signed)strlen(tdbp->To_Line);
+
+ if (tdbp->IsUsingTemp(g))
+ // Because of eventual missing field(s) the buffer must be reset
+ memset(tdbp->To_Line + len, ' ', tdbp->Lrecl - len);
+ else
+ // The size actually available must be recalculated
+ field = MY_MIN(len - Deplac, Long);
+
+ } // endif Ftype
+
+ if (trace(2))
+ htrc("Long=%d field=%d coltype=%d colval=%p\n",
+ Long, field, Buf_Type, Value);
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ /*********************************************************************/
+ /* This test is only useful for compressed(2) tables. */
+ /*********************************************************************/
+ if (tdbp->Ftype != RECFM_BIN) {
+ if (Ldz || Nod || Dcm >= 0) {
+ switch (Buf_Type) {
+ case TYPE_SHORT:
+ strcpy(fmt, (Ldz) ? "%0*hd" : "%*.hd");
+ i = 0;
+
+ if (Nod)
+ for (; i < Dcm; i++)
+ strcat(fmt, "0");
+
+ len = sprintf(Buf, fmt, field - i, Value->GetShortValue());
+ break;
+ case TYPE_INT:
+ strcpy(fmt, (Ldz) ? "%0*d" : "%*.d");
+ i = 0;
+
+ if (Nod)
+ for (; i < Dcm; i++)
+ strcat(fmt, "0");
+
+ len = sprintf(Buf, fmt, field - i, Value->GetIntValue());
+ break;
+ case TYPE_TINY:
+ strcpy(fmt, (Ldz) ? "%0*d" : "%*.d");
+ i = 0;
+
+ if (Nod)
+ for (; i < Dcm; i++)
+ strcat(fmt, "0");
+
+ len = sprintf(Buf, fmt, field - i, Value->GetTinyValue());
+ break;
+ case TYPE_DOUBLE:
+ case TYPE_DECIM:
+ strcpy(fmt, (Ldz) ? "%0*.*lf" : "%*.*lf");
+ len = field + ((Nod && Dcm) ? 1 : 0);
+ snprintf(Buf, len + 1, fmt, len, Dcm, Value->GetFloatValue());
+ len = strlen(Buf);
+
+ if (Nod && Dcm)
+ for (i = k = 0; i < len; i++, k++)
+ if (Buf[i] != ' ') {
+ if (Buf[i] == '.')
+ k++;
+
+ Buf[i] = Buf[k];
+ } // endif Buf(i)
+
+ len = strlen(Buf);
+ break;
+ default:
+ sprintf(g->Message, "Invalid field format for column %s", Name);
+ throw 31;
+ } // endswitch BufType
+
+ n = strlen(Buf);
+ } else // Standard CONNECT format
+ n = Value->ShowValue(Buf, field);
+
+ if (trace(1))
+ htrc("new length(%p)=%d\n", Buf, n);
+
+ if ((len = n) > field) {
+ char *p = Value->GetCharString(Buf);
+
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, field);
+ throw 31;
+ } else if (Dsp)
+ for (i = 0; i < len; i++)
+ if (Buf[i] == '.')
+ Buf[i] = Dsp;
+
+ if (trace(2))
+ htrc("buffer=%s\n", Buf);
+
+ /*******************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*******************************************************************/
+ if (Status) {
+ memset(p, ' ', field);
+ memcpy(p, Buf, len);
+
+ if (trace(2))
+ htrc(" col write: '%.*s'\n", len, p);
+
+ } // endif Status
+
+ } else // BIN compressed table
+ /*******************************************************************/
+ /* Check if updating is Ok, meaning col value is not too long. */
+ /* Updating to be done only during the second pass (Status=true) */
+ /*******************************************************************/
+ if (Value->GetBinValue(p, Long, Status)) {
+ sprintf(g->Message, MSG(BIN_F_TOO_LONG),
+ Name, Value->GetSize(), Long);
+ throw 31;
+ } // endif
+
+ } // end of WriteColumn
+
+/***********************************************************************/
+/* SetMinMax: Calculate minimum and maximum values for one block. */
+/* Note: TYPE_STRING is stored and processed with zero ended strings */
+/* to be matching the way the FILTER Eval function processes them. */
+/***********************************************************************/
+bool DOSCOL::SetMinMax(PGLOBAL g)
+ {
+ PTDBDOS tp = (PTDBDOS)To_Tdb;
+
+ ReadColumn(g); // Extract column value from current line
+
+ if (CheckSorted(g))
+ return true;
+
+ if (!tp->Txfp->CurNum) {
+ Min->SetValue(Value, tp->Txfp->CurBlk);
+ Max->SetValue(Value, tp->Txfp->CurBlk);
+ } else {
+ Min->SetMin(Value, tp->Txfp->CurBlk);
+ Max->SetMax(Value, tp->Txfp->CurBlk);
+ } // endif CurNum
+
+ return false;
+ } // end of SetMinMax
+
+/***********************************************************************/
+/* SetBitMap: Calculate the bit map of existing values in one block. */
+/* Note: TYPE_STRING is processed with zero ended strings */
+/* to be matching the way the FILTER Eval function processes them. */
+/***********************************************************************/
+bool DOSCOL::SetBitMap(PGLOBAL g)
+ {
+ int i, m, n;
+ uint *bmp;
+ PTDBDOS tp = (PTDBDOS)To_Tdb;
+ PDBUSER dup = PlgGetUser(g);
+
+ n = tp->Txfp->CurNum;
+ bmp = (uint*)Bmap->GetValPtr(Nbm * tp->Txfp->CurBlk);
+
+ // Extract column value from current line
+ ReadColumn(g);
+
+ if (CheckSorted(g))
+ return true;
+
+ if (!n) // New block
+ for (m = 0; m < Nbm; m++)
+ bmp[m] = 0; // Reset the new bit map
+
+ if ((i = Dval->Find(Value)) < 0) {
+ char buf[32];
+
+ sprintf(g->Message, MSG(DVAL_NOTIN_LIST),
+ Value->GetCharString(buf), Name);
+ return true;
+ } else if (i >= dup->Maxbmp) {
+ sprintf(g->Message, MSG(OPT_LOGIC_ERR), i);
+ return true;
+ } else {
+ m = i / MAXBMP;
+#if defined(_DEBUG)
+ assert (m < Nbm);
+#endif // _DEBUG
+ bmp[m] |= (1 << (i % MAXBMP));
+ } // endif's i
+
+ return false;
+ } // end of SetBitMap
+
+/***********************************************************************/
+/* Checks whether a column declared as sorted is sorted indeed. */
+/***********************************************************************/
+bool DOSCOL::CheckSorted(PGLOBAL g)
+ {
+ if (Sorted)
+ {
+ if (OldVal) {
+ // Verify whether this column is sorted all right
+ if (OldVal->CompareValue(Value) > 0) {
+ // Column is no more in ascending order
+ sprintf(g->Message, MSG(COL_NOT_SORTED), Name, To_Tdb->GetName());
+ Sorted = false;
+ return true;
+ } else
+ OldVal->SetValue_pval(Value);
+
+ } else
+ OldVal = AllocateValue(g, Value);
+ }
+ return false;
+ } // end of CheckSorted
+
+/***********************************************************************/
+/* AddDistinctValue: Check whether this value already exist in the */
+/* list and if not add it to the distinct values list. */
+/***********************************************************************/
+bool DOSCOL::AddDistinctValue(PGLOBAL g)
+ {
+ bool found = false;
+ int i, m, n;
+
+ ReadColumn(g); // Extract column value from current line
+
+ // Perhaps a better algorithm can be used when Ndv gets bigger
+ // Here we cannot use Find because we must get the index of where
+ // to insert a new value if it is not found in the array.
+ for (n = 0; n < Ndv; n++) {
+ m = Dval->CompVal(Value, n);
+
+ if (m > 0)
+ continue;
+ else if (!m)
+ found = true; // Already there
+
+ break;
+ } // endfor n
+
+ if (!found) {
+ // Check whether we have room for an additional value
+ if (Ndv == Freq) {
+ // Too many values because of wrong Freq setting
+ sprintf(g->Message, MSG(BAD_FREQ_SET), Name);
+ return true;
+ } // endif Ndv
+
+ // New value, add it to the list before the nth value
+ Dval->SetNval(Ndv + 1);
+
+ for (i = Ndv; i > n; i--)
+ Dval->Move(i - 1, i);
+
+ Dval->SetValue(Value, n);
+ Ndv++;
+ } // endif found
+
+ return false;
+ } // end of AddDistinctValue
+
+/* ------------------------------------------------------------------- */
diff --git a/storage/connect/tabdos.h b/storage/connect/tabdos.h
new file mode 100644
index 00000000..80dfe638
--- /dev/null
+++ b/storage/connect/tabdos.h
@@ -0,0 +1,269 @@
+/*************** TabDos H Declares Source Code File (.H) ***************/
+/* Name: TABDOS.H Version 3.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1999-2015 */
+/* */
+/* This file contains the DOS classes declares. */
+/***********************************************************************/
+
+#ifndef __TABDOS_H
+#define __TABDOS_H
+
+#include "xtable.h" // Table base class declares
+#include "colblk.h" // Column base class declares
+#include "xindex.h"
+#include "filter.h"
+
+//pedef struct _tabdesc *PTABD; // For friend setting
+typedef class TXTFAM *PTXF;
+typedef class BLOCKFILTER *PBF;
+typedef class BLOCKINDEX *PBX;
+
+/***********************************************************************/
+/* DOS table. */
+/***********************************************************************/
+class DllExport DOSDEF : public TABDEF { /* Logical table description */
+ friend class OEMDEF;
+ friend class TDBDOS;
+ friend class TDBFIX;
+ friend class TXTFAM;
+ friend class DBFBASE;
+ friend class UNZIPUTL;
+ friend class JSONCOL;
+ friend class TDBDCL;
+ public:
+ // Constructor
+ DOSDEF(void);
+
+ // Implementation
+ virtual AMT GetDefType(void) {return TYPE_AM_DOS;}
+ virtual const char *GetType(void) {return "DOS";}
+ virtual PIXDEF GetIndx(void) {return To_Indx;}
+ virtual void SetIndx(PIXDEF xdp) {To_Indx = xdp;}
+ virtual bool IsHuge(void) {return Huge;}
+ PCSZ GetFn(void) {return Fn;}
+ PCSZ GetOfn(void) {return Ofn;}
+ PCSZ GetEntry(void) {return Entry;}
+ bool GetMul(void) {return Mulentries;}
+ bool GetAppend(void) {return Append;}
+ void SetBlock(int block) { Block = block; }
+ int GetBlock(void) {return Block;}
+ int GetLast(void) {return Last;}
+ void SetLast(int last) {Last = last;}
+ int GetLrecl(void) {return Lrecl;}
+ void SetLrecl(int lrecl) {Lrecl = lrecl;}
+ bool GetPadded(void) {return Padded;}
+ bool GetEof(void) {return Eof;}
+ int GetBlksize(void) {return Blksize;}
+ int GetEnding(void) {return Ending;}
+ bool IsOptimized(void) {return (Optimized == 1);}
+ void SetOptimized(int opt) {Optimized = opt;}
+ void SetAllocBlks(int blks) {AllocBlks = blks;}
+ int GetAllocBlks(void) {return AllocBlks;}
+ int *GetTo_Pos(void) {return To_Pos;}
+
+ // Methods
+ virtual int Indexable(void)
+ {return (!Multiple && !Mulentries && Compressed != 1) ? 1 : 0;}
+ virtual bool DeleteIndexFile(PGLOBAL g, PIXDEF pxdf);
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE mode);
+ bool InvalidateIndex(PGLOBAL g);
+ bool GetOptFileName(PGLOBAL g, char *filename);
+ void RemoveOptValues(PGLOBAL g);
+
+ protected:
+//virtual bool Erase(char *filename);
+
+ // Members
+ PCSZ Fn; /* Path/Name of corresponding file */
+ PCSZ Ofn; /* Base Path/Name of matching index files*/
+ PCSZ Entry; /* Zip entry name or pattern */
+ PCSZ Pwd; /* Zip password */
+ PIXDEF To_Indx; /* To index definitions blocks */
+ bool Mapped; /* 0: disk file, 1: memory mapped file */
+ bool Zipped; /* true for zipped table file */
+ bool Mulentries; /* true for multiple entries */
+ bool Append; /* Used when creating zipped table */
+ bool Padded; /* true for padded table file */
+ bool Huge; /* true for files larger than 2GB */
+ bool Accept; /* true if wrong lines are accepted */
+ bool Eof; /* true if an EOF (0xA) character exists */
+ int *To_Pos; /* To array of block starting positions */
+ int Optimized; /* 0: No, 1:Yes, 2:Redo optimization */
+ int AllocBlks; /* Number of suballocated opt blocks */
+ int Compressed; /* 0: No, 1: gz, 2:zlib compressed file */
+ int Lrecl; /* Size of biggest record */
+ int AvgLen; /* Average size of records */
+ int Block; /* Number de blocks of FIX/VCT tables */
+ int Last; /* Number of elements of last block */
+ int Blksize; /* Size of padded blocks */
+ int Maxerr; /* Maximum number of bad records (DBF) */
+ int ReadMode; /* Specific to DBF */
+ int Ending; /* Length of end of lines */
+ char Teds; /* Binary table default endian setting */
+ }; // end of DOSDEF
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* that are standard files with columns starting at fixed offset. */
+/* The last column (and record) is of variable length. */
+/***********************************************************************/
+class DllExport TDBDOS : public TDBASE {
+ friend class XINDEX;
+ friend class DOSCOL;
+ friend class MAPCOL;
+ friend class TXTFAM;
+ friend class DOSFAM;
+ friend class VCTCOL;
+ friend RCODE CntDeleteRow(PGLOBAL, PTDB, bool);
+ public:
+ // Constructors
+ TDBDOS(PDOSDEF tdp, PTXF txfp);
+ TDBDOS(PGLOBAL g, PTDBDOS tdbp);
+
+ // Inline functions
+ inline void SetTxfp(PTXF txfp) {Txfp = txfp; Txfp->SetTdbp(this);}
+ inline PTXF GetTxfp(void) {return Txfp;}
+ inline char *GetLine(void) {return To_Line;}
+ inline int GetCurBlk(void) {return Txfp->GetCurBlk();}
+ inline void SetLine(char *toline) {To_Line = toline;}
+ inline void IncLine(int inc) {To_Line += inc;}
+ inline bool IsRead(void) {return Txfp->IsRead;}
+ inline PXOB *GetLink(void) {return To_Link;}
+
+ // Implementation
+ virtual AMT GetAmType(void) {return Txfp->GetAmType();}
+ virtual PCSZ GetFile(PGLOBAL) {return Txfp->To_File;}
+ virtual void SetFile(PGLOBAL, PCSZ fn) {Txfp->To_File = fn;}
+ virtual void SetAbort(bool b) {Abort = b;}
+ virtual RECFM GetFtype(void) {return Ftype;}
+ virtual bool SkipHeader(PGLOBAL) {return false;}
+ virtual void RestoreNrec(void) {Txfp->SetNrec(1);}
+ virtual PTDB Duplicate(PGLOBAL g)
+ {return (PTDB)new(g) TDBDOS(g, this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual void ResetDB(void) {Txfp->Reset();}
+ virtual bool IsUsingTemp(PGLOBAL g);
+ virtual bool IsIndexed(void) {return Indxd;}
+ virtual void ResetSize(void) {MaxSize = Cardinal = -1;}
+ virtual int ResetTableOpt(PGLOBAL g, bool dop, bool dox);
+ virtual int MakeBlockValues(PGLOBAL g);
+ virtual bool SaveBlockValues(PGLOBAL g);
+ virtual bool GetBlockValues(PGLOBAL g);
+ virtual PBF InitBlockFilter(PGLOBAL g, PFIL filp);
+//virtual PBX InitBlockIndex(PGLOBAL g);
+ virtual int TestBlock(PGLOBAL g);
+ virtual void PrintAM(FILE *f, char *m);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual char *GetOpenMode(PGLOBAL, char*) {return NULL;}
+ virtual int GetFileLength(PGLOBAL g) {return Txfp->GetFileLength(g);}
+ virtual int GetProgMax(PGLOBAL g);
+ virtual int GetProgCur(void);
+//virtual int GetAffectedRows(void) {return Txfp->GetDelRows();}
+ virtual int GetRecpos(void) {return Txfp->GetPos();}
+ virtual bool SetRecpos(PGLOBAL g, int recpos)
+ {return Txfp->SetPos(g, recpos);}
+ virtual int RowNumber(PGLOBAL g, bool b = false);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g) {return Txfp->ReadBuffer(g);}
+
+ // Specific routine
+ virtual int EstimatedLength(void);
+
+ // Optimization routines
+ virtual int MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add);
+ bool InitialyzeIndex(PGLOBAL g, PIXDEF xdp, bool sorted);
+ void ResetBlockFilter(PGLOBAL g);
+ bool GetDistinctColumnValues(PGLOBAL g, int nrec);
+
+ protected:
+ virtual bool PrepareWriting(PGLOBAL g);
+ PBF CheckBlockFilari(PGLOBAL g, PXOB *arg, int op, bool *cnv);
+
+ // Members
+ PTXF Txfp; // To the File access method class
+//PBX To_BlkIdx; // To index test block
+ PBF To_BlkFil; // To evaluation block filter
+ PFIL SavFil; // Saved hidden filter
+ char *To_Line; // Points to current processed line
+ bool Abort; // TRUE when aborting UPDATE/DELETE
+ bool Indxd; // TRUE for indexed UPDATE/DELETE
+ int Lrecl; // Logical Record Length
+ int AvgLen; // Logical Record Average Length
+//int Xeval; // BlockTest return value
+ int Beval; // BlockEval return value
+ }; // end of class TDBDOS
+
+/***********************************************************************/
+/* Class DOSCOL: DOS access method column descriptor. */
+/* This A.M. is used for text file tables under operating systems */
+/* DOS, OS2, UNIX, WIN16 and WIN32. */
+/***********************************************************************/
+class DllExport DOSCOL : public COLBLK {
+ friend class TDBDOS;
+ friend class TDBFIX;
+ public:
+ // Constructors
+ DOSCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PCSZ am = "DOS");
+ DOSCOL(DOSCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_DOS;}
+ virtual void SetTo_Val(PVAL valp) {To_Val = valp;}
+ virtual int GetClustered(void) {return Clustered;}
+ virtual int IsClustered(void) {return (Clustered &&
+ ((PDOSDEF)(((PTDBDOS)To_Tdb)->To_Def))->IsOptimized());}
+ virtual int IsSorted(void) {return Sorted;}
+ virtual PVBLK GetMin(void) {return Min;}
+ virtual PVBLK GetMax(void) {return Max;}
+ virtual int GetNdv(void) {return Ndv;}
+ virtual int GetNbm(void) {return Nbm;}
+ virtual PVBLK GetBmap(void) {return Bmap;}
+ virtual PVBLK GetDval(void) {return Dval;}
+
+ // Methods
+ virtual bool VarSize(void);
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+ protected:
+ virtual bool SetMinMax(PGLOBAL g);
+ virtual bool SetBitMap(PGLOBAL g);
+ bool CheckSorted(PGLOBAL g);
+ bool AddDistinctValue(PGLOBAL g);
+
+ // Default constructor not to be used
+ DOSCOL(void) {}
+
+ // Members
+ PVBLK Min; // Array of block min values
+ PVBLK Max; // Array of block max values
+ PVBLK Bmap; // Array of block bitmap values
+ PVBLK Dval; // Array of column distinct values
+ PVAL To_Val; // To value used for Update/Insert
+ PVAL OldVal; // The previous value of the object.
+ char *Buf; // Buffer used in read/write operations
+ char Dsp; // The decimal separator
+ bool Ldz; // True if field contains leading zeros
+ bool Nod; // True if no decimal point
+ int Dcm; // Last Dcm digits are decimals
+ int Deplac; // Offset in dos_buf
+ int Clustered; // 0:No 1:Yes
+ int Sorted; // 0:No 1:Asc (2:Desc - NIY)
+ int Ndv; // Number of distinct values
+ int Nbm; // Number of uint in bitmap
+ }; // end of class DOSCOL
+
+#endif // __TABDOS_H
diff --git a/storage/connect/tabext.cpp b/storage/connect/tabext.cpp
new file mode 100644
index 00000000..212d27f0
--- /dev/null
+++ b/storage/connect/tabext.cpp
@@ -0,0 +1,720 @@
+/************* Tabext C++ Functions Source Code File (.CPP) ************/
+/* Name: TABEXT.CPP Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2019 */
+/* */
+/* This file contains the TBX, TDB and OPJOIN classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#define MYSQL_SERVER 1
+#include "my_global.h"
+#include "sql_class.h"
+#include "sql_servers.h"
+#include "sql_string.h"
+#if !defined(_WIN32)
+#include "osutil.h"
+#endif
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* xobject.h is header containing XOBJECT derived classes declares. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "ha_connect.h"
+
+/* -------------------------- Class CONDFIL -------------------------- */
+
+/***********************************************************************/
+/* CONDFIL Constructor. */
+/***********************************************************************/
+CONDFIL::CONDFIL(uint idx, AMT type)
+{
+//Cond = cond;
+ Idx = idx;
+ Type = type;
+ Op = OP_XX;
+ Cmds = NULL;
+ Alist = NULL;
+ All = true;
+ Bd = false;
+ Hv = false;
+ Body = NULL,
+ Having = NULL;
+} // end of CONDFIL constructor
+
+/***********************************************************************/
+/* Make and allocate the alias list. */
+/***********************************************************************/
+int CONDFIL::Init(PGLOBAL g, PHC hc)
+{
+ PTOS options = hc->GetTableOptionStruct();
+ char *p, *cn, *cal, *alt = NULL;
+ int rc = RC_OK;
+ bool h;
+
+ if (options)
+ alt = (char*)GetListOption(g, "Alias", options->oplist, NULL);
+
+ while (alt) {
+ if (!(p = strchr(alt, '='))) {
+ strcpy(g->Message, "Invalid alias list");
+ rc = RC_FX;
+ break;
+ } // endif !p
+
+ cal = alt; // Alias
+ *p++ = 0;
+
+ if ((h = *p == '*')) {
+ rc = RC_INFO;
+ p++;
+ } // endif h
+
+ cn = p; // Remote column name
+
+ if ((alt = strchr(p, ';')))
+ *alt++ = 0;
+
+ if (*cn == 0)
+ cn = alt;
+
+ Alist = new(g) ALIAS(Alist, cn, cal, h);
+ } // endwhile alt
+
+ return rc;
+} // end of Init
+
+/***********************************************************************/
+/* Make and allocate the alias list. */
+/***********************************************************************/
+const char *CONDFIL::Chk(const char *fln, bool *h)
+{
+ for (PAL pal = Alist; pal; pal = pal->Next)
+ if (!stricmp(fln, pal->Alias)) {
+ *h = pal->Having;
+ return pal->Name;
+ } // endif fln
+
+ *h = false;
+ return fln;
+} // end of Chk
+
+/* --------------------------- Class EXTDEF -------------------------- */
+
+/***********************************************************************/
+/* EXTDEF Constructor. */
+/***********************************************************************/
+EXTDEF::EXTDEF(void)
+{
+ Tabname = Tabschema = Username = Password = Tabcat = Tabtyp = NULL;
+ Colpat = Srcdef = Qchar = Qrystr = Sep = Phpos = NULL;
+ Options = Cto = Qto = Quoted = Maxerr = Maxres = Memory = 0;
+ Scrollable = Xsrc = false;
+} // end of EXTDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool EXTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ if (g->Createas) {
+ strcpy(g->Message,
+ "Multiple-table UPDATE/DELETE commands are not supported");
+ return true;
+ } // endif multi
+
+ Desc = NULL;
+ Tabname = GetStringCatInfo(g, "Name",
+ (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
+ Tabname = GetStringCatInfo(g, "Tabname", Tabname);
+ Tabschema = GetStringCatInfo(g, "Dbname", NULL);
+ Tabschema = GetStringCatInfo(g, "Schema", Tabschema);
+ Tabcat = GetStringCatInfo(g, "Qualifier", NULL);
+ Tabcat = GetStringCatInfo(g, "Catalog", Tabcat);
+ Username = GetStringCatInfo(g, "User", NULL);
+ Password = GetStringCatInfo(g, "Password", NULL);
+
+ if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL)))
+ Read_Only = true;
+
+ Qrystr = GetStringCatInfo(g, "Query_String", "?");
+ Sep = GetStringCatInfo(g, "Separator", NULL);
+//Alias = GetStringCatInfo(g, "Alias", NULL);
+ Phpos = GetStringCatInfo(g, "Phpos", NULL);
+ Xsrc = GetBoolCatInfo("Execsrc", FALSE);
+ Maxerr = GetIntCatInfo("Maxerr", 0);
+ Maxres = GetIntCatInfo("Maxres", 0);
+ Quoted = GetIntCatInfo("Quoted", 0);
+ Options = 0;
+ Cto = 0;
+ Qto = 0;
+
+ if ((Scrollable = GetBoolCatInfo("Scrollable", false)) && !Elemt)
+ Elemt = 1; // Cannot merge SQLFetch and SQLExtendedFetch
+
+ if (Catfunc == FNC_COL)
+ Colpat = GetStringCatInfo(g, "Colpat", NULL);
+
+ if (Catfunc == FNC_TABLE)
+ Tabtyp = GetStringCatInfo(g, "Tabtype", NULL);
+
+ // Memory was Boolean, it is now integer
+ if (!(Memory = GetIntCatInfo("Memory", 0)))
+ Memory = GetBoolCatInfo("Memory", false) ? 1 : 0;
+
+ Pseudo = 2; // FILID is Ok but not ROWID
+ return false;
+} // end of DefineAM
+
+/* ---------------------------TDBEXT class --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBEXT class. */
+/***********************************************************************/
+TDBEXT::TDBEXT(EXTDEF *tdp) : TDB(tdp)
+{
+ Qrp = NULL;
+
+ if (tdp) {
+ TableName = tdp->Tabname;
+ Schema = tdp->Tabschema;
+ User = tdp->Username;
+ Pwd = tdp->Password;
+ Catalog = tdp->Tabcat;
+ Srcdef = tdp->Srcdef;
+ Qrystr = tdp->Qrystr;
+ Sep = tdp->GetSep();
+ Options = tdp->Options;
+ Cto = tdp->Cto;
+ Qto = tdp->Qto;
+ Quoted = MY_MAX(0, tdp->GetQuoted());
+ Rows = tdp->GetElemt();
+ Memory = tdp->Memory;
+ Scrollable = tdp->Scrollable;
+ } else {
+ TableName = NULL;
+ Schema = NULL;
+ User = NULL;
+ Pwd = NULL;
+ Catalog = NULL;
+ Srcdef = NULL;
+ Qrystr = NULL;
+ Sep = 0;
+ Options = 0;
+ Cto = 0;
+ Qto = 0;
+ Quoted = 0;
+ Rows = 0;
+ Memory = 0;
+ Scrollable = false;
+ } // endif tdp
+
+ Quote = NULL;
+ Query = NULL;
+ Count = NULL;
+ //Where = NULL;
+ MulConn = NULL;
+ DBQ = NULL;
+ Qrp = NULL;
+ Fpos = 0;
+ Curpos = 0;
+ AftRows = 0;
+ CurNum = 0;
+ Rbuf = 0;
+ BufSize = 0;
+ Nparm = 0;
+ Ncol = 0;
+ Placed = false;
+} // end of TDBEXT constructor
+
+TDBEXT::TDBEXT(PTDBEXT tdbp) : TDB(tdbp)
+{
+ Qrp = tdbp->Qrp;
+ TableName = tdbp->TableName;
+ Schema = tdbp->Schema;
+ User = tdbp->User;
+ Pwd = tdbp->Pwd;
+ Catalog = tdbp->Catalog;
+ Srcdef = tdbp->Srcdef;
+ Qrystr = tdbp->Qrystr;
+ Sep = tdbp->Sep;
+ Options = tdbp->Options;
+ Cto = tdbp->Cto;
+ Qto = tdbp->Qto;
+ Quoted = tdbp->Quoted;
+ Rows = tdbp->Rows;
+ Memory = tdbp->Memory;
+ Scrollable = tdbp->Scrollable;
+ Quote = tdbp->Quote;
+ Query = tdbp->Query;
+ Count = tdbp->Count;
+ //Where = tdbp->Where;
+ MulConn = tdbp->MulConn;
+ DBQ = tdbp->DBQ;
+ Fpos = 0;
+ Curpos = 0;
+ AftRows = 0;
+ CurNum = 0;
+ Rbuf = 0;
+ BufSize = tdbp->BufSize;
+ Nparm = tdbp->Nparm;
+ Ncol = tdbp->Ncol;
+ Placed = false;
+} // end of TDBEXT copy constructor
+
+/******************************************************************/
+/* Convert an UTF-8 string to latin characters. */
+/******************************************************************/
+int TDBEXT::Decode(PCSZ txt, char *buf, size_t n)
+{
+ uint dummy_errors;
+ uint32 len = copy_and_convert(buf, n, &my_charset_latin1,
+ txt, strlen(txt),
+ &my_charset_utf8mb3_general_ci,
+ &dummy_errors);
+ buf[len] = '\0';
+ return 0;
+} // end of Decode
+
+/***********************************************************************/
+/* MakeSrcdef: make the SQL statement from SRDEF option. */
+/***********************************************************************/
+bool TDBEXT::MakeSrcdef(PGLOBAL g)
+{
+ char *catp = strstr(Srcdef, "%s");
+
+ if (catp) {
+ char *fil1 = 0, *fil2;
+ PCSZ ph = ((EXTDEF*)To_Def)->Phpos;
+
+ if (!ph)
+ ph = (strstr(catp + 2, "%s")) ? "WH" : "W";
+
+ if (stricmp(ph, "H")) {
+ fil1 = (To_CondFil && *To_CondFil->Body)
+ ? To_CondFil->Body : PlugDup(g, "1=1");
+ } // endif ph
+
+ if (stricmp(ph, "W")) {
+ fil2 = (To_CondFil && To_CondFil->Having && *To_CondFil->Having)
+ ? To_CondFil->Having : PlugDup(g, "1=1");
+ } // endif ph
+
+ if (!stricmp(ph, "W")) {
+ Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1));
+ Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1));
+ } else if (!stricmp(ph, "WH")) {
+ Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
+ Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1, fil2));
+ } else if (!stricmp(ph, "H")) {
+ Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil2));
+ Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2));
+ } else if (!stricmp(ph, "HW")) {
+ Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
+ Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2, fil1));
+ } else {
+ strcpy(g->Message, "MakeSQL: Wrong place holders specification");
+ return true;
+ } // endif's ph
+
+ } else
+ Query = new(g)STRING(g, 0, Srcdef);
+
+ return false;
+} // end of MakeSrcdef
+
+ /***********************************************************************/
+ /* MakeSQL: make the SQL statement use with remote connection. */
+ /* TODO: when implementing remote filtering, column only used in */
+ /* local filter should be removed from column list. */
+ /***********************************************************************/
+bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt)
+{
+ PCSZ schmp = NULL;
+ char *catp = NULL, buf[NAM_LEN * 3];
+ int len;
+ bool first = true;
+ PCOL colp;
+
+ if (Srcdef)
+ return MakeSrcdef(g);
+
+ // Allocate the string used to contain the Query
+ Query = new(g)STRING(g, 1023, "SELECT ");
+
+ if (!cnt) {
+ if (Columns) {
+ // Normal SQL statement to retrieve results
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!colp->IsSpecial()) {
+ if (!first)
+ Query->Append(", ");
+ else
+ first = false;
+
+ // Column name can be encoded in UTF-8
+ Decode(colp->GetName(), buf, sizeof(buf));
+
+ if (Quote) {
+ // Put column name between identifier quotes in case in contains blanks
+ Query->Append(Quote);
+ Query->Append(buf);
+ Query->Append(Quote);
+ } else
+ Query->Append(buf);
+
+ ((PEXTCOL)colp)->SetRank(++Ncol);
+ } // endif colp
+
+ } else
+ // !Columns can occur for queries such that sql count(*) from...
+ // for which we will count the rows from sql * from...
+ Query->Append('*');
+
+ } else
+ // SQL statement used to retrieve the size of the result
+ Query->Append("count(*)");
+
+ Query->Append(" FROM ");
+
+ if (Catalog && *Catalog)
+ catp = Catalog;
+
+ //if (tablep->GetSchema())
+ // schmp = (char*)tablep->GetSchema();
+ //else
+ if (Schema && *Schema)
+ schmp = Schema;
+
+ if (catp) {
+ Query->Append(catp);
+
+ if (schmp) {
+ Query->Append('.');
+ Query->Append(schmp);
+ } // endif schmp
+
+ Query->Append('.');
+ } else if (schmp) {
+ Query->Append(schmp);
+ Query->Append('.');
+ } // endif schmp
+
+ // Table name can be encoded in UTF-8
+ Decode(TableName, buf, sizeof(buf));
+
+ if (Quote) {
+ // Put table name between identifier quotes in case in contains blanks
+ Query->Append(Quote);
+ Query->Append(buf);
+ Query->Append(Quote);
+ } else
+ Query->Append(buf);
+
+ len = Query->GetLength();
+
+ if (To_CondFil) {
+ if (Mode == MODE_READ) {
+ Query->Append(" WHERE ");
+ Query->Append(To_CondFil->Body);
+ len = Query->GetLength() + 1;
+ } else
+ len += (strlen(To_CondFil->Body) + 256);
+
+ } else
+ len += ((Mode == MODE_READX) ? 256 : 1);
+
+ if (Query->IsTruncated()) {
+ strcpy(g->Message, "MakeSQL: Out of memory");
+ return true;
+ } else
+ Query->Resize(len);
+
+ if (trace(33))
+ htrc("Query=%s\n", Query->GetStr());
+
+ return false;
+} // end of MakeSQL
+
+/***********************************************************************/
+/* Remove the NAME_CONST functions that are added by procedures. */
+/***********************************************************************/
+void TDBEXT::RemoveConst(PGLOBAL g, char *stmt)
+{
+ char *p, *p2;
+ char val[1025], nval[1025];
+ int n, nc;
+
+ while ((p = strstr(stmt, "NAME_CONST")))
+ {
+ if ((n = sscanf(p, "%*[^,],%1024[^)])%n", val, &nc))) {
+ if (trace(33))
+ htrc("p=%s\nn=%d val=%s nc=%d\n", p, n, val, nc);
+
+ *p = 0;
+
+ if ((p2 = strstr(val, "'"))) {
+ if ((n = sscanf(p2, "%*['\\]%1024[^'\\]", nval))) {
+ if (trace(33))
+ htrc("p2=%s\nn=%d nval=%s\n", p2, n, nval);
+
+ strcat(strcat(strcat(strcat(stmt, "'"), nval), "'"), p + nc);
+ } else
+ break;
+
+ } else
+ strcat(strcat(strcat(strcat(stmt, "("), val), ")"), p + nc);
+
+ if (trace(33))
+ htrc("stmt=%s\n", stmt);
+
+ } else
+ break;
+ }
+ return;
+} // end of RemoveConst
+
+/***********************************************************************/
+/* MakeCommand: make the Update or Delete statement to send to the */
+/* MySQL server. Limited to remote values and filtering. */
+/***********************************************************************/
+bool TDBEXT::MakeCommand(PGLOBAL g)
+{
+ PCSZ schmp = NULL;
+ char *p, *stmt, name[132], *body = NULL;
+ char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
+ bool qtd = Quoted > 0;
+ char q = qtd ? *Quote : ' ';
+ int i = 0, k = 0;
+
+ // Make a lower case copy of the originale query and change
+ // back ticks to the data source identifier quoting character
+ do {
+ qrystr[i] = (Qrystr[i] == '`') ? q : tolower(Qrystr[i]);
+ } while (Qrystr[i++]);
+
+ if (To_CondFil && (p = strstr(qrystr, " where "))) {
+ p[7] = 0; // Remove where clause
+ Qrystr[(p - qrystr) + 7] = 0;
+ body = To_CondFil->Body;
+ stmt = (char*)PlugSubAlloc(g, NULL, strlen(qrystr)
+ + strlen(body) + 64);
+ } else
+ stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+
+ // Check whether the table name is equal to a keyword
+ // If so, it must be quoted in the original query
+ strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
+
+ if (strstr(" update delete low_priority ignore quick from ", name)) {
+ if (Quote) {
+ strlwr(strcat(strcat(strcpy(name, Quote), Name), Quote));
+ k += 2;
+ } else {
+ strcpy(g->Message, "Quoted must be specified");
+ return true;
+ } // endif Quote
+
+ } else
+ strlwr(strcpy(name, Name)); // Not a keyword
+
+ if ((p = strstr(qrystr, name))) {
+ for (i = 0; i < p - qrystr; i++)
+ stmt[i] = (Qrystr[i] == '`') ? q : Qrystr[i];
+
+ stmt[i] = 0;
+
+ k += i + (int)strlen(Name);
+
+ if (Schema && *Schema)
+ schmp = Schema;
+
+ if (qtd && *(p - 1) == ' ') {
+ if (schmp)
+ strcat(strcat(stmt, schmp), ".");
+
+ strcat(strcat(strcat(stmt, Quote), TableName), Quote);
+ } else {
+ if (schmp) {
+ if (qtd && *(p - 1) != ' ') {
+ stmt[i - 1] = 0;
+ strcat(strcat(strcat(stmt, schmp), "."), Quote);
+ } else
+ strcat(strcat(stmt, schmp), ".");
+
+ } // endif schmp
+
+ strcat(stmt, TableName);
+ } // endif's
+
+ i = (int)strlen(stmt);
+
+ do {
+ stmt[i++] = (Qrystr[k] == '`') ? q : Qrystr[k];
+ } while (Qrystr[k++]);
+
+ RemoveConst(g, stmt);
+
+ if (body)
+ strcat(stmt, body);
+
+ } else {
+ sprintf(g->Message, "Cannot use this %s command",
+ (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
+ return true;
+ } // endif p
+
+ if (trace(33))
+ htrc("Command=%s\n", stmt);
+
+ Query = new(g)STRING(g, 0, stmt);
+ return (!Query->GetSize());
+} // end of MakeCommand
+
+/***********************************************************************/
+/* GetRecpos: return the position of last read record. */
+/***********************************************************************/
+int TDBEXT::GetRecpos(void)
+{
+ return Fpos;
+} // end of GetRecpos
+
+/***********************************************************************/
+/* ODBC GetMaxSize: returns table size estimate in number of lines. */
+/***********************************************************************/
+int TDBEXT::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0) {
+ if (Mode == MODE_DELETE)
+ // Return 0 in mode DELETE in case of delete all.
+ MaxSize = 0;
+ else if (!Cardinality(NULL))
+ MaxSize = 10; // To make MySQL happy
+ else if ((MaxSize = Cardinality(g)) < 0)
+ MaxSize = 12; // So we can see an error occurred
+
+ } // endif MaxSize
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* Return max size value. */
+/***********************************************************************/
+int TDBEXT::GetProgMax(PGLOBAL g)
+{
+ return GetMaxSize(g);
+} // end of GetProgMax
+
+/* ---------------------------EXTCOL class --------------------------- */
+
+/***********************************************************************/
+/* EXTCOL public constructor. */
+/***********************************************************************/
+EXTCOL::EXTCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : COLBLK(cdp, tdbp, i)
+{
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ if (trace(1))
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ // Set additional remote access method information for column.
+ Crp = NULL;
+ Long = Precision;
+ To_Val = NULL;
+ Bufp = NULL;
+ Blkp = NULL;
+ Rank = 0; // Not known yet
+} // end of JDBCCOL constructor
+
+/***********************************************************************/
+/* EXTCOL private constructor. */
+/***********************************************************************/
+EXTCOL::EXTCOL(void) : COLBLK()
+{
+ Crp = NULL;
+ Buf_Type = TYPE_INT; // This is a count(*) column
+
+ // Set additional Dos access method information for column.
+ Long = sizeof(int);
+ To_Val = NULL;
+ Bufp = NULL;
+ Blkp = NULL;
+ Rank = 1;
+} // end of EXTCOL constructor
+
+/***********************************************************************/
+/* EXTCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+EXTCOL::EXTCOL(PEXTCOL col1, PTDB tdbp) : COLBLK(col1, tdbp)
+{
+ Crp = col1->Crp;
+ Long = col1->Long;
+ To_Val = col1->To_Val;
+ Bufp = col1->Bufp;
+ Blkp = col1->Blkp;
+ Rank = col1->Rank;
+} // end of JDBCCOL copy constructor
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool EXTCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+{
+ if (!(To_Val = value)) {
+ sprintf(g->Message, MSG(VALUE_ERROR), Name);
+ return true;
+ } else if (Buf_Type == value->GetType()) {
+ // Values are of the (good) column type
+ if (Buf_Type == TYPE_DATE) {
+ // If any of the date values is formatted
+ // output format must be set for the receiving table
+ if (GetDomain() || ((DTVAL *)value)->IsFormatted())
+ goto newval; // This will make a new value;
+
+ } else if (Buf_Type == TYPE_DOUBLE)
+ // Float values must be written with the correct (column) precision
+ // Note: maybe this should be forced by ShowValue instead of this ?
+ value->SetPrec(GetScale());
+
+ Value = value; // Directly access the external value
+ } else {
+ // Values are not of the (good) column type
+ if (check) {
+ sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
+ GetTypeName(Buf_Type), GetTypeName(value->GetType()));
+ return true;
+ } // endif check
+
+ newval:
+ if (InitValue(g)) // Allocate the matching value block
+ return true;
+
+ } // endif's Value, Buf_Type
+
+ // Because Colblk's have been made from a copy of the original TDB in
+ // case of Update, we must reset them to point to the original one.
+ if (To_Tdb->GetOrig())
+ To_Tdb = (PTDB)To_Tdb->GetOrig();
+
+ // Set the Column
+ Status = (ok) ? BUF_EMPTY : BUF_NO;
+ return false;
+} // end of SetBuffer
+
diff --git a/storage/connect/tabext.h b/storage/connect/tabext.h
new file mode 100644
index 00000000..5fef1b9e
--- /dev/null
+++ b/storage/connect/tabext.h
@@ -0,0 +1,204 @@
+/*************** Tabext H Declares Source Code File (.H) ***************/
+/* Name: TABEXT.H Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2019 */
+/* */
+/* This is the EXTDEF, TABEXT and EXTCOL classes definitions. */
+/***********************************************************************/
+
+#ifndef __TABEXT_H
+#define __TABEXT_H
+
+#include "reldef.h"
+
+typedef class ALIAS *PAL;
+
+class ALIAS : public BLOCK {
+ public:
+ ALIAS(PAL x, PSZ n, PSZ a, bool h)
+ {Next = x, Name = n, Alias = a, Having = h;}
+
+ PAL Next;
+ PSZ Name;
+ PSZ Alias;
+ bool Having;
+}; // end of class ALIAS
+
+// Condition filter structure
+class CONDFIL : public BLOCK {
+ public:
+ // Constructor
+ CONDFIL(uint idx, AMT type);
+
+ // Functions
+ int Init(PGLOBAL g, PHC hc);
+ const char *Chk(const char *cln, bool *h);
+
+ // Members
+//const Item *Cond;
+ AMT Type;
+ uint Idx;
+ OPVAL Op;
+ PCMD Cmds;
+ PAL Alist;
+ bool All;
+ bool Bd;
+ bool Hv;
+ char *Body;
+ char *Having;
+}; // end of class CONDFIL
+
+/***********************************************************************/
+/* This class corresponds to the data base description for external */
+/* tables of type MYSQL, ODBC, JDBC... */
+/***********************************************************************/
+class DllExport EXTDEF : public TABDEF { /* EXT table */
+ friend class TDBEXT;
+public:
+ // Constructor
+ EXTDEF(void); // Constructor
+
+ // Implementation
+ virtual const char *GetType(void) { return "EXT"; }
+ inline PCSZ GetTabname(void) { return Tabname; }
+ inline PCSZ GetTabschema(void) { return Tabschema; }
+ inline PCSZ GetUsername(void) { return Username; };
+ inline PCSZ GetPassword(void) { return Password; };
+ inline PSZ GetTabcat(void) { return Tabcat; }
+ inline PSZ GetSrcdef(void) { return Srcdef; }
+ inline char GetSep(void) { return (Sep) ? *Sep : 0; }
+ inline int GetQuoted(void) { return Quoted; }
+ inline int GetOptions(void) { return Options; }
+
+ // Methods
+ virtual int Indexable(void) { return 2; }
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+
+protected:
+ // Members
+ PCSZ Tabname; /* External table name */
+ PCSZ Tabschema; /* External table schema */
+ PCSZ Username; /* User connect name */
+ PCSZ Password; /* Password connect info */
+ PSZ Tabcat; /* External table catalog */
+ PSZ Tabtyp; /* Catalog table type */
+ PSZ Colpat; /* Catalog column pattern */
+ PSZ Srcdef; /* The source table SQL definition */
+ PSZ Qchar; /* Identifier quoting character */
+ PSZ Qrystr; /* The original query */
+ PSZ Sep; /* Decimal separator */
+//PSZ Alias; /* Column alias list */
+ PSZ Phpos; /* Place holer positions */
+ int Options; /* Open connection options */
+ int Cto; /* Open connection timeout */
+ int Qto; /* Query (command) timeout */
+ int Quoted; /* Identifier quoting level */
+ int Maxerr; /* Maxerr for an Exec table */
+ int Maxres; /* Maxres for a catalog table */
+ int Memory; /* Put result set in memory */
+ bool Scrollable; /* Use scrollable cursor */
+ bool Xsrc; /* Execution type */
+}; // end of EXTDEF
+
+/***********************************************************************/
+/* This is the base class for all external tables. */
+/***********************************************************************/
+class DllExport TDBEXT : public TDB {
+ friend class JAVAConn;
+ friend class JMgoConn;
+public:
+ // Constructors
+ TDBEXT(EXTDEF *tdp);
+ TDBEXT(PTDBEXT tdbp);
+
+ // Implementation
+
+ // Properties
+ virtual bool IsRemote(void) { return true; }
+
+ // Methods
+ virtual PCSZ GetServer(void) { return "Remote"; }
+ virtual int GetRecpos(void);
+
+ // Database routines
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual int GetProgMax(PGLOBAL g);
+
+protected:
+ // Internal functions
+ virtual bool MakeSrcdef(PGLOBAL g);
+ virtual bool MakeSQL(PGLOBAL g, bool cnt);
+ //virtual bool MakeInsert(PGLOBAL g);
+ virtual bool MakeCommand(PGLOBAL g);
+ void RemoveConst(PGLOBAL g, char *stmt);
+ int Decode(PCSZ utf, char *buf, size_t n);
+
+ // Members
+ PQRYRES Qrp; // Points to storage result
+ PSTRG Query; // Constructed SQL query
+ PCSZ TableName; // Points to ODBC table name
+ PCSZ Schema; // Points to ODBC table Schema
+ PCSZ User; // User connect info
+ PCSZ Pwd; // Password connect info
+ char *Catalog; // Points to ODBC table Catalog
+ char *Srcdef; // The source table SQL definition
+ char *Count; // Points to count(*) SQL statement
+ //char *Where; // Points to local where clause
+ char *Quote; // The identifier quoting character
+ char *MulConn; // Used for multiple ODBC tables
+ char *DBQ; // The address part of Connect string
+ char *Qrystr; // The original query
+ char Sep; // The decimal separator
+ int Options; // Connect options
+ int Cto; // Connect timeout
+ int Qto; // Query timeout
+ int Quoted; // The identifier quoting level
+ int Fpos; // Position of last read record
+ int Curpos; // Cursor position of last fetch
+ int AftRows; // The number of affected rows
+ int Rows; // Rowset size
+ int CurNum; // Current buffer line number
+ int Rbuf; // Number of lines read in buffer
+ int BufSize; // Size of connect string buffer
+ int Nparm; // The number of statement parameters
+ int Memory; // 0: No 1: Alloc 2: Put 3: Get
+ int Ncol; // The column number (JDBC)
+ bool Scrollable; // Use scrollable cursor
+ bool Placed; // True for position reading
+}; // end of class TDBEXT
+
+/***********************************************************************/
+/* Virtual class EXTCOL: external column. */
+/***********************************************************************/
+class DllExport EXTCOL : public COLBLK {
+ friend class TDBEXT;
+public:
+ // Constructor
+ EXTCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am);
+ EXTCOL(PEXTCOL colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ inline int GetRank(void) { return Rank; }
+ inline void SetRank(int k) { Rank = k; }
+ //inline PVBLK GetBlkp(void) {return Blkp;}
+ inline void SetCrp(PCOLRES crp) { Crp = crp; }
+
+ // Methods
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void ReadColumn(PGLOBAL) = 0;
+ virtual void WriteColumn(PGLOBAL) = 0;
+
+protected:
+ // Constructor for count(*) column
+ EXTCOL(void);
+
+ // Members
+ PCOLRES Crp; // To storage result
+ void *Bufp; // To extended buffer
+ PVBLK Blkp; // To Value Block
+ PVAL To_Val; // To value used for Insert
+ int Rank; // Rank (position) number in the query
+ //int Flag; // ???
+}; // end of class EXTCOL
+
+#endif // __TABEXT_H
diff --git a/storage/connect/tabfix.cpp b/storage/connect/tabfix.cpp
new file mode 100644
index 00000000..60c37075
--- /dev/null
+++ b/storage/connect/tabfix.cpp
@@ -0,0 +1,681 @@
+/************* TabFix C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABFIX */
+/* ------------- */
+/* Version 4.9.2 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2017 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TDBFIX class DB routines. */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant section of system dependant header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#include <errno.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h" // global declares
+#include "plgdbsem.h" // DB application declares
+#include "filamfix.h"
+#include "filamdbf.h"
+#include "tabfix.h" // TDBFIX, FIXCOL classes declares
+#include "array.h"
+#include "blkfil.h"
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+extern int num_read, num_there, num_eq[2]; // Statistics
+char BINCOL::Endian = 'H';
+
+/***********************************************************************/
+/* External function. */
+/***********************************************************************/
+USETEMP UseTemp(void);
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBFIX class. */
+/***********************************************************************/
+TDBFIX::TDBFIX(PDOSDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
+ {
+ Teds = tdp->Teds; // For BIN tables
+ } // end of TDBFIX standard constructor
+
+TDBFIX::TDBFIX(PGLOBAL g, PTDBFIX tdbp) : TDBDOS(g, tdbp)
+ {
+ Teds = tdbp->Teds;
+ } // end of TDBFIX copy constructor
+
+// Method
+PTDB TDBFIX::Clone(PTABS t)
+ {
+ PTDB tp;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBFIX(g, this);
+
+ if (Ftype == RECFM_VAR || Ftype == RECFM_FIX) {
+ // File is text
+ PDOSCOL cp1, cp2;
+
+ for (cp1 = (PDOSCOL)Columns; cp1; cp1 = (PDOSCOL)cp1->GetNext()) {
+ cp2 = new(g) DOSCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ } else {
+ // File is binary
+ PBINCOL cp1, cp2;
+
+ for (cp1 = (PBINCOL)Columns; cp1; cp1 = (PBINCOL)cp1->GetNext()) {
+ cp2 = new(g) BINCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ } // endif Ftype
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void TDBFIX::ResetDB(void)
+ {
+ TDBDOS::ResetDB();
+ } // end of ResetDB
+
+/***********************************************************************/
+/* Allocate FIX (DOS) or BIN column description block. */
+/***********************************************************************/
+PCOL TDBFIX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ if (Ftype == RECFM_BIN)
+ return new(g) BINCOL(g, cdp, this, cprec, n);
+ else
+ return new(g) DOSCOL(g, cdp, this, cprec, n);
+
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Remake the indexes after the table was modified. */
+/***********************************************************************/
+int TDBFIX::ResetTableOpt(PGLOBAL g, bool dop, bool dox)
+ {
+ int prc, rc = RC_OK;
+
+ To_Filter = NULL; // Disable filtering
+//To_BlkIdx = NULL; // and block filtering
+ To_BlkFil = NULL; // and index filtering
+ Cardinality(g); // If called by create
+ RestoreNrec(); // May have been modified
+ MaxSize = -1; // Size must be recalculated
+ Cardinal = -1; // as well as Cardinality
+
+ // After the table was modified the indexes
+ // are invalid and we should mark them as such...
+ rc = ((PDOSDEF)To_Def)->InvalidateIndex(g);
+
+ if (dop) {
+ Columns = NULL; // Not used anymore
+ Txfp->Reset();
+// OldBlk = CurBlk = -1;
+// ReadBlks = CurNum = Rbuf = Modif = 0;
+ Use = USE_READY; // So the table can be reopened
+ Mode = MODE_ANY; // Just to be clean
+ rc = MakeBlockValues(g); // Redo optimization
+ } // endif dop
+
+ if (dox && (rc == RC_OK || rc == RC_INFO)) {
+ // Remake eventual indexes
+ Columns = NULL; // Not used anymore
+ Txfp->Reset(); // New start
+ Use = USE_READY; // So the table can be reopened
+ Mode = MODE_READ; // New mode
+ prc = rc;
+
+ if (PlgGetUser(g)->Check & CHK_OPT)
+ // We must remake indexes.
+ rc = MakeIndex(g, NULL, FALSE);
+
+ rc = (rc == RC_INFO) ? prc : rc;
+ } // endif dox
+
+ return rc;
+ } // end of ResetTableOpt
+
+/***********************************************************************/
+/* Reset the Nrec and BlkSize values that can have been modified. */
+/***********************************************************************/
+void TDBFIX::RestoreNrec(void)
+ {
+ if (!Txfp->Padded) {
+ Txfp->Nrec = (To_Def && To_Def->GetElemt()) ? To_Def->GetElemt()
+ : DOS_BUFF_LEN;
+ Txfp->Blksize = Txfp->Nrec * Txfp->Lrecl;
+
+ if (Cardinal >= 0)
+ Txfp->Block = (Cardinal > 0)
+ ? (Cardinal + Txfp->Nrec - 1) / Txfp->Nrec : 0;
+
+ } // endif Padded
+
+ } // end of RestoreNrec
+
+/***********************************************************************/
+/* FIX Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int TDBFIX::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return Txfp->Cardinality(g);
+
+ if (Cardinal < 0)
+ Cardinal = Txfp->Cardinality(g);
+
+ return Cardinal;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* FIX GetMaxSize: returns file size in number of lines. */
+/***********************************************************************/
+int TDBFIX::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ MaxSize = Cardinality(g);
+
+ if (MaxSize > 0 && (To_BlkFil = InitBlockFilter(g, To_Filter))
+ && !To_BlkFil->Correlated()) {
+ // Use BlockTest to reduce the estimated size
+ MaxSize = Txfp->MaxBlkSize(g, MaxSize);
+ ResetBlockFilter(g);
+ } // endif To_BlkFil
+
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* FIX ResetSize: Must reset Headlen for DBF tables only. */
+/***********************************************************************/
+void TDBFIX::ResetSize(void)
+ {
+ if (Txfp->GetAmType() == TYPE_AM_DBF)
+ Txfp->Headlen = 0;
+
+ MaxSize = Cardinal = -1;
+ } // end of ResetSize
+
+/***********************************************************************/
+/* FIX GetProgMax: get the max value for progress information. */
+/***********************************************************************/
+int TDBFIX::GetProgMax(PGLOBAL g)
+ {
+ return Cardinality(g);
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* RowNumber: return the ordinal number of the current row. */
+/***********************************************************************/
+int TDBFIX::RowNumber(PGLOBAL g, bool b)
+ {
+ if (Txfp->GetAmType() == TYPE_AM_DBF) {
+ if (!b && To_Kindex) {
+ /*****************************************************************/
+ /* Don't know how to retrieve Rows from DBF file address */
+ /* because of eventual deleted lines still in the file. */
+ /*****************************************************************/
+ sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
+ GetAmName(g, Txfp->GetAmType()));
+ return 0;
+ } // endif To_Kindex
+
+ if (!b)
+ return Txfp->GetRows();
+
+ } // endif DBF
+
+ return Txfp->GetRowID();
+ } // end of RowNumber
+
+/***********************************************************************/
+/* FIX tables don't use temporary files except if specified as do it. */
+/***********************************************************************/
+bool TDBFIX::IsUsingTemp(PGLOBAL)
+ {
+ // Not ready yet to handle using a temporary file with mapping
+ // or while deleting from DBF files.
+ return ((UseTemp() == TMP_YES && Txfp->GetAmType() != TYPE_AM_MAP &&
+ !(Mode == MODE_DELETE && Txfp->GetAmType() == TYPE_AM_DBF)) ||
+ UseTemp() == TMP_FORCE || UseTemp() == TMP_TEST);
+ } // end of IsUsingTemp
+
+/***********************************************************************/
+/* FIX Access Method opening routine (also used by the BIN a.m.) */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool TDBFIX::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("FIX OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d Ftype=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode, Ftype);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ if (To_Kindex)
+ /*****************************************************************/
+ /* Table is to be accessed through a sorted index table. */
+ /*****************************************************************/
+ To_Kindex->Reset();
+ else
+ Txfp->Rewind(); // see comment in Work.log
+
+ ResetBlockFilter(g);
+ return false;
+ } // endif use
+
+ if (Mode == MODE_DELETE && Txfp->GetAmType() == TYPE_AM_MAP &&
+ (!Next || UseTemp() == TMP_FORCE)) {
+ // Delete all lines or using temp. Not handled in MAP mode
+ Txfp = new(g) FIXFAM((PDOSDEF)To_Def);
+ Txfp->SetTdbp(this);
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Call Cardinality to calculate Block in the case of Func queries. */
+ /* and also in the case of multiple tables. */
+ /*********************************************************************/
+ if (Cardinality(g) < 0)
+ return true;
+
+ /*********************************************************************/
+ /* Open according to required logical input/output mode. */
+ /* Use conventionnal input/output functions. */
+ /* Treat fixed length text files as binary. */
+ /*********************************************************************/
+ if (Txfp->OpenTableFile(g))
+ return true;
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Initialize To_Line at the beginning of the block buffer. */
+ /*********************************************************************/
+ To_Line = Txfp->GetBuf(); // For WriteDB
+
+ /*********************************************************************/
+ /* Allocate the block filter tree if evaluation is possible. */
+ /*********************************************************************/
+ To_BlkFil = InitBlockFilter(g, To_Filter);
+
+ if (trace(1))
+ htrc("OpenFix: R%hd mode=%d BlkFil=%p\n", Tdb_No, Mode, To_BlkFil);
+
+ /*********************************************************************/
+ /* Reset buffer access according to indexing and to mode. */
+ /*********************************************************************/
+ Txfp->ResetBuffer(g);
+
+ /*********************************************************************/
+ /* Reset statistics values. */
+ /*********************************************************************/
+ num_read = num_there = num_eq[0] = num_eq[1] = 0;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for FIX access method. */
+/***********************************************************************/
+int TDBFIX::WriteDB(PGLOBAL g)
+ {
+ return Txfp->WriteBuffer(g);
+ } // end of WriteDB
+
+// ------------------------ BINCOL functions ----------------------------
+
+/***********************************************************************/
+/* BINCOL public constructor. */
+/***********************************************************************/
+BINCOL::BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PCSZ am)
+ : DOSCOL(g, cdp, tp, cp, i, am)
+ {
+ char c, *fmt = cdp->GetFmt();
+
+ Fmt = GetDomain() ? 'C' : 'X';
+ Buff = NULL;
+ Eds = ((PTDBFIX)tp)->Teds;
+ N = 0;
+ M = GetTypeSize(Buf_Type, sizeof(longlong));
+ Lim = 0;
+
+ if (fmt) {
+ for (N = 0, i = 0; fmt[i]; i++) {
+ c = toupper(fmt[i]);
+
+ if (isdigit(c))
+ N = (N * 10 + (c - '0'));
+ else if (c == 'L' || c == 'B' || c == 'H')
+ Eds = c;
+ else
+ Fmt = c;
+
+ } // endfor i
+
+ // M is the size of the source value
+ switch (Fmt) {
+ case 'C': Eds = 0; break;
+ case 'X': break;
+ case 'S': M = sizeof(short); break;
+ case 'T': M = sizeof(char); break;
+ case 'I': M = sizeof(int); break;
+ case 'G': M = sizeof(longlong); break;
+ case 'R': // Real
+ case 'F': M = sizeof(float); break;
+ case 'D': M = sizeof(double); break;
+ default:
+ sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name);
+ throw 11;
+ } // endswitch Fmt
+
+ } else if (IsTypeChar(Buf_Type))
+ Eds = 0;
+
+ if (Eds) {
+ // This is a byte order specification
+ if (!N)
+ N = M;
+
+ if (Eds != 'L' && Eds != 'B')
+ Eds = Endian;
+
+ if (N != M || Eds != Endian || IsTypeChar(Buf_Type)) {
+ Buff = (char*)PlugSubAlloc(g, NULL, M);
+ memset(Buff, 0, M);
+ Lim = MY_MIN(N, M);
+ } else
+ Eds = 0; // New format is a no op
+
+ } // endif Eds
+
+ } // end of BINCOL constructor
+
+/***********************************************************************/
+/* BINCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+BINCOL::BINCOL(BINCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
+ {
+ Eds = col1->Eds;
+ Fmt = col1->Fmt;
+ N = col1->N;
+ M = col1->M;
+ Lim = col1->Lim;
+ } // end of BINCOL copy constructor
+
+/***********************************************************************/
+/* Set Endian according to the host setting. */
+/***********************************************************************/
+void BINCOL::SetEndian(void)
+ {
+ union {
+ short S;
+ char C[sizeof(short)];
+ };
+
+ S = 1;
+ Endian = (C[0] == 1) ? 'L' : 'B';
+ } // end of SetEndian
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the last line */
+/* read from the corresponding table and extract from it the field */
+/* corresponding to this column. */
+/***********************************************************************/
+void BINCOL::ReadColumn(PGLOBAL g)
+ {
+ char *p = NULL;
+ int rc;
+ PTDBFIX tdbp = (PTDBFIX)To_Tdb;
+
+ if (trace(2))
+ htrc("BIN ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type);
+
+ /*********************************************************************/
+ /* If physical reading of the line was deferred, do it now. */
+ /*********************************************************************/
+ if (!tdbp->IsRead())
+ if ((rc = tdbp->ReadBuffer(g)) != RC_OK) {
+ if (rc == RC_EF)
+ sprintf(g->Message, MSG(INV_DEF_READ), rc);
+
+ throw 11;
+ } // endif
+
+ p = tdbp->To_Line + Deplac;
+
+ /*********************************************************************/
+ /* Set Value from the line field. */
+ /*********************************************************************/
+ if (Eds) {
+ for (int i = 0; i < Lim; i++)
+ if (Eds == 'B' && Endian == 'L')
+ Buff[i] = p[N - i - 1];
+ else if (Eds == 'L' && Endian == 'B')
+ Buff[M - i - 1] = p[i];
+ else if (Endian == 'B')
+ Buff[M - i - 1] = p[N - i - 1];
+ else
+ Buff[i] = p[i];
+
+ p = Buff;
+ } // endif Eds
+
+ switch (Fmt) {
+ case 'X': // Standard not converted values
+ if (Eds && IsTypeChar(Buf_Type))
+ Value->SetValueNonAligned<longlong>(p);
+ else
+ Value->SetBinValue(p);
+
+ break;
+ case 'S': // Short integer
+ Value->SetValueNonAligned<short>(p);
+ break;
+ case 'T': // Tiny integer
+ Value->SetValue(*p);
+ break;
+ case 'I': // Integer
+ Value->SetValueNonAligned<int>(p);
+ break;
+ case 'G': // Large (great) integer
+ Value->SetValueNonAligned<longlong>(p);
+ break;
+ case 'F': // Float
+ case 'R': // Real
+ Value->SetValueNonAligned<float>(p);
+ break;
+ case 'D': // Double
+ Value->SetValueNonAligned<double>(p);
+ break;
+ case 'C': // Text
+ if (Value->SetValue_char(p, Long)) {
+ sprintf(g->Message, "Out of range value for column %s at row %d",
+ Name, tdbp->RowNumber(g));
+ PushWarning(g, tdbp);
+ } // endif SetValue_char
+
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name);
+ throw 11;
+ } // endswitch Fmt
+
+ // Set null when applicable
+ if (Nullable)
+ Value->SetNull(Value->IsZero());
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last line */
+/* read from the corresponding table, and rewrite the field */
+/* corresponding to this column from the column buffer. */
+/***********************************************************************/
+void BINCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, *s;
+ longlong n;
+ PTDBFIX tdbp = (PTDBFIX)To_Tdb;
+
+ if (trace(1)) {
+ htrc("BIN WriteColumn: col %s R%d coluse=%.4X status=%.4X",
+ Name, tdbp->GetTdb_No(), ColUse, Status);
+ htrc(" Lrecl=%d\n", tdbp->Lrecl);
+ htrc("Long=%d deplac=%d coltype=%d ftype=%c\n",
+ Long, Deplac, Buf_Type, *Format.Type);
+ } // endif trace
+
+ /*********************************************************************/
+ /* Check whether the new value has to be converted to Buf_Type. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ p = (Eds) ? Buff : tdbp->To_Line + Deplac;
+
+ /*********************************************************************/
+ /* Check whether updating is Ok, meaning col value is not too long. */
+ /* Updating will be done only during the second pass (Status=true) */
+ /* Conversion occurs if the external format Fmt is specified. */
+ /*********************************************************************/
+ switch (Fmt) {
+ case 'X':
+ // Standard not converted values
+ if (Eds && IsTypeChar(Buf_Type)) {
+ if (Status)
+ Value->GetValueNonAligned<longlong>(p, Value->GetBigintValue());
+ } else if (Value->GetBinValue(p, Long, Status)) {
+ sprintf(g->Message, MSG(BIN_F_TOO_LONG),
+ Name, Value->GetSize(), Long);
+ throw 31;
+ } // endif p
+
+ break;
+ case 'S': // Short integer
+ n = Value->GetBigintValue();
+
+ if (n > 32767LL || n < -32768LL) {
+ sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
+ throw 31;
+ } else if (Status)
+ Value->GetValueNonAligned<short>(p, (short)n);
+
+ break;
+ case 'T': // Tiny integer
+ n = Value->GetBigintValue();
+
+ if (n > 255LL || n < -256LL) {
+ sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
+ throw 31;
+ } else if (Status)
+ *p = (char)n;
+
+ break;
+ case 'I': // Integer
+ n = Value->GetBigintValue();
+
+ if (n > INT_MAX || n < INT_MIN) {
+ sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name);
+ throw 31;
+ } else if (Status)
+ Value->GetValueNonAligned<int>(p, (int)n);
+
+ break;
+ case 'G': // Large (great) integer
+ if (Status)
+ *(longlong *)p = Value->GetBigintValue();
+
+ break;
+ case 'F': // Float
+ case 'R': // Real
+ if (Status)
+ Value->GetValueNonAligned<float>(p, (float)Value->GetFloatValue());
+
+ break;
+ case 'D': // Double
+ if (Status)
+ Value->GetValueNonAligned<double>(p, Value->GetFloatValue());
+
+ break;
+ case 'C': // Characters
+ if ((n = (signed)strlen(Value->GetCharString(Buf))) > Long) {
+ sprintf(g->Message, MSG(BIN_F_TOO_LONG), Name, (int) n, Long);
+ throw 31;
+ } // endif n
+
+ if (Status) {
+ s = Value->GetCharString(Buf);
+ memset(p, ' ', Long);
+ memcpy(p, s, strlen(s));
+ } // endif Status
+
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name);
+ throw 31;
+ } // endswitch Fmt
+
+ if (Eds && Status) {
+ p = tdbp->To_Line + Deplac;
+
+ for (int i = 0; i < Lim; i++)
+ if (Eds == 'B' && Endian == 'L')
+ p[N - i - 1] = Buff[i];
+ else if (Eds == 'L' && Endian == 'B')
+ p[i] = Buff[M - i - 1];
+ else if (Endian == 'B')
+ p[N - i - 1] = Buff[M - i - 1];
+ else
+ p[i] = Buff[i];
+
+ } // endif Eds
+
+ } // end of WriteColumn
+
+/* ------------------------ End of TabFix ---------------------------- */
diff --git a/storage/connect/tabfix.h b/storage/connect/tabfix.h
new file mode 100644
index 00000000..5f859a2b
--- /dev/null
+++ b/storage/connect/tabfix.h
@@ -0,0 +1,117 @@
+/*************** TabDos H Declares Source Code File (.H) ***************/
+/* Name: TABFIX.H Version 2.4 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1999-2015 */
+/* */
+/* This file contains the TDBFIX and (FIX/BIN)COL classes declares. */
+/***********************************************************************/
+#ifndef __TABFIX__
+#define __TABFIX__
+#include "tabdos.h" /* Base class declares */
+#include "filamdbf.h"
+
+typedef class FIXCOL *PFIXCOL;
+typedef class BINCOL *PBINCOL;
+typedef class TXTFAM *PTXF;
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* that are standard files with columns starting at fixed offset. */
+/* This class is for fixed formatted files. */
+/***********************************************************************/
+class DllExport TDBFIX : public TDBDOS {
+ friend class FIXCOL;
+ friend class BINCOL;
+ public:
+ // Constructor
+ TDBFIX(PDOSDEF tdp, PTXF txfp);
+ TDBFIX(PGLOBAL g, PTDBFIX tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_FIX;}
+ virtual void RestoreNrec(void);
+ virtual PTDB Duplicate(PGLOBAL g)
+ {return (PTDB)new(g) TDBFIX(g, this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual void ResetDB(void);
+ virtual bool IsUsingTemp(PGLOBAL g);
+ virtual int RowNumber(PGLOBAL g, bool b = false);
+ virtual int ResetTableOpt(PGLOBAL g, bool dop, bool dox);
+ virtual void ResetSize(void);
+ virtual int GetBadLines(void) {return Txfp->GetNerr();}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int GetProgMax(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+
+ protected:
+ virtual bool PrepareWriting(PGLOBAL g) {return false;}
+
+ // Members
+ char Teds; /* Binary table default endian setting */
+ }; // end of class TDBFIX
+
+/***********************************************************************/
+/* Class BINCOL: BIN access method column descriptor. */
+/* This A.M. is used for file processed by blocks. */
+/***********************************************************************/
+class DllExport BINCOL : public DOSCOL {
+ friend class TDBFIX;
+ public:
+ // Constructors
+ BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PCSZ am = "BIN");
+ BINCOL(BINCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_BIN;}
+ int GetDeplac(void) {return Deplac;}
+ int GetFileSize(void)
+ {return N ? N : GetTypeSize(Buf_Type, Long);}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+ // Static
+ static void SetEndian(void);
+
+ protected:
+ BINCOL(void) {} // Default constructor not to be used
+
+ // Members
+ static char Endian; // The host endian setting (L or B)
+ char *Buff; // Utility buffer
+ char Eds; // The file endian setting
+ char Fmt; // The converted value format
+ int N; // The number of bytes in the file
+ int M; // The buffer type size
+ int Lim; // Min(N,M)
+ }; // end of class BINCOL
+
+/***********************************************************************/
+/* This is the class declaration for the DBF columns catalog table. */
+/***********************************************************************/
+class TDBDCL : public TDBCAT {
+public:
+ // Constructor
+ TDBDCL(PDOSDEF tdp) : TDBCAT(tdp)
+ {Fn = tdp->GetFn(); Topt = tdp->GetTopt();}
+
+protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g)
+ {return DBFColumns(g, ((PTABDEF)To_Def)->GetPath(), Fn, Topt, false);}
+
+ // Members
+ PCSZ Fn; // The DBF file (path) name
+ PTOS Topt;
+}; // end of class TDBOCL
+
+
+#endif // __TABFIX__
diff --git a/storage/connect/tabfmt.cpp b/storage/connect/tabfmt.cpp
new file mode 100644
index 00000000..49233f4f
--- /dev/null
+++ b/storage/connect/tabfmt.cpp
@@ -0,0 +1,1573 @@
+/************* TabFmt C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABFMT */
+/* ------------- */
+/* Version 3.9.3 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2001 - 2019 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TABFMT classes DB execution routines. */
+/* The base class CSV is comma separated files. */
+/* FMT (Formatted) files are those having a complex internal record */
+/* format described in the Format keyword of their definition. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <locale.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#include "osutil.h"
+#else
+#if defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#include "osutil.h"
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tabdos.h is header containing the TABDOS class declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "mycat.h"
+#include "filamap.h"
+#if defined(GZ_SUPPORT)
+#include "filamgz.h"
+#endif // GZ_SUPPORT
+#if defined(ZIP_SUPPORT)
+#include "filamzip.h"
+#endif // ZIP_SUPPORT
+#include "tabfmt.h"
+#include "tabmul.h"
+#define NO_FUNC
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+
+/***********************************************************************/
+/* This should be an option. */
+/***********************************************************************/
+#define MAXCOL 200 /* Default max column nb in result */
+#define TYPE_UNKNOWN 12 /* Must be greater than other types */
+
+/***********************************************************************/
+/* External function. */
+/***********************************************************************/
+USETEMP UseTemp(void);
+
+/***********************************************************************/
+/* CSVColumns: constructs the result blocks containing the description */
+/* of all the columns of a CSV file that will be retrieved by #GetData.*/
+/* Note: the algorithm to set the type is based on the internal values */
+/* of types (TYPE_STRING < TYPE_DOUBLE < TYPE_INT) (1 < 2 < 7). */
+/* If these values are changed, this will have to be revisited. */
+/***********************************************************************/
+PQRYRES CSVColumns(PGLOBAL g, PCSZ dp, PTOS topt, bool info)
+ {
+ static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
+ TYPE_INT, TYPE_INT, TYPE_SHORT};
+ static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME,
+ FLD_PREC, FLD_LENGTH, FLD_SCALE};
+ static unsigned int length[] = {6, 6, 8, 10, 10, 6};
+ const char *fn;
+ char sep, q;
+ int rc, mxr;
+ bool hdr;
+ char *p, *colname[MAXCOL], dechar, buf[8];
+ int i, imax, hmax, n, nerr, phase, blank, digit, dec, type;
+ int ncol = sizeof(buftyp) / sizeof(int);
+ int num_read = 0, num_max = 10000000; // Statistics
+ int len[MAXCOL], typ[MAXCOL], prc[MAXCOL];
+ PCSVDEF tdp;
+ PTDBCSV tcvp;
+ PTDBASE tdbp;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ if (info) {
+ imax = hmax = 0;
+ length[0] = 128;
+ goto skipit;
+ } // endif info
+
+ //if (GetIntegerTableOption(g, topt, "Multiple", 0)) {
+ // strcpy(g->Message, "Cannot find column definition for multiple table");
+ // return NULL;
+ //} // endif Multiple
+
+// num_max = atoi(p+1); // Max num of record to test
+ imax = hmax = nerr = 0;
+
+ for (i = 0; i < MAXCOL; i++) {
+ colname[i] = NULL;
+ len[i] = 0;
+ typ[i] = TYPE_UNKNOWN;
+ prc[i] = 0;
+ } // endfor i
+
+ /*********************************************************************/
+ /* Get the CSV table description block. */
+ /*********************************************************************/
+ tdp = new(g) CSVDEF;
+ tdp->Database = dp;
+
+ if ((tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false))) {
+#if defined(ZIP_SUPPORT)
+ tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
+ tdp->Mulentries = (tdp->Entry)
+ ? strchr(tdp->Entry, '*') || strchr(tdp->Entry, '?')
+ : GetBooleanTableOption(g, topt, "Mulentries", false);
+#else // !ZIP_SUPPORT
+ strcpy(g->Message, "ZIP not supported by this version");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } // endif // Zipped
+
+ fn = tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL);
+
+ if (!tdp->Fn) {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return NULL;
+ } // endif Fn
+
+ if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))
+ tdp->Lrecl = 4096;
+
+ tdp->Multiple = GetIntegerTableOption(g, topt, "Multiple", 0);
+ p = (char*)GetStringTableOption(g, topt, "Separator", ",");
+ tdp->Sep = (strlen(p) == 2 && p[0] == '\\' && p[1] == 't') ? '\t' : *p;
+
+#if defined(_WIN32)
+ if (tdp->Sep == ',' || strnicmp(setlocale(LC_NUMERIC, NULL), "French", 6))
+ dechar = '.';
+ else
+ dechar = ',';
+#else // !_WIN32
+ dechar = '.';
+#endif // !_WIN32
+
+ sep = tdp->Sep;
+ tdp->Quoted = GetIntegerTableOption(g, topt, "Quoted", -1);
+ p = (char*)GetStringTableOption(g, topt, "Qchar", "");
+ tdp->Qot = *p;
+
+ if (tdp->Qot && tdp->Quoted < 0)
+ tdp->Quoted = 0;
+ else if (!tdp->Qot && tdp->Quoted >= 0)
+ tdp->Qot = '"';
+
+ q = tdp->Qot;
+ hdr = GetBooleanTableOption(g, topt, "Header", false);
+ tdp->Maxerr = GetIntegerTableOption(g, topt, "Maxerr", 0);
+ tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false);
+
+ if (tdp->Accept && tdp->Maxerr == 0)
+ tdp->Maxerr = INT_MAX32; // Accept all bad lines
+
+ mxr = MY_MAX(0, tdp->Maxerr);
+
+ if (trace(1))
+ htrc("File %s Sep=%c Qot=%c Header=%d maxerr=%d\n",
+ SVP(tdp->Fn), tdp->Sep, tdp->Qot, tdp->Header, tdp->Maxerr);
+
+#if defined(ZIP_SUPPORT)
+ if (tdp->Zipped)
+ tcvp = new(g)TDBCSV(tdp, new(g)UNZFAM(tdp));
+ else
+#endif // ZIP_SUPPORT
+ tcvp = new(g) TDBCSV(tdp, new(g) DOSFAM(tdp));
+
+ tcvp->SetMode(MODE_READ);
+
+ if (tdp->Multiple) {
+ tdbp = new(g)TDBMUL(tcvp);
+ tdbp->SetMode(MODE_READ);
+ } else
+ tdbp = tcvp;
+
+ /*********************************************************************/
+ /* Open the CSV file. */
+ /*********************************************************************/
+ if (tdbp->OpenDB(g))
+ return NULL;
+
+ if (hdr) {
+ /*******************************************************************/
+ /* Make the column names from the first line. */
+ /*******************************************************************/
+ phase = 0;
+
+ if ((rc = tdbp->ReadDB(g)) == RC_OK) {
+ p = PlgDBDup(g, tcvp->To_Line);
+
+ //skip leading blanks
+ for (; *p == ' '; p++) ;
+
+ if (q && *p == q) {
+ // Header is quoted
+ p++;
+ phase = 1;
+ } // endif q
+
+ colname[0] = p;
+ } else if (rc == RC_EF) {
+ sprintf(g->Message, MSG(FILE_IS_EMPTY), fn);
+ goto err;
+ } else
+ goto err;
+
+ for (i = 1; *p; p++)
+ if (phase == 1 && *p == q) {
+ *p = '\0';
+ phase = 0;
+ } else if (*p == sep && !phase) {
+ *p = '\0';
+
+ //skip leading blanks
+ for (; *(p+1) == ' '; p++) ;
+
+ if (q && *(p+1) == q) {
+ // Header is quoted
+ p++;
+ phase = 1;
+ } // endif q
+
+ colname[i++] = p + 1;
+ } // endif sep
+
+ num_read++;
+ imax = hmax = i;
+
+ for (i = 0; i < hmax; i++)
+ length[0] = MY_MAX(length[0], strlen(colname[i]));
+
+ tcvp->Header = true; // In case of multiple table
+ } // endif hdr
+
+ for (num_read++; num_read <= num_max; num_read++) {
+ /*******************************************************************/
+ /* Now start the reading process. Read one line. */
+ /*******************************************************************/
+ if ((rc = tdbp->ReadDB(g)) == RC_OK) {
+ } else if (rc == RC_EF) {
+ sprintf(g->Message, MSG(EOF_AFTER_LINE), num_read -1);
+ break;
+ } else {
+ sprintf(g->Message, MSG(ERR_READING_REC), num_read, fn);
+ goto err;
+ } // endif's
+
+ /*******************************************************************/
+ /* Make the test for field lengths. */
+ /*******************************************************************/
+ i = n = phase = blank = digit = dec = 0;
+
+ for (p = tcvp->To_Line; *p; p++)
+ if (*p == sep) {
+ if (phase != 1) {
+ if (i == MAXCOL - 1) {
+ sprintf(g->Message, MSG(TOO_MANY_FIELDS), num_read, fn);
+ goto err;
+ } // endif i
+
+ if (n) {
+ len[i] = MY_MAX(len[i], n);
+ type = (digit || (dec && n == 1)) ? TYPE_STRING
+ : (dec) ? TYPE_DOUBLE : TYPE_INT;
+ typ[i] = MY_MIN(type, typ[i]);
+ prc[i] = MY_MAX((typ[i] == TYPE_DOUBLE) ? (dec - 1) : 0, prc[i]);
+ } // endif n
+
+ i++;
+ n = phase = blank = digit = dec = 0;
+ } else // phase == 1
+ n++;
+
+ } else if (*p == ' ') {
+ if (phase < 2)
+ n++;
+
+ if (blank)
+ digit = 1;
+
+ } else if (*p == q) {
+ if (phase == 0) {
+ if (blank) {
+ if (++nerr > mxr) {
+ sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
+ goto err;
+ } else
+ goto skip;
+ }
+
+ n = 0;
+ phase = digit = 1;
+ } else if (phase == 1) {
+ if (*(p+1) == q) {
+ // This is currently not implemented for CSV tables
+// if (++nerr > mxr) {
+// sprintf(g->Message, MSG(QUOTE_IN_QUOTE), num_read);
+// goto err;
+// } else
+// goto skip;
+
+ p++;
+ n++;
+ } else
+ phase = 2;
+
+ } else if (++nerr > mxr) { // phase == 2
+ sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
+ goto err;
+ } else
+ goto skip;
+
+ } else {
+ if (phase == 2) {
+ if (++nerr > mxr) {
+ sprintf(g->Message, MSG(MISPLACED_QUOTE), num_read);
+ goto err;
+ } else
+ goto skip;
+ }
+
+ // isdigit cannot be used here because of debug assert
+ if (!strchr("0123456789", *p)) {
+ if (!digit && *p == dechar)
+ dec = 1; // Decimal point found
+ else if (blank || !(*p == '-' || *p == '+'))
+ digit = 1;
+
+ } else if (dec)
+ dec++; // More decimals
+
+ n++;
+ blank = 1;
+ } // endif's *p
+
+ if (phase == 1) {
+ if (++nerr > mxr) {
+ sprintf(g->Message, MSG(UNBALANCE_QUOTE), num_read);
+ goto err;
+ } else
+ goto skip;
+ }
+
+ if (n) {
+ len[i] = MY_MAX(len[i], n);
+ type = (digit || n == 0 || (dec && n == 1)) ? TYPE_STRING
+ : (dec) ? TYPE_DOUBLE : TYPE_INT;
+ typ[i] = MY_MIN(type, typ[i]);
+ prc[i] = MY_MAX((typ[i] == TYPE_DOUBLE) ? (dec - 1) : 0, prc[i]);
+ } // endif n
+
+ imax = MY_MAX(imax, i+1);
+ skip: ; // Skip erroneous line
+ } // endfor num_read
+
+ if (trace(1)) {
+ htrc("imax=%d Lengths:", imax);
+
+ for (i = 0; i < imax; i++)
+ htrc(" %d", len[i]);
+
+ htrc("\n");
+ } // endif trace
+
+ tdbp->CloseDB(g);
+
+ skipit:
+ if (trace(1))
+ htrc("CSVColumns: imax=%d hmax=%d len=%d\n",
+ imax, hmax, length[0]);
+
+ /*********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /*********************************************************************/
+ qrp = PlgAllocResult(g, ncol, imax, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, false);
+ if (info || !qrp)
+ return qrp;
+
+ qrp->Nblin = imax;
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ for (i = 0; i < imax; i++) {
+ if (i >= hmax) {
+ sprintf(buf, "COL%.3d", i+1);
+ p = buf;
+ } else
+ p = colname[i];
+
+ if (typ[i] == TYPE_UNKNOWN) // Void column
+ typ[i] = TYPE_STRING;
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(p, i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(typ[i], i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(typ[i]), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(len[i], i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(len[i], i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(prc[i], i);
+ } // endfor i
+
+ /*********************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /*********************************************************************/
+ return qrp;
+
+ err:
+ tdbp->CloseDB(g);
+ return NULL;
+ } // end of CSVCColumns
+
+/* --------------------------- Class CSVDEF -------------------------- */
+
+/***********************************************************************/
+/* CSVDEF constructor. */
+/***********************************************************************/
+CSVDEF::CSVDEF(void)
+ {
+ Fmtd = Header = false;
+//Maxerr = 0;
+ Quoted = -1;
+ Sep = ',';
+ Qot = '\0';
+ } // end of CSVDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool CSVDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ char buf[8];
+
+ // Double check correctness of offset values
+ if (Catfunc == FNC_NO)
+ for (PCOLDEF cdp = To_Cols; cdp; cdp = cdp->GetNext())
+ if (cdp->GetOffset() < 1 && !cdp->IsSpecial()) {
+ strcpy(g->Message, MSG(BAD_OFFSET_VAL));
+ return true;
+ } // endif Offset
+
+ // Call DOSDEF DefineAM with am=CSV so FMT is not confused with FIX
+ if (DOSDEF::DefineAM(g, "CSV", poff))
+ return true;
+
+ Recfm = RECFM_CSV;
+ GetCharCatInfo("Separator", ",", buf, sizeof(buf));
+ Sep = (strlen(buf) == 2 && buf[0] == '\\' && buf[1] == 't') ? '\t' : *buf;
+ Quoted = GetIntCatInfo("Quoted", -1);
+ GetCharCatInfo("Qchar", "", buf, sizeof(buf));
+ Qot = *buf;
+
+ if (Qot && Quoted < 0)
+ Quoted = 0;
+ else if (!Qot && Quoted >= 0)
+ Qot = '"';
+
+ Fmtd = (!Sep || (am && (*am == 'F' || *am == 'f')));
+ Header = GetBoolCatInfo("Header", false);
+ Maxerr = GetIntCatInfo("Maxerr", 0);
+ Accept = GetBoolCatInfo("Accept", false);
+
+ if (Accept && Maxerr == 0)
+ Maxerr = INT_MAX32; // Accept all bad lines
+
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB CSVDEF::GetTable(PGLOBAL g, MODE mode)
+ {
+ PTDBASE tdbp;
+
+ if (Catfunc != FNC_COL) {
+ USETEMP tmp = UseTemp();
+ bool map = Mapped && mode != MODE_INSERT &&
+ !(tmp != TMP_NO && mode == MODE_UPDATE) &&
+ !(tmp == TMP_FORCE &&
+ (mode == MODE_UPDATE || mode == MODE_DELETE));
+ PTXF txfp;
+
+ /*******************************************************************/
+ /* Allocate a file processing class of the proper type. */
+ /*******************************************************************/
+ if (Zipped) {
+#if defined(ZIP_SUPPORT)
+ if (mode == MODE_READ || mode == MODE_ANY || mode == MODE_ALTER) {
+ txfp = new(g) UNZFAM(this);
+ } else if (mode == MODE_INSERT) {
+ txfp = new(g) ZIPFAM(this);
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's mode
+#else // !ZIP_SUPPORT
+ strcpy(g->Message, "ZIP not supported");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } else if (map) {
+ // Should be now compatible with UNIX
+ txfp = new(g) MAPFAM(this);
+ } else if (Compressed) {
+#if defined(GZ_SUPPORT)
+ if (Compressed == 1)
+ txfp = new(g) GZFAM(this);
+ else
+ txfp = new(g) ZLBFAM(this);
+
+#else // !GZ_SUPPORT
+ strcpy(g->Message, "Compress not supported");
+ return NULL;
+#endif // !GZ_SUPPORT
+ } else
+ txfp = new(g) DOSFAM(this);
+
+ /*******************************************************************/
+ /* Allocate a TDB of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*******************************************************************/
+ if (!Fmtd)
+ tdbp = new(g) TDBCSV(this, txfp);
+ else
+ tdbp = new(g) TDBFMT(this, txfp);
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+ else
+ /*****************************************************************/
+ /* For block tables, get eventually saved optimization values. */
+ /*****************************************************************/
+ if (tdbp->GetBlockValues(g)) {
+ PushWarning(g, tdbp);
+// return NULL; // causes a crash when deleting index
+ } else {
+ if (IsOptimized()) {
+ if (map) {
+ txfp = new(g) MBKFAM(this);
+ } else if (Compressed) {
+#if defined(GZ_SUPPORT)
+ if (Compressed == 1)
+ txfp = new(g) ZBKFAM(this);
+ else {
+ txfp->SetBlkPos(To_Pos);
+ ((PZLBFAM)txfp)->SetOptimized(To_Pos != NULL);
+ } // endelse
+#else
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ");
+ return NULL;
+#endif
+ } else
+ txfp = new(g) BLKFAM(this);
+
+ ((PTDBDOS)tdbp)->SetTxfp(txfp);
+ } // endif Optimized
+
+ } // endelse
+
+ } else
+ tdbp = new(g)TDBCCL(this);
+
+ return tdbp;
+ } // end of GetTable
+
+/* -------------------------- Class TDBCSV --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBCSV class. */
+/***********************************************************************/
+TDBCSV::TDBCSV(PCSVDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
+ {
+#if defined(_DEBUG)
+ assert (tdp);
+#endif
+ Field = NULL;
+ Offset = NULL;
+ Fldlen = NULL;
+ Fields = 0;
+ Nerr = 0;
+ Quoted = tdp->Quoted;
+ Maxerr = tdp->Maxerr;
+ Accept = tdp->Accept;
+ Header = tdp->Header;
+ Sep = tdp->GetSep();
+ Qot = tdp->GetQot();
+ } // end of TDBCSV standard constructor
+
+TDBCSV::TDBCSV(PGLOBAL g, PTDBCSV tdbp) : TDBDOS(g, tdbp)
+ {
+ Fields = tdbp->Fields;
+
+ if (Fields) {
+ if (tdbp->Offset)
+ Offset = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+
+ if (tdbp->Fldlen)
+ Fldlen = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+
+ Field = (PSZ *)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
+
+ for (int i = 0; i < Fields; i++) {
+ if (Offset)
+ Offset[i] = tdbp->Offset[i];
+
+ if (Fldlen)
+ Fldlen[i] = tdbp->Fldlen[i];
+
+ if (Field) {
+ assert (Fldlen);
+ Field[i] = (PSZ)PlugSubAlloc(g, NULL, Fldlen[i] + 1);
+ Field[i][Fldlen[i]] = '\0';
+ } // endif Field
+
+ } // endfor i
+
+ } else {
+ Field = NULL;
+ Offset = NULL;
+ Fldlen = NULL;
+ } // endif Fields
+
+ Nerr = tdbp->Nerr;
+ Maxerr = tdbp->Maxerr;
+ Quoted = tdbp->Quoted;
+ Accept = tdbp->Accept;
+ Header = tdbp->Header;
+ Sep = tdbp->Sep;
+ Qot = tdbp->Qot;
+ } // end of TDBCSV copy constructor
+
+// Method
+PTDB TDBCSV::Clone(PTABS t)
+ {
+ PTDB tp;
+ PCSVCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBCSV(g, this);
+
+ for (cp1 = (PCSVCOL)Columns; cp1; cp1 = (PCSVCOL)cp1->GetNext()) {
+ cp2 = new(g) CSVCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Allocate CSV column description block. */
+/***********************************************************************/
+PCOL TDBCSV::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) CSVCOL(g, cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Check whether the number of errors is greater than the maximum. */
+/***********************************************************************/
+bool TDBCSV::CheckErr(void)
+ {
+ return (++Nerr) > Maxerr;
+ } // end of CheckErr
+
+/***********************************************************************/
+/* CSV EstimatedLength. Returns an estimated minimum line length. */
+/***********************************************************************/
+int TDBCSV::EstimatedLength(void)
+ {
+ int n = 0;
+ PCOLDEF cdp;
+
+ if (trace(1))
+ htrc("EstimatedLength: Fields=%d Columns=%p\n", Fields, Columns);
+
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!cdp->IsSpecial() && !cdp->IsVirtual()) // A true column
+ n++;
+
+ return --n; // Number of separators if all fields are null
+ } // end of Estimated Length
+
+#if 0
+/***********************************************************************/
+/* CSV tables needs the use temporary files for Update. */
+/***********************************************************************/
+bool TDBCSV::IsUsingTemp(PGLOBAL g)
+ {
+ return (Use_Temp == TMP_YES || Use_Temp == TMP_FORCE ||
+ (Use_Temp == TMP_AUTO && Mode == MODE_UPDATE));
+ } // end of IsUsingTemp
+#endif // 0 (Same as TDBDOS one)
+
+/***********************************************************************/
+/* CSV Access Method opening routine. */
+/* First allocate the Offset and Fldlen arrays according to the */
+/* greatest field used in that query. Then call the DOS opening fnc. */
+/***********************************************************************/
+bool TDBCSV::OpenDB(PGLOBAL g)
+ {
+ bool rc = false;
+ PCOLDEF cdp;
+ PDOSDEF tdp = (PDOSDEF)To_Def;
+
+ if (Use != USE_OPEN && (Columns || Mode == MODE_UPDATE)) {
+ // Allocate the storage used to read (or write) records
+ int i, len;
+ PCSVCOL colp;
+
+ if (!Fields) { // May have been set in TABFMT::OpenDB
+ if (Mode != MODE_UPDATE && Mode != MODE_INSERT) {
+ for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
+ if (!colp->IsSpecial() && !colp->IsVirtual())
+ Fields = MY_MAX(Fields, (int)colp->Fldnum);
+
+ if (Columns)
+ Fields++; // Fldnum was 0 based
+
+ } else
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!cdp->IsSpecial() && !cdp->IsVirtual())
+ Fields++;
+ }
+
+ Offset = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+ Fldlen = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+
+ if (Mode == MODE_INSERT || Mode == MODE_UPDATE) {
+ Field = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
+ Fldtyp = (bool*)PlugSubAlloc(g, NULL, sizeof(bool) * Fields);
+ } // endif Mode
+
+ for (i = 0; i < Fields; i++) {
+ Offset[i] = 0;
+ Fldlen[i] = 0;
+
+ if (Field) {
+ Field[i] = NULL;
+ Fldtyp[i] = false;
+ } // endif Field
+
+ } // endfor i
+
+ if (Field) {
+ // Prepare writing fields
+ if (Mode != MODE_UPDATE) {
+ for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
+ if (!colp->IsSpecial() && !colp->IsVirtual()) {
+ i = colp->Fldnum;
+ len = colp->GetLength();
+ Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1);
+ Field[i][len] = '\0';
+ Fldlen[i] = len;
+ Fldtyp[i] = IsTypeNum(colp->GetResultType());
+ } // endif colp
+
+ } else // MODE_UPDATE
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!cdp->IsSpecial() && !cdp->IsVirtual()) {
+ i = cdp->GetOffset() - 1;
+ len = cdp->GetLength();
+ Field[i] = (PSZ)PlugSubAlloc(g, NULL, len + 1);
+ Field[i][len] = '\0';
+ Fldlen[i] = len;
+ Fldtyp[i] = IsTypeNum(cdp->GetType());
+ } // endif cdp
+ }
+ } // endif Use
+
+ if (Header) {
+ // Check that the Lrecl is at least equal to the header line length
+ int headlen = 0;
+ PCOLDEF cdp;
+ PDOSDEF tdp = (PDOSDEF)To_Def;
+
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ headlen += strlen(cdp->GetName()) + 3; // 3 if names are quoted
+
+ if (headlen > Lrecl) {
+ Lrecl = headlen;
+ Txfp->Lrecl = headlen;
+ } // endif headlen
+
+ } // endif Header
+
+ Nerr = 0;
+ rc = TDBDOS::OpenDB(g);
+
+ if (!rc && Mode == MODE_UPDATE && To_Kindex)
+ // Because KINDEX::Init is executed in mode READ, we must restore
+ // the Fldlen array that was modified when reading the table file.
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ Fldlen[cdp->GetOffset() - 1] = cdp->GetLength();
+
+ return rc;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* SkipHeader: Physically skip first header line if applicable. */
+/* This is called from TDBDOS::OpenDB and must be executed before */
+/* Kindex construction if the file is accessed using an index. */
+/***********************************************************************/
+bool TDBCSV::SkipHeader(PGLOBAL g)
+ {
+ int len = GetFileLength(g);
+ bool rc = false;
+
+#if defined(_DEBUG)
+ if (len < 0)
+ return true;
+#endif // _DEBUG
+
+ if (Header) {
+ if (Mode == MODE_INSERT) {
+ if (!len) {
+ // New file, the header line must be constructed and written
+ int i, n = 0;
+ int hlen = 0;
+ bool q = Qot && Quoted > 0;
+ PCOLDEF cdp;
+
+ // Estimate the length of the header list
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) {
+ hlen += (1 + strlen(cdp->GetName()));
+ hlen += ((q) ? 2 : 0);
+ n++; // Calculate the number of columns
+ } // endfor cdp
+
+ if (hlen > Lrecl) {
+ sprintf(g->Message, MSG(LRECL_TOO_SMALL), hlen);
+ return true;
+ } // endif hlen
+
+ // File is empty, write a header record
+ memset(To_Line, 0, Lrecl);
+
+ // The column order in the file is given by the offset value
+ for (i = 1; i <= n; i++)
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
+ if (cdp->GetOffset() == i) {
+ if (q)
+ To_Line[strlen(To_Line)] = Qot;
+
+ strcat(To_Line, cdp->GetName());
+
+ if (q)
+ To_Line[strlen(To_Line)] = Qot;
+
+ if (i < n)
+ To_Line[strlen(To_Line)] = Sep;
+
+ } // endif Offset
+
+ rc = (Txfp->WriteBuffer(g) == RC_FX);
+ } // endif !FileLength
+
+ } else if (Mode == MODE_DELETE) {
+ if (len)
+ rc = (Txfp->SkipRecord(g, true) == RC_FX);
+
+ } else if (len) // !Insert && !Delete
+ rc = (Txfp->SkipRecord(g, false) == RC_FX || Txfp->RecordPos(g));
+
+ } // endif Header
+
+ return rc;
+ } // end of SkipHeader
+
+/***********************************************************************/
+/* ReadBuffer: Physical read routine for the CSV access method. */
+/***********************************************************************/
+int TDBCSV::ReadBuffer(PGLOBAL g)
+ {
+ //char *p1, *p2, *p = NULL;
+ char *p2, *p = NULL;
+ int i, n, len, rc = Txfp->ReadBuffer(g);
+ bool bad = false;
+
+ if (trace(2))
+ htrc("CSV: Row is '%s' rc=%d\n", To_Line, rc);
+
+ if (rc != RC_OK || !Fields)
+ return rc;
+ else
+ p2 = To_Line;
+
+ // Find the offsets and lengths of the columns for this row
+ for (i = 0; i < Fields; i++) {
+ if (!bad) {
+ if (Qot && *p2 == Qot) { // Quoted field
+ //for (n = 0, p1 = ++p2; (p = strchr(p1, Qot)); p1 = p + 2)
+ // if (*(p + 1) == Qot)
+ // n++; // Doubled internal quotes
+ // else
+ // break; // Final quote
+
+ for (n = 0, p = ++p2; p; p++)
+ if (*p == Qot || *p == '\\') {
+ if (*(++p) == Qot)
+ n++; // Escaped internal quotes
+ else if (*(p - 1) == Qot)
+ break; // Final quote
+ } // endif *p
+
+ if (p) {
+ //len = p++ - p2;
+ len = (int)(p - p2 - 1);
+
+// if (Sep != ' ')
+// for (; *p == ' '; p++) ; // Skip blanks
+
+ if (*p != Sep && i != Fields - 1) { // Should be the separator
+ if (CheckErr()) {
+ sprintf(g->Message, MSG(MISSING_FIELD),
+ i+1, Name, RowNumber(g));
+ return RC_FX;
+ } else if (Accept)
+ bad = true;
+ else
+ return RC_NF;
+
+ } // endif p
+
+ if (n) {
+ int j, k;
+
+ // Suppress the escape of internal quotes
+ for (j = k = 0; j < len; j++, k++) {
+ if (p2[j] == Qot || (p2[j] == '\\' && p2[j + 1] == Qot))
+ j++; // skip escape char
+ else if (p2[j] == '\\')
+ p2[k++] = p2[j++]; // avoid \\Qot
+
+ p2[k] = p2[j];
+ } // endfor i, j
+
+ len -= n;
+ } // endif n
+
+ } else if (CheckErr()) {
+ sprintf(g->Message, MSG(BAD_QUOTE_FIELD),
+ Name, i+1, RowNumber(g));
+ return RC_FX;
+ } else if (Accept) {
+ len = strlen(p2);
+ bad = true;
+ } else
+ return RC_NF;
+
+ } else if ((p = strchr(p2, Sep)))
+ len = (int)(p - p2);
+ else if (i == Fields - 1)
+ len = strlen(p2);
+ else if (Accept && Maxerr == 0) {
+ len = strlen(p2);
+ bad = true;
+ } else if (CheckErr()) {
+ sprintf(g->Message, MSG(MISSING_FIELD), i+1, Name, RowNumber(g));
+ return RC_FX;
+ } else if (Accept) {
+ len = strlen(p2);
+ bad = true;
+ } else
+ return RC_NF;
+
+ } else
+ len = 0;
+
+ Offset[i] = (int)(p2 - To_Line);
+
+ if (Mode != MODE_UPDATE)
+ Fldlen[i] = len;
+ else if (len > Fldlen[i]) {
+ sprintf(g->Message, MSG(FIELD_TOO_LONG), i+1, RowNumber(g));
+ return RC_FX;
+ } else {
+ strncpy(Field[i], p2, len);
+ Field[i][len] = '\0';
+ } // endif Mode
+
+ if (p)
+ p2 = p + 1;
+
+ } // endfor i
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Prepare the line to write. */
+/***********************************************************************/
+bool TDBCSV::PrepareWriting(PGLOBAL g)
+ {
+ char sep[2], qot[2];
+ int i, nlen, oldlen = strlen(To_Line);
+
+ if (trace(2))
+ htrc("CSV WriteDB: R%d Mode=%d key=%p link=%p\n",
+ Tdb_No, Mode, To_Key_Col, To_Link);
+
+ // Before writing the line we must check its length
+ if ((nlen = CheckWrite(g)) < 0)
+ return true;
+
+ // Before writing the line we must make it
+ sep[0] = Sep;
+ sep[1] = '\0';
+ qot[0] = Qot;
+ qot[1] = '\0';
+ *To_Line = '\0';
+
+ for (i = 0; i < Fields; i++) {
+ if (i)
+ strcat(To_Line, sep);
+
+ if (Field[i]) {
+ if (!strlen(Field[i])) {
+ // Generally null fields are not quoted
+ if (Quoted > 2)
+ // Except if explicitely required
+ strcat(strcat(To_Line, qot), qot);
+
+ } else if (Qot && (strchr(Field[i], Sep) || *Field[i] == Qot
+ || Quoted > 1 || (Quoted == 1 && !Fldtyp[i]))) {
+ if (strchr(Field[i], Qot)) {
+ // Field contains quotes that must be doubled
+ int j, k = strlen(To_Line), n = strlen(Field[i]);
+
+ To_Line[k++] = Qot;
+
+ for (j = 0; j < n; j++) {
+ if (Field[i][j] == Qot)
+ To_Line[k++] = Qot;
+
+ To_Line[k++] = Field[i][j];
+ } // endfor j
+
+ To_Line[k++] = Qot;
+ To_Line[k] = '\0';
+ } else
+ strcat(strcat(strcat(To_Line, qot), Field[i]), qot);
+ }
+
+ else
+ strcat(To_Line, Field[i]);
+ }
+ } // endfor i
+
+#if defined(_DEBUG)
+ assert ((unsigned)nlen == strlen(To_Line));
+#endif
+
+ if (Mode == MODE_UPDATE && nlen < oldlen
+ && !((PDOSFAM)Txfp)->GetUseTemp()) {
+ // In Update mode with no temp file, line length must not change
+ To_Line[nlen] = Sep;
+
+ for (nlen++; nlen < oldlen; nlen++)
+ To_Line[nlen] = ' ';
+
+ To_Line[nlen] = '\0';
+ } // endif
+
+ if (trace(2))
+ htrc("Write: line is=%s", To_Line);
+
+ return false;
+ } // end of PrepareWriting
+
+/***********************************************************************/
+/* Data Base write routine CSV file access method. */
+/***********************************************************************/
+int TDBCSV::WriteDB(PGLOBAL g)
+ {
+ // Before writing the line we must check and prepare it
+ if (PrepareWriting(g))
+ return RC_FX;
+
+ /*********************************************************************/
+ /* Now start the writing process. */
+ /*********************************************************************/
+ return Txfp->WriteBuffer(g);
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Check whether a new line fit in the file lrecl size. */
+/***********************************************************************/
+int TDBCSV::CheckWrite(PGLOBAL g)
+ {
+ int maxlen, n, nlen = (Fields - 1);
+
+ if (trace(2))
+ htrc("CheckWrite: R%d Mode=%d\n", Tdb_No, Mode);
+
+ // Before writing the line we must check its length
+ maxlen = (Mode == MODE_UPDATE && !Txfp->GetUseTemp())
+ ? strlen(To_Line) : Lrecl;
+
+ // Check whether record is too int
+ for (int i = 0; i < Fields; i++)
+ {
+ if (Field[i]) {
+ if (!(n = strlen(Field[i])))
+ n += (Quoted > 2 ? 2 : 0);
+ else if (strchr(Field[i], Sep) || (Qot && *Field[i] == Qot)
+ || Quoted > 1 || (Quoted == 1 && !Fldtyp[i]))
+ {
+ if (!Qot) {
+ sprintf(g->Message, MSG(SEP_IN_FIELD), i + 1);
+ return -1;
+ } else {
+ // Quotes inside a quoted field must be doubled
+ char *p1, *p2;
+
+ for (p1 = Field[i]; (p2 = strchr(p1, Qot)); p1 = p2 + 1)
+ n++;
+
+ n += 2; // Outside quotes
+ } // endif
+ }
+ if ((nlen += n) > maxlen) {
+ strcpy(g->Message, MSG(LINE_TOO_LONG));
+ return -1;
+ } // endif nlen
+
+ } // endif Field
+ }
+ return nlen;
+ } // end of CheckWrite
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBFMT class. */
+/***********************************************************************/
+TDBFMT::TDBFMT(PGLOBAL g, PTDBFMT tdbp) : TDBCSV(g, tdbp)
+ {
+ FldFormat = tdbp->FldFormat;
+ To_Fld = tdbp->To_Fld;
+ FmtTest = tdbp->FmtTest;
+ Linenum = tdbp->Linenum;
+ } // end of TDBFMT copy constructor
+
+// Method
+PTDB TDBFMT::Clone(PTABS t)
+ {
+ PTDB tp;
+ PCSVCOL cp1, cp2;
+//PFMTCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBFMT(g, this);
+
+ for (cp1 = (PCSVCOL)Columns; cp1; cp1 = (PCSVCOL)cp1->GetNext()) {
+//for (cp1 = (PFMTCOL)Columns; cp1; cp1 = (PFMTCOL)cp1->GetNext()) {
+ cp2 = new(g) CSVCOL(cp1, tp); // Make a copy
+// cp2 = new(g) FMTCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Allocate FMT column description block. */
+/***********************************************************************/
+PCOL TDBFMT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) CSVCOL(g, cdp, this, cprec, n);
+//return new(g) FMTCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* FMT EstimatedLength. Returns an estimated minimum line length. */
+/* The big problem here is how can we astimated that minimum ? */
+/***********************************************************************/
+int TDBFMT::EstimatedLength(void)
+ {
+ // This is rather stupid !!!
+ return ((PDOSDEF)To_Def)->GetEnding() + (int)((Lrecl / 10) + 1);
+ } // end of EstimatedLength
+
+/***********************************************************************/
+/* FMT Access Method opening routine. */
+/***********************************************************************/
+bool TDBFMT::OpenDB(PGLOBAL g)
+ {
+ Linenum = 0;
+
+ if (Mode == MODE_INSERT || Mode == MODE_UPDATE) {
+ sprintf(g->Message, MSG(FMT_WRITE_NIY), "FMT");
+ return true; // NIY
+ } // endif Mode
+
+ if (Use != USE_OPEN && Columns) {
+ // Make the formats used to read records
+ PSZ pfm;
+ int i, n;
+ PCSVCOL colp;
+ PCOLDEF cdp;
+ PDOSDEF tdp = (PDOSDEF)To_Def;
+
+ for (colp = (PCSVCOL)Columns; colp; colp = (PCSVCOL)colp->Next)
+ if (!colp->IsSpecial() && !colp->IsVirtual()) // a true column
+ Fields = MY_MAX(Fields, (int)colp->Fldnum);
+
+ if (Columns)
+ Fields++; // Fldnum was 0 based
+
+ To_Fld = PlugSubAlloc(g, NULL, Lrecl + 1);
+ FldFormat = (PSZ*)PlugSubAlloc(g, NULL, sizeof(PSZ) * Fields);
+ memset(FldFormat, 0, sizeof(PSZ) * Fields);
+ FmtTest = (int*)PlugSubAlloc(g, NULL, sizeof(int) * Fields);
+ memset(FmtTest, 0, sizeof(int) * Fields);
+
+ // Get the column formats
+ for (cdp = tdp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!cdp->IsSpecial() && !cdp->IsVirtual()
+ && (i = cdp->GetOffset() - 1) < Fields) {
+ if (!(pfm = cdp->GetFmt())) {
+ sprintf(g->Message, MSG(NO_FLD_FORMAT), i + 1, Name);
+ return true;
+ } // endif pfm
+
+ // Roughly check the Fmt format
+ if ((n = strlen(pfm) - 2) < 4) {
+ sprintf(g->Message, MSG(BAD_FLD_FORMAT), i + 1, Name);
+ return true;
+ } // endif n
+
+ FldFormat[i] = (PSZ)PlugSubAlloc(g, NULL, n + 5);
+ strcpy(FldFormat[i], pfm);
+
+ if (!strcmp(pfm + n, "%m")) {
+ // This is a field that can be missing. Flag it so it can
+ // be handled with special processing.
+ FldFormat[i][n+1] = 'n'; // To have sscanf normal processing
+ FmtTest[i] = 2;
+ } else if (i+1 < Fields && strcmp(pfm + n, "%n")) {
+ // There are trailing characters after the field contents
+ // add a marker for the next field start position.
+ strcat(FldFormat[i], "%n");
+ FmtTest[i] = 1;
+ } // endif's
+
+ } // endif i
+
+ } // endif Use
+
+ return TDBCSV::OpenDB(g);
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadBuffer: Physical read routine for the FMT access method. */
+/***********************************************************************/
+int TDBFMT::ReadBuffer(PGLOBAL g)
+ {
+ int i, len, n, deb, fin, nwp, pos = 0, rc;
+ bool bad = false;
+
+ if ((rc = Txfp->ReadBuffer(g)) != RC_OK || !Fields)
+ return rc;
+ else
+ ++Linenum;
+
+ if (trace(2))
+ htrc("FMT: Row %d is '%s' rc=%d\n", Linenum, To_Line, rc);
+
+ // Find the offsets and lengths of the columns for this row
+ for (i = 0; i < Fields; i++) {
+ if (!bad) {
+ deb = fin = -1;
+
+ if (!FldFormat[i]) {
+ n = 0;
+ } else if (FmtTest[i] == 1) {
+ nwp = -1;
+ n = sscanf(To_Line + pos, FldFormat[i], &deb, To_Fld, &fin, &nwp);
+ } else {
+ n = sscanf(To_Line + pos, FldFormat[i], &deb, To_Fld, &fin);
+
+ if (n != 1 && (deb >= 0 || i == Fields - 1) && FmtTest[i] == 2) {
+ // Missing optional field, not an error
+ n = 1;
+
+ if (i == Fields - 1)
+ fin = deb = 0;
+ else
+ fin = deb;
+
+ } // endif n
+
+ nwp = fin;
+ } // endif i
+
+ if (n != 1 || deb < 0 || fin < 0 || nwp < 0) {
+ // This is to avoid a very strange sscanf bug occuring
+ // with fields that ends with a null character.
+ // This bug causes subsequent sscanf to return in error,
+ // so next lines are not parsed correctly.
+ sscanf("a", "%*c"); // Seems to reset things Ok
+
+ if (CheckErr()) {
+ sprintf(g->Message, MSG(BAD_LINEFLD_FMT), Linenum, i + 1, Name);
+ return RC_FX;
+ } else if (Accept)
+ bad = true;
+ else
+ return RC_NF;
+
+ } // endif n...
+
+ } // endif !bad
+
+ if (!bad) {
+ Offset[i] = pos + deb;
+ len = fin - deb;
+ } else {
+ nwp = 0;
+ Offset[i] = pos;
+ len = 0;
+ } // endif bad
+
+// if (Mode != MODE_UPDATE)
+ Fldlen[i] = len;
+// else if (len > Fldlen[i]) {
+// sprintf(g->Message, MSG(FIELD_TOO_LONG), i+1, To_Tdb->RowNumber(g));
+// return RC_FX;
+// } else {
+// strncpy(Field[i], To_Line + pos, len);
+// Field[i][len] = '\0';
+// } // endif Mode
+
+ pos += nwp;
+ } // endfor i
+
+ if (bad)
+ Nerr++;
+ else
+ sscanf("a", "%*c"); // Seems to reset things Ok
+
+ return rc;
+ } // end of ReadBuffer
+
+/***********************************************************************/
+/* Data Base write routine FMT file access method. */
+/***********************************************************************/
+int TDBFMT::WriteDB(PGLOBAL g)
+ {
+ sprintf(g->Message, MSG(FMT_WRITE_NIY), "FMT");
+ return RC_FX; // NIY
+ } // end of WriteDB
+
+// ------------------------ CSVCOL functions ----------------------------
+
+/***********************************************************************/
+/* CSVCOL public constructor */
+/***********************************************************************/
+CSVCOL::CSVCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : DOSCOL(g, cdp, tdbp, cprec, i, "CSV")
+ {
+ Fldnum = Deplac - 1;
+ Deplac = 0;
+ } // end of CSVCOL constructor
+
+/***********************************************************************/
+/* CSVCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+CSVCOL::CSVCOL(CSVCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
+ {
+ Fldnum = col1->Fldnum;
+ } // end of CSVCOL copy constructor
+
+/***********************************************************************/
+/* VarSize: This function tells UpdateDB whether or not the block */
+/* optimization file must be redone if this column is updated, even */
+/* it is not sorted or clustered. This applies to a blocked table, */
+/* because if it is updated using a temporary file, the block size */
+/* may be modified. */
+/***********************************************************************/
+bool CSVCOL::VarSize(void)
+ {
+ PTXF txfp = ((PTDBCSV)To_Tdb)->Txfp;
+
+ if (txfp->IsBlocked() && txfp->GetUseTemp())
+ // Blocked table using a temporary file
+ return true;
+ else
+ return false;
+
+ } // end VarSize
+
+/***********************************************************************/
+/* ReadColumn: call DOSCOL::ReadColumn after having set the offet */
+/* and length of the field to read as calculated by TDBCSV::ReadDB. */
+/***********************************************************************/
+void CSVCOL::ReadColumn(PGLOBAL g)
+ {
+ int rc;
+ PTDBCSV tdbp = (PTDBCSV)To_Tdb;
+
+ /*********************************************************************/
+ /* If physical reading of the line was deferred, do it now. */
+ /*********************************************************************/
+ if (!tdbp->IsRead())
+ if ((rc = tdbp->ReadBuffer(g)) != RC_OK) {
+ if (rc == RC_EF)
+ sprintf(g->Message, MSG(INV_DEF_READ), rc);
+
+ throw 34;
+ } // endif
+
+ if (tdbp->Mode != MODE_UPDATE) {
+ int colen = Long; // Column length
+
+ // Set the field offset and length for this row
+ Deplac = tdbp->Offset[Fldnum]; // Field offset
+ Long = tdbp->Fldlen[Fldnum]; // Field length
+
+ if (trace(2))
+ htrc("CSV ReadColumn %s Fldnum=%d offset=%d fldlen=%d\n",
+ Name, Fldnum, Deplac, Long);
+
+ if (Long > colen && tdbp->CheckErr()) {
+ Long = colen; // Restore column length
+ sprintf(g->Message, MSG(FLD_TOO_LNG_FOR),
+ Fldnum + 1, Name, To_Tdb->RowNumber(g), tdbp->GetFile(g));
+ throw 34;
+ } // endif Long
+
+ // Now do the reading
+ DOSCOL::ReadColumn(g);
+
+ // Restore column length
+ Long = colen;
+ } else { // Mode Update
+ // Field have been copied in TDB Field array
+ PSZ fp = tdbp->Field[Fldnum];
+
+ if (Dsp)
+ for (int i = 0; fp[i]; i++)
+ if (fp[i] == Dsp)
+ fp[i] = '.';
+
+ Value->SetValue_psz(fp);
+
+ // Set null when applicable
+ if (Nullable)
+ Value->SetNull(Value->IsZero());
+
+ } // endif Mode
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: The column is written in TDBCSV matching Field. */
+/***********************************************************************/
+void CSVCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p;
+ int n, flen;
+ PTDBCSV tdbp = (PTDBCSV)To_Tdb;
+
+ if (trace(2))
+ htrc("CSV WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status);
+
+ flen = GetLength();
+
+ if (trace(2))
+ htrc("Lrecl=%d Long=%d field=%d coltype=%d colval=%p\n",
+ tdbp->Lrecl, Long, flen, Buf_Type, Value);
+
+ /*********************************************************************/
+ /* Check whether the new value has to be converted to Buf_Type. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ /*********************************************************************/
+ /* Get the string representation of the column value. */
+ /*********************************************************************/
+ p = Value->GetCharString(Buf);
+ n = strlen(p);
+
+ if (trace(2))
+ htrc("new length(%p)=%d\n", p, n);
+
+ if (n > flen) {
+ sprintf(g->Message, MSG(BAD_FLD_LENGTH), Name, p, n,
+ tdbp->RowNumber(g), tdbp->GetFile(g));
+ throw 34;
+ } else if (Dsp)
+ for (int i = 0; p[i]; i++)
+ if (p[i] == '.')
+ p[i] = Dsp;
+
+ if (trace(2))
+ htrc("buffer=%s\n", p);
+
+ /*********************************************************************/
+ /* Updating must be done also during the first pass so writing the */
+ /* updated record can be checked for acceptable record length. */
+ /*********************************************************************/
+ if (Fldnum < 0) {
+ // This can happen for wrong offset value in XDB files
+ sprintf(g->Message, MSG(BAD_FIELD_RANK), Fldnum + 1, Name);
+ throw 34;
+ } else
+ strncpy(tdbp->Field[Fldnum], p, flen);
+
+ if (trace(2))
+ htrc(" col written: '%s'\n", p);
+
+ } // end of WriteColumn
+
+/* ---------------------------TDBCCL class --------------------------- */
+
+/***********************************************************************/
+/* TDBCCL class constructor. */
+/***********************************************************************/
+TDBCCL::TDBCCL(PCSVDEF tdp) : TDBCAT(tdp)
+{
+ Topt = tdp->GetTopt();
+} // end of TDBCCL constructor
+
+/***********************************************************************/
+/* GetResult: Get the list the CSV file columns. */
+/***********************************************************************/
+PQRYRES TDBCCL::GetResult(PGLOBAL g)
+ {
+ return CSVColumns(g, ((PTABDEF)To_Def)->GetPath(), Topt, false);
+ } // end of GetResult
+
+/* ------------------------ End of TabFmt ---------------------------- */
diff --git a/storage/connect/tabfmt.h b/storage/connect/tabfmt.h
new file mode 100644
index 00000000..10f0757c
--- /dev/null
+++ b/storage/connect/tabfmt.h
@@ -0,0 +1,191 @@
+/*************** TabFmt H Declares Source Code File (.H) ***************/
+/* Name: TABFMT.H Version 2.5 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2001-2016 */
+/* */
+/* This file contains the CSV and FMT classes declares. */
+/***********************************************************************/
+#include "xtable.h" // Base class declares
+#include "tabdos.h"
+
+typedef class TDBFMT *PTDBFMT;
+
+/***********************************************************************/
+/* Functions used externally. */
+/***********************************************************************/
+DllExport PQRYRES CSVColumns(PGLOBAL g, PCSZ dp, PTOS topt, bool info);
+
+/***********************************************************************/
+/* CSV table. */
+/***********************************************************************/
+class DllExport CSVDEF : public DOSDEF { /* Logical table description */
+ friend class TDBCSV;
+ friend class TDBCCL;
+ friend PQRYRES CSVColumns(PGLOBAL, PCSZ, PTOS, bool);
+public:
+ // Constructor
+ CSVDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "CSV";}
+ char GetSep(void) {return Sep;}
+ char GetQot(void) {return Qot;}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE mode);
+
+ protected:
+ // Members
+ bool Fmtd; /* true for formatted files */
+//bool Accept; /* true if wrong lines are accepted */
+ bool Header; /* true if first line contains headers */
+//int Maxerr; /* Maximum number of bad records */
+ int Quoted; /* Quoting level for quoted fields */
+ char Sep; /* Separator for standard CSV files */
+ char Qot; /* Character for quoted strings */
+ }; // end of CSVDEF
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* that are CSV files with columns separated by the Sep character. */
+/***********************************************************************/
+class DllExport TDBCSV : public TDBDOS {
+ friend class CSVCOL;
+ friend class MAPFAM;
+ friend PQRYRES CSVColumns(PGLOBAL, PCSZ, PTOS, bool);
+public:
+ // Constructor
+ TDBCSV(PCSVDEF tdp, PTXF txfp);
+ TDBCSV(PGLOBAL g, PTDBCSV tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_CSV;}
+ virtual PTDB Duplicate(PGLOBAL g)
+ {return (PTDB)new(g) TDBCSV(g, this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+//virtual bool IsUsingTemp(PGLOBAL g);
+ virtual int GetBadLines(void) {return (int)Nerr;}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int CheckWrite(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g); // Physical file read
+
+ // Specific routines
+ virtual int EstimatedLength(void);
+ virtual bool SkipHeader(PGLOBAL g);
+ virtual bool CheckErr(void);
+
+ protected:
+ virtual bool PrepareWriting(PGLOBAL g);
+
+ // Members
+ PSZ *Field; // Field to write to current line
+ int *Offset; // Column offsets for current record
+ int *Fldlen; // Column field length for current record
+ bool *Fldtyp; // true for numeric fields
+ int Fields; // Number of fields to handle
+ int Nerr; // Number of bad records
+ int Maxerr; // Maximum number of bad records
+ int Quoted; // Quoting level for quoted fields
+ bool Accept; // true if bad lines are accepted
+ bool Header; // true if first line contains column headers
+ char Sep; // Separator
+ char Qot; // Quoting character
+ }; // end of class TDBCSV
+
+/***********************************************************************/
+/* Class CSVCOL: CSV access method column descriptor. */
+/* This A.M. is used for Comma Separated V(?) files. */
+/***********************************************************************/
+class DllExport CSVCOL : public DOSCOL {
+ friend class TDBCSV;
+ friend class TDBFMT;
+ public:
+ // Constructors
+ CSVCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
+ CSVCOL(CSVCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType() {return TYPE_AM_CSV;}
+
+ // Methods
+ virtual bool VarSize(void);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ CSVCOL(void) {}
+
+ // Members
+ int Fldnum; // Field ordinal number (0 based)
+ }; // end of class CSVCOL
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* whose record format is described by a Format keyword. */
+/***********************************************************************/
+class DllExport TDBFMT : public TDBCSV {
+ friend class CSVCOL;
+//friend class FMTCOL;
+ public:
+ // Standard constructor
+ TDBFMT(PCSVDEF tdp, PTXF txfp) : TDBCSV(tdp, txfp)
+ {FldFormat = NULL; To_Fld = NULL; FmtTest = NULL; Linenum = 0;}
+
+ // Copy constructor
+ TDBFMT(PGLOBAL g, PTDBFMT tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_FMT;}
+ virtual PTDB Duplicate(PGLOBAL g)
+ {return (PTDB)new(g) TDBFMT(g, this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+//virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+//virtual int CheckWrite(PGLOBAL g);
+ virtual int ReadBuffer(PGLOBAL g); // Physical file read
+
+ // Specific routines
+ virtual int EstimatedLength(void);
+
+ protected:
+ virtual bool PrepareWriting(PGLOBAL g)
+ {sprintf(g->Message, MSG(TABLE_READ_ONLY), "FMT"); return true;}
+
+ // Members
+ PSZ *FldFormat; // Field read format
+ void *To_Fld; // To field test buffer
+ int *FmtTest; // Test on ending by %n or %m
+ int Linenum; // Last read line
+ }; // end of class TDBFMT
+
+/***********************************************************************/
+/* This is the class declaration for the CSV catalog table. */
+/***********************************************************************/
+class DllExport TDBCCL : public TDBCAT {
+ public:
+ // Constructor
+ TDBCCL(PCSVDEF tdp);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PTOS Topt;
+}; // end of class TDBCCL
+
+/* ------------------------- End of TabFmt.H ------------------------- */
diff --git a/storage/connect/tabjdbc.cpp b/storage/connect/tabjdbc.cpp
new file mode 100644
index 00000000..1268bcfd
--- /dev/null
+++ b/storage/connect/tabjdbc.cpp
@@ -0,0 +1,1328 @@
+/************* TabJDBC C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: TABJDBC */
+/* ------------- */
+/* Version 1.3 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2016-2019 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TABJDBC class DB execution routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABJDBC.CPP - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABJDBC.H - TABJDBC classes declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#define MYSQL_SERVER 1
+#include "my_global.h"
+#include "sql_class.h"
+#include "sql_servers.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#include <sqltypes.h>
+#else
+#if defined(UNIX)
+#include <errno.h>
+#define NODW
+#include "osutil.h"
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* kindex.h is kindex header that also includes tabdos.h. */
+/* tabJDBC.h is header containing the TABJDBC class declarations. */
+/* JDBConn.h is header containing JDBC connection declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "mycat.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "tabjdbc.h"
+#include "tabmul.h"
+#include "tabcol.h"
+#include "valblk.h"
+#include "ha_connect.h"
+
+#include "sql_string.h"
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+// int num_read, num_there, num_eq[2], num_nf; // Statistics
+extern int num_read, num_there, num_eq[2]; // Statistics
+
+/***********************************************************************/
+/* External function. */
+/***********************************************************************/
+bool ExactInfo(void);
+#if defined(DEVELOPMENT)
+extern char *GetUserVariable(PGLOBAL g, const uchar *varname);
+#endif // DEVELOPMENT
+
+/* -------------------------- Class JDBCDEF -------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+JDBCDEF::JDBCDEF(void)
+{
+ Driver = Url = Wrapname = NULL;
+} // end of JDBCDEF constructor
+
+/***********************************************************************/
+/* Called on table construction. */
+/***********************************************************************/
+bool JDBCDEF::SetParms(PJPARM sjp)
+{
+ sjp->Url= Url;
+ sjp->User= Username;
+ sjp->Pwd= Password;
+//sjp->Properties = Prop;
+ return true;
+} // end of SetParms
+
+/***********************************************************************/
+/* Parse connection string */
+/* */
+/* SYNOPSIS */
+/* ParseURL() */
+/* Url The connection string to parse */
+/* */
+/* DESCRIPTION */
+/* This is used to set the Url in case a wrapper server as been */
+/* specified. This is rather experimental yet. */
+/* */
+/* RETURN VALUE */
+/* RC_OK Url was a true URL */
+/* RC_NF Url was a server name/table */
+/* RC_FX Error */
+/* */
+/***********************************************************************/
+int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b)
+{
+ if (strncmp(url, "jdbc:", 5)) {
+ PSZ p;
+
+ // No "jdbc:" in connection string. Must be a straight
+ // "server" or "server/table"
+ // ok, so we do a little parsing, but not completely!
+ if ((p = strchr(url, '/'))) {
+ // If there is a single '/' in the connection string,
+ // this means the user is specifying a table name
+ *p++= '\0';
+
+ // there better not be any more '/'s !
+ if (strchr(p, '/'))
+ return RC_FX;
+
+ Tabname = p;
+ } // endif
+
+ if (trace(1))
+ htrc("server: %s Tabname: %s", url, Tabname);
+
+ // Now make the required URL
+ FOREIGN_SERVER *server, server_buffer;
+
+ // get_server_by_name() clones the server if exists
+ if (!(server= get_server_by_name(current_thd->mem_root, url, &server_buffer))) {
+ sprintf(g->Message, "Server %s does not exist!", url);
+ return RC_FX;
+ } // endif server
+
+#if defined(DEVELOPMENT)
+ if (*server->host == '@') {
+ Url = GetUserVariable(g, (const uchar*)&server->host[1]);
+ } else
+#endif // 0
+ if (strncmp(server->host, "jdbc:", 5)) {
+ // Now make the required URL
+ Url = (PSZ)PlugSubAlloc(g, NULL, 0);
+ strcat(strcpy(Url, "jdbc:"), server->scheme);
+ strcat(strcat(Url, "://"), server->host);
+
+ if (server->port) {
+ char buf[16];
+
+ sprintf(buf, "%ld", server->port);
+ strcat(strcat(Url, ":"), buf);
+ } // endif port
+
+ if (server->db)
+ strcat(strcat(Url, "/"), server->db);
+
+ PlugSubAlloc(g, NULL, strlen(Url) + 1);
+ } else // host is a URL
+ Url = PlugDup(g, server->host);
+
+ if (!Tabschema && server->db)
+ Tabschema = PlugDup(g, server->db);
+
+ if (!Username && server->username)
+ Username = PlugDup(g, server->username);
+
+ if (!Password && server->password)
+ Password = PlugDup(g, server->password);
+
+ Driver = PlugDup(g, GetListOption(g, "Driver", server->owner, NULL));
+ Wrapname = PlugDup(g, GetListOption(g, "Wrapper", server->owner, NULL));
+ Memory = atoi(GetListOption(g, "Memory", server->owner, "0"));
+ return RC_NF;
+ } // endif
+
+ // Url was a JDBC URL, nothing to do
+ return RC_OK;
+} // end of ParseURL
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from JDBC file. */
+/***********************************************************************/
+bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ int rc = RC_OK;
+
+ if (EXTDEF::DefineAM(g, am, poff))
+ return true;
+
+ Desc = Url = GetStringCatInfo(g, "Connect", NULL);
+
+ if (!Url && !Catfunc) {
+ // Look in the option list (deprecated)
+ Url = GetStringCatInfo(g, "Url", NULL);
+
+ if (!Url) {
+ sprintf(g->Message, "Missing URL for JDBC table %s", Name);
+ return true;
+ } // endif Url
+
+ } // endif Connect
+
+ if (Url)
+ if ((rc = ParseURL(g, Url)) == RC_FX) {
+ sprintf(g->Message, "Wrong JDBC URL %s", Url);
+ return true;
+ } // endif rc
+
+ // Default values may have been set in ParseURL
+ Memory = GetIntCatInfo("Memory", Memory);
+ Driver = GetStringCatInfo(g, "Driver", Driver);
+ Wrapname = GetStringCatInfo(g, "Wrapper", Wrapname);
+ return false;
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB JDBCDEF::GetTable(PGLOBAL g, MODE m)
+{
+ PTDB tdbp = NULL;
+
+ /*********************************************************************/
+ /* Allocate a TDB of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*********************************************************************/
+ if (Xsrc)
+ tdbp = new(g)TDBXJDC(this);
+ else switch (Catfunc) {
+ case FNC_COL:
+ tdbp = new(g)TDBJDBCL(this);
+ break;
+#if 0
+ case FNC_DSN:
+ tdbp = new(g)TDBJSRC(this);
+ break;
+#endif // 0
+ case FNC_TABLE:
+ tdbp = new(g)TDBJTB(this);
+ break;
+ case FNC_DRIVER:
+ tdbp = new(g)TDBJDRV(this);
+ break;
+ default:
+ tdbp = new(g)TDBJDBC(this);
+
+ if (Multiple == 1)
+ tdbp = new(g)TDBMUL(tdbp);
+ else if (Multiple == 2)
+ strcpy(g->Message, "NO_JDBC_MUL");
+
+ } // endswitch Catfunc
+
+ return tdbp;
+} // end of GetTable
+
+/***********************************************************************/
+/* The MySQL and MariaDB JDBC drivers return by default a result set */
+/* containing the entire result of the executed query. This can be an */
+/* issue for big tables and memory error can occur. An alternative is */
+/* to use streaming (reading one row at a time) but to specify this, */
+/* a fech size of the integer min value must be send to the driver. */
+/***********************************************************************/
+int JDBCPARM::CheckSize(int rows)
+{
+ if (Url && rows == 1) {
+ // Are we connected to a MySQL JDBC connector?
+ bool b = (!strncmp(Url, "jdbc:mysql:", 11) ||
+ !strncmp(Url, "jdbc:mariadb:", 13));
+ return b ? INT_MIN32 : rows;
+ } else
+ return rows;
+
+} // end of CheckSize
+
+/* -------------------------- Class TDBJDBC -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBJDBC class. */
+/***********************************************************************/
+TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBEXT(tdp)
+{
+ Jcp = NULL;
+ Cnp = NULL;
+
+ if (tdp) {
+ Ops.Driver = tdp->Driver;
+ Ops.Url = tdp->Url;
+ Wrapname = tdp->Wrapname;
+ Ops.User = tdp->Username;
+ Ops.Pwd = tdp->Password;
+ Ops.Scrollable = tdp->Scrollable;
+ } else {
+ Wrapname = NULL;
+ Ops.Driver = NULL;
+ Ops.Url = NULL;
+ Ops.User = NULL;
+ Ops.Pwd = NULL;
+ Ops.Scrollable = false;
+ } // endif tdp
+
+ Prepared = false;
+ Werr = false;
+ Rerr = false;
+ Ops.Fsize = Ops.CheckSize(Rows);
+} // end of TDBJDBC standard constructor
+
+TDBJDBC::TDBJDBC(PTDBJDBC tdbp) : TDBEXT(tdbp)
+{
+ Jcp = tdbp->Jcp; // is that right ?
+ Cnp = tdbp->Cnp;
+ Wrapname = tdbp->Wrapname;
+ Ops = tdbp->Ops;
+ Prepared = tdbp->Prepared;
+ Werr = tdbp->Werr;
+ Rerr = tdbp->Rerr;
+} // end of TDBJDBC copy constructor
+
+// Method
+PTDB TDBJDBC::Clone(PTABS t)
+{
+ PTDB tp;
+ PJDBCCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g)TDBJDBC(this);
+
+ for (cp1 = (PJDBCCOL)Columns; cp1; cp1 = (PJDBCCOL)cp1->GetNext()) {
+ cp2 = new(g)JDBCCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+} // end of Clone
+
+/***********************************************************************/
+/* Allocate JDBC column description block. */
+/***********************************************************************/
+PCOL TDBJDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ return new(g)JDBCCOL(cdp, this, cprec, n);
+} // end of MakeCol
+
+/***********************************************************************/
+/* MakeInsert: make the Insert statement used with JDBC connection. */
+/***********************************************************************/
+bool TDBJDBC::MakeInsert(PGLOBAL g)
+{
+ PCSZ schmp = NULL;
+ char *catp = NULL, buf[NAM_LEN * 3];
+ int len = 0;
+ uint pos;
+ bool b = false;
+ // PTABLE tablep = To_Table;
+ PCOL colp;
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->IsSpecial()) {
+ strcpy(g->Message, "No JDBC special columns");
+ return true;
+ } else {
+ // Column name can be encoded in UTF-8
+ Decode(colp->GetName(), buf, sizeof(buf));
+ len += (strlen(buf) + 6); // comma + quotes + valist
+ ((PEXTCOL)colp)->SetRank(++Nparm);
+ } // endif colp
+
+ // Below 32 is enough to contain the fixed part of the query
+ if (Catalog && *Catalog)
+ catp = Catalog;
+
+ if (catp)
+ len += strlen(catp) + 1;
+
+ //if (tablep->GetSchema())
+ // schmp = (char*)tablep->GetSchema();
+ //else
+ if (Schema && *Schema)
+ schmp = Schema;
+
+ if (schmp)
+ len += strlen(schmp) + 1;
+
+ // Table name can be encoded in UTF-8
+ Decode(TableName, buf, sizeof(buf));
+ len += (strlen(buf) + 32);
+ Query = new(g)STRING(g, len, "INSERT INTO ");
+
+ if (catp) {
+ Query->Append(catp);
+
+ if (schmp) {
+ Query->Append('.');
+ Query->Append(schmp);
+ } // endif schmp
+
+ Query->Append('.');
+ } else if (schmp) {
+ Query->Append(schmp);
+ Query->Append('.');
+ } // endif schmp
+
+ if (Quote) {
+ // Put table name between identifier quotes in case in contains blanks
+ Query->Append(Quote);
+ Query->Append(buf);
+ Query->Append(Quote);
+ } else
+ Query->Append(buf);
+
+ Query->Append('(');
+
+ for (colp = Columns; colp; colp = colp->GetNext()) {
+ if (b)
+ Query->Append(", ");
+ else
+ b = true;
+
+ // Column name can be in UTF-8 encoding
+ Decode(colp->GetName(), buf, sizeof(buf));
+
+ if (Quote) {
+ // Put column name between identifier quotes in case in contains blanks
+ Query->Append(Quote);
+ Query->Append(buf);
+ Query->Append(Quote);
+ } else
+ Query->Append(buf);
+
+ } // endfor colp
+
+ if ((Query->Append(") VALUES ("))) {
+ strcpy(g->Message, "MakeInsert: Out of memory");
+ return true;
+ } else // in case prepared statement fails
+ pos = Query->GetLength();
+
+ // Make prepared statement
+ for (int i = 0; i < Nparm; i++)
+ Query->Append("?,");
+
+ if (Query->IsTruncated()) {
+ strcpy(g->Message, "MakeInsert: Out of memory");
+ return true;
+ } else
+ Query->RepLast(')');
+
+ // Now see if we can use prepared statement
+ if (Jcp->PrepareSQL(Query->GetStr()))
+ Query->Truncate(pos); // Restore query to not prepared
+ else
+ Prepared = true;
+
+ if (trace(33))
+ htrc("Insert=%s\n", Query->GetStr());
+
+ return false;
+} // end of MakeInsert
+
+/***********************************************************************/
+/* JDBC Set Parameter function. */
+/***********************************************************************/
+bool TDBJDBC::SetParameters(PGLOBAL g)
+{
+ PJDBCCOL colp;
+
+ for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next)
+ if (Jcp->SetParam(colp))
+ return true;
+
+ return false;
+} // end of SetParameters
+
+/***********************************************************************/
+/* ResetSize: call by TDBMUL when calculating size estimate. */
+/***********************************************************************/
+void TDBJDBC::ResetSize(void)
+{
+ MaxSize = -1;
+
+ if (Jcp && Jcp->IsOpen())
+ Jcp->Close();
+
+} // end of ResetSize
+
+/***********************************************************************/
+/* JDBC Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBJDBC::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return (Mode == MODE_ANY && !Srcdef) ? 1 : 0;
+
+#if 0
+ if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) {
+ // Info command, we must return the exact table row number
+ char qry[96], tbn[64];
+ JDBConn *jcp = new(g)JDBConn(g, this);
+
+ if (jcp->Open(&Ops) == RC_FX)
+ return -1;
+
+ // Table name can be encoded in UTF-8
+ Decode(TableName, tbn, sizeof(tbn));
+ strcpy(qry, "SELECT COUNT(*) FROM ");
+
+ if (Quote)
+ strcat(strcat(strcat(qry, Quote), tbn), Quote);
+ else
+ strcat(qry, tbn);
+
+ // Allocate a Count(*) column (must not use the default constructor)
+ Cnp = new(g)JDBCCOL;
+ Cnp->InitValue(g);
+
+ if ((Cardinal = jcp->GetResultSize(qry, Cnp)) < 0)
+ return -3;
+
+ jcp->Close();
+ } else
+#endif // 0
+ Cardinal = 10; // To make MariaDB happy
+
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* JDBC Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool TDBJDBC::OpenDB(PGLOBAL g)
+{
+ bool rc = true;
+
+ if (trace(1))
+ htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ if (Mode == MODE_READ || Mode == MODE_READX) {
+ /*****************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*****************************************************************/
+ if (Memory == 1) {
+ if ((Qrp = Jcp->AllocateResult(g, this)))
+ Memory = 2; // Must be filled
+ else
+ Memory = 0; // Allocation failed, don't use it
+
+ } else if (Memory == 2)
+ Memory = 3; // Ok to use memory result
+
+ if (Memory < 3) {
+ // Method will depend on cursor type
+ if ((Rbuf = Query ? Jcp->Rewind(Query->GetStr()) : 0) < 0)
+ {
+ if (Mode != MODE_READX) {
+ Jcp->Close();
+ return true;
+ } else
+ Rbuf = 0;
+ }
+
+ } else
+ Rbuf = Qrp->Nblin;
+
+ CurNum = 0;
+ Fpos = 0;
+ Curpos = 1;
+ } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ // new update coming from a trigger or procedure
+ Query = NULL;
+ SetCondFil(NULL);
+ Qrystr = To_Def->GetStringCatInfo(g, "Query_String", "?");
+ } else { //if (Mode == MODE_INSERT)
+ } // endif Mode
+
+ return false;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open an JDBC connection for this table. */
+ /* Note: this may not be the proper way to do. Perhaps it is better */
+ /* to test whether a connection is already open for this datasource */
+ /* and if so to allocate just a new result set. But this only for */
+ /* drivers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Jcp)
+ Jcp = new(g)JDBConn(g, Wrapname);
+ else if (Jcp->IsOpen())
+ Jcp->Close();
+
+ if (Jcp->Connect(&Ops))
+ return true;
+ else if (Quoted)
+ Quote = Jcp->GetQuoteChar();
+
+ if (Mode != MODE_READ && Mode != MODE_READX)
+ if (Jcp->SetUUID(g, this))
+ PushWarning(g, this, 1);
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Make the command and allocate whatever is used for getting results*/
+ /*********************************************************************/
+ if (Mode == MODE_READ || Mode == MODE_READX) {
+ if (Memory > 1 && !Srcdef) {
+ int n;
+
+ if (!MakeSQL(g, true)) {
+ // Allocate a Count(*) column
+ Cnp = new(g)JDBCCOL;
+ Cnp->InitValue(g);
+
+ if ((n = Jcp->GetResultSize(Query->GetStr(), Cnp)) < 0) {
+ char* msg = PlugDup(g, g->Message);
+
+ sprintf(g->Message, "Get result size: %s (rc=%d)", msg, n);
+ return true;
+ } else if (n) {
+ Jcp->m_Rows = n;
+
+ if ((Qrp = Jcp->AllocateResult(g, this)))
+ Memory = 2; // Must be filled
+ else {
+ strcpy(g->Message, "Result set memory allocation failed");
+ return true;
+ } // endif n
+
+ } else // Void result
+ Memory = 0;
+
+ Jcp->m_Rows = 0;
+ } else
+ return true;
+
+ } // endif Memory
+
+ if (!(rc = MakeSQL(g, false))) {
+// for (PJDBCCOL colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->GetNext())
+// if (!colp->IsSpecial())
+// colp->AllocateBuffers(g, Rows);
+
+ rc = (Mode == MODE_READ)
+ ? (Jcp->ExecuteQuery(Query->GetStr()) != RC_OK)
+ : false;
+ } // endif rc
+
+ } else if (Mode == MODE_INSERT) {
+#if 0
+ if (!(rc = MakeInsert(g))) {
+ if (Nparm != Jcp->PrepareSQL(Query->GetStr())) {
+ strcpy(g->Message, MSG(PARM_CNT_MISS));
+ rc = true;
+ } else
+ rc = BindParameters(g);
+
+ } // endif rc
+#endif // 0
+ rc = MakeInsert(g);
+ } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ rc = false; // wait for CheckCond before calling MakeCommand(g);
+ } else
+ sprintf(g->Message, "Invalid mode %d", Mode);
+
+ if (rc) {
+ Jcp->Close();
+ return true;
+ } // endif rc
+
+ /*********************************************************************/
+ /* Reset statistics values. */
+ /*********************************************************************/
+ num_read = num_there = num_eq[0] = num_eq[1] = 0;
+ return false;
+} // end of OpenDB
+
+#if 0
+/***********************************************************************/
+/* GetRecpos: return the position of last read record. */
+/***********************************************************************/
+int TDBJDBC::GetRecpos(void)
+{
+ return Fpos;
+} // end of GetRecpos
+#endif // 0
+
+/***********************************************************************/
+/* SetRecpos: set the position of next read record. */
+/***********************************************************************/
+bool TDBJDBC::SetRecpos(PGLOBAL g, int recpos)
+{
+ if (Jcp->m_Full) {
+ Fpos = 0;
+ CurNum = 1;
+ } else if (Memory == 3) {
+ Fpos = 0;
+ CurNum = recpos;
+ } else if (Ops.Scrollable) {
+ // Is new position in the current row set?
+ if (recpos > 0 && recpos <= Rbuf) {
+ CurNum = recpos;
+ Fpos = recpos;
+ } else {
+ strcpy(g->Message, "Scrolling out of row set NIY");
+ return true;
+ } // endif recpos
+
+ } else {
+ strcpy(g->Message, "This action requires a scrollable cursor");
+ return true;
+ } // endif's
+
+ // Indicate the table position was externally set
+ Placed = true;
+ return false;
+} // end of SetRecpos
+
+/***********************************************************************/
+/* Data Base indexed read routine for JDBC access method. */
+/***********************************************************************/
+bool TDBJDBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
+{
+ char c = Quote ? *Quote : 0;
+ int rc, oldlen = Query->GetLength();
+ PHC hc = To_Def->GetHandler();
+
+ if (!(kr || hc->end_range) || op == OP_NEXT ||
+ Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ if (!kr && Mode == MODE_READX) {
+ // This is a false indexed read
+ rc = Jcp->ExecuteQuery((char*)Query->GetStr());
+ Mode = MODE_READ;
+ Rows = 1; // ???
+ return (rc != RC_OK);
+ } // endif key
+
+ return false;
+ } else {
+ if (hc->MakeKeyWhere(g, Query, op, c, kr))
+ return true;
+
+ if (To_CondFil) {
+ if (To_CondFil->Idx != hc->active_index) {
+ To_CondFil->Idx = hc->active_index;
+ To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
+ *To_CondFil->Body= 0;
+
+ if ((To_CondFil = hc->CheckCond(g, To_CondFil, Cond)))
+ PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
+
+ } // endif active_index
+
+ if (To_CondFil)
+ if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
+ strcpy(g->Message, "Readkey: Out of memory");
+ return true;
+ } // endif Append
+
+ } // endif To_Condfil
+
+ Mode = MODE_READ;
+ } // endif's op
+
+ if (trace(33))
+ htrc("JDBC ReadKey: Query=%s\n", Query->GetStr());
+
+ rc = Jcp->ExecuteQuery((char*)Query->GetStr());
+ Query->Truncate(oldlen);
+ Rows = 1; // ???
+ return (rc != RC_OK);
+} // end of ReadKey
+
+/***********************************************************************/
+/* Data Base read routine for JDBC access method. */
+/***********************************************************************/
+int TDBJDBC::ReadDB(PGLOBAL g)
+{
+ int rc;
+
+ if (trace(2))
+ htrc("JDBC ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode);
+
+ if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ if (!Query && MakeCommand(g))
+ return RC_FX;
+
+ // Send the UPDATE/DELETE command to the remote table
+ rc = Jcp->ExecuteUpdate(Query->GetStr());
+
+ if (rc == RC_OK) {
+ AftRows = Jcp->m_Aff;
+ return RC_EF; // Nothing else to do
+ } else {
+ Werr = true;
+ return RC_FX;
+ } // endif rc
+
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Now start the reading process. */
+ /* Here is the place to fetch the line(s). */
+ /*********************************************************************/
+ if (Placed) {
+ if (Fpos && CurNum >= 0)
+ Rbuf = Jcp->Fetch((Curpos = Fpos));
+ else
+ Fpos = CurNum;
+
+ rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
+ Placed = false;
+ } else {
+ if (Memory != 3) {
+ if (++CurNum >= Rbuf) {
+ Rbuf = Jcp->Fetch();
+ Curpos = Fpos + 1;
+ CurNum = 0;
+ } // endif CurNum
+
+ rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
+ } else // Getting result from memory
+ rc = (Fpos < Qrp->Nblin) ? RC_OK : RC_EF;
+
+ if (rc == RC_OK) {
+ if (Memory == 2)
+ Qrp->Nblin++;
+
+ Fpos++; // Used for memory and pos
+ } // endif rc
+
+ } // endif placed
+
+ if (trace(2))
+ htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);
+
+ return rc;
+} // end of ReadDB
+
+/***********************************************************************/
+/* Data Base Insert write routine for JDBC access method. */
+/***********************************************************************/
+int TDBJDBC::WriteDB(PGLOBAL g)
+{
+ int rc;
+
+ if (Prepared) {
+ if (SetParameters(g)) {
+ Werr = true;
+ rc = RC_FX;
+ } else if ((rc = Jcp->ExecuteSQL()) == RC_OK)
+ AftRows += Jcp->m_Aff;
+ else
+ Werr = true;
+
+ return rc;
+ } // endif Prepared
+
+ // Statement was not prepared, we must construct and execute
+ // an insert query for each line to insert
+ uint len = Query->GetLength();
+ char buf[64];
+
+ // Make the Insert command value list
+ for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
+ if (!colp->GetValue()->IsNull()) {
+ char *s = colp->GetValue()->GetCharString(buf);
+
+ if (colp->GetResultType() == TYPE_STRING)
+ Query->Append_quoted(s);
+ else if (colp->GetResultType() == TYPE_DATE) {
+ DTVAL *dtv = (DTVAL*)colp->GetValue();
+
+ if (dtv->IsFormatted())
+ Query->Append_quoted(s);
+ else
+ Query->Append(s);
+
+ } else
+ Query->Append(s);
+
+ } else
+ Query->Append("NULL");
+
+ Query->Append(',');
+ } // endfor colp
+
+ if (unlikely(Query->IsTruncated())) {
+ strcpy(g->Message, "WriteDB: Out of memory");
+ return RC_FX;
+ } // endif Query
+
+ Query->RepLast(')');
+
+ if (trace(2))
+ htrc("Inserting: %s\n", Query->GetStr());
+
+ rc = Jcp->ExecuteUpdate(Query->GetStr());
+ Query->Truncate(len); // Restore query
+
+ if (rc == RC_OK)
+ AftRows += Jcp->m_Aff;
+ else
+ Werr = true;
+
+ return rc;
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for JDBC access method. */
+/***********************************************************************/
+int TDBJDBC::DeleteDB(PGLOBAL g, int irc)
+{
+ if (irc == RC_FX) {
+ if (!Query && MakeCommand(g))
+ return RC_FX;
+
+ // Send the DELETE (all) command to the remote table
+ if (Jcp->ExecuteUpdate(Query->GetStr()) == RC_OK) {
+ AftRows = Jcp->m_Aff;
+ sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ PushWarning(g, this, 0); // 0 means a Note
+ return RC_OK; // This is a delete all
+ } else
+ return RC_FX; // Error
+
+ } else
+ return RC_OK; // Ignore
+
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for JDBC access method. */
+/***********************************************************************/
+void TDBJDBC::CloseDB(PGLOBAL g)
+{
+ if (Jcp)
+ Jcp->Close();
+
+ if (trace(1))
+ htrc("JDBC CloseDB: closing %s\n", Name);
+
+ if (!Werr &&
+ (Mode == MODE_INSERT || Mode == MODE_UPDATE || Mode == MODE_DELETE)) {
+ sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ PushWarning(g, this, 0); // 0 means a Note
+ } // endif Mode
+
+ Prepared = false;
+} // end of CloseDB
+
+/* --------------------------- JDBCCOL ------------------------------- */
+
+/***********************************************************************/
+/* JDBCCOL public constructor. */
+/***********************************************************************/
+JDBCCOL::JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : EXTCOL(cdp, tdbp, cprec, i, am)
+{
+ uuid = false;
+} // end of JDBCCOL constructor
+
+/***********************************************************************/
+/* JDBCCOL private constructor. */
+/***********************************************************************/
+JDBCCOL::JDBCCOL(void) : EXTCOL()
+{
+ uuid = false;
+} // end of JDBCCOL constructor
+
+/***********************************************************************/
+/* JDBCCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+JDBCCOL::JDBCCOL(JDBCCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
+{
+ uuid = col1->uuid;
+} // end of JDBCCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: retrieve the column value via the JDBC driver. */
+/***********************************************************************/
+void JDBCCOL::ReadColumn(PGLOBAL g)
+{
+ PTDBJDBC tdbp = (PTDBJDBC)To_Tdb;
+ int i = tdbp->Fpos - 1;
+
+ if (tdbp->Memory == 3) {
+ // Get the value from the stored memory
+ if (Crp->Nulls && Crp->Nulls[i] == '*') {
+ Value->Reset();
+ Value->SetNull(true);
+ } else {
+ Value->SetValue_pvblk(Crp->Kdata, i);
+ Value->SetNull(false);
+ } // endif Nulls
+
+ return;
+ } // endif Memory
+
+ /*********************************************************************/
+ /* Get the column value. */
+ /*********************************************************************/
+ tdbp->Jcp->SetColumnValue(Rank, Name, Value);
+
+ if (tdbp->Memory != 2)
+ return;
+
+ /*********************************************************************/
+ /* Fill the allocated result structure. */
+ /*********************************************************************/
+ if (Value->IsNull()) {
+ if (Crp->Nulls)
+ Crp->Nulls[i] = '*'; // Null value
+
+ Crp->Kdata->Reset(i);
+ } else
+ Crp->Kdata->SetValue(Value, i);
+
+} // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: Convert if necessary. */
+/***********************************************************************/
+void JDBCCOL::WriteColumn(PGLOBAL g)
+{
+ /*********************************************************************/
+ /* Do convert the column value if necessary. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value
+
+} // end of WriteColumn
+
+/* -------------------------- Class TDBXJDC -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBXJDC class. */
+/***********************************************************************/
+TDBXJDC::TDBXJDC(PJDBCDEF tdp) : TDBJDBC(tdp)
+{
+ Cmdlist = NULL;
+ Cmdcol = NULL;
+ Mxr = tdp->Maxerr;
+ Nerr = 0;
+} // end of TDBXJDC constructor
+
+/***********************************************************************/
+/* Allocate XSRC column description block. */
+/***********************************************************************/
+PCOL TDBXJDC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ PJSRCCOL colp = new(g)JSRCCOL(cdp, this, cprec, n);
+
+ if (!colp->Flag)
+ Cmdcol = colp->GetName();
+
+ return colp;
+} // end of MakeCol
+
+/***********************************************************************/
+/* MakeCMD: make the SQL statement to send to JDBC connection. */
+/***********************************************************************/
+PCMD TDBXJDC::MakeCMD(PGLOBAL g)
+{
+ PCMD xcmd = NULL;
+
+ if (To_CondFil) {
+ if (Cmdcol) {
+ if (!stricmp(Cmdcol, To_CondFil->Body) &&
+ (To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
+ xcmd = To_CondFil->Cmds;
+ } else
+ strcpy(g->Message, "Invalid command specification filter");
+
+ } else
+ strcpy(g->Message, "No command column in select list");
+
+ } else if (!Srcdef)
+ strcpy(g->Message, "No Srcdef default command");
+ else
+ xcmd = new(g) CMD(g, Srcdef);
+
+ return xcmd;
+} // end of MakeCMD
+
+/***********************************************************************/
+/* XDBC GetMaxSize: returns table size (not always one row). */
+/***********************************************************************/
+int TDBXJDC::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = 2; // Just a guess
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* JDBC Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool TDBXJDC::OpenDB(PGLOBAL g)
+{
+ if (trace(1))
+ htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ strcpy(g->Message, "Multiple execution is not allowed");
+ return true;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open an JDBC connection for this table. */
+ /* Note: this may not be the proper way to do. Perhaps it is better */
+ /* to test whether a connection is already open for this datasource */
+ /* and if so to allocate just a new result set. But this only for */
+ /* drivers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Jcp) {
+ Jcp = new(g) JDBConn(g, Wrapname);
+ } else if (Jcp->IsOpen())
+ Jcp->Close();
+
+ if (Jcp->Connect(&Ops))
+ return true;
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ if (Mode != MODE_READ && Mode != MODE_READX) {
+ strcpy(g->Message, "No INSERT/DELETE/UPDATE of XJDBC tables");
+ return true;
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Get the command to execute. */
+ /*********************************************************************/
+ if (!(Cmdlist = MakeCMD(g))) {
+ // Next lines commented out because of CHECK TABLE
+ //Jcp->Close();
+ //return true;
+ } // endif Query
+
+ Rows = 1;
+ return false;
+} // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for xdbc access method. */
+/***********************************************************************/
+int TDBXJDC::ReadDB(PGLOBAL g)
+{
+ if (Cmdlist) {
+ int rc;
+
+ if (!Query)
+ Query = new(g) STRING(g, 0, Cmdlist->Cmd);
+ else
+ Query->Set(Cmdlist->Cmd);
+
+ if ((rc = Jcp->ExecuteCommand(Query->GetStr())) == RC_FX)
+ Nerr++;
+
+ if (rc == RC_NF)
+ AftRows = Jcp->m_Aff;
+ else if (rc == RC_OK)
+ AftRows = Jcp->m_Ncol;
+
+ Fpos++; // Used for progress info
+ Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
+ return RC_OK;
+ } else {
+ PushWarning(g, this, 1);
+ return RC_EF;
+ } // endif Cmdlist
+
+} // end of ReadDB
+
+/***********************************************************************/
+/* Data Base write line routine for JDBC access method. */
+/***********************************************************************/
+int TDBXJDC::WriteDB(PGLOBAL g)
+{
+ strcpy(g->Message, "Execsrc tables are read only");
+ return RC_FX;
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for JDBC access method. */
+/***********************************************************************/
+int TDBXJDC::DeleteDB(PGLOBAL g, int irc)
+{
+ strcpy(g->Message, "NO_XJDBC_DELETE");
+ return RC_FX;
+} // end of DeleteDB
+
+/* --------------------------- JSRCCOL ------------------------------- */
+
+/***********************************************************************/
+/* JSRCCOL public constructor. */
+/***********************************************************************/
+JSRCCOL::JSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : JDBCCOL(cdp, tdbp, cprec, i, am)
+{
+ // Set additional JDBC access method information for column.
+ Flag = cdp->GetOffset();
+} // end of JSRCCOL constructor
+
+/***********************************************************************/
+/* ReadColumn: set column value according to Flag. */
+/***********************************************************************/
+void JSRCCOL::ReadColumn(PGLOBAL g)
+{
+ PTDBXJDC tdbp = (PTDBXJDC)To_Tdb;
+
+ switch (Flag) {
+ case 0: Value->SetValue_psz(tdbp->Query->GetStr()); break;
+ case 1: Value->SetValue(tdbp->AftRows); break;
+ case 2: Value->SetValue_psz(g->Message); break;
+ default: Value->SetValue_psz("Invalid Flag"); break;
+ } // endswitch Flag
+
+} // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: Should never be called. */
+/***********************************************************************/
+void JSRCCOL::WriteColumn(PGLOBAL g)
+{
+ // Should never be called
+} // end of WriteColumn
+
+/* ---------------------------TDBJDRV class -------------------------- */
+
+/***********************************************************************/
+/* GetResult: Get the list of JDBC drivers. */
+/***********************************************************************/
+PQRYRES TDBJDRV::GetResult(PGLOBAL g)
+{
+ return JDBCDrivers(g, Maxres, false);
+} // end of GetResult
+
+/* ---------------------------TDBJTB class --------------------------- */
+
+/***********************************************************************/
+/* TDBJTB class constructor. */
+/***********************************************************************/
+TDBJTB::TDBJTB(PJDBCDEF tdp) : TDBJDRV(tdp)
+{
+ Schema = tdp->Tabschema;
+ Tab = tdp->Tabname;
+ Tabtype = tdp->Tabtyp;
+ Ops.Driver = tdp->Driver;
+ Ops.Url = tdp->Url;
+ Ops.User = tdp->Username;
+ Ops.Pwd = tdp->Password;
+ Ops.Fsize = 0;
+ Ops.Scrollable = false;
+} // end of TDBJTB constructor
+
+/***********************************************************************/
+/* GetResult: Get the list of JDBC tables. */
+/***********************************************************************/
+PQRYRES TDBJTB::GetResult(PGLOBAL g)
+{
+ return JDBCTables(g, Schema, Tab, Tabtype, Maxres, false, &Ops);
+} // end of GetResult
+
+/* --------------------------TDBJDBCL class -------------------------- */
+
+/***********************************************************************/
+/* TDBJDBCL class constructor. */
+/***********************************************************************/
+TDBJDBCL::TDBJDBCL(PJDBCDEF tdp) : TDBJTB(tdp)
+{
+ Colpat = tdp->Colpat;
+} // end of TDBJDBCL constructor
+
+/***********************************************************************/
+/* GetResult: Get the list of JDBC table columns. */
+/***********************************************************************/
+PQRYRES TDBJDBCL::GetResult(PGLOBAL g)
+{
+ return JDBCColumns(g, Schema, Tab, Colpat, Maxres, false, &Ops);
+} // end of GetResult
diff --git a/storage/connect/tabjdbc.h b/storage/connect/tabjdbc.h
new file mode 100644
index 00000000..078129a1
--- /dev/null
+++ b/storage/connect/tabjdbc.h
@@ -0,0 +1,236 @@
+/*************** Tabjdbc H Declares Source Code File (.H) **************/
+/* Name: TABJDBC.H Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2016-2017 */
+/* */
+/* This file contains the TDBJDBC classes declares. */
+/***********************************************************************/
+#include "colblk.h"
+#include "resource.h"
+#include "jdbccat.h"
+
+typedef class JDBCDEF *PJDBCDEF;
+typedef class TDBJDBC *PTDBJDBC;
+typedef class JDBCCOL *PJDBCCOL;
+typedef class TDBXJDC *PTDBXJDC;
+typedef class JSRCCOL *PJSRCCOL;
+
+/***********************************************************************/
+/* JDBC table. */
+/***********************************************************************/
+class DllExport JDBCDEF : public EXTDEF { /* Logical table description */
+ friend class TDBJDBC;
+ friend class TDBXJDC;
+ friend class TDBJDRV;
+ friend class TDBJTB;
+ friend class TDBJDBCL;
+public:
+ // Constructor
+ JDBCDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) { return "JDBC"; }
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+ int ParseURL(PGLOBAL g, char *url, bool b = true);
+ bool SetParms(PJPARM sjp);
+
+protected:
+ // Members
+ PSZ Driver; /* JDBC driver */
+ PSZ Url; /* JDBC driver URL */
+ PSZ Wrapname; /* Java driver name */
+}; // end of JDBCDEF
+
+#if !defined(NJDBC)
+#include "jdbconn.h"
+
+/***********************************************************************/
+/* This is the JDBC Access Method class declaration for files from */
+/* other DB drivers to be accessed via JDBC. */
+/***********************************************************************/
+class TDBJDBC : public TDBEXT {
+ friend class JDBCCOL;
+ friend class JDBConn;
+public:
+ // Constructor
+ TDBJDBC(PJDBCDEF tdp = NULL);
+ TDBJDBC(PTDBJDBC tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_JDBC;}
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBJDBC(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual bool SetRecpos(PGLOBAL g, int recpos);
+ virtual void ResetSize(void);
+ virtual PCSZ GetServer(void) { return "JDBC"; }
+ virtual int Indexable(void) { return 2; }
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr);
+
+protected:
+ // Internal functions
+ bool MakeInsert(PGLOBAL g);
+ bool SetParameters(PGLOBAL g);
+
+ // Members
+ JDBConn *Jcp; // Points to a JDBC connection class
+ JDBCCOL *Cnp; // Points to count(*) column
+ JDBCPARM Ops; // Additional parameters
+ PSZ Wrapname; // Points to Java wrapper name
+ bool Prepared; // True when using prepared statement
+ bool Werr; // Write error
+ bool Rerr; // Rewind error
+}; // end of class TDBJDBC
+
+/***********************************************************************/
+/* Class JDBCCOL: JDBC access method column descriptor. */
+/* This A.M. is used for JDBC tables. */
+/***********************************************************************/
+class JDBCCOL : public EXTCOL {
+ friend class TDBJDBC;
+ friend class JDBConn;
+public:
+ // Constructors
+ JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "JDBC");
+ JDBCCOL(JDBCCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) { return TYPE_AM_JDBC; }
+
+ // Methods
+//virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+protected:
+ // Constructor for count(*) column
+ JDBCCOL(void);
+
+ // Members
+ bool uuid; // For PostgreSQL
+}; // end of class JDBCCOL
+
+/***********************************************************************/
+/* This is the JDBC Access Method class declaration that send */
+/* commands to be executed by other DB JDBC drivers. */
+/***********************************************************************/
+class TDBXJDC : public TDBJDBC {
+ friend class JSRCCOL;
+ friend class JDBConn;
+public:
+ // Constructors
+ TDBXJDC(PJDBCDEF tdp = NULL);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_XDBC;}
+
+ // Methods
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ //virtual int GetProgMax(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ //virtual void CloseDB(PGLOBAL g);
+
+protected:
+ // Internal functions
+ PCMD MakeCMD(PGLOBAL g);
+
+ // Members
+ PCMD Cmdlist; // The commands to execute
+ char *Cmdcol; // The name of the Xsrc command column
+ int Mxr; // Maximum errors before closing
+ int Nerr; // Number of errors so far
+}; // end of class TDBXJDC
+
+/***********************************************************************/
+/* Used by table in source execute mode. */
+/***********************************************************************/
+class JSRCCOL : public JDBCCOL {
+ friend class TDBXJDC;
+public:
+ // Constructors
+ JSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "JDBC");
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_JDBC;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+protected:
+ // Members
+ char *Buffer; // To get returned message
+ int Flag; // Column content desc
+}; // end of class JSRCCOL
+
+/***********************************************************************/
+/* This is the class declaration for the Drivers catalog table. */
+/***********************************************************************/
+class TDBJDRV : public TDBCAT {
+public:
+ // Constructor
+ TDBJDRV(PJDBCDEF tdp) : TDBCAT(tdp) {Maxres = tdp->Maxres;}
+
+protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ int Maxres; // Returned lines limit
+}; // end of class TDBJDRV
+
+/***********************************************************************/
+/* This is the class declaration for the tables catalog table. */
+/***********************************************************************/
+class TDBJTB : public TDBJDRV {
+public:
+ // Constructor
+ TDBJTB(PJDBCDEF tdp);
+
+protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PCSZ Schema; // Points to schema name or NULL
+ PCSZ Tab; // Points to JDBC table name or pattern
+ PCSZ Tabtype; // Points to JDBC table type
+ JDBCPARM Ops; // Additional parameters
+}; // end of class TDBJTB
+
+/***********************************************************************/
+/* This is the class declaration for the columns catalog table. */
+/***********************************************************************/
+class TDBJDBCL : public TDBJTB {
+public:
+ // Constructor
+ TDBJDBCL(PJDBCDEF tdp);
+
+protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PCSZ Colpat; // Points to catalog column pattern
+}; // end of class TDBJDBCL
+
+#endif // !NJDBC
diff --git a/storage/connect/tabjmg.cpp b/storage/connect/tabjmg.cpp
new file mode 100644
index 00000000..983ee39d
--- /dev/null
+++ b/storage/connect/tabjmg.cpp
@@ -0,0 +1,632 @@
+/************** tabjmg C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: tabjmg Version 1.3 */
+/* (C) Copyright to the author Olivier BERTRAND 2021 */
+/* This file contains the MongoDB classes using the Java Driver. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "maputil.h"
+#include "filamtxt.h"
+#include "tabext.h"
+#include "tabjmg.h"
+#include "tabmul.h"
+#include "checklvl.h"
+#include "resource.h"
+#include "mycat.h" // for FNC_COL
+#include "filter.h"
+
+#define nullptr 0
+
+PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info);
+bool Stringified(PCSZ, char*);
+
+/* -------------------------- Class JMGDISC -------------------------- */
+
+/***********************************************************************/
+/* Constructor */
+/***********************************************************************/
+JMGDISC::JMGDISC(PGLOBAL g, int *lg) : MGODISC(g, lg)
+{
+ drv = "Java"; Jcp = NULL; columnid = nullptr; bvnameid = nullptr;
+} // end of JMGDISC constructor
+
+/***********************************************************************/
+/* Initialyze. */
+/***********************************************************************/
+bool JMGDISC::Init(PGLOBAL g)
+{
+ if (!(Jcp = ((TDBJMG*)tmgp)->Jcp)) {
+ strcpy(g->Message, "Init: Jcp is NULL");
+ return true;
+ } else if (Jcp->gmID(g, columnid, "ColumnDesc",
+ "(Ljava/lang/Object;I[II)Ljava/lang/Object;"))
+ return true;
+ else if (Jcp->gmID(g, bvnameid, "ColDescName", "()Ljava/lang/String;"))
+ return true;
+
+ return false;
+} // end of Init
+
+/***********************************************************************/
+/* Analyse passed document. */
+/***********************************************************************/
+bool JMGDISC::Find(PGLOBAL g)
+{
+ return ColDesc(g, nullptr, NULL, NULL, Jcp->m_Ncol, 0);
+} // end of Find
+
+/***********************************************************************/
+/* Analyse passed document. */
+/***********************************************************************/
+bool JMGDISC::ColDesc(PGLOBAL g, jobject obj, char *pcn, char *pfmt,
+ int ncol, int k)
+{
+ const char *key, *utf;
+ char colname[65];
+ char fmt[129];
+ bool rc = true;
+ size_t z;
+ jint *n = nullptr;
+ jstring jkey;
+ jobject jres;
+
+ // Build the java int array
+ jintArray val = Jcp->env->NewIntArray(5);
+
+ if (val == nullptr) {
+ strcpy(g->Message, "Cannot allocate jint array");
+ return true;
+ } else if (!ncol)
+ n = Jcp->env->GetIntArrayElements(val, 0);
+
+ for (int i = 0; i < ncol; i++) {
+ jres = Jcp->env->CallObjectMethod(Jcp->job, columnid, obj, i, val, lvl - k);
+ n = Jcp->env->GetIntArrayElements(val, 0);
+
+ if (Jcp->Check(n[0])) {
+ sprintf(g->Message, "ColDesc: %s", Jcp->Msg);
+ goto err;
+ } else if (!n[0])
+ continue;
+
+ jkey = (jstring)Jcp->env->CallObjectMethod(Jcp->job, bvnameid);
+ utf = Jcp->env->GetStringUTFChars(jkey, nullptr);
+ key = PlugDup(g, utf);
+ Jcp->env->ReleaseStringUTFChars(jkey, utf);
+ Jcp->env->DeleteLocalRef(jkey);
+
+ if (pcn) {
+ strncpy(colname, pcn, 64);
+ colname[64] = 0;
+ z = 65 - strlen(colname);
+ strncat(strncat(colname, "_", z), key, z - 1);
+ } else
+ strcpy(colname, key);
+
+ if (pfmt) {
+ strncpy(fmt, pfmt, 128);
+ fmt[128] = 0;
+ z = 129 - strlen(fmt);
+ strncat(strncat(fmt, ".", z), key, z - 1);
+ } else
+ strcpy(fmt, key);
+
+ if (!jres) {
+ bcol.Type = n[0];
+ bcol.Len = n[1];
+ bcol.Scale = n[2];
+ bcol.Cbn = n[3];
+ AddColumn(g, colname, fmt, k);
+ } else {
+ if (n[0] == 2 && !all)
+ n[4] = MY_MIN(n[4], 1);
+
+ if (ColDesc(g, jres, colname, fmt, n[4], k + 1))
+ goto err;
+
+ } // endif jres
+
+ } // endfor i
+
+ rc = false;
+
+ err:
+ Jcp->env->ReleaseIntArrayElements(val, n, 0);
+ return rc;
+} // end of ColDesc
+
+/* --------------------------- Class TDBJMG -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBJMG class. */
+/***********************************************************************/
+TDBJMG::TDBJMG(PMGODEF tdp) : TDBEXT(tdp)
+{
+ Jcp = NULL;
+//Cnp = NULL;
+
+ if (tdp) {
+ Ops.Driver = tdp->Tabschema;
+ Ops.Url = tdp->Uri;
+ Ops.Version = tdp->Version;
+ Uri = tdp->Uri;
+ Db_name = tdp->Tabschema;
+ Wrapname = tdp->Wrapname;
+ Coll_name = tdp->Tabname;
+ Options = tdp->Colist;
+ Filter = tdp->Filter;
+ Strfy = tdp->Strfy;
+ B = tdp->Base ? 1 : 0;
+ Pipe = tdp->Pipe && Options != NULL;
+ } else {
+ Ops.Driver = NULL;
+ Ops.Url = NULL;
+ Ops.Version = 0;
+ Uri = NULL;
+ Db_name = NULL;
+ Coll_name = NULL;
+ Options = NULL;
+ Filter = NULL;
+ Strfy = NULL;
+ B = 0;
+ Pipe = false;
+ } // endif tdp
+
+ Ops.User = NULL;
+ Ops.Pwd = NULL;
+ Ops.Scrollable = false;
+ Ops.Fsize = 0;
+ Fpos = -1;
+ N = 0;
+ Done = false;
+} // end of TDBJMG standard constructor
+
+TDBJMG::TDBJMG(TDBJMG *tdbp) : TDBEXT(tdbp)
+{
+ Uri = tdbp->Uri;
+ Db_name = tdbp->Db_name;;
+ Coll_name = tdbp->Coll_name;
+ Options = tdbp->Options;
+ Filter = tdbp->Filter;
+ Strfy = tdbp->Strfy;
+ B = tdbp->B;
+ Fpos = tdbp->Fpos;
+ N = tdbp->N;
+ Done = tdbp->Done;
+ Pipe = tdbp->Pipe;
+} // end of TDBJMG copy constructor
+
+// Used for update
+PTDB TDBJMG::Clone(PTABS t)
+{
+ PTDB tp;
+ PJMGCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBJMG(this);
+
+ for (cp1 = (PJMGCOL)Columns; cp1; cp1 = (PJMGCOL)cp1->GetNext())
+ if (!cp1->IsSpecial()) {
+ cp2 = new(g) JMGCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endif cp1
+
+ return tp;
+} // end of Clone
+
+/***********************************************************************/
+/* Allocate JSN column description block. */
+/***********************************************************************/
+PCOL TDBJMG::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ return new(g) JMGCOL(g, cdp, this, cprec, n);
+} // end of MakeCol
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBJMG::InsertSpecialColumn(PCOL colp)
+{
+ if (!colp->IsSpecial())
+ return NULL;
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+} // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* MONGO Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBJMG::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 1;
+ else if (Cardinal < 0)
+ Cardinal = (!Init(g)) ? Jcp->CollSize(g) : 0;
+
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* MONGO GetMaxSize: returns collection size estimate. */
+/***********************************************************************/
+int TDBJMG::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = Cardinality(g);
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* Init: initialize MongoDB processing. */
+/***********************************************************************/
+bool TDBJMG::Init(PGLOBAL g)
+{
+ if (Done)
+ return false;
+
+ /*********************************************************************/
+ /* Open an JDBC connection for this table. */
+ /* Note: this may not be the proper way to do. Perhaps it is better */
+ /* to test whether a connection is already open for this datasource */
+ /* and if so to allocate just a new result set. But this only for */
+ /* drivers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Jcp)
+ Jcp = new(g) JMgoConn(g, Coll_name, Wrapname);
+ else if (Jcp->IsOpen())
+ Jcp->Close();
+
+ if (Jcp->Connect(&Ops))
+ return true;
+
+ Done = true;
+ return false;
+} // end of Init
+
+/***********************************************************************/
+/* OpenDB: Data Base open routine for MONGO access method. */
+/***********************************************************************/
+bool TDBJMG::OpenDB(PGLOBAL g)
+{
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open replace it at its beginning. */
+ /*******************************************************************/
+ if (Jcp->Rewind())
+ return true;
+
+ Fpos = -1;
+ return false;
+ } // endif Use
+
+ /*********************************************************************/
+ /* First opening. */
+ /*********************************************************************/
+ if (Pipe && Mode != MODE_READ) {
+ strcpy(g->Message, "Pipeline tables are read only");
+ return true;
+ } // endif Pipe
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ if (Init(g))
+ return true;
+
+ if (Jcp->GetMethodId(g, Mode))
+ return true;
+
+ if (Mode == MODE_DELETE && !Next) {
+ // Delete all documents
+ if (!Jcp->MakeCursor(g, this, "all", Filter, false))
+ if (Jcp->DocDelete(g, true) == RC_OK)
+ return false;
+
+ return true;
+ } // endif Mode
+
+ if (Mode == MODE_INSERT)
+ Jcp->MakeColumnGroups(g, this);
+
+ if (Mode != MODE_UPDATE)
+ return Jcp->MakeCursor(g, this, Options, Filter, Pipe);
+
+ return false;
+} // end of OpenDB
+
+/***********************************************************************/
+/* Data Base indexed read routine for ODBC access method. */
+/***********************************************************************/
+bool TDBJMG::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
+{
+ strcpy(g->Message, "MONGO tables are not indexable");
+ return true;
+} // end of ReadKey
+
+/***********************************************************************/
+/* ReadDB: Get next document from a collection. */
+/***********************************************************************/
+int TDBJMG::ReadDB(PGLOBAL g)
+{
+ int rc = RC_OK;
+
+ if (!N && Mode == MODE_UPDATE)
+ if (Jcp->MakeCursor(g, this, Options, Filter, Pipe))
+ return RC_FX;
+
+ if (++CurNum >= Rbuf) {
+ Rbuf = Jcp->Fetch();
+ Curpos = Fpos + 1;
+ CurNum = 0;
+ N++;
+ } // endif CurNum
+
+ rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
+
+ return rc;
+} // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for DOS access method. */
+/***********************************************************************/
+int TDBJMG::WriteDB(PGLOBAL g)
+{
+ int rc = RC_OK;
+
+ if (Mode == MODE_INSERT) {
+ rc = Jcp->DocWrite(g, NULL);
+ } else if (Mode == MODE_DELETE) {
+ rc = Jcp->DocDelete(g, false);
+ } else if (Mode == MODE_UPDATE) {
+ rc = Jcp->DocUpdate(g, this);
+ } // endif Mode
+
+ return rc;
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for ODBC access method. */
+/***********************************************************************/
+int TDBJMG::DeleteDB(PGLOBAL g, int irc)
+{
+ return (irc == RC_OK) ? WriteDB(g) : RC_OK;
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Table close routine for MONGO tables. */
+/***********************************************************************/
+void TDBJMG::CloseDB(PGLOBAL g)
+{
+ Jcp->Close();
+ Done = false;
+} // end of CloseDB
+
+/* ----------------------------- JMGCOL ------------------------------ */
+
+/***********************************************************************/
+/* JMGCOL public constructor. */
+/***********************************************************************/
+JMGCOL::JMGCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : EXTCOL(cdp, tdbp, cprec, i, "MGO")
+{
+ Tmgp = (PTDBJMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
+ Sgfy = Stringified(Tmgp->Strfy, Name);
+
+ if ((Jpath = cdp->GetFmt())) {
+ int n = strlen(Jpath);
+
+ if (n && Jpath[n - 1] == '*') {
+ Jpath = PlugDup(g, cdp->GetFmt());
+
+ if (--n) {
+ if (Jpath[n - 1] == '.') n--;
+ Jpath[n] = 0;
+ } // endif n
+
+ Sgfy = true;
+ } // endif Jpath
+
+ } else
+ Jpath = cdp->GetName();
+
+} // end of JMGCOL constructor
+
+/***********************************************************************/
+/* JMGCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+JMGCOL::JMGCOL(JMGCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
+{
+ Tmgp = col1->Tmgp;
+ Jpath = col1->Jpath;
+ Sgfy = col1->Sgfy;
+} // end of JMGCOL copy constructor
+
+/***********************************************************************/
+/* Get path when proj is false or projection path when proj is true. */
+/***********************************************************************/
+PSZ JMGCOL::GetJpath(PGLOBAL g, bool proj)
+{
+ if (Jpath) {
+ if (proj) {
+ char* p1, * p2, * projpath = PlugDup(g, Jpath);
+ int i = 0;
+
+ for (p1 = p2 = projpath; *p1; p1++)
+ if (*p1 == '.') {
+ if (!i)
+ *p2++ = *p1;
+
+ i = 1;
+ } else if (i) {
+ if (!isdigit(*p1)) {
+ *p2++ = *p1;
+ i = 0;
+ } // endif p1
+
+ } else
+ *p2++ = *p1;
+
+ if (*(p2 - 1) == '.')
+ p2--;
+
+ *p2 = 0;
+ return projpath;
+ } else
+ return Jpath;
+
+ } else
+ return Name;
+
+} // end of GetJpath
+
+#if 0
+/***********************************************************************/
+/* Mini: used to suppress blanks to json strings. */
+/***********************************************************************/
+char *JMGCOL::Mini(PGLOBAL g, const bson_t *bson, bool b)
+{
+ char *s, *str = NULL;
+ int i, k = 0;
+ bool ok = true;
+
+ if (b)
+ s = str = bson_array_as_json(bson, NULL);
+ else
+ s = str = bson_as_json(bson, NULL);
+
+ for (i = 0; i < Long && s[i]; i++) {
+ switch (s[i]) {
+ case ' ':
+ if (ok) continue;
+ break;
+ case '"':
+ ok = !ok;
+ default:
+ break;
+ } // endswitch s[i]
+
+ Mbuf[k++] = s[i];
+ } // endfor i
+
+ bson_free(str);
+
+ if (i >= Long) {
+ sprintf(g->Message, "Value too long for column %s", Name);
+ throw (int)TYPE_AM_MGO;
+ } // endif i
+
+ Mbuf[k] = 0;
+ return Mbuf;
+} // end of Mini
+#endif // 0
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void JMGCOL::ReadColumn(PGLOBAL g)
+{
+ Value->SetValue_psz(Tmgp->Jcp->GetColumnValue(Jpath));
+} // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: */
+/***********************************************************************/
+void JMGCOL::WriteColumn(PGLOBAL g)
+{
+ // Check whether this node must be written
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, FALSE); // Convert the updated value
+
+} // end of WriteColumn
+
+#if 0
+/***********************************************************************/
+/* AddValue: Add column value to the document to insert or update. */
+/***********************************************************************/
+bool JMGCOL::AddValue(PGLOBAL g, bson_t *doc, char *key, bool upd)
+{
+ bool rc = false;
+
+ if (Value->IsNull()) {
+ if (upd)
+ rc = BSON_APPEND_NULL(doc, key);
+ else
+ return false;
+
+ } else switch (Buf_Type) {
+ case TYPE_STRING:
+ rc = BSON_APPEND_UTF8(doc, key, Value->GetCharValue());
+ break;
+ case TYPE_INT:
+ case TYPE_SHORT:
+ rc = BSON_APPEND_INT32(doc, key, Value->GetIntValue());
+ break;
+ case TYPE_TINY:
+ rc = BSON_APPEND_BOOL(doc, key, Value->GetIntValue());
+ break;
+ case TYPE_BIGINT:
+ rc = BSON_APPEND_INT64(doc, key, Value->GetBigintValue());
+ break;
+ case TYPE_DOUBLE:
+ rc = BSON_APPEND_DOUBLE(doc, key, Value->GetFloatValue());
+ break;
+ case TYPE_DECIM:
+ {bson_decimal128_t dec;
+
+ if (bson_decimal128_from_string(Value->GetCharValue(), &dec))
+ rc = BSON_APPEND_DECIMAL128(doc, key, &dec);
+
+ } break;
+ case TYPE_DATE:
+ rc = BSON_APPEND_DATE_TIME(doc, key, Value->GetBigintValue() * 1000);
+ break;
+ default:
+ sprintf(g->Message, "Type %d not supported yet", Buf_Type);
+ return true;
+ } // endswitch Buf_Type
+
+ if (!rc) {
+ strcpy(g->Message, "Adding value failed");
+ return true;
+ } else
+ return false;
+
+} // end of AddValue
+#endif // 0
+
+/* -------------------------- TDBJGL class --------------------------- */
+
+/***********************************************************************/
+/* TDBJGL class constructor. */
+/***********************************************************************/
+TDBJGL::TDBJGL(PMGODEF tdp) : TDBCAT(tdp)
+{
+ Topt = tdp->GetTopt();
+ Uri = tdp->Uri;
+ Db = tdp->GetTabschema();
+} // end of TDBJCL constructor
+
+/***********************************************************************/
+/* GetResult: Get the list the MongoDB collection columns. */
+/***********************************************************************/
+PQRYRES TDBJGL::GetResult(PGLOBAL g)
+{
+ return MGOColumns(g, Db, Uri, Topt, false);
+} // end of GetResult
+
+/* -------------------------- End of mongo --------------------------- */
diff --git a/storage/connect/tabjmg.h b/storage/connect/tabjmg.h
new file mode 100644
index 00000000..cf7cff83
--- /dev/null
+++ b/storage/connect/tabjmg.h
@@ -0,0 +1,147 @@
+/**************** tabjmg H Declares Source Code File (.H) **************/
+/* Name: tabjmg.h Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
+/* */
+/* This file contains the MongoDB classes using the Java Driver. */
+/***********************************************************************/
+#include "mongo.h"
+#include "jmgoconn.h"
+#include "jdbccat.h"
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+class JMGDISC : public MGODISC {
+public:
+ // Constructor
+ JMGDISC(PGLOBAL g, int *lg);
+
+ // Methods
+ virtual bool Init(PGLOBAL g);
+ virtual void GetDoc(void) {}
+ virtual bool Find(PGLOBAL g);
+
+protected:
+ // Function
+ bool ColDesc(PGLOBAL g, jobject obj, char *pcn, char *pfmt,
+ int ncol, int k);
+
+ // Members
+ JMgoConn *Jcp; // Points to a Mongo connection class
+ jmethodID columnid; // The ColumnDesc method ID
+ jmethodID bvnameid; // The ColDescName method ID
+}; // end of JMGDISC
+
+/* -------------------------- TDBJMG class --------------------------- */
+
+/***********************************************************************/
+/* This is the MongoDB Table Type using the Java Driver. */
+/* The table is a collection, each record being a document. */
+/***********************************************************************/
+class DllExport TDBJMG : public TDBEXT {
+ friend class JMGCOL;
+ friend class MGODEF;
+ friend class JMGDISC;
+ friend class JAVAConn;
+ friend PQRYRES MGOColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool);
+public:
+ // Constructor
+ TDBJMG(PMGODEF tdp);
+ TDBJMG(TDBJMG *tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) { return TYPE_AM_MGO; }
+ virtual PTDB Duplicate(PGLOBAL g) { return (PTDB)new(g) TDBJMG(this); }
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual PCOL InsertSpecialColumn(PCOL colp);
+//virtual void SetFilter(PFIL fp);
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE) { return N; }
+
+ // Database routines
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr);
+
+protected:
+ bool Init(PGLOBAL g);
+
+ // Members
+ JMgoConn *Jcp; // Points to a Mongo connection class
+//JMGCOL *Cnp; // Points to count(*) column
+ JDBCPARM Ops; // Additional parameters
+ PCSZ Uri;
+ PCSZ Db_name;
+ PCSZ Coll_name;
+ PCSZ Options; // The MongoDB options
+ PCSZ Filter; // The filtering query
+ PCSZ Strfy; // The stringified columns
+ PSZ Wrapname; // Java wrapper name
+ int Fpos; // The current row index
+ int N; // The current Rownum
+ int B; // Array index base
+ bool Done; // Init done
+ bool Pipe; // True for pipeline
+}; // end of class TDBJMG
+
+/* --------------------------- JMGCOL class -------------------------- */
+
+/***********************************************************************/
+/* Class JMGCOL: MongoDB access method column descriptor. */
+/***********************************************************************/
+class DllExport JMGCOL : public EXTCOL {
+ friend class TDBJMG;
+ friend class FILTER;
+public:
+ // Constructors
+ JMGCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
+ JMGCOL(JMGCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return Tmgp->GetAmType();}
+ virtual bool Stringify(void) { return Sgfy; }
+
+ // Methods
+ //virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual PSZ GetJpath(PGLOBAL g, bool proj);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+//bool AddValue(PGLOBAL g, bson_t *doc, char *key, bool upd);
+
+protected:
+ // Default constructor not to be used
+ JMGCOL(void) {}
+//char *GetProjPath(PGLOBAL g);
+//char *Mini(PGLOBAL g, const bson_t *bson, bool b);
+
+ // Members
+ TDBJMG *Tmgp; // To the MGO table block
+ char *Jpath; // The json path
+ bool Sgfy; // True if stringified
+}; // end of class JMGCOL
+
+/***********************************************************************/
+/* This is the class declaration for the MONGO catalog table. */
+/***********************************************************************/
+class DllExport TDBJGL : public TDBCAT {
+public:
+ // Constructor
+ TDBJGL(PMGODEF tdp);
+
+protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PTOS Topt;
+ PCSZ Uri;
+ PCSZ Db;
+}; // end of class TDBGOL
diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp
new file mode 100644
index 00000000..76a1f742
--- /dev/null
+++ b/storage/connect/tabjson.cpp
@@ -0,0 +1,2707 @@
+/************* tabjson C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: tabjson Version 1.9 */
+/* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */
+/* This program are the JSON class DB execution routines. */
+/***********************************************************************/
+#undef BSON_SUPPORT
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+#include <mysqld.h>
+#include <sql_error.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tdbdos.h is header containing the TDBDOS declarations. */
+/* json.h is header containing the JSON classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+//#include "xtable.h"
+#include "maputil.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+//#include "resource.h" // for IDS_COLUMNS
+#include "tabjson.h"
+#include "filamap.h"
+#if defined(GZ_SUPPORT)
+#include "filamgz.h"
+#endif // GZ_SUPPORT
+#if defined(ZIP_SUPPORT)
+#include "filamzip.h"
+#endif // ZIP_SUPPORT
+#if defined(JAVA_SUPPORT)
+#include "jmgfam.h"
+#endif // JAVA_SUPPORT
+#if defined(CMGO_SUPPORT)
+#include "cmgfam.h"
+#endif // CMGO_SUPPORT
+#include "tabmul.h"
+#include "checklvl.h"
+#include "resource.h"
+#include "mycat.h" // for FNC_COL
+
+/***********************************************************************/
+/* This should be an option. */
+/***********************************************************************/
+#define MAXCOL 200 /* Default max column nb in result */
+//#define TYPE_UNKNOWN 12 /* Must be greater than other types */
+
+/***********************************************************************/
+/* External functions. */
+/***********************************************************************/
+USETEMP UseTemp(void);
+bool JsonAllPath(void);
+int GetDefaultDepth(void);
+char *GetJsonNull(void);
+bool Stringified(PCSZ, char*);
+
+/***********************************************************************/
+/* JSONColumns: construct the result blocks containing the description */
+/* of all the columns of a table contained inside a JSON file. */
+/***********************************************************************/
+PQRYRES JSONColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt, bool info)
+{
+ static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
+ TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
+ static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
+ FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
+ static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
+ int i, n = 0;
+ int ncol = sizeof(buftyp) / sizeof(int);
+ PJCL jcp;
+ JSONDISC *pjdc = NULL;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ if (info) {
+ length[0] = 128;
+ length[7] = 256;
+ goto skipit;
+ } // endif info
+
+ if (GetIntegerTableOption(g, topt, "Multiple", 0)) {
+ strcpy(g->Message, "Cannot find column definition for multiple table");
+ return NULL;
+ } // endif Multiple
+
+ pjdc = new(g) JSONDISC(g, length);
+
+ if (!(n = pjdc->GetColumns(g, db, dsn, topt)))
+ return NULL;
+
+ skipit:
+ if (trace(1))
+ htrc("JSONColumns: n=%d len=%d\n", n, length[0]);
+
+ /*********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /*********************************************************************/
+ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, false);
+
+ crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
+ crp->Name = PlugDup(g, "Nullable");
+ crp->Next->Name = PlugDup(g, "Jpath");
+
+ if (info || !qrp)
+ return qrp;
+
+ qrp->Nblin = n;
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ for (i = 0, jcp = pjdc->fjcp; jcp; i++, jcp = jcp->Next) {
+ if (jcp->Type == TYPE_UNKNOWN)
+ jcp->Type = TYPE_STRG; // Void column
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(jcp->Name, i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(jcp->Type, i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(jcp->Type), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(jcp->Len, i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(jcp->Len, i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(jcp->Scale, i);
+ crp = crp->Next; // Nullable
+ crp->Kdata->SetValue(jcp->Cbn ? 1 : 0, i);
+ crp = crp->Next; // Field format
+
+ if (crp->Kdata)
+ crp->Kdata->SetValue(jcp->Fmt, i);
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* Return the result pointer. */
+ /*********************************************************************/
+ return qrp;
+ } // end of JSONColumns
+
+/* -------------------------- Class JSONDISC ------------------------- */
+
+/***********************************************************************/
+/* Class used to get the columns of a JSON table. */
+/***********************************************************************/
+JSONDISC::JSONDISC(PGLOBAL g, uint *lg)
+{
+ length = lg;
+ jcp = fjcp = pjcp = NULL;
+ tdp = NULL;
+ tjnp = NULL;
+ jpp = NULL;
+ tjsp = NULL;
+ jsp = NULL;
+ row = NULL;
+ sep = NULL;
+ strfy = NULL;
+ i = n = bf = ncol = lvl = sz = limit = 0;
+ all = false;
+} // end of JSONDISC constructor
+
+int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt)
+{
+ char filename[_MAX_PATH];
+ size_t reclg = 0;
+ bool mgo = (GetTypeID(topt->type) == TAB_MONGO);
+ PGLOBAL G = NULL;
+
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
+ sep = GetStringTableOption(g, topt, "Separator", ".");
+ strfy = GetStringTableOption(g, topt, "Stringify", NULL);
+ sz = GetIntegerTableOption(g, topt, "Jsize", 1024);
+ limit = GetIntegerTableOption(g, topt, "Limit", 50);
+
+ /*********************************************************************/
+ /* Open the input file. */
+ /*********************************************************************/
+ tdp = new(g) JSONDEF;
+#if defined(ZIP_SUPPORT)
+ tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
+ tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false);
+#endif // ZIP_SUPPORT
+ tdp->Fn = GetStringTableOption(g, topt, "Filename", NULL);
+
+ if (!tdp->Fn && topt->http) {
+ tdp->Fn = GetStringTableOption(g, topt, "Subtype", NULL);
+ topt->subtype = NULL;
+ } // endif fn
+
+ if (!(tdp->Database = SetPath(g, db)))
+ return 0;
+
+ if ((tdp->Objname = GetStringTableOption(g, topt, "Object", NULL))) {
+ if (*tdp->Objname == '$') tdp->Objname++;
+ if (*tdp->Objname == '.') tdp->Objname++;
+ } // endif Objname
+
+ tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0;
+ tdp->Pretty = GetIntegerTableOption(g, topt, "Pretty", 2);
+ tdp->Xcol = GetStringTableOption(g, topt, "Expand", NULL);
+ tdp->Accept = GetBooleanTableOption(g, topt, "Accept", false);
+ tdp->Uri = (dsn && *dsn ? dsn : NULL);
+
+ if (!tdp->Fn && !tdp->Uri) {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return 0;
+ } else
+ topt->subtype = NULL;
+
+ if (tdp->Fn) {
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, tdp->Fn, tdp->GetPath());
+ tdp->Fn = PlugDup(g, filename);
+ } // endif Fn
+
+ if (trace(1))
+ htrc("File %s objname=%s pretty=%d lvl=%d\n",
+ tdp->Fn, tdp->Objname, tdp->Pretty, lvl);
+
+ if (tdp->Uri) {
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+ tdp->Collname = GetStringTableOption(g, topt, "Tabname", NULL);
+ tdp->Schema = GetStringTableOption(g, topt, "Dbname", "test");
+ tdp->Options = (PSZ)GetStringTableOption(g, topt, "Colist", "all");
+ tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false);
+ tdp->Driver = (PSZ)GetStringTableOption(g, topt, "Driver", NULL);
+ tdp->Version = GetIntegerTableOption(g, topt, "Version", 3);
+ tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper",
+ (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface");
+ tdp->Pretty = 0;
+#else // !MONGO_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return 0;
+#endif // !MONGO_SUPPORT
+ } // endif Uri
+
+ if (tdp->Pretty == 2) {
+ if (tdp->Zipped) {
+#if defined(ZIP_SUPPORT)
+ tjsp = new(g) TDBJSON(tdp, new(g) UNZFAM(tdp));
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return 0;
+#endif // !ZIP_SUPPORT
+ } else
+ tjsp = new(g) TDBJSON(tdp, new(g) MAPFAM(tdp));
+
+ if (tjsp->MakeDocument(g))
+ return 0;
+
+ jsp = (tjsp->GetDoc()) ? tjsp->GetDoc()->GetArrayValue(0) : NULL;
+ } else {
+ if (!(tdp->Lrecl = GetIntegerTableOption(g, topt, "Lrecl", 0)))
+ {
+ if (!mgo && !tdp->Uri) {
+ sprintf(g->Message, "LRECL must be specified for pretty=%d", tdp->Pretty);
+ return 0;
+ } else
+ tdp->Lrecl = 8192; // Should be enough
+ }
+
+ tdp->Ending = GetIntegerTableOption(g, topt, "Ending", CRLF);
+
+ if (tdp->Zipped) {
+#if defined(ZIP_SUPPORT)
+ tjnp = new(g)TDBJSN(tdp, new(g) UNZFAM(tdp));
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } else if (tdp->Uri) {
+ if (tdp->Driver && toupper(*tdp->Driver) == 'C') {
+#if defined(CMGO_SUPPORT)
+ tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp));
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "C");
+ return 0;
+#endif
+ } else if (tdp->Driver && toupper(*tdp->Driver) == 'J') {
+#if defined(JAVA_SUPPORT)
+ tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp));
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "Java");
+ return 0;
+#endif
+ } else { // Driver not specified
+#if defined(CMGO_SUPPORT)
+ tjnp = new(g) TDBJSN(tdp, new(g) CMGFAM(tdp));
+#elif defined(JAVA_SUPPORT)
+ tjnp = new(g) TDBJSN(tdp, new(g) JMGFAM(tdp));
+#else
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return 0;
+#endif
+ } // endif Driver
+
+ } else if (tdp->Pretty >= 0)
+ tjnp = new(g) TDBJSN(tdp, new(g) DOSFAM(tdp));
+ else
+ tjnp = new(g) TDBJSN(tdp, new(g) BINFAM(tdp));
+
+ tjnp->SetMode(MODE_READ);
+
+ // Allocate the parse work memory
+ G = PlugInit(NULL, (size_t)tdp->Lrecl * (tdp->Pretty >= 0 ? 10 : 2));
+ tjnp->SetG(G);
+
+ if (tjnp->OpenDB(g))
+ return 0;
+
+ switch (tjnp->ReadDB(g)) {
+ case RC_EF:
+ strcpy(g->Message, "Void json table");
+ case RC_FX:
+ goto err;
+ default:
+ if (tdp->Pretty != 2)
+ reclg = strlen(tjnp->To_Line);
+
+ jsp = tjnp->Row;
+ } // endswitch ReadDB
+
+ } // endif pretty
+
+ if (!(row = (jsp) ? jsp->GetObject() : NULL)) {
+ strcpy(g->Message, "Can only retrieve columns from object rows");
+ goto err;
+ } // endif row
+
+ all = GetBooleanTableOption(g, topt, "Fullarray", false);
+ jcol.Name = jcol.Fmt = NULL;
+ jcol.Next = NULL;
+ jcol.Found = true;
+ colname[0] = 0;
+
+ if (!tdp->Uri) {
+ fmt[0] = '$';
+ fmt[1] = '.';
+ bf = 2;
+ } // endif Uri
+
+ /*********************************************************************/
+ /* Analyse the JSON tree and define columns. */
+ /*********************************************************************/
+ for (i = 1; ; i++) {
+ for (jpp = row->GetFirst(); jpp; jpp = jpp->Next) {
+ strncpy(colname, jpp->Key, 64);
+ fmt[bf] = 0;
+
+ if (Find(g, jpp->Val, colname, MY_MIN(lvl, 0)))
+ goto err;
+
+ } // endfor jpp
+
+ // Missing column can be null
+ for (jcp = fjcp; jcp; jcp = jcp->Next) {
+ jcp->Cbn |= !jcp->Found;
+ jcp->Found = false;
+ } // endfor jcp
+
+ if (tdp->Pretty != 2) {
+ // Read next record
+ switch (tjnp->ReadDB(g)) {
+ case RC_EF:
+ jsp = NULL;
+ break;
+ case RC_FX:
+ goto err;
+ default:
+ if (tdp->Pretty != 2 && reclg < strlen(tjnp->To_Line))
+ reclg = strlen(tjnp->To_Line);
+
+ jsp = tjnp->Row;
+ } // endswitch ReadDB
+
+ } else
+ jsp = tjsp->GetDoc()->GetArrayValue(i);
+
+ if (!(row = (jsp) ? jsp->GetObject() : NULL))
+ break;
+
+ } // endfor i
+
+ if (tdp->Pretty != 2) {
+ if (!topt->lrecl)
+ topt->lrecl = reclg + 10;
+
+ tjnp->CloseDB(g);
+ } // endif Pretty
+
+ return n;
+
+err:
+ if (tdp->Pretty != 2)
+ tjnp->CloseDB(g);
+
+ return 0;
+} // end of GetColumns
+
+bool JSONDISC::Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j)
+{
+ char *p, *pc = colname + strlen(colname);
+ int ars;
+ size_t n;
+ PJOB job;
+ PJAR jar;
+
+ if (jvp && jvp->DataType != TYPE_JSON) {
+ if (JsonAllPath() && !fmt[bf])
+ strcat(fmt, colname);
+
+ jcol.Type = jvp->DataType;
+
+ switch (jvp->DataType) {
+ case TYPE_STRG:
+ case TYPE_DTM:
+ jcol.Len = (int)strlen(jvp->Strp);
+ break;
+ case TYPE_INTG:
+ case TYPE_BINT:
+ jcol.Len = (int)strlen(jvp->GetString(g));
+ break;
+ case TYPE_DBL:
+ jcol.Len = (int)strlen(jvp->GetString(g));
+ jcol.Scale = jvp->Nd;
+ break;
+ case TYPE_BOOL:
+ jcol.Len = 1;
+ break;
+ default:
+ jcol.Len = 0;
+ break;
+ } // endswitch Type
+
+ jcol.Scale = jvp->Nd;
+ jcol.Cbn = jvp->DataType == TYPE_NULL;
+ } else if (!jvp || jvp->IsNull()) {
+ jcol.Type = TYPE_UNKNOWN;
+ jcol.Len = jcol.Scale = 0;
+ jcol.Cbn = true;
+ } else if (j < lvl && !Stringified(strfy, colname)) {
+ if (!fmt[bf])
+ strcat(fmt, colname);
+
+ p = fmt + strlen(fmt);
+ jsp = jvp->GetJson();
+
+ switch (jsp->GetType()) {
+ case TYPE_JOB:
+ job = (PJOB)jsp;
+
+ for (PJPR jrp = job->GetFirst(); jrp; jrp = jrp->Next) {
+ PCSZ k = jrp->Key;
+
+ if (*k != '$') {
+ n = sizeof(fmt) - strlen(fmt) -1;
+ strncat(strncat(fmt, sep, n), k, n - strlen(sep));
+ n = sizeof(colname) - strlen(colname) - 1;
+ strncat(strncat(colname, "_", n), k, n - 1);
+ } // endif Key
+
+ if (Find(g, jrp->Val, k, j + 1))
+ return true;
+
+ *p = *pc = 0;
+ } // endfor jrp
+
+ return false;
+ case TYPE_JAR:
+ jar = (PJAR)jsp;
+
+ if (all || (tdp->Xcol && !stricmp(tdp->Xcol, key)))
+ ars = MY_MIN(jar->GetSize(false), limit);
+ else
+ ars = MY_MIN(jar->GetSize(false), 1);
+
+ for (int k = 0; k < ars; k++) {
+ n = sizeof(fmt) - (strlen(fmt) + 1);
+
+ if (!tdp->Xcol || stricmp(tdp->Xcol, key)) {
+ sprintf(buf, "%d", k);
+
+ if (tdp->Uri) {
+ strncat(strncat(fmt, sep, n), buf, n - strlen(sep));
+ } else {
+ strncat(strncat(fmt, "[", n), buf, n - 1);
+ strncat(fmt, "]", n - (strlen(buf) + 1));
+ } // endif uri
+
+ if (all) {
+ n = sizeof(colname) - (strlen(colname) + 1);
+ strncat(strncat(colname, "_", n), buf, n - 1);
+ } // endif all
+
+ } else
+ strncat(fmt, (tdp->Uri ? sep : "[*]"), n);
+
+ if (Find(g, jar->GetArrayValue(k), "", j))
+ return true;
+
+ *p = *pc = 0;
+ } // endfor k
+
+ return false;
+ default:
+ sprintf(g->Message, "Logical error after %s", fmt);
+ return true;
+ } // endswitch Type
+
+ } else if (lvl >= 0) {
+ if (Stringified(strfy, colname)) {
+ if (!fmt[bf])
+ strcat(fmt, colname);
+
+ strcat(fmt, ".*");
+ } else if (JsonAllPath() && !fmt[bf])
+ strcat(fmt, colname);
+
+ jcol.Type = TYPE_STRG;
+ jcol.Len = sz;
+ jcol.Scale = 0;
+ jcol.Cbn = true;
+ } else
+ return false;
+
+ AddColumn(g);
+ return false;
+} // end of Find
+
+void JSONDISC::AddColumn(PGLOBAL g)
+{
+ bool b = fmt[bf] != 0; // True if formatted
+
+ // Check whether this column was already found
+ for (jcp = fjcp; jcp; jcp = jcp->Next)
+ if (!strcmp(colname, jcp->Name))
+ break;
+
+ if (jcp) {
+ if (jcp->Type != jcol.Type) {
+ if (jcp->Type == TYPE_UNKNOWN || jcp->Type == TYPE_NULL)
+ jcp->Type = jcol.Type;
+// else if (jcol.Type != TYPE_UNKNOWN && jcol.Type != TYPE_VOID)
+// jcp->Type = TYPE_STRING;
+ else if (jcp->Type != TYPE_STRG)
+ switch (jcol.Type) {
+ case TYPE_STRG:
+ case TYPE_DBL:
+ jcp->Type = jcol.Type;
+ break;
+ case TYPE_BINT:
+ if (jcp->Type == TYPE_INTG || jcp->Type == TYPE_BOOL)
+ jcp->Type = jcol.Type;
+
+ break;
+ case TYPE_INTG:
+ if (jcp->Type == TYPE_BOOL)
+ jcp->Type = jcol.Type;
+
+ break;
+ default:
+ break;
+ } // endswith Type
+
+ } // endif Type
+
+ if (b && (!jcp->Fmt || strlen(jcp->Fmt) < strlen(fmt))) {
+ jcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], strlen(fmt));
+ } // endif fmt
+
+ jcp->Len = MY_MAX(jcp->Len, jcol.Len);
+ jcp->Scale = MY_MAX(jcp->Scale, jcol.Scale);
+ jcp->Cbn |= jcol.Cbn;
+ jcp->Found = true;
+ } else if (jcol.Type != TYPE_UNKNOWN || tdp->Accept) {
+ // New column
+ jcp = (PJCL)PlugSubAlloc(g, NULL, sizeof(JCOL));
+ *jcp = jcol;
+ jcp->Cbn |= (i > 1);
+ jcp->Name = PlugDup(g, colname);
+ length[0] = MY_MAX(length[0], strlen(colname));
+
+ if (b) {
+ jcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], strlen(fmt));
+ } else
+ jcp->Fmt = NULL;
+
+ if (pjcp) {
+ jcp->Next = pjcp->Next;
+ pjcp->Next = jcp;
+ } else
+ fjcp = jcp;
+
+ n++;
+ } // endif jcp
+
+ if (jcp)
+ pjcp = jcp;
+
+} // end of AddColumn
+
+
+/* -------------------------- Class JSONDEF -------------------------- */
+
+JSONDEF::JSONDEF(void)
+{
+ Jmode = MODE_OBJECT;
+ Objname = NULL;
+ Xcol = NULL;
+ Pretty = 2;
+ Limit = 1;
+ Base = 0;
+ Strict = false;
+ Sep = '.';
+ Uri = NULL;
+ Collname = Options = Filter = NULL;
+ Pipe = false;
+ Driver = NULL;
+ Version = 0;
+ Wrapname = NULL;
+} // end of JSONDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values. */
+/***********************************************************************/
+bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ Schema = GetStringCatInfo(g, "DBname", Schema);
+ Jmode = (JMODE)GetIntCatInfo("Jmode", MODE_OBJECT);
+
+ if ((Objname = GetStringCatInfo(g, "Object", NULL))) {
+ if (*Objname == '$') Objname++;
+ if (*Objname == '.') Objname++;
+ } // endif Objname
+
+ Xcol = GetStringCatInfo(g, "Expand", NULL);
+ Pretty = GetIntCatInfo("Pretty", 2);
+ Limit = GetIntCatInfo("Limit", 50);
+ Base = GetIntCatInfo("Base", 0) ? 1 : 0;
+ Sep = *GetStringCatInfo(g, "Separator", ".");
+ Accept = GetBoolCatInfo("Accept", false);
+
+ // Don't use url as MONGO uri when called from REST
+ if (stricmp(am, "REST") && (Uri = GetStringCatInfo(g, "Connect", NULL))) {
+#if defined(JAVA_SUPPORT) || defined(CMGO_SUPPORT)
+ Collname = GetStringCatInfo(g, "Name",
+ (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
+ Collname = GetStringCatInfo(g, "Tabname", Collname);
+ Options = GetStringCatInfo(g, "Colist", Xcol ? "all" : NULL);
+ Filter = GetStringCatInfo(g, "Filter", NULL);
+ Pipe = GetBoolCatInfo("Pipeline", false);
+ Driver = GetStringCatInfo(g, "Driver", NULL);
+ Version = GetIntCatInfo("Version", 3);
+ Pretty = 0;
+#if defined(JAVA_SUPPORT)
+ if (Version == 2)
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface");
+ else
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface");
+#endif // JAVA_SUPPORT
+#else // !MONGO_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return true;
+#endif // !MONGO_SUPPORT
+ } // endif Uri
+
+ return DOSDEF::DefineAM(g, (Uri ? "XMGO" : "DOS"), poff);
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB JSONDEF::GetTable(PGLOBAL g, MODE m)
+{
+ if (trace(1))
+ htrc("JSON GetTable Pretty=%d Uri=%s\n", Pretty, SVP(Uri));
+
+ if (Catfunc == FNC_COL)
+ return new(g)TDBJCL(this);
+
+ PTDBASE tdbp;
+ PTXF txfp = NULL;
+
+ // JSN not used for pretty=1 for insert or delete
+ if (Pretty <= 0 || (Pretty == 1 && (m == MODE_READ || m == MODE_UPDATE))) {
+ USETEMP tmp = UseTemp();
+ bool map = Mapped && Pretty >= 0 && m != MODE_INSERT &&
+ !(tmp != TMP_NO && m == MODE_UPDATE) &&
+ !(tmp == TMP_FORCE &&
+ (m == MODE_UPDATE || m == MODE_DELETE));
+
+ if (Uri) {
+ if (Driver && toupper(*Driver) == 'C') {
+#if defined(CMGO_SUPPORT)
+ txfp = new(g) CMGFAM(this);
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "C");
+ return NULL;
+#endif
+ } else if (Driver && toupper(*Driver) == 'J') {
+#if defined(JAVA_SUPPORT)
+ txfp = new(g) JMGFAM(this);
+#else
+ sprintf(g->Message, "Mongo %s Driver not available", "Java");
+ return NULL;
+#endif
+ } else { // Driver not specified
+#if defined(CMGO_SUPPORT)
+ txfp = new(g) CMGFAM(this);
+#elif defined(JAVA_SUPPORT)
+ txfp = new(g) JMGFAM(this);
+#else // !MONGO_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "MONGO");
+ return NULL;
+#endif // !MONGO_SUPPORT
+ } // endif Driver
+
+ Pretty = 4; // Not a file
+ } else if (Zipped) {
+#if defined(ZIP_SUPPORT)
+ if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
+ txfp = new(g) UNZFAM(this);
+ } else if (m == MODE_INSERT) {
+ txfp = new(g) ZIPFAM(this);
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's m
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } else if (Compressed) {
+#if defined(GZ_SUPPORT)
+ if (Compressed == 1)
+ txfp = new(g) GZFAM(this);
+ else
+ txfp = new(g) ZLBFAM(this);
+#else // !GZ_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "GZ");
+ return NULL;
+#endif // !GZ_SUPPORT
+ } else if (map)
+ txfp = new(g) MAPFAM(this);
+ else if (Pretty < 0) // BJsonfile
+ txfp = new(g) BINFAM(this);
+ else
+ txfp = new(g) DOSFAM(this);
+
+ // Txfp must be set for TDBJSN
+ tdbp = new(g) TDBJSN(this, txfp);
+
+ if (Lrecl) {
+ // Allocate the parse work memory
+#if 0
+ PGLOBAL G = (PGLOBAL)PlugSubAlloc(g, NULL, sizeof(GLOBAL));
+ memset(G, 0, sizeof(GLOBAL));
+ G->Sarea_Size = (size_t)Lrecl * 10;
+ G->Sarea = PlugSubAlloc(g, NULL, G->Sarea_Size);
+ PlugSubSet(G->Sarea, G->Sarea_Size);
+ G->jump_level = 0;
+ ((TDBJSN*)tdbp)->G = G;
+#endif // 0
+ ((TDBJSN*)tdbp)->G = PlugInit(NULL, (size_t)Lrecl * (Pretty >= 0 ? 12 : 4));
+ } else {
+ strcpy(g->Message, "LRECL is not defined");
+ return NULL;
+ } // endif Lrecl
+
+ } else {
+ if (Zipped) {
+#if defined(ZIP_SUPPORT)
+ if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) {
+ txfp = new(g) UNZFAM(this);
+ } else if (m == MODE_INSERT) {
+ strcpy(g->Message, "INSERT supported only for zipped JSON when pretty=0");
+ return NULL;
+ } else {
+ strcpy(g->Message, "UPDATE/DELETE not supported for ZIP");
+ return NULL;
+ } // endif's m
+#else // !ZIP_SUPPORT
+ sprintf(g->Message, MSG(NO_FEAT_SUPPORT), "ZIP");
+ return NULL;
+#endif // !ZIP_SUPPORT
+ } else
+ txfp = new(g) MAPFAM(this);
+
+ tdbp = new(g) TDBJSON(this, txfp);
+ ((TDBJSON*)tdbp)->G = g;
+ } // endif Pretty
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+
+ return tdbp;
+} // end of GetTable
+
+/* --------------------------- Class TDBJSN -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBJSN class (Pretty < 2) */
+/***********************************************************************/
+TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
+{
+ G = NULL;
+ Top = NULL;
+ Row = NULL;
+ Val = NULL;
+ Colp = NULL;
+
+ if (tdp) {
+ Jmode = tdp->Jmode;
+ Objname = tdp->Objname;
+ Xcol = tdp->Xcol;
+ Limit = tdp->Limit;
+ Pretty = tdp->Pretty;
+ B = tdp->Base ? 1 : 0;
+ Sep = tdp->Sep;
+ Strict = tdp->Strict;
+ } else {
+ Jmode = MODE_OBJECT;
+ Objname = NULL;
+ Xcol = NULL;
+ Limit = 1;
+ Pretty = 0;
+ B = 0;
+ Sep = '.';
+ Strict = false;
+ } // endif tdp
+
+ Fpos = -1;
+ N = M = 0;
+ NextSame = 0;
+ SameRow = 0;
+ Xval = -1;
+ Comma = false;
+} // end of TDBJSN standard constructor
+
+TDBJSN::TDBJSN(TDBJSN* tdbp) : TDBDOS(NULL, tdbp)
+{
+ G = NULL;
+ Top = tdbp->Top;
+ Row = tdbp->Row;
+ Val = tdbp->Val;
+ Colp = tdbp->Colp;
+ Jmode = tdbp->Jmode;
+ Objname = tdbp->Objname;
+ Xcol = tdbp->Xcol;
+ Fpos = tdbp->Fpos;
+ N = tdbp->N;
+ M = tdbp->M;
+ Limit = tdbp->Limit;
+ NextSame = tdbp->NextSame;
+ SameRow = tdbp->SameRow;
+ Xval = tdbp->Xval;
+ B = tdbp->B;
+ Sep = tdbp->Sep;
+ Pretty = tdbp->Pretty;
+ Strict = tdbp->Strict;
+ Comma = tdbp->Comma;
+} // end of TDBJSN copy constructor
+
+// Used for update
+PTDB TDBJSN::Clone(PTABS t)
+{
+ G = NULL;
+ PTDB tp;
+ PJCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBJSN(this);
+
+ for (cp1 = (PJCOL)Columns; cp1; cp1 = (PJCOL)cp1->GetNext()) {
+ cp2 = new(g) JSONCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+} // end of Clone
+
+/***********************************************************************/
+/* Allocate JSN column description block. */
+/***********************************************************************/
+PCOL TDBJSN::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ PJCOL colp = new(g) JSONCOL(g, cdp, this, cprec, n);
+
+ return (colp->ParseJpath(g)) ? NULL : colp;
+} // end of MakeCol
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBJSN::InsertSpecialColumn(PCOL colp)
+{
+ if (!colp->IsSpecial())
+ return NULL;
+
+//if (Xcol && ((SPCBLK*)colp)->GetRnm())
+// colp->SetKey(0); // Rownum is no more a key
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+} // end of InsertSpecialColumn
+
+#if 0
+/***********************************************************************/
+/* JSON Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBJSN::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 0;
+ else if (Cardinal < 0) {
+ Cardinal = TDBDOS::Cardinality(g);
+
+ } // endif Cardinal
+
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* JSON GetMaxSize: returns file size estimate in number of lines. */
+/***********************************************************************/
+int TDBJSN::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = TDBDOS::GetMaxSize(g) * ((Xcol) ? Limit : 1);
+
+ return MaxSize;
+} // end of GetMaxSize
+#endif // 0
+
+/***********************************************************************/
+/* JSON EstimatedLength. Returns an estimated minimum line length. */
+/***********************************************************************/
+int TDBJSN::EstimatedLength(void)
+{
+ if (AvgLen <= 0)
+ return (Lrecl ? Lrecl : 1024) / 8; // TODO: make it better
+ else
+ return AvgLen;
+
+} // end of Estimated Length
+
+/***********************************************************************/
+/* Find the row in the tree structure. */
+/***********************************************************************/
+PJSON TDBJSN::FindRow(PGLOBAL g)
+{
+ char *p, *objpath = PlugDup(g, Objname);
+ char *sep = (char*)(Sep == ':' ? ":[" : ".[");
+ bool bp = false, b = false;
+ PJSON jsp = Row;
+ PJVAL val = NULL;
+
+ for (; jsp && objpath; objpath = p, bp = b) {
+ if ((p = strpbrk(objpath + 1, sep))) {
+ b = (*p == '[');
+ *p++ = 0;
+ } // endif p
+
+ if (!bp && *objpath != '[' && !IsNum(objpath)) { // objpass is a key
+ val = (jsp->GetType() == TYPE_JOB) ?
+ jsp->GetObject()->GetKeyValue(objpath) : NULL;
+ } else {
+ if (bp || *objpath == '[') {
+ if (objpath[strlen(objpath) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path %s", Objname);
+ return NULL;
+ } else if (!bp)
+ objpath++;
+
+ } // endif [
+
+ val = (jsp->GetType() == TYPE_JAR) ?
+ jsp->GetArray()->GetArrayValue(atoi(objpath) - B) : NULL;
+ } // endif objpath
+
+ jsp = (val) ? val->GetJson() : NULL;
+ } // endfor objpath
+
+ if (jsp && jsp->GetType() != TYPE_JOB) {
+ if (jsp->GetType() == TYPE_JAR) {
+ jsp = jsp->GetArray()->GetArrayValue(B);
+
+ if (jsp->GetType() != TYPE_JOB)
+ jsp = NULL;
+
+ } else
+ jsp = NULL;
+
+ } // endif Type
+
+ return jsp;
+} // end of FindRow
+
+/***********************************************************************/
+/* OpenDB: Data Base open routine for JSN access method. */
+/***********************************************************************/
+bool TDBJSN::OpenDB(PGLOBAL g)
+{
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open replace it at its beginning. */
+ /*******************************************************************/
+ Fpos= -1;
+ NextSame = 0;
+ SameRow = 0;
+ } else {
+ /*******************************************************************/
+ /* First opening. */
+ /*******************************************************************/
+ if (Mode == MODE_INSERT)
+ switch (Jmode) {
+ case MODE_OBJECT: Row = new(g) JOBJECT; break;
+ case MODE_ARRAY: Row = new(g) JARRAY; break;
+ case MODE_VALUE: Row = new(g) JVALUE; break;
+ default:
+ sprintf(g->Message, "Invalid Jmode %d", Jmode);
+ return true;
+ } // endswitch Jmode
+
+ } // endif Use
+
+ if (Pretty < 0) {
+ /*******************************************************************/
+ /* Binary BJSON table. */
+ /*******************************************************************/
+ xtrc(1, "JSN OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ if (!To_Kindex) {
+ Txfp->Rewind(); // see comment in Work.log
+ } else // Table is to be accessed through a sorted index table
+ To_Kindex->Reset();
+
+ return false;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open according to logical input/output mode required. */
+ /* Use conventionnal input/output functions. */
+ /*********************************************************************/
+ if (Txfp->OpenTableFile(g))
+ return true;
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Lrecl is Ok. */
+ /*********************************************************************/
+
+ MODE mode = Mode;
+
+ // Buffer must be allocated in g->Sarea
+ Mode = MODE_ANY;
+ Txfp->AllocateBuffer(g);
+ Mode = mode;
+
+ //To_Line = (char*)PlugSubAlloc(g, NULL, linelen);
+ //memset(To_Line, 0, linelen);
+ To_Line = Txfp->GetBuf();
+ xtrc(1, "OpenJSN: R%hd mode=%d To_Line=%p\n", Tdb_No, Mode, To_Line);
+ return false;
+ } else if (TDBDOS::OpenDB(g))
+ return true;
+
+ if (Xcol)
+ To_Filter = NULL; // Imcompatible
+
+ return false;
+} // end of OpenDB
+
+/***********************************************************************/
+/* SkipHeader: Physically skip first header line if applicable. */
+/* This is called from TDBDOS::OpenDB and must be executed before */
+/* Kindex construction if the file is accessed using an index. */
+/***********************************************************************/
+bool TDBJSN::SkipHeader(PGLOBAL g)
+{
+ int len = GetFileLength(g);
+ bool rc = false;
+
+#if defined(_DEBUG)
+ if (len < 0)
+ return true;
+#endif // _DEBUG
+
+ if (Pretty == 1) {
+ if (Mode == MODE_INSERT || Mode == MODE_DELETE) {
+ // Mode Insert and delete are no more handled here
+ DBUG_ASSERT(false);
+ } else if (len > 0) // !Insert && !Delete
+ rc = (Txfp->SkipRecord(g, false) == RC_FX || Txfp->RecordPos(g));
+
+ } // endif Pretty
+
+ return rc;
+} // end of SkipHeader
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for JSN access method. */
+/***********************************************************************/
+int TDBJSN::ReadDB(PGLOBAL g) {
+ int rc;
+
+ N++;
+
+ if (NextSame) {
+ SameRow = NextSame;
+ NextSame = 0;
+ M++;
+ return RC_OK;
+ } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK) {
+ if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK))
+ return rc; // Deferred reading failed
+
+ if (Pretty >= 0) {
+ // Recover the memory used for parsing
+ PlugSubSet(G->Sarea, G->Sarea_Size);
+
+ if ((Row = ParseJson(G, To_Line, strlen(To_Line), &Pretty, &Comma))) {
+ Row = FindRow(g);
+ SameRow = 0;
+ Fpos++;
+ M = 1;
+ rc = RC_OK;
+ } else if (Pretty != 1 || strcmp(To_Line, "]")) {
+ strcpy(g->Message, G->Message);
+ rc = RC_FX;
+ } else
+ rc = RC_EF;
+
+ } else {
+ // Here we get a movable Json binary tree
+ PJSON jsp;
+ SWAP* swp;
+
+ jsp = (PJSON)To_Line;
+ swp = new(g) SWAP(G, jsp);
+ swp->SwapJson(jsp, false); // Restore pointers from offsets
+ Row = jsp;
+ Row = FindRow(g);
+ SameRow = 0;
+ Fpos++;
+ M = 1;
+ rc = RC_OK;
+ } // endif Pretty
+
+ } // endif ReadDB
+
+ return rc;
+} // end of ReadDB
+
+/***********************************************************************/
+/* Make the top tree from the object path. */
+/***********************************************************************/
+bool TDBJSN::MakeTopTree(PGLOBAL g, PJSON jsp)
+{
+ if (Objname) {
+ if (!Val) {
+ // Parse and allocate Objname item(s)
+ char *p, *objpath = PlugDup(g, Objname);
+ char *sep = (char*)(Sep == ':' ? ":[" : ".[");
+ int i;
+ bool bp = false, b = false;
+ PJOB objp;
+ PJAR arp;
+ PJVAL val = NULL;
+
+ Top = NULL;
+
+ for (; objpath; objpath = p, bp = b) {
+ if ((p = strpbrk(objpath + 1, sep))) {
+ b = (*p == '[');
+ *p++ = 0;
+ } // endif p
+
+ if (!bp && *objpath != '[' && !IsNum(objpath)) {
+ objp = new(g) JOBJECT;
+
+ if (!Top)
+ Top = objp;
+
+ if (val)
+ val->SetValue(objp);
+
+ val = new(g) JVALUE;
+ objp->SetKeyValue(g, val, objpath);
+ } else {
+ if (bp || *objpath == '[') {
+ // Old style
+ if (objpath[strlen(objpath) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path %s", Objname);
+ return true;
+ } else if (!bp)
+ objpath++;
+
+ } // endif bp
+
+ arp = new(g) JARRAY;
+
+ if (!Top)
+ Top = arp;
+
+ if (val)
+ val->SetValue(arp);
+
+ val = new(g) JVALUE;
+ i = atoi(objpath) - B;
+ arp->SetArrayValue(g, val, i);
+ arp->InitArray(g);
+ } // endif objpath
+
+ } // endfor p
+
+ Val = val;
+ } // endif Val
+
+ Val->SetValue(jsp);
+ } else
+ Top = jsp;
+
+ return false;
+} // end of MakeTopTree
+
+/***********************************************************************/
+/* PrepareWriting: Prepare the line for WriteDB. */
+/***********************************************************************/
+bool TDBJSN::PrepareWriting(PGLOBAL g)
+{
+ PSZ s;
+
+ if (MakeTopTree(g, Row))
+ return true;
+
+ if ((s = Serialize(G, Top, NULL, Pretty))) {
+ if (Comma)
+ strcat(s, ",");
+
+ if ((signed)strlen(s) > Lrecl) {
+ strncpy(To_Line, s, Lrecl);
+ sprintf(g->Message, "Line truncated (lrecl=%d)", Lrecl);
+ return PushWarning(g, this);
+ } else
+ strcpy(To_Line, s);
+
+ return false;
+ } else
+ return true;
+
+} // end of PrepareWriting
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for JSON access method. */
+/***********************************************************************/
+int TDBJSN::WriteDB(PGLOBAL g)
+{
+ int rc = TDBDOS::WriteDB(g);
+
+ PlugSubSet(G->Sarea, G->Sarea_Size);
+ Row->Clear();
+ return rc;
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base close routine for JSON access method. */
+/***********************************************************************/
+void TDBJSN::CloseDB(PGLOBAL g)
+{
+ TDBDOS::CloseDB(g);
+ G = PlugExit(G);
+} // end of CloseDB
+
+ /* ---------------------------- JSONCOL ------------------------------ */
+
+/***********************************************************************/
+/* JSONCOL public constructor. */
+/***********************************************************************/
+JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : DOSCOL(g, cdp, tdbp, cprec, i, "DOS")
+{
+ Tjp = (TDBJSN *)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
+ G = Tjp->G;
+ Jpath = cdp->GetFmt();
+ MulVal = NULL;
+ Nodes = NULL;
+ Nod = 0;
+ Sep = Tjp->Sep;
+ Xnod = -1;
+ Xpd = false;
+ Parsed = false;
+ Warned = false;
+ Sgfy = false;
+} // end of JSONCOL constructor
+
+/***********************************************************************/
+/* JSONCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
+{
+ G = col1->G;
+ Tjp = col1->Tjp;
+ Jpath = col1->Jpath;
+ MulVal = col1->MulVal;
+ Nodes = col1->Nodes;
+ Nod = col1->Nod;
+ Sep = col1->Sep;
+ Xnod = col1->Xnod;
+ Xpd = col1->Xpd;
+ Parsed = col1->Parsed;
+ Warned = col1->Warned;
+ Sgfy = col1->Sgfy;
+} // end of JSONCOL copy constructor
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool JSONCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+{
+ if (DOSCOL::SetBuffer(g, value, ok, check))
+ return true;
+
+ // Parse the json path
+ if (ParseJpath(g))
+ return true;
+
+ Tjp = (TDBJSN*)To_Tdb;
+ G = Tjp->G;
+ return false;
+} // end of SetBuffer
+
+/***********************************************************************/
+/* Check whether this object is expanded. */
+/***********************************************************************/
+bool JSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b)
+{
+ if ((Tjp->Xcol && nm && !strcmp(nm, Tjp->Xcol) &&
+ (Tjp->Xval < 0 || Tjp->Xval == i)) || Xpd) {
+ Xpd = true; // Expandable object
+ Nodes[i].Op = OP_EXP;
+ } else if (b) {
+ strcpy(g->Message, "Cannot expand more than one branch");
+ return true;
+ } // endif Xcol
+
+ return false;
+} // end of CheckExpand
+
+/***********************************************************************/
+/* Analyse array processing options. */
+/***********************************************************************/
+bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
+{
+ int n;
+ bool dg = true, b = false;
+ PJNODE jnp = &Nodes[i];
+
+ //if (*p == '[') p++; // Old syntax .[ or :[
+ n = (int)strlen(p);
+
+ if (*p) {
+ if (p[n - 1] == ']') {
+ p[--n] = 0;
+ } else if (!IsNum(p)) {
+ // Wrong array specification
+ sprintf(g->Message, "Invalid array specification %s for %s", p, Name);
+ return true;
+ } // endif p
+
+ } else
+ b = true;
+
+ // To check whether a numeric Rank was specified
+ dg = IsNum(p);
+
+ if (!n) {
+ // Default specifications
+ if (CheckExpand(g, i, nm, false))
+ return true;
+ else if (jnp->Op != OP_EXP) {
+ if (b) {
+ // Return 1st value (B is the index base)
+ jnp->Rank = Tjp->B;
+ jnp->Op = OP_EQ;
+ } else if (!Value->IsTypeNum()) {
+ jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING);
+ jnp->Op = OP_CNC;
+ } else
+ jnp->Op = OP_ADD;
+
+ } // endif OP
+
+ } else if (dg) {
+ // Return nth value
+ jnp->Rank = atoi(p) - Tjp->B;
+ jnp->Op = OP_EQ;
+ } else if (n == 1) {
+ // Set the Op value;
+ if (Sep == ':')
+ switch (*p) {
+ case '*': *p = 'x'; break;
+ case 'x':
+ case 'X': *p = '*'; break; // Expand this array
+ default: break;
+ } // endswitch p
+
+ switch (*p) {
+ case '+': jnp->Op = OP_ADD; break;
+ case 'x': jnp->Op = OP_MULT; break;
+ case '>': jnp->Op = OP_MAX; break;
+ case '<': jnp->Op = OP_MIN; break;
+ case '!': jnp->Op = OP_SEP; break; // Average
+ case '#': jnp->Op = OP_NUM; break;
+ case '*': // Expand this array
+ if (!Tjp->Xcol && nm) {
+ Xpd = true;
+ jnp->Op = OP_EXP;
+ Tjp->Xval = i;
+ Tjp->Xcol = nm;
+ } else if (CheckExpand(g, i, nm, true))
+ return true;
+
+ break;
+ default:
+ sprintf(g->Message,
+ "Invalid function specification %c for %s", *p, Name);
+ return true;
+ } // endswitch *p
+
+ } else if (*p == '"' && p[n - 1] == '"') {
+ // This is a concat specification
+ jnp->Op = OP_CNC;
+
+ if (n > 2) {
+ // Set concat intermediate string
+ p[n - 1] = 0;
+ jnp->CncVal = AllocateValue(g, p + 1, TYPE_STRING);
+ } // endif n
+
+ } else {
+ sprintf(g->Message, "Wrong array specification for %s", Name);
+ return true;
+ } // endif's
+
+ // For calculated arrays, a local Value must be used
+ switch (jnp->Op) {
+ case OP_NUM:
+ jnp->Valp = AllocateValue(g, TYPE_INT);
+ break;
+ case OP_ADD:
+ case OP_MULT:
+ case OP_SEP:
+ if (!IsTypeChar(Buf_Type))
+ jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
+ else
+ jnp->Valp = AllocateValue(g, TYPE_DOUBLE, 0, 2);
+
+ break;
+ case OP_MIN:
+ case OP_MAX:
+ jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
+ break;
+ case OP_CNC:
+ if (IsTypeChar(Buf_Type))
+ jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
+ else
+ jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
+
+ break;
+ default:
+ break;
+ } // endswitch Op
+
+ if (jnp->Valp)
+ MulVal = AllocateValue(g, jnp->Valp);
+
+ return false;
+} // end of SetArrayOptions
+
+/***********************************************************************/
+/* Parse the eventual passed Jpath information. */
+/* This information can be specified in the Fieldfmt column option */
+/* when creating the table. It permits to indicate the position of */
+/* the node corresponding to that column. */
+/***********************************************************************/
+bool JSONCOL::ParseJpath(PGLOBAL g)
+{
+ char *p, *p1 = NULL, *p2 = NULL, *pbuf = NULL;
+ int i;
+ bool a;
+
+ if (Parsed)
+ return false; // Already done
+ else if (InitValue(g))
+ return true;
+ else if (!Jpath)
+ Jpath = Name;
+
+ if (To_Tdb->GetOrig()) {
+ // This is an updated column, get nodes from origin
+ for (PJCOL colp = (PJCOL)Tjp->GetColumns(); colp;
+ colp = (PJCOL)colp->GetNext())
+ if (!stricmp(Name, colp->GetName())) {
+ Nod = colp->Nod;
+ Nodes = colp->Nodes;
+ Xpd = colp->Xpd;
+ goto fin;
+ } // endif Name
+
+ sprintf(g->Message, "Cannot parse updated column %s", Name);
+ return true;
+ } // endif To_Orig
+
+ pbuf = PlugDup(g, Jpath);
+ if (*pbuf == '$') pbuf++;
+ if (*pbuf == Sep) pbuf++;
+ if (*pbuf == '[') p1 = pbuf++;
+
+ // Estimate the required number of nodes
+ for (i = 0, p = pbuf; (p = NextChr(p, Sep)); i++, p++)
+ Nod++; // One path node found
+
+ Nodes = (PJNODE)PlugSubAlloc(g, NULL, (++Nod) * sizeof(JNODE));
+ memset(Nodes, 0, (Nod) * sizeof(JNODE));
+
+ // Analyze the Jpath for this column
+ for (i = 0, p = pbuf; p && i < Nod; i++, p = (p2 ? p2 : NULL)) {
+ a = (p1 != NULL);
+ p1 = strchr(p, '[');
+ p2 = strchr(p, Sep);
+
+ if (!p2)
+ p2 = p1;
+ else if (p1) {
+ if (p1 < p2)
+ p2 = p1;
+ else if (p1 == p2 + 1)
+ *p2++ = 0; // Old syntax .[ or :[
+ else
+ p1 = NULL;
+
+ } // endif p1
+
+ if (p2)
+ *p2++ = 0;
+
+ // Jpath must be explicit
+ if (a || *p == 0 || *p == '[' || IsNum(p)) {
+ // Analyse intermediate array processing
+ if (SetArrayOptions(g, p, i, Nodes[i - 1].Key))
+ return true;
+ else if (Xpd && Tjp->Mode == MODE_DELETE) {
+ strcpy(g->Message, "Cannot delete expanded columns");
+ return true;
+ } // endif Xpd
+
+ } else if (*p == '*') {
+ // Return JSON
+ Nodes[i].Op = OP_XX;
+ } else {
+ Nodes[i].Key = p;
+ Nodes[i].Op = OP_EXIST;
+ } // endif's
+
+ } // endfor i, p
+
+ Nod = i;
+
+fin:
+ MulVal = AllocateValue(g, Value);
+ Parsed = true;
+ return false;
+} // end of ParseJpath
+
+/***********************************************************************/
+/* Get Jpath converted to Mongo path. */
+/***********************************************************************/
+PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj)
+{
+ if (Jpath) {
+ char *p1, *p2, *mgopath;
+ int i = 0;
+
+ if (strcmp(Jpath, "*")) {
+ p1 = Jpath;
+ if (*p1 == '$') p1++;
+ if (*p1 == '.') p1++;
+ mgopath = PlugDup(g, p1);
+ } else {
+ Sgfy = true;
+ return NULL;
+ } // endif
+
+ for (p1 = p2 = mgopath; *p1; p1++)
+ {
+ if (i) { // Inside []
+ if (isdigit(*p1)) {
+ if (!proj)
+ *p2++ = *p1;
+
+ } else if (*p1 == ']' && i == 1) {
+ if (proj && p1[1] == '.')
+ p1++;
+
+ i = 0;
+ } else if (*p1 == '.' && i == 2) {
+ if (!proj)
+ *p2++ = '.';
+
+ i = 0;
+ } else if (!proj)
+ return NULL;
+
+ } else switch (*p1) {
+ case ':':
+ case '.':
+ if (isdigit(p1[1]))
+ i = 2;
+
+ *p2++ = '.';
+ break;
+ case '[':
+ if (*(p2 - 1) != '.')
+ *p2++ = '.';
+
+ i = 1;
+ break;
+ case '*':
+ if (*(p2 - 1) == '.' && !*(p1 + 1)) {
+ p2--; // Suppress last :*
+ Sgfy = true;
+ break;
+ } // endif p2
+ /* falls through */
+ default:
+ *p2++ = *p1;
+ break;
+ } // endswitch p1;
+ }
+
+ if (*(p2 - 1) == '.')
+ p2--;
+
+ *p2 = 0;
+ return mgopath;
+ } else
+ return NULL;
+
+} // end of GetJpath
+
+/***********************************************************************/
+/* MakeJson: Serialize the json item and set value to it. */
+/***********************************************************************/
+PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp, int n)
+{
+ if (Value->IsTypeNum()) {
+ strcpy(g->Message, "Cannot make Json for a numeric column");
+
+ if (!Warned) {
+ PushWarning(g, Tjp);
+ Warned = true;
+ } // endif Warned
+
+ Value->Reset();
+ return Value;
+#if 0
+ } else if (Value->GetType() == TYPE_BIN) {
+ if ((unsigned)Value->GetClen() >= sizeof(BSON)) {
+ ulong len = Tjp->Lrecl ? Tjp->Lrecl : 500;
+ PBSON bsp = JbinAlloc(g, NULL, len, jsp);
+
+ strcat(bsp->Msg, " column");
+ ((BINVAL*)Value)->SetBinValue(bsp, sizeof(BSON));
+ } else {
+ strcpy(g->Message, "Column size too small");
+ Value->SetValue_char(NULL, 0);
+ } // endif Clen
+#endif // 0
+ } else if (n < Nod - 1) {
+ if (jsp->GetType() == TYPE_JAR) {
+ int ars = jsp->GetSize(false);
+ PJNODE jnp = &Nodes[n];
+ PJAR jvp = new(g) JARRAY;
+
+ for (jnp->Rank = 0; jnp->Rank < ars; jnp->Rank++)
+ jvp->AddArrayValue(g, GetRowValue(g, jsp, n));
+
+ jnp->Rank = 0;
+ jvp->InitArray(g);
+ jsp = jvp;
+ } else if (jsp->Type == TYPE_JOB) {
+ PJOB jvp = new(g) JOBJECT;
+
+ for (PJPR prp = ((PJOB)jsp)->GetFirst(); prp; prp = prp->Next)
+ jvp->SetKeyValue(g, GetRowValue(g, prp->Val, n + 1), prp->Key);
+
+ jsp = jvp;
+ } // endif Type
+
+ } // endif
+
+ Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
+ return Value;
+} // end of MakeJson
+
+/***********************************************************************/
+/* GetRowValue: */
+/***********************************************************************/
+PJVAL JSONCOL::GetRowValue(PGLOBAL g, PJSON row, int i)
+{
+ PJVAL val = NULL;
+
+ for (; i < Nod && row; i++) {
+ switch (row->GetType()) {
+ case TYPE_JOB:
+ val = (Nodes[i].Key) ? ((PJOB)row)->GetKeyValue(Nodes[i].Key) : NULL;
+ break;
+ case TYPE_JAR:
+ val = ((PJAR)row)->GetArrayValue(Nodes[i].Rank);
+ break;
+ case TYPE_JVAL:
+ val = (PJVAL)row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+ val = NULL;
+ } // endswitch Type
+
+ if (i < Nod-1)
+ row = (val) ? val->GetJson() : NULL;
+
+ } // endfor i
+
+ return val;
+} // end of GetRowValue
+
+/***********************************************************************/
+/* SetValue: Set a value from a JVALUE contains. */
+/***********************************************************************/
+void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL jvp)
+{
+ if (jvp) {
+ vp->SetNull(false);
+
+ switch (jvp->GetValType()) {
+ case TYPE_STRG:
+ case TYPE_INTG:
+ case TYPE_BINT:
+ case TYPE_DBL:
+ case TYPE_DTM:
+ switch (vp->GetType()) {
+ case TYPE_STRING:
+ vp->SetValue_psz(jvp->GetString(g));
+ break;
+ case TYPE_INT:
+ case TYPE_SHORT:
+ case TYPE_TINY:
+ vp->SetValue(jvp->GetInteger());
+ break;
+ case TYPE_BIGINT:
+ vp->SetValue(jvp->GetBigint());
+ break;
+ case TYPE_DOUBLE:
+ vp->SetValue(jvp->GetFloat());
+
+ if (jvp->GetValType() == TYPE_DBL)
+ vp->SetPrec(jvp->Nd);
+
+ break;
+ case TYPE_DATE:
+ if (jvp->GetValType() == TYPE_STRG) {
+ PSZ dat = jvp->GetString(g);
+
+ if (!IsNum(dat)) {
+ if (!((DTVAL*)vp)->IsFormatted())
+ ((DTVAL*)vp)->SetFormat(g, "YYYY-MM-DDThh:mm:ssZ", 20, 0);
+
+ vp->SetValue_psz(dat);
+ } else
+ vp->SetValue(atoi(dat));
+
+ } else
+ vp->SetValue(jvp->GetInteger());
+
+ break;
+ default:
+ sprintf(g->Message, "Unsupported column type %d\n", vp->GetType());
+ throw 888;
+ } // endswitch Type
+
+ break;
+ case TYPE_BOOL:
+ if (vp->IsTypeNum())
+ vp->SetValue(jvp->GetInteger() ? 1 : 0);
+ else
+ vp->SetValue_psz((PSZ)(jvp->GetInteger() ? "true" : "false"));
+
+ break;
+ case TYPE_JAR:
+// SetJsonValue(g, vp, val->GetArray()->GetValue(0));
+ vp->SetValue_psz(jvp->GetArray()->GetText(g, NULL));
+ break;
+ case TYPE_JOB:
+// if (!vp->IsTypeNum() || !Strict) {
+ vp->SetValue_psz(jvp->GetObject()->GetText(g, NULL));
+ break;
+// } // endif Type
+
+ default:
+ vp->Reset();
+ vp->SetNull(true);
+ } // endswitch Type
+
+ } else {
+ vp->Reset();
+ vp->SetNull(true);
+ } // endif val
+
+} // end of SetJsonValue
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void JSONCOL::ReadColumn(PGLOBAL g)
+{
+ if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
+ Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
+
+// if (Xpd && Value->IsNull() && !((PJDEF)Tjp->To_Def)->Accept)
+// throw("Null expandable JSON value");
+
+ // Set null when applicable
+ if (!Nullable)
+ Value->SetNull(false);
+
+} // end of ReadColumn
+
+/***********************************************************************/
+/* GetColumnValue: */
+/***********************************************************************/
+PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
+{
+ PJAR arp;
+ PJVAL val = NULL;
+
+ for (; i < Nod && row; i++) {
+ if (Nodes[i].Op == OP_NUM) {
+ Value->SetValue(row->GetType() == TYPE_JAR ? ((PJAR)row)->size() : 1);
+ return(Value);
+ } else if (Nodes[i].Op == OP_XX) {
+ return MakeJson(G, row, i);
+ } else switch (row->GetType()) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key) {
+ // Expected Array was not there, wrap the value
+ if (i < Nod-1)
+ continue;
+ else
+ val = new(G) JVALUE(row);
+
+ } else
+ val = ((PJOB)row)->GetKeyValue(Nodes[i].Key);
+
+ break;
+ case TYPE_JAR:
+ arp = (PJAR)row;
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EQ)
+ val = arp->GetArrayValue(Nodes[i].Rank);
+ else if (Nodes[i].Op == OP_EXP)
+ return ExpandArray(g, arp, i);
+ else
+ return CalculateArray(g, arp, i);
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ val = arp->GetArrayValue(0);
+ i--;
+ } // endif's
+
+ break;
+ case TYPE_JVAL:
+ val = (PJVAL)row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+ val = NULL;
+ } // endswitch Type
+
+ if (i < Nod-1)
+ row = (val) ? val->GetJson() : NULL;
+
+ } // endfor i
+
+ SetJsonValue(g, Value, val);
+ return Value;
+} // end of GetColumnValue
+
+/***********************************************************************/
+/* ExpandArray: */
+/***********************************************************************/
+PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
+{
+ int ars = MY_MIN(Tjp->Limit, arp->size());
+ PJVAL jvp;
+ JVALUE jval;
+
+ if (!ars) {
+ Value->Reset();
+ Value->SetNull(true);
+ Tjp->NextSame = 0;
+ return Value;
+ } // endif ars
+
+ if (!(jvp = arp->GetArrayValue((Nodes[n].Rx = Nodes[n].Nx)))) {
+ strcpy(g->Message, "Logical error expanding array");
+ throw 666;
+ } // endif jvp
+
+ if (n < Nod - 1 && jvp->GetJson()) {
+ jval.SetValue(g, GetColumnValue(g, jvp->GetJson(), n + 1));
+ jvp = &jval;
+ } // endif n
+
+ if (n >= Tjp->NextSame) {
+ if (++Nodes[n].Nx == ars) {
+ Nodes[n].Nx = 0;
+ Xnod = 0;
+ } else
+ Xnod = n;
+
+ Tjp->NextSame = Xnod;
+ } // endif NextSame
+
+ SetJsonValue(g, Value, jvp);
+ return Value;
+} // end of ExpandArray
+
+/***********************************************************************/
+/* CalculateArray: */
+/***********************************************************************/
+PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n)
+{
+ int i, ars, nv = 0, nextsame = Tjp->NextSame;
+ bool err;
+ OPVAL op = Nodes[n].Op;
+ PVAL val[2], vp = Nodes[n].Valp;
+ PJVAL jvrp, jvp;
+ JVALUE jval;
+
+ vp->Reset();
+ ars = MY_MIN(Tjp->Limit, arp->size());
+
+ if (trace(1))
+ htrc("CalculateArray: size=%d op=%d nextsame=%d\n",
+ ars, op, nextsame);
+
+ for (i = 0; i < ars; i++) {
+ jvrp = arp->GetArrayValue(i);
+
+ if (trace(1))
+ htrc("i=%d nv=%d\n", i, nv);
+
+ if (!jvrp->IsNull() || (op == OP_CNC && GetJsonNull())) do {
+ if (jvrp->IsNull()) {
+ jvrp->Strp = PlugDup(g, GetJsonNull());
+ jvrp->DataType = TYPE_STRG;
+ jvp = jvrp;
+ } else if (n < Nod - 1 && jvrp->GetJson()) {
+ Tjp->NextSame = nextsame;
+ jval.SetValue(g, GetColumnValue(g, jvrp->GetJson(), n + 1));
+ jvp = &jval;
+ } else
+ jvp = jvrp;
+
+ if (trace(1))
+ htrc("jvp=%s null=%d\n",
+ jvp->GetString(g), jvp->IsNull() ? 1 : 0);
+
+ if (!nv++) {
+ SetJsonValue(g, vp, jvp);
+ continue;
+ } else
+ SetJsonValue(g, MulVal, jvp);
+
+ if (!MulVal->IsNull()) {
+ switch (op) {
+ case OP_CNC:
+ if (Nodes[n].CncVal) {
+ val[0] = Nodes[n].CncVal;
+ err = vp->Compute(g, val, 1, op);
+ } // endif CncVal
+
+ val[0] = MulVal;
+ err = vp->Compute(g, val, 1, op);
+ break;
+// case OP_NUM:
+ case OP_SEP:
+ val[0] = Nodes[n].Valp;
+ val[1] = MulVal;
+ err = vp->Compute(g, val, 2, OP_ADD);
+ break;
+ default:
+ val[0] = Nodes[n].Valp;
+ val[1] = MulVal;
+ err = vp->Compute(g, val, 2, op);
+ } // endswitch Op
+
+ if (err)
+ vp->Reset();
+
+ if (trace(1)) {
+ char buf(32);
+
+ htrc("vp='%s' err=%d\n",
+ vp->GetCharString(&buf), err ? 1 : 0);
+
+ } // endif trace
+
+ } // endif Null
+
+ } while (Tjp->NextSame > nextsame);
+
+ } // endfor i
+
+ if (op == OP_SEP) {
+ // Calculate average
+ MulVal->SetValue(nv);
+ val[0] = vp;
+ val[1] = MulVal;
+
+ if (vp->Compute(g, val, 2, OP_DIV))
+ vp->Reset();
+
+ } // endif Op
+
+ Tjp->NextSame = nextsame;
+ return vp;
+} // end of CalculateArray
+
+/***********************************************************************/
+/* GetRow: Get the object containing this column. */
+/***********************************************************************/
+PJSON JSONCOL::GetRow(PGLOBAL g)
+{
+ PJVAL val = NULL;
+ PJAR arp;
+ PJSON nwr, row = Tjp->Row;
+
+ for (int i = 0; i < Nod && row; i++) {
+ if (i < Nod-1 && Nodes[i+1].Op == OP_XX)
+ break;
+ else switch (row->GetType()) {
+ case TYPE_JOB:
+ if (!Nodes[i].Key)
+ // Expected Array was not there, wrap the value
+ continue;
+
+ val = ((PJOB)row)->GetKeyValue(Nodes[i].Key);
+ break;
+ case TYPE_JAR:
+ arp = (PJAR)row;
+
+ if (!Nodes[i].Key) {
+ if (Nodes[i].Op == OP_EQ)
+ val = arp->GetArrayValue(Nodes[i].Rank);
+ else
+ val = arp->GetArrayValue(Nodes[i].Rx);
+
+ } else {
+ // Unexpected array, unwrap it as [0]
+ val = arp->GetArrayValue(0);
+ i--;
+ } // endif Nodes
+
+ break;
+ case TYPE_JVAL:
+ val = (PJVAL)row;
+ break;
+ default:
+ sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
+ val = NULL;
+ } // endswitch Type
+
+ if (val) {
+ row = val->GetJson();
+ } else {
+ // Construct missing objects
+ for (i++; row && i < Nod; i++) {
+ if (Nodes[i].Op == OP_XX)
+ break;
+ else if (!Nodes[i].Key)
+ // Construct intermediate array
+ nwr = new(G) JARRAY;
+ else
+ nwr = new(G) JOBJECT;
+
+ if (row->GetType() == TYPE_JOB) {
+ ((PJOB)row)->SetKeyValue(G, new(G) JVALUE(nwr), Nodes[i-1].Key);
+ } else if (row->GetType() == TYPE_JAR) {
+ ((PJAR)row)->AddArrayValue(G, new(G) JVALUE(nwr));
+ ((PJAR)row)->InitArray(G);
+ } else {
+ strcpy(g->Message, "Wrong type when writing new row");
+ nwr = NULL;
+ } // endif's
+
+ row = nwr;
+ } // endfor i
+
+ break;
+ } // endelse
+
+ } // endfor i
+
+ return row;
+} // end of GetRow
+
+/***********************************************************************/
+/* WriteColumn: */
+/***********************************************************************/
+void JSONCOL::WriteColumn(PGLOBAL g)
+{
+ if (Xpd && Tjp->Pretty < 2) {
+ strcpy(g->Message, "Cannot write expanded column when Pretty is not 2");
+ throw 666;
+ } // endif Xpd
+
+ /*********************************************************************/
+ /* Check whether this node must be written. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, FALSE); // Convert the updated value
+
+ /*********************************************************************/
+ /* On INSERT Null values are represented by no node. */
+ /*********************************************************************/
+ if (Value->IsNull() && Tjp->Mode == MODE_INSERT)
+ return;
+
+ char *s;
+ PJOB objp = NULL;
+ PJAR arp = NULL;
+ PJVAL jvp = NULL;
+ PJSON jsp, row = GetRow(g);
+
+ switch (row->GetType()) {
+ case TYPE_JOB: objp = (PJOB)row; break;
+ case TYPE_JAR: arp = (PJAR)row; break;
+ case TYPE_JVAL: jvp = (PJVAL)row; break;
+ default: row = NULL; // ???????????????????????????
+ } // endswitch Type
+
+ if (row) switch (Buf_Type) {
+ case TYPE_STRING:
+ if (Nodes[Nod-1].Op == OP_XX) {
+ s = Value->GetCharValue();
+
+ if (s && *s) {
+ if (!(jsp = ParseJson(G, s, strlen(s)))) {
+ strcpy(g->Message, s);
+ throw 666;
+ } // endif jsp
+
+ } else
+ jsp = NULL;
+
+ if (arp) {
+ if (Nod > 1 && Nodes[Nod-2].Op == OP_EQ)
+ arp->SetArrayValue(G, new(G) JVALUE(jsp), Nodes[Nod-2].Rank);
+ else
+ arp->AddArrayValue(G, new(G) JVALUE(jsp));
+
+ arp->InitArray(G);
+ } else if (objp) {
+ if (Nod > 1 && Nodes[Nod-2].Key)
+ objp->SetKeyValue(G, new(G) JVALUE(jsp), Nodes[Nod-2].Key);
+
+ } else if (jvp)
+ jvp->SetValue(jsp);
+
+ break;
+ } // endif Op
+
+ // fall through
+ case TYPE_DATE:
+ case TYPE_INT:
+ case TYPE_TINY:
+ case TYPE_SHORT:
+ case TYPE_BIGINT:
+ case TYPE_DOUBLE:
+ if (arp) {
+ if (Nodes[Nod-1].Op == OP_EQ)
+ arp->SetArrayValue(G, new(G) JVALUE(G, Value), Nodes[Nod-1].Rank);
+ else
+ arp->AddArrayValue(G, new(G) JVALUE(G, Value));
+
+ arp->InitArray(G);
+ } else if (objp) {
+ if (Nodes[Nod-1].Key)
+ objp->SetKeyValue(G, new(G) JVALUE(G, Value), Nodes[Nod-1].Key);
+
+ } else if (jvp)
+ jvp->SetValue(g, Value);
+
+ break;
+ default: // ??????????
+ sprintf(g->Message, "Invalid column type %d", Buf_Type);
+ } // endswitch Type
+
+} // end of WriteColumn
+
+/* -------------------------- Class TDBJSON -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBJSON class. */
+/***********************************************************************/
+TDBJSON::TDBJSON(PJDEF tdp, PTXF txfp) : TDBJSN(tdp, txfp)
+{
+ Doc = NULL;
+ Multiple = tdp->Multiple;
+ Done = Changed = false;
+} // end of TDBJSON standard constructor
+
+TDBJSON::TDBJSON(PJTDB tdbp) : TDBJSN(tdbp)
+{
+ Doc = tdbp->Doc;
+ Multiple = tdbp->Multiple;
+ Done = tdbp->Done;
+ Changed = tdbp->Changed;
+} // end of TDBJSON copy constructor
+
+// Used for update
+PTDB TDBJSON::Clone(PTABS t)
+{
+ PTDB tp;
+ PJCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBJSON(this);
+
+ for (cp1 = (PJCOL)Columns; cp1; cp1 = (PJCOL)cp1->GetNext()) {
+ cp2 = new(g) JSONCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+} // end of Clone
+
+/***********************************************************************/
+/* Make the document tree from the object path. */
+/***********************************************************************/
+int TDBJSON::MakeNewDoc(PGLOBAL g)
+{
+ // Create a void table that will be populated
+ Doc = new(g) JARRAY;
+
+ if (MakeTopTree(g, Doc))
+ return RC_FX;
+
+ Done = true;
+ return RC_OK;
+} // end of MakeNewDoc
+
+/***********************************************************************/
+/* Make the document tree from a file. */
+/***********************************************************************/
+int TDBJSON::MakeDocument(PGLOBAL g)
+{
+ char *p, *p1, *p2, *memory, *objpath, *key = NULL;
+ int i = 0;
+ size_t len;
+ my_bool a;
+ MODE mode = Mode;
+ PJSON jsp;
+ PJOB objp = NULL;
+ PJAR arp = NULL;
+ PJVAL val = NULL;
+
+ if (Done)
+ return RC_OK;
+
+ /*********************************************************************/
+ /* Create the mapping file object in mode read. */
+ /*********************************************************************/
+ Mode = MODE_READ;
+
+ if (!Txfp->OpenTableFile(g)) {
+ PFBLOCK fp = Txfp->GetTo_Fb();
+
+ if (fp) {
+ len = fp->Length;
+ memory = fp->Memory;
+ } else {
+ Mode = mode; // Restore saved Mode
+ return MakeNewDoc(g);
+ } // endif fp
+
+ } else
+ return RC_FX;
+
+ /*********************************************************************/
+ /* Parse the json file and allocate its tree structure. */
+ /*********************************************************************/
+ g->Message[0] = 0;
+ jsp = Top = ParseJson(g, memory, len, &Pretty);
+ Txfp->CloseTableFile(g, false);
+ Mode = mode; // Restore saved Mode
+
+ if (!jsp && g->Message[0])
+ return RC_FX;
+
+ if ((objpath = PlugDup(g, Objname))) {
+ if (*objpath == '$') objpath++;
+ if (*objpath == '.') objpath++;
+ p1 = (*objpath == '[') ? objpath++ : NULL;
+
+ /*********************************************************************/
+ /* Find the table in the tree structure. */
+ /*********************************************************************/
+ for (p = objpath; jsp && p; p = (p2 ? p2 : NULL)) {
+ a = (p1 != NULL);
+ p1 = strchr(p, '[');
+ p2 = strchr(p, '.');
+
+ if (!p2)
+ p2 = p1;
+ else if (p1) {
+ if (p1 < p2)
+ p2 = p1;
+ else if (p1 == p2 + 1)
+ *p2++ = 0; // Old syntax .[
+ else
+ p1 = NULL;
+
+ } // endif p1
+
+ if (p2)
+ *p2++ = 0;
+
+ if (!a && *p && *p != '[' && !IsNum(p)) {
+ // obj is a key
+ if (jsp->GetType() != TYPE_JOB) {
+ strcpy(g->Message, "Table path does not match the json file");
+ return RC_FX;
+ } // endif Type
+
+ key = p;
+ objp = jsp->GetObject();
+ arp = NULL;
+ val = objp->GetKeyValue(key);
+
+ if (!val || !(jsp = val->GetJson())) {
+ sprintf(g->Message, "Cannot find object key %s", key);
+ return RC_FX;
+ } // endif val
+
+ } else {
+ if (*p == '[') {
+ // Old style
+ if (p[strlen(p) - 1] != ']') {
+ sprintf(g->Message, "Invalid Table path near %s", p);
+ return RC_FX;
+ } else
+ p++;
+
+ } // endif p
+
+ if (jsp->GetType() != TYPE_JAR) {
+ strcpy(g->Message, "Table path does not match the json file");
+ return RC_FX;
+ } // endif Type
+
+ arp = jsp->GetArray();
+ objp = NULL;
+ i = atoi(p) - B;
+ val = arp->GetArrayValue(i);
+
+ if (!val) {
+ sprintf(g->Message, "Cannot find array value %d", i);
+ return RC_FX;
+ } // endif val
+
+ } // endif
+
+ jsp = val->GetJson();
+ } // endfor p
+
+ } // endif objpath
+
+ if (jsp && jsp->GetType() == TYPE_JAR)
+ Doc = jsp->GetArray();
+ else {
+ // The table is void or is just one object or one value
+ Doc = new(g) JARRAY;
+
+ if (val) {
+ Doc->AddArrayValue(g, val);
+ Doc->InitArray(g);
+ } else if (jsp) {
+ Doc->AddArrayValue(g, new(g) JVALUE(jsp));
+ Doc->InitArray(g);
+ } // endif val
+
+ if (objp)
+ objp->SetKeyValue(g, new(g) JVALUE(Doc), key);
+ else if (arp)
+ arp->SetArrayValue(g, new(g) JVALUE(Doc), i);
+ else
+ Top = Doc;
+
+ } // endif jsp
+
+ Done = true;
+ return RC_OK;
+} // end of MakeDocument
+
+/***********************************************************************/
+/* JSON Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBJSON::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return (Xcol || Multiple) ? 0 : 1;
+ else if (Cardinal < 0)
+ {
+ if (!Multiple) {
+ if (MakeDocument(g) == RC_OK)
+ Cardinal = Doc->size();
+
+ } else
+ return 10;
+ }
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* JSON GetMaxSize: returns table size estimate in number of rows. */
+/***********************************************************************/
+int TDBJSON::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = Cardinality(g) * ((Xcol) ? Limit : 1);
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* ResetSize: call by TDBMUL when calculating size estimate. */
+/***********************************************************************/
+void TDBJSON::ResetSize(void)
+{
+ MaxSize = Cardinal = -1;
+ Fpos = -1;
+ N = 0;
+ Done = false;
+} // end of ResetSize
+
+/***********************************************************************/
+/* TDBJSON is not indexable. */
+/***********************************************************************/
+int TDBJSON::MakeIndex(PGLOBAL g, PIXDEF pxdf, bool)
+{
+ if (pxdf) {
+ strcpy(g->Message, "JSON not indexable when pretty = 2");
+ return RC_FX;
+ } else
+ return RC_OK;
+
+} // end of MakeIndex
+
+/***********************************************************************/
+/* Return the position in the table. */
+/***********************************************************************/
+int TDBJSON::GetRecpos(void)
+{
+#if 0
+ union {
+ uint Rpos;
+ BYTE Spos[4];
+ };
+
+ Rpos = htonl(Fpos);
+ Spos[0] = (BYTE)NextSame;
+ return Rpos;
+#endif // 0
+ return Fpos;
+} // end of GetRecpos
+
+/***********************************************************************/
+/* Set the position in the table. */
+/***********************************************************************/
+bool TDBJSON::SetRecpos(PGLOBAL, int recpos)
+{
+#if 0
+ union {
+ uint Rpos;
+ BYTE Spos[4];
+ };
+
+ Rpos = recpos;
+ NextSame = Spos[0];
+ Spos[0] = 0;
+ Fpos = (signed)ntohl(Rpos);
+
+//if (Fpos != (signed)ntohl(Rpos)) {
+// Fpos = ntohl(Rpos);
+// same = false;
+//} else
+// same = true;
+#endif // 0
+
+ Fpos = recpos - 1;
+ return false;
+} // end of SetRecpos
+
+/***********************************************************************/
+/* JSON Access Method opening routine. */
+/***********************************************************************/
+bool TDBJSON::OpenDB(PGLOBAL g)
+{
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open replace it at its beginning. */
+ /*******************************************************************/
+ Fpos= -1;
+ NextSame = false;
+ SameRow = 0;
+ return false;
+ } // endif use
+
+ /*********************************************************************/
+ /* OpenDB: initialize the JSON file processing. */
+ /*********************************************************************/
+ if (MakeDocument(g) != RC_OK)
+ return true;
+
+ if (Mode == MODE_INSERT)
+ switch (Jmode) {
+ case MODE_OBJECT: Row = new(g) JOBJECT; break;
+ case MODE_ARRAY: Row = new(g) JARRAY; break;
+ case MODE_VALUE: Row = new(g) JVALUE; break;
+ default:
+ sprintf(g->Message, "Invalid Jmode %d", Jmode);
+ return true;
+ } // endswitch Jmode
+
+ if (Xcol)
+ To_Filter = NULL; // Imcompatible
+
+ Use = USE_OPEN;
+ return false;
+} // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for JSON access method. */
+/***********************************************************************/
+int TDBJSON::ReadDB(PGLOBAL)
+{
+ int rc;
+
+ N++;
+
+ if (NextSame) {
+ SameRow = NextSame;
+ NextSame = false;
+ M++;
+ rc = RC_OK;
+ } else if (++Fpos < (signed)Doc->size()) {
+ Row = Doc->GetArrayValue(Fpos);
+
+ if (Row->GetType() == TYPE_JVAL)
+ Row = ((PJVAL)Row)->GetJson();
+
+ SameRow = 0;
+ M = 1;
+ rc = RC_OK;
+ } else
+ rc = RC_EF;
+
+ return rc;
+} // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for JSON access method. */
+/***********************************************************************/
+int TDBJSON::WriteDB(PGLOBAL g)
+{
+ if (Jmode == MODE_OBJECT) {
+ PJVAL vp = new(g) JVALUE(Row);
+
+ if (Mode == MODE_INSERT) {
+ Doc->AddArrayValue(g, vp);
+ Row = new(g) JOBJECT;
+ } else
+ Doc->SetArrayValue(g, vp, Fpos);
+
+ } else if (Jmode == MODE_ARRAY) {
+ PJVAL vp = new(g) JVALUE(Row);
+
+ if (Mode == MODE_INSERT) {
+ Doc->AddArrayValue(g, vp);
+ Row = new(g) JARRAY;
+ } else
+ Doc->SetArrayValue(g, vp, Fpos);
+
+ } else { // if (Jmode == MODE_VALUE)
+ if (Mode == MODE_INSERT) {
+ Doc->AddArrayValue(g, (PJVAL)Row);
+ Row = new(g) JVALUE;
+ } else
+ Doc->SetArrayValue(g, (PJVAL)Row, Fpos);
+
+ } // endif Jmode
+
+ Changed = true;
+ return RC_OK;
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for JSON access method. */
+/***********************************************************************/
+int TDBJSON::DeleteDB(PGLOBAL g, int irc)
+{
+ if (irc == RC_OK) {
+ // Deleted current row
+ if (Doc->DeleteValue(Fpos)) {
+ sprintf(g->Message, "Value %d does not exist", Fpos + 1);
+ return RC_FX;
+ } // endif Delete
+
+ Changed = true;
+ } else if (irc == RC_FX)
+ // Delete all
+ for (int i = 0; i < Doc->size(); i++) {
+ Doc->DeleteValue(i);
+ Changed = true;
+ } // endfor i
+
+ return RC_OK;
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for JSON access methods. */
+/***********************************************************************/
+void TDBJSON::CloseDB(PGLOBAL g)
+{
+ if (!Changed)
+ return;
+
+ // Save the modified document
+ char filename[_MAX_PATH];
+
+ Doc->InitArray(g);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, ((PJDEF)To_Def)->Fn, GetPath());
+
+ // Serialize the modified table
+ if (!Serialize(g, Top, filename, Pretty))
+ puts(g->Message);
+
+} // end of CloseDB
+
+/* ---------------------------TDBJCL class --------------------------- */
+
+/***********************************************************************/
+/* TDBJCL class constructor. */
+/***********************************************************************/
+TDBJCL::TDBJCL(PJDEF tdp) : TDBCAT(tdp)
+{
+ Topt = tdp->GetTopt();
+ Db = tdp->Schema;
+ Dsn = tdp->Uri;
+} // end of TDBJCL constructor
+
+/***********************************************************************/
+/* GetResult: Get the list the JSON file columns. */
+/***********************************************************************/
+PQRYRES TDBJCL::GetResult(PGLOBAL g)
+{
+ return JSONColumns(g, Db, Dsn, Topt, false);
+} // end of GetResult
+
+/* --------------------------- End of json --------------------------- */
diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h
new file mode 100644
index 00000000..623e5b6d
--- /dev/null
+++ b/storage/connect/tabjson.h
@@ -0,0 +1,323 @@
+/*************** tabjson H Declares Source Code File (.H) **************/
+/* Name: tabjson.h Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2014 - 2021 */
+/* */
+/* This file contains the JSON classes declares. */
+/***********************************************************************/
+#pragma once
+//#include "osutil.h" // Unuseful and bad for OEM
+#include "block.h"
+#include "colblk.h"
+#include "json.h"
+
+enum JMODE {MODE_OBJECT, MODE_ARRAY, MODE_VALUE};
+
+typedef class JSONDEF *PJDEF;
+typedef class TDBJSON *PJTDB;
+typedef class JSONCOL *PJCOL;
+class TDBJSN;
+DllExport PQRYRES JSONColumns(PGLOBAL, PCSZ, PCSZ, PTOS, bool);
+
+/***********************************************************************/
+/* The JSON tree node. Can be an Object or an Array. */
+/***********************************************************************/
+typedef struct _jnode {
+ PSZ Key; // The key used for object
+ OPVAL Op; // Operator used for this node
+ PVAL CncVal; // To cont value used for OP_CNC
+ PVAL Valp; // The internal array VALUE
+ int Rank; // The rank in array
+ int Rx; // Read row number
+ int Nx; // Next to read row number
+} JNODE, *PJNODE;
+
+typedef struct _jncol {
+ struct _jncol *Next;
+ char *Name;
+ char *Fmt;
+ JTYP Type;
+ int Len;
+ int Scale;
+ bool Cbn;
+ bool Found;
+} JCOL, *PJCL;
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+class JSONDISC : public BLOCK {
+public:
+ // Constructor
+ JSONDISC(PGLOBAL g, uint *lg);
+
+ // Functions
+ int GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt);
+ bool Find(PGLOBAL g, PJVAL jvp, PCSZ key, int j);
+ void AddColumn(PGLOBAL g);
+
+ // Members
+ JCOL jcol;
+ PJCL jcp, fjcp, pjcp;
+//PVL vlp;
+ PJDEF tdp;
+ TDBJSN *tjnp;
+ PJTDB tjsp;
+ PJPR jpp;
+ PJSON jsp;
+ PJOB row;
+ PCSZ sep;
+ PCSZ strfy;
+ char colname[65], fmt[129], buf[16];
+ uint *length;
+ int i, n, bf, ncol, lvl, sz, limit;
+ bool all;
+}; // end of JSONDISC
+
+/***********************************************************************/
+/* JSON table. */
+/***********************************************************************/
+class DllExport JSONDEF : public DOSDEF { /* Table description */
+ friend class TDBJSON;
+ friend class TDBJSN;
+ friend class TDBJCL;
+ friend class JSONDISC;
+#if defined(CMGO_SUPPORT)
+ friend class CMGFAM;
+#endif // CMGO_SUPPORT
+#if defined(JAVA_SUPPORT)
+ friend class JMGFAM;
+#endif // JAVA_SUPPORT
+public:
+ // Constructor
+ JSONDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "JSON";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ JMODE Jmode; /* MODE_OBJECT by default */
+ PCSZ Objname; /* Name of first level object */
+ PCSZ Xcol; /* Name of expandable column */
+ int Limit; /* Limit of multiple values */
+ int Pretty; /* Depends on file structure */
+ int Base; /* The array index base */
+ bool Strict; /* Strict syntax checking */
+ char Sep; /* The Jpath separator */
+ const char *Uri; /* MongoDB connection URI */
+ PCSZ Collname; /* External collection name */
+ PSZ Options; /* Colist ; Pipe */
+ PSZ Filter; /* Filter */
+ PSZ Driver; /* MongoDB Driver (C or JAVA) */
+ bool Pipe; /* True if Colist is a pipeline */
+ int Version; /* Driver version */
+ PSZ Wrapname; /* MongoDB java wrapper name */
+ }; // end of JSONDEF
+
+/* -------------------------- TDBJSN class --------------------------- */
+
+/***********************************************************************/
+/* This is the JSN Access Method class declaration. */
+/* The table is a DOS file, each record being a JSON object. */
+/***********************************************************************/
+class DllExport TDBJSN : public TDBDOS {
+ friend class JSONCOL;
+ friend class JSONDEF;
+ friend class JSONDISC;
+#if defined(CMGO_SUPPORT)
+ friend class CMGFAM;
+#endif // CMGO_SUPPORT
+#if defined(JAVA_SUPPORT)
+ friend class JMGFAM;
+#endif // JAVA_SUPPORT
+public:
+ // Constructor
+ TDBJSN(PJDEF tdp, PTXF txfp);
+ TDBJSN(TDBJSN *tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_JSN;}
+ virtual bool SkipHeader(PGLOBAL g);
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBJSN(this);}
+ PJSON GetRow(void) {return Row;}
+ void SetG(PGLOBAL g) {G = g;}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual PCOL InsertSpecialColumn(PCOL colp);
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE)
+ {return (b) ? M : N;}
+ virtual bool CanBeFiltered(void)
+ {return Txfp->GetAmType() == TYPE_AM_MGO || !Xcol;}
+
+ // Database routines
+ //virtual int Cardinality(PGLOBAL g);
+ //virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual bool PrepareWriting(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual void CloseDB(PGLOBAL g);
+
+ // Specific routine
+ virtual int EstimatedLength(void);
+
+protected:
+ PJSON FindRow(PGLOBAL g);
+ bool MakeTopTree(PGLOBAL g, PJSON jsp);
+
+ // Members
+ PGLOBAL G; // Support of parse memory
+ PJSON Top; // The top JSON tree
+ PJSON Row; // The current row
+ PJVAL Val; // The value of the current row
+ PJCOL Colp; // The multiple column
+ JMODE Jmode; // MODE_OBJECT by default
+ PCSZ Objname; // The table object name
+ PCSZ Xcol; // Name of expandable column
+ int Fpos; // The current row index
+ int N; // The current Rownum
+ int M; // Index of multiple value
+ int Limit; // Limit of multiple values
+ int Pretty; // Depends on file structure
+ int NextSame; // Same next row
+ int SameRow; // Same row nb
+ int Xval; // Index of expandable array
+ int B; // Array index base
+ char Sep; // The Jpath separator
+ bool Strict; // Strict syntax checking
+ bool Comma; // Row has final comma
+ bool Xpdable; // False: expandable columns are NULL
+}; // end of class TDBJSN
+
+/* -------------------------- JSONCOL class -------------------------- */
+
+/***********************************************************************/
+/* Class JSONCOL: JSON access method column descriptor. */
+/***********************************************************************/
+class DllExport JSONCOL : public DOSCOL {
+ friend class TDBJSN;
+ friend class TDBJSON;
+#if defined(CMGO_SUPPORT)
+ friend class CMGFAM;
+#endif // CMGO_SUPPORT
+#if defined(JAVA_SUPPORT)
+ friend class JMGFAM;
+#endif // JAVA_SUPPORT
+public:
+ // Constructors
+ JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
+ JSONCOL(JSONCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return Tjp->GetAmType();}
+ virtual bool Stringify(void) { return Sgfy; }
+
+ // Methods
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ bool ParseJpath(PGLOBAL g);
+ virtual PSZ GetJpath(PGLOBAL g, bool proj);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+ protected:
+ bool CheckExpand(PGLOBAL g, int i, PSZ nm, bool b);
+ bool SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm);
+ PVAL GetColumnValue(PGLOBAL g, PJSON row, int i);
+ PVAL ExpandArray(PGLOBAL g, PJAR arp, int n);
+ PVAL CalculateArray(PGLOBAL g, PJAR arp, int n);
+ PVAL MakeJson(PGLOBAL g, PJSON jsp, int n);
+ PJVAL GetRowValue(PGLOBAL g, PJSON row, int i);
+ void SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val);
+ PJSON GetRow(PGLOBAL g);
+
+ // Default constructor not to be used
+ JSONCOL(void) {}
+
+ // Members
+ PGLOBAL G; // Support of parse memory
+ TDBJSN *Tjp; // To the JSN table block
+ PVAL MulVal; // To value used by multiple column
+ char *Jpath; // The json path
+ JNODE *Nodes; // The intermediate objects
+ int Nod; // The number of intermediate objects
+ int Xnod; // Index of multiple values
+ char Sep; // The Jpath separator
+ bool Xpd; // True for expandable column
+ bool Parsed; // True when parsed
+ bool Warned; // True when warning issued
+ bool Sgfy; // True if stringified
+}; // end of class JSONCOL
+
+/* -------------------------- TDBJSON class -------------------------- */
+
+/***********************************************************************/
+/* This is the JSON Access Method class declaration. */
+/***********************************************************************/
+class DllExport TDBJSON : public TDBJSN {
+ friend class JSONDEF;
+ friend class JSONCOL;
+ public:
+ // Constructor
+ TDBJSON(PJDEF tdp, PTXF txfp);
+ TDBJSON(PJTDB tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_JSON;}
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBJSON(this);}
+ PJAR GetDoc(void) {return Doc;}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+
+ // Database routines
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual void ResetSize(void);
+ virtual int GetProgCur(void) {return N;}
+ virtual int GetRecpos(void);
+ virtual bool SetRecpos(PGLOBAL g, int recpos);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual bool PrepareWriting(PGLOBAL g) {return false;}
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ int MakeDocument(PGLOBAL g);
+
+ // Optimization routines
+ virtual int MakeIndex(PGLOBAL g, PIXDEF pxdf, bool add);
+
+ protected:
+ int MakeNewDoc(PGLOBAL g);
+
+ // Members
+ PJAR Doc; // The document array
+ int Multiple; // 0: No 1: DIR 2: Section 3: filelist
+ bool Done; // True when document parsing is done
+ bool Changed; // After Update, Insert or Delete
+ }; // end of class TDBJSON
+
+/***********************************************************************/
+/* This is the class declaration for the JSON catalog table. */
+/***********************************************************************/
+class DllExport TDBJCL : public TDBCAT {
+ public:
+ // Constructor
+ TDBJCL(PJDEF tdp);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PTOS Topt;
+ PCSZ Db;
+ PCSZ Dsn;
+ }; // end of class TDBJCL
diff --git a/storage/connect/table.cpp b/storage/connect/table.cpp
new file mode 100644
index 00000000..d4d3a34d
--- /dev/null
+++ b/storage/connect/table.cpp
@@ -0,0 +1,805 @@
+/************** Table C++ Functions Source Code File (.CPP) ************/
+/* Name: TABLE.CPP Version 2.8 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1999-2017 */
+/* */
+/* This file contains the TBX, TDB and OPJOIN classes functions. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#include "sql_string.h"
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* xobject.h is header containing XOBJECT derived classes declares. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabcol.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+//#include "catalog.h"
+#include "reldef.h"
+
+int TDB::Tnum = 0;
+
+/***********************************************************************/
+/* Utility routines. */
+/***********************************************************************/
+void NewPointer(PTABS, void *, void *);
+void AddPointer(PTABS, void *);
+
+/* ---------------------------- class TDB ---------------------------- */
+
+/***********************************************************************/
+/* TDB public constructors. */
+/***********************************************************************/
+TDB::TDB(PTABDEF tdp) : Tdb_No(++Tnum)
+{
+ To_Def = tdp;
+ Use = USE_NO;
+ To_Orig = NULL;
+ To_Filter = NULL;
+ To_CondFil = NULL;
+ Cond = NULL;
+ Next = NULL;
+ Name = (tdp) ? tdp->GetName() : NULL;
+ To_Table = NULL;
+ Columns = NULL;
+ To_SetCols = NULL;
+ Degree = (tdp) ? tdp->GetDegree() : 0;
+ Mode = MODE_ANY;
+ Cardinal = -1;
+ MaxSize = -1;
+ Read_Only = (tdp) ? tdp->IsReadOnly() : false;
+ m_data_charset = (tdp) ? tdp->data_charset() : NULL;
+ csname = (tdp) ? tdp->csname : NULL;
+} // end of TDB standard constructor
+
+TDB::TDB(PTDB tdbp) : Tdb_No(++Tnum)
+{
+ To_Def = tdbp->To_Def;
+ Use = tdbp->Use;
+ To_Orig = tdbp;
+ To_Filter = NULL;
+ To_CondFil = NULL;
+ Cond = NULL;
+ Next = NULL;
+ Name = tdbp->Name;
+ To_Table = tdbp->To_Table;
+ Columns = NULL;
+ To_SetCols = tdbp->To_SetCols; // ???
+ Degree = tdbp->Degree;
+ Mode = tdbp->Mode;
+ Cardinal = tdbp->Cardinal;
+ MaxSize = tdbp->MaxSize;
+ Read_Only = tdbp->IsReadOnly();
+ m_data_charset = tdbp->data_charset();
+ csname = tdbp->csname;
+} // end of TDB copy constructor
+
+// Methods
+/***********************************************************************/
+/* Return the pointer on the charset of this table. */
+/***********************************************************************/
+CHARSET_INFO *TDB::data_charset(void)
+{
+ // If no DATA_CHARSET is specified, we assume that character
+ // set of the remote data is the same with CHARACTER SET
+ // definition of the SQL column.
+ return m_data_charset ? m_data_charset : &my_charset_bin;
+} // end of data_charset
+
+/***********************************************************************/
+/* Return the datapath of the DB this table belongs to. */
+/***********************************************************************/
+PCSZ TDB::GetPath(void)
+{
+ return To_Def->GetPath();
+} // end of GetPath
+
+/***********************************************************************/
+/* Return true if name is a special column of this table. */
+/***********************************************************************/
+bool TDB::IsSpecial(PSZ name)
+{
+ for (PCOLDEF cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!stricmp(cdp->GetName(), name) && (cdp->Flags & U_SPECIAL))
+ return true; // Special column to ignore while inserting
+
+ return false; // Not found or not special or not inserting
+} // end of IsSpecial
+
+/***********************************************************************/
+/* Initialize TDB based column description block construction. */
+/* name is used to call columns by name. */
+/* num is used by TBL to construct columns by index number. */
+/* Note: name=Null and num=0 for constructing all columns (select *) */
+/***********************************************************************/
+PCOL TDB::ColDB(PGLOBAL g, PSZ name, int num)
+{
+ int i;
+ PCOLDEF cdp;
+ PCOL cp, colp = NULL, cprec = NULL;
+
+ if (trace(1))
+ htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n",
+ GetAmType(), SVP(name), Name, num);
+
+ for (cdp = To_Def->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++)
+ if ((!name && !num) ||
+ (name && !stricmp(cdp->GetName(), name)) || num == i) {
+ /*****************************************************************/
+ /* Check for existence of desired column. */
+ /* Also find where to insert the new block. */
+ /*****************************************************************/
+ for (cp = Columns; cp; cp = cp->GetNext())
+ if ((num && cp->GetIndex() == i) ||
+ (name && !stricmp(cp->GetName(), name)))
+ break; // Found
+ else if (cp->GetIndex() < i)
+ cprec = cp;
+
+ if (trace(1))
+ htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp);
+
+ /*****************************************************************/
+ /* Now take care of Column Description Block. */
+ /*****************************************************************/
+ if (cp)
+ colp = cp;
+ else if (!(cdp->Flags & U_SPECIAL))
+ colp = MakeCol(g, cdp, cprec, i);
+ else if (Mode != MODE_INSERT)
+ colp = InsertSpcBlk(g, cdp);
+
+ if (trace(1))
+ htrc("colp=%p\n", colp);
+
+ if (name || num)
+ break;
+ else if (colp && !colp->IsSpecial())
+ cprec = colp;
+
+ } // endif Name
+
+ return (colp);
+} // end of ColDB
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDB::InsertSpecialColumn(PCOL colp)
+{
+ if (!colp->IsSpecial())
+ return NULL;
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+} // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* Make a special COLBLK to insert in a table. */
+/***********************************************************************/
+PCOL TDB::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp)
+{
+ //char *name = cdp->GetName();
+ char *name = cdp->GetFmt();
+ PCOLUMN cp;
+ PCOL colp;
+
+ cp = new(g)COLUMN(cdp->GetName());
+
+ if (!To_Table) {
+ strcpy(g->Message, "Cannot make special column: To_Table is NULL");
+ return NULL;
+ } else
+ cp->SetTo_Table(To_Table);
+
+ if (!stricmp(name, "FILEID") || !stricmp(name, "FDISK") ||
+ !stricmp(name, "FPATH") || !stricmp(name, "FNAME") ||
+ !stricmp(name, "FTYPE") || !stricmp(name, "SERVID")) {
+ if (!To_Def || !(To_Def->GetPseudo() & 2)) {
+ sprintf(g->Message, MSG(BAD_SPEC_COLUMN));
+ return NULL;
+ } // endif Pseudo
+
+ if (!stricmp(name, "FILEID"))
+ colp = new(g)FIDBLK(cp, OP_XX);
+ else if (!stricmp(name, "FDISK"))
+ colp = new(g)FIDBLK(cp, OP_FDISK);
+ else if (!stricmp(name, "FPATH"))
+ colp = new(g)FIDBLK(cp, OP_FPATH);
+ else if (!stricmp(name, "FNAME"))
+ colp = new(g)FIDBLK(cp, OP_FNAME);
+ else if (!stricmp(name, "FTYPE"))
+ colp = new(g)FIDBLK(cp, OP_FTYPE);
+ else
+ colp = new(g)SIDBLK(cp);
+
+ } else if (!stricmp(name, "TABID")) {
+ colp = new(g)TIDBLK(cp);
+ } else if (!stricmp(name, "PARTID")) {
+ colp = new(g)PRTBLK(cp);
+ //} else if (!stricmp(name, "CONID")) {
+ // colp = new(g) CIDBLK(cp);
+ } else if (!stricmp(name, "ROWID")) {
+ colp = new(g)RIDBLK(cp, false);
+ } else if (!stricmp(name, "ROWNUM")) {
+ colp = new(g)RIDBLK(cp, true);
+ } else {
+ sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
+ return NULL;
+ } // endif's name
+
+ if (!(colp = InsertSpecialColumn(colp))) {
+ sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
+ return NULL;
+ } // endif Insert
+
+ return (colp);
+} // end of InsertSpcBlk
+
+/***********************************************************************/
+/* Marks DOS/MAP table columns used in internal joins. */
+/* tdb2 is the top of tree or first tdb in chained tdb's and tdbp */
+/* points to the currently marked tdb. */
+/* Two questions here: exact meaning of U_J_INT ? */
+/* Why is the eventual reference to To_Key_Col not marked U_J_EXT ? */
+/***********************************************************************/
+void TDB::MarkDB(PGLOBAL, PTDB tdb2)
+{
+ if (trace(1))
+ htrc("DOS MarkDB: tdbp=%p tdb2=%p\n", this, tdb2);
+
+} // end of MarkDB
+
+/***********************************************************************/
+/* RowNumber: returns the current row ordinal number. */
+/***********************************************************************/
+int TDB::RowNumber(PGLOBAL g, bool)
+ {
+ sprintf(g->Message, MSG(ROWID_NOT_IMPL), GetAmName(g, GetAmType()));
+ return 0;
+ } // end of RowNumber
+
+PTDB TDB::Copy(PTABS t)
+ {
+ PTDB tp, tdb1, tdb2 = NULL, outp = NULL;
+//PGLOBAL g = t->G; // Is this really useful ???
+
+ for (tdb1 = this; tdb1; tdb1 = tdb1->Next) {
+ tp = tdb1->Clone(t);
+
+ if (!outp)
+ outp = tp;
+ else
+ tdb2->Next = tp;
+
+ tdb2 = tp;
+ NewPointer(t, tdb1, tdb2);
+ } // endfor tdb1
+
+ return outp;
+ } // end of Copy
+
+/***********************************************************************/
+/* SetRecpos: Replace the table at the specified position. */
+/***********************************************************************/
+bool TDB::SetRecpos(PGLOBAL g, int)
+{
+ strcpy(g->Message, MSG(SETRECPOS_NIY));
+ return true;
+} // end of SetRecpos
+
+void TDB::Printf(PGLOBAL g, FILE *f, uint n)
+ {
+ PCOL cp;
+ char m[64];
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+
+ for (PTDB tp = this; tp; tp = tp->Next) {
+ fprintf(f, "%sTDB (%p) %s no=%d use=%d type=%d\n", m,
+ tp, tp->Name, tp->Tdb_No, tp->Use, tp->GetAmType());
+
+ tp->PrintAM(f, m);
+ fprintf(f, "%s Columns (deg=%d):\n", m, tp->Degree);
+
+ for (cp = tp->Columns; cp; cp = cp->GetNext())
+ cp->Printf(g, f, n);
+
+ } /* endfor tp */
+
+ } // end of Printf
+
+void TDB::Prints(PGLOBAL, char *ps, uint)
+ {
+ sprintf(ps, "R%d.%s", Tdb_No, Name);
+ } // end of Prints
+
+/* -------------------------- class TDBASE --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBASE class. This is the base class to all */
+/* classes for tables that can be joined together. */
+/***********************************************************************/
+TDBASE::TDBASE(PTABDEF tdp) : TDB(tdp)
+ {
+//To_Def = tdp;
+ To_Link = NULL;
+ To_Key_Col = NULL;
+ To_Kindex = NULL;
+ To_Xdp = NULL;
+//To_SetCols = NULL;
+ Ftype = RECFM_NAF;
+//MaxSize = -1;
+ Knum = 0;
+//Read_Only = (tdp) ? tdp->IsReadOnly() : false;
+//m_data_charset= (tdp) ? tdp->data_charset() : NULL;
+//csname = (tdp) ? tdp->csname : NULL;
+ } // end of TDBASE constructor
+
+TDBASE::TDBASE(PTDBASE tdbp) : TDB(tdbp)
+ {
+//To_Def = tdbp->To_Def;
+ To_Link = tdbp->To_Link;
+ To_Key_Col = tdbp->To_Key_Col;
+ To_Kindex = tdbp->To_Kindex;
+ To_Xdp = tdbp->To_Xdp;
+//To_SetCols = tdbp->To_SetCols; // ???
+ Ftype = tdbp->Ftype;
+//MaxSize = tdbp->MaxSize;
+ Knum = tdbp->Knum;
+//Read_Only = tdbp->Read_Only;
+//m_data_charset= tdbp->m_data_charset;
+//csname = tdbp->csname;
+ } // end of TDBASE copy constructor
+
+/***********************************************************************/
+/* Return the pointer on the DB catalog this table belongs to. */
+/***********************************************************************/
+PCATLG TDBASE::GetCat(void)
+ {
+ return (To_Def) ? To_Def->GetCat() : NULL;
+ } // end of GetCat
+
+#if 0
+/***********************************************************************/
+/* Return the pointer on the charset of this table. */
+/***********************************************************************/
+CHARSET_INFO *TDBASE::data_charset(void)
+ {
+ // If no DATA_CHARSET is specified, we assume that character
+ // set of the remote data is the same with CHARACTER SET
+ // definition of the SQL column.
+ return m_data_charset ? m_data_charset : &my_charset_bin;
+ } // end of data_charset
+
+/***********************************************************************/
+/* Return the datapath of the DB this table belongs to. */
+/***********************************************************************/
+PSZ TDBASE::GetPath(void)
+ {
+ return To_Def->GetPath();
+ } // end of GetPath
+
+/***********************************************************************/
+/* Return true if name is a special column of this table. */
+/***********************************************************************/
+bool TDBASE::IsSpecial(PSZ name)
+ {
+ for (PCOLDEF cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!stricmp(cdp->GetName(), name) && (cdp->Flags & U_SPECIAL))
+ return true; // Special column to ignore while inserting
+
+ return false; // Not found or not special or not inserting
+ } // end of IsSpecial
+
+/***********************************************************************/
+/* Initialize TDBASE based column description block construction. */
+/* name is used to call columns by name. */
+/* num is used by TBL to construct columns by index number. */
+/* Note: name=Null and num=0 for constructing all columns (select *) */
+/***********************************************************************/
+PCOL TDBASE::ColDB(PGLOBAL g, PSZ name, int num)
+ {
+ int i;
+ PCOLDEF cdp;
+ PCOL cp, colp = NULL, cprec = NULL;
+
+ if (trace(1))
+ htrc("ColDB: am=%d colname=%s tabname=%s num=%d\n",
+ GetAmType(), SVP(name), Name, num);
+
+ for (cdp = To_Def->GetCols(), i = 1; cdp; cdp = cdp->GetNext(), i++)
+ if ((!name && !num) ||
+ (name && !stricmp(cdp->GetName(), name)) || num == i) {
+ /*****************************************************************/
+ /* Check for existence of desired column. */
+ /* Also find where to insert the new block. */
+ /*****************************************************************/
+ for (cp = Columns; cp; cp = cp->GetNext())
+ if ((num && cp->GetIndex() == i) ||
+ (name && !stricmp(cp->GetName(), name)))
+ break; // Found
+ else if (cp->GetIndex() < i)
+ cprec = cp;
+
+ if (trace(1))
+ htrc("cdp(%d).Name=%s cp=%p\n", i, cdp->GetName(), cp);
+
+ /*****************************************************************/
+ /* Now take care of Column Description Block. */
+ /*****************************************************************/
+ if (cp)
+ colp = cp;
+ else if (!(cdp->Flags & U_SPECIAL))
+ colp = MakeCol(g, cdp, cprec, i);
+ else if (Mode != MODE_INSERT)
+ colp = InsertSpcBlk(g, cdp);
+
+ if (trace(1))
+ htrc("colp=%p\n", colp);
+
+ if (name || num)
+ break;
+ else if (colp && !colp->IsSpecial())
+ cprec = colp;
+
+ } // endif Name
+
+ return (colp);
+ } // end of ColDB
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBASE::InsertSpecialColumn(PCOL colp)
+ {
+ if (!colp->IsSpecial())
+ return NULL;
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+ } // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* Make a special COLBLK to insert in a table. */
+/***********************************************************************/
+PCOL TDBASE::InsertSpcBlk(PGLOBAL g, PCOLDEF cdp)
+ {
+//char *name = cdp->GetName();
+ char *name = cdp->GetFmt();
+ PCOLUMN cp;
+ PCOL colp;
+
+ cp= new(g) COLUMN(cdp->GetName());
+
+ if (! To_Table) {
+ strcpy(g->Message, "Cannot make special column: To_Table is NULL");
+ return NULL;
+ } else
+ cp->SetTo_Table(To_Table);
+
+ if (!stricmp(name, "FILEID") || !stricmp(name, "FDISK") ||
+ !stricmp(name, "FPATH") || !stricmp(name, "FNAME") ||
+ !stricmp(name, "FTYPE") || !stricmp(name, "SERVID")) {
+ if (!To_Def || !(To_Def->GetPseudo() & 2)) {
+ sprintf(g->Message, MSG(BAD_SPEC_COLUMN));
+ return NULL;
+ } // endif Pseudo
+
+ if (!stricmp(name, "FILEID"))
+ colp = new(g) FIDBLK(cp, OP_XX);
+ else if (!stricmp(name, "FDISK"))
+ colp = new(g) FIDBLK(cp, OP_FDISK);
+ else if (!stricmp(name, "FPATH"))
+ colp = new(g) FIDBLK(cp, OP_FPATH);
+ else if (!stricmp(name, "FNAME"))
+ colp = new(g) FIDBLK(cp, OP_FNAME);
+ else if (!stricmp(name, "FTYPE"))
+ colp = new(g) FIDBLK(cp, OP_FTYPE);
+ else
+ colp = new(g) SIDBLK(cp);
+
+ } else if (!stricmp(name, "TABID")) {
+ colp = new(g) TIDBLK(cp);
+ } else if (!stricmp(name, "PARTID")) {
+ colp = new(g) PRTBLK(cp);
+//} else if (!stricmp(name, "CONID")) {
+// colp = new(g) CIDBLK(cp);
+ } else if (!stricmp(name, "ROWID")) {
+ colp = new(g) RIDBLK(cp, false);
+ } else if (!stricmp(name, "ROWNUM")) {
+ colp = new(g) RIDBLK(cp, true);
+ } else {
+ sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
+ return NULL;
+ } // endif's name
+
+ if (!(colp = InsertSpecialColumn(colp))) {
+ sprintf(g->Message, MSG(BAD_SPECIAL_COL), name);
+ return NULL;
+ } // endif Insert
+
+ return (colp);
+ } // end of InsertSpcBlk
+#endif // 0
+
+/***********************************************************************/
+/* ResetTableOpt: Wrong for this table type. */
+/***********************************************************************/
+int TDBASE::ResetTableOpt(PGLOBAL g, bool, bool)
+{
+ strcpy(g->Message, "This table is not indexable");
+ return RC_INFO;
+} // end of ResetTableOpt
+
+/***********************************************************************/
+/* ResetKindex: set or reset the index pointer. */
+/***********************************************************************/
+void TDBASE::ResetKindex(PGLOBAL g, PKXBASE kxp)
+ {
+ if (To_Kindex) {
+ int pos = GetRecpos(); // To be reset in Txfp
+
+ for (PCOL colp= Columns; colp; colp= colp->GetNext())
+ colp->SetKcol(NULL);
+
+ To_Kindex->Close(); // Discard old index
+ SetRecpos(g, pos); // Ignore return value
+ } // endif To_Kindex
+
+ To_Kindex = kxp;
+ } // end of ResetKindex
+
+#if 0
+/***********************************************************************/
+/* SetRecpos: Replace the table at the specified position. */
+/***********************************************************************/
+bool TDBASE::SetRecpos(PGLOBAL g, int)
+ {
+ strcpy(g->Message, MSG(SETRECPOS_NIY));
+ return true;
+ } // end of SetRecpos
+#endif // 0
+
+/***********************************************************************/
+/* Methods */
+/***********************************************************************/
+void TDBASE::PrintAM(FILE *f, char *m)
+ {
+ fprintf(f, "%s AM(%d): mode=%d\n", m, GetAmType(), Mode);
+ } // end of PrintAM
+
+#if 0
+/***********************************************************************/
+/* Marks DOS/MAP table columns used in internal joins. */
+/* tdb2 is the top of tree or first tdb in chained tdb's and tdbp */
+/* points to the currently marked tdb. */
+/* Two questions here: exact meaning of U_J_INT ? */
+/* Why is the eventual reference to To_Key_Col not marked U_J_EXT ? */
+/***********************************************************************/
+void TDBASE::MarkDB(PGLOBAL, PTDB tdb2)
+ {
+ if (trace(1))
+ htrc("DOS MarkDB: tdbp=%p tdb2=%p\n", this, tdb2);
+
+ } // end of MarkDB
+#endif // 0
+
+/* ---------------------------TDBCAT class --------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBCAT class. */
+/***********************************************************************/
+TDBCAT::TDBCAT(PTABDEF tdp) : TDBASE(tdp)
+ {
+ Qrp = NULL;
+ Init = false;
+ N = -1;
+ } // end of TDBCAT constructor
+
+/***********************************************************************/
+/* Allocate CAT column description block. */
+/***********************************************************************/
+PCOL TDBCAT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PCATCOL colp;
+
+ colp = (PCATCOL)new(g) CATCOL(cdp, this, n);
+
+ if (cprec) {
+ colp->SetNext(cprec->GetNext());
+ cprec->SetNext(colp);
+ } else {
+ colp->SetNext(Columns);
+ Columns = colp;
+ } // endif cprec
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Initialize: Get the result query block. */
+/***********************************************************************/
+bool TDBCAT::Initialize(PGLOBAL g)
+ {
+ if (Init)
+ return false;
+
+ if (!(Qrp = GetResult(g)))
+ return true;
+
+ if (Qrp->Truncated) {
+ sprintf(g->Message, "Result limited to %d lines", Qrp->Maxres);
+ PushWarning(g, this);
+ } // endif Truncated
+
+ if (Qrp->BadLines) {
+ sprintf(g->Message, "%d bad lines in result", Qrp->BadLines);
+ PushWarning(g, this);
+ } // endif Badlines
+
+ Init = true;
+ return false;
+ } // end of Initialize
+
+/***********************************************************************/
+/* CAT: Get the number of properties. */
+/***********************************************************************/
+int TDBCAT::GetMaxSize(PGLOBAL g __attribute__((unused)))
+ {
+ if (MaxSize < 0) {
+// if (Initialize(g))
+// return -1;
+
+// MaxSize = Qrp->Nblin;
+ MaxSize = 10; // To make MariaDB happy
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* CAT Access Method opening routine. */
+/***********************************************************************/
+bool TDBCAT::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open. */
+ /*******************************************************************/
+ N = -1;
+ return false;
+ } // endif use
+
+ if (Mode != MODE_READ) {
+ /*******************************************************************/
+ /* ODBC Info tables cannot be modified. */
+ /*******************************************************************/
+ strcpy(g->Message, "CAT tables are read only");
+ return true;
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Initialize the ODBC processing. */
+ /*********************************************************************/
+ if (Initialize(g))
+ return true;
+
+ Use = USE_OPEN;
+ return InitCol(g);
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Initialize columns. */
+/***********************************************************************/
+bool TDBCAT::InitCol(PGLOBAL g)
+ {
+ PCATCOL colp;
+ PCOLRES crp;
+
+ for (colp = (PCATCOL)Columns; colp; colp = (PCATCOL)colp->GetNext()) {
+ for (crp = Qrp->Colresp; crp; crp = crp->Next)
+ if ((colp->Flag && colp->Flag == crp->Fld) ||
+ (!colp->Flag && !stricmp(colp->Name, crp->Name))) {
+ colp->Crp = crp;
+ break;
+ } // endif Flag
+
+
+ if (!colp->Crp /*&& !colp->GetValue()->IsConstant()*/) {
+ sprintf(g->Message, "Invalid flag %d for column %s",
+ colp->Flag, colp->Name);
+ return true;
+ } else if (crp->Fld == FLD_SCALE || crp->Fld == FLD_RADIX)
+ colp->Value->SetNullable(true);
+
+ } // endfor colp
+
+ return false;
+ } // end of InitCol
+
+/***********************************************************************/
+/* SetRecpos: Replace the table at the specified position. */
+/***********************************************************************/
+bool TDBCAT::SetRecpos(PGLOBAL, int recpos)
+ {
+ N = recpos - 1;
+ return false;
+ } // end of SetRecpos
+
+/***********************************************************************/
+/* Data Base read routine for CAT access method. */
+/***********************************************************************/
+int TDBCAT::ReadDB(PGLOBAL)
+ {
+ return (++N < Qrp->Nblin) ? RC_OK : RC_EF;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for CAT access methods. */
+/***********************************************************************/
+int TDBCAT::WriteDB(PGLOBAL g)
+ {
+ strcpy(g->Message, "CAT tables are read only");
+ return RC_FX;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for CAT access methods. */
+/***********************************************************************/
+int TDBCAT::DeleteDB(PGLOBAL g, int)
+ {
+ strcpy(g->Message, "Delete not enabled for CAT tables");
+ return RC_FX;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for WMI access method. */
+/***********************************************************************/
+void TDBCAT::CloseDB(PGLOBAL)
+ {
+ // Nothing to do
+ } // end of CloseDB
+
+// ------------------------ CATCOL functions ----------------------------
+
+/***********************************************************************/
+/* CATCOL public constructor. */
+/***********************************************************************/
+CATCOL::CATCOL(PCOLDEF cdp, PTDB tdbp, int n)
+ : COLBLK(cdp, tdbp, n)
+ {
+ Tdbp = (PTDBCAT)tdbp;
+ Crp = NULL;
+ Flag = cdp->GetOffset();
+ } // end of WMICOL constructor
+
+/***********************************************************************/
+/* Read the next Data Source elements. */
+/***********************************************************************/
+void CATCOL::ReadColumn(PGLOBAL)
+ {
+ bool b = (!Crp->Kdata || Crp->Kdata->IsNull(Tdbp->N));
+
+ // Get the value of the Name or Description property
+ if (!b)
+ Value->SetValue_pvblk(Crp->Kdata, Tdbp->N);
+ else
+ Value->Reset();
+
+ Value->SetNull(b);
+ } // end of ReadColumn
+
diff --git a/storage/connect/tabmac.cpp b/storage/connect/tabmac.cpp
new file mode 100644
index 00000000..ed161ac4
--- /dev/null
+++ b/storage/connect/tabmac.cpp
@@ -0,0 +1,458 @@
+/***********************************************************************/
+/* TABMAC: Author Olivier Bertrand -- PlugDB -- 2008-2012 */
+/* From the article and sample code by Khalid Shaikh. */
+/* TABMAC: virtual table to get the list of MAC addresses. */
+/***********************************************************************/
+#if defined(_WIN32)
+#include "my_global.h"
+//#include <iphlpapi.h>
+#else // !_WIN32
+#error This is a WINDOWS only table type
+#endif // !_WIN32
+#include "global.h"
+#include "plgdbsem.h"
+//#include "catalog.h"
+//#include "reldef.h"
+#include "xtable.h"
+#include "colblk.h"
+#include "tabmac.h"
+
+#if 0 // This is placed here just to know what are the actual values
+#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
+#define MAX_ADAPTER_NAME_LENGTH 256
+#define MAX_ADAPTER_ADDRESS_LENGTH 8
+#define DEFAULT_MINIMUM_ENTITIES 32
+#define MAX_HOSTNAME_LEN 128
+#define MAX_DOMAIN_NAME_LEN 128
+#define MAX_SCOPE_ID_LEN 256
+
+#define BROADCAST_NODETYPE 1
+#define PEER_TO_PEER_NODETYPE 2
+#define MIXED_NODETYPE 4
+#define HYBRID_NODETYPE 8
+
+#define IP_ADAPTER_DDNS_ENABLED 0x01
+#define IP_ADAPTER_REGISTER_ADAPTER_SUFFIX 0x02
+#define IP_ADAPTER_DHCP_ENABLED 0x04
+#define IP_ADAPTER_RECEIVE_ONLY 0x08
+#define IP_ADAPTER_NO_MULTICAST 0x10
+#define IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG 0x20
+#endif // 0
+
+/* -------------- Implementation of the MAC classes ------------------ */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from MAC file. */
+/***********************************************************************/
+bool MACDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB MACDEF::GetTable(PGLOBAL g, MODE m)
+ {
+ return new(g) TDBMAC(this);
+ } // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBMAC class. */
+/***********************************************************************/
+TDBMAC::TDBMAC(PMACDEF tdp) : TDBASE(tdp)
+ {
+ FixedInfo = NULL;
+ Piaf = NULL;
+ Curp = NULL;
+ Next = NULL;
+ Buflen = 0;
+ Fix = false;
+ Adap = false;
+ N = 0;
+ } // end of TDBMAC constructor
+
+/***********************************************************************/
+/* Allocate MAC column description block. */
+/***********************************************************************/
+PCOL TDBMAC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PCOL colp;
+
+ colp = new(g) MACCOL(cdp, this, n);
+
+ if (cprec) {
+ colp->SetNext(cprec->GetNext());
+ cprec->SetNext(colp);
+ } else {
+ colp->SetNext(Columns);
+ Columns = colp;
+ } // endif cprec
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* MAC: Get the number of found adapters. */
+/***********************************************************************/
+void TDBMAC::MakeErrorMsg(PGLOBAL g, DWORD drc)
+ {
+ if (drc == ERROR_BUFFER_OVERFLOW)
+ sprintf(g->Message,
+ "GetAdaptersInfo: Buffer Overflow buflen=%d maxsize=%d",
+ Buflen, MaxSize);
+ else if (drc == ERROR_INVALID_PARAMETER)
+ strcpy(g->Message, "GetAdaptersInfo: Invalid parameters");
+ else if (drc == ERROR_NO_DATA)
+ strcpy(g->Message,
+ "No adapter information exists for the local computer");
+ else if (drc == ERROR_NOT_SUPPORTED)
+ strcpy(g->Message, "GetAdaptersInfo is not supported");
+ else
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
+ 0, g->Message, sizeof(g->Message), NULL);
+
+ } // end of MakeErrorMsg
+
+/***********************************************************************/
+/* GetMacInfo: Get info for all found adapters. */
+/***********************************************************************/
+bool TDBMAC::GetMacInfo(PGLOBAL g)
+ {
+ DWORD drc;
+
+ if (GetMaxSize(g) < 0)
+ return true;
+ else if (MaxSize == 0)
+ return false;
+
+ Piaf = (PIP_ADAPTER_INFO)PlugSubAlloc(g, NULL, Buflen);
+ drc = GetAdaptersInfo(Piaf, &Buflen);
+
+ if (drc == ERROR_SUCCESS) {
+ Next = Piaf; // Next is the first one
+ return false; // Success
+ } // endif drc
+
+ MakeErrorMsg(g, drc);
+ return true;
+ } // end of GetMacInfo
+
+/***********************************************************************/
+/* GetFixedInfo: Get info for network parameters. */
+/***********************************************************************/
+bool TDBMAC::GetFixedInfo(PGLOBAL g)
+ {
+ ULONG len;
+ DWORD drc;
+
+ FixedInfo = (FIXED_INFO*)PlugSubAlloc(g, NULL, sizeof(FIXED_INFO));
+ len = sizeof(FIXED_INFO);
+ drc = GetNetworkParams(FixedInfo, &len);
+
+ if (drc == ERROR_BUFFER_OVERFLOW) {
+ FixedInfo = (FIXED_INFO*)PlugSubAlloc(g, NULL, len);
+ drc = GetNetworkParams(FixedInfo, &len);
+ } // endif drc
+
+ if (drc != ERROR_SUCCESS) {
+ sprintf(g->Message, "GetNetworkParams failed. Rc=%08x\n", drc);
+ return true;
+ } // endif drc
+
+ return false;
+ } // end of GetFixedInfo
+
+/***********************************************************************/
+/* MAC: Get the number of found adapters. */
+/***********************************************************************/
+int TDBMAC::GetMaxSize(PGLOBAL g)
+ {
+ if (Use != USE_OPEN)
+ // Called from info, Adap and Fix are not set yet
+ return 1;
+
+ if (MaxSize < 0) {
+ // Best method
+ if (Adap) {
+ DWORD drc = GetAdaptersInfo(NULL, &(Buflen = 0));
+
+ if (drc == ERROR_SUCCESS)
+ MaxSize = (Fix) ? 1 : 0;
+ else if (drc == ERROR_BUFFER_OVERFLOW) {
+ // sizeof(IP_ADAPTER_INFO) was returning 640 but is now sometimes
+ // returning 648 while the Buflen setting remains the same (n*640)
+ // >> Of course, the code above contains a race condition....
+ // if the size of the structure Windows wants to return grows after
+ // the first call to GetAdaptersInfo() but before the second call
+ // to GetAdaptersInfo(), the second call to GetAdaptersInfo() will
+ // fail with ERROR_BUFFER_OVERFLOW as well, and your function won't
+ // work (by Jeremy Friesner on stackoverflow.com).
+ // That's why we add something to it to be comfortable.
+ MaxSize = (Buflen + 600) / sizeof(IP_ADAPTER_INFO);
+
+ // Now Buflen must be updated if 648 is true.
+ Buflen = MaxSize * sizeof(IP_ADAPTER_INFO);
+ } else
+ MakeErrorMsg(g, drc);
+
+ } else
+ MaxSize = (Fix) ? 1 : 0;
+
+#if 0
+ // This method returns too many adapters
+ DWORD dw, drc = GetNumberOfInterfaces((PDWORD)&dw);
+
+ if (drc == NO_ERROR) {
+ MaxSize = (int)dw;
+ Buflen = MaxSize * sizeof(IP_ADAPTER_INFO);
+ } else
+ MakeErrorMsg(g, 0);
+#endif
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* MAC Access Method opening routine. */
+/***********************************************************************/
+bool TDBMAC::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, this should not happen. */
+ /*******************************************************************/
+ strcpy(g->Message, "TDBMAC should not be reopened");
+ return true;
+ } // endif use
+
+ if (Mode != MODE_READ) {
+ /*******************************************************************/
+ /* MAC tables cannot be modified. */
+ /*******************************************************************/
+ strcpy(g->Message, "MAC tables are read only");
+ return true;
+ } else
+ Use = USE_OPEN;
+
+ /*********************************************************************/
+ /* Get the adapters info. */
+ /*********************************************************************/
+ if (Adap && GetMacInfo(g))
+ return true;
+
+ if (Fix && GetFixedInfo(g))
+ return true;
+
+ /*********************************************************************/
+ /* All is done. */
+ /*********************************************************************/
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for MAC access method. */
+/***********************************************************************/
+int TDBMAC::ReadDB(PGLOBAL g)
+ {
+ Curp = Next;
+
+ if (Curp)
+ Next = Curp->Next;
+ else if (N || !Fix)
+ return RC_EF;
+
+ N++;
+ return RC_OK;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for MAC access methods. */
+/***********************************************************************/
+int TDBMAC::WriteDB(PGLOBAL g)
+ {
+ strcpy(g->Message, "MAC tables are read only");
+ return RC_FX;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for MAC access methods. */
+/***********************************************************************/
+int TDBMAC::DeleteDB(PGLOBAL g, int irc)
+ {
+ strcpy(g->Message, "Delete not enabled for MAC tables");
+ return RC_FX;
+ } // end of DeleteDB
+
+// ------------------------ MACCOL functions ----------------------------
+
+/***********************************************************************/
+/* MACCOL public constructor. */
+/***********************************************************************/
+MACCOL::MACCOL(PCOLDEF cdp, PTDB tdbp, int n)
+ : COLBLK(cdp, tdbp, n)
+ {
+ Tdbp = (PTDBMAC)tdbp;
+ Flag = cdp->GetOffset();
+
+ if (Flag < 10)
+ Tdbp->Fix = true;
+ else
+ Tdbp->Adap = true;
+
+ } // end of MACCOL constructor
+
+/***********************************************************************/
+/* Read the next MAC address elements. */
+/***********************************************************************/
+void MACCOL::ReadColumn(PGLOBAL g)
+ {
+ // Type conversion is handled by Value set routines
+ char *p = NULL, buf[260] = "";
+ unsigned int i;
+ int n = 0;
+ PIP_ADAPTER_INFO adp = Tdbp->Curp;
+ FIXED_INFO *fip = Tdbp->FixedInfo;
+
+ if (!adp && Flag >= 10) {
+ // Fix info row, no adapter info available
+ switch (Flag) {
+ case 13:
+ case 14:
+ case 19:
+ case 22:
+ case 23:
+ n = 0;
+ break;
+ default:
+ p = PlugDup(g, "");
+ } // endswitch Flag
+
+ } else switch (Flag) {
+ // FIXED INFO
+ case 1: // Host Name
+ p = fip->HostName;
+ break;
+ case 2: // Domain Name
+ p = fip->DomainName;
+ break;
+ case 3: // DNS IPaddress
+ p = (fip->CurrentDnsServer)
+ ? (char*)&fip->CurrentDnsServer->IpAddress
+ : (char*)&fip->DnsServerList.IpAddress;
+ break;
+ case 4: // Node Type
+ n = (int)fip->NodeType;
+ break;
+ case 5: // Scope ID ???
+ p = fip->ScopeId;
+ break;
+ case 6: // Routing enabled
+ n = (int)fip->EnableRouting;
+ break;
+ case 7: // Proxy enabled
+ n = (int)fip->EnableProxy;
+ break;
+ case 8: // DNS enabled
+ n = (int)fip->EnableDns;
+ break;
+ // ADAPTERS INFO
+ case 10: // Name
+ p = adp->AdapterName;
+ break;
+ case 11: // Description
+ if ((p = strstr(adp->Description, " - Packet Scheduler Miniport"))) {
+ strncpy(buf, adp->Description, p - adp->Description);
+ i = (int)(p - adp->Description);
+ strncpy(buf, adp->Description, i);
+ buf[i] = 0;
+ p = buf;
+ } else if ((p = strstr(adp->Description,
+ " - Miniport d'ordonnancement de paquets"))) {
+ i = (int)(p - adp->Description);
+ strncpy(buf, adp->Description, i);
+ buf[i] = 0;
+ p = buf;
+ } else
+ p = adp->Description;
+
+ break;
+ case 12: // MAC Address
+ for (p = buf, i = 0; i < adp->AddressLength; i++) {
+ if (i)
+ strcat(p++, "-");
+
+ p += sprintf(p, "%.2X", adp->Address[i]);
+ } // endfor i
+
+ p = buf;
+ break;
+ case 13: // Type
+#if 0 // This is not found in the SDK
+ switch (adp->Type) {
+ case IF_ETHERNET_ADAPTERTYPE: p = "Ethernet Adapter"; break;
+ case IF_TOKEN_RING_ADAPTERTYPE: p = "Token Ring Adapter"; break;
+ case IF_FDDI_ADAPTERTYPE: p = "FDDI Adapter"; break;
+ case IF_PPP_ADAPTERTYPE: p = "PPP Adapter"; break;
+ case IF_LOOPBACK_ADAPTERTYPE: p = "Loop Back Adapter"; break;
+// case IF_SLIP_ADAPTERTYPE: p = "Generic Slip Adapter"; break;
+ default:
+ sprintf(buf, "Other Adapter, type=%d", adp->Type);
+ p = buf;
+ } // endswitch Type
+#endif // 0
+ n = (int)adp->Type;
+ break;
+ case 14: // DHCP enabled
+ n = (int)adp->DhcpEnabled;
+ break;
+ case 15: // IP Address
+ p = (adp->CurrentIpAddress)
+ ? (char*)&adp->CurrentIpAddress->IpAddress
+ : (char*)&adp->IpAddressList.IpAddress;
+ break;
+ case 16: // Subnet Mask
+ p = (adp->CurrentIpAddress)
+ ? (char*)&adp->CurrentIpAddress->IpMask
+ : (char*)&adp->IpAddressList.IpMask;
+ break;
+ case 17: // Gateway
+ p = (char*)&adp->GatewayList.IpAddress;
+ break;
+ case 18: // DHCP Server
+ p = (char*)&adp->DhcpServer.IpAddress;
+ break;
+ case 19: // Have WINS
+ n = (adp->HaveWins) ? 1 : 0;
+ break;
+ case 20: // Primary WINS
+ p = (char*)&adp->PrimaryWinsServer.IpAddress;
+ break;
+ case 21: // Secondary WINS
+ p = (char*)&adp->SecondaryWinsServer.IpAddress;
+ break;
+ case 22: // Lease obtained
+ n = (int)adp->LeaseObtained;
+ break;
+ case 23: // Lease expires
+ n = (int)adp->LeaseExpires;
+ break;
+ default:
+ if (Buf_Type == TYPE_STRING) {
+ sprintf(buf, "Invalid flag value %d", Flag);
+ p = buf;
+ } else
+ n = 0;
+
+ } // endswitch Flag
+
+ if (p)
+ Value->SetValue_psz(p);
+ else
+ Value->SetValue(n);
+
+ } // end of ReadColumn
diff --git a/storage/connect/tabmac.h b/storage/connect/tabmac.h
new file mode 100644
index 00000000..68135edb
--- /dev/null
+++ b/storage/connect/tabmac.h
@@ -0,0 +1,108 @@
+// TABMAC.H Olivier Bertrand 2011-2012
+// MAC: virtual table to Get Mac Addresses via GetAdaptersInfo
+#if defined(_WIN32)
+#include <windows.h>
+#include <iphlpapi.h>
+#else // !_WIN32
+#error This is a WINDOWS only table TYPE
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Definitions. */
+/***********************************************************************/
+typedef class MACDEF *PMACDEF;
+typedef class TDBMAC *PTDBMAC;
+typedef class MACCOL *PMACCOL;
+
+/* -------------------------- MAC classes ---------------------------- */
+
+/***********************************************************************/
+/* MAC: virtual table to get the list of MAC addresses. */
+/***********************************************************************/
+class DllExport MACDEF : public TABDEF { /* Logical table description */
+ friend class TDBMAC;
+ public:
+ // Constructor
+ MACDEF(void) {Pseudo = 3;}
+
+ // Implementation
+ virtual const char *GetType(void) {return "MAC";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+//virtual bool DeleteTableFile(PGLOBAL g) {return true;}
+
+ protected:
+ // Members
+ }; // end of MACDEF
+
+/***********************************************************************/
+/* This is the class declaration for the MAC table. */
+/***********************************************************************/
+class TDBMAC : public TDBASE {
+ friend class MACCOL;
+ public:
+ // Constructor
+ TDBMAC(PMACDEF tdp);
+//TDBMAC(PGLOBAL g, PTDBMAC tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_MAC;}
+//virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMAC(g, this);}
+
+ // Methods
+//virtual PTDB Clone(PTABS t);
+ virtual int GetRecpos(void) {return N;}
+ virtual int RowNumber(PGLOBAL g, bool b = false) {return N;}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g) {return GetMaxSize(g);}
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g) {}
+
+ protected:
+ // Specific routines
+ bool GetMacInfo(PGLOBAL g);
+ bool GetFixedInfo(PGLOBAL g);
+ void MakeErrorMsg(PGLOBAL g, DWORD drc);
+
+ // Members
+ FIXED_INFO *FixedInfo; // Points to fixed info structure
+ PIP_ADAPTER_INFO Piaf; // Points on Adapter info array
+ PIP_ADAPTER_INFO Curp; // Points on current Adapt info
+ PIP_ADAPTER_INFO Next; // Points on next Adapt info
+ ULONG Buflen; // Buffer length
+ bool Fix; // true if FixedInfo is needed
+ bool Adap; // true if Piaf is needed
+ int N; // Row number
+ }; // end of class TDBMAC
+
+/***********************************************************************/
+/* Class MACCOL: MAC Address column. */
+/***********************************************************************/
+class MACCOL : public COLBLK {
+ friend class TDBMAC;
+ public:
+ // Constructors
+ MACCOL(PCOLDEF cdp, PTDB tdbp, int n);
+//MACCOL(MACCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_MAC;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ MACCOL(void) {} // Default constructor not to be used
+
+ // Members
+ PTDBMAC Tdbp; // Points to MAC table block
+ int Flag; // Indicates what to display
+ }; // end of class MACCOL
diff --git a/storage/connect/tabmul.cpp b/storage/connect/tabmul.cpp
new file mode 100644
index 00000000..d2601495
--- /dev/null
+++ b/storage/connect/tabmul.cpp
@@ -0,0 +1,1623 @@
+/************* TabMul C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABMUL */
+/* ------------- */
+/* Version 1.9 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to PlugDB Software Development 2003 - 2017 */
+/* Author: Olivier BERTRAND */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TDBMUL class DB routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABMUL.CPP - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABDOS.H - TABDOS classes declaration file */
+/* TABMUL.H - TABFIX classes declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant section of system dependant header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <stdlib.h>
+#include <stdio.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#if defined(PATHMATCHSPEC)
+#include "Shlwapi.h"
+//using namespace std;
+#pragma comment(lib,"shlwapi.lib")
+#endif // PATHMATCHSPEC
+#else
+#if defined(UNIX)
+#include <fnmatch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+#else
+//#include <io.h>
+#endif
+//#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h" // global declarations
+#include "plgdbsem.h" // DB application declarations
+#include "reldef.h" // DB definition declares
+#include "filamtxt.h"
+#include "tabdos.h" // TDBDOS and DOSCOL class dcls
+#include "tabmul.h" // TDBMUL and MULCOL classes dcls
+
+/* ------------------------- Class TDBMUL ---------------------------- */
+
+/***********************************************************************/
+/* TABMUL constructors. */
+/***********************************************************************/
+TDBMUL::TDBMUL(PTDB tdbp) : TDBASE(tdbp->GetDef())
+ {
+ Tdbp = tdbp;
+ Filenames = NULL;
+ Rows = 0;
+ Mul = tdbp->GetDef()->GetMultiple();
+ NumFiles = 0;
+ iFile = 0;
+ } // end of TDBMUL standard constructor
+
+TDBMUL::TDBMUL(PTDBMUL tdbp) : TDBASE(tdbp)
+ {
+ Tdbp = tdbp->Tdbp;
+ Filenames = tdbp->Filenames;
+ Rows = tdbp->Rows;
+ Mul = tdbp->Mul;
+ NumFiles = tdbp->NumFiles;
+ iFile = tdbp->iFile;
+ } // end of TDBMUL copy constructor
+
+// Method
+PTDB TDBMUL::Clone(PTABS t)
+ {
+ PTDBMUL tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBMUL(this);
+ tp->Tdbp = Tdbp->Clone(t);
+ tp->Columns = tp->Tdbp->GetColumns();
+ return tp;
+ } // end of Clone
+
+PTDB TDBMUL::Duplicate(PGLOBAL g)
+ {
+ PTDBMUL tmup = new(g) TDBMUL(this);
+
+ tmup->Tdbp = Tdbp->Duplicate(g);
+ return tmup;
+ } // end of Duplicate
+
+/***********************************************************************/
+/* Initializes the table filename list. */
+/* Note: tables created by concatenating the file components without */
+/* specifying the LRECL value (that should be restricted to _MAX_PATH)*/
+/* have a LRECL that is the sum of the lengths of all components. */
+/* This is why we use a big filename array to take care of that. */
+/***********************************************************************/
+bool TDBMUL::InitFileNames(PGLOBAL g)
+ {
+#define PFNZ 4096
+#define FNSZ (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT)
+ PTDBDIR dirp;
+ PSZ pfn[PFNZ];
+ PSZ filename;
+ int rc, n = 0;
+
+ if (trace(1))
+ htrc("in InitFileName: fn[]=%d\n", FNSZ);
+
+ filename = (char*)PlugSubAlloc(g, NULL, FNSZ);
+
+ // The sub table may need to refer to the Table original block
+ Tdbp->SetTable(To_Table); // Was not set at construction
+
+ PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
+
+ if (trace(1))
+ htrc("InitFileName: fn='%s'\n", filename);
+
+ if (Mul != 2) {
+ /*******************************************************************/
+ /* To_File is a multiple name with special characters */
+ /*******************************************************************/
+ if (Mul == 1)
+ dirp = new(g) TDBDIR(PlugDup(g, filename));
+ else // Mul == 3 (Subdir)
+ dirp = new(g) TDBSDR(PlugDup(g, filename));
+
+ if (dirp->OpenDB(g))
+ return true;
+
+ if (trace(1) && Mul == 3) {
+ int nf = ((PTDBSDR)dirp)->FindInDir(g);
+ htrc("Number of files = %d\n", nf);
+ } // endif trace
+
+ while (true)
+ if ((rc = dirp->ReadDB(g)) == RC_OK) {
+#if defined(_WIN32)
+ strcat(strcpy(filename, dirp->Drive), dirp->Direc);
+#else // !_WIN32
+ strcpy(filename, dirp->Direc);
+#endif // !_WIN32
+ strcat(strcat(filename, dirp->Fname), dirp->Ftype);
+ pfn[n++] = PlugDup(g, filename);
+ } else
+ break;
+
+ dirp->CloseDB(g);
+
+ if (rc == RC_FX)
+ return true;
+
+ } else {
+ /*******************************************************************/
+ /* To_File is the name of a file containing the file name list */
+ /*******************************************************************/
+ char *p;
+ FILE *stream;
+
+ if (!(stream= global_fopen(g, MSGID_OPEN_MODE_STRERROR, filename, "r")))
+ return true;
+
+ while (n < PFNZ) {
+ if (!fgets(filename, FNSZ, stream)) {
+ fclose(stream);
+ break;
+ } // endif fgets
+
+ p = filename + strlen(filename) - 1;
+
+#if !defined(_WIN32)
+ // Data files can be imported from Windows (having CRLF)
+ if (*p == '\n' || *p == '\r') {
+ // is this enough for Unix ???
+ p--; // Eliminate ending CR or LF character
+
+ if (p >= filename)
+ // is this enough for Unix ???
+ if (*p == '\n' || *p == '\r')
+ p--; // Eliminate ending CR or LF character
+
+ } // endif p
+
+#else
+ if (*p == '\n')
+ p--; // Eliminate ending new-line character
+#endif
+ // Trim rightmost blanks
+ for (; p >= filename && *p == ' '; p--) ;
+
+ *(++p) = '\0';
+
+ // Suballocate the file name
+ pfn[n++] = PlugDup(g, filename);
+ } // endfor n
+
+ } // endif Mul
+
+ if (n) {
+ Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
+
+ for (int i = 0; i < n; i++)
+ Filenames[i] = pfn[i];
+
+ } else {
+ Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
+ Filenames[0] = NULL;
+ } // endif n
+
+ NumFiles = n;
+ return false;
+ } // end of InitFileNames
+
+/***********************************************************************/
+/* The table column list is the sub-table column list. */
+/***********************************************************************/
+PCOL TDBMUL::ColDB(PGLOBAL g, PSZ name, int num)
+ {
+ PCOL cp;
+
+ /*********************************************************************/
+ /* Because special columns are directly added to the MUL block, */
+ /* make sure that the sub-table has the same column list, before */
+ /* and after the call to the ColDB function. */
+ /*********************************************************************/
+ Tdbp->SetColumns(Columns);
+ cp = Tdbp->ColDB(g, name, num);
+ Columns = Tdbp->GetColumns();
+ return cp;
+} // end of ColDB
+
+/***********************************************************************/
+/* MUL GetProgMax: get the max value for progress information. */
+/***********************************************************************/
+int TDBMUL::GetProgMax(PGLOBAL g)
+ {
+ if (!Filenames && InitFileNames(g))
+ return -1;
+
+ return NumFiles; // This is a temporary setting
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* MUL GetProgCur: get the current value for progress information. */
+/***********************************************************************/
+int TDBMUL::GetProgCur(void)
+ {
+ return iFile; // This is a temporary setting
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* MUL Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/* Can be used on Multiple FIX table only. */
+/***********************************************************************/
+int TDBMUL::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return Tdbp->Cardinality(g);
+
+ if (!Filenames && InitFileNames(g))
+ return -1;
+
+ int n, card = 0;
+
+ for (int i = 0; i < NumFiles; i++) {
+ Tdbp->SetFile(g, Filenames[i]);
+ Tdbp->ResetSize();
+
+ if ((n = Tdbp->Cardinality(g)) < 0) {
+// strcpy(g->Message, MSG(BAD_CARDINALITY));
+ return -1;
+ } // endif n
+
+ card += n;
+ } // endfor i
+
+ return card;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Sum up the sizes of all sub-tables. */
+/***********************************************************************/
+int TDBMUL::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ int i;
+ int mxsz;
+
+ if (trace(1))
+ htrc("TDBMUL::GetMaxSize: Filenames=%p\n", Filenames);
+
+ if (!Filenames && InitFileNames(g))
+ return -1;
+
+ if (Use == USE_OPEN) {
+ strcpy(g->Message, MSG(MAXSIZE_ERROR));
+ return -1;
+ } else
+ MaxSize = 0;
+
+ for (i = 0; i < NumFiles; i++) {
+ Tdbp->SetFile(g, Filenames[i]);
+ Tdbp->ResetSize();
+
+ if ((mxsz = Tdbp->GetMaxSize(g)) < 0) {
+ MaxSize = -1;
+ return mxsz;
+ } // endif mxsz
+
+ MaxSize += mxsz;
+ } // endfor i
+
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void TDBMUL::ResetDB(void)
+ {
+ for (PCOL colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_FILID)
+ colp->COLBLK::Reset();
+
+ Tdbp->ResetDB();
+ } // end of ResetDB
+
+/***********************************************************************/
+/* Returns RowId if b is false or Rownum if b is true. */
+/***********************************************************************/
+int TDBMUL::RowNumber(PGLOBAL g, bool b)
+ {
+ return ((b) ? 0 : Rows)
+ + ((iFile < NumFiles) ? Tdbp->RowNumber(g, b) : 1);
+ } // end of RowNumber
+
+/***********************************************************************/
+/* MUL Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBMUL::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("MUL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, replace it at its beginning. */
+ /*******************************************************************/
+ if (Filenames[iFile = 0]) {
+ Tdbp->CloseDB(g);
+ Tdbp->SetUse(USE_READY);
+ Tdbp->SetFile(g, Filenames[iFile = 0]);
+ Tdbp->ResetSize();
+ Rows = 0;
+ ResetDB();
+ return Tdbp->OpenDB(g); // Re-open with new file name
+ } else
+ return false;
+
+ } // endif use
+
+ /*********************************************************************/
+ /* We need to calculate MaxSize before opening the query. */
+ /*********************************************************************/
+ if (GetMaxSize(g) < 0)
+ return true;
+
+ /*********************************************************************/
+ /* Open the first table file of the list. */
+ /*********************************************************************/
+//if (!Filenames && InitFileNames(g)) // was done in GetMaxSize
+// return true;
+
+ if (Filenames[iFile = 0]) {
+ Tdbp->SetFile(g, Filenames[0]);
+ Tdbp->SetMode(Mode);
+ Tdbp->ResetDB();
+ Tdbp->ResetSize();
+
+ if (Tdbp->OpenDB(g))
+ return true;
+
+ } // endif *Filenames
+
+ Use = USE_OPEN;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for MUL access method. */
+/***********************************************************************/
+int TDBMUL::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+ if (NumFiles == 0)
+ return RC_EF;
+ else if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ strcpy(g->Message, MSG(NO_INDEX_READ));
+ rc = RC_FX;
+ } else {
+ /*******************************************************************/
+ /* Now start the reading process. */
+ /*******************************************************************/
+ retry:
+ rc = Tdbp->ReadDB(g);
+
+ if (rc == RC_EF) {
+ if (Tdbp->GetDef()->GetPseudo() & 1)
+ // Total number of rows met so far
+ Rows += Tdbp->RowNumber(g) - 1;
+
+ if (++iFile < NumFiles) {
+ /***************************************************************/
+ /* Continue reading from next table file. */
+ /***************************************************************/
+ Tdbp->CloseDB(g);
+ Tdbp->SetUse(USE_READY);
+ Tdbp->SetFile(g, Filenames[iFile]);
+ Tdbp->ResetSize();
+ ResetDB();
+
+ if (Tdbp->OpenDB(g)) // Re-open with new file name
+ return RC_FX;
+
+ goto retry;
+ } // endif iFile
+
+ } else if (rc == RC_FX)
+ strcat(strcat(strcat(g->Message, " ("), Tdbp->GetFile(g)), ")");
+
+ } // endif To_Kindex
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* Data Base write routine for MUL access method. */
+/***********************************************************************/
+int TDBMUL::WriteDB(PGLOBAL g)
+ {
+ return Tdbp->WriteDB(g);
+// strcpy(g->Message, MSG(TABMUL_READONLY));
+// return RC_FX; // NIY
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for MUL access method. */
+/***********************************************************************/
+int TDBMUL::DeleteDB(PGLOBAL g, int)
+ {
+ // When implementing DELETE_MODE InitFileNames must be updated to
+ // eliminate CRLF under Windows if the file is read in binary.
+ strcpy(g->Message, MSG(TABMUL_READONLY));
+ return RC_FX; // NIY
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for MUL access method. */
+/***********************************************************************/
+void TDBMUL::CloseDB(PGLOBAL g)
+ {
+ if (NumFiles > 0) {
+ Tdbp->CloseDB(g);
+ iFile = NumFiles;
+ } // endif NumFiles
+
+ } // end of CloseDB
+
+#if 0
+/* ------------------------- Class TDBMSD ---------------------------- */
+
+ // Method
+PTDB TDBMSD::Clone(PTABS t)
+{
+ PTDBMSD tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBMSD(this);
+ tp->Tdbp = Tdbp->Clone(t);
+ tp->Columns = tp->Tdbp->GetColumns();
+ return tp;
+} // end of Clone
+
+PTDB TDBMSD::Duplicate(PGLOBAL g)
+{
+ PTDBMSD tmup = new(g) TDBMSD(this);
+
+ tmup->Tdbp = Tdbp->Duplicate(g);
+ return tmup;
+} // end of Duplicate
+
+/***********************************************************************/
+/* Initializes the table filename list. */
+/* Note: tables created by concatenating the file components without */
+/* specifying the LRECL value (that should be restricted to _MAX_PATH)*/
+/* have a LRECL that is the sum of the lengths of all components. */
+/* This is why we use a big filename array to take care of that. */
+/***********************************************************************/
+bool TDBMSD::InitFileNames(PGLOBAL g)
+{
+#define PFNZ 4096
+#define FNSZ (_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT)
+ PTDBSDR dirp;
+ PSZ pfn[PFNZ];
+ PSZ filename;
+ int rc, n = 0;
+
+ if (trace(1))
+ htrc("in InitFileName: fn[]=%d\n", FNSZ);
+
+ filename = (char*)PlugSubAlloc(g, NULL, FNSZ);
+
+ // The sub table may need to refer to the Table original block
+ Tdbp->SetTable(To_Table); // Was not set at construction
+
+ PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
+
+ if (trace(1))
+ htrc("InitFileName: fn='%s'\n", filename);
+
+ dirp = new(g) TDBSDR(filename);
+
+ if (dirp->OpenDB(g))
+ return true;
+
+ while (true)
+ if ((rc = dirp->ReadDB(g)) == RC_OK) {
+#if defined(_WIN32)
+ strcat(strcpy(filename, dirp->Drive), dirp->Direc);
+#else // !_WIN32
+ strcpy(filename, dirp->Direc);
+#endif // !_WIN32
+ strcat(strcat(filename, dirp->Fname), dirp->Ftype);
+ pfn[n++] = PlugDup(g, filename);
+ } else
+ break;
+
+ if (rc == RC_FX)
+ return true;
+
+ if (n) {
+ Filenames = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
+
+ for (int i = 0; i < n; i++)
+ Filenames[i] = pfn[i];
+
+ } else {
+ Filenames = (char**)PlugSubAlloc(g, NULL, sizeof(char*));
+ Filenames[0] = NULL;
+ } // endif n
+
+ NumFiles = n;
+ return false;
+} // end of InitFileNames
+#endif // 0
+
+ /* --------------------------- Class DIRDEF -------------------------- */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool DIRDEF::DefineAM(PGLOBAL g, LPCSTR, int)
+ {
+ Desc = Fn = GetStringCatInfo(g, "Filename", NULL);
+ Incl = GetBoolCatInfo("Subdir", false);
+ Huge = GetBoolCatInfo("Huge", false);
+ Nodir = GetBoolCatInfo("Nodir", true);
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB DIRDEF::GetTable(PGLOBAL g, MODE)
+ {
+#if 0
+ if (Huge)
+ return new(g) TDBDHR(this); // Not implemented yet
+ else
+#endif
+ if (Incl)
+ return new(g) TDBSDR(this); // Including sub-directory files
+ else
+ return new(g) TDBDIR(this); // Not Including sub-directory files
+
+ } // end of GetTable
+
+/* ------------------------- Class TDBDIR ---------------------------- */
+
+/***********************************************************************/
+/* TABDIR constructors. */
+/***********************************************************************/
+void TDBDIR::Init(void)
+{
+ iFile = 0;
+#if defined(_WIN32)
+ Dvalp = NULL;
+ memset(&FileData, 0, sizeof(_finddata_t));
+ hSearch = INVALID_HANDLE_VALUE;
+ *Drive = '\0';
+#else // !_WIN32
+ memset(&Fileinfo, 0, sizeof(struct stat));
+ Entry = NULL;
+ Dir = NULL;
+ Done = false;
+ *Pattern = '\0';
+#endif // !_WIN32
+ *Fpath = '\0';
+ *Direc = '\0';
+ *Fname = '\0';
+ *Ftype = '\0';
+} // end of Init
+
+TDBDIR::TDBDIR(PDIRDEF tdp) : TDBASE(tdp)
+{
+ To_File = tdp->Fn;
+ Nodir = tdp->Nodir;
+ Init();
+} // end of TDBDIR standard constructor
+
+TDBDIR::TDBDIR(PSZ fpat) : TDBASE((PTABDEF)NULL)
+{
+ To_File = fpat;
+ Nodir = true;
+ Init();
+} // end of TDBDIR constructor
+
+/***********************************************************************/
+/* Initialize/get the components of the search file pattern. */
+/***********************************************************************/
+char* TDBDIR::Path(PGLOBAL g)
+ {
+ (void) PlgGetCatalog(g); // XXX Should be removed?
+ PTABDEF defp = (PTABDEF)To_Def;
+
+#if defined(_WIN32)
+ if (!*Drive) {
+ PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL);
+ _splitpath(Fpath, Drive, Direc, Fname, Ftype);
+ } else
+ _makepath(Fpath, Drive, Direc, Fname, Ftype); // Usefull for TDBSDR
+
+ return Fpath;
+#else // !_WIN32
+ if (!Done) {
+ PlugSetPath(Fpath, To_File, defp ? defp->GetPath() : NULL);
+ _splitpath(Fpath, NULL, Direc, Fname, Ftype);
+ strcat(strcpy(Pattern, Fname), Ftype);
+ Done = true;
+ } // endif Done
+
+ return Pattern;
+#endif // !_WIN32
+ } // end of Path
+
+/***********************************************************************/
+/* Allocate DIR column description block. */
+/***********************************************************************/
+PCOL TDBDIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) DIRCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* DIR GetMaxSize: returns the number of retrieved files. */
+/***********************************************************************/
+int TDBDIR::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ int n = -1;
+#if defined(_WIN32)
+ int rc;
+ // Start searching files in the target directory.
+ hSearch = FindFirstFile(Path(g), &FileData);
+
+ if (hSearch == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+
+ if (rc != ERROR_FILE_NOT_FOUND) {
+ char buf[512];
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
+ return -1;
+ } // endif rc
+
+ return 0;
+ } // endif hSearch
+
+ while (true) {
+ if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ n++;
+
+ if (!FindNextFile(hSearch, &FileData)) {
+ rc = GetLastError();
+
+ if (rc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
+ FindClose(hSearch);
+ return -1;
+ } // endif rc
+
+ break;
+ } // endif Next
+
+ } // endwhile
+
+ // Close the search handle.
+ FindClose(hSearch);
+#else // !_WIN32
+ Path(g);
+
+ // Start searching files in the target directory.
+ if (!(Dir = opendir(Direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
+ return -1;
+ } // endif dir
+
+ while ((Entry = readdir(Dir))) {
+ strcat(strcpy(Fpath, Direc), Entry->d_name);
+
+ if (lstat(Fpath, &Fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ return -1;
+ } else if (S_ISREG(Fileinfo.st_mode))
+ // Test whether the file name matches the table name filter
+ if (!fnmatch(Pattern, Entry->d_name, 0))
+ n++; // We have a match
+
+ } // endwhile Entry
+
+ // Close the DIR handle.
+ closedir(Dir);
+#endif // !_WIN32
+ MaxSize = n;
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* DIR Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBDIR::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("DIR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, reopen it. */
+ /*******************************************************************/
+ CloseDB(g);
+ SetUse(USE_READY);
+ } // endif use
+
+ Use = USE_OPEN;
+#if !defined(_WIN32)
+ Path(g); // Be sure it is done
+ Dir = NULL; // For ReadDB
+#endif // !_WIN32
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for DIR access method. */
+/***********************************************************************/
+int TDBDIR::ReadDB(PGLOBAL g)
+ {
+ int rc = RC_OK;
+
+#if defined(_WIN32)
+ do {
+ if (hSearch == INVALID_HANDLE_VALUE) {
+ /*****************************************************************/
+ /* Start searching files in the target directory. The use of */
+ /* the Path function is required when called from TDBSDR. */
+ /*****************************************************************/
+ hSearch = FindFirstFile(Path(g), &FileData);
+
+ if (hSearch == INVALID_HANDLE_VALUE) {
+ rc = RC_EF;
+ break;
+ } else
+ iFile++;
+
+ } else {
+ if (!FindNextFile(hSearch, &FileData)) {
+ // Restore file name and type pattern
+ _splitpath(To_File, NULL, NULL, Fname, Ftype);
+ rc = RC_EF;
+ break;
+ } else
+ iFile++;
+
+ } // endif hSearch
+
+ } while (Nodir && FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+
+ if (rc == RC_OK)
+ _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
+
+#else // !Win32
+ rc = RC_NF;
+
+ if (!Dir)
+ // Start searching files in the target directory.
+ if (!(Dir = opendir(Direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
+ rc = RC_FX;
+ } // endif dir
+
+ while (rc == RC_NF)
+ if ((Entry = readdir(Dir))) {
+ // We need the Fileinfo structure to get info about the file
+ strcat(strcpy(Fpath, Direc), Entry->d_name);
+
+ if (lstat(Fpath, &Fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ rc = RC_FX;
+ } else if (S_ISREG(Fileinfo.st_mode))
+ // Test whether the file name matches the table name filter
+ if (!fnmatch(Pattern, Entry->d_name, 0)) {
+ iFile++; // We have a match
+ _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
+ rc = RC_OK;
+ } // endif fnmatch
+
+ } else {
+ // Restore file name and type pattern
+ _splitpath(To_File, NULL, NULL, Fname, Ftype);
+ rc = RC_EF;
+ } // endif Entry
+
+#endif // !_WIN32
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* Data Base write routine for DIR access method. */
+/***********************************************************************/
+int TDBDIR::WriteDB(PGLOBAL g)
+ {
+ strcpy(g->Message, MSG(TABDIR_READONLY));
+ return RC_FX; // NIY
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for DIR access method. */
+/***********************************************************************/
+int TDBDIR::DeleteDB(PGLOBAL g, int)
+ {
+ strcpy(g->Message, MSG(TABDIR_READONLY));
+ return RC_FX; // NIY
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for MUL access method. */
+/***********************************************************************/
+void TDBDIR::CloseDB(PGLOBAL)
+ {
+#if defined(_WIN32)
+ // Close the search handle.
+ FindClose(hSearch);
+ hSearch = INVALID_HANDLE_VALUE;
+#else // !_WIN32
+ // Close the DIR handle
+ if (Dir) {
+ closedir(Dir);
+ Dir = NULL;
+ } // endif dir
+#endif // !_WIN32
+ iFile = 0;
+ } // end of CloseDB
+
+// ------------------------ DIRCOL functions ----------------------------
+
+/***********************************************************************/
+/* DIRCOL public constructor. */
+/***********************************************************************/
+DIRCOL::DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional DIR access method information for column.
+ Tdbp = (PTDBDIR)tdbp;
+ N = cdp->GetOffset();
+ } // end of DIRCOL constructor
+
+/***********************************************************************/
+/* DIRCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+DIRCOL::DIRCOL(DIRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Tdbp = (PTDBDIR)tdbp;
+ N = col1->N;
+ } // end of DIRCOL copy constructor
+
+#if defined(_WIN32)
+/***********************************************************************/
+/* Retrieve time information from FileData. */
+/***********************************************************************/
+void DIRCOL::SetTimeValue(PGLOBAL g, FILETIME& ftime)
+{
+ char tsp[24];
+ SYSTEMTIME stp;
+
+ if (FileTimeToSystemTime(&ftime, &stp)) {
+ sprintf(tsp, "%04d-%02d-%02d %02d:%02d:%02d",
+ stp.wYear, stp.wMonth, stp.wDay, stp.wHour, stp.wMinute, stp.wSecond);
+
+ if (Value->GetType() != TYPE_STRING) {
+ if (!Tdbp->Dvalp)
+ Tdbp->Dvalp = AllocateValue(g, TYPE_DATE, 20, 0, false,
+ "YYYY-MM-DD hh:mm:ss");
+
+ Tdbp->Dvalp->SetValue_psz(tsp);
+ Value->SetValue_pval(Tdbp->Dvalp);
+ } else
+ Value->SetValue_psz(tsp);
+
+ } else
+ Value->Reset();
+
+} // end of SetTimeValue
+#endif // _WIN32
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the information */
+/* corresponding to this column and convert it to buffer type. */
+/***********************************************************************/
+void DIRCOL::ReadColumn(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("DIR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
+ Name, Tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
+
+ /*********************************************************************/
+ /* Retrieve the information corresponding to the column number. */
+ /*********************************************************************/
+ switch (N) {
+#if defined(_WIN32)
+ case 0: Value->SetValue_psz(Tdbp->Drive); break;
+#endif // _WIN32
+ case 1: Value->SetValue_psz(Tdbp->Direc); break;
+ case 2: Value->SetValue_psz(Tdbp->Fname); break;
+ case 3: Value->SetValue_psz(Tdbp->Ftype); break;
+#if defined(_WIN32)
+ case 4: Value->SetValue((int)Tdbp->FileData.dwFileAttributes); break;
+ case 5: Value->SetValue((int)Tdbp->FileData.nFileSizeLow); break;
+ case 6: SetTimeValue(g, Tdbp->FileData.ftLastWriteTime); break;
+ case 7: SetTimeValue(g, Tdbp->FileData.ftCreationTime); break;
+ case 8: SetTimeValue(g, Tdbp->FileData.ftLastAccessTime); break;
+#else // !_WIN32
+ case 4: Value->SetValue((int)Tdbp->Fileinfo.st_mode); break;
+ case 5: Value->SetValue((int)Tdbp->Fileinfo.st_size); break;
+ case 6: Value->SetValue((int)Tdbp->Fileinfo.st_mtime); break;
+ case 7: Value->SetValue((int)Tdbp->Fileinfo.st_ctime); break;
+ case 8: Value->SetValue((int)Tdbp->Fileinfo.st_atime); break;
+ case 9: Value->SetValue((int)Tdbp->Fileinfo.st_uid); break;
+ case 10: Value->SetValue((int)Tdbp->Fileinfo.st_gid); break;
+#endif // !_WIN32
+ default:
+ sprintf(g->Message, MSG(INV_DIRCOL_OFST), N);
+ throw GetAmType();
+ } // endswitch N
+
+ } // end of ReadColumn
+
+/* ------------------------- Class TDBSDR ---------------------------- */
+
+/***********************************************************************/
+/* SDR GetMaxSize: returns the number of retrieved files. */
+/***********************************************************************/
+int TDBSDR::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ Path(g);
+ MaxSize = FindInDir(g);
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* SDR FindInDir: returns the number of retrieved files. */
+/***********************************************************************/
+int TDBSDR::FindInDir(PGLOBAL g)
+ {
+ int n = 0;
+ size_t m = strlen(Direc);
+
+ // Start searching files in the target directory.
+#if defined(_WIN32)
+ int rc;
+ HANDLE h;
+
+#if defined(PATHMATCHSPEC)
+ if (!*Drive)
+ Path(g);
+
+ _makepath(Fpath, Drive, Direc, "*", "*");
+
+ h = FindFirstFile(Fpath, &FileData);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+
+ if (rc != ERROR_FILE_NOT_FOUND) {
+ char buf[512];
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
+ return -1;
+ } // endif rc
+
+ return 0;
+ } // endif h
+
+ while (true) {
+ if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ *FileData.cFileName != '.') {
+ // Look in the name sub-directory
+ strcat(strcat(Direc, FileData.cFileName), "/");
+ n += FindInDir(g);
+ Direc[m] = '\0'; // Restore path
+ } else if (PathMatchSpec(FileData.cFileName, Fpath))
+ n++;
+
+ if (!FindNextFile(h, &FileData)) {
+ rc = GetLastError();
+
+ if (rc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
+ FindClose(h);
+ return -1;
+ } // endif rc
+
+ break;
+ } // endif Next
+
+ } // endwhile
+#else // !PATHMATCHSPEC
+ h = FindFirstFile(Path(g), &FileData);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+
+ if (rc != ERROR_FILE_NOT_FOUND) {
+ char buf[512];
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), 0, (LPTSTR)&buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), buf);
+ return -1;
+ } // endif rc
+
+ return 0;
+ } // endif hSearch
+
+ while (true) {
+ n++;
+
+ if (!FindNextFile(h, &FileData)) {
+ rc = GetLastError();
+
+ if (rc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
+ FindClose(h);
+ return -1;
+ } // endif rc
+
+ break;
+ } // endif Next
+
+ } // endwhile
+
+ // Now search files in sub-directories.
+ _makepath(Fpath, Drive, Direc, "*", ".");
+ h = FindFirstFile(Fpath, &FileData);
+
+ if (h != INVALID_HANDLE_VALUE) {
+ while (true) {
+ if ((FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ *FileData.cFileName != '.') {
+ // Look in the name sub-directory
+ strcat(strcat(Direc, FileData.cFileName), "/");
+ n += FindInDir(g);
+ Direc[m] = '\0'; // Restore path
+ } // endif SUBDIR
+
+ if (!FindNextFile(h, &FileData))
+ break;
+
+ } // endwhile
+
+ } // endif h
+#endif // !PATHMATCHSPEC
+
+ // Close the search handle.
+ FindClose(h);
+#else // !_WIN32
+ int k;
+ DIR *dir = opendir(Direc);
+
+ if (!dir) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
+ return -1;
+ } // endif dir
+
+ while ((Entry = readdir(dir))) {
+ strcat(strcpy(Fpath, Direc), Entry->d_name);
+
+ if (lstat(Fpath, &Fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ return -1;
+ } else if (S_ISDIR(Fileinfo.st_mode) && *Entry->d_name != '.') {
+ // Look in the name sub-directory
+ strcat(strcat(Direc, Entry->d_name), "/");
+
+ if ((k= FindInDir(g)) < 0)
+ return k;
+ else
+ n += k;
+
+ Direc[m] = '\0'; // Restore path
+ } else if (S_ISREG(Fileinfo.st_mode))
+ // Test whether the file name matches the table name filter
+ if (!fnmatch(Pattern, Entry->d_name, 0))
+ n++; // We have a match
+
+ } // endwhile readdir
+
+ // Close the DIR handle.
+ closedir(dir);
+#endif // !_WIN32
+
+ return n;
+ } // end of FindInDir
+
+/***********************************************************************/
+/* DIR Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBSDR::OpenDB(PGLOBAL g)
+ {
+ if (!Sub) {
+ Path(g);
+ Sub = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
+ Sub->Next = NULL;
+ Sub->Prev = NULL;
+#if defined(_WIN32)
+ Sub->H = INVALID_HANDLE_VALUE;
+ Sub->Len = strlen(Direc);
+#else // !_WIN32
+ Sub->D = NULL;
+ Sub->Len = 0;
+#endif // !_WIN32
+ } // endif To_Sub
+
+ return TDBDIR::OpenDB(g);
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for SDR access method. */
+/***********************************************************************/
+int TDBSDR::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+#if defined(_WIN32)
+ again:
+ rc = TDBDIR::ReadDB(g);
+
+ if (rc == RC_EF) {
+ // Are there more files in sub-directories
+ retry:
+ do {
+ if (Sub->H == INVALID_HANDLE_VALUE) {
+// _makepath(Fpath, Drive, Direc, "*", "."); why was this made?
+ _makepath(Fpath, Drive, Direc, "*", NULL);
+ Sub->H = FindFirstFile(Fpath, &FileData);
+ } else if (!FindNextFile(Sub->H, &FileData)) {
+ FindClose(Sub->H);
+ Sub->H = INVALID_HANDLE_VALUE;
+ *FileData.cFileName= '\0';
+ break;
+ } // endif findnext
+
+ } while(!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
+ (*FileData.cFileName == '.' &&
+ (!FileData.cFileName[1] || FileData.cFileName[1] == '.')));
+
+ if (Sub->H == INVALID_HANDLE_VALUE) {
+ // No more sub-directories. Are we in a sub-directory?
+ if (!Sub->Prev)
+ return rc; // No, all is finished
+
+ // here we must continue in the parent directory
+ Sub = Sub->Prev;
+ goto retry;
+ } else {
+ // Search next sub-directory
+ Direc[Sub->Len] = '\0';
+
+ if (!Sub->Next) {
+ PSUBDIR sup;
+
+ sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
+ sup->Next = NULL;
+ sup->Prev = Sub;
+ sup->H = INVALID_HANDLE_VALUE;
+ Sub->Next = sup;
+ } // endif Next
+
+ Sub = Sub->Next;
+ strcat(strcat(Direc, FileData.cFileName), "/");
+ Sub->Len = strlen(Direc);
+
+ // Reset Hsearch used by TDBDIR::ReadDB
+ FindClose(hSearch);
+ hSearch = INVALID_HANDLE_VALUE;
+ goto again;
+ } // endif H
+
+ } // endif rc
+#else // !_WIN32
+ rc = RC_NF;
+
+ again:
+ if (!Sub->D)
+ // Start searching files in the target directory.
+ if (!(Sub->D = opendir(Direc))) {
+ sprintf(g->Message, MSG(BAD_DIRECTORY), Direc, strerror(errno));
+ rc = RC_FX;
+ } // endif dir
+
+ while (rc == RC_NF)
+ if ((Entry = readdir(Sub->D))) {
+ // We need the Fileinfo structure to get info about the file
+ strcat(strcpy(Fpath, Direc), Entry->d_name);
+
+ if (lstat(Fpath, &Fileinfo) < 0) {
+ sprintf(g->Message, "%s: %s", Fpath, strerror(errno));
+ rc = RC_FX;
+ } else if (S_ISDIR(Fileinfo.st_mode) && strcmp(Entry->d_name, ".")
+ && strcmp(Entry->d_name, "..")) {
+ // Look in the name sub-directory
+ if (!Sub->Next) {
+ PSUBDIR sup;
+
+ sup = (PSUBDIR)PlugSubAlloc(g, NULL, sizeof(SUBDIR));
+ sup->Next = NULL;
+ sup->Prev = Sub;
+ Sub->Next = sup;
+ } // endif Next
+
+ Sub = Sub->Next;
+ Sub->D = NULL;
+ Sub->Len = strlen(Direc);
+ strcat(strcat(Direc, Entry->d_name), "/");
+ goto again;
+ } else if (S_ISREG(Fileinfo.st_mode))
+ // Test whether the file name matches the table name filter
+ if (!fnmatch(Pattern, Entry->d_name, 0)) {
+ iFile++; // We have a match
+ _splitpath(Entry->d_name, NULL, NULL, Fname, Ftype);
+ rc = RC_OK;
+ } // endif fnmatch
+
+ } else {
+ // No more files. Close the DIR handle.
+ closedir(Sub->D);
+
+ // Are we in a sub-directory?
+ if (Sub->Prev) {
+ // Yes, we must continue in the parent directory
+ Direc[Sub->Len] = '\0';
+ Sub = Sub->Prev;
+ } else
+ rc = RC_EF; // No, all is finished
+
+ } // endif Entry
+
+#endif // !_WIN32
+
+ return rc;
+ } // end of ReadDB
+
+#if 0
+/* ------------------------- Class TDBDHR ---------------------------- */
+
+/***********************************************************************/
+/* TABDHR constructors. */
+/***********************************************************************/
+TDBDHR::TDBDHR(PDHRDEF tdp) : TDBASE(tdp)
+ {
+ memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
+ Hsearch = INVALID_HANDLE_VALUE;
+ iFile = 0;
+ *Drive = '\0';
+ *Direc = '\0';
+ *Fname = '\0';
+ *Ftype = '\0';
+ } // end of TDBDHR standard constructor
+
+TDBDHR::TDBDHR(PTDBDHR tdbp) : TDBASE(tdbp)
+ {
+ FileData = tdbp->FileData;
+ Hsearch = tdbp->Hsearch;
+ iFile = tdbp->iFile;
+ strcpy(Drive, tdbp->Drive);
+ strcpy(Direc, tdbp->Direc);
+ strcpy(Fname, tdbp->Fname);
+ strcpy(Ftype, tdbp->Ftype);
+ } // end of TDBDHR copy constructor
+
+// Method
+PTDB TDBDHR::Clone(PTABS t)
+ {
+ PTDB tp;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBDHR(this);
+ tp->Columns = Columns;
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Allocate DHR column description block. */
+/***********************************************************************/
+PCOL TDBDHR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) DHRCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* DHR GetMaxSize: returns the number of retrieved files. */
+/***********************************************************************/
+int TDBDHR::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ char filename[_MAX_PATH];
+ int i, rc;
+ int n = -1;
+ HANDLE h;
+ PDBUSER dup = PlgGetUser(g);
+
+ PlugSetPath(filename, To_File, dup->Path);
+
+ // Start searching files in the target directory.
+ h = FindFirstFile(filename, &FileData);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ switch (rc = GetLastError()) {
+ case ERROR_NO_MORE_FILES:
+ case ERROR_FILE_NOT_FOUND:
+ n = 0;
+ break;
+ default:
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, rc, 0,
+ (LPTSTR)&filename, sizeof(filename), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
+ } // endswitch rc
+
+ } else {
+ for (n = 1;; n++)
+ if (!FindNextFile(h, &FileData)) {
+ rc = GetLastError();
+
+ if (rc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc);
+ n = -1;
+ } // endif rc
+
+ break;
+ } // endif FindNextFile
+
+ // Close the search handle.
+ if (!FindClose(h) && n != -1)
+ strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
+
+ } // endif Hsearch
+
+ MaxSize = n;
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* DHR Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBDHR::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("DHR OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, reopen it. */
+ /*******************************************************************/
+ CloseDB(g);
+ SetUse(USE_READY);
+ } // endif use
+
+ /*********************************************************************/
+ /* Direct access needed for join or sorting. */
+ /*********************************************************************/
+ if (NeedIndexing(g)) {
+ // Direct access of DHR tables is not implemented yet
+ sprintf(g->Message, MSG(NO_DIR_INDX_RD), "DHR");
+ return true;
+ } // endif NeedIndexing
+
+ Use = USE_OPEN;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for DHR access method. */
+/***********************************************************************/
+int TDBDHR::ReadDB(PGLOBAL g)
+ {
+ int rc = RC_OK;
+ DWORD erc;
+
+ if (Hsearch == INVALID_HANDLE_VALUE) {
+ char *filename[_MAX_PATH];
+ PDBUSER dup = PlgGetUser(g);
+
+ PlugSetPath(filename, To_File, dup->Path);
+ _splitpath(filename, Drive, Direc, NULL, NULL);
+
+ /*******************************************************************/
+ /* Start searching files in the target directory. */
+ /*******************************************************************/
+ Hsearch = FindFirstFile(filename, &FileData);
+
+ if (Hsearch != INVALID_HANDLE_VALUE)
+ iFile = 1;
+ else switch (erc = GetLastError()) {
+ case ERROR_NO_MORE_FILES:
+ case ERROR_FILE_NOT_FOUND:
+// case ERROR_PATH_NOT_FOUND: ???????
+ rc = RC_EF;
+ break;
+ default:
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, erc, 0,
+ (LPTSTR)&filename, sizeof(filename), NULL);
+ sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename);
+ rc = RC_FX;
+ } // endswitch erc
+
+ } else {
+ if (!FindNextFile(Hsearch, &FileData)) {
+ DWORD erc = GetLastError();
+
+ if (erc != ERROR_NO_MORE_FILES) {
+ sprintf(g->Message, MSG(NEXT_FILE_ERROR), erc);
+ FindClose(Hsearch);
+ rc = RC_FX;
+ } else
+ rc = RC_EF;
+
+ } else
+ iFile++;
+
+ } // endif Hsearch
+
+ if (rc == RC_OK)
+ _splitpath(FileData.cFileName, NULL, NULL, Fname, Ftype);
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* Data Base close routine for MUL access method. */
+/***********************************************************************/
+void TDBDHR::CloseDB(PGLOBAL g)
+ {
+ // Close the search handle.
+ if (!FindClose(Hsearch)) {
+ strcpy(g->Message, MSG(SRCH_CLOSE_ERR));
+ throw GetAmType();
+ } // endif FindClose
+
+ iFile = 0;
+ Hsearch = INVALID_HANDLE_VALUE;
+ } // end of CloseDB
+
+// ------------------------ DHRCOL functions ----------------------------
+
+/***********************************************************************/
+/* DHRCOL public constructor. */
+/***********************************************************************/
+DHRCOL::DHRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional DHR access method information for column.
+ N = cdp->GetOffset();
+ } // end of DOSCOL constructor
+
+/***********************************************************************/
+/* DHRCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+DHRCOL::DHRCOL(DHRCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ N = col1->N;
+ } // end of DHRCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the information */
+/* corresponding to this column and convert it to buffer type. */
+/***********************************************************************/
+void DHRCOL::ReadColumn(PGLOBAL g)
+ {
+ int rc;
+ PTDBDHR tdbp = (PTDBDHR)To_Tdb;
+
+ if (trace(1))
+ htrc("DHR ReadColumn: col %s R%d use=%.4X status=%.4X type=%d N=%d\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type, N);
+
+ /*********************************************************************/
+ /* Retrieve the information corresponding to the column number. */
+ /*********************************************************************/
+ switch (N) {
+ case 0: // Drive
+ Value->SetValue(Drive, _MAX_DRIVE);
+ break;
+ case 1: // Path
+ Value->SetValue(Direc, _MAX_DHR);
+ break;
+ case 2: // Name
+ Value->SetValue(Fname, _MAX_FNAME);
+ break;
+ case 3: // Extention
+ Value->SetValue(Ftype, _MAX_EXT);
+ break;
+ case 4: // Extention
+ Value->SetValue(tdbp->FileData.cAlternateFileName, 14);
+ break;
+ case 5:
+ Value->SetValue(tdbp->FileData.dwFileAttributes);
+ break;
+ case 6:
+ Value->SetValue(..................
+ } // end of ReadColumn
+#endif // 0
+
diff --git a/storage/connect/tabmul.h b/storage/connect/tabmul.h
new file mode 100644
index 00000000..a9d3f88c
--- /dev/null
+++ b/storage/connect/tabmul.h
@@ -0,0 +1,248 @@
+/*************** Tabmul H Declares Source Code File (.H) ***************/
+/* Name: TABMUL.H Version 1.5 */
+/* */
+/* (C) Copyright to PlugDB Software Development 2003-2017 */
+/* Author: Olivier BERTRAND */
+/* */
+/* This file contains the TDBMUL and TDBDIR classes declares. */
+/***********************************************************************/
+#if defined(_WIN32)
+#include <io.h>
+#else // !_WIN32
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#endif // !_WIN32
+//#include "osutil.h"
+#include "block.h"
+
+typedef class TDBMUL *PTDBMUL;
+typedef class TDBSDR *PTDBSDR;
+
+/***********************************************************************/
+/* This is the MUL Access Method class declaration for files that are */
+/* physically split in multiple files having the same format. */
+/***********************************************************************/
+class DllExport TDBMUL : public TDBASE {
+//friend class MULCOL;
+ public:
+ // Constructor
+ TDBMUL(PTDB tdbp);
+ TDBMUL(PTDBMUL tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return Tdbp->GetAmType();}
+ virtual PTDB Duplicate(PGLOBAL g);
+
+ // Methods
+ virtual void ResetDB(void);
+ virtual PTDB Clone(PTABS t);
+ virtual bool IsSame(PTDB tp) {return tp == (PTDB)Tdbp;}
+ virtual PCSZ GetFile(PGLOBAL g) {return Tdbp->GetFile(g);}
+ virtual int GetRecpos(void) {return 0;}
+ virtual PCOL ColDB(PGLOBAL g, PSZ name, int num);
+ bool InitFileNames(PGLOBAL g);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {strcpy(g->Message, MSG(MUL_MAKECOL_ERR)); return NULL;}
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual int GetProgMax(PGLOBAL g);
+ virtual int GetProgCur(void);
+ virtual int RowNumber(PGLOBAL g, bool b = false);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+
+ protected:
+
+ // Members
+ PTDB Tdbp; // Points to a (file) table class
+ char* *Filenames; // Points to file names
+ int Rows; // Total rows of already read files
+ int Mul; // Type of multiple file list
+ int NumFiles; // Number of physical files
+ int iFile; // Index of currently processed file
+ }; // end of class TDBMUL
+
+#if 0
+/***********************************************************************/
+/* This is the MSD Access Method class declaration for files that are */
+/* physically split in multiple files having the same format. */
+/* This sub-class also include files of the sub-directories. */
+/***********************************************************************/
+class DllExport TDBMSD : public TDBMUL {
+ //friend class MULCOL;
+public:
+ // Constructor
+ TDBMSD(PTDB tdbp) : TDBMUL(tdbp) {}
+ TDBMSD(PTDBMSD tdbp) : TDBMUL(tdbp) {}
+
+ // Implementation
+ virtual PTDB Duplicate(PGLOBAL g);
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ bool InitFileNames(PGLOBAL g);
+
+ // Database routines
+
+protected:
+
+ // Members
+}; // end of class TDBMSD
+#endif
+
+/***********************************************************************/
+/* Directory listing table. */
+/***********************************************************************/
+class DllExport DIRDEF : public TABDEF { /* Directory listing table */
+ friend class CATALOG;
+ friend class TDBDIR;
+ public:
+ // Constructor
+ DIRDEF(void) {Fn = NULL; Incl = false; Huge = false;}
+
+ // Implementation
+ virtual const char *GetType(void) {return "DIR";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ PSZ Fn; /* Path/Name of file search */
+ bool Incl; /* true to include sub-directories */
+ bool Huge; /* true if files can be larger than 2GB */
+ bool Nodir; /* true to exclude directories */
+ }; // end of DIRDEF
+
+/***********************************************************************/
+/* This is the DIR Access Method class declaration for tables that */
+/* represent a directory listing. The pathname is given at the create */
+/* time and can contain wildcard characters in the file name, and the */
+/* (virtual) table is populated when it is in use. */
+/***********************************************************************/
+class TDBDIR : public TDBASE {
+ friend class DIRCOL;
+ friend class TDBMUL;
+public:
+ // Constructor
+ TDBDIR(PDIRDEF tdp);
+ TDBDIR(PSZ fpat);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_DIR;}
+
+ // Methods
+ virtual int GetRecpos(void) {return iFile;}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual int GetProgMax(PGLOBAL g) {return GetMaxSize(g);}
+ virtual int GetProgCur(void) {return iFile;}
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+
+ protected:
+ void Init(void);
+ char *Path(PGLOBAL g);
+
+ // Members
+ PSZ To_File; // Points to file search pathname
+ int iFile; // Index of currently retrieved file
+#if defined(_WIN32)
+ PVAL Dvalp; // Used to retrieve file date values
+ WIN32_FIND_DATA FileData; // Find data structure
+ HANDLE hSearch; // Search handle
+ char Drive[_MAX_DRIVE]; // Drive name
+#else // !_WIN32
+ struct stat Fileinfo; // File info structure
+ struct dirent *Entry; // Point to directory entry structure
+ DIR *Dir; // To searched directory structure
+ bool Done; // true when _splipath is done
+ char Pattern[_MAX_FNAME+_MAX_EXT];
+#endif // !_WIN32
+ char Fpath[_MAX_PATH]; // Absolute file search pattern
+ char Direc[_MAX_DIR]; // Search path
+ char Fname[_MAX_FNAME]; // File name
+ char Ftype[_MAX_EXT]; // File extention
+ bool Nodir; // Exclude directories from file list
+ }; // end of class TDBDIR
+
+/***********************************************************************/
+/* This is the DIR Access Method class declaration for tables that */
+/* represent a directory listing. The pathname is given at the create */
+/* time and can contain wildcard characters in the file name, and the */
+/* (virtual) table is populated when it is in use. In addition, this */
+/* class also includes files of included sub-directories. */
+/***********************************************************************/
+class TDBSDR : public TDBDIR {
+ friend class DIRCOL;
+ friend class TDBMUL;
+ public:
+ // Constructors
+ TDBSDR(PDIRDEF tdp) : TDBDIR(tdp) {Sub = NULL;}
+ TDBSDR(PSZ fpat) : TDBDIR(fpat) {Sub = NULL;}
+
+ // Database routines
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual int GetProgMax(PGLOBAL g) {return GetMaxSize(g);}
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+//virtual void CloseDB(PGLOBAL g);
+
+ protected:
+ int FindInDir(PGLOBAL g);
+
+ typedef struct _Sub_Dir {
+ struct _Sub_Dir *Next;
+ struct _Sub_Dir *Prev;
+#if defined(_WIN32)
+ HANDLE H; // Search handle
+#else // !_WIN32
+ DIR *D;
+#endif // !_WIN32
+ size_t Len; // Initial directory name length
+ } SUBDIR, *PSUBDIR;
+
+ // Members
+ PSUBDIR Sub; // To current Subdir block
+ }; // end of class TDBSDR
+
+/***********************************************************************/
+/* Class DIRCOL: DIR access method column descriptor. */
+/* This A.M. is used for tables populated by DIR file name list. */
+/***********************************************************************/
+class DIRCOL : public COLBLK {
+ public:
+ // Constructors
+ DIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "DIR");
+ DIRCOL(DIRCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_DIR;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ DIRCOL(void) {}
+#if defined(_WIN32)
+ void SetTimeValue(PGLOBAL g, FILETIME& ftime);
+#endif // _WIN32
+
+ // Members
+ PTDBDIR Tdbp; // To DIR table
+ int N; // Column number
+ }; // end of class DIRCOL
diff --git a/storage/connect/tabmysql.cpp b/storage/connect/tabmysql.cpp
new file mode 100644
index 00000000..b14b0b14
--- /dev/null
+++ b/storage/connect/tabmysql.cpp
@@ -0,0 +1,1761 @@
+/************* TabMySQL C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: TABMYSQL */
+/* ------------- */
+/* Version 2.0 */
+/* */
+/* AUTHOR: */
+/* ------- */
+/* Olivier BERTRAND 2007-2017 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* Implements a table type that are MySQL tables. */
+/* It can optionally use the embedded MySQL library. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABMYSQL.CPP - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABMYSQL.H - TABMYSQL classes declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/************************************************************************/
+#define MYSQL_SERVER 1
+#include "my_global.h"
+#include "sql_class.h"
+#include "sql_servers.h"
+#if defined(_WIN32)
+//#include <windows.h>
+#else // !_WIN32
+//#include <fnmatch.h>
+//#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+//#include <io.h>
+//#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "tabcol.h"
+#include "colblk.h"
+//#include "reldef.h"
+#include "tabmysql.h"
+#include "valblk.h"
+#include "tabutil.h"
+#include "ha_connect.h"
+
+#if defined(_CONSOLE)
+void PrintResult(PGLOBAL, PSEM, PQRYRES);
+#endif // _CONSOLE
+
+// Used to check whether a MYSQL table is created on itself
+bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, PCSZ host, PCSZ db,
+ PCSZ tab, PCSZ src, int port);
+
+/***********************************************************************/
+/* External function. */
+/***********************************************************************/
+bool ExactInfo(void);
+
+/* -------------- Implementation of the MYSQLDEF class --------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+MYSQLDEF::MYSQLDEF(void)
+ {
+ Pseudo = 2; // SERVID is Ok but not ROWID
+ Hostname = NULL;
+//Tabschema = NULL;
+//Tabname = NULL;
+//Srcdef = NULL;
+//Username = NULL;
+//Password = NULL;
+ Portnumber = 0;
+ Isview = false;
+ Bind = false;
+ Delayed = false;
+//Xsrc = false;
+ Huge = false;
+ } // end of MYSQLDEF constructor
+
+/***********************************************************************/
+/* Get connection info from the declared server. */
+/***********************************************************************/
+bool MYSQLDEF::GetServerInfo(PGLOBAL g, const char *server_name)
+{
+ THD *thd= current_thd;
+ MEM_ROOT *mem= thd->mem_root;
+ FOREIGN_SERVER *server, server_buffer;
+ DBUG_ENTER("GetServerInfo");
+ DBUG_PRINT("info", ("server_name %s", server_name));
+
+ if (!server_name || !strlen(server_name)) {
+ DBUG_PRINT("info", ("server_name not defined!"));
+ strcpy(g->Message, "server_name not defined!");
+ DBUG_RETURN(true);
+ } // endif server_name
+
+ // get_server_by_name() clones the server if exists and allocates
+ // copies of strings in the supplied mem_root
+ if (!(server= get_server_by_name(mem, server_name, &server_buffer))) {
+ DBUG_PRINT("info", ("get_server_by_name returned > 0 error condition!"));
+ /* need to come up with error handling */
+ strcpy(g->Message, "get_server_by_name returned > 0 error condition!");
+ DBUG_RETURN(true);
+ } // endif server
+
+ DBUG_PRINT("info", ("get_server_by_name returned server at %p",
+ server));
+
+ // TODO: We need to examine which of these can really be NULL
+ Hostname = PlugDup(g, server->host);
+ Tabschema = PlugDup(g, server->db);
+ Username = PlugDup(g, server->username);
+ Password = PlugDup(g, server->password);
+ Portnumber = (server->port) ? server->port : GetDefaultPort();
+
+ DBUG_RETURN(false);
+} // end of GetServerInfo
+
+/***********************************************************************/
+/* Parse connection string */
+/* */
+/* SYNOPSIS */
+/* ParseURL() */
+/* url The connection string to parse */
+/* */
+/* DESCRIPTION */
+/* Populates the table with information about the connection */
+/* to the foreign database that will serve as the data source. */
+/* This string must be specified (currently) in the "CONNECTION" */
+/* field, listed in the CREATE TABLE statement. */
+/* */
+/* This string MUST be in the format of any of these: */
+/* */
+/* CONNECTION="scheme://user:pwd@host:port/database/table" */
+/* CONNECTION="scheme://user@host/database/table" */
+/* CONNECTION="scheme://user@host:port/database/table" */
+/* CONNECTION="scheme://user:pwd@host/database/table" */
+/* */
+/* _OR_ */
+/* */
+/* CONNECTION="connection name" (NIY) */
+/* */
+/* An Example: */
+/* */
+/* CREATE TABLE t1 (id int(32)) */
+/* ENGINE="CONNECT" TABLE_TYPE="MYSQL" */
+/* CONNECTION="mysql://joe:pwd@192.168.1.111:9308/dbname/tabname"; */
+/* */
+/* CREATE TABLE t2 ( */
+/* id int(4) NOT NULL auto_increment, */
+/* name varchar(32) NOT NULL, */
+/* PRIMARY KEY(id) */
+/* ) ENGINE="CONNECT" TABLE_TYPE="MYSQL" */
+/* CONNECTION="my_conn"; (NIY) */
+/* */
+/* 'password' and 'port' are both optional. */
+/* */
+/* RETURN VALUE */
+/* false success */
+/* true error */
+/* */
+/***********************************************************************/
+bool MYSQLDEF::ParseURL(PGLOBAL g, char *url, bool b)
+ {
+ char *tabn, *pwd, *schema;
+
+ if ((!strstr(url, "://") && (!strchr(url, '@')))) {
+ // No :// or @ in connection string. Must be a straight
+ // connection name of either "server" or "server/table"
+ // ok, so we do a little parsing, but not completely!
+ if ((tabn= strchr(url, '/'))) {
+ // If there is a single '/' in the connection string,
+ // this means the user is specifying a table name
+ *tabn++= '\0';
+
+ // there better not be any more '/'s !
+ if (strchr(tabn, '/'))
+ return true;
+
+ Tabname = tabn;
+ } else
+ // Otherwise, straight server name,
+ Tabname = (b) ? GetStringCatInfo(g, "Tabname", Name) : NULL;
+
+ if (trace(1))
+ htrc("server: %s TableName: %s", url, Tabname);
+
+ Server = url;
+ return GetServerInfo(g, url);
+ } else {
+ // URL, parse it
+ char *sport, *scheme = url;
+
+ if (!(Username = strstr(url, "://"))) {
+ strcpy(g->Message, "Connection is not an URL");
+ return true;
+ } // endif User
+
+ scheme[Username - scheme] = 0;
+
+ if (stricmp(scheme, "mysql")) {
+ strcpy(g->Message, "scheme must be mysql");
+ return true;
+ } // endif scheme
+
+ Username += 3;
+
+ if (!(Hostname = (char*)strchr(Username, '@'))) {
+ strcpy(g->Message, "No host specified in URL");
+ return true;
+ } else {
+ *Hostname++ = 0; // End Username
+ Server = Hostname;
+ } // endif Hostname
+
+ if ((pwd = (char*)strchr(Username, ':'))) {
+ *pwd++ = 0; // End username
+
+ // Make sure there isn't an extra /
+ if (strchr(pwd, '/')) {
+ strcpy(g->Message, "Syntax error in URL");
+ return true;
+ } // endif
+
+ // Found that if the string is:
+ // user:@hostname:port/db/table
+ // Then password is a null string, so set to NULL
+ if (pwd[0] == 0)
+ Password = NULL;
+ else
+ Password = pwd;
+
+ } // endif password
+
+ // Make sure there isn't an extra / or @ */
+ if ((strchr(Username, '/')) || (strchr(Hostname, '@'))) {
+ strcpy(g->Message, "Syntax error in URL");
+ return true;
+ } // endif
+
+ if ((schema = strchr(Hostname, '/'))) {
+ *schema++ = 0;
+
+ if ((tabn = strchr(schema, '/'))) {
+ *tabn++ = 0;
+
+ // Make sure there's not an extra /
+ if ((strchr(tabn, '/'))) {
+ strcpy(g->Message, "Syntax error in URL");
+ return true;
+ } // endif /
+
+ Tabname = tabn;
+ } // endif TableName
+
+ Tabschema = schema;
+ } // endif database
+
+ if ((sport = strchr(Hostname, ':')))
+ *sport++ = 0;
+
+ // For unspecified values, get the values of old style options
+ // but only if called from MYSQLDEF, else set them to NULL
+ Portnumber = (sport && sport[0]) ? atoi(sport)
+ : (b) ? GetIntCatInfo("Port", GetDefaultPort()) : 0;
+
+ if (Username[0] == 0)
+ Username = (b) ? GetStringCatInfo(g, "User", "*") : NULL;
+
+ if (Hostname[0] == 0)
+ Hostname = (b) ? GetStringCatInfo(g, "Host", "localhost") : NULL;
+
+ if (!Tabschema || !*Tabschema)
+ Tabschema = (b) ? GetStringCatInfo(g, "Database", "*") : NULL;
+
+ if (!Tabname || !*Tabname)
+ Tabname = (b) ? GetStringCatInfo(g, "Tabname", Name) : NULL;
+
+ if (!Password)
+ Password = (b) ? GetStringCatInfo(g, "Password", NULL) : NULL;
+ } // endif URL
+
+#if 0
+ if (!share->port)
+ if (!share->hostname || strcmp(share->hostname, my_localhost) == 0)
+ share->socket= (char *) MYSQL_UNIX_ADDR;
+ else
+ share->port= MYSQL_PORT;
+#endif // 0
+
+ return false;
+ } // end of ParseURL
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XCV file. */
+/***********************************************************************/
+bool MYSQLDEF::DefineAM(PGLOBAL g, LPCSTR am, int)
+ {
+ char *url;
+
+ Desc = "MySQL Table";
+
+ if (stricmp(am, "MYPRX")) {
+ // Normal case of specific MYSQL table
+ url = GetStringCatInfo(g, "Connect", NULL);
+
+ if (!url || !*url) {
+ // Not using the connection URL
+ Hostname = GetStringCatInfo(g, "Host", "localhost");
+ Tabschema = GetStringCatInfo(g, "Database", "*");
+ Tabname = GetStringCatInfo(g, "Name", Name); // Deprecated
+ Tabname = GetStringCatInfo(g, "Tabname", Tabname);
+ Username = GetStringCatInfo(g, "User", "*");
+ Password = GetStringCatInfo(g, "Password", NULL);
+ Portnumber = GetIntCatInfo("Port", GetDefaultPort());
+ Server = Hostname;
+ } else if (ParseURL(g, url))
+ return true;
+
+ Bind = !!GetIntCatInfo("Bind", 0);
+ Delayed = !!GetIntCatInfo("Delayed", 0);
+ } else {
+ // MYSQL access from a PROXY table
+ TABLE_SHARE* s;
+
+ Tabschema = GetStringCatInfo(g, "Database", Tabschema ? Tabschema : PlugDup(g, "*"));
+ Isview = GetBoolCatInfo("View", false);
+
+ // We must get other connection parms from the calling table
+ s = Remove_tshp(Cat);
+ url = GetStringCatInfo(g, "Connect", NULL);
+
+ if (!url || !*url) {
+ Hostname = GetStringCatInfo(g, "Host", "localhost");
+ Username = GetStringCatInfo(g, "User", "*");
+ Password = GetStringCatInfo(g, "Password", NULL);
+ Portnumber = GetIntCatInfo("Port", GetDefaultPort());
+ Server = Hostname;
+ } else {
+ PCSZ locdb = Tabschema;
+
+ if (ParseURL(g, url))
+ return true;
+
+ Tabschema = locdb;
+ } // endif url
+
+ Tabname = Name;
+
+ // Needed for column description
+ Restore_tshp(Cat, s);
+ } // endif am
+
+ if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) {
+ Read_Only = true;
+ Isview = true;
+ } else if (CheckSelf(g, Hc->GetTable()->s, Hostname, Tabschema,
+ Tabname, Srcdef, Portnumber))
+ return true;
+
+ // Used for Update and Delete
+ Qrystr = GetStringCatInfo(g, "Query_String", "?");
+ Quoted = GetIntCatInfo("Quoted", 0);
+
+ // Specific for command executing tables
+ Xsrc = GetBoolCatInfo("Execsrc", false);
+ Maxerr = GetIntCatInfo("Maxerr", 0);
+ Huge = GetBoolCatInfo("Huge", false);
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB MYSQLDEF::GetTable(PGLOBAL g, MODE)
+ {
+ if (Xsrc)
+ return new(g) TDBMYEXC(this);
+ else if (Catfunc == FNC_COL)
+ return new(g) TDBMCL(this);
+ else
+ return new(g) TDBMYSQL(this);
+
+ } // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBMYSQL class. */
+/***********************************************************************/
+TDBMYSQL::TDBMYSQL(PMYDEF tdp) : TDBEXT(tdp)
+ {
+ if (tdp) {
+ Host = tdp->Hostname;
+// Schema = tdp->Tabschema;
+// TableName = tdp->Tabname;
+// Srcdef = tdp->Srcdef;
+// User = tdp->Username;
+// Pwd = tdp->Password;
+ Server = tdp->Server;
+// Qrystr = tdp->Qrystr;
+ Quoted = MY_MAX(0, tdp->Quoted);
+ Port = tdp->Portnumber;
+ Isview = tdp->Isview;
+ Prep = tdp->Bind;
+ Delayed = tdp->Delayed;
+ Myc.m_Use = tdp->Huge;
+ } else {
+ Host = NULL;
+// Schema = NULL;
+// TableName = NULL;
+// Srcdef = NULL;
+// User = NULL;
+// Pwd = NULL;
+ Server = NULL;
+// Qrystr = NULL;
+// Quoted = 0;
+ Port = 0;
+ Isview = false;
+ Prep = false;
+ Delayed = false;
+ } // endif tdp
+
+ Bind = NULL;
+//Query = NULL;
+ Fetched = false;
+ m_Rc = RC_FX;
+//AftRows = 0;
+ N = -1;
+//Nparm = 0;
+ } // end of TDBMYSQL constructor
+
+TDBMYSQL::TDBMYSQL(PTDBMY tdbp) : TDBEXT(tdbp)
+ {
+ Host = tdbp->Host;
+//Schema = tdbp->Schema;
+//TableName = tdbp->TableName;
+//Srcdef = tdbp->Srcdef;
+//User = tdbp->User;
+//Pwd = tdbp->Pwd;
+//Qrystr = tdbp->Qrystr;
+//Quoted = tdbp->Quoted;
+ Server = tdbp->Server;
+ Port = tdbp->Port;
+ Isview = tdbp->Isview;
+ Prep = tdbp->Prep;
+ Delayed = tdbp->Delayed;
+ Bind = NULL;
+//Query = tdbp->Query;
+ Fetched = tdbp->Fetched;
+ m_Rc = tdbp->m_Rc;
+//AftRows = tdbp->AftRows;
+ N = tdbp->N;
+//Nparm = tdbp->Nparm;
+ } // end of TDBMYSQL copy constructor
+
+// Is this really useful ??? --> Yes for UPDATE
+PTDB TDBMYSQL::Clone(PTABS t)
+ {
+ PTDB tp;
+ PCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBMYSQL(this);
+
+ for (cp1 = Columns; cp1; cp1 = cp1->GetNext()) {
+ cp2 = new(g) MYSQLCOL((PMYCOL)cp1, tp);
+
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Allocate MYSQL column description block. */
+/***********************************************************************/
+PCOL TDBMYSQL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) MYSQLCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* MakeSelect: make the Select statement use with MySQL connection. */
+/* Note: when implementing EOM filtering, column only used in local */
+/* filter should be removed from column list. */
+/***********************************************************************/
+bool TDBMYSQL::MakeSelect(PGLOBAL g, bool mx)
+{
+//char *tk = "`";
+ char tk = '`';
+ int len = 0, rank = 0;
+ bool b = false;
+ PCOL colp;
+//PDBUSER dup = PlgGetUser(g);
+
+ if (Query)
+ return false; // already done
+
+ if (Srcdef)
+ return MakeSrcdef(g);
+
+ // Allocate the string used to contain Query
+ Query = new(g) STRING(g, 1023, "SELECT ");
+
+ if (Columns) {
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!colp->IsSpecial()) {
+ if (b)
+ Query->Append(", ");
+ else
+ b = true;
+
+ Query->Append(tk);
+ Query->Append(colp->GetName());
+ Query->Append(tk);
+ ((PMYCOL)colp)->Rank = rank++;
+ } // endif colp
+
+ } else {
+ // ncol == 0 can occur for views or queries such as
+ // Query count(*) from... for which we will count the rows from
+ // Query '*' from...
+ // (the use of a char constant minimize the result storage)
+ if (Isview)
+ Query->Append('*');
+ else
+ Query->Append("'*'");
+
+ } // endif ncol
+
+ Query->Append(" FROM ");
+ Query->Append(tk);
+ Query->Append(TableName);
+ Query->Append(tk);
+ len = Query->GetLength();
+
+ if (To_CondFil) {
+ if (!mx) {
+ Query->Append(" WHERE ");
+ Query->Append(To_CondFil->Body);
+ len = Query->GetLength() + 1;
+ } else
+ len += (strlen(To_CondFil->Body) + 256);
+
+ } else
+ len += (mx ? 256 : 1);
+
+ if (Query->IsTruncated() || Query->Resize(len)) {
+ strcpy(g->Message, "MakeSelect: Out of memory");
+ return true;
+ } // endif Query
+
+ if (trace(33))
+ htrc("Query=%s\n", Query->GetStr());
+
+ return false;
+} // end of MakeSelect
+
+/***********************************************************************/
+/* MakeInsert: make the Insert statement used with MySQL connection. */
+/***********************************************************************/
+bool TDBMYSQL::MakeInsert(PGLOBAL g)
+ {
+ const char *tk = "`";
+ uint len = 0;
+ bool oom, b = false;
+ PCOL colp;
+
+ if (Query)
+ return false; // already done
+
+ if (Prep) {
+#if !defined(MYSQL_PREPARED_STATEMENTS)
+ strcpy(g->Message, "Prepared statements not used (not supported)");
+ PushWarning(g, this);
+ Prep = false;
+#endif // !MYSQL_PREPARED_STATEMENTS
+ } // endif Prep
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->IsSpecial()) {
+ strcpy(g->Message, MSG(NO_SPEC_COL));
+ return true;
+ } else {
+ len += (strlen(colp->GetName()) + 4);
+
+ // Parameter marker
+ if (!Prep) {
+ if (colp->GetResultType() == TYPE_DATE)
+ len += 20;
+ else
+ len += colp->GetLength();
+
+ } else
+ len += 2;
+
+ ((PMYCOL)colp)->Rank = Nparm++;
+ } // endif colp
+
+ // Below 40 is enough to contain the fixed part of the query
+ len += (strlen(TableName) + 40);
+ Query = new(g) STRING(g, len);
+
+ if (Delayed)
+ Query->Set("INSERT DELAYED INTO ");
+ else
+ Query->Set("INSERT INTO ");
+
+ Query->Append(tk);
+ Query->Append(TableName);
+ Query->Append("` (");
+
+ for (colp = Columns; colp; colp = colp->GetNext()) {
+ if (b)
+ Query->Append(", ");
+ else
+ b = true;
+
+ Query->Append(tk);
+ Query->Append(colp->GetName());
+ Query->Append(tk);
+ } // endfor colp
+
+ Query->Append(") VALUES (");
+
+#if defined(MYSQL_PREPARED_STATEMENTS)
+ if (Prep) {
+ for (int i = 0; i < Nparm; i++)
+ Query->Append("?,");
+
+ Query->RepLast(')');
+ Query->Trim();
+ } // endif Prep
+#endif // MYSQL_PREPARED_STATEMENTS
+
+ if ((oom = Query->IsTruncated()))
+ strcpy(g->Message, "MakeInsert: Out of memory");
+
+ return oom;
+ } // end of MakeInsert
+
+/***********************************************************************/
+/* MakeCommand: make the Update or Delete statement to send to the */
+/* MySQL server. Limited to remote values and filtering. */
+/***********************************************************************/
+bool TDBMYSQL::MakeCommand(PGLOBAL g)
+ {
+ Query = new(g) STRING(g, strlen(Qrystr) + 64);
+
+ if (Quoted > 0 || stricmp(Name, TableName)) {
+ char *p, *qrystr, name[68];
+ bool qtd = Quoted > 0;
+
+
+ // Make a lower case copy of the originale query
+ qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 5);
+ strlwr(strcpy(qrystr, Qrystr));
+
+ // Check whether the table name is equal to a keyword
+ // If so, it must be quoted in the original query
+ strlwr(strcat(strcat(strcpy(name, "`"), Name), "`"));
+
+ if (!strstr("`update`delete`low_priority`ignore`quick`from`", name))
+ strlwr(strcpy(name, Name)); // Not a keyword
+
+ if ((p = strstr(qrystr, name))) {
+ Query->Set(Qrystr, (uint)(p - qrystr));
+
+ if (qtd && *(p-1) == ' ') {
+ Query->Append('`');
+ Query->Append(TableName);
+ Query->Append('`');
+ } else
+ Query->Append(TableName);
+
+ Query->Append(Qrystr + (p - qrystr) + strlen(name));
+
+ if (Query->IsTruncated()) {
+ strcpy(g->Message, "MakeCommand: Out of memory");
+ return true;
+ } else
+ strlwr(strcpy(qrystr, Query->GetStr()));
+
+ } else {
+ sprintf(g->Message, "Cannot use this %s command",
+ (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
+ return true;
+ } // endif p
+
+ } else
+ (void)Query->Set(Qrystr);
+
+ return false;
+ } // end of MakeCommand
+
+#if 0
+/***********************************************************************/
+/* MakeUpdate: make the Update statement use with MySQL connection. */
+/* Limited to remote values and filtering. */
+/***********************************************************************/
+int TDBMYSQL::MakeUpdate(PGLOBAL g)
+ {
+ char *qc, cmd[8], tab[96], end[1024];
+
+ Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ memset(end, 0, sizeof(end));
+
+ if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
+ sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
+ qc = "`";
+ else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2
+ && !stricmp(tab, Name))
+ qc = (Quoted) ? "`" : "";
+ else {
+ strcpy(g->Message, "Cannot use this UPDATE command");
+ return RC_FX;
+ } // endif sscanf
+
+ assert(!stricmp(cmd, "update"));
+ strcat(strcat(strcat(strcpy(Query, "UPDATE "), qc), TableName), qc);
+ strcat(Query, end);
+ return RC_OK;
+ } // end of MakeUpdate
+
+/***********************************************************************/
+/* MakeDelete: make the Delete statement used with MySQL connection. */
+/* Limited to remote filtering. */
+/***********************************************************************/
+int TDBMYSQL::MakeDelete(PGLOBAL g)
+ {
+ char *qc, cmd[8], from[8], tab[96], end[512];
+
+ Query = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ memset(end, 0, sizeof(end));
+
+ if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
+ sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
+ qc = "`";
+ else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
+ qc = (Quoted) ? "`" : "";
+ else {
+ strcpy(g->Message, "Cannot use this DELETE command");
+ return RC_FX;
+ } // endif sscanf
+
+ assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
+ strcat(strcat(strcat(strcpy(Query, "DELETE FROM "), qc), TableName), qc);
+
+ if (*end)
+ strcat(Query, end);
+
+ return RC_OK;
+ } // end of MakeDelete
+#endif // 0
+
+/***********************************************************************/
+/* MYSQL Cardinality: returns the number of rows in the table. */
+/***********************************************************************/
+int TDBMYSQL::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return (Mode == MODE_ANY && !Srcdef) ? 1 : 0;
+
+ if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) {
+ // Info command, we must return the exact table row number
+ char query[96];
+ MYSQLC myc;
+
+ if (myc.Open(g, Host, Schema, User, Pwd, Port, csname))
+ return -1;
+
+ strcpy(query, "SELECT COUNT(*) FROM ");
+
+ if (Quoted > 0)
+ strcat(strcat(strcat(query, "`"), TableName), "`");
+ else
+ strcat(query, TableName);
+
+ Cardinal = myc.GetTableSize(g, query);
+ myc.Close();
+ } else
+ Cardinal = 10; // To make MySQL happy
+
+ return Cardinal;
+} // end of Cardinality
+
+#if 0
+/***********************************************************************/
+/* MYSQL GetMaxSize: returns the maximum number of rows in the table. */
+/***********************************************************************/
+int TDBMYSQL::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ if (Mode == MODE_DELETE)
+ // Return 0 in mode DELETE in case of delete all.
+ MaxSize = 0;
+ else if (!Cardinality(NULL))
+ MaxSize = 10; // To make MySQL happy
+ else if ((MaxSize = Cardinality(g)) < 0)
+ MaxSize = 12; // So we can see an error occurred
+
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+#endif // 0
+
+/***********************************************************************/
+/* This a fake routine as ROWID does not exist in MySQL. */
+/***********************************************************************/
+int TDBMYSQL::RowNumber(PGLOBAL, bool)
+ {
+ return N + 1;
+ } // end of RowNumber
+
+/***********************************************************************/
+/* Return 0 in mode UPDATE to tell that the update is done. */
+/***********************************************************************/
+int TDBMYSQL::GetProgMax(PGLOBAL g)
+ {
+ return (Mode == MODE_UPDATE) ? 0 : GetMaxSize(g);
+ } // end of GetProgMax
+
+/***********************************************************************/
+/* MySQL Bind Parameter function. */
+/***********************************************************************/
+int TDBMYSQL::BindColumns(PGLOBAL g __attribute__((unused)))
+ {
+#if defined(MYSQL_PREPARED_STATEMENTS)
+ if (Prep) {
+ Bind = (MYSQL_BIND*)PlugSubAlloc(g, NULL, Nparm * sizeof(MYSQL_BIND));
+
+ for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
+ colp->InitBind(g);
+
+ return Myc.BindParams(g, Bind);
+ } // endif prep
+#endif // MYSQL_PREPARED_STATEMENTS
+
+ return RC_OK;
+ } // end of BindColumns
+
+/***********************************************************************/
+/* MySQL Access Method opening routine. */
+/***********************************************************************/
+bool TDBMYSQL::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ if (Myc.Rewind(g, (Mode == MODE_READX) ? Query->GetStr() : NULL) != RC_OK)
+ return true;
+
+ N = -1;
+ return false;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open a MySQL connection for this table. */
+ /* Note: this may not be the proper way to do. Perhaps it is better */
+ /* to test whether a connection is already open for this server */
+ /* and if so to allocate just a new result set. But this only for */
+ /* servers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Myc.Connected()) {
+ if (Myc.Open(g, Host, Schema, User, Pwd, Port, csname))
+ return true;
+
+ } // endif Connected
+
+ /*********************************************************************/
+ /* Take care of DATE columns. */
+ /*********************************************************************/
+ for (PMYCOL colp = (PMYCOL)Columns; colp; colp = (PMYCOL)colp->Next)
+ if (colp->Buf_Type == TYPE_DATE)
+ // Format must match DATETIME MySQL type
+ ((DTVAL*)colp->GetValue())->SetFormat(g, "YYYY-MM-DD hh:mm:ss", 19);
+
+ /*********************************************************************/
+ /* Allocate whatever is used for getting results. */
+ /*********************************************************************/
+ if (Mode == MODE_READ || Mode == MODE_READX) {
+ MakeSelect(g, Mode == MODE_READX);
+ m_Rc = (Mode == MODE_READ)
+ ? Myc.ExecSQL(g, Query->GetStr()) : RC_OK;
+
+#if 0
+ if (!Myc.m_Res || !Myc.m_Fields) {
+ sprintf(g->Message, "%s result", (Myc.m_Res) ? "Void" : "No");
+ Myc.Close();
+ return true;
+ } // endif m_Res
+#endif // 0
+
+ if (!m_Rc && Srcdef)
+ if (SetColumnRanks(g))
+ return true;
+
+ } else if (Mode == MODE_INSERT) {
+ if (Srcdef) {
+ strcpy(g->Message, "No insert into anonym views");
+ Myc.Close();
+ return true;
+ } // endif Srcdef
+
+ if (!MakeInsert(g)) {
+#if defined(MYSQL_PREPARED_STATEMENTS)
+ int n = (Prep)
+ ? Myc.PrepareSQL(g, Query->GetCharValue()) : Nparm;
+
+ if (Nparm != n) {
+ if (n >= 0) // Other errors return negative values
+ strcpy(g->Message, MSG(BAD_PARM_COUNT));
+
+ } else
+#endif // MYSQL_PREPARED_STATEMENTS
+ m_Rc = BindColumns(g);
+
+ } // endif MakeInsert
+
+ if (m_Rc != RC_FX) {
+ char cmd[64];
+ int w;
+
+ sprintf(cmd, "ALTER TABLE `%s` DISABLE KEYS", TableName);
+
+ m_Rc = Myc.ExecSQL(g, cmd, &w); // may fail for some engines
+ } // endif m_Rc
+
+ } else
+// m_Rc = (Mode == MODE_DELETE) ? MakeDelete(g) : MakeUpdate(g);
+ m_Rc = (MakeCommand(g)) ? RC_FX : RC_OK;
+
+ if (m_Rc == RC_FX) {
+ Myc.Close();
+ return true;
+ } // endif rc
+
+ Use = USE_OPEN;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Set the rank of columns in the result set. */
+/***********************************************************************/
+bool TDBMYSQL::SetColumnRanks(PGLOBAL g)
+ {
+ for (PCOL colp = Columns; colp; colp = colp->GetNext())
+ if (((PMYCOL)colp)->FindRank(g))
+ return true;
+
+ return false;
+ } // end of SetColumnRanks
+
+/***********************************************************************/
+/* Called by Parent table to make the columns of a View. */
+/***********************************************************************/
+PCOL TDBMYSQL::MakeFieldColumn(PGLOBAL g, char *name)
+ {
+ int n;
+ MYSQL_FIELD *fld;
+ PCOL cp, colp = NULL;
+
+ for (n = 0; n < Myc.m_Fields; n++) {
+ fld = &Myc.m_Res->fields[n];
+
+ if (!stricmp(name, fld->name)) {
+ colp = new(g) MYSQLCOL(fld, this, n);
+
+ if (colp->InitValue(g))
+ return NULL;
+
+ if (!Columns)
+ Columns = colp;
+ else for (cp = Columns; cp; cp = cp->GetNext())
+ if (!cp->GetNext()) {
+ cp->SetNext(colp);
+ break;
+ } // endif Next
+
+ break;
+ } // endif name
+
+ } // endfor n
+
+ if (!colp)
+ sprintf(g->Message, "Column %s is not in view", name);
+
+ return colp;
+ } // end of MakeFieldColumn
+
+/***********************************************************************/
+/* Called by Pivot tables to find default column names in a View */
+/* as the name of last field not equal to the passed name. */
+/***********************************************************************/
+char *TDBMYSQL::FindFieldColumn(char *name)
+ {
+ int n;
+ MYSQL_FIELD *fld;
+ char *cp = NULL;
+
+ for (n = Myc.m_Fields - 1; n >= 0; n--) {
+ fld = &Myc.m_Res->fields[n];
+
+ if (!name || stricmp(name, fld->name)) {
+ cp = fld->name;
+ break;
+ } // endif name
+
+ } // endfor n
+
+ return cp;
+ } // end of FindFieldColumn
+
+/***********************************************************************/
+/* Send an UPDATE or DELETE command to the remote server. */
+/***********************************************************************/
+int TDBMYSQL::SendCommand(PGLOBAL g)
+ {
+ int w;
+
+ if (Myc.ExecSQLcmd(g, Query->GetStr(), &w) == RC_NF) {
+ AftRows = Myc.m_Afrw;
+ sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
+ PushWarning(g, this, 0); // 0 means a Note
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ if (w && Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK) {
+ // We got warnings from the remote server
+ while (Myc.Fetch(g, -1) == RC_OK) {
+ sprintf(g->Message, "%s: (%s) %s", TableName,
+ Myc.GetCharField(1), Myc.GetCharField(2));
+ PushWarning(g, this);
+ } // endwhile Fetch
+
+ Myc.FreeResult();
+ } // endif w
+
+ return RC_EF; // Nothing else to do
+ } else
+ return RC_FX; // Error
+
+ } // end of SendCommand
+
+/***********************************************************************/
+/* Data Base indexed read routine for MYSQL access method. */
+/***********************************************************************/
+bool TDBMYSQL::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
+{
+ int oldlen = Query->GetLength();
+ PHC hc = To_Def->GetHandler();
+
+ if (!(kr || hc->end_range) || op == OP_NEXT ||
+ Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ if (!kr && Mode == MODE_READX) {
+ // This is a false indexed read
+ m_Rc = Myc.ExecSQL(g, Query->GetStr());
+ Mode = MODE_READ;
+ return (m_Rc == RC_FX) ? true : false;
+ } // endif key
+
+ return false;
+ } else {
+ if (Myc.m_Res)
+ Myc.FreeResult();
+
+ if (hc->MakeKeyWhere(g, Query, op, '`', kr))
+ return true;
+
+ if (To_CondFil) {
+ if (To_CondFil->Idx != hc->active_index) {
+ To_CondFil->Idx = hc->active_index;
+ To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
+ *To_CondFil->Body= 0;
+
+ if ((To_CondFil = hc->CheckCond(g, To_CondFil, Cond)))
+ PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
+
+ } // endif active_index
+
+ if (To_CondFil)
+ if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
+ strcpy(g->Message, "Readkey: Out of memory");
+ return true;
+ } // endif Append
+
+ } // endif To_Condfil
+
+ Mode = MODE_READ;
+ } // endif's op
+
+ if (trace(33))
+ htrc("MYSQL ReadKey: Query=%s\n", Query->GetStr());
+
+ m_Rc = Myc.ExecSQL(g, Query->GetStr());
+ Query->Truncate(oldlen);
+ return (m_Rc == RC_FX) ? true : false;
+} // end of ReadKey
+
+/***********************************************************************/
+/* Data Base read routine for MYSQL access method. */
+/***********************************************************************/
+int TDBMYSQL::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+ if (trace(2))
+ htrc("MySQL ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode);
+
+ if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
+ return SendCommand(g);
+
+ /*********************************************************************/
+ /* Now start the reading process. */
+ /* Here is the place to fetch the line. */
+ /*********************************************************************/
+ N++;
+ Fetched = ((rc = Myc.Fetch(g, -1)) == RC_OK);
+
+ if (trace(2))
+ htrc(" Read: rc=%d\n", rc);
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for MYSQL access methods. */
+/***********************************************************************/
+int TDBMYSQL::WriteDB(PGLOBAL g)
+ {
+#if defined(MYSQL_PREPARED_STATEMENTS)
+ if (Prep)
+ return Myc.ExecStmt(g);
+#endif // MYSQL_PREPARED_STATEMENTS
+
+ // Statement was not prepared, we must construct and execute
+ // an insert query for each line to insert
+ int rc;
+ uint len = Query->GetLength();
+ char buf[64];
+
+ // Make the Insert command value list
+ for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
+ if (!colp->GetValue()->IsNull()) {
+ if (colp->GetResultType() == TYPE_STRING ||
+ colp->GetResultType() == TYPE_DATE)
+ Query->Append_quoted(colp->GetValue()->GetCharString(buf));
+ else
+ Query->Append(colp->GetValue()->GetCharString(buf));
+
+ } else
+ Query->Append("NULL");
+
+ Query->Append(',');
+ } // endfor colp
+
+ if (unlikely(Query->IsTruncated())) {
+ strcpy(g->Message, "WriteDB: Out of memory");
+ rc = RC_FX;
+ } else {
+ Query->RepLast(')');
+ Myc.m_Rows = -1; // To execute the query
+ rc = Myc.ExecSQL(g, Query->GetStr());
+ Query->Truncate(len); // Restore query
+ } // endif Query
+
+ return (rc == RC_NF) ? RC_OK : rc; // RC_NF is Ok
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete all routine for MYSQL access methods. */
+/***********************************************************************/
+int TDBMYSQL::DeleteDB(PGLOBAL g, int irc)
+ {
+ if (irc == RC_FX)
+ // Send the DELETE (all) command to the remote table
+ return (SendCommand(g) == RC_FX) ? RC_FX : RC_OK;
+ else
+ return RC_OK; // Ignore
+
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for MySQL access method. */
+/***********************************************************************/
+void TDBMYSQL::CloseDB(PGLOBAL g)
+ {
+ if (Myc.Connected()) {
+ if (Mode == MODE_INSERT) {
+ char cmd[64];
+ int w;
+ PDBUSER dup = PlgGetUser(g);
+
+ dup->Step = "Enabling indexes";
+ sprintf(cmd, "ALTER TABLE `%s` ENABLE KEYS", TableName);
+ Myc.m_Rows = -1; // To execute the query
+ m_Rc = Myc.ExecSQL(g, cmd, &w); // May fail for some engines
+ } // endif m_Rc
+
+ Myc.Close();
+ } // endif Myc
+
+ if (trace(1))
+ htrc("MySQL CloseDB: closing %s rc=%d\n", Name, m_Rc);
+
+ } // end of CloseDB
+
+// ------------------------ MYSQLCOL functions --------------------------
+
+/***********************************************************************/
+/* MYSQLCOL public constructor. */
+/***********************************************************************/
+MYSQLCOL::MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional MySQL access method information for column.
+ Precision = Long = cdp->GetLong();
+ Bind = NULL;
+ To_Val = NULL;
+ Slen = 0;
+ Rank = -1; // Not known yet
+
+ if (trace(1))
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ } // end of MYSQLCOL constructor
+
+/***********************************************************************/
+/* MYSQLCOL public constructor. */
+/***********************************************************************/
+MYSQLCOL::MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am)
+ : COLBLK(NULL, tdbp, i)
+ {
+//const char *chset = get_charset_name(fld->charsetnr);
+//char v = (!strcmp(chset, "binary")) ? 'B' : 0;
+ char v = 0;
+
+ Name = fld->name;
+ Opt = 0;
+ Precision = Long = fld->length;
+ Buf_Type = MYSQLtoPLG(fld->type, &v);
+ strcpy(Format.Type, GetFormatType(Buf_Type));
+ Format.Length = Long;
+ Format.Prec = fld->decimals;
+ ColUse = U_P;
+ Nullable = !IS_NOT_NULL(fld->flags);
+
+ // Set additional MySQL access method information for column.
+ Bind = NULL;
+ To_Val = NULL;
+ Slen = 0;
+ Rank = i;
+
+ if (trace(1))
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ } // end of MYSQLCOL constructor
+
+/***********************************************************************/
+/* MYSQLCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+MYSQLCOL::MYSQLCOL(MYSQLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Long = col1->Long;
+ Bind = NULL;
+ To_Val = NULL;
+ Slen = col1->Slen;
+ Rank = col1->Rank;
+ } // end of MYSQLCOL copy constructor
+
+/***********************************************************************/
+/* FindRank: Find the rank of this column in the result set. */
+/***********************************************************************/
+bool MYSQLCOL::FindRank(PGLOBAL g)
+{
+ int n;
+ MYSQLC myc = ((PTDBMY)To_Tdb)->Myc;
+
+ for (n = 0; n < myc.m_Fields; n++)
+ if (!stricmp(Name, myc.m_Res->fields[n].name)) {
+ Rank = n;
+ return false;
+ } // endif Name
+
+ sprintf(g->Message, "Column %s not in result set", Name);
+ return true;
+} // end of FindRank
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool MYSQLCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+ {
+ if (!(To_Val = value)) {
+ sprintf(g->Message, MSG(VALUE_ERROR), Name);
+ return true;
+ } else if (Buf_Type == value->GetType()) {
+ // Values are of the (good) column type
+ if (Buf_Type == TYPE_DATE) {
+ // If any of the date values is formatted
+ // output format must be set for the receiving table
+ if (GetDomain() || ((DTVAL *)value)->IsFormatted())
+ goto newval; // This will make a new value;
+
+ } else if (Buf_Type == TYPE_DOUBLE)
+ // Float values must be written with the correct (column) precision
+ // Note: maybe this should be forced by ShowValue instead of this ?
+ value->SetPrec(GetScale());
+
+ Value = value; // Directly access the external value
+ } else {
+ // Values are not of the (good) column type
+ if (check) {
+ sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
+ GetTypeName(Buf_Type), GetTypeName(value->GetType()));
+ return true;
+ } // endif check
+
+ newval:
+ if (InitValue(g)) // Allocate the matching value block
+ return true;
+
+ } // endif's Value, Buf_Type
+
+ // Because Colblk's have been made from a copy of the original TDB in
+ // case of Update, we must reset them to point to the original one.
+ if (To_Tdb->GetOrig())
+ To_Tdb = (PTDB)To_Tdb->GetOrig();
+
+ // Set the Column
+ Status = (ok) ? BUF_EMPTY : BUF_NO;
+ return false;
+ } // end of SetBuffer
+
+/***********************************************************************/
+/* InitBind: Initialize the bind structure according to type. */
+/***********************************************************************/
+void MYSQLCOL::InitBind(PGLOBAL g)
+ {
+ PTDBMY tdbp = (PTDBMY)To_Tdb;
+
+ assert(tdbp->Bind && Rank < tdbp->Nparm);
+
+ Bind = &tdbp->Bind[Rank];
+ memset(Bind, 0, sizeof(MYSQL_BIND));
+
+ if (Buf_Type == TYPE_DATE) {
+ Bind->buffer_type = PLGtoMYSQL(TYPE_STRING, false);
+ Bind->buffer = (char *)PlugSubAlloc(g,NULL, 20);
+ Bind->buffer_length = 20;
+ Bind->length = &Slen;
+ } else {
+ Bind->buffer_type = PLGtoMYSQL(Buf_Type, false);
+ Bind->buffer = (char *)Value->GetTo_Val();
+ Bind->buffer_length = Value->GetClen();
+ Bind->length = (IsTypeChar(Buf_Type)) ? &Slen : NULL;
+ } // endif Buf_Type
+
+ } // end of InitBind
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void MYSQLCOL::ReadColumn(PGLOBAL g)
+ {
+ char *p, *buf, tim[20];
+ int rc;
+ PTDBMY tdbp = (PTDBMY)To_Tdb;
+
+ /*********************************************************************/
+ /* If physical fetching of the line was deferred, do it now. */
+ /*********************************************************************/
+ if (!tdbp->Fetched)
+ {
+ if ((rc = tdbp->Myc.Fetch(g, tdbp->N)) != RC_OK) {
+ if (rc == RC_EF)
+ sprintf(g->Message, MSG(INV_DEF_READ), rc);
+
+ throw 11;
+ } else
+ tdbp->Fetched = true;
+ }
+ if ((buf = ((PTDBMY)To_Tdb)->Myc.GetCharField(Rank))) {
+ if (trace(2))
+ htrc("MySQL ReadColumn: name=%s buf=%s\n", Name, buf);
+
+ // TODO: have a true way to differenciate temporal values
+ if (Buf_Type == TYPE_DATE && strlen(buf) == 8)
+ // This is a TIME value
+ p = strcat(strcpy(tim, "1970-01-01 "), buf);
+ else
+ p = buf;
+
+ if (Value->SetValue_char(p, strlen(p))) {
+ sprintf(g->Message, "Out of range value for column %s at row %d",
+ Name, tdbp->RowNumber(g));
+ PushWarning(g, tdbp);
+ } // endif SetValue_char
+
+ } else {
+ if (Nullable)
+ Value->SetNull(true);
+
+ Value->Reset(); // Null value
+ } // endif buf
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: make sure the bind buffer is updated. */
+/***********************************************************************/
+void MYSQLCOL::WriteColumn(PGLOBAL)
+ {
+ /*********************************************************************/
+ /* Do convert the column value if necessary. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the inserted value
+
+#if defined(MYSQL_PREPARED_STATEMENTS)
+ if (((PTDBMY)To_Tdb)->Prep) {
+ if (Buf_Type == TYPE_DATE) {
+ Value->ShowValue((char *)Bind->buffer, (int)Bind->buffer_length);
+ Slen = strlen((char *)Bind->buffer);
+ } else if (IsTypeChar(Buf_Type))
+ Slen = strlen(Value->GetCharValue());
+
+ } // endif Prep
+#endif // MYSQL_PREPARED_STATEMENTS
+
+ } // end of WriteColumn
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBMYEXC class. */
+/***********************************************************************/
+TDBMYEXC::TDBMYEXC(PMYDEF tdp) : TDBMYSQL(tdp)
+{
+ Cmdlist = NULL;
+ Cmdcol = NULL;
+ Shw = false;
+ Havew = false;
+ Isw = false;
+ Warnings = 0;
+ Mxr = tdp->Maxerr;
+ Nerr = 0;
+} // end of TDBMYEXC constructor
+
+TDBMYEXC::TDBMYEXC(PTDBMYX tdbp) : TDBMYSQL(tdbp)
+{
+ Cmdlist = tdbp->Cmdlist;
+ Cmdcol = tdbp->Cmdcol;
+ Shw = tdbp->Shw;
+ Havew = tdbp->Havew;
+ Isw = tdbp->Isw;
+ Mxr = tdbp->Mxr;
+ Nerr = tdbp->Nerr;
+} // end of TDBMYEXC copy constructor
+
+// Is this really useful ???
+PTDB TDBMYEXC::Clone(PTABS t)
+ {
+ PTDB tp;
+ PCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBMYEXC(this);
+
+ for (cp1 = Columns; cp1; cp1 = cp1->GetNext()) {
+ cp2 = new(g) MYXCOL((PMYXCOL)cp1, tp);
+
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Allocate MYSQL column description block. */
+/***********************************************************************/
+PCOL TDBMYEXC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PMYXCOL colp = new(g) MYXCOL(cdp, this, cprec, n);
+
+ if (!colp->Flag)
+ Cmdcol = colp->GetName();
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* MakeCMD: make the SQL statement to send to MYSQL connection. */
+/***********************************************************************/
+PCMD TDBMYEXC::MakeCMD(PGLOBAL g)
+ {
+ PCMD xcmd = NULL;
+
+ if (To_CondFil) {
+ if (Cmdcol) {
+ if (!stricmp(Cmdcol, To_CondFil->Body) &&
+ (To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
+ xcmd = To_CondFil->Cmds;
+ } else
+ strcpy(g->Message, "Invalid command specification filter");
+
+ } else
+ strcpy(g->Message, "No command column in select list");
+
+ } else if (!Srcdef)
+ strcpy(g->Message, "No Srcdef default command");
+ else
+ xcmd = new(g) CMD(g, Srcdef);
+
+ return xcmd;
+ } // end of MakeCMD
+
+/***********************************************************************/
+/* EXC GetMaxSize: returns the maximum number of rows in the table. */
+/***********************************************************************/
+int TDBMYEXC::GetMaxSize(PGLOBAL)
+ {
+ if (MaxSize < 0) {
+ MaxSize = 10; // a guess
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* MySQL Exec Access Method opening routine. */
+/***********************************************************************/
+bool TDBMYEXC::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ strcpy(g->Message, "Multiple execution is not allowed");
+ return true;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open a MySQL connection for this table. */
+ /* Note: this may not be the proper way to do. Perhaps it is better */
+ /* to test whether a connection is already open for this server */
+ /* and if so to allocate just a new result set. But this only for */
+ /* servers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Myc.Connected())
+ if (Myc.Open(g, Host, Schema, User, Pwd, Port))
+ return true;
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ if (Mode != MODE_READ && Mode != MODE_READX) {
+ strcpy(g->Message, "No INSERT/DELETE/UPDATE of MYSQL EXEC tables");
+ return true;
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Get the command to execute. */
+ /*********************************************************************/
+ if (!(Cmdlist = MakeCMD(g))) {
+ // Next lines commented out because of CHECK TABLE
+ //Myc.Close();
+ //return true;
+ } // endif Cmdlist
+
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for MYSQL access method. */
+/***********************************************************************/
+int TDBMYEXC::ReadDB(PGLOBAL g)
+ {
+ if (Havew) {
+ // Process result set from SHOW WARNINGS
+ if (Myc.Fetch(g, -1) != RC_OK) {
+ Myc.FreeResult();
+ Havew = Isw = false;
+ } else {
+ N++;
+ Isw = true;
+ return RC_OK;
+ } // endif Fetch
+
+ } // endif m_Res
+
+ if (Cmdlist) {
+ // Process query to send
+ int rc;
+
+ do {
+ if (Query)
+ Query->Set(Cmdlist->Cmd);
+ else
+ Query = new(g) STRING(g, 0, Cmdlist->Cmd);
+
+ switch (rc = Myc.ExecSQLcmd(g, Query->GetStr(), &Warnings)) {
+ case RC_NF:
+ AftRows = Myc.m_Afrw;
+ strcpy(g->Message, "Affected rows");
+ break;
+ case RC_OK:
+ AftRows = Myc.m_Fields;
+ strcpy(g->Message, "Result set columns");
+ break;
+ case RC_FX:
+ AftRows = Myc.m_Afrw;
+ Nerr++;
+ break;
+ case RC_INFO:
+ Shw = true;
+ } // endswitch rc
+
+ Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
+ } while (rc == RC_INFO);
+
+ if (Shw && Warnings)
+ Havew = (Myc.ExecSQL(g, "SHOW WARNINGS") == RC_OK);
+
+ ++N;
+ return RC_OK;
+ } else {
+ PushWarning(g, this, 1);
+ return RC_EF;
+ } // endif Cmdlist
+
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for Exec MYSQL access methods. */
+/***********************************************************************/
+int TDBMYEXC::WriteDB(PGLOBAL g)
+ {
+ strcpy(g->Message, "EXEC MYSQL tables are read only");
+ return RC_FX;
+ } // end of WriteDB
+
+// ------------------------- MYXCOL functions ---------------------------
+
+/***********************************************************************/
+/* MYXCOL public constructor. */
+/***********************************************************************/
+MYXCOL::MYXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : MYSQLCOL(cdp, tdbp, cprec, i, am)
+ {
+ // Set additional EXEC MYSQL access method information for column.
+ Flag = cdp->GetOffset();
+ } // end of MYSQLCOL constructor
+
+/***********************************************************************/
+/* MYSQLCOL public constructor. */
+/***********************************************************************/
+MYXCOL::MYXCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am)
+ : MYSQLCOL(fld, tdbp, i, am)
+ {
+ if (trace(1))
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ } // end of MYSQLCOL constructor
+
+/***********************************************************************/
+/* MYXCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+MYXCOL::MYXCOL(MYXCOL *col1, PTDB tdbp) : MYSQLCOL(col1, tdbp)
+ {
+ Flag = col1->Flag;
+ } // end of MYXCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void MYXCOL::ReadColumn(PGLOBAL g)
+ {
+ PTDBMYX tdbp = (PTDBMYX)To_Tdb;
+
+ if (tdbp->Isw) {
+ char *buf = NULL;
+
+ if (Flag < 3) {
+ buf = tdbp->Myc.GetCharField(Flag);
+ Value->SetValue_psz(buf);
+ } else
+ Value->Reset();
+
+ } else
+ switch (Flag) {
+ case 0: Value->SetValue_psz(tdbp->Query->GetStr()); break;
+ case 1: Value->SetValue(tdbp->AftRows); break;
+ case 2: Value->SetValue_psz(g->Message); break;
+ case 3: Value->SetValue(tdbp->Warnings); break;
+ default: Value->SetValue_psz("Invalid Flag"); break;
+ } // endswitch Flag
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: should never be called. */
+/***********************************************************************/
+void MYXCOL::WriteColumn(PGLOBAL)
+ {
+ assert(false);
+ } // end of WriteColumn
+
+/* ---------------------------TDBMCL class --------------------------- */
+
+/***********************************************************************/
+/* TDBMCL class constructor. */
+/***********************************************************************/
+TDBMCL::TDBMCL(PMYDEF tdp) : TDBCAT(tdp)
+ {
+ Host = tdp->Hostname;
+ Db = tdp->Tabschema;
+ Tab = tdp->Tabname;
+ User = tdp->Username;
+ Pwd = tdp->Password;
+ Port = tdp->Portnumber;
+ } // end of TDBMCL constructor
+
+/***********************************************************************/
+/* GetResult: Get the list the MYSQL table columns. */
+/***********************************************************************/
+PQRYRES TDBMCL::GetResult(PGLOBAL g)
+ {
+ return MyColumns(g, NULL, Host, Db, User, Pwd, Tab, NULL, Port, false);
+ } // end of GetResult
diff --git a/storage/connect/tabmysql.h b/storage/connect/tabmysql.h
new file mode 100644
index 00000000..4b61c7eb
--- /dev/null
+++ b/storage/connect/tabmysql.h
@@ -0,0 +1,252 @@
+// TDBMYSQL.H Olivier Bertrand 2007-2017
+#include "myconn.h" // MySQL connection declares
+
+typedef class MYSQLDEF *PMYDEF;
+typedef class TDBMYSQL *PTDBMY;
+typedef class MYSQLCOL *PMYCOL;
+typedef class TDBMYEXC *PTDBMYX;
+typedef class MYXCOL *PMYXCOL;
+typedef class MYSQLC *PMYC;
+
+/* ------------------------- MYSQL classes --------------------------- */
+
+/***********************************************************************/
+/* MYSQL: table type that are MySQL tables. */
+/* Using embedded MySQL library (or optionally calling a MySQL server)*/
+/***********************************************************************/
+
+/***********************************************************************/
+/* MYSQL table. */
+/***********************************************************************/
+class MYSQLDEF : public EXTDEF {/* Logical table description */
+ friend class TDBMYSQL;
+ friend class TDBMYEXC;
+ friend class TDBMCL;
+ friend class ha_connect;
+ public:
+ // Constructor
+ MYSQLDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "MYSQL";}
+ inline PSZ GetHostname(void) {return Hostname;};
+//inline PSZ GetDatabase(void) {return Tabschema;};
+//inline PSZ GetTabname(void) {return Tabname;}
+//inline PSZ GetSrcdef(void) {return Srcdef;}
+//inline PSZ GetUsername(void) {return Username;};
+//inline PSZ GetPassword(void) {return Password;};
+ inline int GetPortnumber(void) {return Portnumber;}
+
+ // Methods
+//virtual int Indexable(void) {return 2;}
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+ bool ParseURL(PGLOBAL g, char *url, bool b = true);
+ bool GetServerInfo(PGLOBAL g, const char *server_name);
+
+ protected:
+ // Members
+ PSZ Hostname; /* Host machine to use */
+//PSZ Tabschema; /* Database to be used by server */
+//PSZ Tabname; /* External table name */
+//PSZ Srcdef; /* The source table SQL definition */
+//PSZ Username; /* User logon name */
+//PSZ Password; /* Password logon info */
+ PSZ Server; /* PServerID */
+//PSZ Qrystr; /* The original query */
+ int Portnumber; /* MySQL port number (0 = default) */
+//int Maxerr; /* Maxerr for an Exec table */
+//int Quoted; /* Identifier quoting level */
+ bool Isview; /* true if this table is a MySQL view */
+ bool Bind; /* Use prepared statement on insert */
+ bool Delayed; /* Delayed insert */
+//bool Xsrc; /* Execution type */
+ bool Huge; /* True for big table */
+ }; // end of MYSQLDEF
+
+/***********************************************************************/
+/* This is the class declaration for the MYSQL table. */
+/***********************************************************************/
+class TDBMYSQL : public TDBEXT {
+ friend class MYSQLCOL;
+ friend class TDBTBM;
+ public:
+ // Constructor
+ TDBMYSQL(PMYDEF tdp);
+ TDBMYSQL(PTDBMY tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_MYSQL;}
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMYSQL(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+//virtual int GetAffectedRows(void) {return AftRows;}
+ virtual int GetRecpos(void) {return N;}
+ virtual int GetProgMax(PGLOBAL g);
+ virtual void ResetDB(void) {N = 0;}
+ virtual int RowNumber(PGLOBAL g, bool b = false);
+ virtual bool IsView(void) {return Isview;}
+ virtual PCSZ GetServer(void) {return Server;}
+ void SetDatabase(LPCSTR db) {Schema = (char*)db;}
+
+ // Schema routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g);
+//virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr);
+
+ // Specific routines
+ bool SetColumnRanks(PGLOBAL g);
+ PCOL MakeFieldColumn(PGLOBAL g, char *name);
+ PSZ FindFieldColumn(char *name);
+
+ protected:
+ // Internal functions
+ bool MakeSelect(PGLOBAL g, bool mx);
+ bool MakeInsert(PGLOBAL g);
+ int BindColumns(PGLOBAL g __attribute__((unused)));
+ virtual bool MakeCommand(PGLOBAL g);
+//int MakeUpdate(PGLOBAL g);
+//int MakeDelete(PGLOBAL g);
+ int SendCommand(PGLOBAL g);
+
+ // Members
+ MYSQLC Myc; // MySQL connection class
+ MYSQL_BIND *Bind; // To the MySQL bind structure array
+//PSTRG Query; // Constructed SQL query
+ char *Host; // Host machine to use
+//char *User; // User logon info
+//char *Pwd; // Password logon info
+//char *Schema; // Database to be used by server
+//char *TableName; // External table name
+//char *Srcdef; // The source table SQL definition
+ char *Server; // The server ID
+//char *Qrystr; // The original query
+ bool Fetched; // True when fetch was done
+ bool Isview; // True if this table is a MySQL view
+ bool Prep; // Use prepared statement on insert
+ bool Delayed; // Use delayed insert
+ int m_Rc; // Return code from command
+//int AftRows; // The number of affected rows
+ int N; // The current table index
+ unsigned Port; // MySQL port number (0 = default)
+//int Nparm; // The number of statement parameters
+//int Quoted; // The identifier quoting level
+ }; // end of class TDBMYSQL
+
+/***********************************************************************/
+/* Class MYSQLCOL: MySQL table column. */
+/***********************************************************************/
+class MYSQLCOL : public COLBLK {
+ friend class TDBMYSQL;
+ public:
+ // Constructors
+ MYSQLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "MYSQL");
+ MYSQLCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am = "MYSQL");
+ MYSQLCOL(MYSQLCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_MYSQL;}
+ void InitBind(PGLOBAL g);
+
+ // Methods
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ bool FindRank(PGLOBAL g);
+
+ protected:
+ // Members
+ MYSQL_BIND *Bind; // This column bind structure pointer
+ PVAL To_Val; // To value used for Update/Insert
+ unsigned long Slen; // Bind string lengh
+ int Rank; // Rank (position) number in the query
+ }; // end of class MYSQLCOL
+
+/***********************************************************************/
+/* This is the class declaration for the exec command MYSQL table. */
+/***********************************************************************/
+class TDBMYEXC : public TDBMYSQL {
+ friend class MYXCOL;
+ public:
+ // Constructors
+ TDBMYEXC(PMYDEF tdp);
+ TDBMYEXC(PTDBMYX tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_MYX;}
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBMYEXC(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual bool IsView(void) {return Isview;}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+
+ protected:
+ // Internal functions
+ PCMD MakeCMD(PGLOBAL g);
+
+ // Members
+ PCMD Cmdlist; // The commands to execute
+ char *Cmdcol; // The name of the Xsrc command column
+ bool Shw; // Show warnings
+ bool Havew; // True when processing warnings
+ bool Isw; // True for warning lines
+ int Warnings; // Warnings number
+ int Mxr; // Maximum errors before closing
+ int Nerr; // Number of errors so far
+ }; // end of class TDBMYEXC
+
+/***********************************************************************/
+/* Class MYXCOL: MySQL exec command table column. */
+/***********************************************************************/
+class MYXCOL : public MYSQLCOL {
+ friend class TDBMYEXC;
+ public:
+ // Constructors
+ MYXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "MYSQL");
+ MYXCOL(MYSQL_FIELD *fld, PTDB tdbp, int i, PCSZ am = "MYSQL");
+ MYXCOL(MYXCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+ protected:
+ // Members
+ char *Buffer; // To get returned message
+ int Flag; // Column content desc
+ }; // end of class MYXCOL
+
+/***********************************************************************/
+/* This is the class declaration for the MYSQL column catalog table. */
+/***********************************************************************/
+class TDBMCL : public TDBCAT {
+ public:
+ // Constructor
+ TDBMCL(PMYDEF tdp);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PCSZ Host; // Host machine to use
+ PCSZ Db; // Database to be used by server
+ PCSZ Tab; // External table name
+ PCSZ User; // User logon name
+ PCSZ Pwd; // Password logon info
+ int Port; // MySQL port number (0 = default)
+ }; // end of class TDBMCL
diff --git a/storage/connect/taboccur.cpp b/storage/connect/taboccur.cpp
new file mode 100644
index 00000000..718b8a06
--- /dev/null
+++ b/storage/connect/taboccur.cpp
@@ -0,0 +1,589 @@
+/************ TabOccur CPP Declares Source Code File (.CPP) ************/
+/* Name: TABOCCUR.CPP Version 1.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2013 - 2021 */
+/* */
+/* OCCUR: Table that provides a view of a source table where the */
+/* contain of several columns of the source table is placed in only */
+/* one column, the OCCUR column, this resulting into several rows. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant section of system dependant header files. */
+/***********************************************************************/
+#include "my_global.h"
+#include "table.h" // MySQL table definitions
+#if defined(_WIN32)
+#include <stdlib.h>
+#include <stdio.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else
+#if defined(UNIX)
+#include <fnmatch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+#else
+//#include <io.h>
+#endif
+//#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabext.h"
+//#include "reldef.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#include "tabcol.h"
+#include "taboccur.h"
+#include "tabmysql.h"
+#include "ha_connect.h"
+
+int PrepareColist(char *colist);
+
+/***********************************************************************/
+/* Prepare and count columns in the column list. */
+/***********************************************************************/
+int PrepareColist(char *colist)
+{
+ char *p, *pn;
+ int n = 0;
+
+ // Count the number of columns and change separator into null char
+ for (pn = colist; ; pn += (strlen(pn) + 1))
+ // Separator can be ; if colist was specified in the option_list
+ if ((p = strchr(pn, ',')) || (p = strchr(pn, ';'))) {
+ *p++ = '\0';
+ n++;
+ } else {
+ if (*pn)
+ n++;
+
+ break;
+ } // endif p
+
+ return n;
+} // end of PrepareColist
+
+/************************************************************************/
+/* OcrColumns: constructs the result blocks containing all the columns */
+/* of the object table that will be retrieved by GetData commands. */
+/************************************************************************/
+bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col,
+ const char *ocr, const char *rank)
+{
+ char *pn, *colist;
+ int i, k, m, n = 0, c = 0, j = qrp->Nblin;
+ bool rk, b = false;
+ PCOLRES crp;
+
+ if (!col || !*col) {
+ strcpy(g->Message, "Missing colist");
+ return true;
+ } // endif col
+
+ // Prepare the column list
+ colist = PlugDup(g, col);
+ m = PrepareColist(colist);
+
+ if ((rk = (rank && *rank))) {
+ if (m == 1) {
+ strcpy(g->Message, "Cannot handle one column colist and rank");
+ return true;
+ } // endif m
+
+ for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1))
+ n = MY_MAX(n, (signed)strlen(pn));
+
+ } // endif k
+
+ // Default occur column name is the 1st colist column name
+ if (!ocr || !*ocr)
+ ocr = colist;
+
+ /**********************************************************************/
+ /* Replace the columns of the colist by the rank and occur columns. */
+ /**********************************************************************/
+ for (i = 0; i < qrp->Nblin; i++) {
+ for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1))
+ if (!stricmp(pn, qrp->Colresp->Kdata->GetCharValue(i)))
+ break;
+
+ if (k < m) {
+ // This column belongs to colist
+ if (rk) {
+ // Place the rank column here
+ for (crp = qrp->Colresp; crp; crp = crp->Next)
+ switch (crp->Fld) {
+ case FLD_NAME: crp->Kdata->SetValue((char*)rank, i); break;
+ case FLD_TYPE: crp->Kdata->SetValue(TYPE_STRING, i); break;
+ case FLD_PREC: crp->Kdata->SetValue(n, i); break;
+ case FLD_SCALE: crp->Kdata->SetValue(0, i); break;
+ case FLD_NULL: crp->Kdata->SetValue(0, i); break;
+ case FLD_REM: crp->Kdata->Reset(i); break;
+ default: ; // Ignored by CONNECT
+ } // endswich Fld
+
+ rk = false;
+ } else if (!b) {
+ // First remaining listed column, will be the occur column
+ for (crp = qrp->Colresp; crp; crp = crp->Next)
+ switch (crp->Fld) {
+ case FLD_NAME: crp->Kdata->SetValue((char*)ocr, i); break;
+ case FLD_REM: crp->Kdata->Reset(i); break;
+ default: ; // Nothing to do
+ } // endswich Fld
+
+ b = true;
+ } else if (j == qrp->Nblin)
+ j = i; // Column to remove
+
+ c++;
+ } else if (j < i) {
+ // Move this column in empty spot
+ for (crp = qrp->Colresp; crp; crp = crp->Next)
+ crp->Kdata->Move(i, j);
+
+ j++;
+ } // endif k
+
+ } // endfor i
+
+ // Check whether all columns of the list where found
+ if (c < m) {
+ strcpy(g->Message, "Some colist columns are not in the source table");
+ return true;
+ } // endif crp
+
+ /**********************************************************************/
+ /* Set the number of columns of the table. */
+ /**********************************************************************/
+ qrp->Nblin = j;
+ return false;
+} // end of OcrColumns
+
+/************************************************************************/
+/* OcrSrcCols: constructs the result blocks containing all the columns */
+/* of the object table that will be retrieved by GetData commands. */
+/************************************************************************/
+bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col,
+ const char *ocr, const char *rank)
+{
+ char *pn, *colist;
+ int i, k, m, n = 0, c = 0;
+ bool rk, b = false;
+ PCOLRES crp, rcrp, *pcrp;
+
+ if (!col || !*col) {
+ strcpy(g->Message, "Missing colist");
+ return true;
+ } // endif col
+
+ // Prepare the column list
+ colist = PlugDup(g, col);
+ m = PrepareColist(colist);
+
+ if ((rk = (rank && *rank)))
+ for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1))
+ n = MY_MAX(n, (signed)strlen(pn));
+
+ // Default occur column name is the 1st colist column name
+ if (!ocr || !*ocr)
+ ocr = colist;
+
+ /**********************************************************************/
+ /* Replace the columns of the colist by the rank and occur columns. */
+ /**********************************************************************/
+ for (i = 0, pcrp = &qrp->Colresp; (crp = *pcrp); ) {
+ for (k = 0, pn = colist; k < m; k++, pn += (strlen(pn) + 1))
+ if (!stricmp(pn, crp->Name))
+ break;
+
+ if (k < m) {
+ // This column belongs to colist
+ c++;
+
+ if (!b) {
+ if (rk) {
+ // Add the rank column here
+ rcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
+ memset(rcrp, 0, sizeof(COLRES));
+ rcrp->Next = crp;
+ rcrp->Name = (char*)rank;
+ rcrp->Type = TYPE_STRING;
+ rcrp->Length = n;
+ rcrp->Ncol = ++i;
+ *pcrp = rcrp;
+ } // endif rk
+
+ // First remaining listed column, will be the occur column
+ crp->Name = (char*)ocr;
+ b = true;
+ } else {
+ *pcrp = crp->Next; // Remove this column
+ continue;
+ } // endif b
+
+ } // endif k
+
+ crp->Ncol = ++i;
+ pcrp = &crp->Next;
+ } // endfor pcrp
+
+ // Check whether all columns of the list where found
+ if (c < m) {
+ strcpy(g->Message, "Some colist columns are not in the source table");
+ return true;
+ } // endif crp
+
+ /**********************************************************************/
+ /* Set the number of columns of the table. */
+ /**********************************************************************/
+ qrp->Nblin = i;
+ return false;
+} // end of OcrSrcCols
+
+/* -------------- Implementation of the OCCUR classes ---------------- */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from OCCUR table. */
+/***********************************************************************/
+bool OCCURDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ Rcol = GetStringCatInfo(g, "RankCol", "");
+ Colist = GetStringCatInfo(g, "Colist", "");
+ Xcol = GetStringCatInfo(g, "OccurCol", Colist);
+ return PRXDEF::DefineAM(g, am, poff);
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB OCCURDEF::GetTable(PGLOBAL g, MODE)
+{
+ if (Catfunc != FNC_COL)
+ return new(g) TDBOCCUR(this);
+ else
+ return new(g) TDBTBC(this);
+
+} // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBOCCUR class. */
+/***********************************************************************/
+TDBOCCUR::TDBOCCUR(POCCURDEF tdp) : TDBPRX(tdp)
+{
+//Tdbp = NULL; // Source table (in TDBPRX)
+ Tabname = tdp->Tablep->GetName(); // Name of source table
+ Colist = tdp->Colist; // List of source columns
+ Xcolumn = tdp->Xcol; // Occur column name
+ Rcolumn = tdp->Rcol; // Rank column name
+ Xcolp = NULL; // To the OCCURCOL column
+ Col = NULL; // To source column blocks array
+ Mult = PrepareColist(Colist); // Multiplication factor
+ N = 0; // The current table index
+ M = 0; // The occurrence rank
+ RowFlag = 0; // 0: Ok, 1: Same, 2: Skip
+} // end of TDBOCCUR constructor
+
+/***********************************************************************/
+/* Allocate OCCUR/SRC column description block. */
+/***********************************************************************/
+PCOL TDBOCCUR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ PCOL colp = NULL;
+
+ if (!stricmp(cdp->GetName(), Rcolumn)) {
+ // Allocate a RANK column
+ colp = new(g) RANKCOL(cdp, this, n);
+ } else if (!stricmp(cdp->GetName(), Xcolumn)) {
+ // Allocate the OCCUR column
+ colp = Xcolp = new(g) OCCURCOL(cdp, this, n);
+ } else
+ return new(g) PRXCOL(cdp, this, cprec, n);
+
+ if (cprec) {
+ colp->SetNext(cprec->GetNext());
+ cprec->SetNext(colp);
+ } else {
+ colp->SetNext(Columns);
+ Columns = colp;
+ } // endif cprec
+
+ return colp;
+} // end of MakeCol
+
+/***********************************************************************/
+/* Initializes the table. */
+/***********************************************************************/
+bool TDBOCCUR::InitTable(PGLOBAL g)
+{
+ if (!Tdbp)
+ // Get the table description block of this table
+ if (!(Tdbp = GetSubTable(g, ((POCCURDEF)To_Def)->Tablep, TRUE)))
+ return TRUE;
+
+ if (!Tdbp->IsView())
+ if (MakeColumnList(g))
+ return TRUE;
+
+ return FALSE;
+} // end of InitTable
+
+/***********************************************************************/
+/* Allocate OCCUR column description block. */
+/***********************************************************************/
+bool TDBOCCUR::MakeColumnList(PGLOBAL g)
+{
+ char *pn;
+ int i;
+ PCOL colp;
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_PRX)
+ if (((PPRXCOL)colp)->Init(g, NULL))
+ return true;
+
+ Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL));
+
+ for (i = 0, pn = Colist; i < Mult; i++, pn += (strlen(pn) + 1)) {
+ if (!(Col[i] = Tdbp->ColDB(g, pn, 0))) {
+ // Column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), pn, Tabname);
+ return true;
+ } // endif Col
+
+ if (Col[i]->InitValue(g)) {
+ strcpy(g->Message, "OCCUR InitValue failed");
+ return true;
+ } // endif InitValue
+
+ } // endfor i
+
+ return false;
+} // end of MakeColumnList
+
+/***********************************************************************/
+/* Allocate OCCUR column description block for a view. */
+/***********************************************************************/
+bool TDBOCCUR::ViewColumnList(PGLOBAL g)
+{
+ char *pn;
+ int i;
+ PCOL colp, cp;
+ PTDBMY tdbp;
+
+ if (!Tdbp->IsView())
+ return false;
+
+ if (Tdbp->GetAmType() != TYPE_AM_MYSQL) {
+ strcpy(g->Message, "View is not MySQL");
+ return true;
+ } else
+ tdbp = (PTDBMY)Tdbp;
+
+ for (cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_PRX) {
+ if ((colp = tdbp->MakeFieldColumn(g, cp->GetName()))) {
+ ((PPRXCOL)cp)->Colp = colp;
+ ((PPRXCOL)cp)->To_Val = colp->GetValue();
+ } else
+ return true;
+
+ } // endif Type
+
+ Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL));
+
+ for (i = 0, pn = Colist; i < Mult; i++, pn += (strlen(pn) + 1))
+ if (!(Col[i] = tdbp->MakeFieldColumn(g, pn))) {
+ // Column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), pn, Tabname);
+ return true;
+ } // endif Col
+
+ return false;
+} // end of ViewColumnList
+
+/***********************************************************************/
+/* OCCUR GetMaxSize: returns the maximum number of rows in the table. */
+/***********************************************************************/
+int TDBOCCUR::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0) {
+ if (!(Tdbp = GetSubTable(g, ((POCCURDEF)To_Def)->Tablep, TRUE)))
+ return 0;
+
+ MaxSize = Mult * Tdbp->GetMaxSize(g);
+ } // endif MaxSize
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* In this sample, ROWID will be the (virtual) row number, */
+/* while ROWNUM will be the occurrence rank in the multiple column. */
+/***********************************************************************/
+int TDBOCCUR::RowNumber(PGLOBAL, bool b)
+{
+ return (b) ? M : N;
+} // end of RowNumber
+
+/***********************************************************************/
+/* OCCUR Access Method opening routine. */
+/***********************************************************************/
+bool TDBOCCUR::OpenDB(PGLOBAL g)
+{
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ N = M = 0;
+ RowFlag = 0;
+
+ if (Xcolp)
+ Xcolp->Xreset();
+
+ return Tdbp->OpenDB(g);
+ } // endif use
+
+
+ if (Mode != MODE_READ) {
+ /*******************************************************************/
+ /* Currently OCCUR tables cannot be modified. */
+ /*******************************************************************/
+ strcpy(g->Message, "OCCUR tables are read only");
+ return TRUE;
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Do it here if not done yet. */
+ /*********************************************************************/
+ if (InitTable(g))
+ return TRUE;
+
+ if (Xcolp)
+ // Lock this column so it is evaluated by its table only
+ Xcolp->AddStatus(BUF_READ);
+
+ if (To_Key_Col || To_Kindex) {
+ /*******************************************************************/
+ /* Direct access of OCCUR tables is not implemented yet. */
+ /*******************************************************************/
+ strcpy(g->Message, "No direct access to OCCUR tables");
+ return TRUE;
+ } // endif To_Key_Col
+
+ /*********************************************************************/
+ /* Do open the source table. */
+ /*********************************************************************/
+ if (Tdbp->OpenDB(g))
+ return TRUE;
+
+ Use = USE_OPEN;
+ return ViewColumnList(g);
+} // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for OCCUR access method. */
+/***********************************************************************/
+int TDBOCCUR::ReadDB(PGLOBAL g)
+{
+ int rc = RC_OK;
+
+ /*********************************************************************/
+ /* Now start the multi reading process. */
+ /*********************************************************************/
+ do {
+ if (RowFlag != 1)
+ if ((rc = Tdbp->ReadDB(g)) != RC_OK)
+ break;
+
+ if (Xcolp) {
+ RowFlag = 0;
+ Xcolp->ReadColumn(g);
+ M = Xcolp->GetI();
+ } // endif Xcolp
+
+ } while (RowFlag == 2);
+
+ N++;
+ return rc;
+} // end of ReadDB
+
+// ------------------------ OCCURCOL functions ----------------------------
+
+/***********************************************************************/
+/* OCCURCOL public constructor. */
+/***********************************************************************/
+OCCURCOL::OCCURCOL(PCOLDEF cdp, PTDBOCCUR tdbp, int n)
+ : COLBLK(cdp, tdbp, n)
+{
+ // Set additional OCCUR access method information for column.
+ I = 0;
+} // end of OCCURCOL constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the columns of */
+/* list, extract their value and convert it to buffer type. */
+/***********************************************************************/
+void OCCURCOL::ReadColumn(PGLOBAL g)
+{
+ PTDBOCCUR tdbp = (PTDBOCCUR)To_Tdb;
+ PCOL *col = tdbp->Col;
+
+ for (; I < tdbp->Mult; I++) {
+ col[I]->ReadColumn(g);
+
+ if (Nullable || !col[I]->GetValue()->IsZero())
+ break;
+
+ } // endfor I
+
+ if (I == tdbp->Mult) {
+ // No more values, go to next source row
+ tdbp->RowFlag = 2;
+ I = 0;
+ return;
+ } // endif I
+
+ // Set the OCCUR column value from the Ith source column value
+ Value->SetValue_pval(col[I++]->GetValue());
+ tdbp->RowFlag = 1;
+} // end of ReadColumn
+
+
+// ------------------------ RANKCOL functions ---------------------------
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the Mth columns of */
+/* list, extract its name and set to it the rank column value. */
+/***********************************************************************/
+void RANKCOL::ReadColumn(PGLOBAL)
+{
+ PTDBOCCUR tdbp = (PTDBOCCUR)To_Tdb;
+ PCOL *col = tdbp->Col;
+
+ // Set the RANK column value from the Mth source column name
+ if (tdbp->M)
+ Value->SetValue_psz(col[tdbp->M - 1]->GetName());
+ else {
+ Value->Reset();
+
+ if (Nullable)
+ Value->SetNull(true);
+
+ } // endelse
+
+} // end of ReadColumn
diff --git a/storage/connect/taboccur.h b/storage/connect/taboccur.h
new file mode 100644
index 00000000..13bc055c
--- /dev/null
+++ b/storage/connect/taboccur.h
@@ -0,0 +1,142 @@
+// TABOCCUR.H Olivier Bertrand 2013
+// Defines the OCCUR tables
+
+#include "tabutil.h"
+
+typedef class OCCURDEF *POCCURDEF;
+typedef class TDBOCCUR *PTDBOCCUR;
+typedef class OCCURCOL *POCCURCOL;
+typedef class RANKCOL *PRANKCOL;
+
+/* -------------------------- OCCUR classes -------------------------- */
+
+/***********************************************************************/
+/* OCCUR: Table that provides a view of a source table where the */
+/* contain of several columns of the source table is placed in only */
+/* one column, the OCCUR column, this resulting into several rows. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* OCCUR table. */
+/***********************************************************************/
+class OCCURDEF : public PRXDEF { /* Logical table description */
+ friend class TDBOCCUR;
+ public:
+ // Constructor
+ OCCURDEF(void) {Pseudo = 3; Colist = Xcol = NULL;}
+
+ // Implementation
+ virtual const char *GetType(void) {return "OCCUR";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ char *Colist; /* The source column list */
+ char *Xcol; /* The multiple occurrence column */
+ char *Rcol; /* The rank column */
+ }; // end of OCCURDEF
+
+/***********************************************************************/
+/* This is the class declaration for the OCCUR table. */
+/***********************************************************************/
+class TDBOCCUR : public TDBPRX {
+ friend class OCCURCOL;
+ friend class RANKCOL;
+ public:
+ // Constructor
+ TDBOCCUR(POCCURDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_OCCUR;}
+ void SetTdbp(PTDBASE tdbp) {Tdbp = tdbp;}
+
+ // Methods
+ virtual void ResetDB(void) {N = 0; Tdbp->ResetDB();}
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE);
+ bool MakeColumnList(PGLOBAL g);
+ bool ViewColumnList(PGLOBAL g);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual bool InitTable(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+
+ protected:
+ // Members
+ LPCSTR Tabname; // Name of source table
+ char *Colist; // Source column list
+ char *Xcolumn; // Occurence column name
+ char *Rcolumn; // Rank column name
+ POCCURCOL Xcolp; // To the OCCURCOL column
+ PCOL *Col; // To source multiple columns
+ int Mult; // Multiplication factor
+ int N; // The current table index
+ int M; // The occurrence rank
+ BYTE RowFlag; // 0: Ok, 1: Same, 2: Skip
+ }; // end of class TDBOCCUR
+
+/***********************************************************************/
+/* Class OCCURCOL: for the multiple occurrence column. */
+/***********************************************************************/
+class OCCURCOL : public COLBLK {
+ public:
+ // Constructors
+ OCCURCOL(PCOLDEF cdp, PTDBOCCUR tdbp, int n);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_OCCUR;}
+ int GetI(void) {return I;}
+
+ // Methods
+ virtual void Reset(void) {} // Evaluated only by TDBOCCUR
+ virtual void ReadColumn(PGLOBAL g);
+ void Xreset(void) {I = 0;};
+
+ protected:
+ // Default constructor not to be used
+ OCCURCOL(void) {}
+
+ // Members
+ int I;
+ }; // end of class OCCURCOL
+
+/***********************************************************************/
+/* Class RANKCOL: for the multiple occurrence column ranking. */
+/***********************************************************************/
+class RANKCOL : public COLBLK {
+ public:
+ // Constructors
+ RANKCOL(PCOLDEF cdp, PTDBOCCUR tdbp, int n) : COLBLK(cdp, tdbp, n) {}
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_OCCUR;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ RANKCOL(void) {}
+
+ // Members
+ }; // end of class RANKCOL
+
+/***********************************************************************/
+/* Definition of class XCOLDEF. */
+/* This class purpose is just to access COLDEF protected items! */
+/***********************************************************************/
+class XCOLDEF: public COLDEF {
+ friend class TDBOCCUR;
+ }; // end of class XCOLDEF
+
+
+bool OcrColumns(PGLOBAL g, PQRYRES qrp, const char *col,
+ const char *ocr, const char *rank);
+
+bool OcrSrcCols(PGLOBAL g, PQRYRES qrp, const char *col,
+ const char *ocr, const char *rank);
diff --git a/storage/connect/tabodbc.cpp b/storage/connect/tabodbc.cpp
new file mode 100644
index 00000000..4e8b4417
--- /dev/null
+++ b/storage/connect/tabodbc.cpp
@@ -0,0 +1,1411 @@
+/************* Tabodbc C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: TABODBC */
+/* ------------- */
+/* Version 3.2 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2000-2018 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TABODBC class DB execution routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABODBC.CPP - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABODBC.H - TABODBC classes declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#include "sql_class.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#include <sqltypes.h>
+#else
+#if defined(UNIX)
+#include <errno.h>
+#define NODW
+#include "osutil.h"
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* kindex.h is kindex header that also includes tabdos.h. */
+/* tabodbc.h is header containing the TABODBC class declarations. */
+/* odbconn.h is header containing ODBC connection declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "mycat.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "odbccat.h"
+#include "tabodbc.h"
+#include "tabmul.h"
+//#include "reldef.h"
+#include "tabcol.h"
+#include "valblk.h"
+#include "ha_connect.h"
+
+#include "sql_string.h"
+
+/***********************************************************************/
+/* DB static variables. */
+/***********************************************************************/
+// int num_read, num_there, num_eq[2], num_nf; // Statistics
+extern int num_read, num_there, num_eq[2]; // Statistics
+
+/***********************************************************************/
+/* External function. */
+/***********************************************************************/
+bool ExactInfo(void);
+
+/* -------------------------- Class ODBCDEF -------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+ODBCDEF::ODBCDEF(void)
+{
+ Connect = NULL;
+ Catver = 0;
+ UseCnc = false;
+} // end of ODBCDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ Desc = Connect = GetStringCatInfo(g, "Connect", NULL);
+
+ if (!Connect && !Catfunc) {
+ sprintf(g->Message, "Missing connection for ODBC table %s", Name);
+ return true;
+ } // endif Connect
+
+ if (EXTDEF::DefineAM(g, am, poff))
+ return true;
+
+ Catver = GetIntCatInfo("Catver", 2);
+ Options = ODBConn::noOdbcDialog;
+//Options = ODBConn::noOdbcDialog | ODBConn::useCursorLib;
+ Cto= GetIntCatInfo("ConnectTimeout", DEFAULT_LOGIN_TIMEOUT);
+ Qto= GetIntCatInfo("QueryTimeout", DEFAULT_QUERY_TIMEOUT);
+ UseCnc = GetBoolCatInfo("UseDSN", false);
+ return false;
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB ODBCDEF::GetTable(PGLOBAL g, MODE m)
+{
+ PTDB tdbp = NULL;
+
+ /*********************************************************************/
+ /* Allocate a TDB of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*********************************************************************/
+ if (Xsrc)
+ tdbp = new(g) TDBXDBC(this);
+ else switch (Catfunc) {
+ case FNC_COL:
+ tdbp = new(g) TDBOCL(this);
+ break;
+ case FNC_TABLE:
+ tdbp = new(g) TDBOTB(this);
+ break;
+ case FNC_DSN:
+ tdbp = new(g) TDBSRC(this);
+ break;
+ case FNC_DRIVER:
+ tdbp = new(g) TDBDRV(this);
+ break;
+ default:
+ tdbp = new(g) TDBODBC(this);
+
+ if (Multiple == 1)
+ tdbp = new(g) TDBMUL(tdbp);
+ else if (Multiple == 2)
+ strcpy(g->Message, MSG(NO_ODBC_MUL));
+ } // endswitch Catfunc
+
+ return tdbp;
+} // end of GetTable
+
+/* -------------------------- Class TDBODBC -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBODBC class. */
+/***********************************************************************/
+TDBODBC::TDBODBC(PODEF tdp) : TDBEXT(tdp)
+{
+ Ocp = NULL;
+ Cnp = NULL;
+
+ if (tdp) {
+ Connect = tdp->Connect;
+ Ops.User = tdp->Username;
+ Ops.Pwd = tdp->Password;
+ Ops.Cto = tdp->Cto;
+ Ops.Qto = tdp->Qto;
+ Catver = tdp->Catver;
+ Ops.UseCnc = tdp->UseCnc;
+ } else {
+ Connect = NULL;
+ Ops.User = NULL;
+ Ops.Pwd = NULL;
+ Ops.Cto = DEFAULT_LOGIN_TIMEOUT;
+ Ops.Qto = DEFAULT_QUERY_TIMEOUT;
+ Catver = 0;
+ Ops.UseCnc = false;
+ } // endif tdp
+
+} // end of TDBODBC standard constructor
+
+TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBEXT(tdbp)
+{
+ Ocp = tdbp->Ocp; // is that right ?
+ Cnp = tdbp->Cnp;
+ Connect = tdbp->Connect;
+ Ops = tdbp->Ops;
+} // end of TDBODBC copy constructor
+
+// Method
+PTDB TDBODBC::Clone(PTABS t)
+{
+ PTDB tp;
+ PODBCCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBODBC(this);
+
+ for (cp1 = (PODBCCOL)Columns; cp1; cp1 = (PODBCCOL)cp1->GetNext()) {
+ cp2 = new(g) ODBCCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+} // end of CopyOne
+
+/***********************************************************************/
+/* Allocate ODBC column description block. */
+/***********************************************************************/
+PCOL TDBODBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ return new(g) ODBCCOL(cdp, this, cprec, n);
+} // end of MakeCol
+
+/***********************************************************************/
+/* Extract the filename from connect string and return it. */
+/* This used for Multiple(1) tables. Also prepare a connect string */
+/* with a place holder to be used by SetFile. */
+/***********************************************************************/
+PCSZ TDBODBC::GetFile(PGLOBAL g)
+{
+ if (Connect) {
+ char *p1, *p2;
+ int i;
+ size_t n;
+
+ if (!(p1 = strstr(Connect, "DBQ="))) {
+ char *p, *lc = strlwr(PlugDup(g, Connect));
+
+ if ((p = strstr(lc, "database=")))
+ p1 = Connect + (p - lc);
+
+ i = 9;
+ } else
+ i = 4;
+
+ if (p1) {
+ p1 += i; // Beginning of file name
+ p2 = strchr(p1, ';'); // End of file path/name
+
+ // Make the File path/name from the connect string
+ n = (p2) ? p2 - p1 : strlen(p1);
+ DBQ = (PSZ)PlugSubAlloc(g, NULL, n + 1);
+ memcpy(DBQ, p1, n);
+ DBQ[n] = '\0';
+
+ // Make the Format used to re-generate Connect (3 = "%s" + 1)
+ MulConn = (char*)PlugSubAlloc(g, NULL, strlen(Connect) - n + 3);
+ memcpy(MulConn, Connect, p1 - Connect);
+ MulConn[p1 - Connect] = '\0';
+ strcat(strcat(MulConn, "%s"), (p2) ? p2 : ";");
+ } // endif p1
+
+ } // endif Connect
+
+ return (DBQ) ? DBQ : (PSZ)"???";
+} // end of GetFile
+
+/***********************************************************************/
+/* Set DBQ and get the new file name into the connect string. */
+/***********************************************************************/
+void TDBODBC::SetFile(PGLOBAL g, PCSZ fn)
+{
+ if (MulConn) {
+ int n = strlen(MulConn) + strlen(fn) - 1;
+
+ if (n > BufSize) {
+ // Allocate a buffer larger than needed so the chance
+ // of having to reallocate it is reduced.
+ BufSize = n + 6;
+ Connect = (char*)PlugSubAlloc(g, NULL, BufSize);
+ } // endif n
+
+ // Make the complete connect string
+ sprintf(Connect, MulConn, fn);
+ } // endif MultConn
+
+ DBQ = PlugDup(g, fn);
+} // end of SetFile
+
+/***********************************************************************/
+/* MakeInsert: make the Insert statement used with ODBC connection. */
+/***********************************************************************/
+bool TDBODBC::MakeInsert(PGLOBAL g)
+{
+ PCSZ schmp = NULL;
+ char *catp = NULL, buf[NAM_LEN * 3];
+ int len = 0;
+ bool oom, b = false;
+ PCOL colp;
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->IsSpecial()) {
+ strcpy(g->Message, MSG(NO_ODBC_SPECOL));
+ return true;
+ } else {
+ // Column name can be encoded in UTF-8
+ Decode(colp->GetName(), buf, sizeof(buf));
+ len += (strlen(buf) + 6); // comma + quotes + valist
+ ((PEXTCOL)colp)->SetRank(++Nparm);
+ } // endif colp
+
+ // Below 32 is enough to contain the fixed part of the query
+ if (Catalog && *Catalog)
+ catp = Catalog;
+
+ if (catp)
+ len += strlen(catp) + 1;
+
+ if (Schema && *Schema)
+ schmp = Schema;
+
+ if (schmp)
+ len += strlen(schmp) + 1;
+
+ // Table name can be encoded in UTF-8
+ Decode(TableName, buf, sizeof(buf));
+ len += (strlen(buf) + 32);
+ Query = new(g) STRING(g, len, "INSERT INTO ");
+
+ if (catp) {
+ Query->Append(catp);
+
+ if (schmp) {
+ Query->Append('.');
+ Query->Append(schmp);
+ } // endif schmp
+
+ Query->Append('.');
+ } else if (schmp) {
+ Query->Append(schmp);
+ Query->Append('.');
+ } // endif schmp
+
+ if (Quote) {
+ // Put table name between identifier quotes in case in contains blanks
+ Query->Append(Quote);
+ Query->Append(buf);
+ Query->Append(Quote);
+ } else
+ Query->Append(buf);
+
+ Query->Append('(');
+
+ for (colp = Columns; colp; colp = colp->GetNext()) {
+ if (b)
+ Query->Append(", ");
+ else
+ b = true;
+
+ // Column name can be in UTF-8 encoding
+ Decode(colp->GetName(), buf, sizeof(buf));
+
+ if (Quote) {
+ // Put column name between identifier quotes in case in contains blanks
+ Query->Append(Quote);
+ Query->Append(buf);
+ Query->Append(Quote);
+ } else
+ Query->Append(buf);
+
+ } // endfor colp
+
+ Query->Append(") VALUES (");
+
+ for (int i = 0; i < Nparm; i++)
+ Query->Append("?,");
+
+ if ((oom = Query->IsTruncated()))
+ strcpy(g->Message, "MakeInsert: Out of memory");
+ else
+ Query->RepLast(')');
+
+ return oom;
+} // end of MakeInsert
+
+/***********************************************************************/
+/* ODBC Bind Parameter function. */
+/***********************************************************************/
+bool TDBODBC::BindParameters(PGLOBAL g)
+{
+ PODBCCOL colp;
+
+ for (colp = (PODBCCOL)Columns; colp; colp = (PODBCCOL)colp->Next) {
+ colp->AllocateBuffers(g, 0);
+
+ if (Ocp->BindParam(colp))
+ return true;
+
+ } // endfor colp
+
+ return false;
+} // end of BindParameters
+
+#if 0
+/***********************************************************************/
+/* MakeUpdate: make the SQL statement to send to ODBC connection. */
+/***********************************************************************/
+char *TDBODBC::MakeUpdate(PGLOBAL g)
+{
+ char *qc, *stmt = NULL, cmd[8], tab[96], end[1024];
+
+ stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ memset(end, 0, sizeof(end));
+
+ if (sscanf(Qrystr, "%s `%[^`]`%1023c", cmd, tab, end) > 2 ||
+ sscanf(Qrystr, "%s \"%[^\"]\"%1023c", cmd, tab, end) > 2)
+ qc = Ocp->GetQuoteChar();
+ else if (sscanf(Qrystr, "%s %s%1023c", cmd, tab, end) > 2)
+ qc = (Quoted) ? Quote : "";
+ else {
+ strcpy(g->Message, "Cannot use this UPDATE command");
+ return NULL;
+ } // endif sscanf
+
+ assert(!stricmp(cmd, "update"));
+ strcat(strcat(strcat(strcpy(stmt, "UPDATE "), qc), TableName), qc);
+
+ for (int i = 0; end[i]; i++)
+ if (end[i] == '`')
+ end[i] = *qc;
+
+ strcat(stmt, end);
+ return stmt;
+} // end of MakeUpdate
+
+/***********************************************************************/
+/* MakeDelete: make the SQL statement to send to ODBC connection. */
+/***********************************************************************/
+char *TDBODBC::MakeDelete(PGLOBAL g)
+{
+ char *qc, *stmt = NULL, cmd[8], from[8], tab[96], end[512];
+
+ stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
+ memset(end, 0, sizeof(end));
+
+ if (sscanf(Qrystr, "%s %s `%[^`]`%511c", cmd, from, tab, end) > 2 ||
+ sscanf(Qrystr, "%s %s \"%[^\"]\"%511c", cmd, from, tab, end) > 2)
+ qc = Ocp->GetQuoteChar();
+ else if (sscanf(Qrystr, "%s %s %s%511c", cmd, from, tab, end) > 2)
+ qc = (Quoted) ? Quote : "";
+ else {
+ strcpy(g->Message, "Cannot use this DELETE command");
+ return NULL;
+ } // endif sscanf
+
+ assert(!stricmp(cmd, "delete") && !stricmp(from, "from"));
+ strcat(strcat(strcat(strcpy(stmt, "DELETE FROM "), qc), TableName), qc);
+
+ if (*end) {
+ for (int i = 0; end[i]; i++)
+ if (end[i] == '`')
+ end[i] = *qc;
+
+ strcat(stmt, end);
+ } // endif end
+
+ return stmt;
+} // end of MakeDelete
+#endif // 0
+
+/***********************************************************************/
+/* ResetSize: call by TDBMUL when calculating size estimate. */
+/***********************************************************************/
+void TDBODBC::ResetSize(void)
+{
+ MaxSize = -1;
+
+ if (Ocp && Ocp->IsOpen())
+ Ocp->Close();
+
+} // end of ResetSize
+
+/***********************************************************************/
+/* ODBC Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBODBC::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return (Mode == MODE_ANY && !Srcdef) ? 1 : 0;
+
+ if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) {
+ // Info command, we must return the exact table row number
+ char qry[96], tbn[64];
+ ODBConn *ocp = new(g) ODBConn(g, this);
+
+ if (ocp->Open(Connect, &Ops, Options) < 1)
+ return -1;
+
+ // Table name can be encoded in UTF-8
+ Decode(TableName, tbn, sizeof(tbn));
+ strcpy(qry, "SELECT COUNT(*) FROM ");
+
+ if (Quote)
+ strcat(strcat(strcat(qry, Quote), tbn), Quote);
+ else
+ strcat(qry, tbn);
+
+ // Allocate a Count(*) column (must not use the default constructor)
+ Cnp = new(g) ODBCCOL;
+ Cnp->InitValue(g);
+
+ if ((Cardinal = ocp->GetResultSize(qry, Cnp)) < 0)
+ return -3;
+
+ ocp->Close();
+ } else
+ Cardinal = 10; // To make MySQL happy
+
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* ODBC Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool TDBODBC::OpenDB(PGLOBAL g)
+{
+ bool rc = true;
+
+ if (trace(1))
+ htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ if (Memory == 1) {
+ if ((Qrp = Ocp->AllocateResult(g)))
+ Memory = 2; // Must be filled
+ else
+ Memory = 0; // Allocation failed, don't use it
+
+ } else if (Memory == 2)
+ Memory = 3; // Ok to use memory result
+
+ if (Memory < 3) {
+ // Method will depend on cursor type
+ if ((Rbuf = Ocp->Rewind(Query->GetStr(), (PODBCCOL)Columns)) < 0) {
+ if (Mode != MODE_READX) {
+ Ocp->Close();
+ return true;
+ } else {
+ Rbuf = 0;
+ }
+ }
+ } else {
+ Rbuf = Qrp->Nblin;
+ }
+
+ CurNum = 0;
+ Fpos = 0;
+ Curpos = 1;
+ return false;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open an ODBC connection for this table. */
+ /* Note: this may not be the proper way to do. Perhaps it is better */
+ /* to test whether a connection is already open for this datasource */
+ /* and if so to allocate just a new result set. But this only for */
+ /* drivers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Ocp)
+ Ocp = new(g) ODBConn(g, this);
+ else if (Ocp->IsOpen())
+ Ocp->Close();
+
+ if (Ocp->Open(Connect, &Ops, Options) < 1)
+ return true;
+ else if (Quoted)
+ Quote = Ocp->GetQuoteChar();
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Make the command and allocate whatever is used for getting results*/
+ /*********************************************************************/
+ if (Mode == MODE_READ || Mode == MODE_READX) {
+ if (Memory > 1 && !Srcdef) {
+ int n;
+
+ if (!MakeSQL(g, true)) {
+ // Allocate a Count(*) column
+ Cnp = new(g) ODBCCOL;
+ Cnp->InitValue(g);
+
+ if ((n = Ocp->GetResultSize(Query->GetStr(), Cnp)) < 0) {
+ char* msg = PlugDup(g, g->Message);
+
+ sprintf(g->Message, "Get result size: %s (rc=%d)", msg, n);
+ return true;
+ } else if (n) {
+ Ocp->m_Rows = n;
+
+ if ((Qrp = Ocp->AllocateResult(g)))
+ Memory = 2; // Must be filled
+ else {
+ strcpy(g->Message, "Result set memory allocation failed");
+ return true;
+ } // endif n
+
+ } else // Void result
+ Memory = 0;
+
+ Ocp->m_Rows = 0;
+ } else
+ return true;
+
+ } // endif Memory
+
+ if (!(rc = MakeSQL(g, false))) {
+ for (PODBCCOL colp = (PODBCCOL)Columns; colp;
+ colp = (PODBCCOL)colp->GetNext())
+ if (!colp->IsSpecial())
+ colp->AllocateBuffers(g, Rows);
+
+ rc = (Mode == MODE_READ)
+ ? ((Rows = Ocp->ExecDirectSQL(Query->GetStr(), (PODBCCOL)Columns)) < 0)
+ : false;
+ } // endif rc
+
+ } else if (Mode == MODE_INSERT) {
+ if (!(rc = MakeInsert(g))) {
+ if (Nparm != Ocp->PrepareSQL(Query->GetStr())) {
+ strcpy(g->Message, MSG(PARM_CNT_MISS));
+ rc = true;
+ } else
+ rc = BindParameters(g);
+
+ } // endif rc
+
+ } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ rc = false; // wait for CheckCond before calling MakeCommand(g);
+ } else
+ sprintf(g->Message, "Invalid mode %d", Mode);
+
+ if (rc) {
+ Ocp->Close();
+ return true;
+ } // endif rc
+
+ /*********************************************************************/
+ /* Reset statistics values. */
+ /*********************************************************************/
+ num_read = num_there = num_eq[0] = num_eq[1] = 0;
+ return false;
+} // end of OpenDB
+
+#if 0
+/***********************************************************************/
+/* GetRecpos: return the position of last read record. */
+/***********************************************************************/
+int TDBODBC::GetRecpos(void)
+{
+ return Fpos;
+} // end of GetRecpos
+#endif // 0
+
+/***********************************************************************/
+/* SetRecpos: set the position of next read record. */
+/***********************************************************************/
+bool TDBODBC::SetRecpos(PGLOBAL g, int recpos)
+{
+ if (Ocp->m_Full) {
+ Fpos = 0;
+ CurNum = recpos - 1;
+ } else if (Memory == 3) {
+ Fpos = recpos;
+ CurNum = -1;
+ } else if (Scrollable) {
+ // Is new position in the current row set?
+ if (recpos >= Curpos && recpos < Curpos + Rbuf) {
+ CurNum = recpos - Curpos;
+ Fpos = 0;
+ } else {
+ Fpos = recpos;
+ CurNum = 0;
+ } // endif recpos
+
+ } else {
+ strcpy(g->Message,
+ "This action requires Memory setting or a scrollable cursor");
+ return true;
+ } // endif's
+
+ // Indicate the table position was externally set
+ Placed = true;
+ return false;
+} // end of SetRecpos
+
+/***********************************************************************/
+/* Data Base indexed read routine for ODBC access method. */
+/***********************************************************************/
+bool TDBODBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
+{
+ char c = Quote ? *Quote : 0;
+ int oldlen = Query->GetLength();
+ PHC hc = To_Def->GetHandler();
+
+ if (!(kr || hc->end_range) || op == OP_NEXT ||
+ Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ if (!kr && Mode == MODE_READX) {
+ // This is a false indexed read
+ Rows = Ocp->ExecDirectSQL((char*)Query->GetStr(), (PODBCCOL)Columns);
+ Mode = MODE_READ;
+ return (Rows < 0);
+ } // endif key
+
+ return false;
+ } else {
+ if (hc->MakeKeyWhere(g, Query, op, c, kr))
+ return true;
+
+ if (To_CondFil) {
+ if (To_CondFil->Idx != hc->active_index) {
+ To_CondFil->Idx = hc->active_index;
+ To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
+ *To_CondFil->Body= 0;
+
+ if ((To_CondFil = hc->CheckCond(g, To_CondFil, Cond)))
+ PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
+
+ } // endif active_index
+
+ if (To_CondFil)
+ if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
+ strcpy(g->Message, "Readkey: Out of memory");
+ return true;
+ } // endif Append
+
+ } // endif To_Condfil
+
+ Mode = MODE_READ;
+ } // endif's op
+
+ if (trace(33))
+ htrc("ODBC ReadKey: Query=%s\n", Query->GetStr());
+
+ Rows = Ocp->ExecDirectSQL((char*)Query->GetStr(), (PODBCCOL)Columns);
+ Query->Truncate(oldlen);
+ return (Rows < 0);
+} // end of ReadKey
+
+/***********************************************************************/
+/* VRDNDOS: Data Base read routine for odbc access method. */
+/***********************************************************************/
+int TDBODBC::ReadDB(PGLOBAL g)
+{
+ int rc;
+
+ if (trace(2))
+ htrc("ODBC ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode);
+
+ if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
+ if (!Query && MakeCommand(g))
+ return RC_FX;
+
+ // Send the UPDATE/DELETE command to the remote table
+ if (!Ocp->ExecSQLcommand(Query->GetStr())) {
+ sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ PushWarning(g, this, 0); // 0 means a Note
+ return RC_EF; // Nothing else to do
+ } else
+ return RC_FX; // Error
+
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Now start the reading process. */
+ /* Here is the place to fetch the line(s). */
+ /*********************************************************************/
+ if (Placed) {
+ if (Fpos && CurNum >= 0)
+ Rbuf = Ocp->Fetch((Curpos = Fpos));
+
+ rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
+ Placed = false;
+ } else {
+ if (Memory != 3) {
+ if (++CurNum >= Rbuf) {
+ Rbuf = Ocp->Fetch();
+ Curpos = Fpos + 1;
+ CurNum = 0;
+ } // endif CurNum
+
+ rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
+ } else // Getting result from memory
+ rc = (Fpos < Qrp->Nblin) ? RC_OK : RC_EF;
+
+ if (rc == RC_OK) {
+ if (Memory == 2)
+ Qrp->Nblin++;
+
+ Fpos++; // Used for memory and pos
+ } // endif rc
+
+ } // endif Placed
+
+ if (trace(2))
+ htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);
+
+ return rc;
+} // end of ReadDB
+
+/***********************************************************************/
+/* Data Base Insert write routine for ODBC access method. */
+/***********************************************************************/
+int TDBODBC::WriteDB(PGLOBAL g)
+{
+ int n = Ocp->ExecuteSQL();
+
+ if (n < 0) {
+ AftRows = n;
+ return RC_FX;
+ } else
+ AftRows += n;
+
+ return RC_OK;
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for ODBC access method. */
+/***********************************************************************/
+int TDBODBC::DeleteDB(PGLOBAL g, int irc)
+{
+ if (irc == RC_FX) {
+ if (!Query && MakeCommand(g))
+ return RC_FX;
+
+ // Send the DELETE (all) command to the remote table
+ if (!Ocp->ExecSQLcommand(Query->GetStr())) {
+ sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
+
+ if (trace(1))
+ htrc("%s\n", g->Message);
+
+ PushWarning(g, this, 0); // 0 means a Note
+ return RC_OK; // This is a delete all
+ } else
+ return RC_FX; // Error
+
+ } else
+ return RC_OK; // Ignore
+
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for ODBC access method. */
+/***********************************************************************/
+void TDBODBC::CloseDB(PGLOBAL g)
+{
+ if (Ocp)
+
+ Ocp->Close();
+
+ if (trace(1))
+ htrc("ODBC CloseDB: closing %s\n", Name);
+
+} // end of CloseDB
+
+/* --------------------------- ODBCCOL ------------------------------- */
+
+/***********************************************************************/
+/* ODBCCOL public constructor. */
+/***********************************************************************/
+ODBCCOL::ODBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : EXTCOL(cdp, tdbp, cprec, i, am)
+{
+ // Set additional ODBC access method information for column.
+ Slen = 0;
+ StrLen = &Slen;
+ Sqlbuf = NULL;
+} // end of ODBCCOL constructor
+
+/***********************************************************************/
+/* ODBCCOL private constructor. */
+/***********************************************************************/
+ODBCCOL::ODBCCOL(void) : EXTCOL()
+{
+ Slen = 0;
+ StrLen = &Slen;
+ Sqlbuf = NULL;
+} // end of ODBCCOL constructor
+
+/***********************************************************************/
+/* ODBCCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+ODBCCOL::ODBCCOL(ODBCCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
+{
+ Slen = col1->Slen;
+ StrLen = col1->StrLen;
+ Sqlbuf = col1->Sqlbuf;
+} // end of ODBCCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: when SQLFetch is used there is nothing to do as the */
+/* column buffer was bind to the record set. This is also the case */
+/* when calculating MaxSize (Bufp is NULL even when Rows is not). */
+/***********************************************************************/
+void ODBCCOL::ReadColumn(PGLOBAL g)
+{
+ PTDBODBC tdbp = (PTDBODBC)To_Tdb;
+ int i = tdbp->Fpos - 1, n = tdbp->CurNum;
+
+ if (tdbp->Memory == 3) {
+ // Get the value from the stored memory
+ if (Crp->Nulls && Crp->Nulls[i] == '*') {
+ Value->Reset();
+ Value->SetNull(true);
+ } else {
+ Value->SetValue_pvblk(Crp->Kdata, i);
+ Value->SetNull(false);
+ } // endif Nulls
+
+ return;
+ } // endif Memory
+
+ if (StrLen[n] == SQL_NULL_DATA) {
+ // Null value
+ if (Nullable)
+ Value->SetNull(true);
+
+ Value->Reset();
+ goto put;
+ } else
+ Value->SetNull(false);
+
+ if (Bufp && tdbp->Rows) {
+ if (Buf_Type == TYPE_DATE)
+ *Sqlbuf = ((TIMESTAMP_STRUCT*)Bufp)[n];
+ else
+ Value->SetValue_pvblk(Blkp, n);
+
+ } // endif Bufp
+
+ if (Buf_Type == TYPE_DATE) {
+ struct tm dbtime;
+
+ memset(&dbtime, 0, sizeof(tm));
+ dbtime.tm_sec = (int)Sqlbuf->second;
+ dbtime.tm_min = (int)Sqlbuf->minute;
+ dbtime.tm_hour = (int)Sqlbuf->hour;
+ dbtime.tm_mday = (int)Sqlbuf->day;
+ dbtime.tm_mon = (int)Sqlbuf->month - 1;
+ dbtime.tm_year = (int)Sqlbuf->year - 1900;
+ ((DTVAL*)Value)->MakeTime(&dbtime);
+ } else if (Buf_Type == TYPE_DECIM && tdbp->Sep) {
+ // Be sure to use decimal point
+ char *p = strchr(Value->GetCharValue(), tdbp->Sep);
+
+ if (p)
+ *p = '.';
+
+ } // endif Buf_Type
+
+ if (trace(2)) {
+ char buf[64];
+
+ htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n",
+ Name, tdbp->Rows, Bufp, Buf_Type, Value->GetCharString(buf));
+ } // endif trace
+
+ put:
+ if (tdbp->Memory != 2)
+ return;
+
+ /*********************************************************************/
+ /* Fill the allocated result structure. */
+ /*********************************************************************/
+ if (Value->IsNull()) {
+ if (Crp->Nulls)
+ Crp->Nulls[i] = '*'; // Null value
+
+ Crp->Kdata->Reset(i);
+ } else
+ Crp->Kdata->SetValue(Value, i);
+
+} // end of ReadColumn
+
+/***********************************************************************/
+/* AllocateBuffers: allocate the extended buffer for SQLExtendedFetch */
+/* or Fetch. Note: we use Long+1 here because ODBC must have space */
+/* for the ending null character. */
+/***********************************************************************/
+void ODBCCOL::AllocateBuffers(PGLOBAL g, int rows)
+{
+ if (Buf_Type == TYPE_DATE)
+ Sqlbuf = (TIMESTAMP_STRUCT*)PlugSubAlloc(g, NULL,
+ sizeof(TIMESTAMP_STRUCT));
+
+ if (!rows)
+ return;
+
+ if (Buf_Type == TYPE_DATE)
+ Bufp = PlugSubAlloc(g, NULL, rows * sizeof(TIMESTAMP_STRUCT));
+ else {
+ Blkp = AllocValBlock(g, NULL, Buf_Type, rows, GetBuflen(),
+ GetScale(), true, false, false);
+ Bufp = Blkp->GetValPointer();
+ } // endelse
+
+ if (rows > 1)
+ StrLen = (SQLLEN *)PlugSubAlloc(g, NULL, rows * sizeof(SQLLEN));
+
+} // end of AllocateBuffers
+
+/***********************************************************************/
+/* Returns the buffer to use for Fetch or Extended Fetch. */
+/***********************************************************************/
+void *ODBCCOL::GetBuffer(DWORD rows)
+{
+ if (rows && To_Tdb) {
+ assert(rows == (DWORD)((TDBODBC*)To_Tdb)->Rows);
+ return Bufp;
+ } else
+ return (Buf_Type == TYPE_DATE) ? Sqlbuf : Value->GetTo_Val();
+
+} // end of GetBuffer
+
+/***********************************************************************/
+/* Returns the buffer length to use for Fetch or Extended Fetch. */
+/***********************************************************************/
+SWORD ODBCCOL::GetBuflen(void)
+{
+ SWORD flen;
+
+ switch (Buf_Type) {
+ case TYPE_DATE:
+ flen = (SWORD)sizeof(TIMESTAMP_STRUCT);
+ break;
+ case TYPE_STRING:
+ case TYPE_DECIM:
+ flen = (SWORD)Value->GetClen() + 1;
+ break;
+ default:
+ flen = (SWORD)Value->GetClen();
+ } // endswitch Buf_Type
+
+ return flen;
+} // end of GetBuflen
+
+/***********************************************************************/
+/* WriteColumn: make sure the bind buffer is updated. */
+/***********************************************************************/
+void ODBCCOL::WriteColumn(PGLOBAL g)
+{
+ /*********************************************************************/
+ /* Do convert the column value if necessary. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value
+
+ if (Buf_Type == TYPE_DATE) {
+ struct tm tm, *dbtime = ((DTVAL*)Value)->GetGmTime(&tm);
+
+ Sqlbuf->second = dbtime->tm_sec;
+ Sqlbuf->minute = dbtime->tm_min;
+ Sqlbuf->hour = dbtime->tm_hour;
+ Sqlbuf->day = dbtime->tm_mday;
+ Sqlbuf->month = dbtime->tm_mon + 1;
+ Sqlbuf->year = dbtime->tm_year + 1900;
+ Sqlbuf->fraction = 0;
+ } else if (Buf_Type == TYPE_DECIM) {
+ // Some data sources require local decimal separator
+ char *p, sep = ((PTDBODBC)To_Tdb)->Sep;
+
+ if (sep && (p = strchr(Value->GetCharValue(), '.')))
+ *p = sep;
+
+ } // endif Buf_Type
+
+ if (Nullable)
+ *StrLen = (Value->IsNull()) ? SQL_NULL_DATA :
+ (IsTypeChar(Buf_Type)) ? SQL_NTS : 0;
+
+} // end of WriteColumn
+
+/* -------------------------- Class TDBXDBC -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBXDBC class. */
+/***********************************************************************/
+TDBXDBC::TDBXDBC(PODEF tdp) : TDBODBC(tdp)
+{
+ Cmdlist = NULL;
+ Cmdcol = NULL;
+ Mxr = tdp->Maxerr;
+ Nerr = 0;
+} // end of TDBXDBC constructor
+
+TDBXDBC::TDBXDBC(PTDBXDBC tdbp) : TDBODBC(tdbp)
+{
+ Cmdlist = tdbp->Cmdlist;
+ Cmdcol = tdbp->Cmdcol;
+ Mxr = tdbp->Mxr;
+ Nerr = tdbp->Nerr;
+} // end of TDBXDBC copy constructor
+
+PTDB TDBXDBC::Clone(PTABS t)
+{
+ PTDB tp;
+ PXSRCCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBXDBC(this);
+
+ for (cp1 = (PXSRCCOL)Columns; cp1; cp1 = (PXSRCCOL)cp1->GetNext()) {
+ cp2 = new(g) XSRCCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+} // end of CopyOne
+
+/***********************************************************************/
+/* Allocate XSRC column description block. */
+/***********************************************************************/
+PCOL TDBXDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ PXSRCCOL colp = new(g) XSRCCOL(cdp, this, cprec, n);
+
+ if (!colp->Flag)
+ Cmdcol = colp->GetName();
+
+ return colp;
+} // end of MakeCol
+
+/***********************************************************************/
+/* MakeCMD: make the SQL statement to send to ODBC connection. */
+/***********************************************************************/
+PCMD TDBXDBC::MakeCMD(PGLOBAL g)
+{
+ PCMD xcmd = NULL;
+
+ if (To_CondFil) {
+ if (Cmdcol) {
+ if (!stricmp(Cmdcol, To_CondFil->Body) &&
+ (To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
+ xcmd = To_CondFil->Cmds;
+ } else
+ strcpy(g->Message, "Invalid command specification filter");
+
+ } else
+ strcpy(g->Message, "No command column in select list");
+
+ } else if (!Srcdef)
+ strcpy(g->Message, "No Srcdef default command");
+ else
+ xcmd = new(g) CMD(g, Srcdef);
+
+ return xcmd;
+} // end of MakeCMD
+
+#if 0
+/***********************************************************************/
+/* ODBC Bind Parameter function. */
+/***********************************************************************/
+bool TDBXDBC::BindParameters(PGLOBAL g)
+{
+ PODBCCOL colp;
+
+ for (colp = (PODBCCOL)Columns; colp; colp = (PODBCCOL)colp->Next) {
+ colp->AllocateBuffers(g, 0);
+
+ if (Ocp->BindParam(colp))
+ return true;
+
+ } // endfor colp
+
+ return false;
+} // end of BindParameters
+#endif // 0
+
+/***********************************************************************/
+/* XDBC GetMaxSize: returns table size (not always one row). */
+/***********************************************************************/
+int TDBXDBC::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = 10; // Just a guess
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* ODBC Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool TDBXDBC::OpenDB(PGLOBAL g)
+{
+ if (trace(1))
+ htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
+ this, Tdb_No, Use, Mode);
+
+ if (Use == USE_OPEN) {
+ strcpy(g->Message, "Multiple execution is not allowed");
+ return true;
+ } // endif use
+
+ /*********************************************************************/
+ /* Open an ODBC connection for this table. */
+ /* Note: this may not be the proper way to do. Perhaps it is better */
+ /* to test whether a connection is already open for this datasource */
+ /* and if so to allocate just a new result set. But this only for */
+ /* drivers allowing concurency in getting results ??? */
+ /*********************************************************************/
+ if (!Ocp) {
+ Ocp = new(g) ODBConn(g, this);
+ } else if (Ocp->IsOpen())
+ Ocp->Close();
+
+ if (Ocp->Open(Connect, &Ops, Options) < 1)
+ return true;
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ if (Mode != MODE_READ && Mode != MODE_READX) {
+ strcpy(g->Message, "No INSERT/DELETE/UPDATE of XDBC tables");
+ return true;
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Get the command to execute. */
+ /*********************************************************************/
+ if (!(Cmdlist = MakeCMD(g))) {
+ // Next lines commented out because of CHECK TABLE
+ //Ocp->Close();
+ //return true;
+ } // endif Cmdlist
+
+ Rows = 1;
+ return false;
+} // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for xdbc access method. */
+/***********************************************************************/
+int TDBXDBC::ReadDB(PGLOBAL g)
+{
+ if (Cmdlist) {
+ if (!Query)
+ Query = new(g)STRING(g, 0, Cmdlist->Cmd);
+ else
+ Query->Set(Cmdlist->Cmd);
+
+ if (Ocp->ExecSQLcommand(Query->GetStr()))
+ Nerr++;
+
+ Fpos++; // Used for progress info
+ Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next;
+ return RC_OK;
+ } else {
+ PushWarning(g, this, 1);
+ return RC_EF;
+ } // endif Cmdlist
+
+} // end of ReadDB
+
+/***********************************************************************/
+/* Data Base write line routine for XDBC access method. */
+/***********************************************************************/
+int TDBXDBC::WriteDB(PGLOBAL g)
+{
+ strcpy(g->Message, "Execsrc tables are read only");
+ return RC_FX;
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for XDBC access method. */
+/***********************************************************************/
+int TDBXDBC::DeleteDB(PGLOBAL g, int irc)
+{
+ strcpy(g->Message, MSG(NO_ODBC_DELETE));
+ return RC_FX;
+} // end of DeleteDB
+
+/* --------------------------- XSRCCOL ------------------------------- */
+
+/***********************************************************************/
+/* XSRCCOL public constructor. */
+/***********************************************************************/
+XSRCCOL::XSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : ODBCCOL(cdp, tdbp, cprec, i, am)
+{
+ // Set additional ODBC access method information for column.
+ Flag = cdp->GetOffset();
+} // end of XSRCCOL constructor
+
+/***********************************************************************/
+/* XSRCCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+XSRCCOL::XSRCCOL(XSRCCOL *col1, PTDB tdbp) : ODBCCOL(col1, tdbp)
+{
+ Flag = col1->Flag;
+} // end of XSRCCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: set column value according to Flag. */
+/***********************************************************************/
+void XSRCCOL::ReadColumn(PGLOBAL g)
+{
+ PTDBXDBC tdbp = (PTDBXDBC)To_Tdb;
+
+ switch (Flag) {
+ case 0: Value->SetValue_psz(tdbp->Query->GetStr()); break;
+ case 1: Value->SetValue(tdbp->AftRows); break;
+ case 2: Value->SetValue_psz(g->Message); break;
+ default: Value->SetValue_psz("Invalid Flag"); break;
+ } // endswitch Flag
+
+} // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: Should never be called. */
+/***********************************************************************/
+void XSRCCOL::WriteColumn(PGLOBAL g)
+{
+ // Should never be called
+} // end of WriteColumn
+
+/* ---------------------------TDBDRV class --------------------------- */
+
+/***********************************************************************/
+/* GetResult: Get the list of ODBC drivers. */
+/***********************************************************************/
+PQRYRES TDBDRV::GetResult(PGLOBAL g)
+{
+ return ODBCDrivers(g, Maxres, false);
+} // end of GetResult
+
+/* ---------------------------TDBSRC class --------------------------- */
+
+/***********************************************************************/
+/* GetResult: Get the list of ODBC data sources. */
+/***********************************************************************/
+PQRYRES TDBSRC::GetResult(PGLOBAL g)
+{
+ return ODBCDataSources(g, Maxres, false);
+} // end of GetResult
+
+/* ---------------------------TDBOTB class --------------------------- */
+
+/***********************************************************************/
+/* TDBOTB class constructor. */
+/***********************************************************************/
+TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
+{
+ Dsn = tdp->GetConnect();
+ Schema = tdp->GetTabschema();
+ Tab = tdp->GetTabname();
+ Tabtyp = tdp->Tabtyp;
+ Ops.User = tdp->Username;
+ Ops.Pwd = tdp->Password;
+ Ops.Cto = tdp->Cto;
+ Ops.Qto = tdp->Qto;
+ Ops.UseCnc = tdp->UseCnc;
+} // end of TDBOTB constructor
+
+/***********************************************************************/
+/* GetResult: Get the list of ODBC tables. */
+/***********************************************************************/
+PQRYRES TDBOTB::GetResult(PGLOBAL g)
+{
+ return ODBCTables(g, Dsn, Schema, Tab, Tabtyp, Maxres, false, &Ops);
+} // end of GetResult
+
+/* ---------------------------TDBOCL class --------------------------- */
+
+/***********************************************************************/
+/* TDBOCL class constructor. */
+/***********************************************************************/
+TDBOCL::TDBOCL(PODEF tdp) : TDBOTB(tdp)
+{
+ Colpat = tdp->Colpat;
+} // end of TDBOTB constructor
+
+/***********************************************************************/
+/* GetResult: Get the list of ODBC table columns. */
+/***********************************************************************/
+PQRYRES TDBOCL::GetResult(PGLOBAL g)
+{
+ return ODBCColumns(g, Dsn, Schema, Tab, Colpat, Maxres, false, &Ops);
+} // end of GetResult
+
+/* ------------------------ End of Tabodbc --------------------------- */
diff --git a/storage/connect/tabodbc.h b/storage/connect/tabodbc.h
new file mode 100644
index 00000000..cedcf0f5
--- /dev/null
+++ b/storage/connect/tabodbc.h
@@ -0,0 +1,264 @@
+/*************** Tabodbc H Declares Source Code File (.H) **************/
+/* Name: TABODBC.H Version 1.9 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2000-2017 */
+/* */
+/* This file contains the TDBODBC classes declares. */
+/***********************************************************************/
+#include "colblk.h"
+#include "resource.h"
+
+typedef class ODBCDEF *PODEF;
+typedef class TDBODBC *PTDBODBC;
+typedef class ODBCCOL *PODBCCOL;
+typedef class TDBXDBC *PTDBXDBC;
+typedef class XSRCCOL *PXSRCCOL;
+typedef class TDBOIF *PTDBOIF;
+typedef class OIFCOL *POIFCOL;
+typedef class TDBSRC *PTDBSRC;
+
+/***********************************************************************/
+/* ODBC table. */
+/***********************************************************************/
+class DllExport ODBCDEF : public EXTDEF { /* Logical table description */
+ friend class TDBODBC;
+ friend class TDBXDBC;
+ friend class TDBDRV;
+ friend class TDBOTB;
+ friend class TDBOCL;
+public:
+ // Constructor
+ ODBCDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "ODBC";}
+ PSZ GetConnect(void) {return Connect;}
+ int GetCatver(void) {return Catver;}
+
+ // Methods
+ virtual int Indexable(void) {return 2;}
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ PSZ Connect; /* ODBC connection string */
+ int Catver; /* ODBC version for catalog functions */
+ bool UseCnc; /* Use SQLConnect (!SQLDriverConnect) */
+ }; // end of ODBCDEF
+
+#if !defined(NODBC)
+#include "odbconn.h"
+
+/***********************************************************************/
+/* This is the ODBC Access Method class declaration for files from */
+/* other DB drivers to be accessed via ODBC. */
+/***********************************************************************/
+class TDBODBC : public TDBEXT {
+ friend class ODBCCOL;
+ friend class ODBConn;
+ public:
+ // Constructor
+ TDBODBC(PODEF tdp = NULL);
+ TDBODBC(PTDBODBC tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_ODBC;}
+ virtual PTDB Duplicate(PGLOBAL g)
+ {return (PTDB)new(g) TDBODBC(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual bool SetRecpos(PGLOBAL g, int recpos);
+ virtual PCSZ GetFile(PGLOBAL g);
+ virtual void SetFile(PGLOBAL g, PCSZ fn);
+ virtual void ResetSize(void);
+ virtual PCSZ GetServer(void) {return "ODBC";}
+ virtual int Indexable(void) {return 2;}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ virtual bool ReadKey(PGLOBAL g, OPVAL op, const key_range *kr);
+
+ protected:
+ // Internal functions
+ bool MakeInsert(PGLOBAL g);
+ bool BindParameters(PGLOBAL g);
+
+ // Members
+ ODBConn *Ocp; // Points to an ODBC connection class
+ ODBCCOL *Cnp; // Points to count(*) column
+ ODBCPARM Ops; // Additional parameters
+ char *Connect; // Points to connection string
+ int Catver; // Catalog ODBC version
+ bool UseCnc; // Use SQLConnect (!SQLDriverConnect)
+ }; // end of class TDBODBC
+
+/***********************************************************************/
+/* Class ODBCCOL: ODBC access method column descriptor. */
+/* This A.M. is used for ODBC tables. */
+/***********************************************************************/
+class ODBCCOL : public EXTCOL {
+ friend class TDBODBC;
+ public:
+ // Constructors
+ ODBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "ODBC");
+ ODBCCOL(ODBCCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_ODBC;}
+ SQLLEN *GetStrLen(void) {return StrLen;}
+
+ // Methods
+//virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ void AllocateBuffers(PGLOBAL g, int rows);
+ void *GetBuffer(DWORD rows);
+ SWORD GetBuflen(void);
+
+ protected:
+ // Constructor for count(*) column
+ ODBCCOL(void);
+
+ // Members
+ TIMESTAMP_STRUCT *Sqlbuf; // To get SQL_TIMESTAMP's
+ SQLLEN *StrLen; // As returned by ODBC
+ SQLLEN Slen; // Used with Fetch
+ }; // end of class ODBCCOL
+
+/***********************************************************************/
+/* This is the ODBC Access Method class declaration that send */
+/* commands to be executed by other DB ODBC drivers. */
+/***********************************************************************/
+class TDBXDBC : public TDBODBC {
+ friend class XSRCCOL;
+ friend class ODBConn;
+ public:
+ // Constructors
+ TDBXDBC(PODEF tdp = NULL);
+ TDBXDBC(PTDBXDBC tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_XDBC;}
+ virtual PTDB Duplicate(PGLOBAL g)
+ {return (PTDB)new(g) TDBXDBC(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+
+ protected:
+ // Internal functions
+ PCMD MakeCMD(PGLOBAL g);
+
+ // Members
+ PCMD Cmdlist; // The commands to execute
+ char *Cmdcol; // The name of the Xsrc command column
+ int Mxr; // Maximum errors before closing
+ int Nerr; // Number of errors so far
+ }; // end of class TDBXDBC
+
+/***********************************************************************/
+/* Used by table in source execute mode. */
+/***********************************************************************/
+class XSRCCOL : public ODBCCOL {
+ friend class TDBXDBC;
+ public:
+ // Constructors
+ XSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "ODBC");
+ XSRCCOL(XSRCCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+ protected:
+ // Members
+ char *Buffer; // To get returned message
+ int Flag; // Column content desc
+ }; // end of class XSRCCOL
+
+/***********************************************************************/
+/* This is the class declaration for the Drivers catalog table. */
+/***********************************************************************/
+class TDBDRV : public TDBCAT {
+ public:
+ // Constructor
+ TDBDRV(PODEF tdp) : TDBCAT(tdp) {Maxres = tdp->Maxres;}
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ int Maxres; // Returned lines limit
+ }; // end of class TDBDRV
+
+/***********************************************************************/
+/* This is the class declaration for the Data Sources catalog table. */
+/***********************************************************************/
+class TDBSRC : public TDBDRV {
+ public:
+ // Constructor
+ TDBSRC(PODEF tdp) : TDBDRV(tdp) {}
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // No additional Members
+ }; // end of class TDBSRC
+
+/***********************************************************************/
+/* This is the class declaration for the tables catalog table. */
+/***********************************************************************/
+class TDBOTB : public TDBDRV {
+ public:
+ // Constructor
+ TDBOTB(PODEF tdp);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PCSZ Dsn; // Points to connection string
+ PCSZ Schema; // Points to schema name or NULL
+ PCSZ Tab; // Points to ODBC table name or pattern
+ PCSZ Tabtyp; // Points to ODBC table type
+ ODBCPARM Ops; // Additional parameters
+ }; // end of class TDBOTB
+
+/***********************************************************************/
+/* This is the class declaration for the columns catalog table. */
+/***********************************************************************/
+class TDBOCL : public TDBOTB {
+ public:
+ // Constructor
+ TDBOCL(PODEF tdp);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ char *Colpat; // Points to column pattern
+ }; // end of class TDBOCL
+
+#endif // !NODBC
diff --git a/storage/connect/tabpivot.cpp b/storage/connect/tabpivot.cpp
new file mode 100644
index 00000000..5ba4b511
--- /dev/null
+++ b/storage/connect/tabpivot.cpp
@@ -0,0 +1,912 @@
+/************ TabPivot C++ Program Source Code File (.CPP) *************/
+/* PROGRAM NAME: TABPIVOT */
+/* ------------- */
+/* Version 1.7 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2017 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the PIVOT classes DB execution routines. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the operating system header file. */
+/***********************************************************************/
+#include "my_global.h"
+#include "table.h" // MySQL table definitions
+#if defined(_WIN32)
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#elif defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#include "osutil.h"
+#else
+#include <io.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/***********************************************************************/
+#define FRM_VER 6
+#include "sql_const.h"
+#include "field.h"
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "tabcol.h"
+#include "colblk.h"
+#include "tabmysql.h"
+#include "csort.h"
+#include "tabutil.h"
+#include "tabpivot.h"
+#include "valblk.h"
+#include "ha_connect.h"
+
+/***********************************************************************/
+/* Make the Pivot table column list. */
+/***********************************************************************/
+PQRYRES PivotColumns(PGLOBAL g, const char *tab, const char *src,
+ const char *picol, const char *fncol,
+ const char *skcol, const char *host,
+ const char *db, const char *user,
+ const char *pwd, int port)
+ {
+ PIVAID pvd(tab, src, picol, fncol, skcol, host, db, user, pwd, port);
+
+ return pvd.MakePivotColumns(g);
+ } // end of PivotColumns
+
+/* --------------- Implementation of the PIVAID classe --------------- */
+
+/***********************************************************************/
+/* PIVAID constructor. */
+/***********************************************************************/
+PIVAID::PIVAID(const char *tab, const char *src, const char *picol,
+ const char *fncol, const char *skcol, const char *host,
+ const char *db, const char *user, const char *pwd,
+ int port) : CSORT(false)
+ {
+ Host = (char*)host;
+ User = (char*)user;
+ Pwd = (char*)pwd;
+ Qryp = NULL;
+ Database = (char*)db;
+ Tabname = (char*)tab;
+ Tabsrc = (char*)src;
+ Picol = (char*)picol;
+ Fncol = (char*)fncol;
+ Skcol = (char*)skcol;
+ Rblkp = NULL;
+ Port = (port) ? port : GetDefaultPort();
+ } // end of PIVAID constructor
+
+/***********************************************************************/
+/* Skip columns that are in the skipped column list. */
+/***********************************************************************/
+bool PIVAID::SkipColumn(PCOLRES crp, char *skc)
+ {
+ if (skc)
+ for (char *p = skc; *p; p += (strlen(p) + 1))
+ if (!stricmp(crp->Name, p))
+ return true;
+
+ return false;
+ } // end of SkipColumn
+
+/***********************************************************************/
+/* Make the Pivot table column list. */
+/***********************************************************************/
+PQRYRES PIVAID::MakePivotColumns(PGLOBAL g)
+{
+ char *p, *query, *colname, *skc, buf[64];
+ int ndif, nblin, w = 0;
+ bool b = false;
+ PVAL valp;
+ PQRYRES qrp;
+ PCOLRES *pcrp, crp, fncrp = NULL;
+
+ try {
+ // Are there columns to skip?
+ if (Skcol) {
+ uint n = strlen(Skcol);
+
+ skc = (char*)PlugSubAlloc(g, NULL, n + 2);
+ strcpy(skc, Skcol);
+ skc[n + 1] = 0;
+
+ // Replace ; by nulls in skc
+ for (p = strchr(skc, ';'); p; p = strchr(p, ';'))
+ *p++ = 0;
+
+ } else
+ skc = NULL;
+
+ if (!Tabsrc && Tabname) {
+ // Locate the query
+ query = (char*)PlugSubAlloc(g, NULL, strlen(Tabname) + 26);
+ sprintf(query, "SELECT * FROM `%s` LIMIT 1", Tabname);
+ } else if (!Tabsrc) {
+ strcpy(g->Message, MSG(SRC_TABLE_UNDEF));
+ goto err;
+ } else
+ query = (char*)Tabsrc;
+
+ // Open a MySQL connection for this table
+ if (!Myc.Open(g, Host, Database, User, Pwd, Port)) {
+ b = true;
+
+ // Returned values must be in their original character set
+ if (Myc.ExecSQL(g, "SET character_set_results=NULL", &w) == RC_FX)
+ goto err;
+ else
+ Myc.FreeResult();
+
+ } else
+ goto err;
+
+ // Send the source command to MySQL
+ if (Myc.ExecSQL(g, query, &w) == RC_FX)
+ goto err;
+
+ // We must have a storage query to get pivot column values
+ if (!(Qryp = Myc.GetResult(g, true)))
+ goto err;
+
+ if (!Fncol) {
+ for (crp = Qryp->Colresp; crp; crp = crp->Next)
+ if ((!Picol || stricmp(Picol, crp->Name)) && !SkipColumn(crp, skc))
+ Fncol = crp->Name;
+
+ if (!Fncol) {
+ strcpy(g->Message, MSG(NO_DEF_FNCCOL));
+ goto err;
+ } // endif Fncol
+
+ } // endif Fncol
+
+ if (!Picol) {
+ // Find default Picol as the last one not equal to Fncol
+ for (crp = Qryp->Colresp; crp; crp = crp->Next)
+ if (stricmp(Fncol, crp->Name) && !SkipColumn(crp, skc))
+ Picol = crp->Name;
+
+ if (!Picol) {
+ strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
+ goto err;
+ } // endif Picol
+
+ } // endif picol
+
+ // Prepare the column list
+ for (pcrp = &Qryp->Colresp; (crp = *pcrp); ) {
+ if (SkipColumn(crp, skc)) {
+ // Ignore this column
+ *pcrp = crp->Next;
+ } else if (!stricmp(Picol, crp->Name)) {
+ if (crp->Nulls) {
+ sprintf(g->Message, "Pivot column %s cannot be nullable", Picol);
+ goto err;
+ } // endif Nulls
+
+ Rblkp = crp->Kdata;
+ *pcrp = crp->Next;
+ } else if (!stricmp(Fncol, crp->Name)) {
+ fncrp = crp;
+ *pcrp = crp->Next;
+ } else
+ pcrp = &crp->Next;
+ }
+ if (!Rblkp) {
+ strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
+ goto err;
+ } else if (!fncrp) {
+ strcpy(g->Message, MSG(NO_DEF_FNCCOL));
+ goto err;
+ } // endif
+
+ if (Tabsrc) {
+ Myc.Close();
+ b = false;
+
+ // Before calling sort, initialize all
+ nblin = Qryp->Nblin;
+
+ Index.Size = nblin * sizeof(int);
+ Index.Sub = TRUE; // Should be small enough
+
+ if (!PlgDBalloc(g, NULL, Index))
+ goto err;
+
+ Offset.Size = (nblin + 1) * sizeof(int);
+ Offset.Sub = TRUE; // Should be small enough
+
+ if (!PlgDBalloc(g, NULL, Offset))
+ goto err;
+
+ ndif = Qsort(g, nblin);
+
+ if (ndif < 0) // error
+ goto err;
+
+ } else {
+ // The query was limited, we must get pivot column values
+ // Returned values must be in their original character set
+ // if (Myc.ExecSQL(g, "SET character_set_results=NULL", &w) == RC_FX)
+ // goto err;
+
+ query = (char*)PlugSubAlloc(g, NULL, 0);
+ sprintf(query, "SELECT DISTINCT `%s` FROM `%s`", Picol, Tabname);
+ PlugSubAlloc(g, NULL, strlen(query) + 1);
+ Myc.FreeResult();
+
+ // Send the source command to MySQL
+ if (Myc.ExecSQL(g, query, &w) == RC_FX)
+ goto err;
+
+ // We must have a storage query to get pivot column values
+ if (!(qrp = Myc.GetResult(g, true)))
+ goto err;
+
+ Myc.Close();
+ b = false;
+
+ // Get the column list
+ crp = qrp->Colresp;
+ Rblkp = crp->Kdata;
+ ndif = qrp->Nblin;
+ } // endif Tabsrc
+
+ // Allocate the Value used to retieve column names
+ if (!(valp = AllocateValue(g, Rblkp->GetType(),
+ Rblkp->GetVlen(),
+ Rblkp->GetPrec())))
+ goto err;
+
+ // Now make the functional columns
+ for (int i = 0; i < ndif; i++) {
+ if (i) {
+ crp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
+ memcpy(crp, fncrp, sizeof(COLRES));
+ } else
+ crp = fncrp;
+
+ // Get the value that will be the generated column name
+ if (Tabsrc)
+ valp->SetValue_pvblk(Rblkp, Pex[Pof[i]]);
+ else
+ valp->SetValue_pvblk(Rblkp, i);
+
+ colname = valp->GetCharString(buf);
+ crp->Name = PlugDup(g, colname);
+ crp->Flag = 1;
+
+ // Add this column
+ *pcrp = crp;
+ crp->Next = NULL;
+ pcrp = &crp->Next;
+ } // endfor i
+
+ // We added ndif columns and removed 2 (picol and fncol)
+ Qryp->Nbcol += (ndif - 2);
+ return Qryp;
+ } catch (int n) {
+ if (trace(1))
+ htrc("Exception %d: %s\n", n, g->Message);
+ } catch (const char *msg) {
+ strcpy(g->Message, msg);
+ } // end catch
+
+err:
+ if (b)
+ Myc.Close();
+
+ return NULL;
+} // end of MakePivotColumns
+
+/***********************************************************************/
+/* PIVAID: Compare routine for sorting pivot column values. */
+/***********************************************************************/
+int PIVAID::Qcompare(int *i1, int *i2)
+ {
+ // TODO: the actual comparison between pivot column result values.
+ return Rblkp->CompVal(*i1, *i2);
+ } // end of Qcompare
+
+/* --------------- Implementation of the PIVOT classes --------------- */
+
+/***********************************************************************/
+/* PIVOTDEF constructor. */
+/***********************************************************************/
+ PIVOTDEF::PIVOTDEF(void)
+ {
+ Host = User = Pwd = DB = NULL;
+ Tabname = Tabsrc = Picol = Fncol = Function = NULL;
+ GBdone = Accept = false;
+ Port = 0;
+ } // end of PIVOTDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from PIVOT table. */
+/***********************************************************************/
+bool PIVOTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ char *p1, *p2;
+
+ if (PRXDEF::DefineAM(g, am, poff))
+ return TRUE;
+
+ Tabname = (char*)Tablep->GetName();
+ DB = (char*)Tablep->GetSchema();
+ Tabsrc = (char*)Tablep->GetSrc();
+
+ Host = GetStringCatInfo(g, "Host", "localhost");
+ User = GetStringCatInfo(g, "User", "*");
+ Pwd = GetStringCatInfo(g, "Password", NULL);
+ Picol = GetStringCatInfo(g, "PivotCol", NULL);
+ Fncol = GetStringCatInfo(g, "FncCol", NULL);
+
+ // If fncol is like avg(colname), separate Fncol and Function
+ if (Fncol && (p1 = strchr(Fncol, '(')) && (p2 = strchr(p1, ')')) &&
+ (*Fncol != '"') && (!*(p2+1))) {
+ *p1++ = '\0'; *p2 = '\0';
+ Function = Fncol;
+ Fncol = p1;
+ } else
+ Function = GetStringCatInfo(g, "Function", "SUM");
+
+ GBdone = GetBoolCatInfo("Groupby", false);
+ Accept = GetBoolCatInfo("Accept", false);
+ Port = GetIntCatInfo("Port", 3306);
+ Desc = (Tabsrc) ? Tabsrc : Tabname;
+ return FALSE;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB PIVOTDEF::GetTable(PGLOBAL g, MODE)
+ {
+ return new(g) TDBPIVOT(this);
+ } // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBPIVOT class. */
+/***********************************************************************/
+TDBPIVOT::TDBPIVOT(PPIVOTDEF tdp) : TDBPRX(tdp)
+ {
+ Host = tdp->Host;
+ Database = tdp->DB;
+ User = tdp->User;
+ Pwd = tdp->Pwd;
+ Port = tdp->Port;
+ Tabname = tdp->Tabname; // Name of source table
+ Tabsrc = tdp->Tabsrc; // SQL description of source table
+ Picol = tdp->Picol; // Pivot column name
+ Fncol = tdp->Fncol; // Function column name
+ Function = tdp->Function; // Aggregate function name
+ Xcolp = NULL; // To the FNCCOL column
+//Xresp = NULL; // To the pivot result column
+//Rblkp = NULL; // The value block of the pivot column
+ Fcolp = NULL; // To the function column
+ Dcolp = NULL; // To the dump column
+ GBdone = tdp->GBdone;
+ Accept = tdp->Accept;
+ Mult = -1; // Estimated table size
+ N = 0; // The current table index
+ M = 0; // The occurrence rank
+ FileStatus = 0; // Logical End-of-File
+ RowFlag = 0; // 0: Ok, 1: Same, 2: Skip
+ } // end of TDBPIVOT constructor
+
+/***********************************************************************/
+/* Allocate source column description block. */
+/***********************************************************************/
+PCOL TDBPIVOT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PCOL colp;
+
+ if (cdp->GetOffset()) {
+ colp = new(g) FNCCOL(cdp, this, cprec, n);
+
+ if (cdp->GetOffset() > 1)
+ Dcolp = colp;
+
+ } else
+ colp = new(g) SRCCOL(cdp, this, cprec, n);
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Find default fonction and pivot columns. */
+/***********************************************************************/
+bool TDBPIVOT::FindDefaultColumns(PGLOBAL g)
+ {
+ PCOLDEF cdp;
+ PTABDEF defp = Tdbp->GetDef();
+
+ if (!Fncol) {
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!Picol || stricmp(Picol, cdp->GetName()))
+ Fncol = cdp->GetName();
+
+ if (!Fncol) {
+ strcpy(g->Message, MSG(NO_DEF_FNCCOL));
+ return true;
+ } // endif Fncol
+
+ } // endif Fncol
+
+ if (!Picol) {
+ // Find default Picol as the last one not equal to Fncol
+ for (cdp = defp->GetCols(); cdp; cdp = cdp->GetNext())
+ if (stricmp(Fncol, cdp->GetName()))
+ Picol = cdp->GetName();
+
+ if (!Picol) {
+ strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
+ return true;
+ } // endif Picol
+
+ } // endif Picol
+
+ return false;
+ } // end of FindDefaultColumns
+
+/***********************************************************************/
+/* Prepare the source table Query. */
+/***********************************************************************/
+bool TDBPIVOT::GetSourceTable(PGLOBAL g)
+ {
+ if (Tdbp)
+ return false; // Already done
+
+ if (!Tabsrc && Tabname) {
+ // Get the table description block of this table
+ if (!(Tdbp = GetSubTable(g, ((PPIVOTDEF)To_Def)->Tablep, true)))
+ return true;
+
+ if (!GBdone) {
+ char *colist;
+ PCOLDEF cdp;
+
+ if (FindDefaultColumns(g))
+ return true;
+
+ // Locate the suballocated colist (size is not known yet)
+ *(colist = (char*)PlugSubAlloc(g, NULL, 0)) = 0;
+
+ // Make the column list
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext())
+ if (!cdp->GetOffset())
+ strcat(strcat(colist, cdp->GetName()), ", ");
+
+ // Add the Pivot column at the end of the list
+ strcat(colist, Picol);
+
+ // Now we know how much was suballocated
+ PlugSubAlloc(g, NULL, strlen(colist) + 1);
+
+ // Locate the source string (size is not known yet)
+ Tabsrc = (char*)PlugSubAlloc(g, NULL, 0);
+
+ // Start making the definition
+ strcat(strcat(strcpy(Tabsrc, "SELECT "), colist), ", ");
+
+ // Make it suitable for Pivot by doing the group by
+ strcat(strcat(Tabsrc, Function), "(");
+ strcat(strcat(strcat(Tabsrc, Fncol), ") "), Fncol);
+ strcat(strcat(Tabsrc, " FROM "), Tabname);
+ strcat(strcat(Tabsrc, " GROUP BY "), colist);
+
+ if (Tdbp->IsView()) // Until MariaDB bug is fixed
+ strcat(strcat(Tabsrc, " ORDER BY "), colist);
+
+ // Now we know how much was suballocated
+ PlugSubAlloc(g, NULL, strlen(Tabsrc) + 1);
+ } // endif !GBdone
+
+ } else if (!Tabsrc) {
+ strcpy(g->Message, MSG(SRC_TABLE_UNDEF));
+ return true;
+ } // endif
+
+ if (Tabsrc) {
+ // Get the new table description block of this source table
+ PTABLE tablep = new(g) XTAB("whatever", Tabsrc);
+
+ tablep->SetSchema(Database);
+
+ if (!(Tdbp = GetSubTable(g, tablep, true)))
+ return true;
+
+ } // endif Tabsrc
+
+ return false;
+ } // end of GetSourceTable
+
+/***********************************************************************/
+/* Make the required pivot columns. */
+/***********************************************************************/
+bool TDBPIVOT::MakePivotColumns(PGLOBAL g)
+ {
+ if (!Tdbp->IsView()) {
+ // This was not done yet if GBdone is true
+ if (FindDefaultColumns(g))
+ return true;
+
+ // Now it is time to allocate the pivot and function columns
+ if (!(Fcolp = Tdbp->ColDB(g, Fncol, 0))) {
+ // Function column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), Fncol, Tabname);
+ return true;
+ } else if (Fcolp->InitValue(g))
+ return true;
+
+ if (!(Xcolp = Tdbp->ColDB(g, Picol, 0))) {
+ // Pivot column not found in table
+ sprintf(g->Message, MSG(COL_ISNOT_TABLE), Picol, Tabname);
+ return true;
+ } else if (Xcolp->InitValue(g))
+ return true;
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_SRC) {
+ if (((PSRCCOL)cp)->Init(g, NULL))
+ return TRUE;
+
+ } else if (cp->GetAmType() == TYPE_AM_FNC)
+ if (((PFNCCOL)cp)->InitColumn(g))
+ return TRUE;
+
+ } // endif isview
+
+ return false;
+ } // end of MakePivotColumns
+
+/***********************************************************************/
+/* Make the required pivot columns for an object view. */
+/***********************************************************************/
+bool TDBPIVOT::MakeViewColumns(PGLOBAL g)
+ {
+ if (Tdbp->IsView()) {
+ // Tdbp is a view ColDB cannot be used
+ PCOL colp, cp;
+ PTDBMY tdbp;
+
+ if (Tdbp->GetAmType() != TYPE_AM_MYSQL) {
+ strcpy(g->Message, "View is not MySQL");
+ return true;
+ } else
+ tdbp = (PTDBMY)Tdbp;
+
+ if (!Fncol && !(Fncol = tdbp->FindFieldColumn(Picol))) {
+ strcpy(g->Message, MSG(NO_DEF_FNCCOL));
+ return true;
+ } // endif Fncol
+
+ if (!Picol && !(Picol = tdbp->FindFieldColumn(Fncol))) {
+ strcpy(g->Message, MSG(NO_DEF_PIVOTCOL));
+ return true;
+ } // endif Picol
+
+ // Now it is time to allocate the pivot and function columns
+ if (!(Fcolp = tdbp->MakeFieldColumn(g, Fncol)))
+ return true;
+
+ if (!(Xcolp = tdbp->MakeFieldColumn(g, Picol)))
+ return true;
+
+ // Check and initialize the subtable columns
+ for (cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_SRC) {
+ if ((colp = tdbp->MakeFieldColumn(g, cp->GetName()))) {
+ ((PSRCCOL)cp)->Colp = colp;
+ ((PSRCCOL)cp)->To_Val = colp->GetValue();
+ cp->AddStatus(BUF_READ); // All is done here
+ } else
+ return true;
+
+ } else if (cp->GetAmType() == TYPE_AM_FNC)
+ if (((PFNCCOL)cp)->InitColumn(g))
+ return TRUE;
+
+ } // endif isview
+
+ return false;
+ } // end of MakeViewColumns
+
+/***********************************************************************/
+/* PIVOT GetMaxSize: returns the maximum number of rows in the table. */
+/***********************************************************************/
+int TDBPIVOT::GetMaxSize(PGLOBAL g __attribute__((unused)))
+ {
+#if 0
+ if (MaxSize < 0)
+ MaxSize = MakePivotColumns(g);
+
+ return MaxSize;
+#endif // 0
+ return 10;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* In this sample, ROWID will be the (virtual) row number, */
+/* while ROWNUM will be the occurrence rank in the multiple column. */
+/***********************************************************************/
+int TDBPIVOT::RowNumber(PGLOBAL, bool b)
+ {
+ return (b) ? M : N;
+ } // end of RowNumber
+
+/***********************************************************************/
+/* PIVOT Access Method opening routine. */
+/***********************************************************************/
+bool TDBPIVOT::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ N = M = 0;
+ RowFlag = 0;
+ FileStatus = 0;
+ return FALSE;
+ } // endif use
+
+ if (Mode != MODE_READ) {
+ /*******************************************************************/
+ /* Currently PIVOT tables cannot be modified. */
+ /*******************************************************************/
+ sprintf(g->Message, MSG(TABLE_READ_ONLY), "PIVOT");
+ return TRUE;
+ } // endif Mode
+
+ if (To_Key_Col || To_Kindex) {
+ /*******************************************************************/
+ /* Direct access of PIVOT tables is not implemented yet. */
+ /*******************************************************************/
+ strcpy(g->Message, MSG(NO_PIV_DIR_ACC));
+ return TRUE;
+ } // endif To_Key_Col
+
+ /*********************************************************************/
+ /* Do it here if not done yet (should not be the case). */
+ /*********************************************************************/
+ if (GetSourceTable(g))
+ return TRUE;
+
+ // For tables, columns must be allocated before opening
+ if (MakePivotColumns(g))
+ return TRUE;
+
+ /*********************************************************************/
+ /* Physically open the object table. */
+ /*********************************************************************/
+ if (Tdbp->OpenDB(g))
+ return TRUE;
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Make all required pivot columns for object views. */
+ /*********************************************************************/
+ return MakeViewColumns(g);
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for PIVOT access method. */
+/***********************************************************************/
+int TDBPIVOT::ReadDB(PGLOBAL g)
+ {
+ int rc = RC_OK;
+ bool newrow = FALSE;
+ PCOL colp;
+
+ if (FileStatus == 2)
+ return RC_EF;
+
+ if (FileStatus)
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_SRC)
+ ((PSRCCOL)colp)->SetColumn();
+
+ // New row, reset all function column values
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_FNC)
+ colp->GetValue()->Reset();
+
+ /*********************************************************************/
+ /* Now start the multi reading process. */
+ /*********************************************************************/
+ do {
+ if (RowFlag != 1) {
+ if ((rc = Tdbp->ReadDB(g)) != RC_OK) {
+ if (FileStatus && rc == RC_EF) {
+ // A prepared row remains to be sent
+ FileStatus = 2;
+ rc = RC_OK;
+ } // endif FileStatus
+
+ break;
+ } // endif rc
+
+ for (colp = Tdbp->GetColumns(); colp; colp = colp->GetNext())
+ colp->ReadColumn(g);
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ {
+ if (colp->GetAmType() == TYPE_AM_SRC)
+ {
+ if (FileStatus) {
+ if (((PSRCCOL)colp)->CompareLast()) {
+ newrow = (RowFlag) ? TRUE : FALSE;
+ break;
+ } // endif CompareLast
+
+ } else
+ ((PSRCCOL)colp)->SetColumn();
+ }
+ }
+ FileStatus = 1;
+ } // endif RowFlag
+
+ if (newrow) {
+ RowFlag = 1;
+ break;
+ } else
+ RowFlag = 2;
+
+ // Look for the column having this header
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_FNC) {
+ if (((PFNCCOL)colp)->CompareColumn())
+ break;
+
+ } // endif AmType
+
+ if (!colp && !(colp = Dcolp)) {
+ if (!Accept) {
+ strcpy(g->Message, MSG(NO_MATCH_COL));
+ return RC_FX;
+ } else
+ continue;
+
+ } // endif colp
+
+ // Set the value of the matching column from the fonction value
+ colp->GetValue()->SetValue_pval(Fcolp->GetValue());
+ } while (RowFlag == 2);
+
+ N++;
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for PIVOT access methods. */
+/***********************************************************************/
+int TDBPIVOT::WriteDB(PGLOBAL g)
+ {
+ sprintf(g->Message, MSG(TABLE_READ_ONLY), "PIVOT");
+ return RC_FX;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for PIVOT access methods. */
+/***********************************************************************/
+int TDBPIVOT::DeleteDB(PGLOBAL g, int)
+ {
+ sprintf(g->Message, MSG(NO_TABLE_DEL), "PIVOT");
+ return RC_FX;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for PIVOT access method. */
+/***********************************************************************/
+void TDBPIVOT::CloseDB(PGLOBAL g)
+ {
+ if (Tdbp)
+ Tdbp->CloseDB(g);
+
+ } // end of CloseDB
+
+// ------------------------ FNCCOL functions ----------------------------
+
+/***********************************************************************/
+/* FNCCOL public constructor. */
+/***********************************************************************/
+FNCCOL::FNCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ Value = NULL; // We'll get a new one later
+ Hval = NULL; // The unconverted header value
+ Xcolp = NULL;
+ } // end of FNCCOL constructor
+
+/***********************************************************************/
+/* FNCCOL initialization function. */
+/***********************************************************************/
+bool FNCCOL::InitColumn(PGLOBAL g)
+{
+ // Must have its own value block
+ if (InitValue(g))
+ return TRUE;
+
+ // Make a value from the column name
+ Hval = AllocateValue(g, Name, TYPE_STRING);
+ Hval->SetPrec(1); // Case insensitive
+
+ Xcolp = ((PTDBPIVOT)To_Tdb)->Xcolp;
+ AddStatus(BUF_READ); // All is done here
+ return FALSE;
+} // end of InitColumn
+
+/***********************************************************************/
+/* CompareColumn: Compare column value with source column value. */
+/***********************************************************************/
+bool FNCCOL::CompareColumn(void)
+ {
+ // Compare the unconverted values
+ return Hval->IsEqual(Xcolp->GetValue(), false);
+ } // end of CompareColumn
+
+// ------------------------ SRCCOL functions ----------------------------
+
+/***********************************************************************/
+/* SRCCOL public constructor. */
+/***********************************************************************/
+SRCCOL::SRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int n)
+ : PRXCOL(cdp, tdbp, cprec, n)
+ {
+ } // end of SRCCOL constructor
+
+/***********************************************************************/
+/* Initialize the column as pointing to the source column. */
+/***********************************************************************/
+bool SRCCOL::Init(PGLOBAL g, PTDB tp)
+ {
+ if (PRXCOL::Init(g, tp))
+ return true;
+
+ AddStatus(BUF_READ); // All is done here
+ return false;
+ } // end of SRCCOL constructor
+
+/***********************************************************************/
+/* SetColumn: have the column value set from the source column. */
+/***********************************************************************/
+void SRCCOL::SetColumn(void)
+ {
+ Value->SetValue_pval(To_Val);
+ } // end of SetColumn
+
+/***********************************************************************/
+/* SetColumn: Compare column value with source column value. */
+/***********************************************************************/
+bool SRCCOL::CompareLast(void)
+ {
+ // Compare the unconverted values
+ return !Value->IsEqual(To_Val, true);
+ } // end of CompareColumn
+
+/* --------------------- End of TabPivot/TabQrs ---------------------- */
diff --git a/storage/connect/tabpivot.h b/storage/connect/tabpivot.h
new file mode 100644
index 00000000..d819d55a
--- /dev/null
+++ b/storage/connect/tabpivot.h
@@ -0,0 +1,200 @@
+/************** TabPivot H Declares Source Code File (.H) **************/
+/* Name: TABPIVOT.H Version 1.5 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2013 */
+/* */
+/* This file contains the PIVOT classes declares. */
+/***********************************************************************/
+typedef class PIVOTDEF *PPIVOTDEF;
+typedef class TDBPIVOT *PTDBPIVOT;
+typedef class FNCCOL *PFNCCOL;
+typedef class SRCCOL *PSRCCOL;
+
+/***********************************************************************/
+/* This class is used to generate PIVOT table column definitions. */
+/***********************************************************************/
+class PIVAID : public CSORT {
+ friend class FNCCOL;
+ friend class SRCCOL;
+ public:
+ // Constructor
+ PIVAID(const char *tab, const char *src, const char *picol,
+ const char *fncol, const char *skcol, const char *host,
+ const char *db, const char *user, const char *pwd, int port);
+
+ // Methods
+ PQRYRES MakePivotColumns(PGLOBAL g);
+ bool SkipColumn(PCOLRES crp, char *skc);
+
+ // The sorting function
+ virtual int Qcompare(int *, int *);
+
+ protected:
+ // Members
+ MYSQLC Myc; // MySQL connection class
+ PCSZ Host; // Host machine to use
+ PCSZ User; // User logon info
+ PCSZ Pwd; // Password logon info
+ PCSZ Database; // Database to be used by server
+ PQRYRES Qryp; // Points to Query result block
+ PCSZ Tabname; // Name of source table
+ PCSZ Tabsrc; // SQL of source table
+ PCSZ Picol; // Pivot column name
+ PCSZ Fncol; // Function column name
+ PCSZ Skcol; // Skipped columns
+ PVBLK Rblkp; // The value block of the pivot column
+ int Port; // MySQL port number
+ }; // end of class PIVAID
+
+/* -------------------------- PIVOT classes -------------------------- */
+
+/***********************************************************************/
+/* PIVOT: table that provides a view of a source table where the */
+/* pivot column is expended in as many columns as there are distinct */
+/* values in it and containing the function value matching other cols.*/
+/***********************************************************************/
+
+/***********************************************************************/
+/* PIVOT table. */
+/***********************************************************************/
+class PIVOTDEF : public PRXDEF { /* Logical table description */
+ friend class TDBPIVOT;
+ public:
+ // Constructor
+ PIVOTDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "PIVOT";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ char *Host; /* Host machine to use */
+ char *User; /* User logon info */
+ char *Pwd; /* Password logon info */
+ char *DB; /* Database to be used by server */
+ char *Tabname; /* Name of source table */
+ char *Tabsrc; /* The source table SQL description */
+ char *Picol; /* The pivot column */
+ char *Fncol; /* The function column */
+ char *Function; /* The function applying to group by */
+ bool GBdone; /* True if tabname as group by format */
+ bool Accept; /* TRUE if no match is accepted */
+ int Port; /* MySQL port number */
+ }; // end of PIVOTDEF
+
+/***********************************************************************/
+/* This is the class declaration for the PIVOT table. */
+/***********************************************************************/
+class TDBPIVOT : public TDBPRX {
+ friend class FNCCOL;
+ public:
+ // Constructor
+ TDBPIVOT(PPIVOTDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_PIVOT;}
+
+ // Methods
+ virtual int GetRecpos(void) {return N;}
+ virtual void ResetDB(void) {N = 0;}
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g) {return (g) ? 10 : 0;}
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+
+ protected:
+ // Internal routines
+ bool FindDefaultColumns(PGLOBAL g);
+ bool GetSourceTable(PGLOBAL g);
+ bool MakePivotColumns(PGLOBAL g);
+ bool MakeViewColumns(PGLOBAL g);
+
+ // Members
+ char *Host; // Host machine to use
+ char *User; // User logon info
+ char *Pwd; // Password logon info
+ char *Database; // Database to be used by server
+ char *Tabname; // Name of source table
+ char *Tabsrc; // SQL of source table
+ char *Picol; // Pivot column name
+ char *Fncol; // Function column name
+ char *Function; // The function applying to group by
+ PCOL Fcolp; // To the function column in source
+ PCOL Xcolp; // To the pivot column in source
+ PCOL Dcolp; // To the dump column
+ bool GBdone; // True when subtable is "Group by"
+ bool Accept; // TRUE if no match is accepted
+ int Mult; // Multiplication factor
+ int Ncol; // The number of generated columns
+ int N; // The current table index
+ int M; // The occurrence rank
+ int Port; // MySQL port number
+ BYTE FileStatus; // 0: First 1: Rows 2: End-of-File
+ BYTE RowFlag; // 0: Ok, 1: Same, 2: Skip
+ }; // end of class TDBPIVOT
+
+/***********************************************************************/
+/* Class FNCCOL: for the multiple generated column. */
+/***********************************************************************/
+class FNCCOL : public COLBLK {
+ friend class TDBPIVOT;
+ public:
+ // Constructor
+ FNCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_FNC;}
+
+ // Methods
+ virtual void Reset(void) {}
+ bool InitColumn(PGLOBAL g);
+ bool CompareColumn(void);
+
+ protected:
+ // Member
+ PVAL Hval; // The value containing the header
+ PCOL Xcolp;
+ }; // end of class FNCCOL
+
+/***********************************************************************/
+/* Class SRCCOL: for other source columns. */
+/***********************************************************************/
+class SRCCOL : public PRXCOL {
+ friend class TDBPIVOT;
+ public:
+ // Constructors
+ SRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int n);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_SRC;}
+
+ // Methods
+ using PRXCOL::Init;
+ virtual void Reset(void) {}
+ void SetColumn(void);
+ virtual bool Init(PGLOBAL g, PTDB tp);
+ bool CompareLast(void);
+
+ protected:
+ // Default constructor not to be used
+ SRCCOL(void) {}
+
+ // Members
+ }; // end of class SRCCOL
+
+PQRYRES PivotColumns(PGLOBAL g, const char *tab, const char *src,
+ const char *picol, const char *fncol,
+ const char *skcol, const char *host,
+ const char *db, const char *user,
+ const char *pwd, int port);
diff --git a/storage/connect/tabrest.cpp b/storage/connect/tabrest.cpp
new file mode 100644
index 00000000..c66d8d76
--- /dev/null
+++ b/storage/connect/tabrest.cpp
@@ -0,0 +1,359 @@
+/************** tabrest C++ Program Source Code File (.CPP) ************/
+/* PROGRAM NAME: tabrest Version 2.1 */
+/* (C) Copyright to the author Olivier BERTRAND 2018 - 2021 */
+/* This program is the REST Web API support for MariaDB. */
+/* The way Connect handles NOSQL data returned by REST queries is */
+/* just by retrieving it as a file and then leave the existing data */
+/* type tables (JSON, XML or CSV) process it as usual. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Definitions needed by the included files. */
+/***********************************************************************/
+#include <my_global.h> // All MariaDB stuff
+#include <mysqld.h>
+#include <sql_error.h>
+#if !defined(_WIN32) && !defined(_WINDOWS)
+#include <sys/types.h>
+#include <sys/wait.h>
+#endif // !_WIN32 && !_WINDOWS
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#include "plgxml.h"
+#if defined(XML_SUPPORT)
+#include "tabxml.h"
+#endif // XML_SUPPORT
+#include "tabjson.h"
+#include "tabfmt.h"
+#include "tabrest.h"
+
+#if defined(connect_EXPORTS)
+#define PUSH_WARNING(M) push_warning(current_thd, Sql_condition::WARN_LEVEL_NOTE, 0, M)
+#else
+#define PUSH_WARNING(M) htrc(M)
+#endif
+
+static XGETREST getRestFnc = NULL;
+static int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename);
+
+/***********************************************************************/
+/* Xcurl: retrieve the REST answer by executing cURL. */
+/***********************************************************************/
+int Xcurl(PGLOBAL g, PCSZ Http, PCSZ Uri, PCSZ filename)
+{
+ char buf[512];
+ int rc = 0;
+
+ if (strchr(filename, '"')) {
+ strcpy(g->Message, "Invalid file name");
+ return 1;
+ } // endif filename
+
+ if (Uri) {
+ if (*Uri == '/' || Http[strlen(Http) - 1] == '/')
+ my_snprintf(buf, sizeof(buf)-1, "%s%s", Http, Uri);
+ else
+ my_snprintf(buf, sizeof(buf)-1, "%s/%s", Http, Uri);
+
+ } else
+ my_snprintf(buf, sizeof(buf)-1, "%s", Http);
+
+#if defined(_WIN32)
+ char cmd[1024];
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ sprintf(cmd, "curl \"%s\" -o \"%s\"", buf, filename);
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ ZeroMemory(&pi, sizeof(pi));
+
+ // Start the child process.
+ if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
+ // Wait until child process exits.
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ // Close process and thread handles.
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ } else {
+ sprintf(g->Message, "CreateProcess curl failed (%d)", GetLastError());
+ rc = 1;
+ } // endif CreateProcess
+#else // !_WIN32
+ char fn[600];
+ pid_t pID;
+
+ // Check if curl package is availabe by executing subprocess
+ FILE *f= popen("command -v curl", "r");
+
+ if (!f) {
+ strcpy(g->Message, "Problem in allocating memory.");
+ return 1;
+ } else {
+ char temp_buff[50];
+ size_t len = fread(temp_buff,1, 50, f);
+
+ if(!len) {
+ strcpy(g->Message, "Curl not installed.");
+ return 1;
+ } else
+ pclose(f);
+
+ } // endif f
+
+ pID = vfork();
+ sprintf(fn, "-o%s", filename);
+
+ if (pID == 0) {
+ // Code executed by child process
+ execlp("curl", "curl", buf, fn, (char*)NULL);
+
+ // If execlp() is successful, we should not reach this next line.
+ strcpy(g->Message, "Unsuccessful execlp from vfork()");
+ exit(1);
+ } else if (pID < 0) {
+ // failed to fork
+ strcpy(g->Message, "Failed to fork");
+ rc = 1;
+ } else {
+ // Parent process
+ wait(NULL); // Wait for the child to terminate
+ } // endif pID
+#endif // !_WIN32
+
+ return rc;
+} // end of Xcurl
+
+/***********************************************************************/
+/* GetREST: load the Rest lib and get the Rest function. */
+/***********************************************************************/
+XGETREST GetRestFunction(PGLOBAL g)
+{
+ if (getRestFnc)
+ return getRestFnc;
+
+#if !defined(REST_SOURCE)
+ if (trace(515))
+ htrc("Looking for GetRest library\n");
+
+#if defined(_WIN32) || defined(_WINDOWS)
+ HANDLE Hdll;
+ const char* soname = "GetRest.dll"; // Module name
+
+ if (!(Hdll = LoadLibrary(soname))) {
+ char buf[256];
+ DWORD rc = GetLastError();
+
+ sprintf(g->Message, MSG(DLL_LOAD_ERROR), rc, soname);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ strcat(strcat(g->Message, ": "), buf);
+ return NULL;
+ } // endif Hdll
+
+// Get the function returning an instance of the external DEF class
+ if (!(getRestFnc = (XGETREST)GetProcAddress((HINSTANCE)Hdll, "restGetFile"))) {
+ char buf[256];
+ DWORD rc = GetLastError();
+
+ sprintf(g->Message, MSG(PROCADD_ERROR), rc, "restGetFile");
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ strcat(strcat(g->Message, ": "), buf);
+ FreeLibrary((HMODULE)Hdll);
+ return NULL;
+ } // endif getRestFnc
+#else // !_WIN32
+ void* Hso;
+ const char* error = NULL;
+ const char* soname = "GetRest.so"; // Module name
+
+ // Load the desired shared library
+ if (!(Hso = dlopen(soname, RTLD_LAZY))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error));
+ return NULL;
+ } // endif Hdll
+
+// Get the function returning an instance of the external DEF class
+ if (!(getRestFnc = (XGETREST)dlsym(Hso, "restGetFile"))) {
+ error = dlerror();
+ sprintf(g->Message, MSG(GET_FUNC_ERR), "restGetFile", SVP(error));
+ dlclose(Hso);
+ return NULL;
+ } // endif getdef
+#endif // !_WIN32
+#else // REST_SOURCE
+ getRestFnc = restGetFile;
+#endif // REST_SOURCE
+
+ return getRestFnc;
+} // end of GetRestFunction
+
+/***********************************************************************/
+/* Return the columns definition to MariaDB. */
+/***********************************************************************/
+PQRYRES RESTColumns(PGLOBAL g, PTOS tp, char *tab, char *db, bool info)
+{
+ PQRYRES qrp= NULL;
+ char filename[_MAX_PATH + 1]; // MAX PATH ???
+ int rc;
+ PCSZ http, uri, fn, ftype;
+ XGETREST grf = NULL;
+ bool curl = GetBooleanTableOption(g, tp, "Curl", false);
+
+ if (!curl && !(grf = GetRestFunction(g)))
+ curl = true;
+
+ http = GetStringTableOption(g, tp, "Http", NULL);
+ uri = GetStringTableOption(g, tp, "Uri", NULL);
+ ftype = GetStringTableOption(g, tp, "Type", "JSON");
+ fn = GetStringTableOption(g, tp, "Filename", NULL);
+
+ if (!fn) {
+ int n, m = strlen(ftype) + 1;
+
+ strcat(strcpy(filename, tab), ".");
+ n = strlen(filename);
+
+ // Fold ftype to lower case
+ for (int i = 0; i < m; i++)
+ filename[n + i] = tolower(ftype[i]);
+
+ fn = filename;
+ tp->subtype = PlugDup(g, fn);
+ sprintf(g->Message, "No file name. Table will use %s", fn);
+ PUSH_WARNING(g->Message);
+ } // endif fn
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, fn, db);
+ remove(filename);
+
+ // Retrieve the file from the web and copy it locally
+ if (curl)
+ rc = Xcurl(g, http, uri, filename);
+ else
+ rc = grf(g->Message, trace(515), http, uri, filename);
+
+ if (rc) {
+ strcpy(g->Message, "Cannot access to curl nor casablanca");
+ return NULL;
+ } else if (!stricmp(ftype, "JSON"))
+ qrp = JSONColumns(g, db, NULL, tp, info);
+ else if (!stricmp(ftype, "CSV"))
+ qrp = CSVColumns(g, NULL, tp, info);
+#if defined(XML_SUPPORT)
+ else if (!stricmp(ftype, "XML"))
+ qrp = XMLColumns(g, db, tab, tp, info);
+#endif // XML_SUPPORT
+ else
+ sprintf(g->Message, "Usupported file type %s", ftype);
+
+ return qrp;
+} // end of RESTColumns
+
+/* -------------------------- Class RESTDEF -------------------------- */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values. */
+/***********************************************************************/
+bool RESTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+ char filename[_MAX_PATH + 1];
+ int rc = 0, n;
+ bool xt = trace(515);
+ LPCSTR ftype;
+ XGETREST grf = NULL;
+ bool curl = GetBoolCatInfo("Curl", false);
+
+ if (!curl && !(grf = GetRestFunction(g)))
+ curl = true;
+
+ ftype = GetStringCatInfo(g, "Type", "JSON");
+
+ if (xt)
+ htrc("ftype = %s am = %s\n", ftype, SVP(am));
+
+ n = (!stricmp(ftype, "JSON")) ? 1
+#if defined(XML_SUPPORT)
+ : (!stricmp(ftype, "XML")) ? 2
+#endif // XML_SUPPORT
+ : (!stricmp(ftype, "CSV")) ? 3 : 0;
+
+ if (n == 0) {
+ htrc("DefineAM: Unsupported REST table type %s\n", ftype);
+ sprintf(g->Message, "Unsupported REST table type %s", ftype);
+ return true;
+ } // endif n
+
+ Http = GetStringCatInfo(g, "Http", NULL);
+ Uri = GetStringCatInfo(g, "Uri", NULL);
+ Fn = GetStringCatInfo(g, "Filename", NULL);
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, Fn, GetPath());
+ remove(filename);
+
+ // Retrieve the file from the web and copy it locally
+ if (curl) {
+ rc = Xcurl(g, Http, Uri, filename);
+ xtrc(515, "Return from Xcurl: rc=%d\n", rc);
+ } else {
+ rc = grf(g->Message, xt, Http, Uri, filename);
+ xtrc(515, "Return from restGetFile: rc=%d\n", rc);
+ } // endelse
+
+ if (rc) {
+ // strcpy(g->Message, "Cannot access to curl nor casablanca");
+ return true;
+ } else switch (n) {
+ case 1: Tdp = new (g) JSONDEF; break;
+#if defined(XML_SUPPORT)
+ case 2: Tdp = new (g) XMLDEF; break;
+#endif // XML_SUPPORT
+ case 3: Tdp = new (g) CSVDEF; break;
+ default: Tdp = NULL;
+ } // endswitch n
+
+ // Do make the table/view definition
+ if (Tdp && Tdp->Define(g, Cat, Name, Schema, "REST"))
+ Tdp = NULL; // Error occured
+
+ if (xt)
+ htrc("Tdp defined\n", rc);
+
+ // Return true in case of error
+ return (Tdp == NULL);
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB RESTDEF::GetTable(PGLOBAL g, MODE m)
+{
+ if (trace(515))
+ htrc("REST GetTable mode=%d\n", m);
+
+ if (m != MODE_READ && m != MODE_READX && m != MODE_ANY) {
+ strcpy(g->Message, "REST tables are currently read only");
+ return NULL;
+ } // endif m
+
+ return Tdp->GetTable(g, m); // Leave file type do the job
+} // end of GetTable
+
+/* ---------------------- End of Class RESTDEF ----------------------- */
diff --git a/storage/connect/tabrest.h b/storage/connect/tabrest.h
new file mode 100644
index 00000000..9066a89b
--- /dev/null
+++ b/storage/connect/tabrest.h
@@ -0,0 +1,50 @@
+/*************** TabRest H Declares Source Code File (.H) **************/
+/* Name: tabrest.h Version 1.0 */
+/* (C) Copyright to the author Olivier BERTRAND 2019 */
+/* This file contains the common tabrest classes declares. */
+/***********************************************************************/
+#pragma once
+
+#if defined(_WIN32)
+static PCSZ slash = "\\";
+#else // !_WIN32
+static PCSZ slash = "/";
+#define stricmp strcasecmp
+#endif // !_WIN32
+
+typedef int(__stdcall* XGETREST) (char*, bool, PCSZ, PCSZ, PCSZ);
+
+/***********************************************************************/
+/* Functions used by REST. */
+/***********************************************************************/
+XGETREST GetRestFunction(PGLOBAL g);
+#if defined(REST_SOURCE)
+extern "C" int restGetFile(char* m, bool xt, PCSZ http, PCSZ uri, PCSZ fn);
+#endif // REST_SOURCE
+#if defined(MARIADB)
+PQRYRES RESTColumns(PGLOBAL g, PTOS tp, char* tab, char* db, bool info);
+#endif // !MARIADB
+
+
+/***********************************************************************/
+/* Restest table. */
+/***********************************************************************/
+class RESTDEF : public TABDEF { /* Table description */
+public:
+ // Constructor
+ RESTDEF(void) { Tdp = NULL; Http = Uri = Fn = NULL; }
+
+ // Implementation
+ virtual const char *GetType(void) { return "REST"; }
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+protected:
+ // Members
+ PRELDEF Tdp;
+ PCSZ Http; /* Web connection HTTP */
+ PCSZ Uri; /* Web connection URI */
+ PCSZ Fn; /* The intermediate file name */
+}; // end of class RESTDEF
diff --git a/storage/connect/tabsys.cpp b/storage/connect/tabsys.cpp
new file mode 100644
index 00000000..9a8e4a9c
--- /dev/null
+++ b/storage/connect/tabsys.cpp
@@ -0,0 +1,884 @@
+/************* TabSys C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABSYS */
+/* ------------- */
+/* Version 2.4 */
+/* */
+/* Author Olivier BERTRAND 2004-2017 */
+/* */
+/* This program are the INI/CFG tables classes. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif // __BORLANDC__
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <errno.h>
+#include <unistd.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tabdos.h is header containing the TABDOS class declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "reldef.h"
+#if !defined(_WIN32)
+#include "osutil.h"
+#endif // !_WIN32
+#include "filamtxt.h"
+#include "tabdos.h"
+#include "tabsys.h"
+#include "tabmul.h"
+#include "inihandl.h"
+
+#define CSZ 36 // Column section name length
+#define CDZ 256 // Column definition length
+
+#if !defined(_WIN32)
+#define GetPrivateProfileSectionNames(S,L,I) \
+ GetPrivateProfileString(NULL,NULL,"",S,L,I)
+#endif // !_WIN32
+
+/* -------------- Implementation of the INI classes ------------------ */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+INIDEF::INIDEF(void)
+ {
+ Pseudo = 3;
+ Fn = NULL;
+ Xname = NULL;
+ Layout = '?';
+ Ln = 0;
+ } // end of INIDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool INIDEF::DefineAM(PGLOBAL g, LPCSTR, int)
+ {
+ char buf[8];
+
+ Fn = GetStringCatInfo(g, "Filename", NULL);
+ GetCharCatInfo("Layout", "C", buf, sizeof(buf));
+ Layout = toupper(*buf);
+
+ if (Fn) {
+ char *p = (char*)PlugSubAlloc(g, NULL, _MAX_PATH);
+
+ PlugSetPath(p, Fn, GetPath());
+ Fn = p;
+ } else {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return true;
+ } // endif Fn
+
+ Ln = GetSizeCatInfo("Secsize", "8K");
+ Desc = Fn;
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB INIDEF::GetTable(PGLOBAL g, MODE)
+ {
+ PTDBASE tdbp;
+
+ if (Layout == 'C')
+ tdbp = new(g) TDBINI(this);
+ else
+ tdbp = new(g) TDBXIN(this);
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp); // No block optimization yet
+
+ return tdbp;
+ } // end of GetTable
+
+#if 0
+/***********************************************************************/
+/* DeleteTableFile: Delete INI table files using platform API. */
+/***********************************************************************/
+bool INIDEF::DeleteTableFile(PGLOBAL g)
+ {
+ char filename[_MAX_PATH];
+ bool rc;
+
+ // Delete the INI table file if not protected
+ if (!IsReadOnly()) {
+ PlugSetPath(filename, Fn, GetPath());
+#if defined(_WIN32)
+ rc = !DeleteFile(filename);
+#else // UNIX
+ rc = remove(filename);
+#endif // UNIX
+ } else
+ rc =true;
+
+ return rc; // Return true if error
+ } // end of DeleteTableFile
+#endif // 0
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBINI class. */
+/***********************************************************************/
+TDBINI::TDBINI(PINIDEF tdp) : TDBASE(tdp)
+ {
+ Ifile = tdp->Fn;
+ Seclist = NULL;
+ Section = NULL;
+ Seclen = tdp->Ln;
+ N = 0;
+ } // end of TDBINI constructor
+
+TDBINI::TDBINI(PTDBINI tdbp) : TDBASE(tdbp)
+ {
+ Ifile = tdbp->Ifile;
+ Seclist = tdbp->Seclist;
+ Section = tdbp->Section;
+ Seclen = tdbp->Seclen;
+ N = tdbp->N;
+ } // end of TDBINI copy constructor
+
+// Is this really useful ???
+PTDB TDBINI::Clone(PTABS t)
+ {
+ PTDB tp;
+ PINICOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBINI(this);
+
+ for (cp1 = (PINICOL)Columns; cp1; cp1 = (PINICOL)cp1->GetNext()) {
+ cp2 = new(g) INICOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Get the section list from the INI file. */
+/***********************************************************************/
+char *TDBINI::GetSeclist(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("GetSeclist: Seclist=%p\n", Seclist);
+
+ if (!Seclist) {
+ // Result will be retrieved from the INI file
+ Seclist = (char*)PlugSubAlloc(g, NULL, Seclen);
+ GetPrivateProfileSectionNames(Seclist, Seclen, Ifile);
+ } // endif Seclist
+
+ return Seclist;
+ } // end of GetSeclist
+
+/***********************************************************************/
+/* Allocate INI column description block. */
+/***********************************************************************/
+PCOL TDBINI::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) INICOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* INI Cardinality: returns the number of sections in the INI file. */
+/***********************************************************************/
+int TDBINI::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return 1;
+
+ if (Cardinal < 0) {
+ // Count the number of sections from the section list
+ char *p = GetSeclist(g);
+
+ Cardinal = 0;
+
+ if (p)
+ for (; *p; p += (strlen(p) + 1))
+ Cardinal++;
+
+ } // endif Cardinal
+
+ return Cardinal;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* INI GetMaxSize: returns the table cardinality. */
+/***********************************************************************/
+int TDBINI::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0)
+ MaxSize = Cardinality(g);
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* INI Access Method opening routine. */
+/***********************************************************************/
+bool TDBINI::OpenDB(PGLOBAL g)
+ {
+ PINICOL colp;
+
+ if (Use == USE_OPEN) {
+#if 0
+ if (To_Kindex)
+ /*****************************************************************/
+ /* Table is to be accessed through a sorted index table. */
+ /*****************************************************************/
+ To_Kindex->Reset();
+#endif // 0
+ Section = NULL;
+ N = 0;
+ return false;
+ } // endif use
+
+ /*********************************************************************/
+ /* OpenDB: initialize the INI file processing. */
+ /*********************************************************************/
+ GetSeclist(g);
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Allocate the buffers that will contain key values. */
+ /*********************************************************************/
+ for (colp = (PINICOL)Columns; colp; colp = (PINICOL)colp->GetNext())
+ if (!colp->IsSpecial()) // Not a pseudo column
+ colp->AllocBuf(g);
+
+ if (trace(1))
+ htrc("INI OpenDB: seclist=%s seclen=%d ifile=%s\n",
+ Seclist, Seclen, Ifile);
+
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for INI access method. */
+/***********************************************************************/
+int TDBINI::ReadDB(PGLOBAL)
+ {
+ /*********************************************************************/
+ /* Now start the pseudo reading process. */
+ /*********************************************************************/
+ if (!Section)
+ Section = Seclist;
+ else
+ Section += (strlen(Section) + 1);
+
+ if (trace(2))
+ htrc("INI ReadDB: section=%s N=%d\n", Section, N);
+
+ N++;
+ return (*Section) ? RC_OK : RC_EF;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for INI access methods. */
+/***********************************************************************/
+int TDBINI::WriteDB(PGLOBAL)
+ {
+ // This is to check that section name was given when inserting
+ if (Mode == MODE_INSERT)
+ Section = NULL;
+
+ // Nothing else to do because all was done in WriteColumn
+ return RC_OK;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for INI access methods. */
+/***********************************************************************/
+int TDBINI::DeleteDB(PGLOBAL g, int irc)
+ {
+ switch (irc) {
+ case RC_EF:
+ break;
+ case RC_FX:
+ while (ReadDB(g) == RC_OK)
+ if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
+ sprintf(g->Message, "Error %d accessing %s",
+ GetLastError(), Ifile);
+ return RC_FX;
+ } // endif
+
+ break;
+ default:
+ if (!Section) {
+ strcpy(g->Message, MSG(NO_SECTION_NAME));
+ return RC_FX;
+ } else
+ if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
+ sprintf(g->Message, "Error %d accessing %s",
+ GetLastError(), Ifile);
+ return RC_FX;
+ } // endif rc
+
+ } // endswitch irc
+
+ return RC_OK;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for INI access methods. */
+/***********************************************************************/
+void TDBINI::CloseDB(PGLOBAL)
+ {
+#if !defined(_WIN32)
+ PROFILE_Close(Ifile);
+#endif // !_WIN32
+ } // end of CloseDB
+
+// ------------------------ INICOL functions ----------------------------
+
+/***********************************************************************/
+/* INICOL public constructor. */
+/***********************************************************************/
+INICOL::INICOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional INI access method information for column.
+ Valbuf = NULL;
+ Flag = cdp->GetOffset();
+ Long = cdp->GetLong();
+ To_Val = NULL;
+ } // end of INICOL constructor
+
+/***********************************************************************/
+/* INICOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+INICOL::INICOL(INICOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Valbuf = col1->Valbuf;
+ Flag = col1->Flag;
+ Long = col1->Long;
+ To_Val = col1->To_Val;
+ } // end of INICOL copy constructor
+
+/***********************************************************************/
+/* Allocate a buffer of the proper size. */
+/***********************************************************************/
+void INICOL::AllocBuf(PGLOBAL g)
+ {
+ if (!Valbuf)
+ Valbuf = (char*)PlugSubAlloc(g, NULL, Long + 1);
+
+ } // end of AllocBuf
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool INICOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+ {
+ if (!(To_Val = value)) {
+ sprintf(g->Message, MSG(VALUE_ERROR), Name);
+ return true;
+ } else if (Buf_Type == value->GetType()) {
+ // Values are of the (good) column type
+ if (Buf_Type == TYPE_DATE) {
+ // If any of the date values is formatted
+ // output format must be set for the receiving table
+ if (GetDomain() || ((DTVAL *)value)->IsFormatted())
+ goto newval; // This will make a new value;
+
+ } else if (Buf_Type == TYPE_DOUBLE || Buf_Type == TYPE_DECIM)
+ // Float values must be written with the correct (column) precision
+ // Note: maybe this should be forced by ShowValue instead of this ?
+ value->SetPrec(GetScale());
+
+ Value = value; // Directly access the external value
+ } else {
+ // Values are not of the (good) column type
+ if (check) {
+ sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
+ GetTypeName(Buf_Type), GetTypeName(value->GetType()));
+ return true;
+ } // endif check
+
+ newval:
+ if (InitValue(g)) // Allocate the matching value block
+ return true;
+
+ } // endif's Value, Buf_Type
+
+ // Allocate the internal value buffer
+ AllocBuf(g);
+
+ // Because Colblk's have been made from a copy of the original TDB in
+ // case of Update, we must reset them to point to the original one.
+ if (To_Tdb->GetOrig())
+ To_Tdb = (PTDB)To_Tdb->GetOrig();
+
+ // Set the Column
+ Status = (ok) ? BUF_EMPTY : BUF_NO;
+ return false;
+ } // end of SetBuffer
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the key buffer set */
+/* from the corresponding section, extract from it the key value */
+/* corresponding to this column name and convert it to buffer type. */
+/***********************************************************************/
+void INICOL::ReadColumn(PGLOBAL)
+ {
+ PTDBINI tdbp = (PTDBINI)To_Tdb;
+
+ if (trace(2))
+ htrc("INI ReadColumn: col %s R%d flag=%d\n",
+ Name, tdbp->GetTdb_No(), Flag);
+
+ /*********************************************************************/
+ /* Get the key value from the INI file. */
+ /*********************************************************************/
+ switch (Flag) {
+ case 1:
+ strncpy(Valbuf, tdbp->Section, Long); // Section name
+ Valbuf[Long] = '\0';
+ break;
+ default:
+ GetPrivateProfileString(tdbp->Section, Name, "\b",
+ Valbuf, Long + 1, tdbp->Ifile);
+ break;
+ } // endswitch Flag
+
+ // Missing keys are interpreted as null values
+ if (!strcmp(Valbuf, "\b")) {
+ if (Nullable)
+ Value->SetNull(true);
+
+ Value->Reset(); // Null value
+ } else
+ Value->SetValue_psz(Valbuf);
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last line */
+/* read from the corresponding table, and rewrite the field */
+/* corresponding to this column from the column buffer and type. */
+/***********************************************************************/
+void INICOL::WriteColumn(PGLOBAL g)
+ {
+ char *p;
+ bool rc;
+ PTDBINI tdbp = (PTDBINI)To_Tdb;
+
+ if (trace(2))
+ htrc("INI WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status);
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ // Null key are missing keys
+ if (Value->IsNull())
+ return;
+
+ p = Value->GetCharString(Valbuf);
+
+ if (strlen(p) > (unsigned)Long) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
+ throw 31;
+ } else if (Flag == 1) {
+ if (tdbp->Mode == MODE_UPDATE) {
+ strcpy(g->Message, MSG(NO_SEC_UPDATE));
+ throw 31;
+ } else if (*p) {
+ tdbp->Section = p;
+ } else
+ tdbp->Section = NULL;
+
+ return;
+ } else if (!tdbp->Section) {
+ strcpy(g->Message, MSG(SEC_NAME_FIRST));
+ throw 31;
+ } // endif's
+
+ /*********************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*********************************************************************/
+ if (Status) {
+ rc = WritePrivateProfileString(tdbp->Section, Name, p, tdbp->Ifile);
+
+ if (!rc) {
+ sprintf(g->Message, "Error %d writing to %s",
+ GetLastError(), tdbp->Ifile);
+ throw 31;
+ } // endif rc
+
+ } // endif Status
+
+ } // end of WriteColumn
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBXIN class. */
+/***********************************************************************/
+TDBXIN::TDBXIN(PINIDEF tdp) : TDBINI(tdp)
+ {
+ Keylist = NULL;
+ Keycur = NULL;
+ Keylen = Seclen;
+ Oldsec = -1;
+ } // end of TDBXIN constructor
+
+TDBXIN::TDBXIN(PTDBXIN tdbp) : TDBINI(tdbp)
+ {
+ Keylist = tdbp->Keylist;
+ Keycur = tdbp->Keycur;
+ Keylen = tdbp->Keylen;
+ Oldsec = tdbp->Oldsec;
+ } // end of TDBXIN copy constructor
+
+// Is this really useful ???
+PTDB TDBXIN::Clone(PTABS t)
+ {
+ PTDB tp;
+ PXINCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBXIN(this);
+
+ for (cp1 = (PXINCOL)Columns; cp1; cp1 = (PXINCOL)cp1->GetNext()) {
+ cp2 = new(g) XINCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Get the key list from the INI file. */
+/***********************************************************************/
+char *TDBXIN::GetKeylist(PGLOBAL g, char *sec)
+ {
+ if (!Keylist)
+ Keylist = (char*)PlugSubAlloc(g, NULL, Keylen);
+
+ GetPrivateProfileString(sec, NULL, "", Keylist, Keylen, Ifile);
+ return Keylist;
+ } // end of GetKeylist
+
+/***********************************************************************/
+/* Allocate XIN column description block. */
+/***********************************************************************/
+PCOL TDBXIN::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) XINCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* XIN Cardinality: returns the number of keys in the XIN file. */
+/***********************************************************************/
+int TDBXIN::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return 1;
+
+ if (Cardinal < 0) {
+ // Count the number of keys from the section list
+ char *k, *p = GetSeclist(g);
+
+ Cardinal = 0;
+
+ if (p)
+ for (; *p; p += (strlen(p) + 1))
+ for (k = GetKeylist(g, p); *k; k += (strlen(k) + 1))
+ Cardinal++;
+
+ } // endif Cardinal
+
+ return Cardinal;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Record position is Section+Key. */
+/***********************************************************************/
+int TDBXIN::GetRecpos(void)
+ {
+ union {
+ short X[2]; // Section and Key offsets
+ int Xpos; // File position
+ }; // end of union
+
+ X[0] = (short)(Section - Seclist);
+ X[1] = (short)(Keycur - Keylist);
+ return Xpos;
+ } // end of GetRecpos
+
+/***********************************************************************/
+/* Record position is Section+Key. */
+/***********************************************************************/
+bool TDBXIN::SetRecpos(PGLOBAL g, int recpos)
+ {
+ union {
+ short X[2]; // Section and Key offsets
+ int Xpos; // File position
+ }; // end of union
+
+ Xpos = recpos;
+
+ if (X[0] != Oldsec) {
+ Section = Seclist + X[0];
+ Keycur = GetKeylist(g, Section) + X[1];
+ Oldsec = X[0];
+ } else
+ Keycur = Keylist + X[1];
+
+ return false;
+ } // end of SetRecpos
+
+/***********************************************************************/
+/* XIN Access Method opening routine. */
+/***********************************************************************/
+bool TDBXIN::OpenDB(PGLOBAL g)
+ {
+ Oldsec = -1; // To replace the table at its beginning
+ return TDBINI::OpenDB(g);
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for XIN access method. */
+/***********************************************************************/
+int TDBXIN::ReadDB(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Now start the pseudo reading process. */
+ /*********************************************************************/
+#if 0 // XIN tables are not indexable
+ if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ int recpos = To_Kindex->Fetch(g);
+
+ switch (recpos) {
+ case -1: // End of file reached
+ return RC_EF;
+ case -2: // No match for join
+ return RC_NF;
+ case -3: // Same record as last non null one
+ return RC_OK;
+ default:
+ SetRecpos(g, recpos);
+ } // endswitch recpos
+
+ } else {
+#endif // 0
+ do {
+ if (!Keycur || !*Keycur) {
+ if (!Section)
+ Section = Seclist;
+ else
+ Section += (strlen(Section) + 1);
+
+ if (*Section)
+ Keycur = GetKeylist(g, Section);
+ else
+ return RC_EF;
+
+ } else
+ Keycur += (strlen(Keycur) + 1);
+
+ } while (!*Keycur);
+
+ N++;
+//} // endif To_Kindex
+
+ return RC_OK;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for XIN access methods. */
+/***********************************************************************/
+int TDBXIN::WriteDB(PGLOBAL)
+ {
+ // To check that section and key names were given when inserting
+ if (Mode == MODE_INSERT) {
+ Section = NULL;
+ Keycur = NULL;
+ } // endif Mode
+
+ // Nothing else to do because all was done in WriteColumn
+ return RC_OK;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for XIN access methods. */
+/***********************************************************************/
+int TDBXIN::DeleteDB(PGLOBAL g, int irc)
+ {
+ if (irc == RC_EF) {
+ } else if (irc == RC_FX) {
+ for (Section = Seclist; *Section; Section += (strlen(Section) + 1))
+ if (!WritePrivateProfileString(Section, NULL, NULL, Ifile)) {
+ sprintf(g->Message, "Error %d accessing %s",
+ GetLastError(), Ifile);
+ return RC_FX;
+ } // endif
+
+ } else if (!Section) {
+ strcpy(g->Message, MSG(NO_SECTION_NAME));
+ return RC_FX;
+ } else
+ if (!WritePrivateProfileString(Section, Keycur, NULL, Ifile)) {
+ sprintf(g->Message, "Error %d accessing %s",
+ GetLastError(), Ifile);
+ return RC_FX;
+ } // endif
+
+ return RC_OK;
+ } // end of DeleteDB
+
+// ------------------------ XINCOL functions ----------------------------
+
+/***********************************************************************/
+/* XINCOL public constructor. */
+/***********************************************************************/
+XINCOL::XINCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : INICOL(cdp, tdbp, cprec, i, am)
+ {
+ } // end of XINCOL constructor
+
+/***********************************************************************/
+/* XINCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+XINCOL::XINCOL(XINCOL *col1, PTDB tdbp) : INICOL(col1, tdbp)
+ {
+ } // end of XINCOL copy constructor
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the key buffer set */
+/* from the corresponding section, extract from it the key value */
+/* corresponding to this column name and convert it to buffer type. */
+/***********************************************************************/
+void XINCOL::ReadColumn(PGLOBAL)
+ {
+ PTDBXIN tdbp = (PTDBXIN)To_Tdb;
+
+ /*********************************************************************/
+ /* Get the key value from the XIN file. */
+ /*********************************************************************/
+ switch (Flag) {
+ case 1:
+ strncpy(Valbuf, tdbp->Section, Long); // Section name
+ Valbuf[Long] = '\0';
+ break;
+ case 2:
+ strncpy(Valbuf, tdbp->Keycur, Long); // Key name
+ Valbuf[Long] = '\0';
+ break;
+ default:
+ GetPrivateProfileString(tdbp->Section, tdbp->Keycur, "",
+ Valbuf, Long + 1, tdbp->Ifile);
+ break;
+ } // endswitch Flag
+
+ Value->SetValue_psz(Valbuf);
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last line */
+/* read from the corresponding table, and rewrite the field */
+/* corresponding to this column from the column buffer and type. */
+/***********************************************************************/
+void XINCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p;
+ bool rc;
+ PTDBXIN tdbp = (PTDBXIN)To_Tdb;
+
+ if (trace(2))
+ htrc("XIN WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, tdbp->GetTdb_No(), ColUse, Status);
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ p = Value->GetCharString(Valbuf);
+
+ if (strlen(p) > (unsigned)Long) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
+ throw 31;
+ } else if (Flag == 1) {
+ if (tdbp->Mode == MODE_UPDATE) {
+ strcpy(g->Message, MSG(NO_SEC_UPDATE));
+ throw 31;
+ } else if (*p) {
+ tdbp->Section = p;
+ } else
+ tdbp->Section = NULL;
+
+ return;
+ } else if (Flag == 2) {
+ if (tdbp->Mode == MODE_UPDATE) {
+ strcpy(g->Message, MSG(NO_KEY_UPDATE));
+ throw 31;
+ } else if (*p) {
+ tdbp->Keycur = p;
+ } else
+ tdbp->Keycur = NULL;
+
+ return;
+ } else if (!tdbp->Section || !tdbp->Keycur) {
+ strcpy(g->Message, MSG(SEC_KEY_FIRST));
+ throw 31;
+ } // endif's
+
+ /*********************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*********************************************************************/
+ if (Status) {
+ rc = WritePrivateProfileString(tdbp->Section, tdbp->Keycur, p, tdbp->Ifile);
+
+ if (!rc) {
+ sprintf(g->Message, "Error %d writing to %s",
+ GetLastError(), tdbp->Ifile);
+ throw 31;
+ } // endif rc
+
+ } // endif Status
+
+ } // end of WriteColumn
+
+/* ------------------------ End of System ---------------------------- */
+
+
diff --git a/storage/connect/tabsys.h b/storage/connect/tabsys.h
new file mode 100644
index 00000000..0c6017af
--- /dev/null
+++ b/storage/connect/tabsys.h
@@ -0,0 +1,182 @@
+/*************** TabSys H Declares Source Code File (.H) ***************/
+/* Name: TABSYS.H Version 2.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2004-2014 */
+/* */
+/* This file contains the XDB system tables classes declares. */
+/***********************************************************************/
+typedef class INIDEF *PINIDEF;
+typedef class TDBINI *PTDBINI;
+typedef class INICOL *PINICOL;
+typedef class TDBXIN *PTDBXIN;
+typedef class XINCOL *PXINCOL;
+
+/* --------------------------- INI classes --------------------------- */
+
+/***********************************************************************/
+/* INI, XDB and XCL tables. */
+/***********************************************************************/
+class DllExport INIDEF : public TABDEF { /* INI table description */
+ friend class TDBINI;
+ friend class TDBXIN;
+ friend class TDBXTB;
+ friend class TDBRTB;
+ friend class TDBXCL;
+ public:
+ // Constructor
+ INIDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "INI";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ char *Fn; /* Path/Name of corresponding file */
+ char *Xname; /* The eventual table name */
+ char Layout; /* R: Row, C: Column */
+ int Ln; /* Length of section list buffer */
+ }; // end of INIDEF
+
+/***********************************************************************/
+/* This is the class declaration for the INI tables. */
+/* These are tables represented by a INI like file. */
+/***********************************************************************/
+class TDBINI : public TDBASE {
+ friend class INICOL;
+ public:
+ // Constructor
+ TDBINI(PINIDEF tdp);
+ TDBINI(PTDBINI tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_INI;}
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBINI(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual int GetRecpos(void) {return N;}
+ virtual int GetProgCur(void) {return N;}
+//virtual int GetAffectedRows(void) {return 0;}
+ virtual PCSZ GetFile(PGLOBAL g) {return Ifile;}
+ virtual void SetFile(PGLOBAL g, PCSZ fn) {Ifile = fn;}
+ virtual void ResetDB(void) {Seclist = Section = NULL; N = 0;}
+ virtual void ResetSize(void) {MaxSize = -1; Seclist = NULL;}
+ virtual int RowNumber(PGLOBAL g, bool b = false) {return N;}
+ char *GetSeclist(PGLOBAL g);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+
+ protected:
+ // Members
+ PCSZ Ifile; // The INI file
+ char *Seclist; // The section list
+ char *Section; // The current section
+ int Seclen; // Length of seclist buffer
+ int N; // The current section index
+ }; // end of class TDBINI
+
+/***********************************************************************/
+/* Class INICOL: XDB table access method column descriptor. */
+/***********************************************************************/
+class INICOL : public COLBLK {
+ public:
+ // Constructors
+ INICOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "INI");
+ INICOL(INICOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_INI;}
+ virtual void SetTo_Val(PVAL valp) {To_Val = valp;}
+
+ // Methods
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ virtual void AllocBuf(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ INICOL(void) {}
+
+ // Members
+ char *Valbuf; // To the key value buffer
+ int Flag; // Tells what set in value
+ int Long; // Buffer length
+ PVAL To_Val; // To value used for Update/Insert
+ }; // end of class INICOL
+
+/* --------------------------- XINI class ---------------------------- */
+
+/***********************************************************************/
+/* This is the class declaration for the XINI tables. */
+/* These are tables represented by a INI like file */
+/* having 3 columns Section, Key, and Value. */
+/***********************************************************************/
+class TDBXIN : public TDBINI {
+ friend class XINCOL;
+ public:
+ // Constructor
+ TDBXIN(PINIDEF tdp);
+ TDBXIN(PTDBXIN tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_INI;}
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBXIN(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual int GetRecpos(void);
+ virtual bool SetRecpos(PGLOBAL g, int recpos);
+ virtual void ResetDB(void)
+ {Seclist = Section = Keycur = NULL; N = 0; Oldsec = -1;}
+ char *GetKeylist(PGLOBAL g, char *sec);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+
+ protected:
+ // Members
+ char *Keylist; // The key list
+ char *Keycur; // The current key
+ int Keylen; // Length of keylist buffer
+ short Oldsec; // Last current section
+ }; // end of class TDBXIN
+
+/***********************************************************************/
+/* Class XINCOL: XIN table access method column descriptor. */
+/***********************************************************************/
+class XINCOL : public INICOL {
+ public:
+ // Constructors
+ XINCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "INI");
+ XINCOL(XINCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ XINCOL(void) {}
+
+ // Members
+ }; // end of class XINICOL
diff --git a/storage/connect/tabtbl.cpp b/storage/connect/tabtbl.cpp
new file mode 100644
index 00000000..b6277088
--- /dev/null
+++ b/storage/connect/tabtbl.cpp
@@ -0,0 +1,876 @@
+/************* TabTbl C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABTBL */
+/* ------------- */
+/* Version 1.9 */
+/* */
+/* Author: Olivier BERTRAND 2008-2018 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This program are the TDBTBL class DB routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABTBL.CPP - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABDOS.H - TABDOS classes declaration file */
+/* TABTBL.H - TABTBL classes declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant section of system dependant header files. */
+/***********************************************************************/
+//#include "sql_base.h"
+#include "my_global.h"
+#include "table.h" // MySQL table definitions
+#if defined(_WIN32)
+#include <stdlib.h>
+#include <stdio.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else
+#if defined(UNIX)
+#include <fnmatch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+#else
+//#include <io.h>
+#endif
+//#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h" // global declarations
+#include "plgdbsem.h" // DB application declarations
+#include "reldef.h" // DB definition declares
+#include "filamtxt.h"
+#include "tabcol.h"
+#include "tabdos.h" // TDBDOS and DOSCOL class dcls
+#include "tabtbl.h"
+#include "tabext.h"
+#include "tabmysql.h"
+#include "ha_connect.h"
+
+#if defined(_WIN32)
+#if defined(__BORLANDC__)
+#define SYSEXIT void _USERENTRY
+#else
+#define SYSEXIT void
+#endif
+#else // !_WIN32
+#define SYSEXIT void *
+#endif // !_WIN32
+
+extern pthread_mutex_t tblmut;
+
+/* ---------------------------- Class TBLDEF ---------------------------- */
+
+/**************************************************************************/
+/* Constructor. */
+/**************************************************************************/
+TBLDEF::TBLDEF(void)
+ {
+//To_Tables = NULL;
+ Accept = false;
+ Thread = false;
+ Maxerr = 0;
+ Ntables = 0;
+ Pseudo = 3;
+ } // end of TBLDEF constructor
+
+/**************************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/**************************************************************************/
+bool TBLDEF::DefineAM(PGLOBAL g, LPCSTR, int)
+ {
+ char *tablist, *dbname, *def = NULL;
+
+ Desc = "Table list table";
+ tablist = GetStringCatInfo(g, "Tablist", "");
+ dbname = GetStringCatInfo(g, "Dbname", "*");
+ def = GetStringCatInfo(g, "Srcdef", NULL);
+ Ntables = 0;
+
+ if (*tablist) {
+ char *p, *pn, *pdb;
+ PTABLE tbl;
+
+ for (pdb = tablist; ;) {
+ if ((p = strchr(pdb, ',')))
+ *p = 0;
+
+ // Analyze the table name, it may have the format:
+ // [dbname.]tabname
+ if ((pn = strchr(pdb, '.'))) {
+ *pn++ = 0;
+ } else {
+ pn = pdb;
+ pdb = dbname;
+ } // endif p
+
+ // Allocate the TBLIST block for that table
+ tbl = new(g) XTAB(pn, def);
+ tbl->SetSchema(pdb);
+
+ if (trace(1))
+ htrc("TBL: Name=%s db=%s\n", tbl->GetName(), tbl->GetSchema());
+
+ // Link the blocks
+ if (Tablep)
+ Tablep->Link(tbl);
+ else
+ Tablep = tbl;
+
+ Ntables++;
+
+ if (p)
+ pdb = pn + strlen(pn) + 1;
+ else
+ break;
+
+ } // endfor pdb
+
+ Maxerr = GetIntCatInfo("Maxerr", 0);
+ Accept = GetBoolCatInfo("Accept", false);
+ Thread = GetBoolCatInfo("Thread", false);
+ } // endif tablist
+
+ return FALSE;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB TBLDEF::GetTable(PGLOBAL g, MODE)
+ {
+ if (Catfunc == FNC_COL)
+ return new(g) TDBTBC(this);
+ else if (Thread) {
+#if defined(DEVELOPMENT)
+ return new(g) TDBTBM(this);
+#else
+ strcpy(g->Message, "Option THREAD is no more supported");
+ return NULL;
+#endif // DEVELOPMENT
+ } else
+ return new(g) TDBTBL(this);
+
+ } // end of GetTable
+
+/* ------------------------- Class TDBTBL ---------------------------- */
+
+/***********************************************************************/
+/* TDBTBL constructors. */
+/***********************************************************************/
+TDBTBL::TDBTBL(PTBLDEF tdp) : TDBPRX(tdp)
+ {
+ Tablist = NULL;
+ CurTable = NULL;
+//Tdbp = NULL;
+ Accept = tdp->Accept;
+ Maxerr = tdp->Maxerr;
+ Nbc = 0;
+ Rows = 0;
+ Crp = 0;
+// NTables = 0;
+// iTable = 0;
+ } // end of TDBTBL standard constructor
+
+/***********************************************************************/
+/* Allocate TBL column description block. */
+/***********************************************************************/
+PCOL TDBTBL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) PRXCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBTBL::InsertSpecialColumn(PCOL scp)
+ {
+ PCOL colp;
+
+ if (!scp->IsSpecial())
+ return NULL;
+
+ if (scp->GetAmType() == TYPE_AM_TABID)
+ // This special column is handled locally
+ colp = new((TIDBLK*)scp) TBTBLK(scp->GetValue());
+ else // Other special columns are treated normally
+ colp = scp;
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+ } // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* Initializes the table table list. */
+/***********************************************************************/
+bool TDBTBL::InitTableList(PGLOBAL g)
+ {
+ int n;
+ uint sln;
+ const char *scs;
+ PTABLE tp, tabp;
+ PCOL colp;
+ PTBLDEF tdp = (PTBLDEF)To_Def;
+ PCATLG cat = To_Def->GetCat();
+ PHC hc = ((MYCAT*)cat)->GetHandler();
+
+ scs = hc->get_table()->s->connect_string.str;
+ sln = hc->get_table()->s->connect_string.length;
+// PlugSetPath(filename, Tdbp->GetFile(g), Tdbp->GetPath());
+
+ for (n = 0, tp = tdp->Tablep; tp; tp = tp->GetNext()) {
+ if (TestFil(g, To_CondFil, tp)) {
+ tabp = new(g) XTAB(tp);
+
+ if (tabp->GetSrc()) {
+ // Table list is a list of connections
+ hc->get_table()->s->connect_string.str = (char*)tabp->GetName();
+ hc->get_table()->s->connect_string.length = strlen(tabp->GetName());
+ } // endif Src
+
+ // Get the table description block of this table
+ if (!(Tdbp = GetSubTable(g, tabp))) {
+ if (++Nbc > Maxerr)
+ return TRUE; // Error return
+ else
+ continue; // Skip this table
+
+ } else
+ RemoveNext(tabp); // To avoid looping
+
+ // We must allocate subtable columns before GetMaxSize is called
+ // because some (PLG, ODBC?) need to have their columns attached.
+ // Real initialization will be done later.
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!colp->IsSpecial())
+ if (((PPRXCOL)colp)->Init(g, NULL) && !Accept)
+ return TRUE;
+
+ if (Tablist)
+ Tablist->Link(tabp);
+ else
+ Tablist = tabp;
+
+ n++;
+ } // endif filp
+
+ } // endfor tp
+
+ hc->get_table()->s->connect_string.str = (char*)scs;
+ hc->get_table()->s->connect_string.length = sln;
+
+//NumTables = n;
+ To_CondFil = NULL; // To avoid doing it several times
+ return FALSE;
+ } // end of InitTableList
+
+/***********************************************************************/
+/* Test the tablename against the pseudo "local" filter. */
+/***********************************************************************/
+bool TDBTBL::TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp)
+ {
+ char *body, *fil, op[8], tn[NAME_LEN];
+ bool neg;
+
+ if (!filp)
+ return TRUE;
+ else
+ body = filp->Body;
+
+ if (strstr(body, " OR ") || strstr(body, " AND "))
+ return TRUE; // Not handled yet
+ else
+ fil = body + (*body == '(' ? 1 : 0);
+
+ if (sscanf(fil, "TABID %s", op) != 1)
+ return TRUE; // ignore invalid filter
+
+ if ((neg = !strcmp(op, "NOT")))
+ strcpy(op, "IN");
+
+ if (!strcmp(op, "=")) {
+ // Temporarily, filter must be "TABID = 'value'" only
+ if (sscanf(fil, "TABID = '%[^']'", tn) != 1)
+ return TRUE; // ignore invalid filter
+
+ return !stricmp(tn, tabp->GetName());
+ } else if (!strcmp(op, "IN")) {
+ char *p, *tnl = (char*)PlugSubAlloc(g, NULL, strlen(fil) - 10);
+ int n;
+
+ if (neg)
+ n = sscanf(fil, "TABID NOT IN (%[^)])", tnl);
+ else
+ n = sscanf(fil, "TABID IN (%[^)])", tnl);
+
+ if (n != 1)
+ return TRUE; // ignore invalid filter
+
+ while (tnl) {
+ if ((p = strchr(tnl, ',')))
+ *p++ = 0;
+
+ if (sscanf(tnl, "'%[^']'", tn) != 1)
+ return TRUE; // ignore invalid filter
+ else if (!stricmp(tn, tabp->GetName()))
+ return !neg; // Found
+
+ tnl = p;
+ } // endwhile
+
+ return neg; // Not found
+ } // endif op
+
+ return TRUE; // invalid operator
+ } // end of TestFil
+
+/***********************************************************************/
+/* Sum up the cardinality of all sub-tables. */
+/***********************************************************************/
+int TDBTBL::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return 0; // Cannot make the table list
+ else if (Cardinal < 0) {
+ int tsz;
+
+ if (!Tablist && InitTableList(g))
+ return 0; // Cannot be calculated at this stage
+
+ Cardinal = 0;
+
+ for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) {
+ if ((tsz = tabp->GetTo_Tdb()->Cardinality(g)) < 0) {
+ Cardinal = -1;
+ return tsz;
+ } // endif mxsz
+
+ Cardinal += tsz;
+ } // endfor i
+
+ } // endif Cardinal
+
+ return Cardinal;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* Sum up the maximum sizes of all sub-tables. */
+/***********************************************************************/
+int TDBTBL::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ int mxsz;
+
+ if (!Tablist && InitTableList(g))
+ return 0; // Cannot be calculated at this stage
+
+ MaxSize = 0;
+
+ for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext()) {
+ if ((mxsz = tabp->GetTo_Tdb()->GetMaxSize(g)) < 0) {
+ MaxSize = -1;
+ return mxsz;
+ } // endif mxsz
+
+ MaxSize += mxsz;
+ } // endfor i
+
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void TDBTBL::ResetDB(void)
+ {
+ for (PCOL colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_TABID ||
+ colp->GetAmType() == TYPE_AM_SRVID)
+ colp->COLBLK::Reset();
+
+ for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext())
+ tabp->GetTo_Tdb()->ResetDB();
+
+ Tdbp = Tablist->GetTo_Tdb();
+ Crp = 0;
+ } // end of ResetDB
+
+/***********************************************************************/
+/* Returns RowId if b is false or Rownum if b is true. */
+/***********************************************************************/
+int TDBTBL::RowNumber(PGLOBAL g, bool b)
+ {
+ return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
+ } // end of RowNumber
+
+/***********************************************************************/
+/* TBL Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBTBL::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("TBL OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, replace it at its beginning. */
+ /*******************************************************************/
+ ResetDB();
+ return Tdbp->OpenDB(g); // Re-open fist table
+ } // endif use
+
+ /*********************************************************************/
+ /* When GetMaxsize was called, To_CondFil was not set yet. */
+ /*********************************************************************/
+ if (To_CondFil && Tablist) {
+ Tablist = NULL;
+ Nbc = 0;
+ } // endif To_CondFil
+
+ /*********************************************************************/
+ /* Open the first table of the list. */
+ /*********************************************************************/
+ if (!Tablist && InitTableList(g)) // done in GetMaxSize
+ return TRUE;
+
+ if ((CurTable = Tablist)) {
+ Tdbp = CurTable->GetTo_Tdb();
+// Tdbp->SetMode(Mode);
+// Tdbp->ResetDB();
+// Tdbp->ResetSize();
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_TABID)
+ cp->COLBLK::Reset();
+ else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
+ return TRUE;
+
+ if (trace(1))
+ htrc("Opening subtable %s\n", Tdbp->GetName());
+
+ // Now we can safely open the table
+ if (Tdbp->OpenDB(g))
+ return TRUE;
+
+ } // endif *Tablist
+
+ Use = USE_OPEN;
+ return FALSE;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for MUL access method. */
+/***********************************************************************/
+int TDBTBL::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+ if (!CurTable)
+ return RC_EF;
+ else if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ strcpy(g->Message, MSG(NO_INDEX_READ));
+ rc = RC_FX;
+ } else {
+ /*******************************************************************/
+ /* Now start the reading process. */
+ /*******************************************************************/
+ retry:
+ rc = Tdbp->ReadDB(g);
+
+ if (rc == RC_EF) {
+ // Total number of rows met so far
+ Rows += Tdbp->RowNumber(g) - 1;
+ Crp += Tdbp->GetProgMax(g);
+
+ if ((CurTable = CurTable->GetNext())) {
+ /***************************************************************/
+ /* Continue reading from next table file. */
+ /***************************************************************/
+ Tdbp->CloseDB(g);
+ Tdbp = CurTable->GetTo_Tdb();
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_TABID ||
+ cp->GetAmType() == TYPE_AM_SRVID)
+ cp->COLBLK::Reset();
+ else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
+ return RC_FX;
+
+ if (trace(1))
+ htrc("Opening subtable %s\n", Tdbp->GetName());
+
+ // Now we can safely open the table
+ if (Tdbp->OpenDB(g)) // Open next table
+ return RC_FX;
+
+ goto retry;
+ } // endif iFile
+
+ } else if (rc == RC_FX)
+ strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
+
+ } // endif To_Kindex
+
+ return rc;
+ } // end of ReadDB
+
+/* ---------------------------- TBTBLK ------------------------------- */
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void TBTBLK::ReadColumn(PGLOBAL)
+ {
+ if (trace(1))
+ htrc("TBT ReadColumn: name=%s\n", Name);
+
+ Value->SetValue_psz((char*)((PTDBTBL)To_Tdb)->Tdbp->GetName());
+
+ } // end of ReadColumn
+
+#if defined(DEVELOPMENT)
+/* ------------------------- Class TDBTBM ---------------------------- */
+
+/***********************************************************************/
+/* Thread routine that check and open one remote connection. */
+/***********************************************************************/
+pthread_handler_t ThreadOpen(void *p)
+ {
+ PTBMT cmp = (PTBMT)p;
+
+ if (!my_thread_init()) {
+ set_current_thd(cmp->Thd);
+
+ if (trace(1))
+ htrc("ThreadOpen: Thd=%d\n", cmp->Thd);
+
+ // Try to open the connection
+ pthread_mutex_lock(&tblmut);
+
+ if (!cmp->Tap->GetTo_Tdb()->OpenDB(cmp->G)) {
+// pthread_mutex_lock(&tblmut);
+ if (trace(1))
+ htrc("Table %s ready\n", cmp->Tap->GetName());
+
+ cmp->Ready = true;
+// pthread_mutex_unlock(&tblmut);
+ } else {
+// pthread_mutex_lock(&tblmut);
+ if (trace(1))
+ htrc("Opening %s failed\n", cmp->Tap->GetName());
+
+ cmp->Rc = RC_FX;
+// pthread_mutex_unlock(&tblmut);
+ } // endif OpenDB
+
+ pthread_mutex_unlock(&tblmut);
+ my_thread_end();
+ } else
+ cmp->Rc = RC_FX;
+
+ return NULL;
+ } // end of ThreadOpen
+
+/***********************************************************************/
+/* TDBTBM constructors. */
+/***********************************************************************/
+TDBTBM::TDBTBM(PTBLDEF tdp) : TDBTBL(tdp)
+ {
+ Tmp = NULL; // To data table TBMT structures
+ Cmp = NULL; // Current data table TBMT
+ Bmp = NULL; // To bad (unconnected) TBMT structures
+ Done = false; // TRUE after first GetAllResults
+ Nrc = 0; // Number of remote connections
+ Nlc = 0; // Number of local connections
+ } // end of TDBTBL standard constructor
+
+/***********************************************************************/
+/* Reset read/write position values. */
+/***********************************************************************/
+void TDBTBM::ResetDB(void)
+ {
+ for (PCOL colp = Columns; colp; colp = colp->GetNext())
+ if (colp->GetAmType() == TYPE_AM_TABID)
+ colp->COLBLK::Reset();
+
+ // Local tables
+ for (PTABLE tabp = Tablist; tabp; tabp = tabp->GetNext())
+ tabp->GetTo_Tdb()->ResetDB();
+
+ // Remote tables
+ for (PTBMT tp = Tmp; tp; tp = tp->Next)
+ tp->Tap->GetTo_Tdb()->ResetDB();
+
+ Tdbp = (Tablist) ? Tablist->GetTo_Tdb() : NULL;
+ Crp = 0;
+ } // end of ResetDB
+
+/***********************************************************************/
+/* Returns RowId if b is false or Rownum if b is true. */
+/***********************************************************************/
+int TDBTBM::RowNumber(PGLOBAL g, bool b)
+ {
+ return Tdbp->RowNumber(g) + ((b) ? 0 : Rows);
+ } // end of RowNumber
+
+/***********************************************************************/
+/* Returns true if this MYSQL table refers to a local table. */
+/***********************************************************************/
+bool TDBTBM::IsLocal(PTABLE tbp)
+{
+ TDBMYSQL *tdbp = (TDBMYSQL*)tbp->GetTo_Tdb();
+
+ return ((!stricmp(tdbp->Host, "localhost") ||
+ !strcmp(tdbp->Host, "127.0.0.1")) &&
+ (int) tdbp->Port == (int)GetDefaultPort());
+} // end of IsLocal
+
+/***********************************************************************/
+/* Initialyze table parallel processing. */
+/***********************************************************************/
+bool TDBTBM::OpenTables(PGLOBAL g)
+ {
+ int k;
+ THD *thd = current_thd;
+ PTABLE tabp, *ptabp = &Tablist;
+ PTBMT tp, *ptp = &Tmp;
+
+ // Allocates the TBMT blocks for the tables
+ for (tabp = Tablist; tabp; tabp = tabp->Next)
+ if (tabp->GetTo_Tdb()->GetAmType() == TYPE_AM_MYSQL && !IsLocal(tabp)) {
+ // Remove remote table from the local list
+ *ptabp = tabp->Next;
+
+ if (trace(1))
+ htrc("=====> New remote table %s\n", tabp->GetName());
+
+ // Make the remote table block
+ tp = (PTBMT)PlugSubAlloc(g, NULL, sizeof(TBMT));
+ memset(tp, 0, sizeof(TBMT));
+ tp->G = g;
+ tp->Ready = false;
+ tp->Tap = tabp;
+ tp->Thd = thd;
+
+ // Create the thread that will do the table opening.
+ pthread_attr_init(&tp->attr);
+// pthread_attr_setdetachstate(&tp->attr, PTHREAD_CREATE_JOINABLE);
+
+ if ((k = pthread_create(&tp->Tid, &tp->attr, ThreadOpen, tp))) {
+ sprintf(g->Message, "pthread_create error %d", k);
+ Nbc++;
+ continue;
+ } // endif k
+
+ // Add it to the remote list
+ *ptp = tp;
+ ptp = &tp->Next;
+ Nrc++; // Number of remote connections
+ } else {
+ if (trace(1))
+ htrc("=====> Local table %s\n", tabp->GetName());
+
+ ptabp = &tabp->Next;
+ Nlc++; // Number of local connections
+ } // endif Type
+
+ return false;
+ } // end of OpenTables
+
+/***********************************************************************/
+/* TBL Access Method opening routine. */
+/* Open first file, other will be opened sequencially when reading. */
+/***********************************************************************/
+bool TDBTBM::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("TBM OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, replace it at its beginning. */
+ /*******************************************************************/
+ ResetDB();
+ return (Tdbp) ? Tdbp->OpenDB(g) : false; // Re-open fist table
+ } // endif use
+
+#if 0
+ /*********************************************************************/
+ /* When GetMaxsize was called, To_CondFil was not set yet. */
+ /*********************************************************************/
+ if (To_CondFil && Tablist) {
+ Tablist = NULL;
+ Nbc = 0;
+ } // endif To_CondFil
+#endif // 0
+
+ /*********************************************************************/
+ /* Make the table list. */
+ /*********************************************************************/
+ if (/*!Tablist &&*/ InitTableList(g))
+ return TRUE;
+
+ /*********************************************************************/
+ /* Open all remote tables of the list. */
+ /*********************************************************************/
+ if (OpenTables(g))
+ return TRUE;
+
+ /*********************************************************************/
+ /* Proceed with local tables. */
+ /*********************************************************************/
+ if ((CurTable = Tablist)) {
+ Tdbp = CurTable->GetTo_Tdb();
+// Tdbp->SetMode(Mode);
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_TABID)
+ cp->COLBLK::Reset();
+ else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
+ return TRUE;
+
+ if (trace(1))
+ htrc("Opening subtable %s\n", Tdbp->GetName());
+
+ // Now we can safely open the table
+ if (Tdbp->OpenDB(g))
+ return TRUE;
+
+ } // endif *Tablist
+
+ Use = USE_OPEN;
+ return FALSE;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for MUL access method. */
+/***********************************************************************/
+int TDBTBM::ReadDB(PGLOBAL g)
+ {
+ int rc;
+
+ if (!Done) {
+ // Get result from local tables
+ if ((rc = TDBTBL::ReadDB(g)) != RC_EF)
+ return rc;
+ else if ((rc = ReadNextRemote(g)) != RC_OK)
+ return rc;
+
+ Done = true;
+ } // endif Done
+
+ /*********************************************************************/
+ /* Now start the reading process of remote tables. */
+ /*********************************************************************/
+ retry:
+ rc = Tdbp->ReadDB(g);
+
+ if (rc == RC_EF) {
+ // Total number of rows met so far
+ Rows += Tdbp->RowNumber(g) - 1;
+ Crp += Tdbp->GetProgMax(g);
+ Cmp->Complete = true;
+
+ if ((rc = ReadNextRemote(g)) == RC_OK)
+ goto retry;
+
+ } else if (rc == RC_FX)
+ strcat(strcat(strcat(g->Message, " ("), Tdbp->GetName()), ")");
+
+ return rc;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* ReadNext: Continue reading from next table. */
+/***********************************************************************/
+int TDBTBM::ReadNextRemote(PGLOBAL g)
+ {
+ bool b;
+
+ if (Tdbp)
+ Tdbp->CloseDB(g);
+
+ Cmp = NULL;
+
+ retry:
+ b = false;
+
+ // Search for a remote table having its result set
+ pthread_mutex_lock(&tblmut);
+ for (PTBMT tp = Tmp; tp; tp = tp->Next)
+ if (tp->Rc != RC_FX) {
+ if (tp->Ready) {
+ if (!tp->Complete) {
+ Cmp = tp;
+ break;
+ } // endif Complete
+
+ } else
+ b = true;
+
+ } // endif Rc
+
+ pthread_mutex_unlock(&tblmut);
+
+ if (!Cmp) {
+ if (b) { // more result to come
+// sleep(20);
+ goto retry;
+ } else
+ return RC_EF;
+
+ } // endif Curtable
+
+ Tdbp = Cmp->Tap->GetTo_Tdb();
+
+ // Check and initialize the subtable columns
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (cp->GetAmType() == TYPE_AM_TABID)
+ cp->COLBLK::Reset();
+ else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
+ return RC_FX;
+
+ if (trace(1))
+ htrc("Reading subtable %s\n", Tdbp->GetName());
+
+ return RC_OK;
+ } // end of ReadNextRemote
+#endif // DEVELOPMENT
+
+/* ------------------------------------------------------------------- */
diff --git a/storage/connect/tabtbl.h b/storage/connect/tabtbl.h
new file mode 100644
index 00000000..e7a84395
--- /dev/null
+++ b/storage/connect/tabtbl.h
@@ -0,0 +1,168 @@
+/*************** TabTbl H Declares Source Code File (.H) ***************/
+/* Name: TABTBL.H Version 1.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2008-2013 */
+/* */
+/* This file contains the TDBTBL classes declares. */
+/***********************************************************************/
+#include "block.h"
+#include "colblk.h"
+#include "tabutil.h"
+
+typedef class TBLDEF *PTBLDEF;
+typedef class TDBTBL *PTDBTBL;
+typedef class MYSQLC *PMYC;
+
+/***********************************************************************/
+/* TBL table. */
+/***********************************************************************/
+class DllExport TBLDEF : public PRXDEF { /* Logical table description */
+ friend class TDBTBL;
+ friend class TDBTBC;
+ public:
+ // Constructor
+ TBLDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "TBL";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ bool Accept; /* TRUE if bad tables are accepted */
+ bool Thread; /* Use thread for remote tables */
+ int Maxerr; /* Maximum number of bad tables */
+ int Ntables; /* Number of tables */
+ }; // end of TBLDEF
+
+/***********************************************************************/
+/* This is the TBL Access Method class declaration. */
+/***********************************************************************/
+class DllExport TDBTBL : public TDBPRX {
+ friend class TBTBLK;
+ public:
+ // Constructor
+ TDBTBL(PTBLDEF tdp = NULL);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_TBL;}
+
+ // Methods
+ virtual void ResetDB(void);
+ virtual int GetRecpos(void) {return Rows;}
+ virtual int GetBadLines(void) {return (int)Nbc;}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE);
+ virtual PCOL InsertSpecialColumn(PCOL scp);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+
+ protected:
+ // Internal functions
+ bool InitTableList(PGLOBAL g);
+ bool TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp);
+
+ // Members
+ PTABLE Tablist; // Points to the table list
+ PTABLE CurTable; // Points to the current table
+ bool Accept; // TRUE if bad tables are accepted
+ int Maxerr; // Maximum number of bad tables
+ int Nbc; // Number of bad connections
+ int Rows; // Used for RowID
+ int Crp; // Used for CurPos
+ }; // end of class TDBTBL
+
+/***********************************************************************/
+/* Class TBTBLK: TDBPLG TABID special column descriptor. */
+/***********************************************************************/
+class TBTBLK : public TIDBLK {
+ public:
+ // The constructor must restore Value because XOBJECT has a void
+ // constructor called by default that set Value to NULL
+ TBTBLK(PVAL valp) {Value = valp;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ // Fake operator new used to change TIDBLK into SDTBLK
+ void * operator new(size_t size, TIDBLK *sp) {return sp;}
+
+#if !defined(__BORLANDC__)
+ // Avoid warning C4291 by defining a matching dummy delete operator
+ void operator delete(void *, TIDBLK*) {}
+ void operator delete(void *, size_t size) {}
+#endif
+
+ protected:
+ // Must not have additional members
+}; // end of class TBTBLK
+
+#if defined(DEVELOPMENT)
+/***********************************************************************/
+/* This table type is buggy and removed until a fix is found. */
+/***********************************************************************/
+typedef class TDBTBM *PTDBTBM;
+
+/***********************************************************************/
+/* Defines the structures used for distributed TBM tables. */
+/***********************************************************************/
+typedef struct _TBMtable *PTBMT;
+
+typedef struct _TBMtable {
+ PTBMT Next; // Points to next data table struct
+ PTABLE Tap; // Points to the sub table
+ PGLOBAL G; // Needed in thread routine
+ bool Complete; // TRUE when all results are read
+ bool Ready; // TRUE when results are there
+ int Rows; // Total number of rows read so far
+ int ProgCur; // Current pos
+ int ProgMax; // Max pos
+ int Rc; // Return code
+ THD *Thd;
+ pthread_attr_t attr; // ???
+ pthread_t Tid; // CheckOpen thread ID
+} TBMT;
+
+/***********************************************************************/
+/* This is the TBM Access Method class declaration. */
+/***********************************************************************/
+class DllExport TDBTBM : public TDBTBL {
+ friend class TBTBLK;
+ public:
+ // Constructor
+ TDBTBM(PTBLDEF tdp = NULL);
+
+ // Methods
+ virtual void ResetDB(void);
+
+ // Database routines
+ virtual int Cardinality(PGLOBAL g) { return 10; }
+ virtual int GetMaxSize(PGLOBAL g) { return 10; } // Temporary
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+
+ protected:
+ // Internal functions
+ bool IsLocal(PTABLE tbp);
+ bool OpenTables(PGLOBAL g);
+ int ReadNextRemote(PGLOBAL g);
+
+ // Members
+ PTBMT Tmp; // To data table TBMT structures
+ PTBMT Cmp; // Current data table PLGF (to move to TDBTBL)
+ PTBMT Bmp; // To bad (unconnected) PLGF structures
+ bool Done; // TRUE after first GetAllResults
+ int Nrc; // Number of remote connections
+ int Nlc; // Number of local connections
+ }; // end of class TDBTBM
+
+pthread_handler_t ThreadOpen(void *p);
+#endif // DEVELOPMENT
diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp
new file mode 100644
index 00000000..941073b3
--- /dev/null
+++ b/storage/connect/tabutil.cpp
@@ -0,0 +1,804 @@
+/************* Tabutil cpp Declares Source Code File (.CPP) ************/
+/* Name: TABUTIL.CPP Version 1.2 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2013 - 2017 */
+/* */
+/* Utility function used by the PROXY, XCOL, OCCUR, and TBL tables. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant section of system dependant header files. */
+/***********************************************************************/
+#define MYSQL_SERVER 1
+#include <my_global.h>
+#include "sql_class.h"
+#include "table.h"
+#include "field.h"
+#if defined(_WIN32)
+#include <stdlib.h>
+#include <stdio.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else
+#if defined(UNIX)
+#include <fnmatch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+#else
+//#include <io.h>
+#endif
+//#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "table.h" // MySQL table definitions
+#include "global.h"
+#include "plgdbsem.h"
+#include "plgcnx.h" // For DB types
+#include "myutil.h"
+#include "valblk.h"
+#include "resource.h"
+//#include "reldef.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "tabmysql.h"
+#include "tabcol.h"
+#include "tabutil.h"
+#include "ha_connect.h"
+
+int GetConvSize(void);
+
+/************************************************************************/
+/* Used by MYSQL tables to get MySQL parameters from the calling proxy */
+/* table (PROXY, TBL, XCL, or OCCUR) when used by one of these. */
+/************************************************************************/
+TABLE_SHARE *Remove_tshp(PCATLG cat)
+{
+ TABLE_SHARE *s = ((MYCAT*)cat)->GetHandler()->tshp;
+
+ ((MYCAT*)cat)->GetHandler()->tshp = NULL;
+ return s;
+} // end of Remove_thsp
+
+/************************************************************************/
+/* Used by MYSQL tables to get MySQL parameters from the calling proxy */
+/* table (PROXY, TBL, XCL, or OCCUR) when used by one of these. */
+/************************************************************************/
+void Restore_tshp(PCATLG cat, TABLE_SHARE *s)
+{
+ ((MYCAT*)cat)->GetHandler()->tshp = s;
+} // end of Restore_thsp
+
+/************************************************************************/
+/* GetTableShare: allocates and open a table share. */
+/************************************************************************/
+TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db,
+ const char *name, bool& mysql)
+{
+ char key[256];
+ uint k;
+ TABLE_SHARE *s;
+
+ k = sprintf(key, "%s", db) + 1;
+ k += sprintf(key + k, "%s", name);
+ key[++k] = 0;
+
+ if (!(s = alloc_table_share(db, name, key, ++k))) {
+ strcpy(g->Message, "Error allocating share\n");
+ return NULL;
+ } // endif s
+
+ if (!open_table_def(thd, s, GTS_TABLE | GTS_VIEW)) {
+ if (!s->is_view) {
+ if (stricmp(plugin_name(s->db_plugin)->str, "connect"))
+ mysql = true;
+ else
+ mysql = false;
+
+ } else
+ mysql = true;
+
+ } else {
+ if (thd->is_error())
+ thd->clear_error(); // Avoid stopping info commands
+
+ sprintf(g->Message, "Error %d opening share\n", s->error);
+ free_table_share(s);
+ return NULL;
+ } // endif open_table_def
+
+ return s;
+} // end of GetTableShare
+
+/************************************************************************/
+/* TabColumns: constructs the result blocks containing all the columns */
+/* description of the object table that will be retrieved by discovery.*/
+/************************************************************************/
+PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
+ const char *name, bool& info)
+ {
+ int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
+ TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT,
+ TYPE_STRING, TYPE_STRING, TYPE_STRING};
+ XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
+ FLD_LENGTH, FLD_SCALE, FLD_RADIX, FLD_NULL,
+ FLD_REM, FLD_NO, FLD_CHARSET};
+ unsigned int length[] = {0, 4, 16, 4, 4, 4, 4, 4, 0, 32, 32};
+ PCSZ fmt;
+ char *pn, *tn, *fld, *colname, v; // *chset
+ int i, n, ncol = sizeof(buftyp) / sizeof(int);
+ int prec, len, type, scale;
+ int zconv = GetConvSize();
+ bool mysql;
+ TABLE_SHARE *s = NULL;
+ Field* *field;
+ Field *fp;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ if (!info) {
+ // Analyze the table name, it may have the format: [dbname.]tabname
+ if (strchr((char*)name, '.')) {
+ tn = (char*)PlugDup(g, name);
+ pn = strchr(tn, '.');
+ *pn++ = 0;
+ db = tn;
+ name = pn;
+ } // endif pn
+
+ if (!(s = GetTableShare(g, thd, db, name, mysql))) {
+ return NULL;
+ } else if (s->is_view) {
+ strcpy(g->Message, "Use MYSQL type to see columns from a view");
+ info = true; // To tell caller name is a view
+ free_table_share(s);
+ return NULL;
+ } else
+ n = s->fieldnames.count;
+
+ } else {
+ n = 0;
+ length[0] = 128;
+ } // endif info
+
+ /**********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /**********************************************************************/
+ if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, true)))
+ return NULL;
+
+ // Some columns must be renamed
+ for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
+ switch (++i) {
+ case 2: crp->Nulls = (char*)PlugSubAlloc(g, NULL, n); break;
+ case 10: crp->Name = "Date_fmt"; break;
+ case 11: crp->Name = "Collation"; break;
+ } // endswitch i
+
+ if (info)
+ return qrp;
+
+ /**********************************************************************/
+ /* Now get the results into blocks. */
+ /**********************************************************************/
+ for (i = 0, field= s->field; *field; field++) {
+ fp= *field;
+
+ // Get column name
+ crp = qrp->Colresp; // Column_Name
+ colname = (char *)fp->field_name.str;
+ crp->Kdata->SetValue(colname, i);
+
+// chset = (char *)fp->charset()->name;
+// v = (!strcmp(chset, "binary")) ? 'B' : 0;
+ v = 0;
+
+ if ((type = MYSQLtoPLG(fp->type(), &v)) == TYPE_ERROR) {
+ if (v == 'K') {
+ // Skip this column
+ sprintf(g->Message, "Column %s skipped (unsupported type)", colname);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ continue;
+ } // endif v
+
+ sprintf(g->Message, "Column %s unsupported type", colname);
+ qrp = NULL;
+ break;
+ } // endif type
+
+ if (v == 'X') {
+ len = zconv;
+ sprintf(g->Message, "Column %s converted to varchar(%d)",
+ colname, len);
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
+ } // endif v
+
+ crp = crp->Next; // Data_Type
+ crp->Kdata->SetValue(type, i);
+
+ if (fp->flags & ZEROFILL_FLAG)
+ crp->Nulls[i] = 'Z';
+ else if (fp->flags & UNSIGNED_FLAG)
+ crp->Nulls[i] = 'U';
+ else // X means TEXT field
+ crp->Nulls[i] = (v == 'X') ? 'V' : v;
+
+ crp = crp->Next; // Type_Name
+ crp->Kdata->SetValue(GetTypeName(type), i);
+ fmt = NULL;
+
+ if (type == TYPE_DATE) {
+ // When creating tables we do need info about date columns
+ if (mysql) {
+ fmt = MyDateFmt(fp->type());
+ prec = len = strlen(fmt);
+ } else {
+ fmt = (PCSZ)fp->option_struct->dateformat;
+ prec = len = fp->field_length;
+ } // endif mysql
+
+ } else if (v != 'X') {
+ if (type == TYPE_DECIM)
+ prec = ((Field_new_decimal*)fp)->precision;
+ else
+ prec = fp->field_length;
+// prec = (prec(???) == NOT_FIXED_DEC) ? 0 : fp->field_length;
+
+ len = fp->char_length();
+ } else
+ prec = len = zconv;
+
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(prec, i);
+
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(len, i);
+
+ crp = crp->Next; // Scale
+ scale = (type == TYPE_DOUBLE || type == TYPE_DECIM) ? fp->decimals()
+ : 0;
+ crp->Kdata->SetValue(scale, i);
+
+ crp = crp->Next; // Radix
+ crp->Kdata->SetValue(0, i);
+
+ crp = crp->Next; // Nullable
+ crp->Kdata->SetValue((fp->null_ptr != 0) ? 1 : 0, i);
+
+ crp = crp->Next; // Remark
+
+ // For Valgrind
+ if (fp->comment.length > 0 && (fld = (char*) fp->comment.str))
+ crp->Kdata->SetValue(fld, fp->comment.length, i);
+ else
+ crp->Kdata->Reset(i);
+
+ crp = crp->Next; // New (date format)
+ crp->Kdata->SetValue((fmt) ? fmt : (char*) "", i);
+
+ crp = crp->Next; // New (charset)
+ fld = (char *)fp->charset()->name;
+ crp->Kdata->SetValue(fld, i);
+
+ // Add this item
+ qrp->Nblin++;
+ i++; // Can be skipped
+ } // endfor field
+
+ /**********************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /**********************************************************************/
+ if (s)
+ free_table_share(s);
+
+ return qrp;
+ } // end of TabColumns
+
+/* -------------- Implementation of the PROXY classes ---------------- */
+
+/***********************************************************************/
+/* PRXDEF constructor. */
+/***********************************************************************/
+PRXDEF::PRXDEF(void)
+ {
+ Tablep = NULL;
+ Pseudo = 3;
+} // end of PRXDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XCOL file. */
+/***********************************************************************/
+bool PRXDEF::DefineAM(PGLOBAL g, LPCSTR, int)
+ {
+ char *pn, *db, *tab, *def = NULL;
+
+ db = GetStringCatInfo(g, "Dbname", "*");
+ def = GetStringCatInfo(g, "Srcdef", NULL);
+
+ if (!(tab = GetStringCatInfo(g, "Tabname", NULL))) {
+ if (!def) {
+ strcpy(g->Message, "Missing object table definition");
+ return true;
+ } else
+ tab = PlugDup(g, "Noname");
+
+ } else
+ // Analyze the table name, it may have the format: [dbname.]tabname
+ if ((pn = strchr(tab, '.'))) {
+ *pn++ = 0;
+ db = tab;
+ tab = pn;
+ } // endif pn
+
+ Tablep = new(g) XTAB(tab, def);
+ Tablep->SetSchema(db);
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB PRXDEF::GetTable(PGLOBAL g, MODE)
+ {
+ if (Catfunc == FNC_COL)
+ return new(g) TDBTBC(this);
+ else
+ return new(g) TDBPRX(this);
+
+ } // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBPRX class. */
+/***********************************************************************/
+TDBPRX::TDBPRX(PPRXDEF tdp) : TDBASE(tdp)
+ {
+ Tdbp = NULL; // The object table
+ } // end of TDBPRX constructor
+
+TDBPRX::TDBPRX(PTDBPRX tdbp) : TDBASE(tdbp)
+ {
+ Tdbp = tdbp->Tdbp;
+ } // end of TDBPRX copy constructor
+
+// Method
+PTDB TDBPRX::Clone(PTABS t)
+ {
+ PTDB tp;
+ PPRXCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBPRX(this);
+
+ for (cp1 = (PPRXCOL)Columns; cp1; cp1 = (PPRXCOL)cp1->GetNext()) {
+ cp2 = new(g) PRXCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Get the PTDB of the sub-table. */
+/***********************************************************************/
+PTDB TDBPRX::GetSubTable(PGLOBAL g, PTABLE tabp, bool b)
+ {
+ const char *sp = NULL;
+ char *db, *name;
+ bool mysql = true;
+ PTDB tdbp = NULL;
+ TABLE_SHARE *s = NULL;
+ Field* *fp = NULL;
+ PCATLG cat = To_Def->GetCat();
+ PHC hc = ((MYCAT*)cat)->GetHandler();
+ LPCSTR cdb, curdb = hc->GetDBName(NULL);
+ THD *thd = (hc->GetTable())->in_use;
+
+ db = (char*)(tabp->GetSchema() ? tabp->GetSchema() : curdb);
+ name = (char*)tabp->GetName();
+
+ // Check for eventual loop
+ for (PTABLE tp = To_Table; tp; tp = tp->Next) {
+ cdb = (tp->Schema) ? tp->Schema : curdb;
+
+ if (!stricmp(name, tp->Name) && !stricmp(db, cdb)) {
+ sprintf(g->Message, "Table %s.%s pointing on itself", db, name);
+ return NULL;
+ } // endif
+
+ } // endfor tp
+
+ if (!tabp->GetSrc()) {
+ if (!(s = GetTableShare(g, thd, db, name, mysql)))
+ return NULL;
+
+ if (s->is_view && !b)
+ s->field = hc->get_table()->s->field;
+
+ hc->tshp = s;
+ } else if (b) {
+ // Don't use caller's columns
+ fp = hc->get_table()->field;
+ hc->get_table()->field = NULL;
+
+ // Make caller use the source definition
+ sp = hc->get_table()->s->option_struct->srcdef;
+ hc->get_table()->s->option_struct->srcdef = tabp->GetSrc();
+ } // endif srcdef
+
+ if (mysql) {
+ // Access sub-table via MySQL API
+ if (!(tdbp= cat->GetTable(g, tabp, Mode, "MYPRX"))) {
+ char buf[MAX_STR];
+
+ strcpy(buf, g->Message);
+ snprintf(g->Message, MAX_STR, "Error accessing %s.%s: %s", db, name, buf);
+ hc->tshp = NULL;
+ goto err;
+ } // endif Define
+
+ if (db)
+ ((PTDBMY)tdbp)->SetDatabase(tabp->GetSchema());
+
+ if (Mode == MODE_UPDATE || Mode == MODE_DELETE)
+ tdbp->SetName(Name); // For Make_Command
+
+ } else {
+ // Sub-table is a CONNECT table
+ tabp->Next = To_Table; // For loop checking
+ tdbp = cat->GetTable(g, tabp, Mode);
+ } // endif mysql
+
+ if (s) {
+ if (s->is_view && !b)
+ s->field = NULL;
+
+ hc->tshp = NULL;
+ } else if (b) {
+ // Restore s structure that can be in cache
+ hc->get_table()->field = fp;
+ hc->get_table()->s->option_struct->srcdef = sp;
+ } // endif s
+
+ if (trace(1) && tdbp)
+ htrc("Subtable %s in %s\n",
+ name, SVP(tdbp->GetDef()->GetDB()));
+
+ err:
+ if (s)
+ free_table_share(s);
+
+ return tdbp;
+ } // end of GetSubTable
+
+/***********************************************************************/
+/* Initializes the table. */
+/***********************************************************************/
+bool TDBPRX::InitTable(PGLOBAL g)
+ {
+ if (!Tdbp) {
+ // Get the table description block of this table
+ if (!(Tdbp = GetSubTable(g, ((PPRXDEF)To_Def)->Tablep)))
+ return true;
+
+// Tdbp->SetMode(Mode);
+ } // endif Tdbp
+
+ return false;
+ } // end of InitTable
+
+/***********************************************************************/
+/* Allocate PRX column description block. */
+/***********************************************************************/
+PCOL TDBPRX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) PRXCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* PRX Cardinality: returns the number of rows in the table. */
+/***********************************************************************/
+int TDBPRX::Cardinality(PGLOBAL g)
+ {
+ if (Cardinal < 0) {
+ if (InitTable(g))
+ return 0;
+
+ Cardinal = Tdbp->Cardinality(g);
+ } // endif MaxSize
+
+ return Cardinal;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* PRX GetMaxSize: returns the maximum number of rows in the table. */
+/***********************************************************************/
+int TDBPRX::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ if (InitTable(g))
+ return 0;
+
+ MaxSize = Tdbp->GetMaxSize(g);
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* In this sample, ROWID will be the (virtual) row number, */
+/* while ROWNUM will be the occurrence rank in the multiple column. */
+/***********************************************************************/
+int TDBPRX::RowNumber(PGLOBAL g, bool b)
+ {
+ return Tdbp->RowNumber(g, b);
+ } // end of RowNumber
+
+/***********************************************************************/
+/* PROXY Access Method opening routine. */
+/***********************************************************************/
+bool TDBPRX::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ return Tdbp->OpenDB(g);
+ } // endif use
+
+ if (InitTable(g))
+ return true;
+ else if (Mode != MODE_READ && (Read_Only || Tdbp->IsReadOnly())) {
+ strcpy(g->Message, "Cannot modify a read only table");
+ return true;
+ } // endif tp
+
+ /*********************************************************************/
+ /* Check and initialize the subtable columns. */
+ /*********************************************************************/
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (((PPRXCOL)cp)->Init(g, Tdbp))
+ return true;
+
+ /*********************************************************************/
+ /* In Update mode, the updated column blocks must be distinct from */
+ /* the read column blocks. So make a copy of the TDB and allocate */
+ /* its column blocks in mode write (required by XML tables). */
+ /*********************************************************************/
+ if (Mode == MODE_UPDATE) {
+ PTDB utp;
+
+ if (!(utp= Tdbp->Duplicate(g))) {
+ sprintf(g->Message, MSG(INV_UPDT_TABLE), Tdbp->GetName());
+ return true;
+ } // endif tp
+
+ for (PCOL cp = To_SetCols; cp; cp = cp->GetNext())
+ if (((PPRXCOL)cp)->Init(g, utp))
+ return true;
+
+ } else if (Mode == MODE_DELETE)
+ Tdbp->SetNext(Next);
+
+ /*********************************************************************/
+ /* Physically open the object table. */
+ /*********************************************************************/
+ if (Tdbp->OpenDB(g))
+ return true;
+
+ Tdbp->SetNext(NULL);
+ Use = USE_OPEN;
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for PROY access method. */
+/***********************************************************************/
+int TDBPRX::ReadDB(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Now start the reading process. */
+ /*********************************************************************/
+ return Tdbp->ReadDB(g);
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for PROXY access methods. */
+/***********************************************************************/
+int TDBPRX::WriteDB(PGLOBAL g)
+ {
+ return Tdbp->WriteDB(g);
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for PROXY access methods. */
+/***********************************************************************/
+int TDBPRX::DeleteDB(PGLOBAL g, int irc)
+ {
+ return Tdbp->DeleteDB(g, irc);
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Used by the TBL tables. */
+/***********************************************************************/
+void TDBPRX::RemoveNext(PTABLE tp)
+ {
+ tp->Next = NULL;
+ } // end of RemoveNext
+
+/* ---------------------------- PRXCOL ------------------------------- */
+
+/***********************************************************************/
+/* PRXCOL public constructor. */
+/***********************************************************************/
+PRXCOL::PRXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional Dos access method information for column.
+ Long = cdp->GetLong(); // Useful ???
+//strcpy(F_Date, cdp->F_Date);
+ Colp = NULL;
+ To_Val = NULL;
+ Pseudo = false;
+ Colnum = cdp->GetOffset(); // If columns are retrieved by number
+
+ if (trace(1))
+ htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
+
+ } // end of PRXCOL constructor
+
+/***********************************************************************/
+/* PRXCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+PRXCOL::PRXCOL(PRXCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Colp = col1->Colp;
+ To_Val = col1->To_Val;
+ Pseudo = col1->Pseudo;
+ Colnum = col1->Colnum;
+ } // end of PRXCOL copy constructor
+
+/***********************************************************************/
+/* Convert an UTF-8 name to latin characters. */
+/***********************************************************************/
+char *PRXCOL::Decode(PGLOBAL g, const char *cnm)
+ {
+ char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) + 1);
+ uint dummy_errors;
+ uint32 len= copy_and_convert(buf, strlen(cnm) + 1,
+ &my_charset_latin1,
+ cnm, strlen(cnm),
+ &my_charset_utf8mb3_general_ci,
+ &dummy_errors);
+ buf[len]= '\0';
+ return buf;
+ } // end of Decode
+
+/***********************************************************************/
+/* PRXCOL initialization routine. */
+/* Look for the matching column in the object table. */
+/***********************************************************************/
+bool PRXCOL::Init(PGLOBAL g, PTDB tp)
+ {
+ if (!tp)
+ tp = ((PTDBPRX)To_Tdb)->Tdbp;
+
+ if (!(Colp = tp->ColDB(g, Name, 0)) && Colnum)
+ Colp = tp->ColDB(g, NULL, Colnum);
+
+ if (Colp) {
+ MODE mode = To_Tdb->GetMode();
+
+ // Needed for MYSQL subtables
+ ((COLBLK*)Colp)->SetName(Decode(g, Colp->GetName()));
+
+ // May not have been done elsewhere
+ Colp->InitValue(g);
+ To_Val = Colp->GetValue();
+
+ if (mode == MODE_INSERT || mode == MODE_UPDATE)
+ if (Colp->SetBuffer(g, Colp->GetValue(), true, false))
+ return true;
+
+ // this may be needed by some tables (which?)
+ Colp->SetColUse(ColUse);
+ } else {
+ sprintf(g->Message, MSG(NO_MATCHING_COL), Name, tp->GetName());
+ return true;
+ } // endif Colp
+
+ return false;
+ } // end of Init
+
+/***********************************************************************/
+/* Reset the column descriptor to non evaluated yet. */
+/***********************************************************************/
+void PRXCOL::Reset(void)
+ {
+ if (Colp)
+ Colp->Reset();
+
+ Status &= ~BUF_READ;
+ } // end of Reset
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void PRXCOL::ReadColumn(PGLOBAL g)
+ {
+ if (trace(2))
+ htrc("PRX ReadColumn: name=%s\n", Name);
+
+ if (Colp) {
+ Colp->Eval(g);
+ Value->SetValue_pval(To_Val);
+
+ // Set null when applicable
+ if (Nullable)
+ Value->SetNull(Value->IsNull());
+
+ } else {
+ Value->Reset();
+
+ // Set null when applicable
+ if (Nullable)
+ Value->SetNull(true);
+
+ } // endif Colp
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: */
+/***********************************************************************/
+void PRXCOL::WriteColumn(PGLOBAL g)
+ {
+ if (trace(2))
+ htrc("PRX WriteColumn: name=%s\n", Name);
+
+ if (Colp) {
+ To_Val->SetValue_pval(Value);
+ Colp->WriteColumn(g);
+ } // endif Colp
+
+ } // end of WriteColumn
+
+/* ---------------------------TDBTBC class --------------------------- */
+
+/***********************************************************************/
+/* TDBTBC class constructor. */
+/***********************************************************************/
+TDBTBC::TDBTBC(PPRXDEF tdp) : TDBCAT(tdp)
+ {
+ Db = (PSZ)tdp->Tablep->GetSchema();
+ Tab = (PSZ)tdp->Tablep->GetName();
+ } // end of TDBTBC constructor
+
+/***********************************************************************/
+/* GetResult: Get the list the MYSQL table columns. */
+/***********************************************************************/
+PQRYRES TDBTBC::GetResult(PGLOBAL g)
+ {
+ bool b = false;
+
+ return TabColumns(g, current_thd, Db, Tab, b);
+ } // end of GetResult
+
diff --git a/storage/connect/tabutil.h b/storage/connect/tabutil.h
new file mode 100644
index 00000000..c8e7e751
--- /dev/null
+++ b/storage/connect/tabutil.h
@@ -0,0 +1,155 @@
+// TABUTIL.H Olivier Bertrand 2013
+// Defines the TAB catalog tables
+
+#ifndef TABUTIL
+#define TABUTIL 1
+
+//#include "tabtbl.h"
+
+typedef class PRXDEF *PPRXDEF;
+typedef class TDBPRX *PTDBPRX;
+typedef class XXLCOL *PXXLCOL;
+typedef class PRXCOL *PPRXCOL;
+typedef class TBCDEF *PTBCDEF;
+typedef class TDBTBC *PTDBTBC;
+
+TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db,
+ const char *name, bool& mysql);
+PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
+ const char *name, bool& info);
+
+TABLE_SHARE *Remove_tshp(PCATLG cat);
+void Restore_tshp(PCATLG cat, TABLE_SHARE *s);
+
+/* -------------------------- PROXY classes -------------------------- */
+
+/***********************************************************************/
+/* PROXY: table based on another table. Can be used to have a */
+/* different view on an existing table. */
+/* However, its real use is to be the base of TBL and PRX tables. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* PRX table. */
+/***********************************************************************/
+class DllExport PRXDEF : public TABDEF { /* Logical table description */
+ friend class TDBPRX;
+ friend class TDBTBC;
+ public:
+ // Constructor
+ PRXDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "PRX";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE mode);
+
+ protected:
+ // Members
+ PTABLE Tablep; /* The object table */
+ }; // end of PRXDEF
+
+/***********************************************************************/
+/* This is the class declaration for the XCSV table. */
+/***********************************************************************/
+class DllExport TDBPRX : public TDBASE {
+ friend class PRXDEF;
+ friend class PRXCOL;
+ public:
+ // Constructors
+ TDBPRX(PPRXDEF tdp);
+ TDBPRX(PTDBPRX tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_PRX;}
+ virtual PTDB Duplicate(PGLOBAL g)
+ {return (PTDB)new(g) TDBPRX(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual int GetRecpos(void) {return Tdbp->GetRecpos();}
+ virtual void ResetDB(void) {Tdbp->ResetDB();}
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE);
+ virtual PCSZ GetServer(void) {return (Tdbp) ? Tdbp->GetServer() : (PSZ)"?";}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual bool InitTable(PGLOBAL g);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g) {if (Tdbp) Tdbp->CloseDB(g);}
+ PTDB GetSubTable(PGLOBAL g, PTABLE tabp, bool b = false);
+ void RemoveNext(PTABLE tp);
+
+ protected:
+ // Members
+ PTDB Tdbp; // The object table
+ }; // end of class TDBPRX
+
+/***********************************************************************/
+/* Class PRXCOL: PRX access method column descriptor. */
+/* This A.M. is used for PRX tables. */
+/***********************************************************************/
+class DllExport PRXCOL : public COLBLK {
+ friend class TDBPRX;
+ friend class TDBTBL;
+ friend class TDBOCCUR;
+ public:
+ // Constructors
+ PRXCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "PRX");
+ PRXCOL(PRXCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_PRX;}
+
+ // Methods
+ using COLBLK::Init;
+ virtual void Reset(void);
+ virtual bool IsSpecial(void) {return Pseudo;}
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+ {return false;}
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ virtual bool Init(PGLOBAL g, PTDB tp);
+
+ protected:
+ char *Decode(PGLOBAL g, const char *cnm);
+
+ // Default constructor not to be used
+ PRXCOL(void) {}
+
+ // Members
+ PCOL Colp; // Points to matching table column
+ PVAL To_Val; // To the matching column value
+ bool Pseudo; // TRUE for special columns
+ int Colnum; // Used when retrieving columns by number
+ }; // end of class PRXCOL
+
+/***********************************************************************/
+/* This is the class declaration for the TBC column catalog table. */
+/***********************************************************************/
+class TDBTBC : public TDBCAT {
+ public:
+ // Constructors
+ TDBTBC(PPRXDEF tdp);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PSZ Db; // Database of the table
+ PSZ Tab; // Table name
+ }; // end of class TDBMCL
+
+class XCOLBLK : public COLBLK {
+ friend class PRXCOL;
+}; // end of class XCOLBLK
+
+#endif // TABUTIL
diff --git a/storage/connect/tabvct.cpp b/storage/connect/tabvct.cpp
new file mode 100644
index 00000000..9cf5f41d
--- /dev/null
+++ b/storage/connect/tabvct.cpp
@@ -0,0 +1,588 @@
+/************* TabVct C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABVCT */
+/* ------------- */
+/* Version 3.9 */
+/* */
+/* COPYRIGHT: */
+/* ---------- */
+/* (C) Copyright to the author Olivier BERTRAND 1999-2017 */
+/* */
+/* WHAT THIS PROGRAM DOES: */
+/* ----------------------- */
+/* This is the TDBVCT and VCTCOL classes implementation routines. */
+/* */
+/* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
+/* -------------------------------------- */
+/* */
+/* REQUIRED FILES: */
+/* --------------- */
+/* TABVCT.C - Source code */
+/* PLGDBSEM.H - DB application declaration file */
+/* TABDOS.H - TABDOS classes declaration file */
+/* GLOBAL.H - Global declaration file */
+/* */
+/* REQUIRED LIBRARIES: */
+/* ------------------- */
+/* Large model C library */
+/* */
+/* REQUIRED PROGRAMS: */
+/* ------------------ */
+/* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */
+/* */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#include <sys/stat.h>
+#else
+#if defined(UNIX)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#define NO_ERROR 0
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tabdos.h is header containing the TABDOS class declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "reldef.h"
+#include "osutil.h"
+#include "filamvct.h"
+#include "tabdos.h"
+#include "tabvct.h"
+#include "valblk.h"
+
+#if defined(UNIX)
+//add dummy strerror (NGC)
+char *strerror(int num);
+#endif // UNIX
+
+/***********************************************************************/
+/* External function. */
+/***********************************************************************/
+USETEMP UseTemp(void);
+
+/***********************************************************************/
+/* Char VCT column blocks are right filled with blanks (blank = true) */
+/* Conversion of block values allowed conditionally for insert only. */
+/***********************************************************************/
+PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
+ bool check = true, bool blank = true, bool un = false);
+
+
+/* --------------------------- Class VCTDEF -------------------------- */
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool VCTDEF::DefineAM(PGLOBAL g, LPCSTR, int poff)
+ {
+ DOSDEF::DefineAM(g, "BIN", poff);
+
+ if ((Estimate = GetIntCatInfo("Estimate", 0)))
+ Elemt = MY_MIN(Elemt, Estimate);
+
+ // Split treated as INT to get default value
+ Split = GetIntCatInfo("Split", (Estimate) ? 0 : 1);
+ Header = GetIntCatInfo("Header", 0);
+
+ // CONNECT must have Block/Last info for VEC tables
+ if (Estimate && !Split && !Header) {
+ char *fn = GetStringCatInfo(g, "Filename", "?");
+
+ // No separate header file for urbi tables
+ Header = (*fn == '?') ? 3 : 2;
+ } // endif Estimate
+
+ Recfm = RECFM_VCT;
+
+ // poff is no more in use; This will have to be revisited
+#if 0
+ // For packed files the logical record length is calculated in poff
+ if (poff != Lrecl) {
+ Lrecl = poff;
+ SetIntCatInfo("Lrecl", poff);
+ } // endif poff
+#endif // 0
+
+ Padded = false;
+ Blksize = 0;
+ return false;
+ } // end of DefineAM
+
+#if 0
+/***********************************************************************/
+/* Erase: This was made a separate routine because a strange thing */
+/* happened when DeleteTablefile was defined for the VCTDEF class: */
+/* when called from Catalog, the DOSDEF routine was still called even */
+/* for a VCTDEF class. It also minimizes the specific code. */
+/***********************************************************************/
+bool VCTDEF::Erase(char *filename)
+ {
+ bool rc = false;
+
+ if (Split) {
+ char fpat[_MAX_PATH];
+ int i;
+ PCOLDEF cdp;
+
+ MakeFnPattern(fpat);
+
+ for (i = 1, cdp = To_Cols; cdp; i++, cdp = cdp->GetNext()) {
+ sprintf(filename, fpat, i);
+//#if defined(_WIN32)
+// rc |= !DeleteFile(filename);
+//#else // UNIX
+ rc |= remove(filename);
+//#endif // UNIX
+ } // endfor cdp
+
+ } else {
+ rc = DOSDEF::Erase(filename);
+
+ if (Estimate && Header == 2) {
+ PlugSetPath(filename, Fn, GetPath());
+ strcat(PlugRemoveType(filename, filename), ".blk");
+ rc |= remove(filename);
+ } // endif Header
+
+ } // endif Split
+
+ return rc; // Return true if error
+ } // end of Erase
+#endif // 0
+
+/***********************************************************************/
+/* Prepare the column file name pattern for a split table. */
+/* This function returns the number of columns of the table. */
+/***********************************************************************/
+int VCTDEF::MakeFnPattern(char *fpat)
+ {
+ char pat[16];
+#if defined(_WIN32)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ftype[_MAX_EXT]; // File extention
+ int n, m, ncol = 0;
+ PCOLDEF cdp;
+
+ for (cdp = To_Cols; cdp; cdp = cdp->GetNext())
+ ncol++;
+
+ for (n = 1, m = ncol; m /= 10; n++) ;
+
+ sprintf(pat, "%%0%dd", n);
+ _splitpath(Fn, drive, direc, fname, ftype);
+ strcat(fname, pat);
+ _makepath(fpat, drive, direc, fname, ftype);
+ PlugSetPath(fpat, fpat, GetPath());
+ return ncol;
+ } // end of MakeFnPattern
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB VCTDEF::GetTable(PGLOBAL g, MODE mode)
+ {
+ /*********************************************************************/
+ /* Allocate a TDB of the proper type. */
+ /* Column blocks will be allocated only when needed. */
+ /*********************************************************************/
+ // Mapping not used for insert (except for true VEC not split tables)
+ // or when UseTemp is forced
+ bool map = Mapped && (Estimate || mode != MODE_INSERT) &&
+ !(UseTemp() == TMP_FORCE &&
+ (mode == MODE_UPDATE || mode == MODE_DELETE));
+ PTXF txfp;
+ PTDB tdbp;
+
+ if (Multiple) {
+ strcpy(g->Message, MSG(NO_MUL_VCT));
+ return NULL;
+ } // endif Multiple
+
+ if (Split) {
+ if (map)
+ txfp = new(g) VMPFAM(this);
+ else
+ txfp = new(g) VECFAM(this);
+
+ } else if (Huge)
+ txfp = new(g) BGVFAM(this);
+ else if (map)
+ txfp = new(g) VCMFAM(this);
+ else
+ txfp = new(g) VCTFAM(this);
+
+ tdbp = new(g) TDBVCT(this, txfp);
+
+ /*********************************************************************/
+ /* For block tables, get eventually saved optimization values. */
+ /*********************************************************************/
+ if (mode != MODE_INSERT)
+ if (tdbp->GetBlockValues(g))
+ PushWarning(g, tdbp);
+// return NULL; // causes a crash when deleting index
+
+ return tdbp;
+ } // end of GetTable
+
+/* --------------------------- Class TDBVCT -------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBVCT class. */
+/***********************************************************************/
+TDBVCT::TDBVCT(PVCTDEF tdp, PTXF txfp) : TDBFIX(tdp, txfp)
+ {
+ To_SetCols = NULL;
+ } // end of TDBVCT standard constructor
+
+TDBVCT::TDBVCT(PGLOBAL g, PTDBVCT tdbp) : TDBFIX(g, tdbp)
+ {
+ To_SetCols = tdbp->To_SetCols;
+ } // end of TDBVCT copy constructor
+
+// Method
+PTDB TDBVCT::Clone(PTABS t)
+ {
+ PTDB tp;
+ PVCTCOL cp1, cp2;
+ PGLOBAL g = t->G; // Is this really useful ???
+
+ tp = new(g) TDBVCT(g, this);
+
+ for (cp1 = (PVCTCOL)Columns; cp1; cp1 = (PVCTCOL)cp1->Next) {
+ cp2 = new(g) VCTCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Allocate VCT column description block. */
+/***********************************************************************/
+PCOL TDBVCT::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ return new(g) VCTCOL(g, cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* VEC tables are not ready yet to use temporary files. */
+/***********************************************************************/
+bool TDBVCT::IsUsingTemp(PGLOBAL)
+ {
+ // For developpers
+ return (UseTemp() == TMP_TEST);
+ } // end of IsUsingTemp
+
+/***********************************************************************/
+/* VCT Access Method opening routine. */
+/* New method now that this routine is called recursively (last table */
+/* first in reverse order): index blocks are immediately linked to */
+/* join block of next table if it exists or else are discarted. */
+/***********************************************************************/
+bool TDBVCT::OpenDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("VCT OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d\n",
+ this, Tdb_No, Use, To_Key_Col, Mode);
+
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ if (To_Kindex)
+ // Table is to be accessed through a sorted index table
+ To_Kindex->Reset();
+
+ Txfp->Rewind();
+ ResetBlockFilter(g);
+ return false;
+ } // endif Use
+
+ /*********************************************************************/
+ /* Delete all is not handled using file mapping. */
+ /*********************************************************************/
+ if (Mode == MODE_DELETE && !Next && Txfp->GetAmType() == TYPE_AM_VMP) {
+ if (IsSplit())
+ Txfp = new(g) VECFAM((PVCTDEF)To_Def);
+ else
+ Txfp = new(g) VCTFAM((PVCTDEF)To_Def);
+
+ Txfp->SetTdbp(this);
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Open according to input/output mode required and */
+ /* allocate the block buffers for columns used in the query. */
+ /*********************************************************************/
+ if (Txfp->OpenTableFile(g))
+ return true;
+
+ // This was not done in previous version
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Allocate the block filter tree if evaluation is possible. */
+ /*********************************************************************/
+ To_BlkFil = InitBlockFilter(g, To_Filter);
+
+ /*********************************************************************/
+ /* Reset buffer access according to indexing and to mode. */
+ /*********************************************************************/
+ Txfp->ResetBuffer(g);
+
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for VCT access method. */
+/* This routine just set the new block index and record position. */
+/* For index accessed tables the physical reading is deferred to the */
+/* ReadColumn routine so only really used column are physically read. */
+/***********************************************************************/
+int TDBVCT::ReadDB(PGLOBAL g)
+ {
+ if (trace(1))
+ htrc("VCT ReadDB: R%d Mode=%d CurBlk=%d CurNum=%d key=%p link=%p Kindex=%p\n",
+ GetTdb_No(), Mode, Txfp->CurBlk, Txfp->CurNum,
+ To_Key_Col, To_Link, To_Kindex);
+
+ if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ int recpos = To_Kindex->Fetch(g);
+
+ switch (recpos) {
+ case -1: // End of file reached
+ return RC_EF;
+ case -2: // No match for join
+ return RC_NF;
+ case -3: // Same record as last non null one
+// num_there++;
+ return RC_OK;
+ default:
+ /***************************************************************/
+ /* Set the file position according to record to read. */
+ /***************************************************************/
+ if (SetRecpos(g, recpos))
+ return RC_FX;
+
+ } // endswitch recpos
+
+ } // endif To_Kindex
+
+ return ReadBuffer(g);
+ } // end of ReadDB
+
+/***********************************************************************/
+/* Data Base close routine for VEC access method. */
+/***********************************************************************/
+void TDBVCT::CloseDB(PGLOBAL g)
+ {
+ if (To_Kindex) {
+ To_Kindex->Close();
+ To_Kindex = NULL;
+ } // endif
+
+ Txfp->CloseTableFile(g, false);
+ } // end of CloseDB
+
+// ------------------------ VCTCOL functions ----------------------------
+
+/***********************************************************************/
+/* VCTCOL public constructor. */
+/***********************************************************************/
+VCTCOL::VCTCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : DOSCOL(g, cdp, tdbp, cprec, i, "VCT")
+ {
+ Deplac = cdp->GetPoff();
+ Clen = cdp->GetClen(); // Length of the field in the file
+ ColBlk = -1;
+ ColPos = -1;
+ Blk = NULL;
+ Modif = 0;
+ } // end of VCTCOL constructor
+
+/***********************************************************************/
+/* VCTCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+VCTCOL::VCTCOL(VCTCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
+ {
+ ColBlk = col1->ColBlk;
+ ColPos = col1->ColPos;
+ Blk = col1->Blk; // Should be NULL when copying ????
+ Modif = col1->Modif; // Should be 0 ????
+ } // end of VCTCOL copy constructor
+
+/***********************************************************************/
+/* SetBuffer: allocate and set the buffers needed for write operation.*/
+/***********************************************************************/
+bool VCTCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+ {
+ // Eventual conversion will be done when setting ValBlk from Value.
+ Value = value; // Force To_Val == Value
+
+ if (DOSCOL::SetBuffer(g, value, ok, check))
+ return true;
+
+ if (To_Tdb->GetMode() != MODE_INSERT) {
+ // Allocate the block buffer to use for read/writing except when
+ // updating a mapped VCT table and Ok is true.
+ PTDBVCT tdbp = (PTDBVCT)To_Tdb;
+
+ if (tdbp->Txfp->GetAmType() == TYPE_AM_VMP && ok) {
+ Blk = AllocValBlock(g, (void*)1, Buf_Type, tdbp->Txfp->Nrec,
+ Format.Length, Format.Prec, check, true, Unsigned);
+ Status |= BUF_MAPPED; // Will point into mapped file
+ } else
+ Blk = AllocValBlock(g, NULL, Buf_Type, tdbp->Txfp->Nrec,
+ Format.Length, Format.Prec, check, true, Unsigned);
+ } // endif Mode
+
+ return false;
+ } // end of SetBuffer
+
+/***********************************************************************/
+/* ReadBlock: Indicate it is Ok to make updates. */
+/***********************************************************************/
+void VCTCOL::SetOk(void)
+ {
+ if (((PTDBVCT)To_Tdb)->Txfp->GetAmType() == TYPE_AM_VMP)
+ Status |= BUF_MAPPED;
+
+ Status |= BUF_EMPTY;
+ Modif = 0;
+ } // end of SetOk
+
+/***********************************************************************/
+/* ReadBlock: Read column values from current block. */
+/***********************************************************************/
+void VCTCOL::ReadBlock(PGLOBAL g)
+ {
+ PVCTFAM txfp = (PVCTFAM)((PTDBVCT)To_Tdb)->Txfp;
+
+#if defined(_DEBUG)
+ if (!Blk) {
+ strcpy(g->Message, MSG(TO_BLK_IS_NULL));
+ throw 58;
+ } // endif
+#endif
+
+ /*********************************************************************/
+ /* Read column block according to used access method. */
+ /*********************************************************************/
+ if (txfp->ReadBlock(g, this))
+ throw 6;
+
+ ColBlk = txfp->CurBlk;
+ ColPos = -1; // Any invalid position
+ } // end of ReadBlock
+
+/***********************************************************************/
+/* WriteBlock: Write back current column values for one block. */
+/* Note: the test of Status is meant to prevent physical writing of */
+/* the block during the checking loop in mode Update. It is set to */
+/* BUF_EMPTY when reopening the table between the two loops. */
+/***********************************************************************/
+void VCTCOL::WriteBlock(PGLOBAL g)
+ {
+ if (Modif && (Status & BUF_EMPTY)) {
+ PVCTFAM txfp = (PVCTFAM)((PTDBVCT)To_Tdb)->Txfp;
+
+#if defined(_DEBUG)
+ if (!Blk) {
+ strcpy(g->Message, MSG(BLK_IS_NULL));
+ throw 56;
+ } // endif
+#endif
+
+ /*******************************************************************/
+ /* Write column block according to used access method. */
+ /*******************************************************************/
+ if (txfp->WriteBlock(g, this))
+ throw 6;
+
+ Modif = 0;
+ } // endif Modif
+
+ } // end of WriteBlock
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to check whether a column */
+/* block has been read from the file, then to extract from it the */
+/* field corresponding to this column and convert it to buffer type. */
+/***********************************************************************/
+void VCTCOL::ReadColumn(PGLOBAL g)
+ {
+ PTXF txfp = ((PTDBVCT)To_Tdb)->Txfp;
+
+#if defined(_DEBUG)
+ assert (!To_Kcol);
+#endif
+
+ if (trace(2))
+ htrc("VCT ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n",
+ Name, To_Tdb->GetTdb_No(), ColUse, Status, Buf_Type);
+
+ if (ColBlk != txfp->CurBlk)
+ ReadBlock(g);
+ else if (ColPos == txfp->CurNum)
+ return; // Value is already there
+
+//ColBlk = txfp->CurBlk; done in ReadBlock
+ ColPos = txfp->CurNum;
+ Value->SetValue_pvblk(Blk, ColPos);
+
+ // Set null when applicable
+ if (Nullable)
+ Value->SetNull(Value->IsZero());
+
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: Modifications are written back into column buffer. */
+/* On each change of block the buffer is written back to file and */
+/* in mode Insert the buffer is filled with the block to update. */
+/***********************************************************************/
+void VCTCOL::WriteColumn(PGLOBAL)
+ {
+ PTXF txfp = ((PTDBVCT)To_Tdb)->Txfp;;
+
+ if (trace(2))
+ htrc("VCT WriteColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n",
+ Name, To_Tdb->GetTdb_No(), ColUse, Status, Buf_Type);
+
+ ColBlk = txfp->CurBlk;
+ ColPos = txfp->CurNum;
+ Blk->SetValue(Value, ColPos);
+ Modif++;
+ } // end of WriteColumn
+
+/* ------------------------ End of TabVct ---------------------------- */
diff --git a/storage/connect/tabvct.h b/storage/connect/tabvct.h
new file mode 100644
index 00000000..189a9ae2
--- /dev/null
+++ b/storage/connect/tabvct.h
@@ -0,0 +1,124 @@
+/*************** TabVct H Declares Source Code File (.H) ***************/
+/* Name: TABVCT.H Version 3.4 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1999-2011 */
+/* */
+/* This file contains the TDBVCT class declares. */
+/***********************************************************************/
+#ifndef __TABVCT__
+#define __TABVCT__
+
+#include "tabfix.h"
+#if defined(UNIX)
+//#include <string.h.SUNWCCh>
+#endif
+
+typedef class TDBVCT *PTDBVCT;
+typedef class VCTCOL *PVCTCOL;
+
+/***********************************************************************/
+/* VCT table. */
+/***********************************************************************/
+class DllExport VCTDEF : public DOSDEF { /* Logical table description */
+ friend class TDBVCT;
+ friend class VCTFAM;
+ friend class VECFAM;
+ friend class VMPFAM;
+ public:
+ // Constructor
+ VCTDEF(void) {Split = false; Estimate = Header = 0;}
+
+ // Implementation
+ virtual const char *GetType(void) {return "VCT";}
+ int GetEstimate(void) {return Estimate;}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE mode);
+
+ protected:
+ int MakeFnPattern(char *fpat);
+
+ // Members
+ bool Split; /* Columns in separate files */
+ int Estimate; /* Estimated maximum size of table */
+ int Header; /* 0: no, 1: separate, 2: in data file */
+ }; // end of VCTDEF
+
+/***********************************************************************/
+/* This is the DOS/UNIX Access Method class declaration for files */
+/* in blocked vector format. In each block containing "Elements" */
+/* records, values of each columns are consecutively stored (vector). */
+/***********************************************************************/
+class DllExport TDBVCT : public TDBFIX {
+ friend class VCTCOL;
+ friend class VCTFAM;
+ friend class VCMFAM;
+ friend class VECFAM;
+ friend class VMPFAM;
+ public:
+ // Constructors
+ TDBVCT(PVCTDEF tdp, PTXF txfp);
+ TDBVCT(PGLOBAL g, PTDBVCT tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_VCT;}
+ virtual PTDB Duplicate(PGLOBAL g)
+ {return (PTDB)new(g) TDBVCT(g, this);}
+ bool IsSplit(void) {return ((VCTDEF*)To_Def)->Split;}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual bool IsUsingTemp(PGLOBAL g);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual void CloseDB(PGLOBAL g);
+
+ protected:
+ // Members
+ }; // end of class TDBVCT
+
+/***********************************************************************/
+/* Class VCTCOL: VCT access method column descriptor. */
+/* This A.M. is used for file having column wise organization. */
+/***********************************************************************/
+class DllExport VCTCOL : public DOSCOL {
+ friend class TDBVCT;
+ friend class VCTFAM;
+ friend class VCMFAM;
+ friend class VECFAM;
+ friend class VMPFAM;
+ friend class BGVFAM;
+ public:
+ // Constructors
+ VCTCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
+ VCTCOL(VCTCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_VCT;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void SetOk(void);
+
+ protected:
+ virtual void ReadBlock(PGLOBAL g);
+ virtual void WriteBlock(PGLOBAL g);
+
+ VCTCOL(void) {} // Default constructor not to be used
+
+ // Members
+ PVBLK Blk; // Block buffer
+ int Clen; // Internal length in table
+ int ColBlk; // Block pointed by column
+ int ColPos; // Last position read
+ int Modif; // Number of modified lines in block
+ }; // end of class VCTCOL
+
+#endif // __TABVCT__
+
diff --git a/storage/connect/tabvir.cpp b/storage/connect/tabvir.cpp
new file mode 100644
index 00000000..2fdb7f64
--- /dev/null
+++ b/storage/connect/tabvir.cpp
@@ -0,0 +1,305 @@
+/************* tdbvir C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: tdbvir.cpp Version 1.2 */
+/* (C) Copyright to the author Olivier BERTRAND 2014-2017 */
+/* This program are the VIR classes DB execution routines. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* xtable.h is header containing the TDBASE declarations. */
+/* tdbvir.h is header containing the VIR classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "filter.h"
+#include "xtable.h"
+//#include "reldef.h"
+#include "colblk.h"
+#include "mycat.h" // for FNC_COL
+#include "tabvir.h"
+#include "resource.h" // for IDS_COLUMNS
+
+/***********************************************************************/
+/* Return the unique column definition to MariaDB. */
+/***********************************************************************/
+PQRYRES VirColumns(PGLOBAL g, bool info)
+ {
+ int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
+ TYPE_INT, TYPE_STRING, TYPE_STRING};
+ XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME,
+ FLD_PREC, FLD_KEY, FLD_EXTRA};
+ unsigned int length[] = {8, 4, 16, 4, 16, 16};
+ int i, n, ncol = sizeof(buftyp) / sizeof(int);
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ n = (info) ? 0 : 1;
+
+ /**********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /**********************************************************************/
+ if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, true)))
+ return NULL;
+
+ // Some columns must be renamed before info
+ for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
+ switch (++i) {
+ case 5: crp->Name = "Key"; break;
+ case 6: crp->Name = "Extra"; break;
+ } // endswitch i
+
+ if (info)
+ return qrp;
+
+ /**********************************************************************/
+ /* Now get the results into blocks. */
+ /**********************************************************************/
+ // Set column name
+ crp = qrp->Colresp; // Column_Name
+ crp->Kdata->SetValue("n", 0);
+
+ // Set type, type name, precision
+ crp = crp->Next; // Data_Type
+ crp->Kdata->SetValue(TYPE_INT, 0);
+
+ crp = crp->Next; // Type_Name
+ crp->Kdata->SetValue(GetTypeName(TYPE_INT), 0);
+
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(11, 0);
+
+ crp = crp->Next; // Key
+ crp->Kdata->SetValue("KEY", 0);
+
+ crp = crp->Next; // Extra
+ crp->Kdata->SetValue("SPECIAL=ROWID", 0);
+
+ qrp->Nblin = 1;
+
+ /**********************************************************************/
+ /* Return the result pointer for use by discovery routines. */
+ /**********************************************************************/
+ return qrp;
+ } // end of VirColumns
+
+/* --------------------------- Class VIRDEF --------------------------- */
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB VIRDEF::GetTable(PGLOBAL g, MODE)
+ {
+ // Column blocks will be allocated only when needed.
+ if (Catfunc == FNC_COL)
+ return new(g) TDBVICL(this);
+ else
+ return new(g) TDBVIR(this);
+
+ } // end of GetTable
+
+/* ------------------------ TDBVIR functions ------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBVIR class. */
+/***********************************************************************/
+TDBVIR::TDBVIR(PVIRDEF tdp) : TDBASE(tdp)
+ {
+ Size = (tdp->GetElemt()) ? tdp->GetElemt() : 1;
+ N = -1;
+ } // end of TDBVIR constructor
+
+/***********************************************************************/
+/* Analyze the filter and reset the size limit accordingly. */
+/* This is possible when a filter contains predicates implying the */
+/* special column ROWID. Here we just test for when no more good */
+/* records can be met in the remaining of the table. */
+/***********************************************************************/
+int TDBVIR::TestFilter(PFIL filp, bool nop)
+ {
+ int i, op = filp->GetOpc(), n = 0, type[2] = {0,0};
+ int l1 = 0, l2, limit = Size;
+ PXOB arg[2] = {NULL,NULL};
+
+ if (op == OP_GT || op == OP_GE || op == OP_LT || op == OP_LE) {
+ for (i = 0; i < 2; i++) {
+ arg[i] = filp->Arg(i);
+
+ switch (filp->GetArgType(i)) {
+ case TYPE_CONST:
+ if ((l1 = arg[i]->GetIntValue()) >= 0)
+ type[i] = 1;
+
+ break;
+ case TYPE_COLBLK:
+ if (((PCOL)arg[i])->GetTo_Tdb() == this &&
+ ((PCOL)arg[i])->GetAmType() == TYPE_AM_ROWID)
+ type[i] = 2;
+
+ break;
+ default:
+ break;
+ } // endswitch ArgType
+
+ if (!type[i])
+ break;
+
+ n += type[i];
+ } // endfor i
+
+ if (n == 3) {
+ // If true it will be ok to delete the filter
+ BOOL ok = (filp == To_Filter);
+
+ if (type[0] == 1)
+ // Make it always a Column-op-Value
+ switch (op) {
+ case OP_GT: op = OP_LT; break;
+ case OP_GE: op = OP_LE; break;
+ case OP_LT: op = OP_GT; break;
+ case OP_LE: op = OP_GE; break;
+ } // endswitch op
+
+ if (!nop) switch (op) {
+ case OP_LT: l1--; /* fall through */
+ case OP_LE: limit = l1; break;
+ default: ok = false;
+ } // endswitch op
+
+ else switch (op) {
+ case OP_GE: l1--; /* fall through */
+ case OP_GT: limit = l1; break;
+ default: ok = false;
+ } // endswitch op
+
+ limit = MY_MIN(MY_MAX(0, limit), Size);
+
+ // Just one where clause such as Rowid < limit;
+ if (ok)
+ To_Filter = NULL;
+
+ } else
+ limit = Size;
+
+ } else if ((op == OP_AND && !nop) || (op == OP_OR && nop)) {
+ l1 = TestFilter((PFIL)filp->Arg(0), nop);
+ l2 = TestFilter((PFIL)filp->Arg(1), nop);
+ limit = MY_MIN(l1, l2);
+ } else if (op == OP_NOT)
+ limit = TestFilter((PFIL)filp->Arg(0), !nop);
+
+ return limit;
+ } // end of TestFilter
+
+/***********************************************************************/
+/* Allocate source column description block. */
+/***********************************************************************/
+PCOL TDBVIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PCOL colp = NULL;
+
+ if (cdp->IsVirtual()) {
+ colp = new(g) VIRCOL(cdp, this, cprec, n);
+ } else strcpy(g->Message,
+ "Virtual tables accept only special or virtual columns");
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* VIR Access Method opening routine. */
+/***********************************************************************/
+bool TDBVIR::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ // Table already open
+ N = -1;
+ return false;
+ } // endif use
+
+ if (Mode != MODE_READ) {
+ strcpy(g->Message, "Virtual tables are read only");
+ return true;
+ } // endif Mode
+
+ /*********************************************************************/
+ /* Analyze the filter and refine Size accordingly. */
+ /*********************************************************************/
+ if (To_Filter)
+ Size = TestFilter(To_Filter, false);
+
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for the VIR access method. */
+/***********************************************************************/
+int TDBVIR::ReadDB(PGLOBAL)
+ {
+ return (++N >= Size) ? RC_EF : RC_OK;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for the VIR access methods. */
+/***********************************************************************/
+int TDBVIR::WriteDB(PGLOBAL g)
+ {
+ sprintf(g->Message, MSG(VIR_READ_ONLY), To_Def->GetType());
+ return RC_FX;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for the VIR access methods. */
+/***********************************************************************/
+int TDBVIR::DeleteDB(PGLOBAL g, int)
+ {
+ sprintf(g->Message, MSG(VIR_NO_DELETE), To_Def->GetType());
+ return RC_FX;
+ } // end of DeleteDB
+
+/* ---------------------------- VIRCOL ------------------------------- */
+
+/***********************************************************************/
+/* VIRCOL public constructor. */
+/***********************************************************************/
+VIRCOL::VIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ } // end of VIRCOL constructor
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void VIRCOL::ReadColumn(PGLOBAL g)
+ {
+ // This should never be called
+ sprintf(g->Message, "ReadColumn: Column %s is not virtual", Name);
+ throw (int)TYPE_COLBLK;
+} // end of ReadColumn
+
+/* ---------------------------TDBVICL class -------------------------- */
+
+/***********************************************************************/
+/* GetResult: Get the list the VIRTUAL table columns. */
+/***********************************************************************/
+PQRYRES TDBVICL::GetResult(PGLOBAL g)
+ {
+ return VirColumns(g, false);
+ } // end of GetResult
+
+/* ------------------------- End of Virtual -------------------------- */
diff --git a/storage/connect/tabvir.h b/storage/connect/tabvir.h
new file mode 100644
index 00000000..e7313bba
--- /dev/null
+++ b/storage/connect/tabvir.h
@@ -0,0 +1,110 @@
+/**************** tdbvir H Declares Source Code File (.H) **************/
+/* Name: TDBVIR.H Version 1.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2006-2014 */
+/* */
+/* This file contains the VIR classes declare code. */
+/***********************************************************************/
+typedef class VIRDEF *PVIRDEF;
+typedef class TDBVIR *PTDBVIR;
+
+/***********************************************************************/
+/* Return the unique column definition to MariaDB. */
+/***********************************************************************/
+PQRYRES VirColumns(PGLOBAL g, bool info);
+
+/* --------------------------- VIR classes --------------------------- */
+
+/***********************************************************************/
+/* VIR: Virtual table used to select constant values. */
+/***********************************************************************/
+class DllExport VIRDEF : public TABDEF { /* Logical table description */
+ public:
+ // Constructor
+ VIRDEF(void) {}
+
+ // Implementation
+ virtual const char *GetType(void) {return "VIRTUAL";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL, LPCSTR, int) {Pseudo = 3; return false;}
+ virtual int Indexable(void) {return 3;}
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ }; // end of VIRDEF
+
+/***********************************************************************/
+/* This is the class declaration for the Virtual table. */
+/***********************************************************************/
+class DllExport TDBVIR : public TDBASE {
+ public:
+ // Constructors
+ TDBVIR(PVIRDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_VIR;}
+
+ // Methods
+ virtual int GetRecpos(void) {return N;}
+ virtual bool SetRecpos(PGLOBAL g, int recpos)
+ {N = recpos - 2; return false;}
+ virtual int RowNumber(PGLOBAL g, bool b = false) {return N + 1;}
+ int TestFilter(PFIL filp, bool nop);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g) {return (g) ? Size : 1;}
+ virtual int GetMaxSize(PGLOBAL g) {return Size;}
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g) {}
+
+ protected:
+ // Members
+ int Size; // Table size
+ int N; // The VIR table current position
+ }; // end of class TDBVIR
+
+/***********************************************************************/
+/* Class VIRCOL: VIRTUAL access method column descriptor. */
+/***********************************************************************/
+class VIRCOL : public COLBLK {
+ friend class TDBVIR;
+ public:
+ // Constructors
+ VIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "VIRTUAL");
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_VIR;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ // Default constructor not to be used
+ VIRCOL(void) {}
+
+ // No additional members
+ }; // end of class VIRCOL
+
+/***********************************************************************/
+/* This is the class declaration for the VIR column catalog table. */
+/***********************************************************************/
+class TDBVICL : public TDBCAT {
+ public:
+ // Constructor
+ TDBVICL(PVIRDEF tdp) : TDBCAT(tdp) {}
+
+ // Methods
+ virtual int Cardinality(PGLOBAL g) {return 2;} // Avoid DBUG_ASSERT
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ }; // end of class TDBVICL
diff --git a/storage/connect/tabwmi.cpp b/storage/connect/tabwmi.cpp
new file mode 100644
index 00000000..a6aab7d2
--- /dev/null
+++ b/storage/connect/tabwmi.cpp
@@ -0,0 +1,851 @@
+/***********************************************************************/
+/* TABWMI: Author Olivier Bertrand -- PlugDB -- 2012 - 2017 */
+/* TABWMI: Virtual table to get WMI information. */
+/***********************************************************************/
+#if !defined(_WIN32)
+#error This is a WINDOWS only table type
+#endif // !_WIN32
+#include "my_global.h"
+#include <stdio.h>
+
+#include "global.h"
+#include "plgdbsem.h"
+#include "mycat.h"
+//#include "reldef.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "colblk.h"
+//#include "filter.h"
+//#include "xindex.h"
+#include "tabwmi.h"
+#include "valblk.h"
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+
+/* ------------------- Functions WMI Column info --------------------- */
+
+/***********************************************************************/
+/* Initialize WMI operations. */
+/***********************************************************************/
+PWMIUT InitWMI(PGLOBAL g, PCSZ nsp, PCSZ classname)
+{
+ IWbemLocator *loc;
+ char *p;
+ HRESULT res;
+ PWMIUT wp = (PWMIUT)PlugSubAlloc(g, NULL, sizeof(WMIUTIL));
+
+ if (trace(1))
+ htrc("WMIColumns class %s space %s\n", SVP(classname), SVP(nsp));
+
+ /*********************************************************************/
+ /* Set default values for the namespace and class name. */
+ /*********************************************************************/
+ if (!nsp)
+ nsp = "root\\cimv2";
+
+ if (!classname) {
+ if (!stricmp(nsp, "root\\cimv2"))
+ classname = "ComputerSystemProduct";
+ else if (!stricmp(nsp, "root\\cli"))
+ classname = "Msft_CliAlias";
+ else {
+ strcpy(g->Message, "Missing class name");
+ return NULL;
+ } // endif classname
+
+ } // endif classname
+
+ /*********************************************************************/
+ /* Initialize WMI. */
+ /*********************************************************************/
+//res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "Failed to initialize COM library. "
+ "Error code = %x", res);
+ return NULL;
+ } // endif res
+
+#if 0 // irrelevant for a DLL
+ res = CoInitializeSecurity(NULL, -1, NULL, NULL,
+ RPC_C_AUTHN_LEVEL_CONNECT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL, EOAC_NONE, NULL);
+
+ if (res != RPC_E_TOO_LATE && FAILED(res)) {
+ sprintf(g->Message, "Failed to initialize security. "
+ "Error code = %p", res);
+ CoUninitialize();
+ return NULL;
+ } // endif Res
+#endif // 0
+
+ res = CoCreateInstance(CLSID_WbemLocator, NULL,
+ CLSCTX_INPROC_SERVER, IID_IWbemLocator,
+ (void**) &loc);
+ if (FAILED(res)) {
+ sprintf(g->Message, "Failed to create Locator. "
+ "Error code = %x", res);
+ CoUninitialize();
+ return NULL;
+ } // endif res
+
+ res = loc->ConnectServer(_bstr_t(nsp),
+ NULL, NULL, NULL, 0, NULL, NULL, &wp->Svc);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "Could not connect. Error code = %x", res);
+ loc->Release();
+ CoUninitialize();
+ return NULL;
+ } // endif res
+
+ loc->Release();
+
+ if (trace(1))
+ htrc("Successfully connected to namespace.\n");
+
+ /*********************************************************************/
+ /* Perform a full class object retrieval. */
+ /*********************************************************************/
+ p = (char*)PlugSubAlloc(g, NULL, strlen(classname) + 7);
+
+ if (strchr(classname, '_'))
+ strcpy(p, classname);
+ else
+ strcat(strcpy(p, "Win32_"), classname);
+
+ res = wp->Svc->GetObject(bstr_t(p), 0, 0, &wp->Cobj, 0);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed GetObject %s in %s\n", classname, nsp);
+ wp->Svc->Release();
+ wp->Svc = NULL; // MUST be set to NULL (why?)
+ return NULL;
+ } // endif res
+
+ return wp;
+} // end of InitWMI
+
+/***********************************************************************/
+/* WMIColumns: constructs the result blocks containing the description */
+/* of all the columns of a WMI table of a specified class. */
+/***********************************************************************/
+PQRYRES WMIColumns(PGLOBAL g, PCSZ nsp, PCSZ cls, bool info)
+ {
+ static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
+ TYPE_INT, TYPE_INT, TYPE_SHORT};
+ static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME,
+ FLD_PREC, FLD_LENGTH, FLD_SCALE};
+ static unsigned int len, length[] = {0, 6, 8, 10, 10, 6};
+ int i = 0, n = 0, ncol = sizeof(buftyp) / sizeof(int);
+ int lng, typ, prec;
+ LONG low, upp;
+ BSTR propname;
+ VARIANT val;
+ CIMTYPE type;
+ HRESULT res;
+ PWMIUT wp;
+ SAFEARRAY *prnlist = NULL;
+ PQRYRES qrp = NULL;
+ PCOLRES crp;
+
+ if (!info) {
+ /*******************************************************************/
+ /* Initialize WMI if not done yet. */
+ /*******************************************************************/
+ if (!(wp = InitWMI(g, nsp, cls)))
+ return NULL;
+
+ /*******************************************************************/
+ /* Get the number of properties to return. */
+ /*******************************************************************/
+ res = wp->Cobj->Get(bstr_t("__Property_Count"), 0, &val, NULL, NULL);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed Get(__Property_Count) res=%d\n", res);
+ goto err;
+ } // endif res
+
+ if (!(n = val.lVal)) {
+ sprintf(g->Message, "Class %s in %s has no properties\n",
+ cls, nsp);
+ goto err;
+ } // endif res
+
+ /*******************************************************************/
+ /* Get max property name length. */
+ /*******************************************************************/
+ res = wp->Cobj->GetNames(NULL,
+ WBEM_FLAG_ALWAYS | WBEM_FLAG_NONSYSTEM_ONLY,
+ NULL, &prnlist);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed GetNames res=%d\n", res);
+ goto err;
+ } // endif res
+
+ res = SafeArrayGetLBound(prnlist, 1, &low);
+ res = SafeArrayGetUBound(prnlist, 1, &upp);
+
+ for (long i = low; i <= upp; i++) {
+ // Get this property name.
+ res = SafeArrayGetElement(prnlist, &i, &propname);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed GetArrayElement res=%d\n", res);
+ goto err;
+ } // endif res
+
+ len = (unsigned)SysStringLen(propname);
+ length[0] = MY_MAX(length[0], len);
+ } // enfor i
+
+ res = SafeArrayDestroy(prnlist);
+ } else
+ length[0] = 128;
+
+ /*********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /*********************************************************************/
+ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, true);
+
+ if (info || !qrp)
+ return qrp;
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ res = wp->Cobj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed BeginEnumeration hr=%d\n", res);
+ qrp = NULL;
+ goto err;
+ } // endif hr
+
+ while (TRUE) {
+ res = wp->Cobj->Next(0, &propname, &val, &type, NULL);
+
+ if (FAILED(res)) {
+ sprintf(g->Message, "failed getting Next hr=%d\n", res);
+ qrp = NULL;
+ goto err;
+ } else if (res == WBEM_S_NO_MORE_DATA) {
+ VariantClear(&val);
+ break;
+ } // endif res
+
+ if (i >= n)
+ break; // Should never happen
+ else
+ prec = 0;
+
+ switch (type) {
+ case CIM_STRING:
+ typ = TYPE_STRING;
+ lng = 255;
+ prec = 1; // Case insensitive
+ break;
+ case CIM_SINT32:
+ case CIM_UINT32:
+ case CIM_BOOLEAN:
+ typ = TYPE_INT;
+ lng = 11;
+ break;
+ case CIM_SINT8:
+ case CIM_UINT8:
+ typ = TYPE_TINY;
+ lng = 4;
+ break;
+ case CIM_SINT16:
+ case CIM_UINT16:
+ typ = TYPE_SHORT;
+ lng = 6;
+ break;
+ case CIM_REAL64:
+ case CIM_REAL32:
+ prec = 2;
+ typ = TYPE_DOUBLE;
+ lng = 15;
+ break;
+ case CIM_SINT64:
+ case CIM_UINT64:
+ typ = TYPE_BIGINT;
+ lng = 20;
+ break;
+ case CIM_DATETIME:
+ typ = TYPE_DATE;
+ lng = 19;
+ break;
+ case CIM_CHAR16:
+ typ = TYPE_STRING;
+ lng = 16;
+ break;
+ case CIM_EMPTY:
+ typ = TYPE_STRING;
+ lng = 24; // ???
+ break;
+ default:
+ qrp->BadLines++;
+ goto suite;
+ } // endswitch type
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(_com_util::ConvertBSTRToString(propname), i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(typ, i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(typ), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(lng, i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(lng, i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(prec, i);
+ i++;
+
+ suite:
+ SysFreeString(propname);
+ VariantClear(&val);
+ } // endfor i
+
+ qrp->Nblin = i;
+
+ err:
+ // Cleanup
+ wp->Cobj->Release();
+ wp->Svc->Release();
+ wp->Svc = NULL; // MUST be set to NULL (why?)
+ CoUninitialize();
+
+ /*********************************************************************/
+ /* Return the result pointer for use by GetData routines. */
+ /*********************************************************************/
+ return qrp;
+ } // end of WMIColumns
+
+/* -------------- Implementation of the WMI classes ------------------ */
+
+/***********************************************************************/
+/* DefineAM: define specific AM values for WMI table. */
+/***********************************************************************/
+bool WMIDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ Nspace = GetStringCatInfo(g, "Namespace", "Root\\CimV2");
+ Wclass = GetStringCatInfo(g, "Class",
+ (!stricmp(Nspace, "root\\cimv2") ? "ComputerSystemProduct" :
+ !stricmp(Nspace, "root\\cli") ? "Msft_CliAlias" : ""));
+
+ if (!*Wclass) {
+ sprintf(g->Message, "Missing class name for %s", Nspace);
+ return true;
+ } else if (!strchr(Wclass, '_')) {
+ char *p = (char*)PlugSubAlloc(g, NULL, strlen(Wclass) + 7);
+ Wclass = strcat(strcpy(p, "Win32_"), Wclass);
+ } // endif Wclass
+
+ if (Catfunc == FNC_NO)
+ Ems = GetIntCatInfo("Estimate", 100);
+
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB WMIDEF::GetTable(PGLOBAL g, MODE m)
+ {
+ if (Catfunc == FNC_NO)
+ return new(g) TDBWMI(this);
+ else if (Catfunc == FNC_COL)
+ return new(g) TDBWCL(this);
+
+ sprintf(g->Message, "Bad catfunc %ud for WMI", Catfunc);
+ return NULL;
+ } // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBWMI class. */
+/***********************************************************************/
+TDBWMI::TDBWMI(PWMIDEF tdp) : TDBASE(tdp)
+ {
+ Svc = NULL;
+ Enumerator = NULL;
+ ClsObj = NULL;
+ Nspace = tdp->Nspace;
+ Wclass = tdp->Wclass;
+ ObjPath = NULL;
+ Kvp = NULL;
+ Ems = tdp->Ems;
+ Kcol = NULL;
+ Vbp = NULL;
+ Init = false;
+ Done = false;
+ Res = 0;
+ Rc = 0;
+ N = -1;
+ } // end of TDBWMI constructor
+
+/***********************************************************************/
+/* Allocate WMI column description block. */
+/***********************************************************************/
+PCOL TDBWMI::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PCOL colp;
+
+ colp = new(g) WMICOL(cdp, this, n);
+
+ if (cprec) {
+ colp->SetNext(cprec->GetNext());
+ cprec->SetNext(colp);
+ } else {
+ colp->SetNext(Columns);
+ Columns = colp;
+ } // endif cprec
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* Initialize: Initialize WMI operations. */
+/***********************************************************************/
+bool TDBWMI::Initialize(PGLOBAL g)
+ {
+ if (Init)
+ return false;
+
+ // Initialize COM.
+ Res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ if (FAILED(Res)) {
+ sprintf(g->Message, "Failed to initialize COM library. "
+ "Error code = %x", Res);
+ return true; // Program has failed.
+ } // endif Res
+
+ // Obtain the initial locator to Windows Management
+ // on a particular host computer.
+ IWbemLocator *loc; // Initial Windows Management locator
+
+ Res = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator, (LPVOID*) &loc);
+
+ if (FAILED(Res)) {
+ sprintf(g->Message, "Failed to create Locator. "
+ "Error code = %x", Res);
+ CoUninitialize();
+ return true; // Program has failed.
+ } // endif Res
+
+ // Connect to the specified namespace with the
+ // current user and obtain pointer to Svc
+ // to make IWbemServices calls.
+ Res = loc->ConnectServer(_bstr_t(Nspace),
+ NULL, NULL,0, NULL, 0, 0, &Svc);
+
+ if (FAILED(Res)) {
+ sprintf(g->Message, "Could not connect. Error code = %x", Res);
+ loc->Release();
+ CoUninitialize();
+ return true; // Program has failed.
+ } // endif hres
+
+ loc->Release(); // Not used anymore
+
+ // Set the IWbemServices proxy so that impersonation
+ // of the user (client) occurs.
+ Res = CoSetProxyBlanket(Svc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
+ NULL, RPC_C_AUTHN_LEVEL_CALL,
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
+
+ if (FAILED(Res)) {
+ sprintf(g->Message, "Could not set proxy. Error code = %x", Res);
+ Svc->Release();
+ CoUninitialize();
+ return true; // Program has failed.
+ } // endif Res
+
+ Init = true;
+ return false;
+ } // end of Initialize
+
+/***********************************************************************/
+/* Changes '\' into '\\' in the filter. */
+/***********************************************************************/
+void TDBWMI::DoubleSlash(PGLOBAL g)
+ {
+ if (To_CondFil && strchr(To_CondFil->Body, '\\')) {
+ char *body = To_CondFil->Body;
+ char *buf = (char*)PlugSubAlloc(g, NULL, strlen(body) * 2);
+ int i = 0, k = 0;
+
+ do {
+ if (body[i] == '\\')
+ buf[k++] = '\\';
+
+ buf[k++] = body[i];
+ } while (body[i++]);
+
+ To_CondFil->Body = buf;
+ } // endif To_CondFil
+
+ } // end of DoubleSlash
+
+/***********************************************************************/
+/* MakeWQL: make the WQL statement use with WMI ExecQuery. */
+/***********************************************************************/
+char *TDBWMI::MakeWQL(PGLOBAL g)
+ {
+ char *colist, *wql/*, *pw = NULL*/;
+ int len, ncol = 0;
+ bool first = true, noloc = false;
+ PCOL colp;
+
+ // Normal WQL statement to retrieve results
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!colp->IsSpecial() && (colp->GetColUse(U_P | U_J_EXT) || noloc))
+ ncol++;
+
+ if (ncol) {
+ colist = (char*)PlugSubAlloc(g, NULL, (NAM_LEN + 4) * ncol);
+
+ for (colp = Columns; colp; colp = colp->GetNext())
+ if (!colp->IsSpecial()) {
+ if (colp->GetResultType() == TYPE_DATE)
+ ((DTVAL*)colp->GetValue())->SetFormat(g, "YYYYMMDDhhmmss", 19);
+
+ if (colp->GetColUse(U_P | U_J_EXT) || noloc) {
+ if (first) {
+ strcpy(colist, colp->GetName());
+ first = false;
+ } else
+ strcat(strcat(colist, ", "), colp->GetName());
+
+ } // endif ColUse
+
+ } // endif Special
+
+ } else {
+ // ncol == 0 can occur for queries such that sql count(*) from...
+ // for which we will count the rows from sql * from...
+ colist = (char*)PlugSubAlloc(g, NULL, 2);
+ strcpy(colist, "*");
+ } // endif ncol
+
+ // Below 14 is length of 'select ' + length of ' from ' + 1
+ len = (strlen(colist) + strlen(Wclass) + 14);
+ len += (To_CondFil ? strlen(To_CondFil->Body) + 7 : 0);
+ wql = (char*)PlugSubAlloc(g, NULL, len);
+ strcat(strcat(strcpy(wql, "SELECT "), colist), " FROM ");
+ strcat(wql, Wclass);
+
+ if (To_CondFil)
+ strcat(strcat(wql, " WHERE "), To_CondFil->Body);
+
+ return wql;
+ } // end of MakeWQL
+
+/***********************************************************************/
+/* GetWMIInfo: Get info for the WMI class. */
+/***********************************************************************/
+bool TDBWMI::GetWMIInfo(PGLOBAL g)
+ {
+ if (Done)
+ return false;
+
+ char *cmd = MakeWQL(g);
+
+ if (cmd == NULL) {
+ sprintf(g->Message, "Error making WQL statement");
+ Svc->Release();
+ CoUninitialize();
+ return true; // Program has failed.
+ } // endif cmd
+
+ // Query for Wclass in Nspace
+ Rc = Svc->ExecQuery(bstr_t("WQL"), bstr_t(cmd),
+// WBEM_FLAG_BIDIRECTIONAL | WBEM_FLAG_RETURN_IMMEDIATELY,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &Enumerator);
+
+ if (FAILED(Rc)) {
+ sprintf(g->Message, "Query %s failed. Error code = %x", cmd, Rc);
+ Svc->Release();
+ CoUninitialize();
+ return true; // Program has failed.
+ } // endif Rc
+
+ Done = true;
+ return false;
+ } // end of GetWMIInfo
+
+/***********************************************************************/
+/* WMI: Get the number returned instances. */
+/***********************************************************************/
+int TDBWMI::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ /*******************************************************************/
+ /* Loop enumerating to get the count. This is prone to last a */
+ /* very long time for some classes such as DataFile, this is why */
+ /* we just return an estimated value that will be ajusted later. */
+ /*******************************************************************/
+ MaxSize = Ems;
+#if 0
+ if (Initialize(g))
+ return -1;
+ else if (GetWMIInfo(g))
+ return -1;
+ else
+ MaxSize = 0;
+
+ PDBUSER dup = PlgGetUser(g);
+
+ while (Enumerator) {
+ Res = Enumerator->Next(WBEM_INFINITE, 1, &ClsObj, &Rc);
+
+ if (Rc == 0)
+ break;
+
+ MaxSize++;
+ } // endwile Enumerator
+
+ Res = Enumerator->Reset();
+#endif // 0
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* When making a Kindex, must provide the Key column info. */
+/***********************************************************************/
+int TDBWMI::GetRecpos(void)
+ {
+ if (!Kcol || !Vbp)
+ return N;
+
+ Kcol->Reset();
+ Kcol->Eval(NULL);
+ Vbp->SetValue(Kcol->GetValue(), N);
+ return N;
+ } // end of GetRecpos
+
+/***********************************************************************/
+/* WMI Access Method opening routine. */
+/***********************************************************************/
+bool TDBWMI::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open. */
+ /*******************************************************************/
+ Res = Enumerator->Reset();
+ N = 0;
+ return false;
+ } // endif use
+
+ if (Mode != MODE_READ) {
+ /*******************************************************************/
+ /* WMI tables cannot be modified. */
+ /*******************************************************************/
+ strcpy(g->Message, "WMI tables are read only");
+ return true;
+ } // endif Mode
+
+ if (!To_CondFil && !stricmp(Wclass, "CIM_Datafile")
+ && !stricmp(Nspace, "root\\cimv2")) {
+ strcpy(g->Message,
+ "Would last forever when not filtered, use DIR table instead");
+ return true;
+ } else
+ DoubleSlash(g);
+
+ Use = USE_OPEN; // Do it now in case we are recursively called
+
+ /*********************************************************************/
+ /* Initialize the WMI processing. */
+ /*********************************************************************/
+ if (Initialize(g))
+ return true;
+ else
+ return GetWMIInfo(g);
+
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for WMI access method. */
+/***********************************************************************/
+int TDBWMI::ReadDB(PGLOBAL g)
+ {
+ Res = Enumerator->Next(WBEM_INFINITE, 1, &ClsObj, &Rc);
+
+ if (Rc == 0)
+ return RC_EF;
+
+ N++;
+ return RC_OK;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for WMI access methods. */
+/***********************************************************************/
+int TDBWMI::WriteDB(PGLOBAL g)
+ {
+ strcpy(g->Message, "WMI tables are read only");
+ return RC_FX;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for WMI access methods. */
+/***********************************************************************/
+int TDBWMI::DeleteDB(PGLOBAL g, int irc)
+ {
+ strcpy(g->Message, "Delete not enabled for WMI tables");
+ return RC_FX;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for WMI access method. */
+/***********************************************************************/
+void TDBWMI::CloseDB(PGLOBAL g)
+ {
+ // Cleanup
+ if (ClsObj)
+ ClsObj->Release();
+
+ if (Enumerator)
+ Enumerator->Release();
+
+ if (Svc)
+ Svc->Release();
+
+ CoUninitialize();
+ } // end of CloseDB
+
+// ------------------------ WMICOL functions ----------------------------
+
+/***********************************************************************/
+/* WMICOL public constructor. */
+/***********************************************************************/
+WMICOL::WMICOL(PCOLDEF cdp, PTDB tdbp, int n)
+ : COLBLK(cdp, tdbp, n)
+ {
+ Tdbp = (PTDBWMI)tdbp;
+ VariantInit(&Prop);
+ Ctype = CIM_ILLEGAL;
+ Res = 0;
+ } // end of WMICOL constructor
+
+#if 0
+/***********************************************************************/
+/* WMICOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+WMICOL::WMICOL(WMICOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ } // end of WMICOL copy constructor
+#endif // 0
+
+/***********************************************************************/
+/* Read the next WMI address elements. */
+/***********************************************************************/
+void WMICOL::ReadColumn(PGLOBAL g)
+ {
+ // Get the value of the Name property
+ Res = Tdbp->ClsObj->Get(_bstr_t(Name), 0, &Prop, &Ctype, 0);
+
+ switch (Prop.vt) {
+ case VT_EMPTY:
+ case VT_NULL:
+ case VT_VOID:
+ Value->Reset();
+ break;
+ case VT_BSTR:
+ Value->SetValue_psz(_com_util::ConvertBSTRToString(Prop.bstrVal));
+ break;
+ case VT_I4:
+ case VT_UI4:
+ Value->SetValue(Prop.lVal);
+ break;
+ case VT_I2:
+ case VT_UI2:
+ Value->SetValue(Prop.iVal);
+ break;
+ case VT_INT:
+ case VT_UINT:
+ Value->SetValue((int)Prop.intVal);
+ break;
+ case VT_BOOL:
+ Value->SetValue(((int)Prop.boolVal) ? 1 : 0);
+ break;
+ case VT_R8:
+ Value->SetValue(Prop.dblVal);
+ break;
+ case VT_R4:
+ Value->SetValue((double)Prop.fltVal);
+ break;
+ case VT_DATE:
+ switch (Value->GetType()) {
+ case TYPE_DATE:
+ {SYSTEMTIME stm;
+ struct tm ptm;
+ int rc = VariantTimeToSystemTime(Prop.date, &stm);
+
+ ptm.tm_year = stm.wYear;
+ ptm.tm_mon = stm.wMonth;
+ ptm.tm_mday = stm.wDay;
+ ptm.tm_hour = stm.wHour;
+ ptm.tm_min = stm.wMinute;
+ ptm.tm_sec = stm.wSecond;
+ ((DTVAL*)Value)->MakeTime(&ptm);
+ }break;
+ case TYPE_STRING:
+ {SYSTEMTIME stm;
+ char buf[24];
+ int rc = VariantTimeToSystemTime(Prop.date, &stm);
+
+ sprintf(buf, "%02d/%02d/%d %02d:%02d:%02d",
+ stm.wDay, stm.wMonth, stm.wYear,
+ stm.wHour, stm.wMinute, stm.wSecond);
+ Value->SetValue_psz(buf);
+ }break;
+ default:
+ Value->SetValue((double)Prop.fltVal);
+ } // endswitch Type
+
+ break;
+ default:
+ // This will reset numeric column value
+ Value->SetValue_psz("Type not supported");
+ break;
+ } // endswitch vt
+
+ VariantClear(&Prop);
+ } // end of ReadColumn
+
+/* ---------------------------TDBWCL class --------------------------- */
+
+/***********************************************************************/
+/* TDBWCL class constructor. */
+/***********************************************************************/
+TDBWCL::TDBWCL(PWMIDEF tdp) : TDBCAT(tdp)
+ {
+ Nsp = tdp->Nspace;
+ Cls = tdp->Wclass;
+ } // end of TDBWCL constructor
+
+/***********************************************************************/
+/* GetResult: Get the list of the WMI class properties. */
+/***********************************************************************/
+PQRYRES TDBWCL::GetResult(PGLOBAL g)
+ {
+ return WMIColumns(g, Nsp, Cls, false);
+ } // end of GetResult
+
+
diff --git a/storage/connect/tabwmi.h b/storage/connect/tabwmi.h
new file mode 100644
index 00000000..7a184533
--- /dev/null
+++ b/storage/connect/tabwmi.h
@@ -0,0 +1,151 @@
+// TABWMI.H Olivier Bertrand 2012
+// WMI: Virtual table to Get WMI information
+#define _WIN32_DCOM
+#include <wbemidl.h>
+# pragma comment(lib, "wbemuuid.lib")
+#include <iostream>
+using namespace std;
+#include <comdef.h>
+
+/***********************************************************************/
+/* Definitions. */
+/***********************************************************************/
+typedef class WMIDEF *PWMIDEF;
+typedef class TDBWMI *PTDBWMI;
+typedef class WMICOL *PWMICOL;
+typedef class TDBWCL *PTDBWCL;
+typedef class WCLCOL *PWCLCOL;
+
+/***********************************************************************/
+/* Structure used by WMI column info functions. */
+/***********************************************************************/
+typedef struct _WMIutil {
+ IWbemServices *Svc;
+ IWbemClassObject *Cobj;
+} WMIUTIL, *PWMIUT;
+
+/***********************************************************************/
+/* Functions used externally. */
+/***********************************************************************/
+PQRYRES WMIColumns(PGLOBAL g, PCSZ nsp, PCSZ cls, bool info);
+
+/* -------------------------- WMI classes ---------------------------- */
+
+/***********************************************************************/
+/* WMI: Virtual table to get the WMI information. */
+/***********************************************************************/
+class WMIDEF : public TABDEF { /* Logical table description */
+ friend class TDBWMI;
+ friend class TDBWCL;
+ friend class TDBWCX;
+ public:
+ // Constructor
+ WMIDEF(void) {Pseudo = 3; Nspace = NULL; Wclass = NULL; Ems = 0;}
+
+ // Implementation
+ virtual const char *GetType(void) {return "WMI";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ char *Nspace;
+ char *Wclass;
+ int Ems;
+ }; // end of WMIDEF
+
+/***********************************************************************/
+/* This is the class declaration for the WMI table. */
+/***********************************************************************/
+class TDBWMI : public TDBASE {
+ friend class WMICOL;
+ public:
+ // Constructor
+ TDBWMI(PWMIDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_WMI;}
+
+ // Methods
+ virtual int GetRecpos(void);
+ virtual int GetProgCur(void) {return N;}
+ virtual int RowNumber(PGLOBAL g, bool b = false) {return N + 1;}
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g) {return GetMaxSize(g);}
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+
+ protected:
+ // Specific routines
+ bool Initialize(PGLOBAL g);
+ char *MakeWQL(PGLOBAL g);
+ void DoubleSlash(PGLOBAL g);
+ bool GetWMIInfo(PGLOBAL g);
+
+ // Members
+ IWbemServices *Svc; // IWbemServices pointer
+ IEnumWbemClassObject *Enumerator;
+ IWbemClassObject *ClsObj;
+ char *Nspace; // Namespace
+ char *Wclass; // Class name
+ char *ObjPath; // Used for direct access
+ char *Kvp; // Itou
+ int Ems; // Estimated max size
+ PCOL Kcol; // Key column
+ HRESULT Res;
+ PVBLK Vbp;
+ bool Init;
+ bool Done;
+ ULONG Rc;
+ int N; // Row number
+ }; // end of class TDBWMI
+
+/***********************************************************************/
+/* Class WMICOL: WMI Address column. */
+/***********************************************************************/
+class WMICOL : public COLBLK {
+ friend class TDBWMI;
+ public:
+ // Constructors
+ WMICOL(PCOLDEF cdp, PTDB tdbp, int n);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_WMI;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ WMICOL(void) {} // Default constructor not to be used
+
+ // Members
+ PTDBWMI Tdbp; // Points to WMI table block
+ VARIANT Prop; // Property value
+ CIMTYPE Ctype; // CIM Type
+ HRESULT Res;
+ }; // end of class WMICOL
+
+/***********************************************************************/
+/* This is the class declaration for the WMI catalog table. */
+/***********************************************************************/
+class TDBWCL : public TDBCAT {
+ public:
+ // Constructor
+ TDBWCL(PWMIDEF tdp);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ char *Nsp; // Name space
+ char *Cls; // Class
+ }; // end of class TDBWCL
diff --git a/storage/connect/tabxcl.cpp b/storage/connect/tabxcl.cpp
new file mode 100644
index 00000000..d354f556
--- /dev/null
+++ b/storage/connect/tabxcl.cpp
@@ -0,0 +1,298 @@
+/************* TabXcl CPP Declares Source Code File (.CPP) *************/
+/* Name: TABXCL.CPP Version 1.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2013-2017 */
+/* */
+/* XCOL: Table having one column containing several values */
+/* comma separated. When creating the table, the name of the X */
+/* column is given by the Name option. */
+/* This first version has one limitation: */
+/* - The X column has the same length than in the physical file. */
+/* This tables produces as many rows for a physical row than the */
+/* number of items in the X column (eventually 0). */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant section of system dependant header files. */
+/***********************************************************************/
+#include "my_global.h"
+#include "table.h" // MySQL table definitions
+#if defined(_WIN32)
+#include <stdlib.h>
+#include <stdio.h>
+#if defined(__BORLANDC__)
+#define __MFC_COMPAT__ // To define min/max as macro
+#endif
+//#include <windows.h>
+#else
+#if defined(UNIX)
+#include <fnmatch.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "osutil.h"
+#else
+//#include <io.h>
+#endif
+//#include <fcntl.h>
+#endif
+
+/***********************************************************************/
+/* Include application header files: */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "plgcnx.h" // For DB types
+#include "resource.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#include "tabcol.h"
+#include "tabxcl.h"
+#include "tabmysql.h"
+#include "ha_connect.h"
+
+/* -------------- Implementation of the XCOL classes ---------------- */
+
+/***********************************************************************/
+/* XCLDEF constructor. */
+/***********************************************************************/
+XCLDEF::XCLDEF(void)
+ {
+ Xcol = NULL;
+ Sep = ',';
+ Mult = 10;
+} // end of XCLDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XCOL table. */
+/***********************************************************************/
+bool XCLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ char buf[8];
+
+ Xcol = GetStringCatInfo(g, "Colname", "");
+ GetCharCatInfo("Separator", ",", buf, sizeof(buf));
+ Sep = (strlen(buf) == 2 && buf[0] == '\\' && buf[1] == 't') ? '\t' : *buf;
+ Mult = GetIntCatInfo("Mult", 10);
+ return PRXDEF::DefineAM(g, am, poff);
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB XCLDEF::GetTable(PGLOBAL g, MODE)
+ {
+ if (Catfunc == FNC_COL)
+ return new(g) TDBTBC(this);
+ else
+ return new(g) TDBXCL(this);
+
+ } // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBXCL class. */
+/***********************************************************************/
+TDBXCL::TDBXCL(PXCLDEF tdp) : TDBPRX(tdp)
+ {
+ Xcolumn = tdp->Xcol; // CSV column name
+ Xcolp = NULL; // To the XCLCOL column
+ Mult = tdp->Mult; // Multiplication factor
+ N = 0; // The current table index
+ M = 0; // The occurrence rank
+ RowFlag = 0; // 0: Ok, 1: Same, 2: Skip
+ New = TRUE; // TRUE for new line
+ Sep = tdp->Sep; // The Xcol separator
+ } // end of TDBXCL constructor
+
+/***********************************************************************/
+/* Allocate XCL column description block. */
+/***********************************************************************/
+PCOL TDBXCL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ PCOL colp;
+
+ if (!stricmp(cdp->GetName(), Xcolumn)) {
+ Xcolp = new(g) XCLCOL(cdp, this, cprec, n);
+ colp = Xcolp;
+ } else
+ colp = new(g) PRXCOL(cdp, this, cprec, n);
+
+ return colp;
+ } // end of MakeCol
+
+/***********************************************************************/
+/* XCL GetMaxSize: returns the maximum number of rows in the table. */
+/***********************************************************************/
+int TDBXCL::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ if (InitTable(g))
+ return 0;
+
+ MaxSize = Mult * Tdbp->GetMaxSize(g);
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* For this table type, ROWID is the (virtual) row number, */
+/* while ROWNUM is be the occurrence rank in the multiple column. */
+/***********************************************************************/
+int TDBXCL::RowNumber(PGLOBAL, bool b)
+ {
+ return (b) ? M : N;
+ } // end of RowNumber
+
+/***********************************************************************/
+/* XCL Access Method opening routine. */
+/***********************************************************************/
+bool TDBXCL::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open, just replace it at its beginning. */
+ /*******************************************************************/
+ M = N = 0;
+ RowFlag = 0;
+ New = TRUE;
+ return Tdbp->OpenDB(g);
+ } // endif use
+
+ if (Mode != MODE_READ) {
+ /*******************************************************************/
+ /* Currently XCOL tables cannot be modified. */
+ /*******************************************************************/
+ strcpy(g->Message, "XCOL tables are read only");
+ return TRUE;
+ } // endif Mode
+
+ if (InitTable(g))
+ return TRUE;
+
+ /*********************************************************************/
+ /* Check and initialize the subtable columns. */
+ /*********************************************************************/
+ for (PCOL cp = Columns; cp; cp = cp->GetNext())
+ if (!cp->IsSpecial())
+ if (((PPRXCOL)cp)->Init(g, NULL))
+ return TRUE;
+
+ /*********************************************************************/
+ /* Physically open the object table. */
+ /*********************************************************************/
+ if (Tdbp->OpenDB(g))
+ return TRUE;
+
+ Use = USE_OPEN;
+ return FALSE;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for XCL access method. */
+/***********************************************************************/
+int TDBXCL::ReadDB(PGLOBAL g)
+ {
+ int rc = RC_OK;
+
+ /*********************************************************************/
+ /* Now start the multi reading process. */
+ /*********************************************************************/
+ do {
+ if (RowFlag != 1) {
+ if ((rc = Tdbp->ReadDB(g)) != RC_OK)
+ break;
+
+ New = TRUE;
+ M = 1;
+ } else {
+ New = FALSE;
+ M++;
+ } // endif RowFlag
+
+ if (Xcolp) {
+ RowFlag = 0;
+ Xcolp->ReadColumn(g);
+ } // endif Xcolp
+
+ N++;
+ } while (RowFlag == 2);
+
+ return rc;
+ } // end of ReadDB
+
+
+// ------------------------ XCLCOL functions ----------------------------
+
+/***********************************************************************/
+/* XCLCOL public constructor. */
+/***********************************************************************/
+XCLCOL::XCLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
+ : PRXCOL(cdp, tdbp, cprec, i, "XCL")
+ {
+ // Set additional XXL access method information for column.
+ Cbuf = NULL; // Will be allocated later
+ Cp = NULL; // Pointer to current position in Cbuf
+ Sep = ((PTDBXCL)tdbp)->Sep;
+ AddStatus(BUF_READ); // Only evaluated from TDBXCL::ReadDB
+ } // end of XCLCOL constructor
+
+/***********************************************************************/
+/* XCLCOL initialization routine. */
+/* Allocate Cbuf that will contain the Colp value. */
+/***********************************************************************/
+bool XCLCOL::Init(PGLOBAL g, PTDB tp)
+ {
+ if (PRXCOL::Init(g, tp))
+ return true;
+
+ Cbuf = (char*)PlugSubAlloc(g, NULL, Colp->GetLength() + 1);
+ return false;
+ } // end of Init
+
+/***********************************************************************/
+/* What this routine does is to get the comma-separated string */
+/* from the source table column, extract the single values and */
+/* set the flag for the table ReadDB function. */
+/***********************************************************************/
+void XCLCOL::ReadColumn(PGLOBAL g)
+ {
+ if (((PTDBXCL)To_Tdb)->New) {
+ Colp->Reset(); // Moved here in case of failed filtering
+ Colp->Eval(g);
+ strncpy(Cbuf, To_Val->GetCharValue(), Colp->GetLength());
+ Cbuf[Colp->GetLength()] = 0;
+ Cp = Cbuf;
+ } // endif New
+
+ if (*Cp) {
+ PSZ p;
+
+ // Trim left
+ for (p = Cp; *p == ' '; p++)
+ ;
+
+ if ((Cp = strchr(Cp, Sep)))
+ // Separator is found
+ *Cp++ = '\0';
+
+ Value->SetValue_psz(p);
+ } else if (Nullable) {
+ Value->Reset();
+ Value->SetNull(true);
+ } else {
+ // Skip that row
+ ((PTDBXCL)To_Tdb)->RowFlag = 2;
+ Colp->Reset();
+ } // endif Cp
+
+ if (Cp && *Cp)
+ // More to come from the same row
+ ((PTDBXCL)To_Tdb)->RowFlag = 1;
+
+ } // end of ReadColumn
diff --git a/storage/connect/tabxcl.h b/storage/connect/tabxcl.h
new file mode 100644
index 00000000..2ae96703
--- /dev/null
+++ b/storage/connect/tabxcl.h
@@ -0,0 +1,104 @@
+// TABXCL.H Olivier Bertrand 2013
+// Defines the XCOL tables
+
+#include "tabutil.h"
+
+typedef class XCLDEF *PXCLDEF;
+typedef class TDBXCL *PTDBXCL;
+typedef class XCLCOL *PXCLCOL;
+
+/* -------------------------- XCOL classes --------------------------- */
+
+/***********************************************************************/
+/* XCOL: table having one column containing several values comma */
+/* (or any other character) separated. When creating the table, the */
+/* name of the X column is given by the NAME option. */
+/* This sample has a limitation: */
+/* - The X column has the same length than in the physical file. */
+/* This tables produces as many rows for a physical row than the */
+/* number of items in the X column (eventually 0). */
+/***********************************************************************/
+
+/***********************************************************************/
+/* XCL table. */
+/***********************************************************************/
+class XCLDEF : public PRXDEF { /* Logical table description */
+ friend class TDBXCL;
+ public:
+ // Constructor
+ XCLDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "XCL";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE mode);
+
+ protected:
+ // Members
+ char *Xcol; /* The column containing separated fields */
+ char Sep; /* The field separator, defaults to comma */
+ int Mult; /* Multiplication factor */
+ }; // end of XCLDEF
+
+/***********************************************************************/
+/* This is the class declaration for the XCOL table. */
+/***********************************************************************/
+class TDBXCL : public TDBPRX {
+ friend class XCLDEF;
+ friend class PRXCOL;
+ friend class XCLCOL;
+ public:
+ // Constructor
+ TDBXCL(PXCLDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_XCOL;}
+
+ // Methods
+ virtual void ResetDB(void) {N = 0; Tdbp->ResetDB();}
+ virtual int RowNumber(PGLOBAL g, bool b = FALSE);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+
+ protected:
+ // Members
+ char *Xcolumn; // Multiple column name
+ PXCLCOL Xcolp; // To the XCVCOL column
+ int Mult; // Multiplication factor
+ int N; // The current table index
+ int M; // The occurrence rank
+ BYTE RowFlag; // 0: Ok, 1: Same, 2: Skip
+ bool New; // TRUE for new line
+ char Sep; // The Xcol separator
+ }; // end of class TDBXCL
+
+/***********************************************************************/
+/* Class XCLCOL: for the multiple CSV column. */
+/***********************************************************************/
+class XCLCOL : public PRXCOL {
+ friend class TDBXCL;
+ public:
+ // Constructors
+ XCLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
+
+ // Methods
+ using PRXCOL::Init;
+ virtual void Reset(void) {} // Evaluated only by TDBXCL
+ virtual void ReadColumn(PGLOBAL g);
+ virtual bool Init(PGLOBAL g, PTDB tp = NULL);
+
+ protected:
+ // Default constructor not to be used
+ XCLCOL(void) {}
+
+ // Members
+ char *Cbuf; // The column buffer
+ char *Cp; // Pointer to current position
+ char Sep; // The separator
+ }; // end of class XCLCOL
diff --git a/storage/connect/tabxml.cpp b/storage/connect/tabxml.cpp
new file mode 100644
index 00000000..2d8df9a4
--- /dev/null
+++ b/storage/connect/tabxml.cpp
@@ -0,0 +1,2291 @@
+/************* Tabxml C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABXML */
+/* ------------- */
+/* Version 3.0 */
+/* */
+/* Author Olivier BERTRAND 2007 - 2020 */
+/* */
+/* This program are the XML tables classes using MS-DOM or libxml2. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include required compiler header files. */
+/***********************************************************************/
+#include "my_global.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#if defined(_WIN32)
+#include <io.h>
+#include <winsock2.h>
+//#include <windows.h>
+#include <comdef.h>
+#else // !_WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+//#include <ctype.h>
+#include "osutil.h"
+#define _O_RDONLY O_RDONLY
+#endif // !_WIN32
+#include "resource.h" // for IDS_COLUMNS
+
+#define INCLUDE_TDBXML
+#define NODE_TYPE_LIST
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* tabdos.h is header containing the TABDOS class declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+//#include "reldef.h"
+#include "xtable.h"
+#include "colblk.h"
+#include "mycat.h"
+#include "xindex.h"
+#include "plgxml.h"
+#include "tabxml.h"
+#include "tabmul.h"
+
+extern "C" char version[];
+
+#if defined(_WIN32) && defined(DOMDOC_SUPPORT)
+#define XMLSUP "MS-DOM"
+#else // !_WIN32
+#define XMLSUP "libxml2"
+#endif // !_WIN32
+
+#define TYPE_UNKNOWN 12 /* Must be greater than other types */
+#define XLEN(M) sizeof(M) - strlen(M) - 1 /* To avoid overflow*/
+
+int GetDefaultDepth(void);
+
+/***********************************************************************/
+/* Class and structure used by XMLColumns. */
+/***********************************************************************/
+typedef class XMCOL *PXCL;
+
+class XMCOL : public BLOCK {
+ public:
+ // Constructors
+ XMCOL(void) {Next = NULL;
+ Name[0] = 0;
+ Fmt = NULL;
+ Type = 1;
+ Len = Scale = 0;
+ Cbn = false;
+ Found = true;}
+ XMCOL(PGLOBAL g, PXCL xp, char *fmt, int i) {
+ Next = NULL;
+ strcpy(Name, xp->Name);
+ Fmt = (*fmt) ? PlugDup(g, fmt) : NULL;
+ Type = xp->Type;
+ Len = xp->Len;
+ Scale = xp->Scale;
+ Cbn = (xp->Cbn || i > 1);
+ Found = true;}
+
+ // Members
+ PXCL Next;
+ char Name[64];
+ char *Fmt;
+ int Type;
+ int Len;
+ int Scale;
+ bool Cbn;
+ bool Found;
+}; // end of class XMCOL
+
+typedef struct LVL {
+ PXNODE pn;
+ PXLIST nl;
+ PXATTR atp;
+ bool b;
+ long k;
+ int m, n;
+} *PLVL;
+
+/***********************************************************************/
+/* XMLColumns: construct the result blocks containing the description */
+/* of all the columns of a table contained inside an XML file. */
+/***********************************************************************/
+PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info)
+{
+ static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
+ TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
+ static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
+ FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
+ static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
+ char colname[65], fmt[129], buf[512];
+ int i, j, lvl, n = 0;
+ int ncol = sizeof(buftyp) / sizeof(int);
+ bool ok = true;
+ PCSZ fn, op;
+ PXCL xcol, xcp, fxcp = NULL, pxcp = NULL;
+ PLVL *lvlp, vp;
+ PXNODE node = NULL;
+ PXMLDEF tdp;
+ PTDBXML txmp;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ if (info) {
+ length[0] = 128;
+ length[7] = 256;
+ goto skipit;
+ } // endif info
+
+ if (GetIntegerTableOption(g, topt, "Multiple", 0)) {
+ strcpy(g->Message, "Cannot find column definition for multiple table");
+ return NULL;
+ } // endif Multiple
+
+ /*********************************************************************/
+ /* Open the input file. */
+ /*********************************************************************/
+ if (!(fn = GetStringTableOption(g, topt, "Filename", NULL))) {
+ if (topt->http) // REST table can have default filename
+ fn = GetStringTableOption(g, topt, "Subtype", NULL);
+
+ if (!fn) {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return NULL;
+ } else
+ topt->subtype = NULL;
+
+ } // endif fn
+
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
+ lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl;
+
+ if (trace(1))
+ htrc("File %s lvl=%d\n", topt->filename, lvl);
+
+ tdp = new(g) XMLDEF;
+ tdp->Fn = fn;
+
+ if (!(tdp->Database = SetPath(g, db)))
+ return NULL;
+
+ tdp->Tabname = tab;
+ tdp->Tabname = (char*)GetStringTableOption(g, topt, "Tabname", tab);
+ tdp->Rowname = (char*)GetStringTableOption(g, topt, "Rownode", NULL);
+ tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false);
+ tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
+ tdp->Skip = GetBooleanTableOption(g, topt, "Skipnull", false);
+
+ if (!(op = GetStringTableOption(g, topt, "Xmlsup", NULL)))
+#if defined(_WIN32)
+ tdp->Usedom = true;
+#else // !_WIN32
+ tdp->Usedom = false;
+#endif // !_WIN32
+ else
+ tdp->Usedom = (toupper(*op) == 'M' || toupper(*op) == 'D');
+
+ txmp = new(g) TDBXML(tdp);
+
+ if (txmp->Initialize(g))
+ goto err;
+
+ xcol = new(g) XMCOL;
+ colname[64] = 0;
+ fmt[128] = 0;
+ lvlp = (PLVL*)PlugSubAlloc(g, NULL, sizeof(PLVL) * (lvl + 1));
+
+ for (j = 0; j <= lvl; j++)
+ lvlp[j] = (PLVL)PlugSubAlloc(g, NULL, sizeof(LVL));
+
+ /*********************************************************************/
+ /* Analyse the XML tree and define columns. */
+ /*********************************************************************/
+ for (i = 1; ; i++) {
+ // Get next row
+ switch (txmp->ReadDB(g)) {
+ case RC_EF:
+ vp = NULL;
+ break;
+ case RC_FX:
+ goto err;
+ default:
+ vp = lvlp[0];
+ vp->pn = txmp->RowNode;
+ vp->atp = vp->pn->GetAttribute(g, NULL);
+ vp->nl = vp->pn->GetChildElements(g);
+ vp->b = true;
+ vp->k = 0;
+ vp->m = vp->n = 0;
+ j = 0;
+ } // endswitch ReadDB
+
+ if (!vp)
+ break;
+
+ while (true) {
+ if (!vp->atp &&
+ !(node = (vp->nl) ? vp->nl->GetItem(g, vp->k++, tdp->Usedom ?
+ node : NULL)
+ : NULL))
+ {
+ if (j) {
+ vp = lvlp[--j];
+
+ if (!tdp->Usedom) // nl was destroyed
+ vp->nl = vp->pn->GetChildElements(g);
+
+ if (!lvlp[j+1]->b) {
+ vp->k--;
+ ok = false;
+ } // endif b
+
+ continue;
+ } else
+ break;
+ }
+ xcol->Name[vp->n] = 0;
+ fmt[vp->m] = 0;
+
+ more:
+ if (vp->atp) {
+ size_t z = sizeof(colname) - 1;
+ strncpy(colname, vp->atp->GetName(g), z);
+ colname[z] = 0;
+ strncat(xcol->Name, colname, XLEN(xcol->Name));
+
+ switch (vp->atp->GetText(g, buf, sizeof(buf))) {
+ case RC_INFO:
+ PushWarning(g, txmp);
+ /* falls through */
+ case RC_OK:
+ strncat(fmt, "@", XLEN(fmt));
+ break;
+ default:
+ goto err;
+ } // enswitch rc
+
+ if (j)
+ strncat(fmt, colname, XLEN(fmt));
+
+ } else {
+ if (tdp->Usedom && node->GetType() != 1)
+ continue;
+
+ strncpy(colname, node->GetName(g), sizeof(colname));
+ strncat(xcol->Name, colname, XLEN(xcol->Name));
+
+ if (j)
+ strncat(fmt, colname, XLEN(fmt));
+
+ if (j < lvl && ok) {
+ vp = lvlp[j+1];
+ vp->k = 0;
+ vp->pn = node;
+ vp->atp = node->GetAttribute(g, NULL);
+ vp->nl = node->GetChildElements(g);
+
+ if (tdp->Usedom && vp->nl->GetLength() == 1) {
+ node = vp->nl->GetItem(g, 0, node);
+ vp->b = (node->GetType() == 1); // Must be ab element
+ } else
+ vp->b = (vp->nl && vp->nl->GetLength());
+
+ if (vp->atp || vp->b) {
+ if (!vp->atp)
+ node = vp->nl->GetItem(g, vp->k++, tdp->Usedom ? node : NULL);
+
+ if (!j)
+ strncat(fmt, colname, XLEN(fmt));
+
+ strncat(fmt, "/", XLEN(fmt));
+ strncat(xcol->Name, "_", XLEN(xcol->Name));
+ j++;
+ vp->n = (int)strlen(xcol->Name);
+ vp->m = (int)strlen(fmt);
+ goto more;
+ } else {
+ vp = lvlp[j];
+
+ if (!tdp->Usedom) // nl was destroyed
+ vp->nl = vp->pn->GetChildElements(g);
+
+ } // endif vp
+
+ } else
+ ok = true;
+
+ switch (node->GetContent(g, buf, sizeof(buf))) {
+ case RC_INFO:
+ PushWarning(g, txmp);
+ /* falls through */
+ case RC_OK:
+ xcol->Cbn = !strlen(buf);
+ break;
+ default:
+ goto err;
+ } // enswitch rc
+
+ } // endif atp;
+
+ xcol->Len = strlen(buf);
+
+ // Check whether this column was already found
+ for (xcp = fxcp; xcp; xcp = xcp->Next)
+ if (!strcmp(xcol->Name, xcp->Name))
+ break;
+
+ if (xcp) {
+ if (xcp->Type != xcol->Type)
+ xcp->Type = TYPE_STRING;
+
+ if (*fmt && (!xcp->Fmt || strlen(xcp->Fmt) < strlen(fmt))) {
+ xcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], strlen(fmt));
+ } // endif *fmt
+
+ xcp->Len = MY_MAX(xcp->Len, xcol->Len);
+ xcp->Scale = MY_MAX(xcp->Scale, xcol->Scale);
+ xcp->Cbn |= (xcol->Cbn || !xcol->Len);
+ xcp->Found = true;
+ } else if(xcol->Len || !tdp->Skip) {
+ // New column
+ xcp = new(g) XMCOL(g, xcol, fmt, i);
+ length[0] = MY_MAX(length[0], strlen(xcol->Name));
+ length[7] = MY_MAX(length[7], strlen(fmt));
+
+ if (pxcp) {
+ xcp->Next = pxcp->Next;
+ pxcp->Next = xcp;
+ } else
+ fxcp = xcp;
+
+ n++;
+ } // endif xcp
+
+ if (xcp)
+ pxcp = xcp;
+
+ if (vp->atp)
+ vp->atp = vp->atp->GetNext(g);
+
+ } // endwhile
+
+ // Missing column can be null
+ for (xcp = fxcp; xcp; xcp = xcp->Next) {
+ xcp->Cbn |= !xcp->Found;
+ xcp->Found = false;
+ } // endfor xcp
+
+ } // endor i
+
+ txmp->CloseDB(g);
+
+ skipit:
+ if (trace(1))
+ htrc("XMLColumns: n=%d len=%d\n", n, length[0]);
+
+ /*********************************************************************/
+ /* Allocate the structures used to refer to the result set. */
+ /*********************************************************************/
+ qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
+ buftyp, fldtyp, length, false, false);
+
+ crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
+ crp->Name = "Nullable";
+ crp->Next->Name = "Xpath";
+
+ if (info || !qrp)
+ return qrp;
+
+ qrp->Nblin = n;
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ for (i = 0, xcp = fxcp; xcp; i++, xcp = xcp->Next) {
+ if (xcp->Type == TYPE_UNKNOWN) // Void column
+ xcp->Type = TYPE_STRING;
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(xcp->Name, i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(xcp->Type, i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(xcp->Type), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(xcp->Len, i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(xcp->Len, i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(xcp->Scale, i);
+ crp = crp->Next; // Nullable
+ crp->Kdata->SetValue(xcp->Cbn ? 1 : 0, i);
+ crp = crp->Next; // Field format
+
+ if (crp->Kdata)
+ crp->Kdata->SetValue(xcp->Fmt, i);
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* Return the result pointer. */
+ /*********************************************************************/
+ return qrp;
+
+err:
+ txmp->CloseDB(g);
+ return NULL;
+ } // end of XMLColumns
+
+/* -------------- Implementation of the XMLDEF class ---------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+XMLDEF::XMLDEF(void)
+ {
+ Pseudo = 3;
+ Fn = NULL;
+ Encoding = NULL;
+ Tabname = NULL;
+ Rowname = NULL;
+ Colname = NULL;
+ Mulnode = NULL;
+ XmlDB = NULL;
+ Nslist = NULL;
+ DefNs = NULL;
+ Attrib = NULL;
+ Hdattr = NULL;
+ Entry = NULL;
+ Coltype = 1;
+ Limit = 0;
+ Header = 0;
+ Xpand = false;
+ Usedom = false;
+ Zipped = false;
+ Mulentries = false;
+ Skip = false;
+ } // end of XMLDEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values from XDB file. */
+/***********************************************************************/
+bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+ {
+ PCSZ defrow, defcol;
+ char buf[10];
+
+ Fn = GetStringCatInfo(g, "Filename", NULL);
+ Encoding = GetStringCatInfo(g, "Encoding", "UTF-8");
+
+ if (*Fn == '?') {
+ strcpy(g->Message, MSG(MISSING_FNAME));
+ return true;
+ } // endif fn
+
+ if ((signed)GetIntCatInfo("Flag", -1) != -1) {
+ strcpy(g->Message, MSG(DEPREC_FLAG));
+ return true;
+ } // endif flag
+
+ defrow = defcol = NULL;
+ GetCharCatInfo("Coltype", "", buf, sizeof(buf));
+
+ switch (toupper(*buf)) {
+ case 'A': // Attribute
+ case '@':
+ case '0':
+ Coltype = 0;
+ break;
+ case '\0': // Default
+ case 'T': // Tag
+ case 'N': // Node
+ case '1':
+ Coltype = 1;
+ break;
+ case 'C': // Column
+ case 'P': // Position
+ case 'H': // HTML
+ case '2':
+ Coltype = 2;
+ defrow = "TR";
+ defcol = "TD";
+ break;
+ default:
+ sprintf(g->Message, MSG(INV_COL_TYPE), buf);
+ return true;
+ } // endswitch typname
+
+ Tabname = GetStringCatInfo(g, "Name", Name); // Deprecated
+ Tabname = GetStringCatInfo(g, "Table_name", Tabname); // Deprecated
+ Tabname = GetStringCatInfo(g, "Tabname", Tabname);
+ Rowname = GetStringCatInfo(g, "Rownode", defrow);
+ Colname = GetStringCatInfo(g, "Colnode", defcol);
+ Mulnode = GetStringCatInfo(g, "Mulnode", NULL);
+ XmlDB = GetStringCatInfo(g, "XmlDB", NULL);
+ Nslist = GetStringCatInfo(g, "Nslist", NULL);
+ DefNs = GetStringCatInfo(g, "DefNs", NULL);
+ Limit = GetIntCatInfo("Limit", 50);
+ Xpand = GetBoolCatInfo("Expand", false);
+ Header = GetIntCatInfo("Header", 0);
+ GetCharCatInfo("Xmlsup", "*", buf, sizeof(buf));
+
+ // Note that if no support is specified, the default is MS-DOM
+ // on Windows and libxml2 otherwise
+ if (*buf == '*')
+#if defined(_WIN32)
+ Usedom = true;
+#else // !_WIN32
+ Usedom = false;
+#endif // !_WIN32
+ else
+ Usedom = (toupper(*buf) == 'M' || toupper(*buf) == 'D');
+
+ // Get eventual table node attribute
+ Attrib = GetStringCatInfo(g, "Attribute", NULL);
+ Hdattr = GetStringCatInfo(g, "HeadAttr", NULL);
+
+ // Specific for zipped files
+ if ((Zipped = GetBoolCatInfo("Zipped", false)))
+ Mulentries = ((Entry = GetStringCatInfo(g, "Entry", NULL)))
+ ? strchr(Entry, '*') || strchr(Entry, '?')
+ : GetBoolCatInfo("Mulentries", false);
+
+ return false;
+ } // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new TDB of the proper type. */
+/***********************************************************************/
+PTDB XMLDEF::GetTable(PGLOBAL g, MODE m)
+ {
+ if (Catfunc == FNC_COL)
+ return new(g) TDBXCT(this);
+
+ if (Zipped && !(m == MODE_READ || m == MODE_ANY)) {
+ strcpy(g->Message, "ZIpped XML tables are read only");
+ return NULL;
+ } // endif Zipped
+
+ PTDBASE tdbp = new(g) TDBXML(this);
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+
+ return tdbp;
+ } // end of GetTable
+
+/* ------------------------- TDBXML Class ---------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBXML constuctor. */
+/***********************************************************************/
+TDBXML::TDBXML(PXMLDEF tdp) : TDBASE(tdp)
+ {
+ Docp = NULL;
+ Root = NULL;
+ Curp = NULL;
+ DBnode = NULL;
+ TabNode = NULL;
+ RowNode = NULL;
+ ColNode = NULL;
+ Nlist = NULL;
+ Clist = NULL;
+ To_Xb = NULL;
+ Colp = NULL;
+ Xfile = tdp->Fn;
+ Enc = tdp->Encoding;
+ Tabname = tdp->Tabname;
+#if 0 // why all these?
+ Rowname = (tdp->Rowname) ? tdp->Rowname : NULL;
+ Colname = (tdp->Colname) ? tdp->Colname : NULL;
+ Mulnode = (tdp->Mulnode) ? tdp->Mulnode : NULL;
+ XmlDB = (tdp->XmlDB) ? tdp->XmlDB : NULL;
+ Nslist = (tdp->Nslist) ? tdp->Nslist : NULL;
+ DefNs = (tdp->DefNs) ? tdp->DefNs : NULL;
+ Attrib = (tdp->Attrib) ? tdp->Attrib : NULL;
+ Hdattr = (tdp->Hdattr) ? tdp->Hdattr : NULL;
+#endif // 0
+ Rowname = tdp->Rowname;
+ Colname = tdp->Colname;
+ Mulnode = tdp->Mulnode;
+ XmlDB = tdp->XmlDB;
+ Nslist = tdp->Nslist;
+ DefNs = tdp->DefNs;
+ Attrib = tdp->Attrib;
+ Hdattr = tdp->Hdattr;
+ Entry = tdp->Entry;
+ Coltype = tdp->Coltype;
+ Limit = tdp->Limit;
+ Xpand = tdp->Xpand;
+ Zipped = tdp->Zipped;
+ Mulentries = tdp->Mulentries;
+ Changed = false;
+ Checked = false;
+ NextSame = false;
+ NewRow = false;
+ Hasnod = false;
+ Write = false;
+ Bufdone = false;
+ Nodedone = false;
+ Void = false;
+ Usedom = tdp->Usedom;
+ Header = tdp->Header;
+ Multiple = tdp->Multiple;
+ Nrow = -1;
+ Irow = Header - 1;
+ Nsub = 0;
+ N = 0;
+ } // end of TDBXML constructor
+
+TDBXML::TDBXML(PTDBXML tdbp) : TDBASE(tdbp)
+ {
+ Docp = tdbp->Docp;
+ Root = tdbp->Root;
+ Curp = tdbp->Curp;
+ DBnode = tdbp->DBnode;
+ TabNode = tdbp->TabNode;
+ RowNode = tdbp->RowNode;
+ ColNode = tdbp->ColNode;
+ Nlist = tdbp->Nlist;
+ Clist = tdbp->Clist;
+ To_Xb = tdbp->To_Xb;
+ Colp = tdbp->Colp;
+ Xfile = tdbp->Xfile;
+ Enc = tdbp->Enc;
+ Tabname = tdbp->Tabname;
+ Rowname = tdbp->Rowname;
+ Colname = tdbp->Colname;
+ Mulnode = tdbp->Mulnode;
+ XmlDB = tdbp->XmlDB;
+ Nslist = tdbp->Nslist;
+ DefNs = tdbp->DefNs;
+ Attrib = tdbp->Attrib;
+ Hdattr = tdbp->Hdattr;
+ Entry = tdbp->Entry;
+ Coltype = tdbp->Coltype;
+ Limit = tdbp->Limit;
+ Xpand = tdbp->Xpand;
+ Zipped = tdbp->Zipped;
+ Mulentries = tdbp->Mulentries;
+ Changed = tdbp->Changed;
+ Checked = tdbp->Checked;
+ NextSame = tdbp->NextSame;
+ NewRow = tdbp->NewRow;
+ Hasnod = tdbp->Hasnod;
+ Write = tdbp->Write;
+ Void = tdbp->Void;
+ Usedom = tdbp->Usedom;
+ Header = tdbp->Header;
+ Multiple = tdbp->Multiple;
+ Nrow = tdbp->Nrow;
+ Irow = tdbp->Irow;
+ Nsub = tdbp->Nsub;
+ N = tdbp->N;
+ } // end of TDBXML copy constructor
+
+// Used for update
+PTDB TDBXML::Clone(PTABS t)
+ {
+ PTDB tp;
+ PXMLCOL cp1, cp2;
+ PGLOBAL g = t->G;
+
+ tp = new(g) TDBXML(this);
+
+ for (cp1 = (PXMLCOL)Columns; cp1; cp1 = (PXMLCOL)cp1->GetNext()) {
+ cp2 = new(g) XMLCOL(cp1, tp); // Make a copy
+ NewPointer(t, cp1, cp2);
+ } // endfor cp1
+
+ return tp;
+ } // end of Clone
+
+/***********************************************************************/
+/* Must not be in tabxml.h because of OEM tables */
+/***********************************************************************/
+const CHARSET_INFO *TDBXML::data_charset()
+{
+ return &my_charset_utf8mb3_general_ci;
+} // end of data_charset
+
+/***********************************************************************/
+/* Allocate XML column description block. */
+/***********************************************************************/
+PCOL TDBXML::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+ {
+ if (trace(1))
+ htrc("TDBXML: MakeCol %s n=%d\n", (cdp) ? cdp->GetName() : "<null>", n);
+
+ return new(g) XMLCOL(cdp, this, cprec, n);
+ } // end of MakeCol
+
+/***********************************************************************/
+/* InsertSpecialColumn: Put a special column ahead of the column list.*/
+/***********************************************************************/
+PCOL TDBXML::InsertSpecialColumn(PCOL colp)
+ {
+ if (!colp->IsSpecial())
+ return NULL;
+
+//if (Xpand && ((SPCBLK*)colp)->GetRnm())
+// colp->SetKey(0); // Rownum is no more a key
+
+ colp->SetNext(Columns);
+ Columns = colp;
+ return colp;
+ } // end of InsertSpecialColumn
+
+/***********************************************************************/
+/* LoadTableFile: Load and parse an XML file. */
+/***********************************************************************/
+int TDBXML::LoadTableFile(PGLOBAL g, char *filename)
+ {
+ int rc = RC_OK, type = (Usedom) ? TYPE_FB_XML : TYPE_FB_XML2;
+ PFBLOCK fp = NULL;
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ if (Docp)
+ return rc; // Already done
+
+ if (trace(1))
+ htrc("TDBXML: loading %s\n", filename);
+
+ /*********************************************************************/
+ /* Firstly we check whether this file have been already loaded. */
+ /*********************************************************************/
+ if ((Mode == MODE_READ || Mode == MODE_ANY) && !Zipped)
+ for (fp = dup->Openlist; fp; fp = fp->Next)
+ if (fp->Type == type && fp->Length && fp->Count)
+ if (!stricmp(fp->Fname, filename))
+ break;
+
+ if (fp) {
+ /*******************************************************************/
+ /* File already loaded. Just increment use count and get pointer. */
+ /*******************************************************************/
+ fp->Count++;
+ Docp = (Usedom) ? GetDomDoc(g, Nslist, DefNs, Enc, fp)
+ : GetLibxmlDoc(g, Nslist, DefNs, Enc, fp);
+ } else {
+ /*******************************************************************/
+ /* Parse the XML file. */
+ /*******************************************************************/
+ if (!(Docp = (Usedom) ? GetDomDoc(g, Nslist, DefNs, Enc)
+ : GetLibxmlDoc(g, Nslist, DefNs, Enc)))
+ return RC_FX;
+
+ // Initialize the implementation
+ if (Docp->Initialize(g, Entry, Zipped)) {
+ sprintf(g->Message, MSG(INIT_FAILED), (Usedom) ? "DOM" : "libxml2");
+ return RC_FX;
+ } // endif init
+
+ if (trace(1))
+ htrc("TDBXML: parsing %s rc=%d\n", filename, rc);
+
+ // Parse the XML file
+ if (Docp->ParseFile(g, filename)) {
+ // Does the file exist?
+ int h= global_open(g, MSGID_NONE, filename, _O_RDONLY);
+
+ if (h != -1) {
+ rc = (!_filelength(h)) ? RC_EF : RC_INFO;
+ close(h);
+ } else
+ rc = (errno == ENOENT) ? RC_NF : RC_INFO;
+
+ // Cannot make a Xblock until document is made
+ return rc;
+ } // endif Docp
+
+ /*******************************************************************/
+ /* Link a Xblock. This make possible to reuse already opened docs */
+ /* and also to automatically close them in case of error g->jump. */
+ /*******************************************************************/
+ fp = Docp->LinkXblock(g, Mode, rc, filename);
+ } // endif xp
+
+ To_Xb = fp; // Useful when closing
+ return rc;
+ } // end of LoadTableFile
+
+/***********************************************************************/
+/* Initialize the processing of the XML file. */
+/* Note: this function can be called several times, eventally before */
+/* the columns are known (from TBL for instance) */
+/***********************************************************************/
+bool TDBXML::Initialize(PGLOBAL g)
+ {
+ int rc;
+ PXMLCOL colp;
+
+ if (Void)
+ return false;
+
+ if (Columns) {
+ // Allocate the buffers that will contain node values
+ for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext())
+ if (!colp->IsSpecial()) { // Not a pseudo column
+ if (!Bufdone && colp->AllocBuf(g, Mode == MODE_INSERT))
+ return true;
+
+ colp->Nx = colp->Sx = -1;
+ } // endif Special
+
+ Bufdone = true;
+ } // endif Bufdone
+
+#if !defined(UNIX)
+ if (!Root) try {
+#else
+ if (!Root) {
+#endif
+ char tabpath[64], filename[_MAX_PATH];
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, Xfile, GetPath());
+
+ // Load or re-use the table file
+ rc = LoadTableFile(g, filename);
+
+ if (rc == RC_OK) {
+ // Get root node
+ if (!(Root = Docp->GetRoot(g))) {
+ // This should never happen as load should have failed
+ strcpy(g->Message, MSG(EMPTY_DOC));
+ goto error;
+ } // endif Root
+
+ // If tabname is not an Xpath,
+ // construct one that will find it anywhere
+ if (!strchr(Tabname, '/'))
+ strcat(strcpy(tabpath, "//"), Tabname);
+ else
+ strcpy(tabpath, Tabname);
+
+ // Evaluate table xpath
+ if ((TabNode = Root->SelectSingleNode(g, tabpath))) {
+ if (TabNode->GetType() != XML_ELEMENT_NODE) {
+ sprintf(g->Message, MSG(BAD_NODE_TYPE), TabNode->GetType());
+ goto error;
+ } // endif Type
+
+ } else if (Mode == MODE_INSERT && XmlDB) {
+ // We are adding a new table to a multi-table file
+
+ // If XmlDB is not an Xpath,
+ // construct one that will find it anywhere
+ if (!strchr(XmlDB, '/'))
+ strcat(strcpy(tabpath, "//"), XmlDB);
+ else
+ strcpy(tabpath, XmlDB);
+
+ if (!(DBnode = Root->SelectSingleNode(g, tabpath))) {
+ // DB node does not exist yet; we cannot create it
+ // because we don't know where it should be placed
+ sprintf(g->Message, MSG(MISSING_NODE), XmlDB, Xfile);
+ goto error;
+ } // endif DBnode
+
+ if (!(TabNode = DBnode->AddChildNode(g, Tabname))) {
+ sprintf(g->Message, MSG(FAIL_ADD_NODE), Tabname);
+ goto error;
+ } // endif TabNode
+
+ DBnode->AddText(g, "\n");
+ } else {
+ TabNode = Root; // Try this ?
+ Tabname = TabNode->GetName(g);
+ } // endif's
+
+ } else if (rc == RC_NF || rc == RC_EF) {
+ // The XML file does not exist or is void
+ if (Mode == MODE_INSERT) {
+ // New Document
+ char buf[64];
+
+ // Create the XML node
+ if (Docp->NewDoc(g, "1.0")) {
+ strcpy(g->Message, MSG(NEW_DOC_FAILED));
+ goto error;
+ } // endif NewDoc
+
+ // Now we can link the Xblock
+ To_Xb = Docp->LinkXblock(g, Mode, rc, filename);
+
+ // Add a CONNECT comment node
+ strcpy(buf, " Created by the MariaDB CONNECT Storage Engine");
+ Docp->AddComment(g, buf);
+
+ if (XmlDB) {
+ // This is a multi-table file
+ DBnode = Root = Docp->NewRoot(g, XmlDB);
+ DBnode->AddText(g, "\n");
+ TabNode = DBnode->AddChildNode(g, Tabname);
+ DBnode->AddText(g, "\n");
+ } else
+ TabNode = Root = Docp->NewRoot(g, Tabname);
+
+ if (TabNode == NULL || Root == NULL) {
+ strcpy(g->Message, MSG(XML_INIT_ERROR));
+ goto error;
+ } else if (SetTabNode(g))
+ goto error;
+
+ } else {
+ sprintf(g->Message, MSG(FILE_UNFOUND), Xfile);
+
+ if (Mode == MODE_READ) {
+ PushWarning(g, this);
+ Void = true;
+ } // endif Mode
+
+ goto error;
+ } // endif Mode
+
+ } else if (rc == RC_INFO) {
+ // Loading failed
+ sprintf(g->Message, MSG(LOADING_FAILED), Xfile);
+ goto error;
+ } else // (rc == RC_FX)
+ goto error;
+
+ if (!Rowname) {
+ for (PXNODE n = TabNode->GetChild(g); n; n = n->GetNext(g))
+ if (n->GetType() == XML_ELEMENT_NODE) {
+ Rowname = n->GetName(g);
+ break;
+ } // endif Type
+
+ if (!Rowname)
+ Rowname = TabNode->GetName(g);
+ } // endif Rowname
+
+ // Get row node list
+ if (strcmp(Rowname, Tabname))
+ Nlist = TabNode->SelectNodes(g, Rowname);
+ else
+ Nrow = 1;
+
+
+ Docp->SetNofree(true); // For libxml2
+#if defined(_WIN32)
+ } catch (_com_error e) {
+ // We come here if a DOM command threw an error
+ char buf[128];
+
+ rc = WideCharToMultiByte(CP_ACP, 0, e.Description(), -1,
+ buf, sizeof(buf), NULL, NULL);
+
+ if (rc)
+ sprintf(g->Message, "%s: %s", MSG(COM_ERROR), buf);
+ else
+ sprintf(g->Message, "%s hr=%x", MSG(COM_ERROR), e.Error());
+
+ goto error;
+#endif // _WIN32
+#if !defined(UNIX)
+ } catch(...) {
+ // Other errors
+ strcpy(g->Message, MSG(XMLTAB_INIT_ERR));
+ goto error;
+#endif
+ } // end of try-catches
+
+ if (Root && Columns && (Multiple || !Nodedone)) {
+ // Allocate class nodes to avoid dynamic allocation
+ for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext())
+ if (!colp->IsSpecial()) // Not a pseudo column
+ colp->AllocNodes(g, Docp);
+
+ Nodedone = true;
+ } // endif Nodedone
+
+ if (Nrow < 0)
+ Nrow = (Nlist) ? Nlist->GetLength() : 0;
+
+ // Init is Ok
+ return false;
+
+error:
+ if (Docp)
+ Docp->CloseDoc(g, To_Xb);
+
+ return !Void;
+} // end of Initialize
+
+/***********************************************************************/
+/* Set TabNode attributes or header. */
+/***********************************************************************/
+bool TDBXML::SetTabNode(PGLOBAL g)
+ {
+ assert(Mode == MODE_INSERT);
+
+ if (Attrib)
+ SetNodeAttr(g, Attrib, TabNode);
+
+ if (Header) {
+ PCOLDEF cdp;
+ PXNODE rn, cn;
+
+ if (Rowname) {
+ TabNode->AddText(g, "\n\t");
+ rn = TabNode->AddChildNode(g, Rowname, NULL);
+ } else {
+ strcpy(g->Message, MSG(NO_ROW_NODE));
+ return true;
+ } // endif Rowname
+
+ if (Hdattr)
+ SetNodeAttr(g, Hdattr, rn);
+
+ for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) {
+ rn->AddText(g, "\n\t\t");
+ cn = rn->AddChildNode(g, "TH", NULL);
+ cn->SetContent(g, (char *)cdp->GetName(),
+ strlen(cdp->GetName()) + 1);
+ } // endfor cdp
+
+ rn->AddText(g, "\n\t");
+ } // endif ColType
+
+ return false;
+ } // end of SetTabNode
+
+/***********************************************************************/
+/* Set attributes of a table or header node. */
+/***********************************************************************/
+void TDBXML::SetNodeAttr(PGLOBAL g, char *attr, PXNODE node)
+ {
+ char *p, *pa, *pn = attr;
+ PXATTR an;
+
+ do {
+ if ((p = strchr(pn, '='))) {
+ pa = pn;
+ *p++ = 0;
+
+ if ((pn = strchr(p, ';')))
+ *pn++ = 0;
+
+ an = node->AddProperty(g, pa, NULL);
+ an->SetText(g, p, strlen(p) + 1);
+ } else
+ break;
+
+ } while (pn);
+
+ } // end of SetNodeAttr
+
+/***********************************************************************/
+/* XML Cardinality: returns table cardinality in number of rows. */
+/* This function can be called with a null argument to test the */
+/* availability of Cardinality implementation (1 yes, 0 no). */
+/***********************************************************************/
+int TDBXML::Cardinality(PGLOBAL g)
+ {
+ if (!g)
+ return (Multiple || Xpand || Coltype == 2) ? 0 : 1;
+
+ if (Multiple)
+ return 10;
+
+ if (Nrow < 0)
+ if (Initialize(g))
+ return -1;
+
+ return (Void) ? 0 : Nrow - Header;
+ } // end of Cardinality
+
+/***********************************************************************/
+/* XML GetMaxSize: returns the number of tables in the database. */
+/***********************************************************************/
+int TDBXML::GetMaxSize(PGLOBAL g)
+ {
+ if (MaxSize < 0) {
+ if (!Multiple)
+ MaxSize = Cardinality(g) * ((Xpand) ? Limit : 1);
+ else
+ MaxSize = 10;
+
+ } // endif MaxSize
+
+ return MaxSize;
+ } // end of GetMaxSize
+
+/***********************************************************************/
+/* Return the position in the table. */
+/***********************************************************************/
+int TDBXML::GetRecpos(void)
+ {
+ union {
+ uint Rpos;
+ BYTE Spos[4];
+ };
+
+ Rpos = htonl(Irow);
+ Spos[0] = (BYTE)Nsub;
+ return Rpos;
+ } // end of GetRecpos
+
+/***********************************************************************/
+/* RowNumber: return the ordinal number of the current row. */
+/***********************************************************************/
+int TDBXML::RowNumber(PGLOBAL g, bool b)
+ {
+ if (To_Kindex && (Xpand || Coltype == 2) && !b) {
+ /*******************************************************************/
+ /* Don't know how to retrieve RowID for expanded XML tables. */
+ /*******************************************************************/
+ sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
+ GetAmName(g, GetAmType()));
+ return 0; // Means error
+ } else
+ return (b || !(Xpand || Coltype == 2)) ? Irow - Header + 1 : N;
+
+ } // end of RowNumber
+
+/***********************************************************************/
+/* XML Access Method opening routine. */
+/***********************************************************************/
+bool TDBXML::OpenDB(PGLOBAL g)
+ {
+ if (Use == USE_OPEN) {
+ /*******************************************************************/
+ /* Table already open replace it at its beginning. */
+ /*******************************************************************/
+ if (!To_Kindex) {
+ Irow = Header - 1;
+ Nsub = 0;
+ } else
+ /*****************************************************************/
+ /* Table is to be accessed through a sorted index table. */
+ /*****************************************************************/
+ To_Kindex->Reset();
+
+ return false;
+ } // endif use
+
+ /*********************************************************************/
+ /* OpenDB: initialize the XML file processing. */
+ /*********************************************************************/
+ Write = (Mode == MODE_INSERT || Mode == MODE_UPDATE);
+
+ if (Initialize(g))
+ return true;
+
+ NewRow = (Mode == MODE_INSERT);
+ Nsub = 0;
+ Use = USE_OPEN; // Do it now in case we are recursively called
+ return false;
+ } // end of OpenDB
+
+/***********************************************************************/
+/* Data Base read routine for XML access method. */
+/***********************************************************************/
+int TDBXML::ReadDB(PGLOBAL g)
+ {
+ bool same;
+
+ if (Void)
+ return RC_EF;
+
+ /*********************************************************************/
+ /* Now start the pseudo reading process. */
+ /*********************************************************************/
+ if (To_Kindex) {
+ /*******************************************************************/
+ /* Reading is by an index table. */
+ /*******************************************************************/
+ union {
+ uint Rpos;
+ BYTE Spos[4];
+ };
+
+ int recpos = To_Kindex->Fetch(g);
+
+ switch (recpos) {
+ case -1: // End of file reached
+ return RC_EF;
+ case -2: // No match for join
+ return RC_NF;
+ case -3: // Same record as last non null one
+ same = true;
+ return RC_OK;
+ default:
+ Rpos = recpos;
+ Nsub = Spos[0];
+ Spos[0] = 0;
+
+ if (Irow != (signed)ntohl(Rpos)) {
+ Irow = ntohl(Rpos);
+ same = false;
+ } else
+ same = true;
+
+ } // endswitch recpos
+
+ } else {
+ if (trace(1))
+ htrc("TDBXML ReadDB: Irow=%d Nrow=%d\n", Irow, Nrow);
+
+ // This is to force the table to be expanded when constructing
+ // an index for which the expand column is not specified.
+ if (Colp && Irow >= Header) {
+ Colp->Eval(g);
+ Colp->Reset();
+ } // endif Colp
+
+ if (!NextSame) {
+ if (++Irow == Nrow)
+ return RC_EF;
+
+ same = false;
+ Nsub = 0;
+ } else {
+ // Not sure the multiple column read will be called
+ NextSame = false;
+ same = true;
+ Nsub++;
+ } // endif NextSame
+
+ N++; // RowID
+ } // endif To_Kindex
+
+ if (!same) {
+ if (trace(2))
+ htrc("TDBXML ReadDB: Irow=%d RowNode=%p\n", Irow, RowNode);
+
+ // Get the new row node
+ if (Nlist) {
+ if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
+ sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
+ return RC_FX;
+ } // endif RowNode
+
+ } else
+ RowNode = TabNode;
+
+ if (Colname && Coltype == 2)
+ Clist = RowNode->SelectNodes(g, Colname, Clist);
+
+ } // endif same
+
+ return RC_OK;
+ } // end of ReadDB
+
+/***********************************************************************/
+/* CheckRow: called On Insert and Update. Must create the Row node */
+/* if it does not exist (Insert) and update the Clist if called by */
+/* a column having an Xpath because it can use an existing node that */
+/* was added while inserting or Updating this row. */
+/***********************************************************************/
+bool TDBXML::CheckRow(PGLOBAL g, bool b)
+ {
+ if (NewRow && Mode == MODE_INSERT)
+ {
+ if (Rowname) {
+ TabNode->AddText(g, "\n\t");
+ RowNode = TabNode->AddChildNode(g, Rowname, RowNode);
+ } else {
+ strcpy(g->Message, MSG(NO_ROW_NODE));
+ return true;
+ } // endif Rowname
+ }
+
+ if (Colname && (NewRow || b))
+ Clist = RowNode->SelectNodes(g, Colname, Clist);
+
+ return NewRow = false;
+ } // end of CheckRow
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for XDB access methods. */
+/***********************************************************************/
+int TDBXML::WriteDB(PGLOBAL g)
+ {
+ if (Mode == MODE_INSERT) {
+ if (Hasnod)
+ RowNode->AddText(g, "\n\t");
+
+ NewRow = true;
+ } // endif Mode
+
+ // Something was changed in the document
+ Changed = true;
+ return RC_OK;
+ } // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for XDB access methods. */
+/***********************************************************************/
+int TDBXML::DeleteDB(PGLOBAL g, int irc)
+ {
+ // TODO: Handle null Nlist
+ if (irc == RC_FX) {
+ // Delete all rows
+ for (Irow = 0; Irow < Nrow; Irow++)
+ if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
+ sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
+ return RC_FX;
+ } else {
+ TabNode->DeleteChild(g, RowNode);
+
+ if (Nlist->DropItem(g, Irow))
+ return RC_FX;
+
+ } // endif RowNode
+
+ Changed = true;
+ } else if (irc != RC_EF) {
+ TabNode->DeleteChild(g, RowNode);
+
+ if (Nlist->DropItem(g, Irow))
+ return RC_FX;
+
+ Changed = true;
+ } // endif's irc
+
+ return RC_OK;
+ } // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for XDB access methods. */
+/***********************************************************************/
+void TDBXML::CloseDB(PGLOBAL g)
+ {
+ if (Docp) {
+ if (Changed) {
+ char filename[_MAX_PATH];
+
+ // We used the file name relative to recorded datapath
+ PlugSetPath(filename, Xfile, GetPath());
+
+ if (Mode == MODE_INSERT)
+ TabNode->AddText(g, "\n");
+
+ // Save the modified document
+ if (Docp->DumpDoc(g, filename)) {
+ PushWarning(g, this);
+ Docp->CloseDoc(g, To_Xb);
+
+ // This causes a crash in Diagnostics_area::set_error_status
+// throw (int)TYPE_AM_XML;
+ } // endif DumpDoc
+
+ } // endif Changed
+
+ // Free the document and terminate XML processing
+ Docp->CloseDoc(g, To_Xb);
+ } // endif docp
+
+ if (Multiple) {
+ // Reset all constants to start a new parse
+ Docp = NULL;
+ Root = NULL;
+ Curp = NULL;
+ DBnode = NULL;
+ TabNode = NULL;
+ RowNode = NULL;
+ ColNode = NULL;
+ Nlist = NULL;
+ Clist = NULL;
+ To_Xb = NULL;
+ Colp = NULL;
+ Changed = false;
+ Checked = false;
+ NextSame = false;
+ NewRow = false;
+ Hasnod = false;
+ Write = false;
+ Nodedone = false;
+ Void = false;
+ Nrow = -1;
+ Irow = Header - 1;
+ Nsub = 0;
+ N = 0;
+ } // endif Multiple
+
+ } // end of CloseDB
+
+// ------------------------ XMLCOL functions ----------------------------
+
+/***********************************************************************/
+/* XMLCOL public constructor. */
+/***********************************************************************/
+XMLCOL::XMLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : COLBLK(cdp, tdbp, i)
+ {
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ // Set additional XML access method information for column.
+ Tdbp = (PTDBXML)tdbp;
+ Nl = NULL;
+ Nlx = NULL;
+ ColNode = NULL;
+ ValNode = NULL;
+ Cxnp = NULL;
+ Vxnp = NULL;
+ Vxap = NULL;
+ AttNode = NULL;
+ Nodes = NULL;
+ Nod = 0;
+ Inod = -1;
+ Mul = false;
+ Checked = false;
+ Xname = cdp->GetFmt();
+ Long = cdp->GetLong();
+ Rank = cdp->GetOffset();
+ Type = Tdbp->Coltype;
+ Nx = -1;
+ Sx = -1;
+ N = 0;
+ Valbuf = NULL;
+ To_Val = NULL;
+ } // end of XMLCOL constructor
+
+/***********************************************************************/
+/* XMLCOL constructor used for copying columns. */
+/* tdbp is the pointer to the new table descriptor. */
+/***********************************************************************/
+XMLCOL::XMLCOL(XMLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
+ {
+ Tdbp = col1->Tdbp;
+ Nl = col1->Nl;
+ Nlx = col1->Nlx;
+ ColNode = col1->ColNode;
+ ValNode = col1->ValNode;
+ Cxnp = col1->Cxnp;
+ Vxnp = col1->Vxnp;
+ Vxap = col1->Vxap;
+ AttNode = col1->AttNode;
+ Nodes = col1->Nodes;
+ Nod = col1->Nod;
+ Inod = col1->Inod;
+ Mul = col1->Mul;
+ Checked = col1->Checked;
+ Xname = col1->Xname;
+ Valbuf = col1->Valbuf;
+ Long = col1->Long;
+ Rank = col1->Rank;
+ Nx = col1->Nx;
+ Sx = col1->Sx;
+ N = col1->N;
+ Type = col1->Type;
+ To_Val = col1->To_Val;
+ } // end of XMLCOL copy constructor
+
+/***********************************************************************/
+/* Allocate a buffer of the proper size. */
+/***********************************************************************/
+bool XMLCOL::AllocBuf(PGLOBAL g, bool mode)
+ {
+ if (Valbuf)
+ return false; // Already done
+
+ return ParseXpath(g, mode);
+ } // end of AllocBuf
+
+/***********************************************************************/
+/* Parse the eventual passed Xpath information. */
+/* This information can be specified in the Xpath (or Fieldfmt) */
+/* column option when creating the table. It permits to indicate the */
+/* position of the node corresponding to that column in a Xpath-like */
+/* language (but not a truly compliant one). */
+/***********************************************************************/
+bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
+ {
+ char *p, *p2, *pbuf = NULL;
+ int i, n = 1, len = strlen(Name);
+
+ len += ((Tdbp->Colname) ? strlen(Tdbp->Colname) : 0);
+ len += ((Xname) ? strlen(Xname) : 0);
+ pbuf = (char*)PlugSubAlloc(g, NULL, len + 3);
+ *pbuf = '\0';
+
+ if (!mode)
+ // Take care of an eventual extra column node a la html
+ if (Tdbp->Colname) {
+ sprintf(pbuf, Tdbp->Colname, Rank + ((Tdbp->Usedom) ? 0 : 1));
+ strcat(pbuf, "/");
+ } // endif Colname
+
+ if (Xname) {
+ if (Type == 2) {
+ sprintf(g->Message, MSG(BAD_COL_XPATH), Name, Tdbp->Name);
+ return true;
+ } else
+ strcat(pbuf, Xname);
+
+ if (trace(1))
+ htrc("XMLCOL: pbuf=%s\n", pbuf);
+
+ // For Update or Insert the Xpath must be analyzed
+ if (mode) {
+ for (i = 0, p = pbuf; (p = strchr(p, '/')); i++, p++)
+ Nod++; // One path node found
+
+ if (Nod)
+ Nodes = (char**)PlugSubAlloc(g, NULL, Nod * sizeof(char*));
+
+ } // endif mode
+
+ // Analyze the Xpath for this column
+ for (i = 0, p = pbuf; (p2 = strchr(p, '/')); i++, p = p2 + 1) {
+ if (Tdbp->Mulnode && !strncmp(p, Tdbp->Mulnode, p2 - p))
+ {
+ if (!Tdbp->Xpand && mode) {
+ strcpy(g->Message, MSG(CONCAT_SUBNODE));
+ return true;
+ } else
+ Inod = i; // Index of multiple node
+ }
+
+ if (mode) {
+ // For Update or Insert the Xpath must be explicit
+ if (strchr("@/.*", *p)) {
+ sprintf(g->Message, MSG(XPATH_NOT_SUPP), Name);
+ return true;
+ } else
+ Nodes[i] = p;
+
+ *p2 = '\0';
+ } // endif mode
+
+ } // endfor i, p
+
+ if (*p == '/' || *p == '.') {
+ sprintf(g->Message, MSG(XPATH_NOT_SUPP), Name);
+ return true;
+ } else if (*p == '@') {
+ p++; // Remove the @ if mode
+ Type = 0; // Column is an attribute
+ } else
+ Type = 1; // Column is a node
+
+ if (!*p)
+ strcpy(p, Name); // Xname is column name
+
+ if (Type && Tdbp->Mulnode && !strcmp(p, Tdbp->Mulnode))
+ Inod = Nod; // Index of multiple node
+
+ if (mode) // Prepare Xname
+ pbuf = p;
+
+ } else if (Type == 2) {
+ // HTML like table, columns are retrieved by position
+ new(this) XPOSCOL(Value); // Change the class of this column
+ Inod = -1;
+ } else if (Type == 0 && !mode) {
+ strcat(strcat(pbuf, "@"), Name);
+ } else { // Type == 1
+ if (Tdbp->Mulnode && !strcmp(Name, Tdbp->Mulnode))
+ Inod = 0; // Nod
+
+ strcat(pbuf, Name);
+ } // endif,s
+
+ if (Inod >= 0) {
+ Tdbp->Colp = this; // To force expand
+
+ if (Tdbp->Xpand)
+ n = Tdbp->Limit;
+
+ new(this) XMULCOL(Value); // Change the class of this column
+ } // endif Inod
+
+ Valbuf = (char*)PlugSubAlloc(g, NULL, n * (Long + 1));
+
+ for (i = 0; i < n; i++)
+ Valbuf[Long + (i * (Long + 1))] = '\0';
+
+ if (Type || Nod)
+ Tdbp->Hasnod = true;
+
+ if (trace(1))
+ htrc("XMLCOL: Xname=%s\n", pbuf);
+
+ // Save the calculated Xpath
+ Xname = pbuf;
+ return false;
+ } // end of ParseXpath
+
+/***********************************************************************/
+/* SetBuffer: prepare a column block for write operation. */
+/***********************************************************************/
+bool XMLCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
+ {
+ if (!(To_Val = value)) {
+ sprintf(g->Message, MSG(VALUE_ERROR), Name);
+ return true;
+ } else if (Buf_Type == value->GetType()) {
+ // Values are of the (good) column type
+ if (Buf_Type == TYPE_DATE) {
+ // If any of the date values is formatted
+ // output format must be set for the receiving table
+ if (GetDomain() || ((DTVAL *)value)->IsFormatted())
+ goto newval; // This will make a new value;
+
+ } else if (Buf_Type == TYPE_DOUBLE)
+ // Float values must be written with the correct (column) precision
+ // Note: maybe this should be forced by ShowValue instead of this ?
+ value->SetPrec(GetScale());
+
+ Value = value; // Directly access the external value
+ } else {
+ // Values are not of the (good) column type
+ if (check) {
+ sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
+ GetTypeName(Buf_Type), GetTypeName(value->GetType()));
+ return true;
+ } // endif check
+
+ newval:
+ if (InitValue(g)) // Allocate the matching value block
+ return true;
+
+ } // endif's Value, Buf_Type
+
+ // Because Colblk's have been made from a copy of the original TDB in
+ // case of Update, we must reset them to point to the original one.
+ if (To_Tdb->GetOrig()) {
+ To_Tdb = (PTDB)To_Tdb->GetOrig();
+ Tdbp = (PTDBXML)To_Tdb; // Specific of XMLCOL
+
+ // Allocate the XML buffer
+ if (AllocBuf(g, true)) // In Write mode
+ return true;
+
+ } // endif GetOrig
+
+ // Set the Column
+ Status = (ok) ? BUF_EMPTY : BUF_NO;
+ return false;
+ } // end of SetBuffer
+
+/***********************************************************************/
+/* Alloc the nodes that will be used during the whole process. */
+/***********************************************************************/
+void XMLCOL::AllocNodes(PGLOBAL g, PXDOC dp)
+{
+ Cxnp = dp->NewPnode(g);
+ Vxnp = dp->NewPnode(g);
+ Vxap = dp->NewPattr(g);
+} // end of AllocNodes
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the column node */
+/* from the corresponding table, extract from it the node text and */
+/* convert it to the column type. */
+/***********************************************************************/
+void XMLCOL::ReadColumn(PGLOBAL g)
+ {
+ if (Nx == Tdbp->Irow)
+ return; // Same row than the last read
+
+ ValNode = Tdbp->RowNode->SelectSingleNode(g, Xname, Vxnp);
+
+ if (ValNode) {
+ if (ValNode->GetType() != XML_ELEMENT_NODE &&
+ ValNode->GetType() != XML_ATTRIBUTE_NODE) {
+ sprintf(g->Message, MSG(BAD_VALNODE), ValNode->GetType(), Name);
+ throw (int)TYPE_AM_XML;
+ } // endif type
+
+ // Get the Xname value from the XML file
+ switch (ValNode->GetContent(g, Valbuf, Long + 1)) {
+ case RC_OK:
+ break;
+ case RC_INFO:
+ PushWarning(g, Tdbp);
+ break;
+ default:
+ throw (int)TYPE_AM_XML;
+ } // endswitch
+
+ Value->SetValue_psz(Valbuf);
+ } else {
+ if (Nullable)
+ Value->SetNull(true);
+
+ Value->Reset(); // Null value
+ } // endif ValNode
+
+ Nx = Tdbp->Irow;
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last row of */
+/* the corresponding table, and rewrite the content corresponding */
+/* to this column node from the column buffer and type. */
+/***********************************************************************/
+void XMLCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, buf[16];
+ int done = 0;
+ int i, n, k = 0;
+ PXNODE TopNode = NULL;
+
+ if (trace(2))
+ htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, Tdbp->GetTdb_No(), ColUse, Status);
+
+ /*********************************************************************/
+ /* Check whether this node must be written. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ /*********************************************************************/
+ /* If a check pass was done while updating, all node contruction */
+ /* has been already one. */
+ /*********************************************************************/
+ if (Status && Tdbp->Checked && !Value->IsNull()) {
+ assert (ColNode != NULL);
+ assert ((Type ? (void *)ValNode : (void *)AttNode) != NULL);
+ goto fin;
+ } // endif Checked
+
+ /*********************************************************************/
+ /* On Insert, a Row node must be created for each row; */
+ /* For columns having an Xpath, the Clist must be updated. */
+ /*********************************************************************/
+ if (Tdbp->CheckRow(g, Nod || Tdbp->Colname))
+ throw (int)TYPE_AM_XML;
+
+ /*********************************************************************/
+ /* Null values are represented by no node. */
+ /*********************************************************************/
+ if (Value->IsNull())
+ return;
+
+ /*********************************************************************/
+ /* Find the column and value nodes to update or insert. */
+ /*********************************************************************/
+ if (Tdbp->Clist) {
+ n = Tdbp->Clist->GetLength();
+ ColNode = NULL;
+ } else {
+ n = 1;
+ ColNode = Tdbp->RowNode->Clone(g, ColNode);
+ } // endif Clist
+
+ ValNode = NULL;
+
+ for (i = 0; i < n; i++) {
+ if (Tdbp->Clist)
+ ColNode = Tdbp->Clist->GetItem(g, i, Cxnp);
+
+ /*******************************************************************/
+ /* Check whether an Xpath was provided to go to the column node. */
+ /*******************************************************************/
+ for (k = 0; k < Nod; k++)
+ if ((ColNode = ColNode->SelectSingleNode(g, Nodes[k], Cxnp)))
+ TopNode = ColNode;
+ else
+ break;
+
+ if (ColNode)
+ {
+ if (Type)
+ ValNode = ColNode->SelectSingleNode(g, Xname, Vxnp);
+ else
+ AttNode = ColNode->GetAttribute(g, Xname, Vxap);
+ }
+
+ if (TopNode || ValNode || AttNode)
+ break; // We found the good column
+ else if (Tdbp->Clist)
+ ColNode = NULL;
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* Create missing nodes. */
+ /*********************************************************************/
+ if (ColNode == NULL) {
+ if (TopNode == NULL)
+ {
+ if (Tdbp->Clist) {
+ Tdbp->RowNode->AddText(g, "\n\t\t");
+ ColNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname);
+ done = 2;
+ TopNode = ColNode;
+ } else
+ TopNode = Tdbp->RowNode;
+ }
+ for (; k < Nod && TopNode; k++) {
+ if (!done) {
+ TopNode->AddText(g, "\n\t\t");
+ done = 1;
+ } // endif done
+
+ ColNode = TopNode->AddChildNode(g, Nodes[k], Cxnp);
+ TopNode = ColNode;
+ } // endfor k
+
+ if (ColNode == NULL) {
+ strcpy(g->Message, MSG(COL_ALLOC_ERR));
+ throw (int)TYPE_AM_XML;
+ } // endif ColNode
+
+ } // endif ColNode
+
+ if (Type == 1) {
+ if (ValNode == NULL) {
+ if (done < 2)
+ ColNode->AddText(g, "\n\t\t");
+
+ ValNode = ColNode->AddChildNode(g, Xname, Vxnp);
+ } // endif ValNode
+
+ } else // (Type == 0)
+ if (AttNode == NULL)
+ AttNode = ColNode->AddProperty(g, Xname, Vxap);
+
+ if (ValNode == NULL && AttNode == NULL) {
+ strcpy(g->Message, MSG(VAL_ALLOC_ERR));
+ throw (int)TYPE_AM_XML;
+ } // endif ValNode
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ p = Value->GetCharString(buf);
+
+ if (strlen(p) > (unsigned)Long) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
+ throw (int)TYPE_AM_XML;
+ } else
+ strcpy(Valbuf, p);
+
+ /*********************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*********************************************************************/
+ fin:
+ if (Status) {
+ if (Type) {
+ ValNode->SetContent(g, Valbuf, Long);
+ } else
+ AttNode->SetText(g, Valbuf, Long);
+
+ } // endif Status
+
+ } // end of WriteColumn
+
+// ------------------------ XMULCOL functions ---------------------------
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the column node */
+/* from the corresponding table, extract from it the node text and */
+/* convert it to the column type. */
+/***********************************************************************/
+void XMULCOL::ReadColumn(PGLOBAL g)
+ {
+ char *p;
+ int i, len;
+ bool b = Tdbp->Xpand;
+
+ if (Nx != Tdbp->Irow) { // New row
+ Nl = Tdbp->RowNode->SelectNodes(g, Xname, Nl);
+
+ if ((N = Nl->GetLength())) {
+ *(p = Valbuf) = '\0';
+ len = Long;
+
+ if (N > Tdbp->Limit) {
+ N = Tdbp->Limit;
+ sprintf(g->Message, "Multiple values limited to %d", Tdbp->Limit);
+ PushWarning(g, Tdbp);
+ } // endif N
+
+ for (i = 0; i < N; i++) {
+ ValNode = Nl->GetItem(g, i, Vxnp);
+
+ if (ValNode->GetType() != XML_ELEMENT_NODE &&
+ ValNode->GetType() != XML_ATTRIBUTE_NODE) {
+ sprintf(g->Message, MSG(BAD_VALNODE), ValNode->GetType(), Name);
+ throw (int)TYPE_AM_XML;
+ } // endif type
+
+ // Get the Xname value from the XML file
+ switch (ValNode->GetContent(g, p, (b ? Long : len))) {
+ case RC_OK:
+ break;
+ case RC_INFO:
+ PushWarning(g, Tdbp);
+ break;
+ default:
+ throw (int)TYPE_AM_XML;
+ } // endswitch
+
+ if (!b) {
+ // Concatenate all values
+ if (N - i > 1)
+ strncat(Valbuf, ", ", len - strlen(p));
+
+ if ((len -= strlen(p)) <= 0)
+ break;
+
+ p += strlen(p);
+ } else // Xpand
+ p += (Long + 1);
+
+ } // endfor i
+
+ Value->SetValue_psz(Valbuf);
+ } else {
+ if (Nullable)
+ Value->SetNull(true);
+
+ Value->Reset(); // Null value
+ } // endif ValNode
+
+ } else if (Sx == Tdbp->Nsub)
+ return; // Same row
+ else // Expanded value
+ Value->SetValue_psz(Valbuf + (Tdbp->Nsub * (Long + 1)));
+
+ Nx = Tdbp->Irow;
+ Sx = Tdbp->Nsub;
+ Tdbp->NextSame = (Tdbp->Xpand && N - Sx > 1);
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last line */
+/* read from the corresponding table, and rewrite the field */
+/* corresponding to this column from the column buffer and type. */
+/***********************************************************************/
+void XMULCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, buf[16];
+ int done = 0;
+ int i, n, len, k = 0;
+ PXNODE TopNode = NULL;
+
+ if (trace(1))
+ htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, Tdbp->GetTdb_No(), ColUse, Status);
+
+ /*********************************************************************/
+ /* Check whether this node must be written. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ if (Value->IsNull())
+ return;
+
+ /*********************************************************************/
+ /* If a check pass was done while updating, all node contruction */
+ /* has been already one. */
+ /*********************************************************************/
+ if (Status && Tdbp->Checked) {
+ assert (ColNode);
+ assert ((Type ? (void *)ValNode : (void *)AttNode) != NULL);
+ goto fin;
+ } // endif Checked
+
+ /*********************************************************************/
+ /* On Insert, a Row node must be created for each row; */
+ /* For columns having an Xpath, the Clist must be updated. */
+ /*********************************************************************/
+ if (Tdbp->CheckRow(g, Nod))
+ throw (int)TYPE_AM_XML;
+
+ /*********************************************************************/
+ /* Find the column and value nodes to update or insert. */
+ /*********************************************************************/
+ if (Tdbp->Clist) {
+ n = Tdbp->Clist->GetLength();
+ ColNode = NULL;
+ } else {
+ n = 1;
+ ColNode = Tdbp->RowNode->Clone(g, ColNode);
+ } // endif Clist
+
+ ValNode = NULL;
+
+ for (i = 0; i < n; i++) {
+ if (Tdbp->Clist)
+ ColNode = Tdbp->Clist->GetItem(g, i, Cxnp);
+
+ /*******************************************************************/
+ /* Check whether an Xpath was provided to go to the column node. */
+ /*******************************************************************/
+ for (k = 0; k < Nod; k++) {
+ if (k == Inod) {
+ // This is the multiple node
+ Nlx = ColNode->SelectNodes(g, Nodes[k], Nlx);
+ ColNode = Nlx->GetItem(g, Tdbp->Nsub, Cxnp);
+ } else
+ ColNode = ColNode->SelectSingleNode(g, Nodes[k], Cxnp);
+
+ if (ColNode == NULL)
+ break;
+
+ TopNode = ColNode;
+ } // endfor k
+
+ if (ColNode)
+ {
+ if (Inod == Nod) {
+ /***************************************************************/
+ /* The node value can be multiple. */
+ /***************************************************************/
+ assert (Type);
+
+ // Get the value Node from the XML list
+ Nlx = ColNode->SelectNodes(g, Xname, Nlx);
+ len = Nlx->GetLength();
+
+ if (len > 1 && !Tdbp->Xpand) {
+ sprintf(g->Message, MSG(BAD_VAL_UPDATE), Name);
+ throw (int)TYPE_AM_XML;
+ } else
+ ValNode = Nlx->GetItem(g, Tdbp->Nsub, Vxnp);
+
+ } else // Inod != Nod
+ {
+ if (Type)
+ ValNode = ColNode->SelectSingleNode(g, Xname, Vxnp);
+ else
+ AttNode = ColNode->GetAttribute(g, Xname, Vxap);
+ }
+ }
+ if (TopNode || ValNode || AttNode)
+ break; // We found the good column
+ else if (Tdbp->Clist)
+ ColNode = NULL;
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* Create missing nodes. */
+ /*********************************************************************/
+ if (ColNode == NULL) {
+ if (TopNode == NULL)
+ {
+ if (Tdbp->Clist) {
+ Tdbp->RowNode->AddText(g, "\n\t\t");
+ ColNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname);
+ done = 2;
+ TopNode = ColNode;
+ } else
+ TopNode = Tdbp->RowNode;
+ }
+
+ for (; k < Nod && TopNode; k++) {
+ if (!done) {
+ TopNode->AddText(g, "\n\t\t");
+ done = 1;
+ } // endif done
+
+ ColNode = TopNode->AddChildNode(g, Nodes[k], Cxnp);
+ TopNode = ColNode;
+ } // endfor k
+
+ if (ColNode == NULL) {
+ strcpy(g->Message, MSG(COL_ALLOC_ERR));
+ throw (int)TYPE_AM_XML;
+ } // endif ColNode
+
+ } // endif ColNode
+
+ if (Type == 1) {
+ if (ValNode == NULL) {
+ if (done < 2)
+ ColNode->AddText(g, "\n\t\t");
+
+ ValNode = ColNode->AddChildNode(g, Xname, Vxnp);
+ } // endif ValNode
+
+ } else // (Type == 0)
+ if (AttNode == NULL)
+ AttNode = ColNode->AddProperty(g, Xname, Vxap);
+
+ if (ValNode == NULL && AttNode == NULL) {
+ strcpy(g->Message, MSG(VAL_ALLOC_ERR));
+ throw (int)TYPE_AM_XML;
+ } // endif ValNode
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ p = Value->GetCharString(buf);
+
+ if (strlen(p) > (unsigned)Long) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
+ throw (int)TYPE_AM_XML;
+ } else
+ strcpy(Valbuf, p);
+
+ /*********************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*********************************************************************/
+ fin:
+ if (Status) {
+ if (Type) {
+ ValNode->SetContent(g, Valbuf, Long);
+ } else
+ AttNode->SetText(g, Valbuf, Long);
+
+ } // endif Status
+
+ } // end of WriteColumn
+
+/* ------------------------ XPOSCOL functions ------------------------ */
+
+/***********************************************************************/
+/* ReadColumn: what this routine does is to access the column node */
+/* from the corresponding table, extract from it the node text and */
+/* convert it to the column type. */
+/***********************************************************************/
+void XPOSCOL::ReadColumn(PGLOBAL g)
+ {
+ if (Nx == Tdbp->Irow)
+ return; // Same row than the last read
+
+ if (Tdbp->Clist == NULL) {
+ strcpy(g->Message, MSG(MIS_TAG_LIST));
+ throw (int)TYPE_AM_XML;
+ } // endif Clist
+
+ if ((ValNode = Tdbp->Clist->GetItem(g, Rank, Vxnp))) {
+ // Get the column value from the XML file
+ switch (ValNode->GetContent(g, Valbuf, Long + 1)) {
+ case RC_OK:
+ break;
+ case RC_INFO:
+ PushWarning(g, Tdbp);
+ break;
+ default:
+ throw (int)TYPE_AM_XML;
+ } // endswitch
+
+ Value->SetValue_psz(Valbuf);
+ } else {
+ if (Nullable)
+ Value->SetNull(true);
+
+ Value->Reset(); // Null value
+ } // endif ValNode
+
+ Nx = Tdbp->Irow;
+ } // end of ReadColumn
+
+/***********************************************************************/
+/* WriteColumn: what this routine does is to access the last line */
+/* read from the corresponding table, and rewrite the field */
+/* corresponding to this column from the column buffer and type. */
+/***********************************************************************/
+void XPOSCOL::WriteColumn(PGLOBAL g)
+ {
+ char *p, buf[16];
+ int i, k, n;
+
+ if (trace(1))
+ htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
+ Name, Tdbp->GetTdb_No(), ColUse, Status);
+
+ /*********************************************************************/
+ /* Check whether this node must be written. */
+ /*********************************************************************/
+ if (Value != To_Val)
+ Value->SetValue_pval(To_Val, false); // Convert the updated value
+
+ if (Value->IsNull())
+ return;
+
+ /*********************************************************************/
+ /* If a check pass was done while updating, all node contruction */
+ /* has been already one. */
+ /*********************************************************************/
+ if (Status && Tdbp->Checked) {
+ assert (ValNode);
+ goto fin;
+ } // endif Checked
+
+ /*********************************************************************/
+ /* On Insert, a Row node must be created for each row; */
+ /* For all columns the Clist must be updated. */
+ /*********************************************************************/
+ if (Tdbp->CheckRow(g, true))
+ throw (int)TYPE_AM_XML;
+
+ /*********************************************************************/
+ /* Find the column and value nodes to update or insert. */
+ /*********************************************************************/
+ if (Tdbp->Clist == NULL) {
+ strcpy(g->Message, MSG(MIS_TAG_LIST));
+ throw (int)TYPE_AM_XML;
+ } // endif Clist
+
+ n = Tdbp->Clist->GetLength();
+ k = Rank;
+
+ if (!(ValNode = Tdbp->Clist->GetItem(g, k, Vxnp))) {
+ /*******************************************************************/
+ /* Create missing column nodes. */
+ /*******************************************************************/
+ Tdbp->RowNode->AddText(g, "\n\t\t");
+
+ for (i = n; i <= k; i++)
+ ValNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname, Vxnp);
+
+ assert (ValNode);
+ } // endif ValNode
+
+ /*********************************************************************/
+ /* Get the string representation of Value according to column type. */
+ /*********************************************************************/
+ p = Value->GetCharString(buf);
+
+ if (strlen(p) > (unsigned)Long) {
+ sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
+ throw (int)TYPE_AM_XML;
+ } else
+ strcpy(Valbuf, p);
+
+ /*********************************************************************/
+ /* Updating must be done only when not in checking pass. */
+ /*********************************************************************/
+ fin:
+ if (Status)
+ ValNode->SetContent(g, Valbuf, Long);
+
+ } // end of WriteColumn
+
+/* ---------------------------TDBXCT class --------------------------- */
+
+/***********************************************************************/
+/* TDBXCT class constructor. */
+/***********************************************************************/
+TDBXCT::TDBXCT(PXMLDEF tdp) : TDBCAT(tdp)
+ {
+ Topt = tdp->GetTopt();
+ //Db = (char*)tdp->GetDB();
+ Db = (char*)tdp->Schema;
+ Tabn = tdp->Tabname;
+ } // end of TDBXCT constructor
+
+/***********************************************************************/
+/* GetResult: Get the list the JSON file columns. */
+/***********************************************************************/
+PQRYRES TDBXCT::GetResult(PGLOBAL g)
+ {
+ return XMLColumns(g, Db, Tabn, Topt, false);
+ } // end of GetResult
+
+/* ------------------------ End of Tabxml ---------------------------- */
diff --git a/storage/connect/tabxml.h b/storage/connect/tabxml.h
new file mode 100644
index 00000000..42dbb038
--- /dev/null
+++ b/storage/connect/tabxml.h
@@ -0,0 +1,273 @@
+/*************** Tabxml H Declares Source Code File (.H) ***************/
+/* Name: TABXML.H Version 1.7 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2007-2016 */
+/* */
+/* This file contains the XML table classes declares. */
+/***********************************************************************/
+typedef class XMLDEF *PXMLDEF;
+typedef class TDBXML *PTDBXML;
+typedef class XMLCOL *PXMLCOL;
+
+DllExport PQRYRES XMLColumns(PGLOBAL, char *, char *, PTOS, bool);
+
+/* --------------------------- XML classes --------------------------- */
+
+/***********************************************************************/
+/* XML table. */
+/***********************************************************************/
+class DllExport XMLDEF : public TABDEF { /* Logical table description */
+ friend class TDBXML;
+ friend class TDBXCT;
+ friend PQRYRES XMLColumns(PGLOBAL, char*, char*, PTOS, bool);
+ public:
+ // Constructor
+ XMLDEF(void);
+
+ // Implementation
+ virtual const char *GetType(void) {return "XML";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+ protected:
+ // Members
+ PCSZ Fn; /* Path/Name of corresponding file */
+ char *Encoding; /* New XML table file encoding */
+ char *Tabname; /* Name of Table node */
+ char *Rowname; /* Name of first level nodes */
+ char *Colname; /* Name of second level nodes */
+ char *Mulnode; /* Name of multiple node */
+ char *XmlDB; /* Name of XML DB node */
+ char *Nslist; /* List of namespaces to register */
+ char *DefNs; /* Dummy name of default namespace */
+ char *Attrib; /* Table node attributes */
+ char *Hdattr; /* Header node attributes */
+ PCSZ Entry; /* Zip entry name or pattern */
+ int Coltype; /* Default column type */
+ int Limit; /* Limit of multiple values */
+ int Header; /* n first rows are header rows */
+ bool Xpand; /* Put multiple tags in several rows */
+ bool Usedom; /* True: DOM, False: libxml2 */
+ bool Zipped; /* True: Zipped XML file(s) */
+ bool Mulentries; /* True: multiple entries in zip file*/
+ bool Skip; /* Skip null columns */
+}; // end of XMLDEF
+
+#if defined(INCLUDE_TDBXML)
+#include "m_ctype.h"
+
+/***********************************************************************/
+/* This is the class declaration for the simple XML tables. */
+/***********************************************************************/
+class DllExport TDBXML : public TDBASE {
+ friend class XMLCOL;
+ friend class XMULCOL;
+ friend class XPOSCOL;
+ friend PQRYRES XMLColumns(PGLOBAL, char*, char*, PTOS, bool);
+ public:
+ // Constructor
+ TDBXML(PXMLDEF tdp);
+ TDBXML(PTDBXML tdbp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_XML;}
+ virtual PTDB Duplicate(PGLOBAL g) {return (PTDB)new(g) TDBXML(this);}
+
+ // Methods
+ virtual PTDB Clone(PTABS t);
+ virtual int GetRecpos(void);
+ virtual int GetProgCur(void) {return N;}
+ virtual PCSZ GetFile(PGLOBAL g) {return Xfile;}
+ virtual void SetFile(PGLOBAL g, PCSZ fn) {Xfile = fn;}
+ virtual void ResetDB(void) {N = 0;}
+ virtual void ResetSize(void) {MaxSize = -1;}
+ virtual int RowNumber(PGLOBAL g, bool b = false);
+ int LoadTableFile(PGLOBAL g, char *filename);
+ bool Initialize(PGLOBAL g);
+ bool SetTabNode(PGLOBAL g);
+ void SetNodeAttr(PGLOBAL g, char *attr, PXNODE node);
+ bool CheckRow(PGLOBAL g, bool b);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual PCOL InsertSpecialColumn(PCOL colp);
+//virtual int GetMaxSame(PGLOBAL g) {return (Xpand) ? Limit : 1;}
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+//virtual bool NeedIndexing(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+ virtual int CheckWrite(PGLOBAL g) {Checked = true; return 0;}
+ virtual const CHARSET_INFO *data_charset();
+
+ protected:
+ // Members
+ PXDOC Docp;
+ PXNODE Root;
+ PXNODE Curp;
+ PXNODE DBnode;
+ PXNODE TabNode;
+ PXNODE RowNode;
+ PXNODE ColNode;
+ PXLIST Nlist;
+ PXLIST Clist;
+ PFBLOCK To_Xb; // Pointer to XML file block
+ PCOL Colp; // The multiple column
+ bool Changed; // After Update, Insert or Delete
+ bool Checked; // After Update check pass
+ bool NextSame; // Same next row
+ bool Xpand; // Put multiple tags in several rows
+ bool NewRow; // True when inserting a new row
+ bool Hasnod; // True if rows have subnodes
+ bool Write; // True for Insert and Update
+ bool Usedom; // True for DOM, False for libxml2
+ bool Bufdone; // True when column buffers allocated
+ bool Nodedone; // True when column nodes allocated
+ bool Void; // True if the file does not exist
+ bool Zipped; // True if Zipped XML file(s)
+ bool Mulentries; // True if multiple entries in zip file
+ PCSZ Xfile; // The XML file
+ char *Enc; // New XML table file encoding
+ char *Tabname; // Name of Table node
+ char *Rowname; // Name of first level nodes
+ char *Colname; // Name of second level nodes
+ char *Mulnode; // Name of multiple node
+ char *XmlDB; // Name of XML DB node
+ char *Nslist; // List of namespaces to register
+ char *DefNs; // Dummy name of default namespace
+ char *Attrib; // Table node attribut(s)
+ char *Hdattr; // Header node attribut(s)
+ PCSZ Entry; // Zip entry name or pattern
+ int Coltype; // Default column type
+ int Limit; // Limit of multiple values
+ int Header; // n first rows are header rows
+ int Multiple; // If multiple files
+ int Nrow; // The table cardinality
+ int Irow; // The current row index
+ int Nsub; // The current subrow index
+ int N; // The current Rowid
+ }; // end of class TDBXML
+
+/***********************************************************************/
+/* Class XMLCOL: XDB table access method column descriptor. */
+/***********************************************************************/
+class XMLCOL : public COLBLK {
+ friend class TDBXML;
+ public:
+ // Constructors
+ XMLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "XML");
+ XMLCOL(XMLCOL *colp, PTDB tdbp); // Constructor used in copy process
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_XML;}
+ virtual void SetTo_Val(PVAL valp) {To_Val = valp;}
+ bool ParseXpath(PGLOBAL g, bool mode);
+
+ // Methods
+ virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ bool AllocBuf(PGLOBAL g, bool mode);
+ void AllocNodes(PGLOBAL g, PXDOC dp);
+
+ protected:
+//xmlNodePtr SelectSingleNode(xmlNodePtr node, char *name);
+
+ // Default constructor not to be used
+ XMLCOL(void) : COLBLK(1) {}
+
+ // Members
+ PXLIST Nl;
+ PXLIST Nlx;
+ PXNODE ColNode;
+ PXNODE ValNode;
+ PXNODE Cxnp;
+ PXNODE Vxnp;
+ PXATTR Vxap;
+ PXATTR AttNode;
+ PTDBXML Tdbp;
+ char *Valbuf; // To the node value buffer
+ char *Xname; // The node or attribute name
+ char* *Nodes; // The intermediate nodes
+ int Type; // 0: Attribute, 1: Tag, 2: position
+ int Nod; // The number of intermediate nodes
+ int Inod; // Index of multiple node
+ int Rank; // Position
+ bool Mul; // true for multiple column
+ bool Checked; // Was checked while Updating
+ int Long; // Buffer length
+ int Nx; // The last read row
+ int Sx; // The last read sub-row
+ int N; // The number of (multiple) values
+ PVAL To_Val; // To value used for Update/Insert
+ }; // end of class XMLCOL
+
+/***********************************************************************/
+/* Derived class XMLCOLX: used to replace a multiple XMLCOL by the */
+/* derived class XMULCOL that has specialize read and write functions.*/
+/* Note: this works only if the members of the derived class are the */
+/* same than the ones of the original class (NO added members). */
+/***********************************************************************/
+class XMLCOLX : public XMLCOL {
+ public:
+ // Fake operator new used to change a filter into a derived filter
+ void * operator new(size_t size, PXMLCOL colp) {return colp;}
+#if !defined(__BORLANDC__)
+ // Avoid warning C4291 by defining a matching dummy delete operator
+ void operator delete(void *, size_t size) {}
+ void operator delete(void *, PXMLCOL) {}
+#endif
+ }; // end of class XMLCOLX
+
+/***********************************************************************/
+/* Class XMULCOL: XML table access method multiple column descriptor. */
+/***********************************************************************/
+class XMULCOL : public XMLCOLX {
+ public:
+ // The constructor must restore Value because XOBJECT has a void
+ // constructor called by default that set Value to NULL
+ XMULCOL(PVAL valp) {Value = valp; Mul = true;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ }; // end of class XMULCOL
+
+/***********************************************************************/
+/* Class XPOSCOL: XML table column accessed by position. */
+/***********************************************************************/
+class XPOSCOL : public XMLCOLX {
+ public:
+ // The constructor must restore Value because XOBJECT has a void
+ // constructor called by default that set Value to NULL
+ XPOSCOL(PVAL valp) {Value = valp;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+ virtual void WriteColumn(PGLOBAL g);
+ }; // end of class XPOSCOL
+
+/***********************************************************************/
+/* This is the class declaration for the XML catalog table. */
+/***********************************************************************/
+class TDBXCT : public TDBCAT {
+ public:
+ // Constructor
+ TDBXCT(PXMLDEF tdp);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g);
+
+ // Members
+ PTOS Topt;
+ char *Db;
+ char *Tabn;
+ }; // end of class TDBXCT
+
+#endif // INCLUDE_TDBXML
diff --git a/storage/connect/tabzip.cpp b/storage/connect/tabzip.cpp
new file mode 100644
index 00000000..d9c13e2a
--- /dev/null
+++ b/storage/connect/tabzip.cpp
@@ -0,0 +1,251 @@
+/************* TabZip C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: TABZIP Version 1.0 */
+/* (C) Copyright to the author Olivier BERTRAND 2016 */
+/* This program are the TABZIP class DB execution routines. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the MariaDB header file. */
+/***********************************************************************/
+#include <my_global.h>
+
+/***********************************************************************/
+/* Include application header files: */
+/* global.h is header containing all global declarations. */
+/* plgdbsem.h is header containing the DB application declarations. */
+/* (x)table.h is header containing the TDBASE declarations. */
+/* tabzip.h is header containing the TABZIP classes declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "filamtxt.h"
+#include "filamzip.h"
+#include "resource.h" // for IDS_COLUMNS
+#include "tabdos.h"
+#include "tabmul.h"
+#include "tabzip.h"
+
+/* -------------------------- Class ZIPDEF --------------------------- */
+
+/************************************************************************/
+/* DefineAM: define specific AM block values. */
+/************************************************************************/
+bool ZIPDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
+{
+//target = GetStringCatInfo(g, "Target", NULL);
+ return DOSDEF::DefineAM(g, "ZIP", poff);
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB ZIPDEF::GetTable(PGLOBAL g, MODE m)
+{
+ PTDB tdbp = NULL;
+
+ tdbp = new(g) TDBZIP(this);
+
+ if (Multiple)
+ tdbp = new(g) TDBMUL(tdbp);
+
+ return tdbp;
+} // end of GetTable
+
+/* ------------------------------------------------------------------- */
+
+/***********************************************************************/
+/* Implementation of the TDBZIP class. */
+/***********************************************************************/
+TDBZIP::TDBZIP(PZIPDEF tdp) : TDBASE(tdp)
+{
+ zipfile = NULL;
+ zfn = tdp->Fn;
+//target = tdp->target;
+ nexterr = UNZ_OK;
+} // end of TDBZIP standard constructor
+
+/***********************************************************************/
+/* Allocate ZIP column description block. */
+/***********************************************************************/
+PCOL TDBZIP::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
+{
+ return new(g) ZIPCOL(cdp, this, cprec, n);
+} // end of MakeCol
+
+/***********************************************************************/
+/* open a zip file. */
+/* param: filename path and the filename of the zip file to open. */
+/* return: true if open, false otherwise. */
+/***********************************************************************/
+bool TDBZIP::open(PGLOBAL g, const char *fn)
+{
+ char filename[_MAX_PATH];
+
+ PlugSetPath(filename, fn, GetPath());
+
+ if (!zipfile && !(zipfile = unzOpen64(filename)))
+ sprintf(g->Message, "Zipfile open error");
+
+ return (zipfile == NULL);
+} // end of open
+
+/***********************************************************************/
+/* Close the zip file. */
+/***********************************************************************/
+void TDBZIP::close()
+{
+ if (zipfile) {
+ unzClose(zipfile);
+ zipfile = NULL;
+ } // endif zipfile
+
+} // end of close
+
+/***********************************************************************/
+/* ZIP Cardinality: returns table size in number of rows. */
+/***********************************************************************/
+int TDBZIP::Cardinality(PGLOBAL g)
+{
+ if (!g)
+ return 1;
+ else if (Cardinal < 0) {
+ if (!open(g, zfn)) {
+ unz_global_info64 ginfo;
+ int err = unzGetGlobalInfo64(zipfile, &ginfo);
+
+ Cardinal = (err == UNZ_OK) ? (int)ginfo.number_entry : 0;
+ } else
+ Cardinal = 10; // Dummy for multiple tables
+
+ } // endif Cardinal
+
+ return Cardinal;
+} // end of Cardinality
+
+/***********************************************************************/
+/* ZIP GetMaxSize: returns file size estimate in number of lines. */
+/***********************************************************************/
+int TDBZIP::GetMaxSize(PGLOBAL g)
+{
+ if (MaxSize < 0)
+ MaxSize = Cardinality(g);
+
+ return MaxSize;
+} // end of GetMaxSize
+
+/***********************************************************************/
+/* ZIP Access Method opening routine. */
+/***********************************************************************/
+bool TDBZIP::OpenDB(PGLOBAL g)
+{
+ if (Use == USE_OPEN)
+ // Table already open
+ return false;
+
+ Use = USE_OPEN; // To be clean
+ return open(g, zfn);
+} // end of OpenDB
+
+/***********************************************************************/
+/* ReadDB: Data Base read routine for ZIP access method. */
+/***********************************************************************/
+int TDBZIP::ReadDB(PGLOBAL g)
+{
+ if (nexterr == UNZ_END_OF_LIST_OF_FILE)
+ return RC_EF;
+ else if (nexterr != UNZ_OK) {
+ sprintf(g->Message, "unzGoToNextFile error %d", nexterr);
+ return RC_FX;
+ } // endif nexterr
+
+ int err = unzGetCurrentFileInfo64(zipfile, &finfo, fn,
+ sizeof(fn), NULL, 0, NULL, 0);
+
+ if (err != UNZ_OK) {
+ sprintf(g->Message, "unzGetCurrentFileInfo64 error %d", err);
+ return RC_FX;
+ } // endif err
+
+ nexterr = unzGoToNextFile(zipfile);
+ return RC_OK;
+} // end of ReadDB
+
+/***********************************************************************/
+/* WriteDB: Data Base write routine for ZIP access method. */
+/***********************************************************************/
+int TDBZIP::WriteDB(PGLOBAL g)
+{
+ strcpy(g->Message, "ZIP tables are read only");
+ return RC_FX;
+} // end of WriteDB
+
+/***********************************************************************/
+/* Data Base delete line routine for ZIP access method. */
+/***********************************************************************/
+int TDBZIP::DeleteDB(PGLOBAL g, int irc)
+{
+ strcpy(g->Message, "Delete not enabled for ZIP tables");
+ return RC_FX;
+} // end of DeleteDB
+
+/***********************************************************************/
+/* Data Base close routine for ZIP access method. */
+/***********************************************************************/
+void TDBZIP::CloseDB(PGLOBAL g)
+{
+ close();
+ nexterr = UNZ_OK; // For multiple tables
+ Use = USE_READY; // Just to be clean
+} // end of CloseDB
+
+/* ---------------------------- ZIPCOL ------------------------------- */
+
+/***********************************************************************/
+/* ZIPCOL public constructor. */
+/***********************************************************************/
+ZIPCOL::ZIPCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
+ : COLBLK(cdp, tdbp, i)
+{
+ if (cprec) {
+ Next = cprec->GetNext();
+ cprec->SetNext(this);
+ } else {
+ Next = tdbp->GetColumns();
+ tdbp->SetColumns(this);
+ } // endif cprec
+
+ Tdbz = (TDBZIP*)tdbp;
+ flag = cdp->GetOffset();
+} // end of ZIPCOL constructor
+
+/***********************************************************************/
+/* ReadColumn: */
+/***********************************************************************/
+void ZIPCOL::ReadColumn(PGLOBAL g)
+{
+ switch (flag) {
+ case 1:
+ Value->SetValue(Tdbz->finfo.compressed_size);
+ break;
+ case 2:
+ Value->SetValue(Tdbz->finfo.uncompressed_size);
+ break;
+ case 3:
+ Value->SetValue((int)Tdbz->finfo.compression_method);
+ break;
+ case 4:
+ Tdbz->finfo.tmu_date.tm_year -= 1900;
+
+ if (((DTVAL*)Value)->MakeTime((tm*)&Tdbz->finfo.tmu_date))
+ Value->SetNull(true);
+
+ Tdbz->finfo.tmu_date.tm_year += 1900;
+ break;
+ default:
+ Value->SetValue_psz((PSZ)Tdbz->fn);
+ } // endswitch flag
+
+} // end of ReadColumn
+
+/* -------------------------- End of tabzip -------------------------- */
diff --git a/storage/connect/tabzip.h b/storage/connect/tabzip.h
new file mode 100644
index 00000000..d36e4dc0
--- /dev/null
+++ b/storage/connect/tabzip.h
@@ -0,0 +1,102 @@
+/*************** tabzip H Declares Source Code File (.H) ***************/
+/* Name: tabzip.h Version 1.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2016 */
+/* */
+/* This file contains the ZIP classe declares. */
+/***********************************************************************/
+#include "osutil.h"
+#include "block.h"
+#include "colblk.h"
+#include "xtable.h"
+#include "unzip.h"
+
+typedef class ZIPDEF *PZIPDEF;
+typedef class TDBZIP *PTDBZIP;
+typedef class ZIPCOL *PZIPCOL;
+
+/***********************************************************************/
+/* ZIP table: display info about a ZIP file. */
+/***********************************************************************/
+class DllExport ZIPDEF : public DOSDEF { /* Table description */
+ friend class TDBZIP;
+ friend class UNZFAM;
+public:
+ // Constructor
+ ZIPDEF(void) {}
+
+ // Implementation
+ virtual const char *GetType(void) {return "ZIP";}
+
+ // Methods
+ virtual bool DefineAM(PGLOBAL g, LPCSTR am, int poff);
+ virtual PTDB GetTable(PGLOBAL g, MODE m);
+
+protected:
+ // Members
+ PCSZ target; // The inside file to query
+}; // end of ZIPDEF
+
+/***********************************************************************/
+/* This is the ZIP Access Method class declaration. */
+/***********************************************************************/
+class DllExport TDBZIP : public TDBASE {
+ friend class ZIPCOL;
+public:
+ // Constructor
+ TDBZIP(PZIPDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_ZIP;}
+ virtual PCSZ GetFile(PGLOBAL) {return zfn;}
+ virtual void SetFile(PGLOBAL, PCSZ fn) {zfn = fn;}
+
+ // Methods
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL g);
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual int GetRecpos(void) {return 0;}
+
+ // Database routines
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+
+protected:
+ bool open(PGLOBAL g, const char *filename);
+ void close(void);
+
+ // Members
+ unzFile zipfile; // The ZIP container file
+ PCSZ zfn; // The ZIP file name
+//PSZ target;
+ unz_file_info64 finfo; // The current file info
+ char fn[FILENAME_MAX]; // The current file name
+ int nexterr; // Next file error
+}; // end of class TDBZIP
+
+/***********************************************************************/
+/* Class ZIPCOL: ZIP access method column descriptor. */
+/***********************************************************************/
+class DllExport ZIPCOL : public COLBLK {
+ friend class TDBZIP;
+public:
+ // Constructors
+ ZIPCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am = "ZIP");
+
+ // Implementation
+ virtual int GetAmType(void) { return TYPE_AM_ZIP; }
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+protected:
+ // Default constructor not to be used
+ ZIPCOL(void) {}
+
+ // Members
+ TDBZIP *Tdbz;
+ int flag;
+}; // end of class ZIPCOL
diff --git a/storage/connect/unzip.c b/storage/connect/unzip.c
new file mode 100644
index 00000000..90935043
--- /dev/null
+++ b/storage/connect/unzip.c
@@ -0,0 +1,2125 @@
+/* unzip.c -- IO for uncompress .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+
+ ------------------------------------------------------------------------------------
+ Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
+ compatibility with older software. The following is from the original crypt.c.
+ Code woven in by Terry Thorsen 1/2003.
+
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+
+ crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h]
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+
+ ------------------------------------------------------------------------------------
+
+ Changes in unzip.c
+
+ 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos
+ 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz*
+ 2007-2008 - Even Rouault - Remove old C style function prototypes
+ 2007-2008 - Even Rouault - Add unzip support for ZIP64
+
+ Copyright (C) 2007-2008 Even Rouault
+
+
+ Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).
+ Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G
+ should only read the compressed/uncompressed size from the Zip64 format if
+ the size from normal header was 0xFFFFFFFF
+ Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant
+ Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required)
+ Patch created by Daniel Borca
+
+ Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
+
+ Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef NOUNCRYPT
+ #define NOUNCRYPT
+#endif
+
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+#ifndef CASESENSITIVITYDEFAULT_NO
+# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
+# define CASESENSITIVITYDEFAULT_NO
+# endif
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+const char unz_copyright[] =
+ " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info64_internal_s
+{
+ ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
+} unz_file_info64_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+ when reading and decompress it */
+typedef struct
+{
+ char *read_buffer; /* internal buffer for compressed data */
+ z_stream stream; /* zLib stream structure for inflate */
+
+#ifdef HAVE_BZIP2
+ bz_stream bstream; /* bzLib stream structure for bziped */
+#endif
+
+ ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
+ uLong stream_initialised; /* flag set if stream structure is initialised*/
+
+ ZPOS64_T offset_local_extrafield;/* offset of the local extra field */
+ uInt size_local_extrafield;/* size of the local extra field */
+ ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/
+ ZPOS64_T total_out_64;
+
+ uLong crc32; /* crc32 of all data uncompressed */
+ uLong crc32_wait; /* crc32 we must obtain after decompress all */
+ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */
+ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+ zlib_filefunc64_32_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ uLong compression_method; /* compression method (0==store) */
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ int raw;
+} file_in_zip64_read_info_s;
+
+
+/* unz64_s contain internal information about the zipfile
+*/
+typedef struct
+{
+ zlib_filefunc64_32_def z_filefunc;
+ int is64bitOpenFunction;
+ voidpf filestream; /* io structore of the zipfile */
+ unz_global_info64 gi; /* public global information */
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ ZPOS64_T num_file; /* number of the current file in the zipfile*/
+ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/
+ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/
+ ZPOS64_T central_pos; /* position of the beginning of the central dir*/
+
+ ZPOS64_T size_central_dir; /* size of the central directory */
+ ZPOS64_T offset_central_dir; /* offset of start of central directory with
+ respect to the starting disk number */
+
+ unz_file_info64 cur_file_info; /* public info about the current file in zip*/
+ unz_file_info64_internal cur_file_info_internal; /* private info about it*/
+ file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current
+ file if we are decompressing it */
+ int encrypted;
+
+ int isZip64;
+
+# ifndef NOUNCRYPT
+ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
+ const z_crc_t* pcrc_32_tab;
+# endif
+} unz64_s;
+
+
+#ifndef NOUNCRYPT
+#include "crypt.h"
+#endif
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+
+
+local int unz64local_getByte OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ int *pi));
+
+local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)
+{
+ unsigned char c;
+ int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return UNZ_OK;
+ }
+ else
+ {
+ if (ZERROR64(*pzlib_filefunc_def,filestream))
+ return UNZ_ERRNO;
+ else
+ return UNZ_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int unz64local_getShort OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int unz64local_getLong OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<16;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int unz64local_getLong64 OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ ZPOS64_T *pX));
+
+
+local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ ZPOS64_T *pX)
+{
+ ZPOS64_T x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (ZPOS64_T)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<8;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<16;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<24;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<32;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<40;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<48;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<56;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2)
+{
+ for (;;)
+ {
+ char c1=*(fileName1++);
+ char c2=*(fileName2++);
+ if ((c1>='a') && (c1<='z'))
+ c1 -= 0x20;
+ if ((c2>='a') && (c2<='z'))
+ c2 -= 0x20;
+ if (c1=='\0')
+ return ((c2=='\0') ? 0 : -1);
+ if (c2=='\0')
+ return 1;
+ if (c1<c2)
+ return -1;
+ if (c1>c2)
+ return 1;
+ }
+}
+
+
+#ifdef CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity)
+
+{
+ if (iCaseSensitivity==0)
+ iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+ if (iCaseSensitivity==1)
+ return strcmp(fileName1,fileName2);
+
+ return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+
+
+/*
+ Locate the Central directory 64 of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T unz64local_SearchCentralDir64 OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream));
+
+local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+ uLong uL;
+ ZPOS64_T relativeOffset;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ if (uPosFound == 0)
+ return 0;
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+
+ /* number of the disk with the start of the zip64 end of central directory */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+ if (uL != 0)
+ return 0;
+
+ /* relative offset of the zip64 end of central directory record */
+ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
+ return 0;
+
+ /* total number of disks */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+ if (uL != 1)
+ return 0;
+
+ /* Goto end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+
+ if (uL != 0x06064b50)
+ return 0;
+
+ return relativeOffset;
+}
+
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
+ "zlib/zlib114.zip".
+ If the zipfile cannot be opened (file doesn't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+*/
+local unzFile unzOpenInternal (const void *path,
+ zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
+ int is64bitOpenFunction)
+{
+ unz64_s us;
+ unz64_s *s;
+ ZPOS64_T central_pos;
+ uLong uL;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ ZPOS64_T number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+
+ int err=UNZ_OK;
+
+ if (unz_copyright[0]!=' ')
+ return NULL;
+
+ us.z_filefunc.zseek32_file = NULL;
+ us.z_filefunc.ztell32_file = NULL;
+ if (pzlib_filefunc64_32_def==NULL)
+ fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
+ else
+ us.z_filefunc = *pzlib_filefunc64_32_def;
+ us.is64bitOpenFunction = is64bitOpenFunction;
+
+
+
+ us.filestream = ZOPEN64(us.z_filefunc,
+ path,
+ ZLIB_FILEFUNC_MODE_READ |
+ ZLIB_FILEFUNC_MODE_EXISTING);
+ if (us.filestream==NULL)
+ return NULL;
+
+ central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
+ if (central_pos)
+ {
+ uLong uS;
+ ZPOS64_T uL64;
+
+ us.isZip64 = 1;
+
+ if (ZSEEK64(us.z_filefunc, us.filestream,
+ central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* size of zip64 end of central directory record */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* version made by */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* version needed to extract */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of this disk */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central directory on this disk */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central directory */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if ((number_entry_CD!=us.gi.number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=UNZ_BADZIPFILE;
+
+ /* size of the central directory */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ us.gi.size_comment = 0;
+ }
+ else
+ {
+ central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
+ if (central_pos==0)
+ err=UNZ_ERRNO;
+
+ us.isZip64 = 0;
+
+ if (ZSEEK64(us.z_filefunc, us.filestream,
+ central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of this disk */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.gi.number_entry = uL;
+
+ /* total number of entries in the central dir */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ number_entry_CD = uL;
+
+ if ((number_entry_CD!=us.gi.number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=UNZ_BADZIPFILE;
+
+ /* size of the central directory */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.size_central_dir = uL;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.offset_central_dir = uL;
+
+ /* zipfile comment length */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
+ (err==UNZ_OK))
+ err=UNZ_BADZIPFILE;
+
+ if (err!=UNZ_OK)
+ {
+ ZCLOSE64(us.z_filefunc, us.filestream);
+ return NULL;
+ }
+
+ us.byte_before_the_zipfile = central_pos -
+ (us.offset_central_dir+us.size_central_dir);
+ us.central_pos = central_pos;
+ us.pfile_in_zip_read = NULL;
+ us.encrypted = 0;
+
+
+ s=(unz64_s*)ALLOC(sizeof(unz64_s));
+ if( s != NULL)
+ {
+ *s=us;
+ unzGoToFirstFile((unzFile)s);
+ }
+ return (unzFile)s;
+}
+
+
+extern unzFile ZEXPORT unzOpen2 (const char *path,
+ zlib_filefunc_def* pzlib_filefunc32_def)
+{
+ if (pzlib_filefunc32_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+ return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0);
+ }
+ else
+ return unzOpenInternal(path, NULL, 0);
+}
+
+extern unzFile ZEXPORT unzOpen2_64 (const void *path,
+ zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ if (pzlib_filefunc_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+ zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+ return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1);
+ }
+ else
+ return unzOpenInternal(path, NULL, 1);
+}
+
+extern unzFile ZEXPORT unzOpen (const char *path)
+{
+ return unzOpenInternal(path, NULL, 0);
+}
+
+extern unzFile ZEXPORT unzOpen64 (const void *path)
+{
+ return unzOpenInternal(path, NULL, 1);
+}
+
+/*
+ Close a ZipFile opened with unzOpen.
+ If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+ these files MUST be closed with unzCloseCurrentFile before call unzClose.
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose (unzFile file)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ if (s->pfile_in_zip_read!=NULL)
+ unzCloseCurrentFile(file);
+
+ ZCLOSE64(s->z_filefunc, s->filestream);
+ TRYFREE(s);
+ return UNZ_OK;
+}
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ *pglobal_info=s->gi;
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ /* to do : check if number_entry is not truncated */
+ pglobal_info32->number_entry = (uLong)s->gi.number_entry;
+ pglobal_info32->size_comment = s->gi.size_comment;
+ return UNZ_OK;
+}
+/*
+ Translate date/time from Dos format to tm_unz (readable more easilty)
+*/
+local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm)
+{
+ ZPOS64_T uDate;
+ uDate = (ZPOS64_T)(ulDosDate>>16);
+ ptm->tm_mday = (uInt)(uDate&0x1f) ;
+ ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
+ ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+ ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
+ ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
+ ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+ Get Info about the current file in the zipfile, with internal only info
+*/
+local int unz64local_GetCurrentFileInfoInternal OF((unzFile file,
+ unz_file_info64 *pfile_info,
+ unz_file_info64_internal
+ *pfile_info_internal,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+
+local int unz64local_GetCurrentFileInfoInternal (unzFile file,
+ unz_file_info64 *pfile_info,
+ unz_file_info64_internal
+ *pfile_info_internal,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize)
+{
+ unz64_s* s;
+ unz_file_info64 file_info;
+ unz_file_info64_internal file_info_internal;
+ int err=UNZ_OK;
+ uLong uMagic;
+ long lSeek=0;
+ uLong uL;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (ZSEEK64(s->z_filefunc, s->filestream,
+ s->pos_in_central_dir+s->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+
+ /* we check the magic */
+ if (err==UNZ_OK)
+ {
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x02014b50)
+ err=UNZ_BADZIPFILE;
+ }
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info.compressed_size = uL;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info.uncompressed_size = uL;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ // relative offset of local header
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info_internal.offset_curfile = uL;
+
+ lSeek+=file_info.size_filename;
+ if ((err==UNZ_OK) && (szFileName!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_filename<fileNameBufferSize)
+ {
+ *(szFileName+file_info.size_filename)='\0';
+ uSizeRead = file_info.size_filename;
+ }
+ else
+ uSizeRead = fileNameBufferSize;
+
+ if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek -= uSizeRead;
+ }
+
+ // Read extrafield
+ if ((err==UNZ_OK) && (extraField!=NULL))
+ {
+ ZPOS64_T uSizeRead ;
+ if (file_info.size_file_extra<extraFieldBufferSize)
+ uSizeRead = file_info.size_file_extra;
+ else
+ uSizeRead = extraFieldBufferSize;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+
+ lSeek += file_info.size_file_extra - (uLong)uSizeRead;
+ }
+ else
+ lSeek += file_info.size_file_extra;
+
+
+ if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
+ {
+ uLong acc = 0;
+
+ // since lSeek now points to after the extra field we need to move back
+ lSeek -= file_info.size_file_extra;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ while(acc < file_info.size_file_extra)
+ {
+ uLong headerId;
+ uLong dataSize;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* ZIP64 extra fields */
+ if (headerId == 0x0001)
+ {
+ uLong uL;
+
+ if(file_info.uncompressed_size == MAXU32)
+ {
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info.compressed_size == MAXU32)
+ {
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info_internal.offset_curfile == MAXU32)
+ {
+ /* Relative Header offset */
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info.disk_num_start == MAXU32)
+ {
+ /* Disk Start Number */
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ }
+ else
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
+ err=UNZ_ERRNO;
+ }
+
+ acc += 2 + 2 + dataSize;
+ }
+ }
+
+ if ((err==UNZ_OK) && (szComment!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_file_comment<commentBufferSize)
+ {
+ *(szComment+file_info.size_file_comment)='\0';
+ uSizeRead = file_info.size_file_comment;
+ }
+ else
+ uSizeRead = commentBufferSize;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek+=file_info.size_file_comment - uSizeRead;
+ }
+ else
+ lSeek+=file_info.size_file_comment;
+
+
+ if ((err==UNZ_OK) && (pfile_info!=NULL))
+ *pfile_info=file_info;
+
+ if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+ *pfile_info_internal=file_info_internal;
+
+ return err;
+}
+
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file,
+ unz_file_info64 * pfile_info,
+ char * szFileName, uLong fileNameBufferSize,
+ void *extraField, uLong extraFieldBufferSize,
+ char* szComment, uLong commentBufferSize)
+{
+ return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+ szFileName,fileNameBufferSize,
+ extraField,extraFieldBufferSize,
+ szComment,commentBufferSize);
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
+ unz_file_info * pfile_info,
+ char * szFileName, uLong fileNameBufferSize,
+ void *extraField, uLong extraFieldBufferSize,
+ char* szComment, uLong commentBufferSize)
+{
+ int err;
+ unz_file_info64 file_info64;
+ err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL,
+ szFileName,fileNameBufferSize,
+ extraField,extraFieldBufferSize,
+ szComment,commentBufferSize);
+ if ((err==UNZ_OK) && (pfile_info != NULL))
+ {
+ pfile_info->version = file_info64.version;
+ pfile_info->version_needed = file_info64.version_needed;
+ pfile_info->flag = file_info64.flag;
+ pfile_info->compression_method = file_info64.compression_method;
+ pfile_info->dosDate = file_info64.dosDate;
+ pfile_info->crc = file_info64.crc;
+
+ pfile_info->size_filename = file_info64.size_filename;
+ pfile_info->size_file_extra = file_info64.size_file_extra;
+ pfile_info->size_file_comment = file_info64.size_file_comment;
+
+ pfile_info->disk_num_start = file_info64.disk_num_start;
+ pfile_info->internal_fa = file_info64.internal_fa;
+ pfile_info->external_fa = file_info64.external_fa;
+
+ pfile_info->tmu_date = file_info64.tmu_date,
+
+
+ pfile_info->compressed_size = (uLong)file_info64.compressed_size;
+ pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
+
+ }
+ return err;
+}
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile (unzFile file)
+{
+ int err=UNZ_OK;
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ s->pos_in_central_dir=s->offset_central_dir;
+ s->num_file=0;
+ err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile (unzFile file)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */
+ if (s->num_file+1==s->gi.number_entry)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+ s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+ s->num_file++;
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity)
+{
+ unz64_s* s;
+ int err;
+
+ /* We remember the 'current' position in the file so that we can jump
+ * back there if we fail.
+ */
+ unz_file_info64 cur_file_infoSaved;
+ unz_file_info64_internal cur_file_info_internalSaved;
+ ZPOS64_T num_fileSaved;
+ ZPOS64_T pos_in_central_dirSaved;
+
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+
+ if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+ return UNZ_PARAMERROR;
+
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ /* Save the current state */
+ num_fileSaved = s->num_file;
+ pos_in_central_dirSaved = s->pos_in_central_dir;
+ cur_file_infoSaved = s->cur_file_info;
+ cur_file_info_internalSaved = s->cur_file_info_internal;
+
+ err = unzGoToFirstFile(file);
+
+ while (err == UNZ_OK)
+ {
+ char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+ err = unzGetCurrentFileInfo64(file,NULL,
+ szCurrentFileName,sizeof(szCurrentFileName)-1,
+ NULL,0,NULL,0);
+ if (err == UNZ_OK)
+ {
+ if (unzStringFileNameCompare(szCurrentFileName,
+ szFileName,iCaseSensitivity)==0)
+ return UNZ_OK;
+ err = unzGoToNextFile(file);
+ }
+ }
+
+ /* We failed, so restore the state of the 'current file' to where we
+ * were.
+ */
+ s->num_file = num_fileSaved ;
+ s->pos_in_central_dir = pos_in_central_dirSaved ;
+ s->cur_file_info = cur_file_infoSaved;
+ s->cur_file_info_internal = cur_file_info_internalSaved;
+ return err;
+}
+
+
+/*
+///////////////////////////////////////////
+// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
+// I need random access
+//
+// Further optimization could be realized by adding an ability
+// to cache the directory in memory. The goal being a single
+// comprehensive file read to put the file I need in a memory.
+*/
+
+/*
+typedef struct unz_file_pos_s
+{
+ ZPOS64_T pos_in_zip_directory; // offset in file
+ ZPOS64_T num_of_file; // # of file
+} unz_file_pos;
+*/
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos)
+{
+ unz64_s* s;
+
+ if (file==NULL || file_pos==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ file_pos->pos_in_zip_directory = s->pos_in_central_dir;
+ file_pos->num_of_file = s->num_file;
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetFilePos(
+ unzFile file,
+ unz_file_pos* file_pos)
+{
+ unz64_file_pos file_pos64;
+ int err = unzGetFilePos64(file,&file_pos64);
+ if (err==UNZ_OK)
+ {
+ file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;
+ file_pos->num_of_file = (uLong)file_pos64.num_of_file;
+ }
+ return err;
+}
+
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL || file_pos==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ /* jump to the right spot */
+ s->pos_in_central_dir = file_pos->pos_in_zip_directory;
+ s->num_file = file_pos->num_of_file;
+
+ /* set the current file */
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ /* return results */
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+extern int ZEXPORT unzGoToFilePos(
+ unzFile file,
+ unz_file_pos* file_pos)
+{
+ unz64_file_pos file_pos64;
+ if (file_pos == NULL)
+ return UNZ_PARAMERROR;
+
+ file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
+ file_pos64.num_of_file = file_pos->num_of_file;
+ return unzGoToFilePos64(file,&file_pos64);
+}
+
+/*
+// Unzip Helper Functions - should be here?
+///////////////////////////////////////////
+*/
+
+/*
+ Read the local header of the current zipfile
+ Check the coherency of the local header and info in the end of central
+ directory about this file
+ store in *piSizeVar the size of extra info in local header
+ (filename and size of extra field data)
+*/
+local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar,
+ ZPOS64_T * poffset_local_extrafield,
+ uInt * psize_local_extrafield)
+{
+ uLong uMagic,uData,uFlags;
+ uLong size_filename;
+ uLong size_extra_field;
+ int err=UNZ_OK;
+
+ *piSizeVar = 0;
+ *poffset_local_extrafield = 0;
+ *psize_local_extrafield = 0;
+
+ if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
+ s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+
+ if (err==UNZ_OK)
+ {
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x04034b50)
+ err=UNZ_BADZIPFILE;
+ }
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+/*
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+ err=UNZ_BADZIPFILE;
+*/
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+ err=UNZ_BADZIPFILE;
+
+ if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+/* #ifdef HAVE_BZIP2 */
+ (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
+/* #endif */
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
+ err=UNZ_ERRNO;
+ else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
+ err=UNZ_ERRNO;
+ else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+ err=UNZ_BADZIPFILE;
+
+ *piSizeVar += (uInt)size_filename;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
+ err=UNZ_ERRNO;
+ *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+ SIZEZIPLOCALHEADER + size_filename;
+ *psize_local_extrafield = (uInt)size_extra_field;
+
+ *piSizeVar += (uInt)size_extra_field;
+
+ return err;
+}
+
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method,
+ int* level, int raw, const char* password)
+{
+ int err=UNZ_OK;
+ uInt iSizeVar;
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ ZPOS64_T offset_local_extrafield; /* offset of the local extra field */
+ uInt size_local_extrafield; /* size of the local extra field */
+# ifndef NOUNCRYPT
+ char source[12];
+# else
+ if (password != NULL)
+ return UNZ_PARAMERROR;
+# endif
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_PARAMERROR;
+
+ if (s->pfile_in_zip_read != NULL)
+ unzCloseCurrentFile(file);
+
+ if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+ return UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_INTERNALERROR;
+
+ pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+ pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+ pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+ pfile_in_zip_read_info->pos_local_extrafield=0;
+ pfile_in_zip_read_info->raw=raw;
+
+ if (pfile_in_zip_read_info->read_buffer==NULL)
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return UNZ_INTERNALERROR;
+ }
+
+ pfile_in_zip_read_info->stream_initialised=0;
+
+ if (method!=NULL)
+ *method = (int)s->cur_file_info.compression_method;
+
+ if (level!=NULL)
+ {
+ *level = 6;
+ switch (s->cur_file_info.flag & 0x06)
+ {
+ case 6 : *level = 1; break;
+ case 4 : *level = 2; break;
+ case 2 : *level = 9; break;
+ }
+ }
+
+ if ((s->cur_file_info.compression_method!=0) &&
+/* #ifdef HAVE_BZIP2 */
+ (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
+/* #endif */
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+
+ err=UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+ pfile_in_zip_read_info->crc32=0;
+ pfile_in_zip_read_info->total_out_64=0;
+ pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
+ pfile_in_zip_read_info->filestream=s->filestream;
+ pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
+ pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+ pfile_in_zip_read_info->stream.total_out = 0;
+
+ if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw))
+ {
+#ifdef HAVE_BZIP2
+ pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
+ pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
+ pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->bstream.state = (voidpf)0;
+
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->stream.next_in = (voidpf)0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+#else
+ pfile_in_zip_read_info->raw=1;
+#endif
+ }
+ else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
+ {
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->stream.next_in = 0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END.
+ * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+ * size of both compressed and uncompressed data
+ */
+ }
+ pfile_in_zip_read_info->rest_read_compressed =
+ s->cur_file_info.compressed_size ;
+ pfile_in_zip_read_info->rest_read_uncompressed =
+ s->cur_file_info.uncompressed_size ;
+
+
+ pfile_in_zip_read_info->pos_in_zipfile =
+ s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+ iSizeVar;
+
+ pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+ s->pfile_in_zip_read = pfile_in_zip_read_info;
+ s->encrypted = 0;
+
+# ifndef NOUNCRYPT
+ if (password != NULL)
+ {
+ int i;
+ s->pcrc_32_tab = get_crc_table();
+ init_keys(password,s->keys,s->pcrc_32_tab);
+ if (ZSEEK64(s->z_filefunc, s->filestream,
+ s->pfile_in_zip_read->pos_in_zipfile +
+ s->pfile_in_zip_read->byte_before_the_zipfile,
+ SEEK_SET)!=0)
+ return UNZ_INTERNALERROR;
+ if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12)
+ return UNZ_INTERNALERROR;
+
+ for (i = 0; i<12; i++)
+ zdecode(s->keys,s->pcrc_32_tab,source[i]);
+
+ s->pfile_in_zip_read->pos_in_zipfile+=12;
+ s->encrypted=1;
+ }
+# endif
+
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzOpenCurrentFile (unzFile file)
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password)
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw)
+{
+ return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ s=(unz64_s*)file;
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+ if (pfile_in_zip_read_info==NULL)
+ return 0; //UNZ_PARAMERROR;
+ return pfile_in_zip_read_info->pos_in_zipfile +
+ pfile_in_zip_read_info->byte_before_the_zipfile;
+}
+
+/** Addition for GDAL : END */
+
+/*
+ Read bytes from the current file.
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
+{
+ int err=UNZ_OK;
+ uInt iRead = 0;
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if (pfile_in_zip_read_info->read_buffer == NULL)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (len==0)
+ return 0;
+
+ pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+ pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+
+ if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
+ (!(pfile_in_zip_read_info->raw)))
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+ if ((len>pfile_in_zip_read_info->rest_read_compressed+
+ pfile_in_zip_read_info->stream.avail_in) &&
+ (pfile_in_zip_read_info->raw))
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_compressed+
+ pfile_in_zip_read_info->stream.avail_in;
+
+ while (pfile_in_zip_read_info->stream.avail_out>0)
+ {
+ if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+ (pfile_in_zip_read_info->rest_read_compressed>0))
+ {
+ uInt uReadThis = UNZ_BUFSIZE;
+ if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+ uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+ if (uReadThis == 0)
+ return UNZ_EOF;
+ if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->pos_in_zipfile +
+ pfile_in_zip_read_info->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+ if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->read_buffer,
+ uReadThis)!=uReadThis)
+ return UNZ_ERRNO;
+
+
+# ifndef NOUNCRYPT
+ if(s->encrypted)
+ {
+ uInt i;
+ for(i=0;i<uReadThis;i++)
+ pfile_in_zip_read_info->read_buffer[i] =
+ zdecode(s->keys,s->pcrc_32_tab,
+ pfile_in_zip_read_info->read_buffer[i]);
+ }
+# endif
+
+
+ pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+ pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+
+ pfile_in_zip_read_info->stream.next_in =
+ (Bytef*)pfile_in_zip_read_info->read_buffer;
+ pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+ }
+
+ if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
+ {
+ uInt uDoCopy,i ;
+
+ if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ return (iRead==0) ? UNZ_EOF : iRead;
+
+ if (pfile_in_zip_read_info->stream.avail_out <
+ pfile_in_zip_read_info->stream.avail_in)
+ uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+ else
+ uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+
+ for (i=0;i<uDoCopy;i++)
+ *(pfile_in_zip_read_info->stream.next_out+i) =
+ *(pfile_in_zip_read_info->stream.next_in+i);
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy;
+
+ pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+ pfile_in_zip_read_info->stream.next_out,
+ uDoCopy);
+ pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+ pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+ pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+ pfile_in_zip_read_info->stream.next_out += uDoCopy;
+ pfile_in_zip_read_info->stream.next_in += uDoCopy;
+ pfile_in_zip_read_info->stream.total_out += uDoCopy;
+ iRead += uDoCopy;
+ }
+ else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED)
+ {
+#ifdef HAVE_BZIP2
+ uLong uTotalOutBefore,uTotalOutAfter;
+ const Bytef *bufBefore;
+ uLong uOutThis;
+
+ pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in;
+ pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in;
+ pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in;
+ pfile_in_zip_read_info->bstream.total_in_hi32 = 0;
+ pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out;
+ pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out;
+ pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out;
+ pfile_in_zip_read_info->bstream.total_out_hi32 = 0;
+
+ uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32;
+ bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out;
+
+ err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream);
+
+ uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32;
+ uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
+
+ pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis));
+ pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
+ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+ pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in;
+ pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in;
+ pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32;
+ pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out;
+ pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out;
+ pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32;
+
+ if (err==BZ_STREAM_END)
+ return (iRead==0) ? UNZ_EOF : iRead;
+ if (err!=BZ_OK)
+ break;
+#endif
+ } // end Z_BZIP2ED
+ else
+ {
+ ZPOS64_T uTotalOutBefore,uTotalOutAfter;
+ const Bytef *bufBefore;
+ ZPOS64_T uOutThis;
+ int flush=Z_SYNC_FLUSH;
+
+ uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+ bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+ /*
+ if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+ pfile_in_zip_read_info->stream.avail_out) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ flush = Z_FINISH;
+ */
+ err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+ if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
+ err = Z_DATA_ERROR;
+
+ uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+ uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
+
+ pfile_in_zip_read_info->crc32 =
+ crc32(pfile_in_zip_read_info->crc32,bufBefore,
+ (uInt)(uOutThis));
+
+ pfile_in_zip_read_info->rest_read_uncompressed -=
+ uOutThis;
+
+ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+ if (err==Z_STREAM_END)
+ return (iRead==0) ? UNZ_EOF : iRead;
+ if (err!=Z_OK)
+ break;
+ }
+ }
+
+ if (err==Z_OK)
+ return iRead;
+ return err;
+}
+
+
+/*
+ Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell (unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+extern ZPOS64_T ZEXPORT unztell64 (unzFile file)
+{
+
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return (ZPOS64_T)-1;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return (ZPOS64_T)-1;
+
+ return pfile_in_zip_read_info->total_out_64;
+}
+
+
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+extern int ZEXPORT unzeof (unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/*
+Read extra field from the current file (opened by unzOpenCurrentFile)
+This is the local-header version of the extra field (sometimes, there is
+more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field that can be read
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ uInt read_now;
+ ZPOS64_T size_to_read;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
+ pfile_in_zip_read_info->pos_local_extrafield);
+
+ if (buf==NULL)
+ return (int)size_to_read;
+
+ if (len>size_to_read)
+ read_now = (uInt)size_to_read;
+ else
+ read_now = (uInt)len ;
+
+ if (read_now==0)
+ return 0;
+
+ if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->offset_local_extrafield +
+ pfile_in_zip_read_info->pos_local_extrafield,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ buf,read_now)!=read_now)
+ return UNZ_ERRNO;
+
+ return (int)read_now;
+}
+
+/*
+ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile (unzFile file)
+{
+ int err=UNZ_OK;
+
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+ (!pfile_in_zip_read_info->raw))
+ {
+ if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+ err=UNZ_CRCERROR;
+ }
+
+
+ TRYFREE(pfile_in_zip_read_info->read_buffer);
+ pfile_in_zip_read_info->read_buffer = NULL;
+ if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+ inflateEnd(&pfile_in_zip_read_info->stream);
+#ifdef HAVE_BZIP2
+ else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
+ BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+#endif
+
+
+ pfile_in_zip_read_info->stream_initialised = 0;
+ TRYFREE(pfile_in_zip_read_info);
+
+ s->pfile_in_zip_read=NULL;
+
+ return err;
+}
+
+
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf)
+{
+ unz64_s* s;
+ uLong uReadThis ;
+ if (file==NULL)
+ return (int)UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ uReadThis = uSizeBuf;
+ if (uReadThis>s->gi.size_comment)
+ uReadThis = s->gi.size_comment;
+
+ if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (uReadThis>0)
+ {
+ *szComment='\0';
+ if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
+ return UNZ_ERRNO;
+ }
+
+ if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+ *(szComment+s->gi.size_comment)='\0';
+ return (int)uReadThis;
+}
+
+/* Additions by RX '2004 */
+extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file)
+{
+ unz64_s* s;
+
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return 0;
+ if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
+ if (s->num_file==s->gi.number_entry)
+ return 0;
+ return s->pos_in_central_dir;
+}
+
+extern uLong ZEXPORT unzGetOffset (unzFile file)
+{
+ ZPOS64_T offset64;
+
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ offset64 = unzGetOffset64(file);
+ return (uLong)offset64;
+}
+
+extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ s->pos_in_central_dir = pos;
+ s->num_file = s->gi.number_entry; /* hack */
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos)
+{
+ return unzSetOffset64(file,pos);
+}
diff --git a/storage/connect/unzip.h b/storage/connect/unzip.h
new file mode 100644
index 00000000..2104e391
--- /dev/null
+++ b/storage/connect/unzip.h
@@ -0,0 +1,437 @@
+/* unzip.h -- IO for uncompress .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ ---------------------------------------------------------------------------------
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ ---------------------------------------------------------------------------------
+
+ Changes
+
+ See header of unzip64.c
+
+*/
+
+#ifndef _unz64_H
+#define _unz64_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO (Z_ERRNO)
+#define UNZ_EOF (0)
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir */
+typedef struct unz_global_info64_s
+{
+ ZPOS64_T number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s
+{
+ uLong number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info;
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info64_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ ZPOS64_T compressed_size; /* compressed size 8 bytes */
+ ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info64;
+
+typedef struct unz_file_info_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ uLong compressed_size; /* compressed size 4 bytes */
+ uLong uncompressed_size; /* uncompressed size 4 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity));
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+extern unzFile ZEXPORT unzOpen64 OF((const void *path));
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
+ "zlib/zlib113.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+ the "64" function take a const void* pointer, because the path is just the
+ value passed to the open64_file_func callback.
+ Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
+ is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
+ does not describe the reality
+*/
+
+
+extern unzFile ZEXPORT unzOpen2 OF((const char *path,
+ zlib_filefunc_def* pzlib_filefunc_def));
+/*
+ Open a Zip file, like unzOpen, but provide a set of file low level API
+ for read/write the zip file (see ioapi.h)
+*/
+
+extern unzFile ZEXPORT unzOpen2_64 OF((const void *path,
+ zlib_filefunc64_def* pzlib_filefunc_def));
+/*
+ Open a Zip file, like unz64Open, but provide a set of file low level API
+ for read/write the zip file (see ioapi.h)
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+ Close a ZipFile opened with unzOpen.
+ If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+ these files MUST be closed with unzCloseCurrentFile before call unzClose.
+ return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+ unz_global_info *pglobal_info));
+
+extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,
+ unz_global_info64 *pglobal_info));
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+ char *szComment,
+ uLong uSizeBuf));
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file,
+ const char *szFileName,
+ int iCaseSensitivity));
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+/* ****************************************** */
+/* Ryan supplied functions */
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_pos_s
+{
+ uLong pos_in_zip_directory; /* offset in zip file directory */
+ uLong num_of_file; /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos(
+ unzFile file,
+ unz_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos(
+ unzFile file,
+ unz_file_pos* file_pos);
+
+typedef struct unz64_file_pos_s
+{
+ ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */
+ ZPOS64_T num_of_file; /* # of file */
+} unz64_file_pos;
+
+extern int ZEXPORT unzGetFilePos64(
+ unzFile file,
+ unz64_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos64(
+ unzFile file,
+ const unz64_file_pos* file_pos);
+
+/* ****************************************** */
+
+extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,
+ unz_file_info64 *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+ unz_file_info *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+/*
+ Get Info about the current file
+ if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+ the current file
+ if szFileName!=NULL, the filemane string will be copied in szFileName
+ (fileNameBufferSize is the size of the buffer)
+ if extraField!=NULL, the extra field information will be copied in extraField
+ (extraFieldBufferSize is the size of the buffer).
+ This is the Central-header version of the extra field
+ if szComment!=NULL, the comment string of the file will be copied in szComment
+ (commentBufferSize is the size of the buffer)
+*/
+
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
+
+/** Addition for GDAL : END */
+
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+ from it, and close it (you can close it before reading all the file)
+ */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
+ const char* password));
+/*
+ Open for reading data the current file in the zipfile.
+ password is a crypting password
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
+ int* method,
+ int* level,
+ int raw));
+/*
+ Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1
+ *method will receive method of compression, *level will receive level of
+ compression
+ note : you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL
+*/
+
+extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
+ int* method,
+ int* level,
+ int raw,
+ const char* password));
+/*
+ Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1
+ *method will receive method of compression, *level will receive level of
+ compression
+ note : you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL
+*/
+
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+
+extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
+/*
+ Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+
+/***************************************************************************/
+
+/* Get the current file offset */
+extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
+extern uLong ZEXPORT unzGetOffset (unzFile file);
+
+/* Set the current file offset */
+extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz64_H */
diff --git a/storage/connect/user_connect.cc b/storage/connect/user_connect.cc
new file mode 100644
index 00000000..ba446a3e
--- /dev/null
+++ b/storage/connect/user_connect.cc
@@ -0,0 +1,192 @@
+/* Copyright (C) MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file user_connect.cc
+
+ @brief
+ Implements the user_connect class.
+
+ @details
+ To support multi_threading, each query creates and use a PlugDB "user"
+ that is a connection with its personnal memory allocation.
+
+ @note
+ Author Olivier Bertrand
+*/
+
+/****************************************************************************/
+/* Author: Olivier Bertrand -- bertrandop@gmail.com -- 2004-2020 */
+/****************************************************************************/
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#define DONT_DEFINE_VOID
+#define MYSQL_SERVER
+#include <my_global.h>
+#include "sql_class.h"
+#undef OFFSET
+
+#define NOPARSE
+#include "osutil.h"
+#include "global.h"
+#include "plgdbsem.h"
+#include "connect.h"
+#include "user_connect.h"
+#include "mycat.h"
+
+extern pthread_mutex_t usrmut;
+
+/****************************************************************************/
+/* Initialize the user_connect static member. */
+/****************************************************************************/
+PCONNECT user_connect::to_users= NULL;
+
+/****************************************************************************/
+/* Get the work_size SESSION variable value . */
+/****************************************************************************/
+size_t GetWorkSize(void);
+void SetWorkSize(size_t);
+
+/* -------------------------- class user_connect -------------------------- */
+
+/****************************************************************************/
+/* Constructor. */
+/****************************************************************************/
+user_connect::user_connect(THD *thd)
+{
+ thdp= thd;
+ next= NULL;
+ previous= NULL;
+ g= NULL;
+ last_query_id= 0;
+ count= 0;
+
+ // Statistics
+ nrd= fnd= nfd= 0;
+ tb1= 0;
+} // end of user_connect constructor
+
+
+/****************************************************************************/
+/* Destructor. */
+/****************************************************************************/
+user_connect::~user_connect()
+{
+ // Terminate CONNECT and Plug-like environment, should return NULL
+ g= CntExit(g);
+} // end of user_connect destructor
+
+
+/****************************************************************************/
+/* Initialization. */
+/****************************************************************************/
+bool user_connect::user_init()
+{
+ // Initialize Plug-like environment
+ size_t worksize= GetWorkSize();
+ PACTIVITY ap= NULL;
+ PDBUSER dup= NULL;
+
+ // Areasize= 64M because of VEC tables. Should be parameterisable
+//g= PlugInit(NULL, 67108864);
+//g= PlugInit(NULL, 134217728); // 128M was because of old embedded tests
+ g= PlugInit(NULL, (size_t)worksize);
+
+ // Check whether the initialization is complete
+ if (!g || !g->Sarea || PlugSubSet(g->Sarea, g->Sarea_Size)
+ || !(dup= PlgMakeUser(g))) {
+ if (g)
+ printf("%s\n", g->Message);
+
+ (void) PlugExit(g);
+
+ if (dup)
+ free(dup);
+
+ return true;
+ } // endif g->
+
+ dup->Catalog= new MYCAT(NULL);
+
+ ap= new ACTIVITY;
+ memset(ap, 0, sizeof(ACTIVITY));
+ strcpy(ap->Ap_Name, "CONNECT");
+ g->Activityp= ap;
+ g->Activityp->Aptr= dup;
+
+ pthread_mutex_lock(&usrmut);
+ next= to_users;
+ to_users= this;
+
+ if (next)
+ next->previous= this;
+
+ count = 1;
+ pthread_mutex_unlock(&usrmut);
+
+ last_query_id= thdp->query_id;
+ return false;
+} // end of user_init
+
+
+void user_connect::SetHandler(ha_connect *hc)
+{
+ PDBUSER dup= (PDBUSER)g->Activityp->Aptr;
+ MYCAT *mc= (MYCAT*)dup->Catalog;
+ mc->SetHandler(hc);
+}
+
+/****************************************************************************/
+/* Check whether we begin a new query and if so cleanup the previous one. */
+/****************************************************************************/
+bool user_connect::CheckCleanup(bool force)
+{
+ if (thdp->query_id > last_query_id || force) {
+ size_t worksize = GetWorkSize();
+
+ PlugCleanup(g, true);
+
+ if (worksize != g->Sarea_Size) {
+ FreeSarea(g);
+ g->Saved_Size = g->Sarea_Size;
+
+ // Check whether the work area could be allocated
+ if (AllocSarea(g, worksize)) {
+ AllocSarea(g, g->Saved_Size);
+ SetWorkSize(g->Sarea_Size); // Was too big
+ } // endif sarea
+
+ } // endif worksize
+
+ PlugSubSet(g->Sarea, g->Sarea_Size);
+ g->Xchk = NULL;
+ g->Createas = false;
+ g->Alchecked = 0;
+ g->Mrr = 0;
+ g->More = 0;
+ g->Saved_Size = 0;
+ last_query_id= thdp->query_id;
+
+ if (trace(65) && !force)
+ printf("=====> Begin new query %llu\n", last_query_id);
+
+ return true;
+ } // endif query_id
+
+ return false;
+} // end of CheckCleanup
+
diff --git a/storage/connect/user_connect.h b/storage/connect/user_connect.h
new file mode 100644
index 00000000..53064e62
--- /dev/null
+++ b/storage/connect/user_connect.h
@@ -0,0 +1,73 @@
+/* Copyright (C) MariaDB Corporation Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/** @file user_connect.h
+
+ @brief
+ Declaration of the user_connect class.
+
+ @note
+ Author Olivier Bertrand
+
+ @see
+ /sql/handler.h and /storage/connect/user_connect.cc
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+/*****************************************************************************/
+/* This is the global structure having all CONNECT information. */
+/*****************************************************************************/
+//typedef struct _global *PGLOBAL;
+typedef class user_connect *PCONNECT;
+typedef class ha_connect *PHC;
+int connect_done_func(void *);
+
+/*****************************************************************************/
+/* The CONNECT users. There should be one by connected users. */
+/*****************************************************************************/
+class user_connect
+{
+ friend class ha_connect;
+ friend int connect_done_func(void *);
+public:
+ // Constructor
+ user_connect(THD *thd);
+
+ // Destructor
+ virtual ~user_connect();
+
+ // Implementation
+ bool user_init();
+ void SetHandler(ha_connect *hc);
+ bool CheckCleanup(bool force = false);
+ bool CheckQueryID(void) {return thdp->query_id > last_query_id;}
+ bool CheckQuery(query_id_t vid) {return last_query_id > vid;}
+
+ // Members
+ THD *thdp; // To the user thread
+ static PCONNECT to_users; // To the chain of users
+ PCONNECT next; // Next user in chain
+ PCONNECT previous; // Previous user in chain
+ PGLOBAL g; // The common handle to CONNECT
+ query_id_t last_query_id; // the latest user query id
+ int count; // if used by several handlers
+ // Statistics
+ ulong nrd, fnd, nfd;
+ ulonglong tb1;
+}; // end of user_connect class definition
+
diff --git a/storage/connect/valblk.cpp b/storage/connect/valblk.cpp
new file mode 100644
index 00000000..40d97517
--- /dev/null
+++ b/storage/connect/valblk.cpp
@@ -0,0 +1,1417 @@
+/************ Valblk C++ Functions Source Code File (.CPP) *************/
+/* Name: VALBLK.CPP Version 2.3 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2017 */
+/* */
+/* This file contains the VALBLK and derived classes functions. */
+/* Second family is VALBLK, representing simple suballocated arrays */
+/* of values treated sequentially by FIX, BIN and VCT tables and */
+/* columns, as well for min/max blocks as for VCT column blocks. */
+/* Q&A: why not using only one family ? Simple values are arrays that */
+/* have only one element and arrays could have functions for all kind */
+/* of processing. The answer is a-because historically it was simpler */
+/* to do that way, b-because of performance on single values, and c- */
+/* to avoid too complicated classes and unuseful duplication of many */
+/* functions used on one family only. The drawback is that for new */
+/* types of objects, we shall have more classes to update. */
+/* This is why we are now using a template class for many types. */
+/* Currently the only implemented types are PSZ, chars, int, short, */
+/* DATE, longlong, double and tiny. Fix numeric ones can be unsigned. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+//#include <windows.h>
+#else
+#include "osutil.h"
+#include "string.h"
+#endif
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* valblk.h is header containing VALBLK derived classes declares. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "valblk.h"
+
+#define CheckBlanks assert(!Blanks);
+#define CheckParms(V, N) ChkIndx(N); ChkTyp(V);
+
+extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
+
+/***********************************************************************/
+/* AllocValBlock: allocate a VALBLK according to type. */
+/***********************************************************************/
+PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
+ int prec, bool check, bool blank, bool un)
+ {
+ PVBLK blkp;
+
+ if (trace(1))
+ htrc("AVB: mp=%p type=%d nval=%d len=%d check=%u blank=%u\n",
+ mp, type, nval, len, check, blank);
+
+ switch (type) {
+ case TYPE_STRING:
+ case TYPE_BIN:
+ case TYPE_DECIM:
+ if (len)
+ blkp = new(g) CHRBLK(mp, nval, type, len, prec, blank);
+ else
+ blkp = new(g) STRBLK(g, mp, nval, type);
+
+ break;
+ case TYPE_SHORT:
+ if (un)
+ blkp = new(g) TYPBLK<ushort>(mp, nval, type, 0, true);
+ else
+ blkp = new(g) TYPBLK<short>(mp, nval, type);
+
+ break;
+ case TYPE_INT:
+ if (un)
+ blkp = new(g) TYPBLK<uint>(mp, nval, type, 0, true);
+ else
+ blkp = new(g) TYPBLK<int>(mp, nval, type);
+
+ break;
+ case TYPE_DATE: // ?????
+ blkp = new(g) DATBLK(mp, nval);
+ break;
+ case TYPE_BIGINT:
+ if (un)
+ blkp = new(g) TYPBLK<ulonglong>(mp, nval, type, 0, true);
+ else
+ blkp = new(g) TYPBLK<longlong>(mp, nval, type);
+
+ break;
+ case TYPE_DOUBLE:
+ blkp = new(g) TYPBLK<double>(mp, nval, type, prec);
+ break;
+ case TYPE_TINY:
+ if (un)
+ blkp = new(g) TYPBLK<uchar>(mp, nval, type, 0, true);
+ else
+ blkp = new(g) TYPBLK<char>(mp, nval, type);
+
+ break;
+ case TYPE_PCHAR:
+ blkp = new(g) PTRBLK(g, mp, nval);
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_VALBLK_TYPE), type);
+ return NULL;
+ } // endswitch Type
+
+ return (blkp->Init(g, check)) ? NULL : blkp;
+ } // end of AllocValBlock
+
+/* -------------------------- Class VALBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+VALBLK::VALBLK(void *mp, int type, int nval, bool un)
+ {
+ Mblk = Nmblk;
+ Blkp = mp;
+ To_Nulls = NULL;
+ Check = true;
+ Nullable = false;
+ Unsigned = un;
+ Type = type;
+ Nval = nval;
+ Prec = 0;
+ } // end of VALBLK constructor
+
+/***********************************************************************/
+/* Raise error for numeric types. */
+/***********************************************************************/
+PSZ VALBLK::GetCharValue(int)
+ {
+ PGLOBAL& g = Global;
+
+ assert(g);
+ sprintf(g->Message, MSG(NO_CHAR_FROM), Type);
+ throw Type;
+ return NULL;
+ } // end of GetCharValue
+
+/***********************************************************************/
+/* Set format so formatted dates can be converted on input. */
+/***********************************************************************/
+bool VALBLK::SetFormat(PGLOBAL g, PCSZ, int, int)
+ {
+ sprintf(g->Message, MSG(NO_DATE_FMT), Type);
+ return true;
+ } // end of SetFormat
+
+/***********************************************************************/
+/* Set the index of the location of value and return true if found. */
+/* To be used on ascending sorted arrays only. */
+/* Currently used by some BLKFIL classes only. */
+/***********************************************************************/
+bool VALBLK::Locate(PVAL vp, int& i)
+ {
+ ChkTyp(vp);
+
+ int n = 1;
+
+ for (i = 0; i < Nval; i++)
+ if ((n = CompVal(vp, i)) <= 0)
+ break;
+
+ return (!n);
+ } // end of Locate
+
+/***********************************************************************/
+/* Set Nullable and allocate the Null array. */
+/***********************************************************************/
+void VALBLK::SetNullable(bool b)
+ {
+ if ((Nullable = b)) {
+ To_Nulls = (char*)PlugSubAlloc(Global, NULL, Nval);
+ memset(To_Nulls, 0, Nval);
+ } else
+ To_Nulls = NULL;
+
+ } // end of SetNullable
+
+/***********************************************************************/
+/* Buffer allocation routine. */
+/***********************************************************************/
+bool VALBLK::AllocBuff(PGLOBAL g, size_t size)
+ {
+ Mblk.Size = size;
+
+ if (!(Blkp = PlgDBalloc(g, NULL, Mblk))) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "Blkp", (int) Mblk.Size);
+ fprintf(stderr, "%s\n", g->Message);
+ return true;
+ } // endif Blkp
+
+ return false;
+ } // end of AllocBuff
+
+/***********************************************************************/
+/* Check functions. */
+/***********************************************************************/
+void VALBLK::ChkIndx(int n)
+ {
+ if (n < 0 || n >= Nval) {
+ PGLOBAL& g = Global;
+ xtrc(1, "ChkIndx: n=%d Nval=%d\n", n, Nval);
+ strcpy(g->Message, MSG(BAD_VALBLK_INDX));
+ throw Type;
+ } // endif n
+
+ } // end of ChkIndx
+
+void VALBLK::ChkTyp(PVAL v)
+ {
+ if (Check && (Type != v->GetType() || Unsigned != v->IsUnsigned())) {
+ PGLOBAL& g = Global;
+ xtrc(1, "ChkTyp: Type=%d valType=%d\n", Type, v->GetType());
+ strcpy(g->Message, MSG(VALTYPE_NOMATCH));
+ throw Type;
+ } // endif Type
+
+ } // end of ChkTyp
+
+void VALBLK::ChkTyp(PVBLK vb)
+ {
+ if (Check && (Type != vb->GetType() || Unsigned != vb->IsUnsigned())) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(VALTYPE_NOMATCH));
+ throw Type;
+ } // endif Type
+
+ } // end of ChkTyp
+
+/* -------------------------- Class TYPBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+template <class TYPE>
+TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int type, int prec, bool un)
+ : VALBLK(mp, type, nval, un), Typp((TYPE*&)Blkp)
+ {
+ Prec = prec;
+ Fmt = GetFmt(Type);
+ } // end of TYPBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+template <class TYPE>
+bool TYPBLK<TYPE>::Init(PGLOBAL g, bool check)
+ {
+ if (!Blkp)
+ if (AllocBuff(g, Nval * sizeof(TYPE)))
+ return true;
+
+ Check = check;
+ Global = g;
+ return false;
+ } // end of Init
+
+/***********************************************************************/
+/* TYPVAL GetCharString: get string representation of a typed value. */
+/***********************************************************************/
+template <class TYPE>
+char *TYPBLK<TYPE>::GetCharString(char *p, int n)
+ {
+ sprintf(p, Fmt, Typp[n]);
+ return p;
+ } // end of GetCharString
+
+template <>
+char *TYPBLK<double>::GetCharString(char *p, int n)
+ {
+ sprintf(p, Fmt, Prec, Typp[n]);
+ return p;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+template <class TYPE>
+void TYPBLK<TYPE>::SetValue(PVAL valp, int n)
+ {
+ bool b;
+
+ ChkIndx(n);
+ ChkTyp(valp);
+
+ if (!(b = valp->IsNull()))
+ Typp[n] = GetTypedValue(valp);
+ else
+ Reset(n);
+
+ SetNull(n, b && Nullable);
+ } // end of SetValue
+
+template <>
+int TYPBLK<int>::GetTypedValue(PVAL valp)
+ {return valp->GetIntValue();}
+
+template <>
+uint TYPBLK<uint>::GetTypedValue(PVAL valp)
+ {return valp->GetUIntValue();}
+
+template <>
+short TYPBLK<short>::GetTypedValue(PVAL valp)
+ {return valp->GetShortValue();}
+
+template <>
+ushort TYPBLK<ushort>::GetTypedValue(PVAL valp)
+ {return valp->GetUShortValue();}
+
+template <>
+longlong TYPBLK<longlong>::GetTypedValue(PVAL valp)
+ {return valp->GetBigintValue();}
+
+template <>
+ulonglong TYPBLK<ulonglong>::GetTypedValue(PVAL valp)
+ {return valp->GetUBigintValue();}
+
+template <>
+double TYPBLK<double>::GetTypedValue(PVAL valp)
+ {return valp->GetFloatValue();}
+
+template <>
+char TYPBLK<char>::GetTypedValue(PVAL valp)
+ {return valp->GetTinyValue();}
+
+template <>
+uchar TYPBLK<uchar>::GetTypedValue(PVAL valp)
+ {return valp->GetUTinyValue();}
+
+/***********************************************************************/
+/* Set one value in a block from a zero terminated string. */
+/***********************************************************************/
+template <class TYPE>
+void TYPBLK<TYPE>::SetValue(PCSZ p, int n)
+ {
+ ChkIndx(n);
+
+ if (Check) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BAD_SET_STRING));
+ throw Type;
+ } // endif Check
+
+ bool minus;
+ ulonglong maxval = MaxVal();
+ ulonglong val = CharToNumber(p, strlen(p), maxval, Unsigned, &minus);
+
+ if (minus && val < maxval)
+ Typp[n] = (TYPE)(-(signed)val);
+ else
+ Typp[n] = (TYPE)val;
+
+ SetNull(n, false);
+ } // end of SetValue
+
+template <class TYPE>
+ulonglong TYPBLK<TYPE>::MaxVal(void) {DBUG_ASSERT(false); return 0;}
+
+template <>
+ulonglong TYPBLK<short>::MaxVal(void) {return INT_MAX16;}
+
+template <>
+ulonglong TYPBLK<ushort>::MaxVal(void) {return UINT_MAX16;}
+
+template <>
+ulonglong TYPBLK<int>::MaxVal(void) {return INT_MAX32;}
+
+template <>
+ulonglong TYPBLK<uint>::MaxVal(void) {return UINT_MAX32;}
+
+template <>
+ulonglong TYPBLK<char>::MaxVal(void) {return INT_MAX8;}
+
+template <>
+ulonglong TYPBLK<uchar>::MaxVal(void) {return UINT_MAX8;}
+
+template <>
+ulonglong TYPBLK<longlong>::MaxVal(void) {return INT_MAX64;}
+
+template <>
+ulonglong TYPBLK<ulonglong>::MaxVal(void) {return ULONGLONG_MAX;}
+
+template <>
+void TYPBLK<double>::SetValue(PCSZ p, int n)
+ {
+ ChkIndx(n);
+
+ if (Check) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BAD_SET_STRING));
+ throw Type;
+ } // endif Check
+
+ Typp[n] = atof(p);
+ SetNull(n, false);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block from an array of characters. */
+/***********************************************************************/
+template <class TYPE>
+void TYPBLK<TYPE>::SetValue(PCSZ sp, uint len, int n)
+ {
+ PGLOBAL& g = Global;
+ PSZ spz = (PSZ)PlugSubAlloc(g, NULL, 0); // Temporary
+
+ if (sp)
+ memcpy(spz, sp, len);
+
+ spz[len] = 0;
+ SetValue(spz, n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+template <class TYPE>
+void TYPBLK<TYPE>::SetValue(PVBLK pv, int n1, int n2)
+ {
+ bool b;
+
+ ChkIndx(n1);
+ ChkTyp(pv);
+
+ if (!(b = pv->IsNull(n2) && Nullable))
+ Typp[n1] = GetTypedValue(pv, n2);
+ else
+ Reset(n1);
+
+ SetNull(n1, b);
+ } // end of SetValue
+
+template <>
+int TYPBLK<int>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetIntValue(n);}
+
+template <>
+uint TYPBLK<uint>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUIntValue(n);}
+
+template <>
+short TYPBLK<short>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetShortValue(n);}
+
+template <>
+ushort TYPBLK<ushort>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUShortValue(n);}
+
+template <>
+longlong TYPBLK<longlong>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetBigintValue(n);}
+
+template <>
+ulonglong TYPBLK<ulonglong>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUBigintValue(n);}
+
+template <>
+double TYPBLK<double>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetFloatValue(n);}
+
+template <>
+char TYPBLK<char>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetTinyValue(n);}
+
+template <>
+uchar TYPBLK<uchar>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUTinyValue(n);}
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+template <class TYPE>
+void TYPBLK<TYPE>::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ TYPE tval = GetTypedValue(valp);
+ TYPE& tmin = Typp[n];
+
+ if (tval < tmin)
+ tmin = tval;
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+template <class TYPE>
+void TYPBLK<TYPE>::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ TYPE tval = GetTypedValue(valp);
+ TYPE& tmin = Typp[n];
+
+ if (tval > tmin)
+ tmin = tval;
+
+ } // end of SetMax
+
+#if 0
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+template <class TYPE>
+void TYPBLK<TYPE>::SetValues(PVBLK pv, int k, int n)
+ {
+ CheckType(pv)
+ TYPE *lp = ((TYPBLK*)pv)->Typp;
+
+ for (int i = k; i < n; i++) // TODO
+ Typp[i] = lp[i];
+
+ } // end of SetValues
+#endif // 0
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+template <class TYPE>
+void TYPBLK<TYPE>::Move(int i, int j)
+ {
+ Typp[j] = Typp[i];
+ MoveNull(i, j);
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+template <class TYPE>
+int TYPBLK<TYPE>::CompVal(PVAL vp, int n)
+ {
+#if defined(_DEBUG)
+ ChkIndx(n);
+ ChkTyp(vp);
+#endif // _DEBUG
+ TYPE mlv = Typp[n];
+ TYPE vlv = GetTypedValue(vp);
+
+ return (vlv > mlv) ? 1 : (vlv < mlv) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+template <class TYPE>
+int TYPBLK<TYPE>::CompVal(int i1, int i2)
+ {
+ TYPE lv1 = Typp[i1];
+ TYPE lv2 = Typp[i2];
+
+ return (lv1 > lv2) ? 1 : (lv1 < lv2) ? (-1) : 0;
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+template <class TYPE>
+void *TYPBLK<TYPE>::GetValPtr(int n)
+ {
+ ChkIndx(n);
+ return Typp + n;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+template <class TYPE>
+void *TYPBLK<TYPE>::GetValPtrEx(int n)
+ {
+ ChkIndx(n);
+ return Typp + n;
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+template <class TYPE>
+int TYPBLK<TYPE>::Find(PVAL vp)
+ {
+ ChkTyp(vp);
+
+ int i;
+ TYPE n = GetTypedValue(vp);
+
+ for (i = 0; i < Nval; i++)
+ if (n == Typp[i])
+ break;
+
+ return (i < Nval) ? i : (-1);
+ } // end of Find
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+template <class TYPE>
+int TYPBLK<TYPE>::GetMaxLength(void)
+ {
+ char buf[64];
+ int i, n, m;
+
+ for (i = n = 0; i < Nval; i++) {
+ m = sprintf(buf, Fmt, Typp[i]);
+ n = MY_MAX(n, m);
+ } // endfor i
+
+ return n;
+ } // end of GetMaxLength
+
+
+/* -------------------------- Class CHRBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+CHRBLK::CHRBLK(void *mp, int nval, int type, int len, int prec, bool blank)
+ : VALBLK(mp, type, nval), Chrp((char*&)Blkp)
+ {
+ Valp = NULL;
+ Blanks = blank;
+ Ci = (prec != 0);
+ Long = len;
+ } // end of CHRBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+bool CHRBLK::Init(PGLOBAL g, bool check)
+ {
+ Valp = (char*)PlugSubAlloc(g, NULL, Long + 1);
+ Valp[Long] = '\0';
+
+ if (!Blkp)
+ if (AllocBuff(g, Nval * Long))
+ return true;
+
+ Check = check;
+ Global = g;
+ return false;
+ } // end of Init
+
+/***********************************************************************/
+/* Reset nth element to a null string. */
+/***********************************************************************/
+void CHRBLK::Reset(int n)
+ {
+ if (Blanks)
+ memset(Chrp + n * Long, ' ', Long);
+ else
+ *(Chrp + n * Long) = '\0';
+
+ } // end of Reset
+
+/***********************************************************************/
+/* Return the zero ending value of the nth element. */
+/***********************************************************************/
+char *CHRBLK::GetCharValue(int n)
+ {
+ return (char *)GetValPtrEx(n);
+ } // end of GetCharValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to tiny int. */
+/***********************************************************************/
+char CHRBLK::GetTinyValue(int n)
+ {
+ bool m;
+ ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX8,
+ false, &m);
+
+ return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val;
+ } // end of GetTinyValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to unsigned tiny int.*/
+/***********************************************************************/
+uchar CHRBLK::GetUTinyValue(int n)
+ {
+ return (uchar)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX8, true);
+ } // end of GetTinyValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to short. */
+/***********************************************************************/
+short CHRBLK::GetShortValue(int n)
+ {
+ bool m;
+ ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX16,
+ false, &m);
+
+ return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val;
+ } // end of GetShortValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to ushort. */
+/***********************************************************************/
+ushort CHRBLK::GetUShortValue(int n)
+ {
+ return (ushort)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX16, true);
+ } // end of GetShortValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to int. */
+/***********************************************************************/
+int CHRBLK::GetIntValue(int n)
+ {
+ bool m;
+ ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX32,
+ false, &m);
+
+ return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val;
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to uint. */
+/***********************************************************************/
+uint CHRBLK::GetUIntValue(int n)
+ {
+ return (uint)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX32, true);
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to big int. */
+/***********************************************************************/
+longlong CHRBLK::GetBigintValue(int n)
+ {
+ bool m;
+ ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX64,
+ false, &m);
+
+ return (m && val < INT_MAX64) ? (longlong)(-(signed)val) : (longlong)val;
+ } // end of GetBigintValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to unsigned big int. */
+/***********************************************************************/
+ulonglong CHRBLK::GetUBigintValue(int n)
+ {
+ return CharToNumber((char*)GetValPtr(n), Long, ULONGLONG_MAX, true);
+ } // end of GetUBigintValue
+
+/***********************************************************************/
+/* Return the value of the nth element converted to double. */
+/***********************************************************************/
+double CHRBLK::GetFloatValue(int n)
+ {
+ return atof((char *)GetValPtrEx(n));
+ } // end of GetFloatValue
+
+/***********************************************************************/
+/* STRING GetCharString: get string representation of a char value. */
+/***********************************************************************/
+char *CHRBLK::GetCharString(char *, int n)
+ {
+ return (char *)GetValPtrEx(n);
+ } // end of GetCharString
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void CHRBLK::SetValue(PVAL valp, int n)
+ {
+ bool b;
+
+ ChkIndx(n);
+ ChkTyp(valp);
+
+ if (!(b = valp->IsNull()))
+ SetValue((PSZ)valp->GetCharValue(), n);
+ else
+ Reset(n);
+
+ SetNull(n, b && Nullable);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block from a zero terminated string. */
+/***********************************************************************/
+void CHRBLK::SetValue(PCSZ sp, int n)
+ {
+ uint len = (sp) ? strlen(sp) : 0;
+ SetValue(sp, len, n);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block from an array of characters. */
+/***********************************************************************/
+void CHRBLK::SetValue(const char *sp, uint len, int n)
+ {
+ char *p = Chrp + n * Long;
+
+#if defined(_DEBUG)
+ if (Check && (signed)len > Long) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(SET_STR_TRUNC));
+ throw Type;
+ } // endif Check
+#endif // _DEBUG
+
+ if (sp)
+ memcpy(p, sp, MY_MIN((unsigned)Long, len));
+
+ if (Blanks) {
+ // Suppress eventual ending zero and right fill with blanks
+ for (int i = len; i < Long; i++)
+ p[i] = ' ';
+
+ } else if ((signed)len < Long)
+ p[len] = 0;
+
+ SetNull(n, false);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+void CHRBLK::SetValue(PVBLK pv, int n1, int n2)
+ {
+ bool b;
+
+ if (Type != pv->GetType() || Long != ((CHRBLK*)pv)->Long) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BLKTYPLEN_MISM));
+ throw Type;
+ } // endif Type
+
+ if (!(b = pv->IsNull(n2)))
+ memcpy(Chrp + n1 * Long, ((CHRBLK*)pv)->Chrp + n2 * Long, Long);
+ else
+ Reset(n1);
+
+ SetNull(n1, b && Nullable);
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+void CHRBLK::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ CheckBlanks
+ char *vp = valp->GetCharValue();
+ char *bp = Chrp + n * Long;
+
+ if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) < 0)
+ memcpy(bp, vp, Long);
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+void CHRBLK::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ CheckBlanks
+ char *vp = valp->GetCharValue();
+ char *bp = Chrp + n * Long;
+
+ if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) > 0)
+ memcpy(bp, vp, Long);
+
+ } // end of SetMax
+
+#if 0
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+void CHRBLK::SetValues(PVBLK pv, int k, int n)
+ {
+#if defined(_DEBUG)
+ if (Type != pv->GetType() || Long != ((CHRBLK*)pv)->Long) {
+ PGLOBAL& g = Global;
+ strcpy(g->Message, MSG(BLKTYPLEN_MISM));
+ throw Type;
+ } // endif Type
+#endif // _DEBUG
+ char *p = ((CHRBLK*)pv)->Chrp;
+
+ if (!k)
+ memcpy(Chrp, p, Long * n);
+ else
+ memcpy(Chrp + k * Long, p + k * Long, Long * (n - k));
+
+ } // end of SetValues
+#endif // 0
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+void CHRBLK::Move(int i, int j)
+ {
+ if (i != j) {
+ memcpy(Chrp + j * Long, Chrp + i * Long, Long);
+ MoveNull(i, j);
+ } // endif i
+
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+int CHRBLK::CompVal(PVAL vp, int n)
+ {
+ ChkIndx(n);
+ ChkTyp(vp);
+
+ char *xvp = vp->GetCharValue(); // Get Value zero ended string
+ bool ci = Ci || vp->IsCi(); // true if is case insensitive
+
+ GetValPtrEx(n); // Get a zero ended string in Valp
+ return (ci) ? stricmp(xvp, Valp) : strcmp(xvp, Valp);
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int CHRBLK::CompVal(int i1, int i2)
+ {
+ return (Ci) ? strnicmp(Chrp + i1 * Long, Chrp + i2 * Long, Long)
+ : strncmp(Chrp + i1 * Long, Chrp + i2 * Long, Long);
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *CHRBLK::GetValPtr(int n)
+ {
+ ChkIndx(n);
+ return Chrp + n * Long;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on a zero ended string equal to nth value. */
+/***********************************************************************/
+void *CHRBLK::GetValPtrEx(int n)
+ {
+ ChkIndx(n);
+ memcpy(Valp, Chrp + n * Long, Long);
+
+ if (IsNull(n))
+ return const_cast<char *>("");
+
+ if (Blanks) {
+ // The (fast) way this is done works only for blocks such
+ // as Min and Max where strings are stored with the ending 0
+ // except for those whose length is equal to Len.
+ // For VCT blocks we must remove rightmost blanks.
+ char *p = Valp + Long;
+
+ for (p--; p >= Valp && *p == ' '; p--) ;
+
+ *(++p) = '\0';
+ } // endif Blanks
+
+ return Valp;
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+int CHRBLK::Find(PVAL vp)
+ {
+ ChkTyp(vp);
+
+ int i;
+ bool ci = Ci || vp->IsCi();
+ PSZ s = vp->GetCharValue();
+
+ if (vp->IsNull())
+ return -1;
+
+ for (i = 0; i < Nval; i++) {
+ if (IsNull(i))
+ continue;
+
+ GetValPtrEx(i); // Get a zero ended string in Valp
+
+ if (!((ci) ? strnicmp(s, Valp, Long) : strncmp(s, Valp, Long)))
+ break;
+
+ } // endfor i
+
+ return (i < Nval) ? i : (-1);
+ } // end of Find
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+int CHRBLK::GetMaxLength(void)
+ {
+ int i, n;
+
+ for (i = n = 0; i < Nval; i++)
+ if (!IsNull(i)) {
+ GetValPtrEx(i);
+ n = MY_MAX(n, (signed)strlen(Valp));
+ } // endif null
+
+ return n;
+ } // end of GetMaxLength
+
+
+/* -------------------------- Class STRBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+STRBLK::STRBLK(PGLOBAL g, void *mp, int nval, int type)
+ : VALBLK(mp, type, nval), Strp((PSZ*&)Blkp)
+ {
+ Global = g;
+ Nullable = true;
+ Sorted = false;
+ } // end of STRBLK constructor
+
+/***********************************************************************/
+/* Initialization routine. */
+/***********************************************************************/
+bool STRBLK::Init(PGLOBAL g, bool check)
+ {
+ if (!Blkp)
+ if (AllocBuff(g, Nval * sizeof(PSZ)))
+ return true;
+
+ Check = check;
+ Global = g;
+ return false;
+ } // end of Init
+
+/***********************************************************************/
+/* Get the tiny value represented by the Strp string. */
+/***********************************************************************/
+char STRBLK::GetTinyValue(int n)
+ {
+ bool m;
+ ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX8,
+ false, &m);
+
+ return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val;
+ } // end of GetTinyValue
+
+/***********************************************************************/
+/* Get the unsigned tiny value represented by the Strp string. */
+/***********************************************************************/
+uchar STRBLK::GetUTinyValue(int n)
+ {
+ return (uchar)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX8, true);
+ } // end of GetUTinyValue
+
+/***********************************************************************/
+/* Get the short value represented by the Strp string. */
+/***********************************************************************/
+short STRBLK::GetShortValue(int n)
+ {
+ bool m;
+ ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX16,
+ false, &m);
+
+ return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val;
+ } // end of GetShortValue
+
+/***********************************************************************/
+/* Get the unsigned short value represented by the Strp string. */
+/***********************************************************************/
+ushort STRBLK::GetUShortValue(int n)
+ {
+ return (ushort)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX16, true);
+ } // end of GetUshortValue
+
+/***********************************************************************/
+/* Get the integer value represented by the Strp string. */
+/***********************************************************************/
+int STRBLK::GetIntValue(int n)
+ {
+ bool m;
+ ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX32,
+ false, &m);
+
+ return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val;
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* Get the unsigned integer value represented by the Strp string. */
+/***********************************************************************/
+uint STRBLK::GetUIntValue(int n)
+ {
+ return (uint)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX32, true);
+ } // end of GetUintValue
+
+/***********************************************************************/
+/* Get the big integer value represented by the Strp string. */
+/***********************************************************************/
+longlong STRBLK::GetBigintValue(int n)
+ {
+ bool m;
+ ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX64,
+ false, &m);
+
+ return (m && val < INT_MAX64) ? (-(signed)val) : (longlong)val;
+ } // end of GetBigintValue
+
+/***********************************************************************/
+/* Get the unsigned big integer value represented by the Strp string. */
+/***********************************************************************/
+ulonglong STRBLK::GetUBigintValue(int n)
+ {
+ return CharToNumber(Strp[n], strlen(Strp[n]), ULONGLONG_MAX, true);
+ } // end of GetUBigintValue
+
+/***********************************************************************/
+/* Set one value in a block from a value in another block. */
+/***********************************************************************/
+void STRBLK::SetValue(PVBLK pv, int n1, int n2)
+ {
+ ChkTyp(pv);
+ Strp[n1] = (!pv->IsNull(n2)) ? ((STRBLK*)pv)->Strp[n2] : NULL;
+ } // end of SetValue
+
+#if 0
+/***********************************************************************/
+/* Set many values in a block from values in another block. */
+/***********************************************************************/
+void STRBLK::SetValues(PVBLK pv, int k, int n)
+ {
+ CheckType(pv)
+ PSZ *sp = ((STRBLK*)pv)->Strp;
+
+ for (int i = k; i < n; i++)
+ Strp[i] = (!pv->IsNull(i)) ? sp[i] : NULL;
+
+ } // end of SetValues
+#endif // 0
+
+/***********************************************************************/
+/* Set one value in a block. */
+/***********************************************************************/
+void STRBLK::SetValue(PVAL valp, int n)
+ {
+ ChkIndx(n);
+ ChkTyp(valp);
+
+ if (!valp->IsNull())
+ SetValue((PSZ)valp->GetCharValue(), n);
+ else
+ Strp[n] = NULL;
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block from a zero terminated string. */
+/***********************************************************************/
+void STRBLK::SetValue(PCSZ p, int n)
+ {
+ if (p) {
+ if (!Sorted || !n || !Strp[n-1] || strcmp(p, Strp[n-1]))
+ Strp[n] = (PSZ)PlugDup(Global, p);
+ else
+ Strp[n] = Strp[n-1];
+
+ } else
+ Strp[n] = NULL;
+
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block from an array of characters. */
+/***********************************************************************/
+void STRBLK::SetValue(const char *sp, uint len, int n)
+ {
+ PSZ p;
+
+ if (sp) {
+ if (!Sorted || !n || !Strp[n-1] || strlen(Strp[n-1]) != len ||
+ strncmp(sp, Strp[n-1], len)) {
+ p = (PSZ)PlugSubAlloc(Global, NULL, len + 1);
+ memcpy(p, sp, len);
+ p[len] = 0;
+ } else
+ p = Strp[n-1];
+
+ } else
+ p = NULL;
+
+ Strp[n] = p;
+ } // end of SetValue
+
+/***********************************************************************/
+/* Set one value in a block if val is less than the current value. */
+/***********************************************************************/
+void STRBLK::SetMin(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ char *vp = valp->GetCharValue();
+ char *bp = Strp[n];
+
+ if (strcmp(vp, bp) < 0)
+ SetValue(valp, n);
+
+ } // end of SetMin
+
+/***********************************************************************/
+/* Set one value in a block if val is greater than the current value. */
+/***********************************************************************/
+void STRBLK::SetMax(PVAL valp, int n)
+ {
+ CheckParms(valp, n)
+ char *vp = valp->GetCharValue();
+ char *bp = Strp[n];
+
+ if (strcmp(vp, bp) > 0)
+ SetValue(valp, n);
+
+ } // end of SetMax
+
+/***********************************************************************/
+/* Move one value from i to j. */
+/***********************************************************************/
+void STRBLK::Move(int i, int j)
+ {
+ Strp[j] = Strp[i];
+ } // end of Move
+
+/***********************************************************************/
+/* Compare a Value object with the nth value of the block. */
+/***********************************************************************/
+int STRBLK::CompVal(PVAL vp, int n)
+ {
+ ChkIndx(n);
+ ChkTyp(vp);
+
+ if (vp->IsNull() || !Strp[n])
+ DBUG_ASSERT(false);
+
+ return strcmp(vp->GetCharValue(), Strp[n]);
+ } // end of CompVal
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int STRBLK::CompVal(int i1, int i2)
+ {
+ if (!Strp[i1] || !Strp[i2])
+ DBUG_ASSERT(false);
+
+ return (strcmp(Strp[i1], Strp[i2]));
+ } // end of CompVal
+
+/***********************************************************************/
+/* Get a pointer on the nth value of the block. */
+/***********************************************************************/
+void *STRBLK::GetValPtr(int n)
+ {
+ ChkIndx(n);
+ return Strp + n;
+ } // end of GetValPtr
+
+/***********************************************************************/
+/* Get a pointer on a zero ended string equal to nth value. */
+/***********************************************************************/
+void *STRBLK::GetValPtrEx(int n)
+ {
+ ChkIndx(n);
+ return (Strp[n]) ? Strp[n] : const_cast<char*>("");
+ } // end of GetValPtrEx
+
+/***********************************************************************/
+/* Returns index of matching value in block or -1. */
+/***********************************************************************/
+int STRBLK::Find(PVAL vp)
+ {
+ int i;
+ PSZ s;
+
+ ChkTyp(vp);
+
+ if (vp->IsNull())
+ return -1;
+ else
+ s = vp->GetCharValue();
+
+ for (i = 0; i < Nval; i++)
+ if (Strp[i] && !strcmp(s, Strp[i]))
+ break;
+
+ return (i < Nval) ? i : (-1);
+ } // end of Find
+
+/***********************************************************************/
+/* Returns the length of the longest string in the block. */
+/***********************************************************************/
+int STRBLK::GetMaxLength(void)
+ {
+ int i, n;
+
+ for (i = n = 0; i < Nval; i++)
+ if (Strp[i])
+ n = MY_MAX(n, (signed)strlen(Strp[i]));
+
+ return n;
+ } // end of GetMaxLength
+
+/* -------------------------- Class DATBLK --------------------------- */
+
+/***********************************************************************/
+/* Constructor. */
+/***********************************************************************/
+DATBLK::DATBLK(void *mp, int nval) : TYPBLK<int>(mp, nval, TYPE_INT)
+ {
+ Type = TYPE_DATE;
+ Dvalp = NULL;
+ } // end of DATBLK constructor
+
+/***********************************************************************/
+/* Set format so formatted dates can be converted on input. */
+/***********************************************************************/
+bool DATBLK::SetFormat(PGLOBAL g, PCSZ fmt, int len, int year)
+ {
+ if (!(Dvalp = AllocateValue(g, TYPE_DATE, len, year, false, fmt)))
+ return true;
+
+ return false;
+ } // end of SetFormat
+
+/***********************************************************************/
+/* DTVAL GetCharString: get string representation of a date value. */
+/***********************************************************************/
+char *DATBLK::GetCharString(char *p, int n)
+ {
+ char *vp;
+
+ if (Dvalp) {
+ Dvalp->SetValue(Typp[n]);
+ vp = Dvalp->GetCharString(p);
+ } else
+ vp = TYPBLK<int>::GetCharString(p, n);
+
+ return vp;
+ } // end of GetCharString
+
+/***********************************************************************/
+/* Set one value in a block from a char string. */
+/***********************************************************************/
+void DATBLK::SetValue(PCSZ p, int n)
+ {
+ if (Dvalp) {
+ // Decode the string according to format
+ Dvalp->SetValue_psz(p);
+ Typp[n] = Dvalp->GetIntValue();
+ } else
+ TYPBLK<int>::SetValue(p, n);
+
+ } // end of SetValue
+
+
+/* -------------------------- Class PTRBLK --------------------------- */
+
+/***********************************************************************/
+/* Compare two values of the block. */
+/***********************************************************************/
+int PTRBLK::CompVal(int i1, int i2)
+ {
+ return (Strp[i1] > Strp[i2]) ? 1 : (Strp[i1] < Strp[i2]) ? (-1) : 0;
+ } // end of CompVal
+
+
+/* -------------------------- Class MBVALS --------------------------- */
+
+/***********************************************************************/
+/* Allocate a value block according to type,len, and nb of values. */
+/***********************************************************************/
+PVBLK MBVALS::Allocate(PGLOBAL g, int type, int len, int prec,
+ int n, bool sub)
+ {
+ Mblk.Sub = sub;
+ Mblk.Size = n * GetTypeSize(type, len);
+
+ if (!PlgDBalloc(g, NULL, Mblk)) {
+ sprintf(g->Message, MSG(ALLOC_ERROR), "MBVALS::Allocate");
+ return NULL;
+ } else
+ Vblk = AllocValBlock(g, Mblk.Memp, type, n, len, prec,
+ TRUE, TRUE, FALSE);
+
+ return Vblk;
+ } // end of Allocate
+
+/***********************************************************************/
+/* Reallocate the value block according to the new size. */
+/***********************************************************************/
+bool MBVALS::ReAllocate(PGLOBAL g, int n)
+ {
+ if (!PlgDBrealloc(g, NULL, Mblk, n * Vblk->GetVlen())) {
+ sprintf(g->Message, MSG(ALLOC_ERROR), "MBVALS::ReAllocate");
+ return TRUE;
+ } else
+ Vblk->ReAlloc(Mblk.Memp, n);
+
+ return FALSE;
+ } // end of ReAllocate
+
+/***********************************************************************/
+/* Free the value block. */
+/***********************************************************************/
+void MBVALS::Free(void)
+ {
+ PlgDBfree(Mblk);
+ Vblk = NULL;
+ } // end of Free
+
+/* ------------------------- End of Valblk --------------------------- */
+
diff --git a/storage/connect/valblk.h b/storage/connect/valblk.h
new file mode 100644
index 00000000..568fc172
--- /dev/null
+++ b/storage/connect/valblk.h
@@ -0,0 +1,363 @@
+/*************** Valblk H Declares Source Code File (.H) ***************/
+/* Name: VALBLK.H Version 2.1 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2005-2014 */
+/* */
+/* This file contains the VALBLK and derived classes declares. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include required application header files */
+/* assert.h is header required when using the assert function. */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#ifndef __VALBLK__H__
+#define __VALBLK__H__
+#include "value.h"
+
+/***********************************************************************/
+/* Utility used to allocate value blocks. */
+/***********************************************************************/
+DllExport PVBLK AllocValBlock(PGLOBAL, void*, int, int, int, int,
+ bool, bool, bool);
+const char *GetFmt(int type, bool un = false);
+
+/***********************************************************************/
+/* DB static external variables. */
+/***********************************************************************/
+extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
+
+/***********************************************************************/
+/* Class MBVALS is a utility class for (re)allocating VALBLK's. */
+/***********************************************************************/
+class MBVALS : public BLOCK {
+//friend class LSTBLK;
+ friend class ARRAY;
+ public:
+ // Constructors
+ MBVALS(void) {Vblk = NULL; Mblk = Nmblk;}
+
+ // Methods
+ void *GetMemp(void) {return Mblk.Memp;}
+ PVBLK Allocate(PGLOBAL g, int type, int len, int prec,
+ int n, bool sub = false);
+ bool ReAllocate(PGLOBAL g, int n);
+ void Free(void);
+
+ protected:
+ // Members
+ PVBLK Vblk; // Pointer to VALBLK
+ MBLOCK Mblk; // The memory block
+ }; // end of class MBVALS
+
+typedef class MBVALS *PMBV;
+
+/***********************************************************************/
+/* Class VALBLK represent a base class for variable blocks. */
+/***********************************************************************/
+class VALBLK : public BLOCK {
+ public:
+ // Constructors
+ VALBLK(void *mp, int type, int nval, bool un = false);
+
+ // Implementation
+ int GetNval(void) {return Nval;}
+ void SetNval(int n) {Nval = n;}
+ void *GetValPointer(void) {return Blkp;}
+ void SetValPointer(void *mp) {Blkp = mp;}
+ int GetType(void) {return Type;}
+ int GetPrec(void) {return Prec;}
+ void SetCheck(bool b) {Check = b;}
+ void MoveNull(int i, int j)
+ {if (To_Nulls) To_Nulls[j] = To_Nulls[i];}
+ virtual void SetNull(int n, bool b)
+ {if (To_Nulls) {To_Nulls[n] = (b) ? '*' : 0;}}
+ virtual bool IsNull(int n) {return To_Nulls && To_Nulls[n];}
+ virtual bool IsNullable(void) {return Nullable;}
+ virtual void SetNullable(bool b);
+ virtual bool IsUnsigned(void) {return Unsigned;}
+ virtual bool Init(PGLOBAL g, bool check) = 0;
+ virtual int GetVlen(void) = 0;
+ virtual PSZ GetCharValue(int n);
+ virtual char GetTinyValue(int n) = 0;
+ virtual uchar GetUTinyValue(int n) = 0;
+ virtual short GetShortValue(int n) = 0;
+ virtual ushort GetUShortValue(int n) = 0;
+ virtual int GetIntValue(int n) = 0;
+ virtual uint GetUIntValue(int n) = 0;
+ virtual longlong GetBigintValue(int n) = 0;
+ virtual ulonglong GetUBigintValue(int n) = 0;
+ virtual double GetFloatValue(int n) = 0;
+ virtual char *GetCharString(char *p, int n) = 0;
+ virtual void ReAlloc(void *mp, int n) {Blkp = mp; Nval = n;}
+ virtual void Reset(int n) = 0;
+ virtual bool SetFormat(PGLOBAL g, PCSZ fmt, int len, int year = 0);
+ virtual void SetPrec(int p) {}
+ virtual bool IsCi(void) {return false;}
+
+ // Methods
+ virtual void SetValue(short, int) {assert(false);}
+ virtual void SetValue(ushort, int) {assert(false);}
+ virtual void SetValue(int, int) {assert(false);}
+ virtual void SetValue(uint, int) {assert(false);}
+ virtual void SetValue(longlong, int) {assert(false);}
+ virtual void SetValue(ulonglong, int) {assert(false);}
+ virtual void SetValue(double, int) {assert(false);}
+ virtual void SetValue(char, int) {assert(false);}
+ virtual void SetValue(uchar, int) {assert(false);}
+ virtual void SetValue(PCSZ, int) {assert(false);}
+ virtual void SetValue(const char *, uint, int) {assert(false);}
+ virtual void SetValue(PVAL valp, int n) = 0;
+ virtual void SetValue(PVBLK pv, int n1, int n2) = 0;
+ virtual void SetMin(PVAL valp, int n) = 0;
+ virtual void SetMax(PVAL valp, int n) = 0;
+ virtual void Move(int i, int j) = 0;
+ virtual int CompVal(PVAL vp, int n) = 0;
+ virtual int CompVal(int i1, int i2) = 0;
+ virtual void *GetValPtr(int n) = 0;
+ virtual void *GetValPtrEx(int n) = 0;
+ virtual int Find(PVAL vp) = 0;
+ virtual int GetMaxLength(void) = 0;
+ bool Locate(PVAL vp, int& i);
+
+ protected:
+ bool AllocBuff(PGLOBAL g, size_t size);
+ void ChkIndx(int n);
+ void ChkTyp(PVAL v);
+ void ChkTyp(PVBLK vb);
+
+ // Members
+ PGLOBAL Global; // Used for messages and allocation
+ MBLOCK Mblk; // Used to allocate buffer
+ char *To_Nulls; // Null values array
+ void *Blkp; // To value block
+ bool Check; // If true SetValue types must match
+ bool Nullable; // True if values can be null
+ bool Unsigned; // True if values are unsigned
+ int Type; // Type of individual values
+ int Nval; // Max number of values in block
+ int Prec; // Precision of float values
+ }; // end of class VALBLK
+
+/***********************************************************************/
+/* Class TYPBLK: represents a block of typed values. */
+/***********************************************************************/
+template <class TYPE>
+class TYPBLK : public VALBLK {
+ public:
+ // Constructors
+ TYPBLK(void *mp, int size, int type, int prec = 0, bool un = false);
+
+ // Implementation
+ virtual bool Init(PGLOBAL g, bool check);
+ virtual int GetVlen(void) {return sizeof(TYPE);}
+ virtual char GetTinyValue(int n) {return (char)Typp[n];}
+ virtual uchar GetUTinyValue(int n) {return (uchar)Typp[n];}
+ virtual short GetShortValue(int n) {return (short)Typp[n];}
+ virtual ushort GetUShortValue(int n) {return (ushort)Typp[n];}
+ virtual int GetIntValue(int n) {return (int)Typp[n];}
+ virtual uint GetUIntValue(int n) {return (uint)Typp[n];}
+ virtual longlong GetBigintValue(int n) {return (longlong)Typp[n];}
+ virtual ulonglong GetUBigintValue(int n) {return (ulonglong)Typp[n];}
+ virtual double GetFloatValue(int n) {return (double)Typp[n];}
+ virtual char *GetCharString(char *p, int n);
+ virtual void Reset(int n) {Typp[n] = 0;}
+
+ // Methods
+ using VALBLK::SetValue;
+ virtual void SetValue(PCSZ sp, int n);
+ virtual void SetValue(const char *sp, uint len, int n);
+ virtual void SetValue(short sval, int n)
+ {Typp[n] = (TYPE)sval; SetNull(n, false);}
+ virtual void SetValue(ushort sval, int n)
+ {Typp[n] = (TYPE)sval; SetNull(n, false);}
+ virtual void SetValue(int lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(uint lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(longlong lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(ulonglong lval, int n)
+ {Typp[n] = (TYPE)lval; SetNull(n, false);}
+ virtual void SetValue(double fval, int n)
+ {Typp[n] = (TYPE)fval; SetNull(n, false);}
+ virtual void SetValue(char cval, int n)
+ {Typp[n] = (TYPE)cval; SetNull(n, false);}
+ virtual void SetValue(uchar cval, int n)
+ {Typp[n] = (TYPE)cval; SetNull(n, false);}
+ virtual void SetValue(PVAL valp, int n);
+ virtual void SetValue(PVBLK pv, int n1, int n2);
+ virtual void SetMin(PVAL valp, int n);
+ virtual void SetMax(PVAL valp, int n);
+ virtual void Move(int i, int j);
+ virtual int CompVal(PVAL vp, int n);
+ virtual int CompVal(int i1, int i2);
+ virtual void *GetValPtr(int n);
+ virtual void *GetValPtrEx(int n);
+ virtual int Find(PVAL vp);
+ virtual int GetMaxLength(void);
+
+ protected:
+ // Specialized functions
+ static ulonglong MaxVal(void);
+ TYPE GetTypedValue(PVAL vp);
+ TYPE GetTypedValue(PVBLK blk, int n);
+
+ // Members
+ TYPE* const &Typp;
+ const char *Fmt;
+ }; // end of class TYPBLK
+
+/***********************************************************************/
+/* Class CHRBLK: represent a block of fixed length strings. */
+/***********************************************************************/
+class CHRBLK : public VALBLK {
+ public:
+ // Constructors
+ CHRBLK(void *mp, int size, int type, int len, int prec, bool b);
+
+ // Implementation
+ virtual bool Init(PGLOBAL g, bool check);
+ virtual int GetVlen(void) {return Long;}
+ virtual PSZ GetCharValue(int n);
+ virtual char GetTinyValue(int n);
+ virtual uchar GetUTinyValue(int n);
+ virtual short GetShortValue(int n);
+ virtual ushort GetUShortValue(int n);
+ virtual int GetIntValue(int n);
+ virtual uint GetUIntValue(int n);
+ virtual longlong GetBigintValue(int n);
+ virtual ulonglong GetUBigintValue(int n);
+ virtual double GetFloatValue(int n);
+ virtual char *GetCharString(char *p, int n);
+ virtual void Reset(int n);
+ virtual void SetPrec(int p) {Ci = (p != 0);}
+ virtual bool IsCi(void) {return Ci;}
+
+ // Methods
+ using VALBLK::SetValue;
+ virtual void SetValue(PCSZ sp, int n);
+ virtual void SetValue(const char *sp, uint len, int n);
+ virtual void SetValue(PVAL valp, int n);
+ virtual void SetValue(PVBLK pv, int n1, int n2);
+ virtual void SetMin(PVAL valp, int n);
+ virtual void SetMax(PVAL valp, int n);
+ virtual void Move(int i, int j);
+ virtual int CompVal(PVAL vp, int n);
+ virtual int CompVal(int i1, int i2);
+ virtual void *GetValPtr(int n);
+ virtual void *GetValPtrEx(int n);
+ virtual int Find(PVAL vp);
+ virtual int GetMaxLength(void);
+
+ protected:
+ // Members
+ char* const &Chrp; // Pointer to char buffer
+ PSZ Valp; // Used to make a zero ended value
+ bool Blanks; // True for right filling with blanks
+ bool Ci; // True if case insensitive
+ int Long; // Length of each string
+ }; // end of class CHRBLK
+
+/***********************************************************************/
+/* Class STRBLK: represent a block of string pointers. */
+/* Currently this class is used only by the DECODE scalar function */
+/* and by the MyColumn function to store date formats. */
+/***********************************************************************/
+class STRBLK : public VALBLK {
+ public:
+ // Constructors
+ STRBLK(PGLOBAL g, void *mp, int size, int type);
+
+ // Implementation
+ virtual void SetNull(int n, bool b) {if (b) {Strp[n] = NULL;}}
+ virtual bool IsNull(int n) {return Strp[n] == NULL;}
+ virtual void SetNullable(bool) {} // Always nullable
+ virtual bool Init(PGLOBAL g, bool check);
+ virtual int GetVlen(void) {return sizeof(PSZ);}
+ virtual PSZ GetCharValue(int n) {return Strp[n];}
+ virtual char GetTinyValue(int n);
+ virtual uchar GetUTinyValue(int n);
+ virtual short GetShortValue(int n);
+ virtual ushort GetUShortValue(int n);
+ virtual int GetIntValue(int n);
+ virtual uint GetUIntValue(int n);
+ virtual longlong GetBigintValue(int n);
+ virtual ulonglong GetUBigintValue(int n);
+ virtual double GetFloatValue(int n) {return atof(Strp[n]);}
+ virtual char *GetCharString(char *, int n) {return Strp[n];}
+ virtual void Reset(int n) {Strp[n] = NULL;}
+
+ // Methods
+ using VALBLK::SetValue;
+ virtual void SetValue(PCSZ sp, int n);
+ virtual void SetValue(const char *sp, uint len, int n);
+ virtual void SetValue(PVAL valp, int n);
+ virtual void SetValue(PVBLK pv, int n1, int n2);
+ virtual void SetMin(PVAL valp, int n);
+ virtual void SetMax(PVAL valp, int n);
+ virtual void Move(int i, int j);
+ virtual int CompVal(PVAL vp, int n);
+ virtual int CompVal(int i1, int i2);
+ virtual void *GetValPtr(int n);
+ virtual void *GetValPtrEx(int n);
+ virtual int Find(PVAL vp);
+ virtual int GetMaxLength(void);
+
+ // Specific
+ void SetSorted(bool b) {Sorted = b;}
+
+ protected:
+ // Members
+ PSZ* const &Strp; // Pointer to PSZ buffer
+ bool Sorted; // Values are (semi?) sorted
+ }; // end of class STRBLK
+
+/***********************************************************************/
+/* Class DATBLK: represents a block of time stamp values. */
+/***********************************************************************/
+class DATBLK : public TYPBLK<int> {
+ public:
+ // Constructor
+ DATBLK(void *mp, int size);
+
+ // Implementation
+ virtual bool SetFormat(PGLOBAL g, PCSZ fmt, int len, int year = 0);
+ virtual char *GetCharString(char *p, int n);
+
+ // Methods
+ using TYPBLK<int>::SetValue;
+ virtual void SetValue(PCSZ sp, int n);
+
+ protected:
+ // Members
+ PVAL Dvalp; // Date value used to convert string
+ }; // end of class DATBLK
+
+/***********************************************************************/
+/* Class PTRBLK: represent a block of char pointers. */
+/* Currently this class is used only by the ARRAY class to make and */
+/* sort a list of char pointers. */
+/***********************************************************************/
+class PTRBLK : public STRBLK {
+ friend class ARRAY;
+ friend PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
+ bool, bool, bool);
+ protected:
+ // Constructors
+ PTRBLK(PGLOBAL g, void *mp, int size) : STRBLK(g, mp, size, TYPE_PCHAR) {}
+
+ // Implementation
+
+ // Methods
+ using STRBLK::SetValue;
+ using STRBLK::CompVal;
+ virtual void SetValue(PCSZ p, int n) {Strp[n] = (char*)p;}
+ virtual int CompVal(int i1, int i2);
+
+ protected:
+ // Members
+ }; // end of class PTRBLK
+
+#endif // __VALBLK__H__
+
diff --git a/storage/connect/value.cpp b/storage/connect/value.cpp
new file mode 100644
index 00000000..a34133a9
--- /dev/null
+++ b/storage/connect/value.cpp
@@ -0,0 +1,2891 @@
+/************* Value C++ Functions Source Code File (.CPP) *************/
+/* Name: VALUE.CPP Version 2.9 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2001-2019 */
+/* */
+/* This file contains the VALUE and derived classes family functions. */
+/* These classes contain values of different types. They are used so */
+/* new object types can be defined and added to the processing simply */
+/* (hopefully) adding their specific functions in this file. */
+/* First family is VALUE that represent single typed objects. It is */
+/* used by columns (COLBLK), SELECT and FILTER (derived) objects. */
+/* Second family is VALBLK, representing simple suballocated arrays */
+/* of values treated sequentially by FIX, BIN and VCT tables and */
+/* columns, as well for min/max blocks as for VCT column blocks. */
+/* Q&A: why not using only one family ? Simple values are arrays that */
+/* have only one element and arrays could have functions for all kind */
+/* of processing. The answer is a-because historically it was simpler */
+/* to do that way, b-because of performance on single values, and c- */
+/* to avoid too complicated classes and unuseful duplication of many */
+/* functions used on one family only. The drawback is that for new */
+/* types of objects, we shall have more classes to update. */
+/* Currently the only implemented types are STRING, INT, SHORT, TINY, */
+/* DATE and LONGLONG. Recently we added some UNSIGNED types. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant MariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#include "sql_class.h"
+#include "sql_time.h"
+
+#if defined(_WIN32)
+//#include <windows.h>
+#else // !_WIN32
+#include <string.h>
+#endif // !_WIN32
+
+#include <math.h>
+
+#undef DOMAIN // Was defined in math.h
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "preparse.h" // For DATPAR
+#include "valblk.h"
+#define NO_FUNC // Already defined in ODBConn
+#include "plgcnx.h" // For DB types
+#include "osutil.h"
+
+/***********************************************************************/
+/* Check macro's. */
+/***********************************************************************/
+#if defined(_DEBUG)
+#define CheckType(V) if (Type != V->GetType()) { \
+ PGLOBAL& g = Global; \
+ strcpy(g->Message, MSG(VALTYPE_NOMATCH)); \
+ throw Type;
+#else
+#define CheckType(V)
+#endif
+
+#define FOURYEARS 126230400 // Four years in seconds (1 leap)
+
+/***********************************************************************/
+/* Initialize the DTVAL static member. */
+/***********************************************************************/
+int DTVAL::Shift = 0;
+
+/***********************************************************************/
+/* Routines called externally. */
+/***********************************************************************/
+bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
+
+#if !defined(_WIN32)
+extern "C" {
+PSZ strupr(PSZ s);
+PSZ strlwr(PSZ s);
+}
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Get a long long number from its character representation. */
+/* IN p: Pointer to the numeric string */
+/* IN n: The string length */
+/* IN maxval: The number max value */
+/* IN un: True if the number must be unsigned */
+/* OUT rc: Set to TRUE for out of range value */
+/* OUT minus: Set to true if the number is negative */
+/* Returned val: The resulting number */
+/***********************************************************************/
+ulonglong CharToNumber(const char *p, int n, ulonglong maxval,
+ bool un, bool *minus, bool *rc)
+{
+ const char *p2;
+ uchar c;
+ ulonglong val;
+
+ if (minus) *minus = false;
+ if (rc) *rc = false;
+ if (n <= 0) return 0LL;
+
+ // Eliminate leading blanks or 0
+ for (p2 = p + n; p < p2 && (*p == ' ' || *p == '0'); p++) ;
+
+ // Get an eventual sign character
+ switch (*p) {
+ case '-':
+ if (un) {
+ if (rc) *rc = true;
+ return 0;
+ } else {
+ maxval++;
+ if (minus) *minus = true;
+ } // endif Unsigned
+
+ // Fall through
+ case '+':
+ p++;
+ break;
+ } // endswitch *p
+
+ for (val = 0; p < p2 && (c = (uchar)(*p - '0')) < 10; p++)
+ if (val > (maxval - c) / 10) {
+ val = maxval;
+ if (rc) *rc = true;
+ break;
+ } else
+ val = val * 10 + c;
+
+ return val;
+} // end of CharToNumber
+
+/***********************************************************************/
+/* GetTypeName: returns the PlugDB internal type name. */
+/***********************************************************************/
+PCSZ GetTypeName(int type)
+{
+ PCSZ name;
+
+ switch (type) {
+ case TYPE_STRING: name = "CHAR"; break;
+ case TYPE_SHORT: name = "SMALLINT"; break;
+ case TYPE_INT: name = "INTEGER"; break;
+ case TYPE_BIGINT: name = "BIGINT"; break;
+ case TYPE_DATE: name = "DATE"; break;
+ case TYPE_DOUBLE: name = "DOUBLE"; break;
+ case TYPE_TINY: name = "TINY"; break;
+ case TYPE_DECIM: name = "DECIMAL"; break;
+ case TYPE_BIN: name = "BINARY"; break;
+ case TYPE_PCHAR: name = "PCHAR"; break;
+ default: name = "UNKNOWN"; break;
+ } // endswitch type
+
+ return name;
+} // end of GetTypeName
+
+/***********************************************************************/
+/* GetTypeSize: returns the PlugDB internal type size. */
+/***********************************************************************/
+int GetTypeSize(int type, int len)
+ {
+ switch (type) {
+ case TYPE_DECIM:
+ case TYPE_BIN:
+ case TYPE_STRING: len = len * sizeof(char); break;
+ case TYPE_SHORT: len = sizeof(short); break;
+ case TYPE_INT: len = sizeof(int); break;
+ case TYPE_BIGINT: len = sizeof(longlong); break;
+ case TYPE_DATE: len = sizeof(int); break;
+ case TYPE_DOUBLE: len = sizeof(double); break;
+ case TYPE_TINY: len = sizeof(char); break;
+ case TYPE_PCHAR: len = sizeof(char*); break;
+ default: len = -1;
+ } // endswitch type
+
+ return len;
+} // end of GetTypeSize
+
+/***********************************************************************/
+/* GetFormatType: returns the FORMAT character(s) according to type. */
+/***********************************************************************/
+const char *GetFormatType(int type)
+{
+ const char *c = "X";
+
+ switch (type) {
+ case TYPE_STRING: c = "C"; break;
+ case TYPE_SHORT: c = "S"; break;
+ case TYPE_INT: c = "N"; break;
+ case TYPE_BIGINT: c = "L"; break;
+ case TYPE_DOUBLE: c = "F"; break;
+ case TYPE_DATE: c = "D"; break;
+ case TYPE_TINY: c = "T"; break;
+ case TYPE_DECIM: c = "F"; break;
+ case TYPE_BIN: c = "B"; break;
+ case TYPE_PCHAR: c = "P"; break;
+ } // endswitch type
+
+ return c;
+} // end of GetFormatType
+
+/***********************************************************************/
+/* GetFormatType: returns the FORMAT type according to character. */
+/***********************************************************************/
+int GetFormatType(char c)
+{
+ int type = TYPE_ERROR;
+
+ switch (c) {
+ case 'C': type = TYPE_STRING; break;
+ case 'S': type = TYPE_SHORT; break;
+ case 'N': type = TYPE_INT; break;
+ case 'L': type = TYPE_BIGINT; break;
+ case 'F': type = TYPE_DOUBLE; break;
+ case 'D': type = TYPE_DATE; break;
+ case 'T': type = TYPE_TINY; break;
+ case 'M': type = TYPE_DECIM; break;
+ case 'B': type = TYPE_BIN; break;
+ case 'P': type = TYPE_PCHAR; break;
+ } // endswitch type
+
+ return type;
+} // end of GetFormatType
+
+/***********************************************************************/
+/* IsTypeChar: returns true for character type(s). */
+/***********************************************************************/
+bool IsTypeChar(int type)
+{
+ switch (type) {
+ case TYPE_STRING:
+ case TYPE_DECIM:
+ case TYPE_BIN:
+ return true;
+ } // endswitch type
+
+ return false;
+} // end of IsTypeChar
+
+/***********************************************************************/
+/* IsTypeNum: returns true for numeric types. */
+/***********************************************************************/
+bool IsTypeNum(int type)
+{
+ switch (type) {
+ case TYPE_INT:
+ case TYPE_BIGINT:
+ case TYPE_DATE:
+ case TYPE_DOUBLE:
+ case TYPE_SHORT:
+ case TYPE_NUM:
+ case TYPE_TINY:
+ case TYPE_DECIM:
+ return true;
+ } // endswitch type
+
+ return false;
+} // end of IsTypeNum
+
+/***********************************************************************/
+/* GetFmt: returns the format to use with a typed value. */
+/***********************************************************************/
+const char *GetFmt(int type, bool un)
+{
+ const char *fmt;
+
+ switch (type) {
+ case TYPE_DECIM:
+ case TYPE_STRING: fmt = "%s"; break;
+ case TYPE_SHORT: fmt = (un) ? "%hu" : "%hd"; break;
+ case TYPE_BIGINT: fmt = (un) ? "%llu" : "%lld"; break;
+ case TYPE_DOUBLE: fmt = "%.*lf"; break;
+ case TYPE_BIN: fmt = "%*x"; break;
+ default: fmt = (un) ? "%u" : "%d"; break;
+ } // endswitch Type
+
+ return fmt;
+} // end of GetFmt
+
+/***********************************************************************/
+/* ConvertType: what this function does is to determine the type to */
+/* which should be converted a value so no precision would be lost. */
+/* This can be a numeric type if num is true or non numeric if false. */
+/* Note: this is an ultra simplified version of this function that */
+/* should become more and more complex as new types are added. */
+/* Not evaluated types (TYPE_VOID or TYPE_UNDEF) return false from */
+/* IsType... functions so match does not prevent correct setting. */
+/***********************************************************************/
+int ConvertType(int target, int type, CONV kind, bool match)
+{
+ switch (kind) {
+ case CNV_CHAR:
+ if (match && (!IsTypeChar(target) || !IsTypeChar(type)))
+ return TYPE_ERROR;
+
+ return TYPE_STRING;
+ case CNV_NUM:
+ if (match && (!IsTypeNum(target) || !IsTypeNum(type)))
+ return TYPE_ERROR;
+
+ return (target == TYPE_DOUBLE || type == TYPE_DOUBLE) ? TYPE_DOUBLE
+ : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE
+ : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT
+ : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT
+ : (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT
+ : TYPE_TINY;
+ default:
+ if (target == TYPE_ERROR || target == type)
+ return type;
+
+ if (match && ((IsTypeChar(target) && !IsTypeChar(type)) ||
+ (IsTypeNum(target) && !IsTypeNum(type))))
+ return TYPE_ERROR;
+
+ return (target == TYPE_DOUBLE || type == TYPE_DOUBLE) ? TYPE_DOUBLE
+ : (target == TYPE_DATE || type == TYPE_DATE) ? TYPE_DATE
+ : (target == TYPE_BIGINT || type == TYPE_BIGINT) ? TYPE_BIGINT
+ : (target == TYPE_INT || type == TYPE_INT) ? TYPE_INT
+ : (target == TYPE_SHORT || type == TYPE_SHORT) ? TYPE_SHORT
+ : (target == TYPE_STRING || type == TYPE_STRING) ? TYPE_STRING
+ : (target == TYPE_TINY || type == TYPE_TINY) ? TYPE_TINY
+ : TYPE_ERROR;
+ } // endswitch kind
+
+} // end of ConvertType
+
+/***********************************************************************/
+/* AllocateConstant: allocates a constant Value. */
+/***********************************************************************/
+PVAL AllocateValue(PGLOBAL g, void *value, short type, short prec)
+{
+ PVAL valp;
+
+ if (trace(1))
+ htrc("AllocateConstant: value=%p type=%hd\n", value, type);
+
+ switch (type) {
+ case TYPE_STRING:
+ valp = new(g) TYPVAL<PSZ>((PSZ)value, prec);
+ break;
+ case TYPE_SHORT:
+ valp = new(g) TYPVAL<short>(*(short*)value, TYPE_SHORT);
+ break;
+ case TYPE_INT:
+ valp = new(g) TYPVAL<int>(*(int*)value, TYPE_INT);
+ break;
+ case TYPE_BIGINT:
+ valp = new(g) TYPVAL<longlong>(*(longlong*)value, TYPE_BIGINT);
+ break;
+ case TYPE_DOUBLE:
+ valp = new(g) TYPVAL<double>(*(double *)value, TYPE_DOUBLE, prec);
+ break;
+ case TYPE_TINY:
+ valp = new(g) TYPVAL<char>(*(char *)value, TYPE_TINY);
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
+ return NULL;
+ } // endswitch Type
+
+ valp->SetGlobal(g);
+ return valp;
+} // end of AllocateValue
+
+/***********************************************************************/
+/* Allocate a variable Value according to type, length and precision. */
+/***********************************************************************/
+PVAL AllocateValue(PGLOBAL g, int type, int len, int prec,
+ bool uns, PCSZ fmt)
+{
+ PVAL valp;
+
+ switch (type) {
+ case TYPE_STRING:
+ valp = new(g) TYPVAL<PSZ>(g, (PSZ)NULL, len, prec);
+ break;
+ case TYPE_DATE:
+ valp = new(g) DTVAL(g, len, prec, fmt);
+ break;
+ case TYPE_INT:
+ if (uns)
+ valp = new(g) TYPVAL<uint>((uint)0, TYPE_INT, 0, true);
+ else
+ valp = new(g) TYPVAL<int>((int)0, TYPE_INT);
+
+ break;
+ case TYPE_BIGINT:
+ if (uns)
+ valp = new(g) TYPVAL<ulonglong>((ulonglong)0, TYPE_BIGINT, 0, true);
+ else
+ valp = new(g) TYPVAL<longlong>((longlong)0, TYPE_BIGINT);
+
+ break;
+ case TYPE_SHORT:
+ if (uns)
+ valp = new(g) TYPVAL<ushort>((ushort)0, TYPE_SHORT, 0, true);
+ else
+ valp = new(g) TYPVAL<short>((short)0, TYPE_SHORT);
+
+ break;
+ case TYPE_DOUBLE:
+ valp = new(g) TYPVAL<double>(0.0, TYPE_DOUBLE, prec);
+ break;
+ case TYPE_TINY:
+ if (uns)
+ valp = new(g) TYPVAL<uchar>((uchar)0, TYPE_TINY, 0, true);
+ else
+ valp = new(g) TYPVAL<char>((char)0, TYPE_TINY);
+
+ break;
+ case TYPE_DECIM:
+ valp = new(g) DECVAL(g, (PSZ)NULL, len, prec, uns);
+ break;
+ case TYPE_BIN:
+ valp = new(g) BINVAL(g, (void*)NULL, len, prec);
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_VALUE_TYPE), type);
+ return NULL;
+ } // endswitch type
+
+ valp->SetGlobal(g);
+ return valp;
+} // end of AllocateValue
+
+/***********************************************************************/
+/* Allocate a constant Value converted to newtype. */
+/* Can also be used to copy a Value eventually converted. */
+/***********************************************************************/
+PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns)
+{
+ PSZ p, sp;
+ bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned();
+ PVAL vp;
+
+ if (!valp)
+ return NULL;
+
+ if (newtype == TYPE_VOID) // Means allocate a value of the same type
+ newtype = valp->GetType();
+
+ switch (newtype) {
+ case TYPE_STRING:
+ p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen());
+
+ if ((sp = valp->GetCharString(p)) != p && sp)
+ strcpy(p, sp);
+
+ vp = new(g) TYPVAL<PSZ>(g, p, valp->GetValLen(), valp->GetValPrec());
+ break;
+ case TYPE_SHORT:
+ if (un)
+ vp = new(g) TYPVAL<ushort>(valp->GetUShortValue(),
+ TYPE_SHORT, 0, true);
+ else
+ vp = new(g) TYPVAL<short>(valp->GetShortValue(), TYPE_SHORT);
+
+ break;
+ case TYPE_INT:
+ if (un)
+ vp = new(g) TYPVAL<uint>(valp->GetUIntValue(), TYPE_INT, 0, true);
+ else
+ vp = new(g) TYPVAL<int>(valp->GetIntValue(), TYPE_INT);
+
+ break;
+ case TYPE_BIGINT:
+ if (un)
+ vp = new(g) TYPVAL<ulonglong>(valp->GetUBigintValue(),
+ TYPE_BIGINT, 0, true);
+ else
+ vp = new(g) TYPVAL<longlong>(valp->GetBigintValue(), TYPE_BIGINT);
+
+ break;
+ case TYPE_DATE:
+ vp = new(g) DTVAL(valp->GetIntValue());
+ break;
+ case TYPE_DOUBLE:
+ vp = new(g) TYPVAL<double>(valp->GetFloatValue(), TYPE_DOUBLE,
+ (uns) ? uns : valp->GetValPrec());
+ break;
+ case TYPE_TINY:
+ if (un)
+ vp = new(g) TYPVAL<uchar>(valp->GetUTinyValue(),
+ TYPE_TINY, 0, true);
+ else
+ vp = new(g) TYPVAL<char>(valp->GetTinyValue(), TYPE_TINY);
+
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_VALUE_TYPE), newtype);
+ return NULL;
+ } // endswitch type
+
+ vp->SetNullable(valp->GetNullable());
+ vp->SetNull(valp->IsNull());
+ vp->SetGlobal(g);
+ return vp;
+} // end of AllocateValue
+
+/* -------------------------- Class VALUE ---------------------------- */
+
+/***********************************************************************/
+/* Class VALUE protected constructor. */
+/***********************************************************************/
+VALUE::VALUE(int type, bool un) : Type(type)
+{
+ Null = false;
+ Nullable = false;
+ Unsigned = un;
+ Clen = 0;
+ Prec = 0;
+ Fmt = GetFmt(Type, Unsigned);
+ Xfmt = GetXfmt();
+} // end of VALUE constructor
+
+/***********************************************************************/
+/* VALUE GetXfmt: returns the extended format to use with typed value. */
+/***********************************************************************/
+const char *VALUE::GetXfmt(void)
+{
+ const char *fmt;
+
+ switch (Type) {
+ case TYPE_DECIM:
+ case TYPE_STRING: fmt = "%*s"; break;
+ case TYPE_SHORT: fmt = (Unsigned) ? "%*hu" : "%*hd"; break;
+ case TYPE_BIGINT: fmt = (Unsigned) ? "%*llu" : "%*lld"; break;
+ case TYPE_DOUBLE: fmt = "%*.*lf"; break;
+ case TYPE_BIN: fmt = "%*x"; break;
+ default: fmt = (Unsigned) ? "%*u" : "%*d"; break;
+ } // endswitch Type
+
+ return fmt;
+} // end of GetXFmt
+
+/***********************************************************************/
+/* Returns a BYTE indicating the comparison between two values. */
+/* Bit 1 indicates equality, Bit 2 less than, and Bit3 greater than. */
+/* More than 1 bit can be set only in the case of TYPE_LIST. */
+/***********************************************************************/
+BYTE VALUE::TestValue(PVAL vp)
+{
+ int n = CompareValue(vp);
+
+ return (n > 0) ? 0x04 : (n < 0) ? 0x02 : 0x01;
+} // end of TestValue
+
+/***********************************************************************/
+/* Compute a function on a string. */
+/***********************************************************************/
+bool VALUE::Compute(PGLOBAL g, PVAL *, int, OPVAL)
+{
+ strcpy(g->Message, "Compute not implemented for this value type");
+ return true;
+} // end of Compute
+
+/***********************************************************************/
+/* Make file output of an object value. */
+/***********************************************************************/
+void VALUE::Printf(PGLOBAL g, FILE *f, uint n)
+{
+ char m[64], buf[64];
+
+ memset(m, ' ', n); /* Make margin string */
+ m[n] = '\0';
+
+ if (Null)
+ fprintf(f, "%s<null>\n", m);
+ else
+ fprintf(f, "%s%s\n", m, GetCharString(buf));
+
+} /* end of Printf */
+
+/***********************************************************************/
+/* Make string output of an object value. */
+/***********************************************************************/
+void VALUE::Prints(PGLOBAL g, char *ps, uint z)
+{
+ char *p, buf[64];
+
+ if (Null)
+ p = strcpy(buf, "<null>");
+ else
+ p = GetCharString(buf);
+
+ strncpy(ps, p, z);
+} // end of Prints
+
+/* -------------------------- Class TYPVAL ---------------------------- */
+
+/***********************************************************************/
+/* TYPVAL public constructor from a constant typed value. */
+/***********************************************************************/
+template <class TYPE>
+TYPVAL<TYPE>::TYPVAL(TYPE n, int type, int prec, bool un)
+ : VALUE(type, un)
+{
+ Tval = n;
+ Clen = sizeof(TYPE);
+ Prec = prec;
+} // end of TYPVAL constructor
+
+/***********************************************************************/
+/* Return unsigned max value for the type. */
+/***********************************************************************/
+template <class TYPE>
+ulonglong TYPVAL<TYPE>::MaxVal(void) {DBUG_ASSERT(false); return 0;}
+
+template <>
+ulonglong TYPVAL<short>::MaxVal(void) {return INT_MAX16;}
+
+template <>
+ulonglong TYPVAL<ushort>::MaxVal(void) {return UINT_MAX16;}
+
+template <>
+ulonglong TYPVAL<int>::MaxVal(void) {return INT_MAX32;}
+
+template <>
+ulonglong TYPVAL<uint>::MaxVal(void) {return UINT_MAX32;}
+
+template <>
+ulonglong TYPVAL<char>::MaxVal(void) {return INT_MAX8;}
+
+template <>
+ulonglong TYPVAL<uchar>::MaxVal(void) {return UINT_MAX8;}
+
+template <>
+ulonglong TYPVAL<longlong>::MaxVal(void) {return INT_MAX64;}
+
+template <>
+ulonglong TYPVAL<ulonglong>::MaxVal(void) {return ULONGLONG_MAX;}
+
+/***********************************************************************/
+/* TYPVAL GetValLen: returns the print length of the typed object. */
+/***********************************************************************/
+template <class TYPE>
+int TYPVAL<TYPE>::GetValLen(void)
+{
+ char c[32];
+
+ return snprintf(c, 32, Fmt, Tval);
+} // end of GetValLen
+
+template <>
+int TYPVAL<double>::GetValLen(void)
+{
+ char c[32];
+
+ return snprintf(c, 32, Fmt, Prec, Tval);
+} // end of GetValLen
+
+/***********************************************************************/
+/* TYPVAL SetValue: copy the value of another Value object. */
+/* This function allows conversion if chktype is false. */
+/***********************************************************************/
+template <class TYPE>
+bool TYPVAL<TYPE>::SetValue_pval(PVAL valp, bool chktype)
+{
+ if (valp != this) {
+ if (chktype && Type != valp->GetType())
+ return true;
+
+ if (!(Null = (valp->IsNull() && Nullable)))
+ Tval = GetTypedValue(valp);
+ else
+ Reset();
+
+ } // endif valp
+
+ return false;
+} // end of SetValue
+
+template <>
+short TYPVAL<short>::GetTypedValue(PVAL valp)
+ {return valp->GetShortValue();}
+
+template <>
+ushort TYPVAL<ushort>::GetTypedValue(PVAL valp)
+ {return valp->GetUShortValue();}
+
+template <>
+int TYPVAL<int>::GetTypedValue(PVAL valp)
+ {return valp->GetIntValue();}
+
+template <>
+uint TYPVAL<uint>::GetTypedValue(PVAL valp)
+ {return valp->GetUIntValue();}
+
+template <>
+longlong TYPVAL<longlong>::GetTypedValue(PVAL valp)
+ {return valp->GetBigintValue();}
+
+template <>
+ulonglong TYPVAL<ulonglong>::GetTypedValue(PVAL valp)
+ {return valp->GetUBigintValue();}
+
+template <>
+double TYPVAL<double>::GetTypedValue(PVAL valp)
+ {return valp->GetFloatValue();}
+
+template <>
+char TYPVAL<char>::GetTypedValue(PVAL valp)
+ {return valp->GetTinyValue();}
+
+template <>
+uchar TYPVAL<uchar>::GetTypedValue(PVAL valp)
+ {return valp->GetUTinyValue();}
+
+/***********************************************************************/
+/* TYPVAL SetValue: convert chars extracted from a line to TYPE value.*/
+/***********************************************************************/
+template <class TYPE>
+bool TYPVAL<TYPE>::SetValue_char(const char *p, int n)
+{
+ bool rc, minus;
+ ulonglong maxval = MaxVal();
+ ulonglong val = CharToNumber(p, n, maxval, Unsigned, &minus, &rc);
+
+ if (minus && val < maxval)
+ Tval = (TYPE)(-(signed)val);
+ else
+ Tval = (TYPE)val;
+
+ if (trace(2)) {
+ char buf[64];
+ htrc(strcat(strcat(strcpy(buf, " setting %s to: "), Fmt), "\n"),
+ GetTypeName(Type), Tval);
+ } // endif trace
+
+ Null = false;
+ return rc;
+} // end of SetValue
+
+template <>
+bool TYPVAL<double>::SetValue_char(const char *p, int n)
+{
+ if (p && n > 0) {
+ char buf[64];
+
+ for (; n > 0 && *p == ' '; p++)
+ n--;
+
+ memcpy(buf, p, MY_MIN(n, 31));
+ buf[n] = '\0';
+ Tval = atof(buf);
+
+ if (trace(2))
+ htrc(" setting double: '%s' -> %lf\n", buf, Tval);
+
+ Null = false;
+ } else {
+ Reset();
+ Null = Nullable;
+ } // endif p
+
+ return false;
+} // end of SetValue
+
+/***********************************************************************/
+/* TYPVAL SetValue: fill a typed value from a string. */
+/***********************************************************************/
+template <class TYPE>
+void TYPVAL<TYPE>::SetValue_psz(PCSZ s)
+{
+ if (s) {
+ SetValue_char(s, (int)strlen(s));
+ Null = false;
+ } else {
+ Reset();
+ Null = Nullable;
+ } // endif p
+
+} // end of SetValue
+
+/***********************************************************************/
+/* TYPVAL SetValue: set value with a TYPE extracted from a block. */
+/***********************************************************************/
+template <class TYPE>
+void TYPVAL<TYPE>::SetValue_pvblk(PVBLK blk, int n)
+{
+ Tval = GetTypedValue(blk, n);
+ Null = false;
+} // end of SetValue
+
+template <>
+int TYPVAL<int>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetIntValue(n);}
+
+template <>
+uint TYPVAL<uint>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUIntValue(n);}
+
+template <>
+short TYPVAL<short>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetShortValue(n);}
+
+template <>
+ushort TYPVAL<ushort>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUShortValue(n);}
+
+template <>
+longlong TYPVAL<longlong>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetBigintValue(n);}
+
+template <>
+ulonglong TYPVAL<ulonglong>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUBigintValue(n);}
+
+template <>
+double TYPVAL<double>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetFloatValue(n);}
+
+template <>
+char TYPVAL<char>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetTinyValue(n);}
+
+template <>
+uchar TYPVAL<uchar>::GetTypedValue(PVBLK blk, int n)
+ {return blk->GetUTinyValue(n);}
+
+/***********************************************************************/
+/* TYPVAL SetBinValue: with bytes extracted from a line. */
+/* Currently only used reading column of binary files. */
+/***********************************************************************/
+template <class TYPE>
+void TYPVAL<TYPE>::SetBinValue(void *p)
+{
+#if defined(UNALIGNED_OK)
+ // x86 can cast non-aligned memory directly
+ Tval = *(TYPE *)p;
+#else
+ // Prevent unaligned memory access on MIPS and ArmHF platforms.
+ // Make use of memcpy instead of straight pointer dereferencing.
+ // Currently only used by WriteColumn of binary files.
+ // From original author: Vicentiu Ciorbaru <vicentiu@mariadb.org>
+ memcpy(&Tval, p, sizeof(TYPE));
+#endif
+ Null = false;
+} // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently only used writing column of binary files. */
+/***********************************************************************/
+template <class TYPE>
+bool TYPVAL<TYPE>::GetBinValue(void *buf, int buflen, bool go)
+{
+ // Test on length was removed here until a variable in column give the
+ // real field length. For BIN files the field length logically cannot
+ // be different from the variable length because no conversion is done.
+ // Therefore this test is useless anyway.
+//#if defined(_DEBUG)
+// if (sizeof(TYPE) > buflen)
+// return true;
+//#endif
+
+ if (go)
+#if defined(UNALIGNED_OK)
+ // x86 can cast non-aligned memory directly
+ *(TYPE *)buf = Tval;
+#else
+ // Prevent unaligned memory access on MIPS and ArmHF platforms.
+ // Make use of memcpy instead of straight pointer dereferencing.
+ // Currently only used by WriteColumn of binary files.
+ // From original author: Vicentiu Ciorbaru <vicentiu@mariadb.org>
+ memcpy(buf, &Tval, sizeof(TYPE));
+#endif
+
+ Null = false;
+ return false;
+} // end of GetBinValue
+
+/***********************************************************************/
+/* TYPVAL ShowValue: get string representation of a typed value. */
+/***********************************************************************/
+template <class TYPE>
+int TYPVAL<TYPE>::ShowValue(char *buf, int len)
+{
+ return snprintf(buf, len + 1, Xfmt, len, Tval);
+} // end of ShowValue
+
+template <>
+int TYPVAL<double>::ShowValue(char *buf, int len)
+{
+ // TODO: use a more appropriate format to avoid possible truncation
+ return snprintf(buf, len + 1, Xfmt, len, Prec, Tval);
+} // end of ShowValue
+
+/***********************************************************************/
+/* TYPVAL GetCharString: get string representation of a typed value. */
+/***********************************************************************/
+template <class TYPE>
+char *TYPVAL<TYPE>::GetCharString(char *p)
+{
+ sprintf(p, Fmt, Tval);
+ return p;
+} // end of GetCharString
+
+template <>
+char *TYPVAL<double>::GetCharString(char *p)
+{
+ // Most callers use a 32 long buffer
+ snprintf(p, 32, Fmt, Prec, Tval);
+ return p;
+} // end of GetCharString
+
+#if 0
+/***********************************************************************/
+/* TYPVAL GetShortString: get short representation of a typed value. */
+/***********************************************************************/
+template <class TYPE>
+char *TYPVAL<TYPE>::GetShortString(char *p, int n)
+{
+ sprintf(p, "%*hd", n, (short)Tval);
+ return p;
+} // end of GetShortString
+
+/***********************************************************************/
+/* TYPVAL GetIntString: get int representation of a typed value. */
+/***********************************************************************/
+template <class TYPE>
+char *TYPVAL<TYPE>::GetIntString(char *p, int n)
+{
+ sprintf(p, "%*d", n, (int)Tval);
+ return p;
+} // end of GetIntString
+
+/***********************************************************************/
+/* TYPVAL GetBigintString: get big int representation of a TYPE value.*/
+/***********************************************************************/
+template <class TYPE>
+char *TYPVAL<TYPE>::GetBigintString(char *p, int n)
+{
+ sprintf(p, "%*lld", n, (longlong)Tval);
+ return p;
+} // end of GetBigintString
+
+/***********************************************************************/
+/* TYPVAL GetFloatString: get double representation of a typed value. */
+/***********************************************************************/
+template <class TYPE>
+char *TYPVAL<TYPE>::GetFloatString(char *p, int n, int prec)
+{
+ sprintf(p, "%*.*lf", n, (prec < 0) ? 2 : prec, (double)Tval);
+ return p;
+} // end of GetFloatString
+
+/***********************************************************************/
+/* TYPVAL GetTinyString: get char representation of a typed value. */
+/***********************************************************************/
+template <class TYPE>
+char *TYPVAL<TYPE>::GetTinyString(char *p, int n)
+{
+ sprintf(p, "%*d", n, (int)(char)Tval);
+ return p;
+} // end of GetIntString
+#endif // 0
+
+/***********************************************************************/
+/* TYPVAL compare value with another Value. */
+/***********************************************************************/
+template <class TYPE>
+bool TYPVAL<TYPE>::IsEqual(PVAL vp, bool chktype)
+{
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else if (chktype && Unsigned != vp->IsUnsigned())
+ return false;
+ else if (Null || vp->IsNull())
+ return false;
+ else
+ return (Tval == GetTypedValue(vp));
+
+} // end of IsEqual
+
+/***********************************************************************/
+/* Compare values and returns 1, 0 or -1 according to comparison. */
+/* This function is used for evaluation of numeric filters. */
+/***********************************************************************/
+template <class TYPE>
+int TYPVAL<TYPE>::CompareValue(PVAL vp)
+{
+//assert(vp->GetType() == Type);
+
+ // Process filtering on numeric values.
+ TYPE n = GetTypedValue(vp);
+
+//if (trace(1))
+// htrc(" Comparing: val=%d,%d\n", Tval, n);
+
+ return (Tval > n) ? 1 : (Tval < n) ? (-1) : 0;
+} // end of CompareValue
+
+/***********************************************************************/
+/* Return max type value if b is true, else min type value. */
+/***********************************************************************/
+template <>
+short TYPVAL<short>::MinMaxVal(bool b)
+ {return (b) ? INT_MAX16 : INT_MIN16;}
+
+template <>
+ushort TYPVAL<ushort>::MinMaxVal(bool b)
+ {return (b) ? UINT_MAX16 : 0;}
+
+template <>
+int TYPVAL<int>::MinMaxVal(bool b)
+ {return (b) ? INT_MAX32 : INT_MIN32;}
+
+template <>
+uint TYPVAL<uint>::MinMaxVal(bool b)
+ {return (b) ? UINT_MAX32 : 0;}
+
+template <>
+longlong TYPVAL<longlong>::MinMaxVal(bool b)
+ {return (b) ? INT_MAX64 : INT_MIN64;}
+
+template <>
+ulonglong TYPVAL<ulonglong>::MinMaxVal(bool b)
+ {return (b) ? 0xFFFFFFFFFFFFFFFFLL : 0;}
+
+template <>
+double TYPVAL<double>::MinMaxVal(bool)
+ {assert(false); return 0.0;}
+
+template <>
+char TYPVAL<char>::MinMaxVal(bool b)
+ {return (b) ? INT_MAX8 : INT_MIN8;}
+
+template <>
+uchar TYPVAL<uchar>::MinMaxVal(bool b)
+ {return (b) ? UINT_MAX8 : 0;}
+
+/***********************************************************************/
+/* SafeAdd: adds a value and test whether overflow/underflow occurred. */
+/***********************************************************************/
+template <class TYPE>
+TYPE TYPVAL<TYPE>::SafeAdd(TYPE n1, TYPE n2)
+{
+ PGLOBAL& g = Global;
+ TYPE n = n1 + n2;
+
+ if ((n2 > 0) && (n < n1)) {
+ // Overflow
+ strcpy(g->Message, MSG(FIX_OVFLW_ADD));
+ throw 138;
+ } else if ((n2 < 0) && (n > n1)) {
+ // Underflow
+ strcpy(g->Message, MSG(FIX_UNFLW_ADD));
+ throw 138;
+ } // endif's n2
+
+ return n;
+} // end of SafeAdd
+
+template <>
+inline double TYPVAL<double>::SafeAdd(double n1, double n2)
+{
+ return n1 + n2;
+} // end of SafeAdd
+
+/***********************************************************************/
+/* SafeMult: multiply values and test whether overflow occurred. */
+/***********************************************************************/
+template <class TYPE>
+TYPE TYPVAL<TYPE>::SafeMult(TYPE n1, TYPE n2)
+{
+ PGLOBAL& g = Global;
+ double n = (double)n1 * (double)n2;
+
+ if (n > MinMaxVal(true)) {
+ // Overflow
+ strcpy(g->Message, MSG(FIX_OVFLW_TIMES));
+ throw 138;
+ } else if (n < MinMaxVal(false)) {
+ // Underflow
+ strcpy(g->Message, MSG(FIX_UNFLW_TIMES));
+ throw 138;
+ } // endif's n2
+
+ return (TYPE)n;
+} // end of SafeMult
+
+template <>
+inline double TYPVAL<double>::SafeMult(double n1, double n2)
+{
+ return n1 * n2;
+} // end of SafeMult
+
+/***********************************************************************/
+/* Compute defined functions for the type. */
+/***********************************************************************/
+template <class TYPE>
+bool TYPVAL<TYPE>::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+{
+ bool rc = false;
+ TYPE val[2];
+
+ assert(np == 2);
+
+ for (int i = 0; i < np; i++)
+ val[i] = GetTypedValue(vp[i]);
+
+ switch (op) {
+ case OP_ADD:
+ Tval = SafeAdd(val[0], val[1]);
+ break;
+ case OP_MULT:
+ Tval = SafeMult(val[0], val[1]);
+ break;
+ case OP_DIV:
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Tval = val[0] / val[1];
+ break;
+ default:
+ rc = Compall(g, vp, np, op);
+ break;
+ } // endswitch op
+
+ return rc;
+} // end of Compute
+
+template <>
+bool TYPVAL<double>::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+{
+ bool rc = false;
+ double val[2];
+
+ assert(np == 2);
+
+ for (int i = 0; i < np; i++)
+ val[i] = vp[i]->GetFloatValue();
+
+ switch (op) {
+ case OP_ADD:
+ Tval = val[0] + val[1];
+ break;
+ case OP_MULT:
+ Tval = val[0] * val[1];
+ break;
+ default:
+ rc = Compall(g, vp, np, op);
+ } // endswitch op
+
+ return rc;
+} // end of Compute
+
+/***********************************************************************/
+/* Compute a function for all types. */
+/***********************************************************************/
+template <class TYPE>
+bool TYPVAL<TYPE>::Compall(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+{
+ TYPE val[2];
+
+ for (int i = 0; i < np; i++)
+ val[i] = GetTypedValue(vp[i]);
+
+ switch (op) {
+ case OP_DIV:
+ if (val[0]) {
+ if (!val[1]) {
+ strcpy(g->Message, MSG(ZERO_DIVIDE));
+ return true;
+ } // endif
+
+ Tval = val[0] / val[1];
+ } else
+ Tval = 0;
+
+ break;
+ case OP_MIN:
+ Tval = MY_MIN(val[0], val[1]);
+ break;
+ case OP_MAX:
+ Tval = MY_MAX(val[0], val[1]);
+ break;
+ default:
+// sprintf(g->Message, MSG(BAD_EXP_OPER), op);
+ strcpy(g->Message, "Function not supported");
+ return true;
+ } // endswitch op
+
+ return false;
+} // end of Compall
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+template <class TYPE>
+bool TYPVAL<TYPE>::FormatValue(PVAL vp, PCSZ fmt)
+{
+ // This function is wrong and should never be called
+ assert(false);
+ char *buf = (char*)vp->GetTo_Val(); // Not big enough
+ int n = sprintf(buf, fmt, Tval);
+
+ return (n > vp->GetValLen());
+} // end of FormatValue
+
+/***********************************************************************/
+/* TYPVAL SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+template <class TYPE>
+bool TYPVAL<TYPE>::SetConstFormat(PGLOBAL g, FORMAT& fmt)
+{
+ char c[32];
+
+ fmt.Type[0] = *GetFormatType(Type);
+ fmt.Length = sprintf(c, Fmt, Tval);
+ fmt.Prec = Prec;
+ return false;
+} // end of SetConstFormat
+
+/* -------------------------- Class STRING --------------------------- */
+
+/***********************************************************************/
+/* STRING public constructor from a constant string. */
+/***********************************************************************/
+TYPVAL<PSZ>::TYPVAL(PSZ s, short c) : VALUE(TYPE_STRING)
+{
+ Strp = s;
+ Len = strlen(s);
+ Clen = Len;
+ Ci = (c == 1);
+} // end of STRING constructor
+
+/***********************************************************************/
+/* STRING public constructor from char. */
+/***********************************************************************/
+TYPVAL<PSZ>::TYPVAL(PGLOBAL g, PSZ s, int n, int c)
+ : VALUE(TYPE_STRING)
+{
+ Len = (g) ? n : (s) ? strlen(s) : 0;
+
+ if (!s) {
+ if (g) {
+ if ((Strp = (char *)PlgDBSubAlloc(g, NULL, Len + 1)))
+ memset(Strp, 0, Len + 1);
+ else
+ Len = 0;
+
+ } else
+ assert(false);
+
+ } else
+ Strp = s;
+
+ Clen = Len;
+ Ci = (c != 0);
+} // end of STRING constructor
+
+/***********************************************************************/
+/* Get the tiny value represented by the Strp string. */
+/***********************************************************************/
+char TYPVAL<PSZ>::GetTinyValue(void)
+{
+ bool m;
+ ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX8, false, &m);
+
+ return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val;
+} // end of GetTinyValue
+
+/***********************************************************************/
+/* Get the unsigned tiny value represented by the Strp string. */
+/***********************************************************************/
+uchar TYPVAL<PSZ>::GetUTinyValue(void)
+{
+ return (uchar)CharToNumber(Strp, strlen(Strp), UINT_MAX8, true);
+} // end of GetUTinyValue
+
+/***********************************************************************/
+/* Get the short value represented by the Strp string. */
+/***********************************************************************/
+short TYPVAL<PSZ>::GetShortValue(void)
+{
+ bool m;
+ ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX16, false, &m);
+
+ return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val;
+} // end of GetShortValue
+
+/***********************************************************************/
+/* Get the unsigned short value represented by the Strp string. */
+/***********************************************************************/
+ushort TYPVAL<PSZ>::GetUShortValue(void)
+{
+ return (ushort)CharToNumber(Strp, strlen(Strp), UINT_MAX16, true);
+} // end of GetUshortValue
+
+/***********************************************************************/
+/* Get the integer value represented by the Strp string. */
+/***********************************************************************/
+int TYPVAL<PSZ>::GetIntValue(void)
+{
+ bool m;
+ ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX32, false, &m);
+
+ return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val;
+} // end of GetIntValue
+
+/***********************************************************************/
+/* Get the unsigned integer value represented by the Strp string. */
+/***********************************************************************/
+uint TYPVAL<PSZ>::GetUIntValue(void)
+{
+ return (uint)CharToNumber(Strp, strlen(Strp), UINT_MAX32, true);
+} // end of GetUintValue
+
+/***********************************************************************/
+/* Get the big integer value represented by the Strp string. */
+/***********************************************************************/
+longlong TYPVAL<PSZ>::GetBigintValue(void)
+{
+ bool m;
+ ulonglong val = CharToNumber(Strp, strlen(Strp), INT_MAX64, false, &m);
+
+ return (m && val < INT_MAX64) ? (-(signed)val) : (longlong)val;
+} // end of GetBigintValue
+
+/***********************************************************************/
+/* Get the unsigned big integer value represented by the Strp string. */
+/***********************************************************************/
+ulonglong TYPVAL<PSZ>::GetUBigintValue(void)
+{
+ return CharToNumber(Strp, strlen(Strp), ULONGLONG_MAX, true);
+} // end of GetUBigintValue
+
+/***********************************************************************/
+/* STRING SetValue: copy the value of another Value object. */
+/***********************************************************************/
+bool TYPVAL<PSZ>::SetValue_pval(PVAL valp, bool chktype)
+{
+ if (valp != this) {
+ if (chktype && (valp->GetType() != Type || valp->GetSize() > Len))
+ return true;
+
+ char buf[64];
+
+ if (!(Null = (valp->IsNull() && Nullable)))
+ strncpy(Strp, valp->GetCharString(buf), Len);
+ else
+ Reset();
+
+ } // endif valp
+
+ return false;
+} // end of SetValue_pval
+
+/***********************************************************************/
+/* STRING SetValue: fill string with chars extracted from a line. */
+/***********************************************************************/
+bool TYPVAL<PSZ>::SetValue_char(const char *cp, int n)
+{
+ bool rc = false;
+
+ if (!cp || n == 0) {
+ Reset();
+ Null = (cp) ? false : Nullable;
+ } else if (cp != Strp) {
+ const char *p = cp + n - 1;
+
+ for (; p >= cp; p--, n--)
+ if (*p && *p != ' ')
+ break;
+
+ rc = n > Len;
+
+ if ((n = MY_MIN(n, Len))) {
+ strncpy(Strp, cp, n);
+ Strp[n] = '\0';
+
+ if (trace(2))
+ htrc(" Setting string to: '%s'\n", Strp);
+
+ } else
+ Reset();
+
+ Null = false;
+ } // endif cp
+
+ return rc;
+} // end of SetValue_char
+
+/***********************************************************************/
+/* STRING SetValue: fill string with another string. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue_psz(PCSZ s)
+{
+ if (!s) {
+ Reset();
+ Null = Nullable;
+ } else if (s != Strp) {
+ strncpy(Strp, s, Len);
+ Null = false;
+ } // endif s
+
+} // end of SetValue_psz
+
+/***********************************************************************/
+/* STRING SetValue: fill string with a string extracted from a block. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue_pvblk(PVBLK blk, int n)
+{
+ // STRBLK's can return a NULL pointer
+ PSZ vp = blk->GetCharString(Strp, n);
+
+ if (vp != Strp)
+ SetValue_psz(vp);
+
+} // end of SetValue_pvblk
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of an integer. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(int n)
+{
+ char buf[16];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%d", n);
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ throw 138;
+ } else
+ SetValue_psz(buf);
+
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of an uint. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(uint n)
+{
+ char buf[16];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%u", n);
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ throw 138;
+ } else
+ SetValue_psz(buf);
+
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a short int. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(short i)
+{
+ SetValue((int)i);
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a ushort int. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(ushort i)
+{
+ SetValue((uint)i);
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a big integer.*/
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(longlong n)
+{
+ char buf[24];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%lld", n);
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ throw 138;
+ } else
+ SetValue_psz(buf);
+
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a big integer.*/
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(ulonglong n)
+{
+ char buf[24];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%llu", n);
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ throw 138;
+ } else
+ SetValue_psz(buf);
+
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a double. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(double f)
+{
+ char *p, buf[64];
+ PGLOBAL& g = Global;
+ int k = sprintf(buf, "%lf", f);
+
+ for (p = buf + k - 1; p >= buf; p--)
+ if (*p == '0') {
+ *p = 0;
+ k--;
+ } else
+ break;
+
+ if (k > Len) {
+ sprintf(g->Message, MSG(VALSTR_TOO_LONG), buf, Len);
+ throw 138;
+ } else
+ SetValue_psz(buf);
+
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a tiny int. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(char c)
+{
+ SetValue((int)c);
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetValue: get the character representation of a tiny int. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetValue(uchar c)
+{
+ SetValue((uint)c);
+ Null = false;
+} // end of SetValue
+
+/***********************************************************************/
+/* STRING SetBinValue: fill string with chars extracted from a line. */
+/***********************************************************************/
+void TYPVAL<PSZ>::SetBinValue(void *p)
+{
+ SetValue_char((const char *)p, Len);
+} // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool TYPVAL<PSZ>::GetBinValue(void *buf, int buflen, bool go)
+{
+ int len = (Null) ? 0 : strlen(Strp);
+
+ if (len > buflen)
+ return true;
+ else if (go) {
+ memset(buf, ' ', buflen);
+ memcpy(buf, Strp, len);
+ } // endif go
+
+ return false;
+} // end of GetBinValue
+
+/***********************************************************************/
+/* STRING ShowValue: get string representation of a char value. */
+/***********************************************************************/
+int TYPVAL<PSZ>::ShowValue(char *buf, int buflen)
+{
+ int len = (Null) ? 0 : strlen(Strp);
+
+ if (buf && buf != Strp) {
+ memset(buf, ' ', (size_t)buflen + 1);
+ memcpy(buf, Strp, MY_MIN(len, buflen));
+ } // endif buf
+
+ return len;
+} // end of ShowValue
+
+/***********************************************************************/
+/* STRING GetCharString: get string representation of a char value. */
+/***********************************************************************/
+char *TYPVAL<PSZ>::GetCharString(char *)
+{
+ return Strp;
+} // end of GetCharString
+
+/***********************************************************************/
+/* STRING compare value with another Value. */
+/***********************************************************************/
+bool TYPVAL<PSZ>::IsEqual(PVAL vp, bool chktype)
+{
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else if (Null || vp->IsNull())
+ return false;
+
+ char buf[64];
+
+ if (Ci || vp->IsCi())
+ return !stricmp(Strp, vp->GetCharString(buf));
+ else // (!Ci)
+ return !strcmp(Strp, vp->GetCharString(buf));
+
+} // end of IsEqual
+
+/***********************************************************************/
+/* Compare values and returns 1, 0 or -1 according to comparison. */
+/* This function is used for evaluation of numeric filters. */
+/***********************************************************************/
+int TYPVAL<PSZ>::CompareValue(PVAL vp)
+{
+ int n;
+//assert(vp->GetType() == Type);
+
+ if (trace(1))
+ htrc(" Comparing: val='%s','%s'\n", Strp, vp->GetCharValue());
+
+ // Process filtering on character strings.
+ if (Ci || vp->IsCi())
+ n = stricmp(Strp, vp->GetCharValue());
+ else
+ n = strcmp(Strp, vp->GetCharValue());
+
+#if defined(_WIN32)
+ if (n == _NLSCMPERROR)
+ return n; // Here we should raise an error
+#endif // _WIN32
+
+ return (n > 0) ? 1 : (n < 0) ? -1 : 0;
+} // end of CompareValue
+
+/***********************************************************************/
+/* Compute a function on a string. */
+/***********************************************************************/
+bool TYPVAL<PSZ>::Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op)
+{
+ char *p[2], val[2][32];
+ int i;
+
+ if (trace(1))
+ htrc("Compute: np=%d op=%d\n", np, op);
+
+ for (i = 0; i < np; i++)
+ if (!vp[i]->IsNull()) {
+ p[i] = vp[i]->GetCharString(val[i]);
+
+ if (trace(1))
+ htrc("p[%d]=%s\n", i, p[i]);
+
+ } else
+ return false;
+
+ switch (op) {
+ case OP_CNC:
+ assert(np == 1 || np == 2);
+
+ if (np == 2)
+ SetValue_psz(p[0]);
+
+ if ((i = Len - (signed)strlen(Strp)) > 0)
+ strncat(Strp, p[np - 1], i);
+
+ if (trace(1))
+ htrc("Strp=%s\n", Strp);
+
+ break;
+ case OP_MIN:
+ assert(np == 2);
+ SetValue_psz((strcmp(p[0], p[1]) < 0) ? p[0] : p[1]);
+ break;
+ case OP_MAX:
+ assert(np == 2);
+ SetValue_psz((strcmp(p[0], p[1]) > 0) ? p[0] : p[1]);
+ break;
+ default:
+ // sprintf(g->Message, MSG(BAD_EXP_OPER), op);
+ strcpy(g->Message, "Function not supported");
+ return true;
+ } // endswitch op
+
+ Null = false;
+ return false;
+} // end of Compute
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool TYPVAL<PSZ>::FormatValue(PVAL vp, PCSZ fmt)
+{
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ int n = sprintf(buf, fmt, Strp);
+
+ return (n > vp->GetValLen());
+} // end of FormatValue
+
+/***********************************************************************/
+/* STRING SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+bool TYPVAL<PSZ>::SetConstFormat(PGLOBAL, FORMAT& fmt)
+{
+ fmt.Type[0] = 'C';
+ fmt.Length = Len;
+ fmt.Prec = 0;
+ return false;
+} // end of SetConstFormat
+
+/***********************************************************************/
+/* Make string output of an object value. */
+/***********************************************************************/
+void TYPVAL<PSZ>::Prints(PGLOBAL g, char *ps, uint z)
+{
+ if (Null)
+ strncpy(ps, "null", z);
+ else
+ strcat(strncat(strncpy(ps, "\"", z), Strp, z-2), "\"");
+
+} // end of Prints
+
+/* -------------------------- Class DECIMAL -------------------------- */
+
+/***********************************************************************/
+/* DECIMAL public constructor from a constant string. */
+/***********************************************************************/
+DECVAL::DECVAL(PSZ s) : TYPVAL<PSZ>(s)
+{
+ if (s) {
+ char *p = strchr(Strp, '.');
+
+ Prec = (p) ? (int)(Len - (p - Strp)) : 0;
+ } // endif s
+
+ Type = TYPE_DECIM;
+} // end of DECVAL constructor
+
+/***********************************************************************/
+/* DECIMAL public constructor from char. */
+/***********************************************************************/
+DECVAL::DECVAL(PGLOBAL g, PSZ s, int n, int prec, bool uns)
+ : TYPVAL<PSZ>(g, s, n + (prec ? 1 : 0) + (uns ? 0 : 1), 0)
+{
+ Prec = prec;
+ Unsigned = uns;
+ Type = TYPE_DECIM;
+} // end of DECVAL constructor
+
+/***********************************************************************/
+/* DECIMAL: Check whether the numerica value is equal to 0. */
+/***********************************************************************/
+bool DECVAL::IsZero(void)
+{
+ for (int i = 0; Strp[i]; i++)
+ if (!strchr("0 +-.", Strp[i]))
+ return false;
+
+ return true;
+} // end of IsZero
+
+/***********************************************************************/
+/* DECIMAL: Reset value to zero. */
+/***********************************************************************/
+void DECVAL::Reset(void)
+{
+ int i = 0;
+
+ Strp[i++] = '0';
+
+ if (Prec) {
+ Strp[i++] = '.';
+
+ do {
+ Strp[i++] = '0';
+ } while (i < Prec + 2);
+
+ } // endif Prec
+
+ Strp[i] = 0;
+} // end of Reset
+
+/***********************************************************************/
+/* DECIMAL ShowValue: get string representation right justified. */
+/***********************************************************************/
+int DECVAL::ShowValue(char *buf, int len)
+{
+ return snprintf(buf, len + 1, Xfmt, len, Strp);
+} // end of ShowValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool DECVAL::GetBinValue(void *buf, int buflen, bool go)
+{
+ int len = (Null) ? 0 : strlen(Strp);
+
+ if (len > buflen)
+ return true;
+ else if (go) {
+ memset(buf, ' ', buflen - len);
+ memcpy((char*)buf + buflen - len, Strp, len);
+ } // endif go
+
+ return false;
+} // end of GetBinValue
+
+/***********************************************************************/
+/* DECIMAL compare value with another Value. */
+/***********************************************************************/
+bool DECVAL::IsEqual(PVAL vp, bool chktype)
+{
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else if (Null || vp->IsNull())
+ return false;
+
+ char buf[64];
+
+ return !strcmp(Strp, vp->GetCharString(buf));
+} // end of IsEqual
+
+/***********************************************************************/
+/* Compare values and returns 1, 0 or -1 according to comparison. */
+/* This function is used for evaluation of numeric filters. */
+/***********************************************************************/
+int DECVAL::CompareValue(PVAL vp)
+{
+//assert(vp->GetType() == Type);
+
+ // Process filtering on numeric values.
+ double f = atof(Strp), n = vp->GetFloatValue();
+
+//if (trace(1))
+// htrc(" Comparing: val=%d,%d\n", f, n);
+
+ return (f > n) ? 1 : (f < n) ? (-1) : 0;
+} // end of CompareValue
+
+/* -------------------------- Class BINVAL --------------------------- */
+
+/***********************************************************************/
+/* BINVAL public constructor from bytes. */
+/***********************************************************************/
+BINVAL::BINVAL(PGLOBAL g, void *p, int cl, int n) : VALUE(TYPE_BIN)
+{
+ assert(g);
+ Len = n;
+ Clen = cl;
+ Binp = PlugSubAlloc(g, NULL, Clen + 1);
+ memset(Binp, 0, Clen + 1);
+
+ if (p)
+ memcpy(Binp, p, MY_MIN(Len,Clen));
+
+ Chrp = NULL;
+} // end of BINVAL constructor
+
+/***********************************************************************/
+/* BINVAL: Check whether the hexadecimal value is equal to 0. */
+/***********************************************************************/
+bool BINVAL::IsZero(void)
+{
+ for (int i = 0; i < Len; i++)
+ if (((char*)Binp)[i] != 0)
+ return false;
+
+ return true;
+} // end of IsZero
+
+/***********************************************************************/
+/* BINVAL: Reset value to zero. */
+/***********************************************************************/
+void BINVAL::Reset(void)
+{
+ memset(Binp, 0, Clen);
+ Len = 0;
+} // end of Reset
+
+/***********************************************************************/
+/* Get the tiny value pointed by Binp. */
+/***********************************************************************/
+char BINVAL::GetTinyValue(void)
+{
+ return *(char*)Binp;
+} // end of GetTinyValue
+
+/***********************************************************************/
+/* Get the unsigned tiny value pointed by Binp. */
+/***********************************************************************/
+uchar BINVAL::GetUTinyValue(void)
+{
+ return *(uchar*)Binp;
+} // end of GetUTinyValue
+
+/***********************************************************************/
+/* Get the short value pointed by Binp. */
+/***********************************************************************/
+short BINVAL::GetShortValue(void)
+{
+ if (Len >= 2)
+ return *(short*)Binp;
+ else
+ return (short)GetTinyValue();
+
+} // end of GetShortValue
+
+/***********************************************************************/
+/* Get the unsigned short value pointed by Binp. */
+/***********************************************************************/
+ushort BINVAL::GetUShortValue(void)
+{
+ return (ushort)GetShortValue();
+} // end of GetUshortValue
+
+/***********************************************************************/
+/* Get the integer value pointed by Binp. */
+/***********************************************************************/
+int BINVAL::GetIntValue(void)
+{
+ if (Len >= 4)
+ return *(int*)Binp;
+ else
+ return (int)GetShortValue();
+
+} // end of GetIntValue
+
+/***********************************************************************/
+/* Get the unsigned integer value pointed by Binp. */
+/***********************************************************************/
+uint BINVAL::GetUIntValue(void)
+{
+ return (uint)GetIntValue();
+} // end of GetUintValue
+
+/***********************************************************************/
+/* Get the big integer value pointed by Binp. */
+/***********************************************************************/
+longlong BINVAL::GetBigintValue(void)
+{
+ if (Len >= 8)
+ return *(longlong*)Binp;
+ else
+ return (longlong)GetIntValue();
+
+} // end of GetBigintValue
+
+/***********************************************************************/
+/* Get the unsigned big integer value pointed by Binp. */
+/***********************************************************************/
+ulonglong BINVAL::GetUBigintValue(void)
+{
+ return (ulonglong)GetBigintValue();
+} // end of GetUBigintValue
+
+/***********************************************************************/
+/* Get the double value pointed by Binp. */
+/***********************************************************************/
+double BINVAL::GetFloatValue(void)
+{
+ if (Len >= 8)
+ return *(double*)Binp;
+ else if (Len >= 4)
+ return (double)(*(float*)Binp);
+ else
+ return 0.0;
+
+} // end of GetFloatValue
+
+/***********************************************************************/
+/* BINVAL SetValue: copy the value of another Value object. */
+/***********************************************************************/
+bool BINVAL::SetValue_pval(PVAL valp, bool chktype)
+{
+ bool rc = false;
+
+ if (valp != this) {
+ if (chktype && (valp->GetType() != Type || valp->GetSize() > Clen))
+ return true;
+
+ if (!(Null = valp->IsNull() && Nullable)) {
+ int len = Len;
+
+ if ((rc = (Len = valp->GetSize()) > Clen))
+ Len = Clen;
+ else if (len > Len)
+ memset(Binp, 0, len);
+
+ memcpy(Binp, valp->GetTo_Val(), Len);
+ ((char*)Binp)[Len] = 0;
+ } else
+ Reset();
+
+ } // endif valp
+
+ return rc;
+} // end of SetValue_pval
+
+/***********************************************************************/
+/* BINVAL SetValue: fill value with chars extracted from a line. */
+/***********************************************************************/
+bool BINVAL::SetValue_char(const char *p, int n)
+{
+ bool rc;
+
+ if (p && n > 0) {
+ int len = Len;
+
+ if (len > (Len = MY_MIN(n, Clen)))
+ memset(Binp, 0, len);
+
+ memcpy(Binp, p, Len);
+ ((char*)Binp)[Len] = 0;
+ rc = n > Clen;
+ Null = false;
+ } else {
+ rc = false;
+ Reset();
+ Null = Nullable;
+ } // endif p
+
+ return rc;
+} // end of SetValue_char
+
+/***********************************************************************/
+/* BINVAL SetValue: fill value with another string. */
+/***********************************************************************/
+void BINVAL::SetValue_psz(PCSZ s)
+{
+ if (s) {
+ int len = Len;
+
+ if (len > (Len = MY_MIN(Clen, (signed)strlen(s))))
+ memset(Binp, 0, len);
+
+ memcpy(Binp, s, Len);
+ ((char*)Binp)[Len] = 0;
+ Null = false;
+ } else {
+ Reset();
+ Null = Nullable;
+ } // endif s
+
+} // end of SetValue_psz
+
+/***********************************************************************/
+/* BINVAL SetValue: fill value with bytes extracted from a block. */
+/***********************************************************************/
+void BINVAL::SetValue_pvblk(PVBLK blk, int n)
+{
+ // STRBLK's can return a NULL pointer
+ void *vp = blk->GetValPtrEx(n);
+
+ if (!vp || blk->IsNull(n)) {
+ Reset();
+ Null = Nullable;
+ } else if (vp != Binp) {
+ int len = Len;
+
+ if (blk->GetType() == TYPE_STRING)
+ Len = strlen((char*)vp);
+ else
+ Len = blk->GetVlen();
+
+ if (len > (Len = MY_MIN(Clen, Len)))
+ memset(Binp, 0, len);
+
+ memcpy(Binp, vp, Len);
+ ((char*)Binp)[Len] = 0;
+ Null = false;
+ } // endif vp
+
+} // end of SetValue_pvblk
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of an integer. */
+/***********************************************************************/
+void BINVAL::SetValue(int n)
+{
+ if (Clen >= 4) {
+ if (Len > 4)
+ memset(Binp, 0, Len);
+
+ *((int*)Binp) = n;
+ Len = 4;
+ } else
+ SetValue((short)n);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of an uint. */
+/***********************************************************************/
+void BINVAL::SetValue(uint n)
+{
+ if (Clen >= 4) {
+ if (Len > 4)
+ memset(Binp, 0, Len);
+
+ *((uint*)Binp) = n;
+ Len = 4;
+ } else
+ SetValue((ushort)n);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a short int. */
+/***********************************************************************/
+void BINVAL::SetValue(short i)
+{
+ if (Clen >= 2) {
+ if (Len > 2)
+ memset(Binp, 0, Len);
+
+ *((int*)Binp) = i;
+ Len = 2;
+ } else
+ SetValue((char)i);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a ushort int. */
+/***********************************************************************/
+void BINVAL::SetValue(ushort i)
+{
+ if (Clen >= 2) {
+ if (Len > 2)
+ memset(Binp, 0, Len);
+
+ *((uint*)Binp) = i;
+ Len = 2;
+ } else
+ SetValue((uchar)i);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a big integer. */
+/***********************************************************************/
+void BINVAL::SetValue(longlong n)
+{
+ if (Clen >= 8) {
+ if (Len > 8)
+ memset(Binp, 0, Len);
+
+ *((longlong*)Binp) = n;
+ Len = 8;
+ } else
+ SetValue((int)n);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a big integer. */
+/***********************************************************************/
+void BINVAL::SetValue(ulonglong n)
+{
+ if (Clen >= 8) {
+ if (Len > 8)
+ memset(Binp, 0, Len);
+
+ *((ulonglong*)Binp) = n;
+ Len = 8;
+ } else
+ SetValue((uint)n);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a double. */
+/***********************************************************************/
+void BINVAL::SetValue(double n)
+{
+ if (Len > 8)
+ memset(Binp, 0, Len);
+
+ if (Clen >= 8) {
+ *((double*)Binp) = n;
+ Len = 8;
+ } else if (Clen >= 4) {
+ *((float*)Binp) = (float)n;
+ Len = 4;
+ } else
+ Len = 0;
+
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the character binary of a tiny int. */
+/***********************************************************************/
+void BINVAL::SetValue(char c)
+{
+ if (Len > 1)
+ memset(Binp, 0, Len);
+
+ *((char*)Binp) = c;
+ Len = 1;
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetValue: get the binary representation of a tiny int. */
+/***********************************************************************/
+void BINVAL::SetValue(uchar c)
+{
+ if (Len > 1)
+ memset(Binp, 0, Len);
+
+ *((uchar*)Binp) = c;
+ Len = 1;
+} // end of SetValue
+
+/***********************************************************************/
+/* BINVAL SetBinValue: fill string with bytes extracted from a line. */
+/***********************************************************************/
+void BINVAL::SetBinValue(void *p)
+{
+ memcpy(Binp, p, Clen);
+ Len = Clen;
+} // end of SetBinValue
+
+/***********************************************************************/
+/* BINVAL SetBinValue: fill string with len bytes. */
+/***********************************************************************/
+void BINVAL::SetBinValue(void* p, ulong len)
+{
+ memcpy(Binp, p, len);
+ Len = len;
+} // end of SetBinValue
+
+/***********************************************************************/
+/* GetBinValue: fill a buffer with the internal binary value. */
+/* This function checks whether the buffer length is enough and */
+/* returns true if not. Actual filling occurs only if go is true. */
+/* Currently used by WriteColumn of binary files. */
+/***********************************************************************/
+bool BINVAL::GetBinValue(void *buf, int buflen, bool go)
+{
+ if (Len > buflen)
+ return true;
+ else if (go) {
+ memset(buf, 0, buflen);
+ memcpy(buf, Binp, Len);
+ } // endif go
+
+ return false;
+} // end of GetBinValue
+
+/***********************************************************************/
+/* BINVAL ShowValue: get string representation of a binary value. */
+/***********************************************************************/
+int BINVAL::ShowValue(char *buf, int len)
+{
+ memset(buf, 0, len + 1);
+ memcpy(buf, Binp, MY_MIN(len, Len));
+ return Len;
+} // end of ShowValue
+
+/***********************************************************************/
+/* BINVAL GetCharString: get string representation of a binary value. */
+/***********************************************************************/
+char *BINVAL::GetCharString(char *)
+{
+ if (!Chrp)
+ Chrp = (char*)PlugSubAlloc(Global, NULL, Clen * 2 + 1);
+
+ sprintf(Chrp, GetXfmt(), Len, Binp);
+ return Chrp;
+} // end of GetCharString
+
+/***********************************************************************/
+/* BINVAL compare value with another Value. */
+/***********************************************************************/
+bool BINVAL::IsEqual(PVAL vp, bool chktype)
+{
+ if (this == vp)
+ return true;
+ else if (chktype && Type != vp->GetType())
+ return false;
+ else if (Null || vp->IsNull())
+ return false;
+ else if (Len != vp->GetSize())
+ return false;
+
+ char *v1 = (char*)Binp;
+ char *v2 = (char*)vp->GetTo_Val();
+
+ for (int i = 0; i < Len; i++)
+ if (v1[i] != v2[i])
+ return false;
+
+ return true;
+} // end of IsEqual
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool BINVAL::FormatValue(PVAL vp, PCSZ fmt)
+{
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ int n = sprintf(buf, fmt, Len, Binp);
+
+ return (n > vp->GetValLen());
+} // end of FormatValue
+
+/***********************************************************************/
+/* BINVAL SetFormat function (used to set SELECT output format). */
+/***********************************************************************/
+bool BINVAL::SetConstFormat(PGLOBAL, FORMAT& fmt)
+{
+ fmt.Type[0] = 'B';
+ fmt.Length = Clen;
+ fmt.Prec = 0;
+ return false;
+} // end of SetConstFormat
+
+/* -------------------------- Class DTVAL ---------------------------- */
+
+/***********************************************************************/
+/* DTVAL public constructor for new void values. */
+/***********************************************************************/
+DTVAL::DTVAL(PGLOBAL g, int n, int prec, PCSZ fmt)
+ : TYPVAL<int>((int)0, TYPE_DATE)
+{
+ if (!fmt) {
+ Pdtp = NULL;
+ Sdate = NULL;
+ DefYear = 0;
+ Len = n;
+ } else
+ SetFormat(g, fmt, n, prec);
+
+//Type = TYPE_DATE;
+} // end of DTVAL constructor
+
+/***********************************************************************/
+/* DTVAL public constructor from int. */
+/***********************************************************************/
+DTVAL::DTVAL(int n) : TYPVAL<int>(n, TYPE_DATE)
+{
+ Pdtp = NULL;
+ Len = 19;
+//Type = TYPE_DATE;
+ Sdate = NULL;
+ DefYear = 0;
+} // end of DTVAL constructor
+
+/***********************************************************************/
+/* Set format so formatted dates can be converted on input/output. */
+/***********************************************************************/
+bool DTVAL::SetFormat(PGLOBAL g, PCSZ fmt, int len, int year)
+{
+ Pdtp = MakeDateFormat(g, fmt, true, true, (year > 9999) ? 1 : 0);
+ Sdate = (char*)PlugSubAlloc(g, NULL, len + 1);
+ DefYear = (int)((year > 9999) ? (year - 10000) : year);
+ Len = len;
+ return false;
+} // end of SetFormat
+
+/***********************************************************************/
+/* Set format from the format of another date value. */
+/***********************************************************************/
+bool DTVAL::SetFormat(PGLOBAL g, PVAL valp)
+{
+ DTVAL *vp;
+
+ if (valp->GetType() != TYPE_DATE) {
+ sprintf(g->Message, MSG(NO_FORMAT_TYPE), valp->GetType());
+ return true;
+ } else
+ vp = (DTVAL*)valp;
+
+ Len = vp->Len;
+ Pdtp = vp->Pdtp;
+ Sdate = (char*)PlugSubAlloc(g, NULL, Len + 1);
+ DefYear = vp->DefYear;
+ return false;
+} // end of SetFormat
+
+/***********************************************************************/
+/* We need TimeShift because the mktime C function does a correction */
+/* for local time zone that we want to override for DB operations. */
+/***********************************************************************/
+void DTVAL::SetTimeShift(void)
+{
+ struct tm dtm;
+ memset(&dtm, 0, sizeof(dtm));
+ dtm.tm_mday=2;
+ dtm.tm_mon=0;
+ dtm.tm_year=70;
+
+ Shift = (int)mktime(&dtm) - 86400;
+
+ if (trace(1))
+ htrc("DTVAL Shift=%d\n", Shift);
+
+} // end of SetTimeShift
+
+// Added by Alexander Barkov
+static void TIME_to_localtime(struct tm *tm, const MYSQL_TIME *ltime)
+{
+ bzero(tm, sizeof(*tm));
+ tm->tm_year= ltime->year - 1900;
+ tm->tm_mon= ltime->month - 1;
+ tm->tm_mday= ltime->day;
+ mktime(tm); // set tm->tm_wday tm->yday fields to get proper day name (OB)
+ tm->tm_hour= ltime->hour;
+ tm->tm_min= ltime->minute;
+ tm->tm_sec= ltime->second;
+} // end of TIME_to_localtime
+
+// Added by Alexander Barkov
+static struct tm *gmtime_mysql(const time_t *timep, struct tm *tm)
+{
+ MYSQL_TIME ltime;
+ thd_gmt_sec_to_TIME(current_thd, &ltime, (my_time_t) *timep);
+ TIME_to_localtime(tm, &ltime);
+ return tm;
+} // end of gmtime_mysql
+
+/***********************************************************************/
+/* GetGmTime: returns a pointer to a static tm structure obtained */
+/* though the gmtime C function. The purpose of this function is to */
+/* extend the range of valid dates by accepting negative time values. */
+/***********************************************************************/
+struct tm *DTVAL::GetGmTime(struct tm *tm_buffer)
+{
+ struct tm *datm;
+ time_t t = (time_t)Tval;
+
+ if (Tval < 0) {
+ int n;
+
+ for (n = 0; t < 0; n += 4)
+ t += FOURYEARS;
+
+ datm = gmtime_mysql(&t, tm_buffer);
+
+ if (datm)
+ datm->tm_year -= n;
+
+ } else
+ datm = gmtime_mysql(&t, tm_buffer);
+
+ return datm;
+} // end of GetGmTime
+
+// Added by Alexander Barkov
+static time_t mktime_mysql(struct tm *ptm)
+{
+ MYSQL_TIME ltime;
+ localtime_to_TIME(&ltime, ptm);
+ ltime.time_type= MYSQL_TIMESTAMP_DATETIME;
+ uint error_code;
+ time_t t= TIME_to_timestamp(current_thd, &ltime, &error_code);
+ return error_code ? (time_t) -1 : t;
+}
+
+/***********************************************************************/
+/* MakeTime: calculates a date value from a tm structures using the */
+/* mktime C function. The purpose of this function is to extend the */
+/* range of valid dates by accepting to set negative time values. */
+/***********************************************************************/
+bool DTVAL::MakeTime(struct tm *ptm)
+{
+ int n, y = ptm->tm_year;
+ time_t t = mktime_mysql(ptm);
+
+ if (trace(2))
+ htrc("MakeTime from (%d,%d,%d,%d,%d,%d)\n",
+ ptm->tm_year, ptm->tm_mon, ptm->tm_mday,
+ ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
+
+ if (t == -1) {
+ if (y < 1 || y > 71)
+ return true;
+
+ for (n = 0; t == -1 && n < 20; n++) {
+ ptm->tm_year += 4;
+ t = mktime_mysql(ptm);
+ } // endfor t
+
+ if (t == -1)
+ return true;
+
+ if ((t -= (n * FOURYEARS)) > 2000000000)
+ return true;
+
+ } // endif t
+
+ Tval= (int) t;
+
+ if (trace(2))
+ htrc("MakeTime Ival=%d\n", Tval);
+
+ return false;
+} // end of MakeTime
+
+/***********************************************************************/
+/* Make a time_t datetime from its components (YY, MM, DD, hh, mm, ss) */
+/***********************************************************************/
+bool DTVAL::MakeDate(PGLOBAL g, int *val, int nval)
+{
+ int i, m;
+ int n;
+ bool rc = false;
+ struct tm datm;
+ bzero(&datm, sizeof(datm));
+ datm.tm_mday=1;
+ datm.tm_mon=0;
+ datm.tm_year=70;
+
+ if (trace(2))
+ htrc("MakeDate from(%d,%d,%d,%d,%d,%d) nval=%d\n",
+ val[0], val[1], val[2], val[3], val[4], val[5], nval);
+
+ for (i = 0; i < nval; i++) {
+ n = val[i];
+
+// if (trace(2))
+// htrc("i=%d n=%d\n", i, n);
+
+ switch (i) {
+ case 0:
+ if (n >= 1900)
+ n -= 1900;
+
+ datm.tm_year = n;
+
+// if (trace(2))
+// htrc("n=%d tm_year=%d\n", n, datm.tm_year);
+
+ break;
+ case 1:
+ // If mktime handles apparently correctly large or negative
+ // day values, it is not the same for months. Therefore we
+ // do the ajustment here, thus mktime has not to do it.
+ if (n > 0) {
+ m = (n - 1) % 12;
+ n = (n - 1) / 12;
+ } else {
+ m = 11 + n % 12;
+ n = n / 12 - 1;
+ } // endfi n
+
+ datm.tm_mon = m;
+ datm.tm_year += n;
+
+// if (trace(2))
+// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon);
+
+ break;
+ case 2:
+ // For days, big or negative values may also cause problems
+ m = n % 1461;
+ n = 4 * (n / 1461);
+
+ if (m < 0) {
+ m += 1461;
+ n -= 4;
+ } // endif m
+
+ datm.tm_mday = m;
+ datm.tm_year += n;
+
+// if (trace(2))
+// htrc("n=%d m=%d tm_year=%d tm_mon=%d\n", n, m, datm.tm_year, datm.tm_mon);
+
+ break;
+ case 3: datm.tm_hour = n; break;
+ case 4: datm.tm_min = n; break;
+ case 5: datm.tm_sec = n; break;
+ } // endswitch i
+
+ } // endfor i
+
+ if (trace(2))
+ htrc("MakeDate datm=(%d,%d,%d,%d,%d,%d)\n",
+ datm.tm_year, datm.tm_mon, datm.tm_mday,
+ datm.tm_hour, datm.tm_min, datm.tm_sec);
+
+ // Pass g to have an error return or NULL to set invalid dates to 0
+ if (MakeTime(&datm))
+ {
+ if (g) {
+ strcpy(g->Message, MSG(BAD_DATETIME));
+ rc = true;
+ } else
+ Tval = 0;
+ }
+ return rc;
+} // end of MakeDate
+
+/***********************************************************************/
+/* DTVAL SetValue: copy the value of another Value object. */
+/* This function allows conversion if chktype is false. */
+/***********************************************************************/
+bool DTVAL::SetValue_pval(PVAL valp, bool chktype)
+{
+ if (valp != this) {
+ if (chktype && Type != valp->GetType())
+ return true;
+
+ if (!(Null = valp->IsNull() && Nullable)) {
+ if (Pdtp && !valp->IsTypeNum()) {
+ int ndv;
+ int dval[6];
+
+ ndv = ExtractDate(valp->GetCharValue(), Pdtp, DefYear, dval);
+ MakeDate(NULL, dval, ndv);
+ } else if (valp->GetType() == TYPE_BIGINT &&
+ !(valp->GetBigintValue() % 1000)) {
+ // Assuming that this timestamp is in milliseconds
+ SetValue((int)(valp->GetBigintValue() / 1000));
+ } else
+ SetValue(valp->GetIntValue());
+
+ } else
+ Reset();
+
+ } // endif valp
+
+ return false;
+} // end of SetValue
+
+/***********************************************************************/
+/* SetValue: convert chars extracted from a line to date value. */
+/***********************************************************************/
+bool DTVAL::SetValue_char(const char *p, int n)
+{
+ bool rc= 0;
+
+ if (Pdtp) {
+ const char *p2;
+ int ndv;
+ int dval[6];
+
+ if (n > 0) {
+ // Trim trailing blanks
+ for (p2 = p + n -1; p < p2 && *p2 == ' '; p2--);
+
+ if ((rc = (n = (int)(p2 - p + 1)) > Len))
+ n = Len;
+
+ memcpy(Sdate, p, n);
+ } // endif n
+
+ Sdate[n] = '\0';
+
+ ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
+ MakeDate(NULL, dval, ndv);
+
+ if (trace(2))
+ htrc(" setting date: '%s' -> %d\n", Sdate, Tval);
+
+ Null = (Nullable && ndv == 0);
+ } else {
+ rc = TYPVAL<int>::SetValue_char(p, n);
+ Null = (Nullable && Tval == 0);
+ } // endif Pdtp
+
+ return rc;
+} // end of SetValue
+
+/***********************************************************************/
+/* SetValue: convert a char string to date value. */
+/***********************************************************************/
+void DTVAL::SetValue_psz(PCSZ p)
+{
+ if (Pdtp) {
+ int ndv;
+ int dval[6];
+
+ strncpy(Sdate, p, Len);
+ Sdate[Len] = '\0';
+
+ ndv = ExtractDate(Sdate, Pdtp, DefYear, dval);
+ MakeDate(NULL, dval, ndv);
+
+ if (trace(2))
+ htrc(" setting date: '%s' -> %d\n", Sdate, Tval);
+
+ Null = (Nullable && ndv == 0);
+ } else {
+ TYPVAL<int>::SetValue_psz(p);
+ Null = (Nullable && Tval == 0);
+ } // endif Pdtp
+
+} // end of SetValue
+
+/***********************************************************************/
+/* DTVAL SetValue: set value with a value extracted from a block. */
+/***********************************************************************/
+void DTVAL::SetValue_pvblk(PVBLK blk, int n)
+{
+ if (Pdtp && !::IsTypeNum(blk->GetType())) {
+ int ndv;
+ int dval[6];
+
+ ndv = ExtractDate(blk->GetCharValue(n), Pdtp, DefYear, dval);
+ MakeDate(NULL, dval, ndv);
+ } else
+ Tval = blk->GetIntValue(n);
+
+} // end of SetValue
+
+/***********************************************************************/
+/* DTVAL SetValue: get date as an integer. */
+/***********************************************************************/
+void DTVAL::SetValue(int n)
+{
+ Tval = n;
+
+ if (Pdtp) {
+ size_t slen = (size_t)Len + 1;
+ struct tm tm, *ptm= GetGmTime(&tm);
+
+ if (ptm)
+ strftime(Sdate, slen, Pdtp->OutFmt, ptm);
+
+ } // endif Pdtp
+
+} // end of SetValue
+
+/***********************************************************************/
+/* DTVAL GetCharString: get string representation of a date value. */
+/***********************************************************************/
+char *DTVAL::GetCharString(char *p)
+{
+ if (Pdtp) {
+ size_t n = 0, slen = (size_t)Len + 1;
+ struct tm tm, *ptm= GetGmTime(&tm);
+
+ if (ptm)
+ n = strftime(Sdate, slen, Pdtp->OutFmt, ptm);
+
+ if (!n) {
+ *Sdate = '\0';
+ strncat(Sdate, "Error", slen);
+ } // endif n
+
+ return Sdate;
+ } else
+ sprintf(p, "%d", Tval);
+
+//Null = false; ??????????????
+ return p;
+} // end of GetCharString
+
+/***********************************************************************/
+/* DTVAL ShowValue: get string representation of a date value. */
+/***********************************************************************/
+int DTVAL::ShowValue(char *buf, int len)
+{
+ int rv = 0;
+
+ if (Pdtp) {
+ if (!Null) {
+ size_t n = 0, m = len + 1;
+ struct tm tm, *ptm = GetGmTime(&tm);
+
+ if (ptm)
+ n = strftime(buf, m, Pdtp->OutFmt, ptm);
+
+ if (!n) {
+ *buf = '\0';
+ strncat(buf, "Error", m);
+ rv = 5;
+ } else
+ rv = (int)n;
+
+ } else
+ *buf = '\0'; // DEFAULT VALUE ???
+
+ } else
+ rv = TYPVAL<int>::ShowValue(buf, len);
+
+ return rv;
+} // end of ShowValue
+
+#if 0 // Not used by CONNECT
+/***********************************************************************/
+/* Returns a member of the struct tm representation of the date. */
+/***********************************************************************/
+bool DTVAL::GetTmMember(OPVAL op, int& mval)
+{
+ bool rc = false;
+ struct tm tm, *ptm = GetGmTime(&tm);
+
+ switch (op) {
+ case OP_MDAY: mval = ptm->tm_mday; break;
+ case OP_MONTH: mval = ptm->tm_mon + 1; break;
+ case OP_YEAR: mval = ptm->tm_year + 1900; break;
+ case OP_WDAY: mval = ptm->tm_wday + 1; break;
+ case OP_YDAY: mval = ptm->tm_yday + 1; break;
+ case OP_QUART: mval = ptm->tm_mon / 3 + 1; break;
+ default:
+ rc = true;
+ } // endswitch op
+
+ return rc;
+} // end of GetTmMember
+
+/***********************************************************************/
+/* Calculates the week number of the year for the internal date value.*/
+/* The International Standard ISO 8601 has decreed that Monday shall */
+/* be the first day of the week. A week that lies partly in one year */
+/* and partly in another is assigned a number in the year in which */
+/* most of its days lie. That means that week number 1 of any year is */
+/* the week that contains the January 4th. */
+/***********************************************************************/
+bool DTVAL::WeekNum(PGLOBAL g, int& nval)
+{
+ // w is the start of the week SUN=0, MON=1, etc.
+ int m, n, w = nval % 7;
+ struct tm tm, *ptm = GetGmTime(&tm);
+
+ // Which day is January 4th of this year?
+ m = (367 + ptm->tm_wday - ptm->tm_yday) % 7;
+
+ // When does the first week begins?
+ n = 3 - (7 + m - w) % 7;
+
+ // Now calculate the week number
+ if (!(nval = (7 + ptm->tm_yday - n) / 7))
+ nval = 52;
+
+ // Everything should be Ok
+ return false;
+} // end of WeekNum
+#endif // 0
+
+/***********************************************************************/
+/* FormatValue: This function set vp (a STRING value) to the string */
+/* constructed from its own value formated using the fmt format. */
+/* This function assumes that the format matches the value type. */
+/***********************************************************************/
+bool DTVAL::FormatValue(PVAL vp, PCSZ fmt)
+{
+ char *buf = (char*)vp->GetTo_Val(); // Should be big enough
+ struct tm tm, *ptm = GetGmTime(&tm);
+
+ if (trace(2))
+ htrc("FormatValue: ptm=%p len=%d\n", ptm, vp->GetValLen());
+
+ if (ptm) {
+ size_t n = strftime(buf, vp->GetValLen(), fmt, ptm);
+
+ if (trace(2))
+ htrc("strftime: n=%d buf=%s\n", n, (n) ? buf : "???");
+
+ return (n == 0);
+ } else
+ return true;
+
+} // end of FormatValue
+
+/* -------------------------- End of Value --------------------------- */
diff --git a/storage/connect/value.h b/storage/connect/value.h
new file mode 100644
index 00000000..a0d94734
--- /dev/null
+++ b/storage/connect/value.h
@@ -0,0 +1,451 @@
+/**************** Value H Declares Source Code File (.H) ***************/
+/* Name: VALUE.H Version 2.4 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2001-2019 */
+/* */
+/* This file contains the VALUE and derived classes declares. */
+/***********************************************************************/
+#ifndef __VALUE__H__
+#define __VALUE__H__
+
+/***********************************************************************/
+/* Include required application header files */
+/* assert.h is header required when using the assert function. */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#include "assert.h"
+#include "block.h"
+
+/***********************************************************************/
+/* This should list the processors accepting unaligned numeral values.*/
+/***********************************************************************/
+#if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(_M_IA64)
+#define UNALIGNED_OK
+#endif
+
+/***********************************************************************/
+/* Types used in some class definitions. */
+/***********************************************************************/
+enum CONV {CNV_ANY = 0, /* Convert to any type */
+ CNV_CHAR = 1, /* Convert to character type */
+ CNV_NUM = 2}; /* Convert to numeric type */
+
+/***********************************************************************/
+/* Types used in some class definitions. */
+/***********************************************************************/
+class CONSTANT; // For friend setting
+typedef struct _datpar *PDTP; // For DTVAL
+
+/***********************************************************************/
+/* Utilities used to test types and to allocated values. */
+/***********************************************************************/
+// Exported functions
+DllExport PCSZ GetTypeName(int);
+DllExport int GetTypeSize(int, int);
+#ifdef ODBC_SUPPORT
+/* This function is exported for use in OEM table type DLLs */
+DllExport int TranslateSQLType(int stp, int prec,
+ int& len, char& v, bool& w);
+#endif
+DllExport const char *GetFormatType(int);
+DllExport int GetFormatType(char);
+DllExport bool IsTypeChar(int type);
+DllExport bool IsTypeNum(int type);
+DllExport int ConvertType(int, int, CONV, bool match = false);
+DllExport PVAL AllocateValue(PGLOBAL, void *, short, short = 2);
+DllExport PVAL AllocateValue(PGLOBAL, PVAL, int = TYPE_VOID, int = 0);
+DllExport PVAL AllocateValue(PGLOBAL, int, int len = 0, int prec = 0,
+ bool uns = false, PCSZ fmt = NULL);
+DllExport ulonglong CharToNumber(PCSZ, int, ulonglong, bool,
+ bool *minus = NULL, bool *rc = NULL);
+DllExport BYTE OpBmp(PGLOBAL g, OPVAL opc);
+
+/***********************************************************************/
+/* Class VALUE represents a constant or variable of any valid type. */
+/***********************************************************************/
+class DllExport VALUE : public BLOCK {
+ friend class CONSTANT; // The only object allowed to use SetConstFormat
+ friend class SWAP; // The only class allowed to access protected
+public:
+ // Constructors
+
+ // Implementation
+ virtual bool IsTypeNum(void) = 0;
+ virtual bool IsZero(void) = 0;
+ virtual bool IsCi(void) {return false;}
+ virtual bool IsUnsigned(void) {return Unsigned;}
+ virtual void Reset(void) = 0;
+ virtual int GetSize(void) = 0;
+ virtual int GetValLen(void) = 0;
+ virtual int GetValPrec(void) = 0;
+ virtual int GetLength(void) {return 1;}
+ virtual PSZ GetCharValue(void) {assert(false); return NULL;}
+ virtual char GetTinyValue(void) {assert(false); return 0;}
+ virtual uchar GetUTinyValue(void) {assert(false); return 0;}
+ virtual short GetShortValue(void) {assert(false); return 0;}
+ virtual ushort GetUShortValue(void) {assert(false); return 0;}
+ virtual int GetIntValue(void) = 0;
+ virtual uint GetUIntValue(void) = 0;
+ virtual longlong GetBigintValue(void) = 0;
+ virtual ulonglong GetUBigintValue(void) = 0;
+ virtual double GetFloatValue(void) = 0;
+ virtual void *GetTo_Val(void) = 0;
+ virtual void SetPrec(int prec) {Prec = prec;}
+ bool IsNull(void) {return (Nullable && Null);}
+ void SetNull(bool b) {Null = (Nullable ? b : false);}
+ bool GetNullable(void) {return Nullable;}
+ void SetNullable(bool b) {Nullable = b;}
+ int GetType(void) {return Type;}
+ int GetClen(void) {return Clen;}
+ void SetGlobal(PGLOBAL g) {Global = g;}
+
+ // Methods
+ virtual bool SetValue_pval(PVAL valp, bool chktype = false) = 0;
+ virtual bool SetValue_char(const char *p, int n) = 0;
+ virtual void SetValue_psz(PCSZ s) = 0;
+ virtual void SetValue_bool(bool) {assert(false);}
+ virtual int CompareValue(PVAL vp) = 0;
+ virtual BYTE TestValue(PVAL vp);
+ virtual void SetValue(char) {assert(false);}
+ virtual void SetValue(uchar) {assert(false);}
+ virtual void SetValue(short) {assert(false);}
+ virtual void SetValue(ushort) {assert(false);}
+ virtual void SetValue(int) {assert(false);}
+ virtual void SetValue(uint) {assert(false);}
+ virtual void SetValue(longlong) {assert(false);}
+ virtual void SetValue(ulonglong) {assert(false);}
+ virtual void SetValue(double) {assert(false);}
+ virtual void SetValue_pvblk(PVBLK blk, int n) = 0;
+ virtual void SetBinValue(void* p) = 0;
+ virtual bool GetBinValue(void *buf, int buflen, bool go) = 0;
+ virtual int ShowValue(char *buf, int len) = 0;
+ virtual char *GetCharString(char *p) = 0;
+ virtual bool IsEqual(PVAL vp, bool chktype) = 0;
+ virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op);
+ virtual bool FormatValue(PVAL vp, PCSZ fmt) = 0;
+ virtual void Printf(PGLOBAL g, FILE *, uint);
+ virtual void Prints(PGLOBAL g, char *ps, uint z);
+
+ /**
+ Set value from a non-aligned in-memory value in the machine byte order.
+ TYPE can be either of:
+ - int, short, longlong
+ - uint, ushort, ulonglong
+ - float, double
+ @param - a pointer to a non-aligned value of type TYPE.
+ */
+ template<typename TYPE>
+ void SetValueNonAligned(const char *p)
+ {
+#if defined(UNALIGNED_OK)
+ SetValue(*((TYPE*)p)); // x86 can cast non-aligned memory directly
+#else
+ TYPE tmp; // a slower version for non-x86 platforms
+ memcpy(&tmp, p, sizeof(tmp));
+ SetValue(tmp);
+#endif
+ } // end of SetValueNonAligned
+
+ /**
+ Get value from a non-aligned in-memory value in the machine byte order.
+ TYPE can be either of:
+ - int, short, longlong
+ - uint, ushort, ulonglong
+ - float, double
+ @params - a pointer to a non-aligned value of type TYPE, the TYPE value.
+ */
+ template<typename TYPE>
+ void GetValueNonAligned(char *p, TYPE n)
+ {
+#if defined(UNALIGNED_OK)
+ *(TYPE *)p = n; // x86 can cast non-aligned memory directly
+#else
+ TYPE tmp = n; // a slower version for non-x86 platforms
+ memcpy(p, &tmp, sizeof(tmp));
+#endif
+ } // end of SetValueNonAligned
+
+protected:
+ virtual bool SetConstFormat(PGLOBAL, FORMAT&) = 0;
+ const char *GetXfmt(void);
+
+ // Constructor used by derived classes
+ VALUE(int type, bool un = false);
+
+ // Members
+ PGLOBAL Global; // To reduce arglist
+ const char *Fmt;
+ const char *Xfmt;
+ bool Nullable; // True if value can be null
+ bool Null; // True if value is null
+ bool Unsigned; // True if unsigned
+ int Type; // The value type
+ int Clen; // Internal value length
+ int Prec;
+ }; // end of class VALUE
+
+/***********************************************************************/
+/* Class TYPVAL: represents a typed value. */
+/***********************************************************************/
+template <class TYPE>
+class DllExport TYPVAL : public VALUE {
+ public:
+ // Constructor
+ TYPVAL(TYPE n, int type, int prec = 0, bool un = false);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return true;}
+ virtual bool IsZero(void) {return Tval == 0;}
+ virtual void Reset(void) {Tval = 0;}
+ virtual int GetValLen(void);
+ virtual int GetValPrec() {return Prec;}
+ virtual int GetSize(void) {return sizeof(TYPE);}
+//virtual PSZ GetCharValue(void) {return VALUE::GetCharValue();}
+ virtual char GetTinyValue(void) {return (char)Tval;}
+ virtual uchar GetUTinyValue(void) {return (uchar)Tval;}
+ virtual short GetShortValue(void) {return (short)Tval;}
+ virtual ushort GetUShortValue(void) {return (ushort)Tval;}
+ virtual int GetIntValue(void) {return (int)Tval;}
+ virtual uint GetUIntValue(void) {return (uint)Tval;}
+ virtual longlong GetBigintValue(void) {return (longlong)Tval;}
+ virtual ulonglong GetUBigintValue(void) {return (ulonglong)Tval;}
+ virtual double GetFloatValue(void) {return (double)Tval;}
+ virtual void *GetTo_Val(void) {return &Tval;}
+
+ // Methods
+ virtual bool SetValue_pval(PVAL valp, bool chktype);
+ virtual bool SetValue_char(const char *p, int n);
+ virtual void SetValue_psz(PCSZ s);
+ virtual void SetValue_bool(bool b) {Tval = (b) ? 1 : 0;}
+ virtual int CompareValue(PVAL vp);
+ virtual void SetValue(char c) {Tval = (TYPE)c; Null = false;}
+ virtual void SetValue(uchar c) {Tval = (TYPE)c; Null = false;}
+ virtual void SetValue(short i) {Tval = (TYPE)i; Null = false;}
+ virtual void SetValue(ushort i) {Tval = (TYPE)i; Null = false;}
+ virtual void SetValue(int n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(uint n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(longlong n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(ulonglong n) {Tval = (TYPE)n; Null = false;}
+ virtual void SetValue(double f) {Tval = (TYPE)f; Null = false;}
+ virtual void SetValue_pvblk(PVBLK blk, int n);
+ virtual void SetBinValue(void *p);
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual int ShowValue(char *buf, int len);
+ virtual char *GetCharString(char *p);
+ virtual bool IsEqual(PVAL vp, bool chktype);
+ virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op);
+ virtual bool SetConstFormat(PGLOBAL, FORMAT&);
+ virtual bool FormatValue(PVAL vp, PCSZ fmt);
+
+ protected:
+ static TYPE MinMaxVal(bool b);
+ TYPE SafeAdd(TYPE n1, TYPE n2);
+ TYPE SafeMult(TYPE n1, TYPE n2);
+ bool Compall(PGLOBAL g, PVAL *vp, int np, OPVAL op);
+
+ // Default constructor not to be used
+ TYPVAL(void) : VALUE(TYPE_ERROR) {}
+
+ // Specialized functions
+ static ulonglong MaxVal(void);
+ TYPE GetTypedValue(PVAL vp);
+ TYPE GetTypedValue(PVBLK blk, int n);
+// TYPE GetTypedValue(PSZ s);
+
+ // Members
+ TYPE Tval;
+ }; // end of class TYPVAL
+
+/***********************************************************************/
+/* Specific STRING class. */
+/***********************************************************************/
+template <>
+class DllExport TYPVAL<PSZ>: public VALUE {
+ friend class SWAP; // The only class allowed to offsets Strg
+public:
+ // Constructors
+ TYPVAL(PSZ s, short c = 0);
+ TYPVAL(PGLOBAL g, PSZ s, int n, int c);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return false;}
+ virtual bool IsZero(void) {return *Strp == 0;}
+ virtual void Reset(void) {*Strp = 0;}
+ virtual int GetValLen(void) {return Len;};
+ virtual int GetValPrec() {return (Ci) ? 1 : 0;}
+ virtual int GetSize(void) {return (Strp) ? (int)strlen(Strp) : 0;}
+ virtual PSZ GetCharValue(void) {return Strp;}
+ virtual char GetTinyValue(void);
+ virtual uchar GetUTinyValue(void);
+ virtual short GetShortValue(void);
+ virtual ushort GetUShortValue(void);
+ virtual int GetIntValue(void);
+ virtual uint GetUIntValue(void);
+ virtual longlong GetBigintValue(void);
+ virtual ulonglong GetUBigintValue(void);
+ virtual double GetFloatValue(void) {return atof(Strp);}
+ virtual void *GetTo_Val(void) {return Strp;}
+ virtual void SetPrec(int prec) {Ci = prec != 0;}
+
+ // Methods
+ virtual bool SetValue_pval(PVAL valp, bool chktype);
+ virtual bool SetValue_char(const char *p, int n);
+ virtual void SetValue_psz(PCSZ s);
+ virtual void SetValue_pvblk(PVBLK blk, int n);
+ virtual void SetValue(char c);
+ virtual void SetValue(uchar c);
+ virtual void SetValue(short i);
+ virtual void SetValue(ushort i);
+ virtual void SetValue(int n);
+ virtual void SetValue(uint n);
+ virtual void SetValue(longlong n);
+ virtual void SetValue(ulonglong n);
+ virtual void SetValue(double f);
+ virtual void SetBinValue(void *p);
+ virtual int CompareValue(PVAL vp);
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual int ShowValue(char *buf, int len);
+ virtual char *GetCharString(char *p);
+ virtual bool IsEqual(PVAL vp, bool chktype);
+ virtual bool Compute(PGLOBAL g, PVAL *vp, int np, OPVAL op);
+ virtual bool FormatValue(PVAL vp, PCSZ fmt);
+ virtual bool SetConstFormat(PGLOBAL, FORMAT&);
+ virtual void Prints(PGLOBAL g, char *ps, uint z);
+
+ protected:
+ // Members
+ PSZ Strp;
+ bool Ci; // true if case insensitive
+ int Len;
+ }; // end of class TYPVAL<PSZ>
+
+/***********************************************************************/
+/* Specific DECIMAL class. */
+/***********************************************************************/
+class DllExport DECVAL: public TYPVAL<PSZ> {
+ public:
+ // Constructors
+ DECVAL(PSZ s);
+ DECVAL(PGLOBAL g, PSZ s, int n, int prec, bool uns);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return true;}
+ virtual bool IsZero(void);
+ virtual void Reset(void);
+ virtual int GetValPrec() {return Prec;}
+
+ // Methods
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual int ShowValue(char *buf, int len);
+ virtual bool IsEqual(PVAL vp, bool chktype);
+ virtual int CompareValue(PVAL vp);
+
+ protected:
+ // Members
+ }; // end of class DECVAL
+
+/***********************************************************************/
+/* Specific BINARY class. */
+/***********************************************************************/
+class DllExport BINVAL: public VALUE {
+ friend class SWAP; // The only class allowed to offsets pointers
+public:
+ // Constructors
+//BINVAL(void *p);
+ BINVAL(PGLOBAL g, void *p, int cl, int n);
+
+ // Implementation
+ virtual bool IsTypeNum(void) {return false;}
+ virtual bool IsZero(void);
+ virtual void Reset(void);
+ virtual int GetValLen(void) {return Clen;};
+ virtual int GetValPrec() {return 0;}
+ virtual int GetSize(void) {return Len;}
+ virtual PSZ GetCharValue(void) {return (PSZ)Binp;}
+ virtual char GetTinyValue(void);
+ virtual uchar GetUTinyValue(void);
+ virtual short GetShortValue(void);
+ virtual ushort GetUShortValue(void);
+ virtual int GetIntValue(void);
+ virtual uint GetUIntValue(void);
+ virtual longlong GetBigintValue(void);
+ virtual ulonglong GetUBigintValue(void);
+ virtual double GetFloatValue(void);
+ virtual void *GetTo_Val(void) {return Binp;}
+
+ // Methods
+ virtual bool SetValue_pval(PVAL valp, bool chktype);
+ virtual bool SetValue_char(const char *p, int n);
+ virtual void SetValue_psz(PCSZ s);
+ virtual void SetValue_pvblk(PVBLK blk, int n);
+ virtual void SetValue(char c);
+ virtual void SetValue(uchar c);
+ virtual void SetValue(short i);
+ virtual void SetValue(ushort i);
+ virtual void SetValue(int n);
+ virtual void SetValue(uint n);
+ virtual void SetValue(longlong n);
+ virtual void SetValue(ulonglong n);
+ virtual void SetValue(double f);
+ virtual void SetBinValue(void *p);
+ virtual void SetBinValue(void* p, ulong len);
+ virtual bool GetBinValue(void *buf, int buflen, bool go);
+ virtual int CompareValue(PVAL) {assert(false); return 0;}
+ virtual int ShowValue(char *buf, int len);
+ virtual char *GetCharString(char *p);
+ virtual bool IsEqual(PVAL vp, bool chktype);
+ virtual bool FormatValue(PVAL vp, PCSZ fmt);
+ virtual bool SetConstFormat(PGLOBAL, FORMAT&);
+
+ protected:
+ // Members
+ void *Binp;
+ char *Chrp;
+ int Len;
+ }; // end of class BINVAL
+
+/***********************************************************************/
+/* Class DTVAL: represents a time stamp value. */
+/***********************************************************************/
+class DllExport DTVAL : public TYPVAL<int> {
+ public:
+ // Constructors
+ DTVAL(PGLOBAL g, int n, int p, PCSZ fmt);
+ DTVAL(int n);
+ using TYPVAL<int>::SetValue;
+
+ // Implementation
+ virtual bool SetValue_pval(PVAL valp, bool chktype);
+ virtual bool SetValue_char(const char *p, int n);
+ virtual void SetValue_psz(PCSZ s);
+ virtual void SetValue_pvblk(PVBLK blk, int n);
+ virtual void SetValue(int n);
+ virtual PSZ GetCharValue(void) { return Sdate; }
+ virtual char *GetCharString(char *p);
+ virtual int ShowValue(char *buf, int len);
+ virtual bool FormatValue(PVAL vp, PCSZ fmt);
+ bool SetFormat(PGLOBAL g, PCSZ fmt, int len, int year = 0);
+ bool SetFormat(PGLOBAL g, PVAL valp);
+ bool IsFormatted(void) {return Pdtp != NULL;}
+ bool MakeTime(struct tm *ptm);
+ static void SetTimeShift(void);
+ static int GetShift(void) {return Shift;}
+
+ // Methods
+ bool MakeDate(PGLOBAL g, int *val, int nval);
+
+ struct tm *GetGmTime(struct tm *);
+
+ protected:
+ // Default constructor not to be used
+ DTVAL(void) : TYPVAL<int>() {}
+
+ // Members
+ static int Shift; // Time zone shift in seconds
+ PDTP Pdtp; // To the DATPAR structure
+ char *Sdate; // Utility char buffer
+ int DefYear; // Used by ExtractDate
+ int Len; // Used by CHAR scalar function
+ }; // end of class DTVAL
+
+#endif // __VALUE__H__
diff --git a/storage/connect/xindex.cpp b/storage/connect/xindex.cpp
new file mode 100644
index 00000000..6ed70f21
--- /dev/null
+++ b/storage/connect/xindex.cpp
@@ -0,0 +1,3298 @@
+/***************** Xindex C++ Class Xindex Code (.CPP) *****************/
+/* Name: XINDEX.CPP Version 3.0 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2004-2017 */
+/* */
+/* This file contains the class XINDEX implementation code. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include relevant sections of the System header files. */
+/***********************************************************************/
+#include "my_global.h"
+#if defined(_WIN32)
+#include <io.h>
+#include <fcntl.h>
+#include <errno.h>
+//#include <windows.h>
+#else // !_WIN32
+#if defined(UNIX)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#else // !UNIX
+#include <io.h>
+#endif // !UNIX
+#include <fcntl.h>
+#endif // !_WIN32
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/* kindex.h is header containing the KINDEX class definition. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "osutil.h"
+#include "maputil.h"
+//nclude "filter.h"
+#include "tabcol.h"
+#include "xindex.h"
+#include "xobject.h"
+//nclude "scalfnc.h"
+//nclude "array.h"
+#include "filamtxt.h"
+#include "tabdos.h"
+#if defined(VCT_SUPPORT)
+#include "tabvct.h"
+#endif // VCT_SUPPORT
+
+/***********************************************************************/
+/* Macro or external routine definition */
+/***********************************************************************/
+#define NZ 8
+#define NW 5
+#define MAX_INDX 10
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+#endif
+
+/***********************************************************************/
+/* DB external variables. */
+/***********************************************************************/
+extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
+#if defined(XMAP)
+extern my_bool xmap;
+#endif // XMAP
+
+/***********************************************************************/
+/* Last two parameters are true to enable type checking, and last one */
+/* to have rows filled by blanks to be compatible with QRY blocks. */
+/***********************************************************************/
+PVBLK AllocValBlock(PGLOBAL, void *, int, int, int, int,
+ bool check = true, bool blank = true, bool un = false);
+
+/***********************************************************************/
+/* Check whether we have to create/update permanent indexes. */
+/***********************************************************************/
+int PlgMakeIndex(PGLOBAL g, PSZ name, PIXDEF pxdf, bool add)
+ {
+ int rc;
+ PTABLE tablep;
+ PTDB tdbp;
+ PCATLG cat = PlgGetCatalog(g, true);
+
+ /*********************************************************************/
+ /* Open a new table in mode read and with only the keys columns. */
+ /*********************************************************************/
+ tablep = new(g) XTAB(name);
+
+ if (!(tdbp = cat->GetTable(g, tablep)))
+ rc = RC_NF;
+ else if (!tdbp->GetDef()->Indexable()) {
+ sprintf(g->Message, MSG(TABLE_NO_INDEX), name);
+ rc = RC_NF;
+ } else if ((rc = ((PTDBASE)tdbp)->MakeIndex(g, pxdf, add)) == RC_INFO)
+ rc = RC_OK; // No or remote index
+
+ return rc;
+ } // end of PlgMakeIndex
+
+/* -------------------------- Class INDEXDEF ------------------------- */
+
+/***********************************************************************/
+/* INDEXDEF Constructor. */
+/***********************************************************************/
+INDEXDEF::INDEXDEF(char *name, bool uniq, int n)
+ {
+//To_Def = NULL;
+ Next = NULL;
+ ToKeyParts = NULL;
+ Name = name;
+ Unique = uniq;
+ Invalid = false;
+ AutoInc = false;
+ Dynamic = false;
+ Mapped = false;
+ Nparts = 0;
+ ID = n;
+//Offset = 0;
+//Offhigh = 0;
+//Size = 0;
+ MaxSame = 1;
+ } // end of INDEXDEF constructor
+
+/***********************************************************************/
+/* Set the max same values for each colum after making the index. */
+/***********************************************************************/
+void INDEXDEF::SetMxsame(PXINDEX x)
+ {
+ PKPDEF kdp;
+ PXCOL xcp;
+
+ for (kdp = ToKeyParts, xcp = x->To_KeyCol;
+ kdp && xcp; kdp = kdp->Next, xcp = xcp->Next)
+ kdp->Mxsame = xcp->Mxs;
+ } // end of SetMxsame
+
+/* -------------------------- Class KPARTDEF ------------------------- */
+
+/***********************************************************************/
+/* KPARTDEF Constructor. */
+/***********************************************************************/
+KPARTDEF::KPARTDEF(PSZ name, int n)
+ {
+ Next = NULL;
+ Name = name;
+ Mxsame = 0;
+ Ncol = n;
+ Klen = 0;
+ } // end of KPARTDEF constructor
+
+/* -------------------------- XXBASE Class --------------------------- */
+
+/***********************************************************************/
+/* XXBASE public constructor. */
+/***********************************************************************/
+XXBASE::XXBASE(PTDBDOS tbxp, bool b) : CSORT(b),
+ To_Rec((int*&)Record.Memp)
+ {
+ Tbxp = tbxp;
+ Record = Nmblk;
+ Cur_K = -1;
+ Old_K = -1;
+ Num_K = 0;
+ Ndif = 0;
+ Bot = Top = Inf = Sup = 0;
+ Op = OP_EQ;
+ To_KeyCol = NULL;
+ Mul = false;
+ Srtd = false;
+ Dynamic = false;
+ Val_K = -1;
+ Nblk = Sblk = 0;
+ Thresh = 7;
+ ID = -1;
+ Nth = 0;
+ } // end of XXBASE constructor
+
+/***********************************************************************/
+/* Make file output of XINDEX contents. */
+/***********************************************************************/
+void XXBASE::Printf(PGLOBAL, FILE *f, uint n)
+ {
+ char m[64];
+
+ memset(m, ' ', n); // Make margin string
+ m[n] = '\0';
+ fprintf(f, "%sXINDEX: Tbxp=%p Num=%d\n", m, Tbxp, Num_K);
+ } // end of Printf
+
+/***********************************************************************/
+/* Make string output of XINDEX contents. */
+/***********************************************************************/
+void XXBASE::Prints(PGLOBAL, char *ps, uint z)
+ {
+ *ps = '\0';
+ strncat(ps, "Xindex", z);
+ } // end of Prints
+
+/* -------------------------- XINDEX Class --------------------------- */
+
+/***********************************************************************/
+/* XINDEX public constructor. */
+/***********************************************************************/
+XINDEX::XINDEX(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp, PCOL *cp, PXOB *xp, int k)
+ : XXBASE(tdbp, !xdp->IsUnique())
+ {
+ Xdp = xdp;
+ ID = xdp->GetID();
+ Tdbp = tdbp;
+ X = pxp;
+ To_LastCol = NULL;
+ To_LastVal = NULL;
+ To_Cols = cp;
+ To_Vals = xp;
+ Mul = !xdp->IsUnique();
+ Srtd = false;
+ Nk = xdp->GetNparts();
+ Nval = (k) ? k : Nk;
+ Incr = 0;
+//Defoff = xdp->GetOffset();
+//Defhigh = xdp->GetOffhigh();
+//Size = xdp->GetSize();
+ MaxSame = xdp->GetMaxSame();
+ } // end of XINDEX constructor
+
+/***********************************************************************/
+/* XINDEX Reset: re-initialize a Xindex block. */
+/***********************************************************************/
+void XINDEX::Reset(void)
+ {
+ for (PXCOL kp = To_KeyCol; kp; kp = kp->Next)
+ kp->Val_K = kp->Ndf;
+
+ Cur_K = Num_K;
+ Old_K = -1; // Needed to avoid not setting CurBlk for Update
+ Op = (Op == OP_FIRST || Op == OP_NEXT) ? OP_FIRST :
+ (Op == OP_FSTDIF || Op == OP_NXTDIF) ? OP_FSTDIF : OP_EQ;
+ Nth = 0;
+ } // end of Reset
+
+/***********************************************************************/
+/* XINDEX Close: terminate index and free all allocated data. */
+/* Do not reset values that are used at return to make. */
+/***********************************************************************/
+void XINDEX::Close(void)
+ {
+ // Close file or view of file
+ if (X)
+ X->Close();
+
+ // De-allocate data
+ PlgDBfree(Record);
+ PlgDBfree(Index);
+ PlgDBfree(Offset);
+
+ for (PXCOL kcp = To_KeyCol; kcp; kcp = kcp->Next) {
+ // Column values cannot be retrieved from key anymore
+ if (kcp->Colp)
+ kcp->Colp->SetKcol(NULL);
+
+ // De-allocate Key data
+ kcp->FreeData();
+ } // endfor kcp
+
+ } // end of Close
+
+/***********************************************************************/
+/* XINDEX compare routine for C Quick/Insertion sort. */
+/***********************************************************************/
+int XINDEX::Qcompare(int *i1, int *i2)
+ {
+ int k;
+ PXCOL kcp;
+
+ for (kcp = To_KeyCol, k = 0; kcp; kcp = kcp->Next)
+ if ((k = kcp->Compare(*i1, *i2)))
+ break;
+
+//num_comp++;
+ return k;
+ } // end of Qcompare
+
+/***********************************************************************/
+/* AddColumns: here we try to determine whether it is worthwhile to */
+/* add to the keys the values of the columns selected for this table. */
+/* Sure enough, it is done while records are read and permit to avoid */
+/* reading the table while doing the join (Dynamic index only) */
+/***********************************************************************/
+bool XINDEX::AddColumns(void)
+ {
+ if (!Dynamic)
+ return false; // Not applying to static index
+ else if (IsMul())
+ return false; // Not done yet for multiple index
+#if defined(VCT_SUPPORT)
+ else if (Tbxp->GetAmType() == TYPE_AM_VCT && ((PTDBVCT)Tbxp)->IsSplit())
+ return false; // This would require to read additional files
+#endif // VCT_SUPPORT
+ else
+ return true;
+
+ } // end of AddColumns
+
+/***********************************************************************/
+/* Make: Make and index on key column(s). */
+/***********************************************************************/
+bool XINDEX::Make(PGLOBAL g, PIXDEF sxp)
+ {
+ /*********************************************************************/
+ /* Table can be accessed through an index. */
+ /*********************************************************************/
+ int k, nk = Nk, rc = RC_OK;
+ int *bof, i, j, n, ndf, nkey;
+ PKPDEF kdfp = Xdp->GetToKeyParts();
+ bool brc = false;
+ PCOL colp;
+ PFIL filp = Tdbp->GetFilter();
+ PXCOL kp, addcolp, prev = NULL, kcp = NULL;
+//PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+#if defined(_DEBUG)
+ assert(X || Nk == 1);
+#endif // _DEBUG
+
+ /*********************************************************************/
+ /* Allocate the storage that will contain the keys and the file */
+ /* positions corresponding to them. */
+ /*********************************************************************/
+ if ((n = Tdbp->GetMaxSize(g)) < 0)
+ return true;
+ else if (!n) {
+ Num_K = Ndif = 0;
+ MaxSame = 1;
+
+ // The if condition was suppressed because this may be an existing
+ // index that is now void because all table lines were deleted.
+// if (sxp)
+ goto nox; // Truncate eventually existing index file
+// else
+// return false;
+
+ } // endif n
+
+ if (trace(1))
+ htrc("XINDEX Make: n=%d\n", n);
+
+ // File position must be stored
+ Record.Size = n * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Record)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", n);
+ goto err; // Error
+ } // endif
+
+ /*********************************************************************/
+ /* Allocate the KXYCOL blocks used to store column values. */
+ /*********************************************************************/
+ for (k = 0; k < Nk; k++) {
+ colp = To_Cols[k];
+
+ if (!kdfp) {
+ sprintf(g->Message, MSG(INT_COL_ERROR),
+ (colp) ? colp->GetName() : "???");
+ goto err; // Error
+ } // endif kdfp
+
+ kcp = new(g) KXYCOL(this);
+
+ if (kcp->Init(g, colp, n, true, kdfp->Klen))
+ goto err; // Error
+
+ if (prev) {
+ kcp->Previous = prev;
+ prev->Next = kcp;
+ } else
+ To_KeyCol = kcp;
+
+ prev = kcp;
+ kdfp = kdfp->Next;
+ } // endfor k
+
+ To_LastCol = prev;
+
+ if (AddColumns()) {
+ PCOL kolp = To_Cols[0]; // Temporary while imposing Nk = 1
+
+ i = 0;
+
+ // Allocate the accompanying
+ for (colp = Tbxp->GetColumns(); colp; colp = colp->GetNext()) {
+ // Count how many columns to add
+// for (k = 0; k < Nk; k++)
+// if (colp == To_Cols[k])
+// break;
+
+// if (k == nk)
+ if (colp != kolp)
+ i++;
+
+ } // endfor colp
+
+ if (i && i < 10) // Should be a parameter
+ for (colp = Tbxp->GetColumns(); colp; colp = colp->GetNext()) {
+// for (k = 0; k < Nk; k++)
+// if (colp == To_Cols[k])
+// break;
+
+// if (k < nk)
+ if (colp == kolp)
+ continue; // This is a key column
+
+ kcp = new(g) KXYCOL(this);
+
+ if (kcp->Init(g, colp, n, true, 0))
+ return true;
+
+ if (trace(1))
+ htrc("Adding colp=%p Buf_Type=%d size=%d\n",
+ colp, colp->GetResultType(), n);
+
+ nk++;
+ prev->Next = kcp;
+ prev = kcp;
+ } // endfor colp
+
+ } // endif AddColumns
+
+#if 0
+ /*********************************************************************/
+ /* Get the starting information for progress. */
+ /*********************************************************************/
+ dup->Step = (char*)PlugSubAlloc(g, NULL, 128);
+ sprintf((char*)dup->Step, MSG(BUILD_INDEX), Xdp->GetName(), Tdbp->Name);
+ dup->ProgMax = Tdbp->GetProgMax(g);
+ dup->ProgCur = 0;
+#endif // 0
+
+ /*********************************************************************/
+ /* Standard init: read the file and construct the index table. */
+ /* Note: reading will be sequential as To_Kindex is not set. */
+ /*********************************************************************/
+ for (i = nkey = 0; rc != RC_EF; i++) {
+#if 0
+ if (!dup->Step) {
+ strcpy(g->Message, MSG(QUERY_CANCELLED));
+ throw 99;
+ } // endif Step
+#endif // 0
+
+ /*******************************************************************/
+ /* Read a valid record from table file. */
+ /*******************************************************************/
+ rc = Tdbp->ReadDB(g);
+
+ // Update progress information
+// dup->ProgCur = Tdbp->GetProgCur();
+
+ // Check return code and do whatever must be done according to it
+ switch (rc) {
+ case RC_OK:
+ if (ApplyFilter(g, filp))
+ break;
+
+ // fall through
+ case RC_NF:
+ continue;
+ case RC_EF:
+ goto end_of_file;
+ default:
+ sprintf(g->Message, MSG(RC_READING), rc, Tdbp->Name);
+ goto err;
+ } // endswitch rc
+
+ /*******************************************************************/
+ /* Get and Store the file position of the last read record for */
+ /* future direct access. */
+ /*******************************************************************/
+ if (nkey == n) {
+ sprintf(g->Message, MSG(TOO_MANY_KEYS), nkey);
+ return true;
+ } else
+ To_Rec[nkey] = Tdbp->GetRecpos();
+
+ if (trace(2))
+ htrc("Make: To_Rec[%d]=%d\n", nkey, To_Rec[nkey]);
+
+ /*******************************************************************/
+ /* Get the keys and place them in the key blocks. */
+ /*******************************************************************/
+ for (k = 0, kcp = To_KeyCol;
+ k < nk && kcp;
+ k++, kcp = kcp->Next) {
+// colp = To_Cols[k];
+ colp = kcp->Colp;
+
+ if (!colp->GetStatus(BUF_READ))
+ colp->ReadColumn(g);
+ else
+ colp->Reset();
+
+ kcp->SetValue(colp, nkey);
+ } // endfor k
+
+ nkey++; // A new valid key was found
+ } // endfor i
+
+ end_of_file:
+
+ // Update progress information
+//dup->ProgCur = Tdbp->GetProgMax(g);
+
+ /*********************************************************************/
+ /* Record the Index size and eventually resize memory allocation. */
+ /*********************************************************************/
+ if ((Num_K = nkey) < n) {
+ PlgDBrealloc(g, NULL, Record, Num_K * sizeof(int));
+
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->ReAlloc(g, Num_K);
+
+ } // endif Num_K
+
+ /*********************************************************************/
+ /* Sort the index so we can use an optimized Find algorithm. */
+ /* Note: for a unique index we use the non conservative sort */
+ /* version because normally all index values are different. */
+ /* This was set at CSORT class construction. */
+ /* For all indexes, an offset array is made so we can check the */
+ /* uniqueness of unique indexes. */
+ /*********************************************************************/
+ Index.Size = Num_K * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Index)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", Num_K);
+ goto err; // Error
+ } // endif alloc
+
+ Offset.Size = (Num_K + 1) * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Offset)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "offset", Num_K + 1);
+ goto err; // Error
+ } // endif alloc
+
+ // We must separate keys and added columns before sorting
+ addcolp = To_LastCol->Next;
+ To_LastCol->Next = NULL;
+
+ // Call the sort program, it returns the number of distinct values
+ if ((Ndif = Qsort(g, Num_K)) < 0)
+ goto err; // Error during sort
+
+ if (trace(1))
+ htrc("Make: Nk=%d n=%d Num_K=%d Ndif=%d addcolp=%p BlkFil=%p X=%p\n",
+ Nk, n, Num_K, Ndif, addcolp, Tdbp->To_BlkFil, X);
+
+ // Check whether the unique index is unique indeed
+ if (!Mul)
+ {
+ if (Ndif < Num_K) {
+ strcpy(g->Message, MSG(INDEX_NOT_UNIQ));
+ brc = true;
+ goto err;
+ } else
+ PlgDBfree(Offset); // Not used anymore
+ }
+
+ // Restore kcp list
+ To_LastCol->Next = addcolp;
+
+ // Use the index to physically reorder the xindex
+ Srtd = Reorder(g);
+
+ if (Ndif < Num_K) {
+ // Resize the offset array
+ PlgDBrealloc(g, NULL, Offset, (Ndif + 1) * sizeof(int));
+
+ // Initial value of MaxSame
+ MaxSame = Pof[1] - Pof[0];
+
+ // Resize the Key array by only keeping the distinct values
+ for (i = 1; i < Ndif; i++) {
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Move(i, Pof[i]);
+
+ MaxSame = MY_MAX(MaxSame, Pof[i + 1] - Pof[i]);
+ } // endfor i
+
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->ReAlloc(g, Ndif);
+
+ } else {
+ Mul = false; // Current index is unique
+ PlgDBfree(Offset); // Not used anymore
+ MaxSame = 1; // Reset it when remaking an index
+ } // endif Ndif
+
+ /*********************************************************************/
+ /* Now do the reduction of the index. Indeed a multi-column index */
+ /* can be used for only some of the first columns. For instance if */
+ /* an index is defined for column A, B, C PlugDB can use it for */
+ /* only the column A or the columns A, B. */
+ /* What we do here is to reduce the data so column A will contain */
+ /* only the sorted distinct values of A, B will contain data such */
+ /* as only distinct values of A,B are stored etc. */
+ /* This implies that for each column set an offset array is made */
+ /* except if the subset originally contains unique values. */
+ /*********************************************************************/
+ // Update progress information
+//dup->Step = STEP(REDUCE_INDEX);
+
+ ndf = Ndif;
+ To_LastCol->Mxs = MaxSame;
+
+ for (kcp = To_LastCol->Previous; kcp; kcp = kcp->Previous) {
+ if (!(bof = kcp->MakeOffset(g, ndf)))
+ goto err;
+ else
+ *bof = 0;
+
+ for (n = 0, i = j = 1; i < ndf; i++)
+ for (kp = kcp; kp; kp = kp->Previous)
+ if (kp->Compare(n, i)) {
+ // Values are not equal to last ones
+ bof[j++] = n = i;
+ break;
+ } // endif Compare
+
+ if (j < ndf) {
+ // Sub-index is multiple
+ bof[j] = ndf;
+ ndf = j; // New number of distinct values
+
+ // Resize the Key array by only keeping the distinct values
+ for (kp = kcp; kp; kp = kp->Previous) {
+ for (i = 1; i < ndf; i++)
+ kp->Move(i, bof[i]);
+
+ kp->ReAlloc(g, ndf);
+ } // endif kcp
+
+ // Resize the offset array
+ kcp->MakeOffset(g, ndf);
+
+ // Calculate the max same value for this column
+ kcp->Mxs = ColMaxSame(kcp);
+ } else {
+ // Current sub-index is unique
+ kcp->MakeOffset(g, 0); // The offset is not used anymore
+ kcp->Mxs = 1; // Unique
+ } // endif j
+
+ } // endfor kcp
+
+ /*********************************************************************/
+ /* For sorted columns and fixed record size, file position can be */
+ /* calculated, so the Record array can be discarted. */
+ /* Not true for DBF tables because of eventual soft deleted lines. */
+ /* Note: for Num_K = 1 any non null value is Ok. */
+ /*********************************************************************/
+ if (Srtd && !filp && Tdbp->Ftype != RECFM_VAR && Tdbp->Ftype != RECFM_CSV
+ && Tdbp->Txfp->GetAmType() != TYPE_AM_DBF) {
+ Incr = (Num_K > 1) ? To_Rec[1] : Num_K;
+ PlgDBfree(Record);
+ } // endif Srtd
+
+ /*********************************************************************/
+ /* Check whether a two-tier find algorithm can be implemented. */
+ /* It is currently implemented only for single key indexes. */
+ /*********************************************************************/
+ if (Nk == 1 && ndf >= 65536) {
+ // Implement a two-tier find algorithm
+ for (Sblk = 256; (Sblk * Sblk * 4) < ndf; Sblk *= 2) ;
+
+ Nblk = (ndf -1) / Sblk + 1;
+
+ if (To_KeyCol->MakeBlockArray(g, Nblk, Sblk))
+ goto err; // Error
+
+ } // endif Num_K
+
+ nox:
+ /*********************************************************************/
+ /* No valid record read yet for secondary file. */
+ /*********************************************************************/
+ Cur_K = Num_K;
+
+ /*********************************************************************/
+ /* Save the xindex so it has not to be recalculated. */
+ /*********************************************************************/
+ if (X) {
+ if (SaveIndex(g, sxp))
+ brc = true;
+
+ } else { // Dynamic index
+ // Indicate that key column values can be found from KEYCOL's
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Colp->SetKcol(kcp);
+
+ Tdbp->SetFilter(NULL); // Not used anymore
+ } // endif X
+
+ err:
+ // We don't need the index anymore
+ if (X || brc)
+ Close();
+
+ if (brc)
+ printf("%s\n", g->Message);
+
+ return brc;
+ } // end of Make
+
+/***********************************************************************/
+/* Return the max size of the intermediate column. */
+/***********************************************************************/
+int XINDEX::ColMaxSame(PXCOL kp)
+ {
+ int *kof, i, ck1, ck2, ckn = 1;
+ PXCOL kcp;
+
+ // Calculate the max same value for this column
+ for (i = 0; i < kp->Ndf; i++) {
+ ck1 = i;
+ ck2 = i + 1;
+
+ for (kcp = kp; kcp; kcp = kcp->Next) {
+ if (!(kof = (kcp->Next) ? kcp->Kof : Pof))
+ break;
+
+ ck1 = kof[ck1];
+ ck2 = kof[ck2];
+ } // endfor kcp
+
+ ckn = MY_MAX(ckn, ck2 - ck1);
+ } // endfor i
+
+ return ckn;
+ } // end of ColMaxSame
+
+/***********************************************************************/
+/* Reorder: use the sort index to reorder the data in storage so */
+/* it will be physically sorted and sort index can be removed. */
+/***********************************************************************/
+bool XINDEX::Reorder(PGLOBAL g __attribute__((unused)))
+ {
+ int i, j, k, n;
+ bool sorted = true;
+ PXCOL kcp;
+#if 0
+ PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
+
+ if (Num_K > 500000) {
+ // Update progress information
+ dup->Step = STEP(REORDER_INDEX);
+ dup->ProgMax = Num_K;
+ dup->ProgCur = 0;
+ } else
+ dup = NULL;
+#endif // 0
+
+ if (!Pex)
+ return Srtd;
+
+ for (i = 0; i < Num_K; i++) {
+ if (Pex[i] == Num_K) { // Already moved
+ continue;
+ } else if (Pex[i] == i) { // Already placed
+// if (dup)
+// dup->ProgCur++;
+
+ continue;
+ } // endif's Pex
+
+ sorted = false;
+
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Save(i);
+
+ n = To_Rec[i];
+
+ for (j = i;; j = k) {
+ k = Pex[j];
+ Pex[j] = Num_K; // Mark position as set
+
+ if (k == i) {
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Restore(j);
+
+ To_Rec[j] = n;
+ break; // end of loop
+ } else {
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Move(j, k); // Move k to j
+
+ To_Rec[j] = To_Rec[k];
+ } // endif k
+
+// if (dup)
+// dup->ProgCur++;
+
+ } // endfor j
+
+ } // endfor i
+
+ // The index is not used anymore
+ PlgDBfree(Index);
+ return sorted;
+ } // end of Reorder
+
+/***********************************************************************/
+/* Save the index values for this table. */
+/* The problem here is to avoid name duplication, because more than */
+/* one data file can have the same name (but different types) and/or */
+/* the same data file can be used with different block sizes. This is */
+/* why we use Ofn that defaults to the file name but can be set to a */
+/* different name if necessary. */
+/***********************************************************************/
+bool XINDEX::SaveIndex(PGLOBAL g, PIXDEF sxp)
+ {
+ PCSZ ftype;
+ char fn[_MAX_PATH];
+ int n[NZ], nof = (Mul) ? (Ndif + 1) : 0;
+ int id = -1, size = 0;
+ bool sep, rc = false;
+ PXCOL kcp = To_KeyCol;
+ PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
+//PDBUSER dup = PlgGetUser(g);
+
+//dup->Step = STEP(SAVING_INDEX);
+//dup->ProgMax = 15 + 16 * Nk;
+//dup->ProgCur = 0;
+
+ switch (Tdbp->Ftype) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_CSV: ftype = ".cnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
+ return true;
+ } // endswitch Ftype
+
+ if ((sep = defp->GetBoolCatInfo("SepIndex", false))) {
+ // Index is saved in a separate file
+#if defined(_WIN32)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), Xdp->GetName());
+ _makepath(fn, drive, direc, fname, ftype);
+ sxp = NULL;
+ } else {
+ id = ID;
+ strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
+ } // endif sep
+
+ PlugSetPath(fn, fn, Tdbp->GetPath());
+
+ if (X->Open(g, fn, id, (sxp) ? MODE_INSERT : MODE_WRITE)) {
+ printf("%s\n", g->Message);
+ return true;
+ } // endif Open
+
+ if (!Ndif)
+ goto end; // Void index
+
+ /*********************************************************************/
+ /* Write the index values on the index file. */
+ /*********************************************************************/
+ n[0] = ID + MAX_INDX; // To check validity
+ n[1] = Nk; // The number of indexed columns
+ n[2] = nof; // The offset array size or 0
+ n[3] = Num_K; // The index size
+ n[4] = Incr; // Increment of record positions
+ n[5] = Nblk; n[6] = Sblk;
+ n[7] = Srtd ? 1 : 0; // Values are sorted in the file
+
+ if (trace(1)) {
+ htrc("Saving index %s\n", Xdp->GetName());
+ htrc("ID=%d Nk=%d nof=%d Num_K=%d Incr=%d Nblk=%d Sblk=%d Srtd=%d\n",
+ ID, Nk, nof, Num_K, Incr, Nblk, Sblk, Srtd);
+ } // endif trace
+
+ size = X->Write(g, n, NZ, sizeof(int), rc);
+//dup->ProgCur = 1;
+
+ if (Mul) // Write the offset array
+ size += X->Write(g, Pof, nof, sizeof(int), rc);
+
+//dup->ProgCur = 5;
+
+ if (!Incr) // Write the record position array(s)
+ size += X->Write(g, To_Rec, Num_K, sizeof(int), rc);
+
+//dup->ProgCur = 15;
+
+ for (; kcp; kcp = kcp->Next) {
+ n[0] = kcp->Ndf; // Number of distinct sub-values
+ n[1] = (kcp->Kof) ? kcp->Ndf + 1 : 0; // 0 if unique
+ n[2] = (kcp == To_KeyCol) ? Nblk : 0;
+ n[3] = kcp->Klen; // To be checked later
+ n[4] = kcp->Type; // To be checked later
+
+ size += X->Write(g, n, NW, sizeof(int), rc);
+// dup->ProgCur += 1;
+
+ if (n[2])
+ size += X->Write(g, kcp->To_Bkeys, Nblk, kcp->Klen, rc);
+
+// dup->ProgCur += 5;
+
+ size += X->Write(g, kcp->To_Keys, n[0], kcp->Klen, rc);
+// dup->ProgCur += 5;
+
+ if (n[1])
+ size += X->Write(g, kcp->Kof, n[1], sizeof(int), rc);
+
+// dup->ProgCur += 5;
+ } // endfor kcp
+
+ if (trace(1))
+ htrc("Index %s saved, Size=%d\n", Xdp->GetName(), size);
+
+ end:
+ X->Close(fn, id);
+ return rc;
+ } // end of SaveIndex
+
+/***********************************************************************/
+/* Init: Open and Initialize a Key Index. */
+/***********************************************************************/
+bool XINDEX::Init(PGLOBAL g)
+ {
+#if defined(XMAP)
+ if (xmap)
+ return MapInit(g);
+#endif // XMAP
+
+ /*********************************************************************/
+ /* Table will be accessed through an index table. */
+ /* If sorting is required, this will be done later. */
+ /*********************************************************************/
+ PCSZ ftype;
+ char fn[_MAX_PATH];
+ int k, n, nv[NZ], id = -1;
+ bool estim = false;
+ PCOL colp;
+ PXCOL prev = NULL, kcp = NULL;
+ PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
+
+ /*********************************************************************/
+ /* Get the estimated table size. */
+ /* Note: for fixed tables we must use cardinality to avoid the call */
+ /* to MaxBlkSize that could reduce the cardinality value. */
+ /*********************************************************************/
+ if (Tdbp->Cardinality(NULL)) {
+ // For DBF tables, Cardinality includes bad or soft deleted lines
+ // that are not included in the index, and can be larger then the
+ // index size.
+ estim = (Tdbp->Ftype == RECFM_DBF || Tdbp->Txfp->GetAmType() == TYPE_AM_ZIP);
+ n = Tdbp->Cardinality(g); // n is exact table size
+ } else {
+ // Variable table not optimized
+ estim = true; // n is an estimate of the size
+ n = Tdbp->GetMaxSize(g);
+ } // endif Cardinality
+
+ if (n <= 0)
+ return !(n == 0); // n < 0 error, n = 0 void table
+
+ /*********************************************************************/
+ /* Get the first key column. */
+ /*********************************************************************/
+ if (!Nk || !To_Cols || (!To_Vals && Op != OP_FIRST && Op != OP_FSTDIF)) {
+ strcpy(g->Message, MSG(NO_KEY_COL));
+ return true; // Error
+ } else
+ colp = To_Cols[0];
+
+ switch (Tdbp->Ftype) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_CSV: ftype = ".cnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
+ return true;
+ } // endswitch Ftype
+
+ if (defp->SepIndex()) {
+ // Index was saved in a separate file
+#if defined(_WIN32)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), Xdp->GetName());
+ _makepath(fn, drive, direc, fname, ftype);
+ } else {
+ id = ID;
+ strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
+ } // endif sep
+
+ PlugSetPath(fn, fn, Tdbp->GetPath());
+
+ if (trace(1))
+ htrc("Index %s file: %s\n", Xdp->GetName(), fn);
+
+ /*********************************************************************/
+ /* Open the index file and check its validity. */
+ /*********************************************************************/
+ if (X->Open(g, fn, id, MODE_READ))
+ goto err; // No saved values
+
+ // Now start the reading process.
+ if (X->Read(g, nv, NZ - 1, sizeof(int)))
+ goto err;
+
+ if (nv[0] >= MAX_INDX) {
+ // New index format
+ if (X->Read(g, nv + 7, 1, sizeof(int)))
+ goto err;
+
+ Srtd = nv[7] != 0;
+ nv[0] -= MAX_INDX;
+ } else
+ Srtd = false;
+
+ if (trace(1))
+ htrc("nv=%d %d %d %d %d %d %d (%d)\n",
+ nv[0], nv[1], nv[2], nv[3], nv[4], nv[5], nv[6], Srtd);
+
+ // The test on ID was suppressed because MariaDB can change an index ID
+ // when other indexes are added or deleted
+ if (/*nv[0] != ID ||*/ nv[1] != Nk) {
+ sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
+
+ if (trace(1))
+ htrc("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk);
+
+ goto err;
+ } // endif
+
+ if (nv[2]) {
+ Mul = true;
+ Ndif = nv[2];
+
+ // Allocate the storage that will contain the offset array
+ Offset.Size = Ndif * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Offset)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "offset", Ndif);
+ goto err;
+ } // endif
+
+ if (X->Read(g, Pof, Ndif, sizeof(int)))
+ goto err;
+
+ Ndif--; // nv[2] is offset size, equal to Ndif + 1
+ } else {
+ Mul = false;
+ Ndif = nv[3];
+ } // endif nv[2]
+
+ if (nv[3] < n && estim)
+ n = nv[3]; // n was just an evaluated max value
+
+ if (nv[3] != n) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
+ goto err;
+ } // endif
+
+ Num_K = nv[3];
+ Incr = nv[4];
+ Nblk = nv[5];
+ Sblk = nv[6];
+
+ if (!Incr) {
+ /*******************************************************************/
+ /* Allocate the storage that will contain the file positions. */
+ /*******************************************************************/
+ Record.Size = Num_K * sizeof(int);
+
+ if (!PlgDBalloc(g, NULL, Record)) {
+ sprintf(g->Message, MSG(MEM_ALLOC_ERR), "index", Num_K);
+ goto err;
+ } // endif
+
+ if (X->Read(g, To_Rec, Num_K, sizeof(int)))
+ goto err;
+
+ } else
+ Srtd = true; // Sorted positions can be calculated
+
+ /*********************************************************************/
+ /* Allocate the KXYCOL blocks used to store column values. */
+ /*********************************************************************/
+ for (k = 0; k < Nk; k++) {
+ if (k == Nval)
+ To_LastVal = prev;
+
+ if (X->Read(g, nv, NW, sizeof(int)))
+ goto err;
+
+ colp = To_Cols[k];
+
+ if (nv[4] != colp->GetResultType() || !colp->GetValue() ||
+ (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
+ sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
+ goto err; // Error
+ } // endif GetKey
+
+ kcp = new(g) KXYCOL(this);
+
+ if (kcp->Init(g, colp, nv[0], true, (int)nv[3]))
+ goto err; // Error
+
+ /*******************************************************************/
+ /* Read the index values from the index file. */
+ /*******************************************************************/
+ if (k == 0 && Nblk) {
+ if (kcp->MakeBlockArray(g, Nblk, 0))
+ goto err;
+
+ // Read block values
+ if (X->Read(g, kcp->To_Bkeys, Nblk, kcp->Klen))
+ goto err;
+
+ } // endif Nblk
+
+ // Read the entire (small) index
+ if (X->Read(g, kcp->To_Keys, nv[0], kcp->Klen))
+ goto err;
+
+ if (nv[1]) {
+ if (!kcp->MakeOffset(g, nv[1] - 1))
+ goto err;
+
+ // Read the offset array
+ if (X->Read(g, kcp->Kof, nv[1], sizeof(int)))
+ goto err;
+
+ } // endif n[1]
+
+ if (!kcp->Prefix)
+ // Indicate that the key column value can be found from KXYCOL
+ colp->SetKcol(kcp);
+
+ if (prev) {
+ kcp->Previous = prev;
+ prev->Next = kcp;
+ } else
+ To_KeyCol = kcp;
+
+ prev = kcp;
+ } // endfor k
+
+ To_LastCol = prev;
+
+ if (Mul && prev) {
+ // Last key offset is the index offset
+ kcp->Koff = Offset;
+ kcp->Koff.Sub = true;
+ } // endif Mul
+
+ X->Close();
+
+ /*********************************************************************/
+ /* No valid record read yet for secondary file. */
+ /*********************************************************************/
+ Cur_K = Num_K;
+ return false;
+
+err:
+ Close();
+ return true;
+ } // end of Init
+
+#if defined(XMAP)
+/***********************************************************************/
+/* Init: Open and Initialize a Key Index. */
+/***********************************************************************/
+bool XINDEX::MapInit(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Table will be accessed through an index table. */
+ /* If sorting is required, this will be done later. */
+ /*********************************************************************/
+ const char *ftype;
+ BYTE *mbase;
+ char fn[_MAX_PATH];
+ int *nv, nv0, k, n, id = -1;
+ bool estim;
+ PCOL colp;
+ PXCOL prev = NULL, kcp = NULL;
+ PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
+
+ /*********************************************************************/
+ /* Get the estimated table size. */
+ /* Note: for fixed tables we must use cardinality to avoid the call */
+ /* to MaxBlkSize that could reduce the cardinality value. */
+ /*********************************************************************/
+ if (Tdbp->Cardinality(NULL)) {
+ // For DBF tables, Cardinality includes bad or soft deleted lines
+ // that are not included in the index, and can be larger then the
+ // index size.
+ estim = (Tdbp->Ftype == RECFM_DBF);
+ n = Tdbp->Cardinality(g); // n is exact table size
+ } else {
+ // Variable table not optimized
+ estim = true; // n is an estimate of the size
+ n = Tdbp->GetMaxSize(g);
+ } // endif Cardinality
+
+ if (n <= 0)
+ return !(n == 0); // n < 0 error, n = 0 void table
+
+ /*********************************************************************/
+ /* Get the first key column. */
+ /*********************************************************************/
+ if (!Nk || !To_Cols || (!To_Vals && Op != OP_FIRST && Op != OP_FSTDIF)) {
+ strcpy(g->Message, MSG(NO_KEY_COL));
+ return true; // Error
+ } else
+ colp = To_Cols[0];
+
+ switch (Tdbp->Ftype) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_CSV: ftype = ".cnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
+ return true;
+ } // endswitch Ftype
+
+ if (defp->SepIndex()) {
+ // Index was save in a separate file
+#if defined(_WIN32)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), Xdp->GetName());
+ _makepath(fn, drive, direc, fname, ftype);
+ } else {
+ id = ID;
+ strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
+ } // endif SepIndex
+
+ PlugSetPath(fn, fn, Tdbp->GetPath());
+
+ if (trace(1))
+ htrc("Index %s file: %s\n", Xdp->GetName(), fn);
+
+ /*********************************************************************/
+ /* Get a view on the part of the index file containing this index. */
+ /*********************************************************************/
+ if (!(mbase = (BYTE*)X->FileView(g, fn)))
+ goto err;
+
+ if (id >= 0) {
+ // Get offset from the header
+ IOFF *noff = (IOFF*)mbase;
+
+ // Position the memory base at the offset of this index
+ mbase += noff[id].v.Low;
+ } // endif id
+
+ // Now start the mapping process.
+ nv = (int*)mbase;
+
+ if (nv[0] >= MAX_INDX) {
+ // New index format
+ Srtd = nv[7] != 0;
+ nv0 = nv[0] - MAX_INDX;
+ mbase += NZ * sizeof(int);
+ } else {
+ Srtd = false;
+ mbase += (NZ - 1) * sizeof(int);
+ nv0 = nv[0];
+ } // endif nv
+
+ if (trace(1))
+ htrc("nv=%d %d %d %d %d %d %d %d\n",
+ nv0, nv[1], nv[2], nv[3], nv[4], nv[5], nv[6], Srtd);
+
+ // The test on ID was suppressed because MariaDB can change an index ID
+ // when other indexes are added or deleted
+ if (/*nv0 != ID ||*/ nv[1] != Nk) {
+ // Not this index
+ sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
+
+ if (trace(1))
+ htrc("nv0=%d ID=%d nv[1]=%d Nk=%d\n", nv0, ID, nv[1], Nk);
+
+ goto err;
+ } // endif nv
+
+ if (nv[2]) {
+ // Set the offset array memory block
+ Offset.Memp = mbase;
+ Offset.Size = nv[2] * sizeof(int);
+ Offset.Sub = true;
+ Mul = true;
+ Ndif = nv[2] - 1;
+ mbase += Offset.Size;
+ } else {
+ Mul = false;
+ Ndif = nv[3];
+ } // endif nv[2]
+
+ if (nv[3] < n && estim)
+ n = nv[3]; // n was just an evaluated max value
+
+ if (nv[3] != n) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
+ goto err;
+ } // endif
+
+ Num_K = nv[3];
+ Incr = nv[4];
+ Nblk = nv[5];
+ Sblk = nv[6];
+
+ if (!Incr) {
+ /*******************************************************************/
+ /* Point to the storage that contains the file positions. */
+ /*******************************************************************/
+ Record.Size = Num_K * sizeof(int);
+ Record.Memp = mbase;
+ Record.Sub = true;
+ mbase += Record.Size;
+ } else
+ Srtd = true; // Sorted positions can be calculated
+
+ /*********************************************************************/
+ /* Allocate the KXYCOL blocks used to store column values. */
+ /*********************************************************************/
+ for (k = 0; k < Nk; k++) {
+ if (k == Nval)
+ To_LastVal = prev;
+
+ nv = (int*)mbase;
+ mbase += (NW * sizeof(int));
+
+ colp = To_Cols[k];
+
+ if (nv[4] != colp->GetResultType() || !colp->GetValue() ||
+ (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
+ sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
+ goto err; // Error
+ } // endif GetKey
+
+ kcp = new(g) KXYCOL(this);
+
+ if (!(mbase = kcp->MapInit(g, colp, nv, mbase)))
+ goto err;
+
+ if (!kcp->Prefix)
+ // Indicate that the key column value can be found from KXYCOL
+ colp->SetKcol(kcp);
+
+ if (prev) {
+ kcp->Previous = prev;
+ prev->Next = kcp;
+ } else
+ To_KeyCol = kcp;
+
+ prev = kcp;
+ } // endfor k
+
+ To_LastCol = prev;
+
+ if (Mul && prev)
+ // Last key offset is the index offset
+ kcp->Koff = Offset;
+
+ /*********************************************************************/
+ /* No valid record read yet for secondary file. */
+ /*********************************************************************/
+ Cur_K = Num_K;
+ return false;
+
+err:
+ Close();
+ return true;
+ } // end of MapInit
+#endif // XMAP
+
+/***********************************************************************/
+/* Get Ndif and Num_K from the index file. */
+/***********************************************************************/
+bool XINDEX::GetAllSizes(PGLOBAL g,/* int &ndif,*/ int &numk)
+ {
+ PCSZ ftype;
+ char fn[_MAX_PATH];
+ int nv[NZ], id = -1; // n
+//bool estim = false;
+ bool rc = true;
+ PDOSDEF defp = (PDOSDEF)Tdbp->To_Def;
+
+// ndif = numk = 0;
+ numk = 0;
+
+#if 0
+ /*********************************************************************/
+ /* Get the estimated table size. */
+ /* Note: for fixed tables we must use cardinality to avoid the call */
+ /* to MaxBlkSize that could reduce the cardinality value. */
+ /*********************************************************************/
+ if (Tdbp->Cardinality(NULL)) {
+ // For DBF tables, Cardinality includes bad or soft deleted lines
+ // that are not included in the index, and can be larger then the
+ // index size.
+ estim = (Tdbp->Ftype == RECFM_DBF);
+ n = Tdbp->Cardinality(g); // n is exact table size
+ } else {
+ // Variable table not optimized
+ estim = true; // n is an estimate of the size
+ n = Tdbp->GetMaxSize(g);
+ } // endif Cardinality
+
+ if (n <= 0)
+ return !(n == 0); // n < 0 error, n = 0 void table
+
+ /*********************************************************************/
+ /* Check the key part number. */
+ /*********************************************************************/
+ if (!Nk) {
+ strcpy(g->Message, MSG(NO_KEY_COL));
+ return true; // Error
+ } // endif Nk
+#endif // 0
+
+ switch (Tdbp->Ftype) {
+ case RECFM_VAR: ftype = ".dnx"; break;
+ case RECFM_FIX: ftype = ".fnx"; break;
+ case RECFM_BIN: ftype = ".bnx"; break;
+ case RECFM_VCT: ftype = ".vnx"; break;
+ case RECFM_CSV: ftype = ".cnx"; break;
+ case RECFM_DBF: ftype = ".dbx"; break;
+ default:
+ sprintf(g->Message, MSG(INVALID_FTYPE), Tdbp->Ftype);
+ return true;
+ } // endswitch Ftype
+
+ if (defp->SepIndex()) {
+ // Index was saved in a separate file
+#if defined(_WIN32)
+ char drive[_MAX_DRIVE];
+#else
+ char *drive = NULL;
+#endif
+ char direc[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ _splitpath(defp->GetOfn(), drive, direc, fname, NULL);
+ strcat(strcat(fname, "_"), Xdp->GetName());
+ _makepath(fn, drive, direc, fname, ftype);
+ } else {
+ id = ID;
+ strcat(PlugRemoveType(fn, strcpy(fn, defp->GetOfn())), ftype);
+ } // endif sep
+
+ PlugSetPath(fn, fn, Tdbp->GetPath());
+
+ if (trace(1))
+ htrc("Index %s file: %s\n", Xdp->GetName(), fn);
+
+ /*********************************************************************/
+ /* Open the index file and check its validity. */
+ /*********************************************************************/
+ if (X->Open(g, fn, id, MODE_READ))
+ goto err; // No saved values
+
+ // Get offset from XDB file
+//if (X->Seek(g, Defoff, Defhigh, SEEK_SET))
+// goto err;
+
+ // Now start the reading process.
+ if (X->Read(g, nv, NZ, sizeof(int)))
+ goto err;
+
+ if (trace(1))
+ htrc("nv=%d %d %d %d\n", nv[0], nv[1], nv[2], nv[3]);
+
+ // The test on ID was suppressed because MariaDB can change an index ID
+ // when other indexes are added or deleted
+ if (/*nv[0] != ID ||*/ nv[1] != Nk) {
+ sprintf(g->Message, MSG(BAD_INDEX_FILE), fn);
+
+ if (trace(1))
+ htrc("nv[0]=%d ID=%d nv[1]=%d Nk=%d\n", nv[0], ID, nv[1], Nk);
+
+ goto err;
+ } // endif
+
+#if 0
+ if (nv[2]) {
+ Mul = true;
+ Ndif = nv[2] - 1; // nv[2] is offset size, equal to Ndif + 1
+ } else {
+ Mul = false;
+ Ndif = nv[3];
+ } // endif nv[2]
+
+ if (nv[3] < n && estim)
+ n = nv[3]; // n was just an evaluated max value
+
+ if (nv[3] != n) {
+ sprintf(g->Message, MSG(OPT_NOT_MATCH), fn);
+ goto err;
+ } // endif
+#endif // 0
+
+ Num_K = nv[3];
+
+#if 0
+ if (Nk > 1) {
+ if (nv[2] && X->Seek(g, nv[2] * sizeof(int), 0, SEEK_CUR))
+ goto err;
+
+ if (!nv[4] && X->Seek(g, Num_K * sizeof(int), 0, SEEK_CUR))
+ goto err;
+
+ if (X->Read(g, nv, NW, sizeof(int)))
+ goto err;
+
+ PCOL colp = *To_Cols;
+
+ if (nv[4] != colp->GetResultType() ||
+ (nv[3] != colp->GetValue()->GetClen() && nv[4] != TYPE_STRING)) {
+ sprintf(g->Message, MSG(XCOL_MISMATCH), colp->GetName());
+ goto err; // Error
+ } // endif GetKey
+
+ Ndif = nv[0];
+ } // endif Nk
+#endif // 0
+
+ /*********************************************************************/
+ /* Set size values. */
+ /*********************************************************************/
+//ndif = Ndif;
+ numk = Num_K;
+ rc = false;
+
+err:
+ X->Close();
+ return rc;
+ } // end of GetAllSizes
+
+/***********************************************************************/
+/* RANGE: Tell how many records exist for a given value, for an array */
+/* of values, or in a given value range. */
+/***********************************************************************/
+int XINDEX::Range(PGLOBAL g, int limit, bool incl)
+ {
+ int i, k, n = 0;
+ PXOB *xp = To_Vals;
+ PXCOL kp = To_KeyCol;
+ OPVAL op = Op;
+
+ switch (limit) {
+ case 1: Op = (incl) ? OP_GE : OP_GT; break;
+ case 2: Op = (incl) ? OP_GT : OP_GE; break;
+ default: return 0;
+ } // endswitch limit
+
+ /*********************************************************************/
+ /* Currently only range of constant values with an EQ operator is */
+ /* implemented. Find the number of rows for each given values. */
+ /*********************************************************************/
+ if (xp[0]->GetType() == TYPE_CONST) {
+ for (i = 0; kp; kp = kp->Next) {
+ kp->Valp->SetValue_pval(xp[i]->GetValue(), !kp->Prefix);
+ if (++i == Nval) break;
+ } // endfor kp
+
+ if ((k = FastFind()) < Num_K)
+ n = k;
+// if (limit)
+// n = (Mul) ? k : kp->Val_K;
+// else
+// n = (Mul) ? Pof[kp->Val_K + 1] - k : 1;
+
+ } else {
+ strcpy(g->Message, MSG(RANGE_NO_JOIN));
+ n = -1; // Logical error
+ } // endif'f Type
+
+ Op = op;
+ return n;
+ } // end of Range
+
+/***********************************************************************/
+/* Return the size of the group (equal values) of the current value. */
+/***********************************************************************/
+int XINDEX::GroupSize(void)
+ {
+#if defined(_DEBUG)
+ assert(To_LastCol->Val_K >= 0 && To_LastCol->Val_K < Ndif);
+#endif // _DEBUG
+
+ if (Nval == Nk)
+ return (Pof) ? Pof[To_LastCol->Val_K + 1] - Pof[To_LastCol->Val_K]
+ : 1;
+
+#if defined(_DEBUG)
+ assert(To_LastVal);
+#endif // _DEBUG
+
+ // Index whose only some columns are used
+ int ck1, ck2;
+
+ ck1 = To_LastVal->Val_K;
+ ck2 = ck1 + 1;
+
+#if defined(_DEBUG)
+ assert(ck1 >= 0 && ck1 < To_LastVal->Ndf);
+#endif // _DEBUG
+
+ for (PXCOL kcp = To_LastVal; kcp; kcp = kcp->Next) {
+ ck1 = (kcp->Kof) ? kcp->Kof[ck1] : ck1;
+ ck2 = (kcp->Kof) ? kcp->Kof[ck2] : ck2;
+ } // endfor kcp
+
+ return ck2 - ck1;
+ } // end of GroupSize
+
+/***********************************************************************/
+/* Find Cur_K and Val_K's of the next distinct value of the index. */
+/* Returns false if Ok, true if there are no more different values. */
+/***********************************************************************/
+bool XINDEX::NextValDif(void)
+ {
+ int curk;
+ PXCOL kcp = (To_LastVal) ? To_LastVal : To_LastCol;
+
+ if (++kcp->Val_K < kcp->Ndf) {
+ Cur_K = curk = kcp->Val_K;
+
+ // (Cur_K return is currently not used by SQLGBX)
+ for (PXCOL kp = kcp; kp; kp = kp->Next)
+ Cur_K = (kp->Kof) ? kp->Kof[Cur_K] : Cur_K;
+
+ } else
+ return true;
+
+ for (kcp = kcp->Previous; kcp; kcp = kcp->Previous) {
+ if (kcp->Kof && curk < kcp->Kof[kcp->Val_K + 1])
+ break; // all previous columns have same value
+
+ curk = ++kcp->Val_K; // This is a break, get new column value
+ } // endfor kcp
+
+ return false;
+ } // end of NextValDif
+
+/***********************************************************************/
+/* XINDEX: Find Cur_K and Val_K's of next index entry. */
+/* If eq is true next values must be equal to last ones up to Nval. */
+/* Returns false if Ok, true if there are no more (equal) values. */
+/***********************************************************************/
+bool XINDEX::NextVal(bool eq)
+ {
+ int n, neq = Nk + 1, curk;
+ PXCOL kcp;
+
+ if (Cur_K == Num_K)
+ return true;
+ else
+ curk = ++Cur_K;
+
+ for (n = Nk, kcp = To_LastCol; kcp; n--, kcp = kcp->Previous) {
+ if (kcp->Kof) {
+ if (curk == kcp->Kof[kcp->Val_K + 1])
+ neq = n;
+
+ } else {
+#ifdef _DEBUG
+ assert(curk == kcp->Val_K + 1);
+#endif // _DEBUG
+ neq = n;
+ } // endif Kof
+
+#ifdef _DEBUG
+ assert(kcp->Val_K < kcp->Ndf);
+#endif // _DEBUG
+
+ // If this is not a break...
+ if (neq > n)
+ break; // all previous columns have same value
+
+ curk = ++kcp->Val_K; // This is a break, get new column value
+ } // endfor kcp
+
+ // Return true if no more values or, in case of "equal" values,
+ // if the last used column value has changed
+ return (Cur_K == Num_K || (eq && neq <= Nval));
+ } // end of NextVal
+
+/***********************************************************************/
+/* XINDEX: Find Cur_K and Val_K's of previous index entry. */
+/* Returns false if Ok, true if there are no more values. */
+/***********************************************************************/
+bool XINDEX::PrevVal(void)
+ {
+ int n, neq = Nk + 1, curk;
+ PXCOL kcp;
+
+ if (Cur_K == 0)
+ return true;
+ else
+ curk = --Cur_K;
+
+ for (n = Nk, kcp = To_LastCol; kcp; n--, kcp = kcp->Previous) {
+ if (kcp->Kof) {
+ if (curk < kcp->Kof[kcp->Val_K])
+ neq = n;
+
+ } else {
+#ifdef _DEBUG
+ assert(curk == kcp->Val_K -1);
+#endif // _DEBUG
+ neq = n;
+ } // endif Kof
+
+#ifdef _DEBUG
+ assert(kcp->Val_K >= 0);
+#endif // _DEBUG
+
+ // If this is not a break...
+ if (neq > n)
+ break; // all previous columns have same value
+
+ curk = --kcp->Val_K; // This is a break, get new column value
+ } // endfor kcp
+
+ return false;
+ } // end of PrevVal
+
+/***********************************************************************/
+/* XINDEX: Fetch a physical or logical record. */
+/***********************************************************************/
+int XINDEX::Fetch(PGLOBAL g)
+ {
+ int n;
+ PXCOL kp;
+
+ if (Num_K == 0)
+ return -1; // means end of file
+
+ if (trace(2))
+ htrc("XINDEX Fetch: Op=%d\n", Op);
+
+ /*********************************************************************/
+ /* Table read through a sorted index. */
+ /*********************************************************************/
+ switch (Op) {
+ case OP_NEXT: // Read next
+ if (NextVal(false))
+ return -1; // End of indexed file
+
+ break;
+ case OP_FIRST: // Read first
+ for (Cur_K = 0, kp = To_KeyCol; kp; kp = kp->Next)
+ kp->Val_K = 0;
+
+ Op = OP_NEXT;
+ break;
+ case OP_SAME: // Read next same
+ // Logically the key values should be the same as before
+ if (NextVal(true)) {
+ Op = OP_EQ;
+ return -2; // no more equal values
+ } // endif NextVal
+
+ break;
+ case OP_NXTDIF: // Read next dif
+// while (!NextVal(true)) ;
+
+// if (Cur_K >= Num_K)
+// return -1; // End of indexed file
+ if (NextValDif())
+ return -1; // End of indexed file
+
+ break;
+ case OP_FSTDIF: // Read first diff
+ for (Cur_K = 0, kp = To_KeyCol; kp; kp = kp->Next)
+ kp->Val_K = 0;
+
+ Op = (Mul || Nval < Nk) ? OP_NXTDIF : OP_NEXT;
+ break;
+ case OP_LAST: // Read last key
+ for (Cur_K = Num_K - 1, kp = To_KeyCol; kp; kp = kp->Next)
+ kp->Val_K = kp->Kblp->GetNval() - 1;
+
+ Op = OP_NEXT;
+ break;
+ case OP_PREV: // Read previous
+ if (PrevVal())
+ return -1; // End of indexed file
+
+ break;
+ default: // Should be OP_EQ
+// if (Tbxp->Key_Rank < 0) {
+ /***************************************************************/
+ /* Look for the first key equal to the link column values */
+ /* and return its rank whithin the index table. */
+ /***************************************************************/
+ for (n = 0, kp = To_KeyCol; n < Nval && kp; n++, kp = kp->Next)
+ if (kp->InitFind(g, To_Vals[n]))
+ return -1; // No more constant values
+
+ Nth++;
+
+ if (trace(2))
+ htrc("Fetch: Looking for new value Nth=%d\n", Nth);
+
+ Cur_K = FastFind();
+
+ if (Cur_K >= Num_K)
+ /*************************************************************/
+ /* Rank not whithin index table, signal record not found. */
+ /*************************************************************/
+ return -2;
+
+ else if (Mul || Nval < Nk)
+ Op = OP_SAME;
+
+ } // endswitch Op
+
+ /*********************************************************************/
+ /* If rank is equal to stored rank, record is already there. */
+ /*********************************************************************/
+ if (Cur_K == Old_K)
+ return -3; // Means record already there
+ else
+ Old_K = Cur_K; // Store rank of newly read record
+
+ /*********************************************************************/
+ /* Return the position of the required record. */
+ /*********************************************************************/
+ return (Incr) ? Cur_K * Incr : To_Rec[Cur_K];
+ } // end of Fetch
+
+/***********************************************************************/
+/* FastFind: Returns the index of matching record in a join using an */
+/* optimized algorithm based on dichotomie and optimized comparing. */
+/***********************************************************************/
+int XINDEX::FastFind(void)
+ {
+ int curk, sup, inf, i= 0, k, n = 2;
+ PXCOL kp, kcp;
+
+//assert((int)nv == Nval);
+
+ if (Nblk && Op == OP_EQ) {
+ // Look in block values to find in which block to search
+ sup = Nblk;
+ inf = -1;
+
+ while (n && sup - inf > 1) {
+ i = (inf + sup) >> 1;
+
+ n = To_KeyCol->CompBval(i);
+
+ if (n < 0)
+ sup = i;
+ else
+ inf = i;
+
+ } // endwhile
+
+ if (inf < 0)
+ return Num_K;
+
+// i = inf;
+ inf *= Sblk;
+
+ if ((sup = inf + Sblk) > To_KeyCol->Ndf)
+ sup = To_KeyCol->Ndf;
+
+ inf--;
+ } else {
+ inf = -1;
+ sup = To_KeyCol->Ndf;
+ } // endif Nblk
+
+ if (trace(4))
+ htrc("XINDEX FastFind: Nblk=%d Op=%d inf=%d sup=%d\n",
+ Nblk, Op, inf, sup);
+
+ for (k = 0, kcp = To_KeyCol; kcp; kcp = kcp->Next) {
+ while (sup - inf > 1) {
+ i = (inf + sup) >> 1;
+
+ n = kcp->CompVal(i);
+
+ if (n < 0)
+ sup = i;
+ else if (n > 0)
+ inf = i;
+ else
+ break;
+
+ } // endwhile
+
+ if (n) {
+ if (Op != OP_EQ) {
+ // Currently only OP_GT or OP_GE
+ kcp->Val_K = curk = sup;
+
+ // Check for value changes in previous key parts
+ for (kp = kcp->Previous; kp; kp = kp->Previous)
+ if (kp->Kof && curk < kp->Kof[kp->Val_K + 1])
+ break;
+ else
+ curk = ++kp->Val_K;
+
+ n = 0;
+ } // endif Op
+
+ break;
+ } // endif n
+
+ kcp->Val_K = i;
+
+ if (++k == Nval) {
+ if (Op == OP_GT) { // n is always 0
+ curk = ++kcp->Val_K; // Increment value by 1
+
+ // Check for value changes in previous key parts
+ for (kp = kcp->Previous; kp; kp = kp->Previous)
+ if (kp->Kof && curk < kp->Kof[kp->Val_K + 1])
+ break; // Not changed
+ else
+ curk = ++kp->Val_K;
+
+ } // endif Op
+
+ break; // So kcp remains pointing the last tested block
+ } // endif k
+
+ if (kcp->Kof) {
+ inf = kcp->Kof[i] - 1;
+ sup = kcp->Kof[i + 1];
+ } else {
+ inf = i - 1;
+ sup = i + 1;
+ } // endif Kof
+
+ } // endfor k, kcp
+
+ if (n) {
+ // Record not found
+ for (kcp = To_KeyCol; kcp; kcp = kcp->Next)
+ kcp->Val_K = kcp->Ndf; // Not a valid value
+
+ return Num_K;
+ } // endif n
+
+ for (curk = kcp->Val_K; kcp; kcp = kcp->Next) {
+ kcp->Val_K = curk;
+ curk = (kcp->Kof) ? kcp->Kof[kcp->Val_K] : kcp->Val_K;
+ } // endfor kcp
+
+ if (trace(4))
+ htrc("XINDEX FastFind: curk=%d\n", curk);
+
+ return curk;
+ } // end of FastFind
+
+/* -------------------------- XINDXS Class --------------------------- */
+
+/***********************************************************************/
+/* XINDXS public constructor. */
+/***********************************************************************/
+XINDXS::XINDXS(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp, PCOL *cp, PXOB *xp)
+ : XINDEX(tdbp, xdp, pxp, cp, xp)
+ {
+ Srtd = To_Cols[0]->GetOpt() == 2;
+ } // end of XINDXS constructor
+
+/***********************************************************************/
+/* XINDXS compare routine for C Quick/Insertion sort. */
+/***********************************************************************/
+int XINDXS::Qcompare(int *i1, int *i2)
+ {
+//num_comp++;
+ return To_KeyCol->Compare(*i1, *i2);
+ } // end of Qcompare
+
+/***********************************************************************/
+/* Range: Tell how many records exist for given value(s): */
+/* If limit=0 return range for these values. */
+/* If limit=1 return the start of range. */
+/* If limit=2 return the end of range. */
+/***********************************************************************/
+int XINDXS::Range(PGLOBAL g, int limit, bool incl)
+ {
+ int k, n = 0;
+ PXOB xp = To_Vals[0];
+ PXCOL kp = To_KeyCol;
+ OPVAL op = Op;
+
+ switch (limit) {
+ case 1: Op = (incl) ? OP_GE : OP_GT; break;
+ case 2: Op = (incl) ? OP_GT : OP_GE; break;
+ default: Op = OP_EQ;
+ } // endswitch limit
+
+ /*********************************************************************/
+ /* Currently only range of constant values with an EQ operator is */
+ /* implemented. Find the number of rows for each given values. */
+ /*********************************************************************/
+ if (xp->GetType() == TYPE_CONST) {
+ kp->Valp->SetValue_pval(xp->GetValue(), !kp->Prefix);
+ k = FastFind();
+
+ if (k < Num_K || Op != OP_EQ)
+ {
+ if (limit)
+ n = (Mul) ? k : kp->Val_K;
+ else
+ n = (Mul) ? Pof[kp->Val_K + 1] - k : 1;
+ }
+ } else {
+ strcpy(g->Message, MSG(RANGE_NO_JOIN));
+ n = -1; // Logical error
+ } // endif'f Type
+
+ Op = op;
+ return n;
+ } // end of Range
+
+/***********************************************************************/
+/* Return the size of the group (equal values) of the current value. */
+/***********************************************************************/
+int XINDXS::GroupSize(void)
+ {
+#if defined(_DEBUG)
+ assert(To_KeyCol->Val_K >= 0 && To_KeyCol->Val_K < Ndif);
+#endif // _DEBUG
+ return (Pof) ? Pof[To_KeyCol->Val_K + 1] - Pof[To_KeyCol->Val_K] : 1;
+ } // end of GroupSize
+
+/***********************************************************************/
+/* XINDXS: Find Cur_K and Val_K of previous index value. */
+/* Returns false if Ok, true if there are no more values. */
+/***********************************************************************/
+bool XINDXS::PrevVal(void)
+ {
+ if (--Cur_K < 0)
+ return true;
+
+ if (Mul) {
+ if (Cur_K < Pof[To_KeyCol->Val_K])
+ To_KeyCol->Val_K--;
+
+ } else
+ To_KeyCol->Val_K = Cur_K;
+
+ return false;
+ } // end of PrevVal
+
+/***********************************************************************/
+/* XINDXS: Find Cur_K and Val_K of next index value. */
+/* If b is true next value must be equal to last one. */
+/* Returns false if Ok, true if there are no more (equal) values. */
+/***********************************************************************/
+bool XINDXS::NextVal(bool eq)
+ {
+ bool rc;
+
+ if (To_KeyCol->Val_K == Ndif)
+ return true;
+
+ if (Mul) {
+ int limit = Pof[To_KeyCol->Val_K + 1];
+
+#ifdef _DEBUG
+ assert(Cur_K < limit);
+ assert(To_KeyCol->Val_K < Ndif);
+#endif // _DEBUG
+
+ if (++Cur_K == limit) {
+ To_KeyCol->Val_K++;
+ rc = (eq || limit == Num_K);
+ } else
+ rc = false;
+
+ } else
+ rc = (To_KeyCol->Val_K = ++Cur_K) == Num_K || eq;
+
+ return rc;
+ } // end of NextVal
+
+/***********************************************************************/
+/* XINDXS: Fetch a physical or logical record. */
+/***********************************************************************/
+int XINDXS::Fetch(PGLOBAL g)
+ {
+ if (Num_K == 0)
+ return -1; // means end of file
+
+ if (trace(2))
+ htrc("XINDXS Fetch: Op=%d\n", Op);
+
+ /*********************************************************************/
+ /* Table read through a sorted index. */
+ /*********************************************************************/
+ switch (Op) {
+ case OP_NEXT: // Read next
+ if (NextVal(false))
+ return -1; // End of indexed file
+
+ break;
+ case OP_FIRST: // Read first
+ To_KeyCol->Val_K = Cur_K = 0;
+ Op = OP_NEXT;
+ break;
+ case OP_SAME: // Read next same
+ if (!Mul || NextVal(true)) {
+ Op = OP_EQ;
+ return -2; // No more equal values
+ } // endif Mul
+
+ break;
+ case OP_NXTDIF: // Read next dif
+ if (++To_KeyCol->Val_K == Ndif)
+ return -1; // End of indexed file
+
+ Cur_K = Pof[To_KeyCol->Val_K];
+ break;
+ case OP_FSTDIF: // Read first diff
+ To_KeyCol->Val_K = Cur_K = 0;
+ Op = (Mul) ? OP_NXTDIF : OP_NEXT;
+ break;
+ case OP_LAST: // Read first
+ Cur_K = Num_K - 1;
+ To_KeyCol->Val_K = Ndif - 1;
+ Op = OP_PREV;
+ break;
+ case OP_PREV: // Read previous
+ if (PrevVal())
+ return -1; // End of indexed file
+
+ break;
+ default: // Should be OP_EQ
+ /*****************************************************************/
+ /* Look for the first key equal to the link column values */
+ /* and return its rank whithin the index table. */
+ /*****************************************************************/
+ if (To_KeyCol->InitFind(g, To_Vals[0]))
+ return -1; // No more constant values
+ else
+ Nth++;
+
+ if (trace(2))
+ htrc("Fetch: Looking for new value Nth=%d\n", Nth);
+
+ Cur_K = FastFind();
+
+ if (Cur_K >= Num_K)
+ // Rank not whithin index table, signal record not found
+ return -2;
+ else if (Mul)
+ Op = OP_SAME;
+
+ } // endswitch Op
+
+ /*********************************************************************/
+ /* If rank is equal to stored rank, record is already there. */
+ /*********************************************************************/
+ if (Cur_K == Old_K)
+ return -3; // Means record already there
+ else
+ Old_K = Cur_K; // Store rank of newly read record
+
+ /*********************************************************************/
+ /* Return the position of the required record. */
+ /*********************************************************************/
+ return (Incr) ? Cur_K * Incr : To_Rec[Cur_K];
+ } // end of Fetch
+
+/***********************************************************************/
+/* FastFind: Returns the index of matching indexed record using an */
+/* optimized algorithm based on dichotomie and optimized comparing. */
+/***********************************************************************/
+int XINDXS::FastFind(void)
+ {
+ int sup, inf, i= 0, n = 2;
+ PXCOL kcp = To_KeyCol;
+
+ if (Nblk && Op == OP_EQ) {
+ // Look in block values to find in which block to search
+ sup = Nblk;
+ inf = -1;
+
+ while (n && sup - inf > 1) {
+ i = (inf + sup) >> 1;
+
+ n = kcp->CompBval(i);
+
+ if (n < 0)
+ sup = i;
+ else
+ inf = i;
+
+ } // endwhile
+
+ if (inf < 0)
+ return Num_K;
+
+ inf *= Sblk;
+
+ if ((sup = inf + Sblk) > Ndif)
+ sup = Ndif;
+
+ inf--;
+ } else {
+ inf = -1;
+ sup = Ndif;
+ } // endif Nblk
+
+ if (trace(4))
+ htrc("XINDXS FastFind: Nblk=%d Op=%d inf=%d sup=%d\n",
+ Nblk, Op, inf, sup);
+
+ while (sup - inf > 1) {
+ i = (inf + sup) >> 1;
+
+ n = kcp->CompVal(i);
+
+ if (n < 0)
+ sup = i;
+ else if (n > 0)
+ inf = i;
+ else
+ break;
+
+ } // endwhile
+
+ if (!n && Op == OP_GT) {
+ ++i;
+ } else if (n && Op != OP_EQ) {
+ // Currently only OP_GT or OP_GE
+ i = sup;
+ n = 0;
+ } // endif sup
+
+ if (trace(4))
+ htrc("XINDXS FastFind: n=%d i=%d\n", n, i);
+
+ // Loop on kcp because of dynamic indexing
+ for (; kcp; kcp = kcp->Next)
+ kcp->Val_K = i; // Used by FillValue
+
+ return ((n) ? Num_K : (Mul) ? Pof[i] : i);
+ } // end of FastFind
+
+/* -------------------------- XLOAD Class --------------------------- */
+
+/***********************************************************************/
+/* XLOAD constructor. */
+/***********************************************************************/
+XLOAD::XLOAD(void)
+ {
+ Hfile = INVALID_HANDLE_VALUE;
+ NewOff.Val = 0LL;
+} // end of XLOAD constructor
+
+/***********************************************************************/
+/* Close the index huge file. */
+/***********************************************************************/
+void XLOAD::Close(void)
+ {
+ if (Hfile != INVALID_HANDLE_VALUE) {
+ CloseFileHandle(Hfile);
+ Hfile = INVALID_HANDLE_VALUE;
+ } // endif Hfile
+
+ } // end of Close
+
+/* --------------------------- XFILE Class --------------------------- */
+
+/***********************************************************************/
+/* XFILE constructor. */
+/***********************************************************************/
+XFILE::XFILE(void) : XLOAD()
+ {
+ Xfile = NULL;
+#if defined(XMAP)
+ Mmp = NULL;
+#endif // XMAP
+ } // end of XFILE constructor
+
+/***********************************************************************/
+/* Xopen function: opens a file using native API's. */
+/***********************************************************************/
+bool XFILE::Open(PGLOBAL g, char *filename, int id, MODE mode)
+ {
+ PCSZ pmod;
+ bool rc;
+ IOFF noff[MAX_INDX];
+
+ /*********************************************************************/
+ /* Open the index file according to mode. */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ: pmod = "rb"; break;
+ case MODE_WRITE: pmod = "wb"; break;
+ case MODE_INSERT: pmod = "ab"; break;
+ default:
+ sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
+ return true;
+ } // endswitch mode
+
+ if (!(Xfile= global_fopen(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, pmod))) {
+ if (trace(1))
+ htrc("Open: %s\n", g->Message);
+
+ return true;
+ } // endif Xfile
+
+ if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* Position the cursor at end of file so ftell returns file size. */
+ /*******************************************************************/
+ if (fseek(Xfile, 0, SEEK_END)) {
+ sprintf(g->Message, MSG(FUNC_ERRNO), errno, "Xseek");
+ return true;
+ } // endif
+
+ NewOff.v.Low = (int)ftell(Xfile);
+
+ if (trace(1))
+ htrc("XFILE Open: NewOff.v.Low=%d\n", NewOff.v.Low);
+
+ } else if (mode == MODE_WRITE) {
+ if (id >= 0) {
+ // New not sep index file. Write the header.
+ memset(noff, 0, sizeof(noff));
+ Write(g, noff, sizeof(IOFF), MAX_INDX, rc);
+ fseek(Xfile, 0, SEEK_END);
+ NewOff.v.Low = (int)ftell(Xfile);
+
+ if (trace(1))
+ htrc("XFILE Open: NewOff.v.Low=%d\n", NewOff.v.Low);
+
+ } // endif id
+
+ } else if (mode == MODE_READ && id >= 0) {
+ // Get offset from the header
+ if (fread(noff, sizeof(IOFF), MAX_INDX, Xfile) != MAX_INDX) {
+ sprintf(g->Message, MSG(XFILE_READERR), errno);
+ return true;
+ } // endif MAX_INDX
+
+ if (trace(1))
+ htrc("XFILE Open: noff[%d].v.Low=%d\n", id, noff[id].v.Low);
+
+ // Position the cursor at the offset of this index
+ if (fseek(Xfile, noff[id].v.Low, SEEK_SET)) {
+ sprintf(g->Message, MSG(FUNC_ERRNO), errno, "Xseek");
+ return true;
+ } // endif
+
+ } // endif mode
+
+ return false;
+ } // end of Open
+
+/***********************************************************************/
+/* Move into an index file. */
+/***********************************************************************/
+bool XFILE::Seek(PGLOBAL g, int low, int high __attribute__((unused)),
+ int origin)
+ {
+#if defined(_DEBUG)
+ assert(high == 0);
+#endif // !_DEBUG
+
+ if (fseek(Xfile, low, origin)) {
+ sprintf(g->Message, MSG(FUNC_ERRNO), errno, "Xseek");
+ return true;
+ } // endif
+
+ return false;
+ } // end of Seek
+
+/***********************************************************************/
+/* Read from the index file. */
+/***********************************************************************/
+bool XFILE::Read(PGLOBAL g, void *buf, int n, int size)
+ {
+ if (fread(buf, size, n, Xfile) != (size_t)n) {
+ sprintf(g->Message, MSG(XFILE_READERR), errno);
+ return true;
+ } // endif size
+
+ return false;
+ } // end of Read
+
+/***********************************************************************/
+/* Write on index file, set rc and return the number of bytes written */
+/***********************************************************************/
+int XFILE::Write(PGLOBAL g, void *buf, int n, int size, bool& rc)
+ {
+ int niw = (int)fwrite(buf, size, n, Xfile);
+
+ if (niw != n) {
+ sprintf(g->Message, MSG(XFILE_WRITERR), strerror(errno));
+ rc = true;
+ } // endif size
+
+ return niw * size;
+ } // end of Write
+
+/***********************************************************************/
+/* Update the file header and close the index file. */
+/***********************************************************************/
+void XFILE::Close(char *fn, int id)
+ {
+ if (id >= 0 && fn && Xfile) {
+ fclose(Xfile);
+
+ if ((Xfile = fopen(fn, "r+b")))
+ if (!fseek(Xfile, id * sizeof(IOFF), SEEK_SET))
+ fwrite(&NewOff, sizeof(int), 2, Xfile);
+
+ } // endif id
+
+ Close();
+ } // end of Close
+
+/***********************************************************************/
+/* Close the index file. */
+/***********************************************************************/
+void XFILE::Close(void)
+ {
+ XLOAD::Close();
+
+ if (Xfile) {
+ fclose(Xfile);
+ Xfile = NULL;
+ } // endif Xfile
+
+#if defined(XMAP)
+ if (Mmp && CloseMemMap(Mmp->memory, Mmp->lenL))
+ printf("Error closing mapped index\n");
+#endif // XMAP
+ } // end of Close
+
+#if defined(XMAP)
+ /*********************************************************************/
+ /* Map the entire index file. */
+ /*********************************************************************/
+void *XFILE::FileView(PGLOBAL g, char *fn)
+ {
+ HANDLE h;
+
+ Mmp = (MMP)PlugSubAlloc(g, NULL, sizeof(MEMMAP));
+ h = CreateFileMap(g, fn, Mmp, MODE_READ, false);
+
+ if (h == INVALID_HANDLE_VALUE || (!Mmp->lenH && !Mmp->lenL)) {
+ if (!(*g->Message))
+ strcpy(g->Message, MSG(FILE_MAP_ERR));
+
+ CloseFileHandle(h); // Not used anymore
+ return NULL; // No saved values
+ } // endif h
+
+ CloseFileHandle(h); // Not used anymore
+ return Mmp->memory;
+ } // end of FileView
+#endif // XMAP
+
+/* -------------------------- XHUGE Class --------------------------- */
+
+/***********************************************************************/
+/* Xopen function: opens a file using native API's. */
+/***********************************************************************/
+bool XHUGE::Open(PGLOBAL g, char *filename, int id, MODE mode)
+ {
+ IOFF noff[MAX_INDX];
+
+ if (Hfile != INVALID_HANDLE_VALUE) {
+ sprintf(g->Message, MSG(FILE_OPEN_YET), filename);
+ return true;
+ } // endif
+
+ if (trace(1))
+ htrc(" Xopen: filename=%s id=%d mode=%d\n", filename, id, mode);
+
+#if defined(_WIN32)
+ LONG high = 0;
+ DWORD rc, drc, access, share, creation;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ access = GENERIC_READ;
+ share = FILE_SHARE_READ;
+ creation = OPEN_EXISTING;
+ break;
+ case MODE_WRITE:
+ access = GENERIC_WRITE;
+ share = 0;
+ creation = CREATE_ALWAYS;
+ break;
+ case MODE_INSERT:
+ access = GENERIC_WRITE;
+ share = 0;
+ creation = OPEN_EXISTING;
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
+ return true;
+ } // endswitch
+
+ Hfile = CreateFile(filename, access, share, NULL, creation,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ rc = GetLastError();
+ sprintf(g->Message, MSG(OPEN_ERROR), rc, mode, filename);
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, rc, 0,
+ (LPTSTR)filename, sizeof(filename), NULL);
+ strcat(g->Message, filename);
+ return true;
+ } // endif Hfile
+
+ if (trace(1))
+ htrc(" access=%p share=%p creation=%d handle=%p fn=%s\n",
+ access, share, creation, Hfile, filename);
+
+ if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* In Insert mode we must position the cursor at end of file. */
+ /*******************************************************************/
+ rc = SetFilePointer(Hfile, 0, &high, FILE_END);
+
+ if (rc == INVALID_SET_FILE_POINTER && (drc = GetLastError()) != NO_ERROR) {
+ sprintf(g->Message, MSG(ERROR_IN_SFP), drc);
+ CloseHandle(Hfile);
+ Hfile = INVALID_HANDLE_VALUE;
+ return true;
+ } // endif
+
+ NewOff.v.Low = (int)rc;
+ NewOff.v.High = (int)high;
+ } else if (mode == MODE_WRITE) {
+ if (id >= 0) {
+ // New not sep index file. Write the header.
+ memset(noff, 0, sizeof(noff));
+ rc = WriteFile(Hfile, noff, sizeof(noff), &drc, NULL);
+ NewOff.v.Low = (int)drc;
+ } // endif id
+
+ } else if (mode == MODE_READ && id >= 0) {
+ // Get offset from the header
+ rc = ReadFile(Hfile, noff, sizeof(noff), &drc, NULL);
+
+ if (!rc) {
+ sprintf(g->Message, MSG(XFILE_READERR), GetLastError());
+ return true;
+ } // endif rc
+
+ // Position the cursor at the offset of this index
+ rc = SetFilePointer(Hfile, noff[id].v.Low,
+ (PLONG)&noff[id].v.High, FILE_BEGIN);
+
+ if (rc == INVALID_SET_FILE_POINTER) {
+ sprintf(g->Message, MSG(FUNC_ERRNO), GetLastError(), "SetFilePointer");
+ return true;
+ } // endif
+
+ } // endif Mode
+
+#else // UNIX
+ int oflag = O_LARGEFILE; // Enable file size > 2G
+ mode_t pmod = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+
+ /*********************************************************************/
+ /* Create the file object according to access mode */
+ /*********************************************************************/
+ switch (mode) {
+ case MODE_READ:
+ oflag |= O_RDONLY;
+ break;
+ case MODE_WRITE:
+ oflag |= O_WRONLY | O_CREAT | O_TRUNC;
+// pmod = S_IREAD | S_IWRITE;
+ break;
+ case MODE_INSERT:
+ oflag |= (O_WRONLY | O_APPEND);
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_FUNC_MODE), "Xopen", mode);
+ return true;
+ } // endswitch
+
+ Hfile= global_open(g, MSGID_OPEN_ERROR_AND_STRERROR, filename, oflag, pmod);
+
+ if (Hfile == INVALID_HANDLE_VALUE) {
+ /*rc = errno;*/
+ if (trace(1))
+ htrc("Open: %s\n", g->Message);
+
+ return true;
+ } // endif Hfile
+
+ if (trace(1))
+ htrc(" oflag=%p mode=%d handle=%d fn=%s\n",
+ oflag, mode, Hfile, filename);
+
+ if (mode == MODE_INSERT) {
+ /*******************************************************************/
+ /* Position the cursor at end of file so ftell returns file size. */
+ /*******************************************************************/
+ if (!(NewOff.Val = (longlong)lseek64(Hfile, 0LL, SEEK_END))) {
+ sprintf(g->Message, MSG(FUNC_ERRNO), errno, "Seek");
+ return true;
+ } // endif
+
+ if (trace(1))
+ htrc("INSERT: NewOff=%lld\n", NewOff.Val);
+
+ } else if (mode == MODE_WRITE) {
+ if (id >= 0) {
+ // New not sep index file. Write the header.
+ memset(noff, 0, sizeof(noff));
+ NewOff.v.Low = write(Hfile, &noff, sizeof(noff));
+ } // endif id
+
+ if (trace(1))
+ htrc("WRITE: NewOff=%lld\n", NewOff.Val);
+
+ } else if (mode == MODE_READ && id >= 0) {
+ // Get offset from the header
+ if (read(Hfile, noff, sizeof(noff)) != sizeof(noff)) {
+ sprintf(g->Message, MSG(READ_ERROR), "Index file", strerror(errno));
+ return true;
+ } // endif read
+
+ if (trace(1))
+ htrc("noff[%d]=%lld\n", id, noff[id].Val);
+
+ // Position the cursor at the offset of this index
+ if (lseek64(Hfile, noff[id].Val, SEEK_SET) < 0) {
+ sprintf(g->Message, "(XHUGE)lseek64: %s (%lld)", strerror(errno), noff[id].Val);
+ printf("%s\n", g->Message);
+// sprintf(g->Message, MSG(FUNC_ERRNO), errno, "Hseek");
+ return true;
+ } // endif lseek64
+
+ } // endif mode
+#endif // UNIX
+
+ return false;
+ } // end of Open
+
+/***********************************************************************/
+/* Go to position in a huge file. */
+/***********************************************************************/
+bool XHUGE::Seek(PGLOBAL g, int low, int high, int origin)
+ {
+#if defined(_WIN32)
+ LONG hi = high;
+ DWORD rc = SetFilePointer(Hfile, low, &hi, origin);
+
+ if (rc == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
+ sprintf(g->Message, MSG(FUNC_ERROR), "Xseek");
+ return true;
+ } // endif
+
+#else // UNIX
+ off64_t pos = (off64_t)low
+ + (off64_t)high * ((off64_t)0x100 * (off64_t)0x1000000);
+
+ if (lseek64(Hfile, pos, origin) < 0) {
+ sprintf(g->Message, MSG(ERROR_IN_LSK), errno);
+
+ if (trace(1))
+ htrc("lseek64 error %d\n", errno);
+
+ return true;
+ } // endif lseek64
+
+ if (trace(1))
+ htrc("Seek: low=%d high=%d\n", low, high);
+#endif // UNIX
+
+ return false;
+ } // end of Seek
+
+/***********************************************************************/
+/* Read from a huge index file. */
+/***********************************************************************/
+bool XHUGE::Read(PGLOBAL g, void *buf, int n, int size)
+ {
+ bool rc = false;
+
+#if defined(_WIN32)
+ bool brc;
+ DWORD nbr, count = (DWORD)(n * size);
+
+ brc = ReadFile(Hfile, buf, count, &nbr, NULL);
+
+ if (brc) {
+ if (nbr != count) {
+ strcpy(g->Message, MSG(EOF_INDEX_FILE));
+ rc = true;
+ } // endif nbr
+
+ } else {
+ char buf[256];
+ DWORD drc = GetLastError();
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)buf, sizeof(buf), NULL);
+ sprintf(g->Message, MSG(READ_ERROR), "index file", buf);
+ rc = true;
+ } // endif brc
+#else // UNIX
+ ssize_t count = (ssize_t)(n * size);
+
+ if (trace(1))
+ htrc("Hfile=%d n=%d size=%d count=%d\n", Hfile, n, size, count);
+
+ if (read(Hfile, buf, count) != count) {
+ sprintf(g->Message, MSG(READ_ERROR), "Index file", strerror(errno));
+
+ if (trace(1))
+ htrc("read error %d\n", errno);
+
+ rc = true;
+ } // endif nbr
+#endif // UNIX
+
+ return rc;
+ } // end of Read
+
+/***********************************************************************/
+/* Write on a huge index file. */
+/***********************************************************************/
+int XHUGE::Write(PGLOBAL g, void *buf, int n, int size, bool& rc)
+ {
+#if defined(_WIN32)
+ bool brc;
+ DWORD nbw, count = (DWORD)n * (DWORD) size;
+
+ brc = WriteFile(Hfile, buf, count, &nbw, NULL);
+
+ if (!brc) {
+ char msg[256];
+ DWORD drc = GetLastError();
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, drc, 0,
+ (LPTSTR)msg, sizeof(msg), NULL);
+ sprintf(g->Message, MSG(WRITING_ERROR), "index file", msg);
+ rc = true;
+ } // endif size
+
+ return (int)nbw;
+#else // UNIX
+ ssize_t nbw;
+ size_t count = (size_t)n * (size_t)size;
+
+ nbw = write(Hfile, buf, count);
+
+ if (nbw != (signed)count) {
+ sprintf(g->Message, MSG(WRITING_ERROR),
+ "index file", strerror(errno));
+ rc = true;
+ } // endif nbw
+
+ return (int)nbw;
+#endif // UNIX
+ } // end of Write
+
+/***********************************************************************/
+/* Update the file header and close the index file. */
+/***********************************************************************/
+void XHUGE::Close(char *fn, int id)
+ {
+ if (trace(1))
+ htrc("XHUGE::Close: fn=%s id=%d NewOff=%lld\n", fn, id, NewOff.Val);
+
+#if defined(_WIN32)
+ if (id >= 0 && fn) {
+ CloseFileHandle(Hfile);
+ Hfile = CreateFile(fn, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (Hfile != INVALID_HANDLE_VALUE)
+ if (SetFilePointer(Hfile, id * sizeof(IOFF), NULL, FILE_BEGIN)
+ != INVALID_SET_FILE_POINTER) {
+ DWORD nbw;
+
+ WriteFile(Hfile, &NewOff, sizeof(IOFF), &nbw, NULL);
+ } // endif SetFilePointer
+
+ } // endif id
+#else // !_WIN32
+ if (id >= 0 && fn) {
+ if (Hfile != INVALID_HANDLE_VALUE) {
+ if (lseek64(Hfile, id * sizeof(IOFF), SEEK_SET) >= 0) {
+ ssize_t nbw = write(Hfile, &NewOff, sizeof(IOFF));
+
+ if (nbw != (signed)sizeof(IOFF))
+ htrc("Error writing index file header: %s\n", strerror(errno));
+
+ } else
+ htrc("(XHUGE::Close)lseek64: %s (%d)\n", strerror(errno), id);
+
+ } else
+ htrc("(XHUGE)error reopening %s: %s\n", fn, strerror(errno));
+
+ } // endif id
+#endif // !_WIN32
+
+ XLOAD::Close();
+ } // end of Close
+
+#if defined(XMAP)
+/***********************************************************************/
+/* Don't know whether this is possible for huge files. */
+/***********************************************************************/
+void *XHUGE::FileView(PGLOBAL g, char *)
+ {
+ strcpy(g->Message, MSG(NO_PART_MAP));
+ return NULL;
+ } // end of FileView
+#endif // XMAP
+
+/* -------------------------- XXROW Class --------------------------- */
+
+/***********************************************************************/
+/* XXROW Public Constructor. */
+/***********************************************************************/
+XXROW::XXROW(PTDBDOS tdbp) : XXBASE(tdbp, false)
+ {
+ Srtd = true;
+ Tdbp = tdbp;
+ Valp = NULL;
+ } // end of XXROW constructor
+
+/***********************************************************************/
+/* XXROW Reset: re-initialize a Kindex block. */
+/***********************************************************************/
+void XXROW::Reset(void)
+ {
+#if defined(_DEBUG)
+ assert(Tdbp->GetLink()); // This a join index
+#endif // _DEBUG
+ } // end of Reset
+
+/***********************************************************************/
+/* Init: Open and Initialize a Key Index. */
+/***********************************************************************/
+bool XXROW::Init(PGLOBAL g)
+ {
+ /*********************************************************************/
+ /* Table will be accessed through an index table. */
+ /* To_Link should not be NULL. */
+ /*********************************************************************/
+ if (!Tdbp->GetLink() || Tbxp->GetKnum() != 1)
+ return true;
+
+ if ((*Tdbp->GetLink())->GetResultType() != TYPE_INT) {
+ strcpy(g->Message, MSG(TYPE_MISMATCH));
+ return true;
+ } else
+ Valp = (*Tdbp->GetLink())->GetValue();
+
+ if ((Num_K = Tbxp->Cardinality(g)) < 0)
+ return true; // Not a fixed file
+
+ /*********************************************************************/
+ /* The entire table is indexed, no need to construct the index. */
+ /*********************************************************************/
+ Cur_K = Num_K;
+ return false;
+ } // end of Init
+
+/***********************************************************************/
+/* RANGE: Tell how many record exist in a given value range. */
+/***********************************************************************/
+int XXROW::Range(PGLOBAL, int limit, bool incl)
+ {
+ int n = Valp->GetIntValue();
+
+ switch (limit) {
+ case 1: n += ((incl) ? 0 : 1); break;
+ case 2: n += ((incl) ? 1 : 0); break;
+ default: n = 1;
+ } // endswitch limit
+
+ return n;
+ } // end of Range
+
+/***********************************************************************/
+/* XXROW: Fetch a physical or logical record. */
+/***********************************************************************/
+int XXROW::Fetch(PGLOBAL)
+ {
+ if (Num_K == 0)
+ return -1; // means end of file
+
+ /*********************************************************************/
+ /* Look for a key equal to the link column of previous table, */
+ /* and return its rank whithin the index table. */
+ /*********************************************************************/
+ Cur_K = FastFind();
+
+ if (Cur_K >= Num_K)
+ /*******************************************************************/
+ /* Rank not whithin index table, signal record not found. */
+ /*******************************************************************/
+ return -2; // Means record not found
+
+ /*********************************************************************/
+ /* If rank is equal to stored rank, record is already there. */
+ /*********************************************************************/
+ if (Cur_K == Old_K)
+ return -3; // Means record already there
+ else
+ Old_K = Cur_K; // Store rank of newly read record
+
+ return Cur_K;
+ } // end of Fetch
+
+/***********************************************************************/
+/* FastFind: Returns the index of matching record in a join. */
+/***********************************************************************/
+int XXROW::FastFind(void)
+ {
+ int n = Valp->GetIntValue();
+
+ if (n < 0)
+ return (Op == OP_EQ) ? (-1) : 0;
+ else if (n > Num_K)
+ return Num_K;
+ else
+ return (Op == OP_GT) ? n : (n - 1);
+
+ } // end of FastFind
+
+/* ------------------------- KXYCOL Classes -------------------------- */
+
+/***********************************************************************/
+/* KXYCOL public constructor. */
+/***********************************************************************/
+KXYCOL::KXYCOL(PKXBASE kp) : To_Keys(Keys.Memp),
+ To_Bkeys(Bkeys.Memp), Kof((CPINT&)Koff.Memp)
+ {
+ Next = NULL;
+ Previous = NULL;
+ Kxp = kp;
+ Colp = NULL;
+ IsSorted = false;
+ Asc = true;
+ Keys = Nmblk;
+ Kblp = NULL;
+ Bkeys = Nmblk;
+ Blkp = NULL;
+ Valp = NULL;
+ Klen = 0;
+ Kprec = 0;
+ Type = TYPE_ERROR;
+ Prefix = false;
+ Koff = Nmblk;
+ Val_K = 0;
+ Ndf = 0;
+ Mxs = 0;
+ } // end of KXYCOL constructor
+
+/***********************************************************************/
+/* KXYCOL Init: initialize and allocate storage. */
+/* Key length kln can be smaller than column length for CHAR columns. */
+/***********************************************************************/
+bool KXYCOL::Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln)
+ {
+ int len = colp->GetLength(), prec = colp->GetScale();
+ bool un = colp->IsUnsigned();
+
+ // Currently no indexing on NULL columns
+ if (colp->IsNullable() && kln) {
+ sprintf(g->Message, "Cannot index nullable column %s", colp->GetName());
+ return true;
+ } // endif nullable
+
+ if (kln && len > kln && colp->GetResultType() == TYPE_STRING) {
+ len = kln;
+ Prefix = true;
+ } // endif kln
+
+ if (trace(1))
+ htrc("KCOL(%p) Init: col=%s n=%d type=%d sm=%d\n",
+ this, colp->GetName(), n, colp->GetResultType(), sm);
+
+ // Allocate the Value object used when moving items
+ Type = colp->GetResultType();
+
+ if (!(Valp = AllocateValue(g, Type, len, prec, un)))
+ return true;
+
+ Klen = Valp->GetClen();
+ Keys.Size = (size_t)n * (size_t)Klen;
+
+ if (!PlgDBalloc(g, NULL, Keys)) {
+ sprintf(g->Message, MSG(KEY_ALLOC_ERROR), Klen, n);
+ return true; // Error
+ } // endif
+
+ // Allocate the Valblock. The last parameter is to have rows filled
+ // by blanks (if true) or keep the zero ending char (if false).
+ // Currently we set it to true to be compatible with QRY blocks,
+ // and the one before last is to enable length/type checking, set to
+ // true if not a prefix key.
+ Kblp = AllocValBlock(g, To_Keys, Type, n, len, prec, !Prefix, true, un);
+ Asc = sm; // Sort mode: Asc=true Desc=false
+ Ndf = n;
+
+ // Store this information to avoid sorting when already done
+ if (Asc)
+ IsSorted = colp->GetOpt() == 2;
+
+//SetNulls(colp->IsNullable()); for when null columns will be indexable
+ Colp = colp;
+ return false;
+ } // end of Init
+
+#if defined(XMAP)
+/***********************************************************************/
+/* KXYCOL MapInit: initialize and address storage. */
+/* Key length kln can be smaller than column length for CHAR columns. */
+/***********************************************************************/
+BYTE* KXYCOL::MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m)
+ {
+ int len = colp->GetLength(), prec = colp->GetScale();
+ bool un = colp->IsUnsigned();
+
+ if (n[3] && colp->GetLength() > n[3]
+ && colp->GetResultType() == TYPE_STRING) {
+ len = n[3];
+ Prefix = true;
+ } // endif kln
+
+ Type = colp->GetResultType();
+
+ if (trace(1))
+ htrc("MapInit(%p): colp=%p type=%d n=%d len=%d m=%p\n",
+ this, colp, Type, n[0], len, m);
+
+ // Allocate the Value object used when moving items
+ Valp = AllocateValue(g, Type, len, prec, un);
+ Klen = Valp->GetClen();
+
+ if (n[2]) {
+ Bkeys.Size = n[2] * Klen;
+ Bkeys.Memp = m;
+ Bkeys.Sub = true;
+
+ // Allocate the Valblk containing initial block key values
+ Blkp = AllocValBlock(g, To_Bkeys, Type, n[2], len, prec, true, true, un);
+ } // endif nb
+
+ Keys.Size = n[0] * Klen;
+ Keys.Memp = m + Bkeys.Size;
+ Keys.Sub = true;
+
+ // Allocate the Valblock. Last two parameters are to have rows filled
+ // by blanks (if true) or keep the zero ending char (if false).
+ // Currently we set it to true to be compatible with QRY blocks,
+ // and last one to enable type checking (no conversion).
+ Kblp = AllocValBlock(g, To_Keys, Type, n[0], len, prec, !Prefix, true, un);
+
+ if (n[1]) {
+ Koff.Size = n[1] * sizeof(int);
+ Koff.Memp = m + Bkeys.Size + Keys.Size;
+ Koff.Sub = true;
+ } // endif n[1]
+
+ Ndf = n[0];
+//IsSorted = colp->GetOpt() < 0;
+ IsSorted = false;
+ Colp = colp;
+ return m + Bkeys.Size + Keys.Size + Koff.Size;
+ } // end of MapInit
+#endif // XMAP
+
+/***********************************************************************/
+/* Allocate the offset block used by intermediate key columns. */
+/***********************************************************************/
+int *KXYCOL::MakeOffset(PGLOBAL g, int n)
+ {
+ if (!Kof) {
+ // Calculate the initial size of the offset
+ Koff.Size = (n + 1) * sizeof(int);
+
+ // Allocate the required memory
+ if (!PlgDBalloc(g, NULL, Koff)) {
+ strcpy(g->Message, MSG(KEY_ALLOC_ERR));
+ return NULL; // Error
+ } // endif
+
+ } else if (n) {
+ // This is a reallocation call
+ PlgDBrealloc(g, NULL, Koff, (n + 1) * sizeof(int));
+ } else
+ PlgDBfree(Koff);
+
+ return (int*)Kof;
+ } // end of MakeOffset
+
+/***********************************************************************/
+/* Make a front end array of key values that are the first value of */
+/* each blocks (of size n). This to reduce paging in FastFind. */
+/***********************************************************************/
+bool KXYCOL::MakeBlockArray(PGLOBAL g, int nb, int size)
+ {
+ int i, k;
+
+ // Calculate the size of the block array in the index
+ Bkeys.Size = nb * Klen;
+
+ // Allocate the required memory
+ if (!PlgDBalloc(g, NULL, Bkeys)) {
+ sprintf(g->Message, MSG(KEY_ALLOC_ERROR), Klen, nb);
+ return true; // Error
+ } // endif
+
+ // Allocate the Valblk used to contains initial block key values
+ Blkp = AllocValBlock(g, To_Bkeys, Type, nb, Klen, Kprec);
+
+ // Populate the array with values
+ for (i = k = 0; i < nb; i++, k += size)
+ Blkp->SetValue(Kblp, i, k);
+
+ return false;
+ } // end of MakeBlockArray
+
+/***********************************************************************/
+/* KXYCOL SetValue: read column value for nth array element. */
+/***********************************************************************/
+void KXYCOL::SetValue(PCOL colp, int i)
+ {
+#if defined(_DEBUG)
+ assert (Kblp != NULL);
+#endif
+
+ Kblp->SetValue(colp->GetValue(), i);
+ } // end of SetValue
+
+/***********************************************************************/
+/* InitFind: initialize finding the rank of column value in index. */
+/***********************************************************************/
+bool KXYCOL::InitFind(PGLOBAL g, PXOB xp)
+ {
+ if (xp->GetType() == TYPE_CONST) {
+ if (Kxp->Nth)
+ return true;
+
+ Valp->SetValue_pval(xp->GetValue(), !Prefix);
+ } else {
+ xp->Reset();
+ xp->Eval(g);
+ Valp->SetValue_pval(xp->GetValue(), false);
+ } // endif Type
+
+ if (trace(2)) {
+ char buf[32];
+
+ htrc("KCOL InitFind: value=%s\n", Valp->GetCharString(buf));
+ } // endif trace
+
+ return false;
+ } // end of InitFind
+
+#if 0
+/***********************************************************************/
+/* InitBinFind: initialize Value to the value pointed by vp. */
+/***********************************************************************/
+void KXYCOL::InitBinFind(void *vp)
+ {
+ Valp->SetBinValue(vp);
+ } // end of InitBinFind
+#endif // 0
+
+/***********************************************************************/
+/* KXYCOL FillValue: called by COLBLK::Eval when a column value is */
+/* already in storage in the corresponding KXYCOL. */
+/***********************************************************************/
+void KXYCOL::FillValue(PVAL valp)
+ {
+ valp->SetValue_pvblk(Kblp, Val_K);
+
+ // Set null when applicable (NIY)
+//if (valp->GetNullable())
+// valp->SetNull(valp->IsZero());
+
+ } // end of FillValue
+
+/***********************************************************************/
+/* KXYCOL: Compare routine for one numeric value. */
+/***********************************************************************/
+int KXYCOL::Compare(int i1, int i2)
+ {
+ // Do the actual comparison between values.
+ int k = Kblp->CompVal(i1, i2);
+
+ if (trace(4))
+ htrc("Compare done result=%d\n", k);
+
+ return (Asc) ? k : -k;
+ } // end of Compare
+
+/***********************************************************************/
+/* KXYCOL: Compare the ith key to the stored Value. */
+/***********************************************************************/
+int KXYCOL::CompVal(int i)
+ {
+ // Do the actual comparison between numerical values.
+ if (trace(4)) {
+ int k = (int)Kblp->CompVal(Valp, (int)i);
+
+ htrc("Compare done result=%d\n", k);
+ return k;
+ } else
+ return Kblp->CompVal(Valp, i);
+
+ } // end of CompVal
+
+/***********************************************************************/
+/* KXYCOL: Compare the key to the stored block value. */
+/***********************************************************************/
+int KXYCOL::CompBval(int i)
+ {
+ // Do the actual comparison between key values.
+ return Blkp->CompVal(Valp, i);
+ } // end of CompBval
+
+/***********************************************************************/
+/* KXYCOL ReAlloc: ReAlloc To_Data if it is not suballocated. */
+/***********************************************************************/
+void KXYCOL::ReAlloc(PGLOBAL g, int n)
+ {
+ PlgDBrealloc(g, NULL, Keys, n * Klen);
+ Kblp->ReAlloc(To_Keys, n);
+ Ndf = n;
+ } // end of ReAlloc
+
+/***********************************************************************/
+/* KXYCOL FreeData: Free To_Keys if it is not suballocated. */
+/***********************************************************************/
+void KXYCOL::FreeData(void)
+ {
+ PlgDBfree(Keys);
+ Kblp = NULL;
+ PlgDBfree(Bkeys);
+ Blkp = NULL;
+ PlgDBfree(Koff);
+ Ndf = 0;
+ } // end of FreeData
diff --git a/storage/connect/xindex.h b/storage/connect/xindex.h
new file mode 100644
index 00000000..ce62f059
--- /dev/null
+++ b/storage/connect/xindex.h
@@ -0,0 +1,509 @@
+/*************** Xindex H Declares Source Code File (.H) ***************/
+/* Name: XINDEX.H Version 3.5 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 2004 - 2015 */
+/* */
+/* This file contains the XINDEX class declares. */
+/***********************************************************************/
+#ifndef __XINDEX_H__
+#define __XINDEX_H__
+#include "block.h"
+#include "csort.h" /* Base class declares */
+#include "xtable.h"
+#include "valblk.h"
+#if defined(XMAP)
+#include "maputil.h"
+#endif // XMAP
+
+enum IDT {TYPE_IDX_ERROR = 0, /* Type not defined */
+ TYPE_IDX_INDX = 4, /* Permanent standard index */
+ TYPE_IDX_XROW = 5}; /* Permanent row index */
+
+#if defined(XMAP)
+typedef MEMMAP *MMP;
+#endif // XMAP
+typedef class INDEXDEF *PIXDEF;
+typedef class KPARTDEF *PKPDEF;
+typedef class XINDEX *PXINDEX;
+typedef class XLOAD *PXLOAD;
+typedef class KXYCOL *PXCOL;
+
+/***********************************************************************/
+/* Structures used when checking for possible indexing */
+/***********************************************************************/
+typedef struct index_col *PICOL;
+typedef struct index_val *PIVAL;
+typedef struct index_def *PINDX;
+typedef struct indx_used *PXUSED;
+
+typedef struct index_val : public BLOCK {
+ index_val(PXOB xp) {Next = NULL; Xval = xp; Kp = NULL;}
+ PIVAL Next; // Next value
+ PXOB Xval; // To value or array
+ int *Kp; // The coordonates in a LSTBLK
+ } IVAL;
+
+typedef struct index_col : public BLOCK {
+ index_col(PCOL cp)
+ {Next = Nxtgrp = NULL; Colp = cp; Ngrp = N = 0; Vals = NULL;}
+ PICOL Next; // Next column
+ PICOL Nxtgrp; // Next group
+ PCOL Colp; // The column
+ PIVAL Vals; // To column values
+ int Ngrp; // Group number of values
+ int N; // Column number of values
+ } ICOL;
+
+typedef struct index_def : public BLOCK {
+ index_def(PIXDEF xdp)
+ {Next = NULL; Pxdf = xdp; Cols = NULL; Alloc = false;}
+ PINDX Next;
+ PIXDEF Pxdf;
+ PICOL Cols;
+ bool Alloc; // Must allocate values
+ } INDX;
+
+typedef struct index_off {
+ union {
+#if defined(WORDS_BIGENDIAN)
+ struct {int High; int Low;} v;
+#else // !WORDS_BIGENDIAN
+ struct {int Low; int High;} v;
+#endif //!WORDS_BIGENDIAN
+ longlong Val; // File position
+ }; // end of union
+ } IOFF;
+
+/***********************************************************************/
+/* Index definition block. */
+/***********************************************************************/
+class DllExport INDEXDEF : public BLOCK { /* Index description block */
+ friend class PLUGCAT;
+ friend class DOSDEF;
+ friend class ha_connect;
+ friend int PlgMakeIndex(PGLOBAL g, PSZ name, PIXDEF pxdf, bool add);
+ public:
+ // Constructor
+ INDEXDEF(char *name, bool uniq = false, int n = 0);
+
+ // Implementation
+ PIXDEF GetNext(void) {return Next;}
+ void SetNext(PIXDEF pxdf) {Next = pxdf;}
+ PSZ GetName(void) {return (PSZ)Name;}
+ bool IsUnique(void) {return Unique;}
+ bool IsDynamic(void) {return Dynamic;}
+ bool IsAuto(void) {return AutoInc;}
+ bool IsValid(void) {return !Invalid;}
+ void SetAuto(bool b) {AutoInc = b;}
+ void SetInvalid(bool b) {Invalid = b;}
+ int GetNparts(void) {return Nparts;}
+ int GetID(void) {return ID;}
+ void SetID(int n) {ID = n;}
+ PKPDEF GetToKeyParts(void) {return ToKeyParts;}
+ void SetToKeyParts(PKPDEF kp) {ToKeyParts = kp;}
+ void SetNParts(uint np) {Nparts = (signed)np;}
+ void SetMaxSame(int mxs) {MaxSame = mxs;}
+ void SetMxsame(PXINDEX x);
+ int GetMaxSame(void) {return MaxSame;}
+ bool Define(PGLOBAL g, void *memp, PTABDEF dfp, LPCSTR p);
+ PIXDEF GetIndexOf(PCOL colp, bool hd = false);
+ int IsIndexOf(PCOL colp);
+ PKXBASE CheckIndexing(PGLOBAL g, PTDBDOS tdbp);
+ PINDX CheckAND(PGLOBAL g, PINDX pix1, PINDX pix2);
+ PINDX CheckOR(PGLOBAL g, PINDX pix1, PINDX pix2);
+ PINDX CheckEQ(PGLOBAL g, PTDB tdbp, PXOB *arg, int op, int *kp = NULL);
+ bool TestEQ(PGLOBAL g, PTDB tdbp, PXOB *arg, int op, bool b = false);
+
+ protected:
+ PIXDEF Next; /* To next block */
+ PKPDEF ToKeyParts; /* To the key part definitions */
+ char *Name; /* Index name */
+ bool Unique; /* true if defined as unique */
+ bool Invalid; /* true if marked as Invalid */
+ bool AutoInc; /* true if unique key in auto increment */
+ bool Dynamic; /* KINDEX style */
+ bool Mapped; /* Use file mapping */
+ int Nparts; /* Number of key parts */
+ int ID; /* Index ID number */
+ int MaxSame; /* Max number of same values */
+ }; // end of INDEXDEF
+
+typedef struct indx_used : public BLOCK {
+ indx_used(PTDB tp, PIXDEF xdp, PCOL *cp, int k)
+ {Tname = (char*)tp->GetName(); Xname = xdp->GetName(); Cp = cp; K = k;}
+ PXUSED Next;
+ char *Tname;
+ PSZ Xname;
+ PCOL *Cp;
+ int K;
+ } XUSED;
+
+/***********************************************************************/
+/* Index Key Part definition block. */
+/***********************************************************************/
+class DllExport KPARTDEF : public BLOCK { /* Index Key Part desc block */
+ friend class INDEXDEF;
+ friend class XINDEX;
+ friend class PLUGCAT;
+ friend class DOSDEF;
+ friend class ha_connect;
+ friend int PlgMakeIndex(PGLOBAL g, PSZ name, PIXDEF pxdf, bool add);
+ public:
+ KPARTDEF(PSZ name, int n); // Constructor
+
+ // Implementation
+ PKPDEF GetNext(void) {return Next;}
+ PSZ GetName(void) {return (PSZ)Name;}
+ int GetNcol(void) {return Ncol;}
+ void SetNext(PKPDEF pkdf) {Next = pkdf;}
+ void SetKlen(int len) {Klen = len;}
+ void SetMxsame(int mxs) {Mxsame = mxs;}
+
+ protected:
+ PKPDEF Next; /* To next block */
+ PSZ Name; /* Field name */
+ int Mxsame; /* Field max same values */
+ int Ncol; /* Field number */
+ int Klen; /* Key length */
+ }; // end of KPARTDEF
+
+/***********************************************************************/
+/* This is the XDB Index virtual base class declaration. */
+/***********************************************************************/
+class DllExport XXBASE : public CSORT, public BLOCK {
+ friend class INDEXDEF;
+ friend class KXYCOL;
+ public:
+ // Constructor
+ XXBASE(PTDBDOS tbxp, bool b);
+
+ // Implementation
+ virtual IDT GetType(void) = 0;
+ virtual void Reset(void) = 0;
+ virtual bool IsMul(void) {return false;}
+ virtual bool IsRandom(void) {return true;}
+ virtual bool IsDynamic(void) {return Dynamic;}
+ virtual void SetDynamic(bool dyn) {Dynamic = dyn;}
+//virtual bool HaveSame(void) {return false;}
+ virtual int GetCurPos(void) {return Cur_K;}
+ virtual void SetNval(int n) {assert(n == 1);}
+ virtual void SetOp(OPVAL op) {Op = op;}
+ int GetNdif(void) {return Ndif;}
+ int GetNum_K(void) {return Num_K;}
+ int GetCur_K(void) {return Cur_K;}
+ int GetID(void) {return ID;}
+ void SetID(int id) {ID = id;}
+ void SetNth(int n) {Nth = n;}
+ int *GetPof(void) {return Pof;}
+ int *GetPex(void) {return Pex;}
+ bool IsSorted(void) {return Srtd;}
+ void FreeIndex(void) {PlgDBfree(Index);}
+
+ // Methods
+ virtual void Printf(PGLOBAL g, FILE *f, uint n);
+ virtual void Prints(PGLOBAL g, char *ps, uint z);
+ virtual bool Init(PGLOBAL g) = 0;
+ virtual bool Make(PGLOBAL g, PIXDEF sxp) = 0;
+#if defined(XMAP)
+ virtual bool MapInit(PGLOBAL g) = 0;
+#endif // XMAP
+ virtual int MaxRange(void) {return 1;}
+ virtual int Fetch(PGLOBAL g) = 0;
+ virtual bool NextVal(bool) {return true;}
+ virtual bool PrevVal(void) {return true;}
+ virtual int FastFind(void) = 0;
+ virtual bool Reorder(PGLOBAL) {return true;}
+ virtual int Range(PGLOBAL, int = 0, bool = true) {return -1;} // Means error
+ virtual int Qcompare(int *, int *) = 0;
+ virtual int GroupSize(void) {return 1;}
+ virtual void Close(void) = 0;
+
+ protected:
+ // Members
+ PTDBASE Tbxp; // Points to calling table TDB
+ PXCOL To_KeyCol; // To KeyCol class list
+ MBLOCK Record; // Record allocation block
+ int* &To_Rec; // We are using ftell, fseek
+ int Cur_K; // Index of current record
+ int Old_K; // Index of last record
+ int Num_K; // Size of Rec_K pointer array
+ int Ndif; // Number of distinct values
+ int Bot; // Bottom of research index
+ int Top; // Top of research index
+ int Inf, Sup; // Used for block optimization
+ OPVAL Op; // Search operator
+ bool Mul; // true if multiple
+ bool Srtd; // true for sorted column
+ bool Dynamic; // true when dynamically made
+ int Val_K; // Index of current value
+ int Nblk; // Number of blocks
+ int Sblk; // Block size
+ int Thresh; // Thresh for sorting join indexes
+ int ID; // Index ID number
+ int Nth; // Nth constant to fetch
+ }; // end of class XXBASE
+
+/***********************************************************************/
+/* This is the standard (multicolumn) Index class declaration. */
+/***********************************************************************/
+class DllExport XINDEX : public XXBASE {
+ friend class KXYCOL;
+ public:
+ // Constructor
+ XINDEX(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp,
+ PCOL *cp, PXOB *xp = NULL, int k = 0);
+
+ // Implementation
+ virtual IDT GetType(void) {return TYPE_IDX_INDX;}
+ virtual bool IsMul(void) {return (Nval < Nk) ? true : Mul;}
+//virtual bool HaveSame(void) {return Op == OP_SAME;}
+ virtual int GetCurPos(void) {return (Pex) ? Pex[Cur_K] : Cur_K;}
+ virtual void SetNval(int n) {Nval = n;}
+ int GetMaxSame(void) {return MaxSame;}
+
+ // Methods
+ virtual void Reset(void);
+ virtual bool Init(PGLOBAL g);
+#if defined(XMAP)
+ virtual bool MapInit(PGLOBAL g);
+#endif // XMAP
+ virtual int Qcompare(int *, int *);
+ virtual int Fetch(PGLOBAL g);
+ virtual int FastFind(void);
+ virtual int GroupSize(void);
+ virtual int Range(PGLOBAL g, int limit = 0, bool incl = true);
+ virtual int MaxRange(void) {return MaxSame;}
+ virtual int ColMaxSame(PXCOL kp);
+ virtual void Close(void);
+ virtual bool NextVal(bool eq);
+ virtual bool PrevVal(void);
+ virtual bool Make(PGLOBAL g, PIXDEF sxp);
+ virtual bool SaveIndex(PGLOBAL g, PIXDEF sxp);
+ virtual bool Reorder(PGLOBAL g);
+ bool GetAllSizes(PGLOBAL g,/* int &ndif,*/ int &numk);
+
+ protected:
+ bool AddColumns(void);
+ bool NextValDif(void);
+
+ // Members
+ PIXDEF Xdp; // To index definition
+ PTDBDOS Tdbp; // Points to calling table TDB
+ PXLOAD X; // To XLOAD class
+ PXCOL To_LastCol; // To the last key part block
+ PXCOL To_LastVal; // To the last used key part block
+ PCOL *To_Cols; // To array of indexed columns
+ PXOB *To_Vals; // To array of column values
+ int Nk; // The number of indexed columns
+ int Nval; // The number of used columns
+ int Incr; // Increment of record position
+ int MaxSame; // Max number of same values
+ }; // end of class XINDEX
+
+/***********************************************************************/
+/* This is the fast single column index class declaration. */
+/***********************************************************************/
+class DllExport XINDXS : public XINDEX {
+ friend class KXYCOL;
+ public:
+ // Constructor
+ XINDXS(PTDBDOS tdbp, PIXDEF xdp, PXLOAD pxp, PCOL *cp, PXOB *xp = NULL);
+
+ // Implementation
+ virtual void SetNval(int n) {assert(n == 1);}
+
+ // Methods
+ virtual int Qcompare(int *, int *);
+ virtual int Fetch(PGLOBAL g);
+ virtual int FastFind(void);
+ virtual bool NextVal(bool eq);
+ virtual bool PrevVal(void);
+ virtual int Range(PGLOBAL g, int limit = 0, bool incl = true);
+ virtual int GroupSize(void);
+
+ protected:
+ // Members
+ }; // end of class XINDXS
+
+/***********************************************************************/
+/* This is the saving/loading index utility base class. */
+/***********************************************************************/
+class DllExport XLOAD : public BLOCK {
+ friend class XINDEX;
+ friend class XBIGEX;
+ friend class XBIGXS;
+ public:
+ // Constructor
+ XLOAD(void);
+
+ // Methods
+ virtual bool Open(PGLOBAL g, char *filename, int id, MODE mode) = 0;
+ virtual bool Seek(PGLOBAL g, int low, int high, int origin) = 0;
+ virtual bool Read(PGLOBAL g, void *buf, int n, int size) = 0;
+ virtual int Write(PGLOBAL g, void *buf, int n,
+ int size, bool& rc) = 0;
+ virtual void Close(char *fn, int id) = 0;
+ virtual void Close(void);
+#if defined(XMAP)
+ virtual void *FileView(PGLOBAL g, char *fn) = 0;
+#endif // XMAP
+
+ protected:
+ // Members
+#if defined(_WIN32)
+ HANDLE Hfile; // Handle to file or map
+#else // UNIX
+ int Hfile; // Descriptor to file or map
+#endif // UNIX
+ IOFF NewOff; // New offset
+ }; // end of class XLOAD
+
+/***********************************************************************/
+/* This is the saving/loading indexes utility class. */
+/***********************************************************************/
+class DllExport XFILE : public XLOAD {
+ public:
+ // Constructor
+ XFILE(void);
+
+ // Methods
+ virtual bool Open(PGLOBAL g, char *filename, int id, MODE mode);
+ virtual bool Seek(PGLOBAL g, int low, int high, int origin);
+ virtual bool Read(PGLOBAL g, void *buf, int n, int size);
+ virtual int Write(PGLOBAL g, void *buf, int n, int size, bool& rc);
+ virtual void Close(char *fn, int id);
+ virtual void Close(void);
+#if defined(XMAP)
+ virtual void *FileView(PGLOBAL g, char *fn);
+#endif // XMAP
+
+ protected:
+ // Members
+ FILE *Xfile; // Index stream file
+#if defined(XMAP)
+ MMP Mmp; // Mapped view base address and length
+#endif // XMAP
+ }; // end of class XFILE
+
+/***********************************************************************/
+/* This is the saving/loading huge indexes utility class. */
+/***********************************************************************/
+class DllExport XHUGE : public XLOAD {
+ public:
+ // Constructor
+ XHUGE(void) : XLOAD() {}
+
+ // Methods
+ using XLOAD::Close;
+ virtual bool Open(PGLOBAL g, char *filename, int id, MODE mode);
+ virtual bool Seek(PGLOBAL g, int low, int high, int origin);
+ virtual bool Read(PGLOBAL g, void *buf, int n, int size);
+ virtual int Write(PGLOBAL g, void *buf, int n, int size, bool& rc);
+ virtual void Close(char *fn, int id);
+#if defined(XMAP)
+ virtual void *FileView(PGLOBAL g, char *fn);
+#endif // XMAP
+
+ protected:
+ // Members
+ }; // end of class XHUGE
+
+/***********************************************************************/
+/* This is the XDB index for columns containing ROWID values. */
+/***********************************************************************/
+class DllExport XXROW : public XXBASE {
+ friend class KXYCOL;
+ public:
+ // Constructor
+ XXROW(PTDBDOS tbxp);
+
+ // Implementation
+ virtual IDT GetType(void) {return TYPE_IDX_XROW;}
+ virtual void Reset(void);
+
+ // Methods
+ virtual bool Init(PGLOBAL g);
+#if defined(XMAP)
+ virtual bool MapInit(PGLOBAL) {return true;}
+#endif // XMAP
+ virtual int Fetch(PGLOBAL g);
+ virtual int FastFind(void);
+ virtual int MaxRange(void) {return 1;}
+ virtual int Range(PGLOBAL g, int limit = 0, bool incl = true);
+ virtual int Qcompare(int *, int *) {assert(false); return 0;}
+ virtual bool Make(PGLOBAL, PIXDEF) {return false;}
+ virtual void Close(void) {}
+
+ protected:
+ // Members
+ PTDBDOS Tdbp; // Points to calling table TDB
+ PVAL Valp; // The value to match in index
+ }; // end of class XXROW
+
+/***********************************************************************/
+/* Definition of class KXYCOL used to store values of indexed columns */
+/***********************************************************************/
+class KXYCOL: public BLOCK {
+ friend class INDEXDEF;
+ friend class XINDEX;
+ friend class XINDXS;
+ friend class XBIGEX;
+ friend class XBIGXS;
+ friend class TDBDOS;
+ public:
+ // Constructors
+ KXYCOL(PKXBASE kp);
+
+ // Implementation
+ int GetType(void) {return Type;}
+ void SetValue(PCOL colp, int i);
+
+ public:
+ // Methods
+ virtual bool Init(PGLOBAL g, PCOL colp, int n, bool sm, int kln);
+ virtual bool InitFind(PGLOBAL g, PXOB xp);
+ virtual void ReAlloc(PGLOBAL g, int n);
+ virtual void FreeData(void);
+ virtual void FillValue(PVAL valp);
+ virtual int CompVal(int i);
+// void InitBinFind(void *vp);
+ bool MakeBlockArray(PGLOBAL g, int nb, int size);
+ int Compare(int i1, int i2);
+ int CompBval(int i);
+ void Save(int i) {Valp->SetBinValue(Kblp->GetValPtr(i));}
+ void Restore(int j) {Kblp->SetValue(Valp, j);}
+ void Move(int j, int k) {Kblp->Move(k, j);}
+
+ // Specific functions
+#if defined(XMAP)
+ BYTE *MapInit(PGLOBAL g, PCOL colp, int *n, BYTE *m);
+#endif // XMAP
+ int *MakeOffset(PGLOBAL g, int n);
+
+ protected:
+ // Members
+ PXCOL Next; // To next in the key part list
+ PXCOL Previous; // To previous in the key part list
+ PKXBASE Kxp; // To the INDEX class block
+ PCOL Colp; // To matching object if a column
+ bool IsSorted; // true if column is already sorted
+ bool Asc; // true for ascending sort, false for Desc
+ MBLOCK Keys; // Data array allocation block
+ void* &To_Keys; // To data array
+ PVBLK Kblp; // To Valblock of the data array
+ MBLOCK Bkeys; // Block array allocation block
+ void* &To_Bkeys; // To block array
+ PVBLK Blkp; // To Valblock of the block array
+ PVAL Valp; // Value use by Find
+ int Klen; // Length of character string or num value
+ int Kprec; // The Value(s) precision or CI
+ int Type; // The Value(s) type
+ bool Prefix; // Key on CHAR column prefix
+ MBLOCK Koff; // Offset allocation block
+ CPINT &Kof; // Reference to offset array
+ int Val_K; // Index of current column value
+ int Ndf; // Number of stored values
+ int Mxs; // Max same for this column
+ }; // end of class KXYCOL
+
+#endif // __XINDEX_H__
diff --git a/storage/connect/xobject.cpp b/storage/connect/xobject.cpp
new file mode 100644
index 00000000..c595ce5d
--- /dev/null
+++ b/storage/connect/xobject.cpp
@@ -0,0 +1,441 @@
+/************ Xobject C++ Functions Source Code File (.CPP) ************/
+/* Name: XOBJECT.CPP Version 2.5 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2017 */
+/* */
+/* This file contains base XOBJECT class functions. */
+/* Also here is the implementation of the CONSTANT class. */
+/***********************************************************************/
+
+/***********************************************************************/
+/* Include mariaDB header file. */
+/***********************************************************************/
+#include "my_global.h"
+#include "m_string.h"
+
+/***********************************************************************/
+/* Include required application header files */
+/* global.h is header containing all global Plug declarations. */
+/* plgdbsem.h is header containing the DB applic. declarations. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xobject.h"
+
+/***********************************************************************/
+/* Macro definitions. */
+/***********************************************************************/
+#if defined(_DEBUG) || defined(DEBTRACE)
+#define ASSERT(B) assert(B);
+#else
+#define ASSERT(B)
+#endif
+
+/***********************************************************************/
+/* The one and only needed void object. */
+/***********************************************************************/
+XVOID Xvoid;
+PXOB const pXVOID = &Xvoid; // Pointer used by other classes
+
+/* ------------------------- Class XOBJECT --------------------------- */
+
+/***********************************************************************/
+/* GetCharValue: returns the Result value as a char string. */
+/* Using GetCharValue provides no conversion from numeric types. */
+/***********************************************************************/
+PSZ XOBJECT::GetCharValue(void)
+ {
+ ASSERT(Value)
+ return Value->GetCharValue();
+ } // end of GetCharValue()
+
+/***********************************************************************/
+/* GetShortValue: returns the Result value as a short integer. */
+/***********************************************************************/
+short XOBJECT::GetShortValue(void)
+ {
+ ASSERT(Value)
+ return Value->GetShortValue();
+ } // end of GetShortValue
+
+/***********************************************************************/
+/* GetIntValue: returns the Result value as a int integer. */
+/***********************************************************************/
+int XOBJECT::GetIntValue(void)
+ {
+ ASSERT(Value)
+ return Value->GetIntValue();
+ } // end of GetIntValue
+
+/***********************************************************************/
+/* GetFloatValue: returns the Result value as a double float. */
+/***********************************************************************/
+double XOBJECT::GetFloatValue(void)
+ {
+ ASSERT(Value)
+ return Value->GetFloatValue();
+ } // end of GetFloatValue
+
+/* ------------------------- Class CONSTANT -------------------------- */
+
+/***********************************************************************/
+/* CONSTANT public constructor. */
+/***********************************************************************/
+CONSTANT::CONSTANT(PGLOBAL g, void *value, short type)
+ {
+ if (!(Value = AllocateValue(g, value, (int)type)))
+ throw (int)TYPE_CONST;
+
+ Constant = true;
+ } // end of CONSTANT constructor
+
+/***********************************************************************/
+/* CONSTANT public constructor. */
+/***********************************************************************/
+CONSTANT::CONSTANT(PGLOBAL g, int n)
+ {
+ if (!(Value = AllocateValue(g, &n, TYPE_INT)))
+ throw (int)TYPE_CONST;
+
+ Constant = true;
+ } // end of CONSTANT constructor
+
+/***********************************************************************/
+/* GetLengthEx: returns an evaluation of the constant string length. */
+/* Note: When converting from token to string, length has to be */
+/* specified but we need the domain length, not the value length. */
+/***********************************************************************/
+int CONSTANT::GetLengthEx(void)
+ {
+ return Value->GetValLen();
+ } // end of GetLengthEx
+
+/***********************************************************************/
+/* Convert a constant to the given type. */
+/***********************************************************************/
+void CONSTANT::Convert(PGLOBAL g, int newtype)
+ {
+ if (Value->GetType() != newtype)
+ if (!(Value = AllocateValue(g, Value, newtype)))
+ throw (int)TYPE_CONST;
+
+ } // end of Convert
+
+/***********************************************************************/
+/* Compare: returns true if this object is equivalent to xp. */
+/***********************************************************************/
+bool CONSTANT::Compare(PXOB xp)
+ {
+ if (this == xp)
+ return true;
+ else if (xp->GetType() != TYPE_CONST)
+ return false;
+ else
+ return Value->IsEqual(xp->GetValue(), true);
+
+ } // end of Compare
+
+#if 0
+/***********************************************************************/
+/* Rephrase: temporary implementation used by PlugRephraseSQL. */
+/***********************************************************************/
+bool CONSTANT::Rephrase(PGLOBAL g, PSZ work)
+ {
+ switch (Value->GetType()) {
+ case TYPE_STRING:
+ sprintf(work + strlen(work), "'%s'", Value->GetCharValue());
+ break;
+ case TYPE_SHORT:
+ sprintf(work + strlen(work), "%hd", Value->GetShortValue());
+ break;
+ case TYPE_INT:
+ case TYPE_DATE:
+ sprintf(work + strlen(work), "%d", Value->GetIntValue());
+ break;
+ case TYPE_DOUBLE:
+ sprintf(work + strlen(work), "%lf", Value->GetFloatValue());
+ break;
+ case TYPE_BIGINT:
+ sprintf(work + strlen(work), "%lld", Value->GetBigintValue());
+ break;
+ case TYPE_TINY:
+ sprintf(work + strlen(work), "%d", Value->GetTinyValue());
+ break;
+ default:
+ sprintf(g->Message, MSG(BAD_CONST_TYPE), Value->GetType());
+ return false;
+ } // endswitch
+
+ return false;
+ } // end of Rephrase
+#endif // 0
+
+/***********************************************************************/
+/* Make file output of a constant object. */
+/***********************************************************************/
+void CONSTANT::Printf(PGLOBAL g, FILE *f, uint n)
+ {
+ Value->Printf(g, f, n);
+ } /* end of Printf */
+
+/***********************************************************************/
+/* Make string output of a constant object. */
+/***********************************************************************/
+void CONSTANT::Prints(PGLOBAL g, char *ps, uint z)
+ {
+ Value->Prints(g, ps, z);
+ } /* end of Prints */
+
+/* -------------------------- Class STRING --------------------------- */
+
+/***********************************************************************/
+/* STRING public constructor for new char values. Alloc Size must be */
+/* calculated because PlugSubAlloc rounds up size to multiple of 8. */
+/***********************************************************************/
+STRING::STRING(PGLOBAL g, uint n, PCSZ str)
+{
+ G = g;
+ Length = (str) ? strlen(str) : 0;
+
+ if ((Strp = (PSZ)PlgDBSubAlloc(g, NULL, MY_MAX(n, Length) + 1))) {
+ if (str)
+ strcpy(Strp, str);
+ else
+ *Strp = 0;
+
+ Next = GetNext();
+ Size = (int)(Next - Strp);
+ Trc = false;
+ } else {
+ // This should normally never happen
+ Next = NULL;
+ Size = 0;
+ Trc = true;
+ } // endif Strp
+
+} // end of STRING constructor
+
+/***********************************************************************/
+/* Reallocate the string memory and return the (new) position. */
+/* If Next is equal to GetNext() this means that no new suballocation */
+/* has been done. Then we can just increase the size of the current */
+/* allocation and the Strp will remain pointing to the same memory. */
+/***********************************************************************/
+char *STRING::Realloc(uint len)
+{
+ char *p;
+ bool b = (Next == GetNext());
+
+ p = (char*)PlgDBSubAlloc(G, NULL, b ? len - Size : len);
+
+ if (!p) {
+ // No more room in Sarea; this is very unlikely
+ strcpy(G->Message, "No more room in work area");
+ Trc = true;
+ return NULL;
+ } // endif p
+
+ if (b)
+ p = Strp;
+
+ Next = GetNext();
+ Size = (int)(Next - p);
+ return p;
+} // end of Realloc
+
+/***********************************************************************/
+/* Set a STRING new PSZ value. */
+/***********************************************************************/
+bool STRING::Set(PCSZ s)
+{
+ if (!s)
+ return false;
+
+ uint len = strlen(s) + 1;
+
+ if (len > Size) {
+ char *p = Realloc(len);
+
+ if (!p)
+ return true;
+ else
+ Strp = p;
+
+ } // endif n
+
+ strcpy(Strp, s);
+ Length = len - 1;
+ return false;
+} // end of Set
+
+/***********************************************************************/
+/* Set a STRING new PSZ value. */
+/***********************************************************************/
+bool STRING::Set(char *s, uint n)
+{
+ if (!s)
+ return false;
+
+ uint len = strnlen(s, n) + 1;
+
+ if (len > Size) {
+ char *p = Realloc(len);
+
+ if (!p)
+ return true;
+ else
+ Strp = p;
+
+ } // endif n
+
+ strncpy(Strp, s, n);
+ Length = len - 1;
+ return false;
+} // end of Set
+
+/***********************************************************************/
+/* Append a char* to a STRING. */
+/***********************************************************************/
+bool STRING::Append(const char *s, uint ln, bool nq)
+{
+ if (!s)
+ return false;
+
+ uint i, len = Length + ln + 1;
+
+ if (len > Size) {
+ char *p = Realloc(len);
+
+ if (!p)
+ return true;
+ else if (p != Strp) {
+ strcpy(p, Strp);
+ Strp = p;
+ } // endif p
+
+ } // endif n
+
+ if (nq) {
+ for (i = 0; i < ln; i++)
+ switch (s[i]) {
+ case '\\': Strp[Length++] = '\\'; Strp[Length++] = '\\'; break;
+ case '\0': Strp[Length++] = '\\'; Strp[Length++] = '0'; break;
+ case '\'': Strp[Length++] = '\\'; Strp[Length++] = '\''; break;
+ case '\n': Strp[Length++] = '\\'; Strp[Length++] = 'n'; break;
+ case '\r': Strp[Length++] = '\\'; Strp[Length++] = 'r'; break;
+ case '\032': Strp[Length++] = '\\'; Strp[Length++] = 'Z'; break;
+ default: Strp[Length++] = s[i];
+ } // endswitch s[i]
+
+ } else
+ for (i = 0; i < ln && s[i]; i++)
+ Strp[Length++] = s[i];
+
+ Strp[Length] = 0;
+ return false;
+} // end of Append
+
+/***********************************************************************/
+/* Append a PCSZ to a STRING. */
+/***********************************************************************/
+bool STRING::Append(PCSZ s)
+{
+ if (!s)
+ return false;
+
+ uint len = Length + strlen(s) + 1;
+
+ if (len > Size) {
+ char *p = Realloc(len);
+
+ if (!p)
+ return true;
+ else if (p != Strp) {
+ strcpy(p, Strp);
+ Strp = p;
+ } // endif p
+
+ } // endif n
+
+ strcpy(Strp + Length, s);
+ Length = len - 1;
+ return false;
+} // end of Append
+
+/***********************************************************************/
+/* Append a STRING to a STRING. */
+/***********************************************************************/
+bool STRING::Append(STRING &str)
+{
+ return Append(str.GetStr());
+} // end of Append
+
+/***********************************************************************/
+/* Append a char to a STRING. */
+/***********************************************************************/
+bool STRING::Append(char c)
+{
+ if (Length + 2 > Size) {
+ char *p = Realloc(Length + 2);
+
+ if (!p)
+ return true;
+ else if (p != Strp) {
+ strcpy(p, Strp);
+ Strp = p;
+ } // endif p
+
+ } // endif n
+
+ Strp[Length++] = c;
+ Strp[Length] = 0;
+ return false;
+} // end of Append
+
+/***********************************************************************/
+/* Append a quoted PSZ to a STRING. */
+/***********************************************************************/
+bool STRING::Append_quoted(PCSZ s)
+{
+ bool b = Append('\'');
+
+ if (s) for (const char *p = s; !b && *p; p++)
+ switch (*p) {
+ case '\'':
+ case '\\':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\b':
+ case '\f': b |= Append('\\');
+ // fall through
+ default:
+ b |= Append(*p);
+ break;
+ } // endswitch *p
+
+ return (b |= Append('\''));
+} // end of Append_quoted
+
+/***********************************************************************/
+/* Resize to given length but only when last suballocated. */
+/* New size should be greater than string length. */
+/***********************************************************************/
+bool STRING::Resize(uint newsize)
+{
+ if (Next == GetNext() && newsize > Length) {
+ uint nsz = (((signed)newsize + 7) / 8) * 8;
+ int diff = (signed)Size - (signed)nsz;
+ PPOOLHEADER pp = (PPOOLHEADER)G->Sarea;
+
+ if ((signed)pp->FreeBlk + diff < 0)
+ return true; // Out of memory
+
+ pp->To_Free -= diff;
+ pp->FreeBlk += diff;
+ Size = nsz;
+ return false;
+ } else
+ return newsize > Size;
+
+} // end of Resize
diff --git a/storage/connect/xobject.h b/storage/connect/xobject.h
new file mode 100644
index 00000000..5b50e932
--- /dev/null
+++ b/storage/connect/xobject.h
@@ -0,0 +1,165 @@
+/*************** Xobject H Declares Source Code File (.H) **************/
+/* Name: XOBJECT.H Version 2.4 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1998-2014 */
+/* */
+/* This file contains the XOBJECT and derived classes declares. */
+/***********************************************************************/
+
+#ifndef __XOBJECT__H
+#define __XOBJECT__H
+
+/***********************************************************************/
+/* Include required application header files */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#include "block.h"
+#include "valblk.h" // includes value.h
+
+/***********************************************************************/
+/* Types used in some class definitions. */
+/***********************************************************************/
+typedef class STRING *PSTRG;
+
+/***********************************************************************/
+/* The pointer to the one and only needed void object. */
+/***********************************************************************/
+extern PXOB const pXVOID;
+
+/***********************************************************************/
+/* Class XOBJECT is the base class for all classes that can be used */
+/* in evaluation operations: FILTER, EXPRESSION, SCALF, FNC, COLBLK, */
+/* SELECT, FILTER as well as all the constant object types. */
+/***********************************************************************/
+class DllExport XOBJECT : public BLOCK {
+ public:
+ XOBJECT(void) {Value = NULL; Constant = false;}
+
+ // Implementation
+ PVAL GetValue(void) {return Value;}
+ bool IsConstant(void) {return Constant;}
+ virtual int GetType(void) {return TYPE_XOBJECT;}
+ virtual int GetResultType(void) {return TYPE_VOID;}
+ virtual int GetKey(void) {return 0;}
+#if defined(_DEBUG)
+ virtual void SetKey(int) {assert(false);}
+#else // !_DEBUG
+ virtual void SetKey(int) {} // Only defined for COLBLK
+#endif // !_DEBUG
+ virtual int GetLength(void) = 0;
+ virtual int GetLengthEx(void) = 0;
+ virtual PSZ GetCharValue(void);
+ virtual short GetShortValue(void);
+ virtual int GetIntValue(void);
+ virtual double GetFloatValue(void);
+ virtual int GetScale(void) = 0;
+
+ // Methods
+ virtual void Reset(void) {}
+ virtual bool Compare(PXOB) = 0;
+ virtual bool Init(PGLOBAL) {return false;}
+ virtual bool Eval(PGLOBAL) {return false;}
+ virtual bool SetFormat(PGLOBAL, FORMAT&) = 0;
+
+ protected:
+ PVAL Value; // The current value of the object.
+ bool Constant; // true for an object having a constant value.
+ }; // end of class XOBJECT
+
+/***********************************************************************/
+/* Class XVOID: represent a void (null) object. */
+/* Used to represent a void parameter for count(*) or for a filter. */
+/***********************************************************************/
+class DllExport XVOID : public XOBJECT {
+ public:
+ XVOID(void) {Constant = true;}
+
+ // Implementation
+ virtual int GetType(void) {return TYPE_VOID;}
+ virtual int GetLength(void) {return 0;}
+ virtual int GetLengthEx(void) {return 0;}
+ virtual PSZ GetCharValue(void) {return NULL;}
+ virtual int GetIntValue(void) {return 0;}
+ virtual double GetFloatValue(void) {return 0.0;}
+ virtual int GetScale() {return 0;}
+
+ // Methods
+ virtual bool Compare(PXOB xp) {return xp->GetType() == TYPE_VOID;}
+ virtual bool SetFormat(PGLOBAL, FORMAT&) {return true;}
+ }; // end of class XVOID
+
+
+/***********************************************************************/
+/* Class CONSTANT: represents a constant XOBJECT of any value type. */
+/* Note that the CONSTANT class is a friend of the VALUE class; */
+/***********************************************************************/
+class DllExport CONSTANT : public XOBJECT {
+ public:
+ CONSTANT(PGLOBAL g, void *value, short type);
+ CONSTANT(PGLOBAL g, int n);
+ CONSTANT(PVAL valp) {Value = valp; Constant = true;}
+
+ // Implementation
+ virtual int GetType(void) {return TYPE_CONST;}
+ virtual int GetResultType(void) {return Value->Type;}
+ virtual int GetLength(void) {return Value->GetValLen();}
+ virtual int GetScale() {return Value->GetValPrec();}
+ virtual int GetLengthEx(void);
+
+ // Methods
+ virtual bool Compare(PXOB xp);
+ virtual bool SetFormat(PGLOBAL g, FORMAT& fmt)
+ {return Value->SetConstFormat(g, fmt);}
+ void Convert(PGLOBAL g, int newtype);
+ void SetValue(PVAL vp) {Value = vp;}
+ virtual void Printf(PGLOBAL g, FILE *, uint);
+ virtual void Prints(PGLOBAL g, char *, uint);
+ }; // end of class CONSTANT
+
+/***********************************************************************/
+/* Class STRING handles variable length char strings. */
+/* It is mainly used to avoid buffer overrun. */
+/***********************************************************************/
+class DllExport STRING : public BLOCK {
+ public:
+ // Constructor
+ STRING(PGLOBAL g, uint n, PCSZ str = NULL);
+
+ // Implementation
+ inline int GetLength(void) {return (int)Length;}
+ inline void SetLength(uint n) {Length = n;}
+ inline PSZ GetStr(void) {return Strp;}
+ inline uint32 GetSize(void) {return Size;}
+ inline char GetLastChar(void) {return Length ? Strp[Length - 1] : 0;}
+ inline bool IsTruncated(void) {return Trc;}
+
+ // Methods
+ inline void Reset(void) {*Strp = 0;}
+ bool Set(PCSZ s);
+ bool Set(char *s, uint n);
+ bool Append(const char *s, uint ln, bool nq = false);
+ bool Append(PCSZ s);
+ bool Append(STRING &str);
+ bool Append(char c);
+ bool Resize(uint n);
+ bool Append_quoted(PCSZ s);
+ inline void Trim(void) {(void)Resize(Length + 1);}
+ inline void Chop(void) {if (Length) Strp[--Length] = 0;}
+ inline void RepLast(char c) {if (Length) Strp[Length-1] = c;}
+ inline void Truncate(uint n) {if (n < Length) {Strp[n] = 0; Length = n;}}
+
+ protected:
+ char *Realloc(uint len);
+ inline char *GetNext(void)
+ {return ((char*)G->Sarea)+((PPOOLHEADER)G->Sarea)->To_Free;}
+
+ // Members
+ PGLOBAL G; // To avoid parameter
+ PSZ Strp; // The char string
+ uint Length; // String length
+ uint Size; // Allocated size
+ bool Trc; // When truncated
+ char *Next; // Next alloc position
+ }; // end of class STRING
+
+#endif
diff --git a/storage/connect/xtable.h b/storage/connect/xtable.h
new file mode 100644
index 00000000..1b499e09
--- /dev/null
+++ b/storage/connect/xtable.h
@@ -0,0 +1,275 @@
+/**************** Table H Declares Source Code File (.H) ***************/
+/* Name: TABLE.H Version 2.4 */
+/* */
+/* (C) Copyright to the author Olivier BERTRAND 1999-2017 */
+/* */
+/* This file contains the TBX, OPJOIN and TDB class definitions. */
+/***********************************************************************/
+#if !defined(TABLE_DEFINED)
+#define TABLE_DEFINED
+
+
+/***********************************************************************/
+/* Include required application header files */
+/* block.h is header containing Block global declarations. */
+/***********************************************************************/
+#include "assert.h"
+#include "block.h"
+#include "colblk.h"
+//#include "m_ctype.h"
+#include "reldef.h"
+
+typedef class CMD *PCMD;
+typedef struct st_key_range key_range;
+
+// Commands executed by XDBC and MYX tables
+class CMD : public BLOCK {
+ public:
+ // Constructor
+ CMD(PGLOBAL g, char *cmd) {Cmd = PlugDup(g, cmd); Next = NULL;}
+
+ // Members
+ PCMD Next;
+ char *Cmd;
+}; // end of class CMD
+
+typedef class EXTCOL *PEXTCOL;
+typedef class CONDFIL *PCFIL;
+typedef class TDBCAT *PTDBCAT;
+typedef class CATCOL *PCATCOL;
+
+/***********************************************************************/
+/* Definition of class TDB with all its method functions. */
+/***********************************************************************/
+class DllExport TDB: public BLOCK { // Table Descriptor Block.
+ public:
+ // Constructors
+ TDB(PTABDEF tdp = NULL);
+ TDB(PTDB tdbp);
+
+ // Implementation
+ static void SetTnum(int n) {Tnum = n;}
+ inline PTABDEF GetDef(void) {return To_Def;}
+ inline PTDB GetOrig(void) {return To_Orig;}
+ inline TUSE GetUse(void) {return Use;}
+ inline PCFIL GetCondFil(void) {return To_CondFil;}
+ inline LPCSTR GetName(void) {return Name;}
+ inline PTABLE GetTable(void) {return To_Table;}
+ inline PCOL GetColumns(void) {return Columns;}
+ inline int GetDegree(void) {return Degree;}
+ inline MODE GetMode(void) {return Mode;}
+ inline PFIL GetFilter(void) {return To_Filter;}
+ inline PCOL GetSetCols(void) {return To_SetCols;}
+ inline void SetSetCols(PCOL colp) {To_SetCols = colp;}
+ inline void SetOrig(PTDB txp) {To_Orig = txp;}
+ inline void SetUse(TUSE n) {Use = n;}
+ inline void SetCondFil(PCFIL cfp) {To_CondFil = cfp;}
+ inline void SetNext(PTDB tdbp) {Next = tdbp;}
+ inline void SetName(LPCSTR name) {Name = name;}
+ inline void SetTable(PTABLE tablep) {To_Table = tablep;}
+ inline void SetColumns(PCOL colp) {Columns = colp;}
+ inline void SetDegree(int degree) {Degree = degree;}
+ inline void SetMode(MODE mode) {Mode = mode;}
+ inline const Item *GetCond(void) {return Cond;}
+ inline void SetCond(const Item *cond) {Cond = cond;}
+
+ // Properties
+ virtual AMT GetAmType(void) {return TYPE_AM_ERROR;}
+ virtual bool IsRemote(void) {return false;}
+ virtual bool IsIndexed(void) {return false;}
+ virtual void SetFilter(PFIL fp) {To_Filter = fp;}
+ virtual int GetTdb_No(void) {return Tdb_No;}
+ virtual PTDB GetNext(void) {return Next;}
+ virtual PCATLG GetCat(void) {return NULL;}
+ virtual void SetAbort(bool) {;}
+ virtual PKXBASE GetKindex(void) {return NULL;}
+
+ // Methods
+ virtual bool IsSame(PTDB tp) {return tp == this;}
+ virtual bool IsSpecial(PSZ name);
+ virtual bool IsReadOnly(void) {return Read_Only;}
+ virtual bool IsView(void) {return FALSE;}
+ virtual PCSZ GetPath(void);
+ virtual RECFM GetFtype(void) {return RECFM_NAF;}
+ virtual bool GetBlockValues(PGLOBAL) { return false; }
+ virtual int Cardinality(PGLOBAL) {return 0;}
+ virtual int GetRecpos(void) = 0;
+ virtual bool SetRecpos(PGLOBAL g, int recpos);
+ virtual int GetMaxSize(PGLOBAL) = 0;
+ virtual int GetProgMax(PGLOBAL) = 0;
+ virtual int GetProgCur(void) {return GetRecpos();}
+ virtual PCSZ GetFile(PGLOBAL) {return "Not a file";}
+ virtual void SetFile(PGLOBAL, PCSZ) {}
+ virtual void ResetDB(void) {}
+ virtual void ResetSize(void) {MaxSize = -1;}
+ virtual int RowNumber(PGLOBAL g, bool b = false);
+ virtual bool CanBeFiltered(void) {return true;}
+ virtual PTDB Duplicate(PGLOBAL) {return NULL;}
+ virtual PTDB Clone(PTABS) {return this;}
+ virtual PTDB Copy(PTABS t);
+ virtual void PrintAM(FILE *f, char *m)
+ {fprintf(f, "%s AM(%d)\n", m, GetAmType());}
+ virtual void Printf(PGLOBAL g, FILE *f, uint n);
+ virtual void Prints(PGLOBAL g, char *ps, uint z);
+ virtual PCSZ GetServer(void) = 0;
+ virtual int GetBadLines(void) {return 0;}
+ virtual CHARSET_INFO *data_charset(void);
+
+ // Database routines
+ virtual PCOL ColDB(PGLOBAL g, PSZ name, int num);
+ virtual PCOL MakeCol(PGLOBAL, PCOLDEF, PCOL, int)
+ {assert(false); return NULL;}
+ virtual PCOL InsertSpecialColumn(PCOL colp);
+ virtual PCOL InsertSpcBlk(PGLOBAL g, PCOLDEF cdp);
+ virtual void MarkDB(PGLOBAL g, PTDB tdb2);
+ virtual bool OpenDB(PGLOBAL) = 0;
+ virtual int ReadDB(PGLOBAL) = 0;
+ virtual int WriteDB(PGLOBAL) = 0;
+ virtual int DeleteDB(PGLOBAL, int) = 0;
+ virtual void CloseDB(PGLOBAL) = 0;
+ virtual int CheckWrite(PGLOBAL) {return 0;}
+ virtual bool ReadKey(PGLOBAL, OPVAL, const key_range *) = 0;
+
+ protected:
+ // Members
+ PTDB To_Orig; // Pointer to original if it is a copy
+ PTABDEF To_Def; // Points to catalog description block
+ TUSE Use;
+ PFIL To_Filter;
+ PCFIL To_CondFil; // To condition filter structure
+ const Item *Cond; // The condition used to make filters
+ static int Tnum; // Used to generate Tdb_no's
+ const int Tdb_No; // GetTdb_No() is always 0 for OPJOIN
+ PTDB Next; // Next in linearized queries
+ PTABLE To_Table; // Points to the XTAB object
+ LPCSTR Name; // Table name
+ PCOL Columns; // Points to the first column of the table
+ PCOL To_SetCols; // Points to updated columns
+ MODE Mode; // 10 Read, 30 Update, 40 Insert, 50 Delete
+ int Degree; // Number of columns
+ int Cardinal; // Table number of rows
+ int MaxSize; // Max size in number of lines
+ bool Read_Only; // True for read only tables
+ const CHARSET_INFO *m_data_charset;
+ const char *csname; // Table charset name
+}; // end of class TDB
+
+/***********************************************************************/
+/* This is the base class for all query tables (except decode). */
+/***********************************************************************/
+class DllExport TDBASE : public TDB {
+ friend class INDEXDEF;
+ friend class XINDEX;
+ friend class XINDXS;
+ public:
+ // Constructor
+ TDBASE(PTABDEF tdp = NULL);
+ TDBASE(PTDBASE tdbp);
+
+ // Implementation
+ inline int GetKnum(void) {return Knum;}
+ inline void SetKey_Col(PCOL *cpp) {To_Key_Col = cpp;}
+ inline void SetXdp(PIXDEF xdp) {To_Xdp = xdp;}
+ inline void SetKindex(PKXBASE kxp) {To_Kindex = kxp;}
+
+ // Properties
+ PKXBASE GetKindex(void) {return To_Kindex;}
+ PXOB *GetLink(void) {return To_Link;}
+ PIXDEF GetXdp(void) {return To_Xdp;}
+ void ResetKindex(PGLOBAL g, PKXBASE kxp);
+ PCOL Key(int i) {return (To_Key_Col) ? To_Key_Col[i] : NULL;}
+ PXOB Link(int i) { return (To_Link) ? To_Link[i] : NULL; }
+
+ // Methods
+ virtual bool IsUsingTemp(PGLOBAL) {return false;}
+ virtual PCATLG GetCat(void);
+ virtual void PrintAM(FILE *f, char *m);
+ virtual int GetProgMax(PGLOBAL g) {return GetMaxSize(g);}
+ virtual void RestoreNrec(void) {}
+ virtual int ResetTableOpt(PGLOBAL g, bool dop, bool dox);
+ virtual PCSZ GetServer(void) {return "Current";}
+
+ // Database routines
+ virtual int MakeIndex(PGLOBAL g, PIXDEF, bool)
+ {strcpy(g->Message, "Remote index"); return RC_INFO;}
+ virtual bool ReadKey(PGLOBAL, OPVAL, const key_range *)
+ {assert(false); return true;}
+
+ protected:
+ virtual bool PrepareWriting(PGLOBAL g) {strcpy(g->Message,
+ "This function should not be called for this table"); return true;}
+
+ // Members
+ PXOB *To_Link; // Points to column of previous relations
+ PCOL *To_Key_Col; // Points to key columns in current file
+ PKXBASE To_Kindex; // Points to table key index
+ PIXDEF To_Xdp; // To the index definition block
+ RECFM Ftype; // File type: 0-var 1-fixed 2-binary (VCT)
+ int Knum; // Size of key arrays
+}; // end of class TDBASE
+
+/***********************************************************************/
+/* The abstract base class declaration for the catalog tables. */
+/***********************************************************************/
+class DllExport TDBCAT : public TDBASE {
+ friend class CATCOL;
+ public:
+ // Constructor
+ TDBCAT(PTABDEF tdp);
+
+ // Implementation
+ virtual AMT GetAmType(void) {return TYPE_AM_CAT;}
+
+ // Methods
+ virtual int GetRecpos(void) {return N;}
+ virtual int GetProgCur(void) {return N;}
+ virtual int RowNumber(PGLOBAL, bool = false) {return N + 1;}
+ virtual bool SetRecpos(PGLOBAL g, int recpos);
+
+ // Database routines
+ virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
+ virtual int Cardinality(PGLOBAL) {return 10;} // To avoid assert
+ virtual int GetMaxSize(PGLOBAL g);
+ virtual bool OpenDB(PGLOBAL g);
+ virtual int ReadDB(PGLOBAL g);
+ virtual int WriteDB(PGLOBAL g);
+ virtual int DeleteDB(PGLOBAL g, int irc);
+ virtual void CloseDB(PGLOBAL g);
+
+ protected:
+ // Specific routines
+ virtual PQRYRES GetResult(PGLOBAL g) = 0;
+ bool Initialize(PGLOBAL g);
+ bool InitCol(PGLOBAL g);
+
+ // Members
+ PQRYRES Qrp;
+ int N; // Row number
+ bool Init;
+ }; // end of class TDBCAT
+
+/***********************************************************************/
+/* Class CATCOL: ODBC info column. */
+/***********************************************************************/
+class DllExport CATCOL : public COLBLK {
+ friend class TDBCAT;
+ public:
+ // Constructors
+ CATCOL(PCOLDEF cdp, PTDB tdbp, int n);
+
+ // Implementation
+ virtual int GetAmType(void) {return TYPE_AM_ODBC;}
+
+ // Methods
+ virtual void ReadColumn(PGLOBAL g);
+
+ protected:
+ CATCOL(void) {} // Default constructor not to be used
+
+ // Members
+ PTDBCAT Tdbp; // Points to ODBC table block
+ PCOLRES Crp; // The column data array
+ int Flag;
+ }; // end of class CATCOL
+
+#endif // TABLE_DEFINED
diff --git a/storage/connect/zip.c b/storage/connect/zip.c
new file mode 100644
index 00000000..52d63e10
--- /dev/null
+++ b/storage/connect/zip.c
@@ -0,0 +1,2007 @@
+/* zip.c -- IO on .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ Changes
+ Oct-2009 - Mathias Svensson - Remove old C style function prototypes
+ Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives
+ Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.
+ Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data
+ It is used when recreting zip archive with RAW when deleting items from a zip.
+ ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed.
+ Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required)
+ Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "zlib.h"
+#include "zip.h"
+#include "my_attribute.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#ifndef VERSIONMADEBY
+# define VERSIONMADEBY (0x0) /* platform depedent */
+#endif
+
+#ifndef Z_BUFSIZE
+#define Z_BUFSIZE (64*1024) //(16384)
+#endif
+
+#ifndef Z_MAXFILENAMEINZIP
+#define Z_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+/*
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+*/
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+
+// NOT sure that this work on ALL platform
+#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32))
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifndef DEF_MEM_LEVEL
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+#endif
+const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+
+#define SIZEDATA_INDATABLOCK (4096-(4*4))
+
+#define LOCALHEADERMAGIC (0x04034b50)
+#define CENTRALHEADERMAGIC (0x02014b50)
+#define ENDHEADERMAGIC (0x06054b50)
+#define ZIP64ENDHEADERMAGIC (0x6064b50)
+#define ZIP64ENDLOCHEADERMAGIC (0x7064b50)
+
+#define FLAG_LOCALHEADER_OFFSET (0x06)
+#define CRC_LOCALHEADER_OFFSET (0x0e)
+
+#define SIZECENTRALHEADER (0x2e) /* 46 */
+
+typedef struct linkedlist_datablock_internal_s
+{
+ struct linkedlist_datablock_internal_s* next_datablock;
+ uLong avail_in_this_block;
+ uLong filled_in_this_block;
+ uLong unused; /* for future use and alignement */
+ unsigned char data[SIZEDATA_INDATABLOCK];
+} linkedlist_datablock_internal;
+
+typedef struct linkedlist_data_s
+{
+ linkedlist_datablock_internal* first_block;
+ linkedlist_datablock_internal* last_block;
+} linkedlist_data;
+
+
+typedef struct
+{
+ z_stream stream; /* zLib stream structure for inflate */
+#ifdef HAVE_BZIP2
+ bz_stream bstream; /* bzLib stream structure for bziped */
+#endif
+
+ int stream_initialised; /* 1 is stream is initialised */
+ uInt pos_in_buffered_data; /* last written byte in buffered_data */
+
+ ZPOS64_T pos_local_header; /* offset of the local header of the file
+ currenty writing */
+ char* central_header; /* central header data for the current file */
+ uLong size_centralExtra;
+ uLong size_centralheader; /* size of the central header for cur file */
+ uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */
+ uLong flag; /* flag of the file currently writing */
+
+ int method; /* compression method of file currenty wr.*/
+ int raw; /* 1 for directly writing raw data */
+ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
+ uLong dosDate;
+ uLong crc32;
+ int encrypt;
+ int zip64; /* Add ZIP64 extened information in the extra field */
+ ZPOS64_T pos_zip64extrainfo;
+ ZPOS64_T totalCompressedData;
+ ZPOS64_T totalUncompressedData;
+#ifndef NOCRYPT
+ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
+ const z_crc_t* pcrc_32_tab;
+ int crypt_header_size;
+#endif
+} curfile64_info;
+
+typedef struct
+{
+ zlib_filefunc64_32_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ linkedlist_data central_dir;/* datablock with central dir in construction*/
+ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
+ curfile64_info ci; /* info on the file curretly writing */
+
+ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */
+ ZPOS64_T add_position_when_writting_offset;
+ ZPOS64_T number_entry;
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ char *globalcomment;
+#endif
+
+} zip64_internal;
+
+
+#ifndef NOCRYPT
+#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+#include "crypt.h"
+#endif
+
+local linkedlist_datablock_internal* allocate_new_datablock()
+{
+ linkedlist_datablock_internal* ldi;
+ ldi = (linkedlist_datablock_internal*)
+ ALLOC(sizeof(linkedlist_datablock_internal));
+ if (ldi!=NULL)
+ {
+ ldi->next_datablock = NULL ;
+ ldi->filled_in_this_block = 0 ;
+ ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
+ }
+ return ldi;
+}
+
+local void free_datablock(linkedlist_datablock_internal* ldi)
+{
+ while (ldi!=NULL)
+ {
+ linkedlist_datablock_internal* ldinext = ldi->next_datablock;
+ TRYFREE(ldi);
+ ldi = ldinext;
+ }
+}
+
+local void init_linkedlist(linkedlist_data* ll)
+{
+ ll->first_block = ll->last_block = NULL;
+}
+
+local void free_linkedlist(linkedlist_data* ll)
+{
+ free_datablock(ll->first_block);
+ ll->first_block = ll->last_block = NULL;
+}
+
+
+local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len)
+{
+ linkedlist_datablock_internal* ldi;
+ const unsigned char* from_copy;
+
+ if (ll==NULL)
+ return ZIP_INTERNALERROR;
+
+ if (ll->last_block == NULL)
+ {
+ ll->first_block = ll->last_block = allocate_new_datablock();
+ if (ll->first_block == NULL)
+ return ZIP_INTERNALERROR;
+ }
+
+ ldi = ll->last_block;
+ from_copy = (unsigned char*)buf;
+
+ while (len>0)
+ {
+ uInt copy_this;
+ uInt i;
+ unsigned char* to_copy;
+
+ if (ldi->avail_in_this_block==0)
+ {
+ ldi->next_datablock = allocate_new_datablock();
+ if (ldi->next_datablock == NULL)
+ return ZIP_INTERNALERROR;
+ ldi = ldi->next_datablock ;
+ ll->last_block = ldi;
+ }
+
+ if (ldi->avail_in_this_block < len)
+ copy_this = (uInt)ldi->avail_in_this_block;
+ else
+ copy_this = (uInt)len;
+
+ to_copy = &(ldi->data[ldi->filled_in_this_block]);
+
+ for (i=0;i<copy_this;i++)
+ *(to_copy+i)=*(from_copy+i);
+
+ ldi->filled_in_this_block += copy_this;
+ ldi->avail_in_this_block -= copy_this;
+ from_copy += copy_this ;
+ len -= copy_this;
+ }
+ return ZIP_OK;
+}
+
+
+
+/****************************************************************************/
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+/* ===========================================================================
+ Inputs a long in LSB order to the given file
+ nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)
+*/
+
+local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte));
+local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)
+{
+ unsigned char buf[8];
+ int n;
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+ if (x != 0)
+ { /* data overflow - hack for ZIP64 (X Roche) */
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = 0xff;
+ }
+ }
+
+ if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte)
+ return ZIP_ERRNO;
+ else
+ return ZIP_OK;
+}
+
+local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte));
+local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte)
+{
+ unsigned char* buf=(unsigned char*)dest;
+ int n;
+ for (n = 0; n < nbByte; n++) {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+
+ if (x != 0)
+ { /* data overflow - hack for ZIP64 */
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = 0xff;
+ }
+ }
+}
+
+/****************************************************************************/
+
+
+local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm)
+{
+ uLong year = (uLong)ptm->tm_year;
+ if (year>=1980)
+ year-=1980;
+ else if (year>=80)
+ year-=80;
+ return
+ (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
+ ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
+}
+
+
+/****************************************************************************/
+
+local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi));
+
+local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi)
+{
+ unsigned char c;
+ int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return ZIP_OK;
+ }
+ else
+ {
+ if (ZERROR64(*pzlib_filefunc_def,filestream))
+ return ZIP_ERRNO;
+ else
+ return ZIP_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
+
+local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
+
+local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<16;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX));
+
+
+local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)
+{
+ ZPOS64_T x;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (ZPOS64_T)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<8;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<16;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<24;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<32;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<40;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<48;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<56;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+
+ return err;
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+
+local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;) {
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+ }
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+
+/*
+Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before
+the global comment)
+*/
+local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+
+local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+ uLong uL;
+ ZPOS64_T relativeOffset;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ {
+ // Signature "0x07064b50" Zip64 end of central directory locater
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+
+ TRYFREE(buf);
+ if (uPosFound == 0)
+ return 0;
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+
+ /* number of the disk with the start of the zip64 end of central directory */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+ if (uL != 0)
+ return 0;
+
+ /* relative offset of the zip64 end of central directory record */
+ if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK)
+ return 0;
+
+ /* total number of disks */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+ if (uL != 1)
+ return 0;
+
+ /* Goto Zip64 end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+
+ if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'
+ return 0;
+
+ return relativeOffset;
+}
+
+static int LoadCentralDirectoryRecord(zip64_internal* pziinit)
+{
+ int err=ZIP_OK;
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+
+ ZPOS64_T size_central_dir; /* size of the central directory */
+ ZPOS64_T offset_central_dir; /* offset of start of central directory */
+ ZPOS64_T central_pos;
+ uLong uL;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ ZPOS64_T number_entry;
+ ZPOS64_T number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+ uLong VersionMadeBy;
+ uLong VersionNeeded;
+ uLong size_comment;
+
+ int hasZIP64Record = 0;
+
+ // check first if we find a ZIP64 record
+ central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream);
+ if(central_pos > 0)
+ {
+ hasZIP64Record = 1;
+ }
+ else if(central_pos == 0)
+ {
+ central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream);
+ }
+
+/* disable to allow appending to empty ZIP archive
+ if (central_pos==0)
+ err=ZIP_ERRNO;
+*/
+
+ if(hasZIP64Record)
+ {
+ ZPOS64_T sizeEndOfCentralDirectory;
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* size of zip64 end of central directory record */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* version made by */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* version needed to extract */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of this disk */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central directory on this disk */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central directory */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
+ err=ZIP_BADZIPFILE;
+
+ /* size of the central directory */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ // TODO..
+ // read the comment from the standard central header.
+ size_comment = 0;
+ }
+ else
+ {
+ // Read End of central Directory info
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=ZIP_ERRNO;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of this disk */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ number_entry = 0;
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ number_entry = uL;
+
+ /* total number of entries in the central dir */
+ number_entry_CD = 0;
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ number_entry_CD = uL;
+
+ if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
+ err=ZIP_BADZIPFILE;
+
+ /* size of the central directory */
+ size_central_dir = 0;
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ size_central_dir = uL;
+
+ /* offset of start of central directory with respect to the starting disk number */
+ offset_central_dir = 0;
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ offset_central_dir = uL;
+
+
+ /* zipfile global comment length */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ }
+
+ if ((central_pos<offset_central_dir+size_central_dir) &&
+ (err==ZIP_OK))
+ err=ZIP_BADZIPFILE;
+
+ if (err!=ZIP_OK)
+ {
+ ZCLOSE64(pziinit->z_filefunc, pziinit->filestream);
+ return ZIP_ERRNO;
+ }
+
+ if (size_comment>0)
+ {
+ pziinit->globalcomment = (char*)ALLOC(size_comment+1);
+ if (pziinit->globalcomment)
+ {
+ size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment);
+ pziinit->globalcomment[size_comment]=0;
+ }
+ }
+
+ byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir);
+ pziinit->add_position_when_writting_offset = byte_before_the_zipfile;
+
+ {
+ ZPOS64_T size_central_dir_to_read = size_central_dir;
+ size_t buf_size = SIZEDATA_INDATABLOCK;
+ void* buf_read = (void*)ALLOC(buf_size);
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ while ((size_central_dir_to_read>0) && (err==ZIP_OK))
+ {
+ ZPOS64_T read_this = SIZEDATA_INDATABLOCK;
+ if (read_this > size_central_dir_to_read)
+ read_this = size_central_dir_to_read;
+
+ if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this)
+ err=ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this);
+
+ size_central_dir_to_read-=read_this;
+ }
+ TRYFREE(buf_read);
+ }
+ pziinit->begin_pos = byte_before_the_zipfile;
+ pziinit->number_entry = number_entry_CD;
+
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ return err;
+}
+
+
+#endif /* !NO_ADDFILEINEXISTINGZIP*/
+
+
+/************************************************************/
+static zipFile zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def)
+{
+ zip64_internal ziinit;
+ zip64_internal* zi;
+ int err=ZIP_OK;
+
+ ziinit.z_filefunc.zseek32_file = NULL;
+ ziinit.z_filefunc.ztell32_file = NULL;
+ if (pzlib_filefunc64_32_def==NULL)
+ fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64);
+ else
+ ziinit.z_filefunc = *pzlib_filefunc64_32_def;
+
+ ziinit.filestream = ZOPEN64(ziinit.z_filefunc,
+ pathname,
+ (append == APPEND_STATUS_CREATE) ?
+ (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :
+ (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));
+
+ if (ziinit.filestream == NULL)
+ return NULL;
+
+ if (append == APPEND_STATUS_CREATEAFTER)
+ ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END);
+
+ ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream);
+ ziinit.in_opened_file_inzip = 0;
+ ziinit.ci.stream_initialised = 0;
+ ziinit.number_entry = 0;
+ ziinit.add_position_when_writting_offset = 0;
+ init_linkedlist(&(ziinit.central_dir));
+
+
+
+ zi = (zip64_internal*)ALLOC(sizeof(zip64_internal));
+ if (zi==NULL)
+ {
+ ZCLOSE64(ziinit.z_filefunc,ziinit.filestream);
+ return NULL;
+ }
+
+ /* now we add file in a zipfile */
+# ifndef NO_ADDFILEINEXISTINGZIP
+ ziinit.globalcomment = NULL;
+ if (append == APPEND_STATUS_ADDINZIP)
+ {
+ // Read and Cache Central Directory Records
+ err = LoadCentralDirectoryRecord(&ziinit);
+ }
+
+ if (globalcomment)
+ {
+ *globalcomment = ziinit.globalcomment;
+ }
+# endif /* !NO_ADDFILEINEXISTINGZIP*/
+
+ if (err != ZIP_OK)
+ {
+# ifndef NO_ADDFILEINEXISTINGZIP
+ TRYFREE(ziinit.globalcomment);
+# endif /* !NO_ADDFILEINEXISTINGZIP*/
+ TRYFREE(zi);
+ return NULL;
+ }
+ else
+ {
+ *zi = ziinit;
+ return (zipFile)zi;
+ }
+}
+
+extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def)
+{
+ if (pzlib_filefunc32_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+ return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
+ }
+ else
+ return zipOpen3(pathname, append, globalcomment, NULL);
+}
+
+extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ if (pzlib_filefunc_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+ zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+ return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
+ }
+ else
+ return zipOpen3(pathname, append, globalcomment, NULL);
+}
+
+
+
+extern zipFile ZEXPORT zipOpen (const char* pathname, int append)
+{
+ return zipOpen3((const void*)pathname,append,NULL,NULL);
+}
+
+extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append)
+{
+ return zipOpen3(pathname,append,NULL,NULL);
+}
+
+static int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local)
+{
+ /* write the local header */
+ int err;
+ uInt size_filename = (uInt)strlen(filename);
+ uInt size_extrafield = size_extrafield_local;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4);
+
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2);
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2);
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);
+
+ // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */
+ }
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2);
+
+ if(zi->ci.zip64)
+ {
+ size_extrafield += 20;
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2);
+
+ if ((err==ZIP_OK) && (size_filename > 0))
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename)
+ err = ZIP_ERRNO;
+ }
+
+ if ((err==ZIP_OK) && (size_extrafield_local > 0))
+ {
+ if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local)
+ err = ZIP_ERRNO;
+ }
+
+
+ if ((err==ZIP_OK) && (zi->ci.zip64))
+ {
+ // write the Zip64 extended info
+ short HeaderID = 1;
+ short DataSize = 16;
+ ZPOS64_T CompressedSize = 0;
+ ZPOS64_T UncompressedSize = 0;
+
+ // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file)
+ zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2);
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2);
+
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8);
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8);
+ }
+
+ return err;
+}
+
+/*
+ NOTE.
+ When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped
+ before calling this function it can be done with zipRemoveExtraInfoBlock
+
+ It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize
+ unnecessary allocations.
+ */
+extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting __attribute__((unused)),
+ uLong versionMadeBy, uLong flagBase, int zip64)
+{
+ zip64_internal* zi;
+ uInt size_filename;
+ uInt size_comment;
+ uInt i;
+ int err = ZIP_OK;
+
+#ifdef NOCRYPT
+ if (password != NULL)
+ return ZIP_PARAMERROR;
+#endif
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+
+#ifdef HAVE_BZIP2
+ if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED))
+ return ZIP_PARAMERROR;
+#else
+ if ((method!=0) && (method!=Z_DEFLATED))
+ return ZIP_PARAMERROR;
+#endif
+
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ if (err != ZIP_OK)
+ return err;
+ }
+
+ if (filename==NULL)
+ filename="-";
+
+ if (comment==NULL)
+ size_comment = 0;
+ else
+ size_comment = (uInt)strlen(comment);
+
+ size_filename = (uInt)strlen(filename);
+
+ if (zipfi == NULL)
+ zi->ci.dosDate = 0;
+ else
+ {
+ if (zipfi->dosDate != 0)
+ zi->ci.dosDate = zipfi->dosDate;
+ else
+ zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date);
+ }
+
+ zi->ci.flag = flagBase;
+ if ((level==8) || (level==9))
+ zi->ci.flag |= 2;
+ if (level==2)
+ zi->ci.flag |= 4;
+ if (level==1)
+ zi->ci.flag |= 6;
+ if (password != NULL)
+ zi->ci.flag |= 1;
+
+ zi->ci.crc32 = 0;
+ zi->ci.method = method;
+ zi->ci.encrypt = 0;
+ zi->ci.stream_initialised = 0;
+ zi->ci.pos_in_buffered_data = 0;
+ zi->ci.raw = raw;
+ zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment;
+ zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data
+
+ zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree);
+
+ zi->ci.size_centralExtra = size_extrafield_global;
+ zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
+ /* version info */
+ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
+ zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
+ zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
+ zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
+ zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
+
+ if (zipfi==NULL)
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
+
+ if (zipfi==NULL)
+ zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
+
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4);
+
+ for (i=0;i<size_filename;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
+
+ for (i=0;i<size_extrafield_global;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
+ *(((const char*)extrafield_global)+i);
+
+ for (i=0;i<size_comment;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
+ size_extrafield_global+i) = *(comment+i);
+ if (zi->ci.central_header == NULL)
+ return ZIP_INTERNALERROR;
+
+ zi->ci.zip64 = zip64;
+ zi->ci.totalCompressedData = 0;
+ zi->ci.totalUncompressedData = 0;
+ zi->ci.pos_zip64extrainfo = 0;
+
+ err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local);
+
+#ifdef HAVE_BZIP2
+ zi->ci.bstream.avail_in = (uInt)0;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ zi->ci.bstream.total_in_hi32 = 0;
+ zi->ci.bstream.total_in_lo32 = 0;
+ zi->ci.bstream.total_out_hi32 = 0;
+ zi->ci.bstream.total_out_lo32 = 0;
+#endif
+
+ zi->ci.stream.avail_in = (uInt)0;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ zi->ci.stream.total_in = 0;
+ zi->ci.stream.total_out = 0;
+ zi->ci.stream.data_type = Z_BINARY;
+
+#ifdef HAVE_BZIP2
+ if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+#else
+ if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+#endif
+ {
+ if(zi->ci.method == Z_DEFLATED)
+ {
+ zi->ci.stream.zalloc = (alloc_func)0;
+ zi->ci.stream.zfree = (free_func)0;
+ zi->ci.stream.opaque = (voidpf)0;
+
+ if (windowBits>0)
+ windowBits = -windowBits;
+
+ err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
+
+ if (err==Z_OK)
+ zi->ci.stream_initialised = Z_DEFLATED;
+ }
+ else if(zi->ci.method == Z_BZIP2ED)
+ {
+#ifdef HAVE_BZIP2
+ // Init BZip stuff here
+ zi->ci.bstream.bzalloc = 0;
+ zi->ci.bstream.bzfree = 0;
+ zi->ci.bstream.opaque = (voidpf)0;
+
+ err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35);
+ if(err == BZ_OK)
+ zi->ci.stream_initialised = Z_BZIP2ED;
+#endif
+ }
+
+ }
+
+# ifndef NOCRYPT
+ zi->ci.crypt_header_size = 0;
+ if ((err==Z_OK) && (password != NULL))
+ {
+ unsigned char bufHead[RAND_HEAD_LEN];
+ unsigned int sizeHead;
+ zi->ci.encrypt = 1;
+ zi->ci.pcrc_32_tab = get_crc_table();
+ /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
+
+ sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
+ zi->ci.crypt_header_size = sizeHead;
+
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)
+ err = ZIP_ERRNO;
+ }
+# endif
+
+ if (err==Z_OK)
+ zi->in_opened_file_inzip = 1;
+ return err;
+}
+
+extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting,
+ uLong versionMadeBy, uLong flagBase)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, versionMadeBy, flagBase, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, VERSIONMADEBY, 0, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void*extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void*extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, 0);
+}
+
+local int zip64FlushWriteBuffer(zip64_internal* zi)
+{
+ int err=ZIP_OK;
+
+ if (zi->ci.encrypt != 0)
+ {
+#ifndef NOCRYPT
+ uInt i;
+ int t;
+ for (i=0;i<zi->ci.pos_in_buffered_data;i++)
+ zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t);
+#endif
+ }
+
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data)
+ err = ZIP_ERRNO;
+
+ zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data;
+
+#ifdef HAVE_BZIP2
+ if(zi->ci.method == Z_BZIP2ED)
+ {
+ zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32;
+ zi->ci.bstream.total_in_lo32 = 0;
+ zi->ci.bstream.total_in_hi32 = 0;
+ }
+ else
+#endif
+ {
+ zi->ci.totalUncompressedData += zi->ci.stream.total_in;
+ zi->ci.stream.total_in = 0;
+ }
+
+
+ zi->ci.pos_in_buffered_data = 0;
+
+ return err;
+}
+
+extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len)
+{
+ zip64_internal* zi;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+
+ zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len);
+
+#ifdef HAVE_BZIP2
+ if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw))
+ {
+ zi->ci.bstream.next_in = (void*)buf;
+ zi->ci.bstream.avail_in = len;
+ err = BZ_RUN_OK;
+
+ while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0))
+ {
+ if (zi->ci.bstream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ }
+
+
+ if(err != BZ_RUN_OK)
+ break;
+
+ if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+ uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32;
+// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32;
+ err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN);
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ;
+ }
+ }
+
+ if(err == BZ_RUN_OK)
+ err = ZIP_OK;
+ }
+ else
+#endif
+ {
+ zi->ci.stream.next_in = (Bytef*)buf;
+ zi->ci.stream.avail_in = len;
+
+ while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
+ {
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+
+
+ if(err != ZIP_OK)
+ break;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ uLong uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_NO_FLUSH);
+ if(uTotalOutBefore > zi->ci.stream.total_out)
+ {
+ int bBreak = 0;
+ bBreak++;
+ }
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+ }
+ else
+ {
+ uInt copy_this,i;
+ if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
+ copy_this = zi->ci.stream.avail_in;
+ else
+ copy_this = zi->ci.stream.avail_out;
+
+ for (i = 0; i < copy_this; i++)
+ *(((char*)zi->ci.stream.next_out)+i) =
+ *(((const char*)zi->ci.stream.next_in)+i);
+ {
+ zi->ci.stream.avail_in -= copy_this;
+ zi->ci.stream.avail_out-= copy_this;
+ zi->ci.stream.next_in+= copy_this;
+ zi->ci.stream.next_out+= copy_this;
+ zi->ci.stream.total_in+= copy_this;
+ zi->ci.stream.total_out+= copy_this;
+ zi->ci.pos_in_buffered_data += copy_this;
+ }
+ }
+ }// while(...)
+ }
+
+ return err;
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32)
+{
+ return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32);
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32)
+{
+ zip64_internal* zi;
+ ZPOS64_T compressed_size;
+ uLong invalidValue = 0xffffffff;
+ short datasize = 0;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+ zi->ci.stream.avail_in = 0;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ while (err==ZIP_OK)
+ {
+ uLong uTotalOutBefore;
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+ uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_FINISH);
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+ }
+ }
+ else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+#ifdef HAVE_BZIP2
+ err = BZ_FINISH_OK;
+ while (err==BZ_FINISH_OK)
+ {
+ uLong uTotalOutBefore;
+ if (zi->ci.bstream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ }
+ uTotalOutBefore = zi->ci.bstream.total_out_lo32;
+ err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH);
+ if(err == BZ_STREAM_END)
+ err = Z_STREAM_END;
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore);
+ }
+
+ if(err == BZ_FINISH_OK)
+ err = ZIP_OK;
+#endif
+ }
+
+ if (err==Z_STREAM_END)
+ err=ZIP_OK; /* this is normal */
+
+ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
+ {
+ if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ }
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ int tmp_err = deflateEnd(&zi->ci.stream);
+ if (err == ZIP_OK)
+ err = tmp_err;
+ zi->ci.stream_initialised = 0;
+ }
+#ifdef HAVE_BZIP2
+ else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+ int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream);
+ if (err==ZIP_OK)
+ err = tmperr;
+ zi->ci.stream_initialised = 0;
+ }
+#endif
+
+ if (!zi->ci.raw)
+ {
+ crc32 = (uLong)zi->ci.crc32;
+ uncompressed_size = zi->ci.totalUncompressedData;
+ }
+ compressed_size = zi->ci.totalCompressedData;
+
+# ifndef NOCRYPT
+ compressed_size += zi->ci.crypt_header_size;
+# endif
+
+ // update Current Item crc and sizes,
+ if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff)
+ {
+ /*version Made by*/
+ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2);
+ /*version needed*/
+ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2);
+
+ }
+
+ zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/
+
+
+ if(compressed_size >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/
+
+ /// set internal file attributes field
+ if (zi->ci.stream.data_type == Z_ASCII)
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);
+
+ if(uncompressed_size >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/
+
+ // Add ZIP64 extra info field for uncompressed size
+ if(uncompressed_size >= 0xffffffff)
+ datasize += 8;
+
+ // Add ZIP64 extra info field for compressed size
+ if(compressed_size >= 0xffffffff)
+ datasize += 8;
+
+ // Add ZIP64 extra info field for relative offset to local file header of current file
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ datasize += 8;
+
+ if(datasize > 0)
+ {
+ char* p = NULL;
+
+ if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree)
+ {
+ // we can not write more data to the buffer that we have room for.
+ return ZIP_BADZIPFILE;
+ }
+
+ p = zi->ci.central_header + zi->ci.size_centralheader;
+
+ // Add Extra Information Header for 'ZIP64 information'
+ zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID
+ p += 2;
+ zip64local_putValue_inmemory(p, datasize, 2); // DataSize
+ p += 2;
+
+ if(uncompressed_size >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, uncompressed_size, 8);
+ p += 8;
+ }
+
+ if(compressed_size >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, compressed_size, 8);
+ p += 8;
+ }
+
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8);
+ p += 8;
+ }
+
+ // Update how much extra free space we got in the memory buffer
+ // and increase the centralheader size so the new ZIP64 fields are included
+ // ( 4 below is the size of HeaderID and DataSize field )
+ zi->ci.size_centralExtraFree -= datasize + 4;
+ zi->ci.size_centralheader += datasize + 4;
+
+ // Update the extra info size field
+ zi->ci.size_centralExtra += datasize + 4;
+ zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2);
+ }
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader);
+
+ free(zi->ci.central_header);
+
+ if (err==ZIP_OK)
+ {
+ // Update the LocalFileHeader with the new values.
+
+ ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
+
+ if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff )
+ {
+ if(zi->ci.pos_zip64extrainfo > 0)
+ {
+ // Update the size in the ZIP64 extended field.
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+
+ if (err==ZIP_OK) /* compressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8);
+
+ if (err==ZIP_OK) /* uncompressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8);
+ }
+ else
+ err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal
+ }
+ else
+ {
+ if (err==ZIP_OK) /* compressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
+
+ if (err==ZIP_OK) /* uncompressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
+ }
+
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+ }
+
+ zi->number_entry ++;
+ zi->in_opened_file_inzip = 0;
+
+ return err;
+}
+
+extern int ZEXPORT zipCloseFileInZip (zipFile file)
+{
+ return zipCloseFileInZipRaw (file,0,0);
+}
+
+static int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip)
+{
+ int err = ZIP_OK;
+ ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4);
+
+ /*num disks*/
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ /*relative offset*/
+ if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8);
+
+ /*total disks*/ /* Do not support spawning of disk so always say 1 here*/
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4);
+
+ return err;
+}
+
+static int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
+{
+ int err = ZIP_OK;
+
+ uLong Zip64DataSize = 44;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4);
+
+ if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ?
+
+ if (err==ZIP_OK) /* version made by */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
+
+ if (err==ZIP_OK) /* version needed */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
+
+ if (err==ZIP_OK) /* number of this disk */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
+
+ if (err==ZIP_OK) /* size of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8);
+
+ if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
+ {
+ ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8);
+ }
+ return err;
+}
+static int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
+{
+ int err = ZIP_OK;
+
+ /*signature*/
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
+
+ if (err==ZIP_OK) /* number of this disk */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
+
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+ {
+ {
+ if(zi->number_entry >= 0xFFFF)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
+ }
+ }
+
+ if (err==ZIP_OK) /* total number of entries in the central dir */
+ {
+ if(zi->number_entry >= 0xFFFF)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
+ }
+
+ if (err==ZIP_OK) /* size of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4);
+
+ if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
+ {
+ ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ if(pos >= 0xffffffff)
+ {
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4);
+ }
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);
+ }
+
+ return err;
+}
+
+static int Write_GlobalComment(zip64_internal* zi, const char* global_comment)
+{
+ int err = ZIP_OK;
+ uInt size_global_comment = 0;
+
+ if(global_comment != NULL)
+ size_global_comment = (uInt)strlen(global_comment);
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);
+
+ if (err == ZIP_OK && size_global_comment > 0)
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment)
+ err = ZIP_ERRNO;
+ }
+ return err;
+}
+
+extern int ZEXPORT zipClose (zipFile file, const char* global_comment)
+{
+ zip64_internal* zi;
+ int err = 0;
+ uLong size_centraldir = 0;
+ ZPOS64_T centraldir_pos_inzip;
+ ZPOS64_T pos;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ }
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ if (global_comment==NULL)
+ global_comment = zi->globalcomment;
+#endif
+
+ centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ if (err==ZIP_OK)
+ {
+ linkedlist_datablock_internal* ldi = zi->central_dir.first_block;
+ while (ldi!=NULL)
+ {
+ if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block)
+ err = ZIP_ERRNO;
+ }
+
+ size_centraldir += ldi->filled_in_this_block;
+ ldi = ldi->next_datablock;
+ }
+ }
+ free_linkedlist(&(zi->central_dir));
+
+ pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ if(pos >= 0xffffffff || zi->number_entry > 0xFFFF)
+ {
+ ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream);
+ Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
+
+ Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos);
+ }
+
+ if (err==ZIP_OK)
+ err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
+
+ if(err == ZIP_OK)
+ err = Write_GlobalComment(zi, global_comment);
+
+ if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0)
+ if (err == ZIP_OK)
+ err = ZIP_ERRNO;
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ TRYFREE(zi->globalcomment);
+#endif
+ TRYFREE(zi);
+
+ return err;
+}
+
+extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader)
+{
+ char* p = pData;
+ int size = 0;
+ char* pNewHeader;
+ char* pTmp;
+ short header;
+ short dataSize;
+
+ int retVal = ZIP_OK;
+
+ if(pData == NULL || *dataLen < 4)
+ return ZIP_PARAMERROR;
+
+ pNewHeader = (char*)ALLOC(*dataLen);
+ pTmp = pNewHeader;
+
+ while(p < (pData + *dataLen))
+ {
+ header = *(short*)p;
+ dataSize = *(((short*)p)+1);
+
+ if( header == sHeader ) // Header found.
+ {
+ p += dataSize + 4; // skip it. do not copy to temp buffer
+ }
+ else
+ {
+ // Extra Info block should not be removed, So copy it to the temp buffer.
+ memcpy(pTmp, p, dataSize + 4);
+ p += dataSize + 4;
+ size += dataSize + 4;
+ }
+
+ }
+
+ if(size < *dataLen)
+ {
+ // clean old extra info block.
+ memset(pData,0, *dataLen);
+
+ // copy the new extra info block over the old
+ if(size > 0)
+ memcpy(pData, pNewHeader, size);
+
+ // set the new extra info size
+ *dataLen = size;
+
+ retVal = ZIP_OK;
+ }
+ else
+ retVal = ZIP_ERRNO;
+
+ TRYFREE(pNewHeader);
+
+ return retVal;
+}
diff --git a/storage/connect/zip.h b/storage/connect/zip.h
new file mode 100644
index 00000000..8aaebb62
--- /dev/null
+++ b/storage/connect/zip.h
@@ -0,0 +1,362 @@
+/* zip.h -- IO on .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ ---------------------------------------------------------------------------
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ ---------------------------------------------------------------------------
+
+ Changes
+
+ See header of zip.h
+
+*/
+
+#ifndef _zip12_H
+#define _zip12_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define HAVE_BZIP2
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagzipFile__ { int unused; } zipFile__;
+typedef zipFile__ *zipFile;
+#else
+typedef voidp zipFile;
+#endif
+
+#define ZIP_OK (0)
+#define ZIP_EOF (0)
+#define ZIP_ERRNO (Z_ERRNO)
+#define ZIP_PARAMERROR (-102)
+#define ZIP_BADZIPFILE (-103)
+#define ZIP_INTERNALERROR (-104)
+
+#ifndef DEF_MEM_LEVEL
+# if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+# else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+# endif
+#endif
+/* default memLevel */
+
+/* tm_zip contain date/time info */
+typedef struct tm_zip_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_zip;
+
+typedef struct
+{
+ tm_zip tmz_date; /* date in understandable format */
+ uLong dosDate; /* if dos_date == 0, tmu_date is used */
+/* uLong flag; */ /* general purpose bit flag 2 bytes */
+
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+} zip_fileinfo;
+
+typedef const char* zipcharpc;
+
+
+#define APPEND_STATUS_CREATE (0)
+#define APPEND_STATUS_CREATEAFTER (1)
+#define APPEND_STATUS_ADDINZIP (2)
+
+extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append));
+extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append));
+/*
+ Create a zipfile.
+ pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on
+ an Unix computer "zlib/zlib113.zip".
+ if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
+ will be created at the end of the file.
+ (useful if the file contain a self extractor code)
+ if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
+ add files in existing zip (be sure you don't add file that doesn't exist)
+ If the zipfile cannot be opened, the return value is NULL.
+ Else, the return value is a zipFile Handle, usable with other function
+ of this zip package.
+*/
+
+/* Note : there is no delete function into a zipfile.
+ If you want delete file into a zipfile, you must open a zipfile, and create another
+ Of couse, you can use RAW reading and writing to copy the file you did not want delte
+*/
+
+extern zipFile ZEXPORT zipOpen2 OF((const char *pathname,
+ int append,
+ zipcharpc* globalcomment,
+ zlib_filefunc_def* pzlib_filefunc_def));
+
+extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname,
+ int append,
+ zipcharpc* globalcomment,
+ zlib_filefunc64_def* pzlib_filefunc_def));
+
+extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level));
+
+extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int zip64));
+
+/*
+ Open a file in the ZIP for writing.
+ filename : the filename in zip (if NULL, '-' without quote will be used
+ *zipfi contain supplemental information
+ if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
+ contains the extrafield data the the local header
+ if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
+ contains the extrafield data the the local header
+ if comment != NULL, comment contain the comment string
+ method contain the compression method (0 for store, Z_DEFLATED for deflate)
+ level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
+ zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
+ this MUST be '1' if the uncompressed size is >= 0xffffffff.
+
+*/
+
+
+extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw));
+
+
+extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int zip64));
+/*
+ Same than zipOpenNewFileInZip, except if raw=1, we write raw file
+ */
+
+extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting));
+
+extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ int zip64
+ ));
+
+/*
+ Same than zipOpenNewFileInZip2, except
+ windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
+ password : crypting password (NULL for no crypting)
+ crcForCrypting : crc of file to compress (needed for crypting)
+ */
+
+extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ uLong versionMadeBy,
+ uLong flagBase
+ ));
+
+
+extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ uLong versionMadeBy,
+ uLong flagBase,
+ int zip64
+ ));
+/*
+ Same than zipOpenNewFileInZip4, except
+ versionMadeBy : value for Version made by field
+ flag : value for flag field (compression level info will be added)
+ */
+
+
+extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
+ const void* buf,
+ unsigned len));
+/*
+ Write data in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
+/*
+ Close the current file in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
+ uLong uncompressed_size,
+ uLong crc32));
+
+extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file,
+ ZPOS64_T uncompressed_size,
+ uLong crc32));
+
+/*
+ Close the current file in the zipfile, for file opened with
+ parameter raw=1 in zipOpenNewFileInZip2
+ uncompressed_size and crc32 are value for the uncompressed size
+*/
+
+extern int ZEXPORT zipClose OF((zipFile file,
+ const char* global_comment));
+/*
+ Close the zipfile
+*/
+
+
+extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader));
+/*
+ zipRemoveExtraInfoBlock - Added by Mathias Svensson
+
+ Remove extra information block from a extra information data for the local file header or central directory header
+
+ It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.
+
+ 0x0001 is the signature header for the ZIP64 extra information blocks
+
+ usage.
+ Remove ZIP64 Extra information from a central director extra field data
+ zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001);
+
+ Remove ZIP64 Extra information from a Local File Header extra field data
+ zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _zip64_H */